package com.runt.open.mvi.base.model import android.content.Intent import android.net.Uri import android.os.Build import android.util.Log import androidx.compose.ui.text.input.KeyboardType import androidx.core.content.FileProvider import androidx.lifecycle.ViewModel import com.google.gson.Gson import com.runt.open.mvi.base.BaseActivity import com.runt.open.mvi.base.LayoutView import com.runt.open.mvi.data.InputMessageState import com.runt.open.mvi.data.LoadingState import com.runt.open.mvi.data.Message import com.runt.open.mvi.data.MessageState import com.runt.open.mvi.data.PopupMessage import com.runt.open.mvi.retrofit.AndroidScheduler import io.reactivex.Observable import io.reactivex.Observer import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import okhttp3.Callback import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response import java.io.File import java.io.FileOutputStream import java.io.IOException import java.io.InputStream /** * * @author Runt(qingingrunt2010@qq.com) * @purpose * @date 6/1/24 */ open abstract class BaseViewModel : ViewModel(){ var TAG = ""; protected var mActivity : BaseActivity , BaseViewModel>? = null private val _isLoading = MutableStateFlow(LoadingState()) val isLoading = _isLoading.asStateFlow() val messageSetDismiss = { _messageState.value = MessageState(isVisible = false) } private val _messageState = MutableStateFlow(Message(isVisible = false, setDismiss = { })) val messageState = _messageState.asStateFlow() private val _popupState = MutableStateFlow(PopupMessage(isVisible = false,"","")) val popupState = _popupState.asStateFlow() open fun onCreate(activity : BaseActivity , BaseViewModel>) { mActivity = activity TAG = javaClass.simpleName; } open fun onPause(){ } open fun onResume(){ } open fun onStart(){ } open fun onStop(){ } open fun onDestroy(){ } fun getActivity(): BaseActivity , BaseViewModel> { return mActivity!!; } fun showLoading(message : String = "加载中...") { _isLoading.value = LoadingState(isVisible = true,message = message); } fun hideLoading() { _isLoading.value = _isLoading.value.copy(isVisible = false); } fun showInputDialog( title : String = "" , message : String = "" , hint : String = "",regex : String = "", confirmText:String = "确定", cancelText:String = "取消", maxLines:Int = 1, minLength:Int = 0, maxLength:Int = 0, inputType : KeyboardType = KeyboardType.Text , touchOutside : Boolean = true , //空白和系统返回 是否关闭 showClose : Boolean = false , //显示关闭图标(默认不显示) confirmDismiss : Boolean = true , //点击确定是否关闭 cancelDismiss : Boolean = true , //点击取消是否关闭 onDismissRequest : () -> Unit = {} , onCancelRequest : () -> Unit = {} , onConfirmRequest : (String) -> Unit = {} , ){ _messageState.value = InputMessageState(title = title, message = message, hint = hint, regex = regex, maxLines = maxLines, minLength = minLength, maxLength = maxLength, inputType = inputType, touchOutside = touchOutside, showClose = showClose, confirmText = confirmText, cancelText = cancelText, confirmDismiss = confirmDismiss, cancelDismiss = cancelDismiss, onCancelRequest = onCancelRequest, onDismissRequest = onDismissRequest, onConfirmRequest = onConfirmRequest, setDismiss = messageSetDismiss); } fun showDialog( title : String = "" , message : String = "" , confirmText : String = "确定" , cancelText : String = "" , touchOutside : Boolean = true , //空白和系统返回 是否关闭 showClose : Boolean = false , //显示关闭图标(默认不显示) confirmDismiss : Boolean = true , //点击确定是否关闭 cancelDismiss : Boolean = true , //点击取消是否关闭 onDismissRequest : () -> Unit = {} , onCancelRequest : () -> Unit = {} , onConfirmRequest : () -> Unit = {} , ){ _messageState.value = MessageState(title = title, message = message, touchOutside = touchOutside, showClose = showClose, confirmText = confirmText, cancelText = cancelText, confirmDismiss = confirmDismiss, cancelDismiss = cancelDismiss, onCancelRequest = onCancelRequest, onDismissRequest = onDismissRequest, onConfirmRequest = onConfirmRequest, setDismiss = messageSetDismiss); } fun dismissDialog(){ messageSetDismiss.invoke(); } fun showPopupWindow(title : String,message : String){ _popupState.value = PopupMessage(isVisible = true,title,message) } fun hidePopupWindow(){ _popupState.value = _popupState.value.copy(isVisible = false); } /** * 获取用户信息 */ /*fun getUserBean() { httpObserverOn(commonApi.getUserBean() , object : HttpObserver() { protected fun onSuccess(data : UserBean?) { UserBean.setUser(data) } }) }*/ /** * 随机字符串 * @param phone * @param time * @return */ fun randomString(phone : String , time : String) : String { val p = Math.round(phone.length / 6.0).toInt() val t = time.length / 6 val list : MutableList = ArrayList() for (i in 0 .. 5) { var str = "" str = if (i * p > phone.length) { phone.substring((i - 1) * p) } else if ((i + 1) * p > phone.length) { phone.substring(i * p) } else { phone.substring(i * p , (i + 1) * p) } val num = (str.toInt() * time.toLong()).toString() + "" list.add(num) } //return sb.toString(); return plusSingle2(list) } private fun plusSingle2(list : List) : String { val sb = StringBuilder() for (i in list.indices) { sb.append(list[i].substring(if (list[i].length - 2 < 0) 0 else list[i].length - 2)) } return sb.toString() } private fun downloadApk(url : String) { val request : Request = Request.Builder().url(url).build() val client = OkHttpClient() client.newCall(request).enqueue(object : Callback { override fun onResponse(call : okhttp3.Call , response : Response) { val code : Int = response.code Log.d("downloadFile" , "code:$code") if (code != 200) { mActivity!!.showToast("下载失败$code") return } var fos : FileOutputStream? = null var input : InputStream? = null var file : File? = null val buf = ByteArray(2048) var len = 0 try { Log.d("downloadFile" , "下载文件:$url") input = response.body!!.byteStream() val total : Long = response.body!!.contentLength() Log.d("downloadFile" , "total:$total") file = File(mActivity!!.getExternalFilesDir(null)!!.getAbsolutePath() + "/") if (! file !!.exists()) { file.mkdirs() } file = File(file.path + "/" + url.substring(url.lastIndexOf("/"))) file.createNewFile() fos = FileOutputStream(file) var sum : Long = 0 while (input.read(buf).also { len = it } != - 1) { fos.write(buf , 0 , len) sum += len.toLong() val progress = sum * 1.0f / total * 100 // 下载中 Log.d("downloadFile" , "下载进度:$progress") } Log.d("downloadFile" , file.path) // 下载完成 val finalFile : File = file mActivity!!.runOnUiThread { /*mActivity!!.showDialog("安装" , "新版安装包下载完成" , "安装" , "取消" , object : ResPonse() { fun doSuccess(obj : Any?) { openAPK(finalFile) } })*/ } } catch (e : Exception) { Log.d("downloadFileException" , e.toString()) Log.d("downloadFileException" , "Url:\${call.request().url}") mActivity!!.showToast("下载失败$e") file !!.delete() call.cancel() } finally { fos !!.flush() input !!.close() fos.close() } } override fun onFailure(call : okhttp3.Call , e : IOException) { mActivity!!.showToast("下载失败$e") } }) } /** * 打开apk文件 * * @param file */ private fun openAPK(file : File) { val intent = Intent() intent.setAction(Intent.ACTION_VIEW) var photoURI : Uri? = null photoURI = if (Build.VERSION.SDK_INT >= 24) { //判读版本是否在7.0以上 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) FileProvider.getUriForFile(mActivity!! , mActivity!!.getApplicationContext().getPackageName() + ".fileprovider" , file) //添加这一句表示对目标应用临时授权该Uri所代表的文件 } else { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) Uri.fromFile(file) } intent.setDataAndType(photoURI , "application/vnd.android.package-archive") mActivity!!.startActivity(intent) } /** * 网络请求观察 * @param observable * @param * @return */ fun httpObserverOn(observable : Observable , observer : Observer) { observable.subscribeOn(Schedulers.io()) //指定网络请求在io后台线程中进行 .observeOn(AndroidScheduler.mainThread()).subscribe(observer) } /** * 网络请求观察(加载框) * @param observable * @param * @return */ fun httpObserverOnLoading(observable : Observable , observer : Observer) { observable.subscribeOn(Schedulers.io()) //指定网络请求在io后台线程中进行 .doOnSubscribe { disposable -> //mActivity.showLoadingDialog("") } .observeOn(AndroidScheduler.mainThread()).doOnError { throwable -> //mActivity.dissmissLoadingDialog() Log.e("ViewModel" , hashCode().toString() + " httpObserverOnLoading " + throwable) }.doOnComplete { //mActivity.dissmissLoadingDialog() }.subscribe(observer) } fun createJsonBody(obj : Any) : RequestBody { val mediaType = "application/json; charset=utf-8".toMediaType() val json = if (obj is String) obj else Gson().toJson(obj) val requestBody = json.toString().toRequestBody(mediaType) return requestBody; } }