From 2c33619e03259b44f0506cfc965717b4a5d66ac8 Mon Sep 17 00:00:00 2001 From: aibingbing Date: Fri, 24 Nov 2023 21:22:16 +0800 Subject: [PATCH] =?UTF-8?q?[=E8=87=AA=E4=B8=BB=E7=AE=97=E8=B7=AF=E9=AA=8C?= =?UTF-8?q?=E8=AF=81]=20feat:=20=E8=81=94=E8=B0=83=E5=90=8E=E7=AB=AF?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=EF=BC=8C=E5=A2=9E=E5=8A=A0=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E8=87=AA=E9=A9=BE=EF=BC=8C=E9=AB=98=E5=BE=B7=E5=AF=BC=E8=88=AA?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E9=80=BB=E8=BE=91=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/mogo/och/taxi/bean/TaxiRoutingBean.kt | 38 ++- .../och/taxi/callback/ITaxiRoutingCallback.kt | 4 + .../taxi/constant/TaxiDriverEventConst.java | 2 +- .../taxi/network/TaxiRoutingServiceManager.kt | 4 + .../com/mogo/och/taxi/ui/base/TaxiFragment.kt | 16 +- .../mogo/och/taxi/ui/base/TaxiPresenter.java | 3 + .../routing/TaxiRoutingChooseLineActivity.kt | 26 +- .../routing/TaxiRoutingChooseLineViewModel.kt | 59 +++-- .../ui/routing/TaxiRoutingFeedbackDialog.kt | 21 +- .../taxi/ui/routing/TaxiRoutingFragment.kt | 199 +++++++++++++-- .../routing/TaxiRoutingFragmentViewModel.kt | 91 ++++++- .../och/taxi/ui/routing/TaxiRoutingModel.kt | 232 +++++++++++++++++- .../taxi/ui/routing/TaxiRoutingUiIntent.kt | 12 +- .../och/taxi/ui/routing/TaxiRoutingUiState.kt | 16 +- 14 files changed, 638 insertions(+), 85 deletions(-) diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/bean/TaxiRoutingBean.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/bean/TaxiRoutingBean.kt index a19c466320..3411b14cdb 100644 --- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/bean/TaxiRoutingBean.kt +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/bean/TaxiRoutingBean.kt @@ -9,17 +9,35 @@ data class GrayLineBean( var carVerificationCount: Int?, //本次今日已验证次数 var lineSuccessCount: Int?, //线路累计反馈可用次数 var lineFailCount: Int?, //线路累计反馈不可用次数 - var isChoosed: Boolean = false //当前是否选中 + var isChoosed: Boolean = false, //当前是否选中 + var startSite: RoutingSite?, + var endSite: RoutingSite? +) + +data class RoutingSite( + var siteId: Long, + var siteName: String, + var gcjLat: Double, + var gcjLon: Double, + var wgs84Lon: Double, + var wgs84Lat: Double ) data class ContrailBean( - var lineId: Long?, - var contrailId: Long?, - var csvFileUrl: String?, - var csvFileMd5: String?, - var txtFileUrl: String?, - var txtFileMd5: String?, - var version: Long? + var lineId: Long = -1L, + var lineName: String = "", + var contrailId: Long = -1L, + var csvFileUrl: String = "", + var csvFileMd5: String = "", + var txtFileUrl: String = "", + var txtFileMd5: String = "", + var contrailSaveTime: Long = -1L, + var csvFileUrlDPQP: String = "", + var csvFileMd5DPQP: String = "", + var txtFileUrlDPQP: String = "", + var txtFileMd5DPQP: String = "", + var contrailSaveTimeDPQP: Long = -1L, + var version: Long = -1L ) data class QueryGrayContrailListRsp(var data: MutableList?) : BaseData() @@ -34,6 +52,10 @@ data class StartGrayAndQueryContrailRsp( var grayLineBean: GrayLineBean ) : BaseData() +enum class EndGrayTaskFeedbackType(var type: Int) { + USABLE_YES(1), + USABLE_NO(2) +} diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/callback/ITaxiRoutingCallback.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/callback/ITaxiRoutingCallback.kt index 125e1c13c1..980921759f 100644 --- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/callback/ITaxiRoutingCallback.kt +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/callback/ITaxiRoutingCallback.kt @@ -8,4 +8,8 @@ interface ITaxiRoutingCallback { fun onQueryRoutingGrayLineListFailed(errorStr: String) fun onStartGrayTaskAndQueryContrailSuccess(data: StartGrayAndQueryContrailRsp) fun onStartGrayTaskAndQueryContrailFailed(errorStr: String) + fun onSubmitGrayLineIssueLocationSuccess() + fun onSubmitGrayLineIssueLocationFailed(errorStr: String) + fun onSubmitEndTaskSuccess() + fun onSubmitEndTaskFailed(errorStr: String) } diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/constant/TaxiDriverEventConst.java b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/constant/TaxiDriverEventConst.java index e7bb8bdc2f..ed2c9f757d 100644 --- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/constant/TaxiDriverEventConst.java +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/constant/TaxiDriverEventConst.java @@ -15,6 +15,6 @@ public interface TaxiDriverEventConst { } interface RoutingActivityEvent { - String EVENT_TYPE_GET_CHOSEN_LINE_TASK_ID = "event_type_get_chosen_line_task_id"; + String EVENT_TYPE_GET_CHOSEN_LINE_TASK = "event_type_get_chosen_line_task"; } } diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/network/TaxiRoutingServiceManager.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/network/TaxiRoutingServiceManager.kt index 3047ebd492..aaa1b5c288 100644 --- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/network/TaxiRoutingServiceManager.kt +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/network/TaxiRoutingServiceManager.kt @@ -105,6 +105,8 @@ object TaxiRoutingServiceManager { contrail = null, grayLineBean = grayLineBean ) + result.code = startGrayRsp.code + result.msg = startGrayRsp.msg return@flatMap Observable.just(result) } taskId = startGrayRsp.data!! @@ -115,6 +117,8 @@ object TaxiRoutingServiceManager { contrail = queryRoutingContrailRsp.data, grayLineBean = grayLineBean ) + result.code = queryRoutingContrailRsp.code + result.msg = queryRoutingContrailRsp.msg result } } diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/base/TaxiFragment.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/base/TaxiFragment.kt index 18ecb7806e..e53a9b617d 100644 --- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/base/TaxiFragment.kt +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/base/TaxiFragment.kt @@ -163,9 +163,9 @@ class TaxiFragment : BaseTaxiTabFragment(), if (StatusDescriptor.TAXI_UNMANED_DRIVER_LINE_ROUTING_VERIFY_MODE == descriptor) { UiThreadHandler.post { if (isTrue) { - showRoutingFragment() + showRoutingFragment() } else { - showTaskFragment() + showTaskFragment() } } } @@ -272,8 +272,12 @@ class TaxiFragment : BaseTaxiTabFragment(), fun onNaviToEnd(isAmap: Boolean, isShow: Boolean) { if (isAmap) { - if (null == taskTabFragment || taskTabFragment!!.get() == null) return - taskTabFragment!!.get()!!.onNaviToEndStationByAMap(isShow) + if (MogoStatusManager.getInstance().isTaxiUnmanedDriverLineRoutingVerifyMode) { + showAmapNaviToStationFragment(isShow) + } else { + if (null == taskTabFragment || taskTabFragment!!.get() == null) return + taskTabFragment!!.get()!!.onNaviToEndStationByAMap(isShow) + } } else if (isShow) { //使用routing数据 showRoutingToStationFragment(true) } else { @@ -304,8 +308,8 @@ class TaxiFragment : BaseTaxiTabFragment(), if (it.order != null && it.order!!.orderStatus >= TaxiOrderStatusEnum.ArriveAtStart.code) it.order!!.orderLine else - it.lineId - ,true) + it.lineId, true + ) } } diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/base/TaxiPresenter.java b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/base/TaxiPresenter.java index 8fc079b3bb..ab3e77109b 100644 --- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/base/TaxiPresenter.java +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/base/TaxiPresenter.java @@ -20,6 +20,7 @@ import com.mogo.och.taxi.callback.ITaxiOrderStatusCallback; import com.mogo.och.taxi.constant.TaxiCarServingStatusManager; import com.mogo.och.taxi.constant.TaxiDriverRoleEnum; import com.mogo.och.taxi.constant.TaxiUnmannedConst; +import com.mogo.och.taxi.ui.routing.TaxiRoutingModel; import com.mogo.och.taxi.ui.task.TaxiTaskModel; /** @@ -51,6 +52,8 @@ public class TaxiPresenter extends Presenter implements ITaxiADASS TaxiTaskModel.INSTANCE.setADASStatusCallback(this); TaxiTaskModel.INSTANCE.setControllerStatusCallback(this); TaxiTaskModel.INSTANCE.setOrderStatusCallback(this); + TaxiRoutingModel.INSTANCE.setControllerStatusCallback(this); + TaxiRoutingModel.INSTANCE.setOrderStatusCallback(this); } private void releaseListeners() { diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingChooseLineActivity.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingChooseLineActivity.kt index 4bef569900..3d092a4711 100644 --- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingChooseLineActivity.kt +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingChooseLineActivity.kt @@ -13,7 +13,6 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger import com.mogo.eagle.core.utilcode.mogo.view.SpacesItemDecoration import com.mogo.eagle.core.utilcode.util.ToastUtils -import com.mogo.eagle.core.utilcode.util.UiThreadHandler import com.mogo.och.common.module.utils.FlowBus import com.mogo.och.taxi.R import com.mogo.och.taxi.bean.GrayLineBean @@ -101,14 +100,6 @@ class TaxiRoutingChooseLineActivity : AppCompatActivity() { mViewModel.sendUiIntent( TaxiRoutingUiIntent.StartTaskAndQueryContrail(chosenItem) ) - // TODO - UiThreadHandler.postDelayed({ - mLoadingDialog.hideLoading() - FlowBus.with(TaxiDriverEventConst.RoutingActivityEvent.EVENT_TYPE_GET_CHOSEN_LINE_TASK_ID) - .post(this.lifecycleScope, 1000) - mChooseLineListAdapter.setOnLineItemClickListener(null) - finish() - }, 3000L) } } @@ -127,6 +118,23 @@ class TaxiRoutingChooseLineActivity : AppCompatActivity() { is RoutingUIState.ShowGrayLineList -> { onRoutingGrayLineListChanged(routingUiState.data) } + + is RoutingUIState.HideChooseLineLoading -> { + mLoadingDialog.hideLoading() + if (routingUiState.isCosePage) { + mChooseLineListAdapter.setOnLineItemClickListener(null) + finish() + } + } + + is RoutingUIState.PostRoutingTaskResult -> { + FlowBus.with(TaxiDriverEventConst.RoutingActivityEvent.EVENT_TYPE_GET_CHOSEN_LINE_TASK) + .post(this, RoutingUIState.RoutingTask( + grayLineBean = routingUiState.grayLineBean, + contrailBean = routingUiState.contrailBean, + grayId = routingUiState.grayId + )) + } } } } diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingChooseLineViewModel.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingChooseLineViewModel.kt index b616f28e18..8977f56aa0 100644 --- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingChooseLineViewModel.kt +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingChooseLineViewModel.kt @@ -1,6 +1,7 @@ package com.mogo.och.taxi.ui.routing import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant +import com.mogo.eagle.core.utilcode.util.ToastUtils import com.mogo.och.taxi.base.BaseViewModel import com.mogo.och.taxi.base.IUiIntent import com.mogo.och.taxi.bean.GrayLineBean @@ -45,46 +46,58 @@ class TaxiRoutingChooseLineViewModel : BaseViewModel = mutableListOf() - for (i in 1..15) { - val result = GrayLineBean( - lineId = i + 1L, - lineName = "路线名称$i", - contrailId = i + 1L, - carVerificationCount = i, - lineSuccessCount = i, - lineFailCount = i, - isChoosed = false - ) - data.add(result) - } + ToastUtils.showShort(errorStr) sendUiState { copy( - routingUiState = RoutingUIState.ShowGrayLineList(data) + routingUiState = RoutingUIState.Init ) } } override fun onStartGrayTaskAndQueryContrailSuccess(data: StartGrayAndQueryContrailRsp) { + if (data.taskId == -1L) { + onStartGrayTaskAndQueryContrailFailed("开始任务失败, 请稍后重试") + return + } sendUiState { copy( - routingUiState = RoutingUIState.RoutingTask( - grayId = data.taskId, + routingUiState = RoutingUIState.PostRoutingTaskResult( grayLineBean = data.grayLineBean, - contrailBean = data.contrail + contrailBean = data.contrail, + grayId = data.taskId + ) + ) + } + sendUiState { + copy( + routingUiState = RoutingUIState.HideChooseLineLoading( + isCosePage = true ) ) } } override fun onStartGrayTaskAndQueryContrailFailed(errorStr: String) { + ToastUtils.showShort(errorStr) + sendUiState { + copy( + routingUiState = RoutingUIState.HideChooseLineLoading( + isCosePage = false + ) + ) + } + } + override fun onSubmitGrayLineIssueLocationSuccess() { + } + + override fun onSubmitGrayLineIssueLocationFailed(errorStr: String) { + } + + override fun onSubmitEndTaskSuccess() { + } + + override fun onSubmitEndTaskFailed(errorStr: String) { } override fun onCleared() { diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFeedbackDialog.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFeedbackDialog.kt index b7de129128..dfd851184e 100644 --- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFeedbackDialog.kt +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFeedbackDialog.kt @@ -13,12 +13,13 @@ class TaxiRoutingFeedbackDialog : BaseFloatDialog, LifecycleObserver { private var commonCancel: TextView? = null private var commonTips: TextView? = null private var commonCloseIcon: ImageView? = null - private var clickListener: ClickListener? = null + private var clickListener: TaxiRoutingFeedBackDialogClickListener? = null constructor(builder: Builder, context: Context) : super(context) { commonTips?.text = builder.tipsStr commonCancel?.text = builder.cancelStr commonConfirm?.text = builder.confirmStr + clickListener = builder.clickListener } init { @@ -46,10 +47,6 @@ class TaxiRoutingFeedbackDialog : BaseFloatDialog, LifecycleObserver { } } - fun setClickListener(clickListener: ClickListener) { - this.clickListener = clickListener - } - fun showDialog() { if (isShowing) { return @@ -57,7 +54,13 @@ class TaxiRoutingFeedbackDialog : BaseFloatDialog, LifecycleObserver { show() } - interface ClickListener { + fun hideDialog() { + if (isShowing) { + dismiss() + } + } + + interface TaxiRoutingFeedBackDialogClickListener { fun confirm() fun cancel() } @@ -66,6 +69,7 @@ class TaxiRoutingFeedbackDialog : BaseFloatDialog, LifecycleObserver { var tipsStr: String = "" var confirmStr: String = "" var cancelStr: String = "" + var clickListener: TaxiRoutingFeedBackDialogClickListener? = null fun tips(tips: String): Builder { this.tipsStr = tips @@ -82,6 +86,11 @@ class TaxiRoutingFeedbackDialog : BaseFloatDialog, LifecycleObserver { return this } + fun clickListener(listener: TaxiRoutingFeedBackDialogClickListener): Builder { + this.clickListener = listener + return this + } + fun build(context: Context): TaxiRoutingFeedbackDialog? { return TaxiRoutingFeedbackDialog(this, context) } diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFragment.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFragment.kt index 1462cdc8c5..997388a043 100644 --- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFragment.kt +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFragment.kt @@ -4,25 +4,38 @@ import android.os.Bundle import android.view.View import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope +import com.amap.api.navi.model.NaviLatLng import com.mogo.commons.mvp.BaseFragment +import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager import com.mogo.eagle.core.function.main.MainMoGoApplication 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.util.ToastUtils +import com.mogo.eagle.core.utilcode.util.UiThreadHandler +import com.mogo.och.common.module.map.AmapNaviToDestinationModel +import com.mogo.och.common.module.map.ICommonNaviChangedCallback import com.mogo.och.common.module.utils.FlowBus import com.mogo.och.taxi.R +import com.mogo.och.taxi.bean.EndGrayTaskFeedbackType import com.mogo.och.taxi.constant.TaxiDriverEventConst +import com.mogo.och.taxi.utils.TaskUtils import kotlinx.android.synthetic.main.routing_fragment.btnChooseTask import kotlinx.android.synthetic.main.routing_fragment.btnFinishTask import kotlinx.android.synthetic.main.routing_fragment.btnStartTask +import kotlinx.android.synthetic.main.routing_fragment.btnSummitIssue +import kotlinx.android.synthetic.main.routing_fragment.endStationName import kotlinx.android.synthetic.main.routing_fragment.finishSubmitIssueGroup import kotlinx.android.synthetic.main.routing_fragment.headerTitleContainer import kotlinx.android.synthetic.main.routing_fragment.mCurrentTaskLayout +import kotlinx.android.synthetic.main.routing_fragment.naviToEnd +import kotlinx.android.synthetic.main.routing_fragment.naviToStart import kotlinx.android.synthetic.main.routing_fragment.noDataContainer +import kotlinx.android.synthetic.main.routing_fragment.startStationName import kotlinx.android.synthetic.main.routing_fragment.taskTitleTv +import kotlinx.android.synthetic.main.routing_fragment.taskTripInfo import kotlinx.coroutines.flow.map -class TaxiRoutingFragment : BaseFragment() { +class TaxiRoutingFragment : BaseFragment(), ICommonNaviChangedCallback { companion object { const val TAG = SceneConstant.M_TAXI + "TaxiRoutingFragment" @@ -35,6 +48,8 @@ class TaxiRoutingFragment : BaseFragment() { } } + private var mFeedbackDialog: TaxiRoutingFeedbackDialog? = null + private val mViewModel: TaxiRoutingFragmentViewModel by lazy { ViewModelProvider( this, @@ -57,7 +72,7 @@ class TaxiRoutingFragment : BaseFragment() { } private fun initEventBus() { - FlowBus.with(TaxiDriverEventConst.RoutingActivityEvent.EVENT_TYPE_GET_CHOSEN_LINE_TASK_ID) + FlowBus.with(TaxiDriverEventConst.RoutingActivityEvent.EVENT_TYPE_GET_CHOSEN_LINE_TASK) .register(this) { task -> ToastUtils.showLong("接收到taskId:${task.grayId}") mViewModel.sendUiIntent(TaxiRoutingUiIntent.ShowRoutingTask(task)) @@ -80,6 +95,7 @@ class TaxiRoutingFragment : BaseFragment() { when (routingUiState) { is RoutingUIState.Init -> { showChooseTaskView() + AmapNaviToDestinationModel.getInstance(context).destroyAmaNavi() } is RoutingUIState.RoutingTask -> { @@ -87,11 +103,15 @@ class TaxiRoutingFragment : BaseFragment() { } is RoutingUIState.ShowFinishTaskButton -> { - showFinishTaskView() + showFinishTaskView(routingUiState.routingTask) } is RoutingUIState.ShowFeedbackDialog -> { - showFeedbackDialog() + showFeedbackDialog(routingUiState.grayId) + } + + is RoutingUIState.DismissFeedbackDialog -> { + hideFeedbackDialog() } } } @@ -113,38 +133,179 @@ class TaxiRoutingFragment : BaseFragment() { mCurrentTaskLayout.visibility = View.VISIBLE headerTitleContainer.visibility = View.VISIBLE - taskTitleTv.text = data.grayLineBean.lineName + taskTitleTv.text = data.grayLineBean?.lineName btnChooseTask.visibility = View.GONE btnStartTask.visibility = View.VISIBLE btnStartTask.setOnClickListener { - mViewModel.sendUiIntent(TaxiRoutingUiIntent.StartTaskAction) + mViewModel.sendUiIntent(TaxiRoutingUiIntent.StartTaskAction(data)) } finishSubmitIssueGroup.visibility = View.GONE + + naviToStart.visibility = View.VISIBLE + naviToEnd.visibility = View.INVISIBLE + + data.grayLineBean?.startSite?.also { + initStartNaviToStationParam( + false, + it.gcjLat, + it.gcjLon + ) + naviToStart.setOnClickListener { + showNaviToEndStationFragment(true) + } + } + + startStationName.text = data.grayLineBean?.startSite?.siteName + endStationName.text = data.grayLineBean?.endSite?.siteName } - private fun showFinishTaskView() { + private fun showFinishTaskView(routingTask: RoutingUIState.RoutingTask) { btnChooseTask.visibility = View.GONE btnStartTask.visibility = View.GONE finishSubmitIssueGroup.visibility = View.VISIBLE btnFinishTask.setOnClickListener { - mViewModel.sendUiIntent(TaxiRoutingUiIntent.ShowFeedbackDialog) + mViewModel.sendUiIntent( + TaxiRoutingUiIntent.ShowFeedbackDialog( + routingTask.grayId ?: -1 + ) + ) + } + btnSummitIssue.setOnClickListener { + mViewModel.sendUiIntent( + TaxiRoutingUiIntent.SubmitGrayLineIssueLocation( + routingTask.grayId ?: -1L + ) + ) + } + + naviToStart.visibility = View.INVISIBLE + naviToEnd.visibility = View.VISIBLE + routingTask.grayLineBean?.endSite?.also { + initStartNaviToStationParam( + false, + it.gcjLat, + it.gcjLon + ) + naviToEnd.setOnClickListener { + showNaviToEndStationFragment(true) + } } } - private fun showFeedbackDialog() { - val builder: TaxiRoutingFeedbackDialog.Builder = TaxiRoutingFeedbackDialog.Builder() - builder.cancelStr( - MainMoGoApplication.getApp() - .getString(R.string.routing_feedback_result_btn_not_sure) - ) - .confirmStr( + private fun showFeedbackDialog(grayId: Long) { + if (mFeedbackDialog == null) { + val builder: TaxiRoutingFeedbackDialog.Builder = TaxiRoutingFeedbackDialog.Builder() + builder.cancelStr( + MainMoGoApplication.getApp() + .getString(R.string.routing_feedback_result_btn_not_sure) + ).confirmStr( MainMoGoApplication.getApp() .getString(R.string.routing_feedback_result_btn_sure) - ) - .tips(MainMoGoApplication.getApp().getString(R.string.routing_feedback_result_hint)) - activity?.also { - builder.build(it)?.showDialog() + ).tips(MainMoGoApplication.getApp().getString(R.string.routing_feedback_result_hint)) + .clickListener(object : + TaxiRoutingFeedbackDialog.TaxiRoutingFeedBackDialogClickListener { + override fun confirm() { + mViewModel.sendUiIntent( + TaxiRoutingUiIntent.SubmitEndTask( + grayId, + EndGrayTaskFeedbackType.USABLE_YES + ) + ) + } + + override fun cancel() { + mViewModel.sendUiIntent( + TaxiRoutingUiIntent.SubmitEndTask( + grayId, + EndGrayTaskFeedbackType.USABLE_NO + ) + ) + } + }) + activity?.also { + mFeedbackDialog = builder.build(it) + mFeedbackDialog?.showDialog() + } + } else { + activity?.also { + mFeedbackDialog?.showDialog() + } } } + + private fun hideFeedbackDialog() { + mFeedbackDialog?.hideDialog() + } + + /** + * 显示/隐藏 前往任务目的地的导航 + * + * @param isShow + */ + private fun showNaviToEndStationFragment(isShow: Boolean) { +// FlowBus.with(TaxiDriverEventConst.TaxiFragmentEvent.EVENT_TYPE_START_NAVI_TO_END_STATION) +// .post(this.lifecycleScope, isShow) + TaxiRoutingModel.startNaviToEndStationByAMap(isShow) + } + + private fun initStartNaviToStationParam( + isVoicePlay: Boolean, + stationLat: Double, + stationLng: Double + ) { + AmapNaviToDestinationModel.getInstance(context).destroyAmaNavi() + val mCurLatitude = + CallerChassisLocationGCJ02ListenerManager.getChassisLocationGCJ02().latitude + val mCurLongitude = + CallerChassisLocationGCJ02ListenerManager.getChassisLocationGCJ02().longitude + CallerLogger.d( + TAG, + "currentLocation, lat=$mCurLatitude, lon=$mCurLongitude" + ) + val startNaviLatLng = NaviLatLng(mCurLatitude, mCurLongitude) + val endNaviLatLng = NaviLatLng(stationLat, stationLng) + AmapNaviToDestinationModel.getInstance(context).initAMapNavi(startNaviLatLng, endNaviLatLng) + AmapNaviToDestinationModel.getInstance(context).setVoiceIsMute(isVoicePlay) + AmapNaviToDestinationModel.getInstance(context).setTaxiNaviChangedCallback(this) + } + + override fun onCurrentNaviDistAndTimeChanged(meters: Int, timeInSecond: Long) { + updateCurrentTaskTripInfo(meters.toLong(), timeInSecond) + } + + override fun reInitNaviAmap(isPlay: Boolean, isRestart: Boolean) { + CallerLogger.d(TAG, "isPlay = $isPlay, isRestart=$isRestart") + if (!isRestart) { +// FlowBus.with(TaxiDriverEventConst.TaxiFragmentEvent.EVENT_TYPE_SHOW_AMAP_NAVI_TO_STATION_FRAGMENT) +// .post(this.lifecycleScope, false) + TaxiRoutingModel.startNaviToEndStationByAMap(false) + return + } + } + + /** + * 剩余里程和剩余时间 + * @param meters 米 + * @param timeInSecond 秒 + */ + private fun updateCurrentTaskTripInfo(meters: Long, timeInSecond: Long) { + UiThreadHandler.post { + CallerLogger.d( + TAG, + "updateCurrentTaskTripInfo, taskUtil, ${ + TaskUtils.getCurrentTaskTripHtml( + meters, + timeInSecond + ) + }" + ) + taskTripInfo.text = TaskUtils.getCurrentTaskTripHtml(meters, timeInSecond) + } + } + + override fun onDestroyView() { + AmapNaviToDestinationModel.getInstance(context).destroyAmaNavi() + super.onDestroyView() + } } \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFragmentViewModel.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFragmentViewModel.kt index fbd9b4aab6..8465751e2f 100644 --- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFragmentViewModel.kt +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingFragmentViewModel.kt @@ -3,16 +3,26 @@ package com.mogo.och.taxi.ui.routing import android.content.Context import android.content.Intent import com.mogo.commons.AbsMogoApplication +import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant +import com.mogo.eagle.core.utilcode.util.ToastUtils import com.mogo.och.taxi.base.BaseViewModel import com.mogo.och.taxi.base.IUiIntent +import com.mogo.och.taxi.bean.GrayLineBean +import com.mogo.och.taxi.bean.StartGrayAndQueryContrailRsp +import com.mogo.och.taxi.callback.ITaxiRoutingCallback -class TaxiRoutingFragmentViewModel : BaseViewModel() { +class TaxiRoutingFragmentViewModel : BaseViewModel(), + ITaxiRoutingCallback { companion object { const val TAG = SceneConstant.M_TAXI + "TaxiRoutingFragmentViewModel" } + init { + TaxiRoutingModel.addTaxiRoutingListener(TAG, this) + } + private val mContext: Context get() = AbsMogoApplication.getApp().applicationContext @@ -41,13 +51,88 @@ class TaxiRoutingFragmentViewModel : BaseViewModel { - //TODO 启动自动驾驶 + val grayLineBean = intent.routingTask.grayLineBean + val contrailBean = intent.routingTask.contrailBean + if (grayLineBean == null || contrailBean == null) { + ToastUtils.showShort("灰度线路或轨迹信息异常,请稍后再试") + return + } + TaxiRoutingModel.startAutoPilot(grayLineBean!!, contrailBean!!) sendUiState { copy( - routingUiState = RoutingUIState.ShowFinishTaskButton + routingUiState = RoutingUIState.ShowFinishTaskButton(intent.routingTask) ) } } + + is TaxiRoutingUiIntent.SubmitGrayLineIssueLocation -> { + val grayId = intent.grayId + val currentLocation = + CallerChassisLocationGCJ02ListenerManager.getChassisLocationGCJ02() + TaxiRoutingModel.submitGrayLineIssueLocation( + grayId, + currentLocation.longitude, + currentLocation.latitude + ) + } + + is TaxiRoutingUiIntent.ShowFeedbackDialog -> { + sendUiState { + copy( + routingUiState = RoutingUIState.ShowFeedbackDialog( + intent.grayId, + System.currentTimeMillis() + ) + ) + } + } + + is TaxiRoutingUiIntent.SubmitEndTask -> { + TaxiRoutingModel.endGrayTask(intent.grayId, intent.type) + } } } + + override fun onQueryRoutingGrayLineListSuccess(data: MutableList) { + } + + override fun onQueryRoutingGrayLineListFailed(errorStr: String) { + } + + override fun onStartGrayTaskAndQueryContrailSuccess(data: StartGrayAndQueryContrailRsp) { + } + + override fun onStartGrayTaskAndQueryContrailFailed(errorStr: String) { + } + + override fun onSubmitGrayLineIssueLocationSuccess() { + ToastUtils.showShort("上报问题打点成功") + } + + override fun onSubmitGrayLineIssueLocationFailed(errorStr: String) { + ToastUtils.showShort("上报问题打点失败:$errorStr") + } + + override fun onSubmitEndTaskSuccess() { + ToastUtils.showLong("结束任务成功") + sendUiState { + copy( + routingUiState = RoutingUIState.Init + ) + } + } + + override fun onSubmitEndTaskFailed(errorStr: String) { + ToastUtils.showLong("结束任务失败") + sendUiState { + copy( + routingUiState = RoutingUIState.DismissFeedbackDialog + ) + } + } + + override fun onCleared() { + TaxiRoutingModel.removeTaxiRoutingListener(TAG) + super.onCleared() + } } \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingModel.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingModel.kt index de6ccc7914..572e522c01 100644 --- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingModel.kt +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingModel.kt @@ -1,19 +1,34 @@ package com.mogo.och.taxi.ui.routing import android.content.Context +import android.text.TextUtils import com.mogo.cloud.passport.MoGoAiCloudClientConfig import com.mogo.commons.AbsMogoApplication +import com.mogo.eagle.core.data.BaseData +import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters +import com.mogo.eagle.core.data.config.FunctionBuildConfig +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager +import com.mogo.eagle.core.network.utils.GsonUtil 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.util.GsonUtils import com.mogo.eagle.core.utilcode.util.NetworkUtils import com.mogo.eagle.core.utilcode.util.ToastUtils import com.mogo.och.common.module.biz.network.OchCommonServiceCallback +import com.mogo.och.common.module.manager.autopilotmanager.OCHAdasAbilityManager +import com.mogo.och.taxi.bean.ContrailBean +import com.mogo.och.taxi.bean.EndGrayContrailTaskReq +import com.mogo.och.taxi.bean.EndGrayTaskFeedbackType import com.mogo.och.taxi.bean.GrayLineBean import com.mogo.och.taxi.bean.QueryGrayContrailListRsp import com.mogo.och.taxi.bean.StartGrayAndQueryContrailRsp +import com.mogo.och.taxi.bean.SubmitGrayLineIssueLocationReq +import com.mogo.och.taxi.callback.ITaxiControllerStatusCallback +import com.mogo.och.taxi.callback.ITaxiOrderStatusCallback import com.mogo.och.taxi.callback.ITaxiRoutingCallback +import com.mogo.och.taxi.constant.TaxiUnmannedConst import com.mogo.och.taxi.network.TaxiRoutingServiceManager +import com.mogo.och.taxi.ui.debug.DebugView import java.util.concurrent.ConcurrentHashMap object TaxiRoutingModel { @@ -25,7 +40,6 @@ object TaxiRoutingModel { private val mTaxiRoutingCallbackMap: ConcurrentHashMap = ConcurrentHashMap() - fun addTaxiRoutingListener(tag: String, listener: ITaxiRoutingCallback) { if (mTaxiRoutingCallbackMap.containsKey(tag)) { return @@ -40,6 +54,18 @@ object TaxiRoutingModel { mTaxiRoutingCallbackMap.remove(tag) } + private var mControllerStatusCallback: ITaxiControllerStatusCallback? = null + + fun setControllerStatusCallback(callback: ITaxiControllerStatusCallback?) { + mControllerStatusCallback = callback + } + + private var mOrderStatusCallback: ITaxiOrderStatusCallback? = null + + fun setOrderStatusCallback(callback: ITaxiOrderStatusCallback?) { + mOrderStatusCallback = callback + } + fun queryRoutingGrayLineList() { TaxiRoutingServiceManager.queryRoutingGrayLineList(mContext, object : OchCommonServiceCallback { @@ -77,10 +103,8 @@ object TaxiRoutingModel { var hintStr = "" if (!NetworkUtils.isConnected(mContext)) { hintStr = "网络出现异常,请稍后重试" - ToastUtils.showShort(hintStr) } else { hintStr = "查询灰度线路列表异常, 请稍后重试" - ToastUtils.showShort(hintStr) } CallerLogger.d( TAG, @@ -134,10 +158,8 @@ object TaxiRoutingModel { var hintStr = "" if (!NetworkUtils.isConnected(mContext)) { hintStr = "网络出现异常,请稍后重试" - ToastUtils.showShort(hintStr) } else { hintStr = "开始任务并查询轨迹详情异常, 请稍后重试" - ToastUtils.showShort(hintStr) } CallerLogger.d( TAG, @@ -151,4 +173,204 @@ object TaxiRoutingModel { } ) } + + fun submitGrayLineIssueLocation(grayId: Long, gcjLon: Double, gcjLat: Double) { + val submit = SubmitGrayLineIssueLocationReq(grayId, gcjLon, gcjLat) + TaxiRoutingServiceManager.submitGrayLineIssueLocation( + mContext, + submit, + object : OchCommonServiceCallback { + override fun onSuccess(data: BaseData?) { + CallerLogger.d( + TAG, + "submitGrayLineIssueLocation onSuccess: data=${ + GsonUtils.toJson( + data + ) + }" + ) + mTaxiRoutingCallbackMap.forEach { + val listener = it.value + listener.onSubmitGrayLineIssueLocationSuccess() + } + } + + override fun onFail(code: Int, msg: String?) { + CallerLogger.d( + TAG, + "submitGrayLineIssueLocation onFail: code=$code, msg=$msg" + ) + mTaxiRoutingCallbackMap.forEach { + val listener = it.value + listener.onSubmitGrayLineIssueLocationFailed( + msg ?: "submitGrayLineIssueLocation onFail" + ) + } + } + + override fun onError() { + super.onError() + var hintStr = "" + if (!NetworkUtils.isConnected(mContext)) { + hintStr = "网络出现异常,请稍后重试" + } else { + hintStr = "上报问题打点异常, 请稍后重试" + } + CallerLogger.d( + TAG, + "submitGrayLineIssueLocation onError, msg=$hintStr" + ) + mTaxiRoutingCallbackMap.forEach { + val listener = it.value + listener.onSubmitGrayLineIssueLocationFailed(hintStr) + } + } + } + ) + } + + fun endGrayTask(grayId: Long, type: EndGrayTaskFeedbackType) { + val submit = EndGrayContrailTaskReq(grayId, type.type) + TaxiRoutingServiceManager.endGrayTask( + mContext, + submit, + object : OchCommonServiceCallback { + override fun onSuccess(data: BaseData?) { + CallerLogger.d( + TAG, + "endGrayTask onSuccess: data=${ + GsonUtils.toJson( + data + ) + }" + ) + mTaxiRoutingCallbackMap.forEach { + val listener = it.value + listener.onSubmitEndTaskSuccess() + } + } + + override fun onFail(code: Int, msg: String?) { + CallerLogger.d( + TAG, + "endGrayTask onFail: code=$code, msg=$msg" + ) + mTaxiRoutingCallbackMap.forEach { + val listener = it.value + listener.onSubmitEndTaskFailed( + msg ?: "endGrayTask onFail" + ) + } + } + + override fun onError() { + super.onError() + var hintStr = "" + if (!NetworkUtils.isConnected(mContext)) { + hintStr = "网络出现异常,请稍后重试" + } else { + hintStr = "上报结束任务异常, 请稍后重试" + } + CallerLogger.d( + TAG, + "endGrayTask onError, msg=$hintStr" + ) + mTaxiRoutingCallbackMap.forEach { + val listener = it.value + listener.onSubmitEndTaskFailed(hintStr) + } + } + }) + } + + fun startAutoPilot(grayLineBean: GrayLineBean, contrailBean: ContrailBean) { + if (grayLineBean.startSite == null || grayLineBean.endSite == null) { + CallerLogger.e(TAG, "start site or end site is null") + DebugView.printErrorMsg("[启自驾] 当前订单不存在或异常!") + ToastUtils.showShort("当前订单不存在或异常!") + return + } + //根据开关和后台是否发布轨迹启动自驾 + if (FunctionBuildConfig.isPassStartAutopilotCommand && TextUtils.isEmpty( + contrailBean.csvFileUrl + ) + ) { + ToastUtils.showLong("无发布轨迹, 请发布后重试") + DebugView.printErrorMsg("[启自驾] 无发布轨迹, 请发布后重试") + CallerLogger.e( + TAG, "isPassStartAutopilotCommand = " + + FunctionBuildConfig.isPassStartAutopilotCommand + + "busRoutesResult.csvFileUrl = " + contrailBean.csvFileUrl + ) + return + } + if (!FunctionBuildConfig.isDemoMode && !OCHAdasAbilityManager.getInstance().autopilotAbilityStatus) { + DebugView.printErrorMsg("[启自驾] ${OCHAdasAbilityManager.getInstance().autopilotUnAbilityReason}") + ToastUtils.showLong( + OCHAdasAbilityManager.getInstance().autopilotUnAbilityReason + + ", 请稍候重试" + ) + return + } + + val parameters = initAutopilotControlParameters(grayLineBean, contrailBean) + if (null == parameters) { + CallerLogger.e(TAG, "AutopilotControlParameters is empty.") + return + } + + CallerAutoPilotControlManager.startAutoPilot(parameters) + DebugView.printInfoMsg("[启自驾] 调用成功") + CallerLogger.d( + TAG, "start autopilot with parameter: %s", + GsonUtil.jsonFromObject(parameters) + ) + mControllerStatusCallback?.startOpenAutopilot() + } + + private fun initAutopilotControlParameters( + grayLineBean: GrayLineBean, + contrailBean: ContrailBean + ): AutopilotControlParameters? { + val parameters = AutopilotControlParameters() + val startWgsLon = grayLineBean.startSite!!.wgs84Lon + val startWgsLat = grayLineBean.startSite!!.wgs84Lat + val endWgsLon = grayLineBean.endSite!!.wgs84Lon + val endWgsLat = grayLineBean.endSite!!.wgs84Lat + parameters.vehicleType = TaxiUnmannedConst.BUSINESSTYPE + parameters.startName = + grayLineBean.startSite!!.siteName // 8.10 拼音首字母大写 改为直接传中文 + parameters.endName = + grayLineBean.endSite!!.siteName // 8.10 拼音首字母大写 改为直接传中文 + parameters.startLatLon = + AutopilotControlParameters.AutoPilotLonLat(startWgsLat, startWgsLon) + parameters.endLatLon = AutopilotControlParameters.AutoPilotLonLat(endWgsLat, endWgsLon) + if (parameters.autoPilotLine == null) { + parameters.autoPilotLine = AutopilotControlParameters.AutoPilotLine( + contrailBean.lineId, + contrailBean.lineName, + contrailBean.csvFileUrl, + contrailBean.csvFileMd5, + contrailBean.txtFileUrl, + contrailBean.txtFileMd5, + contrailBean.contrailSaveTime, + TaxiUnmannedConst.BUSINESSTYPE.toString(), + contrailBean.csvFileUrlDPQP, + contrailBean.csvFileMd5DPQP, + contrailBean.txtFileUrlDPQP, + contrailBean.txtFileMd5DPQP, + contrailBean.contrailSaveTimeDPQP + ) + } + return parameters + } + + /** + * 显示/隐藏 前往任务目的地的导航 + * + * @param isShow + */ + fun startNaviToEndStationByAMap(isShow: Boolean) { + mOrderStatusCallback?.onNaviToEnd(true, isShow) + } } \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingUiIntent.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingUiIntent.kt index f6c285633a..f2459f9e57 100644 --- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingUiIntent.kt +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingUiIntent.kt @@ -1,6 +1,7 @@ package com.mogo.och.taxi.ui.routing import com.mogo.och.taxi.base.IUiIntent +import com.mogo.och.taxi.bean.EndGrayTaskFeedbackType import com.mogo.och.taxi.bean.GrayLineBean sealed class TaxiRoutingUiIntent : IUiIntent { @@ -19,8 +20,15 @@ sealed class TaxiRoutingUiIntent : IUiIntent { TaxiRoutingUiIntent() //开始任务 - object StartTaskAction : TaxiRoutingUiIntent() + data class StartTaskAction(val routingTask: RoutingUIState.RoutingTask) : TaxiRoutingUiIntent() + + //问题打点 + data class SubmitGrayLineIssueLocation(val grayId: Long) : TaxiRoutingUiIntent() //展示结束任务反馈弹框 - object ShowFeedbackDialog : TaxiRoutingUiIntent() + data class ShowFeedbackDialog(val grayId: Long) : TaxiRoutingUiIntent() + + //结束任务 + data class SubmitEndTask(val grayId: Long, val type: EndGrayTaskFeedbackType) : + TaxiRoutingUiIntent() } \ No newline at end of file diff --git a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingUiState.kt b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingUiState.kt index 69c83eccee..9aef55856b 100644 --- a/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingUiState.kt +++ b/OCH/taxi/unmanned-driver/src/main/java/com/mogo/och/taxi/ui/routing/TaxiRoutingUiState.kt @@ -9,15 +9,25 @@ data class TaxiRoutingUiState(val routingUiState: RoutingUIState) : IUiState sealed class RoutingUIState { object Init : RoutingUIState() + data class ShowGrayLineList(var data: MutableList) : RoutingUIState() + + data class HideChooseLineLoading(var isCosePage: Boolean) : RoutingUIState() + + data class PostRoutingTaskResult( + val grayLineBean: GrayLineBean?, + val contrailBean: ContrailBean?, + val grayId: Long? + ) : RoutingUIState() + data class RoutingTask( val grayLineBean: GrayLineBean?, val contrailBean: ContrailBean?, val grayId: Long? ) : RoutingUIState() - object ShowFinishTaskButton : RoutingUIState() - object ShowFeedbackDialog : RoutingUIState() - data class ShowGrayLineList(var data: MutableList) : RoutingUIState() + data class ShowFinishTaskButton(val routingTask: RoutingTask) : RoutingUIState() + data class ShowFeedbackDialog(val grayId: Long, val currentTimestamp: Long) : RoutingUIState() + object DismissFeedbackDialog : RoutingUIState() }