package com.xw.yunwei.push
|
|
import android.app.Activity
|
import android.content.Intent
|
import android.view.View.inflate
|
import android.widget.ImageView
|
import android.widget.TextView
|
import androidx.databinding.DataBindingUtil
|
import com.afollestad.materialdialogs.customview.customView
|
import com.afollestad.materialdialogs.customview.getCustomView
|
import com.blankj.utilcode.util.AppUtils
|
import com.xw.common.net.UpdateManager
|
import com.xw.common.net.interceptor.ApiException
|
import com.xw.common.utils.KeyPreferences
|
import com.xw.common.utils.LogUtils
|
import com.xw.common.utils.MMKVManager
|
import com.xw.common.utils.ToastUtilCommon
|
import com.xw.yunwei.MyApp
|
import com.xw.yunwei.R
|
import com.xw.yunwei.databinding.DialogProtocolBinding
|
import com.xw.yunwei.model.AgreeInfo
|
import com.xw.yunwei.model.SwitchTabMain
|
import com.xw.yunwei.model.SwitchTabTask
|
import com.xw.yunwei.net.TaskRepository
|
import com.xw.yunwei.net.UserRepository
|
import com.xw.yunwei.ui.MainActivity
|
import com.xw.yunwei.ui.task.TaskVM
|
import com.xw.yunwei.ui.task.accident.detail.AccidentDetailActivity
|
import com.xw.yunwei.ui.task.normal.NormalTaskDetailActivity
|
import com.xw.yunwei.ui.user.mine.protocol.ProtocolActivity
|
import com.xw.yunwei.ui.user.mine.scheduling.SchedulingActivity
|
import com.xw.yunwei.ui.work.car.detail.StandardDescriptionActivity
|
import com.xw.yunwei.utils.DialogFactory
|
import kotlinx.coroutines.CoroutineExceptionHandler
|
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.launch
|
import org.greenrobot.eventbus.EventBus
|
import org.json.JSONObject
|
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.inject
|
import java.io.IOException
|
import java.net.ConnectException
|
import java.net.SocketException
|
import java.net.SocketTimeoutException
|
import java.net.UnknownHostException
|
|
object MessageHandler : KoinComponent {
|
var TAG = "zmc-${this.javaClass.simpleName}"
|
val userRepository: UserRepository by inject()
|
val taskRepository: TaskRepository by inject()
|
|
fun handlePushEvent(content: String?, isPush: Boolean = false) {
|
try {
|
handlePushEvent(JSONObject(content ?: ""), isPush)
|
} catch (e: Exception) {
|
ToastUtilCommon.showError("未获取到消息详情")
|
LogUtils.e("zmc-MessageHandler", "handlePushEvent content = $content error = $e")
|
}
|
}
|
|
fun handlePushEvent(map: Map<String?, String?>?, isPush: Boolean = false) {
|
map?.let {
|
handlePushEvent(map.toJSONObject(), isPush)
|
}
|
}
|
|
@OptIn(DelicateCoroutinesApi::class)
|
fun handlePushEvent(jsob: JSONObject, isPush: Boolean) {
|
LogUtils.i("zmc-MessageHandler", "handlePushEvent $jsob isPush = $isPush")
|
TaskVM.needRefresh.value = true
|
/**
|
* content:消息内容
|
* strategy:推送策略 1=新增事故,2=事故即将超时提示,3=事故超时提示,4=排班信息变动,5=事故状态变更,6=新增任务,7=任务过期提示,8=版本更新提示,9=变更协议政策内容,10=变更协议内容并需用户授权,11=打卡成功通知, 12=强制升级
|
* type:类型,事故需要,根据不同的id查询不同的事故详情 无-null 1=车辆检测 2=车辆充电 3=车辆整备 4=整备洗车 5=车辆维修 6=其他常规任务 7=事故任务
|
* id:页面id(事故为事故id),无-null或0
|
*/
|
val content = jsob.optString("content")
|
val strategy = jsob.optInt("strategy")
|
val type = jsob.optInt("type")
|
val id = jsob.optString("id")
|
handleMsg(strategy, id, isPush)
|
}
|
|
private fun handleMsg(
|
strategy: Int,
|
id: String,
|
isPush: Boolean
|
) {
|
runOnMainThread {
|
val currentShowActivity = MyApp.myApp.getCurrentShowActivity()
|
LogUtils.i(
|
"zmc-MessageHandler", "handlePushEvent ${currentShowActivity.javaClass.name}"
|
)
|
when (strategy) {
|
1, 2, 3, 5 -> { // 1=新增事故,2=事故即将超时提示,3=事故超时提示,5=事故状态变更 点击都跳事故详情
|
if (strategy == 5 && isPush) return@runOnMainThread
|
checkTaskCouldInDetail(id) {
|
if (!it) {
|
ToastUtilCommon.showSuc("事故处理完成,已归档")
|
return@checkTaskCouldInDetail
|
}
|
currentShowActivity.startActivity(
|
Intent(currentShowActivity, AccidentDetailActivity::class.java).apply {
|
putExtra("taskId", id.toLong())
|
})
|
}
|
}
|
|
4 -> { // 排班信息变动
|
currentShowActivity.startActivity(
|
Intent(currentShowActivity, SchedulingActivity::class.java)
|
)
|
}
|
|
6, 7 -> { // 6=新增任务,7=任务过期提示 点击都跳任务详情
|
if (isPush) return@runOnMainThread
|
if (strategy == 6 && id == "0") { // 多条任务 跳转任务中心待处理页面
|
EventBus.getDefault().post(SwitchTabMain(1))
|
EventBus.getDefault().post(SwitchTabTask(2))
|
currentShowActivity.startActivity(
|
Intent(
|
currentShowActivity,
|
MainActivity::class.java
|
)
|
)
|
} else {
|
currentShowActivity.startActivity(
|
Intent(
|
currentShowActivity,
|
NormalTaskDetailActivity::class.java
|
).apply {
|
putExtra("taskId", id.toLong())
|
})
|
}
|
}
|
|
8, 12 -> { // 升级
|
if (strategy == 8 && isPush) return@runOnMainThread
|
showUpdateDialog(currentShowActivity)
|
}
|
|
9, 10 -> { // 变更协议内容
|
if (strategy == 9 && isPush) return@runOnMainThread
|
if (strategy == 9) {
|
currentShowActivity.startActivity(
|
Intent(currentShowActivity, ProtocolActivity::class.java)
|
)
|
} else {
|
MMKVManager.getInstance().saveBoolean(KeyPreferences.NEED_READ, true)
|
showProtocolDialog(currentShowActivity, true)
|
}
|
}
|
}
|
}
|
}
|
|
//检测任务是否能够进入详情页
|
private fun checkTaskCouldInDetail(taskId: String, block: (could: Boolean) -> Unit) {
|
launchRequest {
|
taskRepository.vehicleAccidentDetail(taskId)?.also {
|
runOnMainThread {
|
block.invoke(it.status != 2)
|
}
|
}
|
}
|
}
|
|
fun Map<String?, String?>.toJSONObject(): JSONObject {
|
return JSONObject().apply {
|
this@toJSONObject.forEach { (key, value) ->
|
if (key != null) {
|
put(key, value ?: JSONObject.NULL)
|
}
|
}
|
}
|
}
|
|
fun showUpdateDialog(currentShowActivity: Activity) {
|
launchRequest {
|
userRepository.getVersion()?.let {
|
runOnMainThread {
|
UpdateManager.instance!!
|
.setContext(currentShowActivity)
|
.apkUrl(it.getDownloadUrl() ?: "")
|
.updateContent(it.updateDescription ?: "")
|
.updateVersionCode(it.versionCode ?: 1)
|
.updateVersionName(it.version ?: "1.0")
|
.updateForceUpdateFlag(it.forceUpdateFlag ?: 0)
|
.show()
|
}
|
}
|
}
|
}
|
|
fun showProtocolDialog(
|
currentShowActivity: Activity,
|
forced: Boolean,
|
dismissBlock: (() -> Unit)? = null
|
) {
|
launchRequest {
|
userRepository.getAgreeConfig()?.also { list ->
|
runOnMainThread {
|
showProtocolDialog(currentShowActivity, forced, list, dismissBlock)
|
}
|
}
|
}
|
}
|
|
//显示隐私弹窗
|
private fun showProtocolDialog(
|
currentShowActivity: Activity,
|
forced: Boolean,
|
list: List<AgreeInfo>,
|
dismissBlock: (() -> Unit)? = null
|
) {
|
DialogFactory.produce(currentShowActivity).cornerRadius(15f).cancelable(!forced).show {
|
customView(
|
com.xw.yunwei.R.layout.dialog_protocol,
|
noVerticalPadding = true,
|
dialogWrapContent = true
|
)
|
cornerRadius(8f)
|
DataBindingUtil.bind<DialogProtocolBinding>(getCustomView())?.let { bind ->
|
val checked = mutableSetOf<AgreeInfo>()
|
|
fun refreshCheck(imageView: ImageView, checked: Boolean) {
|
imageView.setImageResource(if (checked) R.mipmap.icon_tick_circle_blue else R.mipmap.icon_circle_gray2)
|
}
|
|
fun checkAllChecked() {
|
(0..<bind.llAgree.childCount).forEachIndexed { index, i ->
|
val checked = checked.contains(list[index])
|
refreshCheck(
|
bind.llAgree.getChildAt(index).findViewById<ImageView>(R.id.iv_check),
|
checked
|
)
|
}
|
refreshCheck(bind.ivCheckAll, checked.size == list.size)
|
}
|
|
list.forEach { info ->
|
val itemView = inflate(
|
currentShowActivity,
|
R.layout.item_protocol,
|
null
|
).apply {
|
findViewById<ImageView>(R.id.iv_check).apply {
|
setOnClickListener {
|
if (checked.contains(info)) {
|
checked.remove(info)
|
} else {
|
checked.add(info)
|
}
|
checkAllChecked()
|
}
|
}
|
findViewById<TextView>(R.id.tv_name).apply {
|
text = info.name
|
setOnClickListener {
|
// if (!checked.contains(info)) {
|
// checked.add(info)
|
// checkAllChecked()
|
// }
|
currentShowActivity.startActivity(
|
Intent(
|
currentShowActivity,
|
StandardDescriptionActivity::class.java
|
).apply {
|
putExtra("type", info.id?.toInt())
|
putExtra("webType", 1)
|
putExtra("title", info.name)
|
}
|
)
|
}
|
}
|
}
|
bind.llAgree.addView(itemView)
|
}
|
bind.llCheckAll.setOnClickListener {
|
if (checked.size != list.size) {
|
checked.addAll(list)
|
} else {
|
checked.clear()
|
}
|
checkAllChecked()
|
}
|
bind.btnLeft.setOnClickListener {
|
dismiss()
|
if (forced) {
|
currentShowActivity.finishAffinity()
|
android.os.Process.killProcess(android.os.Process.myPid())
|
}
|
}
|
bind.btnRight.setOnClickListener {
|
if (checked.size != list.size) {
|
ToastUtilCommon.showError("请勾选全部协议后再确认同意")
|
return@setOnClickListener
|
}
|
MMKVManager.getInstance().saveBoolean(KeyPreferences.NEED_READ, false)
|
dismiss()
|
}
|
|
}
|
setOnDismissListener { dismissBlock?.invoke() }
|
}
|
}
|
|
private val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
|
LogUtils.e(TAG, "Uncaught coroutine exception: ${throwable.message}")
|
runOnMainThread {
|
ToastUtilCommon.showError(getNetworkErrorMessage(throwable))
|
}
|
}
|
|
private suspend fun errorHandling(
|
e: Throwable,
|
error: suspend (code: Int, msg: String) -> Unit
|
) {
|
if (e is ApiException) {
|
when {
|
e.isTokenExpired() -> {
|
MMKVManager.getInstance().clear()
|
ToastUtilCommon.showWarn("登录已过期,请重新登录")
|
CoroutineScope(Dispatchers.IO + exceptionHandler).launch {
|
delay(1000)
|
AppUtils.relaunchApp(true)
|
}
|
}
|
|
else -> {
|
error.invoke(e.code, e.message ?: "")
|
}
|
}
|
} else {
|
val errorMsg = getNetworkErrorMessage(e)
|
error.invoke(-1, errorMsg)
|
}
|
}
|
|
/**
|
* 获取网络异常的友好提示信息
|
*/
|
private fun getNetworkErrorMessage(e: Throwable): String {
|
return when (e) {
|
is UnknownHostException -> "网络连接失败,请检查网络设置"
|
is ConnectException -> "无法连接到服务器,请检查网络"
|
is SocketTimeoutException -> "连接超时,请稍后重试"
|
is SocketException -> "网络异常,请检查网络连接"
|
is IOException -> "网络请求失败,请检查网络"
|
else -> e.message ?: "未知错误"
|
}
|
}
|
|
//运行在主线程
|
private fun runOnMainThread(block: suspend () -> Unit) {
|
CoroutineScope(Dispatchers.Main + exceptionHandler).launch {
|
block()
|
}
|
}
|
|
private fun launchRequest(
|
error: suspend (code: Int, msg: String) -> Unit = { code, msg ->
|
ToastUtilCommon.showError(msg)
|
LogUtils.e(TAG, "launchRequest: code = $code msg = $msg")
|
}, request: suspend () -> Unit
|
) {
|
CoroutineScope(Dispatchers.IO + exceptionHandler).launch {
|
try {
|
request()
|
} catch (e: Throwable) {
|
try {
|
errorHandling(e, error)
|
} catch (handlingError: Throwable) {
|
LogUtils.e(TAG, "Error handling failed: ${handlingError.message}")
|
}
|
}
|
}
|
}
|
}
|