[2.8.0-f] 屏幕适配 删除废弃代码
This commit is contained in:
@@ -82,6 +82,8 @@ dependencies {
|
||||
implementation rootProject.ext.dependencies.androidxconstraintlayout
|
||||
implementation rootProject.ext.dependencies.androidxrecyclerview
|
||||
implementation rootProject.ext.dependencies.flexbox
|
||||
implementation rootProject.ext.dependencies.androidautoSize
|
||||
|
||||
if (Boolean.valueOf(USE_MAVEN_PACKAGE)) {
|
||||
implementation rootProject.ext.dependencies.mogoserviceapi
|
||||
implementation rootProject.ext.dependencies.modulecommon
|
||||
|
||||
@@ -152,89 +152,10 @@ internal object BadCaseManager : LifecycleEventObserver {
|
||||
}else{
|
||||
ToastUtils.showShort("请勿连续点击,稍后再试")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private fun register() {
|
||||
scope?.launch(Dispatchers.Default) {
|
||||
while (true) {
|
||||
showBadCaseInternal(AutoPilotRecord())
|
||||
CallerLogger.d("$M_DEVA$TAG", "---- 开始监听BadCase事件 ----")
|
||||
val old = record
|
||||
if (old == null || old.consumed) {
|
||||
CallerLogger.d("$M_DEVA$TAG", "---- 当前事件已消费 -- value: $old")
|
||||
var receive = channel.receive()
|
||||
var oldT = record?.toLongTime() ?: 0L
|
||||
var newT = receive.toLongTime()
|
||||
if (isValid(oldT, newT)) {
|
||||
record = receive
|
||||
CallerLogger.d("$M_DEVA$TAG", "---- 时间有效,开始展示入口 ---")
|
||||
withContext(Dispatchers.Main) {
|
||||
showBadCaseInternal(receive)
|
||||
}
|
||||
continue
|
||||
}
|
||||
CallerLogger.d("$M_DEVA$TAG", "---- 时间无效,移除管道中无用数据 ---")
|
||||
presenter.deleteRecord(receive)
|
||||
while (oldT != 0L && newT != 0L && (newT - oldT) >= CASE_EXPIRE_DURATION) {
|
||||
oldT = newT
|
||||
receive = channel.receive()
|
||||
newT = receive.toLongTime()
|
||||
presenter.deleteRecord(receive)
|
||||
}
|
||||
receive.takeIf { it.key != old?.key }?.also {
|
||||
CallerLogger.d(
|
||||
"$M_DEVA$TAG",
|
||||
"record: [$record] is displaying for rest ..."
|
||||
)
|
||||
record = receive
|
||||
withContext(Dispatchers.Main) {
|
||||
showBadCaseInternal(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun recoverBadCase() {
|
||||
scope?.launchWhenCreated {
|
||||
val lastModified = presenter.getLastModified()
|
||||
val list = withContext(Dispatchers.IO) {
|
||||
try {
|
||||
CallerLogger.d("$M_DEVA$TAG", " --- 1 ----")
|
||||
CallerLogger.d("$M_DEVA$TAG", "恢复持久化的数据 - 最后修改时间:$lastModified")
|
||||
presenter.getUnConsumedRecords()
|
||||
.fold(mutableListOf<AutoPilotRecord>()) { acc, record ->
|
||||
if (isValid(lastModified, record.toLongTime())) {
|
||||
acc.add(record)
|
||||
} else {
|
||||
presenter.deleteRecord(record)
|
||||
}
|
||||
acc
|
||||
}
|
||||
} catch (t: Throwable) {
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
if (list.isEmpty()) {
|
||||
CallerLogger.d("$M_DEVA$TAG", "没有要恢复的数据")
|
||||
} else {
|
||||
list.forEach {
|
||||
CallerLogger.d("$M_DEVA$TAG", "恢复的接管数据:$it")
|
||||
channel.send(it)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun isValid(oldT: Long, newT: Long): Boolean {
|
||||
return oldT == 0L || newT == 0L || (newT - oldT >= 0 && (newT - oldT) < CASE_EXPIRE_DURATION)
|
||||
}
|
||||
|
||||
fun onReceiveBadCaseRecord(record: RecordPanelOuterClass.RecordPanel,activity: Activity) {
|
||||
CallerLogger.d("$M_DEVA$TAG", "收到录包结果回调${record}")
|
||||
CallerLogger.d("$M_DEVA$TAG", "开始创建被动录包弹窗,window num=${BadCaseConfig.windowNum}")
|
||||
@@ -251,67 +172,6 @@ internal object BadCaseManager : LifecycleEventObserver {
|
||||
}
|
||||
}
|
||||
|
||||
private fun CoroutineScope.showBadCaseInternal(record: AutoPilotRecord) = launch {
|
||||
viewHolder?.get()?.also { itx ->
|
||||
presenter.updateLastModified(CallerAutopilotVehicleStateListenerManager.getAutopilotTimeStamp())
|
||||
|
||||
itx.onClick {
|
||||
showBadCaseFloat(
|
||||
onDismiss = {
|
||||
hideFloat?.invoke()
|
||||
hideFloat = null
|
||||
},
|
||||
onSelect = { reason ->
|
||||
val uploadResult = presenter.upload(mutableMapOf<String, String>().also { itx ->
|
||||
itx["carLicense"] = MoGoAiCloudClientConfig.getInstance().sn
|
||||
itx["filename"] = record.fileName ?: ""
|
||||
itx["filesize"] = record.total.toString()
|
||||
itx["key"] = record.key ?: ""
|
||||
itx["reason"] = reason.reason ?: ""
|
||||
itx["duration"] = record.duration.toInt().toString()
|
||||
itx["timestamp"] = record.timestamp
|
||||
itx["channel"] = "0"
|
||||
})
|
||||
if (uploadResult == null || uploadResult.code != 200) {
|
||||
it.context.toast("上报失败")
|
||||
} else {
|
||||
it.context.toast("上报成功")
|
||||
record.consumed = true
|
||||
withContext(Dispatchers.IO) {
|
||||
presenter.deleteRecord(record)
|
||||
}
|
||||
|
||||
hideFloat?.invoke()
|
||||
hideFloat = null
|
||||
}
|
||||
})
|
||||
}
|
||||
dismissAfterDelay()?.also { dismissJob = it }
|
||||
}
|
||||
}
|
||||
|
||||
private fun dismissAfterDelay(): Job? {
|
||||
dismissJob?.takeIf { it.isActive }?.cancel()
|
||||
return scope?.launch {
|
||||
delay(CASE_EXPIRE_DURATION)
|
||||
record?.also {
|
||||
it.consumed = true
|
||||
withContext(Dispatchers.IO) {
|
||||
presenter.deleteRecord(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showBadCaseFloat(onDismiss: () -> Unit, onSelect:suspend (reason: Reason) -> Unit) {
|
||||
val activity = viewHolder?.get()?.context as? FragmentActivity ?: throw IllegalStateException("please ensure context is FragmentActivity.")
|
||||
BadCaseView(activity).also { itx ->
|
||||
itx.register(record, onDismiss, onSelect)
|
||||
activity.enqueuePop(itx, 960.PX, WindowManager.LayoutParams.MATCH_PARENT, key = "BadCaseFloatWindow_").also {
|
||||
hideFloat = it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStateChanged(source: LifecycleOwner, event: Event) {
|
||||
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
package com.zhjt.mogo_core_function_devatools.badcase.biz
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.graphics.drawable.StateListDrawable
|
||||
import android.util.AttributeSet
|
||||
import android.util.StateSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.mogo.eagle.core.utilcode.kotlin.*
|
||||
import com.mogo.eagle.core.utilcode.rv.divider.CommonDividerItemDecoration
|
||||
import com.zhjt.mogo_core_function_devatools.R
|
||||
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.BadCaseResponse
|
||||
import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord
|
||||
import kotlinx.android.synthetic.main.layout_badcase_collect.view.*
|
||||
import kotlinx.coroutines.launch
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
internal class BadCaseView: ConstraintLayout {
|
||||
|
||||
@Volatile
|
||||
private var selectCase: BadCaseResponse.Reason? = null
|
||||
|
||||
@Volatile
|
||||
private var cases: List<BadCaseResponse.Reason>? = null
|
||||
|
||||
private val presenter by lazy {
|
||||
BadCasePresenter()
|
||||
}
|
||||
|
||||
private var onDismiss: (() -> Unit)? = null
|
||||
private var onSelect:(suspend (reason: BadCaseResponse.Reason) -> Unit)? = null
|
||||
|
||||
private val scope by lazy {
|
||||
lifecycleOwner.lifecycleScope
|
||||
}
|
||||
|
||||
private var record: AutoPilotRecord? = null
|
||||
|
||||
constructor(context: Context) : this(context, null)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||
LayoutInflater.from(context).inflate(R.layout.layout_badcase_collect, this, true)
|
||||
background = ColorDrawable(Color.parseColor("#F0151D41"))
|
||||
isClickable = true
|
||||
close?.onClick {
|
||||
onDismiss?.invoke()
|
||||
}
|
||||
//fitsSystemWindows = true
|
||||
cancel?.also {
|
||||
it.background = shape(solid = Color.parseColor("#3B4577"), radius = 16)
|
||||
it.onClick {
|
||||
onDismiss?.invoke()
|
||||
}
|
||||
}
|
||||
ok?.also {
|
||||
val enabled = gradient(radius = 16.PX, orientation = GradientDrawable.Orientation.LEFT_RIGHT, centerX = 0.06f, startColor = Color.rgb(35, 146, 252), endColor = Color.rgb(28, 75, 252))
|
||||
val disabled = gradient(radius = 16.PX, orientation = GradientDrawable.Orientation.LEFT_RIGHT, centerX = 0.06f, startColor = Color.rgb(24, 71, 129), endColor = Color.rgb(21, 46, 129))
|
||||
it.background = object : StateListDrawable() {}.also { itx ->
|
||||
itx.addState(intArrayOf(android.R.attr.state_enabled), enabled)
|
||||
itx.addState(StateSet.WILD_CARD, disabled)
|
||||
}
|
||||
it.onClick {
|
||||
selectCase?.run {
|
||||
scope.launch {
|
||||
onSelect?.invoke(this@run)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
scope.launchWhenCreated {
|
||||
time_of_take_over?.text = "接管时间: ${SimpleDateFormat("yyyy.MM.dd HH:mm", Locale.getDefault()).format(record?.toLongTime() ?: System.currentTimeMillis())}"
|
||||
showLoading()
|
||||
presenter.loadBadCases(true).also {
|
||||
cases = it
|
||||
refresh(it)
|
||||
}
|
||||
hideLoading()
|
||||
}
|
||||
}
|
||||
|
||||
private fun refresh(causes: List<BadCaseResponse.Reason>) {
|
||||
cases = causes
|
||||
rv_take_over?.let {
|
||||
it.layoutManager = LinearLayoutManager(it.context, LinearLayoutManager.VERTICAL, false)
|
||||
it.addItemDecoration(
|
||||
CommonDividerItemDecoration
|
||||
.Builder()
|
||||
.verticalInnerSpace(50.PX)
|
||||
.build())
|
||||
it.adapter = object : RecyclerView.Adapter<BadCaseViewHolder>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BadCaseViewHolder = BadCaseViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.layout_badcase_item, parent, false))
|
||||
override fun onBindViewHolder(holder: BadCaseViewHolder, position: Int) {
|
||||
val cases = cases
|
||||
if (cases == null || cases.isEmpty()) {
|
||||
return
|
||||
}
|
||||
if (position >= cases.size) {
|
||||
return
|
||||
}
|
||||
val case = cases[position]
|
||||
holder.bindData(case)
|
||||
}
|
||||
override fun getItemCount(): Int = cases?.size ?: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showLoading() {
|
||||
pb?.let {
|
||||
it.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideLoading() {
|
||||
pb?.let {
|
||||
it.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
private inner class BadCaseViewHolder(item: View) : RecyclerView.ViewHolder(item) {
|
||||
|
||||
private val check: ImageView = item.findViewById(R.id.check)
|
||||
private val reason: TextView = item.findViewById(R.id.reason)
|
||||
|
||||
init {
|
||||
check.background = StateListDrawable().also {
|
||||
it.addState(intArrayOf(android.R.attr.state_selected), ContextCompat.getDrawable(itemView.context, R.drawable.icon_ap_badcase_check))
|
||||
it.addState(StateSet.WILD_CARD, ContextCompat.getDrawable(itemView.context, R.drawable.icon_ap_badcase_default))
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun bindData(case: BadCaseResponse.Reason) {
|
||||
check.isSelected = case.isChecked
|
||||
reason.text = case.reason ?: ""
|
||||
if (case.isChecked) {
|
||||
ok?.isSelected = true
|
||||
}
|
||||
itemView.onClick {
|
||||
case.isChecked = !case.isChecked
|
||||
selectCase = case
|
||||
cancelOtherChecked(case)
|
||||
ok?.isEnabled = hasCheckedItem()
|
||||
rv_take_over?.adapter?.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasCheckedItem(): Boolean = cases?.find { it.isChecked } != null
|
||||
|
||||
private fun cancelOtherChecked(case: BadCaseResponse.Reason) {
|
||||
val cases = cases
|
||||
if (cases == null || cases.isEmpty()) {
|
||||
return
|
||||
}
|
||||
cases.filterNot { it == case }.forEach {
|
||||
it.isChecked = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun register(record: AutoPilotRecord?, onDismiss: () -> Unit, onSelect:suspend (reason: BadCaseResponse.Reason) -> Unit) {
|
||||
this.record = record
|
||||
this.onDismiss = onDismiss
|
||||
this.onSelect = onSelect
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import mogo.telematics.pad.MessagePad
|
||||
import com.zhidao.loglib.upload.UploadManager
|
||||
import me.jessyan.autosize.utils.AutoSizeUtils
|
||||
import java.io.File
|
||||
import java.lang.reflect.Field
|
||||
|
||||
@@ -309,7 +310,7 @@ class PassiveBadCaseWindow constructor(activity: Activity) : View.OnTouchListene
|
||||
SizeUtils.dp2px(10f),
|
||||
SizeUtils.dp2px(10f),
|
||||
SizeUtils.dp2px(10f))
|
||||
checkBox.textSize = SizeUtils.sp2px(9f).toFloat()
|
||||
checkBox.textSize = AutoSizeUtils.dp2px(mActivity,34f).toFloat()
|
||||
checkBox.text = it.reason
|
||||
checkBox.isChecked = it.isChecked
|
||||
checkBox.setOnCheckedChangeListener(this@PassiveBadCaseWindow)
|
||||
|
||||
@@ -1,257 +0,0 @@
|
||||
package com.zhjt.mogo_core_function_devatools.feedback
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotRecordListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotRecordListenerManager
|
||||
import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager
|
||||
import com.mogo.eagle.core.utilcode.kotlin.PX
|
||||
import com.mogo.eagle.core.utilcode.kotlin.onDetach
|
||||
import com.mogo.eagle.core.utilcode.kotlin.safeCancel
|
||||
import com.mogo.eagle.core.utilcode.kotlin.scope
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_DEVA
|
||||
import com.mogo.eagle.core.utilcode.mogo.toast.TipToast
|
||||
import com.mogo.eagle.core.utilcode.util.KeyboardUtils
|
||||
import com.mogo.eagle.core.utilcode.util.ThreadUtils
|
||||
import com.zhjt.mogo_core_function_devatools.R
|
||||
import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord
|
||||
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.BadCaseResponse.Reason
|
||||
import com.zhjt.mogo_core_function_devatools.badcase.toRecord
|
||||
import com.zhjt.mogo_core_function_devatools.ext.enqueuePop
|
||||
import com.zhjt.mogo_core_function_devatools.ext.toast
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.FeedBackView
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback.BadCase
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.impl.FeedbackPresenter
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.callback.IFeedbackCallback
|
||||
import kotlinx.coroutines.*
|
||||
import record_cache.RecordPanelOuterClass
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import kotlin.Result.Companion
|
||||
|
||||
internal object FeedbackManager {
|
||||
|
||||
const val TAG = "feedback"
|
||||
private var hideFloat: (() -> Unit)? = null
|
||||
private val presenter by lazy { FeedbackPresenter() }
|
||||
|
||||
fun showFeedbackWindow(ctx: Context) {
|
||||
val activity = ctx as? FragmentActivity ?: throw IllegalStateException("please ensure context is FragmentActivity.")
|
||||
activity.enqueuePop(FeedBackView(ctx).also { itx ->
|
||||
itx.registerCallback(object : IFeedbackCallback {
|
||||
override fun onClose(v: View) {
|
||||
KeyboardUtils.hideSoftInput(v)
|
||||
hideFloat?.invoke()
|
||||
}
|
||||
override fun onBadCaseItemClicked(reason: Reason) {
|
||||
val oldData = itx.adapter.data ?: return
|
||||
if (reason.isChecked) {
|
||||
return
|
||||
}
|
||||
reason.isChecked = true
|
||||
val badCase = oldData.firstOrNull() as? BadCase
|
||||
badCase?.reasons?.filterNot { it.id == reason.id }?.forEach {
|
||||
it.isChecked = false
|
||||
}
|
||||
itx.adapter.notifyItemChanged(0)
|
||||
}
|
||||
@SuppressLint("SetTextI18n") override fun onStartBadCaseRecord(record: TextView) {
|
||||
if (!CallerAutoPilotManager.isConnected()) {
|
||||
TipToast.shortTip("请检查车机与域控制器连接是否正常")
|
||||
return
|
||||
}
|
||||
val data = itx.adapter.data ?: return
|
||||
val badCase = data.firstOrNull() as? BadCase ?: return
|
||||
val checked = badCase.reasons.find { it.isChecked }
|
||||
if (checked == null) {
|
||||
TipToast.shortTip("请选择一个Case")
|
||||
return
|
||||
}
|
||||
|
||||
record.scope.launch {
|
||||
val taskId = presenter.getBadCaseTaskId()
|
||||
val listener = object : IMoGoAutopilotRecordListener {
|
||||
override fun onAutopilotRecordResult(recordPanel: RecordPanelOuterClass.RecordPanel) {
|
||||
super.onAutopilotRecordResult(recordPanel)
|
||||
record.scope.launch {
|
||||
val newRecord = recordPanel.toRecord()
|
||||
CallerLogger.d("${M_DEVA}${TAG}", "-- 收到工控机录制任务回调 -- $recordPanel")
|
||||
if (newRecord.type == 1 && newRecord.id == taskId) {
|
||||
when(newRecord.stat) {
|
||||
100, 101 -> {
|
||||
//成功结束录制
|
||||
stopRecordLog(newRecord)
|
||||
launch {
|
||||
val ret = upload(record.context, badCase, checked, newRecord)
|
||||
if (!ret) {
|
||||
record.text = "开始录制"
|
||||
record.setTag(R.id.feed_back_badcase_tag, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
300 -> {
|
||||
//开始录制
|
||||
startRecordLog(newRecord)
|
||||
}
|
||||
200 -> {
|
||||
TipToast.shortTip("录制失败")
|
||||
hideFloat?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CallerAutopilotRecordListenerManager.addListener("Feedback", listener)
|
||||
record.onDetach {
|
||||
CallerAutopilotRecordListenerManager.removeListener("Feedback")
|
||||
hideFloat = null
|
||||
}
|
||||
record.text = "结束录制"
|
||||
record.setTag(R.id.feed_back_badcase_tag, 1)
|
||||
record.setTag(R.id.feed_back_badcase_taskid_tag, taskId)
|
||||
recordBag(1, taskId)
|
||||
launch {
|
||||
CallerLogger.d("${M_DEVA}${TAG}", "延时20秒开始....")
|
||||
launch {
|
||||
var left = 20
|
||||
while (left >= 0) {
|
||||
record.text = "结束录制(${left}s)"
|
||||
delay(1000)
|
||||
left--
|
||||
}
|
||||
}.also {
|
||||
record.setTag(R.id.feed_back_badcase_count_down_job, it)
|
||||
}
|
||||
delay(20000) //延时20秒
|
||||
CallerLogger.d("${M_DEVA}${TAG}", "延时20秒结束....")
|
||||
record.text = "正在结束录制"
|
||||
(record.getTag(R.id.feed_back_badcase_count_down_job) as? Job)?.safeCancel()
|
||||
record.setTag(R.id.feed_back_badcase_tag, 2)
|
||||
stopRecordBag(1, taskId)
|
||||
}.also { itx ->
|
||||
itx.invokeOnCompletion {
|
||||
if (it is CancellationException) {
|
||||
CallerLogger.d("${M_DEVA}${TAG}", "延时任务取消")
|
||||
}
|
||||
}
|
||||
record.setTag(R.id.feed_back_badcase_job, itx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStopBadCaseRecord(record: TextView) {
|
||||
val tag = (record.getTag(R.id.feed_back_badcase_tag) as? Int) ?: throw IllegalStateException("这个状态不存在")
|
||||
if (tag == 2) {
|
||||
TipToast.shortTip("正在结束录制,请稍候...")
|
||||
return
|
||||
}
|
||||
val taskId = (record.getTag(R.id.feed_back_badcase_taskid_tag) as? Int) ?: throw IllegalStateException("TaskId 不存在")
|
||||
(record.getTag(R.id.feed_back_badcase_job) as? Job)?.safeCancel()
|
||||
(record.getTag(R.id.feed_back_badcase_count_down_job) as? Job)?.safeCancel()
|
||||
record.text = "正在结束录制"
|
||||
record.setTag(R.id.feed_back_badcase_tag, 2)
|
||||
record.scope.launch {
|
||||
stopRecordBag(1, taskId)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
width = 960.PX,
|
||||
height = WindowManager.LayoutParams.MATCH_PARENT,
|
||||
key = "FeedBackFloatWindow_",
|
||||
onOuterViewClicked = {
|
||||
KeyboardUtils.hideSoftInput(it)
|
||||
}
|
||||
).also { hideFloat = it }
|
||||
}
|
||||
|
||||
private fun startRecordLog(record: AutoPilotRecord) {
|
||||
val prefix = record.fileName?.split(File.separator)?.last()?.substringBeforeLast(".")?.let { "BadCase-$it" } ?: "BadCase-${SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault()).format(Date())}"
|
||||
CallerLogger.d("${M_DEVA}${TAG}", "录制Bag开始, 触发录制全量日志 ...")
|
||||
CallerLogger.d("${M_DEVA}${TAG}", "全量日志前缀: $prefix")
|
||||
CallerDevaToolsManager.startCatchLog(1, prefix)
|
||||
}
|
||||
|
||||
private fun stopRecordLog(newRecord: AutoPilotRecord) {
|
||||
val prefix = newRecord.fileName?.split(File.separator)?.last()?.substringBeforeLast(".")?.let { "BadCase-$it" } ?: "BadCase-${SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault()).format(Date())}"
|
||||
CallerLogger.d("${M_DEVA}${TAG}", "录制Bag完成, 触发结束录制全量日志 ...")
|
||||
CallerDevaToolsManager.stopCatchLog(prefix)
|
||||
}
|
||||
|
||||
private suspend fun upload(ctx: Context, badCase: BadCase, checked: Reason, record: AutoPilotRecord): Boolean {
|
||||
try {
|
||||
val remark = badCase.remark.text
|
||||
return presenter.upload(mutableMapOf<String, String>().also { itx ->
|
||||
itx["carLicense"] = MoGoAiCloudClientConfig.getInstance().sn
|
||||
itx["filename"] = record.fileName ?: ""
|
||||
itx["filesize"] = record.total.toString()
|
||||
itx["key"] = record.key ?: ""
|
||||
itx["reason"] = checked.reason ?: ""
|
||||
itx["duration"] = record.duration.toInt().toString()
|
||||
itx["timestamp"] = record.timestamp
|
||||
itx["channel"] = "1"
|
||||
if (!TextUtils.isEmpty(remark)) {
|
||||
itx["remark"] = remark.toString()
|
||||
}
|
||||
}).let {
|
||||
if (it == null || it.code != 200) {
|
||||
ctx.toast("上报失败")
|
||||
false
|
||||
} else {
|
||||
ctx.toast("上报成功")
|
||||
hideFloat?.invoke()
|
||||
true
|
||||
}
|
||||
}
|
||||
} catch (t: Throwable) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun recordBag(type: Int, id: Int) = suspendCancellableCoroutine<Unit> {
|
||||
val future = ThreadUtils.getIoPool().submit {
|
||||
try {
|
||||
CallerAutoPilotManager.recordPackage(type, id)
|
||||
it.resumeWith(Result.success(Unit))
|
||||
} catch (t: Throwable) {
|
||||
it.resumeWith(Companion.failure(t))
|
||||
}
|
||||
}
|
||||
it.invokeOnCancellation {
|
||||
try {
|
||||
future.cancel(true)
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun stopRecordBag(type: Int, id: Int) = suspendCancellableCoroutine<Unit> {
|
||||
val future = ThreadUtils.getIoPool().submit {
|
||||
try {
|
||||
CallerAutoPilotManager.stopRecord(type, id)
|
||||
it.resumeWith(Result.success(Unit))
|
||||
} catch (t: Throwable) {
|
||||
it.resumeWith(Companion.failure(t))
|
||||
}
|
||||
}
|
||||
it.invokeOnCancellation {
|
||||
try {
|
||||
future.cancel(true)
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
package com.zhjt.mogo_core_function_devatools.feedback.biz
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.util.AttributeSet
|
||||
import android.util.Log
|
||||
import android.view.*
|
||||
import android.widget.EditText
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.Lifecycle.Event.ON_DESTROY
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.mogo.eagle.core.utilcode.kotlin.*
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_DEVA
|
||||
import com.zhjt.mogo_core_function_devatools.R
|
||||
import com.zhjt.mogo_core_function_devatools.badcase.BadCaseManager
|
||||
import com.zhjt.mogo_core_function_devatools.ext.softKeyboardHeightChanged
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.FeedbackManager
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.adapter.FeedbackAdapter
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.adapter.vh.BadCaseFBViewHolder
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.impl.FeedbackPresenter
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.callback.IFeedbackCallback
|
||||
import kotlinx.android.synthetic.main.layout_fb.view.*
|
||||
|
||||
|
||||
internal class FeedBackView : ConstraintLayout {
|
||||
|
||||
private var cb: IFeedbackCallback? = null
|
||||
private var softKeyboardCb: (() -> Unit)? = null
|
||||
private var editOutRect: Rect = Rect()
|
||||
private val presenter by lazy {
|
||||
FeedbackPresenter()
|
||||
}
|
||||
private var rvTransAnimator: ViewPropertyAnimator? = null
|
||||
|
||||
private val scope by lazy {
|
||||
lifecycleOwner.lifecycleScope
|
||||
}
|
||||
|
||||
internal val adapter by lazy {
|
||||
FeedbackAdapter<Feedback> { itx ->
|
||||
if (itx is BadCaseFBViewHolder) {
|
||||
itx.itemView.findViewById<EditText>(R.id.et).also {
|
||||
val listener = object : ViewTreeObserver.OnPreDrawListener {
|
||||
override fun onPreDraw(): Boolean {
|
||||
it.viewTreeObserver.removeOnPreDrawListener(this)
|
||||
it.getGlobalVisibleRect(editOutRect)
|
||||
return true
|
||||
}
|
||||
}
|
||||
it.viewTreeObserver.addOnPreDrawListener(listener)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(context: Context) : this(context, null)
|
||||
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||
LayoutInflater.from(context).inflate(R.layout.layout_fb, this, true).also {
|
||||
observe(arrayOf(ON_DESTROY)) { itx ->
|
||||
if (itx == ON_DESTROY) {
|
||||
cb = null
|
||||
softKeyboardCb?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
background = ColorDrawable(Color.parseColor("#F0151D41"))
|
||||
close.onClick {
|
||||
cb?.onClose(this)
|
||||
}
|
||||
|
||||
top_mask?.background = gradient(orientation = GradientDrawable.Orientation.TOP_BOTTOM, startColor = Color.parseColor("#151D41"), endColor = Color.parseColor("#05151D41"))
|
||||
rv?.also {
|
||||
it.fixGestureConflictForViews(listOf(R.id.et))
|
||||
it.itemAnimator?.run {
|
||||
changeDuration = 0
|
||||
addDuration = 0
|
||||
moveDuration = 0
|
||||
removeDuration = 0
|
||||
}
|
||||
it.adapter = adapter
|
||||
it.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
||||
loadFeedbackAndRefresh()
|
||||
}
|
||||
val activity = context as? FragmentActivity
|
||||
activity?.also { itx ->
|
||||
itx.softKeyboardHeightChanged {
|
||||
CallerLogger.d("${M_DEVA}${FeedbackManager.TAG}", "-- onHeightChanged ---:H -> $it")
|
||||
if (it == 0) {
|
||||
transitionTo(0)
|
||||
} else {
|
||||
editOutRect.run {
|
||||
transitionTo(-( it - top + height() + 228.PX))
|
||||
}
|
||||
}
|
||||
}.also {
|
||||
softKeyboardCb = it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun transitionTo(targetY: Int) {
|
||||
rv?.also { itx ->
|
||||
rvTransAnimator?.cancel()
|
||||
itx.animate().translationY(targetY.toFloat()).setDuration(200).also {
|
||||
rvTransAnimator = it
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadFeedbackAndRefresh() {
|
||||
scope.launchWhenCreated {
|
||||
showLoading()
|
||||
CallerLogger.d("$M_DEVA${BadCaseManager.TAG}", "-- show loading ---")
|
||||
presenter.loadFeedBacks().also {
|
||||
CallerLogger.d("$M_DEVA${BadCaseManager.TAG}", "-- data load ${it.joinToString(",")} ---")
|
||||
adapter.data = it
|
||||
}
|
||||
CallerLogger.d("$M_DEVA${BadCaseManager.TAG}", "-- hide loading ---")
|
||||
hideLoading()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showLoading() {
|
||||
pb?.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
private fun hideLoading() {
|
||||
pb?.visibility = View.GONE
|
||||
}
|
||||
|
||||
fun registerCallback(cb: IFeedbackCallback) {
|
||||
this.cb = cb
|
||||
this.adapter.setCallback(cb)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package com.zhjt.mogo_core_function_devatools.feedback.biz.adapter
|
||||
|
||||
import android.util.Log
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.FeedbackManager
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.adapter.vh.BadCaseFBViewHolder
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.adapter.vh.base.FeedbackViewHolder
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback.BadCase
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.diff.FeedbackDiffCallback
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.callback.IFeedbackCallback
|
||||
|
||||
internal class FeedbackAdapter<T: Feedback>(val onHolderAttached: (holder: FeedbackViewHolder<*>) -> Unit): RecyclerView.Adapter<FeedbackViewHolder<T>>() {
|
||||
|
||||
companion object {
|
||||
const val ITEM_TYPE_BAD_CASE = 0x0101
|
||||
}
|
||||
|
||||
private var cb: IFeedbackCallback? = null
|
||||
|
||||
var data: List<T>? = null
|
||||
@Synchronized
|
||||
set(value) {
|
||||
val result = DiffUtil.calculateDiff(FeedbackDiffCallback(field, value))
|
||||
result.dispatchUpdatesTo(this)
|
||||
field = value
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
val data = data ?: return super.getItemViewType(position)
|
||||
when(val item = data[position]) {
|
||||
is BadCase -> {
|
||||
CallerLogger.d("${SceneConstant.M_DEVA}${FeedbackManager.TAG}", "item->$item")
|
||||
return ITEM_TYPE_BAD_CASE
|
||||
}
|
||||
}
|
||||
return super.getItemViewType(position)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FeedbackViewHolder<T> {
|
||||
when (viewType) {
|
||||
ITEM_TYPE_BAD_CASE -> {
|
||||
return BadCaseFBViewHolder(cb, parent) as FeedbackViewHolder<T>
|
||||
}
|
||||
else -> {
|
||||
throw IllegalStateException("不支持ViewType: $viewType")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: FeedbackViewHolder<T>, position: Int) {
|
||||
val item = data?.get(position) ?: return
|
||||
holder.onBind(item, position)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = data?.size ?: 0
|
||||
|
||||
fun setCallback(cb: IFeedbackCallback) {
|
||||
this.cb = cb
|
||||
}
|
||||
|
||||
override fun onViewAttachedToWindow(holder: FeedbackViewHolder<T>) {
|
||||
super.onViewAttachedToWindow(holder)
|
||||
onHolderAttached.invoke(holder)
|
||||
}
|
||||
}
|
||||
@@ -1,193 +0,0 @@
|
||||
package com.zhjt.mogo_core_function_devatools.feedback.biz.adapter.vh
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.GradientDrawable.Orientation.LEFT_RIGHT
|
||||
import android.graphics.drawable.StateListDrawable
|
||||
import android.text.Selection
|
||||
import android.text.TextUtils
|
||||
import android.text.TextUtils.TruncateAt.END
|
||||
import android.util.StateSet
|
||||
import android.util.TypedValue
|
||||
import android.view.*
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
import com.mogo.eagle.core.utilcode.kotlin.*
|
||||
import com.mogo.eagle.core.utilcode.util.KeyboardUtils
|
||||
import com.mogo.eagle.core.utilcode.util.ToastUtils
|
||||
import com.zhjt.mogo_core_function_devatools.R
|
||||
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.BadCaseResponse.Reason
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.adapter.vh.base.FeedbackViewHolder
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback.BadCase
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.callback.IFeedbackCallback
|
||||
import kotlin.Int.Companion
|
||||
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
internal class BadCaseFBViewHolder(cb: IFeedbackCallback?, parent: ViewGroup): FeedbackViewHolder<BadCase>(cb,
|
||||
LayoutInflater
|
||||
.from(parent.context)
|
||||
.inflate(R.layout.layout_fb_badcase, parent, false)) {
|
||||
|
||||
private val flex by lazy {
|
||||
itemView.findViewById<FlexboxLayout>(R.id.flex)
|
||||
}
|
||||
|
||||
private val et by lazy {
|
||||
itemView.findViewById<EditText>(R.id.et)
|
||||
}
|
||||
|
||||
private val etParent by lazy {
|
||||
itemView.findViewById<View>(R.id.et_root)
|
||||
}
|
||||
|
||||
private val words by lazy {
|
||||
itemView.findViewById<TextView>(R.id.words_count)
|
||||
}
|
||||
|
||||
private var first = false
|
||||
|
||||
init {
|
||||
itemView.findViewById<TextView>(R.id.record).also {
|
||||
it.background = gradient(radius = 16.PX, orientation = LEFT_RIGHT, centerX = 0.06f, startColor = Color.rgb(35, 146, 252), endColor = Color.rgb(28, 75, 252))
|
||||
it.onClick { _ ->
|
||||
val flag = (it.getTag(R.id.feed_back_badcase_tag) as? Int) ?: 0
|
||||
if (flag == 0) {
|
||||
cb?.onStartBadCaseRecord(it)
|
||||
} else {
|
||||
cb?.onStopBadCaseRecord(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
etParent.also {
|
||||
it.background = shape(solid = Color.parseColor("#263869"), radius = 20.PX)
|
||||
}
|
||||
|
||||
val action = Runnable { KeyboardUtils.showSoftInput(et) }
|
||||
et.onDetach {
|
||||
et.removeCallbacks(action)
|
||||
}
|
||||
et.onClick {
|
||||
it.post(action)
|
||||
etParent.background = shape(solid = Color.parseColor("#263869"), radius = 20.PX, stroke = Color.parseColor("#5EBFFF"), strokeWidth = 2.PX)
|
||||
}
|
||||
et.setOnEditorActionListener { _, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
KeyboardUtils.hideSoftInput(et)
|
||||
return@setOnEditorActionListener true
|
||||
}
|
||||
return@setOnEditorActionListener false
|
||||
}
|
||||
et.maxLines = Int.MAX_VALUE
|
||||
et.setHorizontallyScrolling(false)
|
||||
et.watch(
|
||||
200,
|
||||
onCountChanged = {
|
||||
if (first) {
|
||||
return@watch
|
||||
}
|
||||
words.visibility = View.VISIBLE
|
||||
words.spannableText(listOf(it.toString(), "/200"), listOf(Color.parseColor("#5EBFFF"), Color.WHITE))
|
||||
},
|
||||
onTextChanged = {
|
||||
if (it?.length ?: 0 > 0) {
|
||||
first = false
|
||||
}
|
||||
data().remark.text = it?.toString() ?: ""
|
||||
},
|
||||
onReachMaxCountAction = {
|
||||
ToastUtils.showShort("已超过最大字符数")
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun onBind(data: BadCase, position: Int) {
|
||||
super.onBind(data, position)
|
||||
flex.refresh(data)
|
||||
val text = data.remark.text
|
||||
if (!TextUtils.isEmpty(text)) {
|
||||
et.setText(text)
|
||||
et.isCursorVisible = true
|
||||
Selection.setSelection(et.text, et.text.length)
|
||||
etParent.background = shape(solid = Color.parseColor("#263869"), radius = 20.PX, stroke = Color.parseColor("#5EBFFF"), strokeWidth = 2.PX)
|
||||
words.visibility = View.VISIBLE
|
||||
} else {
|
||||
words.visibility = View.INVISIBLE
|
||||
if (!first) {
|
||||
first = true
|
||||
et.setText("")
|
||||
}
|
||||
et.isCursorVisible = false
|
||||
etParent.background = shape(solid = Color.parseColor("#263869"), radius = 20.PX)
|
||||
}
|
||||
}
|
||||
|
||||
private fun FlexboxLayout.refresh(data: BadCase) {
|
||||
val vh = (tag as? Map<*, *> ?: emptyMap<Reason, ViewHolder>()).toMutableMap()
|
||||
if (vh.isEmpty()) {
|
||||
data.reasons.forEach { itx ->
|
||||
val view = getBadCaseView(context)
|
||||
val check = view.findViewById<ImageView>(R.id.check)
|
||||
check.background = StateListDrawable().also {
|
||||
it.addState(intArrayOf(android.R.attr.state_selected), ContextCompat.getDrawable(itemView.context, R.drawable.icon_ap_badcase_check))
|
||||
it.addState(StateSet.WILD_CARD, ContextCompat.getDrawable(itemView.context, R.drawable.icon_ap_badcase_default))
|
||||
}
|
||||
check.isSelected = itx.isChecked
|
||||
val reason = view.findViewById<TextView>(R.id.reason)
|
||||
reason.text = itx.reason
|
||||
vh[itx] = ViewHolder(check, reason)
|
||||
view.onClick {
|
||||
cb?.onBadCaseItemClicked(itx)
|
||||
}
|
||||
view.layoutParams = FlexboxLayout.LayoutParams(FlexboxLayout.LayoutParams.WRAP_CONTENT, FlexboxLayout.LayoutParams.WRAP_CONTENT).also {
|
||||
it.flexBasisPercent = 0.5f
|
||||
}
|
||||
addView(view)
|
||||
}
|
||||
tag = vh
|
||||
} else {
|
||||
data.reasons.forEach {
|
||||
(vh[it] as? ViewHolder)?.run {
|
||||
check.isSelected = it.isChecked
|
||||
reason.text = it.reason
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getBadCaseView(context: Context): View {
|
||||
return LinearLayout(context).also { itx ->
|
||||
itx.orientation = LinearLayout.HORIZONTAL
|
||||
itx.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
itx.gravity = Gravity.CENTER_VERTICAL
|
||||
|
||||
//ImageView -- check
|
||||
val check = ImageView(context)
|
||||
check.layoutParams = LinearLayout.LayoutParams(70.PX, 70.PX)
|
||||
check.id = R.id.check
|
||||
itx.addView(check)
|
||||
|
||||
//TextView -- Reason
|
||||
val reason = TextView(context)
|
||||
reason.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).also {
|
||||
it.marginStart = 30.PX
|
||||
it.marginEnd = 20.PX
|
||||
}
|
||||
reason.setTextColor(Color.WHITE)
|
||||
reason.setTextSize(TypedValue.COMPLEX_UNIT_PX, 42.0f)
|
||||
reason.maxLines = 1
|
||||
reason.ellipsize = END
|
||||
reason.id = R.id.reason
|
||||
itx.addView(reason)
|
||||
}
|
||||
}
|
||||
|
||||
private data class ViewHolder(val check: ImageView, val reason: TextView)
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.zhjt.mogo_core_function_devatools.feedback.biz.adapter.vh.base
|
||||
|
||||
import android.view.View
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback
|
||||
import com.zhjt.mogo_core_function_devatools.feedback.callback.IFeedbackCallback
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
internal open class FeedbackViewHolder<T: Feedback>(internal val cb: IFeedbackCallback?, view: View): RecyclerView.ViewHolder(view) {
|
||||
|
||||
private val data by lazy { AtomicReference<T>() }
|
||||
|
||||
fun data(): T {
|
||||
return data.get()
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
open fun onBind(data: T, position: Int) {
|
||||
this.data.set(data)
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:background="#151D41F0"
|
||||
tools:layout_height="match_parent"
|
||||
tools:layout_width="match_parent"
|
||||
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/close"
|
||||
android:layout_width="107dp"
|
||||
android:layout_height="107dp"
|
||||
android:layout_marginTop="66dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:src="@drawable/icon_close_nor"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/blue_block"
|
||||
android:layout_width="14dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_marginStart="80dp"
|
||||
android:layout_marginTop="92dp"
|
||||
android:background="#2966EC"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="19dp"
|
||||
android:text="请选择本次接管原因"
|
||||
android:textColor="#ffffff"
|
||||
android:textSize="42dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/blue_block"
|
||||
app:layout_constraintStart_toEndOf="@+id/blue_block"
|
||||
app:layout_constraintTop_toTopOf="@+id/blue_block" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/time_of_take_over"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="113dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:textColor="#A7B6F0"
|
||||
android:textSize="32dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/blue_block"
|
||||
tools:text="接管时间:2021.12.21 14:32" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_take_over"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="101dp"
|
||||
android:overScrollMode="never"
|
||||
app:layout_constraintBottom_toTopOf="@+id/ok"
|
||||
android:layout_marginBottom="20dp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/time_of_take_over" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ok"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="123dp"
|
||||
android:paddingTop="31dp"
|
||||
android:paddingEnd="123dp"
|
||||
android:paddingBottom="31dp"
|
||||
android:text="确认"
|
||||
android:textColor="#ffffff"
|
||||
android:textSize="42dp"
|
||||
android:layout_marginStart="100dp"
|
||||
android:layout_marginEnd="100dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/cancel"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:enabled="false"
|
||||
android:layout_marginBottom="150dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cancel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="123dp"
|
||||
android:paddingTop="31dp"
|
||||
android:paddingEnd="123dp"
|
||||
android:paddingBottom="31dp"
|
||||
android:text="取消"
|
||||
android:textColor="#ffffff"
|
||||
android:textSize="42dp"
|
||||
android:layout_marginEnd="100dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/ok"
|
||||
android:layout_marginBottom="150dp"/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/pb"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@android:style/Widget.Holo.Light.ProgressBar.Inverse"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||
</merge>
|
||||
@@ -1,27 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
tools:ignore="HardcodedText,dpUsage,ContentDescription">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/check"
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="70dp"
|
||||
android:layout_marginStart="113dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/reason"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#ffffff"
|
||||
android:layout_marginStart="30dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:textSize="42dp"
|
||||
android:lines="1"
|
||||
android:ellipsize="end"
|
||||
tools:text="转弯过于靠近路侧转弯过于靠近路侧转弯过于靠近路侧转弯过于靠近路侧转弯过于靠近路侧转弯过于靠近路侧转弯过于靠近路侧转弯过于靠近路侧"/>
|
||||
</LinearLayout>
|
||||
@@ -1,47 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:layout_width="match_parent"
|
||||
tools:layout_height="match_parent"
|
||||
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/close"
|
||||
android:layout_width="107dp"
|
||||
android:layout_height="107dp"
|
||||
android:layout_marginTop="66dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:src="@drawable/icon_close_nor"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:ignore="dpUsage" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/pb"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@android:style/Widget.Holo.Light.ProgressBar.Inverse"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<View
|
||||
android:id="@+id/top_mask"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="80dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
</merge>
|
||||
@@ -1,118 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:ignore="HardcodedText,dpUsage">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginTop="92dp"
|
||||
android:layout_marginStart="80dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<View
|
||||
android:layout_width="14dp"
|
||||
android:layout_height="50dp"
|
||||
android:background="#2966EC"
|
||||
android:layout_marginEnd="19dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="42dp"
|
||||
android:textColor="#ffffff"
|
||||
android:text="Case上报"/>
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.flexbox.FlexboxLayout
|
||||
android:id="@+id/flex"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/ll_title"
|
||||
app:flexWrap="wrap"
|
||||
app:flexDirection="row"
|
||||
app:dividerDrawable="@drawable/flex_divider"
|
||||
app:showDivider="middle"
|
||||
app:justifyContent="flex_start"
|
||||
android:layout_marginStart="80dp"
|
||||
android:layout_marginTop="54dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/supply"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toBottomOf="@+id/flex"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:layout_marginStart="80dp"
|
||||
android:layout_marginTop="86dp"
|
||||
android:text="补充"
|
||||
android:textColor="#ffffff"
|
||||
android:textSize="36dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/et_root"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="396dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/supply"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:paddingTop="30dp"
|
||||
android:paddingStart="25dp"
|
||||
android:paddingEnd="45dp"
|
||||
android:layout_marginStart="75dp"
|
||||
android:layout_marginEnd="95dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1"
|
||||
android:background="@null"
|
||||
android:focusable="false"
|
||||
android:gravity="start"
|
||||
android:focusableInTouchMode="true"
|
||||
android:inputType="text"
|
||||
android:textSize="36dp"
|
||||
android:textColorHint="#4CFFFFFF"
|
||||
android:imeOptions="actionDone"
|
||||
android:hint="Case细节描述"
|
||||
android:textColor="#FFFFFF" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/words_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="28dp"
|
||||
android:layout_gravity="end"
|
||||
tools:text="126/200"
|
||||
android:layout_marginBottom="30dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/record"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="126dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginStart="75dp"
|
||||
android:layout_marginEnd="95dp"
|
||||
android:layout_marginTop="40dp"
|
||||
android:textColor="#ffffff"
|
||||
android:textSize="42dp"
|
||||
android:gravity="center"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintTop_toBottomOf="@+id/et_root"
|
||||
android:text="录制Case"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,28 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivBadCaseTools"
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="120dp"
|
||||
android:src="@drawable/bad_case_selector"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivAiCollectTools"
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="120dp"
|
||||
android:src="@drawable/ai_collect_selector"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toRightOf="@id/ivBadCaseTools"
|
||||
android:layout_marginStart="50dp"
|
||||
/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
Reference in New Issue
Block a user