mirror of
https://github.com/rhunk/SnapEnhance.git
synced 2025-06-12 05:07:46 +02:00
feat: download section
This commit is contained in:
@ -4,15 +4,17 @@ import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import me.rhunk.snapenhance.download.data.DownloadMetadata
|
||||
import me.rhunk.snapenhance.download.data.PendingDownload
|
||||
import me.rhunk.snapenhance.download.data.DownloadObject
|
||||
import me.rhunk.snapenhance.download.data.DownloadStage
|
||||
import me.rhunk.snapenhance.ui.download.MediaFilter
|
||||
import me.rhunk.snapenhance.util.SQLiteDatabaseHelper
|
||||
import me.rhunk.snapenhance.util.getIntOrNull
|
||||
import me.rhunk.snapenhance.util.getStringOrNull
|
||||
|
||||
class DownloadTaskManager {
|
||||
private lateinit var taskDatabase: SQLiteDatabase
|
||||
private val pendingTasks = mutableMapOf<Int, PendingDownload>()
|
||||
private val cachedTasks = mutableMapOf<Int, PendingDownload>()
|
||||
private val pendingTasks = mutableMapOf<Int, DownloadObject>()
|
||||
private val cachedTasks = mutableMapOf<Int, DownloadObject>()
|
||||
|
||||
@SuppressLint("Range")
|
||||
fun init(context: Context) {
|
||||
@ -33,7 +35,7 @@ class DownloadTaskManager {
|
||||
}
|
||||
}
|
||||
|
||||
fun addTask(task: PendingDownload): Int {
|
||||
fun addTask(task: DownloadObject): Int {
|
||||
taskDatabase.execSQL("INSERT INTO tasks (hash, outputPath, outputFile, mediaDisplayType, mediaDisplaySource, iconUrl, downloadStage) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
arrayOf(
|
||||
task.metadata.mediaIdentifier,
|
||||
@ -53,7 +55,7 @@ class DownloadTaskManager {
|
||||
return task.downloadId
|
||||
}
|
||||
|
||||
fun updateTask(task: PendingDownload) {
|
||||
fun updateTask(task: DownloadObject) {
|
||||
taskDatabase.execSQL("UPDATE tasks SET hash = ?, outputPath = ?, outputFile = ?, mediaDisplayType = ?, mediaDisplaySource = ?, iconUrl = ?, downloadStage = ? WHERE id = ?",
|
||||
arrayOf(
|
||||
task.metadata.mediaIdentifier,
|
||||
@ -107,13 +109,13 @@ class DownloadTaskManager {
|
||||
pendingTasks.remove(id)
|
||||
}
|
||||
|
||||
fun removeTask(task: PendingDownload) {
|
||||
fun removeTask(task: DownloadObject) {
|
||||
removeTask(task.downloadId)
|
||||
}
|
||||
|
||||
fun queryAllTasks(filter: MediaFilter): Map<Int, PendingDownload> {
|
||||
fun queryFirstTasks(filter: MediaFilter): Map<Int, DownloadObject> {
|
||||
val isPendingFilter = filter == MediaFilter.PENDING
|
||||
val tasks = mutableMapOf<Int, PendingDownload>()
|
||||
val tasks = mutableMapOf<Int, DownloadObject>()
|
||||
|
||||
tasks.putAll(pendingTasks.filter { isPendingFilter || filter.matches(it.value.metadata.mediaDisplayType) })
|
||||
if (isPendingFilter) {
|
||||
@ -130,7 +132,7 @@ class DownloadTaskManager {
|
||||
}
|
||||
|
||||
@SuppressLint("Range")
|
||||
fun queryTasks(from: Int, amount: Int = 20, filter: MediaFilter = MediaFilter.NONE): Map<Int, PendingDownload> {
|
||||
fun queryTasks(from: Int, amount: Int = 30, filter: MediaFilter = MediaFilter.NONE): Map<Int, DownloadObject> {
|
||||
if (filter == MediaFilter.PENDING) {
|
||||
return emptyMap()
|
||||
}
|
||||
@ -139,27 +141,27 @@ class DownloadTaskManager {
|
||||
"SELECT * FROM tasks WHERE id < ? AND mediaDisplayType LIKE ? ORDER BY id DESC LIMIT ?",
|
||||
arrayOf(
|
||||
from.toString(),
|
||||
filter.mediaDisplayType.let { if (it == null) "%" else "%$it" },
|
||||
if (filter.shouldIgnoreFilter) "%" else "%${filter.key}",
|
||||
amount.toString()
|
||||
)
|
||||
)
|
||||
|
||||
val result = sortedMapOf<Int, PendingDownload>()
|
||||
val result = sortedMapOf<Int, DownloadObject>()
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
val task = PendingDownload(
|
||||
downloadId = cursor.getInt(cursor.getColumnIndex("id")),
|
||||
outputFile = cursor.getString(cursor.getColumnIndex("outputFile")),
|
||||
val task = DownloadObject(
|
||||
downloadId = cursor.getIntOrNull("id")!!,
|
||||
outputFile = cursor.getStringOrNull("outputFile"),
|
||||
metadata = DownloadMetadata(
|
||||
outputPath = cursor.getString(cursor.getColumnIndex("outputPath")),
|
||||
mediaIdentifier = cursor.getString(cursor.getColumnIndex("hash")),
|
||||
mediaDisplayType = cursor.getString(cursor.getColumnIndex("mediaDisplayType")),
|
||||
mediaDisplaySource = cursor.getString(cursor.getColumnIndex("mediaDisplaySource")),
|
||||
iconUrl = cursor.getString(cursor.getColumnIndex("iconUrl"))
|
||||
outputPath = cursor.getStringOrNull("outputPath")!!,
|
||||
mediaIdentifier = cursor.getStringOrNull("hash"),
|
||||
mediaDisplayType = cursor.getStringOrNull("mediaDisplayType"),
|
||||
mediaDisplaySource = cursor.getStringOrNull("mediaDisplaySource"),
|
||||
iconUrl = cursor.getStringOrNull("iconUrl")
|
||||
)
|
||||
).apply {
|
||||
downloadTaskManager = this@DownloadTaskManager
|
||||
downloadStage = DownloadStage.valueOf(cursor.getString(cursor.getColumnIndex("downloadStage")))
|
||||
downloadStage = DownloadStage.valueOf(cursor.getStringOrNull("downloadStage")!!)
|
||||
//if downloadStage is not saved, it means the app was killed before the download was finished
|
||||
if (downloadStage != DownloadStage.SAVED) {
|
||||
downloadStage = DownloadStage.FAILED
|
||||
|
@ -1,10 +1,9 @@
|
||||
package me.rhunk.snapenhance.download.data
|
||||
|
||||
import kotlinx.coroutines.Job
|
||||
import me.rhunk.snapenhance.SharedContext
|
||||
import me.rhunk.snapenhance.download.DownloadTaskManager
|
||||
|
||||
data class PendingDownload(
|
||||
data class DownloadObject(
|
||||
var downloadId: Int = 0,
|
||||
var outputFile: String? = null,
|
||||
val metadata : DownloadMetadata
|
@ -242,7 +242,7 @@ class MediaDownloader : Feature("MediaDownloader", loadParams = FeatureLoadParam
|
||||
pathSuffix = authorUsername,
|
||||
mediaIdentifier = "$conversationId$senderId${conversationMessage.server_message_id}",
|
||||
mediaDisplaySource = authorUsername,
|
||||
mediaDisplayType = MediaFilter.CHAT_MEDIA.mediaDisplayType,
|
||||
mediaDisplayType = MediaFilter.CHAT_MEDIA.key,
|
||||
friendInfo = author
|
||||
), mediaInfoMap)
|
||||
|
||||
@ -282,7 +282,7 @@ class MediaDownloader : Feature("MediaDownloader", loadParams = FeatureLoadParam
|
||||
pathSuffix = authorName,
|
||||
mediaIdentifier = paramMap["MEDIA_ID"].toString(),
|
||||
mediaDisplaySource = authorName,
|
||||
mediaDisplayType = MediaFilter.STORY.mediaDisplayType,
|
||||
mediaDisplayType = MediaFilter.STORY.key,
|
||||
friendInfo = author
|
||||
), mediaInfoMap)
|
||||
return
|
||||
@ -311,7 +311,7 @@ class MediaDownloader : Feature("MediaDownloader", loadParams = FeatureLoadParam
|
||||
downloadOperaMedia(provideDownloadManagerClient(
|
||||
pathSuffix = "Spotlight",
|
||||
mediaIdentifier = paramMap["SNAP_ID"].toString(),
|
||||
mediaDisplayType = MediaFilter.SPOTLIGHT.mediaDisplayType,
|
||||
mediaDisplayType = MediaFilter.SPOTLIGHT.key,
|
||||
mediaDisplaySource = paramMap["TIME_STAMP"].toString()
|
||||
), mediaInfoMap)
|
||||
return
|
||||
@ -476,7 +476,7 @@ class MediaDownloader : Feature("MediaDownloader", loadParams = FeatureLoadParam
|
||||
pathSuffix = authorName,
|
||||
mediaIdentifier = "${message.client_conversation_id}${message.sender_id}${message.server_message_id}",
|
||||
mediaDisplaySource = authorName,
|
||||
mediaDisplayType = MediaFilter.CHAT_MEDIA.mediaDisplayType,
|
||||
mediaDisplayType = MediaFilter.CHAT_MEDIA.key,
|
||||
friendInfo = friendInfo
|
||||
).downloadSingleMedia(
|
||||
Base64.UrlSafe.encode(urlProto),
|
||||
|
@ -26,7 +26,7 @@ import me.rhunk.snapenhance.Logger
|
||||
import me.rhunk.snapenhance.SharedContext
|
||||
import me.rhunk.snapenhance.core.R
|
||||
import me.rhunk.snapenhance.data.FileType
|
||||
import me.rhunk.snapenhance.download.data.PendingDownload
|
||||
import me.rhunk.snapenhance.download.data.DownloadObject
|
||||
import me.rhunk.snapenhance.download.data.DownloadStage
|
||||
import me.rhunk.snapenhance.util.snap.PreviewUtils
|
||||
import java.io.File
|
||||
@ -37,7 +37,7 @@ import kotlin.coroutines.coroutineContext
|
||||
|
||||
class DownloadListAdapter(
|
||||
private val activity: DownloadManagerActivity,
|
||||
private val downloadList: MutableList<PendingDownload>
|
||||
private val downloadList: MutableList<DownloadObject>
|
||||
): Adapter<DownloadListAdapter.ViewHolder>() {
|
||||
private val coroutineScope = CoroutineScope(Dispatchers.IO)
|
||||
private val previewJobs = mutableMapOf<Int, Job>()
|
||||
@ -68,7 +68,7 @@ class DownloadListAdapter(
|
||||
}
|
||||
|
||||
@SuppressLint("Recycle")
|
||||
private suspend fun handlePreview(download: PendingDownload, holder: ViewHolder) {
|
||||
private suspend fun handlePreview(download: DownloadObject, holder: ViewHolder) {
|
||||
download.outputFile?.let {
|
||||
val uri = Uri.parse(it)
|
||||
runCatching {
|
||||
@ -124,7 +124,7 @@ class DownloadListAdapter(
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateViewHolder(download: PendingDownload, holder: ViewHolder) {
|
||||
private fun updateViewHolder(download: DownloadObject, holder: ViewHolder) {
|
||||
holder.status.text = download.downloadStage.toString()
|
||||
holder.view.background = holder.view.context.getDrawable(R.drawable.download_manager_item_background)
|
||||
|
||||
@ -163,7 +163,7 @@ class DownloadListAdapter(
|
||||
}
|
||||
}
|
||||
|
||||
holder.bitmojiIcon.setImageResource(R.drawable.bitmoji_blank)
|
||||
// holder.bitmojiIcon.setImageResource(R.drawable.bitmoji_blank)
|
||||
|
||||
pendingDownload.metadata.iconUrl?.let { url ->
|
||||
thread(start = true) {
|
||||
|
@ -19,13 +19,13 @@ import me.rhunk.snapenhance.SharedContext
|
||||
import me.rhunk.snapenhance.bridge.wrapper.LocaleWrapper
|
||||
import me.rhunk.snapenhance.core.BuildConfig
|
||||
import me.rhunk.snapenhance.core.R
|
||||
import me.rhunk.snapenhance.download.data.PendingDownload
|
||||
import me.rhunk.snapenhance.download.data.DownloadObject
|
||||
|
||||
class DownloadManagerActivity : Activity() {
|
||||
lateinit var translation: LocaleWrapper
|
||||
|
||||
private val backCallbacks = mutableListOf<() -> Unit>()
|
||||
private val fetchedDownloadTasks = mutableListOf<PendingDownload>()
|
||||
private val fetchedDownloadTasks = mutableListOf<DownloadObject>()
|
||||
private var listFilter = MediaFilter.NONE
|
||||
|
||||
private val preferences by lazy {
|
||||
@ -42,7 +42,7 @@ class DownloadManagerActivity : Activity() {
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun updateListContent() {
|
||||
fetchedDownloadTasks.clear()
|
||||
fetchedDownloadTasks.addAll(SharedContext.downloadTaskManager.queryAllTasks(filter = listFilter).values)
|
||||
fetchedDownloadTasks.addAll(SharedContext.downloadTaskManager.queryFirstTasks(filter = listFilter).values)
|
||||
|
||||
with(findViewById<RecyclerView>(R.id.download_list)) {
|
||||
adapter?.notifyDataSetChanged()
|
||||
|
@ -1,17 +1,17 @@
|
||||
package me.rhunk.snapenhance.ui.download
|
||||
|
||||
enum class MediaFilter(
|
||||
val mediaDisplayType: String? = null
|
||||
val key: String,
|
||||
val shouldIgnoreFilter: Boolean = false
|
||||
) {
|
||||
NONE,
|
||||
PENDING,
|
||||
CHAT_MEDIA("Chat Media"),
|
||||
STORY("Story"),
|
||||
SPOTLIGHT("Spotlight");
|
||||
NONE("none", true),
|
||||
PENDING("pending", true),
|
||||
CHAT_MEDIA("chat_media"),
|
||||
STORY("story"),
|
||||
SPOTLIGHT("spotlight");
|
||||
|
||||
fun matches(source: String?): Boolean {
|
||||
if (mediaDisplayType == null) return true
|
||||
if (source == null) return false
|
||||
return source.contains(mediaDisplayType, ignoreCase = true)
|
||||
return source.contains(key, ignoreCase = true)
|
||||
}
|
||||
}
|
@ -48,9 +48,7 @@ object PreviewUtils {
|
||||
setDataSource(file.absolutePath)
|
||||
}.getFrameAtTime(0, MediaMetadataRetriever.OPTION_CLOSEST_SYNC)
|
||||
} else {
|
||||
BitmapFactory.decodeFile(file.absolutePath, BitmapFactory.Options().apply {
|
||||
inSampleSize = 1
|
||||
})
|
||||
BitmapFactory.decodeFile(file.absolutePath, BitmapFactory.Options())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="90dp"
|
||||
android:height="90dp"
|
||||
android:viewportWidth="90"
|
||||
android:viewportHeight="90">
|
||||
<path
|
||||
android:pathData="M45,90.1c10.8,0 20.8,-3.8 28.6,-10.2c-1.4,-2.1 -3,-3.6 -4.7,-5c-5.2,-4.1 -12.6,-5.6 -17.7,-6.5l-0.2,-2c7.8,-4.6 9.7,-9.5 12.8,-19.8l0.1,-0.7c0,0 2.7,-1.1 3.1,-6.1c0.6,-6.8 -2.2,-4.8 -2.2,-5.3C65.1,31 65,26.4 64,23c-2.1,-7.3 -9.2,-13.1 -19,-13.1S28.1,15.6 26,23c-1,3.4 -1.1,8 -0.8,11.6c0,0.5 -2.7,-1.5 -2.2,5.3c0.4,5 3.1,6.1 3.1,6.1l0.1,0.7c3.1,10.3 5,15.2 12.8,19.8l-0.2,2c-5,0.9 -12.5,2.4 -17.7,6.5c-1.7,1.4 -3.3,2.9 -4.7,5C24.2,86.3 34.2,90.1 45,90.1z"
|
||||
android:strokeWidth="1.5"
|
||||
android:fillColor="#979797"
|
||||
android:strokeColor="#000000"/>
|
||||
</vector>
|
Reference in New Issue
Block a user