[8.4.0][乘客屏] 添加B4模块代码

This commit is contained in:
xinfengkun
2026-02-12 15:05:14 +08:00
parent 4ff040f0a7
commit 1c968c4774
134 changed files with 6086 additions and 9 deletions

View File

@@ -49,11 +49,13 @@ android {
res.srcDirs = [ res.srcDirs = [
'src/main/res', 'src/main/res',
'src/main/res/b2', 'src/main/res/b2',
'src/main/res/b4',
'src/main/res/b1', 'src/main/res/b1',
] ]
java.srcDirs = [ java.srcDirs = [
'src/main/java', 'src/main/java',
'src/main/java/b2', 'src/main/java/b2',
'src/main/java/b4',
'src/main/java/b1', 'src/main/java/b1',
] ]
} }

View File

@@ -0,0 +1,16 @@
package com.mogo.och.shuttle.weaknet.passenger.constant
/**
* Created on 2021/12/6
*/
class B4Const {
companion object {
//站点UUID
const val M2_MAP_STATION_MAKER = "m2_map_station_maker"
/**
* Marker类型
*/
const val TYPE_MARKER_M2_LINE = "TYPE_MARKER_M2_LINE"
}
}

View File

@@ -0,0 +1,203 @@
package com.mogo.och.shuttle.weaknet.passenger.presenter
import androidx.lifecycle.LifecycleOwner
import com.amap.api.maps.model.LatLng
import com.mogo.commons.mvp.Presenter
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.util.ThreadUtils
import com.mogo.och.common.module.biz.birdge.BridgeListener
import com.mogo.och.common.module.biz.birdge.BridgeManager
import com.mogo.och.common.module.manager.loop.BizLoopManager
import com.mogo.och.common.module.utils.RxUtils
import com.mogo.och.data.bean.BusStationBean
import com.mogo.och.shuttle.weaknet.passenger.callback.ADASCallback
import com.mogo.och.shuttle.weaknet.passenger.callback.ICommonCallback
import com.mogo.och.shuttle.weaknet.passenger.constant.B4Const.Companion.M2_MAP_STATION_MAKER
import com.mogo.och.shuttle.weaknet.passenger.model.CommonModel
import com.mogo.och.shuttle.weaknet.passenger.model.PM2ADASModel
import com.mogo.och.shuttle.weaknet.passenger.ui.map.PB4HPMapFragment
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.B4AIMessageManager
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.bean.B4AIMessage
import io.reactivex.disposables.Disposable
import kotlin.properties.Delegates
class PB4ADASPresenter(view: PB4HPMapFragment?) :
Presenter<PB4HPMapFragment?>(view), ADASCallback, ICommonCallback, BridgeListener,
B4AIMessageManager.AIMessageListener {
private val TAG = "PB4ADASPresenter"
private var haveTrajectoryInfos: Boolean by Delegates.observable(false) { _, oldValue, newValue ->
if (oldValue != newValue) {
// checkScreenChange()
}
}
private var havePredictionInfos: Boolean by Delegates.observable(false) { _, oldValue, newValue ->
if (oldValue != newValue) {
// checkScreenChange()
}
}
// 是否有订单
private var haveLine: Boolean by Delegates.observable(false) { _, oldValue, newValue ->
if (oldValue != newValue) {
// checkScreenChange()
}
}
private var arrived: Boolean by Delegates.observable(false) { _, oldValue, newValue ->
if (oldValue != newValue) {
// checkScreenChange()
}
}
private var aiMessageShowmagic: Boolean by Delegates.observable(false) { _, oldValue, newValue ->
if (oldValue != newValue) {
checkScreenChange()
}
}
private var lastAiMessageTime: Long by Delegates.observable(System.currentTimeMillis()) { _, oldValue, newValue ->
if (oldValue != newValue) {
aiMessageShowmagic = true
RxUtils.disposeSubscribe(lastAIMessageCountDown)
lastAIMessageCountDown = RxUtils.createSubscribe(5_000) {
aiMessageShowmagic = false
}
}
}
private var lastAIMessageCountDown: Disposable? = null
override fun onCreate(owner: LifecycleOwner) {
super.onCreate(owner)
PM2ADASModel.INSTANCE.init(context)
initListener()
}
private fun initListener() {
PM2ADASModel.INSTANCE.setAdasCallback(this)
CommonModel.setRouteLineInfoCallback(TAG, this)
BridgeManager.addBridgeListener(TAG, this)
B4AIMessageManager.registerListener(this)
}
private fun removeListener() {
PM2ADASModel.INSTANCE.setAdasCallback(null)
CommonModel.setRouteLineInfoCallback(TAG, null)
CommonModel.releaseListeners()
BridgeManager.removeBridgeListener(TAG)
B4AIMessageManager.unregisterListener(this)
}
override fun onDestroy(owner: LifecycleOwner) {
super.onDestroy(owner)
removeListener()
}
override fun updateHDMapStations(stations: MutableList<MutableList<Double>>) {
for (i in stations.indices) {
mView?.setMapMaker(M2_MAP_STATION_MAKER + i, stations[i])
}
}
override fun clearCustomPolyline() {
ThreadUtils.runOnUiThread {
mView?.clearCustomPolyline()
}
}
override fun updateLineStations(stations: MutableList<BusStationBean>) {
val stationsList = mutableListOf<LatLng>()
val stationsListPass = mutableListOf<LatLng>()
var startStation: LatLng? = null
var endStation: LatLng? = null
for (i in stations.indices) {
val station = stations[i]
val latLng = LatLng(station.gcjLat, station.gcjLon)
if (i == 0) {
startStation = latLng
continue
}
if (i == stations.size - 1) {
endStation = latLng
continue
}
if (station.drivingStatus == 1) {//行驶信息0初始值1已经过2当前站3未到站
stationsListPass.add(latLng)
} else if (station.drivingStatus == 2) {
if (station.isLeaving) {
arrived = false
stationsListPass.add(latLng)
} else {
arrived = true
stationsList.add(latLng)
}
} else {
stationsList.add(latLng)
}
}
ThreadUtils.runOnUiThread {
mView?.updateLineStations(stationsList, stationsListPass, startStation, endStation)
}
PM2ADASModel.INSTANCE.updateHDMapStations(stations)
}
override fun removeHDMapStations() {
mView?.removeMapMaker(M2_MAP_STATION_MAKER)
}
override fun showNoTaskView(noLine: Boolean) {
haveLine = !noLine
ThreadUtils.runOnUiThread {
mView?.showNoTaskView(!noLine)
}
}
override fun onTrajectoryHaveData(haveTrajectoryInfos: Boolean) {
this.haveTrajectoryInfos = haveTrajectoryInfos
// checkScreenChange()
}
override fun onPredictionHavaData(havePredictionInfos: Boolean) {
this.havePredictionInfos = havePredictionInfos
// checkScreenChange()
}
override fun onReceive(msg: B4AIMessage) {
lastAiMessageTime = System.currentTimeMillis()
}
override fun clear() {
}
fun checkScreenChange() {
CallerLogger.d(TAG, "haveLine:$haveLine arrived:$arrived havePredictionInfos:$havePredictionInfos haveTrajectoryInfos:$haveTrajectoryInfos aiMessageShowmagic:$aiMessageShowmagic")
BizLoopManager.runInMainThread {
if (aiMessageShowmagic) {// 有mogomind 消息
updateMapFlag(false)
// 展示高精地图+mogoMind
mView?.showHDMap_mind()
} else {
updateMapFlag(false)
// 展示高精地图
mView?.showHDMap()
}
}
}
private fun updateMapFlag(open: Boolean) {
// if (open) {
// FunctionBuildConfig.isDrawDecIdentifyData = true
// FunctionBuildConfig.isDrawPreIdentifyData = true
// } else {
// FunctionBuildConfig.isDrawDecIdentifyData = false
// FunctionBuildConfig.isDrawPreIdentifyData = false
// }
}
}

View File

@@ -0,0 +1,65 @@
package com.mogo.och.shuttle.weaknet.passenger.presenter
import androidx.lifecycle.LifecycleOwner
import com.mogo.commons.mvp.Presenter
import com.mogo.eagle.core.utilcode.util.ThreadUtils
import com.mogo.och.data.bean.BusStationBean
import com.mogo.och.shuttle.weaknet.passenger.callback.ICommonCallback
import com.mogo.och.shuttle.weaknet.passenger.model.CommonModel
import com.mogo.och.shuttle.weaknet.passenger.model.PM2ADASModel
import com.mogo.och.shuttle.weaknet.passenger.ui.line.PB4DrivingInfoFragment
class PB4DrivingPresenter(view: PB4DrivingInfoFragment?) :
Presenter<PB4DrivingInfoFragment?>(view),
ICommonCallback {
private val TAG = "PB4DrivingPresenter"
init {
CommonModel.init(context)
PM2ADASModel.INSTANCE.init(context)
initListener()
}
override fun onDestroy(owner: LifecycleOwner) {
super.onDestroy(owner)
destroyListener()
CommonModel.releaseListeners()
}
private fun initListener() {
CommonModel.setRouteLineInfoCallback(TAG, this)
}
private fun destroyListener() {
CommonModel.setRouteLineInfoCallback(TAG, null)
}
override fun updateSpeed(speed: Int) {
}
override fun updateRemainMT(meters: Long, timeInSecond: Long) {
ThreadUtils.runOnUiThread {
mView?.updateRemainMT(meters, timeInSecond) //米,秒
}
}
override fun showNoTaskView(empty: Boolean) {
ThreadUtils.runOnUiThread {
mView?.showNoTaskView(empty)
}
if (empty) {
PM2ADASModel.INSTANCE.removeHDMapStations()
}
}
override fun updateStationsInfo(stations: MutableList<BusStationBean>, i: Int, isArrived: Boolean) {
ThreadUtils.runOnUiThread {
mView?.updateStationsInfo(stations, i, isArrived)
}
}
}

View File

@@ -0,0 +1,7 @@
package com.mogo.och.shuttle.weaknet.passenger.presenter
import com.mogo.commons.mvp.Presenter
import com.mogo.och.shuttle.weaknet.passenger.ui.PB4BaseFragment
class PB4Presenter(view: PB4BaseFragment?) :
Presenter<PB4BaseFragment?>(view)

View File

@@ -0,0 +1,188 @@
package com.mogo.och.shuttle.weaknet.passenger.ui
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.fragment.app.Fragment
import com.mogo.commons.mvp.MvpFragment
import com.mogo.eagle.core.data.enums.EventTypeEnumNew
import com.mogo.eagle.core.function.call.hmi.CallerRoadV2NEventWindowListenerManager
import com.mogo.eagle.core.function.call.map.CallerMapRoadListenerManager
import com.mogo.eagle.core.utilcode.kotlin.onClick
import com.mogo.eagle.core.utilcode.util.AppUtils
import com.mogo.eagle.core.utilcode.util.StringUtils
import com.mogo.eagle.core.utilcode.util.UriUtils
import com.mogo.och.common.module.biz.birdge.data.RoadMsg
import com.mogo.och.common.module.biz.media.MediaManager
import com.mogo.och.common.module.manager.loop.BizLoopManager
import com.mogo.och.common.module.manager.transform.OchTransform
import com.mogo.och.common.module.manager.transform.OchTransformDispatch
import com.mogo.och.shuttle.weaknet.passenger.R
import com.mogo.och.shuttle.weaknet.passenger.presenter.PB4Presenter
import com.mogo.och.shuttle.weaknet.passenger.ui.line.PB4DrivingInfoFragment
import com.mogo.och.shuttle.weaknet.passenger.ui.map.PB4HPMapFragment
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.B4AIMessageManager
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.bean.B4AIMessage
import kotlinx.android.synthetic.main.shuttle_p_b4_fragment.b4_test1
import kotlinx.android.synthetic.main.shuttle_p_b4_fragment.b4_test2
import kotlinx.android.synthetic.main.shuttle_p_b4_fragment.b4_test3
import kotlinx.android.synthetic.main.shuttle_p_b4_fragment.b4_tv_shuttle_b2_p_version
import kotlinx.android.synthetic.main.shuttle_p_b4_fragment.b4_video_fragment
/**
* @author: wangmingjun
* @date: 2022/4/12
*/
class PB4BaseFragment :
MvpFragment<PB4BaseFragment?, PB4Presenter?>() {
val TAG = PB4BaseFragment::class.java.simpleName
private var drivingFragment: PB4DrivingInfoFragment? = null
private var hdMapFragment: PB4HPMapFragment? = null
private var mediaFragment: Fragment? = null
private var mediaView: View? = null
// 视频直播流
private val ochTransform = object : OchTransformDispatch {
override fun setVideoView(target: View?) {
super.setVideoView(target)
if (target != null) {
BizLoopManager.runInMainThread {
target.id = R.id.b4_video_show
val params = FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
b4_video_fragment.addView(target, params)
MediaManager.setMediaPause()
}
} else {
BizLoopManager.runInMainThread {
findViewById<View>(R.id.b4_video_show)?.let {
b4_video_fragment.removeView(it)
MediaManager.setMediaResume()
}
}
}
}
}
override fun getLayoutId(): Int {
return R.layout.shuttle_p_b4_fragment
}
override fun getTagName(): String {
return TAG
}
override fun initViews() {
// tv_shuttle_b2_p_version.text = "版本:${AppUtils.getAppVersionName()}"
b4_tv_shuttle_b2_p_version.text = StringUtils.getString(R.string.module_och_version, AppUtils.getAppVersionName())
initFragment()
OchTransform.addListener(TAG, ochTransform)
}
override fun onDestroy() {
OchTransform.removeListener(TAG)
super.onDestroy()
}
/**
* 初始化行程信息,高静地图,宣传 三个fragment
*/
private fun initFragment() {
if (drivingFragment == null) drivingFragment = PB4DrivingInfoFragment()
childFragmentManager.beginTransaction().add(R.id.b4_driving_fragment, drivingFragment!!)
.show(drivingFragment!!).commitAllowingStateLoss()
if (hdMapFragment == null) hdMapFragment = PB4HPMapFragment()
childFragmentManager.beginTransaction().add(R.id.b4_hd_map_fragment, hdMapFragment!!)
.show(hdMapFragment!!).commitAllowingStateLoss()
// if (mediaFragment == null) {
// mediaFragment = MediaManager.Video.getAdFragment()
// }
if (mediaView == null && context != null) {
context?.let {
mediaView = MediaManager.Video.getAdView(it)
}
}
mediaView?.let {
b4_video_fragment.addView(it)
}
// childFragmentManager.beginTransaction().add(R.id.video_fragment, mediaFragment!!)
// .show(mediaFragment!!).commitAllowingStateLoss()
b4_test1.onClick {
CallerRoadV2NEventWindowListenerManager.showImage(
System.currentTimeMillis().toString(),
System.currentTimeMillis(),
EventTypeEnumNew.getUpdateIconRes(EventTypeEnumNew.TYPE_USECASE_ROAD_BUS_STATION.poiType),
String.format(
EventTypeEnumNew.getAlarmContent(EventTypeEnumNew.TYPE_USECASE_ROAD_BUS_STATION.poiType),
100
),
false,
EventTypeEnumNew.getWarningTts(EventTypeEnumNew.TYPE_USECASE_ROAD_BUS_STATION.poiType),
UriUtils.res2Uri(
EventTypeEnumNew.getPoiTypeBg(
EventTypeEnumNew.TYPE_USECASE_ROAD_BUS_STATION.poiType,
false
).toString()
).toString()
)
}
b4_test2.onClick {
CallerMapRoadListenerManager.invokeCrossDevice(true)
}
b4_test3.onClick {
val one = RoadMsg(201, 1, true, false)
val two = RoadMsg(202, 2, false, false)
val three = RoadMsg(203, 3, false, true)
val sortedList = ArrayList<RoadMsg>()
sortedList.add(one)
sortedList.add(two)
sortedList.add(three)
// val ndeEvent = AIMessage.NDEData(System.currentTimeMillis().toString(),"路口车龙","前方路口有车龙",sortedList)
val ndeEvent = B4AIMessage.B4NDEData(
System.currentTimeMillis().toString(),
StringUtils.getString(R.string.module_och_crossing_tailback),
StringUtils.getString(R.string.module_och_crossing_tailback_desc),
sortedList
)
B4AIMessageManager.post(ndeEvent)
// CallerRoadV2NEventWindowListenerManager.showImage(
// System.currentTimeMillis().toString(),
// System.currentTimeMillis(),
// EventTypeEnumNew.getUpdateIconRes(EventTypeEnumNew.TYPE_USECASE_ROAD_BUS_STATION.poiType),
// String.format(
// EventTypeEnumNew.getAlarmContent(EventTypeEnumNew.TYPE_USECASE_ROAD_BUS_STATION.poiType),
// 100
// ),
// false,
// String.format(
// EventTypeEnumNew.getWarningTts(EventTypeEnumNew.TYPE_USECASE_ROAD_BUS_STATION.poiType),
// 100
// ),
// UriUtils.res2Uri(
// EventTypeEnumNew.getPoiTypeBg(
// EventTypeEnumNew.TYPE_USECASE_ROAD_BUS_STATION.poiType,
// false
// ).toString()
// ).toString()
// )
}
}
override fun createPresenter(): PB4Presenter {
return PB4Presenter(this)
}
}

View File

@@ -0,0 +1,124 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.line
import android.os.Bundle
import android.view.View
import com.mogo.commons.mvp.MvpFragment
import com.mogo.eagle.core.utilcode.util.StringUtils
import com.mogo.och.common.module.utils.NumberFormatUtil
import com.mogo.och.data.bean.BusStationBean
import com.mogo.och.shuttle.weaknet.passenger.R
import com.mogo.och.shuttle.weaknet.passenger.presenter.PB4DrivingPresenter
import kotlinx.android.synthetic.main.shuttle_p_b4_driving_info_fragment.b4ArriveView
import kotlinx.android.synthetic.main.shuttle_p_b4_driving_info_fragment.b4EmptyView
import kotlinx.android.synthetic.main.shuttle_p_b4_driving_info_fragment.b4LineView
import kotlin.math.ceil
import kotlin.math.roundToInt
/**
* @author: wangmingjun
* @date: 2022/4/12
*/
class PB4DrivingInfoFragment :
MvpFragment<PB4DrivingInfoFragment?, PB4DrivingPresenter?>() {
override fun getLayoutId(): Int {
return R.layout.shuttle_p_b4_driving_info_fragment
}
override fun getTagName(): String {
return TAG
}
override fun initViews() {
}
override fun initViews(savedInstanceState: Bundle?) {
super.initViews(savedInstanceState)
}
override fun onResume() {
super.onResume()
}
override fun onPause() {
super.onPause()
}
override fun onDestroyView() {
mPresenter?.onDestroy(this)
super.onDestroyView()
}
fun showNoTaskView(haveTask: Boolean) {
if (haveTask) {
b4EmptyView.visibility = View.VISIBLE
b4ArriveView.visibility = View.GONE
b4LineView.visibility = View.GONE
} else {
b4EmptyView.visibility = View.GONE
b4ArriveView.visibility = View.GONE
b4LineView.visibility = View.VISIBLE
}
}
override fun createPresenter(): PB4DrivingPresenter {
return PB4DrivingPresenter(this)
}
fun updateStationsInfo(stations: MutableList<BusStationBean>, i: Int, isArrived: Boolean) {
if (stations.isEmpty()) {
b4EmptyView.visibility = View.VISIBLE
b4ArriveView.visibility = View.GONE
b4LineView.visibility = View.GONE
b4LineView.clear()
} else {
if (isArrived && i != 0) {
b4EmptyView.visibility = View.GONE
b4ArriveView.visibility = View.VISIBLE
b4LineView.visibility = View.GONE
b4ArriveView.setArrivedStation(stations.get(i))
} else {
b4EmptyView.visibility = View.GONE
b4ArriveView.visibility = View.GONE
b4LineView.visibility = View.VISIBLE
}
}
}
/**
* 剩余里程和时间
*/
fun updateRemainMT(meters: Long, timeInSecond: Long) { //米。秒
// var disUnit = "公里"
var disUnit = StringUtils.getString(R.string.module_och_km)
var remainDis: String? = "0"
if (meters > 0) {
if (meters / 1000 < 1) {
// disUnit = "米"
disUnit = StringUtils.getString(R.string.module_och_m)
remainDis = meters.toFloat().roundToInt().toString()
} else {
// disUnit = "公里"
// disUnit = "公里";
disUnit = StringUtils.getString(R.string.module_och_km)
remainDis = NumberFormatUtil.formatLong(meters.toDouble() / 1000)
}
}
val time = ceil(timeInSecond / 60f).toInt()
// "$remainDis$disUnit".also { tv_distance.text = it }
// "${time}分钟".also { tv_left_time.text = it }
}
companion object {
private val TAG = PB4DrivingInfoFragment::class.java.simpleName
}
}

View File

@@ -0,0 +1,139 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.line.arrive
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.drawable.AnimationDrawable
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import androidx.constraintlayout.widget.ConstraintLayout
import com.mogo.commons.AbsMogoApplication
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.och.common.module.manager.loop.BizLoopManager
import com.mogo.och.common.module.utils.ResourcesUtils
import com.mogo.och.data.bean.BusStationBean
import com.mogo.och.shuttle.weaknet.passenger.R
import kotlinx.android.synthetic.main.b4_arrive_view.view.b4_aciv_arrow_left
import kotlinx.android.synthetic.main.b4_arrive_view.view.b4_aciv_arrow_right
import kotlinx.android.synthetic.main.b4_arrive_view.view.b4_aciv_door_left
import kotlinx.android.synthetic.main.b4_arrive_view.view.b4_aciv_door_right
import kotlinx.android.synthetic.main.b4_arrive_view.view.b4_iv_animal_list
import kotlinx.android.synthetic.main.b4_arrive_view.view.b4_och_tv_arrive_station_value
import me.jessyan.autosize.utils.AutoSizeUtils
class B4ArrivedView : ConstraintLayout {
private val TAG = "B4ArrivedView"
constructor(context: Context) : super(context)
constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet)
constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr)
constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attributeSet, defStyleAttr, defStyleRes)
val marginMax = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(), -137f)
val marginMin = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(), -55f)
val animatorArrow = ValueAnimator.ofInt(0, 30).apply {
duration = 500
repeatMode = ValueAnimator.REVERSE
repeatCount = -1
addUpdateListener { animation ->
val index = animation.animatedValue as Int
val paramsLeft = b4_aciv_arrow_left.layoutParams as LayoutParams
paramsLeft.marginEnd = index
b4_aciv_arrow_left.layoutParams = paramsLeft
val paramsRight = b4_aciv_arrow_right.layoutParams as LayoutParams
paramsRight.marginStart = index
b4_aciv_arrow_right.layoutParams = paramsRight
}
}
val animator = ValueAnimator.ofInt(marginMax, marginMin).apply {
duration = 500
addUpdateListener { animation ->
val index = animation.animatedValue as Int
val paramsLeft = b4_aciv_door_left.layoutParams as LayoutParams
paramsLeft.marginEnd = index
b4_aciv_door_left.layoutParams = paramsLeft
val paramsRight = b4_aciv_door_right.layoutParams as LayoutParams
paramsRight.marginStart = index
b4_aciv_door_right.layoutParams = paramsRight
if (index == -100) {
b4_aciv_arrow_left.visibility = VISIBLE
b4_aciv_arrow_right.visibility = VISIBLE
}
}
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
animatorArrow.start()
CallerLogger.d(TAG, "动画结束了")
}
})
}
private fun initView() {
LayoutInflater.from(context).inflate(R.layout.b4_arrive_view, this, true)
b4_och_tv_arrive_station_value.setVertrial(true)
val intArrayOf = intArrayOf(
ResourcesUtils.getColor(R.color.shuttle_p_b4_color_43cefe),
ResourcesUtils.getColor(R.color.shuttle_p_b4_color_1466fb),
)
b4_och_tv_arrive_station_value.setmColorList(intArrayOf)
}
override fun onVisibilityAggregated(isVisible: Boolean) {
super.onVisibilityAggregated(isVisible)
CallerLogger.d(TAG, "isVisible:${isVisible}")
if (isVisible) {
if (!animator.isRunning) {
animator.start()
}
b4_iv_animal_list.visibility = View.VISIBLE
val animationDrawable = b4_iv_animal_list.drawable as AnimationDrawable
animationDrawable.start()
} else {
animator.cancel()
val paramsLeft = b4_aciv_door_left.layoutParams as LayoutParams
paramsLeft.marginEnd = marginMax
b4_aciv_door_left.layoutParams = paramsLeft
val paramsRight = b4_aciv_door_right.layoutParams as LayoutParams
paramsRight.marginStart = marginMax
b4_aciv_door_right.layoutParams = paramsRight
b4_aciv_arrow_left.visibility = GONE
b4_aciv_arrow_right.visibility = GONE
animatorArrow.cancel()
b4_iv_animal_list.visibility = View.VISIBLE
val animationDrawable = b4_iv_animal_list.drawable as AnimationDrawable
animationDrawable.stop()
}
}
fun setArrivedStation(busStationBean: BusStationBean) {
BizLoopManager.runInMainThread {
b4_och_tv_arrive_station_value.text = busStationBean.name
}
}
init {
try {
initView()
} catch (e: Exception) {
e.printStackTrace()
}
}
}

View File

@@ -0,0 +1,38 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.line.autopilot
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import androidx.constraintlayout.widget.ConstraintLayout
import com.mogo.och.shuttle.weaknet.passenger.R
class B4AutopilotView : ConstraintLayout {
private val TAG = "B4AutopilotView"
constructor(context: Context) : super(context)
constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet)
constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr)
constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attributeSet, defStyleAttr, defStyleRes)
private fun initView() {
LayoutInflater.from(context).inflate(R.layout.b4_autopilot, this, true)
}
override fun onVisibilityAggregated(isVisible: Boolean) {
super.onVisibilityAggregated(isVisible)
}
init {
try {
initView()
} catch (e: Exception) {
e.printStackTrace()
}
}
}

View File

@@ -0,0 +1,180 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.line.autopilot.light
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.animation.AlphaAnimation
import android.view.animation.Animation
import android.widget.ImageView
import androidx.constraintlayout.widget.ConstraintLayout
import com.mogo.eagle.core.function.api.datacenter.union.IMoGoTurnLightListener
import com.mogo.eagle.core.function.call.v2x.CallerTurnLightListenerManager
import com.mogo.eagle.core.utilcode.util.ThreadUtils
import com.mogo.och.common.module.manager.light.TurnLightManager
import com.mogo.och.shuttle.weaknet.passenger.R
import kotlinx.android.synthetic.main.shuttle_p_b4_turn_light_status.view.b4_left_select_image
import kotlinx.android.synthetic.main.shuttle_p_b4_turn_light_status.view.b4_right_nor_image
import kotlinx.android.synthetic.main.shuttle_p_b4_turn_light_status.view.b4_right_select_image
/**
* @author: wangmingjun
* @date: 2023/2/13
*/
class B4TurnLightView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr),
IMoGoTurnLightListener, TurnLightManager.TurnLightListener {
companion object {
private const val TAG = "B4TurnLightView"
}
private var isLeftLight: Boolean = false
private var isRightLight: Boolean = false
private var isDisappear: Boolean = false
init {
LayoutInflater.from(context).inflate(R.layout.shuttle_p_b4_turn_light_status, this, true)
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
CallerTurnLightListenerManager.addListener(TAG, this)
TurnLightManager.addTurnLightStatusChangeListener(TAG, this)
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
CallerTurnLightListenerManager.removeListener(TAG)
TurnLightManager.removeTurnLightStatusChangeListener(TAG)
}
override fun hideTurnLightView() {
ThreadUtils.runOnUiThread {
if (!isDisappear) {
isDisappear = true
isLeftLight = false
isRightLight = false
animationDisappear()
}
}
}
override fun statusChange(newStatus: TurnLightManager.TurnLightStatus) {
ThreadUtils.runOnUiThread {
setTurnLight(newStatus)
}
}
/**
* 转向灯动画
*/
private fun setTurnLight(directionLight: TurnLightManager.TurnLightStatus) {
if (!isAttachedToWindow) {
return
}
//根据左右进行显示和隐藏,实际要判断每个来的时间和频度
when (directionLight) {
TurnLightManager.TurnLightStatus.TURN_LIGHT_LEFT -> { //左转向
if (!isLeftLight) {
isLeftLight = true
isRightLight = false
isDisappear = false
showNormalAnimation()
b4_left_select_image.visibility = View.VISIBLE
b4_right_select_image.visibility = View.GONE
b4_right_select_image.clearAnimation()
setAnimation(b4_left_select_image)
}
}
TurnLightManager.TurnLightStatus.TURN_LIGHT_RIGHT -> { //右转向
if (!isRightLight) {
isRightLight = true
isLeftLight = false
isDisappear = false
showNormalAnimation()
b4_left_select_image.visibility = View.GONE
b4_right_select_image.visibility = View.VISIBLE
b4_left_select_image.clearAnimation()
setAnimation(b4_right_select_image)
}
}
TurnLightManager.TurnLightStatus.TURN_LIGHT_NONE -> { //消失
if (!isDisappear) {
isDisappear = true
isLeftLight = false
isRightLight = false
animationDisappear()
}
}
}
}
//显示背景
private fun showNormalAnimation() {
val appearAnimation = AlphaAnimation(0f, 1.0f)
appearAnimation.duration = 300
val appearAnimationImage = AlphaAnimation(0f, 1.0f)
appearAnimation.duration = 500
// turn_light_layout.startAnimation(appearAnimation)
// left_nor_image.startAnimation(appearAnimationImage)
b4_right_nor_image.startAnimation(appearAnimationImage)
// turn_light_layout.visibility = View.VISIBLE
// left_nor_image.visibility = View.VISIBLE
b4_right_nor_image.visibility = View.VISIBLE
}
//消失动画,当转向等数据为空时候
private fun animationDisappear() {
b4_left_select_image.visibility = View.GONE
b4_right_select_image.visibility = View.GONE
b4_left_select_image.clearAnimation()
b4_right_select_image.clearAnimation()
//left_nor_image.clearAnimation()
b4_right_nor_image.clearAnimation()
val disappearAnimationLeft = AlphaAnimation(1.0f, 0f)
disappearAnimationLeft.duration = 300
//left_nor_image.startAnimation(disappearAnimationLeft)
b4_right_nor_image.startAnimation(disappearAnimationLeft)
disappearAnimationLeft.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationRepeat(p0: Animation?) {
}
override fun onAnimationStart(p0: Animation?) {
}
override fun onAnimationEnd(p0: Animation?) {
// left_nor_image.visibility = View.GONE
// right_nor_image.visibility = View.GONE
}
})
}
//实现图片闪烁效果
private fun setAnimation(imageView: ImageView) {
val animationSet = AnimatorSet()
val valueAnimator = ObjectAnimator.ofFloat(imageView, "alpha", 0f, 1.0f)
val valueAnimatorDisappear = ObjectAnimator.ofFloat(imageView, "alpha", 1.0f, 0f)
valueAnimator.duration = 1000
valueAnimatorDisappear.duration = 800
valueAnimator.repeatCount = -1
valueAnimatorDisappear.repeatCount = -1
animationSet.playTogether(valueAnimatorDisappear, valueAnimator)
animationSet.start()
}
}

View File

@@ -0,0 +1,64 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.line.autopilot.speed
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import androidx.constraintlayout.widget.ConstraintLayout
import com.mogo.eagle.core.data.map.MogoLocation
import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLocationGCJ02Listener
import com.mogo.eagle.core.function.hmi.ui.setting.ToggleDebugView
import com.mogo.och.bridge.autopilot.location.OchLocationManager
import com.mogo.och.common.module.manager.loop.BizLoopManager
import com.mogo.och.shuttle.weaknet.passenger.R
import kotlinx.android.synthetic.main.b4_speed.view.b4_tv_speed
import kotlin.math.abs
class B4SpeedView : ConstraintLayout, IMoGoChassisLocationGCJ02Listener {
private val TAG = "B4SpeedView"
constructor(context: Context) : super(context)
constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet)
constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr)
constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attributeSet, defStyleAttr, defStyleRes)
private fun initView() {
LayoutInflater.from(context).inflate(R.layout.b4_speed, this, true)
b4_tv_speed.setOnLongClickListener {
context?.let { ToggleDebugView.toggleDebugView.toggle(it) }
true
}
}
override fun onVisibilityAggregated(isVisible: Boolean) {
super.onVisibilityAggregated(isVisible)
if (isVisible) {
OchLocationManager.addGCJ02Listener(TAG, 3, this)
} else {
OchLocationManager.removeGCJ02Listener(TAG)
}
}
init {
try {
initView()
} catch (e: Exception) {
e.printStackTrace()
}
}
override fun onChassisLocationGCJ02(mogoLocation: MogoLocation?) {
mogoLocation?.let {
BizLoopManager.runInMainThread {
val speedKM = (abs(it.gnssSpeed) * 3.6f).toInt()
b4_tv_speed.text = speedKM.toString()
}
}
}
}

View File

@@ -0,0 +1,127 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.line.autopilot.status
import android.content.Context
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.content.ContextCompat
import com.mogo.eagle.core.data.config.FunctionBuildConfig
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener
import com.mogo.eagle.core.function.api.telematic.IReceivedMsgListener
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
import com.mogo.eagle.core.function.call.telematic.CallerTelematicListenerManager
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.och.common.module.manager.loop.BizLoopManager
import com.mogo.och.shuttle.weaknet.passenger.R
import com.mogo.och.shuttle.weaknet.passenger.callback.ICommonCallback
import com.mogo.och.shuttle.weaknet.passenger.model.CommonModel
class B4StatusView : AppCompatTextView, ICommonCallback, IReceivedMsgListener {
private val TAG = "B4StatusView"
constructor(context: Context) : super(context)
constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet)
constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(
context,
attributeSet,
defStyleAttr
)
override fun onAttachedToWindow() {
super.onAttachedToWindow()
CallerTelematicListenerManager.addListener(TAG, this)
CommonModel.setRouteLineInfoCallback(TAG, this)
updateAutoIconState(0)
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
CallerTelematicListenerManager.removeListener(TAG)
CommonModel.setRouteLineInfoCallback(TAG, null)
}
private fun initView() {
}
override fun onB2DemoMode(isB2DemoMode: Boolean) {
super.onB2DemoMode(isB2DemoMode)
updateAutoIconState(1)
}
//美化模式状态变更回调
override fun onDemoMode(isDemoMode: Boolean) {
super.onDemoMode(isDemoMode)
updateAutoIconState(2)
}
override fun updateInOrderStatus(inOrder: Boolean) {
super.updateInOrderStatus(inOrder)
updateAutoIconState(3)
}
//自动驾驶状态变更
override fun updateAutoStatus(state: Int) {
updateAutoIconState(4)
}
private fun getStateIcon(source: Int): Int {
// 平行驾驶状态下
val sourceStr = when (source) {
0 -> "View初始化"
1 -> "B2美化模式状态变更"
2 -> "美化模式状态变更"
3 -> "订单状态变更"
4 -> "自动驾驶状态变更"
else -> "错误"
}
val autopilotState = CallerAutoPilotStatusListenerManager.getState()
CallerLogger.i(
TAG,
"数据刷新来源=$sourceStr 自动驾驶状态=${autopilotState} 订单状态=${CommonModel.inOrder} 美化模式状态=${FunctionBuildConfig.isDemoMode} B2美化模式状态=${FunctionBuildConfig.isB2DemoMode} "
)
if (IMoGoAutopilotStatusListener.STATUS_PARALLEL_DRIVING == autopilotState) {
return R.drawable.b4_status_parallel
}
// 处理非平行驾驶状态的情况
return when {
// 无订单的情况
!CommonModel.inOrder -> {
R.drawable.b4_status_basic
}
// 有订单且美化状态和b2美化状态任意开着
CommonModel.inOrder && (FunctionBuildConfig.isDemoMode || FunctionBuildConfig.isB2DemoMode) -> {
R.drawable.b4_status_order_auto
}
// 有订单且美化状态和b2美化状态都关着
CommonModel.inOrder && !FunctionBuildConfig.isDemoMode && !FunctionBuildConfig.isB2DemoMode -> {
if (autopilotState == IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING) R.drawable.b4_status_order_auto else R.drawable.b4_status_basic
}
// 覆盖所有可能的情况
else -> R.drawable.b4_status_basic
}
}
private fun updateAutoIconState(source: Int) {
BizLoopManager.runInMainThread {
context?.let {
setTextColor(ContextCompat.getColor(it, R.color.common_FFFFFF))
background = ContextCompat.getDrawable(it, getStateIcon(source))
}
}
}
init {
try {
initView()
} catch (e: Exception) {
e.printStackTrace()
}
}
}

View File

@@ -0,0 +1,47 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.line.empty
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import androidx.constraintlayout.widget.ConstraintLayout
import com.mogo.och.common.module.utils.ResourcesUtils
import com.mogo.och.shuttle.weaknet.passenger.R
import kotlinx.android.synthetic.main.b4_empty_view.view.b4_tv_title
class B4EmptyView : ConstraintLayout {
private val TAG = "B4EmptyView"
constructor(context: Context) : super(context)
constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet)
constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr)
constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attributeSet, defStyleAttr, defStyleRes)
private fun initView() {
LayoutInflater.from(context).inflate(R.layout.b4_empty_view, this, true)
b4_tv_title.setVertrial(true)
val intArrayOf = intArrayOf(
ResourcesUtils.getColor(R.color.shuttle_p_b4_color_43cefe),
ResourcesUtils.getColor(R.color.shuttle_p_b4_color_1466fb),
)
b4_tv_title.setmColorList(intArrayOf)
}
override fun onVisibilityAggregated(isVisible: Boolean) {
super.onVisibilityAggregated(isVisible)
}
init {
try {
initView()
} catch (e: Exception) {
e.printStackTrace()
}
}
}

View File

@@ -0,0 +1,87 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.line.lineinfo
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.findViewTreeViewModelStoreOwner
import androidx.recyclerview.widget.LinearLayoutManager
import com.mogo.och.common.module.manager.loop.BizLoopManager
import com.mogo.och.data.bean.BusStationBean
import com.mogo.och.shuttle.weaknet.passenger.R
import com.mogo.och.shuttle.weaknet.passenger.ui.line.lineinfo.item.B4ItemDecoration
import com.mogo.och.shuttle.weaknet.passenger.ui.line.lineinfo.item.B4StationAdapter
import kotlinx.android.synthetic.main.b4_line_view.view.b4_ll_station_container
class B4LineView : ConstraintLayout, B4LineViewModel.LineViewCallback {
private val TAG = "B4LineView"
constructor(context: Context) : super(context)
constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet)
constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr)
constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attributeSet, defStyleAttr, defStyleRes)
private lateinit var mAdapter: B4StationAdapter
private lateinit var linearLayoutManager: LinearLayoutManager
private var viewModel: B4LineViewModel? = null
private fun initView() {
LayoutInflater.from(context).inflate(R.layout.b4_line_view, this, true)
linearLayoutManager = LinearLayoutManager(context)
b4_ll_station_container.setLayoutManager(linearLayoutManager)
mAdapter = B4StationAdapter()
b4_ll_station_container.addItemDecoration(B4ItemDecoration())
b4_ll_station_container.setAdapter(mAdapter)
b4_ll_station_container.itemAnimator?.addDuration = 0;
b4_ll_station_container.itemAnimator?.changeDuration = 0;
b4_ll_station_container.itemAnimator?.moveDuration = 0;
b4_ll_station_container.itemAnimator?.removeDuration = 0;
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
viewModel = findViewTreeViewModelStoreOwner()?.let {
ViewModelProvider(it).get(B4LineViewModel::class.java)
}
viewModel?.setLineCallback(this)
}
override fun onVisibilityAggregated(isVisible: Boolean) {
super.onVisibilityAggregated(isVisible)
}
init {
try {
initView()
} catch (e: Exception) {
e.printStackTrace()
}
}
override fun updateLineStations(stations: MutableList<BusStationBean>?) {
// CallerLogger.d(TAG,"展示站点:${stations}")
mAdapter.submitList(stations)
}
override fun updateRemainMt(distance: String, time: String) {
BizLoopManager.runInMainThread {
mAdapter.notifyDistanceAndTime(distance, time)
}
}
fun clear() {
mAdapter.clear()
}
}

View File

@@ -0,0 +1,80 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.line.lineinfo
import androidx.lifecycle.ViewModel
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_BUS
import com.mogo.eagle.core.utilcode.util.StringUtils
import com.mogo.och.common.module.manager.loop.BizLoopManager
import com.mogo.och.common.module.utils.NumberFormatUtil
import com.mogo.och.data.bean.BusStationBean
import com.mogo.och.shuttle.weaknet.passenger.R
import com.mogo.och.shuttle.weaknet.passenger.callback.ICommonCallback
import com.mogo.och.shuttle.weaknet.passenger.model.CommonModel
import io.reactivex.disposables.Disposable
import kotlin.math.ceil
import kotlin.math.roundToInt
/**
* @author XuXinChao
* @description BadCase录包管理页面
* @since: 2022/12/15
*/
class B4LineViewModel : ViewModel(), ICommonCallback {
private val TAG = M_BUS + B4LineViewModel::class.java.simpleName
private var viewCallback: LineViewCallback? = null
private var endTaskDisposable: Disposable? = null
override fun onCleared() {
d(TAG, "onCleared")
CommonModel.setRouteLineInfoCallback(TAG, null)
}
fun setLineCallback(viewCallback: LineViewCallback) {
this.viewCallback = viewCallback
CommonModel.setRouteLineInfoCallback(TAG, this)
}
override fun updateLineStations(stations: MutableList<BusStationBean>?) {
BizLoopManager.runInMainThread {
this.viewCallback?.updateLineStations(stations)
}
}
override fun updateRemainMT(meters: Long, timeInSecond: Long) {
super.updateRemainMT(meters, timeInSecond)
// var disUnit = "公里"
var disUnit = StringUtils.getString(R.string.module_och_km)
var remainDis: String? = "0"
if (meters > 0) {
if (meters / 1000 < 1) {
// disUnit = "米"
disUnit = StringUtils.getString(R.string.module_och_m)
remainDis = meters.toFloat().roundToInt().toString()
} else {
// disUnit = "公里"
disUnit = StringUtils.getString(R.string.module_och_km)
remainDis = NumberFormatUtil.formatLong(meters.toDouble() / 1000)
}
}
val time = ceil(timeInSecond / 60f).toInt()
// "$remainDis$disUnit".also { tv_distance.text = it }
// "${time}分钟".also { tv_left_time.text = it }
// this.viewCallback?.updateRemainMt("$remainDis$disUnit","${time}分钟")
this.viewCallback?.updateRemainMt("$remainDis$disUnit", "${time}${StringUtils.getString(R.string.module_och_minute)}")
}
interface LineViewCallback {
fun updateLineStations(stations: MutableList<BusStationBean>?)
fun updateRemainMt(distance: String, time: String)
}
}

View File

@@ -0,0 +1,40 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.line.lineinfo.item
import android.graphics.Rect
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import me.jessyan.autosize.utils.AutoSizeUtils
/**
* 这是LinearLayoutManager设置Item间距的的一个辅助类
*
* @author donghongyu
*/
class B4ItemDecoration() : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect, view: View,
parent: RecyclerView, state: RecyclerView.State
) {
if ((parent.adapter?.itemCount ?: 4) < 4) {
val height = AutoSizeUtils.dp2px(parent.context, 140f)
val layoutParams = view.layoutParams as RecyclerView.LayoutParams
layoutParams.height = height
view.layoutParams = layoutParams
} else if ((parent.adapter?.itemCount ?: 4) == 4) {
val height = AutoSizeUtils.dp2px(parent.context, 100f)
val layoutParams = view.layoutParams as RecyclerView.LayoutParams
layoutParams.height = height
view.layoutParams = layoutParams
} else {
val height = AutoSizeUtils.dp2px(parent.context, 68f)
val layoutParams = view.layoutParams as RecyclerView.LayoutParams
layoutParams.height = height
view.layoutParams = layoutParams
}
super.getItemOffsets(outRect, view, parent, state)
}
}

View File

@@ -0,0 +1,239 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.line.lineinfo.item
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
import com.mogo.och.data.bean.BusStationBean
import com.mogo.och.shuttle.weaknet.passenger.R
class B4StationAdapter : ListAdapter<BusStationBean, B4StationViewHolder>(B4MessageDiffCallback()) {
var currentIndex = 0
var distanceAndTime = ""
override fun submitList(list: MutableList<BusStationBean>?) {
list?.let {
var currentStationIndex = -1
var isLeavingStatus = false
// --- 新逻辑开始 ---
// 1. 首选查找: 查找第一个 drivingStatus == 2 且 tag != 2 的站点
val currentStation = it.firstOrNull { bean ->
bean.drivingStatus == 2 && bean.tag != 2
}
if (currentStation != null) {
currentStationIndex = it.indexOf(currentStation)
isLeavingStatus = currentStation.isLeaving
} else {
// 2. 备用查找: 如果找不到,则查找第一个 tag != 2 的站点
val firstValidStation = it.firstOrNull { bean ->
bean.tag != 2
}
if (firstValidStation != null) {
currentStationIndex = it.indexOf(firstValidStation)
isLeavingStatus = firstValidStation.isLeaving
} else {
// 如果整个列表都没有 tag != 2 的站点,则保持默认值 -1 (或 0)
currentStationIndex = 0 // 默认为第一个
isLeavingStatus = false
}
}
// 3. 处理 isLeaving 状态,更新 currentIndex 到下一个有效站点
if (currentStationIndex != -1 && isLeavingStatus) {
// 从当前站点的下一个位置开始查找第一个 tag != 2 的站点
val nextValidStation = it.subList(currentStationIndex + 1, it.size)
.firstOrNull { bean -> bean.tag != 2 }
if (nextValidStation != null) {
// 更新 currentIndex 为下一个有效站点的实际索引
currentStationIndex = it.indexOf(nextValidStation)
} else {
// 如果后面没有 tag != 2 的站点,则 currentIndex 保持在列表末尾或上一个有效站点的索引
currentStationIndex = currentStationIndex // 保持在当前站点的索引
}
}
// 更新 Adapter 的 currentIndex 和 isLeaving虽然 isLeaving 没有直接存储在 Adapter 中,但逻辑上已处理)
currentIndex = if (currentStationIndex != -1) currentStationIndex else 0
// --- 新逻辑结束 ---
val newDataList = mutableListOf<BusStationBean>()
var showPassOmit = false
var showFuluterOmit = false
if ((it.size) <= 7) {
showPassOmit = false
showFuluterOmit = false
newDataList.addAll(it.toList())
} else {
if (currentIndex - 1 < 3) {
showPassOmit = false // 全展示
} else {
showPassOmit = true // 展示省略
}
if (it.size - (currentIndex + 1) - 1 < 3) {// 全展示
showFuluterOmit = false
} else {// 展示省略
showFuluterOmit = true
}
if (showPassOmit && showFuluterOmit) {// 都有
newDataList.add(it.first())
newDataList.add(B4StationBeanOmit(currentIndex - 1 - 1))
newDataList.addAll(list.slice(currentIndex - 1..currentIndex + 1))
newDataList.add(B4StationBeanOmit(list.size - (currentIndex + 3)))// 减去+1 省略 和最后一个
newDataList.add(list.last())
} else {
if (showFuluterOmit || showPassOmit) {
if (showFuluterOmit) {// 只展示下面的省略号
newDataList.addAll(list.subList(0, 5))
newDataList.add(B4StationBeanOmit(list.size - 5 - 1))
newDataList.add(list.last())
}
if (showPassOmit) {// 只展示上面的手机号
newDataList.add(list.first())
newDataList.add(B4StationBeanOmit(list.size - 5 - 1))
newDataList.addAll(list.slice(list.size - 5 until list.size))
} else {
// 保持原来的逻辑,如果不满足省略条件,则全展示
}
} else {
newDataList.addAll(it.toList())
}
}
}
// 在将列表提交给 ListAdapter 之前,再次确定 currentIndex。
// 这里的逻辑需要根据newDataList重新计算currentIndex因为列表可能已经被裁剪和插入了省略号
// 但是因为省略号逻辑是根据原始 currentIndex 计算的,所以我们只需确保在最终列表中正确标记 'CurrentStation' 即可。
// 考虑到 getItemViewType 依赖 position 和 currentIndex 来判断 ViewType我们保留在提交前更新 currentIndex 的步骤。
// 再次更新 currentIndex以匹配 newDataList 中的索引位置
if (currentStationIndex != -1) {
// 找到原列表中 currentIndex 对应的站点对象
val originalCurrentBean = it[currentStationIndex]
// 查找该对象在 newDataList 中的新索引
val newIndex = newDataList.indexOfFirst { item ->
// 确保 item 是 BusStationBean 且与原始对象匹配
item is BusStationBean && item.siteId == originalCurrentBean.siteId
}
currentIndex = if (newIndex != -1) newIndex else 0 // 如果找不到,则默认为第一个
} else {
currentIndex = 0
}
distanceAndTime = ""
super.submitList(newDataList)
}
}
override fun onBindViewHolder(holder: B4StationViewHolder, position: Int) {
getItem(position)?.let {
holder.bind(it, distanceAndTime)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): B4StationViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
B4StationViewHolder.NormalStationStart -> B4NormalStationStartViewHolder(
inflater.inflate(R.layout.b4_station_normal_start_view, parent, false)
)
B4StationViewHolder.NormalStationEnd -> B4NormalStationEndViewHolder(
inflater.inflate(R.layout.b4_station_normal_end_view, parent, false)
)
B4StationViewHolder.NormalStationFuture -> B4NormalStationFutureViewHolder(
inflater.inflate(R.layout.b4_station_normal_future_view, parent, false)
)
B4StationViewHolder.NormalStationPass -> B4NormalStationPassViewHolder(
inflater.inflate(R.layout.b4_station_normal_pass_view, parent, false)
)
B4StationViewHolder.CurrentStationStart -> B4CurrentStationStartViewHolder(
inflater.inflate(R.layout.b4_station_current_start_view, parent, false)
)
B4StationViewHolder.CurrentStationEnd -> B4CurrentStationEndViewHolder(
inflater.inflate(R.layout.b4_station_current_end_view, parent, false)
)
B4StationViewHolder.CurrentStation -> B4CurrentStationViewHolder(
inflater.inflate(R.layout.b4_station_current_view, parent, false)
)
B4StationViewHolder.OmitStationPass -> B4OmitPassViewHolder(
inflater.inflate(R.layout.b4_station_omit_view_pass, parent, false)
)
B4StationViewHolder.OmitStationFuture -> B4OmitFutureViewHolder(
inflater.inflate(R.layout.b4_station_omit_view_future, parent, false)
)
else -> throw IllegalArgumentException("Invalid view type")
}
}
override fun getItemViewType(position: Int): Int {
if (getItem(position) is B4StationBeanOmit) {
return if (position < currentIndex) {
B4StationViewHolder.OmitStationPass
} else {
B4StationViewHolder.OmitStationFuture
}
}
when (position) {
0 -> {
return if (currentIndex == position) {
B4StationViewHolder.CurrentStationStart
} else {
B4StationViewHolder.NormalStationStart
}
}
itemCount - 1 -> {
return if (currentIndex == position) {
B4StationViewHolder.CurrentStationEnd
} else {
B4StationViewHolder.NormalStationEnd
}
}
else -> {
return if (currentIndex == position) {
B4StationViewHolder.CurrentStation
} else if (currentIndex < position) {
B4StationViewHolder.NormalStationFuture
} else {
B4StationViewHolder.NormalStationPass
}
}
}
}
fun clear() {
super.submitList(null)
currentIndex = 0
distanceAndTime = ""
}
override fun onViewRecycled(holder: B4StationViewHolder) {
super.onViewRecycled(holder)
holder.viewRecycled(holder)
}
fun notifyDistanceAndTime(distance: String, time: String) {
if (currentList.isNotEmpty() && currentIndex < itemCount) {
distanceAndTime = "${distance}·${time}"
notifyItemChanged(currentIndex)
}
}
}

View File

@@ -0,0 +1,17 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.line.lineinfo.item
import androidx.recyclerview.widget.DiffUtil
import com.mogo.och.data.bean.BusStationBean
class B4MessageDiffCallback : DiffUtil.ItemCallback<BusStationBean>() {
override fun areContentsTheSame(oldItem: BusStationBean, newItem: BusStationBean): Boolean {
return oldItem == newItem
}
override fun areItemsTheSame(oldItem: BusStationBean, newItem: BusStationBean): Boolean {
return oldItem.siteId == newItem.siteId
}
}
data class B4StationBeanOmit(var coutOmit: Int) : BusStationBean()

View File

@@ -0,0 +1,156 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.line.lineinfo.item
import android.view.View
import androidx.appcompat.widget.AppCompatTextView
import androidx.recyclerview.widget.RecyclerView
import com.mogo.eagle.core.utilcode.util.StringUtils
import com.mogo.och.common.module.utils.ResourcesUtils
import com.mogo.och.common.module.wigets.OCHGradientTextView
import com.mogo.och.data.bean.BusStationBean
import com.mogo.och.shuttle.weaknet.passenger.R
import java.text.SimpleDateFormat
import java.util.Locale
abstract class B4StationViewHolder(view: View) : RecyclerView.ViewHolder(view) {
abstract fun bind(item: BusStationBean, distanceAndView: String)
open fun viewRecycled(holder: B4StationViewHolder) {}
private val sampleDateFormat = SimpleDateFormat("HH:mm", Locale.CHINA)
protected val TAG = javaClass.simpleName
companion object {
val CurrentStationStart = 0
val CurrentStationEnd = 1
val CurrentStation = 2
val NormalStationStart = 3
var NormalStationEnd = 4
val NormalStationPass = 5
val NormalStationFuture = 6
val OmitStationPass = 7
val OmitStationFuture = 8
}
}
class B4NormalStationStartViewHolder(binding: View) : B4StationViewHolder(binding) {
private var startStaionName: AppCompatTextView = binding.findViewById(R.id.b4_actv_normal_station_start)
private val stationStatus: AppCompatTextView = itemView.findViewById(R.id.b4_station_status)//站点状态
override fun bind(item: BusStationBean, distanceAndView: String) {
startStaionName.text = item.name
stationStatus.visibility = if (item.tag == 2) {
View.VISIBLE
} else {
View.GONE
}
}
}
class B4NormalStationEndViewHolder(binding: View) : B4StationViewHolder(binding) {
private var endStaionName: AppCompatTextView = binding.findViewById(R.id.b4_actv_normal_station_end)
private val stationStatus: AppCompatTextView = itemView.findViewById(R.id.b4_station_status)//站点状态
override fun bind(item: BusStationBean, distanceAndView: String) {
endStaionName.text = item.name
stationStatus.visibility = if (item.tag == 2) {
View.VISIBLE
} else {
View.GONE
}
}
}
class B4NormalStationPassViewHolder(binding: View) : B4StationViewHolder(binding) {
private var passStaionName: AppCompatTextView = binding.findViewById(R.id.b4_actv_normal_station_pass)
private val stationStatus: AppCompatTextView = itemView.findViewById(R.id.b4_station_status)//站点状态
override fun bind(item: BusStationBean, distanceAndView: String) {
passStaionName.text = item.name
stationStatus.visibility = if (item.tag == 2) {
View.VISIBLE
} else {
View.GONE
}
}
}
class B4NormalStationFutureViewHolder(binding: View) : B4StationViewHolder(binding) {
private var futureStaionName: AppCompatTextView = binding.findViewById(R.id.b4_actv_normal_station_future)
private val stationStatus: AppCompatTextView = itemView.findViewById(R.id.b4_station_status)//站点状态
override fun bind(item: BusStationBean, distanceAndView: String) {
futureStaionName.text = item.name
stationStatus.visibility = if (item.tag == 2) {
View.VISIBLE
} else {
View.GONE
}
}
}
class B4CurrentStationViewHolder(binding: View) : B4StationViewHolder(binding) {
private var currentStaionName: OCHGradientTextView = binding.findViewById(R.id.b4_och_current_station_name)
private var actv_distance: AppCompatTextView = binding.findViewById(R.id.b4_actv_distance)
override fun bind(item: BusStationBean, distanceAndView: String) {
var text = item.name ?: ""
if (text.length > 12) {
text = text.slice(0..10) + ""
}
currentStaionName.text = text
currentStaionName.setVertrial(true)
val intArrayOf = intArrayOf(
ResourcesUtils.getColor(R.color.shuttle_p_b4_color_43cefe),
ResourcesUtils.getColor(R.color.shuttle_p_b4_color_1466fb),
)
currentStaionName.setmColorList(intArrayOf)
actv_distance.text = distanceAndView
}
}
class B4CurrentStationStartViewHolder(binding: View) : B4StationViewHolder(binding) {
private var currentStaionStartName: OCHGradientTextView = binding.findViewById(R.id.b4_och_current_station_start_name)
override fun bind(item: BusStationBean, distanceAndView: String) {
currentStaionStartName.text = item.name
val intArrayOf = intArrayOf(
ResourcesUtils.getColor(R.color.shuttle_p_b4_color_43cefe),
ResourcesUtils.getColor(R.color.shuttle_p_b4_color_1466fb),
)
currentStaionStartName.setmColorList(intArrayOf)
}
}
class B4CurrentStationEndViewHolder(binding: View) : B4StationViewHolder(binding) {
private var currentStaionEndName: OCHGradientTextView = binding.findViewById(R.id.b4_och_current_station_end_name)
private var actv_distance_end: AppCompatTextView = binding.findViewById(R.id.b4_actv_distance_end)
override fun bind(item: BusStationBean, distanceAndView: String) {
var text = item.name ?: ""
if (text.length > 12) {
text = text.slice(0..10) + ""
}
currentStaionEndName.text = text
val intArrayOf = intArrayOf(
ResourcesUtils.getColor(R.color.shuttle_p_b4_color_43cefe),
ResourcesUtils.getColor(R.color.shuttle_p_b4_color_1466fb),
)
currentStaionEndName.setmColorList(intArrayOf)
actv_distance_end.text = distanceAndView
}
}
class B4OmitPassViewHolder(binding: View) : B4StationViewHolder(binding) {
private var omitCout: AppCompatTextView = binding.findViewById(R.id.b4_actv_pass_omit_cout)
override fun bind(item: BusStationBean, distanceAndView: String) {
if (item is B4StationBeanOmit) {
// omitCout.text = "${item.coutOmit}站"
omitCout.text = StringUtils.getString(R.string.module_och_station, item.coutOmit)
}
}
}
class B4OmitFutureViewHolder(binding: View) : B4StationViewHolder(binding) {
private var omitCout: AppCompatTextView = binding.findViewById(R.id.b4_actv_future_omit_count)
override fun bind(item: BusStationBean, distanceAndView: String) {
if (item is B4StationBeanOmit) {
// omitCout.text = "${item.coutOmit}站"
omitCout.text = StringUtils.getString(R.string.module_och_station, item.coutOmit)
}
}
}

View File

@@ -0,0 +1,298 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.map
import android.graphics.BitmapFactory
import android.os.Bundle
import android.view.View
import androidx.constraintlayout.widget.ConstraintLayout
import com.amap.api.maps.model.LatLng
import com.mogo.commons.AbsMogoApplication
import com.mogo.commons.mvp.MvpFragment
import com.mogo.eagle.core.function.call.map.CallerMapUIServiceManager
import com.mogo.eagle.core.function.view.SiteMarkerBean
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
import com.mogo.eagle.core.widget.media.video.TextureVideoViewOutlineProvider
import com.mogo.map.MapDataWrapper
import com.mogo.map.overlay.core.Level
import com.mogo.map.overlay.point.Point
import com.mogo.och.common.module.utils.OCHThreadPoolManager
import com.mogo.och.shuttle.weaknet.passenger.R
import com.mogo.och.shuttle.weaknet.passenger.constant.B4Const.Companion.TYPE_MARKER_M2_LINE
import com.mogo.och.shuttle.weaknet.passenger.presenter.PB4ADASPresenter
import kotlinx.android.synthetic.main.shuttle_p_b4_hpmap_fragment.b4_aciv_top_shader
import kotlinx.android.synthetic.main.shuttle_p_b4_hpmap_fragment.b4HomeView
import kotlinx.android.synthetic.main.shuttle_p_b4_hpmap_fragment.b4MindView
import kotlinx.android.synthetic.main.shuttle_p_b4_hpmap_fragment.b4OverMapView
import me.jessyan.autosize.utils.AutoSizeUtils
import java.util.*
/**
* @author: wangmingjun
* @date: 2022/4/12
*/
class PB4HPMapFragment :
MvpFragment<PB4HPMapFragment?, PB4ADASPresenter?>() {
private val stationIcon = BitmapFactory.decodeResource(
AbsMogoApplication.getApp().resources,
R.drawable.shuttle_p_b4_map_staton_icon
)
private val stationPassIcon = BitmapFactory.decodeResource(
AbsMogoApplication.getApp().resources,
R.drawable.shuttle_p_b4_map_staton_arrived_icon
)
private val startStationIcon = BitmapFactory.decodeResource(
AbsMogoApplication.getApp().resources,
R.drawable.shuttle_p_b4_map_start_icon
)
private val endStationIcon = BitmapFactory.decodeResource(
AbsMogoApplication.getApp().resources,
R.drawable.shuttle_p_b4_map_end_icon
)
/**
* 改变自动驾驶状态
*
* @param status 2 - running 1 - enable 2 - disable
*/
override fun getLayoutId(): Int {
return R.layout.shuttle_p_b4_hpmap_fragment
}
override fun getTagName(): String {
return TAG
}
override fun initViews() {
}
override fun initViews(savedInstanceState: Bundle?) {
super.initViews(savedInstanceState)
b4HomeView.onCreate(savedInstanceState)
b4OverMapView?.let {
it.onCreateView(savedInstanceState)
val radius = AutoSizeUtils.dp2px(requireContext(), 16f)
it.outlineProvider = TextureVideoViewOutlineProvider(radius.toFloat())
it.clipToOutline = true
it.hideResetView()
}
// cl_prediction_contain.onCreate(savedInstanceState)
}
override fun onResume() {
super.onResume()
b4HomeView.onResume()
b4OverMapView?.onResume()
// cl_prediction_contain.onResume()
}
override fun onLowMemory() {
super.onLowMemory()
b4HomeView.onLowMemory()
// cl_prediction_contain.onLowMemory()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
b4HomeView.onSaveInstanceState(outState)
// cl_prediction_contain.onSaveInstanceState(outState)
}
override fun onPause() {
super.onPause()
b4HomeView.onPause()
b4OverMapView?.onPause()
// cl_prediction_contain.onPause()
}
override fun onDestroyView() {
b4HomeView.onDestroy()
b4OverMapView?.onDestroy()
// cl_prediction_contain.onDestroy()
super.onDestroyView()
}
override fun createPresenter(): PB4ADASPresenter {
return PB4ADASPresenter(this)
}
companion object {
private val TAG = PB4HPMapFragment::class.java.simpleName
}
fun updateLineStations(
stations: MutableList<LatLng>,
stationsPass: MutableList<LatLng>,
startStation: LatLng?,
endStation: LatLng?
) {
b4OverMapView?.let {
val stationsList: MutableList<SiteMarkerBean> = mutableListOf()
startStation?.let { start ->
stationsList.add(SiteMarkerBean(start, startStationIcon, 0.5f, 0.5f))
}
for (stationPass in stationsPass) {
stationsList.add(SiteMarkerBean(stationPass, stationPassIcon, 0.5f, 0.5f))
}
for (stationPass in stations) {
stationsList.add(SiteMarkerBean(stationPass, stationIcon, 0.5f, 0.5f))
}
endStation?.let { end ->
stationsList.add(SiteMarkerBean(end, endStationIcon, 0.5f, 0.5f))
}
it.drawSiteMarkers(stationsList)
}
}
fun setMapMaker(
uuid: String,
station: MutableList<Double>,
) {
//开启线程执行起终点marker设置
val setMapMarkerRunnable = Runnable {
d(
"setMapMaker= " + Thread.currentThread().name,
uuid + "=latitude=" + station[1] + ",longitude=" + station[0]
)
val builder = Point.Options.Builder(
TYPE_MARKER_M2_LINE,
Level.MAP_MARKER
)
.setId(uuid)
.anchor(0.5f, 0.5f)
.set3DMode(true)
.isUseGps(true)
.controlAngle(true)
.icon3DRes(R.raw.b4_star_marker)
.longitude(station[0])
.latitude(station[1])
MapDataWrapper.getCenterLineInfo(
station[0], station[1], -1f
) {
// 有可能鹰眼map为空没有角度。判空使用后可能造成maker角度跟道路角度不一致 地图未初始化会返回空
it?.let {
builder.rotate(it.angle.toFloat())
}
val overlayManager = CallerMapUIServiceManager.getOverlayManager()
overlayManager?.showOrUpdatePoint(builder.build())
}
}
OCHThreadPoolManager.getsInstance().execute(setMapMarkerRunnable)
}
fun removeMapMaker(
uuid: String,
) {
//开启线程移除起终点marker设置
val removeMapMarkerRunnable = Runnable {
d("RemoveMapMaker=" + Thread.currentThread().name, uuid)
val overlayManager = CallerMapUIServiceManager.getOverlayManager()
overlayManager?.removeAllPointsInOwner(TYPE_MARKER_M2_LINE)
}
OCHThreadPoolManager.getsInstance().execute(removeMapMarkerRunnable)
}
fun showNoTaskView(b: Boolean) {
if (!b) {
b4OverMapView?.clearSiteMarkers()
clearCustomPolyline()
}
}
fun clearCustomPolyline() {
b4OverMapView?.clearCustomPolyline()
}
// 展示高精地图
// 展示高精地图+展示预测和决策
// 展示高精地图+mogoMind
// 展示高德地图
// 展示高德地图+展示mogomind
val hdMapMarginEnd = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(), -170f)
// 展示高精地图
fun showHDMap() {
b4HomeView.visibility = View.VISIBLE
val layoutParams = b4HomeView.layoutParams as ConstraintLayout.LayoutParams
layoutParams.marginStart = 0
b4HomeView.layoutParams = layoutParams
b4_aciv_top_shader.visibility = View.GONE
// cl_aip_contain.visibility = View.GONE
// cl_prediction_contain.visibility = View.GONE
b4MindView.visibility = View.GONE
b4OverMapView.visibility = View.GONE
}
// 展示高德地图
fun showAmap() {
b4HomeView.visibility = View.GONE
b4_aciv_top_shader.visibility = View.GONE
// cl_aip_contain.visibility = View.GONE
// cl_prediction_contain.visibility = View.GONE
b4MindView.visibility = View.GONE
b4OverMapView.visibility = View.VISIBLE
val layoutParams = b4OverMapView.layoutParams as ConstraintLayout.LayoutParams
layoutParams.marginStart = 0
b4OverMapView.layoutParams = layoutParams
}
// 展示高精地图+mogoMind
fun showHDMap_mind() {
b4HomeView.visibility = View.VISIBLE
val layoutParams = b4HomeView.layoutParams as ConstraintLayout.LayoutParams
layoutParams.marginStart = hdMapMarginEnd
b4HomeView.layoutParams = layoutParams
b4_aciv_top_shader.visibility = View.VISIBLE
// cl_aip_contain.visibility = View.GONE
// cl_prediction_contain.visibility = View.GONE
b4MindView.visibility = View.VISIBLE
b4OverMapView.visibility = View.GONE
}
// 展示高精地图+展示预测和决策
fun showHDMap_aip_prediction() {
b4HomeView.visibility = View.VISIBLE
val layoutParams = b4HomeView.layoutParams as ConstraintLayout.LayoutParams
layoutParams.marginStart = hdMapMarginEnd
b4HomeView.layoutParams = layoutParams
b4_aciv_top_shader.visibility = View.VISIBLE
// cl_aip_contain.visibility = View.VISIBLE
// cl_prediction_contain.visibility = View.VISIBLE
b4MindView.visibility = View.GONE
b4OverMapView.visibility = View.GONE
}
fun showAmap_mind() {
b4HomeView.visibility = View.GONE
b4_aciv_top_shader.visibility = View.VISIBLE
// cl_aip_contain.visibility = View.GONE
// cl_prediction_contain.visibility = View.GONE
b4MindView.visibility = View.VISIBLE
b4OverMapView.visibility = View.VISIBLE
val layoutParams = b4OverMapView.layoutParams as ConstraintLayout.LayoutParams
layoutParams.marginStart = hdMapMarginEnd
b4OverMapView.layoutParams = layoutParams
}
}

View File

@@ -0,0 +1,64 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.mind
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.bean.B4AIMessage
import java.util.concurrent.CopyOnWriteArrayList
object B4AIMessageManager {
// 使用 CopyOnWriteArrayList 来存储消息回调列表,保证线程安全
private val messageListeners: MutableList<AIMessageListener> = CopyOnWriteArrayList()
/**
* 注册一个消息监听器。
*
* @param listener 要注册的 AiMessageListener 实例。
*/
fun registerListener(listener: AIMessageListener) {
messageListeners.add(listener)
}
/**
* 取消注册一个消息监听器。
*
* @param listener 要取消注册的 AiMessageListener 实例。
*/
fun unregisterListener(listener: AIMessageListener) {
messageListeners.remove(listener)
}
/**
* 发布一条消息。
*
* 这条消息会被发送给所有已注册的监听器。
*
* @param msg 要发布的消息。
*/
fun post(msg: B4AIMessage) {
// 遍历所有已注册的监听器,并调用它们的 onReceive 方法
messageListeners.forEach { callback ->
callback.onReceive(msg)
}
}
fun clearData() {
messageListeners.forEach { callback ->
callback.clear()
}
}
/**
* 消息监听器接口。
*/
interface AIMessageListener {
/**
* 当接收到消息时,会调用此方法。
*
* @param msg 接收到的消息。
*/
fun onReceive(msg: B4AIMessage)
fun clear()
}
}

View File

@@ -0,0 +1,146 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.mind
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.findViewTreeLifecycleOwner
import androidx.lifecycle.findViewTreeViewModelStoreOwner
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.mogo.och.shuttle.weaknet.passenger.R
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.adapter.B4AIMessageAdapter
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.adapter.B4OnItemClickListener
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.adapter.B4PaddingItemDecoration
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.bean.B4AIMessage
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.data.B4AutomaticExplorationViewModel
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.data.B4NDEViewModel
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.data.B4RoadCrossRoamViewModel
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.data.B4RoadV2NEventViewModel
import kotlinx.android.synthetic.main.b4_mind_view.view.b4_rv_mind_list
import kotlinx.coroutines.launch
class B4MindView : ConstraintLayout, B4MindViewModel.AiViewCallback {
private val TAG = "B4MindView"
constructor(context: Context) : super(context)
constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet)
constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr)
constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attributeSet, defStyleAttr, defStyleRes)
private var roadV2NEventModel: B4RoadV2NEventViewModel? = null
private var roadCrossRoamModel: B4RoadCrossRoamViewModel? = null
private var automaticExplorationModel: B4AutomaticExplorationViewModel? = null
private var ndeViewModel: B4NDEViewModel? = null
private var viewModel: B4MindViewModel? = null
private var isUserScrollingTime = 0L
private val SCROLL_THRESHOLD = 2000L
private val messageAdapter: B4AIMessageAdapter by lazy { B4AIMessageAdapter() }
private val messageLayoutManager: LinearLayoutManager by lazy {
LinearLayoutManager(context).apply {
stackFromEnd = true
}
}
private fun initView() {
LayoutInflater.from(context).inflate(R.layout.b4_mind_view, this, true)
b4_rv_mind_list.layoutManager = messageLayoutManager
b4_rv_mind_list.adapter = messageAdapter
b4_rv_mind_list.addItemDecoration(B4PaddingItemDecoration(200, 300))
messageAdapter.onItemClickListener = B4OnItemClickListener { item, position ->
if (item is B4AIMessage.B4Event) {
}
}
b4_rv_mind_list.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState != RecyclerView.SCROLL_STATE_IDLE) {
isUserScrollingTime = System.currentTimeMillis()
}
}
})
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
viewModel = findViewTreeViewModelStoreOwner()?.let {
ViewModelProvider(it).get(B4MindViewModel::class.java)
}
viewModel?.setViewCallback(this)
roadV2NEventModel = findViewTreeViewModelStoreOwner()?.let {
ViewModelProvider(it)[B4RoadV2NEventViewModel::class.java]
}
roadV2NEventModel?.init()
roadCrossRoamModel = findViewTreeViewModelStoreOwner()?.let {
ViewModelProvider(it)[B4RoadCrossRoamViewModel::class.java]
}
roadCrossRoamModel?.init(context)
// automaticExplorationModel = findViewTreeViewModelStoreOwner()?.let{
// ViewModelProvider(it)[AutomaticExplorationViewModel::class.java]
// }
// automaticExplorationModel?.init()
ndeViewModel = findViewTreeViewModelStoreOwner()?.let {
ViewModelProvider(it)[B4NDEViewModel::class.java]
}
ndeViewModel?.init()
findViewTreeLifecycleOwner()?.lifecycleScope?.launch {
viewModel?.messagesFlow?.collect {
Log.d(TAG, "${tName()} onMessages update: ${it}")
if (it.isNotEmpty()) {
b4_rv_mind_list.visibility = View.VISIBLE
} else {
b4_rv_mind_list.visibility = View.VISIBLE
}
messageAdapter.submitList(it) {
Log.d(TAG, "${tName()} adapter submit: ")
scrollToBottom()
}
}
}
}
// 滚动到RecyclerView底部
private fun scrollToBottom() {
val delay = System.currentTimeMillis() - isUserScrollingTime
if (delay < SCROLL_THRESHOLD) {
return
}
val layoutManager = b4_rv_mind_list.layoutManager as LinearLayoutManager
layoutManager.scrollToPositionWithOffset(messageAdapter.itemCount - 1, 0)
}
fun tName(): String {
return "${Thread.currentThread().name}"
}
override fun onVisibilityAggregated(isVisible: Boolean) {
super.onVisibilityAggregated(isVisible)
}
init {
try {
initView()
} catch (e: Exception) {
e.printStackTrace()
}
}
}

View File

@@ -0,0 +1,170 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.mind
import android.util.Log
import androidx.lifecycle.ViewModel
import com.mogo.eagle.core.data.ai.V2XRepository
import com.mogo.eagle.core.data.map.MogoLocation
import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLocationGCJ02Listener
import com.mogo.och.bridge.autopilot.location.OchLocationManager
import com.mogo.och.common.module.biz.birdge.BridgeListener
import com.mogo.och.common.module.biz.birdge.BridgeManager
import com.mogo.och.common.module.biz.media.VoiceNotice
import com.mogo.och.shuttle.weaknet.passenger.callback.ICommonCallback
import com.mogo.och.shuttle.weaknet.passenger.model.CommonModel
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.bean.B4AIMessage
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
class B4MindViewModel : ViewModel(), B4AIMessageManager.AIMessageListener,
BridgeListener {
private val msgList = mutableListOf<B4AIMessage>()
private var lastTimestamp = System.currentTimeMillis()
// 记录最后一次事件发生的时间,使用 private set 限制外部修改
// private val TIMESTAMP_THRESHOLD = 1000 * 60 * 5 // 5分钟
private val TIMESTAMP_THRESHOLD = 1000 * 30
private var llmResultJob: Job? = null
private var isChecking = false
private val _messagesFlow = MutableStateFlow<List<B4AIMessage>>(emptyList())
val messagesFlow: SharedFlow<List<B4AIMessage>> get() = _messagesFlow
private val commontCallback = object : ICommonCallback {
override fun showNoTaskView(isTrue: Boolean) {
if (isTrue) {
clearMsg()
}
}
}
private val locationCallback = object : IMoGoChassisLocationGCJ02Listener {
override fun onChassisLocationGCJ02(mogoLocation: MogoLocation?) {
mogoLocation?.let {
V2XRepository.provideLocation(it, 0)
}
}
}
init {
}
fun setViewCallback(aiView: AiViewCallback) {
CommonModel.setRouteLineInfoCallback(TAG, commontCallback)
OchLocationManager.addGCJ02Listener(TAG, 1, locationCallback)
B4AIMessageManager.registerListener(this)
BridgeManager.addBridgeListener(TAG, this)
}
override fun onCleared() {
B4AIMessageManager.unregisterListener(this)
llmResultJob?.cancel()
CommonModel.setRouteLineInfoCallback(TAG, null)
OchLocationManager.removeGCJ02Listener(TAG)
super.onCleared()
}
override fun onReceive(msg: B4AIMessage) {
Log.d(TAG, "onReceive: $msg")
if (isChecking) {
if (msg is B4AIMessage.B4Event) {
msg.showScanFlag = true
}
}
// 获更新消息
updateMsg(msg)
}
override fun clear() {
clearMsg()
}
private fun handleMsg(newMessage: B4AIMessage) {
val existingIndex = findMessageIndex(newMessage.id)
if (existingIndex != -1) {
handleExistingMessage(existingIndex, newMessage)
} else {
handleNewMessage(newMessage)
}
}
private fun findMessageIndex(messageId: String): Int {
return msgList.indexOfFirst { it.id == messageId }
}
private fun handleExistingMessage(index: Int, newMessage: B4AIMessage) {
val oldMessage = msgList[index]
newMessage.showTimestamp = oldMessage.showTimestamp
msgList[index] = newMessage
speakMessageIfNeeded(newMessage, isLastMessage = msgList.last() == newMessage)
}
private fun handleNewMessage(newMessage: B4AIMessage) {
updateTimestampIfNeeded(newMessage)
msgList.add(newMessage)
speakMessageIfNeeded(newMessage, isLastMessage = true)
}
private fun updateTimestampIfNeeded(newMessage: B4AIMessage) {
val time = newMessage.timestamp - lastTimestamp
if (time >= TIMESTAMP_THRESHOLD) {
newMessage.showTimestamp = true
lastTimestamp = newMessage.timestamp
}
}
private fun speakMessageIfNeeded(newMessage: B4AIMessage, isLastMessage: Boolean) {
if (isLastMessage && newMessage.tts.isNotEmpty()) {
VoiceNotice.showNotice(newMessage.tts)
}
}
companion object {
private const val TAG = "B4MindViewModel"
}
private fun updateMsg(msg: B4AIMessage) {
synchronized(msgList) {
handleMsg(msg)
_messagesFlow.value = msgList.toList()
}
}
private fun deleteMsg(msgId: String) {
synchronized(msgList) {
val iterator = msgList.iterator()
while (iterator.hasNext()) {
if (iterator.next().id == msgId) {
iterator.remove()
}
}
_messagesFlow.value = msgList.toList()
}
}
private fun clearMsg() {
synchronized(msgList) {
msgList.clear()
_messagesFlow.value = msgList.toList()
}
}
interface AiViewCallback {
}
}

View File

@@ -0,0 +1,83 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.mind.adapter
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.LinearInterpolator
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.mogo.eagle.core.data.notice.AutoExplorationEntity
import com.mogo.och.shuttle.weaknet.passenger.R
/**
* 自动探查适配器
* 鹰眼650需求
*/
class AutomaticExplorationB4Adapter(val context: Context) : RecyclerView.Adapter<AutomaticExplorationB4Adapter.ExplorationHolder>() {
private var data: List<AutoExplorationEntity>? = null
private var completeListener: CompleteListener? = null
fun setData(data: List<AutoExplorationEntity>) {
this.data = data
notifyDataSetChanged()
}
fun setListener(listener: CompleteListener) {
completeListener = listener
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ExplorationHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_auto_exploration_b4, parent, false)
return ExplorationHolder(view)
}
override fun getItemCount() = data?.size ?: 0
override fun onBindViewHolder(holder: ExplorationHolder, position: Int) {
data?.let {
val entity = it[position]
holder.tvExplorationContent.text = entity.explorationContent
holder.ivExplorationLoading.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_exploration_loading_p
))
val rotationAnim = ObjectAnimator.ofFloat(holder.ivExplorationLoading, "rotation", 0f, 360f)
rotationAnim.repeatCount = entity.explorationDuration.toInt() / 1000
rotationAnim.repeatMode = ValueAnimator.RESTART
rotationAnim.duration = 1000
rotationAnim.interpolator = LinearInterpolator()
rotationAnim.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
super.onAnimationEnd(animation)
completeListener?.onComplete(entity)
holder.ivExplorationLoading.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_exploration_done_p
))
}
})
rotationAnim.start()
}
}
class ExplorationHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var ivExplorationLoading: ImageView = itemView.findViewById(R.id.b4IvExplorationLoading)
var tvExplorationContent: TextView = itemView.findViewById(R.id.b4TvExplorationContent)
}
interface CompleteListener {
fun onComplete(entity: AutoExplorationEntity)
}
}

View File

@@ -0,0 +1,51 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.mind.adapter
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
import com.mogo.och.shuttle.weaknet.passenger.R
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.bean.B4AIMessage
class B4AIMessageAdapter : ListAdapter<B4AIMessage, B4MessageViewHolder>(B4MessageDiffCallback()) {
var onItemClickListener: B4OnItemClickListener? = null
override fun onBindViewHolder(holder: B4MessageViewHolder, position: Int) {
getItem(position)?.let {
holder.bind(it, onItemClickListener)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): B4MessageViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
B4AIMessage.TYPE_PNC_ACTION -> B4PNCActionViewHolder(inflater.inflate(R.layout.b4_item_ai_pnc_action, parent, false))
B4AIMessage.TYPE_ROAD_V2N -> B4RoadV2NEventViewHolder(inflater.inflate(R.layout.b4_item_ai_road_v2n_event, parent, false))
B4AIMessage.TYPE_ROAD_CROSS -> B4RoadCrossRoamViewHolder(inflater.inflate(R.layout.b4_item_ai_road_cross_roam, parent, false))// 全息路口
B4AIMessage.TYPE_AUTOMATIC_EXPLORATION -> B4AutomaticExplorationViewHolder(inflater.inflate(R.layout.b4_item_ai_automatic_exploration, parent, false))// 探查
B4AIMessage.TYPE_NDE -> B4NDEViewHolder(inflater.inflate(R.layout.b4_item_ai_nde_event, parent, false))// 车龙
else -> throw IllegalArgumentException("Invalid view type")
}
}
override fun getItemViewType(position: Int): Int {
return when (getItem(position)) {
is B4AIMessage.B4Event -> B4AIMessage.TYPE_EVENT
is B4AIMessage.B4Scan -> B4AIMessage.TYPE_SCAN
is B4AIMessage.B4Light -> B4AIMessage.TYPE_LIGHT
is B4AIMessage.B4Speed -> B4AIMessage.TYPE_SPEED
is B4AIMessage.B4Warning -> B4AIMessage.TYPE_WARNING
is B4AIMessage.B4PNCAction -> B4AIMessage.TYPE_PNC_ACTION
is B4AIMessage.B4RoadV2NEvent -> B4AIMessage.TYPE_ROAD_V2N
is B4AIMessage.B4RoadCrossRoam -> B4AIMessage.TYPE_ROAD_CROSS
is B4AIMessage.B4AutomaticExploration -> B4AIMessage.TYPE_AUTOMATIC_EXPLORATION
is B4AIMessage.B4NDEData -> B4AIMessage.TYPE_NDE
else -> B4AIMessage.TYPE_EVENT
}
}
override fun onViewRecycled(holder: B4MessageViewHolder) {
super.onViewRecycled(holder)
holder.viewRecycled(holder)
}
}

View File

@@ -0,0 +1,221 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.mind.adapter
import android.content.Context
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.mogo.eagle.core.data.notice.AutoExplorationEntity
import com.mogo.eagle.core.data.v2x.RoadV2NEventType
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationWGS84ListenerManager
import com.mogo.eagle.core.function.hmi.ui.v2n.RoadV2NEventLivePlayView
import com.mogo.eagle.core.utilcode.mogo.glide.GlideImageLoader
import com.mogo.eagle.core.utilcode.mogo.imageloader.MogoImageView
import com.mogo.eagle.core.utilcode.util.StringUtils
import com.mogo.och.shuttle.weaknet.passenger.R
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.bean.B4AIMessage
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
abstract class B4MessageViewHolder(view: View) : RecyclerView.ViewHolder(view) {
abstract fun bind(item: B4AIMessage, onItemClickListener: B4OnItemClickListener? = null)
open fun viewRecycled(holder: B4MessageViewHolder) {}
private val sampleDateFormat = SimpleDateFormat("HH:mm", Locale.CHINA)
protected val TAG = javaClass.simpleName
fun handleTimestamp(item: B4AIMessage, tvTimestamp: TextView) {
if (item.showTimestamp) {
tvTimestamp.visibility = View.VISIBLE
tvTimestamp.text = sampleDateFormat.format(Date(item.timestamp))
} else {
tvTimestamp.visibility = View.GONE
}
}
fun View.setVisibilityBasedOn(condition: Boolean) {
visibility = if (condition) View.VISIBLE else View.GONE
}
fun TextView.setTextAndVisibility(text: String) {
if (text.isEmpty()) {
visibility = View.GONE
this.text = ""
} else {
visibility = View.VISIBLE
this.text = text
}
}
fun ImageView.showOrHideWithUrl(url: String) {
if (url.isEmpty()) {
visibility = View.GONE
} else {
visibility = View.VISIBLE
Glide.with(this)
.load(url)
.placeholder(R.drawable.b4_icon_pic_holder)
.error(R.drawable.b4_icon_pic_error)
// .error(R.drawable.icon_marker_window_place_holder)
// .placeholder(R.drawable.icon_marker_window_place_holder)
.into(this)
}
}
}
class B4PNCActionViewHolder(binding: View) : B4MessageViewHolder(binding) {
private var tvPncActionDesc: TextView = binding.findViewById(R.id.b4TvPNCHintContent)
override fun bind(item: B4AIMessage, onItemClickListener: B4OnItemClickListener?) {
if (item is B4AIMessage.B4PNCAction) {
tvPncActionDesc.text = item.actionDesc
}
}
}
class B4RoadV2NEventViewHolder(binding: View) : B4MessageViewHolder(binding) {
private var tvV2XHintContent: TextView = binding.findViewById(R.id.b4TvV2XHintContent)
private var containerImageAndLiveVideo: FrameLayout = binding.findViewById(R.id.b4ContainerImageAndLiveVideo)
private var livePlayView: RoadV2NEventLivePlayView = binding.findViewById(R.id.b4LivePlayView)
private var contentImageView: MogoImageView = binding.findViewById(R.id.b4ContentImageView)
override fun bind(item: B4AIMessage, onItemClickListener: B4OnItemClickListener?) {
if (item is B4AIMessage.B4RoadV2NEvent) {
tvV2XHintContent.text = item.title
when (item.eventType) {
RoadV2NEventType.TEXT -> {
containerImageAndLiveVideo.visibility = View.GONE
contentImageView.visibility = View.GONE
livePlayView.visibility = View.GONE
}
RoadV2NEventType.IMAGE -> {
containerImageAndLiveVideo.visibility = View.VISIBLE
contentImageView.visibility = View.VISIBLE
livePlayView.visibility = View.GONE
GlideImageLoader.getInstance()
.displayImage(item.contentImageUrl, contentImageView)
}
RoadV2NEventType.LIVE_VIDEO -> {
containerImageAndLiveVideo.visibility = View.VISIBLE
contentImageView.visibility = View.GONE
livePlayView.visibility = View.VISIBLE
val cityCode =
CallerChassisLocationWGS84ListenerManager.getChassisLocationWGS84().cityCode
livePlayView.startRoadCameraLive(
item.id,
item.cameraIp, item.lon, item.lat, cityCode
)
}
}
}
}
}
class B4RoadCrossRoamViewHolder(binding: View) : B4MessageViewHolder(binding) {
private var tvRoadRoamTitle: TextView = binding.findViewById(R.id.b4TvRoadRoamTitle)
private var lvRoadCrossRoamTip: RecyclerView = binding.findViewById(R.id.b4LvRoadCrossRoamTip)
override fun bind(item: B4AIMessage, onItemClickListener: B4OnItemClickListener?) {
if (item is B4AIMessage.B4RoadCrossRoam) {
lvRoadCrossRoamTip.layoutManager = B4NoScrollLayoutManager(itemView.context)
lvRoadCrossRoamTip.adapter = RoadCrossRoamListB4Adapter(itemView.context)
tvRoadRoamTitle.setTextColor(itemView.context.getColor(R.color.color_131415))
}
}
}
class B4AutomaticExplorationViewHolder(binding: View) : B4MessageViewHolder(binding) {
private var rvExplorationList: RecyclerView = binding.findViewById(R.id.b4RvExplorationList)
private lateinit var automaticExplorationAdapter: AutomaticExplorationB4Adapter
override fun bind(item: B4AIMessage, onItemClickListener: B4OnItemClickListener?) {
val linearLayoutManager = LinearLayoutManager(itemView.context)
linearLayoutManager.orientation = LinearLayoutManager.VERTICAL
automaticExplorationAdapter = AutomaticExplorationB4Adapter(itemView.context)
rvExplorationList.adapter = automaticExplorationAdapter
rvExplorationList.layoutManager = linearLayoutManager
initData()
}
private fun initData() {
val dataList = ArrayList<AutoExplorationEntity>(7)
// dataList.add(AutoExplorationEntity("当前道路事件分析",2000L,false))
dataList.add(AutoExplorationEntity(StringUtils.getString(R.string.module_och_crossing_event_analyse), 2000L, false))
// dataList.add(AutoExplorationEntity("前方车辆",2000L,false))
dataList.add(AutoExplorationEntity(StringUtils.getString(R.string.module_och_vehicle_ahead), 2000L, false))
// dataList.add(AutoExplorationEntity("两侧车辆",2600L,false))
dataList.add(AutoExplorationEntity(StringUtils.getString(R.string.module_och_vehicle_both_sides), 2600L, false))
// dataList.add(AutoExplorationEntity("后方车辆",3000L,false))
dataList.add(AutoExplorationEntity(StringUtils.getString(R.string.module_och_vehicle_behind), 3000L, false))
// dataList.add(AutoExplorationEntity("前方路口车辆流速分析",4000L,false))
dataList.add(AutoExplorationEntity(StringUtils.getString(R.string.module_och_analysis_vehicle_flow_ahead), 4000L, false))
// dataList.add(AutoExplorationEntity("前方路口行人/非机动车分析",4300L,false))
dataList.add(AutoExplorationEntity(StringUtils.getString(R.string.module_och_pedestrians_ahead), 4300L, false))
// dataList.add(AutoExplorationEntity("路侧视频分析",5000L,false))
dataList.add(AutoExplorationEntity(StringUtils.getString(R.string.module_och_sidewalk_video_analysis), 5000L, false))
automaticExplorationAdapter.setListener(object : AutomaticExplorationB4Adapter.CompleteListener {
override fun onComplete(entity: AutoExplorationEntity) {
dataList.forEach {
if (it.explorationContent == entity.explorationContent) {
it.explorationComplete = true
}
}
}
})
automaticExplorationAdapter.setData(dataList)
}
}
class B4NDEViewHolder(binding: View) : B4MessageViewHolder(binding) {
private var tvNdeContent: TextView = binding.findViewById(R.id.b4TvNdeHintContent)
private var rvNdeList: RecyclerView = binding.findViewById(R.id.b4RvNdeList)
override fun bind(item: B4AIMessage, onItemClickListener: B4OnItemClickListener?) {
if (item is B4AIMessage.B4NDEData) {
tvNdeContent.text = item.desc
val linearLayoutManager = LinearLayoutManager(itemView.context)
linearLayoutManager.orientation = LinearLayoutManager.HORIZONTAL
val ndeRoadAdapter = B4AINDERoadAdapter(itemView.context)
rvNdeList.adapter = ndeRoadAdapter
rvNdeList.layoutManager = linearLayoutManager
ndeRoadAdapter.setData(item.roadList)
}
}
}
private class B4NoScrollLayoutManager(context: Context?) : LinearLayoutManager(context) {
override fun canScrollVertically(): Boolean {
return false
}
override fun canScrollHorizontally(): Boolean {
return false
}
}
fun interface B4OnItemClickListener {
fun onItemClick(item: B4AIMessage, position: Int)
}

View File

@@ -0,0 +1,237 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.mind.adapter
import android.content.Context
import android.util.TypedValue
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.recyclerview.widget.RecyclerView
import com.mogo.och.common.module.biz.birdge.data.RoadMsg
import com.mogo.och.shuttle.weaknet.passenger.R
class B4AINDERoadAdapter(private val context: Context) : RecyclerView.Adapter<B4AINDERoadAdapter.AIRoadHolder>() {
private var roadList: List<RoadMsg>? = null
fun setData(list: List<RoadMsg>) {
roadList = list
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AIRoadHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.b4_item_ai_nde_road, parent, false)
return AIRoadHolder(view)
}
override fun onBindViewHolder(holder: AIRoadHolder, position: Int) {
roadList?.let {
val roadMsg = it[position]
if (it.size < 3) {
//设置item宽度为最大宽度180dp
val params = ConstraintLayout.LayoutParams(
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 90f,
context.resources.displayMetrics).toInt(),
ConstraintLayout.LayoutParams.WRAP_CONTENT)
holder.clRoadLayout.layoutParams = params
} else if (it.size == 3) {
//设置item宽度为最大宽度180dp
val params = ConstraintLayout.LayoutParams(
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60f,
context.resources.displayMetrics).toInt(),
ConstraintLayout.LayoutParams.WRAP_CONTENT)
holder.clRoadLayout.layoutParams = params
} else if (it.size == 4) {
//设置item宽度为最大宽度180dp
val params = ConstraintLayout.LayoutParams(
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50f,
context.resources.displayMetrics).toInt(),
ConstraintLayout.LayoutParams.WRAP_CONTENT)
holder.clRoadLayout.layoutParams = params
} else {
val params = ConstraintLayout.LayoutParams(
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 45f,
context.resources.displayMetrics).toInt(),
ConstraintLayout.LayoutParams.WRAP_CONTENT)
holder.clRoadLayout.layoutParams = params
}
when (roadMsg.arrowType) {
//直行
201 -> {
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_forward
))
}
//直行或左转
202 -> {
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_forward_or_turn_left
))
}
//直行或右转
203 -> {
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_forward_or_turn_right
))
}
//直行或掉头
204 -> {
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_forward_or_reverse
))
}
//左转
205 -> {
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_turn_left
))
}
//左转或掉头
206 -> {
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_turn_left_or_reverse
))
}
//左弯或向左合流
207 -> {
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_turn_or_merge_left
))
}
//右转
208 -> {
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_turn_right
))
}
//右转或向右合流
209 -> {
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_turn_or_merge_right
))
}
//左右转弯
210 -> {
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_turn_left_or_right
))
}
//掉头
211 -> {
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_reverse
))
}
//禁止左转
212 -> {
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_prohibit_turn_left
))
}
//禁止右转
213 -> {
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_prohibit_turn_right
))
}
//禁止掉头
214 -> {
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_prohibit_reverse
))
}
//直行或左转或右转
215 -> {
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_forward_turn_left_right
))
}
//直行或掉头或左转
216 -> {
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_forward_turn_left_reverse
))
}
//右转或掉头
217 -> {
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_turn_right_or_reverse
))
}
//禁止右转或向右合流
218 -> {
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_prohibit_turn_or_merge_right
))
}
}
//是否是推荐车道
if (roadMsg.isRecommend) {
holder.tvRoadStatus.text = context.getString(R.string.nde_road_recommend)
holder.tvRoadStatus.setTextColor(context.getColor(R.color.msg_nde_road_recommend))
holder.clRoadLayout.background = ContextCompat.getDrawable(
context,
R.drawable.bg_nde_road_recommend
)
}
//是否有车龙,代表拥堵、行驶缓慢
if (roadMsg.isCheLong) {
holder.tvRoadStatus.text = context.getString(R.string.nde_road_slow)
holder.tvRoadStatus.setTextColor(context.getColor(R.color.msg_nde_road_slow))
}
if (position == it.lastIndex) {
holder.viewDivider.visibility = View.INVISIBLE
}
}
}
override fun getItemCount() = roadList?.size ?: 0
class AIRoadHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var clRoadLayout: ConstraintLayout = itemView.findViewById(R.id.clRoadLayout)
var ivRoadType: ImageView = itemView.findViewById(R.id.b4IvRoadType)
var tvRoadStatus: TextView = itemView.findViewById(R.id.b4TvRoadStatus)
var viewDivider: View = itemView.findViewById(R.id.b4ViewDivider)
}
}

View File

@@ -0,0 +1,15 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.mind.adapter
import androidx.recyclerview.widget.DiffUtil
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.bean.B4AIMessage
class B4MessageDiffCallback : DiffUtil.ItemCallback<B4AIMessage>() {
override fun areContentsTheSame(oldItem: B4AIMessage, newItem: B4AIMessage): Boolean {
return oldItem == newItem
}
override fun areItemsTheSame(oldItem: B4AIMessage, newItem: B4AIMessage): Boolean {
return oldItem.id == newItem.id
}
}

View File

@@ -0,0 +1,94 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.mind.adapter
import android.graphics.Canvas
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.view.View
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import com.mogo.commons.AbsMogoApplication
import com.mogo.och.common.module.utils.ResourcesUtils
import com.mogo.och.shuttle.weaknet.passenger.R
import me.jessyan.autosize.utils.AutoSizeUtils
class B4PaddingItemDecoration(private val topPadding: Int, private val bottomPadding: Int) : RecyclerView.ItemDecoration() {
private var divider: Drawable
private var padding = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(), 13f)
init {
val shapeDrawable = GradientDrawable()
shapeDrawable.setColor(ResourcesUtils.getColor(R.color.b4_BBC9D4))
shapeDrawable.shape = GradientDrawable.RECTANGLE
val width = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(), 343f)
val height = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(), 1f)
shapeDrawable.setSize(width, height)
divider = shapeDrawable
}
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
super.getItemOffsets(outRect, view, parent, state)
// 只有第一个 item 的顶部添加空白
if (parent.getChildAdapterPosition(view) == 0) {
outRect.top = topPadding
} else {
outRect.top = 0
}
// 最后一个 item 的底部添加空白
// if (parent.getChildAdapterPosition(view) == state.itemCount - 1) {
// outRect.bottom = bottomPadding
// } else{
// outRect.bottom = 0
// }
}
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDraw(c, parent, state)
val childCount = parent.childCount //获取可见item的数量
val spanCount: Int = getSpanCount(parent)
for (i in 0 until childCount) {
val child = parent.getChildAt(i)
val params = child
.layoutParams as RecyclerView.LayoutParams
val left = child.left - params.leftMargin + padding
val right = child.right - padding //- params.rightMargin - divider.intrinsicWidth
val top = child.bottom + params.bottomMargin
val bottom = top + divider.intrinsicHeight
divider.setBounds(left, top, right, bottom)
divider.draw(c)
if (i < spanCount) { //画第一行顶部的分割线
drawHorizontalForFirstRow(c, child)
}
}
}
private fun drawHorizontalForFirstRow(c: Canvas, child: View) {
val params = child
.layoutParams as RecyclerView.LayoutParams
val left = child.left - params.leftMargin - divider.intrinsicWidth
val top = child.top - params.topMargin - divider.intrinsicHeight
val right = child.right + params.rightMargin + divider.intrinsicWidth
val bottom = top + divider.intrinsicHeight
divider.setBounds(left, top, right, bottom)
divider.draw(c)
}
private fun getSpanCount(parent: RecyclerView): Int {
// 列数
var spanCount = -1
val layoutManager = parent.layoutManager
if (layoutManager is GridLayoutManager) {
spanCount = layoutManager.spanCount
} else if (layoutManager is StaggeredGridLayoutManager) {
spanCount = layoutManager
.spanCount
}
return spanCount
}
}

View File

@@ -0,0 +1,72 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.mind.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.mogo.eagle.core.utilcode.util.StringUtils
import com.mogo.och.shuttle.weaknet.passenger.R
import kotlin.random.Random
class RoadCrossRoamListB4Adapter(private val mContext: Context) : RecyclerView.Adapter<RoadCrossRoamListB4Adapter.ViewHolder>() {
private val items: MutableList<String> = mutableListOf()
init {
// items.add("前方路况拥堵分析")
items.add(StringUtils.getString(R.string.module_och_analysis_traffic_conditions_ahead))
// items.add("路口危险车辆分析")
items.add(StringUtils.getString(R.string.module_och_analysis_dangerous_vehicles_intersections))
// items.add("路口交通事故分析")
items.add(StringUtils.getString(R.string.module_och_analysis_roadside_traffic_accidents))
// items.add("路口行人碰撞分析")
items.add(StringUtils.getString(R.string.module_och_analysis_pedestrian_collisions_crossroads))
// items.add("路口非机动车分析")
items.add(StringUtils.getString(R.string.module_och_analysis_non_motorized_vehicles_intersections))
// items.add("路口灯态分析")
items.add(StringUtils.getString(R.string.module_och_analysis_intersection_signal_status))
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view: View =
LayoutInflater.from(mContext).inflate(R.layout.item_road_cross_ai_roam_tip_b4, parent, false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return 6
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = items[position]
holder.textView.setTextColor(mContext.getColor(R.color.color_191A1C))
holder.textView.text = item
// 随机决定是否显示ProgressBar
// if (Random.nextBoolean()) { // 50%的几率显示ProgressBar
holder.progressBar.visibility = View.VISIBLE
holder.checkIcon.visibility = View.INVISIBLE
val r0 = Random.nextInt(0, 3)
val r1 = Random.nextInt(1, 9)
// 模拟加载完成
holder.itemView.postDelayed({
holder.progressBar.visibility = View.INVISIBLE
holder.checkIcon.visibility = View.VISIBLE
}, r0 * 1000L + r1 * 100L)
// } else {
// holder.progressBar.visibility = View.GONE
// holder.checkIcon.visibility = View.VISIBLE
// }
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var textView: TextView = itemView.findViewById(R.id.b4TvRoadItemTip)
var progressBar: ProgressBar = itemView.findViewById(R.id.b4PbRoadItemTip)
var checkIcon: ImageView = itemView.findViewById(R.id.b4IvRoadItemTip)
}
}

View File

@@ -0,0 +1,179 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.mind.bean
import android.os.CountDownTimer
import android.util.Log
import com.mogo.eagle.core.data.v2x.RoadV2NEventType
import com.mogo.och.common.module.biz.birdge.data.RoadMsg
import kotlin.math.floor
sealed class B4AIMessage(
open val id: String,
open val title: String,
open val tts: String = "",
val timestamp: Long = System.currentTimeMillis(),
var showTimestamp: Boolean = false
) {
companion object {
const val TYPE_SCAN = 0
const val TYPE_EVENT = 1
const val TYPE_LIGHT = 3
const val TYPE_SPEED = 4
const val TYPE_WARNING = 5
const val TYPE_PNC_ACTION = 6
const val TYPE_ROAD_V2N = 7
const val TYPE_ROAD_CROSS = 8
const val TYPE_AUTOMATIC_EXPLORATION = 9
const val TYPE_NDE = 11
}
data class B4Scan(
override val id: String,
override val title: String,
val pictureUrl: String = "",
var showScanFlag: Boolean = false
) : B4AIMessage(id, title)
data class B4Event(
override val id: String,
override val title: String,
override val tts: String = "",
val position: String = "",
val distance: String = "",
val range: String = "",
val time: String = "",
val pictureUrl: String = "",
val videoUrl: String = "",
var showScanFlag: Boolean = false
) : B4AIMessage(id, title, tts)
data class B4QA(
override val id: String,
override val title: String,
override val tts: String = "",
val question: String,
val answer: String,
var state: B4QuestionState = B4QuestionState.UNDERSTAND,
val pictureUrl: String = "",
var pictureUrlList: List<String> = listOf(),
val videoUrl: String = "",
) : B4AIMessage(id, title, tts) {
enum class B4QuestionState(val code: Int) {
UNDERSTAND(1),
ANALYZE(2),
ANSWER(3),
FINISH(4),
ERROR(-1),
}
}
data class B4Light(
override val id: String,
override val title: String,
override val tts: String = "",
var seconds: Int,
val status: Int
) : B4AIMessage(id, title, tts) {
private var countDownTimer: CountDownTimer? = null
private var listener: OnCountdownUpdateListener? = null
fun startCountdown(millisInFuture: Long, countDownInternal: Long) {
countDownTimer?.cancel()
countDownTimer = object : CountDownTimer(millisInFuture, countDownInternal) {
override fun onTick(millisUntilFinished: Long) {
//倒计时开始
Log.d(
"StartOrSlowDownTip",
"millisUntilFinished = $millisUntilFinished, countDownInternal = $countDownInternal"
)
val cd = millisUntilFinished / 1000.0
// val split = String.format("%.2f", cd).split(".")
seconds = floor(cd).toInt()
listener?.onCountdownUpdate()
}
override fun onFinish() {
//倒计时完成
seconds = 0
listener?.onCountdownFinish()
}
}
countDownTimer?.start()
}
fun stopCountdown() {
countDownTimer?.cancel()
}
fun setOnCountdownUpdateListener(listener: OnCountdownUpdateListener) {
this.listener = listener
}
interface OnCountdownUpdateListener {
fun onCountdownUpdate()
fun onCountdownFinish()
}
}
data class B4Speed(
override val id: String,
override val title: String,
override val tts: String = "",
val speedMax: Int,
val speedMin: Int,
) : B4AIMessage(id, title, tts)
data class B4Warning(
override val id: String,
override val title: String,
override val tts: String = "",
) : B4AIMessage(id, title, tts)
data class B4PNCAction(
override val id: String,
override val title: String,
var actionDesc: String,
var timeStamp: Long = 0, //事件发生事件戳
) : B4AIMessage(id, title)
data class B4RoadV2NEvent(
override val id: String,
override val title: String,
override val tts: String = "", //TTS的文案
var eventType: RoadV2NEventType, //事件弹框类型
var timeStamp: Long = 0, //事件发生事件戳
var iconResId: Int, //事件icon res id
var isNeedTTS: Boolean = false, //事件文案是否需要同步tts
var contentImageUrl: String, // Image 类型时图片 url
var cameraIp: String, // 路侧camera ip,用于请求获取拉流地址
var lon: Double, //事件坐标-经度
var lat: Double, //事件坐标-纬度
) : B4AIMessage(id, title, tts)
data class B4RoadCrossRoam(
override val id: String,
override val title: String
) : B4AIMessage(id, title)
data class B4AutomaticExploration(
override val id: String,
override val title: String
) : B4AIMessage(id, title)
data class B4EvaluateData(
override val id: String,
override val title: String,
var isFirst: Boolean = true
) : B4AIMessage(id, title)
data class B4NDEData(
override val id: String,
override val title: String,
var desc: String,
var roadList: List<RoadMsg>
) : B4AIMessage(id, title)
}

View File

@@ -0,0 +1,3 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.mind.bean
data class B4ListenUIState(val show: Boolean, val text: String, val showTips: Boolean = false)

View File

@@ -0,0 +1,117 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.mind.data
import android.os.CountDownTimer
import androidx.lifecycle.ViewModel
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
import com.mogo.eagle.core.data.msgbox.MsgBoxType
import com.mogo.eagle.core.data.msgbox.MsgCategory
import com.mogo.eagle.core.function.api.datacenter.msgbox.IMsgBoxListener
import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxListenerManager
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.util.ThreadUtils
import com.mogo.och.shuttle.weaknet.passenger.callback.ICommonCallback
import com.mogo.och.shuttle.weaknet.passenger.model.CommonModel
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.B4AIMessageManager
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.bean.B4AIMessage
/**
* 自动探查
*/
class B4AutomaticExplorationViewModel : ViewModel(), IMsgBoxListener, ICommonCallback {
companion object {
private const val TAG = "B4AutomaticExplorationViewModel"
private const val EXPLORATION_SHOW_TIME = 300000L //距离用户在触发上一次事件播报的时间5分钟后自动触发常规道路情况检测
}
private var showViewTimer: CountDownTimer? = null //展示自动探查倒计时
private var isCountingDown: Boolean = false //是否处于倒计时中
private var hasOrder: Boolean = false // 车当前是否有订单
fun init() {
CommonModel.setRouteLineInfoCallback(TAG, this)
CallerMsgBoxListenerManager.addListener(TAG, this)
}
override fun onCleared() {
super.onCleared()
CommonModel.setRouteLineInfoCallback(TAG, null)
CallerMsgBoxListenerManager.removeListener(TAG)
}
override fun showNoTaskView(isTrue: Boolean) {
super.showNoTaskView(isTrue)
if (isTrue) {
cancelTimer()
currentOrderStatus(false)
} else {
startShowTimer()
currentOrderStatus(true)
}
}
override fun onDataChanged(category: MsgCategory, msgBoxList: MsgBoxBean) {
if (category == MsgCategory.NOTICE) {
if (msgBoxList.type == MsgBoxType.V2X) {
//重置倒计时时长
cancelTimer()
if (hasOrder) {
startShowTimer()
}
}
}
}
/**
* 取消倒计时
*/
private fun cancelTimer() {
CallerLogger.d(TAG, "cancelTimer")
showViewTimer?.cancel()
showViewTimer = null
isCountingDown = false
}
/**
* 开始倒计时
*/
private fun startShowTimer() {
CallerLogger.d(TAG, "startShowTimer")
if (!isCountingDown) {
ThreadUtils.runOnUiThread {
if (showViewTimer == null) {
showViewTimer = object : CountDownTimer(EXPLORATION_SHOW_TIME, EXPLORATION_SHOW_TIME) {
override fun onTick(millisUntilFinished: Long) {
CallerLogger.d(TAG, "倒计时+:${millisUntilFinished}")
}
override fun onFinish() {
if (hasOrder) {
showAutoExploration()
}
isCountingDown = false
}
}
}
isCountingDown = true
showViewTimer?.start()
}
}
}
/**
* 设置当前订单状态
* @param orderStatus true有订单false没有订单
*/
private fun currentOrderStatus(orderStatus: Boolean) {
hasOrder = orderStatus
}
private fun showAutoExploration() {
val automaticExploration = B4AIMessage.B4AutomaticExploration(System.currentTimeMillis().toString(), "")
B4AIMessageManager.post(automaticExploration)
}
}

View File

@@ -0,0 +1,33 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.mind.data
import androidx.lifecycle.ViewModel
import com.mogo.och.common.module.biz.birdge.BridgeListener
import com.mogo.och.common.module.biz.birdge.BridgeManager
import com.mogo.och.common.module.biz.birdge.data.RoadMsg
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.B4AIMessageManager
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.bean.B4AIMessage
/**
* 车龙信息
*/
class B4NDEViewModel : ViewModel(), BridgeListener {
companion object {
private const val TAG = "B4NDEViewModel"
}
fun init() {
BridgeManager.addBridgeListener(TAG, this)
}
override fun onCleared() {
super.onCleared()
BridgeManager.removeBridgeListener(TAG)
}
override fun onNdeDataListener(title: String, desc: String, sortedList: List<RoadMsg>) {
val ndeEvent = B4AIMessage.B4NDEData(System.currentTimeMillis().toString(), title, desc, sortedList)
B4AIMessageManager.post(ndeEvent)
}
}

View File

@@ -0,0 +1,357 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.mind.data
import androidx.lifecycle.ViewModel
import com.mogo.eagle.core.data.autopilot.pnc.PncActionsHelper
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotPlanningActionsListener
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
import com.mogo.eagle.core.function.call.autopilot.CallerPlanningActionsListenerManager
import com.mogo.eagle.core.utilcode.util.StringUtils
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager
import com.mogo.och.common.module.manager.loop.BizLoopManager
import com.mogo.och.data.bean.BusStationBean
import com.mogo.och.shuttle.weaknet.passenger.R
import com.mogo.och.shuttle.weaknet.passenger.callback.ICommonCallback
import com.mogo.och.shuttle.weaknet.passenger.model.CommonModel
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.B4AIMessageManager
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.bean.B4AIMessage
import mogo.telematics.pad.MessagePad
class B4PNCActionsViewModel : ViewModel(), IMoGoAutopilotPlanningActionsListener, ICommonCallback {
companion object {
private const val TAG = "B4PNCActionsViewModel"
}
private var currentAction = ""
private var currentStation: BusStationBean? = null
fun init() {
CallerPlanningActionsListenerManager.addListener(TAG, this)
CommonModel.setRouteLineInfoCallback(TAG, this)
}
override fun onCleared() {
super.onCleared()
CallerPlanningActionsListenerManager.removeListener(TAG)
CommonModel.setRouteLineInfoCallback(TAG, null)
}
override fun updateStationsInfo(
stations: MutableList<BusStationBean>?,
currentStationIndex: Int,
isArrived: Boolean
) {
try {
currentStation = stations?.get(currentStationIndex)
} catch (e: Exception) {
OchChainLogManager.writeChainLogError("PNCActionsViewModel 设置错误", "${e.message}")
}
}
override fun showNoTaskView(isTrue: Boolean) {
super.showNoTaskView(isTrue)
if (isTrue) {
currentStation = null
}
}
override fun pncActions(planningActionMsg: MessagePad.PlanningActionMsg) {
try {
BizLoopManager.runInMainThread {
if (CallerAutoPilotStatusListenerManager.getState() == IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING) {
var actions: String? = null
planningActionMsg.actionMsg?.let {
try {
actions = PncActionsHelper.getAction(
it.drivingState.number,
it.drivingAction.number
)
} catch (e: Exception) {
e.printStackTrace()
}
}
planningActionMsg.v2NActionMsgList?.forEach { v2nAction ->
actions = PncActionsHelper.getAction(
v2nAction.drivingState.number,
v2nAction.drivingAction.number
)
}
// update view
actions?.let {
if (it.isNotEmpty() && it != currentAction) {
currentAction = it
val title = getActionTitle(it)
if (title.isNotEmpty()) {
val desc = getActionDesc(title)
val action = B4AIMessage.B4PNCAction(it + System.currentTimeMillis(), title, desc, System.currentTimeMillis())
B4AIMessageManager.post(action)
}
}
}
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun getActionTitle(pncAction: String): String {
return when (pncAction) {
// "正在进站"->{
StringUtils.getString(R.string.module_core_entering_the_station) -> {
// "车辆进站"
StringUtils.getString(R.string.module_core_entering_the_station_title)
}
// "等待进站"->{
StringUtils.getString(R.string.module_core_await_station) -> {
// "车辆等待进站"
StringUtils.getString(R.string.module_core_await_station_title)
}
// "正在出站"->{
StringUtils.getString(R.string.module_core_leaving_the_station) -> {
// "车辆出站"
StringUtils.getString(R.string.module_core_leaving_the_station_title)
}
// "等待出站"->{
StringUtils.getString(R.string.module_core_await_leaving_the_station) -> {
// "车辆等待出站"
StringUtils.getString(R.string.module_core_await_leaving_the_station_title)
}
// "正在向左变道"->{
StringUtils.getString(R.string.module_core_changing_lane_to_left) -> {
// "车辆向左变道"
StringUtils.getString(R.string.module_core_changing_lane_to_left_title)
}
// "正在向右变道"->{
StringUtils.getString(R.string.module_core_changing_lane_to_right) -> {
// "车辆向右变道"
StringUtils.getString(R.string.module_core_changing_lane_to_right_title)
}
// "正在完成变道"->{
StringUtils.getString(R.string.module_core_completing_lane_change) -> {
// "车辆完成变道"
StringUtils.getString(R.string.module_core_completing_lane_change_title)
}
// "正在绕过障碍物"->{
StringUtils.getString(R.string.module_core_bypassing_obstacle) -> {
// "车辆正在绕过前方障碍物"
StringUtils.getString(R.string.module_core_bypassing_obstacle_title)
}
// "正在向左绕行避让前方静止障碍物"->{
StringUtils.getString(R.string.module_core_turning_left_to_bypass_stationary_obstacle_ahead) -> {
// "车辆正在绕过前方障碍物"
StringUtils.getString(R.string.module_core_bypassing_obstacle_title)
}
// "正在向右绕行避让前方静止障碍物"->{
StringUtils.getString(R.string.module_core_turning_right_to_bypass_stationary_obstacle_ahead) -> {
// "车辆正在绕过前方障碍物"
StringUtils.getString(R.string.module_core_bypassing_obstacle_title)
}
// "正在避让障碍物"->{
StringUtils.getString(R.string.module_core_avoiding_obstacle) -> {
// "车辆正在避让前方障碍物"
StringUtils.getString(R.string.module_core_avoiding_obstacle_title)
}
// "正在向左变道避让前方静止障碍物"->{
StringUtils.getString(R.string.module_core_changing_lane_to_left_to_avoid_stationary_obstacle_ahead) -> {
// "车辆正在避让前方障碍物"
StringUtils.getString(R.string.module_core_avoiding_obstacle_title)
}
// "正在向右变道避让前方静止障碍物"->{
StringUtils.getString(R.string.module_core_changing_lane_to_right_to_avoid_stationary_obstacle_ahead) -> {
// "车辆正在避让前方障碍物"
StringUtils.getString(R.string.module_core_avoiding_obstacle_title)
}
// "正在等红灯"->{
StringUtils.getString(R.string.module_core_waiting_for_red_light) -> {
// "路口等红灯"
StringUtils.getString(R.string.module_core_waiting_for_red_light_title)
}
// "正在向左变道避让前方道路施工"->{
StringUtils.getString(R.string.module_core_changing_lane_to_left_to_avoid_road_construction_ahead) -> {
// "车辆正在变道避让前方道路施工"
StringUtils.getString(R.string.module_core_changing_lane_to_left_to_avoid_road_construction_ahead_title)
}
// "正在向右变道避让前方道路施工"->{
StringUtils.getString(R.string.module_core_changing_lane_to_right_to_avoid_road_construction_ahead) -> {
// "车辆正在变道避让前方道路施工"
StringUtils.getString(R.string.module_core_changing_lane_to_left_to_avoid_road_construction_ahead_title)
}
// "正在向左绕行避让前方道路施工"->{
StringUtils.getString(R.string.module_core_turning_left_to_bypass_road_construction_ahead) -> {
// "车辆正在绕行避让前方道路施工"
StringUtils.getString(R.string.module_core_turning_left_to_bypass_road_construction_ahead_title)
}
// "正在向右绕行避让前方道路施工"->{
StringUtils.getString(R.string.module_core_turning_right_to_bypass_road_construction_ahead) -> {
// "车辆正在绕行避让前方道路施工"
StringUtils.getString(R.string.module_core_turning_left_to_bypass_road_construction_ahead_title)
}
// "正在向左变道避让前方道路事故"->{
StringUtils.getString(R.string.module_core_changing_lane_to_left_to_avoid_road_accident_ahead) -> {
// "车辆正在变道避让前方道路事故"
StringUtils.getString(R.string.module_core_changing_lane_to_left_to_avoid_road_accident_ahead_title)
}
// "正在向右变道避让前方道路事故"->{
StringUtils.getString(R.string.module_core_changing_lane_to_right_to_avoid_road_accident_ahead) -> {
// "车辆正在变道避让前方道路事故"
StringUtils.getString(R.string.module_core_changing_lane_to_left_to_avoid_road_accident_ahead_title)
}
// "正在向左绕行避让前方道路事故"->{
StringUtils.getString(R.string.module_core_turning_left_to_bypass_road_accident_ahead) -> {
// "车辆正在绕行避让前方道路事故"
StringUtils.getString(R.string.module_core_turning_left_to_bypass_road_accident_ahead_title)
}
// "正在向右绕行避让前方道路事故"->{
StringUtils.getString(R.string.module_core_turning_right_to_bypass_road_accident_ahead) -> {
// "车辆正在绕行避让前方道路事故"
StringUtils.getString(R.string.module_core_turning_left_to_bypass_road_accident_ahead_title)
}
// "正在跟随车辆行驶"->{
StringUtils.getString(R.string.module_core_following_vehicle_driving) -> {
// "车辆正在跟车通行"
StringUtils.getString(R.string.module_core_following_vehicle_driving_title)
}
// "正在跟车行驶"->{
StringUtils.getString(R.string.module_core_following_the_vehicle_ahead) -> {
// "车辆正在跟车通行"
StringUtils.getString(R.string.module_core_following_vehicle_driving_title)
}
// "正在向左变道避让前方车龙"->{
StringUtils.getString(R.string.module_core_changing_lane_left_avoid_vehicle_queue_ahead) -> {
// "车辆正在绕行前方车龙"
StringUtils.getString(R.string.module_core_changing_lane_left_avoid_vehicle_queue_ahead_title)
}
// "正在向右变道避让前方车龙"->{
StringUtils.getString(R.string.module_core_changing_lane_right_avoid_vehicle_queue_ahead) -> {
// "车辆正在绕行前方车龙"
StringUtils.getString(R.string.module_core_changing_lane_left_avoid_vehicle_queue_ahead_title)
}
// "正在使用云端规划通过路口"->{
StringUtils.getString(R.string.module_core_using_cloud_planning_pass_intersection) -> {
// "车辆正在使用云端轨迹通行"
StringUtils.getString(R.string.module_core_using_cloud_planning_pass_intersection_title)
}
// "正在避让后方来车"->{
StringUtils.getString(R.string.module_core_avoiding_oncoming_vehicles_from_behind) -> {
// "车辆正在避让后方来车"
StringUtils.getString(R.string.module_core_avoiding_oncoming_vehicles_from_behind_title)
}
else -> {
""
}
}
}
private fun getActionDesc(action: String): String {
return when (action) {
// "车辆进站"->{
StringUtils.getString(R.string.module_core_entering_the_station_title) -> {
// "前方即将到达${CommonModel.routesResult}" +
// "车辆正在规划减速并进站停靠,请安心等待车辆停稳再下车哦~"
StringUtils.getString(R.string.module_core_entering_the_station_desc, CommonModel.routesResult)
}
// "车辆等待进站"->{
StringUtils.getString(R.string.module_core_await_station_title) -> {
// "车辆待环境安全后进站,耐心等几秒,安全比赶路更重要~"
StringUtils.getString(R.string.module_core_await_station_desc)
}
// "车辆出站"->{
StringUtils.getString(R.string.module_core_leaving_the_station_title) -> {
// "欢迎乘坐MOGO RoboTaxi车辆正在规划出站坐稳扶好哦我们出发啦小智持续守护您的行程。"
StringUtils.getString(R.string.module_core_leaving_the_station_desc_bus)
}
// "车辆等待出站"->{
StringUtils.getString(R.string.module_core_await_leaving_the_station_title) -> {
// "车辆待环境安全后出站,耐心等几秒,安全比赶路更重要~"
StringUtils.getString(R.string.module_core_await_leaving_the_station_desc)
}
// "车辆向左变道"->{
StringUtils.getString(R.string.module_core_changing_lane_to_left_title) -> {
// "确认环境安全,车辆正在规划平稳向左变道,同时持续监测周边交通参与者动向,放心交给我们吧!"
StringUtils.getString(R.string.module_core_changing_lane_to_left_desc)
}
// "车辆向右变道"->{
StringUtils.getString(R.string.module_core_changing_lane_to_right_title) -> {
// "确认环境安全,车辆正在规划平稳向右变道,同时持续监测周边交通参与者动向,放心交给我们吧!"
StringUtils.getString(R.string.module_core_changing_lane_to_right_desc)
}
// "车辆完成变道"->{
StringUtils.getString(R.string.module_core_completing_lane_change_title) -> {
// "变道完成啦,继续前进!小智持续守护您的行程。"
StringUtils.getString(R.string.module_core_completing_lane_change_desc)
}
// "车辆正在绕过前方障碍物"->{
StringUtils.getString(R.string.module_core_turning_left_to_bypass_stationary_obstacle_ahead_title) -> {
// "发现前方障碍物,车辆正在规划平稳变道,即将画出一条完美弧线~"
StringUtils.getString(R.string.module_core_turning_left_to_bypass_stationary_obstacle_ahead_desc)
}
// "车辆正在避让前方障碍物"->{
StringUtils.getString(R.string.module_core_avoiding_obstacle_title) -> {
// "发现前方障碍物,车辆正在规划平稳避让,诠释优雅与丝滑~"
StringUtils.getString(R.string.module_core_avoiding_obstacle_desc)
}
// "车辆完成绕障"->{
StringUtils.getString(R.string.module_core_vehicle_completed_obstacle_avoidance_title) -> {
// "绕障完成啦,继续前进!小智持续守护您的行程。"
StringUtils.getString(R.string.module_core_vehicle_completed_obstacle_avoidance_desc)
}
// "路口等红灯"->{
StringUtils.getString(R.string.module_core_waiting_for_red_light_title) -> {
// "车辆正在路口等红灯,可以安心放空望望窗外~小智一直在您身边哦!"
StringUtils.getString(R.string.module_core_waiting_for_red_light_desc)
}
// "车辆正在变道避让前方道路施工"->{
StringUtils.getString(R.string.module_core_changing_lane_to_left_to_avoid_road_construction_ahead_title) -> {
// "车辆正在提前规划变道避让前方道路施工,稳稳的很安心~您已体验到车路云一体化协同应用场景,是当之无愧的先锋体验官!"
StringUtils.getString(R.string.module_core_changing_lane_to_left_to_avoid_road_construction_ahead_desc)
}
// "车辆正在绕行避让前方道路施工"->{
StringUtils.getString(R.string.module_core_turning_left_to_bypass_road_construction_ahead_title) -> {
// "车辆正在提前规划绕行避让前方道路施工,稳稳的很安心~您已体验到车路云一体化协同应用场景,是当之无愧的先锋体验官!"
StringUtils.getString(R.string.module_core_turning_left_to_bypass_road_construction_ahead_desc)
}
// "车辆正在变道避让前方道路事故"->{
StringUtils.getString(R.string.module_core_changing_lane_to_left_to_avoid_road_accident_ahead_title) -> {
// "车辆正在提前规划变道避让前方道路事故,放心看我表现吧!您已体验到车路云一体化协同应用场景,小智为您欢呼!"
StringUtils.getString(R.string.module_core_changing_lane_to_left_to_avoid_road_accident_ahead_desc)
}
// "车辆正在绕行避让前方道路事故"->{
StringUtils.getString(R.string.module_core_turning_left_to_bypass_road_accident_ahead_title) -> {
// "车辆正在提前规划绕行避让前方道路事故,放心看我表现吧!您已体验到车路云一体化协同应用场景,小智为您欢呼!"
StringUtils.getString(R.string.module_core_turning_left_to_bypass_road_accident_ahead_desc)
}
// "车辆正在跟车通行"->{
StringUtils.getString(R.string.module_core_following_vehicle_driving_title) -> {
// "车辆正在跟随前车通行舒适度MAX您已体验到车路云一体化协同应用场景超越全国99%的乘客!"
StringUtils.getString(R.string.module_core_following_vehicle_driving_desc)
}
// "车辆正在绕行前方车龙"->{
StringUtils.getString(R.string.module_core_changing_lane_left_avoid_vehicle_queue_ahead_title) -> {
// "车辆正在提前规划变道避让路口车龙舒适度MAX。您已体验到车路云一体化协同应用场景超越全国99%的乘客!"
StringUtils.getString(R.string.module_core_changing_lane_left_avoid_vehicle_queue_ahead_desc)
}
// "车辆正在使用云端轨迹通行"->{
StringUtils.getString(R.string.module_core_using_cloud_planning_pass_intersection_title) -> {
// "前方智慧路口内有障碍物车辆正在使用云端规划轨迹通行。您已体验到车路云一体化协同应用场景超越全国99%的乘客!"
StringUtils.getString(R.string.module_core_using_cloud_planning_pass_intersection_desc)
}
// "车辆正在避让后方来车"->{
StringUtils.getString(R.string.module_core_avoiding_oncoming_vehicles_from_behind_title) -> {
// "车辆正在避让后方来车,耐心等几秒,安全比赶路更重要~"
StringUtils.getString(R.string.module_core_avoiding_oncoming_vehicles_from_behind_desc)
}
else -> {
""
}
}
}
}

View File

@@ -0,0 +1,66 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.mind.data
import android.content.Context
import androidx.lifecycle.ViewModel
import com.mogo.commons.voice.AIAssist
import com.mogo.eagle.core.data.config.FunctionBuildConfig
import com.mogo.eagle.core.function.api.map.road.IMoGoMapRoadListener
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
import com.mogo.eagle.core.function.call.autopilot.CallerServicesEventManager
import com.mogo.eagle.core.function.call.hmi.CallerHmiViewControlListenerManager
import com.mogo.eagle.core.function.call.map.CallerMapRoadListenerManager
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.util.StringUtils
import com.mogo.och.shuttle.weaknet.passenger.R
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.B4AIMessageManager
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.bean.B4AIMessage
class B4RoadCrossRoamViewModel : ViewModel(), IMoGoMapRoadListener {
companion object {
const val TAG = "B4RoadCrossRoamViewModel"
}
private lateinit var mContext: Context
fun init(context: Context) {
CallerMapRoadListenerManager.addListener(TAG, this)
mContext = context
}
override fun onCrossDevice(trigger: Boolean) {
super.onCrossDevice(trigger)
if (trigger) {
show()
}
}
private fun show() {
// 没有路线不做提示
if (CallerAutoPilotStatusListenerManager.getLineId() == 0L) {
CallerLogger.d(TAG, "没有路线不做提示")
return
}
// 首页被遮挡不做提示
if (!CallerHmiViewControlListenerManager.getMainPageVisible()) {
CallerLogger.d(TAG, "attachView return , mainPageVisible is false")
return
}
// 没有路侧设备,不做处理
CallerLogger.d(TAG, "命中attachView")
val cross = CallerMapRoadListenerManager.getCrossEndInfo()
if (cross.isNullOrEmpty()) {
CallerLogger.d(TAG, "未触发路口ID:$cross")
return
}
if (AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)) {
// val disStr = "为您提供路口全息影像,助力出行"
val disStr = StringUtils.getString(R.string.module_och_offer_intersection_holographic_image)
AIAssist.getInstance(mContext).speakTTSVoiceWithLevel(disStr, AIAssist.NEW_LEVEL_2)
}
CallerServicesEventManager.updateServicesNum(CallerServicesEventManager.ServiceType.ROAD)
B4AIMessageManager.post(B4AIMessage.B4RoadCrossRoam(System.currentTimeMillis().toString(), ""))
}
}

View File

@@ -0,0 +1,74 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.mind.data
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.lifecycle.ViewModel
import androidx.lifecycle.lifecycleScope
import com.mogo.commons.utils.MogoAnalyticUtils
import com.mogo.eagle.core.data.v2x.RoadV2NEventWindowBean
import com.mogo.eagle.core.function.api.hmi.v2n.IRoadV2NEventWindowListener
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
import com.mogo.eagle.core.function.call.hmi.CallerHmiViewControlListenerManager
import com.mogo.eagle.core.function.call.hmi.CallerRoadV2NEventWindowListenerManager
import com.mogo.eagle.core.function.hmi.ui.utils.HmiActionLog
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.B4AIMessageManager
import com.mogo.och.shuttle.weaknet.passenger.ui.mind.bean.B4AIMessage
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class B4RoadV2NEventViewModel : ViewModel(), IRoadV2NEventWindowListener {
companion object {
const val TAG = "B4RoadV2NEventViewModel"
const val ANALYTICS_KEY = "hmi_road_event_window_view"
fun trackEvent(msg: String) {
ProcessLifecycleOwner.get().lifecycleScope.launch(Dispatchers.IO) {
val map: MutableMap<String, Any> = HashMap()
map["msg"] = msg
MogoAnalyticUtils.track(
ANALYTICS_KEY,
map
)
HmiActionLog.hmiAction(TAG, msg)
}
CallerLogger.i(TAG, msg)
}
}
fun init() {
CallerRoadV2NEventWindowListenerManager.addListener(TAG, this)
}
override fun show(dataBean: RoadV2NEventWindowBean) {
trackEvent("show --> $dataBean")
val canShowV2NEventWindowView = CallerHmiViewControlListenerManager.getMainPageVisible()
if (!canShowV2NEventWindowView) {
trackEvent("show --> 当前不在高精地图页面,跳过")
return
}
val lineId = CallerAutoPilotStatusListenerManager.getLineId()
if (lineId <= 0) {
trackEvent("show --> 当前无订单,跳过")
return
}
val event = B4AIMessage.B4RoadV2NEvent(
dataBean.eventId,
dataBean.hintStr,
"",
dataBean.eventType,
dataBean.timestamp,
dataBean.iconResId,
false,
dataBean.contentImageUrl,
dataBean.cameraIp,
dataBean.lon,
dataBean.lat
)
B4AIMessageManager.post(event)
}
override fun dismiss(eventId: String) {
}
}

View File

@@ -0,0 +1,19 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.widget
import android.content.Context
import android.util.AttributeSet
import com.mogo.eagle.core.function.view.MapBizView
import com.mogo.eagle.core.widget.media.video.TextureVideoViewOutlineProvider
import me.jessyan.autosize.utils.AutoSizeUtils
class B4OchMapBizPView(context: Context?, attrs: AttributeSet?) : MapBizView(context, attrs) {
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
this.outlineProvider =
TextureVideoViewOutlineProvider(AutoSizeUtils.dp2px(context, 36f).toFloat())
this.clipToOutline = true
}
}

View File

@@ -0,0 +1,184 @@
package com.mogo.och.shuttle.weaknet.passenger.ui.widget
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.LinearLayout
import com.mogo.eagle.core.data.enums.DataSourceType
import com.mogo.eagle.core.data.enums.TrafficLightEnum
import com.mogo.eagle.core.function.api.datacenter.union.IMoGoTrafficLightListener
import com.mogo.eagle.core.function.call.v2x.CallerTrafficLightListenerManager
import com.mogo.eagle.core.utilcode.util.UiThreadHandler
import com.mogo.och.shuttle.weaknet.passenger.R
import kotlinx.android.synthetic.main.shuttle_p_b4_traffic_light_view.view.b4_p_traffic_light_bg
import kotlinx.android.synthetic.main.shuttle_p_b4_traffic_light_view.view.b4_p_traffic_light_iv
import kotlinx.android.synthetic.main.shuttle_p_b4_traffic_light_view.view.b4_p_traffic_light_time_tv
/**
* bus乘客端红绿灯view
*
* Created on 2022/3/14
*/
class B4PTrafficLightView @JvmOverloads constructor(
context: Context?,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr), IMoGoTrafficLightListener {
companion object {
private const val TAG = "B4PTrafficLightView"
}
private var mCurrentLightId = TrafficLightEnum.BLACK
init {
init(context)
}
private fun init(context: Context?) {
LayoutInflater.from(context).inflate(R.layout.shuttle_p_b4_traffic_light_view, this, true)
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
CallerTrafficLightListenerManager.addListener(TAG, this)
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
CallerTrafficLightListenerManager.removeListener(TAG)
}
/**
* 展示红绿灯预警
*
* @param checkLightId 0-都是默认1-红2-黄3-绿
* @param lightSource 1:云端下发2:自车感知
*/
override fun showTrafficLight(checkLightId: TrafficLightEnum, lightSource: DataSourceType) {
super.showTrafficLight(checkLightId, lightSource)
mCurrentLightId = checkLightId
updateTrafficLightIcon(checkLightId)
}
/**
* 关闭红绿灯预警展示,并重制灯态
*/
override fun disableTrafficLight() {
super.disableTrafficLight()
UiThreadHandler.post {
mCurrentLightId = TrafficLightEnum.BLACK
this@B4PTrafficLightView.visibility = GONE
}
}
/**
* @param redNum 红灯倒计时
* @param yellowNum 黄灯倒计时
* @param greenNum 绿灯倒计时
*/
override fun changeCountdownTrafficLightNum(redNum: Int, yellowNum: Int, greenNum: Int) {
super.changeCountdownTrafficLightNum(redNum, yellowNum, greenNum)
resetView()
when (mCurrentLightId) {
TrafficLightEnum.RED -> changeCountdownRed(redNum)
TrafficLightEnum.YELLOW -> changeCountdownYellow(yellowNum)
TrafficLightEnum.GREEN -> changeCountdownGreen(greenNum)
else -> UiThreadHandler.post { b4_p_traffic_light_time_tv.text = "" }
}
}
override fun changeCountdownRed(redNum: Int) {
super.changeCountdownRed(redNum)
UiThreadHandler.post {
if (redNum > 0) {
resetView()
b4_p_traffic_light_time_tv.text = redNum.toString()
} else {
disableTrafficLightCountDown()
b4_p_traffic_light_time_tv.text = ""
}
}
}
override fun changeCountdownGreen(greenNum: Int) {
super.changeCountdownGreen(greenNum)
UiThreadHandler.post {
if (greenNum > 0) {
resetView()
b4_p_traffic_light_time_tv.text = greenNum.toString()
} else {
disableTrafficLightCountDown()
b4_p_traffic_light_time_tv.text = ""
}
}
}
override fun changeCountdownYellow(yellowNum: Int) {
super.changeCountdownYellow(yellowNum)
UiThreadHandler.post {
if (yellowNum > 0) {
resetView()
b4_p_traffic_light_time_tv.text = yellowNum.toString()
} else {
disableTrafficLightCountDown()
b4_p_traffic_light_time_tv.text = ""
}
}
}
/**
* 更新红绿灯icon
*
* @param lightId 0-都是默认1-红2-黄3-绿
*/
private fun updateTrafficLightIcon(lightId: TrafficLightEnum) {
UiThreadHandler.post {
when (lightId) {
TrafficLightEnum.RED -> {
b4_p_traffic_light_iv.setBackgroundResource(R.drawable.shuttle_p_b4_light_red_nor)
this@B4PTrafficLightView.visibility = VISIBLE
}
TrafficLightEnum.YELLOW -> {
b4_p_traffic_light_iv.setBackgroundResource(R.drawable.shuttle_p_b4_light_yellow_nor)
this@B4PTrafficLightView.visibility = VISIBLE
}
TrafficLightEnum.GREEN -> {
b4_p_traffic_light_iv.setBackgroundResource(R.drawable.shuttle_p_b4_light_green_nor)
this@B4PTrafficLightView.visibility = VISIBLE
}
else -> this@B4PTrafficLightView.visibility = GONE
}
}
}
override fun disableTrafficLightCountDown() {
super.disableTrafficLightCountDown()
UiThreadHandler.post {
val layoutParams = layoutParams
if (layoutParams is MarginLayoutParams) {
val lp = layoutParams
lp.width = resources.getDimension(R.dimen.dp_40).toInt()
setLayoutParams(lp)
b4_p_traffic_light_time_tv.visibility = GONE
b4_p_traffic_light_bg.layoutParams.width =
resources.getDimension(R.dimen.dp_40).toInt()
}
}
}
private fun resetView() {
val layoutParams = layoutParams
if (layoutParams is MarginLayoutParams) {
val lp = layoutParams
lp.width = resources.getDimension(R.dimen.dp_60).toInt()
setLayoutParams(lp)
b4_p_traffic_light_time_tv.visibility = VISIBLE
b4_p_traffic_light_bg.layoutParams.width =
resources.getDimension(R.dimen.dp_60).toInt()
}
}
}

View File

@@ -8,13 +8,15 @@ import com.mogo.eagle.core.data.config.FunctionBuildConfig
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
import com.mogo.eagle.core.utilcode.util.DeviceUtils import com.mogo.eagle.core.utilcode.util.DeviceUtils
import com.mogo.och.common.module.biz.media.MediaManager import com.mogo.och.common.module.biz.media.MediaManager
import com.mogo.och.common.module.constant.OchCommonConst
import com.mogo.och.common.module.biz.provider.CommonServiceImpl import com.mogo.och.common.module.biz.provider.CommonServiceImpl
import com.mogo.och.common.module.constant.OchCommonConst
import com.mogo.och.shuttle.weaknet.passenger.model.TicketModel import com.mogo.och.shuttle.weaknet.passenger.model.TicketModel
import com.mogo.och.shuttle.weaknet.passenger.ui.widget.BusPStatusBarView
import com.mogo.och.shuttle.weaknet.passenger.ui.BusPassengerRouteFragment import com.mogo.och.shuttle.weaknet.passenger.ui.BusPassengerRouteFragment
import com.mogo.och.shuttle.weaknet.passenger.ui.PB4BaseFragment
import com.mogo.och.shuttle.weaknet.passenger.ui.PM2BaseFragment import com.mogo.och.shuttle.weaknet.passenger.ui.PM2BaseFragment
import com.mogo.och.shuttle.weaknet.passenger.ui.statusbar.B4StatusBarView
import com.mogo.och.shuttle.weaknet.passenger.ui.statusbar.M2StatusBarView import com.mogo.och.shuttle.weaknet.passenger.ui.statusbar.M2StatusBarView
import com.mogo.och.shuttle.weaknet.passenger.ui.widget.BusPStatusBarView
/** /**
* 网约车-Bus-乘客端 * 网约车-Bus-乘客端
@@ -25,19 +27,21 @@ import com.mogo.och.shuttle.weaknet.passenger.ui.statusbar.M2StatusBarView
class ShuttlePassengerProvider : CommonServiceImpl() { class ShuttlePassengerProvider : CommonServiceImpl() {
private val tag = ShuttlePassengerProvider::class.java.simpleName private val tag = ShuttlePassengerProvider::class.java.simpleName
private var mPM2Fragment: Fragment?=null private var mPM2Fragment: Fragment? = null
override fun init(context: Context) { override fun init(context: Context) {
} }
override fun getStatusBarView(context: Context): View { override fun getStatusBarView(context: Context): View {
if(statusBarView==null){ if (statusBarView == null) {
statusBarView = if (AppIdentityModeUtils.isB2(FunctionBuildConfig.appIdentityMode)) { statusBarView = if (AppIdentityModeUtils.isB2(FunctionBuildConfig.appIdentityMode)) {
M2StatusBarView(context); M2StatusBarView(context);
} else if (AppIdentityModeUtils.isB4(FunctionBuildConfig.appIdentityMode)) {
//TODO 返回null 没有状态栏
} else if (AppIdentityModeUtils.isB1(FunctionBuildConfig.appIdentityMode)) { } else if (AppIdentityModeUtils.isB1(FunctionBuildConfig.appIdentityMode)) {
BusPStatusBarView(context); BusPStatusBarView(context);
}else{ } else {
BusPStatusBarView(context); BusPStatusBarView(context);
} }
} }
@@ -46,14 +50,16 @@ class ShuttlePassengerProvider : CommonServiceImpl() {
override fun getFragment(): Fragment { override fun getFragment(): Fragment {
if (AppIdentityModeUtils.isB1(FunctionBuildConfig.appIdentityMode) && DeviceUtils.isEB5Model()) { if (AppIdentityModeUtils.isB1(FunctionBuildConfig.appIdentityMode) && DeviceUtils.isEB5Model()) {
MediaManager.Video.startSecondAds() MediaManager.Video.startSecondAds()
} }
if(mPM2Fragment==null){ if (mPM2Fragment == null) {
mPM2Fragment = if (AppIdentityModeUtils.isB2(FunctionBuildConfig.appIdentityMode)) { mPM2Fragment = if (AppIdentityModeUtils.isB2(FunctionBuildConfig.appIdentityMode)) {
PM2BaseFragment() PM2BaseFragment()
}else if (AppIdentityModeUtils.isB1(FunctionBuildConfig.appIdentityMode)) { } else if (AppIdentityModeUtils.isB4(FunctionBuildConfig.appIdentityMode)) {
PB4BaseFragment()
} else if (AppIdentityModeUtils.isB1(FunctionBuildConfig.appIdentityMode)) {
BusPassengerRouteFragment() BusPassengerRouteFragment()
}else{ } else {
BusPassengerRouteFragment() BusPassengerRouteFragment()
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 921 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 791 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 828 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 811 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 841 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 899 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 608 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 973 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1018 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 974 B

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/common_B3FFFFFF" />
<corners android:radius="@dimen/dp_18" />
</shape>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="#DDDDDD" />
</shape>
</item>
<item>
<inset android:inset="100dp">
<bitmap android:src="@drawable/b4_icon_image_error" />
</inset>
</item>
</layer-list>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="#DDDDDD" />
</shape>
</item>
<item>
<inset android:inset="100dp">
<bitmap android:src="@drawable/b4_icon_image_holder" />
</inset>
</item>
</layer-list>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="0"
android:endColor="@color/common_color_00000000"
android:startColor="@color/common_B3FFFFFF" />
<corners android:radius="@dimen/dp_18" />
</shape>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/b4_1F82FB" />
<corners
android:topLeftRadius="@dimen/dp_18"
android:topRightRadius="@dimen/dp_18" />
</shape>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/b4_1F82FB" />
<corners
android:bottomLeftRadius="@dimen/dp_18"
android:bottomRightRadius="@dimen/dp_18" />
</shape>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/b4_95B1D6" />
<corners
android:topLeftRadius="@dimen/dp_18"
android:topRightRadius="@dimen/dp_18" />
</shape>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/b4_95B1D6" />
<corners
android:bottomLeftRadius="@dimen/dp_18"
android:bottomRightRadius="@dimen/dp_18" />
</shape>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false"
android:visible="true">
<item
android:drawable="@drawable/shuttle_p_b4_arrived_an_0"
android:duration="300" />
<item
android:drawable="@drawable/shuttle_p_b4_arrived_an_1"
android:duration="300" />
<item
android:drawable="@drawable/shuttle_p_b4_arrived_an_2"
android:duration="300" />
</animation-list>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size
android:width="@dimen/dp_66"
android:height="@dimen/dp_38" />
<solid android:color="@color/shuttle_p_b4_button_un_auto_bg_color" />
<corners android:radius="@dimen/dp_20" />
</shape>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="16dp" />
<gradient
android:angle="0"
android:endColor="#D5DDED"
android:startColor="#D5DDED"
android:type="linear" />
</shape>

Some files were not shown because too many files have changed in this diff Show More