refactor(sdk): 重构项目并添加 native 代码支持

- 移除了不必要的日志库 LogUtil
- 添加了高德地图服务并配置了相关权限
- 更新了 API 接口定义,统一添加了前缀
-重构了 AppConfig 类,使用 native代码获取配置信息
- 更新了项目构建配置,支持 native 代码编译
- 优化了部分代码结构,提高了代码的可维护性
This commit is contained in:
songzhiling
2025-07-17 11:35:38 +08:00
parent c1c070dfac
commit 96a61fe09f
126 changed files with 1480 additions and 1299 deletions

View File

@ -1,7 +1,9 @@
import com.android.build.gradle.LibraryExtension
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.jetbrains.kotlin.android)
id 'com.google.devtools.ksp'
alias(libs.plugins.jetbrains.kotlin.android)
id 'maven-publish'
// kotlin 序列化注解
id 'kotlin-parcelize'
@ -19,6 +21,12 @@ android {
vectorDrawables {
useSupportLibrary true
}
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
multiDexEnabled true
}
buildTypes {
@ -31,7 +39,6 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
// publishNonDefault true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
@ -48,9 +55,17 @@ android {
composeOptions {
kotlinCompilerExtensionVersion '1.5.15'
}
packaging {
resources {
excludes += '/META-INF/{AL2.0,LGPL2.1}'
if (project.extensions.getByName("android") is LibraryExtension) {
// AGP 7.0+
packaging {
resources {
excludes += "META-INF/LICENSE"
}
}
} else {
// AGP 6.x
packagingOptions {
exclude("META-INF/LICENSE")
}
}
publishing {
@ -64,7 +79,7 @@ publishing {
release(MavenPublication) {
groupId = 'io.github.szl9'
artifactId = 'zd_servicing'
version = "1.0.1.9.9.138"
version = "1.0.3"
pom {
packaging = "aar"
@ -135,81 +150,87 @@ tasks.register('generateRepo', Zip) {
into 'zd_servicing'
archiveFileName.set('zd_servicing.zip')
}
dependencies {
api libs.androidx.core.ktx
api libs.androidx.appcompat
api libs.material
api libs.androidx.lifecycle.viewmodel.compose
api libs.androidx.lifecycle.runtime.ktx
api libs.androidx.activity.compose
api platform(libs.androidx.compose.bom)
api libs.androidx.ui
api libs.androidx.ui.graphics
api libs.androidx.ui.tooling.preview
api libs.androidx.material3
api libs.androidx.work.runtime.ktx
api libs.androidx.exifinterface
api "androidx.core:core-ktx:1.15.0" // coreKtx = "1.15.0"
api "androidx.appcompat:appcompat:1.7.0" // appcompat = "1.7.0"
api "com.google.android.material:material:1.12.0" // material = "1.12.0"
api "androidx.lifecycle:lifecycle-viewmodel-compose:2.8.7" // lifecycleRuntimeKtx = "2.8.7"
api "androidx.lifecycle:lifecycle-runtime-ktx:2.8.7" // lifecycleRuntimeKtx = "2.8.7"
api "androidx.activity:activity-compose:1.10.0" // activityCompose = "1.10.0"
api platform("androidx.compose:compose-bom:2025.01.01") // composeBom = "2025.01.01"
api "androidx.compose.ui:ui:1.7.7" // uiVersion = "1.7.7"
api "androidx.compose.ui:ui-graphics:1.7.7" // uiGraphics = "1.7.7"
api "androidx.compose.ui:ui-tooling-preview:1.7.7" // uiToolingPreview = "1.7.7"
api "androidx.compose.material3:material3:1.3.1" // material3="1.3.1"
api "androidx.work:work-runtime-ktx:2.10.0" // workRuntimeKtx = "2.10.0"
api "androidx.exifinterface:exifinterface:1.3.7" // exifinterface = "1.3.7"
testApi libs.junit
androidTestApi libs.androidx.junit
androidTestApi libs.androidx.espresso.core
androidTestApi platform(libs.androidx.compose.bom)
androidTestApi libs.androidx.ui.test.junit4
debugApi libs.androidx.ui.test.manifest
debugApi libs.ui.tooling
testApi "junit:junit:4.13.2" // junit = "4.13.2"
androidTestApi "androidx.test.ext:junit:1.2.1" // junitVersion = "1.2.1"
androidTestApi "androidx.test.espresso:espresso-core:3.6.1" // espressoCore = "3.6.1"
androidTestApi platform("androidx.compose:compose-bom:2025.01.01") // composeBom = "2025.01.01"
androidTestApi "androidx.compose.ui:ui-test-junit4:1.7.7" // uiGraphics = "1.7.7"
debugApi "androidx.compose.ui:ui-test-manifest:1.7.7" // uiGraphics = "1.7.7"
debugApi "androidx.compose.ui:ui-tooling:1.4.0"
// From [libraries] ui-tooling, version.ref = "uiToolingVersion", and [versions] uiToolingVersion = "1.4.0"
api libs.coil.compose
api libs.coil.gif
api "io.coil-kt:coil-compose:2.6.0" // coilCompose = "2.6.0"
api "io.coil-kt:coil-gif:2.6.0" // coilCompose = "2.6.0"
api libs.permissionx
api libs.utilcodex
api "com.guolindev.permissionx:permissionx:1.8.0" // permissionx = "1.8.0"
api "com.blankj:utilcodex:1.31.1" // utilcodex = "1.31.1"
api libs.crashreport
api "com.tencent.bugly:crashreport:4.0.4" // crashreport = "4.0.4"
// 高德地图
api libs.xdmap
api libs.location
api libs.search
api "com.amap.api:3dmap:8.1.0" // xdmap = "8.1.0"
api "com.amap.api:location:5.6.1" // location = "5.6.1"
api "com.amap.api:search:7.3.0" // search = "7.3.0"
// // JPush
api libs.jpush
api libs.gson
// JPush
api "cn.jiguang.sdk:jpush:5.6.0" // jpush = "5.6.0"
api "com.google.code.gson:gson:2.11.0" // gson = "2.11.0"
// 网络
api libs.retrofit
api libs.converter.gson
api libs.adapter.rxjava3
api libs.rxjava
api libs.rxandroid
api libs.logging.interceptor
api libs.fastjson
api "com.squareup.retrofit2:retrofit:2.9.0" // retrofit = "2.9.0"
api "com.squareup.retrofit2:converter-gson:2.9.0" // converterGson = "2.9.0"
api "com.squareup.retrofit2:adapter-rxjava3:2.9.0"
// From [libraries] adapter-rxjava3, version.ref = "converterGson"
api "io.reactivex.rxjava3:rxjava:3.1.7" // rxjava = "3.1.7"
api "io.reactivex.rxjava3:rxandroid:3.0.2" // rxandroid = "3.0.2"
api "com.squareup.okhttp3:logging-interceptor:4.11.0" // loggingInterceptor = "4.11.0"
api "com.alibaba:fastjson:1.2.69" // fastjson = "1.2.69"
// 本地数据
api libs.room.runtime
annotationProcessor libs.room.compiler
ksp libs.room.compiler
api libs.mmkv
api "androidx.room:room-runtime:2.6.1" // roomRuntimeVersion = "2.6.1"
annotationProcessor "androidx.room:room-compiler:2.6.1" // roomCompilerVersion = "2.6.1"
ksp "androidx.room:room-compiler:2.6.1" // roomCompilerVersion = "2.6.1"
api "com.tencent:mmkv:1.3.11" // mmkv = "1.3.11"
// 7z
api libs.xz
api libs.commons.compress
api "org.tukaani:xz:1.9" // xz = "1.9"
api "org.apache.commons:commons-compress:1.23.0" // commonsCompress = "1.23.0"
api libs.core
api libs.tbssdk
api "com.google.zxing:core:3.5.3" // core = "3.5.3"
api "com.tencent.tbs:tbssdk:44286" // tbssdk = "44286"
// CameraX
api libs.androidx.camera.core
api libs.androidx.camera.camera2
api libs.androidx.camera.lifecycle
api libs.androidx.camera.view
api libs.androidx.camera.extensions
// CameraX - Assuming all camera dependencies use 'cameraCore' version
api "androidx.camera:camera-core:1.4.1" // cameraCore = "1.4.1"
api "androidx.camera:camera-camera2:1.4.1" // cameraCore = "1.4.1"
api "androidx.camera:camera-lifecycle:1.4.1" // cameraCore = "1.4.1"
api "androidx.camera:camera-view:1.4.1" // cameraCore = "1.4.1"
api "androidx.camera:camera-extensions:1.4.1" // cameraCore = "1.4.1"
api libs.glide
annotationProcessor libs.compiler
api "com.github.bumptech.glide:glide:4.16.0" // glide = "4.16.0"
annotationProcessor "com.github.bumptech.glide:compiler:4.14.2" // compiler = "4.14.2"
api libs.org.eclipse.paho.client.mqttv3
api libs.org.eclipse.paho.android.service
api "org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5"
// orgEclipsePahoClientMqttv3 = "1.2.5"
api "org.eclipse.paho:org.eclipse.paho.android.service:1.1.1"
// orgEclipsePahoAndroidService = "1.1.1"
api libs.face.detection
api "com.google.mlkit:face-detection:16.1.7" // faceDetection = "16.1.7"
}

View File

@ -1,5 +1,11 @@
-dontwarn java.lang.invoke.StringConcatFactory
# 设置混淆的压缩比率 0 ~ 7
-optimizationpasses 5
# 混淆采用的算法
-optimizations !code/simplification/cast,!field/*,!class/merging/*
# 保留行号用于调试
-keepattributes SourceFile,LineNumberTable
-renamesourcefileattribute SourceFile

View File

@ -226,6 +226,12 @@
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<service
android:name="com.amap.api.location.APSService"
android:exported="false"
android:foregroundServiceType="location"
android:process=":aps" />
<receiver
android:name="com.za.service.ZdPushServiceReceive"
android:exported="false">

View File

@ -3,7 +3,7 @@ package com.za.base
import com.za.common.GlobalData
import com.za.net.RetrofitHelper
object AppConfig {
internal object AppConfig {
var isRelease = false
// API 相关地址
@ -52,14 +52,14 @@ object AppConfig {
fun release() {
isRelease = true // API 配置
GlobalData.networkEnv = Const.NetEnv.Main
BASE_URL = "https://api.sinoassist.com"
IMG_BASE_URL = "https://api.sinoassist.com"
Resource_URL = "https://www.sinoassist.com/res"
BASE_URL = getReleaseBaseUrl()
IMG_BASE_URL = getReleaseImgBaseUrl()
Resource_URL = getReleaseResourceUrl()
// H5 配置
trainUrl = "https://www.sinoassist.com/h5/supplier/dispatch/diverTrainDocment"
documentUrl = "https://www.sinoassist.com/h5/supplier/dispatch/docmentList"
newDriverTrainUrl = "https://www.sinoassist.com/h5/supplier/dispatch/driverTrainingList";
trainUrl = getReleaseTrainUrl()
documentUrl = getReleaseDocumentUrl()
newDriverTrainUrl = getReleaseNewDriverTrainUrl()
}
@ -71,13 +71,12 @@ object AppConfig {
GlobalData.networkEnv = Const.NetEnv.Review
// API 配置
BASE_URL = "http://interface.review.sino-assist.com"
IMG_BASE_URL = "http://interface.review.sino-assist.com"
Resource_URL = "https://www.sinoassist.com/res"
documentUrl = "http://interface.review.sino-assist.com/h5/supplier/dispatch/docmentList"
trainUrl = "http://interface.review.sino-assist.com/h5/supplier/dispatch/diverTrainDocment"
newDriverTrainUrl =
"http://interface.review.sino-assist.com/h5/supplier/dispatch/driverTrainingList"
BASE_URL = getReviewBaseUrl()
IMG_BASE_URL = getReviewImgBaseUrl()
Resource_URL = getReviewResourceUrl()
documentUrl = getReviewDocumentUrl()
trainUrl = getReviewTrainUrl()
newDriverTrainUrl = getReviewNewDriverTrainUrl()
}
/**
@ -88,13 +87,13 @@ object AppConfig {
GlobalData.networkEnv = Const.NetEnv.CRM1
// API 配置
BASE_URL = "https://api1.sino-assist.com"
IMG_BASE_URL = "https://api1.sino-assist.com"
Resource_URL = "https://crm1.sino-assist.com/res"
BASE_URL = getCrm1BaseUrl()
IMG_BASE_URL = getCrm1ImgBaseUrl()
Resource_URL = getCrm1ResourceUrl()
documentUrl = "https://crm1.sino-assist.com/h5/supplier/dispatch/docmentList";
trainUrl = "https://crm1.sino-assist.com/h5/supplier/dispatch/diverTrainDocment";
newDriverTrainUrl = "https://crm1.sino-assist.com/h5/supplier/dispatch/driverTrainingList";
documentUrl = getCrm1DocumentUrl()
trainUrl = getCrm1TrainUrl()
newDriverTrainUrl = getCrm1NewDriverTrainUrl()
}
/**
@ -105,9 +104,9 @@ object AppConfig {
GlobalData.networkEnv = Const.NetEnv.CRM2
// API 配置
BASE_URL = "https://api2.sino-assist.com"
IMG_BASE_URL = "https://api2.sino-assist.com"
Resource_URL = "https://crm2.sino-assist.com/res"
BASE_URL = getCrm2BaseUrl()
IMG_BASE_URL = getCrm2ImgBaseUrl()
Resource_URL = getCrm2ResourceUrl()
}
@ -115,15 +114,12 @@ object AppConfig {
isRelease = false
GlobalData.networkEnv = Const.NetEnv.UAT
BASE_URL = "https://api-uat.sino-assist.com" //crm2
IMG_BASE_URL = "https://api-uat.sino-assist.com"
Resource_URL = "https://uat.sino-assist.com/res"
documentUrl = "https://uat.sino-assist.com/h5/supplier/dispatch/docmentList"
trainUrl = "https://uat.sino-assist.com/h5/supplier/dispatch/diverTrainDocment"
newDriverTrainUrl = "https://uat.sino-assist.com/h5/supplier/dispatch/driverTrainingList"
documentUrl = "https://uat.sino-assist.com/h5/supplier/dispatch/docmentList";
trainUrl = "https://uat.sino-assist.com/h5/supplier/dispatch/diverTrainDocment";
newDriverTrainUrl = "https://uat.sino-assist.com/h5/supplier/dispatch/driverTrainingList";
BASE_URL = getUatBaseUrl()
IMG_BASE_URL = getUatImgBaseUrl()
Resource_URL = getUatResourceUrl()
documentUrl = getUatDocumentUrl()
trainUrl = getUatTrainUrl()
newDriverTrainUrl = getUatNewDriverTrainUrl()
}
/**
@ -151,4 +147,42 @@ object AppConfig {
}
return documentUrl + "?token=${GlobalData.token}&driverId=${GlobalData.driverInfoBean?.userId}&keyword=$keyWord"
}
private external fun getReleaseBaseUrl() : String
private external fun getReleaseImgBaseUrl() : String
private external fun getReleaseResourceUrl() : String
private external fun getReleaseTrainUrl() : String
private external fun getReleaseDocumentUrl() : String
private external fun getReleaseNewDriverTrainUrl() : String
private external fun getReviewBaseUrl() : String
private external fun getReviewImgBaseUrl() : String
private external fun getReviewResourceUrl() : String
private external fun getReviewTrainUrl() : String
private external fun getReviewDocumentUrl() : String
private external fun getReviewNewDriverTrainUrl() : String
private external fun getCrm1BaseUrl() : String
private external fun getCrm1ImgBaseUrl() : String
private external fun getCrm1ResourceUrl() : String
private external fun getCrm1TrainUrl() : String
private external fun getCrm1DocumentUrl() : String
private external fun getCrm1NewDriverTrainUrl() : String
private external fun getCrm2BaseUrl() : String
private external fun getCrm2ImgBaseUrl() : String
private external fun getCrm2ResourceUrl() : String
private external fun getCrm2TrainUrl() : String
private external fun getCrm2DocumentUrl() : String
private external fun getCrm2NewDriverTrainUrl() : String
private external fun getUatBaseUrl() : String
private external fun getUatImgBaseUrl() : String
private external fun getUatResourceUrl() : String
private external fun getUatTrainUrl() : String
private external fun getUatDocumentUrl() : String
private external fun getUatNewDriverTrainUrl() : String
}

View File

@ -1,6 +1,6 @@
package com.za.base
interface AppForegroundListener {
internal interface AppForegroundListener {
/**
* APP处于 前台

View File

@ -9,7 +9,7 @@ import com.za.common.GlobalData
import com.za.common.log.LogUtil
import java.util.concurrent.atomic.AtomicBoolean
open class BaseActivityLifecycleCallbacks : ActivityLifecycleCallbacks {
internal class BaseActivityLifecycleCallbacks : ActivityLifecycleCallbacks {
override fun onActivityCreated(activity : Activity, savedInstanceState : Bundle?) {

View File

@ -5,7 +5,7 @@ import androidx.lifecycle.ViewModel
val showTipDialog = mutableStateOf<String?>(null) //提示框
abstract class BaseVm<T, U> : ViewModel() {
internal abstract class BaseVm<T, U> : ViewModel() {
val tag : String = javaClass.simpleName
abstract fun updateState(uiState : U)
abstract fun dispatch(action : T)

View File

@ -1,6 +1,6 @@
package com.za.base
object Const {
internal object Const {
const val Image_Max_length = 1024 * 400L
const val faceFileName = "zd_com.dear"
const val NetWorkException = 999

View File

@ -12,7 +12,7 @@ import com.za.offline.OfflineManager
import com.za.offline.OfflineUpdateTaskBean
import com.za.room.RoomHelper
abstract class IServicingVm<T, U> : BaseVm<T, U>() {
internal abstract class IServicingVm<T, U> : BaseVm<T, U>() {
fun getCurrentOrder() : OrderInfo? =
GlobalData.currentOrder ?: RoomHelper.db?.orderDao()?.getCurrentOrder()

View File

@ -106,7 +106,7 @@ enum class DetectionStatus {
ABNORMAL // 异常
}
class NetworkRouteSelectionActivity : BaseActivity() {
internal class NetworkRouteSelectionActivity : BaseActivity() {
@Composable
override fun ContentView() {
NetworkRouteScreen(telephonyManager = getSystemService(TELEPHONY_SERVICE) as TelephonyManager,

View File

@ -7,7 +7,6 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.google.gson.Gson
import com.za.bean.JpushBean
import com.za.common.GlobalData
import com.za.common.log.LogUtil
import com.za.service.PushListener
import com.za.service.ServiceManager
@ -82,7 +81,7 @@ open class PushMessageActivity : AppCompatActivity() {
currentDialog?.dismiss()
currentDialog = null
} catch (e : Exception) {
LogUtil.print("PushActivityLifecycleCallbacks", "关闭对话框失败: ${e.message}")
LogUtil.print("PushMessageActivity", "关闭对话框失败: ${e.message}")
}
}
@ -91,10 +90,11 @@ open class PushMessageActivity : AppCompatActivity() {
internal const val DIALOG_TAG_GIVE_UP = "giveUp"
private fun sendMessageToMainProcess(context : Context, type : String, message : String) {
// 使用广播将消息发送到主进程
val intent = Intent(Const.PushMessageType.ACTION_MAIN.takeIf { GlobalData.isMaster }
?: Const.PushMessageType.ACTION_SDK)
val intent = if (context.packageName == "com.za.rescue.dealer") {
Intent(Const.PushMessageType.ACTION_MAIN)
} else {
Intent(Const.PushMessageType.ACTION_SDK)
}
intent.setPackage(context.packageName)
intent.putExtra("type", type)
intent.putExtra("message", message)

View File

@ -19,72 +19,48 @@ import coil.compose.AsyncImage
import com.za.servicing.R
@Composable
fun EmptyView(
modifier: Modifier = Modifier,
message: String = "暂无数据",
imageSize: Pair<Int, Int> = Pair(118, 143),
imageRes: Int = R.drawable.sv_emty_data
) {
Column(
modifier = modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
AsyncImage(
model = imageRes,
contentDescription = message,
modifier = Modifier.size(imageSize.first.dp, imageSize.second.dp)
)
Spacer(modifier = Modifier.height(12.dp))
Text(
text = message,
color = Color.Gray,
fontSize = 14.sp,
textAlign = TextAlign.Center
)
}
fun EmptyView(modifier : Modifier = Modifier,
message : String = "暂无数据",
imageSize : Pair<Int, Int> = Pair(118, 143),
imageRes : Int = R.drawable.sv_emty_data) {
Column(modifier = modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally) {
AsyncImage(model = imageRes,
contentDescription = message,
modifier = Modifier.size(imageSize.first.dp, imageSize.second.dp))
Spacer(modifier = Modifier.height(12.dp))
Text(text = message, color = Color.Gray, fontSize = 14.sp, textAlign = TextAlign.Center)
}
}
@Composable
fun LoadError(
modifier: Modifier = Modifier,
message: String = "加载出错",
imageSize: Pair<Int, Int> = Pair(118, 143),
onRetry: (() -> Unit)? = null
) {
Column(
modifier = modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
AsyncImage(
model = R.drawable.sv_load_error,
contentDescription = message,
modifier = Modifier.size(imageSize.first.dp, imageSize.second.dp)
)
Spacer(modifier = Modifier.height(12.dp))
Text(
text = message,
color = Color.Gray,
fontSize = 14.sp,
textAlign = TextAlign.Center
)
if (onRetry != null) {
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "点击重试",
color = Color(0xFF1BA8F7),
fontSize = 14.sp,
modifier = Modifier
fun LoadError(modifier : Modifier = Modifier,
message : String = "加载出错",
imageSize : Pair<Int, Int> = Pair(118, 143),
onRetry : (() -> Unit)? = null) {
Column(modifier = modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally) {
AsyncImage(model = R.drawable.sv_load_error,
contentDescription = message,
modifier = Modifier.size(imageSize.first.dp, imageSize.second.dp))
Spacer(modifier = Modifier.height(12.dp))
Text(text = message, color = Color.Gray, fontSize = 14.sp, textAlign = TextAlign.Center)
if (onRetry != null) {
Spacer(modifier = Modifier.height(16.dp))
Text(text = "点击重试",
color = Color(0xFF1BA8F7),
fontSize = 14.sp,
modifier = Modifier
.align(Alignment.CenterHorizontally)
.clickable { onRetry() }
)
}
}
.clickable { onRetry() })
}
}
}

View File

@ -15,7 +15,7 @@ import com.za.net.RetrofitHelper
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
object CallLogManager {
internal object CallLogManager {
private const val TAG = "CallLogManager"
private var lastUploadTime : Long? = null
set(value) {

View File

@ -12,7 +12,7 @@ import com.za.room.RoomHelper
import com.za.room.db.user.DriverInfoBean
import com.za.service.location.ZdLocationManager
object GlobalData : GlobalLocalData() {
internal object GlobalData : GlobalLocalData() {
lateinit var application : Application
private val mmkv : MMKV by lazy { MMKV.defaultMMKV() }
var activityCount : Int = 0

View File

@ -11,6 +11,7 @@ import com.za.service.location.ZdLocationManager
object ZDManager {
lateinit var application : Application
fun init(application : Application, isRelease : Boolean = false) {
this.application = application
thirdSdkInit(isRelease)
@ -20,10 +21,17 @@ object ZDManager {
GlobalData.application = application
MMKV.initialize(application)
AppConfig.init(isRelease)
Bugly.init(application, "6972a6b56d", true)
Bugly.init(application, getBuglyAppId(), true)
LogUtil.init(application)
RoomHelper.init(application)
ZdLocationManager.init(application)
SpeechManager.init(application)
}
init {
System.loadLibrary("config")
}
private external fun getBuglyAppId() : String
}

View File

@ -10,7 +10,7 @@ import java.io.UnsupportedEncodingException
import java.net.URLDecoder
import java.util.concurrent.TimeUnit
object LogRetrofitHelper {
internal object LogRetrofitHelper {
private var retrofit: Retrofit? = null
private var apiService: LogService? = null
private val loggerInterceptor = HttpLoggingInterceptor {

View File

@ -7,7 +7,7 @@ import retrofit2.http.POST
import retrofit2.http.Part
import retrofit2.http.Query
interface LogService {
internal interface LogService {
//日志上传
@Multipart
@POST("/oss/minio/upload")

View File

@ -32,7 +32,7 @@ import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
object LogUtil {
internal object LogUtil {
private var context : Application? = null
private var executors : ExecutorService? = null
private var normalLogDirPath : String? = null
@ -113,6 +113,7 @@ object LogUtil {
}
LogUtils.getConfig().setFilePrefix(this.vehicleName)
LogUtils.e("$tag---$content")
} catch (e : Exception) {
e.printStackTrace()
}

View File

@ -1,122 +0,0 @@
package com.za.common.speech
import android.media.MediaPlayer
import com.google.gson.Gson
import com.google.gson.JsonObject
import com.za.common.log.LogUtil
import okhttp3.OkHttpClient
import okhttp3.ResponseBody
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.Body
import retrofit2.http.POST
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
interface SpeechApiService {
@POST("v1/audio/speech")
fun textToSpeech(@Body request: JsonObject): Call<ResponseBody>
}
object CustomerSpeechManager {
private const val BASE_URL = "http://192.168.3.129:8880/"
private val gson: Gson by lazy {
Gson().newBuilder()
.setLenient()
.create()
}
private val retrofit: Retrofit by lazy {
val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
val client = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build()
Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.build()
}
private val speechApiService: SpeechApiService by lazy {
retrofit.create(SpeechApiService::class.java)
}
fun textToSpeech(input: String, destinationFile: File): Boolean {
val requestBody = JsonObject().apply {
addProperty("input", input)
addProperty("voice", "zf_xiaoxiao")
addProperty("response_format", "mp3")
addProperty("stream", true)
addProperty("speed", 1)
addProperty("return_download_link", false) // Set to false to get the stream directly
addProperty("lang_code", "z")
}
val call = speechApiService.textToSpeech(requestBody)
try {
val response = call.execute()
LogUtil.print("CustomerSpeechManager", "response: $response")
if (response.isSuccessful) {
val responseBody = response.body()
if (responseBody != null) {
saveToFile(responseBody, destinationFile)
playAudio(destinationFile)
return true
}
} else {
LogUtil.print("CustomerSpeechManager", "Request failed: ${response.code()}")
}
} catch (e: IOException) {
e.printStackTrace()
}
return false
}
private fun saveToFile(body: ResponseBody, destinationFile: File) {
body.byteStream().use {
FileOutputStream(destinationFile).buffered().use { outputStream ->
val buffer = ByteArray(4096)
var bytesRead: Int
while (it.read(buffer).also { bytesRead = it } != -1) {
outputStream.write(buffer, 0, bytesRead)
}
}
}
}
private fun playAudio(file: File) {
val mediaPlayer = MediaPlayer().apply {
try {
setDataSource(file.absolutePath)
prepare()
start()
} catch (e: IOException) {
e.printStackTrace()
release()
}
}
mediaPlayer.setOnCompletionListener {
it.release()
}
mediaPlayer.setOnErrorListener { mp, what, extra ->
mp.release()
false
}
}
}

View File

@ -21,7 +21,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
object SpeechManager {
internal object SpeechManager {
private var mContext : Application? = null

View File

@ -12,7 +12,7 @@ import java.util.Locale
@SuppressLint("StaticFieldLeak")
object TTSManager {
internal object TTSManager {
private var tts : TextToSpeech? = null
private var context : Context? = null
private var listener : OnTTSListener? = null

View File

@ -95,7 +95,7 @@ import retrofit2.http.Multipart
import retrofit2.http.POST
import retrofit2.http.Part
interface ApiService {
internal interface ApiService {
//获取车辆列表
@POST("/driverApp/supplier/listVehicleNew")
@ -236,35 +236,35 @@ interface ApiService {
@POST("/driverApp/task/getTaskSettlementAndTrace")
fun getTaskSettlementAndTrace(@Body info : HistoryDetailRequest) : Observable<BaseResponse<TaskSettlementAndTraceBean>>
@POST("driverApp/task/updateSettleInfo")
@POST("/driverApp/task/updateSettleInfo")
fun updateSettleInfo(@Body settleInfoRequest : SettleInfoRequest) : Observable<BaseResponse<String>>
//人脸比对
@POST("driverApp/supplier/driverFaceCompare")
@POST("/driverApp/supplier/driverFaceCompare")
fun driverFaceCompare(@Body driverFaceCompareRequest : DriverFaceCompareRequest) : Observable<BaseResponse<DriverFaceCompareBean>>
@POST("driverApp/supplier/driverIdentityAuthWeb")
@POST("/driverApp/supplier/driverIdentityAuthWeb")
fun driverIdentityAuthWeb(@Body request : DriverIdentityAuthWebRequest) : Observable<BaseResponse<DriverIdentityAuthWebBean>>
//今日保养
@POST("driverApp/supplier/getTodayMaintain")
@POST("/driverApp/supplier/getTodayMaintain")
fun getTodayMaintain(@Body info : TodayMaintainRequest) : Observable<BaseResponse<List<TodayMaintainbean>>>
//今日保养
@POST("driverApp/supplier/uploadTodayMaintain")
@POST("/driverApp/supplier/uploadTodayMaintain")
fun uploadTodayMaintain(@Body params : TodayMaintainUploadRequest) : Observable<BaseResponse<String>>
//加油小票识别
@POST("driverApp/supplier/recognizeRefuelTicket")
@POST("/driverApp/supplier/recognizeRefuelTicket")
fun recognizeRefuelTicket(@Body bean : RecognizeRefuelOcrRequestBean?) : Observable<BaseResponse<RecognizeRefuelTicketBean>>
//提交加油记录
@POST("driverApp/supplier/vehicleRefuelSubmit")
@POST("/driverApp/supplier/vehicleRefuelSubmit")
fun vehicleRefuelSubmit(@Body info : RecognizeRefuelTicketRequestBean?) : Observable<BaseResponse<String>>
//获取车辆维保记录
@POST("driverApp/supplier/v2/getVehicleMaintenanceSubmit")
@POST("/driverApp/supplier/v2/getVehicleMaintenanceSubmit")
fun getVehicleMaintenanceSubmit(@Body info : FetchVehicleMaintenanceSubmitHistoryRequestBean) : Observable<BaseResponse<VehicleRepairBean>>
//获取车辆维保详细信息
@ -272,31 +272,29 @@ interface ApiService {
fun getVehicleRepairDetail(@Body info : FetchVehicleMaintenanceSubmitHistoryRequestBean) : Observable<BaseResponse<VehicleRepairBean>>
//维修地点匹配
@POST("driverApp/supplier/v2/vehicleRepairPointMatcherList")
@POST("/driverApp/supplier/v2/vehicleRepairPointMatcherList")
fun vehicleRepairPointMatcherList(@Body info : VehicleRepairPointMatcherListRequest) : Observable<BaseResponse<List<VehicleRepairPointMatcherItem>>>
//提交维保记录
@POST("driverApp/supplier/v2/vehicleMaintenanceSubmit")
@POST("/driverApp/supplier/v2/vehicleMaintenanceSubmit")
fun vehicleMaintenanceSubmit(@Body info : VehicleMaintenanceSubmitRequest) : Observable<BaseResponse<String>>
//获取车辆维修历史
@POST("/driverApp/supplier/v2/vehicleMaintenanceList")
fun vehicleMaintenanceList(@Body info : FetchVehicleMaintenanceSubmitHistoryRequestBean) : Observable<BaseResponse<List<VehicleMaintenanceHistoryBean>>>
@POST("driverApp/base/getVoiceUrl")
@POST("/driverApp/base/getVoiceUrl")
fun getVoiceUrl(@Body info : AppNewOrderVoiceRequest) : Observable<BaseResponse<String>>
@POST("driverApp/supplier/iaiCompareFace")
@POST("/driverApp/supplier/iaiCompareFace")
fun iaiCompareFace(@Body info : DriverFaceCompareRequest) : Observable<BaseResponse<IaiCompareFaceBean>>
@POST("driverApp/task/getTaskNotes")
@POST("/driverApp/task/getTaskNotes")
fun getTaskNotes(@Body request : TaskNotesRequest) : Observable<BaseResponse<TaskNotesBean>>
@POST("driverApp/supplier/unifiedOCRWithCompress")
@POST("/driverApp/supplier/unifiedOCRWithCompress")
fun unifiedOCRWithCompress(@Body request : UnifiedOCRWithCompressRequest) : Observable<BaseResponse<String>>
@POST("driverApp/v2/user/saveSignature")
@POST("/driverApp/v2/user/saveSignature")
fun saveSignature(@Body request : SaveSignatureRequest) : Observable<BaseResponse<String>>
}

View File

@ -25,7 +25,7 @@ import javax.net.ssl.SSLHandshakeException
/**
* Created by DoggieX on 2017/7/26.
*/
abstract class BaseObserver<T> : Observer<BaseResponse<T>> {
internal abstract class BaseObserver<T> : Observer<BaseResponse<T>> {
override fun onSubscribe(d : Disposable) { // if (!NetworkUtils.isAvailable()) {
// doFailure(999, "网络无法使用")
// d.dispose()

View File

@ -39,7 +39,7 @@ import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
import java.io.File
object CommonMethod {
internal object CommonMethod {
fun uploadGps(uploadGpsRequest : UploadGpsRequest,
success : () -> Unit = {},
failed : (String?) -> Unit = {}) {

View File

@ -6,7 +6,7 @@ import com.za.bean.db.order.PhotoTemplateInfo
import com.za.common.log.LogUtil
import com.za.servicing.R
object LocalPhotoTemplateControl {
internal object LocalPhotoTemplateControl {
fun buildPhotoTemplate(orderInfo : OrderInfo?) : List<PhotoTemplateInfo> {
if (orderInfo == null) {

View File

@ -26,12 +26,14 @@ import okio.Buffer;
*/
public class RequestEncryptInterceptor implements Interceptor {
static final String PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7UM6zdWdBuO0DZZVkxVfJioawUe6qH1p5Uz/qR9zbawl2oWyxxcBfxQyPS+HxOej/ZnyS4bu7qhh99alDqkJzk6g9oGZWs+jEF5GRWt9nChlfUsjvHQwuF2TSQMTdPtDPCByF/QgMFCAfbCqTrNmOETrZ/2GFy1Re0BTlhh6X/XzpzqtK+enikEMlQ5fIM5ljdXgyCnvDou9ptWqzw8Zmsat6LeA0UKz+bgpJAbw6KfK+8lPMqUpNFfkmJuEd5+JQOG9McH7j9pBagohkC6k3Cn92dAf9iD6NSDKSNgt1vxXhaNnfAbYJ5pqeSGy6QMSVO0TXYj4asln5OutD/284QIDAQAB";
@NonNull
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
Request request = chain.request();
return chain.proceed(invoke(chain.request()));
}
private Request invoke(Request req) throws IOException {
Request request = req;
String method = request.method().toLowerCase().trim();
HttpUrl url = request.url();
boolean skipEncrypt = url.encodedPath().endsWith("appVersion")
@ -87,7 +89,7 @@ public class RequestEncryptInterceptor implements Interceptor {
|| url.encodedPath().endsWith("fastLogin")
|| url.encodedPath().endsWith("loginWithTask")) {
byte[] bytes = RSAUtils.encryptByPublicKey(aesKey.getBytes(StandardCharsets.UTF_8), PUBLIC_KEY);
byte[] bytes = RSAUtils.encryptByPublicKey(aesKey.getBytes(StandardCharsets.UTF_8), getPublicKey());
String tokenSecret = Base64.encodeToString(bytes, Base64.NO_WRAP);
requestBuilder.addHeader("secret", tokenSecret);
} else {
@ -104,6 +106,10 @@ public class RequestEncryptInterceptor implements Interceptor {
}
}
}
return chain.proceed(request);
return request;
}
}
private native String getPublicKey();
}

View File

@ -1,6 +1,7 @@
package com.za.net
import com.za.base.AppConfig
import com.za.common.GlobalData
import com.za.common.log.LogUtil
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
@ -11,7 +12,7 @@ import java.io.UnsupportedEncodingException
import java.net.URLDecoder
import java.util.concurrent.TimeUnit
object RetrofitHelper {
internal object RetrofitHelper {
private var retrofit : Retrofit? = null
private var apiService : ApiService? = null
private val loggerInterceptor = HttpLoggingInterceptor {
@ -29,8 +30,9 @@ object RetrofitHelper {
if (it.contains("name=\"file\"; filename")) {
return@HttpLoggingInterceptor
}
LogUtil.print("--network--",
URLDecoder.decode(it.replace(Regex("%(?![0-9a-fA-F]{2})"), ""), "utf-8"))
// LogUtil.print("--network--",
// URLDecoder.decode(it.replace(Regex("%(?![0-9a-fA-F]{2})"), ""), "utf-8"))
} catch (e : UnsupportedEncodingException) {
e.printStackTrace()
}

View File

@ -10,7 +10,7 @@ import com.za.base.Const
import com.za.room.db.GlobalRoom
@SuppressLint("StaticFieldLeak")
object RoomHelper {
internal object RoomHelper {
const val VERSION: Int = 43
private lateinit var mContext: Context
var db: GlobalRoom? = null

View File

@ -26,7 +26,7 @@ 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, PhotoTemplateInfo::class],
version = RoomHelper.VERSION,
exportSchema = false)
abstract class GlobalRoom : RoomDatabase() {
internal abstract class GlobalRoom : RoomDatabase() {
abstract fun eleWorkOrderDao() : EleWorkOrderDao
abstract fun eleCarDamagePhotoDao() : EleCarDamagePhotoDao

View File

@ -9,7 +9,7 @@ import androidx.room.Update
import com.za.bean.db.ele.EleCarDamagePhotoBean
@Dao
interface EleCarDamagePhotoDao {
internal interface EleCarDamagePhotoDao {
@Insert(onConflict = OnConflictStrategy.REPLACE, entity = EleCarDamagePhotoBean::class)
fun insert(eleCarDamagePhotoBean: EleCarDamagePhotoBean)

View File

@ -8,7 +8,7 @@ import androidx.room.Update
import com.za.bean.db.ele.EleWorkOrderBean
@Dao
interface EleWorkOrderDao {
internal interface EleWorkOrderDao {
@Insert(onConflict = OnConflictStrategy.REPLACE, entity = EleWorkOrderBean::class)
fun insertEleWorkOrder(eleWorkOrderBean: EleWorkOrderBean)

View File

@ -9,7 +9,7 @@ import com.za.base.Const
import com.za.bean.db.order.PhotoTemplateInfo
@Dao
interface ChangeBatteryDao {
internal interface ChangeBatteryDao {
@Insert(onConflict = OnConflictStrategy.REPLACE, entity = PhotoTemplateInfo::class)
fun insert(photoTemplateInfo: PhotoTemplateInfo)

View File

@ -8,7 +8,7 @@ import androidx.room.Update
import com.za.bean.db.order.OrderInfo
@Dao
interface OrderDao {
internal interface OrderDao {
//更换电瓶照片
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertOrder(orderInfo: OrderInfo)

View File

@ -9,7 +9,7 @@ import com.za.base.Const
import com.za.bean.db.order.PhotoTemplateInfo
@Dao
interface PhotoTemplateDao {
internal interface PhotoTemplateDao {
@Insert(onConflict = OnConflictStrategy.REPLACE, entity = PhotoTemplateInfo::class)
fun insert(photoTemplateInfo: PhotoTemplateInfo)

View File

@ -35,7 +35,7 @@ interface PushListener {
data class LastJPushBean(val msg : String, val time : Long = System.currentTimeMillis())
object ServiceManager {
internal object ServiceManager {
@Volatile
private var pushListener : PushListener? = null
private var lastJPushBean : LastJPushBean? = null

View File

@ -43,7 +43,7 @@ class ZdPushServiceReceive : BroadcastReceiver() {
if (ActivityUtils.getTopActivity() == null) {
AppUtils.launchApp(GlobalData.application.packageName)
}
LogUtil.print("PushActivityLifecycleCallbacks", "收到来自远程进程的消息: $type")
LogUtil.print("ZdPushServiceReceive", "收到来自远程进程的消息: $type")
when (type) {
Const.PushMessageType.BROADCAST -> handleBroadcast("broadcast:$message")
@ -56,7 +56,7 @@ class ZdPushServiceReceive : BroadcastReceiver() {
handleGiveUpOrder(activity, jpushBean)
}
} catch (e : Exception) {
LogUtil.print("PushActivityLifecycleCallbacks",
LogUtil.print("ZdPushServiceReceive",
"处理订单放弃消息失败: ${e.message}")
}
}
@ -70,7 +70,7 @@ class ZdPushServiceReceive : BroadcastReceiver() {
handleImportantTip(activity, jpushBean)
}
} catch (e : Exception) {
LogUtil.print("PushActivityLifecycleCallbacks",
LogUtil.print("ZdPushServiceReceive",
"处理重要提示消息失败: ${e.message}")
}
}
@ -84,7 +84,7 @@ class ZdPushServiceReceive : BroadcastReceiver() {
handleReDispatchOrder(activity, jpushBean)
}
} catch (e : Exception) {
LogUtil.print("PushActivityLifecycleCallbacks",
LogUtil.print("ZdPushServiceReceive",
"处理订单重新派发消息失败: ${e.message}")
}
}
@ -97,7 +97,7 @@ class ZdPushServiceReceive : BroadcastReceiver() {
handlerModifyOrder()
}
} catch (e : Exception) {
LogUtil.print("PushActivityLifecycleCallbacks",
LogUtil.print("ZdPushServiceReceive",
"处理重要提示消息失败: ${e.message}")
}
}
@ -110,7 +110,7 @@ class ZdPushServiceReceive : BroadcastReceiver() {
handleRevokeOrder(activity)
}
} catch (e : Exception) {
LogUtil.print("PushActivityLifecycleCallbacks",
LogUtil.print("ZdPushServiceReceive",
"处理订单撤回消息失败: ${e.message}")
}
}
@ -124,7 +124,7 @@ class ZdPushServiceReceive : BroadcastReceiver() {
handeReportMessage(jpushBean = jpushBean)
}
} catch (e : Exception) {
LogUtil.print("PushActivityLifecycleCallbacks",
LogUtil.print("ZdPushServiceReceive",
"处理重要提示消息失败: ${e.message}")
}
}

View File

@ -32,7 +32,7 @@ import kotlin.math.sin
import kotlin.math.sqrt
@SuppressLint("StaticFieldLeak")
object ZdLocationManager : AMapLocationListener {
internal object ZdLocationManager : AMapLocationListener {
private const val TAG = "ZdLocationManager"
private var aMapLocationClient : AMapLocationClient? = null
private var context : Context? = null

View File

@ -1,11 +1,18 @@
package com.za.service.mqtt
object MqttConfig {
const val INSTANCE_ID = "mqtt-cn-oew23jbkb1f"
const val END_POINT = "mqtt-cn-oew23jbkb1f.mqtt.aliyuncs.com"
const val ACCESS_KEY = "LTAI5tKgZ9ACKorXzzWLxgg7"
const val SECRET_KEY = "D04F0UH2GzrDsYaJ9GTfULGPjcsvvz"
const val GROUP_ID = "GID_ZDJY"
const val TOPIC_PREFIX = "pushBaseTopic/p2p"
const val QOS_LEVEL = 0
}
val INSTANCE_ID = getMqttInstanceId()
val END_POINT = getMqttEndpoint()
val ACCESS_KEY = getMqttAccessKey()
val SECRET_KEY = getMqttSecretKey()
val GROUP_ID = getMqttGroupId()
val TOPIC_PREFIX = getMqttTopicPrefix()
const val QOS_LEVEL = 0
external fun getMqttInstanceId() : String
external fun getMqttEndpoint() : String
external fun getMqttAccessKey() : String
external fun getMqttSecretKey() : String
external fun getMqttGroupId() : String
external fun getMqttTopicPrefix() : String
}

View File

@ -1,16 +1,16 @@
package com.za.service.mqtt
import android.annotation.SuppressLint
import android.os.Handler
import android.os.Looper
import com.za.common.GlobalData
import com.za.common.log.LogUtil
import com.za.common.util.DeviceUtil
import com.za.common.util.Tools.macSignature
import com.za.service.ServiceManager
import org.eclipse.paho.android.service.MqttAndroidClient
import org.eclipse.paho.client.mqttv3.IMqttActionListener
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken
import org.eclipse.paho.client.mqttv3.IMqttToken
import org.eclipse.paho.client.mqttv3.MqttCallback
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended
import org.eclipse.paho.client.mqttv3.MqttClient
import org.eclipse.paho.client.mqttv3.MqttConnectOptions
import org.eclipse.paho.client.mqttv3.MqttException
import org.eclipse.paho.client.mqttv3.MqttMessage
@ -23,35 +23,45 @@ object MyMqttClient {
private lateinit var topic : String
@SuppressLint("StaticFieldLeak")
private var mqttClient : MqttAndroidClient? = null
private var mqttClient : MqttClient? = null
fun initialize(deviceId : String?) {
clientId = "${MqttConfig.GROUP_ID}@@@$deviceId"
topic = "${MqttConfig.TOPIC_PREFIX}/$clientId"
mqttClient = MqttAndroidClient(GlobalData.application,
"tcp://${MqttConfig.END_POINT}:1883",
clientId,
MemoryPersistence())
mqttClient = MqttClient("tcp://${MqttConfig.END_POINT}:1883", clientId, MemoryPersistence())
setupMqttCallbacks()
connect()
LogUtil.print("MyMqttClient ", "initialize success")
}
private fun setupMqttCallbacks() {
mqttClient?.setCallback(object : MqttCallback {
override fun connectionLost(throwable : Throwable) {
LogUtil.print("MyMqttClient ",
"Connection lost: ${throwable.message}") // connect()
mqttClient?.setCallback(object : MqttCallbackExtended {
override fun connectComplete(reconnect : Boolean, serverURI : String?) {
Handler(Looper.getMainLooper()).post {
isConnecting = false
LogUtil.print("MyMqttClient ", "connect success==")
subscribeTopic()
}
}
override fun messageArrived(topic : String, mqttMessage : MqttMessage) {
val message = String(mqttMessage.payload)
LogUtil.print("MyMqttClient ", "Message arrived: $message")
ServiceManager.handlerPushMsg(message)
override fun connectionLost(cause : Throwable?) {
isConnecting = false
LogUtil.print("MyMqttClient ", "Connection lost: ${cause?.message}")
}
override fun deliveryComplete(token : IMqttDeliveryToken) {
override fun messageArrived(topic : String?, message : MqttMessage?) {
if (message == null) {
LogUtil.print("MyMqttClient ", "Message arrived: null")
return
}
Handler(Looper.getMainLooper()).post {
val message = String(message.payload)
LogUtil.print("MyMqttClient ", "Message arrived: $message")
ServiceManager.handlerPushMsg(message)
}
}
override fun deliveryComplete(token : IMqttDeliveryToken?) {
LogUtil.print("MyMqttClient ", "Message delivery complete")
}
})
@ -78,19 +88,7 @@ object MyMqttClient {
mqttConnectOption.maxReconnectDelay = 30 * 1000
mqttConnectOption.mqttVersion = MqttConnectOptions.MQTT_VERSION_3_1_1
mqttConnectOption.connectionTimeout = 30
mqttClient?.connect(mqttConnectOption, null, object : IMqttActionListener {
override fun onSuccess(asyncActionToken : IMqttToken?) {
isConnecting = false
LogUtil.print("MyMqttClient ", "connect success==")
subscribeTopic()
}
override fun onFailure(asyncActionToken : IMqttToken?, exception : Throwable?) {
isConnecting = false
LogUtil.print("MyMqttClient ", "connect failed== ${exception?.message}")
}
})
mqttClient?.connect(mqttConnectOption)
} catch (e : MqttException) {
LogUtil.print("MyMqttClient ", "Connection failed2: ${e.message}")
}
@ -99,7 +97,6 @@ object MyMqttClient {
//检测mqtt连接状态
fun publishMessage() {
if (mqttClient == null) {
initialize(deviceId = DeviceUtil.getAndroidId(GlobalData.application))
return
@ -117,19 +114,8 @@ object MyMqttClient {
private fun subscribeTopic() {
try {
if (mqttClient?.isConnected == true) {
mqttClient?.subscribe(topic,
MqttConfig.QOS_LEVEL,
null,
object : IMqttActionListener {
override fun onSuccess(asyncActionToken : IMqttToken?) {
LogUtil.print("MyMqttClient ", "Subscribed to topic: $topic")
}
override fun onFailure(asyncActionToken : IMqttToken?,
exception : Throwable) {
LogUtil.print("MyMqttClient ", "Subscribe failed: ${exception.message}")
}
})
mqttClient?.subscribe(topic, MqttConfig.QOS_LEVEL)
LogUtil.print("MyMqttClient ", "mqtt subscribe $topic ")
} else {
LogUtil.print("MyMqttClient ", "Cannot subscribe: MQTT client is not connected")
}
@ -141,15 +127,7 @@ object MyMqttClient {
fun disconnect() {
try {
if (mqttClient?.isConnected == true) {
mqttClient?.disconnect(null, object : IMqttActionListener {
override fun onSuccess(asyncActionToken : IMqttToken?) {
LogUtil.print("MyMqttClient ", "Disconnected")
}
override fun onFailure(asyncActionToken : IMqttToken?, exception : Throwable) {
LogUtil.print("MyMqttClient ", "Disconnect failed")
}
})
mqttClient?.disconnect()
}
} catch (e : MqttException) {
LogUtil.print("MyMqttClient ", "Disconnect failed: ${e.message}")

View File

@ -41,7 +41,7 @@ import com.za.common.log.LogUtil
import com.za.ext.finish
import com.za.servicing.R
class CommonH5Activity : BaseActivity() {
internal class CommonH5Activity : BaseActivity() {
private var webView : WebView? = null
private var isDestroyed = false

View File

@ -136,11 +136,12 @@ class ServicingMainActivity : BaseActivity() {
})
}
fun sendMessageToMainProcess(context : Context,
type : String,
message : String) { // 使用广播将消息发送到主进程
val intent = Intent(Const.PushMessageType.ACTION_MAIN.takeIf { GlobalData.isMaster }
?: Const.PushMessageType.ACTION_SDK)
fun sendMessageToMainProcess(context : Context, type : String, message : String) {
val intent = if (context.packageName == "com.za.rescue.dealer") {
Intent(Const.PushMessageType.ACTION_MAIN)
} else {
Intent(Const.PushMessageType.ACTION_SDK)
}
intent.setPackage(context.packageName)
intent.putExtra("type", type)
intent.putExtra("message", message)

View File

@ -15,7 +15,7 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.flow.MutableStateFlow
class ServicingMainVm : BaseVm<ServicingMainVm.Action, ServicingMainVm.UiState>() {
internal class ServicingMainVm : BaseVm<ServicingMainVm.Action, ServicingMainVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState
@ -87,6 +87,9 @@ class ServicingMainVm : BaseVm<ServicingMainVm.Action, ServicingMainVm.UiState>(
return
}
GlobalData.token = it.token
GlobalData.driverId = it.userId
GlobalData.vehicleId = it.vehicleId
GlobalData.deviceId = deviceId
CommonMethod.getGenerateInfo(success = { success() },
failed = { failure(it ?: "") })
}

View File

@ -68,277 +68,252 @@ import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
class MapSearchActivity : BaseActivity() {
@SuppressLint("MissingPermission")
@Composable
override fun ContentView() {
MapSearchScreen(onLocationSelected = ::onLocationSelected)
}
@SuppressLint("MissingPermission")
@Composable
override fun ContentView() {
MapSearchScreen(onLocationSelected = ::onLocationSelected)
}
private fun onLocationSelected(poiData: PoiData) {
val intent = Intent()
intent.putExtra("poiData", poiData)
setResult(RESULT_OK, intent)
finish()
}
private fun onLocationSelected(poiData : PoiData) {
val intent = Intent()
intent.putExtra("poiData", poiData)
setResult(RESULT_OK, intent)
finish()
}
}
@SuppressLint("MissingPermission")
@Composable
fun MapSearchScreen(onLocationSelected: (PoiData) -> Unit) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
var searchText by remember { mutableStateOf("") }
var selectLatLng by remember { mutableStateOf(LatLonPoint(0.0, 0.0)) }
var mapInitialized by remember { mutableStateOf(false) }
val mapView = remember { MapView(context) } // Remember the MapView instance
var locationClient: AMapLocationClient? by remember { mutableStateOf(null) }
var isLoading by remember { mutableStateOf(false) }
var errorMessage by remember { mutableStateOf<String?>(null) }
var searchResults by remember { mutableStateOf<List<PoiItem>>(emptyList()) }
fun MapSearchScreen(onLocationSelected : (PoiData) -> Unit) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
var searchText by remember { mutableStateOf("") }
var selectLatLng by remember { mutableStateOf(LatLonPoint(0.0, 0.0)) }
var mapInitialized by remember { mutableStateOf(false) }
val mapView = remember { MapView(context) } // Remember the MapView instance
var locationClient : AMapLocationClient? by remember { mutableStateOf(null) }
var isLoading by remember { mutableStateOf(false) }
var errorMessage by remember { mutableStateOf<String?>(null) }
var searchResults by remember { mutableStateOf<List<PoiItem>>(emptyList()) }
// Permission handling
val locationPermissionGranted = remember { mutableStateOf(false) }
val locationPermissionLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
locationPermissionGranted.value = isGranted
}
// Permission handling
val locationPermissionGranted = remember { mutableStateOf(false) }
val locationPermissionLauncher =
rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted : Boolean ->
locationPermissionGranted.value = isGranted
}
// Check if location permission is granted
val checkPermission = {
if (ContextCompat.checkSelfPermission(
context,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
locationPermissionGranted.value = true
} else {
locationPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
}
}
// Check if location permission is granted
val checkPermission = {
if (ContextCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
) {
locationPermissionGranted.value = true
} else {
locationPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
}
}
errorMessage?.let { message ->
Snackbar(
action = {
Button(onClick = { errorMessage = null }) {
Text("关闭")
}
},
modifier = Modifier.padding(8.dp)
) {
Text(message)
}
}
errorMessage?.let { message ->
Snackbar(action = {
Button(onClick = { errorMessage = null }) {
Text("关闭")
}
}, modifier = Modifier.padding(8.dp)) {
Text(message)
}
}
LaunchedEffect(key1 = Unit) {
checkPermission()
}
LaunchedEffect(key1 = Unit) {
checkPermission()
}
LaunchedEffect(key1 = locationPermissionGranted.value) {
if (locationPermissionGranted.value) {
locationClient = AMapLocationClient(context).apply {
setLocationOption(AMapLocationClientOption().apply {
isOnceLocation = true // Only need the location once
isNeedAddress = true
})
setLocationListener { location ->
if (location != null) {
val latLng = LatLng(location.latitude, location.longitude)
selectLatLng = LatLonPoint(location.latitude, location.longitude)
scope.launch {
val address = reverseGeocode(context, selectLatLng)
searchText = address
}
mapView.map.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15f))
} else {
Log.e("MapSearchScreen", "Location failed")
errorMessage = "位置获取失败"
}
locationClient?.apply {
stopLocation() // 停止位置更新
onDestroy() // 销毁位置客户端
}
locationClient = null
}
startLocation()
}
} else {
Log.e("MapSearchScreen", "Location permission not granted")
errorMessage = "位置权限未授予"
}
}
LaunchedEffect(key1 = locationPermissionGranted.value) {
if (locationPermissionGranted.value) {
locationClient = AMapLocationClient(context).apply {
setLocationOption(AMapLocationClientOption().apply {
isOnceLocation = true // Only need the location once
isNeedAddress = true
})
setLocationListener { location ->
if (location != null) {
val latLng = LatLng(location.latitude, location.longitude)
selectLatLng = LatLonPoint(location.latitude, location.longitude)
scope.launch {
val address = reverseGeocode(context, selectLatLng)
searchText = address
}
mapView.map.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15f))
} else {
Log.e("MapSearchScreen", "Location failed")
errorMessage = "位置获取失败"
}
locationClient?.apply {
stopLocation() // 停止位置更新
onDestroy() // 销毁位置客户端
}
locationClient = null
}
startLocation()
}
} else {
Log.e("MapSearchScreen", "Location permission not granted")
errorMessage = "位置权限未授予"
}
}
DisposableEffect(key1 = mapView) {
onDispose {
locationClient?.onDestroy()
mapView.onDestroy()
}
}
DisposableEffect(key1 = mapView) {
onDispose {
locationClient?.onDestroy()
mapView.onDestroy()
}
}
Scaffold(
topBar = {
HeadView(title = "地图选点", onBack = { context.finish() })
}
) { paddingValues ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
.padding(16.dp)
.verticalScroll(state = rememberScrollState())
) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 16.dp)
) {
Column(
modifier = Modifier.padding(16.dp)
) {
TextField(
value = searchText,
onValueChange = { searchText = it },
label = { Text("搜索地址") },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(8.dp))
Button(
onClick = {
if (searchText.isNotBlank()) {
isLoading = true
errorMessage = null
searchResults = emptyList() // Clear previous results
scope.launch {
val results = searchPoi(context, searchText)
searchResults = results
isLoading = false
}
} else {
errorMessage = "请输入地址"
}
},
modifier = Modifier.fillMaxWidth()
) {
Text("搜索")
}
}
}
if (isLoading) {
CircularProgressIndicator(
modifier = Modifier.align(Alignment.CenterHorizontally)
)
}
if (searchResults.isNotEmpty()) {
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.height(180.dp)
.padding(bottom = 16.dp)
) {
items(items = searchResults) {
Box(modifier = Modifier
.fillMaxWidth()
.clickable {
selectLatLng = it.latLonPoint
searchText = it.title
}
.padding(5.dp)) {
Text(it.title, color = Color.Black)
}
}
}
}
// Wrap MapView with AndroidView
AndroidView(
factory = {
mapView.apply {
onCreate(null)
onResume()
}
},
update = {
it.map.setOnMapClickListener { latLng ->
selectLatLng = LatLonPoint(latLng.latitude, latLng.longitude)
scope.launch {
val address = reverseGeocode(context, selectLatLng)
searchText = address
}
}
if (!mapInitialized) {
mapInitialized = true
}
},
modifier = Modifier
.fillMaxWidth()
.height(300.dp)
)
Scaffold(topBar = {
HeadView(title = "地图选点", onBack = { context.finish() })
}) { paddingValues ->
Column(modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
.padding(16.dp)
.verticalScroll(state = rememberScrollState())) {
Card(modifier = Modifier
.fillMaxWidth()
.padding(bottom = 16.dp)) {
Column(modifier = Modifier.padding(16.dp)) {
TextField(value = searchText,
onValueChange = { searchText = it },
label = { Text("搜索地址") },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
modifier = Modifier.fillMaxWidth())
Spacer(modifier = Modifier.height(8.dp))
Button(onClick = {
if (searchText.isNotBlank()) {
isLoading = true
errorMessage = null
searchResults = emptyList() // Clear previous results
scope.launch {
val results = searchPoi(context, searchText)
searchResults = results
isLoading = false
}
} else {
errorMessage = "请输入地址"
}
}, modifier = Modifier.fillMaxWidth()) {
Text("搜索")
}
}
}
if (isLoading) {
CircularProgressIndicator(modifier = Modifier.align(Alignment.CenterHorizontally))
}
if (searchResults.isNotEmpty()) {
LazyColumn(modifier = Modifier
.fillMaxWidth()
.height(180.dp)
.padding(bottom = 16.dp)) {
items(items = searchResults) {
Box(modifier = Modifier
.fillMaxWidth()
.clickable {
selectLatLng = it.latLonPoint
searchText = it.title
}
.padding(5.dp)) {
Text(it.title, color = Color.Black)
}
}
}
} // Wrap MapView with AndroidView
AndroidView(factory = {
mapView.apply {
onCreate(null)
onResume()
}
}, update = {
it.map.setOnMapClickListener { latLng ->
selectLatLng = LatLonPoint(latLng.latitude, latLng.longitude)
scope.launch {
val address = reverseGeocode(context, selectLatLng)
searchText = address
}
}
if (! mapInitialized) {
mapInitialized = true
}
}, modifier = Modifier
.fillMaxWidth()
.height(300.dp))
Spacer(modifier = Modifier.height(20.dp))
Spacer(modifier = Modifier.height(20.dp))
CommonButton(text = "确定") {
onLocationSelected(PoiData(name = searchText, lat = selectLatLng.latitude, lng = selectLatLng.longitude))
}
}
}
CommonButton(text = "确定") {
onLocationSelected(PoiData(name = searchText,
lat = selectLatLng.latitude,
lng = selectLatLng.longitude))
}
}
}
}
private suspend fun searchPoi(context: Context, query: String): List<PoiItem> {
return suspendCoroutine { continuation ->
val poiSearchQuery = PoiSearch.Query(query, "", "") // 第二个参数是城市代码,留空表示全国搜索
poiSearchQuery.pageNum = 0
poiSearchQuery.pageSize = 10
val poiSearch = PoiSearch(context, poiSearchQuery)
private suspend fun searchPoi(context : Context, query : String) : List<PoiItem> {
return suspendCoroutine { continuation ->
val poiSearchQuery = PoiSearch.Query(query, "", "") // 第二个参数是城市代码,留空表示全国搜索
poiSearchQuery.pageNum = 0
poiSearchQuery.pageSize = 10
val poiSearch = PoiSearch(context, poiSearchQuery)
poiSearch.setOnPoiSearchListener(object : PoiSearch.OnPoiSearchListener {
override fun onPoiSearched(result: PoiResult?, rCode: Int) {
if (rCode == AMapException.CODE_AMAP_SUCCESS) {
val pois = result?.pois ?: emptyList()
continuation.resume(pois)
} else {
Log.e("MapSearchScreen", "POI 搜索失败:$rCode")
continuation.resume(emptyList())
}
}
poiSearch.setOnPoiSearchListener(object : PoiSearch.OnPoiSearchListener {
override fun onPoiSearched(result : PoiResult?, rCode : Int) {
if (rCode == AMapException.CODE_AMAP_SUCCESS) {
val pois = result?.pois ?: emptyList()
continuation.resume(pois)
} else {
Log.e("MapSearchScreen", "POI 搜索失败:$rCode")
continuation.resume(emptyList())
}
}
override fun onPoiItemSearched(poiItem: PoiItem?, rCode: Int) {
// Not used in this case
}
})
override fun onPoiItemSearched(poiItem : PoiItem?,
rCode : Int) { // Not used in this case
}
})
poiSearch.searchPOIAsyn()
}
poiSearch.searchPOIAsyn()
}
}
private suspend fun reverseGeocode(context: Context, latLng: LatLonPoint): String {
return suspendCoroutine { continuation ->
val geocodeSearch = GeocodeSearch(context)
geocodeSearch.setOnGeocodeSearchListener(object : GeocodeSearch.OnGeocodeSearchListener {
override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) {
if (rCode == AMapException.CODE_AMAP_SUCCESS) {
val address = result?.regeocodeAddress?.formatAddress
continuation.resume(address ?: "")
} else {
Log.e("MapSearchScreen", "Reverse Geocode failed: $rCode")
continuation.resume("")
}
}
private suspend fun reverseGeocode(context : Context, latLng : LatLonPoint) : String {
return suspendCoroutine { continuation ->
val geocodeSearch = GeocodeSearch(context)
geocodeSearch.setOnGeocodeSearchListener(object : GeocodeSearch.OnGeocodeSearchListener {
override fun onRegeocodeSearched(result : RegeocodeResult?, rCode : Int) {
if (rCode == AMapException.CODE_AMAP_SUCCESS) {
val address = result?.regeocodeAddress?.formatAddress
continuation.resume(address ?: "")
} else {
Log.e("MapSearchScreen", "Reverse Geocode failed: $rCode")
continuation.resume("")
}
}
override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) {
// Not used in reverse geocoding
}
})
override fun onGeocodeSearched(result : GeocodeResult?,
rCode : Int) { // Not used in reverse geocoding
}
})
// Perform Reverse Geocoding (LatLng -> address)
val query = com.amap.api.services.geocoder.RegeocodeQuery(latLng, 200f, GeocodeSearch.AMAP)
geocodeSearch.getFromLocationAsyn(query) // Use the async version
}
// Perform Reverse Geocoding (LatLng -> address)
val query = com.amap.api.services.geocoder.RegeocodeQuery(latLng, 200f, GeocodeSearch.AMAP)
geocodeSearch.getFromLocationAsyn(query) // Use the async version
}
}
data class PoiData(val name: String? = null, val lat: Double? = null, val lng: Double? = null) : Serializable
data class PoiData(val name : String? = null, val lat : Double? = null, val lng : Double? = null) :
Serializable
@Preview
@Composable
fun PreviewMapSearchScreen() {
MapSearchScreen(onLocationSelected = {})
MapSearchScreen(onLocationSelected = {})
}

View File

@ -74,7 +74,7 @@ import com.za.ext.finish
import com.za.servicing.R
import com.za.ui.servicing.in_servicing_setting.OrderTaskNotesDialog
class NewOrderActivity : BaseActivity() {
internal class NewOrderActivity : BaseActivity() {
@Composable
override fun ContentView() {

View File

@ -89,7 +89,7 @@ data class NewOrderItemUIBean(
// 1 服务中 2 历史订单
@Composable
fun NewOrderItem(uiBean : NewOrderItemUIBean?,
internal fun NewOrderItem(uiBean : NewOrderItemUIBean?,
goInServicing : () -> Unit = {},
goHistory : () -> Unit = {},
goDetail : () -> Unit = {},

View File

@ -34,7 +34,7 @@ import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
class NewOrderVm : BaseVm<NewOrderVm.Action, NewOrderVm.UiState>() {
internal class NewOrderVm : BaseVm<NewOrderVm.Action, NewOrderVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState

View File

@ -42,7 +42,7 @@ import com.za.base.view.EmptyView
import com.za.base.view.HeadView
import com.za.ext.finish
class HistoryReportActivity : BaseActivity() {
internal class HistoryReportActivity : BaseActivity() {
@Composable
override fun ContentView() {
HistoryReportScreen()
@ -50,7 +50,7 @@ class HistoryReportActivity : BaseActivity() {
}
@Composable
fun HistoryReportScreen(vm : HistoryReportVm = viewModel()) {
internal fun HistoryReportScreen(vm : HistoryReportVm = viewModel()) {
val uiState by vm.uiState.collectAsStateWithLifecycle()
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current

View File

@ -13,42 +13,41 @@ import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
class HistoryReportVm : BaseVm<HistoryReportVm.Action, HistoryReportVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState.asStateFlow()
internal class HistoryReportVm : BaseVm<HistoryReportVm.Action, HistoryReportVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState.asStateFlow()
override fun updateState(uiState: UiState) {
_uiState.value = uiState
}
override fun updateState(uiState : UiState) {
_uiState.value = uiState
}
override fun dispatch(action: Action) {
when (action) {
Action.Init -> init()
}
}
override fun dispatch(action : Action) {
when (action) {
Action.Init -> init()
}
}
private fun init() {
LoadingManager.showLoading()
val request = ReportHistoryRequest(taskId = "${GlobalData.currentOrder?.taskId}")
RetrofitHelper.getDefaultService().getReportHistory(request)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BaseObserver<List<ReportHistoryBean>>() {
override fun doSuccess(it: List<ReportHistoryBean>?) {
LoadingManager.hideLoading()
updateState(uiState.value.copy(historyReportList = it))
}
private fun init() {
LoadingManager.showLoading()
val request = ReportHistoryRequest(taskId = "${GlobalData.currentOrder?.taskId}")
RetrofitHelper.getDefaultService().getReportHistory(request).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BaseObserver<List<ReportHistoryBean>>() {
override fun doSuccess(it : List<ReportHistoryBean>?) {
LoadingManager.hideLoading()
updateState(uiState.value.copy(historyReportList = it))
}
override fun doFailure(code: Int, msg: String?) {
LoadingManager.hideLoading()
ToastUtils.showLong(msg)
}
})
}
override fun doFailure(code : Int, msg : String?) {
LoadingManager.hideLoading()
ToastUtils.showLong(msg)
}
})
}
data class UiState(val historyReportList: List<ReportHistoryBean>? = null)
data class UiState(val historyReportList : List<ReportHistoryBean>? = null)
sealed class Action {
data object Init : Action()
}
sealed class Action {
data object Init : Action()
}
}

View File

@ -44,7 +44,6 @@ import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.TextStyle
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
@ -61,7 +60,7 @@ import com.za.ui.map_search.MapSearchActivity
import com.za.ui.map_search.PoiData
import kotlinx.coroutines.launch
class OrderReportActivity : BaseActivity() {
internal class OrderReportActivity : BaseActivity() {
@Composable
override fun ContentView() {
OrderReportScreen()
@ -73,7 +72,7 @@ private val TextGrey = Color(0xFF5F6368)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun OrderReportScreen(vm: OrderReportVm = viewModel()) {
internal fun OrderReportScreen(vm: OrderReportVm = viewModel()) {
val uiState by vm.uiState.collectAsStateWithLifecycle()
val scaffoldState = rememberBottomSheetScaffoldState()
val scope = rememberCoroutineScope()
@ -202,9 +201,3 @@ fun OrderReportScreen(vm: OrderReportVm = viewModel()) {
}
}
}
@Preview
@Composable
fun OrderReportPreview(modifier: Modifier = Modifier) {
OrderReportScreen()
}

View File

@ -14,7 +14,7 @@ import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
class OrderReportVm : BaseVm<OrderReportVm.Action, OrderReportVm.UiState>() {
internal class OrderReportVm : BaseVm<OrderReportVm.Action, OrderReportVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState.asStateFlow()

View File

@ -38,7 +38,7 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlin.math.abs
class ReportFloatingManager : Service() {
internal class ReportFloatingManager : Service() {
private var windowManager : WindowManager? = null
private var floatingView : View? = null
private var touchJob : Job? = null

View File

@ -359,7 +359,7 @@ private fun ocrRecognition(photoTemplateInfo : PhotoTemplateInfo,
@Composable
fun InServicingPhotoView(modifier : Modifier = Modifier,
internal fun InServicingPhotoView(modifier : Modifier = Modifier,
photoTemplateInfo : PhotoTemplateInfo,
index : Int? = null,
success : (PhotoTemplateInfo) -> Unit) {
@ -445,7 +445,7 @@ fun InServicingPhotoView(modifier : Modifier = Modifier,
@Composable
fun InServicingPhotoViewIsCanClick(modifier : Modifier = Modifier,
internal fun InServicingPhotoViewIsCanClick(modifier : Modifier = Modifier,
photoTemplateInfo : PhotoTemplateInfo,
index : Int? = null,
isCanClick : Boolean = true,
@ -534,7 +534,7 @@ fun InServicingPhotoViewIsCanClick(modifier : Modifier = Modifier,
@Composable
fun InServicingPhotoWithoutTitleView(modifier : Modifier = Modifier,
internal fun InServicingPhotoWithoutTitleView(modifier : Modifier = Modifier,
photoTemplateInfo : PhotoTemplateInfo,
index : Int? = null,
success : (PhotoTemplateInfo) -> Unit) {
@ -591,7 +591,7 @@ fun InServicingPhotoWithoutTitleView(modifier : Modifier = Modifier,
}
@Composable
fun InServicingPhotoItemView(modifier : Modifier = Modifier,
internal fun InServicingPhotoItemView(modifier : Modifier = Modifier,
photoTemplateInfo : PhotoTemplateInfo,
isCanClick : Boolean = true,
success : (PhotoTemplateInfo) -> Unit) {

View File

@ -24,7 +24,7 @@ import com.za.ext.goNextPage
import com.za.ui.servicing.InServicingPhotoView
import com.za.ui.servicing.view.InServicingHeadView
class CheckVehicleActivity : BaseActivity() {
internal class CheckVehicleActivity : BaseActivity() {
@Composable
override fun ContentView() {
CheckVehicleScreen()
@ -32,7 +32,7 @@ class CheckVehicleActivity : BaseActivity() {
}
@Composable
fun CheckVehicleScreen(vm: CheckVehicleVm = viewModel()) {
internal fun CheckVehicleScreen(vm: CheckVehicleVm = viewModel()) {
val uiState = vm.uiState.collectAsStateWithLifecycle()
val context = LocalContext.current

View File

@ -19,7 +19,7 @@ import com.za.offline.OfflineUpdateTaskBean
import com.za.service.location.ZdLocationManager
import kotlinx.coroutines.flow.MutableStateFlow
class CheckVehicleVm : IServicingVm<CheckVehicleVm.Action, CheckVehicleVm.UiState>() {
internal class CheckVehicleVm : IServicingVm<CheckVehicleVm.Action, CheckVehicleVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState
override fun updateState(uiState : UiState) {

View File

@ -24,7 +24,7 @@ import com.za.ext.goNextPage
import com.za.ui.servicing.InServicingPhotoView
import com.za.ui.servicing.view.InServicingHeadView
class DeparturePhotoActivity : BaseActivity() {
internal class DeparturePhotoActivity : BaseActivity() {
@Composable
override fun ContentView() {
DeparturePhotoScreen()
@ -32,7 +32,7 @@ class DeparturePhotoActivity : BaseActivity() {
}
@Composable
fun DeparturePhotoScreen(vm : DeparturePhotoVm = viewModel()) {
internal fun DeparturePhotoScreen(vm : DeparturePhotoVm = viewModel()) {
val uiState = vm.uiState.collectAsStateWithLifecycle()
val context = LocalContext.current

View File

@ -15,7 +15,7 @@ import com.za.net.CommonMethod
import com.za.service.location.ZdLocationManager
import kotlinx.coroutines.flow.MutableStateFlow
class DeparturePhotoVm : IServicingVm<DeparturePhotoVm.Action, DeparturePhotoVm.UiState>() {
internal class DeparturePhotoVm : IServicingVm<DeparturePhotoVm.Action, DeparturePhotoVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState

View File

@ -24,7 +24,7 @@ import com.za.ext.goNextPage
import com.za.ui.servicing.InServicingPhotoView
import com.za.ui.servicing.view.InServicingHeadView
class DestinationPhotoActivity : BaseActivity() {
internal class DestinationPhotoActivity : BaseActivity() {
@Composable
override fun ContentView() {
DestinationPhotoScreen()
@ -32,7 +32,7 @@ class DestinationPhotoActivity : BaseActivity() {
}
@Composable
fun DestinationPhotoScreen(vm: DestinationPhotoVm = viewModel()) {
internal fun DestinationPhotoScreen(vm: DestinationPhotoVm = viewModel()) {
val uiState = vm.uiState.collectAsStateWithLifecycle()
val context = LocalContext.current

View File

@ -19,7 +19,7 @@ import com.za.offline.OfflineUpdateTaskBean
import com.za.service.location.ZdLocationManager
import kotlinx.coroutines.flow.MutableStateFlow
class DestinationPhotoVm : IServicingVm<DestinationPhotoVm.Action, DestinationPhotoVm.UiState>() {
internal class DestinationPhotoVm : IServicingVm<DestinationPhotoVm.Action, DestinationPhotoVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState
override fun updateState(uiState : UiState) {

View File

@ -61,7 +61,7 @@ import com.za.ui.camera.ZdCameraXActivity
import com.za.ui.servicing.view.InServicingHeadView
@Composable
fun EleSignCheckScreen(vm: EleSignCheckVm = viewModel()) {
internal fun EleSignCheckScreen(vm: EleSignCheckVm = viewModel()) {
val context = LocalContext.current
val uiState = vm.uiState.collectAsStateWithLifecycle()
LaunchedEffect(key1 = Unit) {
@ -163,8 +163,8 @@ private fun EleSignCheckContent(eleWorkOrderBean: EleWorkOrderBean?,
.background(color = Color.White, shape = RoundedCornerShape(4.dp))) {
Column(modifier = Modifier
.fillMaxWidth()
.background(brush = Brush.verticalGradient(arrayListOf(Color(0xFF97A0BA), Color(0xFFE1E8F3))),
shape = RoundedCornerShape(topStart = 4.dp, topEnd = 4.dp))
.background(brush = Brush.verticalGradient(arrayListOf(Color(0xFF97A0BA),
Color(0xFFE1E8F3))), shape = RoundedCornerShape(topStart = 4.dp, topEnd = 4.dp))
.padding(10.dp)) {
Text(text = "验车拍照", color = Color(0xFF213B54), fontWeight = FontWeight.Bold, fontSize = 16.sp)
Row(modifier = Modifier

View File

@ -24,7 +24,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import java.io.File
import java.util.Date
class EleSignCheckVm : IServicingVm<EleSignCheckVm.Action, EleSignCheckVm.UiState>() {
internal class EleSignCheckVm : IServicingVm<EleSignCheckVm.Action, EleSignCheckVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState
override fun updateState(uiState: UiState) {

View File

@ -49,7 +49,7 @@ import com.za.ui.view.SignatureView
import kotlin.math.ceil
@Composable
fun EleSignScreen(vm : EleSignVm = viewModel()) {
internal fun EleSignScreen(vm : EleSignVm = viewModel()) {
val context = LocalContext.current
val uiState = vm.uiState.collectAsStateWithLifecycle()
LaunchedEffect(key1 = Unit) {

View File

@ -26,7 +26,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
class EleSignVm : IServicingVm<EleSignVm.Action, EleSignVm.UiState>() {
internal class EleSignVm : IServicingVm<EleSignVm.Action, EleSignVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState
override fun updateState(uiState : UiState) {

View File

@ -52,7 +52,7 @@ import com.za.ui.new_order.NewOrderUiType
import com.za.ui.servicing.view.InServicingHeadView
import com.za.ui.servicing.view.ServiceOperation
class GoAccidentSiteActivity : BaseActivity() {
internal class GoAccidentSiteActivity : BaseActivity() {
@Composable
override fun ContentView() {
GoAccidentSiteScreen()
@ -61,7 +61,7 @@ class GoAccidentSiteActivity : BaseActivity() {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun GoAccidentSiteScreen(vm : GoAccidentSiteVm = viewModel()) {
internal fun GoAccidentSiteScreen(vm : GoAccidentSiteVm = viewModel()) {
val uiState = vm.uiState.collectAsStateWithLifecycle()
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
@ -121,16 +121,13 @@ fun GoAccidentSiteScreen(vm : GoAccidentSiteVm = viewModel()) {
title = "任务提交失败,是否离线提交?",
cancelEnable = true,
cancel = {
vm.dispatch(GoAccidentSiteVm.Action.UpdateState(uiState.value.copy(
showOfflineDialog = false)))
vm.dispatch(GoAccidentSiteVm.Action.UpdateState(uiState.value.copy(showOfflineDialog = false)))
},
dismiss = {
vm.dispatch(GoAccidentSiteVm.Action.UpdateState(uiState.value.copy(
showOfflineDialog = false)))
vm.dispatch(GoAccidentSiteVm.Action.UpdateState(uiState.value.copy(showOfflineDialog = false)))
},
confirm = {
vm.dispatch(GoAccidentSiteVm.Action.UpdateState(uiState.value.copy(
showOfflineDialog = false)))
vm.dispatch(GoAccidentSiteVm.Action.UpdateState(uiState.value.copy(showOfflineDialog = false)))
vm.dispatch(GoAccidentSiteVm.Action.UpdateOffline)
})
}

View File

@ -34,7 +34,7 @@ import java.util.Calendar
import java.util.Date
import java.util.Locale
class GoAccidentSiteVm : IServicingVm<GoAccidentSiteVm.Action, GoAccidentSiteVm.UiState>() {
internal class GoAccidentSiteVm : IServicingVm<GoAccidentSiteVm.Action, GoAccidentSiteVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState
override fun updateState(uiState : UiState) {

View File

@ -52,7 +52,7 @@ import com.za.ui.new_order.NewOrderUiType
import com.za.ui.servicing.view.InServicingHeadView
import com.za.ui.servicing.view.ServiceOperation
class GoToDestinationActivity : BaseActivity() {
internal class GoToDestinationActivity : BaseActivity() {
@Composable
override fun ContentView() {
GoToDestinationScreen()
@ -61,7 +61,7 @@ class GoToDestinationActivity : BaseActivity() {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun GoToDestinationScreen(vm : GoToDestinationVm = viewModel()) {
internal fun GoToDestinationScreen(vm : GoToDestinationVm = viewModel()) {
val uiState = vm.uiState.collectAsStateWithLifecycle()
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current

View File

@ -39,7 +39,7 @@ import java.util.Calendar
import java.util.Date
import java.util.Locale
class GoToDestinationVm : IServicingVm<GoToDestinationVm.Action, GoToDestinationVm.UiState>() {
internal class GoToDestinationVm : IServicingVm<GoToDestinationVm.Action, GoToDestinationVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState
override fun updateState(uiState : UiState) {

View File

@ -47,7 +47,7 @@ import com.za.ext.copy
import com.za.servicing.R
@Composable
fun OrderDetailItemScreen(orderInfo : OrderInfo?) {
internal fun OrderDetailItemScreen(orderInfo : OrderInfo?) {
Column(modifier = Modifier
.fillMaxSize()
.verticalScroll(state = rememberScrollState())
@ -433,7 +433,7 @@ private fun OrderDetailServiceInformationView(orderInfo : OrderInfo?) {
}
@Composable
fun OrderDetailTime(orderInfo : OrderInfo?) {
internal fun OrderDetailTime(orderInfo : OrderInfo?) {
val titleSize = 12.sp
val titleColor = Color(0xFF7A7A7A)
val contentColor = Color.Black

View File

@ -44,7 +44,7 @@ import com.za.ui.servicing.order_give_up.OrderGiveUpActivity
import kotlinx.coroutines.launch
@Composable
fun OrderDetailScreen(orderInfo : OrderInfo?) {
internal fun OrderDetailScreen(orderInfo : OrderInfo?) {
val context = LocalContext.current
val titleList = listOf("订单详情", "案件要求")
val pagerState = rememberPagerState(initialPage = 0, pageCount = { titleList.size })

View File

@ -9,9 +9,9 @@ import androidx.compose.ui.graphics.Color
import com.za.bean.db.order.OrderInfo
@Composable
fun OrderEleScreen(orderInfo: OrderInfo?) {
Box(modifier = Modifier.fillMaxSize()) {
Text(text = "电子工单", color = Color.Black)
}
internal fun OrderEleScreen(orderInfo : OrderInfo?) {
Box(modifier = Modifier.fillMaxSize()) {
Text(text = "电子工单", color = Color.Black)
}
}

View File

@ -28,7 +28,7 @@ import com.za.bean.db.order.OrderInfo
import com.za.ext.finish
@Composable
fun OrderOnSitePhotoScreen(orderInfo: OrderInfo?) {
internal fun OrderOnSitePhotoScreen(orderInfo: OrderInfo?) {
val context = LocalContext.current
val showPreviewPhotoDialog = remember { mutableStateOf<String?>("") }
if (!showPreviewPhotoDialog.value.isNullOrBlank()) {

View File

@ -9,7 +9,7 @@ import androidx.compose.ui.graphics.Color
import com.za.bean.db.order.OrderInfo
@Composable
fun OrderPhotoScreen(orderInfo: OrderInfo?) {
internal fun OrderPhotoScreen(orderInfo: OrderInfo?) {
Box(modifier = Modifier.fillMaxSize()) {
Text(text = "案件照片", color = Color.Black)
}

View File

@ -8,7 +8,7 @@ import com.za.base.BaseActivity
import com.za.base.Const
import com.za.bean.db.order.OrderInfo
class OrderRequirementsActivity : BaseActivity() {
internal class OrderRequirementsActivity : BaseActivity() {
@Composable
override fun ContentView() {
val orderInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {

View File

@ -44,7 +44,7 @@ import com.za.servicing.R
import com.za.ui.h5.CommonH5Activity
@Composable
fun OrderRequirementsScreen(orderInfo : OrderInfo?) {
internal fun OrderRequirementsScreen(orderInfo : OrderInfo?) {
Scaffold {
Column(modifier = Modifier
.fillMaxSize()
@ -63,7 +63,7 @@ fun OrderRequirementsScreen(orderInfo : OrderInfo?) {
}
@Composable
fun OrderRequirementsItemView(title : String?, content : String?) {
internal fun OrderRequirementsItemView(title : String?, content : String?) {
Column(modifier = Modifier
.fillMaxWidth()
.padding(vertical = 5.dp)) {

View File

@ -9,7 +9,7 @@ import androidx.compose.ui.graphics.Color
import com.za.bean.db.order.OrderInfo
@Composable
fun OrderSettleScreen(orderInfo: OrderInfo?) {
internal fun OrderSettleScreen(orderInfo: OrderInfo?) {
Box(modifier = Modifier.fillMaxSize()) {
Text(text = "结算单", color = Color.Black)
}

View File

@ -9,8 +9,8 @@ import androidx.compose.ui.graphics.Color
import com.za.bean.db.order.OrderInfo
@Composable
fun OrderTriceScreen(orderInfo: OrderInfo?) {
Box(modifier = Modifier.fillMaxSize()) {
Text(text = "订单轨迹", color = Color.Black)
}
internal fun OrderTriceScreen(orderInfo : OrderInfo?) {
Box(modifier = Modifier.fillMaxSize()) {
Text(text = "订单轨迹", color = Color.Black)
}
}

View File

@ -4,7 +4,7 @@ import androidx.compose.runtime.Composable
import com.za.base.BaseActivity
class ServicePeopleConfirmActivity : BaseActivity() {
internal class ServicePeopleConfirmActivity : BaseActivity() {
@Composable
override fun ContentView() {

View File

@ -23,7 +23,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import java.io.File
class InServicePeopleConfirmVm : IServicingVm<Action, UiState>() {
internal class InServicePeopleConfirmVm : IServicingVm<Action, UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState as StateFlow<UiState>
override fun updateState(uiState : UiState) {

View File

@ -43,7 +43,7 @@ import com.za.servicing.R
import com.za.ui.camera.ServicePeopleRealActivity
@Composable
fun ServicePeopleConfirmScreen(vm : InServicePeopleConfirmVm = viewModel(),
internal fun ServicePeopleConfirmScreen(vm : InServicePeopleConfirmVm = viewModel(),
success : () -> Unit = {},
onBack : () -> Unit) {
val context = LocalContext.current

View File

@ -7,7 +7,7 @@ import com.za.ext.getEleState
import com.za.ui.servicing.ele_check.EleSignCheckScreen
import com.za.ui.servicing.ele_sign.EleSignScreen
class InOperationActivity : BaseActivity() {
internal class InOperationActivity : BaseActivity() {
@Composable
override fun ContentView() {

View File

@ -24,7 +24,7 @@ import com.za.ui.servicing.InServicingPhotoView
import com.za.ui.servicing.view.InServicingHeadView
@Composable
fun InOperationScreen(vm: InOperationVm = viewModel()) {
internal fun InOperationScreen(vm: InOperationVm = viewModel()) {
val uiState = vm.uiState.collectAsStateWithLifecycle()
val context = LocalContext.current

View File

@ -19,7 +19,7 @@ import com.za.offline.OfflineUpdateTaskBean
import com.za.service.location.ZdLocationManager
import kotlinx.coroutines.flow.MutableStateFlow
class InOperationVm : IServicingVm<InOperationVm.Action, InOperationVm.UiState>() {
internal class InOperationVm : IServicingVm<InOperationVm.Action, InOperationVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState
override fun updateState(uiState : UiState) {

View File

@ -33,7 +33,7 @@ import com.za.ext.goStatusPage
import com.za.ui.servicing.InServicingPhotoView
@Composable
fun ChangeBatteryScreen(vm : ChangeBatteryVm = viewModel()) {
internal fun ChangeBatteryScreen(vm : ChangeBatteryVm = viewModel()) {
val uiState = vm.uiState.collectAsStateWithLifecycle()
val context = LocalContext.current
LaunchedEffect(key1 = Unit) {

View File

@ -23,7 +23,7 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.flow.MutableStateFlow
class ChangeBatteryVm : BaseVm<ChangeBatteryVm.Action, ChangeBatteryVm.UiState>() {
internal class ChangeBatteryVm : BaseVm<ChangeBatteryVm.Action, ChangeBatteryVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState

View File

@ -73,7 +73,7 @@ import kotlin.math.ceil
@Preview
@Composable
fun ConfirmEleScreen(vm : ConfirmEleVm = viewModel()) {
internal fun ConfirmEleScreen(vm : ConfirmEleVm = viewModel()) {
val context = LocalContext.current
val uiState = vm.uiState.collectAsStateWithLifecycle()
LaunchedEffect(key1 = Unit) {
@ -414,7 +414,8 @@ fun ConfirmEleScreen(vm : ConfirmEleVm = viewModel()) {
vm.dispatch(ConfirmEleVm.Action.UploadServiceSignature(it))
},
serverPath = uiState.value.eleWorkOrderBean?.localServicePeopleSignPath
?: uiState.value.eleWorkOrderBean?.serverServicePeopleSignPath)
?: uiState.value.eleWorkOrderBean?.serverServicePeopleSignPath
?: GlobalData.driverInfoBean?.signatureUrl)
}
}
}

View File

@ -30,7 +30,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
class ConfirmEleVm : IServicingVm<ConfirmEleVm.Action, ConfirmEleVm.UiState>() {
internal class ConfirmEleVm : IServicingVm<ConfirmEleVm.Action, ConfirmEleVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState
@ -283,7 +283,8 @@ class ConfirmEleVm : IServicingVm<ConfirmEleVm.Action, ConfirmEleVm.UiState>() {
} else null,
hasSuccess = eleWorkOrderBean.isSuccess,
recipientSignPath = eleWorkOrderBean.serverAcceptCarSignPath,
waitstaffSignPath = eleWorkOrderBean.serverServicePeopleSignPath)
waitstaffSignPath = eleWorkOrderBean.serverServicePeopleSignPath
?: GlobalData.driverInfoBean?.signatureUrl)
LoadingManager.showLoading()
RetrofitHelper.getDefaultService().saveElectronOrder(saveEleOrderRequest)
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())

View File

@ -55,7 +55,7 @@ import com.za.signature.GridPaintActivity
import com.za.signature.config.PenConfig
@Composable
fun ConfirmH5SuccessScreen(vm : ConfirmH5SuccessVm = viewModel()) {
internal fun ConfirmH5SuccessScreen(vm : ConfirmH5SuccessVm = viewModel()) {
val uiState = vm.uiState.collectAsStateWithLifecycle()
val context = LocalContext.current
val webView = WebView(context)

View File

@ -26,7 +26,7 @@ import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.flow.MutableStateFlow
import java.io.File
class ConfirmH5SuccessVm : IServicingVm<ConfirmH5SuccessVm.Action, ConfirmH5SuccessVm.UiState>() {
internal class ConfirmH5SuccessVm : IServicingVm<ConfirmH5SuccessVm.Action, ConfirmH5SuccessVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState
override fun updateState(uiState : UiState) {

View File

@ -1,9 +0,0 @@
package com.za.ui.servicing.order_confirm
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@Composable
fun EleSuccessScreen(modifier: Modifier = Modifier) {
}

View File

@ -17,7 +17,7 @@ import com.za.ui.servicing.order_confirm.input_money.InputMoneyActivity
import com.za.ui.servicing.order_confirm.real_order_confirm.RealOrderConfirmActivity
import com.za.ui.servicing.order_confirm.receive_money.ReceiveMoneyActivity
class OrderConfirmActivity : BaseActivity() {
internal class OrderConfirmActivity : BaseActivity() {
@Composable
override fun ContentView() {
@ -26,7 +26,7 @@ class OrderConfirmActivity : BaseActivity() {
}
@Composable
fun OrderConfirmInitScreen(vm : OrderConfirmInitVm = viewModel()) {
internal fun OrderConfirmInitScreen(vm : OrderConfirmInitVm = viewModel()) {
val uiState = vm.uiState.collectAsStateWithLifecycle()
val context = LocalContext.current
LaunchedEffect(key1 = Unit) {

View File

@ -16,7 +16,7 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.flow.MutableStateFlow
class OrderConfirmInitVm : IServicingVm<OrderConfirmInitVm.Action, OrderConfirmInitVm.UiState>() {
internal class OrderConfirmInitVm : IServicingVm<OrderConfirmInitVm.Action, OrderConfirmInitVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState
override fun updateState(uiState : UiState) {

View File

@ -82,7 +82,7 @@ import kotlinx.coroutines.delay
val primaryColor = Color(0xFF3B82F6)
val gradientColors = listOf(Color(0xFF3B82F6), Color(0xFF60A5FA))
class InputMoneyActivity : BaseActivity() {
internal class InputMoneyActivity : BaseActivity() {
@Composable
override fun ContentView() {
InputMoneyScreen(userOrderId = intent.getIntExtra("userOrderId", 0),
@ -101,7 +101,7 @@ class InputMoneyActivity : BaseActivity() {
@Composable
fun InputMoneyScreen(userOrderId : Int, taskId : Int, vm : InputMoneyVm = viewModel()) {
internal fun InputMoneyScreen(userOrderId : Int, taskId : Int, vm : InputMoneyVm = viewModel()) {
val context = LocalContext.current
val uiState = vm.uiState.collectAsStateWithLifecycle()
var showSuccessDialog by remember { mutableStateOf(false) }
@ -414,9 +414,3 @@ private fun SuccessDialog(amount : String, onDismiss : () -> Unit) {
}
}
}
@Preview()
@Composable
fun PreviewInputMoneyScreen() {
InputMoneyScreen(userOrderId = 1, taskId = 1)
}

View File

@ -20,7 +20,7 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
class InputMoneyVm : BaseVm<InputMoneyVm.Action, InputMoneyVm.UiState>() {
internal class InputMoneyVm : BaseVm<InputMoneyVm.Action, InputMoneyVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState.asStateFlow()
private var timerJob: Job? = null

View File

@ -5,7 +5,7 @@ import android.content.Intent
import androidx.compose.runtime.Composable
import com.za.base.BaseActivity
class ModifyMoneyActivity : BaseActivity() {
internal class ModifyMoneyActivity : BaseActivity() {
@Composable
override fun ContentView() {
ModifyMoneyScreen(userOrderId = intent.getIntExtra("userOrderId", 0), taskId = intent.getIntExtra("taskId", 0))

View File

@ -39,7 +39,7 @@ import com.za.ui.servicing.order_confirm.modify_money.ModifyMoneyViewModel
@Composable
fun ModifyMoneyScreen(userOrderId : Int, taskId : Int, vm : ModifyMoneyViewModel = viewModel()) {
internal fun ModifyMoneyScreen(userOrderId : Int, taskId : Int, vm : ModifyMoneyViewModel = viewModel()) {
val uiState = vm.uiState.collectAsStateWithLifecycle()
val context = LocalContext.current

View File

@ -15,7 +15,7 @@ import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
class ModifyMoneyViewModel : BaseVm<Action, UiState>() {
internal class ModifyMoneyViewModel : BaseVm<Action, UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState.asStateFlow()

View File

@ -50,7 +50,7 @@ import com.za.ui.servicing.InServicingPhotoWithoutTitleView
import com.za.ui.servicing.view.InServicingHeadView
@Composable
fun OrderConfirmScreen(vm : OrderConfirmVm = viewModel()) {
internal fun OrderConfirmScreen(vm : OrderConfirmVm = viewModel()) {
val context = LocalContext.current
val uiState = vm.uiState.collectAsStateWithLifecycle()
LaunchedEffect(key1 = Unit) {
@ -113,7 +113,7 @@ fun OrderConfirmScreen(vm : OrderConfirmVm = viewModel()) {
}
@Composable
fun BaseFeeView(flowType : Int,
internal fun BaseFeeView(flowType : Int,
startPrice : Int?,
unitPrice : Int?,
overKm : Int?,
@ -173,7 +173,7 @@ fun BaseFeeView(flowType : Int,
}
@Composable
fun AuxiliaryFeeView(dilemmaFee : Int?,
internal fun AuxiliaryFeeView(dilemmaFee : Int?,
basementFee : Int?,
abroadFee : Int?,
bcRoadFee : Int?,

View File

@ -22,7 +22,7 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.flow.MutableStateFlow
class OrderConfirmVm : IServicingVm<OrderConfirmVm.Action, OrderConfirmVm.UiState>() {
internal class OrderConfirmVm : IServicingVm<OrderConfirmVm.Action, OrderConfirmVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState
override fun updateState(uiState : UiState) {
@ -75,7 +75,7 @@ class OrderConfirmVm : IServicingVm<OrderConfirmVm.Action, OrderConfirmVm.UiStat
return
}
uiState.value.photoTemplateList?.forEach {
photoTemplateList?.forEach {
if (it.photoType == 2) {
return@forEach
}

View File

@ -6,7 +6,7 @@ import androidx.compose.runtime.Composable
import com.za.base.BaseActivity
import com.za.ext.finish
class RealOrderConfirmActivity : BaseActivity() {
internal class RealOrderConfirmActivity : BaseActivity() {
@Composable
override fun ContentView() {
OrderConfirmScreen()

View File

@ -6,7 +6,7 @@ import androidx.compose.runtime.Composable
import com.za.base.BaseActivity
import com.za.ext.finish
class ReceiveMoneyActivity : BaseActivity() {
internal class ReceiveMoneyActivity : BaseActivity() {
@Composable
override fun ContentView() {

View File

@ -90,392 +90,348 @@ val backgroundColor = Color(0xFFF8FAFC)
@Preview(showBackground = true)
@Composable
fun PreviewReceiveMoneyScreen() {
ReceiveMoneyScreen(userOrderId = 1, taskId = 1)
ReceiveMoneyScreen(userOrderId = 1, taskId = 1)
}
@Composable
fun ReceiveMoneyScreen(userOrderId: Int,
taskId: Int,
vm: ReceiveMoneyVm = viewModel()) {
val context = LocalContext.current
val uiState = vm.uiState.collectAsStateWithLifecycle()
var showSuccessDialog by remember { mutableStateOf(false) }
internal fun ReceiveMoneyScreen(userOrderId : Int,
taskId : Int,
vm : ReceiveMoneyVm = viewModel()) {
val context = LocalContext.current
val uiState = vm.uiState.collectAsStateWithLifecycle()
var showSuccessDialog by remember { mutableStateOf(false) }
val lifecycleOwner = LocalLifecycleOwner.current
DisposableEffect(key1 = lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_RESUME) {
vm.dispatch(action = ReceiveMoneyVm.Action.Init(userOrderId, taskId))
}
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose {
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
val lifecycleOwner = LocalLifecycleOwner.current
DisposableEffect(key1 = lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_RESUME) {
vm.dispatch(action = ReceiveMoneyVm.Action.Init(userOrderId, taskId))
}
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose {
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
if (showSuccessDialog) {
SuccessDialog(
amount = "${uiState.value.paymentInfoBean?.amount ?: 0.00}",
onDismiss = { showSuccessDialog = false }
)
}
if (showSuccessDialog) {
SuccessDialog(amount = "${uiState.value.paymentInfoBean?.amount ?: 0.00}",
onDismiss = { showSuccessDialog = false })
}
if (uiState.value.payState == 3) {
CommonDialog(title = "收款成功", message = "收款成功", cancelEnable = false,
confirm = {
goNextPage(GlobalData.currentOrder?.taskState, context)
}, dismiss = {
goNextPage(GlobalData.currentOrder?.taskState, context)
})
}
if (uiState.value.payState == 3) {
CommonDialog(title = "收款成功", message = "收款成功", cancelEnable = false, confirm = {
goNextPage(GlobalData.currentOrder?.taskState, context)
}, dismiss = {
goNextPage(GlobalData.currentOrder?.taskState, context)
})
}
Scaffold(
topBar = { HeadView(title = "客户收款", onBack = { context.finish() }) },
bottomBar = {
AnimatedVisibility(visible = uiState.value.isOnSite == 2) {
Column {
Spacer(modifier = Modifier.height(32.dp))
AnimatedVisibility(visible = uiState.value.payState != 1) {
CommonButton("发送短信链接") {
if (uiState.value.userPhone.isNullOrEmpty()) {
ToastUtils.showLong("请输入客户手机号")
return@CommonButton
}
vm.dispatch(ReceiveMoneyVm.Action.CreatePaymentInfo)
}
}
}
}
}, containerColor = bgColor) {
// Main Content
Column(modifier = Modifier
Scaffold(topBar = { HeadView(title = "客户收款", onBack = { context.finish() }) }, bottomBar = {
AnimatedVisibility(visible = uiState.value.isOnSite == 2) {
Column {
Spacer(modifier = Modifier.height(32.dp))
AnimatedVisibility(visible = uiState.value.payState != 1) {
CommonButton("发送短信链接") {
if (uiState.value.userPhone.isNullOrEmpty()) {
ToastUtils.showLong("请输入客户手机号")
return@CommonButton
}
vm.dispatch(ReceiveMoneyVm.Action.CreatePaymentInfo)
}
}
}
}
}, containerColor = bgColor) { // Main Content
Column(modifier = Modifier
.fillMaxSize()
.padding(it)
.verticalScroll(rememberScrollState())
.padding(10.dp)) {
// Amount Section
AmountSection(paymentInfoBean = uiState.value.paymentInfoBean) {
// ModifyMoneyActivity.goModifyMoney(context, uiState.value.paymentInfoBean?.userOrderId
// ?: 0, uiState.value.paymentInfoBean?.taskOrderId ?: 0)
ModifyMoneyActivity.goModifyMoney(context, uiState.value.paymentInfoBean?.userOrderId
?: 0, uiState.value.paymentInfoBean?.taskOrderId ?: 0)
}
.padding(10.dp)) { // Amount Section
AmountSection(paymentInfoBean = uiState.value.paymentInfoBean) { // ModifyMoneyActivity.goModifyMoney(context, uiState.value.paymentInfoBean?.userOrderId
// ?: 0, uiState.value.paymentInfoBean?.taskOrderId ?: 0)
ModifyMoneyActivity.goModifyMoney(context,
uiState.value.paymentInfoBean?.userOrderId ?: 0,
uiState.value.paymentInfoBean?.taskOrderId ?: 0)
}
Spacer(modifier = Modifier.height(32.dp))
Spacer(modifier = Modifier.height(32.dp))
if (!uiState.value.paymentInfoBean?.settlementRule.isNullOrBlank()) {
// Rules Section
RulesSection(uiState.value.paymentInfoBean?.settlementRule ?: "")
Spacer(modifier = Modifier.height(32.dp))
}
if (! uiState.value.paymentInfoBean?.settlementRule.isNullOrBlank()) { // Rules Section
RulesSection(uiState.value.paymentInfoBean?.settlementRule ?: "")
Spacer(modifier = Modifier.height(32.dp))
}
// Action Buttons
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(16.dp)
) {
Row(
modifier = if (uiState.value.isOnSite == 1) {
Modifier
.weight(1f)
.background(color = primaryColor, shape = RoundedCornerShape(3.dp))
.padding(vertical = 15.dp)
} else {
Modifier
.weight(1f)
.noDoubleClick {
vm.dispatch(ReceiveMoneyVm.Action.ChangeOnSite(1))
}
.border(1.dp, color = Color.Gray, shape = RoundedCornerShape(3.dp))
.padding(vertical = 15.dp)
},
horizontalArrangement = Arrangement.Center
) {
if (uiState.value.isOnSite == 1) {
Icon(imageVector = Icons.Default.LocationOn, contentDescription = null, tint = Color.White)
Text(text = "在现场", color = Color.White)
} else {
Icon(imageVector = Icons.Default.LocationOn, contentDescription = null, tint = Color.Gray)
Text(text = "在现场", color = Color.Gray)
}
}
// Action Buttons
Row(modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(16.dp)) {
Row(modifier = if (uiState.value.isOnSite == 1) {
Modifier
.weight(1f)
.background(color = primaryColor, shape = RoundedCornerShape(3.dp))
.padding(vertical = 15.dp)
} else {
Modifier
.weight(1f)
.noDoubleClick {
vm.dispatch(ReceiveMoneyVm.Action.ChangeOnSite(1))
}
.border(1.dp, color = Color.Gray, shape = RoundedCornerShape(3.dp))
.padding(vertical = 15.dp)
}, horizontalArrangement = Arrangement.Center) {
if (uiState.value.isOnSite == 1) {
Icon(imageVector = Icons.Default.LocationOn,
contentDescription = null,
tint = Color.White)
Text(text = "在现场", color = Color.White)
} else {
Icon(imageVector = Icons.Default.LocationOn,
contentDescription = null,
tint = Color.Gray)
Text(text = "在现场", color = Color.Gray)
}
}
Row(
modifier = if (uiState.value.isOnSite == 2) {
Modifier
.weight(1f)
.background(color = primaryColor, shape = RoundedCornerShape(3.dp))
.padding(vertical = 15.dp)
} else {
Modifier
.weight(1f)
.noDoubleClick {
vm.dispatch(ReceiveMoneyVm.Action.ChangeOnSite(2))
}
.border(1.dp, color = Color.Gray, shape = RoundedCornerShape(3.dp))
.padding(vertical = 15.dp)
},
horizontalArrangement = Arrangement.Center
) {
if (uiState.value.isOnSite == 2) {
Icon(imageVector = Icons.Default.Notifications, contentDescription = null, tint = Color.White)
Text(text = "不在现场", color = Color.White)
} else {
Icon(imageVector = Icons.Default.Notifications, contentDescription = null, tint = Color.Gray)
Text(text = "不在现场", color = Color.Gray)
}
}
}
Row(modifier = if (uiState.value.isOnSite == 2) {
Modifier
.weight(1f)
.background(color = primaryColor, shape = RoundedCornerShape(3.dp))
.padding(vertical = 15.dp)
} else {
Modifier
.weight(1f)
.noDoubleClick {
vm.dispatch(ReceiveMoneyVm.Action.ChangeOnSite(2))
}
.border(1.dp, color = Color.Gray, shape = RoundedCornerShape(3.dp))
.padding(vertical = 15.dp)
}, horizontalArrangement = Arrangement.Center) {
if (uiState.value.isOnSite == 2) {
Icon(imageVector = Icons.Default.Notifications,
contentDescription = null,
tint = Color.White)
Text(text = "不在现场", color = Color.White)
} else {
Icon(imageVector = Icons.Default.Notifications,
contentDescription = null,
tint = Color.Gray)
Text(text = "不在现场", color = Color.Gray)
}
}
}
AnimatedVisibility(visible = uiState.value.isOnSite == 1) {
Column {
Spacer(modifier = Modifier.height(22.dp))
QRCodeSection(uiState.value.qrCode ?: "",
createPayment = { vm.dispatch(ReceiveMoneyVm.Action.CreatePaymentInfo) })
}
}
AnimatedVisibility(visible = uiState.value.isOnSite == 1) {
Column {
Spacer(modifier = Modifier.height(22.dp))
QRCodeSection(uiState.value.qrCode ?: "",
createPayment = { vm.dispatch(ReceiveMoneyVm.Action.CreatePaymentInfo) })
}
}
AnimatedVisibility(visible = uiState.value.isOnSite == 2) {
Box(modifier = Modifier
AnimatedVisibility(visible = uiState.value.isOnSite == 2) {
Box(modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 10.dp, vertical = 30.dp)) {
OutlinedTextField(
value = uiState.value.userPhone ?: "",
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Phone),
onValueChange = { vm.updateState(uiState.value.copy(userPhone = it)) },
label = { Text("请输入客户手机号") },
leadingIcon = {
Icon(
imageVector = Icons.Rounded.Phone,
contentDescription = null,
tint = primaryColor
)
},
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(12.dp),
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = primaryColor,
unfocusedBorderColor = Color.Gray,
focusedLabelColor = primaryColor,
unfocusedLabelColor = Color.Gray),
singleLine = true
)
}
}
OutlinedTextField(value = uiState.value.userPhone ?: "",
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Phone),
onValueChange = { vm.updateState(uiState.value.copy(userPhone = it)) },
label = { Text("请输入客户手机号") },
leadingIcon = {
Icon(imageVector = Icons.Rounded.Phone,
contentDescription = null,
tint = primaryColor)
},
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(12.dp),
colors = OutlinedTextFieldDefaults.colors(focusedBorderColor = primaryColor,
unfocusedBorderColor = Color.Gray,
focusedLabelColor = primaryColor,
unfocusedLabelColor = Color.Gray),
singleLine = true)
}
}
if (uiState.value.payState == 1) {
Column {
Spacer(modifier = Modifier.height(32.dp))
CountdownRing { vm.updateState(uiState.value.copy(payState = 4, qrCode = null)) }
}
}
}
}
if (uiState.value.payState == 1) {
Column {
Spacer(modifier = Modifier.height(32.dp))
CountdownRing {
vm.updateState(uiState.value.copy(payState = 4,
qrCode = null))
}
}
}
}
}
}
@Composable
private fun AmountSection(paymentInfoBean: PaymentInfoBean? = null, goModifyMoney: () -> Unit = {}) {
Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth()) {
Text("收款金额", color = Color.Gray, fontSize = 14.sp)
Spacer(modifier = Modifier.height(8.dp))
Row(verticalAlignment = Alignment.CenterVertically) {
Text("", fontSize = 30.sp, fontWeight = FontWeight.Medium, color = black90)
Text("${paymentInfoBean?.amount ?: "0.00"}", fontSize = 36.sp, fontWeight = FontWeight.Medium, color = black90)
//一口价不允许修改金额
if (paymentInfoBean?.contractSettleRule != 2) {
IconButton(onClick = { goModifyMoney() }) {
Icon(
painter = rememberVectorPainter(Icons.Default.Edit),
contentDescription = null,
tint = primaryColor
)
}
}
}
private fun AmountSection(paymentInfoBean : PaymentInfoBean? = null,
goModifyMoney : () -> Unit = {}) {
Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth()) {
Text("收款金额", color = Color.Gray, fontSize = 14.sp)
Spacer(modifier = Modifier.height(8.dp))
Row(verticalAlignment = Alignment.CenterVertically) {
Text("", fontSize = 30.sp, fontWeight = FontWeight.Medium, color = black90)
Text("${paymentInfoBean?.amount ?: "0.00"}",
fontSize = 36.sp,
fontWeight = FontWeight.Medium,
color = black90) //一口价不允许修改金额
if (paymentInfoBean?.contractSettleRule != 2) {
IconButton(onClick = { goModifyMoney() }) {
Icon(painter = rememberVectorPainter(Icons.Default.Edit),
contentDescription = null,
tint = primaryColor)
}
}
}
Spacer(modifier = Modifier.height(16.dp))
Spacer(modifier = Modifier.height(16.dp))
Row(
horizontalArrangement = Arrangement.spacedBy(32.dp),
verticalAlignment = Alignment.CenterVertically
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text("超限单价", color = Color.Gray, fontSize = 14.sp)
Row(verticalAlignment = Alignment.Top) {
Text("", fontSize = 16.sp, color = Color.DarkGray)
Text("${paymentInfoBean?.unitPrice ?: ""}", fontSize = 16.sp, color = Color.DarkGray)
Text("/公里", fontSize = 12.sp, color = Color.Gray)
}
}
Row(horizontalArrangement = Arrangement.spacedBy(32.dp),
verticalAlignment = Alignment.CenterVertically) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text("超限单价", color = Color.Gray, fontSize = 14.sp)
Row(verticalAlignment = Alignment.Top) {
Text("", fontSize = 16.sp, color = Color.DarkGray)
Text("${paymentInfoBean?.unitPrice ?: ""}",
fontSize = 16.sp,
color = Color.DarkGray)
Text("/公里", fontSize = 12.sp, color = Color.Gray)
}
}
VerticalDivider(
modifier = Modifier
.height(32.dp)
.width(1.dp),
color = Color.LightGray
)
VerticalDivider(modifier = Modifier
.height(32.dp)
.width(1.dp), color = Color.LightGray)
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text("超限公里数", color = Color.Gray, fontSize = 14.sp)
Row(verticalAlignment = Alignment.Top) {
Text("${paymentInfoBean?.mileage ?: ""}", fontSize = 16.sp, color = Color.DarkGray)
Text("公里", fontSize = 12.sp, color = Color.Gray)
}
}
}
}
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text("超限公里数", color = Color.Gray, fontSize = 14.sp)
Row(verticalAlignment = Alignment.Top) {
Text("${paymentInfoBean?.mileage ?: ""}",
fontSize = 16.sp,
color = Color.DarkGray)
Text("公里", fontSize = 12.sp, color = Color.Gray)
}
}
}
}
}
@Composable
private fun RulesSection(rules: String) {
Surface(modifier = Modifier.fillMaxWidth(),
color = backgroundColor,
shape = RoundedCornerShape(8.dp)) {
Column(modifier = Modifier.padding(16.dp)) {
Text("收款规则说明", fontWeight = FontWeight.Medium, fontSize = 12.sp, color = Color.Gray)
Spacer(modifier = Modifier.height(10.dp))
RuleItem(rules)
Spacer(modifier = Modifier.height(10.dp))
}
}
private fun RulesSection(rules : String) {
Surface(modifier = Modifier.fillMaxWidth(),
color = backgroundColor,
shape = RoundedCornerShape(8.dp)) {
Column(modifier = Modifier.padding(16.dp)) {
Text("收款规则说明",
fontWeight = FontWeight.Medium,
fontSize = 12.sp,
color = Color.Gray)
Spacer(modifier = Modifier.height(10.dp))
RuleItem(rules)
Spacer(modifier = Modifier.height(10.dp))
}
}
}
@Composable
private fun RuleItem(text: String) {
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center) {
Icon(
painter = rememberVectorPainter(Icons.Default.CheckCircle),
contentDescription = null,
tint = primaryColor,
modifier = Modifier.size(12.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Text(text, fontSize = 14.sp, color = Color.DarkGray)
}
private fun RuleItem(text : String) {
Row(verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center) {
Icon(painter = rememberVectorPainter(Icons.Default.CheckCircle),
contentDescription = null,
tint = primaryColor,
modifier = Modifier.size(12.dp))
Spacer(modifier = Modifier.width(8.dp))
Text(text, fontSize = 14.sp, color = Color.DarkGray)
}
}
@Composable
private fun QRCodeSection(qrCode: String? = null, createPayment: () -> Unit = {}) {
Surface(
color = backgroundColor,
shape = RoundedCornerShape(8.dp)
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
private fun QRCodeSection(qrCode : String? = null, createPayment : () -> Unit = {}) {
Surface(color = backgroundColor, shape = RoundedCornerShape(8.dp)) {
Column(modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally) {
if (qrCode.isNullOrEmpty()) {
LoadError(message = "收款码失效", onRetry = { createPayment() })
} else {
Surface(
color = Color.White,
shape = RoundedCornerShape(8.dp)
) {
Box(
modifier = Modifier
.size(160.dp)
.padding(16.dp),
contentAlignment = Alignment.Center
) {
// Replace with actual QR code image
AsyncImage(model = qrCode, contentDescription = null)
}
}
Spacer(modifier = Modifier.height(8.dp))
Text("请顾客扫码支付", color = Color.Gray, fontSize = 14.sp)
}
}
}
if (qrCode.isNullOrEmpty()) {
LoadError(message = "收款码失效", onRetry = { createPayment() })
} else {
Surface(color = Color.White, shape = RoundedCornerShape(8.dp)) {
Box(modifier = Modifier
.size(160.dp)
.padding(16.dp),
contentAlignment = Alignment.Center) { // Replace with actual QR code image
AsyncImage(model = qrCode, contentDescription = null)
}
}
Spacer(modifier = Modifier.height(8.dp))
Text("请顾客扫码支付", color = Color.Gray, fontSize = 14.sp)
}
}
}
}
@Composable
private fun CountdownRing(outTime: () -> Unit) {
var countdown by remember { mutableIntStateOf(5 * 60) }
val progress by animateFloatAsState(
targetValue = (countdown / 5 * 60) * 360f,
animationSpec = remember { androidx.compose.animation.core.tween(1000) }
)
private fun CountdownRing(outTime : () -> Unit) {
var countdown by remember { mutableIntStateOf(5 * 60) }
val progress by animateFloatAsState(targetValue = (countdown / 5 * 60) * 360f,
animationSpec = remember { androidx.compose.animation.core.tween(1000) })
LaunchedEffect(Unit) {
while (countdown > 0) {
delay(1000)
countdown--
if (countdown == 0) {
outTime()
}
}
}
LaunchedEffect(Unit) {
while (countdown > 0) {
delay(1000)
countdown --
if (countdown == 0) {
outTime()
}
}
}
Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
Box(modifier = Modifier.size(50.dp), contentAlignment = Alignment.Center) {
Canvas(modifier = Modifier.fillMaxSize()) {
drawArc(
brush = Brush.sweepGradient(
0f to primaryColor,
1f to Color.LightGray
),
startAngle = -90f,
sweepAngle = progress,
useCenter = false,
style = Stroke(width = 8.dp.toPx(), cap = StrokeCap.Round)
)
}
Surface(
color = Color.White,
shape = CircleShape,
modifier = Modifier.size(50.dp)
) {}
Text(
text = countdown.toString(),
fontSize = 20.sp,
color = black90,
fontWeight = FontWeight.Medium
)
}
}
Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
Box(modifier = Modifier.size(50.dp), contentAlignment = Alignment.Center) {
Canvas(modifier = Modifier.fillMaxSize()) {
drawArc(brush = Brush.sweepGradient(0f to primaryColor, 1f to Color.LightGray),
startAngle = - 90f,
sweepAngle = progress,
useCenter = false,
style = Stroke(width = 8.dp.toPx(), cap = StrokeCap.Round))
}
Surface(color = Color.White, shape = CircleShape, modifier = Modifier.size(50.dp)) {}
Text(text = countdown.toString(),
fontSize = 20.sp,
color = black90,
fontWeight = FontWeight.Medium)
}
}
}
@Composable
private fun SuccessDialog(amount: String, onDismiss: () -> Unit) {
Dialog(onDismissRequest = onDismiss) {
Surface(
shape = RoundedCornerShape(16.dp),
color = Color.White
) {
Column(
modifier = Modifier.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Box(
modifier = Modifier
.size(64.dp)
.background(primaryColor.copy(alpha = 0.1f), CircleShape)
.clip(CircleShape),
contentAlignment = Alignment.Center
) {
Icon(
Icons.Default.Check,
contentDescription = null,
tint = primaryColor,
modifier = Modifier.size(32.dp)
)
}
Spacer(modifier = Modifier.height(16.dp))
Text("收款成功", fontWeight = FontWeight.Medium, fontSize = 18.sp)
Text("已收款 ¥$amount", color = Color.Gray, fontSize = 14.sp)
Spacer(modifier = Modifier.height(16.dp))
Button(
onClick = onDismiss,
modifier = Modifier.fillMaxWidth()
) {
Text("完成")
}
}
}
}
private fun SuccessDialog(amount : String, onDismiss : () -> Unit) {
Dialog(onDismissRequest = onDismiss) {
Surface(shape = RoundedCornerShape(16.dp), color = Color.White) {
Column(modifier = Modifier.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally) {
Box(modifier = Modifier
.size(64.dp)
.background(primaryColor.copy(alpha = 0.1f), CircleShape)
.clip(CircleShape),
contentAlignment = Alignment.Center) {
Icon(Icons.Default.Check,
contentDescription = null,
tint = primaryColor,
modifier = Modifier.size(32.dp))
}
Spacer(modifier = Modifier.height(16.dp))
Text("收款成功", fontWeight = FontWeight.Medium, fontSize = 18.sp)
Text("已收款 ¥$amount", color = Color.Gray, fontSize = 14.sp)
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = onDismiss, modifier = Modifier.fillMaxWidth()) {
Text("完成")
}
}
}
}
}

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