feat(servicing): 新增快速登录功能并优化用户信息处理- 新增 FastLoginRequest 数据类用于快速登录
- 添加 iaiCompareFace API 接口用于人脸识别比较 - 更新 DriverInfo 数据类,增加 loginLogId 字段- 重构 GlobalData 中的用户信息存储逻辑,使用 MMKV替代数据库 - 优化 InServicingBottomView 中的订单放弃和拨打电话功能 - 更新 JpushBean,增加 userOrderId 字段 - 修改 AndroidManifest.xml 中的权限声明,使用动态应用ID
This commit is contained in:
@ -3,8 +3,9 @@
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-sdk tools:overrideLibrary="androidx.camera.view,androidx.camera:camera-camera2,androidx.camera.camera2,androidx.camera.lifecycle,androidx.camera.core" />
|
||||
|
||||
<permission
|
||||
android:name="com.za.rescue.dealer.permission.JPUSH_MESSAGE"
|
||||
android:name="${applicationId}.permission.JPUSH_MESSAGE"
|
||||
android:protectionLevel="signature" /> <!-- 位置相关权限 -->
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
@ -78,9 +79,7 @@
|
||||
<activity
|
||||
android:name="com.za.ui.main.ServiceLauncherActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.Dealer">
|
||||
|
||||
</activity>
|
||||
android:theme="@style/Theme.Dealer" />
|
||||
<activity
|
||||
android:name="com.za.ui.main.ServicingMainActivity"
|
||||
android:exported="false"
|
||||
@ -162,6 +161,7 @@
|
||||
<activity
|
||||
android:name="com.za.ui.camera.ZdCameraXActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/Theme.Dealer"
|
||||
android:screenOrientation="portrait">
|
||||
<meta-data
|
||||
android:name="android.app.lib_name"
|
||||
@ -202,7 +202,6 @@
|
||||
android:exported="true"
|
||||
tools:node="replace">
|
||||
<intent-filter>
|
||||
|
||||
<action android:name="cn.jpush.android.intent.NOTIFICATION_RECEIVED_ACTION" />
|
||||
<action android:name="cn.jpush.android.intent.NOTIFICATION_OPENED_ACTION" />
|
||||
<action android:name="cn.jpush.android.intent.CONNECTION" />
|
||||
@ -243,6 +242,7 @@
|
||||
<category android:name="${applicationId}" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service
|
||||
android:name="cn.jpush.android.service.DaemonService"
|
||||
android:enabled="true"
|
||||
|
@ -30,6 +30,7 @@ data class GeneralInfo(
|
||||
val vehicleName : String? = null,
|
||||
val vehicleState : Int? = null, //车辆状态 0 空闲 1 忙碌
|
||||
val supplierId : Int? = null,
|
||||
val loginLogId : Int? = null,
|
||||
val supplierName : String? = null,
|
||||
val supplierType : Int?,
|
||||
val plateNumber : String? = null, //车牌号
|
||||
@ -216,4 +217,4 @@ data class AppNewDriverInfoDTO(val userId : Int? = null,
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ data class JpushBean(
|
||||
val carModel: String? = null,//车辆型号 "carModel":"秦"
|
||||
val contract: String? = null, //车辆型号 "carModel":"秦"
|
||||
val typeDesc: String? = null, //推送的附加消息 revoke 撤回 giveUp放弃 reDispatch改派
|
||||
|
||||
val userOrderId: Int? = null,
|
||||
val carNo: String? = null, //客户车车牌号 "carNo":"粤AF53918"
|
||||
val taskState: String? = null, //订单状态 "taskState":"GOTO"
|
||||
val address: String? = null, //任务地址 "address":"广东省广州市白云区107国道石井凰岗路342号(白云黄石、同德围地区近庆丰兴隆公园)美景大酒店"
|
||||
|
15
servicing/src/main/java/com/za/bean/PreviewBean.kt
Normal file
15
servicing/src/main/java/com/za/bean/PreviewBean.kt
Normal file
@ -0,0 +1,15 @@
|
||||
package com.za.bean
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import com.za.bean.db.order.OrderInfo
|
||||
|
||||
class OrderInfoPreviewParameters : PreviewParameterProvider<OrderInfo> {
|
||||
override val values : Sequence<OrderInfo>
|
||||
get() = sequenceOf(OrderInfo(taskCode = "123456789",
|
||||
address = "上海市浦东新区",
|
||||
distAddress = "上海市浦东新区",
|
||||
addressProperty = "服务中",
|
||||
serviceTypeName = "救援",
|
||||
plateNumber = "沪A12345",
|
||||
importantTip = "请保持电话畅通,服务人员将尽快联系您。"))
|
||||
}
|
@ -1,5 +1,11 @@
|
||||
package com.za.bean.request
|
||||
|
||||
data class DriverFaceCompareRequest(val vehicleId: Int? = null, val driverId: Int? = null, val photoUrl: String? = null)
|
||||
data class DriverFaceCompareRequest(val vehicleId : Int? = null,
|
||||
val driverId : Int? = null,
|
||||
val photoUrl : String? = null)
|
||||
|
||||
data class DriverFaceCompareBean(val flowId: Int? = null, val shortLink: String? = null, val url: String? = null)
|
||||
data class DriverFaceCompareBean(val flowId : Int? = null,
|
||||
val shortLink : String? = null,
|
||||
val url : String? = null)
|
||||
|
||||
data class IaiCompareFaceBean(val score : Float? = null, val compareResult : Boolean? = null)
|
@ -15,6 +15,8 @@ data class LoginRequest(
|
||||
var dashboardPath: String? = null //里程表照片路径
|
||||
)
|
||||
|
||||
data class FastLoginRequest(var deviceId: String? = null)
|
||||
|
||||
data class PhoneBean(
|
||||
var versionRelease: String? = null,//系统版本
|
||||
var model: String? = null,//手机型号
|
||||
|
@ -5,60 +5,82 @@ import com.amap.api.location.AMapLocation
|
||||
import com.blankj.utilcode.util.AppUtils
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.za.bean.db.order.OrderInfo
|
||||
import com.za.common.log.LogUtil
|
||||
import com.za.room.RoomHelper
|
||||
import com.za.room.db.user.DriverInfoBean
|
||||
|
||||
object GlobalData {
|
||||
lateinit var application : Application
|
||||
private val mmkv : MMKV by lazy { MMKV.defaultMMKV() }
|
||||
var activityCount : Int = 0
|
||||
var isMaster = AppUtils.getAppPackageName() == "com.za.rescue.dealer"
|
||||
|
||||
var token : String? = null
|
||||
get() {
|
||||
return MMKV.defaultMMKV().decodeString("ZD_TOKEN", null)
|
||||
return mmkv.decodeString("ZD_TOKEN", null)
|
||||
}
|
||||
set(value) {
|
||||
MMKV.defaultMMKV().encode("ZD_TOKEN", value)
|
||||
mmkv.encode("ZD_TOKEN", value)
|
||||
field = value
|
||||
}
|
||||
|
||||
var regid : String? = null
|
||||
get() {
|
||||
return MMKV.defaultMMKV().decodeString("regid", null)
|
||||
return mmkv.decodeString("regid", null)
|
||||
}
|
||||
set(value) {
|
||||
MMKV.defaultMMKV().encode("regid", value)
|
||||
mmkv.encode("regid", value)
|
||||
field = value
|
||||
}
|
||||
|
||||
var aesKey : String? = null
|
||||
get() {
|
||||
return MMKV.defaultMMKV().decodeString("AES_KEY", null)
|
||||
return mmkv.decodeString("AES_KEY", null)
|
||||
}
|
||||
set(value) {
|
||||
MMKV.defaultMMKV().encode("AES_KEY", value)
|
||||
mmkv.encode("AES_KEY", value)
|
||||
field = value
|
||||
}
|
||||
|
||||
//新订单是否已经被处理
|
||||
var isHandlerNewOrder : Boolean? = false
|
||||
|
||||
var driverInfoBean : DriverInfoBean? = null
|
||||
private val lock = Any()
|
||||
var driverInfoBean : DriverInfoBean?
|
||||
get() {
|
||||
val driverInfoBean = RoomHelper.db?.driverInfoDao()?.getDriverInfoFromUserId()
|
||||
synchronized(lock) {
|
||||
val driverInfoBean =
|
||||
mmkv.decodeParcelable("driverInfoBean", DriverInfoBean::class.java)
|
||||
LogUtil.print("driverInfo get", "driverInfoBean = $driverInfoBean")
|
||||
return driverInfoBean
|
||||
}
|
||||
}
|
||||
set(value) {
|
||||
synchronized(lock) {
|
||||
mmkv.encode("driverInfoBean", value)
|
||||
if (value != null) {
|
||||
lastLoginBean = value
|
||||
}
|
||||
LogUtil.print("driverInfo set", "driverInfoBean = $value")
|
||||
}
|
||||
}
|
||||
|
||||
var lastLoginBean : DriverInfoBean? = null
|
||||
get() {
|
||||
val driverInfoBean = mmkv.decodeParcelable("lastLoginBean", DriverInfoBean::class.java)
|
||||
field = driverInfoBean
|
||||
return driverInfoBean
|
||||
}
|
||||
set(value) {
|
||||
RoomHelper.db?.driverInfoDao()?.updateDriverInfo(value)
|
||||
mmkv.encode("lastLoginBean", value)
|
||||
}
|
||||
|
||||
var currentOrder : OrderInfo? = null
|
||||
get() {
|
||||
return MMKV.defaultMMKV().decodeParcelable("currentOrder", OrderInfo::class.java)
|
||||
return mmkv.decodeParcelable("currentOrder", OrderInfo::class.java)
|
||||
}
|
||||
set(value) {
|
||||
MMKV.defaultMMKV().encode("currentOrder", value)
|
||||
mmkv.encode("currentOrder", value)
|
||||
if (RoomHelper.db?.orderDao()?.getCurrentOrder() == null && value != null) {
|
||||
RoomHelper.db?.orderDao()?.insertOrder(value)
|
||||
} else if (value != null) {
|
||||
@ -78,10 +100,10 @@ object GlobalData {
|
||||
|
||||
var loginTime : Long? = null
|
||||
get() {
|
||||
return MMKV.defaultMMKV().decodeLong("loginTime", System.currentTimeMillis())
|
||||
return mmkv.decodeLong("loginTime", System.currentTimeMillis())
|
||||
}
|
||||
set(value) {
|
||||
MMKV.defaultMMKV().encode("loginTime", value ?: System.currentTimeMillis())
|
||||
mmkv.encode("loginTime", value ?: System.currentTimeMillis())
|
||||
field = value
|
||||
}
|
||||
|
||||
@ -89,6 +111,7 @@ object GlobalData {
|
||||
token = null
|
||||
aesKey = null
|
||||
currentLocation = null
|
||||
driverInfoBean = null
|
||||
loginTime = null
|
||||
}
|
||||
|
||||
|
@ -37,12 +37,14 @@ import com.za.bean.request.CustomerPaymentCreateRequest
|
||||
import com.za.bean.request.DriverFaceCompareBean
|
||||
import com.za.bean.request.DriverFaceCompareRequest
|
||||
import com.za.bean.request.ElectronOrderResponse
|
||||
import com.za.bean.request.FastLoginRequest
|
||||
import com.za.bean.request.FetchVehicleMaintenanceSubmitHistoryRequestBean
|
||||
import com.za.bean.request.GeneralInfoRequest
|
||||
import com.za.bean.request.GiveUpTaskRequest
|
||||
import com.za.bean.request.HistoryDetailRequest
|
||||
import com.za.bean.request.HistoryPhotoTemplateRequest
|
||||
import com.za.bean.request.HistoryTasksRequest
|
||||
import com.za.bean.request.IaiCompareFaceBean
|
||||
import com.za.bean.request.LoginRequest
|
||||
import com.za.bean.request.OrderListRequest
|
||||
import com.za.bean.request.OrderPhotoOcrRecognizeRequest
|
||||
@ -116,6 +118,9 @@ interface ApiService {
|
||||
@POST("/driverApp/task/login")
|
||||
fun login(@Body info : LoginRequest) : Observable<BaseResponse<DriverInfo?>>
|
||||
|
||||
@POST("/driverApp/supplier/fastLogin")
|
||||
fun fastLogin(@Body info : FastLoginRequest) : Observable<BaseResponse<DriverInfo?>>
|
||||
|
||||
//获取该手机号下面服务商列表
|
||||
@POST("/driverApp/supplier/getDriverListInfo")
|
||||
fun getDriverListInfo(@Body info : VerifyCodeRequest) : Observable<BaseResponse<List<AppNewDriverInfoDTO>>>
|
||||
@ -271,4 +276,7 @@ interface ApiService {
|
||||
|
||||
@POST("driverApp/base/getVoiceUrl")
|
||||
fun getVoiceUrl(@Body info : AppNewOrderVoiceRequest) : Observable<BaseResponse<String>>
|
||||
}
|
||||
|
||||
@POST("driverApp/supplier/iaiCompareFace")
|
||||
fun iaiCompareFace(@Body info : DriverFaceCompareRequest) : Observable<BaseResponse<IaiCompareFaceBean>>
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package com.za.net
|
||||
|
||||
import android.net.ParseException
|
||||
import com.blankj.utilcode.util.ActivityUtils
|
||||
import com.blankj.utilcode.util.NetworkUtils
|
||||
import com.blankj.utilcode.util.ToastUtils
|
||||
import com.google.gson.JsonParseException
|
||||
import com.za.base.Const
|
||||
@ -105,21 +104,6 @@ abstract class BaseObserver<T> : Observer<BaseResponse<T>> {
|
||||
GlobalData.clearUserCache()
|
||||
ZdLocationManager.stopContinuousLocation()
|
||||
ActivityUtils.finishAllActivities()
|
||||
// val oldLoginInfo: LoginInfo = DbManager.getInstance(context).queryLoginInfo()
|
||||
// val loginInfo: LoginInfo = LoginInfo()
|
||||
// loginInfo.setSupplierId(oldLoginInfo.getSupplierId())
|
||||
// loginInfo.setSupplierCode(oldLoginInfo.getSupplierCode())
|
||||
// loginInfo.setJobNumber(oldLoginInfo.getJobNumber())
|
||||
// loginInfo.setPassword(oldLoginInfo.getPassword())
|
||||
// DbManager.getInstance(context).deleteLoginInfo()
|
||||
// DbManager.getInstance(context).saveLoginInfo(loginInfo)
|
||||
// SPKit.saveString(context, "userId", "-1")
|
||||
// SPKit.saveString(context, "vehicleId", "-1")
|
||||
//
|
||||
// LBSManager.getInstance().cancel()
|
||||
// DaemonService.stopService()
|
||||
// //跳转
|
||||
// RsaRouter.navigateNoFlag(context, "/page/login")
|
||||
} catch (e: Exception) {
|
||||
LogUtil.print("handlerTokenExpired", e)
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import com.za.common.util.DeviceUtil
|
||||
import com.za.ext.toJson
|
||||
import com.za.offline.OfflineManager
|
||||
import com.za.room.RoomHelper
|
||||
import com.za.room.db.user.DriverInfoBean
|
||||
import com.za.ui.new_order.NewOrderActivity
|
||||
import com.za.ui.order_report.ReportFloatingManager
|
||||
import com.za.water_marker.WaterMarkerTemplateManager
|
||||
@ -113,6 +114,8 @@ object CommonMethod {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
private var lastFetchGenerateInfoTime : Long = 0L
|
||||
fun getGenerateInfo(vehicleId : Int? = null,
|
||||
userId : Int? = null,
|
||||
success : (GeneralInfo) -> Unit = {},
|
||||
@ -130,22 +133,46 @@ object CommonMethod {
|
||||
LogUtil.print("getGenerateInfo", "获取车辆信息失败")
|
||||
return
|
||||
}
|
||||
val driverInfoBean = GlobalData.driverInfoBean
|
||||
GlobalData.driverInfoBean = driverInfoBean?.copy(vehicleId = it.vehicleId,
|
||||
vehicleName = it.vehicleName,
|
||||
userName = it.userName,
|
||||
userPhone = it.userPhone,
|
||||
plateNumber = it.plateNumber,
|
||||
vehicleState = it.vehicleState,
|
||||
supplierType = it.supplierType,
|
||||
userPortrait = it.userPortrait,
|
||||
userId = it.userId,
|
||||
supplierId = it.supplierId,
|
||||
deviceId = it.deviceId,
|
||||
supplierName = it.supplierName,
|
||||
authStatus = it.authStatus,
|
||||
serviceList = it.serviceList?.toString())
|
||||
|
||||
if (GlobalData.driverInfoBean != null && (System.currentTimeMillis() - lastFetchGenerateInfoTime < 1000 * 10)) {
|
||||
LogUtil.print("getGenerateInfo", "获取车辆信息成功,但是时间间隔小于10秒,不更新车辆信息")
|
||||
success(it)
|
||||
return
|
||||
}
|
||||
if (GlobalData.driverInfoBean == null) {
|
||||
GlobalData.driverInfoBean = DriverInfoBean(vehicleId = it.vehicleId,
|
||||
vehicleName = it.vehicleName,
|
||||
userName = it.userName,
|
||||
loginLogId = it.loginLogId,
|
||||
userPhone = it.userPhone,
|
||||
plateNumber = it.plateNumber,
|
||||
vehicleState = it.vehicleState,
|
||||
supplierType = it.supplierType,
|
||||
userPortrait = it.userPortrait,
|
||||
userId = it.userId,
|
||||
supplierId = it.supplierId,
|
||||
deviceId = it.deviceId,
|
||||
supplierName = it.supplierName,
|
||||
authStatus = it.authStatus,
|
||||
serviceList = it.serviceList?.toString())
|
||||
} else {
|
||||
GlobalData.driverInfoBean =
|
||||
GlobalData.driverInfoBean?.copy(vehicleId = it.vehicleId,
|
||||
vehicleName = it.vehicleName,
|
||||
userName = it.userName,
|
||||
userPhone = it.userPhone,
|
||||
plateNumber = it.plateNumber,
|
||||
vehicleState = it.vehicleState,
|
||||
supplierType = it.supplierType,
|
||||
userPortrait = it.userPortrait,
|
||||
userId = it.userId,
|
||||
loginLogId = it.loginLogId,
|
||||
supplierId = it.supplierId,
|
||||
deviceId = it.deviceId,
|
||||
supplierName = it.supplierName,
|
||||
authStatus = it.authStatus,
|
||||
serviceList = it.serviceList?.toString())
|
||||
}
|
||||
lastFetchGenerateInfoTime = System.currentTimeMillis()
|
||||
LogUtil.print("GlobalData.driverInfoBean",
|
||||
"${GlobalData.driverInfoBean?.toJson()}}")
|
||||
|
||||
|
@ -11,7 +11,7 @@ import com.za.room.db.GlobalRoom
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
object RoomHelper {
|
||||
const val VERSION: Int = 37
|
||||
const val VERSION: Int = 38
|
||||
private lateinit var mContext: Context
|
||||
var db: GlobalRoom? = null
|
||||
|
||||
|
@ -18,14 +18,12 @@ import com.za.room.db.ele_work.EleWorkOrderDao
|
||||
import com.za.room.db.order.ChangeBatteryDao
|
||||
import com.za.room.db.order.OrderDao
|
||||
import com.za.room.db.order.PhotoTemplateDao
|
||||
import com.za.room.db.user.DriverInfoBean
|
||||
import com.za.room.db.user.DriverInfoDao
|
||||
import com.za.room.db.user.LocalResourceBean
|
||||
import com.za.room.db.user.LocalResourceDao
|
||||
import com.za.room.db.water_marker.WaterMarkerDao
|
||||
|
||||
|
||||
@Database(entities = [EleWorkOrderBean::class, EleCarDamagePhotoBean::class, LocalResourceBean::class, WaterMarkerTemplateBean::class, WaterMarkerItemBean::class, ChangeBatteryPhoto::class, NewPhotoTemplateBean::class, OrderInfo::class, OfflineUpdateTaskBean::class, DriverInfoBean::class, PhotoTemplateInfo::class],
|
||||
@Database(entities = [EleWorkOrderBean::class, EleCarDamagePhotoBean::class, LocalResourceBean::class, WaterMarkerTemplateBean::class, WaterMarkerItemBean::class, ChangeBatteryPhoto::class, NewPhotoTemplateBean::class, OrderInfo::class, OfflineUpdateTaskBean::class, PhotoTemplateInfo::class],
|
||||
version = RoomHelper.VERSION,
|
||||
exportSchema = false)
|
||||
abstract class GlobalRoom : RoomDatabase() {
|
||||
@ -43,7 +41,5 @@ abstract class GlobalRoom : RoomDatabase() {
|
||||
|
||||
abstract fun offlineTaskDao() : OfflineDao
|
||||
|
||||
abstract fun driverInfoDao() : DriverInfoDao
|
||||
|
||||
abstract fun localResourceDao() : LocalResourceDao
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
package com.za.room.db.user
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
|
||||
@Entity(tableName = "driver_info")
|
||||
data class DriverInfoBean(
|
||||
@PrimaryKey(autoGenerate = false) val userId : Int? = null, //用户id
|
||||
val userId : Int? = null, //用户id
|
||||
val userName : String? = null, //用户姓名
|
||||
val userPhone : String? = null, //用户手机号
|
||||
val userPortrait : String? = null, //用户头像
|
||||
@ -23,4 +22,59 @@ data class DriverInfoBean(
|
||||
val vehicleState : Int? = null, //车辆状态 0 空闲 1 忙碌
|
||||
val plateNumber : String? = null, //车牌号
|
||||
val deviceId : String? = null,
|
||||
)
|
||||
) : Parcelable {
|
||||
constructor(parcel : Parcel) : this(parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readString(),
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readString(),
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readString(),
|
||||
parcel.readString()) {
|
||||
}
|
||||
|
||||
override fun writeToParcel(parcel : Parcel, flags : Int) {
|
||||
parcel.writeValue(userId)
|
||||
parcel.writeString(userName)
|
||||
parcel.writeString(userPhone)
|
||||
parcel.writeString(userPortrait)
|
||||
parcel.writeString(rongyunToken)
|
||||
parcel.writeString(logTime)
|
||||
parcel.writeValue(supplierId)
|
||||
parcel.writeString(supplierName)
|
||||
parcel.writeValue(supplierType)
|
||||
parcel.writeValue(loginLogId)
|
||||
parcel.writeString(serviceList)
|
||||
parcel.writeString(assistUserCode)
|
||||
parcel.writeValue(authStatus)
|
||||
parcel.writeValue(vehicleId)
|
||||
parcel.writeString(vehicleName)
|
||||
parcel.writeValue(vehicleState)
|
||||
parcel.writeString(plateNumber)
|
||||
parcel.writeString(deviceId)
|
||||
}
|
||||
|
||||
override fun describeContents() : Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<DriverInfoBean> {
|
||||
override fun createFromParcel(parcel : Parcel) : DriverInfoBean {
|
||||
return DriverInfoBean(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size : Int) : Array<DriverInfoBean?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
package com.za.room.db.user
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import androidx.room.Update
|
||||
import com.za.common.log.LogUtil
|
||||
|
||||
@Dao
|
||||
interface DriverInfoDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insert(driverInfoBean : DriverInfoBean)
|
||||
|
||||
@Query("SELECT * FROM driver_info")
|
||||
fun getDriverInfoFromUserId() : DriverInfoBean?
|
||||
|
||||
|
||||
@Query("DELETE FROM driver_info")
|
||||
fun deleteAll()
|
||||
|
||||
@Update(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun update(driverInfoBean : DriverInfoBean)
|
||||
|
||||
@Transaction
|
||||
fun updateDriverInfo(driverInfoBean : DriverInfoBean?) {
|
||||
if (driverInfoBean == null) {
|
||||
LogUtil.print("DriverInfoDao", "updateDriverInfo driverInfoBean is null")
|
||||
return
|
||||
}
|
||||
val driverInfo = getDriverInfoFromUserId()
|
||||
if (driverInfo != null && driverInfo.userId == driverInfoBean.userId) {
|
||||
update(driverInfoBean)
|
||||
return
|
||||
}
|
||||
deleteAll()
|
||||
insert(driverInfoBean)
|
||||
}
|
||||
}
|
@ -65,457 +65,490 @@ import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
class ZdCameraXActivity : AppCompatActivity() {
|
||||
private var exposurePopupWindow: PopupWindow? = null
|
||||
private var exposurePopupWindow : PopupWindow? = null
|
||||
|
||||
internal enum class FlashMode {
|
||||
auto, open, light, close
|
||||
}
|
||||
internal enum class FlashMode {
|
||||
auto, open, light, close
|
||||
}
|
||||
|
||||
private var rootView: ConstraintLayout? = null
|
||||
private var imageCapture: ImageCapture? = null
|
||||
private var cameraInfo: CameraInfo? = null
|
||||
private var rootView : ConstraintLayout? = null
|
||||
private var imageCapture : ImageCapture? = null
|
||||
private var cameraInfo : CameraInfo? = null
|
||||
|
||||
private var exposureState: ExposureState? = null
|
||||
private var cameraExecutor: ExecutorService? = null
|
||||
private var zoomState: LiveData<ZoomState>? = null
|
||||
private var viewFinder: PreviewView? = null
|
||||
private var takePhoto: TakePhotoButtonView? = null
|
||||
private var ivFlash: ImageView? = null
|
||||
private var ivChangeCamera: ImageView? = null
|
||||
private var ivConfirm: ImageView? = null
|
||||
private var ivCancel: ImageView? = null
|
||||
private lateinit var ivPreview: ImageFilterView
|
||||
private var ivBack: ImageView? = null
|
||||
private var sliderExposure: AppCompatSeekBar? = null
|
||||
private var groupOperation: Group? = null
|
||||
private var groupPreview: Group? = null
|
||||
private var uri: Uri? = null
|
||||
private var animatorSet: AnimatorSet? = null
|
||||
private var location: Location? = null
|
||||
private var camera: Camera? = null
|
||||
private var isBack = true
|
||||
private var exposureState : ExposureState? = null
|
||||
private var cameraExecutor : ExecutorService? = null
|
||||
private var zoomState : LiveData<ZoomState>? = null
|
||||
private var viewFinder : PreviewView? = null
|
||||
private var takePhoto : TakePhotoButtonView? = null
|
||||
private var ivFlash : ImageView? = null
|
||||
private var ivChangeCamera : ImageView? = null
|
||||
private var ivConfirm : ImageView? = null
|
||||
private var ivCancel : ImageView? = null
|
||||
private lateinit var ivPreview : ImageFilterView
|
||||
private var ivBack : ImageView? = null
|
||||
private var sliderExposure : AppCompatSeekBar? = null
|
||||
private var groupOperation : Group? = null
|
||||
private var groupPreview : Group? = null
|
||||
private var uri : Uri? = null
|
||||
private var animatorSet : AnimatorSet? = null
|
||||
private var location : Location? = null
|
||||
private var camera : Camera? = null
|
||||
private var isBack = true
|
||||
|
||||
private var orientationEventListener: OrientationEventListener? = null
|
||||
private var flashPopWindow: PopupWindow? = null
|
||||
private var flashMode = FlashMode.close
|
||||
private var orientationEventListener : OrientationEventListener? = null
|
||||
private var flashPopWindow : PopupWindow? = null
|
||||
private var flashMode = FlashMode.close
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_zd_camera_xactivity)
|
||||
initView()
|
||||
initLocation()
|
||||
startCamera()
|
||||
setOnClick()
|
||||
override fun onCreate(savedInstanceState : Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_zd_camera_xactivity)
|
||||
isBack = intent.getBooleanExtra("isBack", true)
|
||||
initView()
|
||||
initLocation()
|
||||
startCamera()
|
||||
setOnClick()
|
||||
|
||||
orientationEventListener = object : OrientationEventListener(this) {
|
||||
override fun onOrientationChanged(orientation: Int) {
|
||||
if (orientation == ORIENTATION_UNKNOWN || imageCapture == null) {
|
||||
print("zdCamerax orientation", "orientation==$orientation")
|
||||
return
|
||||
}
|
||||
when (orientation) {
|
||||
in 45..134 -> {
|
||||
imageCapture?.targetRotation = Surface.ROTATION_270
|
||||
}
|
||||
in 135..224 -> {
|
||||
imageCapture?.targetRotation = Surface.ROTATION_180
|
||||
}
|
||||
in 225..314 -> {
|
||||
imageCapture?.targetRotation = Surface.ROTATION_90
|
||||
}
|
||||
else -> {
|
||||
imageCapture?.targetRotation = Surface.ROTATION_0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
orientationEventListener = object : OrientationEventListener(this) {
|
||||
override fun onOrientationChanged(orientation : Int) {
|
||||
if (orientation == ORIENTATION_UNKNOWN || imageCapture == null) {
|
||||
print("zdCamerax orientation", "orientation==$orientation")
|
||||
return
|
||||
}
|
||||
when (orientation) {
|
||||
in 45 .. 134 -> {
|
||||
imageCapture?.targetRotation = Surface.ROTATION_270
|
||||
}
|
||||
|
||||
@SuppressLint("ObjectAnimatorBinding")
|
||||
private fun initView() {
|
||||
cameraExecutor = Executors.newSingleThreadExecutor()
|
||||
rootView = findViewById(R.id.viewGroup_parent)
|
||||
viewFinder = findViewById(R.id.viewFinder)
|
||||
takePhoto = findViewById(R.id.iv_takePhoto)
|
||||
ivConfirm = findViewById(R.id.iv_confirm)
|
||||
ivCancel = findViewById(R.id.iv_cancel)
|
||||
ivBack = findViewById(R.id.iv_back)
|
||||
sliderExposure = findViewById(R.id.slider_exposureState)
|
||||
groupOperation = findViewById(R.id.group_opera)
|
||||
groupPreview = findViewById(R.id.group_preview)
|
||||
groupPreview?.visibility = View.GONE
|
||||
ivChangeCamera = findViewById(R.id.iv_changeCamera)
|
||||
ivPreview = findViewById(R.id.iv_preview)
|
||||
ivFlash = findViewById(R.id.iv_flash)
|
||||
animatorSet = AnimatorSet()
|
||||
animatorSet?.playTogether(ObjectAnimator.ofFloat(ivCancel, "translationX", 0f, -200f), ObjectAnimator.ofFloat(ivConfirm, "translationX", 200f))
|
||||
in 135 .. 224 -> {
|
||||
imageCapture?.targetRotation = Surface.ROTATION_180
|
||||
}
|
||||
|
||||
animatorSet?.setDuration(500)
|
||||
}
|
||||
in 225 .. 314 -> {
|
||||
imageCapture?.targetRotation = Surface.ROTATION_90
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
private fun setOnClick() {
|
||||
takePhoto?.setOnClickListener(ClickProxy { v: View? -> takePhoto() })
|
||||
else -> {
|
||||
imageCapture?.targetRotation = Surface.ROTATION_0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ivChangeCamera?.setOnClickListener(ClickProxy { v: View? ->
|
||||
isBack = !isBack
|
||||
if (!isBack) {
|
||||
if (flashPopWindow != null && flashPopWindow?.isShowing == true) {
|
||||
flashPopWindow?.dismiss()
|
||||
}
|
||||
flashMode = FlashMode.close
|
||||
ivFlash?.setImageResource(R.drawable.picture_ic_flash_off)
|
||||
}
|
||||
startCamera()
|
||||
})
|
||||
@SuppressLint("ObjectAnimatorBinding")
|
||||
private fun initView() {
|
||||
cameraExecutor = Executors.newSingleThreadExecutor()
|
||||
rootView = findViewById(R.id.viewGroup_parent)
|
||||
viewFinder = findViewById(R.id.viewFinder)
|
||||
takePhoto = findViewById(R.id.iv_takePhoto)
|
||||
ivConfirm = findViewById(R.id.iv_confirm)
|
||||
ivCancel = findViewById(R.id.iv_cancel)
|
||||
ivBack = findViewById(R.id.iv_back)
|
||||
sliderExposure = findViewById(R.id.slider_exposureState)
|
||||
groupOperation = findViewById(R.id.group_opera)
|
||||
groupPreview = findViewById(R.id.group_preview)
|
||||
groupPreview?.visibility = View.GONE
|
||||
ivChangeCamera = findViewById(R.id.iv_changeCamera)
|
||||
ivPreview = findViewById(R.id.iv_preview)
|
||||
ivFlash = findViewById(R.id.iv_flash)
|
||||
animatorSet = AnimatorSet()
|
||||
animatorSet?.playTogether(ObjectAnimator.ofFloat(ivCancel, "translationX", 0f, - 200f),
|
||||
ObjectAnimator.ofFloat(ivConfirm, "translationX", 200f))
|
||||
|
||||
ivFlash?.setOnClickListener {
|
||||
if (!isBack) {
|
||||
ToastUtils.showShort("前置模式下无法开启!")
|
||||
return@setOnClickListener
|
||||
}
|
||||
if (flashPopWindow != null && flashPopWindow?.isShowing==true) {
|
||||
flashPopWindow?.dismiss()
|
||||
} else {
|
||||
showFlashView()
|
||||
}
|
||||
}
|
||||
animatorSet?.setDuration(500)
|
||||
}
|
||||
|
||||
ivCancel?.setOnClickListener {
|
||||
groupPreview?.visibility = View.GONE
|
||||
groupOperation?.visibility = View.VISIBLE
|
||||
}
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
private fun setOnClick() {
|
||||
takePhoto?.setOnClickListener(ClickProxy { v : View? -> takePhoto() })
|
||||
|
||||
ivConfirm?.setOnClickListener {
|
||||
val intent = Intent()
|
||||
if (uri != null) {
|
||||
intent.putExtra("path", UriUtils.uri2File(uri).absolutePath)
|
||||
}
|
||||
setResult(RESULT_OK, intent)
|
||||
finish()
|
||||
}
|
||||
ivChangeCamera?.setOnClickListener(ClickProxy { v : View? ->
|
||||
isBack = ! isBack
|
||||
if (! isBack) {
|
||||
if (flashPopWindow != null && flashPopWindow?.isShowing == true) {
|
||||
flashPopWindow?.dismiss()
|
||||
}
|
||||
flashMode = FlashMode.close
|
||||
ivFlash?.setImageResource(R.drawable.picture_ic_flash_off)
|
||||
}
|
||||
startCamera()
|
||||
})
|
||||
|
||||
ivBack?.setOnClickListener { finish() }
|
||||
ivFlash?.setOnClickListener {
|
||||
if (! isBack) {
|
||||
ToastUtils.showShort("前置模式下无法开启!")
|
||||
return@setOnClickListener
|
||||
}
|
||||
if (flashPopWindow != null && flashPopWindow?.isShowing == true) {
|
||||
flashPopWindow?.dismiss()
|
||||
} else {
|
||||
showFlashView()
|
||||
}
|
||||
}
|
||||
|
||||
sliderExposure?.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
||||
if (exposureState != null) {
|
||||
camera?.cameraControl?.setExposureCompensationIndex(Math.round(progress.toFloat()))
|
||||
if (exposurePopupWindow != null) {
|
||||
val textView = exposurePopupWindow?.contentView?.findViewWithTag<TextView>("tv_exposureView")
|
||||
textView?.text = progress.toString() + ""
|
||||
}
|
||||
}
|
||||
}
|
||||
ivCancel?.setOnClickListener {
|
||||
groupPreview?.visibility = View.GONE
|
||||
groupOperation?.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar) {
|
||||
showExposureView()
|
||||
}
|
||||
ivConfirm?.setOnClickListener {
|
||||
val intent = Intent()
|
||||
if (uri != null) {
|
||||
intent.putExtra("path", UriUtils.uri2File(uri).absolutePath)
|
||||
}
|
||||
setResult(RESULT_OK, intent)
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun onStopTrackingTouch(seekBar: SeekBar) {
|
||||
viewFinder?.postDelayed({ exposurePopupWindow?.dismiss() }, 1000)
|
||||
}
|
||||
})
|
||||
ivBack?.setOnClickListener { finish() }
|
||||
|
||||
val cameraXPreviewViewTouchListener = CameraXPreviewViewTouchListener(this)
|
||||
viewFinder?.setOnTouchListener(cameraXPreviewViewTouchListener)
|
||||
cameraXPreviewViewTouchListener.setCustomTouchListener(object : CustomTouchListener {
|
||||
override fun zoom(delta: Float) {
|
||||
if (zoomState == null) {
|
||||
return
|
||||
}
|
||||
val currentZoomRatio = zoomState?.value?.zoomRatio
|
||||
currentZoomRatio?.let {
|
||||
camera?.cameraControl?.setZoomRatio(it.times(delta))
|
||||
}
|
||||
sliderExposure?.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onProgressChanged(seekBar : SeekBar, progress : Int, fromUser : Boolean) {
|
||||
if (exposureState != null) {
|
||||
camera?.cameraControl?.setExposureCompensationIndex(Math.round(progress.toFloat()))
|
||||
if (exposurePopupWindow != null) {
|
||||
val textView =
|
||||
exposurePopupWindow?.contentView?.findViewWithTag<TextView>("tv_exposureView")
|
||||
textView?.text = progress.toString() + ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
override fun onStartTrackingTouch(seekBar : SeekBar) {
|
||||
showExposureView()
|
||||
}
|
||||
|
||||
override fun click(event: MotionEvent) {
|
||||
val action = viewFinder?.meteringPointFactory?.createPoint(event.x, event.y)?.let { FocusMeteringAction.Builder(it).build() }
|
||||
rootView?.post { showTapView(event.rawX.toInt(), event.rawY.toInt()) }
|
||||
action?.let {
|
||||
camera?.cameraControl?.startFocusAndMetering(action)
|
||||
}
|
||||
}
|
||||
override fun onStopTrackingTouch(seekBar : SeekBar) {
|
||||
viewFinder?.postDelayed({ exposurePopupWindow?.dismiss() }, 1000)
|
||||
}
|
||||
})
|
||||
|
||||
override fun doubleClick(x: Float, y: Float) {
|
||||
if (zoomState == null) {
|
||||
return
|
||||
}
|
||||
val currentZoomRatio = zoomState?.value?.zoomRatio
|
||||
zoomState?.value?.minZoomRatio?.let {
|
||||
if (currentZoomRatio!! > it) {
|
||||
camera?.cameraControl?.setLinearZoom(0f)
|
||||
} else {
|
||||
camera?.cameraControl?.setLinearZoom(0.5f)
|
||||
}
|
||||
}
|
||||
val cameraXPreviewViewTouchListener = CameraXPreviewViewTouchListener(this)
|
||||
viewFinder?.setOnTouchListener(cameraXPreviewViewTouchListener)
|
||||
cameraXPreviewViewTouchListener.setCustomTouchListener(object : CustomTouchListener {
|
||||
override fun zoom(delta : Float) {
|
||||
if (zoomState == null) {
|
||||
return
|
||||
}
|
||||
val currentZoomRatio = zoomState?.value?.zoomRatio
|
||||
currentZoomRatio?.let {
|
||||
camera?.cameraControl?.setZoomRatio(it.times(delta))
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun takePhoto() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
ThreadUtils.runOnUiThread {
|
||||
PermissionX.init(this@ZdCameraXActivity).permissions(Manifest.permission.ACCESS_MEDIA_LOCATION)
|
||||
.request { allGranted: Boolean, grantedList: List<String?>?, deniedList: List<String?>? ->
|
||||
print("ZDCamerax ACCESS_MEDIA_LOCATION 权限请求结果", "allGranted==$allGranted")
|
||||
if (!allGranted) {
|
||||
ToastUtils.showLong("权限获取失败")
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (imageCapture == null) {
|
||||
ToastUtils.showShort("相机打开失败")
|
||||
finish()
|
||||
}
|
||||
// val filename = TimeUtils.date2String(Date(), "yyyyMMddHHmmss")
|
||||
// val contentValues = ContentValues()
|
||||
// contentValues.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, filename)
|
||||
// contentValues.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/jpeg")
|
||||
// contentValues.put(MediaStore.Images.ImageColumns.DATE_TAKEN, System.currentTimeMillis())
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
// contentValues.put(MediaStore.Images.ImageColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
|
||||
// } else {
|
||||
// ImageUtils.save2Album()
|
||||
// contentValues.put(MediaStore.Images.ImageColumns.DATA, getTakePictureParentPath() + File.separator + filename + ".jpg")
|
||||
// }
|
||||
//
|
||||
// val outputOptions = ImageCapture.OutputFileOptions.Builder(contentResolver,
|
||||
// MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues).build()
|
||||
override fun click(event : MotionEvent) {
|
||||
val action = viewFinder?.meteringPointFactory?.createPoint(event.x, event.y)
|
||||
?.let { FocusMeteringAction.Builder(it).build() }
|
||||
rootView?.post { showTapView(event.rawX.toInt(), event.rawY.toInt()) }
|
||||
action?.let {
|
||||
camera?.cameraControl?.startFocusAndMetering(action)
|
||||
}
|
||||
}
|
||||
|
||||
override fun doubleClick(x : Float, y : Float) {
|
||||
if (zoomState == null) {
|
||||
return
|
||||
}
|
||||
val currentZoomRatio = zoomState?.value?.zoomRatio
|
||||
zoomState?.value?.minZoomRatio?.let {
|
||||
if (currentZoomRatio !! > it) {
|
||||
camera?.cameraControl?.setLinearZoom(0f)
|
||||
} else {
|
||||
camera?.cameraControl?.setLinearZoom(0.5f)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun takePhoto() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
ThreadUtils.runOnUiThread {
|
||||
PermissionX.init(this@ZdCameraXActivity)
|
||||
.permissions(Manifest.permission.ACCESS_MEDIA_LOCATION)
|
||||
.request { allGranted : Boolean, grantedList : List<String?>?, deniedList : List<String?>? ->
|
||||
print("ZDCamerax ACCESS_MEDIA_LOCATION 权限请求结果",
|
||||
"allGranted==$allGranted")
|
||||
if (! allGranted) {
|
||||
ToastUtils.showLong("权限获取失败")
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (imageCapture == null) {
|
||||
ToastUtils.showShort("相机打开失败")
|
||||
finish()
|
||||
} // val filename = TimeUtils.date2String(Date(), "yyyyMMddHHmmss")
|
||||
// val contentValues = ContentValues()
|
||||
// contentValues.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, filename)
|
||||
// contentValues.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/jpeg")
|
||||
// contentValues.put(MediaStore.Images.ImageColumns.DATE_TAKEN, System.currentTimeMillis())
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
// contentValues.put(MediaStore.Images.ImageColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
|
||||
// } else {
|
||||
// ImageUtils.save2Album()
|
||||
// contentValues.put(MediaStore.Images.ImageColumns.DATA, getTakePictureParentPath() + File.separator + filename + ".jpg")
|
||||
// }
|
||||
//
|
||||
// val outputOptions = ImageCapture.OutputFileOptions.Builder(contentResolver,
|
||||
// MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues).build()
|
||||
|
||||
|
||||
// Create time stamped name and MediaStore entry.
|
||||
val filename = SimpleDateFormat("yyyyMMddHHmmss",
|
||||
Locale.getDefault()).format(System.currentTimeMillis())
|
||||
val contentValues = ContentValues().apply {
|
||||
put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
|
||||
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
|
||||
put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/中道救援")
|
||||
}
|
||||
}
|
||||
|
||||
// Create time stamped name and MediaStore entry.
|
||||
val filename = SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault())
|
||||
.format(System.currentTimeMillis())
|
||||
val contentValues = ContentValues().apply {
|
||||
put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
|
||||
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
|
||||
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
|
||||
put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/中道救援")
|
||||
}
|
||||
}
|
||||
|
||||
// Create output options object which contains file + metadata
|
||||
val outputOptions = ImageCapture.OutputFileOptions
|
||||
.Builder(contentResolver, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
|
||||
.build()
|
||||
// Create output options object which contains file + metadata
|
||||
val outputOptions = ImageCapture.OutputFileOptions.Builder(contentResolver,
|
||||
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||
contentValues).build()
|
||||
|
||||
|
||||
takePhoto?.startAnimation()
|
||||
takePhoto?.startAnimation()
|
||||
|
||||
imageCapture?.takePicture(outputOptions, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback {
|
||||
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
|
||||
this@ZdCameraXActivity.uri = outputFileResults.savedUri
|
||||
//保存照片信息
|
||||
val exifInterface: ExifInterface
|
||||
try {
|
||||
exifInterface = ExifInterface(UriUtils.uri2File(outputFileResults.savedUri).absolutePath)
|
||||
exifInterface.setAttribute(ExifInterface.TAG_DATETIME, filename)
|
||||
if (location != null) {
|
||||
exifInterface.setGpsInfo(location)
|
||||
if (location?.latitude!! > 0f && location?.longitude != null && location?.longitude!! > 0f) {
|
||||
exifInterface.setLatLong(location?.latitude!!, location?.longitude!!)
|
||||
}
|
||||
}
|
||||
imageCapture?.takePicture(outputOptions,
|
||||
ContextCompat.getMainExecutor(this),
|
||||
object : ImageCapture.OnImageSavedCallback {
|
||||
override fun onImageSaved(outputFileResults : ImageCapture.OutputFileResults) {
|
||||
this@ZdCameraXActivity.uri = outputFileResults.savedUri //保存照片信息
|
||||
val exifInterface : ExifInterface
|
||||
try {
|
||||
exifInterface =
|
||||
ExifInterface(UriUtils.uri2File(outputFileResults.savedUri).absolutePath)
|
||||
exifInterface.setAttribute(ExifInterface.TAG_DATETIME, filename)
|
||||
if (location != null) {
|
||||
exifInterface.setGpsInfo(location)
|
||||
if (location?.latitude !! > 0f && location?.longitude != null && location?.longitude !! > 0f) {
|
||||
exifInterface.setLatLong(location?.latitude !!,
|
||||
location?.longitude !!)
|
||||
}
|
||||
}
|
||||
|
||||
exifInterface.saveAttributes()
|
||||
takePhoto?.cancelAnimation()
|
||||
groupPreview?.visibility = View.VISIBLE
|
||||
if (!this@ZdCameraXActivity.isFinishing) {
|
||||
Glide.with(this@ZdCameraXActivity).load(outputFileResults.savedUri).into(ivPreview)
|
||||
}
|
||||
groupOperation?.visibility = View.GONE
|
||||
animatorSet?.start()
|
||||
} catch (e: IOException) {
|
||||
takePhoto?.cancelAnimation()
|
||||
ToastUtils.showShort("照片保存失败" + e.message)
|
||||
print("照片保存失败", e)
|
||||
}
|
||||
}
|
||||
exifInterface.saveAttributes()
|
||||
takePhoto?.cancelAnimation()
|
||||
groupPreview?.visibility = View.VISIBLE
|
||||
if (! this@ZdCameraXActivity.isFinishing) {
|
||||
Glide.with(this@ZdCameraXActivity).load(outputFileResults.savedUri)
|
||||
.into(ivPreview)
|
||||
}
|
||||
groupOperation?.visibility = View.GONE
|
||||
animatorSet?.start()
|
||||
} catch (e : IOException) {
|
||||
takePhoto?.cancelAnimation()
|
||||
ToastUtils.showShort("照片保存失败" + e.message)
|
||||
print("照片保存失败", e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(exception: ImageCaptureException) {
|
||||
takePhoto?.cancelAnimation()
|
||||
ToastUtils.showShort("Photo capture failed" + exception.message)
|
||||
print("onCameraError", exception)
|
||||
}
|
||||
})
|
||||
}
|
||||
override fun onError(exception : ImageCaptureException) {
|
||||
takePhoto?.cancelAnimation()
|
||||
ToastUtils.showShort("Photo capture failed" + exception.message)
|
||||
print("onCameraError", exception)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun startCamera() {
|
||||
imageCapture = ImageCapture.Builder().setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY).build()
|
||||
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
|
||||
cameraProviderFuture.addListener({
|
||||
try {
|
||||
val cameraProvider = cameraProviderFuture.get()
|
||||
val preview = Preview.Builder().setTargetAspectRatio(AspectRatio.RATIO_4_3).build()
|
||||
private fun startCamera() {
|
||||
imageCapture =
|
||||
ImageCapture.Builder().setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
|
||||
.build()
|
||||
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
|
||||
cameraProviderFuture.addListener({
|
||||
try {
|
||||
val cameraProvider = cameraProviderFuture.get()
|
||||
val preview = Preview.Builder().setTargetAspectRatio(AspectRatio.RATIO_4_3).build()
|
||||
|
||||
preview.setSurfaceProvider(viewFinder?.surfaceProvider)
|
||||
val cameraSelector = if (isBack) CameraSelector.DEFAULT_BACK_CAMERA else CameraSelector.DEFAULT_FRONT_CAMERA
|
||||
preview.targetRotation = Surface.ROTATION_0
|
||||
cameraProvider.unbindAll()
|
||||
camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture)
|
||||
cameraInfo = camera?.cameraInfo
|
||||
zoomState = cameraInfo?.zoomState
|
||||
exposureState = cameraInfo?.exposureState
|
||||
if (exposureState?.isExposureCompensationSupported == true) {
|
||||
sliderExposure?.visibility = View.VISIBLE
|
||||
sliderExposure?.max = exposureState?.exposureCompensationRange?.upper ?: 1
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
sliderExposure?.min = exposureState?.exposureCompensationRange?.lower ?: 1
|
||||
}
|
||||
} else {
|
||||
sliderExposure?.visibility = View.GONE
|
||||
}
|
||||
} catch (e: ExecutionException) {
|
||||
finish()
|
||||
print("相机初始化失败", e)
|
||||
} catch (e: InterruptedException) {
|
||||
finish()
|
||||
print("相机初始化失败", e)
|
||||
}
|
||||
}, ContextCompat.getMainExecutor(this))
|
||||
}
|
||||
preview.surfaceProvider = viewFinder?.surfaceProvider
|
||||
val cameraSelector =
|
||||
if (isBack) CameraSelector.DEFAULT_BACK_CAMERA else CameraSelector.DEFAULT_FRONT_CAMERA
|
||||
preview.targetRotation = Surface.ROTATION_0
|
||||
cameraProvider.unbindAll()
|
||||
camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture)
|
||||
cameraInfo = camera?.cameraInfo
|
||||
zoomState = cameraInfo?.zoomState
|
||||
exposureState = cameraInfo?.exposureState
|
||||
if (exposureState?.isExposureCompensationSupported == true) {
|
||||
sliderExposure?.visibility = View.VISIBLE
|
||||
sliderExposure?.max = exposureState?.exposureCompensationRange?.upper ?: 1
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
sliderExposure?.min = exposureState?.exposureCompensationRange?.lower ?: 1
|
||||
}
|
||||
} else {
|
||||
sliderExposure?.visibility = View.GONE
|
||||
}
|
||||
} catch (e : ExecutionException) {
|
||||
finish()
|
||||
print("相机初始化失败", e)
|
||||
} catch (e : InterruptedException) {
|
||||
finish()
|
||||
print("相机初始化失败", e)
|
||||
}
|
||||
}, ContextCompat.getMainExecutor(this))
|
||||
}
|
||||
|
||||
private fun initLocation() {
|
||||
val locationManager = ContextCompat.getSystemService(this, LocationManager::class.java)
|
||||
if ((ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA), 102)
|
||||
} else {
|
||||
if (locationManager != null) {
|
||||
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
|
||||
}
|
||||
}
|
||||
}
|
||||
private fun initLocation() {
|
||||
val locationManager = ContextCompat.getSystemService(this, LocationManager::class.java)
|
||||
if ((ActivityCompat.checkSelfPermission(this,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) && ActivityCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
ActivityCompat.requestPermissions(this,
|
||||
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
Manifest.permission.ACCESS_COARSE_LOCATION,
|
||||
Manifest.permission.RECORD_AUDIO,
|
||||
Manifest.permission.CAMERA),
|
||||
102)
|
||||
} else {
|
||||
if (locationManager != null) {
|
||||
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("RtlHardcoded")
|
||||
private fun showTapView(x: Int, y: Int) {
|
||||
if (takePhoto?.visibility == View.GONE) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
val popupWindow = PopupWindow(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
popupWindow.width = 200
|
||||
popupWindow.height = 200
|
||||
val imageView = ImageView(this)
|
||||
imageView.setImageResource(R.drawable.focus_focusing)
|
||||
imageView.scaleType = ImageView.ScaleType.CENTER_CROP
|
||||
popupWindow.contentView = imageView
|
||||
popupWindow.showAtLocation(rootView, Gravity.LEFT or Gravity.TOP, x, y)
|
||||
viewFinder?.postDelayed({ popupWindow.dismiss() }, 1000)
|
||||
viewFinder?.playSoundEffect(SoundEffectConstants.CLICK)
|
||||
} catch (e: Exception) {
|
||||
print("zdCameraX showTapView", e)
|
||||
}
|
||||
}
|
||||
@SuppressLint("RtlHardcoded")
|
||||
private fun showTapView(x : Int, y : Int) {
|
||||
if (takePhoto?.visibility == View.GONE) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
val popupWindow = PopupWindow(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
popupWindow.width = 200
|
||||
popupWindow.height = 200
|
||||
val imageView = ImageView(this)
|
||||
imageView.setImageResource(R.drawable.focus_focusing)
|
||||
imageView.scaleType = ImageView.ScaleType.CENTER_CROP
|
||||
popupWindow.contentView = imageView
|
||||
popupWindow.showAtLocation(rootView, Gravity.LEFT or Gravity.TOP, x, y)
|
||||
viewFinder?.postDelayed({ popupWindow.dismiss() }, 1000)
|
||||
viewFinder?.playSoundEffect(SoundEffectConstants.CLICK)
|
||||
} catch (e : Exception) {
|
||||
print("zdCameraX showTapView", e)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("RtlHardcoded", "SetTextI18n")
|
||||
private fun showExposureView() {
|
||||
if (takePhoto?.visibility == View.GONE) {
|
||||
return
|
||||
}
|
||||
exposurePopupWindow = PopupWindow(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
exposurePopupWindow?.width = 300
|
||||
exposurePopupWindow?.height = 200
|
||||
val textView = TextView(this)
|
||||
textView.setTextColor(Color.YELLOW)
|
||||
textView.textSize = 50f
|
||||
textView.tag = "tv_exposureView"
|
||||
textView.gravity = Gravity.CENTER
|
||||
textView.text = exposureState?.exposureCompensationIndex.toString() + ""
|
||||
exposurePopupWindow?.contentView = textView
|
||||
exposurePopupWindow?.showAtLocation(rootView, Gravity.CENTER, 0, 0)
|
||||
}
|
||||
@SuppressLint("RtlHardcoded", "SetTextI18n")
|
||||
private fun showExposureView() {
|
||||
if (takePhoto?.visibility == View.GONE) {
|
||||
return
|
||||
}
|
||||
exposurePopupWindow =
|
||||
PopupWindow(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
exposurePopupWindow?.width = 300
|
||||
exposurePopupWindow?.height = 200
|
||||
val textView = TextView(this)
|
||||
textView.setTextColor(Color.YELLOW)
|
||||
textView.textSize = 50f
|
||||
textView.tag = "tv_exposureView"
|
||||
textView.gravity = Gravity.CENTER
|
||||
textView.text = exposureState?.exposureCompensationIndex.toString() + ""
|
||||
exposurePopupWindow?.contentView = textView
|
||||
exposurePopupWindow?.showAtLocation(rootView, Gravity.CENTER, 0, 0)
|
||||
}
|
||||
|
||||
@SuppressLint("RtlHardcoded")
|
||||
private fun showFlashView() {
|
||||
if (flashPopWindow != null) {
|
||||
flashPopWindow = null
|
||||
}
|
||||
flashPopWindow = PopupWindow(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
@SuppressLint("InflateParams") val view = LayoutInflater.from(this).inflate(R.layout.item_flash_mode, null)
|
||||
val tvFlashAuto = view.findViewById<TextView>(R.id.tvFlashAuto)
|
||||
val tvFlashOpen = view.findViewById<TextView>(R.id.tvFlashOpen)
|
||||
val tvFlashLight = view.findViewById<TextView>(R.id.tvFlashLight)
|
||||
val tvFlashClose = view.findViewById<TextView>(R.id.tvFlashClose)
|
||||
@SuppressLint("RtlHardcoded")
|
||||
private fun showFlashView() {
|
||||
if (flashPopWindow != null) {
|
||||
flashPopWindow = null
|
||||
}
|
||||
flashPopWindow =
|
||||
PopupWindow(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
@SuppressLint("InflateParams") val view =
|
||||
LayoutInflater.from(this).inflate(R.layout.item_flash_mode, null)
|
||||
val tvFlashAuto = view.findViewById<TextView>(R.id.tvFlashAuto)
|
||||
val tvFlashOpen = view.findViewById<TextView>(R.id.tvFlashOpen)
|
||||
val tvFlashLight = view.findViewById<TextView>(R.id.tvFlashLight)
|
||||
val tvFlashClose = view.findViewById<TextView>(R.id.tvFlashClose)
|
||||
|
||||
when (flashMode) {
|
||||
FlashMode.auto -> tvFlashAuto.setTextColor(Color.YELLOW)
|
||||
FlashMode.open -> tvFlashOpen.setTextColor(Color.YELLOW)
|
||||
FlashMode.light -> tvFlashLight.setTextColor(Color.YELLOW)
|
||||
FlashMode.close -> tvFlashClose.setTextColor(Color.YELLOW)
|
||||
}
|
||||
tvFlashAuto.setOnClickListener { v: View? ->
|
||||
if (imageCapture != null) {
|
||||
camera?.cameraControl?.enableTorch(false)
|
||||
imageCapture?.flashMode = ImageCapture.FLASH_MODE_AUTO
|
||||
ivFlash?.setImageResource(R.drawable.picture_ic_flash_auto)
|
||||
flashMode = FlashMode.auto
|
||||
}
|
||||
flashPopWindow?.dismiss()
|
||||
}
|
||||
tvFlashOpen.setOnClickListener { v: View? ->
|
||||
if (imageCapture != null) {
|
||||
camera?.cameraControl?.enableTorch(false)
|
||||
imageCapture?.flashMode = ImageCapture.FLASH_MODE_ON
|
||||
ivFlash?.setImageResource(R.drawable.picture_ic_flash_on)
|
||||
flashMode = FlashMode.open
|
||||
}
|
||||
flashPopWindow?.dismiss()
|
||||
}
|
||||
when (flashMode) {
|
||||
FlashMode.auto -> tvFlashAuto.setTextColor(Color.YELLOW)
|
||||
FlashMode.open -> tvFlashOpen.setTextColor(Color.YELLOW)
|
||||
FlashMode.light -> tvFlashLight.setTextColor(Color.YELLOW)
|
||||
FlashMode.close -> tvFlashClose.setTextColor(Color.YELLOW)
|
||||
}
|
||||
tvFlashAuto.setOnClickListener { v : View? ->
|
||||
if (imageCapture != null) {
|
||||
camera?.cameraControl?.enableTorch(false)
|
||||
imageCapture?.flashMode = ImageCapture.FLASH_MODE_AUTO
|
||||
ivFlash?.setImageResource(R.drawable.picture_ic_flash_auto)
|
||||
flashMode = FlashMode.auto
|
||||
}
|
||||
flashPopWindow?.dismiss()
|
||||
}
|
||||
tvFlashOpen.setOnClickListener { v : View? ->
|
||||
if (imageCapture != null) {
|
||||
camera?.cameraControl?.enableTorch(false)
|
||||
imageCapture?.flashMode = ImageCapture.FLASH_MODE_ON
|
||||
ivFlash?.setImageResource(R.drawable.picture_ic_flash_on)
|
||||
flashMode = FlashMode.open
|
||||
}
|
||||
flashPopWindow?.dismiss()
|
||||
}
|
||||
|
||||
tvFlashLight.setOnClickListener { v: View? ->
|
||||
if (camera != null) {
|
||||
camera?.cameraControl?.enableTorch(true)
|
||||
ivFlash?.setImageResource(R.drawable.ic_flash_light)
|
||||
flashMode = FlashMode.light
|
||||
}
|
||||
flashPopWindow?.dismiss()
|
||||
}
|
||||
tvFlashLight.setOnClickListener { v : View? ->
|
||||
if (camera != null) {
|
||||
camera?.cameraControl?.enableTorch(true)
|
||||
ivFlash?.setImageResource(R.drawable.ic_flash_light)
|
||||
flashMode = FlashMode.light
|
||||
}
|
||||
flashPopWindow?.dismiss()
|
||||
}
|
||||
|
||||
tvFlashClose.setOnClickListener { v: View? ->
|
||||
if (imageCapture != null) {
|
||||
camera?.cameraControl?.enableTorch(false)
|
||||
imageCapture?.flashMode = ImageCapture.FLASH_MODE_OFF
|
||||
ivFlash?.setImageResource(R.drawable.picture_ic_flash_off)
|
||||
flashMode = FlashMode.close
|
||||
}
|
||||
flashPopWindow?.dismiss()
|
||||
}
|
||||
tvFlashClose.setOnClickListener { v : View? ->
|
||||
if (imageCapture != null) {
|
||||
camera?.cameraControl?.enableTorch(false)
|
||||
imageCapture?.flashMode = ImageCapture.FLASH_MODE_OFF
|
||||
ivFlash?.setImageResource(R.drawable.picture_ic_flash_off)
|
||||
flashMode = FlashMode.close
|
||||
}
|
||||
flashPopWindow?.dismiss()
|
||||
}
|
||||
|
||||
flashPopWindow?.contentView = view
|
||||
flashPopWindow?.showAtLocation(ivFlash, Gravity.LEFT or Gravity.TOP, 0, ivFlash?.y?.toInt()?.minus(view.height)
|
||||
?: 0)
|
||||
}
|
||||
flashPopWindow?.contentView = view
|
||||
flashPopWindow?.showAtLocation(ivFlash,
|
||||
Gravity.LEFT or Gravity.TOP,
|
||||
0,
|
||||
ivFlash?.y?.toInt()?.minus(view.height) ?: 0)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
if (camera != null && imageCapture != null) {
|
||||
camera?.cameraControl?.enableTorch(false)
|
||||
imageCapture?.flashMode = ImageCapture.FLASH_MODE_OFF
|
||||
ivFlash?.setImageResource(R.drawable.picture_ic_flash_off)
|
||||
}
|
||||
}
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
if (camera != null && imageCapture != null) {
|
||||
camera?.cameraControl?.enableTorch(false)
|
||||
imageCapture?.flashMode = ImageCapture.FLASH_MODE_OFF
|
||||
ivFlash?.setImageResource(R.drawable.picture_ic_flash_off)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
orientationEventListener?.enable()
|
||||
}
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
orientationEventListener?.enable()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
orientationEventListener?.disable()
|
||||
}
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
orientationEventListener?.disable()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
cameraExecutor?.shutdown()
|
||||
}
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
cameraExecutor?.shutdown()
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import coil.compose.AsyncImage
|
||||
import com.blankj.utilcode.util.ToastUtils
|
||||
import com.permissionx.guolindev.PermissionX
|
||||
@ -195,6 +196,7 @@ class ServiceLauncherActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun LauncherScreen() {
|
||||
Scaffold { paddingValues ->
|
||||
|
@ -2,22 +2,65 @@ package com.za.ui.main
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.basicMarquee
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Done
|
||||
import androidx.compose.material.icons.filled.Menu
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.blankj.utilcode.util.ActivityUtils
|
||||
import com.za.base.BaseActivity
|
||||
import com.za.base.theme.bgColor
|
||||
import com.za.base.view.CommonButton
|
||||
import com.za.base.view.HeadView
|
||||
import com.za.bean.db.order.OrderInfo
|
||||
import com.za.common.GlobalData
|
||||
import com.za.common.util.DeviceUtil
|
||||
import com.za.ext.convertToFlowName
|
||||
import com.za.ext.copy
|
||||
import com.za.ext.finish
|
||||
import com.za.ext.goStatusPage
|
||||
import com.za.service.ServiceManager
|
||||
import com.za.service.location.ZdLocationManager
|
||||
import com.za.servicing.R
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ServicingMainActivity : BaseActivity() {
|
||||
@ -59,8 +102,8 @@ private fun ServicingMainScreen(jobCode : String? = null,
|
||||
rescueVehicle : String? = null,
|
||||
vm : ServicingMainVm = viewModel()) {
|
||||
val uiState = vm.uiState.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
val context = LocalContext.current
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
vm.dispatch(ServicingMainVm.Action.Init(jobCode,
|
||||
@ -75,12 +118,200 @@ private fun ServicingMainScreen(jobCode : String? = null,
|
||||
}
|
||||
}
|
||||
|
||||
if (uiState.value.state == 2) {
|
||||
Box {
|
||||
Text(text = "加载失败")
|
||||
Scaffold(topBar = { HeadView("订单信息确认", onBack = { context.finish() }) }, bottomBar = {
|
||||
if (uiState.value.state == 1) {
|
||||
CommonButton(text = "已确认,去服务") {
|
||||
GlobalData.currentOrder?.goStatusPage(ActivityUtils.getTopActivity())
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Box(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(bgColor)
|
||||
.padding(it)) {
|
||||
if (uiState.value.state == 2) {
|
||||
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
CommonButton(text = "订单获取异常,点击重新获取") {
|
||||
vm.dispatch(ServicingMainVm.Action.Init(jobCode,
|
||||
phone,
|
||||
taskCode,
|
||||
vehicleId,
|
||||
deviceId,
|
||||
rescueVehicle))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Box(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(top = 10.dp),
|
||||
contentAlignment = Alignment.TopCenter) {
|
||||
OrderItemView(GlobalData.currentOrder)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
GlobalData.currentOrder?.goStatusPage(ActivityUtils.getTopActivity())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun OrderItemView(orderInfo : OrderInfo?) {
|
||||
val context = LocalContext.current
|
||||
|
||||
Card(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 10.dp, vertical = 5.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp, hoveredElevation = 4.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = Color.White)) {
|
||||
Column(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)) { // 订单头部
|
||||
Row(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(brush = Brush.linearGradient(colors = listOf(Color(0xFFF5F9FF),
|
||||
Color(0xFFEDF4FF)),
|
||||
start = androidx.compose.ui.geometry.Offset(0f, 0f),
|
||||
end = androidx.compose.ui.geometry.Offset(Float.POSITIVE_INFINITY, 0f)),
|
||||
shape = RoundedCornerShape(12.dp))
|
||||
.padding(horizontal = 12.dp, vertical = 10.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Text(text = orderInfo?.taskCode ?: "",
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = Color(0xFF1A1A1A))
|
||||
|
||||
Icon(painter = painterResource(R.drawable.sv_copy),
|
||||
contentDescription = "复制",
|
||||
modifier = Modifier
|
||||
.size(25.dp)
|
||||
.clickable {
|
||||
orderInfo?.taskCode?.copy(context)
|
||||
},
|
||||
tint = Color(0xFF666666))
|
||||
}
|
||||
Button(onClick = {
|
||||
|
||||
},
|
||||
colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFFF5A2C)),
|
||||
contentPadding = PaddingValues(horizontal = 14.dp, vertical = 2.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
modifier = Modifier.height(28.dp)) {
|
||||
Text(text = orderInfo?.convertToFlowName() ?: "",
|
||||
fontSize = 13.sp,
|
||||
fontWeight = FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
|
||||
// 车辆位于
|
||||
if (! orderInfo?.addressProperty.isNullOrBlank()) {
|
||||
Row(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(color = Color(0xFFF8F9FA), shape = RoundedCornerShape(10.dp))
|
||||
.padding(vertical = 12.dp, horizontal = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(painter = rememberVectorPainter(image = Icons.Default.Menu),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(20.dp),
|
||||
tint = Color(0xFF3364B7))
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(text = "服务类型:", fontSize = 13.sp, color = Color(0x802F3059))
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Text(text = orderInfo?.serviceTypeName ?: "",
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
color = Color(0xFF2F3059))
|
||||
}
|
||||
}
|
||||
|
||||
// 车牌信息
|
||||
if (! orderInfo?.plateNumber.isNullOrBlank()) {
|
||||
Row(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(color = Color(0xFFF8F9FA), shape = RoundedCornerShape(10.dp))
|
||||
.padding(vertical = 12.dp, horizontal = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(painter = painterResource(id = R.drawable.sv_map_marker_driver),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(20.dp),
|
||||
tint = Color(0xFF3364B7))
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(text = "车牌号:", fontSize = 13.sp, color = Color(0x802F3059))
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Text(text = orderInfo?.plateNumber ?: "",
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
color = Color(0xFF2F3059))
|
||||
}
|
||||
}
|
||||
|
||||
// 地址信息容器
|
||||
Column(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(color = Color(0xFFFAFBFC), shape = RoundedCornerShape(12.dp))
|
||||
.padding(16.dp), verticalArrangement = Arrangement.spacedBy(12.dp)) { // 救援地址信息
|
||||
AddressItem(icon = {
|
||||
Box(modifier = Modifier
|
||||
.size(10.dp)
|
||||
.background(Color(0xFFFD8205), CircleShape))
|
||||
}, label = "救援地", address = orderInfo?.address ?: "")
|
||||
|
||||
// 只有当目的地不为空时才显示分割线和目的地信息
|
||||
if (! orderInfo?.distAddress.isNullOrBlank()) {
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = 4.dp),
|
||||
color = Color(0xFFEEEEEE))
|
||||
|
||||
AddressItem(icon = {
|
||||
Box(modifier = Modifier
|
||||
.size(10.dp)
|
||||
.background(Color(0xFF5CC4BF), CircleShape))
|
||||
}, label = "目的地", address = orderInfo?.distAddress ?: "")
|
||||
}
|
||||
}
|
||||
|
||||
//重要提示
|
||||
if (! orderInfo?.importantTip.isNullOrBlank()) { // 订单状态
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(brush = Brush.linearGradient(colors = listOf(Color(0xFFFFF3E0),
|
||||
Color(0xFFFFE0B2)),
|
||||
start = androidx.compose.ui.geometry.Offset(0f, 0f),
|
||||
end = androidx.compose.ui.geometry.Offset(Float.POSITIVE_INFINITY, 0f)),
|
||||
shape = RoundedCornerShape(10.dp))
|
||||
.padding(12.dp),
|
||||
contentAlignment = Alignment.Center) {
|
||||
Text(text = orderInfo?.importantTip ?: "",
|
||||
color = Color(0xFFFF5722),
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
modifier = Modifier.basicMarquee())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AddressItem(icon : @Composable () -> Unit, label : String, address : String) {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
icon()
|
||||
Text(text = label, fontSize = 13.sp, color = Color(0x802F3059))
|
||||
}
|
||||
|
||||
Text(text = address,
|
||||
fontSize = 15.sp,
|
||||
color = Color(0xFF2F3059),
|
||||
fontWeight = FontWeight.Medium,
|
||||
modifier = Modifier.padding(start = 18.dp))
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun ServiceMainPreview() {
|
||||
ServicingMainScreen()
|
||||
}
|
@ -48,6 +48,9 @@ class ServicingMainVm : BaseVm<ServicingMainVm.Action, ServicingMainVm.UiState>(
|
||||
LoadingManager.hideLoading()
|
||||
GlobalData.currentOrder = orderInfo
|
||||
updateState(uiState.value.copy(state = 1))
|
||||
if (orderInfos.isNullOrEmpty()) {
|
||||
ToastUtils.showShort("未查询到订单")
|
||||
}
|
||||
},
|
||||
failed = {
|
||||
updateState(uiState.value.copy(state = 2))
|
||||
|
@ -57,7 +57,6 @@ import coil.compose.AsyncImage
|
||||
import com.amap.api.location.AMapLocationClient
|
||||
import com.amap.api.maps.CameraUpdateFactory
|
||||
import com.amap.api.maps.MapView
|
||||
import com.amap.api.maps.model.BitmapDescriptorFactory
|
||||
import com.amap.api.maps.model.LatLng
|
||||
import com.amap.api.maps.model.LatLngBounds
|
||||
import com.amap.api.maps.model.MarkerOptions
|
||||
|
@ -43,102 +43,124 @@ import com.za.ui.view.SignatureView
|
||||
|
||||
class OrderGiveUpActivity : BaseActivity() {
|
||||
|
||||
@Composable
|
||||
override fun ContentView() {
|
||||
val orderInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
intent.getParcelableExtra("orderInfo", OrderInfo::class.java)
|
||||
} else {
|
||||
intent.getParcelableExtra("orderInfo")
|
||||
}
|
||||
@Composable
|
||||
override fun ContentView() {
|
||||
val orderInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
intent.getParcelableExtra("orderInfo", OrderInfo::class.java)
|
||||
} else {
|
||||
intent.getParcelableExtra("orderInfo")
|
||||
}
|
||||
|
||||
OrderGiveUpScreen(orderInfo = orderInfo, taskId = intent.getIntExtra("taskId", 0), giveUpType = intent.getIntExtra("giveUpType", 0))
|
||||
}
|
||||
OrderGiveUpScreen(orderInfo = orderInfo,
|
||||
taskId = intent.getIntExtra("taskId", 0),
|
||||
giveUpType = intent.getIntExtra("giveUpType", 0))
|
||||
}
|
||||
|
||||
companion object {
|
||||
//giveUp type
|
||||
//0 师傅手机操作放弃 1 后台操作放弃 2 师傅出发前后台操作放弃
|
||||
fun goOrderGiveUpActivity(context: Context,
|
||||
orderInfo: OrderInfo? = null,
|
||||
taskId: Int? = null,
|
||||
giveUpType: Int) {
|
||||
val intent = Intent(context, OrderGiveUpActivity::class.java)
|
||||
intent.putExtra("giveUpType", giveUpType)
|
||||
intent.putExtra("orderInfo", orderInfo)
|
||||
intent.putExtra("taskId", taskId)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
companion object {
|
||||
//giveUp type
|
||||
//0 师傅手机操作放弃 1 后台操作放弃 2 师傅出发前后台操作放弃
|
||||
fun goOrderGiveUpActivity(context : Context,
|
||||
orderInfo : OrderInfo? = null,
|
||||
taskId : Int? = null,
|
||||
userOrderId : Int? = null,
|
||||
giveUpType : Int) {
|
||||
val intent = Intent(context, OrderGiveUpActivity::class.java)
|
||||
intent.putExtra("giveUpType", giveUpType)
|
||||
intent.putExtra("orderInfo", orderInfo)
|
||||
intent.putExtra("taskId", taskId)
|
||||
intent.putExtra("userOrderId", userOrderId)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun OrderGiveUpScreen(vm: OrderGiveUpVm = viewModel(), orderInfo: OrderInfo?, taskId: Int, giveUpType: Int) {
|
||||
val uiState = vm.uiState.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
fun OrderGiveUpScreen(vm : OrderGiveUpVm = viewModel(),
|
||||
orderInfo : OrderInfo?,
|
||||
taskId : Int,
|
||||
giveUpType : Int) {
|
||||
val uiState = vm.uiState.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
|
||||
LaunchedEffect(key1 = Unit) {
|
||||
vm.dispatch(OrderGiveUpVm.Action.UpdateState(uiState.value.copy(orderInfo = orderInfo, taskId = taskId, giveUpType = giveUpType)))
|
||||
vm.dispatch(OrderGiveUpVm.Action.Init)
|
||||
}
|
||||
LaunchedEffect(key1 = Unit) {
|
||||
vm.dispatch(OrderGiveUpVm.Action.UpdateState(uiState.value.copy(orderInfo = orderInfo,
|
||||
taskId = taskId,
|
||||
giveUpType = giveUpType)))
|
||||
vm.dispatch(OrderGiveUpVm.Action.Init)
|
||||
}
|
||||
|
||||
if (uiState.value.orderGiveUpSuccess == true) {
|
||||
context.finish()
|
||||
}
|
||||
if (uiState.value.orderGiveUpSuccess == true) {
|
||||
context.finish()
|
||||
}
|
||||
|
||||
if (uiState.value.isGoNextPageDialog == true) {
|
||||
CommonDialog(cancelText = "取消", confirmText = "是否确认放弃订单", title = "放弃订单", cancelEnable = true, cancel = {
|
||||
vm.dispatch(OrderGiveUpVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = false)))
|
||||
}, dismiss = {
|
||||
vm.dispatch(OrderGiveUpVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = false)))
|
||||
}, confirm = {
|
||||
vm.dispatch(OrderGiveUpVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = false)))
|
||||
vm.dispatch(OrderGiveUpVm.Action.UpdateTask)
|
||||
})
|
||||
}
|
||||
if (uiState.value.isGoNextPageDialog == true) {
|
||||
CommonDialog(cancelText = "取消",
|
||||
confirmText = "是否确认放弃订单",
|
||||
title = "放弃订单",
|
||||
cancelEnable = true,
|
||||
cancel = {
|
||||
vm.dispatch(OrderGiveUpVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = false)))
|
||||
},
|
||||
dismiss = {
|
||||
vm.dispatch(OrderGiveUpVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = false)))
|
||||
},
|
||||
confirm = {
|
||||
vm.dispatch(OrderGiveUpVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = false)))
|
||||
vm.dispatch(OrderGiveUpVm.Action.UpdateTask)
|
||||
})
|
||||
}
|
||||
|
||||
Scaffold(topBar = {
|
||||
HeadView(title = "放弃信息", onBack = { context.finish() })
|
||||
}, bottomBar = {
|
||||
CommonButton(text = "提交信息,确认放弃案件") {
|
||||
vm.dispatch(OrderGiveUpVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = true)))
|
||||
}
|
||||
}) { it ->
|
||||
LazyColumn(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(it), contentPadding = PaddingValues(10.dp)) {
|
||||
Scaffold(topBar = {
|
||||
HeadView(title = "放弃信息", onBack = { context.finish() })
|
||||
}, bottomBar = {
|
||||
CommonButton(text = "提交信息,确认放弃案件") {
|
||||
vm.dispatch(OrderGiveUpVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = true)))
|
||||
}
|
||||
}) { it ->
|
||||
LazyColumn(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(it),
|
||||
contentPadding = PaddingValues(10.dp)) {
|
||||
|
||||
itemsIndexed(items = uiState.value.photoTemplateList
|
||||
?: arrayListOf(), key = { _, item -> item.hashCode() }) { index: Int, item: PhotoTemplateInfo ->
|
||||
InServicingPhotoView(photoTemplateInfo = item, index = index + 1, success = {
|
||||
vm.dispatch(OrderGiveUpVm.Action.UpdatePhotoTemplate(it))
|
||||
})
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
}
|
||||
itemsIndexed(items = uiState.value.photoTemplateList ?: arrayListOf(),
|
||||
key = { _, item -> item.hashCode() }) { index : Int, item : PhotoTemplateInfo ->
|
||||
InServicingPhotoView(photoTemplateInfo = item, index = index + 1, success = {
|
||||
vm.dispatch(OrderGiveUpVm.Action.UpdatePhotoTemplate(it))
|
||||
})
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
}
|
||||
|
||||
if (uiState.value.giveUpType == 0) {
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
Column(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 10.dp)
|
||||
.background(color = Color.White, shape = RoundedCornerShape(6.dp))
|
||||
.padding(10.dp)) {
|
||||
if (uiState.value.giveUpType == 0) {
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
Column(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 10.dp)
|
||||
.background(color = Color.White, shape = RoundedCornerShape(6.dp))
|
||||
.padding(10.dp)) {
|
||||
|
||||
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(text = "司机签名", color = Color.Black, fontWeight = FontWeight.Medium, fontSize = 14.sp)
|
||||
Spacer(Modifier.weight(1f))
|
||||
AsyncImage(model = R.drawable.sv_sign_new, contentDescription = "", modifier = Modifier.size(20.dp))
|
||||
}
|
||||
Row(modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(text = "司机签名",
|
||||
color = Color.Black,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp)
|
||||
Spacer(Modifier.weight(1f))
|
||||
AsyncImage(model = R.drawable.sv_sign_new,
|
||||
contentDescription = "",
|
||||
modifier = Modifier.size(20.dp))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
SignatureView(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(122.dp), success = {
|
||||
vm.dispatch(OrderGiveUpVm.Action.UploadSign(it))
|
||||
}, serverPath = uiState.value.serverServicePeopleSignPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
SignatureView(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(122.dp), success = {
|
||||
vm.dispatch(OrderGiveUpVm.Action.UploadSign(it))
|
||||
}, serverPath = uiState.value.serverServicePeopleSignPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -46,186 +46,287 @@ import com.za.ui.servicing.order_give_up.OrderGiveUpActivity
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun InServicingHeadView(title: String, onBack: () -> Unit = {}, orderInfo: OrderInfo?, isCanBack: Boolean = true) {
|
||||
val context = LocalContext.current
|
||||
val showBottomSheetDialog = remember { mutableStateOf(false) }
|
||||
val showNavigationDialog = remember { mutableStateOf(false) }
|
||||
val showCallPhoneDialog = remember { mutableStateOf(false) }
|
||||
fun InServicingHeadView(title : String,
|
||||
onBack : () -> Unit = {},
|
||||
orderInfo : OrderInfo?,
|
||||
isCanBack : Boolean = true) {
|
||||
val context = LocalContext.current
|
||||
val showBottomSheetDialog = remember { mutableStateOf(false) }
|
||||
val showNavigationDialog = remember { mutableStateOf(false) }
|
||||
val showCallPhoneDialog = remember { mutableStateOf(false) }
|
||||
val showCallServicePhoneDialog = remember { mutableStateOf(false) }
|
||||
|
||||
if (showNavigationDialog.value) {
|
||||
StartNavigationView(orderInfo = orderInfo, dismiss = { showNavigationDialog.value = false })
|
||||
}
|
||||
if (showNavigationDialog.value) {
|
||||
StartNavigationView(orderInfo = orderInfo, dismiss = { showNavigationDialog.value = false })
|
||||
}
|
||||
|
||||
if (showCallPhoneDialog.value) {
|
||||
CommonDialog(
|
||||
cancelText = "取消",
|
||||
confirmText = "确定",
|
||||
title = "是否联系客户?",
|
||||
cancelEnable = true,
|
||||
cancel = {
|
||||
showCallPhoneDialog.value = false
|
||||
},
|
||||
dismiss = { showCallPhoneDialog.value = false },
|
||||
confirm = {
|
||||
showCallPhoneDialog.value = false
|
||||
context.callPhone(orderInfo?.customerPhone)
|
||||
context.finish()
|
||||
})
|
||||
}
|
||||
if (showCallPhoneDialog.value) {
|
||||
CommonDialog(cancelText = "取消",
|
||||
confirmText = "确定",
|
||||
title = "是否联系客户?",
|
||||
cancelEnable = true,
|
||||
cancel = {
|
||||
showCallPhoneDialog.value = false
|
||||
},
|
||||
dismiss = { showCallPhoneDialog.value = false },
|
||||
confirm = {
|
||||
showCallPhoneDialog.value = false
|
||||
context.callPhone(orderInfo?.customerPhone)
|
||||
context.finish()
|
||||
})
|
||||
}
|
||||
|
||||
if (showCallServicePhoneDialog.value) {
|
||||
CommonDialog(cancelText = "取消",
|
||||
confirmText = "确定",
|
||||
title = "是否联系中道客服?",
|
||||
cancelEnable = true,
|
||||
cancel = {
|
||||
showCallServicePhoneDialog.value = false
|
||||
},
|
||||
dismiss = { showCallServicePhoneDialog.value = false },
|
||||
confirm = {
|
||||
showCallServicePhoneDialog.value = false
|
||||
context.callPhone(orderInfo?.hotline)
|
||||
context.finish()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
if (showBottomSheetDialog.value) {
|
||||
ModalBottomSheet(containerColor = Color.White,
|
||||
onDismissRequest = { showBottomSheetDialog.value = false }) {
|
||||
Column(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(10.dp)) {
|
||||
if (showBottomSheetDialog.value) {
|
||||
ModalBottomSheet(containerColor = Color.White,
|
||||
onDismissRequest = { showBottomSheetDialog.value = false }) {
|
||||
Column(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(10.dp)) {
|
||||
|
||||
if (!orderInfo?.customerReportImgs.isNullOrBlank()) {
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
showBottomSheetDialog.value = false
|
||||
OrderRequirementsActivity.goOrderRequirementsActivity(context, orderInfo, type = Const.InServiceSettingType.ON_SITE_PHOTO)
|
||||
}, contentAlignment = Alignment.Center) {
|
||||
Text(text = "现场照片", fontSize = 15.sp, fontWeight = FontWeight.Medium, color = Color.Black)
|
||||
}
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = 10.dp), color = black5)
|
||||
}
|
||||
if (! orderInfo?.customerReportImgs.isNullOrBlank()) {
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
showBottomSheetDialog.value = false
|
||||
OrderRequirementsActivity.goOrderRequirementsActivity(context,
|
||||
orderInfo,
|
||||
type = Const.InServiceSettingType.ON_SITE_PHOTO)
|
||||
}, contentAlignment = Alignment.Center) {
|
||||
Text(text = "现场照片",
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = Color.Black)
|
||||
}
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = 10.dp), color = black5)
|
||||
}
|
||||
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
showNavigationDialog.value = true
|
||||
showBottomSheetDialog.value = false
|
||||
}, contentAlignment = Alignment.Center) {
|
||||
Text(text = "开启外部导航", fontSize = 15.sp, fontWeight = FontWeight.Medium, color = Color.Black)
|
||||
}
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = 10.dp), color = black5)
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
showNavigationDialog.value = true
|
||||
showBottomSheetDialog.value = false
|
||||
}, contentAlignment = Alignment.Center) {
|
||||
Text(text = "开启外部导航",
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = Color.Black)
|
||||
}
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = 10.dp), color = black5)
|
||||
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
showBottomSheetDialog.value = false
|
||||
OrderRequirementsActivity.goOrderRequirementsActivity(context, orderInfo, type = Const.InServiceSettingType.ORDER_REQUIREMENTS)
|
||||
}, contentAlignment = Alignment.Center) {
|
||||
Text(text = "案件要求", fontSize = 15.sp, fontWeight = FontWeight.Medium, color = Color.Black)
|
||||
}
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = 10.dp), color = black5)
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
showBottomSheetDialog.value = false
|
||||
OrderRequirementsActivity.goOrderRequirementsActivity(context,
|
||||
orderInfo,
|
||||
type = Const.InServiceSettingType.ORDER_REQUIREMENTS)
|
||||
}, contentAlignment = Alignment.Center) {
|
||||
Text(text = "案件要求",
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = Color.Black)
|
||||
}
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = 10.dp), color = black5)
|
||||
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
showBottomSheetDialog.value = false
|
||||
OrderRequirementsActivity.goOrderRequirementsActivity(context, orderInfo, type = Const.InServiceSettingType.ORDER_DETAIL)
|
||||
}, contentAlignment = Alignment.Center) {
|
||||
Text(text = "案件详情", fontSize = 15.sp, fontWeight = FontWeight.Medium, color = Color.Black)
|
||||
}
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = 10.dp), color = black5)
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
showBottomSheetDialog.value = false
|
||||
OrderRequirementsActivity.goOrderRequirementsActivity(context,
|
||||
orderInfo,
|
||||
type = Const.InServiceSettingType.ORDER_DETAIL)
|
||||
}, contentAlignment = Alignment.Center) {
|
||||
Text(text = "案件详情",
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = Color.Black)
|
||||
}
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = 10.dp), color = black5)
|
||||
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
showBottomSheetDialog.value = false
|
||||
OrderGiveUpActivity.goOrderGiveUpActivity(context, orderInfo = orderInfo, giveUpType = 0)
|
||||
}, contentAlignment = Alignment.Center) {
|
||||
Text(text = "订单放弃", fontSize = 15.sp, fontWeight = FontWeight.Medium, color = Color.Red)
|
||||
}
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = 10.dp), color = black5)
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
showBottomSheetDialog.value = false
|
||||
OrderGiveUpActivity.goOrderGiveUpActivity(context,
|
||||
orderInfo = orderInfo,
|
||||
userOrderId = orderInfo?.userOrderId,
|
||||
giveUpType = 0)
|
||||
}, contentAlignment = Alignment.Center) {
|
||||
Text(text = "订单放弃",
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = Color.Black)
|
||||
}
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = 10.dp), color = black5)
|
||||
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
showBottomSheetDialog.value = false
|
||||
showCallPhoneDialog.value = true
|
||||
}, contentAlignment = Alignment.Center) {
|
||||
Text(text = "拨打电话", fontSize = 15.sp, fontWeight = FontWeight.Medium, color = Color.Black)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
showBottomSheetDialog.value = false
|
||||
showCallPhoneDialog.value = true
|
||||
}, contentAlignment = Alignment.Center) {
|
||||
Text(text = "拨打客户电话",
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = Color.Black)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = 10.dp), color = black5)
|
||||
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
showBottomSheetDialog.value = false
|
||||
showCallServicePhoneDialog.value = true
|
||||
}, contentAlignment = Alignment.Center) {
|
||||
Text(text = "联系中道客服",
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = Color.Black)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CenterAlignedTopAppBar(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(color = headBgColor)
|
||||
.padding(top = headPadding),
|
||||
colors = TopAppBarDefaults.centerAlignedTopAppBarColors().copy(containerColor = headBgColor, titleContentColor = Color.White),
|
||||
title = { Text(text = title, fontSize = 15.sp, fontWeight = FontWeight.Medium) },
|
||||
navigationIcon = {
|
||||
if (isCanBack) {
|
||||
AsyncImage(model = R.drawable.sv_back, contentDescription = "", modifier = Modifier
|
||||
.size(40.dp)
|
||||
.clickable { onBack() }
|
||||
.padding(10.dp))
|
||||
}
|
||||
}, actions = {
|
||||
Box(modifier = Modifier
|
||||
.size(39.dp)
|
||||
.clickable { showBottomSheetDialog.value = true }
|
||||
.padding(10.dp), contentAlignment = Alignment.Center) {
|
||||
AsyncImage(model = R.drawable.sv_setting, contentDescription = "", modifier = Modifier.fillMaxSize())
|
||||
}
|
||||
})
|
||||
CenterAlignedTopAppBar(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(color = headBgColor)
|
||||
.padding(top = headPadding),
|
||||
colors = TopAppBarDefaults.centerAlignedTopAppBarColors()
|
||||
.copy(containerColor = headBgColor, titleContentColor = Color.White),
|
||||
title = { Text(text = title, fontSize = 15.sp, fontWeight = FontWeight.Medium) },
|
||||
navigationIcon = {
|
||||
if (isCanBack) {
|
||||
AsyncImage(model = R.drawable.sv_back,
|
||||
contentDescription = "",
|
||||
modifier = Modifier
|
||||
.size(40.dp)
|
||||
.clickable { onBack() }
|
||||
.padding(10.dp))
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
Box(modifier = Modifier
|
||||
.size(39.dp)
|
||||
.clickable { showBottomSheetDialog.value = true }
|
||||
.padding(10.dp), contentAlignment = Alignment.Center) {
|
||||
AsyncImage(model = R.drawable.sv_setting,
|
||||
contentDescription = "",
|
||||
modifier = Modifier.fillMaxSize())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun StartNavigationView(orderInfo: OrderInfo?, dismiss: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
fun StartNavigationView(orderInfo : OrderInfo?, dismiss : () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
|
||||
Dialog(onDismissRequest = { dismiss() }) {
|
||||
Row(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(180.dp)
|
||||
.background(color = Color.White, shape = RoundedCornerShape(8.dp))
|
||||
.padding(10.dp), verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceAround) {
|
||||
if (MapUtil.isGdMapInstalled(context)) {
|
||||
Column(modifier = Modifier.clickable {
|
||||
if ("SENDTO" == orderInfo?.taskState) {
|
||||
MapUtil.startNavigationGd(context, orderInfo.distLat, lng = orderInfo.distLng, address = orderInfo.distAddress)
|
||||
} else {
|
||||
MapUtil.startNavigationGd(context, orderInfo?.lat, lng = orderInfo?.lng, address = orderInfo?.address)
|
||||
}
|
||||
dismiss()
|
||||
}) {
|
||||
AsyncImage(model = R.drawable.sv_amap_icon, contentDescription = "", modifier = Modifier.size(60.dp))
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
Text(text = "高德地图", color = Color.Black, fontWeight = FontWeight.Medium, fontSize = 14.sp)
|
||||
}
|
||||
}
|
||||
Dialog(onDismissRequest = { dismiss() }) {
|
||||
Row(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(180.dp)
|
||||
.background(color = Color.White, shape = RoundedCornerShape(8.dp))
|
||||
.padding(10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceAround) {
|
||||
if (MapUtil.isGdMapInstalled(context)) {
|
||||
Column(modifier = Modifier.clickable {
|
||||
if ("SENDTO" == orderInfo?.taskState) {
|
||||
MapUtil.startNavigationGd(context,
|
||||
orderInfo.distLat,
|
||||
lng = orderInfo.distLng,
|
||||
address = orderInfo.distAddress)
|
||||
} else {
|
||||
MapUtil.startNavigationGd(context,
|
||||
orderInfo?.lat,
|
||||
lng = orderInfo?.lng,
|
||||
address = orderInfo?.address)
|
||||
}
|
||||
dismiss()
|
||||
}) {
|
||||
AsyncImage(model = R.drawable.sv_amap_icon,
|
||||
contentDescription = "",
|
||||
modifier = Modifier.size(60.dp))
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
Text(text = "高德地图",
|
||||
color = Color.Black,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp)
|
||||
}
|
||||
}
|
||||
|
||||
if (MapUtil.isBaiduMapInstalled(context)) {
|
||||
Column(modifier = Modifier.clickable {
|
||||
if ("SENDTO" == orderInfo?.taskState) {
|
||||
MapUtil.startNavigationBd(context, orderInfo.distLat, lng = orderInfo.distLng, address = orderInfo.distAddress)
|
||||
} else {
|
||||
MapUtil.startNavigationBd(context, orderInfo?.lat, lng = orderInfo?.lng, address = orderInfo?.address)
|
||||
}
|
||||
dismiss()
|
||||
}) {
|
||||
AsyncImage(model = R.drawable.sv_baidu_icon, contentDescription = "", modifier = Modifier.size(60.dp))
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
Text(text = "百度地图", color = Color.Black, fontWeight = FontWeight.Medium, fontSize = 14.sp)
|
||||
}
|
||||
}
|
||||
if (MapUtil.isBaiduMapInstalled(context)) {
|
||||
Column(modifier = Modifier.clickable {
|
||||
if ("SENDTO" == orderInfo?.taskState) {
|
||||
MapUtil.startNavigationBd(context,
|
||||
orderInfo.distLat,
|
||||
lng = orderInfo.distLng,
|
||||
address = orderInfo.distAddress)
|
||||
} else {
|
||||
MapUtil.startNavigationBd(context,
|
||||
orderInfo?.lat,
|
||||
lng = orderInfo?.lng,
|
||||
address = orderInfo?.address)
|
||||
}
|
||||
dismiss()
|
||||
}) {
|
||||
AsyncImage(model = R.drawable.sv_baidu_icon,
|
||||
contentDescription = "",
|
||||
modifier = Modifier.size(60.dp))
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
Text(text = "百度地图",
|
||||
color = Color.Black,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp)
|
||||
}
|
||||
}
|
||||
|
||||
if (MapUtil.isTencentInstalled(context)) {
|
||||
Column(modifier = Modifier.clickable {
|
||||
if ("SENDTO" == orderInfo?.taskState) {
|
||||
MapUtil.startNavigationTencent(context, orderInfo.distLat, lng = orderInfo.distLng, address = orderInfo.distAddress)
|
||||
} else {
|
||||
MapUtil.startNavigationTencent(context, orderInfo?.lat, lng = orderInfo?.lng, address = orderInfo?.address)
|
||||
}
|
||||
dismiss()
|
||||
}) {
|
||||
AsyncImage(model = R.drawable.sv_tencent_icon, contentDescription = "", modifier = Modifier.size(60.dp))
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
Text(text = "腾讯地图", color = Color.Black, fontWeight = FontWeight.Medium, fontSize = 14.sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (MapUtil.isTencentInstalled(context)) {
|
||||
Column(modifier = Modifier.clickable {
|
||||
if ("SENDTO" == orderInfo?.taskState) {
|
||||
MapUtil.startNavigationTencent(context,
|
||||
orderInfo.distLat,
|
||||
lng = orderInfo.distLng,
|
||||
address = orderInfo.distAddress)
|
||||
} else {
|
||||
MapUtil.startNavigationTencent(context,
|
||||
orderInfo?.lat,
|
||||
lng = orderInfo?.lng,
|
||||
address = orderInfo?.address)
|
||||
}
|
||||
dismiss()
|
||||
}) {
|
||||
AsyncImage(model = R.drawable.sv_tencent_icon,
|
||||
contentDescription = "",
|
||||
modifier = Modifier.size(60.dp))
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
Text(text = "腾讯地图",
|
||||
color = Color.Black,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,12 @@
|
||||
package com.za.ui.servicing.wait_to_start
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@ -55,476 +59,367 @@ import com.amap.api.maps.model.LatLng
|
||||
import com.amap.api.maps.model.LatLngBounds
|
||||
import com.amap.api.maps.model.MarkerOptions
|
||||
import com.amap.api.maps.model.PolylineOptions
|
||||
import com.blankj.utilcode.util.ToastUtils
|
||||
import com.za.base.BaseActivity
|
||||
import com.za.base.theme.headBgColor
|
||||
import com.za.base.view.CommonDialog
|
||||
import com.za.common.GlobalData
|
||||
import com.za.common.log.LogUtil
|
||||
import com.za.common.util.ImageUtil
|
||||
import com.za.common.util.ServicingSpeechManager
|
||||
import com.za.ext.copy
|
||||
import com.za.ext.finish
|
||||
import com.za.ext.goNextPage
|
||||
import com.za.servicing.R
|
||||
import com.za.ui.camera.ZdCameraXActivity
|
||||
import com.za.ui.servicing.view.InServicingHeadView
|
||||
|
||||
|
||||
class WaitToStartActivity : BaseActivity() {
|
||||
@Composable
|
||||
override fun ContentView() {
|
||||
WaitToStartScreen()
|
||||
}
|
||||
@Composable
|
||||
override fun ContentView() {
|
||||
WaitToStartScreen()
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun WaitToStartScreen(vm: WaitToStartVm = viewModel()) {
|
||||
val uiState = vm.uiState.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
val mapView = remember { MapView(context) }
|
||||
fun WaitToStartScreen(vm : WaitToStartVm = viewModel()) {
|
||||
val uiState = vm.uiState.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
val mapView = remember { MapView(context) }
|
||||
|
||||
// 添加 BottomSheet 状态
|
||||
val bottomSheetState = rememberStandardBottomSheetState(
|
||||
initialValue = SheetValue.Expanded
|
||||
)
|
||||
val scaffoldState = rememberBottomSheetScaffoldState(
|
||||
bottomSheetState = bottomSheetState
|
||||
)
|
||||
val getResult =
|
||||
rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) { it ->
|
||||
if (it.resultCode == Activity.RESULT_OK) {
|
||||
val value = it.data?.getStringExtra("path")
|
||||
LogUtil.print("takePhoto", "path==$value")
|
||||
if (value.isNullOrBlank()) {
|
||||
ToastUtils.showLong("照片路径为空,请重新拍摄!")
|
||||
return@rememberLauncherForActivityResult
|
||||
}
|
||||
vm.dispatch(WaitToStartVm.Action.CompareServicePeople(value))
|
||||
}
|
||||
}
|
||||
|
||||
DisposableEffect(key1 = lifecycleOwner) {
|
||||
val observer = LifecycleEventObserver { _, event ->
|
||||
when (event) {
|
||||
Lifecycle.Event.ON_CREATE -> {
|
||||
mapView.onCreate(Bundle())
|
||||
vm.dispatch(WaitToStartVm.Action.Init)
|
||||
ServicingSpeechManager.playStartTip(context)
|
||||
}
|
||||
// 添加 BottomSheet 状态
|
||||
val bottomSheetState = rememberStandardBottomSheetState(initialValue = SheetValue.Expanded)
|
||||
val scaffoldState = rememberBottomSheetScaffoldState(bottomSheetState = bottomSheetState)
|
||||
|
||||
Lifecycle.Event.ON_RESUME -> mapView.onResume()
|
||||
Lifecycle.Event.ON_PAUSE -> mapView.onPause()
|
||||
Lifecycle.Event.ON_DESTROY -> mapView.onDestroy()
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
DisposableEffect(key1 = lifecycleOwner) {
|
||||
val observer = LifecycleEventObserver { _, event ->
|
||||
when (event) {
|
||||
Lifecycle.Event.ON_CREATE -> {
|
||||
mapView.onCreate(Bundle())
|
||||
vm.dispatch(WaitToStartVm.Action.Init)
|
||||
ServicingSpeechManager.playStartTip(context)
|
||||
}
|
||||
|
||||
lifecycleOwner.lifecycle.addObserver(observer)
|
||||
onDispose {
|
||||
lifecycleOwner.lifecycle.removeObserver(observer)
|
||||
}
|
||||
}
|
||||
Lifecycle.Event.ON_RESUME -> mapView.onResume()
|
||||
Lifecycle.Event.ON_PAUSE -> mapView.onPause()
|
||||
Lifecycle.Event.ON_DESTROY -> mapView.onDestroy()
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
if (uiState.value.goNextPage != null) {
|
||||
goNextPage(uiState.value.goNextPage?.nextState, context)
|
||||
}
|
||||
lifecycleOwner.lifecycle.addObserver(observer)
|
||||
onDispose {
|
||||
lifecycleOwner.lifecycle.removeObserver(observer)
|
||||
}
|
||||
}
|
||||
|
||||
if (uiState.value.isGoNextPageDialog == true) {
|
||||
CommonDialog(
|
||||
cancelText = "取消",
|
||||
confirmText = "前往下一步",
|
||||
title = "是否前往下一步?",
|
||||
cancelEnable = true,
|
||||
cancel = {
|
||||
vm.dispatch(WaitToStartVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = false)))
|
||||
},
|
||||
dismiss = { vm.dispatch(WaitToStartVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = false))) },
|
||||
confirm = {
|
||||
vm.dispatch(WaitToStartVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = false)))
|
||||
vm.dispatch(WaitToStartVm.Action.UpdateTask)
|
||||
}
|
||||
)
|
||||
}
|
||||
if (uiState.value.goNextPage != null) {
|
||||
goNextPage(uiState.value.goNextPage?.nextState, context)
|
||||
vm.dispatch(WaitToStartVm.Action.UpdateState(uiState.value.copy(goNextPage = null)))
|
||||
}
|
||||
|
||||
BottomSheetScaffold(
|
||||
scaffoldState = scaffoldState,
|
||||
topBar = {
|
||||
InServicingHeadView(
|
||||
title = "调度成功,等待发车",
|
||||
onBack = { context.finish() },
|
||||
orderInfo = uiState.value.orderInfo
|
||||
)
|
||||
},
|
||||
sheetContent = {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
// 滑动指示器
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 8.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(32.dp)
|
||||
.height(4.dp)
|
||||
.background(
|
||||
color = Color(0xFFE0E0E0),
|
||||
shape = RoundedCornerShape(2.dp)
|
||||
)
|
||||
)
|
||||
}
|
||||
if (uiState.value.showServicePeopleConfirmDialog == true) {
|
||||
CommonDialog(cancelText = "取消",
|
||||
confirmText = "去拍照",
|
||||
title = "服务人员确认",
|
||||
cancelEnable = true,
|
||||
cancel = {
|
||||
vm.dispatch(WaitToStartVm.Action.UpdateState(uiState.value.copy(
|
||||
showServicePeopleConfirmDialog = false)))
|
||||
},
|
||||
dismiss = {
|
||||
vm.dispatch(WaitToStartVm.Action.UpdateState(uiState.value.copy(
|
||||
showServicePeopleConfirmDialog = false)))
|
||||
},
|
||||
confirm = {
|
||||
vm.dispatch(WaitToStartVm.Action.UpdateState(uiState.value.copy(
|
||||
showServicePeopleConfirmDialog = false)))
|
||||
val intent = Intent(context, ZdCameraXActivity::class.java)
|
||||
intent.putExtra("isBack", false)
|
||||
getResult.launch(intent)
|
||||
})
|
||||
}
|
||||
|
||||
// 距离和时间信息
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = if (uiState.value.estimatedArrivalTime.isNotEmpty())
|
||||
"预计到达: ${uiState.value.estimatedArrivalTime}"
|
||||
else
|
||||
"计算中...",
|
||||
color = Color(0xFF666666),
|
||||
fontSize = 14.sp
|
||||
)
|
||||
BottomSheetScaffold(scaffoldState = scaffoldState,
|
||||
topBar = {
|
||||
InServicingHeadView(title = "调度成功,等待发车",
|
||||
onBack = { context.finish() },
|
||||
orderInfo = uiState.value.orderInfo)
|
||||
},
|
||||
sheetContent = {
|
||||
Column(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.verticalScroll(rememberScrollState())) { // 滑动指示器
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 8.dp),
|
||||
contentAlignment = Alignment.Center) {
|
||||
Box(modifier = Modifier
|
||||
.width(32.dp)
|
||||
.height(4.dp)
|
||||
.background(color = Color(0xFFE0E0E0), shape = RoundedCornerShape(2.dp)))
|
||||
}
|
||||
|
||||
Text(
|
||||
text = if (uiState.value.remainingDistance > 0)
|
||||
"距离救援地: %.1fkm".format(uiState.value.remainingDistance / 1000f)
|
||||
else
|
||||
"计算中...",
|
||||
color = Color(0xFFFF4D4F),
|
||||
fontSize = 14.sp
|
||||
)
|
||||
}
|
||||
// 距离和时间信息
|
||||
Row(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(text = if (uiState.value.estimatedArrivalTime.isNotEmpty()) "预计到达: ${uiState.value.estimatedArrivalTime}"
|
||||
else "计算中...", color = Color(0xFF666666), fontSize = 14.sp)
|
||||
|
||||
HorizontalDivider(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.alpha(0.1f)
|
||||
)
|
||||
Text(text = if (uiState.value.remainingDistance > 0) "距离救援地: %.1fkm".format(
|
||||
uiState.value.remainingDistance / 1000f)
|
||||
else "计算中...", color = Color(0xFFFF4D4F), fontSize = 14.sp)
|
||||
}
|
||||
|
||||
// 订单信息
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp)
|
||||
) {
|
||||
// 订单类型
|
||||
Text(
|
||||
text = uiState.value.orderInfo?.serviceTypeName ?: "",
|
||||
fontSize = 18.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = Color.Black
|
||||
)
|
||||
HorizontalDivider(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.alpha(0.1f))
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
// 订单信息
|
||||
Column(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp)) { // 订单类型
|
||||
Text(text = uiState.value.orderInfo?.serviceTypeName ?: "",
|
||||
fontSize = 18.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = Color.Black)
|
||||
|
||||
// 订单标签
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(Color(0xFF9BA1B2), RoundedCornerShape(4.dp))
|
||||
.padding(horizontal = 6.dp, vertical = 2.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "月结".takeIf { uiState.value.orderInfo?.settleType == 1 }
|
||||
?: "现金",
|
||||
color = Color.White,
|
||||
fontSize = 12.sp
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Text(
|
||||
text = uiState.value.orderInfo?.orderSource ?: "",
|
||||
color = Color.Black,
|
||||
fontSize = 12.sp
|
||||
)
|
||||
// 订单标签
|
||||
Row(verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Box(modifier = Modifier
|
||||
.background(Color(0xFF9BA1B2), RoundedCornerShape(4.dp))
|
||||
.padding(horizontal = 6.dp, vertical = 2.dp)) {
|
||||
Text(text = "月结".takeIf { uiState.value.orderInfo?.settleType == 1 }
|
||||
?: "现金", color = Color.White, fontSize = 12.sp)
|
||||
}
|
||||
|
||||
Text(
|
||||
text = uiState.value.orderInfo?.addressProperty ?: "",
|
||||
color = Color(0xFFFD8205),
|
||||
fontSize = 12.sp,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
}
|
||||
Text(text = uiState.value.orderInfo?.orderSource ?: "",
|
||||
color = Color.Black,
|
||||
fontSize = 12.sp)
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Text(text = uiState.value.orderInfo?.addressProperty ?: "",
|
||||
color = Color(0xFFFD8205),
|
||||
fontSize = 12.sp,
|
||||
fontWeight = FontWeight.Medium)
|
||||
}
|
||||
|
||||
// 订单号
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.clickable { uiState.value.orderInfo?.taskCode?.copy(context) }
|
||||
) {
|
||||
Text(
|
||||
text = "单号",
|
||||
color = Color(0xFF999999),
|
||||
fontSize = 13.sp
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
// 订单号
|
||||
Row(verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.clickable {
|
||||
uiState.value.orderInfo?.taskCode?.copy(context)
|
||||
}) {
|
||||
Text(text = "单号", color = Color(0xFF999999), fontSize = 13.sp)
|
||||
|
||||
Text(
|
||||
text = uiState.value.orderInfo?.taskCode ?: "",
|
||||
color = Color(0xFF666666),
|
||||
fontSize = 14.sp
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(text = uiState.value.orderInfo?.taskCode ?: "",
|
||||
color = Color(0xFF666666),
|
||||
fontSize = 14.sp)
|
||||
|
||||
AsyncImage(
|
||||
model = R.drawable.sv_copy,
|
||||
contentDescription = "copy",
|
||||
modifier = Modifier.size(16.dp)
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
AsyncImage(model = R.drawable.sv_copy,
|
||||
contentDescription = "copy",
|
||||
modifier = Modifier.size(16.dp))
|
||||
}
|
||||
|
||||
// 地址信息
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
// 救援地
|
||||
Row(
|
||||
verticalAlignment = Alignment.Top,
|
||||
modifier = Modifier.clickable {
|
||||
// 点击救援地时移动地图到救援位置
|
||||
uiState.value.orderInfo?.let { order ->
|
||||
if (order.lat != null && order.lat != 0.0 &&
|
||||
order.lng != null && order.lng != 0.0
|
||||
) {
|
||||
mapView.map.animateCamera(
|
||||
CameraUpdateFactory.newLatLngZoom(
|
||||
LatLng(order.lat!!, order.lng!!),
|
||||
16f
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
AsyncImage(
|
||||
model = R.drawable.sv_rescuing,
|
||||
contentDescription = "rescue",
|
||||
modifier = Modifier.size(16.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
// 地址信息
|
||||
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) { // 救援地
|
||||
Row(verticalAlignment = Alignment.Top,
|
||||
modifier = Modifier.clickable { // 点击救援地时移动地图到救援位置
|
||||
uiState.value.orderInfo?.let { order ->
|
||||
if (order.lat != null && order.lat != 0.0 && order.lng != null && order.lng != 0.0) {
|
||||
mapView.map.animateCamera(CameraUpdateFactory.newLatLngZoom(
|
||||
LatLng(order.lat !!, order.lng !!),
|
||||
16f))
|
||||
}
|
||||
}
|
||||
}) {
|
||||
AsyncImage(model = R.drawable.sv_rescuing,
|
||||
contentDescription = "rescue",
|
||||
modifier = Modifier.size(16.dp))
|
||||
|
||||
Text(
|
||||
text = uiState.value.orderInfo?.address ?: "",
|
||||
color = Color.Black,
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
|
||||
// 目的地
|
||||
if (!uiState.value.orderInfo?.distAddress.isNullOrBlank()) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.Top,
|
||||
modifier = Modifier.clickable {
|
||||
// 点击目的地时移动地图到目的地位置
|
||||
uiState.value.orderInfo?.let { order ->
|
||||
if (order.distLat != null && order.distLat != 0.0 &&
|
||||
order.distLng != null && order.distLng != 0.0
|
||||
) {
|
||||
mapView.map.animateCamera(
|
||||
CameraUpdateFactory.newLatLngZoom(
|
||||
LatLng(order.distLat!!, order.distLng!!),
|
||||
16f
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
AsyncImage(
|
||||
model = R.drawable.sv_dist,
|
||||
contentDescription = "destination",
|
||||
modifier = Modifier.size(16.dp)
|
||||
)
|
||||
Text(text = uiState.value.orderInfo?.address ?: "",
|
||||
color = Color.Black,
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Medium)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
// 目的地
|
||||
if (! uiState.value.orderInfo?.distAddress.isNullOrBlank()) {
|
||||
Row(verticalAlignment = Alignment.Top,
|
||||
modifier = Modifier.clickable { // 点击目的地时移动地图到目的地位置
|
||||
uiState.value.orderInfo?.let { order ->
|
||||
if (order.distLat != null && order.distLat != 0.0 && order.distLng != null && order.distLng != 0.0) {
|
||||
mapView.map.animateCamera(CameraUpdateFactory.newLatLngZoom(
|
||||
LatLng(order.distLat !!, order.distLng !!),
|
||||
16f))
|
||||
}
|
||||
}
|
||||
}) {
|
||||
AsyncImage(model = R.drawable.sv_dist,
|
||||
contentDescription = "destination",
|
||||
modifier = Modifier.size(16.dp))
|
||||
|
||||
Text(
|
||||
text = uiState.value.orderInfo?.distAddress ?: "",
|
||||
color = Color.Black,
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Text(text = uiState.value.orderInfo?.distAddress ?: "",
|
||||
color = Color.Black,
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 发车按钮
|
||||
Button(
|
||||
onClick = { vm.dispatch(WaitToStartVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = true))) },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(44.dp)
|
||||
.padding(horizontal = 16.dp),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = headBgColor
|
||||
),
|
||||
shape = RoundedCornerShape(8.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "发车",
|
||||
color = Color.White,
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
}
|
||||
},
|
||||
sheetPeekHeight = 180.dp,
|
||||
sheetShape = RoundedCornerShape(topStart = 12.dp, topEnd = 12.dp),
|
||||
sheetContainerColor = Color.White,
|
||||
sheetDragHandle = null,
|
||||
sheetSwipeEnabled = true
|
||||
) { paddingValues ->
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
) {
|
||||
AndroidView(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
factory = {
|
||||
AMapLocationClient.updatePrivacyShow(context, true, true)
|
||||
AMapLocationClient.updatePrivacyAgree(context, true)
|
||||
mapView.apply {
|
||||
map.apply {
|
||||
isTrafficEnabled = false
|
||||
isMyLocationEnabled = false
|
||||
uiSettings.isMyLocationButtonEnabled = false
|
||||
uiSettings.setLogoBottomMargin(-100)
|
||||
uiSettings.isZoomControlsEnabled = false
|
||||
// 发车按钮
|
||||
Button(onClick = {
|
||||
vm.dispatch(WaitToStartVm.Action.UpdateState(uiState.value.copy(
|
||||
showServicePeopleConfirmDialog = true)))
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(44.dp)
|
||||
.padding(horizontal = 16.dp),
|
||||
colors = ButtonDefaults.buttonColors(containerColor = headBgColor),
|
||||
shape = RoundedCornerShape(8.dp)) {
|
||||
Text(text = "发车",
|
||||
color = Color.White,
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Medium)
|
||||
}
|
||||
|
||||
// 修改标记点点击事件
|
||||
setOnMarkerClickListener { marker ->
|
||||
marker.showInfoWindow()
|
||||
// 800ms后隐藏信息窗口
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
marker.hideInfoWindow()
|
||||
}, 800)
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
update = {
|
||||
// 清除旧标记和路线
|
||||
mapView.map.clear()
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
}
|
||||
},
|
||||
sheetPeekHeight = 180.dp,
|
||||
sheetShape = RoundedCornerShape(topStart = 12.dp, topEnd = 12.dp),
|
||||
sheetContainerColor = Color.White,
|
||||
sheetDragHandle = null,
|
||||
sheetSwipeEnabled = true) { paddingValues ->
|
||||
Box(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)) {
|
||||
AndroidView(modifier = Modifier.fillMaxSize(), factory = {
|
||||
AMapLocationClient.updatePrivacyShow(context, true, true)
|
||||
AMapLocationClient.updatePrivacyAgree(context, true)
|
||||
mapView.apply {
|
||||
map.apply {
|
||||
isTrafficEnabled = false
|
||||
isMyLocationEnabled = false
|
||||
uiSettings.isMyLocationButtonEnabled = false
|
||||
uiSettings.setLogoBottomMargin(- 100)
|
||||
uiSettings.isZoomControlsEnabled = false
|
||||
|
||||
// 先绘制路线
|
||||
uiState.value.routePoints?.let { points ->
|
||||
mapView.map.addPolyline(
|
||||
PolylineOptions()
|
||||
.addAll(points)
|
||||
.width(15f)
|
||||
.setCustomTexture(BitmapDescriptorFactory.fromResource(R.drawable.icon_road_green_arrow))
|
||||
.zIndex(1f)
|
||||
)
|
||||
}
|
||||
// 修改标记点点击事件
|
||||
setOnMarkerClickListener { marker ->
|
||||
marker.showInfoWindow() // 800ms后隐藏信息窗口
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
marker.hideInfoWindow()
|
||||
}, 800)
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}, update = { // 清除旧标记和路线
|
||||
mapView.map.clear()
|
||||
|
||||
// 再添加标记点,确保标记点在路线上层
|
||||
// 添加当前位置标记
|
||||
if (GlobalData.currentLocation != null) {
|
||||
mapView.map.addMarker(
|
||||
MarkerOptions()
|
||||
.position(LatLng(
|
||||
GlobalData.currentLocation?.latitude!!,
|
||||
GlobalData.currentLocation?.longitude!!
|
||||
))
|
||||
.title("当前位置")
|
||||
.icon(ImageUtil.vectorToBitmap(context,R.drawable.ic_current_location))
|
||||
.anchor(0.5f, 0.5f)
|
||||
.visible(true)
|
||||
)
|
||||
}
|
||||
// 先绘制路线
|
||||
uiState.value.routePoints?.let { points ->
|
||||
mapView.map.addPolyline(PolylineOptions().addAll(points).width(15f)
|
||||
.setCustomTexture(BitmapDescriptorFactory.fromResource(R.drawable.icon_road_green_arrow))
|
||||
.zIndex(1f))
|
||||
}
|
||||
|
||||
// 添加救援地标记
|
||||
uiState.value.orderInfo?.let { order ->
|
||||
if (order.lat != null && order.lat != 0.0 &&
|
||||
order.lng != null && order.lng != 0.0 &&
|
||||
GlobalData.currentLocation != null
|
||||
) {
|
||||
mapView.map.addMarker(
|
||||
MarkerOptions()
|
||||
.position(LatLng(order.lat!!, order.lng!!))
|
||||
.title("救援地点")
|
||||
.icon(BitmapDescriptorFactory.fromResource(R.mipmap.sv_rescuing_map))
|
||||
.anchor(0.5f, 0.5f)
|
||||
)
|
||||
}
|
||||
// 再添加标记点,确保标记点在路线上层
|
||||
// 添加当前位置标记
|
||||
if (GlobalData.currentLocation != null) {
|
||||
mapView.map.addMarker(MarkerOptions().position(LatLng(GlobalData.currentLocation?.latitude !!,
|
||||
GlobalData.currentLocation?.longitude !!)).title("当前位置")
|
||||
.icon(ImageUtil.vectorToBitmap(context, R.drawable.ic_current_location))
|
||||
.anchor(0.5f, 0.5f).visible(true))
|
||||
}
|
||||
|
||||
// 添加目的地标记
|
||||
if (order.distLat != null && order.distLat != 0.0 &&
|
||||
order.distLng != null && order.distLng != 0.0 &&
|
||||
GlobalData.currentLocation != null
|
||||
) {
|
||||
mapView.map.addMarker(
|
||||
MarkerOptions()
|
||||
.position(LatLng(order.distLat!!, order.distLng!!))
|
||||
.title("目的地")
|
||||
.icon(BitmapDescriptorFactory.fromResource(R.mipmap.sv_dist_map))
|
||||
.anchor(0.5f, 0.5f)
|
||||
)
|
||||
}
|
||||
}
|
||||
// 添加救援地标记
|
||||
uiState.value.orderInfo?.let { order ->
|
||||
if (order.lat != null && order.lat != 0.0 && order.lng != null && order.lng != 0.0 && GlobalData.currentLocation != null) {
|
||||
mapView.map.addMarker(MarkerOptions().position(LatLng(order.lat !!,
|
||||
order.lng !!)).title("救援地点")
|
||||
.icon(BitmapDescriptorFactory.fromResource(R.mipmap.sv_rescuing_map))
|
||||
.anchor(0.5f, 0.5f))
|
||||
}
|
||||
|
||||
// 最后调整地图显示范围
|
||||
// 计算地图显示范围
|
||||
val bounds = LatLngBounds.Builder().apply {
|
||||
// 添加当前位置
|
||||
GlobalData.currentLocation?.let {
|
||||
include(LatLng(it.latitude, it.longitude))
|
||||
}
|
||||
// 添加目的地标记
|
||||
if (order.distLat != null && order.distLat != 0.0 && order.distLng != null && order.distLng != 0.0 && GlobalData.currentLocation != null) {
|
||||
mapView.map.addMarker(MarkerOptions().position(LatLng(order.distLat !!,
|
||||
order.distLng !!)).title("目的地")
|
||||
.icon(BitmapDescriptorFactory.fromResource(R.mipmap.sv_dist_map))
|
||||
.anchor(0.5f, 0.5f))
|
||||
}
|
||||
}
|
||||
|
||||
// 添加救援地点
|
||||
uiState.value.orderInfo?.let { order ->
|
||||
if (order.lat != null && order.lat != 0.0 &&
|
||||
order.lng != null && order.lng != 0.0
|
||||
) {
|
||||
include(LatLng(order.lat!!, order.lng!!))
|
||||
}
|
||||
// 最后调整地图显示范围
|
||||
// 计算地图显示范围
|
||||
val bounds = LatLngBounds.Builder().apply { // 添加当前位置
|
||||
GlobalData.currentLocation?.let {
|
||||
include(LatLng(it.latitude, it.longitude))
|
||||
}
|
||||
|
||||
// 添加目的地
|
||||
if (order.distLat != null && order.distLat != 0.0 &&
|
||||
order.distLng != null && order.distLng != 0.0
|
||||
) {
|
||||
include(LatLng(order.distLat!!, order.distLng!!))
|
||||
}
|
||||
}
|
||||
}.build()
|
||||
// 添加救援地点
|
||||
uiState.value.orderInfo?.let { order ->
|
||||
if (order.lat != null && order.lat != 0.0 && order.lng != null && order.lng != 0.0) {
|
||||
include(LatLng(order.lat !!, order.lng !!))
|
||||
}
|
||||
|
||||
// 调整地图显示范围,确保所有点都可见
|
||||
try {
|
||||
mapView.map.animateCamera(
|
||||
CameraUpdateFactory.newLatLngBounds(bounds, 100)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
// 如果计算边界失败,则使用默认缩放级别
|
||||
GlobalData.currentLocation?.let {
|
||||
mapView.map.animateCamera(
|
||||
CameraUpdateFactory.newLatLngZoom(
|
||||
LatLng(it.latitude, it.longitude),
|
||||
15f
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
// 添加目的地
|
||||
if (order.distLat != null && order.distLat != 0.0 && order.distLng != null && order.distLng != 0.0) {
|
||||
include(LatLng(order.distLat !!, order.distLng !!))
|
||||
}
|
||||
}
|
||||
}.build()
|
||||
|
||||
// 调整地图显示范围,确保所有点都可见
|
||||
try {
|
||||
mapView.map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 100))
|
||||
} catch (e : Exception) { // 如果计算边界失败,则使用默认缩放级别
|
||||
GlobalData.currentLocation?.let {
|
||||
mapView.map.animateCamera(CameraUpdateFactory.newLatLngZoom(LatLng(it.latitude,
|
||||
it.longitude), 15f))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,20 +15,27 @@ import com.blankj.utilcode.util.ToastUtils
|
||||
import com.za.base.IServicingVm
|
||||
import com.za.base.view.LoadingManager
|
||||
import com.za.bean.db.order.OrderInfo
|
||||
import com.za.bean.request.DriverFaceCompareRequest
|
||||
import com.za.bean.request.IaiCompareFaceBean
|
||||
import com.za.bean.request.UpdateTaskBean
|
||||
import com.za.bean.request.UpdateTaskRequest
|
||||
import com.za.common.GlobalData
|
||||
import com.za.common.log.LogUtil
|
||||
import com.za.ext.toJson
|
||||
import com.za.net.BaseObserver
|
||||
import com.za.net.CommonMethod
|
||||
import com.za.net.RetrofitHelper
|
||||
import com.za.service.location.ZdLocationManager
|
||||
import com.za.servicing.R
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Locale
|
||||
@ -47,6 +54,7 @@ class WaitToStartVm : IServicingVm<WaitToStartVm.Action, WaitToStartVm.UiState>(
|
||||
is Action.UpdateState -> updateState(action.uiState)
|
||||
is Action.StartTimer -> startTimer()
|
||||
is Action.UpdateTimer -> updateTimer()
|
||||
is Action.CompareServicePeople -> compareServicePeople(action.localPath)
|
||||
}
|
||||
}
|
||||
|
||||
@ -216,6 +224,52 @@ class WaitToStartVm : IServicingVm<WaitToStartVm.Action, WaitToStartVm.UiState>(
|
||||
private fun updateTimer() { // 在这里处理倒计时更新逻辑
|
||||
}
|
||||
|
||||
private fun compareServicePeople(localPath : String) {
|
||||
LoadingManager.showLoading()
|
||||
CommonMethod.uploadImage(file = File(localPath), success = { it ->
|
||||
compilePeople(it, success = {
|
||||
LoadingManager.hideLoading()
|
||||
updateTask()
|
||||
}, failed = {
|
||||
LoadingManager.hideLoading()
|
||||
ToastUtils.showLong(it)
|
||||
})
|
||||
}, failed = {
|
||||
LoadingManager.hideLoading()
|
||||
ToastUtils.showLong(it)
|
||||
})
|
||||
}
|
||||
|
||||
private fun compilePeople(url : String?,
|
||||
success : (IaiCompareFaceBean?) -> Unit,
|
||||
failed : (String) -> Unit) {
|
||||
if (url.isNullOrBlank()) {
|
||||
ToastUtils.showLong("图片路径为空!")
|
||||
return
|
||||
}
|
||||
val driverFaceCompareRequest =
|
||||
DriverFaceCompareRequest(vehicleId = GlobalData.driverInfoBean?.vehicleId,
|
||||
driverId = GlobalData.driverInfoBean?.userId,
|
||||
photoUrl = url)
|
||||
RetrofitHelper.getDefaultService().iaiCompareFace(driverFaceCompareRequest)
|
||||
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BaseObserver<IaiCompareFaceBean>() {
|
||||
override fun doSuccess(it : IaiCompareFaceBean?) {
|
||||
if (it?.compareResult == true) {
|
||||
success(it)
|
||||
return
|
||||
}
|
||||
failed("人脸对比失败")
|
||||
LogUtil.print("face", "人脸对比成功:$it")
|
||||
}
|
||||
|
||||
override fun doFailure(code : Int, msg : String?) {
|
||||
failed(msg ?: "人脸对比失败")
|
||||
LogUtil.print("face", "人脸对比失败:$msg")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
timerJob?.cancel()
|
||||
@ -227,14 +281,15 @@ class WaitToStartVm : IServicingVm<WaitToStartVm.Action, WaitToStartVm.UiState>(
|
||||
data class UpdateState(val uiState : UiState) : Action()
|
||||
data object StartTimer : Action()
|
||||
data object UpdateTimer : Action()
|
||||
data class CompareServicePeople(val localPath : String) : Action()
|
||||
}
|
||||
|
||||
data class UiState(val orderInfo : OrderInfo? = null,
|
||||
val showCallPhoneDialog : Boolean? = false,
|
||||
val markers : ArrayList<MarkerOptions>? = null,
|
||||
val goNextPage : UpdateTaskBean? = null,
|
||||
val isGoNextPageDialog : Boolean? = null,
|
||||
val routePoints : List<LatLng>? = null,
|
||||
val remainingDistance : Float = 0f,
|
||||
val showServicePeopleConfirmDialog : Boolean? = false,
|
||||
val estimatedArrivalTime : String = "")
|
||||
}
|
@ -1,14 +1,14 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="11dp"
|
||||
android:height="11dp"
|
||||
android:viewportWidth="11"
|
||||
android:viewportHeight="11">
|
||||
android:width="128dp"
|
||||
android:height="128dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:pathData="M3.25,8.804L3.26,8.793L7.74,8.793C8.301,8.793 8.76,8.334 8.76,7.773L8.76,4.257L8.757,1.244L8.76,1.245L8.76,1.053C8.76,0.492 8.301,0.033 7.74,0.033L1.02,0.033C0.459,0.033 0,0.492 0,1.053L0,7.773C0,8.334 0.459,8.793 1.02,8.793L2.14,8.793L2.15,8.804L3.25,8.804ZM7.18,7.872L1.58,7.872C1.189,7.872 0.921,7.604 0.921,7.213L0.921,1.613C0.921,1.222 1.189,0.953 1.58,0.953L7.18,0.953C7.571,0.953 7.84,1.222 7.84,1.613L7.84,7.213C7.84,7.604 7.571,7.872 7.18,7.872ZM9.98,11.033C10.541,11.033 11,10.574 11,10.013L11,3.293C11,2.732 10.541,2.273 9.98,2.273L9.556,2.273L9.557,3.205C9.872,3.261 10.079,3.51 10.079,3.853L10.079,9.453C10.079,9.844 9.811,10.112 9.42,10.112L3.82,10.112C3.482,10.112 3.235,9.911 3.175,9.604L2.239,9.604L2.24,10.013C2.24,10.574 2.699,11.033 3.26,11.033L9.98,11.033Z"
|
||||
android:strokeAlpha="0.8312872"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="#9197AB"
|
||||
android:fillType="nonZero"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillAlpha="0.8312872"/>
|
||||
android:pathData="M675.9,265.9H388.9c-68,0 -123.1,55.1 -123.1,123.1v287c-53.3,-2.6 -82,-33.8 -82,-89.3V273.3c0,-58 31.5,-89.5 89.5,-89.5h313.3c55.5,0 86.7,28.8 89.3,82z"
|
||||
android:strokeAlpha="0.3"
|
||||
android:fillColor="#1A73E8"
|
||||
android:fillAlpha="0.3"/>
|
||||
<path
|
||||
android:pathData="M437.4,347.9h313.3c58,0 89.5,31.5 89.5,89.5v313.3c0,58 -31.5,89.5 -89.5,89.5H437.4c-58,0 -89.5,-31.5 -89.5,-89.5V437.4c0,-58 31.5,-89.5 89.5,-89.5z"
|
||||
android:fillColor="#1A73E8"/>
|
||||
</vector>
|
||||
|
@ -18,4 +18,5 @@
|
||||
9.拖车服务时,救援人员仅按照道路救援中心的指令,将车辆拖往指定目的地,如果顾客需要变更拖车目的地,请与道路救援中心联系。\n
|
||||
10.顾客如果要求自费服务项目,请与第三方公司或人员协商相关费用并现场向其支付。因为此类服务发生任何争议,请与数援人员双方自行解决,救援中心不再介入和负责。\n
|
||||
11.服务完成后客户接收车辆时,应再次签字确认服务完成及车辆无损,中道救援不接受客户己在服务完成记录中签字后的任何索赔和投诉:若接车方为维修站,且维修站接车员签字确认车辆无损,则事后发现的任何车辆损伤及相关责任应由维修站承担。如客户认为被救车辆损伤由中道救援服务商造成,应出具权威部门出具的检测报告,中道救援将根据检测报告确定服务商是否进行赔偿。</string>
|
||||
<string name="title_activity_service_people_confirm">ServicePeopleConfirmActivity</string>
|
||||
</resources>
|
@ -2,4 +2,6 @@
|
||||
<resources>
|
||||
|
||||
<style name="Theme.Dealer" parent="Theme.AppCompat.Light.NoActionBar" />
|
||||
|
||||
<style name="Theme.Zd_sdk_demo" parent="android:Theme.Material.Light.NoActionBar" />
|
||||
</resources>
|
Reference in New Issue
Block a user