From 5fa94b3718b4a78a4fcea4c97652b0ef20b7de3a Mon Sep 17 00:00:00 2001
From: puzhibing <393733352@qq.com>
Date: 星期五, 21 八月 2026 09:34:49 +0800
Subject: [PATCH] 提交最终代码
---
app/src/main/java/com/xw/yunwei/ui/task/selectCar/SelectCarActivity.kt | 98
common/src/main/res/drawable/shape_while_bg_5.xml | 5
app/src/main/java/com/xw/yunwei/ui/work/checkInMission/CruiseCheckInActivity.kt | 821 +
app/src/main/java/com/xw/yunwei/model/AgreeInfo.kt | 10
app/src/main/java/com/xw/yunwei/websocket/WebSocketManager.kt | 237
app/src/main/java/com/xw/yunwei/MyApp.kt | 242
gradle/libs.versions.toml | 24
app/src/main/java/com/xw/yunwei/ui/task/list/TaskListVM.kt | 69
app/src/main/java/com/xw/yunwei/ui/user/mine/checkin/CheckInVM.kt | 80
app/src/main/java/com/xw/yunwei/ui/dialog/NewTaskDialog.kt | 217
app/src/main/java/com/xw/yunwei/ui/work/checkInMission/CruiseCheckInMissionCompleteActivity.kt | 96
app/src/main/java/com/xw/yunwei/ui/work/car/detail/CarDetailVM.kt | 174
app/src/main/java/com/xw/yunwei/ui/user/mine/protocol/ProtocolVM.kt | 23
app/src/main/java/com/xw/yunwei/model/AppVersionModel.kt | 13
app/src/main/java/com/xw/yunwei/ui/work/checkInMission/viewmodel/RoutePlanningViewModel.kt | 74
app/src/main/res/drawable/svg_circle_loading.xml | 40
app/src/main/res/mipmap-xhdpi/ic_start_point.png | 0
app/src/main/res/layout/layout_normal_task_car_charge.xml | 2
app/src/main/res/mipmap-xhdpi/icon_car_charge.png | 0
app/src/main/res/layout/activity_car_manage.xml | 18
app/src/main/res/layout/dialog_protocol.xml | 133
app/src/main/java/com/xw/yunwei/net/WorkApi.kt | 44
app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/clean/CleanCarDetailActivity.kt | 16
app/src/main/res/layout/fragment_task.xml | 190
app/src/main/res/layout/fragment_task_list.xml | 4
app/src/main/res/layout/activity_car_check_detail.xml | 14
app/src/main/res/drawable/shape_gray_4_bg_4.xml | 5
app/src/main/res/layout/fragment_car_dispatch.xml | 326
common/src/main/res/mipmap-xhdpi/icon_default.png | 0
app/src/main/java/com/xw/yunwei/ui/widget/LineView.kt | 116
app/src/main/res/mipmap-xhdpi/icon_note_triangle2.png | 0
app/src/main/java/com/xw/yunwei/ui/widget/ClearEditText.kt | 195
app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/clean/CleanCarActivity.kt | 37
app/src/main/res/mipmap-hdpi/icon_map_arrow_blue.png | 0
app/src/main/res/values/colors.xml | 21
app/src/main/res/drawable/selector_switch_off_on.xml | 5
app/src/main/res/layout/item_work_car.xml | 21
app/src/main/res/mipmap-xhdpi/ic_route_arrow_close.png | 0
app/src/main/java/com/xw/yunwei/utils/DialogFactory.kt | 43
app/src/main/java/com/xw/yunwei/model/TaskNormalRepairModel.kt | 23
app/src/main/res/mipmap-xhdpi/icon_note.png | 0
app/src/main/java/com/xw/yunwei/ui/work/WorkVM.kt | 25
app/src/main/res/mipmap-xhdpi/icon_clock_blue.png | 0
common/src/main/res/drawable/shape_white_bg_top_16.xml | 5
app/src/main/res/layout/layout_normal_task_car_nj_or_by_or_bx_detail.xml | 2
app/src/main/java/com/xw/yunwei/model/ClockInStatusModel.kt | 177
app/src/main/res/layout/item_protocol.xml | 22
app/src/main/java/com/xw/yunwei/ui/task/taskDetail/TaskDetailActivity.kt | 4
app/src/main/res/mipmap-xhdpi/ic_route_arrow.png | 0
app/src/main/res/mipmap-xhdpi/img_work_car_bg.png | 0
app/src/main/res/drawable/shape_gray11_bg_4.xml | 5
app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/maintain/MaintainDetailActivity.kt | 5
app/src/main/res/mipmap-hdpi/caricon.png | 0
app/src/main/res/layout/activity_check_in.xml | 77
common/src/main/res/layout/layout_empty_view2.xml | 22
app/src/main/java/com/xw/yunwei/ui/work/car/manage/CarAdapter.kt | 60
app/src/main/res/layout/activity_car_repair_detail.xml | 8
app/src/main/java/com/xw/yunwei/ui/widget/CustomRefreshLayout.kt | 37
app/src/main/java/com/xw/yunwei/ui/dialog/ApplyForReassignReasonDialog.kt | 140
app/src/main/res/layout/fragment_car_operations.xml | 107
app/src/main/java/com/xw/yunwei/net/TaskApi.kt | 21
common/src/main/res/layout/common_item_image_empty.xml | 2
app/src/main/res/layout/activity_cruise_check_in_mission_complete.xml | 212
app/src/main/java/com/xw/yunwei/ui/work/checkInMission/CruiseCheckInOperationActivity.kt | 145
app/src/main/java/com/xw/yunwei/model/CarModel.kt | 113
app/src/main/java/com/xw/yunwei/ui/task/list/TaskListAdapter.kt | 174
app/src/main/java/com/xw/yunwei/model/TaskNormalChargeModel.kt | 12
app/src/main/java/com/xw/yunwei/ui/user/mine/set/SetVM.kt | 22
app/src/main/java/com/xw/yunwei/ui/task/accident/handle/AccidentProcessVM.kt | 151
app/src/main/java/com/xw/yunwei/ui/work/checkInMission/util/Utils.java | 42
app/src/main/java/com/xw/yunwei/ui/common/WebActivity.kt | 72
app/src/main/java/com/xw/yunwei/ui/MainVM.kt | 25
app/src/main/res/mipmap-xhdpi/ic_apply_reassign_bg.png | 0
app/src/main/res/mipmap-xhdpi/icon_switch_off.png | 0
app/src/main/java/com/xw/yunwei/ui/work/car/detail/adapter/AcceptCarPointAdapter.kt | 40
app/src/main/java/com/xw/yunwei/ui/work/amap/util/BasicThreadFactory.java | 252
common/src/main/res/values/colors.xml | 2
app/src/main/java/com/xw/yunwei/ui/widget/DirectionRecyclerView.kt | 40
common/src/main/res/drawable/svg_filter2.xml | 33
app/src/main/res/mipmap-xxhdpi/ic_map_car_r.png | 0
app/src/main/res/drawable/selector_nav_task_accident.xml | 5
app/src/main/res/mipmap-xhdpi/ic_bicycle_gray.png | 0
app/src/main/java/com/xw/yunwei/model/SiteModel.kt | 7
app/src/main/java/com/xw/yunwei/utils/TTS.java | 29
app/src/main/res/layout/fragment_mine.xml | 1237 +-
app/src/main/java/com/xw/yunwei/ui/task/normal/NormalTaskDetailVM.kt | 260
app/src/main/res/drawable/selector_nav_task_all.xml | 5
app/src/main/res/drawable/shape_orange_1_bg_2.xml | 5
app/src/main/res/mipmap-xxhdpi/ic_map_site_r.png | 0
app/src/main/res/mipmap-xhdpi/ic_add_picture.png | 0
app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/OperationsFragment.kt | 15
app/src/main/res/drawable/shape_red_5_line_gray_3_bg_4.xml | 8
app/src/main/java/com/xw/yunwei/model/AcceptCarPointInfo.kt | 62
app/src/main/java/com/xw/yunwei/ui/work/car/detail/StandardDescriptionVM.kt | 7
app/src/main/res/mipmap-xhdpi/icon_circle_line_black.png | 0
app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/charge/ChargeCarActivity.kt | 54
app/src/main/java/com/xw/yunwei/ui/work/amap/util/NaviUtil.java | 120
app/src/main/res/layout/item_week_day.xml | 29
app/src/main/res/layout/layout_normal_task_status2.xml | 4
app/src/main/java/com/xw/yunwei/model/CarOperationRecordModel.kt | 9
app/src/main/res/mipmap-xhdpi/icon_date_empty.png | 0
app/src/main/java/com/xw/yunwei/model/CruiseCheckInOperationInfo.kt | 25
app/src/main/res/drawable/shape_red_1_bg_4.xml | 5
app/src/main/AndroidManifest.xml | 269
app/src/main/java/com/xw/yunwei/websocket/WebSocketClient.kt | 444 +
app/src/main/java/com/xw/yunwei/ui/work/checkInMission/util/AMapNaviListenerWrap.kt | 187
app/src/main/res/mipmap-xhdpi/icon_tick_double_rect2.png | 0
app/src/main/res/layout/activity_protocol.xml | 50
app/src/main/assets/iflytek/warning.png | 0
app/src/main/java/com/xw/yunwei/ui/task/selectCar/SelectCarVM.kt | 46
app/src/main/res/mipmap-xhdpi/ic_end_point.png | 0
app/src/main/java/com/xw/yunwei/model/TaskNormalModel.kt | 30
app/src/main/res/layout/activity_accident_detail.xml | 110
common/src/main/res/drawable/svg_car_chongdian.xml | 18
app/src/main/java/com/xw/yunwei/net/UserApi.kt | 19
app/src/main/res/drawable/selector_car_trunk.xml | 5
app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/SchedulingActivity.kt | 169
app/src/main/res/layout/activity_car_charge_detail.xml | 8
app/src/main/res/mipmap-xhdpi/img_work_report.png | 0
app/src/main/java/com/xw/yunwei/ui/user/mine/upload/CertUploadActivity.kt | 143
app/src/main/res/mipmap-xhdpi/icon_car_running.png | 0
app/src/main/res/mipmap-xhdpi/icon_car_order.png | 0
app/src/main/java/com/xw/yunwei/websocket/WebSocketConfig.kt | 13
app/src/main/res/layout/fragment_work.xml | 73
app/src/main/res/layout/item_check_in_mission_point.xml | 123
app/src/main/java/com/xw/yunwei/net/WorkRepository.kt | 92
common/src/main/java/com/xw/common/CommonDialog.kt | 236
app/src/main/res/mipmap-xhdpi/ic_task_item_left_three.png | 0
app/src/main/assets/iflytek/voice_bg.9.png | 0
app/src/main/res/mipmap-xhdpi/icon_location_blue.png | 0
app/build.gradle.kts | 75
app/src/main/res/layout/activity_create_task.xml | 95
app/src/main/java/com/xw/yunwei/utils/VibrateUtils.kt | 85
app/src/main/res/layout/layout_normal_task_status1.xml | 26
app/src/main/res/drawable/shape_0d31456a_0031456a_bg_4.xml | 8
app/src/main/res/drawable/shape_0d31456a_bg_8.xml | 5
app/src/main/java/com/xw/yunwei/model/TrunkLockStatusInfo.kt | 4
app/src/main/res/drawable/shape_while_bg_100.xml | 2
app/src/main/res/layout/dialog_car_filter.xml | 277
app/src/main/java/com/xw/yunwei/ui/widget/WatermarkDrawable.kt | 74
app/src/main/res/layout/item_pdf_entrance.xml | 36
app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/check/CheckCarActivity.kt | 225
app/src/main/res/drawable/img_site_bg.xml | 52
common/src/main/java/com/xw/common/viewAdapter/ViewAdapter.kt | 8
app/src/main/java/com/xw/yunwei/ui/common/WebVM.kt | 7
app/src/main/java/com/xw/yunwei/model/TaskStatisticInfo.kt | 12
app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/adapter/WeekPagerAdapter.kt | 95
app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/maintain/MaintainCarActivity.kt | 30
app/src/main/java/com/xw/yunwei/ui/work/site/SiteNavVM.kt | 27
app/src/main/java/com/xw/yunwei/ui/task/create/RightItemAdapter.kt | 29
app/src/main/res/drawable/shape_e5f0fc_bg_2.xml | 5
app/src/main/res/layout/dialog_site_filter.xml | 2
app/src/main/java/com/xw/yunwei/ui/work/car/detail/StandardDescriptionActivity.kt | 17
app/src/main/res/drawable/selector_task_bottom_nav.xml | 6
app/src/main/res/layout/activity_site_error_upload.xml | 247
app/src/main/res/mipmap-xhdpi/icon_ring_blue.png | 0
app/src/main/java/com/xw/yunwei/model/CarRecordCheckModel.kt | 9
app/src/main/res/drawable/shape_gray_4_line_gray_3_bg_4.xml | 8
app/src/main/res/layout/activity_cruise_check_in.xml | 526 +
app/src/main/assets/iflytek/voice_empty.png | 0
app/src/main/java/com/xw/yunwei/ui/task/create/CreateTaskActivity.kt | 384
app/src/main/java/com/xw/yunwei/model/CruiseCheckInMissionInfo.kt | 21
common/src/main/java/com/xw/common/TimeDialog.kt | 29
app/src/main/res/layout/item_work_site.xml | 220
app/src/main/res/drawable/svg_net_lock_gray.xml | 43
app/src/main/res/mipmap-xhdpi/ic_clock_note.png | 0
app/src/main/res/mipmap-xhdpi/ic_task_item_left_two.png | 0
app/src/main/java/com/xw/yunwei/ui/task/create/LeftCategoryAdapter.kt | 18
app/src/main/res/drawable/shape_blue1_00006be1_bg_4.xml | 7
app/src/main/assets/iflytek/recognize.xml | 0
app/src/main/res/layout/activity_find_psw.xml | 8
app/src/main/assets/iflytek/voice_full.png | 0
app/src/main/res/mipmap-xhdpi/ic_notice_blue.png | 0
README.md | 13
app/src/main/java/com/xw/yunwei/ui/work/CarAdapter.kt | 22
app/src/main/java/com/xw/yunwei/ui/user/mine/MineFragment.kt | 15
app/src/main/java/com/xw/yunwei/model/CarRecordRepairModel.kt | 21
app/src/main/java/com/xw/yunwei/Constants.kt | 9
app/src/main/res/drawable/shape_blue_1_bg_2.xml | 5
app/src/main/res/layout/activity_standard_description.xml | 1
app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/adapter/WeekDayAdapter.kt | 51
app/src/main/java/com/xw/yunwei/utils/SystemTTS.java | 113
app/src/main/java/com/xw/yunwei/ui/user/login/LoginActivity.kt | 336
common/src/main/res/mipmap/ic_slide_gray_r.png | 0
app/src/main/res/drawable/shape_red_1_bg_2.xml | 5
app/src/main/java/com/xw/yunwei/ui/task/TaskFragment.kt | 579
app/src/main/java/com/xw/yunwei/net/UserRepository.kt | 10
app/src/main/java/com/xw/yunwei/ui/work/amap/custom/view/CarOverlay.java | 292
app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/charge/ChargeCarVM.kt | 21
app/src/main/res/mipmap-xhdpi/ic_accident_one.png | 0
common/src/main/java/com/xw/common/base/ImageSelectAdapter.kt | 2
app/src/main/java/com/xw/yunwei/model/event/TaskEvent.kt | 7
app/src/main/res/layout/dialog_cruise_check_in_success.xml | 151
app/src/main/res/mipmap-xhdpi/img_work_map.png | 0
app/src/main/res/mipmap-xhdpi/ic_up.png | 0
app/src/main/res/layout/layout_infowindow.xml | 7
app/src/main/java/com/xw/yunwei/BaseBusinessActivity.kt | 77
app/src/main/res/drawable/ps_demo_blue_num_selector.xml | 5
settings.gradle.kts | 3
app/src/main/java/com/xw/yunwei/ui/user/mine/upload/CertUploadVM.kt | 60
app/src/main/java/com/xw/yunwei/ui/work/amap/util/IBuilder.java | 17
app/src/main/java/com/xw/yunwei/model/CruiseCheckInOperationResult.kt | 59
app/src/main/res/layout/activity_site_nav.xml | 518
app/src/main/res/layout/layout_normal_task_charge_detail.xml | 8
app/src/main/res/layout/item_accept_car_point.xml | 81
app/src/main/java/com/xw/yunwei/ui/task/selectCar/SelectCarAdapter.kt | 62
app/src/main/res/layout/dialog_apply_for_reassign_reason.xml | 62
app/src/main/res/layout/activity_car_charge.xml | 49
app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/adapter/DateWeekAdapter.kt | 44
app/src/main/java/com/xw/yunwei/ui/work/checkInMission/viewmodel/CruiseCheckInOperationViewModel.kt | 225
app/src/main/res/mipmap-xhdpi/ic_task_item_left_one.png | 0
app/src/main/res/mipmap-xhdpi/ic_close_black.png | 0
app/src/main/res/layout/activity_select_car.xml | 6
app/src/main/res/drawable/selector_nav_task_normal.xml | 5
app/src/main/java/com/xw/yunwei/model/TaskModel.kt | 19
app/libs/iflytek/arm64-v8a/libmsc.so | 0
app/src/main/res/mipmap-xhdpi/icon_clock_blue2.png | 0
app/src/main/res/mipmap-xhdpi/icon_car_stop_order.png | 0
app/src/main/res/drawable/shape_gray2_bg_4.xml | 5
app/src/main/res/mipmap-xhdpi/img_clock_out_s.png | 0
app/src/main/java/com/xw/yunwei/push/PopupPushActivity.kt | 154
common/src/main/res/mipmap-xhdpi/icon_default4.png | 0
app/src/main/res/layout/activity_route_planning.xml | 232
app/src/main/res/drawable/shape_ccffffff_bg_80ffffff_line_30.xml | 8
app/src/main/res/layout/layout_normal_task_car_repair_detail.xml | 8
app/src/main/res/mipmap-xhdpi/ic_accident_two.png | 0
app/src/main/res/layout/item_picture_operation.xml | 23
app/src/main/res/layout/activity_login.xml | 37
common/src/main/java/com/xw/common/utils/GlideEngine.java | 42
app/src/main/res/layout/activity_scheduling.xml | 263
app/src/main/java/com/xw/yunwei/ui/work/checkInMission/viewmodel/CheckInMissionPointsListViewModel.kt | 82
app/src/main/java/com/xw/yunwei/ui/dialog/CruiseCheckInSuccessDialog.kt | 87
common/src/main/java/com/xw/common/custom/ShowTextLinearLayout.kt | 8
app/src/main/java/com/xw/yunwei/ui/work/checkInMission/viewmodel/CruiseCheckInMissionCompleteViewModel.kt | 17
app/src/main/java/com/xw/yunwei/ui/work/car/manage/CarManageActivity.kt | 109
app/src/main/java/com/xw/yunwei/model/CarRecordCleanModel.kt | 6
app/src/main/res/xml/network_security_config.xml | 10
app/src/main/java/com/xw/yunwei/ui/MainActivity.kt | 135
app/src/main/res/mipmap-xhdpi/ic_down.png | 0
app/src/main/java/com/xw/yunwei/model/VehicleLocationInfo.kt | 1
app/src/main/java/com/xw/yunwei/extension/ActivityExtension.kt | 15
app/src/main/java/com/xw/yunwei/ui/work/site/adapter/PictureOperationAdapter.kt | 29
app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/charge/ChargeDetailActivity.kt | 4
app/src/main/res/values/attrs.xml | 59
app/src/main/res/layout/layout_normal_task_car_clear.xml | 2
app/src/main/java/com/xw/yunwei/model/RoutePlanningOperationInfo.kt | 12
app/src/main/res/layout/layout_normal_task_check_detail.xml | 16
app/src/main/java/com/xw/yunwei/ui/work/AMapFragment.kt | 65
common/src/main/res/layout/dialog_notice.xml | 77
app/src/main/res/layout/activity_car_maintain.xml | 47
app/src/main/res/layout/activity_car_report.xml | 73
app/src/main/res/mipmap-xhdpi/icon_arrow_blue.png | 0
app/src/main/java/com/xw/yunwei/ui/user/login/LoginVM.kt | 213
app/src/main/java/com/xw/yunwei/ui/work/car/detail/management/report/CarReportActivity.kt | 54
app/src/main/res/layout/dialog_new_task.xml | 233
app/src/main/java/com/xw/yunwei/ui/task/create/CreateTaskVM.kt | 81
app/src/main/res/drawable/shape_white_bg_8.xml | 5
app/src/main/res/layout/activity_car_maintain_detail.xml | 6
app/src/main/res/mipmap-xhdpi/icon_tick_double_rect.png | 0
app/src/main/java/com/xw/yunwei/extension/ViewExtension.kt | 174
app/src/main/res/layout/layout_normal_task_car_nj_or_by_or_bx.xml | 54
app/src/main/res/mipmap-xhdpi/ic_bicycle_blue.png | 0
common/src/main/java/com/xw/common/custom/ClassicsFooter11.java | 2
app/src/main/res/layout/dialog_select_confirm_accept_car_point.xml | 41
app/src/main/res/mipmap-hdpi/navi_direction.png | 0
app/src/main/res/layout/layout_car_repair_send.xml | 65
app/src/main/java/com/xw/yunwei/ui/work/site/SiteNavActivity.kt | 160
app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/RepairCarActivity.kt | 59
app/src/main/res/mipmap-xhdpi/icon_tick_green.png | 0
app/src/main/res/mipmap-xhdpi/ic_pass_point.png | 0
app/src/main/res/drawable/circle_gray_6.xml | 6
app/src/main/java/com/xw/yunwei/model/CertificateAuditInfo.kt | 31
app/src/main/res/mipmap-xhdpi/icon_circle_gray.png | 0
app/src/main/res/mipmap-xhdpi/icon_tick_circle_blue.png | 0
app/src/main/res/drawable/layer_list_green_progress_bar.xml | 20
app/src/main/res/drawable/shape_red_5_bg_white_line_20.xml | 8
common/src/main/java/com/xw/common/SecureScreenShot.kt | 85
app/src/main/res/drawable/ps_demo_blue_num_selected.xml | 10
app/src/main/java/com/xw/yunwei/model/CarRecordChargeModel.kt | 14
common/src/main/res/drawable/shape_black_bg_8.xml | 2
common/src/main/res/layout/dialog_loading.xml | 9
app/src/main/res/layout/item_task_content.xml | 421
app/src/main/java/com/xw/yunwei/net/TaskRepository.kt | 52
app/src/main/java/com/xw/yunwei/ui/work/checkInMission/CheckInMissionPointsListActivity.kt | 73
app/src/main/res/mipmap-xhdpi/icon_close_gray.png | 0
common/src/main/res/mipmap-xhdpi/icon_default5.png | 0
app/src/main/res/layout/activity_normal_task_detail.xml | 18
common/src/main/res/drawable/shape_while_bg_8.xml | 5
app/src/main/java/com/xw/yunwei/ui/user/mine/info/UserInfoActivity.kt | 3
app/src/main/res/mipmap-xhdpi/icon_car_working.png | 0
.gitignore | 16
app/src/main/res/mipmap-xhdpi/icon_circle_ring_blue.png | 0
app/src/main/java/com/xw/yunwei/model/CarRecordMaintainModel.kt | 6
app/src/main/java/com/xw/yunwei/ui/task/accident/detail/AccidentDetailVM.kt | 294
app/src/main/res/mipmap-xhdpi/icon_note_tick_circle.png | 0
app/src/main/res/drawable/svg_car_trunk_closed.xml | 29
app/src/main/java/com/xw/yunwei/model/TaskNormalMaintainModel.kt | 8
app/src/main/java/com/xw/yunwei/ui/user/mine/checkin/CheckInActivity.kt | 40
app/src/main/res/drawable/ps_demo_blue_num_normal.xml | 13
app/src/main/java/com/xw/yunwei/ui/user/mine/info/UserInfoVM.kt | 4
app/src/main/java/com/xw/yunwei/ui/user/mine/protocol/adapter/ProtocolEntranceAdapter.kt | 13
app/src/main/res/mipmap-xhdpi/ic_tick_green.png | 0
app/src/main/res/drawable/circle_blue_5.xml | 6
app/src/main/res/layout/activity_car_check.xml | 448
app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/SchedulingVM.kt | 62
app/src/main/res/layout/layout_normal_task_car_clear_detail.xml | 2
app/src/main/res/mipmap-xhdpi/ic_work_quche.png | 0
app/src/main/java/com/xw/yunwei/ui/work/checkInMission/adapter/CheckInMissionPointAdapter.kt | 66
app/src/main/java/com/xw/yunwei/ui/task/taskSub/TaskSubActivity.kt | 4
app/src/main/res/drawable/shape_gray_5_bg_4.xml | 5
app/src/main/res/mipmap-xhdpi/ic_close_black2.png | 0
app/src/main/res/mipmap-xhdpi/icon_location_green.png | 0
app/src/main/res/layout/item_protocol_entrance.xml | 39
app/src/main/res/mipmap-xhdpi/icon_note_tick_circle2.png | 0
app/src/main/java/com/xw/yunwei/model/TaskAccidentModel.kt | 35
app/src/main/res/layout/layout_normal_task_maintain_detail.xml | 2
app/src/main/java/com/xw/yunwei/ui/user/mine/protocol/ProtocolActivity.kt | 108
app/src/main/res/mipmap-xhdpi/img_work_car.png | 0
common/src/main/res/drawable/svg_car_weixiu.xml | 18
app/src/main/res/mipmap-xhdpi/icon_close_red.png | 0
app/src/main/java/com/xw/yunwei/extension/NumExtension.kt | 18
common/src/main/res/mipmap-xhdpi/icon_default2.png | 0
app/src/main/res/mipmap-xhdpi/ic_walk_gray.png | 0
common/src/main/res/drawable/svg_car_qingjie.xml | 46
app/src/main/res/mipmap-xhdpi/ic_filter_task2.png | 0
app/src/main/java/com/xw/yunwei/model/CheckInMissionPointInfo.kt | 45
app/src/main/java/com/xw/yunwei/ui/dialog/SelectConfirmAcceptCarPointDialog.kt | 71
app/src/main/java/com/xw/yunwei/ui/work/notice/NoticeActivity.kt | 6
app/src/main/res/drawable/shape_gray_5_line_4.xml | 8
app/libs/iflytek/armeabi-v7a/libmsc.so | 0
app/src/main/java/com/xw/yunwei/ui/user/mine/MineVM.kt | 101
app/src/main/java/com/xw/yunwei/utils/ICallBack.java | 19
common/build.gradle.kts | 3
app/src/main/res/layout/activity_cruise_check_in_operation.xml | 283
app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/check/CheckCarDetailActivity.kt | 4
app/src/main/java/com/xw/yunwei/utils/PictureSelectorFactory.kt | 47
app/src/main/res/layout/dialog_accident_filter.xml | 53
app/src/main/res/layout/item_car_repair.xml | 3
app/src/main/java/com/xw/yunwei/ui/task/TaskVM.kt | 166
app/src/main/res/layout/activity_web.xml | 54
app/src/main/res/layout/activity_car_clean_detail.xml | 2
app/libs/iflytek/Msc.jar | 0
app/proguard-rules.pro | 21
app/src/main/res/drawable/selector_gray2_to_blue1_bg_4.xml | 6
app/src/main/res/layout/dialog_confirm_accept_car_point.xml | 101
app/src/main/java/com/xw/yunwei/ui/work/checkInMission/viewmodel/CruiseCheckInViewModel.kt | 146
app/src/main/java/com/xw/yunwei/ui/work/checkInMission/RoutePlanningActivity.kt | 566 +
app/src/main/java/com/xw/yunwei/ui/work/site/SiteAdapter.kt | 29
app/src/main/res/mipmap-xhdpi/icon_switch_on.png | 0
common/src/main/java/com/xw/common/custom/SlideButtonView.kt | 10
app/src/main/java/com/xw/yunwei/ui/work/car/detail/CarDetailActivity.kt | 12
app/src/main/java/com/xw/yunwei/model/TaskNormalCheckModel.kt | 10
app/src/main/java/com/xw/yunwei/ui/task/normal/NormalTaskDetailActivity.kt | 94
app/src/main/res/mipmap-xhdpi/icon_circle_gray2.png | 0
app/src/main/res/mipmap-xhdpi/icon_map_arrow_blue.png | 0
app/src/main/res/layout/item_select_car.xml | 6
app/src/main/java/com/xw/yunwei/ui/task/accident/detail/AccidentDetailActivity.kt | 131
app/src/main/java/com/xw/yunwei/ui/work/car/detail/management/ManagementFragment.kt | 27
app/src/main/java/com/xw/yunwei/ui/work/site/SiteErrorUploadActivity.kt | 132
app/src/main/res/mipmap-xhdpi/ic_walk_blue.png | 0
app/src/main/res/layout/activity_set.xml | 9
app/src/main/res/mipmap-xxhdpi/ic_map_car_g.png | 0
app/src/main/res/layout/dialog_data_filter.xml | 40
app/src/main/java/com/xw/yunwei/constants/Key.kt | 15
app/src/main/java/com/xw/yunwei/ui/widget/CircleProgressView.kt | 234
app/src/main/java/com/xw/yunwei/utils/IFlyTTS.java | 161
app/src/main/java/com/xw/yunwei/utils/HtmlSanitizer.kt | 229
app/src/main/res/layout/activity_check_in_mission_points_list.xml | 85
app/src/main/res/layout/activity_cert_upload.xml | 740 +
app/src/main/java/com/xw/yunwei/ui/task/list/TaskListFragment.kt | 133
common/src/main/res/mipmap-xhdpi/icon_default3.png | 0
app/src/main/java/com/xw/yunwei/ui/work/site/viewmodel/SiteErrorUploadVM.kt | 199
common/src/main/res/drawable/svg_car_zhengbei.xml | 18
app/src/main/java/com/xw/yunwei/push/MessageHandler.kt | 448
app/src/main/java/com/xw/yunwei/model/UploadModel.kt | 7
app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/check/CheckCarVM.kt | 47
app/src/main/res/mipmap-xhdpi/icon_car_exception.png | 0
app/src/main/res/mipmap-xhdpi/ic_cup_book.png | 0
app/src/main/java/com/xw/yunwei/extension/StringExtension.kt | 14
app/src/main/java/com/xw/yunwei/ui/work/car/manage/CarManageVM.kt | 19
common/src/main/res/values/attrs.xml | 4
app/src/main/res/layout/fragment_car_management.xml | 11
app/src/main/java/com/xw/yunwei/ui/dialog/ConfirmAcceptCarPointDialog.kt | 61
common/src/main/java/com/xw/common/utils/MMKVManager.kt | 1
app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/RepairCarDetailActivity.kt | 6
app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/record/RepairRecordActivity.kt | 19
app/src/main/res/layout/layout_car_repair_get.xml | 12
app/src/main/res/layout/activity_accident_process.xml | 200
app/src/main/java/com/xw/yunwei/ui/widget/WatermarkView.kt | 114
common/src/main/java/com/xw/common/utils/GpsHelper.kt | 74
app/src/main/res/mipmap-xhdpi/icon_note_triangle.png | 0
app/src/main/res/layout/activity_car_clean.xml | 17
app/src/main/res/mipmap-xhdpi/icon_warn_red.png | 0
app/src/main/res/drawable/layer_list_orange_progress_bar.xml | 20
app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/RepairCarVM.kt | 2
app/src/main/res/mipmap-xhdpi/icon_arrow_left_blue.png | 0
app/src/main/res/layout/fragment_record_list.xml | 3
app/src/main/java/com/xw/yunwei/ui/user/mine/set/SetActivity.kt | 86
app/src/main/java/com/xw/yunwei/utils/TTSController.java | 142
app/src/main/res/mipmap-xxhdpi/ic_map_site_g.png | 0
app/src/main/res/drawable/shape_fdedeb_bg_2.xml | 5
app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/record/RecordAdapter.kt | 2
app/src/main/java/com/xw/yunwei/ui/task/accident/handle/AccidentProcessActivity.kt | 328
app/src/main/res/layout/item_date_week.xml | 148
app/src/main/res/layout/item_accident_right_filter.xml | 4
app/src/main/res/drawable/shape_green_1_bg_2.xml | 5
app/src/main/assets/iflytek/waiting.png | 0
common/src/main/java/com/xw/common/custom/SlideSwitchView.kt | 91
common/src/main/java/com/xw/common/utils/BindUtils.kt | 18
app/src/main/res/mipmap-xhdpi/icon_close2.png | 0
app/src/main/res/layout/layout_normal_task_car_repair.xml | 2
app/src/main/res/mipmap-xhdpi/ic_accident_three.png | 0
app/src/main/java/com/xw/yunwei/ui/work/car/detail/dispatch/DispatchFragment.kt | 257
common/src/main/res/drawable/svg_car_jiance.xml | 34
/dev/null | 0
app/src/main/java/com/xw/yunwei/model/LoginModel.kt | 9
app/src/main/java/com/xw/yunwei/websocket/IWebSocketListener.kt | 54
417 files changed, 21,348 insertions(+), 4,840 deletions(-)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..bd4c41d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,16 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/app/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..8cbe50e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,13 @@
+# xp-robotaxi-maintenance-app
+
+## 约束
+- 语言:Kotlin 1.9.20 以上
+- agp & gradle:8.2 以上,不要用9以上
+- minSdkVersion 26
+- targetSdkVersion 35及以上
+- java 17
+- 业务框架推荐 MVVM + jetpack Compose
+- 模块化
+- 自定义类, 全面要求使用 kotlin 语言, 禁止使用 java 语言
+- 禁止使用 EventBus 全局事件总线库, 要求使用新范式: LiveData/StateFlow/ViewModel
+- 移除 utilcodex 库(已停止维护,且跟 kt/AndroidX 有重叠工具类)
\ No newline at end of file
diff --git a/README.txt b/README.txt
deleted file mode 100644
index 80ef8ec..0000000
--- a/README.txt
+++ /dev/null
@@ -1 +0,0 @@
-小鹏运维app
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 77f0cfa..9d38811 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,3 +1,6 @@
+import java.text.SimpleDateFormat
+import java.util.Date
+
apply(plugin = "com.huawei.agconnect")
plugins {
alias(libs.plugins.android.application)
@@ -7,9 +10,6 @@
}
val APPLICATION_ID = "com.xw.yunwei"
-// 阿里云推送
-val PUSH_KEY = "335666352"
-val PUSH_SECRET = "0252ebde2dc84f63aebd41f757f213d7"
android {
namespace = APPLICATION_ID
@@ -25,12 +25,23 @@
ndk {
// 选择要添加的对应cpu类型的.so库。此处仅为示意,推送支持所有主流类型,请根据实际需求选择
- abiFilters.addAll(listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64"))
+ abiFilters.addAll(listOf("arm64-v8a", "armeabi-v7a"))//, "x86", "x86_64"
}
+ vectorDrawables.useSupportLibrary = true
- buildConfigField("String", "PUSH_KEY", "\"${PUSH_KEY}\"")
- buildConfigField("String", "PUSH_SECRET", "\"${PUSH_SECRET}\"")
-
+ // 华为
+ manifestPlaceholders["PUSH_HW_CLIENT_ID"] = "117680933"
+ manifestPlaceholders["PUSH_HW_CLIENT_SECRET"] = "1c18a9c784ff6e47242af5a60e3d22c658b0d76757ede5ba4e15ee329cab8d4a"
+ // 荣耀
+ manifestPlaceholders["PUSH_RY_APP_ID"] = "104570357"
+ manifestPlaceholders["PUSH_RY_APP_SECRET"] = "67f554e43f744e89fed9d09ca21c0cfa584665ba56af0d6f46c11af2434e577d"
+ // VIVO
+ manifestPlaceholders["PUSH_VV_APP_ID"] = "106095676"
+ manifestPlaceholders["PUSH_VV_APP_KEY"] = "27f39e188ef0acce7fd7de80dc9edb55"
+ manifestPlaceholders["PUSH_VV_APP_SECRET"] = "23a58cd0-9a17-418c-bdcc-236fafe8692a"
+ // OPPO
+ buildConfigField("String", "PUSH_OP_APP_KEY", "\"3a308dc2996f44b78400f0e48500616d\"")
+ buildConfigField("String", "PUSH_OP_APP_SECRET", "\"dbc906a01ff944009482d2b4cc549563\"")
}
signingConfigs {
@@ -83,15 +94,16 @@
manifestPlaceholders["APP_NAME"] = "@string/app_name_dev"
manifestPlaceholders["icon"] = "@mipmap/ic_launcher"
- buildConfigField("String", "DEV_API_HOST", "\"\"")
+ buildConfigField("String", "DEV_API_HOST", "\"http://221.182.45.100:8000/\"")
buildConfigField("String", "API_HOST", "\"http://rt-admin.test.xiaopeng.local/\"")
- buildConfigField("String", "WS_URL", "\"ws://221.182.45.100:8888/websocket\"")
+ buildConfigField("String", "DEV_WS_URL", "\"ws://221.182.45.100:8888/websocket\"")
+ buildConfigField("String", "WS_URL", "\"ws://rt-admin.test.xiaopeng.local/websocket\"")
//翼虎appId
- buildConfigField("String", "YIHU_APPID", "\"RoboTaxi-admin-test\"")
+ buildConfigField("String", "YIHU_APPID", "\"RoboTaxi-admin\"")
//翼虎appSecret
- buildConfigField("String", "YIHU_APP_SECRET", "\"SXa7vEe7V23Xh3RN\"")
+ buildConfigField("String", "YIHU_APP_SECRET", "\"9UvdqMuZRRTNcpeA\"")
//翼虎公钥
- buildConfigField("String", "YIHU_PUBLIC_KEY", "\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjT9Pl5kqJeinJyAjvW95ulxtON34ABhX pTRiPczVRJSVSTQzqLyr6UNRU6AvR2diZ4eGRHbeJ+NNtiuSverAZ+xu4B05xWhERThV0SETigkR 9IaJ9glucmAL6S6CNE5JCwWYYDfCgSIN3fzWhC48hGwEL8nauBIHrg2TRs0x4/rtmUR5oEMrm6RA eafdHDD62Dtsc7zm7uIxaOfn90cG35DKsp3iIcw7BLFT/HmBSVML2SLTruNkgDhH2qIZ1t6YQEJj C0uO+jiHXoluKRLWDMg9+SuoJHrsntCzRdwx246g6nMKfxtyC/jrPB6KUdrSR9xaxXZPcNQLb0ip y6mTkwIDAQAB\"")
+ buildConfigField("String", "YIHU_PUBLIC_KEY", "\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAko2oXAtrtl2BGUZjjDZBbEtbYd8pddah hqTbQ68F59no7eZGdfE4PQyKnPZTJSR0XApwydqB6nKEID58bej3F7p/2mL7i/s9+9zdepMSpg9b 1nTi730Fs1pzEalew7V839/Wg/RPFr6xZEqU8oaKWT6fe4anRAOI7aCgA8CxEB8YwQvrMTYetFnE QRGHlziKKDHmurKXToGdu2SSXzYLy8Cl2X79z3rBUBQpMZI63g93wcRIToSP8DUkbQFY64cXa6cT ZyBrt72K2Dx4IfuLb7K1BZbZxXswN/Lx4rQ7anQ8HFtA5bE7sNznj16pgoI3aUKjVm45JWtxTAWa XrSwTQIDAQAB\"")
//翼虎网络域名
buildConfigField("String", "YIHU_API_HOST", "\"https://sso.test.xiaopeng.com/sso/\"")
}
@@ -104,13 +116,14 @@
buildConfigField("String", "DEV_API_HOST", "\"\"")
buildConfigField("String", "API_HOST", "\"https://rt-mt.deploy-test.xiaopeng.com/\"")
- buildConfigField("String", "WS_URL", "\"ws://192.168.110.188:8888/websocket\"")
+ buildConfigField("String", "DEV_WS_URL", "\"\"")
+ buildConfigField("String", "WS_URL", "\"wss://rt-ws.deploy-test.xiaopeng.com/websocket\"")
//翼虎appId
- buildConfigField("String", "YIHU_APPID", "\"RoboTaxi-admin-predeploy\"")
+ buildConfigField("String", "YIHU_APPID", "\"RoboTaxi-admin\"")
//翼虎appSecret
- buildConfigField("String", "YIHU_APP_SECRET", "\"i6B5t4744XzO9Ed4\"")
+ buildConfigField("String", "YIHU_APP_SECRET", "\"FcJ8gsdgaTKsIhD4\"")
//翼虎公钥
- buildConfigField("String", "YIHU_PUBLIC_KEY", "\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvvLduJASaa//KZNaVOH7ieU9QlMs/XxN CRBfFKAtWdwAGtaEnGoAdVJ+6c5dRICVm65Nbq0Xu4jqmdyZceUgWkXjBnxCRNCF0KT5HP6f08XS maDlWXXGDcE3ybZ9rhjwAplAJXoDHjLIi8aklI8qY6G5qUIPX+Occun5xhmiVDTKoyAkNFZ+n1K7 pVc+0rYzownPrGo4Yg+BmSJPoigxJJVZeVZ91jOiwt7F8jyE6EDmTQItJaElFF/zCbY6JlE3Ftsg HjkP/2lFDp+xMZi6b//BvB/GctWmLhkgFZ7j1PtH2Q5YKUzz8Ko6FhAkLaP7K7LXFfkQ1edOrygn 5XRuxQIDAQAB\"")
+ buildConfigField("String", "YIHU_PUBLIC_KEY", "\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm4xWZvcXI4Ae8RbhvjwKclShdhxYjnGXkLaHNmAp1npExV3XaQygAyCd9HXrjPOkCQoTOfk7LiUL35RarAqurHuSk/PArOmOBiAe+8KjeQuoVTINX43bYCgZhBpDWURbANQYsA5Sw6OkjsjFtvFbwrYackSKqwtwOpeXCTrL/X+KmQJb1sMEHfaHGv3XStX4Hl98/vTJpysXANqiszuL6Pvd4zl1zZpkdzirCq6N1Hl5YgAZtmrHP5vu41iMChpZBnvG+yNWBfVqTFDiW+C1vpWmO2WSw3QnIsWDsXuoCRhL8zaw2zQG1u1wSeuWN9hJng4h8nWULSv7gTHTXwTgDQIDAQAB\"")
//翼虎网络域名
buildConfigField("String", "YIHU_API_HOST", "\"https://sso-xt.deploy-test.xiaopeng.com/sso/\"")
}
@@ -123,13 +136,14 @@
buildConfigField("String", "DEV_API_HOST", "\"\"")
buildConfigField("String", "API_HOST", "\"https://rt-mt.xiaopeng.com/\"")
- buildConfigField("String", "WS_URL", "\"ws://192.168.110.188:8888/websocket\"")
+ buildConfigField("String", "DEV_WS_URL", "\"\"")
+ buildConfigField("String", "WS_URL", "\"wss://rt-ws.xiaopeng.com/websocket\"")
//翼虎appId
- buildConfigField("String", "YIHU_APPID", "\"xx\"")
+ buildConfigField("String", "YIHU_APPID", "\"RoboTaxi-admin\"")
//翼虎appSecret
- buildConfigField("String", "YIHU_APP_SECRET", "\"xx\"")
+ buildConfigField("String", "YIHU_APP_SECRET", "\"ctSuxCrDXi1qeQfi\"")
//翼虎公钥
- buildConfigField("String", "YIHU_PUBLIC_KEY", "\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3O+kbGNL8OsgS8ejbYh7MLxwr6dzrvE4euAcUn+Yk8H5aCgkd7tSCYntd8iQZoml1japizdB8MedJeMZZGeuNLXcHMpf+OmBA//ms3SG6aiocgxruHuHDVkVri/2rTuo078OsHaqnCJlvYEwbuuGj3D3So+TFz/Cw67ipL++j9z90tec40kzNebdfWG12Bv3uX+U8a34QhwE95+uKgwfCU8JEFqXWmA3KAV0COCL4glf3eioe5dBmpBvgnOwauepthjfOKPNqfGqHN88/WTgOHuQraWs9YY4QeYk5s+2CXVWMNlX++r83otgcfzMKmEdToQAHvfLRM4W4I1qaTKR8wIDAQAB\"")
+ buildConfigField("String", "YIHU_PUBLIC_KEY", "\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0tfVskBwiwMFPwt3UCAKaenpVnLjR0Fs dH5Kf+Wr/35cOyzpWlK3SY6HdOZRPszGkQDEUJMNTYyU40WLLUQgGfqlSao1ya4tIcPRKgocDF+v TjizUv7t0Fd41I5ELzhYdMZiFg22/og+mqlKigw6yiIDAcdLXiAym5YJW4Xa/ZUAkMuOdZH7AYOV B+ru04teRlPUNKk//kx7eryIE1cbXix+ux+dT0/wGym7X+uFg8N2GGOz7jl4XlTcF2CTpAGJa1KN OPM39sZjp2j5OADI0K7NIqCg68OhVcuC31QCCyJgnbpUaVuV0bagvsHHVsJeVvg9HHtIc4t5X7cM j4DsIQIDAQAB\"")
//翼虎网络域名
buildConfigField("String", "YIHU_API_HOST", "\"https://xpsso.xiaopeng.com/sso/\"")
}
@@ -139,14 +153,21 @@
val flavor = flavorName.ifBlank { "default" }
outputs.configureEach {
if (this is com.android.build.gradle.internal.api.BaseVariantOutputImpl) {
- outputFileName = "小鹏RT运维-$flavor-${buildType.name}-${versionName}-${versionCode}.apk"
+ outputFileName =
+ "小鹏RT运维-$flavor-${buildType.name}-${versionName}-${versionCode}-${SimpleDateFormat("yyyy-MM-dd").format(Date())}.apk"
}
}
}
-
+ sourceSets {
+ getByName("main") {
+ jniLibs.srcDirs("libs/iflytek")
+ }
+ }
}
dependencies {
+ implementation(libs.androidx.activity.ktx)
+ implementation(fileTree("libs/iflytek") { include("*.jar") })
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.activity)
@@ -155,10 +176,18 @@
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
- implementation("com.aliyun.ams:alicloud-android-push:3.10.1")
+ implementation(libs.shadowLayout)
implementation(project(":common"))
implementation(libs.dialog.pickerview)
implementation(libs.huawei.agconnect.core)
+ implementation(libs.jsoup)
+
+ implementation(libs.alicloud)
+ implementation(libs.alicloud.android.third.push)
+ implementation(libs.alicloud.android.third.push.huawei)
+ implementation(libs.alicloud.android.third.push.honor)
+ implementation(libs.alicloud.android.third.push.oppo)
+ implementation(libs.alicloud.android.third.push.vivo)
}
diff --git a/app/libs/iflytek/Msc.jar b/app/libs/iflytek/Msc.jar
new file mode 100644
index 0000000..9f11d84
--- /dev/null
+++ b/app/libs/iflytek/Msc.jar
Binary files differ
diff --git a/app/libs/iflytek/arm64-v8a/libmsc.so b/app/libs/iflytek/arm64-v8a/libmsc.so
new file mode 100644
index 0000000..d4e8d91
--- /dev/null
+++ b/app/libs/iflytek/arm64-v8a/libmsc.so
Binary files differ
diff --git a/app/libs/iflytek/armeabi-v7a/libmsc.so b/app/libs/iflytek/armeabi-v7a/libmsc.so
new file mode 100644
index 0000000..0ad5471
--- /dev/null
+++ b/app/libs/iflytek/armeabi-v7a/libmsc.so
Binary files differ
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 481bb43..4a15998 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -18,4 +18,23 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
-#-renamesourcefileattribute SourceFile
\ No newline at end of file
+#-renamesourcefileattribute SourceFile
+# 华为通道
+-keep class com.huawei.** {*;}
+-dontwarn com.huawei.**
+
+# 荣耀通道
+-ignorewarnings
+-keepattributes *Annotation*
+-keepattributes Exceptions
+-keepattributes InnerClasses
+-keepattributes Signature
+-keepattributes SourceFile,LineNumberTable
+-keep class com.hihonor.push.**{*;}
+
+# OPPO通道
+-keep public class * extends android.app.Service
+
+# VIVO通道
+-keep class com.vivo.** {*;}
+-dontwarn com.vivo.**
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 0c265f7..fff73da 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,22 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
-
- <!--允许访问网络,必选权限-->
- <uses-permission android:name="android.permission.INTERNET" />
- <!--允许获取粗略位置,若用GPS实现定位小蓝点功能则必选-->
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
- <!--允许获取精准位置-->
- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
- <!--允许获取网络状态,用于网络定位,若无gps但仍需实现定位小蓝点功能则此权限必选-->
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <!--允许获取wifi网络信息,用于网络定位,若无gps但仍需实现定位小蓝点功能则此权限必选-->
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
- <!--允许获取wifi状态改变,用于网络定位,若无gps但仍需实现定位小蓝点功能则此权限必选-->
- <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
- <!--允许写设备缓存,用于问题排查-->
+ <!-- 允许访问网络,必选权限 -->
+ <uses-permission android:name="android.permission.INTERNET" /> <!-- 允许获取粗略位置,若用GPS实现定位小蓝点功能则必选 -->
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- 允许获取精准位置 -->
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- 允许获取网络状态,用于网络定位,若无gps但仍需实现定位小蓝点功能则此权限必选 -->
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 允许获取wifi网络信息,用于网络定位,若无gps但仍需实现定位小蓝点功能则此权限必选 -->
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- 允许获取wifi状态改变,用于网络定位,若无gps但仍需实现定位小蓝点功能则此权限必选 -->
+ <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <!-- 允许写设备缓存,用于问题排查 -->
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
-
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-feature
@@ -24,157 +16,241 @@
android:required="false" />
<uses-permission android:name="android.permission.CAMERA" />
-
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
-
- <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
- <!--Android 13版本适配,细化存储权限-->
+ <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" /> <!-- Android 13版本适配,细化存储权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
- <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
- <!--允许通知权限-->
- <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
- <!-- 普通震动 -->
+ <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <!-- 允许通知权限 -->
+ <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <!-- 普通震动 -->
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:name=".MyApp"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
- android:fullBackupContent="@xml/backup_rules"
android:extractNativeLibs="true"
- android:requestLegacyExternalStorage="true"
+ android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/img_logo"
android:label="${APP_NAME}"
android:networkSecurityConfig="@xml/network_security_config"
+ android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/img_logo"
android:supportsRtl="true"
android:theme="@style/Theme.Yunwei">
-
+ <activity
+ android:name=".ui.common.WebActivity"
+ android:exported="false" />
+ <activity
+ android:name=".ui.work.checkInMission.CruiseCheckInMissionCompleteActivity"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:exported="false"
+ android:screenOrientation="portrait" />
+ <activity
+ android:name=".ui.work.checkInMission.CruiseCheckInOperationActivity"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:exported="false"
+ android:screenOrientation="portrait" />
+ <activity
+ android:name=".ui.work.checkInMission.CruiseCheckInActivity"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:exported="false"
+ android:screenOrientation="portrait" />
+ <activity
+ android:name=".ui.work.checkInMission.RoutePlanningActivity"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:exported="false"
+ android:screenOrientation="portrait" />
+ <activity
+ android:name=".ui.work.checkInMission.CheckInMissionPointsListActivity"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:exported="false"
+ android:screenOrientation="portrait" />
+ <activity
+ android:name=".ui.work.site.SiteErrorUploadActivity"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:exported="false"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.user.login.LoginActivity"
- android:exported="true">
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:exported="true"
+ android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
+
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
-
<activity
android:name=".ui.MainActivity"
- android:launchMode="singleTask" />
-
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTask"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.user.login.FindPswActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.user.mine.info.UserInfoActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.user.mine.upload.CertUploadActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.user.mine.set.SetActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.user.mine.scheduling.SchedulingActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.user.mine.checkin.CheckInActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.user.mine.protocol.ProtocolActivity"
- android:launchMode="singleTop" />
-
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.work.notice.NoticeActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.work.car.manage.CarManageActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.work.car.detail.CarDetailActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.work.car.detail.operations.clean.CleanCarActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.work.car.detail.operations.clean.CleanCarDetailActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.work.car.detail.operations.check.CheckCarActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.work.car.detail.operations.check.CheckCarDetailActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.work.car.detail.operations.charge.ChargeCarActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.work.car.detail.operations.charge.ChargeDetailActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.work.car.detail.operations.repair.RepairCarActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.work.car.detail.operations.repair.RepairCarDetailActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.work.car.detail.operations.maintain.MaintainCarActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.work.car.detail.operations.maintain.MaintainDetailActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.work.car.detail.operations.repair.record.RepairRecordActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.work.car.detail.management.report.CarReportActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.work.car.detail.StandardDescriptionActivity"
- android:launchMode="singleTop" />
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
android:name=".ui.work.site.SiteNavActivity"
- android:launchMode="singleTop" />
-
-
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait"
+ android:windowSoftInputMode="adjustResize" />
<activity
- android:name="com.xw.yunwei.ui.task.normal.NormalTaskDetailActivity"
- android:launchMode="singleTop" />
+ android:name=".ui.task.normal.NormalTaskDetailActivity"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
- android:name="com.xw.yunwei.ui.task.selectCar.SelectCarActivity"
- android:launchMode="singleTop" />
+ android:name=".ui.task.selectCar.SelectCarActivity"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
- android:name="com.xw.yunwei.ui.task.create.CreateTaskActivity"
- android:launchMode="singleTop" />
+ android:name=".ui.task.create.CreateTaskActivity"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
- android:name="com.xw.yunwei.ui.task.accident.detail.AccidentDetailActivity"
- android:launchMode="singleTop" />
+ android:name=".ui.task.accident.detail.AccidentDetailActivity"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
- android:name="com.xw.yunwei.ui.task.accident.handle.AccidentProcessActivity"
- android:launchMode="singleTop" />
+ android:name=".ui.task.accident.handle.AccidentProcessActivity"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
- android:name="com.xw.yunwei.ui.task.taskSub.TaskSubActivity"
- android:launchMode="singleTop" />
+ android:name=".ui.task.taskSub.TaskSubActivity"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" />
<activity
- android:name="com.xw.yunwei.ui.task.taskDetail.TaskDetailActivity"
- android:launchMode="singleTop" />
-
-
- <!-- 配置高德key -->
+ android:name=".ui.task.taskDetail.TaskDetailActivity"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" /> <!-- 配置高德key -->
<meta-data
android:name="com.amap.api.v2.apikey"
- android:value="dc26e21a7c2a494443eddbe52a331f19" />
- <!-- android:value="c237d9248cc928ec73f078507122ed7d" />-->
+ android:value="dc26e21a7c2a494443eddbe52a331f19" /> <!-- android:value="c237d9248cc928ec73f078507122ed7d" /> -->
<!-- 配置高德定位服务 -->
- <service android:name="com.amap.api.location.APSService" />
-
-
- <!--推送消息接收监听器-->
- <receiver android:name=".push.PushMsgReceiver"
+ <service android:name="com.amap.api.location.APSService" /> <!-- 推送消息接收监听器 -->
+ <receiver
+ android:name=".push.PushMsgReceiver"
android:exported="false">
<intent-filter>
<action android:name="com.alibaba.push2.action.NOTIFICATION_OPENED" />
@@ -187,7 +263,6 @@
</intent-filter>
</receiver>
-
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.xw.yunwei.fileprovider"
@@ -199,6 +274,36 @@
android:resource="@xml/file_paths" />
</provider>
+ <meta-data
+ android:name="com.huawei.hms.client.appid"
+ android:value="appid=${PUSH_HW_CLIENT_ID}" /> <!-- 荣耀推送通道 -->
+ <meta-data
+ android:name="com.hihonor.push.app_id"
+ android:value="${PUSH_RY_APP_ID}" /> <!-- VIVO推送通道 -->
+ <meta-data
+ android:name="com.vivo.push.api_key"
+ android:value="${PUSH_VV_APP_KEY}" />
+ <meta-data
+ android:name="com.vivo.push.app_id"
+ android:value="${PUSH_VV_APP_ID}" />
+
+ <activity
+ android:name=".push.PopupPushActivity"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
+ android:exported="true"
+ android:screenOrientation="portrait">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="com.xw.yunwei"
+ android:path="/thirdpush"
+ android:scheme="agoo" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
\ No newline at end of file
diff --git a/app/src/main/assets/iflytek/recognize.xml b/app/src/main/assets/iflytek/recognize.xml
new file mode 100644
index 0000000..78300c1
--- /dev/null
+++ b/app/src/main/assets/iflytek/recognize.xml
Binary files differ
diff --git a/app/src/main/assets/iflytek/voice_bg.9.png b/app/src/main/assets/iflytek/voice_bg.9.png
new file mode 100644
index 0000000..217f9dc
--- /dev/null
+++ b/app/src/main/assets/iflytek/voice_bg.9.png
Binary files differ
diff --git a/app/src/main/assets/iflytek/voice_empty.png b/app/src/main/assets/iflytek/voice_empty.png
new file mode 100644
index 0000000..08ffc43
--- /dev/null
+++ b/app/src/main/assets/iflytek/voice_empty.png
Binary files differ
diff --git a/app/src/main/assets/iflytek/voice_full.png b/app/src/main/assets/iflytek/voice_full.png
new file mode 100644
index 0000000..4bf5bbc
--- /dev/null
+++ b/app/src/main/assets/iflytek/voice_full.png
Binary files differ
diff --git a/app/src/main/assets/iflytek/waiting.png b/app/src/main/assets/iflytek/waiting.png
new file mode 100644
index 0000000..d13bb33
--- /dev/null
+++ b/app/src/main/assets/iflytek/waiting.png
Binary files differ
diff --git a/app/src/main/assets/iflytek/warning.png b/app/src/main/assets/iflytek/warning.png
new file mode 100644
index 0000000..48150ff
--- /dev/null
+++ b/app/src/main/assets/iflytek/warning.png
Binary files differ
diff --git a/app/src/main/java/com/xw/yunwei/BaseBusinessActivity.kt b/app/src/main/java/com/xw/yunwei/BaseBusinessActivity.kt
new file mode 100644
index 0000000..969cbef
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/BaseBusinessActivity.kt
@@ -0,0 +1,77 @@
+package com.xw.yunwei
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.net.ConnectivityManager
+import android.net.NetworkCapabilities
+import android.os.Build
+import android.os.Bundle
+import android.view.View
+import android.widget.FrameLayout
+import androidx.databinding.ViewDataBinding
+import com.xw.common.SecureScreenShot
+import com.xw.common.base.BaseActivity
+import com.xw.common.base.BaseViewModel
+import com.xw.common.utils.BindUtils
+import com.xw.yunwei.extension.dpToPx
+import com.xw.yunwei.extension.spToPx
+import com.xw.yunwei.ui.widget.WatermarkView
+
+//基础业务activity,增加水印和防截屏
+abstract class BaseBusinessActivity<V : ViewDataBinding, VM : BaseViewModel>() :
+ BaseActivity<V, VM>() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ SecureScreenShot.apply(window)
+ }
+
+ override fun setContentView(view: View?) {
+ val wrapWatermark = wrapWatermark(view)
+ super.setContentView(wrapWatermark)
+ }
+
+ private fun wrapWatermark(view: View?): FrameLayout {
+ val layout = FrameLayout(this)
+ layout.addView(view)
+ val watermarkView = WatermarkView(this)
+ watermarkView.layoutParams = FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT
+ ).also {
+ it.topMargin = 88.dpToPx(this)
+ it.bottomMargin = 66.dpToPx(this)
+ }
+ watermarkView.watermarkText = getWatermarkText()
+ watermarkView.textColor = BindUtils.getResColor(R.color.color_0f31456a)
+ watermarkView.isStaggered = false
+ watermarkView.watermarkTextRotation = -15f
+ watermarkView.spacingX = (375f / 2f).dpToPx(this)
+ watermarkView.spacingY = 200f.dpToPx(this)
+ watermarkView.textSize = 14f.spToPx(this)
+ layout.addView(watermarkView)
+ return layout
+ }
+
+ //获取水印文案
+ protected fun getWatermarkText() = Constants.user?.let {
+ "${it.nickName}-${it.phoneNumber}"
+ } ?: ""
+
+ //判断是否有无网络
+ @SuppressLint("Deprecation")
+ fun isNetworkAvailableLegacy(): Boolean {
+ val connectivityManager =
+ getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ val network = connectivityManager.activeNetwork
+ val networkCapabilities = connectivityManager.getNetworkCapabilities(network)
+ return networkCapabilities != null && (
+ networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
+ networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
+ )
+ } else {
+ val networkInfo = connectivityManager.activeNetworkInfo
+ return networkInfo != null && networkInfo.isConnected
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/Constants.kt b/app/src/main/java/com/xw/yunwei/Constants.kt
index ce7b33b..008b31d 100644
--- a/app/src/main/java/com/xw/yunwei/Constants.kt
+++ b/app/src/main/java/com/xw/yunwei/Constants.kt
@@ -18,4 +18,13 @@
return field
}
+ //改派原因
+ val reasons = listOf<String>(
+ "任务分派冲突",
+ "个人原因",
+ "任务距离太远",
+ "临时处理紧急情况",
+ "交通拥堵",
+ "其他"
+ )
}
diff --git a/app/src/main/java/com/xw/yunwei/MyApp.kt b/app/src/main/java/com/xw/yunwei/MyApp.kt
index 3e9cb88..37c180d 100644
--- a/app/src/main/java/com/xw/yunwei/MyApp.kt
+++ b/app/src/main/java/com/xw/yunwei/MyApp.kt
@@ -7,37 +7,75 @@
import android.graphics.Color
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
+import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.MutableLiveData
+import com.afollestad.materialdialogs.MaterialDialog
import com.alibaba.sdk.android.push.CloudPushService
import com.alibaba.sdk.android.push.CommonCallback
+import com.alibaba.sdk.android.push.HonorRegister
+import com.alibaba.sdk.android.push.huawei.HuaWeiRegister
import com.alibaba.sdk.android.push.noonesdk.PushInitConfig
import com.alibaba.sdk.android.push.noonesdk.PushServiceFactory
+import com.alibaba.sdk.android.push.register.OppoRegister
+import com.alibaba.sdk.android.push.register.VivoRegister
+import com.amap.api.location.AMapLocationClient
import com.amap.api.maps.MapsInitializer
+import com.amap.api.navi.NaviSetting
+import com.amap.api.services.core.ServiceSettings
+import com.blankj.utilcode.util.GsonUtils
import com.scwang.smart.refresh.layout.SmartRefreshLayout
+import com.tencent.bugly.crashreport.CrashReport
+import com.xw.common.base.BaseActivity
import com.xw.common.custom.ClassicsFooter11
import com.xw.common.custom.ClassicsHeader11
import com.xw.common.utils.ActivityManager
+import com.xw.common.utils.KeyPreferences
import com.xw.common.utils.LogUtils
import com.xw.common.utils.LogUtils.useThreeLog
import com.xw.common.utils.MMKVManager
+import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.di.networkModule
import com.xw.yunwei.model.AppPermissionModel
+import com.xw.yunwei.model.SwitchTabMain
+import com.xw.yunwei.model.SwitchTabTask
+import com.xw.yunwei.model.TaskModel
+import com.xw.yunwei.model.ThirdInfo
+import com.xw.yunwei.model.event.TaskEvent
+import com.xw.yunwei.net.TaskRepository
+import com.xw.yunwei.ui.MainActivity
+import com.xw.yunwei.ui.dialog.ApplyForReassignReasonDialog
+import com.xw.yunwei.ui.dialog.NewTaskDialog
+import com.xw.yunwei.ui.task.accident.detail.AccidentDetailActivity
+import com.xw.yunwei.ui.task.normal.NormalTaskDetailActivity
+import com.xw.yunwei.utils.DeviceId
+import com.xw.yunwei.utils.TTSController
+import com.xw.yunwei.utils.VibrateUtils
+import com.xw.yunwei.websocket.WebSocketManager
import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import org.greenrobot.eventbus.EventBus
+import org.json.JSONObject
+import org.koin.android.ext.android.inject
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.GlobalContext.startKoin
-import com.tencent.bugly.crashreport.CrashReport
-import com.xw.yunwei.utils.DeviceId
class MyApp : Application() {
companion object {
+ private const val TAG = "MyApp"
lateinit var myApp: MyApp
var pageShowNum = 0 // 可见页面数
// 用户权限
var permissions = MutableLiveData<List<AppPermissionModel>>()
+
+ //语音播报
+ var ttsManager: TTSController = TTSController.getInstance()
/**
* 在权限列表中递归查找指定菜单名的对象
@@ -67,6 +105,8 @@
}
}
+ val taskRepository: TaskRepository by inject()
+
override fun onCreate() {
super.onCreate()
myApp = this
@@ -84,8 +124,14 @@
registerActivityLifecycleCallbacks()
// 高德隐私政策合规
+ AMapLocationClient.updatePrivacyShow(this, true, true)
+ AMapLocationClient.updatePrivacyAgree(this, true)
MapsInitializer.updatePrivacyShow(this, true, true)
MapsInitializer.updatePrivacyAgree(this, true)
+ ServiceSettings.updatePrivacyShow(this, true, true)
+ ServiceSettings.updatePrivacyAgree(this, true)
+ NaviSetting.updatePrivacyShow(this, true, true)
+ NaviSetting.updatePrivacyAgree(this, true)
SmartRefreshLayout.setDefaultRefreshInitializer { _, layout ->
layout.setEnableAutoLoadMore(true)
@@ -101,6 +147,9 @@
SmartRefreshLayout.setDefaultRefreshFooterCreator { context, _ ->
ClassicsFooter11(context)
}
+ ttsManager.init(this)
+ initWebSocket()
+ VibrateUtils.init(this)
}
fun initLog() {
@@ -134,7 +183,7 @@
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
ActivityManager.addActivity(activity)
- LogUtils.i("zmc-pageA", "onActivityCreated: " + activity.javaClass.name)
+ LogUtils.i(TAG, "onActivityCreated: " + activity.javaClass.name)
if (activity is AppCompatActivity) {
activity.supportFragmentManager.registerFragmentLifecycleCallbacks(object :
FragmentManager.FragmentLifecycleCallbacks() {
@@ -156,41 +205,42 @@
}
override fun onActivityStarted(activity: Activity) {
- LogUtils.d("zmc-pageA", "onActivityStarted: " + activity.javaClass.name)
+ LogUtils.d(TAG, "onActivityStarted: " + activity.javaClass.name)
}
override fun onActivityResumed(activity: Activity) {
- LogUtils.i("zmc-pageA", "onActivityResumed: " + activity.javaClass.name)
+ LogUtils.i(TAG, "onActivityResumed: " + activity.javaClass.name)
currentShowActivity!!.complete(activity)
pageShowNum++
}
override fun onActivityPaused(activity: Activity) {
- LogUtils.e("zmc-pageA", "onActivityPaused: " + activity.javaClass.name)
+ LogUtils.e(TAG, "onActivityPaused: " + activity.javaClass.name)
pageShowNum--
currentShowActivity = null
}
override fun onActivityStopped(activity: Activity) {
- LogUtils.e("zmc-pageA", "onActivityStopped: " + activity.javaClass.name)
+ LogUtils.e(TAG, "onActivityStopped: " + activity.javaClass.name)
}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
- LogUtils.d("zmc-pageA", "onActivitySaveInstanceState: " + activity.javaClass.name)
+ LogUtils.d(TAG, "onActivitySaveInstanceState: " + activity.javaClass.name)
}
override fun onActivityDestroyed(activity: Activity) {
- LogUtils.e("zmc-pageA", "onActivityDestroyed: " + activity.javaClass.name)
+ LogUtils.e(TAG, "onActivityDestroyed: " + activity.javaClass.name)
ActivityManager.removeActivity(activity)
}
})
}
- private fun initPush() {
+ fun initPush() {
+ val third = MMKVManager.getInstance().getModel<ThirdInfo?>(KeyPreferences.THIRD) ?: return
val pushInitConfig = PushInitConfig.Builder()
.application(this)
- .appKey(BuildConfig.PUSH_KEY)
- .appSecret(BuildConfig.PUSH_SECRET)
+ .appKey(third.pushKey)
+ .appSecret(third.pushSecret)
.build()
PushServiceFactory.init(pushInitConfig)
@@ -198,10 +248,21 @@
// 此阶段初始化用于建立推送的长连接,可以根据业务需要和合规要求延迟执行。
val pushService = PushServiceFactory.getCloudPushService()
// 仅适用于Debug包,正式包不需要此行
- pushService.setLogLevel(CloudPushService.LOG_DEBUG)
- pushService.register(this, object : com.alibaba.sdk.android.push.CommonCallback {
+ if (BuildConfig.DEBUG) {
+ pushService.setLogLevel(CloudPushService.LOG_DEBUG)
+ }
+ pushService.register(this, object : CommonCallback {
override fun onSuccess(success: String) {
LogUtils.i("zmc-push", "初始化成功,设备ID: " + pushService.deviceId)
+ // 注册各厂商推送通道(会自动判断设备是否支持,不支持则跳过)
+ HuaWeiRegister.register(myApp)
+ HonorRegister.register(myApp)
+ OppoRegister.register(
+ myApp,
+ BuildConfig.PUSH_OP_APP_KEY,
+ BuildConfig.PUSH_OP_APP_SECRET
+ )
+ VivoRegister.register(myApp)
}
override fun onFailed(errorCode: String, errorMessage: String) {
@@ -268,4 +329,157 @@
})
}
+ //初始化websocket
+ private fun initWebSocket() {
+ WebSocketManager.initialize(this)
+ CoroutineScope(Dispatchers.Main).launch {
+ WebSocketManager.eventFlow.collect { event ->
+ when (event) {
+ is WebSocketManager.WebSocketEvent.Connected -> {
+
+ }
+
+ is WebSocketManager.WebSocketEvent.ConnectFailed -> {
+
+ }
+
+ is WebSocketManager.WebSocketEvent.Message -> {
+ try {
+ val json = JSONObject(event.text)
+ if (json.optString("type") == "task") {
+ LogUtils.d(TAG, "接收到改派任务")
+ val data = json.optString("data")
+ val taskModel = GsonUtils.fromJson(data, TaskModel::class.java)
+ val currentShowActivity = MyApp.myApp.getCurrentShowActivity()
+ LogUtils.d(
+ TAG,
+ "显示activity ${currentShowActivity.javaClass.name}"
+ )
+ if (currentShowActivity is BaseActivity<*, *>) {
+ if (taskModel.voiceBroadcast) {
+ ttsManager.setVideoText("您收到一条${if (taskModel.isAccidentTask()) "事故任务" else "任务指派"},请及时处理!")
+ }
+ if (taskModel.vibration) {
+ VibrateUtils.vibratePattern()
+ }
+ if (taskModel.isAccidentTask()) {
+ return@collect
+ }
+ showNewTaskDialog(currentShowActivity, taskModel)
+ }
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ LogUtils.e(TAG, "json 解析失败")
+ }
+ }
+
+ is WebSocketManager.WebSocketEvent.BinaryMessage -> {
+ }
+
+ is WebSocketManager.WebSocketEvent.Disconnected -> {
+ }
+ }
+ }
+ }
+ }
+
+ //显示新任务弹窗
+ private fun showNewTaskDialog(activity: BaseActivity<*, *>, taskModel: TaskModel) {
+ NewTaskDialog.show(
+ context = activity,
+ item = taskModel,
+ applyForReassignBlock = { dialog ->
+ showApplyForReassignReasonDialog(activity, taskModel, dialog)
+ },
+ receive = { dialog ->
+ activity.viewModel.launchRequest(error = { code, msg ->
+ ToastUtilCommon.showError(msg)
+ LogUtils.e(TAG, "launchRequest: code = $code msg = $msg")
+ if (msg == "任务已被接收") {
+ dialog.dismiss()
+ }
+ }) {
+ if (taskRepository.acceptTask(taskModel.id.toString())) {
+ ToastUtilCommon.showSuc("接收任务成功")
+ EventBus.getDefault()
+ .post(TaskEvent.TaskAcceptEvent(taskModel.id.toString()))
+ dialog.dismiss()
+ if (taskModel.taskCategory == 1) {
+ activity.startActivity(
+ NormalTaskDetailActivity::class.java,
+ bundleOf("taskId" to taskModel.id)
+ )
+ } else if (taskModel.taskCategory == 2) {
+ activity.startActivity(
+ AccidentDetailActivity::class.java,
+ bundleOf("taskId" to taskModel.id)
+ )
+ }
+ }
+ }
+ }
+ )
+ }
+
+ //显示申请改派任务弹窗
+ private fun showApplyForReassignReasonDialog(
+ activity: BaseActivity<*, *>,
+ taskModel: TaskModel,
+ newTaskDialog: MaterialDialog
+ ) {
+ ApplyForReassignReasonDialog.show(
+ activity,
+ Constants.reasons,
+ ) { position, input, dialog2 ->
+ activity.viewModel.showDialog(content = "改派中...")
+ activity.viewModel.launchRequest(showLoading = false, error = { code, msg ->
+ activity.viewModel.dismissDialog()
+ ToastUtilCommon.showError(msg)
+ LogUtils.e(TAG, "launchRequest: code = $code msg = $msg")
+ if (msg == "不能申请改派") {
+ newTaskDialog.dismiss()
+ dialog2.dismiss()
+ }
+ }) {
+ val comment = Constants.reasons[position]
+ taskRepository.taskReassignment(comment, input, taskModel.id.toString()).also {
+ newTaskDialog.dismiss()
+ dialog2.dismiss()
+ checkApplyForReassignResult(activity, taskModel)
+ }
+ }
+ }
+ }
+
+ //检测申请改派结果
+ private fun checkApplyForReassignResult(activity: BaseActivity<*, *>, taskModel: TaskModel) {
+ activity.viewModel.launchRequest(showLoading = false, error = { code, msg ->
+ activity.viewModel.dismissDialog()
+ ToastUtilCommon.showError(msg)
+ LogUtils.e(TAG, "launchRequest: code = $code msg = $msg")
+ }) {
+ delay(3 * 1000)
+ val isOk = taskRepository.checkApplyForReassignResult(taskModel.id.toString())
+ activity.viewModel.dismissDialog()
+ isOk?.also {
+ if (it) ToastUtilCommon.showSuc("改派成功") else ToastUtilCommon.showError("暂未找到运维人员")
+ EventBus.getDefault().post(SwitchTabMain(1))
+ if (!it) {
+ EventBus.getDefault().post(SwitchTabTask(4))
+ }
+ }
+ activity.startActivity(MainActivity::class.java)
+ }
+ }
+
+ //连接websocket
+ fun connectWebSocket() {
+ WebSocketManager.connect()
+ }
+
+ //断连websocket
+ fun disconnectWebSocket() {
+ WebSocketManager.disconnect()
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/constants/Key.kt b/app/src/main/java/com/xw/yunwei/constants/Key.kt
new file mode 100644
index 0000000..b9dbafa
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/constants/Key.kt
@@ -0,0 +1,15 @@
+package com.xw.yunwei.constants
+
+//全局所有的KEY
+object Key {
+ const val ID = "id"
+ const val DATA = "data"
+ const val TYPE = "type"
+ const val POINTS = "points"
+ const val START_POINT = "startPoint"
+ const val END_POINT = "endPoint"
+ const val PASS_POINTS = "passPoints"
+ const val CLOCK_MODEL = "clockModel"
+ const val ENTER_TYPE = "enterType"
+ const val TITLE = "title"
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/extension/ActivityExtension.kt b/app/src/main/java/com/xw/yunwei/extension/ActivityExtension.kt
new file mode 100644
index 0000000..9f9f6b9
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/extension/ActivityExtension.kt
@@ -0,0 +1,15 @@
+package com.xw.yunwei.extension
+
+import android.app.Activity
+import android.content.Context
+import android.view.inputmethod.InputMethodManager
+
+//扩展函数 清掉当前焦点 收起输入法
+fun Activity.hideKeyboardAndClearFocus() {
+ // 1. 清掉当前 focued 的输入框
+ currentFocus?.clearFocus()
+
+ // 2. 收起输入法
+ val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+ imm.hideSoftInputFromWindow(window.decorView.windowToken, 0)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/extension/NumExtension.kt b/app/src/main/java/com/xw/yunwei/extension/NumExtension.kt
index 006a204..44f1f2a 100644
--- a/app/src/main/java/com/xw/yunwei/extension/NumExtension.kt
+++ b/app/src/main/java/com/xw/yunwei/extension/NumExtension.kt
@@ -1,6 +1,7 @@
package com.xw.yunwei.extension
import android.content.Context
+import android.graphics.drawable.Drawable
import androidx.core.content.ContextCompat
// 扩展 Float
@@ -47,4 +48,19 @@
//颜色资源id转颜色值
fun Int.colorIdToColorValue(context: Context): Int =
- ContextCompat.getColor(context, this)
\ No newline at end of file
+ ContextCompat.getColor(context, this)
+
+//Drawable资源id转Drawable
+fun Int.drawableIdToDrawable(context: Context): Drawable? =
+ ContextCompat.getDrawable(context, this)
+
+//扩展函数 显示统计数量
+fun Int?.showCount(max: Int? = null): String {
+ return takeIf { (this ?: 0) > 0 }?.let {
+ if (max != null && it > max) {
+ "${max}+"
+ } else {
+ it.toString()
+ }
+ } ?: ""
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/extension/StringExtension.kt b/app/src/main/java/com/xw/yunwei/extension/StringExtension.kt
index 858e422..94093b3 100644
--- a/app/src/main/java/com/xw/yunwei/extension/StringExtension.kt
+++ b/app/src/main/java/com/xw/yunwei/extension/StringExtension.kt
@@ -6,6 +6,8 @@
import java.security.MessageDigest
import java.security.PublicKey
import java.security.spec.X509EncodedKeySpec
+import java.text.SimpleDateFormat
+import java.util.Locale
import javax.crypto.Cipher
import javax.crypto.Mac
import javax.crypto.SecretKey
@@ -80,3 +82,15 @@
""
}
}
+
+//扩展函数 日期字符串更换格式
+fun String.dateChangePattern(oldPattern: String, newPattern: String): String {
+ return try {
+ SimpleDateFormat(oldPattern, Locale.getDefault()).parse(this)?.let {
+ SimpleDateFormat(newPattern, Locale.getDefault()).format(it)
+ } ?: this
+ } catch (e: Exception) {
+ e.printStackTrace()
+ this
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/extension/ViewExtension.kt b/app/src/main/java/com/xw/yunwei/extension/ViewExtension.kt
index 1225b4e..15b1242 100644
--- a/app/src/main/java/com/xw/yunwei/extension/ViewExtension.kt
+++ b/app/src/main/java/com/xw/yunwei/extension/ViewExtension.kt
@@ -1,6 +1,14 @@
package com.xw.yunwei.extension
+import android.util.Log
import android.view.View
+import android.webkit.WebResourceRequest
+import android.webkit.WebResourceResponse
+import android.webkit.WebView
+import android.webkit.WebViewClient
+import com.xw.yunwei.utils.HtmlSanitizer
+import java.net.HttpURLConnection
+import java.net.URL
//扩展函数 设置防重复点击监听器
fun View.setOnDurationClickListener(duration: Long = 1000L, listener: View.OnClickListener) {
@@ -12,4 +20,170 @@
listener.onClick(it)
}
}
+}
+
+//扩展函数 网页加载控件安全设置
+fun WebView.setSafeSetting() {
+ apply {
+ settings.allowFileAccess = false //设置不可以访问文件
+ webViewClient = object : WebViewClient() {
+ override fun shouldInterceptRequest(
+ view: WebView,
+ request: WebResourceRequest
+ ): WebResourceResponse? {
+ val url = request.url.toString()
+ //访问文件危险操作
+ val dangerousOperation = listOf("file://", "content://", "android_asset")
+ // 阻止文件访问
+ if (dangerousOperation.any { url.contains(it, ignoreCase = true) }) {
+ return WebResourceResponse("text/plain", "UTF-8", 403, "Forbidden", emptyMap(), "".byteInputStream())
+ }
+ // 只对HTML文档添加CSP
+ if (isHtmlDocument(request)) {
+ return getResponseWithCSP(request)
+ }
+ return super.shouldInterceptRequest(view, request)
+ }
+
+ private fun isHtmlDocument(request: WebResourceRequest): Boolean {
+ val url = request.url.toString()
+ val contentType = request.requestHeaders?.get("Accept")
+ val urlPatterns = listOf(".html", ".htm", ".php", ".jsp", ".asp")
+
+ return urlPatterns.any { url.endsWith(it) } ||
+ contentType?.contains("text/html") == true
+ }
+
+ private fun getResponseWithCSP(request: WebResourceRequest): WebResourceResponse? {
+ try {
+ val urlConnection =
+ URL(request.url.toString()).openConnection() as HttpURLConnection
+
+ // 设置请求头
+ request.requestHeaders?.forEach { (key, value) ->
+ urlConnection.setRequestProperty(key, value)
+ }
+
+ urlConnection.requestMethod = request.method
+ val responseCode = urlConnection.responseCode
+
+ if (responseCode == HttpURLConnection.HTTP_OK) {
+ val mimeType =
+ urlConnection.contentType?.split(";")?.firstOrNull() ?: "text/html"
+ val encoding = urlConnection.contentEncoding ?: "UTF-8"
+ val inputStream = urlConnection.inputStream
+
+ // 创建带有CSP头的响应
+ val headers = mutableMapOf<String, String>()
+
+ // 收集原始响应头
+ urlConnection.headerFields.forEach { (key, valueList) ->
+ if (key != null && valueList != null && valueList.isNotEmpty()) {
+ headers[key] = valueList.joinToString(", ")
+ }
+ }
+
+ // 添加或覆盖CSP头
+ headers["Content-Security-Policy"] = buildCSPPolicy()
+
+ return WebResourceResponse(
+ mimeType, encoding, responseCode,
+ urlConnection.responseMessage, headers, inputStream
+ )
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ Log.e("CSP", "Failed to add CSP header")
+ }
+ return null
+ }
+
+ private fun buildCSPPolicy(): String {
+ return """
+ default-src 'self';
+ script-src 'self' 'unsafe-inline' 'unsafe-eval' https://trusted-cdn.com;
+ style-src 'self' 'unsafe-inline' https://trusted-cdn.com;
+ img-src 'self' data: https:;
+ font-src 'self' https://fonts.gstatic.com;
+ connect-src 'self' https://api.example.com;
+ frame-src 'self' https://trusted-iframe.com;
+ report-uri /csp-report-endpoint
+ """.trimIndent().replace("\n", " ")
+ }
+
+ override fun onPageFinished(view: WebView?, url: String?) {
+ super.onPageFinished(view, url)
+ // 注入安全监控脚本
+ injectSecurityMonitor(view)
+ }
+
+ private fun injectSecurityMonitor(view: WebView?) {
+ val securityScript = """
+ (function() {
+ 'use strict';
+
+ // 监控DOM变化
+ const observer = new MutationObserver(function(mutations) {
+ mutations.forEach(function(mutation) {
+ mutation.addedNodes.forEach(function(node) {
+ if (node.nodeName === 'SCRIPT') {
+ console.warn('Dynamic script added:', node.src || node.textContent.substring(0, 100));
+ }
+ if (node.nodeName === 'IFRAME') {
+ console.warn('Dynamic iframe added:', node.src);
+ }
+ });
+ });
+ });
+
+ observer.observe(document.documentElement, {
+ childList: true,
+ subtree: true
+ });
+
+ // 拦截危险API调用
+ const originalFetch = window.fetch;
+ window.fetch = function() {
+ const url = arguments[0];
+ if (typeof url === 'string') {
+ if (url.startsWith('file://') || url.includes('localhost')) {
+ console.error('Blocked fetch to local file:', url);
+ return Promise.reject(new Error('Access to local files is blocked'));
+ }
+ }
+ return originalFetch.apply(this, arguments);
+ };
+
+ // 监控表单提交
+ document.addEventListener('submit', function(e) {
+ const form = e.target;
+ const action = form.getAttribute('action') || '';
+ if (action.startsWith('file://')) {
+ e.preventDefault();
+ console.error('Blocked form submission to file:', action);
+ }
+ });
+ })();
+ """.trimIndent()
+ view?.evaluateJavascript(securityScript, null)
+ }
+ }
+ }
+}
+
+//扩展函数 安全加载本地数据
+fun WebView.safeLoadDataWithBaseURL(
+ baseUrl: String?,
+ data: String,
+ mimeType: String?,
+ encoding: String?,
+ historyUrl: String?
+) {
+ loadDataWithBaseURL(
+ baseUrl,
+ HtmlSanitizer().sanitizeUserContent(data),
+ mimeType,
+ encoding,
+ historyUrl
+ )
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/AcceptCarPointInfo.kt b/app/src/main/java/com/xw/yunwei/model/AcceptCarPointInfo.kt
new file mode 100644
index 0000000..9a6c56b
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/model/AcceptCarPointInfo.kt
@@ -0,0 +1,62 @@
+package com.xw.yunwei.model
+
+import android.os.Parcelable
+import com.xw.common.utils.BindUtils.getUrl
+import kotlinx.parcelize.Parcelize
+import org.json.JSONArray
+
+@Parcelize
+data class AcceptCarPointInfo(
+ val chargePoint: String? = null,//0否 1是充电点位
+ val cityCode: String? = null,//城市code
+ val cityName: String? = null,//城市名称
+ val deleted: String? = null,//是否删除 0未删除 1已删除
+ val distance: String? = null,//距离 单位米
+ val districtCode: String? = null,//区县code
+ val districtName: String? = null,//区县名称
+ val effectTime: String? = null,//生效时间
+ val effectivePeriod: String? = null,//生效周期 1=“每日生效”、2=“仅工作日生效”、3=“仅非工作日生效”、4=“仅节假日生效”
+ val effectiveTimePeriod: String? = null,//自定义运营生效时间段
+ val electronicAreaId: String? = null,//电子围栏区域id
+ val electronicEffectTime: String? = null,//围栏的生效时间
+ val electronicName: String? = null,//电子围栏名称
+ val fenceOperationStrategy: String? = null,//围栏运营策略
+ val fpElectronicAreaId: String? = null,//
+ val hoverStatusDes: String? = null,//状态描述
+ val id: String? = null,//
+ val operationStatus: String? = null,//运营状态 1=待启用 2=启用中 3=已停用 4=已失效
+ val operationType: String? = null,//运营类型 1=与运营区同步 2=自定义时间段
+ val parkingPoint: String? = null,//0否 1是收车点位
+ val parkingTimeLimit: String? = null,//限停时长
+ val pointAddress: String? = null,//点位地址
+ val pointLat: String? = null,//纬度
+ val pointLon: String? = null,//经度
+ val pointName: String? = null,//点位名称
+ val pointNumber: String? = null,//点位编号唯一
+ val pointOnOff: String? = null,//点位上下车 1仅上车点/ 2 仅下车/ 3上下车均可
+ val pointOnOffName: String? = null,//
+ val pointPictures: String? = null,//点位照片
+ val pointPoi: String? = null,//点位poi
+ val pointType: String? = null,//点位类型 1=运营点位 2=测试点位
+ val provinceCode: String? = null,//省份code
+ val provinceName: String? = null,//省份名称
+ val remarks: String? = null,//备注
+ val stationEffectivePeriod: String? = null,//场站生效周期 1=每日 2=仅工作日 3=仅非工作日 4=仅节假日
+ val stationEffectiveTimePeriod: String? = null,//场站运营策略
+ val stationId: String? = null,//所属场站id,为空表示运营区直属点位
+ val stationName: String? = null,//所属场站名称
+ val stationOperationType: String? = null,//场站运营类型 1=与运营区同步 2=自定义时间段
+ val stationSortNo: String? = null,//点位在场站内排序
+ val strId: String? = null,//
+ val verificationStatus: String? = null,//验证状态 1=待验证、2=验证中、3=已验证 4验证失败 5待生效
+) : Parcelable {
+ //获取显示图片地址
+ fun getShowPictureUrl(): String {
+ return try {
+ JSONArray(pointPictures).get(0).toString().getUrl()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ return ""
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/AgreeInfo.kt b/app/src/main/java/com/xw/yunwei/model/AgreeInfo.kt
new file mode 100644
index 0000000..ec135a8
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/model/AgreeInfo.kt
@@ -0,0 +1,10 @@
+package com.xw.yunwei.model
+
+//协议信息
+data class AgreeInfo(
+ val id: String?,
+ val name: String?,
+ val content: String?,
+ val type: Int?,
+ val version: String?
+)
diff --git a/app/src/main/java/com/xw/yunwei/model/AppVersionModel.kt b/app/src/main/java/com/xw/yunwei/model/AppVersionModel.kt
index 2956299..83dd197 100644
--- a/app/src/main/java/com/xw/yunwei/model/AppVersionModel.kt
+++ b/app/src/main/java/com/xw/yunwei/model/AppVersionModel.kt
@@ -1,6 +1,7 @@
package com.xw.yunwei.model
import com.google.gson.annotations.SerializedName
+import org.json.JSONObject
/**
* 应用版本更新信息数据类
@@ -43,4 +44,14 @@
@SerializedName("forceUpdateFlag")
val forceUpdateFlag: Int? = null,
- )
\ No newline at end of file
+ ) {
+ //获取下载路径
+ fun getDownloadUrl(): String? {
+ return try {
+ JSONObject(androidFile ?: "").optString("url")
+ } catch (e: Exception) {
+ e.printStackTrace()
+ null
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/CarModel.kt b/app/src/main/java/com/xw/yunwei/model/CarModel.kt
index 61f9ea1..e6e4d85 100644
--- a/app/src/main/java/com/xw/yunwei/model/CarModel.kt
+++ b/app/src/main/java/com/xw/yunwei/model/CarModel.kt
@@ -2,7 +2,10 @@
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
+import com.xw.common.utils.BindUtils.getUrl
+import com.xw.yunwei.R
import kotlinx.parcelize.Parcelize
+import kotlin.math.min
/**
* 车辆管理实体
@@ -243,5 +246,111 @@
* 记录修改时间,前端忽略
*/
@SerializedName("updateTime")
- val updateTime: String? = null
-) : Parcelable
\ No newline at end of file
+ val updateTime: String? = null,
+ var pointName: String? = null,//收车点位名称
+
+ /**
+ * 是否已经打开后备箱 1是 前端字段
+ */
+ val hadTrunkOpened: String? = null,
+
+ /**
+ * 车辆状态(1=运营中,2=出车中,3=接单中,4=停止接单,5=已收车,6=车辆异常,7=维修中,8=充电中)
+ */
+ val vehicleStatus: String? = null
+) : Parcelable {
+ //获取车辆图片
+ fun getShowVehiclePicture(): String {
+ return try {
+ vehiclePictures?.getUrl() ?: ""
+ } catch (e: Exception) {
+ ""
+ }
+ }
+
+ //是否已开启车门
+ fun hadOpenedDoor(): Boolean {
+ return false
+ }
+
+ //是否已开启后备箱
+ fun hadOpenedTrunk(): Boolean {
+ return hadTrunkOpened == "1"
+ }
+
+ //是否正在工作中
+ fun isWorking(): Boolean {
+ return operatingStatus == 1
+ }
+
+ //是否已经开启接单
+ fun hadOpenTakeOrder(): Boolean {
+ return acceptOrTest == 1 && acceptOrTestStatus == 1
+ }
+
+ //正在前往收车点中
+ fun isArrivingPoint(): Boolean {
+ return !pointName.isNullOrEmpty()
+ }
+
+ //获取显示状态 1=运营中,2=出车中,3=接单中,4=停止接单,5=已收车,6=车辆异常,7=维修中,8=充电中
+ fun getShowStatus(): String {
+ return when (vehicleStatus) {
+ "1" -> "运营中"
+ "2" -> "出车中"
+ "3" -> "接单中"
+ "4" -> "停止接单"
+ "5" -> "已收车"
+ "6" -> "车辆异常"
+ "7" -> "维修中"
+ "8" -> "充电中"
+ else -> ""
+ }
+ }
+
+ //获取显示状态文字颜色 1=运营中,2=出车中,3=接单中,4=停止接单,5=已收车,6=车辆异常,7=维修中,8=充电中
+ fun getShowStatusTextColor(): Int {
+ return when (vehicleStatus) {
+ "1", "2", "3" -> com.xw.common.R.color.blue_5
+ "4", "5" -> com.xw.common.R.color.gray_8
+ "6", "7", "8" -> com.xw.common.R.color.orange_5
+ else -> com.xw.common.R.color.black
+ }
+ }
+
+ //获取显示状态背景资源 1=运营中,2=出车中,3=接单中,4=停止接单,5=已收车,6=车辆异常,7=维修中,8=充电中
+ fun getShowStatusBgResource(): Int {
+ return when (vehicleStatus) {
+ "1", "2", "3" -> R.drawable.shape_blue_1_bg_2
+ "4", "5" -> R.drawable.shape_gray_3_bg_2
+ "6", "7", "8" -> R.drawable.shape_orange_1_bg_2
+ else -> 0
+ }
+ }
+
+ //获取显示状态图片资源 1=运营中,2=出车中,3=接单中,4=停止接单,5=已收车,6=车辆异常,7=维修中,8=充电中
+ fun getShowStatusImageResource(): Int {
+ return when (vehicleStatus) {
+ "1" -> R.mipmap.icon_car_running
+ "2" -> R.mipmap.icon_car_working
+ "3" -> R.mipmap.icon_car_order
+ "4" -> R.mipmap.icon_car_stop_order
+ "5" -> R.mipmap.ic_work_quche
+ "6" -> R.mipmap.icon_car_exception
+ "7" -> R.mipmap.ic_work_weixiu
+ "8" -> R.mipmap.icon_car_charge
+ else -> 0
+ }
+ }
+
+ //获取显示车身编码
+ fun getShowVehicleCode(maxLength: Int): String {
+ return vehicleCode?.let {
+ if (it.isNotEmpty()) {
+ it.substring(0, min(it.length, maxLength))
+ } else {
+ ""
+ }
+ } ?: ""
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/CarOperationRecordModel.kt b/app/src/main/java/com/xw/yunwei/model/CarOperationRecordModel.kt
index cb2bb0d..cc2feda 100644
--- a/app/src/main/java/com/xw/yunwei/model/CarOperationRecordModel.kt
+++ b/app/src/main/java/com/xw/yunwei/model/CarOperationRecordModel.kt
@@ -1,6 +1,7 @@
package com.xw.yunwei.model
import com.google.gson.annotations.SerializedName
+import com.xw.yunwei.extension.dateChangePattern
import java.util.Date
/**
@@ -81,4 +82,10 @@
*/
@SerializedName("vehiclePictures")
val vehiclePictures: String? = null
-)
\ No newline at end of file
+){
+
+ //获取显示操作时间
+ fun getShowOperationTime(): String?{
+ return operationTime?.dateChangePattern("yyyy-MM-dd HH:mm:ss","yyyy/MM/dd HH:mm:ss")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/CarRecordChargeModel.kt b/app/src/main/java/com/xw/yunwei/model/CarRecordChargeModel.kt
index e3f08cb..dc5aaa0 100644
--- a/app/src/main/java/com/xw/yunwei/model/CarRecordChargeModel.kt
+++ b/app/src/main/java/com/xw/yunwei/model/CarRecordChargeModel.kt
@@ -1,6 +1,7 @@
package com.xw.yunwei.model
import com.google.gson.annotations.SerializedName
+import com.xw.yunwei.extension.dateChangePattern
/**
* 车辆充电记录实体类
@@ -160,4 +161,15 @@
*/
@SerializedName("vehiclePictures")
val vehiclePictures: String? = null
-)
\ No newline at end of file
+){
+
+ //获取显示开始充电时间
+ fun getShowStartTime(): String?{
+ return startTime?.dateChangePattern("yyyy-MM-dd HH:mm:ss","yyyy/MM/dd HH:mm:ss")
+ }
+
+ //获取显示结束充电时间
+ fun getShowEndTime(): String?{
+ return endTime?.dateChangePattern("yyyy-MM-dd HH:mm:ss","yyyy/MM/dd HH:mm:ss")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/CarRecordCheckModel.kt b/app/src/main/java/com/xw/yunwei/model/CarRecordCheckModel.kt
index 36db963..7051c07 100644
--- a/app/src/main/java/com/xw/yunwei/model/CarRecordCheckModel.kt
+++ b/app/src/main/java/com/xw/yunwei/model/CarRecordCheckModel.kt
@@ -1,6 +1,7 @@
package com.xw.yunwei.model
import com.google.gson.annotations.SerializedName
+import com.xw.yunwei.extension.dateChangePattern
/**
* 车辆检测记录实体类
@@ -217,4 +218,10 @@
*/
@SerializedName("versionVerification")
val versionVerification: Int? = null
-)
\ No newline at end of file
+){
+
+ //获取显示操作时间
+ fun getShowOperationTime(): String?{
+ return operationTime?.dateChangePattern("yyyy-MM-dd HH:mm:ss","yyyy/MM/dd HH:mm:ss")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/CarRecordCleanModel.kt b/app/src/main/java/com/xw/yunwei/model/CarRecordCleanModel.kt
index 717ba45..eddadae 100644
--- a/app/src/main/java/com/xw/yunwei/model/CarRecordCleanModel.kt
+++ b/app/src/main/java/com/xw/yunwei/model/CarRecordCleanModel.kt
@@ -1,6 +1,7 @@
package com.xw.yunwei.model
import com.google.gson.annotations.SerializedName
+import com.xw.yunwei.extension.dateChangePattern
/**
* 车辆任务完成记录实体类
@@ -117,4 +118,9 @@
/** 测试模式 */
const val MODE_TEST = 2
}
+
+ //获取显示操作时间
+ fun getShowOperationTime(): String?{
+ return operationTime?.dateChangePattern("yyyy-MM-dd HH:mm:ss","yyyy/MM/dd HH:mm:ss")
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/CarRecordMaintainModel.kt b/app/src/main/java/com/xw/yunwei/model/CarRecordMaintainModel.kt
index e088418..1c511f6 100644
--- a/app/src/main/java/com/xw/yunwei/model/CarRecordMaintainModel.kt
+++ b/app/src/main/java/com/xw/yunwei/model/CarRecordMaintainModel.kt
@@ -1,6 +1,7 @@
package com.xw.yunwei.model
import com.google.gson.annotations.SerializedName
+import com.xw.yunwei.extension.dateChangePattern
/**
* 车辆整备记录VO
@@ -184,4 +185,9 @@
/** 测试模式 */
const val MODE_TEST = 2
}
+
+ //获取显示操作时间
+ fun getShowOperationTime(): String?{
+ return operationTime?.dateChangePattern("yyyy-MM-dd HH:mm:ss","yyyy/MM/dd HH:mm:ss")
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/CarRecordRepairModel.kt b/app/src/main/java/com/xw/yunwei/model/CarRecordRepairModel.kt
index 94bef2a..2a3d73e 100644
--- a/app/src/main/java/com/xw/yunwei/model/CarRecordRepairModel.kt
+++ b/app/src/main/java/com/xw/yunwei/model/CarRecordRepairModel.kt
@@ -1,5 +1,6 @@
package com.xw.yunwei.model
import com.google.gson.annotations.SerializedName
+import com.xw.yunwei.extension.dateChangePattern
/**
* 车辆维修记录实体类
@@ -164,4 +165,24 @@
/** 测试模式 */
const val MODE_TEST = 2
}
+
+ //获取显示开始时间
+ fun getShowStartTime(): String?{
+ return startTime?.dateChangePattern("yyyy年MM月dd日","yyyy/MM/dd")
+ }
+
+ //获取显示结束时间
+ fun getShowEndTime(): String?{
+ return endTime?.dateChangePattern("yyyy年MM月dd日","yyyy/MM/dd")
+ }
+
+ //获取显示送修时间
+ fun getShowSendTime(): String?{
+ return sendTime?.dateChangePattern("yyyy年MM月dd日 HH:mm:ss","yyyy/MM/dd HH:mm:ss")
+ }
+
+ //获取显示取回时间
+ fun getShowReturnTime(): String?{
+ return returnTime?.dateChangePattern("yyyy年MM月dd日 HH:mm:ss","yyyy/MM/dd HH:mm:ss")
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/CertificateAuditInfo.kt b/app/src/main/java/com/xw/yunwei/model/CertificateAuditInfo.kt
new file mode 100644
index 0000000..6494c28
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/model/CertificateAuditInfo.kt
@@ -0,0 +1,31 @@
+package com.xw.yunwei.model
+
+//证件审核信息
+data class CertificateAuditInfo(
+ var auditRemark: String? = null,//审核备注
+ var auditStatus: String? = null,//审核状态 1待审核 2审核通过 3审核驳回
+ var auditTime: String? = null,//审核时间
+ var auditUserId: String? = null,//审核人id
+ var certificateOfNoCriminalRecord: String? = null,//无犯罪记录正面
+ var driverLicense: String? = null,//驾驶证
+ var idCardBack: String? = null,//身份证背面
+ var idCardFront: String? = null,//身份证正面
+ var operationsUserId: String? = null,//运维人员id
+ var trainingGraduationCertificate: String? = null,//培训结业证
+ var isUpdateAuditing: String? = null,//是否更新资料审核中 1是
+) {
+ //是否有效
+ fun isEffective() = !auditStatus.isNullOrEmpty()
+
+ //是否需要等待审核
+ fun needWaitAudit() = auditStatus == "1"
+
+ //是否审核通过
+ fun hadAuditSuccess() = auditStatus == "2"
+
+ //是否审核失败
+ fun hadAuditFail() = auditStatus == "3"
+
+ //是否在更新资料审核中
+ fun isInUpdateWaitAudit() = isUpdateAuditing == "1"
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/CheckInMissionPointInfo.kt b/app/src/main/java/com/xw/yunwei/model/CheckInMissionPointInfo.kt
new file mode 100644
index 0000000..36a8cb6
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/model/CheckInMissionPointInfo.kt
@@ -0,0 +1,45 @@
+package com.xw.yunwei.model
+
+import android.os.Parcelable
+import kotlinx.parcelize.Parcelize
+
+//巡游任务点信息
+@Parcelize
+data class CheckInMissionPointInfo(
+ var checkIn: String?,//是否已打卡(0=否,1=是)
+ var checkInResult: String?,//打卡结果(1=正常打卡,2=超时打卡,3=未打卡)
+ val lat: String?,//纬度
+ val lon: String?,//经度
+ val locationId: String?,//点位id
+ val address: String?, // 地址,如"蜀山区华侨中心A座2301"
+ val checkInTime: String? = null, // 打卡时间,仅已打卡/超时打卡时有值
+ val time: String? = null, // 打卡时限,如"08:00~09:00"
+ val latestTime: String? = null, // 最晚打卡时间
+ val openRange: String? = null, // 打卡范围 单位米
+) : Parcelable {
+ //获取显示打卡时间
+ fun getShowCheckTime() = when (checkInResult) {
+ "1", "2" -> "${if (checkInTime.isNullOrEmpty()) "" else "$checkInTime "}${getShowStatus()}"
+ "3" -> getShowStatus()
+ else -> ""
+ }
+
+
+ //获取显示状态
+ fun getShowStatus() = checkInResult?.let {
+ when (it) {
+ "1" -> "已打卡"
+ "2" -> "超时打卡"
+ "3" -> "未打卡"
+ else -> ""
+ }
+ } ?: ""
+
+ //是否已经打卡
+ fun hadCheckIn() = checkIn == "1"
+
+ //获取最晚打卡时间戳
+ fun getLatestTimestamp(): Long {
+ return latestTime?.toLongOrNull() ?: System.currentTimeMillis()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/ClockInStatusModel.kt b/app/src/main/java/com/xw/yunwei/model/ClockInStatusModel.kt
index 4047caa..5cbc5db 100644
--- a/app/src/main/java/com/xw/yunwei/model/ClockInStatusModel.kt
+++ b/app/src/main/java/com/xw/yunwei/model/ClockInStatusModel.kt
@@ -2,7 +2,9 @@
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
+import com.xw.yunwei.extension.dateChangePattern
import kotlinx.parcelize.Parcelize
+import java.util.Calendar
/**
* 打卡状态VO
@@ -41,7 +43,28 @@
@SerializedName("xpClockIn")
val xpClockIn: XpClockInVO? = null
-) : Parcelable
+) : Parcelable {
+ //是否需要上班打卡
+ fun needWorkCheckIn(): Boolean {
+ if (clockIn == true) {
+ return false
+ }
+ return xpClockIn?.hadLostWorkCheckedIn() != true
+ }
+
+ //是否需要下班打卡
+ fun needOffWorkCheckIn(): Boolean {
+ if (clockOut == true) {
+ return false
+ }
+ return xpClockIn?.hadLostOffWorkCheckedIn() != true
+ }
+
+ //是否配置打卡信息
+ fun hadConfigCheckInfo(): Boolean {
+ return (xpShift?.id ?: 0) > 0
+ }
+}
/**
* 打卡地址管理VO
@@ -116,7 +139,7 @@
*/
@SerializedName("upStringTime")
val upStringTime: String? = null
-): Parcelable
+) : Parcelable
/**
* 班次管理VO
@@ -202,8 +225,103 @@
* 记录修改时间(前端忽略)
*/
@SerializedName("upStringTime")
- val upStringTime: String? = null
-): Parcelable
+ val upStringTime: String? = null,
+ //上班最早打卡时间
+ val maxStartTime: String?,
+ //上班最晚打卡时间
+ val minStartTime: String?,
+ //下班最早打卡时间
+ val maxEndTime: String?,
+ //下班最晚打卡时间
+ val minEndTime: String?,
+ //是否跨天
+ val crossDay: Boolean?,
+) : Parcelable {
+ //是否当前时间打卡上班有效
+ fun isNowTimeCheckInWorkEffective(): Boolean {
+ return isNowTimeAfterCheckInWorkStartTime() && isNowTimeBeforeCheckInWorkEndTime()
+ }
+
+ //是否当前时间在打卡上班最早时间之前
+ fun isNowTimeAfterCheckInWorkStartTime(): Boolean {
+ return try {
+ val now = Calendar.getInstance()
+ val current = now.timeInMillis
+ val min = now.apply {
+ set(Calendar.HOUR_OF_DAY, maxStartTime!!.split(":").first().toInt())
+ set(Calendar.MINUTE, maxStartTime.split(":").last().toInt())
+ set(Calendar.SECOND, 0)
+ set(Calendar.MILLISECOND, 0)
+ }.timeInMillis
+ current >= min
+ } catch (e: Exception) {
+ e.printStackTrace()
+ false
+ }
+ }
+
+ //是否当前时间在打卡上班最晚时间之后
+ fun isNowTimeBeforeCheckInWorkEndTime(): Boolean {
+ return try {
+ val now = Calendar.getInstance()
+ val current = now.timeInMillis
+ val max = now.apply {
+ set(Calendar.HOUR_OF_DAY, minStartTime!!.split(":").first().toInt())
+ set(Calendar.MINUTE, minStartTime.split(":").last().toInt())
+ set(Calendar.SECOND, 0)
+ set(Calendar.MILLISECOND, 0)
+ }.timeInMillis
+ current <= max
+ } catch (e: Exception) {
+ e.printStackTrace()
+ false
+ }
+ }
+
+ //是否当前时间打卡下班有效
+ fun isNowTimeCheckInOffWorkEffective(): Boolean {
+ return isNowTimeAfterCheckInOffWorkStartTime() && isNowTimeBeforeCheckInOffWorkEndTime()
+ }
+
+ //是否当前时间在下班打卡最早时间之前
+ fun isNowTimeAfterCheckInOffWorkStartTime(): Boolean {
+ return try {
+ val now = Calendar.getInstance()
+ val current = now.timeInMillis
+ val min = now.apply {
+ set(Calendar.HOUR_OF_DAY, maxEndTime!!.split(":").first().toInt())
+ set(Calendar.MINUTE, maxEndTime.split(":").last().toInt())
+ set(Calendar.SECOND, 0)
+ set(Calendar.MILLISECOND, 0)
+ }.timeInMillis
+ current >= min
+ } catch (e: Exception) {
+ e.printStackTrace()
+ false
+ }
+ }
+
+ //是否当前时间在下班打卡最晚时间之前
+ fun isNowTimeBeforeCheckInOffWorkEndTime(): Boolean {
+ return try {
+ val now = Calendar.getInstance()
+ val current = now.timeInMillis
+ val max = now.apply {
+ set(Calendar.HOUR_OF_DAY, minEndTime!!.split(":").first().toInt())
+ set(Calendar.MINUTE, minEndTime.split(":").last().toInt())
+ if (crossDay == true) {
+ add(Calendar.DAY_OF_MONTH, 1)
+ }
+ set(Calendar.SECOND, 0)
+ set(Calendar.MILLISECOND, 0)
+ }.timeInMillis
+ current <= max
+ } catch (e: Exception) {
+ e.printStackTrace()
+ false
+ }
+ }
+}
/**
@@ -299,4 +417,53 @@
@SerializedName("clockInAddress")
val clockInAddress: String? = null,
- ): Parcelable
\ No newline at end of file
+ ) : Parcelable {
+ //是否已经上班打卡
+ fun hadWorkCheckedIn(): Boolean {
+ return clockInResult == 1 || clockInResult == 2
+ }
+
+ //是否缺失上班打卡
+ fun hadLostWorkCheckedIn(): Boolean {
+ return clockInResult == 3
+ }
+
+ //是否已经下班打卡
+ fun hadOffWorkCheckedIn(): Boolean {
+ return clockOutResult == 1 || clockOutResult == 2
+ }
+
+ //是否缺失下班打卡
+ fun hadLostOffWorkCheckedIn(): Boolean {
+ return clockOutResult == 3
+ }
+
+ //获取上班打卡成功时间
+ fun getFormateClockInTime(): String {
+ return try {
+ clockInTime?.let {
+ val split = it.split(" ")
+ val ymd = split[0].dateChangePattern("yyyy-MM-dd", "yyyy/MM/dd")
+ "$ymd ${split[1]}"
+ } ?: ""
+ } catch (e: Exception) {
+ e.printStackTrace()
+ ""
+ }
+ }
+
+ //获取下班打卡成功时间
+ fun getFormateClockOutTime(): String {
+ return try {
+ clockOutTime?.let {
+ val split = it.split(" ")
+ val ymd = split[0].dateChangePattern("yyyy-MM-dd", "yyyy/MM/dd")
+ "$ymd ${split[1]}"
+ } ?: ""
+ } catch (e: Exception) {
+ e.printStackTrace()
+ ""
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/CruiseCheckInMissionInfo.kt b/app/src/main/java/com/xw/yunwei/model/CruiseCheckInMissionInfo.kt
new file mode 100644
index 0000000..ad58ec2
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/model/CruiseCheckInMissionInfo.kt
@@ -0,0 +1,21 @@
+package com.xw.yunwei.model
+
+import android.os.Parcelable
+import kotlinx.parcelize.Parcelize
+
+//巡游打卡任务信息
+@Parcelize
+data class CruiseCheckInMissionInfo(
+ val checkInPointCount: Int,
+ val checkInPointFinishCount: Int,
+ val checkInPointUnFinishCount: Int,
+ val cruiseCheckInTaskTime: String,
+ val id: String
+) : Parcelable {
+ //数据是否有效
+ fun isEffective() = (id.toLongOrNull() ?: 0L) > 0L
+
+ //获取完成进度
+ fun getFinishProgress() =
+ (checkInPointFinishCount.toFloat() / checkInPointCount.toFloat()) * 100f
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/CruiseCheckInOperationInfo.kt b/app/src/main/java/com/xw/yunwei/model/CruiseCheckInOperationInfo.kt
new file mode 100644
index 0000000..35d051b
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/model/CruiseCheckInOperationInfo.kt
@@ -0,0 +1,25 @@
+package com.xw.yunwei.model
+
+import android.os.Parcelable
+import kotlinx.parcelize.Parcelize
+
+//巡游打卡操作信息
+@Parcelize
+class CruiseCheckInOperationInfo(
+ val checkLocationId: String? = null,//巡游打卡点位id
+ val message: String? = null,//提示内容
+ val messageType: String? = null,//消息类型(1=即将超时提醒,2=到达打卡点提醒)
+ val isInRange: Boolean? = null,//是否在打卡范围内
+) : Parcelable {
+ //是否有效
+ fun isEffective() = (checkLocationId?.toIntOrNull() ?: 0) > 0
+
+ //是否需要显示超时提示
+ fun needShowTimeoutNotice() = messageType == "1" && isEffective()
+
+ //是否需要显示打卡提示
+ fun needShowCheckInNotice() = messageType == "2" && isEffective()
+
+ //是否在打卡范围内
+ fun isLocationInCheckInRange() = isInRange == true
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/CruiseCheckInOperationResult.kt b/app/src/main/java/com/xw/yunwei/model/CruiseCheckInOperationResult.kt
new file mode 100644
index 0000000..3cb8326
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/model/CruiseCheckInOperationResult.kt
@@ -0,0 +1,59 @@
+package com.xw.yunwei.model
+
+import android.os.Parcelable
+import com.blankj.utilcode.util.GsonUtils
+import com.google.gson.reflect.TypeToken
+import kotlinx.parcelize.Parcelize
+import java.text.SimpleDateFormat
+import java.util.Locale
+
+//巡游打卡操作结果
+@Parcelize
+data class CruiseCheckInOperationResult(
+ val id: String,
+ val cruiseCheckInRuleId: String?,//巡游打卡任务id
+ val checkLocationId: String?,//打卡点位id
+ val checkIn: String?,//是否已打卡(0=否,1=是)
+ val checkInResult: String?,//打卡结果(1=正常打卡,2=超时打卡)
+ val checkInTime: String? = null, // 打卡时间,仅已打卡/超时打卡时有值
+ val fieldSituation: String? = null,//现场情况(1=正常,2=拥堵)
+ val sceneDescription: String? = null,//现场情况说明
+ val scenePhoto: String? = null,//现场照片JSON数组
+) : Parcelable {
+
+ //获取显示状态
+ fun getShowCheckInStatus() = checkInResult?.let {
+ when (it) {
+ "1" -> "正常打卡"
+ "2" -> "超时打卡"
+ else -> "未打卡"
+ }
+ } ?: "未打卡"
+
+ //获取显示打卡时间
+ fun getShowCheckInTime(): String? {
+ return try {
+ checkInTime?.replace("T", " ")?.let { it ->
+ SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).parse(it)?.let {
+ SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.getDefault()).format(it)
+ }
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ checkInTime
+ }
+ }
+
+ //获取显示工作状态
+ fun getShowWorkStatus() = if (fieldSituation == "1") "正常" else "异常"
+
+ //获取上传结果
+ fun getUploadInfoList(): List<UploadModel>? {
+ return scenePhoto?.takeIf { it.isNotEmpty() }?.let {
+ GsonUtils.fromJson(
+ it,
+ object : TypeToken<List<UploadModel>>() {}.type
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/LoginModel.kt b/app/src/main/java/com/xw/yunwei/model/LoginModel.kt
index 8ffd8d9..889e177 100644
--- a/app/src/main/java/com/xw/yunwei/model/LoginModel.kt
+++ b/app/src/main/java/com/xw/yunwei/model/LoginModel.kt
@@ -2,7 +2,8 @@
data class LoginModel(
val info: Info?,
- val token: Token?
+ val token: Token?,
+ val thirdInfo: ThirdInfo?
)
data class Info(
@@ -44,6 +45,12 @@
val updateTime: String?
)
+//第三方sdk信息
+data class ThirdInfo(
+ val pushKey: String,//阿里推送appKey
+ val pushSecret: String,//阿里推送appSecret
+)
+
/**
* 用户信息实体类
* 包含用户基本信息、所属车队、角色列表等完整信息
diff --git a/app/src/main/java/com/xw/yunwei/model/RoutePlanningOperationInfo.kt b/app/src/main/java/com/xw/yunwei/model/RoutePlanningOperationInfo.kt
new file mode 100644
index 0000000..cd7e19e
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/model/RoutePlanningOperationInfo.kt
@@ -0,0 +1,12 @@
+package com.xw.yunwei.model
+
+import com.amap.api.navi.model.AMapNaviPath
+import com.amap.api.navi.model.NaviPoi
+
+//路线规划操作信息
+class RoutePlanningOperationInfo(
+ var type: Int,
+ var passingPoints: List<NaviPoi>,
+ var endPoint: NaviPoi,
+ val naviPaths: MutableList<AMapNaviPath> = mutableListOf(),
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/SiteModel.kt b/app/src/main/java/com/xw/yunwei/model/SiteModel.kt
index 836e582..76d2ba3 100644
--- a/app/src/main/java/com/xw/yunwei/model/SiteModel.kt
+++ b/app/src/main/java/com/xw/yunwei/model/SiteModel.kt
@@ -1,10 +1,15 @@
package com.xw.yunwei.model
+import android.os.Parcelable
import com.google.gson.annotations.SerializedName
+import kotlinx.parcelize.Parcelize
+
+val sitePlaceHolder = SiteModel()
/**
* 点位管理数据类
*/
+@Parcelize
data class SiteModel(
/**
@@ -151,4 +156,4 @@
*/
@SerializedName("distance")
val distance: Double? = null
-)
\ No newline at end of file
+) : Parcelable
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/TaskAccidentModel.kt b/app/src/main/java/com/xw/yunwei/model/TaskAccidentModel.kt
index 797c168..9647ea6 100644
--- a/app/src/main/java/com/xw/yunwei/model/TaskAccidentModel.kt
+++ b/app/src/main/java/com/xw/yunwei/model/TaskAccidentModel.kt
@@ -1,6 +1,8 @@
package com.xw.yunwei.model
import com.google.gson.annotations.SerializedName
+import com.xw.yunwei.extension.dateChangePattern
+import kotlin.math.min
/**
* 任务事故详情
@@ -143,7 +145,12 @@
* 可以操作到达的配置范围,单位米
*/
@SerializedName("canArriveRange")
- val canArriveRange: Int? = null
+ val canArriveRange: Int? = null,
+
+ /**
+ * 是否已经打开后备箱 1是 前端字段
+ */
+ val hadTrunkOpened: String? = null
) {
/**
@@ -159,6 +166,32 @@
}
return names.filter { it.isNotEmpty() }
}
+
+ //是否已开启车门
+ fun hadOpenedDoor(): Boolean {
+ return false
+ }
+
+ //是否已开启后备箱
+ fun hadOpenedTrunk(): Boolean {
+ return hadTrunkOpened == "1"
+ }
+
+ //获取显示创建事件
+ fun getShowCreateTime(): String?{
+ return createTime?.dateChangePattern("yyyy-MM-dd HH:mm:ss","yyyy/MM/dd HH:mm:ss")
+ }
+
+ //获取显示车身编码
+ fun getShowVehicleCode(maxLength: Int): String {
+ return vehicleCode?.let {
+ if (it.isNotEmpty()) {
+ it.substring(0, min(it.length, maxLength))
+ } else {
+ ""
+ }
+ } ?: ""
+ }
}
/**
diff --git a/app/src/main/java/com/xw/yunwei/model/TaskModel.kt b/app/src/main/java/com/xw/yunwei/model/TaskModel.kt
index 1a37f3f..d52dfb5 100644
--- a/app/src/main/java/com/xw/yunwei/model/TaskModel.kt
+++ b/app/src/main/java/com/xw/yunwei/model/TaskModel.kt
@@ -2,6 +2,8 @@
import com.google.gson.annotations.SerializedName
+val taskPlaceHolder = TaskModel()
+
/**
* 车辆任务实体类
*/
@@ -31,6 +33,7 @@
* 1 = 待处理
* 2 = 已完成
* 3 = 已取消
+ * 4 = 改派中
*/
@SerializedName("status")
val status: Int? = null,
@@ -102,28 +105,38 @@
* 可以操作到达的配置范围,单位米
*/
@SerializedName("canArriveRange")
- val canArriveRange: Int? = null
-
-
+ val canArriveRange: Int? = null,
+ //websocket 功能控制字段 是否震动
+ val vibration: Boolean = true,
+ //websocket 功能控制字段 是否语音
+ val voiceBroadcast: Boolean = true,
) {
companion object Companion {
// 常规任务类型枚举(taskCategory=1时使用)
/** 车辆检查 */
const val TYPE_VEHICLE_CHECK = "1"
+
/** 车辆充电 */
const val TYPE_VEHICLE_CHARGING = "2"
+
/** 车辆整备 */
const val TYPE_VEHICLE_PREPARATION = "3"
+
/** 整备洗车 */
const val TYPE_PREPARATION_WASH = "4"
+
/** 车辆维修 */
const val TYPE_VEHICLE_REPAIR = "5"
+
/** 车辆保养 */
const val TYPE_VEHICLE_MAINTENANCE = "6"
+
/** 车辆保险到期 */
const val TYPE_INSURANCE_EXPIRE = "7"
+
/** 车辆年检到期 */
const val TYPE_ANNUAL_INSPECTION_EXPIRE = "8"
+
/** 车辆运营资质到期 */
const val TYPE_OPERATING_LICENSE_EXPIRE = "9"
}
diff --git a/app/src/main/java/com/xw/yunwei/model/TaskNormalChargeModel.kt b/app/src/main/java/com/xw/yunwei/model/TaskNormalChargeModel.kt
index 07e511c..779b463 100644
--- a/app/src/main/java/com/xw/yunwei/model/TaskNormalChargeModel.kt
+++ b/app/src/main/java/com/xw/yunwei/model/TaskNormalChargeModel.kt
@@ -1,6 +1,7 @@
package com.xw.yunwei.model
import com.google.gson.annotations.SerializedName
+import com.xw.yunwei.extension.dateChangePattern
/**
* 常规任务任务充电详情
@@ -175,4 +176,13 @@
*/
@SerializedName("vehicleLocation")
val vehicleLocation: String? = null
-)
\ No newline at end of file
+){
+ //获取显示开始充电时间
+ fun getShowStartTime(): String?{
+ return startTime?.dateChangePattern("yyyy-MM-dd HH:mm:ss","yyyy/MM/dd HH:mm:ss")
+ }
+ //获取显示结束充电时间
+ fun getShowEndTime(): String?{
+ return endTime?.dateChangePattern("yyyy-MM-dd HH:mm:ss","yyyy/MM/dd HH:mm:ss")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/TaskNormalCheckModel.kt b/app/src/main/java/com/xw/yunwei/model/TaskNormalCheckModel.kt
index 6c65246..a59e408 100644
--- a/app/src/main/java/com/xw/yunwei/model/TaskNormalCheckModel.kt
+++ b/app/src/main/java/com/xw/yunwei/model/TaskNormalCheckModel.kt
@@ -1,6 +1,7 @@
package com.xw.yunwei.model
import com.google.gson.annotations.SerializedName
+import com.xw.yunwei.extension.dateChangePattern
/**
* 常规任务任务检测详情
@@ -234,4 +235,11 @@
*/
@SerializedName("versionVerification")
val versionVerification: Int? = null
-)
\ No newline at end of file
+){
+
+ //获取显示检测时间
+ fun getShowCheckTime(): String?{
+ return checkTime?.dateChangePattern("yyyy-MM-dd HH:mm:ss","yyyy/MM/dd HH:mm:ss")
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/TaskNormalMaintainModel.kt b/app/src/main/java/com/xw/yunwei/model/TaskNormalMaintainModel.kt
index 4e873f5..cf99bd2 100644
--- a/app/src/main/java/com/xw/yunwei/model/TaskNormalMaintainModel.kt
+++ b/app/src/main/java/com/xw/yunwei/model/TaskNormalMaintainModel.kt
@@ -1,6 +1,7 @@
package com.xw.yunwei.model
import com.google.gson.annotations.SerializedName
+import com.xw.yunwei.extension.dateChangePattern
/**
* 常规任务任务整备详情
@@ -199,4 +200,9 @@
*/
@SerializedName("vehicleLocation")
val vehicleLocation: String? = null
-)
\ No newline at end of file
+) {
+ //获取显示操作时间
+ fun getShowOperationsTime(): String?{
+ return operationsTime?.dateChangePattern("yyyy-MM-dd HH:mm:ss","yyyy/MM/dd HH:mm:ss")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/TaskNormalModel.kt b/app/src/main/java/com/xw/yunwei/model/TaskNormalModel.kt
index 1f535b1..40fcce8 100644
--- a/app/src/main/java/com/xw/yunwei/model/TaskNormalModel.kt
+++ b/app/src/main/java/com/xw/yunwei/model/TaskNormalModel.kt
@@ -1,6 +1,8 @@
package com.xw.yunwei.model
import com.google.gson.annotations.SerializedName
+import com.xw.yunwei.extension.dateChangePattern
+import kotlin.math.min
/**
* 常规任务详情
@@ -145,4 +147,30 @@
*/
@SerializedName("vehicleLon")
val vehicleLon: Double? = null,
-)
\ No newline at end of file
+){
+ //是否能够改派
+ fun couldReassignment(): Boolean {
+ return status != 2 && taskCategory != 1
+ }
+
+ //获取显示创建事件
+ fun getShowCreateTime(): String?{
+ return createTime?.dateChangePattern("yyyy-MM-dd HH:mm:ss","yyyy/MM/dd HH:mm:ss")
+ }
+
+ //获取显示车身编码
+ fun getShowVehicleCode(maxLength: Int): String {
+ return vehicleCode?.let {
+ if (it.isNotEmpty()) {
+ it.substring(0, min(it.length, maxLength))
+ } else {
+ ""
+ }
+ } ?: ""
+ }
+
+ //获取显示操作时间
+ fun getShowHandleTime(): String?{
+ return handleTime?.dateChangePattern("yyyy-MM-dd HH:mm:ss","yyyy/MM/dd HH:mm:ss")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/TaskNormalRepairModel.kt b/app/src/main/java/com/xw/yunwei/model/TaskNormalRepairModel.kt
index 17ffa23..9d77c2c 100644
--- a/app/src/main/java/com/xw/yunwei/model/TaskNormalRepairModel.kt
+++ b/app/src/main/java/com/xw/yunwei/model/TaskNormalRepairModel.kt
@@ -1,6 +1,7 @@
package com.xw.yunwei.model
import com.google.gson.annotations.SerializedName
+import com.xw.yunwei.extension.dateChangePattern
/**
* 常规任务任务维修详情
@@ -181,4 +182,24 @@
*/
@SerializedName("vehicleLocation")
val vehicleLocation: String? = null
-)
\ No newline at end of file
+) {
+
+ //获取显示开始时间
+ fun getShowStartTime(): String?{
+ return startTime?.dateChangePattern("yyyy年MM月dd日","yyyy/MM/dd")
+ }
+
+ //获取显示结束时间
+ fun getShowEndTime(): String?{
+ return endTime?.dateChangePattern("yyyy年MM月dd日","yyyy/MM/dd")
+ }
+
+ //获取显示送修时间
+ fun getShowSendTime(): String?{
+ return sendTime?.dateChangePattern("yyyy年MM月dd日 HH:mm:ss","yyyy/MM/dd HH:mm:ss")
+ }
+ //获取显示取回时间
+ fun getShowReturnTime(): String?{
+ return returnTime?.dateChangePattern("yyyy年MM月dd日 HH:mm:ss","yyyy/MM/dd HH:mm:ss")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/TaskStatisticInfo.kt b/app/src/main/java/com/xw/yunwei/model/TaskStatisticInfo.kt
new file mode 100644
index 0000000..c070464
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/model/TaskStatisticInfo.kt
@@ -0,0 +1,12 @@
+package com.xw.yunwei.model
+
+//任务统计信息
+data class TaskStatisticInfo(
+ var totalTableCount: Int?,//全部数量
+ var reassignmentCount: Int?,//改派中数量
+ var waitArriveCount: Int?,//待到达数量
+ var waitHandleCount: Int?,//待处理数量
+ var totalCount: Int?,//底部全部事故数量
+ var accidentCount: Int?,//底部事故数量
+ var routineCount: Int?,//底部常规数量
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/TrunkLockStatusInfo.kt b/app/src/main/java/com/xw/yunwei/model/TrunkLockStatusInfo.kt
new file mode 100644
index 0000000..421bf62
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/model/TrunkLockStatusInfo.kt
@@ -0,0 +1,4 @@
+package com.xw.yunwei.model
+
+//后备箱解锁状态
+data class TrunkLockStatusInfo(val status: String? = null)
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/UploadModel.kt b/app/src/main/java/com/xw/yunwei/model/UploadModel.kt
index 34b676f..72c17fc 100644
--- a/app/src/main/java/com/xw/yunwei/model/UploadModel.kt
+++ b/app/src/main/java/com/xw/yunwei/model/UploadModel.kt
@@ -1,7 +1,12 @@
package com.xw.yunwei.model
+import android.os.Parcelable
+import kotlinx.parcelize.Parcelize
+
+//上传结果
+@Parcelize
data class UploadModel(
val url: String?,
val name: String?,
val id: String?
-)
+) : Parcelable
diff --git a/app/src/main/java/com/xw/yunwei/model/VehicleLocationInfo.kt b/app/src/main/java/com/xw/yunwei/model/VehicleLocationInfo.kt
index 64a3291..78cd481 100644
--- a/app/src/main/java/com/xw/yunwei/model/VehicleLocationInfo.kt
+++ b/app/src/main/java/com/xw/yunwei/model/VehicleLocationInfo.kt
@@ -5,4 +5,5 @@
val longitude: String? = null,//经度
val latitude: String? = null,//纬度
val address: String? = null,//地址
+ val tips: String? = null,//提示语
)
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/model/event/TaskEvent.kt b/app/src/main/java/com/xw/yunwei/model/event/TaskEvent.kt
new file mode 100644
index 0000000..40a17c6
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/model/event/TaskEvent.kt
@@ -0,0 +1,7 @@
+package com.xw.yunwei.model.event
+
+//任务事件
+sealed class TaskEvent(val taskId: String? = null) {
+ //任务接收事件
+ class TaskAcceptEvent(taskId: String?) : TaskEvent(taskId)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/net/TaskApi.kt b/app/src/main/java/com/xw/yunwei/net/TaskApi.kt
index db4b399..e9b1d6d 100644
--- a/app/src/main/java/com/xw/yunwei/net/TaskApi.kt
+++ b/app/src/main/java/com/xw/yunwei/net/TaskApi.kt
@@ -10,12 +10,15 @@
import com.xw.yunwei.model.TaskNormalMaintainModel
import com.xw.yunwei.model.TaskNormalModel
import com.xw.yunwei.model.TaskNormalRepairModel
+import com.xw.yunwei.model.TaskStatisticInfo
+import com.xw.yunwei.model.VehicleLocationInfo
import com.xw.yunwei.model.XpErrorType
import okhttp3.RequestBody
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
+import retrofit2.http.Path
import retrofit2.http.Query
interface TaskApi {
@@ -76,5 +79,23 @@
@GET("account/maintenance-app/api/v1/notification/unreadCount")
fun getUnreadCount(): Call<HttpResponse<String>>
+ /*任务改派*/
+ @POST("maintenance/maintenance-app/api/v1/task/reassign")
+ fun taskReassignment(@Body body: RequestBody): Call<HttpResponse<Any>>
+ /*检测申请改派结果*/
+ @POST("maintenance/maintenance-app/api/v1/task/getTaskReassignmentStatus/{taskId}")
+ fun checkApplyForReassignResult(@Path("taskId") taskId: String): Call<HttpResponse<Boolean>>
+
+ /*接收工单*/
+ @POST("maintenance/maintenance-app/api/v1/task/accept/{taskId}")
+ fun acceptTask(@Path("taskId") taskId: String): Call<HttpResponse<Any>>
+
+ /*任务中心状态统计*/
+ @POST("maintenance/maintenance-app/api/v1/task/statistic")
+ fun statistic(@Body body: RequestBody): Call<HttpResponse<TaskStatisticInfo>>
+
+ /*查询车辆新位置信息*/
+ @POST("maintenance/maintenance-app/api/v1/task/queryVehicleNewPoint")
+ fun queryVehicleNewPoint(@Body body: RequestBody): Call<HttpResponse<VehicleLocationInfo>>
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/net/TaskRepository.kt b/app/src/main/java/com/xw/yunwei/net/TaskRepository.kt
index ee98791..30328d0 100644
--- a/app/src/main/java/com/xw/yunwei/net/TaskRepository.kt
+++ b/app/src/main/java/com/xw/yunwei/net/TaskRepository.kt
@@ -1,7 +1,10 @@
package com.xw.yunwei.net
+import com.xw.common.Constants
import com.xw.common.net.BaseHttpManager.Companion.getBody
import com.xw.common.net.interceptAwait
+import com.xw.yunwei.model.TaskStatisticInfo
+import com.xw.yunwei.model.VehicleLocationInfo
class TaskRepository(private val api: TaskApi) {
@@ -11,7 +14,7 @@
suspend fun saveRoutineDetail(map: Map<String, Any?>) =
api.saveRoutineDetail(getBody(map)).interceptAwait()
- suspend fun saveVehicleAccident(map: Map<String, Any?>) =
+ suspend fun saveVehicleAccident(map: Map<String, Any?>) =
api.saveVehicleAccident(getBody(map)).interceptAwait()
suspend fun handleVehicleAccident(map: Map<String, Any?>) =
@@ -28,4 +31,51 @@
suspend fun getTypeList() = api.getTypeList().interceptAwait()
suspend fun getUnreadCount() = api.getUnreadCount().interceptAwait()
+ /*任务改派*/
+ suspend fun taskReassignment(comment: String, remark: String, taskId: String?): Boolean {
+ val map = mapOf<String, Any?>("comment" to comment, "remark" to remark, "taskId" to taskId)
+ api.taskReassignment(getBody(map)).interceptAwait()
+ return true
+ }
+
+ /*检测申请改派结果*/
+ suspend fun checkApplyForReassignResult(taskId: String): Boolean? {
+ return api.checkApplyForReassignResult(taskId).interceptAwait()
+ }
+
+ /*接收工单*/
+ suspend fun acceptTask(taskId: String): Boolean {
+ api.acceptTask(taskId).interceptAwait()
+ return true
+ }
+
+ /*任务中心状态统计*/
+ suspend fun statistic(
+ distributeType: String?,
+ startTime: String?,
+ endTime: String?,
+ taskCategory: String?,
+ taskUrgencyLevel: String?,
+ plateNumber: String?
+ ): TaskStatisticInfo? {
+ val map = mapOf(
+ "distributeType" to distributeType,
+ "startTime" to if (startTime.isNullOrEmpty()) null else plateNumber,
+ "endTime" to if (endTime.isNullOrEmpty()) null else plateNumber,
+ "taskUrgencyLevel" to taskUrgencyLevel,
+ "taskCategory" to taskCategory,
+ "plateNumber" to if (plateNumber.isNullOrEmpty()) null else plateNumber,
+ )
+ return api.statistic(getBody(map)).interceptAwait()
+ }
+
+ /*查询车辆新位置信息*/
+ suspend fun queryVehicleNewPoint(vehicleId: String?): VehicleLocationInfo? {
+ val map = mapOf(
+ "vehicleId" to vehicleId,
+ "longitude" to Constants.longitude,
+ "latitude" to Constants.latitude
+ )
+ return api.queryVehicleNewPoint(getBody(map)).interceptAwait()
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/net/UserApi.kt b/app/src/main/java/com/xw/yunwei/net/UserApi.kt
index 4a934a3..b746825 100644
--- a/app/src/main/java/com/xw/yunwei/net/UserApi.kt
+++ b/app/src/main/java/com/xw/yunwei/net/UserApi.kt
@@ -2,9 +2,11 @@
import com.xw.common.net.interceptor.HttpResponse
import com.xw.common.net.interceptor.PageResponse
+import com.xw.yunwei.model.AgreeInfo
import com.xw.yunwei.BuildConfig
import com.xw.yunwei.model.AppPermissionModel
import com.xw.yunwei.model.AppVersionModel
+import com.xw.yunwei.model.CertificateAuditInfo
import com.xw.yunwei.model.ClockInStatusModel
import com.xw.yunwei.model.LoginModel
import com.xw.yunwei.model.NoticeModel
@@ -40,7 +42,7 @@
@Header("XT-Nonce") nonce: String,
@Header("XT-AppId") appId: String,
@Header("XT-Signature") sign: String,
- @Header("Authorization") token: String
+ @Header("XP-TOKEN") token: String
): Call<HttpResponse<LoginModel>>
/*获取手机验证码*/
@@ -98,4 +100,19 @@
@GET("operation/maintenance-app/api/v1/getAppPermission")
fun getAppPermission(): Call<HttpResponse<List<AppPermissionModel>>>
+ /*获取协议配置 */
+ @GET("operation/maintenance-app/base/v1/loginAgreement/getLoginAgreementList")
+ fun getAgreeConfig(): Call<HttpResponse<List<AgreeInfo>>>
+
+ /*获取登录协议*/
+ @GET("operation/maintenance-app/base/v1/privacy/getAppContentById/{id}")
+ fun getLoginProtocol(@Path("id") id: Int): Call<HttpResponse<WebContentModel>>
+
+ /*个人中心-查询证件上传详情*/
+ @POST("account/maintenance-app/api/v1/getCertificate")
+ fun getCertificate(): Call<HttpResponse<CertificateAuditInfo>>
+
+ /*个人中心-退出登录*/
+ @POST("account/maintenance-app/ssoAuthSdk/appLoginOut")
+ fun appLoginOut(): Call<HttpResponse<Any>>
}
diff --git a/app/src/main/java/com/xw/yunwei/net/UserRepository.kt b/app/src/main/java/com/xw/yunwei/net/UserRepository.kt
index 7586024..05a1754 100644
--- a/app/src/main/java/com/xw/yunwei/net/UserRepository.kt
+++ b/app/src/main/java/com/xw/yunwei/net/UserRepository.kt
@@ -79,7 +79,17 @@
suspend fun clockOut(map: Map<String, Any?>) =
api.clockOut(getBody(map)).interceptAwait()
+ /*获取协议配置 */
+ suspend fun getAgreeConfig() = api.getAgreeConfig().interceptAwait()
+
fun getUserInfo() = flow { emit(api.getUserInfo().interceptAwait()) }
+ /*获取登录协议*/
+ suspend fun getLoginProtocol(id: Int) = api.getLoginProtocol(id).interceptAwait()
+ /*个人中心-查询证件上传详情*/
+ suspend fun getCertificate() = api.getCertificate().interceptAwait()
+
+ /*个人中心-退出登录*/
+ suspend fun appLoginOut() = api.appLoginOut().interceptAwait()
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/net/WorkApi.kt b/app/src/main/java/com/xw/yunwei/net/WorkApi.kt
index eae9d18..2ce1b5d 100644
--- a/app/src/main/java/com/xw/yunwei/net/WorkApi.kt
+++ b/app/src/main/java/com/xw/yunwei/net/WorkApi.kt
@@ -2,6 +2,7 @@
import com.xw.common.net.interceptor.HttpResponse
import com.xw.common.net.interceptor.PageResponse
+import com.xw.yunwei.model.AcceptCarPointInfo
import com.xw.yunwei.model.AreaModel
import com.xw.yunwei.model.CarModel
import com.xw.yunwei.model.CarOperationRecordModel
@@ -12,11 +13,16 @@
import com.xw.yunwei.model.CarRecordRepairModel
import com.xw.yunwei.model.CarReportModel
import com.xw.yunwei.model.ChargeRecordModel
+import com.xw.yunwei.model.CheckInMissionPointInfo
import com.xw.yunwei.model.CheckRecordModel
+import com.xw.yunwei.model.CruiseCheckInMissionInfo
+import com.xw.yunwei.model.CruiseCheckInOperationInfo
+import com.xw.yunwei.model.CruiseCheckInOperationResult
import com.xw.yunwei.model.FenceInfoModel
import com.xw.yunwei.model.MaintainRecordModel
import com.xw.yunwei.model.RepairRecordModel
import com.xw.yunwei.model.SiteModel
+import com.xw.yunwei.model.TrunkLockStatusInfo
import com.xw.yunwei.model.VehicleLocationInfo
import com.xw.yunwei.model.WebContent1Model
import okhttp3.RequestBody
@@ -54,8 +60,8 @@
fun vehicleDispatchDeparture(@Body body: RequestBody): Call<HttpResponse<CarModel>>
/* 车辆运维-车门解锁/后备箱解锁 */
- @POST("vehicleConvoy/maintenance-app/api/v1/vehicle/unlockByType")
- fun unlockByType(@Body body: RequestBody): Call<HttpResponse<CarModel>>
+ @POST("vehicleConvoy/maintenance-app/api/v1/vehicle/unlockDoor")
+ fun unlockByType(@Body body: RequestBody): Call<HttpResponse<Any>>
/* 车辆运维-车辆运维-车辆整备 */
@POST("maintenance/maintenance-app/api/v1/vehiclePreparation/savePreparation")
@@ -140,4 +146,38 @@
/* 获取车辆实时位置 */
@GET("maintenance/maintenance-app/api/v1/task/getVehicleLocation/{vehicleId}")
fun getVehicleLocation(@Path("vehicleId") vehicleId: String): Call<HttpResponse<VehicleLocationInfo>>
+ /* 现场情况上报 */
+ @POST("operation/maintenance-app/api/v1/pointSituationReport/addPointSituationReport")
+ fun addPointSituationReport(@Body params: RequestBody): Call<HttpResponse<Any>>
+
+ /* 获取个人中心巡游打卡任务 */
+ @GET("maintenance/maintenance-app/api/v1/cruiseCheckInRule/getMyXpCruiseCheckInRule")
+ fun getMyCruiseCheckInMissionInfo(): Call<HttpResponse<CruiseCheckInMissionInfo>>
+
+ /* 获取巡游打卡定位列表 */
+ @GET("maintenance/maintenance-app/api/v1/cruiseCheckInRule/getAppXpCruiseCheckInLocation/{id}")
+ fun getCheckInMissionPointsList(@Path("id") id: String): Call<HttpResponse<List<CheckInMissionPointInfo>>>
+
+ /* 巡游打卡5秒钟轮询上传实时位置 */
+ @POST("maintenance/maintenance-app/api/v1/cruiseCheckInRule/uploadRealTimePosition")
+ fun uploadRealTimePosition(@Body params: RequestBody): Call<HttpResponse<CruiseCheckInOperationInfo>>
+
+ /* 巡游打卡操作 */
+ @POST("maintenance/maintenance-app/api/v1/cruiseCheckInRule/saveCruiseCheckInRecord")
+ fun saveCruiseCheckInRecord(@Body params: RequestBody): Call<HttpResponse<CruiseCheckInOperationResult>>
+
+ /* 获取打卡结果详情 */
+ @GET("maintenance/maintenance-app/api/v1/cruiseCheckInRule/getCruiseCheckInRecordInfo/{id}/{locationId}")
+ fun getCruiseCheckInRecordInfo(
+ @Path("id") id: String,
+ @Path("locationId") locationId: String
+ ): Call<HttpResponse<CruiseCheckInOperationResult>>
+
+ /* 获取所有收车点 */
+ @GET("operation/maintenance-app/api/v1/point/listParkingPoint")
+ fun getAllAcceptCarPoints(@Query("vehicleId") vehicleId: String): Call<HttpResponse<List<AcceptCarPointInfo>>>
+
+ /* 车辆运维-检测后备箱解锁状态 */
+ @GET("vehicleConvoy/maintenance-app/api/v1/order/queryVehicleTrunkStatus")
+ fun checkTrunkLockStatus(@Query("vehicleId") vehicleId: String): Call<HttpResponse<Int>>
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/net/WorkRepository.kt b/app/src/main/java/com/xw/yunwei/net/WorkRepository.kt
index d665833..d9300a3 100644
--- a/app/src/main/java/com/xw/yunwei/net/WorkRepository.kt
+++ b/app/src/main/java/com/xw/yunwei/net/WorkRepository.kt
@@ -1,9 +1,18 @@
package com.xw.yunwei.net
+import com.blankj.utilcode.util.GsonUtils
import com.xw.common.net.BaseHttpManager.Companion.getBody
import com.xw.common.net.interceptAwait
+import com.xw.yunwei.model.AcceptCarPointInfo
+import com.xw.yunwei.model.CheckInMissionPointInfo
import com.xw.yunwei.model.CheckRecordModel
+import com.xw.yunwei.model.CruiseCheckInMissionInfo
+import com.xw.yunwei.model.CruiseCheckInOperationInfo
+import com.xw.yunwei.model.CruiseCheckInOperationResult
import com.xw.yunwei.model.MaintainRecordModel
+import com.xw.yunwei.model.SiteModel
+import com.xw.yunwei.model.TrunkLockStatusInfo
+import com.xw.yunwei.model.UploadModel
class WorkRepository(private val api: WorkApi) {
@@ -18,20 +27,17 @@
suspend fun unlockByType(map: Map<String, Any?>) =
api.unlockByType(getBody(map)).interceptAwait()
- suspend fun saveRepair(map: Map<String, Any?>) =
- api.saveRepair(getBody(map)).interceptAwait()
+ suspend fun saveRepair(map: Map<String, Any?>) = api.saveRepair(getBody(map)).interceptAwait()
suspend fun saveReturnRepair(map: Map<String, Any?>) =
api.saveReturnRepair(getBody(map)).interceptAwait()
- suspend fun cleanCar(map: Map<String, Any?>) =
- api.cleanCar(getBody(map)).interceptAwait()
+ suspend fun cleanCar(map: Map<String, Any?>) = api.cleanCar(getBody(map)).interceptAwait()
suspend fun savePreparation(body: MaintainRecordModel) =
api.savePreparation(body).interceptAwait()
- suspend fun getRecord(map: Map<String, Any?>) =
- api.getRecord(getBody(map)).interceptAwait()
+ suspend fun getRecord(map: Map<String, Any?>) = api.getRecord(getBody(map)).interceptAwait()
suspend fun startCharging(map: Map<String, Any?>) =
api.startCharging(getBody(map)).interceptAwait()
@@ -58,4 +64,78 @@
/* 获取车辆实时位置 */
suspend fun getVehicleLocation(vehicleId: String) =
api.getVehicleLocation(vehicleId).interceptAwait()
+
+ /* 现场情况上报 */
+ suspend fun addPointSituationReport(
+ work: Boolean,
+ model: SiteModel,
+ sceneDescription: String,
+ scenePhoto: MutableList<UploadModel>,
+ ): Boolean {
+ val map = mapOf<String, Any>(
+ "fieldSituation" to if (work) 1 else 2,//现场情况(1=正常,2=异常)
+ "pointId" to model.id.toString(),//点位id
+ "sceneDescription" to sceneDescription,//现场情况说明
+ "scenePhoto" to GsonUtils.toJson(scenePhoto),//现场照片JSON数组
+ )
+ api.addPointSituationReport(getBody(map)).interceptAwait()
+ return true
+ }
+
+ /* 获取个人中心巡游打卡任务 */
+ suspend fun getMyCruiseCheckInMissionInfo(): CruiseCheckInMissionInfo? {
+ return api.getMyCruiseCheckInMissionInfo().interceptAwait()
+ }
+
+ /* 获取巡游打卡定位列表 */
+ suspend fun getCheckInMissionPointsList(id: String): List<CheckInMissionPointInfo>? {
+ return api.getCheckInMissionPointsList(id).interceptAwait()
+ }
+
+ /* 巡游打卡5秒钟轮询上传实时位置 */
+ suspend fun uploadRealTimePosition(
+ id: String,
+ latitude: Double,
+ longitude: Double,
+ ): CruiseCheckInOperationInfo? {
+ val map = mapOf<String, Any>(
+ "id" to id,
+ "latitude" to latitude,
+ "longitude" to longitude,
+ )
+ return api.uploadRealTimePosition(getBody(map)).interceptAwait()
+ }
+
+ /* 巡游打卡操作 */
+ suspend fun saveCruiseCheckInRecord(
+ locationId: String,
+ work: Boolean,
+ sceneDescription: String,
+ scenePhoto: MutableList<UploadModel>,
+ ): CruiseCheckInOperationResult? {
+ val map = mapOf<String, Any>(
+ "checkLocationId" to locationId,//打卡点位id
+ "fieldSituation" to if (work) 1 else 2,//现场情况(1=正常,2=拥堵)
+ "sceneDescription" to sceneDescription,//现场情况说明
+ "scenePhoto" to GsonUtils.toJson(scenePhoto),//现场照片JSON数组
+ )
+ return api.saveCruiseCheckInRecord(getBody(map)).interceptAwait()
+ }
+
+ /* 获取打卡结果详情 */
+ suspend fun getCruiseCheckInRecordInfo(
+ id: String, locationId: String
+ ): CruiseCheckInOperationResult? {
+ return api.getCruiseCheckInRecordInfo(id, locationId).interceptAwait()
+ }
+
+ /* 获取所有收车点 */
+ suspend fun getAllAcceptCarPoints(vehicleId: String): List<AcceptCarPointInfo>? {
+ return api.getAllAcceptCarPoints(vehicleId).interceptAwait()
+ }
+
+ /* 车辆运维-检测后备箱解锁状态 */
+ suspend fun checkTrunkLockStatus(vehicleId: String): Int? {
+ return api.checkTrunkLockStatus(vehicleId).interceptAwait()
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/push/MessageHandler.kt b/app/src/main/java/com/xw/yunwei/push/MessageHandler.kt
index c69eb06..4f45125 100644
--- a/app/src/main/java/com/xw/yunwei/push/MessageHandler.kt
+++ b/app/src/main/java/com/xw/yunwei/push/MessageHandler.kt
@@ -1,28 +1,27 @@
package com.xw.yunwei.push
-import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
-import android.os.Handler
-import android.os.Looper
-import android.webkit.WebSettings
-import android.webkit.WebView
-import androidx.appcompat.app.AppCompatActivity
+import android.view.View.inflate
+import android.widget.ImageView
+import android.widget.TextView
import androidx.databinding.DataBindingUtil
-import androidx.lifecycle.lifecycleScope
-import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.customview.customView
import com.afollestad.materialdialogs.customview.getCustomView
-import com.google.android.material.tabs.TabLayout
+import com.blankj.utilcode.util.AppUtils
import com.xw.common.net.UpdateManager
+import com.xw.common.net.interceptor.ApiException
import com.xw.common.utils.KeyPreferences
import com.xw.common.utils.LogUtils
import com.xw.common.utils.MMKVManager
import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.MyApp
+import com.xw.yunwei.R
import com.xw.yunwei.databinding.DialogProtocolBinding
+import com.xw.yunwei.model.AgreeInfo
import com.xw.yunwei.model.SwitchTabMain
import com.xw.yunwei.model.SwitchTabTask
+import com.xw.yunwei.net.TaskRepository
import com.xw.yunwei.net.UserRepository
import com.xw.yunwei.ui.MainActivity
import com.xw.yunwei.ui.task.TaskVM
@@ -30,24 +29,35 @@
import com.xw.yunwei.ui.task.normal.NormalTaskDetailActivity
import com.xw.yunwei.ui.user.mine.protocol.ProtocolActivity
import com.xw.yunwei.ui.user.mine.scheduling.SchedulingActivity
+import com.xw.yunwei.ui.work.car.detail.StandardDescriptionActivity
+import com.xw.yunwei.utils.DialogFactory
+import kotlinx.coroutines.CoroutineExceptionHandler
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
-import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.greenrobot.eventbus.EventBus
import org.json.JSONObject
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
-import kotlin.getValue
+import java.io.IOException
+import java.net.ConnectException
+import java.net.SocketException
+import java.net.SocketTimeoutException
+import java.net.UnknownHostException
object MessageHandler : KoinComponent {
+ var TAG = "zmc-${this.javaClass.simpleName}"
val userRepository: UserRepository by inject()
+ val taskRepository: TaskRepository by inject()
fun handlePushEvent(content: String?, isPush: Boolean = false) {
try {
handlePushEvent(JSONObject(content ?: ""), isPush)
} catch (e: Exception) {
ToastUtilCommon.showError("未获取到消息详情")
- LogUtils.e("zmc-MessageHandler","handlePushEvent content = $content error = $e")
+ LogUtils.e("zmc-MessageHandler", "handlePushEvent content = $content error = $e")
}
}
@@ -59,7 +69,7 @@
@OptIn(DelicateCoroutinesApi::class)
fun handlePushEvent(jsob: JSONObject, isPush: Boolean) {
- LogUtils.i("zmc-MessageHandler","handlePushEvent $jsob isPush = $isPush")
+ LogUtils.i("zmc-MessageHandler", "handlePushEvent $jsob isPush = $isPush")
TaskVM.needRefresh.value = true
/**
* content:消息内容
@@ -71,67 +81,88 @@
val strategy = jsob.optInt("strategy")
val type = jsob.optInt("type")
val id = jsob.optString("id")
- GlobalScope.launch {
+ handleMsg(strategy, id, isPush)
+ }
+
+ private fun handleMsg(
+ strategy: Int,
+ id: String,
+ isPush: Boolean
+ ) {
+ runOnMainThread {
val currentShowActivity = MyApp.myApp.getCurrentShowActivity()
LogUtils.i(
- "zmc-MessageHandler",
- "handlePushEvent ${currentShowActivity.javaClass.name}"
+ "zmc-MessageHandler", "handlePushEvent ${currentShowActivity.javaClass.name}"
)
- handleMsg(currentShowActivity, strategy, id, isPush)
+ when (strategy) {
+ 1, 2, 3, 5 -> { // 1=新增事故,2=事故即将超时提示,3=事故超时提示,5=事故状态变更 点击都跳事故详情
+ if (strategy == 5 && isPush) return@runOnMainThread
+ checkTaskCouldInDetail(id) {
+ if (!it) {
+ ToastUtilCommon.showSuc("事故处理完成,已归档")
+ return@checkTaskCouldInDetail
+ }
+ currentShowActivity.startActivity(
+ Intent(currentShowActivity, AccidentDetailActivity::class.java).apply {
+ putExtra("taskId", id.toLong())
+ })
+ }
+ }
+
+ 4 -> { // 排班信息变动
+ currentShowActivity.startActivity(
+ Intent(currentShowActivity, SchedulingActivity::class.java)
+ )
+ }
+
+ 6, 7 -> { // 6=新增任务,7=任务过期提示 点击都跳任务详情
+ if (isPush) return@runOnMainThread
+ if (strategy == 6 && id == "0") { // 多条任务 跳转任务中心待处理页面
+ EventBus.getDefault().post(SwitchTabMain(1))
+ EventBus.getDefault().post(SwitchTabTask(2))
+ currentShowActivity.startActivity(
+ Intent(
+ currentShowActivity,
+ MainActivity::class.java
+ )
+ )
+ } else {
+ currentShowActivity.startActivity(
+ Intent(
+ currentShowActivity,
+ NormalTaskDetailActivity::class.java
+ ).apply {
+ putExtra("taskId", id.toLong())
+ })
+ }
+ }
+
+ 8, 12 -> { // 升级
+ if (strategy == 8 && isPush) return@runOnMainThread
+ showUpdateDialog(currentShowActivity)
+ }
+
+ 9, 10 -> { // 变更协议内容
+ if (strategy == 9 && isPush) return@runOnMainThread
+ if (strategy == 9) {
+ currentShowActivity.startActivity(
+ Intent(currentShowActivity, ProtocolActivity::class.java)
+ )
+ } else {
+ MMKVManager.getInstance().saveBoolean(KeyPreferences.NEED_READ, true)
+ showProtocolDialog(currentShowActivity, true)
+ }
+ }
+ }
}
}
- private fun handleMsg(currentShowActivity: Activity, strategy: Int, id: String, isPush: Boolean) {
- when (strategy) {
- 1, 2, 3, 5 -> { // 1=新增事故,2=事故即将超时提示,3=事故超时提示,5=事故状态变更 点击都跳事故详情
- if(strategy == 5 && isPush) return
- currentShowActivity.startActivity(
- Intent(currentShowActivity, AccidentDetailActivity::class.java).apply {
- putExtra("taskId", id.toLong())
- }
- )
- }
-
- 4 -> { // 排班信息变动
- currentShowActivity.startActivity(
- Intent(currentShowActivity, SchedulingActivity::class.java)
- )
- }
-
- 6, 7 -> { // 6=新增任务,7=任务过期提示 点击都跳任务详情
- if (isPush) return
- if (strategy == 6 && id == "0") { // 多条任务 跳转任务中心待处理页面
- EventBus.getDefault().post(SwitchTabMain(1))
- EventBus.getDefault().post(SwitchTabTask(2))
- currentShowActivity.startActivity(
- Intent(
- currentShowActivity,
- MainActivity::class.java
- )
- )
- } else {
- currentShowActivity.startActivity(
- Intent(currentShowActivity, NormalTaskDetailActivity::class.java).apply {
- putExtra("taskId", id.toLong())
- }
- )
- }
- }
-
- 8, 12 -> { // 升级
- if(strategy == 8 && isPush) return
- showUpdateDialog(currentShowActivity)
- }
-
- 9, 10 -> { // 变更协议内容
- if (strategy == 9 && isPush) return
- if (strategy == 9) {
- currentShowActivity.startActivity(
- Intent(currentShowActivity, ProtocolActivity::class.java)
- )
- } else {
- MMKVManager.getInstance().saveBoolean(KeyPreferences.NEED_READ, true)
- showProtocolDialog(currentShowActivity, true)
+ //检测任务是否能够进入详情页
+ private fun checkTaskCouldInDetail(taskId: String, block: (could: Boolean) -> Unit) {
+ launchRequest {
+ taskRepository.vehicleAccidentDetail(taskId)?.also {
+ runOnMainThread {
+ block.invoke(it.status != 2)
}
}
}
@@ -148,12 +179,12 @@
}
fun showUpdateDialog(currentShowActivity: Activity) {
- (currentShowActivity as AppCompatActivity).lifecycleScope.launch {
+ launchRequest {
userRepository.getVersion()?.let {
- Handler(Looper.getMainLooper()).post {
+ runOnMainThread {
UpdateManager.instance!!
.setContext(currentShowActivity)
- .apkUrl(it.androidFile ?: "")
+ .apkUrl(it.getDownloadUrl() ?: "")
.updateContent(it.updateDescription ?: "")
.updateVersionCode(it.versionCode ?: 1)
.updateVersionName(it.version ?: "1.0")
@@ -164,113 +195,188 @@
}
}
- fun showProtocolDialog(currentShowActivity: Activity, forced: Boolean) {
- Handler(Looper.getMainLooper()).post {
- MaterialDialog(currentShowActivity).cornerRadius(15f).cancelable(!forced).show {
- customView(
- com.xw.yunwei.R.layout.dialog_protocol,
- noVerticalPadding = true,
- dialogWrapContent = true
- )
- DataBindingUtil.bind<DialogProtocolBinding>(getCustomView())?.let { bind ->
-// val tab1 = bind.protocolLayout.tabLayout.newTab().apply { text = "用户协议" }
-// val tab2 = bind.protocolLayout.tabLayout.newTab().apply { text = "隐私条款" }
-
- val tab1 = bind.protocolLayout.tabLayout.newTab().apply { text = "小鹏Robotaxi...隐私政策" }
- val tab2 = bind.protocolLayout.tabLayout.newTab().apply { text = "第三方共享信息清单" }
- val tab3 = bind.protocolLayout.tabLayout.newTab().apply { text = "个人信息收集清单" }
- val tab4 = bind.protocolLayout.tabLayout.newTab().apply { text = "权限调用" }
-
- bind.protocolLayout.tabLayout.addTab(tab1, true)
- bind.protocolLayout.tabLayout.addTab(tab2, false)
- bind.protocolLayout.tabLayout.addTab(tab3, false)
- bind.protocolLayout.tabLayout.addTab(tab4, false)
-
- // bind.btnLeft.text = if (forced) "取消并退出" else "关闭"
- bind.btnLeft.text = "关闭"
- bind.btnLeft.setOnClickListener {
- dismiss()
- if (forced) {
- currentShowActivity.finishAffinity()
- android.os.Process.killProcess(android.os.Process.myPid())
- }
- }
- bind.btnRight.setOnClickListener {
- MMKVManager.getInstance().saveBoolean(KeyPreferences.NEED_READ, false)
- dismiss()
- }
- initWeb(bind.protocolLayout.web)
-
- val getProtocol: (Int) -> Unit = { type ->
- (currentShowActivity as AppCompatActivity).lifecycleScope.launch {
- val data = userRepository.getProtocol(type)
- Handler(Looper.getMainLooper()).post {
- setContent(bind.protocolLayout.web, data?.content ?: "")
- }
- }
- }
-
- getProtocol(8)
- bind.protocolLayout.tabLayout.addOnTabSelectedListener(object :
- TabLayout.OnTabSelectedListener {
- override fun onTabSelected(tab: TabLayout.Tab?) {
- tab?.let {
- when (it.text) {
- "用户协议" -> getProtocol(1)
- "隐私条款" -> getProtocol(2)
- "小鹏Robotaxi...隐私政策" -> getProtocol(8)
- "第三方共享信息清单" -> getProtocol(9)
- "个人信息收集清单" -> getProtocol(10)
- "权限调用" -> getProtocol(11)
- else -> {}
- }
- }
- }
-
- override fun onTabUnselected(tab: TabLayout.Tab?) {}
- override fun onTabReselected(tab: TabLayout.Tab?) {}
- })
+ fun showProtocolDialog(
+ currentShowActivity: Activity,
+ forced: Boolean,
+ dismissBlock: (() -> Unit)? = null
+ ) {
+ launchRequest {
+ userRepository.getAgreeConfig()?.also { list ->
+ runOnMainThread {
+ showProtocolDialog(currentShowActivity, forced, list, dismissBlock)
}
}
}
}
- @SuppressLint("SetJavaScriptEnabled")
- private fun initWeb(webView: WebView) {
- //声明WebSettings子类
- val webSettings = webView.settings
- webSettings.domStorageEnabled = true //设置适应Html5
-
- //如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
- webSettings.javaScriptEnabled = true //允许js调用
- webSettings.allowFileAccess = true //在File域下,能够执行任意的JavaScript代码,同源策略跨域访问能够对私有目录文件进行访问等
- webSettings.allowContentAccess = true //是否允许在WebView中访问内容URL(Content Url),默认允许
-
- //缩放操作
- webSettings.setSupportZoom(true) //支持缩放,默认为true。是下面那个的前提。
- webSettings.builtInZoomControls = true //设置内置的缩放控件。若为false,则该WebView不可缩放
- webSettings.displayZoomControls = false //隐藏原生的缩放控件
-
- //其他细节操作
- webSettings.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK //关闭webview中缓存
- webSettings.allowFileAccess = true //设置可以访问文件
- webSettings.javaScriptCanOpenWindowsAutomatically = true //支持通过JS打开新窗口
- webSettings.loadsImagesAutomatically = true //支持自动加载图片
- webSettings.defaultTextEncodingName = "utf-8" //设置编码格式
- }
-
- @SuppressLint("SetJavaScriptEnabled")
- private fun setContent(webView: WebView, content: String?) {
- content?.let {
- // 加载并显示HTML代码
- webView.loadDataWithBaseURL(
- null,
- content,
- "text/html",
- "utf-8",
- null
+ //显示隐私弹窗
+ private fun showProtocolDialog(
+ currentShowActivity: Activity,
+ forced: Boolean,
+ list: List<AgreeInfo>,
+ dismissBlock: (() -> Unit)? = null
+ ) {
+ DialogFactory.produce(currentShowActivity).cornerRadius(15f).cancelable(!forced).show {
+ customView(
+ com.xw.yunwei.R.layout.dialog_protocol,
+ noVerticalPadding = true,
+ dialogWrapContent = true
)
+ cornerRadius(8f)
+ DataBindingUtil.bind<DialogProtocolBinding>(getCustomView())?.let { bind ->
+ val checked = mutableSetOf<AgreeInfo>()
+
+ fun refreshCheck(imageView: ImageView, checked: Boolean) {
+ imageView.setImageResource(if (checked) R.mipmap.icon_tick_circle_blue else R.mipmap.icon_circle_gray2)
+ }
+
+ fun checkAllChecked() {
+ (0..<bind.llAgree.childCount).forEachIndexed { index, i ->
+ val checked = checked.contains(list[index])
+ refreshCheck(
+ bind.llAgree.getChildAt(index).findViewById<ImageView>(R.id.iv_check),
+ checked
+ )
+ }
+ refreshCheck(bind.ivCheckAll, checked.size == list.size)
+ }
+
+ list.forEach { info ->
+ val itemView = inflate(
+ currentShowActivity,
+ R.layout.item_protocol,
+ null
+ ).apply {
+ findViewById<ImageView>(R.id.iv_check).apply {
+ setOnClickListener {
+ if (checked.contains(info)) {
+ checked.remove(info)
+ } else {
+ checked.add(info)
+ }
+ checkAllChecked()
+ }
+ }
+ findViewById<TextView>(R.id.tv_name).apply {
+ text = info.name
+ setOnClickListener {
+// if (!checked.contains(info)) {
+// checked.add(info)
+// checkAllChecked()
+// }
+ currentShowActivity.startActivity(
+ Intent(
+ currentShowActivity,
+ StandardDescriptionActivity::class.java
+ ).apply {
+ putExtra("type", info.id?.toInt())
+ putExtra("webType", 1)
+ putExtra("title", info.name)
+ }
+ )
+ }
+ }
+ }
+ bind.llAgree.addView(itemView)
+ }
+ bind.llCheckAll.setOnClickListener {
+ if (checked.size != list.size) {
+ checked.addAll(list)
+ } else {
+ checked.clear()
+ }
+ checkAllChecked()
+ }
+ bind.btnLeft.setOnClickListener {
+ dismiss()
+ if (forced) {
+ currentShowActivity.finishAffinity()
+ android.os.Process.killProcess(android.os.Process.myPid())
+ }
+ }
+ bind.btnRight.setOnClickListener {
+ if (checked.size != list.size) {
+ ToastUtilCommon.showError("请勾选全部协议后再确认同意")
+ return@setOnClickListener
+ }
+ MMKVManager.getInstance().saveBoolean(KeyPreferences.NEED_READ, false)
+ dismiss()
+ }
+
+ }
+ setOnDismissListener { dismissBlock?.invoke() }
}
}
+ private val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
+ LogUtils.e(TAG, "Uncaught coroutine exception: ${throwable.message}")
+ runOnMainThread {
+ ToastUtilCommon.showError(getNetworkErrorMessage(throwable))
+ }
+ }
+
+ private suspend fun errorHandling(
+ e: Throwable,
+ error: suspend (code: Int, msg: String) -> Unit
+ ) {
+ if (e is ApiException) {
+ when {
+ e.isTokenExpired() -> {
+ MMKVManager.getInstance().clear()
+ ToastUtilCommon.showWarn("登录已过期,请重新登录")
+ CoroutineScope(Dispatchers.IO + exceptionHandler).launch {
+ delay(1000)
+ AppUtils.relaunchApp(true)
+ }
+ }
+
+ else -> {
+ error.invoke(e.code, e.message ?: "")
+ }
+ }
+ } else {
+ val errorMsg = getNetworkErrorMessage(e)
+ error.invoke(-1, errorMsg)
+ }
+ }
+
+ /**
+ * 获取网络异常的友好提示信息
+ */
+ private fun getNetworkErrorMessage(e: Throwable): String {
+ return when (e) {
+ is UnknownHostException -> "网络连接失败,请检查网络设置"
+ is ConnectException -> "无法连接到服务器,请检查网络"
+ is SocketTimeoutException -> "连接超时,请稍后重试"
+ is SocketException -> "网络异常,请检查网络连接"
+ is IOException -> "网络请求失败,请检查网络"
+ else -> e.message ?: "未知错误"
+ }
+ }
+
+ //运行在主线程
+ private fun runOnMainThread(block: suspend () -> Unit) {
+ CoroutineScope(Dispatchers.Main + exceptionHandler).launch {
+ block()
+ }
+ }
+
+ private fun launchRequest(
+ error: suspend (code: Int, msg: String) -> Unit = { code, msg ->
+ ToastUtilCommon.showError(msg)
+ LogUtils.e(TAG, "launchRequest: code = $code msg = $msg")
+ }, request: suspend () -> Unit
+ ) {
+ CoroutineScope(Dispatchers.IO + exceptionHandler).launch {
+ try {
+ request()
+ } catch (e: Throwable) {
+ try {
+ errorHandling(e, error)
+ } catch (handlingError: Throwable) {
+ LogUtils.e(TAG, "Error handling failed: ${handlingError.message}")
+ }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/push/PopupPushActivity.kt b/app/src/main/java/com/xw/yunwei/push/PopupPushActivity.kt
new file mode 100644
index 0000000..9e02f59
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/push/PopupPushActivity.kt
@@ -0,0 +1,154 @@
+package com.xw.yunwei.push
+
+import android.content.Intent
+import android.os.Bundle
+import com.alibaba.sdk.android.push.AndroidPopupActivity
+import com.blankj.utilcode.util.ActivityUtils.startActivity
+import com.xw.common.Constants
+import com.xw.common.utils.KeyPreferences
+import com.xw.common.utils.MMKVManager
+import com.xw.yunwei.model.SwitchTabMain
+import com.xw.yunwei.model.SwitchTabTask
+import com.xw.yunwei.push.MessageHandler.showProtocolDialog
+import com.xw.yunwei.push.MessageHandler.showUpdateDialog
+import com.xw.yunwei.ui.MainActivity
+import com.xw.yunwei.ui.task.accident.detail.AccidentDetailActivity
+import com.xw.yunwei.ui.task.normal.NormalTaskDetailActivity
+import com.xw.yunwei.ui.user.login.LoginActivity
+import com.xw.yunwei.ui.user.mine.protocol.ProtocolActivity
+import com.xw.yunwei.ui.user.mine.scheduling.SchedulingActivity
+import org.greenrobot.eventbus.EventBus
+
+/**
+ * 辅助弹窗Activity
+ * 这个方案介绍的是自定义Activity作为中转Activity,辅助获取推送的额外参数,额外参数里必须配置指定Activity的路由信息,您可以根据这些路由信息跳转到指定Activity。
+ * 如果您通过推送通知要打开的Activity页面较多的话,建议用这种方式。
+ * 在推送时,配置的打开的页面要配置成实现的辅助弹窗中转Activity,且真正要打开的指定Activity路由信息需要配置在额外参数中。
+ */
+class PopupPushActivity : AndroidPopupActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ }
+
+ /**
+ * 实现通知打开回调方法,获取通知相关信息
+ * @param title 标题
+ * @param summary 内容
+ * @param extMap 额外参数
+ */
+ override fun onSysNoticeOpened(title: String, summary: String, extMap: Map<String?, String?>?) {
+ if (extMap.isNullOrEmpty()) {
+ startActivity(LoginActivity::class.java)
+ finish()
+ } else {
+ if (Constants.token.isEmpty()) {
+ startActivity(LoginActivity::class.java)
+ finish()
+ return
+ }
+ /**
+ * content:消息内容
+ * strategy:推送策略 1=新增事故,2=事故即将超时提示,3=事故超时提示,4=排班信息变动,5=事故状态变更,6=新增任务,7=任务过期提示,8=版本更新提示,9=变更协议政策内容,10=变更协议内容并需用户授权,11=打卡成功通知, 12=强制升级
+ * type:类型,事故需要,根据不同的id查询不同的事故详情 无-null 1=车辆检测 2=车辆充电 3=车辆整备 4=整备洗车 5=车辆维修 6=其他常规任务 7=事故任务
+ * id:页面id(事故为事故id),无-null或0
+ */
+ val content = extMap["content"]
+ val strategy = extMap["strategy"].toString().toIntOrNull() ?: 0
+ val type = extMap["type"]
+ val id = extMap["id"].toString()
+ when (strategy) {
+ 1, 2, 3, 5 -> { // 1=新增事故,2=事故即将超时提示,3=事故超时提示,5=事故状态变更 点击都跳事故详情
+ startActivities(
+ arrayOf(
+ Intent(this, MainActivity::class.java),
+ Intent(this, AccidentDetailActivity::class.java).apply {
+ putExtra("taskId", id.toLong())
+ }
+ )
+ )
+ finish()
+ }
+
+ 4 -> { // 排班信息变动
+ startActivities(
+ arrayOf(
+ Intent(this, MainActivity::class.java),
+ Intent(this, SchedulingActivity::class.java)
+ )
+ )
+ finish()
+ }
+
+ 6, 7 -> { // 6=新增任务,7=任务过期提示 点击都跳任务详情
+ if (strategy == 6 && id == "0") { // 多条任务 跳转任务中心待处理页面
+ EventBus.getDefault().post(SwitchTabMain(1))
+ EventBus.getDefault().post(SwitchTabTask(2))
+ startActivity(MainActivity::class.java)
+ } else {
+ startActivities(
+ arrayOf(
+ Intent(this, MainActivity::class.java),
+ Intent(
+ this,
+ NormalTaskDetailActivity::class.java
+ ).apply {
+ putExtra("taskId", id.toLong())
+ }
+ )
+ )
+ }
+ finish()
+ }
+
+ 8, 12 -> { // 升级
+ showUpdateDialog(this)
+ }
+
+ 9, 10 -> { // 变更协议内容
+ if (strategy == 9) {
+ startActivities(
+ arrayOf(
+ Intent(this, MainActivity::class.java),
+ Intent(this, ProtocolActivity::class.java)
+ )
+ )
+ finish()
+ } else {
+ MMKVManager.getInstance().saveBoolean(KeyPreferences.NEED_READ, true)
+ showProtocolDialog(this, true) {
+ startActivity(LoginActivity::class.java)
+ finish()
+ }
+ }
+ }
+
+ else -> {
+ startActivity(LoginActivity::class.java)
+ finish()
+ }
+ }
+ }
+ }
+
+ /**
+ * 不是推送数据的回调
+ *
+ * @param intent
+ */
+ override fun onNotPushData(intent: Intent) {
+ super.onNotPushData(intent)
+ startActivity(LoginActivity::class.java)
+ finish()
+ }
+
+ /**
+ * 是推送数据,但是又解密失败时的回调
+ *
+ * @param intent
+ */
+ override fun onParseFailed(intent: Intent) {
+ super.onParseFailed(intent)
+ startActivity(LoginActivity::class.java)
+ finish()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/MainActivity.kt b/app/src/main/java/com/xw/yunwei/ui/MainActivity.kt
index 5c26f40..71adda3 100644
--- a/app/src/main/java/com/xw/yunwei/ui/MainActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/MainActivity.kt
@@ -2,22 +2,26 @@
import android.content.pm.PackageManager
import android.os.Build
+import android.os.Bundle
+import android.view.View
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentTransaction
import androidx.lifecycle.lifecycleScope
+import com.amap.api.location.AMapLocation
import com.blankj.utilcode.util.AppUtils
import com.hjq.permissions.OnPermissionCallback
import com.hjq.permissions.XXPermissions
-import com.xw.common.base.BaseActivity
import com.xw.common.net.UpdateManager
+import com.xw.common.utils.GpsHelper
import com.xw.common.utils.KeyPreferences
import com.xw.common.utils.MMKVManager
import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.MyApp
import com.xw.yunwei.R
import com.xw.yunwei.databinding.ActivityMainBinding
-import com.xw.yunwei.model.LocationData
import com.xw.yunwei.model.SwitchTabMain
import com.xw.yunwei.model.UserInfo
import com.xw.yunwei.push.MessageHandler.showProtocolDialog
@@ -30,7 +34,7 @@
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
-class MainActivity : BaseActivity<ActivityMainBinding, MainVM>() {
+class MainActivity : BaseBusinessActivity<ActivityMainBinding, MainVM>(), GpsHelper.OnMapLocation {
override fun getBindingVariable() = BR.viewModel
private var mCurrentFragment: Fragment? = null
@@ -39,11 +43,34 @@
TaskFragment::class.java.name,
MineFragment::class.java.name
)
+ lateinit var gpsHelper: GpsHelper
+
+ /**
+ * 进程被杀重建时(如后台禁用运行时权限触发进程死亡),
+ * ViewModel 会被重建、selectIndex 丢失并回退到默认 0。
+ * 此处在 ViewModel 创建之后、setObservable 注册观察者之前,
+ * 先把上次保存的 index 恢复回去,避免重建后底部导航错乱。
+ */
+ override fun myCreate(savedInstanceState: Bundle?) {
+ super.myCreate(savedInstanceState)
+ savedInstanceState?.let {
+ if (it.containsKey(KEY_SELECT_INDEX)) {
+ viewModel.selectIndex.value = it.getInt(KEY_SELECT_INDEX)
+ }
+ }
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ viewModel.selectIndex.value?.let { outState.putInt(KEY_SELECT_INDEX, it) }
+ }
override fun init() {
super.init()
val user = MMKVManager.getInstance().getModel<UserInfo>(KeyPreferences.USER)
if (user == null) {
+ MyApp.myApp.disconnectWebSocket()
+ MyApp.myApp.unbindPushAccount()
MMKVManager.getInstance().clear()
ToastUtilCommon.showWarn("登录已过期,请重新登录")
lifecycleScope.launch {
@@ -51,7 +78,16 @@
AppUtils.relaunchApp(true)
}
} else {
+ MyApp.myApp.connectWebSocket()
MyApp.myApp.bindPushAccount(user.phoneNumber ?: "")
+ gpsHelper = GpsHelper(
+ this,
+ this,
+ isOnceLocation = false,
+ savedInstanceState = null,
+ interval = 6000
+ )
+ lifecycle.addObserver(gpsHelper)
}
EventBus.getDefault().register(this)
checkNewProtocol()
@@ -61,36 +97,57 @@
override fun setObservable() {
super.setObservable()
- viewModel.selectIndex.observe(this) { showFragment(it) }
- MyApp.permissions.observe(this){
+ viewModel.selectIndex.observe(this) {
+ showFragment(it)
+ updateNavViewVisibility(it)
+ }
+ MyApp.permissions.observe(this) {
viewModel.workPermissions.value = MyApp.findPermissionByName("工作台")?.visible == "0"
viewModel.taskPermissions.value = MyApp.findPermissionByName("任务中心")?.visible == "0"
if (viewModel.selectIndex.value == null) {
if (viewModel.workPermissions.value == true) {
- viewModel.selectIndex.value = 0
+ viewModel.changeSelectFragmentIndex(0)
} else if (viewModel.taskPermissions.value == true) {
- viewModel.selectIndex.value = 1
+ viewModel.changeSelectFragmentIndex(1)
} else {
- viewModel.selectIndex.value = 2
+ viewModel.changeSelectFragmentIndex(2)
}
} else {
- var currentIndex = viewModel.selectIndex.value
+ var currentIndex = viewModel.selectIndex.value ?: 0
if (currentIndex == 0 && viewModel.workPermissions.value == false) {
currentIndex = 1
}
if (currentIndex == 1 && viewModel.taskPermissions.value == false) {
currentIndex = 2
}
- if (viewModel.selectIndex.value != currentIndex) {
- viewModel.selectIndex.value = currentIndex
- }
+ viewModel.changeSelectFragmentIndex(currentIndex)
+ // 权限可能在 index 不变的情况下变化,需主动重算底部主导航可见性,
+ // 否则 selectIndex 不发射时 navView 可见性无法被纠正(双 Tab bar 叠加根因之一)
+ updateNavViewVisibility(currentIndex)
}
}
}
+ /**
+ * 重新计算 Activity 底部主导航(工作台/任务中心/我的)的可见性。
+ * 进入任务中心(index==1)时隐藏主导航,仅展示 TaskFragment 自带的底部栏。
+ * 抽成独立方法,使其在 index 变化与权限变化时都能被触发。
+ */
+ private fun updateNavViewVisibility(index: Int) {
+ binding.navView.visibility = if (viewModel.taskPermissions.value == true) {
+ if (viewModel.workPermissions.value == true) {
+ if (index == 1) View.GONE else View.VISIBLE
+ } else {
+ if (index == 0) View.GONE else View.VISIBLE
+ }
+ } else {
+ View.VISIBLE
+ }
+ }
+
// 检测是否有新协议
- private fun checkNewProtocol(){
+ private fun checkNewProtocol() {
val needRead = MMKVManager.getInstance().getBoolean(KeyPreferences.NEED_READ, false)
if (needRead) {
showProtocolDialog(this, true)
@@ -98,12 +155,12 @@
}
// 检测是否有强制升级版本
- private fun checkNewForcedVersion(){
+ private fun checkNewForcedVersion() {
viewModel.getVersion {
if (it.forceUpdateFlag == 1) {
UpdateManager.instance!!
.setContext(this@MainActivity)
- .apkUrl(it.androidFile ?: "")
+ .apkUrl(it.getDownloadUrl() ?: "")
.updateContent(it.updateDescription ?: "")
.updateVersionCode(it.versionCode ?: 1)
.updateVersionName(it.version ?: "1.0")
@@ -118,7 +175,11 @@
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val permissionList: MutableList<String> = ArrayList()
for (permission in listOf("android.permission.POST_NOTIFICATIONS")) {
- if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
+ if (ContextCompat.checkSelfPermission(
+ this,
+ permission
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
permissionList.add(permission)
}
}
@@ -126,10 +187,16 @@
if (!result) { // 无权限 申请
val pl = arrayOf("android.permission.POST_NOTIFICATIONS")
XXPermissions.with(this).permission(pl).request(object : OnPermissionCallback {
- override fun onGranted(permissions: MutableList<String>, allGranted: Boolean) { // 权限同意
+ override fun onGranted(
+ permissions: MutableList<String>,
+ allGranted: Boolean
+ ) { // 权限同意
}
- override fun onDenied(permissions: MutableList<String>, doNotAskAgain: Boolean) {
+ override fun onDenied(
+ permissions: MutableList<String>,
+ doNotAskAgain: Boolean
+ ) {
super.onDenied(permissions, doNotAskAgain)
ToastUtilCommon.showWarn("您未授权通知权限,可能会导致无法及时收到消息")
}
@@ -152,6 +219,10 @@
private fun showFragment(from: Fragment?, to: Fragment, tag: String) {
val transaction = supportFragmentManager.beginTransaction()
if (from == null) {
+ // 进程重建后 mCurrentFragment 丢失,FragmentManager 会自动恢复之前 add 过的
+ // Fragment 并保留其显隐状态。此处主动隐藏除目标外的其他 Fragment,
+ // 避免任务中心与工作台等 Fragment 叠加导致出现两套底部 Tab bar。
+ hideOtherFragments(transaction, tag)
if (to.isAdded) {
transaction.show(to)
} else {
@@ -168,6 +239,17 @@
mCurrentFragment = to
}
+ /**
+ * 隐藏除 currentTag 之外、已被 FragmentManager 恢复/添加的导航 Fragment,
+ * 保证同一时刻只有一个 Fragment 可见。
+ */
+ private fun hideOtherFragments(transaction: FragmentTransaction, currentTag: String) {
+ for (name in fragmentNames) {
+ if (name == currentTag) continue
+ supportFragmentManager.findFragmentByTag(name)?.let { transaction.hide(it) }
+ }
+ }
+
override fun onResume() {
super.onResume()
viewModel.getAppPermission()
@@ -181,7 +263,22 @@
@Suppress("unused")
@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(event: SwitchTabMain) {
- viewModel.selectIndex.value = event.index
+ viewModel.changeSelectFragmentIndex(event.index)
}
+ override fun onBackPressedHandel() {
+ if (viewModel.selectIndex.value == 1) {
+ viewModel.changeSelectFragmentIndex(viewModel.lastSelectIndex)
+ return
+ }
+ super.onBackPressedHandel()
+ }
+
+ override fun location(pLocation: AMapLocation?) {
+
+ }
+
+ companion object {
+ private const val KEY_SELECT_INDEX = "key_select_index"
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/MainVM.kt b/app/src/main/java/com/xw/yunwei/ui/MainVM.kt
index d530294..035258b 100644
--- a/app/src/main/java/com/xw/yunwei/ui/MainVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/MainVM.kt
@@ -7,25 +7,38 @@
import com.xw.yunwei.MyApp
import com.xw.yunwei.R
import com.xw.yunwei.model.AppVersionModel
+import com.xw.yunwei.model.SwitchTabTask
import com.xw.yunwei.net.UserRepository
+import org.greenrobot.eventbus.EventBus
import org.koin.core.component.inject
-import kotlin.getValue
class MainVM(application: Application) : BaseViewModel(application) {
val userRepository: UserRepository by inject()
- val selectIndex = MutableLiveData<Int>()
+ val selectIndex = MutableLiveData<Int>(0)
+ //上一次显示fragment下标
+ var lastSelectIndex = 0
val taskPermissions = MutableLiveData(false) // 任务中心权限
val workPermissions = MutableLiveData(false) // 工作台权限
-
val onClick = View.OnClickListener {
when (it.id) {
- R.id.navWork -> selectIndex.value = 0
- R.id.navTask -> selectIndex.value = 1
- R.id.navMine -> selectIndex.value = 2
+ R.id.navWork -> changeSelectFragmentIndex(0)
+ R.id.navTask -> {
+ changeSelectFragmentIndex(1)
+ EventBus.getDefault().post(SwitchTabTask(1))
+ }
+ R.id.navMine -> changeSelectFragmentIndex(2)
+ }
+ }
+
+ //改变选择fragment下标
+ fun changeSelectFragmentIndex(index: Int) {
+ if (selectIndex.value != index) {
+ lastSelectIndex = selectIndex.value ?: 0
+ selectIndex.postValue(index)
}
}
diff --git a/app/src/main/java/com/xw/yunwei/ui/common/WebActivity.kt b/app/src/main/java/com/xw/yunwei/ui/common/WebActivity.kt
new file mode 100644
index 0000000..c6fe965
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/common/WebActivity.kt
@@ -0,0 +1,72 @@
+package com.xw.yunwei.ui.common
+
+import android.annotation.SuppressLint
+import android.os.Bundle
+import android.webkit.WebChromeClient
+import android.webkit.WebSettings
+import android.webkit.WebView
+import androidx.core.os.bundleOf
+import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
+import com.xw.yunwei.constants.Key
+import com.xw.yunwei.databinding.ActivityWebBinding
+
+//通用网页
+class WebActivity : BaseBusinessActivity<ActivityWebBinding, WebVM>() {
+ val url by lazy {
+ intent.getStringExtra(Key.DATA)
+ }
+ val title by lazy {
+ intent.getStringExtra(Key.TITLE)
+ }
+
+ override fun getBindingVariable() = BR.viewModel
+
+ companion object {
+ //获取跳转该页面参数
+ fun getParams(url: String, title: String? = null): Bundle {
+ return bundleOf(Key.DATA to url, Key.TITLE to title)
+ }
+ }
+
+ override fun setListener() {
+ super.setListener()
+ binding.back.setOnClickListener { onBackPressedHandel() }
+ }
+
+ override fun init() {
+ super.init()
+ initWeb(binding.web)
+ url?.also { binding.web.loadUrl(it) }
+ }
+
+ @SuppressLint("SetJavaScriptEnabled")
+ private fun initWeb(webView: WebView) {
+ //声明WebSettings子类
+ val webSettings = webView.settings
+ webSettings.domStorageEnabled = true //设置适应Html5
+
+ //如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
+ webSettings.javaScriptEnabled = true //允许js调用
+ webSettings.allowContentAccess = true //是否允许在WebView中访问内容URL(Content Url),默认允许
+
+ //缩放操作
+ webSettings.setSupportZoom(true) //支持缩放,默认为true。是下面那个的前提。
+ webSettings.builtInZoomControls = true //设置内置的缩放控件。若为false,则该WebView不可缩放
+ webSettings.displayZoomControls = false //隐藏原生的缩放控件
+
+ //其他细节操作
+ webSettings.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK //关闭webview中缓存
+ webSettings.javaScriptCanOpenWindowsAutomatically = true //支持通过JS打开新窗口
+ webSettings.loadsImagesAutomatically = true //支持自动加载图片
+ webSettings.defaultTextEncodingName = "utf-8" //设置编码格式
+
+ webView.webChromeClient = object : WebChromeClient() {
+ override fun onReceivedTitle(view: WebView?, title: String?) {
+ super.onReceivedTitle(view, title)
+ binding.title.text =
+ title?.ifEmpty { this@WebActivity.title } ?: this@WebActivity.title
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/common/WebVM.kt b/app/src/main/java/com/xw/yunwei/ui/common/WebVM.kt
new file mode 100644
index 0000000..800247e
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/common/WebVM.kt
@@ -0,0 +1,7 @@
+package com.xw.yunwei.ui.common
+
+import android.app.Application
+import com.xw.common.base.BaseViewModel
+
+class WebVM(application: Application): BaseViewModel(application) {
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/dialog/ApplyForReassignReasonDialog.kt b/app/src/main/java/com/xw/yunwei/ui/dialog/ApplyForReassignReasonDialog.kt
new file mode 100644
index 0000000..cc662d4
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/dialog/ApplyForReassignReasonDialog.kt
@@ -0,0 +1,140 @@
+package com.xw.yunwei.ui.dialog
+
+import android.content.Context
+import android.util.TypedValue
+import android.view.Gravity
+import android.widget.EditText
+import android.widget.TextView
+import androidx.core.content.ContextCompat
+import androidx.core.widget.addTextChangedListener
+import com.afollestad.materialdialogs.MaterialDialog
+import com.afollestad.materialdialogs.customview.customView
+import com.google.android.flexbox.FlexboxLayout
+import com.scwang.smart.refresh.layout.util.SmartUtil
+import com.xw.common.utils.ToastUtilCommon
+import com.xw.yunwei.R
+import com.xw.yunwei.utils.DialogFactory
+
+//申请改派原因弹窗
+object ApplyForReassignReasonDialog {
+ fun show(
+ context: Context,
+ reasons: List<String>,
+ submitBlock: (position: Int, input: String, dialog: MaterialDialog) -> Unit
+ ) {
+ val dialog = DialogFactory.produce(context).apply {
+ customView(
+ R.layout.dialog_apply_for_reassign_reason,
+ noVerticalPadding = true,
+ dialogWrapContent = false
+ )
+ cornerRadius(4f)
+
+ val flexboxLayout = findViewById<FlexboxLayout>(R.id.fl_tags)
+ val etInput = findViewById<EditText>(R.id.et_input)
+ val tvOperation = findViewById<TextView>(R.id.tv_operation)
+ val set = mutableSetOf<String>()
+ fillTag(flexboxLayout, reasons, set) {
+ tvOperation.setTextColor(
+ ContextCompat.getColor(
+ context,
+ com.xw.common.R.color.blue_5
+ )
+ )
+ etInput.setBackgroundResource(if(set.first() == "其他"){
+ R.drawable.shape_red_5_line_gray_3_bg_4
+ }else{
+ R.drawable.shape_gray_4_line_gray_3_bg_4
+ })
+ }
+ etInput.addTextChangedListener {
+ if ((it?.length ?: 0) >= 200) {
+ ToastUtilCommon.showSuc("最多输入200字")
+ }
+ }
+ tvOperation.setOnClickListener {
+ if (set.isEmpty()) {
+ ToastUtilCommon.showSuc("请选择原因")
+ return@setOnClickListener
+ }
+ if (set.first() == "其他" && etInput.text.isNullOrEmpty()) {
+ ToastUtilCommon.showSuc("请输入改派原因")
+ return@setOnClickListener
+ }
+ submitBlock.invoke(
+ reasons.indexOf(set.first()),
+ etInput.text?.toString() ?: "",
+ this
+ )
+ dismiss()
+ }
+ }
+ dialog.show()
+ dialog.window?.setGravity(Gravity.CENTER)
+ dialog.window?.setWindowAnimations(com.xw.common.R.style.AnimLeft)
+ }
+
+ //填充标签
+ private fun fillTag(
+ flexboxLayout: FlexboxLayout,
+ reasons: List<String>,
+ set: MutableSet<String>,
+ refreshListener: () -> Unit,
+ ) {
+ flexboxLayout.removeAllViews()
+ reasons.map { it ->
+ getTagItemView(flexboxLayout.context, it, set.contains(it)) {
+ if (set.contains(it)) {
+ set.remove(it)
+ } else {
+ set.clear()
+ set.add(it)
+ }
+ refreshListener.invoke()
+ fillTag(flexboxLayout, reasons, set, refreshListener)
+ }
+ }.forEach {
+ flexboxLayout.addView(it)
+ }
+ }
+
+ //获取标签item控件
+ private fun getTagItemView(
+ context: Context,
+ tag: String,
+ isChecked: Boolean,
+ clickListener: (tag: String) -> Unit
+ ): TextView {
+ return TextView(context).apply {
+ layoutParams = FlexboxLayout.LayoutParams(
+ FlexboxLayout.LayoutParams.WRAP_CONTENT,
+ FlexboxLayout.LayoutParams.WRAP_CONTENT
+ ).apply {
+ topMargin = SmartUtil.dp2px(4f)
+ bottomMargin = SmartUtil.dp2px(4f)
+ leftMargin = SmartUtil.dp2px(4f)
+ rightMargin = SmartUtil.dp2px(4f)
+ }
+
+ setPadding(
+ SmartUtil.dp2px(8f),
+ SmartUtil.dp2px(6f),
+ SmartUtil.dp2px(8f),
+ SmartUtil.dp2px(6f)
+ )
+ text = tag
+ setTextSize(TypedValue.COMPLEX_UNIT_SP, 12f)
+ setTextColor(
+ ContextCompat.getColor(
+ context,
+ if (isChecked) com.xw.common.R.color.blue_5 else com.xw.common.R.color.gray_9
+ )
+ )
+ gravity = Gravity.CENTER
+ setBackgroundResource(if (isChecked) R.drawable.shape_blue_1_bg_4 else R.drawable.shape_gray_3_bg_4)
+ setOnClickListener {
+ clickListener.invoke(tag)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/dialog/ConfirmAcceptCarPointDialog.kt b/app/src/main/java/com/xw/yunwei/ui/dialog/ConfirmAcceptCarPointDialog.kt
new file mode 100644
index 0000000..e06358c
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/dialog/ConfirmAcceptCarPointDialog.kt
@@ -0,0 +1,61 @@
+package com.xw.yunwei.ui.dialog
+
+import android.content.Context
+import android.view.Gravity
+import android.widget.TextView
+import com.afollestad.materialdialogs.MaterialDialog
+import com.afollestad.materialdialogs.customview.customView
+import com.xw.yunwei.R
+import com.xw.yunwei.model.AcceptCarPointInfo
+import com.xw.yunwei.utils.DialogFactory
+
+//收车点确认弹窗
+object ConfirmAcceptCarPointDialog {
+ fun show(
+ context: Context,
+ index: Int = 0,
+ points: List<AcceptCarPointInfo>,
+ cancelBlock: () -> Unit,
+ confirmBlock: (AcceptCarPointInfo, MaterialDialog) -> Unit
+ ) {
+ val dialog = DialogFactory.produce(context).apply {
+ customView(
+ R.layout.dialog_confirm_accept_car_point,
+ noVerticalPadding = true,
+ dialogWrapContent = false
+ )
+ cornerRadius(8f)
+
+ val tvTitle = findViewById<TextView>(R.id.tv_title)
+ val tvDetail = findViewById<TextView>(R.id.tv_detail)
+ val tvChange = findViewById<TextView>(R.id.tv_change)
+ val tvConfirm = findViewById<TextView>(R.id.tv_confirm)
+
+ tvTitle.text = points[index].pointName
+ tvDetail.text = points[index].pointAddress
+ var needChange = false
+ tvChange.setOnClickListener {
+ needChange = true
+ dismiss()
+ SelectConfirmAcceptCarPointDialog.show(
+ context = context,
+ index = index,
+ points = points,
+ cancelBlock = cancelBlock,
+ confirmBlock = confirmBlock
+ )
+ }
+ tvConfirm.setOnClickListener {
+ confirmBlock.invoke(points[index], this)
+ }
+ setOnDismissListener {
+ if (!needChange) {
+ cancelBlock.invoke()
+ }
+ }
+ }
+ dialog.show()
+ dialog.window?.setGravity(Gravity.CENTER)
+ dialog.window?.setWindowAnimations(com.xw.common.R.style.AnimLeft)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/dialog/CruiseCheckInSuccessDialog.kt b/app/src/main/java/com/xw/yunwei/ui/dialog/CruiseCheckInSuccessDialog.kt
new file mode 100644
index 0000000..cba74f7
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/dialog/CruiseCheckInSuccessDialog.kt
@@ -0,0 +1,87 @@
+package com.xw.yunwei.ui.dialog
+
+import android.content.Context
+import android.view.Gravity
+import android.view.View
+import android.widget.TextView
+import androidx.recyclerview.widget.GridLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.afollestad.materialdialogs.MaterialDialog
+import com.afollestad.materialdialogs.customview.customView
+import com.xw.common.utils.BindUtils.getResColor
+import com.xw.yunwei.R
+import com.xw.yunwei.model.CruiseCheckInOperationResult
+import com.xw.yunwei.ui.work.site.adapter.PictureOperationAdapter
+import com.xw.yunwei.utils.DialogFactory
+
+//巡游打卡成功弹窗
+object CruiseCheckInSuccessDialog {
+ fun show(
+ context: Context,
+ result: CruiseCheckInOperationResult,
+ needOperation: Boolean = true,
+ operationLabel: String? = "前往下一个点位",
+ ): MaterialDialog {
+ val dialog = DialogFactory.produce(context).apply {
+ customView(
+ R.layout.dialog_cruise_check_in_success,
+ noVerticalPadding = true,
+ dialogWrapContent = false
+ )
+ cornerRadius(4f)
+ val tvTime = findViewById<TextView>(R.id.tv_time)
+ val tvCheckResult = findViewById<TextView>(R.id.tv_check_result)
+ val tvWorkStatus = findViewById<TextView>(R.id.tv_work_status)
+ val tvDesc = findViewById<TextView>(R.id.tv_desc)
+ val rvList = findViewById<RecyclerView>(R.id.rv_list)
+ val tvOperation = findViewById<TextView>(R.id.tv_operation)
+ tvTime.text = "打卡时间:${result.getShowCheckInTime()}"
+ tvCheckResult.text = result.getShowCheckInStatus()
+ tvCheckResult.setTextColor(
+ getResColor(
+ when (result.checkInResult) {
+ "1" -> com.xw.common.R.color.green_5
+ "2" -> com.xw.common.R.color.red_5
+ else -> com.xw.common.R.color.gray_9
+ }
+ )
+ )
+ tvCheckResult.setBackgroundResource(
+ when (result.checkInResult) {
+ "1" -> R.drawable.shape_green_1_bg_2
+ "2" -> R.drawable.shape_fdedeb_bg_2
+ else -> 0
+ }
+ )
+ tvWorkStatus.text = result.getShowWorkStatus()
+ tvWorkStatus.setTextColor(
+ getResColor(
+ when (result.fieldSituation) {
+ "1" -> com.xw.common.R.color.green_5
+ "2" -> com.xw.common.R.color.orange_5
+ else -> com.xw.common.R.color.gray_9
+ }
+ )
+ )
+ tvWorkStatus.setBackgroundResource(
+ when (result.fieldSituation) {
+ "1" -> R.drawable.shape_green_1_bg_2
+ "2" -> R.drawable.shape_orange_1_bg_2
+ else -> 0
+ }
+ )
+ tvDesc.text = result.sceneDescription
+ rvList.adapter = PictureOperationAdapter(couldDelete = false).apply {
+ setNewInstance(result.getUploadInfoList()?.map { it.url!! }?.toMutableList())
+ }
+ rvList.layoutManager = GridLayoutManager(context, 3)
+ tvOperation.setOnClickListener { dismiss() }
+ tvOperation.visibility = if (needOperation) View.VISIBLE else View.GONE
+ tvOperation.text = operationLabel
+ }
+ dialog.show()
+ dialog.window?.setGravity(Gravity.CENTER)
+ dialog.window?.setWindowAnimations(com.xw.common.R.style.AnimLeft)
+ return dialog
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/dialog/NewTaskDialog.kt b/app/src/main/java/com/xw/yunwei/ui/dialog/NewTaskDialog.kt
new file mode 100644
index 0000000..14a0d5b
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/dialog/NewTaskDialog.kt
@@ -0,0 +1,217 @@
+package com.xw.yunwei.ui.dialog
+
+import android.content.Context
+import android.os.Handler
+import android.os.Looper
+import android.view.Gravity
+import android.view.View
+import android.widget.LinearLayout
+import androidx.appcompat.widget.AppCompatImageView
+import androidx.appcompat.widget.AppCompatTextView
+import androidx.core.view.isVisible
+import com.afollestad.materialdialogs.MaterialDialog
+import com.afollestad.materialdialogs.customview.customView
+import com.xw.common.utils.BindUtils.getResColor
+import com.xw.yunwei.R
+import com.xw.yunwei.model.TaskModel
+import com.xw.yunwei.utils.DialogFactory
+import java.time.Duration
+import java.time.LocalDateTime
+import java.time.format.DateTimeFormatter
+import java.util.concurrent.TimeUnit
+import kotlin.math.max
+
+//新任务弹窗
+object NewTaskDialog {
+ // 倒计时Handler
+ private val countdownHandler = Handler(Looper.getMainLooper())
+
+ //显示
+ fun show(
+ context: Context, item: TaskModel,
+ applyForReassignBlock: (dialog: MaterialDialog) -> Unit,
+ receive: (dialog: MaterialDialog) -> Unit
+ ) {
+ var runnable: Runnable? = null
+ val dialog = DialogFactory.produce(context).apply {
+ customView(
+ R.layout.dialog_new_task,
+ noVerticalPadding = true,
+ dialogWrapContent = false
+ )
+
+ cancelable(false)
+ cancelOnTouchOutside(false)
+ cornerRadius(4f)
+ val levelId = when (item.taskUrgencyLevel) {
+ 0 -> R.mipmap.ic_task_item_left_one
+ 1 -> R.mipmap.ic_task_item_left_two
+ 2 -> R.mipmap.ic_task_item_left_three
+ 3 -> R.mipmap.ic_task_item_left_four
+ else -> null
+ }
+ val level = findViewById<AppCompatImageView>(R.id.level)
+ val countdownLayout = findViewById<LinearLayout>(R.id.countdownLayout)
+ val countdownTips = findViewById<AppCompatTextView>(R.id.countdownTips)
+ val hour = findViewById<AppCompatTextView>(R.id.hour)
+ val colon1 = findViewById<AppCompatImageView>(R.id.colon1)
+ val minutes = findViewById<AppCompatTextView>(R.id.minutes)
+ val colon2 = findViewById<AppCompatImageView>(R.id.colon2)
+ val second = findViewById<AppCompatTextView>(R.id.second)
+ val type = findViewById<AppCompatTextView>(R.id.type)
+ val plateNumber = findViewById<AppCompatTextView>(R.id.plateNumber)
+ val status = findViewById<AppCompatTextView>(R.id.status)
+ val address = findViewById<AppCompatTextView>(R.id.address)
+ val tvApplyForReassignment =
+ findViewById<AppCompatTextView>(R.id.tv_apply_for_reassignment)
+ val tvControl = findViewById<AppCompatTextView>(R.id.tvControl)
+ levelId?.let { level.setImageResource(levelId) }
+
+ countdownLayout.visibility = View.VISIBLE
+ val list = calculateTimeDifference(item.endTime)
+ updateTime(
+ hour,
+ colon1,
+ minutes,
+ colon2,
+ second,
+ countdownTips,
+ countdownLayout,
+ list
+ )
+ if (list.all { it == 0L }) { // 全0
+ countdownTips.text = "已超时"
+ } else { // 注册到倒计时列表
+ countdownTips.text = "倒计时结束前,务必到达现场"
+ runnable = object : Runnable {
+ override fun run() {
+ val list = calculateTimeDifference(item.endTime)
+ updateTime(
+ hour,
+ colon1,
+ minutes,
+ colon2,
+ second,
+ countdownTips,
+ countdownLayout,
+ list
+ )
+ if (list.count { it == 0L } == list.size) {
+ countdownHandler.removeCallbacks(this)
+ } else {
+ countdownHandler.postDelayed(this, 1000)
+ }
+ }
+ }
+ countdownHandler.postDelayed(runnable, 1000)
+ }
+
+ if (item.isAccidentTask()) {
+ type.text = "事故"
+ } else if (item.isRoutineTask()) {
+ type.text = item.getTaskType()
+ }
+ plateNumber.text = item.plateNumber
+
+ val setStatus: (Int, Int) -> Unit = { text, bg ->
+ status.setTextColor(text)
+ status.setBackgroundResource(bg)
+ }
+ setStatus(
+ getResColor(com.xw.common.R.color.gray_8),
+ com.xw.common.R.color.gray_3
+ )
+ // 0 = 待到达 1 = 待处理 2 = 已完成 3 = 已取消 4 = 已取消
+ when (item.status) {
+ 0 -> status.text = "待到达"
+ 1 -> status.text = "待处理"
+ 2 -> status.text = "已处理"
+ 3 -> status.text = "已取消"
+ 4 -> status.text = "改派中"
+ }
+ address.text = item.vehicleLocation
+
+ tvApplyForReassignment.setOnClickListener {
+ applyForReassignBlock.invoke(this)
+ }
+ tvControl.setOnClickListener {
+ receive.invoke(this)
+ }
+ }
+ dialog.setOnDismissListener {
+ runnable?.also {
+ countdownHandler.removeCallbacks(it)
+ }
+ }
+ dialog.show()
+ dialog.window?.setGravity(Gravity.CENTER)
+ dialog.window?.setWindowAnimations(com.xw.common.R.style.AnimLeft)
+ }
+
+ //更新时间
+ private fun updateTime(
+ hour: AppCompatTextView,
+ colon1: AppCompatImageView,
+ minutes: AppCompatTextView,
+ colon2: AppCompatImageView,
+ second: AppCompatTextView,
+ countdownTips: AppCompatTextView,
+ countdownLayout: LinearLayout,
+ list: List<Long>
+ ) {
+
+ hour.text = if (list[0] < 10) "0${list[0]}" else "${list[0]}"
+ minutes.text = if (list[1] < 10) "0${list[1]}" else "${list[1]}"
+ second.text = if (list[2] < 10) "0${list[2]}" else "${list[2]}"
+
+ val showRed = list[0] == 0L && list[1] == 0L
+
+ val countdownId =
+ if (showRed) R.mipmap.img_task_item_top_bg_red else R.mipmap.img_task_item_top_bg_blue
+ countdownLayout.setBackgroundResource(countdownId)
+
+ val colorId =
+ if (showRed) getResColor(com.xw.common.R.color.red_6) else getResColor(com.xw.common.R.color.blue_5)
+ countdownTips.setTextColor(colorId)
+
+ val bgId = if (showRed) R.drawable.shape_fa3e3e_bg_4 else R.drawable.shape_blue_5_bg_4
+ hour.setBackgroundResource(bgId)
+ minutes.setBackgroundResource(bgId)
+ second.setBackgroundResource(bgId)
+
+ val imgId = if (showRed) R.mipmap.ic_task_item_colon_r else R.mipmap.ic_task_item_colon_b
+ colon1.setImageResource(imgId)
+ colon2.setImageResource(imgId)
+
+ val hideTime = list[0] == 0L && list[1] == 0L && list[2] == 0L
+
+ hour.isVisible = !hideTime
+ minutes.isVisible = !hideTime
+ second.isVisible = !hideTime
+ colon1.isVisible = !hideTime
+ colon2.isVisible = !hideTime
+ }
+
+ /**
+ * 计算目标时间与当前时间的差值,返回时分秒格式
+ */
+ private fun calculateTimeDifference(targetTimeStr: String?): List<Long> {
+ targetTimeStr?.let {
+ // 定义输入格式
+ val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+ // 解析目标时间
+ val targetTime = LocalDateTime.parse(targetTimeStr, formatter)
+ // 获取当前时间
+ val now = LocalDateTime.now()
+ // 计算时间差(毫秒)
+ val duration = Duration.between(now, targetTime)
+ val totalSeconds = max(duration.seconds, 0L)
+ // 转换为时分秒
+ val hours = TimeUnit.SECONDS.toHours(totalSeconds)
+ val minutes = TimeUnit.SECONDS.toMinutes(totalSeconds) % 60
+ val seconds = totalSeconds % 60
+ return listOf(hours, minutes, seconds)
+ }
+ return listOf(0L, 0L, 0L)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/dialog/SelectConfirmAcceptCarPointDialog.kt b/app/src/main/java/com/xw/yunwei/ui/dialog/SelectConfirmAcceptCarPointDialog.kt
new file mode 100644
index 0000000..45ab41d
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/dialog/SelectConfirmAcceptCarPointDialog.kt
@@ -0,0 +1,71 @@
+package com.xw.yunwei.ui.dialog
+
+import android.content.Context
+import android.view.Gravity
+import android.view.ViewGroup
+import android.widget.ImageView
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.afollestad.materialdialogs.MaterialDialog
+import com.afollestad.materialdialogs.customview.customView
+import com.google.android.material.button.MaterialButton
+import com.xw.yunwei.R
+import com.xw.yunwei.extension.dpToPx
+import com.xw.yunwei.model.AcceptCarPointInfo
+import com.xw.yunwei.ui.work.car.detail.adapter.AcceptCarPointAdapter
+import com.xw.yunwei.utils.DialogFactory
+import kotlin.math.min
+
+//选择确认收车点弹窗
+object SelectConfirmAcceptCarPointDialog {
+ var hadOperation = false
+ fun show(
+ context: Context,
+ index: Int = 0,
+ points: List<AcceptCarPointInfo>,
+ maxShowLength: Int = 3,
+ cancelBlock: () -> Unit,
+ confirmBlock: (AcceptCarPointInfo, MaterialDialog) -> Unit
+ ) {
+ val dialog = DialogFactory.produce(context).apply {
+ customView(
+ R.layout.dialog_select_confirm_accept_car_point,
+ noVerticalPadding = true,
+ dialogWrapContent = false
+ )
+
+ val ivFlexing = findViewById<ImageView>(R.id.iv_flexing)
+ val rvList = findViewById<RecyclerView>(R.id.rv_list)
+ val btnOperation = findViewById<MaterialButton>(R.id.btn_operation)
+
+ ivFlexing.setOnClickListener {
+ dismiss()
+ cancelBlock.invoke()
+ }
+ val recyclerViewHeight = min(maxShowLength, points.size) * 109.dpToPx(context)
+ rvList.layoutParams = rvList.layoutParams.apply {
+ height = recyclerViewHeight
+ }
+ rvList.layoutManager = LinearLayoutManager(context)
+ val adapter = AcceptCarPointAdapter(index)
+ rvList.adapter = adapter
+ adapter.setList(points)
+ btnOperation.setOnClickListener {
+ hadOperation = true
+ confirmBlock.invoke(points[adapter.selectIndex], this)
+ }
+ setOnDismissListener {
+ if (!hadOperation) {
+ cancelBlock.invoke()
+ }
+ }
+ }
+ dialog.show()
+ dialog.window?.setLayout(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ dialog.window?.setGravity(Gravity.BOTTOM)
+ dialog.window?.setWindowAnimations(com.xw.common.R.style.AnimUp)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/task/TaskFragment.kt b/app/src/main/java/com/xw/yunwei/ui/task/TaskFragment.kt
index 6764a2a..1ac8027 100644
--- a/app/src/main/java/com/xw/yunwei/ui/task/TaskFragment.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/task/TaskFragment.kt
@@ -5,9 +5,9 @@
import android.view.Gravity
import android.view.KeyEvent
import android.view.LayoutInflater
+import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
-import androidx.core.os.bundleOf
import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
@@ -25,36 +25,51 @@
import com.xw.common.TimeDialog.Companion.getTime
import com.xw.common.base.BaseFragment
import com.xw.common.utils.GpsHelper
-import com.xw.common.utils.LogUtils
import com.xw.common.utils.ToastUtilCommon
import com.xw.common.utils.ToolUtil
import com.xw.yunwei.BR
import com.xw.yunwei.databinding.DialogDataFilterBinding
import com.xw.yunwei.databinding.FragmentTaskBinding
import com.xw.yunwei.databinding.ItemArrow2TextBinding
+import com.xw.yunwei.extension.showCount
import com.xw.yunwei.model.FilterData
import com.xw.yunwei.model.LocationData
-import com.xw.yunwei.model.SwitchTabMain
import com.xw.yunwei.model.SwitchTabTask
import com.xw.yunwei.ui.task.list.TaskListFragment
import com.xw.yunwei.ui.work.notice.NoticeActivity
+import com.xw.yunwei.utils.DialogFactory
import kotlinx.coroutines.launch
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
/**
+ * 任务中心 Fragment
*
- * 任务中心
+ * 负责展示任务列表的 ViewPager 页面(全部/待到达/待处理/已处理),
+ * 集成筛选弹窗(时间、优先级、类型、排序)、车牌号搜索、定位下发等功能。
+ *
+ * @author zmc
*/
class TaskFragment : BaseFragment<FragmentTaskBinding, TaskVM>(), GpsHelper.OnMapLocation {
override fun getBindingVariable(): Int = BR.viewModel
- private val tabTitles = arrayOf("全部", "待到达", "待处理", "已处理")
+ /** 标签页标题数组 */
+ private val tabTitles = arrayOf("全部", "待到达", "待处理", "已处理", "改派中")
+
+ /** 筛选弹窗实例 */
private var filterDialog: MaterialDialog? = null
+
+ /** 日期选择弹窗 */
val dialogTime: TimeDialog by lazy { TimeDialog(requireActivity()) }
+ /** GPS 定位辅助类 */
var gpsHelper: GpsHelper? = null
+
+ /**
+ * 当前筛选条件数据
+ * 根据 ViewModel 中用户选中的筛选项动态组装
+ */
val filterData: FilterData
get() {
// 构建筛选数据
@@ -70,16 +85,24 @@
)
}
+ /**
+ * 当前定位数据
+ * 用于下发给子 Fragment
+ */
val locationData: LocationData
get() {
return LocationData(
- lat = viewModel.location?.latitude,
- lng = viewModel.location?.longitude
+ lat = viewModel.location?.latitude, lng = viewModel.location?.longitude
)
}
+ val adapter by lazy {
+ PagerAdapter(this)
+ }
+ private var tabLayoutMediator: TabLayoutMediator? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ // 初始化一次性定位,用于后续筛选或下发位置
gpsHelper = GpsHelper(
requireActivity(),
this,
@@ -90,28 +113,55 @@
lifecycle.addObserver(gpsHelper!!)
}
+ /**
+ * 初始化页面基础组件
+ * 注册 EventBus,设置 ViewPager 与 TabLayout 联动
+ */
override fun init() {
super.init()
EventBus.getDefault().register(this)
- binding.viewPager.adapter = PagerAdapter(this)
- TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
- tab.text = tabTitles[position]
- }.attach()
}
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ binding.viewPager.adapter = adapter
+ binding.viewPager.offscreenPageLimit = 5 // 默认值,可根据需要调整
+ tabLayoutMediator =
+ TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
+ tab.text = tabTitles[position]
+ }.apply {
+ attach()
+ }
+ view.post {
+ binding.viewPager.currentItem = 1
+ }
+ refreshFilterStatus()
+ }
+
+ //刷新筛选状态
+ private fun refreshFilterStatus() {
+ binding.iconFilter.setImageResource(if (viewModel.hadFilter()) com.xw.yunwei.R.mipmap.ic_filter_task2 else com.xw.yunwei.R.mipmap.ic_filter_task)
+ }
+
+ /**
+ * 设置各类点击及输入监听器
+ */
override fun setListener() {
super.setListener()
+ // 点击筛选按钮弹出筛选弹窗
binding.llFilter.setOnClickListener {
showFilterDialog()
}
+ // 车牌号输入框监听回车键,触发搜索并下发筛选条件
binding.searchEt.setOnKeyListener { _, keyCode, event ->
if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_UP) {
if (viewModel.plateNumber.value.isNullOrEmpty()) {
ToastUtilCommon.show("请输入车牌号")
} else {
EventBus.getDefault().post(filterData)
+ viewModel.statistic()
// requireActivity().supportFragmentManager.setFragmentResult(
// REQUEST_KEY_FILTER,
// bundleOf(KEY_FILTER_DATA to filterData)
@@ -121,6 +171,7 @@
}
false
}
+ // 监听软键盘收起,清除输入框焦点
binding.root.viewTreeObserver.addOnGlobalLayoutListener {
val rect = Rect()
binding.root.getWindowVisibleDisplayFrame(rect)
@@ -132,239 +183,314 @@
}
}
+ // 点击通知入口跳转通知页面
binding.notice.setOnClickListener { startActivity(NoticeActivity::class.java) }
}
+ /**
+ * 设置 LiveData 等可观察数据监听
+ */
override fun setObservable() {
super.setObservable()
- TaskVM.needRefresh.observe(this) {
+ TaskVM.needRefresh.observe(viewLifecycleOwner) {
if (it) {
TaskVM.needRefresh.value = false
+ // 刷新未读消息数量并控制角标显示
viewModel.getUnreadCount {
binding.count.isVisible = it.isNotEmpty() && (it.toInt() > 0)
}
}
}
+ viewModel.taskStatistic.observe(viewLifecycleOwner) {
+ val totalCountShow = it.totalTableCount.showCount(99)
+ val waitArriveCountShow = it.waitArriveCount.showCount(99)
+ val waitHandleCountShow = it.waitHandleCount.showCount(99)
+ val reassignmentCount = it.reassignmentCount.showCount(99)
+ tabTitles[0] = "全部${if (totalCountShow.isEmpty()) "" else " $totalCountShow"}"
+ tabTitles[1] =
+ "待到达${if (waitArriveCountShow.isEmpty()) "" else " $waitArriveCountShow"}"
+ tabTitles[2] =
+ "待处理${if (waitHandleCountShow.isEmpty()) "" else " $waitHandleCountShow"}"
+ tabTitles[3] = "已处理"
+ tabTitles[4] = "改派中${if (reassignmentCount.isEmpty()) "" else " $reassignmentCount"}"
+ adapter.notifyDataSetChanged()
+ binding.tvAllCount.visibility =
+ if ((it.totalCount ?: 0) > 0) View.VISIBLE else View.GONE
+ binding.tvAllCount.text = it.totalCount.showCount(99)
+ binding.tvAccidentCount.visibility =
+ if ((it.accidentCount ?: 0) > 0) View.VISIBLE else View.GONE
+ binding.tvAccidentCount.text = it.accidentCount.showCount(99)
+ binding.tvNormalCount.visibility =
+ if ((it.routineCount ?: 0) > 0) View.VISIBLE else View.GONE
+ binding.tvNormalCount.text = it.routineCount.showCount(99)
+ }
+ viewModel.needRefreshList.observe(viewLifecycleOwner) {
+ if (it == true) {
+ EventBus.getDefault().post(filterData)
+ viewModel.statistic()
+ }
+ }
}
+ override fun onResume() {
+ super.onResume()
+ viewModel.statistic()
+ }
+
+ /**
+ * 显示任务筛选弹窗
+ *
+ * 弹窗包含:派发时间、优先级、任务类型、自定义时间范围、排序方式等选项。
+ * 首次创建时初始化各选项的默认选中状态及点击逻辑。
+ */
private fun showFilterDialog() {
- if (filterDialog == null) {
- filterDialog = MaterialDialog(requireActivity()).apply {
- customView(
- com.xw.yunwei.R.layout.dialog_data_filter,
- noVerticalPadding = true,
- horizontalPadding = false
+ filterDialog = DialogFactory.produce(requireActivity()).apply {
+ customView(
+ com.xw.yunwei.R.layout.dialog_data_filter,
+ noVerticalPadding = true,
+ horizontalPadding = false
+ )
+ cancelable(true)
+ cornerRadius(12f)
+
+ val bind: DialogDataFilterBinding? = DataBindingUtil.bind(getCustomView())
+
+ with(bind!!) {
+ // 移除默认的标题栏显示,改用自定义数据填充
+ bind.stllTaskTime.remove()
+ bind.stllTaskLevel.remove()
+ bind.stllTaskType.remove()
+
+ // 初始化派发时间筛选项
+ bind.stllTaskTime.setData(
+ viewModel.filterTaskTime,
+ requireActivity(),
+ arrayListOf(
+ viewModel.filterTaskTime.indexOf(viewModel.selectTaskTime).toString()
+ ),
+ requireActivity().resources.getColor(R.color.blue_5),
+ "shape_blue1_bg_4"
)
- cancelable(true)
- cornerRadius(12f)
+ bind.tvStartTime.text = viewModel.startTime
+ bind.tvEndTime.text = viewModel.endTime
+ // 初始化优先级筛选项
+ bind.stllTaskLevel.setData(
+ viewModel.filterTaskLevel,
+ requireActivity(),
+ arrayListOf(
+ viewModel.filterTaskLevel.indexOf(viewModel.selectTaskLevel).toString()
+ ),
+ requireActivity().resources.getColor(R.color.blue_5),
+ "shape_blue1_bg_4"
+ )
+ // 初始化任务类型筛选项
+ bind.stllTaskType.setData(
+ viewModel.filterTaskType,
+ requireActivity(),
+ arrayListOf(
+ viewModel.filterTaskType.indexOf(viewModel.selectTaskType).toString()
+ ),
+ requireActivity().resources.getColor(R.color.blue_5),
+ "shape_blue1_bg_4"
+ )
- val bind: DialogDataFilterBinding? = DataBindingUtil.bind(getCustomView())
-
- with(bind!!) {
- bind.stllTaskTime.remove()
- bind.stllTaskLevel.remove()
- bind.stllTaskType.remove()
-
- bind.stllTaskTime.setData(
- viewModel.filterTaskTime,
- requireActivity(),
- arrayListOf("2"),
- requireActivity().resources.getColor(R.color.blue_5),
- "shape_blue1_bg_4"
- )
- bind.stllTaskLevel.setData(
- viewModel.filterTaskLevel,
- requireActivity(),
- arrayListOf("0"),
- requireActivity().resources.getColor(R.color.blue_5),
- "shape_blue1_bg_4"
- )
- bind.stllTaskType.setData(
- viewModel.filterTaskType,
- requireActivity(),
- arrayListOf("0"),
- requireActivity().resources.getColor(R.color.blue_5),
- "shape_blue1_bg_4"
- )
-
- bind.stllTaskTime.setListener {
- for (index in bind.stllTaskTime.selectIndexList) { // 先取消选中状态
- bind.stllTaskTime.onTvClick(index)
- }
- val index = it.tag as Int // 当前点击的下标
+ // 派发时间点击监听:单选切换并清空自定义时间
+ bind.stllTaskTime.setListener {
+ for (index in bind.stllTaskTime.selectIndexList) { // 先取消选中状态
bind.stllTaskTime.onTvClick(index)
- viewModel.selectTaskTime = viewModel.filterTaskTime[index]
-
- viewModel.startTime = ""
- viewModel.endTime = ""
- bind.tvStartTime.text = viewModel.startTime
- bind.tvEndTime.text = viewModel.endTime
}
- bind.stllTaskLevel.setListener {
- for (index in bind.stllTaskLevel.selectIndexList) { // 先取消选中状态
- bind.stllTaskLevel.onTvClick(index)
- }
- val index = it.tag as Int // 当前点击的下标
+ val index = it.tag as Int // 当前点击的下标
+ bind.stllTaskTime.onTvClick(index)
+ viewModel.selectTaskTime = viewModel.filterTaskTime[index]
+
+ viewModel.startTime = ""
+ viewModel.endTime = ""
+ bind.tvStartTime.text = viewModel.startTime
+ bind.tvEndTime.text = viewModel.endTime
+ }
+ // 优先级点击监听:单选切换
+ bind.stllTaskLevel.setListener {
+ for (index in bind.stllTaskLevel.selectIndexList) { // 先取消选中状态
bind.stllTaskLevel.onTvClick(index)
- viewModel.selectTaskLevel = viewModel.filterTaskLevel[index]
}
- bind.stllTaskType.setListener {
- for (index in bind.stllTaskType.selectIndexList) { // 先取消选中状态
- bind.stllTaskType.onTvClick(index)
- }
- val index = it.tag as Int // 当前点击的下标
+ val index = it.tag as Int // 当前点击的下标
+ bind.stllTaskLevel.onTvClick(index)
+ viewModel.selectTaskLevel = viewModel.filterTaskLevel[index]
+ }
+ // 任务类型点击监听:单选切换
+ bind.stllTaskType.setListener {
+ for (index in bind.stllTaskType.selectIndexList) { // 先取消选中状态
bind.stllTaskType.onTvClick(index)
- viewModel.selectTaskType = viewModel.filterTaskType[index]
}
- val onCheck: (String) -> Unit = { name ->
- if (name == viewModel.selectTaskSort) {
- viewModel.taskSort = if (viewModel.taskSort == 1) 2 else 1
+ val index = it.tag as Int // 当前点击的下标
+ bind.stllTaskType.onTvClick(index)
+ viewModel.changeTaskType(index)
+ }
+ val refresh: () -> Unit = {
+ viewModel.sortViews.forEach {
+ if (it.name.text == viewModel.selectTaskSort) {
+ it.layout.isSelected = true
+ it.name.isSelected = true
+ it.arrowUp.isSelected = viewModel.taskSort == 2
+ it.arrowDown.isSelected = viewModel.taskSort == 1
} else {
- viewModel.selectTaskSort = name
- viewModel.taskSort = 1
- }
- viewModel.sortViews.forEach {
- if (it.name.text == viewModel.selectTaskSort) {
- it.layout.isSelected = true
- it.name.isSelected = true
- it.arrowUp.isSelected = viewModel.taskSort == 2
- it.arrowDown.isSelected = viewModel.taskSort == 1
- } else {
- it.layout.isSelected = false
- it.name.isSelected = false
- it.arrowUp.isSelected = false
- it.arrowDown.isSelected = false
- }
+ it.layout.isSelected = false
+ it.name.isSelected = false
+ it.arrowUp.isSelected = false
+ it.arrowDown.isSelected = false
}
}
- val defaultSelectFirst: () -> Unit = {
- viewModel.sortViews.forEachIndexed { index, itemBind ->
- itemBind.layout.isSelected = index == 0
- itemBind.name.isSelected = index == 0
- itemBind.arrowUp.isSelected = index == 0 && viewModel.taskSort == 2
- itemBind.arrowDown.isSelected = index == 0 && viewModel.taskSort == 1
- }
+ }
+
+ /**
+ * 排序选项点击回调
+ * @param name 排序字段名称
+ */
+ val onCheck: (String) -> Unit = { name ->
+ if (name == viewModel.selectTaskSort) {
+ // 同一字段再次点击,切换正序/倒序
+ viewModel.taskSort = if (viewModel.taskSort == 1) 2 else 1
+ } else {
+ // 切换排序字段,默认正序
+ viewModel.selectTaskSort = name
+ viewModel.taskSort = 1
}
+ // 更新所有排序项的选中状态及箭头方向
+ refresh()
+ }
- bind.tagLayout.removeAllViews()
- viewModel.sortViews.clear()
- viewModel.filterTaskSort.forEachIndexed { index, name ->
- val itemBind: ItemArrow2TextBinding = DataBindingUtil.inflate(
- LayoutInflater.from(activity),
- com.xw.yunwei.R.layout.item_arrow2_text,
- null,
- false
- )
- itemBind.name.text = name
- viewModel.sortViews.add(itemBind)
- itemBind.root.setOnClickListener { onCheck(name) }
- bind.tagLayout.addView(itemBind.root)
+ // 动态构建排序选项视图
+ bind.tagLayout.removeAllViews()
+ viewModel.sortViews.clear()
+ viewModel.filterTaskSort.forEachIndexed { index, name ->
+ val itemBind: ItemArrow2TextBinding = DataBindingUtil.inflate(
+ LayoutInflater.from(activity),
+ com.xw.yunwei.R.layout.item_arrow2_text,
+ null,
+ false
+ )
+ itemBind.name.text = name
+ viewModel.sortViews.add(itemBind)
+ itemBind.root.setOnClickListener { onCheck(name) }
+ bind.tagLayout.addView(itemBind.root)
+ }
+ refresh()
+ viewModel.sortViews.forEach {
+ if (it.name.text == viewModel.selectTaskSort) {
+ it.layout.isSelected = true
+ it.name.isSelected = true
+ it.arrowUp.isSelected = viewModel.taskSort == 2
+ it.arrowDown.isSelected = viewModel.taskSort == 1
+ } else {
+ it.layout.isSelected = false
+ it.name.isSelected = false
+ it.arrowUp.isSelected = false
+ it.arrowDown.isSelected = false
}
- defaultSelectFirst()
-
- bind.tvStartTime.setOnClickListener {
- val showTime = getTime(viewModel.startTime)
- val minTime = getTime("2020-01-01")
- dialogTime.show("选择日期", showTime, minTime) {
- val odlIndex = mutableListOf<Int>()
- for (index in bind.stllTaskTime.selectIndexList) { // 先取消选中状态
- odlIndex.add(index)
- }
- odlIndex.forEach { bind.stllTaskTime.onTvClick(it) }
- viewModel.selectTaskTime = ""
-
- val selectTime = getTime(it)
- if (viewModel.endTime.isNotEmpty()) {
- if (selectTime.replace("-", "") >
- viewModel.endTime.replace("-", "")
- ) {
- ToastUtilCommon.showWarn("开始时间不能大于结束时间")
- return@show
- }
- }
- viewModel.startTime = selectTime
- bind.tvStartTime.text = viewModel.startTime
- }
- }
- bind.tvEndTime.setOnClickListener {
- val showTime = getTime(viewModel.endTime)
- val minTime = getTime("2020-01-01")
- dialogTime.show("选择日期", showTime, minTime) {
- val odlIndex = mutableListOf<Int>()
- for (index in bind.stllTaskTime.selectIndexList) { // 先取消选中状态
- odlIndex.add(index)
- }
- odlIndex.forEach { bind.stllTaskTime.onTvClick(it) }
- viewModel.selectTaskTime = ""
-
- val selectTime = getTime(it)
- if (viewModel.startTime.isNotEmpty()) {
- if (selectTime.replace("-", "") <
- viewModel.startTime.replace("-", "")
- ) {
- ToastUtilCommon.showWarn("开始时间不能大于结束时间")
- return@show
- }
- }
- viewModel.endTime = getTime(it)
- bind.tvEndTime.text = viewModel.endTime
- }
- }
-
- bind.cancel.setOnClickListener { dismiss() }
- bind.btnLeft.setOnClickListener {
+ }
+ // 开始时间选择:弹出日期选择器并校验不能大于结束时间
+ bind.tvStartTime.setOnClickListener {
+ val showTime = getTime(viewModel.startTime)
+ val minTime = getTime("2020-01-01")
+ dialogTime.show("选择日期", showTime, minTime) {
val odlIndex = mutableListOf<Int>()
for (index in bind.stllTaskTime.selectIndexList) { // 先取消选中状态
odlIndex.add(index)
}
odlIndex.forEach { bind.stllTaskTime.onTvClick(it) }
- viewModel.selectTaskTime = viewModel.filterTaskTime[2]
- bind.stllTaskTime.onTvClick(2)
+ viewModel.selectTaskTime = ""
- odlIndex.clear()
- for (index in bind.stllTaskLevel.selectIndexList) { // 先取消选中状态
- odlIndex.add(index)
+ val selectTime = getTime(it)
+ if (viewModel.endTime.isNotEmpty()) {
+ if (selectTime.replace("-", "") > viewModel.endTime.replace(
+ "-", ""
+ )
+ ) {
+ ToastUtilCommon.showWarn("开始时间不能大于结束时间")
+ return@show
+ }
}
- odlIndex.forEach { bind.stllTaskLevel.onTvClick(it) }
- viewModel.selectTaskLevel = viewModel.filterTaskLevel[0]
- bind.stllTaskLevel.onTvClick(0)
-
- odlIndex.clear()
- for (index in bind.stllTaskType.selectIndexList) { // 先取消选中状态
- odlIndex.add(index)
- }
- odlIndex.forEach { bind.stllTaskType.onTvClick(it) }
- viewModel.selectTaskType = viewModel.filterTaskType[0]
- bind.stllTaskType.onTvClick(0)
-
- viewModel.startTime = ""
+ viewModel.startTime = selectTime
bind.tvStartTime.text = viewModel.startTime
- viewModel.endTime = ""
- bind.tvEndTime.text = viewModel.endTime
-
- viewModel.selectTaskSort = viewModel.filterTaskSort[0]
- defaultSelectFirst()
}
- bind.btnRight.setOnClickListener {
- if (viewModel.selectTaskTime.isEmpty() && (viewModel.startTime.isEmpty() || viewModel.endTime.isEmpty())) {
- ToastUtilCommon.showWarn("请正确选择时间")
- return@setOnClickListener
+ }
+ // 结束时间选择:弹出日期选择器并校验不能小于开始时间
+ bind.tvEndTime.setOnClickListener {
+ val showTime = getTime(viewModel.endTime)
+ val minTime = getTime("2020-01-01")
+ dialogTime.show("选择日期", showTime, minTime) {
+ val odlIndex = mutableListOf<Int>()
+ for (index in bind.stllTaskTime.selectIndexList) { // 先取消选中状态
+ odlIndex.add(index)
}
- EventBus.getDefault().post(filterData)
+ odlIndex.forEach { bind.stllTaskTime.onTvClick(it) }
+ viewModel.selectTaskTime = ""
+
+ val selectTime = getTime(it)
+ if (viewModel.startTime.isNotEmpty()) {
+ if (selectTime.replace("-", "") < viewModel.startTime.replace(
+ "-", ""
+ )
+ ) {
+ ToastUtilCommon.showWarn("开始时间不能大于结束时间")
+ return@show
+ }
+ }
+ viewModel.endTime = getTime(it)
+ bind.tvEndTime.text = viewModel.endTime
+ }
+ }
+
+ // 取消:直接关闭弹窗
+ bind.close.setOnClickListener { dismiss() }
+ // 重置:恢复所有筛选项为默认状态
+ bind.btnLeft.setOnClickListener {
+ val odlIndex = mutableListOf<Int>()
+ for (index in bind.stllTaskTime.selectIndexList) { // 先取消选中状态
+ odlIndex.add(index)
+ }
+ odlIndex.forEach { bind.stllTaskTime.onTvClick(it) }
+ viewModel.selectTaskTime = viewModel.filterTaskTime[2]
+ bind.stllTaskTime.onTvClick(2)
+
+ odlIndex.clear()
+ for (index in bind.stllTaskLevel.selectIndexList) { // 先取消选中状态
+ odlIndex.add(index)
+ }
+ odlIndex.forEach { bind.stllTaskLevel.onTvClick(it) }
+ viewModel.selectTaskLevel = viewModel.filterTaskLevel[0]
+ bind.stllTaskLevel.onTvClick(0)
+
+ odlIndex.clear()
+ for (index in bind.stllTaskType.selectIndexList) { // 先取消选中状态
+ odlIndex.add(index)
+ }
+ odlIndex.forEach { bind.stllTaskType.onTvClick(it) }
+ viewModel.changeTaskType(0)
+ bind.stllTaskType.onTvClick(0)
+
+ viewModel.startTime = ""
+ bind.tvStartTime.text = viewModel.startTime
+ viewModel.endTime = ""
+ bind.tvEndTime.text = viewModel.endTime
+
+ viewModel.selectTaskSort = viewModel.filterTaskSort[0]
+ refresh()
+ }
+ // 确定:校验时间合法性后下发筛选条件
+ bind.btnRight.setOnClickListener {
+ if (viewModel.selectTaskTime.isEmpty() && (viewModel.startTime.isEmpty() || viewModel.endTime.isEmpty())) {
+ ToastUtilCommon.showWarn("请正确选择时间")
+ return@setOnClickListener
+ }
+ EventBus.getDefault().post(filterData)
+ viewModel.statistic()
// requireActivity().supportFragmentManager.setFragmentResult(
// REQUEST_KEY_FILTER,
// bundleOf(KEY_FILTER_DATA to filterData)
// )
- filterDialog?.dismiss()
- }
- bind.sure.setOnClickListener {
- EventBus.getDefault().post(filterData)
-// requireActivity().supportFragmentManager.setFragmentResult(
-// REQUEST_KEY_FILTER,
-// bundleOf(KEY_FILTER_DATA to filterData)
-// )
- filterDialog?.dismiss()
- }
+ filterDialog?.dismiss()
+ refreshFilterStatus()
}
}
}
@@ -379,12 +505,14 @@
filterDialog?.window?.setWindowAnimations(R.style.AnimUp)
}
+ /**
+ * 定位结果回调
+ *
+ * @param pLocation 定位结果,null 表示未获取到定位权限
+ */
override fun location(pLocation: AMapLocation?) {
if (pLocation == null) {
- CommonDialog.showTipsDialog(
- requireActivity(),
- "您未开启gps权限,无法获取当前定位,请打开后重新操作",
- null)
+ CommonDialog.showLocationNotGrantedTipsDialog(requireActivity())
} else {
viewModel.location = pLocation
EventBus.getDefault().post(locationData)
@@ -395,11 +523,21 @@
}
}
+ override fun onDestroyView() {
+ super.onDestroyView()
+ tabLayoutMediator?.detach()
+ }
+
override fun onDestroy() {
super.onDestroy()
EventBus.getDefault().unregister(this)
}
+ /**
+ * EventBus 消息接收:切换任务 Tab
+ *
+ * @param event 切换目标 Tab 索引事件
+ */
@Suppress("unused")
@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(event: SwitchTabTask) {
@@ -410,17 +548,34 @@
}
}
+ /**
+ * ViewPager2 适配器
+ *
+ * 根据 position 返回对应状态的任务列表 Fragment
+ */
inner class PagerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
+ private val pages = listOf(
+ viewModel.allTaskFragment,
+ viewModel.togoTaskFragment,
+ viewModel.todoTaskFragment,
+ viewModel.finishTaskFragment,
+ viewModel.reassignmentTaskFragment
+ )
+
override fun getItemCount(): Int = tabTitles.size
override fun createFragment(position: Int): TaskListFragment {
- return when (position) {
- 0 -> viewModel.allTaskFragment
- 1 -> viewModel.togoTaskFragment
- 2 -> viewModel.todoTaskFragment
- 3 -> viewModel.finishTaskFragment
- else -> error("Wrong position $position")
- }
+ return pages[position]
+ }
+
+ // 返回唯一的 ID,推荐使用数据的哈希值
+ override fun getItemId(position: Int): Long {
+ return pages[position].hashCode().toLong()
+ }
+
+ // 告诉 ViewPager2 某个 ID 是否仍然有效
+ override fun containsItem(itemId: Long): Boolean {
+ return pages.any { it.hashCode().toLong() == itemId }
}
}
diff --git a/app/src/main/java/com/xw/yunwei/ui/task/TaskVM.kt b/app/src/main/java/com/xw/yunwei/ui/task/TaskVM.kt
index d637b7f..872784a 100644
--- a/app/src/main/java/com/xw/yunwei/ui/task/TaskVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/task/TaskVM.kt
@@ -4,52 +4,113 @@
import android.view.View
import androidx.lifecycle.MutableLiveData
import com.amap.api.location.AMapLocation
-import com.blankj.utilcode.util.TimeUtils
import com.xw.common.base.BaseViewModel
-import com.xw.common.utils.ToastUtilCommon
+import com.xw.common.utils.LogUtils
import com.xw.yunwei.R
import com.xw.yunwei.databinding.ItemArrow2TextBinding
+import com.xw.yunwei.model.TaskStatisticInfo
import com.xw.yunwei.net.TaskRepository
import com.xw.yunwei.ui.task.list.TaskListFragment
import org.koin.core.component.inject
-import java.text.SimpleDateFormat
-import kotlin.getValue
+/**
+ * 任务中心 ViewModel
+ *
+ * 管理任务筛选条件、任务列表 Fragment 实例、未读消息数量等业务数据,
+ * 提供筛选参数转换及网络请求能力。
+ *
+ * @author zmc
+ */
class TaskVM(myApplication: Application) : BaseViewModel(myApplication) {
- companion object{
- val needRefresh = MutableLiveData(true) // 需要刷新消息
+ companion object {
+ /** 全局标识:是否需要刷新消息红点 */
+ val needRefresh = MutableLiveData(true)
}
+ /** 全部任务列表 Fragment */
val allTaskFragment by lazy { TaskListFragment.newInstance(null) }
- val togoTaskFragment by lazy { TaskListFragment.newInstance(0) }
- val todoTaskFragment by lazy { TaskListFragment.newInstance(1) }
- val finishTaskFragment by lazy { TaskListFragment.newInstance(2) }
+ /** 待到达任务列表 Fragment */
+ val togoTaskFragment by lazy { TaskListFragment.newInstance(0) }
+
+ /** 待处理任务列表 Fragment */
+ val todoTaskFragment by lazy { TaskListFragment.newInstance(1) }
+
+ /** 已处理任务列表 Fragment */
+ val finishTaskFragment by lazy { TaskListFragment.newInstance(2) }
+ val reassignmentTaskFragment by lazy { TaskListFragment.newInstance(4) }
+
+ /** 任务数据仓库 */
val taskRepository: TaskRepository by inject()
+ //选中任务类型下标
+ val selectTaskTypeIndex = MutableLiveData(0)
+
+ //统计信息
+ val taskStatistic = MutableLiveData<TaskStatisticInfo>()
+
+ /** 当前定位信息 */
var location: AMapLocation? = null
+
+ /** 车牌号搜索关键字 */
// 车牌号
val plateNumber: MutableLiveData<String> = MutableLiveData("")
+
+ /** 筛选开始时间(yyyy-MM-dd) */
var startTime = ""
+
+ /** 筛选结束时间(yyyy-MM-dd) */
var endTime = ""
- /*派发时间*/
+
+ /** 派发时间筛选项 */
val filterTaskTime = listOf("今天", "昨天", "近一周", "近一月")
- /*优先级*/
+
+ /** 优先级筛选项 */
val filterTaskLevel = listOf("全部", "一级", "二级", "三级")
- /*任务类型*/
+
+ /** 任务类型筛选项 */
val filterTaskType = listOf("全部", "事故", "常规")
- /*排序优先*/
+
+ /** 排序优先筛选项 */
val filterTaskSort = listOf("任务优先级", "车牌号", "任务时间")
+ /** 当前选中的派发时间 */
var selectTaskTime = filterTaskTime[2]
+
+ /** 当前选中的优先级 */
var selectTaskLevel = filterTaskLevel[0]
+
+ /** 当前选中的任务类型 */
var selectTaskType = filterTaskType[0]
+
+ /** 当前选中的排序字段 */
var selectTaskSort = filterTaskSort[0]
- var taskSort = 1 // 1正序 2倒序
+
+ /** 排序规则:1 正序,2 倒序 */
+ var taskSort = 1
+
+ /** 排序视图绑定列表,用于动态更新 UI 状态 */
val sortViews = mutableListOf<ItemArrow2TextBinding>()
- fun getDistributeType(): Int? = when {
+ //是否刷新列表
+ val needRefreshList = MutableLiveData(false)
+
+ //是否已经筛选
+ fun hadFilter(): Boolean {
+ return selectTaskTime != filterTaskTime[2] || selectTaskLevel != filterTaskLevel[0] ||
+ selectTaskType != filterTaskType[0] || selectTaskSort != filterTaskSort[0] || taskSort != 1 ||
+ startTime.isNotEmpty() || endTime.isNotEmpty()
+ }
+
+ /**
+ * 获取派发类型对应的服务器参数
+ *
+ * 若用户自定义了时间范围则返回 5;否则根据快捷选项返回对应编码。
+ *
+ * @return 派发类型编码,null 表示未选择
+ */
+ fun getDistributeType(): Int? = when {
startTime.isNotEmpty() || endTime.isNotEmpty() -> 5
selectTaskTime == "今天" -> 1
selectTaskTime == "昨天" -> 2
@@ -58,27 +119,46 @@
else -> null
}
- fun getUrgencyLevel(): Int? = when (selectTaskLevel) {
+ /**
+ * 获取紧急程度对应的服务器参数
+ *
+ * @return 紧急程度编码,null 表示全部
+ */
+ fun getUrgencyLevel(): Int? = when (selectTaskLevel) {
"一级" -> 0
"二级" -> 1
"三级" -> 2
else -> null
}
- fun getTaskCategory(): Int? = when(selectTaskType) {
+ /**
+ * 获取任务类别对应的服务器参数
+ *
+ * @return 任务类别编码,null 表示全部
+ */
+ fun getTaskCategory(): Int? = when (selectTaskType) {
"事故" -> 2
"常规" -> 1
else -> null
}
- fun getSortType(): Int? = when (selectTaskSort) {
+ /**
+ * 获取排序类型对应的服务器参数
+ *
+ * @return 排序类型编码,null 表示未选择
+ */
+ fun getSortType(): Int? = when (selectTaskSort) {
"任务优先级" -> 1
"车牌号" -> 2
"任务时间" -> 3
else -> null
}
-
+ /**
+ * 获取未读消息数量
+ *
+ * @param block 请求结果回调,参数为未读数量字符串
+ */
fun getUnreadCount(block: (String) -> Unit) {
launchRequest(showLoading = false) {
taskRepository.getUnreadCount().let {
@@ -86,4 +166,52 @@
}
}
}
+
+ //更改任务类型
+ fun changeTaskType(index: Int) {
+ selectTaskType = filterTaskType[index]
+ selectTaskTypeIndex.postValue(index)
+ }
+
+ val onClick = View.OnClickListener {
+ when (it.id) {
+ R.id.back -> onBackPressed()
+
+ R.id.rl_all -> {
+ changeTaskType(0)
+ statistic()
+ needRefreshList.postValue(true)
+ }
+
+ R.id.rl_accident -> {
+ changeTaskType(1)
+ statistic()
+ needRefreshList.postValue(true)
+ }
+
+ R.id.rl_normal -> {
+ changeTaskType(2)
+ statistic()
+ needRefreshList.postValue(true)
+ }
+ }
+ }
+
+ //获取统计信息
+ fun statistic() {
+ launchRequest(error = { code, msg ->
+ LogUtils.e(TAG, "launchRequest: code = $code msg = $msg")
+ }) {
+ taskRepository.statistic(
+ getDistributeType()?.toString(),
+ startTime,
+ endTime,
+ getTaskCategory()?.toString(),
+ getUrgencyLevel()?.toString(),
+ plateNumber.value
+ )?.also {
+ taskStatistic.postValue(it)
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/task/accident/detail/AccidentDetailActivity.kt b/app/src/main/java/com/xw/yunwei/ui/task/accident/detail/AccidentDetailActivity.kt
index f8a7aa3..d7bea84 100644
--- a/app/src/main/java/com/xw/yunwei/ui/task/accident/detail/AccidentDetailActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/task/accident/detail/AccidentDetailActivity.kt
@@ -1,13 +1,17 @@
package com.xw.yunwei.ui.task.accident.detail
+import android.animation.ObjectAnimator
+import android.animation.ValueAnimator
import android.os.Bundle
import android.view.LayoutInflater
+import android.view.View
+import android.view.animation.LinearInterpolator
+import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.GridLayoutManager
import com.amap.api.location.AMapLocation
import com.amap.api.maps.model.LatLng
import com.xw.common.CommonDialog
-import com.xw.common.base.BaseActivity
import com.xw.common.base.FileSelectBean
import com.xw.common.base.ImageEventListener
import com.xw.common.base.ImageSelectAdapter
@@ -17,32 +21,49 @@
import com.xw.common.utils.GpsHelper.Companion.navigate
import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.MyApp
import com.xw.yunwei.R
import com.xw.yunwei.databinding.ActivityAccidentDetailBinding
import com.xw.yunwei.databinding.LayoutAccidentType1Binding
import com.xw.yunwei.databinding.LayoutAccidentType2Binding
+import com.xw.yunwei.extension.colorIdToColorValue
import com.xw.yunwei.model.XpErrorType
-import java.util.ArrayList
-import kotlin.text.ifEmpty
/**
- * 事故详情
+ * 事故详情页面
+ *
+ * 展示事故任务详情信息,包括任务图片、事故类型标签、
+ * 倒计时、到达/处理操作按钮及导航等功能。
+ *
+ * @author zmc
*/
-class AccidentDetailActivity : BaseActivity<ActivityAccidentDetailBinding, AccidentDetailVM>(), GpsHelper.OnMapLocation {
+class AccidentDetailActivity :
+ BaseBusinessActivity<ActivityAccidentDetailBinding, AccidentDetailVM>(),
+ GpsHelper.OnMapLocation {
override fun getBindingVariable() = BR.viewModel
+ /** 图片查看事件监听 */
lateinit var imageEvent: ImageEventListener<FileSelectBean>
+
+ /** 图片选择/展示适配器 */
lateinit var adapter: ImageSelectAdapter
+
+ /** GPS 定位辅助类 */
var gpsHelper: GpsHelper? = null
- var savedInstanceState: Bundle?=null
+
+ /** 页面状态保存 */
+ var savedInstanceState: Bundle? = null
override fun myCreate(savedInstanceState: Bundle?) {
super.myCreate(savedInstanceState)
this.savedInstanceState = savedInstanceState
}
+ /**
+ * 初始化页面数据及适配器
+ */
override fun init() {
super.init()
viewModel.taskId = intent.getLongExtra("taskId", 0L)
@@ -55,13 +76,18 @@
viewModel.getAppPermission()
}
+ /**
+ * 设置数据观察监听
+ */
override fun setObservable() {
super.setObservable()
+ // 监听事故详情数据变化,更新图片、事故类型、定位及权限校验
viewModel.taskDetail.observe(this) {
it.taskImage?.getUrls()?.let {
adapter.setList(it.map { FileSelectBean(url = it, type = "img") })
}
initTypeLayout(it.errorTypeList)
+ // 待到达状态才需要开启定位校验
if (viewModel.taskDetail.value?.status == 0) { // 待到达 才需要定位
if (gpsHelper == null) {
gpsHelper = GpsHelper(
@@ -77,18 +103,78 @@
viewModel.locationCheck()
checkActionPermissions()
}
- viewModel.canConfirmArrive.observe(this){
+ // 监听是否可确认到达,控制按钮背景色
+ viewModel.canConfirmArrive.observe(this) {
if (it) {
binding.tvControl.setBackgroundResource(R.drawable.shape_blue_5_bg_4)
} else {
binding.tvControl.setBackgroundResource(R.drawable.shape_blue_1_bg_4)
}
}
- MyApp.permissions.observe(this){
+ // 监听应用权限变化,重新校验按钮权限
+ MyApp.permissions.observe(this) {
checkActionPermissions()
+ }
+
+ viewModel.hadCheckDoorStatus.observe(this) {
+ binding.ivDoorStatus.isVisible = !it
+ binding.ivDoorStatusLoading.isVisible = it
+ if (it) {
+ // 创建旋转动画
+ val rotateAnimator = getRotationAnimator(binding.ivDoorStatusLoading)
+ rotateAnimator.start()
+ binding.ivDoorStatusLoading.tag = rotateAnimator
+ } else {
+ (binding.ivDoorStatusLoading.tag as? ObjectAnimator)?.cancel()
+ }
+ }
+ viewModel.hadDoorOpened.observe(this) {
+ binding.unlockDoor.setBackgroundResource(if (it) com.xw.common.R.drawable.shape_blue1_bg_4 else R.drawable.shape_gray2_bg_4)
+ binding.ivDoorStatus.setImageResource(if (it) com.xw.common.R.drawable.svg_car_cmjs else R.drawable.svg_net_lock_gray)
+ binding.tvDoorLock.setTextColor(
+ (if (it) com.xw.common.R.color.blue_5 else com.xw.common.R.color.gray_7).colorIdToColorValue(
+ this
+ )
+ )
+ }
+ viewModel.hadCheckTrunkStatus.observe(this) {
+ binding.ivTrunkStatus.isVisible = !it
+ binding.ivTrunkStatusLoading.isVisible = it
+ if (it) {
+ // 创建旋转动画
+ val rotateAnimator = getRotationAnimator(binding.ivTrunkStatusLoading)
+ rotateAnimator.start()
+ binding.ivTrunkStatusLoading.tag = rotateAnimator
+ } else {
+ (binding.ivTrunkStatusLoading.tag as? ObjectAnimator)?.cancel()
+ }
+ }
+ viewModel.hadTrunkOpened.observe(this) {
+ binding.unlockBox.setBackgroundResource(if (it) com.xw.common.R.drawable.shape_blue1_bg_4 else R.drawable.shape_gray2_bg_4)
+ binding.ivTrunkStatus.setImageResource(if (it) com.xw.common.R.drawable.svg_car_hbxjs else R.drawable.svg_car_trunk_closed)
+ binding.tvTrunkLock.setTextColor(
+ (if (it) com.xw.common.R.color.blue_5 else com.xw.common.R.color.gray_7).colorIdToColorValue(
+ this
+ )
+ )
}
}
+ //获取无限旋转动画
+ private fun getRotationAnimator(view: View): ObjectAnimator {
+ return ObjectAnimator.ofFloat(view, "rotation", 0f, 360f)
+ .apply {
+ duration = 2000 // 旋转一圈用时 2 秒
+ repeatCount = ValueAnimator.INFINITE // 无限重复
+ interpolator = LinearInterpolator() // 匀速旋转
+ }
+ }
+
+ /**
+ * 根据任务状态检查当前用户是否有操作权限
+ *
+ * 状态 0(待到达)检查"到达事故现场"权限,状态 1(待处理)检查"处理事故"权限
+ */
private fun checkActionPermissions() {
when (viewModel.taskDetail.value?.status) {
0 -> viewModel.actionPermissions.value =
@@ -99,8 +185,15 @@
}
}
+ /**
+ * 设置页面点击监听器
+ */
override fun setListener() {
super.setListener()
+ binding.tvApplyForReassignment.setOnClickListener {
+ viewModel.showApplyForReassignDialog(this)
+ }
+ // 导航按钮:校验坐标合法性后跳转地图导航
binding.nav.setOnClickListener {
viewModel.taskDetail.value?.let { item ->
if ((item.vehicleLat ?: 0.0) != 0.0 && (item.vehicleLon ?: 0.0) != 0.0) {
@@ -115,6 +208,9 @@
}
}
+ /**
+ * 初始化图片展示适配器
+ */
private fun initAdapter() {
imageEvent = object : ImageEventListener<FileSelectBean>() {
override fun viewImage(item: FileSelectBean) {
@@ -134,6 +230,13 @@
binding.rv.layoutManager = GridLayoutManager(this, 5)
}
+ /**
+ * 初始化事故类型布局
+ *
+ * 根据服务端返回的事故类型列表动态构建多级标签视图
+ *
+ * @param errorTypeList 事故类型数据列表
+ */
private fun initTypeLayout(errorTypeList: List<XpErrorType>?) {
binding.accidentLayout.removeAllViews()
errorTypeList?.forEach {
@@ -145,6 +248,7 @@
)
bind.name.text = it.errorName
bind.icon.setImageResource(map[it.errorName] ?: R.mipmap.ic_task_accident1)
+ // 动态添加子类型标签
it.child?.forEach {
val tvBind: LayoutAccidentType2Binding = DataBindingUtil.inflate(
LayoutInflater.from(this),
@@ -159,6 +263,7 @@
}
}
+ /** 事故类型名称与图标资源映射表 */
val map = mapOf(
"车辆技术故障类" to R.mipmap.ic_task_accident1,
@@ -173,12 +278,14 @@
"综合保障事件类" to R.mipmap.ic_task_accident6,
)
+ /**
+ * 定位结果回调
+ *
+ * @param pLocation 定位结果,null 表示未获取到定位权限
+ */
override fun location(pLocation: AMapLocation?) {
if (pLocation == null) {
- CommonDialog.showTipsDialog(
- this@AccidentDetailActivity,
- "您未开启gps权限,无法获取当前定位,请打开后重新操作",
- null)
+ CommonDialog.showLocationNotGrantedTipsDialog(this@AccidentDetailActivity)
} else {
viewModel.location = pLocation
viewModel.locationCheck()
diff --git a/app/src/main/java/com/xw/yunwei/ui/task/accident/detail/AccidentDetailVM.kt b/app/src/main/java/com/xw/yunwei/ui/task/accident/detail/AccidentDetailVM.kt
index a03e2d8..8c16f93 100644
--- a/app/src/main/java/com/xw/yunwei/ui/task/accident/detail/AccidentDetailVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/task/accident/detail/AccidentDetailVM.kt
@@ -1,49 +1,77 @@
package com.xw.yunwei.ui.task.accident.detail
import android.app.Application
+import android.content.Context
import android.os.Handler
import android.os.Looper
import android.os.Message
-import com.xw.common.utils.LogUtils
import android.view.View
-import androidx.core.os.bundleOf
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.map
+import androidx.lifecycle.viewModelScope
import com.amap.api.location.AMapLocation
import com.amap.api.maps.model.LatLng
import com.xw.common.base.BaseViewModel
import com.xw.common.utils.CalculatorLineDistance
+import com.xw.common.utils.LogUtils
import com.xw.common.utils.ToastUtilCommon
+import com.xw.yunwei.Constants
import com.xw.yunwei.MyApp
import com.xw.yunwei.R
+import com.xw.yunwei.model.SwitchTabMain
+import com.xw.yunwei.model.SwitchTabTask
import com.xw.yunwei.model.TaskAccidentModel
+import com.xw.yunwei.model.VehicleLocationInfo
import com.xw.yunwei.net.TaskRepository
import com.xw.yunwei.net.UserRepository
import com.xw.yunwei.net.WorkRepository
+import com.xw.yunwei.ui.dialog.ApplyForReassignReasonDialog
import com.xw.yunwei.ui.task.accident.handle.AccidentProcessActivity
import com.xw.yunwei.ui.task.list.TaskListAdapter.Companion.MSG_COUNTDOWN
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import org.greenrobot.eventbus.EventBus
import org.koin.core.component.inject
import java.time.Duration
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.concurrent.TimeUnit
-import kotlin.getValue
import kotlin.math.max
+/**
+ * 事故详情 ViewModel
+ *
+ * 管理事故详情数据加载、倒计时计算、位置校验、
+ * 到达确认及车门/后备箱解锁等业务逻辑。
+ *
+ * @author zmc
+ */
class AccidentDetailVM(myApplication: Application) : BaseViewModel(myApplication) {
+ /** 任务数据仓库 */
val taskRepository: TaskRepository by inject()
+
+ /** 工作数据仓库(解锁等操作) */
val workRepository: WorkRepository by inject()
+
+ /** 用户数据仓库(权限获取) */
val userRepository: UserRepository by inject()
+ /** 当前任务 ID */
var taskId = 0L
+
+ /** 事故详情数据 */
val taskDetail: MutableLiveData<TaskAccidentModel> = MutableLiveData()
+
+ /** 页面标题,根据状态显示"待到达"/"待处理" */
val title = taskDetail.map {
- if(it.status == 0) "待到达" else if(it.status == 1) "待处理" else ""
+ if (it.status == 0) "待到达" else if (it.status == 1) "待处理" else ""
}
+
+ /** 紧急程度图标资源 ID */
val levelId = taskDetail.map {
- LogUtils.e("zmc-L", "taskDetail ${it.taskUrgencyLevel}" )
- when(it.taskUrgencyLevel){
+ LogUtils.e("zmc-L", "taskDetail ${it.taskUrgencyLevel}")
+ when (it.taskUrgencyLevel) {
0 -> R.mipmap.ic_accident_one
1 -> R.mipmap.ic_accident_two
2 -> R.mipmap.ic_accident_three
@@ -51,26 +79,65 @@
else -> R.mipmap.ic_accident_one
}
}
- val isTimeOut = MutableLiveData(false) // 是否超时
+
+ /** 是否已超时 */
+ val isTimeOut = MutableLiveData(false)
+
+ /** 倒计时:小时 */
val hour = MutableLiveData("")
+
+ /** 倒计时:分钟 */
val minutes = MutableLiveData("")
+
+ /** 倒计时:秒 */
val second = MutableLiveData("")
+
+ /** 是否显示红色警告样式 */
val showRed = MutableLiveData(false)
+
+ /** 冒号图标,根据 showRed 切换颜色 */
val icon1 = showRed.map {
if (it) R.mipmap.ic_task_item_colon_r else R.mipmap.ic_task_item_colon_b
}
- val topBgId = isTimeOut.map {
+
+ /** 顶部背景图,根据是否超时切换红/蓝主题 */
+ val topBgId = showRed.map {
if (it) R.mipmap.img_accident_top_bg_red else R.mipmap.img_accident_top_bg_blue
}
+ /** 操作按钮是否可见(权限控制) */
val actionPermissions = MutableLiveData(false) // 按钮权限
+ /** 操作按钮文字 */
val actionName = taskDetail.map {
- if(it.status == 0) "到达现场" else if(it.status == 1) "事故处理" else ""
+ if (it.status == 0) "到达现场" else if (it.status == 1) "事故处理" else ""
}
+
+ /** 是否能提交到达操作(需在指定范围内) */
var canConfirmArrive = MutableLiveData(false) // 是否能提交到达操作
+
+ /** 当前定位信息 */
var location: AMapLocation? = null
+ //是否已经循环检测车辆位置
+ var hadLoopRefreshCarLocation = false
+
+ //车辆位置
+ val carLocation = MutableLiveData<VehicleLocationInfo>()
+
+ //是否已经循环检测车门状态
+ var hadCheckDoorStatus = MutableLiveData(false)
+
+ //是否已经车门开启
+ var hadDoorOpened = MutableLiveData(false)
+
+ //是否已经循环检测后备箱状态
+ var hadCheckTrunkStatus = MutableLiveData(false)
+
+ //是否已经后备箱开启
+ var hadTrunkOpened = MutableLiveData(false)
+
+ /** 页面点击事件统一监听 */
var onClick = View.OnClickListener {
when (it.id) {
R.id.back -> onBackPressed()
@@ -80,40 +147,136 @@
}
}
+ /**
+ * 查询事故详情
+ *
+ * 请求成功后根据任务状态决定是否启动倒计时
+ */
fun queryDetail() {
launchRequest {
- taskRepository.vehicleAccidentDetail("$taskId")?.let {
+ taskRepository.vehicleAccidentDetail("$taskId")?.let { it ->
taskDetail.postValue(it)
if (it.status == 0) {
startCountdown()
+ carLocation.postValue(
+ VehicleLocationInfo(
+ it.vehicleLon?.toString(),
+ it.vehicleLat?.toString(),
+ it.vehicleLocation
+ )
+ )
} else if (it.status == 1) {
stopCountdown()
+ carLocation.postValue(
+ VehicleLocationInfo(
+ it.vehicleLon?.toString(),
+ it.vehicleLat?.toString(),
+ it.vehicleLocation
+ )
+ )
+ }
+ loopRefreshCarLocation()
+ checkTrunkStatus(it.vehicleId.toString()) {
+ taskDetail.postValue(taskDetail.value?.copy(hadTrunkOpened = it.toString()))
}
}
}
}
- fun confirmArrive(){
+ /**
+ * 确认到达事故现场
+ */
+ fun confirmArrive() {
launchRequest("操作中...") {
taskRepository.confirmArrive("${taskDetail.value!!.id}")
queryDetail()
}
}
+ /**
+ * 按类型解锁车辆
+ *
+ * @param type 解锁类型:1 车门,2 后备箱
+ */
fun unlockByType(type: Int) {
- launchRequest(tips = "正在传达指令", error = { code, msg ->
- ToastUtilCommon.showError("操作失败,请重试")
+ if (type == 1 && hadDoorOpened.value == true) {
+ return
+ }
+ if (type == 2 && hadTrunkOpened.value == true) {
+ return
+ }
+ if (type == 1 && hadCheckDoorStatus.value == true) {
+ ToastUtilCommon.showError("正在检测后备箱状态中...")
+ return
+ }
+ if (type == 2 && hadCheckTrunkStatus.value == true) {
+ ToastUtilCommon.showError("正在检测后备箱状态中...")
+ return
+ }
+ when (type) {
+ 1 -> {
+ hadCheckDoorStatus.value = true
+ }
+
+ 2 -> {
+ hadCheckTrunkStatus.value = true
+ }
+ }
+ launchRequest(tips = "正在传达指令", showLoading = false, error = { code, msg ->
+ runOnMainThread { ToastUtilCommon.showError(msg.ifEmpty { "操作失败,请重试" }) }
+ when (type) {
+ 1 -> {
+ hadCheckDoorStatus.postValue(false)
+ }
+
+ 2 -> {
+ hadCheckTrunkStatus.postValue(false)
+ }
+ }
}) {
val map = mutableMapOf<String, Any?>()
+ val isOpen =
+ if (type == 1) taskDetail.value?.hadOpenedDoor() != true else taskDetail.value?.hadOpenedTrunk() != true
map["vehicleId"] = taskDetail.value?.vehicleId // 车辆ID
- map["unlockType"] = type // 解锁类型 1车门 2后备箱
+ map["latitude"] = com.xw.common.Constants.latitude
+ map["longitude"] = com.xw.common.Constants.longitude
+ map["doorType"] = if (type == 1) "door" else "trunk" // 解锁类型 1车门 2后备箱
+ map["operationType"] = if (isOpen) "open" else "close" // 操作类型(open/close)
workRepository.unlockByType(map)
- val tips = if (type == 1) "车门已解锁" else "后备箱已解锁"
- ToastUtilCommon.showSuc(tips)
+ when (type) {
+ 1 -> {
+ runOnMainThread { ToastUtilCommon.showSuc("车门解锁成功") }
+ hadCheckDoorStatus.postValue(false)
+ hadDoorOpened.postValue(true)
+ }
+
+ 2 -> {
+ runOnMainThread { ToastUtilCommon.showSuc("后备箱解锁成功") }
+ hadCheckTrunkStatus.postValue(false)
+ hadTrunkOpened.postValue(true)
+ }
+ }
}
}
- private fun handleAction(){
+ //检测后备箱状态
+ private fun checkTrunkStatus(vehicleId: String, block: (status: Int) -> Unit) {
+ launchRequest(showLoading = false, error = { code, msg ->
+ LogUtils.e(TAG, "launchRequest: code = $code msg = $msg")
+ }) {
+ workRepository.checkTrunkLockStatus(vehicleId)?.also {
+ block.invoke(it)
+ }
+ }
+ }
+
+ /**
+ * 处理底部操作按钮点击事件
+ *
+ * 状态 0:校验是否在到达范围内,合法则确认到达
+ * 状态 1:跳转到事故处理页面
+ */
+ private fun handleAction() {
when (taskDetail.value?.status) {
0 -> {
if (canConfirmArrive.value == true) {
@@ -126,12 +289,18 @@
1 -> {
startActivity(
AccidentProcessActivity::class.java,
- bundleOf("taskId" to taskDetail.value?.id)
+ AccidentProcessActivity.getParams(taskDetail.value)
)
}
}
}
+ /**
+ * 位置检查
+ *
+ * 计算当前定位与事故车辆位置的距离,
+ * 若在 canArriveRange 范围内则允许确认到达。
+ */
/*位置检查*/
fun locationCheck() {
taskDetail.value?.let {
@@ -139,13 +308,18 @@
val lat = location?.latitude ?: 0.0
val lng = location?.longitude ?: 0.0
- if (lat != 0.0 && lng != 0.0 && (it.vehicleLat ?: 0.0) != 0.0 && (it.vehicleLon ?: 0.0) != 0.0) {
+ if (lat != 0.0 && lng != 0.0 && (it.vehicleLat ?: 0.0) != 0.0 && (it.vehicleLon
+ ?: 0.0) != 0.0
+ ) {
val dis = CalculatorLineDistance.calculate(
LatLng(lat, lng),
LatLng(it.vehicleLat!!, it.vehicleLon!!)
)
canConfirmArrive.postValue((it.canArriveRange ?: 0) > dis.toInt())
- LogUtils.i("zmc-test-detail","${it.plateNumber} dis = $dis canArriveRange = ${it.canArriveRange} canClick = ${(it.canArriveRange ?: 0) > dis.toInt()}")
+ LogUtils.i(
+ "zmc-test-detail",
+ "${it.plateNumber} dis = $dis canArriveRange = ${it.canArriveRange} canClick = ${(it.canArriveRange ?: 0) > dis.toInt()}"
+ )
}
} else {
@@ -156,6 +330,8 @@
/**
* 计算目标时间与当前时间的差值,返回时分秒格式
+ *
+ * @return 包含 [时, 分, 秒] 的列表
*/
fun calculateTimeDifference(): List<Long> {
try {
@@ -176,7 +352,7 @@
return listOf(hours, minutes, seconds)
}
} catch (e: Exception) {
- LogUtils.e(TAG, "calculateTimeDifference: $e", )
+ LogUtils.e(TAG, "calculateTimeDifference: $e")
}
return listOf(0L, 0L, 0L)
}
@@ -197,6 +373,7 @@
countdownHandler.removeMessages(MSG_COUNTDOWN)
}
+ /** 倒计时 Handler,每秒刷新一次剩余时间 */
// 倒计时Handler
private val countdownHandler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
@@ -205,10 +382,12 @@
stopCountdown()
} else {
val list = calculateTimeDifference()
+ // 补零格式化时间显示
hour.postValue(if (list[0] < 10) "0${list[0]}" else "${list[0]}")
minutes.postValue(if (list[1] < 10) "0${list[1]}" else "${list[1]}")
second.postValue(if (list[2] < 10) "0${list[2]}" else "${list[2]}")
- showRed.postValue(list[0] == 0L && list[1] == 0L)
+ // 剩余时间不足3分钟显示红色警告
+ showRed.postValue(list[0] == 0L && list[1] <= 2L)
if (list.all { it == 0L }) { // 全0 此项移除
isTimeOut.postValue(true)
}
@@ -223,6 +402,9 @@
stopCountdown()
}
+ /**
+ * 获取应用权限配置
+ */
fun getAppPermission() {
launchRequest(showLoading = false) {
userRepository.getAppPermission()?.let {
@@ -232,4 +414,72 @@
}
}
}
+
+ //显示改派弹窗
+ fun showApplyForReassignDialog(context: Context) {
+ if (taskDetail.value == null) {
+ return
+ }
+ ApplyForReassignReasonDialog.show(
+ context,
+ Constants.reasons,
+ ) { position, input, dialog ->
+ showDialog(content = "改派中...")
+ launchRequest(showLoading = false, error = { code, msg ->
+ dismissDialog()
+ ToastUtilCommon.showError(msg)
+ LogUtils.e(TAG, "launchRequest: code = $code msg = $msg")
+ }) {
+ val comment = Constants.reasons[position]
+ taskRepository.taskReassignment(comment, input, taskId.toString()).also {
+ dialog.dismiss()
+ checkApplyForReassignResult()
+ }
+ }
+ }
+ }
+
+ //检测申请改派结果
+ private fun checkApplyForReassignResult() {
+ launchRequest(showLoading = false, error = { code, msg ->
+ dismissDialog()
+ ToastUtilCommon.showError(msg)
+ LogUtils.e(TAG, "launchRequest: code = $code msg = $msg")
+ }) {
+ delay(3 * 1000)
+ val isOk = taskRepository.checkApplyForReassignResult(taskId.toString())
+ dismissDialog()
+ isOk?.also {
+ if (it) ToastUtilCommon.showSuc("改派成功") else ToastUtilCommon.showError("暂未找到运维人员")
+ EventBus.getDefault().post(SwitchTabMain(1))
+ if (!it) {
+ EventBus.getDefault().post(SwitchTabTask(4))
+ }
+ }
+ finish()
+ }
+ }
+
+ //循环刷新车辆位置
+ private fun loopRefreshCarLocation() {
+ if (hadLoopRefreshCarLocation) {
+ return
+ }
+ hadLoopRefreshCarLocation = true
+
+ viewModelScope.launch {
+ while (true) {
+ delay(60 * 1000)
+ launchRequest(showLoading = false, error = { code, msg ->
+ LogUtils.e(TAG, "launchRequest: code = $code msg = $msg")
+ }) {
+ taskDetail.value?.also { it ->
+ taskRepository.queryVehicleNewPoint(it.vehicleId?.toString())?.also {
+ carLocation.postValue(it)
+ }
+ }
+ }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/task/accident/handle/AccidentProcessActivity.kt b/app/src/main/java/com/xw/yunwei/ui/task/accident/handle/AccidentProcessActivity.kt
index 62c7e69..b257249 100644
--- a/app/src/main/java/com/xw/yunwei/ui/task/accident/handle/AccidentProcessActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/task/accident/handle/AccidentProcessActivity.kt
@@ -2,36 +2,97 @@
import android.annotation.SuppressLint
import android.net.Uri
+import android.os.Bundle
+import android.text.StaticLayout
+import android.text.TextPaint
+import android.text.TextUtils
+import android.util.TypedValue
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowManager
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.core.os.bundleOf
+import androidx.core.view.isVisible
+import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.GridLayoutManager
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.afollestad.materialdialogs.MaterialDialog
+import com.afollestad.materialdialogs.customview.customView
+import com.afollestad.materialdialogs.customview.getCustomView
import com.blankj.utilcode.util.UriUtils
-import com.luck.picture.lib.basic.PictureSelector
import com.luck.picture.lib.config.PictureMimeType
-import com.luck.picture.lib.config.SelectMimeType
import com.luck.picture.lib.entity.LocalMedia
import com.luck.picture.lib.interfaces.OnResultCallbackListener
import com.xw.common.CommonDialog
import com.xw.common.R
-import com.xw.common.base.BaseActivity
import com.xw.common.base.FileSelectBean
import com.xw.common.base.ImageEventListener
import com.xw.common.base.ImageSelectAdapter
import com.xw.common.base.ShowImgListDialog
-import com.xw.common.utils.GlideEngine
-import com.xw.common.utils.PictureCompressEngine
+import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
+import com.xw.yunwei.constants.Key
import com.xw.yunwei.databinding.ActivityAccidentProcessBinding
-import java.util.ArrayList
+import com.xw.yunwei.databinding.DialogAccidentFilterBinding
+import com.xw.yunwei.extension.colorIdToColorValue
+import com.xw.yunwei.extension.dpToPx
+import com.xw.yunwei.extension.spToPx
+import com.xw.yunwei.model.TaskAccidentModel
+import com.xw.yunwei.ui.task.create.LeftCategoryAdapter
+import com.xw.yunwei.ui.task.create.RightItemAdapter
+import com.xw.yunwei.utils.DialogFactory
+import com.xw.yunwei.utils.PictureSelectorFactory
+import kotlin.math.ceil
/**
- * 事故处理
+ * 事故处理页面
+ *
+ * 提供事故处理信息录入功能,包括:
+ * - 人员伤亡情况(死亡、重伤、轻伤)的增减操作
+ * - 责任判定选择(我方主责 / 我方无责 / 双方同责)
+ * - 现场情况与处置情况的多行文本描述
+ * - 三组图片上传(交警判责照片、现场情况照片、处置情况照片)
+ *
+ * 图片支持拍照和从图库选择两种方式,提交时先上传图片再调用接口。
*/
-class AccidentProcessActivity : BaseActivity<ActivityAccidentProcessBinding, AccidentProcessVM>(){
+class AccidentProcessActivity :
+ BaseBusinessActivity<ActivityAccidentProcessBinding, AccidentProcessVM>() {
+ /** 事故类型筛选弹窗 */
+ private var filterDialog: MaterialDialog? = null
+
+ /** 左侧事故大类 Adapter */
+ private lateinit var leftAdapter: LeftCategoryAdapter
+
+ /** 右侧事故子类 Adapter */
+ private lateinit var rightAdapter: RightItemAdapter
+
+ //用于测量
+ private val textPaint = TextPaint()
+
+ companion object {
+ //获取跳转该页面参数
+ fun getParams(model: TaskAccidentModel?): Bundle {
+ return bundleOf(
+ Key.ID to model?.id,
+ Key.DATA to model?.errorTypeList?.joinToString { it ->
+ (it.child ?: emptyList()).map { it.id }.joinToString()
+ }
+ )
+ }
+ }
+
override fun getBindingVariable() = BR.viewModel
override fun init() {
super.init()
- viewModel.taskId = intent.getLongExtra("taskId", 0L)
+ // 从Intent获取任务ID并保存到ViewModel
+ viewModel.taskId = intent.getLongExtra(Key.ID, 0L)
+ viewModel.taskTypeId = intent.getStringExtra(Key.DATA)
initAdapter()
+ // 移除默认选中状态,由用户手动选择责任判定
binding.stllZrpd.remove()
binding.stllZrpd.setData(
viewModel.dataZrpd,
@@ -40,10 +101,23 @@
resources.getColor(R.color.white),
"shape_blue_5_bg_4"
)
+ viewModel.getTypeList { refreshFilterData() }
}
override fun setListener() {
super.setListener()
+ binding.llFilters.setOnClickListener {
+ viewModel.getTypeList {
+ showFilterDialog()
+ }
+ }
+ // 点击事故类型筛选按钮,先拉取类型列表再弹窗
+ binding.tvAccidentFilter.setOnClickListener {
+ viewModel.getTypeList {
+ showFilterDialog()
+ }
+ }
+ // 责任判定标签点击监听:单选逻辑,先取消全部选中,再选中当前点击项
binding.stllZrpd.setListener {
for (index in binding.stllZrpd.selectIndexList) { // 先取消选中状态
binding.stllZrpd.onTvClick(index)
@@ -54,7 +128,13 @@
}
}
- private fun initAdapter(){
+ /**
+ * 初始化三组图片选择适配器
+ *
+ * 分别绑定到 rv1(交警判责照片)、rv2(现场情况照片)、rv3(处置情况照片),
+ * 每组最多上传 [AccidentProcessVM.maxSizes] 张图片。
+ */
+ private fun initAdapter() {
viewModel.adapters.clear()
viewModel.imageEvents.clear()
for (index in 0 until 3) {
@@ -96,34 +176,44 @@
binding.rv3.layoutManager = GridLayoutManager(this, 5)
}
+ /**
+ * 显示图片选择方式弹窗(拍照 / 图库)
+ */
private fun showTypeDialog() {
CommonDialog.showTypeDialog(this) {
if (it == 0) takeAPhotograph() else if (it == 1) enterGallery()
}
}
+ /**
+ * 进入图库选择图片
+ *
+ * 使用 PictureSelector 打开相册,最大可选数量为该组剩余可上传数量。
+ */
// 进入图库
@SuppressLint("SourceLockedOrientationActivity")
private fun enterGallery() {
- PictureSelector.create(this)
- .openGallery(SelectMimeType.ofImage())
- .setImageEngine(GlideEngine.createGlideEngine())
- .setMaxSelectNum(viewModel.maxSizes[viewModel.operateIndex] - viewModel.adapters[viewModel.operateIndex].data.size)
- .setImageSpanCount(4)
- .isPreviewImage(true)
- .isDisplayCamera(false)
- .setCompressEngine(PictureCompressEngine())
- .forResult(resultCallbackListener)
+ PictureSelectorFactory.enterGallery(
+ this,
+ viewModel.maxSizes[viewModel.operateIndex] - viewModel.adapters[viewModel.operateIndex].data.size,
+ resultCallbackListener
+ )
}
+ /**
+ * 调用系统相机拍照
+ */
// 拍照
private fun takeAPhotograph() {
- PictureSelector.create(this)
- .openCamera(SelectMimeType.ofImage())
- .setCompressEngine(PictureCompressEngine())
- .forResultActivity(resultCallbackListener)
+ PictureSelectorFactory.takeAPhotograph(this, resultCallbackListener)
}
+ /**
+ * 图片选择/拍照结果回调
+ *
+ * 将选中的图片路径转换为 [FileSelectBean] 并更新到当前操作组的适配器中。
+ * 若为 Content URI 且未裁剪/压缩,则通过 [UriUtils.uri2File] 转为本地绝对路径。
+ */
private var resultCallbackListener = object : OnResultCallbackListener<LocalMedia> {
override fun onResult(result: ArrayList<LocalMedia>?) {
result?.let { selectList ->
@@ -131,17 +221,199 @@
dataList.addAll(viewModel.adapters[viewModel.operateIndex].data)
for (item in selectList) {
val path: String = item.availablePath
- var imgPath = if (PictureMimeType.isContent(path) && !item.isCut && !item.isCompressed) {
- UriUtils.uri2File(Uri.parse(path)).absolutePath
- } else {
- path
- }
+ var imgPath =
+ if (PictureMimeType.isContent(path) && !item.isCut && !item.isCompressed) {
+ UriUtils.uri2File(Uri.parse(path)).absolutePath
+ } else {
+ path
+ }
dataList.add(FileSelectBean(localPath = imgPath, type = "img"))
}
viewModel.adapters[viewModel.operateIndex].setList(dataList)
}
}
+
override fun onCancel() {}
}
+ /**
+ * 显示事故类型筛选弹窗(底部 BottomSheet 样式)
+ *
+ * 左侧显示事故大类,右侧显示对应子类,支持多选。
+ * 弹窗 dismiss 时更新筛选按钮文案。
+ */
+ private fun showFilterDialog() {
+ if (filterDialog == null) {
+ filterDialog = DialogFactory.produce(this).apply {
+ customView(
+ com.xw.yunwei.R.layout.dialog_accident_filter,
+ noVerticalPadding = true,
+ horizontalPadding = false
+ )
+ cancelable(true)
+ cornerRadius(12f)
+ val bind: DialogAccidentFilterBinding? = DataBindingUtil.bind(getCustomView())
+ bind?.let {
+ setupRecyclerViews(it)
+ it.close.setOnClickListener { dismiss() }
+ // 左侧按钮:仅重置选中状态,不关闭弹窗
+ it.btnLeft.setOnClickListener {
+ viewModel.categories.forEach {
+ it.items.forEach {
+ it.isSelected = false
+ }
+ }
+ leftAdapter.selectedPosition = 0
+ rightAdapter.updateData(viewModel.categories[0].items)
+
+ }
+ // 右侧按钮:确认选择并关闭弹窗
+ it.btnRight.setOnClickListener {
+ if (viewModel.getSelectType().isEmpty()) {
+ ToastUtilCommon.showWarn("还未选择事故类型")
+ return@setOnClickListener
+ }
+ dismiss()
+ }
+ }
+ }
+
+ // 弹窗关闭时更新筛选按钮文案(已选则显示"选好了")
+ filterDialog!!.setOnDismissListener { refreshFilterData() }
+ }
+
+ filterDialog?.show()
+ // 关键:让软键盘把 BottomSheet 顶上去
+ filterDialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
+ filterDialog?.window?.setLayout(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ filterDialog?.window?.setGravity(Gravity.BOTTOM)
+ filterDialog?.window?.setWindowAnimations(R.style.AnimUp)
+ }
+
+ /**
+ * 初始化事故类型筛选弹窗中的左右 RecyclerView
+ *
+ * @param bind 弹窗视图绑定对象
+ */
+ private fun setupRecyclerViews(bind: DialogAccidentFilterBinding) {
+ bind.leftRecyclerView.layoutManager = LinearLayoutManager(this)
+ leftAdapter = LeftCategoryAdapter(viewModel.categories) { category, position ->
+ rightAdapter.updateData(category.items)
+ }
+ bind.leftRecyclerView.adapter = leftAdapter
+
+ bind.rightRecyclerView.layoutManager = LinearLayoutManager(this)
+ rightAdapter = RightItemAdapter(viewModel.categories[0].items)
+ bind.rightRecyclerView.adapter = rightAdapter
+ }
+
+ //刷新筛选数据
+ private fun refreshFilterData() {
+ val selectTypeName = viewModel.getSelectTypeName()
+ binding.llFilters.isVisible = selectTypeName.isNotEmpty()
+ binding.tvAccidentFilter.isVisible = selectTypeName.isEmpty()
+ binding.llFilters.removeAllViews()
+ if (selectTypeName.isNotEmpty()) {
+ binding.llFilters.post {
+ fill(binding.llFilters, binding.llFilters.width, selectTypeName)
+ }
+ }
+ }
+
+ //填充数据
+ private fun fill(parent: LinearLayout, parenWidth: Int, list: List<String>) {
+ val itemWidths = list.map { calculationItemViewWidth(it, 8, 4) }
+ val pair = findWrapIndex(parenWidth, itemWidths)
+ val numItemWidth = if (pair.second) {
+ calculationItemViewWidth("+${list.size - pair.first - 1}", 4, 0)
+ } else {
+ 0
+ }
+ val needWeight =
+ pair.second && pair.first == 0 && itemWidths.first() >= (parenWidth - numItemWidth)
+ list.subList(0, pair.first + 1).forEach {
+ parent.addView(getFilterItemView(it, 8, 4, if (needWeight) 1f else 0f))
+ }
+ if (pair.second) {
+ parent.addView(getFilterItemView("+${list.size - pair.first - 1}", 4, 0))
+ }
+ }
+
+ //查找合适的下标
+ private fun findWrapIndex(
+ parenWidth: Int,
+ list: List<Int>,
+ needLastNum: Boolean = true
+ ): Pair<Int, Boolean> {
+ val size = list.size
+ var itemWidthCount = 0
+ for ((index, itemWidth) in list.withIndex()) {
+ if (itemWidthCount + itemWidth == parenWidth) {
+ return Pair(index, false)
+ }
+ if (itemWidthCount + itemWidth > parenWidth) {
+ if (needLastNum) {
+ if (index == 0) {
+ return Pair(index, size > 1)
+ }
+ //末尾的计数
+ val numberItemWidth =
+ calculationItemViewWidth("+${size - index}", 4, 0)
+ //剩余内容宽度
+ val surplusContentWidth = parenWidth - numberItemWidth
+ //将剩余内容宽度带入,重新找适合的下标
+ val wrapIndex = findWrapIndex(surplusContentWidth, list, false)
+ return Pair(wrapIndex.first, true)
+ } else {
+ return Pair(index - 1, false)
+ }
+ }
+ itemWidthCount += itemWidth
+ }
+ return Pair(size - 1, false)
+ }
+
+ //计算item控件宽度
+ private fun calculationItemViewWidth(item: String, padHorizontal: Int, marginEnd: Int): Int {
+ textPaint.textSize = 12f.spToPx(this@AccidentProcessActivity)
+ val sl = StaticLayout.Builder.obtain(item, 0, item.length, textPaint, Int.MAX_VALUE)
+ .setIncludePad(false) // 看你期望要不要 TextView 默认那套 pad
+ .build()
+
+ val line0Width = sl.getLineWidth(0) // 这一行的“排版宽度”
+ val padWidth = padHorizontal.dpToPx(this) * 2//两侧内间距宽度
+ return ceil(line0Width + padWidth + marginEnd.dpToPx(this)).toInt()
+ }
+
+ //获取筛选item控件
+ private fun getFilterItemView(
+ item: String,
+ padHorizontal: Int,
+ marginEnd: Int,
+ weight: Float = 0f,
+ ): View {
+ return TextView(this).apply {
+ setBackgroundResource(com.xw.yunwei.R.drawable.shape_gray11_bg_4)
+ layoutParams = LinearLayout.LayoutParams(
+ if (weight > 0) 0 else LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ weight
+ ).apply {
+ this.marginEnd = marginEnd.dpToPx(this@AccidentProcessActivity)
+ }
+ setPadding(
+ padHorizontal.dpToPx(this@AccidentProcessActivity),
+ 4.dpToPx(this@AccidentProcessActivity),
+ padHorizontal.dpToPx(this@AccidentProcessActivity),
+ 4.dpToPx(this@AccidentProcessActivity),
+ )
+ setTextColor(R.color.gray_9.colorIdToColorValue(this@AccidentProcessActivity))
+ setTextSize(TypedValue.COMPLEX_UNIT_SP, 12f)
+ text = item
+ maxLines = 1
+ ellipsize = TextUtils.TruncateAt.END
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/task/accident/handle/AccidentProcessVM.kt b/app/src/main/java/com/xw/yunwei/ui/task/accident/handle/AccidentProcessVM.kt
index f963345..f4de6ee 100644
--- a/app/src/main/java/com/xw/yunwei/ui/task/accident/handle/AccidentProcessVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/task/accident/handle/AccidentProcessVM.kt
@@ -11,6 +11,8 @@
import com.xw.common.base.ImageSelectAdapter
import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.R
+import com.xw.yunwei.model.Category
+import com.xw.yunwei.model.Item
import com.xw.yunwei.net.CommonRepository
import com.xw.yunwei.net.TaskRepository
import com.xw.yunwei.ui.MainActivity
@@ -20,31 +22,74 @@
import okhttp3.RequestBody.Companion.asRequestBody
import org.koin.core.component.inject
import java.io.File
-import kotlin.getValue
+/**
+ * 事故处理页面 ViewModel
+ *
+ * 负责事故处理页面的业务逻辑与数据管理,包括:
+ * - 人员伤亡计数(死亡、重伤、轻伤)的 LiveData 维护与增减操作
+ * - 现场情况、处置情况文本及字数统计
+ * - 责任判定选项与选中状态
+ * - 三组图片适配器与图片事件监听的管理
+ * - 文件上传(递归上传本地图片到服务器)
+ * - 事故处理提交
+ */
class AccidentProcessVM(myApplication: Application) : BaseViewModel(myApplication) {
val commonRepository: CommonRepository by inject()
val taskRepository: TaskRepository by inject()
+ /** 当前任务ID */
var taskId = 0L
- val death = MutableLiveData("0") // 死
- val badlyHurt = MutableLiveData("0") // 重伤
- val minorInjuries = MutableLiveData("0") // 轻伤
- val siteDesc = MutableLiveData("") // 现场情况
- val disposalDesc = MutableLiveData("") // 处置情况
+
+ /**
+ * 任务类型ID 组id|子id1, 子id2, 子id3...
+ */
+ var taskTypeId: String? = null
+
+ /** 死亡人数 LiveData,默认 0 */
+ val death = MutableLiveData("0")
+
+ /** 重伤人数 LiveData,默认 0 */
+ val badlyHurt = MutableLiveData("0")
+
+ /** 轻伤人数 LiveData,默认 0 */
+ val minorInjuries = MutableLiveData("0")
+
+ /** 现场情况描述 LiveData */
+ val siteDesc = MutableLiveData("")
+
+ /** 处置情况描述 LiveData */
+ val disposalDesc = MutableLiveData("")
+
+ /** 现场情况当前字数 / 200 */
val siteNums = siteDesc.map { "${it.length}/200" }
+
+ /** 处置情况当前字数 / 200 */
val disposalNums = disposalDesc.map { "${it.length}/200" }
+ /** 责任判定选项列表 */
val dataZrpd = listOf("我方主责", "我方无责", "双方同责")
+
+ /** 当前选中的责任判定 */
var selectZrpd = ""
+ /** 三组图片选择适配器(对应交警判责、现场情况、处置情况) */
val adapters = mutableListOf<ImageSelectAdapter>()
+
+ /** 三组图片的事件监听器 */
val imageEvents = mutableListOf<ImageEventListener<FileSelectBean>>()
+
+ /** 每组图片最大可上传数量,默认均为 8 张 */
val maxSizes = listOf(8, 8, 8)
+
+ /** 当前正在操作的图片组下标(0/1/2),-1 表示未选择 */
var operateIndex = -1
+ /** 事故类型分类列表(大类 + 子类) */
+ var categories = mutableListOf<Category>()
+ /** 页面点击事件统一处理:增减人数按钮、提交按钮 */
var onClick = View.OnClickListener {
when (it.id) {
R.id.cut1 -> death.cut()
@@ -57,6 +102,17 @@
}
}
+ /**
+ * 提交事故处理信息
+ *
+ * 校验逻辑:
+ * 1. 必须选择责任判定
+ * 2. 必须上传交警判责照片
+ * 3. 现场情况(文字或照片)至少填一项
+ * 4. 处置情况(文字或照片)至少填一项
+ *
+ * 校验通过后先递归上传本地图片,再调用 [TaskRepository.handleVehicleAccident] 提交。
+ */
private fun submit() {
// if (selectZrpd.isEmpty()) {
// ToastUtilCommon.showWarn("请选择责任判断")
@@ -93,15 +149,25 @@
map["responsibleImage"] = "${adapters[0].data.map { it.url }}"
map["situationImage"] = "${adapters[1].data.map { it.url }}"
map["disposalImage"] = "${adapters[2].data.map { it.url }}"
+ map["taskTypeId"] = getSelectType()
taskRepository.handleVehicleAccident(map)
- ToastUtilCommon.showSuc("提交成功")
-
+ runOnMainThread { ToastUtilCommon.showSuc("提交成功,事故已归档") }
+ delay(500)
startActivity(MainActivity::class.java)
}
}
}
+ /**
+ * 递归上传本地图片文件到服务器
+ *
+ * 遍历 [files] 列表,找到第一个 [FileSelectBean.url] 为空的本地文件进行上传,
+ * 上传成功后将服务器返回的 URL 写入 [FileSelectBean.url],再继续递归处理下一个。
+ *
+ * @param files 待上传的文件列表
+ * @param succ 全部上传完成后的回调
+ */
private fun uploadFile(files: List<FileSelectBean>, succ: () -> Unit) {
val result = files.find { it.url.isEmpty() }
if (result == null) {
@@ -123,6 +189,11 @@
}
}
+ /**
+ * MutableLiveData<String> 扩展:人数减 1
+ *
+ * 当前值小于等于 0 时给出提示,不再递减。
+ */
fun MutableLiveData<String>.cut() {
val current = value?.toInt() ?: 0
if (current <= 0) {
@@ -132,6 +203,11 @@
}
}
+ /**
+ * MutableLiveData<String> 扩展:人数加 1
+ *
+ * 当前值大于等于 99 时给出提示,不再递增。
+ */
fun MutableLiveData<String>.add() {
val current = value?.toInt() ?: 0
if (current >= 99) {
@@ -140,4 +216,63 @@
value = (current + 1).toString()
}
}
+
+ /**
+ * 获取事故类型列表
+ *
+ * 若 [categories] 已存在则直接回调,否则通过网络请求拉取并转换数据结构。
+ *
+ * @param block 数据就绪后的回调(在主线程执行)
+ */
+ fun getTypeList(block: () -> Unit) {
+ if (categories.isNotEmpty()) {
+ block()
+ } else {
+ launchRequest {
+ taskRepository.getTypeList()?.also { it ->
+ runOnMainThread {
+ categories.clear()
+ it.mapIndexed { index, type ->
+ val items = mutableListOf<Item>()
+ type.child?.forEach {
+ items.add(Item(it.id ?: 0L, it.errorName ?: ""))
+ }
+ categories.add(Category(index, type.errorName ?: "", items))
+ }
+ val ids = taskTypeId?.split(", ") ?: emptyList()
+ categories.forEach { category ->
+ category.items.forEach {
+ it.isSelected = ids.contains(it.id.toString())
+ }
+ }
+ block()
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * 获取当前已选中的事故类型 ID 字符串
+ *
+ * 遍历所有分类的子项,过滤出 [Item.isSelected] 为 true 的项,
+ * 将其 ID 以逗号分隔拼接成字符串返回。
+ *
+ * @return 已选中事故类型 ID 的逗号分隔字符串,未选择时返回空串
+ */
+ fun getSelectType(): String {
+ val items = mutableListOf<Item>()
+ categories.forEach { items.addAll(it.items) }
+ return items.filter { it.isSelected }.map { it.id }.joinToString()
+ }
+
+ /**
+ * 获取当前已选中的事故类型 name 列表
+ *
+ */
+ fun getSelectTypeName(): List<String> {
+ val items = mutableListOf<Item>()
+ categories.forEach { items.addAll(it.items) }
+ return items.filter { it.isSelected }.map { it.name }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/task/create/CreateTaskActivity.kt b/app/src/main/java/com/xw/yunwei/ui/task/create/CreateTaskActivity.kt
index 731de58..c0f66e7 100644
--- a/app/src/main/java/com/xw/yunwei/ui/task/create/CreateTaskActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/task/create/CreateTaskActivity.kt
@@ -1,13 +1,19 @@
package com.xw.yunwei.ui.task.create
import android.annotation.SuppressLint
-import android.content.Intent
import android.net.Uri
import android.os.Bundle
+import android.text.StaticLayout
+import android.text.TextPaint
+import android.text.TextUtils
+import android.util.TypedValue
import android.view.Gravity
+import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
-import androidx.core.os.bundleOf
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
@@ -16,49 +22,71 @@
import com.afollestad.materialdialogs.customview.getCustomView
import com.amap.api.location.AMapLocation
import com.blankj.utilcode.util.UriUtils
-import com.luck.picture.lib.basic.PictureSelector
import com.luck.picture.lib.config.PictureMimeType
-import com.luck.picture.lib.config.SelectMimeType
import com.luck.picture.lib.entity.LocalMedia
import com.luck.picture.lib.interfaces.OnResultCallbackListener
import com.xw.common.CommonDialog
import com.xw.common.R
-import com.xw.common.base.BaseActivity
import com.xw.common.base.FileSelectBean
import com.xw.common.base.ImageEventListener
import com.xw.common.base.ImageSelectAdapter
import com.xw.common.base.ShowImgListDialog
-import com.xw.common.utils.BindUtils.getResColor
-import com.xw.common.utils.BindUtils.getUrl
-import com.xw.common.utils.GlideEngine
import com.xw.common.utils.GpsHelper
import com.xw.common.utils.KeyPreferences
import com.xw.common.utils.MMKVManager
-import com.xw.common.utils.PictureCompressEngine
import com.xw.common.utils.ToastUtilCommon
import com.xw.common.viewAdapter.ImageDefault
import com.xw.common.viewAdapter.ViewAdapter
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.databinding.ActivityCreateTaskBinding
import com.xw.yunwei.databinding.DialogAccidentFilterBinding
+import com.xw.yunwei.extension.colorIdToColorValue
+import com.xw.yunwei.extension.dpToPx
+import com.xw.yunwei.extension.spToPx
import com.xw.yunwei.model.CacheAccidentModel
import com.xw.yunwei.model.CarModel
-import com.xw.yunwei.ui.task.selectCar.SelectCarActivity
-import java.util.ArrayList
-import kotlin.text.ifEmpty
+import com.xw.yunwei.utils.DialogFactory
+import com.xw.yunwei.utils.PictureSelectorFactory
+import kotlin.math.ceil
/**
- * 事故上报
+ * 事故上报页面
+ *
+ * 提供事故工单创建功能,包括:
+ * - 车辆信息展示与选择(接收上一页传递的 [CarModel])
+ * - 高德定位获取当前位置地址
+ * - 事故类型多级筛选(左侧大类 + 右侧子类)
+ * - 任务紧急等级选择(P0 ~ P3)
+ * - 任务描述文字输入
+ * - 相关照片上传(拍照 / 图库)
+ * - 草稿缓存:返回时若已填写内容,提示是否保存到 MMKV
+ *
+ * 实现 [GpsHelper.OnMapLocation] 接口以接收定位结果。
*/
-class CreateTaskActivity : BaseActivity<ActivityCreateTaskBinding, CreateTaskVM>(), GpsHelper.OnMapLocation {
+class CreateTaskActivity : BaseBusinessActivity<ActivityCreateTaskBinding, CreateTaskVM>(),
+ GpsHelper.OnMapLocation {
override fun getBindingVariable() = BR.viewModel
+
+ /** 事故类型筛选弹窗 */
private var filterDialog: MaterialDialog? = null
+
+ /** 左侧事故大类 Adapter */
private lateinit var leftAdapter: LeftCategoryAdapter
+
+ /** 右侧事故子类 Adapter */
private lateinit var rightAdapter: RightItemAdapter
+ /** 高德定位辅助类 */
// lateinit var gpsHelper : GpsHelper
+ /** 从 MMKV 恢复的草稿数据 */
var cacheData: CacheAccidentModel? = null
+
+ //用于测量
+ private val textPaint = TextPaint()
+
override fun myCreate(savedInstanceState: Bundle?) {
super.myCreate(savedInstanceState)
+ // 尝试读取本地缓存的事故草稿数据
cacheData = MMKVManager.getInstance().getModel(KeyPreferences.ACCIDENT)
MMKVManager.getInstance().deleteModel(KeyPreferences.ACCIDENT)
// gpsHelper = GpsHelper(
@@ -75,6 +103,7 @@
super.init()
initAdapter()
val selectCar = intent.getParcelableExtra<CarModel>("car")
+ // 若存在缓存草稿,则恢复相关字段;否则仅设置选中的车辆
cacheData?.let {
// viewModel.selectCar.value = it.car
viewModel.selectCar.value = selectCar
@@ -83,8 +112,8 @@
viewModel.taskLevel.value = it.taskLevel
viewModel.taskDesc.value = it.taskDesc
viewModel.adapter.setList(it.files)
- binding.tvAccidentFilter.text = if (viewModel.getSelectType().isEmpty()) "" else "选好了"
- } ?: run{ viewModel.selectCar.value = selectCar }
+ refreshFilterData()
+ } ?: run { viewModel.selectCar.value = selectCar }
// if (viewModel.selectCar.value == null) {
// startActivityForResult(
@@ -93,15 +122,20 @@
// bundleOf("car" to null)
// )
// }
+ // 有缓存但定位为空时,重新发起定位
// if (cacheData != null && viewModel.location.value == null) {
// gpsHelper.startLocation()
// }
viewModel.getVehicleLocation()
+
+ // 检查任务等级选项文字是否重叠,重叠则将横向内边距减半
+ binding.root.post { adjustLevelPaddingIfOverlap() }
}
override fun setObservable() {
super.setObservable()
- viewModel.selectCar.observe(this){
+ // 监听选中车辆变化,更新车辆信息布局
+ viewModel.selectCar.observe(this) {
initCarLayout(it)
}
viewModel.carLocationInfo.observe(this) {
@@ -111,13 +145,24 @@
override fun setListener() {
super.setListener()
+ binding.llFilters.setOnClickListener {
+ viewModel.getTypeList {
+ showFilterDialog()
+ }
+ }
+ // 点击事故类型筛选按钮,先拉取类型列表再弹窗
binding.tvAccidentFilter.setOnClickListener {
- viewModel.getTypeList{
+ viewModel.getTypeList {
showFilterDialog()
}
}
}
+ /**
+ * 初始化图片选择适配器
+ *
+ * 绑定单组图片 RecyclerView,最大数量由 [CreateTaskVM.maxSize] 控制。
+ */
private fun initAdapter() {
val imageEvent = object : ImageEventListener<FileSelectBean>() {
override fun addImage(item: FileSelectBean) {
@@ -130,9 +175,7 @@
imgList.add(item1.localPath.ifEmpty { item1.url })
}
ShowImgListDialog(
- this@CreateTaskActivity,
- imgList,
- imgList.indexOf(item.localPath)
+ this@CreateTaskActivity, imgList, imgList.indexOf(item.localPath)
).show()
}
@@ -145,34 +188,41 @@
binding.rv.layoutManager = GridLayoutManager(this, 5)
}
+ /**
+ * 显示图片选择方式弹窗(拍照 / 图库)
+ */
private fun showTypeDialog() {
CommonDialog.showTypeDialog(this) {
if (it == 0) takeAPhotograph() else if (it == 1) enterGallery()
}
}
+ /**
+ * 进入图库选择图片
+ *
+ * 使用 PictureSelector 打开相册,最大可选数量为剩余可上传数量。
+ */
// 进入图库
@SuppressLint("SourceLockedOrientationActivity")
private fun enterGallery() {
- PictureSelector.create(this)
- .openGallery(SelectMimeType.ofImage())
- .setImageEngine(GlideEngine.createGlideEngine())
- .setMaxSelectNum(viewModel.maxSize - viewModel.adapter.data.size)
- .setImageSpanCount(4)
- .isPreviewImage(true)
- .isDisplayCamera(false)
- .setCompressEngine(PictureCompressEngine())
- .forResult(resultCallbackListener)
+ PictureSelectorFactory.enterGallery(
+ this, viewModel.maxSize - viewModel.adapter.data.size, resultCallbackListener
+ )
}
+ /**
+ * 调用系统相机拍照
+ */
// 拍照
private fun takeAPhotograph() {
- PictureSelector.create(this)
- .openCamera(SelectMimeType.ofImage())
- .setCompressEngine(PictureCompressEngine())
- .forResultActivity(resultCallbackListener)
+ PictureSelectorFactory.takeAPhotograph(this, resultCallbackListener)
}
+ /**
+ * 图片选择/拍照结果回调
+ *
+ * 将选中的图片路径转为 [FileSelectBean] 并追加到现有数据列表中。
+ */
private var resultCallbackListener = object : OnResultCallbackListener<LocalMedia> {
override fun onResult(result: ArrayList<LocalMedia>?) {
result?.let { selectList ->
@@ -180,11 +230,12 @@
dataList.addAll(viewModel.adapter.data)
for (item in selectList) {
val path: String = item.availablePath
- var imgPath = if (PictureMimeType.isContent(path) && !item.isCut && !item.isCompressed) {
- UriUtils.uri2File(Uri.parse(path)).absolutePath
- } else {
- path
- }
+ var imgPath =
+ if (PictureMimeType.isContent(path) && !item.isCut && !item.isCompressed) {
+ UriUtils.uri2File(Uri.parse(path)).absolutePath
+ } else {
+ path
+ }
dataList.add(FileSelectBean(localPath = imgPath, type = "img"))
}
viewModel.adapter.setList(dataList)
@@ -194,9 +245,15 @@
override fun onCancel() {}
}
+ /**
+ * 显示事故类型筛选弹窗(底部 BottomSheet 样式)
+ *
+ * 左侧显示事故大类,右侧显示对应子类,支持多选。
+ * 弹窗 dismiss 时更新筛选按钮文案。
+ */
private fun showFilterDialog() {
if (filterDialog == null) {
- filterDialog = MaterialDialog(this).apply {
+ filterDialog = DialogFactory.produce(this).apply {
customView(
com.xw.yunwei.R.layout.dialog_accident_filter,
noVerticalPadding = true,
@@ -207,16 +264,8 @@
val bind: DialogAccidentFilterBinding? = DataBindingUtil.bind(getCustomView())
bind?.let {
setupRecyclerViews(it)
- it.cancel.setOnClickListener {
- viewModel.categories.forEach {
- it.items.forEach {
- it.isSelected = false
- }
- }
- leftAdapter.selectedPosition = 0
- rightAdapter.updateData(viewModel.categories[0].items)
- dismiss()
- }
+ it.close.setOnClickListener { dismiss() }
+ // 左侧按钮:仅重置选中状态,不关闭弹窗
it.btnLeft.setOnClickListener {
viewModel.categories.forEach {
it.items.forEach {
@@ -227,15 +276,9 @@
rightAdapter.updateData(viewModel.categories[0].items)
}
+ // 右侧按钮:确认选择并关闭弹窗
it.btnRight.setOnClickListener {
- if(viewModel.getSelectType().isEmpty()){
- ToastUtilCommon.showWarn("还未选择事故类型")
- return@setOnClickListener
- }
- dismiss()
- }
- it.sure.setOnClickListener {
- if(viewModel.getSelectType().isEmpty()){
+ if (viewModel.getSelectType().isEmpty()) {
ToastUtilCommon.showWarn("还未选择事故类型")
return@setOnClickListener
}
@@ -244,9 +287,8 @@
}
}
- filterDialog!!.setOnDismissListener {
- binding.tvAccidentFilter.text = if(viewModel.getSelectType().isEmpty()) "" else "选好了"
- }
+ // 弹窗关闭时更新筛选按钮文案(已选则显示"选好了")
+ filterDialog!!.setOnDismissListener { refreshFilterData() }
}
filterDialog?.show()
@@ -260,6 +302,11 @@
}
+ /**
+ * 初始化事故类型筛选弹窗中的左右 RecyclerView
+ *
+ * @param bind 弹窗视图绑定对象
+ */
private fun setupRecyclerViews(bind: DialogAccidentFilterBinding) {
bind.leftRecyclerView.layoutManager = LinearLayoutManager(this)
leftAdapter = LeftCategoryAdapter(viewModel.categories) { category, position ->
@@ -273,64 +320,41 @@
}
+ /**
+ * 初始化车辆信息展示布局
+ *
+ * 根据 [CarModel] 加载车辆图片、车牌号、车身编码、运营状态等。
+ * 运营状态对应不同颜色:
+ * - 1 = 运营中(蓝色)
+ * - 2 = 维修中(红色)
+ * - 3 = 已收车(灰色)
+ * - 4 = 车辆异常(橙色)
+ *
+ * @param item 当前选中的车辆信息
+ */
@SuppressLint("SetTextI18n")
- private fun initCarLayout(item: CarModel){
- var url = ""
- try {
- url = item.vehiclePictures?.getUrl() ?: ""
- } catch (e: Exception) {
- }
- ViewAdapter.loadImage(binding.icon, ImageDefault(url, com.xw.yunwei.R.mipmap.img_work_car))
+ private fun initCarLayout(item: CarModel) {
+ ViewAdapter.loadImage(
+ binding.icon,
+ ImageDefault(item.getShowVehiclePicture(), com.xw.yunwei.R.mipmap.img_work_car)
+ )
binding.name.text = item.plateNumber
- binding.color.text = "${item.vehicleColor} | 车身编码:${item.vehicleCode}"
-
- val setStatus: (Int, Int) -> Unit = { text, bg ->
- binding.status.setTextColor(text)
- binding.status.setBackgroundResource(bg)
- }
-
- // 1=运营中 2=维修中 3=已收车 4=车辆异常
- when (item.operatingStatus) {
- 1 -> {
- setStatus(
- getResColor(R.color.blue_5),
- R.color.blue_1
- )
- binding.status.text = "运营中"
- }
-
- 2 -> {
- setStatus(
- getResColor(R.color.red_5),
- R.color.red_1
- )
- binding.status.text = "维修中"
- }
-
- 3 -> {
- setStatus(
- getResColor(R.color.gray_7),
- R.color.gray_3
- )
- binding.status.text = "已收车"
- }
-
- 4 -> {
- setStatus(
- getResColor(R.color.orange_5),
- R.color.orange_1
- )
- binding.status.text = "车辆异常"
- }
- }
+ binding.color.text = "${item.vehicleColor} | 车身编码:${item.getShowVehicleCode(6)}"
+ binding.status.setTextColor(item.getShowStatusTextColor().colorIdToColorValue(this))
+ binding.status.setBackgroundResource(item.getShowStatusBgResource())
+ binding.status.text=item.getShowStatus()
}
+ /**
+ * 高德定位结果回调
+ *
+ * 定位失败时提示用户开启 GPS 权限;定位成功则将地址保存到 [CreateTaskVM.location]。
+ *
+ * @param pLocation 定位结果,null 表示定位失败
+ */
override fun location(pLocation: AMapLocation?) {
if (pLocation == null) {
- CommonDialog.showTipsDialog(
- this@CreateTaskActivity,
- "您未开启gps权限,无法获取当前定位,请打开后重新操作",
- null)
+ CommonDialog.showLocationNotGrantedTipsDialog(this@CreateTaskActivity)
} else {
//viewModel.location.value = pLocation
}
@@ -351,13 +375,22 @@
// }
// }
+ /**
+ * 返回键拦截处理
+ *
+ * 若当前页面已填写事故相关内容,弹出确认框询问是否保存草稿到 MMKV;
+ * 未填写则直接返回。
+ */
override fun onBackPressedHandel() {
val cacheData = viewModel.getDataWrite()
if (cacheData == null) {
super.onBackPressedHandel()
} else {
CommonDialog.showTipsDialog(
- this, "是否保存当前事故数据", "不保存", "保存",
+ this,
+ "保存当前已填写内容,更换车辆后将不用重新填写,是否保存?",
+ "不保存",
+ "保存",
leftBlock = {
super.onBackPressedHandel()
true
@@ -369,4 +402,127 @@
})
}
}
+
+ //刷新筛选数据
+ private fun refreshFilterData() {
+ val selectTypeName = viewModel.getSelectTypeName()
+ binding.llFilters.isVisible = selectTypeName.isNotEmpty()
+ binding.tvAccidentFilter.isVisible = selectTypeName.isEmpty()
+ binding.llFilters.removeAllViews()
+ if (selectTypeName.isNotEmpty()) {
+ binding.llFilters.post {
+ fill(binding.llFilters, binding.llFilters.width, selectTypeName)
+ }
+ }
+ }
+
+ //填充数据
+ private fun fill(parent: LinearLayout, parenWidth: Int, list: List<String>) {
+ val itemWidths = list.map { calculationItemViewWidth(it, 8, 4) }
+ val pair = findWrapIndex(parenWidth, itemWidths)
+ val numItemWidth = if (pair.second) {
+ calculationItemViewWidth("+${list.size - pair.first - 1}", 4, 0)
+ } else {
+ 0
+ }
+ val needWeight =
+ pair.second && pair.first == 0 && itemWidths.first() >= (parenWidth - numItemWidth)
+ list.subList(0, pair.first + 1).forEach {
+ parent.addView(getFilterItemView(it, 8, 4, if (needWeight) 1f else 0f))
+ }
+ if (pair.second) {
+ parent.addView(getFilterItemView("+${list.size - pair.first - 1}", 4, 0))
+ }
+ }
+
+ //查找合适的下标
+ private fun findWrapIndex(
+ parenWidth: Int,
+ list: List<Int>,
+ needLastNum: Boolean = true
+ ): Pair<Int, Boolean> {
+ val size = list.size
+ var itemWidthCount = 0
+ for ((index, itemWidth) in list.withIndex()) {
+ if (itemWidthCount + itemWidth == parenWidth) {
+ return Pair(index, false)
+ }
+ if (itemWidthCount + itemWidth > parenWidth) {
+ if (needLastNum) {
+ if (index == 0) {
+ return Pair(index, size > 1)
+ }
+ //末尾的计数
+ val numberItemWidth =
+ calculationItemViewWidth("+${size - index}", 4, 0)
+ //剩余内容宽度
+ val surplusContentWidth = parenWidth - numberItemWidth
+ //将剩余内容宽度带入,重新找适合的下标
+ val wrapIndex = findWrapIndex(surplusContentWidth, list, false)
+ return Pair(wrapIndex.first, true)
+ } else {
+ return Pair(index - 1, false)
+ }
+ }
+ itemWidthCount += itemWidth
+ }
+ return Pair(size - 1, false)
+ }
+
+ //计算item控件宽度
+ private fun calculationItemViewWidth(item: String, padHorizontal: Int, marginEnd: Int): Int {
+ textPaint.textSize = 12f.spToPx(this@CreateTaskActivity)
+ val sl = StaticLayout.Builder.obtain(item, 0, item.length, textPaint, Int.MAX_VALUE)
+ .setIncludePad(false) // 看你期望要不要 TextView 默认那套 pad
+ .build()
+
+ val line0Width = sl.getLineWidth(0) // 这一行的“排版宽度”
+ val padWidth = padHorizontal.dpToPx(this) * 2//两侧内间距宽度
+ return ceil(line0Width + padWidth + marginEnd.dpToPx(this)).toInt()
+ }
+
+ //获取筛选item控件
+ private fun getFilterItemView(
+ item: String,
+ padHorizontal: Int,
+ marginEnd: Int,
+ weight: Float = 0f,
+ ): View {
+ return TextView(this).apply {
+ setBackgroundResource(com.xw.yunwei.R.drawable.shape_gray11_bg_4)
+ layoutParams = LinearLayout.LayoutParams(
+ if (weight > 0) 0 else LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ weight
+ ).apply {
+ this.marginEnd = marginEnd.dpToPx(this@CreateTaskActivity)
+ }
+ setPadding(
+ padHorizontal.dpToPx(this@CreateTaskActivity),
+ 4.dpToPx(this@CreateTaskActivity),
+ padHorizontal.dpToPx(this@CreateTaskActivity),
+ 4.dpToPx(this@CreateTaskActivity),
+ )
+ setTextColor(R.color.gray_9.colorIdToColorValue(this@CreateTaskActivity))
+ setTextSize(TypedValue.COMPLEX_UNIT_SP, 12f)
+ text = item
+ maxLines = 1
+ ellipsize = TextUtils.TruncateAt.END
+ }
+ }
+
+ private fun adjustLevelPaddingIfOverlap() {
+ val levels = listOf(binding.level0 /*, binding.level1, binding.level2*/)
+ val hasOverlap = levels.any { level ->
+ val leftTv = level.getChildAt(0) as TextView
+ val rightTv = level.getChildAt(1) as TextView
+ rightTv.left - leftTv.right < 5.dpToPx(this)
+ }
+ if (hasOverlap) {
+ val halfPadding = 8.dpToPx(this)
+ levels.forEach {
+ it.setPadding(halfPadding, it.paddingTop, halfPadding, it.paddingBottom)
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/task/create/CreateTaskVM.kt b/app/src/main/java/com/xw/yunwei/ui/task/create/CreateTaskVM.kt
index 4878426..6bd042b 100644
--- a/app/src/main/java/com/xw/yunwei/ui/task/create/CreateTaskVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/task/create/CreateTaskVM.kt
@@ -27,26 +27,44 @@
import org.koin.core.component.inject
import java.io.File
+/**
+ * 事故上报页面 ViewModel
+ *
+ * 负责事故工单创建的业务逻辑与数据管理,包括:
+ * - 车辆信息、定位地址、事故类型、任务等级、任务描述的 LiveData 维护
+ * - 图片选择适配器管理
+ * - 事故类型列表的获取与缓存
+ * - 本地图片递归上传到服务器
+ * - 提交事故工单并通知首页/任务页切换 Tab
+ * - 草稿数据组装与恢复
+ */
class CreateTaskVM(myApplication: Application) : BaseViewModel(myApplication) {
val workRepository: WorkRepository by inject()
val taskRepository: TaskRepository by inject()
val commonRepository: CommonRepository by inject()
+ /** 事故类型分类列表(大类 + 子类) */
var categories = mutableListOf<Category>()
+ /** 当前选中的车辆信息 */
var selectCar: MutableLiveData<CarModel> = MutableLiveData()
-
+ /** 当前定位信息,null 表示未获取到定位 */
// var location: MutableLiveData<AMapLocation?> = MutableLiveData(null)
+ /** 根据定位信息转换的地址文案,未定位时显示"定位中..." */
// val address = location.map {
// it?.address ?: "定位中..."
// }
- // 0 = P0(最紧急), 1 = P1 , 2 = P2 , 3 = P3(最不紧急)
+ /** 任务紧急等级:0 = P0(最紧急), 1 = P1 , 2 = P2 , 3 = P3(最不紧急),默认 P3 */
val taskLevel: MutableLiveData<Int> = MutableLiveData(2)
+
+ /** 任务描述文本 */
val taskDesc = MutableLiveData("")
//车辆实时位置信息
val carLocationInfo = MutableLiveData<VehicleLocationInfo?>()
+
+ /** 页面点击事件统一处理:选择车辆、等级切换、提交 */
var onClick = View.OnClickListener {
when (it.id) {
R.id.imgSelectCar -> {
@@ -65,9 +83,26 @@
}
}
+ /** 图片选择适配器 */
lateinit var adapter: ImageSelectAdapter
+
+ /** 图片最大可上传数量 */
val maxSize = 6
+ /**
+ * 提交事故上报信息
+ *
+ * 校验逻辑:
+ * 1. 必须选择车辆
+ * 2. 必须获取到定位
+ * 3. 必须选择事故类型
+ * 4. 必须选择任务等级(0~3)
+ * 5. 必须填写任务描述
+ * 6. 必须上传相关照片
+ *
+ * 校验通过后先递归上传本地图片,再调用 [TaskRepository.saveVehicleAccident] 提交。
+ * 提交成功后通过 EventBus 通知首页切换到任务 Tab 并关闭当前页面。
+ */
fun submit() {
if (selectCar.value == null) {
ToastUtilCommon.showWarn("请选择车辆")
@@ -116,6 +151,15 @@
}
+ /**
+ * 递归上传本地图片文件到服务器
+ *
+ * 遍历 [files] 列表,找到第一个 [FileSelectBean.url] 为空的本地文件进行上传,
+ * 上传成功后将服务器返回的 URL 写入 [FileSelectBean.url],再继续递归处理下一个。
+ *
+ * @param files 待上传的文件列表
+ * @param succ 全部上传完成后的回调
+ */
private fun uploadFile(files: List<FileSelectBean>, succ: () -> Unit) {
val result = files.find { it.url.isEmpty() }
if (result == null) {
@@ -137,6 +181,13 @@
}
}
+ /**
+ * 获取事故类型列表
+ *
+ * 若 [categories] 已存在则直接回调,否则通过网络请求拉取并转换数据结构。
+ *
+ * @param block 数据就绪后的回调(在主线程执行)
+ */
fun getTypeList(block: () -> Unit) {
if (categories.isNotEmpty()) {
block()
@@ -154,12 +205,38 @@
}
}
+ /**
+ * 获取当前已选中的事故类型 ID 字符串
+ *
+ * 遍历所有分类的子项,过滤出 [Item.isSelected] 为 true 的项,
+ * 将其 ID 以逗号分隔拼接成字符串返回。
+ *
+ * @return 已选中事故类型 ID 的逗号分隔字符串,未选择时返回空串
+ */
fun getSelectType(): String {
val items = mutableListOf<Item>()
categories.forEach { items.addAll(it.items) }
return items.filter { it.isSelected }.map { it.id }.joinToString()
}
+ /**
+ * 获取当前已选中的事故类型 name 列表
+ *
+ */
+ fun getSelectTypeName(): List<String> {
+ val items = mutableListOf<Item>()
+ categories.forEach { items.addAll(it.items) }
+ return items.filter { it.isSelected }.map { it.name }
+ }
+
+ /**
+ * 获取当前数据填写情况,用于判断是否需要保存草稿
+ *
+ * 当事故类型、任务等级、任务描述、相关照片均未填写时返回 null,
+ * 否则返回包含当前页面数据的 [CacheAccidentModel]。
+ *
+ * @return 当前页面缓存数据,或 null 表示未填写任何内容
+ */
/*获取数据填写情况*/
fun getDataWrite(): CacheAccidentModel? {
// 事故类型/任务等级/任务描述/相关照片 暂时定义为这几个填了就算填了事故
diff --git a/app/src/main/java/com/xw/yunwei/ui/task/create/LeftCategoryAdapter.kt b/app/src/main/java/com/xw/yunwei/ui/task/create/LeftCategoryAdapter.kt
index 7c516d4..adcd27d 100644
--- a/app/src/main/java/com/xw/yunwei/ui/task/create/LeftCategoryAdapter.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/task/create/LeftCategoryAdapter.kt
@@ -10,11 +10,21 @@
import com.xw.yunwei.R
import com.xw.yunwei.model.Category
+/**
+ * 事故类型筛选左侧大类 Adapter
+ *
+ * 用于事故上报页面的底部筛选弹窗,展示事故类型的大类列表(如剐蹭、碰撞等)。
+ * 支持单选高亮效果:选中项白色背景 + 蓝色文字,未选中项灰色背景 + 深灰文字。
+ *
+ * @param categories 大类数据列表
+ * @param onItemClick 大类点击回调,参数为当前选中的 [Category] 及其下标
+ */
class LeftCategoryAdapter(
private var categories: List<Category>,
private val onItemClick: (Category, Int) -> Unit
) : RecyclerView.Adapter<LeftCategoryAdapter.ViewHolder>() {
+ /** 当前选中的大类下标,修改后会自动刷新列表 */
var selectedPosition = 0
@SuppressLint("NotifyDataSetChanged")
set(value) {
@@ -22,6 +32,11 @@
notifyDataSetChanged()
}
+ /**
+ * 左侧大类 ViewHolder
+ *
+ * @property tvCategory 大类名称文本控件
+ */
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val tvCategory: TextView = itemView.findViewById(R.id.tvLeft)
}
@@ -35,7 +50,7 @@
val category = categories[position]
holder.tvCategory.text = category.name
- // 设置选中效果
+ // 设置选中效果:选中为白色背景 + 蓝色文字,未选中为灰色背景 + 深灰文字
if (selectedPosition == position) {
holder.tvCategory.setBackgroundResource(R.color.white)
holder.tvCategory.setTextColor(getResColor(com.xw.common.R.color.blue_5))
@@ -44,6 +59,7 @@
holder.tvCategory.setTextColor(getResColor(com.xw.common.R.color.gray_9))
}
+ // 点击后更新选中状态并通知右侧刷新子类数据
holder.itemView.setOnClickListener {
val previousSelected = selectedPosition
selectedPosition = position
diff --git a/app/src/main/java/com/xw/yunwei/ui/task/create/RightItemAdapter.kt b/app/src/main/java/com/xw/yunwei/ui/task/create/RightItemAdapter.kt
index 1afa7a6..512d358 100644
--- a/app/src/main/java/com/xw/yunwei/ui/task/create/RightItemAdapter.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/task/create/RightItemAdapter.kt
@@ -11,11 +11,25 @@
import com.xw.yunwei.model.Item
import kotlin.collections.filter
+/**
+ * 事故类型筛选右侧子类 Adapter
+ *
+ * 用于事故上报页面的底部筛选弹窗,展示当前选中大类下的具体子项列表。
+ * 支持多选效果:选中项蓝色背景 + 蓝色文字,未选中项透明背景 + 深灰文字。
+ *
+ * @param items 子类数据列表
+ * @param onItemClick 子项点击回调,参数为当前点击的 [Item] 及其下标,可为 null
+ */
class RightItemAdapter(
private var items: List<Item>,
private val onItemClick: ((Item, Int) -> Unit)? = null
) : RecyclerView.Adapter<RightItemAdapter.ViewHolder>() {
+ /**
+ * 右侧子类 ViewHolder
+ *
+ * @property tvItem 子项名称文本控件
+ */
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val tvItem: TextView = itemView.findViewById(R.id.tvRight)
}
@@ -30,7 +44,7 @@
val item = items[position]
holder.tvItem.text = item.name
- // 设置选中效果
+ // 设置选中效果:选中为蓝色圆角背景 + 蓝色文字,未选中为半透明背景 + 深灰文字
if (item.isSelected) {
holder.tvItem.setBackgroundResource(R.drawable.shape_blue_1_bg_4)
holder.tvItem.setTextColor(getResColor(com.xw.common.R.color.blue_5))
@@ -39,6 +53,7 @@
holder.tvItem.setTextColor(getResColor(com.xw.common.R.color.gray_9))
}
+ // 点击切换选中状态并局部刷新
holder.itemView.setOnClickListener {
// 切换选中状态
item.isSelected = !item.isSelected
@@ -49,12 +64,24 @@
override fun getItemCount() = items.size
+ /**
+ * 更新子类数据并刷新列表
+ *
+ * 通常在左侧大类切换时调用,用于展示新选中大类对应的子项。
+ *
+ * @param newItems 新的子类数据列表
+ */
@SuppressLint("NotifyDataSetChanged")
fun updateData(newItems: List<Item>) {
items = newItems
notifyDataSetChanged()
}
+ /**
+ * 获取当前已选中的子项列表
+ *
+ * @return 所有 [Item.isSelected] 为 true 的子项
+ */
fun getSelectedItems(): List<Item> {
return items.filter { it.isSelected }
}
diff --git a/app/src/main/java/com/xw/yunwei/ui/task/list/TaskListAdapter.kt b/app/src/main/java/com/xw/yunwei/ui/task/list/TaskListAdapter.kt
index 5fc5dea..d7ae46a 100644
--- a/app/src/main/java/com/xw/yunwei/ui/task/list/TaskListAdapter.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/task/list/TaskListAdapter.kt
@@ -4,14 +4,13 @@
import android.os.Handler
import android.os.Looper
import android.os.Message
+import android.view.View
import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.RecyclerView
import com.amap.api.maps.model.LatLng
-import com.blankj.utilcode.util.TimeUtils
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
-import com.xw.common.TimeDialog.Companion.getTime
import com.xw.common.base.TwoItemElementClickListener
import com.xw.common.utils.BindUtils.getResColor
import com.xw.common.utils.CalculatorLineDistance
@@ -20,32 +19,54 @@
import com.xw.yunwei.R
import com.xw.yunwei.databinding.ItemTaskContentBinding
import com.xw.yunwei.model.TaskModel
+import com.xw.yunwei.model.taskPlaceHolder
import java.time.Duration
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
-import java.util.concurrent.TimeUnit
import java.util.concurrent.ConcurrentHashMap
+import java.util.concurrent.TimeUnit
import kotlin.math.max
+/**
+ * 任务列表适配器
+ *
+ * 负责展示任务列表项,支持以下功能:
+ * - 根据任务紧急程度显示不同等级图标
+ * - 对事故类待到达任务进行倒计时展示
+ * - 根据当前定位计算与车辆距离,控制"到达现场"按钮可用状态
+ * - 支持列表项点击、操作按钮点击及导航点击事件
+ *
+ * @property listener 列表项及子元素点击事件回调
+ */
class TaskListAdapter(var listener: TwoItemElementClickListener<TaskModel>) :
BaseQuickAdapter<TaskModel, BaseViewHolder>(R.layout.item_task_content) {
+ /** 当前纬度,用于计算与任务车辆的距离 */
var lat: Double = 0.0
+
+ /** 当前经度,用于计算与任务车辆的距离 */
var lng: Double = 0.0
+ /**
+ * 设置当前定位坐标
+ *
+ * @param lat 纬度,为空时默认为 0.0
+ * @param lng 经度,为空时默认为 0.0
+ * @param refresh 是否立即刷新列表,默认为 true
+ */
@SuppressLint("NotifyDataSetChanged")
fun setLocation(lat: Double?, lng: Double?, refresh: Boolean = true) {
this.lat = lat ?: 0.0
this.lng = lng ?: 0.0
if (refresh) {
- recyclerView.post { notifyDataSetChanged() }
+ notifyDataSetChanged()
}
}
- // 记录需要倒计时的holder,key为holder.hashCode()
+ /** 记录需要倒计时的 holder,key 为 holder.hashCode(),用于每秒刷新倒计时 UI */
private val countdownHolders = ConcurrentHashMap<Int, ItemTaskContentBinding>()
- // 倒计时Handler
+ /** 倒计时 Handler,主线程每秒发送消息更新所有可见倒计时 */
private val countdownHandler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
if (msg.what == MSG_COUNTDOWN) {
@@ -61,17 +82,27 @@
}
/**
- * 更新所有可见的倒计时
+ * 更新所有可见项的倒计时 UI
+ *
+ * 遍历当前已注册的倒计时 holder,计算剩余时间并更新显示;
+ * 若倒计时结束(时分秒均为 0),则标记为"已超时"并从注册表中移除。
*/
private fun updateAllCountdowns() {
+ if (!recyclerView.isAttachedToWindow) {
+ return
+ }
val timeComplete = mutableListOf<Int>()
countdownHolders.forEach { (code, binding) ->
+ if (!binding.root.isAttachedToWindow) {
+ return@forEach
+ }
// 获取当前绑定的数据
val position = binding.root.tag as? Int ?: return@forEach
val item = getItemOrNull(position) ?: return@forEach
- if (item.status == 0 && item.taskCategory == 2) {
+ // 仅对待到达状态(status=0)的事故任务(taskCategory=2)进行倒计时
+ if ((item.status == 0 || item.status == 4) && item.taskCategory == 2) {
val list = calculateTimeDifference(item.endTime)
updateTime(binding, list)
if (list.all { it == 0L }) { // 全0 此项移除
@@ -81,6 +112,7 @@
}
}
+ // 移除已超时的 holder,避免无效刷新
timeComplete.forEach {
countdownHolders.remove(it)
}
@@ -88,6 +120,8 @@
/**
* 开始倒计时循环
+ *
+ * 发送倒计时消息,触发每秒刷新机制。
*/
fun startCountdown() {
countdownHandler.removeMessages(MSG_COUNTDOWN)
@@ -96,6 +130,8 @@
/**
* 停止倒计时循环
+ *
+ * 移除 Handler 中待处理的倒计时消息。
*/
fun stopCountdown() {
countdownHandler.removeMessages(MSG_COUNTDOWN)
@@ -103,10 +139,21 @@
@SuppressLint("SetTextI18n")
override fun convert(holder: BaseViewHolder, item: TaskModel) {
+ if (!recyclerView.isAttachedToWindow) {
+ return
+ }
+ if (holder.bindingAdapterPosition == RecyclerView.NO_POSITION) {
+ return
+ }
DataBindingUtil.bind<ItemTaskContentBinding>(holder.itemView)?.let { bind ->
- // 保存position到tag,用于后续更新时获取数据
+ // 保存 position 到 tag,用于后续更新时获取数据
bind.root.tag = holder.bindingAdapterPosition
-
+ bind.clContent.visibility = if (item == taskPlaceHolder) View.GONE else View.VISIBLE
+ bind.tips.visibility = if (item == taskPlaceHolder) View.VISIBLE else View.GONE
+ if (item == taskPlaceHolder) {
+ return
+ }
+ // 根据任务紧急程度设置左侧等级图标
val levelId = when (item.taskUrgencyLevel) {
0 -> R.mipmap.ic_task_item_left_one
1 -> R.mipmap.ic_task_item_left_two
@@ -116,30 +163,51 @@
}
levelId?.let { bind.level.setImageResource(levelId) }
- if (item.status == 0 && item.taskCategory == 2) {
+ // 事故类待到达任务显示倒计时布局
+ if ((item.status == 0 || item.status == 4) && item.taskCategory == 2) {
bind.countdownLayout.isVisible = true
val list = calculateTimeDifference(item.endTime)
updateTime(bind, list)
- if (list.all { it == 0L }) { // 全0
+ if (list.all { it == 0L }) { // 全0 表示已超时
bind.countdownTips.text = "已超时"
- } else { // 注册到倒计时列表
+ } else { // 注册到倒计时列表,启动每秒刷新
bind.countdownTips.text = "倒计时结束前,务必到达现场"
countdownHolders[holder.hashCode()] = bind
startCountdown()
}
} else {
bind.countdownLayout.isVisible = false
- // 如果不是倒计时项,从列表移除
+ // 如果不是倒计时项,从列表移除,避免内存泄漏
countdownHolders.remove(holder.hashCode())
}
+ // 设置任务类型文本:事故或常规任务类型名称
if (item.isAccidentTask()) {
bind.type.text = "事故"
} else if (item.isRoutineTask()) {
bind.type.text = item.getTaskType()
}
+ // 先按"与 type 同行"展示车牌号;待布局完成后检测是否被省略,
+ // 若被省略则把车牌号下移到 type 的下一行整行显示。
bind.plateNumber.text = item.plateNumber
+ bind.plateNumberFull.text = item.plateNumber
+ bind.plateNumber.isVisible = true
+ bind.plateNumberFull.isVisible = false
+ bind.plateNumber.post {
+ val layout = bind.plateNumber.layout ?: return@post
+ val ellipsized = (0 until layout.lineCount).any {
+ layout.getEllipsisCount(it) > 0
+ }
+ if (ellipsized) {
+ bind.plateNumber.visibility = View.INVISIBLE
+ bind.plateNumberFull.isVisible = true
+ } else {
+ bind.plateNumber.isVisible = true
+ bind.plateNumberFull.isVisible = false
+ }
+ }
+ // 初始化状态文本颜色与背景
val setStatus: (Int, Int) -> Unit = { text, bg ->
bind.status.setTextColor(text)
bind.status.setBackgroundResource(bg)
@@ -148,59 +216,96 @@
getResColor(com.xw.common.R.color.gray_8),
com.xw.common.R.color.gray_3
)
- // 0 = 待到达 1 = 待处理 2 = 已完成 3 = 已取消
+ // 0 = 待到达 1 = 待处理 2 = 已完成 3 = 已取消 4 = 改派中
when (item.status) {
0 -> bind.status.text = "待到达"
1 -> bind.status.text = "待处理"
2 -> bind.status.text = "已处理"
3 -> bind.status.text = "已取消"
+ 4 -> bind.status.text = "改派中"
}
-
+ bind.ivArrow.visibility = if (item.status == 4) View.GONE else View.VISIBLE
bind.address.text = item.vehicleLocation
-
+ bind.llNotice.visibility = if (item.status == 4) View.VISIBLE else View.GONE
+ // 控制"操作按钮"是否可点击
var canClick = true
+ // 仅对待到达或待处理状态的事故任务显示操作按钮
bind.tvControl.isVisible = item.status in arrayOf(0, 1) && item.taskCategory == 2
if (item.status == 0) {
- bind.tvControl.isVisible = MyApp.findPermissionByName("到达事故现场")?.visible == "0"
+ // 检查是否有"到达事故现场"权限
+ bind.tvControl.isVisible =
+ MyApp.findPermissionByName("到达事故现场")?.visible == "0"
bind.tvControl.text = "我已到达现场"
canClick = false
- if (lat != 0.0 && lng != 0.0 && (item.vehicleLat ?: 0.0) != 0.0 && (item.vehicleLon ?: 0.0) != 0.0) {
+ // 当定位与车辆位置均有效时,计算距离并判断是否在允许到达范围内
+ if (lat != 0.0 && lng != 0.0 && (item.vehicleLat ?: 0.0) != 0.0 && (item.vehicleLon
+ ?: 0.0) != 0.0
+ ) {
val dis = CalculatorLineDistance.calculate(
LatLng(lat, lng),
LatLng(item.vehicleLat!!, item.vehicleLon!!)
)
canClick = (item.canArriveRange ?: 0) > dis.toInt()
- LogUtils.i("zmc-test-adapter","${item.plateNumber} dis = $dis canArriveRange = ${item.canArriveRange} canClick = $canClick")
+ LogUtils.i(
+ "zmc-test-adapter",
+ "${item.plateNumber} dis = $dis canArriveRange = ${item.canArriveRange} canClick = $canClick"
+ )
}
} else if (item.status == 1) {
bind.tvControl.text = "处理事故"
}
+ // 根据按钮可用状态设置不同背景样式
if (canClick) {
bind.tvControl.setBackgroundResource(R.drawable.shape_blue_5_bg_4)
} else {
bind.tvControl.setBackgroundResource(R.drawable.shape_blue_1_bg_4)
}
- bind.root.setOnClickListener { listener.onItemClick(item) }
- bind.tvControl.setOnClickListener { if (canClick) listener.oneItemElementClick(item) }
- bind.nav.setOnClickListener { listener.twoItemElementClick(item) }
+ // 设置点击事件:整项点击、操作按钮点击、导航点击
+ bind.clContent.setOnClickListener {
+ if (item.status == 4) {
+ return@setOnClickListener
+ }
+ listener.onItemClick(item)
+ }
+ bind.tvControl.setOnClickListener {
+ if (item.status == 4) {
+ return@setOnClickListener
+ }
+ if (canClick) listener.oneItemElementClick(item)
+ }
+ bind.nav.setOnClickListener {
+ if (item.status == 4) {
+ return@setOnClickListener
+ }
+ listener.twoItemElementClick(item)
+ }
}
}
+ /**
+ * 更新倒计时时间显示及样式
+ *
+ * @param bind 列表项视图绑定对象
+ * @param list 包含时、分、秒的列表
+ */
private fun updateTime(bind: ItemTaskContentBinding, list: List<Long>) {
bind.hour.text = if (list[0] < 10) "0${list[0]}" else "${list[0]}"
bind.minutes.text = if (list[1] < 10) "0${list[1]}" else "${list[1]}"
bind.second.text = if (list[2] < 10) "0${list[2]}" else "${list[2]}"
- val showRed = list[0] == 0L && list[1] == 0L
+ // 当剩余时间不足3分钟时,切换为红色警示样式
+ val showRed = list[0] == 0L && list[1] <= 2L
- val countdownId = if (showRed) R.mipmap.img_task_item_top_bg_red else R.mipmap.img_task_item_top_bg_blue
+ val countdownId =
+ if (showRed) R.mipmap.img_task_item_top_bg_red else R.mipmap.img_task_item_top_bg_blue
bind.countdownLayout.setBackgroundResource(countdownId)
- val colorId = if (showRed) getResColor(com.xw.common.R.color.red_6) else getResColor(com.xw.common.R.color.blue_5)
+ val colorId =
+ if (showRed) getResColor(com.xw.common.R.color.red_6) else getResColor(com.xw.common.R.color.blue_5)
bind.countdownTips.setTextColor(colorId)
val bgId = if (showRed) R.drawable.shape_fa3e3e_bg_4 else R.drawable.shape_blue_5_bg_4
@@ -212,6 +317,7 @@
bind.colon1.setImageResource(imgId)
bind.colon2.setImageResource(imgId)
+ // 倒计时全部归零时隐藏时间数字与冒号
val hideTime = list[0] == 0L && list[1] == 0L && list[2] == 0L
bind.hour.isVisible = !hideTime
@@ -223,6 +329,9 @@
/**
* 计算目标时间与当前时间的差值,返回时分秒格式
+ *
+ * @param targetTimeStr 目标时间字符串,格式为 yyyy-MM-dd HH:mm:ss
+ * @return 包含 [时, 分, 秒] 的列表;若输入为空则返回 [0, 0, 0]
*/
fun calculateTimeDifference(targetTimeStr: String?): List<Long> {
targetTimeStr?.let {
@@ -234,7 +343,7 @@
val now = LocalDateTime.now()
// 计算时间差(毫秒)
val duration = Duration.between(now, targetTime)
- val totalSeconds = max(duration.seconds,0L)
+ val totalSeconds = max(duration.seconds, 0L)
// 转换为时分秒
val hours = TimeUnit.SECONDS.toHours(totalSeconds)
val minutes = TimeUnit.SECONDS.toMinutes(totalSeconds) % 60
@@ -245,15 +354,19 @@
}
/**
- * View被回收时清理
+ * View 被回收时清理
+ *
+ * 移除该 holder 在倒计时注册表中的记录,防止对已回收视图进行刷新。
*/
override fun onViewRecycled(holder: BaseViewHolder) {
- super.onViewRecycled(holder)
countdownHolders.remove(holder.hashCode())
+ super.onViewRecycled(holder)
}
/**
- * Adapter从RecyclerView分离时清理所有倒计时
+ * Adapter 从 RecyclerView 分离时清理所有倒计时
+ *
+ * 停止 Handler 消息循环并清空 holder 注册表,防止内存泄漏。
*/
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
super.onDetachedFromRecyclerView(recyclerView)
@@ -262,6 +375,7 @@
}
companion object {
+ /** 倒计时消息标识 */
const val MSG_COUNTDOWN = 1001
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/task/list/TaskListFragment.kt b/app/src/main/java/com/xw/yunwei/ui/task/list/TaskListFragment.kt
index ca9ac52..cdd7eb8 100644
--- a/app/src/main/java/com/xw/yunwei/ui/task/list/TaskListFragment.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/task/list/TaskListFragment.kt
@@ -1,15 +1,14 @@
package com.xw.yunwei.ui.task.list
import android.annotation.SuppressLint
+import android.os.Bundle
import android.view.View
import androidx.core.os.bundleOf
-import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
import com.amap.api.maps.model.LatLng
import com.blankj.utilcode.util.GsonUtils
-import com.google.gson.Gson
import com.xw.common.base.BaseFragment
-import com.xw.common.base.ListState
import com.xw.common.base.TwoItemElementClickListener
import com.xw.common.base.fastObserve
import com.xw.common.utils.BindUtils
@@ -19,21 +18,26 @@
import com.xw.yunwei.BR
import com.xw.yunwei.MyApp
import com.xw.yunwei.databinding.FragmentTaskListBinding
+import com.xw.yunwei.extension.hideKeyboardAndClearFocus
import com.xw.yunwei.model.FilterData
import com.xw.yunwei.model.LocationData
import com.xw.yunwei.model.TaskModel
+import com.xw.yunwei.model.event.TaskEvent
import com.xw.yunwei.ui.task.TaskFragment
import com.xw.yunwei.ui.task.accident.detail.AccidentDetailActivity
import com.xw.yunwei.ui.task.normal.NormalTaskDetailActivity
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
-import android.os.Bundle
-import kotlin.jvm.java
/**
- * 任务列表
- * @param status 0=待到达 1=待处理 2=已完成 3=已取消
+ * 任务列表页面
+ *
+ * 展示不同状态(待到达、待处理、已完成、已取消)的任务列表,
+ * 支持下拉刷新、上拉加载、筛选过滤及定位导航功能。
+ * 通过状态参数 [status] 区分不同 Tab 页面。
+ *
+ * @param status 任务状态:0=待到达 1=待处理 2=已完成 3=已取消 4=改派中
*/
class TaskListFragment : BaseFragment<FragmentTaskListBinding, TaskListVM>(),
TwoItemElementClickListener<TaskModel> {
@@ -41,6 +45,13 @@
companion object {
private const val ARG_STATUS = "status"
+
+ /**
+ * 创建任务列表片段实例
+ *
+ * @param status 任务状态,用于区分不同页面
+ * @return 配置好参数的任务列表片段
+ */
fun newInstance(status: Int?): TaskListFragment {
return TaskListFragment().apply {
arguments = bundleOf(ARG_STATUS to status)
@@ -48,6 +59,7 @@
}
}
+ /** 当前页面所展示的任务状态 */
private var status: Int? = null
override fun onCreate(savedInstanceState: Bundle?) {
@@ -55,18 +67,40 @@
status = arguments?.getInt(ARG_STATUS, -1).takeIf { it != -1 }
}
+ /** 空数据提示视图,懒加载创建 */
val emptyView by lazy {
- BindUtils.getEmptyView(requireActivity(), "暂无数据").apply { visibility = View.GONE }
+ BindUtils.getEmptyView(requireActivity(), "暂无任务")
}
- val footView by lazy {
- BindUtils.getFootView(requireActivity(), "已加载全部任务").apply { visibility = View.GONE }
- }
+
+ /** 任务列表适配器,配置空视图与底部视图 */
val adapter by lazy {
TaskListAdapter(this).apply {
setHasStableIds(true)
setEmptyView(emptyView)
- setFooterView(footView)
}
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ binding.rv.addOnScrollListener(object : RecyclerView.OnScrollListener() {
+ override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
+ super.onScrollStateChanged(recyclerView, newState)
+ when (newState) {
+ RecyclerView.SCROLL_STATE_IDLE -> {
+ // 滚动停止
+ }
+
+ RecyclerView.SCROLL_STATE_DRAGGING -> {
+ // 手指正在拖动
+ requireActivity().hideKeyboardAndClearFocus()
+ }
+
+ RecyclerView.SCROLL_STATE_SETTLING -> {
+ // 惯性滑动中
+ }
+ }
+ }
+ })
}
override fun init() {
@@ -80,58 +114,52 @@
@SuppressLint("NotifyDataSetChanged")
override fun setObservable() {
super.setObservable()
- viewModel.refreshLiveData.fastObserve(this, binding.refreshLayout) { state->
- binding.refreshLayout.post {
- when (state) {
- ListState.DONE -> {
- if (viewModel.dataList.value.isNullOrEmpty()) {
- emptyView.isVisible = true
- } else {
- footView.isVisible = true
- }
- }
- else -> {
- emptyView.isVisible = false
- footView.isVisible = false
- }
- }
- }
+ // 监听刷新状态,控制空视图与底部视图的显示
+ viewModel.refreshLiveData.fastObserve(this, binding.refreshLayout)
+ // 监听数据变化,更新适配器列表
+ viewModel.dataList.observe(viewLifecycleOwner) {
+ adapter.setList(it)
}
- viewModel.dataList.observe(this) {
- binding.rv.post { adapter.setList(it) }
- }
- MyApp.permissions.observe(this) {
- binding.rv.post { adapter.notifyDataSetChanged() }
+ // 权限变化时刷新列表,控制按钮显示状态
+ MyApp.permissions.observe(viewLifecycleOwner) {
+ adapter.notifyDataSetChanged()
}
}
override fun setListener() {
with(binding.refreshLayout) {
+ // 下拉刷新
setOnRefreshListener {
refreshData()
}
+ // 上拉加载更多
setOnLoadMoreListener {
viewModel.loadMoreData()
}
}
}
+ /** 初始化 RecyclerView 适配器与布局管理器 */
private fun initAdapter() {
- adapter.setList(viewModel.dataList.value ?: ArrayList())
binding.rv.adapter = adapter
binding.rv.layoutManager = LinearLayoutManager(requireActivity())
}
override fun onResume() {
super.onResume()
+ // 恢复父片段中的定位数据到适配器
with((parentFragment as TaskFragment).locationData) {
adapter.setLocation(lat, lng, false)
}
+ // 应用筛选条件
applyFilterToViewModel((parentFragment as TaskFragment).filterData)
+ viewModel.loopRefreshWaitReassignTaskList()
}
+ /** 初始化筛选与定位结果的 FragmentResult 监听器 */
private fun initFilterListener() {
LogUtils.i("zmc-test", "initFilterListener")
+ // 监听筛选条件变化
requireActivity().supportFragmentManager.setFragmentResultListener(
TaskFragment.REQUEST_KEY_FILTER,
this
@@ -144,6 +172,7 @@
filter?.let { applyFilterToViewModel(it) }
}
+ // 监听定位数据变化
requireActivity().supportFragmentManager.setFragmentResultListener(
TaskFragment.REQUEST_KEY_LOCATION,
this
@@ -158,6 +187,11 @@
}
}
+ /**
+ * 将筛选条件应用到 ViewModel 并触发刷新
+ *
+ * @param filter 用户选择的筛选数据
+ */
private fun applyFilterToViewModel(filter: FilterData) {
with(viewModel) {
distributeType.value = filter.distributeType
@@ -173,12 +207,19 @@
refreshData()
}
+ /** 刷新数据:启动定位并请求第一页数据 */
private fun refreshData() {
- (parentFragment as TaskFragment).gpsHelper?.startLocation()
-
+ parentFragment?.also {
+ (it as TaskFragment).gpsHelper?.startLocation()
+ }
viewModel.refreshData()
}
+ /**
+ * 列表项点击事件,跳转到任务详情
+ *
+ * @param item 点击的任务数据
+ */
override fun onItemClick(item: TaskModel) { // 详情
if (item.taskCategory == 1) {
// startActivity(TaskDetailActivity::class.java)
@@ -189,6 +230,14 @@
}
}
+ /**
+ * 操作按钮点击事件
+ *
+ * - 待到达:确认到达现场后跳转事故详情
+ * - 待处理:跳转事故详情进行处理
+ *
+ * @param item 点击的任务数据
+ */
override fun oneItemElementClick(item: TaskModel) { // 按钮事件
if (item.status == 0) { // 到达现场
viewModel.confirmArrive("${item.id}") {
@@ -199,6 +248,11 @@
}
}
+ /**
+ * 导航按钮点击事件,调用高德导航到车辆位置
+ *
+ * @param item 点击的任务数据
+ */
override fun twoItemElementClick(item: TaskModel) { // 导航事件
if ((item.vehicleLat ?: 0.0) != 0.0 && (item.vehicleLon ?: 0.0) != 0.0) {
navigate(
@@ -229,4 +283,11 @@
}
}
+ @Suppress("unused")
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ fun onMessageEvent(event: TaskEvent) {
+ if (event is TaskEvent.TaskAcceptEvent) {
+ refreshData()
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/task/list/TaskListVM.kt b/app/src/main/java/com/xw/yunwei/ui/task/list/TaskListVM.kt
index afba051..64791be 100644
--- a/app/src/main/java/com/xw/yunwei/ui/task/list/TaskListVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/task/list/TaskListVM.kt
@@ -2,48 +2,69 @@
import android.app.Application
import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.viewModelScope
import com.xw.common.base.BasePagingViewModel
import com.xw.common.utils.LogUtils
import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.model.TaskModel
+import com.xw.yunwei.model.taskPlaceHolder
import com.xw.yunwei.net.TaskRepository
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
import org.koin.core.component.inject
-import kotlin.getValue
+/**
+ * 任务列表视图模型
+ *
+ * 负责任务列表的分页加载、筛选条件管理及"确认到达"操作。
+ * 通过多个 [MutableLiveData] 暴露筛选状态,支持车牌号、时间、优先级、类别等维度的过滤。
+ */
class TaskListVM(application: Application) : BasePagingViewModel(application) {
+ /** 任务数据仓库 */
val taskRepository: TaskRepository by inject()
+ /** 任务列表数据 */
val dataList: MutableLiveData<List<TaskModel>> = MutableLiveData()
- // 车牌号
+ /** 车牌号筛选 */
val plateNumber: MutableLiveData<String> = MutableLiveData("")
- // 状态0=待到达 1=待处理 2=已完成 3=已取消
+ /** 任务状态:0=待到达 1=待处理 2=已完成 3=已取消 4=改派中 */
val status: MutableLiveData<Int?> = MutableLiveData()
- // 派发类型 1今天 2昨天 3近一周 4近一月 5自定义时间
+ /** 派发类型:1今天 2昨天 3近一周 4近一月 5自定义时间 */
val distributeType: MutableLiveData<Int?> = MutableLiveData()
- // 派发类型为5 开始时间 yyyy-MM-dd HH:mm:ss
+ /** 派发类型为 5 时的开始时间,格式 yyyy-MM-dd HH:mm:ss */
val startTime: MutableLiveData<String> = MutableLiveData("")
- // 派发类型为5 结束时间 yyyy-MM-dd HH:mm:ss
+ /** 派发类型为 5 时的结束时间,格式 yyyy-MM-dd HH:mm:ss */
val endTime: MutableLiveData<String> = MutableLiveData("")
- // 任务优先级 0=P0 1=P1 2=P2 3=P3 不传为全部
+ /** 任务优先级:0=P0 1=P1 2=P2 3=P3,不传为全部 */
val taskUrgencyLevel: MutableLiveData<Int?> = MutableLiveData()
- // 任务类别1常规 2事故
+ /** 任务类别:1常规 2事故 */
val taskCategory: MutableLiveData<Int?> = MutableLiveData()
- // 排序优先 1依据任务优先级 2车牌号 3任务时间
+ /** 排序优先:1依据任务优先级 2车牌号 3任务时间 */
val sortType: MutableLiveData<Int?> = MutableLiveData()
- // 排序规则 1正序 2倒序
+ /** 排序规则:1正序 2倒序 */
val sortRule: MutableLiveData<Int?> = MutableLiveData()
+ //是否已经循环刷新
+ var hadLoopRefresh = false
+
+ /**
+ * 获取任务列表数据
+ *
+ * 根据当前筛选条件组装请求参数,支持分页加载。
+ *
+ * @param index 页码,1 表示刷新,大于 1 表示加载更多
+ */
override fun getDataList(index: Int) {
if (index == 1) {
refreshLiveData.refresh()
@@ -79,16 +100,26 @@
list.add(item)
}
if ((data?.total ?: 0) <= list.size) {
+ if (list.isNotEmpty()) {
+ list.add(taskPlaceHolder)
+ }
refreshLiveData.done()
}
- LogUtils.d("zmc-test","initFilterListener received location data")
+ LogUtils.d("zmc-test", "initFilterListener received location data")
dataList.postValue(list)
pageNo = index
}
}
-
+ /**
+ * 确认到达现场
+ *
+ * 调用接口上报到达状态,成功后执行回调跳转。
+ *
+ * @param id 任务 ID
+ * @param block 成功后的回调,用于页面跳转
+ */
fun confirmArrive(id: String, block: () -> Unit) {
launchRequest("操作中...") {
taskRepository.confirmArrive(id)
@@ -97,5 +128,17 @@
}
}
-
+ //循环检测等待改派列表
+ fun loopRefreshWaitReassignTaskList() {
+ if (status.value != 4 || hadLoopRefresh) {
+ return
+ }
+ hadLoopRefresh = true
+ viewModelScope.launch {
+ while (true) {
+ delay(30 * 1000)
+ refreshData()
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/task/normal/NormalTaskDetailActivity.kt b/app/src/main/java/com/xw/yunwei/ui/task/normal/NormalTaskDetailActivity.kt
index fd35ea6..fa0632a 100644
--- a/app/src/main/java/com/xw/yunwei/ui/task/normal/NormalTaskDetailActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/task/normal/NormalTaskDetailActivity.kt
@@ -9,55 +9,37 @@
import com.amap.api.location.AMapLocation
import com.amap.api.maps.model.LatLng
import com.blankj.utilcode.util.UriUtils
-import com.luck.picture.lib.basic.PictureSelector
import com.luck.picture.lib.config.PictureMimeType
-import com.luck.picture.lib.config.SelectMimeType
import com.luck.picture.lib.entity.LocalMedia
import com.luck.picture.lib.interfaces.OnResultCallbackListener
import com.xw.common.CommonDialog
-import com.xw.common.base.BaseActivity
import com.xw.common.base.FileSelectBean
import com.xw.common.base.ImageEventListener
import com.xw.common.base.ImageSelectAdapter
import com.xw.common.base.ShowImgListDialog
import com.xw.common.custom.BatteryView.Companion.getBatteryColorByBatteryLife
import com.xw.common.utils.BindUtils.getUrls
-import com.xw.common.utils.GlideEngine
import com.xw.common.utils.GpsHelper
import com.xw.common.utils.GpsHelper.Companion.navigate
-import com.xw.common.utils.PictureCompressEngine
import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.databinding.ActivityNormalTaskDetailBinding
import com.xw.yunwei.model.TaskNormalModel
import com.xw.yunwei.ui.work.car.detail.operations.charge.ChargeCarActivity
-import java.util.ArrayList
+import com.xw.yunwei.utils.PictureSelectorFactory
/**
- * 任务详情 待处理
+ * 常规任务详情页面
*
- * 日常检查 -> 工作台对应业务
- * 车辆充电 1:充电中 2:结束充电
- * 车辆整备 -> 工作台对应业务
- * 洗车
- * 维修 1:送修 -> 工作台对应业务 2:取回
- * 保养
- * 年检
- * 保险
- * 车辆运营资质到期
+ * 支持展示多种任务类型的详情,包括:
+ * - 待处理:日常检查、车辆充电、车辆整备、洗车、维修、保养、年检、保险、车辆运营资质到期
+ * - 已处理:检测、车辆充电、车辆整备、洗车、维修、保养、年检、保险、车辆运营资质到期
*
- * 任务详情 已处理
- * 检测
- * 车辆充电
- * 车辆整备
- * 洗车
- * 维修
- * 保养
- * 年检
- * 保险
- * 车辆运营资质到期
+ * 页面根据任务状态(待处理/已处理)和任务类型动态展示不同布局,
+ * 并支持图片选择、上传及高德地图导航功能。
*/
-class NormalTaskDetailActivity: BaseActivity<ActivityNormalTaskDetailBinding, NormalTaskDetailVM>(), GpsHelper.OnMapLocation{
+class NormalTaskDetailActivity: BaseBusinessActivity<ActivityNormalTaskDetailBinding, NormalTaskDetailVM>(), GpsHelper.OnMapLocation{
override fun getBindingVariable(): Int = BR.viewModel
// var gpsHelper: GpsHelper? = null
@@ -75,24 +57,30 @@
override fun init() {
super.init()
+ // 从 intent 中获取任务 ID
viewModel.taskId = intent.getLongExtra("taskId", 0L)
}
+ /** 标识是否从图片选择页返回,避免 onResume 中重复刷新详情 */
var isGetPictureBack = false
+
override fun onResume() {
super.onResume()
if (isGetPictureBack) {
isGetPictureBack = false
return
}
+ // 查询任务详情及子详情
viewModel.queryDetail()
}
@SuppressLint("SetTextI18n")
override fun setObservable() {
super.setObservable()
+ // 监听任务主详情,初始化适配器与按钮文案
viewModel.taskDetail.observe(this) {
initAdapter(it)
+ // 根据任务类型设置待处理状态下的操作按钮文案
viewModel.btnDoingAction.value = when (it.taskTypeId) {
"1" -> "开始检查"
"2" -> "开始充电"
@@ -105,12 +93,15 @@
"9" -> "完成任务"
else -> ""
}
+ // 整备和维修任务隐藏详情入口
binding.layoutDoing.viewDetail.isVisible = it.taskTypeId !in arrayOf("3", "5")
binding.layoutFinish.viewDetail1.isVisible = it.taskTypeId !in arrayOf("3", "5")
+ // 加载任务图片到第一个仅查看适配器
it.taskImage?.getUrls()?.let {
viewModel.adapters.getOrNull(0)?.setList(it.map { FileSelectBean(url = it, type = "img") })
}
}
+ // 监听充电任务子详情
viewModel.chargeModel.observe(this) {
if (viewModel.taskDetail.value?.status == 1) { // 待处理
if (it.startOperationsUserId == null) { // 未充电
@@ -132,6 +123,7 @@
binding.layoutFinish.chargeLayout.batteryLife2.setTextColor(getBatteryColorByBatteryLife(it.endRemainingBattery ?: 0))
}
+ // 加载充电开始/结束图片
it.startChargingPicture?.getUrls()?.let {
viewModel.adapters.getOrNull(0)?.setList(it.map { FileSelectBean(url = it, type = "img") })
}
@@ -139,11 +131,13 @@
viewModel.adapters.getOrNull(1)?.setList(it.map { FileSelectBean(url = it, type = "img") })
}
}
+ // 监听洗车任务子详情
viewModel.cleanModel.observe(this) {
it.taskImage?.getUrls()?.let {
viewModel.adapters.getOrNull(0)?.setList(it.map { FileSelectBean(url = it, type = "img") })
}
}
+ // 监听检测任务子详情
viewModel.checkModel.observe(this) {
it.sensorCleaningPicture?.getUrls()?.let {
viewModel.adapters.getOrNull(0)?.setList(it.map { FileSelectBean(url = it, type = "img") })
@@ -161,6 +155,7 @@
viewModel.adapters.getOrNull(4)?.setList(it.map { FileSelectBean(url = it, type = "img") })
}
}
+ // 监听整备任务子详情
viewModel.maintainModel.observe(this) {
it.headLight?.getUrls()?.let {
viewModel.adapters.getOrNull(0)?.setList(it.map { FileSelectBean(url = it, type = "img") })
@@ -182,6 +177,7 @@
}
}
+ // 监听维修任务子详情
viewModel.repairModel.observe(this) {
if (viewModel.taskDetail.value?.status == 1) { // 待处理
viewModel.isRepair.value = it.sendUserId != null
@@ -198,6 +194,10 @@
override fun setListener() {
super.setListener()
+ binding.tvApplyForReassignment.setOnClickListener {
+ viewModel.showApplyForReassignDialog(this)
+ }
+ // 导航按钮:跳转高德地图导航到车辆位置
binding.layoutDoing.nav.setOnClickListener {
viewModel.taskDetail.value?.let { item ->
if ((item.vehicleLat ?: 0.0) != 0.0 && (item.vehicleLon ?: 0.0) != 0.0) {
@@ -211,6 +211,7 @@
}
}
+ // 滑动完成按钮:充电任务中滑动结束后跳转到充电页面
binding.layoutDoing.slideView.setOnSlideCompleteListener{
viewModel.taskDetail.value?.let {
startActivity(
@@ -222,9 +223,15 @@
}
}
+ /**
+ * 根据任务状态与类型初始化对应的图片适配器
+ *
+ * @param it 任务详情数据
+ */
private fun initAdapter(it: TaskNormalModel) {
if (it.status == 1) { // 待处理
if (it.taskTypeId in arrayOf("4", "6", "7", "8", "9")) {
+ // 洗车、保养、年检、保险、资质到期:使用可编辑适配器
initEditAdapter()
if (it.taskTypeId == "4") {
binding.layoutDoing.cleanLayout.rv.adapter = viewModel.adapterCanEdit
@@ -293,6 +300,7 @@
}
}
+ /** 初始化可编辑图片适配器,支持添加、查看、删除图片 */
private fun initEditAdapter() {
viewModel.imageEventCanEdit = object : ImageEventListener<FileSelectBean>() {
override fun addImage(item: FileSelectBean) {
@@ -318,6 +326,11 @@
viewModel.adapterCanEdit = ImageSelectAdapter(this, viewModel.maxSize, 1, viewModel.imageEventCanEdit)
}
+ /**
+ * 初始化仅查看图片适配器
+ *
+ * @param num 需要创建的适配器数量
+ */
private fun initOnlyViewAdapter(num: Int){
viewModel.imageEvents.clear()
viewModel.adapters.clear()
@@ -341,6 +354,7 @@
}
}
+ /** 显示选择拍照或相册的弹窗 */
private fun showTypeDialog() {
CommonDialog.showTypeDialog(this) {
isGetPictureBack = it in arrayOf(1, 0)
@@ -351,25 +365,19 @@
// 进入图库
@SuppressLint("SourceLockedOrientationActivity")
private fun enterGallery() {
- PictureSelector.create(this)
- .openGallery(SelectMimeType.ofImage())
- .setImageEngine(GlideEngine.createGlideEngine())
- .setMaxSelectNum(viewModel.maxSize - viewModel.adapterCanEdit.data.size)
- .setImageSpanCount(4)
- .isPreviewImage(true)
- .isDisplayCamera(false)
- .setCompressEngine(PictureCompressEngine())
- .forResult(resultCallbackListener)
+ PictureSelectorFactory.enterGallery(
+ this,
+ viewModel.maxSize - viewModel.adapterCanEdit.data.size,
+ resultCallbackListener
+ )
}
// 拍照
private fun takeAPhotograph() {
- PictureSelector.create(this)
- .openCamera(SelectMimeType.ofImage())
- .setCompressEngine(PictureCompressEngine())
- .forResultActivity(resultCallbackListener)
+ PictureSelectorFactory.takeAPhotograph(this, resultCallbackListener)
}
+ /** 图片选择结果回调 */
private var resultCallbackListener = object : OnResultCallbackListener<LocalMedia> {
override fun onResult(result: ArrayList<LocalMedia>?) {
result?.let { selectList ->
@@ -377,6 +385,7 @@
dataList.addAll(viewModel.adapterCanEdit.data)
for (item in selectList) {
val path: String = item.availablePath
+ // 处理 content Uri,转换为绝对路径
var imgPath = if (PictureMimeType.isContent(path) && !item.isCut && !item.isCompressed) {
UriUtils.uri2File(Uri.parse(path)).absolutePath
} else {
@@ -390,6 +399,11 @@
override fun onCancel() {}
}
+ /**
+ * 高德定位回调
+ *
+ * @param pLocation 定位结果
+ */
override fun location(pLocation: AMapLocation?) {
viewModel.location = pLocation
}
diff --git a/app/src/main/java/com/xw/yunwei/ui/task/normal/NormalTaskDetailVM.kt b/app/src/main/java/com/xw/yunwei/ui/task/normal/NormalTaskDetailVM.kt
index 67923a3..0dc0b01 100644
--- a/app/src/main/java/com/xw/yunwei/ui/task/normal/NormalTaskDetailVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/task/normal/NormalTaskDetailVM.kt
@@ -1,87 +1,150 @@
package com.xw.yunwei.ui.task.normal
import android.app.Application
+import android.content.Context
import android.util.Log
import android.view.View
import androidx.core.os.bundleOf
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.map
+import androidx.lifecycle.viewModelScope
import com.amap.api.location.AMapLocation
import com.blankj.utilcode.util.GsonUtils
import com.xw.common.base.BaseViewModel
import com.xw.common.base.FileSelectBean
import com.xw.common.base.ImageEventListener
import com.xw.common.base.ImageSelectAdapter
+import com.xw.common.utils.LogUtils
import com.xw.common.utils.ToastUtilCommon
+import com.xw.yunwei.Constants
import com.xw.yunwei.Constants.user
import com.xw.yunwei.R
+import com.xw.yunwei.model.SwitchTabMain
+import com.xw.yunwei.model.SwitchTabTask
import com.xw.yunwei.model.TaskNormalChargeModel
import com.xw.yunwei.model.TaskNormalCheckModel
import com.xw.yunwei.model.TaskNormalCleanModel
import com.xw.yunwei.model.TaskNormalMaintainModel
import com.xw.yunwei.model.TaskNormalModel
import com.xw.yunwei.model.TaskNormalRepairModel
+import com.xw.yunwei.model.VehicleLocationInfo
+import com.xw.yunwei.net.CommonRepository
import com.xw.yunwei.net.TaskRepository
import com.xw.yunwei.net.WorkRepository
-import com.xw.yunwei.net.CommonRepository
+import com.xw.yunwei.ui.dialog.ApplyForReassignReasonDialog
import com.xw.yunwei.ui.work.car.detail.StandardDescriptionActivity
import com.xw.yunwei.ui.work.car.detail.operations.charge.ChargeCarActivity
import com.xw.yunwei.ui.work.car.detail.operations.check.CheckCarActivity
import com.xw.yunwei.ui.work.car.detail.operations.maintain.MaintainCarActivity
import com.xw.yunwei.ui.work.car.detail.operations.repair.RepairCarActivity
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
+import org.greenrobot.eventbus.EventBus
import org.koin.core.component.inject
import java.io.File
-import kotlin.getValue
+/**
+ * 常规任务详情视图模型
+ *
+ * 负责任务详情的查询、子详情加载、图片适配器管理以及任务提交操作。
+ * 根据任务类型(检测、充电、整备、洗车、维修、保养等)和状态(待处理/已处理)
+ * 动态切换 UI 状态并处理对应的业务逻辑。
+ */
class NormalTaskDetailVM(application: Application) : BaseViewModel(application) {
+ /** 任务数据仓库 */
val taskRepository: TaskRepository by inject()
+
+ /** 工作台数据仓库 */
val workRepository: WorkRepository by inject()
+
+ /** 通用数据仓库(如文件上传) */
val commonRepository: CommonRepository by inject()
+ /** 当前定位信息 */
var location: AMapLocation? = null
+ /** 当前任务 ID */
var taskId = 0L
- val taskDetail: MutableLiveData<TaskNormalModel> = MutableLiveData()
- val title = taskDetail.map {
- if(it.status == 1) "待处理" else if(it.status == 2) "已处理" else ""
- }
- val levelId = taskDetail.map {
- when(it.taskUrgencyLevel){
- 0 -> R.mipmap.ic_accident_one
- 1 -> R.mipmap.ic_accident_two
- 2 -> R.mipmap.ic_accident_three
- 3 -> R.mipmap.ic_accident_four
- else -> R.mipmap.ic_accident_one
- }
- }
- val btnDoingAction = MutableLiveData("")
- val showDoingBtn = MutableLiveData(true) // 显示按钮
- val showDoingSlide = MutableLiveData(false) // 显示滑块
- val isRepair = MutableLiveData(false) // 是否已送修
- val taskDescription = MutableLiveData("") // 完成任务情况
- /*可编辑*/
- lateinit var adapterCanEdit: ImageSelectAdapter // 只有洗车和(保养/年检/保险)
+ /** 任务主详情数据 */
+ val taskDetail: MutableLiveData<TaskNormalModel> = MutableLiveData()
+
+ /** 页面标题:根据任务状态映射为"待处理"或"已处理" */
+ val title = taskDetail.map {
+ if (it.status == 1) "待处理" else if (it.status == 2) "已处理" else ""
+ }
+
+ /** 紧急程度图标资源 ID */
+ val levelId = taskDetail.map {
+ when (it.taskUrgencyLevel) {
+ 0 -> R.mipmap.ic_accident_one
+ 1 -> R.mipmap.ic_accident_two
+ 2 -> R.mipmap.ic_accident_three
+ 3 -> R.mipmap.ic_accident_four
+ else -> R.mipmap.ic_accident_one
+ }
+ }
+
+ /** 待处理状态下操作按钮的文案 */
+ val btnDoingAction = MutableLiveData("")
+
+ /** 是否显示操作按钮 */
+ val showDoingBtn = MutableLiveData(true)
+
+ /** 是否显示滑动完成控件(用于充电任务结束充电) */
+ val showDoingSlide = MutableLiveData(false)
+
+ /** 维修任务是否已送修 */
+ val isRepair = MutableLiveData(false)
+
+ /** 完成任务情况说明(用于保养/年检/保险等) */
+ val taskDescription = MutableLiveData("")
+
+ /** 可编辑图片适配器,仅用于洗车和保养/年检/保险等需要上传图片的任务 */
+ lateinit var adapterCanEdit: ImageSelectAdapter
+
+ /** 可编辑图片的事件监听器 */
lateinit var imageEventCanEdit: ImageEventListener<FileSelectBean>
+
+ /** 图片最大选择数量 */
val maxSize = 6
- /*仅查看*/
+ /** 仅查看模式的图片适配器列表 */
val adapters = mutableListOf<ImageSelectAdapter>()
+
+ /** 仅查看模式的图片事件监听器列表 */
val imageEvents = mutableListOf<ImageEventListener<FileSelectBean>>()
- val chargeModel: MutableLiveData<TaskNormalChargeModel> = MutableLiveData() // 充电
- val cleanModel: MutableLiveData<TaskNormalCleanModel> = MutableLiveData() // 洗车
- val checkModel: MutableLiveData<TaskNormalCheckModel> = MutableLiveData() // 检测
- val maintainModel: MutableLiveData<TaskNormalMaintainModel> = MutableLiveData() // 整备
- val repairModel: MutableLiveData<TaskNormalRepairModel> = MutableLiveData() // 维修
+ /** 充电任务子详情 */
+ val chargeModel: MutableLiveData<TaskNormalChargeModel> = MutableLiveData()
+ /** 洗车任务子详情 */
+ val cleanModel: MutableLiveData<TaskNormalCleanModel> = MutableLiveData()
+
+ /** 检测任务子详情 */
+ val checkModel: MutableLiveData<TaskNormalCheckModel> = MutableLiveData()
+
+ /** 整备任务子详情 */
+ val maintainModel: MutableLiveData<TaskNormalMaintainModel> = MutableLiveData()
+
+ /** 维修任务子详情 */
+ val repairModel: MutableLiveData<TaskNormalRepairModel> = MutableLiveData()
+
+ //是否已经循环检测车辆位置
+ var hadLoopRefreshCarLocation = false
+
+ //车辆位置
+ val carLocation = MutableLiveData<VehicleLocationInfo>()
+
+ /** 统一点击事件处理:查看标准说明、提交任务 */
val onClick = View.OnClickListener {
when (it.id) {
R.id.viewDetail, R.id.viewDetail1 -> {
taskDetail.value?.let {
+ // 根据任务类型跳转到对应标准说明页面
val type = when (it.taskTypeId) {
"1" -> 7 // 车辆检测
"2" -> 6 // 开始充电
@@ -105,16 +168,30 @@
}
}
+ /**
+ * 查询任务详情
+ *
+ * 根据 [taskId] 拉取主详情,并根据任务状态进一步查询子详情。
+ */
fun queryDetail() {
launchRequest {
- Log.e(TAG, "queryDetail: $taskId", )
+ Log.e(TAG, "queryDetail: $taskId")
taskRepository.vehicleRoutineDetail("$taskId")?.let {
runOnMainThread {
+ // 当首次加载或任务状态发生变化时更新主详情
if (taskDetail.value == null || taskDetail.value!!.status != it.status) {
taskDetail.value = it
}
if (it.status == 1) { // 待处理
queryDoingTaskStatusByType()
+ carLocation.postValue(
+ VehicleLocationInfo(
+ it.vehicleLon?.toString(),
+ it.vehicleLat?.toString(),
+ it.vehicleLocation
+ )
+ )
+ loopRefreshCarLocation()
} else if (it.status == 2) { // 已处理
queryFinishTaskByType()
}
@@ -123,7 +200,11 @@
}
}
- /*查询进行中任务状态*/
+ /**
+ * 查询进行中(待处理)任务的子详情
+ *
+ * 目前仅充电和维修任务有待处理子详情需要单独查询。
+ */
fun queryDoingTaskStatusByType() {
taskDetail.value?.let {
launchRequest {
@@ -145,7 +226,11 @@
}
}
- /*查询已完成任务的具体子详情*/
+ /**
+ * 查询已完成任务的子详情
+ *
+ * 根据任务类型分别查询检测、充电、整备、洗车、维修等子详情数据。
+ */
fun queryFinishTaskByType() {
taskDetail.value?.let {
launchRequest {
@@ -155,21 +240,25 @@
checkModel.postValue(it)
}
}
+
"2" -> { // 充电
taskRepository.chargingDetail("$taskId")?.let {
chargeModel.postValue(it)
}
}
+
"3" -> { // 整备
taskRepository.preparationDetail("$taskId")?.let {
maintainModel.postValue(it)
}
}
+
"4" -> { // 洗车
taskRepository.cleanDetail("$taskId")?.let {
cleanModel.postValue(it)
}
}
+
"5" -> { // 维修
taskRepository.repairDetail("$taskId")?.let {
repairModel.postValue(it)
@@ -180,7 +269,14 @@
}
}
- private fun submit(){
+ /**
+ * 根据任务类型执行对应的提交操作
+ *
+ * 检测、充电、整备、维修等任务跳转对应页面;
+ * 洗车任务直接提交;
+ * 保养/年检/保险/资质到期调用统一保存接口。
+ */
+ private fun submit() {
taskDetail.value?.let {
when (it.taskTypeId) {
"1" -> { // 车辆检测
@@ -189,34 +285,44 @@
bundleOf("carId" to (it.vehicleId ?: 0L), "taskId" to (it.id ?: 0L))
)
}
+
"2" -> { // 开始充电
startActivity(
ChargeCarActivity::class.java,
bundleOf("carId" to (it.vehicleId ?: 0L), "taskId" to (it.id ?: 0L))
)
}
+
"3" -> { // 开始整备
startActivity(
MaintainCarActivity::class.java,
bundleOf("carId" to (it.vehicleId ?: 0L), "taskId" to (it.id ?: 0L))
)
}
+
"4" -> { // 完成洗车任务
cleanCar()
}
+
"5" -> { // 去送修/取回
startActivity(
RepairCarActivity::class.java,
bundleOf("carId" to (it.vehicleId ?: 0L), "taskId" to (it.id ?: 0L))
)
}
- "6","7","8","9" -> { // 完成保养 完成续保 完成年检 车辆运营资质到期
+
+ "6", "7", "8", "9" -> { // 完成保养 完成续保 完成年检 车辆运营资质到期
saveBy()
}
}
}
}
+ /**
+ * 提交洗车任务
+ *
+ * 校验图片非空后上传图片,随后调用洗车完成接口。
+ */
private fun cleanCar() {
if (adapterCanEdit.data.isEmpty()) {
ToastUtilCommon.showError("请先上传车身清洁照片")
@@ -233,7 +339,7 @@
val map = mapOf(
"operationsUserId" to user?.id,
"vehicleId" to taskDetail.value?.vehicleId,
- "taskImage" to GsonUtils.toJson(files.map { it.url }),
+ "taskImage" to "${files.map { it.url }}",
"taskId" to taskDetail.value?.id
)
launchRequest(tips = "提交中...") {
@@ -244,8 +350,12 @@
}
}
- /*完成保养/保险/年检*/
- private fun saveBy(){
+ /**
+ * 提交保养/保险/年检任务
+ *
+ * 校验说明文字与图片非空后上传图片,随后调用统一保存接口。
+ */
+ private fun saveBy() {
if (taskDescription.value.isNullOrEmpty()) {
ToastUtilCommon.showError("请录入完成任务情况说明")
return
@@ -275,6 +385,15 @@
}
}
+ /**
+ * 递归上传文件
+ *
+ * 遍历待上传文件列表,对未上传(url 为空)的文件逐个上传到服务器,
+ * 全部上传完成后执行成功回调。
+ *
+ * @param files 待上传的文件列表
+ * @param succ 全部上传成功后的回调
+ */
private fun uploadFile(files: List<FileSelectBean>, succ: () -> Unit) {
val result = files.find { it.url.isEmpty() }
if (result == null) {
@@ -295,4 +414,73 @@
}
}
}
+
+ //显示改派弹窗
+ fun showApplyForReassignDialog(context: Context) {
+ if (taskDetail.value == null) {
+ return
+ }
+ ApplyForReassignReasonDialog.show(
+ context,
+ Constants.reasons,
+ ) { position, input, dialog ->
+ showDialog(content = "改派中...")
+ launchRequest(showLoading = false, error = { code, msg ->
+ dismissDialog()
+ ToastUtilCommon.showError(msg)
+ LogUtils.e(TAG, "launchRequest: code = $code msg = $msg")
+ }) {
+ val comment = Constants.reasons[position]
+ taskRepository.taskReassignment(comment, input, taskId.toString()).also {
+ dialog.dismiss()
+ checkApplyForReassignResult()
+ }
+ }
+ }
+ }
+
+ //检测申请改派结果
+ private fun checkApplyForReassignResult() {
+ launchRequest(showLoading = false, error = { code, msg ->
+ dismissDialog()
+ ToastUtilCommon.showError(msg)
+ LogUtils.e(TAG, "launchRequest: code = $code msg = $msg")
+ }) {
+ delay(3 * 1000)
+ val isOk = taskRepository.checkApplyForReassignResult(taskId.toString())
+ dismissDialog()
+ isOk?.also {
+ if (it) ToastUtilCommon.showSuc("改派成功") else ToastUtilCommon.showError("暂未找到运维人员")
+ EventBus.getDefault().post(SwitchTabMain(1))
+ if (!it) {
+ EventBus.getDefault().post(SwitchTabTask(4))
+ }
+ }
+ delay(1000)
+ finish()
+ }
+ }
+
+ //循环刷新车辆位置
+ private fun loopRefreshCarLocation() {
+ if (hadLoopRefreshCarLocation) {
+ return
+ }
+ hadLoopRefreshCarLocation = true
+
+ viewModelScope.launch {
+ while (true) {
+ delay(60 * 1000)
+ launchRequest(showLoading = false, error = { code, msg ->
+ LogUtils.e(TAG, "launchRequest: code = $code msg = $msg")
+ }) {
+ taskDetail.value?.also { it ->
+ taskRepository.queryVehicleNewPoint(it.vehicleId?.toString())?.also {
+ carLocation.postValue(it)
+ }
+ }
+ }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/task/selectCar/SelectCarActivity.kt b/app/src/main/java/com/xw/yunwei/ui/task/selectCar/SelectCarActivity.kt
index ef22d75..dbaff32 100644
--- a/app/src/main/java/com/xw/yunwei/ui/task/selectCar/SelectCarActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/task/selectCar/SelectCarActivity.kt
@@ -1,6 +1,5 @@
package com.xw.yunwei.ui.task.selectCar
-import android.content.Intent
import android.view.Gravity
import android.view.KeyEvent
import android.view.ViewGroup
@@ -9,50 +8,96 @@
import androidx.core.os.bundleOf
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.LinearLayoutManager
-import anet.channel.util.Utils.context
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.customview.customView
import com.afollestad.materialdialogs.customview.getCustomView
import com.xw.common.R
-import com.xw.common.base.BaseActivity
import com.xw.common.base.OnItemClickListener
import com.xw.common.base.fastObserve
+import com.xw.common.utils.BindUtils
import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.databinding.ActivitySelectCarBinding
import com.xw.yunwei.databinding.DialogCarFilterBinding
+import com.xw.yunwei.extension.colorIdToColorValue
+import com.xw.yunwei.extension.dpToPx
+import com.xw.yunwei.extension.drawableIdToDrawable
import com.xw.yunwei.model.CarModel
import com.xw.yunwei.model.FinishPage
import com.xw.yunwei.ui.task.create.CreateTaskActivity
+import com.xw.yunwei.utils.DialogFactory
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
/**
- * 选择车辆
+ * 选择车辆页面
+ *
+ * 展示可运营车辆列表,支持关键词搜索、区域与运营状态筛选,
+ * 选中车辆后可跳转创建任务页面。
+ * 通过 EventBus 接收 [FinishPage] 事件关闭当前页。
*/
-class SelectCarActivity : BaseActivity<ActivitySelectCarBinding, SelectCarVM>(),
+class SelectCarActivity : BaseBusinessActivity<ActivitySelectCarBinding, SelectCarVM>(),
OnItemClickListener<CarModel> {
override fun getBindingVariable() = BR.viewModel
- val adapter by lazy { SelectCarAdapter(this).apply { setHasStableIds(true) } }
+ /** 空数据提示视图,懒加载创建 */
+ val emptyView by lazy {
+ BindUtils.getEmptyView2(this, "暂无符合条件的车辆")
+ }
+
+ /** 车辆列表适配器 */
+ val adapter by lazy {
+ SelectCarAdapter(this).apply {
+ setHasStableIds(true)
+ setEmptyView(emptyView)
+ }
+ }
+
+ /** 筛选弹窗 */
private var filterDialog: MaterialDialog? = null
override fun init() {
super.init()
EventBus.getDefault().register(this)
+ // 若外部传入已选车辆,则直接选中
val selectCar = intent.getParcelableExtra<CarModel>("car")
if (selectCar != null) {
onItemClick(selectCar)
}
initAdapter()
viewModel.refreshData()
+ refreshFilterStatus()
+ }
+
+ //刷新筛选状态
+ private fun refreshFilterStatus() {
+ binding.filter.setTextColor(
+ (if (viewModel.hadFilter()) R.color.blue_5 else R.color.gray_9).colorIdToColorValue(
+ this
+ )
+ )
+ binding.filter.setCompoundDrawables(
+ null,
+ null,
+ (if (viewModel.hadFilter()) R.drawable.svg_filter2 else R.drawable.svg_filter).drawableIdToDrawable(
+ this
+ )?.apply {
+ setBounds(
+ 0, 0, 12.dpToPx(this@SelectCarActivity), 12.dpToPx(this@SelectCarActivity)
+ )
+ },
+ null
+ )
}
override fun setObservable() {
super.setObservable()
+ // 绑定刷新布局与 ViewModel 刷新状态
viewModel.refreshLiveData.fastObserve(this, binding.refreshLayout)
+ // 监听数据变化并刷新列表
viewModel.dataList.observe(this) {
adapter.setList(it)
}
@@ -60,13 +105,16 @@
override fun setListener() {
with(binding.refreshLayout) {
+ // 下拉刷新
setOnRefreshListener {
viewModel.refreshData()
}
+ // 上拉加载更多
setOnLoadMoreListener {
viewModel.loadMoreData()
}
}
+ // 搜索框回车监听
binding.searchEt.setOnKeyListener { _, keyCode, event ->
if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_UP) {
if (viewModel.search.value.isNullOrEmpty()) {
@@ -77,6 +125,7 @@
}
false
}
+ // 确认按钮:选中车辆后跳转创建任务
binding.tvControl.setOnClickListener {
if (viewModel.selectCar == null) {
ToastUtilCommon.showWarn("请先选择一辆车辆")
@@ -89,17 +138,24 @@
startActivity(CreateTaskActivity::class.java, bundleOf("car" to viewModel.selectCar))
}
+ // 筛选按钮:先查询区域数据再展示弹窗
binding.filter.setOnClickListener {
viewModel.queryAreas { showFilterDialog() }
}
}
+ /** 初始化 RecyclerView 适配器 */
private fun initAdapter() {
adapter.selectCar = viewModel.selectCar
binding.rv.adapter = adapter
binding.rv.layoutManager = LinearLayoutManager(this)
}
+ /**
+ * 列表项点击事件,更新选中状态与底部按钮样式
+ *
+ * @param item 点击的车辆数据
+ */
override fun onItemClick(item: CarModel) {
viewModel.selectCar = adapter.selectCar
binding.tvControl.backgroundTintList = ContextCompat.getColorStateList(
@@ -114,9 +170,14 @@
// super.onBackPressedHandel()
// }
+ /**
+ * 显示车辆筛选弹窗
+ *
+ * 包含区域多选与运营状态单选/多选逻辑,支持"全部"互斥处理。
+ */
private fun showFilterDialog() {
if (filterDialog == null) {
- filterDialog = MaterialDialog(this).apply {
+ filterDialog = DialogFactory.produce(this).apply {
customView(
com.xw.yunwei.R.layout.dialog_car_filter,
noVerticalPadding = true,
@@ -132,13 +193,15 @@
bind.stllArea.remove()
bind.stllStatus.remove()
+ // 初始化区域筛选数据
bind.stllArea.setData(
- viewModel.filterAreas.map { it.electronicName?:"" },
+ viewModel.filterAreas.map { it.electronicName ?: "" },
this@SelectCarActivity,
ArrayList(),
this@SelectCarActivity.resources.getColor(R.color.blue_5),
"shape_blue1_bg_4"
)
+ // 初始化运营状态筛选数据
bind.stllStatus.setData(
viewModel.filterStatus,
this@SelectCarActivity,
@@ -147,6 +210,7 @@
"shape_blue1_bg_4"
)
+ // 区域点击监听:维护选中区域列表
bind.stllArea.setListener {
val index = it.tag as Int // 当前点击的下标
if (bind.stllArea.selectIndexList.contains(index)) {
@@ -157,6 +221,7 @@
bind.stllArea.onTvClick(index)
}
+ // 运营状态点击监听:处理"全部"与其他状态的互斥逻辑
bind.stllStatus.setListener {
val index = it.tag as Int // 当前点击的下标
if (index == 0) { // 选择全部 取消其他
@@ -183,9 +248,24 @@
}
bind.close.setOnClickListener { dismiss() }
- bind.btnLeft.setOnClickListener { dismiss() }
+ bind.btnLeft.setOnClickListener {
+ val odlIndex = mutableListOf<Int>()
+ for (index in bind.stllArea.selectIndexList) { // 先取消选中状态
+ odlIndex.add(index)
+ }
+ odlIndex.forEach { bind.stllArea.onTvClick(it) }
+ viewModel.selectArea.clear()
+
+ odlIndex.clear()
+ for (index in bind.stllStatus.selectIndexList) { // 先取消选中状态
+ odlIndex.add(index)
+ }
+ odlIndex.forEach { bind.stllStatus.onTvClick(it) }
+ viewModel.selectStatus.clear()
+ }
bind.btnRight.setOnClickListener {
viewModel.refreshData()
+ refreshFilterStatus()
dismiss()
}
}
diff --git a/app/src/main/java/com/xw/yunwei/ui/task/selectCar/SelectCarAdapter.kt b/app/src/main/java/com/xw/yunwei/ui/task/selectCar/SelectCarAdapter.kt
index 3270826..3ab1018 100644
--- a/app/src/main/java/com/xw/yunwei/ui/task/selectCar/SelectCarAdapter.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/task/selectCar/SelectCarAdapter.kt
@@ -6,67 +6,40 @@
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.xw.common.base.OnItemClickListener
import com.xw.common.utils.BindUtils.getResColor
-import com.xw.common.utils.BindUtils.getUrl
import com.xw.common.viewAdapter.ImageDefault
import com.xw.common.viewAdapter.ViewAdapter
import com.xw.yunwei.R
import com.xw.yunwei.databinding.ItemSelectCarBinding
+import com.xw.yunwei.extension.colorIdToColorValue
import com.xw.yunwei.model.CarModel
+/**
+ * 选择车辆列表适配器
+ *
+ * 展示车辆基本信息(车牌号、颜色、编码、车辆照片),
+ * 根据运营状态显示不同颜色标签,并支持单选高亮效果。
+ *
+ * @property listener 列表项点击事件回调
+ */
class SelectCarAdapter(var listener: OnItemClickListener<CarModel>) :
BaseQuickAdapter<CarModel, BaseViewHolder>(R.layout.item_select_car) {
+ /** 当前选中的车辆,为空表示未选择 */
var selectCar: CarModel? = null
@SuppressLint("SetTextI18n", "NotifyDataSetChanged")
override fun convert(holder: BaseViewHolder, item: CarModel) {
val binding = DataBindingUtil.bind<ItemSelectCarBinding>(holder.itemView)
binding?.let {
- var url = ""
- try {
- url = item.vehiclePictures?.getUrl() ?: ""
- } catch (e: Exception) {
- }
- ViewAdapter.loadImage(binding.icon, ImageDefault(url, R.mipmap.img_work_car))
+ // 加载车辆图片,异常时显示默认车辆图
+ ViewAdapter.loadImage(binding.icon, ImageDefault(item.getShowVehiclePicture(), R.mipmap.img_work_car))
binding.name.text = item.plateNumber
- binding.color.text = "${item.vehicleColor} | 车身编码:${item.vehicleCode}"
+ binding.color.text = "${item.vehicleColor} | 车身编码:${item.getShowVehicleCode(6)}"
+ binding.status.setBackgroundResource(item.getShowStatusBgResource())
+ binding.status.setTextColor(item.getShowStatusTextColor().colorIdToColorValue(it.root.context))
+ binding.status.text=item.getShowStatus()
- val setStatus: (Int, Int) -> Unit = { text, bg ->
- binding.status.setTextColor(text)
- binding.status.setBackgroundResource(bg)
- }
-
- // 1=运营中 2=维修中 3=已收车 4=车辆异常
- when (item.operatingStatus) {
- 1 -> {
- setStatus(
- getResColor(com.xw.common.R.color.blue_5), com.xw.common.R.color.blue_1
- )
- binding.status.text = "运营中"
- }
-
- 2 -> {
- setStatus(
- getResColor(com.xw.common.R.color.red_5), com.xw.common.R.color.red_1
- )
- binding.status.text = "维修中"
- }
-
- 3 -> {
- setStatus(
- getResColor(com.xw.common.R.color.gray_7), com.xw.common.R.color.gray_3
- )
- binding.status.text = "已收车"
- }
-
- 4 -> {
- setStatus(
- getResColor(com.xw.common.R.color.orange_5), com.xw.common.R.color.orange_1
- )
- binding.status.text = "车辆异常"
- }
- }
-
+ // 选中状态高亮:变更背景与文字颜色
if (item.id == selectCar?.id) {
binding.llContent.setBackgroundColor(getResColor(com.xw.common.R.color.blue_1))
binding.name.setTextColor(getResColor(com.xw.common.R.color.blue_5))
@@ -77,6 +50,7 @@
binding.color.setTextColor(getResColor(com.xw.common.R.color.gray_7))
}
it.root.setOnClickListener {
+ // 切换选中状态:再次点击取消选中
selectCar = if (selectCar == item) null else item
notifyDataSetChanged()
listener.onItemClick(item)
diff --git a/app/src/main/java/com/xw/yunwei/ui/task/selectCar/SelectCarVM.kt b/app/src/main/java/com/xw/yunwei/ui/task/selectCar/SelectCarVM.kt
index a5213f7..2f3fa13 100644
--- a/app/src/main/java/com/xw/yunwei/ui/task/selectCar/SelectCarVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/task/selectCar/SelectCarVM.kt
@@ -12,30 +12,61 @@
import org.koin.core.component.inject
import kotlin.getValue
+/**
+ * 选择车辆页面视图模型
+ *
+ * 负责车辆列表的分页加载、关键词搜索、区域与运营状态筛选。
+ * 支持懒加载区域数据,并在筛选条件变化时触发列表刷新。
+ */
class SelectCarVM(myApplication: Application) : BasePagingViewModel(myApplication) {
+ /** 工作台数据仓库 */
val workRepository: WorkRepository by inject()
+ /** 搜索关键词(车牌号) */
val search = MutableLiveData("")
+ /** 车辆列表数据 */
val dataList: MutableLiveData<List<CarModel>> = MutableLiveData()
+ /** 当前选中的车辆 */
var selectCar: CarModel? = null
+ /** 可选区域列表,从接口懒加载 */
val filterAreas = mutableListOf<AreaModel>()
+ /** 运营状态筛选选项 */
val filterStatus = listOf(
"全部",
"运营中",
- "维修中",
+ "出车中",
+ "接单中",
+ "停止接单",
"已收车",
"车辆异常",
+ "维修中",
+ "充电中",
)
+ /** 用户已选中的区域列表 */
val selectArea = mutableListOf<AreaModel>()
+ /** 用户已选中的运营状态列表 */
val selectStatus = mutableListOf<String>()
+ /** 统一点击事件处理:搜索按钮 */
var onClick = View.OnClickListener {
when (it.id) {
R.id.search -> refreshData()
}
}
+ //是否已经筛选
+ fun hadFilter(): Boolean {
+ return selectArea.isNotEmpty() || selectStatus.count { it != filterStatus[0] } > 0
+ }
+
+ /**
+ * 获取车辆列表数据
+ *
+ * 根据当前搜索词、选中区域和运营状态组装请求参数,支持分页加载。
+ *
+ * @param index 页码,1 表示刷新,大于 1 表示加载更多
+ */
override fun getDataList(index: Int) {
if (index == 1) {
refreshLiveData.refresh()
@@ -50,15 +81,17 @@
map["pageNum"] = index
map["pageSize"] = pageSize
map["plateNumber"] = search.value // 查询参数
+ // 1=运营中,2=出车中,3=接单中,4=停止接单,5=已收车,6=车辆异常,7=维修中,8=充电中
map["status"] =
if (selectStatus.contains("全部")) null
else {
if (selectStatus.isNotEmpty()) selectStatus.map { filterStatus.indexOf(it) }.joinToString(",")
- else null // 运营状态 1运营中 2维修中 3已收车 4车辆异常
+ else null
}
+ // 围栏 id:多个区域用逗号拼接
map["electronicId"] =
if (selectArea.isNotEmpty()) selectArea.map { it.id ?: 0L }.joinToString(",")
- else null// 围栏id
+ else null
val data = workRepository.queryCars(map)
val list: MutableList<CarModel> = ArrayList()
@@ -79,6 +112,13 @@
}
}
+ /**
+ * 查询区域列表
+ *
+ * 若已缓存则直接回调,否则请求接口并缓存结果。
+ *
+ * @param block 数据准备好后的回调,用于展示筛选弹窗
+ */
fun queryAreas(block: () -> Unit) {
if (filterAreas.isEmpty()) {
launchRequest {
diff --git a/app/src/main/java/com/xw/yunwei/ui/task/taskDetail/TaskDetailActivity.kt b/app/src/main/java/com/xw/yunwei/ui/task/taskDetail/TaskDetailActivity.kt
index 423918b..3595472 100644
--- a/app/src/main/java/com/xw/yunwei/ui/task/taskDetail/TaskDetailActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/task/taskDetail/TaskDetailActivity.kt
@@ -1,8 +1,8 @@
package com.xw.yunwei.ui.task.taskDetail
-import com.xw.common.base.BaseActivity
import com.xw.common.base.OnItemClickListener
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.databinding.ActivityTaskDetailBinding
@@ -10,7 +10,7 @@
* 任务详情 已处理
*/
class TaskDetailActivity :
- BaseActivity<ActivityTaskDetailBinding, TaskDetailVM>(), OnItemClickListener<Any> {
+ BaseBusinessActivity<ActivityTaskDetailBinding, TaskDetailVM>(), OnItemClickListener<Any> {
override fun setListener() {
super.setListener()
diff --git a/app/src/main/java/com/xw/yunwei/ui/task/taskSub/TaskSubActivity.kt b/app/src/main/java/com/xw/yunwei/ui/task/taskSub/TaskSubActivity.kt
index 51f74f9..ea0fac2 100644
--- a/app/src/main/java/com/xw/yunwei/ui/task/taskSub/TaskSubActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/task/taskSub/TaskSubActivity.kt
@@ -1,8 +1,8 @@
package com.xw.yunwei.ui.task.taskSub
-import com.xw.common.base.BaseActivity
import com.xw.common.base.OnItemClickListener
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.databinding.ActivityTaskSubBinding
@@ -19,7 +19,7 @@
* 保险
*/
class TaskSubActivity :
- BaseActivity<ActivityTaskSubBinding, TaskSubVM>(), OnItemClickListener<Any> {
+ BaseBusinessActivity<ActivityTaskSubBinding, TaskSubVM>(), OnItemClickListener<Any> {
override fun setListener() {
super.setListener()
diff --git a/app/src/main/java/com/xw/yunwei/ui/user/login/LoginActivity.kt b/app/src/main/java/com/xw/yunwei/ui/user/login/LoginActivity.kt
index f3585c8..540dc0b 100644
--- a/app/src/main/java/com/xw/yunwei/ui/user/login/LoginActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/user/login/LoginActivity.kt
@@ -1,25 +1,24 @@
package com.xw.yunwei.ui.user.login
-import android.annotation.SuppressLint
import android.graphics.Color
+import android.text.InputType
import android.text.TextPaint
+import android.text.TextUtils
import android.text.method.HideReturnsTransformationMethod
import android.text.method.LinkMovementMethod
import android.text.method.PasswordTransformationMethod
import android.text.style.ClickableSpan
+import android.view.Gravity
import android.view.View
import android.webkit.WebSettings
import android.webkit.WebView
import android.widget.Button
import androidx.appcompat.widget.AppCompatEditText
import androidx.core.os.bundleOf
-import androidx.core.view.isGone
-import androidx.databinding.DataBindingUtil
-import com.afollestad.materialdialogs.MaterialDialog
-import com.afollestad.materialdialogs.customview.customView
-import com.afollestad.materialdialogs.customview.getCustomView
+import androidx.lifecycle.Observer
import com.blankj.utilcode.util.SpanUtils
import com.google.android.material.tabs.TabLayout
+import com.xw.common.CommonDialog
import com.xw.common.Constants
import com.xw.common.R
import com.xw.common.base.BaseActivity
@@ -29,7 +28,7 @@
import com.xw.yunwei.BR
import com.xw.yunwei.MyApp
import com.xw.yunwei.databinding.ActivityLoginBinding
-import com.xw.yunwei.databinding.DialogProtocolBinding
+import com.xw.yunwei.model.AgreeInfo
import com.xw.yunwei.ui.MainActivity
import com.xw.yunwei.ui.work.car.detail.StandardDescriptionActivity
@@ -38,11 +37,11 @@
override fun init() {
super.init()
-
if (Constants.token.isNotEmpty()) {
startActivity(MainActivity::class.java)
finish()
} else {
+ MyApp.myApp.disconnectWebSocket()
MyApp.myApp.unbindPushAccount()
viewModel.tabs.forEach {
@@ -52,66 +51,46 @@
)
}
- val protocol =
- SpanUtils().append("我已阅读并同意")
- .setForegroundColor(getResColor(R.color.gray_9))
- .append("《小鹏Robotaxi自动驾驶出行运维隐私政策》").setBold()
- .setForegroundColor(getResColor(R.color.blue_5))
- .setClickSpan(object : ClickableSpan() {
- override fun onClick(widget: View) {
-// showProtocolDialog(1)
- startActivity(
- StandardDescriptionActivity::class.java,
- bundleOf("type" to 8, "webType" to 1)
- )
- }
-
- override fun updateDrawState(ds: TextPaint) {}
- })
- .append("《第三方共享信息清单》").setBold()
- .setForegroundColor(getResColor(R.color.blue_5))
- .setClickSpan(object : ClickableSpan() {
- override fun onClick(widget: View) {
-// showProtocolDialog(2)
- startActivity(
- StandardDescriptionActivity::class.java,
- bundleOf("type" to 9, "webType" to 1)
- )
- }
-
- override fun updateDrawState(ds: TextPaint) {}
- })
- .append("《个人信息收集清单》").setBold()
- .setForegroundColor(getResColor(R.color.blue_5))
- .setClickSpan(object : ClickableSpan() {
- override fun onClick(widget: View) {
- startActivity(
- StandardDescriptionActivity::class.java,
- bundleOf("type" to 10, "webType" to 1)
- )
- }
-
- override fun updateDrawState(ds: TextPaint) {}
- })
- .append("《权限调用》").setBold()
- .setForegroundColor(getResColor(R.color.blue_5))
- .setClickSpan(object : ClickableSpan() {
- override fun onClick(widget: View) {
- startActivity(
- StandardDescriptionActivity::class.java,
- bundleOf("type" to 11, "webType" to 1)
- )
- }
-
- override fun updateDrawState(ds: TextPaint) {}
- })
- .create()
-
- binding.protocol.text = protocol
- binding.protocol.highlightColor = Color.TRANSPARENT
- binding.protocol.movementMethod = LinkMovementMethod.getInstance()
+ viewModel.getAgreeConfig()
}
+ }
+
+ //获取协议文案
+ private fun getAgreeText(
+ prefix: String,
+ prefixTextColor: Int = R.color.gray_9,
+ list: List<AgreeInfo>,
+ agreeBold: Boolean = true,
+ agreeTextColor: Int = R.color.blue_5
+ ): CharSequence {
+ if (list.isEmpty()) {
+ return ""
+ }
+ val spanUtils = SpanUtils().append(prefix).setForegroundColor(getResColor(prefixTextColor))
+
+ list.forEach {
+ spanUtils.append("《${it.name ?: ""}》")
+ if (agreeBold) {
+ spanUtils.setBold()
+ }
+ spanUtils.setForegroundColor(getResColor(agreeTextColor))
+ .setClickSpan(object : ClickableSpan() {
+ override fun onClick(widget: View) {
+ startActivity(
+ StandardDescriptionActivity::class.java,
+ bundleOf(
+ "type" to it.id?.toInt(),
+ "webType" to 1,
+ "title" to it.name
+ )
+ )
+ }
+
+ override fun updateDrawState(ds: TextPaint) {}
+ })
+ }
+ return spanUtils.create()
}
override fun setListener() {
@@ -125,6 +104,36 @@
override fun onTabUnselected(tab: TabLayout.Tab?) {}
override fun onTabReselected(tab: TabLayout.Tab?) {}
+ })
+ binding.login.setOnClickListener {
+ val agreeText = getAgreeText(
+ prefix = "为了更好地保障您的合法权益,请您阅读并同意以下协议",
+ prefixTextColor = R.color.gray_9,
+ list = viewModel.agreeList.value ?: listOf(),
+ agreeBold = false,
+ agreeTextColor = R.color.gray_9
+ )
+ if (viewModel.protocolStatus.value != true && !TextUtils.isEmpty(agreeText)) {
+ CommonDialog.showNoticeDialog(
+ context = this,
+ title = "服务协议及隐私保护",
+ content = agreeText,
+ contentTextGravity = Gravity.START,
+ leftOperationText = "不同意",
+ rightOperationText = "同意",
+ rightOperationBlock = {
+ viewModel.protocolStatus.value = true
+ viewModel.login()
+ return@showNoticeDialog true
+ })
+ return@setOnClickListener
+ }
+ viewModel.login()
+ }
+ viewModel.agreeList.observe(this, Observer<List<AgreeInfo>> {
+ binding.protocol.text = getAgreeText(prefix = "我已阅读并同意", list = it)
+ binding.protocol.highlightColor = Color.TRANSPARENT
+ binding.protocol.movementMethod = LinkMovementMethod.getInstance()
})
}
@@ -141,7 +150,6 @@
binding.psw.visibility=View.GONE
binding.eye2.visibility=View.GONE
binding.vPswLine.visibility=View.GONE
- binding.forgetPsw.visibility=View.GONE
}
viewModel.hadCheckMobilePasswordLogin() -> {
@@ -150,7 +158,6 @@
binding.psw.visibility=View.VISIBLE
binding.eye2.visibility=View.VISIBLE
binding.vPswLine.visibility=View.VISIBLE
- binding.forgetPsw.visibility=View.VISIBLE
}
}
}
@@ -186,198 +193,5 @@
}
// 关键:切换后需要将光标移到最后,防止光标跳到开头
et.setSelection(et.text?.length ?: 0)
- }
-
- // 标记两个协议是否都已读到底部
- private var userProtocolRead = false
- private var privacyProtocolRead = false
- private var currentTab = 1 // 当前选中标签
- fun showProtocolDialog(type: Int) {
- MaterialDialog(this).cornerRadius(15f).cancelable(true).show {
- customView(
- com.xw.yunwei.R.layout.dialog_protocol,
- noVerticalPadding = true,
- dialogWrapContent = true
- )
- DataBindingUtil.bind<DialogProtocolBinding>(getCustomView())?.let { bind ->
- // 初始禁用确认按钮
- bind.btnRight.isEnabled = false
- // bind.btnRight.alpha = 0.5f
- bind.btnRight.setTextColor(getResColor(R.color.gray_7))
-
- val tab1 = bind.protocolLayout.tabLayout.newTab().apply { text = "用户协议" }
- val tab2 = bind.protocolLayout.tabLayout.newTab().apply { text = "隐私条款" }
-
- bind.protocolLayout.tabLayout.addTab(tab1, type == 1)
- bind.protocolLayout.tabLayout.addTab(tab2, type == 2)
- bind.btnLeft.setOnClickListener { dismiss() }
- bind.btnRight.setOnClickListener {
- viewModel.protocolStatus.value = true
- dismiss()
- }
- initWeb(bind.protocolLayout.web, bind.btnRight)
-
- val getProtocol: (Int) -> Unit = { type ->
- currentTab = type
- viewModel.getProtocol(type) {
- setContent(bind.protocolLayout.web, it, bind.btnRight)
- }
- }
-
- getProtocol(type)
- bind.protocolLayout.tabLayout.addOnTabSelectedListener(object :
- TabLayout.OnTabSelectedListener {
- override fun onTabSelected(tab: TabLayout.Tab?) {
- tab?.let {
- when (it.text) {
- "用户协议" -> getProtocol(1)
- "隐私条款" -> getProtocol(2)
- else -> {}
- }
- }
- }
-
- override fun onTabUnselected(tab: TabLayout.Tab?) {}
- override fun onTabReselected(tab: TabLayout.Tab?) {}
- })
-
- }
- }
- }
-
- @SuppressLint("SetJavaScriptEnabled")
- private fun initWeb(webView: WebView, confirmBtn: Button) {
- //声明WebSettings子类
- val webSettings = webView.settings
- webSettings.domStorageEnabled = true //设置适应Html5
-
- //如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
- webSettings.javaScriptEnabled = true //允许js调用
- webSettings.allowFileAccess = true //在File域下,能够执行任意的JavaScript代码,同源策略跨域访问能够对私有目录文件进行访问等
- webSettings.allowContentAccess = true //是否允许在WebView中访问内容URL(Content Url),默认允许
-
- //缩放操作
- webSettings.setSupportZoom(true) //支持缩放,默认为true。是下面那个的前提。
- webSettings.builtInZoomControls = true //设置内置的缩放控件。若为false,则该WebView不可缩放
- webSettings.displayZoomControls = false //隐藏原生的缩放控件
-
- //其他细节操作
- webSettings.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK //关闭webview中缓存
- webSettings.allowFileAccess = true //设置可以访问文件
- webSettings.javaScriptCanOpenWindowsAutomatically = true //支持通过JS打开新窗口
- webSettings.loadsImagesAutomatically = true //支持自动加载图片
- webSettings.defaultTextEncodingName = "utf-8" //设置编码格式
-
- // 关键:添加滚动监听
- webView.setOnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
- // 只有向下滑动时才检测
- if (scrollY > oldScrollY) {
- checkScrollBottom(webView, confirmBtn)
- }
- }
- }
-
- @SuppressLint("SetJavaScriptEnabled")
- private fun setContent(webView: WebView, content: String?, confirmBtn: Button) {
- content?.let {
- webView.loadDataWithBaseURL(null, it, "text/html", "utf-8", null)
-
-// confirmBtn.text = if(currentTab == 1) "请阅读协议" else "请阅读条款"
- // 禁用按钮直到滚动到底
- confirmBtn.isEnabled = false
-// confirmBtn.alpha = 0.5f
- confirmBtn.setTextColor(getResColor(R.color.gray_7))
-
-
- // 页面加载完成后延迟检查(确保内容渲染完成)
- webView.postDelayed({
- checkScrollBottom(webView, confirmBtn)
- }, 500)
- }
- }
-
- /**
- * 检测是否滚动到底部
- */
- private fun checkScrollBottom(webView: WebView, confirmBtn: Button) {
- webView.evaluateJavascript(
- """
- (function() {
- var scrollHeight = Math.max(
- document.body.scrollHeight,
- document.documentElement.scrollHeight,
- document.body.offsetHeight,
- document.documentElement.offsetHeight,
- document.body.clientHeight,
- document.documentElement.clientHeight
- );
- var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
- var clientHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight || 0;
-
- // 计算距离底部距离,允许20px误差
- var distanceToBottom = scrollHeight - scrollTop - clientHeight;
- return distanceToBottom <= 20;
- })();
- """.trimIndent()
- ) { result ->
- val isBottom = result?.trim() == "true"
-
- if (isBottom) {
- // 标记当前协议已读
- when (currentTab) {
- 1 -> userProtocolRead = true
- 2 -> privacyProtocolRead = true
- }
- updateButtonState(confirmBtn)
- }
- }
- }
-
- /**
- * 更新按钮状态:两个协议都必须阅读完才能点击
- */
- private fun updateButtonState(confirmBtn: Button) {
- val allRead = userProtocolRead && privacyProtocolRead
-
- if (allRead && !confirmBtn.isEnabled) {
- confirmBtn.isEnabled = true
-// confirmBtn.alpha = 1.0f
- confirmBtn.setTextColor(getResColor(R.color.blue_5))
- confirmBtn.text = "同意并继续"
-
- // 可选:启用动画
- confirmBtn.animate()
- .scaleX(1.05f)
- .scaleY(1.05f)
- .setDuration(150)
- .withEndAction {
- confirmBtn.animate()
- .scaleX(1.0f)
- .scaleY(1.0f)
- .setDuration(150)
- .start()
- }
- .start()
- } else if (!allRead) {
- confirmBtn.isEnabled = false
-// confirmBtn.alpha = 0.5f
- confirmBtn.setTextColor(getResColor(R.color.gray_7))
-
- // 提示还需阅读哪个协议
-// val hint = if(currentTab == 1){
-// when {
-// !userProtocolRead -> "请阅读协议"
-// !privacyProtocolRead -> "请阅读条款"
-// else -> "请阅读协议"
-// }
-// }else{
-// when {
-// !privacyProtocolRead -> "请阅读条款"
-// !userProtocolRead -> "请阅读协议"
-// else -> "请阅读协议"
-// }
-// }
-// confirmBtn.text = hint
- }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/user/login/LoginVM.kt b/app/src/main/java/com/xw/yunwei/ui/user/login/LoginVM.kt
index 353fb5a..34da2d6 100644
--- a/app/src/main/java/com/xw/yunwei/ui/user/login/LoginVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/user/login/LoginVM.kt
@@ -10,12 +10,15 @@
import com.xw.common.utils.MMKVManager
import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.BuildConfig
+import com.xw.yunwei.MyApp
import com.xw.yunwei.R
import com.xw.yunwei.extension.encryptByPublicKey
+import com.xw.yunwei.model.AgreeInfo
import com.xw.yunwei.model.PasswordLoginCodeValidateInfo
import com.xw.yunwei.net.UserRepository
import com.xw.yunwei.net.YiHuRepository
import com.xw.yunwei.ui.MainActivity
+import com.xw.yunwei.ui.common.WebActivity
import org.koin.core.component.inject
class LoginVM(application: Application) : BaseViewModel(application) {
@@ -40,9 +43,14 @@
val eyeStatus2 = MutableLiveData(false)
val protocolStatus = MutableLiveData(false)
+ private var loginFailCount = 0
+ private var lastFailTime = 0L
//账号密码验证码验证信息
var passwordLoginCodeValidateInfo: PasswordLoginCodeValidateInfo? = null
+
+ //协议列表
+ val agreeList: MutableLiveData<List<AgreeInfo>> = MutableLiveData(mutableListOf<AgreeInfo>())
val onClick = View.OnClickListener {
when (it.id) {
R.id.protocolStatus -> protocolStatus.value = !protocolStatus.value!!
@@ -53,6 +61,13 @@
R.id.submit -> modifyPsw()
R.id.eye1 -> eyeStatus1.value = !eyeStatus1.value!!
R.id.eye2 -> eyeStatus2.value = !eyeStatus2.value!!
+ R.id.tv_rest_psw -> startActivity(
+ WebActivity::class.java,
+ WebActivity.getParams(
+ "https://xpsso.xiaopeng.com/sso_login_page/forget.html",
+ "重置密码"
+ )
+ )
}
}
@@ -64,7 +79,7 @@
fun hadCheckMobilePasswordLogin() =
tabs.contains(mobilePasswordTab) && tabIndex.value == tabs.indexOf(mobilePasswordTab)
- private fun login() {
+ public fun login() {
if (protocolStatus.value != true) {
ToastUtilCommon.showWarn("请先阅读并同意用户协议和隐私政策")
return
@@ -84,22 +99,29 @@
ToastUtilCommon.showError("请输入验证码!")
return
}
- launchRequestFlow(tips = "登录中...", flowBlock = {
- yiHuRepository.login(phone.value!!, code.value!!)
- }, onCollect = { yiHuData ->
- yiHuData?.let {
- launchRequest(tips = "登录中...") {
- val data = userRepository.loginByThirdToken(yiHuData.access_token!!)
- data?.let {
- Constants.token = it.token?.access_token ?: ""
- MMKVManager.getInstance()
- .saveModel(KeyPreferences.USER, it.info?.xpOperationsUser)
- startActivity(MainActivity::class.java)
- finish()
+ launchRequestFlow(
+ tips = "登录中...",
+ flowBlock = {
+ yiHuRepository.login(phone.value!!, code.value!!)
+ },
+ onCollect = { yiHuData ->
+ yiHuData?.let {
+ launchRequest(tips = "登录中...") {
+ val data = userRepository.loginByThirdToken(yiHuData.access_token!!)
+ data?.let {
+ Constants.token = it.token?.access_token ?: ""
+ MMKVManager.getInstance()
+ .saveModel(KeyPreferences.USER, it.info?.xpOperationsUser)
+ MMKVManager.getInstance()
+ .saveModel(KeyPreferences.THIRD, it.thirdInfo)
+ MyApp.myApp.initPush()
+ startActivity(MainActivity::class.java)
+ finish()
+ }
}
}
}
- })
+ )
}
private fun loginByPassword() {
@@ -107,11 +129,11 @@
ToastUtilCommon.showError("请输入手机号!")
return
}
- if (code.value.isNullOrEmpty()) {
+ if (code.value.isNullOrEmpty() && !BuildConfig.DEBUG) {
ToastUtilCommon.showError("请输入验证码!")
return
}
- if (passwordLoginCodeValidateInfo == null) {
+ if (passwordLoginCodeValidateInfo == null && !BuildConfig.DEBUG) {
ToastUtilCommon.showError("请重新获取验证码!")
return
}
@@ -119,27 +141,89 @@
ToastUtilCommon.showError("请输入密码!")
return
}
- launchRequestFlow(tips = "登录中...", flowBlock = {
- yiHuRepository.passwordLogin(
- phone.value!!,
- code.value!!,
- psw.value!!.encryptByPublicKey(BuildConfig.YIHU_PUBLIC_KEY),
- passwordLoginCodeValidateInfo!!.randomKey
- )
- }, onCollect = { yiHuData ->
- yiHuData?.let {
- launchRequest(tips = "登录中...") {
- val data = userRepository.loginByThirdToken(yiHuData.access_token!!)
+ val psw = psw.value ?: ""
+ if (psw.length < 8) {
+ ToastUtilCommon.showError("密码长度至少8位!")
+ return
+ }
+ if (!psw.matches(Regex(".*[A-Z].*")) && !BuildConfig.DEBUG) {
+ ToastUtilCommon.showError("密码需包含大写字母!")
+ return
+ }
+ if (!psw.matches(Regex(".*[a-z].*")) && !BuildConfig.DEBUG) {
+ ToastUtilCommon.showError("密码需包含小写字母!")
+ return
+ }
+ if (!psw.matches(Regex(".*[0-9].*"))) {
+ ToastUtilCommon.showError("密码需包含数字!")
+ return
+ }
+ val now = System.currentTimeMillis()
+ if (loginFailCount >= 5 && now - lastFailTime < 60_000) {
+ ToastUtilCommon.showError("登录失败次数过多,请1分钟后重试")
+ return
+ }
+ if (BuildConfig.DEBUG && BuildConfig.DEV_API_HOST.isNotEmpty()) {
+ launchRequestFlow(
+ tips = "登录中...",
+ flowBlock = {
+ val map =
+ mapOf("phoneNumber" to phone.value, "password" to psw, "deviceType" to 1)
+ userRepository.loginByPassword(map)
+ },
+ error = { code, msg ->
+ ToastUtilCommon.showError(msg)
+ loginFailCount++
+ lastFailTime = System.currentTimeMillis()
+ },
+ onCollect = { data ->
data?.let {
Constants.token = it.token?.access_token ?: ""
MMKVManager.getInstance()
.saveModel(KeyPreferences.USER, it.info?.xpOperationsUser)
+ MMKVManager.getInstance()
+ .saveModel(KeyPreferences.THIRD, it.thirdInfo)
+ MyApp.myApp.initPush()
startActivity(MainActivity::class.java)
finish()
}
}
+ )
+ return
+ }
+ launchRequestFlow(
+ tips = "登录中...",
+ flowBlock = {
+ yiHuRepository.passwordLogin(
+ phone.value!!,
+ code.value!!,
+ psw.encryptByPublicKey(BuildConfig.YIHU_PUBLIC_KEY),
+ passwordLoginCodeValidateInfo!!.randomKey
+ )
+ },
+ error = { code, msg ->
+ ToastUtilCommon.showError(msg)
+ loginFailCount++
+ lastFailTime = System.currentTimeMillis()
+ },
+ onCollect = { yiHuData ->
+ yiHuData?.let {
+ launchRequest(tips = "登录中...") {
+ val data = userRepository.loginByThirdToken(yiHuData.access_token!!)
+ data?.let {
+ Constants.token = it.token?.access_token ?: ""
+ MMKVManager.getInstance()
+ .saveModel(KeyPreferences.USER, it.info?.xpOperationsUser)
+ MMKVManager.getInstance()
+ .saveModel(KeyPreferences.THIRD, it.thirdInfo)
+ MyApp.myApp.initPush()
+ startActivity(MainActivity::class.java)
+ finish()
+ }
+ }
+ }
}
- })
+ )
}
/**
@@ -167,23 +251,28 @@
}
return
}
- launchRequestFlow(tips = "验证码获取中...", flowBlock = {
- if (hadCheckMobileCodeLogin()) {
- yiHuRepository.getPhoneLoginCode(phone.value!!)
- } else {
- yiHuRepository.getPasswordLoginCode(phone.value!!)
+ launchRequestFlow(
+ tips = "验证码获取中...",
+ flowBlock = {
+ if (hadCheckMobileCodeLogin()) {
+ yiHuRepository.getPhoneLoginCode(phone.value!!)
+ } else {
+ yiHuRepository.getPasswordLoginCode(phone.value!!)
+ }
+ },
+ error = { code, msg ->
+ canGetCode.postValue(true)
+ timer.cancel()
+ codeTips.postValue("重新发送")
+ ToastUtilCommon.showError(msg)
+ },
+ onCollect = { data ->
+ ToastUtilCommon.showSuc("验证码已发送")
+ if (hadCheckMobilePasswordLogin()) {
+ passwordLoginCodeValidateInfo = data as PasswordLoginCodeValidateInfo?
+ }
}
- }, error = { code, msg ->
- canGetCode.postValue(true)
- timer.cancel()
- codeTips.postValue("重新发送")
- ToastUtilCommon.showError(msg)
- }, onCollect = { data ->
- ToastUtilCommon.showSuc("验证码已发送")
- if (hadCheckMobilePasswordLogin()) {
- passwordLoginCodeValidateInfo = data as PasswordLoginCodeValidateInfo?
- }
- })
+ )
}
}
@@ -200,20 +289,29 @@
ToastUtilCommon.showError("请输入密码!")
return
}
- if (psw.value!!.length < 6) {
- ToastUtilCommon.showError("密码长度至少6位!")
- return
- }
if (pswConfirm.value.isNullOrEmpty()) {
ToastUtilCommon.showError("请再次输入密码!")
return
}
- if (pswConfirm.value!!.length < 6) {
- ToastUtilCommon.showError("密码长度至少6位!")
- return
- }
if (psw.value != pswConfirm.value) {
ToastUtilCommon.showError("两次密码不一致!")
+ return
+ }
+ val psw = psw.value ?: ""
+ if (psw.length < 8) {
+ ToastUtilCommon.showError("密码长度至少8位!")
+ return
+ }
+ if (!psw.matches(Regex(".*[A-Z].*"))) {
+ ToastUtilCommon.showError("密码需包含大写字母!")
+ return
+ }
+ if (!psw.matches(Regex(".*[a-z].*"))) {
+ ToastUtilCommon.showError("密码需包含小写字母!")
+ return
+ }
+ if (!psw.matches(Regex(".*[0-9].*"))) {
+ ToastUtilCommon.showError("密码需包含数字!")
return
}
@@ -221,7 +319,7 @@
val map = mapOf(
"phoneNumber" to phone.value,
"verificationCode" to code.value,
- "newPassword" to psw.value,
+ "newPassword" to psw,
"confirmPassword" to pswConfirm.value,
)
userRepository.modifierPsw(map)
@@ -230,10 +328,11 @@
}
}
- fun getProtocol(type: Int, block: (String) -> Unit) {
- launchRequest(showLoading = false) {
- val data = userRepository.getProtocol(type)
- runOnMainThread { block(data?.content ?: "") }
+ /*获取协议配置 */
+ fun getAgreeConfig() {
+ launchRequest {
+ val data = userRepository.getAgreeConfig()
+ runOnMainThread { agreeList.postValue(data ?: mutableListOf()) }
}
}
diff --git a/app/src/main/java/com/xw/yunwei/ui/user/mine/MineFragment.kt b/app/src/main/java/com/xw/yunwei/ui/user/mine/MineFragment.kt
index ee32893..5de935c 100644
--- a/app/src/main/java/com/xw/yunwei/ui/user/mine/MineFragment.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/user/mine/MineFragment.kt
@@ -24,6 +24,7 @@
super.onResume()
viewModel.getInfo()
viewModel.querySchedule()
+ viewModel.getMyCruiseCheckInMissionInfo()
}
@SuppressLint("UseKtx")
@@ -48,7 +49,9 @@
binding.nav.setOnClickListener {
viewModel.clockModel.value?.let {
- if ((it.xpCheckLocation?.locationLat ?: 0.0) != 0.0 && (it.xpCheckLocation?.locationLon ?: 0.0) != 0.0) {
+ if ((it.xpCheckLocation?.locationLat
+ ?: 0.0) != 0.0 && (it.xpCheckLocation?.locationLon ?: 0.0) != 0.0
+ ) {
navigate(
end = LatLng(
it.xpCheckLocation?.locationLat!!,
@@ -73,11 +76,13 @@
binding.status.setTextColor(getResColor(com.xw.common.R.color.orange_5))
binding.status.setBackgroundResource(R.drawable.shape_orange_1_bg_4)
}
+
2 -> {
binding.status.text = "上班中"
binding.status.setTextColor(getResColor(com.xw.common.R.color.green_5))
binding.status.setBackgroundResource(R.drawable.shape_green_1_bg_4)
}
+
3 -> {
binding.status.text = "休息"
binding.status.setTextColor(getResColor(com.xw.common.R.color.gray_9))
@@ -85,6 +90,14 @@
}
}
}
+
+ viewModel.cruiseCheckInMissionInfo.observe(this) {
+ binding.tvMissionTime.text = viewModel.getFormateCruiseCheckInMissionTime()
+ binding.cpvProgress.setProgress(viewModel.getCruiseCheckInProgress(), true)
+ binding.tvMissionPointCount.text = it.checkInPointCount.toString()
+ binding.tvHadReportNum.text = it.checkInPointFinishCount.toString()
+ binding.tvNotReportNum.text = it.checkInPointUnFinishCount.toString()
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/user/mine/MineVM.kt b/app/src/main/java/com/xw/yunwei/ui/user/mine/MineVM.kt
index 7883125..a9f2f5c 100644
--- a/app/src/main/java/com/xw/yunwei/ui/user/mine/MineVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/user/mine/MineVM.kt
@@ -2,34 +2,35 @@
import android.app.Application
import android.view.View
-import androidx.core.os.bundleOf
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.map
import com.xw.common.Constants.gson
import com.xw.common.TimeDialog.Companion.getTime
import com.xw.common.base.BaseViewModel
import com.xw.common.utils.BindUtils.getUrl
-import com.xw.common.utils.KeyPreferences
-import com.xw.common.utils.MMKVManager
import com.xw.common.viewAdapter.ImageDefault
import com.xw.yunwei.R
+import com.xw.yunwei.extension.dateChangePattern
import com.xw.yunwei.model.ClockInStatusModel
-import com.xw.yunwei.model.UserInfo
+import com.xw.yunwei.model.CruiseCheckInMissionInfo
+import com.xw.yunwei.model.UserInfoRealtime
import com.xw.yunwei.net.UserRepository
+import com.xw.yunwei.net.WorkRepository
import com.xw.yunwei.ui.user.mine.checkin.CheckInActivity
import com.xw.yunwei.ui.user.mine.info.UserInfoActivity
import com.xw.yunwei.ui.user.mine.scheduling.SchedulingActivity
import com.xw.yunwei.ui.user.mine.set.SetActivity
import com.xw.yunwei.ui.user.mine.upload.CertUploadActivity
+import com.xw.yunwei.ui.work.checkInMission.CheckInMissionPointsListActivity
import org.json.JSONObject
import org.koin.core.component.inject
-import kotlin.getValue
class MineVM(application: Application) : BaseViewModel(application) {
val userRepository: UserRepository by inject()
+ val workRepository: WorkRepository by inject()
- val userInfo = MutableLiveData(MMKVManager.getInstance().getModel<UserInfo>(KeyPreferences.USER))
+ val userInfo = MutableLiveData<UserInfoRealtime>()
val avatar = MutableLiveData(ImageDefault("", com.xw.common.R.drawable.svg_avatar))
@@ -39,11 +40,19 @@
val clockModel: MutableLiveData<ClockInStatusModel> = MutableLiveData()
val clockTime = clockModel.map {
// "${it.xpShift?.startTime ?: ""} - ${it.xpShift?.restStartTime ?: ""} ${it.xpShift?.restEndTime ?: ""} - ${it.xpShift?.endTime ?: ""}"
- "${getTime(System.currentTimeMillis())} ${it?.xpShift?.startTime ?: ""}~${it?.xpShift?.endTime ?: ""}"
+ "${
+ getTime(
+ System.currentTimeMillis(),
+ "yyyy/MM/dd"
+ )
+ } ${it?.xpShift?.startTime ?: ""}~${it?.xpShift?.endTime ?: ""}"
}
val workFlag = MutableLiveData(0)
- var phone = "" // 客服电话
+ //巡游打卡任务
+ val cruiseCheckInMissionInfo = MutableLiveData<CruiseCheckInMissionInfo>()
+
+ var phone = MutableLiveData("") // 客服电话
val onClick = View.OnClickListener {
@@ -51,21 +60,40 @@
R.id.infoLayout -> startActivity(UserInfoActivity::class.java)
R.id.uploadLayout -> startActivity(CertUploadActivity::class.java)
R.id.setLayout -> startActivity(SetActivity::class.java)
- R.id.schedulingLayout -> startActivity(SchedulingActivity::class.java)
- R.id.goCheck -> startActivity(CheckInActivity::class.java,
- bundleOf("clockModel" to clockModel.value))
+ R.id.schedulingLayout, R.id.ll_empty -> startActivity(SchedulingActivity::class.java)
+ R.id.goCheck -> startActivity(
+ CheckInActivity::class.java,
+ CheckInActivity.getParams(
+ clockModel.value!!,
+ if (clockModel.value?.needWorkCheckIn() == true) 1 else 2
+ )
+ )
+
+ R.id.cv_task -> startActivity(
+ CheckInMissionPointsListActivity::class.java,
+ CheckInMissionPointsListActivity.getParams(cruiseCheckInMissionInfo.value!!.id)
+ )
}
}
+ override fun onCreate() {
+ super.onCreate()
+ getPhone()
+ }
fun getInfo() {
launchRequestFlow(
showLoading = false,
flowBlock = { userRepository.getUserInfo() },
onCollect = {
+ userInfo.postValue(it)
avatar.postValue(avatar.value!!.apply { this.url = it?.avatar?.getUrl() ?: "" })
- workFlag.postValue(it?.workFlag?:0)
- roleName.postValue(it?.roles?.getOrNull(0)?.roleName ?: "未分配")
+ workFlag.postValue(it?.workFlag ?: 0)
+ // 展示全部角色名称,用"、"拼接,与 iOS 保持一致;无角色时显示"未分配"
+ val roleNames = it?.roles
+ ?.mapNotNull { role -> role.roleName?.takeIf { name -> name.isNotBlank() } }
+ ?: emptyList()
+ roleName.postValue(if (roleNames.isEmpty()) "未分配" else roleNames.joinToString("、"))
fleetLeaderName.postValue(it?.fleet?.fleetLeaderName ?: "无")
fleetName.postValue(it?.fleet?.fleetName ?: "无")
}
@@ -74,23 +102,54 @@
fun querySchedule() {
launchRequest(showLoading = clockModel.value == null) {
- userRepository.querySchedule(mapOf("schedulingDate" to getTime(System.currentTimeMillis())))?.let {
- clockModel.postValue(it)
- }
+ userRepository.querySchedule(mapOf("schedulingDate" to getTime(System.currentTimeMillis())))
+ ?.let {
+ clockModel.postValue(it)
+ }
}
}
- fun getPhone(block: (String) -> Unit) {
- if (phone.isEmpty()) {
+ fun getPhone(block: ((String) -> Unit)? = null) {
+ if (phone.value.isNullOrEmpty()) {
launchRequest {
userRepository.getPhone()?.let {
- phone = JSONObject(gson.toJson(it)).optString("customerServicePhone")
- runOnMainThread { block(phone) }
+ val phone = JSONObject(gson.toJson(it)).optString("customerServicePhone")
+ this.phone.postValue(phone)
+ runOnMainThread {
+ block?.invoke(phone)
+ }
}
}
} else {
- block(phone)
+ block?.invoke(phone.value!!)
}
}
+ //获取个人中心巡游打卡任务
+ fun getMyCruiseCheckInMissionInfo() {
+ launchRequest {
+ workRepository.getMyCruiseCheckInMissionInfo()?.also {
+ cruiseCheckInMissionInfo.postValue(it)
+ }
+ }
+ }
+
+ //获取个人中心巡游打卡任务时间
+ fun getFormateCruiseCheckInMissionTime(): String {
+ return try {
+ cruiseCheckInMissionInfo.value?.cruiseCheckInTaskTime?.let {
+ val split = it.split(" ")
+ val ymd = split[0].dateChangePattern("yyyy-MM-dd", "yyyy/MM/dd")
+ "$ymd ${split[1]}"
+ } ?: ""
+ } catch (e: Exception) {
+ e.printStackTrace()
+ ""
+ }
+ }
+
+ //获取巡游打卡进度
+ fun getCruiseCheckInProgress(): Float {
+ return cruiseCheckInMissionInfo.value?.getFinishProgress() ?: 0f
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/user/mine/checkin/CheckInActivity.kt b/app/src/main/java/com/xw/yunwei/ui/user/mine/checkin/CheckInActivity.kt
index e9291a1..c5f0433 100644
--- a/app/src/main/java/com/xw/yunwei/ui/user/mine/checkin/CheckInActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/user/mine/checkin/CheckInActivity.kt
@@ -1,26 +1,37 @@
package com.xw.yunwei.ui.user.mine.checkin
import android.os.Bundle
+import android.view.View
import androidx.appcompat.widget.AppCompatTextView
+import androidx.core.os.bundleOf
import com.amap.api.location.AMapLocation
import com.amap.api.maps.model.LatLng
import com.xw.common.CommonDialog
-import com.xw.common.base.BaseActivity
import com.xw.common.utils.BindUtils.getResColor
import com.xw.common.utils.GpsHelper
import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.R
+import com.xw.yunwei.constants.Key
import com.xw.yunwei.databinding.ActivityCheckInBinding
+import com.xw.yunwei.model.ClockInStatusModel
import com.xw.yunwei.ui.work.AMapFragment
/**
* 打卡
*/
-class CheckInActivity : BaseActivity<ActivityCheckInBinding, CheckInVM>(), GpsHelper.OnMapLocation {
+class CheckInActivity : BaseBusinessActivity<ActivityCheckInBinding, CheckInVM>(), GpsHelper.OnMapLocation {
+ companion object {
+ //获取跳转此页面参数
+ fun getParams(model: ClockInStatusModel, enterType: Int): Bundle {
+ return bundleOf(Key.CLOCK_MODEL to model, Key.ENTER_TYPE to enterType)
+ }
+ }
+
override fun getBindingVariable() = BR.viewModel
-// var gpsHelper: GpsHelper? = null
+ // var gpsHelper: GpsHelper? = null
val mapFrag: AMapFragment by lazy { AMapFragment(R.mipmap.ic_map_location_my, false) }
override fun myCreate(savedInstanceState: Bundle?) {
@@ -40,7 +51,7 @@
super.init()
viewModel.enterType = intent.getIntExtra("enterType", 0).takeIf { it != 0 }
viewModel.clockModel.value = intent.getParcelableExtra("clockModel")
- viewModel.locationCheck()
+ //viewModel.locationCheck()
val transaction = supportFragmentManager.beginTransaction()
transaction.add(R.id.map_container, mapFrag)
@@ -49,11 +60,7 @@
mapFrag.locationChangeCallback = {
dismissDialog()
if (it == null) {
- CommonDialog.showTipsDialog(
- this@CheckInActivity,
- "您未开启gps权限,无法获取当前定位,请打开后重新操作",
- null
- )
+ CommonDialog.showLocationNotGrantedTipsDialog(this@CheckInActivity)
} else {
if (viewModel.pageType.value == 2) {
mapMarkRefresh()
@@ -104,9 +111,16 @@
}
viewModel.clockModel.observe(this) {
it?.let {
- val clockType = if (it.clockIn != true) 1 else 2
- val isClock = if (clockType == 1) it.clockIn ?: false else it.clockOut ?: false
-
+ val isClock = viewModel.isClock()
+ binding.ivCheckSuccess.visibility = if (isClock) View.VISIBLE else View.GONE
+ binding.clockIn.visibility =
+ if (isClock || viewModel.enterType == 2) View.GONE else View.VISIBLE
+ binding.clockOut.visibility =
+ if (isClock || viewModel.enterType == 1) View.GONE else View.VISIBLE
+ binding.llCheckInInfo.visibility =
+ if (isClock && viewModel.enterType == 1) View.VISIBLE else View.GONE
+ binding.llCheckOutInfo.visibility =
+ if (isClock && viewModel.enterType == 2) View.VISIBLE else View.GONE
if (isClock) {
it.xpClockIn?.let {
when (it.clockInResult) { // 上班打卡结果 1 = 正常 2 = 迟到 3 = 缺卡
@@ -181,7 +195,7 @@
)
)
- if (mapFrag.circles.isEmpty()){
+ if (mapFrag.circles.isEmpty()) {
mapFrag.moveCameraToArea(
LatLng(it.latitude, it.longitude),
LatLng(lat, lon)
diff --git a/app/src/main/java/com/xw/yunwei/ui/user/mine/checkin/CheckInVM.kt b/app/src/main/java/com/xw/yunwei/ui/user/mine/checkin/CheckInVM.kt
index ca153c0..c8685a7 100644
--- a/app/src/main/java/com/xw/yunwei/ui/user/mine/checkin/CheckInVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/user/mine/checkin/CheckInVM.kt
@@ -11,9 +11,7 @@
import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.model.ClockInStatusModel
import com.xw.yunwei.net.UserRepository
-import com.xw.yunwei.ui.MainActivity
import org.koin.core.component.inject
-import kotlin.getValue
class CheckInVM(application: Application) : BaseViewModel(application) {
@@ -26,15 +24,11 @@
var location: AMapLocation? = null
val clockModel: MutableLiveData<ClockInStatusModel> = MutableLiveData()
+ val distanceEffective = MutableLiveData(false) // 位置是否合适
+ val timeEffective = MutableLiveData(false) // 是否打卡时间有效
val canClock = MutableLiveData(false) // 是否能打卡
var enterType: Int? = null // 页面传入类型 1:上班 2:下班
- val clockType = clockModel.map { // 打卡类型 1:上班 2:下班
- enterType ?: if (it.clockIn != true) 1 else 2
- }
- val isClock = clockType.map { // 是否已打卡
- if (it == 1) clockModel.value!!.clockIn ?: false else clockModel.value!!.clockOut ?: false
- }
val tipsId = MutableLiveData<Int>()
val tips = MutableLiveData<String>()
@@ -48,7 +42,11 @@
clockModel.value?.let {
val lat = location?.latitude ?: 0.0
val lng = location?.longitude ?: 0.0
-
+ //位置是否合适
+ var distanceEffective = false
+ //时间是否合适
+ var timeEffective = false
+ var couldCheck = false
if (lat != 0.0 && lng != 0.0 && (it.xpCheckLocation?.locationLat
?: 0.0) != 0.0 && (it.xpCheckLocation?.locationLon ?: 0.0) != 0.0
) {
@@ -56,34 +54,33 @@
LatLng(lat, lng),
LatLng(it.xpCheckLocation!!.locationLat!!, it.xpCheckLocation.locationLon!!)
)
- canClock.value = (it.xpCheckLocation.locationRange ?: 0.0) > dis.toDouble()
+ distanceEffective = (it.xpCheckLocation.locationRange ?: 0.0) > dis.toDouble()
+ timeEffective =
+ if (enterType == 1) it.xpShift?.isNowTimeCheckInWorkEffective() == true else it.xpShift?.isNowTimeCheckInOffWorkEffective() == true
+ this.distanceEffective.postValue(distanceEffective)
+ this.timeEffective.postValue(timeEffective)
+ couldCheck = distanceEffective && timeEffective
+ canClock.postValue(couldCheck)
}
- }
- getTipsAbout()
- }
+// val clockType = if (it.clockIn != true) 1 else 2
+// val isClock = if (clockType == 1) clockModel.value!!.clockIn
+// ?: false else clockModel.value!!.clockOut ?: false
- var alreadyTipsNoCanClock = false
- fun getTipsAbout() {
- clockModel.value?.let {
- val clockType = if (it.clockIn != true) 1 else 2
- val isClock = if (clockType == 1) clockModel.value!!.clockIn
- ?: false else clockModel.value!!.clockOut ?: false
-
- if (isClock || canClock.value!!) {
+ if (isClock() || couldCheck) {
tipsId.value = com.xw.common.R.drawable.svg_checkin_location
} else {
tipsId.value = com.xw.common.R.drawable.svg_toast_warn
}
- if (isClock) {
- tips.value = "今日打卡已完成"
+ if (isClock()) {
+ tips.postValue(if (enterType == 1) "成功打卡上班" else "今日打卡已完成")
} else {
- if (canClock.value!!) {
- tips.value = "您已在打卡范围内"
+ if (couldCheck) {
+ tips.postValue("您已在打卡范围内")
} else {
- tips.value = "当前设备GPS定位不在打卡范围内"
- if (!alreadyTipsNoCanClock && location != null) {
+ tips.postValue(if (!distanceEffective) "当前设备GPS定位不在打卡范围内" else "您不在打卡时间范围内")
+ if (!alreadyTipsNoCanClock && location != null && !distanceEffective) {
alreadyTipsNoCanClock = true
ToastUtilCommon.showWarn("不在打卡范围内")
}
@@ -91,6 +88,13 @@
}
}
}
+
+ var alreadyTipsNoCanClock = false
+
+ fun isClock() = enterType?.let { // 是否已打卡
+ if (it == 1) (clockModel.value!!.clockIn == true && clockModel.value!!.xpClockIn?.hadLostWorkCheckedIn() != true) else
+ (clockModel.value!!.clockOut == true && clockModel.value!!.xpClockIn?.hadLostOffWorkCheckedIn() != true)
+ } ?: false
fun clockIn() {
launchRequest("打卡中") {
@@ -100,10 +104,12 @@
map["clockInAddress"] = location?.address
map["shiftId"] = clockModel.value?.xpShift?.id
map["locationId"] = clockModel.value?.xpCheckLocation?.id
- userRepository.clockIn(map)
- ToastUtilCommon.showSuc("打卡成功")
-// querySchedule(getTime(System.currentTimeMillis()))
- startActivity(MainActivity::class.java)
+ userRepository.clockIn(map)?.also {
+ ToastUtilCommon.showSuc("打卡成功")
+ querySchedule(getTime(System.currentTimeMillis())) {
+ tips.postValue("成功打卡上班")
+ }
+ }
}
}
@@ -115,16 +121,20 @@
map["clockOutAddress"] = location?.address
map["shiftId"] = clockModel.value?.xpShift?.id
map["locationId"] = clockModel.value?.xpCheckLocation?.id
- userRepository.clockOut(map)
- ToastUtilCommon.showSuc("打卡成功")
- querySchedule(getTime(System.currentTimeMillis()))
+ userRepository.clockOut(map)?.also {
+ ToastUtilCommon.showSuc("打卡成功")
+ querySchedule(getTime(System.currentTimeMillis())) {
+ tips.postValue("今日打卡已完成")
+ }
+ }
}
}
- fun querySchedule(time: String) {
+ fun querySchedule(time: String, successListener: () -> Unit) {
launchRequest {
userRepository.querySchedule(mapOf("schedulingDate" to time)).let {
clockModel.postValue(it)
+ successListener.invoke()
}
}
}
diff --git a/app/src/main/java/com/xw/yunwei/ui/user/mine/info/UserInfoActivity.kt b/app/src/main/java/com/xw/yunwei/ui/user/mine/info/UserInfoActivity.kt
index 6a653cc..9c4750c 100644
--- a/app/src/main/java/com/xw/yunwei/ui/user/mine/info/UserInfoActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/user/mine/info/UserInfoActivity.kt
@@ -2,12 +2,13 @@
import com.xw.common.base.BaseActivity
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.databinding.ActivityUserInfoBinding
/**
* 用户信息
*/
-class UserInfoActivity : BaseActivity<ActivityUserInfoBinding, UserInfoVM>() {
+class UserInfoActivity : BaseBusinessActivity<ActivityUserInfoBinding, UserInfoVM>() {
override fun getBindingVariable() = BR.viewModel
override fun init() {
diff --git a/app/src/main/java/com/xw/yunwei/ui/user/mine/info/UserInfoVM.kt b/app/src/main/java/com/xw/yunwei/ui/user/mine/info/UserInfoVM.kt
index 03eaf26..52aeab2 100644
--- a/app/src/main/java/com/xw/yunwei/ui/user/mine/info/UserInfoVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/user/mine/info/UserInfoVM.kt
@@ -9,6 +9,7 @@
import com.xw.common.utils.MMKVManager
import com.xw.common.viewAdapter.ImageDefault
import com.xw.yunwei.model.UserInfo
+import com.xw.yunwei.model.UserInfoRealtime
import com.xw.yunwei.net.UserRepository
import org.koin.core.component.inject
import kotlin.getValue
@@ -16,7 +17,7 @@
class UserInfoVM(application: Application) : BaseViewModel(application) {
val userRepository: UserRepository by inject()
- val userInfo = MutableLiveData(MMKVManager.getInstance().getModel<UserInfo>(KeyPreferences.USER))
+ val userInfo = MutableLiveData<UserInfoRealtime>()
val avatar = MutableLiveData(ImageDefault("", com.xw.common.R.drawable.svg_avatar))
val name = userInfo.map { it?.nickName }
@@ -30,6 +31,7 @@
showLoading = false,
flowBlock = { userRepository.getUserInfo() },
onCollect = {
+ userInfo.postValue(it)
avatar.postValue(avatar.value!!.apply { this.url = it?.avatar?.getUrl() ?: "" })
captain.postValue(it?.fleet?.fleetLeaderName ?: "无")
team.postValue(it?.fleet?.fleetName ?: "无")
diff --git a/app/src/main/java/com/xw/yunwei/ui/user/mine/protocol/ProtocolActivity.kt b/app/src/main/java/com/xw/yunwei/ui/user/mine/protocol/ProtocolActivity.kt
index 8527713..cd064de 100644
--- a/app/src/main/java/com/xw/yunwei/ui/user/mine/protocol/ProtocolActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/user/mine/protocol/ProtocolActivity.kt
@@ -1,94 +1,44 @@
package com.xw.yunwei.ui.user.mine.protocol
-import android.annotation.SuppressLint
-import android.webkit.WebSettings
-import android.webkit.WebView
-import com.google.android.material.tabs.TabLayout
-import com.xw.common.base.BaseActivity
+import androidx.core.os.bundleOf
+import androidx.recyclerview.widget.LinearLayoutManager
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.databinding.ActivityProtocolBinding
+import com.xw.yunwei.ui.user.mine.protocol.adapter.ProtocolEntranceAdapter
+import com.xw.yunwei.ui.work.car.detail.StandardDescriptionActivity
-class ProtocolActivity: BaseActivity<ActivityProtocolBinding, ProtocolVM>() {
+class ProtocolActivity : BaseBusinessActivity<ActivityProtocolBinding, ProtocolVM>() {
override fun getBindingVariable() = BR.viewModel
-
+ val adapter by lazy { ProtocolEntranceAdapter() }
override fun init() {
super.init()
- initWeb(binding.web)
- binding.back.setOnClickListener { onBackPressedHandel() }
-// val tab1 = binding.tabLayout.newTab().apply { text = "小鹏Robotaxi自动驾驶出行运维隐私政策" }
- val tab1 = binding.tabLayout.newTab().apply { text = "小鹏Robotaxi...隐私政策" }
- val tab2 = binding.tabLayout.newTab().apply { text = "第三方共享信息清单" }
- val tab3 = binding.tabLayout.newTab().apply { text = "个人信息收集清单" }
- val tab4 = binding.tabLayout.newTab().apply { text = "权限调用" }
-
- binding.tabLayout.addTab(tab1, true)
- binding.tabLayout.addTab(tab2, false)
- binding.tabLayout.addTab(tab3, false)
- binding.tabLayout.addTab(tab4, false)
-
- val getProtocol: (Int) -> Unit = { type ->
- viewModel.getProtocol(type) {
- setContent(binding.web, it)
- }
+ binding.back.setOnClickListener {
+ finish()
}
- getProtocol(8)
-
- binding.tabLayout.addOnTabSelectedListener(object :
- TabLayout.OnTabSelectedListener {
- override fun onTabSelected(tab: TabLayout.Tab?) {
- tab?.let {
- when (it.text) {
- "用户协议" -> getProtocol(1)
- "隐私条款" -> getProtocol(2)
- "小鹏Robotaxi...隐私政策" -> getProtocol(8)
- "第三方共享信息清单" -> getProtocol(9)
- "个人信息收集清单" -> getProtocol(10)
- "权限调用" -> getProtocol(11)
- else -> {}
- }
- }
- }
- override fun onTabUnselected(tab: TabLayout.Tab?) {}
- override fun onTabReselected(tab: TabLayout.Tab?) {}
- })
-
+ binding.rvList.adapter = adapter
+ binding.rvList.layoutManager = LinearLayoutManager(this)
}
- @SuppressLint("SetJavaScriptEnabled")
- private fun initWeb(webView: WebView) {
- //声明WebSettings子类
- val webSettings = webView.settings
- webSettings.domStorageEnabled = true //设置适应Html5
-
- //如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
- webSettings.javaScriptEnabled = true //允许js调用
- webSettings.allowFileAccess = true //在File域下,能够执行任意的JavaScript代码,同源策略跨域访问能够对私有目录文件进行访问等
- webSettings.allowContentAccess = true //是否允许在WebView中访问内容URL(Content Url),默认允许
-
- //缩放操作
- webSettings.setSupportZoom(true) //支持缩放,默认为true。是下面那个的前提。
- webSettings.builtInZoomControls = true //设置内置的缩放控件。若为false,则该WebView不可缩放
- webSettings.displayZoomControls = false //隐藏原生的缩放控件
-
- //其他细节操作
- webSettings.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK //关闭webview中缓存
- webSettings.allowFileAccess = true //设置可以访问文件
- webSettings.javaScriptCanOpenWindowsAutomatically = true //支持通过JS打开新窗口
- webSettings.loadsImagesAutomatically = true //支持自动加载图片
- webSettings.defaultTextEncodingName = "utf-8" //设置编码格式
- }
-
- @SuppressLint("SetJavaScriptEnabled")
- private fun setContent(webView: WebView, content: String?) {
- content?.let {
- // 加载并显示HTML代码
- webView.loadDataWithBaseURL(
- null,
- content,
- "text/html",
- "utf-8",
- null
+ override fun setListener() {
+ super.setListener()
+ adapter.setOnItemClickListener { adapter, view, i ->
+ val info = viewModel.protocols.value!![i]
+ startActivity(
+ StandardDescriptionActivity::class.java,
+ bundleOf(
+ "type" to info.id?.toInt(),
+ "webType" to 1,
+ "title" to info.name
+ )
)
}
}
+
+ override fun setObservable() {
+ super.setObservable()
+ viewModel.protocols.observe(this) { it ->
+ adapter.setList(it.map { it.name ?: "" })
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/user/mine/protocol/ProtocolVM.kt b/app/src/main/java/com/xw/yunwei/ui/user/mine/protocol/ProtocolVM.kt
index 2538ab9..0c09058 100644
--- a/app/src/main/java/com/xw/yunwei/ui/user/mine/protocol/ProtocolVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/user/mine/protocol/ProtocolVM.kt
@@ -1,19 +1,26 @@
package com.xw.yunwei.ui.user.mine.protocol
import android.app.Application
+import androidx.lifecycle.MutableLiveData
import com.xw.common.base.BaseViewModel
+import com.xw.yunwei.model.AgreeInfo
import com.xw.yunwei.net.UserRepository
import org.koin.core.component.inject
-import kotlin.getValue
-class ProtocolVM (application: Application) : BaseViewModel(application) {
+class ProtocolVM(application: Application) : BaseViewModel(application) {
val userRepository: UserRepository by inject()
-
- fun getProtocol(type: Int, block: (String) -> Unit) {
- launchRequest {
- val data = userRepository.getProtocol(type)
- runOnMainThread { block(data?.content ?: "") }
- }
+ val protocols = MutableLiveData<List<AgreeInfo>>()
+ override fun onCreate() {
+ super.onCreate()
+ getAgreeConfig()
}
+ /*获取协议配置 */
+ fun getAgreeConfig() {
+ launchRequest {
+ userRepository.getAgreeConfig()?.also {
+ protocols.postValue(it)
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/user/mine/protocol/adapter/ProtocolEntranceAdapter.kt b/app/src/main/java/com/xw/yunwei/ui/user/mine/protocol/adapter/ProtocolEntranceAdapter.kt
new file mode 100644
index 0000000..f099b0b
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/user/mine/protocol/adapter/ProtocolEntranceAdapter.kt
@@ -0,0 +1,13 @@
+package com.xw.yunwei.ui.user.mine.protocol.adapter
+
+import com.chad.library.adapter.base.BaseQuickAdapter
+import com.chad.library.adapter.base.viewholder.BaseViewHolder
+import com.xw.yunwei.R
+
+//服务条款入口适配器
+class ProtocolEntranceAdapter :
+ BaseQuickAdapter<String, BaseViewHolder>(R.layout.item_protocol_entrance) {
+ override fun convert(holder: BaseViewHolder, item: String) {
+ holder.setText(R.id.tv_title, item)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/SchedulingActivity.kt b/app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/SchedulingActivity.kt
index 0a5283e..3e0445d 100644
--- a/app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/SchedulingActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/SchedulingActivity.kt
@@ -3,40 +3,46 @@
import android.content.res.ColorStateList
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.content.ContextCompat
+import androidx.recyclerview.widget.LinearLayoutManager
import com.amap.api.maps.model.LatLng
-import com.blankj.utilcode.util.TimeUtils
-import com.blankj.utilcode.util.TimeUtils.getSafeDateFormat
import com.xw.common.R
-import com.xw.common.base.BaseActivity
-import com.xw.yunwei.BR
-import com.xw.yunwei.databinding.ActivitySchedulingBinding
import com.xw.common.TimeDialog
import com.xw.common.TimeDialog.Companion.getTime
import com.xw.common.utils.BindUtils.getResColor
import com.xw.common.utils.GpsHelper.Companion.navigate
import com.xw.common.utils.ToastUtilCommon
+import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
+import com.xw.yunwei.databinding.ActivitySchedulingBinding
+import com.xw.yunwei.ui.user.mine.scheduling.adapter.WeekDayAdapter
+import java.time.LocalDate
+import java.util.Calendar
+import java.util.Locale
/**
* 排班考勤
*/
-class SchedulingActivity: BaseActivity<ActivitySchedulingBinding, SchedulingVM>() {
+class SchedulingActivity : BaseBusinessActivity<ActivitySchedulingBinding, SchedulingVM>() {
override fun getBindingVariable() = BR.viewModel
val dialogTime: TimeDialog by lazy { TimeDialog(this) }
+ val startDate = LocalDate.of(2020, 1, 1)
+ val endDate = LocalDate.of(2050, 12, 31)
+
+ val adapter by lazy {
+ WeekDayAdapter()
+ }
override fun init() {
super.init()
val time = getTime(System.currentTimeMillis())
viewModel.today = time
- viewModel.createNext7DaysWeekNames(time)
viewModel.selectTime.value = time
val bgColorStateList = ColorStateList(
arrayOf(
- intArrayOf(-android.R.attr.state_enabled),
- intArrayOf()
- ),
- intArrayOf(
+ intArrayOf(-android.R.attr.state_enabled), intArrayOf()
+ ), intArrayOf(
ContextCompat.getColor(this, R.color.blue_3),
ContextCompat.getColor(this, R.color.blue_5)
)
@@ -51,33 +57,77 @@
backgroundTintList = bgColorStateList
setTextColor(ContextCompat.getColor(this@SchedulingActivity, android.R.color.white))
}
+ binding.rvList.adapter = adapter
+ binding.rvList.layoutManager =
+ LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
+ scrollToDate(time)
+ }
+
+ //滚动到指定日期
+ private fun scrollToDate(dateString: String) {
+ val split = dateString.split("-")
+ Calendar.getInstance().apply {
+ set(Calendar.YEAR, split[0].toInt())
+ set(Calendar.MONTH, split[1].toInt() - 1)
+ set(Calendar.DAY_OF_MONTH, split[2].toInt())
+ }.also { calendar ->
+ adapter.setList((0..29).mapIndexed { index, i ->
+ calendar.add(Calendar.DAY_OF_MONTH, if (index == 0) 0 else 1)
+ "${calendar.get(Calendar.YEAR)}-${
+ String.format(Locale.getDefault(), "%02d", calendar.get(Calendar.MONTH) + 1)
+ }-${
+ String.format(Locale.getDefault(), "%02d", calendar.get(Calendar.DAY_OF_MONTH))
+ }"
+ })
+ adapter.selectDate = dateString
+ viewModel.yearMonth.value =
+ "${split[0]}年${String.format(Locale.getDefault(), "%02d", split[1].toInt())}月"
+ binding.rvList.smoothScrollToPosition(0)
+ }
+ }
+
+ //格式化日期
+ private fun formateDate(localDate: LocalDate): String {
+ return "${localDate.year}-${
+ String.format(Locale.getDefault(), "%02d", localDate.monthValue)
+ }-${
+ String.format(Locale.getDefault(), "%02d", localDate.dayOfMonth)
+ }"
}
override fun setListener() {
super.setListener()
binding.dateSelect.setOnClickListener {
val showTime = getTime(viewModel.selectTime.value)
- val minTime = getTime("2020-01-01")
- dialogTime.show("选择日期", showTime, minTime) {
+ val minTime = getTime(formateDate(startDate))
+ val maxTime = getTime(formateDate(endDate))
+ dialogTime.show("选择日期", showTime, minTime, maxTime) {
val time = getTime(it)
- viewModel.createNext7DaysWeekNames(time)
+ scrollToDate(time)
viewModel.selectTime.value = time
}
}
binding.nav.setOnClickListener {
viewModel.clockModel.value?.let {
- if ((it.xpCheckLocation?.locationLat ?: 0.0) != 0.0 && (it.xpCheckLocation?.locationLon ?: 0.0) != 0.0) {
+ if ((it.xpCheckLocation?.locationLat
+ ?: 0.0) != 0.0 && (it.xpCheckLocation?.locationLon ?: 0.0) != 0.0
+ ) {
navigate(
end = LatLng(
- it.xpCheckLocation?.locationLat!!,
- it.xpCheckLocation.locationLon!!
- ),
- context = this
+ it.xpCheckLocation?.locationLat!!, it.xpCheckLocation.locationLon!!
+ ), context = this
)
} else {
ToastUtilCommon.showError("数据异常")
}
}
+ }
+ adapter.setOnItemClickListener { _, _, i ->
+ val item = adapter.getItem(i)
+ adapter.selectDate = item
+ viewModel.selectTime.value = item
+ val split = item.split("-")
+ viewModel.yearMonth.value = "${split[0]}年${split[1]}月"
}
}
@@ -90,7 +140,7 @@
override fun setObservable() {
super.setObservable()
- viewModel.selectTime.observe(this){
+ viewModel.selectTime.observe(this) {
viewModel.querySchedule(it)
}
val setStatus: (AppCompatTextView, Int, Int, String) -> Unit = { tv, color, bg, text ->
@@ -100,66 +150,29 @@
}
viewModel.clockModel.observe(this) {
it?.let {
+ val now = Calendar.getInstance()
+ val isToday =
+ viewModel.selectTime.value == null || viewModel.selectTime.value == getTime(now.timeInMillis)
// 状态提示控制
- if (it.clockIn != true) {
- setStatus(
- binding.clockIntStatus,
- getResColor(R.color.orange_5),
- R.color.orange_1,
- "未打卡"
- )
- } else {
- it.xpClockIn?.let {
- when (it.clockInResult) { // 上班打卡结果 1 = 正常 2 = 迟到 3 = 缺卡
- 3 -> setStatus(
- binding.clockIntStatus,
- getResColor(R.color.orange_5),
- R.color.orange_1,
- "未打卡"
- )
- else -> setStatus(
- binding.clockIntStatus,
- getResColor(R.color.gray_7),
- R.color.gray_3,
- "已打卡"
- )
- }
- }
- }
+ setStatus(
+ binding.clockIntStatus,
+ getResColor(if (it.xpClockIn?.hadLostWorkCheckedIn() == true) R.color.red_5 else if (it.clockIn == true) R.color.gray_7 else if (!isToday) R.color.gray_8 else R.color.orange_5),
+ if (it.xpClockIn?.hadLostWorkCheckedIn() == true) R.color.red_1 else if (it.clockIn == true) R.color.gray_3 else if (!isToday) com.xw.yunwei.R.drawable.shape_gray_4_bg_4 else R.color.orange_1,
+ if (it.xpClockIn?.hadLostWorkCheckedIn() == true) "缺卡" else if (it.clockIn == true) "已打卡" else if (!isToday) "不在打卡时间范围内" else "未打卡"
+ )
+ setStatus(
+ binding.clockOutStatus,
+ getResColor(if (it.xpClockIn?.hadLostOffWorkCheckedIn() == true) R.color.red_5 else if (it.clockOut == true) R.color.gray_7 else if (!isToday) R.color.gray_8 else R.color.orange_5),
+ if (it.xpClockIn?.hadLostOffWorkCheckedIn() == true) R.color.red_1 else if (it.clockOut == true) R.color.gray_3 else if (!isToday) com.xw.yunwei.R.drawable.shape_gray_4_bg_4 else R.color.orange_1,
+ if (it.xpClockIn?.hadLostOffWorkCheckedIn() == true) "缺卡" else if (it.clockOut == true) "已打卡" else if (!isToday) "不在打卡时间范围内" else "未打卡"
+ )
+ // 未上班打卡或缺卡 可上班打卡
+ binding.clockIn.isEnabled =
+ it.clockIn != true || it.xpClockIn?.hadLostWorkCheckedIn() == true
- if (it.clockOut != true) {
- setStatus(
- binding.clockOutStatus,
- getResColor(R.color.orange_5),
- R.color.orange_1,
- "未打卡"
- )
- } else {
- it.xpClockIn?.let {
- when (it.clockOutResult) { // 下班打卡结果 1 = 正常 2 = 早退 3 = 缺卡
- 3 -> setStatus(
- binding.clockOutStatus,
- getResColor(R.color.orange_5),
- R.color.orange_1,
- "未打卡"
- )
- else -> setStatus(
- binding.clockOutStatus,
- getResColor(R.color.gray_7),
- R.color.gray_3,
- "已打卡"
- )
- }
- }
- }
- // 未打卡 且 状态不为缺卡 可上班打卡
- binding.clockIn.isEnabled = it.clockIn != true && it.xpClockIn?.clockInResult != 3
-
- val startTime = it.xpShift?.startTime ?: "23:59" // 接口不配置 就不让能打卡
- val currentTime = TimeUtils.millis2String(System.currentTimeMillis(),getSafeDateFormat("HH:mm"))
- // 已打上班卡 或 (未下班打卡 且 状态不为缺卡 且 已过上班时间) 可下班打卡
- binding.clockOut.isEnabled = (it.clockIn == true && it.xpClockIn?.clockInResult != 3) ||
- (it.clockOut != true && it.xpClockIn?.clockOutResult != 3 && currentTime > startTime)
+ // 未下班打卡或缺卡 可下班打卡
+ binding.clockOut.isEnabled =
+ it.clockOut != true || it.xpClockIn?.hadLostOffWorkCheckedIn() == true
}
}
}
diff --git a/app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/SchedulingVM.kt b/app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/SchedulingVM.kt
index cc5ddc7..a8deb95 100644
--- a/app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/SchedulingVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/SchedulingVM.kt
@@ -3,12 +3,11 @@
import android.annotation.SuppressLint
import android.app.Application
import android.view.View
-import androidx.core.os.bundleOf
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.map
import com.xw.common.base.BaseViewModel
-import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.R
+import com.xw.yunwei.extension.dateChangePattern
import com.xw.yunwei.model.ClockInStatusModel
import com.xw.yunwei.net.UserRepository
import com.xw.yunwei.ui.user.mine.checkin.CheckInActivity
@@ -16,7 +15,6 @@
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.util.Locale
-import kotlin.getValue
@SuppressLint("SimpleDateFormat")
class SchedulingVM(application: Application) : BaseViewModel(application) {
@@ -24,25 +22,13 @@
var today = ""
val selectTime = MutableLiveData<String>()
- val yearMonth = selectTime.map {
- try {
- val inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
- val date = LocalDate.parse(it, inputFormatter)
- val outputFormatter = DateTimeFormatter.ofPattern("yyyy年M月", Locale.CHINESE)
- date.format(outputFormatter)
- } catch (e: Exception) {
- ""
- }
- }
- // 一周的中文以及格式化时间
- val showWeekDay: MutableLiveData<List<String>> = MutableLiveData()
- val showWeekDate: MutableLiveData<List<String>> = MutableLiveData()
+ val yearMonth = MutableLiveData<String>()
// 对应currentTime的打卡信息
val clockModel: MutableLiveData<ClockInStatusModel?> = MutableLiveData()
val clockTime = clockModel.map {
// "${it?.xpShift?.startTime ?: ""} - ${it?.xpShift?.restStartTime ?: ""} ${it?.xpShift?.restEndTime ?: ""} - ${it?.xpShift?.endTime ?: ""}"
- "${selectTime.value?:""} ${it?.xpShift?.startTime ?: ""}~${it?.xpShift?.endTime ?: ""}"
+ "${selectTime.value?.dateChangePattern("yyyy-MM-dd","yyyy/MM/dd") ?: ""} ${it?.xpShift?.startTime ?: ""}~${it?.xpShift?.endTime ?: ""}"
}
val onClick = View.OnClickListener {
@@ -51,21 +37,14 @@
// CheckInActivity::class.java,
// bundleOf("clockModel" to clockModel.value)
// )
- R.id.date1 -> selectTime.value = showWeekDate.value?.getOrNull(0) ?: ""
- R.id.date2 -> selectTime.value = showWeekDate.value?.getOrNull(1) ?: ""
- R.id.date3 -> selectTime.value = showWeekDate.value?.getOrNull(2) ?: ""
- R.id.date4 -> selectTime.value = showWeekDate.value?.getOrNull(3) ?: ""
- R.id.date5 -> selectTime.value = showWeekDate.value?.getOrNull(4) ?: ""
- R.id.date6 -> selectTime.value = showWeekDate.value?.getOrNull(5) ?: ""
- R.id.date7 -> selectTime.value = showWeekDate.value?.getOrNull(6) ?: ""
R.id.clockIn -> startActivity(
CheckInActivity::class.java,
- bundleOf("clockModel" to clockModel.value, "enterType" to 1)
+ CheckInActivity.getParams(clockModel.value!!, 1)
)
R.id.clockOut -> startActivity(
CheckInActivity::class.java,
- bundleOf("clockModel" to clockModel.value, "enterType" to 2)
+ CheckInActivity.getParams(clockModel.value!!, 2)
)
}
}
@@ -76,36 +55,5 @@
clockModel.postValue(it)
}
}
- }
-
- /**
- * 生成从输入日期开始后7天的星期名称
- * @param dateString 日期字符串
- */
- fun createNext7DaysWeekNames(dateString: String) {
- val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
- val startDate = LocalDate.parse(dateString, formatter)
-
- // 中文星期简写映射
- val weekDayMap = mapOf(
- java.time.DayOfWeek.MONDAY to "一",
- java.time.DayOfWeek.TUESDAY to "二",
- java.time.DayOfWeek.WEDNESDAY to "三",
- java.time.DayOfWeek.THURSDAY to "四",
- java.time.DayOfWeek.FRIDAY to "五",
- java.time.DayOfWeek.SATURDAY to "六",
- java.time.DayOfWeek.SUNDAY to "日"
- )
-
- val days = mutableListOf<String>()
- val weeks = mutableListOf<String>()
-
- (0 until 7).map { dayOffset ->
- val date = startDate.plusDays(dayOffset.toLong())
- days.add(date.format(formatter)) // 几号:24, 25, 26...
- weeks.add(weekDayMap[date.dayOfWeek] ?: "")
- }
- showWeekDate.value = days
- showWeekDay.value = weeks
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/adapter/DateWeekAdapter.kt b/app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/adapter/DateWeekAdapter.kt
new file mode 100644
index 0000000..a50bf43
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/adapter/DateWeekAdapter.kt
@@ -0,0 +1,44 @@
+package com.xw.yunwei.ui.user.mine.scheduling.adapter
+
+import android.widget.TextView
+import com.chad.library.adapter.base.BaseQuickAdapter
+import com.chad.library.adapter.base.viewholder.BaseViewHolder
+import com.xw.yunwei.R
+import java.util.Calendar
+
+//日期星期适配器
+class DateWeekAdapter() :
+ BaseQuickAdapter<String, BaseViewHolder>(R.layout.item_date_week) {
+ private val calendar = Calendar.getInstance()
+ var selectDate: String? = null
+ set(value) {
+ data.indexOf(field).takeIf { it != -1 }?.also { notifyItemChanged(it) }
+ field = value
+ data.indexOf(field).takeIf { it != -1 }?.also { notifyItemChanged(it) }
+ }
+
+ override fun convert(holder: BaseViewHolder, item: String) {
+ calendar.apply {
+ val split = item.split("-")
+ set(Calendar.YEAR, split[0].toInt())
+ set(Calendar.MONTH, split[1].toInt() - 1)
+ set(Calendar.DAY_OF_MONTH, split[2].toInt())
+ holder.setText(
+ R.id.tv_week, when (get(Calendar.DAY_OF_WEEK)) {
+ Calendar.SUNDAY -> "日"
+ Calendar.MONDAY -> "一"
+ Calendar.TUESDAY -> "二"
+ Calendar.WEDNESDAY -> "三"
+ Calendar.THURSDAY -> "四"
+ Calendar.FRIDAY -> "五"
+ Calendar.SATURDAY -> "六"
+ else -> ""
+ }
+ )
+ holder.getView<TextView>(R.id.tv_day).apply {
+ text = split[2].toInt().toString()
+ isSelected = selectDate == item
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/adapter/WeekDayAdapter.kt b/app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/adapter/WeekDayAdapter.kt
new file mode 100644
index 0000000..8683601
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/adapter/WeekDayAdapter.kt
@@ -0,0 +1,51 @@
+package com.xw.yunwei.ui.user.mine.scheduling.adapter
+
+import android.view.View
+import com.chad.library.adapter.base.BaseQuickAdapter
+import com.chad.library.adapter.base.viewholder.BaseViewHolder
+import com.xw.yunwei.R
+import java.util.Calendar
+
+//星期月份天数适配器
+class WeekDayAdapter() : BaseQuickAdapter<String, BaseViewHolder>(R.layout.item_week_day) {
+ private val calendar = Calendar.getInstance()
+ var selectDate: String? = null
+ set(value) {
+ data.filter { isSameDate(field, it) }.forEach { notifyItemChanged(data.indexOf(it)) }
+ field = value
+ data.filter { isSameDate(field, it) }.forEach { notifyItemChanged(data.indexOf(it)) }
+ }
+
+ override fun convert(holder: BaseViewHolder, item: String) {
+ val split = item.split("-")
+ if (split.size == 3) {
+ calendar.apply {
+ set(Calendar.YEAR, split[0].toInt())
+ set(Calendar.MONTH, split[1].toInt() - 1)
+ set(Calendar.DAY_OF_MONTH, split[2].toInt())
+ }.also {
+ holder.setText(
+ R.id.tv_week, when (it.get(Calendar.DAY_OF_WEEK)) {
+ Calendar.SUNDAY -> "日"
+ Calendar.MONDAY -> "一"
+ Calendar.TUESDAY -> "二"
+ Calendar.WEDNESDAY -> "三"
+ Calendar.THURSDAY -> "四"
+ Calendar.FRIDAY -> "五"
+ Calendar.SATURDAY -> "六"
+ else -> ""
+ }
+ )
+ holder.setText(R.id.tv_day, split[2].toInt().toString())
+ holder.getView<View>(R.id.tv_day).isSelected = isSameDate(item, selectDate)
+ }
+ }
+ }
+
+ //是否是相同日期
+ private fun isSameDate(left: String?, right: String?): Boolean {
+ val l = left?.split("-") ?: emptyList()
+ val r = right?.split("-") ?: emptyList()
+ return l.size == r.size && l[0].toInt() == r[0].toInt() && l[1].toInt() == r[1].toInt() && l[2].toInt() == r[2].toInt()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/adapter/WeekPagerAdapter.kt b/app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/adapter/WeekPagerAdapter.kt
new file mode 100644
index 0000000..e235fea
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/user/mine/scheduling/adapter/WeekPagerAdapter.kt
@@ -0,0 +1,95 @@
+package com.xw.yunwei.ui.user.mine.scheduling.adapter
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+import com.xw.yunwei.R
+import java.time.DayOfWeek
+import java.time.LocalDate
+import java.time.temporal.ChronoUnit
+import java.time.temporal.TemporalAdjusters
+import kotlin.math.abs
+
+
+//一周日期适配器
+class WeekPagerAdapter(
+ var startDate: LocalDate,
+ var endDate: LocalDate,
+) : RecyclerView.Adapter<WeekPagerAdapter.WeekViewHolder>() {
+ private var showStartSundayDate: LocalDate =
+ startDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY))
+ private var showEndSundayDate: LocalDate =
+ endDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY))
+
+ //选中日期
+ var selectDate: LocalDate? = null
+ set(value) {
+ field?.with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY))?.let {
+ ChronoUnit.WEEKS.between(startDate, it)
+ }?.takeIf { it > 0 }?.also {
+ notifyItemChanged(it.toInt())
+ }
+ field = value
+ field?.with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY))?.let {
+ ChronoUnit.WEEKS.between(startDate, it)
+ }?.takeIf { it > 0 }?.also {
+ notifyItemChanged(it.toInt())
+ }
+ }
+
+ //日期item点击事件
+ private var onDateItemClickListener: ((date: LocalDate) -> Unit)? = null
+
+ //设置日期item点击事件
+ fun setOnDateItemClickListener(onDateItemClickListener: ((date: LocalDate) -> Unit)) {
+ this.onDateItemClickListener = onDateItemClickListener
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WeekViewHolder {
+ val inflate =
+ LayoutInflater.from(parent.context).inflate(R.layout.item_date_week, parent, false)
+ return WeekViewHolder(inflate)
+ }
+
+ override fun onBindViewHolder(holder: WeekViewHolder, position: Int) {
+ val localDate = getItem(position)
+ onBindViewHolder(holder, localDate)
+ }
+
+ //获取显示的LocalDate
+ fun getItem(position: Int): LocalDate {
+ return startDate.plusWeeks(position.toLong())
+ }
+
+ private fun onBindViewHolder(holder: WeekViewHolder, date: LocalDate) {
+ // 遍历 7 天,更新每个 TextView
+ for (i in 0 until 7) {
+ val localDate = date.plusDays(i.toLong())
+ holder.children[i].setOnClickListener {
+ selectDate = localDate
+ onDateItemClickListener?.invoke(localDate)
+ }
+ holder.textViews[i].text = localDate.dayOfMonth.toString()
+ holder.textViews[i].isSelected = localDate == selectDate
+ }
+ }
+
+ override fun getItemCount() =
+ abs(ChronoUnit.WEEKS.between(showStartSundayDate, showEndSundayDate).toInt())
+
+ class WeekViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ val children = arrayOf(
+ itemView.findViewById<LinearLayout>(R.id.ll_date1)!!,
+ itemView.findViewById<LinearLayout>(R.id.ll_date2)!!,
+ itemView.findViewById<LinearLayout>(R.id.ll_date3)!!,
+ itemView.findViewById<LinearLayout>(R.id.ll_date4)!!,
+ itemView.findViewById<LinearLayout>(R.id.ll_date5)!!,
+ itemView.findViewById<LinearLayout>(R.id.ll_date6)!!,
+ itemView.findViewById<LinearLayout>(R.id.ll_date7)!!,
+ )
+ val textViews: List<TextView> = children.map { it.getChildAt(0) as TextView }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/user/mine/set/SetActivity.kt b/app/src/main/java/com/xw/yunwei/ui/user/mine/set/SetActivity.kt
index 617ec17..8956cab 100644
--- a/app/src/main/java/com/xw/yunwei/ui/user/mine/set/SetActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/user/mine/set/SetActivity.kt
@@ -3,30 +3,26 @@
import android.annotation.SuppressLint
import android.content.Intent
import android.content.pm.PackageManager
-import android.os.Build
+import android.net.Uri
+import android.provider.Settings
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
-import androidx.lifecycle.lifecycleScope
import com.blankj.utilcode.util.AppUtils
import com.hjq.permissions.OnPermissionCallback
import com.hjq.permissions.Permission
import com.hjq.permissions.XXPermissions
import com.xw.common.CommonDialog
-import com.xw.common.base.BaseActivity
+import com.xw.common.SecureScreenShot
import com.xw.common.net.UpdateManager
-import com.xw.common.utils.MMKVManager
import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.databinding.ActivitySetBinding
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
-import android.net.Uri
-import android.provider.Settings
/**
* 设置
*/
-class SetActivity : BaseActivity<ActivitySetBinding, SetVM>() {
+class SetActivity : BaseBusinessActivity<ActivitySetBinding, SetVM>() {
override fun getBindingVariable() = BR.viewModel
override fun onResume() {
@@ -58,11 +54,19 @@
if (binding.locationTips.text == "去授权") {
val pl = arrayOf(Permission.ACCESS_FINE_LOCATION, Permission.ACCESS_COARSE_LOCATION)
XXPermissions.with(this).permission(pl).request(object : OnPermissionCallback {
- override fun onGranted(permissions: MutableList<String>, allGranted: Boolean) { // 权限同意
- if(allGranted){ binding.locationTips.text = "已开启" }
+ override fun onGranted(
+ permissions: MutableList<String>,
+ allGranted: Boolean
+ ) { // 权限同意
+ if (allGranted) {
+ binding.locationTips.text = "使用APP时"
+ }
}
- override fun onDenied(permissions: MutableList<String>, doNotAskAgain: Boolean) {
+ override fun onDenied(
+ permissions: MutableList<String>,
+ doNotAskAgain: Boolean
+ ) {
super.onDenied(permissions, doNotAskAgain)
//权限禁止
}
@@ -80,32 +84,51 @@
}
binding.about.setOnClickListener {
+ handleAboutClickForScreenShot()
val versionCode = AppUtils.getAppVersionCode()
viewModel.getVersion {
if (versionCode < (it.forceUpdateFlag ?: 0)) {
UpdateManager.instance!!
.setContext(this@SetActivity)
- .apkUrl(it.androidFile ?: "")
+ .apkUrl(it.getDownloadUrl() ?: "")
.updateContent(it.updateDescription ?: "")
.updateVersionCode(it.versionCode ?: 1)
.updateVersionName(it.version ?: "1.0")
.updateForceUpdateFlag(it.forceUpdateFlag ?: 0)
.show()
} else {
- ToastUtilCommon.show("当前也是最新版本")
+ ToastUtilCommon.show("当前已是最新版本")
}
}
}
binding.logOut.setOnClickListener {
- CommonDialog.showTipsDialog(this, "确认退出当前账号登录吗?", rightBlock = {
- MMKVManager.getInstance().clear()
- lifecycleScope.launch {
- delay(100)
- AppUtils.relaunchApp(true)
- }
- true
- })
+ CommonDialog.showCommonTipsDialog(
+ this, "确认退出当前账号登录吗?",
+ cancelable = false,
+ cancelOnTouchOutside = false,
+ leftBlock = {
+ it.dismiss()
+ }, rightBlock = {
+ viewModel.loginOut(it)
+ })
+ }
+ }
+
+ /** 连续点击「关于」的次数,达到阈值后开启截屏权限 */
+ private var aboutClickCount = 0
+
+ /**
+ * 连续点击「关于」5 次后,允许 APP 被截屏(清除 FLAG_SECURE)。
+ */
+ private fun handleAboutClickForScreenShot() {
+ if (SecureScreenShot.allowScreenShot) return
+ aboutClickCount++
+ if (aboutClickCount >= 5) {
+ // 赋值变化会自动刷新所有已登记 window 的截屏标记
+ SecureScreenShot.allowScreenShot = true
+ aboutClickCount = 0
+ ToastUtilCommon.show("已开启截屏权限")
}
}
@@ -115,19 +138,28 @@
binding.switchNotification.isChecked = isEnabled
}
- private fun checkLocation(){
- val result = checkPermission(listOf(Permission.ACCESS_FINE_LOCATION, Permission.ACCESS_COARSE_LOCATION))
+ private fun checkLocation() {
+ val result = checkPermission(
+ listOf(
+ Permission.ACCESS_FINE_LOCATION,
+ Permission.ACCESS_COARSE_LOCATION
+ )
+ )
if (result) {
- binding.locationTips.text = "已开启"
+ binding.locationTips.text = "使用APP时"
} else {
binding.locationTips.text = "去授权"
}
}
- private fun checkPermission(permission: List<String>): Boolean{
+ private fun checkPermission(permission: List<String>): Boolean {
val permissionList: MutableList<String> = ArrayList()
for (permission in permission) {
- if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
+ if (ContextCompat.checkSelfPermission(
+ this,
+ permission
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
permissionList.add(permission)
}
}
diff --git a/app/src/main/java/com/xw/yunwei/ui/user/mine/set/SetVM.kt b/app/src/main/java/com/xw/yunwei/ui/user/mine/set/SetVM.kt
index 273e1c5..f8ff1ce 100644
--- a/app/src/main/java/com/xw/yunwei/ui/user/mine/set/SetVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/user/mine/set/SetVM.kt
@@ -1,9 +1,16 @@
package com.xw.yunwei.ui.user.mine.set
import android.app.Application
+import androidx.lifecycle.viewModelScope
+import com.afollestad.materialdialogs.MaterialDialog
+import com.blankj.utilcode.util.AppUtils
import com.xw.common.base.BaseViewModel
+import com.xw.common.utils.MMKVManager
+import com.xw.yunwei.MyApp
import com.xw.yunwei.model.AppVersionModel
import com.xw.yunwei.net.UserRepository
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
import org.koin.core.component.inject
class SetVM(application: Application) : BaseViewModel(application) {
@@ -18,4 +25,19 @@
}
}
}
+
+ //退出登录
+ fun loginOut(dialog: MaterialDialog) {
+ launchRequest {
+ val resultOk = userRepository.appLoginOut()
+ dialog.dismiss()
+ MMKVManager.getInstance().clear()
+ MyApp.myApp.disconnectWebSocket()
+ MyApp.myApp.unbindPushAccount()
+ viewModelScope.launch {
+ delay(100)
+ AppUtils.relaunchApp(true)
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/user/mine/upload/CertUploadActivity.kt b/app/src/main/java/com/xw/yunwei/ui/user/mine/upload/CertUploadActivity.kt
index 5a16344..12225f2 100644
--- a/app/src/main/java/com/xw/yunwei/ui/user/mine/upload/CertUploadActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/user/mine/upload/CertUploadActivity.kt
@@ -2,32 +2,32 @@
import android.annotation.SuppressLint
import android.net.Uri
+import android.view.View
import com.blankj.utilcode.util.UriUtils
-import com.luck.picture.lib.basic.PictureSelector
import com.luck.picture.lib.config.PictureMimeType
-import com.luck.picture.lib.config.SelectMimeType
import com.luck.picture.lib.entity.LocalMedia
import com.luck.picture.lib.interfaces.OnResultCallbackListener
import com.xw.common.CommonDialog
-import com.xw.common.base.BaseActivity
import com.xw.common.base.ShowImgListDialog
-import com.xw.common.utils.GlideEngine
-import com.xw.common.utils.PictureCompressEngine
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
+import com.xw.yunwei.R
import com.xw.yunwei.databinding.ActivityCertUploadBinding
-import java.util.ArrayList
+import com.xw.yunwei.extension.colorIdToColorValue
+import com.xw.yunwei.utils.PictureSelectorFactory
/**
* 证件上传
*/
-class CertUploadActivity : BaseActivity<ActivityCertUploadBinding, CertUploadVM>() {
+class CertUploadActivity : BaseBusinessActivity<ActivityCertUploadBinding, CertUploadVM>() {
override fun getBindingVariable() = BR.viewModel
- override fun initData() {
- super.initData()
- viewModel.initData()
- }
var operateIndex = -1
+ override fun init() {
+ super.init()
+ viewModel.queryAuditInfo()
+ }
+
override fun setListener() {
super.setListener()
binding.idFront.setOnClickListener { showTypeDialog(0) }
@@ -50,6 +50,111 @@
binding.certRefresh.setOnClickListener { showTypeDialog(4) }
}
+ override fun setObservable() {
+ super.setObservable()
+ viewModel.progress.observe(this) {
+ if (!it.isEffective()) {
+ binding.ivUploadProgress.setImageResource(R.mipmap.icon_clock_blue)
+ binding.tvUploadProgress.setTextColor(
+ com.xw.common.R.color.blue_5.colorIdToColorValue(
+ this
+ )
+ )
+ binding.lvLine1.lineColor = R.color.color_d9d9d9.colorIdToColorValue(this)
+ binding.lvLine1.dashLineEnable = true
+ binding.ivAuditProgress.setImageResource(R.mipmap.icon_circle_gray)
+ binding.tvAuditProgress.setTextColor(
+ com.xw.common.R.color.gray_7.colorIdToColorValue(
+ this
+ )
+ )
+ binding.lvLine2.dashLineEnable = true
+ binding.lvLine2.lineColor = R.color.color_d9d9d9.colorIdToColorValue(this)
+ binding.ivThroughProgress.setImageResource(R.mipmap.icon_circle_gray)
+ binding.tvThroughProgress.setTextColor(
+ com.xw.common.R.color.gray_7.colorIdToColorValue(
+ this
+ )
+ )
+ binding.llNotice.visibility = View.GONE
+ binding.llAudit.visibility = View.GONE
+ binding.svCert.visibility = View.VISIBLE
+ binding.upload.visibility = View.VISIBLE
+ binding.upload.text = "上传"
+ } else if (it.needWaitAudit()) {
+ binding.ivUploadProgress.setImageResource(R.mipmap.icon_tick_green)
+ binding.tvUploadProgress.setTextColor(
+ com.xw.common.R.color.gray_7.colorIdToColorValue(
+ this
+ )
+ )
+ binding.lvLine1.dashLineEnable = false
+ binding.lvLine1.lineColor =
+ com.xw.common.R.color.green_5.colorIdToColorValue(this)
+ binding.ivAuditProgress.setImageResource(R.mipmap.icon_clock_blue)
+ binding.tvAuditProgress.setTextColor(
+ com.xw.common.R.color.blue_5.colorIdToColorValue(
+ this
+ )
+ )
+ binding.lvLine2.dashLineEnable = true
+ binding.lvLine2.lineColor = R.color.color_d9d9d9.colorIdToColorValue(this)
+ binding.ivThroughProgress.setImageResource(R.mipmap.icon_circle_gray)
+ binding.tvThroughProgress.setTextColor(
+ com.xw.common.R.color.gray_7.colorIdToColorValue(
+ this
+ )
+ )
+ binding.llNotice.visibility = View.GONE
+ binding.llAudit.visibility = View.VISIBLE
+ binding.svCert.visibility = View.GONE
+ binding.upload.visibility = View.GONE
+ binding.upload.text = "上传"
+ } else {
+ binding.ivUploadProgress.setImageResource(R.mipmap.icon_tick_green)
+ binding.tvUploadProgress.setTextColor(
+ com.xw.common.R.color.gray_7.colorIdToColorValue(
+ this
+ )
+ )
+ binding.lvLine1.dashLineEnable = false
+ binding.lvLine1.lineColor =
+ com.xw.common.R.color.green_5.colorIdToColorValue(this)
+ binding.ivAuditProgress.setImageResource(R.mipmap.icon_tick_green)
+ binding.tvAuditProgress.setTextColor(
+ com.xw.common.R.color.gray_7.colorIdToColorValue(
+ this
+ )
+ )
+ binding.lvLine2.dashLineEnable = false
+ binding.lvLine2.lineColor =
+ com.xw.common.R.color.green_5.colorIdToColorValue(this)
+ binding.ivThroughProgress.setImageResource(if (it.hadAuditSuccess()) R.mipmap.icon_tick_green else R.mipmap.icon_close_red)
+ binding.tvThroughProgress.text =
+ if (it.hadAuditSuccess()) "认证通过" else "认证失败"
+ binding.tvThroughProgress.setTextColor(
+ (if (it.hadAuditSuccess()) com.xw.common.R.color.gray_7 else com.xw.common.R.color.red_5).colorIdToColorValue(
+ this
+ )
+ )
+ binding.llNotice.visibility =
+ if (it.hadAuditSuccess()) View.GONE else View.VISIBLE
+ binding.tvAuditFail.text = "驳回原因:${it.auditRemark ?: ""}"
+ binding.llAudit.visibility = View.GONE
+ binding.svCert.visibility = View.VISIBLE
+ binding.upload.visibility = View.VISIBLE
+ binding.upload.text = "更新证件资料"
+ }
+ }
+ viewModel.hadAuditHistory.observe(this) {
+ binding.tvWaitAuditNotice.text = if (it) {
+ "本次更新证件正在复核,原有认证资质暂保持有效"
+ } else {
+ "请等待平台审核证件资料"
+ }
+ }
+ }
+
fun showImageDialog(index: Int) {
ShowImgListDialog(
this@CertUploadActivity,
@@ -68,23 +173,12 @@
// 进入图库
@SuppressLint("SourceLockedOrientationActivity")
private fun enterGallery() {
- PictureSelector.create(this)
- .openGallery(SelectMimeType.ofImage())
- .setImageEngine(GlideEngine.createGlideEngine())
- .setMaxSelectNum(1)
- .setImageSpanCount(4)
- .isPreviewImage(true)
- .isDisplayCamera(false)
- .setCompressEngine(PictureCompressEngine())
- .forResult(resultCallbackListener)
+ PictureSelectorFactory.enterGallery(this, 1, resultCallbackListener)
}
// 拍照
private fun takeAPhotograph() {
- PictureSelector.create(this)
- .openCamera(SelectMimeType.ofImage())
- .setCompressEngine(PictureCompressEngine())
- .forResultActivity(resultCallbackListener)
+ PictureSelectorFactory.takeAPhotograph(this, resultCallbackListener)
}
private var resultCallbackListener = object : OnResultCallbackListener<LocalMedia> {
@@ -99,6 +193,7 @@
path
}
viewModel.urls[operateIndex].postValue(imgPath)
+ viewModel.refresh[operateIndex].postValue(true)
}
}
}
diff --git a/app/src/main/java/com/xw/yunwei/ui/user/mine/upload/CertUploadVM.kt b/app/src/main/java/com/xw/yunwei/ui/user/mine/upload/CertUploadVM.kt
index 164e17f..84b1973 100644
--- a/app/src/main/java/com/xw/yunwei/ui/user/mine/upload/CertUploadVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/user/mine/upload/CertUploadVM.kt
@@ -12,16 +12,15 @@
import com.xw.common.utils.MMKVManager
import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.R
+import com.xw.yunwei.model.CertificateAuditInfo
import com.xw.yunwei.model.UserInfo
import com.xw.yunwei.net.CommonRepository
import com.xw.yunwei.net.UserRepository
-import kotlinx.coroutines.delay
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
import org.koin.core.component.inject
import java.io.File
-import kotlin.getValue
class CertUploadVM(application: Application) : BaseViewModel(application) {
@@ -34,9 +33,19 @@
val prove = MutableLiveData("")
val cert = MutableLiveData("")
+ val idFrontRefresh = MutableLiveData(false)
+ val idBackRefresh = MutableLiveData(false)
+ val driveCardRefresh = MutableLiveData(false)
+ val proveRefresh = MutableLiveData(false)
+ val certRefresh = MutableLiveData(false)
+
+ //是否有审核通过历史
+ val hadAuditHistory = MutableLiveData(false)
+
val userInfo by lazy { MMKVManager.getInstance().getModel<UserInfo>(KeyPreferences.USER) }
val urls = listOf(idFront, idBack, driveCard, prove, cert)
+ val refresh = listOf(idFrontRefresh, idBackRefresh, driveCardRefresh, proveRefresh, certRefresh)
val urlModel = listOf(
userInfo?.idCardFront ?: "",
userInfo?.idCardBack ?: "",
@@ -45,6 +54,8 @@
userInfo?.trainingGraduationCertificate ?: ""
)
+ //进度
+ val progress = MutableLiveData<CertificateAuditInfo>()
val onClick = View.OnClickListener {
when (it.id) {
@@ -52,18 +63,21 @@
}
}
- fun initData() {
- idFront.value = (userInfo?.idCardFront ?: "").getUrl()
- idBack.value = (userInfo?.idCardBack ?: "").getUrl()
- driveCard.value = (userInfo?.driverLicense ?: "").getUrl()
- prove.value = (userInfo?.certificateOfNoCriminalRecord ?: "").getUrl()
- cert.value = (userInfo?.trainingGraduationCertificate ?: "").getUrl()
- }
-
var isUploading = false
private fun upload() {
- if (isUploading) return
- isUploading = true
+ if (isUploading || progress.value == null) return
+ if (progress.value?.hadAuditFail() == true || progress.value?.hadAuditSuccess() == true) {
+ idFront.postValue("")
+ idBack.postValue("")
+ driveCard.postValue("")
+ prove.postValue("")
+ cert.postValue("")
+ refresh.forEach { refresh ->
+ refresh.postValue(false)
+ }
+ progress.postValue(CertificateAuditInfo())
+ return
+ }
urls.forEach {
if (it.value.isNullOrEmpty()) {
@@ -71,6 +85,7 @@
return
}
}
+ isUploading = true
val files = mutableListOf<FileSelectBean>()
urls.forEachIndexed { index, it ->
@@ -133,4 +148,25 @@
}
}
}
+
+ //获取审核信息
+ fun queryAuditInfo() {
+ launchRequest {
+ val auditInfo = userRepository.getCertificate() ?: CertificateAuditInfo()
+ progress.postValue(auditInfo)
+ if (auditInfo.isEffective()) {
+ idFront.postValue((auditInfo.idCardFront ?: "").getUrl())
+ idBack.postValue((auditInfo.idCardBack ?: "").getUrl())
+ driveCard.postValue((auditInfo.driverLicense ?: "").getUrl())
+ prove.postValue((auditInfo.certificateOfNoCriminalRecord ?: "").getUrl())
+ cert.postValue((auditInfo.trainingGraduationCertificate ?: "").getUrl())
+ refresh.forEach { refresh ->
+ refresh.postValue(false)
+ }
+ hadAuditHistory.postValue(auditInfo.isInUpdateWaitAudit())
+ } else {
+ hadAuditHistory.postValue(false)
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/widget/CircleProgressView.kt b/app/src/main/java/com/xw/yunwei/ui/widget/CircleProgressView.kt
new file mode 100644
index 0000000..7d8f02e
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/widget/CircleProgressView.kt
@@ -0,0 +1,234 @@
+package com.xw.yunwei.ui.widget
+
+import android.animation.ValueAnimator
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.RectF
+import android.util.AttributeSet
+import android.view.View
+import android.view.animation.AccelerateDecelerateInterpolator
+import androidx.core.graphics.toColorInt
+import com.xw.yunwei.R
+
+class CircularProgressView @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0
+) : View(context, attrs, defStyleAttr) {
+
+ // 画笔
+ private val backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG)
+ private val progressPaint = Paint(Paint.ANTI_ALIAS_FLAG)
+
+ // 颜色
+ var backgroundProgressColor: Int = "#FF9800".toColorInt()
+ set(value) {
+ field = value
+ backgroundPaint.color = value
+ invalidate()
+ }
+
+ var progressColor: Int = "#4CAF50".toColorInt()
+ set(value) {
+ field = value
+ progressPaint.color = value
+ invalidate()
+ }
+
+ //进度圆角风格
+ var progressRoundStyle: Boolean = true
+ set(value) {
+ field = value
+ progressPaint.strokeCap = if (value) Paint.Cap.ROUND else Paint.Cap.BUTT
+ invalidate()
+ }
+
+ // 尺寸
+ var ringWidth: Float = 40f
+ set(value) {
+ field = value
+ backgroundPaint.strokeWidth = value
+ progressPaint.strokeWidth = value
+ requestLayout()
+ }
+
+ // 进度
+ var progress: Float = 0f
+ set(value) {
+ field = value.coerceIn(0f, maxProgress)
+ animateProgress()
+ }
+
+ var maxProgress: Float = 100f
+ set(value) {
+ field = value
+ invalidate()
+ }
+
+ // 动画进度
+ private var animatedProgress: Float = 0f
+ private var progressAnimator: ValueAnimator? = null
+
+ // 坐标
+ private var centerX: Float = 0f
+ private var centerY: Float = 0f
+ private var radius: Float = 0f
+
+ init {
+ setupAttributes(attrs)
+ setupPaints()
+ }
+
+ private fun setupAttributes(attrs: AttributeSet?) {
+ attrs?.let {
+ val typedArray = context.obtainStyledAttributes(it, R.styleable.CircularProgressView)
+
+ try {
+ ringWidth = typedArray.getDimension(
+ R.styleable.CircularProgressView_ringWidth,
+ ringWidth
+ )
+
+ backgroundProgressColor = typedArray.getColor(
+ R.styleable.CircularProgressView_backgroundProgressColor,
+ backgroundProgressColor
+ )
+
+ progressColor = typedArray.getColor(
+ R.styleable.CircularProgressView_progressColor,
+ progressColor
+ )
+
+ progressRoundStyle = typedArray.getBoolean(
+ R.styleable.CircularProgressView_progressRoundStyle,
+ progressRoundStyle
+ )
+
+ progress = typedArray.getFloat(
+ R.styleable.CircularProgressView_progress,
+ progress
+ )
+
+ maxProgress = typedArray.getFloat(
+ R.styleable.CircularProgressView_maxProgress,
+ maxProgress
+ )
+ } finally {
+ typedArray.recycle()
+ }
+ }
+ }
+
+ private fun setupPaints() {
+ // 背景环画笔
+ backgroundPaint.style = Paint.Style.STROKE
+ backgroundPaint.strokeCap = Paint.Cap.ROUND
+ backgroundPaint.strokeWidth = ringWidth
+ backgroundPaint.color = backgroundProgressColor
+
+ // 进度环画笔
+ progressPaint.style = Paint.Style.STROKE
+ progressPaint.strokeCap = if (progressRoundStyle) Paint.Cap.ROUND else Paint.Cap.BUTT
+ progressPaint.strokeWidth = ringWidth
+ progressPaint.color = progressColor
+ }
+
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+ super.onSizeChanged(w, h, oldw, oldh)
+
+ // 计算中心点和半径
+ centerX = w / 2f
+ centerY = h / 2f
+ radius = minOf(w, h) / 2f - ringWidth / 2f
+
+ // 更新画笔宽度
+ backgroundPaint.strokeWidth = ringWidth
+ progressPaint.strokeWidth = ringWidth
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+
+ // 绘制背景环
+ canvas.drawCircle(centerX, centerY, radius, backgroundPaint)
+
+ // 绘制进度环
+ if (animatedProgress > 0) {
+ val sweepAngle = 360f * (animatedProgress / maxProgress)
+ val rect = RectF(
+ centerX - radius,
+ centerY - radius,
+ centerX + radius,
+ centerY + radius
+ )
+
+ canvas.drawArc(
+ rect,
+ -90f, // 从顶部开始
+ -sweepAngle,
+ false,
+ progressPaint
+ )
+ }
+ }
+
+ /**
+ * 设置进度
+ * @param progress 进度值
+ * @param animate 是否开启动画
+ */
+ fun setProgress(progress: Float, animate: Boolean = true) {
+ this.progress = progress.coerceIn(0f, maxProgress)
+
+ if (animate) {
+ animateProgress()
+ } else {
+ animatedProgress = this.progress
+ invalidate()
+ }
+ }
+
+ /**
+ * 进度动画
+ */
+ private fun animateProgress() {
+ progressAnimator?.cancel()
+
+ progressAnimator = ValueAnimator.ofFloat(animatedProgress, progress).apply {
+ duration = 800
+ interpolator = AccelerateDecelerateInterpolator()
+ addUpdateListener { animation ->
+ animatedProgress = animation.animatedValue as Float
+ invalidate()
+ }
+ start()
+ }
+ }
+
+ /**
+ * 获取当前动画进度
+ */
+ fun getAnimatedProgress(): Float = animatedProgress
+
+ /**
+ * 重置进度
+ */
+ fun resetProgress(animate: Boolean = true) {
+ setProgress(0f, animate)
+ }
+
+ /**
+ * 设置进度到最大值
+ */
+ fun setProgressToMax(animate: Boolean = true) {
+ setProgress(maxProgress, animate)
+ }
+
+ /**
+ * 释放资源
+ */
+ fun release() {
+ progressAnimator?.cancel()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/widget/ClearEditText.kt b/app/src/main/java/com/xw/yunwei/ui/widget/ClearEditText.kt
new file mode 100644
index 0000000..9177784
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/widget/ClearEditText.kt
@@ -0,0 +1,195 @@
+package com.xw.yunwei.ui.widget
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.content.res.ColorStateList
+import android.graphics.Canvas
+import android.graphics.Rect
+import android.graphics.RectF
+import android.graphics.drawable.Drawable
+import android.text.Editable
+import android.text.TextWatcher
+import android.util.AttributeSet
+import android.view.MotionEvent
+import androidx.appcompat.widget.AppCompatEditText
+import androidx.core.content.ContextCompat
+import androidx.core.graphics.drawable.DrawableCompat
+import androidx.core.graphics.withClip
+import com.xw.yunwei.R
+
+/**
+ * 自定义 EditText,右侧带有可自定义大小和位置的清除按钮(Canvas 绘制)
+ */
+class ClearEditText @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = androidx.appcompat.R.attr.editTextStyle
+) : AppCompatEditText(context, attrs, defStyleAttr) {
+
+ // 清除按钮相关
+ private var clearIcon: Drawable? = null
+ private var iconWidth: Int = 0
+ private var iconHeight: Int = 0
+ private var iconMarginRight: Int = 0
+ private var iconMarginTop: Int = 0
+ private var showClearIcon: Boolean = true
+ private var iconTint: ColorStateList? = null
+
+ // 图标绘制区域
+ private var iconRect = RectF()
+
+ // 图标绘制区域
+ private var iconRectBound = Rect()
+ private var isIconVisible = false
+
+ // 默认清除图标资源
+ private val defaultClearIconRes = android.R.drawable.ic_menu_close_clear_cancel
+
+ init {
+ // 解析自定义属性
+ val typedArray =
+ context.obtainStyledAttributes(attrs, R.styleable.ClearEditText, defStyleAttr, 0)
+ val clearIconRes =
+ typedArray.getResourceId(R.styleable.ClearEditText_clearIcon, defaultClearIconRes)
+ iconWidth = typedArray.getDimensionPixelSize(R.styleable.ClearEditText_iconWidth, iconWidth)
+ iconHeight =
+ typedArray.getDimensionPixelSize(R.styleable.ClearEditText_iconHeight, iconHeight)
+ iconMarginRight =
+ typedArray.getDimensionPixelSize(
+ R.styleable.ClearEditText_iconMarginRight,
+ iconMarginRight
+ )
+ iconMarginTop =
+ typedArray.getDimensionPixelSize(R.styleable.ClearEditText_iconMarginTop, iconMarginTop)
+ showClearIcon =
+ typedArray.getBoolean(R.styleable.ClearEditText_showClearIcon, showClearIcon)
+ iconTint = typedArray.getColorStateList(R.styleable.ClearEditText_iconTint)
+ typedArray.recycle()
+
+ // 加载图标
+ val drawable = ContextCompat.getDrawable(context, clearIconRes)
+ clearIcon = drawable?.let {
+ val wrapped = DrawableCompat.wrap(it)
+ if (iconTint != null) {
+ DrawableCompat.setTintList(wrapped, iconTint)
+ }
+ wrapped
+ }
+
+ // 添加文本变化监听
+ addTextChangedListener(object : TextWatcher {
+ override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
+ override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
+ updateIconVisibility()
+ }
+
+ override fun afterTextChanged(s: Editable?) {}
+ })
+
+ // 焦点变化监听
+ setOnFocusChangeListener { _, _ ->
+ updateIconVisibility()
+ }
+
+ // 初始更新可见性
+ post { updateIconVisibility() }
+ }
+
+ /**
+ * 更新图标可见性
+ */
+ private fun updateIconVisibility() {
+ val shouldShow = showClearIcon && hasFocus() && text?.isNotEmpty() == true
+ if (isIconVisible != shouldShow) {
+ isIconVisible = shouldShow
+ invalidate()
+ }
+ }
+
+ /**
+ * 计算图标绘制区域
+ */
+ private fun calculateIconRect() {
+ if (clearIcon == null) return
+
+ val paddingRight = paddingEnd
+ val availableHeight = height - paddingTop - paddingBottom
+
+ // 图标右边位置 = 控件右边 - paddingRight - iconMarginRight
+ val right = width - paddingRight - iconMarginRight
+ val left = right - iconWidth
+
+ // 垂直居中,加上 marginTop 微调
+ val centerY = paddingTop + availableHeight / 2f + iconMarginTop
+ val top = centerY - iconHeight / 2f
+ val bottom = centerY + iconHeight / 2f
+
+ iconRect.set(left.toFloat(), top, right.toFloat(), bottom)
+ }
+
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+ super.onSizeChanged(w, h, oldw, oldh)
+ calculateIconRect()
+ }
+
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+
+ // 绘制清除图标
+ if (isIconVisible && clearIcon != null) {
+ canvas.withClip(iconRect) {
+ // 剪切到图标区域(可选,防止绘制超出)
+ iconRectBound.apply {
+ left = iconRect.left.toInt()
+ top = iconRect.top.toInt()
+ right = iconRect.right.toInt()
+ bottom = iconRect.bottom.toInt()
+ }
+ // 设置图标的边界
+ clearIcon?.bounds = iconRectBound
+ clearIcon?.draw(this)
+ }
+ }
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ override fun onTouchEvent(event: MotionEvent): Boolean {
+ if (event.action == MotionEvent.ACTION_UP) {
+ val x = event.x
+ val y = event.y
+ // 检查点击是否在图标区域内
+ if (isIconVisible && iconRect.contains(x, y)) {
+ text?.clear()
+ // 清除后保持焦点
+ requestFocus()
+ performClick() // 辅助功能
+ return true
+ }
+ }
+ return super.onTouchEvent(event)
+ }
+
+ /**
+ * 设置清除按钮是否可见
+ */
+ fun setShowClearIcon(show: Boolean) {
+ showClearIcon = show
+ updateIconVisibility()
+ }
+
+ /**
+ * 设置清除图标资源
+ */
+ fun setClearIconRes(@androidx.annotation.DrawableRes resId: Int) {
+ val drawable = ContextCompat.getDrawable(context, resId)
+ clearIcon = drawable?.let {
+ val wrapped = DrawableCompat.wrap(it)
+ if (iconTint != null) {
+ DrawableCompat.setTintList(wrapped, iconTint)
+ }
+ wrapped
+ }
+ invalidate()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/widget/CustomRefreshLayout.kt b/app/src/main/java/com/xw/yunwei/ui/widget/CustomRefreshLayout.kt
new file mode 100644
index 0000000..4a971f2
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/widget/CustomRefreshLayout.kt
@@ -0,0 +1,37 @@
+package com.xw.yunwei.ui.widget
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.MotionEvent
+import com.scwang.smart.refresh.layout.SmartRefreshLayout
+
+//处理viewpager2+fragment+SmartRefreshLayout+recyclerView 手指上下滑动很容易变成触发viewpager2左右滑动
+class CustomRefreshLayout @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+) : SmartRefreshLayout(context, attrs) {
+
+ private var startX = 0f
+ private var startY = 0f
+
+ override fun onInterceptTouchEvent(e: MotionEvent): Boolean {
+ when (e.action) {
+ MotionEvent.ACTION_DOWN -> {
+ startX = e.x
+ startY = e.y
+ // DOWN 先让 VP2 能收到,不然后续 MOVE 它连机会都没
+ parent.requestDisallowInterceptTouchEvent(false)
+ }
+ MotionEvent.ACTION_MOVE -> {
+ val dx = kotlin.math.abs(e.x - startX)
+ val dy = kotlin.math.abs(e.y - startY)
+ // 纵向主导 → 锁住,VP2 别抢;横向主导 → 放开给 VP2 翻页
+ parent.requestDisallowInterceptTouchEvent(dy > dx/2.5)
+ }
+ MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
+ parent.requestDisallowInterceptTouchEvent(false)
+ }
+ }
+ return super.onInterceptTouchEvent(e)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/widget/DirectionRecyclerView.kt b/app/src/main/java/com/xw/yunwei/ui/widget/DirectionRecyclerView.kt
new file mode 100644
index 0000000..7980e1b
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/widget/DirectionRecyclerView.kt
@@ -0,0 +1,40 @@
+package com.xw.yunwei.ui.widget
+
+import android.content.Context
+import android.util.AttributeSet
+import android.util.Log
+import android.view.MotionEvent
+import androidx.recyclerview.widget.RecyclerView
+
+//
+class DirectionRecyclerView @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null
+) : RecyclerView(context, attrs) {
+
+ private var startX = 0f
+ private var startY = 0f
+
+ override fun onInterceptTouchEvent(e: MotionEvent): Boolean {
+ when (e.action) {
+ MotionEvent.ACTION_DOWN -> {
+ startX = e.x
+ startY = e.y
+ // 先让父 VP2 能拿到 DOWN,否则后续 MOVE 它连机会都没有
+ parent.requestDisallowInterceptTouchEvent(false)
+ }
+ MotionEvent.ACTION_MOVE -> {
+ val dx = kotlin.math.abs(e.x - startX)
+ val dy = kotlin.math.abs(e.y - startY)
+ Log.d("xxx","dx==>$dx")
+ Log.d("xxx","dy==>$dy")
+ // 纵向主导 → RV 自己吃;横向主导 → 放开给 VP2
+ parent.requestDisallowInterceptTouchEvent(dy > dx)
+ }
+ MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
+ parent.requestDisallowInterceptTouchEvent(false)
+ }
+ }
+ return super.onInterceptTouchEvent(e)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/widget/LineView.kt b/app/src/main/java/com/xw/yunwei/ui/widget/LineView.kt
new file mode 100644
index 0000000..d42c651
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/widget/LineView.kt
@@ -0,0 +1,116 @@
+package com.xw.yunwei.ui.widget
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.DashPathEffect
+import android.graphics.Paint
+import android.util.AttributeSet
+import android.view.View
+import com.xw.yunwei.R
+
+class LineView @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0
+) : View(context, attrs, defStyleAttr) {
+ //线条厚度
+ var lineStroke: Float = 4f
+ set(value) {
+ field = value
+ paint.strokeWidth = value
+ invalidate()
+ }
+
+ //虚线长度
+ var dashLineSize: Float = 10f
+ set(value) {
+ field = value
+ paint.pathEffect = DashPathEffect(floatArrayOf(value, lineInterval), 0f)
+ invalidate()
+ }
+
+ //间隔
+ var lineInterval: Float = 10f
+ set(value) {
+ field = value
+ paint.pathEffect = DashPathEffect(floatArrayOf(dashLineSize, value), 0f)
+ invalidate()
+ }
+
+ //线颜色
+ var lineColor: Int = Color.GREEN
+ set(value) {
+ field = value
+ paint.color = value
+ invalidate()
+ }
+
+ //是否启用虚线
+ var dashLineEnable: Boolean = true
+ set(value) {
+ field = value
+ invalidate()
+ }
+ private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
+ style = Paint.Style.STROKE
+ }
+
+ init {
+ setupAttributes(attrs)
+ }
+
+ private fun setupAttributes(attrs: AttributeSet?) {
+ attrs?.let {
+ val typedArray = context.obtainStyledAttributes(it, R.styleable.LineView)
+
+ try {
+ dashLineEnable = typedArray.getBoolean(
+ R.styleable.LineView_dashLineEnable,
+ dashLineEnable
+ )
+ lineStroke = typedArray.getDimension(
+ R.styleable.LineView_dashLineStroke,
+ lineStroke
+ )
+ dashLineSize = typedArray.getDimension(
+ R.styleable.LineView_dashLineSize,
+ dashLineSize
+ )
+ lineInterval = typedArray.getDimension(
+ R.styleable.LineView_lineInterval,
+ lineInterval
+ )
+
+ lineColor = typedArray.getColor(
+ R.styleable.LineView_lineColor,
+ lineColor
+ )
+ } finally {
+ typedArray.recycle()
+ }
+ }
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ paint.apply {
+ color = lineColor
+ strokeWidth = lineStroke
+ // 关键:设置虚线效果
+ // 参数解释:float[] {实线长度, 间隔长度, 实线长度, 间隔长度, ...}
+ pathEffect = if (dashLineEnable) DashPathEffect(
+ floatArrayOf(dashLineSize, lineInterval),
+ 0f
+ ) else null
+ }
+ if (width > height) {
+ //绘制横线
+ canvas.drawLine(0f, height / 2f, width.toFloat(), height / 2f, paint)
+ }
+ if (height > width) {
+ //绘制竖线
+ canvas.drawLine(width / 2f, 0f, width / 2f, height.toFloat(), paint)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/widget/WatermarkDrawable.kt b/app/src/main/java/com/xw/yunwei/ui/widget/WatermarkDrawable.kt
new file mode 100644
index 0000000..df68c92
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/widget/WatermarkDrawable.kt
@@ -0,0 +1,74 @@
+package com.xw.yunwei.ui.widget
+
+import android.graphics.Canvas
+import android.graphics.ColorFilter
+import android.graphics.Paint
+import android.graphics.PixelFormat
+import android.graphics.drawable.Drawable
+import androidx.core.graphics.toColorInt
+
+//水印 Drawable
+class WatermarkDrawable(
+ private val watermarkText: String,
+ private val textColor: Int = "#1A000000".toColorInt(), // 浅灰色
+ private val textSize: Float = 40f,
+ private val watermarkTextRotation: Float = -30f, // 旋转角度
+ private val spacingX: Float = 200f, // 水印占用宽度
+ private val spacingY: Float = 200f, // 水印占用高度
+ private val isStaggered: Boolean = true, // 是否交错排列
+) : Drawable() {
+
+ private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
+ color = textColor
+ textSize = this@WatermarkDrawable.textSize
+ textAlign = Paint.Align.CENTER
+ alpha = 50 // 设置透明度
+ }
+
+ override fun draw(canvas: Canvas) {
+ val bounds = bounds
+ val width = bounds.width()
+ val height = bounds.height()
+
+ val textWidth = paint.measureText(watermarkText)
+ // 计算水印之间的间距
+ val textHeight = paint.descent() - paint.ascent()
+
+ // 保存画布状态
+ canvas.save()
+
+ // 计算每行每列的数量
+ val countX = (width / spacingX).toInt() + 2
+ val countY = (height / spacingY).toInt() + 2
+
+ for (i in -1..countY) {
+ for (j in -1..countX) {
+ canvas.save()
+
+ val x = j * spacingX
+ val y = i * spacingY
+
+ // 交错排列
+ val offsetX = if (isStaggered && i % 2 == 0) spacingX / 2 else 0f
+
+ // 移动到绘制位置
+ canvas.translate(x + offsetX, y)
+ // 旋转
+ canvas.rotate(watermarkTextRotation, textWidth / 2, textHeight / 2)
+ // 绘制文字
+ canvas.drawText(watermarkText, 0f, textHeight / 2 - paint.descent(), paint)
+ canvas.restore()
+ }
+ }
+ }
+
+ override fun setAlpha(alpha: Int) {
+ paint.alpha = alpha
+ }
+
+ override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
+
+ override fun setColorFilter(colorFilter: ColorFilter?) {
+ paint.colorFilter = colorFilter
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/widget/WatermarkView.kt b/app/src/main/java/com/xw/yunwei/ui/widget/WatermarkView.kt
new file mode 100644
index 0000000..a42b201
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/widget/WatermarkView.kt
@@ -0,0 +1,114 @@
+package com.xw.yunwei.ui.widget
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.util.AttributeSet
+import android.view.View
+import androidx.core.content.withStyledAttributes
+import androidx.core.graphics.toColorInt
+import com.xw.yunwei.R
+
+//水印背景
+class WatermarkView @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0
+) : View(context, attrs, defStyleAttr) {
+
+ var watermarkText: String = "保密"
+ set(value) {
+ field = value
+ invalidate()
+ }
+ var textColor: Int = "#1A000000".toColorInt()
+ set(value) {
+ field = value
+ paint.color = value
+ invalidate()
+ }
+ var textSize: Float = 40f
+ set(value) {
+ field = value
+ paint.textSize = value
+ invalidate()
+ }
+ var watermarkTextRotation: Float = -30f
+ set(value) {
+ field = value
+ invalidate()
+ }
+ var spacingX: Float = 200f
+ set(value) {
+ field = value
+ invalidate()
+ }
+ var spacingY: Float = 150f
+ set(value) {
+ field = value
+ invalidate()
+ }
+ var isStaggered: Boolean = true // 是否交错排列
+ set(value) {
+ field = value
+ invalidate()
+ }
+
+ val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
+ isAntiAlias = true
+ style = Paint.Style.FILL
+ }
+
+ init {
+ // 从 XML 属性读取配置
+ attrs?.let {
+ context.withStyledAttributes(it, R.styleable.WatermarkView) {
+ watermarkText = getString(R.styleable.WatermarkView_watermarkText) ?: "保密"
+ textColor = getColor(R.styleable.WatermarkView_textColor, textColor)
+ textSize = getDimension(R.styleable.WatermarkView_textSize, textSize)
+ watermarkTextRotation =
+ getFloat(R.styleable.WatermarkView_watermarkTextRotation, watermarkTextRotation)
+ spacingX = getDimension(R.styleable.WatermarkView_spacingX, spacingX)
+ spacingY = getDimension(R.styleable.WatermarkView_spacingY, spacingY)
+ isStaggered = getBoolean(R.styleable.WatermarkView_isStaggered, isStaggered)
+ }
+ }
+
+ paint.color = textColor
+ paint.textSize = textSize
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+
+ val width = width.toFloat()
+ val height = height.toFloat()
+ val textWidth = paint.measureText(watermarkText)
+ val textHeight = paint.descent() - paint.ascent()
+
+ // 计算每行每列的数量
+ val countX = (width / spacingX).toInt() + 2
+ val countY = (height / spacingY).toInt() + 2
+
+ for (i in -1..countY) {
+ for (j in -1..countX) {
+ canvas.save()
+
+ val x = j * spacingX
+ val y = i * spacingY
+
+ // 交错排列
+ val offsetX = if (isStaggered && i % 2 == 0) spacingX / 2 else 0f
+
+ // 移动到绘制位置
+ canvas.translate(x + offsetX, y)
+ // 旋转
+ canvas.rotate(watermarkTextRotation, textWidth / 2, textHeight / 2)
+ // 绘制文字
+ canvas.drawText(watermarkText, 0f, textHeight / 2 - paint.descent(), paint)
+
+ canvas.restore()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/AMapFragment.kt b/app/src/main/java/com/xw/yunwei/ui/work/AMapFragment.kt
index 8a7514a..8cd6eb5 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/AMapFragment.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/AMapFragment.kt
@@ -3,6 +3,7 @@
import android.content.Context
import android.content.Intent
import android.graphics.Color
+import android.graphics.Point
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
@@ -59,6 +60,9 @@
private var locationMarker: Marker? = null
private var isMoved = false // 是否已经移动过地图
private var currentZoom = 14f
+
+ /** Screen-Y ratio used for the initial auto-center on first GPS fix. 0.5 = screen center. */
+ var initialLocationScreenYRatio: Float = 0.5f
private var polygonAreas = mutableListOf<Polygon>() // 面区域s
var polylines = mutableListOf<Polyline>() // 线s
@@ -195,6 +199,7 @@
view.findViewById<AppCompatTextView>(R.id.name).text = marker.snippet
return view
}
+
// 定制 InfoWindow 内容(如果 getInfoWindow 返回 null,则使用此方法)
override fun getInfoContents(marker: Marker): View? {
return null // 使用上面的 getInfoWindow
@@ -204,7 +209,8 @@
private fun initSensor() {
if (needSensor) {
- sensorManager = requireActivity().getSystemService(Context.SENSOR_SERVICE) as SensorManager
+ sensorManager =
+ requireActivity().getSystemService(Context.SENSOR_SERVICE) as SensorManager
// 尝试获取方向传感器。TYPE_ORIENTATION已废弃,但兼容性好。
orientationSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION)
// 如果设备不支持TYPE_ORIENTATION,可以尝试使用更新的传感器类型,如TYPE_GAME_ROTATION_VECTOR
@@ -272,7 +278,7 @@
updateLocationMarker(l.latitude, l.longitude)
if (!isMoved) {
isMoved = true
- moveToLocation()
+ moveToLocation(initialLocationScreenYRatio)
}
}
locationChangeCallback?.invoke(l)
@@ -299,12 +305,16 @@
/*==========================对外============================*/
+ fun setCurrentZoom(zoom: Float) {
+ currentZoom = zoom
+ }
+
/* 移动到当前定位 */
- fun moveToLocation() {
+ fun moveToLocation(targetScreenYRatio: Float = 0.5f) {
locationMarker?.let {
currentZoom = 16f
val position = locationMarker!!.position
- moveTo(position.latitude, position.longitude)
+ animateTo(position.latitude, position.longitude, currentZoom, targetScreenYRatio)
} ?: run { ToastUtilCommon.showWarn("未获取到定位信息") }
}
@@ -316,6 +326,32 @@
zoom
)
)
+ }
+ }
+
+ fun animateTo(
+ latitude: Double,
+ longitude: Double,
+ zoom: Float = currentZoom,
+ targetScreenYRatio: Float = 0.5f
+ ) {
+ lifecycleScope.launchWhenResumed {
+ val map = aMap ?: return@launchWhenResumed
+ val height = mapView?.height ?: 0
+ if (height == 0 || targetScreenYRatio == 0.5f) {
+ val update = CameraUpdateFactory.newLatLngZoom(LatLng(latitude, longitude), zoom)
+ map.animateCamera(update, 300, null)
+ return@launchWhenResumed
+ }
+ // Analytically compute the camera offset so the marker lands at targetScreenYRatio
+ // This avoids depending on current projection which would stack offsets on repeated calls
+ val deltaYPixels = height * (0.5f - targetScreenYRatio)
+ val metersPerPixel =
+ 156543.03392 * Math.cos(Math.toRadians(latitude)) / Math.pow(2.0, zoom.toDouble())
+ val deltaLat = deltaYPixels * metersPerPixel / 111320.0
+ val targetLatLng = LatLng(latitude + deltaLat, longitude)
+ val update = CameraUpdateFactory.newLatLngZoom(targetLatLng, zoom)
+ map.animateCamera(update, 300, null)
}
}
@@ -351,7 +387,9 @@
point: LatLng,
resId: Int,
id: String,
- description: String? = null
+ description: String? = null,
+ anchorHeightRatio: Float = 0.5f,
+ infoWindowOffsetY: Int = 0,
) {
lifecycleScope.launchWhenResumed {
aMap?.let { aMap ->
@@ -361,11 +399,12 @@
val markerOptions = MarkerOptions()
.position(point)
.icon(centerIcon)
- .anchor(0.5f, 0.5f) // 将图标的中心点(而非左下角)设置为锚点,这样旋转更自然
+ .anchor(0.5f, anchorHeightRatio) // 将图标的中心点(而非左下角)设置为锚点,这样旋转更自然
.setFlat(true) // 重要:设置为平面模式,Marker可围绕锚点旋转
- .title(description?:"")
- .snippet(description?:"")
+ .title(description ?: "")
+ .snippet(description ?: "")
.draggable(true)
+ .setInfoWindowOffset(0, infoWindowOffsetY)
description?.let { markerOptions.title(tag) }
marker = aMap.addMarker(markerOptions)
@@ -396,7 +435,7 @@
}
}
- fun clearMarks(){
+ fun clearMarks() {
customMarkers.forEach { it.value.remove() }
customMarkers.clear()
}
@@ -454,8 +493,12 @@
} else {
marker.showInfoWindow()
}
- currentBigMarker?.let { setMarkerScaleAnimation(it, 2.0f, 1.0f) }
- setMarkerScaleAnimation(marker, 1.0f, 2.0f)
+ currentBigMarker?.let {
+ setMarkerScaleAnimation(it, 1.5f, 1.0f)
+ it.zIndex = 0f
+ }
+ setMarkerScaleAnimation(marker, 1.0f, 1.5f)
+ marker.zIndex = 1f
currentBigMarker = marker
}
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/CarAdapter.kt b/app/src/main/java/com/xw/yunwei/ui/work/CarAdapter.kt
index 3bd2c21..828f660 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/CarAdapter.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/CarAdapter.kt
@@ -21,14 +21,9 @@
binding?.let {
it.root.setOnClickListener { listener.onItemClick(item) }
- var url = ""
- try {
- url = item.vehiclePictures?.getUrl() ?: ""
- } catch (e: Exception) {
- }
- ViewAdapter.loadImage(binding.icon, ImageDefault(url, R.mipmap.img_work_car))
+ ViewAdapter.loadImage(binding.icon, ImageDefault(item.getShowVehiclePicture(), R.mipmap.img_work_car))
binding.name.text = item.plateNumber
- binding.no.text = "NO.${item.vehicleCode}"
+ binding.no.text = item.getShowVehicleCode(6)
binding.batteryLife.text = "${item.mileageRange?.toInt()}km"
binding.batteryLife.setTextColor(
com.xw.common.custom.BatteryView.getBatteryColor(
@@ -36,18 +31,7 @@
)
)
binding.batteryView.setLevel(item.currentElectricity ?: 0)
-
- val setStatus: (Int) -> Unit = { id ->
- binding.status.setImageResource(id)
- }
-
- // 1=运营中 2=维修中 3=已收车 4=车辆异常
- when (item.operatingStatus) {
- 1 -> setStatus(R.mipmap.ic_work_fache)
- 2 -> setStatus(R.mipmap.ic_work_weixiu)
- 3 -> setStatus(R.mipmap.ic_work_quche)
- 4 -> setStatus(R.mipmap.ic_work_weixiu)
- }
+ binding.status.setImageResource(item.getShowStatusImageResource())
}
}
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/WorkVM.kt b/app/src/main/java/com/xw/yunwei/ui/work/WorkVM.kt
index f250aa7..5be8e3c 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/WorkVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/WorkVM.kt
@@ -5,15 +5,14 @@
import androidx.core.os.bundleOf
import androidx.lifecycle.MutableLiveData
import com.xw.common.base.BaseViewModel
+import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.R
import com.xw.yunwei.model.CarModel
import com.xw.yunwei.net.WorkRepository
-import com.xw.yunwei.ui.task.create.CreateTaskActivity
import com.xw.yunwei.ui.task.selectCar.SelectCarActivity
import com.xw.yunwei.ui.work.car.manage.CarManageActivity
import com.xw.yunwei.ui.work.site.SiteNavActivity
import org.koin.core.component.inject
-import kotlin.getValue
class WorkVM(application: Application) : BaseViewModel(application) {
val workRepository: WorkRepository by inject()
@@ -26,10 +25,28 @@
val onClick = View.OnClickListener {
when (it.id) {
- R.id.cardManage -> startActivity(CarManageActivity::class.java)
- R.id.siteNav -> startActivity(SiteNavActivity::class.java)
+ R.id.cardManage -> {
+ if (carPermissions.value != true) {
+ ToastUtilCommon.showError("暂无查看权限")
+ return@OnClickListener
+ }
+ startActivity(CarManageActivity::class.java)
+ }
+
+ R.id.siteNav -> {
+ if (sitePermissions.value != true) {
+ ToastUtilCommon.showError("暂无查看权限")
+ return@OnClickListener
+ }
+ startActivity(SiteNavActivity::class.java)
+ }
+
R.id.report -> {
// startActivity(CreateTaskActivity::class.java)
+ if (reportPermissions.value != true) {
+ ToastUtilCommon.showError("暂无查看权限")
+ return@OnClickListener
+ }
startActivity(
SelectCarActivity::class.java,
bundleOf("car" to null)
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/amap/custom/view/CarOverlay.java b/app/src/main/java/com/xw/yunwei/ui/work/amap/custom/view/CarOverlay.java
new file mode 100644
index 0000000..9e3b09f
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/amap/custom/view/CarOverlay.java
@@ -0,0 +1,292 @@
+package com.xw.yunwei.ui.work.amap.custom.view;
+
+import android.content.Context;
+import android.graphics.BitmapFactory;
+
+import com.amap.api.maps.AMap;
+import com.amap.api.maps.AMapUtils;
+import com.amap.api.maps.CameraUpdateFactory;
+import com.amap.api.maps.TextureMapView;
+import com.amap.api.maps.model.BitmapDescriptor;
+import com.amap.api.maps.model.BitmapDescriptorFactory;
+import com.amap.api.maps.model.CameraPosition;
+import com.amap.api.maps.model.LatLng;
+import com.amap.api.maps.model.Marker;
+import com.amap.api.maps.model.MarkerOptions;
+import com.amap.api.maps.model.Polyline;
+import com.autonavi.amap.mapcore.IPoint;
+import com.xw.yunwei.R;
+import com.xw.yunwei.ui.work.amap.util.BasicThreadFactory;
+import com.xw.yunwei.ui.work.amap.util.NaviUtil;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 包名: com.amap.api.navi.core
+ * <p>
+ * 创建时间:2018/3/1
+ * 项目名称:AndroidNavigationSDK
+ *
+ * @author guibao.ggb
+ * @email guibao.ggb@alibaba-inc.com
+ * <p>
+ * 类说明:自车位置管理Overlay类
+ */
+public class CarOverlay {
+
+ protected static final int CAR_MOVE_ANIMATION_PERIOD = 50;
+ protected int carMoveAnimationFrameNum = 2;
+ protected boolean mIsLock = true;
+ protected IPoint mapAnchorBackup = null;
+ protected double dXOffStep;
+ protected double dYOffStep;
+ protected float dAngleOffStep;
+ protected int currentFrameIndex;
+ protected float angleStart = 0;
+ protected boolean isMoveStarted = false;
+ protected float newAngle = 0;
+ protected BitmapDescriptor carDescriptor = null;
+ protected BitmapDescriptor fourCornersDescriptor = null;
+ protected Marker carMarker;
+ protected Marker directionMarker;
+ protected AMap mAmap = null;
+ protected TextureMapView mapView;
+ protected boolean isDirectionVisible = false;
+ protected LatLng endLatLng = null;
+ protected Polyline leaderLine = null;
+ protected final int DISTANCE_OFFSET = 150;// 默认 500 偏差
+
+ // API 默认 1800 UI 默认 360
+ protected int angleModValue = 1800;
+
+
+ private ScheduledExecutorService executorService;
+
+ public CarOverlay(Context context, TextureMapView mapView) {
+ this.mapView = mapView;
+
+ fourCornersDescriptor = BitmapDescriptorFactory.fromBitmap(BitmapFactory
+ .decodeResource(context.getResources(),
+ R.mipmap.navi_direction));
+
+ carDescriptor = BitmapDescriptorFactory.fromBitmap(BitmapFactory
+ .decodeResource(context.getResources(),
+ R.mipmap.icon_map_arrow_blue));
+ angleModValue = 1800;
+
+ }
+
+ /**
+ * 设置自车状态
+ *
+ * @param lock true 锁车 false 非锁车
+ */
+ public void setLock(boolean lock) {
+ mIsLock = lock;
+ if (carMarker == null) {
+ return;
+ }
+ if (mAmap == null) {
+ return;
+ }
+ if (directionMarker == null) {
+ return;
+ }
+ carMarker.setFlat(true);
+ directionMarker.setGeoPoint(carMarker.getGeoPoint());
+ carMarker.setGeoPoint(carMarker.getGeoPoint());
+ carMarker.setRotateAngle(carMarker.getRotateAngle());
+ if (mIsLock) {
+ CameraPosition cameraPosition = new CameraPosition.Builder().target(carMarker.getPosition()).bearing(newAngle).tilt(0).zoom(16).build();
+ mAmap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
+ }
+ }
+
+ public void reset() {
+ if (carMarker != null) {
+ carMarker.remove();
+ }
+ if (directionMarker != null) {
+ directionMarker.remove();
+ }
+ if (leaderLine != null) {
+ leaderLine.remove();
+ }
+ leaderLine = null;
+ carMarker = null;
+ directionMarker = null;
+
+ if (executorService != null) {
+ if (!executorService.isShutdown()) {
+ executorService.shutdown();
+ }
+ isMoveStarted = false;
+
+ executorService = null;
+ }
+ }
+
+ /**
+ * 绘制自车
+ *
+ * @param aMap
+ * @param mLatLng
+ * @param bearing
+ */
+ public void draw(AMap aMap, LatLng mLatLng, float bearing) {
+ if (aMap == null || mLatLng == null || carDescriptor == null) {
+ return;
+ }
+ mAmap = aMap;
+ try {
+ if (carMarker == null) {
+ carMarker = aMap.addMarker(new MarkerOptions().anchor(0.5f, 0.5f).setFlat(true).icon(carDescriptor).position(mLatLng));
+ }
+
+ if (directionMarker == null) {
+ directionMarker = aMap.addMarker(new MarkerOptions().anchor(0.5f, 0.5f).setFlat(true).icon(fourCornersDescriptor).position(mLatLng));
+ if (isDirectionVisible) {
+ directionMarker.setVisible(true);
+ } else {
+ directionMarker.setVisible(false);
+ }
+ }
+ carMarker.setVisible(true);
+ newAngle = bearing;
+ IPoint resultGeoPnt = IPoint.obtain();
+ resultGeoPnt = NaviUtil.lonlat2Geo(mLatLng.latitude, mLatLng.longitude, 20);
+ updateCarPosition(resultGeoPnt);
+ resultGeoPnt.recycle();
+
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ private void updateCarPosition(IPoint p) {
+ carMarker.setGeoPoint(p);
+ carMarker.setFlat(true);
+ carMarker.setRotateAngle(360 - newAngle);
+ if (directionMarker != null) {
+ directionMarker.setGeoPoint(p);
+ }
+
+ if (mIsLock) {
+ CameraPosition cameraPosition = new CameraPosition.Builder().target(carMarker.getPosition()).bearing(newAngle).tilt(0).zoom(16).build();
+ mAmap.moveCamera(CameraUpdateFactory.changeBearingGeoCenter(newAngle, p));
+ }
+ }
+
+
+ public void setEndPoi(LatLng latlng) {
+ endLatLng = latlng;
+ }
+
+ /**
+ * 释放自车资源
+ */
+ public void destroy() {
+ if (carMarker != null) {
+ carMarker.remove();
+ carMarker = null;
+ }
+ if (directionMarker != null) {
+ directionMarker.remove();
+ directionMarker = null;
+ }
+ carDescriptor = null;
+
+ if (executorService != null && !executorService.isShutdown()) {
+ executorService.shutdown();
+ isMoveStarted = false;
+
+ executorService = null;
+ }
+ }
+
+ private void calculateCarSmoothMoveOffset(IPoint newCenter, float newAngle) {
+ if (carMarker == null) {
+ return;
+ }
+ IPoint currentAnchorGeoPoint = carMarker.getGeoPoint();
+ if (currentAnchorGeoPoint == null || currentAnchorGeoPoint.x == 0 || currentAnchorGeoPoint.y == 0) {
+ currentAnchorGeoPoint = newCenter;
+ }
+ currentFrameIndex = 0;
+ mapAnchorBackup = currentAnchorGeoPoint;
+ dXOffStep = (newCenter.x - currentAnchorGeoPoint.x) / carMoveAnimationFrameNum;
+ dYOffStep = (newCenter.y - currentAnchorGeoPoint.y) / carMoveAnimationFrameNum;
+ // 获取当前的旋转角度
+ angleStart = carMarker.getRotateAngle();
+ boolean isFirst = false;
+
+ if (Float.compare(angleStart, newAngle) == 0) {
+ isFirst = true;
+ } else {
+ angleStart = 360 - angleStart;
+ }
+ // 校正旋转角度问题
+ float dAngleDelta = newAngle - angleStart;
+ if (isFirst) {
+ dAngleDelta = 0;
+ }
+ if (dAngleDelta > 180) {
+ dAngleDelta = dAngleDelta - 360;
+ }
+ else if (dAngleDelta < -180) {
+ dAngleDelta = dAngleDelta + 360;
+ }
+ dAngleOffStep = dAngleDelta / carMoveAnimationFrameNum;
+ isMoveStarted = true;
+ }
+
+ protected void startSmoothMoveTimer() {
+ if (executorService == null) {
+ executorService = new ScheduledThreadPoolExecutor(1, new BasicThreadFactory.Builder().namingPattern("caroverlay-schedule-pool-%d").daemon(true).build());
+
+ executorService.scheduleAtFixedRate(new Runnable() {
+ long currentSeconds;
+ @Override
+ public void run() {
+ try{
+ currentSeconds = System.currentTimeMillis();
+ mapSmoothMoveTimerTick();
+ } catch(Throwable e){
+ e.printStackTrace();
+ }
+ }
+ }, 0, CAR_MOVE_ANIMATION_PERIOD, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ private void mapSmoothMoveTimerTick() {
+ if (!isMoveStarted) {
+ return;
+ }
+ if (carMarker == null) {
+ return;
+ }
+ if (mAmap == null) {
+ return;
+ }
+ try {
+ IPoint p = carMarker.getGeoPoint();
+ double newX = 0, newY = 0;
+ if (currentFrameIndex++ < carMoveAnimationFrameNum) {
+ newX = mapAnchorBackup.x + dXOffStep * currentFrameIndex;
+ newY = mapAnchorBackup.y + dYOffStep * currentFrameIndex;
+ newAngle = angleStart + dAngleOffStep * currentFrameIndex;
+ newAngle %= angleModValue;
+ if (newX != 0 || newY != 0) {
+ p = new IPoint((int)newX, (int)newY);
+ }
+ updateCarPosition(p);
+ }
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/amap/util/BasicThreadFactory.java b/app/src/main/java/com/xw/yunwei/ui/work/amap/util/BasicThreadFactory.java
new file mode 100644
index 0000000..dfe620d
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/amap/util/BasicThreadFactory.java
@@ -0,0 +1,252 @@
+package com.xw.yunwei.ui.work.amap.util;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * 包名: com.amap.api.navi.core
+ * <p>
+ * 创建时间:2018/3/12
+ * 项目名称:AndroidNavigationSDK
+ *
+ * @author guibao.ggb
+ * @email guibao.ggb@alibaba-inc.com
+ * <p>
+ * 类说明:
+ */
+public class BasicThreadFactory implements ThreadFactory {
+
+ //计算线程工厂创建的线程数
+ private final AtomicLong threadCounter;
+
+ //包装工厂
+ private final ThreadFactory wrappedFactory;
+
+ //非捕获异常处理
+ private final Thread.UncaughtExceptionHandler uncaughtExceptionHandler;
+
+ //线程命名模式
+ private final String namingPattern;
+
+ //优先级
+ private final Integer priority;
+
+ //后台状态标识
+ private final Boolean daemonFlag;
+
+ /**
+ * Creates a new instance of {@code ThreadFactoryImpl} and configures it
+ * from the specified {@code Builder} object.
+ *
+ * @param builder the {@code Builder} object
+ */
+ private BasicThreadFactory(Builder builder) {
+ if (builder.wrappedFactory == null) {
+ wrappedFactory = Executors.defaultThreadFactory();
+ } else {
+ wrappedFactory = builder.wrappedFactory;
+ }
+
+ namingPattern = builder.namingPattern;
+ priority = builder.priority;
+ daemonFlag = builder.daemonFlag;
+ uncaughtExceptionHandler = builder.exceptionHandler;
+
+ threadCounter = new AtomicLong();
+ }
+
+ /**
+ * 获取包装工厂
+ * @return 不会返回null
+ */
+ public final ThreadFactory getWrappedFactory() {
+ return wrappedFactory;
+ }
+
+ /**
+ * 获取命名模式
+ * @return
+ */
+ public final String getNamingPattern() {
+ return namingPattern;
+ }
+
+ /**
+ * 获取是否为后台线程标识
+ * @return
+ */
+ public final Boolean getDaemonFlag() {
+ return daemonFlag;
+ }
+
+ /**
+ * 获取优先级
+ * @return
+ */
+ public final Integer getPriority() {
+ return priority;
+ }
+
+ /**
+ * 获取非捕获异常处理器
+ * @return
+ */
+ public final Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() {
+ return uncaughtExceptionHandler;
+ }
+
+ /**
+ * 获取创建的线程数量
+ * @return
+ */
+ public long getThreadCount() {
+ return threadCounter.get();
+ }
+
+ /**
+ * 创建新线程
+ * @param r
+ * @return
+ */
+ @Override
+ public Thread newThread(Runnable r) {
+ Thread t = getWrappedFactory().newThread(r);
+ initializeThread(t);
+
+ return t;
+ }
+
+ /**
+ * 初始化线程
+ * @param t
+ */
+ private void initializeThread(Thread t) {
+
+ if (getNamingPattern() != null) {
+ Long count = Long.valueOf(threadCounter.incrementAndGet());
+ t.setName(String.format(getNamingPattern(), count));
+ }
+
+ if (getUncaughtExceptionHandler() != null) {
+ t.setUncaughtExceptionHandler(getUncaughtExceptionHandler());
+ }
+
+ if (getPriority() != null) {
+ t.setPriority(getPriority().intValue());
+ }
+
+ if (getDaemonFlag() != null) {
+ t.setDaemon(getDaemonFlag().booleanValue());
+ }
+ }
+
+ /**
+ * 创建器类
+ */
+ public static class Builder implements IBuilder<BasicThreadFactory> {
+
+ //包装工厂
+ private ThreadFactory wrappedFactory;
+
+ //非捕获异常处理器
+ private Thread.UncaughtExceptionHandler exceptionHandler;
+
+ //命名模式
+ private String namingPattern;
+
+ //优先级
+ private Integer priority;
+
+ //后台标识
+ private Boolean daemonFlag;
+
+ /**
+ * 创建包装工厂
+ * @param factory
+ * @return
+ */
+ public Builder wrappedFactory(ThreadFactory factory) {
+ if (factory == null) {
+ throw new NullPointerException(
+ "Wrapped ThreadFactory must not be null!");
+ }
+
+ wrappedFactory = factory;
+ return this;
+ }
+
+ /**
+ * 设置命名模式
+ * @param pattern
+ * @return
+ */
+ public Builder namingPattern(String pattern) {
+ if (pattern == null) {
+ throw new NullPointerException(
+ "Naming pattern must not be null!");
+ }
+
+ namingPattern = pattern;
+ return this;
+ }
+
+ /**
+ * 设置后台标识
+ * @param f
+ * @return
+ */
+ public Builder daemon(boolean f) {
+ daemonFlag = Boolean.valueOf(f);
+ return this;
+ }
+
+ /**
+ * 设置优先级
+ * @param prio
+ * @return
+ */
+ public Builder priority(int prio) {
+ priority = Integer.valueOf(prio);
+ return this;
+ }
+
+ /**
+ * 设置非捕获异常处理器
+ * @param handler
+ * @return
+ */
+ public Builder uncaughtExceptionHandler(
+ Thread.UncaughtExceptionHandler handler) {
+ if (handler == null) {
+ throw new NullPointerException(
+ "Uncaught exception handler must not be null!");
+ }
+
+ exceptionHandler = handler;
+ return this;
+ }
+
+ /**
+ * 重置构建参数
+ */
+ public void reset() {
+ wrappedFactory = null;
+ exceptionHandler = null;
+ namingPattern = null;
+ priority = null;
+ daemonFlag = null;
+ }
+
+ /**
+ * 构建基类线程工厂
+ * @return
+ */
+ @Override
+ public BasicThreadFactory build() {
+ BasicThreadFactory factory = new BasicThreadFactory(this);
+ reset();
+ return factory;
+ }
+ }
+}
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/amap/util/IBuilder.java b/app/src/main/java/com/xw/yunwei/ui/work/amap/util/IBuilder.java
new file mode 100644
index 0000000..d15a3a9
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/amap/util/IBuilder.java
@@ -0,0 +1,17 @@
+package com.xw.yunwei.ui.work.amap.util;
+
+/**
+ * 包名: com.amap.api.navi.core
+ * <p>
+ * 创建时间:2018/3/12
+ * 项目名称:AndroidNavigationSDK
+ *
+ * @author guibao.ggb
+ * @email guibao.ggb@alibaba-inc.com
+ * <p>
+ * 类说明:构建器接口
+ */
+public interface IBuilder<T> {
+
+ T build();
+}
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/amap/util/NaviUtil.java b/app/src/main/java/com/xw/yunwei/ui/work/amap/util/NaviUtil.java
new file mode 100644
index 0000000..e8c0026
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/amap/util/NaviUtil.java
@@ -0,0 +1,120 @@
+package com.xw.yunwei.ui.work.amap.util;
+
+import com.amap.api.maps.AMapUtils;
+import com.amap.api.maps.model.LatLng;
+import com.amap.api.navi.model.NaviLatLng;
+import com.autonavi.amap.mapcore.IPoint;
+import com.autonavi.amap.mapcore.MapProjection;
+
+/**
+ * 包名: com.amap.navi.demo.util
+ * <p>
+ * 创建时间:2018/4/19
+ * 项目名称:NaviDemo
+ *
+ * @author guibao.ggb
+ * @email guibao.ggb@alibaba-inc.com
+ * <p>
+ * 类说明:
+ */
+public class NaviUtil {
+ /**
+ * 转换成LatLng对象
+ *
+ * @param naviLatLng 导航经纬度对象
+ */
+ public static LatLng toLatLng(NaviLatLng naviLatLng) {
+ return new LatLng(naviLatLng.getLatitude(), naviLatLng.getLongitude());
+ }
+
+ public static float calculateDistance(NaviLatLng start, NaviLatLng end) {
+ double x1 = start.getLongitude();
+ double y1 = start.getLatitude();
+ double x2 = end.getLongitude();
+ double y2 = end.getLatitude();
+ return AMapUtils.calculateLineDistance(new LatLng(y1, x1), new LatLng(y2, x2));
+ }
+
+ public static NaviLatLng getPointForDis(NaviLatLng sPt, NaviLatLng ePt, double dis) {
+ double lSegLength = calculateDistance(sPt, ePt);
+ NaviLatLng pt = new NaviLatLng();
+ double preResult = dis / lSegLength;
+ pt.setLatitude(((ePt.getLatitude() - sPt.getLatitude()) * preResult + sPt.getLatitude()));
+ pt.setLongitude(((ePt.getLongitude() - sPt.getLongitude()) * preResult + sPt.getLongitude()));
+ return pt;
+ }
+
+ /**
+ * 根据经纬度计算需要偏转的角度
+ *
+ * @param startPoi
+ * @param secondPoi
+ * @return
+ */
+ public static float getRotate(NaviLatLng startPoi, NaviLatLng secondPoi) {
+ float rotate = 0;
+ try {
+ IPoint point1 = new IPoint();
+ IPoint point2 = new IPoint();
+ MapProjection.lonlat2Geo(startPoi.getLongitude(), startPoi.getLatitude(), point1);
+ MapProjection.lonlat2Geo(secondPoi.getLongitude(), secondPoi.getLatitude(), point2);
+ double x1 = point1.x;
+ double x2 = point2.x;
+ double y1 = point1.y;
+ double y2 = point2.y;
+ rotate = (float) (Math.atan2(y2 - y1, x2 - x1) / Math.PI * 180);
+ rotate = rotate + 90;
+ return rotate;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return rotate;
+ }
+
+ public static final int MAXZOOMLEVEL = 20;
+ public static final int PIXELSPERTILE = 256;
+ public static final double MINLATITUDE = -85.0511287798;
+ public static final double MAXLATITUDE = 85.0511287798;
+ public static final double MINLONGITUDE = -180;
+ public static final double MAXLONGITUDE = 180;
+ public static final int EARTHRADIUSINMETERS = 6378137;
+ public static final int TILESPLITLEVEL = 0;
+
+ public static final double EarthCircumferenceInMeters = 2 * Math.PI * EARTHRADIUSINMETERS;
+
+ public static double clip(double n, double minValue, double maxValue) {
+ return Math.min(Math.max(n, minValue), maxValue);
+ }
+
+ public static IPoint lonlat2Geo(double latitude, double longitude, int levelOfDetail) {
+ IPoint rPnt = new IPoint();
+ latitude = clip(latitude, MINLATITUDE, MAXLATITUDE) * Math.PI / 180;
+ longitude = clip(longitude, MINLONGITUDE, MAXLONGITUDE) * Math.PI / 180;
+ double sinLatitude = Math.sin(latitude);
+ double xMeters = EARTHRADIUSINMETERS * longitude;
+ double lLog = Math.log((1 + sinLatitude) / (1 - sinLatitude));
+ double yMeters = EARTHRADIUSINMETERS / 2 * lLog;
+ long numPixels = (long) PIXELSPERTILE << levelOfDetail;
+ double metersPerPixel = EarthCircumferenceInMeters / numPixels;
+ rPnt.x = (int) clip((EarthCircumferenceInMeters / 2 + xMeters)
+ / metersPerPixel + 0.5, 0, numPixels - 1);
+ long tmp = (long) (EarthCircumferenceInMeters / 2 - yMeters);
+ rPnt.y = (int) clip((double) tmp / metersPerPixel + 0.5, 0, numPixels - 1);
+ return rPnt;
+ }
+
+ public static String formatKM(int d) {
+ if (d == 0) {
+ return "0米";
+ } else if (d < 100) {
+ return d + "米";
+ } else if ((100 <= d) && (d < 1000)) {
+ return d + "米";
+ } else if ((1000 <= d) && (d < 10000)) {
+ return (d / 10) * 10 / 1000.0D + "公里";
+ } else if ((10000 <= d) && (d < 100000)) {
+ return (d / 100) * 100 / 1000.0D + "公里";
+ }
+ return (d / 1000) + "公里";
+ }
+}
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/CarDetailActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/CarDetailActivity.kt
index b5d8eb1..96513e8 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/CarDetailActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/CarDetailActivity.kt
@@ -1,13 +1,11 @@
package com.xw.yunwei.ui.work.car.detail
-import android.util.Log
import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter
-import com.blankj.utilcode.util.GsonUtils
import com.google.android.material.tabs.TabLayoutMediator
-import com.xw.common.base.BaseActivity
import com.xw.common.base.fastObserve
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.MyApp
import com.xw.yunwei.MyApp.Companion.findPermissionByName
import com.xw.yunwei.databinding.ActivityCarDetailBinding
@@ -18,10 +16,10 @@
/**
* 车辆详情
*/
-class CarDetailActivity : BaseActivity<ActivityCarDetailBinding, CarDetailVM>() {
+class CarDetailActivity : BaseBusinessActivity<ActivityCarDetailBinding, CarDetailVM>() {
override fun getBindingVariable() = BR.viewModel
- private val tabTitles = listOf("车辆调度", "车辆运维", "车辆管理")
+ private val tabTitles = listOf("运营管理", "车辆运维", "车辆管理")
override fun init() {
super.init()
@@ -31,6 +29,7 @@
TabLayoutMediator(binding.tabs, binding.pager) { tab, positon ->
tab.text = tabTitles[positon]
}.attach()
+ binding.pager.isUserInputEnabled = false
}
override fun setListener() {
@@ -59,6 +58,7 @@
viewModel.qingjiePermissions.value = findPermissionByName("车辆清洁")?.visible == "0"
viewModel.recordPermissions.value = findPermissionByName("运维记录")?.visible == "0"
viewModel.policyPermissions.value = findPermissionByName("查看保单")?.visible == "0"
+ viewModel.checkCould()
}
}
@@ -71,7 +71,7 @@
override fun getItemCount(): Int = tabTitles.size
override fun createFragment(position: Int): Fragment {
return when (tabTitles[position]) {
- "车辆调度" -> DispatchFragment()
+ "运营管理" -> DispatchFragment()
"车辆运维" -> OperationsFragment()
"车辆管理" -> ManagementFragment()
else -> error("Wrong position $position")
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/CarDetailVM.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/CarDetailVM.kt
index d6f0ba1..34d0129 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/CarDetailVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/CarDetailVM.kt
@@ -4,14 +4,14 @@
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.map
import com.xw.common.base.BasePagingViewModel
-import com.xw.common.base.BaseViewModel
+import com.xw.common.utils.LogUtils
import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.MyApp
+import com.xw.yunwei.model.AcceptCarPointInfo
import com.xw.yunwei.model.CarModel
import com.xw.yunwei.net.UserRepository
import com.xw.yunwei.net.WorkRepository
import org.koin.core.component.inject
-import kotlin.getValue
class CarDetailVM(application: Application) : BasePagingViewModel(application) {
val workRepository: WorkRepository by inject()
@@ -21,14 +21,18 @@
val carInfo: MutableLiveData<CarModel> = MutableLiveData()
val nextTime = carInfo.map {
- it.nextMaintenanceTime?:"--"
+ it.nextMaintenanceTime ?: "--"
}
- val unlockDoorPermissions = MutableLiveData(false) // 车门解锁权限
- val unlockBoxPermissions = MutableLiveData(false) // 车门解锁权限
+ val isArrivingAcceptPoint = MutableLiveData(false) // 是否正在前往收车点
+ val arrivingAcceptPointAddress = MutableLiveData("") // 正在前往收车点信息
val departurePermissions = MutableLiveData(false) // 发车/收车权限
val takeOrdersPermissions = MutableLiveData(false) // 接单/测试权限
-
+ val couldTakeOrderOrTest = MutableLiveData(false) // 是否能接单/测试
+ val hadOpenTakeOrder = MutableLiveData(false) // 是否打开接单
+ val couldOperationDevice = MutableLiveData(false)//是否能操作设备
+ val unlockDoorPermissions = MutableLiveData(false) // 车门解锁权限
+ val unlockBoxPermissions = MutableLiveData(false) // 车门解锁权限
val zhengbeiPermissions = MutableLiveData(false) // 整备权限
val chongdianPermissions = MutableLiveData(false) // 充电权限
val jiancePermissions = MutableLiveData(false) // 检测权限
@@ -37,16 +41,50 @@
val recordPermissions = MutableLiveData(false) // 运维记录权限
val policyPermissions = MutableLiveData(false) // 保单权限
+ //是否已经循环检测车门状态
+ var hadCheckDoorStatus = MutableLiveData(false)
+
+ //是否已经车门开启
+ var hadDoorOpened = MutableLiveData(false)
+
+ //是否已经循环检测后备箱状态
+ var hadCheckTrunkStatus = MutableLiveData(false)
+
+ //是否已经后备箱开启
+ var hadTrunkOpened = MutableLiveData(false)
+
fun queryInfo() {
refreshLiveData.refresh()
launchRequest(showLoading = false, error = { code, msg ->
ToastUtilCommon.showError(msg)
refreshLiveData.done()
}) {
- workRepository.queryCarInfo(carId)?.let {
- carInfo.postValue(it)
- refreshLiveData.done()
+ workRepository.queryCarInfo(carId)?.let { info ->
+ runOnMainThread {
+ carInfo.value = info
+ refreshLiveData.done()
+ checkCould()
+ }
+ checkTrunkStatus(info.id.toString()) {
+ hadTrunkOpened.postValue(it == 1)
+ }
}
+ }
+ }
+
+ //检查是否能够
+ fun checkCould() {
+ carInfo.value?.also {
+ this.isArrivingAcceptPoint.postValue(it.isArrivingPoint() && !it.isWorking())
+ this.arrivingAcceptPointAddress.postValue(it.pointName)
+ val couldTakeOrder = (takeOrdersPermissions.value ?: false) && it.isWorking()
+ this.couldTakeOrderOrTest.postValue(couldTakeOrder)
+ val hadOpenTakeOrder = it.hadOpenTakeOrder()
+ this.hadOpenTakeOrder.postValue(hadOpenTakeOrder)
+ val couldOperationDevice =
+ ((unlockDoorPermissions.value ?: false) || (unlockBoxPermissions.value
+ ?: false)) && !hadOpenTakeOrder && couldTakeOrder
+ this.couldOperationDevice.postValue(couldOperationDevice)
}
}
@@ -66,31 +104,119 @@
}
}
- fun vehicleDispatchDeparture(map: Map<String, Any?>, error: () -> Unit, block: () -> Unit) {
- launchRequest(tips = "正在传达指令", error = { code, msg ->
- runOnMainThread {
- ToastUtilCommon.showError(msg.ifEmpty { "操作失败" })
- error()
+ //获取所有收车点
+ fun getAllAcceptCarPoints(error: () -> Unit, block: (List<AcceptCarPointInfo>) -> Unit) {
+ carInfo.value?.also { it ->
+ launchRequest(error = { code, msg ->
+ runOnMainThread {
+ ToastUtilCommon.showError(msg.ifEmpty { "操作失败" })
+ error()
+ }
+ }) {
+ workRepository.getAllAcceptCarPoints(it.id.toString())?.also {
+ runOnMainThread { block.invoke(it) }
+ }
}
- }) {
- workRepository.vehicleDispatchDeparture(map)
- runOnMainThread {
- ToastUtilCommon.showSuc("操作成功")
- block()
+ }
+ }
+
+ //收发车
+ fun vehicleDispatchDeparture(
+ setStatus: Int,
+ xpPointId: String? = null,
+ error: () -> Unit,
+ block: () -> Unit
+ ) {
+ carInfo.value?.let {
+ val map = mutableMapOf<String, Any?>()
+ map["vehicleId"] = it.id // 车辆ID
+ map["xpPointId"] = xpPointId // 车辆ID
+ map["departureStatus"] = setStatus // 发车状态 1=发车 3=收车
+ launchRequest(tips = "正在传达指令", error = { code, msg ->
+ runOnMainThread {
+ ToastUtilCommon.showError(msg.ifEmpty { "操作失败" })
+ error()
+ }
+ }) {
+ workRepository.vehicleDispatchDeparture(map)
+ runOnMainThread {
+ ToastUtilCommon.showSuc("操作成功")
+ carInfo.value?.operatingStatus = setStatus
+ block()
+ }
}
}
}
fun unlockByType(type: Int) {
- launchRequest(tips = "正在传达指令", error = { code, msg ->
- ToastUtilCommon.showError("操作失败,请重试")
+ if (type == 1 && hadDoorOpened.value == true) {
+ return
+ }
+ if (type == 2 && hadTrunkOpened.value == true) {
+ return
+ }
+ if (type == 1 && hadCheckDoorStatus.value == true) {
+ ToastUtilCommon.showError("正在检测后备箱状态中...")
+ return
+ }
+ if (type == 2 && hadCheckTrunkStatus.value == true) {
+ ToastUtilCommon.showError("正在检测后备箱状态中...")
+ return
+ }
+ when (type) {
+ 1 -> {
+ hadCheckDoorStatus.value = true
+ }
+
+ 2 -> {
+ hadCheckTrunkStatus.value = true
+ }
+ }
+ launchRequest(tips = "正在传达指令", showLoading = false, error = { code, msg ->
+ runOnMainThread { ToastUtilCommon.showError(msg.ifEmpty { "操作失败,请重试" }) }
+ when (type) {
+ 1 -> {
+ hadCheckDoorStatus.postValue(false)
+ }
+
+ 2 -> {
+ hadCheckTrunkStatus.postValue(false)
+ }
+ }
}) {
val map = mutableMapOf<String, Any?>()
+ val isOpen =
+ if (type == 1) carInfo.value?.hadOpenedDoor() != true else carInfo.value?.hadOpenedTrunk() != true
map["vehicleId"] = carInfo.value?.id // 车辆ID
- map["unlockType"] = type // 解锁类型 1车门 2后备箱
+ map["latitude"] = com.xw.common.Constants.latitude
+ map["longitude"] = com.xw.common.Constants.longitude
+ map["doorType"] = if (type == 1) "door" else "trunk" // 解锁类型 1车门 2后备箱
+ map["operationType"] = if (isOpen) "open" else "close" // 操作类型(open/close)
workRepository.unlockByType(map)
- val tips = if (type == 1) "车门已解锁" else "后备箱已解锁"
- ToastUtilCommon.showSuc(tips)
+ when (type) {
+ 1 -> {
+ runOnMainThread { ToastUtilCommon.showSuc("车门解锁成功") }
+ hadCheckDoorStatus.postValue(false)
+ hadDoorOpened.postValue(true)
+ }
+
+ 2 -> {
+ runOnMainThread { ToastUtilCommon.showSuc("后备箱解锁成功") }
+ hadCheckTrunkStatus.postValue(false)
+ hadTrunkOpened.postValue(true)
+ }
+ }
+ }
+ }
+
+ //检测后备箱状态
+ private fun checkTrunkStatus(vehicleId: String, block: (status: Int) -> Unit) {
+ launchRequest(showLoading = false, error = { code, msg ->
+ LogUtils.e(TAG, "launchRequest: code = $code msg = $msg")
+ }) {
+ workRepository.checkTrunkLockStatus(vehicleId)?.also {
+ block.invoke(it)
+ }
}
}
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/StandardDescriptionActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/StandardDescriptionActivity.kt
index 45cedb6..4087527 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/StandardDescriptionActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/StandardDescriptionActivity.kt
@@ -3,9 +3,11 @@
import android.annotation.SuppressLint
import android.webkit.WebSettings
import android.webkit.WebView
-import com.xw.common.base.BaseActivity
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.databinding.ActivityStandardDescriptionBinding
+import com.xw.yunwei.extension.safeLoadDataWithBaseURL
+import com.xw.yunwei.extension.setSafeSetting
/**
* 标准说明
@@ -16,18 +18,19 @@
* 8=运维APP-小鹏Robotaxi自动驾驶出行运维隐私政策 9=运维APP-第三方共享信息清单 10=运维APP-个人信息收集清单 11=运维APP-权限调用
*/
class StandardDescriptionActivity :
- BaseActivity<ActivityStandardDescriptionBinding, StandardDescriptionVM>() {
+ BaseBusinessActivity<ActivityStandardDescriptionBinding, StandardDescriptionVM>() {
override fun getBindingVariable() = BR.viewModel
override fun init() {
super.init()
+ val title = intent.getStringExtra("title")
val type = intent.getIntExtra("type", 1)
val webType = intent.getIntExtra("webType", 0)
if (webType == 0) {
viewModel.getDesc(type)
} else {
- binding.title.text = "协议内容"
- viewModel.getProtocol(type)
+ binding.title.text = title ?: "协议内容"
+ viewModel.getLoginProtocol(type)
}
initWeb(binding.web)
binding.back.setOnClickListener { onBackPressedHandel() }
@@ -48,7 +51,6 @@
//如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
webSettings.javaScriptEnabled = true //允许js调用
- webSettings.allowFileAccess = true //在File域下,能够执行任意的JavaScript代码,同源策略跨域访问能够对私有目录文件进行访问等
webSettings.allowContentAccess = true //是否允许在WebView中访问内容URL(Content Url),默认允许
//缩放操作
@@ -58,17 +60,18 @@
//其他细节操作
webSettings.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK //关闭webview中缓存
- webSettings.allowFileAccess = true //设置可以访问文件
webSettings.javaScriptCanOpenWindowsAutomatically = true //支持通过JS打开新窗口
webSettings.loadsImagesAutomatically = true //支持自动加载图片
webSettings.defaultTextEncodingName = "utf-8" //设置编码格式
+
+ webView.setSafeSetting()//安全设置
}
@SuppressLint("SetJavaScriptEnabled")
private fun setContent(webView: WebView, content: String?) {
content?.let {
// 加载并显示HTML代码
- webView.loadDataWithBaseURL(
+ webView.safeLoadDataWithBaseURL(
null,
content,
"text/html",
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/StandardDescriptionVM.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/StandardDescriptionVM.kt
index 7e4b698..46d616b 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/StandardDescriptionVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/StandardDescriptionVM.kt
@@ -30,4 +30,11 @@
}
}
+ fun getLoginProtocol(type: Int) {
+ launchRequest(showLoading = false) {
+ userRepository.getLoginProtocol(type)?.let {
+ data.postValue(it.content?:"")
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/adapter/AcceptCarPointAdapter.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/adapter/AcceptCarPointAdapter.kt
new file mode 100644
index 0000000..0876aeb
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/adapter/AcceptCarPointAdapter.kt
@@ -0,0 +1,40 @@
+package com.xw.yunwei.ui.work.car.detail.adapter
+
+import android.widget.ImageView
+import com.chad.library.adapter.base.BaseQuickAdapter
+import com.chad.library.adapter.base.viewholder.BaseViewHolder
+import com.xw.common.utils.GlideEngine
+import com.xw.yunwei.R
+import com.xw.yunwei.model.AcceptCarPointInfo
+
+//收车点适配器
+class AcceptCarPointAdapter(var selectIndex: Int = 0) :
+ BaseQuickAdapter<AcceptCarPointInfo, BaseViewHolder>(R.layout.item_accept_car_point) {
+ val defaultSelectIndex = selectIndex
+ override fun convert(holder: BaseViewHolder, item: AcceptCarPointInfo) {
+ holder
+ .setImageResource(
+ R.id.iv_selected,
+ if (holder.bindingAdapterPosition == selectIndex) R.mipmap.icon_circle_ring_blue else R.mipmap.icon_circle_gray2
+ )
+ .setText(R.id.tv_title, item.pointName)
+ .setText(R.id.tv_detail, item.pointAddress)
+ .setGone(R.id.tv_label, defaultSelectIndex != holder.bindingAdapterPosition)
+ .setGone(R.id.v_line, holder.bindingAdapterPosition == data.size - 1)
+ val ivPicture = holder.getView<ImageView>(R.id.iv_picture)
+ GlideEngine.createGlideEngine()
+ .load(
+ ivPicture,
+ item.getShowPictureUrl(),
+ R.drawable.img_site_bg,
+ R.drawable.img_site_bg,
+ 4f
+ )
+ holder.itemView.setOnClickListener {
+ val lastIndex = selectIndex
+ selectIndex = holder.bindingAdapterPosition
+ notifyItemChanged(lastIndex)
+ notifyItemChanged(selectIndex)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/dispatch/DispatchFragment.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/dispatch/DispatchFragment.kt
index 7b48f99..a33cffb 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/dispatch/DispatchFragment.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/dispatch/DispatchFragment.kt
@@ -1,22 +1,28 @@
package com.xw.yunwei.ui.work.car.detail.dispatch
+import android.animation.ObjectAnimator
+import android.animation.ValueAnimator
import android.annotation.SuppressLint
+import android.view.View
+import android.view.animation.LinearInterpolator
+import androidx.core.view.isVisible
import com.xw.common.base.BaseFragmentNoVM
import com.xw.common.custom.SlideButtonView
import com.xw.common.custom.SlideButtonView.Companion.DIRECTION_LEFT
import com.xw.common.custom.SlideButtonView.Companion.DIRECTION_RIGHT
-import com.xw.common.utils.BindUtils.getUrl
import com.xw.common.utils.BindUtils.getResColor
-import com.xw.common.utils.ToastUtilCommon
import com.xw.common.viewAdapter.ImageDefault
import com.xw.common.viewAdapter.ViewAdapter
import com.xw.yunwei.R
import com.xw.yunwei.databinding.FragmentCarDispatchBinding
+import com.xw.yunwei.extension.colorIdToColorValue
import com.xw.yunwei.model.CarModel
+import com.xw.yunwei.ui.dialog.ConfirmAcceptCarPointDialog
+import com.xw.yunwei.ui.dialog.SelectConfirmAcceptCarPointDialog
import com.xw.yunwei.ui.work.car.detail.CarDetailActivity
/**
- * 车辆调度
+ * 运营管理
*/
class DispatchFragment : BaseFragmentNoVM<FragmentCarDispatchBinding>() {
@@ -32,98 +38,169 @@
super.setObservable()
viewModel.carInfo.observe(this) {
initBasicInfo(it)
- initSlideView(it)
+ if (it.isWorking()) {
+ resetSlideView(
+ binding.slideView1,
+ !it.hadOpenTakeOrder(),
+ DIRECTION_LEFT,
+ if (!it.hadOpenTakeOrder()) "左滑收车" else "车辆接单中,暂无法收车"
+ )
+ } else {
+ resetSlideView(binding.slideView1, true, DIRECTION_RIGHT, "右滑发车")
+ }
}
+
+ viewModel.hadCheckDoorStatus.observe(this) {
+ binding.ivDoorStatus.isVisible = !it
+ binding.ivDoorStatusLoading.isVisible = it
+ if (it) {
+ // 创建旋转动画
+ val rotateAnimator = getRotationAnimator(binding.ivDoorStatusLoading)
+ rotateAnimator.start()
+ binding.ivDoorStatusLoading.tag = rotateAnimator
+ } else {
+ (binding.ivDoorStatusLoading.tag as? ObjectAnimator)?.cancel()
+ }
+ }
+ viewModel.hadDoorOpened.observe(this) {
+ binding.unlockDoor.setBackgroundResource(if (it) com.xw.common.R.drawable.shape_blue1_bg_4 else R.drawable.shape_gray2_bg_4)
+ binding.ivDoorStatus.setImageResource(if (it) com.xw.common.R.drawable.svg_car_cmjs else R.drawable.svg_net_lock_gray)
+ binding.tvDoorLock.setTextColor(
+ (if (it) com.xw.common.R.color.blue_5 else com.xw.common.R.color.gray_7).colorIdToColorValue(
+ requireActivity()
+ )
+ )
+ }
+ viewModel.hadCheckTrunkStatus.observe(this) {
+ binding.ivTrunkStatus.isVisible = !it
+ binding.ivTrunkStatusLoading.isVisible = it
+ if (it) {
+ // 创建旋转动画
+ val rotateAnimator = getRotationAnimator(binding.ivTrunkStatusLoading)
+ rotateAnimator.start()
+ binding.ivTrunkStatusLoading.tag = rotateAnimator
+ } else {
+ (binding.ivTrunkStatusLoading.tag as? ObjectAnimator)?.cancel()
+ }
+ }
+ viewModel.hadTrunkOpened.observe(this) {
+ binding.unlockBox.setBackgroundResource(if (it) com.xw.common.R.drawable.shape_blue1_bg_4 else R.drawable.shape_gray2_bg_4)
+ binding.ivTrunkStatus.setImageResource(if (it) com.xw.common.R.drawable.svg_car_hbxjs else R.drawable.svg_car_trunk_closed)
+ binding.tvTrunkLock.setTextColor(
+ (if (it) com.xw.common.R.color.blue_5 else com.xw.common.R.color.gray_7).colorIdToColorValue(
+ requireActivity()
+ )
+ )
+ }
+ }
+
+ //获取无限旋转动画
+ private fun getRotationAnimator(view: View): ObjectAnimator {
+ return ObjectAnimator.ofFloat(view, "rotation", 0f, 360f)
+ .apply {
+ duration = 2000 // 旋转一圈用时 2 秒
+ repeatCount = ValueAnimator.INFINITE // 无限重复
+ interpolator = LinearInterpolator() // 匀速旋转
+ }
}
override fun setListener() {
super.setListener()
with(binding.slideView1) {
setOnSlideCompleteListener {
- val carInfo = viewModel.carInfo.value
- carInfo?.let { carInfo ->
- val setStatus = if (carInfo.operatingStatus == 1) 3 else 1
- val map = mutableMapOf<String, Any?>()
- map["vehicleId"] = carInfo.id // 车辆ID
- map["departureStatus"] = setStatus // 发车状态 1=发车 3=收车
- viewModel.vehicleDispatchDeparture(map, {
- binding.slideView1.animateReset()
- }) {
- carInfo.operatingStatus = setStatus
- if (getSlideDirection() == DIRECTION_RIGHT) {
- resetSlideView(this, DIRECTION_LEFT, "左滑收车")
- } else if (getSlideDirection() == DIRECTION_LEFT) {
- resetSlideView(this, DIRECTION_RIGHT, "右滑发车")
+ viewModel.carInfo.value?.also { carModel ->
+ val setStatus = if (carModel.isWorking()) 3 else 1
+ if (setStatus == 3) {
+ viewModel.getAllAcceptCarPoints(error = {
+ binding.slideView1.animateReset()
+ }) {
+ ConfirmAcceptCarPointDialog.show(
+ context = requireActivity(),
+ points = it,
+ cancelBlock = {
+ binding.slideView1.animateReset()
+ },
+ confirmBlock = { point, dialog ->
+ dialog.dismiss()
+ viewModel.vehicleDispatchDeparture(
+ setStatus = setStatus,
+ xpPointId = point.id,
+ error = {
+ SelectConfirmAcceptCarPointDialog.hadOperation = false
+ }) {
+ if (getSlideDirection() == DIRECTION_RIGHT) {
+ resetSlideView(
+ this,
+ !carModel.hadOpenTakeOrder(),
+ DIRECTION_LEFT,
+ if (!carModel.hadOpenTakeOrder()) "左滑收车" else "车辆接单中,暂无法收车"
+ )
+ } else if (getSlideDirection() == DIRECTION_LEFT) {
+ resetSlideView(this, true, DIRECTION_RIGHT, "右滑发车")
+ }
+ viewModel.queryInfo()
+ }
+ })
}
+ return@also
}
- }
- }
- }
- with(binding.slideView2) {
- setOnSlideCompleteListener {
- val carInfo = viewModel.carInfo.value
- carInfo?.let { carInfo ->
- val setStatus = if (carInfo.acceptOrTestStatus == 1) 2 else 1
- val map = mutableMapOf<String, Any?>()
- map["vehicleId"] = carInfo.id // 车辆ID
- map["acceptOrTest"] = carInfo.acceptOrTest // 当前模式 1接单 2测试
- map["acceptOrTestStatus"] = setStatus // 模式状态 1开始接单/开始测试 2停止接单/停止测试
- viewModel.vehicleDispatchAccept(map, {
- binding.slideView2.animateReset()
- }) {
- carInfo.acceptOrTestStatus = setStatus
+ viewModel.vehicleDispatchDeparture(
+ setStatus = setStatus,
+ error = {
+ binding.slideView1.animateReset()
+ }) {
if (getSlideDirection() == DIRECTION_RIGHT) {
- val text = if (carInfo.acceptOrTest == 1) "左滑关闭接单" else "左滑关闭测试"
- resetSlideView(this, DIRECTION_LEFT, text)
+ resetSlideView(
+ this,
+ !carModel.hadOpenTakeOrder(),
+ DIRECTION_LEFT,
+ if (!carModel.hadOpenTakeOrder()) "左滑收车" else "车辆接单中,暂无法收车"
+ )
} else if (getSlideDirection() == DIRECTION_LEFT) {
- val text = if (carInfo.acceptOrTest == 1) "右滑开始接单" else "右滑开始测试"
- resetSlideView(this, DIRECTION_RIGHT, text)
+ resetSlideView(this, true, DIRECTION_RIGHT, "右滑发车")
}
+ viewModel.queryInfo()
}
}
}
}
- binding.takeOrders.setOnClickListener {
- viewModel.carInfo.value?.let {
- if (it.acceptOrTest != 1) {
- val map = mutableMapOf<String, Any?>()
- map["vehicleId"] = it.id // 车辆ID
- map["acceptOrTest"] = 1 // 当前模式 1接单 2测试
- map["acceptOrTestStatus"] = 1 // 模式状态 1开始接单/开始测试 2停止接单/停止测试
- viewModel.vehicleDispatchAccept(map, {
- binding.slideView2.animateReset()
- }) {
- it.acceptOrTest = 1
- it.acceptOrTestStatus = 1
- initSlideView(it)
+ binding.cbTakeOrder.setOnCheckedChangeListener { button, bool ->
+ viewModel.hadOpenTakeOrder.value?.takeIf {
+ it != bool
+ }?.also { hadOpenTakeOrder ->
+ val setStatus = if (hadOpenTakeOrder) 2 else 1
+ val map = mutableMapOf<String, Any?>()
+ map["vehicleId"] = viewModel.carInfo.value?.id // 车辆ID
+ map["acceptOrTest"] = 1 // 当前模式 1接单 2测试
+ map["acceptOrTestStatus"] = setStatus // 模式状态 1开始接单/开始测试 2停止接单/停止测试
+ viewModel.vehicleDispatchAccept(map, {
+ viewModel.queryInfo()
+ }) {
+ viewModel.runOnMainThread {
+ viewModel.carInfo.value?.acceptOrTestStatus = setStatus
+ viewModel.checkCould()
+ resetSlideView(
+ binding.slideView1,
+ viewModel.carInfo.value?.hadOpenTakeOrder() != true,
+ DIRECTION_LEFT,
+ if (viewModel.carInfo.value?.hadOpenTakeOrder() != true) "左滑收车" else "车辆接单中,暂无法收车"
+ )
}
}
}
}
- binding.test.setOnClickListener {
- viewModel.carInfo.value?.let {
- if (it.acceptOrTest != 2) {
- val map = mutableMapOf<String, Any?>()
- map["vehicleId"] = it.id // 车辆ID
- map["acceptOrTest"] = 2 // 当前模式 1接单 2测试
- map["acceptOrTestStatus"] = 1 // 模式状态 1开始接单/开始测试 2停止接单/停止测试
- viewModel.vehicleDispatchAccept(map, {
- binding.slideView2.animateReset()
- }) {
- it.acceptOrTest = 2
- it.acceptOrTestStatus = 1
- initSlideView(it)
- }
- }
- }
- }
-
binding.unlockDoor.setOnClickListener { viewModel.unlockByType(1) }
binding.unlockBox.setOnClickListener { viewModel.unlockByType(2) }
}
- private fun resetSlideView(slideView: SlideButtonView, direction: Int, text: String) {
+ private fun resetSlideView(
+ slideView: SlideButtonView,
+ enable: Boolean,
+ direction: Int,
+ text: String
+ ) {
+ slideView.enable = enable
if (direction == DIRECTION_RIGHT) { // 右滑模式
slideView.setThumbDrawable(com.xw.common.R.mipmap.ic_slide_r)
slideView.setSlideTextColor(getResColor(com.xw.common.R.color.blue_5))
@@ -131,9 +208,9 @@
slideView.setSlideText(text)
slideView.setSlideDirection(direction)
} else if (direction == DIRECTION_LEFT) { // 左滑模式
- slideView.setThumbDrawable(com.xw.common.R.mipmap.ic_slide_l)
+ slideView.setThumbDrawable(if (enable) com.xw.common.R.mipmap.ic_slide_l else com.xw.common.R.mipmap.ic_slide_gray_r)
slideView.setSlideTextColor(getResColor(com.xw.common.R.color.white))
- slideView.setSlideBackgroundColor(getResColor(com.xw.common.R.color.orange_5))
+ slideView.setSlideBackgroundColor(getResColor(if (enable) com.xw.common.R.color.orange_5 else com.xw.common.R.color.gray_4))
slideView.setSlideText(text)
slideView.setSlideDirection(direction)
}
@@ -148,38 +225,10 @@
)
)
binding.batteryView.setLevel(it.currentElectricity ?: 0)
- var url = ""
- try {
- url = it.vehiclePictures?.getUrl() ?: ""
- } catch (e: Exception) {
- }
- ViewAdapter.loadImage(binding.icon, ImageDefault(url, R.mipmap.img_work_car1))
- }
- private fun initSlideView(it: CarModel) {
- if (it.acceptOrTest == 1) {
- binding.takeOrders.setBackgroundResource(R.drawable.shape_white_bg_4)
- binding.test.setBackgroundResource(com.xw.common.R.color.color_transparent)
- if (it.acceptOrTestStatus == 1) {
- resetSlideView(binding.slideView2, DIRECTION_RIGHT, "右滑开始接单")
- } else {
- resetSlideView(binding.slideView2, DIRECTION_LEFT, "左滑关闭接单")
- }
-
- } else if (it.acceptOrTest == 2) {
- binding.test.setBackgroundResource(R.drawable.shape_white_bg_4)
- binding.takeOrders.setBackgroundResource(com.xw.common.R.color.color_transparent)
- if (it.acceptOrTestStatus == 1) {
- resetSlideView(binding.slideView2, DIRECTION_RIGHT, "右滑开始测试")
- } else {
- resetSlideView(binding.slideView2, DIRECTION_LEFT, "左滑关闭测试")
- }
- }
-
- if (it.operatingStatus == 1) {
- resetSlideView(binding.slideView1, DIRECTION_LEFT, "左滑收车")
- } else {
- resetSlideView(binding.slideView1, DIRECTION_RIGHT, "右滑发车")
- }
+ ViewAdapter.loadImage(
+ binding.icon,
+ ImageDefault(it.getShowVehiclePicture(), R.mipmap.img_work_car1)
+ )
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/management/ManagementFragment.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/management/ManagementFragment.kt
index 6130c05..8eebd93 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/management/ManagementFragment.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/management/ManagementFragment.kt
@@ -1,7 +1,10 @@
package com.xw.yunwei.ui.work.car.detail.management
import android.annotation.SuppressLint
+import android.content.Intent
+import androidx.core.net.toUri
import androidx.core.os.bundleOf
+import com.xw.common.CommonDialog
import com.xw.common.base.BaseFragmentNoVM
import com.xw.common.utils.BindUtils.getUrl
import com.xw.common.utils.BindUtils.getResColor
@@ -41,6 +44,19 @@
bundleOf("carId" to (viewModel.carInfo.value?.id ?: 0L))
)
}
+ binding.tvPhone.setOnClickListener {
+ viewModel.carInfo.value?.insurancePhone?.also {
+ CommonDialog.showTipsDialog(requireContext(), "即将拨打电话:$it", rightBlock = {
+ val intent = Intent(Intent.ACTION_DIAL).apply {
+ data = "tel:$it".toUri()
+ }
+ if (intent.resolveActivity(requireActivity().packageManager) != null) {
+ startActivity(intent)
+ }
+ true
+ })
+ }
+ }
}
@SuppressLint("SetTextI18n")
@@ -52,12 +68,11 @@
)
)
binding.batteryView.setLevel(it.currentElectricity ?: 0)
- var url = ""
- try {
- url = it.vehiclePictures?.getUrl() ?: ""
- } catch (e: Exception) {
- }
- ViewAdapter.loadImage(binding.icon, ImageDefault(url, R.mipmap.img_work_car1))
+
+ ViewAdapter.loadImage(
+ binding.icon,
+ ImageDefault(it.getShowVehiclePicture(), R.mipmap.img_work_car1)
+ )
val setStatus: (Int, Int) -> Unit = { text, bg ->
binding.status.setTextColor(text)
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/management/report/CarReportActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/management/report/CarReportActivity.kt
index 5a81c36..3a88d3a 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/management/report/CarReportActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/management/report/CarReportActivity.kt
@@ -1,19 +1,22 @@
package com.xw.yunwei.ui.work.car.detail.management.report
+import android.view.Gravity
+import android.view.View
+import android.widget.TextView
+import com.xw.common.CommonDialog
import com.xw.common.PdfViewDialog
-import com.xw.common.base.BaseActivity
import com.xw.common.utils.BindUtils.getResColor
-import com.xw.common.utils.BindUtils.getUrl
import com.xw.common.utils.BindUtils.getUrls
-import com.xw.common.utils.ToastUtilCommon
+import com.xw.common.utils.BindUtils.getValueList
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.R
import com.xw.yunwei.databinding.ActivityCarReportBinding
/**
* 查看保单
*/
-class CarReportActivity : BaseActivity<ActivityCarReportBinding, CarReportVM>() {
+class CarReportActivity : BaseBusinessActivity<ActivityCarReportBinding, CarReportVM>() {
override fun getBindingVariable() = BR.viewModel
override fun init() {
@@ -24,7 +27,7 @@
override fun setObservable() {
super.setObservable()
- viewModel.carReportModel.observe(this) {
+ viewModel.carReportModel.observe(this) { it ->
when (it.status) {
// 保单申请状态 0 = 待申请 1 = 待审核 2 = 已通过 3 = 已驳回
0 -> {
@@ -59,18 +62,38 @@
binding.img.setImageResource(R.mipmap.img_car_report1)
}
}
+ binding.llPdf.removeAllViews()
+ it.xpPolicyApplicationVO?.policyInformation?.also { it ->
+ val urls = it.getUrls()
+ val names = it.getValueList("name")
+ urls.forEachIndexed { index, url ->
+ val view = View.inflate(this, R.layout.item_pdf_entrance, null).apply {
+ findViewById<TextView>(R.id.tv_name).apply {
+ text = names[index]
+ }
+ setOnClickListener {
+ PdfViewDialog().show(
+ supportFragmentManager,
+ "PDF_VIEW",
+ url = url
+ )
+ }
+ }
+ binding.llPdf.addView(view)
+ }
+ }
}
}
override fun setListener() {
super.setListener()
- binding.apply.setOnClickListener { viewModel.apply() }
- binding.reapply.setOnClickListener { viewModel.apply() }
+ binding.apply.setOnClickListener { apply() }
+ binding.reapply.setOnClickListener { apply() }
binding.viewPdf.setOnClickListener {
viewModel.carReportModel.value?.let {
it.xpPolicyApplicationVO?.policyInformation?.getUrls()?.getOrNull(0)?.let {
// if (it.endsWith("pdf")) {
- PdfViewDialog().show(supportFragmentManager, "PDF_VIEW", url = it)
+ PdfViewDialog().show(supportFragmentManager, "PDF_VIEW", url = it)
// } else {
// ToastUtilCommon.showWarn("文件格式异常,无法查看,当前查看pdf链接为 $it")
// }
@@ -78,4 +101,19 @@
}
}
}
+
+ //申请查看
+ private fun apply() {
+ CommonDialog.showNoticeDialog(
+ context = this,
+ cancelable = true,
+ cancelOnTouchOutside = true,
+ title = "确认申请查看保单?",
+ content = "提交后需后台人工审核,审核通过放能查看保单。",
+ contentTextGravity = Gravity.START,
+ rightOperationBlock = {
+ viewModel.apply()
+ true
+ })
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/OperationsFragment.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/OperationsFragment.kt
index 5a16b94..12a5087 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/OperationsFragment.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/OperationsFragment.kt
@@ -42,7 +42,12 @@
binding.viewDetail.setOnClickListener {
startActivity(
RepairRecordActivity::class.java,
- bundleOf("carId" to (viewModel.carInfo.value?.id ?: 0L))
+ bundleOf(
+ "carId" to (viewModel.carInfo.value?.id ?: 0L),
+ "plateNumber" to (viewModel.carInfo.value?.plateNumber ?: ""),
+ "mileageRange" to (viewModel.carInfo.value?.mileageRange ?: 0.0),
+ "vehicleColor" to (viewModel.carInfo.value?.vehicleColor ?: "")
+ )
)
}
binding.zhengbeiLayout.setOnClickListener {
@@ -86,11 +91,7 @@
)
)
binding.batteryView.setLevel(it.currentElectricity ?: 0)
- var url = ""
- try {
- url = it.vehiclePictures?.getUrl() ?: ""
- } catch (e: Exception) {
- }
- ViewAdapter.loadImage(binding.icon, ImageDefault(url, R.mipmap.img_work_car1))
+
+ ViewAdapter.loadImage(binding.icon, ImageDefault(it.getShowVehiclePicture(), R.mipmap.img_work_car1))
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/charge/ChargeCarActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/charge/ChargeCarActivity.kt
index d7f70c6..39be303 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/charge/ChargeCarActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/charge/ChargeCarActivity.kt
@@ -1,18 +1,14 @@
package com.xw.yunwei.ui.work.car.detail.operations.charge
import android.annotation.SuppressLint
-import android.content.res.ColorStateList
import android.net.Uri
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.GridLayoutManager
import com.blankj.utilcode.util.UriUtils
-import com.luck.picture.lib.basic.PictureSelector
import com.luck.picture.lib.config.PictureMimeType
-import com.luck.picture.lib.config.SelectMimeType
import com.luck.picture.lib.entity.LocalMedia
import com.luck.picture.lib.interfaces.OnResultCallbackListener
import com.xw.common.CommonDialog
-import com.xw.common.base.BaseActivity
import com.xw.common.base.FileSelectBean
import com.xw.common.base.ImageEventListener
import com.xw.common.base.ImageSelectAdapter
@@ -21,25 +17,25 @@
import com.xw.common.custom.SlideButtonView.Companion.DIRECTION_RIGHT
import com.xw.common.utils.BindUtils.getResColor
import com.xw.common.utils.BindUtils.getUrls
-import com.xw.common.utils.GlideEngine
-import com.xw.common.utils.PictureCompressEngine
+import com.xw.common.viewAdapter.ImageDefault
+import com.xw.common.viewAdapter.ViewAdapter
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.R
import com.xw.yunwei.databinding.ActivityCarChargeBinding
import com.xw.yunwei.model.CarModel
-import java.util.ArrayList
+import com.xw.yunwei.utils.PictureSelectorFactory
/**
* 车辆充电
*/
-class ChargeCarActivity : BaseActivity<ActivityCarChargeBinding, ChargeCarVM>() {
+class ChargeCarActivity : BaseBusinessActivity<ActivityCarChargeBinding, ChargeCarVM>() {
override fun getBindingVariable() = BR.viewModel
override fun init() {
super.init()
viewModel.carId = intent.getLongExtra("carId", 0L)
viewModel.taskId = intent.getLongExtra("taskId", -1L)
- viewModel.queryInfo()
viewModel.queryStatus()
initAdapter()
}
@@ -52,19 +48,21 @@
}
viewModel.chargeRecord.observe(this) {
initSlideView(it.status ?: 1)
- if(it.status == 2){
+ if (it.status == 2) {
it.xpChargingRecord?.startChargingPicture?.let {
val list = it.getUrls().map { FileSelectBean(url = it, type = "img") }
viewModel.adapterHis.setList(list)
}
- binding.batteryLifeHis.text = "${it.xpChargingRecord?.startRemainingBattery?:0}km"
+ binding.batteryLifeHis.text = "${it.xpChargingRecord?.startRemainingBattery ?: 0}km"
binding.batteryLifeHis.setTextColor(
getBatteryColorByBatteryLife(
it.xpChargingRecord?.startRemainingBattery ?: 0
)
)
- binding.batteryViewHis.setBatteryLife(it.xpChargingRecord?.startRemainingBattery ?: 0)
+ binding.batteryViewHis.setBatteryLife(
+ it.xpChargingRecord?.startRemainingBattery ?: 0
+ )
}
}
}
@@ -87,16 +85,20 @@
binding.slideView.setThumbDrawable(com.xw.common.R.mipmap.ic_slide_b)
binding.slideView.setSlideTextColor(getResColor(com.xw.common.R.color.blue_5))
binding.slideView.setSlideBackgroundColor(getResColor(com.xw.common.R.color.blue_1))
- binding.slideArrow.imageTintList = ContextCompat.getColorStateList(this, com.xw.common.R.color.blue_5)
+ binding.slideArrow.imageTintList =
+ ContextCompat.getColorStateList(this, com.xw.common.R.color.blue_5)
binding.slideView.setSlideText("右滑开始充电")
binding.slideView.setSlideDirection(DIRECTION_RIGHT)
+ binding.tv2.text ="充电前照片"
} else if (status == 2) { // 已开始充电
binding.slideView.setThumbDrawable(com.xw.common.R.mipmap.ic_slide_o)
binding.slideView.setSlideTextColor(getResColor(com.xw.common.R.color.orange_5))
binding.slideView.setSlideBackgroundColor(getResColor(com.xw.common.R.color.orange_1))
binding.slideView.setSlideText("右滑结束充电")
- binding.slideArrow.imageTintList = ContextCompat.getColorStateList(this, com.xw.common.R.color.orange_5)
+ binding.slideArrow.imageTintList =
+ ContextCompat.getColorStateList(this, com.xw.common.R.color.orange_5)
binding.slideView.setSlideDirection(DIRECTION_RIGHT)
+ binding.tv2.text ="充电后照片"
}
}
@@ -156,6 +158,11 @@
)
)
binding.batteryView.setLevel(it.currentElectricity ?: 0)
+
+ ViewAdapter.loadImage(
+ binding.ivCar,
+ ImageDefault(it.getShowVehiclePicture(), R.mipmap.img_work_car1)
+ )
}
private fun showTypeDialog() {
@@ -167,23 +174,16 @@
// 进入图库
@SuppressLint("SourceLockedOrientationActivity")
private fun enterGallery() {
- PictureSelector.create(this)
- .openGallery(SelectMimeType.ofImage())
- .setImageEngine(GlideEngine.createGlideEngine())
- .setMaxSelectNum(viewModel.maxSize - viewModel.adapterNow.data.size)
- .setImageSpanCount(4)
- .isPreviewImage(true)
- .isDisplayCamera(false)
- .setCompressEngine(PictureCompressEngine())
- .forResult(resultCallbackListener)
+ PictureSelectorFactory.enterGallery(
+ this,
+ viewModel.maxSize - viewModel.adapterNow.data.size,
+ resultCallbackListener
+ )
}
// 拍照
private fun takeAPhotograph() {
- PictureSelector.create(this)
- .openCamera(SelectMimeType.ofImage())
- .setCompressEngine(PictureCompressEngine())
- .forResultActivity(resultCallbackListener)
+ PictureSelectorFactory.takeAPhotograph(this,resultCallbackListener)
}
private var resultCallbackListener = object : OnResultCallbackListener<LocalMedia> {
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/charge/ChargeCarVM.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/charge/ChargeCarVM.kt
index f5d3920..db96772 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/charge/ChargeCarVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/charge/ChargeCarVM.kt
@@ -21,7 +21,6 @@
import okhttp3.RequestBody.Companion.asRequestBody
import org.koin.core.component.inject
import java.io.File
-import kotlin.getValue
class ChargeCarVM(application: Application) : BaseViewModel(application) {
val workRepository: WorkRepository by inject()
@@ -52,6 +51,9 @@
launchRequest {
workRepository.queryCarInfo(carId)?.let {
carInfo.postValue(it)
+ val left =
+ if ((it.mileageRange ?: 0.0) <= 0) "" else it.mileageRange!!.toInt().toString()
+ leftCharge.postValue(left)
}
}
}
@@ -62,6 +64,7 @@
chargeRecord.postValue(it)
}
}
+ queryInfo()
}
fun startCharging(block: (Boolean) -> Unit) {
@@ -106,12 +109,20 @@
}
}
- fun stopCharging(block: (Boolean) -> Unit){
+ fun stopCharging(block: (Boolean) -> Unit) {
if (leftCharge.value.isNullOrEmpty()) {
ToastUtilCommon.showError("请输入剩余里程")
block(false)
return
}
+ if (leftCharge.value!!.toDouble() < (chargeRecord.value?.xpChargingRecord?.startRemainingBattery
+ ?: 0)
+ ) {
+ ToastUtilCommon.showError("结束电量不得低于开始电量")
+ block(false)
+ return
+ }
+
if (adapterNow.data.isEmpty()) {
ToastUtilCommon.showError("请上传照片")
block(false)
@@ -139,7 +150,11 @@
}
}
- private fun uploadFile(files: List<FileSelectBean>,block: (Boolean) -> Unit, succ: () -> Unit) {
+ private fun uploadFile(
+ files: List<FileSelectBean>,
+ block: (Boolean) -> Unit,
+ succ: () -> Unit
+ ) {
val result = files.find { it.url.isEmpty() }
if (result == null) {
succ()
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/charge/ChargeDetailActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/charge/ChargeDetailActivity.kt
index c5ca893..eaa3f99 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/charge/ChargeDetailActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/charge/ChargeDetailActivity.kt
@@ -2,7 +2,6 @@
import android.annotation.SuppressLint
import androidx.recyclerview.widget.GridLayoutManager
-import com.xw.common.base.BaseActivity
import com.xw.common.base.FileSelectBean
import com.xw.common.base.ImageEventListener
import com.xw.common.base.ImageSelectAdapter
@@ -10,6 +9,7 @@
import com.xw.common.custom.BatteryView.Companion.getBatteryColorByBatteryLife
import com.xw.common.utils.BindUtils.getUrls
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.databinding.ActivityCarChargeDetailBinding
import com.xw.yunwei.model.CarModel
import java.util.ArrayList
@@ -18,7 +18,7 @@
/**
* 充电详情
*/
-class ChargeDetailActivity: BaseActivity<ActivityCarChargeDetailBinding, ChargeDetailVM>() {
+class ChargeDetailActivity: BaseBusinessActivity<ActivityCarChargeDetailBinding, ChargeDetailVM>() {
override fun getBindingVariable() = BR.viewModel
override fun init() {
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/check/CheckCarActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/check/CheckCarActivity.kt
index 6ca9005..9d1d486 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/check/CheckCarActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/check/CheckCarActivity.kt
@@ -1,41 +1,41 @@
package com.xw.yunwei.ui.work.car.detail.operations.check
import android.annotation.SuppressLint
-import android.net.Uri
+import android.util.TypedValue
+import android.widget.TextView
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.core.net.toUri
+import androidx.lifecycle.MutableLiveData
import androidx.recyclerview.widget.GridLayoutManager
import com.blankj.utilcode.util.UriUtils
-import com.luck.picture.lib.basic.PictureSelector
import com.luck.picture.lib.config.PictureMimeType
-import com.luck.picture.lib.config.SelectMimeType
import com.luck.picture.lib.entity.LocalMedia
import com.luck.picture.lib.interfaces.OnResultCallbackListener
import com.xw.common.CommonDialog
-import com.xw.common.base.BaseActivity
import com.xw.common.base.FileSelectBean
import com.xw.common.base.ImageEventListener
import com.xw.common.base.ImageSelectAdapter
import com.xw.common.base.ShowImgListDialog
-import com.xw.common.custom.SlideSwitchView.OnStateChangeListener
-import com.xw.common.utils.BindUtils.getUrl
-import com.xw.common.utils.GlideEngine
-import com.xw.common.utils.PictureCompressEngine
-import com.xw.common.utils.ToastUtilCommon
import com.xw.common.viewAdapter.ImageDefault
import com.xw.common.viewAdapter.ViewAdapter
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.Constants.user
import com.xw.yunwei.R
import com.xw.yunwei.databinding.ActivityCarCheckBinding
-import com.xw.yunwei.model.CarCheckModel
+import com.xw.yunwei.extension.colorIdToColorValue
+import com.xw.yunwei.extension.dpToPx
import com.xw.yunwei.model.CarModel
import com.xw.yunwei.model.CheckRecordModel
-import java.util.ArrayList
-import kotlin.text.ifEmpty
+import com.xw.yunwei.utils.PictureSelectorFactory
+import kotlin.math.max
+import kotlin.math.min
/**
* 车辆检测
*/
-class CheckCarActivity : BaseActivity<ActivityCarCheckBinding, CheckCarVM>() {
+class CheckCarActivity : BaseBusinessActivity<ActivityCarCheckBinding, CheckCarVM>() {
+ private val animationHeight = 100.0
override fun getBindingVariable() = BR.viewModel
val adapter by lazy { CheckCarAdapter().apply { setHasStableIds(true) } }
@@ -55,72 +55,6 @@
)
viewModel.queryInfo()
initAdapter()
- viewModel.switchs.clear()
- viewModel.switchs.addAll(listOf(
- binding.switch1,
- binding.switch2,
- binding.switch3,
- binding.switch4,
- binding.switch5
- ))
- }
-
- override fun setListener() {
- super.setListener()
- /**
- * 未检测状态必须是没有照片的情况下修改,传了照片不能修改为未检测:提示先删除照片;
- * 未传照片可以改为已检测,照片非必传
- */
- binding.switch1.setOnStateChangeListener(object : OnStateChangeListener {
- override fun onStateChanged(isChecked: Boolean) {
- if (viewModel.adapters[0].data.isNotEmpty() && !isChecked) {
- binding.switch1.setChecked(checked = true, animate = true)
- ToastUtilCommon.showWarn("请先删除照片")
- } else {
- viewModel.requestModel.sensorCleaning = if (isChecked) 1 else 0
- }
- }
- })
- binding.switch2.setOnStateChangeListener(object : OnStateChangeListener {
- override fun onStateChanged(isChecked: Boolean) {
- if (viewModel.adapters[1].data.isNotEmpty() && !isChecked) {
- binding.switch2.setChecked(checked = true, animate = true)
- ToastUtilCommon.showWarn("请先删除照片")
- } else {
- viewModel.requestModel.interactiveScreen = if (isChecked) 1 else 0
- }
- }
- })
- binding.switch3.setOnStateChangeListener(object : OnStateChangeListener {
- override fun onStateChanged(isChecked: Boolean) {
- if (viewModel.adapters[2].data.isNotEmpty() && !isChecked) {
- binding.switch3.setChecked(checked = true, animate = true)
- ToastUtilCommon.showWarn("请先删除照片")
- } else {
- viewModel.requestModel.helpButton = if (isChecked) 1 else 0
- }
- }
- })
- binding.switch4.setOnStateChangeListener(object : OnStateChangeListener {
- override fun onStateChanged(isChecked: Boolean) {
- if (viewModel.adapters[3].data.isNotEmpty() && !isChecked) {
- binding.switch4.setChecked(checked = true, animate = true)
- ToastUtilCommon.showWarn("请先删除照片")
- } else {
- viewModel.requestModel.paymentFunction = if (isChecked) 1 else 0
- }
- }
- })
- binding.switch5.setOnStateChangeListener(object : OnStateChangeListener {
- override fun onStateChanged(isChecked: Boolean) {
- if (viewModel.adapters[4].data.isNotEmpty() && !isChecked) {
- binding.switch5.setChecked(checked = true, animate = true)
- ToastUtilCommon.showWarn("请先删除照片")
- } else {
- viewModel.requestModel.systemCheck = if (isChecked) 1 else 0
- }
- }
- })
}
override fun setObservable() {
@@ -133,7 +67,7 @@
viewModel.startCheck()// 检测
}
}
- viewModel.checkResult.observe(this){
+ viewModel.checkResult.observe(this) {
if (adapter.data.isEmpty()) { // 首次加载,触发动画
binding.rvCheck.post {
it.forEachIndexed { index, item ->
@@ -146,9 +80,80 @@
adapter.setList(it) // 后续更新
}
}
+
+ viewModel.checkStatus1.observe(this) {
+ refreshStatus(binding.tvStatus1, it)
+ }
+
+ viewModel.checkStatus2.observe(this) {
+ refreshStatus(binding.tvStatus2, it)
+ }
+
+ viewModel.checkStatus3.observe(this) {
+ refreshStatus(binding.tvStatus3, it)
+ }
+
+ viewModel.checkStatus4.observe(this) {
+ refreshStatus(binding.tvStatus4, it)
+ }
+
+ viewModel.checkStatus5.observe(this) {
+ refreshStatus(binding.tvStatus5, it)
+ }
}
- private fun initAdapter(){
+ override fun setListener() {
+ super.setListener()
+ binding.scrollView.setOnScrollChangeListener { view, scrollX, scrollY, oldScrollX, oldScrollY ->
+ updateHeader(scrollY)
+ }
+ }
+
+ //更新标题栏
+ private fun updateHeader(scrollY: Int) {
+ val scrollX = (binding.title.width + binding.basicLayout.width) / 2 + 4.dpToPx(this)
+ val ratio = max(0.0, min(scrollY / animationHeight, 1.0))
+ binding.title.layoutParams =
+ (binding.title.layoutParams as ConstraintLayout.LayoutParams).apply {
+ val marginTop =
+ (-15).dpToPx(this@CheckCarActivity) + (ratio * 15.dpToPx(this@CheckCarActivity))
+ val marginEnd = scrollX * ratio
+ setMargins(0, marginTop.toInt(), marginEnd.toInt(), 0)
+ }
+ binding.title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16 - 2 * ratio.toFloat())
+ binding.basicLayout.layoutParams =
+ (binding.basicLayout.layoutParams as ConstraintLayout.LayoutParams).apply {
+ val marginStart = scrollX * ratio
+ val marginTop =
+ 10.dpToPx(this@CheckCarActivity) - (ratio * 8.dpToPx(this@CheckCarActivity))
+ setMargins(marginStart.toInt(), marginTop.toInt(), 0, 0)
+ }
+ }
+
+ //刷新状态
+ private fun refreshStatus(textView: TextView, hadChecked: Boolean) {
+ textView.setBackgroundResource(if (hadChecked) R.drawable.shape_green_1_bg_2 else R.drawable.shape_gray_3_bg_2)
+ textView.setTextColor(
+ (if (hadChecked) com.xw.common.R.color.green_5 else com.xw.common.R.color.gray_8).colorIdToColorValue(
+ this
+ )
+ )
+ textView.text = if (hadChecked) "检测完成" else "待检测"
+ }
+
+ //获取状态
+ private fun getStatusLiveData(position: Int): MutableLiveData<Boolean> {
+ return when (position) {
+ 0 -> viewModel.checkStatus1
+ 1 -> viewModel.checkStatus2
+ 2 -> viewModel.checkStatus3
+ 3 -> viewModel.checkStatus4
+ 4 -> viewModel.checkStatus5
+ else -> MutableLiveData(false)
+ }
+ }
+
+ private fun initAdapter() {
binding.rvCheck.adapter = adapter
binding.rvCheck.layoutManager = GridLayoutManager(this, 2)
binding.rvCheck.itemAnimator = GridSlideInAnimator() // 设置自定义动画器
@@ -176,6 +181,9 @@
override fun deleteImage(item: FileSelectBean) {
viewModel.adapters[index].remove(item)
+ if (viewModel.adapters[index].data.isEmpty() && getStatusLiveData(index).value == true) {
+ getStatusLiveData(index).value = false
+ }
}
}
viewModel.imageEvents.add(imageEvent)
@@ -185,19 +193,19 @@
}
binding.rv1.adapter = viewModel.adapters[0]
- binding.rv1.layoutManager = GridLayoutManager(this, 5)
+ binding.rv1.layoutManager = GridLayoutManager(this, 4)
binding.rv2.adapter = viewModel.adapters[1]
- binding.rv2.layoutManager = GridLayoutManager(this, 5)
+ binding.rv2.layoutManager = GridLayoutManager(this, 4)
binding.rv3.adapter = viewModel.adapters[2]
- binding.rv3.layoutManager = GridLayoutManager(this, 5)
+ binding.rv3.layoutManager = GridLayoutManager(this, 4)
binding.rv4.adapter = viewModel.adapters[3]
- binding.rv4.layoutManager = GridLayoutManager(this, 5)
+ binding.rv4.layoutManager = GridLayoutManager(this, 4)
binding.rv5.adapter = viewModel.adapters[4]
- binding.rv5.layoutManager = GridLayoutManager(this, 5)
+ binding.rv5.layoutManager = GridLayoutManager(this, 4)
}
@SuppressLint("SetTextI18n")
@@ -209,12 +217,11 @@
)
)
binding.batteryView.setLevel(it.currentElectricity ?: 0)
- var url = ""
- try {
- url = it.vehiclePictures?.getUrl() ?: ""
- } catch (e: Exception) {
- }
- ViewAdapter.loadImage(binding.icon, ImageDefault(url, R.mipmap.img_work_car1))
+
+ ViewAdapter.loadImage(
+ binding.icon,
+ ImageDefault(it.getShowVehiclePicture(), R.mipmap.img_work_car1)
+ )
}
private fun showTypeDialog() {
@@ -226,23 +233,16 @@
// 进入图库
@SuppressLint("SourceLockedOrientationActivity")
private fun enterGallery() {
- PictureSelector.create(this)
- .openGallery(SelectMimeType.ofImage())
- .setImageEngine(GlideEngine.createGlideEngine())
- .setMaxSelectNum(viewModel.maxSizes[viewModel.operateIndex] - viewModel.adapters[viewModel.operateIndex].data.size)
- .setImageSpanCount(4)
- .isPreviewImage(true)
- .isDisplayCamera(false)
- .setCompressEngine(PictureCompressEngine())
- .forResult(resultCallbackListener)
+ PictureSelectorFactory.enterGallery(
+ this,
+ viewModel.maxSizes[viewModel.operateIndex] - viewModel.adapters[viewModel.operateIndex].data.size,
+ resultCallbackListener
+ )
}
// 拍照
private fun takeAPhotograph() {
- PictureSelector.create(this)
- .openCamera(SelectMimeType.ofImage())
- .setCompressEngine(PictureCompressEngine())
- .forResultActivity(resultCallbackListener)
+ PictureSelectorFactory.takeAPhotograph(this, resultCallbackListener)
}
private var resultCallbackListener = object : OnResultCallbackListener<LocalMedia> {
@@ -252,16 +252,17 @@
dataList.addAll(viewModel.adapters[viewModel.operateIndex].data)
for (item in selectList) {
val path: String = item.availablePath
- var imgPath = if (PictureMimeType.isContent(path) && !item.isCut && !item.isCompressed) {
- UriUtils.uri2File(Uri.parse(path)).absolutePath
- } else {
- path
- }
+ var imgPath =
+ if (PictureMimeType.isContent(path) && !item.isCut && !item.isCompressed) {
+ UriUtils.uri2File(path.toUri()).absolutePath
+ } else {
+ path
+ }
dataList.add(FileSelectBean(localPath = imgPath, type = "img"))
}
viewModel.adapters[viewModel.operateIndex].setList(dataList)
- if (dataList.isNotEmpty() && !viewModel.switchs[viewModel.operateIndex].isChecked()) {
- viewModel.switchs[viewModel.operateIndex].setChecked(checked = true, animate = true)
+ if (dataList.isNotEmpty() && getStatusLiveData(viewModel.operateIndex).value != true) {
+ getStatusLiveData(viewModel.operateIndex).value = true
}
}
}
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/check/CheckCarDetailActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/check/CheckCarDetailActivity.kt
index ef293b8..3836680 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/check/CheckCarDetailActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/check/CheckCarDetailActivity.kt
@@ -2,13 +2,13 @@
import android.annotation.SuppressLint
import androidx.recyclerview.widget.GridLayoutManager
-import com.xw.common.base.BaseActivity
import com.xw.common.base.FileSelectBean
import com.xw.common.base.ImageEventListener
import com.xw.common.base.ImageSelectAdapter
import com.xw.common.base.ShowImgListDialog
import com.xw.common.utils.BindUtils.getUrls
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.databinding.ActivityCarCheckDetailBinding
import com.xw.yunwei.model.CarCheckModel
import com.xw.yunwei.model.CarModel
@@ -17,7 +17,7 @@
/**
* 车辆检测
*/
-class CheckCarDetailActivity : BaseActivity<ActivityCarCheckDetailBinding, CheckCarDetailVM>() {
+class CheckCarDetailActivity : BaseBusinessActivity<ActivityCarCheckDetailBinding, CheckCarDetailVM>() {
override fun getBindingVariable() = BR.viewModel
val adapter by lazy { CheckCarAdapter().apply { setHasStableIds(true) } }
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/check/CheckCarVM.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/check/CheckCarVM.kt
index c0b1492..125c1d0 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/check/CheckCarVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/check/CheckCarVM.kt
@@ -10,7 +10,6 @@
import com.xw.common.base.FileSelectBean
import com.xw.common.base.ImageEventListener
import com.xw.common.base.ImageSelectAdapter
-import com.xw.common.custom.SlideSwitchView
import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.R
import com.xw.yunwei.model.CarCheckModel
@@ -26,7 +25,6 @@
import org.json.JSONObject
import org.koin.core.component.inject
import java.io.File
-import kotlin.getValue
class CheckCarVM(application: Application) : BaseViewModel(application) {
val workRepository: WorkRepository by inject()
@@ -55,8 +53,21 @@
}
}
- val switchs = mutableListOf<SlideSwitchView>()
- val adaptersName = listOf("传感器清洁", "车内交互屏检查", "紧急求助按钮/应答机", "支付功能", "订单系统检查")
+ //传感器清洁 检测状态
+ val checkStatus1 = MutableLiveData(false)
+
+ //车内交互屏检查 检测状态
+ val checkStatus2 = MutableLiveData(false)
+
+ //紧急求助按钮/应答机 检测状态
+ val checkStatus3 = MutableLiveData(false)
+
+ //支付功能 检测状态
+ val checkStatus4 = MutableLiveData(false)
+
+ //订单系统检查 检测状态
+ val checkStatus5 = MutableLiveData(false)
+
val adapters = mutableListOf<ImageSelectAdapter>()
val imageEvents = mutableListOf<ImageEventListener<FileSelectBean>>()
val maxSizes = listOf(6, 6, 6, 6, 6) // 先默认每个都是最大9张
@@ -106,10 +117,22 @@
val jsob = JSONObject(GsonUtils.toJson(data))
checkResult.value = listOf(
CarCheckModel("网络检测", if (jsob.optInt("networkDetection") == 1) 2 else 3),
- CarCheckModel("远程控制自检", if (jsob.optInt("remoteSelfCheck") == 1) 2 else 3),
- CarCheckModel("软件版本核对", if (jsob.optInt("versionVerification") == 1) 2 else 3),
- CarCheckModel("防撞激活", if (jsob.optInt("collisionAvoidanceActivation") == 1) 2 else 3),
- CarCheckModel("通讯自检", if (jsob.optInt("communicationSelfCheck") == 1) 2 else 3),
+ CarCheckModel(
+ "远程控制自检",
+ if (jsob.optInt("remoteSelfCheck") == 1) 2 else 3
+ ),
+ CarCheckModel(
+ "软件版本核对",
+ if (jsob.optInt("versionVerification") == 1) 2 else 3
+ ),
+ CarCheckModel(
+ "防撞激活",
+ if (jsob.optInt("collisionAvoidanceActivation") == 1) 2 else 3
+ ),
+ CarCheckModel(
+ "通讯自检",
+ if (jsob.optInt("communicationSelfCheck") == 1) 2 else 3
+ ),
CarCheckModel("传感器自检", if (jsob.optInt("sensorSelfCheck") == 1) 2 else 3),
)
requestModel.networkDetection = jsob.optInt("networkDetection")
@@ -128,7 +151,13 @@
// return
// }
adapters.forEachIndexed { index, adapter ->
- if (adapter.data.isEmpty() && !switchs[index].isChecked()) {
+ if ((adapter.data.isEmpty() && index != 3) ||
+ checkStatus1.value != true ||
+ checkStatus2.value != true ||
+ checkStatus3.value != true ||
+// checkStatus4.value != true ||
+ checkStatus5.value != true
+ ) {
// ToastUtilCommon.showError("请上传${adaptersName[index]}照片或修改检测状态")
ToastUtilCommon.showError("请完成所有检测项并上传图片")
return
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/clean/CleanCarActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/clean/CleanCarActivity.kt
index 5fdb8f4..9d914ac 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/clean/CleanCarActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/clean/CleanCarActivity.kt
@@ -4,29 +4,27 @@
import android.net.Uri
import androidx.recyclerview.widget.GridLayoutManager
import com.blankj.utilcode.util.UriUtils
-import com.luck.picture.lib.basic.PictureSelector
import com.luck.picture.lib.config.PictureMimeType
-import com.luck.picture.lib.config.SelectMimeType
import com.luck.picture.lib.entity.LocalMedia
import com.luck.picture.lib.interfaces.OnResultCallbackListener
import com.xw.common.CommonDialog
-import com.xw.common.base.BaseActivity
import com.xw.common.base.FileSelectBean
import com.xw.common.base.ImageEventListener
import com.xw.common.base.ImageSelectAdapter
import com.xw.common.base.ShowImgListDialog
-import com.xw.common.utils.GlideEngine
-import com.xw.common.utils.PictureCompressEngine
+import com.xw.common.viewAdapter.ImageDefault
+import com.xw.common.viewAdapter.ViewAdapter
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
+import com.xw.yunwei.R
import com.xw.yunwei.databinding.ActivityCarCleanBinding
import com.xw.yunwei.model.CarModel
-import java.util.ArrayList
-import kotlin.text.ifEmpty
+import com.xw.yunwei.utils.PictureSelectorFactory
/**
* 车身清洁
*/
-class CleanCarActivity : BaseActivity<ActivityCarCleanBinding, CleanCarVM>() {
+class CleanCarActivity : BaseBusinessActivity<ActivityCarCleanBinding, CleanCarVM>() {
override fun getBindingVariable() = BR.viewModel
override fun init() {
@@ -79,6 +77,10 @@
)
)
binding.batteryView.setLevel(it.currentElectricity ?: 0)
+ ViewAdapter.loadImage(
+ binding.ivCar,
+ ImageDefault(it.getShowVehiclePicture(), R.mipmap.img_work_car1)
+ )
}
private fun showTypeDialog() {
@@ -90,23 +92,16 @@
// 进入图库
@SuppressLint("SourceLockedOrientationActivity")
private fun enterGallery() {
- PictureSelector.create(this)
- .openGallery(SelectMimeType.ofImage())
- .setImageEngine(GlideEngine.createGlideEngine())
- .setMaxSelectNum(viewModel.maxSize - viewModel.adapter.data.size)
- .setImageSpanCount(4)
- .isPreviewImage(true)
- .isDisplayCamera(false)
- .setCompressEngine(PictureCompressEngine())
- .forResult(resultCallbackListener)
+ PictureSelectorFactory.enterGallery(
+ this,
+ viewModel.maxSize - viewModel.adapter.data.size,
+ resultCallbackListener
+ )
}
// 拍照
private fun takeAPhotograph() {
- PictureSelector.create(this)
- .openCamera(SelectMimeType.ofImage())
- .setCompressEngine(PictureCompressEngine())
- .forResultActivity(resultCallbackListener)
+ PictureSelectorFactory.takeAPhotograph(this,resultCallbackListener)
}
private var resultCallbackListener = object : OnResultCallbackListener<LocalMedia> {
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/clean/CleanCarDetailActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/clean/CleanCarDetailActivity.kt
index 9c3a7fe..0fefe1c 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/clean/CleanCarDetailActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/clean/CleanCarDetailActivity.kt
@@ -1,33 +1,21 @@
package com.xw.yunwei.ui.work.car.detail.operations.clean
import android.annotation.SuppressLint
-import android.net.Uri
import androidx.recyclerview.widget.GridLayoutManager
-import com.blankj.utilcode.util.UriUtils
-import com.luck.picture.lib.basic.PictureSelector
-import com.luck.picture.lib.config.PictureMimeType
-import com.luck.picture.lib.config.SelectMimeType
-import com.luck.picture.lib.entity.LocalMedia
-import com.luck.picture.lib.interfaces.OnResultCallbackListener
-import com.xw.common.CommonDialog
-import com.xw.common.base.BaseActivity
import com.xw.common.base.FileSelectBean
import com.xw.common.base.ImageEventListener
import com.xw.common.base.ImageSelectAdapter
import com.xw.common.base.ShowImgListDialog
import com.xw.common.utils.BindUtils.getUrls
-import com.xw.common.utils.GlideEngine
-import com.xw.common.utils.PictureCompressEngine
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.databinding.ActivityCarCleanDetailBinding
import com.xw.yunwei.model.CarModel
-import java.util.ArrayList
-import kotlin.text.ifEmpty
/**
* 车身清洁详情
*/
-class CleanCarDetailActivity : BaseActivity<ActivityCarCleanDetailBinding, CleanCarDetailVM>() {
+class CleanCarDetailActivity : BaseBusinessActivity<ActivityCarCleanDetailBinding, CleanCarDetailVM>() {
override fun getBindingVariable() = BR.viewModel
override fun init() {
super.init()
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/maintain/MaintainCarActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/maintain/MaintainCarActivity.kt
index a20b630..260690e 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/maintain/MaintainCarActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/maintain/MaintainCarActivity.kt
@@ -4,31 +4,26 @@
import android.net.Uri
import androidx.recyclerview.widget.GridLayoutManager
import com.blankj.utilcode.util.UriUtils
-import com.luck.picture.lib.basic.PictureSelector
import com.luck.picture.lib.config.PictureMimeType
-import com.luck.picture.lib.config.SelectMimeType
import com.luck.picture.lib.entity.LocalMedia
import com.luck.picture.lib.interfaces.OnResultCallbackListener
import com.xw.common.CommonDialog
-import com.xw.common.base.BaseActivity
import com.xw.common.base.FileSelectBean
import com.xw.common.base.ImageEventListener
import com.xw.common.base.ImageSelectAdapter
import com.xw.common.base.ShowImgListDialog
-import com.xw.common.utils.GlideEngine
-import com.xw.common.utils.PictureCompressEngine
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.Constants.user
import com.xw.yunwei.databinding.ActivityCarMaintainBinding
import com.xw.yunwei.model.CarModel
import com.xw.yunwei.model.MaintainRecordModel
-import java.util.ArrayList
-import kotlin.text.ifEmpty
+import com.xw.yunwei.utils.PictureSelectorFactory
/**
* 车辆整备
*/
-class MaintainCarActivity: BaseActivity<ActivityCarMaintainBinding, MaintainCarVM>() {
+class MaintainCarActivity: BaseBusinessActivity<ActivityCarMaintainBinding, MaintainCarVM>() {
override fun getBindingVariable() = BR.viewModel
override fun init() {
@@ -130,23 +125,16 @@
// 进入图库
@SuppressLint("SourceLockedOrientationActivity")
private fun enterGallery() {
- PictureSelector.create(this)
- .openGallery(SelectMimeType.ofImage())
- .setImageEngine(GlideEngine.createGlideEngine())
- .setMaxSelectNum(viewModel.maxSizes[viewModel.operateIndex] - viewModel.adapters[viewModel.operateIndex].data.size)
- .setImageSpanCount(4)
- .isPreviewImage(true)
- .isDisplayCamera(false)
- .setCompressEngine(PictureCompressEngine())
- .forResult(resultCallbackListener)
+ PictureSelectorFactory.enterGallery(
+ this,
+ viewModel.maxSizes[viewModel.operateIndex] - viewModel.adapters[viewModel.operateIndex].data.size,
+ resultCallbackListener
+ )
}
// 拍照
private fun takeAPhotograph() {
- PictureSelector.create(this)
- .openCamera(SelectMimeType.ofImage())
- .setCompressEngine(PictureCompressEngine())
- .forResultActivity(resultCallbackListener)
+ PictureSelectorFactory.takeAPhotograph(this,resultCallbackListener)
}
private var resultCallbackListener = object : OnResultCallbackListener<LocalMedia> {
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/maintain/MaintainDetailActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/maintain/MaintainDetailActivity.kt
index 65284ff..ecca569 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/maintain/MaintainDetailActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/maintain/MaintainDetailActivity.kt
@@ -2,21 +2,20 @@
import android.annotation.SuppressLint
import androidx.recyclerview.widget.GridLayoutManager
-import com.xw.common.base.BaseActivity
import com.xw.common.base.FileSelectBean
import com.xw.common.base.ImageEventListener
import com.xw.common.base.ImageSelectAdapter
import com.xw.common.base.ShowImgListDialog
import com.xw.common.utils.BindUtils.getUrls
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.databinding.ActivityCarMaintainDetailBinding
import com.xw.yunwei.model.CarModel
-import java.util.ArrayList
/**
* 整备详情
*/
-class MaintainDetailActivity : BaseActivity<ActivityCarMaintainDetailBinding, MaintainDetailVM>(){
+class MaintainDetailActivity : BaseBusinessActivity<ActivityCarMaintainDetailBinding, MaintainDetailVM>(){
override fun getBindingVariable() = BR.viewModel
override fun init() {
super.init()
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/RepairCarActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/RepairCarActivity.kt
index 189d226..1646ae7 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/RepairCarActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/RepairCarActivity.kt
@@ -4,43 +4,32 @@
import android.net.Uri
import androidx.recyclerview.widget.GridLayoutManager
import com.blankj.utilcode.util.UriUtils
-import com.luck.picture.lib.basic.PictureSelector
import com.luck.picture.lib.config.PictureMimeType
-import com.luck.picture.lib.config.SelectMimeType
import com.luck.picture.lib.entity.LocalMedia
import com.luck.picture.lib.interfaces.OnResultCallbackListener
import com.xw.common.CommonDialog
import com.xw.common.TimeDialog
import com.xw.common.TimeDialog.Companion.getTime
-import com.xw.common.base.BaseActivity
import com.xw.common.base.FileSelectBean
import com.xw.common.base.ImageEventListener
import com.xw.common.base.ImageSelectAdapter
import com.xw.common.base.ShowImgListDialog
-import com.xw.common.utils.BindUtils.getUrl
import com.xw.common.utils.BindUtils.getUrls
-import com.xw.common.utils.GlideEngine
-import com.xw.common.utils.PictureCompressEngine
import com.xw.common.utils.ToastUtilCommon
-import com.xw.common.viewAdapter.ImageDefault
-import com.xw.common.viewAdapter.ViewAdapter
import com.xw.yunwei.BR
-import com.xw.yunwei.Constants.user
-import com.xw.yunwei.R
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.databinding.ActivityCarRepairBinding
import com.xw.yunwei.model.CarModel
-import com.xw.yunwei.model.MaintainRecordModel
-import java.util.ArrayList
-import kotlin.text.isNotEmpty
-import kotlin.text.replace
+import com.xw.yunwei.utils.PictureSelectorFactory
+import java.util.Calendar
/**
* 车辆维修
*/
-class RepairCarActivity : BaseActivity<ActivityCarRepairBinding, RepairCarVM>() {
+class RepairCarActivity : BaseBusinessActivity<ActivityCarRepairBinding, RepairCarVM>() {
override fun getBindingVariable() = BR.viewModel
- val dialogTime: TimeDialog by lazy { TimeDialog(this) }
+ val dialogTime: TimeDialog by lazy { TimeDialog(this) }
override fun init() {
super.init()
@@ -61,8 +50,8 @@
}
}
viewModel.carInfo.observe(this) { initBasicInfo(it) }
- viewModel.repairRecord.observe(this){
- if(it.status == 2){
+ viewModel.repairRecord.observe(this) {
+ if (it.status == 2) {
it.xpVehicleRepair?.startRepairPicture?.let {
val list = it.getUrls().map { FileSelectBean(url = it, type = "img") }
viewModel.adapters[0].setList(list)
@@ -75,7 +64,9 @@
super.setListener()
binding.layoutSend.startTimeContainer.setOnClickListener {
val showTime = getTime(viewModel.startTime.value)
- val minTime = getTime("2020-01-01")
+ val minTime = Calendar.getInstance().apply {
+ add(Calendar.DAY_OF_MONTH, -7)
+ }.timeInMillis
dialogTime.show("选择日期", showTime, minTime) {
val selectTime = getTime(it)
if (!viewModel.endTime.value.isNullOrEmpty()) {
@@ -169,23 +160,16 @@
// 进入图库
@SuppressLint("SourceLockedOrientationActivity")
private fun enterGallery() {
- PictureSelector.create(this)
- .openGallery(SelectMimeType.ofImage())
- .setImageEngine(GlideEngine.createGlideEngine())
- .setMaxSelectNum(viewModel.maxSizes[viewModel.operateIndex] - viewModel.adapters[viewModel.operateIndex].data.size)
- .setImageSpanCount(4)
- .isPreviewImage(true)
- .isDisplayCamera(false)
- .setCompressEngine(PictureCompressEngine())
- .forResult(resultCallbackListener)
+ PictureSelectorFactory.enterGallery(
+ this,
+ viewModel.maxSizes[viewModel.operateIndex] - viewModel.adapters[viewModel.operateIndex].data.size,
+ resultCallbackListener
+ )
}
// 拍照
private fun takeAPhotograph() {
- PictureSelector.create(this)
- .openCamera(SelectMimeType.ofImage())
- .setCompressEngine(PictureCompressEngine())
- .forResultActivity(resultCallbackListener)
+ PictureSelectorFactory.takeAPhotograph(this, resultCallbackListener)
}
private var resultCallbackListener = object : OnResultCallbackListener<LocalMedia> {
@@ -195,11 +179,12 @@
dataList.addAll(viewModel.adapters[viewModel.operateIndex].data)
for (item in selectList) {
val path: String = item.availablePath
- var imgPath = if (PictureMimeType.isContent(path) && !item.isCut && !item.isCompressed) {
- UriUtils.uri2File(Uri.parse(path)).absolutePath
- } else {
- path
- }
+ var imgPath =
+ if (PictureMimeType.isContent(path) && !item.isCut && !item.isCompressed) {
+ UriUtils.uri2File(Uri.parse(path)).absolutePath
+ } else {
+ path
+ }
dataList.add(FileSelectBean(localPath = imgPath, type = "img"))
}
viewModel.adapters[viewModel.operateIndex].setList(dataList)
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/RepairCarDetailActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/RepairCarDetailActivity.kt
index 5f93715..0820068 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/RepairCarDetailActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/RepairCarDetailActivity.kt
@@ -2,23 +2,21 @@
import android.annotation.SuppressLint
import androidx.recyclerview.widget.GridLayoutManager
-import com.xw.common.base.BaseActivity
import com.xw.common.base.FileSelectBean
import com.xw.common.base.ImageEventListener
import com.xw.common.base.ImageSelectAdapter
import com.xw.common.base.ShowImgListDialog
import com.xw.common.utils.BindUtils.getUrls
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.databinding.ActivityCarRepairDetailBinding
-import com.xw.yunwei.model.CarCheckModel
import com.xw.yunwei.model.CarModel
import com.xw.yunwei.ui.work.car.detail.operations.repair.record.RepairCarDetailVM
-import java.util.ArrayList
/**
* 车辆维修详情
*/
-class RepairCarDetailActivity : BaseActivity<ActivityCarRepairDetailBinding, RepairCarDetailVM>() {
+class RepairCarDetailActivity : BaseBusinessActivity<ActivityCarRepairDetailBinding, RepairCarDetailVM>() {
override fun getBindingVariable() = BR.viewModel
override fun init() {
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/RepairCarVM.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/RepairCarVM.kt
index eeb72dd..0a251f0 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/RepairCarVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/RepairCarVM.kt
@@ -139,7 +139,7 @@
launchRequest("操作中..") {
val map = mapOf(
"repairMoney" to repairFees.value,
- "repairMoneyDetail" to GsonUtils.toJson(files.map { it.url }),
+ "repairMoneyDetail" to "${files.map { it.url }}",
"id" to repairRecord.value?.xpVehicleRepair?.id,
).toMutableMap()
if (taskId != -1L) {
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/record/RecordAdapter.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/record/RecordAdapter.kt
index 905cee4..f43f988 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/record/RecordAdapter.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/record/RecordAdapter.kt
@@ -37,7 +37,7 @@
binding.batteryView2.setBatteryLife(item.endRemainingBattery ?: 0)
}
it.name.text = item.operatorName
- it.time.text = item.operationTime
+ it.time.text = item.getShowOperationTime()
it.root.setOnClickListener { listener.onItemClick(item) }
}
}
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/record/RepairRecordActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/record/RepairRecordActivity.kt
index cff6751..738ff2d 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/record/RepairRecordActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/detail/operations/repair/record/RepairRecordActivity.kt
@@ -4,17 +4,15 @@
import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.google.android.material.tabs.TabLayoutMediator
-import com.xw.common.base.BaseActivity
import com.xw.yunwei.BR
-import com.xw.yunwei.Constants.user
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.databinding.ActivityCarRepairRecordBinding
import com.xw.yunwei.model.CarModel
-import com.xw.yunwei.model.MaintainRecordModel
/**
* 车辆维修记录
*/
-class RepairRecordActivity : BaseActivity<ActivityCarRepairRecordBinding, RepairRecordVM>() {
+class RepairRecordActivity : BaseBusinessActivity<ActivityCarRepairRecordBinding, RepairRecordVM>() {
override fun getBindingVariable() = BR.viewModel
private val tabTitles = listOf("整备记录", "充电记录", "检测记录", "维修记录", "车身清洁")
@@ -22,6 +20,19 @@
override fun init() {
super.init()
viewModel.carId = intent.getLongExtra("carId", 0L)
+ // 提前展示来源页传入的车牌号,无需等待 queryInfo 接口返回。
+ // 通过预填一个仅含 plateNumber 的占位 CarModel 触发 DataBinding,
+ // 避免直接 setText 后被 binding.executePendingBindings() 用空值覆盖。
+ val plateNumber = intent.getStringExtra("plateNumber")
+ val mileageRange = intent.getDoubleExtra("mileageRange", 0.0)
+ val vehicleColor = intent.getStringExtra("vehicleColor")
+ plateNumber?.takeIf { it.isNotEmpty() }?.let {
+ viewModel.carInfo.value = CarModel(
+ plateNumber = it,
+ mileageRange = mileageRange,
+ vehicleColor = vehicleColor
+ )
+ }
viewModel.queryInfo()
binding.pager.adapter = PageAdapter()
TabLayoutMediator(binding.tabs, binding.pager) { tab, positon ->
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/manage/CarAdapter.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/manage/CarAdapter.kt
index 08bde6c..6e13afc 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/manage/CarAdapter.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/manage/CarAdapter.kt
@@ -5,18 +5,23 @@
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.xw.common.base.OnItemClickListener
-import com.xw.common.utils.BindUtils.getUrl
import com.xw.common.utils.BindUtils.getResColor
import com.xw.common.viewAdapter.ImageDefault
import com.xw.common.viewAdapter.ViewAdapter
import com.xw.yunwei.R
import com.xw.yunwei.databinding.ItemWorkManageCarBinding
+import com.xw.yunwei.extension.colorIdToColorValue
import com.xw.yunwei.model.CarModel
class CarAdapter(var listener: OnItemClickListener<CarModel>) :
BaseQuickAdapter<CarModel, BaseViewHolder>(R.layout.item_work_manage_car) {
var selectItem: CarModel? = null
+ set(value) {
+ data.indexOf(field).takeIf { it != -1 }?.also { notifyItemChanged(it) }
+ field = value
+ data.indexOf(field).takeIf { it != -1 }?.also { notifyItemChanged(it) }
+ }
@SuppressLint("SetTextI18n")
override fun convert(holder: BaseViewHolder, item: CarModel) {
@@ -31,12 +36,10 @@
it.parent.setBackgroundColor(getResColor(com.xw.common.R.color.white))
}
- var url = ""
- try {
- url = item.vehiclePictures?.getUrl() ?: ""
- } catch (e: Exception) {
- }
- ViewAdapter.loadImage(binding.icon, ImageDefault(url, R.mipmap.img_work_car))
+ ViewAdapter.loadImage(
+ binding.icon,
+ ImageDefault(item.getShowVehiclePicture(), R.mipmap.img_work_car)
+ )
binding.name.text = item.plateNumber
binding.color.text = item.vehicleColor
binding.batteryLife.text = "${item.mileageRange?.toInt()}km"
@@ -46,46 +49,9 @@
)
)
binding.batteryView.setLevel(item.currentElectricity ?: 0)
-
- val setStatus: (Int, Int) -> Unit = { text, bg ->
- binding.status.setTextColor(text)
- binding.status.setBackgroundResource(bg)
- }
-
- // 1=运营中 2=维修中 3=已收车 4=车辆异常
- when (item.operatingStatus) {
- 1 -> {
- setStatus(
- getResColor(com.xw.common.R.color.blue_5),
- com.xw.common.R.color.blue_1
- )
- binding.status.text = "运营中"
- }
-
- 2 -> {
- setStatus(
- getResColor(com.xw.common.R.color.red_5),
- com.xw.common.R.color.red_1
- )
- binding.status.text = "维修中"
- }
-
- 3 -> {
- setStatus(
- getResColor(com.xw.common.R.color.gray_7),
- com.xw.common.R.color.gray_3
- )
- binding.status.text = "已收车"
- }
-
- 4 -> {
- setStatus(
- getResColor(com.xw.common.R.color.orange_5),
- com.xw.common.R.color.orange_1
- )
- binding.status.text = "车辆异常"
- }
- }
+ binding.status.setBackgroundResource(item.getShowStatusBgResource())
+ binding.status.setTextColor(item.getShowStatusTextColor().colorIdToColorValue(it.root.context))
+ binding.status.text=item.getShowStatus()
}
}
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/manage/CarManageActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/manage/CarManageActivity.kt
index 432e4aa..716dcbe 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/manage/CarManageActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/manage/CarManageActivity.kt
@@ -1,6 +1,7 @@
package com.xw.yunwei.ui.work.car.manage
import android.annotation.SuppressLint
+import android.os.Bundle
import android.view.Gravity
import android.view.KeyEvent
import android.view.View
@@ -16,25 +17,30 @@
import com.afollestad.materialdialogs.customview.customView
import com.afollestad.materialdialogs.customview.getCustomView
import com.amap.api.maps.model.LatLng
+import com.blankj.utilcode.util.BarUtils
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.xw.common.CommonDialog
import com.xw.common.R
-import com.xw.common.base.BaseActivity
import com.xw.common.base.OnItemClickListener
import com.xw.common.utils.BindUtils
-import com.xw.common.utils.ToastUtilCommon
import com.xw.common.viewAdapter.ViewAdapter.Companion.showAnim
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.databinding.ActivityCarManageBinding
import com.xw.yunwei.databinding.DialogCarFilterBinding
+import com.xw.yunwei.extension.colorIdToColorValue
+import com.xw.yunwei.extension.dpToPx
+import com.xw.yunwei.extension.drawableIdToDrawable
+import com.xw.yunwei.extension.hideKeyboardAndClearFocus
import com.xw.yunwei.model.CarModel
import com.xw.yunwei.ui.work.AMapFragment
import com.xw.yunwei.ui.work.car.detail.CarDetailActivity
+import com.xw.yunwei.utils.DialogFactory
/**
* 车辆管理
*/
-class CarManageActivity : BaseActivity<ActivityCarManageBinding, CarManageVM>(),
+class CarManageActivity : BaseBusinessActivity<ActivityCarManageBinding, CarManageVM>(),
OnItemClickListener<CarModel> {
override fun getBindingVariable() = BR.viewModel
@@ -56,13 +62,49 @@
)
}
+ // 设置底部导航栏的沉浸式 --------- START ---------
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ BarUtils.transparentNavBar(this)
+ BarUtils.setNavBarLightMode(this, true)
+ }
+
+ override fun onApplyNavigationBarInsets(view: View, bottomInset: Int) {
+ // view.updatePadding(bottom = bottomInset)
+ }
+ // 设置底部导航栏的沉浸式 --------- OVER ---------
+
override fun init() {
super.init()
val transaction = supportFragmentManager.beginTransaction()
transaction.add(com.xw.yunwei.R.id.map_container, mapFrag)
transaction.commit()
+ // halfExpandedRatio=0.58 → visible map area is top 42% of screen; midpoint = 0.21
+ mapFrag.initialLocationScreenYRatio = 0.55f
initAdapter()
setBehavior()
+ refreshFilterStatus()
+ }
+
+ //刷新筛选状态
+ private fun refreshFilterStatus() {
+ binding.filter.setTextColor(
+ (if (viewModel.hadFilter()) R.color.blue_5 else R.color.gray_9).colorIdToColorValue(
+ this
+ )
+ )
+ binding.filter.setCompoundDrawables(
+ null,
+ null,
+ (if (viewModel.hadFilter()) R.drawable.svg_filter2 else R.drawable.svg_filter).drawableIdToDrawable(
+ this
+ )?.apply {
+ setBounds(
+ 0, 0, 12.dpToPx(this@CarManageActivity), 12.dpToPx(this@CarManageActivity)
+ )
+ },
+ null
+ )
}
override fun onResume() {
@@ -76,13 +118,14 @@
binding.filter.setOnClickListener {
viewModel.queryAreas { showFilterDialog() }
}
- binding.location.setOnClickListener { mapFrag.moveToLocation() }
+ binding.location.setOnClickListener { mapFrag.moveToLocation(0.55f) }
binding.searchEt.setOnKeyListener { _, keyCode, event ->
if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_UP) {
// if (viewModel.search.value.isNullOrEmpty()) {
// ToastUtilCommon.show("请输入搜索内容")
// } else {
- viewModel.queryCars()
+ viewModel.queryCars()
+ hideKeyboardAndClearFocus()
// }
}
false
@@ -90,11 +133,9 @@
binding.arrow.setOnClickListener { toggleBottomSheetState() }
mapFrag.locationChangeCallback = { location ->
if (location == null) {
- CommonDialog.showTipsDialog(
- this@CarManageActivity,
- "您未开启gps权限,无法获取当前定位,请打开后重新操作",
- null)
+ CommonDialog.showLocationNotGrantedTipsDialog(this@CarManageActivity)
} else {
+ // TODO ... FATAL BUG: 当服务不可用,isNullOrEmpty永远为true时,这里会被1秒调一次去请求
if (viewModel.fences.value.isNullOrEmpty()) {
val cityCode = location.adCode.substring(0, 4) + "00"
viewModel.getFenceByCode(cityCode)
@@ -107,6 +148,10 @@
adapter.addData(0, it)
adapter.selectItem = it
adapter.notifyDataSetChanged()
+ animateMapTo(it.latitude ?: 0.0, it.longitude ?: 0.0)
+ mapFrag.findMarkerById("${it.id ?: ""}")?.let { marker ->
+ mapFrag.clickMarker(marker)
+ }
}
}
}
@@ -123,12 +168,15 @@
adapter.setList(it)
mapFrag.clearMarks()
it.forEach {
- val resId = if (it.operatingStatus == 1) com.xw.yunwei.R.mipmap.ic_map_car_g else com.xw.yunwei.R.mipmap.ic_map_car_r
+ val resId =
+ if (it.isWorking()) com.xw.yunwei.R.mipmap.ic_map_car_g else com.xw.yunwei.R.mipmap.ic_map_car_r
mapFrag.drawCustomMarker(
LatLng(it.latitude ?: 0.0, it.longitude ?: 0.0),
resId,
"${it.id}",
- it.plateNumber
+ it.plateNumber,
+ 1f,
+ (-20).dpToPx(this)
)
}
}
@@ -143,7 +191,7 @@
areas.add(area)
}
}
- if(areas.isNotEmpty()){
+ if (areas.isNotEmpty()) {
mapFrag.drawPolygon(areas)
}
}
@@ -242,11 +290,8 @@
}
private fun arrow(value: Float) {
- binding.arrow.animate()
- .rotation(value)
- .setDuration(300)
- .setInterpolator(DecelerateInterpolator())
- .start()
+ binding.arrow.animate().rotation(value).setDuration(300)
+ .setInterpolator(DecelerateInterpolator()).start()
}
private fun initAdapter() {
@@ -256,7 +301,7 @@
private fun showFilterDialog() {
if (filterDialog == null) {
- filterDialog = MaterialDialog(this).apply {
+ filterDialog = DialogFactory.produce(this).apply {
customView(
com.xw.yunwei.R.layout.dialog_car_filter,
noVerticalPadding = true,
@@ -273,7 +318,7 @@
bind.stllStatus.remove()
bind.stllArea.setData(
- viewModel.filterAreas.map { it.electronicName?:"" },
+ viewModel.filterAreas.map { it.electronicName ?: "" },
this@CarManageActivity,
ArrayList(),
this@CarManageActivity.resources.getColor(R.color.blue_5),
@@ -359,18 +404,21 @@
}
bind.btnRight.setOnClickListener {
viewModel.queryCars()
+ refreshFilterStatus()
dismiss()
}
}
+ setOnDismissListener { binding.filterOverlay.visibility = View.GONE }
}
}
filterDialog?.show()
+ binding.filterOverlay.visibility = View.VISIBLE
// 关键:让软键盘把 BottomSheet 顶上去
filterDialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
+ filterDialog?.window?.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
filterDialog?.window?.setLayout(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT
)
filterDialog?.window?.setGravity(Gravity.BOTTOM)
filterDialog?.window?.setWindowAnimations(R.style.AnimUp)
@@ -379,7 +427,26 @@
override fun onItemClick(item: CarModel) {
+ if ((item.latitude ?: 0.0) > 0 && (item.longitude ?: 0.0) > 0) {
+ animateMapTo(item.latitude!!, item.longitude!!)
+ mapFrag.findMarkerById("${item.id ?: ""}")?.let {
+ mapFrag.clickMarker(it)
+ }
+ }
+ if (adapter.selectItem != item) {
+ adapter.selectItem = item
+ return
+ }
+ jumpToDetail(item)
+ }
+
+ //跳转详情页
+ private fun jumpToDetail(item: CarModel) {
startActivity(CarDetailActivity::class.java, bundleOf("carId" to item.id))
}
+ private fun animateMapTo(latitude: Double, longitude: Double) {
+ val ratio = if (bottomSheetBehavior.state == BottomSheetBehavior.STATE_HALF_EXPANDED) 0.55f else 0.5f
+ mapFrag.animateTo(latitude, longitude, targetScreenYRatio = ratio)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/car/manage/CarManageVM.kt b/app/src/main/java/com/xw/yunwei/ui/work/car/manage/CarManageVM.kt
index 9743a7e..70a6e41 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/car/manage/CarManageVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/car/manage/CarManageVM.kt
@@ -6,7 +6,6 @@
import com.xw.yunwei.model.AreaModel
import com.xw.yunwei.model.CarModel
import com.xw.yunwei.model.FenceInfoModel
-import com.xw.yunwei.model.SiteModel
import com.xw.yunwei.net.WorkRepository
import org.koin.core.component.inject
@@ -17,9 +16,13 @@
val filterStatus = listOf(
"全部",
"运营中",
- "维修中",
+ "出车中",
+ "接单中",
+ "停止接单",
"已收车",
"车辆异常",
+ "维修中",
+ "充电中",
)
val selectArea = mutableListOf<AreaModel>()
@@ -27,6 +30,11 @@
val search = MutableLiveData("") // 车牌号
val carList: MutableLiveData<List<CarModel>> = MutableLiveData()
var fences: MutableLiveData<List<FenceInfoModel>> = MutableLiveData() // 站点详情
+
+ //是否已经筛选
+ fun hadFilter(): Boolean {
+ return selectArea.isNotEmpty() || selectStatus.count { it != filterStatus[0] } > 0
+ }
fun queryCars() {
launchRequest {
@@ -36,8 +44,9 @@
map["status"] =
if (selectStatus.contains("全部")) null
else {
- if (selectStatus.isNotEmpty()) selectStatus.map { filterStatus.indexOf(it) }.joinToString(",")
- else null // 运营状态 1运营中 2维修中 3已收车 4车辆异常
+ if (selectStatus.isNotEmpty()) selectStatus.map { filterStatus.indexOf(it) }
+ .joinToString(",")
+ else null // 1=运营中,2=出车中,3=接单中,4=停止接单,5=已收车,6=车辆异常,7=维修中,8=充电中
}
map["electronicId"] =
if (selectArea.isNotEmpty()) selectArea.map { it.id ?: 0L }.joinToString(",")
@@ -62,7 +71,7 @@
}
}
- fun getFenceByCode(cityCode: String){
+ fun getFenceByCode(cityCode: String) {
launchRequest(showLoading = false) {
workRepository.getFenceByCode(cityCode)?.let {
fences.postValue(it)
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/CheckInMissionPointsListActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/CheckInMissionPointsListActivity.kt
new file mode 100644
index 0000000..5a198c6
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/CheckInMissionPointsListActivity.kt
@@ -0,0 +1,73 @@
+package com.xw.yunwei.ui.work.checkInMission
+
+import android.os.Bundle
+import androidx.core.os.bundleOf
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.xw.common.base.fastObserve
+import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
+import com.xw.yunwei.R
+import com.xw.yunwei.constants.Key
+import com.xw.yunwei.databinding.ActivityCheckInMissionPointsListBinding
+import com.xw.yunwei.ui.work.checkInMission.adapter.CheckInMissionPointAdapter
+import com.xw.yunwei.ui.work.checkInMission.viewmodel.CheckInMissionPointsListViewModel
+
+//打卡点位列表页
+class CheckInMissionPointsListActivity :
+ BaseBusinessActivity<ActivityCheckInMissionPointsListBinding, CheckInMissionPointsListViewModel>() {
+ companion object {
+ //获取跳转该页面参数
+ fun getParams(id: String): Bundle {
+ return bundleOf(Key.ID to id)
+ }
+ }
+
+ val adapter by lazy {
+ CheckInMissionPointAdapter().apply {
+ addChildClickViewIds(R.id.ll_address_nav)
+ }
+ }
+
+ override fun getBindingVariable() = BR.viewModel
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ viewModel.id = intent.getStringExtra(Key.ID) ?: ""
+ viewModel.refreshLiveData.fastObserve(this, binding.refreshLayout)
+ }
+
+ override fun setObservable() {
+ super.setObservable()
+ viewModel.pointsList.observe(this) {
+ adapter.setNewInstance(it.toMutableList())
+ }
+ }
+
+ override fun setListener() {
+ super.setListener()
+ binding.rvList.adapter = adapter
+ binding.rvList.layoutManager = LinearLayoutManager(this)
+ with(binding.refreshLayout) {
+ setOnRefreshListener {
+ viewModel.refreshData()
+ }
+ }
+ adapter.setOnItemClickListener { adapter, view, i ->
+ if (viewModel.pointsList.value!![i].hadCheckIn()) {
+ viewModel.showCheckInSuccessDialog(this, viewModel.pointsList.value!![i])
+ return@setOnItemClickListener
+ }
+ }
+ adapter.setOnItemChildClickListener { adapter, view, i ->
+ if (viewModel.pointsList.value!![i].hadCheckIn()) {
+ viewModel.showCheckInSuccessDialog(this, viewModel.pointsList.value!![i])
+ return@setOnItemChildClickListener
+ }
+ viewModel.routePlanning(i)
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ viewModel.refreshData()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/CruiseCheckInActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/CruiseCheckInActivity.kt
new file mode 100644
index 0000000..80afd6f
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/CruiseCheckInActivity.kt
@@ -0,0 +1,821 @@
+package com.xw.yunwei.ui.work.checkInMission
+
+import android.graphics.Color
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import androidx.core.os.bundleOf
+import androidx.core.view.isVisible
+import com.amap.api.maps.AMap
+import com.amap.api.maps.AMapUtils
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.BitmapDescriptorFactory
+import com.amap.api.maps.model.CameraPosition
+import com.amap.api.maps.model.CircleOptions
+import com.amap.api.maps.model.LatLng
+import com.amap.api.maps.model.MarkerOptions
+import com.amap.api.maps.model.Polyline
+import com.amap.api.maps.model.PolylineOptions
+import com.amap.api.navi.AMapNavi
+import com.amap.api.navi.AMapNaviIndependentRouteListener
+import com.amap.api.navi.AMapNaviListener
+import com.amap.api.navi.TTSPlayListener
+import com.amap.api.navi.enums.NaviType
+import com.amap.api.navi.enums.TransportType
+import com.amap.api.navi.enums.TravelStrategy
+import com.amap.api.navi.model.AMapCalcRouteResult
+import com.amap.api.navi.model.AMapLaneInfo
+import com.amap.api.navi.model.AMapModelCross
+import com.amap.api.navi.model.AMapNaviCameraInfo
+import com.amap.api.navi.model.AMapNaviCross
+import com.amap.api.navi.model.AMapNaviLocation
+import com.amap.api.navi.model.AMapNaviPath
+import com.amap.api.navi.model.AMapNaviPathGroup
+import com.amap.api.navi.model.AMapNaviRouteNotifyData
+import com.amap.api.navi.model.AMapNaviTrafficFacilityInfo
+import com.amap.api.navi.model.AMapServiceAreaInfo
+import com.amap.api.navi.model.AMapTravelInfo
+import com.amap.api.navi.model.AimLessModeCongestionInfo
+import com.amap.api.navi.model.AimLessModeStat
+import com.amap.api.navi.model.NaviInfo
+import com.amap.api.navi.model.NaviLatLng
+import com.amap.api.navi.model.NaviPoi
+import com.amap.api.navi.model.RouteOverlayOptions
+import com.amap.api.navi.view.RouteOverLay
+import com.blankj.utilcode.util.GsonUtils
+import com.blankj.utilcode.util.SpanUtils
+import com.google.gson.reflect.TypeToken
+import com.xw.common.CommonDialog
+import com.xw.common.utils.BindUtils.getResColor
+import com.xw.common.utils.ToastUtilCommon
+import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
+import com.xw.yunwei.R
+import com.xw.yunwei.constants.Key
+import com.xw.yunwei.databinding.ActivityCruiseCheckInBinding
+import com.xw.yunwei.extension.colorIdToColorValue
+import com.xw.yunwei.model.CheckInMissionPointInfo
+import com.xw.yunwei.model.CruiseCheckInOperationResult
+import com.xw.yunwei.ui.work.amap.custom.view.CarOverlay
+import com.xw.yunwei.ui.work.amap.util.NaviUtil
+import com.xw.yunwei.ui.work.checkInMission.util.Utils
+import com.xw.yunwei.ui.work.checkInMission.viewmodel.CruiseCheckInViewModel
+import org.greenrobot.eventbus.EventBus
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+import java.text.SimpleDateFormat
+import java.util.Date
+
+//巡游打卡导航页
+class CruiseCheckInActivity :
+ BaseBusinessActivity<ActivityCruiseCheckInBinding, CruiseCheckInViewModel>(),
+ AMapNaviListener, TTSPlayListener, AMapNaviIndependentRouteListener {
+ companion object {
+ //获取跳转此页面参数
+ fun getParams(
+ id: String,
+ points: List<CheckInMissionPointInfo>,
+ startPoint: NaviPoi,
+ type: Int,
+ ): Bundle {
+ return bundleOf(
+ Key.ID to id,
+ Key.POINTS to GsonUtils.toJson(points),
+ Key.START_POINT to startPoint,
+ Key.TYPE to type
+ )
+ }
+ }
+
+ //导航对象
+ var aMapNavi: AMapNavi? = null
+
+ //设备位置类
+ var carOverlay: CarOverlay? = null
+
+ //路线OverLay
+ var routeOverLay: RouteOverLay? = null
+
+ //起点/终点回拉线
+ private val leaderLines = mutableListOf<Polyline>()
+
+ //上次计算路线起点定位
+ var lastCalculateRouteStartLocation: AMapNaviLocation? = null
+ override fun getBindingVariable() = BR.viewModel
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ if (!EventBus.getDefault().isRegistered(this)) {
+ EventBus.getDefault().register(this)
+ }
+
+ binding.amapView.onCreate(savedInstanceState)
+
+ initAMapView()
+
+ aMapNavi = AMapNavi.getInstance(this)?.also {
+ it.isNaviTravelView = true
+ it.addAMapNaviListener(this)
+ it.addTTSPlayListener(this)
+ it.setUseInnerVoice(true, true)
+ it.setEmulatorNaviSpeed(75)
+ }
+
+ viewModel.id = intent.getStringExtra(Key.ID) ?: ""
+ viewModel.points.postValue(
+ GsonUtils.fromJson(
+ intent.getStringExtra(Key.POINTS),
+ object : TypeToken<List<CheckInMissionPointInfo>>() {}.type
+ )
+ )
+ viewModel.startPoint = intent.getParcelableExtra(Key.START_POINT)
+ viewModel.type = intent.getIntExtra(Key.TYPE, 0)
+
+ viewModel.checkOutTimeOut()
+ }
+
+ //初始化高德导航控件
+ private fun initAMapView() {
+ binding.amapView.map?.also { it ->
+ it.mapType = AMap.MAP_TYPE_NAVI
+
+ it.uiSettings?.setZoomInByScreenCenter(false)
+ it.uiSettings?.isZoomControlsEnabled = false
+ it.setOnMapLoadedListener {
+ it.setPointToCenter(
+ binding.amapView.width / 2,
+ binding.amapView.height / 2
+ )
+ it.moveCamera(CameraUpdateFactory.zoomTo(16f))
+ carOverlay = CarOverlay(this, binding.amapView).apply {
+ setLock(false)
+ }
+ viewModel.needCalculateRoute.postValue(true)
+ }
+ it.setOnMarkerClickListener { marker ->
+ if (binding.slFloatNotice.isVisible) {
+ return@setOnMarkerClickListener false
+ }
+ val poi = marker.`object` as NaviPoi?
+ viewModel.points.value?.find {
+ it.lat?.toDoubleOrNull() == poi?.coordinate?.latitude &&
+ it.lon?.toDoubleOrNull() == poi?.coordinate?.longitude
+ }?.also {
+ viewModel.choicePoint.postValue(it)
+ }
+ return@setOnMarkerClickListener true
+ }
+ }
+ }
+
+ override fun setObservable() {
+ super.setObservable()
+ viewModel.needCalculateRoute.observe(this) { it ->
+ if (!it || viewModel.getEndPoint() == null) {
+ return@observe
+ }
+ aMapNavi?.also { it ->
+ if (viewModel.type == 0) {
+ it.travelInfo = AMapTravelInfo(TransportType.Walk)
+ val success = it.calculateWalkRoute(
+ viewModel.startPoint,
+ viewModel.getPassingPoints(),
+ viewModel.getEndPoint()!!,
+ TravelStrategy.SINGLE
+ )
+ if (!success) {
+ Log.d(TAG, "步行路线计算失败,检查参数情况")
+ }
+ }
+ if (viewModel.type == 1) {
+ it.travelInfo = AMapTravelInfo(TransportType.Ride)
+ val success = it.calculateRideRoute(
+ viewModel.startPoint,
+ viewModel.getPassingPoints(),
+ viewModel.getEndPoint()!!,
+ TravelStrategy.SINGLE
+ )
+ if (!success) {
+ Log.d(TAG, "骑行路线计算失败,检查参数情况")
+ }
+ }
+ }
+ }
+ viewModel.points.observe(this) {
+ refreshNextPointInfo()
+ }
+ viewModel.isOverview.observe(this) { it ->
+ binding.ivOverview.setImageResource(if (it) R.mipmap.ic_route_arrow_close else R.mipmap.ic_route_arrow)
+ binding.tvOverview.text = if (it) "退出全览" else "全览"
+ if (it) {
+ routeOverLay?.zoomToSpan()
+ } else {
+ binding.amapView.map?.also {
+ viewModel.aMapNaviLocation?.also { location ->
+ it.animateCamera(
+ CameraUpdateFactory.newCameraPosition(
+ CameraPosition.fromLatLngZoom(
+ LatLng(
+ location.coord.latitude,
+ location.coord.longitude
+ ), 16f
+ )
+ )
+ )
+ }
+ }
+ }
+ }
+ viewModel.hadExpand.observe(this) {
+ binding.ivFlexing.setImageResource(if (it) R.mipmap.ic_down else R.mipmap.ic_up)
+ binding.llLocationInfo.visibility = if (it) View.VISIBLE else View.GONE
+ }
+ viewModel.couldCheckIn.observe(this) {
+ binding.tvCheckIn.setBackgroundResource(if (it) R.drawable.shape_blue_5_bg_4 else R.drawable.shape_gray_4_bg_4)
+ binding.tvCheckInNotice.visibility = if (it) View.INVISIBLE else View.VISIBLE
+ binding.tvFloatCheckIn.setBackgroundResource(if (it) R.drawable.shape_blue_5_bg_4 else R.drawable.shape_gray_4_bg_4)
+ }
+ viewModel.checkInOperationInfo.observe(this) {
+ viewModel.getNextPoint()?.also { nextPoint ->
+ viewModel.couldCheckIn.postValue(it.isLocationInCheckInRange())
+ if (!it.isEffective()) {
+ binding.llTimeoutNotice.visibility = View.GONE
+ binding.slFloatNotice.visibility = View.GONE
+ return@observe
+ }
+ binding.tvTime.text = nextPoint.time
+ binding.tvAddress.text = nextPoint.address
+
+ if (it.needShowCheckInNotice() && !viewModel.showCheckInNoticeHistory.contains(it.checkLocationId)) {
+ viewModel.showCheckInNoticeHistory.add(it.checkLocationId!!)
+ viewModel.choicePoint.postValue(null)
+ viewModel.hadExpand.postValue(false)
+ binding.slFloatNotice.visibility = View.VISIBLE
+ SpanUtils.with(binding.tvFloatNotice)
+ .append("您已到达")
+ .setForegroundColor(getResColor(com.xw.common.R.color.gray_9))
+ .append("【${it.message ?: nextPoint.address ?: ""}】")
+ .setForegroundColor(getResColor(com.xw.common.R.color.blue_5))
+ .append("打卡点,是否立即打卡?")
+ .setForegroundColor(getResColor(com.xw.common.R.color.gray_9))
+ .create()
+ }
+ if (it.needShowTimeoutNotice()) {
+ binding.tvTimeoutNotice.text = it.message
+ binding.llTimeoutNotice.visibility = View.VISIBLE
+ binding.llTimeoutNotice.postDelayed(Runnable {
+ if (isFinishing || isDestroyed) {
+ return@Runnable
+ }
+ binding.ivCloseTimeoutNotice.performClick()
+ }, 3000)
+ }
+ }
+ }
+ viewModel.choicePoint.observe(this) {
+ if (it == null) {
+ binding.llClickLocationInfo.visibility = View.GONE
+ binding.ivFlexing.visibility = View.VISIBLE
+ binding.tvClickLocationCheckIn.setOnClickListener(null)
+ return@observe
+ }
+ binding.llClickLocationInfo.visibility = View.VISIBLE
+ binding.ivFlexing.visibility = View.GONE
+ binding.tvClickLocationTime.text = it.time
+ binding.tvClickLocationAddress.text = it.address
+ if (it.locationId == viewModel.checkInOperationInfo.value?.checkLocationId) {
+ binding.tvClickLocationCheckIn.setBackgroundResource(R.drawable.shape_blue_5_bg_4)
+ binding.tvClickLocationCheckInNotice.visibility = View.INVISIBLE
+ } else {
+ binding.tvClickLocationCheckIn.setBackgroundResource(R.drawable.shape_gray_4_bg_4)
+ binding.tvClickLocationCheckInNotice.visibility = View.VISIBLE
+ }
+ binding.tvClickLocationCheckIn.setOnClickListener { _ ->
+ binding.llClickLocationInfo.visibility = View.GONE
+ binding.ivFlexing.visibility = View.VISIBLE
+ binding.tvClickLocationCheckIn.setOnClickListener(null)
+ viewModel.jumpToCheckInPage(it)
+ }
+ }
+ }
+
+ //刷新下一个打卡点信息
+ private fun refreshNextPointInfo() {
+ viewModel.getNextPoint()?.also {
+ binding.tvTime.text = it.time
+ binding.tvAddress.text = it.address
+ }
+ }
+
+ //刷新预计耗时和剩余距离
+ private fun refreshCostDurationDistance(path: AMapNaviPath) {
+ binding.tvDistanceCostTime.text =
+ "${Utils.getFriendlyDistance(path.allLength)} ${
+ Utils.getFriendlyTime(path.allTime)
+ }"
+ val arrivalTime = System.currentTimeMillis() + (path.allTime * 1000)
+ binding.tvEstimatedTimeOfArrival.text =
+ "${SimpleDateFormat("HH:mm").format(Date(arrivalTime))}到达"
+ }
+
+ override fun setListener() {
+ super.setListener()
+ binding.llExit.setOnClickListener {
+ CommonDialog.showTipsDialog(
+ context = this,
+ content = "是否退出导航?",
+ rightText = "确认退出",
+ rightBlock = {
+ finish()
+ return@showTipsDialog true
+ })
+ }
+ binding.llOverview.setOnClickListener {
+ viewModel.isOverview.postValue(!(viewModel.isOverview.value ?: false))
+ }
+ binding.ivFlexing.setOnClickListener {
+ if (binding.slFloatNotice.isVisible) {
+ return@setOnClickListener
+ }
+ viewModel.hadExpand.postValue(!(viewModel.hadExpand.value ?: false))
+ //binding.slFloatNotice.visibility = View.GONE
+ }
+ binding.tvFloatDelayCheckIn.setOnClickListener { _ ->
+ binding.slFloatNotice.visibility = View.GONE
+ binding.ivFlexing.performClick()
+ }
+ binding.tvFloatCheckIn.setOnClickListener { _ ->
+ binding.slFloatNotice.visibility = View.GONE
+ viewModel.getNextPoint()?.also { nextPoint ->
+ viewModel.jumpToCheckInPage(nextPoint)
+ }
+ }
+ binding.tvCheckIn.setOnClickListener {
+ viewModel.getNextPoint()?.also { nextPoint ->
+ viewModel.jumpToCheckInPage(nextPoint)
+ }
+ }
+ binding.ivCloseTimeoutNotice.setOnClickListener {
+ binding.llTimeoutNotice.animate()
+ .alpha(0f)
+ .setDuration(300) // 动画时长(毫秒)
+ .withEndAction {
+ binding.llTimeoutNotice.visibility = View.GONE // 动画结束后隐藏控件
+ binding.llTimeoutNotice.alpha = 1f
+ }
+ .start()
+ }
+ binding.llClickLocationInfoBack.setOnClickListener {
+ viewModel.choicePoint.postValue(null)
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ binding.amapView.onResume()
+ }
+
+ override fun onPause() {
+ super.onPause()
+ binding.amapView.onPause()
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ binding.amapView.onSaveInstanceState(outState)
+ }
+
+ override fun onBackPressed() {
+ //super.onBackPressed()
+ binding.llExit.performClick()
+ }
+
+ //清除地图上的路线
+ private fun clearRouteFromMap() {
+ routeOverLay?.also {
+ it.removeFromMap()
+ it.destroy()
+ }
+ routeOverLay = null
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ if (EventBus.getDefault().isRegistered(this)) {
+ EventBus.getDefault().unregister(this)
+ }
+ clearRouteFromMap()
+ carOverlay?.also {
+ it.destroy()
+ }
+ carOverlay = null
+ binding.amapView.onDestroy()
+ aMapNavi?.also {
+ it.removeAMapNaviListener(this)
+ it.removeTTSPlayListener(this)
+ it.stopNavi()
+ AMapNavi.destroy()
+ }
+ }
+
+ override fun onInitNaviFailure() {
+
+ }
+
+ override fun onInitNaviSuccess() {
+
+ }
+
+ override fun onStartNavi(p0: Int) {
+
+ }
+
+ override fun onTrafficStatusUpdate() {
+
+ }
+
+ override fun onLocationChange(p0: AMapNaviLocation?) {
+ p0?.also { location ->
+ carOverlay?.also { it ->
+ viewModel.aMapNaviLocation = location
+ val latLng = LatLng(location.coord.latitude, location.coord.longitude)
+ it.draw(binding.amapView.map, latLng, location.bearing)
+ }
+ independentCalculateRoute()
+ }
+ refreshNextPointInfo()
+ }
+
+ override fun onGetNavigationText(p0: Int, p1: String?) {
+
+ }
+
+ override fun onGetNavigationText(p0: String?) {
+
+ }
+
+ override fun onEndEmulatorNavi() {
+
+ }
+
+ override fun onArriveDestination() {
+
+ }
+
+ override fun onCalculateRouteFailure(p0: Int) {
+ Log.d(TAG, "${if (viewModel.type == 0) "步行" else "骑行"}路线计算失败,$p0")
+ ToastUtilCommon.showError("${if (viewModel.type == 0) "步行" else "骑行"}路线计算失败")
+ }
+
+ override fun onReCalculateRouteForYaw() {
+
+ }
+
+ override fun onReCalculateRouteForTrafficJam() {
+
+ }
+
+ override fun onArrivedWayPoint(p0: Int) {
+
+ }
+
+ override fun onGpsOpenStatus(p0: Boolean) {
+
+ }
+
+ override fun onNaviInfoUpdate(p0: NaviInfo?) {
+
+ }
+
+ override fun updateCameraInfo(p0: Array<out AMapNaviCameraInfo?>?) {
+
+ }
+
+ override fun updateIntervalCameraInfo(
+ p0: AMapNaviCameraInfo?,
+ p1: AMapNaviCameraInfo?,
+ p2: Int
+ ) {
+
+ }
+
+ override fun onServiceAreaUpdate(p0: Array<out AMapServiceAreaInfo?>?) {
+
+ }
+
+ override fun showCross(p0: AMapNaviCross?) {
+
+ }
+
+ override fun hideCross() {
+
+ }
+
+ override fun showModeCross(p0: AMapModelCross?) {
+
+ }
+
+ override fun hideModeCross() {
+
+ }
+
+ override fun showLaneInfo(
+ p0: Array<out AMapLaneInfo?>?,
+ p1: ByteArray?,
+ p2: ByteArray?
+ ) {
+
+ }
+
+ override fun showLaneInfo(p0: AMapLaneInfo?) {
+
+ }
+
+ override fun hideLaneInfo() {
+
+ }
+
+ override fun onCalculateRouteSuccess(p0: IntArray?) {
+
+ }
+
+ override fun notifyParallelRoad(p0: Int) {
+
+ }
+
+ override fun OnUpdateTrafficFacility(p0: Array<out AMapNaviTrafficFacilityInfo?>?) {
+
+ }
+
+ override fun OnUpdateTrafficFacility(p0: AMapNaviTrafficFacilityInfo?) {
+
+ }
+
+ override fun updateAimlessModeStatistics(p0: AimLessModeStat?) {
+
+ }
+
+ override fun updateAimlessModeCongestionInfo(p0: AimLessModeCongestionInfo?) {
+
+ }
+
+ override fun onPlayRing(p0: Int) {
+
+ }
+
+ override fun onCalculateRouteSuccess(p0: AMapCalcRouteResult?) {
+ Log.d(TAG, "${if (viewModel.type == 0) "步行" else "骑行"}路线计算成功,$p0")
+ aMapNavi?.naviPath?.takeIf {
+ !isFinishing && !isDestroyed
+ }?.also { path ->
+ clearRouteFromMap()
+ binding.amapView.map?.clear()
+ refreshCostDurationDistance(path)
+ initRouteOverlay(path)
+ initArea()
+ initMarker()
+ initCarOverlay(path)
+ // 开启导航
+ aMapNavi?.startNavi(NaviType.GPS)
+ binding.amapView.postDelayed({
+ if (isFinishing || isDestroyed) {
+ return@postDelayed
+ }
+ viewModel.isOverview.postValue(false)
+ }, 100L)
+ }
+ }
+
+ //初始化路线
+ private fun initRouteOverlay(path: AMapNaviPath) {
+ routeOverLay = RouteOverLay(binding.amapView.map, path, this).apply {
+ setTrafficLine(true)
+ setLightsVisible(false)
+ setStartPointBitmap(null)
+ setEndPointBitmap(null)
+ setWayPointBitmap(null)
+ showRouteStart(false)
+ showRouteEnd(false)
+// setPassRouteVisible(false)
+ routeOverlayOptions = RouteOverlayOptions().apply {
+ setOnRouteCameShow(false)
+ }
+ addToMap()
+ }
+ drawLeaderLines(path)
+ }
+
+ //绘制起点/终点的回拉线(人到路线起点、路线终点到建筑内终点)
+ private fun drawLeaderLines(naviPath: AMapNaviPath) {
+ binding.amapView.map?.also { aMap ->
+ leaderLines.forEach { it.remove() }
+ leaderLines.clear()
+
+ val coordList = naviPath.coordList ?: return
+ if (coordList.isEmpty()) return
+ val routeStart = LatLng(coordList.first().latitude, coordList.first().longitude)
+ val routeEnd = LatLng(coordList.last().latitude, coordList.last().longitude)
+ val lineColor = getResColor(com.xw.common.R.color.gray_6)
+
+ viewModel.startPoint?.coordinate?.also { startLatLng ->
+ if (AMapUtils.calculateLineDistance(startLatLng, routeStart) > 5) {
+ aMap.addPolyline(
+ PolylineOptions()
+ .add(startLatLng, routeStart)
+ .width(13f)
+ .color(lineColor)
+ .setDottedLine(true)
+ )?.also { leaderLines.add(it) }
+ }
+ }
+
+ viewModel.getEndPoint()?.coordinate?.also { endLatLng ->
+ if (AMapUtils.calculateLineDistance(routeEnd, endLatLng) > 5) {
+ aMap.addPolyline(
+ PolylineOptions()
+ .add(routeEnd, endLatLng)
+ .width(13f)
+ .color(lineColor)
+ .setDottedLine(true)
+ )?.also { leaderLines.add(it) }
+ }
+ }
+ }
+ }
+
+ //初始化marker
+ private fun initMarker() {
+ binding.amapView.map?.also {
+// viewModel.startPoint?.also { startPoint ->
+// it.addMarker(
+// MarkerOptions()
+// .position(
+// LatLng(
+// startPoint.coordinate.latitude,
+// startPoint.coordinate.longitude
+// )
+// )
+// .icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_start_point))
+// .anchor(0.5f, 0.5f)
+// )?.apply {
+// isClickable = true
+// `object` = startPoint
+// }
+// }
+ viewModel.getEndPoint()?.also { endPoint ->
+ it.addMarker(
+ MarkerOptions()
+ .position(
+ LatLng(
+ endPoint.coordinate.latitude,
+ endPoint.coordinate.longitude
+ )
+ )
+ .icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_end_point))
+ .anchor(0.5f, 0.5f)
+ )?.apply {
+ isClickable = true
+ `object` = endPoint
+ }
+ }
+ viewModel.getPassingPoints().forEach { point ->
+ it.addMarker(
+ MarkerOptions()
+ .position(
+ LatLng(
+ point.coordinate.latitude,
+ point.coordinate.longitude
+ )
+ )
+ .icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_pass_point))
+ .anchor(0.5f, 0.5f)
+ )?.apply {
+ isClickable = true
+ `object` = point
+ }
+ }
+ }
+ }
+
+ //初始化范围
+ private fun initArea() {
+ binding.amapView.map?.also { it ->
+ viewModel.points.value?.filter { !it.hadCheckIn() }?.forEach { point ->
+ it.addCircle(CircleOptions().apply {
+ center(
+ LatLng(
+ point.lat?.toDoubleOrNull() ?: 0.0,
+ point.lon?.toDoubleOrNull() ?: 0.0
+ )
+ )
+ radius(point.openRange?.toDoubleOrNull() ?: 0.0)
+ fillColor(R.color.color_1a026ee4.colorIdToColorValue(application))
+ strokeColor(Color.TRANSPARENT)
+ })
+ }
+ }
+ }
+
+ //初始化车标
+ private fun initCarOverlay(path: AMapNaviPath) {
+ carOverlay?.also { it ->
+ it.reset()
+ path.endPoint?.also { end ->
+ it.setEndPoi(LatLng(end.latitude, end.longitude))
+ }
+ val latLng = viewModel.aMapNaviLocation?.let {
+ NaviLatLng(it.coord.latitude, it.coord.longitude)
+ } ?: NaviLatLng(
+ viewModel.startPoint!!.coordinate.latitude,
+ viewModel.startPoint!!.coordinate.longitude
+ )
+ val rotate = NaviUtil.getRotate(latLng, path.coordList.first())
+ it.draw(binding.amapView.map, viewModel.startPoint!!.coordinate, rotate)
+ }
+ }
+
+ //POI独立算路
+ //独立路径规划是指路径规划的结果不会自动应用于当前导航,也不会干扰当前的导航
+ private fun independentCalculateRoute() {
+ viewModel.aMapNaviLocation?.takeIf {
+ (lastCalculateRouteStartLocation == null || NaviUtil.calculateDistance(
+ lastCalculateRouteStartLocation!!.coord,
+ it.coord
+ ) > 10) && viewModel.getEndPoint() != null
+ }?.also { location ->
+ aMapNavi?.also {
+ when (viewModel.type) {
+ 0, 1 -> {
+ lastCalculateRouteStartLocation = location
+ val success = it.independentCalculateRoute(
+ NaviPoi(
+ "起点",
+ LatLng(location.coord.latitude, location.coord.longitude),
+ ""
+ ),
+ viewModel.getEndPoint()!!,
+ viewModel.getPassingPoints(),
+ TravelStrategy.SINGLE.value,
+ if (viewModel.type == 0) TransportType.Walk else TransportType.Ride,
+ this
+ )
+ if (!success) {
+ Log.d(
+ TAG,
+ "${if (viewModel.type == 0) "步行" else "骑行"}独立算路失败,检查参数情况"
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+
+ override fun onCalculateRouteFailure(p0: AMapCalcRouteResult?) {
+
+ }
+
+ override fun onNaviRouteNotify(p0: AMapNaviRouteNotifyData?) {
+
+ }
+
+ override fun onGpsSignalWeak(p0: Boolean) {
+
+ }
+
+ override fun onPlayStart(p0: String?) {
+ viewModel.hadPlayTTS = true
+ }
+
+ override fun onPlayEnd(p0: String?) {
+ viewModel.hadPlayTTS = false
+ }
+
+ override fun onIndependentCalculateSuccess(p0: AMapNaviPathGroup?) {
+ Log.d(TAG, "${if (viewModel.type == 0) "步行" else "骑行"}独立算路成功${p0}")
+ p0?.takeIf {
+ it.mainPath != null && !isFinishing && !isDestroyed
+ }?.also {
+ refreshCostDurationDistance(it.mainPath)
+ clearRouteFromMap()
+ initRouteOverlay(it.mainPath)
+ }
+ }
+
+ override fun onIndependentCalculateFail(p0: AMapCalcRouteResult?) {
+ Log.d(TAG, "${if (viewModel.type == 0) "步行" else "骑行"}独立算路失败,$p0")
+ }
+
+ override fun onIndependentCalculateInvoke(p0: Int) {
+
+ }
+
+ @Suppress("unused")
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ fun onMessageEvent(event: CruiseCheckInOperationResult) {
+ if (event.cruiseCheckInRuleId != viewModel.id) {
+ return
+ }
+ viewModel.refreshPoints(event.checkLocationId, event.checkIn, event.checkInResult)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/CruiseCheckInMissionCompleteActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/CruiseCheckInMissionCompleteActivity.kt
new file mode 100644
index 0000000..a004213
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/CruiseCheckInMissionCompleteActivity.kt
@@ -0,0 +1,96 @@
+package com.xw.yunwei.ui.work.checkInMission
+
+import android.os.Bundle
+import androidx.core.os.bundleOf
+import androidx.recyclerview.widget.GridLayoutManager
+import com.xw.common.base.ShowImgListDialog
+import com.xw.common.utils.BindUtils.getResColor
+import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
+import com.xw.yunwei.R
+import com.xw.yunwei.constants.Key
+import com.xw.yunwei.databinding.ActivityCruiseCheckInMissionCompleteBinding
+import com.xw.yunwei.model.CruiseCheckInOperationResult
+import com.xw.yunwei.ui.work.checkInMission.viewmodel.CruiseCheckInMissionCompleteViewModel
+import com.xw.yunwei.ui.work.site.adapter.PictureOperationAdapter
+
+//巡游打卡任务完成页
+class CruiseCheckInMissionCompleteActivity :
+ BaseBusinessActivity<ActivityCruiseCheckInMissionCompleteBinding, CruiseCheckInMissionCompleteViewModel>() {
+ companion object {
+ //获取跳转该页面参数
+ fun getParams(result: CruiseCheckInOperationResult): Bundle {
+ return bundleOf(Key.DATA to result)
+ }
+ }
+
+ val adapter by lazy {
+ PictureOperationAdapter(couldDelete = false)
+ }
+
+ override fun getBindingVariable() = BR.viewModel
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ viewModel.model.postValue(intent.getParcelableExtra(Key.DATA))
+ }
+
+ override fun setListener() {
+ super.setListener()
+ adapter.setOnItemClickListener { _, _, i ->
+ ShowImgListDialog(
+ this,
+ adapter.data,
+ i
+ ).show()
+ }
+ }
+
+ override fun setObservable() {
+ super.setObservable()
+ viewModel.model.observe(this) { it ->
+ binding.tvTime.text = "打卡时间:${it.getShowCheckInTime()}"
+ binding.tvCheckResult.text = it.getShowCheckInStatus()
+ binding.tvCheckResult.setTextColor(
+ getResColor(
+ when (it.checkInResult) {
+ "1" -> com.xw.common.R.color.green_5
+ "2" -> com.xw.common.R.color.red_5
+ else -> com.xw.common.R.color.gray_9
+ }
+ )
+ )
+ binding.tvCheckResult.setBackgroundResource(
+ when (it.checkInResult) {
+ "1" -> R.drawable.shape_green_1_bg_2
+ "2" -> R.drawable.shape_fdedeb_bg_2
+ else -> 0
+ }
+ )
+ binding.tvWorkStatus.text = it.getShowWorkStatus()
+ binding.tvWorkStatus.setTextColor(
+ getResColor(
+ when (it.fieldSituation) {
+ "1" -> com.xw.common.R.color.green_5
+ "2" -> com.xw.common.R.color.orange_5
+ else -> com.xw.common.R.color.gray_9
+ }
+ )
+ )
+ binding.tvWorkStatus.setBackgroundResource(
+ when (it.fieldSituation) {
+ "1" -> R.drawable.shape_green_1_bg_2
+ "2" -> R.drawable.shape_orange_1_bg_2
+ else -> 0
+ }
+ )
+ binding.tvDesc.text = it.sceneDescription
+ adapter.setNewInstance(it.getUploadInfoList()?.map { it.url!! }?.toMutableList())
+ }
+ }
+
+ override fun init() {
+ super.init()
+ binding.rvList.adapter = adapter
+ binding.rvList.layoutManager = GridLayoutManager(this, 3)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/CruiseCheckInOperationActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/CruiseCheckInOperationActivity.kt
new file mode 100644
index 0000000..b32dedb
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/CruiseCheckInOperationActivity.kt
@@ -0,0 +1,145 @@
+package com.xw.yunwei.ui.work.checkInMission
+
+import android.os.Bundle
+import android.view.View
+import androidx.core.content.ContextCompat
+import androidx.core.graphics.drawable.toDrawable
+import androidx.core.os.bundleOf
+import androidx.core.widget.addTextChangedListener
+import androidx.recyclerview.widget.GridLayoutManager
+import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
+import com.xw.yunwei.R
+import com.xw.yunwei.constants.Key
+import com.xw.yunwei.databinding.ActivityCruiseCheckInOperationBinding
+import com.xw.yunwei.extension.dpToPx
+import com.xw.yunwei.extension.drawableIdToDrawable
+import com.xw.yunwei.model.CheckInMissionPointInfo
+import com.xw.yunwei.ui.work.checkInMission.viewmodel.CruiseCheckInOperationViewModel
+import com.xw.yunwei.ui.work.site.adapter.PictureOperationAdapter
+
+//巡游打卡页
+class CruiseCheckInOperationActivity :
+ BaseBusinessActivity<ActivityCruiseCheckInOperationBinding, CruiseCheckInOperationViewModel>() {
+ override fun getBindingVariable() = BR.viewModel
+
+ companion object {
+ //获取跳转此页面参数
+ fun getParams(id: String, point: CheckInMissionPointInfo, endPoint: Boolean): Bundle {
+ return bundleOf(
+ Key.ID to id,
+ Key.DATA to point,
+ Key.END_POINT to endPoint,
+ )
+ }
+ }
+
+ val adapter by lazy {
+ PictureOperationAdapter().apply {
+ addChildClickViewIds(R.id.iv_delete)
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ viewModel.id = intent.getStringExtra(Key.ID) ?: ""
+ viewModel.model.postValue(intent.getParcelableExtra(Key.DATA))
+ viewModel.isEndPoint = intent.getBooleanExtra(Key.END_POINT, false)
+ }
+
+ override fun setListener() {
+ super.setListener()
+ binding.tvWork.setOnClickListener {
+ viewModel.working.postValue(true)
+ }
+ binding.tvError.setOnClickListener {
+ viewModel.working.postValue(false)
+ }
+ binding.etInput.addTextChangedListener {
+ binding.tvNotice.visibility =
+ if ((it?.toString()?.length ?: 0) > viewModel.maxLength.value!!) {
+ View.VISIBLE
+ } else {
+ View.GONE
+ }
+ viewModel.countNotice.postValue("${it?.toString()?.length ?: 0}/${viewModel.maxLength.value!!}")
+ }
+ adapter.setOnItemClickListener { _, _, i -> viewModel.operatePicture(this, i) }
+ adapter.setOnItemChildClickListener { _, _, i -> viewModel.removePicture(i) }
+
+ binding.btnSubmit.setOnClickListener { viewModel.submit(this) }
+ }
+
+ //设置运行状态
+ private fun setWorkState() {
+ binding.tvWork.setTextColor(
+ ContextCompat.getColor(
+ this,
+ if (viewModel.working.value == true) {
+ com.xw.common.R.color.green_5
+ } else {
+ com.xw.common.R.color.gray_9
+ }
+ )
+ )
+ binding.tvWork.setBackgroundResource(
+ if (viewModel.working.value == true) {
+ R.drawable.shape_green_1_bg_4
+ } else {
+ R.drawable.shape_gray11_bg_4
+ }
+ )
+ binding.tvError.setTextColor(
+ ContextCompat.getColor(
+ this,
+ if (viewModel.working.value == false) {
+ com.xw.common.R.color.orange_5
+ } else {
+ com.xw.common.R.color.gray_9
+ }
+ )
+ )
+ binding.tvError.setBackgroundResource(
+ if (viewModel.working.value == false) {
+ R.drawable.shape_orange_1_bg_4
+ } else {
+ R.drawable.shape_gray11_bg_4
+ }
+ )
+ binding.tvLabel2.setCompoundDrawables(
+ (if (viewModel.working.value != true) com.xw.common.R.drawable.svg_must.drawableIdToDrawable(
+ this
+ ) else com.xw.common.R.color.color_transparent.drawableIdToDrawable(this))?.apply {
+ setBounds(
+ 0,
+ 0,
+ 8.dpToPx(this@CruiseCheckInOperationActivity),
+ 15.dpToPx(this@CruiseCheckInOperationActivity)
+ )
+ },
+ null,
+ null,
+ null
+ )
+ }
+
+ override fun setObservable() {
+ super.setObservable()
+ viewModel.model.observe(this) {
+ binding.tvTime.text = it.time
+ binding.tvAddress.text = it.address
+ }
+ viewModel.operationPictures.observe(this) {
+ adapter.setNewInstance(it)
+ }
+ viewModel.working.observe(this) {
+ setWorkState()
+ }
+ }
+
+ override fun init() {
+ super.init()
+ binding.rvList.adapter = adapter
+ binding.rvList.layoutManager = GridLayoutManager(this, 5)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/RoutePlanningActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/RoutePlanningActivity.kt
new file mode 100644
index 0000000..85b9e7f
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/RoutePlanningActivity.kt
@@ -0,0 +1,566 @@
+package com.xw.yunwei.ui.work.checkInMission
+
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import androidx.core.content.ContextCompat
+import androidx.core.os.bundleOf
+import com.amap.api.location.AMapLocation
+import com.amap.api.maps.AMap
+import com.amap.api.maps.AMapUtils
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.BitmapDescriptorFactory
+import com.amap.api.maps.model.LatLng
+import com.amap.api.maps.model.MarkerOptions
+import com.amap.api.maps.model.Polyline
+import com.amap.api.maps.model.PolylineOptions
+import com.amap.api.navi.AMapNavi
+import com.amap.api.navi.enums.TransportType
+import com.amap.api.navi.enums.TravelStrategy
+import com.amap.api.navi.model.AMapCalcRouteResult
+import com.amap.api.navi.model.AMapNaviPath
+import com.amap.api.navi.model.AMapTravelInfo
+import com.amap.api.navi.model.NaviPoi
+import com.amap.api.navi.model.RouteOverlayOptions
+import com.amap.api.navi.view.RouteOverLay
+import com.blankj.utilcode.util.GsonUtils
+import com.google.gson.reflect.TypeToken
+import com.xw.common.CommonDialog
+import com.xw.common.utils.GpsHelper
+import com.xw.common.utils.LogUtils
+import com.xw.common.utils.ToastUtilCommon
+import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
+import com.xw.yunwei.BuildConfig
+import com.xw.yunwei.R
+import com.xw.yunwei.constants.Key
+import com.xw.yunwei.databinding.ActivityRoutePlanningBinding
+import com.xw.yunwei.model.CheckInMissionPointInfo
+import com.xw.yunwei.model.RoutePlanningOperationInfo
+import com.xw.yunwei.ui.work.checkInMission.util.AMapNaviListenerWrap
+import com.xw.yunwei.ui.work.checkInMission.util.Utils
+import com.xw.yunwei.ui.work.checkInMission.viewmodel.RoutePlanningViewModel
+
+//路径规划页
+class RoutePlanningActivity :
+ BaseBusinessActivity<ActivityRoutePlanningBinding, RoutePlanningViewModel>(),
+ GpsHelper.OnMapLocation {
+ companion object {
+ //获取跳转此页面参数
+ fun getParams(id: String, points: List<CheckInMissionPointInfo>): Bundle {
+ return bundleOf(
+ Key.ID to id,
+ Key.POINTS to GsonUtils.toJson(points)
+ )
+ }
+ }
+
+ //导航对象
+ var aMapNavi: AMapNavi? = null
+
+ //定位工具类
+ lateinit var gpsHelper: GpsHelper
+
+ //定位点
+ var aMapLocation: AMapLocation? = null
+
+ //步行导航算路监听
+ var walkListener: AMapNaviListenerWrap? = null
+
+ //骑行导航算路监听
+ var rideListener: AMapNaviListenerWrap? = null
+
+ //路线OverLay
+ var routeOverLay: RouteOverLay? = null
+
+ //起点/终点回拉线
+ private val leaderLines = mutableListOf<Polyline>()
+
+ override fun getBindingVariable() = BR.viewModel
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ viewModel.id = intent.getStringExtra(Key.ID) ?: ""
+ viewModel.points = GsonUtils.fromJson(
+ intent.getStringExtra(Key.POINTS),
+ object : TypeToken<List<CheckInMissionPointInfo>>() {}.type
+ )
+ aMapNavi = AMapNavi.getInstance(this)
+ aMapNavi?.isNaviTravelView = true
+ binding.mapView.onCreate(savedInstanceState);// 此方法必须重写
+ binding.mapView.map?.apply {
+ isTrafficEnabled = true
+ mapType = AMap.MAP_TYPE_NAVI
+ setOnMapLoadedListener {
+ calculateRoute()
+ }
+ uiSettings.isZoomControlsEnabled = false
+ }
+ gpsHelper = GpsHelper(
+ this,
+ this,
+ isOnceLocation = true,
+ isAutomatic = true,
+ savedInstanceState = savedInstanceState
+ )
+ lifecycle.addObserver(gpsHelper)
+ gpsHelper.startLocation()
+ }
+
+ override fun setObservable() {
+ super.setObservable()
+ viewModel.naviPaths.observe(this) { it ->
+ it[0]?.also {
+ binding.tvWalkDistance.text = if (it.naviPaths.isEmpty()) "" else
+ Utils.getFriendlyDistance(it.naviPaths.first().allLength)
+ binding.tvWalkCostTime.text = if (it.naviPaths.isEmpty()) "路线计算失败" else
+ Utils.getFriendlyTime(it.naviPaths.first().allTime)
+ binding.tvWalkPoints.text = "${it.passingPoints.size}个途经点"
+ binding.tvWalkPoints.visibility =
+ if (it.passingPoints.isEmpty()) View.GONE else View.VISIBLE
+ }
+ it[1]?.also {
+ binding.tvBicycleDistance.text = if (it.naviPaths.isEmpty()) "" else
+ Utils.getFriendlyDistance(it.naviPaths.first().allLength)
+ binding.tvBicycleCostTime.text = if (it.naviPaths.isEmpty()) "路线计算失败" else
+ Utils.getFriendlyTime(it.naviPaths.first().allTime)
+ binding.tvBicyclePoints.text = "${it.passingPoints.size}个途经点"
+ binding.tvBicyclePoints.visibility =
+ if (it.passingPoints.isEmpty()) View.GONE else View.VISIBLE
+ }
+ if (it[0] != null) {
+ binding.llWalk.performClick()
+ } else {
+ if (it[1] != null) {
+ binding.llBicycle.performClick()
+ }
+ }
+ }
+ viewModel.checkWalk.observe(this) {
+ binding.llWalk.setBackgroundResource(if (it) R.drawable.shape_blue_1_bg_4 else R.drawable.shape_gray11_bg_4)
+ binding.ivWalk.setImageResource(if (it) R.mipmap.ic_walk_blue else R.mipmap.ic_walk_gray)
+ binding.tvWalkRoute.setTextColor(
+ ContextCompat.getColor(
+ this,
+ if (it) com.xw.common.R.color.blue_5 else com.xw.common.R.color.gray_9
+ )
+ )
+ binding.tvWalkCostTime.setTextColor(
+ ContextCompat.getColor(
+ this,
+ if (it) com.xw.common.R.color.blue_5 else com.xw.common.R.color.gray_9
+ )
+ )
+ binding.tvWalkDistance.setTextColor(
+ ContextCompat.getColor(
+ this,
+ if (it) com.xw.common.R.color.blue_5 else com.xw.common.R.color.gray_9
+ )
+ )
+ binding.tvWalkPoints.setTextColor(
+ ContextCompat.getColor(
+ this,
+ if (it) com.xw.common.R.color.blue_5 else com.xw.common.R.color.gray_9
+ )
+ )
+ binding.llBicycle.setBackgroundResource(if (!it) R.drawable.shape_blue_1_bg_4 else R.drawable.shape_gray11_bg_4)
+ binding.ivBicycle.setImageResource(if (!it) R.mipmap.ic_bicycle_blue else R.mipmap.ic_bicycle_gray)
+ binding.tvBicycleRoute.setTextColor(
+ ContextCompat.getColor(
+ this,
+ if (!it) com.xw.common.R.color.blue_5 else com.xw.common.R.color.gray_9
+ )
+ )
+ binding.tvBicycleCostTime.setTextColor(
+ ContextCompat.getColor(
+ this,
+ if (!it) com.xw.common.R.color.blue_5 else com.xw.common.R.color.gray_9
+ )
+ )
+ binding.tvBicycleDistance.setTextColor(
+ ContextCompat.getColor(
+ this,
+ if (!it) com.xw.common.R.color.blue_5 else com.xw.common.R.color.gray_9
+ )
+ )
+ binding.tvBicyclePoints.setTextColor(
+ ContextCompat.getColor(
+ this,
+ if (!it) com.xw.common.R.color.blue_5 else com.xw.common.R.color.gray_9
+ )
+ )
+ binding.btnPlan.setBackgroundResource(
+ if (viewModel.naviPaths.value?.get(if (it) 0 else 1)?.naviPaths?.isNotEmpty() == true) R.drawable.shape_blue_5_bg_4 else R.drawable.shape_gray_5_bg_4
+ )
+ }
+// viewModel.couldNavi.observe(this) {
+// binding.btnPlan.setBackgroundResource(
+// if (it) R.drawable.shape_blue_5_bg_4 else R.drawable.shape_gray_5_bg_4
+// )
+// }
+ }
+
+ override fun setListener() {
+ super.setListener()
+ binding.llWalk.setOnClickListener {
+ // 用 get 而非 getValue:步行路线未算出时 key 0 不存在,getValue 会抛 NoSuchElementException 导致闪退
+ viewModel.naviPaths.value?.get(0)?.also {
+ viewModel.checkWalk.postValue(true)
+ drawRoutes(it)
+ }
+ }
+ binding.llBicycle.setOnClickListener {
+ // 用 get 而非 getValue:骑行路线未算出时 key 1 不存在,getValue 会抛 NoSuchElementException 导致闪退
+ viewModel.naviPaths.value?.get(1)?.also {
+ viewModel.checkWalk.postValue(false)
+ drawRoutes(it)
+ }
+ }
+ binding.btnPlan.setOnClickListener {
+ if (!(viewModel.couldNavi.value ?: false)) {
+ ToastUtilCommon.showError("请等待路线初始化完成")
+ return@setOnClickListener
+ }
+ if (viewModel.checkWalk.value == true && viewModel.naviPaths.value?.get(0)?.naviPaths?.isNotEmpty() != true) {
+ LogUtils.d(TAG, "步行导航路线计算失败")
+ return@setOnClickListener
+ }
+ if (viewModel.checkWalk.value == false && viewModel.naviPaths.value?.get(1)?.naviPaths?.isNotEmpty() != true) {
+ LogUtils.d(TAG, "骑行导航路线计算失败")
+ return@setOnClickListener
+ }
+ if (!isNetworkAvailableLegacy()) {
+ ToastUtilCommon.showError("当前网络不佳,导航功能不可用")
+ return@setOnClickListener
+ }
+ aMapLocation?.also {
+ viewModel.navigate(NaviPoi("起点", LatLng(it.latitude, it.longitude), ""))
+ }
+ }
+ }
+
+ override fun location(pLocation: AMapLocation?) {
+ if (pLocation == null) {
+ CommonDialog.showLocationNotGrantedTipsDialog(this)
+ } else {
+ val hadNotInitLocation = aMapLocation == null
+ aMapLocation = pLocation
+ // 拿到定位后立即把地图相机移到当前位置,避免默认停留在北京(高德地图默认中心点)
+ moveCameraToCurrentLocation(pLocation)
+ if (hadNotInitLocation) {
+ calculateRoute()
+ }
+ }
+ }
+
+ //移动地图相机到当前定位位置
+ private fun moveCameraToCurrentLocation(location: AMapLocation) {
+ if (location.latitude == 0.0 && location.longitude == 0.0) return
+ // 路线尚未绘制时才移动相机,避免覆盖 drawRoutes 中 zoomToSpan 的路线视角
+ if (routeOverLay == null) {
+ binding.mapView.map?.moveCamera(
+ CameraUpdateFactory.newLatLngZoom(
+ LatLng(location.latitude, location.longitude),
+ 16f
+ )
+ )
+ }
+ }
+
+ //算路
+ private fun calculateRoute() {
+ calculateWalkRoute {
+ calculateRideRoute {
+ aMapNavi?.also {
+ it.stopNavi()
+ AMapNavi.destroy()
+ }
+ viewModel.checkWalk.postValue(true)
+ viewModel.couldNavi.postValue(true)
+ }
+ }
+ }
+
+ //步行POI算路
+ private fun calculateWalkRoute(block: () -> Unit) {
+ val routePlanningEndPoint = viewModel.getRoutePlanningEndPoint()
+ if (aMapLocation == null || routePlanningEndPoint == null) {
+ return
+ }
+ val startPoint = NaviPoi(
+ "起点",
+ LatLng(aMapLocation!!.latitude, aMapLocation!!.longitude),
+ ""
+ )
+ viewModel.startPoint = startPoint
+ val passingPoints = viewModel.getRoutePlanningPassingPoints()
+ aMapNavi?.also { it ->
+ walkListener = object : AMapNaviListenerWrap() {
+ override fun onCalculateRouteFailure(p0: AMapCalcRouteResult?) {
+ super.onCalculateRouteFailure(p0)
+ if (BuildConfig.DEBUG) {
+ p0?.errorDescription?.let {
+ ToastUtilCommon.showError(it)
+ }
+ }
+ }
+
+ override fun onCalculateRouteSuccess(p0: AMapCalcRouteResult?) {
+ it.removeAMapNaviListener(this)
+ super.onCalculateRouteSuccess(p0)
+ Log.d(TAG, "步行路线计算成功,$p0")
+ if (viewModel.naviPaths.value?.get(0) != null) {
+ return
+ }
+ it.naviPath?.also { path ->
+ val info =
+ RoutePlanningOperationInfo(0, passingPoints, routePlanningEndPoint)
+ info.naviPaths.add(path)
+ val map = viewModel.naviPaths.value ?: mutableMapOf()
+ map[0] = info
+ viewModel.naviPaths.postValue(map.toMutableMap())
+ }
+ block.invoke()
+ }
+
+ override fun onCalculateRouteFailure(p0: Int) {
+ it.removeAMapNaviListener(this)
+ super.onCalculateRouteFailure(p0)
+ Log.d(TAG, "步行路线计算失败,$p0")
+ val map = viewModel.naviPaths.value ?: mutableMapOf()
+ map[0] = RoutePlanningOperationInfo(0, passingPoints, routePlanningEndPoint)
+ viewModel.naviPaths.postValue(map.toMutableMap())
+ block.invoke()
+ }
+ }
+ it.addAMapNaviListener(walkListener)
+ it.travelInfo = AMapTravelInfo(TransportType.Walk)
+ val success = it.calculateWalkRoute(
+ startPoint,
+ passingPoints,
+ routePlanningEndPoint,
+ TravelStrategy.SINGLE
+ )
+ if (!success) {
+ Log.d(TAG, "步行路线计算失败,检查参数情况")
+ block.invoke()
+ }
+ }
+ }
+
+ //骑行(自行车)POI算路
+ private fun calculateRideRoute(block: () -> Unit) {
+ val routePlanningEndPoint = viewModel.getRoutePlanningEndPoint()
+ if (aMapLocation == null || routePlanningEndPoint == null) {
+ return
+ }
+ val startPoint = NaviPoi(
+ "起点",
+ LatLng(aMapLocation!!.latitude, aMapLocation!!.longitude),
+ ""
+ )
+ val passingPoints = viewModel.getRoutePlanningPassingPoints()
+ aMapNavi?.also { it ->
+ rideListener = object : AMapNaviListenerWrap() {
+ override fun onCalculateRouteSuccess(p0: IntArray?) {
+ it.removeAMapNaviListener(this)
+ super.onCalculateRouteSuccess(p0)
+ Log.d(TAG, "骑行路线计算成功,$p0")
+ it.naviPath?.also { path ->
+ val info =
+ RoutePlanningOperationInfo(1, passingPoints, routePlanningEndPoint)
+ info.naviPaths.add(path)
+ val map = viewModel.naviPaths.value ?: mutableMapOf()
+ map[1] = info
+ viewModel.naviPaths.postValue(map.toMutableMap())
+ }
+ block.invoke()
+ }
+
+ override fun onCalculateRouteFailure(p0: Int) {
+ it.removeAMapNaviListener(this)
+ super.onCalculateRouteFailure(p0)
+ Log.d(TAG, "骑行路线计算失败,$p0")
+ val info = RoutePlanningOperationInfo(1, passingPoints, routePlanningEndPoint)
+ val map = viewModel.naviPaths.value ?: mutableMapOf()
+ map[1] = info
+ viewModel.naviPaths.postValue(map.toMutableMap())
+ block.invoke()
+ }
+ }
+ it.travelInfo = AMapTravelInfo(TransportType.Ride)
+ it.addAMapNaviListener(rideListener)
+ val success = it.calculateRideRoute(
+ startPoint,
+ passingPoints,
+ routePlanningEndPoint,
+ TravelStrategy.SINGLE
+ )
+ if (!success) {
+ Log.d(TAG, "骑行路线计算失败,检查参数情况")
+ block.invoke()
+ }
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ binding.mapView.onResume()
+ }
+
+ override fun onPause() {
+ super.onPause()
+ binding.mapView.onPause()
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ binding.mapView.onSaveInstanceState(outState)
+ }
+
+ override fun finish() {
+ super.finish()
+ aMapNavi?.also {
+ it.removeAMapNaviListener(walkListener)
+ it.removeAMapNaviListener(rideListener)
+// it.stopNavi()
+// AMapNavi.destroy()
+ }
+ clearRouteFromMap()
+ }
+
+ //清除地图上的路线
+ private fun clearRouteFromMap() {
+ routeOverLay?.also {
+ it.removeFromMap()
+ it.destroy()
+ }
+ routeOverLay = null
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ binding.mapView.onDestroy()
+ clearRouteFromMap()
+ }
+
+ //绘制路径规划结果
+ private fun drawRoutes(routePlanningOperationInfo: RoutePlanningOperationInfo) {
+ binding.mapView.map?.also {
+ clearRouteFromMap()
+ it.moveCamera(CameraUpdateFactory.changeTilt(0f))
+ it.clear()
+ if (routePlanningOperationInfo.naviPaths.isEmpty()) {
+ return@also
+ }
+ val naviPath = routePlanningOperationInfo.naviPaths.first()
+ routeOverLay = RouteOverLay(it, naviPath, this).apply {
+ setTrafficLine(true)
+ setLightsVisible(false)
+ setStartPointBitmap(null)
+ setEndPointBitmap(null)
+ setWayPointBitmap(null)
+ routeOverlayOptions = RouteOverlayOptions().apply {
+ setOnRouteCameShow(false)
+ }
+ addToMap()
+ }
+ runOnUiThread {
+ routeOverLay?.zoomToSpan()
+ drawLeaderLines(naviPath)
+ initMarker()
+ }
+ }
+ }
+
+ //绘制起点/终点的回拉线(人到路线起点、路线终点到建筑内终点)
+ private fun drawLeaderLines(naviPath: AMapNaviPath) {
+ binding.mapView.map?.also { aMap ->
+ leaderLines.forEach { it.remove() }
+ leaderLines.clear()
+
+ val coordList = naviPath.coordList ?: return
+ if (coordList.isEmpty()) return
+ val routeStart = LatLng(coordList.first().latitude, coordList.first().longitude)
+ val routeEnd = LatLng(coordList.last().latitude, coordList.last().longitude)
+ val lineColor = ContextCompat.getColor(this, com.xw.common.R.color.gray_6)
+
+ viewModel.startPoint?.coordinate?.also { startLatLng ->
+ if (AMapUtils.calculateLineDistance(startLatLng, routeStart) > 5) {
+ aMap.addPolyline(
+ PolylineOptions()
+ .add(startLatLng, routeStart)
+ .width(13f)
+ .color(lineColor)
+ .setDottedLine(true)
+ )?.also { leaderLines.add(it) }
+ }
+ }
+
+ viewModel.getRoutePlanningEndPoint()?.coordinate?.also { endLatLng ->
+ if (AMapUtils.calculateLineDistance(routeEnd, endLatLng) > 5) {
+ aMap.addPolyline(
+ PolylineOptions()
+ .add(routeEnd, endLatLng)
+ .width(13f)
+ .color(lineColor)
+ .setDottedLine(true)
+ )?.also { leaderLines.add(it) }
+ }
+ }
+ }
+ }
+
+ //初始化marker
+ private fun initMarker() {
+ binding.mapView.map?.also {
+ viewModel.startPoint?.also { startPoint ->
+ it.addMarker(
+ MarkerOptions()
+ .position(
+ LatLng(
+ startPoint.coordinate.latitude,
+ startPoint.coordinate.longitude
+ )
+ )
+ .icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_start_point))
+ .anchor(0.5f, 0.5f)
+ )?.apply {
+ isClickable = true
+ `object` = startPoint
+ }
+ }
+ viewModel.getRoutePlanningEndPoint()?.also { endPoint ->
+ it.addMarker(
+ MarkerOptions()
+ .position(
+ LatLng(
+ endPoint.coordinate.latitude,
+ endPoint.coordinate.longitude
+ )
+ )
+ .icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_end_point))
+ .anchor(0.5f, 0.5f)
+ )?.apply {
+ isClickable = true
+ `object` = endPoint
+ }
+ }
+ viewModel.getRoutePlanningPassingPoints().forEach { point ->
+ it.addMarker(
+ MarkerOptions()
+ .position(
+ LatLng(
+ point.coordinate.latitude,
+ point.coordinate.longitude
+ )
+ )
+ .icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_pass_point))
+ .anchor(0.5f, 0.5f)
+ )?.apply {
+ isClickable = true
+ `object` = point
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/adapter/CheckInMissionPointAdapter.kt b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/adapter/CheckInMissionPointAdapter.kt
new file mode 100644
index 0000000..c8e6071
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/adapter/CheckInMissionPointAdapter.kt
@@ -0,0 +1,66 @@
+package com.xw.yunwei.ui.work.checkInMission.adapter
+
+import android.content.Context
+import android.graphics.Color
+import android.view.View
+import androidx.core.content.ContextCompat
+import com.chad.library.adapter.base.BaseQuickAdapter
+import com.chad.library.adapter.base.viewholder.BaseViewHolder
+import com.xw.yunwei.R
+import com.xw.yunwei.model.CheckInMissionPointInfo
+import com.xw.yunwei.ui.widget.LineView
+
+//巡游任务点适配器
+class CheckInMissionPointAdapter() :
+ BaseQuickAdapter<CheckInMissionPointInfo, BaseViewHolder>(R.layout.item_check_in_mission_point) {
+
+ override fun convert(
+ holder: BaseViewHolder,
+ item: CheckInMissionPointInfo
+ ) {
+ holder
+ .setText(R.id.tv_index, (holder.layoutPosition + 1).toString())
+ .setText(R.id.tv_time_range, item.time)
+ .setText(R.id.tv_status, item.getShowCheckTime())
+ .setBackgroundResource(
+ R.id.tv_status,
+ getCheckTimeBackgroundResource(item.checkInResult)
+ )
+ .setTextColor(
+ R.id.tv_status,
+ getCheckTimeTextColor(holder.itemView.context, item.checkInResult)
+ )
+ .setText(R.id.address, item.address)
+ .setBackgroundResource(
+ R.id.tv_index,
+ if (item.hadCheckIn()) R.drawable.circle_blue_5 else R.drawable.circle_gray_6
+ )
+ val lvLine = holder.getView<LineView>(R.id.lv_line)
+ lvLine.visibility = if (item == data.last()) View.INVISIBLE else View.VISIBLE
+ lvLine.dashLineEnable = item == data.last() || !data[holder.layoutPosition + 1].hadCheckIn()
+ lvLine.lineColor = ContextCompat.getColor(
+ holder.itemView.context,
+ if (item.hadCheckIn()) com.xw.common.R.color.blue_5 else com.xw.common.R.color.gray_6
+ )
+ }
+
+ private fun getCheckTimeBackgroundResource(status: String?) = status?.let {
+ when (it) {
+ "1" -> R.drawable.shape_green_1_bg_2
+ "2" -> R.drawable.shape_red_1_bg_2
+ "3" -> R.drawable.shape_orange_1_bg_2
+ else -> 0
+ }
+ } ?: 0
+
+ private fun getCheckTimeTextColor(context: Context, status: String?) = status?.let {
+ ContextCompat.getColor(
+ context, when (it) {
+ "1" -> com.xw.common.R.color.green_5
+ "2" -> com.xw.common.R.color.red_5
+ "3" -> com.xw.common.R.color.orange_5
+ else -> 0
+ }
+ )
+ } ?: Color.TRANSPARENT
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/util/AMapNaviListenerWrap.kt b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/util/AMapNaviListenerWrap.kt
new file mode 100644
index 0000000..1066fae
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/util/AMapNaviListenerWrap.kt
@@ -0,0 +1,187 @@
+package com.xw.yunwei.ui.work.checkInMission.util
+
+import android.util.Log
+import com.amap.api.navi.AMapNaviListener
+import com.amap.api.navi.model.AMapCalcRouteResult
+import com.amap.api.navi.model.AMapLaneInfo
+import com.amap.api.navi.model.AMapModelCross
+import com.amap.api.navi.model.AMapNaviCameraInfo
+import com.amap.api.navi.model.AMapNaviCross
+import com.amap.api.navi.model.AMapNaviLocation
+import com.amap.api.navi.model.AMapNaviRouteNotifyData
+import com.amap.api.navi.model.AMapNaviTrafficFacilityInfo
+import com.amap.api.navi.model.AMapServiceAreaInfo
+import com.amap.api.navi.model.AimLessModeCongestionInfo
+import com.amap.api.navi.model.AimLessModeStat
+import com.amap.api.navi.model.NaviInfo
+import com.xw.common.utils.ToastUtilCommon
+import com.xw.yunwei.BuildConfig
+
+//高德地图导航监听包裹类
+open class AMapNaviListenerWrap : AMapNaviListener {
+
+ companion object {
+ private const val TAG = "AMapNaviListenerWrap"
+ }
+
+ override fun onInitNaviFailure() {
+ Log.d(TAG, "onInitNaviFailure")
+ }
+
+ override fun onInitNaviSuccess() {
+ Log.d(TAG, "onInitNaviSuccess")
+ }
+
+ override fun onStartNavi(p0: Int) {
+ Log.d(TAG, "onStartNavi: type=$p0")
+ }
+
+ override fun onTrafficStatusUpdate() {
+ Log.d(TAG, "onTrafficStatusUpdate")
+ }
+
+ override fun onLocationChange(p0: AMapNaviLocation?) {
+ Log.d(TAG, "onLocationChange: location=$p0")
+ }
+
+ override fun onGetNavigationText(p0: Int, p1: String?) {
+ Log.d(TAG, "onGetNavigationText: type=$p0, text=$p1")
+ }
+
+ override fun onGetNavigationText(p0: String?) {
+ Log.d(TAG, "onGetNavigationText: text=$p0")
+ }
+
+ override fun onEndEmulatorNavi() {
+ Log.d(TAG, "onEndEmulatorNavi")
+ }
+
+ override fun onArriveDestination() {
+ Log.d(TAG, "onArriveDestination")
+ }
+
+ override fun onCalculateRouteFailure(p0: Int) {
+ Log.d(TAG, "onCalculateRouteFailure: errorCode=$p0")
+ }
+
+ override fun onReCalculateRouteForYaw() {
+ Log.d(TAG, "onReCalculateRouteForYaw")
+ }
+
+ override fun onReCalculateRouteForTrafficJam() {
+ Log.d(TAG, "onReCalculateRouteForTrafficJam")
+ }
+
+ override fun onArrivedWayPoint(p0: Int) {
+ Log.d(TAG, "onArrivedWayPoint: wayPointIndex=$p0")
+ }
+
+ override fun onGpsOpenStatus(p0: Boolean) {
+ Log.d(TAG, "onGpsOpenStatus: enabled=$p0")
+ }
+
+ override fun onNaviInfoUpdate(p0: NaviInfo?) {
+ Log.d(TAG, "onNaviInfoUpdate: naviInfo=$p0")
+ }
+
+ override fun updateCameraInfo(p0: Array<out AMapNaviCameraInfo?>?) {
+ Log.d(TAG, "updateCameraInfo: cameraInfoCount=${p0?.size}")
+ }
+
+ override fun updateIntervalCameraInfo(
+ p0: AMapNaviCameraInfo?,
+ p1: AMapNaviCameraInfo?,
+ p2: Int
+ ) {
+ Log.d(TAG, "updateIntervalCameraInfo: start=$p0, end=$p1, type=$p2")
+ }
+
+ override fun onServiceAreaUpdate(p0: Array<out AMapServiceAreaInfo?>?) {
+ Log.d(TAG, "onServiceAreaUpdate: serviceAreaCount=${p0?.size}")
+ }
+
+ override fun showCross(p0: AMapNaviCross?) {
+ Log.d(TAG, "showCross: cross=$p0")
+ }
+
+ override fun hideCross() {
+ Log.d(TAG, "hideCross")
+ }
+
+ override fun showModeCross(p0: AMapModelCross?) {
+ Log.d(TAG, "showModeCross: modelCross=$p0")
+ }
+
+ override fun hideModeCross() {
+ Log.d(TAG, "hideModeCross")
+ }
+
+ override fun showLaneInfo(
+ p0: Array<out AMapLaneInfo?>?,
+ p1: ByteArray?,
+ p2: ByteArray?
+ ) {
+ Log.d(TAG, "showLaneInfo: laneInfoCount=${p0?.size}")
+ }
+
+ override fun showLaneInfo(p0: AMapLaneInfo?) {
+ Log.d(TAG, "showLaneInfo: laneInfo=$p0")
+ }
+
+ override fun hideLaneInfo() {
+ Log.d(TAG, "hideLaneInfo")
+ }
+
+ override fun onCalculateRouteSuccess(p0: IntArray?) {
+ Log.d(TAG, "onCalculateRouteSuccess: routeIds=${p0?.contentToString()}")
+ }
+
+ override fun notifyParallelRoad(p0: Int) {
+ Log.d(TAG, "notifyParallelRoad: roadType=$p0")
+ }
+
+ override fun OnUpdateTrafficFacility(p0: Array<out AMapNaviTrafficFacilityInfo?>?) {
+ Log.d(TAG, "OnUpdateTrafficFacility: facilityCount=${p0?.size}")
+ }
+
+ override fun OnUpdateTrafficFacility(p0: AMapNaviTrafficFacilityInfo?) {
+ Log.d(TAG, "OnUpdateTrafficFacility: facility=$p0")
+ }
+
+ override fun updateAimlessModeStatistics(p0: AimLessModeStat?) {
+ Log.d(TAG, "updateAimlessModeStatistics: stat=$p0")
+ }
+
+ override fun updateAimlessModeCongestionInfo(p0: AimLessModeCongestionInfo?) {
+ Log.d(TAG, "updateAimlessModeCongestionInfo: congestionInfo=$p0")
+ }
+
+ override fun onPlayRing(p0: Int) {
+ Log.d(TAG, "onPlayRing: ringType=$p0")
+ }
+
+ override fun onCalculateRouteSuccess(p0: AMapCalcRouteResult?) {
+ Log.d(TAG, "onCalculateRouteSuccess: result=$p0。errorCode: ${p0?.errorCode}.")
+ }
+
+ override fun onCalculateRouteFailure(p0: AMapCalcRouteResult?) {
+ Log.d(TAG, "onCalculateRouteFailure: result=$p0。" +
+ "errorCode: ${p0?.errorCode}, " +
+ "errorDetail: ${p0?.errorDetail}, " +
+ "errorDescription: ${p0?.errorDescription}"
+ )
+ if (BuildConfig.DEBUG) {
+ p0?.errorDescription?.let { it ->
+ ToastUtilCommon.showError(it)
+ }
+ }
+ }
+
+ override fun onNaviRouteNotify(p0: AMapNaviRouteNotifyData?) {
+ Log.d(TAG, "onNaviRouteNotify: notifyData=$p0")
+ }
+
+ override fun onGpsSignalWeak(p0: Boolean) {
+ Log.d(TAG, "onGpsSignalWeak: weak=$p0")
+ }
+}
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/util/Utils.java b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/util/Utils.java
new file mode 100644
index 0000000..ca27c2d
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/util/Utils.java
@@ -0,0 +1,42 @@
+package com.xw.yunwei.ui.work.checkInMission.util;
+
+import com.amap.api.navi.model.AMapNaviPath;
+import com.amap.api.navi.model.AMapNaviStep;
+
+import java.text.DecimalFormat;
+import java.util.List;
+
+public class Utils {
+ private static DecimalFormat fnum = new DecimalFormat("##0.0");
+
+ public static String getFriendlyTime(int s) {
+ String timeDes = "";
+ int h = s / 3600;
+ if (h > 0) {
+ timeDes += h + "小时";
+ }
+ int min = (int) (s % 3600) / 60;
+ if (min > 0) {
+ timeDes += min + "分";
+ }
+ return timeDes;
+ }
+
+ public static String getFriendlyDistance(int m) {
+ float dis = m / 1000f;
+ String disDes = fnum.format(dis) + "公里";
+ return disDes;
+ }
+
+ public static int getTrafficNumber(AMapNaviPath path) {
+ int trafficLightNumber = 0;
+ if (path == null) {
+ return trafficLightNumber;
+ }
+ List<AMapNaviStep> steps = path.getSteps();
+ for (AMapNaviStep step : steps) {
+ trafficLightNumber += step.getTrafficLightNumber();
+ }
+ return trafficLightNumber;
+ }
+}
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/viewmodel/CheckInMissionPointsListViewModel.kt b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/viewmodel/CheckInMissionPointsListViewModel.kt
new file mode 100644
index 0000000..545af6c
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/viewmodel/CheckInMissionPointsListViewModel.kt
@@ -0,0 +1,82 @@
+package com.xw.yunwei.ui.work.checkInMission.viewmodel
+
+import android.app.Application
+import android.content.Context
+import android.view.View
+import androidx.lifecycle.MutableLiveData
+import com.xw.common.base.BasePagingViewModel
+import com.xw.common.utils.ToastUtilCommon
+import com.xw.yunwei.R
+import com.xw.yunwei.model.CheckInMissionPointInfo
+import com.xw.yunwei.net.WorkRepository
+import com.xw.yunwei.ui.dialog.CruiseCheckInSuccessDialog
+import com.xw.yunwei.ui.work.checkInMission.RoutePlanningActivity
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import org.koin.core.component.inject
+
+class CheckInMissionPointsListViewModel(application: Application) :
+ BasePagingViewModel(application) {
+ val workRepository: WorkRepository by inject()
+ var id: String = ""
+
+ //打卡点列表
+ val pointsList = MutableLiveData<List<CheckInMissionPointInfo>>()
+
+ var onClick = View.OnClickListener {
+ when (it.id) {
+ R.id.btn_plan -> routePlanning()
+ }
+ }
+
+ override fun getDataList(index: Int) {
+ launchRequest(showLoading = false, error = { code, msg ->
+ ToastUtilCommon.showError(msg)
+ refreshLiveData.done()
+ }) {
+ workRepository.getCheckInMissionPointsList(id)?.also {
+ pointsList.postValue(it)
+ refreshLiveData.first()
+ }
+ }
+ }
+
+ //路线规划
+ fun routePlanning(position: Int = -1) {
+ if (pointsList.value.isNullOrEmpty()) {
+ return
+ }
+ if (position in 0..<(pointsList.value?.size ?: 0)) {
+ if (pointsList.value!![position].hadCheckIn()) {
+ return
+ }
+// val list =
+// pointsList.value!!.filterIndexed { index, info -> index <= position && !info.hadCheckIn() }
+ startActivity(
+ RoutePlanningActivity::class.java,
+ RoutePlanningActivity.getParams(id, listOf(pointsList.value!![position]))
+ )
+ } else {
+ val list = pointsList.value!!.filter { !it.hadCheckIn() }
+ if (list.isEmpty()) {
+ ToastUtilCommon.showWarn("暂无未打卡点位")
+ return
+ }
+ startActivity(
+ RoutePlanningActivity::class.java,
+ RoutePlanningActivity.getParams(id, list)
+ )
+ }
+ }
+
+ //显示打卡成功弹窗
+ fun showCheckInSuccessDialog(context: Context, info: CheckInMissionPointInfo) {
+ launchRequest {
+ workRepository.getCruiseCheckInRecordInfo(id, info.locationId!!)?.also {
+ withContext(Dispatchers.Main) {
+ CruiseCheckInSuccessDialog.show(context, it, needOperation = false)
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/viewmodel/CruiseCheckInMissionCompleteViewModel.kt b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/viewmodel/CruiseCheckInMissionCompleteViewModel.kt
new file mode 100644
index 0000000..0b97171
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/viewmodel/CruiseCheckInMissionCompleteViewModel.kt
@@ -0,0 +1,17 @@
+package com.xw.yunwei.ui.work.checkInMission.viewmodel
+
+import android.app.Application
+import android.view.View
+import androidx.lifecycle.MutableLiveData
+import com.xw.common.base.BaseViewModel
+import com.xw.yunwei.R
+import com.xw.yunwei.model.CruiseCheckInOperationResult
+
+class CruiseCheckInMissionCompleteViewModel(application: Application) : BaseViewModel(application) {
+ val model = MutableLiveData<CruiseCheckInOperationResult>()
+ val onClick = View.OnClickListener {
+ when (it.id) {
+ R.id.btn_operation -> finish()
+ }
+ }
+}
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/viewmodel/CruiseCheckInOperationViewModel.kt b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/viewmodel/CruiseCheckInOperationViewModel.kt
new file mode 100644
index 0000000..3726077
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/viewmodel/CruiseCheckInOperationViewModel.kt
@@ -0,0 +1,225 @@
+package com.xw.yunwei.ui.work.checkInMission.viewmodel
+
+import android.annotation.SuppressLint
+import android.app.Application
+import android.content.Context
+import androidx.core.net.toUri
+import androidx.fragment.app.FragmentActivity
+import androidx.lifecycle.MutableLiveData
+import com.amap.location.support.util.TextUtils
+import com.blankj.utilcode.util.UriUtils
+import com.luck.picture.lib.config.PictureMimeType
+import com.luck.picture.lib.entity.LocalMedia
+import com.luck.picture.lib.interfaces.OnResultCallbackListener
+import com.xw.common.CommonDialog
+import com.xw.common.base.BaseViewModel
+import com.xw.common.base.ShowImgListDialog
+import com.xw.common.utils.ToastUtilCommon
+import com.xw.yunwei.model.CheckInMissionPointInfo
+import com.xw.yunwei.model.UploadModel
+import com.xw.yunwei.net.CommonRepository
+import com.xw.yunwei.net.WorkRepository
+import com.xw.yunwei.ui.dialog.CruiseCheckInSuccessDialog
+import com.xw.yunwei.ui.work.checkInMission.CruiseCheckInMissionCompleteActivity
+import com.xw.yunwei.utils.PictureSelectorFactory
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.MultipartBody
+import okhttp3.RequestBody.Companion.asRequestBody
+import org.greenrobot.eventbus.EventBus
+import org.koin.core.component.inject
+import java.io.File
+
+class CruiseCheckInOperationViewModel(application: Application) : BaseViewModel(application),
+ OnResultCallbackListener<LocalMedia> {
+
+ val commonRepository: CommonRepository by inject()
+ val workRepository: WorkRepository by inject()
+ var id: String = ""
+ val model = MutableLiveData<CheckInMissionPointInfo>()
+
+ //是否是最后一个点
+ var isEndPoint = false
+ val working = MutableLiveData<Boolean>(true)
+ val maxLength = MutableLiveData(200)
+ val desc = MutableLiveData("")
+ val countNotice: MutableLiveData<String> =
+ MutableLiveData("${desc.value?.length ?: 0}/${maxLength.value}")
+ val noticeLabel: MutableLiveData<String> = MutableLiveData("最多输入${maxLength.value}字")
+ val pictureMax = MutableLiveData(6)
+
+ //操作图片
+ val operationPictures: MutableLiveData<MutableList<String>> = MutableLiveData(mutableListOf(""))
+
+ //是否正在上传中
+ var isUploading = false
+
+ //添加图片
+ fun addPicture(url: String) {
+ val list = operationPictures.value ?: mutableListOf()
+ list.add(url)
+ refreshPictures(list)
+ operationPictures.postValue(list.toMutableList())
+ }
+
+ //移除图片
+ fun removePicture(position: Int) {
+ val list = operationPictures.value ?: mutableListOf()
+ list.removeAt(position)
+ refreshPictures(list)
+ operationPictures.postValue(list.toMutableList())
+ }
+
+ //刷新图片
+ fun refreshPictures(list: MutableList<String>) {
+ list.removeIf { it.isEmpty() }
+ if (list.size == pictureMax.value) {
+ return
+ }
+ list.add("")
+ }
+
+ //操作图片
+ fun operatePicture(context: Context, position: Int) {
+ val list = operationPictures.value ?: mutableListOf()
+ val element = list.elementAtOrNull(position) ?: return
+ if (element.isEmpty()) {
+ operatePictureFromDevice(context)
+ } else {
+ val backUp = list.toMutableList()
+ backUp.removeIf { it.isEmpty() }
+ ShowImgListDialog(
+ context as FragmentActivity,
+ backUp,
+ position
+ ).show()
+ }
+ }
+
+ //从设备操作图片
+ fun operatePictureFromDevice(context: Context) {
+ CommonDialog.showTypeDialog(context) {
+ if (it == 0) takeAPhotograph(context) else if (it == 1) enterGallery(context)
+ }
+ }
+
+ // 进入图库
+ @SuppressLint("SourceLockedOrientationActivity")
+ private fun enterGallery(context: Context) {
+ PictureSelectorFactory.enterGallery(
+ context,
+ (pictureMax.value ?: 1) - (operationPictures.value?.count { it.isNotEmpty() } ?: 0),
+ this)
+ }
+
+ // 拍照
+ private fun takeAPhotograph(context: Context) {
+ PictureSelectorFactory.takeAPhotograph(context, this)
+ }
+
+ override fun onResult(result: ArrayList<LocalMedia>?) {
+ result?.let { selectList ->
+ for (item in selectList) {
+ val path: String = item.availablePath
+ val imgPath =
+ if (PictureMimeType.isContent(path) && !item.isCut && !item.isCompressed) {
+ UriUtils.uri2File(path.toUri()).absolutePath
+ } else {
+ path
+ }
+ addPicture(imgPath)
+ }
+ }
+ }
+
+ override fun onCancel() {
+
+ }
+
+ private fun uploadFile(files: MutableList<Pair<String, UploadModel?>>, succ: () -> Unit) {
+ val result = files.find { it.second == null }
+ if (result == null) {
+ succ()
+ } else {
+ launchRequest(showLoading = false, error = { _, errMsg ->
+ ToastUtilCommon.showError(errMsg)
+ dismissDialog()
+ isUploading = false
+ }) {
+ val file = File(result.first)
+ val fileRequestBody = file.asRequestBody("image/jpg".toMediaType())
+ val mBuilder = MultipartBody.Builder()
+ mBuilder.addFormDataPart("file", file.name, fileRequestBody)
+ mBuilder.setType(MultipartBody.FORM)
+ val data = commonRepository.uploadFile(mBuilder.build())
+ files[files.indexOf(result)] = result.first to data
+ uploadFile(files, succ)
+ }
+ }
+ }
+
+ //提交
+ fun submit(context: Context) {
+ if (model.value == null) {
+ return
+ }
+ if (working.value == null) {
+ ToastUtilCommon.showError("请选择现场情况")
+ return
+ }
+ if (TextUtils.isEmpty(desc.value) && working.value != true) {
+ ToastUtilCommon.showError("请输入现场情况描述")
+ return
+ }
+ if ((desc.value?.length ?: 0) > maxLength.value!!) {
+ ToastUtilCommon.showError(noticeLabel.value)
+ return
+ }
+ val list = operationPictures.value ?: mutableListOf()
+ list.removeIf { it.isEmpty() }
+ if (list.count { !it.startsWith("http") } > 0) {
+ val result = list.map { Pair<String, UploadModel?>(it, null) }.toMutableList()
+ uploadFile(result) {
+ result.removeIf { it.second == null }
+ submit(context, result.map { it.second!! }.toMutableList())
+ }
+ return
+ }
+ submit(context, mutableListOf())
+ }
+
+ //提交
+ private fun submit(context: Context, urls: MutableList<UploadModel>) {
+ launchRequest {
+ workRepository.saveCruiseCheckInRecord(
+ model.value!!.locationId!!,
+ working.value!!,
+ desc.value ?: "",
+ urls
+ )?.also { it ->
+ val list = workRepository.getCheckInMissionPointsList(id)
+ if (list == null || list.count { !it.hadCheckIn() } > 0) {
+ withContext(Dispatchers.Main) {
+ CruiseCheckInSuccessDialog.show(
+ context = context, result = it,
+ operationLabel = if (isEndPoint) "前往打卡列表页" else "前往下一个点位"
+ ).apply {
+ setOnDismissListener { _ ->
+ EventBus.getDefault().post(it)
+ finish()
+ }
+ }
+ }
+ return@also
+ }
+ EventBus.getDefault().post(it)
+ startActivity(
+ CruiseCheckInMissionCompleteActivity::class.java,
+ CruiseCheckInMissionCompleteActivity.getParams(it)
+ )
+ finish()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/viewmodel/CruiseCheckInViewModel.kt b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/viewmodel/CruiseCheckInViewModel.kt
new file mode 100644
index 0000000..58c9ba6
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/viewmodel/CruiseCheckInViewModel.kt
@@ -0,0 +1,146 @@
+package com.xw.yunwei.ui.work.checkInMission.viewmodel
+
+import android.app.Application
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.viewModelScope
+import com.amap.api.maps.model.LatLng
+import com.amap.api.navi.model.AMapNaviLocation
+import com.amap.api.navi.model.NaviPoi
+import com.xw.common.base.BaseViewModel
+import com.xw.yunwei.model.CheckInMissionPointInfo
+import com.xw.yunwei.model.CruiseCheckInOperationInfo
+import com.xw.yunwei.net.WorkRepository
+import com.xw.yunwei.ui.work.checkInMission.CruiseCheckInOperationActivity
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import org.koin.core.component.inject
+
+class CruiseCheckInViewModel(application: Application) : BaseViewModel(application) {
+ val workRepository: WorkRepository by inject()
+ var id: String = ""
+ var points = MutableLiveData(listOf<CheckInMissionPointInfo>())
+ var startPoint: NaviPoi? = null
+ var type: Int = 0
+
+ //是否需要算路
+ var needCalculateRoute = MutableLiveData(false)
+
+ //是否在播放语音
+ var hadPlayTTS = false;
+
+ //是否全览
+ val isOverview = MutableLiveData(false)
+
+ //是否展开
+ val hadExpand = MutableLiveData(false)
+
+ //是否能够打卡
+ val couldCheckIn = MutableLiveData(false)
+
+ //高德导航定位
+ var aMapNaviLocation: AMapNaviLocation? = null
+
+ //操作打卡信息
+ val checkInOperationInfo = MutableLiveData<CruiseCheckInOperationInfo>()
+
+ //记录是否弹窗显示打卡
+ val showCheckInNoticeHistory = mutableListOf<String>()
+
+ //选中点
+ val choicePoint = MutableLiveData<CheckInMissionPointInfo>()
+
+ //获取路径规划终点
+ fun getEndPoint(): NaviPoi? {
+ return points.value?.lastOrNull { !it.hadCheckIn() }?.let {
+ NaviPoi(
+ "终点",
+ LatLng(it.lat?.toDoubleOrNull() ?: 0.0, it.lon?.toDoubleOrNull() ?: 0.0),
+ ""
+ )
+ }?.takeIf {
+ it.coordinate.latitude != 0.0 && it.coordinate.longitude != 0.0
+ }
+ }
+
+ //获取路径规划途经点
+ fun getPassingPoints(): List<NaviPoi> {
+ val endPoint = getEndPoint()
+ return points.value?.filter { !it.hadCheckIn() }?.mapIndexed { index, info ->
+ NaviPoi(
+ "途经点${index + 1}",
+ LatLng(info.lat?.toDoubleOrNull() ?: 0.0, info.lon?.toDoubleOrNull() ?: 0.0),
+ ""
+ )
+ }?.filter {
+ it.coordinate.latitude != 0.0 && it.coordinate.longitude != 0.0 && it.coordinate != endPoint?.coordinate
+ } ?: emptyList()
+ }
+
+ //获取下一个点
+ fun getNextPoint(): CheckInMissionPointInfo? {
+ return points.value?.find {
+ if (checkInOperationInfo.value?.needShowCheckInNotice() == true) {
+ if (it.hadCheckIn()) {
+ return@find false
+ }
+ it.locationId == checkInOperationInfo.value?.checkLocationId
+ } else !it.hadCheckIn()
+ }
+ }
+
+ //检测超时
+ fun checkOutTimeOut() {
+ viewModelScope.launch {
+ while (true) {
+ delay(5000)
+ aMapNaviLocation?.also { it ->
+ launchRequest(showLoading = false, error = { _, _ -> }) {
+ workRepository.uploadRealTimePosition(
+ id,
+ it.coord.latitude,
+ it.coord.longitude
+ )
+ ?.also { it ->
+ points.value?.filter { point -> point.locationId == it.checkLocationId && !point.hadCheckIn() }
+ ?.takeIf { it.isNotEmpty() }
+ .also { _ -> checkInOperationInfo.postValue(it) }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //跳转打卡页
+ fun jumpToCheckInPage(info: CheckInMissionPointInfo) {
+ startActivity(
+ CruiseCheckInOperationActivity::class.java,
+ CruiseCheckInOperationActivity.getParams(id, info, info == points.value?.lastOrNull())
+ )
+ }
+
+ //刷新点
+ fun refreshPoints(locationId: String?, checkIn: String?, checkInResult: String?) {
+ points.value?.find { it.locationId == locationId }?.apply {
+ this.checkIn = checkIn
+ this.checkInResult = checkInResult
+ }
+ if (checkInOperationInfo.value?.checkLocationId == locationId) {
+ checkInOperationInfo.postValue(CruiseCheckInOperationInfo())
+ }
+ val endPoint = getEndPoint()
+ if (endPoint == null) {
+ finish()
+ } else {
+ points.postValue((points.value ?: mutableListOf()).toMutableList())
+ aMapNaviLocation?.also {
+ startPoint = NaviPoi(
+ "起点",
+ LatLng(it.coord.latitude, it.coord.longitude),
+ ""
+ )
+ }
+ needCalculateRoute.postValue(true)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/viewmodel/RoutePlanningViewModel.kt b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/viewmodel/RoutePlanningViewModel.kt
new file mode 100644
index 0000000..2aa0433
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/checkInMission/viewmodel/RoutePlanningViewModel.kt
@@ -0,0 +1,74 @@
+package com.xw.yunwei.ui.work.checkInMission.viewmodel
+
+import android.app.Application
+import androidx.lifecycle.MutableLiveData
+import com.amap.api.maps.model.LatLng
+import com.amap.api.navi.model.NaviPoi
+import com.xw.common.base.BaseViewModel
+import com.xw.yunwei.model.CheckInMissionPointInfo
+import com.xw.yunwei.model.RoutePlanningOperationInfo
+import com.xw.yunwei.net.WorkRepository
+import com.xw.yunwei.ui.work.checkInMission.CruiseCheckInActivity
+import org.koin.core.component.inject
+
+class RoutePlanningViewModel(application: Application) : BaseViewModel(application) {
+ val workRepository: WorkRepository by inject()
+ var id: String = ""
+ var points: List<CheckInMissionPointInfo> = listOf()
+
+ //起点
+ var startPoint: NaviPoi? = null
+
+ //是否选中步行
+ var checkWalk = MutableLiveData(true)
+
+ //算好的路线
+ val naviPaths = MutableLiveData(mutableMapOf<Int, RoutePlanningOperationInfo>())
+
+ //是否能导航
+ val couldNavi = MutableLiveData(false)
+
+ //获取路径规划终点
+ fun getRoutePlanningEndPoint(): NaviPoi? {
+ return points.lastOrNull { !it.hadCheckIn() }?.let {
+ NaviPoi(
+ "终点",
+ LatLng(it.lat?.toDoubleOrNull() ?: 0.0, it.lon?.toDoubleOrNull() ?: 0.0),
+ ""
+ )
+ }?.takeIf {
+ it.coordinate.latitude != 0.0 && it.coordinate.longitude != 0.0
+ }
+ }
+
+ //获取路径规划途经点
+ fun getRoutePlanningPassingPoints(): List<NaviPoi> {
+ val endPoint = getRoutePlanningEndPoint()
+ return points.filter { !it.hadCheckIn() }.mapIndexed { index, info ->
+ NaviPoi(
+ "途经点${index + 1}",
+ LatLng(info.lat?.toDoubleOrNull() ?: 0.0, info.lon?.toDoubleOrNull() ?: 0.0),
+ ""
+ )
+ }.filter {
+ it.coordinate.latitude != 0.0 && it.coordinate.longitude != 0.0 && it.coordinate != endPoint?.coordinate
+ }
+ }
+
+ //导航
+ fun navigate(startPoint: NaviPoi) {
+ // 用 get 而非 getValue:对应出行方式路线未算出时 key 不存在,getValue 会抛 NoSuchElementException
+ naviPaths.value?.get(if (checkWalk.value ?: false) 0 else 1)?.let {
+ startActivity(
+ CruiseCheckInActivity::class.java,
+ CruiseCheckInActivity.getParams(
+ id,
+ points,
+ startPoint,
+ it.type
+ )
+ )
+ finish()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/notice/NoticeActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/notice/NoticeActivity.kt
index 13107c4..6af9eaf 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/notice/NoticeActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/notice/NoticeActivity.kt
@@ -1,20 +1,18 @@
package com.xw.yunwei.ui.work.notice
import androidx.recyclerview.widget.LinearLayoutManager
-import com.xw.common.base.BaseActivity
import com.xw.common.base.OnItemClickListener
import com.xw.common.base.fastObserve
-import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.databinding.ActivityNoticeBinding
import com.xw.yunwei.model.NoticeModel
import com.xw.yunwei.push.MessageHandler.handlePushEvent
-import org.json.JSONObject
/**
* 消息通知
*/
-class NoticeActivity : BaseActivity<ActivityNoticeBinding, NoticeVM>(), OnItemClickListener<NoticeModel> {
+class NoticeActivity : BaseBusinessActivity<ActivityNoticeBinding, NoticeVM>(), OnItemClickListener<NoticeModel> {
override fun getBindingVariable() = BR.viewModel
val adapter by lazy { NoticeAdapter(this).apply { setHasStableIds(true) } }
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/site/SiteAdapter.kt b/app/src/main/java/com/xw/yunwei/ui/work/site/SiteAdapter.kt
index 9b61381..7b357e0 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/site/SiteAdapter.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/site/SiteAdapter.kt
@@ -1,25 +1,25 @@
package com.xw.yunwei.ui.work.site
import android.annotation.SuppressLint
-import android.view.LayoutInflater
+import android.view.View
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.FragmentActivity
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
-import com.xw.common.base.OnItemClickListener
import com.xw.common.base.OneItemElementClickListener
-import com.xw.common.databinding.ItemTextBinding
import com.xw.common.utils.BindUtils.getResColor
import com.xw.common.utils.BindUtils.getUrl
-import com.xw.common.viewAdapter.ImageDefault
-import com.xw.common.viewAdapter.ViewAdapter
+import com.xw.common.utils.GlideEngine
import com.xw.yunwei.R
import com.xw.yunwei.databinding.ItemWorkSiteBinding
-import com.xw.yunwei.model.CarModel
import com.xw.yunwei.model.SiteModel
+import com.xw.yunwei.model.sitePlaceHolder
import org.json.JSONArray
-class SiteAdapter(val activity: FragmentActivity, var listener: OneItemElementClickListener<SiteModel>) :
+class SiteAdapter(
+ val activity: FragmentActivity,
+ var listener: OneItemElementClickListener<SiteModel>
+) :
BaseQuickAdapter<SiteModel, BaseViewHolder>(R.layout.item_work_site) {
var selectItem: SiteModel? = null
@@ -32,8 +32,14 @@
override fun convert(holder: BaseViewHolder, item: SiteModel) {
val binding: ItemWorkSiteBinding? = DataBindingUtil.bind(holder.itemView)
binding?.let {
- it.root.setOnClickListener { listener.onItemClick(item) }
+ it.parent.visibility = if (item == sitePlaceHolder) View.GONE else View.VISIBLE
+ it.tips.visibility = if (item == sitePlaceHolder) View.VISIBLE else View.GONE
+ if (item == sitePlaceHolder) {
+ return
+ }
+ it.parent.setOnClickListener { listener.onItemClick(item) }
it.nav.setOnClickListener { listener.oneItemElementClick(item) }
+ // 与 @苏清禾 确认,选择的样式恢复回来
if (item == selectItem) {
it.parent.setBackgroundColor(getResColor(com.xw.common.R.color.gray_3))
} else {
@@ -46,8 +52,11 @@
var url = ""
try {
url = JSONArray(item.pointPictures).get(0).toString().getUrl()
- } catch (e: Exception) { }
- ViewAdapter.loadImage(binding.icon, ImageDefault(url, R.mipmap.img_site_bg))
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ GlideEngine.createGlideEngine()
+ .load(binding.icon, url, R.drawable.img_site_bg, R.drawable.img_site_bg, 5f)
// 接口未返回
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/site/SiteErrorUploadActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/site/SiteErrorUploadActivity.kt
new file mode 100644
index 0000000..3d1c9c0
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/site/SiteErrorUploadActivity.kt
@@ -0,0 +1,132 @@
+package com.xw.yunwei.ui.work.site
+
+import android.os.Bundle
+import android.view.View
+import androidx.core.content.ContextCompat
+import androidx.core.os.bundleOf
+import androidx.core.widget.addTextChangedListener
+import androidx.recyclerview.widget.GridLayoutManager
+import com.xw.common.utils.BindUtils.getUrl
+import com.xw.common.utils.GlideEngine
+import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
+import com.xw.yunwei.R
+import com.xw.yunwei.constants.Key
+import com.xw.yunwei.databinding.ActivitySiteErrorUploadBinding
+import com.xw.yunwei.extension.setOnDurationClickListener
+import com.xw.yunwei.model.SiteModel
+import com.xw.yunwei.ui.work.site.adapter.PictureOperationAdapter
+import com.xw.yunwei.ui.work.site.viewmodel.SiteErrorUploadVM
+import org.json.JSONArray
+
+class SiteErrorUploadActivity :
+ BaseBusinessActivity<ActivitySiteErrorUploadBinding, SiteErrorUploadVM>() {
+ companion object {
+ //获取跳转该页面参数
+ fun getParams(model: SiteModel): Bundle {
+ return bundleOf(Key.DATA to model)
+ }
+ }
+
+ val adapter by lazy {
+ PictureOperationAdapter().apply {
+ addChildClickViewIds(R.id.iv_delete)
+ }
+ }
+
+ override fun getBindingVariable() = BR.viewModel
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ viewModel.model.postValue(intent.getParcelableExtra(Key.DATA))
+ }
+
+ override fun setListener() {
+ super.setListener()
+ binding.tvWork.setOnClickListener {
+ viewModel.working.postValue(true)
+ }
+ binding.tvError.setOnClickListener {
+ viewModel.working.postValue(false)
+ }
+ binding.etInput.addTextChangedListener {
+ binding.tvNotice.visibility =
+ if ((it?.toString()?.length ?: 0) > viewModel.maxLength.value!!) {
+ View.VISIBLE
+ } else {
+ View.GONE
+ }
+ viewModel.countNotice.postValue("${it?.toString()?.length ?: 0}/${viewModel.maxLength.value!!}")
+ }
+ adapter.setOnItemClickListener { _, _, i -> viewModel.operatePicture(this, i) }
+ adapter.setOnItemChildClickListener { _, _, i -> viewModel.removePicture(i) }
+
+ binding.btnErrorUpload.setOnDurationClickListener { viewModel.submit() }
+ }
+
+ //设置运行状态
+ private fun setWorkState() {
+ binding.tvWork.setTextColor(
+ ContextCompat.getColor(
+ this,
+ if (viewModel.working.value == true) {
+ com.xw.common.R.color.green_5
+ } else {
+ com.xw.common.R.color.gray_9
+ }
+ )
+ )
+ binding.tvWork.setBackgroundResource(
+ if (viewModel.working.value == true) {
+ R.drawable.shape_green_1_bg_4
+ } else {
+ R.drawable.shape_gray11_bg_4
+ }
+ )
+ binding.tvError.setTextColor(
+ ContextCompat.getColor(
+ this,
+ if (viewModel.working.value == false) {
+ com.xw.common.R.color.orange_5
+ } else {
+ com.xw.common.R.color.gray_9
+ }
+ )
+ )
+ binding.tvError.setBackgroundResource(
+ if (viewModel.working.value == false) {
+ R.drawable.shape_orange_1_bg_4
+ } else {
+ R.drawable.shape_gray11_bg_4
+ }
+ )
+ }
+
+ override fun setObservable() {
+ super.setObservable()
+ viewModel.model.observe(this) {
+ var url = ""
+ try {
+ url = JSONArray(it.pointPictures).get(0).toString().getUrl()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ GlideEngine.createGlideEngine()
+ .load(binding.ivPicture, url, R.drawable.img_site_bg, R.drawable.img_site_bg, 4f)
+ }
+ binding.tvTitle.text = it.pointName
+ binding.tvDetail.text = it.pointAddress
+ }
+ viewModel.operationPictures.observe(this) {
+ adapter.setNewInstance(it)
+ }
+ viewModel.working.observe(this) {
+ setWorkState()
+ }
+ }
+
+ override fun init() {
+ super.init()
+ binding.rvList.adapter = adapter
+ binding.rvList.layoutManager = GridLayoutManager(this, 5)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/site/SiteNavActivity.kt b/app/src/main/java/com/xw/yunwei/ui/work/site/SiteNavActivity.kt
index 21bd6ec..e4dc859 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/site/SiteNavActivity.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/site/SiteNavActivity.kt
@@ -1,6 +1,6 @@
package com.xw.yunwei.ui.work.site
-import com.xw.common.utils.LogUtils
+import android.os.Bundle
import android.view.Gravity
import android.view.KeyEvent
import android.view.View
@@ -10,34 +10,37 @@
import android.widget.LinearLayout
import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil
-import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.customview.customView
import com.afollestad.materialdialogs.customview.getCustomView
import com.amap.api.maps.model.LatLng
+import com.blankj.utilcode.util.BarUtils
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.xw.common.CommonDialog
import com.xw.common.R
-import com.xw.common.base.BaseActivity
-import com.xw.common.base.OnItemClickListener
import com.xw.common.base.OneItemElementClickListener
import com.xw.common.utils.BindUtils
import com.xw.common.utils.BindUtils.getUrl
+import com.xw.common.utils.GlideEngine
import com.xw.common.utils.GpsHelper.Companion.navigate
import com.xw.common.utils.ToastUtilCommon
-import com.xw.common.viewAdapter.ImageDefault
-import com.xw.common.viewAdapter.ViewAdapter
import com.xw.common.viewAdapter.ViewAdapter.Companion.showAnim
import com.xw.yunwei.BR
+import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.databinding.ActivitySiteNavBinding
import com.xw.yunwei.databinding.DialogSiteFilterBinding
+import com.xw.yunwei.extension.colorIdToColorValue
+import com.xw.yunwei.extension.dpToPx
+import com.xw.yunwei.extension.drawableIdToDrawable
+import com.xw.yunwei.extension.hideKeyboardAndClearFocus
import com.xw.yunwei.model.SiteModel
+import com.xw.yunwei.model.sitePlaceHolder
import com.xw.yunwei.ui.work.AMapFragment
-import kotlinx.coroutines.launch
+import com.xw.yunwei.utils.DialogFactory
import org.json.JSONArray
-class SiteNavActivity : BaseActivity<ActivitySiteNavBinding, SiteNavVM>(),
+class SiteNavActivity : BaseBusinessActivity<ActivitySiteNavBinding, SiteNavVM>(),
OneItemElementClickListener<SiteModel> {
override fun getBindingVariable() = BR.viewModel
@@ -47,6 +50,7 @@
}
}
private var filterDialog: MaterialDialog? = null
+ private var pendingMarkerId: String? = null
val mapFrag: AMapFragment by lazy { AMapFragment() }
private val bottomSheetBehavior: BottomSheetBehavior<LinearLayout> by lazy {
@@ -55,20 +59,56 @@
)
}
+ // 设置底部导航栏的沉浸式 --------- START ---------
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ BarUtils.transparentNavBar(this)
+ BarUtils.setNavBarLightMode(this, true)
+ }
+
+ override fun onApplyNavigationBarInsets(view: View, bottomInset: Int) {
+ // view.updatePadding(bottom = bottomInset)
+ }
+ // 设置底部导航栏的沉浸式 --------- OVER ---------
+
override fun init() {
super.init()
showDialog("定位中...")
val transaction = supportFragmentManager.beginTransaction()
transaction.add(com.xw.yunwei.R.id.map_container, mapFrag)
transaction.commit()
+ // halfExpandedRatio=0.58 → visible map area is top 42% of screen; midpoint = 0.21
+ mapFrag.initialLocationScreenYRatio = 0.55f
initAdapter()
setBehavior()
// viewModel.query()
+ refreshFilterStatus()
+ }
+
+ //刷新筛选状态
+ private fun refreshFilterStatus() {
+ binding.filter.setTextColor(
+ (if (viewModel.hadFilter()) R.color.blue_5 else R.color.gray_9).colorIdToColorValue(
+ this
+ )
+ )
+ binding.filter.setCompoundDrawables(
+ null,
+ null,
+ (if (viewModel.hadFilter()) R.drawable.svg_filter2 else R.drawable.svg_filter).drawableIdToDrawable(
+ this
+ )?.apply {
+ setBounds(
+ 0, 0, 12.dpToPx(this@SiteNavActivity), 12.dpToPx(this@SiteNavActivity)
+ )
+ },
+ null
+ )
}
override fun setObservable() {
super.setObservable()
- viewModel.dataList.observe(this) {
+ viewModel.dataList.observe(this) { it ->
// if (it.isEmpty()) ToastUtilCommon.showWarn("未找到对应点位信息")
adapter.setList(it)
if (it.isEmpty() && !adapter.hasEmptyView()) {
@@ -80,7 +120,7 @@
)
}
mapFrag.clearMarks()
- it.forEach {
+ it.filter { it!= sitePlaceHolder }.forEach {
val resId =
if (it.operationStatus !in arrayOf(3, 4)) com.xw.yunwei.R.mipmap.ic_map_site_g
else com.xw.yunwei.R.mipmap.ic_map_site_r
@@ -88,8 +128,19 @@
LatLng(it.pointLat ?: 0.0, it.pointLon ?: 0.0),
resId,
"${it.id}",
- it.pointName
+ it.pointName,
+ 0.65f
)
+ }
+ pendingMarkerId?.let { id ->
+ it.find { item -> "${item.id}" == id }?.let { selected ->
+ adapter.selectItem = selected
+ animateMapTo(selected.pointLat ?: 0.0, selected.pointLon ?: 0.0)
+ mapFrag.findMarkerById("${selected.id ?: ""}")?.let { marker ->
+ mapFrag.clickMarker(marker)
+ }
+ }
+ pendingMarkerId = null
}
}
viewModel.siteItem.observe(this) { setPointInfo() }
@@ -104,7 +155,7 @@
areas.add(area)
}
}
- if(areas.isNotEmpty()){
+ if (areas.isNotEmpty()) {
mapFrag.drawPolygon(areas)
}
}
@@ -119,7 +170,8 @@
// if (viewModel.search.value.isNullOrEmpty()) {
// ToastUtilCommon.show("请输入搜索内容")
// } else {
- viewModel.query()
+ viewModel.query()
+ hideKeyboardAndClearFocus()
// }
}
false
@@ -132,15 +184,19 @@
}
}
binding.arrow.setOnClickListener { toggleBottomSheetState() }
- binding.location.setOnClickListener { mapFrag.moveToLocation() }
+ binding.location.setOnClickListener {
+ // mapFrag.moveToLocation()
+ mapFrag.getLocation()?.let { it ->
+ mapFrag.setCurrentZoom(16f)
+ mapFrag.animateTo(it.latitude, it.longitude, targetScreenYRatio = 0.55f)
+ } ?: run { ToastUtilCommon.showWarn("未获取到定位信息") }
+ }
mapFrag.locationChangeCallback = { location ->
dismissDialog()
if (location == null) {
- CommonDialog.showTipsDialog(
- this@SiteNavActivity,
- "您未开启gps权限,无法获取当前定位,请打开后重新操作",
- null)
+ CommonDialog.showLocationNotGrantedTipsDialog(this@SiteNavActivity)
} else {
+ // TODO ... FATAL BUG: 当服务不可用,isNullOrEmpty永远为true时,这里会被1秒调一次去请求
if (viewModel.fences.value.isNullOrEmpty()) {
viewModel.cityCode = location.adCode.substring(0, 4) + "00"
viewModel.getFenceByCode()
@@ -150,9 +206,21 @@
}
mapFrag.markerClickCallback = { id ->
adapter.data.find { "${it.id}" == id }?.let {
+ /*
adapter.remove(it)
adapter.addData(0, it)
adapter.selectItem = it
+ */
+ pendingMarkerId = id
+ viewModel.query(it.pointLat, it.pointLon)
+ }
+ }
+ binding.btnErrorUpload.setOnClickListener {
+ viewModel.siteItem.value?.let {
+ startActivity(
+ SiteErrorUploadActivity::class.java,
+ SiteErrorUploadActivity.getParams(it)
+ )
}
}
}
@@ -165,10 +233,6 @@
isHideable = false
skipCollapsed = false // 允许进入折叠状态
halfExpandedRatio = 0.58f
-
- // 展开时距离顶部距离(留出状态栏和搜索区域)
- // expandedOffset = resources.getDimensionPixelSize(R.dimen.dp_50)
- expandedOffset = 0 // 顶部有定位图标占位 暂不需要设置
addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
@@ -185,9 +249,7 @@
if (!binding.arrow.isVisible) {
showAnim(binding.arrow, true)
}
- if (binding.title1.isVisible) {
- showAnim(binding.title1, false)
- }
+
binding.location.visibility = View.VISIBLE
arrow(0f)
}
@@ -197,9 +259,7 @@
if (!binding.arrow.isVisible) {
showAnim(binding.arrow, true)
}
- if (binding.title1.isVisible) {
- showAnim(binding.title1, false)
- }
+
binding.location.visibility = View.VISIBLE
arrow(180f)
}
@@ -207,6 +267,7 @@
else -> {}
}
}
+ updateLocationIconY(bottomSheet)
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {
@@ -218,8 +279,12 @@
// binding.arrow.rotation = 360f * (0.5f - slideOffset)
// }
// }
+ updateLocationIconY(bottomSheet)
}
})
+
+ // 初始位置:等布局完成后更新 location 按钮
+ binding.bottomSheet.post { updateLocationIconY(binding.bottomSheet) }
}
}
@@ -246,6 +311,14 @@
.start()
}
+ private fun updateLocationIconY(bottomSheet: View) {
+ val coordinator = bottomSheet.parent as? View ?: return
+ val sheetTop = bottomSheet.top + coordinator.top
+ val locHeight = binding.location.height
+ if (locHeight == 0) return
+ val marginBottom = resources.getDimensionPixelSize(R.dimen.dp_12)
+ binding.location.y = (sheetTop - locHeight - marginBottom).toFloat()
+ }
private fun initAdapter() {
binding.siteRv.adapter = adapter
@@ -254,7 +327,7 @@
private fun showFilterDialog() {
if (filterDialog == null) {
- filterDialog = MaterialDialog(this).apply {
+ filterDialog = DialogFactory.produce(this).apply {
customView(
com.xw.yunwei.R.layout.dialog_site_filter,
noVerticalPadding = true,
@@ -306,15 +379,19 @@
}
bind.btnRight.setOnClickListener {
viewModel.query()
+ refreshFilterStatus()
dismiss()
}
}
}
+ filterDialog?.setOnDismissListener { binding.filterOverlay.visibility = View.GONE }
}
filterDialog?.show()
+ binding.filterOverlay.visibility = View.VISIBLE
// 关键:让软键盘把 BottomSheet 顶上去
filterDialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
+ filterDialog?.window?.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
filterDialog?.window?.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
@@ -326,7 +403,7 @@
}
override fun onItemClick(item: SiteModel) {
- viewModel.siteItem.value = item
+ viewModel.siteItem.postValue(item)
}
override fun oneItemElementClick(item: SiteModel) {
@@ -342,17 +419,21 @@
binding.name.text = item.pointName
binding.address.text = item.pointAddress
binding.remark.text = item.remarks
- binding.remark.isVisible = !item.remarks.isNullOrEmpty()
+ binding.remark.visibility = if(!item.remarks.isNullOrEmpty()) View.VISIBLE else View.INVISIBLE
var url = ""
try {
url = JSONArray(item.pointPictures).get(0).toString().getUrl()
} catch (e: Exception) {
+ e.printStackTrace()
}
- ViewAdapter.loadImage(
- binding.icon,
- ImageDefault(url, com.xw.yunwei.R.mipmap.img_site_bg)
- )
-
+ GlideEngine.createGlideEngine()
+ .load(
+ binding.icon,
+ url,
+ com.xw.yunwei.R.drawable.img_site_bg,
+ com.xw.yunwei.R.drawable.img_site_bg,
+ 5f
+ )
// 接口未返回
// binding.stllTag.remove()
// binding.stllTag.setData(listOf("上车点", "下车点"), this)
@@ -374,11 +455,16 @@
}
}
+ private fun animateMapTo(latitude: Double, longitude: Double) {
+ val ratio = if (bottomSheetBehavior.state == BottomSheetBehavior.STATE_HALF_EXPANDED) 0.55f else 0.5f
+ mapFrag.animateTo(latitude, longitude, targetScreenYRatio = ratio)
+ }
+
override fun onBackPressedHandel() {
if (viewModel.siteItem.value == null) {
super.onBackPressedHandel()
} else {
- viewModel.siteItem.value = null
+ viewModel.siteItem.postValue(null)
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/site/SiteNavVM.kt b/app/src/main/java/com/xw/yunwei/ui/work/site/SiteNavVM.kt
index ffb422b..22eda08 100644
--- a/app/src/main/java/com/xw/yunwei/ui/work/site/SiteNavVM.kt
+++ b/app/src/main/java/com/xw/yunwei/ui/work/site/SiteNavVM.kt
@@ -2,9 +2,11 @@
import android.app.Application
import androidx.lifecycle.MutableLiveData
+import com.xw.common.Constants
import com.xw.common.base.BaseViewModel
import com.xw.yunwei.model.FenceInfoModel
import com.xw.yunwei.model.SiteModel
+import com.xw.yunwei.model.sitePlaceHolder
import com.xw.yunwei.net.WorkRepository
import org.koin.core.component.inject
@@ -13,7 +15,7 @@
val workRepository: WorkRepository by inject()
val filterStatus = listOf(
- "全部", "启用中", "已停用", "失效"
+ "全部", "可运营", "待生效","启用中", "已停用", "失效"
)
val selectStatus = mutableListOf<String>(filterStatus[0])
@@ -25,20 +27,37 @@
val search = MutableLiveData("")
var cityCode: String = ""
- fun query() {
+
+ //是否已经筛选
+ fun hadFilter(): Boolean {
+ return selectStatus.count { it != filterStatus[0] } > 0
+ }
+
+ fun query(lat: Double? = null, lon: Double? = null) {
launchRequest {
val map = mutableMapOf<String, Any?>()
// 运营状态 1=待启用 2=启用中 3=已停用 4=已失效
// map["operationStatus"] =
// if (selectStatus.isNotEmpty()) selectStatus.map { filterStatus.indexOf(it) + 1 }
// .joinToString(",") else null
- map["operationStatus"] = if(selectStatus.getOrNull(0) == filterStatus[0]) null else "${filterStatus.indexOf(selectStatus.getOrNull(0))+1}"
+ map["operationStatus"] = if(selectStatus.getOrNull(0) == filterStatus[0]) null else "${filterStatus.indexOf(selectStatus.getOrNull(0))+3}"
// map["operationStatus"] = if (selectStatus.isEmpty()) null else filterStatus.indexOf(selectStatus[0]) + 1
// map["pointType"] = null // 点位类型1运营点位 2测试点位
map["queryParams"] = search.value // 查询参数
map["cityCode"] = cityCode
+ if (lat != null && lon != null) {
+ map["longitude"] = lon
+ map["latitude"] = lat
+ } else {
+ map["longitude"] = Constants.longitude
+ map["latitude"] = Constants.latitude
+ }
workRepository.querySites(map)?.let {
- dataList.postValue(it)
+ val data = it.toMutableList()
+ if (it.isNotEmpty()) {
+ data.add(sitePlaceHolder)
+ }
+ dataList.postValue(data)
}
}
}
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/site/adapter/PictureOperationAdapter.kt b/app/src/main/java/com/xw/yunwei/ui/work/site/adapter/PictureOperationAdapter.kt
new file mode 100644
index 0000000..77780ab
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/site/adapter/PictureOperationAdapter.kt
@@ -0,0 +1,29 @@
+package com.xw.yunwei.ui.work.site.adapter
+
+import android.widget.ImageView
+import com.chad.library.adapter.base.BaseQuickAdapter
+import com.chad.library.adapter.base.viewholder.BaseViewHolder
+import com.xw.common.utils.GlideEngine
+import com.xw.yunwei.R
+
+//图片操作适配器
+class PictureOperationAdapter(val couldDelete: Boolean = true) :
+ BaseQuickAdapter<String, BaseViewHolder>(R.layout.item_picture_operation) {
+ override fun convert(
+ holder: BaseViewHolder,
+ item: String
+ ) {
+ val imageView = holder.getView<ImageView>(R.id.iv_picture)
+ if (item.isEmpty()) {
+ imageView.setImageResource(R.mipmap.ic_add_picture)
+ } else {
+ GlideEngine.createGlideEngine().load(
+ imageView,
+ item,
+ com.xw.common.R.mipmap.icon_default5, com.xw.common.R.mipmap.icon_default5,
+ 4f
+ )
+ }
+ holder.setGone(R.id.iv_delete, item.isEmpty() || !couldDelete)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/ui/work/site/viewmodel/SiteErrorUploadVM.kt b/app/src/main/java/com/xw/yunwei/ui/work/site/viewmodel/SiteErrorUploadVM.kt
new file mode 100644
index 0000000..bab7694
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/ui/work/site/viewmodel/SiteErrorUploadVM.kt
@@ -0,0 +1,199 @@
+package com.xw.yunwei.ui.work.site.viewmodel
+
+import android.annotation.SuppressLint
+import android.app.Application
+import android.content.Context
+import android.view.View
+import androidx.core.net.toUri
+import androidx.fragment.app.FragmentActivity
+import androidx.lifecycle.MutableLiveData
+import com.blankj.utilcode.util.UriUtils
+import com.luck.picture.lib.config.PictureMimeType
+import com.luck.picture.lib.entity.LocalMedia
+import com.luck.picture.lib.interfaces.OnResultCallbackListener
+import com.xw.common.CommonDialog
+import com.xw.common.base.BaseViewModel
+import com.xw.common.base.ShowImgListDialog
+import com.xw.common.utils.ToastUtilCommon
+import com.xw.yunwei.R
+import com.xw.yunwei.model.SiteModel
+import com.xw.yunwei.model.UploadModel
+import com.xw.yunwei.net.CommonRepository
+import com.xw.yunwei.net.WorkRepository
+import com.xw.yunwei.utils.PictureSelectorFactory
+import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.MultipartBody
+import okhttp3.RequestBody.Companion.asRequestBody
+import org.koin.core.component.inject
+import java.io.File
+
+class SiteErrorUploadVM(application: Application) : BaseViewModel(application),
+ OnResultCallbackListener<LocalMedia> {
+ val commonRepository: CommonRepository by inject()
+ val workRepository: WorkRepository by inject()
+
+ val model = MutableLiveData<SiteModel>()
+ val working = MutableLiveData<Boolean>(true)
+ val maxLength = MutableLiveData(200)
+ val desc = MutableLiveData("")
+ val countNotice: MutableLiveData<String> =
+ MutableLiveData("${desc.value?.length ?: 0}/${maxLength.value}")
+ val noticeLabel: MutableLiveData<String> = MutableLiveData("最多输入${maxLength.value}字")
+ val pictureMax = MutableLiveData(9)
+
+ //操作图片
+ val operationPictures: MutableLiveData<MutableList<String>> = MutableLiveData(mutableListOf(""))
+
+ //是否正在上传中
+ var isUploading = false
+ val onClick = View.OnClickListener {
+ when (it.id) {
+ R.id.btn_error_upload -> submit()
+ }
+ }
+
+ //添加图片
+ fun addPicture(url: String) {
+ val list = operationPictures.value ?: mutableListOf()
+ list.add(url)
+ refreshPictures(list)
+ operationPictures.postValue(list.toMutableList())
+ }
+
+ //移除图片
+ fun removePicture(position: Int) {
+ val list = operationPictures.value ?: mutableListOf()
+ list.removeAt(position)
+ refreshPictures(list)
+ operationPictures.postValue(list.toMutableList())
+ }
+
+ //刷新图片
+ fun refreshPictures(list: MutableList<String>) {
+ list.removeIf { it.isEmpty() }
+ if (list.size == pictureMax.value) {
+ return
+ }
+ list.add("")
+ }
+
+ //操作图片
+ fun operatePicture(context: Context, position: Int) {
+ val list = operationPictures.value ?: mutableListOf()
+ val element = list.elementAtOrNull(position) ?: return
+ if (element.isEmpty()) {
+ operatePictureFromDevice(context)
+ } else {
+ val backUp = list.toMutableList()
+ backUp.removeIf { it.isEmpty() }
+ ShowImgListDialog(
+ context as FragmentActivity,
+ backUp,
+ position
+ ).show()
+ }
+ }
+
+ //从设备操作图片
+ fun operatePictureFromDevice(context: Context) {
+ CommonDialog.showTypeDialog(context) {
+ if (it == 0) takeAPhotograph(context) else if (it == 1) enterGallery(context)
+ }
+ }
+
+ // 进入图库
+ @SuppressLint("SourceLockedOrientationActivity")
+ private fun enterGallery(context: Context) {
+ PictureSelectorFactory.enterGallery(
+ context,
+ (pictureMax.value ?: 1) - (operationPictures.value?.count { it.isNotEmpty() } ?: 0),
+ this)
+ }
+
+ // 拍照
+ private fun takeAPhotograph(context: Context) {
+ PictureSelectorFactory.takeAPhotograph(context,this)
+ }
+
+ override fun onResult(result: ArrayList<LocalMedia>?) {
+ result?.let { selectList ->
+ for (item in selectList) {
+ val path: String = item.availablePath
+ val imgPath =
+ if (PictureMimeType.isContent(path) && !item.isCut && !item.isCompressed) {
+ UriUtils.uri2File(path.toUri()).absolutePath
+ } else {
+ path
+ }
+ addPicture(imgPath)
+ }
+ }
+ }
+
+ override fun onCancel() {
+
+ }
+
+ private fun uploadFile(files: MutableList<Pair<String, UploadModel?>>, succ: () -> Unit) {
+ val result = files.find { it.second == null }
+ if (result == null) {
+ succ()
+ } else {
+ launchRequest(showLoading = false, error = { _, errMsg ->
+ ToastUtilCommon.showError(errMsg)
+ dismissDialog()
+ isUploading = false
+ }) {
+ val file = File(result.first)
+ val fileRequestBody = file.asRequestBody("image/jpg".toMediaType())
+ val mBuilder = MultipartBody.Builder()
+ mBuilder.addFormDataPart("file", file.name, fileRequestBody)
+ mBuilder.setType(MultipartBody.FORM)
+ val data = commonRepository.uploadFile(mBuilder.build())
+ files[files.indexOf(result)] = result.first to data
+ uploadFile(files, succ)
+ }
+ }
+ }
+
+ //提交
+ fun submit() {
+ if (model.value == null) {
+ return
+ }
+ if (working.value == null) {
+ ToastUtilCommon.showError("请选择现场情况")
+ return
+ }
+ if ((desc.value?.length ?: 0) > maxLength.value!!) {
+ ToastUtilCommon.showError(noticeLabel.value)
+ return
+ }
+ val list = operationPictures.value ?: mutableListOf()
+ list.removeIf { it.isEmpty() }
+ if (list.count { !it.startsWith("http") } > 0) {
+ val result = list.map { Pair<String, UploadModel?>(it, null) }.toMutableList()
+ uploadFile(result) {
+ result.removeIf { it.second == null }
+ submit(result.map { it.second!! }.toMutableList())
+ }
+ return
+ }
+ submit(mutableListOf())
+ }
+
+ //提交
+ private fun submit(urls: MutableList<UploadModel>) {
+ launchRequest {
+ workRepository.addPointSituationReport(
+ working.value!!,
+ model.value!!,
+ desc.value ?: "",
+ urls
+ ).also {
+ ToastUtilCommon.showSuc("提交成功")
+ finish()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/utils/DialogFactory.kt b/app/src/main/java/com/xw/yunwei/utils/DialogFactory.kt
new file mode 100644
index 0000000..1fe80c0
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/utils/DialogFactory.kt
@@ -0,0 +1,43 @@
+package com.xw.yunwei.utils
+
+import android.content.Context
+import android.widget.FrameLayout
+import com.afollestad.materialdialogs.MaterialDialog
+import com.afollestad.materialdialogs.customview.getCustomView
+import com.xw.common.SecureScreenShot
+import com.xw.common.utils.BindUtils
+import com.xw.yunwei.Constants
+import com.xw.yunwei.R
+import com.xw.yunwei.extension.dpToPx
+import com.xw.yunwei.extension.spToPx
+import com.xw.yunwei.ui.widget.WatermarkView
+
+//弹窗工厂
+object DialogFactory {
+ //生产
+ fun produce(context: Context): MaterialDialog {
+ return MaterialDialog(context).apply {
+ SecureScreenShot.apply(window)
+ this.view.post {
+ getCustomView().post {
+ val root = window!!.decorView as FrameLayout
+ val watermarkView = WatermarkView(context)
+ watermarkView.layoutParams = FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ getCustomView().height
+ )
+ watermarkView.watermarkText = Constants.user?.let {
+ "${it.nickName}-${it.phoneNumber}"
+ } ?: ""
+ watermarkView.textColor = BindUtils.getResColor(R.color.color_0f31456a)
+ watermarkView.isStaggered = false
+ watermarkView.watermarkTextRotation = -15f
+ watermarkView.spacingX = (375f / 2f).dpToPx(context)
+ watermarkView.spacingY = 200f.dpToPx(context)
+ watermarkView.textSize = 14f.spToPx(context)
+ root.addView(watermarkView)
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/utils/HtmlSanitizer.kt b/app/src/main/java/com/xw/yunwei/utils/HtmlSanitizer.kt
new file mode 100644
index 0000000..a147f01
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/utils/HtmlSanitizer.kt
@@ -0,0 +1,229 @@
+package com.xw.yunwei.utils
+
+import org.jsoup.Jsoup
+import org.jsoup.nodes.Document
+import org.jsoup.safety.Safelist
+import java.util.Locale
+
+class HtmlSanitizer {
+
+ // 定义不同安全等级的白名单
+ object Whitelists {
+ // 1. 基本文本(最严格)
+ val BASIC_TEXT = Safelist.none()
+ .addTags("p", "br", "b", "i", "strong", "em", "blockquote")
+ .addAttributes("p", "class")
+
+ // 2. 简单文档
+ val SIMPLE_DOCUMENT = Safelist.simpleText()
+ .addTags("h1", "h2", "h3", "h4", "h5", "h6", "hr", "ul", "ol", "li")
+ .addAttributes("a", "href", "title", "target")
+ .addProtocols("a", "href", "http", "https", "mailto")
+
+ // 3. 富文本(允许格式和媒体)
+ val RICH_TEXT = Safelist.relaxed()
+ .addTags("div", "span", "table", "tr", "td", "th", "tbody", "thead")
+ .addAttributes("div", "class", "style", "id")
+ .addAttributes("span", "class", "style")
+ .addAttributes("table", "border", "cellpadding", "cellspacing")
+ .addAttributes("img", "src", "alt", "title", "width", "height")
+ .addProtocols("img", "src", "http", "https", "data")
+ .removeTags("iframe", "object", "embed", "script", "style")
+
+ // 4. 自定义白名单(根据业务需求)
+ // 以 relaxed() 为基础,覆盖常见正常 HTML(表格、列表、标题、引用、代码块等),
+ // 并通过 ":all" 放行 class/style/id 等属性,使已清洗过的内联样式与 class 能正常保留,
+ // 避免“样式被无脑剥离导致正常内容渲染异常”。
+ val CUSTOM = Safelist.relaxed()
+ // 补充 relaxed 未包含但常见的安全标签
+ .addTags(
+ "u", "s", "strike", "del", "ins", "mark", "small", "big",
+ "section", "article", "header", "footer", "nav", "aside",
+ "figure", "figcaption", "font", "center", "label",
+ "abbr", "address", "time", "wbr"
+ )
+ // 允许所有标签携带 class/style/id 等展示相关属性
+ // (style 的具体内容已在 sanitizeCss 中过滤危险值,class 已在 isValidClassName 中校验)
+ .addAttributes(":all", "class", "style", "id", "title", "dir", "lang")
+ // 表格相关的排版属性,保证表格样式不丢
+ .addAttributes("table", "border", "cellpadding", "cellspacing", "width", "bgcolor")
+ .addAttributes("td", "colspan", "rowspan", "width", "height", "align", "valign", "bgcolor")
+ .addAttributes("th", "colspan", "rowspan", "width", "height", "align", "valign", "bgcolor")
+ .addAttributes("img", "src", "alt", "title", "width", "height")
+ .addAttributes("font", "color", "face", "size")
+ .addAttributes("a", "href", "target", "rel", "name")
+ .addProtocols("a", "href", "http", "https", "mailto", "tel")
+ .addProtocols("img", "src", "http", "https", "data")
+ // 外链强制加安全属性,防止 tabnabbing 与权重泄露
+ .addEnforcedAttribute("a", "rel", "nofollow noopener noreferrer")
+ }
+
+ /**
+ * 基础清洗方法
+ */
+ fun sanitizeBasic(html: String, whitelist: Safelist = Whitelists.SIMPLE_DOCUMENT): String {
+ return Jsoup.clean(html, whitelist)
+ }
+
+ /**
+ * 高级清洗:包含额外安全检查和转换
+ */
+ fun sanitizeAdvanced(
+ html: String,
+ baseUri: String = ""
+ ): String {
+ val document = Jsoup.parse(html, baseUri)
+
+ // 1. 移除危险标签
+ val dangerousTags = listOf("script", "iframe", "object", "embed",
+ "applet", "meta", "link", "base", "frame")
+ dangerousTags.forEach { tag ->
+ document.select(tag).remove()
+ }
+
+ // 2. 移除危险属性
+ val dangerousAttrs = listOf(
+ "onclick", "onload", "onerror", "onmouseover", "onmouseout",
+ "onkeydown", "onkeypress", "onkeyup", "onfocus", "onblur",
+ "onchange", "onsubmit", "href" // 特别处理href
+ )
+
+ document.allElements.forEach { element ->
+ val attributes = element.attributes()
+ attributes.forEach { attr ->
+ // 移除以"on"开头的事件处理器
+ if (attr.key.startsWith("on")) {
+ attributes.remove(attr.key)
+ }
+ // 移除javascript:协议
+ if (attr.key == "href" || attr.key == "src") {
+ val value = attr.value.lowercase(Locale.ROOT)
+ if (value.startsWith("javascript:") ||
+ value.startsWith("data:text/html") ||
+ value.startsWith("file://")) {
+ attributes.remove(attr.key)
+ }
+ }
+ }
+ }
+
+ // 3. 净化链接(确保外部链接有安全属性)
+ document.select("a[href]").forEach { link ->
+ val href = link.attr("href")
+ if (href.startsWith("http://") || href.startsWith("https://")) {
+ link.attr("target", "_blank")
+ link.attr("rel", "noopener noreferrer")
+ }
+ }
+
+ // 4. 净化图片(防止盗链和XSS)
+ document.select("img[src]").forEach { img ->
+ val src = img.attr("src")
+ // 检查data:协议图片
+ if (src.startsWith("data:image")) {
+ // 可以限制data URL大小
+ if (src.length > 10000) { // 限制10KB
+ img.remove()
+ }
+ }
+ }
+
+ // 5. 应用白名单
+ val cleaned = Jsoup.clean(document.body().html(), Whitelists.RICH_TEXT)
+
+ return cleaned
+ }
+
+ /**
+ * 针对用户输入的富文本编辑器内容清洗
+ */
+ fun sanitizeUserContent(html: String): String {
+ // 解析文档
+ val doc = Jsoup.parseBodyFragment(html)
+
+ // 创建自定义白名单
+ val whitelist = Whitelists.CUSTOM
+
+ // 特别处理style属性
+ doc.select("*[style]").forEach { element ->
+ val style = element.attr("style")
+ val sanitizedStyle = sanitizeCss(style)
+ if (sanitizedStyle.isNotEmpty()) {
+ element.attr("style", sanitizedStyle)
+ } else {
+ element.removeAttr("style")
+ }
+ }
+
+ // 清理class属性
+ doc.select("*[class]").forEach { element ->
+ val classes = element.attr("class").split(" ")
+ val safeClasses = classes.filter { isValidClassName(it) }
+ if (safeClasses.isNotEmpty()) {
+ element.attr("class", safeClasses.joinToString(" "))
+ } else {
+ element.removeAttr("class")
+ }
+ }
+
+ // 最终应用白名单
+ return Jsoup.clean(doc.body().html(), whitelist)
+ }
+
+ private fun sanitizeCss(css: String): String {
+ // 采用“危险值黑名单”策略:保留所有正常 CSS 属性,仅剔除真正的 XSS 向量,
+ // 避免误删 line-height、text-decoration、list-style、background 等常用属性导致样式异常。
+ val pattern = Regex("""([a-zA-Z\-]+)\s*:\s*([^;]+)""")
+ val sanitized = StringBuilder()
+
+ pattern.findAll(css).forEach { match ->
+ val property = match.groupValues[1].trim().lowercase(Locale.ROOT)
+ val value = match.groupValues[2].trim()
+
+ // 过滤危险属性(老式浏览器脚本注入向量)
+ if (isDangerousCssProperty(property)) {
+ return@forEach
+ }
+
+ // 过滤危险值
+ if (isSafeCssValue(property, value)) {
+ if (sanitized.isNotEmpty()) sanitized.append("; ")
+ sanitized.append("$property: $value")
+ }
+ }
+
+ return sanitized.toString()
+ }
+
+ /**
+ * 危险 CSS 属性(可触发脚本执行的历史浏览器特性)
+ */
+ private fun isDangerousCssProperty(property: String): Boolean {
+ val dangerous = listOf("behavior", "-moz-binding", "-o-link", "-o-link-source")
+ return dangerous.contains(property) || property.endsWith("-binding")
+ }
+
+ private fun isSafeCssValue(property: String, value: String): Boolean {
+ // 防止 CSS 注入攻击:拦截脚本协议、表达式、外部绑定与可执行 data URL
+ val v = value.lowercase(Locale.ROOT)
+ val unsafePatterns = listOf(
+ Regex("expression\\s*\\("),
+ Regex("javascript:"),
+ Regex("vbscript:"),
+ Regex("-moz-binding"),
+ Regex("@import"),
+ Regex("""url\s*\(\s*['"]?\s*javascript:"""),
+ Regex("""url\s*\(\s*['"]?\s*vbscript:"""),
+ Regex("""url\s*\(\s*['"]?\s*data:text/html""")
+ )
+
+ return unsafePatterns.none { pattern ->
+ pattern.containsMatchIn(v)
+ }
+ }
+
+ private fun isValidClassName(className: String): Boolean {
+ // 只允许字母、数字、连字符、下划线
+ return className.matches(Regex("^[a-zA-Z0-9_\\-]+$"))
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/utils/ICallBack.java b/app/src/main/java/com/xw/yunwei/utils/ICallBack.java
new file mode 100644
index 0000000..0215e91
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/utils/ICallBack.java
@@ -0,0 +1,19 @@
+package com.xw.yunwei.utils;
+
+/**
+ * 创建时间:2017-9-20 下午3:37:55
+ * 项目名称:IndexActivity
+ *
+ * @author liqi
+ * @version 1.0
+ * @since JDK 1.6.0_21
+ * 文件名称:TTS.java
+ * 类说明:
+ */
+
+/**
+ * 播报回调类
+ */
+public interface ICallBack {
+ void onCompleted(int code);
+}
diff --git a/app/src/main/java/com/xw/yunwei/utils/IFlyTTS.java b/app/src/main/java/com/xw/yunwei/utils/IFlyTTS.java
new file mode 100644
index 0000000..8defcab
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/utils/IFlyTTS.java
@@ -0,0 +1,161 @@
+package com.xw.yunwei.utils;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.media.AudioManager.OnAudioFocusChangeListener;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+
+import com.iflytek.cloud.ErrorCode;
+import com.iflytek.cloud.SpeechConstant;
+import com.iflytek.cloud.SpeechError;
+import com.iflytek.cloud.SpeechSynthesizer;
+import com.iflytek.cloud.SpeechUtility;
+import com.iflytek.cloud.SynthesizerListener;
+
+/**
+ * 创建时间:2017-9-20 下午3:35:23
+ * 项目名称:IndexActivity
+ *
+ * @author liqi
+ * @version 1.0
+ * @since JDK 1.6.0_21
+ * 文件名称:MscTTS.java
+ * 类说明: 科大讯飞播报类
+ */
+public class IFlyTTS implements TTS, SynthesizerListener, OnAudioFocusChangeListener {
+ private static IFlyTTS iflyTTS = null;
+ private boolean isPlaying = false;
+ private AudioManager mAm = null;
+ private SpeechSynthesizer mTts;
+
+ /**
+ * todo 请替换您自己申请的ID。
+ */
+ private final String appId = "5fbf299f";
+
+ public static IFlyTTS getInstance() {
+ if (iflyTTS == null) {
+ iflyTTS = new IFlyTTS();
+ }
+ return iflyTTS;
+ }
+
+ private IFlyTTS() {
+ }
+
+ public void init(@NonNull Context context) {
+ SpeechUtility.createUtility(context, SpeechConstant.APPID + "=" + appId);
+ mAm = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ mTts = SpeechSynthesizer.createSynthesizer(context, errorcode -> {
+ if (ErrorCode.SUCCESS == errorcode) {
+ //初始化成功
+ //Toast.makeText(mContext, "初始化音频成功", Toast.LENGTH_SHORT).show();
+ }
+ });
+// mTts.setParameter(SpeechConstant.VOICE_NAME, "xiaoyan");
+// //设置语速,值范围:[0, 100],默认值:50
+// mTts.setParameter(SpeechConstant.SPEED, "55");
+// //设置音量
+// mTts.setParameter(SpeechConstant.VOLUME, "tts_volume");
+// //设置语调
+// mTts.setParameter(SpeechConstant.PITCH, "tts_pitch");
+// //设置与其他音频软件冲突的时候是否暂停其他音频
+// mTts.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "false");
+// //女生仅vixy支持多音字播报
+// mTts.setParameter(SpeechConstant.VOICE_NAME, "vixy");
+ }
+
+ public void playText(String playText) {
+ //多音字处理举例
+ if (playText != null && playText.contains("京藏")) {
+ playText = playText.replace("京藏", "京藏[=zang4]");
+ }
+ if (playText != null && playText.length() > 0) {
+ int result = mAm.requestAudioFocus(this,
+ AudioManager.STREAM_MUSIC,
+ AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
+ if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+ mTts.startSpeaking(playText, this);
+ isPlaying = true;
+ }
+ }
+ }
+
+ public void stopSpeak() {
+ if (mTts != null) {
+ mTts.stopSpeaking();
+ }
+ isPlaying = false;
+ }
+
+ public void destroy() {
+ stopSpeak();
+ if (mTts != null) {
+ mTts.destroy();
+ }
+ iflyTTS = null;
+ }
+
+ @Override
+ public void onBufferProgress(int arg0, int arg1, int arg2, String arg3) {
+ }
+
+ //播报是否成功以及错误码
+ //在音频播放完成,或会话出现错误时,将回调此函数。若为null,则没有出现错误。
+ @Override
+ public void onCompleted(SpeechError arg0) {
+ isPlaying = false;
+ if (mAm != null) {
+ mAm.abandonAudioFocus(this);
+ }
+ if (callBack != null) {
+ if (arg0 == null) {
+ callBack.onCompleted(0);
+ }
+ }
+ }
+
+ @Override
+ public void onEvent(int arg0, int arg1, int arg2, Bundle arg3) {
+ }
+
+ @Override
+ public void onSpeakBegin() {
+ isPlaying = true;
+ }
+
+ @Override
+ public void onSpeakPaused() {
+ isPlaying = false;
+ }
+
+ @Override
+ public void onSpeakProgress(int arg0, int arg1, int arg2) {
+ }
+
+ @Override
+ public void onSpeakResumed() {
+ }
+
+
+ @Override
+ public boolean isPlaying() {
+ return isPlaying;
+ }
+
+
+ ICallBack callBack = null;
+
+ @Override
+ public void setCallback(ICallBack callback) {
+ callBack = callback;
+ }
+
+ @Override
+ public void onAudioFocusChange(int focusChange) {
+ // TODO Auto-generated method stub
+
+ }
+}
diff --git a/app/src/main/java/com/xw/yunwei/utils/PictureSelectorFactory.kt b/app/src/main/java/com/xw/yunwei/utils/PictureSelectorFactory.kt
new file mode 100644
index 0000000..d87e506
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/utils/PictureSelectorFactory.kt
@@ -0,0 +1,47 @@
+package com.xw.yunwei.utils
+
+import android.content.Context
+import com.luck.picture.lib.basic.PictureSelector
+import com.luck.picture.lib.config.SelectMimeType
+import com.luck.picture.lib.entity.LocalMedia
+import com.luck.picture.lib.interfaces.OnResultCallbackListener
+import com.luck.picture.lib.style.PictureSelectorStyle
+import com.luck.picture.lib.style.SelectMainStyle
+import com.xw.common.utils.GlideEngine
+import com.xw.common.utils.PictureCompressEngine
+import com.xw.yunwei.R
+
+//图片选择器工厂
+object PictureSelectorFactory {
+ //获取选择器
+ fun enterGallery(
+ context: Context,
+ max: Int,
+ call: OnResultCallbackListener<LocalMedia>,
+ ) {
+ PictureSelector.create(context)
+ .openGallery(SelectMimeType.ofImage())
+ .setSelectorUIStyle(PictureSelectorStyle().apply {
+ selectMainStyle = SelectMainStyle().apply {
+ isPreviewSelectNumberStyle = true
+ isSelectNumberStyle = true
+ selectBackground = R.drawable.ps_demo_blue_num_selector
+ }
+ })
+ .setImageEngine(GlideEngine.createGlideEngine())
+ .setMaxSelectNum(max)
+ .setImageSpanCount(4)
+ .isPreviewImage(true)
+ .isDisplayCamera(false)
+ .setCompressEngine(PictureCompressEngine())
+ .forResult(call)
+ }
+
+ //拍摄照片
+ fun takeAPhotograph(context: Context, call: OnResultCallbackListener<LocalMedia>) {
+ PictureSelector.create(context)
+ .openCamera(SelectMimeType.ofImage())
+ .setCompressEngine(PictureCompressEngine())
+ .forResultActivity(call)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/utils/SystemTTS.java b/app/src/main/java/com/xw/yunwei/utils/SystemTTS.java
new file mode 100644
index 0000000..5743120
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/utils/SystemTTS.java
@@ -0,0 +1,113 @@
+package com.xw.yunwei.utils;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.speech.tts.TextToSpeech;
+import android.speech.tts.TextToSpeech.OnUtteranceCompletedListener;
+import android.speech.tts.UtteranceProgressListener;
+
+import androidx.annotation.NonNull;
+
+import java.util.Locale;
+
+/**
+ * 系统播报类,部分手机不支持中文播报
+ */
+@SuppressLint("NewApi")
+public class SystemTTS extends UtteranceProgressListener implements TTS, OnUtteranceCompletedListener {
+ private static volatile SystemTTS singleton;
+ private TextToSpeech textToSpeech; // 系统语音播报类
+ private boolean isSuccess = true;
+
+ public static SystemTTS getInstance() {
+ if (singleton == null) {
+ synchronized (SystemTTS.class) {
+ if (singleton == null) {
+ singleton = new SystemTTS();
+ }
+ }
+ }
+ return singleton;
+ }
+
+ private SystemTTS() {
+ }
+
+
+ public void destroy() {
+ stopSpeak();
+ if (textToSpeech != null) {
+ textToSpeech.shutdown();
+ }
+ singleton = null;
+ }
+
+ public void init(@NonNull Context context) {
+ textToSpeech = new TextToSpeech(context.getApplicationContext(), new TextToSpeech.OnInitListener() {
+ @Override
+ public void onInit(int i) {
+ //系统语音初始化成功
+ if (i == TextToSpeech.SUCCESS) {
+ int result = textToSpeech.setLanguage(Locale.CHINA);
+ textToSpeech.setPitch(1.0f);// 设置音调,值越大声音越尖(女生),值越小则变成男声,1.0是常规
+ textToSpeech.setSpeechRate(1.0f);
+ textToSpeech.setOnUtteranceProgressListener(SystemTTS.this);
+ textToSpeech.setOnUtteranceCompletedListener(SystemTTS.this);
+ if (result == TextToSpeech.LANG_MISSING_DATA
+ || result == TextToSpeech.LANG_NOT_SUPPORTED) {
+ //系统不支持中文播报
+ isSuccess = false;
+ }
+ }
+ }
+ });
+ }
+
+ public void playText(String playText) {
+ if (!isSuccess) {
+ return;
+ }
+ if (textToSpeech != null) {
+ textToSpeech.speak(playText,
+ TextToSpeech.QUEUE_ADD, null, null);
+ }
+ }
+
+ public void stopSpeak() {
+ if (textToSpeech != null) {
+ textToSpeech.stop();
+ }
+ }
+
+ @Override
+ public boolean isPlaying() {
+ return textToSpeech.isSpeaking();
+ }
+
+ ICallBack callBack = null;
+
+ @Override
+ public void setCallback(ICallBack callback) {
+ callBack = callback;
+ }
+
+
+ //播报完成回调
+ @Override
+ public void onUtteranceCompleted(String utteranceId) {
+ }
+
+ @Override
+ public void onStart(String utteranceId) {
+
+ }
+
+ @Override
+ public void onDone(String utteranceId) {
+ }
+
+ @Override
+ public void onError(String utteranceId) {
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/utils/TTS.java b/app/src/main/java/com/xw/yunwei/utils/TTS.java
new file mode 100644
index 0000000..8403439
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/utils/TTS.java
@@ -0,0 +1,29 @@
+package com.xw.yunwei.utils;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+
+/**
+ * 创建时间:2017-9-20 下午3:37:55
+ * 项目名称:IndexActivity
+ *
+ * @author liqi
+ * @version 1.0
+ * @since JDK 1.6.0_21
+ * 文件名称:TTS.java
+ * 类说明:
+ */
+public interface TTS {
+ public void init(@NonNull Context context);
+
+ public void playText(String playText);
+
+ public void stopSpeak();
+
+ public void destroy();
+
+ public boolean isPlaying();
+
+ public void setCallback(ICallBack callback);
+}
diff --git a/app/src/main/java/com/xw/yunwei/utils/TTSController.java b/app/src/main/java/com/xw/yunwei/utils/TTSController.java
new file mode 100644
index 0000000..b66a7e3
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/utils/TTSController.java
@@ -0,0 +1,142 @@
+package com.xw.yunwei.utils;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+import androidx.annotation.NonNull;
+
+import com.amap.api.navi.AMapNavi;
+
+import java.util.LinkedList;
+
+/**
+ * 当前DEMO的播报方式是队列模式。其原理就是依次将需要播报的语音放入链表中,播报过程是从头开始依次往后播报。
+ * <p>
+ * 导航SDK原则上是不提供语音播报模块的,如果您觉得此种播报方式不能满足你的需求,请自行优化或改进。
+ */
+public class TTSController implements ICallBack {
+
+
+ @Override
+ public void onCompleted(int code) {
+ AMapNavi.setTtsPlaying(false);
+
+ handler.obtainMessage(1).sendToTarget();
+ }
+
+ public static enum TTSType {
+ /**
+ * 讯飞语音
+ */
+ IFLYTTS,
+ /**
+ * 系统语音
+ */
+ SYSTEMTTS;
+ }
+
+ public static TTSController ttsManager;
+ private TTS tts = null;
+ private SystemTTS systemTTS;
+ private IFlyTTS iflyTTS = null;
+ private final LinkedList<String> wordList = new LinkedList<String>();
+ private final int TTS_PLAY = 1;
+ private final int CHECK_TTS_PLAY = 2;
+ private final Handler handler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(@NonNull Message msg) {
+ super.handleMessage(msg);
+ switch (msg.what) {
+ case TTS_PLAY:
+ if (tts != null && wordList.size() > 0) {
+ tts.playText(wordList.removeFirst());
+ }
+ break;
+ case CHECK_TTS_PLAY:
+ if (!tts.isPlaying()) {
+ handler.obtainMessage(1).sendToTarget();
+ }
+ break;
+ default:
+ }
+
+ }
+ };
+
+ public void setVideoText(String s) {
+ try {
+// if (tts.isPlaying()){
+//
+// }
+// setVideoTextInNavi(s);
+ tts.playText(s);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void setVideoTextInNavi(String s) {
+ try {
+ if (wordList != null)
+ wordList.addLast(s);
+ handler.obtainMessage(CHECK_TTS_PLAY).sendToTarget();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void setTTSType(TTSType type) {
+ if (type == TTSType.SYSTEMTTS) {
+ tts = systemTTS;
+ } else {
+ tts = iflyTTS;
+ }
+ tts.setCallback(this);
+ }
+
+ private TTSController() {
+ systemTTS = SystemTTS.getInstance();
+ iflyTTS = IFlyTTS.getInstance();
+ tts = iflyTTS;
+ }
+
+ public void init(@NonNull Context context) {
+ if (systemTTS != null) {
+ systemTTS.init(context);
+ }
+ if (iflyTTS != null) {
+ iflyTTS.init(context);
+ }
+ tts.setCallback(this);
+ }
+
+ public static TTSController getInstance() {
+ if (ttsManager == null) {
+ ttsManager = new TTSController();
+ }
+ return ttsManager;
+ }
+
+ public void stopSpeaking() {
+ if (systemTTS != null) {
+ systemTTS.stopSpeak();
+ }
+ if (iflyTTS != null) {
+ iflyTTS.stopSpeak();
+ }
+ wordList.clear();
+ }
+
+ public void destroy() {
+ handler.removeCallbacksAndMessages(null);
+ if (systemTTS != null) {
+ systemTTS.destroy();
+ }
+ if (iflyTTS != null) {
+ iflyTTS.destroy();
+ }
+ ttsManager = null;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/utils/VibrateUtils.kt b/app/src/main/java/com/xw/yunwei/utils/VibrateUtils.kt
new file mode 100644
index 0000000..a266601
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/utils/VibrateUtils.kt
@@ -0,0 +1,85 @@
+package com.xw.yunwei.utils
+
+import android.content.Context
+import android.os.Build
+import android.os.VibrationEffect
+import android.os.Vibrator
+import android.os.VibratorManager
+
+//设备震动工具
+object VibrateUtils {
+
+ private var vibrator: Vibrator? = null
+
+ fun init(context: Context) {
+ vibrator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ val manager =
+ context.getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager
+ manager.defaultVibrator
+ } else {
+ @Suppress("DEPRECATION")
+ context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
+ }
+ }
+
+ /** 检查设备是否有震动器 */
+ fun hasVibrator(): Boolean {
+ return vibrator?.hasVibrator() ?: false
+ }
+
+ /** 简单震动(毫秒) */
+ fun vibrate(durationMs: Long = 200) {
+ if (!hasVibrator()) return
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ vibrator?.vibrate(
+ VibrationEffect.createOneShot(durationMs, VibrationEffect.DEFAULT_AMPLITUDE)
+ )
+ } else {
+ @Suppress("DEPRECATION")
+ vibrator?.vibrate(durationMs)
+ }
+ }
+
+ /** 模式震动 */
+ fun vibratePattern(
+ pattern: LongArray = longArrayOf(0, 500, 200, 500, 200, 500),
+ repeat: Int = -1
+ ) {
+ if (!hasVibrator()) return
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ vibrator?.vibrate(
+ VibrationEffect.createWaveform(pattern, repeat)
+ )
+ } else {
+ @Suppress("DEPRECATION")
+ vibrator?.vibrate(pattern, repeat)
+ }
+ }
+
+ /** 按键点击效果(API 29+) */
+ fun click() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && hasVibrator()) {
+ vibrator?.vibrate(
+ VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)
+ )
+ } else {
+ vibrate(50) // 降级方案
+ }
+ }
+
+ /** 双击效果 */
+ fun doubleClick() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && hasVibrator()) {
+ vibrator?.vibrate(
+ VibrationEffect.createPredefined(VibrationEffect.EFFECT_DOUBLE_CLICK)
+ )
+ } else {
+ vibratePattern(longArrayOf(0, 70, 50, 70))
+ }
+ }
+
+ /** 停止震动 */
+ fun cancel() {
+ vibrator?.cancel()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/websocket/IWebSocketListener.kt b/app/src/main/java/com/xw/yunwei/websocket/IWebSocketListener.kt
new file mode 100644
index 0000000..c0f100a
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/websocket/IWebSocketListener.kt
@@ -0,0 +1,54 @@
+package com.xw.yunwei.websocket
+
+import okio.ByteString
+
+interface IWebSocketListener {
+ /**
+ * WebSocket连接成功
+ */
+ fun onConnected()
+
+ /**
+ * WebSocket连接失败
+ * @param t 异常信息
+ */
+ fun onConnectFailed(t: Throwable)
+
+ /**
+ * 接收到消息
+ * @param text 文本消息
+ */
+ fun onMessage(text: String)
+
+ /**
+ * 接收到二进制消息
+ * @param bytes 二进制数据
+ */
+ fun onMessage(bytes: ByteString)
+
+ /**
+ * 连接断开
+ * @param code 断开码
+ * @param reason 断开原因
+ */
+ fun onDisconnected(code: Int, reason: String)
+
+ /**
+ * 网络状态变化
+ * @param isAvailable 网络是否可用
+ */
+ fun onNetworkStateChanged(isAvailable: Boolean)
+
+ /**
+ * 发送消息成功
+ * @param message 消息内容
+ */
+ fun onSendMessageSuccess(message: String)
+
+ /**
+ * 发送消息失败
+ * @param message 消息内容
+ * @param t 异常
+ */
+ fun onSendMessageFailed(message: String, t: Throwable)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/websocket/WebSocketClient.kt b/app/src/main/java/com/xw/yunwei/websocket/WebSocketClient.kt
new file mode 100644
index 0000000..ffe2fe2
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/websocket/WebSocketClient.kt
@@ -0,0 +1,444 @@
+package com.xw.yunwei.websocket
+
+import com.google.gson.Gson
+import com.xw.common.utils.LogUtils
+import com.xw.yunwei.BuildConfig
+import com.xw.yunwei.Constants
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.launch
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.Response
+import okhttp3.WebSocket
+import okhttp3.WebSocketListener
+import okhttp3.logging.HttpLoggingInterceptor
+import okio.ByteString
+import org.json.JSONObject
+import java.util.LinkedList
+import java.util.concurrent.CopyOnWriteArrayList
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.atomic.AtomicBoolean
+
+//WebSocket客户端
+class WebSocketClient(
+ private val config: WebSocketConfig = WebSocketConfig
+) {
+ private var webSocket: WebSocket? = null
+ private var okHttpClient: OkHttpClient? = null
+ private var isConnecting = AtomicBoolean(false)
+ private var isConnected = AtomicBoolean(false)
+
+ private var reconnectCount = 0
+ private val gson = Gson()
+ private val ioCoroutineScope = CoroutineScope(Dispatchers.IO)
+
+ // 监听器列表
+ private val listeners = CopyOnWriteArrayList<IWebSocketListener>()
+
+ // 心跳相关
+ private var heartbeatJob: Job? = null
+
+ // 消息队列(连接失败时缓存)
+ private val messageQueue = LinkedList<String>()
+ private val maxQueueSize = 50
+
+ companion object {
+ private const val TAG = "WebSocketClient"
+ }
+
+ /**
+ * 初始化WebSocket客户端
+ */
+ private fun initClient(): OkHttpClient {
+ return OkHttpClient.Builder()
+ .connectTimeout(config.WS_TIMEOUT, TimeUnit.SECONDS)
+ .writeTimeout(config.WS_TIMEOUT, TimeUnit.SECONDS)
+ .readTimeout(config.WS_TIMEOUT, TimeUnit.SECONDS)
+ .pingInterval(config.PING_INTERVAL, TimeUnit.SECONDS) // 自动Ping
+ .retryOnConnectionFailure(true)
+ .addInterceptor { chain ->
+ val original = chain.request()
+ val request = original.newBuilder()
+ .header("User-Agent", "Android-App/${BuildConfig.VERSION_NAME}")
+ .header("Connection", "Upgrade")
+ .header("Upgrade", "websocket")
+ .header("Sec-WebSocket-Version", "13")
+ .build()
+ chain.proceed(request)
+ }
+ .addInterceptor(HttpLoggingInterceptor().apply {
+ level = if (BuildConfig.DEBUG) {
+ HttpLoggingInterceptor.Level.BODY
+ } else {
+ HttpLoggingInterceptor.Level.NONE
+ }
+ })
+ .build()
+ }
+
+ /**
+ * 连接WebSocket
+ */
+ fun connect(isFirstConnect: Boolean) {
+ if (isConnecting.get() || isConnected.get()) {
+ LogUtils.d(TAG, "WebSocket正在连接或已连接")
+ return
+ }
+
+ isConnecting.set(true)
+ reconnectCount = 0
+
+ ioCoroutineScope.launch {
+ try {
+ val request = Request.Builder()
+ .url(config.WS_URL)
+ .header("token", com.xw.common.Constants.token)
+ .build()
+
+ okHttpClient = initClient()
+ okHttpClient?.newWebSocket(request, createWebSocketListener())
+
+ LogUtils.i(TAG, "开始连接WebSocket: ${config.WS_URL}")
+ } catch (e: Exception) {
+ isConnecting.set(false)
+ LogUtils.d(TAG, "连接WebSocket失败: ${e.message}")
+ notifyConnectFailed(e)
+ }
+ }
+ }
+
+ /**
+ * 创建WebSocket监听器
+ */
+ private fun createWebSocketListener(): WebSocketListener {
+ return object : WebSocketListener() {
+ override fun onOpen(webSocket: WebSocket, response: Response) {
+ LogUtils.i(TAG, "WebSocket连接成功")
+
+ isConnecting.set(false)
+ isConnected.set(true)
+ reconnectCount = 0
+ this@WebSocketClient.webSocket = webSocket
+
+ // 启动心跳
+ startHeartbeat()
+
+ // 发送积压的消息
+ flushMessageQueue()
+
+ // 通知监听器
+ notifyConnected()
+ }
+
+ override fun onMessage(webSocket: WebSocket, text: String) {
+ LogUtils.d(TAG, "收到文本消息: $text")
+ handleReceivedMessage(text)
+ }
+
+ override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
+ LogUtils.d(TAG, "收到二进制消息, 长度: ${bytes.size}")
+ handleReceivedMessage(bytes)
+ }
+
+ override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
+ LogUtils.w(TAG, "WebSocket正在关闭: code=$code, reason=$reason")
+ isConnected.set(false)
+ stopHeartbeat()
+ }
+
+ override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
+ LogUtils.w(TAG, "WebSocket已关闭: code=$code, reason=$reason")
+ isConnected.set(false)
+ stopHeartbeat()
+ notifyDisconnected(code, reason)
+
+ // 根据关闭码决定是否重连
+ if (shouldReconnect(code)) {
+ scheduleReconnect()
+ }
+ }
+
+ override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
+ LogUtils.d(TAG, "WebSocket连接失败: ${t.message}")
+ isConnecting.set(false)
+ isConnected.set(false)
+ stopHeartbeat()
+ notifyConnectFailed(t)
+
+ // 失败时尝试重连
+ if (reconnectCount < config.MAX_RECONNECT_COUNT) {
+ scheduleReconnect()
+ }
+ }
+ }
+ }
+
+ /**
+ * 发送消息
+ */
+ fun sendMessage(message: String): Boolean {
+ return if (isConnected.get()) {
+ try {
+ webSocket?.send(message)
+ LogUtils.d(TAG, "发送消息成功: $message")
+ notifySendMessageSuccess(message)
+ true
+ } catch (e: Exception) {
+ LogUtils.d(TAG, "发送消息失败: ${e.message}")
+ cacheMessage(message)
+ notifySendMessageFailed(message, e)
+ false
+ }
+ } else {
+ LogUtils.w(TAG, "WebSocket未连接,缓存消息: $message")
+ cacheMessage(message)
+ false
+ }
+ }
+
+ /**
+ * 发送认证消息
+ */
+ private fun setAuthMessage(): Boolean {
+ return sendJsonMessage(
+ "auth", mapOf(
+ "appUserId" to com.xw.yunwei.Constants.user?.id,
+// "token" to com.xw.common.Constants.token,
+ )
+ )
+ }
+
+ /**
+ * 发送心跳消息
+ */
+ private fun setHeartbeatMessage(): Boolean {
+ return sendJsonMessage("ping")
+ }
+
+ /**
+ * 发送位置消息
+ */
+ private fun setPositionMessage(): Boolean {
+ return sendJsonMessage(
+ "position", mapOf(
+ "longitude" to com.xw.common.Constants.longitude,
+ "latitude" to com.xw.common.Constants.latitude,
+ "userId" to (Constants.user?.id ?: "0"),
+ )
+ )
+ }
+
+ /**
+ * 发送JSON消息
+ */
+ fun sendJsonMessage(type: String, data: Map<String, Any?> = emptyMap()): Boolean {
+ val json = try {
+ val jsonObject = JSONObject().apply {
+ put("type", type)
+ data.forEach { (key, value) ->
+ value?.also {
+ put(key, it.toString())
+ }
+ }
+ put("timestamp", System.currentTimeMillis())
+ }
+ jsonObject.toString()
+ } catch (e: Exception) {
+ LogUtils.d(TAG, "构建JSON失败: ${e.message}")
+ return false
+ }
+ return sendMessage(json)
+ }
+
+ /**
+ * 断开连接
+ */
+ fun disconnect(code: Int = 1000, reason: String = "normal closure") {
+ LogUtils.i(TAG, "主动断开WebSocket连接")
+
+ stopHeartbeat()
+ isConnecting.set(false)
+ isConnected.set(false)
+ reconnectCount = config.MAX_RECONNECT_COUNT // 阻止重连
+
+ webSocket?.close(code, reason)
+ webSocket = null
+
+ try {
+ okHttpClient?.dispatcher?.executorService?.shutdown()
+ okHttpClient?.connectionPool?.evictAll()
+ } catch (e: Exception) {
+ LogUtils.d(TAG, "清理资源失败: ${e.message}")
+ }
+ }
+
+ /**
+ * 重新连接
+ */
+ fun reconnect() {
+ if (isConnecting.get()) {
+ LogUtils.d(TAG, "已经在重连中...")
+ return
+ }
+
+ disconnect()
+ LogUtils.d(TAG, "开始重连...")
+ ioCoroutineScope.launch {
+ delay(1000) // 延迟1秒重连
+ connect(false)
+ }
+ }
+
+ /**
+ * 添加监听器
+ */
+ fun addListener(listener: IWebSocketListener) {
+ if (!listeners.contains(listener)) {
+ listeners.add(listener)
+ }
+ }
+
+ /**
+ * 移除监听器
+ */
+ fun removeListener(listener: IWebSocketListener) {
+ listeners.remove(listener)
+ }
+
+ /**
+ * 清除所有监听器
+ */
+ fun clearListeners() {
+ listeners.clear()
+ }
+
+ /**
+ * 获取连接状态
+ */
+ fun getConnectionState(): ConnectionState {
+ return when {
+ isConnected.get() -> ConnectionState.CONNECTED
+ isConnecting.get() -> ConnectionState.CONNECTING
+ else -> ConnectionState.DISCONNECTED
+ }
+ }
+
+ // 私有方法
+ private fun startHeartbeat() {
+ stopHeartbeat()
+
+ heartbeatJob = ioCoroutineScope.launch {
+ while (isActive && isConnected.get()) {
+ delay(config.PING_INTERVAL * 1000)
+ if (isConnected.get()) {
+ setAuthMessage()
+ setHeartbeatMessage()
+ setPositionMessage()
+ }
+ }
+ }
+ }
+
+ private fun stopHeartbeat() {
+ heartbeatJob?.cancel()
+ heartbeatJob = null
+ }
+
+ private fun scheduleReconnect() {
+ if (reconnectCount >= config.MAX_RECONNECT_COUNT) {
+ LogUtils.w(TAG, "已达到最大重连次数: ${config.MAX_RECONNECT_COUNT}")
+ return
+ }
+
+ reconnectCount++
+ val delay = config.RECONNECT_DELAY * reconnectCount // 退避策略
+
+ LogUtils.i(TAG, "计划 ${reconnectCount} 秒后重连")
+
+ ioCoroutineScope.launch {
+ delay(delay * 1000)
+ if (!isConnected.get() && !isConnecting.get()) {
+ connect(false)
+ }
+ }
+ }
+
+ private fun cacheMessage(message: String) {
+ synchronized(messageQueue) {
+ if (messageQueue.size >= maxQueueSize) {
+ messageQueue.poll() // 移除最旧的消息
+ }
+ messageQueue.offer(message)
+ }
+ }
+
+ private fun flushMessageQueue() {
+ synchronized(messageQueue) {
+ while (messageQueue.isNotEmpty()) {
+ messageQueue.poll()?.also {
+ sendMessage(it)
+ }
+ }
+ }
+ }
+
+ private fun handleReceivedMessage(text: String) {
+ try {
+ val json = JSONObject(text)
+ val type = json.optString("type")
+
+ when (type) {
+ "pong" -> {
+ // 心跳响应
+ LogUtils.d(TAG, "收到心跳响应")
+ }
+
+ else -> {
+ listeners.forEach { it.onMessage(text) }
+ }
+ }
+ } catch (e: Exception) {
+ LogUtils.d(TAG, "解析消息失败: ${e.message}")
+ listeners.forEach { it.onMessage(text) }
+ }
+ }
+
+ private fun handleReceivedMessage(bytes: ByteString) {
+ listeners.forEach { it.onMessage(bytes) }
+ }
+
+ private fun notifyConnected() {
+ listeners.forEach { it.onConnected() }
+ }
+
+ private fun notifyConnectFailed(t: Throwable) {
+ listeners.forEach { it.onConnectFailed(t) }
+ }
+
+ private fun notifyDisconnected(code: Int, reason: String) {
+ listeners.forEach { it.onDisconnected(code, reason) }
+ }
+
+ private fun notifySendMessageSuccess(message: String) {
+ listeners.forEach { it.onSendMessageSuccess(message) }
+ }
+
+ private fun notifySendMessageFailed(message: String, t: Throwable) {
+ listeners.forEach { it.onSendMessageFailed(message, t) }
+ }
+
+ private fun shouldReconnect(code: Int): Boolean {
+ // 正常关闭不重连
+ return false
+ }
+
+ enum class ConnectionState {
+ CONNECTING,
+ CONNECTED,
+ DISCONNECTED
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/websocket/WebSocketConfig.kt b/app/src/main/java/com/xw/yunwei/websocket/WebSocketConfig.kt
new file mode 100644
index 0000000..98bd773
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/websocket/WebSocketConfig.kt
@@ -0,0 +1,13 @@
+package com.xw.yunwei.websocket
+
+import com.xw.yunwei.BuildConfig
+
+// WebSocket配置
+object WebSocketConfig {
+ val WS_URL =
+ if (BuildConfig.DEV_WS_URL.isNotEmpty() && BuildConfig.DEBUG) BuildConfig.DEV_WS_URL else BuildConfig.WS_URL
+ const val WS_TIMEOUT = 10L // 连接超时(秒)
+ const val PING_INTERVAL = 5L // 心跳间隔(秒)
+ const val RECONNECT_DELAY = 3L // 重连延迟(秒)
+ const val MAX_RECONNECT_COUNT = 1200 // 最大重连次数
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/xw/yunwei/websocket/WebSocketManager.kt b/app/src/main/java/com/xw/yunwei/websocket/WebSocketManager.kt
new file mode 100644
index 0000000..0a42cbc
--- /dev/null
+++ b/app/src/main/java/com/xw/yunwei/websocket/WebSocketManager.kt
@@ -0,0 +1,237 @@
+package com.xw.yunwei.websocket
+
+import android.content.Context
+import android.net.ConnectivityManager
+import android.net.Network
+import android.net.NetworkCapabilities
+import android.net.NetworkRequest
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import com.xw.common.utils.LogUtils
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.flow.asSharedFlow
+import kotlinx.coroutines.launch
+import okio.ByteString
+
+// WebSocket管理器(单例)
+object WebSocketManager : IWebSocketListener {
+ private const val TAG = "WebSocketManager"
+ private lateinit var webSocketClient: WebSocketClient
+ private var isInitialized = false
+ private var enableConnect = false
+
+ private val mainCoroutineScope: CoroutineScope = CoroutineScope(Dispatchers.Main)
+
+ // 连接状态LiveData
+ private val _connectionState = MutableLiveData<WebSocketClient.ConnectionState>()
+ val connectionState: LiveData<WebSocketClient.ConnectionState> = _connectionState
+
+ // 消息LiveData
+ private val _messageEvent = MutableLiveData<Event<String>>()
+ val messageEvent: LiveData<Event<String>> = _messageEvent
+
+ // 事件Flow
+ private val _eventFlow = MutableSharedFlow<WebSocketEvent>()
+ val eventFlow: SharedFlow<WebSocketEvent> = _eventFlow.asSharedFlow()
+
+ /**
+ * 初始化
+ */
+ fun initialize(context: Context) {
+ if (isInitialized) return
+
+ webSocketClient = WebSocketClient()
+ webSocketClient.addListener(this)
+
+ // 监听网络状态
+ observeNetworkState(context)
+
+ isInitialized = true
+ LogUtils.i(TAG, "WebSocket管理器初始化完成")
+ }
+
+ /**
+ * 连接WebSocket
+ */
+ fun connect() {
+ if (!isInitialized) {
+ LogUtils.e(TAG, "请先调用initialize()初始化")
+ return
+ }
+ enableConnect = true
+ webSocketClient.connect(true)
+ }
+
+ /**
+ * 断开连接
+ */
+ fun disconnect() {
+ if (isInitialized) {
+ enableConnect = false
+ webSocketClient.disconnect()
+ }
+ }
+
+ /**
+ * 发送消息
+ */
+ fun sendMessage(message: String): Boolean {
+ return if (isInitialized) {
+ webSocketClient.sendMessage(message)
+ } else {
+ false
+ }
+ }
+
+ /**
+ * 发送JSON消息
+ */
+ fun sendJson(type: String, data: Map<String, Any> = emptyMap()): Boolean {
+ return if (isInitialized) {
+ webSocketClient.sendJsonMessage(type, data)
+ } else {
+ false
+ }
+ }
+
+ /**
+ * 重新连接
+ */
+ fun reconnect() {
+ if (isInitialized && enableConnect) {
+ webSocketClient.reconnect()
+ }
+ }
+
+ /**
+ * 获取连接状态
+ */
+ fun getConnectionState(): WebSocketClient.ConnectionState {
+ return if (isInitialized) {
+ webSocketClient.getConnectionState()
+ } else {
+ WebSocketClient.ConnectionState.DISCONNECTED
+ }
+ }
+
+ /**
+ * 清理资源
+ */
+ fun release() {
+ if (isInitialized) {
+ webSocketClient.disconnect()
+ webSocketClient.clearListeners()
+ isInitialized = false
+ }
+ }
+
+ // 实现IWebSocketListener接口
+ override fun onConnected() {
+ LogUtils.i(TAG, "WebSocket已连接")
+ _connectionState.postValue(WebSocketClient.ConnectionState.CONNECTED)
+
+ mainCoroutineScope.launch {
+ _eventFlow.emit(WebSocketEvent.Connected)
+ }
+ }
+
+ override fun onConnectFailed(t: Throwable) {
+ LogUtils.e(TAG, "连接失败: ${t.message}")
+ _connectionState.postValue(WebSocketClient.ConnectionState.DISCONNECTED)
+
+ mainCoroutineScope.launch {
+ _eventFlow.emit(WebSocketEvent.ConnectFailed(t))
+ }
+ }
+
+ override fun onMessage(text: String) {
+ LogUtils.d(TAG, "收到消息: $text")
+ _messageEvent.postValue(Event(text))
+
+ mainCoroutineScope.launch {
+ _eventFlow.emit(WebSocketEvent.Message(text))
+ }
+ }
+
+ override fun onMessage(bytes: ByteString) {
+ LogUtils.d(TAG, "收到二进制消息, 长度: ${bytes.size}")
+
+ mainCoroutineScope.launch {
+ _eventFlow.emit(WebSocketEvent.BinaryMessage(bytes))
+ }
+ }
+
+ override fun onDisconnected(code: Int, reason: String) {
+ LogUtils.w(TAG, "连接断开: code=$code, reason=$reason")
+ _connectionState.postValue(WebSocketClient.ConnectionState.DISCONNECTED)
+
+ mainCoroutineScope.launch {
+ _eventFlow.emit(WebSocketEvent.Disconnected(code, reason))
+ }
+ }
+
+ override fun onNetworkStateChanged(isAvailable: Boolean) {
+ if (isAvailable && getConnectionState() == WebSocketClient.ConnectionState.DISCONNECTED) {
+ // 网络恢复时重连
+ reconnect()
+ }
+ }
+
+ override fun onSendMessageSuccess(message: String) {
+ LogUtils.d(TAG, "发送消息成功: $message")
+ }
+
+ override fun onSendMessageFailed(message: String, t: Throwable) {
+ LogUtils.e(TAG, "发送消息失败: ${t.message}")
+ }
+
+ // 网络状态监听
+ private fun observeNetworkState(context: Context) {
+ val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE)
+ as ConnectivityManager
+
+ val networkCallback = object : ConnectivityManager.NetworkCallback() {
+ override fun onAvailable(network: Network) {
+ LogUtils.i(TAG, "网络已连接")
+ onNetworkStateChanged(true)
+ }
+
+ override fun onLost(network: Network) {
+ LogUtils.w(TAG, "网络已断开")
+ onNetworkStateChanged(false)
+ }
+ }
+
+ val request = NetworkRequest.Builder()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build()
+
+ connectivityManager.registerNetworkCallback(request, networkCallback)
+ }
+
+ // Event包装类(避免LiveData重复触发)
+ class Event<T>(private val content: T) {
+ private var hasBeenHandled = false
+
+ fun getContentIfNotHandled(): T? {
+ return if (hasBeenHandled) {
+ null
+ } else {
+ hasBeenHandled = true
+ content
+ }
+ }
+ }
+
+ // WebSocket事件密封类
+ sealed class WebSocketEvent {
+ object Connected : WebSocketEvent()
+ data class ConnectFailed(val throwable: Throwable) : WebSocketEvent()
+ data class Message(val text: String) : WebSocketEvent()
+ data class BinaryMessage(val bytes: ByteString) : WebSocketEvent()
+ data class Disconnected(val code: Int, val reason: String) : WebSocketEvent()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/circle_blue_5.xml b/app/src/main/res/drawable/circle_blue_5.xml
new file mode 100644
index 0000000..b1f55bd
--- /dev/null
+++ b/app/src/main/res/drawable/circle_blue_5.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval"
+ android:useLevel="false">
+ <solid android:color="@color/blue_5" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/circle_gray_6.xml b/app/src/main/res/drawable/circle_gray_6.xml
new file mode 100644
index 0000000..26aadc9
--- /dev/null
+++ b/app/src/main/res/drawable/circle_gray_6.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval"
+ android:useLevel="false">
+ <solid android:color="@color/gray_6" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/img_site_bg.xml b/app/src/main/res/drawable/img_site_bg.xml
new file mode 100644
index 0000000..0c6269e
--- /dev/null
+++ b/app/src/main/res/drawable/img_site_bg.xml
@@ -0,0 +1,52 @@
+<!--
+ ~ Copyright (C) 2026 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="68dp"
+ android:height="92dp"
+ android:viewportWidth="68"
+ android:viewportHeight="92">
+ <path
+ android:pathData="M4,0L64,0A4,4 0,0 1,68 4L68,88A4,4 0,0 1,64 92L4,92A4,4 0,0 1,0 88L0,4A4,4 0,0 1,4 0z"
+ android:fillColor="#F3F5F9"/>
+ <group>
+ <clip-path
+ android:pathData="M11,23h45v45h-45z"/>
+ <path
+ android:pathData="M55.374,45.504Q55.374,46.049 55.348,46.593Q55.321,47.137 55.267,47.679Q55.214,48.221 55.134,48.76Q55.054,49.299 54.948,49.833Q54.842,50.367 54.709,50.896Q54.577,51.424 54.419,51.945Q54.261,52.467 54.077,52.979Q53.894,53.492 53.685,53.996Q53.477,54.499 53.244,54.991Q53.011,55.484 52.754,55.964Q52.497,56.445 52.217,56.912Q51.937,57.379 51.635,57.832Q51.332,58.285 51.008,58.722Q50.683,59.16 50.338,59.581Q49.992,60.002 49.626,60.406Q49.261,60.809 48.875,61.195Q48.49,61.58 48.087,61.946Q47.683,62.311 47.262,62.657Q46.841,63.003 46.403,63.327Q45.966,63.652 45.513,63.954Q45.06,64.257 44.593,64.537Q44.126,64.817 43.645,65.074Q43.165,65.33 42.673,65.563Q42.18,65.796 41.677,66.005Q41.174,66.213 40.661,66.397Q40.148,66.58 39.627,66.738Q39.106,66.896 38.577,67.029Q38.049,67.161 37.515,67.267Q36.98,67.374 36.442,67.454Q35.903,67.534 35.361,67.587Q34.819,67.64 34.275,67.667Q33.731,67.694 33.186,67.694Q32.641,67.694 32.097,67.667Q31.553,67.64 31.011,67.587Q30.469,67.534 29.93,67.454Q29.391,67.374 28.857,67.267Q28.323,67.161 27.795,67.029Q27.266,66.896 26.745,66.738Q26.224,66.58 25.711,66.397Q25.198,66.213 24.695,66.005Q24.192,65.796 23.699,65.563Q23.207,65.33 22.727,65.074Q22.246,64.817 21.779,64.537Q21.312,64.257 20.859,63.954Q20.406,63.652 19.968,63.327Q19.531,63.003 19.11,62.657Q18.689,62.311 18.285,61.946Q17.882,61.58 17.497,61.195Q17.111,60.809 16.746,60.406Q16.38,60.002 16.034,59.581Q15.689,59.16 15.364,58.722Q15.04,58.285 14.737,57.832Q14.435,57.379 14.154,56.912Q13.874,56.445 13.618,55.964Q13.361,55.484 13.128,54.991Q12.895,54.499 12.687,53.996Q12.478,53.492 12.295,52.979Q12.111,52.467 11.953,51.945Q11.795,51.424 11.663,50.896Q11.53,50.367 11.424,49.833Q11.318,49.299 11.238,48.76Q11.158,48.221 11.105,47.679Q11.051,47.137 11.024,46.593Q10.998,46.049 10.998,45.504Q10.998,44.959 11.024,44.415Q11.051,43.871 11.105,43.329Q11.158,42.787 11.238,42.248Q11.318,41.709 11.424,41.175Q11.53,40.64 11.663,40.112Q11.795,39.584 11.953,39.062Q12.111,38.541 12.295,38.028Q12.478,37.515 12.687,37.012Q12.895,36.509 13.128,36.016Q13.361,35.524 13.618,35.043Q13.874,34.563 14.154,34.096Q14.435,33.629 14.737,33.176Q15.04,32.723 15.364,32.285Q15.689,31.848 16.034,31.427Q16.38,31.005 16.746,30.602Q17.111,30.198 17.497,29.813Q17.882,29.428 18.285,29.062Q18.689,28.696 19.11,28.351Q19.531,28.005 19.968,27.681Q20.406,27.356 20.859,27.053Q21.312,26.751 21.779,26.471Q22.246,26.191 22.727,25.934Q23.207,25.677 23.699,25.444Q24.192,25.211 24.695,25.003Q25.198,24.794 25.711,24.611Q26.224,24.427 26.745,24.269Q27.266,24.111 27.795,23.979Q28.323,23.846 28.857,23.74Q29.391,23.634 29.93,23.554Q30.469,23.474 31.011,23.421Q31.553,23.367 32.097,23.34Q32.641,23.314 33.186,23.314Q33.731,23.314 34.275,23.34Q34.819,23.367 35.361,23.421Q35.903,23.474 36.442,23.554Q36.98,23.634 37.515,23.74Q38.049,23.846 38.577,23.979Q39.106,24.111 39.627,24.269Q40.148,24.427 40.661,24.611Q41.174,24.794 41.677,25.003Q42.18,25.211 42.673,25.444Q43.165,25.677 43.645,25.934Q44.126,26.191 44.593,26.471Q45.06,26.751 45.513,27.053Q45.966,27.356 46.403,27.681Q46.841,28.005 47.262,28.351Q47.683,28.696 48.087,29.062Q48.49,29.428 48.875,29.813Q49.261,30.198 49.626,30.602Q49.992,31.005 50.338,31.427Q50.683,31.848 51.008,32.285Q51.332,32.723 51.635,33.176Q51.937,33.629 52.217,34.096Q52.497,34.563 52.754,35.043Q53.011,35.524 53.244,36.016Q53.477,36.509 53.685,37.012Q53.894,37.515 54.077,38.028Q54.261,38.541 54.419,39.062Q54.577,39.584 54.709,40.112Q54.842,40.64 54.948,41.175Q55.054,41.709 55.134,42.248Q55.214,42.787 55.267,43.329Q55.321,43.871 55.348,44.415Q55.374,44.959 55.374,45.504Z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M13.882,34.571L31.609,52.296L20.327,63.575C11.066,56.985 8.284,44.463 13.882,34.571Z"
+ android:strokeAlpha="0.241"
+ android:fillColor="#38CF99"
+ android:fillAlpha="0.241"/>
+ <path
+ android:pathData="M33.189,67.686C45.442,67.686 55.375,57.753 55.375,45.5C55.375,44.029 55.229,42.562 54.938,41.12L28.812,67.249C30.254,67.54 31.718,67.686 33.191,67.686L33.189,67.686Z"
+ android:strokeAlpha="0.241"
+ android:fillColor="#FF8549"
+ android:fillAlpha="0.241"/>
+ <path
+ android:pathData="M51.266,32.636L37.488,46.414L19.289,28.21C29.237,20.212 43.865,22.237 51.266,32.636Z"
+ android:strokeAlpha="0.241"
+ android:fillColor="#3B8CFF"
+ android:fillAlpha="0.241"/>
+ <path
+ android:pathData="M33.188,34.407C28.283,34.407 24.313,37.95 24.313,42.341C24.313,45.831 29.935,53.234 32.223,56.143C32.728,56.741 33.65,56.741 34.155,56.143C36.44,53.236 42.062,45.833 42.062,42.341C42.062,37.95 38.098,34.407 33.188,34.407ZM33.188,44.985C31.553,44.985 30.233,43.803 30.233,42.341C30.233,40.876 31.553,39.696 33.19,39.696C34.825,39.696 36.145,40.876 36.145,42.341C36.145,43.805 34.825,44.985 33.19,44.985L33.188,44.985Z"
+ android:fillColor="#3B9DFF"/>
+ <path
+ android:pathData="M36.516,42.172Q36.516,42.336 36.5,42.498Q36.484,42.661 36.452,42.821Q36.42,42.982 36.373,43.138Q36.325,43.295 36.263,43.446Q36.2,43.597 36.123,43.741Q36.046,43.885 35.955,44.021Q35.865,44.157 35.761,44.283Q35.657,44.41 35.541,44.525Q35.426,44.641 35.3,44.745Q35.173,44.848 35.037,44.939Q34.901,45.03 34.757,45.107Q34.613,45.184 34.462,45.247Q34.311,45.309 34.154,45.357Q33.998,45.404 33.838,45.436Q33.677,45.468 33.514,45.484Q33.352,45.5 33.188,45.5Q33.025,45.5 32.862,45.484Q32.699,45.468 32.539,45.436Q32.379,45.404 32.222,45.357Q32.066,45.309 31.915,45.247Q31.764,45.184 31.62,45.107Q31.475,45.03 31.339,44.939Q31.203,44.848 31.077,44.745Q30.951,44.641 30.835,44.525Q30.719,44.41 30.616,44.283Q30.512,44.157 30.421,44.021Q30.33,43.885 30.253,43.741Q30.176,43.597 30.114,43.446Q30.051,43.295 30.004,43.138Q29.956,42.982 29.924,42.821Q29.892,42.661 29.876,42.498Q29.86,42.336 29.86,42.172Q29.86,42.009 29.876,41.846Q29.892,41.683 29.924,41.523Q29.956,41.363 30.004,41.206Q30.051,41.05 30.114,40.899Q30.176,40.748 30.253,40.603Q30.33,40.459 30.421,40.323Q30.512,40.187 30.616,40.061Q30.719,39.935 30.835,39.819Q30.951,39.703 31.077,39.6Q31.203,39.496 31.339,39.405Q31.475,39.314 31.62,39.237Q31.764,39.16 31.915,39.098Q32.066,39.035 32.222,38.988Q32.379,38.94 32.539,38.908Q32.699,38.876 32.862,38.86Q33.025,38.844 33.188,38.844Q33.352,38.844 33.514,38.86Q33.677,38.876 33.838,38.908Q33.998,38.94 34.154,38.988Q34.311,39.035 34.462,39.098Q34.613,39.16 34.757,39.237Q34.901,39.314 35.037,39.405Q35.173,39.496 35.3,39.6Q35.426,39.703 35.541,39.819Q35.657,39.935 35.761,40.061Q35.865,40.187 35.955,40.323Q36.046,40.459 36.123,40.603Q36.2,40.748 36.263,40.899Q36.325,41.05 36.373,41.206Q36.42,41.363 36.452,41.523Q36.484,41.683 36.5,41.846Q36.516,42.009 36.516,42.172Z"
+ android:fillColor="#FFFFFF"/>
+ </group>
+</vector>
diff --git a/app/src/main/res/drawable/layer_list_green_progress_bar.xml b/app/src/main/res/drawable/layer_list_green_progress_bar.xml
new file mode 100644
index 0000000..e10cd56
--- /dev/null
+++ b/app/src/main/res/drawable/layer_list_green_progress_bar.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- 背景 -->
+ <item android:id="@android:id/background">
+ <shape>
+ <corners android:radius="@dimen/dp_8" />
+ <solid android:color="@color/gray_5" />
+ </shape>
+ </item>
+
+ <!-- 主进度 -->
+ <item android:id="@android:id/progress">
+ <clip>
+ <shape>
+ <corners android:radius="@dimen/dp_8" />
+ <solid android:color="@color/green_5" />
+ </shape>
+ </clip>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/layer_list_orange_progress_bar.xml b/app/src/main/res/drawable/layer_list_orange_progress_bar.xml
new file mode 100644
index 0000000..49a2328
--- /dev/null
+++ b/app/src/main/res/drawable/layer_list_orange_progress_bar.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- 背景 -->
+ <item android:id="@android:id/background">
+ <shape>
+ <corners android:radius="@dimen/dp_8" />
+ <solid android:color="@color/gray_5" />
+ </shape>
+ </item>
+
+ <!-- 主进度 -->
+ <item android:id="@android:id/progress">
+ <clip>
+ <shape>
+ <corners android:radius="@dimen/dp_8" />
+ <solid android:color="@color/orange_5" />
+ </shape>
+ </clip>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ps_demo_blue_num_normal.xml b/app/src/main/res/drawable/ps_demo_blue_num_normal.xml
new file mode 100644
index 0000000..e1a43af
--- /dev/null
+++ b/app/src/main/res/drawable/ps_demo_blue_num_normal.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval"
+ android:useLevel="false">
+
+ <solid android:color="@color/ps_color_transparent" />
+ <stroke
+ android:width="1dp"
+ android:color="@color/ps_color_white" />
+ <size
+ android:width="18dp"
+ android:height="18dp" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ps_demo_blue_num_selected.xml b/app/src/main/res/drawable/ps_demo_blue_num_selected.xml
new file mode 100644
index 0000000..906646c
--- /dev/null
+++ b/app/src/main/res/drawable/ps_demo_blue_num_selected.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval"
+ android:useLevel="false">
+
+ <solid android:color="@color/color_00c25c" />
+ <size
+ android:width="18dp"
+ android:height="18dp" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ps_demo_blue_num_selector.xml b/app/src/main/res/drawable/ps_demo_blue_num_selector.xml
new file mode 100644
index 0000000..3bebbd6
--- /dev/null
+++ b/app/src/main/res/drawable/ps_demo_blue_num_selector.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/ps_demo_blue_num_normal" android:state_selected="false" />
+ <item android:drawable="@drawable/ps_demo_blue_num_selected" android:state_selected="true" />
+</selector>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/selector_car_trunk.xml b/app/src/main/res/drawable/selector_car_trunk.xml
new file mode 100644
index 0000000..a2800c3
--- /dev/null
+++ b/app/src/main/res/drawable/selector_car_trunk.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/svg_car_trunk_closed" android:state_selected="false" />
+ <item android:drawable="@drawable/svg_car_hbxjs" android:state_selected="true" />
+</selector>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/selector_gray2_to_blue1_bg_4.xml b/app/src/main/res/drawable/selector_gray2_to_blue1_bg_4.xml
new file mode 100644
index 0000000..236bbaa
--- /dev/null
+++ b/app/src/main/res/drawable/selector_gray2_to_blue1_bg_4.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/shape_blue1_bg_4" android:state_selected="true" />
+ <item android:drawable="@drawable/shape_gray2_bg_4" android:state_selected="false" />
+
+</selector>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/selector_nav_task_accident.xml b/app/src/main/res/drawable/selector_nav_task_accident.xml
new file mode 100644
index 0000000..68dae4e
--- /dev/null
+++ b/app/src/main/res/drawable/selector_nav_task_accident.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@mipmap/icon_note_triangle" android:state_selected="true"/>
+ <item android:drawable="@mipmap/icon_note_triangle2"/>
+</selector>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/selector_nav_task_all.xml b/app/src/main/res/drawable/selector_nav_task_all.xml
new file mode 100644
index 0000000..2079f6b
--- /dev/null
+++ b/app/src/main/res/drawable/selector_nav_task_all.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@mipmap/icon_tick_double_rect" android:state_selected="true"/>
+ <item android:drawable="@mipmap/icon_tick_double_rect2"/>
+</selector>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/selector_nav_task_normal.xml b/app/src/main/res/drawable/selector_nav_task_normal.xml
new file mode 100644
index 0000000..abbe058
--- /dev/null
+++ b/app/src/main/res/drawable/selector_nav_task_normal.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@mipmap/icon_note_tick_circle" android:state_selected="true"/>
+ <item android:drawable="@mipmap/icon_note_tick_circle2"/>
+</selector>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/selector_switch_off_on.xml b/app/src/main/res/drawable/selector_switch_off_on.xml
new file mode 100644
index 0000000..36ea723
--- /dev/null
+++ b/app/src/main/res/drawable/selector_switch_off_on.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@mipmap/icon_switch_on" android:state_checked="true" />
+ <item android:drawable="@mipmap/icon_switch_off" android:state_checked="false" />
+</selector>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/selector_task_bottom_nav.xml b/app/src/main/res/drawable/selector_task_bottom_nav.xml
new file mode 100644
index 0000000..1f87b20
--- /dev/null
+++ b/app/src/main/res/drawable/selector_task_bottom_nav.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@color/color_4c5e7e" android:state_selected="true" />
+ <item android:color="@color/gray_7" android:state_selected="false"/>
+</selector>
+
diff --git a/app/src/main/res/drawable/shape_0d31456a_0031456a_bg_4.xml b/app/src/main/res/drawable/shape_0d31456a_0031456a_bg_4.xml
new file mode 100644
index 0000000..b0868c8
--- /dev/null
+++ b/app/src/main/res/drawable/shape_0d31456a_0031456a_bg_4.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <gradient
+ android:angle="-90"
+ android:endColor="@color/color_0031456a"
+ android:startColor="@color/color_0d31456a" />
+ <corners android:radius="@dimen/dp_4" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_0d31456a_bg_8.xml b/app/src/main/res/drawable/shape_0d31456a_bg_8.xml
new file mode 100644
index 0000000..9c1e509
--- /dev/null
+++ b/app/src/main/res/drawable/shape_0d31456a_bg_8.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="@color/color_0d31456a" />
+ <corners android:radius="@dimen/dp_8" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_blue1_00006be1_bg_4.xml b/app/src/main/res/drawable/shape_blue1_00006be1_bg_4.xml
new file mode 100644
index 0000000..1ab774f
--- /dev/null
+++ b/app/src/main/res/drawable/shape_blue1_00006be1_bg_4.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <gradient
+ android:endColor="@color/color_00006be1"
+ android:startColor="@color/blue_1" />
+ <corners android:radius="@dimen/dp_4" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_blue_1_bg_2.xml b/app/src/main/res/drawable/shape_blue_1_bg_2.xml
new file mode 100644
index 0000000..cab645d
--- /dev/null
+++ b/app/src/main/res/drawable/shape_blue_1_bg_2.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="@dimen/dp_2" />
+ <solid android:color="@color/blue_1" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_ccffffff_bg_80ffffff_line_30.xml b/app/src/main/res/drawable/shape_ccffffff_bg_80ffffff_line_30.xml
new file mode 100644
index 0000000..6a1af98
--- /dev/null
+++ b/app/src/main/res/drawable/shape_ccffffff_bg_80ffffff_line_30.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <stroke
+ android:width="1px"
+ android:color="@color/color_80ffffff" />
+ <solid android:color="@color/color_ccffffff" />
+ <corners android:radius="@dimen/dp_30" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_e5f0fc_bg_2.xml b/app/src/main/res/drawable/shape_e5f0fc_bg_2.xml
new file mode 100644
index 0000000..21d5b7b
--- /dev/null
+++ b/app/src/main/res/drawable/shape_e5f0fc_bg_2.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="@dimen/dp_2" />
+ <solid android:color="@color/color_e5f0fc" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_fdedeb_bg_2.xml b/app/src/main/res/drawable/shape_fdedeb_bg_2.xml
new file mode 100644
index 0000000..25e8fa7
--- /dev/null
+++ b/app/src/main/res/drawable/shape_fdedeb_bg_2.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="@dimen/dp_2" />
+ <solid android:color="@color/color_fdedeb" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_gray11_bg_4.xml b/app/src/main/res/drawable/shape_gray11_bg_4.xml
new file mode 100644
index 0000000..9ea3c56
--- /dev/null
+++ b/app/src/main/res/drawable/shape_gray11_bg_4.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="@dimen/dp_4" />
+ <solid android:color="@color/gray_11" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_gray2_bg_4.xml b/app/src/main/res/drawable/shape_gray2_bg_4.xml
new file mode 100644
index 0000000..f30626d
--- /dev/null
+++ b/app/src/main/res/drawable/shape_gray2_bg_4.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="@dimen/dp_4" />
+ <solid android:color="@color/gray_2" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_gray_4_bg_4.xml b/app/src/main/res/drawable/shape_gray_4_bg_4.xml
new file mode 100644
index 0000000..410c88a
--- /dev/null
+++ b/app/src/main/res/drawable/shape_gray_4_bg_4.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="@dimen/dp_4" />
+ <solid android:color="@color/gray_4" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_gray_4_line_gray_3_bg_4.xml b/app/src/main/res/drawable/shape_gray_4_line_gray_3_bg_4.xml
new file mode 100644
index 0000000..8159de8
--- /dev/null
+++ b/app/src/main/res/drawable/shape_gray_4_line_gray_3_bg_4.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <stroke
+ android:width="@dimen/dp_1"
+ android:color="@color/gray_4" />
+ <corners android:radius="@dimen/dp_4" />
+ <solid android:color="@color/gray_3" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_gray_5_bg_4.xml b/app/src/main/res/drawable/shape_gray_5_bg_4.xml
new file mode 100644
index 0000000..f134bfc
--- /dev/null
+++ b/app/src/main/res/drawable/shape_gray_5_bg_4.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="@dimen/dp_4" />
+ <solid android:color="@color/gray_5" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_gray_5_line_4.xml b/app/src/main/res/drawable/shape_gray_5_line_4.xml
new file mode 100644
index 0000000..a656c72
--- /dev/null
+++ b/app/src/main/res/drawable/shape_gray_5_line_4.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <stroke
+ android:width="1px"
+ android:color="@color/gray_5" />
+ <corners android:radius="@dimen/dp_4" />
+
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_green_1_bg_2.xml b/app/src/main/res/drawable/shape_green_1_bg_2.xml
new file mode 100644
index 0000000..007a2de
--- /dev/null
+++ b/app/src/main/res/drawable/shape_green_1_bg_2.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="@dimen/dp_2" />
+ <solid android:color="@color/green_1" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_orange_1_bg_2.xml b/app/src/main/res/drawable/shape_orange_1_bg_2.xml
new file mode 100644
index 0000000..5f68787
--- /dev/null
+++ b/app/src/main/res/drawable/shape_orange_1_bg_2.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="@dimen/dp_2" />
+ <solid android:color="@color/orange_1" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_red_1_bg_2.xml b/app/src/main/res/drawable/shape_red_1_bg_2.xml
new file mode 100644
index 0000000..695d084
--- /dev/null
+++ b/app/src/main/res/drawable/shape_red_1_bg_2.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="@dimen/dp_2" />
+ <solid android:color="@color/red_1" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_red_1_bg_4.xml b/app/src/main/res/drawable/shape_red_1_bg_4.xml
new file mode 100644
index 0000000..7ec044a
--- /dev/null
+++ b/app/src/main/res/drawable/shape_red_1_bg_4.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="@dimen/dp_4" />
+ <solid android:color="@color/red_1" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_red_5_bg_white_line_20.xml b/app/src/main/res/drawable/shape_red_5_bg_white_line_20.xml
new file mode 100644
index 0000000..0001acd
--- /dev/null
+++ b/app/src/main/res/drawable/shape_red_5_bg_white_line_20.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="@color/red_5" />
+ <corners android:radius="@dimen/dp_20" />
+ <stroke
+ android:width="@dimen/dp_1"
+ android:color="@color/white" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_red_5_line_gray_3_bg_4.xml b/app/src/main/res/drawable/shape_red_5_line_gray_3_bg_4.xml
new file mode 100644
index 0000000..3521d13
--- /dev/null
+++ b/app/src/main/res/drawable/shape_red_5_line_gray_3_bg_4.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <stroke
+ android:width="@dimen/dp_1"
+ android:color="@color/red_5" />
+ <corners android:radius="@dimen/dp_4" />
+ <solid android:color="@color/gray_3" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_while_bg_100.xml b/app/src/main/res/drawable/shape_while_bg_100.xml
index 17fd22c..21d0c6c 100644
--- a/app/src/main/res/drawable/shape_while_bg_100.xml
+++ b/app/src/main/res/drawable/shape_while_bg_100.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="@color/white" />
+ <solid android:color="@color/color_ccffffff" />
<corners android:radius="@dimen/dp_100" />
</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_white_bg_8.xml b/app/src/main/res/drawable/shape_white_bg_8.xml
new file mode 100644
index 0000000..b3fb883
--- /dev/null
+++ b/app/src/main/res/drawable/shape_white_bg_8.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="@dimen/dp_8" />
+ <solid android:color="@color/white" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/svg_car_trunk_closed.xml b/app/src/main/res/drawable/svg_car_trunk_closed.xml
new file mode 100644
index 0000000..62121e1
--- /dev/null
+++ b/app/src/main/res/drawable/svg_car_trunk_closed.xml
@@ -0,0 +1,29 @@
+<!--
+ ~ Copyright (C) 2026 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="32"
+ android:viewportHeight="32">
+ <group>
+ <clip-path
+ android:pathData="M0,0h32v32h-32z"/>
+ <path
+ android:pathData="M8.057,10.323C10.944,10.094 12.889,10.29 15.022,10.99L15.418,11.128C16.047,11.36 16.828,11.697 17.779,12.139L18.612,12.533C19.121,12.777 20.599,13.5 21.074,13.734L21.207,13.799L23.385,14.545L23.508,14.586C23.88,14.707 24.123,15.069 24.096,15.463L24.065,15.913C24.037,16.386 24.072,16.824 24.173,17.277L24.404,18.372L24.714,19.967C24.747,20.137 24.727,20.313 24.659,20.471L23.532,23.09C23.41,23.372 23.149,23.567 22.848,23.6L20.468,23.866L20.44,23.934C19.861,25.235 18.615,26.1 17.209,26.18L17.004,26.185C15.531,26.183 14.193,25.313 13.578,23.958L13.557,23.91L8.156,23.91C7.728,23.91 7.367,23.588 7.313,23.158L7.307,23.051C7.307,22.576 7.687,22.192 8.156,22.192L14.076,22.192C14.466,22.192 14.809,22.431 14.956,22.782L14.998,22.905C15.243,23.823 16.064,24.463 17.004,24.467C17.886,24.467 18.657,23.901 18.955,23.074L19.008,22.905C19.123,22.484 19.5,22.193 19.931,22.193L19.979,22.197L22.171,21.948L22.997,20.028L22.811,19.066L22.552,17.805C22.419,17.275 22.355,16.729 22.36,16.182L22.364,16.012L21.06,15.565C20.876,15.501 20.734,15.452 20.569,15.388L17.886,14.086L17.388,13.849C16.126,13.255 15.164,12.841 14.499,12.624C12.589,11.997 10.864,11.823 8.191,12.036C7.722,12.076 7.31,11.723 7.273,11.248C7.236,10.773 7.588,10.358 8.057,10.323Z"
+ android:fillColor="#31456A"
+ android:fillAlpha="0.6"/>
+ </group>
+</vector>
diff --git a/app/src/main/res/drawable/svg_circle_loading.xml b/app/src/main/res/drawable/svg_circle_loading.xml
new file mode 100644
index 0000000..67a920a
--- /dev/null
+++ b/app/src/main/res/drawable/svg_circle_loading.xml
@@ -0,0 +1,40 @@
+<!--
+ ~ Copyright (C) 2026 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="32"
+ android:viewportHeight="32">
+ <group>
+ <clip-path
+ android:pathData="M-1,-1h34v34h-34z"/>
+ <path
+ android:pathData="M8.929,8.929Q11.858,6 16,6Q20.142,6 23.071,8.929Q26,11.858 26,16L26,16Q26,16.098 25.981,16.195Q25.961,16.292 25.924,16.383Q25.886,16.474 25.831,16.555Q25.777,16.637 25.707,16.707Q25.637,16.777 25.555,16.831Q25.474,16.886 25.383,16.924Q25.292,16.961 25.195,16.981Q25.098,17 25,17Q24.902,17 24.805,16.981Q24.708,16.961 24.617,16.924Q24.526,16.886 24.445,16.831Q24.363,16.777 24.293,16.707Q24.223,16.637 24.169,16.555Q24.114,16.474 24.076,16.383Q24.039,16.292 24.019,16.195Q24,16.098 24,16L24,16Q24,12.686 21.657,10.343Q19.314,8 16,8Q12.686,8 10.343,10.343Q8,12.686 8,16Q8,19.314 10.343,21.657Q12.686,24 16,24Q20.337,24 22.708,20.36L22.709,20.361Q22.777,20.256 22.868,20.171Q22.96,20.087 23.07,20.027Q23.18,19.968 23.301,19.937Q23.422,19.906 23.546,19.906Q23.645,19.906 23.741,19.926Q23.838,19.945 23.929,19.983Q24.02,20.02 24.102,20.075Q24.184,20.13 24.253,20.199Q24.323,20.269 24.378,20.351Q24.432,20.433 24.47,20.524Q24.508,20.615 24.527,20.711Q24.546,20.808 24.546,20.906Q24.546,21.203 24.384,21.452L24.384,21.452Q21.421,26 16,26Q11.858,26 8.929,23.071Q6,20.142 6,16Q6,11.858 8.929,8.929Z"
+ android:fillType="evenOdd">
+ <aapt:attr name="android:fillColor">
+ <gradient
+ android:centerX="16"
+ android:centerY="16"
+ android:gradientRadius="9"
+ android:type="radial">
+ <item android:offset="0.928" android:color="#00006BE1"/>
+ <item android:offset="0.979" android:color="#FF006BE1"/>
+ </gradient>
+ </aapt:attr>
+ </path>
+ </group>
+</vector>
diff --git a/app/src/main/res/drawable/svg_net_lock_gray.xml b/app/src/main/res/drawable/svg_net_lock_gray.xml
new file mode 100644
index 0000000..236d04e
--- /dev/null
+++ b/app/src/main/res/drawable/svg_net_lock_gray.xml
@@ -0,0 +1,43 @@
+<!--
+ ~ Copyright (C) 2026 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="32"
+ android:viewportHeight="32">
+ <group>
+ <clip-path
+ android:pathData="M-0.75,-0.75h33.5v33.5h-33.5z"/>
+ <path
+ android:pathData="M6.554,11.966Q6.295,12.9 6.25,14.631L6.25,14.631Q6.25,14.64 6.25,14.65Q6.25,14.724 6.265,14.796Q6.279,14.869 6.307,14.937Q6.335,15.005 6.377,15.067Q6.418,15.128 6.47,15.18Q6.522,15.232 6.583,15.273Q6.645,15.315 6.713,15.343Q6.781,15.371 6.854,15.385Q6.926,15.4 7,15.4Q7.073,15.4 7.144,15.386Q7.215,15.372 7.282,15.345Q7.35,15.317 7.411,15.277Q7.471,15.238 7.523,15.187Q7.575,15.136 7.617,15.077Q7.658,15.017 7.687,14.95Q7.716,14.884 7.732,14.813Q7.748,14.742 7.75,14.669L7.75,14.669Q7.79,13.123 8,12.368Q8.21,11.609 8.716,11.18Q9.399,10.6 10.91,10.427Q12.026,10.3 15.491,10.3L15.491,10.3Q15.565,10.3 15.638,10.285Q15.71,10.271 15.778,10.243Q15.847,10.215 15.908,10.173Q15.969,10.132 16.022,10.08Q16.074,10.028 16.115,9.967Q16.156,9.905 16.184,9.837Q16.213,9.769 16.227,9.696Q16.241,9.624 16.241,9.55Q16.241,9.476 16.227,9.404Q16.213,9.331 16.184,9.263Q16.156,9.195 16.115,9.133Q16.074,9.072 16.022,9.02Q15.969,8.968 15.908,8.927Q15.847,8.886 15.778,8.857Q15.71,8.829 15.638,8.815Q15.565,8.8 15.491,8.8L15.491,8.8Q11.94,8.8 10.74,8.937Q8.776,9.161 7.746,10.036Q6.889,10.763 6.554,11.966ZM24.75,16.775L24.75,16.775Q24.75,19.813 24.585,20.855Q24.308,22.606 23.24,23.514Q22.337,24.28 20.79,24.537Q19.64,24.729 17.199,24.747L16.346,24.75L16.346,24.75L16.343,24.75Q16.269,24.75 16.197,24.735Q16.124,24.721 16.056,24.693Q15.988,24.665 15.927,24.623Q15.865,24.582 15.813,24.53Q15.761,24.478 15.72,24.417Q15.679,24.355 15.65,24.287Q15.622,24.219 15.608,24.146Q15.593,24.074 15.593,24Q15.593,23.926 15.608,23.854Q15.622,23.782 15.65,23.714Q15.678,23.646 15.719,23.584Q15.76,23.523 15.812,23.471Q15.864,23.419 15.925,23.378Q15.986,23.336 16.054,23.308Q16.122,23.28 16.194,23.265Q16.267,23.25 16.34,23.25L16.34,23.25L17.188,23.247Q19.51,23.23 20.544,23.058Q21.682,22.868 22.268,22.371Q22.913,21.823 23.103,20.621Q23.25,19.695 23.25,16.775L23.25,16.775Q23.25,16.701 23.265,16.629Q23.279,16.556 23.307,16.488Q23.335,16.42 23.376,16.358Q23.418,16.297 23.47,16.245Q23.522,16.193 23.583,16.152Q23.645,16.11 23.713,16.082Q23.781,16.054 23.854,16.04Q23.926,16.025 24,16.025Q24.074,16.025 24.146,16.04Q24.219,16.054 24.287,16.082Q24.355,16.11 24.417,16.152Q24.478,16.193 24.53,16.245Q24.582,16.297 24.623,16.358Q24.664,16.42 24.693,16.488Q24.721,16.556 24.735,16.629Q24.75,16.701 24.75,16.775Z"
+ android:fillColor="#31456A"
+ android:fillAlpha="0.6"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M22.571,10.507L22.571,9.214C22.571,8.267 21.804,7.5 20.857,7.5L20.286,7.5C19.339,7.5 18.571,8.267 18.571,9.214L18.571,10.507C17.692,10.58 17,11.316 17,12.214L17,13.786C17,14.732 17.768,15.5 18.714,15.5L22.429,15.5C23.375,15.5 24.143,14.732 24.143,13.786L24.143,12.214C24.143,11.316 23.451,10.58 22.571,10.507ZM19.286,9.214C19.286,8.663 19.734,8.214 20.286,8.214L20.857,8.214C21.409,8.214 21.857,8.663 21.857,9.214L21.857,10.5L19.286,10.5L19.286,9.214ZM23.429,13.786C23.429,14.337 22.98,14.786 22.429,14.786L18.714,14.786C18.163,14.786 17.714,14.337 17.714,13.786L17.714,12.214C17.714,11.663 18.163,11.214 18.714,11.214L22.429,11.214C22.98,11.214 23.429,11.663 23.429,12.214L23.429,13.786Z"
+ android:fillColor="#31456A"
+ android:fillAlpha="0.6"/>
+ <path
+ android:pathData="M24.443,13.786L24.443,12.214Q24.443,11.425 23.907,10.847Q23.472,10.377 22.871,10.249L22.871,9.214Q22.871,8.38 22.281,7.79Q21.691,7.2 20.857,7.2L20.286,7.2Q19.451,7.2 18.861,7.79Q18.271,8.38 18.271,9.214L18.271,10.249Q17.671,10.377 17.236,10.847Q16.7,11.425 16.7,12.214L16.7,13.786Q16.7,14.62 17.29,15.21Q17.88,15.8 18.714,15.8L22.429,15.8Q23.263,15.8 23.853,15.21Q24.443,14.62 24.443,13.786ZM23.467,11.255Q23.843,11.661 23.843,12.214L23.843,13.786Q23.843,14.371 23.429,14.786Q23.014,15.2 22.429,15.2L18.714,15.2Q18.128,15.2 17.714,14.786Q17.3,14.371 17.3,13.786L17.3,12.214Q17.3,11.661 17.676,11.255Q18.05,10.851 18.596,10.806L18.871,10.783L18.871,9.214Q18.871,8.628 19.286,8.214Q19.7,7.8 20.286,7.8L20.857,7.8Q21.443,7.8 21.857,8.214Q22.271,8.628 22.271,9.214L22.271,10.783L22.547,10.806Q23.093,10.851 23.467,11.255ZM18.986,9.214L18.986,10.8L22.157,10.8L22.157,9.214Q22.157,8.676 21.776,8.295Q21.395,7.914 20.857,7.914L20.286,7.914Q19.748,7.914 19.367,8.295Q18.986,8.676 18.986,9.214ZM19.586,10.2L21.557,10.2L21.557,9.214Q21.557,8.925 21.352,8.72Q21.146,8.514 20.857,8.514L20.286,8.514Q19.996,8.514 19.791,8.72Q19.586,8.925 19.586,9.214L19.586,10.2ZM23.729,13.786L23.729,12.214Q23.729,11.676 23.347,11.295Q22.966,10.914 22.429,10.914L18.714,10.914Q18.176,10.914 17.795,11.295Q17.414,11.676 17.414,12.214L17.414,13.786Q17.414,14.323 17.795,14.705Q18.176,15.086 18.714,15.086L22.429,15.086Q22.966,15.086 23.347,14.705Q23.729,14.323 23.729,13.786ZM22.923,11.72Q23.129,11.925 23.129,12.214L23.129,13.786Q23.129,14.075 22.923,14.28Q22.718,14.486 22.429,14.486L18.714,14.486Q18.425,14.486 18.22,14.28Q18.014,14.075 18.014,13.786L18.014,12.214Q18.014,11.925 18.22,11.72Q18.425,11.514 18.714,11.514L22.429,11.514Q22.718,11.514 22.923,11.72Z"
+ android:fillColor="#7F8BA3"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M7.038,16.45Q8.439,16.45 9.806,17.035Q11.137,17.604 12.198,18.625Q14.55,20.886 14.55,24L14.55,24Q14.55,24.074 14.535,24.146Q14.521,24.219 14.493,24.287Q14.464,24.355 14.423,24.417Q14.382,24.478 14.33,24.53Q14.278,24.582 14.216,24.623Q14.155,24.664 14.087,24.693Q14.019,24.721 13.946,24.735Q13.874,24.75 13.8,24.75Q13.726,24.75 13.654,24.735Q13.581,24.721 13.513,24.693Q13.445,24.664 13.383,24.623Q13.322,24.582 13.27,24.53Q13.217,24.478 13.176,24.417Q13.135,24.355 13.107,24.287Q13.079,24.219 13.064,24.146Q13.05,24.074 13.05,24L13.05,24Q13.05,21.525 11.158,19.706Q9.332,17.95 7.038,17.95L7.038,17.95Q6.964,17.95 6.892,17.935Q6.819,17.921 6.751,17.893Q6.683,17.864 6.621,17.823Q6.56,17.782 6.508,17.73Q6.456,17.678 6.415,17.617Q6.374,17.555 6.345,17.487Q6.317,17.419 6.303,17.346Q6.288,17.274 6.288,17.2Q6.288,17.126 6.303,17.054Q6.317,16.981 6.345,16.913Q6.374,16.845 6.415,16.783Q6.456,16.722 6.508,16.67Q6.56,16.618 6.621,16.577Q6.683,16.535 6.751,16.507Q6.819,16.479 6.892,16.465Q6.964,16.45 7.038,16.45L7.038,16.45ZM10.304,24Q10.304,22.719 9.292,21.709Q8.28,20.7 7,20.7L7,20.7Q6.926,20.7 6.854,20.685Q6.781,20.671 6.713,20.642Q6.645,20.614 6.583,20.573Q6.522,20.532 6.47,20.48Q6.417,20.428 6.376,20.366Q6.335,20.305 6.307,20.237Q6.279,20.168 6.264,20.096Q6.25,20.024 6.25,19.95Q6.25,19.876 6.264,19.803Q6.279,19.731 6.307,19.663Q6.335,19.595 6.376,19.533Q6.417,19.472 6.47,19.42Q6.522,19.367 6.583,19.326Q6.645,19.285 6.713,19.257Q6.781,19.229 6.854,19.214Q6.926,19.2 7,19.2L7,19.2Q7.937,19.2 8.833,19.599Q9.678,19.976 10.351,20.647Q11.025,21.319 11.403,22.164Q11.804,23.06 11.804,24L11.804,24Q11.804,24.074 11.79,24.146Q11.775,24.219 11.747,24.287Q11.719,24.355 11.678,24.417Q11.637,24.478 11.585,24.53Q11.532,24.582 11.471,24.623Q11.409,24.664 11.341,24.693Q11.273,24.721 11.201,24.735Q11.128,24.75 11.054,24.75Q10.98,24.75 10.908,24.735Q10.836,24.721 10.767,24.693Q10.699,24.664 10.638,24.623Q10.576,24.582 10.524,24.53Q10.472,24.478 10.431,24.417Q10.39,24.355 10.362,24.287Q10.333,24.219 10.319,24.146Q10.304,24.074 10.304,24L10.304,24ZM7.835,23.9L7.835,23.9Q7.761,23.9 7.688,23.885Q7.616,23.871 7.548,23.843Q7.479,23.814 7.418,23.773Q7.357,23.732 7.304,23.68Q7.252,23.628 7.211,23.567Q7.17,23.505 7.142,23.437Q7.113,23.369 7.099,23.296Q7.085,23.224 7.085,23.15Q7.085,23.076 7.099,23.004Q7.113,22.931 7.142,22.863Q7.17,22.795 7.211,22.733Q7.252,22.672 7.304,22.62Q7.357,22.567 7.418,22.526Q7.479,22.485 7.548,22.457Q7.616,22.429 7.688,22.414Q7.761,22.4 7.835,22.4L7.835,22.4L7.843,22.4L7.843,22.4Q7.917,22.4 7.989,22.414Q8.062,22.429 8.13,22.457Q8.198,22.485 8.26,22.526Q8.321,22.567 8.373,22.62Q8.425,22.672 8.467,22.733Q8.508,22.795 8.536,22.863Q8.564,22.931 8.578,23.004Q8.593,23.076 8.593,23.15Q8.593,23.224 8.578,23.296Q8.564,23.369 8.536,23.437Q8.508,23.505 8.467,23.567Q8.425,23.628 8.373,23.68Q8.321,23.732 8.26,23.773Q8.198,23.814 8.13,23.843Q8.062,23.871 7.989,23.885Q7.917,23.9 7.843,23.9L7.843,23.9L7.835,23.9Z"
+ android:fillColor="#31456A"
+ android:fillAlpha="0.6"
+ android:fillType="evenOdd"/>
+ </group>
+</vector>
diff --git a/app/src/main/res/layout/activity_accident_detail.xml b/app/src/main/res/layout/activity_accident_detail.xml
index 2f7dd93..e05c314 100644
--- a/app/src/main/res/layout/activity_accident_detail.xml
+++ b/app/src/main/res/layout/activity_accident_detail.xml
@@ -41,6 +41,19 @@
app:layout_constraintTop_toTopOf="@+id/back"
tools:text="待到达" />
+ <TextView
+ android:id="@+id/tv_apply_for_reassignment"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_56"
+ android:paddingHorizontal="@dimen/dp_20"
+ android:text="申请改派"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
@@ -112,7 +125,7 @@
android:background="@drawable/shape_gray_3_bg_4"
android:paddingHorizontal="@dimen/dp_8"
android:paddingVertical="@dimen/dp_4"
- android:text='@{"车身编码:" + viewModel.taskDetail.vehicleCode}'
+ android:text='@{"车身编码:" + viewModel.taskDetail.getShowVehicleCode(6)}'
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_12"
tools:text="车身编码:01234" />
@@ -145,11 +158,11 @@
tools:text="11" />
<androidx.appcompat.widget.AppCompatImageView
+ src="@{viewModel.icon1}"
android:layout_width="@dimen/dp_4"
android:layout_height="@dimen/dp_24"
android:layout_marginHorizontal="@dimen/dp_3"
android:layout_marginTop="@dimen/dp_3"
- src="@{viewModel.icon1}"
tools:src="@mipmap/ic_task_item_colon_b" />
<androidx.appcompat.widget.AppCompatTextView
@@ -165,10 +178,10 @@
tools:text="33" />
<androidx.appcompat.widget.AppCompatImageView
+ src="@{viewModel.icon1}"
android:layout_width="@dimen/dp_4"
android:layout_height="@dimen/dp_24"
android:layout_marginHorizontal="@dimen/dp_3"
- src="@{viewModel.icon1}"
android:layout_marginTop="@dimen/dp_3"
tools:src="@mipmap/ic_task_item_colon_b" />
@@ -189,10 +202,10 @@
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_5"
+ android:layout_marginTop="@dimen/dp_8"
android:text="倒计时结束前,务必到达现场"
- android:textColor="@color/blue_5"
- android:textSize="@dimen/sp_14" />
+ android:textColor="@{viewModel.showRed?@color/red_5:@color/blue_5}"
+ android:textSize="@dimen/sp_12" />
</LinearLayout>
@@ -220,7 +233,7 @@
android:gravity="center"
android:text="系统已自动通知相关负责人,请尽快处理该事故单!"
android:textColor="#ffEC5340"
- android:textSize="@dimen/sp_14"
+ android:textSize="@dimen/sp_12"
android:textStyle="bold" />
</LinearLayout>
@@ -238,7 +251,7 @@
android:layout_gravity="center_vertical"
android:layout_marginStart="@dimen/dp_12"
android:layout_weight="1"
- android:text="@{viewModel.taskDetail.vehicleLocation}"
+ android:text="@{viewModel.carLocation.address}"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_14"
android:textStyle="bold"
@@ -253,6 +266,20 @@
android:src="@drawable/svg_map_nav" />
</LinearLayout>
+
+ <TextView
+ android:id="@+id/tv_notice"
+ show='@{viewModel.carLocation.tips != "" && viewModel.carLocation.tips != null}'
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_4"
+ android:text="@{viewModel.carLocation.tips}"
+ android:textColor="@color/red_5"
+ android:textSize="@dimen/sp_12"
+ android:visibility="gone"
+ app:layout_constraintStart_toStartOf="@id/et_input"
+ app:layout_constraintTop_toBottomOf="@id/et_input"
+ tools:visibility="visible" />
<LinearLayout
android:layout_width="match_parent"
@@ -311,7 +338,7 @@
android:layout_weight="1"
android:gravity="end"
android:singleLine="true"
- android:text="@{viewModel.taskDetail.vehicleLocation}"
+ android:text="@{viewModel.carLocation.address}"
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_14"
tools:text="深圳市南山区南大街龙葵小区7栋1701" />
@@ -371,7 +398,7 @@
android:gravity="end"
android:maxLines="1"
android:singleLine="true"
- android:text="@{viewModel.taskDetail.createTime}"
+ android:text="@{viewModel.taskDetail.getShowCreateTime()}"
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_14"
tools:text="2026-1-25 17:43:02" />
@@ -408,13 +435,11 @@
</LinearLayout>
-<!-- show="@{viewModel.taskDetail.status == 1}"-->
+ <!-- show="@{viewModel.taskDetail.status == 1}"-->
<LinearLayout
- android:baselineAligned="false"
- android:visibility="gone"
- tools:visibility="visible"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:baselineAligned="false"
android:orientation="horizontal">
<LinearLayout
@@ -424,7 +449,7 @@
android:layout_marginTop="@dimen/dp_12"
android:layout_marginEnd="@dimen/dp_6"
android:layout_weight="1"
- android:background="@drawable/shape_blue1_bg_4"
+ android:background="@drawable/shape_gray2_bg_4"
android:gravity="center"
android:onClick="@{viewModel.onClick}"
android:orientation="horizontal"
@@ -432,22 +457,34 @@
app:layout_constraintRight_toLeftOf="@+id/unlockBox"
app:layout_constraintTop_toBottomOf="@+id/icon">
+ <FrameLayout
+ android:layout_width="@dimen/dp_32"
+ android:layout_height="@dimen/dp_32"
+ android:layout_marginStart="@dimen/dp_20">
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
- android:src="@drawable/svg_car_cmjs"
- android:tint="@color/blue_5" />
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/iv_door_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/svg_net_lock_gray" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/iv_door_status_loading"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:src="@drawable/svg_circle_loading" />
+ </FrameLayout>
<androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_door_lock"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/dp_20"
android:layout_weight="1"
android:gravity="center"
android:text="车门解锁"
- android:textColor="@color/blue_5"
+ android:textColor="@color/gray_7"
android:textSize="@dimen/sp_14" />
</LinearLayout>
@@ -459,7 +496,7 @@
android:layout_marginStart="@dimen/dp_6"
android:layout_marginTop="@dimen/dp_12"
android:layout_weight="1"
- android:background="@drawable/shape_blue1_bg_4"
+ android:background="@drawable/shape_gray2_bg_4"
android:gravity="center"
android:onClick="@{viewModel.onClick}"
android:orientation="horizontal"
@@ -467,21 +504,34 @@
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/icon">
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
- android:src="@drawable/svg_car_hbxjs"
- android:tint="@color/blue_5" />
+ <FrameLayout
+ android:layout_width="@dimen/dp_32"
+ android:layout_height="@dimen/dp_32"
+ android:layout_marginStart="@dimen/dp_20">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/iv_trunk_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/svg_car_trunk_closed" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/iv_trunk_status_loading"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:src="@drawable/svg_circle_loading" />
+ </FrameLayout>
<androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_trunk_lock"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/dp_20"
android:layout_weight="1"
android:gravity="center"
android:text="后备箱解锁"
- android:textColor="@color/blue_5"
+ android:textColor="@color/gray_7"
android:textSize="@dimen/sp_14" />
</LinearLayout>
diff --git a/app/src/main/res/layout/activity_accident_process.xml b/app/src/main/res/layout/activity_accident_process.xml
index f3d320c..7ef8bae 100644
--- a/app/src/main/res/layout/activity_accident_process.xml
+++ b/app/src/main/res/layout/activity_accident_process.xml
@@ -45,8 +45,8 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="@dimen/dp_88"
- android:fillViewport="true"
android:layout_marginBottom="@dimen/dp_66"
+ android:fillViewport="true"
android:scrollbars="none"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent">
@@ -54,16 +54,16 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingBottom="@dimen/dp_30"
- android:orientation="vertical">
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/dp_30">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_8"
- android:text="人员伤亡情况"
android:drawableStart="@drawable/svg_must"
+ android:text="人员伤亡情况"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16"
android:textStyle="bold" />
@@ -71,7 +71,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginHorizontal="@dimen/dp_28"
android:layout_marginTop="@dimen/dp_12"
android:background="@drawable/shape_f9f9f9_bg_4"
android:orientation="vertical"
@@ -101,10 +101,10 @@
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/cut1"
- android:onClick="@{viewModel.onClick}"
android:layout_width="@dimen/dp_28"
android:layout_height="match_parent"
android:gravity="center"
+ android:onClick="@{viewModel.onClick}"
android:text="-"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_20" />
@@ -118,10 +118,10 @@
android:layout_width="@dimen/dp_42"
android:layout_height="match_parent"
android:gravity="center"
- tools:text="0"
android:text="@{viewModel.death}"
android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_14" />
+ android:textSize="@dimen/sp_14"
+ tools:text="0" />
<View
android:layout_width="1px"
@@ -129,12 +129,12 @@
android:background="@color/gray_4" />
<androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/add1"
android:layout_width="@dimen/dp_28"
android:layout_height="match_parent"
android:gravity="center"
- android:text="+"
- android:id="@+id/add1"
android:onClick="@{viewModel.onClick}"
+ android:text="+"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_20" />
@@ -166,12 +166,12 @@
tools:ignore="UselessLeaf">
<androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/cut2"
android:layout_width="@dimen/dp_28"
android:layout_height="match_parent"
android:gravity="center"
- android:text="-"
- android:id="@+id/cut2"
android:onClick="@{viewModel.onClick}"
+ android:text="-"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_20" />
@@ -184,10 +184,10 @@
android:layout_width="@dimen/dp_42"
android:layout_height="match_parent"
android:gravity="center"
- tools:text="0"
android:text="@{viewModel.badlyHurt}"
android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_14" />
+ android:textSize="@dimen/sp_14"
+ tools:text="0" />
<View
android:layout_width="1px"
@@ -195,10 +195,10 @@
android:background="@color/gray_4" />
<androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/add2"
android:layout_width="@dimen/dp_28"
android:layout_height="match_parent"
android:gravity="center"
- android:id="@+id/add2"
android:onClick="@{viewModel.onClick}"
android:text="+"
android:textColor="@color/gray_9"
@@ -232,12 +232,12 @@
tools:ignore="UselessLeaf">
<androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/cut3"
android:layout_width="@dimen/dp_28"
android:layout_height="match_parent"
android:gravity="center"
- android:text="-"
- android:id="@+id/cut3"
android:onClick="@{viewModel.onClick}"
+ android:text="-"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_20" />
@@ -250,10 +250,10 @@
android:layout_width="@dimen/dp_42"
android:layout_height="match_parent"
android:gravity="center"
- tools:text="0"
android:text="@{viewModel.minorInjuries}"
android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_14" />
+ android:textSize="@dimen/sp_14"
+ tools:text="0" />
<View
android:layout_width="1px"
@@ -261,10 +261,10 @@
android:background="@color/gray_4" />
<androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/add3"
android:layout_width="@dimen/dp_28"
android:layout_height="match_parent"
android:gravity="center"
- android:id="@+id/add3"
android:onClick="@{viewModel.onClick}"
android:text="+"
android:textColor="@color/gray_9"
@@ -276,10 +276,61 @@
</LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_58"
+ android:layout_marginTop="@dimen/dp_8"
+ android:layout_marginHorizontal="@dimen/dp_28"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="事故类型"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16" />
+
+ <LinearLayout
+ android:id="@+id/ll_filters"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_weight="1"
+ android:gravity="center_vertical|end"
+ android:orientation="horizontal" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tvAccidentFilter"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="end"
+ android:hint="请选择"
+ android:paddingVertical="@dimen/dp_3"
+ android:textColor="@color/gray_9"
+ android:textColorHint="@color/gray_6"
+ android:textSize="@dimen/sp_14" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="@dimen/dp_16"
+ android:layout_height="@dimen/dp_16"
+ android:layout_marginStart="@dimen/dp_4"
+ android:src="@mipmap/ic_task_item_arrow_right" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:layout_marginHorizontal="@dimen/dp_28"
+ android:background="@color/gray_4" />
+
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginHorizontal="@dimen/dp_28"
android:layout_marginTop="@dimen/dp_8"
android:text="初版(交警)责任判断"
android:textColor="@color/gray_9"
@@ -289,7 +340,7 @@
android:id="@+id/stllZrpd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginHorizontal="@dimen/dp_28"
android:layout_marginTop="@dimen/dp_12"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@+id/tv1"
@@ -306,7 +357,7 @@
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginHorizontal="@dimen/dp_28"
android:layout_marginTop="@dimen/dp_12"
android:text="交警判责照片"
android:textColor="@color/gray_9"
@@ -316,7 +367,7 @@
android:id="@+id/rv1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_15"
+ android:layout_marginHorizontal="@dimen/dp_23"
android:layout_marginTop="@dimen/dp_12"
android:orientation="horizontal"
tools:layout_height="@dimen/dp_63" />
@@ -336,10 +387,10 @@
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16" />
- <androidx.constraintlayout.widget.ConstraintLayout
+ <FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginHorizontal="@dimen/dp_28"
android:layout_marginTop="@dimen/dp_8"
android:background="@drawable/shape_f9f9f9_bg_4"
android:minHeight="100dp">
@@ -350,32 +401,43 @@
android:background="@null"
android:gravity="top"
android:hint="请输入现场描述,最多可输入200字"
- android:text="@={viewModel.siteDesc}"
android:maxLength="200"
- android:padding="@dimen/dp_12"
+ android:paddingLeft="@dimen/dp_12"
+ android:paddingRight="@dimen/dp_12"
+ android:paddingTop="@dimen/dp_12"
+ android:paddingBottom="@dimen/dp_18"
+ android:text="@={viewModel.siteDesc}"
android:textColor="@color/gray_9"
android:textColorHint="@color/gray_6"
- android:textSize="@dimen/sp_14"
- app:layout_constraintTop_toTopOf="parent" />
+ android:textSize="@dimen/sp_14" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
- android:textColor="@color/gray_6"
- android:textSize="@dimen/sp_14"
- tools:text="1/200"
- android:text="@{viewModel.siteNums}"
- android:layout_margin="@dimen/dp_6"
android:layout_height="wrap_content"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintRight_toRightOf="parent" />
+ android:layout_gravity="bottom|end"
+ android:layout_marginEnd="@dimen/dp_12"
+ android:layout_marginBottom="@dimen/dp_2"
+ android:text="@{viewModel.siteNums}"
+ android:textColor="@color/gray_6"
+ android:textSize="@dimen/sp_11"
+ tools:text="1/200" />
- </androidx.constraintlayout.widget.ConstraintLayout>
+ </FrameLayout>
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_28"
+ android:layout_marginTop="@dimen/dp_12"
+ android:text="现场照片"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_15"
+ android:layout_marginHorizontal="@dimen/dp_23"
android:layout_marginTop="@dimen/dp_12"
android:orientation="horizontal"
tools:layout_height="@dimen/dp_63" />
@@ -390,15 +452,15 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/dp_20"
- android:text="处置情况"
android:drawableStart="@drawable/svg_must"
+ android:text="处置情况"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16" />
- <androidx.constraintlayout.widget.ConstraintLayout
+ <FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginHorizontal="@dimen/dp_28"
android:layout_marginTop="@dimen/dp_8"
android:background="@drawable/shape_f9f9f9_bg_4"
android:minHeight="100dp">
@@ -408,33 +470,44 @@
android:layout_height="wrap_content"
android:background="@null"
android:gravity="top"
- android:text="@={viewModel.disposalDesc}"
android:hint="请输入处置描述,最多可输入200字"
android:maxLength="200"
- android:padding="@dimen/dp_12"
+ android:paddingLeft="@dimen/dp_12"
+ android:paddingRight="@dimen/dp_12"
+ android:paddingTop="@dimen/dp_12"
+ android:paddingBottom="@dimen/dp_18"
+ android:text="@={viewModel.disposalDesc}"
android:textColor="@color/gray_9"
android:textColorHint="@color/gray_6"
- android:textSize="@dimen/sp_14"
- app:layout_constraintTop_toTopOf="parent" />
+ android:textSize="@dimen/sp_14" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
- android:textColor="@color/gray_6"
- android:textSize="@dimen/sp_14"
- android:text="@{viewModel.disposalNums}"
- tools:text="1/200"
- android:layout_margin="@dimen/dp_6"
android:layout_height="wrap_content"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintRight_toRightOf="parent" />
+ android:layout_gravity="bottom|end"
+ android:layout_marginEnd="@dimen/dp_12"
+ android:layout_marginBottom="@dimen/dp_2"
+ android:text="@{viewModel.disposalNums}"
+ android:textColor="@color/gray_6"
+ android:textSize="@dimen/sp_11"
+ tools:text="1/200" />
- </androidx.constraintlayout.widget.ConstraintLayout>
+ </FrameLayout>
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_28"
+ android:layout_marginTop="@dimen/dp_12"
+ android:text="处置照片"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_15"
+ android:layout_marginHorizontal="@dimen/dp_23"
android:layout_marginTop="@dimen/dp_12"
android:orientation="horizontal"
tools:layout_height="@dimen/dp_63" />
@@ -445,7 +518,7 @@
<RelativeLayout
android:layout_width="match_parent"
- android:layout_height="@dimen/dp_66"
+ android:layout_height="wrap_content"
android:background="@color/white"
app:layout_constraintBottom_toBottomOf="parent">
@@ -455,11 +528,24 @@
android:background="@color/gray_4" />
<androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_notice"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_12"
+ android:layout_centerHorizontal="true"
+ android:layout_marginHorizontal="@dimen/dp_28"
+ android:text="提交归档后,任务列表不再展示本条事故"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_12" />
+
+ <androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvControl"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_40"
android:layout_centerVertical="true"
- android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_below="@id/tv_notice"
+ android:layout_marginVertical="@dimen/dp_12"
+ android:layout_marginHorizontal="@dimen/dp_28"
android:background="@drawable/shape_blue_5_bg_4"
android:gravity="center"
android:onClick="@{viewModel.onClick}"
diff --git a/app/src/main/res/layout/activity_car_charge.xml b/app/src/main/res/layout/activity_car_charge.xml
index 5ce7a89..550d87b 100644
--- a/app/src/main/res/layout/activity_car_charge.xml
+++ b/app/src/main/res/layout/activity_car_charge.xml
@@ -88,12 +88,22 @@
android:orientation="vertical"
app:layout_constraintTop_toTopOf="parent">
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/iv_car"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_168"
+ android:layout_marginTop="@dimen/dp_10"
+ android:adjustViewBounds="true"
+ android:scaleType="centerCrop"
+ android:src="@mipmap/img_work_car1"
+ app:layout_constraintTop_toTopOf="parent" />
+
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/chargeLayout"
show="@{viewModel.chargeRecord.status==2}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- app:layout_constraintTop_toTopOf="parent">
+ app:layout_constraintTop_toBottomOf="@id/iv_car">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon"
@@ -159,10 +169,10 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:text='@{"开始时间:" + viewModel.chargeRecord.xpChargingRecord.startTime}'
+ android:text='@{viewModel.chargeRecord.xpChargingRecord.startTime}'
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_12"
- tools:text="开始时间:2026-09-31 11:00:09" />
+ tools:text="2026-09-31 11:00:09" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
@@ -223,6 +233,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_20"
+ android:drawableStart="@drawable/svg_must"
android:text="当前剩余电量"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16"
@@ -246,20 +257,26 @@
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@+id/tv" />
- <androidx.appcompat.widget.AppCompatEditText
+ <com.xw.yunwei.ui.widget.ClearEditText
android:id="@+id/chargeEt"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_56"
- android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginStart="@dimen/dp_28"
+ android:layout_marginEnd="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_16"
android:background="@null"
android:gravity="center_vertical"
android:hint="请输入剩余里程"
+ android:maxLength="4"
android:inputType="number"
android:text="@={viewModel.leftCharge}"
android:textColor="@color/gray_10"
android:textColorHint="@color/gray_6"
android:textSize="@dimen/sp_14"
+ app:iconHeight="@dimen/dp_18"
+ app:iconWidth="@dimen/dp_18"
+ app:iconMarginRight="@dimen/dp_40"
+ app:clearIcon="@mipmap/icon_close_gray"
app:layout_constraintTop_toBottomOf="@+id/tv" />
<androidx.appcompat.widget.AppCompatTextView
@@ -273,20 +290,36 @@
app:layout_constraintTop_toTopOf="@+id/chargeEt" />
<View
+ android:id="@+id/v_line"
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginHorizontal="@dimen/dp_20"
android:background="@color/gray_4"
app:layout_constraintTop_toBottomOf="@+id/chargeEt" />
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_20"
+ android:drawableStart="@drawable/svg_must"
+ android:text="充电前照片"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/v_line" />
+
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_20"
- app:layout_constraintLeft_toLeftOf="@+id/chargeEt"
+ android:layout_marginTop="@dimen/dp_16"
+ android:layout_marginStart="@dimen/dp_3"
+ app:layout_constraintLeft_toLeftOf="@+id/tv2"
app:layout_constraintRight_toRightOf="@+id/chargeEt"
- app:layout_constraintTop_toBottomOf="@+id/chargeEt"
+ app:layout_constraintTop_toBottomOf="@+id/tv2"
tools:layout_height="@dimen/dp_40" />
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/layout/activity_car_charge_detail.xml b/app/src/main/res/layout/activity_car_charge_detail.xml
index b9ed34f..64f1218 100644
--- a/app/src/main/res/layout/activity_car_charge_detail.xml
+++ b/app/src/main/res/layout/activity_car_charge_detail.xml
@@ -160,8 +160,8 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- tools:text="开始时间:2026-09-31 11:00:09"
- android:text='@{"开始时间:" + viewModel.recordInfo.startTime}'
+ tools:text="2026-09-31 11:00:09"
+ android:text='@{viewModel.recordInfo.getShowStartTime()}'
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_12" />
@@ -277,8 +277,8 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- tools:text="结束时间:2026-09-31 11:00:09"
- android:text='@{"结束时间:" + viewModel.recordInfo.endTime}'
+ tools:text="2026-09-31 11:00:09"
+ android:text='@{viewModel.recordInfo.getShowEndTime()}'
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_12" />
diff --git a/app/src/main/res/layout/activity_car_check.xml b/app/src/main/res/layout/activity_car_check.xml
index 3decadc..25a7979 100644
--- a/app/src/main/res/layout/activity_car_check.xml
+++ b/app/src/main/res/layout/activity_car_check.xml
@@ -34,23 +34,22 @@
android:textColor="@color/gray_10"
android:textSize="@dimen/sp_16"
android:textStyle="bold"
- app:layout_constraintBottom_toTopOf="@+id/basicLayout"
+ android:layout_marginTop="-15dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toTopOf="@+id/back"
+ app:layout_constraintTop_toTopOf="@id/back"
tools:text="粤A 88934试" />
<LinearLayout
android:id="@+id/basicLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_2"
+ android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:orientation="horizontal"
- app:layout_constraintBottom_toBottomOf="@+id/back"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/title">
+ app:layout_constraintTop_toTopOf="@id/back">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
@@ -82,6 +81,7 @@
</LinearLayout>
<androidx.core.widget.NestedScrollView
+ android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="@dimen/dp_88"
@@ -100,31 +100,31 @@
android:layout_marginStart="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_20"
android:text="车身自检"
- tools:visibility="visible"
- android:visibility="gone"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16"
android:textStyle="bold"
+ android:visibility="gone"
app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
+ app:layout_constraintTop_toTopOf="parent"
+ tools:visibility="visible" />
<com.google.android.material.button.MaterialButton
android:id="@+id/check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/dp_20"
- tools:visibility="visible"
- android:visibility="gone"
android:backgroundTint="@{viewModel.btnEnableStatus==true?@color/blue_5:@color/gray_4}"
android:onClick="@{viewModel.onClick}"
android:text="@{viewModel.btnText}"
android:textSize="@dimen/sp_12"
android:textStyle="bold"
+ android:visibility="gone"
app:cornerRadius="@dimen/dp_4"
app:layout_constraintBottom_toBottomOf="@+id/tv"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@+id/tv"
- tools:text="开始自检" />
+ tools:text="开始自检"
+ tools:visibility="visible" />
<LinearLayout
android:id="@+id/layout"
@@ -135,23 +135,24 @@
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@+id/check">
-<!-- show="@{viewModel.checkStatus==1}"-->
+ <!-- show="@{viewModel.checkStatus==1}"-->
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- tools:visibility="visible"
- android:visibility="gone"
android:text="请点击右上角按钮开始车辆自检"
android:textColor="@color/gray_6"
- android:textSize="@dimen/sp_12" />
+ android:textSize="@dimen/sp_12"
+ android:visibility="gone"
+ tools:visibility="visible" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon"
show="@{viewModel.checkStatus==1}"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/dp_168"
android:layout_marginTop="@dimen/dp_10"
android:adjustViewBounds="true"
+ android:scaleType="centerCrop"
android:src="@mipmap/img_work_car1" />
<androidx.recyclerview.widget.RecyclerView
@@ -181,10 +182,10 @@
android:id="@+id/viewDetail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/dp_20"
+ android:layout_marginEnd="@dimen/dp_16"
+ android:onClick="@{viewModel.onClick}"
android:padding="4dp"
android:text="标准说明"
- android:onClick="@{viewModel.onClick}"
android:textColor="@color/blue_5"
android:textSize="@dimen/sp_12"
android:textStyle="bold"
@@ -196,222 +197,371 @@
android:id="@+id/tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginStart="@dimen/dp_8"
android:layout_marginTop="@dimen/dp_20"
- android:text="传感器清洁"
+ android:drawableStart="@drawable/svg_must"
+ android:text="外观和轮胎"
android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_16"
+ android:textSize="@dimen/sp_14"
android:textStyle="bold"
- app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintStart_toEndOf="@id/v_point1"
app:layout_constraintTop_toBottomOf="@+id/tv1" />
- <com.xw.common.custom.SlideSwitchView
- android:id="@+id/switch1"
- android:layout_width="@dimen/dp_110"
- android:layout_height="@dimen/dp_36"
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_status1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/dp_20"
+ android:background="@drawable/shape_gray_3_bg_2"
+ android:textColor="@color/gray_8"
+ android:gravity="center"
+ android:paddingHorizontal="@dimen/dp_8"
+ android:paddingVertical="@dimen/dp_4"
+ android:text="待检测"
+ android:textSize="@dimen/sp_12"
app:layout_constraintBottom_toBottomOf="@+id/tv2"
app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toTopOf="@+id/tv2"
- app:switchBackgroundColorChecked="@color/gray_3"
- app:switchBackgroundColorUnchecked="@color/gray_3"
- app:switchChecked="false"
- app:switchCornerRadius="@dimen/dp_4"
- app:switchTextChecked="检测完成"
- app:switchTextColorChecked="@color/white"
- app:switchTextColorUnchecked="@color/white"
- app:switchTextSize="@dimen/sp_12"
- app:switchTextUnchecked="待检测"
- app:switchThumbColorChecked="@color/green_5"
- app:switchThumbColorUnchecked="@color/gray_6"
- app:switchThumbCornerRadius="@dimen/dp_4"
- app:switchThumbMargin="@dimen/dp_2" />
+ app:layout_constraintTop_toTopOf="@+id/tv2" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_label2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_8"
+ android:layout_marginTop="@dimen/dp_10"
+ android:text="请上传图片"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_14"
+ app:layout_constraintStart_toStartOf="@id/tv2"
+ app:layout_constraintTop_toBottomOf="@+id/tv2" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv1"
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_14"
- app:layout_constraintTop_toBottomOf="@+id/tv2"
+ android:layout_marginStart="@dimen/dp_3"
+ android:layout_marginTop="@dimen/dp_3"
+ android:layout_marginEnd="@dimen/dp_20"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="@id/tv2"
+ app:layout_constraintTop_toBottomOf="@+id/tv_label2"
tools:layout_height="@dimen/dp_40" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginStart="@dimen/dp_8"
android:layout_marginTop="@dimen/dp_20"
- android:text="车内交互屏检查"
+ android:drawableStart="@drawable/svg_must"
+ android:text="车内大屏"
android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_16"
+ android:textSize="@dimen/sp_14"
android:textStyle="bold"
- app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintStart_toEndOf="@id/v_point2"
app:layout_constraintTop_toBottomOf="@+id/rv1" />
- <com.xw.common.custom.SlideSwitchView
- android:id="@+id/switch2"
- android:layout_width="@dimen/dp_110"
- android:layout_height="@dimen/dp_36"
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_status2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/dp_20"
+ android:background="@drawable/shape_gray_3_bg_2"
+ android:textColor="@color/gray_8"
+ android:gravity="center"
+ android:paddingHorizontal="@dimen/dp_8"
+ android:paddingVertical="@dimen/dp_4"
+ android:text="待检测"
+ android:textSize="@dimen/sp_12"
app:layout_constraintBottom_toBottomOf="@+id/tv3"
app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toTopOf="@+id/tv3"
- app:switchBackgroundColorChecked="@color/gray_3"
- app:switchBackgroundColorUnchecked="@color/gray_3"
- app:switchChecked="false"
- app:switchCornerRadius="@dimen/dp_4"
- app:switchTextChecked="检测完成"
- app:switchTextColorChecked="@color/white"
- app:switchTextColorUnchecked="@color/white"
- app:switchTextSize="@dimen/sp_12"
- app:switchTextUnchecked="待检测"
- app:switchThumbColorChecked="@color/green_5"
- app:switchThumbColorUnchecked="@color/gray_6"
- app:switchThumbCornerRadius="@dimen/dp_4"
- app:switchThumbMargin="@dimen/dp_2" />
+ app:layout_constraintTop_toTopOf="@+id/tv3" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_label3"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_8"
+ android:layout_marginTop="@dimen/dp_10"
+ android:text="请上传图片"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_14"
+ app:layout_constraintStart_toStartOf="@id/tv3"
+ app:layout_constraintTop_toBottomOf="@+id/tv3" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv2"
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_14"
- app:layout_constraintTop_toBottomOf="@+id/tv3"
+ android:layout_marginStart="@dimen/dp_3"
+ android:layout_marginTop="@dimen/dp_3"
+ android:layout_marginEnd="@dimen/dp_20"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="@id/tv3"
+ app:layout_constraintTop_toBottomOf="@+id/tv_label3"
tools:layout_height="@dimen/dp_40" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginStart="@dimen/dp_8"
android:layout_marginTop="@dimen/dp_20"
- android:text="紧急求助按钮/应答机"
+ android:drawableStart="@drawable/svg_must"
+ android:text="舱内外清洁"
android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_16"
+ android:textSize="@dimen/sp_14"
android:textStyle="bold"
- app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintStart_toEndOf="@id/v_point3"
app:layout_constraintTop_toBottomOf="@+id/rv2" />
- <com.xw.common.custom.SlideSwitchView
- android:id="@+id/switch3"
- android:layout_width="@dimen/dp_110"
- android:layout_height="@dimen/dp_36"
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_status3"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/dp_20"
+ android:background="@drawable/shape_gray_3_bg_2"
+ android:textColor="@color/gray_8"
+ android:gravity="center"
+ android:paddingHorizontal="@dimen/dp_8"
+ android:paddingVertical="@dimen/dp_4"
+ android:text="待检测"
+ android:textSize="@dimen/sp_12"
app:layout_constraintBottom_toBottomOf="@+id/tv4"
app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toTopOf="@+id/tv4"
- app:switchBackgroundColorChecked="@color/gray_3"
- app:switchBackgroundColorUnchecked="@color/gray_3"
- app:switchChecked="false"
- app:switchCornerRadius="@dimen/dp_4"
- app:switchTextChecked="检测完成"
- app:switchTextColorChecked="@color/white"
- app:switchTextColorUnchecked="@color/white"
- app:switchTextSize="@dimen/sp_12"
- app:switchTextUnchecked="待检测"
- app:switchThumbColorChecked="@color/green_5"
- app:switchThumbColorUnchecked="@color/gray_6"
- app:switchThumbCornerRadius="@dimen/dp_4"
- app:switchThumbMargin="@dimen/dp_2" />
+ app:layout_constraintTop_toTopOf="@+id/tv4" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_label4"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_8"
+ android:layout_marginTop="@dimen/dp_10"
+ android:text="请上传图片"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_14"
+ app:layout_constraintStart_toStartOf="@id/tv4"
+ app:layout_constraintTop_toBottomOf="@+id/tv4" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv3"
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_14"
- app:layout_constraintTop_toBottomOf="@+id/tv4"
+ android:layout_marginStart="@dimen/dp_3"
+ android:layout_marginTop="@dimen/dp_3"
+ android:layout_marginEnd="@dimen/dp_20"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="@id/tv4"
+ app:layout_constraintTop_toBottomOf="@+id/tv_label4"
tools:layout_height="@dimen/dp_40" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginStart="@dimen/dp_8"
android:layout_marginTop="@dimen/dp_20"
+ android:drawableStart="@drawable/svg_must"
android:text="支付功能"
android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_16"
+ android:textSize="@dimen/sp_14"
android:textStyle="bold"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/rv3" />
+ android:visibility="gone"
+ app:layout_constraintStart_toEndOf="@id/v_point4"
+ app:layout_constraintTop_toBottomOf="@+id/rv3"
+ tools:visibility="visible" />
- <com.xw.common.custom.SlideSwitchView
- android:id="@+id/switch4"
- android:layout_width="@dimen/dp_110"
- android:layout_height="@dimen/dp_36"
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_status4"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/dp_20"
+ android:background="@drawable/shape_gray_3_bg_2"
+ android:textColor="@color/gray_8"
+ android:gravity="center"
+ android:paddingHorizontal="@dimen/dp_8"
+ android:paddingVertical="@dimen/dp_4"
+ android:text="待检测"
+ android:textSize="@dimen/sp_12"
+ android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/tv5"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@+id/tv5"
- app:switchBackgroundColorChecked="@color/gray_3"
- app:switchBackgroundColorUnchecked="@color/gray_3"
- app:switchChecked="false"
- app:switchCornerRadius="@dimen/dp_4"
- app:switchTextChecked="检测完成"
- app:switchTextColorChecked="@color/white"
- app:switchTextColorUnchecked="@color/white"
- app:switchTextSize="@dimen/sp_12"
- app:switchTextUnchecked="待检测"
- app:switchThumbColorChecked="@color/green_5"
- app:switchThumbColorUnchecked="@color/gray_6"
- app:switchThumbCornerRadius="@dimen/dp_4"
- app:switchThumbMargin="@dimen/dp_2" />
+ tools:visibility="visible" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_label5"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_8"
+ android:layout_marginTop="@dimen/dp_10"
+ android:text="请上传图片"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_14"
+ android:visibility="gone"
+ app:layout_constraintStart_toStartOf="@id/tv5"
+ app:layout_constraintTop_toBottomOf="@+id/tv5"
+ tools:visibility="visible" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv4"
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_14"
- app:layout_constraintTop_toBottomOf="@+id/tv5"
- tools:layout_height="@dimen/dp_40" />
+ android:layout_marginStart="@dimen/dp_3"
+ android:layout_marginTop="@dimen/dp_3"
+ android:layout_marginEnd="@dimen/dp_20"
+ android:visibility="gone"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="@id/tv5"
+ app:layout_constraintTop_toBottomOf="@+id/tv_label5"
+ tools:layout_height="@dimen/dp_40"
+ tools:visibility="visible" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginStart="@dimen/dp_8"
android:layout_marginTop="@dimen/dp_20"
- android:text="订单系统检查"
+ android:drawableStart="@drawable/svg_must"
+ android:text="随车安全设备"
android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_16"
+ android:textSize="@dimen/sp_14"
android:textStyle="bold"
- app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintStart_toEndOf="@id/v_point5"
app:layout_constraintTop_toBottomOf="@+id/rv4" />
- <com.xw.common.custom.SlideSwitchView
- android:id="@+id/switch5"
- android:layout_width="@dimen/dp_110"
- android:layout_height="@dimen/dp_36"
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_status5"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/dp_20"
+ android:background="@drawable/shape_gray_3_bg_2"
+ android:textColor="@color/gray_8"
+ android:gravity="center"
+ android:paddingHorizontal="@dimen/dp_8"
+ android:paddingVertical="@dimen/dp_4"
+ android:text="待检测"
+ android:textSize="@dimen/sp_12"
app:layout_constraintBottom_toBottomOf="@+id/tv6"
app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toTopOf="@+id/tv6"
- app:switchBackgroundColorChecked="@color/gray_3"
- app:switchBackgroundColorUnchecked="@color/gray_3"
- app:switchChecked="false"
- app:switchCornerRadius="@dimen/dp_4"
- app:switchTextChecked="检测完成"
- app:switchTextColorChecked="@color/white"
- app:switchTextColorUnchecked="@color/white"
- app:switchTextSize="@dimen/sp_12"
- app:switchTextUnchecked="待检测"
- app:switchThumbColorChecked="@color/green_5"
- app:switchThumbColorUnchecked="@color/gray_6"
- app:switchThumbCornerRadius="@dimen/dp_4"
- app:switchThumbMargin="@dimen/dp_2" />
+ app:layout_constraintTop_toTopOf="@+id/tv6" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_label6"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_8"
+ android:layout_marginTop="@dimen/dp_10"
+ android:text="请上传图片"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_14"
+ app:layout_constraintStart_toStartOf="@id/tv6"
+ app:layout_constraintTop_toBottomOf="@+id/tv6" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv5"
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_14"
- app:layout_constraintTop_toBottomOf="@+id/tv6"
+ android:layout_marginStart="@dimen/dp_3"
+ android:layout_marginTop="@dimen/dp_3"
+ android:layout_marginEnd="@dimen/dp_20"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="@id/tv6"
+ app:layout_constraintTop_toBottomOf="@+id/tv_label6"
tools:layout_height="@dimen/dp_40" />
+ <View
+ android:id="@+id/v_point1"
+ android:layout_width="@dimen/dp_6"
+ android:layout_height="@dimen/dp_6"
+ android:layout_marginTop="@dimen/dp_6"
+ android:background="@drawable/circle_blue_5"
+ app:layout_constraintStart_toStartOf="@id/tv1"
+ app:layout_constraintTop_toTopOf="@id/tv2" />
+
+ <View
+ android:id="@+id/v_point2"
+ android:layout_width="@dimen/dp_6"
+ android:layout_height="@dimen/dp_6"
+ android:layout_marginTop="@dimen/dp_6"
+ android:background="@drawable/circle_blue_5"
+ app:layout_constraintEnd_toEndOf="@id/v_point1"
+ app:layout_constraintStart_toStartOf="@id/v_point1"
+ app:layout_constraintTop_toTopOf="@id/tv3" />
+
+ <View
+ android:id="@+id/v_point3"
+ android:layout_width="@dimen/dp_6"
+ android:layout_height="@dimen/dp_6"
+ android:layout_marginTop="@dimen/dp_6"
+ android:background="@drawable/circle_blue_5"
+ app:layout_constraintEnd_toEndOf="@id/v_point1"
+ app:layout_constraintStart_toStartOf="@id/v_point1"
+ app:layout_constraintTop_toTopOf="@id/tv4" />
+
+ <View
+ android:id="@+id/v_point4"
+ android:layout_width="@dimen/dp_6"
+ android:layout_height="@dimen/dp_6"
+ android:layout_marginTop="@dimen/dp_6"
+ android:background="@drawable/circle_blue_5"
+ android:visibility="gone"
+ app:layout_constraintEnd_toEndOf="@id/v_point1"
+ app:layout_constraintStart_toStartOf="@id/v_point1"
+ app:layout_constraintTop_toTopOf="@id/tv5"
+ app:layout_goneMarginTop="0dp"
+ tools:visibility="visible" />
+
+ <View
+ android:id="@+id/v_point5"
+ android:layout_width="@dimen/dp_6"
+ android:layout_height="@dimen/dp_6"
+ android:layout_marginTop="@dimen/dp_6"
+ android:background="@drawable/circle_blue_5"
+ app:layout_constraintEnd_toEndOf="@id/v_point1"
+ app:layout_constraintStart_toStartOf="@id/v_point1"
+ app:layout_constraintTop_toTopOf="@id/tv6" />
+
+ <com.xw.yunwei.ui.widget.LineView
+ android:layout_width="@dimen/dp_1"
+ android:layout_height="0dp"
+ android:layout_marginVertical="@dimen/dp_3"
+ app:dashLineSize="@dimen/dp_4"
+ app:dashLineStroke="@dimen/dp_1"
+ app:layout_constraintBottom_toTopOf="@id/v_point2"
+ app:layout_constraintEnd_toEndOf="@id/v_point1"
+ app:layout_constraintStart_toStartOf="@id/v_point1"
+ app:layout_constraintTop_toBottomOf="@id/v_point1"
+ app:lineColor="@color/color_5931456a"
+ app:lineInterval="@dimen/dp_2" />
+
+ <com.xw.yunwei.ui.widget.LineView
+ android:layout_width="@dimen/dp_1"
+ android:layout_height="0dp"
+ android:layout_marginVertical="@dimen/dp_3"
+ app:dashLineSize="@dimen/dp_4"
+ app:dashLineStroke="@dimen/dp_1"
+ app:layout_constraintBottom_toTopOf="@id/v_point3"
+ app:layout_constraintEnd_toEndOf="@id/v_point2"
+ app:layout_constraintStart_toStartOf="@id/v_point2"
+ app:layout_constraintTop_toBottomOf="@id/v_point2"
+ app:lineColor="@color/color_5931456a"
+ app:lineInterval="@dimen/dp_2" />
+
+ <com.xw.yunwei.ui.widget.LineView
+ android:layout_width="@dimen/dp_1"
+ android:layout_height="0dp"
+ android:layout_marginTop="@dimen/dp_3"
+ android:layout_marginBottom="@dimen/dp_3"
+ app:dashLineSize="@dimen/dp_4"
+ app:dashLineStroke="@dimen/dp_1"
+ app:layout_constraintBottom_toTopOf="@id/v_point5"
+ app:layout_constraintEnd_toEndOf="@id/v_point3"
+ app:layout_constraintStart_toStartOf="@id/v_point3"
+ app:layout_constraintTop_toBottomOf="@id/v_point3"
+ app:lineColor="@color/color_5931456a"
+ app:lineInterval="@dimen/dp_2" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
@@ -431,8 +581,8 @@
android:layout_marginTop="@dimen/dp_24"
android:layout_marginBottom="@dimen/dp_12"
android:backgroundTint="@color/blue_5"
- android:text="提交检测结果"
android:onClick="@{viewModel.onClick}"
+ android:text="提交检测结果"
android:textSize="@dimen/sp_16"
android:textStyle="bold"
app:cornerRadius="@dimen/dp_4"
diff --git a/app/src/main/res/layout/activity_car_check_detail.xml b/app/src/main/res/layout/activity_car_check_detail.xml
index 2c4c66f..1f7847b 100644
--- a/app/src/main/res/layout/activity_car_check_detail.xml
+++ b/app/src/main/res/layout/activity_car_check_detail.xml
@@ -125,7 +125,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_20"
- android:text="传感器清洁"
+ android:text="外观和轮胎"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16"
android:textStyle="bold"
@@ -182,7 +182,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_30"
- android:text="车内交互屏检查"
+ android:text="车内大屏"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16"
android:textStyle="bold"
@@ -205,7 +205,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_30"
- android:text="紧急求助按钮/应答机"
+ android:text="舱内外清洁"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16"
android:textStyle="bold"
@@ -231,6 +231,8 @@
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16"
android:textStyle="bold"
+ android:visibility="gone"
+ tools:visibility="visible"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/rv3" />
@@ -240,6 +242,8 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_14"
+ android:visibility="gone"
+ tools:visibility="visible"
app:layout_constraintTop_toBottomOf="@+id/tv5"
tools:layout_height="@dimen/dp_40" />
@@ -249,7 +253,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_30"
- android:text="订单系统检查"
+ android:text="随车安全设备"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16"
android:textStyle="bold"
@@ -317,7 +321,7 @@
android:layout_marginHorizontal="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_10"
tools:text="2026年 xxxxxxxxx"
- android:text="@{BindUtils.INSTANCE.formatDate(viewModel.recordInfo.operationTime)}"
+ android:text="@{viewModel.recordInfo.getShowOperationTime()}"
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_14"
app:layout_constraintTop_toBottomOf="@+id/tv8" />
diff --git a/app/src/main/res/layout/activity_car_clean.xml b/app/src/main/res/layout/activity_car_clean.xml
index f6946c9..dab1724 100644
--- a/app/src/main/res/layout/activity_car_clean.xml
+++ b/app/src/main/res/layout/activity_car_clean.xml
@@ -81,18 +81,29 @@
</LinearLayout>
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/iv_car"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_168"
+ android:layout_marginTop="@dimen/dp_108"
+ android:adjustViewBounds="true"
+ android:scaleType="centerCrop"
+ android:src="@mipmap/img_work_car1"
+ app:layout_constraintTop_toTopOf="parent" />
+
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_108"
+ android:layout_marginTop="@dimen/dp_10"
android:text="车身标识及清洁"
+ android:drawableStart="@drawable/svg_must"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16"
android:textStyle="bold"
app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
+ app:layout_constraintTop_toBottomOf="@id/iv_car" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/viewDetail"
@@ -114,7 +125,7 @@
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="0dp"
- android:layout_marginHorizontal="@dimen/dp_15"
+ android:layout_marginHorizontal="@dimen/dp_23"
android:layout_marginTop="@dimen/dp_16"
android:layout_marginBottom="@dimen/dp_28"
app:layout_constraintBottom_toTopOf="@+id/submit"
diff --git a/app/src/main/res/layout/activity_car_clean_detail.xml b/app/src/main/res/layout/activity_car_clean_detail.xml
index 71c1d4d..be11239 100644
--- a/app/src/main/res/layout/activity_car_clean_detail.xml
+++ b/app/src/main/res/layout/activity_car_clean_detail.xml
@@ -163,7 +163,7 @@
android:layout_marginHorizontal="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_10"
tools:text="2026年 xxxxxxxxx"
- android:text="@{BindUtils.INSTANCE.formatDate(viewModel.recordInfo.operationTime)}"
+ android:text="@{viewModel.recordInfo.getShowOperationTime()}"
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_14"
app:layout_constraintTop_toBottomOf="@+id/tv8" />
diff --git a/app/src/main/res/layout/activity_car_maintain.xml b/app/src/main/res/layout/activity_car_maintain.xml
index 05a6520..fb1df88 100644
--- a/app/src/main/res/layout/activity_car_maintain.xml
+++ b/app/src/main/res/layout/activity_car_maintain.xml
@@ -20,8 +20,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_20"
- android:onClick="@{viewModel::onBack}"
android:layout_marginTop="@dimen/dp_56"
+ android:onClick="@{viewModel::onBack}"
android:src="@drawable/svg_back"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@@ -30,7 +30,6 @@
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- tools:text="粤A 88934试"
android:text="@{viewModel.carInfo.plateNumber}"
android:textColor="@color/gray_10"
android:textSize="@dimen/sp_16"
@@ -38,7 +37,8 @@
app:layout_constraintBottom_toTopOf="@+id/basicLayout"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toTopOf="@+id/back" />
+ app:layout_constraintTop_toTopOf="@+id/back"
+ tools:text="粤A 88934试" />
<LinearLayout
android:id="@+id/basicLayout"
@@ -55,10 +55,10 @@
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- tools:text="白色 |"
android:text='@{viewModel.carInfo.vehicleColor + " |"}'
android:textColor="@color/gray_6"
- android:textSize="@dimen/sp_12" />
+ android:textSize="@dimen/sp_12"
+ tools:text="白色 |" />
<com.xw.common.custom.BatteryView
android:id="@+id/batteryView"
@@ -113,8 +113,8 @@
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginEnd="@dimen/dp_20"
- android:padding="4dp"
android:onClick="@{viewModel.onClick}"
+ android:padding="4dp"
android:text="标准说明"
android:textColor="@color/blue_5"
android:textSize="@dimen/sp_12"
@@ -364,8 +364,8 @@
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginEnd="@dimen/dp_20"
- android:padding="4dp"
android:onClick="@{viewModel.onClick}"
+ android:padding="4dp"
android:text="标准说明"
android:textColor="@color/blue_5"
android:textSize="@dimen/sp_12"
@@ -387,6 +387,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_20"
android:layout_marginEnd="@dimen/dp_10"
+ android:drawableStart="@drawable/svg_must"
android:text="大灯情况"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_14"
@@ -401,6 +402,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_10"
android:layout_marginEnd="20dp"
+ android:drawableStart="@drawable/svg_must"
android:text="转向灯情况"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_14"
@@ -414,6 +416,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_10"
+ android:layout_marginStart="@dimen/dp_3"
app:layout_constraintLeft_toLeftOf="@+id/tv2"
app:layout_constraintRight_toRightOf="@+id/tv2"
app:layout_constraintTop_toBottomOf="@+id/tv2"
@@ -423,6 +426,7 @@
android:id="@+id/rv2"
android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_3"
android:layout_marginTop="@dimen/dp_10"
app:layout_constraintLeft_toLeftOf="@+id/tv3"
app:layout_constraintRight_toRightOf="@+id/tv3"
@@ -434,54 +438,58 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_15"
+ android:drawableStart="@drawable/svg_must"
android:text="刹车灯情况"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_14"
- android:visibility="gone"
- tools:visibility="visible"
android:textStyle="bold"
+ android:visibility="gone"
app:layout_constraintLeft_toLeftOf="@+id/tv2"
app:layout_constraintRight_toRightOf="@+id/tv2"
- app:layout_constraintTop_toBottomOf="@+id/rv1" />
+ app:layout_constraintTop_toBottomOf="@+id/rv1"
+ tools:visibility="visible" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv5"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_15"
+ android:drawableStart="@drawable/svg_must"
android:text="雾灯情况"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_14"
android:textStyle="bold"
android:visibility="gone"
- tools:visibility="visible"
app:layout_constraintLeft_toLeftOf="@+id/tv3"
app:layout_constraintRight_toRightOf="@+id/tv3"
- app:layout_constraintTop_toBottomOf="@+id/rv2" />
+ app:layout_constraintTop_toBottomOf="@+id/rv2"
+ tools:visibility="visible" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv3"
android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_3"
android:layout_marginTop="@dimen/dp_10"
android:visibility="gone"
- tools:visibility="visible"
app:layout_constraintLeft_toLeftOf="@+id/tv2"
app:layout_constraintRight_toRightOf="@+id/tv2"
app:layout_constraintTop_toBottomOf="@+id/tv4"
- tools:layout_height="@dimen/dp_40" />
+ tools:layout_height="@dimen/dp_40"
+ tools:visibility="visible" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv4"
android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_3"
android:layout_marginTop="@dimen/dp_10"
android:visibility="gone"
- tools:visibility="visible"
app:layout_constraintLeft_toLeftOf="@+id/tv3"
app:layout_constraintRight_toRightOf="@+id/tv3"
app:layout_constraintTop_toBottomOf="@+id/tv5"
- tools:layout_height="@dimen/dp_40" />
+ tools:layout_height="@dimen/dp_40"
+ tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -498,6 +506,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_40"
+ android:drawableStart="@drawable/svg_must"
android:text="舱内清洁及消毒"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16"
@@ -511,8 +520,8 @@
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginEnd="@dimen/dp_20"
- android:padding="4dp"
android:onClick="@{viewModel.onClick}"
+ android:padding="4dp"
android:text="标准说明"
android:textColor="@color/blue_5"
android:textSize="@dimen/sp_12"
@@ -525,7 +534,7 @@
android:id="@+id/rv5"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginHorizontal="@dimen/dp_23"
android:layout_marginTop="@dimen/dp_10"
app:layout_constraintTop_toBottomOf="@+id/tv6"
tools:layout_height="@dimen/dp_40" />
@@ -548,8 +557,8 @@
android:layout_marginHorizontal="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_24"
android:layout_marginBottom="@dimen/dp_12"
- android:onClick="@{viewModel.onClick}"
android:backgroundTint="@color/blue_5"
+ android:onClick="@{viewModel.onClick}"
android:text="提交整备结果"
android:textSize="@dimen/sp_16"
android:textStyle="bold"
diff --git a/app/src/main/res/layout/activity_car_maintain_detail.xml b/app/src/main/res/layout/activity_car_maintain_detail.xml
index 7e04e5e..13b25c1 100644
--- a/app/src/main/res/layout/activity_car_maintain_detail.xml
+++ b/app/src/main/res/layout/activity_car_maintain_detail.xml
@@ -251,6 +251,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_15"
android:text="刹车灯情况"
+ android:visibility="gone"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_14"
android:textStyle="bold"
@@ -264,6 +265,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_15"
android:text="雾灯情况"
+ android:visibility="gone"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_14"
android:textStyle="bold"
@@ -276,6 +278,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_10"
+ android:visibility="gone"
app:layout_constraintLeft_toLeftOf="@+id/tv2"
app:layout_constraintRight_toRightOf="@+id/tv2"
app:layout_constraintTop_toBottomOf="@+id/tv4"
@@ -286,6 +289,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_10"
+ android:visibility="gone"
app:layout_constraintLeft_toLeftOf="@+id/tv3"
app:layout_constraintRight_toRightOf="@+id/tv3"
app:layout_constraintTop_toBottomOf="@+id/tv5"
@@ -396,7 +400,7 @@
android:layout_marginHorizontal="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_10"
tools:text="2026年 xxxxxxxxx"
- android:text="@{BindUtils.INSTANCE.formatDate(viewModel.recordInfo.operationTime)}"
+ android:text="@{viewModel.recordInfo.getShowOperationTime()}"
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_14"
app:layout_constraintTop_toBottomOf="@+id/tv8" />
diff --git a/app/src/main/res/layout/activity_car_manage.xml b/app/src/main/res/layout/activity_car_manage.xml
index 0c5e0bb..24ae697 100644
--- a/app/src/main/res/layout/activity_car_manage.xml
+++ b/app/src/main/res/layout/activity_car_manage.xml
@@ -60,7 +60,7 @@
android:paddingHorizontal="@dimen/dp_10"
app:layout_constraintTop_toTopOf="parent">
- <androidx.appcompat.widget.AppCompatEditText
+ <com.xw.yunwei.ui.widget.ClearEditText
android:id="@+id/searchEt"
android:layout_width="0dp"
android:layout_height="@dimen/dp_34"
@@ -70,6 +70,10 @@
android:drawableStart="@drawable/svg_search"
android:drawablePadding="@dimen/dp_10"
android:hint="请输入车牌号"
+ app:iconHeight="@dimen/dp_18"
+ android:maxLength="8"
+ app:iconWidth="@dimen/dp_18"
+ app:clearIcon="@mipmap/icon_close_gray"
android:imeOptions="actionSearch"
android:paddingHorizontal="@dimen/dp_10"
android:singleLine="true"
@@ -95,6 +99,18 @@
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
+ <View
+ android:id="@+id/filterOverlay"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:background="#80000000"
+ android:elevation="@dimen/dp_4"
+ android:visibility="gone"
+ app:layout_constraintTop_toBottomOf="@id/topLayout"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent" />
+
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="0dp"
diff --git a/app/src/main/res/layout/activity_car_repair_detail.xml b/app/src/main/res/layout/activity_car_repair_detail.xml
index 3f1ea78..7caea10 100644
--- a/app/src/main/res/layout/activity_car_repair_detail.xml
+++ b/app/src/main/res/layout/activity_car_repair_detail.xml
@@ -112,7 +112,7 @@
android:layout_marginHorizontal="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_10"
tools:text="2026年 xxxxxxxxx - 2026年 xxxxxxxxx"
- android:text='@{BindUtils.INSTANCE.formatDate(viewModel.recordInfo.startTime) + " ~ " + BindUtils.INSTANCE.formatDate(viewModel.recordInfo.endTime)}'
+ android:text='@{viewModel.recordInfo.getShowStartTime() + " ~ " + viewModel.recordInfo.getShowEndTime()}'
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_14" />
@@ -177,7 +177,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_15"
- android:text="送检时间"
+ android:text="送修时间"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16"
android:textStyle="bold" />
@@ -188,7 +188,7 @@
android:layout_marginHorizontal="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_10"
tools:text="2026年 xxxxx"
- android:text="@{BindUtils.INSTANCE.formatDate(viewModel.recordInfo.sendTime)}"
+ android:text="@{viewModel.recordInfo.getShowSendTime()}"
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_14" />
@@ -303,7 +303,7 @@
android:layout_marginTop="@dimen/dp_10"
show="@{viewModel.recordInfo.repairMoney != null}"
tools:text="2026年 xxxxx"
- android:text='@{BindUtils.INSTANCE.formatDate(viewModel.recordInfo.returnTime)}'
+ android:text='@{viewModel.recordInfo.getShowReturnTime()}'
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_14" />
diff --git a/app/src/main/res/layout/activity_car_report.xml b/app/src/main/res/layout/activity_car_report.xml
index 9d6d897..587a894 100644
--- a/app/src/main/res/layout/activity_car_report.xml
+++ b/app/src/main/res/layout/activity_car_report.xml
@@ -50,21 +50,21 @@
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon1"
+ src="@{viewModel.icon1}"
android:layout_width="@dimen/dp_16"
android:layout_height="@dimen/dp_16"
android:layout_marginStart="@dimen/dp_68"
android:layout_marginTop="@dimen/dp_16"
- src="@{viewModel.icon1}"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/svg_time2" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/line1"
+ src="@{viewModel.line1}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- src="@{viewModel.line1}"
app:layout_constraintBottom_toBottomOf="@+id/icon1"
app:layout_constraintLeft_toRightOf="@+id/icon1"
app:layout_constraintRight_toLeftOf="@+id/icon2"
@@ -73,10 +73,10 @@
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon2"
+ src="@{viewModel.icon2}"
android:layout_width="@dimen/dp_16"
android:layout_height="@dimen/dp_16"
android:layout_marginTop="@dimen/dp_16"
- src="@{viewModel.icon2}"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
@@ -84,10 +84,10 @@
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/line2"
+ src="@{viewModel.line2}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- src="@{viewModel.line2}"
app:layout_constraintBottom_toBottomOf="@+id/icon1"
app:layout_constraintLeft_toRightOf="@+id/icon2"
app:layout_constraintRight_toLeftOf="@+id/icon3"
@@ -96,11 +96,11 @@
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon3"
+ src="@{viewModel.icon3}"
android:layout_width="@dimen/dp_16"
android:layout_height="@dimen/dp_16"
android:layout_marginTop="@dimen/dp_16"
android:layout_marginEnd="@dimen/dp_68"
- src="@{viewModel.icon3}"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/svg_circle" />
@@ -149,12 +149,19 @@
</androidx.constraintlayout.widget.ConstraintLayout>
+ <View
+ android:id="@+id/v_line"
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:background="@color/gray_4"
+ app:layout_constraintTop_toBottomOf="@id/layout" />
+
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="@dimen/dp_24"
app:layout_constraintBottom_toTopOf="@+id/viewPdf"
- app:layout_constraintTop_toBottomOf="@+id/layout">
+ app:layout_constraintTop_toBottomOf="@+id/v_line">
<RelativeLayout
android:layout_width="match_parent"
@@ -163,21 +170,57 @@
app:layout_constraintBottom_toTopOf="@+id/viewPdf"
app:layout_constraintTop_toBottomOf="@+id/layout">
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/img"
+ <LinearLayout
+ android:id="@+id/ll_notice"
+ show="@{viewModel.carReportModel.status == 1}"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_40"
+ android:background="@color/color_e0ebf7"
+ android:gravity="center"
+ android:orientation="horizontal"
+ android:visibility="gone"
+ tools:visibility="visible">
+
+ <ImageView
+ android:layout_width="@dimen/dp_12"
+ android:layout_height="@dimen/dp_12"
+ android:src="@mipmap/ic_notice_blue" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_4"
+ android:text="您的保单查看申请已提交,等待运营管理人员人工审核"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_12" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/ll_pdf"
+ show="@{viewModel.carReportModel.status == 2}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_below="@id/ll_notice"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:orientation="vertical" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/img"
+ show="@{viewModel.carReportModel.status != 2}"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/ll_notice"
android:layout_margin="@dimen/dp_12"
android:adjustViewBounds="true"
android:src="@mipmap/img_car_report1" />
<com.google.android.material.button.MaterialButton
android:id="@+id/apply"
+ show="@{viewModel.carReportModel.status == 0}"
android:layout_width="@dimen/dp_200"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:backgroundTint="@color/blue_5"
- show="@{viewModel.carReportModel.status == 0}"
android:text="申请查看"
android:textSize="@dimen/sp_16"
android:textStyle="bold"
@@ -188,12 +231,12 @@
show="@{viewModel.carReportModel.status == 3}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- tools:visibility="visible"
android:layout_centerInParent="true"
android:layout_marginHorizontal="@dimen/dp_28"
android:background="@drawable/shape_white_bg_4"
+ android:orientation="vertical"
android:padding="@dimen/dp_12"
- android:orientation="vertical">
+ tools:visibility="visible">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv"
@@ -212,10 +255,10 @@
android:layout_marginTop="@dimen/dp_8"
android:lineSpacingMultiplier="1.3"
android:text="@{viewModel.carReportModel.xpPolicyApplicationVO.auditRemarks}"
- tools:text="维修原因描述维修原因描述维修原因描述维修原因描述维修原因描述维修原因描述维修原因描述维修原因描述维修原因描述"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_14"
- android:textStyle="bold" />
+ android:textStyle="bold"
+ tools:text="维修原因描述维修原因描述维修原因描述维修原因描述维修原因描述维修原因描述维修原因描述维修原因描述维修原因描述" />
<com.google.android.material.button.MaterialButton
android:id="@+id/reapply"
@@ -238,10 +281,10 @@
</ScrollView>
<View
+ show="@{viewModel.carReportModel.status == 2}"
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginBottom="@dimen/dp_12"
- show="@{viewModel.carReportModel.status == 2}"
android:background="@color/gray_4"
app:layout_constraintBottom_toTopOf="@+id/viewPdf" />
@@ -250,13 +293,13 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/dp_20"
- show="@{viewModel.carReportModel.status == 2}"
android:layout_marginTop="@dimen/dp_24"
android:layout_marginBottom="@dimen/dp_12"
android:backgroundTint="@color/blue_5"
android:text="查看PDF"
android:textSize="@dimen/sp_16"
android:textStyle="bold"
+ android:visibility="gone"
app:cornerRadius="@dimen/dp_4"
app:layout_constraintBottom_toBottomOf="parent" />
diff --git a/app/src/main/res/layout/activity_cert_upload.xml b/app/src/main/res/layout/activity_cert_upload.xml
index b4636a5..48cf32d 100644
--- a/app/src/main/res/layout/activity_cert_upload.xml
+++ b/app/src/main/res/layout/activity_cert_upload.xml
@@ -39,320 +39,490 @@
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@+id/back" />
-
- <ScrollView
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="@dimen/dp_88"
android:fillViewport="true"
+ android:orientation="vertical"
app:layout_constraintBottom_toTopOf="@+id/upload"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/cl_audit_progress"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="@dimen/dp_72">
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_18"
- android:text="身份证"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
+ <ImageView
+ android:id="@+id/iv_upload_progress"
+ android:layout_width="@dimen/dp_16"
+ android:layout_height="@dimen/dp_16"
+ android:layout_marginEnd="@dimen/dp_4"
+ android:src="@mipmap/icon_circle_gray"
+ app:layout_constraintBottom_toBottomOf="@id/lv_line1"
+ app:layout_constraintEnd_toStartOf="@id/lv_line1"
+ app:layout_constraintTop_toTopOf="@id/lv_line1" />
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/idFront"
- android:layout_width="@dimen/dp_160"
- android:layout_height="@dimen/dp_100"
- android:layout_marginTop="@dimen/dp_52"
- android:src="@mipmap/img_card_front"
- app:layout_constraintEnd_toStartOf="@+id/idBack"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
+ <com.xw.yunwei.ui.widget.LineView
+ android:id="@+id/lv_line1"
+ android:layout_width="@dimen/dp_88"
+ android:layout_height="@dimen/dp_5"
+ android:layout_marginEnd="@dimen/dp_4"
+ app:dashLineSize="@dimen/dp_3"
+ app:dashLineStroke="@dimen/dp_1"
+ app:layout_constraintBottom_toBottomOf="@id/iv_audit_progress"
+ app:layout_constraintEnd_toStartOf="@id/iv_audit_progress"
+ app:layout_constraintTop_toTopOf="@id/iv_audit_progress"
+ app:lineColor="@color/color_d9d9d9"
+ app:lineInterval="@dimen/dp_1" />
- <com.makeramen.roundedimageview.RoundedImageView
- android:id="@+id/idFrontPic"
- imageUrl="@{viewModel.idFront}"
- show='@{!"".equals(viewModel.idFront)}'
- android:layout_width="@dimen/dp_160"
- android:layout_height="@dimen/dp_100"
- android:background="@color/white"
- android:scaleType="centerCrop"
- app:layout_constraintBottom_toBottomOf="@+id/idFront"
- app:layout_constraintLeft_toLeftOf="@+id/idFront"
- app:layout_constraintRight_toRightOf="@+id/idFront"
- app:layout_constraintTop_toTopOf="@+id/idFront"
- app:riv_corner_radius="@dimen/dp_8"
- tools:background="@null" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/idBack"
- android:layout_width="@dimen/dp_160"
- android:layout_height="@dimen/dp_100"
- android:layout_marginTop="@dimen/dp_52"
- android:src="@mipmap/img_card_back"
+ <ImageView
+ android:id="@+id/iv_audit_progress"
+ android:layout_width="@dimen/dp_16"
+ android:layout_height="@dimen/dp_16"
+ android:layout_marginTop="@dimen/dp_16"
+ android:src="@mipmap/icon_circle_gray"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toEndOf="@+id/idFront"
+ app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
- <com.makeramen.roundedimageview.RoundedImageView
- android:id="@+id/idBackPic"
- imageUrl="@{viewModel.idBack}"
- show='@{!"".equals(viewModel.idBack)}'
- android:layout_width="@dimen/dp_160"
- android:layout_height="@dimen/dp_100"
- android:background="@color/white"
- android:scaleType="centerCrop"
- app:layout_constraintBottom_toBottomOf="@+id/idBack"
- app:layout_constraintLeft_toLeftOf="@+id/idBack"
- app:layout_constraintRight_toRightOf="@+id/idBack"
- app:layout_constraintTop_toTopOf="@+id/idBack"
- app:riv_corner_radius="@dimen/dp_8"
- tools:background="@null" />
+ <com.xw.yunwei.ui.widget.LineView
+ android:id="@+id/lv_line2"
+ android:layout_width="@dimen/dp_88"
+ android:layout_height="@dimen/dp_5"
+ android:layout_marginStart="@dimen/dp_4"
+ app:dashLineSize="@dimen/dp_3"
+ app:dashLineStroke="@dimen/dp_1"
+ app:layout_constraintBottom_toBottomOf="@id/iv_audit_progress"
+ app:layout_constraintStart_toEndOf="@id/iv_audit_progress"
+ app:layout_constraintTop_toTopOf="@id/iv_audit_progress"
+ app:lineColor="@color/color_d9d9d9"
+ app:lineInterval="@dimen/dp_1" />
- <androidx.appcompat.widget.AppCompatTextView
+ <ImageView
+ android:id="@+id/iv_through_progress"
+ android:layout_width="@dimen/dp_16"
+ android:layout_height="@dimen/dp_16"
+ android:layout_marginStart="@dimen/dp_4"
+ android:src="@mipmap/icon_circle_gray"
+ app:layout_constraintBottom_toBottomOf="@id/lv_line2"
+ app:layout_constraintStart_toEndOf="@id/lv_line2"
+ app:layout_constraintTop_toTopOf="@id/lv_line2" />
+
+ <TextView
+ android:id="@+id/tv_upload_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:layout_marginTop="@dimen/dp_4"
- android:text="请上传身份证头像正面照片"
- android:textColor="@color/gray_6"
+ android:layout_marginTop="@dimen/dp_8"
+ android:text="证件上传"
+ android:textColor="@color/gray_7"
android:textSize="@dimen/sp_12"
- app:layout_constraintLeft_toLeftOf="@+id/idFront"
- app:layout_constraintRight_toRightOf="@+id/idFront"
- app:layout_constraintTop_toBottomOf="@+id/idFront" />
+ app:layout_constraintEnd_toEndOf="@id/iv_upload_progress"
+ app:layout_constraintStart_toStartOf="@id/iv_upload_progress"
+ app:layout_constraintTop_toBottomOf="@id/iv_upload_progress" />
- <androidx.appcompat.widget.AppCompatTextView
+ <TextView
+ android:id="@+id/tv_audit_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:layout_marginTop="@dimen/dp_4"
- android:text="请上传身份证国徽面照片"
- android:textColor="@color/gray_6"
+ android:layout_marginTop="@dimen/dp_8"
+ android:text="平台审核"
+ android:textColor="@color/gray_7"
android:textSize="@dimen/sp_12"
- app:layout_constraintLeft_toLeftOf="@+id/idBack"
- app:layout_constraintRight_toRightOf="@+id/idBack"
- app:layout_constraintTop_toBottomOf="@+id/idBack" />
+ app:layout_constraintEnd_toEndOf="@id/iv_audit_progress"
+ app:layout_constraintStart_toStartOf="@id/iv_audit_progress"
+ app:layout_constraintTop_toBottomOf="@id/iv_audit_progress" />
- <View
- android:layout_width="match_parent"
- android:layout_height="@dimen/dp_8"
- android:layout_marginTop="@dimen/dp_36"
- android:background="@color/color_surface"
- app:layout_constraintTop_toBottomOf="@+id/idBack" />
-
- <androidx.appcompat.widget.AppCompatTextView
+ <TextView
+ android:id="@+id/tv_through_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_64"
- android:text="驾驶证"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/idBack" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/driveCard"
- android:layout_width="@dimen/dp_160"
- android:layout_height="@dimen/dp_100"
- android:layout_marginTop="@dimen/dp_98"
- android:src="@mipmap/img_driver"
- app:layout_constraintStart_toStartOf="@+id/idFront"
- app:layout_constraintTop_toBottomOf="@+id/idBack" />
-
- <com.makeramen.roundedimageview.RoundedImageView
- android:id="@+id/driveCardPic"
- imageUrl="@{viewModel.driveCard}"
- show='@{!"".equals(viewModel.driveCard)}'
- android:layout_width="@dimen/dp_160"
- android:layout_height="@dimen/dp_100"
- android:background="@color/white"
- android:scaleType="centerCrop"
- app:layout_constraintBottom_toBottomOf="@+id/driveCard"
- app:layout_constraintLeft_toLeftOf="@+id/driveCard"
- app:layout_constraintRight_toRightOf="@+id/driveCard"
- app:layout_constraintTop_toTopOf="@+id/driveCard"
- app:riv_corner_radius="@dimen/dp_8"
- tools:background="@null" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:layout_marginTop="@dimen/dp_4"
- android:text="请上传驾驶证主页"
- android:textColor="@color/gray_6"
+ android:layout_marginTop="@dimen/dp_8"
+ android:text="认证通过"
+ android:textColor="@color/gray_7"
android:textSize="@dimen/sp_12"
- app:layout_constraintLeft_toLeftOf="@+id/driveCard"
- app:layout_constraintRight_toRightOf="@+id/driveCard"
- app:layout_constraintTop_toBottomOf="@+id/driveCard" />
-
- <View
- android:layout_width="match_parent"
- android:layout_height="@dimen/dp_8"
- android:layout_marginTop="@dimen/dp_36"
- android:background="@color/color_surface"
- app:layout_constraintTop_toBottomOf="@+id/driveCard" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_64"
- android:text="无犯罪记录证明"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/driveCard" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/prove"
- android:layout_width="@dimen/dp_160"
- android:layout_height="@dimen/dp_100"
- android:layout_marginTop="@dimen/dp_98"
- android:src="@mipmap/img_prove"
- app:layout_constraintStart_toStartOf="@+id/idFront"
- app:layout_constraintTop_toBottomOf="@+id/driveCard" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@mipmap/ic_add"
- app:layout_constraintBottom_toBottomOf="@+id/prove"
- app:layout_constraintLeft_toLeftOf="@+id/prove"
- app:layout_constraintRight_toRightOf="@+id/prove"
- app:layout_constraintTop_toTopOf="@+id/prove" />
-
-
- <com.makeramen.roundedimageview.RoundedImageView
- android:id="@+id/provePic"
- imageUrl="@{viewModel.prove}"
- show='@{!"".equals(viewModel.prove)}'
- android:layout_width="@dimen/dp_160"
- android:layout_height="@dimen/dp_100"
- android:background="@color/white"
- android:scaleType="centerCrop"
- app:layout_constraintBottom_toBottomOf="@+id/prove"
- app:layout_constraintLeft_toLeftOf="@+id/prove"
- app:layout_constraintRight_toRightOf="@+id/prove"
- app:layout_constraintTop_toTopOf="@+id/prove"
- app:riv_corner_radius="@dimen/dp_8"
- tools:background="@null" />
-
- <View
- android:layout_width="match_parent"
- android:layout_height="@dimen/dp_8"
- android:layout_marginTop="@dimen/dp_36"
- android:background="@color/color_surface"
- app:layout_constraintTop_toBottomOf="@+id/prove" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_64"
- android:text="培训结业证书"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/prove" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/cert"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_98"
- android:src="@mipmap/img_cert"
- app:layout_constraintStart_toStartOf="@+id/idFront"
- app:layout_constraintTop_toBottomOf="@+id/prove" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@mipmap/ic_add"
- app:layout_constraintBottom_toBottomOf="@+id/cert"
- app:layout_constraintLeft_toLeftOf="@+id/cert"
- app:layout_constraintRight_toRightOf="@+id/cert"
- app:layout_constraintTop_toTopOf="@+id/cert" />
-
- <com.makeramen.roundedimageview.RoundedImageView
- android:id="@+id/certPic"
- imageUrl="@{viewModel.cert}"
- show='@{!"".equals(viewModel.cert)}'
- android:layout_width="@dimen/dp_160"
- android:layout_height="@dimen/dp_100"
- android:background="@color/white"
- android:scaleType="centerCrop"
- app:layout_constraintBottom_toBottomOf="@+id/cert"
- app:layout_constraintLeft_toLeftOf="@+id/cert"
- app:layout_constraintRight_toRightOf="@+id/cert"
- app:layout_constraintTop_toTopOf="@+id/cert"
- app:riv_corner_radius="@dimen/dp_8"
- tools:background="@null" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/certRefresh"
- show='@{!"".equals(viewModel.cert)}'
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/svg_refresh1"
- app:layout_constraintRight_toRightOf="@+id/cert"
- app:layout_constraintTop_toTopOf="@+id/cert" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/proveRefresh"
- show='@{!"".equals(viewModel.prove)}'
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/svg_refresh1"
- app:layout_constraintRight_toRightOf="@+id/prove"
- app:layout_constraintTop_toTopOf="@+id/prove" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/driveCardRefresh"
- show='@{!"".equals(viewModel.driveCard)}'
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/svg_refresh1"
- app:layout_constraintRight_toRightOf="@+id/driveCard"
- app:layout_constraintTop_toTopOf="@+id/driveCard" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/idBackRefresh"
- show='@{!"".equals(viewModel.idBack)}'
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/svg_refresh1"
- app:layout_constraintRight_toRightOf="@+id/idBack"
- app:layout_constraintTop_toTopOf="@+id/idBack" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/idFrontRefresh"
- show='@{!"".equals(viewModel.idFront)}'
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/svg_refresh1"
- app:layout_constraintRight_toRightOf="@+id/idFront"
- app:layout_constraintTop_toTopOf="@+id/idFront" />
-
- <View
- android:layout_width="match_parent"
- android:layout_height="@dimen/dp_8"
- android:layout_marginTop="@dimen/dp_36"
- android:background="@color/color_surface"
- app:layout_constraintTop_toBottomOf="@+id/cert" />
-
+ app:layout_constraintEnd_toEndOf="@id/iv_through_progress"
+ app:layout_constraintStart_toStartOf="@id/iv_through_progress"
+ app:layout_constraintTop_toBottomOf="@id/iv_through_progress" />
</androidx.constraintlayout.widget.ConstraintLayout>
- </ScrollView>
+ <LinearLayout
+ android:id="@+id/ll_notice"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/color_f8e4e1"
+ android:orientation="horizontal"
+ android:paddingHorizontal="@dimen/dp_20"
+ android:paddingVertical="@dimen/dp_12"
+ android:visibility="gone"
+ tools:visibility="visible">
+
+ <ImageView
+ android:layout_width="@dimen/dp_12"
+ android:layout_height="@dimen/dp_12"
+ android:layout_marginTop="@dimen/dp_4"
+ android:src="@mipmap/icon_warn_red" />
+
+ <TextView
+ android:id="@+id/tv_audit_fail"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_4"
+ android:textColor="@color/red_5"
+ android:textSize="@dimen/sp_12"
+ tools:text="驳回原因:这里是驳回原因这里是驳回原因这里是驳回这里是驳回原因这里是驳回原因这里是驳回" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/ll_audit"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:visibility="gone"
+ tools:visibility="visible">
+
+ <ImageView
+ android:layout_width="@dimen/dp_120"
+ android:layout_height="@dimen/dp_120"
+ android:layout_marginTop="@dimen/dp_44"
+ android:src="@mipmap/icon_clock_blue2" />
+
+ <TextView
+ android:id="@+id/tv_wait_audit_notice"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_8"
+ android:layout_marginHorizontal="@dimen/dp_60"
+ android:gravity="center"
+ android:text="本次更新证件正在复核,原有认证资质暂保持有效"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold" />
+ </LinearLayout>
+
+ <ScrollView
+ android:id="@+id/sv_cert"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:visibility="gone"
+ tools:visibility="visible">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_20"
+ android:drawableStart="@drawable/svg_must"
+ android:text="身份证"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/idFront"
+ android:layout_width="@dimen/dp_160"
+ android:layout_height="@dimen/dp_100"
+ android:layout_marginTop="@dimen/dp_52"
+ android:layout_marginStart="@dimen/dp_8"
+ android:src="@mipmap/img_card_front"
+ app:layout_constraintEnd_toStartOf="@+id/idBack"
+ app:layout_constraintHorizontal_chainStyle="spread_inside"
+ app:layout_constraintStart_toStartOf="@id/tv_label"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <com.makeramen.roundedimageview.RoundedImageView
+ android:id="@+id/idFrontPic"
+ imageUrl="@{viewModel.idFront}"
+ show='@{!"".equals(viewModel.idFront)}'
+ android:layout_width="@dimen/dp_160"
+ android:layout_height="@dimen/dp_100"
+ android:background="@color/white"
+ android:scaleType="centerCrop"
+ app:layout_constraintBottom_toBottomOf="@+id/idFront"
+ app:layout_constraintLeft_toLeftOf="@+id/idFront"
+ app:layout_constraintRight_toRightOf="@+id/idFront"
+ app:layout_constraintTop_toTopOf="@+id/idFront"
+ app:riv_corner_radius="@dimen/dp_8"
+ tools:background="@null" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/idBack"
+ android:layout_width="@dimen/dp_160"
+ android:layout_height="@dimen/dp_100"
+ android:layout_marginTop="@dimen/dp_52"
+ android:layout_marginStart="@dimen/dp_15"
+ android:src="@mipmap/img_card_back"
+ app:layout_constraintStart_toEndOf="@+id/idFront"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <com.makeramen.roundedimageview.RoundedImageView
+ android:id="@+id/idBackPic"
+ imageUrl="@{viewModel.idBack}"
+ show='@{!"".equals(viewModel.idBack)}'
+ android:layout_width="@dimen/dp_160"
+ android:layout_height="@dimen/dp_100"
+ android:background="@color/white"
+ android:scaleType="centerCrop"
+ app:layout_constraintBottom_toBottomOf="@+id/idBack"
+ app:layout_constraintLeft_toLeftOf="@+id/idBack"
+ app:layout_constraintRight_toRightOf="@+id/idBack"
+ app:layout_constraintTop_toTopOf="@+id/idBack"
+ app:riv_corner_radius="@dimen/dp_8"
+ tools:background="@null" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="@dimen/dp_4"
+ android:text="请上传身份证头像正面照片"
+ android:textColor="@color/gray_6"
+ android:textSize="@dimen/sp_12"
+ app:layout_constraintLeft_toLeftOf="@+id/idFront"
+ app:layout_constraintRight_toRightOf="@+id/idFront"
+ app:layout_constraintTop_toBottomOf="@+id/idFront" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="@dimen/dp_4"
+ android:text="请上传身份证国徽面照片"
+ android:textColor="@color/gray_6"
+ android:textSize="@dimen/sp_12"
+ app:layout_constraintLeft_toLeftOf="@+id/idBack"
+ app:layout_constraintRight_toRightOf="@+id/idBack"
+ app:layout_constraintTop_toBottomOf="@+id/idBack" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_8"
+ android:layout_marginTop="@dimen/dp_36"
+ android:background="@color/color_surface"
+ app:layout_constraintTop_toBottomOf="@+id/idBack" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_64"
+ android:drawableStart="@drawable/svg_must"
+ android:text="驾驶证"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/idBack" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/driveCard"
+ android:layout_width="@dimen/dp_160"
+ android:layout_height="@dimen/dp_100"
+ android:layout_marginTop="@dimen/dp_98"
+ android:src="@mipmap/img_driver"
+ app:layout_constraintStart_toStartOf="@+id/idFront"
+ app:layout_constraintTop_toBottomOf="@+id/idBack" />
+
+ <com.makeramen.roundedimageview.RoundedImageView
+ android:id="@+id/driveCardPic"
+ imageUrl="@{viewModel.driveCard}"
+ show='@{!"".equals(viewModel.driveCard)}'
+ android:layout_width="@dimen/dp_160"
+ android:layout_height="@dimen/dp_100"
+ android:background="@color/white"
+ android:scaleType="centerCrop"
+ app:layout_constraintBottom_toBottomOf="@+id/driveCard"
+ app:layout_constraintLeft_toLeftOf="@+id/driveCard"
+ app:layout_constraintRight_toRightOf="@+id/driveCard"
+ app:layout_constraintTop_toTopOf="@+id/driveCard"
+ app:riv_corner_radius="@dimen/dp_8"
+ tools:background="@null" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="@dimen/dp_4"
+ android:text="请上传驾驶证主页"
+ android:textColor="@color/gray_6"
+ android:textSize="@dimen/sp_12"
+ app:layout_constraintLeft_toLeftOf="@+id/driveCard"
+ app:layout_constraintRight_toRightOf="@+id/driveCard"
+ app:layout_constraintTop_toBottomOf="@+id/driveCard" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_8"
+ android:layout_marginTop="@dimen/dp_36"
+ android:background="@color/color_surface"
+ app:layout_constraintTop_toBottomOf="@+id/driveCard" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_64"
+ android:drawableStart="@drawable/svg_must"
+ android:text="无犯罪记录证明"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/driveCard" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/prove"
+ android:layout_width="@dimen/dp_160"
+ android:layout_height="@dimen/dp_100"
+ android:layout_marginTop="@dimen/dp_98"
+ android:src="@mipmap/img_prove"
+ app:layout_constraintStart_toStartOf="@+id/idFront"
+ app:layout_constraintTop_toBottomOf="@+id/driveCard" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@mipmap/ic_add"
+ app:layout_constraintBottom_toBottomOf="@+id/prove"
+ app:layout_constraintLeft_toLeftOf="@+id/prove"
+ app:layout_constraintRight_toRightOf="@+id/prove"
+ app:layout_constraintTop_toTopOf="@+id/prove" />
+
+
+ <com.makeramen.roundedimageview.RoundedImageView
+ android:id="@+id/provePic"
+ imageUrl="@{viewModel.prove}"
+ show='@{!"".equals(viewModel.prove)}'
+ android:layout_width="@dimen/dp_160"
+ android:layout_height="@dimen/dp_100"
+ android:background="@color/white"
+ android:scaleType="centerCrop"
+ app:layout_constraintBottom_toBottomOf="@+id/prove"
+ app:layout_constraintLeft_toLeftOf="@+id/prove"
+ app:layout_constraintRight_toRightOf="@+id/prove"
+ app:layout_constraintTop_toTopOf="@+id/prove"
+ app:riv_corner_radius="@dimen/dp_8"
+ tools:background="@null" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_8"
+ android:layout_marginTop="@dimen/dp_36"
+ android:background="@color/color_surface"
+ app:layout_constraintTop_toBottomOf="@+id/prove" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_64"
+ android:drawableStart="@drawable/svg_must"
+ android:text="培训结业证书"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/prove" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/cert"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_98"
+ android:src="@mipmap/img_cert"
+ app:layout_constraintStart_toStartOf="@+id/idFront"
+ app:layout_constraintTop_toBottomOf="@+id/prove" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@mipmap/ic_add"
+ app:layout_constraintBottom_toBottomOf="@+id/cert"
+ app:layout_constraintLeft_toLeftOf="@+id/cert"
+ app:layout_constraintRight_toRightOf="@+id/cert"
+ app:layout_constraintTop_toTopOf="@+id/cert" />
+
+ <com.makeramen.roundedimageview.RoundedImageView
+ android:id="@+id/certPic"
+ imageUrl="@{viewModel.cert}"
+ show='@{!"".equals(viewModel.cert)}'
+ android:layout_width="@dimen/dp_160"
+ android:layout_height="@dimen/dp_100"
+ android:background="@color/white"
+ android:scaleType="centerCrop"
+ app:layout_constraintBottom_toBottomOf="@+id/cert"
+ app:layout_constraintLeft_toLeftOf="@+id/cert"
+ app:layout_constraintRight_toRightOf="@+id/cert"
+ app:layout_constraintTop_toTopOf="@+id/cert"
+ app:riv_corner_radius="@dimen/dp_8"
+ tools:background="@null" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/certRefresh"
+ show='@{viewModel.certRefresh}'
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/svg_refresh1"
+ app:layout_constraintRight_toRightOf="@+id/cert"
+ app:layout_constraintTop_toTopOf="@+id/cert" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/proveRefresh"
+ show='@{viewModel.proveRefresh}'
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/svg_refresh1"
+ app:layout_constraintRight_toRightOf="@+id/prove"
+ app:layout_constraintTop_toTopOf="@+id/prove" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/driveCardRefresh"
+ show='@{viewModel.driveCardRefresh}'
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/svg_refresh1"
+ app:layout_constraintRight_toRightOf="@+id/driveCard"
+ app:layout_constraintTop_toTopOf="@+id/driveCard" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/idBackRefresh"
+ show='@{viewModel.idBackRefresh}'
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/svg_refresh1"
+ app:layout_constraintRight_toRightOf="@+id/idBack"
+ app:layout_constraintTop_toTopOf="@+id/idBack" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/idFrontRefresh"
+ show='@{viewModel.idFrontRefresh}'
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/svg_refresh1"
+ app:layout_constraintRight_toRightOf="@+id/idFront"
+ app:layout_constraintTop_toTopOf="@+id/idFront" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_8"
+ android:layout_marginTop="@dimen/dp_36"
+ android:background="@color/color_surface"
+ app:layout_constraintTop_toBottomOf="@+id/cert" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ </ScrollView>
+
+ </LinearLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/upload"
diff --git a/app/src/main/res/layout/activity_check_in.xml b/app/src/main/res/layout/activity_check_in.xml
index 1696ec9..c9e6c91 100644
--- a/app/src/main/res/layout/activity_check_in.xml
+++ b/app/src/main/res/layout/activity_check_in.xml
@@ -9,7 +9,7 @@
name="viewModel"
type="com.xw.yunwei.ui.user.mine.checkin.CheckInVM" />
- <import type="com.xw.common.utils.BindUtils"/>
+ <import type="com.xw.common.utils.BindUtils" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
@@ -56,31 +56,35 @@
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatImageView
- show="@{viewModel.isClock}"
+ android:id="@+id/iv_check_success"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/dp_22"
android:layout_marginBottom="@dimen/dp_30"
- android:src="@mipmap/img_check_in_suc" />
+ android:src="@mipmap/img_check_in_suc"
+ android:visibility="gone"
+ tools:visibility="visible" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/clockIn"
selected="@{viewModel.canClock}"
- show="@{!viewModel.isClock && viewModel.clockType==1}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
- android:src="@drawable/selector_clock_in" />
+ android:src="@drawable/selector_clock_in"
+ android:visibility="gone"
+ tools:visibility="visible" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/clockOut"
selected="@{viewModel.canClock}"
- show="@{!viewModel.isClock && viewModel.clockType==2}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
- android:src="@drawable/selector_clock_out" />
+ android:src="@drawable/selector_clock_out"
+ android:visibility="gone"
+ tools:visibility="visible" />
</RelativeLayout>
@@ -116,14 +120,16 @@
</LinearLayout>
<LinearLayout
+ android:id="@+id/ll_check_in_info"
android:layout_width="match_parent"
- android:orientation="vertical"
- show="@{viewModel.isClock}"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/tipsLayout"
+ android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_24"
android:layout_marginTop="@dimen/dp_30"
- android:layout_height="wrap_content">
+ android:orientation="vertical"
+ android:visibility="gone"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/tipsLayout"
+ tools:visibility="visible">
<LinearLayout
android:layout_width="match_parent"
@@ -156,11 +162,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_16"
- tools:text="打卡时间:2026-09-09 18:09:09"
- android:text='@{"打卡时间:" + (viewModel.clockModel.xpClockIn.clockInResult != 3 ? viewModel.clockModel.xpClockIn.clockInTime : "-")}'
+ android:text='@{"打卡时间:" + (viewModel.clockModel.xpClockIn.clockInResult != 3 ? viewModel.clockModel.xpClockIn.getFormateClockInTime() : "-")}'
android:textColor="@color/gray_8"
android:textSize="@dimen/sp_14"
- android:textStyle="bold"/>
+ android:textStyle="bold"
+ tools:text="打卡时间:2026-09-09 18:09:09" />
<LinearLayout
show='@{viewModel.clockModel.xpClockIn.clockInResult != 3}'
@@ -180,17 +186,29 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_5"
- tools:text="广州市天河区珠江新城幸福小区东北门"
android:text="@{viewModel.clockModel.xpClockIn.clockInAddress}"
android:textColor="@color/gray_7"
- android:textSize="@dimen/sp_12" />
+ android:textSize="@dimen/sp_12"
+ tools:text="广州市天河区珠江新城幸福小区东北门" />
</LinearLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/ll_check_out_info"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_24"
+ android:layout_marginTop="@dimen/dp_30"
+ android:orientation="vertical"
+ android:visibility="gone"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/ll_check_in_info"
+ tools:visibility="visible">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_30"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatTextView
@@ -219,11 +237,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_16"
- tools:text="打卡时间:2026-09-09 18:09:09"
- android:text='@{"打卡时间:"+viewModel.clockModel.xpClockIn.clockOutTime}'
+ android:text='@{"打卡时间:"+viewModel.clockModel.xpClockIn.getFormateClockOutTime()}'
android:textColor="@color/gray_8"
android:textSize="@dimen/sp_14"
- android:textStyle="bold"/>
+ android:textStyle="bold"
+ tools:text="打卡时间:2026-09-09 18:09:09" />
<LinearLayout
android:layout_width="wrap_content"
@@ -242,10 +260,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_5"
- tools:text="广州市天河区珠江新城幸福小区东北门"
android:text="@{viewModel.clockModel.xpClockIn.clockOutAddress}"
android:textColor="@color/gray_7"
- android:textSize="@dimen/sp_12" />
+ android:textSize="@dimen/sp_12"
+ tools:text="广州市天河区珠江新城幸福小区东北门" />
</LinearLayout>
@@ -253,19 +271,19 @@
<LinearLayout
android:id="@+id/viewDetail"
- show="@{!viewModel.canClock && !viewModel.isClock}"
+ show="@{!viewModel.canClock && !viewModel.isClock && !viewModel.distanceEffective}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="@dimen/dp_24"
- tools:visibility="gone"
android:background="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="4dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/tipsLayout">
+ app:layout_constraintTop_toBottomOf="@+id/tipsLayout"
+ tools:visibility="gone">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
@@ -280,16 +298,14 @@
android:layout_marginStart="4dp"
android:src="@drawable/svg_arrow_r"
android:tint="@color/blue_5" />
-
</LinearLayout>
<LinearLayout
android:id="@+id/refreshLayout"
- show="@{!viewModel.canClock && !viewModel.isClock}"
+ show="@{!viewModel.canClock && !viewModel.isClock && !viewModel.distanceEffective}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_24"
- tools:visibility="gone"
android:background="@drawable/shape_f8f9fa_bg_4"
android:gravity="center_vertical"
android:orientation="horizontal"
@@ -297,7 +313,8 @@
android:paddingVertical="@dimen/dp_8"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/viewDetail">
+ app:layout_constraintTop_toBottomOf="@+id/viewDetail"
+ tools:visibility="visible">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
diff --git a/app/src/main/res/layout/activity_check_in_mission_points_list.xml b/app/src/main/res/layout/activity_check_in_mission_points_list.xml
new file mode 100644
index 0000000..1beadfb
--- /dev/null
+++ b/app/src/main/res/layout/activity_check_in_mission_points_list.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <data>
+
+ <variable
+ name="viewModel"
+ type="com.xw.yunwei.ui.work.checkInMission.viewmodel.CheckInMissionPointsListViewModel" />
+
+ <import type="com.xw.common.utils.BindUtils" />
+ </data>
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/white">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/back"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_56"
+ android:onClick="@{viewModel::onBack}"
+ android:src="@drawable/svg_back"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="打卡点位列表"
+ android:textColor="@color/gray_10"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:layout_constraintBottom_toBottomOf="@+id/back"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="@+id/back" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="@dimen/dp_88"
+ android:fillViewport="true"
+ android:orientation="vertical">
+
+ <com.scwang.smart.refresh.layout.SmartRefreshLayout
+ android:id="@+id/refreshLayout"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/rv_list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:itemCount="3"
+ tools:listitem="@layout/item_check_in_mission_point" />
+
+ </com.scwang.smart.refresh.layout.SmartRefreshLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:background="@color/gray_4" />
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/btn_plan"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginVertical="@dimen/dp_12"
+ android:backgroundTint="@color/blue_5"
+ android:onClick="@{viewModel.onClick}"
+ android:text="路径规划"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:cornerRadius="@dimen/dp_4" />
+ </LinearLayout>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_create_task.xml b/app/src/main/res/layout/activity_create_task.xml
index 8b2acc1..a18ccd8 100644
--- a/app/src/main/res/layout/activity_create_task.xml
+++ b/app/src/main/res/layout/activity_create_task.xml
@@ -82,7 +82,7 @@
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_10"
+ android:layout_marginHorizontal="@dimen/dp_10"
android:layout_weight="1"
android:orientation="vertical">
@@ -97,9 +97,11 @@
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/color"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/dp_4"
+ android:singleLine="true"
+ android:ellipsize="end"
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_14"
tools:text="白色 | 车身编码:01234" />
@@ -140,10 +142,10 @@
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_address"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:layout_marginStart="@dimen/dp_12"
+ android:layout_marginHorizontal="@dimen/dp_12"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_14"
android:textStyle="bold"
@@ -167,11 +169,19 @@
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16" />
+ <LinearLayout
+ android:id="@+id/ll_filters"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_weight="1"
+ android:gravity="center_vertical|end"
+ android:orientation="horizontal" />
+
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvAccidentFilter"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
android:layout_weight="1"
android:gravity="end"
android:hint="请选择"
@@ -194,15 +204,28 @@
android:layout_marginHorizontal="@dimen/dp_20"
android:background="@color/gray_4" />
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_8"
- android:text="任务等级"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold" />
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_8">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="@dimen/dp_12"
+ android:src="@drawable/svg_must" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:text="任务等级"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold" />
+
+ </FrameLayout>
<LinearLayout
android:layout_width="match_parent"
@@ -331,22 +354,42 @@
android:textSize="@dimen/sp_16"
android:textStyle="bold" />
- <androidx.appcompat.widget.AppCompatEditText
+ <FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_16"
- android:background="@drawable/shape_gray_3_bg_4"
- android:gravity="top"
- android:hint="请输入任务描述"
- android:maxLength="600"
- android:minHeight="@dimen/dp_100"
- android:padding="@dimen/dp_12"
- android:text="@={viewModel.taskDesc}"
- android:textColor="@color/gray_9"
- android:textColorHint="@color/gray_6"
- android:textSize="@dimen/sp_14"
- app:layout_constraintTop_toBottomOf="@+id/tv1" />
+ app:layout_constraintTop_toBottomOf="@+id/tv1">
+
+ <androidx.appcompat.widget.AppCompatEditText
+ android:id="@+id/et_input"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_gray_3_bg_4"
+ android:gravity="top"
+ android:hint="请输入任务描述"
+ android:maxLength="600"
+ android:minHeight="@dimen/dp_100"
+ android:paddingLeft="@dimen/dp_12"
+ android:paddingRight="@dimen/dp_12"
+ android:paddingTop="@dimen/dp_12"
+ android:paddingBottom="@dimen/dp_18"
+ android:text="@={viewModel.taskDesc}"
+ android:textColor="@color/gray_9"
+ android:textColorHint="@color/gray_6"
+ android:textSize="@dimen/sp_14" />
+
+ <TextView
+ android:id="@+id/tv_count"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|end"
+ android:layout_marginEnd="@dimen/dp_12"
+ android:layout_marginBottom="@dimen/dp_2"
+ android:text='@{viewModel.taskDesc.length()+"/600"}'
+ android:textColor="@color/gray_6"
+ android:textSize="@dimen/sp_11" />
+ </FrameLayout>
<View
android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/activity_cruise_check_in.xml b/app/src/main/res/layout/activity_cruise_check_in.xml
new file mode 100644
index 0000000..7b49c97
--- /dev/null
+++ b/app/src/main/res/layout/activity_cruise_check_in.xml
@@ -0,0 +1,526 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <data>
+
+ <variable
+ name="viewModel"
+ type="com.xw.yunwei.ui.work.checkInMission.viewmodel.CruiseCheckInViewModel" />
+
+ <import type="com.xw.common.utils.BindUtils" />
+ </data>
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/white">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/back"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_56"
+ android:onClick="@{viewModel::onBack}"
+ android:src="@drawable/svg_back"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="巡游打卡"
+ android:textColor="@color/gray_10"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:layout_constraintBottom_toBottomOf="@+id/back"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="@+id/back" />
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="@dimen/dp_88">
+
+ <com.amap.api.maps.TextureMapView
+ android:id="@+id/amap_view"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_marginBottom="@dimen/dp_107"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <FrameLayout
+ android:id="@+id/fl_bottom_operation"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_white_bg_top_12"
+ android:paddingBottom="@dimen/dp_85"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent">
+
+ <LinearLayout
+ android:id="@+id/ll_operation_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/iv_flexing"
+ android:layout_width="@dimen/dp_40"
+ android:layout_height="@dimen/dp_40"
+ android:padding="@dimen/dp_8"
+ android:src="@mipmap/ic_up" />
+
+ <LinearLayout
+ android:id="@+id/ll_location_info"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingHorizontal="@dimen/dp_20"
+ android:paddingBottom="@dimen/dp_20"
+ android:visibility="gone"
+ tools:visibility="visible">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="正在前往"
+ android:textColor="@color/gray_10"
+ android:textSize="@dimen/sp_18"
+ android:textStyle="bold" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_16"
+ android:text="打卡限时"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_36"
+ android:layout_marginTop="@dimen/dp_8"
+ android:background="@drawable/shape_f8f9fa_bg_4"
+ android:gravity="center"
+ android:orientation="horizontal"
+ android:paddingStart="@dimen/dp_8">
+
+ <TextView
+ android:id="@+id/tv_time"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ tools:text="08:00~09:00" />
+
+ <TextView
+ android:id="@+id/tv_check_in"
+ android:layout_width="@dimen/dp_120"
+ android:layout_height="match_parent"
+ android:background="@drawable/shape_blue_5_bg_4"
+ android:gravity="center"
+ android:text="打卡"
+ android:textColor="@color/white"
+ android:textSize="@dimen/sp_16" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="end"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/tv_check_in_notice"
+ android:layout_width="@dimen/dp_120"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:text="未进入打卡范围"
+ android:textColor="@color/red_5"
+ android:textSize="@dimen/sp_11" />
+ </LinearLayout>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_16"
+ android:text="打卡点位信息"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_8"
+ android:background="@mipmap/img_map"
+ android:minHeight="@dimen/dp_58"
+ android:orientation="horizontal">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_address"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="@dimen/dp_12"
+ android:layout_weight="1"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ tools:text="蜀山区华侨中心A座2301" />
+ </LinearLayout>
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/ll_click_location_info"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:orientation="vertical"
+ android:padding="@dimen/dp_20"
+ android:visibility="gone"
+ tools:visibility="visible">
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:id="@+id/ll_click_location_info_back"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:layout_width="@dimen/dp_6"
+ android:layout_height="@dimen/dp_12"
+ android:src="@mipmap/icon_arrow_left_blue" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_4"
+ android:text="返回"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold" />
+ </LinearLayout>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:text="点位信息"
+ android:textColor="@color/gray_10"
+ android:textSize="@dimen/sp_18"
+ android:textStyle="bold" />
+ </FrameLayout>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_16"
+ android:text="打卡限时"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_36"
+ android:layout_marginTop="@dimen/dp_8"
+ android:background="@drawable/shape_f8f9fa_bg_4"
+ android:gravity="center"
+ android:orientation="horizontal"
+ android:paddingStart="@dimen/dp_8">
+
+ <TextView
+ android:id="@+id/tv_click_location_time"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ tools:text="08:00~09:00" />
+
+ <TextView
+ android:id="@+id/tv_click_location_check_in"
+ android:layout_width="@dimen/dp_120"
+ android:layout_height="match_parent"
+ android:background="@drawable/shape_blue_5_bg_4"
+ android:gravity="center"
+ android:text="打卡"
+ android:textColor="@color/white"
+ android:textSize="@dimen/sp_16" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="end"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/tv_click_location_check_in_notice"
+ android:layout_width="@dimen/dp_120"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:text="未进入打卡范围"
+ android:textColor="@color/red_5"
+ android:textSize="@dimen/sp_11" />
+ </LinearLayout>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="打卡点位信息"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_8"
+ android:background="@mipmap/img_map"
+ android:minHeight="@dimen/dp_58"
+ android:orientation="horizontal">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_click_location_address"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="@dimen/dp_12"
+ android:layout_weight="1"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ tools:text="蜀山区华侨中心A座2301" />
+ </LinearLayout>
+ </LinearLayout>
+ </FrameLayout>
+
+ <com.lihang.ShadowLayout
+ android:id="@+id/sl_float_notice"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_16"
+ android:layout_marginBottom="@dimen/dp_17"
+ android:visibility="gone"
+ app:hl_cornerRadius="@dimen/dp_8"
+ app:hl_shadowColor="#2a000000"
+ app:hl_shadowLimit="@dimen/dp_8"
+ app:layout_constraintBottom_toTopOf="@id/fl_bottom_operation"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ tools:visibility="visible">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_white_bg_8"
+ android:orientation="vertical"
+ android:padding="@dimen/dp_16">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:layout_width="@dimen/dp_20"
+ android:layout_height="@dimen/dp_20"
+ android:src="@mipmap/icon_ring_blue" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="提示"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_13"
+ android:textStyle="bold" />
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/tv_float_notice"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_16"
+ android:layout_marginBottom="@dimen/dp_20"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ tools:text="您已到达【蜀山区华侨中心A座2301】打卡点,是否立即打卡?" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_42"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/tv_float_delay_check_in"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/dp_5"
+ android:layout_weight="96"
+ android:background="@drawable/shape_gray_5_line_4"
+ android:gravity="center"
+ android:text="稍后打卡"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16" />
+
+ <TextView
+ android:id="@+id/tv_float_check_in"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_marginStart="@dimen/dp_5"
+ android:layout_weight="189"
+ android:background="@drawable/shape_blue_5_bg_4"
+ android:gravity="center"
+ android:text="立即打卡"
+ android:textColor="@color/white"
+ android:textSize="@dimen/sp_16" />
+ </LinearLayout>
+ </LinearLayout>
+ </com.lihang.ShadowLayout>
+
+ <LinearLayout
+ android:id="@+id/ll_timeout_notice"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/dp_40"
+ android:background="@color/color_f8e4e1"
+ android:gravity="center"
+ android:orientation="horizontal"
+ android:visibility="gone"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:visibility="visible">
+
+ <ImageView
+ android:layout_width="@dimen/dp_12"
+ android:layout_height="@dimen/dp_12"
+ android:layout_marginStart="@dimen/dp_20"
+ android:src="@mipmap/icon_warn_red" />
+
+ <TextView
+ android:id="@+id/tv_timeout_notice"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_4"
+ android:layout_weight="1"
+ android:text="即将超时,请尽快前往打卡点"
+ android:textColor="@color/red_5"
+ android:textSize="@dimen/sp_12" />
+
+ <ImageView
+ android:id="@+id/iv_close_timeout_notice"
+ android:layout_width="@dimen/dp_20"
+ android:layout_height="@dimen/dp_20"
+ android:layout_marginEnd="@dimen/dp_10"
+ android:src="@mipmap/ic_close_black" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/ll_bottom_operation"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/dp_85"
+ android:gravity="center"
+ android:orientation="horizontal"
+ android:paddingHorizontal="@dimen/dp_20"
+ android:paddingBottom="@dimen/dp_20"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent">
+
+ <LinearLayout
+ android:id="@+id/ll_exit"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <ImageView
+ android:layout_width="@dimen/dp_24"
+ android:layout_height="@dimen/dp_24"
+ android:src="@mipmap/ic_close_black2" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_4"
+ android:text="退出"
+ android:textColor="@color/color_3d3d3d"
+ android:textSize="@dimen/sp_14" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/ll_navi_info"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/tv_distance_cost_time"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:singleLine="true"
+ android:textColor="@color/gray_10"
+ android:textSize="@dimen/sp_20"
+ android:textStyle="bold"
+ tools:text="8.4公里 1小时28分" />
+
+ <TextView
+ android:id="@+id/tv_estimated_time_of_arrival"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:singleLine="true"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_18"
+ android:textStyle="bold"
+ tools:text="20:20到达" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/ll_overview"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/iv_overview"
+ android:layout_width="@dimen/dp_24"
+ android:layout_height="@dimen/dp_24"
+ android:src="@mipmap/ic_route_arrow" />
+
+ <TextView
+ android:id="@+id/tv_overview"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_4"
+ android:text="全览"
+ android:textColor="@color/color_3d3d3d"
+ android:textSize="@dimen/sp_14" />
+ </LinearLayout>
+ </LinearLayout>
+ </androidx.constraintlayout.widget.ConstraintLayout>
+ </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_cruise_check_in_mission_complete.xml b/app/src/main/res/layout/activity_cruise_check_in_mission_complete.xml
new file mode 100644
index 0000000..85f2c48
--- /dev/null
+++ b/app/src/main/res/layout/activity_cruise_check_in_mission_complete.xml
@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <data>
+
+ <variable
+ name="viewModel"
+ type="com.xw.yunwei.ui.work.checkInMission.viewmodel.CruiseCheckInMissionCompleteViewModel" />
+
+ <import type="com.xw.common.utils.BindUtils" />
+ </data>
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/white">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/back"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_56"
+ android:onClick="@{viewModel::onBack}"
+ android:src="@drawable/svg_back"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="打卡成功"
+ android:textColor="@color/gray_10"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:layout_constraintBottom_toBottomOf="@+id/back"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="@+id/back" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="@dimen/dp_88"
+ android:fillViewport="true"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <ImageView
+ android:layout_width="@dimen/dp_160"
+ android:layout_height="@dimen/dp_160"
+ android:layout_marginTop="@dimen/dp_14"
+ android:src="@mipmap/ic_cup_book" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="恭喜您,已完成所有点位打卡!"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold" />
+
+ <LinearLayout
+ android:layout_width="@dimen/dp_144"
+ android:layout_height="@dimen/dp_36"
+ android:layout_marginTop="@dimen/dp_40"
+ android:gravity="center"
+ android:background="@drawable/shape_gray_3_bg_4"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:layout_width="@dimen/dp_20"
+ android:layout_height="@dimen/dp_20"
+ android:src="@mipmap/icon_location_green" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_4"
+ android:text="该点位已成功打卡"
+ android:textColor="@color/gray_8"
+ android:textSize="@dimen/sp_13" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_marginHorizontal="@dimen/dp_24"
+ android:layout_marginTop="@dimen/dp_24"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/tv_time"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textColor="@color/color_cc31456A"
+ android:textSize="@dimen/sp_14"
+ tools:text="打卡时间:2026/09/09 18:09:09" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_8"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="打卡类型:"
+ android:textColor="@color/color_cc31456A"
+ android:textSize="@dimen/sp_14" />
+
+ <TextView
+ android:id="@+id/tv_check_result"
+ android:layout_width="@dimen/dp_64"
+ android:layout_height="@dimen/dp_24"
+ android:gravity="center"
+ android:text="超时打卡"
+ android:textColor="@color/color_cc31456A"
+ android:textSize="@dimen/sp_12" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_8"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="现场情况:"
+ android:textColor="@color/color_cc31456A"
+ android:textSize="@dimen/sp_14" />
+
+ <TextView
+ android:id="@+id/tv_work_status"
+ android:layout_width="@dimen/dp_40"
+ android:layout_height="@dimen/dp_24"
+ android:gravity="center"
+ android:text="拥堵"
+ android:textColor="@color/color_cc31456A"
+ android:textSize="@dimen/sp_12" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_8"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="描述内容:"
+ android:textColor="@color/color_cc31456A"
+ android:textSize="@dimen/sp_14" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/tv_desc"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textColor="@color/color_cc31456A"
+ android:textSize="@dimen/sp_14"
+ tools:text="描述内容详情描述内容详情描述内容详情描述内容详情描述内容详情描述内容详情描述内容详情" />
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/rv_list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_8"
+ android:layout_marginEnd="@dimen/dp_60"
+ tools:itemCount="3"
+ tools:layoutManager="GridLayoutManager"
+ tools:listitem="@layout/item_picture_operation"
+ tools:spanCount="3" />
+ </LinearLayout>
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:background="@color/gray_4" />
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/btn_operation"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginVertical="@dimen/dp_12"
+ android:backgroundTint="@color/green_5"
+ android:onClick="@{viewModel.onClick}"
+ android:text="已完成巡游打卡,返回任务列表"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:cornerRadius="@dimen/dp_4" />
+ </LinearLayout>
+ </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_cruise_check_in_operation.xml b/app/src/main/res/layout/activity_cruise_check_in_operation.xml
new file mode 100644
index 0000000..8c3f278
--- /dev/null
+++ b/app/src/main/res/layout/activity_cruise_check_in_operation.xml
@@ -0,0 +1,283 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <data>
+
+ <variable
+ name="viewModel"
+ type="com.xw.yunwei.ui.work.checkInMission.viewmodel.CruiseCheckInOperationViewModel" />
+
+ <import type="com.xw.common.utils.BindUtils" />
+ </data>
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/white">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/back"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_56"
+ android:onClick="@{viewModel::onBack}"
+ android:src="@drawable/svg_back"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="巡游打卡"
+ android:textColor="@color/gray_10"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:layout_constraintBottom_toBottomOf="@+id/back"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="@+id/back" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="@dimen/dp_88"
+ android:fillViewport="true"
+ android:orientation="vertical">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_marginTop="@dimen/dp_12"
+ android:layout_weight="1">
+
+ <LinearLayout
+ android:id="@+id/ll_location_info"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingHorizontal="@dimen/dp_20"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="打卡限时"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_36"
+ android:layout_marginTop="@dimen/dp_8"
+ android:background="@drawable/shape_f8f9fa_bg_4"
+ android:gravity="center"
+ android:orientation="horizontal"
+ android:paddingStart="@dimen/dp_8">
+
+ <TextView
+ android:id="@+id/tv_time"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ tools:text="08:00~09:00" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_8"
+ android:background="@mipmap/img_map"
+ android:minHeight="@dimen/dp_58"
+ android:orientation="horizontal">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_address"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="@dimen/dp_12"
+ android:layout_weight="1"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ tools:text="蜀山区华侨中心A座2301" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/nav"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|center_vertical"
+ android:layout_margin="@dimen/dp_12"
+ android:visibility="gone"
+ android:src="@drawable/svg_map_nav" />
+ </LinearLayout>
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/tv_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_20"
+ android:drawableStart="@drawable/svg_must"
+ android:text="现场情况"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/ll_location_info" />
+
+ <TextView
+ android:id="@+id/tv_work"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/dp_36"
+ android:layout_marginStart="@dimen/dp_28"
+ android:layout_marginTop="@dimen/dp_12"
+ android:layout_marginEnd="5dp"
+ android:background="@drawable/shape_gray11_bg_4"
+ android:gravity="center"
+ android:text="正常"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ app:layout_constraintEnd_toStartOf="@id/tv_error"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_label" />
+
+ <TextView
+ android:id="@+id/tv_error"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/dp_36"
+ android:layout_marginStart="@dimen/dp_5"
+ android:layout_marginTop="@dimen/dp_12"
+ android:layout_marginEnd="@dimen/dp_28"
+ android:background="@drawable/shape_gray11_bg_4"
+ android:gravity="center"
+ android:text="异常"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@id/tv_work"
+ app:layout_constraintTop_toBottomOf="@id/tv_label" />
+
+ <TextView
+ android:id="@+id/tv_label2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_20"
+ android:drawableStart="@drawable/svg_must"
+ android:text="现场情况描述"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_work" />
+
+ <FrameLayout
+ android:id="@+id/fl_input"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_28"
+ android:layout_marginTop="@dimen/dp_12"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_label2">
+
+ <EditText
+ android:id="@+id/et_input"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_gray_3_bg_4"
+ android:gravity="top|start"
+ android:hint="请输入现场情况描述,最多可输入200字"
+ android:maxLength="200"
+ android:minHeight="@dimen/dp_91"
+ android:paddingLeft="@dimen/dp_12"
+ android:paddingRight="@dimen/dp_12"
+ android:paddingTop="@dimen/dp_12"
+ android:paddingBottom="@dimen/dp_18"
+ android:text="@={viewModel.desc}"
+ android:textColor="@color/gray_9"
+ android:textColorHint="@color/gray_6"
+ android:textSize="@dimen/sp_14" />
+
+ <TextView
+ android:id="@+id/tv_count"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|end"
+ android:layout_marginEnd="@dimen/dp_12"
+ android:layout_marginBottom="@dimen/dp_2"
+ android:text="@{viewModel.countNotice}"
+ android:textColor="@color/gray_6"
+ android:textSize="@dimen/sp_11" />
+
+ </FrameLayout>
+
+ <TextView
+ android:id="@+id/tv_notice"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_4"
+ android:text="@={viewModel.noticeLabel}"
+ android:textColor="@color/red_5"
+ android:textSize="@dimen/sp_11"
+ android:visibility="gone"
+ app:layout_constraintStart_toStartOf="@id/fl_input"
+ app:layout_constraintTop_toBottomOf="@id/fl_input"
+ tools:visibility="visible" />
+
+ <TextView
+ android:id="@+id/tv_label3"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_28"
+ android:layout_marginTop="@dimen/dp_20"
+ android:text="现场照片"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_notice" />
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/rv_list"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_25"
+ android:layout_marginTop="@dimen/dp_9"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_label3"
+ tools:itemCount="5"
+ tools:layoutManager="GridLayoutManager"
+ tools:listitem="@layout/item_picture_operation"
+ tools:spanCount="5" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:background="@color/gray_4" />
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/btn_submit"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginVertical="@dimen/dp_12"
+ android:backgroundTint="@color/blue_5"
+ android:text="提交打卡结果"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:cornerRadius="@dimen/dp_4" />
+ </LinearLayout>
+ </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_find_psw.xml b/app/src/main/res/layout/activity_find_psw.xml
index c9dc6d0..aed528a 100644
--- a/app/src/main/res/layout/activity_find_psw.xml
+++ b/app/src/main/res/layout/activity_find_psw.xml
@@ -40,7 +40,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
- <androidx.appcompat.widget.AppCompatEditText
+ <com.xw.yunwei.ui.widget.ClearEditText
android:id="@+id/phone"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_56"
@@ -49,6 +49,10 @@
android:background="@null"
android:gravity="center_vertical"
android:hint="手机号"
+ app:iconHeight="@dimen/dp_18"
+ app:iconWidth="@dimen/dp_18"
+ app:iconMarginRight="@dimen/dp_10"
+ app:clearIcon="@mipmap/icon_close_gray"
android:inputType="phone"
android:text="@={viewModel.phone}"
android:textColor="@color/gray_10"
@@ -105,7 +109,7 @@
android:layout_marginHorizontal="@dimen/dp_32"
android:background="@null"
android:gravity="center_vertical"
- android:hint="请输入密码(最少6位)"
+ android:hint="请输入密码(最少8位)"
android:inputType="textPassword"
android:text="@={viewModel.psw}"
android:textColor="@color/gray_10"
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
index 175dc8a..a666b35 100644
--- a/app/src/main/res/layout/activity_login.xml
+++ b/app/src/main/res/layout/activity_login.xml
@@ -27,7 +27,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/dp_32"
- android:layout_marginTop="@dimen/dp_120"
+ android:layout_marginTop="@dimen/dp_122"
android:lineHeight="@dimen/dp_32"
android:text="欢迎使用\nRobotaxi运维APP"
android:textColor="@color/gray_9"
@@ -41,7 +41,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_40"
+ android:layout_marginTop="@dimen/dp_34"
android:background="@null"
app:layout_collapseMode="pin"
app:layout_constraintStart_toStartOf="parent"
@@ -58,7 +58,7 @@
app:tabTextAppearance="@style/TabTextStyle"
app:tabTextColor="@color/gray_7" />
- <androidx.appcompat.widget.AppCompatEditText
+ <com.xw.yunwei.ui.widget.ClearEditText
android:id="@+id/phone"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_56"
@@ -72,6 +72,10 @@
android:textColor="@color/gray_10"
android:textColorHint="@color/gray_6"
android:textSize="@dimen/sp_14"
+ app:iconHeight="@dimen/dp_18"
+ app:iconWidth="@dimen/dp_18"
+ app:iconMarginRight="@dimen/dp_10"
+ app:clearIcon="@mipmap/icon_close_gray"
app:layout_constraintTop_toBottomOf="@+id/tabLayout" />
<View
@@ -81,7 +85,7 @@
android:background="@color/gray_4"
app:layout_constraintTop_toBottomOf="@+id/phone" />
- <androidx.appcompat.widget.AppCompatEditText
+ <com.xw.yunwei.ui.widget.ClearEditText
android:id="@+id/code"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_56"
@@ -94,6 +98,10 @@
android:textColor="@color/gray_10"
android:textColorHint="@color/gray_6"
android:textSize="@dimen/sp_14"
+ app:iconHeight="@dimen/dp_18"
+ app:iconWidth="@dimen/dp_18"
+ app:iconMarginRight="@dimen/dp_100"
+ app:clearIcon="@mipmap/icon_close_gray"
app:layout_constraintTop_toBottomOf="@+id/phone" />
<androidx.appcompat.widget.AppCompatTextView
@@ -116,7 +124,7 @@
android:background="@color/gray_4"
app:layout_constraintTop_toBottomOf="@+id/code" />
- <androidx.appcompat.widget.AppCompatEditText
+ <com.xw.yunwei.ui.widget.ClearEditText
android:id="@+id/psw"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_56"
@@ -129,6 +137,10 @@
android:textColor="@color/gray_10"
android:textColorHint="@color/gray_6"
android:textSize="@dimen/sp_14"
+ app:iconHeight="@dimen/dp_18"
+ app:iconWidth="@dimen/dp_18"
+ app:iconMarginRight="@dimen/dp_50"
+ app:clearIcon="@mipmap/icon_close_gray"
app:layout_constraintTop_toBottomOf="@+id/code" />
<androidx.appcompat.widget.AppCompatImageView
@@ -151,12 +163,12 @@
app:layout_constraintTop_toBottomOf="@+id/psw" />
<androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/forgetPsw"
+ android:id="@+id/tv_rest_psw"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_12"
android:onClick="@{viewModel.onClick}"
- android:text="忘记密码"
+ android:text="重置密码"
android:textColor="@color/gray_6"
android:textSize="@dimen/sp_12"
app:layout_constraintEnd_toEndOf="@+id/psw"
@@ -169,18 +181,19 @@
android:layout_marginHorizontal="@dimen/dp_32"
android:layout_marginTop="@dimen/dp_24"
android:backgroundTint="@color/blue_5"
- android:onClick="@{viewModel.onClick}"
android:text="登录"
android:textSize="@dimen/sp_16"
android:textStyle="bold"
app:cornerRadius="@dimen/dp_4"
- app:layout_constraintTop_toBottomOf="@+id/forgetPsw" />
+ app:layout_constraintTop_toBottomOf="@+id/tv_rest_psw"
+ app:layout_goneMarginTop="@dimen/dp_56" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/protocolStatus"
selected="@{viewModel.protocolStatus}"
android:layout_width="@dimen/dp_20"
android:layout_height="@dimen/dp_20"
+ android:layout_marginStart="@dimen/sp_10"
android:onClick="@{viewModel.onClick}"
android:src="@drawable/selector_protocol_status"
app:layout_constraintStart_toStartOf="@+id/phone"
@@ -191,13 +204,13 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_4"
+ android:layout_marginEnd="@dimen/dp_10"
android:layout_marginBottom="@dimen/dp_42"
+ android:justificationMode="inter_character"
android:textSize="@dimen/sp_14"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/protocolStatus"
app:layout_constraintRight_toRightOf="@+id/phone"
- tools:text="我已阅读并同意《用户协议》《隐私协议》" />
-
-
+ tools:text="我已阅读并同意《用户协议》《隐私协议》《隐私协议》" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_normal_task_detail.xml b/app/src/main/res/layout/activity_normal_task_detail.xml
index 30b2fae..9d479a9 100644
--- a/app/src/main/res/layout/activity_normal_task_detail.xml
+++ b/app/src/main/res/layout/activity_normal_task_detail.xml
@@ -40,6 +40,20 @@
app:layout_constraintTop_toTopOf="@+id/back"
tools:text="待到达" />
+ <TextView
+ android:id="@+id/tv_apply_for_reassignment"
+ show="@{viewModel.taskDetail.couldReassignment()}"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_56"
+ android:paddingHorizontal="@dimen/dp_20"
+ android:text="申请改派"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
<RelativeLayout
show="@{viewModel.taskDetail.status == 1}"
android:layout_width="match_parent"
@@ -57,8 +71,8 @@
show="@{viewModel.taskDetail.status == 2}"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:visibility="gone"
- android:layout_marginTop="@dimen/dp_88">
+ android:layout_marginTop="@dimen/dp_88"
+ tools:visibility="gone">
<include
android:id="@+id/layoutFinish"
diff --git a/app/src/main/res/layout/activity_protocol.xml b/app/src/main/res/layout/activity_protocol.xml
index c530e0e..86de749 100644
--- a/app/src/main/res/layout/activity_protocol.xml
+++ b/app/src/main/res/layout/activity_protocol.xml
@@ -1,14 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools">
<data>
+ <variable
+ name="viewModel"
+ type="com.xw.yunwei.ui.user.mine.protocol.ProtocolVM" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:background="@color/white">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/back"
@@ -32,47 +37,18 @@
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@+id/back" />
-
<LinearLayout
android:layout_width="match_parent"
- android:orientation="vertical"
+ android:layout_height="match_parent"
android:layout_marginTop="@dimen/dp_88"
- android:layout_height="match_parent">
+ android:orientation="vertical">
- <com.google.android.material.tabs.TabLayout
- android:id="@+id/tabLayout"
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/rv_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@null"
- app:layout_collapseMode="pin"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/title"
- app:tabBackground="@null"
- app:tabIndicatorColor="@color/blue_5"
- app:tabIndicator="@drawable/layer_indicator_1"
- app:tabIndicatorHeight="@dimen/dp_4"
- app:tabGravity="fill"
- app:tabIndicatorFullWidth="false"
- app:tabMode="scrollable"
- app:tabRippleColor="@null"
- app:tabSelectedTextColor="@color/blue_5"
- app:tabTextAppearance="@style/TabTextStyle14"
- app:tabTextColor="@color/gray_7" />
-
- <View
- android:layout_width="match_parent"
- android:layout_height="1px"
- android:background="@color/gray_4"/>
-
- <WebView
- android:id="@+id/web"
- android:background="@color/white"
- android:layout_marginHorizontal="@dimen/dp_20"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
-
+ tools:itemCount="4"
+ tools:listitem="@layout/item_protocol_entrance" />
</LinearLayout>
-
-
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_route_planning.xml b/app/src/main/res/layout/activity_route_planning.xml
new file mode 100644
index 0000000..a3b5b74
--- /dev/null
+++ b/app/src/main/res/layout/activity_route_planning.xml
@@ -0,0 +1,232 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <data>
+
+ <variable
+ name="viewModel"
+ type="com.xw.yunwei.ui.work.checkInMission.viewmodel.RoutePlanningViewModel" />
+
+ <import type="com.xw.common.utils.BindUtils" />
+ </data>
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/white">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/back"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_56"
+ android:onClick="@{viewModel::onBack}"
+ android:src="@drawable/svg_back"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="路径规划"
+ android:textColor="@color/gray_10"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:layout_constraintBottom_toBottomOf="@+id/back"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="@+id/back" />
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="@dimen/dp_88">
+
+ <com.amap.api.maps.MapView
+ android:id="@+id/map_view"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_marginBottom="@dimen/dp_170"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <LinearLayout
+ android:id="@+id/ll_route_select"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_white_bg_top_12"
+ android:orientation="vertical"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="@dimen/dp_20"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:id="@+id/ll_walk"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/dp_4"
+ android:layout_weight="1"
+ android:background="@drawable/shape_blue_1_bg_4"
+ android:gravity="center"
+ android:orientation="horizontal"
+ android:padding="@dimen/dp_8">
+
+ <ImageView
+ android:id="@+id/iv_walk"
+ android:layout_width="@dimen/dp_20"
+ android:layout_height="@dimen/dp_20"
+ android:src="@mipmap/ic_walk_blue" />
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_8"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/tv_walk_route"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="步行导航"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold" />
+
+
+ <TextView
+ android:id="@+id/tv_walk_cost_time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/tv_walk_route"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_12"
+ android:textStyle="bold"
+ tools:text="1小时19分" />
+
+ <TextView
+ android:id="@+id/tv_walk_distance"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/tv_walk_cost_time"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_12"
+ android:textStyle="bold"
+ tools:text="12.9公里" />
+
+ <TextView
+ android:id="@+id/tv_walk_points"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignBottom="@id/tv_walk_distance"
+ android:layout_alignParentEnd="true"
+ android:background="@drawable/shape_while_bg_12"
+ android:paddingHorizontal="@dimen/dp_4"
+ android:paddingVertical="@dimen/dp_2"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_10"
+ android:textStyle="bold"
+ tools:text="4个途经点" />
+ </RelativeLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/ll_bicycle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_4"
+ android:layout_weight="1"
+ android:background="@drawable/shape_gray11_bg_4"
+ android:gravity="center"
+ android:orientation="horizontal"
+ android:padding="@dimen/dp_8">
+
+ <ImageView
+ android:id="@+id/iv_bicycle"
+ android:layout_width="@dimen/dp_20"
+ android:layout_height="@dimen/dp_20"
+ android:src="@mipmap/ic_bicycle_gray" />
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_8"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/tv_bicycle_route"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="骑行导航"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold" />
+
+
+ <TextView
+ android:id="@+id/tv_bicycle_cost_time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/tv_bicycle_route"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_12"
+ android:textStyle="bold"
+ tools:text="1小时19分" />
+
+ <TextView
+ android:id="@+id/tv_bicycle_distance"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/tv_bicycle_cost_time"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_12"
+ android:textStyle="bold"
+ tools:text="12.9公里" />
+
+ <TextView
+ android:id="@+id/tv_bicycle_points"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignBottom="@id/tv_bicycle_distance"
+ android:layout_alignParentEnd="true"
+ android:background="@drawable/shape_while_bg_12"
+ android:paddingHorizontal="@dimen/dp_4"
+ android:paddingVertical="@dimen/dp_2"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_10"
+ android:textStyle="bold"
+ tools:text="4个途经点" />
+ </RelativeLayout>
+ </LinearLayout>
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:background="@color/gray_4" />
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/btn_plan"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginVertical="@dimen/dp_12"
+ android:background="@drawable/shape_blue_5_bg_4"
+ android:text="开始导航"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:cornerRadius="@dimen/dp_4" />
+ </LinearLayout>
+ </androidx.constraintlayout.widget.ConstraintLayout>
+ </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_scheduling.xml b/app/src/main/res/layout/activity_scheduling.xml
index aeb79f7..b974aa1 100644
--- a/app/src/main/res/layout/activity_scheduling.xml
+++ b/app/src/main/res/layout/activity_scheduling.xml
@@ -8,7 +8,8 @@
<variable
name="viewModel"
type="com.xw.yunwei.ui.user.mine.scheduling.SchedulingVM" />
- <import type="com.xw.common.utils.BindUtils"/>
+
+ <import type="com.xw.common.utils.BindUtils" />
</data>
@@ -75,217 +76,15 @@
</LinearLayout>
- <LinearLayout
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/rv_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_16"
- android:orientation="horizontal">
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:gravity="center"
- android:text="@{viewModel.showWeekDay.get(0)}"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_12"
- tools:text="日" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:gravity="center"
- android:text="@{viewModel.showWeekDay.get(1)}"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_12"
- tools:text="一" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:gravity="center"
- android:text="@{viewModel.showWeekDay.get(2)}"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_12"
- tools:text="二" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:gravity="center"
- android:text="@{viewModel.showWeekDay.get(3)}"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_12"
- tools:text="三" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:gravity="center"
- android:text="@{viewModel.showWeekDay.get(4)}"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_12"
- tools:text="四" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:gravity="center"
- android:text="@{viewModel.showWeekDay.get(5)}"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_12"
- tools:text="五" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:gravity="center"
- android:text="@{viewModel.showWeekDay.get(6)}"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_12"
- tools:text="六" />
-
- </LinearLayout>
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_12"
- android:orientation="horizontal">
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/date1"
- selected="@{viewModel.selectTime.equals(viewModel.showWeekDate.get(0))}"
- android:layout_width="@dimen/dp_44"
- android:layout_height="@dimen/dp_44"
- android:layout_weight="1"
- android:background="@drawable/selector_date_bg"
- android:gravity="center"
- android:onClick="@{viewModel.onClick}"
- android:text="@{BindUtils.INSTANCE.showDay(viewModel.showWeekDate.get(0))}"
- android:textColor="@color/selector_grey9_to_white"
- android:textSize="@dimen/sp_20"
- android:textStyle="bold"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintRight_toLeftOf="@+id/date2"
- app:layout_constraintTop_toTopOf="parent"
- tools:text="18" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/date2"
- selected="@{viewModel.selectTime.equals(viewModel.showWeekDate.get(1))}"
- android:layout_width="@dimen/dp_44"
- android:layout_height="@dimen/dp_44"
- android:layout_weight="1"
- android:background="@drawable/selector_date_bg"
- android:gravity="center"
- android:onClick="@{viewModel.onClick}"
- android:text="@{BindUtils.INSTANCE.showDay(viewModel.showWeekDate.get(1))}"
- android:textColor="@color/selector_grey9_to_white"
- android:textSize="@dimen/sp_20"
- android:textStyle="bold"
- app:layout_constraintLeft_toRightOf="@+id/date1"
- app:layout_constraintRight_toLeftOf="@+id/date3"
- app:layout_constraintTop_toTopOf="parent"
- tools:text="19" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/date3"
- selected="@{viewModel.selectTime.equals(viewModel.showWeekDate.get(2))}"
- android:layout_width="@dimen/dp_44"
- android:layout_height="@dimen/dp_44"
- android:layout_weight="1"
- android:background="@drawable/selector_date_bg"
- android:gravity="center"
- android:onClick="@{viewModel.onClick}"
- android:text="@{BindUtils.INSTANCE.showDay(viewModel.showWeekDate.get(2))}"
- android:textColor="@color/selector_grey9_to_white"
- android:textSize="@dimen/sp_20"
- android:textStyle="bold"
- app:layout_constraintLeft_toRightOf="@+id/date2"
- app:layout_constraintRight_toLeftOf="@+id/date4"
- app:layout_constraintTop_toTopOf="parent"
- tools:text="20" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/date4"
- selected="@{viewModel.selectTime.equals(viewModel.showWeekDate.get(3))}"
- android:layout_width="@dimen/dp_44"
- android:layout_height="@dimen/dp_44"
- android:layout_weight="1"
- android:background="@drawable/selector_date_bg"
- android:gravity="center"
- android:onClick="@{viewModel.onClick}"
- android:text="@{BindUtils.INSTANCE.showDay(viewModel.showWeekDate.get(3))}"
- android:textColor="@color/selector_grey9_to_white"
- android:textSize="@dimen/sp_20"
- android:textStyle="bold"
- app:layout_constraintLeft_toRightOf="@+id/date3"
- app:layout_constraintRight_toLeftOf="@+id/date5"
- app:layout_constraintTop_toTopOf="parent"
- tools:text="21" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/date5"
- selected="@{viewModel.selectTime.equals(viewModel.showWeekDate.get(4))}"
- android:layout_width="@dimen/dp_44"
- android:layout_height="@dimen/dp_44"
- android:layout_weight="1"
- android:background="@drawable/selector_date_bg"
- android:gravity="center"
- android:onClick="@{viewModel.onClick}"
- android:text="@{BindUtils.INSTANCE.showDay(viewModel.showWeekDate.get(4))}"
- android:textColor="@color/selector_grey9_to_white"
- android:textSize="@dimen/sp_20"
- android:textStyle="bold"
- app:layout_constraintLeft_toRightOf="@+id/date4"
- app:layout_constraintRight_toLeftOf="@+id/date6"
- app:layout_constraintTop_toTopOf="parent"
- tools:text="22" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/date6"
- selected="@{viewModel.selectTime.equals(viewModel.showWeekDate.get(5))}"
- android:layout_width="@dimen/dp_44"
- android:layout_height="@dimen/dp_44"
- android:layout_weight="1"
- android:background="@drawable/selector_date_bg"
- android:gravity="center"
- android:onClick="@{viewModel.onClick}"
- android:text="@{BindUtils.INSTANCE.showDay(viewModel.showWeekDate.get(5))}"
- android:textColor="@color/selector_grey9_to_white"
- android:textSize="@dimen/sp_20"
- android:textStyle="bold"
- app:layout_constraintLeft_toRightOf="@+id/date5"
- app:layout_constraintRight_toLeftOf="@+id/date7"
- app:layout_constraintTop_toTopOf="parent"
- tools:text="23" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/date7"
- selected="@{viewModel.selectTime.equals(viewModel.showWeekDate.get(6))}"
- android:layout_width="@dimen/dp_44"
- android:layout_height="@dimen/dp_44"
- android:layout_weight="1"
- android:background="@drawable/selector_date_bg"
- android:gravity="center"
- android:onClick="@{viewModel.onClick}"
- android:text="@{BindUtils.INSTANCE.showDay(viewModel.showWeekDate.get(6))}"
- android:textColor="@color/selector_grey9_to_white"
- android:textSize="@dimen/sp_20"
- android:textStyle="bold"
- app:layout_constraintLeft_toRightOf="@+id/date6"
- app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- tools:text="24" />
-
- </androidx.constraintlayout.widget.ConstraintLayout>
+ tools:itemCount="7"
+ tools:layoutManager="LinearLayoutManager"
+ tools:listitem="@layout/item_week_day"
+ tools:orientation="horizontal" />
<View
android:layout_width="match_parent"
@@ -373,23 +172,23 @@
android:layout_height="0dp"
android:layout_weight="1" />
-<!-- <androidx.appcompat.widget.AppCompatImageView-->
-<!-- show="@{viewModel.selectTime.equals(viewModel.today) && (viewModel.clockModel.clockIn != true || viewModel.clockModel.clockOut != true)}"-->
-<!-- android:layout_width="wrap_content"-->
-<!-- android:layout_height="wrap_content"-->
-<!-- android:src="@drawable/svg_location" />-->
+ <!-- <androidx.appcompat.widget.AppCompatImageView-->
+ <!-- show="@{viewModel.selectTime.equals(viewModel.today) && (viewModel.clockModel.clockIn != true || viewModel.clockModel.clockOut != true)}"-->
+ <!-- android:layout_width="wrap_content"-->
+ <!-- android:layout_height="wrap_content"-->
+ <!-- android:src="@drawable/svg_location" />-->
-<!-- <androidx.appcompat.widget.AppCompatTextView-->
-<!-- android:id="@+id/goCheck"-->
-<!-- show="@{viewModel.selectTime.equals(viewModel.today) && (viewModel.clockModel.clockIn != true || viewModel.clockModel.clockOut != true)}"-->
-<!-- android:layout_width="wrap_content"-->
-<!-- android:layout_height="wrap_content"-->
-<!-- android:layout_marginStart="4dp"-->
-<!-- android:onClick="@{viewModel.onClick}"-->
-<!-- android:text="去打卡"-->
-<!-- android:textColor="@color/blue_5"-->
-<!-- android:textSize="@dimen/sp_14"-->
-<!-- android:textStyle="bold" />-->
+ <!-- <androidx.appcompat.widget.AppCompatTextView-->
+ <!-- android:id="@+id/goCheck"-->
+ <!-- show="@{viewModel.selectTime.equals(viewModel.today) && (viewModel.clockModel.clockIn != true || viewModel.clockModel.clockOut != true)}"-->
+ <!-- android:layout_width="wrap_content"-->
+ <!-- android:layout_height="wrap_content"-->
+ <!-- android:layout_marginStart="4dp"-->
+ <!-- android:onClick="@{viewModel.onClick}"-->
+ <!-- android:text="去打卡"-->
+ <!-- android:textColor="@color/blue_5"-->
+ <!-- android:textSize="@dimen/sp_14"-->
+ <!-- android:textStyle="bold" />-->
</LinearLayout>
@@ -419,7 +218,7 @@
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:layout_margin="@dimen/dp_12"
- android:src="@drawable/svg_map_location" />
+ android:src="@drawable/svg_map_nav" />
</FrameLayout>
@@ -457,6 +256,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/orange_1"
+ android:gravity="center"
+ android:minWidth="@dimen/dp_49"
android:paddingHorizontal="@dimen/dp_8"
android:paddingVertical="@dimen/dp_2"
android:text="未打卡"
@@ -467,7 +268,7 @@
<com.google.android.material.button.MaterialButton
android:id="@+id/clockIn"
- show="@{viewModel.selectTime.equals(viewModel.today) && (viewModel.clockModel.clockIn != true || viewModel.clockModel.xpClockIn.clockInResult == 3)}"
+ show="@{viewModel.selectTime.equals(viewModel.today) && (viewModel.clockModel.clockIn != true && viewModel.clockModel.xpClockIn.clockInResult != 3)}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_8"
@@ -483,7 +284,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_8"
- android:text='@{"打卡时间:"+viewModel.clockModel.xpClockIn.clockInTime}'
+ android:text='@{"打卡时间:"+viewModel.clockModel.xpClockIn.getFormateClockInTime()}'
android:textColor="@color/gray_8"
android:textSize="@dimen/sp_14"
android:textStyle="bold"
@@ -540,6 +341,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/orange_1"
+ android:gravity="center"
+ android:minWidth="@dimen/dp_49"
android:paddingHorizontal="@dimen/dp_8"
android:paddingVertical="@dimen/dp_2"
android:text="未打卡"
@@ -549,7 +352,7 @@
<com.google.android.material.button.MaterialButton
android:id="@+id/clockOut"
- show="@{viewModel.selectTime.equals(viewModel.today) && (viewModel.clockModel.clockOut != true || viewModel.clockModel.xpClockIn.clockOutResult == 3)}"
+ show="@{viewModel.selectTime.equals(viewModel.today) && (viewModel.clockModel.clockOut != true && viewModel.clockModel.xpClockIn.clockOutResult != 3)}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_8"
@@ -565,7 +368,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_8"
- android:text='@{"打卡时间:"+viewModel.clockModel.xpClockIn.clockOutTime}'
+ android:text='@{"打卡时间:"+viewModel.clockModel.xpClockIn.getFormateClockOutTime()}'
android:textColor="@color/gray_8"
android:textSize="@dimen/sp_14"
android:textStyle="bold"
diff --git a/app/src/main/res/layout/activity_select_car.xml b/app/src/main/res/layout/activity_select_car.xml
index b8186a5..9d97ac1 100644
--- a/app/src/main/res/layout/activity_select_car.xml
+++ b/app/src/main/res/layout/activity_select_car.xml
@@ -59,7 +59,7 @@
app:layout_constraintTop_toBottomOf="@+id/rlTitleBar"
tools:ignore="MissingConstraints">
- <androidx.appcompat.widget.AppCompatEditText
+ <com.xw.yunwei.ui.widget.ClearEditText
android:id="@+id/searchEt"
android:layout_width="0dp"
android:layout_height="@dimen/dp_34"
@@ -68,6 +68,10 @@
android:drawableStart="@drawable/svg_search"
android:drawablePadding="@dimen/dp_10"
android:hint="请输入车牌号"
+ android:maxLength="8"
+ app:iconHeight="@dimen/dp_18"
+ app:iconWidth="@dimen/dp_18"
+ app:clearIcon="@mipmap/icon_close_gray"
android:imeOptions="actionSearch"
android:paddingHorizontal="@dimen/dp_10"
android:singleLine="true"
diff --git a/app/src/main/res/layout/activity_set.xml b/app/src/main/res/layout/activity_set.xml
index f16b42f..01dfe35 100644
--- a/app/src/main/res/layout/activity_set.xml
+++ b/app/src/main/res/layout/activity_set.xml
@@ -98,7 +98,7 @@
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
- android:layout_marginEnd="12dp"
+ android:layout_marginEnd="4dp"
android:checked="true"
android:clickable="false"
android:focusable="false"
@@ -206,7 +206,12 @@
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_14"
android:textStyle="bold" />
-
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_alignParentBottom="true"
+ android:background="@color/gray_4" />
</LinearLayout>
</ScrollView>
diff --git a/app/src/main/res/layout/activity_site_error_upload.xml b/app/src/main/res/layout/activity_site_error_upload.xml
new file mode 100644
index 0000000..937906d
--- /dev/null
+++ b/app/src/main/res/layout/activity_site_error_upload.xml
@@ -0,0 +1,247 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <data>
+
+ <variable
+ name="viewModel"
+ type="com.xw.yunwei.ui.work.site.viewmodel.SiteErrorUploadVM" />
+ </data>
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/white">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/back"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_56"
+ android:onClick="@{viewModel::onBack}"
+ android:src="@drawable/svg_back"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="现场情况上报"
+ android:textColor="@color/gray_10"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:layout_constraintBottom_toBottomOf="@+id/back"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="@+id/back" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="@dimen/dp_88"
+ android:fillViewport="true"
+ android:orientation="vertical">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_marginTop="@dimen/dp_12"
+ android:layout_weight="1">
+
+ <ImageView
+ android:id="@+id/iv_picture"
+ android:layout_width="@dimen/dp_68"
+ android:layout_height="@dimen/dp_92"
+ android:layout_marginStart="@dimen/dp_20"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/tv_title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_8"
+ android:layout_marginEnd="@dimen/dp_20"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@id/iv_picture"
+ app:layout_constraintTop_toTopOf="@id/iv_picture" />
+
+ <TextView
+ android:id="@+id/tv_detail"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_8"
+ android:layout_marginTop="@dimen/dp_4"
+ android:layout_marginEnd="@dimen/dp_20"
+ android:textColor="@color/color_838fa6"
+ android:textSize="@dimen/sp_14"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@id/iv_picture"
+ app:layout_constraintTop_toBottomOf="@id/tv_title" />
+
+ <TextView
+ android:id="@+id/tv_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_20"
+ android:drawableStart="@drawable/svg_must"
+ android:text="现场情况"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/iv_picture" />
+
+ <TextView
+ android:id="@+id/tv_work"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/dp_36"
+ android:layout_marginStart="@dimen/dp_28"
+ android:layout_marginTop="@dimen/dp_12"
+ android:layout_marginEnd="5dp"
+ android:background="@drawable/shape_gray11_bg_4"
+ android:gravity="center"
+ android:text="正常"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ app:layout_constraintEnd_toStartOf="@id/tv_error"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_label" />
+
+ <TextView
+ android:id="@+id/tv_error"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/dp_36"
+ android:layout_marginStart="@dimen/dp_5"
+ android:layout_marginTop="@dimen/dp_12"
+ android:layout_marginEnd="@dimen/dp_28"
+ android:background="@drawable/shape_gray11_bg_4"
+ android:gravity="center"
+ android:text="异常"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@id/tv_work"
+ app:layout_constraintTop_toBottomOf="@id/tv_label" />
+
+ <TextView
+ android:id="@+id/tv_label2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_20"
+ android:text="现场情况描述"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_work" />
+
+ <FrameLayout
+ android:id="@+id/fl_input"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_12"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_label2">
+
+ <EditText
+ android:id="@+id/et_input"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_gray_3_bg_4"
+ android:gravity="top|start"
+ android:hint="请输入现场情况描述,最多可输入200字"
+ android:maxLength="200"
+ android:minHeight="@dimen/dp_91"
+ android:paddingLeft="@dimen/dp_12"
+ android:paddingRight="@dimen/dp_12"
+ android:paddingTop="@dimen/dp_12"
+ android:paddingBottom="@dimen/dp_18"
+ android:text="@={viewModel.desc}"
+ android:textColor="@color/gray_9"
+ android:textColorHint="@color/gray_6"
+ android:textSize="@dimen/sp_14" />
+
+ <TextView
+ android:id="@+id/tv_count"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|end"
+ android:layout_marginEnd="@dimen/dp_12"
+ android:layout_marginBottom="@dimen/dp_2"
+ android:text="@{viewModel.countNotice}"
+ android:textColor="@color/gray_6"
+ android:textSize="@dimen/sp_11" />
+
+ </FrameLayout>
+
+ <TextView
+ android:id="@+id/tv_notice"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_4"
+ android:text="@={viewModel.noticeLabel}"
+ android:textColor="@color/red_5"
+ android:textSize="@dimen/sp_11"
+ android:visibility="gone"
+ app:layout_constraintStart_toStartOf="@id/fl_input"
+ app:layout_constraintTop_toBottomOf="@id/fl_input"
+ tools:visibility="visible" />
+
+ <TextView
+ android:id="@+id/tv_label3"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_20"
+ android:text="现场照片"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_notice" />
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/rv_list"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_17"
+ android:layout_marginTop="@dimen/dp_9"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_label3"
+ tools:itemCount="5"
+ tools:layoutManager="GridLayoutManager"
+ tools:listitem="@layout/item_picture_operation"
+ tools:spanCount="5" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:background="@color/gray_4" />
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/btn_error_upload"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginVertical="@dimen/dp_12"
+ android:backgroundTint="@color/blue_5"
+ android:text="提交"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:cornerRadius="@dimen/dp_4" />
+ </LinearLayout>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_site_nav.xml b/app/src/main/res/layout/activity_site_nav.xml
index 6322392..9b7f352 100644
--- a/app/src/main/res/layout/activity_site_nav.xml
+++ b/app/src/main/res/layout/activity_site_nav.xml
@@ -21,24 +21,24 @@
android:layout_height="match_parent"
tools:background="@mipmap/img_test_map" />
-<!-- <androidx.appcompat.widget.AppCompatTextView-->
-<!-- showAnim='@{!"".equals(viewModel.selectSiteName)}'-->
-<!-- android:layout_width="wrap_content"-->
-<!-- android:layout_height="wrap_content"-->
-<!-- android:layout_marginBottom="@dimen/dp_80"-->
-<!-- android:background="@drawable/shape_while_bg_100"-->
-<!-- android:elevation="@dimen/dp_2"-->
-<!-- android:paddingHorizontal="@dimen/dp_20"-->
-<!-- android:paddingVertical="@dimen/dp_6"-->
-<!-- android:text="@{viewModel.selectSiteName}"-->
-<!-- android:textColor="@color/gray_9"-->
-<!-- android:textSize="@dimen/sp_12"-->
-<!-- android:textStyle="bold"-->
-<!-- app:layout_constraintBottom_toBottomOf="parent"-->
-<!-- app:layout_constraintLeft_toLeftOf="parent"-->
-<!-- app:layout_constraintRight_toRightOf="parent"-->
-<!-- app:layout_constraintTop_toTopOf="parent"-->
-<!-- tools:text="点位名称" />-->
+ <!-- <androidx.appcompat.widget.AppCompatTextView-->
+ <!-- showAnim='@{!"".equals(viewModel.selectSiteName)}'-->
+ <!-- android:layout_width="wrap_content"-->
+ <!-- android:layout_height="wrap_content"-->
+ <!-- android:layout_marginBottom="@dimen/dp_80"-->
+ <!-- android:background="@drawable/shape_while_bg_100"-->
+ <!-- android:elevation="@dimen/dp_2"-->
+ <!-- android:paddingHorizontal="@dimen/dp_20"-->
+ <!-- android:paddingVertical="@dimen/dp_6"-->
+ <!-- android:text="@{viewModel.selectSiteName}"-->
+ <!-- android:textColor="@color/gray_9"-->
+ <!-- android:textSize="@dimen/sp_12"-->
+ <!-- android:textStyle="bold"-->
+ <!-- app:layout_constraintBottom_toBottomOf="parent"-->
+ <!-- app:layout_constraintLeft_toLeftOf="parent"-->
+ <!-- app:layout_constraintRight_toRightOf="parent"-->
+ <!-- app:layout_constraintTop_toTopOf="parent"-->
+ <!-- tools:text="点位名称" />-->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/topLayout"
@@ -61,7 +61,7 @@
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="站点导航"
+ android:text="站点管理"
android:textColor="@color/gray_10"
android:textSize="@dimen/sp_16"
android:textStyle="bold"
@@ -70,16 +70,18 @@
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@+id/back" />
- <LinearLayout
- android:id="@+id/searchLayout"
- android:layout_width="match_parent"
- android:layout_height="@dimen/dp_56"
- android:layout_marginTop="@dimen/dp_88"
- android:gravity="center_vertical"
- android:paddingHorizontal="@dimen/dp_10"
- app:layout_constraintTop_toTopOf="parent">
+ </androidx.constraintlayout.widget.ConstraintLayout>
- <androidx.appcompat.widget.AppCompatEditText
+ <LinearLayout
+ android:id="@+id/searchLayout"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_56"
+ android:background="@color/white"
+ android:gravity="center_vertical"
+ android:paddingHorizontal="@dimen/dp_10"
+ app:layout_constraintTop_toBottomOf="@+id/topLayout">
+
+ <com.xw.yunwei.ui.widget.ClearEditText
android:id="@+id/searchEt"
android:layout_width="0dp"
android:layout_height="@dimen/dp_34"
@@ -89,6 +91,9 @@
android:drawableStart="@drawable/svg_search"
android:drawablePadding="@dimen/dp_10"
android:hint="请输入站点名称"
+ app:iconHeight="@dimen/dp_18"
+ app:iconWidth="@dimen/dp_18"
+ app:clearIcon="@mipmap/icon_close_gray"
android:imeOptions="actionSearch"
android:paddingHorizontal="@dimen/dp_10"
android:singleLine="true"
@@ -113,38 +118,28 @@
</LinearLayout>
- </androidx.constraintlayout.widget.ConstraintLayout>
-
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="0dp"
+ android:layout_marginTop="@dimen/dp_50"
android:elevation="@dimen/dp_2"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/topLayout">
+ app:layout_constraintTop_toBottomOf="@+id/searchLayout">
<!-- 底部滑动面板 -->
<LinearLayout
android:id="@+id/bottom_sheet"
+ showAnim="@{viewModel.siteItem==null}"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/shape_update"
android:orientation="vertical"
app:behavior_fitToContents="false"
app:behavior_halfExpandedRatio="0.58"
- app:behavior_peekHeight="@dimen/dp_92"
- tools:behavior_peekHeight="@dimen/dp_500"
+ app:behavior_peekHeight="@dimen/dp_54"
app:behavior_skipCollapsed="false"
- app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
-
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/location"
- android:layout_width="@dimen/dp_32"
- android:layout_height="@dimen/dp_32"
- android:layout_gravity="end"
- android:layout_marginEnd="@dimen/dp_12"
- android:layout_marginBottom="@dimen/dp_12"
- android:elevation="2dp"
- android:src="@drawable/svg_location1" />
+ app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
+ tools:behavior_peekHeight="@dimen/dp_500">
<LinearLayout
android:layout_width="match_parent"
@@ -154,45 +149,22 @@
android:orientation="vertical">
<RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="@dimen/dp_50">
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_50">
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/arrow"
- showAnim="@{viewModel.siteItem==null}"
- android:layout_width="@dimen/dp_24"
- android:layout_height="@dimen/dp_24"
- android:layout_centerInParent="true"
- android:background="@drawable/svg_arrow_d1" />
+ <RelativeLayout
+ android:id="@+id/arrow"
+ android:layout_width="@dimen/dp_50"
+ android:layout_height="@dimen/dp_50"
+ android:layout_centerInParent="true">
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/title1"
- showAnim="@{viewModel.siteItem!=null}"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:gravity="center_vertical"
- android:paddingHorizontal="@dimen/dp_20"
- android:text="点位信息"
- android:textColor="@color/gray_10"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold"
- android:visibility="gone" />
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="@dimen/dp_24"
+ android:layout_height="@dimen/dp_24"
+ android:layout_centerInParent="true"
+ android:background="@drawable/svg_arrow_d1" />
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/back1"
- showAnim="@{viewModel.siteItem!=null}"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_marginStart="@dimen/dp_20"
- android:drawableStart="@drawable/svg_arrow_l"
- android:drawablePadding="@dimen/dp_5"
- android:text="返回"
- android:textColor="@color/blue_5"
- android:textSize="@dimen/sp_14"
- android:visibility="gone" />
-
+ </RelativeLayout>
</RelativeLayout>
<androidx.core.widget.NestedScrollView
@@ -207,164 +179,10 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/siteRv"
showAnim="@{viewModel.siteItem==null}"
- tools:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:nestedScrollingEnabled="false" />
-
- <LinearLayout
- android:id="@+id/siteDetail"
- showAnim="@{viewModel.siteItem!=null}"
- android:layout_width="match_parent"
- tools:visibility="visible"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:visibility="gone">
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <com.makeramen.roundedimageview.RoundedImageView
- android:id="@+id/icon"
- android:layout_width="@dimen/dp_68"
- android:layout_height="@dimen/dp_92"
- android:layout_marginStart="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_8"
- android:adjustViewBounds="true"
- android:scaleType="centerCrop"
- android:src="@mipmap/img_site_bg"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:riv_corner_radius="@dimen/dp_5" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/name"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_8"
- android:layout_marginEnd="@dimen/dp_20"
- android:maxLines="1"
- android:text="广州市白云机场T2航站楼"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_14"
- android:textStyle="bold"
- app:layout_constraintLeft_toRightOf="@+id/icon"
- app:layout_constraintRight_toLeftOf="@+id/nav"
- app:layout_constraintTop_toTopOf="@+id/icon" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/address"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_4"
- android:layout_marginRight="@dimen/dp_20"
- android:maxLines="2"
- android:text="深圳市宝安区西大街阳光绿色温馨家园17号楼313"
- android:textColor="@color/gray_6"
- android:textSize="@dimen/sp_12"
- app:layout_constraintLeft_toLeftOf="@+id/name"
- app:layout_constraintRight_toLeftOf="@+id/nav"
- app:layout_constraintTop_toBottomOf="@+id/name" />
-
- <com.xw.common.custom.ShowTextLinearLayout
- android:id="@+id/stllTag"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_4"
- android:layout_marginEnd="@dimen/dp_10"
- android:orientation="vertical"
- app:layout_constraintLeft_toLeftOf="@+id/name"
- app:layout_constraintRight_toLeftOf="@+id/arrow1"
- app:layout_constraintTop_toBottomOf="@+id/address"
- app:margin_width="@dimen/dp_8"
- app:max_padding_width="@dimen/dp_12"
- app:min_padding_width="@dimen/dp_12"
- app:padding_height="@dimen/dp_6"
- app:padding_left="0dp"
- app:padding_right="0dp"
- app:text_bg="@drawable/shape_blue1_bg_4"
- app:text_color="@color/blue_5"
- app:text_size="@dimen/sp_12" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/arrow1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/dp_20"
- app:layout_constraintTop_toBottomOf="@+id/address"
- android:src="@drawable/svg_arrow_r"
- android:layout_marginTop="@dimen/dp_8"
- app:layout_constraintRight_toRightOf="parent" />
-
- <LinearLayout
- android:id="@+id/nav"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_8"
- android:layout_marginEnd="@dimen/dp_20"
- android:orientation="vertical"
- app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toTopOf="parent">
-
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="@dimen/dp_20"
- android:layout_height="@dimen/dp_20"
- android:layout_gravity="end|center_vertical"
- android:src="@drawable/svg_map_nav" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="导航"
- android:textColor="@color/blue_5"
- android:textSize="@dimen/sp_10"
- app:layout_constraintRight_toRightOf="parent" />
-
- </LinearLayout>
-
- </androidx.constraintlayout.widget.ConstraintLayout>
-
- <View
- android:layout_width="match_parent"
- android:layout_height="1px"
- android:layout_marginHorizontal="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_8"
- android:background="@color/gray_4"
- app:layout_constraintBottom_toBottomOf="parent" />
-
- <com.xw.common.custom.ShowTextLinearLayout
- android:id="@+id/stllTag1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginHorizontal="20dp"
- android:layout_marginTop="@dimen/dp_12"
- android:orientation="vertical"
- app:margin_width="@dimen/dp_8"
- app:max_padding_width="@dimen/dp_12"
- app:min_padding_width="@dimen/dp_12"
- app:padding_height="@dimen/dp_6"
- app:padding_left="0dp"
- app:padding_right="0dp"
- app:text_bg="@drawable/shape_f8f9fa_bg_4"
- app:text_color="@color/gray_9"
- app:text_size="@dimen/sp_12" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/remark"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_8"
- android:background="@drawable/shape_gray_3_bg_4"
- android:padding="@dimen/dp_12"
- android:text="深圳市宝安区西大街阳光绿色温馨家园17号楼313深圳市宝安区西大街阳光绿色温馨家园17号楼313深圳市宝安区西大街阳光绿色温馨家园17号楼313"
- android:textColor="@color/gray_7"
- android:textSize="@dimen/sp_14" />
-
- </LinearLayout>
-
+ android:nestedScrollingEnabled="false"
+ tools:visibility="gone" />
</RelativeLayout>
</androidx.core.widget.NestedScrollView>
@@ -375,5 +193,233 @@
</androidx.coordinatorlayout.widget.CoordinatorLayout>
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/location"
+ android:layout_width="@dimen/dp_32"
+ android:layout_height="@dimen/dp_32"
+ android:layout_marginEnd="@dimen/dp_12"
+ android:layout_marginBottom="@dimen/dp_12"
+ android:elevation="@dimen/dp_2"
+ android:src="@drawable/svg_location1"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent" />
+
+ <View
+ android:id="@+id/filterOverlay"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:background="#80000000"
+ android:elevation="@dimen/dp_4"
+ android:visibility="gone"
+ app:layout_constraintTop_toBottomOf="@+id/topLayout"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent" />
+
+ <LinearLayout
+ showAnim="@{viewModel.siteItem!=null}"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_white_bg_top_12"
+ android:elevation="@dimen/dp_2"
+ android:orientation="vertical"
+ app:layout_constraintBottom_toBottomOf="parent">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_50">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/title1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:gravity="center_vertical"
+ android:paddingHorizontal="@dimen/dp_20"
+ android:text="点位信息"
+ android:textColor="@color/gray_10"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/back1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginStart="@dimen/dp_20"
+ android:drawableStart="@drawable/svg_arrow_l"
+ android:drawablePadding="@dimen/dp_5"
+ android:text="返回"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_14" />
+
+ </RelativeLayout>
+
+ <LinearLayout
+ android:id="@+id/siteDetail"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <com.makeramen.roundedimageview.RoundedImageView
+ android:id="@+id/icon"
+ android:layout_width="@dimen/dp_68"
+ android:layout_height="@dimen/dp_92"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_8"
+ android:adjustViewBounds="true"
+ android:scaleType="centerCrop"
+ android:src="@drawable/img_site_bg"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:riv_corner_radius="@dimen/dp_5" />
+ <LinearLayout
+ android:id="@+id/nav"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/dp_20"
+ android:gravity="center"
+ android:orientation="vertical"
+ app:layout_constraintTop_toTopOf="@id/icon"
+ app:layout_constraintEnd_toEndOf="parent">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="@dimen/dp_10"
+ android:layout_height="@dimen/dp_10"
+ android:src="@mipmap/icon_arrow_blue" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="去导航"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_12" />
+ </LinearLayout>
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/name"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_8"
+ android:layout_marginEnd="@dimen/dp_8"
+ android:maxLines="1"
+ android:text="广州市白云机场T2航站楼"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ app:layout_constraintEnd_toStartOf="@id/nav"
+ app:layout_constraintStart_toEndOf="@+id/icon"
+ app:layout_constraintTop_toTopOf="@+id/icon" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/address"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_10"
+ android:maxLines="2"
+ android:text="深圳市宝安区西大街阳光绿色温馨家园17号楼313"
+ android:textColor="@color/gray_6"
+ android:textSize="@dimen/sp_12"
+ app:layout_constraintEnd_toEndOf="@id/name"
+ app:layout_constraintStart_toStartOf="@+id/name"
+ app:layout_constraintTop_toBottomOf="@+id/name" />
+
+ <com.xw.common.custom.ShowTextLinearLayout
+ android:id="@+id/stllTag"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_4"
+ android:layout_marginEnd="@dimen/dp_10"
+ android:orientation="vertical"
+ app:layout_constraintLeft_toLeftOf="@+id/name"
+ app:layout_constraintRight_toLeftOf="@+id/arrow1"
+ app:layout_constraintTop_toBottomOf="@+id/address"
+ app:margin_width="@dimen/dp_8"
+ app:max_padding_width="@dimen/dp_12"
+ app:min_padding_width="@dimen/dp_12"
+ app:padding_height="@dimen/dp_6"
+ app:padding_left="0dp"
+ app:padding_right="0dp"
+ app:text_bg="@drawable/shape_blue1_bg_4"
+ app:text_color="@color/blue_5"
+ app:text_size="@dimen/sp_12" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/arrow1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_8"
+ android:layout_marginEnd="@dimen/dp_20"
+ android:src="@drawable/svg_arrow_r"
+ android:visibility="gone"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/address" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_8"
+ android:background="@color/gray_4"
+ app:layout_constraintBottom_toBottomOf="parent" />
+
+ <com.xw.common.custom.ShowTextLinearLayout
+ android:id="@+id/stllTag1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="20dp"
+ android:layout_marginTop="@dimen/dp_12"
+ android:orientation="vertical"
+ app:margin_width="@dimen/dp_8"
+ app:max_padding_width="@dimen/dp_12"
+ app:min_padding_width="@dimen/dp_12"
+ app:padding_height="@dimen/dp_6"
+ app:padding_left="0dp"
+ app:padding_right="0dp"
+ app:text_bg="@drawable/shape_f8f9fa_bg_4"
+ app:text_color="@color/gray_9"
+ app:text_size="@dimen/sp_12" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/remark"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_8"
+ android:background="@drawable/shape_gray_3_bg_4"
+ android:minHeight="@dimen/dp_64"
+ android:padding="@dimen/dp_12"
+ android:text="深圳市宝安区西大街阳光绿色温馨家园17号楼313深圳市宝安区西大街阳光绿色温馨家园17号楼313深圳市宝安区西大街阳光绿色温馨家园17号楼313"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_14" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:layout_marginTop="@dimen/dp_38"
+ android:background="@color/gray_4" />
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/btn_error_upload"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginVertical="@dimen/dp_12"
+ android:backgroundTint="@color/blue_5"
+ android:text="现场情况上报"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:cornerRadius="@dimen/dp_4" />
+
+ </LinearLayout>
+ </LinearLayout>
+
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_standard_description.xml b/app/src/main/res/layout/activity_standard_description.xml
index 8ddde95..289ecfc 100644
--- a/app/src/main/res/layout/activity_standard_description.xml
+++ b/app/src/main/res/layout/activity_standard_description.xml
@@ -27,6 +27,7 @@
android:text="标准说明"
android:textColor="@color/gray_10"
android:textSize="@dimen/sp_16"
+ android:maxLength="16"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/back"
app:layout_constraintLeft_toLeftOf="parent"
diff --git a/app/src/main/res/layout/activity_web.xml b/app/src/main/res/layout/activity_web.xml
new file mode 100644
index 0000000..3506361
--- /dev/null
+++ b/app/src/main/res/layout/activity_web.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <data>
+
+ <variable
+ name="viewModel"
+ type="com.xw.yunwei.ui.common.WebVM" />
+ </data>
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/main"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".ui.common.WebActivity">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/back"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_56"
+ android:src="@drawable/svg_back"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxLength="16"
+ android:textColor="@color/gray_10"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:layout_constraintBottom_toBottomOf="@+id/back"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="@+id/back"
+ tools:text="标准说明" />
+
+
+ <WebView
+ android:id="@+id/web"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_marginTop="@dimen/dp_88"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_accident_filter.xml b/app/src/main/res/layout/dialog_accident_filter.xml
index 0025389..2fa3a90 100644
--- a/app/src/main/res/layout/dialog_accident_filter.xml
+++ b/app/src/main/res/layout/dialog_accident_filter.xml
@@ -11,36 +11,6 @@
android:layout_height="wrap_content"
android:background="@color/white"
android:paddingBottom="@dimen/dp_10">
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/cancel"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:paddingHorizontal="@dimen/dp_12"
- android:paddingVertical="@dimen/dp_8"
- android:text="取消"
- android:textColor="@color/gray_7"
- android:textSize="@dimen/sp_16"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintBottom_toBottomOf="@+id/title"
- app:layout_constraintTop_toTopOf="@+id/title" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/sure"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:paddingHorizontal="@dimen/dp_12"
- android:paddingVertical="@dimen/dp_8"
- app:layout_constraintRight_toRightOf="parent"
- android:text="确定"
- android:textColor="@color/blue_5"
- android:textSize="@dimen/sp_16"
- app:layout_constraintBottom_toBottomOf="@+id/title"
- app:layout_constraintTop_toTopOf="@+id/title" />
-
-
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/title"
android:layout_width="wrap_content"
@@ -52,9 +22,26 @@
android:textSize="@dimen/sp_16"
android:textStyle="bold"
app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/close"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/dp_20"
+ android:adjustViewBounds="true"
+ android:src="@drawable/svg_close"
+ app:layout_constraintBottom_toBottomOf="@+id/title"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="@+id/title" />
+
+ <View
+ android:id="@+id/v_line1"
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:layout_marginTop="@dimen/dp_20"
+ android:background="@color/gray_4"
+ app:layout_constraintTop_toBottomOf="@+id/title" />
<!-- 左边列表 -->
<androidx.recyclerview.widget.RecyclerView
@@ -74,14 +61,14 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginHorizontal="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_40"
+ android:layout_marginTop="@dimen/dp_12"
android:layout_weight="1"
android:background="@android:color/white"
android:scrollbars="vertical"
app:layout_constraintBottom_toTopOf="@+id/view"
app:layout_constraintLeft_toRightOf="@+id/leftRecyclerView"
app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/title" />
+ app:layout_constraintTop_toTopOf="@id/leftRecyclerView" />
<View
diff --git a/app/src/main/res/layout/dialog_apply_for_reassign_reason.xml b/app/src/main/res/layout/dialog_apply_for_reassign_reason.xml
new file mode 100644
index 0000000..2cca146
--- /dev/null
+++ b/app/src/main/res/layout/dialog_apply_for_reassign_reason.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_while_bg_5"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_16"
+ android:gravity="center"
+ android:text="请选择改派原因"
+ android:textColor="@color/gray_10"
+ android:textSize="@dimen/sp_18"
+ android:textStyle="bold" />
+
+ <com.google.android.flexbox.FlexboxLayout
+ android:id="@+id/fl_tags"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_16"
+ android:layout_marginVertical="@dimen/dp_12"
+ app:alignContent="stretch"
+ app:alignItems="stretch"
+ app:flexWrap="wrap"
+ app:justifyContent="flex_start" />
+
+ <EditText
+ android:id="@+id/et_input"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_4"
+ android:layout_marginBottom="@dimen/dp_8"
+ android:background="@drawable/shape_gray_4_line_gray_3_bg_4"
+ android:gravity="top|start"
+ android:hint="请输入改派原因"
+ android:maxLength="200"
+ android:minHeight="@dimen/dp_95"
+ android:padding="@dimen/dp_12"
+ android:textColor="@color/gray_9"
+ android:textColorLink="@color/gray_6"
+ android:textSize="@dimen/sp_14" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:background="@color/gray_4" />
+
+ <TextView
+ android:id="@+id/tv_operation"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_60"
+ android:gravity="center"
+ android:text="提交"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold" />
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_car_filter.xml b/app/src/main/res/layout/dialog_car_filter.xml
index 7e720cc..3c54341 100644
--- a/app/src/main/res/layout/dialog_car_filter.xml
+++ b/app/src/main/res/layout/dialog_car_filter.xml
@@ -6,154 +6,165 @@
</data>
- <androidx.core.widget.NestedScrollView
+ <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:background="@color/white"
+ android:paddingBottom="@dimen/dp_10">
- <androidx.constraintlayout.widget.ConstraintLayout
- android:layout_width="match_parent"
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:background="@color/white"
- android:paddingBottom="@dimen/dp_10">
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_20"
+ android:text="车辆状态筛选"
+ android:textColor="@color/gray_10"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_20"
- android:text="车辆状态筛选"
- android:textColor="@color/gray_10"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/close"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/dp_20"
+ android:adjustViewBounds="true"
+ android:src="@drawable/svg_close"
+ app:layout_constraintBottom_toBottomOf="@+id/title"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="@+id/title" />
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/close"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/dp_20"
- android:adjustViewBounds="true"
- android:src="@drawable/svg_close"
- app:layout_constraintBottom_toBottomOf="@+id/title"
- app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toTopOf="@+id/title" />
+ <View
+ android:id="@+id/v_line1"
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:layout_marginTop="@dimen/dp_20"
+ android:background="@color/gray_4"
+ app:layout_constraintTop_toBottomOf="@+id/title" />
- <View
- android:layout_width="match_parent"
- android:layout_height="1px"
- android:layout_marginTop="@dimen/dp_20"
- android:background="@color/gray_4"
- app:layout_constraintTop_toBottomOf="@+id/title" />
+ <androidx.core.widget.NestedScrollView
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:orientation="vertical"
+ app:layout_constraintBottom_toTopOf="@id/v_line2"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/v_line1">
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/tv"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_40"
- android:text="运营区域"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_14"
- android:textStyle="bold"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/title" />
-
- <com.xw.common.custom.ShowTextLinearLayout
- android:id="@+id/stllArea"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_12"
- android:orientation="vertical"
- app:layout_constraintTop_toBottomOf="@+id/tv"
- app:margin_width="@dimen/dp_8"
- app:max_padding_width="@dimen/dp_12"
- app:min_padding_width="@dimen/dp_12"
- app:padding_height="@dimen/dp_6"
- app:padding_left="0dp"
- app:padding_right="0dp"
- app:text_bg="@drawable/shape_f8f9fa_bg_4"
- app:text_color="@color/gray_9"
- app:text_size="@dimen/sp_12" />
+ android:orientation="vertical">
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/tv1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_20"
- android:text="车辆状态"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_14"
- android:textStyle="bold"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/stllArea" />
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_20"
+ android:text="运营区域"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/title" />
- <com.xw.common.custom.ShowTextLinearLayout
- android:id="@+id/stllStatus"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_12"
- android:orientation="vertical"
- app:layout_constraintTop_toBottomOf="@+id/tv1"
- app:margin_width="@dimen/dp_8"
- app:max_padding_width="@dimen/dp_12"
- app:min_padding_width="@dimen/dp_12"
- app:padding_height="@dimen/dp_6"
- app:padding_left="0dp"
- app:padding_right="0dp"
- app:text_bg="@drawable/shape_f8f9fa_bg_4"
- app:text_color="@color/gray_9"
- app:text_size="@dimen/sp_12" />
+ <com.xw.common.custom.ShowTextLinearLayout
+ android:id="@+id/stllArea"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_12"
+ android:orientation="vertical"
+ app:layout_constraintTop_toBottomOf="@+id/tv"
+ app:margin_width="@dimen/dp_8"
+ app:max_padding_width="@dimen/dp_12"
+ app:min_padding_width="@dimen/dp_12"
+ app:padding_height="@dimen/dp_6"
+ app:padding_left="0dp"
+ app:padding_right="0dp"
+ app:text_bg="@drawable/shape_f8f9fa_bg_4"
+ app:text_color="@color/gray_9"
+ app:text_size="@dimen/sp_12" />
- <View
- android:layout_width="match_parent"
- android:layout_height="1px"
- android:layout_marginTop="@dimen/dp_20"
- android:background="@color/gray_4"
- app:layout_constraintTop_toBottomOf="@+id/stllStatus" />
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_20"
+ android:text="车辆状态"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/stllArea" />
- <com.google.android.material.button.MaterialButton
- android:id="@+id/btnLeft"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_30"
- android:layout_marginEnd="@dimen/dp_5"
- android:backgroundTint="@color/blue_1"
- android:text="重置"
- android:textColor="@color/blue_5"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold"
- app:cornerRadius="@dimen/dp_4"
- app:layout_constraintHorizontal_weight="1"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintRight_toLeftOf="@+id/btnRight"
- app:layout_constraintTop_toBottomOf="@id/stllStatus" />
+ <com.xw.common.custom.ShowTextLinearLayout
+ android:id="@+id/stllStatus"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_12"
+ android:orientation="vertical"
+ app:layout_constraintTop_toBottomOf="@+id/tv1"
+ app:margin_width="@dimen/dp_8"
+ app:max_padding_width="@dimen/dp_12"
+ app:min_padding_width="@dimen/dp_12"
+ app:padding_height="@dimen/dp_6"
+ app:padding_left="0dp"
+ app:padding_right="0dp"
+ app:text_bg="@drawable/shape_f8f9fa_bg_4"
+ app:text_color="@color/gray_9"
+ app:text_size="@dimen/sp_12" />
+ </LinearLayout>
+ </androidx.core.widget.NestedScrollView>
- <com.google.android.material.button.MaterialButton
- android:id="@+id/btnRight"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_5"
- android:layout_marginTop="@dimen/dp_30"
- android:layout_marginEnd="@dimen/dp_20"
- android:backgroundTint="@color/blue_5"
- android:text="确定"
- android:textColor="@color/white"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold"
- app:cornerRadius="@dimen/dp_4"
- app:layout_constraintHorizontal_weight="1"
- app:layout_constraintLeft_toRightOf="@+id/btnLeft"
- app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toBottomOf="@id/stllStatus" />
+ <View
+ android:id="@+id/v_line2"
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:layout_marginTop="@dimen/dp_260"
+ android:background="@color/gray_4"
+ app:layout_constraintTop_toBottomOf="@id/v_line1" />
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/btnLeft"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_12"
+ android:layout_marginEnd="@dimen/dp_5"
+ android:backgroundTint="@color/blue_1"
+ android:text="重置"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:cornerRadius="@dimen/dp_4"
+ app:layout_constraintHorizontal_weight="1"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toLeftOf="@+id/btnRight"
+ app:layout_constraintTop_toBottomOf="@id/v_line2" />
- </androidx.constraintlayout.widget.ConstraintLayout>
- </androidx.core.widget.NestedScrollView>
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/btnRight"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_5"
+ android:layout_marginTop="@dimen/dp_12"
+ android:layout_marginEnd="@dimen/dp_20"
+ android:backgroundTint="@color/blue_5"
+ android:text="确定"
+ android:textColor="@color/white"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:cornerRadius="@dimen/dp_4"
+ app:layout_constraintHorizontal_weight="1"
+ app:layout_constraintLeft_toRightOf="@+id/btnLeft"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/v_line2" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_confirm_accept_car_point.xml b/app/src/main/res/layout/dialog_confirm_accept_car_point.xml
new file mode 100644
index 0000000..0e37afc
--- /dev/null
+++ b/app/src/main/res/layout/dialog_confirm_accept_car_point.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_while_bg_5"
+ android:orientation="vertical"
+ android:padding="@dimen/dp_16">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:text="收车点确认"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold" />
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_16"
+ android:background="@drawable/shape_0d31456a_bg_8"
+ android:padding="@dimen/dp_16">
+
+ <TextView
+ android:id="@+id/tv_label"
+ android:layout_width="@dimen/dp_38"
+ android:layout_height="@dimen/dp_18"
+ android:background="@drawable/shape_e5f0fc_bg_2"
+ android:gravity="center"
+ android:text="默认"
+ android:textColor="@color/color_0256ff"
+ android:textSize="@dimen/sp_11"
+ app:layout_constraintBottom_toBottomOf="@id/tv_title"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="@id/tv_title" />
+
+ <TextView
+ android:id="@+id/tv_title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_4"
+ android:singleLine="true"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@id/tv_label"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:text="广州市白云机场T2航站楼" />
+
+ <TextView
+ android:id="@+id/tv_detail"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_4"
+ android:layout_marginTop="@dimen/dp_4"
+ android:lineSpacingMultiplier="1.1"
+ android:textColor="@color/color_838fa6"
+ android:textSize="@dimen/sp_14"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_title"
+ tools:text="深圳市宝安区西大街阳光绿色温馨家园17号楼313" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_20"
+ android:orientation="horizontal">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_change"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/dp_42"
+ android:layout_marginEnd="@dimen/dp_6"
+ android:layout_weight="1"
+ android:background="@drawable/shape_gray_5_line_4"
+ android:gravity="center"
+ android:text="更换收车点"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_confirm"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/dp_42"
+ android:layout_marginStart="@dimen/dp_6"
+ android:layout_weight="1"
+ android:background="@drawable/shape_blue_5_bg_4"
+ android:gravity="center"
+ android:text="确认并收车"
+ android:textColor="@color/white"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold" />
+ </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_cruise_check_in_success.xml b/app/src/main/res/layout/dialog_cruise_check_in_success.xml
new file mode 100644
index 0000000..e8dd495
--- /dev/null
+++ b/app/src/main/res/layout/dialog_cruise_check_in_success.xml
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_while_bg_8"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/dp_32"
+ android:layout_marginTop="@dimen/dp_24"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:layout_width="@dimen/dp_32"
+ android:layout_height="@dimen/dp_32"
+ android:src="@mipmap/ic_tick_green" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="该点位已成功打卡"
+ android:layout_marginStart="@dimen/dp_11"
+ android:textColor="@color/gray_8"
+ android:textSize="@dimen/sp_18"
+ android:textStyle="bold" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_24"
+ android:layout_marginBottom="@dimen/dp_20"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/tv_time"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textColor="@color/color_cc31456A"
+ android:textSize="@dimen/sp_14"
+ tools:text="打卡时间:2026/09/09 18:09:09" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_8"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="打卡类型:"
+ android:textColor="@color/color_cc31456A"
+ android:textSize="@dimen/sp_14" />
+
+ <TextView
+ android:id="@+id/tv_check_result"
+ android:layout_width="@dimen/dp_64"
+ android:layout_height="@dimen/dp_24"
+ android:gravity="center"
+ android:text="超时打卡"
+ android:textColor="@color/color_cc31456A"
+ android:textSize="@dimen/sp_12" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_8"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="现场情况:"
+ android:textColor="@color/color_cc31456A"
+ android:textSize="@dimen/sp_14" />
+
+ <TextView
+ android:id="@+id/tv_work_status"
+ android:layout_width="@dimen/dp_40"
+ android:layout_height="@dimen/dp_24"
+ android:gravity="center"
+ android:text="拥堵"
+ android:textColor="@color/color_cc31456A"
+ android:textSize="@dimen/sp_12" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_8"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="描述内容:"
+ android:textColor="@color/color_cc31456A"
+ android:textSize="@dimen/sp_14" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/tv_desc"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textColor="@color/color_cc31456A"
+ android:textSize="@dimen/sp_14"
+ tools:text="描述内容详情描述内容详情描述内容详情描述内容详情描述内容详情描述内容详情描述内容详情" />
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/rv_list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_8"
+ tools:itemCount="3"
+ tools:layoutManager="GridLayoutManager"
+ tools:listitem="@layout/item_picture_operation"
+ tools:spanCount="3" />
+ </LinearLayout>
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:background="@color/gray_4" />
+
+ <TextView
+ android:id="@+id/tv_operation"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_60"
+ android:gravity="center"
+ android:text="前往下一个点位"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold" />
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_data_filter.xml b/app/src/main/res/layout/dialog_data_filter.xml
index 87e7eaa..5e37017 100644
--- a/app/src/main/res/layout/dialog_data_filter.xml
+++ b/app/src/main/res/layout/dialog_data_filter.xml
@@ -20,42 +20,30 @@
android:layout_marginTop="@dimen/dp_20"
android:text="任务筛选"
android:textColor="@color/gray_10"
- android:textSize="@dimen/sp_18"
+ android:textSize="@dimen/sp_16"
android:textStyle="bold"
app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/cancel"
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:paddingHorizontal="@dimen/dp_20"
- android:paddingVertical="@dimen/dp_8"
- android:text="取消"
- android:textColor="@color/gray_7"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold"
- app:layout_constraintBottom_toBottomOf="@+id/title"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintTop_toTopOf="@+id/title" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/sure"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:paddingHorizontal="@dimen/dp_20"
- android:paddingVertical="@dimen/dp_8"
- android:text="确定"
- android:textColor="@color/blue_5"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold"
+ android:layout_marginEnd="@dimen/dp_20"
+ android:adjustViewBounds="true"
+ android:src="@drawable/svg_close"
app:layout_constraintBottom_toBottomOf="@+id/title"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@+id/title" />
+ <View
+ android:id="@+id/v_line1"
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:layout_marginTop="@dimen/dp_20"
+ android:background="@color/gray_4"
+ app:layout_constraintTop_toBottomOf="@+id/title" />
+
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv"
android:layout_width="wrap_content"
diff --git a/app/src/main/res/layout/dialog_new_task.xml b/app/src/main/res/layout/dialog_new_task.xml
new file mode 100644
index 0000000..8e1775b
--- /dev/null
+++ b/app/src/main/res/layout/dialog_new_task.xml
@@ -0,0 +1,233 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <ImageView
+ android:id="@+id/iv_bg"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:scaleType="fitXY"
+ android:src="@mipmap/ic_apply_reassign_bg" />
+
+ <ImageView
+ android:id="@+id/iv_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentEnd="true"
+ android:src="@mipmap/icon_note" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_16"
+ android:layout_marginTop="@dimen/dp_20"
+ android:text="新任务提示"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold" />
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_alignStart="@id/iv_bg"
+ android:layout_alignTop="@id/iv_bg"
+ android:layout_alignEnd="@id/iv_bg"
+ android:layout_marginHorizontal="@dimen/dp_4"
+ android:layout_marginTop="@dimen/dp_60">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_4"
+ android:layout_marginTop="@dimen/dp_4"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/dp_20"
+ app:layout_constraintTop_toTopOf="parent">
+
+ <LinearLayout
+ android:id="@+id/countdownLayout"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_36"
+ android:layout_marginEnd="@dimen/dp_4"
+ android:background="@mipmap/img_task_item_top_bg_blue"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:paddingHorizontal="@dimen/dp_8">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/countdownTips"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:ellipsize="end"
+ android:gravity="end"
+ android:maxLines="1"
+ android:singleLine="true"
+ android:text="倒计时结束前,务必到达现场"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_12" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/hour"
+ android:layout_width="@dimen/dp_24"
+ android:layout_height="@dimen/dp_20"
+ android:layout_marginStart="@dimen/dp_4"
+ android:background="@drawable/shape_blue_5_bg_4"
+ android:gravity="center"
+ android:text="11"
+ android:textColor="@color/white"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/colon1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_3"
+ android:layout_marginTop="@dimen/dp_3"
+ android:src="@mipmap/ic_task_item_colon_b" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/minutes"
+ android:layout_width="@dimen/dp_24"
+ android:layout_height="@dimen/dp_20"
+ android:background="@drawable/shape_blue_5_bg_4"
+ android:gravity="center"
+ android:text="33"
+ android:textColor="@color/white"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/colon2"
+ android:layout_width="@dimen/dp_3"
+ android:layout_height="@dimen/dp_10"
+ android:layout_marginHorizontal="@dimen/dp_3"
+ android:layout_marginTop="@dimen/dp_3"
+ android:src="@mipmap/ic_task_item_colon_b" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/second"
+ android:layout_width="@dimen/dp_24"
+ android:layout_height="@dimen/dp_20"
+ android:background="@drawable/shape_blue_5_bg_4"
+ android:gravity="center"
+ android:text="09"
+ android:textColor="@color/white"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_16"
+ android:layout_marginTop="@dimen/dp_20"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/type"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_gray_7_r_4"
+ android:paddingHorizontal="@dimen/dp_8"
+ android:paddingVertical="@dimen/dp_3"
+ android:text="事故"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_14" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/plateNumber"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_marginHorizontal="@dimen/dp_8"
+ android:layout_weight="1"
+ android:text="粤A 888WM试"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_18"
+ android:textStyle="bold" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_gray_3_bg_2"
+ android:paddingHorizontal="@dimen/dp_8"
+ android:paddingVertical="@dimen/dp_3"
+ android:text="待到达"
+ android:textColor="@color/gray_8"
+ android:textSize="@dimen/sp_12" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_16"
+ android:layout_marginTop="@dimen/dp_16"
+ android:background="@mipmap/img_map"
+ android:minHeight="@dimen/dp_58"
+ android:orientation="horizontal">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/address"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="@dimen/dp_12"
+ android:layout_weight="1"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ tools:text="蜀山区华侨中心A座2301" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_16"
+ android:layout_marginTop="@dimen/dp_16"
+ android:orientation="horizontal">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_apply_for_reassignment"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/dp_40"
+ android:layout_marginEnd="@dimen/dp_6"
+ android:layout_weight="1"
+ android:background="@drawable/shape_gray_5_line_4"
+ android:gravity="center"
+ android:text="申请改派"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tvControl"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/dp_40"
+ android:layout_marginStart="@dimen/dp_6"
+ android:layout_weight="1"
+ android:background="@drawable/shape_blue_5_bg_4"
+ android:gravity="center"
+ android:text="接受任务"
+ android:textColor="@color/white"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold" />
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/level"
+ android:layout_width="@dimen/dp_32"
+ android:layout_height="@dimen/dp_24"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:src="@mipmap/ic_task_item_left_one" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
+</RelativeLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_protocol.xml b/app/src/main/res/layout/dialog_protocol.xml
index b30912b..5e9208b 100644
--- a/app/src/main/res/layout/dialog_protocol.xml
+++ b/app/src/main/res/layout/dialog_protocol.xml
@@ -1,61 +1,110 @@
<?xml version="1.0" encoding="utf-8"?>
-<layout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
</data>
- <androidx.constraintlayout.widget.ConstraintLayout
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
- <RelativeLayout
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_marginTop="@dimen/dp_32"
+ android:text="协议更新通知"
+ android:textColor="@color/gray_10"
+ android:textSize="@dimen/sp_18"
+ android:textStyle="bold" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_16"
+ android:text="为保障您的使用权益与数据安全,我们对以下平台相关协议内容进行优化更新,更新内容不影响原有服务。"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_16"
+ android:text="我已阅读并同意"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold" />
+
+ <LinearLayout
+ android:id="@+id/ll_agree"
android:layout_width="match_parent"
- android:layout_height="@dimen/dp_450"
- app:layout_constraintBottom_toTopOf="@+id/btnLeft"
- app:layout_constraintTop_toTopOf="parent">
+ android:layout_height="wrap_content"
+ android:paddingVertical="@dimen/dp_8"
+ android:orientation="vertical"
+ android:paddingHorizontal="@dimen/dp_20" />
- <include
- android:id="@+id/protocolLayout"
- layout="@layout/layout_protocol" />
+ <LinearLayout
+ android:id="@+id/ll_check_all"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/dp_32"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:paddingHorizontal="@dimen/dp_20">
- </RelativeLayout>
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/iv_check_all"
+ android:layout_width="@dimen/dp_20"
+ android:layout_height="@dimen/dp_20"
+ android:src="@mipmap/icon_circle_gray2" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_4"
+ android:text="全部勾选"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold" />
+ </LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
- android:layout_marginTop="@dimen/dp_30"
- android:background="@color/gray_4"
- app:layout_constraintBottom_toTopOf="@+id/btnLeft" />
+ android:background="@color/gray_4" />
- <Button
- android:id="@+id/btnLeft"
- android:layout_width="0dp"
- android:layout_height="@dimen/dp_50"
- android:layout_marginTop="@dimen/dp_30"
- android:background="@android:color/transparent"
- android:text="关闭"
- android:textColor="@color/gray_7"
- android:textSize="@dimen/sp_14"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintHorizontal_weight="1"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintRight_toLeftOf="@+id/btnRight" />
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_60"
+ android:orientation="horizontal">
- <Button
- android:id="@+id/btnRight"
- android:layout_width="0dp"
- android:layout_height="@dimen/dp_50"
- android:layout_marginTop="@dimen/dp_30"
- android:background="@android:color/transparent"
- android:text="同意并继续"
- android:textColor="@color/blue_5"
- android:textSize="@dimen/sp_14"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintHorizontal_weight="1"
- app:layout_constraintLeft_toRightOf="@+id/btnLeft"
- app:layout_constraintRight_toRightOf="parent" />
+ <Button
+ android:id="@+id/btnLeft"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@android:color/transparent"
+ android:text="不同意"
+ android:textColor="@color/gray_10"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold" />
- </androidx.constraintlayout.widget.ConstraintLayout>
+ <Button
+ android:id="@+id/btnRight"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@android:color/transparent"
+ android:text="同意"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold" />
+
+ </LinearLayout>
+ </LinearLayout>
</layout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_select_confirm_accept_car_point.xml b/app/src/main/res/layout/dialog_select_confirm_accept_car_point.xml
new file mode 100644
index 0000000..f6e9522
--- /dev/null
+++ b/app/src/main/res/layout/dialog_select_confirm_accept_car_point.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_white_bg_top_16"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/iv_flexing"
+ android:layout_width="@dimen/dp_40"
+ android:layout_height="@dimen/dp_40"
+ android:padding="@dimen/dp_8"
+ android:src="@mipmap/ic_down" />
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/rv_list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ tools:itemCount="3"
+ tools:listitem="@layout/item_accept_car_point" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:background="@color/gray_4" />
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/btn_operation"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_42"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginVertical="@dimen/dp_12"
+ android:background="@drawable/shape_blue_5_bg_4"
+ android:text="确认选择"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:cornerRadius="@dimen/dp_4" />
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_site_filter.xml b/app/src/main/res/layout/dialog_site_filter.xml
index 89ecc47..a87c3c5 100644
--- a/app/src/main/res/layout/dialog_site_filter.xml
+++ b/app/src/main/res/layout/dialog_site_filter.xml
@@ -60,7 +60,7 @@
android:id="@+id/stllStatus"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="10dp"
+ android:layout_marginHorizontal="20dp"
android:layout_marginTop="@dimen/dp_12"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@+id/tv"
diff --git a/app/src/main/res/layout/fragment_car_dispatch.xml b/app/src/main/res/layout/fragment_car_dispatch.xml
index db5b49d..0e183e3 100644
--- a/app/src/main/res/layout/fragment_car_dispatch.xml
+++ b/app/src/main/res/layout/fragment_car_dispatch.xml
@@ -13,19 +13,28 @@
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/color_surface">
+ android:background="@color/white">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/dp_50">
+ <View
+ android:layout_width="0dp"
+ android:layout_height="@dimen/dp_315"
+ android:layout_marginHorizontal="@dimen/dp_8"
+ android:background="@drawable/shape_0d31456a_0031456a_bg_4"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/carNo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_10"
android:text="@{viewModel.carInfo.plateNumber}"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_24"
@@ -75,111 +84,75 @@
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_10"
+ android:layout_width="@dimen/dp_335"
+ android:layout_height="@dimen/dp_168"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ android:layout_marginTop="@dimen/dp_8"
android:adjustViewBounds="true"
+ android:scaleType="centerCrop"
android:src="@mipmap/img_work_car1"
app:layout_constraintTop_toBottomOf="@+id/basicLayout" />
<LinearLayout
- android:id="@+id/unlockLayout"
+ android:id="@+id/ll_destination"
+ show="@{viewModel.isArrivingAcceptPoint}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_14"
+ android:layout_marginHorizontal="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_12"
- android:baselineAligned="false"
+ android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone"
app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/icon">
+ app:layout_constraintTop_toBottomOf="@+id/icon"
+ tools:visibility="visible">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="当前正在前往收车点"
+ android:textColor="@color/color_cc31456A"
+ android:textSize="@dimen/sp_11" />
<LinearLayout
- android:id="@+id/unlockDoor"
- show="@{viewModel.unlockDoorPermissions}"
- android:layout_width="0dp"
- android:layout_height="@dimen/dp_48"
- android:layout_marginHorizontal="@dimen/dp_6"
- android:layout_weight="1"
- android:background="@drawable/shape_blue1_bg_4"
- android:gravity="center"
- android:orientation="horizontal">
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_21"
+ android:layout_marginStart="@dimen/dp_4"
+ android:background="@drawable/shape_blue1_00006be1_bg_4"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:paddingHorizontal="@dimen/dp_4">
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
- android:src="@drawable/svg_car_cmjs"
- android:tint="@color/blue_5" />
+ <ImageView
+ android:layout_width="@dimen/dp_12"
+ android:layout_height="@dimen/dp_12"
+ android:src="@mipmap/icon_location_blue" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/dp_20"
+ android:layout_marginStart="@dimen/dp_4"
android:layout_weight="1"
- android:gravity="center"
- android:text="车门解锁"
+ android:ellipsize="end"
+ android:singleLine="true"
+ android:text="@{viewModel.arrivingAcceptPointAddress}"
android:textColor="@color/blue_5"
- android:textSize="@dimen/sp_14" />
-
+ android:textSize="@dimen/sp_11"
+ tools:text="广州市天河区珠江新城幸福小区东北门广州市天河区珠江新城幸福小区东北门" />
</LinearLayout>
-
- <LinearLayout
- android:id="@+id/unlockBox"
- android:layout_width="0dp"
- android:layout_height="@dimen/dp_48"
- show="@{viewModel.unlockBoxPermissions}"
- android:layout_marginHorizontal="@dimen/dp_6"
- android:layout_weight="1"
- android:background="@drawable/shape_blue1_bg_4"
- android:gravity="center"
- android:orientation="horizontal">
-
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
- android:src="@drawable/svg_car_hbxjs"
- android:tint="@color/blue_5" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/dp_20"
- android:layout_weight="1"
- android:gravity="center"
- android:text="后备箱解锁"
- android:textColor="@color/blue_5"
- android:textSize="@dimen/sp_14" />
-
- </LinearLayout>
-
</LinearLayout>
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/tv"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_30"
- app:layout_goneMarginTop="@dimen/dp_12"
- show="@{viewModel.departurePermissions}"
- android:text="发车状态"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold"
- app:layout_constraintLeft_toLeftOf="parent"
- android:layout_marginStart="@dimen/dp_20"
- app:layout_constraintTop_toBottomOf="@+id/unlockLayout" />
<com.xw.common.custom.SlideButtonView
android:id="@+id/slideView1"
+ show="@{viewModel.departurePermissions}"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_42"
android:layout_marginHorizontal="@dimen/dp_20"
- show="@{viewModel.departurePermissions}"
- android:layout_marginTop="@dimen/dp_10"
+ android:layout_marginTop="@dimen/dp_8"
app:backgroundCornerRadius="@dimen/dp_4"
- app:layout_constraintTop_toBottomOf="@+id/tv"
+ app:layout_constraintTop_toBottomOf="@id/ll_destination"
+ app:layout_goneMarginTop="@dimen/dp_12"
app:slideBackgroundColor="@color/blue_1"
app:slideDirection="right"
app:slideText="右滑发车"
@@ -191,78 +164,173 @@
<LinearLayout
android:id="@+id/layout1"
+ show="@{viewModel.couldTakeOrderOrTest}"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- show="@{viewModel.takeOrdersPermissions}"
+ android:layout_height="@dimen/dp_72"
android:layout_marginHorizontal="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_30"
+ android:layout_marginTop="@dimen/dp_12"
android:layout_marginBottom="8dp"
android:gravity="center_vertical"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@+id/slideView1">
- <androidx.appcompat.widget.AppCompatTextView
+ <LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:text="接单/测试"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold" />
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@drawable/shape_gray_3_bg_4"
- android:orientation="horizontal"
- android:padding="@dimen/dp_2">
+ android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/takeOrders"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:background="@drawable/shape_white_bg_4"
- android:gravity="center"
- android:paddingHorizontal="@dimen/dp_12"
- android:paddingVertical="@dimen/dp_6"
- android:text="接单"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="接单状态"
android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_12"
+ android:textSize="@dimen/sp_14"
android:textStyle="bold" />
<androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/test"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:gravity="center"
- android:paddingHorizontal="@dimen/dp_12"
- android:paddingVertical="@dimen/dp_6"
- android:text="测试"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_12"
- android:textStyle="bold" />
-
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_4"
+ android:text="控制平台是否给该车辆派发运营订单"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_12" />
</LinearLayout>
+ <CheckBox
+ android:id="@+id/cb_take_order"
+ android:layout_width="@dimen/dp_52"
+ android:layout_height="@dimen/dp_32"
+ android:background="@drawable/selector_switch_off_on"
+ android:button="@null"
+ android:checked="@{viewModel.hadOpenTakeOrder}"
+ android:text="" />
</LinearLayout>
- <com.xw.common.custom.SlideButtonView
- android:id="@+id/slideView2"
+ <LinearLayout
+ android:id="@+id/unlockLayout"
+ show="@{viewModel.couldOperationDevice}"
android:layout_width="match_parent"
- android:layout_height="@dimen/dp_42"
- android:layout_marginHorizontal="@dimen/dp_20"
- show="@{viewModel.takeOrdersPermissions}"
- android:layout_marginTop="@dimen/dp_10"
- app:backgroundCornerRadius="@dimen/dp_4"
- app:layout_constraintTop_toBottomOf="@+id/layout1"
- app:slideBackgroundColor="@color/orange_5"
- app:slideDirection="left"
- app:slideText="左滑关闭接单"
- app:slideTextColor="@color/white"
- app:slideTextSize="@dimen/sp_14"
- app:thumbCornerRadius="@dimen/dp_4"
- app:thumbDrawable="@mipmap/ic_slide_l"
- app:thumbShape="roundRect" />
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/layout1">
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:background="@color/gray_4" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_16"
+ android:text="车辆控制"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/icon"
+ app:layout_goneMarginTop="@dimen/dp_12" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_14"
+ android:layout_marginTop="@dimen/dp_8"
+ android:baselineAligned="false"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:id="@+id/unlockDoor"
+ show="@{viewModel.unlockDoorPermissions}"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/dp_48"
+ android:layout_marginHorizontal="@dimen/dp_6"
+ android:layout_weight="1"
+ android:background="@drawable/shape_gray2_bg_4"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <FrameLayout
+ android:layout_width="@dimen/dp_32"
+ android:layout_height="@dimen/dp_32"
+ android:layout_marginStart="@dimen/dp_20">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/iv_door_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/svg_net_lock_gray" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/iv_door_status_loading"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:src="@drawable/svg_circle_loading" />
+ </FrameLayout>
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_door_lock"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/dp_20"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:text="车门解锁"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_14" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/unlockBox"
+ show="@{viewModel.unlockBoxPermissions}"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/dp_48"
+ android:layout_marginHorizontal="@dimen/dp_6"
+ android:layout_weight="1"
+ android:background="@drawable/shape_gray2_bg_4"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <FrameLayout
+ android:layout_width="@dimen/dp_32"
+ android:layout_height="@dimen/dp_32"
+ android:layout_marginStart="@dimen/dp_20">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/iv_trunk_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/svg_car_trunk_closed" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/iv_trunk_status_loading"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:src="@drawable/svg_circle_loading" />
+ </FrameLayout>
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_trunk_lock"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/dp_20"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:text="后备箱解锁"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_14" />
+
+ </LinearLayout>
+
+ </LinearLayout>
+ </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/layout/fragment_car_management.xml b/app/src/main/res/layout/fragment_car_management.xml
index d251d16..693c6db 100644
--- a/app/src/main/res/layout/fragment_car_management.xml
+++ b/app/src/main/res/layout/fragment_car_management.xml
@@ -76,9 +76,12 @@
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_width="@dimen/dp_335"
+ android:layout_height="@dimen/dp_168"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="@dimen/dp_10"
+ android:scaleType="centerCrop"
android:adjustViewBounds="true"
android:src="@mipmap/img_work_car1"
app:layout_constraintTop_toBottomOf="@+id/basicLayout" />
@@ -199,12 +202,13 @@
android:textSize="@dimen/sp_14" />
<androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_phone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:text="@{viewModel.carInfo.insurancePhone}"
- android:textColor="@color/gray_9"
+ android:textColor="@color/blue_5"
android:textSize="@dimen/sp_14"
tools:text="8888888888" />
@@ -237,6 +241,7 @@
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
+ android:layout_centerVertical="true"
android:layout_height="wrap_content"
android:text="下次保养时间"
android:textColor="@color/gray_7"
diff --git a/app/src/main/res/layout/fragment_car_operations.xml b/app/src/main/res/layout/fragment_car_operations.xml
index d583ec8..0f31538 100644
--- a/app/src/main/res/layout/fragment_car_operations.xml
+++ b/app/src/main/res/layout/fragment_car_operations.xml
@@ -41,10 +41,12 @@
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginEnd="@dimen/dp_20"
- android:background="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
- android:padding="4dp"
+ android:paddingLeft="8dp"
+ android:paddingRight="4dp"
+ android:paddingTop="10dp"
+ android:paddingBottom="10dp"
show="@{viewModel.recordPermissions}"
app:layout_constraintBottom_toBottomOf="@+id/carNo"
app:layout_constraintRight_toRightOf="parent"
@@ -108,10 +110,13 @@
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_width="@dimen/dp_335"
+ android:layout_height="@dimen/dp_168"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="@dimen/dp_10"
android:adjustViewBounds="true"
+ android:scaleType="centerCrop"
android:src="@mipmap/img_work_car1"
app:layout_constraintTop_toBottomOf="@+id/basicLayout" />
@@ -126,22 +131,20 @@
android:orientation="horizontal"
app:layout_flexBasisPercent="50%">
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
- android:layout_weight="1"
- android:text="车辆整备"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold" />
-
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/dp_20"
+ android:layout_marginStart="@dimen/dp_30"
android:src="@drawable/svg_car_zhengbei" />
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_18"
+ android:layout_weight="1"
+ android:text="车辆整备"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16" />
</LinearLayout>
<LinearLayout
@@ -155,6 +158,12 @@
android:orientation="horizontal"
app:layout_flexBasisPercent="50%">
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_31"
+ android:src="@drawable/svg_car_chongdian" />
+
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="0dp"
android:layout_height="wrap_content"
@@ -162,14 +171,7 @@
android:layout_weight="1"
android:text="车辆充电"
android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/dp_20"
- android:src="@drawable/svg_car_chongdian" />
+ android:textSize="@dimen/sp_16" />
</LinearLayout>
@@ -183,6 +185,11 @@
android:gravity="center"
android:orientation="horizontal"
app:layout_flexBasisPercent="50%">
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_33"
+ android:src="@drawable/svg_car_jiance" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="0dp"
@@ -191,15 +198,7 @@
android:layout_weight="1"
android:text="车辆检测"
android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/dp_20"
- android:src="@drawable/svg_car_jiance" />
-
+ android:textSize="@dimen/sp_16" />
</LinearLayout>
<LinearLayout
@@ -213,21 +212,20 @@
android:orientation="horizontal"
app:layout_flexBasisPercent="50%">
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
- android:layout_weight="1"
- android:text="车辆维修"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold" />
-
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/dp_20"
+ android:layout_marginStart="@dimen/dp_30"
android:src="@drawable/svg_car_weixiu" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_18"
+ android:layout_weight="1"
+ android:text="车辆维修"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16" />
</LinearLayout>
@@ -242,21 +240,20 @@
android:orientation="horizontal"
app:layout_flexBasisPercent="50%">
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_20"
- android:layout_weight="1"
- android:text="车身清洁"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold" />
-
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/dp_20"
+ android:layout_marginStart="@dimen/dp_31"
android:src="@drawable/svg_car_qingjie" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_18"
+ android:layout_weight="1"
+ android:text="车身清洁"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_16" />
</LinearLayout>
@@ -264,7 +261,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/dp_12"
- android:layout_marginTop="@dimen/dp_4"
+ android:layout_marginTop="@dimen/dp_12"
app:constraint_referenced_ids="zhengbeiLayout,chongdianLayout,jianceLayout,weixiuLayout,qingjieLayout"
app:flow_horizontalGap="@dimen/dp_12"
app:flow_maxElementsWrap="2"
diff --git a/app/src/main/res/layout/fragment_mine.xml b/app/src/main/res/layout/fragment_mine.xml
index 6da1617..2e750df 100644
--- a/app/src/main/res/layout/fragment_mine.xml
+++ b/app/src/main/res/layout/fragment_mine.xml
@@ -11,489 +11,802 @@
</data>
- <androidx.core.widget.NestedScrollView
+ <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_surface"
android:fillViewport="true">
- <androidx.constraintlayout.widget.ConstraintLayout
+ <androidx.appcompat.widget.AppCompatImageView
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:adjustViewBounds="true"
+ android:background="@mipmap/img_mine_bg"
+ app:layout_constraintTop_toTopOf="parent" />
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:adjustViewBounds="true"
- android:background="@mipmap/img_mine_bg"
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/infoLayout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_68"
+ android:onClick="@{viewModel.onClick}"
+ app:layout_constraintTop_toTopOf="parent">
+
+ <de.hdodenhof.circleimageview.CircleImageView
+ android:id="@+id/avatar"
+ imageDefault="@{viewModel.avatar}"
+ android:layout_width="@dimen/dp_60"
+ android:layout_height="@dimen/dp_60"
+ android:layout_marginStart="@dimen/dp_28"
+ android:scaleType="centerCrop"
+ android:src="@drawable/svg_avatar"
+ app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
- <androidx.constraintlayout.widget.ConstraintLayout
- android:id="@+id/infoLayout"
- android:layout_width="match_parent"
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/name"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_68"
- android:onClick="@{viewModel.onClick}"
- app:layout_constraintTop_toTopOf="parent">
+ android:layout_marginStart="@dimen/dp_12"
+ android:text="@{viewModel.userInfo.nickName}"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_20"
+ android:textStyle="bold"
+ app:layout_constraintStart_toEndOf="@+id/avatar"
+ app:layout_constraintTop_toTopOf="@+id/avatar"
+ tools:text="李嘉峰" />
- <de.hdodenhof.circleimageview.CircleImageView
- android:id="@+id/avatar"
- imageDefault="@{viewModel.avatar}"
- android:layout_width="@dimen/dp_60"
- android:layout_height="@dimen/dp_60"
- android:layout_marginStart="@dimen/dp_28"
- android:scaleType="centerCrop"
- android:src="@drawable/svg_avatar"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_12"
- android:text="@{viewModel.userInfo.nickName}"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_20"
- android:textStyle="bold"
- app:layout_constraintStart_toEndOf="@+id/avatar"
- app:layout_constraintTop_toTopOf="@+id/avatar"
- tools:text="李嘉峰" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/phone"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_6"
- android:text="@{viewModel.userInfo.phoneNumber}"
- android:textColor="@color/blue_5"
- android:textSize="@dimen/sp_14"
- app:layout_constraintTop_toTopOf="@+id/name"
- app:layout_constraintBottom_toBottomOf="@+id/name"
- app:layout_constraintStart_toEndOf="@+id/name"
- tools:text="13488881203" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/dp_28"
- android:src="@drawable/svg_arrow_r"
- app:layout_constraintBottom_toBottomOf="@+id/name"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="@+id/name" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/role"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_2"
- android:text="所属角色:"
- android:textColor="@color/gray_7"
- android:textSize="@dimen/sp_12"
- app:layout_constraintStart_toStartOf="@+id/name"
- app:layout_constraintTop_toBottomOf="@+id/name" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_2"
- android:text="@{viewModel.roleName}"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_12"
- app:layout_constraintBaseline_toBaselineOf="@+id/role"
- app:layout_constraintStart_toEndOf="@+id/role"
- tools:text="未分配" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/captain"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_2"
- android:text="所属队长:"
- android:textColor="@color/gray_7"
- android:textSize="@dimen/sp_12"
- app:layout_constraintStart_toStartOf="@+id/name"
- app:layout_constraintTop_toBottomOf="@+id/role" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_2"
- android:text="@{viewModel.fleetLeaderName}"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_12"
- app:layout_constraintBaseline_toBaselineOf="@+id/captain"
- app:layout_constraintStart_toEndOf="@+id/captain"
- tools:text="李雷" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/team"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_2"
- android:text="所属队伍:"
- android:textColor="@color/gray_7"
- android:textSize="@dimen/sp_12"
- app:layout_constraintStart_toStartOf="@+id/name"
- app:layout_constraintTop_toBottomOf="@+id/captain" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_2"
- android:text="@{viewModel.fleetName}"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_12"
- app:layout_constraintBaseline_toBaselineOf="@+id/team"
- app:layout_constraintStart_toEndOf="@+id/team"
- tools:text="广州网格员一队" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@drawable/shape_orange_1_bg_4"
- android:gravity="center"
- android:paddingHorizontal="@dimen/dp_8"
- android:paddingVertical="@dimen/dp_2"
- android:textColor="@color/orange_5"
- android:textSize="@dimen/sp_10"
- app:layout_constraintBottom_toBottomOf="@+id/team"
- app:layout_constraintEnd_toEndOf="@+id/avatar"
- app:layout_constraintStart_toStartOf="@+id/avatar"
- tools:text="未打卡" />
- </androidx.constraintlayout.widget.ConstraintLayout>
-
- <androidx.cardview.widget.CardView
- android:id="@+id/layout"
- android:layout_width="match_parent"
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/phone"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_12"
- android:layout_marginTop="@dimen/dp_25"
- app:cardCornerRadius="@dimen/dp_8"
- app:cardElevation="@dimen/dp_2"
- app:layout_constraintTop_toBottomOf="@+id/infoLayout">
+ android:layout_marginStart="@dimen/dp_6"
+ android:text="@{viewModel.userInfo.phoneNumber}"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ app:layout_constraintBottom_toBottomOf="@+id/name"
+ app:layout_constraintStart_toEndOf="@+id/name"
+ app:layout_constraintTop_toTopOf="@+id/name"
+ tools:text="13488881203" />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:padding="16dp">
-
- <LinearLayout
- android:id="@+id/schedulingLayout"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:onClick="@{viewModel.onClick}"
- android:orientation="horizontal">
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="排班考勤"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_14"
- android:textStyle="bold" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/svg_arrow_r" />
-
- </LinearLayout>
-
-<!-- show="@{viewModel.clockModel!=null}"-->
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dp"
- android:background="@drawable/shape_f8f9fa_bg_4"
- android:gravity="center_vertical"
- android:orientation="horizontal"
- android:paddingHorizontal="@dimen/dp_9"
- android:paddingVertical="@dimen/dp_7">
-
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="20dp"
- android:layout_height="20dp"
- android:src="@drawable/svg_banci"
- app:tint="#1976D2" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
- show="@{viewModel.clockModel!=null}"
- android:text='@{viewModel.clockModel.xpShift.shiftName+""}'
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_12"
- tools:text="早班" />
-
- <View
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@{viewModel.clockTime}"
- show="@{viewModel.clockModel!=null}"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_12"
- android:textStyle="bold"
- tools:text="2026-09-21 09:00~17:00" />
-
- </LinearLayout>
-
-<!-- show="@{viewModel.clockModel!=null}"-->
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dp"
- android:gravity="center_vertical"
- android:orientation="horizontal">
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="打卡地点"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_14"
- android:textStyle="bold" />
-
- <View
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1" />
-
-<!-- show="@{viewModel.clockModel.clockIn != true || viewModel.clockModel.clockOut != true}"-->
- <androidx.appcompat.widget.AppCompatImageView
- show="@{viewModel.clockModel!=null && (viewModel.clockModel.clockIn != true || viewModel.clockModel.clockOut != true)}"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/svg_location" />
-
-<!-- show="@{viewModel.clockModel.clockIn != true || viewModel.clockModel.clockOut != true}"-->
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/goCheck"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- show="@{viewModel.clockModel!=null && (viewModel.clockModel.clockIn != true || viewModel.clockModel.clockOut != true)}"
- android:layout_marginStart="4dp"
- android:onClick="@{viewModel.onClick}"
- android:text="去打卡"
- android:textColor="@color/blue_5"
- android:textSize="@dimen/sp_14"
- android:textStyle="bold" />
-
- </LinearLayout>
-
-<!-- show="@{viewModel.clockModel!=null}"-->
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_12"
- android:background="@mipmap/img_map">
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginVertical="@dimen/dp_10"
- android:layout_marginStart="@dimen/dp_12"
- android:layout_marginEnd="@dimen/dp_60"
- android:text="@{viewModel.clockModel.xpCheckLocation.locationAddress}"
- show="@{viewModel.clockModel!=null}"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_14"
- android:textStyle="bold"
- tools:text="蜀山区华侨中心A座2301" />
-
- <!-- 导航按钮 -->
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/nav"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="end|center_vertical"
- android:layout_margin="@dimen/dp_12"
- android:src="@drawable/svg_map_nav" />
-
- </FrameLayout>
-
- </LinearLayout>
-
- </androidx.cardview.widget.CardView>
-
- <androidx.cardview.widget.CardView
- android:layout_width="match_parent"
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_12"
- android:layout_marginTop="@dimen/dp_12"
- android:layout_marginBottom="@dimen/dp_25"
- app:cardCornerRadius="@dimen/dp_8"
- app:cardElevation="@dimen/dp_2"
- app:layout_constraintTop_toBottomOf="@+id/layout">
+ android:layout_marginEnd="@dimen/dp_28"
+ android:src="@drawable/svg_arrow_r"
+ app:layout_constraintBottom_toBottomOf="@+id/name"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="@+id/name" />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/role"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_2"
+ android:text="所属角色:"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_12"
+ app:layout_constraintStart_toStartOf="@+id/name"
+ app:layout_constraintTop_toBottomOf="@+id/name" />
- <LinearLayout
- android:id="@+id/setLayout"
- android:layout_width="match_parent"
- android:layout_height="@dimen/dp_56"
- android:gravity="center_vertical"
- android:onClick="@{viewModel.onClick}"
- android:orientation="horizontal"
- android:paddingHorizontal="@dimen/dp_16">
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/roleValue"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/dp_28"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:text="@{viewModel.roleName}"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_12"
+ app:layout_constraintBaseline_toBaselineOf="@+id/role"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0"
+ app:layout_constraintStart_toEndOf="@+id/role"
+ app:layout_constraintWidth_default="wrap"
+ tools:text="未分配" />
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/svg_mine_set" />
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/captain"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_2"
+ android:text="所属队长:"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_12"
+ app:layout_constraintStart_toStartOf="@+id/name"
+ app:layout_constraintTop_toBottomOf="@+id/roleValue" />
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginStart="12dp"
- android:layout_weight="1"
- android:text="设置"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_14"
- android:textStyle="bold" />
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_2"
+ android:text="@{viewModel.fleetLeaderName}"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_12"
+ app:layout_constraintBaseline_toBaselineOf="@+id/captain"
+ app:layout_constraintStart_toEndOf="@+id/captain"
+ tools:text="李雷" />
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/svg_arrow_r" />
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/team"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_2"
+ android:text="所属队伍:"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_12"
+ app:layout_constraintStart_toStartOf="@+id/name"
+ app:layout_constraintTop_toBottomOf="@+id/captain" />
- </LinearLayout>
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_2"
+ android:text="@{viewModel.fleetName}"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_12"
+ app:layout_constraintBaseline_toBaselineOf="@+id/team"
+ app:layout_constraintStart_toEndOf="@+id/team"
+ tools:text="广州网格员一队" />
- <View
- android:layout_width="match_parent"
- android:layout_height="1px"
- android:layout_marginHorizontal="@dimen/dp_16"
- android:background="@color/gray_4" />
-
- <LinearLayout
- android:id="@+id/tiaokuan"
- android:layout_width="match_parent"
- android:layout_height="@dimen/dp_56"
- android:gravity="center_vertical"
- android:orientation="horizontal"
- android:paddingHorizontal="@dimen/dp_16">
-
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/svg_mine_tiaokuan" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginStart="12dp"
- android:layout_weight="1"
- android:text="服务条款"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_14"
- android:textStyle="bold" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/svg_arrow_r" />
-
- </LinearLayout>
-
- <View
- android:layout_width="match_parent"
- android:layout_height="1px"
- android:layout_marginHorizontal="@dimen/dp_16"
- android:background="@color/gray_4" />
-
- <LinearLayout
- android:id="@+id/contact"
- android:layout_width="match_parent"
- android:layout_height="@dimen/dp_56"
- android:gravity="center_vertical"
- android:orientation="horizontal"
- android:paddingHorizontal="@dimen/dp_16">
-
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/svg_mine_kefu" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginStart="12dp"
- android:layout_weight="1"
- android:text="联系客服"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_14"
- android:textStyle="bold" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/svg_arrow_r" />
-
- </LinearLayout>
-
- <View
- android:layout_width="match_parent"
- android:layout_height="1px"
- android:layout_marginHorizontal="@dimen/dp_16"
- android:background="@color/gray_4" />
-
- <LinearLayout
- android:id="@+id/uploadLayout"
- android:layout_width="match_parent"
- android:layout_height="@dimen/dp_56"
- android:gravity="center_vertical"
- android:onClick="@{viewModel.onClick}"
- android:orientation="horizontal"
- android:paddingHorizontal="@dimen/dp_16">
-
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/svg_mine_card" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginStart="12dp"
- android:layout_weight="1"
- android:text="证件上传"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_14"
- android:textStyle="bold" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/svg_arrow_r" />
-
- </LinearLayout>
-
- <View
- android:layout_width="match_parent"
- android:layout_height="1px"
- android:layout_marginHorizontal="@dimen/dp_16"
- android:background="@color/gray_4" />
-
- </LinearLayout>
-
- </androidx.cardview.widget.CardView>
-
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_orange_1_bg_4"
+ android:gravity="center"
+ android:paddingHorizontal="@dimen/dp_8"
+ android:paddingVertical="@dimen/dp_2"
+ android:textColor="@color/orange_5"
+ android:textSize="@dimen/sp_10"
+ app:layout_constraintBottom_toBottomOf="@+id/team"
+ app:layout_constraintEnd_toEndOf="@+id/avatar"
+ app:layout_constraintStart_toStartOf="@+id/avatar"
+ tools:text="未打卡" />
</androidx.constraintlayout.widget.ConstraintLayout>
- </androidx.core.widget.NestedScrollView>
+ <androidx.core.widget.NestedScrollView
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_marginTop="@dimen/dp_16"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/infoLayout">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_12"
+ app:cardCornerRadius="@dimen/dp_8"
+ app:cardElevation="@dimen/dp_2">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="16dp">
+
+ <LinearLayout
+ android:id="@+id/schedulingLayout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:onClick="@{viewModel.onClick}"
+ android:orientation="horizontal">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="排班考勤"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/svg_arrow_r" />
+
+ </LinearLayout>
+
+ <!-- show="@{viewModel.clockModel!=null}"-->
+ <LinearLayout
+ show="@{viewModel.clockModel.hadConfigCheckInfo()}"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dp"
+ android:background="@drawable/shape_f8f9fa_bg_4"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:paddingHorizontal="@dimen/dp_9"
+ android:paddingVertical="@dimen/dp_7"
+ android:visibility="gone"
+ tools:visibility="visible">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="20dp"
+ android:layout_height="20dp"
+ android:src="@drawable/svg_banci"
+ app:tint="#1976D2" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ show="@{viewModel.clockModel!=null}"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="8dp"
+ android:text='@{viewModel.clockModel.xpShift.shiftName+""}'
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_12"
+ tools:text="早班" />
+
+ <View
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ show="@{viewModel.clockModel!=null}"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@{viewModel.clockTime}"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_12"
+ tools:text="2026-09-21 09:00~17:00" />
+
+ </LinearLayout>
+
+ <!-- show="@{viewModel.clockModel!=null}"-->
+ <LinearLayout
+ show="@{viewModel.clockModel.hadConfigCheckInfo()}"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dp"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:visibility="gone"
+ tools:visibility="visible">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="打卡地点"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold" />
+
+ <View
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <!-- show="@{viewModel.clockModel.clockIn != true || viewModel.clockModel.clockOut != true}"-->
+ <androidx.appcompat.widget.AppCompatImageView
+ show="@{viewModel.clockModel!=null && (viewModel.clockModel.clockIn != true || viewModel.clockModel.clockOut != true)}"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/svg_location" />
+
+ <!-- show="@{viewModel.clockModel.clockIn != true || viewModel.clockModel.clockOut != true}"-->
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/goCheck"
+ show="@{viewModel.clockModel!=null && (viewModel.clockModel.clockIn != true || viewModel.clockModel.clockOut != true)}"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="4dp"
+ android:onClick="@{viewModel.onClick}"
+ android:text="去打卡"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold" />
+
+ </LinearLayout>
+
+ <!-- show="@{viewModel.clockModel!=null}"-->
+ <FrameLayout
+ show="@{viewModel.clockModel.hadConfigCheckInfo()}"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_12"
+ android:background="@mipmap/img_map"
+ android:visibility="gone"
+ tools:visibility="visible">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ show="@{viewModel.clockModel!=null}"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginVertical="@dimen/dp_10"
+ android:layout_marginStart="@dimen/dp_12"
+ android:layout_marginEnd="@dimen/dp_60"
+ android:text="@{viewModel.clockModel.xpCheckLocation.locationAddress}"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ tools:text="蜀山区华侨中心A座2301" />
+
+ <!-- 导航按钮 -->
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/nav"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|center_vertical"
+ android:layout_margin="@dimen/dp_12"
+ android:src="@drawable/svg_map_nav" />
+
+ </FrameLayout>
+
+ <LinearLayout
+ android:id="@+id/ll_empty"
+ show="@{!viewModel.clockModel.hadConfigCheckInfo()}"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_20"
+ android:gravity="center"
+ android:onClick="@{viewModel.onClick}"
+ android:orientation="vertical">
+
+ <ImageView
+ android:layout_width="@dimen/dp_58"
+ android:layout_height="@dimen/dp_64"
+ android:src="@mipmap/icon_date_empty" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_8"
+ android:text="今日暂无排班安排"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_12"
+ android:textStyle="bold" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_4"
+ android:text="点击卡片可查看近30天全部排班"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_12" />
+ </LinearLayout>
+ </LinearLayout>
+
+ </androidx.cardview.widget.CardView>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/cv_task"
+ show="@{viewModel.cruiseCheckInMissionInfo.effective}"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_12"
+ android:layout_marginTop="@dimen/dp_16"
+ android:onClick="@{viewModel.onClick}"
+ android:visibility="gone"
+ app:cardCornerRadius="@dimen/dp_8"
+ app:cardElevation="@dimen/dp_2"
+ app:layout_constraintTop_toBottomOf="@+id/layout"
+ tools:visibility="visible">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="16dp">
+
+ <LinearLayout
+ android:id="@+id/ll_cruise_check_in_mission"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="巡游打卡任务"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/svg_arrow_r" />
+
+ </LinearLayout>
+
+ <!-- show="@{viewModel.clockModel!=null}"-->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dp"
+ android:background="@drawable/shape_f8f9fa_bg_4"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:paddingHorizontal="@dimen/dp_9"
+ android:paddingVertical="@dimen/dp_7">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="20dp"
+ android:layout_height="20dp"
+ android:src="@mipmap/ic_clock_note" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_4"
+ android:text="任务时间"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_12" />
+
+ <View
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_mission_time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_12"
+ tools:text="2026-09-21 09:00~17:00" />
+
+ </LinearLayout>
+
+ <!-- show="@{viewModel.clockModel!=null}"-->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dp"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="打卡情况"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold" />
+
+ <View
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+ </LinearLayout>
+
+ <!-- show="@{viewModel.clockModel!=null}"-->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_12"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center">
+
+ <com.xw.yunwei.ui.widget.CircularProgressView
+ android:id="@+id/cpv_progress"
+ android:layout_width="@dimen/dp_100"
+ android:layout_height="@dimen/dp_100"
+ app:backgroundProgressColor="@color/orange_5"
+ app:maxProgress="100"
+ app:progress="0"
+ app:progressColor="@color/green_5"
+ app:progressRoundStyle="false"
+ app:ringWidth="@dimen/dp_10" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/tv_mission_point_count"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="0"
+ android:textColor="@color/color_3d3d3d"
+ android:textSize="@dimen/sp_20"
+ android:textStyle="bold" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="打卡点位"
+ android:textColor="@color/color_3d3d3d"
+ android:textSize="@dimen/sp_12"
+ android:textStyle="bold" />
+ </LinearLayout>
+ </FrameLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_24"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="@dimen/dp_124"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="已打卡"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_12"
+ android:textStyle="bold" />
+
+ <View
+ android:layout_width="0dp"
+ android:layout_height="@dimen/dp_1"
+ android:layout_weight="1" />
+
+ <TextView
+ android:id="@+id/tv_had_report_num"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/green_5"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ tools:text="16" />
+
+ </LinearLayout>
+
+ <ProgressBar
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="@dimen/dp_124"
+ android:layout_height="@dimen/dp_8"
+ android:max="@{viewModel.cruiseCheckInMissionInfo.checkInPointCount}"
+ android:maxHeight="@dimen/dp_8"
+ android:minHeight="@dimen/dp_8"
+ android:progress="@{viewModel.cruiseCheckInMissionInfo.checkInPointFinishCount}"
+ android:progressDrawable="@drawable/layer_list_green_progress_bar" />
+
+ <LinearLayout
+ android:layout_width="@dimen/dp_124"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_20"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="未打卡"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_12"
+ android:textStyle="bold" />
+
+ <View
+ android:layout_width="0dp"
+ android:layout_height="@dimen/dp_1"
+ android:layout_weight="1" />
+
+ <TextView
+ android:id="@+id/tv_not_report_num"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/orange_5"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ tools:text="16" />
+
+ </LinearLayout>
+
+ <ProgressBar
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="@dimen/dp_124"
+ android:layout_height="@dimen/dp_8"
+ android:max="@{viewModel.cruiseCheckInMissionInfo.checkInPointCount}"
+ android:maxHeight="@dimen/dp_8"
+ android:minHeight="@dimen/dp_8"
+ android:progress="@{viewModel.cruiseCheckInMissionInfo.checkInPointUnFinishCount}"
+ android:progressDrawable="@drawable/layer_list_orange_progress_bar" />
+
+ </LinearLayout>
+ </LinearLayout>
+
+ </LinearLayout>
+
+ </androidx.cardview.widget.CardView>
+
+ <androidx.cardview.widget.CardView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_12"
+ android:layout_marginTop="@dimen/dp_16"
+ android:layout_marginBottom="@dimen/dp_25"
+ app:cardCornerRadius="@dimen/dp_8"
+ app:cardElevation="@dimen/dp_2"
+ app:layout_constraintTop_toBottomOf="@+id/cv_task">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:id="@+id/uploadLayout"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_56"
+ android:gravity="center_vertical"
+ android:onClick="@{viewModel.onClick}"
+ android:orientation="horizontal"
+ android:paddingHorizontal="@dimen/dp_16">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/svg_mine_card" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_weight="1"
+ android:text="证件上传"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/svg_arrow_r" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:layout_marginHorizontal="@dimen/dp_16"
+ android:background="@color/gray_4" />
+
+ <LinearLayout
+ android:id="@+id/contact"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_56"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:paddingHorizontal="@dimen/dp_16">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/svg_mine_kefu" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_weight="1"
+ android:text="联系客服"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_phone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/dp_6"
+ android:text="@{viewModel.phone}"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_12"
+ tools:text="12345678901" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/svg_arrow_r" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:layout_marginHorizontal="@dimen/dp_16"
+ android:background="@color/gray_4" />
+
+ <LinearLayout
+ android:id="@+id/tiaokuan"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_56"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:paddingHorizontal="@dimen/dp_16">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/svg_mine_tiaokuan" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_weight="1"
+ android:text="服务条款"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/svg_arrow_r" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:layout_marginHorizontal="@dimen/dp_16"
+ android:background="@color/gray_4" />
+
+ <LinearLayout
+ android:id="@+id/setLayout"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_56"
+ android:gravity="center_vertical"
+ android:onClick="@{viewModel.onClick}"
+ android:orientation="horizontal"
+ android:paddingHorizontal="@dimen/dp_16">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/svg_mine_set" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_weight="1"
+ android:text="设置"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/svg_arrow_r" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:layout_marginHorizontal="@dimen/dp_16"
+ android:background="@color/gray_4" />
+
+ </LinearLayout>
+
+ </androidx.cardview.widget.CardView>
+
+ </LinearLayout>
+ </androidx.core.widget.NestedScrollView>
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
</layout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_record_list.xml b/app/src/main/res/layout/fragment_record_list.xml
index efeaa12..d663348 100644
--- a/app/src/main/res/layout/fragment_record_list.xml
+++ b/app/src/main/res/layout/fragment_record_list.xml
@@ -30,7 +30,8 @@
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
- android:gravity="center"
+ android:gravity="center_vertical|start"
+ android:paddingStart="@dimen/dp_16"
android:text="操作人"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_12" />
diff --git a/app/src/main/res/layout/fragment_task.xml b/app/src/main/res/layout/fragment_task.xml
index 83cff93..3149415 100644
--- a/app/src/main/res/layout/fragment_task.xml
+++ b/app/src/main/res/layout/fragment_task.xml
@@ -31,16 +31,28 @@
app:layout_constraintTop_toTopOf="parent"
tools:ignore="UselessLeaf">
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/back"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginStart="@dimen/dp_8"
+ android:onClick="@{viewModel.onClick}"
+ android:paddingHorizontal="@dimen/dp_12"
+ android:paddingVertical="@dimen/dp_8"
+ android:src="@drawable/svg_back"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
- android:layout_marginStart="@dimen/dp_20"
+ android:layout_toEndOf="@id/back"
android:text="任务中心"
android:textColor="@color/gray_10"
android:textSize="@dimen/sp_20"
android:textStyle="bold" />
-
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/notice"
@@ -73,17 +85,21 @@
app:layout_constraintTop_toBottomOf="@+id/rlTitleBar"
tools:ignore="MissingConstraints">
- <androidx.appcompat.widget.AppCompatEditText
+ <com.xw.yunwei.ui.widget.ClearEditText
android:id="@+id/searchEt"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
+ app:iconHeight="@dimen/dp_18"
+ app:iconWidth="@dimen/dp_18"
+ app:clearIcon="@mipmap/icon_close_gray"
android:background="@drawable/shape_white_bg_4"
android:drawableStart="@mipmap/ic_search_task"
android:drawablePadding="@dimen/dp_6"
android:ellipsize="end"
android:gravity="center_vertical"
android:hint="请输入车牌号"
+ android:maxLength="8"
android:imeOptions="actionSearch"
android:orientation="horizontal"
android:paddingHorizontal="@dimen/dp_8"
@@ -119,14 +135,14 @@
android:layout_marginTop="@dimen/dp_3"
android:background="@null"
app:layout_constraintTop_toBottomOf="@+id/llSearchAndFilter"
+ app:tabBackground="@null"
app:tabGravity="fill"
app:tabIndicator="@drawable/layer_indicator_task"
app:tabIndicatorColor="@color/blue_5"
app:tabIndicatorHeight="@dimen/dp_2"
- app:tabMode="fixed"
+ app:tabMode="scrollable"
app:tabPaddingEnd="12dp"
app:tabPaddingStart="12dp"
- app:tabBackground="@null"
app:tabRippleColor="@null"
app:tabSelectedTextColor="@color/blue_5"
app:tabTextColor="@color/gray_7" />
@@ -137,10 +153,172 @@
android:layout_height="0dp"
android:layout_marginTop="-8dp"
android:paddingTop="@dimen/dp_12"
- app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/navView"
app:layout_constraintTop_toBottomOf="@+id/tabLayout"
app:layout_constraintVertical_bias="0.0"
tools:layout_editor_absoluteX="0dp" />
+ <LinearLayout
+ android:id="@+id/navView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/white"
+ android:gravity="center"
+ android:orientation="horizontal"
+ app:layout_constraintBottom_toBottomOf="parent">
+
+ <RelativeLayout
+ android:id="@+id/rl_all"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:onClick="@{viewModel.onClick}">
+
+ <LinearLayout
+ android:id="@+id/ll_all"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:layout_marginVertical="@dimen/dp_8"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ selected="@{viewModel.selectTaskTypeIndex==0}"
+ android:layout_width="@dimen/dp_28"
+ android:layout_height="@dimen/dp_28"
+ android:src="@drawable/selector_nav_task_all" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ selected="@{viewModel.selectTaskTypeIndex==0}"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_4"
+ android:gravity="center"
+ android:text="全部任务"
+ android:textColor="@drawable/selector_task_bottom_nav"
+ android:textSize="@dimen/sp_10" />
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/tv_all_count"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/dp_18"
+ android:layout_alignStart="@id/ll_all"
+ android:layout_marginStart="@dimen/dp_24"
+ android:background="@drawable/shape_red_5_bg_white_line_20"
+ android:gravity="center"
+ android:minWidth="@dimen/dp_18"
+ android:paddingHorizontal="@dimen/dp_4"
+ android:textColor="@color/white"
+ android:textSize="@dimen/sp_11"
+ android:textStyle="bold"
+ android:visibility="gone"
+ tools:text="1"
+ tools:visibility="visible" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/rl_accident"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:onClick="@{viewModel.onClick}">
+
+ <LinearLayout
+ android:id="@+id/ll_accident"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:layout_marginVertical="@dimen/dp_8"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ selected="@{viewModel.selectTaskTypeIndex==1}"
+ android:layout_width="@dimen/dp_28"
+ android:layout_height="@dimen/dp_28"
+ android:src="@drawable/selector_nav_task_accident" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ selected="@{viewModel.selectTaskTypeIndex==1}"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_4"
+ android:gravity="center"
+ android:text="事故任务"
+ android:textColor="@drawable/selector_task_bottom_nav"
+ android:textSize="@dimen/sp_10" />
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/tv_accident_count"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/dp_18"
+ android:layout_alignStart="@id/ll_accident"
+ android:layout_marginStart="@dimen/dp_24"
+ android:background="@drawable/shape_red_5_bg_white_line_20"
+ android:gravity="center"
+ android:minWidth="@dimen/dp_18"
+ android:paddingHorizontal="@dimen/dp_4"
+ android:textColor="@color/white"
+ android:textSize="@dimen/sp_11"
+ android:textStyle="bold"
+ android:visibility="gone"
+ tools:text="99"
+ tools:visibility="visible" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/rl_normal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:onClick="@{viewModel.onClick}">
+
+ <LinearLayout
+ android:id="@+id/ll_normal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:layout_marginVertical="@dimen/dp_8"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ selected="@{viewModel.selectTaskTypeIndex==2}"
+ android:layout_width="@dimen/dp_28"
+ android:layout_height="@dimen/dp_28"
+ android:src="@drawable/selector_nav_task_normal" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ selected="@{viewModel.selectTaskTypeIndex==2}"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_4"
+ android:gravity="center"
+ android:text="常规任务"
+ android:textColor="@drawable/selector_task_bottom_nav"
+ android:textSize="@dimen/sp_10" />
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/tv_normal_count"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/dp_18"
+ android:layout_alignStart="@id/ll_normal"
+ android:layout_marginStart="@dimen/dp_24"
+ android:background="@drawable/shape_red_5_bg_white_line_20"
+ android:gravity="center"
+ android:minWidth="@dimen/dp_18"
+ android:paddingHorizontal="@dimen/dp_4"
+ android:textColor="@color/white"
+ android:textSize="@dimen/sp_11"
+ android:textStyle="bold"
+ android:visibility="gone"
+ tools:text="99+"
+ tools:visibility="visible" />
+ </RelativeLayout>
+ </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_task_list.xml b/app/src/main/res/layout/fragment_task_list.xml
index cb17ce0..ef51697 100644
--- a/app/src/main/res/layout/fragment_task_list.xml
+++ b/app/src/main/res/layout/fragment_task_list.xml
@@ -6,7 +6,7 @@
</data>
- <com.scwang.smart.refresh.layout.SmartRefreshLayout
+ <com.xw.yunwei.ui.widget.CustomRefreshLayout
android:id="@+id/refreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -17,6 +17,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
- </com.scwang.smart.refresh.layout.SmartRefreshLayout>
+ </com.xw.yunwei.ui.widget.CustomRefreshLayout>
</layout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_work.xml b/app/src/main/res/layout/fragment_work.xml
index d04d6d6..22c3a6f 100644
--- a/app/src/main/res/layout/fragment_work.xml
+++ b/app/src/main/res/layout/fragment_work.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools">
<data>
@@ -11,12 +12,12 @@
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:background="@color/color_surface">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@color/color_surface">
+ android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="match_parent"
@@ -26,21 +27,20 @@
app:layout_constraintTop_toTopOf="parent" />
<View
+ android:id="@+id/situated"
android:layout_width="match_parent"
android:layout_height="1px"
- app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="@dimen/dp_52"
- android:id="@+id/situated"/>
+ app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/report"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:onClick="@{viewModel.onClick}"
android:layout_marginHorizontal="@dimen/dp_12"
- show="@{viewModel.reportPermissions}"
android:layout_marginTop="@dimen/dp_12"
android:adjustViewBounds="true"
+ android:onClick="@{viewModel.onClick}"
android:src="@mipmap/img_work_report"
app:layout_constraintTop_toBottomOf="@+id/situated" />
@@ -48,12 +48,11 @@
android:id="@+id/cardLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- show="@{viewModel.carPermissions}"
android:layout_marginHorizontal="@dimen/dp_12"
android:layout_marginTop="@dimen/dp_12"
app:cardCornerRadius="@dimen/dp_8"
app:cardElevation="@dimen/dp_2"
- app:layout_constraintTop_toBottomOf="@+id/report">
+ app:layout_constraintTop_toBottomOf="@id/report">
<LinearLayout
android:layout_width="match_parent"
@@ -65,8 +64,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
- android:orientation="horizontal"
android:onClick="@{viewModel.onClick}"
+ android:orientation="horizontal"
android:padding="@dimen/dp_16"
android:paddingHorizontal="16dp">
@@ -76,24 +75,37 @@
android:layout_weight="1"
android:text="车辆管理"
android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_14"
+ android:textSize="@dimen/sp_16"
android:textStyle="bold" />
<androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/svg_arrow_r" />
+ android:layout_width="@dimen/dp_16"
+ android:layout_height="@dimen/dp_16"
+ android:src="@mipmap/ic_task_item_arrow_right" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/carRv"
+ show="@{viewModel.carPermissions&&viewModel.carList.size()>0}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingBottom="@dimen/dp_16"
- show="@{viewModel.carList.size()>0}"
- android:paddingHorizontal="@dimen/dp_16" />
+ android:paddingHorizontal="@dimen/dp_13"
+ android:paddingBottom="@dimen/dp_13"
+ tools:itemCount="4"
+ tools:layoutManager="LinearLayoutManager"
+ tools:listitem="@layout/item_work_car"
+ tools:orientation="horizontal" />
+ <androidx.appcompat.widget.AppCompatTextView
+ show="@{!viewModel.carPermissions}"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_70"
+ android:text="暂无可管理车辆"
+ android:gravity="center"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold" />
</LinearLayout>
</androidx.cardview.widget.CardView>
@@ -102,12 +114,10 @@
android:id="@+id/siteLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- show="@{viewModel.sitePermissions}"
- android:layout_marginHorizontal="@dimen/dp_12"
- android:layout_marginTop="@dimen/dp_12"
+ android:layout_margin="@dimen/dp_12"
app:cardCornerRadius="@dimen/dp_8"
app:cardElevation="@dimen/dp_2"
- app:layout_constraintTop_toBottomOf="@+id/cardLayout">
+ app:layout_constraintTop_toBottomOf="@id/cardLayout">
<LinearLayout
android:id="@+id/siteNav"
@@ -127,15 +137,15 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:text="站点点位"
+ android:text="站点管理"
android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_14"
+ android:textSize="@dimen/sp_16"
android:textStyle="bold" />
<androidx.appcompat.widget.AppCompatImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/svg_arrow_r" />
+ android:layout_width="@dimen/dp_16"
+ android:layout_height="@dimen/dp_16"
+ android:src="@mipmap/ic_task_item_arrow_right" />
</LinearLayout>
@@ -150,10 +160,16 @@
</androidx.cardview.widget.CardView>
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_10"
+ app:layout_constraintTop_toBottomOf="@id/siteLayout" />
+
<androidx.cardview.widget.CardView
android:id="@+id/courseLayout"
android:layout_width="0dp"
android:layout_height="0dp"
+ android:visibility="gone"
app:cardCornerRadius="@dimen/dp_8"
app:cardElevation="@dimen/dp_2"
app:layout_constraintBottom_toBottomOf="@+id/course"
@@ -170,12 +186,14 @@
android:adjustViewBounds="true"
android:elevation="@dimen/dp_3"
android:src="@mipmap/img_work_course"
+ android:visibility="gone"
app:layout_constraintTop_toBottomOf="@+id/siteLayout" />
<androidx.cardview.widget.CardView
android:id="@+id/examLayout"
android:layout_width="0dp"
android:layout_height="0dp"
+ android:visibility="gone"
app:cardCornerRadius="@dimen/dp_8"
app:cardElevation="@dimen/dp_2"
app:layout_constraintBottom_toBottomOf="@+id/exam"
@@ -193,6 +211,7 @@
android:adjustViewBounds="true"
android:elevation="@dimen/dp_3"
android:src="@mipmap/img_work_exam"
+ android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/course" />
diff --git a/app/src/main/res/layout/item_accept_car_point.xml b/app/src/main/res/layout/item_accept_car_point.xml
new file mode 100644
index 0000000..ab256e2
--- /dev/null
+++ b/app/src/main/res/layout/item_accept_car_point.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_109">
+
+ <ImageView
+ android:id="@+id/iv_selected"
+ android:layout_width="@dimen/dp_20"
+ android:layout_height="@dimen/dp_20"
+ android:layout_marginStart="@dimen/dp_20"
+ android:src="@mipmap/icon_circle_gray2"
+ app:layout_constraintBottom_toBottomOf="@id/iv_picture"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="@id/iv_picture" />
+
+ <ImageView
+ android:id="@+id/iv_picture"
+ android:layout_width="@dimen/dp_68"
+ android:layout_height="@dimen/dp_92"
+ android:layout_marginStart="@dimen/dp_48"
+ android:layout_marginTop="@dimen/dp_8"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/tv_label"
+ android:layout_width="@dimen/dp_38"
+ android:layout_height="@dimen/dp_18"
+ android:layout_marginStart="@dimen/dp_8"
+ android:background="@drawable/shape_e5f0fc_bg_2"
+ android:gravity="center"
+ android:text="默认"
+ android:textColor="@color/color_0256ff"
+ android:textSize="@dimen/sp_11"
+ android:visibility="gone"
+ app:layout_constraintBottom_toBottomOf="@id/tv_title"
+ app:layout_constraintStart_toEndOf="@id/iv_picture"
+ app:layout_constraintTop_toTopOf="@id/tv_title"
+ tools:visibility="visible" />
+
+ <TextView
+ android:id="@+id/tv_title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_4"
+ android:layout_marginEnd="@dimen/dp_20"
+ android:singleLine="true"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@id/tv_label"
+ app:layout_constraintTop_toTopOf="@id/iv_picture"
+ app:layout_goneMarginStart="@dimen/dp_8"
+ tools:text="广州市白云机场T2航站楼" />
+
+ <TextView
+ android:id="@+id/tv_detail"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_8"
+ android:layout_marginTop="@dimen/dp_4"
+ android:layout_marginEnd="@dimen/dp_20"
+ android:textColor="@color/color_838fa6"
+ android:textSize="@dimen/sp_14"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@id/iv_picture"
+ app:layout_constraintTop_toBottomOf="@id/tv_title"
+ tools:text="深圳市宝安区西大街阳光绿色温馨家园17号楼313" />
+
+ <View
+ android:id="@+id/v_line"
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:layout_marginStart="@dimen/dp_20"
+ android:background="@color/gray_4"
+ app:layout_constraintBottom_toBottomOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_accident_right_filter.xml b/app/src/main/res/layout/item_accident_right_filter.xml
index 9418402..8cd333a 100644
--- a/app/src/main/res/layout/item_accident_right_filter.xml
+++ b/app/src/main/res/layout/item_accident_right_filter.xml
@@ -12,9 +12,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dp_12"
- android:gravity="center"
+ android:gravity="center|start"
android:minHeight="@dimen/dp_32"
- android:padding="@dimen/dp_6"
+ android:padding="@dimen/dp_8"
android:textSize="@dimen/sp_14" />
diff --git a/app/src/main/res/layout/item_car_repair.xml b/app/src/main/res/layout/item_car_repair.xml
index 5d7e8a1..8b232b7 100644
--- a/app/src/main/res/layout/item_car_repair.xml
+++ b/app/src/main/res/layout/item_car_repair.xml
@@ -18,7 +18,8 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:gravity="center"
+ android:gravity="center_vertical|start"
+ android:paddingStart="@dimen/dp_16"
android:text="李中冰"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_12"
diff --git a/app/src/main/res/layout/item_check_in_mission_point.xml b/app/src/main/res/layout/item_check_in_mission_point.xml
new file mode 100644
index 0000000..f0013e9
--- /dev/null
+++ b/app/src/main/res/layout/item_check_in_mission_point.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:id="@+id/ll_no"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:gravity="center"
+ android:orientation="vertical"
+ app:layout_constraintBottom_toBottomOf="@id/ll_content"
+ app:layout_constraintEnd_toStartOf="@id/ll_content"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
+
+ <!-- 序号 -->
+ <TextView
+ android:id="@+id/tv_index"
+ android:layout_width="@dimen/dp_16"
+ android:layout_height="@dimen/dp_16"
+ android:background="@drawable/circle_gray_6"
+ android:gravity="center"
+ android:text="1"
+ android:textColor="@color/white"
+ android:textSize="@dimen/sp_10"
+ android:textStyle="bold" />
+
+ <com.xw.yunwei.ui.widget.LineView
+ android:id="@+id/lv_line"
+ android:layout_width="@dimen/dp_3"
+ android:layout_height="0dp"
+ android:layout_marginVertical="@dimen/dp_6"
+ android:layout_weight="1"
+ app:dashLineSize="@dimen/dp_3"
+ app:lineColor="@color/gray_6"
+ app:dashLineStroke="@dimen/dp_1"
+ app:lineInterval="@dimen/dp_1" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/ll_content"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_12"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/dp_12"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@id/ll_no"
+ app:layout_constraintTop_toTopOf="parent">
+ <!-- 顶部信息行 -->
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/tv_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="打卡限时"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_12"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/tv_time_range"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/tv_title"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ tools:text="08:00~09:00" />
+
+ <TextView
+ android:id="@+id/tv_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/tv_title"
+ android:layout_alignParentEnd="true"
+ android:paddingHorizontal="@dimen/dp_8"
+ android:paddingVertical="@dimen/dp_1"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_12"
+ tools:text="08:41:57 已打卡" />
+ </RelativeLayout>
+
+ <LinearLayout
+ android:id="@+id/ll_address_nav"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_8"
+ android:background="@mipmap/img_map"
+ android:minHeight="@dimen/dp_58"
+ android:orientation="horizontal">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/address"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="@dimen/dp_12"
+ android:layout_weight="1"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ tools:text="蜀山区华侨中心A座2301" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/nav"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|center_vertical"
+ android:layout_margin="@dimen/dp_12"
+ android:src="@drawable/svg_map_nav" />
+ </LinearLayout>
+
+ </LinearLayout>
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_date_week.xml b/app/src/main/res/layout/item_date_week.xml
new file mode 100644
index 0000000..df9ad0e
--- /dev/null
+++ b/app/src/main/res/layout/item_date_week.xml
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:id="@+id/ll_date1"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_day1"
+ android:layout_width="@dimen/dp_44"
+ android:layout_height="@dimen/dp_44"
+ android:background="@drawable/selector_date_bg"
+ android:gravity="center"
+ android:textColor="@color/selector_grey9_to_white"
+ android:textSize="@dimen/sp_20"
+ android:textStyle="bold"
+ tools:text="18" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/ll_date2"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_day2"
+ android:layout_width="@dimen/dp_44"
+ android:layout_height="@dimen/dp_44"
+ android:background="@drawable/selector_date_bg"
+ android:gravity="center"
+ android:textColor="@color/selector_grey9_to_white"
+ android:textSize="@dimen/sp_20"
+ android:textStyle="bold"
+ tools:text="18" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/ll_date3"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_day3"
+ android:layout_width="@dimen/dp_44"
+ android:layout_height="@dimen/dp_44"
+ android:background="@drawable/selector_date_bg"
+ android:gravity="center"
+ android:textColor="@color/selector_grey9_to_white"
+ android:textSize="@dimen/sp_20"
+ android:textStyle="bold"
+ tools:text="18" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/ll_date4"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_day4"
+ android:layout_width="@dimen/dp_44"
+ android:layout_height="@dimen/dp_44"
+ android:background="@drawable/selector_date_bg"
+ android:gravity="center"
+ android:textColor="@color/selector_grey9_to_white"
+ android:textSize="@dimen/sp_20"
+ android:textStyle="bold"
+ tools:text="18" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/ll_date5"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_day5"
+ android:layout_width="@dimen/dp_44"
+ android:layout_height="@dimen/dp_44"
+ android:background="@drawable/selector_date_bg"
+ android:gravity="center"
+ android:textColor="@color/selector_grey9_to_white"
+ android:textSize="@dimen/sp_20"
+ android:textStyle="bold"
+ tools:text="18" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/ll_date6"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_day6"
+ android:layout_width="@dimen/dp_44"
+ android:layout_height="@dimen/dp_44"
+ android:background="@drawable/selector_date_bg"
+ android:gravity="center"
+ android:textColor="@color/selector_grey9_to_white"
+ android:textSize="@dimen/sp_20"
+ android:textStyle="bold"
+ tools:text="18" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/ll_date7"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_day7"
+ android:layout_width="@dimen/dp_44"
+ android:layout_height="@dimen/dp_44"
+ android:background="@drawable/selector_date_bg"
+ android:gravity="center"
+ android:textColor="@color/selector_grey9_to_white"
+ android:textSize="@dimen/sp_20"
+ android:textStyle="bold"
+ tools:text="18" />
+ </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_pdf_entrance.xml b/app/src/main/res/layout/item_pdf_entrance.xml
new file mode 100644
index 0000000..a743fe0
--- /dev/null
+++ b/app/src/main/res/layout/item_pdf_entrance.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_56"
+ android:gravity="center_vertical">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_name"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:ellipsize="end"
+ android:singleLine="true"
+ android:text=""
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="@dimen/dp_16"
+ android:layout_height="@dimen/dp_16"
+ android:layout_marginStart="@dimen/dp_10"
+ android:src="@mipmap/ic_task_item_arrow_right" />
+ </LinearLayout>
+
+ <View
+ android:id="@+id/v_line"
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:background="@color/gray_4" />
+</LinearLayout>
diff --git a/app/src/main/res/layout/item_picture_operation.xml b/app/src/main/res/layout/item_picture_operation.xml
new file mode 100644
index 0000000..7be74a1
--- /dev/null
+++ b/app/src/main/res/layout/item_picture_operation.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="@dimen/dp_69"
+ android:layout_height="@dimen/dp_69"
+ android:padding="@dimen/dp_3">
+
+ <ImageView
+ android:id="@+id/iv_picture"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:src="@mipmap/ic_add_picture" />
+
+ <ImageView
+ android:id="@+id/iv_delete"
+ android:layout_width="@dimen/dp_24"
+ android:layout_height="@dimen/dp_24"
+ android:layout_gravity="end"
+ android:padding="@dimen/dp_4"
+ android:src="@mipmap/icon_circle_line_black"
+ android:visibility="gone"
+ tools:visibility="visible" />
+</FrameLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_protocol.xml b/app/src/main/res/layout/item_protocol.xml
new file mode 100644
index 0000000..ac5f1b7
--- /dev/null
+++ b/app/src/main/res/layout/item_protocol.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingVertical="@dimen/dp_8"
+ android:orientation="horizontal">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/iv_check"
+ android:layout_width="@dimen/dp_20"
+ android:layout_height="@dimen/dp_20"
+ android:src="@mipmap/icon_circle_gray2" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_4"
+ android:text="全部勾选"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_14" />
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_protocol_entrance.xml b/app/src/main/res/layout/item_protocol_entrance.xml
new file mode 100644
index 0000000..2fc6bf7
--- /dev/null
+++ b/app/src/main/res/layout/item_protocol_entrance.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_50">
+
+ <TextView
+ android:id="@+id/tv_title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_20"
+ android:singleLine="true"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/iv_more"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:text="权限调用" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/iv_more"
+ android:layout_width="@dimen/dp_16"
+ android:layout_height="@dimen/dp_16"
+ android:layout_marginEnd="@dimen/dp_20"
+ android:src="@mipmap/ic_task_item_arrow_right"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <View
+ android:id="@+id/v_line"
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:layout_marginStart="@dimen/dp_20"
+ android:background="@color/gray_4"
+ app:layout_constraintBottom_toBottomOf="parent" />
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_select_car.xml b/app/src/main/res/layout/item_select_car.xml
index 7c12442..5889cea 100644
--- a/app/src/main/res/layout/item_select_car.xml
+++ b/app/src/main/res/layout/item_select_car.xml
@@ -30,7 +30,7 @@
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_10"
+ android:layout_marginHorizontal="@dimen/dp_10"
android:layout_weight="1"
android:orientation="vertical">
@@ -45,11 +45,13 @@
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/color"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/dp_4"
android:gravity="left|center_vertical"
android:text="白色 | 车身编码:01234"
+ android:singleLine="true"
+ android:ellipsize="end"
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_14" />
diff --git a/app/src/main/res/layout/item_task_content.xml b/app/src/main/res/layout/item_task_content.xml
index e7a6246..f5a3aec 100644
--- a/app/src/main/res/layout/item_task_content.xml
+++ b/app/src/main/res/layout/item_task_content.xml
@@ -7,200 +7,263 @@
</data>
- <androidx.constraintlayout.widget.ConstraintLayout
+ <FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/dp_10"
android:layout_marginBottom="@dimen/dp_12">
- <LinearLayout
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/cl_content"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_4"
- android:layout_marginTop="@dimen/dp_4"
- android:background="@drawable/shape_white_bg_4"
- android:orientation="vertical"
- android:paddingBottom="@dimen/dp_16"
- app:layout_constraintTop_toTopOf="parent">
-
- <LinearLayout
- android:id="@+id/countdownLayout"
- android:layout_width="match_parent"
- android:layout_height="@dimen/dp_36"
- android:background="@mipmap/img_task_item_top_bg_blue"
- android:gravity="center_vertical"
- android:orientation="horizontal"
- android:paddingHorizontal="@dimen/dp_12">
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/countdownTips"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:ellipsize="end"
- android:gravity="end"
- android:paddingEnd="@dimen/dp_8"
- android:maxLines="1"
- android:singleLine="true"
- android:text="倒计时结束前,务必到达现场"
- android:textColor="@color/blue_5"
- android:textSize="@dimen/sp_12" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/hour"
- android:layout_width="@dimen/dp_30"
- android:layout_height="@dimen/dp_23"
- android:layout_marginStart="@dimen/dp_8"
- android:background="@drawable/shape_blue_5_bg_4"
- android:gravity="center"
- android:text="11"
- android:textColor="@color/white"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/colon1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_3"
- android:layout_marginTop="@dimen/dp_3"
- android:src="@mipmap/ic_task_item_colon_b" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/minutes"
- android:layout_width="@dimen/dp_30"
- android:layout_height="@dimen/dp_23"
- android:background="@drawable/shape_blue_5_bg_4"
- android:gravity="center"
- android:text="33"
- android:textColor="@color/white"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="@dimen/dp_3"
- android:id="@+id/colon2"
- android:layout_height="@dimen/dp_10"
- android:layout_marginHorizontal="@dimen/dp_3"
- android:layout_marginTop="@dimen/dp_3"
- android:src="@mipmap/ic_task_item_colon_b" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/second"
- android:layout_width="@dimen/dp_30"
- android:layout_height="@dimen/dp_23"
- android:background="@drawable/shape_blue_5_bg_4"
- android:gravity="center"
- android:text="09"
- android:textColor="@color/white"
- android:textSize="@dimen/sp_16"
- android:textStyle="bold" />
-
- </LinearLayout>
+ android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_16"
- android:layout_marginTop="@dimen/dp_20"
- android:gravity="center_vertical"
- android:orientation="horizontal">
+ android:layout_marginStart="@dimen/dp_4"
+ android:layout_marginTop="@dimen/dp_4"
+ android:background="@drawable/shape_white_bg_4"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/dp_16"
+ app:layout_constraintTop_toTopOf="parent">
+
+ <LinearLayout
+ android:id="@+id/countdownLayout"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_36"
+ android:background="@mipmap/img_task_item_top_bg_blue"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:paddingHorizontal="@dimen/dp_12">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/countdownTips"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:ellipsize="end"
+ android:gravity="end"
+ android:maxLines="1"
+ android:paddingEnd="@dimen/dp_8"
+ android:singleLine="true"
+ android:text="倒计时结束前,务必到达现场"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_12" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/hour"
+ android:layout_width="@dimen/dp_30"
+ android:layout_height="@dimen/dp_23"
+ android:layout_marginStart="@dimen/dp_8"
+ android:background="@drawable/shape_blue_5_bg_4"
+ android:gravity="center"
+ android:text="11"
+ android:textColor="@color/white"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/colon1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_3"
+ android:layout_marginTop="@dimen/dp_3"
+ android:src="@mipmap/ic_task_item_colon_b" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/minutes"
+ android:layout_width="@dimen/dp_30"
+ android:layout_height="@dimen/dp_23"
+ android:background="@drawable/shape_blue_5_bg_4"
+ android:gravity="center"
+ android:text="33"
+ android:textColor="@color/white"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/colon2"
+ android:layout_width="@dimen/dp_3"
+ android:layout_height="@dimen/dp_10"
+ android:layout_marginHorizontal="@dimen/dp_3"
+ android:layout_marginTop="@dimen/dp_3"
+ android:src="@mipmap/ic_task_item_colon_b" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/second"
+ android:layout_width="@dimen/dp_30"
+ android:layout_height="@dimen/dp_23"
+ android:background="@drawable/shape_blue_5_bg_4"
+ android:gravity="center"
+ android:text="09"
+ android:textColor="@color/white"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_16"
+ android:layout_marginTop="@dimen/dp_20"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/type"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_gray_7_r_4"
+ android:paddingHorizontal="@dimen/dp_8"
+ android:paddingVertical="@dimen/dp_3"
+ android:text="事故"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_14" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/plateNumber"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_8"
+ android:layout_weight="1"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:text="粤A 888WM试"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_18"
+ android:textStyle="bold" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_gray_3_bg_2"
+ android:paddingHorizontal="@dimen/dp_8"
+ android:paddingVertical="@dimen/dp_3"
+ android:text="待到达"
+ android:textColor="@color/gray_8"
+ android:textSize="@dimen/sp_12" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/iv_arrow"
+ android:layout_width="@dimen/dp_16"
+ android:layout_height="@dimen/dp_16"
+ android:layout_marginStart="@dimen/dp_4"
+ android:src="@mipmap/ic_task_item_arrow_right" />
+
+ </LinearLayout>
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/plateNumberFull"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_10"
+ android:text="粤A 888WM试"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_18"
+ android:textStyle="bold"
+ android:visibility="gone"
+ tools:visibility="visible" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_16"
+ android:layout_marginTop="@dimen/dp_16"
+ android:background="@mipmap/img_map"
+ android:minHeight="@dimen/dp_58"
+ android:orientation="horizontal">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/address"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="@dimen/dp_12"
+ android:layout_weight="1"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ tools:text="蜀山区华侨中心A座2301" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/nav"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|center_vertical"
+ android:layout_margin="@dimen/dp_12"
+ android:src="@drawable/svg_map_nav" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/ll_notice"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_16"
+ android:layout_marginTop="@dimen/dp_12"
+ android:gravity="center"
+ android:orientation="horizontal"
+ android:visibility="gone"
+ tools:visibility="visible">
+
+ <ImageView
+ android:layout_width="@dimen/dp_12"
+ android:layout_height="@dimen/dp_12"
+ android:src="@mipmap/ic_notice_blue" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_4"
+ android:text="系统暂未找到运营维护人员,请等待管理员处理"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_12" />
+ </LinearLayout>
<androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/type"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@drawable/shape_gray_7_r_4"
- android:paddingHorizontal="@dimen/dp_8"
- android:paddingVertical="@dimen/dp_3"
- android:text="事故"
- android:textColor="@color/gray_7"
+ android:id="@+id/tvControl"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_40"
+ android:layout_marginHorizontal="@dimen/dp_16"
+ android:layout_marginTop="@dimen/dp_16"
+ android:background="@drawable/shape_blue_5_bg_4"
+ android:gravity="center"
+ android:text="我已到达现场"
+ android:textColor="@color/white"
android:textSize="@dimen/sp_14" />
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/plateNumber"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_marginHorizontal="@dimen/dp_8"
- android:layout_weight="1"
- android:text="粤A 888WM试"
- android:textStyle="bold"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_18" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@drawable/shape_gray_3_bg_2"
- android:paddingHorizontal="@dimen/dp_8"
- android:paddingVertical="@dimen/dp_3"
- android:text="待到达"
- android:textColor="@color/gray_8"
- android:textSize="@dimen/sp_12" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="@dimen/dp_16"
- android:layout_height="@dimen/dp_16"
- android:layout_marginStart="@dimen/dp_4"
- android:src="@mipmap/ic_task_item_arrow_right" />
-
-
</LinearLayout>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="@dimen/dp_58"
- android:layout_marginHorizontal="@dimen/dp_16"
- android:layout_marginTop="@dimen/dp_16"
- android:orientation="horizontal"
- android:background="@mipmap/img_map">
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/level"
+ android:layout_width="@dimen/dp_33"
+ android:layout_height="@dimen/dp_24"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:src="@mipmap/ic_task_item_left_one" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/address"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginStart="@dimen/dp_12"
- tools:text="蜀山区华侨中心A座2301"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_14"
- android:textStyle="bold" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/nav"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="end|center_vertical"
- android:layout_margin="@dimen/dp_12"
- android:src="@drawable/svg_map_nav" />
-
- </LinearLayout>
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/tvControl"
- android:layout_width="match_parent"
- android:layout_height="@dimen/dp_40"
- android:layout_marginHorizontal="@dimen/dp_16"
- android:layout_marginTop="@dimen/dp_16"
- android:background="@drawable/shape_blue_5_bg_4"
- android:gravity="center"
- android:text="我已到达现场"
- android:textColor="@color/white"
- android:textSize="@dimen/sp_14" />
-
- </LinearLayout>
-
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/level"
- android:layout_width="@dimen/dp_33"
- android:layout_height="@dimen/dp_24"
- tools:src="@mipmap/ic_task_item_left_one"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
-
-
- </androidx.constraintlayout.widget.ConstraintLayout>
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tips"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/white"
+ android:gravity="center"
+ android:paddingVertical="@dimen/dp_10"
+ android:text="已加载全部任务"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:visibility="gone"
+ tools:visibility="visible" />
+ </FrameLayout>
</layout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_week_day.xml b/app/src/main/res/layout/item_week_day.xml
new file mode 100644
index 0000000..6af9d43
--- /dev/null
+++ b/app/src/main/res/layout/item_week_day.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="@dimen/dp_51"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_week"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:text="日"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_12" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tv_day"
+ android:layout_width="@dimen/dp_44"
+ android:layout_height="@dimen/dp_44"
+ android:layout_marginTop="@dimen/dp_12"
+ android:background="@drawable/selector_date_bg"
+ android:gravity="center"
+ android:textColor="@color/selector_grey9_to_white"
+ android:textSize="@dimen/sp_20"
+ android:textStyle="bold"
+ tools:text="18" />
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_work_car.xml b/app/src/main/res/layout/item_work_car.xml
index 1588ef9..7a4ec90 100644
--- a/app/src/main/res/layout/item_work_car.xml
+++ b/app/src/main/res/layout/item_work_car.xml
@@ -27,9 +27,9 @@
<com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/icon"
- android:layout_width="@dimen/dp_68"
- android:layout_height="@dimen/dp_32"
- android:layout_marginTop="@dimen/dp_12"
+ android:layout_width="@dimen/dp_78"
+ android:layout_height="@dimen/dp_36"
+ android:layout_marginTop="@dimen/dp_20"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:src="@mipmap/img_work_car"
@@ -42,14 +42,13 @@
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_7"
android:layout_marginTop="@dimen/dp_10"
android:layout_weight="1"
android:gravity="center"
android:maxLines="1"
android:text="粤A XV7029"
android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_10"
+ android:textSize="@dimen/sp_12"
android:textStyle="bold"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
@@ -67,7 +66,7 @@
android:maxLines="1"
android:text="NO.0088"
android:textColor="@color/gray_6"
- android:textSize="@dimen/sp_10"
+ android:textSize="@dimen/sp_12"
android:textStyle="bold"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
@@ -75,7 +74,7 @@
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="@dimen/dp_20"
+ android:layout_height="@dimen/dp_22"
android:layout_marginTop="@dimen/dp_4"
android:background="@mipmap/img_work_car_bg1"
android:gravity="center"
@@ -86,8 +85,8 @@
<com.xw.common.custom.BatteryView
android:id="@+id/batteryView"
- android:layout_width="@dimen/dp_23"
- android:layout_height="@dimen/dp_11"
+ android:layout_width="@dimen/dp_28"
+ android:layout_height="@dimen/dp_12"
app:batteryFrame="@mipmap/ic_battery"
app:batteryLevel="75"
app:showPercentage="false" />
@@ -96,11 +95,11 @@
android:id="@+id/batteryLife"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_4"
+ android:layout_marginStart="@dimen/dp_6"
android:maxLines="1"
android:text="543KM"
android:textColor="@color/green_5"
- android:textSize="@dimen/sp_8" />
+ android:textSize="@dimen/sp_11" />
</LinearLayout>
diff --git a/app/src/main/res/layout/item_work_site.xml b/app/src/main/res/layout/item_work_site.xml
index 713d1b7..2d9e3f7 100644
--- a/app/src/main/res/layout/item_work_site.xml
+++ b/app/src/main/res/layout/item_work_site.xml
@@ -1,123 +1,137 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
- <LinearLayout
- android:id="@+id/parent"
+ <FrameLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
+ android:layout_height="wrap_content">
- <androidx.constraintlayout.widget.ConstraintLayout
+ <LinearLayout
+ android:id="@+id/parent"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
- <com.makeramen.roundedimageview.RoundedImageView
- android:id="@+id/icon"
- android:layout_width="@dimen/dp_68"
- android:layout_height="@dimen/dp_92"
- android:layout_marginStart="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_8"
- android:adjustViewBounds="true"
- android:scaleType="centerCrop"
- android:src="@mipmap/img_site_bg"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:riv_corner_radius="@dimen/dp_5" />
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/name"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/dp_8"
- android:layout_marginEnd="@dimen/dp_20"
- android:maxLines="1"
- android:text="广州市白云机场T2航站楼"
- android:textColor="@color/gray_9"
- android:textSize="@dimen/sp_14"
- android:textStyle="bold"
- app:layout_constraintLeft_toRightOf="@+id/icon"
- app:layout_constraintRight_toLeftOf="@+id/nav"
- app:layout_constraintTop_toTopOf="@+id/icon" />
+ <com.makeramen.roundedimageview.RoundedImageView
+ android:id="@+id/icon"
+ android:layout_width="@dimen/dp_68"
+ android:layout_height="@dimen/dp_92"
+ android:layout_marginStart="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_8"
+ android:adjustViewBounds="true"
+ android:scaleType="centerCrop"
+ android:src="@drawable/img_site_bg"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:riv_corner_radius="@dimen/dp_5" />
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/address"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_4"
- android:layout_marginRight="@dimen/dp_20"
- android:maxLines="2"
- android:text="深圳市宝安区西大街阳光绿色温馨家园17号楼313"
- android:textColor="@color/gray_6"
- android:textSize="@dimen/sp_12"
- app:layout_constraintLeft_toLeftOf="@+id/name"
- app:layout_constraintRight_toLeftOf="@+id/nav"
- app:layout_constraintTop_toBottomOf="@+id/name" />
-
- <com.google.android.flexbox.FlexboxLayout
- android:id="@+id/tagLayout"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_gravity="right"
- android:layout_marginTop="@dimen/dp_4"
- app:flexWrap="wrap"
- app:justifyContent="flex_start"
- app:layout_constraintLeft_toLeftOf="@+id/name"
- app:layout_constraintRight_toLeftOf="@+id/arrow"
- app:layout_constraintTop_toBottomOf="@+id/address"
- app:showDivider="middle" />
-
- <androidx.appcompat.widget.AppCompatImageView
- android:id="@+id/arrow"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_8"
- android:src="@drawable/svg_arrow_r"
- app:layout_constraintTop_toBottomOf="@+id/address"
- app:layout_constraintRight_toRightOf="parent" />
-
- <LinearLayout
- android:id="@+id/nav"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/dp_8"
- android:layout_marginEnd="@dimen/dp_20"
- android:orientation="vertical"
- app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toTopOf="parent">
-
- <androidx.appcompat.widget.AppCompatImageView
- android:layout_width="@dimen/dp_20"
- android:layout_height="@dimen/dp_20"
- android:layout_gravity="end|center_vertical"
- android:src="@drawable/svg_map_nav" />
-
- <androidx.appcompat.widget.AppCompatTextView
+ <LinearLayout
+ android:id="@+id/nav"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="导航"
- android:textColor="@color/blue_5"
- android:textSize="@dimen/sp_10"
- app:layout_constraintRight_toRightOf="parent" />
+ android:layout_marginEnd="@dimen/dp_20"
+ android:gravity="center"
+ android:orientation="vertical"
+ app:layout_constraintTop_toTopOf="@id/icon"
+ app:layout_constraintEnd_toEndOf="parent">
- </LinearLayout>
+ <androidx.appcompat.widget.AppCompatImageView
+ android:layout_width="@dimen/dp_10"
+ android:layout_height="@dimen/dp_10"
+ android:src="@mipmap/icon_arrow_blue" />
- </androidx.constraintlayout.widget.ConstraintLayout>
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="去导航"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_12" />
+ </LinearLayout>
- <View
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/name"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_8"
+ android:layout_marginEnd="@dimen/dp_8"
+ android:maxLines="1"
+ android:text="广州市白云机场T2航站楼"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:textStyle="bold"
+ app:layout_constraintEnd_toStartOf="@id/nav"
+ app:layout_constraintStart_toEndOf="@+id/icon"
+ app:layout_constraintTop_toTopOf="@+id/icon" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/address"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_10"
+ android:maxLines="2"
+ android:text="深圳市宝安区西大街阳光绿色温馨家园17号楼313"
+ android:textColor="@color/gray_6"
+ android:textSize="@dimen/sp_12"
+ app:layout_constraintEnd_toEndOf="@id/name"
+ app:layout_constraintStart_toStartOf="@+id/name"
+ app:layout_constraintTop_toBottomOf="@+id/name" />
+
+ <com.google.android.flexbox.FlexboxLayout
+ android:id="@+id/tagLayout"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right"
+ android:layout_marginTop="@dimen/dp_4"
+ app:flexWrap="wrap"
+ app:justifyContent="flex_start"
+ app:layout_constraintLeft_toLeftOf="@+id/name"
+ app:layout_constraintRight_toLeftOf="@+id/arrow"
+ app:layout_constraintTop_toBottomOf="@+id/address"
+ app:showDivider="middle" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/arrow"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_8"
+ android:layout_marginEnd="@dimen/dp_20"
+ android:src="@drawable/svg_arrow_r"
+ android:visibility="gone"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/address" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginTop="@dimen/dp_8"
+ android:background="@color/gray_4"
+ app:layout_constraintBottom_toBottomOf="parent" />
+
+ </LinearLayout>
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tips"
android:layout_width="match_parent"
- android:layout_height="1px"
- android:layout_marginHorizontal="@dimen/dp_20"
- android:layout_marginTop="@dimen/dp_8"
- android:background="@color/gray_4"
- app:layout_constraintBottom_toBottomOf="parent" />
-
- </LinearLayout>
-
+ android:layout_height="wrap_content"
+ android:background="@color/white"
+ android:gravity="center"
+ android:paddingVertical="@dimen/dp_10"
+ android:text="已加载全部站点"
+ android:textColor="@color/gray_9"
+ android:textSize="@dimen/sp_14"
+ android:visibility="gone"
+ />
+ </FrameLayout>
</layout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/layout_car_repair_get.xml b/app/src/main/res/layout/layout_car_repair_get.xml
index 021f392..22595b6 100644
--- a/app/src/main/res/layout/layout_car_repair_get.xml
+++ b/app/src/main/res/layout/layout_car_repair_get.xml
@@ -35,8 +35,8 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_20"
- android:orientation="vertical"
android:background="@drawable/shape_gray_3_bg_4"
+ android:orientation="vertical"
android:padding="@dimen/dp_16"
app:layout_constraintTop_toTopOf="parent">
@@ -128,6 +128,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/dp_20"
+ android:drawableStart="@drawable/svg_must"
android:text="维修总费用"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16"
@@ -139,7 +140,8 @@
android:id="@+id/fees"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_56"
- android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginStart="@dimen/dp_28"
+ android:layout_marginEnd="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_4"
android:background="@null"
android:hint="请输入维修总费用"
@@ -164,7 +166,8 @@
<View
android:layout_width="match_parent"
android:layout_height="1px"
- android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginStart="@dimen/dp_28"
+ android:layout_marginEnd="@dimen/dp_20"
android:background="@color/gray_4"
app:layout_constraintTop_toBottomOf="@+id/fees" />
@@ -173,6 +176,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/dp_20"
+ android:drawableStart="@drawable/svg_must"
android:text="维修费用明细单"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16"
@@ -184,7 +188,7 @@
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_15"
+ android:layout_marginHorizontal="@dimen/dp_23"
android:layout_marginTop="@dimen/dp_10"
app:layout_constraintTop_toBottomOf="@+id/tv1" />
diff --git a/app/src/main/res/layout/layout_car_repair_send.xml b/app/src/main/res/layout/layout_car_repair_send.xml
index 02060fd..208c20b 100644
--- a/app/src/main/res/layout/layout_car_repair_send.xml
+++ b/app/src/main/res/layout/layout_car_repair_send.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools">
+ xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
@@ -34,6 +33,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/dp_20"
+ android:drawableStart="@drawable/svg_must"
android:text="预计维修停运时间"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16"
@@ -46,6 +46,7 @@
android:layout_width="match_parent"
android:layout_height="@dimen/dp_56"
android:layout_marginTop="@dimen/dp_4"
+ android:paddingHorizontal="@dimen/dp_8"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@+id/tv">
@@ -109,7 +110,7 @@
<View
android:layout_width="match_parent"
android:layout_height="1px"
- android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginHorizontal="@dimen/dp_28"
android:background="@color/gray_4"
app:layout_constraintTop_toBottomOf="@+id/timeLayout" />
@@ -118,6 +119,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_20"
+ android:drawableStart="@drawable/svg_must"
android:text="本次维修原因"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16"
@@ -125,48 +127,69 @@
app:layout_constraintLeft_toLeftOf="@+id/tv"
app:layout_constraintTop_toBottomOf="@+id/timeLayout" />
- <androidx.appcompat.widget.AppCompatEditText
- android:id="@+id/repairReason"
+ <FrameLayout
+ android:id="@+id/flRepairReason"
android:layout_width="match_parent"
- android:layout_height="@dimen/dp_120"
- android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/dp_28"
android:layout_marginTop="@dimen/dp_16"
- android:background="@drawable/shape_gray_3_bg_4"
- android:gravity="top"
- android:hint="请输入维修原因描述内容"
- android:maxLength="600"
- android:padding="@dimen/dp_12"
- android:text="@={viewModel.reason}"
- android:textColor="@color/gray_9"
- android:textColorHint="@color/gray_6"
- android:textSize="@dimen/sp_14"
- app:layout_constraintTop_toBottomOf="@+id/tv1" />
+ app:layout_constraintTop_toBottomOf="@+id/tv1">
+
+ <androidx.appcompat.widget.AppCompatEditText
+ android:id="@+id/repairReason"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dp_120"
+ android:background="@drawable/shape_gray_3_bg_4"
+ android:gravity="top"
+ android:hint="请输入维修原因描述内容"
+ android:maxLength="600"
+ android:paddingLeft="@dimen/dp_12"
+ android:paddingRight="@dimen/dp_12"
+ android:paddingTop="@dimen/dp_12"
+ android:paddingBottom="@dimen/dp_18"
+ android:text="@={viewModel.reason}"
+ android:textColor="@color/gray_9"
+ android:textColorHint="@color/gray_6"
+ android:textSize="@dimen/sp_14" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|end"
+ android:layout_marginEnd="@dimen/dp_12"
+ android:layout_marginBottom="@dimen/dp_2"
+ android:text='@{viewModel.reason.length()+"/600"}'
+ android:textColor="@color/gray_6"
+ android:textSize="@dimen/sp_11" />
+
+ </FrameLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
- android:layout_marginHorizontal="@dimen/dp_20"
+ android:layout_marginHorizontal="@dimen/dp_28"
android:layout_marginTop="@dimen/dp_16"
android:background="@color/gray_4"
- app:layout_constraintTop_toBottomOf="@+id/repairReason" />
+ app:layout_constraintTop_toBottomOf="@+id/flRepairReason" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_36"
+ android:drawableStart="@drawable/svg_must"
android:text="维修前图片"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16"
android:textStyle="bold"
app:layout_constraintLeft_toLeftOf="@+id/tv"
- app:layout_constraintTop_toBottomOf="@+id/repairReason" />
+ app:layout_constraintTop_toBottomOf="@+id/flRepairReason" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/dp_15"
+ android:layout_marginHorizontal="@dimen/dp_23"
android:layout_marginTop="@dimen/dp_16"
app:layout_constraintTop_toBottomOf="@+id/tv3">
diff --git a/app/src/main/res/layout/layout_infowindow.xml b/app/src/main/res/layout/layout_infowindow.xml
index 69ff84e..8fb136d 100644
--- a/app/src/main/res/layout/layout_infowindow.xml
+++ b/app/src/main/res/layout/layout_infowindow.xml
@@ -10,11 +10,10 @@
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingHorizontal="@dimen/dp_20"
- android:paddingVertical="@dimen/dp_6"
- android:textColor="@color/gray_9"
+ android:paddingHorizontal="@dimen/dp_12"
+ android:paddingVertical="@dimen/dp_4"
+ android:textColor="@color/color_838fa6"
android:textSize="@dimen/sp_12"
- android:textStyle="bold"
tools:text="点位名称" />
</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/layout_normal_task_car_charge.xml b/app/src/main/res/layout/layout_normal_task_car_charge.xml
index 5b125ab..3af86dc 100644
--- a/app/src/main/res/layout/layout_normal_task_car_charge.xml
+++ b/app/src/main/res/layout/layout_normal_task_car_charge.xml
@@ -82,7 +82,7 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="@color/gray_7"
- android:text='@{"开始时间:" + viewModel.chargeModel.startTime}'
+ android:text='@{"开始时间:" + viewModel.chargeModel.getShowStartTime()}'
android:textSize="@dimen/sp_12"
tools:text="开始时间:2026-09-31 11:00:09" />
diff --git a/app/src/main/res/layout/layout_normal_task_car_clear.xml b/app/src/main/res/layout/layout_normal_task_car_clear.xml
index 97a0b2b..6197a32 100644
--- a/app/src/main/res/layout/layout_normal_task_car_clear.xml
+++ b/app/src/main/res/layout/layout_normal_task_car_clear.xml
@@ -23,6 +23,7 @@
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:drawableStart="@drawable/svg_must"
android:text="车身标识及清洁"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16" />
@@ -31,6 +32,7 @@
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/dp_3"
android:layout_marginTop="@dimen/dp_5"
tools:layout_height="@dimen/dp_100" />
diff --git a/app/src/main/res/layout/layout_normal_task_car_clear_detail.xml b/app/src/main/res/layout/layout_normal_task_car_clear_detail.xml
index 46a8465..3ef3033 100644
--- a/app/src/main/res/layout/layout_normal_task_car_clear_detail.xml
+++ b/app/src/main/res/layout/layout_normal_task_car_clear_detail.xml
@@ -84,7 +84,7 @@
android:gravity="end"
android:maxLines="1"
android:singleLine="true"
- android:text="@{viewModel.taskDetail.handleTime}"
+ android:text="@{viewModel.taskDetail.getShowHandleTime()}"
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_14"
tools:text="2026-1-25 17:43:02" />
diff --git a/app/src/main/res/layout/layout_normal_task_car_nj_or_by_or_bx.xml b/app/src/main/res/layout/layout_normal_task_car_nj_or_by_or_bx.xml
index c647ff4..8e4eab1 100644
--- a/app/src/main/res/layout/layout_normal_task_car_nj_or_by_or_bx.xml
+++ b/app/src/main/res/layout/layout_normal_task_car_nj_or_by_or_bx.xml
@@ -23,27 +23,59 @@
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:drawableStart="@drawable/svg_must"
android:text="完成任务情况"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16" />
- <androidx.appcompat.widget.AppCompatEditText
+ <FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginVertical="@dimen/dp_8"
- android:background="@drawable/shape_f9f9f9_bg_4"
- android:gravity="top"
- android:hint="请录入完成任务情况说明"
- android:minHeight="@dimen/dp_100"
- android:text="@={viewModel.taskDescription}"
- android:padding="@dimen/dp_12"
- android:maxLength="600"
+ android:layout_marginTop="@dimen/dp_8"
+ android:layout_marginHorizontal="@dimen/dp_8">
+
+ <androidx.appcompat.widget.AppCompatEditText
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_f9f9f9_bg_4"
+ android:gravity="top"
+ android:hint="请录入完成任务情况说明"
+ android:maxLength="600"
+ android:minHeight="@dimen/dp_100"
+ android:paddingLeft="@dimen/dp_12"
+ android:paddingRight="@dimen/dp_12"
+ android:paddingTop="@dimen/dp_12"
+ android:paddingBottom="@dimen/dp_18"
+ android:text="@={viewModel.taskDescription}"
+ android:textColor="@color/gray_9"
+ android:textColorHint="@color/gray_6"
+ android:textSize="@dimen/sp_14" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|end"
+ android:layout_marginEnd="@dimen/dp_12"
+ android:layout_marginBottom="@dimen/dp_2"
+ android:text='@{viewModel.taskDescription.length()+"/600"}'
+ android:textColor="@color/gray_6"
+ android:textSize="@dimen/sp_11" />
+
+ </FrameLayout>
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:drawableStart="@drawable/svg_must"
+ android:layout_marginTop="@dimen/dp_8"
+ android:text="相关照片"
android:textColor="@color/gray_9"
- android:textColorHint="@color/gray_6"
- android:textSize="@dimen/sp_14" />
+ android:textSize="@dimen/sp_16" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
+ android:layout_marginTop="@dimen/dp_8"
+ android:layout_marginStart="@dimen/dp_3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:layout_height="@dimen/dp_100" />
diff --git a/app/src/main/res/layout/layout_normal_task_car_nj_or_by_or_bx_detail.xml b/app/src/main/res/layout/layout_normal_task_car_nj_or_by_or_bx_detail.xml
index 4be0241..1dfdb9f 100644
--- a/app/src/main/res/layout/layout_normal_task_car_nj_or_by_or_bx_detail.xml
+++ b/app/src/main/res/layout/layout_normal_task_car_nj_or_by_or_bx_detail.xml
@@ -84,7 +84,7 @@
android:gravity="end"
android:maxLines="1"
android:singleLine="true"
- android:text="@{viewModel.taskDetail.handleTime}"
+ android:text="@{viewModel.taskDetail.getShowHandleTime()}"
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_14"
tools:text="2026-1-25 17:43:02" />
diff --git a/app/src/main/res/layout/layout_normal_task_car_repair.xml b/app/src/main/res/layout/layout_normal_task_car_repair.xml
index 55a992b..c87959c 100644
--- a/app/src/main/res/layout/layout_normal_task_car_repair.xml
+++ b/app/src/main/res/layout/layout_normal_task_car_repair.xml
@@ -34,7 +34,7 @@
android:layout_marginHorizontal="@dimen/dp_8"
android:layout_weight="1"
tools:text="送修时间:2026-2-6 16:35:56"
- android:text='@{"送修时间:" + viewModel.repairModel.sendTime}'
+ android:text='@{"送修时间:" + viewModel.repairModel.getShowSendTime()}'
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_14" />
diff --git a/app/src/main/res/layout/layout_normal_task_car_repair_detail.xml b/app/src/main/res/layout/layout_normal_task_car_repair_detail.xml
index 8ee7e76..5e8f9cf 100644
--- a/app/src/main/res/layout/layout_normal_task_car_repair_detail.xml
+++ b/app/src/main/res/layout/layout_normal_task_car_repair_detail.xml
@@ -31,7 +31,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_10"
tools:text="2026年 xxxxxxxxx - 2026年 xxxxxxxxx"
- android:text='@{viewModel.repairModel.startTime + " - " + viewModel.repairModel.endTime}'
+ android:text='@{viewModel.repairModel.getShowStartTime() + " - " + viewModel.repairModel.getShowEndTime()}'
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_14" />
@@ -91,7 +91,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_15"
- android:text="送检时间"
+ android:text="送修时间"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_16"
android:textStyle="bold" />
@@ -101,7 +101,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_10"
tools:text="2026年 xxxxx"
- android:text="@{viewModel.repairModel.sendTime}"
+ android:text="@{viewModel.repairModel.getShowSendTime()}"
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_14" />
@@ -200,7 +200,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_10"
tools:text="2026年 xxxxx"
- android:text="@{viewModel.repairModel.returnTime}"
+ android:text="@{viewModel.repairModel.getShowReturnTime()}"
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_14" />
diff --git a/app/src/main/res/layout/layout_normal_task_charge_detail.xml b/app/src/main/res/layout/layout_normal_task_charge_detail.xml
index 142611e..8faea01 100644
--- a/app/src/main/res/layout/layout_normal_task_charge_detail.xml
+++ b/app/src/main/res/layout/layout_normal_task_charge_detail.xml
@@ -92,8 +92,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
- tools:text="开始时间:2026-09-09 11:09:09"
- android:text='@{"开始时间:" + viewModel.chargeModel.startTime}'
+ tools:text="2026-09-09 11:09:09"
+ android:text='@{viewModel.chargeModel.getShowStartTime()}'
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_12" />
@@ -186,8 +186,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
- android:text='@{"结束时间:" + viewModel.chargeModel.endTime}'
- tools:text="结束时间:2026-09-09 11:09:09"
+ android:text='@{viewModel.chargeModel.getShowEndTime()}'
+ tools:text="2026-09-09 11:09:09"
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_12" />
diff --git a/app/src/main/res/layout/layout_normal_task_check_detail.xml b/app/src/main/res/layout/layout_normal_task_check_detail.xml
index a8c5e3a..8c700f0 100644
--- a/app/src/main/res/layout/layout_normal_task_check_detail.xml
+++ b/app/src/main/res/layout/layout_normal_task_check_detail.xml
@@ -82,7 +82,7 @@
android:gravity="end"
android:maxLines="1"
android:singleLine="true"
- android:text="@{viewModel.checkModel.checkTime}"
+ android:text="@{viewModel.checkModel.getShowCheckTime()}"
tools:text="2026-2-5 17:47:08"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_14" />
@@ -396,7 +396,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_8"
- android:text="传感器清洁:"
+ android:text="外观和轮胎:"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_12" />
@@ -416,7 +416,7 @@
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="车内交互屏检查:"
+ android:text="车内大屏:"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_12" />
@@ -436,7 +436,7 @@
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="紧急求救按钮/应答机:"
+ android:text="舱内外清洁:"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_12" />
@@ -458,6 +458,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="支付功能:"
+ android:visibility="gone"
+ tools:visibility="visible"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_12" />
@@ -465,19 +467,23 @@
android:id="@+id/rv4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:visibility="gone"
+ tools:visibility="visible"
android:layout_marginTop="@dimen/dp_5"
tools:layout_height="@dimen/dp_50" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
+ android:visibility="gone"
+ tools:visibility="visible"
android:layout_marginVertical="@dimen/dp_12"
android:background="@color/gray_4" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="订单系统检查:"
+ android:text="随车安全设备:"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_12" />
diff --git a/app/src/main/res/layout/layout_normal_task_maintain_detail.xml b/app/src/main/res/layout/layout_normal_task_maintain_detail.xml
index 5301d32..1aeedb7 100644
--- a/app/src/main/res/layout/layout_normal_task_maintain_detail.xml
+++ b/app/src/main/res/layout/layout_normal_task_maintain_detail.xml
@@ -391,7 +391,7 @@
android:gravity="end"
android:maxLines="1"
android:singleLine="true"
- android:text="@{viewModel.maintainModel.operationsTime}"
+ android:text="@{viewModel.maintainModel.getShowOperationsTime()}"
tools:text="2026-2-5 17:47:08"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_14" />
diff --git a/app/src/main/res/layout/layout_normal_task_status1.xml b/app/src/main/res/layout/layout_normal_task_status1.xml
index 2c1c8d3..3eac677 100644
--- a/app/src/main/res/layout/layout_normal_task_status1.xml
+++ b/app/src/main/res/layout/layout_normal_task_status1.xml
@@ -70,7 +70,7 @@
android:layout_marginStart="@dimen/dp_8"
android:paddingVertical="@dimen/dp_4"
android:paddingHorizontal="@dimen/dp_8"
- android:text='@{"车身编码:" + viewModel.taskDetail.vehicleCode}'
+ android:text='@{"车身编码:" + viewModel.taskDetail.getShowVehicleCode(6)}'
android:background="@drawable/shape_gray_3_bg_4"
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_12"
@@ -106,6 +106,20 @@
android:src="@drawable/svg_map_nav" />
</LinearLayout>
+
+ <TextView
+ android:id="@+id/tv_notice"
+ show='@{viewModel.carLocation.tips != "" && viewModel.carLocation.tips != null}'
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_4"
+ android:text="@{viewModel.carLocation.tips}"
+ android:textColor="@color/red_5"
+ android:textSize="@dimen/sp_12"
+ android:visibility="gone"
+ app:layout_constraintStart_toStartOf="@id/et_input"
+ app:layout_constraintTop_toBottomOf="@id/et_input"
+ tools:visibility="visible" />
<!--车辆信息-->
<LinearLayout
@@ -164,7 +178,7 @@
android:layout_marginStart="@dimen/dp_16"
android:layout_weight="1"
android:gravity="end"
- android:text="@{viewModel.taskDetail.vehicleLocation}"
+ android:text="@{viewModel.carLocation.address}"
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_14"
tools:text="深圳市南山区南大街龙葵小区7栋1701" />
@@ -224,7 +238,7 @@
android:gravity="end"
android:maxLines="1"
android:singleLine="true"
- android:text="@{viewModel.taskDetail.createTime}"
+ android:text="@{viewModel.taskDetail.getShowCreateTime()}"
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_14"
tools:text="2026-1-25 17:43:02" />
@@ -356,7 +370,7 @@
tools:visibility="gone"
android:layout_marginTop="@dimen/dp_12"
show='@{viewModel.taskDetail.taskTypeId.equals("4")}'
- android:background="@drawable/shape_0f06b752_bg_4"
+ android:background="@drawable/shape_0f006be1_bg_4"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="@dimen/dp_12"
@@ -365,14 +379,14 @@
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="@dimen/dp_16"
android:layout_height="@dimen/dp_16"
- android:src="@mipmap/ic_task_xc" />
+ android:src="@mipmap/ic_task_xc1" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_10"
android:text="洗车"
- android:textColor="#ff06B752"
+ android:textColor="@color/blue_5"
android:textSize="@dimen/sp_14" />
</LinearLayout>
diff --git a/app/src/main/res/layout/layout_normal_task_status2.xml b/app/src/main/res/layout/layout_normal_task_status2.xml
index cf2f3f3..07f0ca5 100644
--- a/app/src/main/res/layout/layout_normal_task_status2.xml
+++ b/app/src/main/res/layout/layout_normal_task_status2.xml
@@ -65,7 +65,7 @@
android:paddingHorizontal="@dimen/dp_8"
android:paddingVertical="@dimen/dp_4"
android:background="@drawable/shape_gray_3_bg_4"
- android:text='@{"车身编码:" + viewModel.taskDetail.vehicleCode}'
+ android:text='@{"车身编码:" + viewModel.taskDetail.getShowVehicleCode(6)}'
android:textColor="@color/gray_9"
android:textSize="@dimen/sp_12"
tools:text="车身编码:01234" />
@@ -162,7 +162,7 @@
android:gravity="end"
android:maxLines="1"
android:singleLine="true"
- android:text="@{viewModel.taskDetail.createTime}"
+ android:text="@{viewModel.taskDetail.getShowCreateTime()}"
android:textColor="@color/gray_7"
android:textSize="@dimen/sp_14"
tools:text="2026-1-25 17:43:02" />
diff --git a/app/src/main/res/mipmap-hdpi/caricon.png b/app/src/main/res/mipmap-hdpi/caricon.png
new file mode 100644
index 0000000..8fb09fd
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/caricon.png
Binary files differ
diff --git a/app/src/main/res/mipmap-hdpi/icon_map_arrow_blue.png b/app/src/main/res/mipmap-hdpi/icon_map_arrow_blue.png
new file mode 100644
index 0000000..e0cceb3
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/icon_map_arrow_blue.png
Binary files differ
diff --git a/app/src/main/res/mipmap-hdpi/navi_direction.png b/app/src/main/res/mipmap-hdpi/navi_direction.png
new file mode 100644
index 0000000..2041128
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/navi_direction.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_accident_one.png b/app/src/main/res/mipmap-xhdpi/ic_accident_one.png
index ccb33e0..9944e20 100644
--- a/app/src/main/res/mipmap-xhdpi/ic_accident_one.png
+++ b/app/src/main/res/mipmap-xhdpi/ic_accident_one.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_accident_three.png b/app/src/main/res/mipmap-xhdpi/ic_accident_three.png
index f1f8235..1fd676d 100644
--- a/app/src/main/res/mipmap-xhdpi/ic_accident_three.png
+++ b/app/src/main/res/mipmap-xhdpi/ic_accident_three.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_accident_two.png b/app/src/main/res/mipmap-xhdpi/ic_accident_two.png
index 5adb0e1..90d28d3 100644
--- a/app/src/main/res/mipmap-xhdpi/ic_accident_two.png
+++ b/app/src/main/res/mipmap-xhdpi/ic_accident_two.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_add_picture.png b/app/src/main/res/mipmap-xhdpi/ic_add_picture.png
new file mode 100644
index 0000000..0d2fc2f
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_add_picture.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_apply_reassign_bg.png b/app/src/main/res/mipmap-xhdpi/ic_apply_reassign_bg.png
new file mode 100644
index 0000000..639314d
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_apply_reassign_bg.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_bicycle_blue.png b/app/src/main/res/mipmap-xhdpi/ic_bicycle_blue.png
new file mode 100644
index 0000000..b032e9b
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_bicycle_blue.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_bicycle_gray.png b/app/src/main/res/mipmap-xhdpi/ic_bicycle_gray.png
new file mode 100644
index 0000000..cda996f
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_bicycle_gray.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_clock_note.png b/app/src/main/res/mipmap-xhdpi/ic_clock_note.png
new file mode 100644
index 0000000..d6669d1
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_clock_note.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_close_black.png b/app/src/main/res/mipmap-xhdpi/ic_close_black.png
new file mode 100644
index 0000000..c575653
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_close_black.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_close_black2.png b/app/src/main/res/mipmap-xhdpi/ic_close_black2.png
new file mode 100644
index 0000000..e92f412
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_close_black2.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_cup_book.png b/app/src/main/res/mipmap-xhdpi/ic_cup_book.png
new file mode 100644
index 0000000..0284ea4
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_cup_book.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_down.png b/app/src/main/res/mipmap-xhdpi/ic_down.png
new file mode 100644
index 0000000..9b7a42e
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_down.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_end_point.png b/app/src/main/res/mipmap-xhdpi/ic_end_point.png
new file mode 100644
index 0000000..d72a770
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_end_point.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_filter_task2.png b/app/src/main/res/mipmap-xhdpi/ic_filter_task2.png
new file mode 100644
index 0000000..bc3a7e6
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_filter_task2.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_map_car_g.png b/app/src/main/res/mipmap-xhdpi/ic_map_car_g.png
deleted file mode 100644
index 6d6e745..0000000
--- a/app/src/main/res/mipmap-xhdpi/ic_map_car_g.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_map_car_r.png b/app/src/main/res/mipmap-xhdpi/ic_map_car_r.png
deleted file mode 100644
index 5881aab..0000000
--- a/app/src/main/res/mipmap-xhdpi/ic_map_car_r.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_map_site_g.png b/app/src/main/res/mipmap-xhdpi/ic_map_site_g.png
deleted file mode 100644
index 7147897..0000000
--- a/app/src/main/res/mipmap-xhdpi/ic_map_site_g.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_map_site_r.png b/app/src/main/res/mipmap-xhdpi/ic_map_site_r.png
deleted file mode 100644
index d3cab8b..0000000
--- a/app/src/main/res/mipmap-xhdpi/ic_map_site_r.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_notice_blue.png b/app/src/main/res/mipmap-xhdpi/ic_notice_blue.png
new file mode 100644
index 0000000..c02e831
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_notice_blue.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_pass_point.png b/app/src/main/res/mipmap-xhdpi/ic_pass_point.png
new file mode 100644
index 0000000..d6442eb
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_pass_point.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_route_arrow.png b/app/src/main/res/mipmap-xhdpi/ic_route_arrow.png
new file mode 100644
index 0000000..adf210f
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_route_arrow.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_route_arrow_close.png b/app/src/main/res/mipmap-xhdpi/ic_route_arrow_close.png
new file mode 100644
index 0000000..2ea7228
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_route_arrow_close.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_start_point.png b/app/src/main/res/mipmap-xhdpi/ic_start_point.png
new file mode 100644
index 0000000..a1943ac
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_start_point.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_task_item_left_one.png b/app/src/main/res/mipmap-xhdpi/ic_task_item_left_one.png
index 5eec75c..e18bb72 100644
--- a/app/src/main/res/mipmap-xhdpi/ic_task_item_left_one.png
+++ b/app/src/main/res/mipmap-xhdpi/ic_task_item_left_one.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_task_item_left_three.png b/app/src/main/res/mipmap-xhdpi/ic_task_item_left_three.png
index 25161a2..224f9e9 100644
--- a/app/src/main/res/mipmap-xhdpi/ic_task_item_left_three.png
+++ b/app/src/main/res/mipmap-xhdpi/ic_task_item_left_three.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_task_item_left_two.png b/app/src/main/res/mipmap-xhdpi/ic_task_item_left_two.png
index 2476c8c..f7790b0 100644
--- a/app/src/main/res/mipmap-xhdpi/ic_task_item_left_two.png
+++ b/app/src/main/res/mipmap-xhdpi/ic_task_item_left_two.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_tick_green.png b/app/src/main/res/mipmap-xhdpi/ic_tick_green.png
new file mode 100644
index 0000000..7f41ef8
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_tick_green.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_up.png b/app/src/main/res/mipmap-xhdpi/ic_up.png
new file mode 100644
index 0000000..0ca32ac
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_up.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_walk_blue.png b/app/src/main/res/mipmap-xhdpi/ic_walk_blue.png
new file mode 100644
index 0000000..8f39c83
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_walk_blue.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_walk_gray.png b/app/src/main/res/mipmap-xhdpi/ic_walk_gray.png
new file mode 100644
index 0000000..eed3eb6
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_walk_gray.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_work_quche.png b/app/src/main/res/mipmap-xhdpi/ic_work_quche.png
index 92d24b8..bff0b39 100644
--- a/app/src/main/res/mipmap-xhdpi/ic_work_quche.png
+++ b/app/src/main/res/mipmap-xhdpi/ic_work_quche.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_arrow_blue.png b/app/src/main/res/mipmap-xhdpi/icon_arrow_blue.png
new file mode 100644
index 0000000..f41d38c
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_arrow_blue.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_arrow_left_blue.png b/app/src/main/res/mipmap-xhdpi/icon_arrow_left_blue.png
new file mode 100644
index 0000000..9ad8cf6
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_arrow_left_blue.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_car_charge.png b/app/src/main/res/mipmap-xhdpi/icon_car_charge.png
new file mode 100644
index 0000000..3667373
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_car_charge.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_car_exception.png b/app/src/main/res/mipmap-xhdpi/icon_car_exception.png
new file mode 100644
index 0000000..1c3d34a
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_car_exception.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_car_order.png b/app/src/main/res/mipmap-xhdpi/icon_car_order.png
new file mode 100644
index 0000000..6b3f6ee
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_car_order.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_car_running.png b/app/src/main/res/mipmap-xhdpi/icon_car_running.png
new file mode 100644
index 0000000..36f43af
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_car_running.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_car_stop_order.png b/app/src/main/res/mipmap-xhdpi/icon_car_stop_order.png
new file mode 100644
index 0000000..11cb810
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_car_stop_order.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_car_working.png b/app/src/main/res/mipmap-xhdpi/icon_car_working.png
new file mode 100644
index 0000000..5166dcf
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_car_working.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_circle_gray.png b/app/src/main/res/mipmap-xhdpi/icon_circle_gray.png
new file mode 100644
index 0000000..ddb02e8
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_circle_gray.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_circle_gray2.png b/app/src/main/res/mipmap-xhdpi/icon_circle_gray2.png
new file mode 100644
index 0000000..9a2219f
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_circle_gray2.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_circle_line_black.png b/app/src/main/res/mipmap-xhdpi/icon_circle_line_black.png
new file mode 100644
index 0000000..f5f3b7c
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_circle_line_black.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_circle_ring_blue.png b/app/src/main/res/mipmap-xhdpi/icon_circle_ring_blue.png
new file mode 100644
index 0000000..17e0690
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_circle_ring_blue.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_clock_blue.png b/app/src/main/res/mipmap-xhdpi/icon_clock_blue.png
new file mode 100644
index 0000000..fc728e5
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_clock_blue.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_clock_blue2.png b/app/src/main/res/mipmap-xhdpi/icon_clock_blue2.png
new file mode 100644
index 0000000..a3aa29a
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_clock_blue2.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_close2.png b/app/src/main/res/mipmap-xhdpi/icon_close2.png
new file mode 100644
index 0000000..e92f412
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_close2.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_close_gray.png b/app/src/main/res/mipmap-xhdpi/icon_close_gray.png
new file mode 100644
index 0000000..a8c05c7
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_close_gray.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_close_red.png b/app/src/main/res/mipmap-xhdpi/icon_close_red.png
new file mode 100644
index 0000000..50a1078
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_close_red.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_date_empty.png b/app/src/main/res/mipmap-xhdpi/icon_date_empty.png
new file mode 100644
index 0000000..690a9c5
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_date_empty.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_location_blue.png b/app/src/main/res/mipmap-xhdpi/icon_location_blue.png
new file mode 100644
index 0000000..51764f5
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_location_blue.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_location_green.png b/app/src/main/res/mipmap-xhdpi/icon_location_green.png
new file mode 100644
index 0000000..a29f986
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_location_green.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_map_arrow_blue.png b/app/src/main/res/mipmap-xhdpi/icon_map_arrow_blue.png
new file mode 100644
index 0000000..7ab0c14
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_map_arrow_blue.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_note.png b/app/src/main/res/mipmap-xhdpi/icon_note.png
new file mode 100644
index 0000000..52520d6
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_note.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_note_tick_circle.png b/app/src/main/res/mipmap-xhdpi/icon_note_tick_circle.png
new file mode 100644
index 0000000..1452658
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_note_tick_circle.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_note_tick_circle2.png b/app/src/main/res/mipmap-xhdpi/icon_note_tick_circle2.png
new file mode 100644
index 0000000..9791a1a
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_note_tick_circle2.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_note_triangle.png b/app/src/main/res/mipmap-xhdpi/icon_note_triangle.png
new file mode 100644
index 0000000..70a564c
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_note_triangle.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_note_triangle2.png b/app/src/main/res/mipmap-xhdpi/icon_note_triangle2.png
new file mode 100644
index 0000000..3812a5b
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_note_triangle2.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_ring_blue.png b/app/src/main/res/mipmap-xhdpi/icon_ring_blue.png
new file mode 100644
index 0000000..cc365d2
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_ring_blue.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_switch_off.png b/app/src/main/res/mipmap-xhdpi/icon_switch_off.png
new file mode 100644
index 0000000..b79038a
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_switch_off.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_switch_on.png b/app/src/main/res/mipmap-xhdpi/icon_switch_on.png
new file mode 100644
index 0000000..59e74c5
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_switch_on.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_tick_circle_blue.png b/app/src/main/res/mipmap-xhdpi/icon_tick_circle_blue.png
new file mode 100644
index 0000000..1306d47
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_tick_circle_blue.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_tick_double_rect.png b/app/src/main/res/mipmap-xhdpi/icon_tick_double_rect.png
new file mode 100644
index 0000000..9246dce
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_tick_double_rect.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_tick_double_rect2.png b/app/src/main/res/mipmap-xhdpi/icon_tick_double_rect2.png
new file mode 100644
index 0000000..4e45648
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_tick_double_rect2.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_tick_green.png b/app/src/main/res/mipmap-xhdpi/icon_tick_green.png
new file mode 100644
index 0000000..c15df68
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_tick_green.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/icon_warn_red.png b/app/src/main/res/mipmap-xhdpi/icon_warn_red.png
new file mode 100644
index 0000000..baad052
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_warn_red.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/img_clock_out_s.png b/app/src/main/res/mipmap-xhdpi/img_clock_out_s.png
index 1a23f04..b7c623a 100644
--- a/app/src/main/res/mipmap-xhdpi/img_clock_out_s.png
+++ b/app/src/main/res/mipmap-xhdpi/img_clock_out_s.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/img_site_bg.png b/app/src/main/res/mipmap-xhdpi/img_site_bg.png
deleted file mode 100644
index 0c3c0e6..0000000
--- a/app/src/main/res/mipmap-xhdpi/img_site_bg.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/img_work_car.png b/app/src/main/res/mipmap-xhdpi/img_work_car.png
index 47e5a3b..78060e8 100644
--- a/app/src/main/res/mipmap-xhdpi/img_work_car.png
+++ b/app/src/main/res/mipmap-xhdpi/img_work_car.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/img_work_car_bg.png b/app/src/main/res/mipmap-xhdpi/img_work_car_bg.png
index a06274b..ac33e05 100644
--- a/app/src/main/res/mipmap-xhdpi/img_work_car_bg.png
+++ b/app/src/main/res/mipmap-xhdpi/img_work_car_bg.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/img_work_map.png b/app/src/main/res/mipmap-xhdpi/img_work_map.png
index 0dec765..8b1dd39 100644
--- a/app/src/main/res/mipmap-xhdpi/img_work_map.png
+++ b/app/src/main/res/mipmap-xhdpi/img_work_map.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/img_work_report.png b/app/src/main/res/mipmap-xhdpi/img_work_report.png
index e47eda3..b87a041 100644
--- a/app/src/main/res/mipmap-xhdpi/img_work_report.png
+++ b/app/src/main/res/mipmap-xhdpi/img_work_report.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_map_car_g.png b/app/src/main/res/mipmap-xxhdpi/ic_map_car_g.png
new file mode 100644
index 0000000..80499db
--- /dev/null
+++ b/app/src/main/res/mipmap-xxhdpi/ic_map_car_g.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_map_car_r.png b/app/src/main/res/mipmap-xxhdpi/ic_map_car_r.png
new file mode 100644
index 0000000..8720389
--- /dev/null
+++ b/app/src/main/res/mipmap-xxhdpi/ic_map_car_r.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_map_site_g.png b/app/src/main/res/mipmap-xxhdpi/ic_map_site_g.png
new file mode 100644
index 0000000..ab33fa9
--- /dev/null
+++ b/app/src/main/res/mipmap-xxhdpi/ic_map_site_g.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_map_site_r.png b/app/src/main/res/mipmap-xxhdpi/ic_map_site_r.png
new file mode 100644
index 0000000..fcc0bfa
--- /dev/null
+++ b/app/src/main/res/mipmap-xxhdpi/ic_map_site_r.png
Binary files differ
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..116bbf8
--- /dev/null
+++ b/app/src/main/res/values/attrs.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <declare-styleable name="CircularProgressView">
+ <!-- 环宽度 -->
+ <attr name="ringWidth" format="dimension" />
+
+ <!-- 背景环颜色 -->
+ <attr name="backgroundProgressColor" format="color" />
+
+ <!-- 进度环颜色 -->
+ <attr name="progressColor" format="color" />
+
+ <!-- 进度圆角风格 -->
+ <attr name="progressRoundStyle" format="boolean" />
+
+ <!-- 当前进度 -->
+ <attr name="progress" format="float" />
+
+ <!-- 最大进度 -->
+ <attr name="maxProgress" format="float" />
+ </declare-styleable>
+ <declare-styleable name="LineView">
+ <!--虚线长度-->
+ <attr name="dashLineSize" format="dimension" />
+ <!--虚线厚度-->
+ <attr name="dashLineStroke" format="dimension" />
+ <!--间隔-->
+ <attr name="lineInterval" format="dimension" />
+ <!--线颜色-->
+ <attr name="lineColor" format="color" />
+ <!--是否启用虚线-->
+ <attr name="dashLineEnable" format="boolean" />
+ </declare-styleable>
+ <declare-styleable name="WatermarkView">
+ <attr name="watermarkText" format="string" />
+ <attr name="textColor" format="color" />
+ <attr name="textSize" format="dimension" />
+ <attr name="watermarkTextRotation" format="float" />
+ <attr name="spacingX" format="dimension" />
+ <attr name="spacingY" format="dimension" />
+ <attr name="isStaggered" format="boolean" />
+ </declare-styleable>
+ <declare-styleable name="ClearEditText">
+ <!-- 清除按钮图标 -->
+ <attr name="clearIcon" format="reference" />
+ <!-- 图标宽度 -->
+ <attr name="iconWidth" format="dimension" />
+ <!-- 图标高度 -->
+ <attr name="iconHeight" format="dimension" />
+ <!-- 图标距离右边的距离 -->
+ <attr name="iconMarginRight" format="dimension" />
+ <!-- 图标距离顶部的偏移(用于垂直居中微调) -->
+ <attr name="iconMarginTop" format="dimension" />
+ <!-- 是否显示清除按钮(默认true) -->
+ <attr name="showClearIcon" format="boolean" />
+ <!-- 图标着色(可选) -->
+ <attr name="iconTint" format="color|reference" />
+ </declare-styleable>
+</resources>
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index f8c6127..383e97a 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -7,4 +7,25 @@
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
+ <color name="color_3d3d3d">#FF3D3D3D</color>
+ <color name="color_f8f9fa">#FFF8F9FA</color>
+ <color name="color_f8e4e1">#FFF8E4E1</color>
+ <color name="color_cc31456A">#cc31456A</color>
+ <color name="color_fdedeb">#FDEDEB</color>
+ <color name="color_d9d9d9">#d9d9d9</color>
+ <color name="color_0f31456a">#0f31456A</color>
+ <color name="color_1a026ee4">#1a026EE4</color>
+ <color name="color_00c25c">#00c25c</color>
+ <color name="color_80ffffff">#80ffffff</color>
+ <color name="color_ccffffff">#ccffffff</color>
+ <color name="color_5931456a">#5931456a</color>
+ <color name="color_4c5e7e">#4C5E7E</color>
+ <color name="color_dcdcdc">#DCDCDC</color>
+ <color name="color_0d31456a">#0d31456a</color>
+ <color name="color_0031456a">#0031456A</color>
+ <color name="color_00006be1">#00006be1</color>
+ <color name="color_e5f0fc">#e5f0fc</color>
+ <color name="color_0256ff">#0256ff</color>
+ <color name="color_ec5340">#ec5340</color>
+ <color name="color_e0ebf7">#e0ebf7</color>
</resources>
\ No newline at end of file
diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml
index dca93c0..78814d2 100644
--- a/app/src/main/res/xml/network_security_config.xml
+++ b/app/src/main/res/xml/network_security_config.xml
@@ -1,4 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
-</network-security-config>
\ No newline at end of file
+
+ <!-- 仅 debug 构建生效:信任用户安装的 CA(Proxyman/Charles 抓包用),release 不受影响 -->
+ <debug-overrides>
+ <trust-anchors>
+ <certificates src="system" />
+ <certificates src="user" />
+ </trust-anchors>
+ </debug-overrides>
+</network-security-config>
diff --git a/common/build.gradle.kts b/common/build.gradle.kts
index 222e83f..e3305a8 100644
--- a/common/build.gradle.kts
+++ b/common/build.gradle.kts
@@ -60,6 +60,7 @@
api(libs.kotlinx.coroutines.core)
api(libs.kotlinx.coroutines.android)
api(libs.okhttp)
+ api(libs.okhttp.logging.interceptor)
api(libs.retrofit)
api(libs.retrofit.converter.gson)
api(libs.retrofit.converter.scalars)
@@ -77,7 +78,7 @@
api(libs.dialog.bottomsheets)
api(libs.image.circle)
api(libs.image.rounde)
- api(libs.xdmap.location.search)
+ api(libs.navi.xdmap.location.search)
api(libs.mmkv)
api(libs.eventbus)
api(libs.dialog.ios.style)
diff --git a/common/src/main/java/com/xw/common/CommonDialog.kt b/common/src/main/java/com/xw/common/CommonDialog.kt
index 37288aa..0faf366 100644
--- a/common/src/main/java/com/xw/common/CommonDialog.kt
+++ b/common/src/main/java/com/xw/common/CommonDialog.kt
@@ -1,40 +1,85 @@
package com.xw.common
import android.content.Context
+import android.graphics.Color
import android.os.Handler
import android.os.Looper
+import android.text.method.LinkMovementMethod
+import android.util.TypedValue
import android.view.Gravity
-import android.view.ViewGroup
-import android.view.WindowManager
import android.widget.Button
import androidx.appcompat.widget.AppCompatTextView
+import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil
import com.afollestad.materialdialogs.LayoutMode
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.bottomsheets.BottomSheet
+import com.afollestad.materialdialogs.callbacks.onDismiss
import com.afollestad.materialdialogs.customview.customView
import com.afollestad.materialdialogs.customview.getCustomView
+import com.hjq.permissions.Permission
+import com.hjq.permissions.XXPermissions
import com.xw.common.databinding.DialogShowSelectBinding
+import java.util.WeakHashMap
object CommonDialog {
+ fun showLocationNotGrantedTipsDialog(context: Context) {
+ /*
+ CommonDialog.showSingleTipsDialog(
+ context,
+ "您未开启gps权限,无法获取当前定位,请打开后重新操作",
+ null
+ )
+ */
+
+ // CommonDialog.showCommonTipsDialog(
+ CommonDialog.showSingleTipsDialog(
+ context = context,
+ content = "您未开启gps权限,无法获取当前定位,请打开后重新操作", // "定位权限已被拒绝,将无法获取当前位置,请前往系统设置开启定位权限。",
+ leftText = "取消",
+ rightText = "去设置",
+ // leftBlock = { dialog -> dialog.dismiss() },
+ rightBlock = { dialog ->
+ // 跳转到当前应用的权限设置页
+ XXPermissions.startPermissionActivity(
+ context,
+ arrayOf(Permission.ACCESS_FINE_LOCATION, Permission.ACCESS_COARSE_LOCATION)
+ )
+ true
+ }
+ )
+ }
+
+ // 记录每个页面(Context)当前正在展示的"单例"提示弹窗,避免同一界面重复弹出相同弹窗。
+ // 用 WeakHashMap 以 Context 为 key,Activity 销毁后可被回收,不会内存泄漏。
+ private val singleTipsDialogMap = WeakHashMap<Context, MaterialDialog>()
+
/**
- * 通用提示弹窗
+ * 单例提示弹窗:同一个 Activity(Context) 内若已弹出且尚未取消,则不再重复弹出。
+ *
+ * 适用于定位/GPS 等可能被多处回调(多次 onLocationChanged 等)同时触发、
+ * 导致同一界面叠加出多个相同提示弹窗的场景。
+ *
* @param content 内容
* @param leftBlock 回调事件 返回true dismiss
* @param rightBlock 回调事件 返回true dismiss
*/
- fun showTipsDialog(
+ private fun showSingleTipsDialog(
context: Context,
content: String,
- leftText: String? = "取消",
+ leftText: String? = null,
rightText: String? = "确定",
- leftBlock: () -> Boolean = { true },
- rightBlock: () -> Boolean = { true }
+ leftBlock: (MaterialDialog) -> Boolean = { true },
+ rightBlock: (MaterialDialog) -> Boolean = { true }
) {
Handler(Looper.getMainLooper()).post {
+ // 该界面已弹出同类弹窗且仍在显示,直接跳过,避免重复弹出
+ singleTipsDialogMap[context]?.let { if (it.isShowing) return@post }
+
val dialog = MaterialDialog(context).apply {
+ SecureScreenShot.apply(window)
customView(
R.layout.dialog_confirm, noVerticalPadding = true, dialogWrapContent = false
)
@@ -50,20 +95,95 @@
btnRight.text = rightText ?: ""
btnLeft.isVisible = !leftText.isNullOrEmpty()
btnRight.isVisible = !rightText.isNullOrEmpty()
+ btnLeft.setOnClickListener { if (leftBlock(this)) dismiss() }
+ btnRight.setOnClickListener { if (rightBlock(this)) dismiss() }
+ // 弹窗被关闭后移除记录,下次可正常再次弹出
+ onDismiss { singleTipsDialogMap.remove(context) }
+ }
+ singleTipsDialogMap[context] = dialog
+ dialog.show()
+ dialog.window?.setGravity(Gravity.CENTER)
+// dialog.window?.setWindowAnimations(R.style.AnimLeft)
+ }
+ }
+
+ /**
+ * 通用提示弹窗
+ * @param content 内容
+ * @param leftBlock 回调事件 返回true dismiss
+ * @param rightBlock 回调事件 返回true dismiss
+ */
+ fun showTipsDialog(
+ context: Context,
+ content: String,
+ leftText: String? = "取消",
+ rightText: String? = "确定",
+ leftBlock: () -> Boolean = { true },
+ rightBlock: () -> Boolean = { true }
+ ) {
+ showCommonTipsDialog(
+ context = context,
+ content = content,
+ leftText = leftText,
+ rightText = rightText,
+ leftBlock = { dialog ->
+ if (leftBlock.invoke()) {
+ dialog.dismiss()
+ }
+ },
+ rightBlock = { dialog ->
+ if (rightBlock.invoke()) {
+ dialog.dismiss()
+ }
+ },
+ )
+ }
+
+ /**
+ * 通用提示弹窗
+ * @param content 内容
+ * @param leftBlock 回调事件 返回true dismiss
+ * @param rightBlock 回调事件 返回true dismiss
+ */
+ fun showCommonTipsDialog(
+ context: Context,
+ content: String,
+ leftText: String? = "取消",
+ rightText: String? = "确定",
+ cancelable: Boolean = true,
+ cancelOnTouchOutside: Boolean = true,
+ leftBlock: (MaterialDialog) -> Unit = { },
+ rightBlock: (MaterialDialog) -> Unit = { }
+ ) {
+ Handler(Looper.getMainLooper()).post {
+ val dialog = MaterialDialog(context).apply {
+ SecureScreenShot.apply(window)
+ customView(
+ R.layout.dialog_confirm, noVerticalPadding = true, dialogWrapContent = false
+ )
+
+ cancelable(cancelable)
+ cancelOnTouchOutside(cancelOnTouchOutside)
+ cornerRadius(15f)
+
+ val tvContent = findViewById<AppCompatTextView>(R.id.content)
+ val btnLeft = findViewById<Button>(R.id.btnLeft)
+ val btnRight = findViewById<Button>(R.id.btnRight)
+ tvContent.text = content
+ btnLeft.text = leftText ?: ""
+ btnRight.text = rightText ?: ""
+ btnLeft.isVisible = !leftText.isNullOrEmpty()
+ btnRight.isVisible = !rightText.isNullOrEmpty()
btnLeft.setOnClickListener {
- if (leftBlock()) {
- dismiss()
- }
+ leftBlock(this)
}
btnRight.setOnClickListener {
- if (rightBlock()) {
- dismiss()
- }
+ rightBlock(this)
}
}
dialog.show()
dialog.window?.setGravity(Gravity.CENTER)
- dialog.window?.setWindowAnimations(R.style.AnimLeft)
+// dialog.window?.setWindowAnimations(R.style.AnimLeft)
}
}
@@ -72,6 +192,7 @@
.cornerRadius(15f)
.cancelable(true)
.show {
+ SecureScreenShot.apply(window)
customView(
R.layout.dialog_show_select,
noVerticalPadding = true,
@@ -91,4 +212,91 @@
}
}
+ /**
+ * 通用提示弹窗
+ * @param cancelable 是否能够点击物理返回按钮取消
+ * @param cancelOnTouchOutside 是否能够点击空白区域取消
+ * @param title 标题
+ * @param titleTextSize 标题字号大小 单位SP
+ * @param titleTextColor 标题字体颜色资源id
+ * @param content 内容
+ * @param contentTextSize 内容字号大小 单位SP
+ * @param contentTextColor 内容字体颜色资源id
+ * @param leftOperationText 左边操作按钮文案
+ * @param leftOperationTextSize 左边操作按钮文案字体大小
+ * @param leftOperationTextColor 左边操作按钮文案字体颜色
+ * @param rightOperationText 右边操作按钮文案
+ * @param rightOperationTextSize 右边操作按钮文案字体大小
+ * @param rightOperationTextColor 右边操作按钮文案字体颜色
+ * @param leftOperationBlock 回调事件 返回true dismiss
+ * @param rightOperationBlock 回调事件 返回true dismiss
+ */
+ fun showNoticeDialog(
+ context: Context,
+ cancelable: Boolean = true,
+ cancelOnTouchOutside: Boolean = true,
+ title: CharSequence,
+ titleTextSize: Float = 18f,
+ titleTextColor: Int = R.color.gray_10,
+ content: CharSequence,
+ contentTextSize: Float = 14f,
+ contentTextColor: Int = R.color.gray_9,
+ contentTextGravity: Int = Gravity.CENTER,
+ leftOperationText: String? = "取消",
+ leftOperationTextSize: Float = 16f,
+ leftOperationTextColor: Int = R.color.gray_10,
+ rightOperationText: String? = "确定",
+ rightOperationTextSize: Float = 16f,
+ rightOperationTextColor: Int = R.color.blue_5,
+ leftOperationBlock: () -> Boolean = { true },
+ rightOperationBlock: () -> Boolean = { true }
+ ) {
+ Handler(Looper.getMainLooper()).post {
+ val dialog = MaterialDialog(context).apply {
+ SecureScreenShot.apply(window)
+ customView(
+ R.layout.dialog_notice, noVerticalPadding = true, dialogWrapContent = false
+ )
+ cancelable(cancelable)
+ cancelOnTouchOutside(cancelOnTouchOutside)
+ cornerRadius(5f)
+
+ val tvTitle = findViewById<AppCompatTextView>(R.id.title)
+ val tvContent = findViewById<AppCompatTextView>(R.id.content)
+ val btnLeft = findViewById<Button>(R.id.btnLeft)
+ val btnRight = findViewById<Button>(R.id.btnRight)
+ tvTitle.text = title
+ tvTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, titleTextSize)
+ tvTitle.setTextColor(ContextCompat.getColor(context, titleTextColor))
+ tvContent.text = content
+ tvContent.highlightColor = Color.TRANSPARENT
+ tvContent.movementMethod = LinkMovementMethod.getInstance()
+ tvContent.setTextSize(TypedValue.COMPLEX_UNIT_SP, contentTextSize)
+ tvContent.setTextColor(ContextCompat.getColor(context, contentTextColor))
+ tvContent.gravity = contentTextGravity
+ btnLeft.text = leftOperationText ?: ""
+ btnLeft.setTextSize(TypedValue.COMPLEX_UNIT_SP, leftOperationTextSize)
+ btnLeft.setTextColor(ContextCompat.getColor(context, leftOperationTextColor))
+ btnRight.text = rightOperationText ?: ""
+ btnRight.setTextSize(TypedValue.COMPLEX_UNIT_SP, rightOperationTextSize)
+ btnRight.setTextColor(ContextCompat.getColor(context, rightOperationTextColor))
+ btnLeft.isVisible = !leftOperationText.isNullOrEmpty()
+ btnRight.isVisible = !rightOperationText.isNullOrEmpty()
+ btnLeft.setOnClickListener {
+ if (leftOperationBlock()) {
+ dismiss()
+ }
+ }
+ btnRight.setOnClickListener {
+ if (rightOperationBlock()) {
+ dismiss()
+ }
+ }
+ }
+ dialog.show()
+ dialog.window?.setGravity(Gravity.CENTER)
+// dialog.window?.setWindowAnimations(R.style.AnimLeft)
+ }
+ }
+
}
\ No newline at end of file
diff --git a/common/src/main/java/com/xw/common/SecureScreenShot.kt b/common/src/main/java/com/xw/common/SecureScreenShot.kt
new file mode 100644
index 0000000..3232e6f
--- /dev/null
+++ b/common/src/main/java/com/xw/common/SecureScreenShot.kt
@@ -0,0 +1,85 @@
+package com.xw.common
+
+import android.view.Window
+import android.view.WindowManager
+import java.lang.ref.WeakReference
+
+/**
+ * 统一管理 APP 防截屏(FLAG_SECURE)开关。
+ *
+ * 默认行为:非 DEBUG 包禁止截屏,DEBUG 包允许截屏,保持与历史逻辑一致。
+ *
+ * 内部用弱引用集合保存所有受管理的 [Window](避免持有 Activity/Dialog 导致内存泄漏)。
+ * 当 [allowScreenShot] 在 true/false 之间发生变化时,会自动刷新所有存活 window 的
+ * FLAG_SECURE 标记,从而实时启用 / 禁用截屏。
+ */
+object SecureScreenShot {
+
+ /** 受管理的 window 弱引用集合 */
+ private val windowRefs = mutableListOf<WeakReference<Window>>()
+
+ /**
+ * 运行时是否允许截屏。默认 false(即开启防截屏)。
+ * 赋值发生变化时,会自动刷新所有已登记 window 的截屏标记。
+ */
+ @Volatile
+ var allowScreenShot: Boolean = false
+ set(value) {
+ if (field == value) return
+ field = value
+ refreshAll()
+ }
+
+ /**
+ * 登记并立即为指定 [window] 应用当前的截屏配置。
+ * 同一个 window 不会重复登记,失效的弱引用会被顺带清理。
+ */
+ @Synchronized
+ fun apply(window: Window?) {
+ window ?: return
+ var exists = false
+ val iterator = windowRefs.iterator()
+ while (iterator.hasNext()) {
+ val w = iterator.next().get()
+ if (w == null) {
+ iterator.remove()
+ } else if (w === window) {
+ exists = true
+ }
+ }
+ if (!exists) {
+ windowRefs.add(WeakReference(window))
+ }
+ applyFlag(window)
+ }
+
+ /**
+ * 刷新所有存活 window 的截屏标记,并清理已失效的弱引用。
+ */
+ @Synchronized
+ private fun refreshAll() {
+ val iterator = windowRefs.iterator()
+ while (iterator.hasNext()) {
+ val w = iterator.next().get()
+ if (w == null) {
+ iterator.remove()
+ } else {
+ applyFlag(w)
+ }
+ }
+ }
+
+ /**
+ * 根据当前配置为指定 [window] 应用或清除防截屏标记。
+ *
+ * - DEBUG 包或 [allowScreenShot] 为 true 时:清除 FLAG_SECURE,允许截屏
+ * - 否则:添加 FLAG_SECURE,禁止截屏
+ */
+ private fun applyFlag(window: Window) {
+ if (BuildConfig.DEBUG || allowScreenShot) {
+ window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
+ } else {
+ window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)//禁止截屏
+ }
+ }
+}
diff --git a/common/src/main/java/com/xw/common/TimeDialog.kt b/common/src/main/java/com/xw/common/TimeDialog.kt
index dc8578b..24d37a5 100644
--- a/common/src/main/java/com/xw/common/TimeDialog.kt
+++ b/common/src/main/java/com/xw/common/TimeDialog.kt
@@ -60,14 +60,23 @@
dismiss()
}
}
-
+
/*仅显示年月日*/
- fun show(title: String, showTime: Long = -1L, minTime: Long = -1L, onSure: (Long) -> Unit) {
+ fun show(
+ title: String,
+ showTime: Long = -1L,
+ minTime: Long = -1L,
+ maxTime: Long? = null,
+ onSure: (Long) -> Unit
+ ) {
bind.title.text = title
- getCurrentData(if (minTime == -1L) System.currentTimeMillis() else minTime)
+ getCurrentData(if (minTime == -1L) System.currentTimeMillis() else minTime, maxTime)
this.onSure = onSure
- val time = if (showTime == -1L && minTime == -1L) System.currentTimeMillis() else max(showTime, minTime)
+ val time = if (showTime == -1L && minTime == -1L) System.currentTimeMillis() else max(
+ showTime,
+ minTime
+ )
initSelectTime(TimeUtils.millis2String(time, "yyyy-MM-dd"))
super.show()
}
@@ -132,8 +141,10 @@
private fun initDays(days: Int) {
dayDataList.clear()
- val dayStart = if (minYear == showYear && minMouth == showMouth) minDay.toInt() else 1
- val dayEnd = if ("$maxYear" == showYear && "$maxMouth" == showMouth) maxDay else days
+ val dayStart =
+ if (minYear.toInt() == showYear.toInt() && minMouth.toInt() == showMouth.toInt()) minDay.toInt() else 1
+ val dayEnd =
+ if (maxYear == showYear.toInt() && maxMouth == showMouth.toInt()) maxDay else days
for (i in dayStart..dayEnd) {
// dayDataList.add("${if (i < 10) "0$i" else i}日")
dayDataList.add("${i}日")
@@ -162,7 +173,7 @@
}
override fun onItemSelected(loopview: LoopView, index: Int) {
- if(index == - 1) return
+ if (index == -1) return
when (loopview.tag.toString()) {
"yearView" -> {
showYear = yearDataList[index].replace("年", "")
@@ -201,8 +212,8 @@
else TimeUtils.string2Millis(time, "yyyy-MM-dd")
}
- fun getTime(time: Long): String {
- return TimeUtils.millis2String(time, "yyyy-MM-dd")
+ fun getTime(time: Long, pattern: String = "yyyy-MM-dd"): String {
+ return TimeUtils.millis2String(time, pattern)
}
}
diff --git a/common/src/main/java/com/xw/common/base/ImageSelectAdapter.kt b/common/src/main/java/com/xw/common/base/ImageSelectAdapter.kt
index 61dc373..7db556c 100644
--- a/common/src/main/java/com/xw/common/base/ImageSelectAdapter.kt
+++ b/common/src/main/java/com/xw/common/base/ImageSelectAdapter.kt
@@ -144,6 +144,8 @@
var url: String = "",
var localPath: String = "",
var type: String = "", // video ic_notice audio
+ var placeholder: Int = R.mipmap.icon_default5,
+ var error: Int = R.mipmap.icon_default5,
){
override fun toString(): String {
return "FileSelectBean(url='$url', localPath='$localPath', type='$type')"
diff --git a/common/src/main/java/com/xw/common/custom/ClassicsFooter11.java b/common/src/main/java/com/xw/common/custom/ClassicsFooter11.java
index c690cd3..0e82f8e 100644
--- a/common/src/main/java/com/xw/common/custom/ClassicsFooter11.java
+++ b/common/src/main/java/com/xw/common/custom/ClassicsFooter11.java
@@ -31,7 +31,7 @@
public static String REFRESH_FOOTER_RELEASE = "释放立即加载~";//"释放立即加载";
public static String REFRESH_FOOTER_LOADING = "加载中...";//"正在加载...";
public static String REFRESH_FOOTER_REFRESHING = "正在刷新...";//"正在刷新...";
- public static String REFRESH_FOOTER_FINISH = "加载完成~";//"加载完成";
+ public static String REFRESH_FOOTER_FINISH = "上滑继续加载";//"加载完成";
public static String REFRESH_FOOTER_FAILED = "加载失败~";//"加载失败";
public static String REFRESH_FOOTER_NOTHING = "已经到底了~";//"没有更多数据了";
diff --git a/common/src/main/java/com/xw/common/custom/ShowTextLinearLayout.kt b/common/src/main/java/com/xw/common/custom/ShowTextLinearLayout.kt
index de2d5dc..9f8fb01 100644
--- a/common/src/main/java/com/xw/common/custom/ShowTextLinearLayout.kt
+++ b/common/src/main/java/com/xw/common/custom/ShowTextLinearLayout.kt
@@ -469,15 +469,11 @@
val tv = AppCompatTextView(context!!)
// 长度限制
val maxLength = 30
- val displayText = if (name.length > maxLength) {
- name.take(maxLength) + "…"
- } else {
- name
- }
+ val displayText = name
tv.text = displayText
tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, text_size.toFloat()) //设置字体大小 像素单位
tv.setTextColor(textColor)
- tv.setGravity(Gravity.CENTER)
+ tv.setGravity(Gravity.CENTER_VERTICAL)
tv_list.add(tv)
tv.tag = tv_list.size - 1
diff --git a/common/src/main/java/com/xw/common/custom/SlideButtonView.kt b/common/src/main/java/com/xw/common/custom/SlideButtonView.kt
index d13823a..d71bf32 100644
--- a/common/src/main/java/com/xw/common/custom/SlideButtonView.kt
+++ b/common/src/main/java/com/xw/common/custom/SlideButtonView.kt
@@ -56,6 +56,12 @@
private var maxThumbX: Float = 0f
private var isDragging = false
private var slideThreshold: Float = 0.7f
+ //是否能够使用
+ var enable: Boolean = true
+ set(value) {
+ field = value
+ invalidate()
+ }
private val scroller = Scroller(context, DecelerateInterpolator())
private var onSlideCompleteListener: (() -> Unit)? = null
@@ -78,6 +84,7 @@
thumbShape = getInt(R.styleable.SlideButtonView_thumbShape, SHAPE_ROUND_RECT)
thumbCornerRadius = getDimension(R.styleable.SlideButtonView_thumbCornerRadius, 0f)
slideThreshold = getFloat(R.styleable.SlideButtonView_slideThreshold, 0.7f)
+ enable = getBoolean(R.styleable.SlideButtonView_enable, enable)
} finally {
recycle()
}
@@ -213,6 +220,9 @@
}
override fun onTouchEvent(event: MotionEvent): Boolean {
+ if (!enable) {
+ return super.onTouchEvent(event)
+ }
when (event.action) {
MotionEvent.ACTION_DOWN -> {
val touchX = event.x
diff --git a/common/src/main/java/com/xw/common/custom/SlideSwitchView.kt b/common/src/main/java/com/xw/common/custom/SlideSwitchView.kt
index 4bd674e..bbd8b20 100644
--- a/common/src/main/java/com/xw/common/custom/SlideSwitchView.kt
+++ b/common/src/main/java/com/xw/common/custom/SlideSwitchView.kt
@@ -1,15 +1,18 @@
package com.xw.common.custom
import android.content.Context
-import android.graphics.*
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.RectF
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.view.animation.DecelerateInterpolator
import android.widget.Scroller
import androidx.core.content.withStyledAttributes
-import kotlin.math.abs
import com.xw.common.R
+import kotlin.math.abs
/**
* 自定义滑动开关 View
@@ -25,6 +28,13 @@
interface OnStateChangeListener {
fun onStateChanged(isChecked: Boolean)
}
+
+ //是否能手动点击
+ var switchEnable = true
+ set(value) {
+ field = value
+ invalidate()
+ }
// 尺寸配置
private var switchWidth = 0f
@@ -68,6 +78,7 @@
init {
context.withStyledAttributes(attrs, R.styleable.SlideSwitchView, defStyleAttr, 0) {
+ switchEnable = getBoolean(R.styleable.SlideSwitchView_switchEnable, switchEnable)
// 背景颜色
backgroundColorUnchecked = getColor(
R.styleable.SlideSwitchView_switchBackgroundColorUnchecked,
@@ -99,7 +110,8 @@
)
// 文字内容
- textUnchecked = getString(R.styleable.SlideSwitchView_switchTextUnchecked) ?: textUnchecked
+ textUnchecked =
+ getString(R.styleable.SlideSwitchView_switchTextUnchecked) ?: textUnchecked
textChecked = getString(R.styleable.SlideSwitchView_switchTextChecked) ?: textChecked
// 文字大小
@@ -107,7 +119,8 @@
// 圆角
cornerRadius = getDimension(R.styleable.SlideSwitchView_switchCornerRadius, 0f)
- thumbCornerRadius = getDimension(R.styleable.SlideSwitchView_switchThumbCornerRadius, 0f)
+ thumbCornerRadius =
+ getDimension(R.styleable.SlideSwitchView_switchThumbCornerRadius, 0f)
// 滑块间距(新增)
thumbMargin = getDimension(R.styleable.SlideSwitchView_switchThumbMargin, 0f)
@@ -222,44 +235,46 @@
}
override fun onTouchEvent(event: MotionEvent): Boolean {
- when (event.action) {
- MotionEvent.ACTION_DOWN -> {
- lastX = event.x
- isDragging = false
- parent?.requestDisallowInterceptTouchEvent(true)
- return true
- }
-
- MotionEvent.ACTION_MOVE -> {
- val deltaX = event.x - lastX
- if (!isDragging && abs(deltaX) > touchSlop) {
- isDragging = true
+ if (switchEnable) {
+ when (event.action) {
+ MotionEvent.ACTION_DOWN -> {
+ lastX = event.x
+ isDragging = false
+ parent?.requestDisallowInterceptTouchEvent(true)
+ return true
}
- if (isDragging) {
- thumbPosition += deltaX
- // 限制滑动范围
- thumbPosition = thumbPosition.coerceIn(0f, maxThumbPosition)
- invalidate()
- }
- lastX = event.x
- return true
- }
+ MotionEvent.ACTION_MOVE -> {
+ val deltaX = event.x - lastX
+ if (!isDragging && abs(deltaX) > touchSlop) {
+ isDragging = true
+ }
- MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
- parent?.requestDisallowInterceptTouchEvent(false)
-
- if (!isDragging) {
- // 点击切换
- toggle()
- } else {
- // 滑动释放,根据位置决定状态
- val threshold = maxThumbPosition / 2
- val targetChecked = thumbPosition > threshold
- animateToState(targetChecked)
+ if (isDragging) {
+ thumbPosition += deltaX
+ // 限制滑动范围
+ thumbPosition = thumbPosition.coerceIn(0f, maxThumbPosition)
+ invalidate()
+ }
+ lastX = event.x
+ return true
}
- isDragging = false
- return true
+
+ MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
+ parent?.requestDisallowInterceptTouchEvent(false)
+
+ if (!isDragging) {
+ // 点击切换
+ toggle()
+ } else {
+ // 滑动释放,根据位置决定状态
+ val threshold = maxThumbPosition / 2
+ val targetChecked = thumbPosition > threshold
+ animateToState(targetChecked)
+ }
+ isDragging = false
+ return true
+ }
}
}
return super.onTouchEvent(event)
diff --git a/common/src/main/java/com/xw/common/utils/BindUtils.kt b/common/src/main/java/com/xw/common/utils/BindUtils.kt
index 49f31fc..e732445 100644
--- a/common/src/main/java/com/xw/common/utils/BindUtils.kt
+++ b/common/src/main/java/com/xw/common/utils/BindUtils.kt
@@ -5,12 +5,13 @@
import android.view.LayoutInflater
import android.view.View
import androidx.databinding.DataBindingUtil
-import com.xw.common.BuildConfig
import androidx.databinding.ObservableField
import androidx.databinding.OnRebindCallback
import androidx.databinding.ViewDataBinding
import androidx.lifecycle.LiveData
+import com.xw.common.BuildConfig
import com.xw.common.R
+import com.xw.common.databinding.LayoutEmptyView2Binding
import com.xw.common.databinding.LayoutEmptyViewBinding
import com.xw.common.databinding.LayoutFootViewBinding
import org.json.JSONArray
@@ -23,6 +24,14 @@
@SuppressLint("DefaultLocale")
object BindUtils {
+
+ fun getEmptyView2(context: Context, tips: String = "空空如也~"): View {
+ val itemBind = DataBindingUtil.inflate<LayoutEmptyView2Binding>(
+ LayoutInflater.from(context), R.layout.layout_empty_view2, null, false
+ )
+ itemBind.tips.text = tips
+ return itemBind.root
+ }
fun getEmptyView(context: Context, tips: String = "空空如也~"): View {
val itemBind = DataBindingUtil.inflate<LayoutEmptyViewBinding>(
@@ -127,7 +136,8 @@
// return urls
// }
- fun String.getUrls(): List<String> {
+ fun String.getUrls() = getValueList("url")
+ fun String.getValueList(key: String): List<String> {
val urls = mutableListOf<String>()
try {
val trimmed = this.trim()
@@ -143,7 +153,7 @@
is String -> JSONObject(item) // 处理转义的JSON字符串
else -> continue
}
- urls.add(jsonObj.optString("url").trim())
+ urls.add(jsonObj.optString(key).trim())
}
} else {
// 单个:JSONObject 或 转义的JSON字符串
@@ -153,7 +163,7 @@
} else {
JSONObject(trimmed)
}
- urls.add(jsonObj.optString("url").trim())
+ urls.add(jsonObj.optString(key).trim())
}
} catch (e: Exception) {
e.printStackTrace()
diff --git a/common/src/main/java/com/xw/common/utils/GlideEngine.java b/common/src/main/java/com/xw/common/utils/GlideEngine.java
index f09291d..6234864 100644
--- a/common/src/main/java/com/xw/common/utils/GlideEngine.java
+++ b/common/src/main/java/com/xw/common/utils/GlideEngine.java
@@ -3,6 +3,10 @@
import android.content.Context;
import android.widget.ImageView;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.IdRes;
+import androidx.annotation.NonNull;
+
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
@@ -26,8 +30,8 @@
}
Glide.with(context)
.load(url)
- .placeholder(R.mipmap.ic_loading)
- .error(R.mipmap.ic_load_fail).into(imageView);
+ .placeholder(R.mipmap.icon_default)
+ .error(R.mipmap.icon_default).into(imageView);
}
@Override
@@ -38,8 +42,8 @@
Glide.with(context)
.load(url)
.override(maxWidth, maxHeight)
- .placeholder(R.mipmap.ic_loading)
- .error(R.mipmap.ic_load_fail).into(imageView);
+ .placeholder(R.mipmap.icon_default)
+ .error(R.mipmap.icon_default).into(imageView);
}
/**
@@ -60,8 +64,8 @@
.override(180, 180)
.sizeMultiplier(0.5f)
.transform(new CenterCrop(), new RoundedCorners(8))
- .placeholder(R.mipmap.ic_loading)
- .error(R.mipmap.ic_load_fail).into(imageView);
+ .placeholder(R.mipmap.icon_default)
+ .error(R.mipmap.icon_default).into(imageView);
}
@@ -81,8 +85,8 @@
.load(url)
.override(200, 200)
.centerCrop()
- .placeholder(R.mipmap.ic_loading)
- .error(R.mipmap.ic_load_fail).into(imageView);
+ .placeholder(R.mipmap.icon_default)
+ .error(R.mipmap.icon_default).into(imageView);
}
@Override
@@ -101,6 +105,28 @@
Glide.with(context).resumeRequests();
}
+ /**
+ * 加载图片
+ *
+ * @param imageView 图片控件
+ * @param url 链接
+ * @param error 加载异常占位图资源id
+ * @param placeHolder 占位图资源id
+ * @param radius 圆角 单位dp
+ */
+ public void load(@NonNull ImageView imageView,
+ String url,
+ @DrawableRes int error, @DrawableRes int placeHolder,
+ float radius) {
+ float value = radius * imageView.getContext().getResources().getDisplayMetrics().density;
+ Glide.with(imageView)
+ .load(url)
+ .transform(new CenterCrop(), new RoundedCorners((int) value))
+ .placeholder(placeHolder)
+ .error(error)
+ .into(imageView);
+ }
+
private GlideEngine() {
}
diff --git a/common/src/main/java/com/xw/common/utils/GpsHelper.kt b/common/src/main/java/com/xw/common/utils/GpsHelper.kt
index af3cff2..0bdf641 100644
--- a/common/src/main/java/com/xw/common/utils/GpsHelper.kt
+++ b/common/src/main/java/com/xw/common/utils/GpsHelper.kt
@@ -7,6 +7,7 @@
import android.location.LocationManager
import android.os.Build
import android.os.Bundle
+import android.provider.Settings
import androidx.core.net.toUri
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
@@ -20,8 +21,9 @@
import com.hjq.permissions.OnPermissionCallback
import com.hjq.permissions.Permission
import com.hjq.permissions.XXPermissions
+import com.xw.common.CommonDialog
import com.xw.common.Constants
-import android.provider.Settings
+
/**
* GPS
*
@@ -32,6 +34,7 @@
var isOnceLocation: Boolean, // 是否定位一次
var isAutomatic: Boolean = true,// isAutomatic 是否自动开启定位
var savedInstanceState: Bundle?,
+ var interval: Long = 2000L,//默认定位间隔
) : AMapLocationListener, LifecycleObserver {
val TAG = "zmc-GpsHelper"
@@ -46,6 +49,16 @@
// 标记是否正在监听 GPS 状态(用于避免重复注册)
private var isWatchingGpsStatus = false
+
+ // 是否已经发起过位置权限申请(避免每次 onResume 都重复 request 导致权限 Activity 反复拉起、onResume 死循环)
+ private var hasRequestedPermission = false
+
+ // 是否已经弹过"权限被拒绝"提示框(避免多次弹出)
+ private var hasShownDeniedDialog = false
+
+ // 定位权限组
+ private val locationPermissions =
+ arrayOf(Permission.ACCESS_FINE_LOCATION, Permission.ACCESS_COARSE_LOCATION)
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun resume() {
@@ -71,18 +84,48 @@
}
fun startLocation() {
- val pl = arrayOf(Permission.ACCESS_FINE_LOCATION, Permission.ACCESS_COARSE_LOCATION)
- XXPermissions.with(context).permission(pl).request(object : OnPermissionCallback {
- override fun onGranted(permissions: MutableList<String>, allGranted: Boolean) { // 权限同意
- initLocation()
- }
+ // 已授权:直接定位,绝不再调 request()。
+ // request() 在 XXPermissions 18+ 会拉起一个透明的权限 Activity,
+ // 权限被永久拒绝时该 Activity 会立即返回并 finish,从而再次触发宿主 onResume,
+ // 若每次 onResume 都无条件 request 就会形成 onResume <-> 权限 Activity 的死循环。
+ if (XXPermissions.isGranted(context, locationPermissions)) {
+ hasShownDeniedDialog = false // 已授权,重置提示状态,便于下次被撤销时能再次提醒
+ initLocation()
+ return
+ }
- override fun onDenied(permissions: MutableList<String>, doNotAskAgain: Boolean) {
- super.onDenied(permissions, doNotAskAgain)
- //权限禁止
- listener.location(null)
- }
- })
+ // 之前已经申请过且现在仍未授权 => 已被拒绝:不再 request,避免死循环,只提示一次
+ if (hasRequestedPermission) {
+ listener.location(null)
+ showDeniedDialogOnce()
+ return
+ }
+
+ // 首次申请,最多触发一次
+ hasRequestedPermission = true
+ XXPermissions.with(context).permission(locationPermissions)
+ .request(object : OnPermissionCallback {
+ override fun onGranted(permissions: MutableList<String>, allGranted: Boolean) { // 权限同意
+ hasShownDeniedDialog = false
+ initLocation()
+ }
+
+ override fun onDenied(permissions: MutableList<String>, doNotAskAgain: Boolean) {
+ super.onDenied(permissions, doNotAskAgain)
+ //权限禁止
+ listener.location(null)
+ showDeniedDialogOnce()
+ }
+ })
+ }
+
+ /**
+ * 位置权限被拒绝后,弹框告知用户(同一生命周期内只弹一次,避免重复打扰)
+ */
+ private fun showDeniedDialogOnce() {
+ if (hasShownDeniedDialog) return
+ hasShownDeniedDialog = true
+ CommonDialog.showLocationNotGrantedTipsDialog(context)
}
private fun initLocation() {
@@ -105,7 +148,7 @@
// 设置是否允许模拟位置,默认为false,不允许模拟位置
mLocationOption.isMockEnable = false
// 设置定位间隔,单位毫秒,默认为2000ms
- mLocationOption.interval = 2000
+ mLocationOption.interval = interval
//返回方位角
mLocationOption.isSensorEnable = false
// 给定位客户端对象设置定位参数
@@ -119,7 +162,7 @@
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
- fun pause(){
+ fun pause() {
mLocationClient?.let { mLocationClient ->
mLocationClient.stopLocation()
LogUtils.d(TAG, "onPause")
@@ -186,7 +229,8 @@
fun isLocationEnabledModern(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// Android 9.0 (API 28) 及以上
- val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
+ val locationManager =
+ context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
locationManager.isLocationEnabled
} else {
// 兼容旧版本
diff --git a/common/src/main/java/com/xw/common/utils/MMKVManager.kt b/common/src/main/java/com/xw/common/utils/MMKVManager.kt
index bc2d5a7..c574e5c 100644
--- a/common/src/main/java/com/xw/common/utils/MMKVManager.kt
+++ b/common/src/main/java/com/xw/common/utils/MMKVManager.kt
@@ -88,6 +88,7 @@
enum class KeyPreferences(val value: String) {
TOKEN("token"),
USER("user"),
+ THIRD("third"),
ACCIDENT("accident"),
NEED_READ("needRead"), // 是否需要阅读协议
NEED_UPDATE("needUpdate") // 是否升级
diff --git a/common/src/main/java/com/xw/common/viewAdapter/ViewAdapter.kt b/common/src/main/java/com/xw/common/viewAdapter/ViewAdapter.kt
index 932c033..988fe69 100644
--- a/common/src/main/java/com/xw/common/viewAdapter/ViewAdapter.kt
+++ b/common/src/main/java/com/xw/common/viewAdapter/ViewAdapter.kt
@@ -80,7 +80,7 @@
if (!url.isNullOrEmpty()) {
Glide.with(imageView.context)
.load(if (url.startsWith("content://")) Uri.parse(url) else url)
- .placeholder(R.mipmap.ic_loading).error(R.mipmap.ic_load_fail)
+ .placeholder(R.mipmap.icon_default).error(R.mipmap.icon_default)
.format(DecodeFormat.PREFER_RGB_565).into(imageView)
}
}
@@ -92,7 +92,7 @@
if (url.isNotEmpty()) {
Glide.with(imageView.context)
.load(if (url.startsWith("content://")) Uri.parse(url) else url)
- .placeholder(R.mipmap.ic_loading).error(R.mipmap.ic_load_fail)
+ .placeholder(R.mipmap.icon_default).error(R.mipmap.icon_default)
.format(DecodeFormat.PREFER_RGB_565).into(imageView)
} else {
item?.defaultSrc?.let {
@@ -110,13 +110,13 @@
val url = item.localPath
Glide.with(imageView.context)
.load(if (url.startsWith("content://")) Uri.parse(url) else url)
- .placeholder(R.mipmap.ic_loading).error(R.mipmap.ic_load_fail)
+ .placeholder(item.placeholder).error(it.error)
.format(DecodeFormat.PREFER_RGB_565).into(imageView)
}
item.url.isNotEmpty() -> {
Glide.with(imageView.context).load(item.url)
- .placeholder(R.mipmap.ic_loading).error(R.mipmap.ic_load_fail)
+ .placeholder(item.placeholder).error(it.error)
.format(DecodeFormat.PREFER_RGB_565).into(imageView)
}
diff --git a/common/src/main/res/drawable/shape_black_bg_8.xml b/common/src/main/res/drawable/shape_black_bg_8.xml
index 3a1380a..8d81184 100644
--- a/common/src/main/res/drawable/shape_black_bg_8.xml
+++ b/common/src/main/res/drawable/shape_black_bg_8.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="8dp" />
- <solid android:color="#000000" />
+ <solid android:color="#b8000000" />
</shape>
\ No newline at end of file
diff --git a/common/src/main/res/drawable/shape_while_bg_5.xml b/common/src/main/res/drawable/shape_while_bg_5.xml
new file mode 100644
index 0000000..43cee60
--- /dev/null
+++ b/common/src/main/res/drawable/shape_while_bg_5.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="@color/white" />
+ <corners android:radius="@dimen/dp_5" />
+</shape>
\ No newline at end of file
diff --git a/common/src/main/res/drawable/shape_while_bg_8.xml b/common/src/main/res/drawable/shape_while_bg_8.xml
new file mode 100644
index 0000000..d4ee6a9
--- /dev/null
+++ b/common/src/main/res/drawable/shape_while_bg_8.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="@color/white" />
+ <corners android:radius="@dimen/dp_8" />
+</shape>
\ No newline at end of file
diff --git a/common/src/main/res/drawable/shape_white_bg_top_16.xml b/common/src/main/res/drawable/shape_white_bg_top_16.xml
new file mode 100644
index 0000000..5afec0b
--- /dev/null
+++ b/common/src/main/res/drawable/shape_white_bg_top_16.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:topLeftRadius="@dimen/dp_16" android:topRightRadius="@dimen/dp_16" />
+ <solid android:color="@color/white" />
+</shape>
\ No newline at end of file
diff --git a/common/src/main/res/drawable/svg_car_chongdian.xml b/common/src/main/res/drawable/svg_car_chongdian.xml
index 42c55d2..d939bd9 100644
--- a/common/src/main/res/drawable/svg_car_chongdian.xml
+++ b/common/src/main/res/drawable/svg_car_chongdian.xml
@@ -1,3 +1,18 @@
+<!--
+ ~ Copyright (C) 2026 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="17dp"
android:height="17dp"
@@ -5,5 +20,6 @@
android:viewportHeight="17">
<path
android:pathData="M12.75,0C13.924,0 14.875,0.951 14.875,2.125L14.875,15.229L16.115,15.229C16.604,15.229 17,15.626 17,16.115C17,16.604 16.604,17 16.115,17L0.885,17C0.396,17 -0,16.604 -0,16.115C-0,15.626 0.396,15.229 0.885,15.229L2.125,15.229L2.125,2.125C2.125,0.951 3.076,0 4.25,0L12.75,0ZM9.507,7.437L6.021,11.377L7.847,11.377L7.349,14.167L11.333,10.064L9.507,10.064L9.507,7.437ZM12.396,2.125L4.604,2.125C4.233,2.125 3.925,2.411 3.898,2.78L3.896,2.833L3.896,5.313C3.896,5.683 4.181,5.991 4.551,6.019L4.604,6.021L12.396,6.021C12.767,6.021 13.075,5.735 13.102,5.366L13.104,5.313L13.104,2.833C13.104,2.442 12.787,2.125 12.396,2.125Z"
- android:fillColor="#31456A"/>
+ android:fillColor="#31456A"
+ android:fillAlpha="0.8"/>
</vector>
diff --git a/common/src/main/res/drawable/svg_car_jiance.xml b/common/src/main/res/drawable/svg_car_jiance.xml
index be3c8ca..f5cb8ef 100644
--- a/common/src/main/res/drawable/svg_car_jiance.xml
+++ b/common/src/main/res/drawable/svg_car_jiance.xml
@@ -1,13 +1,25 @@
+<!--
+ ~ Copyright (C) 2026 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="20dp"
- android:height="20dp"
- android:viewportWidth="20"
- android:viewportHeight="20">
- <group>
- <clip-path
- android:pathData="M0,0h20v20h-20z"/>
- <path
- android:pathData="M17.31,5.64L16,4.1L14.88,2.86C14.408,2.313 13.722,1.999 13,2L5.49,2C4.115,2 3,3.115 3,4.49L3,16.11C3,17.485 4.115,18.6 5.49,18.6L15.49,18.6C16.865,18.6 17.98,17.485 17.98,16.11L17.98,7.29C17.971,6.675 17.732,6.087 17.31,5.64ZM13.19,10.82L10.5,14.14C10.347,14.332 10.116,14.446 9.87,14.45C9.626,14.454 9.393,14.352 9.23,14.17L7.77,12.51C7.524,12.165 7.576,11.691 7.892,11.408C8.208,11.126 8.685,11.127 9,11.41L9.81,12.33L11.9,9.78C12.138,9.319 12.736,9.186 13.146,9.504C13.556,9.822 13.577,10.434 13.19,10.78L13.19,10.82ZM13.79,7.15C13.238,7.15 12.79,6.702 12.79,6.15L12.79,3.15L16.54,7.15L13.79,7.15Z"
- android:fillColor="#31456A"/>
- </group>
+ android:width="14.98dp"
+ android:height="16.6dp"
+ android:viewportWidth="14.98"
+ android:viewportHeight="16.6">
+ <path
+ android:pathData="M14.31,3.64L13,2.1L11.88,0.86C11.408,0.313 10.722,-0.001 10,0L2.49,0C1.115,0 0,1.115 0,2.49L0,14.11C0,15.485 1.115,16.6 2.49,16.6L12.49,16.6C13.865,16.6 14.98,15.485 14.98,14.11L14.98,5.29C14.971,4.676 14.732,4.087 14.31,3.64ZM10.19,8.82L7.5,12.14C7.347,12.333 7.116,12.446 6.87,12.45C6.626,12.454 6.393,12.352 6.23,12.17L4.77,10.51C4.524,10.166 4.576,9.691 4.892,9.409C5.208,9.126 5.685,9.127 6,9.41L6.81,10.33L8.9,7.78C9.138,7.319 9.736,7.187 10.146,7.504C10.556,7.822 10.577,8.435 10.19,8.78L10.19,8.82ZM10.79,5.15C10.238,5.15 9.79,4.702 9.79,4.15L9.79,1.15L13.54,5.15L10.79,5.15Z"
+ android:fillColor="#31456A"
+ android:fillAlpha="0.8"/>
</vector>
diff --git a/common/src/main/res/drawable/svg_car_qingjie.xml b/common/src/main/res/drawable/svg_car_qingjie.xml
index 5f31ecc..e7e19d3 100644
--- a/common/src/main/res/drawable/svg_car_qingjie.xml
+++ b/common/src/main/res/drawable/svg_car_qingjie.xml
@@ -1,29 +1,25 @@
+<!--
+ ~ Copyright (C) 2026 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="20dp"
+ android:width="18.75dp"
android:height="20dp"
- android:viewportWidth="20"
+ android:viewportWidth="18.75"
android:viewportHeight="20">
- <group>
- <clip-path
- android:pathData="M0,0h20v20h-20z"/>
- <path
- android:pathData="M7.985,5.611C9.315,5.418 10.665,5.418 11.995,5.611C12.929,5.793 13.864,5.939 14.745,6.174C15.392,6.329 15.914,6.806 16.127,7.437Q16.698,8.999 17.323,10.533C17.398,10.705 17.623,10.96 17.754,10.942C18.485,10.814 19.187,11.287 19.342,12.014C19.389,12.198 19.389,12.391 19.342,12.576L18.274,12.856C18.34,13.216 18.384,13.581 18.405,13.947L18.405,18.981C18.392,19.287 18.28,19.58 18.086,19.816C17.099,20.001 16.089,20.02 15.096,19.871C14.405,19.444 14.835,18.725 14.611,18.145L5.528,18.145C5.35,18.763 5.247,19.798 5.042,19.871C4.029,20.043 2.994,20.043 1.98,19.871C1.766,19.596 1.648,19.257 1.644,18.908C1.588,18.181 1.588,17.492 1.588,16.783C1.588,15.467 1.588,14.15 1.644,12.824L0.651,12.569C0.619,12.423 0.619,12.271 0.651,12.124C0.932,11.397 1.306,10.835 2.268,10.917C2.381,10.917 2.595,10.698 2.661,10.535C3.019,9.727 3.332,8.899 3.598,8.056C3.972,6.796 5.088,5.9 6.399,5.806C6.913,5.716 7.446,5.652 7.962,5.571L7.99,5.606L7.985,5.611ZM3.848,11.224C7.88,12.052 12.039,12.052 16.071,11.224C15.728,10.218 15.383,9.317 15.14,8.407C14.979,7.685 14.328,7.178 13.588,7.2C11.651,7.118 9.714,7.055 7.776,7.036C7.144,7.06 6.517,7.155 5.907,7.318C5.628,7.372 5.382,7.535 5.225,7.772C4.701,8.871 4.309,10.007 3.85,11.224L3.848,11.224ZM4.642,15.509C4.977,15.527 5.312,15.509 5.642,15.455C5.899,15.399 6.119,15.237 6.25,15.01C6.296,14.874 6.084,14.538 5.895,14.456C5.134,14.11 4.353,13.806 3.558,13.548C3.166,13.423 2.717,13.448 2.624,13.985C2.436,14.776 2.624,15.214 3.231,15.339C3.714,15.415 4.201,15.466 4.689,15.493L4.642,15.509ZM15.416,15.509C15.909,15.475 16.399,15.415 16.885,15.327C17.585,15.173 17.436,14.619 17.416,14.14C17.397,13.66 17.137,13.431 16.755,13.54C15.796,13.817 14.86,14.163 13.952,14.575C13.538,14.766 13.69,15.293 14.157,15.395C14.575,15.455 14.996,15.491 15.418,15.503L15.416,15.509Z"
- android:fillColor="#31456A"/>
- <path
- android:pathData="M11.367,2.201C11.364,2.953 10.751,3.559 9.999,3.556C9.246,3.559 8.634,2.953 8.63,2.201C8.63,1.451 9.999,0 9.999,0C9.999,0 11.367,1.452 11.367,2.201Z"
- android:fillColor="#31456A"/>
- <path
- android:pathData="M11.995,5.611C10.665,5.418 9.315,5.418 7.985,5.611L7.99,5.606L7.962,5.571C7.446,5.652 6.913,5.716 6.399,5.806C5.088,5.9 3.972,6.796 3.598,8.056C3.332,8.899 3.019,9.727 2.661,10.535C2.595,10.698 2.381,10.917 2.268,10.917C1.306,10.835 0.932,11.397 0.651,12.124C0.619,12.271 0.619,12.423 0.651,12.569L1.644,12.824C1.588,14.15 1.588,15.467 1.588,16.783C1.588,17.492 1.588,18.181 1.644,18.908C1.648,19.257 1.766,19.596 1.98,19.871C2.994,20.043 4.029,20.043 5.042,19.871C5.247,19.798 5.35,18.763 5.528,18.145L14.611,18.145C14.694,18.359 14.687,18.592 14.681,18.822C14.671,19.216 14.66,19.602 15.096,19.871C16.089,20.02 17.099,20.001 18.086,19.816C18.28,19.58 18.392,19.287 18.405,18.981L18.405,13.947C18.384,13.581 18.34,13.216 18.274,12.856L19.342,12.576C19.389,12.391 19.389,12.198 19.342,12.014C19.187,11.287 18.485,10.814 17.754,10.942C17.623,10.96 17.398,10.705 17.323,10.533Q16.698,8.999 16.127,7.437C15.914,6.806 15.392,6.329 14.745,6.174C13.864,5.939 12.929,5.793 11.995,5.611ZM16.071,11.224C12.039,12.052 7.881,12.052 3.849,11.224L3.851,11.224C4.309,10.007 4.702,8.872 5.225,7.772C5.383,7.536 5.629,7.373 5.907,7.318C6.518,7.155 7.145,7.06 7.777,7.037C9.714,7.055 11.652,7.118 13.589,7.2C14.329,7.179 14.98,7.685 15.14,8.408C15.384,9.317 15.729,10.218 16.071,11.224ZM5.643,15.453C5.313,15.506 4.977,15.525 4.643,15.507L4.69,15.491C4.202,15.464 3.715,15.413 3.232,15.337C2.624,15.212 2.437,14.774 2.624,13.983C2.718,13.446 3.166,13.421 3.559,13.546C4.354,13.804 5.134,14.107 5.895,14.454C6.085,14.536 6.297,14.872 6.25,15.007C6.12,15.235 5.899,15.397 5.643,15.453ZM16.885,15.325C16.399,15.413 15.909,15.473 15.417,15.507L15.419,15.501C14.997,15.489 14.576,15.453 14.158,15.393C13.691,15.291 13.538,14.764 13.952,14.573C14.86,14.161 15.797,13.815 16.755,13.538C17.137,13.429 17.397,13.658 17.417,14.138C17.419,14.201 17.424,14.265 17.429,14.329C17.461,14.756 17.493,15.192 16.885,15.325Z"
- android:fillColor="#31456A"
- android:fillType="evenOdd"/>
- <path
- android:pathData="M11.367,2.201C11.364,2.953 10.751,3.559 9.999,3.556C9.246,3.559 8.634,2.953 8.63,2.201C8.63,1.451 9.999,0 9.999,0C9.999,0 11.367,1.452 11.367,2.201Z"
- android:fillColor="#31456A"/>
- <path
- android:pathData="M6.746,3.212C6.743,3.723 6.327,4.135 5.816,4.132C5.305,4.135 4.888,3.723 4.886,3.212C4.886,2.703 5.816,1.716 5.816,1.716C5.816,1.716 6.746,2.703 6.746,3.212Z"
- android:fillColor="#31456A"/>
- <path
- android:pathData="M15.113,3.212C15.111,3.723 14.694,4.135 14.183,4.132C13.672,4.135 13.256,3.723 13.253,3.212C13.253,2.703 14.183,1.716 14.183,1.716C14.183,1.716 15.113,2.703 15.113,3.212Z"
- android:fillColor="#31456A"/>
- </group>
+ <path
+ android:pathData="M7.358,5.611C8.688,5.418 10.038,5.418 11.368,5.611C12.302,5.793 13.237,5.939 14.118,6.174C14.765,6.329 15.287,6.806 15.5,7.437Q16.071,8.999 16.696,10.533C16.771,10.705 16.996,10.96 17.127,10.942C17.858,10.814 18.56,11.287 18.715,12.014C18.762,12.198 18.762,12.391 18.715,12.576L17.647,12.856C17.713,13.216 17.757,13.581 17.778,13.947L17.778,18.981C17.765,19.287 17.653,19.58 17.459,19.816C16.472,20.001 15.462,20.02 14.47,19.871C13.778,19.444 14.208,18.725 13.984,18.145L4.901,18.145C4.723,18.763 4.62,19.798 4.415,19.871C3.402,20.043 2.367,20.043 1.353,19.871C1.139,19.596 1.021,19.257 1.017,18.908C0.961,18.181 0.961,17.492 0.961,16.783C0.961,15.467 0.961,14.15 1.017,12.824L0.024,12.569C-0.008,12.423 -0.008,12.271 0.024,12.124C0.305,11.397 0.679,10.835 1.641,10.917C1.754,10.917 1.968,10.698 2.034,10.535C2.392,9.727 2.705,8.899 2.971,8.056C3.345,6.796 4.461,5.9 5.772,5.806C6.286,5.716 6.819,5.652 7.335,5.571L7.363,5.606L7.358,5.611ZM3.221,11.224C7.253,12.052 11.412,12.052 15.444,11.224C15.101,10.218 14.756,9.317 14.513,8.407C14.352,7.685 13.701,7.178 12.961,7.2C11.024,7.118 9.087,7.055 7.149,7.036C6.517,7.06 5.89,7.155 5.28,7.318C5.001,7.372 4.755,7.535 4.598,7.772C4.074,8.871 3.682,10.007 3.223,11.224L3.221,11.224ZM4.015,15.509C4.35,15.527 4.685,15.509 5.015,15.455C5.272,15.399 5.492,15.237 5.623,15.01C5.669,14.874 5.457,14.538 5.268,14.456C4.507,14.11 3.727,13.806 2.931,13.548C2.539,13.423 2.091,13.448 1.997,13.985C1.809,14.776 1.997,15.214 2.604,15.339C3.087,15.415 3.574,15.466 4.062,15.493L4.015,15.509ZM14.79,15.509C15.282,15.475 15.772,15.415 16.258,15.327C16.958,15.173 16.809,14.619 16.789,14.14C16.77,13.66 16.51,13.431 16.128,13.54C15.169,13.817 14.233,14.163 13.325,14.575C12.911,14.766 13.063,15.293 13.53,15.395C13.948,15.455 14.369,15.491 14.791,15.503L14.79,15.509ZM10.74,2.201C10.737,2.953 10.124,3.559 9.372,3.556C8.62,3.559 8.007,2.953 8.003,2.201C8.003,1.451 9.372,0 9.372,0C9.372,0 10.74,1.452 10.74,2.201ZM6.119,3.212C6.116,3.723 5.7,4.135 5.189,4.132C4.678,4.135 4.261,3.723 4.259,3.212C4.259,2.703 5.189,1.716 5.189,1.716C5.189,1.716 6.119,2.703 6.119,3.212ZM14.486,3.212C14.484,3.723 14.067,4.135 13.556,4.132C13.045,4.135 12.628,3.723 12.626,3.212C12.626,2.703 13.556,1.716 13.556,1.716C13.556,1.716 14.486,2.703 14.486,3.212Z"
+ android:fillColor="#31456A"
+ android:fillAlpha="0.8"/>
</vector>
diff --git a/common/src/main/res/drawable/svg_car_weixiu.xml b/common/src/main/res/drawable/svg_car_weixiu.xml
index 4029c8d..d0c01e5 100644
--- a/common/src/main/res/drawable/svg_car_weixiu.xml
+++ b/common/src/main/res/drawable/svg_car_weixiu.xml
@@ -1,3 +1,18 @@
+<!--
+ ~ Copyright (C) 2026 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="19.973dp"
android:height="18.888dp"
@@ -5,5 +20,6 @@
android:viewportHeight="18.888">
<path
android:pathData="M6.923,2.217C6.923,3.434 5.924,4.433 4.707,4.433C3.489,4.433 2.49,3.434 2.49,2.217C2.49,0.999 3.489,0 4.707,0C5.924,0 6.923,0.999 6.923,2.217ZM13.417,12.082C11.544,12.082 10.045,13.612 10.045,15.485C10.045,17.358 11.544,18.888 13.417,18.888C15.29,18.888 16.789,17.358 16.789,15.485C16.789,13.612 15.259,12.082 13.417,12.082ZM13.417,17.046C12.574,17.046 11.856,16.359 11.856,15.485C11.856,14.611 12.543,13.924 13.417,13.924C14.26,13.924 14.978,14.611 14.978,15.485C14.978,16.328 14.26,17.046 13.417,17.046ZM14.322,6.775C14.198,6.244 9.671,1.342 8.516,2.092C7.704,2.622 8.391,3.497 8.391,3.497C9.92,3.871 12.886,7.368 12.886,7.368L8.141,9.21C7.579,9.553 6.549,9.553 6.549,11.458L6.549,14.142C6.549,14.985 7.579,15.922 8.391,15.922L9.171,15.922C9.171,15.922 9.14,15.547 9.14,15.422C9.14,13.081 11.013,11.145 13.323,11.145C15.634,11.145 17.507,13.112 17.507,15.454C17.507,15.61 17.507,15.953 17.476,15.953L19.973,15.953L19.973,4.527L14.322,6.775ZM7.798,11.426C6.892,9.647 10.576,9.553 10.576,9.553L7.798,11.426ZM8.765,7.212C8.765,7.212 7.954,6.65 6.518,7.305C4.644,8.148 4.957,4.87 3.021,4.215C3.021,4.215 1.054,4.215 0.211,7.524C0.211,7.524 -0.444,9.678 0.555,12.519L0.555,17.42C0.555,17.42 1.554,18.981 3.052,17.42L3.052,12.425C3.052,12.425 3.021,9.335 4.176,8.18C4.176,8.18 4.426,9.272 6.361,9.179C6.361,9.21 10.639,8.585 8.765,7.212Z"
- android:fillColor="#31456A"/>
+ android:fillColor="#31456A"
+ android:fillAlpha="0.8"/>
</vector>
diff --git a/common/src/main/res/drawable/svg_car_zhengbei.xml b/common/src/main/res/drawable/svg_car_zhengbei.xml
index 41f00d7..0975de5 100644
--- a/common/src/main/res/drawable/svg_car_zhengbei.xml
+++ b/common/src/main/res/drawable/svg_car_zhengbei.xml
@@ -1,3 +1,18 @@
+<!--
+ ~ Copyright (C) 2026 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20.006dp"
android:height="15.955dp"
@@ -5,5 +20,6 @@
android:viewportHeight="15.955">
<path
android:pathData="M7.853,0.159C9.271,-0.053 10.713,-0.053 12.131,0.159C13.128,0.358 14.125,0.518 15.062,0.777C15.76,0.955 16.317,1.478 16.538,2.163Q17.146,3.878 17.814,5.563C17.894,5.753 18.133,6.032 18.273,6.012C19.064,5.878 19.817,6.401 19.968,7.188C20.018,7.391 20.018,7.604 19.968,7.807L18.831,8.116C18.902,8.511 18.948,8.911 18.971,9.312L18.971,14.836C18.958,15.17 18.839,15.491 18.632,15.753C17.58,15.956 16.5,15.976 15.441,15.813C14.703,15.344 15.162,14.557 14.923,13.919L5.231,13.919C5.042,14.597 4.932,15.733 4.713,15.813C3.631,16.003 2.524,16.003 1.442,15.813C1.213,15.508 1.087,15.138 1.083,14.756C1.023,13.959 1.023,13.201 1.023,12.423C1.023,10.977 1.023,9.531 1.083,8.076L0.026,7.797C-0.009,7.636 -0.009,7.469 0.026,7.308C0.325,6.51 0.724,5.892 1.751,5.982C1.871,5.982 2.1,5.743 2.17,5.563C2.551,4.674 2.884,3.766 3.167,2.841C3.551,1.475 4.744,0.492 6.158,0.378C6.707,0.279 7.275,0.209 7.823,0.119L7.853,0.159ZM3.446,6.321C7.746,7.231 12.188,7.231 16.488,6.321C16.119,5.214 15.75,4.227 15.491,3.23C15.332,2.446 14.636,1.888 13.836,1.904C11.772,1.814 9.698,1.744 7.634,1.724C6.96,1.751 6.291,1.855 5.64,2.033C5.34,2.095 5.078,2.275 4.912,2.532C4.354,3.738 3.935,4.985 3.446,6.321ZM4.294,11.027C4.651,11.046 5.008,11.026 5.361,10.967C5.636,10.904 5.872,10.726 6.009,10.479C6.059,10.329 5.829,9.96 5.63,9.871C4.819,9.491 3.987,9.158 3.137,8.873C2.718,8.734 2.24,8.764 2.14,9.352C1.941,10.219 2.14,10.698 2.788,10.838C3.297,10.937 3.785,10.957 4.344,11.007L4.294,11.027ZM15.79,11.027C16.315,10.99 16.838,10.923 17.356,10.828C18.103,10.658 17.944,10.05 17.924,9.522C17.904,8.993 17.625,8.744 17.216,8.863C16.192,9.168 15.192,9.548 14.225,10C13.786,10.21 13.946,10.788 14.444,10.897C14.89,10.964 15.339,11.004 15.79,11.017L15.79,11.027Z"
- android:fillColor="#31456A"/>
+ android:fillColor="#31456A"
+ android:fillAlpha="0.8"/>
</vector>
diff --git a/common/src/main/res/drawable/svg_filter2.xml b/common/src/main/res/drawable/svg_filter2.xml
new file mode 100644
index 0000000..5cd9451
--- /dev/null
+++ b/common/src/main/res/drawable/svg_filter2.xml
@@ -0,0 +1,33 @@
+<!--
+ ~ Copyright (C) 2026 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="12dp"
+ android:height="12dp"
+ android:viewportWidth="12"
+ android:viewportHeight="12">
+ <path
+ android:pathData="M3.88,5.476L1.398,3.491L1.35,3.426Q0.768,2.819 1.109,2.007Q1.457,1.178 2.347,1.2L9.23,1.2Q10.097,1.2 10.459,2.001Q10.804,2.799 10.219,3.438L10.211,3.446L10.144,3.513L7.67,5.489L7.67,9.43Q7.67,9.979 7.29,10.368Q6.91,10.758 6.35,10.77L6.33,10.77Q5.98,10.77 5.674,10.606L4.581,9.99Q3.88,9.621 3.88,8.82L3.88,5.476ZM4.88,8.82L4.88,5.31Q4.88,4.987 4.617,4.786L2.122,2.789L2.109,2.772L2.084,2.746Q1.942,2.605 2.031,2.393Q2.115,2.194 2.325,2.2L2.333,2.2L9.23,2.2Q9.451,2.2 9.541,2.399Q9.627,2.597 9.487,2.756L9.476,2.767L6.896,4.827L6.876,4.846Q6.67,5.053 6.67,5.34L6.67,9.43Q6.67,9.763 6.35,9.77L6.33,9.77Q6.232,9.77 6.165,9.734L5.058,9.11L5.05,9.106Q4.88,9.018 4.88,8.82Z"
+ android:fillColor="#006BE1"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M8.782,8.99C9.157,8.99 9.702,8.99 10.077,8.99C10.314,8.99 10.499,9.186 10.499,9.423C10.499,9.654 10.314,9.85 10.077,9.85C9.702,9.85 9.157,9.85 8.782,9.85C8.544,9.85 8.359,9.654 8.359,9.417C8.359,9.186 8.544,8.99 8.782,8.99"
+ android:fillColor="#006BE1"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M8.782,7.27C9.157,7.27 9.702,7.27 10.077,7.27C10.314,7.27 10.499,7.466 10.499,7.703C10.499,7.934 10.314,8.13 10.077,8.13C9.702,8.13 9.157,8.13 8.782,8.13C8.544,8.13 8.359,7.934 8.359,7.697C8.359,7.466 8.544,7.27 8.782,7.27"
+ android:fillColor="#006BE1"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/common/src/main/res/layout/common_item_image_empty.xml b/common/src/main/res/layout/common_item_image_empty.xml
index a182daa..2448d98 100644
--- a/common/src/main/res/layout/common_item_image_empty.xml
+++ b/common/src/main/res/layout/common_item_image_empty.xml
@@ -15,7 +15,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
- android:src="@mipmap/ic_no_img"
+ android:src="@mipmap/icon_default"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:riv_corner_radius="@dimen/dp_5" />
diff --git a/common/src/main/res/layout/dialog_loading.xml b/common/src/main/res/layout/dialog_loading.xml
index 04ecea8..96bd1b4 100644
--- a/common/src/main/res/layout/dialog_loading.xml
+++ b/common/src/main/res/layout/dialog_loading.xml
@@ -32,12 +32,11 @@
<ProgressBar
android:id="@+id/indicatorView"
- android:layout_width="@dimen/dp_45"
- android:layout_height="@dimen/dp_45"
- android:layout_marginTop="@dimen/dp_10"
+ android:layout_width="@dimen/dp_30"
+ android:layout_height="@dimen/dp_30"
+ android:layout_marginTop="@dimen/dp_24"
android:indeterminateDrawable="@drawable/circular_progress"
android:indeterminate="true"
- app:layout_constraintBottom_toTopOf="@+id/tv_tips"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
@@ -50,11 +49,11 @@
android:layout_marginHorizontal="@dimen/dp_5"
android:layout_marginLeft="@dimen/dp_20"
android:maxLines="1"
+ android:layout_marginTop="@dimen/dp_10"
android:text="加载中..."
android:textColor="@color/white"
android:textSize="@dimen/sp_14"
android:visibility="visible"
- app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/indicatorView"
diff --git a/common/src/main/res/layout/dialog_notice.xml b/common/src/main/res/layout/dialog_notice.xml
new file mode 100644
index 0000000..9b4f067
--- /dev/null
+++ b/common/src/main/res/layout/dialog_notice.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_while_bg_5">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_32"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:textColor="@color/gray_10"
+ android:textSize="@dimen/sp_18"
+ android:gravity="center"
+ android:textStyle="bold"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:text="文本内容" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/content"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_16"
+ android:layout_marginHorizontal="@dimen/dp_20"
+ android:textColor="@color/gray_10"
+ android:textSize="@dimen/sp_14"
+ android:gravity="center"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/title"
+ tools:text="文本内容" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:layout_marginTop="@dimen/dp_30"
+ android:background="@color/gray_4"
+ app:layout_constraintTop_toBottomOf="@+id/content" />
+
+
+ <Button
+ android:id="@+id/btnLeft"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/dp_60"
+ android:layout_marginTop="@dimen/dp_30"
+ android:background="@android:color/transparent"
+ android:text="取消"
+ android:textColor="@color/gray_10"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:layout_constraintHorizontal_weight="1"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/content"
+ app:layout_constraintRight_toLeftOf="@+id/btnRight" />
+
+ <Button
+ android:id="@+id/btnRight"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/dp_60"
+ android:background="@android:color/transparent"
+ android:layout_marginTop="@dimen/dp_30"
+ android:text="确定"
+ android:textColor="@color/blue_5"
+ android:textSize="@dimen/sp_16"
+ android:textStyle="bold"
+ app:layout_constraintHorizontal_weight="1"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintLeft_toRightOf="@+id/btnLeft"
+ app:layout_constraintTop_toBottomOf="@id/content" />
+
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/common/src/main/res/layout/layout_empty_view2.xml b/common/src/main/res/layout/layout_empty_view2.xml
new file mode 100644
index 0000000..b5885b1
--- /dev/null
+++ b/common/src/main/res/layout/layout_empty_view2.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <data>
+
+ </data>
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/tips"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dp_80"
+ android:gravity="center"
+ android:text="暂无搜索结果"
+ android:textColor="@color/gray_7"
+ android:textSize="@dimen/sp_14" />
+ </FrameLayout>
+</layout>
\ No newline at end of file
diff --git a/common/src/main/res/mipmap-xhdpi/icon_default.png b/common/src/main/res/mipmap-xhdpi/icon_default.png
new file mode 100644
index 0000000..84c5031
--- /dev/null
+++ b/common/src/main/res/mipmap-xhdpi/icon_default.png
Binary files differ
diff --git a/common/src/main/res/mipmap-xhdpi/icon_default2.png b/common/src/main/res/mipmap-xhdpi/icon_default2.png
new file mode 100644
index 0000000..461cfcd
--- /dev/null
+++ b/common/src/main/res/mipmap-xhdpi/icon_default2.png
Binary files differ
diff --git a/common/src/main/res/mipmap-xhdpi/icon_default3.png b/common/src/main/res/mipmap-xhdpi/icon_default3.png
new file mode 100644
index 0000000..21e9375
--- /dev/null
+++ b/common/src/main/res/mipmap-xhdpi/icon_default3.png
Binary files differ
diff --git a/common/src/main/res/mipmap-xhdpi/icon_default4.png b/common/src/main/res/mipmap-xhdpi/icon_default4.png
new file mode 100644
index 0000000..f5a627b
--- /dev/null
+++ b/common/src/main/res/mipmap-xhdpi/icon_default4.png
Binary files differ
diff --git a/common/src/main/res/mipmap-xhdpi/icon_default5.png b/common/src/main/res/mipmap-xhdpi/icon_default5.png
new file mode 100644
index 0000000..c120d59
--- /dev/null
+++ b/common/src/main/res/mipmap-xhdpi/icon_default5.png
Binary files differ
diff --git a/common/src/main/res/mipmap/ic_slide_gray_r.png b/common/src/main/res/mipmap/ic_slide_gray_r.png
new file mode 100644
index 0000000..38a6d51
--- /dev/null
+++ b/common/src/main/res/mipmap/ic_slide_gray_r.png
Binary files differ
diff --git a/common/src/main/res/values/attrs.xml b/common/src/main/res/values/attrs.xml
index 3297403..f446962 100644
--- a/common/src/main/res/values/attrs.xml
+++ b/common/src/main/res/values/attrs.xml
@@ -50,9 +50,13 @@
<attr name="backgroundCornerRadius" format="dimension" />
<!-- 滑块圆角半径(当 thumbShape=roundRect 时有效) -->
<attr name="thumbCornerRadius" format="dimension" />
+ <!-- 是否能够使用 -->
+ <attr name="enable" format="boolean" />
</declare-styleable>
<declare-styleable name="SlideSwitchView">
+ <!-- 是否能手动点击 -->
+ <attr name="switchEnable" format="boolean"/>
<!-- 背景颜色 -->
<attr name="switchBackgroundColorUnchecked" format="color"/>
<attr name="switchBackgroundColorChecked" format="color"/>
diff --git a/common/src/main/res/values/colors.xml b/common/src/main/res/values/colors.xml
index bf38d28..00f443a 100644
--- a/common/src/main/res/values/colors.xml
+++ b/common/src/main/res/values/colors.xml
@@ -67,6 +67,7 @@
<color name="gray_8">#DB31456A</color>
<color name="gray_9">#FF31456A</color>
<color name="gray_10">#FF0F1521</color>
+ <color name="gray_11">#0831456A</color>
<!-- 中性色语义化别名 -->
<color name="color_background">@color/gray_1</color>
@@ -79,5 +80,6 @@
<color name="color_transparent">#00000000</color>
+ <color name="color_838fa6">#ff838fa6</color>
</resources>
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index b0670a8..c5a9a1d 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -25,6 +25,7 @@
lifecycleVersion = "2.10.0"
mmkv = "2.3.0"
okhttp = "4.9.3" # 升级有兼容性问题
+okhttpLoggingInterceptor = "4.9.3" # 升级有兼容性问题
pdfrendererview = "1.0.10"
photoview = "2.3.0"
pictureselector = "v3.11.2"
@@ -32,10 +33,14 @@
retrofit = "3.0.0"
roundedimageview = "2.3.0"
utilcodex = "1.31.1"
-xdmapLocationSearch = "latest.integration"
+navi3dmapLocationSearch = "11.1.001_3dmap11.1.001_loc11.1.001_sea9.7.4"
xxpermissions = "20.0"
flexbox = "3.0.0"
crashreport = "latest.release"
+alicloud = "3.10.1"
+shadowLayout = "3.4.5"
+jsoup = "1.22.2"
+activityKtx = "1.8.0"
[libraries]
@@ -57,6 +62,8 @@
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutinesCore" }
# okhttp
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
+okhttp-logging-interceptor = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttpLoggingInterceptor" }
+
# retrofit
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
retrofit-converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "retrofit" }
@@ -87,8 +94,8 @@
image-circle = { module = "de.hdodenhof:circleimageview", version.ref = "circleimageview" }
image-rounde = { module = "com.makeramen:roundedimageview", version.ref = "roundedimageview" }
image-photoview = { module = "com.github.chrisbanes:PhotoView", version.ref = "photoview" }
-# amap 3D地图so及jar,已经包含定位和搜索功能无需单独引用
-xdmap-location-search = { module = "com.amap.api:3dmap-location-search", version.ref = "xdmapLocationSearch" }
+# amap 导航3D地图so及jar,已经包含定位和搜索功能无需单独引用
+navi-xdmap-location-search = { module = "com.amap.api:navi-3dmap-location-search", version.ref = "navi3dmapLocationSearch" }
# mmkv
mmkv = { module = "com.tencent:mmkv", version.ref = "mmkv" }
# eventbus
@@ -107,7 +114,18 @@
# 腾讯bugly
crashreport = { module = "com.tencent.bugly:crashreport", version.ref = "crashreport" }
nativecrashreport = { module = "com.tencent.bugly:nativecrashreport", version.ref = "crashreport" }
+shadowLayout = { module = "com.github.lihangleo2:ShadowLayout", version.ref = "shadowLayout" }
huawei-agconnect-core = { module = "com.huawei.agconnect:agconnect-core", version.ref = "huawei" }
+jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" }
+
+# 阿里云推送及厂商
+alicloud = { module = "com.aliyun.ams:alicloud-android-push", version.ref = "alicloud" }
+alicloud-android-third-push = { module = "com.aliyun.ams:alicloud-android-third-push", version.ref = "alicloud" }
+alicloud-android-third-push-huawei = { module = "com.aliyun.ams:alicloud-android-third-push-huawei", version.ref = "alicloud" }
+alicloud-android-third-push-honor = { module = "com.aliyun.ams:alicloud-android-third-push-honor", version.ref = "alicloud" }
+alicloud-android-third-push-oppo = { module = "com.aliyun.ams:alicloud-android-third-push-oppo", version.ref = "alicloud" }
+alicloud-android-third-push-vivo = { module = "com.aliyun.ams:alicloud-android-third-push-vivo", version.ref = "alicloud" }
+androidx-activity-ktx = { group = "androidx.activity", name = "activity-ktx", version.ref = "activityKtx" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
diff --git a/settings.gradle.kts b/settings.gradle.kts
index fa71671..38e838a 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -37,7 +37,8 @@
maven("https://maven.aliyun.com/nexus/content/repositories/releases/")
// 配置HMS Core SDK的Maven仓地址,集成华为通道需要。
maven("https://developer.huawei.com/repo/")
-
+ // 荣耀开发者 Maven 仓库,集成荣耀推送通道需要。
+ maven("https://developer.hihonor.com/repo")
}
}
--
Gitblit v1.7.1