package com.adealink.weparty.effect import androidx.lifecycle.LiveData import com.adealink.frame.base.IError import com.adealink.frame.download.listener.TaskListener import com.adealink.frame.download.task.Task import com.adealink.frame.download.task.TaskPriority import com.adealink.frame.effect.data.EffectAnimType import com.adealink.frame.log.Log import com.adealink.frame.mvvm.livedata.OnceMutableLiveData import com.adealink.frame.mvvm.viewmodel.BaseViewModel import com.adealink.frame.storage.file.WeFile import com.adealink.frame.storage.file.getCacheFilePathByUrl import com.adealink.frame.storageService import com.adealink.frame.util.md5 import com.adealink.weparty.App import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine import kotlin.coroutines.resume class EffectViewModel : BaseViewModel() { fun downloadResources(urls: List, priority: TaskPriority): LiveData> { val liveData = OnceMutableLiveData>() viewModelScope.launch { val resultList = coroutineScope { urls.map { url -> async { downloadEffect(url, priority) } }.awaitAll() } liveData.send(resultList) } return liveData } fun downloadResource(url: String, priority: TaskPriority): LiveData { val liveData = OnceMutableLiveData() viewModelScope.launch { liveData.send( downloadEffect(url, priority) ) } return liveData } /** * 接入腾讯云特效播放器后按需使用,需传入新旧链接,根据特效特效播放器可用情况下载对应资源 */ fun downloadResource( oldUrl: String, newUrl: String?, newAnimType: Int, forceOldRes: Boolean = false, priority: TaskPriority = TaskPriority.NORMAL ): LiveData { val liveData = OnceMutableLiveData() val effectUrl: String val effectAnimType: Int when (forceOldRes || newUrl.isNullOrEmpty()) { true -> { effectUrl = oldUrl effectAnimType = EffectAnimType.getOldEffectAnimTypeByUrl(oldUrl) } else -> { effectUrl = newUrl effectAnimType = newAnimType } } viewModelScope.launch { val animType = EffectAnimType.map(effectAnimType) if (animType == null) { //不支持的动效类型 liveData.send(EffectSaveResource(null, effectAnimType)) return@launch } liveData.send( EffectSaveResource(downloadEffect(effectUrl, priority), effectAnimType) ) } return liveData } private suspend fun downloadEffect(url: String, priority: TaskPriority): WeFile? { val savePath = getCacheFilePathByUrl(url) return suspendCancellableCoroutine { continuation -> addDownloadTask(url, savePath, priority, { localPath -> if (continuation.isActive) { continuation.resume( localPath ) } }, { if (continuation.isActive) { continuation.resume(null) } }) } } private fun addDownloadTask( url: String, savePath: String, priority: TaskPriority, success: ((path: WeFile) -> Unit)? = null, failed: ((error: IError) -> Unit)? = null, ) { Log.d(TAG, "addDownloadTask, url: $url") Log.d(TAG, " savePath: $savePath") val file = storageService.file.createWeFile(savePath) if (file.exists()) { Log.d(TAG, "addDownloadTask, fileExist, return") success?.invoke(file) return } val taskId = url.md5() val task = Task(taskId, url, savePath, TaskPriority.getPriority(priority)) Log.d( TAG, "addDownloadTask, start download, url:$url, task:$task" ) task.listeners.add(object : TaskListener { override fun onFinished(task: Task) { super.onFinished(task) success?.invoke(file) Log.d( TAG, "addDownloadTask, download success, task:$task" ) } override fun onError(task: Task, error: IError) { super.onError(task, error) failed?.invoke(error) Log.e( TAG, "addDownloadTask, task:$task, error:$error" ) } }) addDownloadTask(task) } private fun addDownloadTask(task: Task) { App.instance.downloadService.addTask(task) } companion object { private const val TAG = "EffectViewModel" } }