[fea]
[访客模式]
This commit is contained in:
yangyakun
2024-12-19 17:16:07 +08:00
parent 3ebf8ac078
commit 88566ffe0e
173 changed files with 4010 additions and 5696 deletions

View File

@@ -27,6 +27,12 @@
<color name="common_B3000000">#B3000000</color>
<color name="common_5F6582">#5F6582</color>
<color name="common_A0B3DA">#A0B3DA</color>
<color name="common_CCB9C3E9">#CCB9C3E9</color>
<color name="common_4DFFFFFF">#4DFFFFFF</color>
<color name="common_1970FF">#1970FF</color>
<color name="common_19FF7F">#19FF7F</color>
<color name="common_2EACFF">#2EACFF</color>
<color name="common_3B4577">#3B4577</color>
<color name="common_232A3F">#232A3F</color>
@@ -39,4 +45,6 @@
<color name="common_3B3D44">#3B3D44</color>
<color name="common_2E323A">#2E323A</color>
<color name="common_ffffffff">#ffffffff</color>
</resources>

View File

@@ -62,9 +62,7 @@ abstract class BaseLineDb {
needMinusDatas.forEach { minusLine->
minusLine.lineId?.let { lineId->
// 删除线路对应的站点
deleteSitesTaskAndContraiDb(lineId)
}
}
}

View File

@@ -20,6 +20,7 @@ android {
useBuildCache = false
arguments {
arg("AROUTER_MODULE_NAME", "offline"+project.getName())
arg("room.schemaLocation", "$projectDir/schemas".toString())
}
}
}
@@ -61,6 +62,11 @@ dependencies {
implementation rootProject.ext.dependencies.androidxrecyclerview
compileOnly rootProject.ext.dependencies.recyclerviewadapterhelper
implementation rootProject.ext.dependencies.roomRxjava
implementation rootProject.ext.dependencies.androidxroomruntime
kapt rootProject.ext.dependencies.androidxroomcompiler
implementation project(":OCH:common:common")
implementation project(":OCH:common:data")
compileOnly project(":libraries:mogo-map")

View File

@@ -2,10 +2,7 @@
package="com.mogo.och.offline">
<application>
<activity android:name=".ui.BusSwitchLineActivity"
android:theme="@style/SwitchLineDialogStyle"
android:launchMode="singleTask"
android:screenOrientation="landscape" />
</application>
</manifest>

View File

@@ -6,11 +6,13 @@ import androidx.fragment.app.Fragment
import com.alibaba.android.arouter.facade.annotation.Route
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
import com.mogo.och.offline.fragment.ShuttleFragment
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_OFFLINE
import com.mogo.och.common.module.constant.OchCommonConst
import com.mogo.och.common.module.biz.provider.CommonServiceImpl
import com.mogo.och.bridge.autopilot.autopilot.OchAutopilotAnalytics
import com.mogo.och.bridge.ui.autopilot.AutopilotState
import com.mogo.och.offline.ui.bizswitch.SwitchBizView
import com.mogo.och.offline.ui.fragment.OfflineFragment
import com.mogo.och.offline.util.BusAnalyticsManager
import com.mogo.och.offline.util.OffLineTrajectoryManager
@@ -22,8 +24,8 @@ import com.mogo.och.offline.util.OffLineTrajectoryManager
@Route(path = OchCommonConst.OFFLINE_DRIVER)
class ShuttleDriverProvider : CommonServiceImpl() {
private val TAG = ShuttleDriverProvider::class.java.simpleName
private var busFragment: ShuttleFragment?=null
private val TAG = M_OFFLINE+ShuttleDriverProvider::class.java.simpleName
private var busFragment: OfflineFragment?=null
override fun init(context: Context) {
d(SceneConstant.M_TAXI + TAG, "init")
@@ -31,7 +33,7 @@ class ShuttleDriverProvider : CommonServiceImpl() {
override fun getFragment(): Fragment {
if(busFragment==null){
busFragment = ShuttleFragment()
busFragment = OfflineFragment()
}
OchAutopilotAnalytics.ochEventKey = BusAnalyticsManager.getInstance()
OffLineTrajectoryManager.load()
@@ -44,6 +46,13 @@ class ShuttleDriverProvider : CommonServiceImpl() {
busFragment = null
}
override fun createOchBusinessView(context: Context?): View? {
d(TAG, "createOchBusinessView")
return context?.let {
SwitchBizView(it)
}
}
override fun createStartAutopilotView(context: Context?): View? {
return context?.let {
AutopilotState(it)

View File

@@ -1,50 +0,0 @@
package com.mogo.och.offline.bean
import com.mogo.eagle.core.data.BaseData
import com.mogo.och.data.bean.BusRoutesResult
import com.mogo.och.data.bean.BusStationBean
import java.util.*
/**
*
*/
data class BindLineListResponse(val data: List<Result>?) : BaseData(){
data class Result(
var line: LineInfo?,
var siteList: List<BusStationBean>?,//站点名称
val contrail: Contrail?,//站点名称
)
data class LineInfo(
val lineId:Long?,
var lineName:String?,
)
data class Contrail(
val csvFileUrl:String?,
val csvFileMd5:String?,
val txtFileUrl:String?,
val txtFileMd5:String?,
val contrailSaveTime:Long?,
)
companion object{
@JvmStatic
fun getCommonLineInfo(dataItem:Result):BusRoutesResult?{
val result = BusRoutesResult()
dataItem.siteList?.forEach {
it.drivingStatus = 3
}
result.setSite(dataItem.siteList)
result.csvFileUrl = dataItem.contrail?.csvFileUrl
result.csvFileMd5 = dataItem.contrail?.csvFileMd5
result.txtFileUrl = dataItem.contrail?.txtFileUrl
result.txtFileMd5 = dataItem.contrail?.txtFileMd5
result.contrailSaveTime = dataItem.contrail?.contrailSaveTime?:0
result.name = dataItem.line?.lineName?:""
result.lineId = dataItem.line?.lineId?.toInt()?:0
return result
}
}
}

View File

@@ -1,11 +0,0 @@
package com.mogo.och.offline.callback;
/**
* Created on 2021/9/8
*
* Model->Presenter回调ADAS相关自动驾驶状态回调到达终点等等
*/
public interface IBusADASStatusCallback {
//自驾返回失败
void onStartAdasFailure();
}

View File

@@ -1,15 +0,0 @@
package com.mogo.och.offline.callback;
import com.mogo.eagle.core.data.map.MogoLocation;
/**
* Created on 2021/9/10
*
* Model->Presenter回调状态控制器监听accOn、adas ui show、voice ui show、push ui show、v2x ui show等等
*/
public interface IBusControllerStatusCallback {
// 自车定位
void onCarLocationChanged(MogoLocation location);
//开始开启自动驾驶
void startOpenAutopilot();
}

View File

@@ -1,12 +1,30 @@
package com.mogo.och.offline.callback;
import com.mogo.och.offline.bean.BindLineListResponse;
/**
* @author: wangmingjun
* @date: 2022/2/9
*/
public interface IBusLinesCallback {
void onBusLinesChange(BindLineListResponse lines);
void onChangeLineIdSuccess(BindLineListResponse.Result checkLineInfo);
default void onChangeLineIdSuccess(){}
default void onRefreshSuccess(long currentTimeStamp){}
default void onRefreshSuccessWIthData(){}
default void onChangeLineIdFail(){}
default void onNoRunningTask(){}
default void onRunningTask(){}
default void onLeaveStaionSuccess(){}
default void onArriveStationSuccess(){}
default void onCompleteTask(){}
default void onCompleteTaskFail(){}
default void onEndTaskByOther(long taskId,String plateNumber){}
}

View File

@@ -1,23 +0,0 @@
package com.mogo.och.offline.callback;
import com.mogo.och.data.bean.BusStationBean;
import java.util.List;
/**
* @author: wangmingjun
* @date: 2021/10/22
*/
public interface IRefreshBusStationsCallback {
void updateBusTaskStatus(String lineName,String lintTime,
List<BusStationBean> stationList,
int arrivingOrArrivedIndex,
boolean isArrived);
/**
* 结束清理一遍、选择任务后清理一遍
*/
void clearBusStationsMarkers();
void updateEmptyUi();
}

View File

@@ -1,9 +0,0 @@
package com.mogo.och.offline.callback;
/**
* @author: wangmingjun
* @date: 2021/10/22
*/
public interface ISlidePannelHideCallback {
void hideSlidePanel();
}

View File

@@ -36,6 +36,8 @@ class BusConst {
//终点UUID
const val BUS_END_MAP_MAKER = "bus_end_map_maker";
const val SEND_OUTVOICE_DISTANCES_TARTSTATIONE = 15
/**
* 订单起终点Marker类型

View File

@@ -1,558 +0,0 @@
package com.mogo.och.offline.fragment;
import static com.mogo.och.offline.constant.BusConst.TIMER_START_AUTOPILOT_INTERVAL;
import android.animation.ObjectAnimator;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.Group;
import androidx.core.content.ContextCompat;
import com.mogo.commons.AbsMogoApplication;
import com.mogo.commons.mvp.IView;
import com.mogo.commons.mvp.MvpFragment;
import com.mogo.commons.mvp.Presenter;
import com.mogo.eagle.core.data.config.FunctionBuildConfig;
import com.mogo.eagle.core.data.config.HdMapBuildConfig;
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener;
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager;
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager;
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotRecordListenerManager;
import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager;
import com.mogo.eagle.core.function.call.map.CallerMapUIServiceManager;
import com.mogo.eagle.core.function.hmi.ui.msgbox.DriverMsgBoxBubbleView;
import com.mogo.eagle.core.function.hmi.ui.msgbox.DriverMsgBoxButtonView;
import com.mogo.eagle.core.function.hmi.ui.msgbox.DriverMsgBoxListView;
import com.mogo.eagle.core.function.smp.view.SmallMapView;
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils;
import com.mogo.eagle.core.utilcode.mogo.view.OnPreventFastClickListener;
import com.mogo.eagle.core.utilcode.util.UiThreadHandler;
import com.mogo.map.MogoMap;
import com.mogo.map.uicontroller.IMogoMapUIController;
import com.mogo.och.common.module.utils.ResourcesUtils;
import com.mogo.och.offline.R;
import com.mogo.och.offline.model.OrderModel;
import com.mogo.och.offline.view.BizMapView;
import com.mogo.och.data.bean.BusRoutesResult;
import com.mogo.och.offline.view.SlidePanelView;
import com.mogo.och.common.module.utils.SoundPoolHelper;
import org.greenrobot.eventbus.EventBus;
/**
* 网约车基础Fragment主要负责布局通用界面处理站点面板和通话面板互斥情况
* <p>
* 部分业务放在了此处处理
*
* @author tongchenfei
*/
public abstract class BaseShuttleTabFragment<V extends IView, P extends Presenter<V>> extends MvpFragment<V, P> {
private static final String TAG = "BaseBusTabFragment";
protected SlidePanelView slidePanelView;
private RelativeLayout ctvAutopilotStatus;
private ImageView ctvAutopilotStatusIv;
private TextView ctvAutopilotStatusTv;
protected TextView tvArrived;
private FrameLayout flStationPanelContainer;
private BizMapView mapBizView;
private Group groupTestPanel;
protected SmallMapView smallMapView;
//消息盒子
private DriverMsgBoxButtonView viewDriverMsgBoxButton;
private DriverMsgBoxListView viewDriverMsgBoxList;
private DriverMsgBoxBubbleView viewDriverMsgBoxBubble;
private ObjectAnimator autopilotLoadingAnimator;
public boolean isAnimateRunning = false;
/**
* 滑动按钮触发的事件
*/
private final SlidePanelView.OnSlidePanelMoveToEndListener onSlideToEndListener = () -> {
// 此处做一个代理,处理一下共有情况
if (getSlidePanelOnEndListener() != null) {
getSlidePanelOnEndListener().moveToEnd();
}
};
@Override
protected int getLayoutId() {
return R.layout.offline_base_fragment;
}
@Override
protected void initViews() {
mapBizView = findViewById(R.id.mapBizView);
groupTestPanel = findViewById(R.id.groupTestPanel);
slidePanelView = findViewById(R.id.module_mogo_och_slide_panel);
ctvAutopilotStatus = findViewById(R.id.module_mogo_och_autopilot_status);
ctvAutopilotStatusIv = findViewById(R.id.bus_autopilot_btn_iv);
ctvAutopilotStatusTv = findViewById(R.id.bus_autopolot_btn_tv);
flStationPanelContainer = findViewById(R.id.module_mogo_och_station_panel_container);
tvArrived = findViewById(R.id.module_mogo_och_arrived_tv);
FrameLayout flSpeed = findViewById(R.id.fl_speed);
if (flSpeed != null) {
CallerDevaToolsManager.INSTANCE.attachAutopilotBeforeLaunchView(flSpeed.getContext(), flSpeed);
}
LayoutInflater.from(getContext()).inflate(getStationPanelViewId(), flStationPanelContainer);
slidePanelView.setOnSlidePanelMoveToEndListener(onSlideToEndListener);
updateSwitchMapIcon();
initListener();
setAutopilotBtnStatus(CallerAutoPilotStatusListenerManager.INSTANCE.getState(),
CallerAutoPilotControlManager.INSTANCE.isCanStartAutopilot(false, 0));
ctvAutopilotStatus.setOnClickListener(new OnPreventFastClickListener() {
@Override
public void onClickImpl(View v) {
restartAutopilot();
}
});
// 模拟 不可自动驾驶目前场景是刚开机adas还未和工控机连接
findViewById(R.id.btnAutopilotDisable).setOnClickListener(view ->
debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE)
);
// 模拟 可自动驾驶,工控机连接正常,且处于人工干预状态
findViewById(R.id.btnAutopilotEnable).setOnClickListener(view ->
debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE)
);
// 模拟 自动驾驶能力,自动驾驶中,可能是停车,可能是行进,但是是机器在处理车的前进后退,不是人
findViewById(R.id.btnAutopilotRunning).setOnClickListener(view ->
debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING)
);
findViewById(R.id.btnAutopilotPingxing).setOnClickListener(view ->
debugAutoPilotStatus(IMoGoAutopilotStatusListener.STATUS_PARALLEL_DRIVING)
);
// 模拟 自动驾驶网约车回调数据
findViewById(R.id.btnAutopilotArrive).setOnClickListener(view ->
debugArrivedStation()
);
tvArrived.setOnClickListener(view -> {
onArriveStation();
});
//消息盒子
viewDriverMsgBoxButton = findViewById(R.id.viewDriverMsgBoxButton);
viewDriverMsgBoxList = findViewById(R.id.viewDriverMsgBoxList);
viewDriverMsgBoxBubble = findViewById(R.id.viewDriverMsgBoxBubble);
viewDriverMsgBoxButton.setClickListener(show -> {
if(show){
viewDriverMsgBoxList.setVisibility(View.VISIBLE);
viewDriverMsgBoxList.notifyData();
viewDriverMsgBoxBubble.setVisibility(View.GONE);
viewDriverMsgBoxBubble.isShowData(false);
}else{
viewDriverMsgBoxList.setVisibility(View.GONE);
viewDriverMsgBoxBubble.setVisibility(View.VISIBLE);
viewDriverMsgBoxBubble.isShowData(true);
}
});
smallMapView = findViewById(R.id.smallMapView);
}
@Override
protected void initViews(Bundle savedInstanceState) {
super.initViews(savedInstanceState);
mapBizView.onCreate(savedInstanceState);
smallMapView.onCreateView(savedInstanceState);
}
@Override
public void onResume() {
super.onResume();
mapBizView.onResume();
smallMapView.onResume();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container
, @Nullable Bundle savedInstanceState) {
EventBus.getDefault().register(this);
return super.onCreateView(inflater, container, savedInstanceState);
}
protected abstract void onArriveStation();
private void updateSwitchMapIcon() {
IMogoMapUIController mapUIController = CallerMapUIServiceManager.INSTANCE.getMapUIController(MogoMap.DEFAULT);
if(mapUIController!=null){
if (AppIdentityModeUtils.isB2(FunctionBuildConfig.appIdentityMode)) {
mapUIController.changeCurrentIcon(R.raw.m2);
HdMapBuildConfig.currentCarVrIconRes = R.raw.m2;
}else if (AppIdentityModeUtils.isB1(FunctionBuildConfig.appIdentityMode)) {
mapUIController.changeCurrentIcon(R.raw.xiaoba);
HdMapBuildConfig.currentCarVrIconRes = R.raw.xiaoba;
}
}
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
mapBizView.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapBizView.onLowMemory();
}
@Override
public void onPause() {
super.onPause();
mapBizView.onPause();
smallMapView.onPause();
}
@Override
public void onDestroyView() {
mapBizView.onDestroy();
if(smallMapView != null){
smallMapView.onDestroy();
}
super.onDestroyView();
CallerAutopilotRecordListenerManager.INSTANCE.removeListener(TAG);
EventBus.getDefault().unregister(this);
}
/**
* 测试到站
*/
protected abstract void debugArrivedStation();
private void initListener() {
}
/**
* 展示滑动按钮
*
* @param text 指定的文字
*/
public void showSlidePanel(String text) {
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
slidePanelView.setText(text);
slidePanelView.setVisibility(View.VISIBLE);
}
}, UiThreadHandler.MODE.QUEUE);
setArrivedClikable(false);
}
/**
* 设置进站按钮状态
*
* @param isClickable
*/
public void setArrivedClikable(boolean isClickable) {
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
tvArrived.setEnabled(isClickable);
if (isClickable) {
tvArrived.setTextColor(ContextCompat.getColor(AbsMogoApplication.getApp(),R.color.bus_white));
} else {
tvArrived.setTextColor(ContextCompat.getColor(AbsMogoApplication.getApp(),R.color.bus_arrived_btn_un_clickable_color));
}
}
}, UiThreadHandler.MODE.QUEUE);
}
/**
* 隐藏滑动按钮
*/
public void hideSlidePanel() {
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
slidePanelView.setVisibility(View.GONE);
}
}, UiThreadHandler.MODE.QUEUE);
}
public void playDI() {
SoundPoolHelper.getSoundPoolHelper().playSoundWithRedId(getContext(), R.raw.bus_di);
}
/**
* 改变自动驾驶状态
*
* @param autopilotStatus 0:不可用 1:可用状态 2:自动驾驶中
*/
public void onAutopilotStatusChanged(int autopilotStatus,boolean canStartAuto) {
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
changeAutopilotBtnView(autopilotStatus, isAnimateRunning,canStartAuto);
}
}, UiThreadHandler.MODE.QUEUE);
}
public void setAutopilotBtnStatus(int autopilotStatus,boolean canStartAuto) {
if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE == autopilotStatus) {//0不可用
ctvAutopilotStatusTv.setTextColor(ResourcesUtils.getColor(R.color.bus_autopilot_text_color_disable));
ctvAutopilotStatusTv.setText(ResourcesUtils.getString(R.string.bus_loading_autopilot_runnig_tv));
ctvAutopilotStatusIv.setImageResource(R.drawable.bus_disable_autopilot_icon);
ctvAutopilotStatus.setClickable(true);
ctvAutopilotStatus.setBackgroundResource(R.drawable.common_autopilot_start_fail);
} else {
ctvAutopilotStatusTv.setTextColor(AbsMogoApplication.getApp().getColor(R.color.bus_autopilot_text_color_normal));
ctvAutopilotStatusIv.setImageResource(R.drawable.bus_ic_autopilot);
if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE == autopilotStatus) { //1可用
ctvAutopilotStatusTv.setText(ResourcesUtils.getString(R.string.bus_loading_autopilot_runnig_tv));
if(canStartAuto){
ctvAutopilotStatus.setClickable(true);
ctvAutopilotStatus.setBackgroundResource(R.drawable.common_autopilot_press);
}else {
ctvAutopilotStatusTv.setTextColor(ResourcesUtils.getColor(R.color.bus_autopilot_text_color_disable));
ctvAutopilotStatusIv.setImageResource(R.drawable.bus_disable_autopilot_icon);
ctvAutopilotStatus.setClickable(true);
ctvAutopilotStatus.setBackgroundResource(R.drawable.common_autopilot_start_fail);
}
} else if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING == autopilotStatus) {
ctvAutopilotStatusTv.setText(R.string.bus_loading_autopilot_runnig_tv);
ctvAutopilotStatus.setClickable(true);
ctvAutopilotStatus.setBackgroundResource(R.drawable.common_autopilot_in_autopilot);
} else if (IMoGoAutopilotStatusListener.STATUS_PARALLEL_DRIVING
== autopilotStatus){
ctvAutopilotStatusTv.setText(R.string.bus_pingxing_driver);
ctvAutopilotStatus.setClickable(false);
ctvAutopilotStatus.setBackgroundResource(R.drawable.common_autopilot_pxjs);
}
}
}
public void updateAutopilotStatus(int autopilotStatus) {
if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING
== autopilotStatus) {//2 running
ctvAutopilotStatusIv.setImageResource(R.drawable.bus_right_autopilot_icon);
ctvAutopilotStatusTv.setTextColor(ResourcesUtils.getColor(R.color.bus_autopilot_text_color_normal));
ctvAutopilotStatusTv.setText(ResourcesUtils.getString(R.string.bus_loading_autopilot_success_tv));
// ctvAutopilotStatus.setSelected(false);
ctvAutopilotStatus.setClickable(false);
} else {
ctvAutopilotStatusIv.setImageResource(R.drawable.bus_wrong_autopilot_icon);
ctvAutopilotStatusTv.setTextColor(ResourcesUtils.getColor(R.color.bus_autopilot_text_color_normal));
ctvAutopilotStatusTv.setText(ResourcesUtils.getString(R.string.bus_loading_autopilot_failure_tv));
ctvAutopilotStatus.setClickable(false);
// ctvAutopilotStatus.setSelected(false);
}
UiThreadHandler.postDelayed(new Runnable() {
@Override
public void run() {
setAutopilotBtnStatus(autopilotStatus,CallerAutoPilotControlManager.INSTANCE.isCanStartAutopilot(false, 0));
}
}, 1000);
}
private void changeAutopilotBtnView(int autopilotStatus, boolean isAnimateRunning,boolean canStartAuto) {
if (isAnimateRunning && IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING
!= autopilotStatus) {
// 主动开启自动驾驶中不为2为0、1则继续loading
return;
}
if (isAnimateRunning) {
stopAnimAndUpdateBtnStatus();
} else {
setAutopilotBtnStatus(autopilotStatus,canStartAuto);
}
}
public void stopAnimAndUpdateBtnStatus() {
stopAutopilotAnimation();
updateAutopilotStatus(CallerAutoPilotStatusListenerManager.INSTANCE.getState());
}
/**
* 隐藏【自动驾驶】按钮
*/
public void hideAutopilotBiz() {
}
/**
* 展示【自动驾驶】按钮
*/
public void showAutopilotBiz() {
}
public SlidePanelView.OnSlidePanelMoveToEndListener getSlidePanelOnEndListener() {
return null;
}
/**
* 获取站点面板view在{@link #initViews()}时候添加到container中
*
* @return 站点面板view
*/
public abstract int getStationPanelViewId();
/**
* 重新开启自动驾驶
*/
public abstract void restartAutopilot();
/**
* 模拟自动驾驶返回状态
*
* @param status
*/
public abstract void debugAutoPilotStatus(int status);
/**
* 开启自动驾驶中间动画
*/
public void startAutopilotAnimation() {
isAnimateRunning = true;
ctvAutopilotStatusTv.setText(ResourcesUtils.getString(R.string.bus_loading_autopilot_tv));
ctvAutopilotStatusTv.setTextColor(ResourcesUtils.getColor(R.color.bus_autopilot_text_color_normal));
ctvAutopilotStatus.setClickable(true);
ctvAutopilotStatusIv.setImageResource(R.drawable.bus_loading_autopilot_icon);
if (autopilotLoadingAnimator == null) {
autopilotLoadingAnimator = ObjectAnimator.ofFloat(ctvAutopilotStatusIv, "rotation", 0f, 360f);
autopilotLoadingAnimator.setInterpolator(new LinearInterpolator());
autopilotLoadingAnimator.setRepeatCount(-1);//无限循环
autopilotLoadingAnimator.setDuration(1000);//设置持续时间
}
autopilotLoadingAnimator.start();//动画开始
startingAutoApilotCountDown();
}
private void startingAutoApilotCountDown() {
//10s 若自动驾驶没有开启,则结束动画
UiThreadHandler.postDelayed(new Runnable() {
@Override
public void run() { //未启动成功做处理
if (isAnimateRunning) {// 只判断动画是否在进行,根据自动驾驶当前状态去设置自动驾驶状态
stopAutopilotAnimation();
updateAutopilotStatus(CallerAutoPilotStatusListenerManager.INSTANCE.getState());
}
}
}, TIMER_START_AUTOPILOT_INTERVAL);
}
/**
* 停止自动驾驶中间动画
*/
protected void stopAutopilotAnimation() {
if (autopilotLoadingAnimator != null) {
autopilotLoadingAnimator.end();
ctvAutopilotStatusIv.clearAnimation();
autopilotLoadingAnimator = null;
isAnimateRunning = false;
}
}
// /**
// * 迈速表实时更新
// *
// * @param newSpeed
// */
// public void updateSpeedView(float newSpeed) {
// int speed = (int) (Math.abs(newSpeed) * 3.6F); // 倒车时工控机反馈定位信息中speed为负值
// if (mTrafficDataView != null) {
// mTrafficDataView.updateSpeedWithValue(speed);
// }
// }
@Override
public void onDestroy() {
super.onDestroy();
}
/**
* bus调试面板打开关闭
*/
public void debugTestBar() {
if (groupTestPanel.getVisibility() == View.VISIBLE) {
groupTestPanel.setVisibility(View.GONE);
} else {
groupTestPanel.setVisibility(View.VISIBLE);
}
}
/**
* Bus调试信息线路、轨迹等信息
* <p>
* START
*/
private View busTestBar;
private TextView lineIdTV;
private TextView lineNameTV;
private TextView trajMd5TV;
private TextView stopMd5TV;
private TextView trajMd5DPQPTV;
private TextView stopMd5DPQPTV;
public void showHideTestBar() {
if (busTestBar == null) {
busTestBar = findViewById(R.id.module_mogo_och_bus_test_bar);
lineIdTV = findViewById(R.id.bus_test_bar_current_line_id);
lineNameTV = findViewById(R.id.bus_test_bar_current_line_name);
trajMd5TV = findViewById(R.id.bus_test_bar_current_traj_md5);
stopMd5TV = findViewById(R.id.bus_test_bar_current_stop_md5);
trajMd5DPQPTV = findViewById(R.id.bus_test_bar_current_traj_md5_dpqp);
stopMd5DPQPTV = findViewById(R.id.bus_test_bar_current_stop_md5_dpqp);
}
if (busTestBar.getVisibility() == View.VISIBLE) {
busTestBar.setVisibility(View.GONE);
} else {
BusRoutesResult routesResult = OrderModel.getInstance().getBusRoutesResult();
lineIdTV.setText("lineId:" + (routesResult == null ? "" : String.valueOf(routesResult.getLineId())));
lineNameTV.setText("lineName:" + (routesResult == null ? "" : routesResult.getName()));
trajMd5TV.setText("TMd5:" + (routesResult == null ? "" : routesResult.csvFileMd5));
stopMd5TV.setText("SMd5:" + (routesResult == null ? "" : routesResult.txtFileMd5));
trajMd5DPQPTV.setText("TMd5DPQP:" + (routesResult == null ? "" : routesResult.csvFileMd5DPQP));
stopMd5DPQPTV.setText("SMd5DPQP:" + (routesResult == null ? "" : routesResult.txtFileMd5DPQP));
busTestBar.setVisibility(View.VISIBLE);
}
}
public void updateBusTestBarInfo() {
if (busTestBar != null && busTestBar.getVisibility() == View.VISIBLE) {
BusRoutesResult routesResult = OrderModel.getInstance().getBusRoutesResult();
lineIdTV.setText("lineId:" + (routesResult == null ? "" : String.valueOf(routesResult.getLineId())));
lineNameTV.setText("lineName:" + (routesResult == null ? "" : routesResult.getName()));
trajMd5TV.setText("TMd5:" + (routesResult == null ? "" : routesResult.csvFileMd5));
stopMd5TV.setText("SMd5:" + (routesResult == null ? "" : routesResult.txtFileMd5));
trajMd5DPQPTV.setText("TMd5DPQP:" + (routesResult == null ? "" : routesResult.csvFileMd5DPQP));
stopMd5DPQPTV.setText("SMd5DPQP:" + (routesResult == null ? "" : routesResult.txtFileMd5DPQP));
}
}
/**
* END
*/
}

View File

@@ -1,554 +0,0 @@
package com.mogo.och.offline.fragment;
import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_BUS;
import static com.mogo.map.MogoMap.DEFAULT;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.Group;
import androidx.annotation.Nullable;
import com.mogo.commons.storage.SharedPrefsMgr;
import com.mogo.eagle.core.data.config.FunctionBuildConfig;
import com.mogo.eagle.core.data.temp.EventLogout;
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.map.CallerMapUIServiceManager;
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant;
import com.mogo.eagle.core.utilcode.util.ActivityUtils;
import com.mogo.eagle.core.utilcode.util.ImageUtils;
import com.mogo.eagle.core.utilcode.util.ToastUtils;
import com.mogo.eagle.core.utilcode.util.UiThreadHandler;
import com.mogo.map.overlay.IMoGoOverlayManager;
import com.mogo.map.overlay.core.Level;
import com.mogo.map.overlay.point.Point;
import com.mogo.och.common.module.utils.ResourcesUtils;
import com.mogo.och.offline.R;
import com.mogo.och.offline.presenter.BusPresenter;
import com.mogo.och.offline.ui.BusStationCommonItem;
import com.mogo.och.offline.ui.BusSwitchLineActivity;
import com.mogo.och.data.bean.BusStationBean;
import com.mogo.och.offline.constant.BusConst;
import com.mogo.och.offline.view.SlidePanelView;
import com.mogo.och.common.module.utils.BlinkAnimationUtil;
import com.mogo.och.common.module.utils.OCHThreadPoolManager;
import com.mogo.och.common.module.utils.QRUtilsKt;
import com.mogo.och.common.module.wigets.BindQRCodeDialog;
import com.mogo.och.common.module.wigets.MarqueeTextView;
import com.mogo.och.common.module.wigets.OCHCommitDialog;
import com.mogo.skin.utils.SkinResources;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.List;
import java.util.Objects;
import me.jessyan.autosize.utils.AutoSizeUtils;
/**
* 网约车小巴界面
*
* @author tongchenfei
*/
public class ShuttleFragment extends BaseShuttleTabFragment<ShuttleFragment, BusPresenter>
implements SlidePanelView.OnSlidePanelMoveToEndListener, View.OnClickListener {
public static final String TAG = "BusFragment";
private TextView mSwitchLine; //切换路线
private MarqueeTextView mLineName;
private TextView mTaskTime;
private Group groupStationsPanel;
private ConstraintLayout noDataView;
private BusStationBean startStation = null;
private BusStationBean endStation = null;
private BusStationCommonItem firstStationItem;
private BusStationCommonItem secondStationItem;
private BusStationCommonItem thirdStationItem;
@Override
public String getTagName() {
return "BusFragment";
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
@Override
public void onDestroyView() {
if (mPresenter != null) {
mPresenter.onDestroy(this);
}
super.onDestroyView();
}
@Override
protected void initViews() {
super.initViews();
mSwitchLine = findViewById(R.id.switch_line_btn);
mSwitchLine.setTag(0);
mLineName = findViewById(R.id.module_och_bus_line_name);
firstStationItem = findViewById(R.id.bus_panel_first_station);
secondStationItem = findViewById(R.id.bus_panel_second_station);
thirdStationItem = findViewById(R.id.bus_panel_third_station);
mTaskTime = findViewById(R.id.bus_task_time_tv);
groupStationsPanel = findViewById(R.id.group_stations_panel);
noDataView = findViewById(R.id.no_line_data_view);
CallerLogger.d(M_BUS + TAG, "initView: " + CallerAutoPilotStatusListenerManager.INSTANCE.getState());
// 初始化的时候设置 UI 按钮状态
showAutopilotBiz();
mSwitchLine.setOnClickListener(this);
mLineName.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
showHideTestBar();
return false;
}
});
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void changeOverview(EventLogout eventLogout){
if (eventLogout.getMessgae() == EventLogout.LOGOUT_TYPE){
CallerLogger.d(M_BUS + TAG,"changeOverview Event消息去登出");
mPresenter.logout();
}else if (eventLogout.getMessgae() == EventLogout.SHOW_QR_TYPE){ //显示二维码
CallerLogger.d(M_BUS + TAG,"changeOverview Event qrcodesn = "
+ SharedPrefsMgr.getInstance().getSn());
String qrUrl = String.format(FunctionBuildConfig.urlJson.getBindDriverQRUrl(),
SharedPrefsMgr.getInstance().getSn());
Drawable qrCenterLogoDrawable =
SkinResources.getInstance().getDrawable(R.drawable.icon_qr_center_logo);
Bitmap qrCenterLogoBitmap = ImageUtils.drawable2Bitmap(qrCenterLogoDrawable);
Bitmap bmQr = QRUtilsKt.createQRCodeWithPicture(
qrCenterLogoBitmap
,qrUrl, AutoSizeUtils.dp2px(getContext(),340f),
AutoSizeUtils.dp2px(getContext(),340f),true);
if (bmQr != null){
BindQRCodeDialog.Builder builder = new BindQRCodeDialog.Builder();
builder.title(getString(R.string.bind_driver_qr_title))
.cancelStr(getString(R.string.qr_cancel))
.qrBm(bmQr).build(getContext()).show();
}else {
CallerLogger.d(M_BUS + TAG,"bmQr = null ");
}
}
}
@Override
protected void onArriveStation() {
mPresenter.onAutopilotArriveAtStation(null);
mPresenter.arriveStation(null,"点击进站触发进站操作");
}
@Override
protected void debugArrivedStation() {
mPresenter.onAutopilotArriveAtStation(null);
mPresenter.arriveStation(null,"点击debug进站按钮触发进站操作");
}
@NonNull
@Override
protected BusPresenter createPresenter() {
return new BusPresenter(this);
}
@Override
public void onResume() {
super.onResume();
}
public void hideStationsPanel(){
groupStationsPanel.setVisibility(View.GONE);
noDataView.setVisibility(View.VISIBLE);
}
public void showStationsPanel(){
groupStationsPanel.setVisibility(View.VISIBLE);
noDataView.setVisibility(View.GONE);
}
public void updateLineEmptyUI(){
setArrivedClikable(false);
showOrHideSwitchLineBtn(true);
hideStationsPanel();
hideSlidePanel();
resetStationBlinkAnim();
}
private void resetStationBlinkAnim() {
BlinkAnimationUtil.clearAnimation(firstStationItem.getCircleImageView());
BlinkAnimationUtil.clearAnimation(secondStationItem.getCircleImageView());
BlinkAnimationUtil.clearAnimation(thirdStationItem.getCircleImageView());
}
public void updateBusTaskStatus(String lineName, String lineTime,
List<BusStationBean> stationList,
int arrivingOrArrivedIndex,
boolean isArrived){
if (getActivity() == null) {
return;
}
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if (stationList == null) {
// 获取小巴数据失败
return;
}
showStationsPanel();
showOrHideSwitchLineBtn(false);
mLineName.setText(lineName);
mTaskTime.setText(getString(R.string.bus_line_time_tag)+ lineTime);
// 渲染小巴路线数据
updateBusStationStatus(stationList,arrivingOrArrivedIndex,isArrived);
}
},UiThreadHandler.MODE.QUEUE);
}
private void updateBusStationStatus(List<BusStationBean> stationList,
int arrivingOrArrivedIndex,
boolean isArrived) {
startStation = stationList.get(0);
endStation = stationList.get(stationList.size() - 1);
if (arrivingOrArrivedIndex == stationList.size() - 1 && isArrived){
//切换路线和结束路线按钮切换
showSlidePanel("单程结束");
setOrRemoveMapMaker(false, BusConst.BUS_END_MAP_MAKER, endStation.getLat()
, endStation.getLon(),R.raw.end_marker);
}else if (arrivingOrArrivedIndex == 0 && isArrived){
showSlidePanel("滑动出发");
setOrRemoveMapMaker(true, BusConst.BUS_START_MAP_MAKER,
startStation.getLat(), startStation.getLon(),R.raw.star_marker);
setOrRemoveMapMaker(true, BusConst.BUS_END_MAP_MAKER,
endStation.getLat(), endStation.getLon(),R.raw.end_marker);
}else{
if (isArrived){
// 重置滑动按钮文字
showSlidePanel("滑动出发");
}
setOrRemoveMapMaker(false, BusConst.BUS_START_MAP_MAKER, startStation.getLat()
, startStation.getLon(),R.raw.star_marker);
setOrRemoveMapMaker(true, BusConst.BUS_END_MAP_MAKER, endStation.getLat()
, endStation.getLon(),R.raw.end_marker);
}
if (stationList.size() > 2){ //只有两个站点
updateMoreThanTwoStationsUI(stationList,arrivingOrArrivedIndex,isArrived);
}else {
updateTwoStationsUI(stationList,arrivingOrArrivedIndex,isArrived);
}
updateBusTestBarInfo();
}
/**
* 有两个以上站点的路线
* @param stationList
* @param arrivingOrArrivedIndex
* @param isArrived
*/
private void updateMoreThanTwoStationsUI(List<BusStationBean> stationList,
int arrivingOrArrivedIndex,
boolean isArrived) {
secondStationItem.setStationTag("");
secondStationItem.showOrHideStationArrowBg(true);
thirdStationItem.setStationTag("");
secondStationItem.setVisibility(View.VISIBLE);
thirdStationItem.showOrHideStationArrowBg(false);
if (arrivingOrArrivedIndex == 0 || arrivingOrArrivedIndex -1 == 0
|| (arrivingOrArrivedIndex -2 == 0 && stationList.size() == 3)){
firstStationItem.setStationTag(ResourcesUtils.getString(R.string.bus_station_txt_tag_start));
}else {
firstStationItem.setStationTag("");
}
if (arrivingOrArrivedIndex + 1 == stationList.size() - 1 || arrivingOrArrivedIndex == stationList.size() - 1
|| (arrivingOrArrivedIndex == 0 && arrivingOrArrivedIndex + 2 == stationList.size() - 1)){ //确认是否显示 "终"
thirdStationItem.setStationTag(ResourcesUtils.getString(R.string.bus_station_txt_tag_end));
}else {
thirdStationItem.setStationTag("");
}
//圆点: 0:灰色 过站 1绿色 到站或者即将到站 2蓝色未到站
if (arrivingOrArrivedIndex == 0 && isArrived){
firstStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_line_station_color_selected));
secondStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_arrived_station_name_text_color));
thirdStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_arrived_station_name_text_color));
firstStationItem.setStationName(stationList.get(0).getName());
secondStationItem.setStationName(stationList.get(1).getName());
thirdStationItem.setStationName(stationList.get(2).getName());
firstStationItem.setStationPointBg(1);
secondStationItem.setStationPointBg(2);
thirdStationItem.setStationPointBg(2);
firstStationItem.setStationArrowBg(2);
secondStationItem.setStationArrowBg(2);
}else if (arrivingOrArrivedIndex == stationList.size() - 1){
firstStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_station_tag_txt_un_color));
secondStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_station_tag_txt_un_color));
thirdStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_line_station_color_selected));
firstStationItem.setStationName(stationList.get(arrivingOrArrivedIndex -2).getName());
secondStationItem.setStationName(stationList.get(arrivingOrArrivedIndex -1).getName());
thirdStationItem.setStationName(stationList.get(arrivingOrArrivedIndex).getName());
firstStationItem.setStationPointBg(0);
secondStationItem.setStationPointBg(0);
thirdStationItem.setStationPointBg(1);
firstStationItem.setStationArrowBg(0);
if (isArrived){
secondStationItem.setStationArrowBg(0);
}else {
secondStationItem.setStationArrowBg(1);
}
}else {
firstStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_station_tag_txt_un_color));
secondStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_line_station_color_selected));
thirdStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_arrived_station_name_text_color));
firstStationItem.setStationName(stationList.get(arrivingOrArrivedIndex -1).getName());
secondStationItem.setStationName(stationList.get(arrivingOrArrivedIndex).getName());
thirdStationItem.setStationName(stationList.get(arrivingOrArrivedIndex + 1).getName());
firstStationItem.setStationPointBg(0);
secondStationItem.setStationPointBg(1);
thirdStationItem.setStationPointBg(2);
secondStationItem.setStationArrowBg(2);
if (isArrived){
firstStationItem.setStationArrowBg(0);
}else {
firstStationItem.setStationArrowBg(1);
}
}
}
/**
* 只有两个站点的路线
* @param stationList
* @param arrivingOrArrivedIndex
* @param isArrived
*/
private void updateTwoStationsUI(List<BusStationBean> stationList,
int arrivingOrArrivedIndex,
boolean isArrived) {
secondStationItem.setVisibility(View.GONE);
secondStationItem.showOrHideStationArrowBg(false);
thirdStationItem.showOrHideStationArrowBg(false);
firstStationItem.setStationTag(ResourcesUtils.getString(R.string.bus_station_txt_tag_start));
thirdStationItem.setStationTag(ResourcesUtils.getString(R.string.bus_station_txt_tag_end));
firstStationItem.setStationName(stationList.get(0).getName());
thirdStationItem.setStationName(stationList.get(1).getName());
//圆点: 0:灰色 过站 1绿色 到站或者即将到站 2蓝色未到站
if (arrivingOrArrivedIndex == 0 && isArrived){//到站
firstStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_line_station_color_selected));
thirdStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_arrived_station_name_text_color));
firstStationItem.setStationPointBg(1);
firstStationItem.setStationArrowBg(2);
thirdStationItem.setStationPointBg(0);
}else {
firstStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_station_tag_txt_un_color));
thirdStationItem.setStationNameColor(ResourcesUtils.getColor(R.color.bus_line_station_color_selected));
if (isArrived){ //到终点
firstStationItem.setStationPointBg(0);
firstStationItem.setStationArrowBg(0);
thirdStationItem.setStationPointBg(1);
}else { //到终点途中
firstStationItem.setStationPointBg(0);
firstStationItem.setStationArrowBg(1);
thirdStationItem.setStationPointBg(1);
}
}
}
private void showOrHideSwitchLineBtn(boolean isShow) {
if (isShow){//显示切换路线
mSwitchLine.setTag(0);
mSwitchLine.setText(ResourcesUtils.getString(R.string.bus_switch_line_btn));
}else {//显示结束路线
mSwitchLine.setTag(1);
mSwitchLine.setText(ResourcesUtils.getString(R.string.bus_close_line_btn));
}
}
public void hideOchBus() {
// tvNotice.setVisibility(View.GONE);
}
@Override
public int getStationPanelViewId() {
return R.layout.offline_fragment_och;
}
@Override
public void restartAutopilot() {
if (!isAnimateRunning) {
mPresenter.restartAutopilot();
}
}
@Override
public SlidePanelView.OnSlidePanelMoveToEndListener getSlidePanelOnEndListener() {
return this;
}
@Override
public void moveToEnd() {
// 开启自动驾驶到下一站
if (isAnimateRunning){
stopAutopilotAnimation();
}
mPresenter.autoDriveToNextStation();
}
/**
* 设置自动驾驶可用状态
*/
public void onAutopilotEnableChange(boolean isEnable) {
if (isEnable) {
showAutopilotBiz();
} else {
hideAutopilotBiz();
}
}
public void clearBusStationsMarkers(){
CallerLogger.d(M_BUS + TAG,"clearBusStationsMarkers()");
if (null != startStation) {
setOrRemoveMapMaker(false, BusConst.BUS_START_MAP_MAKER, startStation.getLat()
, startStation.getLon(),R.raw.star_marker);
}
if (null != endStation) {
setOrRemoveMapMaker(false, BusConst.BUS_END_MAP_MAKER, endStation.getLat()
, endStation.getLon(),R.raw.end_marker);
}
//清除鹰眼右下角小地图轨迹
CallerLogger.d(SceneConstant.M_BUS, "clearBusStationsMarkers --------->");
smallMapView.clearPolyline();
}
/**
* 绘制地图起点终点
*
* @param isAdd
* @param uuid
*/
private void setOrRemoveMapMaker(boolean isAdd, String uuid, double lat, double longi,int resourceId) {
if (isAdd) {
Runnable setMapMarkerRunnable = () -> {
CallerLogger.d(M_BUS + "setMapMaker= "+Thread.currentThread().getName(),
uuid + "=latitude=" + lat + ",longitude=" + longi);
Point.Options.Builder builder = new Point.Options.Builder(BusConst.TYPE_MARKER_BUS_ORDER, Level.MAP_MARKER)
.setId(uuid)
.anchor(0.5f, 0.5f)
.set3DMode(true)
.isUseGps(true)
.controlAngle(false)
.icon3DRes(resourceId)
.latitude(lat)
.longitude(longi);
IMoGoOverlayManager overlayManager = CallerMapUIServiceManager.INSTANCE.getOverlayManager();
if (overlayManager != null) {
overlayManager.showOrUpdatePoint(builder.build(),DEFAULT);
}
};
OCHThreadPoolManager.getsInstance().execute(setMapMarkerRunnable);
}else {
Runnable removeMapMarkerRunnable = () -> {
CallerLogger.d(M_BUS + "RemoveMapMaker="+Thread.currentThread().getName(),
uuid+"=latitude="+lat+",longitude="+longi);
Objects.requireNonNull(CallerMapUIServiceManager.INSTANCE.getOverlayManager()).removePoint(uuid);
};
OCHThreadPoolManager.getsInstance().execute(removeMapMarkerRunnable);
}
}
@Override
public void debugAutoPilotStatus(int status) {
mPresenter.debugAutoPilotStatus(status);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.switch_line_btn) {//切换路线条件: 自动驾驶过程中点击则toast提示自动驾驶中不可切换路线
//本次行程未结束不支持切换路线。点击则toast提示当前行程未完成不可切换路线
if (CallerAutoPilotStatusListenerManager.INSTANCE.getState()
== IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING) {
ToastUtils.showLong(ResourcesUtils.getString(R.string.bus_switch_line_btn_warning1));
return;
}
if ((int)mSwitchLine.getTag() == 0){//切换路线
Intent intent = new Intent(getContext(), BusSwitchLineActivity.class);
ActivityUtils.startActivity(intent);
}else {//结束任务
OCHCommitDialog.Builder builder = new OCHCommitDialog.Builder();
OCHCommitDialog closeLineConfirmDialog = builder
.title(getString(R.string.bus_dialog_title))
.tips(getString(R.string.bus_dialog_tips))
.confirmStr(getString(R.string.bus_dialog_confirm))
.cancelStr(getString(R.string.bus_dialog_cancel))
.build(getContext());
closeLineConfirmDialog.setClickListener(new OCHCommitDialog.ClickListener() {
@Override
public void confirm() {
mPresenter.abortTask();
}
@Override
public void cancel() {
closeLineConfirmDialog.dismiss();
}
});
closeLineConfirmDialog.show();
}
}
}
}

View File

@@ -1,105 +0,0 @@
package com.mogo.och.offline.model
import com.mogo.commons.storage.SharedPrefsMgr
import com.mogo.eagle.core.utilcode.util.GsonUtils
import com.mogo.och.common.module.manager.loop.BizLoopManager
import com.mogo.och.common.module.manager.loop.LoopInfo
import com.mogo.och.common.module.network.OchCommonServiceCallback
import com.mogo.och.offline.bean.BindLineListResponse
import com.mogo.och.offline.callback.IBusLinesCallback
import com.mogo.och.offline.net.OrderServiceManager
import io.reactivex.schedulers.Schedulers
/**
* @author: wangmingjun
* @date: 2022/2/9
*/
object BusLineModel {
private var mBusLinesCallback: IBusLinesCallback? = null
private const val Catche4AllLines = "Catche4AllLines"
private const val TAG = "BusLineModel"
private var lastAllLinesJson = ""
@JvmStatic
fun setBusLinesCallback(callback: IBusLinesCallback?) {
mBusLinesCallback = callback
}
@JvmStatic
fun queryBusLines() {
val catche4AllLines = SharedPrefsMgr.getInstance().getString(Catche4AllLines)
val bindLineListResponse =
GsonUtils.fromJson(catche4AllLines, BindLineListResponse::class.java)
if (bindLineListResponse != null && mBusLinesCallback != null) {
mBusLinesCallback!!.onBusLinesChange(bindLineListResponse)
}
lastAllLinesJson = catche4AllLines
OrderServiceManager.queryBindLineListBySn(object : OchCommonServiceCallback<BindLineListResponse> {
override fun onSuccess(data: BindLineListResponse) {
if (null == data && mBusLinesCallback != null) {
mBusLinesCallback?.onBusLinesChange(null)
return
}
mBusLinesCallback?.onBusLinesChange(data)
val toJson = GsonUtils.toJson(data)
if(lastAllLinesJson==toJson){
return
}else{
lastAllLinesJson = toJson
SharedPrefsMgr.getInstance().putString(Catche4AllLines, toJson)
}
}
override fun onError() {
}
override fun onFail(code: Int, failMsg: String) {
}
})
}
@JvmStatic
fun queryBusLinesByIo() {
OrderServiceManager.queryBindLineListBySn(object : OchCommonServiceCallback<BindLineListResponse> {
override fun onSuccess(data: BindLineListResponse) {
if (null == data) {
return
}
val toJson = GsonUtils.toJson(data)
if(lastAllLinesJson==toJson){
return
}else{
lastAllLinesJson = toJson
SharedPrefsMgr.getInstance().putString(Catche4AllLines, toJson)
}
}
override fun onError() {
}
override fun onFail(code: Int, failMsg: String) {
}
})
}
@JvmStatic
fun commitSwitchLineId(checkLineInfo: BindLineListResponse.Result?) {
if (mBusLinesCallback != null) {
mBusLinesCallback!!.onChangeLineIdSuccess(checkLineInfo)
}
}
@JvmStatic
fun startLoopAllLine() {
BizLoopManager.setLoopFunction(TAG, LoopInfo(60,::queryBusLinesByIo, scheduler = Schedulers.io()))
}
@JvmStatic
fun stopLoopAllLine() {
BizLoopManager.removeLoopFunction(TAG)
}
}

View File

@@ -0,0 +1,509 @@
package com.mogo.och.offline.model
import android.annotation.SuppressLint
import android.content.Context
import com.mogo.commons.AbsMogoApplication
import com.mogo.commons.storage.SharedPrefsMgr
import com.mogo.eagle.core.data.config.FunctionBuildConfig
import com.mogo.eagle.core.data.map.SiteMarkerBean
import com.mogo.eagle.core.data.och.OchInfo
import com.mogo.eagle.core.data.v2x.Point
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager
import com.mogo.eagle.core.function.call.datacenter.CallerDataCenterBizListener
import com.mogo.eagle.core.network.utils.digest.DigestUtils
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.NetworkUtils
import com.mogo.eagle.core.utilcode.util.ToastUtils
import com.mogo.och.bridge.autopilot.line.LineManager
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager
import com.mogo.och.common.module.manager.loop.BizLoopManager
import com.mogo.och.common.module.manager.socket.lan.LanSocketManager
import com.mogo.och.common.module.manager.socket.lan.bean.WriteOffResultMsg
import com.mogo.och.common.module.network.OchCommonServiceCallback
import com.mogo.och.common.module.utils.DateTimeUtil
import com.mogo.och.common.module.utils.ResourcesUtils
import com.mogo.och.common.module.utils.RxUtils
import com.mogo.och.data.bean.BusStationBean
import com.mogo.och.data.db.bean.LineDataBean
import com.mogo.och.offline.R
import com.mogo.och.offline.callback.IBusLinesCallback
import com.mogo.och.offline.model.OrderModel.isGoingToNextStation
import com.mogo.och.offline.repository.RepositoryManager
import com.mogo.och.offline.repository.db.bean.TaskDataBean
import com.mogo.och.offline.repository.db.bean.TaskSiteDataBean
import com.mogo.och.offline.repository.db.repository.SiteDb
import com.mogo.och.offline.repository.exception.DataException
import com.mogo.och.offline.repository.net.bean.BindLineListResponse
import com.mogo.och.offline.util.ShuttleVoiceManager
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicBoolean
/**
* @author: wangmingjun
* @date: 2022/2/9
*/
@SuppressLint("StaticFieldLeak")
object LineModel {
private var mContext: Context? = null
private val mBusLinesCallbackMap: MutableMap<String, IBusLinesCallback> = ConcurrentHashMap()
const val TAG = "${M_BUS}BusLineModel"
private val context = AbsMogoApplication.getApp()
// 判断接口是否变化
private const val EXECUTABLECHANGEMD5 = "EXECUTABLECHANGEMD5"
// 展示上一次刷新时间
const val EXECUTABLECHANGETIME = "executablechangetime"
var currentTask: TaskDataBean? = null
// 当前任务的站点列表
var stationList: MutableList<BusStationBean>? = mutableListOf()
private val isRequesting = AtomicBoolean(false)
private var startTaskDisposable: Disposable? = null
private var queryCarInfo: Disposable? = null
// 当前站点
@JvmStatic
var startStationIndex: Int = 0 //A->B 此处值是A站点索引
@JvmStatic
fun init() {
d(TAG, "init")
mContext = AbsMogoApplication.getApp()
queryCarExecutableTaskList(true)
}
@JvmStatic
@Synchronized
fun release() {
d(TAG, "release")
mContext = null
isRequesting.set(false)
mBusLinesCallbackMap.clear()
RxUtils.disposeSubscribe(queryCarInfo)
}
@JvmStatic
fun setBusLinesCallback(tag: String?, callback: IBusLinesCallback?) {
if (tag == null || "" == tag) return
if (callback == null) {
mBusLinesCallbackMap.remove(tag)
return
}
mBusLinesCallbackMap[tag] = callback
}
fun refreshTask() {
RxUtils.disposeSubscribe(queryCarInfo)
queryCarExecutableTaskList(false)
}
/**
* 同步基础信息
*/
private fun queryCarExecutableTaskList(isBackground: Boolean) {
if (isRequesting.get()) {
d(TAG, "正在同步请稍等")
val lastUpdateTime = SharedPrefsMgr.getInstance().getLong(EXECUTABLECHANGETIME, 0)
mBusLinesCallbackMap.forEach { callback ->
callback.value.onRefreshSuccess(lastUpdateTime)
}
return
}
isRequesting.set(true)
d(TAG, "开始同步数据")
RepositoryManager.queryCarExecutableTaskList(
object : OchCommonServiceCallback<BindLineListResponse> {
override fun onSuccess(data: BindLineListResponse) {
isRequesting.set(false)
d(TAG, "同步数据成功")
RxUtils.disposeSubscribe(queryCarInfo)
queryCarInfo = RxUtils.createSubscribe(60_000) {
queryCarExecutableTaskList(true)
}
// 第一次过滤 请求返回值的md5
val currentRequest = DigestUtils.md5Hex(data.data.toString())
val lastChangeMd5 = SharedPrefsMgr.getInstance().getString(EXECUTABLECHANGEMD5)
val lastUpdateTime =
SharedPrefsMgr.getInstance().getLong(EXECUTABLECHANGETIME, 0)
val currentTimeStamp = DateTimeUtil.getCurrentTimeStamp()
SharedPrefsMgr.getInstance().putLong(EXECUTABLECHANGETIME, currentTimeStamp)
val sameDay = DateTimeUtil.isSameDay(currentTimeStamp, lastUpdateTime)
mBusLinesCallbackMap.forEach { callback ->
callback.value.onRefreshSuccess(currentTimeStamp)
}
if (isBackground) {
if (currentRequest == lastChangeMd5 && sameDay) {
return
}
}
SharedPrefsMgr.getInstance().putString(EXECUTABLECHANGEMD5, currentRequest)
OchChainLogManager.writeChainLog(
"数据发生变化",
"接口信息发生变化 $lastChangeMd5 new md5${currentRequest}"
)
val startTime = System.currentTimeMillis()
BindLineListResponse.save2Db(data)
d(TAG, "更新数据耗时${System.currentTimeMillis() - startTime}")
RxUtils.createSubscribe(800) {
// 等待写入数据库
mBusLinesCallbackMap.forEach { callback ->
callback.value.onRefreshSuccessWIthData()
}
}
}
override fun onError() {
isRequesting.set(false)
d(TAG, "同步数据失败 onError")
RxUtils.disposeSubscribe(queryCarInfo)
queryCarInfo = RxUtils.createSubscribe(60_000) {
queryCarExecutableTaskList(true)
}
if (!isBackground) {
if (!NetworkUtils.isConnected(mContext)) {
ToastUtils.showShort(ResourcesUtils.getString(R.string.network_error_tip))
} else {
ToastUtils.showShort(ResourcesUtils.getString(R.string.request_error_tip))
}
}
}
override fun onFail(code: Int, failMsg: String) {
isRequesting.set(false)
d(TAG, "同步数据失败 onFail")
RxUtils.disposeSubscribe(queryCarInfo)
queryCarInfo = RxUtils.createSubscribe(60_000) {
queryCarExecutableTaskList(true)
}
if (!isBackground) {
if (!NetworkUtils.isConnected(mContext)) {
ToastUtils.showShort("网络异常,请稍后重试")
} else {
ToastUtils.showShort(failMsg)
}
}
}
})
}
/**
* 开始任务
*/
@JvmStatic
fun commitSwitchLineId(task: TaskDataBean, line: LineDataBean) {
RxUtils.disposeSubscribe(startTaskDisposable)
line.getLineIdAndName { lineId, lineName ->
RepositoryManager.startTask(task.taskId?:0, lineId, lineName)
?.subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread())
?.subscribe(object : Observer<Boolean> {
override fun onSubscribe(d: Disposable) {
startTaskDisposable = d
d(TAG, "commitSwitchLineId onSubscribe")
}
override fun onError(e: Throwable) {
d(TAG, "commitSwitchLineId onError${e.printStackTrace()}")
if (e is DataException) {
OchChainLogManager.writeChainLog("开始任务", "${e.message}")
ToastUtils.showShort("选择任务失败:${e.message}")
mBusLinesCallbackMap.forEach {
it.value.onChangeLineIdFail()
}
}
}
override fun onComplete() {
d(TAG, "commitSwitchLineId onComplete")
}
override fun onNext(data: Boolean) {
d(TAG, "commitSwitchLineId onNext ${data}")
if (data) {
OrderModel.queryBusRoutes()
BizLoopManager.runInIoThread {
val querySiteByLineId = SiteDb.querySiteByLineId(lineId)
querySiteByLineId?.forEach {
if (it.seq == 1) {
LanSocketManager.sendMsgToClient(
WriteOffResultMsg(
-99,
"",
"",
System.currentTimeMillis(),
LineManager.lineInfos?.lineId ?: 0,
it.siteId ?: 0L
)
)
}
return@forEach
}
}
mBusLinesCallbackMap.forEach {
it.value.onChangeLineIdSuccess()
}
}
RxUtils.disposeSubscribe(startTaskDisposable)
}
})
}
}
fun haveRunningTask() {
mBusLinesCallbackMap.forEach { callback ->
callback.value.onRunningTask()
}
}
fun haveNoRunningTask() {
mBusLinesCallbackMap.forEach { callback ->
callback.value.onNoRunningTask()
}
}
fun leaveStationSuccess() {
mBusLinesCallbackMap.forEach { map ->
map.value.onLeaveStaionSuccess()
}
}
fun arrivedStationSuccess() {
LanSocketManager.sendMsgToClient(
WriteOffResultMsg(
-99,
"",
"",
System.currentTimeMillis(),
LineManager.lineInfos?.lineId ?: 0,
LineManager.getStations()?.first?.siteId?.toLong() ?: 0L
)
)
mBusLinesCallbackMap.forEach { callback ->
callback.value.onArriveStationSuccess()
}
}
fun isLastStation(): Boolean? {
return if (stationList.isNullOrEmpty()) {
null
} else {
startStationIndex == stationList!!.size - 1
}
}
fun getTaskTime(): String {
return DateTimeUtil.formatLongToString(
currentTask?.startTime ?: System.currentTimeMillis(),
DateTimeUtil.HH_mm
)
}
fun endTask() {
currentTask?.taskId?.let { taskId ->
RepositoryManager.endTask(taskId)
?.subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread())
?.subscribe(object : Observer<Boolean> {
override fun onSubscribe(d: Disposable) {
startTaskDisposable
d(TAG, "endTask onSubscribe")
}
override fun onError(e: Throwable) {
d(TAG, "endTask onError${e.printStackTrace()}")
if (e is DataException) {
}
isGoingToNextStation = false
ThirdDeviceData.endTask()
ThirdDeviceData.sendTaskDetailsToClients()
ShuttleVoiceManager.endOrderBus()
// 取消自驾
CallerAutoPilotControlManager.cancelAutoPilot()
currentTask = null
LineManager.setLineInfo(null)
LineManager.setStartAndEndStation(null, null)
LanSocketManager.sendMsgToClient(
WriteOffResultMsg(
-99,
"",
"",
System.currentTimeMillis(),
LineManager.lineInfos?.lineId ?: 0,
LineManager.getStations()?.first?.siteId?.toLong() ?: 0L
)
)
LineModel.callEyeMap(1)
stationList = mutableListOf()
startStationIndex = 0
mBusLinesCallbackMap.forEach {
it.value.onCompleteTask()
}
val changeInfo =
"taskId:${currentTask?.taskId}--lineInfo:${LineManager.lineInfos}"
OchChainLogManager.writeChainLog("结束任务", changeInfo)
}
override fun onComplete() {
d(TAG, "endTask onComplete")
}
override fun onNext(data: Boolean) {
d(TAG, "endTask onNext ${data}")
if (data) {
isGoingToNextStation = false
ThirdDeviceData.endTask()
ThirdDeviceData.sendTaskDetailsToClients()
ShuttleVoiceManager.endOrderBus()
// 取消自驾
CallerAutoPilotControlManager.cancelAutoPilot()
currentTask = null
LineManager.setLineInfo(null)
LineManager.setStartAndEndStation(null, null)
LanSocketManager.sendMsgToClient(
WriteOffResultMsg(
-99,
"",
"",
System.currentTimeMillis(),
LineManager.lineInfos?.lineId ?: 0,
LineManager.getStations()?.first?.siteId?.toLong() ?: 0L
)
)
stationList = mutableListOf()
startStationIndex = 0
LineModel.callEyeMap(2)
mBusLinesCallbackMap.forEach {
it.value.onCompleteTask()
}
val changeInfo =
"taskId:${currentTask?.taskId}--lineInfo:${LineManager.lineInfos}"
OchChainLogManager.writeChainLog("结束任务", changeInfo)
}
onComplete()
}
})
}
}
fun startTaskMessage(): Boolean {
if (!stationList.isNullOrEmpty()) {
return startStationIndex == 0 && stationList!!.first().drivingStatus == TaskSiteDataBean.drivingStatusCurrent && !stationList!!.first().isLeaving
}
return false
}
fun setDemoMode() {
// 美化是否开始
if (FunctionBuildConfig.isDemoMode) { //行驶过程中设置美化
val (startStation, _) = LineManager.getStations()
if (startStation != null && startStation.isLeaving) {
OrderModel.startBeautificationMode()
d(TAG, "美化模式-ignore置为true每次滑动出发")
} else if (startStationIndex > 0 && startStationIndex < stationList!!.size - 1) {
//美化模式下 中间站点到站 引导线要一直绘制所以此处不出强制绘制不传false
CallerAutoPilotControlManager.setIPCDemoMode(false)
d(TAG, "美化模式-ignorefalse到达中间站")
} else {
OrderModel.closeBeautificationMode()
}
}
}
fun callEyeMap(index: Int) {
d(TAG, "执行${index} callEyeMap${stationList?.size}")
if (stationList.isNullOrEmpty()) {
val ochInfo = OchInfo(1, mutableListOf())
ochInfo.siteMarkerList = mutableListOf()
CallerDataCenterBizListener.invokeOchInfo(ochInfo)
OchChainLogManager.writeChainLogMap("地图", "站点信息:${ochInfo}")
} else {
val siteList = mutableListOf<SiteMarkerBean>()
var temp: SiteMarkerBean? = null
stationList?.let {
it.forEachIndexed { index, busStationBean ->
if (index == 0) {
temp = SiteMarkerBean(
Point(busStationBean.gcjLon, busStationBean.gcjLat),
R.drawable.offline_map_start,
0.5f,
0.87f
)
} else if (index == it.size - 1) {
temp = SiteMarkerBean(
Point(busStationBean.gcjLon, busStationBean.gcjLat),
R.drawable.offline_map_end,
0.5f,
0.87f
)
} else {
if (busStationBean.drivingStatus == 1) {
temp = SiteMarkerBean(
Point(busStationBean.gcjLon, busStationBean.gcjLat),
R.drawable.offline_map_pass,
0.5f,
0.478f
)
} else if (busStationBean.drivingStatus == 3) {
temp = SiteMarkerBean(
Point(busStationBean.gcjLon, busStationBean.gcjLat),
R.drawable.offline_map_notarrive,
0.5f,
0.478f
)
} else if (busStationBean.drivingStatus == 2) {
if (busStationBean.isLeaving) {
temp = SiteMarkerBean(
Point(
busStationBean.gcjLon,
busStationBean.gcjLat
), R.drawable.offline_map_pass, 0.5f, 0.478f
)
} else {
temp = SiteMarkerBean(
Point(
busStationBean.gcjLon,
busStationBean.gcjLat
), R.drawable.offline_map_notarrive, 0.5f, 0.478f
)
}
}
}
temp?.let { temp ->
siteList.add(temp)
}
}
}
val (start, end) = LineManager.getStations()
if (start != null && end != null) {
val ochInfo =
OchInfo(1, mutableListOf(start.toMogoLocation(), end.toMogoLocation()))
ochInfo.siteMarkerList = siteList
CallerDataCenterBizListener.invokeOchInfo(ochInfo)
OchChainLogManager.writeChainLogMap("地图", "站点信息:${ochInfo}")
}
}
}
}

View File

@@ -0,0 +1,150 @@
package com.mogo.och.offline.model
import com.mogo.commons.AbsMogoApplication
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.GsonUtils
import com.mogo.eagle.core.utilcode.util.UiThreadHandler
import com.mogo.och.common.module.biz.login.LoginStatusManager
import com.mogo.och.bridge.autopilot.line.LineManager
import com.mogo.och.common.module.manager.socket.cloud.AbnormalFactorsLoopManager
import com.mogo.och.common.module.manager.socket.cloud.OCHSocketMessageManager
import com.mogo.och.common.module.manager.socket.cloud.action.OperateAction
import com.mogo.och.common.module.manager.socket.lan.ILanMessageListener
import com.mogo.och.common.module.manager.socket.lan.LanSocketManager
import com.mogo.och.common.module.manager.socket.lan.LedScreenManager
import com.mogo.och.common.module.manager.socket.lan.bean.BusinessType
import com.mogo.och.common.module.manager.socket.lan.bean.DPMsgType
import com.mogo.och.common.module.manager.socket.lan.bean.TaskDetailsMsg
import com.mogo.och.common.module.utils.ResourcesUtils
import com.mogo.och.data.bean.BusRoutesResult
import com.mogo.och.data.bean.BusTransferData
import com.mogo.och.offline.R
import com.mogo.och.offline.constant.BusConst
import com.mogo.och.offline.util.ShuttleVoiceManager
object ThirdDeviceData {
const val TAG = M_BUS+"ThirdDeviceData"
@JvmStatic
val busRoutesResult: BusRoutesResult = BusRoutesResult()
fun init() {
//监听运营消息
OCHSocketMessageManager.registerSocketMessageListener(
OCHSocketMessageManager.msgMonitorType,
OperateAction(true)
)
// 长链接监听
AbnormalFactorsLoopManager.startLoopAbnormalFactors(AbsMogoApplication.getApp())
//监听乘客屏发来的消息
LanSocketManager.registerSocketMessageListener(
DPMsgType.TYPE_TASK_DETAILS.type,
taskDetailsMsgListener
)
}
fun release() {
OCHSocketMessageManager.releaseSocketMessageListener(OCHSocketMessageManager.msgMonitorType)
AbnormalFactorsLoopManager.stopLoopAbnormalFactors()
//监听乘客屏发来的消息
LanSocketManager.unRegisterSocketMessageListener(
DPMsgType.TYPE_TASK_DETAILS.type,
taskDetailsMsgListener
)
}
// 乘客屏请求线路信息
private val taskDetailsMsgListener = object : ILanMessageListener<TaskDetailsMsg> {
override fun targetLan(): Class<TaskDetailsMsg> = TaskDetailsMsg::class.java
override fun onLanMsgReceived(taskDetailsMsg: TaskDetailsMsg?) = sendTaskDetailsToClients()
}
private var delayedTts:Runnable?=null
// 离站
fun leaveStation() {
LineManager.getStationsWithLine { start, end, lineInfo ->
delayedTts = object :Runnable{
override fun run() {
ShuttleVoiceManager.leaveStationBus(end.name, end.nameKr)
}
}
UiThreadHandler.postDelayed(delayedTts, BusConst.DELAY_10S)
//给bus外屏发送
LedScreenManager.sendTripInfo2Led(
LedScreenManager.LEAVE_STATION,
lineInfo.lineName,
start.name,
end.name,
LineModel.isLastStation() == true
)
}
}
//到站
fun arriveStation() {
delayedTts?.let {
UiThreadHandler.removeCallbacks(delayedTts)
}
LineManager.getStationsWithLine { start, end, lineInfo ->
ShuttleVoiceManager.arrivedStationBus(end.name, end.nameKr)
// 收到正在进站的决策信息时播报每个站点仅播报1次
ShuttleVoiceManager.arrivedStationOut(ResourcesUtils.getString(R.string.m2_voice_out_arrive_station))
//给bus外屏发送
LedScreenManager.sendTripInfo2Led(
LedScreenManager.ARRIVE_STATION,
lineInfo.lineName,
start.name,
end.name,
LineModel.isLastStation() == true
)
}
}
//结束任务
fun endTask() {
delayedTts?.let {
UiThreadHandler.removeCallbacks(delayedTts)
}
LineManager.getLineInfo {lineInfo ->
LedScreenManager.sendTripInfo2Led(
LedScreenManager.END_TRIP,
lineInfo.lineName,
"",
"",
false
)
}
}
fun sendTaskDetailsToClients() {
if (LineManager.lineInfos == null || LineModel.currentTask == null || LineModel.stationList.isNullOrEmpty()) {
val data = BusTransferData(if (LoginStatusManager.isLogin()) 1 else 0, null)
val msg = TaskDetailsMsg(GsonUtils.toJson(data), BusinessType.shuttle)
d(TAG, "sendTaskDetailsToClients = " + GsonUtils.toJson(msg))
LanSocketManager.sendMsgToClient(msg)
} else {
LineManager.getLineInfo {lineInfo ->
busRoutesResult.setSite(LineModel.stationList)
busRoutesResult.lineId = lineInfo.lineId.toInt()
busRoutesResult.name = lineInfo.lineName
busRoutesResult.taskId = LineModel.currentTask!!.taskId!!.toInt()
busRoutesResult.taskTime = LineModel.currentTask!!.startTime
busRoutesResult.writeVersion = System.currentTimeMillis()
val data = BusTransferData(if (LoginStatusManager.isLogin()) 1 else 0, busRoutesResult)
val msg = TaskDetailsMsg(GsonUtils.toJson(data), BusinessType.shuttle)
d(TAG, "sendTaskDetailsToClients = " + GsonUtils.toJson(msg))
LanSocketManager.sendMsgToClient(msg)
}
}
}
}

View File

@@ -1,83 +0,0 @@
package com.mogo.och.offline.presenter;
import androidx.annotation.NonNull;
import androidx.lifecycle.LifecycleOwner;
import com.mogo.commons.mvp.Presenter;
import com.mogo.eagle.core.utilcode.util.UiThreadHandler;
import com.mogo.och.offline.bean.BindLineListResponse;
import com.mogo.och.offline.ui.BusSwitchLineView;
import com.mogo.och.offline.callback.IBusLinesCallback;
import com.mogo.och.offline.model.BusLineModel;
import com.mogo.och.offline.model.OrderModel;
/**
* @author: wangmingjun
* @date: 2022/2/9
*/
public class BusLinePresenter extends Presenter<BusSwitchLineView> implements IBusLinesCallback {
public BusLinePresenter(BusSwitchLineView view) {
super(view);
OrderModel.getInstance().init();
}
@Override
public void onCreate(@NonNull LifecycleOwner owner) {
super.onCreate(owner);
initListener();
}
private void initListener() {
BusLineModel.setBusLinesCallback(this);
}
@Override
public void onBusLinesChange(BindLineListResponse lines) {
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.onBusLinesChange(lines);
}
}
}, UiThreadHandler.MODE.QUEUE);
}
@Override
public void onChangeLineIdSuccess(BindLineListResponse.Result checkLineInfo) {
OrderModel.getInstance().pushCacheTransferData(BindLineListResponse.getCommonLineInfo(checkLineInfo));
OrderModel.getInstance().clearBusStationDatas();
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.onChangeLineIdSuccess();
}
}
}, UiThreadHandler.MODE.QUEUE);
}
public void queryBusLines(){
BusLineModel.queryBusLines();
}
public void commitSwitchLineId(BindLineListResponse.Result checkLineInfo){
BusLineModel.commitSwitchLineId(checkLineInfo);
}
public void removeListener(){
BusLineModel.setBusLinesCallback(null);
}
public void queryBusRoutes(){
OrderModel.getInstance().queryBusRoutes();
}
@Override
public void onDestroy(@NonNull LifecycleOwner owner) {
super.onDestroy(owner);
}
}

View File

@@ -1,329 +0,0 @@
package com.mogo.och.offline.presenter;
import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_BUS;
import android.os.Looper;
import androidx.annotation.NonNull;
import androidx.lifecycle.LifecycleOwner;
import com.mogo.commons.AbsMogoApplication;
import com.mogo.commons.mvp.Presenter;
import com.mogo.eagle.core.data.config.FunctionBuildConfig;
import com.mogo.eagle.core.data.map.MogoLocation;
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener;
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager;
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager;
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
import com.mogo.eagle.core.utilcode.util.UiThreadHandler;
import com.mogo.och.bridge.autopilot.OCHAdasAbilityManager;
import com.mogo.och.bridge.autopilot.autopilot.IOchAutopilotStatusListener;
import com.mogo.och.bridge.autopilot.autopilot.OchAutoPilotStatusListenerManager;
import com.mogo.och.bridge.autopilot.autopilot.bean.ArrivedStation;
import com.mogo.och.common.module.biz.login.LoginStatusEnum;
import com.mogo.och.data.bean.BusStationBean;
import com.mogo.och.offline.callback.IBusADASStatusCallback;
import com.mogo.och.offline.callback.IBusControllerStatusCallback;
import com.mogo.och.offline.callback.IRefreshBusStationsCallback;
import com.mogo.och.offline.callback.ISlidePannelHideCallback;
import com.mogo.och.offline.fragment.ShuttleFragment;
import com.mogo.och.offline.model.BusLineModel;
import com.mogo.och.offline.model.OrderModel;
import com.mogo.och.offline.util.OffLineTrajectoryManager;
import com.mogo.och.common.module.biz.login.ILoginCallback;
import com.mogo.och.common.module.biz.login.LoginStatusManager;
import java.util.ArrayList;
import java.util.List;
/**
* 网约车小巴
*
* @author tongchenfei
*/
public class BusPresenter extends Presenter<ShuttleFragment>
implements IRefreshBusStationsCallback, ISlidePannelHideCallback
, IOchAutopilotStatusListener, IBusControllerStatusCallback, ILoginCallback, IBusADASStatusCallback {
private static final String TAG = "BusPresenter";
private final List<BusStationBean> mStationList = new ArrayList<>();
private int mCurrentStation = 0;
public BusPresenter(ShuttleFragment view) {
super(view);
//2021.11.1 鹰眼架构整合由IMoGoAutopilotStatusListener逐步替代IMogoAdasOCHCallback接口
OrderModel.getInstance().init();
OCHAdasAbilityManager.getInstance().init(AbsMogoApplication.getApp());
}
@Override
public void onCreate(@NonNull LifecycleOwner owner) {
super.onCreate(owner);
initModelListener();
OrderModel.getInstance().queryBusCacheRoutes();
}
@Override
public void onDestroy(@NonNull LifecycleOwner owner) {
super.onDestroy(owner);
OrderModel.getInstance().release();
releaseListener();
}
public void initModelListener() {
OrderModel.getInstance().setRefreshBusStationsCallback(this);
OrderModel.getInstance().setSlidePanelHideCallback(this);
OrderModel.getInstance().setControllerStatusCallback(this);
OrderModel.getInstance().setAdasStatusCallback(this);
OchAutoPilotStatusListenerManager.INSTANCE.addListener(TAG,this);
LoginStatusManager.INSTANCE.addListener(TAG,this);
}
public void releaseListener() {
OrderModel.getInstance().setRefreshBusStationsCallback(null);
OrderModel.getInstance().setSlidePanelHideCallback(null);
OrderModel.getInstance().setControllerStatusCallback(null);
OrderModel.getInstance().setAdasStatusCallback(null);
OCHAdasAbilityManager.getInstance().release();
OchAutoPilotStatusListenerManager.INSTANCE.removeListener(TAG);
LoginStatusManager.INSTANCE.removeListener(TAG);
}
public void abortTask() {
OrderModel.getInstance().abortTask();
}
public void autoDriveToNextStation() {
OrderModel.getInstance().autoDriveToNextStation();
}
public void restartAutopilot() {
if (OrderModel.getInstance().isGoingToNextStation()){
OrderModel.getInstance().restartAutopilot();
}
}
// 登出
public void logout() {
OrderModel.getInstance().logout();
}
@Override
public void updateBusTaskStatus(String lineName,String lineTime,
List<BusStationBean> stationList,
int arrivingOrArrivedIndex,
boolean isArrived) {
mStationList.clear();
mStationList.addAll(stationList);
if (arrivingOrArrivedIndex == 0 || isArrived){
mCurrentStation = arrivingOrArrivedIndex;
}else {
mCurrentStation = arrivingOrArrivedIndex -1;
}
CallerLogger.d(M_BUS + "BusOrderModel =", " mCurrentStation =" + mCurrentStation);
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.updateBusTaskStatus(lineName,lineTime,
stationList, arrivingOrArrivedIndex, isArrived);
}
}
}, UiThreadHandler.MODE.QUEUE);
}
@Override
public void updateEmptyUi() {
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.updateLineEmptyUI();
}
}
}, UiThreadHandler.MODE.QUEUE);
}
@Override
public void clearBusStationsMarkers() {
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.clearBusStationsMarkers();
}
}
}, UiThreadHandler.MODE.QUEUE);
}
@Override
public void hideSlidePanel() {
if (mView != null) {
mView.hideSlidePanel();
mView.setArrivedClikable(true);
}
}
@Override
public void onAutopilotArriveAtStation(ArrivedStation arrivedStation) {
CallerLogger.e( M_BUS + TAG, "行程日志-onAutopilotArriveAtStation arrive");
arriveStation(arrivedStation,"底盘触发进站");
}
public void arriveStation(ArrivedStation arrivedStation,String type){
OrderModel.getInstance().onArriveAt(arrivedStation,type);
}
@Override
public void onAutopilotStatusResponse(int state) {
switch (state) {
case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE:
case IMoGoAutopilotStatusListener.STATUS_PARALLEL_DRIVING:
case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE:
if (FunctionBuildConfig.isDemoMode
&& (
(mCurrentStation >= 0 && mCurrentStation <= mStationList.size() - 1)
&& OrderModel.getInstance().isGoingToNextStation()
)
) {
CallerLogger.d(M_BUS + "BusOrderModel=", "有美化功能");
return;
}
// 改变UI自动驾驶状态
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.onAutopilotStatusChanged(state, CallerAutoPilotControlManager.INSTANCE.isCanStartAutopilot(false,0));
}
}
}, UiThreadHandler.MODE.QUEUE);
break;
case IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING:
OrderModel.getInstance().triggerStartServiceEvent(
OrderModel.getInstance().isRestartAutopilot(), true,0,"");
// 改变UI自动驾驶状态
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.onAutopilotStatusChanged(state, CallerAutoPilotControlManager.INSTANCE.isCanStartAutopilot(false,0));
}
}
}, UiThreadHandler.MODE.QUEUE);
break;
default:
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.onAutopilotEnableChange(false);
}
}
}, UiThreadHandler.MODE.QUEUE);
break;
}
}
@Override
public void onAutopilotStatusResponseFromCan(int state) {
if (state == IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING) {
OrderModel.getInstance().triggerStartServiceEvent(
OrderModel.getInstance().isRestartAutopilot(), true,1,"");
}
}
@Override
public void onCarLocationChanged(MogoLocation location) {
// if (null != location) {
// runOnUIThread(() -> mView.updateSpeedView(location.getGnssSpeed()));
// }
}
@Override
public void startOpenAutopilot() {
//非美化模式下启动动画
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.startAutopilotAnimation();
}
}
}, UiThreadHandler.MODE.QUEUE);
//中间站点再次开启自驾时, 自动驾驶状态是2未改变 此次鹰眼底层不再返给业务,需优化按钮动画显示
if (IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING
== CallerAutoPilotStatusListenerManager.INSTANCE.getState()&&mView!=null){
mView.onAutopilotStatusChanged(CallerAutoPilotStatusListenerManager.INSTANCE.getState(),
CallerAutoPilotControlManager.INSTANCE.isCanStartAutopilot(false,0));
}
}
private void runOnUIThread(Runnable executor) {
if (executor == null) {
return;
}
if (Looper.myLooper() != Looper.getMainLooper()) {
UiThreadHandler.post(executor);
} else {
executor.run();
}
}
/**
* 测试使用
*/
public void debugAutoPilotStatus(int status) {
onAutopilotStatusResponse(status);
}
@Override
public void onStatusChange(LoginStatusEnum currentStatus) {
CallerLogger.d(M_BUS + TAG, " loginStatus =" + LoginStatusManager.isLogin());
if(LoginStatusManager.isLogin()){
// OrderModel.getInstance().queryBusRoutes();
OrderModel.getInstance().queryBusCacheRoutes();
BusLineModel.startLoopAllLine();
}else {
BusLineModel.stopLoopAllLine();
OffLineTrajectoryManager.INSTANCE.stopTrajReqLoop();
clearBusStationsMarkers();
if(mView!=null) {
mView.hideSlidePanel();
}
OrderModel.getInstance().closeBeautificationMode();
}
}
@Override
public void onStartAdasFailure() {
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.stopAnimAndUpdateBtnStatus();
}
}
}, UiThreadHandler.MODE.QUEUE);
}
@Override
public void canStartAutopilot(boolean canStart) {
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
if(mView!=null) {
mView.onAutopilotStatusChanged(CallerAutoPilotStatusListenerManager.INSTANCE.getState(),canStart);
}
}
}, UiThreadHandler.MODE.QUEUE);
}
}

View File

@@ -0,0 +1,239 @@
package com.mogo.och.offline.repository
import com.google.gson.reflect.TypeToken
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_BUS
import com.mogo.eagle.core.utilcode.util.GsonUtils
import com.mogo.eagle.core.utilcode.util.ToastUtils
import com.mogo.och.bridge.autopilot.line.LineManager
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager
import com.mogo.och.common.module.network.OchCommonServiceCallback
import com.mogo.och.data.bean.BusStationBean
import com.mogo.och.data.bean.ContraiInfo
import com.mogo.och.data.bean.LineInfo
import com.mogo.och.data.bean.SiteIntroduce
import com.mogo.och.data.db.bean.LineDataBean
import com.mogo.och.offline.model.LineModel
import com.mogo.och.offline.model.LineModel.currentTask
import com.mogo.och.offline.repository.db.bean.TaskSiteDataBean
import com.mogo.och.offline.repository.db.repository.ContraiDb
import com.mogo.och.offline.repository.db.repository.LineDb
import com.mogo.och.offline.repository.db.repository.TaskDb
import com.mogo.och.offline.repository.db.repository.TaskSiteDb
import com.mogo.och.offline.repository.net.OrderServiceManager
import com.mogo.och.offline.repository.net.bean.BindLineListResponse
import io.reactivex.Observable
object RepositoryManager {
const val TAG = "${M_BUS}RepositoryManager"
fun queryCanUseLine(): Observable<List<LineDataBean>?>? {
return LineDb.queryCanUseLineRx()
}
fun startTask(taskId:Long,lineId:Long,lineName:String): Observable<Boolean>? {
return TaskDb.startTask(taskId, lineId, lineName)
}
fun queryCarExecutableTaskList(ochCommonServiceCallback: OchCommonServiceCallback<BindLineListResponse>) {
OrderServiceManager.queryBindLineListBySn(ochCommonServiceCallback)
}
fun endTask(taskId: Long): Observable<Boolean>? {
return Observable.just(taskId).flatMap {
currentTask?.let {task->
if (task.taskId!=null&&task.lineId!=null) {
TaskDb.endTask(task.taskId!!)
}
}
return@flatMap Observable.just(true)
}
}
fun loadCurrentTaskInfo(): Observable<Boolean>? {
return Observable.just(123)
.flatMap {
// 获取正在运行的任务
val runningTaskInfo = TaskDb.queryRunningTask()
if (runningTaskInfo.isNullOrEmpty()) {
// 本地没有进行中的任务
CallerLogger.d(TAG, "loadCurrentTaskInfo 没有查询到正在运行的任务")
return@flatMap Observable.just(false)
} else if (runningTaskInfo.size > 1) {
// 本地有多条正在进行的任务 需要check event
// 1 比对event表 1 清理错误数据 2 加载后台数据
CallerLogger.d(TAG, "loadCurrentTaskInfo 查询到多个正在执行的任务")
return@flatMap Observable.just(false)
} else {
// 只有一条进行中的任务
currentTask = runningTaskInfo.first()
// 恢复站点信息
currentTask?.taskId?.let {
// 获取正在进行中的具体信息
val runnintTaskAndSites = TaskSiteDb.queryRunningTask(it)
if(runnintTaskAndSites.isNullOrEmpty()||runnintTaskAndSites.size<2){
CallerLogger.d(TAG, "异常情况:有任务:${runningTaskInfo} runningTask 表格没有对应的数据:${runnintTaskAndSites}")
OchChainLogManager.writeChainLogDb("加载任务", "异常情况:有任务:${runningTaskInfo} runningTask 表格没有对应的数据:${runnintTaskAndSites}")
TaskSiteDb.deleteErrorData(it)
return@flatMap Observable.just(false)
}
val db2Beans = db2Beans(runnintTaskAndSites)
LineModel.stationList = db2Beans.first
LineModel.startStationIndex = db2Beans.second
LineModel.stationList?.let { stationlist->
val startStation = stationlist[LineModel.startStationIndex]
if (LineModel.startStationIndex < stationlist.size-1) {
val endStation = stationlist[LineModel.startStationIndex + 1]
LineManager.setStartAndEndStation(startStation,endStation)
LineModel.callEyeMap(8)
}
}
}
// 设置自动驾驶信息
currentTask?.lineId?.let {
ContraiDb.queryAutopilotInfoByLineid(it)?.apply {
if (lineId == null || lineId!! < 0L||csvFileUrl.isNullOrEmpty()||csvFileMd5.isNullOrEmpty()||txtFileUrl.isNullOrEmpty()||txtFileMd5.isNullOrEmpty()) {
ToastUtils.showLong("请设置轨迹信息")
OchChainLogManager.writeChainLogAutopilot("轨迹错误",this.toString())
CallerLogger.d(TAG,"轨迹错误,$this")
}
LineManager.setContraiInfo(ContraiInfo(lineId!!,csvFileUrl!!,csvFileMd5!!,txtFileUrl!!,txtFileMd5!!,contrailSaveTime!!))
}
}
return@flatMap Observable.just(true)
}
}
}
fun leaveStation(
taskId: Long
): Observable<Boolean>?{
return Observable.just(taskId)
.flatMap {
//开始站点: leaving false->true
LineManager.getStartStation {
TaskSiteDb.updateLeave(taskId, it.siteId.toLong(), true)
OchChainLogManager.writeChainLogDb(
"滑动出发",
"task:${currentTask}__taskId:${currentTask?.taskId}"
)
CallerLogger.d(TAG,"滑动出发:task:${currentTask}__taskId:${currentTask?.taskId}")
}
val (startStation, endStation) = LineManager.getStations()
val changeInfo =
"taskId:${currentTask?.taskId}--lineId:${currentTask?.lineId}--currentStationName:${startStation?.name}--finalNextStationName:${endStation?.name}"
OchChainLogManager.writeChainLog("滑动出发", changeInfo)
CallerLogger.d(TAG,"滑动出发:$changeInfo")
// 开始任务成功
return@flatMap Observable.just(true)
}
}
fun arriveStation(taskId: Long): Observable<Boolean>? {
// 开始站点leaving true->false drivingStatus 2->1
return Observable.just(taskId)
.flatMap {
LineManager.getStations { start, end ->
if (currentTask != null && currentTask!!.taskId != null) {
currentTask?.let { task ->
if (task.taskId != null && task.lineId != null) {
TaskSiteDb.updateDrivingStatusAndLeave(
task.taskId!!,
start.siteId.toLong(),
TaskSiteDataBean.drivingStatusPassed,
false
)
}
}
} else {
OchChainLogManager.writeChainLog(
"到站_数据更新_error",
"task:${currentTask}__taskId:${currentTask?.taskId}"
)
CallerLogger.d(TAG,"到站_数据更新_error:task:${currentTask}__taskId:${currentTask?.taskId}")
}
// 结束站点: drivingStatus 3-2
if (currentTask != null && currentTask!!.taskId != null) {
currentTask?.taskId?.let { taskId ->
TaskSiteDb.updateDrivingStatus(
taskId,
end.siteId.toLong(),
TaskSiteDataBean.drivingStatusCurrent
)
}
} else {
OchChainLogManager.writeChainLog(
"到站_数据更新_error",
"task:${currentTask}__taskId:${currentTask?.taskId}"
)
CallerLogger.d(TAG,"到站_数据更新_error:task:${currentTask}__taskId:${currentTask?.taskId}")
}
val changeInfo =
"taskId:${currentTask?.taskId}--lineId:${currentTask?.lineId}--currentStationName:${start.name}--finalNextStationName:${end.name}"
OchChainLogManager.writeChainLog("到站", changeInfo)
CallerLogger.d(TAG,"到站:$changeInfo")
}
return@flatMap Observable.just(true)
}
}
fun db2Beans(runnintTaskAndSites: List<TaskSiteDataBean>?): Pair<MutableList<BusStationBean>,Int> {
val result = mutableListOf<BusStationBean>()
var temp: BusStationBean? = null
var currentStationIndex = -1
var lineInfo: LineInfo?=null
if (runnintTaskAndSites.isNullOrEmpty()) {
LineManager.setLineInfo(lineInfo)
return Pair(result,currentStationIndex)
}
runnintTaskAndSites.forEachIndexed { index, taskAndsite ->
temp = BusStationBean()
temp?.drivingStatus = (taskAndsite.drivingStatus ?: 0)
temp?.lat = (taskAndsite.lat ?: 0.0)
temp?.lon = (taskAndsite.lon ?: 0.0)
temp?.gcjLat = (taskAndsite.gcjLat ?: 0.0)
temp?.gcjLon = (taskAndsite.gcjLon ?: 0.0)
temp?.introduction = taskAndsite.introduction
temp?.isLeaving = java.lang.Boolean.TRUE == taskAndsite.leaving
temp?.name = taskAndsite.name
temp?.nameKr = taskAndsite.nameKr
temp?.isPlayTts = java.lang.Boolean.TRUE == taskAndsite.isPlayTts
temp?.seq = (taskAndsite.seq ?: 0)
temp?.siteId = if (taskAndsite.siteId == null) 0 else taskAndsite.siteId!!.toInt()
if(!taskAndsite.videoList.isNullOrEmpty()){
try {
val list = GsonUtils.fromJson<List<SiteIntroduce>>(
taskAndsite.videoList,
object : TypeToken<List<SiteIntroduce?>?>() {}.type
)
temp?.videoList = list.toMutableList()
}catch (e:Exception){
temp?.videoList = null
}
}
result.add(temp!!)
// 正在进行中的任务
if (temp!!.drivingStatus == TaskSiteDataBean.drivingStatusCurrent) {
currentStationIndex = index
}
// 线路信息
if (lineInfo == null && taskAndsite.lineId != null && taskAndsite.lineName != null) {
lineInfo = LineInfo(taskAndsite.lineId!!, taskAndsite.lineName!!, orderId = taskAndsite.taskId.toString())
}
lineInfo?.multiMap?.put("taskInfo",LineModel.getTaskTime())
}
LineManager.setLineInfo(lineInfo)
return Pair(result,currentStationIndex)
}
}

View File

@@ -0,0 +1,8 @@
package com.mogo.och.offline.repository.db
interface IDbRepository {
fun register(){
MyDataBase.instance?.register(this)
}
fun release()
}

View File

@@ -0,0 +1,87 @@
package com.mogo.och.offline.repository.db
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteOpenHelper
import com.mogo.commons.AbsMogoApplication
import com.mogo.commons.env.Project
import com.mogo.commons.env.ProjectUtils
import com.mogo.eagle.core.data.config.FunctionBuildConfig
import com.mogo.och.data.db.bean.ContrailDataBean
import com.mogo.och.data.db.bean.LineDataBean
import com.mogo.och.data.db.bean.SiteDataBean
import com.mogo.och.data.db.dao.ContrailDataDao
import com.mogo.och.data.db.dao.LineDataDao
import com.mogo.och.data.db.dao.SiteDataDao
import com.mogo.och.offline.repository.db.bean.TaskSiteDataBean
import com.mogo.och.offline.repository.db.dao.TaskDataDao
import com.mogo.och.offline.repository.db.dao.TaskSiteDataDao
//注解Database告诉系统这是Room数据库对象
//entities指定该数据库有哪些表多张表就逗号分隔
//version指定数据库版本号升级时需要用到
//数据库继承自RoomDatabase
@Database(entities = [ContrailDataBean::class, LineDataBean::class, SiteDataBean::class, TaskSiteDataBean::class], version = 6)
abstract class MyDataBase : RoomDatabase() {
override fun getOpenHelper(): SupportSQLiteOpenHelper {
return super.getOpenHelper()
}
private val dbRepositorys = mutableListOf<IDbRepository>()
override fun close() {
super.close()
dbRepositorys.forEach {
it.release()
}
dbRepositorys.clear()
}
fun register(iDbRepository: IDbRepository) {
dbRepositorys.add(iDbRepository)
}
abstract val contrailDataDao: ContrailDataDao?
abstract val lineDataDao: LineDataDao?
abstract val siteDataDao: SiteDataDao?
abstract val taskDataDao: TaskDataDao?
abstract val taskSiteDataDao: TaskSiteDataDao?
companion object {
fun getDBName():MyDataBase{
val roomName = when (ProjectUtils.getProjectType()) {
Project.SAAS -> {
"saas_offline_db"
}
Project.DALI -> {
"dali_offline_db"
}
else->{
FunctionBuildConfig.appIdentityMode
}
}
val dbFile = AbsMogoApplication.getApp().getDatabasePath(roomName)
return Room.databaseBuilder(
AbsMogoApplication.getApp()!!.applicationContext,
MyDataBase::class.java,
dbFile.path
)
.fallbackToDestructiveMigration()
.build()
}
var instance: MyDataBase? = getDBName()
get() {
if(field==null){
field = getDBName()
}
return field
}
}
}

View File

@@ -0,0 +1,73 @@
package com.mogo.och.offline.repository.db.bean
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.google.gson.annotations.SerializedName
@Entity(tableName = TaskDataBean.tableName)
data class TaskDataBean(
@PrimaryKey(autoGenerate = true)
@SerializedName("idtemp")
var id: Int = 0,
/**
* 任务id
*/
@ColumnInfo(name = "task_id", typeAffinity = ColumnInfo.INTEGER, index = true)
@SerializedName("id", alternate = ["shiftsId"])
var taskId: Long? = null,
/**
* 任务所属线路
*/
@ColumnInfo(name = "line_id", typeAffinity = ColumnInfo.INTEGER, index = true)
var lineId: Long? = null,
/**
* 任务开始时间
*/
@ColumnInfo(name = "start_time", typeAffinity = ColumnInfo.INTEGER)
var startTime: Long = System.currentTimeMillis(),
/**
* 任务结束时间
*/
@ColumnInfo(name = "end_time", typeAffinity = ColumnInfo.INTEGER)
var endtime: Long? = null,
/**
* 任务状态 (0 未使用) (1 运行中) (2 已使用)
*/
@ColumnInfo(name = "status", typeAffinity = ColumnInfo.INTEGER)
var status: Long? = unUse,
) {
companion object {
const val tableName: String = "temp_task_data_table"
const val unUse = 0L //未使用
const val useing = 1L //运行中
const val used = 2L //已使用
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as TaskDataBean
if (taskId != other.taskId) return false
if (lineId != other.lineId) return false
return true
}
override fun hashCode(): Int {
var result = taskId?.hashCode() ?: 0
result = 31 * result + (lineId?.hashCode() ?: 0)
return result
}
}

View File

@@ -0,0 +1,168 @@
package com.mogo.och.offline.repository.db.bean
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.mogo.och.data.db.bean.SiteDataBean
@Entity(tableName = TaskSiteDataBean.tableName)
data class TaskSiteDataBean(
@PrimaryKey(autoGenerate = true) var id: Int = 0,
/**
* 任务id
*/
@ColumnInfo(name = "task_id", typeAffinity = ColumnInfo.INTEGER)
var taskId: Long? = null,
/**
* 线路id
*/
@ColumnInfo(name = "line_id", typeAffinity = ColumnInfo.INTEGER)
var lineId: Long? = null,
/**
* 站点id
*/
@ColumnInfo(name = "site_id", typeAffinity = ColumnInfo.INTEGER)
var siteId: Long? = null,
/**
* 线路名称 删除线路 特殊情况下要展示线路的冗余
*/
@ColumnInfo(name = "line_name", typeAffinity = ColumnInfo.TEXT)
var lineName: String? = null,
/**
* 站点名称
*/
@ColumnInfo(name = "name", typeAffinity = ColumnInfo.TEXT)
var name: String? = null,
/**
* 站点韩文
*/
@ColumnInfo(name = "name_kr", typeAffinity = ColumnInfo.TEXT)
var nameKr: String? = null,
/**
* 站点排序
*/
@ColumnInfo(name = "seq", typeAffinity = ColumnInfo.INTEGER)
var seq: Int? = null,
/**
* 高德坐标
*/
@ColumnInfo(name = "gcj_lon", typeAffinity = ColumnInfo.REAL)
var gcjLon: Double? = null,
/**
* 高德坐标
*/
@ColumnInfo(name = "gcj_lat", typeAffinity = ColumnInfo.REAL)
var gcjLat: Double? = null,
/**
* 高精坐标
*/
@ColumnInfo(name = "lon", typeAffinity = ColumnInfo.REAL)
var lon: Double? = null,
/**
* 高精坐标
*/
@ColumnInfo(name = "lat", typeAffinity = ColumnInfo.REAL)
var lat: Double? = null,
/**
* 当前站点状态 行驶信息0初始值1已经过2当前站3未到站
*/
@ColumnInfo(name = "driving_status", typeAffinity = ColumnInfo.INTEGER)
var drivingStatus: Int? = null,
/**
* 是否离站
*/
@ColumnInfo(name = "leaving", typeAffinity = ColumnInfo.INTEGER)
var leaving: Boolean? = null,
/**
* 到站时间
*/
@ColumnInfo(name = "arrived_time", typeAffinity = ColumnInfo.INTEGER)
var arrivedTime: Long? = null,
/**
* 离站时间
*/
@ColumnInfo(name = "leave_time", typeAffinity = ColumnInfo.INTEGER)
var leaveTime: Long? = null,
/**
* 站点介绍
*/
@ColumnInfo(name = "introduction", typeAffinity = ColumnInfo.TEXT)
var introduction: String? = null,
/**
* 是否播放站点介绍
*/
@ColumnInfo(name = "is_play_tts", typeAffinity = ColumnInfo.INTEGER)
var isPlayTts: Boolean? = null,
/**
* 任务保存到数据库的时间 用来第二天删除前几天的任务
*/
@ColumnInfo(name = "event_save_time", typeAffinity = ColumnInfo.INTEGER)
var eventSaveTime: Long = System.currentTimeMillis(),
/**
* 站点视频
*/
@ColumnInfo(name = "videoList", typeAffinity = ColumnInfo.TEXT)
var videoList: String? = null,
) {
companion object {
/**
* 开始任务 并把第一站置为 2 当前站
*/
fun toTaskSiteDatas(querySites: List<SiteDataBean>, lineName: String): MutableList<TaskSiteDataBean> {
val result = mutableListOf<TaskSiteDataBean>()
var temp: TaskSiteDataBean?
querySites.forEach {
temp = TaskSiteDataBean()
temp?.lineId = it.lineId
temp?.lineName = lineName
temp?.siteId = it.siteId
temp?.name = it.name
temp?.nameKr = it.nameKr
temp?.seq = it.seq
temp?.gcjLon = it.gcjLon
temp?.gcjLat = it.gcjLat
temp?.lon = it.lon
temp?.lat = it.lat
if(it.seq==1){
temp?.drivingStatus = drivingStatusCurrent
}else{
temp?.drivingStatus = drivingStatusNotArrived
}
temp?.leaving = false
temp?.introduction = it.introduction
temp?.isPlayTts = it.isPlayTts
temp?.videoList = it.videoListDB
result.add(temp!!)
}
return result
}
const val tableName: String = "used_line_data_table"
const val drivingStatusInit = 0//0初始值
const val drivingStatusPassed = 1//1已经过
const val drivingStatusCurrent = 2//2当前站
const val drivingStatusNotArrived = 3//3未到站
}
}

View File

@@ -0,0 +1,86 @@
package com.mogo.och.offline.repository.db.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.mogo.och.common.module.utils.DateTimeUtil
import com.mogo.och.offline.repository.db.bean.TaskDataBean
import io.reactivex.Observable
@Dao
interface TaskDataDao {
//插入数据
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(vararg lineDataBean: TaskDataBean)
//删除数据
@Delete
fun delete(vararg lineDataBean: TaskDataBean)
@Query("UPDATE ${TaskDataBean.tableName} SET start_time = :currentTimeMillis ,status = :useing WHERE id = :id")
fun updateStatus(currentTimeMillis: Long, useing: Long, id: Int)
//删除非昨天添加的数据
@Query("DELETE FROM ${TaskDataBean.tableName} WHERE start_time < :zeroTime")
fun deleteDataByZero(zeroTime: Long): Int
@Query("UPDATE ${TaskDataBean.tableName} SET end_time = :endTime,status = ${TaskDataBean.used} WHERE task_id = :taskId")
fun endTask(taskId: Long, endTime: Long = DateTimeUtil.getCurrentTimeStamp())
//查询当天插入的所有数据
@Query("SELECT * FROM ${TaskDataBean.tableName} WHERE start_time > :zeroTime")
fun loadAllData(zeroTime: Long): List<TaskDataBean>?
// 查询当天特定线路正在执行的任务
@Query("SELECT * FROM ${TaskDataBean.tableName} WHERE task_get_time > :zeroTime and status = ${TaskDataBean.useing} and line_id = :lineId")
fun queryRunningTaskByLineId(
lineId: Long,
zeroTime: Long = DateTimeUtil.getCurrentDateZero()
): List<TaskDataBean>?
// 查询当天特定线路正在执行的任务
@Query("SELECT * FROM ${TaskDataBean.tableName} WHERE task_get_time > :zeroTime and status = ${TaskDataBean.useing}")
fun queryRunningTaskByStatus(zeroTime: Long = DateTimeUtil.getCurrentDateZero()): List<TaskDataBean>?
@Query("SELECT * FROM ${TaskDataBean.tableName} WHERE task_get_time > :zeroTime and status = ${TaskDataBean.unUse} and line_id = :lineId order by task_start_time")
fun queryUnuseTask(
lineId: Long,
zeroTime: Long = DateTimeUtil.getCurrentDateZero()
): Observable<List<TaskDataBean>?>
@Query("DELETE FROM ${TaskDataBean.tableName} WHERE start_time > :zeroTime and line_id = :lineId")
fun deleteByLineId(lineId: Long, zeroTime: Long = DateTimeUtil.getCurrentDateZero())
@Query("SELECT * FROM ${TaskDataBean.tableName} WHERE line_id = :lineId and start_time > :zeroTime")
fun querySitesByLineId(
lineId: Long?,
zeroTime: Long = DateTimeUtil.getCurrentDateZero()
): List<TaskDataBean>?
//查询线路对应的轨迹信息
@Query("SELECT * FROM ${TaskDataBean.tableName} WHERE task_id = :taskId")
fun queryContrailByLineId(taskId: Long): List<TaskDataBean>?
//查询线路对应的轨迹信息
@Query("SELECT * FROM ${TaskDataBean.tableName}")
fun queryAllTask(): List<TaskDataBean>?
// 删除过时数据
@Query("DELETE FROM ${TaskDataBean.tableName} WHERE start_time < :zeroTime")
fun deleteObsoleteData(zeroTime: Long = DateTimeUtil.getCurrentDateZero()): Int
//查询线路对应的轨迹信息 只要一个结果
fun queryTaskByTaskIdOne(taskId: Long): TaskDataBean? {
val queryContrailByLineId = queryContrailByLineId(taskId)
return if (queryContrailByLineId.isNullOrEmpty()) {
null
} else {
queryContrailByLineId.first()
}
}
}

View File

@@ -0,0 +1,37 @@
package com.mogo.och.offline.repository.db.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.mogo.och.common.module.utils.DateTimeUtil
import com.mogo.och.offline.repository.db.bean.TaskSiteDataBean
@Dao
interface TaskSiteDataDao {
//插入数据
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(vararg lineDataBean: TaskSiteDataBean):List<Long>
//查询当天插入的所有数据
@Query("SELECT * FROM ${TaskSiteDataBean.tableName} WHERE task_id = :taskId order by seq")
fun queryRunningTask(taskId: Long): List<TaskSiteDataBean>?
@Query("UPDATE ${TaskSiteDataBean.tableName} SET leaving = :leave WHERE task_id = :taskId and site_id = :siteId")
fun updateLeave(taskId: Long, siteId: Long, leave: Int)
@Query("UPDATE ${TaskSiteDataBean.tableName} SET leaving = :leave , driving_status = :drivingStatusCurrent WHERE task_id = :taskId and site_id = :siteId")
fun updateDrivingStatusANdLeave(taskId: Long, siteId: Long, drivingStatusCurrent: Int, leave: Int)
@Query("UPDATE ${TaskSiteDataBean.tableName} SET driving_status = :drivingStatusCurrent WHERE task_id = :taskId and site_id = :siteId")
fun updateDrivingStatus(taskId: Long, siteId: Long, drivingStatusCurrent: Int)
// 删除过时数据
@Query("DELETE FROM ${TaskSiteDataBean.tableName} WHERE event_save_time < :zeroTime")
fun deleteObsoleteData(zeroTime: Long = DateTimeUtil.getCurrentDateZero()):Int
// 根据taskId删除所属站点信息
@Query("DELETE FROM ${TaskSiteDataBean.tableName} WHERE task_id = :taskId")
fun deleteErrorDataByTaskId(taskId: Long)
}

View File

@@ -0,0 +1,25 @@
package com.mogo.och.offline.repository.db.repository
import com.mogo.och.data.db.dao.ContrailDataDao
import com.mogo.och.data.db.repository.BaseContraiDb
import com.mogo.och.offline.repository.db.IDbRepository
import com.mogo.och.offline.repository.db.MyDataBase
object ContraiDb : IDbRepository, BaseContraiDb() {
override var contrailDao: ContrailDataDao?=null
get() {
if(field==null){
field = MyDataBase.instance?.contrailDataDao
register()
}
return field
}
override fun release(){
contrailDao = null
}
}

View File

@@ -0,0 +1,28 @@
package com.mogo.och.offline.repository.db.repository
import com.mogo.och.data.db.dao.LineDataDao
import com.mogo.och.data.db.repository.BaseLineDb
import com.mogo.och.offline.repository.db.IDbRepository
import com.mogo.och.offline.repository.db.MyDataBase
object LineDb: IDbRepository, BaseLineDb() {
override var lineDao: LineDataDao?=null
get() {
if(field==null){
field = MyDataBase.instance?.lineDataDao
register()
}
return field
}
override fun deleteSitesTaskAndContraiDb(lineId: Long) {
SiteDb.deleteByLineId(lineId)
}
override fun release() {
lineDao = null
}
}

View File

@@ -0,0 +1,23 @@
package com.mogo.och.offline.repository.db.repository
import com.mogo.och.data.db.dao.SiteDataDao
import com.mogo.och.data.db.repository.BaseSiteDb
import com.mogo.och.offline.repository.db.IDbRepository
import com.mogo.och.offline.repository.db.MyDataBase
object SiteDb: IDbRepository, BaseSiteDb() {
override var siteDataDao: SiteDataDao? = null
get() {
if(field==null){
field = MyDataBase.instance?.siteDataDao
register()
}
return field
}
override fun release() {
siteDataDao = null
}
}

View File

@@ -0,0 +1,194 @@
package com.mogo.och.offline.repository.db.repository
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_BUS
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager
import com.mogo.och.common.module.manager.loop.BizLoopManager
import com.mogo.och.common.module.utils.DateTimeUtil
import com.mogo.och.data.db.exception.DbException
import com.mogo.och.offline.repository.db.IDbRepository
import com.mogo.och.offline.repository.db.MyDataBase
import com.mogo.och.offline.repository.db.bean.TaskDataBean
import com.mogo.och.offline.repository.db.dao.TaskDataDao
import com.mogo.och.offline.repository.exception.DataException
import io.reactivex.Observable
object TaskDb : IDbRepository {
private const val TAG = "${M_BUS}TaskDb"
private var taskDataDao: TaskDataDao? = null
get() {
if(field==null){
field = MyDataBase.instance?.taskDataDao
register()
}
return field
}
override fun release() {
taskDataDao = null
}
fun addOrUpdate(vararg lineDataBean: TaskDataBean){
// 从接口恢复数据
taskDataDao?.insert(*lineDataBean)
}
fun addOrUpdate(serverDateList: List<TaskDataBean>, lineId: Long?) {
val runable = object :Runnable {
override fun run() {
taskDataDao?.let { taskDataDao ->
val localTasks = taskDataDao.querySitesByLineId(lineId)
if(localTasks==null){
taskDataDao.insert(*serverDateList.toTypedArray())
// TODO: Ui展示需要动态刷新UI去
return
}
// 后台新增数据
val needAddDatas = serverDateList - localTasks
// 后台没有本地数据库有的未分配线路
val needMinusDatas = localTasks - serverDateList
// TODO: Ui展示需要动态刷新UI去
if (needAddDatas.isNotEmpty()) {
// 新增任务
taskDataDao.insert(*needAddDatas.toTypedArray())
}
if (needMinusDatas.isNotEmpty()) {
val needSaveTask = mutableListOf<TaskDataBean>()
// 删除任务
needMinusDatas.forEach {
if(it.status==TaskDataBean.useing||it.status==TaskDataBean.used){
needSaveTask.add(it)
}
}
val failneedMinusDatas = needMinusDatas-needSaveTask
taskDataDao.delete(*failneedMinusDatas.toTypedArray())
}
}
}
}
BizLoopManager.runInIoThread(runable)
}
fun startTask(taskId: Long, lineId: Long,lineName:String): Observable<Boolean>? {
return Observable.just(taskId)
.flatMap {
var updateCount:Int? = 0
var startTime = System.currentTimeMillis()
try {
// 更新task状态
taskDataDao?.queryTaskByTaskIdOne(taskId)?.let {
it.startTime = System.currentTimeMillis()
it.status = TaskDataBean.useing
// 更新任务状态
taskDataDao?.updateStatus(System.currentTimeMillis(),TaskDataBean.useing,it.id)
OchChainLogManager.writeChainLogDb("开始任务", "变更线路:${lineId}_${lineName}_task:${taskId} 为正在使用的状态")
}
CallerLogger.d(TAG,"更新任务状态用时:${System.currentTimeMillis()-startTime}")
startTime = System.currentTimeMillis()
updateCount = TaskSiteDb.startTask(taskId, lineId, lineName)
OchChainLogManager.writeChainLogDb("开始任务", "把正在使用的数据更新到RunningTask表格一共${updateCount}行数据")
CallerLogger.d(TAG,"插入正在运行的线路用时:${System.currentTimeMillis()-startTime}")
} catch (e: Exception) {
if (e is DbException) {
println("数据不全")
// 恢复数据
taskDataDao?.queryTaskByTaskIdOne(taskId)?.let {
it.startTime = System.currentTimeMillis()
it.status = TaskDataBean.unUse
// 更新任务状态
taskDataDao?.updateStatus(System.currentTimeMillis(),TaskDataBean.unUse,it.id)
OchChainLogManager.writeChainLogDb("开始任务", "异常情况${lineId}_${lineName}_task:${taskId} 为未使用的状态 原因:${e.message}")
}
}
return@flatMap Observable.error(DataException(DataException.startTaskErrorCode,e.message?:""))
}
updateCount?.let {
if(it<=0){
// 插入失败
return@flatMap Observable.error(DataException(DataException.startTaskErrorCode,"未插入数据"))
}else{
// 开始任务成功
return@flatMap Observable.just(true)
}
}
}
}
fun queryRunningTaskByLineId(lineId: Long): List<TaskDataBean>? {
return taskDataDao?.queryRunningTaskByLineId(lineId)
}
fun deleteByLineId(lineId: Long) {
taskDataDao?.deleteByLineId(lineId)
}
fun queryRunningTask(): List<TaskDataBean>? {
return taskDataDao?.queryRunningTaskByStatus()
}
fun queryTaskById(taskId: Long): TaskDataBean? {
return taskDataDao?.queryTaskByTaskIdOne(taskId)
}
fun queryAllTask(): List<TaskDataBean>? {
return taskDataDao?.queryAllTask()
}
fun endTask(taskId: Long) {
BizLoopManager.runInIoThread{
taskDataDao?.endTask(taskId)
}
}
fun deleteObsoleteData(){
taskDataDao?.deleteObsoleteData()?.let {
OchChainLogManager.writeChainLogDb("删除临时数据","Task删除数量:${it}")
}
}
fun saveRunningInfo(lineId: Int, taskId: Int, taskTime: Long) {
val runningTask = taskDataDao?.queryTaskByTaskIdOne(taskId.toLong())
if (runningTask==null) {
val taskDataBean = TaskDataBean()
taskDataBean.taskId = taskId.toLong()
taskDataBean.lineId = lineId.toLong()
taskDataBean.status = TaskDataBean.useing
taskDataDao?.insert(taskDataBean)
}else{
runningTask.status = TaskDataBean.useing
taskDataDao?.insert(runningTask)
}
}
fun endTaskByOther(taskId: Long) {
BizLoopManager.runInIoThread{
val taskInfo = taskDataDao?.queryTaskByTaskIdOne(taskId)
if(taskInfo!=null){
if (taskInfo.status == TaskDataBean.unUse) {
taskDataDao?.endTask(taskId)
}
}
}
}
fun restoreTask(taskId: Long) {
// 更新task状态
taskDataDao?.queryTaskByTaskIdOne(taskId)?.let {
it.startTime = System.currentTimeMillis()
it.status = TaskDataBean.useing
// 更新任务状态
taskDataDao?.updateStatus(System.currentTimeMillis(),TaskDataBean.useing,it.id)
OchChainLogManager.writeChainLogDb("恢复任务", "线路任务改为正在执行的状态")
}
}
}

View File

@@ -0,0 +1,165 @@
package com.mogo.och.offline.repository.db.repository
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_BUS
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager
import com.mogo.och.common.module.manager.loop.BizLoopManager
import com.mogo.och.data.db.bean.LineDataBean
import com.mogo.och.data.db.exception.DbException
import com.mogo.och.offline.repository.db.IDbRepository
import com.mogo.och.offline.repository.db.MyDataBase
import com.mogo.och.offline.repository.db.bean.TaskSiteDataBean
import com.mogo.och.offline.repository.db.dao.TaskSiteDataDao
object TaskSiteDb : IDbRepository {
private const val TAG = "${M_BUS}TaskSiteDb"
private var taskSiteDataDao: TaskSiteDataDao? = null
get() {
if (field == null) {
field = MyDataBase.instance?.taskSiteDataDao
register()
}
return field
}
override fun release() {
taskSiteDataDao = null
}
fun addOrUpdate(vararg lineDataBean: TaskSiteDataBean) {
taskSiteDataDao?.insert(*lineDataBean)
}
// 开始线路
fun startTask(taskId: Long, linId: Long, lineName: String): Int? {
// 获取线路的站点
var startTime = System.currentTimeMillis()
val querySites = SiteDb.querySiteByLineId(linId)?.distinctBy { it.siteId }
if (querySites.isNullOrEmpty()) {
throw DbException("没有站点数据")
}
CallerLogger.d(TAG, "查询站点用时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis()
val toTaskSiteDatas = TaskSiteDataBean.toTaskSiteDatas(
querySites,
lineName
)
CallerLogger.d(TAG, "数据转换用时:${System.currentTimeMillis() - startTime}")
if (toTaskSiteDatas.size < 2) {
throw DbException("站点数据不全请稍后再试")
}
// 把线路所有的站点搬迁到运行中表格中
startTime = System.currentTimeMillis()
val result = taskSiteDataDao?.insert(*toTaskSiteDatas.toTypedArray())
CallerLogger.d(TAG, "数据插入用时:${System.currentTimeMillis() - startTime}")
return if (result.isNullOrEmpty()) {
null
} else {
result.size
}
}
// 滑动出发
fun updateLeave(taskId: Long, siteId: Long, leave: Boolean) {
BizLoopManager.runInIoThread {
taskSiteDataDao?.updateLeave(taskId, siteId, if (leave) 1 else 0)
}
}
fun updateDrivingStatus(taskId: Long, siteId: Long, drivingStatus: Int) {
BizLoopManager.runInIoThread {
taskSiteDataDao?.updateDrivingStatus(taskId, siteId, drivingStatus)
}
}
fun updateDrivingStatusAndLeave(
taskId: Long,
siteId: Long,
drivingStatus: Int,
leave: Boolean
) {
BizLoopManager.runInIoThread {
taskSiteDataDao?.updateDrivingStatusANdLeave(
taskId,
siteId,
drivingStatus,
if (leave) 1 else 0
)
}
}
fun queryRunningTask(taskId: Long): List<TaskSiteDataBean>? {
return taskSiteDataDao?.queryRunningTask(taskId)
}
fun deleteErrorData(taskId: Long) {
taskSiteDataDao?.deleteErrorDataByTaskId(taskId)
}
fun deleteObsoleteData() {
taskSiteDataDao?.deleteObsoleteData()?.let {
OchChainLogManager.writeChainLogDb("删除临时数据", "rurnning Task删除数量:${it}")
}
}
/**
* 从后台恢复正在执行的任务
*/
fun restoreRunningTask(
taskId: Long,
currentSiteId: Long,
leaving: Boolean,
lineInfo: LineDataBean
) {
val taskHistory = queryRunningTask(taskId)
if (!taskHistory.isNullOrEmpty()) {
//有错误数据
deleteErrorData(taskId)
}
// 获取线路的站点
val querySites = SiteDb.querySiteByLineId(lineInfo.lineId!!)?.distinctBy { it.siteId }
if (querySites.isNullOrEmpty()) {
throw DbException("没有站点数据")
}
// val toTaskSiteDatas = TaskSiteDataBean.toTaskSiteDatas(
// querySites,
// taskId,
// lineInfo.lineName!!
// )
// val resetData = resetInfo(currentSiteId, leaving, toTaskSiteDatas)
// 把线路所有的站点搬迁到运行中表格中
// taskSiteDataDao?.insert(*resetData.toTypedArray())
}
fun resetInfo(
currentSiteId: Long,
leaving: Boolean,
runningSite: MutableList<TaskSiteDataBean>
): MutableList<TaskSiteDataBean> {
var currentSeq = 0
runningSite.forEach {
if (it.siteId == currentSiteId) {
currentSeq = it.seq ?: 0
it.drivingStatus = TaskSiteDataBean.drivingStatusCurrent
it.leaving = leaving
return@forEach
}
}
runningSite.forEach {
val seq = it.seq ?: 0
if (seq < currentSeq) {
it.drivingStatus = TaskSiteDataBean.drivingStatusPassed
it.leaving = true
} else if (seq > currentSeq) {
it.drivingStatus = TaskSiteDataBean.drivingStatusNotArrived
it.leaving = false
}
}
return runningSite
}
}

View File

@@ -0,0 +1,15 @@
package com.mogo.och.offline.repository.exception
class DataException: RuntimeException {
var code:Int = 0
var msg:String = ""
constructor() : super()
constructor(code:Int, message: String) : super("${code}_${message}"){
this.code = code
this.msg = message
}
companion object{
val startTaskErrorCode = 10010
}
}

View File

@@ -1,5 +1,5 @@
package com.mogo.och.offline.net;
import com.mogo.och.offline.bean.BindLineListResponse;
package com.mogo.och.offline.repository.net;
import com.mogo.och.offline.repository.net.bean.BindLineListResponse;
import io.reactivex.Observable;
import retrofit2.http.GET;

View File

@@ -1,4 +1,4 @@
package com.mogo.och.offline.net
package com.mogo.och.offline.repository.net
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
import com.mogo.commons.AbsMogoApplication
@@ -9,7 +9,7 @@ import com.mogo.och.common.module.constant.OchCommonConst
import com.mogo.och.common.module.network.OchCommonServiceCallback
import com.mogo.och.common.module.network.OchCommonSubscribeImpl
import com.mogo.och.common.module.network.interceptor.transformIoTry
import com.mogo.och.offline.bean.BindLineListResponse
import com.mogo.och.offline.repository.net.bean.BindLineListResponse
/**
* @author: wangmingjun

View File

@@ -0,0 +1,37 @@
package com.mogo.och.offline.repository.net.bean
import com.mogo.eagle.core.data.BaseData
import com.mogo.och.data.bean.BusRoutesResult
import com.mogo.och.data.bean.BusStationBean
import java.util.*
/**
*
*/
data class BindLineListResponse(val data: List<Result>?) : BaseData(){
data class Result(
var line: LineInfo?,
var siteList: List<BusStationBean>?,//站点名称
val contrail: Contrail?,//站点名称
)
data class LineInfo(
val lineId:Long?,
var lineName:String?,
)
data class Contrail(
val csvFileUrl:String?,
val csvFileMd5:String?,
val txtFileUrl:String?,
val txtFileMd5:String?,
val contrailSaveTime:Long?,
)
companion object{
fun save2Db(data: BindLineListResponse) {
}
}
}

View File

@@ -1,99 +0,0 @@
package com.mogo.och.offline.ui
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.core.content.ContextCompat
import com.mogo.och.common.module.utils.BlinkAnimationUtil
import com.mogo.och.offline.R
import kotlinx.android.synthetic.main.offline_stations_common_item.view.*
/**
* @author: wangmingjun
* @date: 2022/9/15
*/
class BusStationCommonItem @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr){
init {
LayoutInflater.from(context).inflate(R.layout.offline_stations_common_item,this,true)
}
fun setStationName(name: String){
busStationNameTv.text = name
}
fun setStationNameColor(color: Int){
busStationNameTv.setTextColor(color)
}
fun setStationPointBg(type: Int) { // 0:灰色 过站 1绿色 到站或者即将到站 2蓝色未到站
BlinkAnimationUtil.clearAnimation(busCircleIv)
when (type) {
0 -> {
busCircleIvBg.visibility = GONE
busCircleIv.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_point_grey_bus
)
)
}
1 -> {
busCircleIvBg.visibility = VISIBLE
busCircleIv.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_point_green_bus
)
)
BlinkAnimationUtil.setAnimation(busCircleIv)
}
2 -> {
busCircleIvBg.visibility = GONE
busCircleIv.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_point_blue_bus
)
)
}
}
}
fun getCircleImageView() : ImageView{
return busCircleIv
}
fun setStationArrowBg(type: Int){// 0:灰色 过站 1绿色 前往下一站 2蓝色 未到站
when(type){
0 -> busArrowBg.setImageResource(R.drawable.icon_arrow_grey_bus)
1 -> busArrowBg.setImageResource(R.drawable.icon_arrow_green_bus)
2 -> busArrowBg.setImageResource(R.drawable.icon_arrow_blue_bus)
}
}
fun setStationTag(tag: String){ // 0起 1
if (tag.isNullOrEmpty()){
busTagTxt.visibility = GONE
}else{
busTagTxt.text = tag
busTagTxt.visibility = VISIBLE
}
}
fun showOrHideStationArrowBg(isShow:Boolean){
if (isShow){
busArrowBg.visibility = VISIBLE
}else{
busArrowBg.visibility = GONE
}
}
}

View File

@@ -1,181 +0,0 @@
package com.mogo.och.offline.ui
import android.graphics.Point
import android.os.Bundle
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.mogo.commons.mvp.MvpActivity
import com.mogo.commons.storage.SharedPrefsMgr
import com.mogo.och.offline.presenter.BusLinePresenter
import com.mogo.och.offline.ui.adapter.SwitchLineAdapter
import com.mogo.och.offline.ui.adapter.OpenItemAnimator
import com.mogo.eagle.core.utilcode.mogo.view.SpacesItemDecoration
import com.mogo.eagle.core.utilcode.util.ToastUtils
import com.mogo.och.offline.R
import com.mogo.och.offline.bean.BindLineListResponse
import java.util.ArrayList
/**
* @author: wangmingjun
* @date: 2022/2/8
*/
class BusSwitchLineActivity : MvpActivity<BusSwitchLineView?, BusLinePresenter?>(),
View.OnClickListener, BusSwitchLineView {
companion object{
const val LASTCOMMITLINEID = "lastcommitlineid"
}
private lateinit var mClose: ImageView
private lateinit var mNoDatasView: ConstraintLayout
private lateinit var mLinesListView: RecyclerView
private lateinit var mLineCommitBtn: TextView
private lateinit var mAdapter: SwitchLineAdapter
private lateinit var linearLayoutManager:LinearLayoutManager
private val mData: MutableList<BindLineListResponse.Result> = ArrayList()
private var checkLineInfo:BindLineListResponse.Result? = null
override fun getLayoutId(): Int {
return R.layout.offline_switch_line
}
override fun createPresenter(): BusLinePresenter {
return BusLinePresenter(this)
}
override fun initViews() {
initWH()
initView()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onResume() {
super.onResume()
initDatas()
}
/**
* 初始化view
*/
private fun initView() {
mClose = findViewById(R.id.switch_line_close)
mClose.setOnClickListener(this)
mNoDatasView = findViewById(R.id.no_order_data_view)
mLineCommitBtn = findViewById(R.id.switch_line_btn_commit)
mLineCommitBtn.setOnClickListener(this)
mLinesListView = findViewById(R.id.switch_line_rv)
linearLayoutManager = LinearLayoutManager(this)
mLinesListView.setLayoutManager(linearLayoutManager)
mLinesListView.setItemAnimator(OpenItemAnimator())
mAdapter = SwitchLineAdapter(applicationContext, mData)
mLinesListView.addItemDecoration(
SpacesItemDecoration(
4
)
)
mLinesListView.setAdapter(mAdapter)
//设置item 点击事件
mAdapter.setOnLineItemClickListener(object : SwitchLineAdapter.LineItemClickListener{
override fun onItemClick(lineInfo: BindLineListResponse.Result) {
// 选中的线路
checkLineInfo = lineInfo
}
})
}
/**
* 设置布局宽高
*/
private fun initWH() {
val window = window
val params = window.attributes
val windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
val point = Point()
windowManager.defaultDisplay.getSize(point) //用于获取屏幕高度
params.width = (point.x * 0.375).toInt()
params.height = ViewGroup.LayoutParams.MATCH_PARENT
window.attributes = params
window.setGravity(Gravity.START or Gravity.BOTTOM)
}
/**
* 初始化数据
*/
private fun initDatas() {
mPresenter?.queryBusLines()
}
/**
* 查询返回绑定路线集合
* @param data
*/
override fun onBusLinesChange(data: BindLineListResponse?) {
if (null == data) {
showNoData(true)
return
}
if (data.data != null && data.data.size > 0) {
showNoData(false)
mData.clear()
mData.addAll(data.data)
mAdapter.notifyDataSetChanged()
} else {
showNoData(true)
}
}
override fun onChangeLineIdSuccess() {
ToastUtils.showLong(resources.getString(R.string.bus_change_line_commit_tip_s))
mPresenter?.queryBusRoutes()
mAdapter.setOnLineItemClickListener(null)
mPresenter?.removeListener()
finish()
}
/**
* 有无数据UI显示
* @param b
*/
private fun showNoData(b: Boolean) {
if (b) {
mLinesListView.visibility = View.GONE
mLineCommitBtn.visibility = View.GONE
mNoDatasView.visibility = View.VISIBLE
} else {
mLinesListView.visibility = View.VISIBLE
mLineCommitBtn.visibility = View.VISIBLE
mNoDatasView.visibility = View.GONE
}
}
override fun onClick(v: View) {
//关闭dialog
if (v.id == R.id.switch_line_close) {
finish()
return
}
//切换路线提交
if (v.id == R.id.switch_line_btn_commit) {
if (checkLineInfo==null) {
ToastUtils.showLong("请选择任务")
}else{
mPresenter?.commitSwitchLineId(checkLineInfo)
}
}
}
override fun onDestroy() {
mPresenter!!.removeListener()
super.onDestroy()
}
}

View File

@@ -1,16 +0,0 @@
package com.mogo.och.offline.ui;
import com.mogo.commons.mvp.IView;
import com.mogo.och.offline.bean.BindLineListResponse;
/**
* @author: wangmingjun
* @date: 2022/2/10
*/
public interface BusSwitchLineView extends IView {
void onBusLinesChange(BindLineListResponse data);
void onChangeLineIdSuccess();
}

View File

@@ -1,643 +0,0 @@
package com.mogo.och.offline.ui.adapter;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.view.View;
import android.view.ViewPropertyAnimator;
import androidx.annotation.NonNull;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.SimpleItemAnimator;
import java.util.ArrayList;
import java.util.List;
/**
* This implementation of {@link RecyclerView.ItemAnimator} provides basic
* animations on remove, add, and move events that happen to the items in
* a RecyclerView. RecyclerView uses a DefaultItemAnimator by default.
*
* @see RecyclerView#setItemAnimator(RecyclerView.ItemAnimator)
*/
public class OpenItemAnimator extends DefaultItemAnimator {
private static final boolean DEBUG = false;
private static TimeInterpolator sDefaultInterpolator;
private final ArrayList<RecyclerView.ViewHolder> mPendingRemovals = new ArrayList<>();
private final ArrayList<RecyclerView.ViewHolder> mPendingAdditions = new ArrayList<>();
private final ArrayList<MoveInfo> mPendingMoves = new ArrayList<>();
private final ArrayList<ChangeInfo> mPendingChanges = new ArrayList<>();
ArrayList<ArrayList<RecyclerView.ViewHolder>> mAdditionsList = new ArrayList<>();
ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<>();
ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<>();
ArrayList<RecyclerView.ViewHolder> mAddAnimations = new ArrayList<>();
ArrayList<RecyclerView.ViewHolder> mMoveAnimations = new ArrayList<>();
ArrayList<RecyclerView.ViewHolder> mRemoveAnimations = new ArrayList<>();
ArrayList<RecyclerView.ViewHolder> mChangeAnimations = new ArrayList<>();
private static class MoveInfo {
public RecyclerView.ViewHolder holder;
public int fromX, fromY, toX, toY;
MoveInfo(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
this.holder = holder;
this.fromX = fromX;
this.fromY = fromY;
this.toX = toX;
this.toY = toY;
}
}
private static class ChangeInfo {
public RecyclerView.ViewHolder oldHolder, newHolder;
public int fromX, fromY, toX, toY;
private ChangeInfo(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder) {
this.oldHolder = oldHolder;
this.newHolder = newHolder;
}
ChangeInfo(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder,
int fromX, int fromY, int toX, int toY) {
this(oldHolder, newHolder);
this.fromX = fromX;
this.fromY = fromY;
this.toX = toX;
this.toY = toY;
}
@Override
public String toString() {
return "ChangeInfo{"
+ "oldHolder=" + oldHolder
+ ", newHolder=" + newHolder
+ ", fromX=" + fromX
+ ", fromY=" + fromY
+ ", toX=" + toX
+ ", toY=" + toY
+ '}';
}
}
@Override
public void runPendingAnimations() {
boolean removalsPending = !mPendingRemovals.isEmpty();
boolean movesPending = !mPendingMoves.isEmpty();
boolean changesPending = !mPendingChanges.isEmpty();
boolean additionsPending = !mPendingAdditions.isEmpty();
if (!removalsPending && !movesPending && !additionsPending && !changesPending) {
// nothing to animate
return;
}
// First, remove stuff
for (RecyclerView.ViewHolder holder : mPendingRemovals) {
animateRemoveImpl(holder);
}
mPendingRemovals.clear();
// Next, move stuff
if (movesPending) {
final ArrayList<MoveInfo> moves = new ArrayList<>(mPendingMoves);
mMovesList.add(moves);
mPendingMoves.clear();
Runnable mover = () -> {
for (MoveInfo moveInfo : moves) {
animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY,
moveInfo.toX, moveInfo.toY);
}
moves.clear();
mMovesList.remove(moves);
};
if (removalsPending) {
View view = moves.get(0).holder.itemView;
ViewCompat.postOnAnimationDelayed(view, mover, getRemoveDuration());
} else {
mover.run();
}
}
// Next, change stuff, to run in parallel with move animations
if (changesPending) {
final ArrayList<ChangeInfo> changes = new ArrayList<>(mPendingChanges);
mChangesList.add(changes);
mPendingChanges.clear();
Runnable changer = () -> {
for (ChangeInfo change : changes) {
animateChangeImpl(change);
}
changes.clear();
mChangesList.remove(changes);
};
if (removalsPending) {
RecyclerView.ViewHolder holder = changes.get(0).oldHolder;
ViewCompat.postOnAnimationDelayed(holder.itemView, changer, getRemoveDuration());
} else {
changer.run();
}
}
// Next, add stuff
if (additionsPending) {
final ArrayList<RecyclerView.ViewHolder> additions = new ArrayList<>(mPendingAdditions);
mAdditionsList.add(additions);
mPendingAdditions.clear();
Runnable adder = () -> {
for (RecyclerView.ViewHolder holder : additions) {
animateAddImpl(holder);
}
additions.clear();
mAdditionsList.remove(additions);
};
if (removalsPending || movesPending || changesPending) {
long removeDuration = removalsPending ? getRemoveDuration() : 0;
long moveDuration = movesPending ? getMoveDuration() : 0;
long changeDuration = changesPending ? getChangeDuration() : 0;
long totalDelay = removeDuration + Math.max(moveDuration, changeDuration);
View view = additions.get(0).itemView;
ViewCompat.postOnAnimationDelayed(view, adder, totalDelay);
} else {
adder.run();
}
}
}
@Override
public boolean animateRemove(final RecyclerView.ViewHolder holder) {
resetAnimation(holder);
mPendingRemovals.add(holder);
return true;
}
private void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
final View view = holder.itemView;
final ViewPropertyAnimator animation = view.animate();
mRemoveAnimations.add(holder);
animation.setDuration(getRemoveDuration()).alpha(0).setListener(
new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animator) {
dispatchRemoveStarting(holder);
}
@Override
public void onAnimationEnd(Animator animator) {
animation.setListener(null);
view.setAlpha(1);
dispatchRemoveFinished(holder);
mRemoveAnimations.remove(holder);
dispatchFinishedWhenDone();
}
}).start();
}
@Override
public boolean animateAdd(final RecyclerView.ViewHolder holder) {
resetAnimation(holder);
holder.itemView.setAlpha(0);
mPendingAdditions.add(holder);
return true;
}
void animateAddImpl(final RecyclerView.ViewHolder holder) {
final View view = holder.itemView;
final ViewPropertyAnimator animation = view.animate();
mAddAnimations.add(holder);
animation.alpha(1).setDuration(getAddDuration())
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animator) {
dispatchAddStarting(holder);
}
@Override
public void onAnimationCancel(Animator animator) {
view.setAlpha(1);
}
@Override
public void onAnimationEnd(Animator animator) {
animation.setListener(null);
dispatchAddFinished(holder);
mAddAnimations.remove(holder);
dispatchFinishedWhenDone();
}
}).start();
}
@Override
public boolean animateMove(final RecyclerView.ViewHolder holder, int fromX, int fromY,
int toX, int toY) {
final View view = holder.itemView;
fromX += (int) holder.itemView.getTranslationX();
fromY += (int) holder.itemView.getTranslationY();
resetAnimation(holder);
int deltaX = toX - fromX;
int deltaY = toY - fromY;
if (deltaX == 0 && deltaY == 0) {
dispatchMoveFinished(holder);
return false;
}
if (deltaX != 0) {
view.setTranslationX(-deltaX);
}
if (deltaY != 0) {
view.setTranslationY(-deltaY);
}
mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY));
return true;
}
void animateMoveImpl(final RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
final View view = holder.itemView;
final int deltaX = toX - fromX;
final int deltaY = toY - fromY;
if (deltaX != 0) {
view.animate().translationX(0);
}
if (deltaY != 0) {
view.animate().translationY(0);
}
// TODO: make EndActions end listeners instead, since end actions aren't called when
// vpas are canceled (and can't end them. why?)
// need listener functionality in VPACompat for this. Ick.
final ViewPropertyAnimator animation = view.animate();
mMoveAnimations.add(holder);
animation.setDuration(getMoveDuration()).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animator) {
dispatchMoveStarting(holder);
}
@Override
public void onAnimationCancel(Animator animator) {
if (deltaX != 0) {
view.setTranslationX(0);
}
if (deltaY != 0) {
view.setTranslationY(0);
}
}
@Override
public void onAnimationEnd(Animator animator) {
animation.setListener(null);
dispatchMoveFinished(holder);
mMoveAnimations.remove(holder);
dispatchFinishedWhenDone();
}
}).start();
}
@Override
public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder,
int fromX, int fromY, int toX, int toY) {
if (oldHolder == newHolder) {
// Don't know how to run change animations when the same view holder is re-used.
// run a move animation to handle position changes.
return animateMove(oldHolder, fromX, fromY, toX, toY);
}
final float prevTranslationX = oldHolder.itemView.getTranslationX();
final float prevTranslationY = oldHolder.itemView.getTranslationY();
final float prevAlpha = oldHolder.itemView.getAlpha();
resetAnimation(oldHolder);
int deltaX = (int) (toX - fromX - prevTranslationX);
int deltaY = (int) (toY - fromY - prevTranslationY);
// recover prev translation state after ending animation
oldHolder.itemView.setTranslationX(prevTranslationX);
oldHolder.itemView.setTranslationY(prevTranslationY);
oldHolder.itemView.setAlpha(prevAlpha);
if (newHolder != null) {
// carry over translation values
resetAnimation(newHolder);
newHolder.itemView.setTranslationX(-deltaX);
newHolder.itemView.setTranslationY(-deltaY);
newHolder.itemView.setAlpha(0);
}
mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
return true;
}
void animateChangeImpl(final ChangeInfo changeInfo) {
final RecyclerView.ViewHolder holder = changeInfo.oldHolder;
final View view = holder == null ? null : holder.itemView;
final RecyclerView.ViewHolder newHolder = changeInfo.newHolder;
final View newView = newHolder != null ? newHolder.itemView : null;
if (view != null) {
final ViewPropertyAnimator oldViewAnim = view.animate().setDuration(
getChangeDuration());
mChangeAnimations.add(changeInfo.oldHolder);
oldViewAnim.translationX((float)(changeInfo.toX - changeInfo.fromX));
oldViewAnim.translationY((float)(changeInfo.toY - changeInfo.fromY));
oldViewAnim.alpha(0).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animator) {
dispatchChangeStarting(changeInfo.oldHolder, true);
}
@Override
public void onAnimationEnd(Animator animator) {
oldViewAnim.setListener(null);
view.setAlpha(1);
view.setTranslationX(0);
view.setTranslationY(0);
dispatchChangeFinished(changeInfo.oldHolder, true);
mChangeAnimations.remove(changeInfo.oldHolder);
dispatchFinishedWhenDone();
}
}).start();
}
if (newView != null) {
final ViewPropertyAnimator newViewAnimation = newView.animate();
mChangeAnimations.add(changeInfo.newHolder);
newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration())
.alpha(1).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animator) {
dispatchChangeStarting(changeInfo.newHolder, false);
}
@Override
public void onAnimationEnd(Animator animator) {
newViewAnimation.setListener(null);
newView.setAlpha(1);
newView.setTranslationX(0);
newView.setTranslationY(0);
dispatchChangeFinished(changeInfo.newHolder, false);
mChangeAnimations.remove(changeInfo.newHolder);
dispatchFinishedWhenDone();
}
}).start();
}
}
private void endChangeAnimation(List<ChangeInfo> infoList, RecyclerView.ViewHolder item) {
for (int i = infoList.size() - 1; i >= 0; i--) {
ChangeInfo changeInfo = infoList.get(i);
if (endChangeAnimationIfNecessary(changeInfo, item)) {
if (changeInfo.oldHolder == null && changeInfo.newHolder == null) {
infoList.remove(changeInfo);
}
}
}
}
private void endChangeAnimationIfNecessary(ChangeInfo changeInfo) {
if (changeInfo.oldHolder != null) {
endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder);
}
if (changeInfo.newHolder != null) {
endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder);
}
}
private boolean endChangeAnimationIfNecessary(ChangeInfo changeInfo, RecyclerView.ViewHolder item) {
boolean oldItem = false;
if (changeInfo.newHolder == item) {
changeInfo.newHolder = null;
} else if (changeInfo.oldHolder == item) {
changeInfo.oldHolder = null;
oldItem = true;
} else {
return false;
}
item.itemView.setAlpha(1);
item.itemView.setTranslationX(0);
item.itemView.setTranslationY(0);
dispatchChangeFinished(item, oldItem);
return true;
}
@Override
public void endAnimation(RecyclerView.ViewHolder item) {
final View view = item.itemView;
// this will trigger end callback which should set properties to their target values.
view.animate().cancel();
// TODO if some other animations are chained to end, how do we cancel them as well?
for (int i = mPendingMoves.size() - 1; i >= 0; i--) {
MoveInfo moveInfo = mPendingMoves.get(i);
if (moveInfo.holder == item) {
view.setTranslationY(0);
view.setTranslationX(0);
dispatchMoveFinished(item);
mPendingMoves.remove(i);
}
}
endChangeAnimation(mPendingChanges, item);
if (mPendingRemovals.remove(item)) {
view.setAlpha(1);
dispatchRemoveFinished(item);
}
if (mPendingAdditions.remove(item)) {
view.setAlpha(1);
dispatchAddFinished(item);
}
for (int i = mChangesList.size() - 1; i >= 0; i--) {
ArrayList<ChangeInfo> changes = mChangesList.get(i);
endChangeAnimation(changes, item);
if (changes.isEmpty()) {
mChangesList.remove(i);
}
}
for (int i = mMovesList.size() - 1; i >= 0; i--) {
ArrayList<MoveInfo> moves = mMovesList.get(i);
for (int j = moves.size() - 1; j >= 0; j--) {
MoveInfo moveInfo = moves.get(j);
if (moveInfo.holder == item) {
view.setTranslationY(0);
view.setTranslationX(0);
dispatchMoveFinished(item);
moves.remove(j);
if (moves.isEmpty()) {
mMovesList.remove(i);
}
break;
}
}
}
for (int i = mAdditionsList.size() - 1; i >= 0; i--) {
ArrayList<RecyclerView.ViewHolder> additions = mAdditionsList.get(i);
if (additions.remove(item)) {
view.setAlpha(1);
dispatchAddFinished(item);
if (additions.isEmpty()) {
mAdditionsList.remove(i);
}
}
}
// animations should be ended by the cancel above.
//noinspection PointlessBooleanExpression,ConstantConditions
if (mRemoveAnimations.remove(item) && DEBUG) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mRemoveAnimations list");
}
//noinspection PointlessBooleanExpression,ConstantConditions
if (mAddAnimations.remove(item) && DEBUG) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mAddAnimations list");
}
//noinspection PointlessBooleanExpression,ConstantConditions
if (mChangeAnimations.remove(item) && DEBUG) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mChangeAnimations list");
}
//noinspection PointlessBooleanExpression,ConstantConditions
if (mMoveAnimations.remove(item) && DEBUG) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mMoveAnimations list");
}
dispatchFinishedWhenDone();
}
private void resetAnimation(RecyclerView.ViewHolder holder) {
if (sDefaultInterpolator == null) {
sDefaultInterpolator = new ValueAnimator().getInterpolator();
}
holder.itemView.animate().setInterpolator(sDefaultInterpolator);
endAnimation(holder);
}
@Override
public boolean isRunning() {
return (!mPendingAdditions.isEmpty()
|| !mPendingChanges.isEmpty()
|| !mPendingMoves.isEmpty()
|| !mPendingRemovals.isEmpty()
|| !mMoveAnimations.isEmpty()
|| !mRemoveAnimations.isEmpty()
|| !mAddAnimations.isEmpty()
|| !mChangeAnimations.isEmpty()
|| !mMovesList.isEmpty()
|| !mAdditionsList.isEmpty()
|| !mChangesList.isEmpty());
}
/**
* Check the state of currently pending and running animations. If there are none
* pending/running, call {@link #dispatchAnimationsFinished()} to notify any
* listeners.
*/
void dispatchFinishedWhenDone() {
if (!isRunning()) {
dispatchAnimationsFinished();
}
}
@Override
public void endAnimations() {
int count = mPendingMoves.size();
for (int i = count - 1; i >= 0; i--) {
MoveInfo item = mPendingMoves.get(i);
View view = item.holder.itemView;
view.setTranslationY(0);
view.setTranslationX(0);
dispatchMoveFinished(item.holder);
mPendingMoves.remove(i);
}
count = mPendingRemovals.size();
for (int i = count - 1; i >= 0; i--) {
RecyclerView.ViewHolder item = mPendingRemovals.get(i);
dispatchRemoveFinished(item);
mPendingRemovals.remove(i);
}
count = mPendingAdditions.size();
for (int i = count - 1; i >= 0; i--) {
RecyclerView.ViewHolder item = mPendingAdditions.get(i);
item.itemView.setAlpha(1);
dispatchAddFinished(item);
mPendingAdditions.remove(i);
}
count = mPendingChanges.size();
for (int i = count - 1; i >= 0; i--) {
endChangeAnimationIfNecessary(mPendingChanges.get(i));
}
mPendingChanges.clear();
if (!isRunning()) {
return;
}
int listCount = mMovesList.size();
for (int i = listCount - 1; i >= 0; i--) {
ArrayList<MoveInfo> moves = mMovesList.get(i);
count = moves.size();
for (int j = count - 1; j >= 0; j--) {
MoveInfo moveInfo = moves.get(j);
RecyclerView.ViewHolder item = moveInfo.holder;
View view = item.itemView;
view.setTranslationY(0);
view.setTranslationX(0);
dispatchMoveFinished(moveInfo.holder);
moves.remove(j);
if (moves.isEmpty()) {
mMovesList.remove(moves);
}
}
}
listCount = mAdditionsList.size();
for (int i = listCount - 1; i >= 0; i--) {
ArrayList<RecyclerView.ViewHolder> additions = mAdditionsList.get(i);
count = additions.size();
for (int j = count - 1; j >= 0; j--) {
RecyclerView.ViewHolder item = additions.get(j);
View view = item.itemView;
view.setAlpha(1);
dispatchAddFinished(item);
additions.remove(j);
if (additions.isEmpty()) {
mAdditionsList.remove(additions);
}
}
}
listCount = mChangesList.size();
for (int i = listCount - 1; i >= 0; i--) {
ArrayList<ChangeInfo> changes = mChangesList.get(i);
count = changes.size();
for (int j = count - 1; j >= 0; j--) {
endChangeAnimationIfNecessary(changes.get(j));
if (changes.isEmpty()) {
mChangesList.remove(changes);
}
}
}
cancelAll(mRemoveAnimations);
cancelAll(mMoveAnimations);
cancelAll(mAddAnimations);
cancelAll(mChangeAnimations);
dispatchAnimationsFinished();
}
void cancelAll(List<RecyclerView.ViewHolder> viewHolders) {
for (int i = viewHolders.size() - 1; i >= 0; i--) {
viewHolders.get(i).itemView.animate().cancel();
}
}
/**
* {@inheritDoc}
* <p>
* If the payload list is not empty, DefaultItemAnimator returns <code>true</code>.
* When this is the case:
* <ul>
* <li>If you override {@link #animateChange(RecyclerView.ViewHolder, RecyclerView.ViewHolder, int, int, int, int)}, both
* ViewHolder arguments will be the same instance.
* </li>
* <li>
* If you are not overriding {@link #animateChange(RecyclerView.ViewHolder, RecyclerView.ViewHolder, int, int, int, int)},
* then DefaultItemAnimator will call {@link #animateMove(RecyclerView.ViewHolder, int, int, int, int)} and
* run a move animation instead.
* </li>
* </ul>
*/
@Override
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder,
@NonNull List<Object> payloads) {
return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads);
}
}

View File

@@ -1,107 +0,0 @@
package com.mogo.och.offline.ui.adapter
import android.content.Context
import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.appcompat.widget.AppCompatTextView
import androidx.recyclerview.widget.RecyclerView
import com.mogo.och.offline.R
import com.mogo.och.offline.bean.BindLineListResponse
import com.mogo.och.offline.ui.adapter.SwitchLineAdapter.SwitchLineViewHolder
import kotlin.text.StringBuilder
/**
* 路线列表adapter
*/
class SwitchLineAdapter(
private val mContext: Context,
private val mData: List<BindLineListResponse.Result>
) : RecyclerView.Adapter<SwitchLineViewHolder>() {
companion object{
const val TAG = "SwitchLineAdapter"
}
// RecyclerView设置点击事件
private var mItemClickListener: LineItemClickListener? = null
private var checkInfo:BindLineListResponse.Result? = null
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): SwitchLineViewHolder {
val view = LayoutInflater.from(mContext).inflate(
R.layout.offline_switch_line_list_item, parent, false
)
return SwitchLineViewHolder(view)
}
override fun onBindViewHolder(holder: SwitchLineViewHolder, position: Int) {
val currentPosition = holder.bindingAdapterPosition
val lineInfo = mData[currentPosition]
if (lineInfo==checkInfo) {
holder.itemView.setBackgroundResource(R.drawable.bus_shape_select_line_item_bg_normal)
} else {
holder.itemView.setBackgroundColor(Color.parseColor("#162761"))
}
lineInfo.line?.let {line->
line.lineName?.let {
if(it.length>10){
holder.linelineName.text = it.substring(0,10)+""
}else{
holder.linelineName.text = lineInfo.line?.lineName
}
}
}
lineInfo.siteList?.let {
val last = it.last()
last.name?.let {siteName->
val sb = StringBuilder()
if (siteName.length>10) {
sb.append(siteName.substring(0,5))
sb.append("")
sb.append(siteName.substring(siteName.length-5,siteName.length))
}else{
sb.append(siteName)
}
val string = mContext.getString(R.string.bus_line_goto_end, sb.toString())
holder.lineEndlineName.text = string
}
}
//设置item点击事件
holder.itemView.setOnClickListener {
val oldPosition = mData.indexOf(checkInfo)
checkInfo = lineInfo
notifyItemChanged(oldPosition)
notifyItemChanged(currentPosition)
mItemClickListener?.onItemClick(lineInfo)
}
}
override fun getItemCount(): Int {
return mData.size
}
fun setOnLineItemClickListener(itemClickListener: LineItemClickListener?) {
mItemClickListener = itemClickListener
}
class SwitchLineViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val linelineName: AppCompatTextView//线路名称
val lineEndlineName: AppCompatTextView //终点
init {
linelineName = itemView.findViewById(R.id.switch_line_name)
lineEndlineName = itemView.findViewById(R.id.switch_line_end_station)
}
}
interface LineItemClickListener {
fun onItemClick(lineInfo: BindLineListResponse.Result)
}
}

View File

@@ -0,0 +1,119 @@
package com.mogo.och.offline.ui.bizswitch
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.findViewTreeViewModelStoreOwner
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_BUS
import com.mogo.eagle.core.utilcode.util.ThreadUtils
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager
import com.mogo.och.common.module.utils.ResourcesUtils
import com.mogo.och.common.module.utils.RxUtils
import com.mogo.och.common.module.wigets.WindowRelativeLayout
import com.mogo.och.offline.R
import io.reactivex.disposables.Disposable
import kotlinx.android.synthetic.main.offline_switch_biz.view.loading_biz
import kotlinx.android.synthetic.main.offline_switch_biz.view.swtichLine
import kotlinx.android.synthetic.main.offline_switch_biz.view.taskRunning
class SwitchBizView: WindowRelativeLayout, SwtichBizModel.SwtichLineViewCallback {
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)
companion object {
const val TAG = M_BUS+"SwitchBizView"
}
private var viewModel: SwtichBizModel?=null
private var queryTimeout: Disposable? = null
init {
LayoutInflater.from(context).inflate(R.layout.offline_switch_biz, this, true)
initView()
}
private fun initView(){
loading_biz.setEmptyText(ResourcesUtils.getString(R.string.offline_switch_biz_loading))
}
override fun onAttachedToWindow() {
CallerLogger.d(TAG,"SwitchBizViewonAttachedToWindow")
super.onAttachedToWindow()
viewModel = findViewTreeViewModelStoreOwner()?.let {
ViewModelProvider(it)[SwtichBizModel::class.java]
}
viewModel?.setSwitchBizCallback(this)
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
CallerLogger.d(TAG,"SwitchBizViewonDetachedFromWindow")
}
var startLoading = System.currentTimeMillis()
/**
* 展示loading页面
* 1、
* 2、第一次加载页面时展示
* 3、
*/
override fun showLoadingView(){
startLoading = System.currentTimeMillis()
CallerLogger.d(TAG,"开始展示 lading 时间:${startLoading}")
loading_biz.visibility = VISIBLE
swtichLine.visibility = GONE
queryTimeout = RxUtils.createSubscribe(10_1000) {
OchChainLogManager.writeChainLog("Loading超时","loading 展示了10s")
CallerLogger.d(TAG,"Loading超时loading 展示了10s")
viewModel?.queryRuningTask()
}
}
/**
* 初始化数据
*/
override fun loadLineData() {
swtichLine.loadingDatas()
}
// 展示选择线路页面
override fun showSwtichLineView() {
RxUtils.disposeSubscribe(queryTimeout)
val endLoading = System.currentTimeMillis()
val dex = (100-(endLoading - startLoading)).takeIf { it>=0 }?:0
CallerLogger.d(TAG,"展示线路 lading 展示了 ${dex}毫秒")
ThreadUtils.runOnUiThreadDelayed({
loading_biz.visibility = GONE
swtichLine.visibility = VISIBLE
taskRunning.visibility = GONE
},dex,ThreadUtils.MODE.QUEUE)
}
// 展示正在进行的任务
override fun loadRunningTask() {
RxUtils.disposeSubscribe(queryTimeout)
val endLoading = System.currentTimeMillis()
val dex = (100-(endLoading - startLoading)).takeIf { it>=0 }?:0
CallerLogger.d(TAG,"展示运行中任务 lading 展示了 ${dex}毫秒")
ThreadUtils.runOnUiThreadDelayed({
loading_biz.visibility = GONE
swtichLine.visibility = GONE
taskRunning.visibility = VISIBLE
taskRunning.showRunningTaskInfo()
},dex,ThreadUtils.MODE.QUEUE)
}
}

View File

@@ -0,0 +1,77 @@
package com.mogo.och.offline.ui.bizswitch
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.ThreadUtils
import com.mogo.och.offline.callback.IBusLinesCallback
import com.mogo.och.offline.model.LineModel
import com.mogo.och.offline.model.OrderModel
/**
* @author XuXinChao
* @description BadCase录包管理页面
* @since: 2022/12/15
*/
class SwtichBizModel : ViewModel(), IBusLinesCallback {
private val TAG = M_BUS + SwtichBizModel::class.java.simpleName
private var viewCallback: SwtichLineViewCallback? = null
override fun onCleared() {
d(TAG, "onCleared")
LineModel.setBusLinesCallback(TAG, null)
}
fun setSwitchBizCallback(viewCallback: SwtichLineViewCallback) {
d(TAG, "setSwitchBizCallback")
LineModel.setBusLinesCallback(TAG, this)
this.viewCallback = viewCallback
this.viewCallback?.showLoadingView()
ThreadUtils.getIoPool().execute {
OrderModel.queryBusRoutes()
}
}
fun queryRuningTask() {
ThreadUtils.getIoPool().execute {
OrderModel.queryBusRoutes()
}
}
fun showSwitchLineInfo() {
viewCallback?.showLoadingView()
viewCallback?.loadLineData()
}
fun showSwitchLineInfoResult() {
viewCallback?.showSwtichLineView()
}
interface SwtichLineViewCallback {
fun showSwtichLineView()
fun showLoadingView()
fun loadLineData()
fun loadRunningTask()
}
override fun onNoRunningTask() {
this.viewCallback?.loadLineData()
d(TAG, "没有任务去加载线路")
}
override fun onRunningTask() {
this.viewCallback?.loadRunningTask()
d(TAG, "有任务去加载正在执行的任务")
}
override fun onCompleteTask() {
OrderModel.queryBusRoutes()
}
}

View File

@@ -0,0 +1,100 @@
package com.mogo.och.offline.ui.fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.mogo.commons.mvp.MvpFragment
import com.mogo.eagle.core.function.call.och.CallerEagleBaseFunctionCall4OchManager
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_BUS
import com.mogo.och.bridge.ui.drawline.LineView
import com.mogo.och.offline.R
import kotlinx.android.synthetic.main.offline_base_fragment.mapContainerLayout
/**
* 网约车基础Fragment主要负责布局通用界面处理站点面板和通话面板互斥情况
*
*
* 部分业务放在了此处处理
*
* @author tongchenfei
*/
class OfflineFragment : MvpFragment<OfflineFragment?, OfflinePresenter?>() {
private val runningTaskGateWay = "RUNNINGTASKGATEWAY"
private val lineView = "LINEVIEW"
override fun getLayoutId(): Int {
return R.layout.offline_base_fragment
}
override fun getTagName(): String {
return "ShuttleFragment"
}
override fun initViews() {
context?.let {
CallerEagleBaseFunctionCall4OchManager.addSingleToolKitCustomItem(lineView, LineView(it),10)
}
}
override fun initViews(savedInstanceState: Bundle?) {
super.initViews(savedInstanceState)
mapContainerLayout?.onCreate(savedInstanceState)
}
override fun createPresenter(): OfflinePresenter {
return OfflinePresenter(this)
}
override fun onResume() {
super.onResume()
mapContainerLayout?.onResume()
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return super.onCreateView(inflater, container, savedInstanceState)
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapContainerLayout?.onSaveInstanceState(outState)
}
override fun onLowMemory() {
super.onLowMemory()
mapContainerLayout?.onLowMemory()
}
override fun onPause() {
super.onPause()
mapContainerLayout?.onPause()
}
override fun onDestroyView() {
mapContainerLayout?.onDestroy()
if (mPresenter != null) {
mPresenter!!.onDestroy(this)
}
CallerEagleBaseFunctionCall4OchManager.removeToolKitDefaultItemClickListener(lineView)
super.onDestroyView()
}
override fun onDestroy() {
super.onDestroy()
}
/**
* END
*/
companion object {
private const val TAG = "${M_BUS}BaseBusTabFragment"
}
}

View File

@@ -0,0 +1,57 @@
package com.mogo.och.offline.ui.fragment
import androidx.lifecycle.LifecycleOwner
import com.mogo.commons.AbsMogoApplication
import com.mogo.commons.mvp.Presenter
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.och.common.module.biz.login.ILoginCallback
import com.mogo.och.common.module.biz.login.LoginStatusEnum
import com.mogo.och.common.module.biz.login.LoginStatusManager
import com.mogo.och.common.module.biz.login.LoginStatusManager.isLogin
import com.mogo.och.bridge.autopilot.OCHAdasAbilityManager
import com.mogo.och.offline.model.OrderModel
import com.mogo.och.offline.util.OffLineTrajectoryManager
/**
* 网约车小巴
*
* @author tongchenfei
*/
class OfflinePresenter(view: OfflineFragment?) : Presenter<OfflineFragment?>(view), ILoginCallback {
override fun onCreate(owner: LifecycleOwner) {
super.onCreate(owner)
initModelListener()
}
override fun onDestroy(owner: LifecycleOwner) {
super.onDestroy(owner)
releaseListener()
}
private fun initModelListener() {
OCHAdasAbilityManager.getInstance().init(AbsMogoApplication.getApp())
LoginStatusManager.addListener(TAG, this)
OrderModel.init()
}
private fun releaseListener() {
OCHAdasAbilityManager.getInstance().release()
LoginStatusManager.removeListener(TAG)
OrderModel.release()
}
override fun onStatusChange(currentStatus: LoginStatusEnum) {
d(TAG, " loginStatus =" + isLogin())
if (!isLogin()) {
OffLineTrajectoryManager.stopTrajReqLoop()
OrderModel.closeBeautificationMode()
}
}
companion object {
private const val TAG = M_BUS+"BusPresenter"
}
}

View File

@@ -0,0 +1,104 @@
package com.mogo.och.offline.ui.switchline
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.AppCompatTextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.DiffUtil.Callback
import androidx.recyclerview.widget.RecyclerView
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_BUS
import com.mogo.och.offline.ui.switchline.SwitchLineAdapter.SwitchLineViewHolder
import com.mogo.och.data.db.bean.LineDataBean
import com.mogo.och.offline.R
import me.jessyan.autosize.AutoSizeCompat
/**
* 路线列表adapter
*/
class SwitchLineAdapter(
private val mContext: Context,
val mData: MutableList<LineDataBean>
) : RecyclerView.Adapter<SwitchLineViewHolder>() {
companion object{
const val TAG = M_BUS+"SwitchLineAdapter"
}
// RecyclerView设置点击事件
private var mItemClickListener: LineItemClickListener? = null
fun setDataList(dataList: List<LineDataBean>) {
val diffResult = DiffUtil.calculateDiff(MyDiffCallback(this.mData, dataList))
this.mData.clear()
this.mData.addAll(dataList)
diffResult.dispatchUpdatesTo(this)
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): SwitchLineViewHolder {
val view = LayoutInflater.from(mContext).inflate(
R.layout.offline_switch_line_list_item, parent, false
)
return SwitchLineViewHolder(view)
}
override fun onBindViewHolder(holder: SwitchLineViewHolder, position: Int) {
val currentPosition = holder.bindingAdapterPosition
AutoSizeCompat.autoConvertDensityOfGlobal(holder.itemView.resources)
val line = mData[currentPosition]
holder.lineName.text = line.lineName
val string = mContext.getString(R.string.offline_switch_line_endstationname, line.endStationName)
holder.lineEndName.text = string
//设置item点击事件
holder.itemView.setOnClickListener {
mItemClickListener?.onItemClick(line)
}
}
override fun getItemCount(): Int {
return mData.size
}
fun setOnLineItemClickListener(itemClickListener: LineItemClickListener?) {
mItemClickListener = itemClickListener
}
class SwitchLineViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val lineName: AppCompatTextView = itemView.findViewById(R.id.switch_line_name)//线路名称
val lineEndName: AppCompatTextView = itemView.findViewById(R.id.switch_line_end_station) //终点
}
interface LineItemClickListener {
fun onItemClick(data: LineDataBean)
}
inner class MyDiffCallback(private val oldData:List<LineDataBean>, private val newData:List<LineDataBean>):
Callback(){
override fun getOldListSize(): Int {
return oldData.size
}
override fun getNewListSize(): Int {
return newData.size
}
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldItem = oldData[oldItemPosition]
val newItem = newData[newItemPosition]
return oldItem == newItem && oldItem.endStationName == newItem.endStationName
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldItem = oldData[oldItemPosition]
val newItem = newData[newItemPosition]
return oldItem == newItem && oldItem.endStationName == newItem.endStationName
}
}
}

View File

@@ -0,0 +1,182 @@
package com.mogo.och.offline.ui.switchline
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.findViewTreeViewModelStoreOwner
import com.mogo.eagle.core.utilcode.kotlin.onClick
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_BUS
import com.mogo.eagle.core.utilcode.mogo.view.SpacesItemDecoration
import com.mogo.eagle.core.utilcode.util.UiThreadHandler
import com.mogo.och.common.module.manager.loop.BizLoopManager
import com.mogo.och.common.module.utils.ResourcesUtils
import com.mogo.och.common.module.wigets.WindowRelativeLayout
import com.mogo.och.common.module.wigets.WrapContentLinearLayoutManager
import com.mogo.och.common.module.wigets.commonview.ErrorView
import com.mogo.och.data.db.bean.LineDataBean
import com.mogo.och.offline.R
import com.mogo.och.offline.ui.bizswitch.SwtichBizModel
import kotlinx.android.synthetic.main.offline_switch_line.view.aciv_refresh_task
import kotlinx.android.synthetic.main.offline_switch_line.view.actv_last_refresh_date
import kotlinx.android.synthetic.main.offline_switch_line.view.include_empty
import kotlinx.android.synthetic.main.offline_switch_line.view.include_errorview
import kotlinx.android.synthetic.main.offline_switch_line.view.switch_line_rv
import me.jessyan.autosize.utils.AutoSizeUtils
class SwitchLineView: WindowRelativeLayout, SwtichLineModel.SwtichLineViewCallback {
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)
companion object {
const val TAG = "${M_BUS}SwitchLineView"
}
private var viewModel: SwtichLineModel?=null
private var viewbizModel: SwtichBizModel?=null
private lateinit var mAdapter: SwitchLineAdapter
private var animator:ObjectAnimator?=null
private lateinit var linearLayoutManager: WrapContentLinearLayoutManager
private var animatorStart = System.currentTimeMillis()
init {
LayoutInflater.from(context).inflate(R.layout.offline_switch_line, this, true)
initView()
}
private fun initView(){
linearLayoutManager = WrapContentLinearLayoutManager(context)
switch_line_rv.setLayoutManager(linearLayoutManager)
mAdapter = SwitchLineAdapter(context, mutableListOf())
switch_line_rv.addItemDecoration(
SpacesItemDecoration(
AutoSizeUtils.dp2px(context,20f)
)
)
switch_line_rv.setAdapter(mAdapter)
//设置item 点击事件
mAdapter.setOnLineItemClickListener(object : SwitchLineAdapter.LineItemClickListener{
override fun onItemClick(data: LineDataBean) {
CallerLogger.d(TAG,"选择线路 线路信息:${data}")
}
})
aciv_refresh_task.onClick(5_000) {
viewModel?.refreshTask()
animatorStart = System.currentTimeMillis()
if(animator==null) {
animator = ObjectAnimator.ofFloat(aciv_refresh_task, "rotation", 0f, 360f)
animator?.setDuration(1000) // 设置动画持续时间
animator?.repeatCount = ValueAnimator.INFINITE // 设置动画无限重复
animator?.repeatMode = ValueAnimator.RESTART // 设置重复模式
}
animator?.start()
}
include_errorview.reloadLIstener = object :ErrorView.ReloadLIstener{
override fun reload() {
viewbizModel?.showSwitchLineInfo()
}
}
}
/**
* 初始化数据
*/
fun loadingDatas() {
CallerLogger.d(TAG,"加载线路去")
viewModel?.queryBusLines(true)
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
viewModel = findViewTreeViewModelStoreOwner()?.let {
ViewModelProvider(it).get(SwtichLineModel::class.java)
}
viewbizModel = findViewTreeViewModelStoreOwner()?.let {
ViewModelProvider(it).get(SwtichBizModel::class.java)
}
viewModel?.setDistanceCallback(this)
CallerLogger.d(TAG,"onAttachedToWindow")
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
CallerLogger.d(TAG,"onDetachedFromWindow")
}
override fun startTaskState(success: Boolean) {
}
override fun onBusLinesChange(data: MutableList<LineDataBean>?, show:Boolean) {
if (data.isNullOrEmpty()) {
showNoData(true)
}else{
showNoData(false)
mAdapter.setDataList(data)
}
CallerLogger.d(TAG,"加载线路成功")
if(show) {
viewbizModel?.showSwitchLineInfoResult()
}
}
/**
* 有无数据UI显示
* @param b
*/
private fun showNoData(b: Boolean) {
BizLoopManager.runInMainThread{
include_errorview.visibility = View.GONE
if (b) {
switch_line_rv.visibility = View.GONE
include_empty.visibility = View.VISIBLE
} else {
switch_line_rv.visibility = View.VISIBLE
include_empty.visibility = View.GONE
}
}
}
override fun refreshDate(formatLongToString: String?) {
val endTime = System.currentTimeMillis()
val dex = (1000-(endTime - animatorStart)).takeIf { it>=0 }?:0
UiThreadHandler.postDelayed({
formatLongToString?.let {
actv_last_refresh_date.text = ResourcesUtils.getString(R.string.offline_switch_line_refresh_time,it)
animator?.cancel()
}
},dex,UiThreadHandler.MODE.QUEUE,)
}
override fun onBusLinesChangeFaile() {
include_errorview.visibility = View.VISIBLE
switch_line_rv.visibility = View.GONE
include_empty.visibility = View.GONE
viewbizModel?.showSwitchLineInfoResult()
}
}

View File

@@ -0,0 +1,97 @@
package com.mogo.och.offline.ui.switchline
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.och.common.module.utils.DateTimeUtil
import com.mogo.och.common.module.utils.RxUtils
import com.mogo.och.data.db.bean.LineDataBean
import com.mogo.och.offline.callback.IBusLinesCallback
import com.mogo.och.offline.model.LineModel
import com.mogo.och.offline.repository.RepositoryManager
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
/**
* @author XuXinChao
* @description BadCase录包管理页面
* @since: 2022/12/15
*/
class SwtichLineModel : ViewModel(), IBusLinesCallback {
private val TAG = M_BUS+ SwtichLineModel::class.java.simpleName
private var viewCallback: SwtichLineViewCallback?=null
private var endTaskDisposable:Disposable?=null
override fun onCleared() {
d(TAG,"onCleared")
LineModel.setBusLinesCallback(TAG,null)
}
fun setDistanceCallback(viewCallback: SwtichLineViewCallback){
this.viewCallback = viewCallback
LineModel.setBusLinesCallback(TAG,this)
}
fun queryBusLines(loading:Boolean) {
RxUtils.disposeSubscribe(endTaskDisposable)
RepositoryManager.queryCanUseLine()
?.subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread())
?.subscribe(object : Observer<List<LineDataBean>?> {
override fun onSubscribe(d: Disposable) {
endTaskDisposable = d
d(TAG, "queryBusLines onSubscribe")
}
override fun onError(e: Throwable) {
d(TAG, "queryBusLines onError${e.printStackTrace()}")
viewCallback?.onBusLinesChangeFaile()
}
override fun onComplete() {
d(TAG, "queryBusLines onComplete")
}
override fun onNext(data: List<LineDataBean>) {
d(TAG, "queryBusLines onNext ${data}")
val tempData = data.distinctBy { it.lineId }
viewCallback?.onBusLinesChange(tempData.toMutableList(),loading)
RxUtils.disposeSubscribe(endTaskDisposable)
}
})
}
fun refreshTask() {
LineModel.refreshTask()
}
interface SwtichLineViewCallback{
fun startTaskState(success: Boolean)
fun onBusLinesChange(data: MutableList<LineDataBean>?, show:Boolean)
fun refreshDate(formatLongToString: String?)
fun onBusLinesChangeFaile()
}
override fun onRefreshSuccess(currentTimeStamp: Long) {
viewCallback?.refreshDate(
DateTimeUtil.formatLongToString(currentTimeStamp, DateTimeUtil.HH_mm_ss)
)
}
override fun onRefreshSuccessWIthData() {
super.onRefreshSuccessWIthData()
queryBusLines(false)
}
override fun onChangeLineIdFail() {
viewCallback?.startTaskState(false)
}
}

View File

@@ -0,0 +1,258 @@
package com.mogo.och.offline.ui.taskrunning
import android.animation.ArgbEvaluator
import android.content.Context
import android.graphics.drawable.GradientDrawable
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.AppCompatImageView
import androidx.appcompat.widget.AppCompatTextView
import androidx.recyclerview.widget.RecyclerView
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_BUS
import com.mogo.och.common.module.utils.ResourcesUtils
import com.mogo.och.data.bean.BusStationBean
import com.mogo.och.offline.R
import com.mogo.och.offline.model.LineModel
import me.jessyan.autosize.utils.AutoSizeUtils
/**
* 路线列表adapter
*/
class TaskRunningAdapter(
private val mContext: Context,
val mData: MutableList<BusStationBean>
) : RecyclerView.Adapter<TaskRunningAdapter.TaskRunningViewHolder>() {
companion object {
const val TAG = "${M_BUS}TaskRunningAdapter"
}
private val argbEvaluator: ArgbEvaluator = ArgbEvaluator()
private val startColor = ResourcesUtils.getColor(R.color.common_1970FF)
private val endColor = ResourcesUtils.getColor(R.color.common_19FF7F)
private val heightItem = 100f
private val halfHeight = 16.5f
private var totalHeight = 0f
fun setDataList(dataList: List<BusStationBean>) {
this.mData.clear()
this.mData.addAll(dataList)
if (LineModel.startStationIndex == 0) {
totalHeight = 33 + (dataList.size - 2) * heightItem
} else {
totalHeight =
(halfHeight + (dataList.size - 1 - LineModel.startStationIndex) * heightItem).toFloat()
}
notifyItemRangeChanged(0, dataList.size, true)
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): TaskRunningViewHolder {
val view = LayoutInflater.from(mContext).inflate(
R.layout.offline_task_running_item, parent, false
)
return TaskRunningViewHolder(view)
}
override fun onBindViewHolder(holder: TaskRunningViewHolder, position: Int) {
val currentPosition = holder.bindingAdapterPosition
val line = mData[currentPosition]
holder.actvStationName.text = line.name
val startStationIndex = LineModel.startStationIndex
if (startStationIndex > 0) {
CallerLogger.d(TAG, "位置:$currentPosition 当前站${mData[startStationIndex]} ")
}
if (currentPosition < startStationIndex) {
holder.actvStationName.setTextSize(
TypedValue.COMPLEX_UNIT_PX,
AutoSizeUtils.dp2px(mContext, 40f).toFloat()
)
holder.actvStationName.setTextColor(ResourcesUtils.getColor(R.color.common_4DFFFFFF))
holder.acivStationHead.setImageResource(R.drawable.offline_task_running_pass_station_head)
} else if (currentPosition == startStationIndex) {
holder.actvStationName.setTextSize(
TypedValue.COMPLEX_UNIT_PX,
AutoSizeUtils.dp2px(mContext, 45f).toFloat()
)
holder.actvStationName.setTextColor(ResourcesUtils.getColor(R.color.common_2EACFF))
holder.acivStationHead.setImageResource(R.drawable.offline_task_running_item_normal)
} else {
holder.actvStationName.setTextColor(ResourcesUtils.getColor(R.color.white))
holder.actvStationName.setTextSize(
TypedValue.COMPLEX_UNIT_PX,
AutoSizeUtils.dp2px(mContext, 40f).toFloat()
)
holder.itemView.background = null
holder.acivStationHead.setImageResource(R.drawable.offline_task_running_item_normal)
}
when (currentPosition) {
0 -> {
holder.acivStationHeadBig.visibility = View.VISIBLE
holder.acivStationHead.visibility = View.INVISIBLE
holder.acivStationHeadBig.setImageResource(R.drawable.offline_task_running_item_start)
holder.middleStationBg.visibility = View.GONE
holder.startStationBg.visibility = View.VISIBLE
holder.endStationBg.visibility = View.GONE
if (startStationIndex == 0) {
if (line.isLeaving) {
// 下端 灰色
holder.startStationBg.setBackgroundResource(R.color.common_4DFFFFFF)
holder.itemView.background = null
} else {
// 下端 彩色
holder.itemView.setBackgroundResource(R.drawable.offline_task_running_current_station_bg)
val orientation = GradientDrawable.Orientation.TOP_BOTTOM
val temp01 = GradientDrawable(
orientation, intArrayOf(
startColor,
endColor
)
)
holder.startStationBg.background = temp01
}
} else {
// 下端 灰色
holder.startStationBg.setBackgroundResource(R.color.common_4DFFFFFF)
holder.itemView.background = null
}
}
mData.size - 1 -> {
holder.acivStationHeadBig.visibility = View.VISIBLE
holder.acivStationHead.visibility = View.INVISIBLE
holder.acivStationHeadBig.setImageResource(R.drawable.offline_task_running_item_end)
holder.middleStationBg.visibility = View.GONE
holder.startStationBg.visibility = View.GONE
holder.endStationBg.visibility = View.VISIBLE
if (startStationIndex == itemCount - 1) {
if (line.isLeaving) {
holder.endStationBg.setBackgroundResource(R.color.common_4DFFFFFF)
holder.itemView.setBackgroundResource(R.drawable.offline_task_running_current_station_bg)
} else {
holder.itemView.setBackgroundResource(R.drawable.offline_task_running_current_station_bg)
holder.endStationBg.setBackgroundResource(R.color.common_4DFFFFFF)
}
} else {
// 上端 彩色
holder.itemView.background = null
val startColorTemp = argbEvaluator.evaluate(
((totalHeight - halfHeight) / totalHeight).toFloat(),
startColor,
endColor
) as Int
val endColorTemp = argbEvaluator.evaluate(1f, startColor, endColor) as Int
val orientation = GradientDrawable.Orientation.TOP_BOTTOM
val temp01 = GradientDrawable(
orientation, intArrayOf(
startColorTemp,
endColorTemp
)
)
holder.endStationBg.background = temp01
}
}
else -> {
holder.acivStationHeadBig.visibility = View.GONE
holder.acivStationHead.visibility = View.VISIBLE
holder.middleStationBg.visibility = View.VISIBLE
holder.startStationBg.visibility = View.GONE
holder.endStationBg.visibility = View.GONE
if (currentPosition == startStationIndex) {
if (line.isLeaving) {
// 灰色
holder.middleStationBg.setBackgroundResource(R.color.common_4DFFFFFF)
holder.itemView.background = null
} else {
// 彩色
holder.itemView.setBackgroundResource(R.drawable.offline_task_running_current_station_bg)
val startColorTemp = argbEvaluator.evaluate(0f, startColor, endColor) as Int
val endColorTemp =
argbEvaluator.evaluate(100f / totalHeight, startColor, endColor) as Int
val orientation = GradientDrawable.Orientation.TOP_BOTTOM
val temp01 = GradientDrawable(
orientation, intArrayOf(
startColorTemp,
endColorTemp
)
)
holder.middleStationBg.background = temp01
}
} else if (currentPosition < startStationIndex) {
// 灰色
holder.middleStationBg.setBackgroundResource(R.color.common_4DFFFFFF)
holder.itemView.background = null
} else {
var dex = 0f
if (startStationIndex == 0) {
val firstItemData = mData[0]
if (!firstItemData.isLeaving) {
dex = halfHeight
}
} else {
val checkIndex = mData.get(startStationIndex)
if (!checkIndex.isLeaving) {
dex = heightItem
}
}
// 彩色
holder.itemView.background = null
val index = (currentPosition - startStationIndex - 1) * 100
val startFraction = (dex + index) / totalHeight
val endFraction = (dex + index + 100) / totalHeight
CallerLogger.d(
TAG,
"位置:$currentPosition 当前站${startStationIndex} 开始百分比:${startFraction} 结束百分比:${endFraction}"
)
val startColorTemp =
argbEvaluator.evaluate(startFraction, startColor, endColor) as Int
val endColorTemp =
argbEvaluator.evaluate(endFraction, startColor, endColor) as Int
val orientation = GradientDrawable.Orientation.TOP_BOTTOM
val temp01 = GradientDrawable(
orientation, intArrayOf(
startColorTemp,
endColorTemp
)
)
holder.middleStationBg.background = temp01
}
}
}
if (currentPosition == startStationIndex + 1) {
val preLine = mData[currentPosition - 1]
if (preLine.isLeaving) {
holder.itemView.setBackgroundResource(R.drawable.offline_task_running_current_station_bg)
} else {
holder.itemView.background = null
}
}
}
override fun getItemCount(): Int {
return mData.size
}
class TaskRunningViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val actvStationName: AppCompatTextView = itemView.findViewById(R.id.actv_station_name)//站点名称
val acivStationHead: AppCompatImageView =
itemView.findViewById(R.id.aciv_station_head)//普通站点标识 不是起始和终点坐标
val acivStationHeadBig: AppCompatImageView =
itemView.findViewById(R.id.aciv_station_head_big)//起始和终点坐标标识
val middleStationBg: View = itemView.findViewById(R.id.bg_pass_bg) //贯通背景调
val endStationBg: View = itemView.findViewById(R.id.bg_pass_head_bg) //终点的背景
val startStationBg: View = itemView.findViewById(R.id.bg_pass_bottom_bg) //起点坐标的背景
}
}

View File

@@ -0,0 +1,84 @@
package com.mogo.och.offline.ui.taskrunning
import androidx.lifecycle.ViewModel
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_BUS
import com.mogo.och.common.module.manager.loop.BizLoopManager
import com.mogo.och.offline.callback.IBusLinesCallback
import com.mogo.och.offline.model.LineModel
import com.mogo.och.offline.model.OrderModel
/**
* @author XuXinChao
* @description BadCase录包管理页面
* @since: 2022/12/15
*/
class TaskRunningModel : ViewModel(), IBusLinesCallback {
private val TAG = M_BUS + TaskRunningModel::class.java.simpleName
private var viewCallback: SwtichLineViewCallback? = null
override fun onCleared() {
}
fun setDistanceCallback(viewCallback: SwtichLineViewCallback) {
this.viewCallback = viewCallback
LineModel.setBusLinesCallback(TAG, this)
}
fun leaveStation() {
OrderModel.driveToNextStation()
}
interface SwtichLineViewCallback {
fun showRunningTaskInfo()
fun hideLoadingAndshowRunningTaskInfo()
fun smoothScrollToPosition(position: Int)
fun completeTaskFail()
}
override fun onLeaveStaionSuccess() {
BizLoopManager.runInMainThread {
viewCallback?.hideLoadingAndshowRunningTaskInfo()
smoothScrollToPosition()
}
}
fun smoothScrollToPosition() {
BizLoopManager.runInMainThread(object : Runnable {
override fun run() {
viewCallback?.smoothScrollToPosition(LineModel.startStationIndex)
}
})
}
fun arriveStation() {
OrderModel.onArriveAt(null, "页面触发到站")
}
override fun onArriveStationSuccess() {
BizLoopManager.runInMainThread {
smoothScrollToPosition()
viewCallback?.showRunningTaskInfo()
}
}
override fun onCompleteTask() {
}
override fun onCompleteTaskFail() {
super.onCompleteTaskFail()
BizLoopManager.runInMainThread {
viewCallback?.completeTaskFail()
}
}
fun completeTask() {
OrderModel.completeTask()
}
}

View File

@@ -0,0 +1,168 @@
package com.mogo.och.offline.ui.taskrunning
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 com.mogo.eagle.core.utilcode.kotlin.onClick
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_BUS
import com.mogo.och.bridge.autopilot.line.LineManager
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager
import com.mogo.och.common.module.utils.ResourcesUtils
import com.mogo.och.common.module.wigets.dialog.CommonDialogStatus
import com.mogo.och.common.module.wigets.CommonSlideView
import com.mogo.och.common.module.wigets.WrapContentLinearLayoutManager
import com.mogo.och.offline.R
import com.mogo.och.offline.model.LineModel
import com.mogo.och.offline.ui.bizswitch.SwtichBizModel
import kotlinx.android.synthetic.main.offline_task_running.view.aciv_task_leave_station_slide_bg
import kotlinx.android.synthetic.main.offline_task_running.view.actv_arriver_station
import kotlinx.android.synthetic.main.offline_task_running.view.actv_complete_task
import kotlinx.android.synthetic.main.offline_task_running.view.actv_running_task_last_station
import kotlinx.android.synthetic.main.offline_task_running.view.actv_running_task_time
import kotlinx.android.synthetic.main.offline_task_running.view.bus_task_running_line_name
import kotlinx.android.synthetic.main.offline_task_running.view.loading_arrive_station
import kotlinx.android.synthetic.main.offline_task_running.view.rl_running_task_station_list
class TaskRunningView : ConstraintLayout, TaskRunningModel.SwtichLineViewCallback {
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)
companion object {
const val TAG = M_BUS + "TaskRunningView"
}
private var viewModel: TaskRunningModel? = null
private var viewbizModel: SwtichBizModel? = null
private lateinit var mAdapter: TaskRunningAdapter
private lateinit var linearLayoutManager: WrapContentLinearLayoutManager
init {
LayoutInflater.from(context).inflate(R.layout.offline_task_running, this, true)
initView()
}
private fun initView() {
linearLayoutManager = WrapContentLinearLayoutManager(context)
rl_running_task_station_list.setLayoutManager(linearLayoutManager)
mAdapter = TaskRunningAdapter(context, mutableListOf())
rl_running_task_station_list.setAdapter(mAdapter)
aciv_task_leave_station_slide_bg.setSlideListener(object : CommonSlideView.SlideListener {
override fun slideEnd() {
viewModel?.leaveStation()
}
})
actv_arriver_station.onClick {
loading_arrive_station.visibility = VISIBLE
viewModel?.arriveStation()
}
actv_complete_task.onClick {
val builder = CommonDialogStatus.Builder()
val closeLineConfirmDialog = builder
.tips(ResourcesUtils.getString(R.string.offline_dialog_tips))
.status(CommonDialogStatus.Status.ask)
.build(context)
closeLineConfirmDialog.setClickListener(object : CommonDialogStatus.ClickListener {
override fun confirm() {
viewModel?.completeTask()
}
override fun cancel() {
closeLineConfirmDialog.dismiss()
}
})
closeLineConfirmDialog.show()
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
viewModel = findViewTreeViewModelStoreOwner()?.let {
ViewModelProvider(it).get(TaskRunningModel::class.java)
}
viewbizModel = findViewTreeViewModelStoreOwner()?.let {
ViewModelProvider(it).get(SwtichBizModel::class.java)
}
viewModel?.setDistanceCallback(this)
}
override fun showRunningTaskInfo() {
LineManager.getLineInfo { lineInfo ->
bus_task_running_line_name.text = lineInfo.lineName
}
actv_running_task_time.text = "班次:${LineModel.getTaskTime()}"
LineModel.stationList?.takeIf { it.size >= 2 }?.let {
actv_running_task_last_station.text = "${it.last().name ?: ""}"
mAdapter.setDataList(it)
CallerLogger.d(
TAG,
"BusLineModel.startStationIndex:${LineModel.startStationIndex}___$it"
)
val currentStation = it.get(LineModel.startStationIndex)
if (currentStation.isLeaving) {
showArriverStationAndCompleteTask()
} else {
showLeaveStationView()
}
if (LineModel.startStationIndex == it.size - 1) {
aciv_task_leave_station_slide_bg.setTextValue("单程结束")
} else {
aciv_task_leave_station_slide_bg.setTextValue("滑动出发")
}
}
}
override fun hideLoadingAndshowRunningTaskInfo() {
loading_arrive_station.visibility = GONE
showRunningTaskInfo()
}
override fun completeTaskFail() {
aciv_task_leave_station_slide_bg.reset()
}
override fun smoothScrollToPosition(position: Int) {
try {
rl_running_task_station_list.smoothScrollToPosition(position)
} catch (e: Exception) {
OchChainLogManager.writeChainLog("错误", "e:${e.message}")
}
}
fun showLeaveStationView() {
aciv_task_leave_station_slide_bg.visibility = VISIBLE
actv_arriver_station.visibility = GONE
actv_complete_task.visibility = GONE
}
fun showArriverStationAndCompleteTask() {
aciv_task_leave_station_slide_bg.visibility = INVISIBLE
actv_arriver_station.visibility = VISIBLE
actv_complete_task.visibility = VISIBLE
}
}

View File

@@ -4,15 +4,23 @@ import com.mogo.commons.AbsMogoApplication
import com.mogo.commons.voice.AIAssist
import com.mogo.eagle.core.data.config.FunctionBuildConfig
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
import com.mogo.och.common.module.manager.socket.lan.LanSocketManager
import com.mogo.och.common.module.manager.socket.lan.bean.AppConnectMsg
import com.mogo.och.common.module.utils.ResourcesUtils
import com.mogo.och.common.module.voice.VoiceNotice
import com.mogo.och.offline.R
import com.mogo.och.shuttle.weaknet.R
import com.mogo.skin.utils.SkinResources
import com.mogo.tts.base.LangTtsEntity
import com.mogo.tts.base.LanguageType
import java.util.ArrayList
object ShuttleVoiceManager {
fun arrivedStationOut(notice:String?){
if (AppIdentityModeUtils.isB2(FunctionBuildConfig.appIdentityMode)) {
VoiceNotice.showNoticeOut(notice)
}
}
fun arrivedStationBus(siteNameCN: String?, siteNameKR: String?) {
val context = AbsMogoApplication.getApp()
val list: MutableList<LangTtsEntity> = ArrayList()
@@ -23,7 +31,7 @@ object ShuttleVoiceManager {
)
val engTTS = LangTtsEntity(
context.getString(R.string.bus_arrived_station_english_tip, it),
LanguageType.CHINESE
LanguageType.ENGLISH
)
val koreanTTS = LangTtsEntity(
context.getString(R.string.bus_arrived_station_korean_tip, siteNameKR?:it),
@@ -32,9 +40,25 @@ object ShuttleVoiceManager {
list.add(chineseTTS)
list.add(engTTS)
list.add(koreanTTS)
}
VoiceNotice.showNotice(list, AIAssist.LEVEL1,null)
if (AppIdentityModeUtils.isB1(FunctionBuildConfig.appIdentityMode)) {
VoiceNotice.showNotice(list, AIAssist.LEVEL1,null)
} else if (AppIdentityModeUtils.isB2(FunctionBuildConfig.appIdentityMode)) {
siteNameCN?.let {
sendArrivedStationToClient(it)
}
}
}
private fun sendArrivedStationToClient(arriveStation: String) {
val arrivedMsg = AppConnectMsg(
isViewShow = false,
isPlay = true,
msg = ResourcesUtils.getString(R.string.bus_arrived_station_tip,arriveStation),
)
LanSocketManager.sendMsgToClient(arrivedMsg)
}
fun leaveStationBus(siteNameCN: String?, siteNameKR: String?) {
@@ -47,7 +71,7 @@ object ShuttleVoiceManager {
)
val engTTS = LangTtsEntity(
context.getString(R.string.bus_leave_station_english_tip, it),
LanguageType.CHINESE
LanguageType.ENGLISH
)
list.add(chineseTTS)
list.add(engTTS)
@@ -56,9 +80,26 @@ object ShuttleVoiceManager {
context.getString(R.string.bus_leave_station_korean_tip, siteNameKR ?: it),
LanguageType.KOREAN
)
list.add(koreanTTS)
}
VoiceNotice.showNotice(list, AIAssist.LEVEL1,null)
if (AppIdentityModeUtils.isB1(FunctionBuildConfig.appIdentityMode)) {
VoiceNotice.showNotice(list, AIAssist.LEVEL1,null)
} else if (AppIdentityModeUtils.isB2(FunctionBuildConfig.appIdentityMode)) {
siteNameCN?.let {
sendStartStationToClient(it)
}
}
}
private fun sendStartStationToClient(nextStation: String) {
val startMsg = AppConnectMsg(
isViewShow = false,
isPlay = true,
msg = ResourcesUtils.getString(R.string.bus_leave_station_tip,nextStation),
)
LanSocketManager.sendMsgToClient(startMsg)
}
fun endOrderBus() {
@@ -70,17 +111,45 @@ object ShuttleVoiceManager {
list.add(chineseTTS)
list.add(engTTS)
list.add(koreanTTS)
VoiceNotice.showNotice(list, AIAssist.LEVEL0,null)
if (AppIdentityModeUtils.isB1(FunctionBuildConfig.appIdentityMode)) {
VoiceNotice.showNotice(list, AIAssist.LEVEL0,null)
} else if (AppIdentityModeUtils.isB2(FunctionBuildConfig.appIdentityMode)) {
sendEndTaskToClient()
}
}
private fun sendEndTaskToClient() {
val endMsg = AppConnectMsg(
isViewShow = false,
isPlay = true,
msg = SkinResources.getInstance().getString(R.string.bus_end_task_tip),
)
LanSocketManager.sendMsgToClient(endMsg)
}
fun writeOffCount(successNum:Int){
if(successNum<=1){
VoiceNotice.showNotice("核验通过", AIAssist.LEVEL3);
VoiceNotice.showNotice("核验通过", AIAssist.LEVEL3)
//sendWriteOffNumToClient("核验通过")
}else{
VoiceNotice.showNotice("$successNum 人核验通过", AIAssist.LEVEL3)
//sendWriteOffNumToClient("$successNum 人核验通过")
}
}
private fun sendWriteOffNumToClient(msg: String?) {
val passengerMsg = AppConnectMsg(
isViewShow = false,
isPlay = true,
msg = msg!!,
)
LanSocketManager.sendMsgToClient(passengerMsg)
}
// 距离发车还有1分钟
fun showLeafTime(tips: String) {
//语音提示

View File

@@ -1,63 +0,0 @@
package com.mogo.och.offline.view
import android.content.Context
import android.os.Bundle
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.FrameLayout
import com.mogo.eagle.core.data.config.FunctionBuildConfig
import com.mogo.eagle.core.function.view.MapBizView
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
import com.mogo.map.uicontroller.IMogoMapUIController
import com.mogo.och.offline.R
/**
* 魔戒蓝牙控件
* 放置于StatusBar右侧位置
*/
class BizMapView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
private lateinit var mapBizView: MapBizView
init {
if (AppIdentityModeUtils.isB2(FunctionBuildConfig.appIdentityMode)) {
LayoutInflater.from(context).inflate(R.layout.offline_m2_bizmap_map, this, true)
}else if(AppIdentityModeUtils.isB1(FunctionBuildConfig.appIdentityMode)){
LayoutInflater.from(context).inflate(R.layout.offline_jl_bizmap_map, this, true)
}else{
LayoutInflater.from(context).inflate(R.layout.offline_jl_bizmap_map, this, true)
}
mapBizView = findViewById(R.id.bizMapView)
}
fun getUI(): IMogoMapUIController? {
return mapBizView.getUI()
}
fun onCreate(bundle: Bundle?) {
mapBizView.onCreate(bundle)
}
fun onResume() {
mapBizView.onResume()
}
fun onSaveInstanceState(outState: Bundle){
mapBizView.onSaveInstanceState(outState)
}
fun onLowMemory() {
mapBizView.onLowMemory()
}
fun onPause() {
mapBizView.onPause()
}
fun onDestroy() {
mapBizView.onDestroy()
}
}

View File

@@ -1,300 +0,0 @@
package com.mogo.och.offline.view;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import androidx.annotation.Nullable;
import com.mogo.commons.AbsMogoApplication;
import com.mogo.eagle.core.utilcode.util.ConvertUtils;
import com.mogo.eagle.core.utilcode.util.ThreadUtils;
import com.mogo.eagle.core.utilcode.util.UiThreadHandler;
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager;
import com.mogo.och.offline.R;
import me.jessyan.autosize.AutoSizeConfig;
import me.jessyan.autosize.utils.AutoSizeUtils;
/**
* 滑块滑动面板
*
* @author tongchenfei
*/
public class SlidePanelView extends View {
private static final String TAG = "SlidePanelView";
public SlidePanelView(Context context) {
this(context, null);
}
public SlidePanelView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public SlidePanelView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.SlidePanelView);
textSize = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_textSize, textSize);
BLOCK_START_X = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_BLOCK_START_X, BLOCK_START_X);
BLOCK_START_Y = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_BLOCK_START_Y, BLOCK_START_Y);
NORMAL_TEXT_MARGIN_LEFT = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_NORMAL_TEXT_MARGIN_LEFT, NORMAL_TEXT_MARGIN_LEFT);
NORMAL_TEXT_MARGIN_RIGHT = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_NORMAL_TEXT_MARGIN_RIGHT, NORMAL_TEXT_MARGIN_RIGHT);
SHORT_TEXT_MARGIN_LEFT = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_SHORT_TEXT_MARGIN_LEFT, SHORT_TEXT_MARGIN_LEFT);
SHORT_TEXT_MARGIN_RIGHT = (int) mTypedArray.getDimension(R.styleable.SlidePanelView_SHORT_TEXT_MARGIN_RIGHT, SHORT_TEXT_MARGIN_RIGHT);
init();
}
private final Paint bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint blockPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private static int textSize = 40;
private static int BLOCK_START_X = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(),15);
private static int BLOCK_START_Y = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(),15);
private static int NORMAL_TEXT_MARGIN_LEFT = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(),40);
private static int NORMAL_TEXT_MARGIN_RIGHT = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(),60);
private static int SHORT_TEXT_MARGIN_LEFT = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(),60);;
private static int SHORT_TEXT_MARGIN_RIGHT = AutoSizeUtils.dp2px(AbsMogoApplication.getApp(),70);;
private int textMarginLeft = NORMAL_TEXT_MARGIN_LEFT;
private int textMarginRight = NORMAL_TEXT_MARGIN_RIGHT;
private OnSlidePanelMoveToEndListener moveToEndListener;
private int blockWidth = 0;
private int blockOffset = 0;
private float lastX;
private boolean isToEnd = false;
private static final String STRING_SLIDE_TO_RIGHT = "向右滑动";
private RectF bgRectF;
private Bitmap bmBlock;
private final Matrix gradientMatrix = new Matrix();
private float matrixTranslate;
private final Rect textRect = new Rect();
private LinearGradient textGradient;
private ObjectAnimator matrixAnim;
private String blockText = STRING_SLIDE_TO_RIGHT;
private final Paint.FontMetrics blockTextMetrics = new Paint.FontMetrics();
private static final int GRADIENT_OFFSET = 200;
public void setOnSlidePanelMoveToEndListener(OnSlidePanelMoveToEndListener moveToEndListener) {
this.moveToEndListener = moveToEndListener;
}
private void setBlockOffset(int blockOffset) {
this.blockOffset = blockOffset;
invalidate();
}
private void setMatrixTranslate(float matrixTranslate) {
this.matrixTranslate = matrixTranslate;
invalidate();
}
public void setText(String text) {
this.blockText = text;
requestLayout();
invalidate();
}
private void init() {
bgRectF = new RectF(0, 0, 0, 0);
bgPaint.setColor(Color.parseColor("#CC0F1325"));
bgPaint.setStyle(Paint.Style.FILL);
textPaint.setStyle(Paint.Style.FILL);
textPaint.setTextSize(textSize);
textPaint.setTextAlign(Paint.Align.LEFT);
textGradient = new LinearGradient(-GRADIENT_OFFSET, 0, 0, 0, new int[]{0x33ffffff, 0xffffffff, 0x33ffffff}, null, Shader.TileMode.CLAMP);
textGradient.setLocalMatrix(gradientMatrix);
textPaint.setShader(textGradient);
textPaint.getFontMetrics(blockTextMetrics);
decodeImage();
}
private void decodeImage(){
ThreadUtils.getCpuPool().execute(() -> {
int size = AutoSizeUtils.dp2px(getContext(), 120);
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inDensity = (int) AutoSizeConfig.getInstance().getInitDensity();
bmBlock = BitmapFactory.decodeResource(getResources(), R.drawable.bus_base_slide_block,opts);
bmBlock = Bitmap.createScaledBitmap(bmBlock, size, size, true);
blockWidth = bmBlock.getWidth();
UiThreadHandler.post(this::requestLayout,UiThreadHandler.MODE.QUEUE);
});
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize;
int heightSize;
if (blockText.length() < 5) {
textMarginLeft = SHORT_TEXT_MARGIN_LEFT;
textMarginRight = SHORT_TEXT_MARGIN_RIGHT;
} else {
textMarginLeft = NORMAL_TEXT_MARGIN_LEFT;
textMarginRight = NORMAL_TEXT_MARGIN_RIGHT;
}
if(bmBlock!=null) {
if (widthMode == MeasureSpec.AT_MOST) {
// 宽度根据图片大小,字符串长度,各种间隔确定
// 高度根据图片大小和上下间隔确定
textPaint.getTextBounds(blockText, 0, blockText.length(), textRect);
widthSize = BLOCK_START_X * 2 + bmBlock.getWidth() + textMarginLeft + textMarginRight + textRect.width();
heightSize = BLOCK_START_Y * 2 + bmBlock.getHeight();
widthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private float textOffset = 0;
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (bgRectF != null){
bgRectF.left = 0;
bgRectF.top = 0;
bgRectF.right = w;
bgRectF.bottom = h;
}
if (matrixAnim != null) {
matrixAnim.cancel();
}
textOffset = (getHeight() - blockTextMetrics.ascent - blockTextMetrics.descent) / 2;
matrixAnim = ObjectAnimator.ofFloat(this, "matrixTranslate", 0, w + GRADIENT_OFFSET).setDuration(2000);
matrixAnim.setRepeatCount(ValueAnimator.INFINITE);
matrixAnim.start();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (matrixAnim != null) {
matrixAnim.start();
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (matrixAnim != null) {
matrixAnim.cancel();
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (x > BLOCK_START_X + blockOffset && x < blockWidth + BLOCK_START_X + blockOffset && y > BLOCK_START_Y && y < getHeight() - BLOCK_START_Y) {
isToEnd = false;
lastX = x;
}
break;
case MotionEvent.ACTION_MOVE:
if (lastX != 0) {
blockOffset = (int) (x - lastX);
if (blockOffset < 0) {
blockOffset = 0;
}
if (blockOffset + BLOCK_START_X + blockWidth > getWidth()) {
// 超出右边界
blockOffset = getWidth() - BLOCK_START_X - blockWidth;
if (!isToEnd) {
isToEnd = true;
if (moveToEndListener != null) {
moveToEndListener.moveToEnd();
}
startBlockBackAnim();
}
}
invalidate();
}
break;
case MotionEvent.ACTION_UP:
// 执行滑块回归动画
if (!isToEnd) {
startBlockBackAnim();
}
break;
default:
break;
}
return true;
}
private void startBlockBackAnim() {
ObjectAnimator blockBackanimator = ObjectAnimator.ofInt(this, "blockOffset", blockOffset, 0);
blockBackanimator.setInterpolator(new DecelerateInterpolator());
blockBackanimator.setDuration(1000 * blockOffset / getWidth());
blockBackanimator.start();
lastX = 0;
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 画背景
canvas.drawRoundRect(bgRectF, (float) getHeight() / 2.0f, (float) getHeight() / 2.0f, bgPaint);
// 画文字
gradientMatrix.setTranslate(matrixTranslate, 0);
textGradient.setLocalMatrix(gradientMatrix);
canvas.save();
canvas.drawText(blockText, (float) (blockWidth + BLOCK_START_X + textMarginLeft), (float) textOffset, textPaint);
canvas.restore();
if (bmBlock != null) {
if(bmBlock.getByteCount()>=5*1024*1024){
OchChainLogManager.writeChainLog("崩溃兜底策略",
"图片大小监听"+ ConvertUtils.byte2FitMemorySize(bmBlock.getByteCount()),true,OchChainLogManager.EVENT_KEY_INFE_ERROR);
bmBlock.recycle();
bmBlock = null;
blockWidth = 0;
decodeImage();
}else {
// 画滑块
canvas.drawBitmap(bmBlock, (float) (BLOCK_START_X + blockOffset), (float) BLOCK_START_Y, blockPaint);
}
}
}
public interface OnSlidePanelMoveToEndListener {
/**
* 滑块滑到了末尾
*/
void moveToEnd();
}
}

View File

@@ -1,64 +0,0 @@
package com.mogo.och.offline.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
/**
* 垂直虚线
*
* @author tongchenfei
*/
public class VerticalDashLineView extends View {
public VerticalDashLineView(Context context) {
this(context,null);
}
public VerticalDashLineView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public VerticalDashLineView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private final Paint linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Path dashPath = new Path();
private void init(){
linePaint.setColor(Color.GREEN);
linePaint.setStyle(Paint.Style.STROKE);
linePaint.setStrokeWidth(2);
linePaint.setPathEffect(new DashPathEffect(new float[]{5, 5}, 0));
}
public void setGradient(int startColor, int endColor) {
LinearGradient linearGradient = new LinearGradient(0, 0, getWidth(), getHeight(), startColor, endColor, Shader.TileMode.CLAMP);
linePaint.setShader(linearGradient);
invalidate();
}
public void setColor(int color) {
linePaint.setShader(null);
linePaint.setColor(color);
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
dashPath.reset();
dashPath.moveTo((float) getWidth()/2, 0);
dashPath.lineTo((float) getWidth()/2,getHeight());
canvas.drawPath(dashPath,linePaint);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1004 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 377 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

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