329 lines
13 KiB
Kotlin
329 lines
13 KiB
Kotlin
package com.gh.base
|
||
|
||
import android.app.Application
|
||
import android.content.Intent
|
||
import android.text.TextUtils
|
||
import androidx.lifecycle.AndroidViewModel
|
||
import androidx.lifecycle.MediatorLiveData
|
||
import androidx.lifecycle.MutableLiveData
|
||
import com.gh.base.fragment.WaitingDialogFragment
|
||
import com.gh.common.runOnUiThread
|
||
import com.gh.common.util.*
|
||
import com.gh.gamecenter.R
|
||
import com.gh.gamecenter.entity.ErrorEntity
|
||
import com.gh.gamecenter.entity.LocalVideoEntity
|
||
import com.gh.gamecenter.qa.BbsType
|
||
import com.gh.gamecenter.retrofit.Response
|
||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||
import com.gh.gamecenter.retrofit.service.ApiService
|
||
import com.gh.gamecenter.video.upload.OnUploadListener
|
||
import com.gh.gamecenter.video.upload.UploadManager
|
||
import com.google.gson.JsonObject
|
||
import com.lightgame.utils.Utils
|
||
import com.zhihu.matisse.Matisse
|
||
import com.zhihu.matisse.internal.utils.PathUtils
|
||
import io.reactivex.disposables.Disposable
|
||
import okhttp3.ResponseBody
|
||
import retrofit2.HttpException
|
||
import java.io.File
|
||
import java.util.*
|
||
import kotlin.collections.HashMap
|
||
import kotlin.collections.List
|
||
import kotlin.collections.Map
|
||
import kotlin.collections.find
|
||
import kotlin.collections.forEach
|
||
import kotlin.collections.set
|
||
|
||
abstract class BaseRichEditorViewModel(application: Application) : AndroidViewModel(application) {
|
||
val mApi: ApiService = RetrofitManager.getInstance(application).api
|
||
val processDialog = MediatorLiveData<WaitingDialogFragment.WaitingDialogData>()
|
||
val uploadingImage = ArrayList<LinkedHashMap<String, String>>()
|
||
val chooseImagesUpload = MutableLiveData<LinkedHashMap<String, String>>()
|
||
val chooseImagesUploadSuccess = MutableLiveData<LinkedHashMap<String, String>>()
|
||
var uploadImageSubscription: Disposable? = null
|
||
val mapImages = HashMap<String, String>()
|
||
val localVideoList = ArrayList<LocalVideoEntity>()
|
||
val uploadVideoErrorList = ArrayList<LocalVideoEntity>()
|
||
var currentUploadingVideo: LocalVideoEntity? = null
|
||
var type: String = ""//游戏论坛:game_bbs 官方论坛:official_bbs
|
||
private var mUploadVideoListener: UploadVideoListener? = null
|
||
val TITLE_MIN_LENGTH = 6
|
||
val MIN_TEXT_LENGTH = 6
|
||
val MAX_TEXT_LENGTH = 10000
|
||
val FILE_HOST = "file:///"
|
||
var id = ""//视频标记
|
||
var videoId = ""//更改封面视频id
|
||
|
||
fun setUploadVideoListener(uploadVideoListener: UploadVideoListener) {
|
||
this.mUploadVideoListener = uploadVideoListener
|
||
}
|
||
|
||
//检查图片是否符合规则并上传图片
|
||
fun uploadPic(data: Intent) {
|
||
val uris = Matisse.obtainResult(data)
|
||
val pictureList = ArrayList<String>()
|
||
for (uri in uris) {
|
||
val picturePath = PathUtils.getPath(getApplication(), uri)
|
||
if (picturePath != null) {
|
||
if (File(picturePath).length() > ImageUtils.getUploadFileMaxSize()) {
|
||
val count = ImageUtils.getUploadFileMaxSize() / 1024 / 1024
|
||
val application: Application = getApplication()
|
||
Utils.toast(getApplication(), application.getString(R.string.pic_max_hint, count))
|
||
continue
|
||
}
|
||
Utils.log("picturePath = $picturePath")
|
||
pictureList.add(picturePath)
|
||
} else {
|
||
Utils.log("picturePath is null")
|
||
}
|
||
}
|
||
if (pictureList.size == 0) return
|
||
|
||
uploadImageSubscription = UploadImageUtils.compressAndUploadImageList(UploadImageUtils.UploadType.answer, pictureList
|
||
, false, object : UploadImageUtils.OnUploadImageListListener {
|
||
override fun onProgress(total: Long, progress: Long) {}
|
||
|
||
override fun onCompressSuccess(imageUrls: List<String>) {
|
||
val chooseImageMd5Map = LinkedHashMap<String, String>()
|
||
imageUrls.forEach {
|
||
chooseImageMd5Map[MD5Utils.getUrlMD5(it)] = ""
|
||
}
|
||
uploadingImage.add(chooseImageMd5Map)
|
||
chooseImagesUpload.postValue(chooseImageMd5Map)
|
||
}
|
||
|
||
override fun onSuccess(imageUrl: LinkedHashMap<String, String>, errorMap: Map<String, Exception>) {
|
||
val uploadMap = uploadingImage.find { it.containsKey(MD5Utils.getUrlMD5(imageUrl.entries.iterator().next().key)) }
|
||
uploadMap?.let {
|
||
for (key in imageUrl.keys) {
|
||
uploadMap[MD5Utils.getUrlMD5(key)] = FILE_HOST + key.decodeURI()
|
||
mapImages[TextUtils.htmlEncode(key).decodeURI()] = imageUrl[key] ?: ""
|
||
}
|
||
chooseImagesUploadSuccess.postValue(uploadMap)
|
||
uploadingImage.remove(uploadMap)
|
||
}
|
||
val errorSize = pictureList.size - imageUrl.size
|
||
if (errorSize > 0) {
|
||
for (error in errorMap.values) {
|
||
if (error is HttpException && error.code() == 403) {
|
||
Utils.toast(getApplication(), errorSize.toString() + "张违规图片上传失败")
|
||
return
|
||
}
|
||
}
|
||
Utils.toast(getApplication(), errorSize.toString() + "张图片上传失败")
|
||
}
|
||
}
|
||
|
||
override fun onError(errorMap: Map<String, Exception>) {
|
||
val errorSize = pictureList.size
|
||
|
||
for (error in errorMap.values) {
|
||
if (error is HttpException && error.code() == 403) {
|
||
val e = error.response()?.errorBody()?.string()?.toObject<ErrorEntity>()
|
||
if (e != null && e.code == 403017) {
|
||
Utils.toast(getApplication(), errorSize.toString() + "张图片的宽或高超过限制,请裁剪后上传")
|
||
} else {
|
||
Utils.toast(getApplication(), errorSize.toString() + "张违规图片上传失败")
|
||
}
|
||
return
|
||
}
|
||
}
|
||
if (errorSize == 1) {
|
||
Utils.toast(getApplication(), "图片上传失败")
|
||
} else {
|
||
Utils.toast(getApplication(), errorSize.toString() + "张图片上传失败")
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
fun uploadPoster(picturePath: String) {
|
||
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("图片上传中...", true))
|
||
uploadImageSubscription = UploadImageUtils.compressAndUploadImage(UploadImageUtils.UploadType.poster, picturePath, false,
|
||
object : UploadImageUtils.OnUploadImageListener {
|
||
override fun onSuccess(imageUrl: String) {
|
||
patchVideoPoster(imageUrl)
|
||
}
|
||
|
||
override fun onError(e: Throwable?) {
|
||
handleUploadPosterResult(true)
|
||
}
|
||
|
||
override fun onProgress(total: Long, progress: Long) {
|
||
|
||
}
|
||
})
|
||
}
|
||
|
||
private fun patchVideoPoster(poster: String) {
|
||
if (id.isEmpty() || videoId.isEmpty()) return
|
||
val map = hashMapOf("poster" to poster)
|
||
mApi.patchBbsVideo(videoId, map.toRequestBody())
|
||
.compose(observableToMain())
|
||
.subscribe(object : Response<ResponseBody>() {
|
||
override fun onResponse(response: ResponseBody?) {
|
||
super.onResponse(response)
|
||
mUploadVideoListener?.changePoster(id, poster)
|
||
handleUploadPosterResult(false)
|
||
}
|
||
|
||
override fun onFailure(e: HttpException?) {
|
||
super.onFailure(e)
|
||
handleUploadPosterResult(true)
|
||
}
|
||
})
|
||
}
|
||
|
||
private fun handleUploadPosterResult(isFailure: Boolean = false) {
|
||
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("图片上传中...", false))
|
||
if (isFailure) {
|
||
ToastUtils.showToast("封面更改失败")
|
||
}
|
||
id = ""
|
||
videoId = ""
|
||
}
|
||
|
||
fun deleteVideo(id: String) {
|
||
if (localVideoList.isNotEmpty()) {
|
||
val video = localVideoList.find { it.id == id }
|
||
if (video != null) {
|
||
if (UploadManager.isUploading(video.filePath)) {
|
||
UploadManager.cancelTask(video.filePath)
|
||
}
|
||
localVideoList.remove(video)
|
||
}
|
||
}
|
||
if (uploadVideoErrorList.isNotEmpty()) {
|
||
val video = uploadVideoErrorList.find { it.id == id }
|
||
if (video != null) {
|
||
uploadVideoErrorList.remove(video)
|
||
}
|
||
}
|
||
if (currentUploadingVideo?.id == id) {
|
||
currentUploadingVideo = null
|
||
uploadVideo()
|
||
}
|
||
}
|
||
|
||
fun uploadVideo() {
|
||
if (currentUploadingVideo != null) return
|
||
if (localVideoList.isEmpty()) return
|
||
currentUploadingVideo = localVideoList[0]
|
||
UploadManager.createUploadTask(currentUploadingVideo?.filePath
|
||
?: "", object : OnUploadListener {
|
||
override fun onProgressChanged(uploadFilePath: String, currentSize: Long, totalSize: Long, speed: Long) {
|
||
runOnUiThread {
|
||
val percent = (currentSize * 100 / totalSize.toFloat()).roundTo(1)
|
||
currentUploadingVideo?.id?.let {
|
||
mUploadVideoListener?.updateVideoProgress(it, percent.toString())
|
||
}
|
||
}
|
||
}
|
||
|
||
override fun onUploadSuccess(uploadFilePath: String, url: String) {
|
||
if (currentUploadingVideo != null) {
|
||
val newPoster = ImageUtils.getVideoSnapshot(url, 0)
|
||
postVideoInfo(url, newPoster)
|
||
}
|
||
}
|
||
|
||
override fun onUploadFailure(uploadFilePath: String, errorMsg: String) {
|
||
uploadFailure()
|
||
}
|
||
})
|
||
}
|
||
|
||
private fun getVideoType(): String {
|
||
return when (type) {
|
||
BbsType.GAME_BBS.value -> BbsType.GAME_BBS_INSERT.value
|
||
BbsType.OFFICIAL_BBS.value -> BbsType.OFFICIAL_BBS_INSERT.value
|
||
else -> ""
|
||
}
|
||
}
|
||
|
||
fun postVideoInfo(url: String, poster: String) {
|
||
val map = HashMap<String, Any>().apply {
|
||
put("poster", poster)
|
||
put("url", url)
|
||
put("format", currentUploadingVideo?.format ?: "")
|
||
put("size", currentUploadingVideo?.size ?: 0)
|
||
put("length", currentUploadingVideo?.duration ?: 0)
|
||
put("type", getVideoType())
|
||
}
|
||
val requestBody = map.toRequestBody()
|
||
mApi.postBbsVideo(requestBody)
|
||
.compose(observableToMain())
|
||
.subscribe(object : Response<JsonObject>() {
|
||
override fun onResponse(response: JsonObject?) {
|
||
super.onResponse(response)
|
||
if (response != null) {
|
||
uploadSuccess(poster, url, response)
|
||
}
|
||
}
|
||
|
||
override fun onFailure(e: HttpException?) {
|
||
super.onFailure(e)
|
||
uploadFailure()
|
||
}
|
||
})
|
||
}
|
||
|
||
private fun uploadSuccess(poster: String, url: String, data: JsonObject) {
|
||
currentUploadingVideo?.let {
|
||
mUploadVideoListener?.changePoster(it.id, poster)
|
||
mUploadVideoListener?.videoUploadFinished(it.id, url, data.toString())
|
||
UploadManager.cancelTask(it.filePath)
|
||
localVideoList.remove(it)
|
||
}
|
||
currentUploadingVideo = null
|
||
uploadVideo()
|
||
}
|
||
|
||
private fun uploadFailure() {
|
||
currentUploadingVideo?.let {
|
||
runOnUiThread {
|
||
mUploadVideoListener?.videoUploadFailed(it.id)
|
||
}
|
||
uploadVideoErrorList.add(it)
|
||
localVideoList.remove(it)
|
||
UploadManager.cancelTask(it.filePath)
|
||
}
|
||
currentUploadingVideo = null
|
||
uploadVideo()
|
||
}
|
||
|
||
fun checkIsAllUploadedAndToast(): Boolean {
|
||
if (localVideoList.isNotEmpty() || uploadVideoErrorList.isNotEmpty()) {
|
||
ToastUtils.showToast("视频未上传完成,视频内容保存失败")
|
||
return false
|
||
}
|
||
return true
|
||
}
|
||
}
|
||
|
||
interface UploadVideoListener {
|
||
/**
|
||
* 插入视频占位图
|
||
*/
|
||
fun insertPlaceholderVideo(id: String, poster: String)
|
||
|
||
/**
|
||
* 更新视频进度条
|
||
*/
|
||
fun updateVideoProgress(id: String, progress: String)
|
||
|
||
/**
|
||
* 上传视频完成
|
||
*/
|
||
fun videoUploadFinished(id: String, url: String, msg: String)
|
||
|
||
/**
|
||
* 更换封面图
|
||
*/
|
||
fun changePoster(id: String, poster: String)
|
||
|
||
/**
|
||
* 上传失败
|
||
*/
|
||
fun videoUploadFailed(id: String)
|
||
} |