Compare commits

...

62 Commits

Author SHA1 Message Date
mxy6664
fafefa3c38 删除无用吐司 2026-08-07 08:09:11 +08:00
mxy6664
a05cebae3f wifi选择弹窗修改 2026-08-03 16:01:53 +08:00
mxy6664
638233279f wifi选择按钮优化 2026-07-30 15:47:58 +08:00
mxy6664
8b413c5a0c 修改中英文 2026-07-30 11:15:03 +08:00
mxy6664
d79f43e2c9 标题改为“驱离设置” 2026-07-30 09:37:19 +08:00
mxy6664
8e237bd24a 修改按钮高度不生效原因 2026-07-28 10:45:27 +08:00
mxy6664
9f31f12463 修改按钮圆角值,和颜色差 2026-07-28 10:35:44 +08:00
mxy6664
55cf7196a6 app所有名称改为:驭鲲智防系统 2026-07-28 09:49:15 +08:00
mxy6664
fb99e7ecf4 1、app所有名称改为:驭鲲智防系统
2、“打击”字样全部改为“驱离”
3、logo的整体只保留文字部分
4.修改吐司中英文显示
2026-07-27 18:01:53 +08:00
f154f30e2d 优化布局样式,修改text的展示错误显示 2026-07-21 17:46:48 +08:00
7114e36165 初始化 2026-07-21 10:22:18 +08:00
195fb73620 优化res加密 2026-07-18 17:24:37 +08:00
655279a8a1 个人碎片和消息记录LoadingDialog 2026-07-17 15:35:36 +08:00
46385d5358 res加密 2026-07-15 15:26:00 +08:00
ab0dd2fbf6 修改告警记录 2026-07-14 17:35:34 +08:00
a9a69ca31b 自定义下拉刷新控件 2026-07-10 17:14:55 +08:00
1d54d6aa2a logd加载动画优化 2026-07-10 10:42:28 +08:00
200086301a 优化布局,删除不需要的view背景 2026-07-09 14:14:59 +08:00
0d0838d0e1 注销确定弹窗显示 2026-07-07 16:19:21 +08:00
a132cdfd27 注销按钮优化 2026-07-07 15:31:09 +08:00
96c8cca033 个人碎片页面的注销账号和设置页面 2026-07-07 09:15:33 +08:00
07f634ae05 直播流开始和停止 2026-07-03 17:58:51 +08:00
4819dbce86 云台控制攻击 2026-07-03 11:30:41 +08:00
6942abca3b 云台控制 2026-07-01 17:59:23 +08:00
02fc928f20 统一验证码按钮的效果 2026-06-30 14:23:47 +08:00
b67de551ba 资源 2026-06-30 11:44:46 +08:00
e28e167085 修改登录页面发送验证码按钮动态效果 2026-06-30 11:44:19 +08:00
8cd802a826 优化首页背景图和返回按钮虚化问题 2026-06-29 17:15:52 +08:00
7e14dd379a 修改添加设备返回页面,通知刷新首页列表,优化首页列表边距 2026-06-29 16:12:33 +08:00
4a584fa7d7 优化设置页面到操作密码传值 2026-06-29 15:20:47 +08:00
a32c165424 优化设置页面到水枪设置的操作密码传值,关闭lint这个检查 2026-06-29 11:09:23 +08:00
9177c00a3c 修改app名字 2026-06-29 09:40:46 +08:00
e937ce207c 401跳转登录界面 2026-06-26 11:48:26 +08:00
4462ba5ba2 个人碎片优化 2026-06-25 10:43:51 +08:00
0672d762c9 生成推荐吗底部按钮优化 2026-06-24 10:45:00 +08:00
efbba44250 时间戳 2026-06-23 14:08:36 +08:00
ef4dfb0307 获取邀请人信息和扫一扫加入xxx家庭 2026-06-22 16:50:18 +08:00
086f1226a1 优化推荐吗页面按钮 2026-06-21 09:12:33 +08:00
5cf30411c1 优化某某某家庭页面 2026-06-20 16:27:19 +08:00
76e4949dd7 移除页面无用功能 2026-06-20 16:22:07 +08:00
4a16010bd6 某某某家庭 2026-06-20 16:19:59 +08:00
b55d9a4b38 修改全局按钮背景阴影,生成二维码和撤销接口调用 2026-06-20 16:11:09 +08:00
6a1cfaeda9 修改按钮 2026-06-20 15:03:29 +08:00
f57975ef1e 修改base_url地址,斌一起当前版本适配 2026-06-19 08:40:56 +08:00
548d501a44 列表网络错误显示 2026-06-18 09:02:21 +08:00
a997190480 优化列表图片展示 2026-06-16 15:59:11 +08:00
631f9831c3 优化列表请求失败和没有网络的显示状态,优化渐变颜色展示 2026-06-16 15:40:20 +08:00
b2c3ed9015 退出登录 2026-06-15 16:02:24 +08:00
6bd31327db 优化家庭状态 2026-06-15 14:06:13 +08:00
7e362038b3 优化列表 2026-06-15 10:19:42 +08:00
d30c025874 注释解释 2026-06-12 17:20:31 +08:00
78d2d2cd79 下载视频 2026-06-11 15:25:06 +08:00
9eb47345fe 修改包名 2026-06-11 14:25:09 +08:00
57188d27cc 视频下载功能 2026-06-11 11:53:52 +08:00
e40403f7db 视频删除功能 2026-06-11 09:45:31 +08:00
09fdb75644 全屏直播自定义功能按钮 2026-06-10 16:01:24 +08:00
0f07736d1e 全屏视频自定义 2026-06-10 11:20:35 +08:00
e7331f64f4 扫一扫打开相册 2026-06-09 16:43:24 +08:00
98e7d57c7d 启动页修改 2026-06-09 08:45:23 +08:00
3c8ac29398 全局图标优化2 2026-06-08 17:23:25 +08:00
5f945fe6e3 全局图标优化 2026-06-08 17:07:44 +08:00
11ab4e244d 登录注册图标优化 2026-06-08 11:58:40 +08:00
505 changed files with 5878 additions and 2132 deletions

View File

@@ -3,6 +3,17 @@
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2026-06-22T08:46:41.014465400Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=80bece4" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState>
<SelectionState runConfigName="AlarmLogActivity">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2026-05-18T09:18:19.023586Z">
<Target type="DEFAULT_BOOT">

View File

@@ -0,0 +1,48 @@
kotlin version: 2.2.10
error message: java.nio.file.AccessDeniedException: C:\Users\Administrator\AppData\Local\kotlin\daemon\kotlin-daemon-client-tsmarker7700090853507788345.tmp
error message: Daemon compilation failed: Could not connect to Kotlin compile daemon
java.lang.RuntimeException: Could not connect to Kotlin compile daemon
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:214)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74)
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:64)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:61)
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:102)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:61)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:58)
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
at org.gradle.internal.Factories$1.create(Factories.java:30)
at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$withLocksAcquired$0(DefaultWorkerLeaseService.java:269)
at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:42)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:267)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:259)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)

View File

@@ -0,0 +1,48 @@
kotlin version: 2.2.10
error message: java.nio.file.AccessDeniedException: C:\Users\Administrator\AppData\Local\kotlin\daemon\kotlin-daemon-client-tsmarker12680940025563006602.tmp
error message: Daemon compilation failed: Could not connect to Kotlin compile daemon
java.lang.RuntimeException: Could not connect to Kotlin compile daemon
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:214)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74)
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:64)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:61)
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:102)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:61)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:58)
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
at org.gradle.internal.Factories$1.create(Factories.java:30)
at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$withLocksAcquired$0(DefaultWorkerLeaseService.java:269)
at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:42)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:267)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:259)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)

View File

@@ -0,0 +1,48 @@
kotlin version: 2.2.10
error message: java.nio.file.AccessDeniedException: C:\Users\Administrator\AppData\Local\kotlin\daemon\kotlin-daemon-client-tsmarker3894271637508823813.tmp
error message: Daemon compilation failed: Could not connect to Kotlin compile daemon
java.lang.RuntimeException: Could not connect to Kotlin compile daemon
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:214)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74)
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:64)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:61)
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:102)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:61)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:58)
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
at org.gradle.internal.Factories$1.create(Factories.java:30)
at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$withLocksAcquired$0(DefaultWorkerLeaseService.java:269)
at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:42)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:267)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:259)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)

View File

@@ -0,0 +1,48 @@
kotlin version: 2.2.10
error message: java.nio.file.AccessDeniedException: C:\Users\Administrator\AppData\Local\kotlin\daemon\kotlin-daemon-client-tsmarker16051875768763165132.tmp
error message: Daemon compilation failed: Could not connect to Kotlin compile daemon
java.lang.RuntimeException: Could not connect to Kotlin compile daemon
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:214)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74)
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:64)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:61)
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:102)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:61)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:58)
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
at org.gradle.internal.Factories$1.create(Factories.java:30)
at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$withLocksAcquired$0(DefaultWorkerLeaseService.java:269)
at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:42)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:267)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:259)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)

View File

@@ -0,0 +1,48 @@
kotlin version: 2.2.10
error message: java.nio.file.AccessDeniedException: C:\Users\Administrator\AppData\Local\kotlin\daemon\kotlin-daemon-client-tsmarker3580585840179793220.tmp
error message: Daemon compilation failed: Could not connect to Kotlin compile daemon
java.lang.RuntimeException: Could not connect to Kotlin compile daemon
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:214)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74)
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:64)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:61)
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:102)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:61)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:58)
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
at org.gradle.internal.Factories$1.create(Factories.java:30)
at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$withLocksAcquired$0(DefaultWorkerLeaseService.java:269)
at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:42)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:267)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:259)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)

View File

@@ -0,0 +1,48 @@
kotlin version: 2.2.10
error message: java.nio.file.AccessDeniedException: C:\Users\Administrator\AppData\Local\kotlin\daemon\kotlin-daemon-client-tsmarker11763075351170172587.tmp
error message: Daemon compilation failed: Could not connect to Kotlin compile daemon
java.lang.RuntimeException: Could not connect to Kotlin compile daemon
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:214)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74)
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:64)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:61)
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:102)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:61)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:58)
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
at org.gradle.internal.Factories$1.create(Factories.java:30)
at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$withLocksAcquired$0(DefaultWorkerLeaseService.java:269)
at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:42)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:267)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:259)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)

View File

@@ -0,0 +1,48 @@
kotlin version: 2.2.10
error message: java.nio.file.AccessDeniedException: C:\Users\Administrator\AppData\Local\kotlin\daemon\kotlin-daemon-client-tsmarker3368904538941318214.tmp
error message: Daemon compilation failed: Could not connect to Kotlin compile daemon
java.lang.RuntimeException: Could not connect to Kotlin compile daemon
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:214)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74)
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:64)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:61)
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:102)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:61)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:58)
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
at org.gradle.internal.Factories$1.create(Factories.java:30)
at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$withLocksAcquired$0(DefaultWorkerLeaseService.java:269)
at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:42)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:267)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:259)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)

View File

@@ -0,0 +1,48 @@
kotlin version: 2.2.10
error message: java.nio.file.AccessDeniedException: C:\Users\Administrator\AppData\Local\kotlin\daemon\kotlin-daemon-client-tsmarker2940944726750836786.tmp
error message: Daemon compilation failed: Could not connect to Kotlin compile daemon
java.lang.RuntimeException: Could not connect to Kotlin compile daemon
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:214)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74)
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:64)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:61)
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:102)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:61)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:58)
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
at org.gradle.internal.Factories$1.create(Factories.java:30)
at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$withLocksAcquired$0(DefaultWorkerLeaseService.java:269)
at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:42)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:267)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:259)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)

View File

@@ -0,0 +1,48 @@
kotlin version: 2.2.10
error message: java.nio.file.AccessDeniedException: C:\Users\Administrator\AppData\Local\kotlin\daemon\kotlin-daemon-client-tsmarker13384034999995465012.tmp
error message: Daemon compilation failed: Could not connect to Kotlin compile daemon
java.lang.RuntimeException: Could not connect to Kotlin compile daemon
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:214)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74)
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:64)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:61)
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:102)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:61)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:58)
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
at org.gradle.internal.Factories$1.create(Factories.java:30)
at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$withLocksAcquired$0(DefaultWorkerLeaseService.java:269)
at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:42)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:267)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:259)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)

View File

@@ -0,0 +1,48 @@
kotlin version: 2.2.10
error message: java.nio.file.AccessDeniedException: C:\Users\Administrator\AppData\Local\kotlin\daemon\kotlin-daemon-client-tsmarker11134052769962658558.tmp
error message: Daemon compilation failed: Could not connect to Kotlin compile daemon
java.lang.RuntimeException: Could not connect to Kotlin compile daemon
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:214)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74)
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:64)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:61)
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:102)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:61)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:58)
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
at org.gradle.internal.Factories$1.create(Factories.java:30)
at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$withLocksAcquired$0(DefaultWorkerLeaseService.java:269)
at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:42)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:267)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:259)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)

View File

@@ -0,0 +1,48 @@
kotlin version: 2.2.10
error message: java.nio.file.AccessDeniedException: C:\Users\Administrator\AppData\Local\kotlin\daemon\kotlin-daemon-client-tsmarker4236714666597388016.tmp
error message: Daemon compilation failed: Could not connect to Kotlin compile daemon
java.lang.RuntimeException: Could not connect to Kotlin compile daemon
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:214)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74)
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:64)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:61)
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:102)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:61)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:58)
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
at org.gradle.internal.Factories$1.create(Factories.java:30)
at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$withLocksAcquired$0(DefaultWorkerLeaseService.java:269)
at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:42)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:267)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:259)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)

View File

@@ -0,0 +1,48 @@
kotlin version: 2.2.10
error message: java.nio.file.AccessDeniedException: C:\Users\Administrator\AppData\Local\kotlin\daemon\kotlin-daemon-client-tsmarker12754528945444950713.tmp
error message: Daemon compilation failed: Could not connect to Kotlin compile daemon
java.lang.RuntimeException: Could not connect to Kotlin compile daemon
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:214)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74)
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:64)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:61)
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:102)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:61)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:58)
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
at org.gradle.internal.Factories$1.create(Factories.java:30)
at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$withLocksAcquired$0(DefaultWorkerLeaseService.java:269)
at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:42)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:267)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:259)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)

View File

@@ -3,7 +3,7 @@ plugins {
}
android {
namespace = "com.example.defenseapplication"
namespace = "com.ckkj.defense_device"
compileSdk {
version = release(36) {
minorApiLevel = 1
@@ -11,9 +11,9 @@ android {
}
defaultConfig {
applicationId = "com.example.defenseapplication"
applicationId = "com.ckkj.defense_device"
minSdk = 24
targetSdk = 36
targetSdk = 30
versionCode = 1
versionName = "1.0"
@@ -36,6 +36,11 @@ android {
buildFeatures {
viewBinding=true
}
lint {
disable += "ExpiredTargetSdkVersion"
checkReleaseBuilds = false
abortOnError = false
}
}
dependencies {
@@ -69,14 +74,8 @@ dependencies {
// Kotlin 协程
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
// CameraX 用于相机预览
implementation("androidx.camera:camera-camera2:1.3.0")
implementation("androidx.camera:camera-lifecycle:1.3.0")
implementation("androidx.camera:camera-view:1.3.0")
// Google ML Kit 人脸检测
implementation("com.google.mlkit:face-detection:16.1.5")
// 图形绘制库(绘制人脸框)
implementation("com.github.bumptech.glide:glide:4.15.1")
//Glide 依赖
implementation("com.github.bumptech.glide:glide:4.16.0")
// ZXing 二维码扫描库
@@ -87,8 +86,6 @@ dependencies {
implementation("com.geyifeng.immersionbar:immersionbar-ktx:3.2.2")
implementation("com.wdullaer:materialdatetimepicker:4.2.3") // 经典稳定
implementation("androidx.core:core-ktx:1.12.0")
// Android-PickerView 时间选择器
implementation("com.contrarywind:Android-PickerView:4.1.9")
//二维码三方库
implementation("com.github.maning0303:MNMLKitScanner:V1.0.4")
implementation("com.google.mlkit:barcode-scanning:17.0.2")
@@ -103,6 +100,8 @@ dependencies {
implementation("com.contrarywind:Android-PickerView:4.1.9")
// GSYVideoPlayer
implementation("io.github.carguo:gsyvideoplayer:13.0.0")
//下载
implementation("io.github.chiclaim:downloader:1.0.2")
}

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication
package com.ckkj.defense_device
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4

View File

@@ -22,11 +22,18 @@
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/loge"
android:icon="@mipmap/logo"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.DefenseApplication">
<activity
android:name=".personal.CancelAccountActivity"
android:exported="false" />
<activity
android:name=".personal.SettingsMenusActivity"
android:exported="false" />
<activity
android:name=".home.StartActivity"
android:exported="true">
@@ -42,6 +49,9 @@
<activity
android:name=".personal.InvitationCodeActivity"
android:exported="false" />
<activity
android:name=".personal.JoinFamilyInviteActivity"
android:exported="false" />
<activity
android:name=".liveVideo.StrikePositionActivity"
android:exported="false" />
@@ -118,8 +128,7 @@
android:exported="false" />
<activity
android:name=".home.HomeActivity"
android:exported="false">
</activity>
android:exported="false" />
<activity
android:name=".login.RegisterSuccessActivity"
android:exported="false" />

View File

@@ -0,0 +1,41 @@
package com.ckkj.defense_device
import android.app.Application
import android.content.Context
import com.blankj.utilcode.util.Utils
import com.ckkj.defense_device.utils.LanguageUtil
// _ooOoo_
// o8888888o
// 88" . "88
// (| -_- |)
// O\ = /O
// ____/`---'\____
// . ' \\| |// `.
// / \\||| : |||// \
// / _||||| -:- |||||- \
// | | \\\ - /// | |
// | \_| ''\---/'' | |
// \ .-\__ `-` ___/-. /
// ___`. .' /--.--\ `. . __
// ."" '< `.___\_<|>_/___.' >'"".
// | | : `- \`.;`\ _ /`;.`/ - ` : | |
// \ \ `-. \_ __\ /__ _/ .-` / /
// ======`-.____`-.___\_____/___.-`____.-'======
// `=---='
//
// 佛祖保佑 永无BUG
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
Utils.init(this) // 初始化 AndroidUtilCode
LanguageUtil.init(this)
}
override fun attachBaseContext(base: Context) {
// 在应用启动时应用语言设置
val context = LanguageUtil.attachBaseContext(base)
super.attachBaseContext(context)
}
}

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.adapter
package com.ckkj.defense_device.adapter
import android.view.LayoutInflater
import android.view.View
@@ -6,7 +6,7 @@ import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.R
import com.ckkj.defense_device.R
data class Device(
val name: String,
@@ -18,6 +18,8 @@ class AddDeviceAdapter(
private val onItemClick: (Device) -> Unit
) : RecyclerView.Adapter<AddDeviceAdapter.ViewHolder>() {
private val defaultIcons = listOf(R.mipmap.img1, R.mipmap.img2, R.mipmap.img3)
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val ivIcon: ImageView = itemView.findViewById(R.id.ivDeviceIcon2)
val tvName: TextView = itemView.findViewById(R.id.tvDeviceName2)
@@ -47,7 +49,9 @@ class AddDeviceAdapter(
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val device = devices[position]
holder.tvName.text = device.name
holder.ivIcon.setImageResource(R.drawable.img)
val iconResId = defaultIcons[position % defaultIcons.size]
holder.ivIcon.setImageResource(iconResId)
// 点击事件
holder.itemView.setOnClickListener { onItemClick(device) }

View File

@@ -1,11 +1,10 @@
package com.example.defenseapplication.adapter
package com.ckkj.defense_device.adapter
import android.graphics.Color
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.ItemAddLinkedUserBinding
import com.ckkj.defense_device.databinding.ItemAddLinkedUserBinding
data class UserItem(val name: String, val phone: String, val userId: String = "")

View File

@@ -1,10 +1,10 @@
package com.example.defenseapplication.adapter
package com.ckkj.defense_device.adapter
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.bean.DeviceAlarmBean
import com.example.defenseapplication.databinding.ItemAlarmLogBinding
import com.ckkj.defense_device.bean.DeviceAlarmBean
import com.ckkj.defense_device.databinding.ItemAlarmLogBinding
class AlarmLogAdapter(
private val items: List<DeviceAlarmBean>,

View File

@@ -1,11 +1,11 @@
package com.example.defenseapplication.adapter
package com.ckkj.defense_device.adapter
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.example.defenseapplication.bean.DeviceAlarmBean
import com.example.defenseapplication.databinding.ItemAlarmLogHorizontalBinding
import com.ckkj.defense_device.bean.DeviceAlarmBean
import com.ckkj.defense_device.databinding.ItemAlarmLogHorizontalBinding
class AlarmLogHorizontalAdapter(
private val items: List<DeviceAlarmBean>,

View File

@@ -1,27 +1,20 @@
package com.example.defenseapplication.adapter
package com.ckkj.defense_device.adapter
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.ItemDeviceBinding
data class DeviceUi(
val name: String,
val status: String,
val deviceId: String = ""
) {
val isOnline: Boolean
get() = status == "1"
}
import com.bumptech.glide.Glide
import com.ckkj.defense_device.R
import com.ckkj.defense_device.bean.DeviceBean
import com.ckkj.defense_device.databinding.ItemDeviceBinding
class DeviceAdapter(
private val onItemClick: (DeviceUi) -> Unit = {}
private val onItemClick: (DeviceBean) -> Unit = {}
) : RecyclerView.Adapter<DeviceAdapter.DeviceViewHolder>() {
private val items = mutableListOf<DeviceUi>()
private val items = mutableListOf<DeviceBean>()
fun submitList(deviceList: List<DeviceUi>) {
fun submitList(deviceList: List<DeviceBean>) {
items.clear()
items.addAll(deviceList)
notifyDataSetChanged()
@@ -33,15 +26,25 @@ class DeviceAdapter(
}
override fun onBindViewHolder(holder: DeviceViewHolder, position: Int) {
holder.bind(items[position])
holder.bind(items[position], position)
}
override fun getItemCount(): Int = items.size
private val defaultIcons = listOf(R.mipmap.img1, R.mipmap.img2, R.mipmap.img3)
inner class DeviceViewHolder(private val binding: ItemDeviceBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item: DeviceUi) {
fun bind(item: DeviceBean, position: Int) {
if (item.deviceImg.isNullOrEmpty()) {
val iconResId = defaultIcons[position % defaultIcons.size]
binding.ivDeviceIcon.setImageResource(iconResId)
} else {
Glide.with(binding.root.context)
.load(item.deviceImg)
.into(binding.ivDeviceIcon)
}
binding.tvDeviceType.text = item.name
when (item.status) {
"1" -> {

View File

@@ -1,12 +1,12 @@
package com.example.defenseapplication.adapter
package com.ckkj.defense_device.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.R
import com.example.defenseapplication.bean.FamilyBean
import com.example.defenseapplication.databinding.ItemFamilyBinding
import com.ckkj.defense_device.R
import com.ckkj.defense_device.bean.FamilyBean
import com.ckkj.defense_device.databinding.ItemFamilyBinding
class FamilyAdapter(
private val onItemClick: (String) -> Unit
@@ -64,7 +64,7 @@ class FamilyAdapter(
binding.tvFamilyName.setTextColor(binding.root.context.getColor(R.color.white))
binding.tvFamilyRole.setTextColor(binding.root.context.getColor(R.color.white))
binding.ivCheck.visibility = View.VISIBLE
binding.ivCheck.setImageResource(R.drawable.ic_check_white)
binding.ivCheck.setImageResource(R.mipmap.ic_check_white)
} else {
binding.layoutFamilyItem.setBackgroundResource(0)
binding.tvFamilyName.setTextColor(binding.root.context.getColor(R.color.black))

View File

@@ -1,12 +1,12 @@
package com.example.defenseapplication.adapter
package com.ckkj.defense_device.adapter
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.ItemSwitchFamilyBinding
import com.example.defenseapplication.model.FamilyItem
import com.ckkj.defense_device.R
import com.ckkj.defense_device.databinding.ItemSwitchFamilyBinding
import com.ckkj.defense_device.model.FamilyItem
class FamilySwitchAdapter(
private var familyList: List<FamilyItem>,

View File

@@ -1,11 +1,10 @@
package com.example.defenseapplication.adapter
package com.ckkj.defense_device.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.ItemLinkedUserBinding
import com.ckkj.defense_device.R
import com.ckkj.defense_device.databinding.ItemLinkedUserBinding
data class LinkedUser(
val userId: String,

View File

@@ -1,11 +1,11 @@
package com.example.defenseapplication.adapter
package com.ckkj.defense_device.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.databinding.ItemMessageGroupTitleBinding
import com.example.defenseapplication.databinding.ItemMessageNoticeBinding
import com.ckkj.defense_device.databinding.ItemMessageGroupTitleBinding
import com.ckkj.defense_device.databinding.ItemMessageNoticeBinding
sealed class MessageListItem {
data class Header(val title: String) : MessageListItem()

View File

@@ -1,9 +1,10 @@
package com.example.defenseapplication.adapter
package com.ckkj.defense_device.adapter
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.databinding.ItemWifiBinding
import com.ckkj.defense_device.databinding.ItemWifiBinding
class WifiListAdapter(
wifiList: List<String>,
@@ -39,14 +40,25 @@ class WifiListAdapter(
override fun getItemCount(): Int = wifiList.size
fun updateData(newList: List<String>) {
val oldList = wifiList.toList()
val diffResult = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
override fun getOldListSize() = oldList.size
override fun getNewListSize() = newList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
oldList[oldItemPosition] == newList[newItemPosition]
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
oldList[oldItemPosition] == newList[newItemPosition]
})
wifiList.clear()
wifiList.addAll(newList)
notifyDataSetChanged()
diffResult.dispatchUpdatesTo(this)
}
fun addData(newList: List<String>) {
val startPosition = wifiList.size
val newItems = newList.filter { !wifiList.contains(it) }
if (newItems.isEmpty()) return
wifiList.addAll(newItems)
notifyItemRangeInserted(startPosition, newItems.size)
}

View File

@@ -1,10 +1,10 @@
package com.example.defenseapplication.base
package com.ckkj.defense_device.base
import android.content.Context
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.utils.ActivityManager
import com.example.defenseapplication.utils.LanguageUtil
import com.ckkj.defense_device.utils.ActivityManager
import com.ckkj.defense_device.utils.LanguageUtil
open class BaseActivity : AppCompatActivity() {

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
data class AddDeviceBean(
val deviceEm: String? = null,//设备型号

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
data class AddDeviceUserRequest(
val deviceId: String,

View File

@@ -1,10 +1,10 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
/**
* 统一返回数据基类根据你的后端实际字段调整
*/
data class BaseInfo(
val message: String? = null,
val msg: String? = null,
val code: Int = 0,
val data: Any? = null
)

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
class DeleteBean {
var deviceId: String? = null

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
data class DeleteDeviceUserRequest(
val userId: String,

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
import android.os.Parcel
import android.os.Parcelable

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
data class DeviceAlarmResponse(
val total: Int,

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
data class DeviceBean(
val alertAudio: String? = null,//告警播放
@@ -9,11 +9,11 @@ data class DeviceBean(
val deviceFamilyId: String? = null,
val deviceImg: String? = null,
val deviceName: String? = null,//设备名称
val deviceNo: String? = null,//设备编号
val deviceSn: String? = null,//设备序列号
val deviceNo: String = "",//设备编号
val deviceSn: String = "",//设备序列号
val endTime: String? = null,//自动布放结束时间
val expirationTime: String? = null,
val fwVer: String? = null,//固件版本
val fwVer: String= "",//固件版本
val id: String? = null,
val light: String? = null,//强光开启
val patternPerception: String? = null,//识别模式
@@ -27,4 +27,13 @@ data class DeviceBean(
val wifiPassword: String? = null,//WiFi密码
val workMode: String? = null,//工作模式 0-自动 1-半自动
val optionPassword: String? = null, //操作密码
)
) {
val deviceId: String
get() = id ?: ""
val name: String
get() = deviceName ?: ""
val isOnline: Boolean
get() = status == "1"
}

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
data class DeviceUserBean(
val createDept: Int ? = null, //创建部门

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
data class FamilyBean(
val id: String,

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
data class FamilyMembersBean(
val id: String? = null, // ID

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
data class GetCodeBean<T> (
val code:Int,

View File

@@ -0,0 +1,18 @@
package com.ckkj.defense_device.bean
data class InviterInfoBean(
val nickName: String? = null,
val idCard: String? = null,
val phonenumber: String? = null,
val avatar: String? = null,
val id: String? = null,
val parentId: String? = null,
val userId: String? = null,
val mac: String? = null,
val status: String? = null,
) {
fun resolveParentId(): String? =
parentId?.takeIf { it.isNotBlank() }
?: userId?.takeIf { it.isNotBlank() }
?: id?.takeIf { it.isNotBlank() }
}

View File

@@ -0,0 +1,7 @@
package com.ckkj.defense_device.bean
data class JoinTheFamilyBean(
val parentId: String,
val inviteCode: String,
)

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
import android.os.Parcel
import android.os.Parcelable

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
data class MessageListResponse(
val total: Int,

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
data class ObtainInviterInformationBean(
val nickName: String? = null,

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
data class ObtainInviterInformationRequest(
val childId: String

View File

@@ -0,0 +1,8 @@
package com.ckkj.defense_device.bean
data class RecommendationCodeBean(
val inviteCode: String? = null,
val code: String? = null,
val expireTime: Long? = null,
val expire: Long? = null
)

View File

@@ -0,0 +1,5 @@
package com.ckkj.defense_device.bean
data class SelectInviterInfoBean(
val code: String
)

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
data class SwitchFamilyRequest(
val clientId: String,

View File

@@ -0,0 +1,8 @@
package com.ckkj.defense_device.bean
data class UpdateFamilyUserRequest(
val id: String,
val optionPassword: String,
val optionStatus: String,
val status: String,
)

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
data class UpdatePassword(
val oldPassword: String,

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
data class UpdateUserInfo(
val userId: String?=null,

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
data class UploadResponse(
val code: Int,

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
import java.io.Serializable

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean
package com.ckkj.defense_device.bean
data class VerifyOptionPasswordRequest(
val optionPassword: String

View File

@@ -0,0 +1,20 @@
package com.ckkj.defense_device.bean
data class VideoStreamInfo(
val deviceNo: String,
val streamId: String,
val app: String,
val online: Boolean,
val pushUrl: String,
val playToken: String,
val expireAt: String,
val playUrls:playUrls,
val expireSeconds: Int,
)
class playUrls(
val flv: String,
val hls: String,
val rtmp: String,
val rtsp: String,
val webrtc: String,
)

View File

@@ -0,0 +1,5 @@
package com.ckkj.defense_device.bean
data class VideoStreamRequest(
val deviceNo: String
)

View File

@@ -1,7 +1,6 @@
package com.example.defenseapplication.home
package com.ckkj.defense_device.home
import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
@@ -14,10 +13,10 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.GridLayoutManager
import com.example.defenseapplication.R
import com.example.defenseapplication.adapter.AddDeviceAdapter
import com.example.defenseapplication.adapter.Device
import com.example.defenseapplication.databinding.AddDeviceActivityBinding
import com.ckkj.defense_device.R
import com.ckkj.defense_device.adapter.AddDeviceAdapter
import com.ckkj.defense_device.adapter.Device
import com.ckkj.defense_device.databinding.AddDeviceActivityBinding
import com.gyf.immersionbar.ImmersionBar
import com.maning.mlkitscanner.scan.MNScanManager
import com.maning.mlkitscanner.scan.callback.act.MNScanCallback

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.home
package com.ckkj.defense_device.home
import android.Manifest
import android.content.BroadcastReceiver
@@ -23,10 +23,10 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.R
import com.example.defenseapplication.adapter.WifiListAdapter
import com.example.defenseapplication.databinding.AddFamilyActivityBinding
import com.example.defenseapplication.databinding.DialogWifiListBinding
import com.ckkj.defense_device.R
import com.ckkj.defense_device.adapter.WifiListAdapter
import com.ckkj.defense_device.databinding.AddFamilyActivityBinding
import com.ckkj.defense_device.databinding.DialogWifiListBinding
import com.gyf.immersionbar.ImmersionBar
//选择Wi-Fi
class AddFamilyActivity : AppCompatActivity() {
@@ -144,10 +144,6 @@ class AddFamilyActivity : AppCompatActivity() {
}
dialogBinding.rvWifiList.adapter = wifiListAdapter
dialogBinding.swipeRefreshLayout.setOnRefreshListener {
refreshWifiList(dialogBinding)
}
dialogBinding.rvWifiList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
@@ -168,16 +164,6 @@ class AddFamilyActivity : AppCompatActivity() {
return rect.height()
}
private fun refreshWifiList(dialogBinding: DialogWifiListBinding) {
dialogBinding.swipeRefreshLayout.isRefreshing = true
handler.postDelayed({
wifiManager.startScan()
val newWifiList = getWifiList()
wifiListAdapter?.updateData(newWifiList)
dialogBinding.swipeRefreshLayout.isRefreshing = false
}, 1000)
}
private fun loadMoreWifiList() {
isLoadingMore = true
handler.postDelayed({
@@ -204,12 +190,8 @@ class AddFamilyActivity : AppCompatActivity() {
}
private fun updateWifiList() {
popupWindow?.contentView?.findViewById<androidx.recyclerview.widget.RecyclerView>(R.id.rvWifiList)?.let { recyclerView ->
val wifiList = getWifiList()
recyclerView.adapter = WifiListAdapter(wifiList) { wifiName ->
binding.etWifiName.setText(wifiName)
popupWindow?.dismiss()
}
popupWindow?.contentView?.findViewById<androidx.recyclerview.widget.RecyclerView>(R.id.rvWifiList)?.let {
wifiListAdapter?.updateData(getWifiList())
}
}

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.home
package com.ckkj.defense_device.home
import android.content.Intent
import android.graphics.drawable.AnimationDrawable
@@ -6,14 +6,9 @@ import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.View
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.AddDeviceActivityBinding
import com.example.defenseapplication.databinding.ConnectDeviceActivityBinding
import com.ckkj.defense_device.R
import com.ckkj.defense_device.databinding.ConnectDeviceActivityBinding
import com.gyf.immersionbar.ImmersionBar
//连接设备
class ConnectDeviceActivity : AppCompatActivity() {

View File

@@ -1,17 +1,17 @@
package com.example.defenseapplication.home
package com.ckkj.defense_device.home
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.Fragment
import com.example.defenseapplication.R
import com.example.defenseapplication.base.BaseActivity
import com.example.defenseapplication.databinding.HomeActivityBinding
import com.example.defenseapplication.databinding.HomeMenuFragmentBinding
import com.gyf.immersionbar.ImmersionBar
import com.ckkj.defense_device.R
import com.ckkj.defense_device.base.BaseActivity
import com.ckkj.defense_device.databinding.HomeActivityBinding
class HomeActivity : BaseActivity() {
companion object {
const val EXTRA_REFRESH = "extra_refresh"
}
// ViewBinding 核心对象
private lateinit var binding: HomeActivityBinding
@@ -37,10 +37,10 @@ class HomeActivity : BaseActivity() {
binding.tabHome.setOnClickListener {
switchFragment(homeMenuFragment)
// 切换图标 + 文字颜色
binding.ivHome.setImageResource(R.drawable.home_checked)
binding.ivHome.setImageResource(R.mipmap.home_checked)
binding.tvHome.setTextColor(resources.getColor(R.color.ic_selected))
binding.ivProfile.setImageResource(R.drawable.profile)
binding.ivProfile.setImageResource(R.mipmap.profile)
binding.tvProfile.setTextColor(resources.getColor(R.color.ic_normal))
}
@@ -48,12 +48,34 @@ class HomeActivity : BaseActivity() {
binding.tabProfile.setOnClickListener {
switchFragment(personalFragment)
// 切换图标 + 文字颜色
binding.ivHome.setImageResource(R.drawable.home)
binding.ivHome.setImageResource(R.mipmap.home)
binding.tvHome.setTextColor(resources.getColor(R.color.ic_normal))
binding.ivProfile.setImageResource(R.drawable.profile_checked)
binding.ivProfile.setImageResource(R.mipmap.profile_checked)
binding.tvProfile.setTextColor(resources.getColor(R.color.ic_selected))
}
handleRefreshIntent(intent)
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
if (intent != null) {
setIntent(intent)
handleRefreshIntent(intent)
}
}
private fun handleRefreshIntent(intent: Intent) {
if (intent.getBooleanExtra(EXTRA_REFRESH, false)) {
intent.removeExtra(EXTRA_REFRESH)
switchFragment(homeMenuFragment)
binding.ivHome.setImageResource(R.mipmap.home_checked)
binding.tvHome.setTextColor(resources.getColor(R.color.ic_selected))
binding.ivProfile.setImageResource(R.mipmap.profile)
binding.tvProfile.setTextColor(resources.getColor(R.color.ic_normal))
homeMenuFragment.refreshHomeData()
}
}
/**

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.home
package com.ckkj.defense_device.home
import android.Manifest
import android.app.Activity
@@ -7,7 +7,7 @@ import android.content.pm.PackageManager
import android.graphics.Color
import android.os.Build
import android.graphics.Rect
import android.graphics.drawable.GradientDrawable
import android.os.Bundle
import android.util.Log
import android.util.TypedValue
@@ -21,23 +21,27 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.R
import com.example.defenseapplication.adapter.DeviceAdapter
import com.example.defenseapplication.adapter.DeviceUi
import com.example.defenseapplication.adapter.FamilyAdapter
import com.example.defenseapplication.bean.DeviceBean
import com.example.defenseapplication.bean.FamilyBean
import com.example.defenseapplication.bean.SwitchFamilyRequest
import com.example.defenseapplication.databinding.HomeMenuFragmentBinding
import com.example.defenseapplication.liveVideo.LiveVideoActivity
import com.example.defenseapplication.utils.DeviceIdEvent
import com.example.defenseapplication.utils.DeviceUpdateEvent
import com.example.defenseapplication.utils.FamilySwitchEvent
import com.example.defenseapplication.utils.MessageStatusManager
import com.example.defenseapplication.utils.RetrofitNetwork
import com.example.defenseapplication.utils.UserinfoUtil
import com.example.defenseapplication.view.DefenseDialogs
import com.example.defenseapplication.view.showDefenseDialog
import com.alibaba.sdk.android.emas.g
import com.ckkj.defense_device.R
import com.ckkj.defense_device.adapter.DeviceAdapter
import com.ckkj.defense_device.adapter.FamilyAdapter
import com.ckkj.defense_device.bean.DeviceBean
import com.ckkj.defense_device.bean.FamilyBean
import com.ckkj.defense_device.bean.SwitchFamilyRequest
import com.ckkj.defense_device.bean.SelectInviterInfoBean
import com.ckkj.defense_device.databinding.HomeMenuFragmentBinding
import com.ckkj.defense_device.liveVideo.LiveVideoActivity
import com.ckkj.defense_device.personal.JoinFamilyInviteActivity
import com.ckkj.defense_device.utils.DeviceIdEvent
import com.ckkj.defense_device.utils.DeviceUpdateEvent
import com.ckkj.defense_device.utils.FamilySwitchEvent
import com.ckkj.defense_device.utils.MessageStatusManager
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.ckkj.defense_device.utils.UserinfoUtil
import com.ckkj.defense_device.view.DefenseDialogs
import com.ckkj.defense_device.view.LoadingDialog
import com.ckkj.defense_device.view.PullRefreshLayout
import com.ckkj.defense_device.view.showDefenseDialog
import com.gyf.immersionbar.ImmersionBar
import com.maning.mlkitscanner.scan.MNScanManager
import com.maning.mlkitscanner.scan.callback.act.MNScanCallback
@@ -45,6 +49,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.json.JSONObject
//主页碎片
class HomeMenuFragment : Fragment() {
// ViewBinding
@@ -59,18 +64,21 @@ class HomeMenuFragment : Fragment() {
private val pageSize = 10
private var hasMore = true
private var isLoading = false
private var loadingDialog: LoadingDialog? = null
private var lastNoMoreToastTime: Long = 0L
private val noMoreToastInterval: Long = 1500L
private val requestPermissionsLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
val cameraGranted = permissions[Manifest.permission.CAMERA] ?: false
val storageGranted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
permissions[Manifest.permission.READ_MEDIA_IMAGES] ?: false
} else {
permissions[Manifest.permission.READ_EXTERNAL_STORAGE] ?: false
}
if (cameraGranted && storageGranted) {
startScan()
} else {
@@ -83,7 +91,7 @@ class HomeMenuFragment : Fragment() {
requireContext(),
Manifest.permission.CAMERA
)
val storagePermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
ContextCompat.checkSelfPermission(
requireContext(),
@@ -96,7 +104,7 @@ class HomeMenuFragment : Fragment() {
)
}
if (cameraPermission == PackageManager.PERMISSION_GRANTED &&
if (cameraPermission == PackageManager.PERMISSION_GRANTED &&
storagePermission == PackageManager.PERMISSION_GRANTED) {
startScan()
} else {
@@ -122,23 +130,86 @@ class HomeMenuFragment : Fragment() {
MNScanManager.RESULT_SUCCESS -> {
val result = data?.getStringArrayListExtra(MNScanManager.INTENT_KEY_RESULT_SUCCESS)
if (!result.isNullOrEmpty()) {
ToastUtils.showToast(requireContext(), "扫码成功: $result")
val inviteCode = parseInviteCode(result[0])
if (inviteCode.isNullOrEmpty()) {
Toast.makeText(requireContext(), "无效的邀请码", Toast.LENGTH_SHORT).show()
} else {
fetchInviterInfo(inviteCode)
}
} else {
ToastUtils.showToast(requireContext(), "扫码结果为空")
Toast.makeText(requireContext(), "扫码结果为空", Toast.LENGTH_SHORT).show()
}
}
MNScanManager.RESULT_FAIL -> {
val error = data?.getStringExtra(MNScanManager.INTENT_KEY_RESULT_ERROR)
ToastUtils.showToast(requireContext(), "扫码失败: $error")
Toast.makeText(requireContext(), "扫码失败: $error", Toast.LENGTH_SHORT).show()
}
MNScanManager.RESULT_CANCLE -> {
ToastUtils.showToast(requireContext(), "扫码取消")
Toast.makeText(requireContext(), "扫码取消", Toast.LENGTH_SHORT).show()
}
}
}
})
}
private fun parseInviteCode(scanResult: String): String? {
val trimmed = scanResult.trim()
if (trimmed.isEmpty()) return null
return try {
if (trimmed.startsWith("{")) {
JSONObject(trimmed).optString("code").takeIf { it.isNotEmpty() }
} else {
trimmed
}
} catch (e: Exception) {
trimmed
}
}
private fun fetchInviterInfo(inviteCode: String) {
val loadingDialog = LoadingDialog(requireActivity()).setMessage(this.getString(R.string.loading)).apply { show() }
CoroutineScope(Dispatchers.IO).launch {
try {
val response = RetrofitNetwork.getNetworkService()
.selectInviterInfo(SelectInviterInfoBean(code = inviteCode))
withContext(Dispatchers.Main) {
loadingDialog.dismiss()
if (response.code == 200 && response.data != null) {
val inviter = response.data
val parentId = inviter.resolveParentId()
if (parentId.isNullOrEmpty()) {
Toast.makeText(
requireContext(),
getString(R.string.network_error),
Toast.LENGTH_SHORT
).show()
return@withContext
}
val intent = Intent(requireContext(), JoinFamilyInviteActivity::class.java).apply {
putExtra(JoinFamilyInviteActivity.EXTRA_INVITE_CODE, inviteCode)
putExtra(JoinFamilyInviteActivity.EXTRA_NICK_NAME, inviter.nickName)
putExtra(JoinFamilyInviteActivity.EXTRA_AVATAR, inviter.avatar)
putExtra(JoinFamilyInviteActivity.EXTRA_PARENT_ID, parentId)
putExtra(JoinFamilyInviteActivity.EXTRA_USER_ID, inviter.userId)
}
startActivity(intent)
} else {
Toast.makeText(
requireContext(),
response.msg.ifBlank { getString(R.string.network_error) },
Toast.LENGTH_SHORT
).show()
}
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
loadingDialog.dismiss()
Toast.makeText(requireContext(), R.string.network_error, Toast.LENGTH_SHORT).show()
}
}
}
}
private val unreadCountChangeListener = object : MessageStatusManager.UnreadCountChangeListener {
override fun onUnreadCountChanged(count: Int) {
updateUnreadCountUI(count)
@@ -197,13 +268,8 @@ class HomeMenuFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// 为 LinearLayout 设置渐变背景
setGradientBackground(
view = binding.gradientLayout,
startColor = Color.parseColor("#EBDCED"),
endColor = Color.parseColor("#CAF4FF")
)
binding.message.setOnClickListener {
binding.gradientLayout.setBackgroundColor(Color.TRANSPARENT)
binding.message.setOnClickListener {
val intent = Intent(requireContext(), MessageActivity::class.java)
startActivity(intent)
}
@@ -236,9 +302,11 @@ class HomeMenuFragment : Fragment() {
)
}
binding.swipeRefreshLayout.setOnRefreshListener {
refreshDeviceList()
}
binding.swipeRefreshLayout.setOnRefreshListener(object : PullRefreshLayout.OnRefreshListener {
override fun onRefresh() {
refreshDeviceList()
}
})
binding.rvDeviceList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
@@ -246,9 +314,24 @@ class HomeMenuFragment : Fragment() {
val layoutManager = recyclerView.layoutManager as GridLayoutManager
val lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition()
val totalItemCount = layoutManager.itemCount
val firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition()
if (firstVisibleItemPosition == 0) {
val firstChild = layoutManager.findViewByPosition(0)
firstChild?.let { child ->
val top = child.top
if (top >= 0) {
val offset = (top.toFloat() / dpToPx(80f)).coerceIn(0f, 1f)
binding.gradientLayout.translationY = -offset * dpToPx(20f)
}
}
}
if (!isLoading && hasMore && lastVisibleItemPosition >= totalItemCount - 1 && dy > 0) {
loadMoreDevices()
} else if (!hasMore && !isLoading && lastVisibleItemPosition >= totalItemCount - 1
&& dy > 0 && totalItemCount > 0) {
showNoMoreToast()
}
}
})
@@ -285,6 +368,10 @@ class HomeMenuFragment : Fragment() {
}
}
fun refreshHomeData() {
fetchFamilyList()
}
private fun fetchFamilyList() {
CoroutineScope(Dispatchers.IO).launch {
try {
@@ -321,18 +408,22 @@ class HomeMenuFragment : Fragment() {
Log.d("HomeMenuFragment", "canViewDevice = $canViewDevice")
if (canViewDevice) {
binding.tvDeviceTitle.visibility = View.VISIBLE
binding.swipeRefreshLayout.visibility = View.VISIBLE
binding.rvDeviceList.visibility = View.VISIBLE
binding.message.visibility = View.VISIBLE
binding.addFamily.visibility = View.VISIBLE
binding.add.visibility = View.VISIBLE
binding.layoutNoPermission.visibility = View.GONE
binding.layoutNoNetwork.visibility = View.GONE
} else {
binding.tvDeviceTitle.visibility = View.GONE
binding.swipeRefreshLayout.visibility = View.GONE
binding.rvDeviceList.visibility = View.GONE
binding.message.visibility = View.GONE
binding.addFamily.visibility = View.GONE
binding.add.visibility = View.GONE
binding.layoutNoPermission.visibility = View.VISIBLE
binding.layoutNoNetwork.visibility = View.GONE
}
}
@@ -356,7 +447,7 @@ class HomeMenuFragment : Fragment() {
canViewDevice = userInfo?.role == "appadmin" && familyBean.role != "member"
updateAdminUI()
updateFamilyDisplayText(familyName)
fetchDeviceList()
fetchDeviceList(showLoading = true)
FamilySwitchEvent.notifyFamilySwitched(familyName)
} else {
Toast.makeText(requireContext(), response.msg, Toast.LENGTH_SHORT).show()
@@ -370,15 +461,20 @@ class HomeMenuFragment : Fragment() {
}
}
private fun fetchDeviceList(page: Int = 1, isLoadMore: Boolean = false) {
private fun fetchDeviceList(page: Int = 1, isLoadMore: Boolean = false, showLoading: Boolean = false) {
if (!canViewDevice || isLoading) return
isLoading = true
loadingDialog = if (showLoading) LoadingDialog(requireActivity()).setMessage(getString(R.string.loading)).apply { show() } else null
CoroutineScope(Dispatchers.IO).launch {
try {
val response = RetrofitNetwork.getNetworkService().getDeviceList()
withContext(Dispatchers.Main) {
if (!isAdded) return@withContext
loadingDialog?.dismiss()
loadingDialog = null
Log.d("DeviceList", "code = ${response.code}, data = ${response.data}")
if (response.code == 200 && response.data != null) {
val newDevices = response.data
@@ -390,32 +486,47 @@ class HomeMenuFragment : Fragment() {
hasMore = newDevices.size >= pageSize
}
Log.d("DeviceList", "deviceBeanList size = ${deviceBeanList.size}")
showDeviceContent()
updateDeviceList()
} else {
Toast.makeText(requireContext(), response.msg, Toast.LENGTH_SHORT).show()
noNetwork()
val errorMsg = response.msg.ifBlank { getString(R.string.network_error) }
Toast.makeText(requireContext(), errorMsg, Toast.LENGTH_SHORT).show()
if (isLoadMore) {
hasMore = false
}
}
isLoading = false
binding.swipeRefreshLayout.finishRefresh()
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
if (!isAdded) return@withContext
loadingDialog?.dismiss()
loadingDialog = null
noNetwork()
Toast.makeText(requireContext(), R.string.network_error, Toast.LENGTH_SHORT).show()
isLoading = false
if (isLoadMore) {
hasMore = false
}
binding.swipeRefreshLayout.finishRefresh()
}
}
}
}
private fun showNoMoreToast() {
val now = System.currentTimeMillis()
if (now - lastNoMoreToastTime < noMoreToastInterval) return
lastNoMoreToastTime = now
ToastUtils.showToast(requireContext(), getString(R.string.no_more_data))
}
private fun refreshDeviceList() {
currentPage = 1
hasMore = true
fetchDeviceList(currentPage, false)
binding.swipeRefreshLayout.isRefreshing = false
}
private fun loadMoreDevices() {
@@ -445,26 +556,38 @@ class HomeMenuFragment : Fragment() {
}
}
private fun updateDeviceList() {
val deviceUiList = deviceBeanList.map {
DeviceUi(it.deviceName ?: "", it.status ?: "", it.id ?: "")
}
private fun showDeviceContent() {
binding.swipeRefreshLayout.visibility = View.VISIBLE
binding.rvDeviceList.visibility = View.VISIBLE
binding.layoutNoPermission.visibility = View.GONE
binding.layoutNoNetwork.visibility = View.GONE
}
if (deviceUiList.isEmpty()) {
private fun noNetwork() {
binding.swipeRefreshLayout.visibility = View.GONE
binding.rvDeviceList.visibility = View.GONE
binding.layoutNoPermission.visibility = View.GONE
binding.layoutNoNetwork.visibility = View.VISIBLE
}
private fun updateDeviceList() {
if (deviceBeanList.isEmpty()) {
deviceAdapter.submitList(listOf(
DeviceUi(getString(R.string.no_device), "0")
DeviceBean(deviceName = getString(R.string.no_device), status = "0")
))
} else {
deviceAdapter.submitList(deviceUiList)
deviceAdapter.submitList(deviceBeanList)
}
}
private fun onDeviceClicked(device: DeviceUi) {
private fun onDeviceClicked(device: DeviceBean) {
if (device.isOnline) {
DeviceIdEvent.setDeviceId(device.deviceId)
val intent = Intent(requireContext(), LiveVideoActivity::class.java)
intent.putExtra("device_id", device.deviceId)
intent.putExtra("device_name", device.name)
intent.putExtra("deviceNo", device.deviceNo)
intent.putExtra("light", device.light)
startActivity(intent)
} else {
showDefenseDialog(
@@ -481,6 +604,14 @@ class HomeMenuFragment : Fragment() {
).toInt()
}
private fun dpToPx(dp: Float): Float {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dp,
resources.displayMetrics
)
}
private class GridHorizontalSpaceItemDecoration(
private val horizontalSpace: Int
) : RecyclerView.ItemDecoration() {
@@ -501,19 +632,10 @@ class HomeMenuFragment : Fragment() {
}
}
private fun setGradientBackground(
view: View,
startColor: Int,
endColor: Int,
orientation: GradientDrawable.Orientation = GradientDrawable.Orientation.TL_BR
) {
val gradientDrawable = GradientDrawable(orientation, intArrayOf(startColor, endColor))
gradientDrawable.gradientType = GradientDrawable.LINEAR_GRADIENT
view.background = gradientDrawable
}
override fun onDestroyView() {
super.onDestroyView()
loadingDialog?.dismiss()
loadingDialog = null
binding.rvFamilyList.adapter = null
binding.rvDeviceList.adapter = null
MessageStatusManager.removeListener(unreadCountChangeListener)

View File

@@ -1,15 +1,18 @@
package com.example.defenseapplication.home
package com.ckkj.defense_device.home
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.adapter.MessageListAdapter
import com.example.defenseapplication.adapter.MessageListItem
import com.example.defenseapplication.databinding.MessageActivityBinding
import com.example.defenseapplication.utils.MessageStatusManager
import com.example.defenseapplication.utils.RetrofitNetwork
import com.ckkj.defense_device.R
import com.ckkj.defense_device.adapter.MessageListAdapter
import com.ckkj.defense_device.adapter.MessageListItem
import com.ckkj.defense_device.databinding.MessageActivityBinding
import com.ckkj.defense_device.utils.MessageStatusManager
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.ckkj.defense_device.view.LoadingDialog
import com.ckkj.defense_device.view.PullRefreshLayout
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -19,13 +22,13 @@ import kotlinx.coroutines.withContext
class MessageActivity : AppCompatActivity() {
private lateinit var binding: MessageActivityBinding
private val messageAdapter by lazy { MessageListAdapter() }
private lateinit var loadingDialog: LoadingDialog
private var currentPage = 1
private val pageSize = 10
private var isLoading = false
private var hasMoreData = true
private val allMessages = mutableListOf<com.example.defenseapplication.bean.MessageBean>()
private var lastLoadedCount = 0
private val allMessages = mutableListOf<com.ckkj.defense_device.bean.MessageBean>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -41,9 +44,18 @@ class MessageActivity : AppCompatActivity() {
}
private fun initView() {
loadingDialog = LoadingDialog(this).setMessage(getString(R.string.loading))
binding.ivBack.setOnClickListener { finish() }
binding.rvMessageList.layoutManager = LinearLayoutManager(this)
binding.rvMessageList.adapter = messageAdapter
binding.swipeRefreshLayout.setOnRefreshListener(object : PullRefreshLayout.OnRefreshListener {
override fun onRefresh() {
currentPage = 1
hasMoreData = true
loadMessageList()
}
})
binding.rvMessageList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
@@ -70,20 +82,21 @@ class MessageActivity : AppCompatActivity() {
if (isLoading) return
isLoading = true
if (currentPage == 1) {
showLoading()
}
CoroutineScope(Dispatchers.IO).launch {
try {
val messageResponse = RetrofitNetwork.getNetworkService().getMessage(
pageNum = currentPage,
pageSize = pageSize
)
println("total: ${messageResponse.total}")
println("rows size: ${messageResponse.rows.size}")
println("当前页:$currentPage, 加载条数:${messageResponse.rows.size}")
val newMessages = messageResponse.rows
val loadedCount = newMessages.size
if (loadedCount < pageSize) {
if (newMessages.size < pageSize) {
hasMoreData = false
}
@@ -98,11 +111,11 @@ class MessageActivity : AppCompatActivity() {
allMessages.clear()
}
allMessages.addAll(newMessages)
lastLoadedCount = loadedCount
val items = convertToMessageListItems(allMessages)
withContext(Dispatchers.Main) {
hideLoading()
hideEmptyState()
messageAdapter.submitList(items)
@@ -116,20 +129,24 @@ class MessageActivity : AppCompatActivity() {
withContext(Dispatchers.Main) {
if (allMessages.isEmpty()) {
println("items is empty, showing empty state")
showEmptyState()
}
}
} catch (e: Exception) {
println("Exception: ${e.message}")
e.printStackTrace()
withContext(Dispatchers.Main) {
if (allMessages.isEmpty()) {
showEmptyState()
noNetwork()
}
}
} finally {
isLoading = false
if (currentPage == 1) {
withContext(Dispatchers.Main) {
hideLoading()
binding.swipeRefreshLayout.finishRefresh()
}
}
}
}
}
@@ -141,16 +158,34 @@ class MessageActivity : AppCompatActivity() {
loadMessageList()
}
private fun showLoading() {
binding.swipeRefreshLayout.visibility = View.GONE
binding.emptyLayout.visibility = View.GONE
binding.layoutNoNetwork.visibility = View.GONE
loadingDialog.show()
}
private fun hideLoading() {
binding.swipeRefreshLayout.visibility = View.VISIBLE
loadingDialog.dismiss()
}
private fun showEmptyState() {
binding.rvMessageList.visibility = View.GONE
binding.swipeRefreshLayout.visibility = View.GONE
binding.emptyLayout.visibility = View.VISIBLE
binding.tvNoMoreData.visibility = View.GONE
}
private fun hideEmptyState() {
binding.rvMessageList.visibility = View.VISIBLE
binding.swipeRefreshLayout.visibility = View.VISIBLE
binding.emptyLayout.visibility = View.GONE
}
private fun noNetwork() {
binding.swipeRefreshLayout.visibility = View.GONE
binding.layoutNoNetwork.visibility = View.VISIBLE
binding.tvNoMoreData.visibility = View.GONE
}
private fun showNoMoreDataHint() {
binding.tvNoMoreData.visibility = View.VISIBLE
@@ -160,20 +195,17 @@ class MessageActivity : AppCompatActivity() {
binding.tvNoMoreData.visibility = View.GONE
}
private fun convertToMessageListItems(messages: List<com.example.defenseapplication.bean.MessageBean>): List<MessageListItem> {
private fun convertToMessageListItems(messages: List<com.ckkj.defense_device.bean.MessageBean>): List<MessageListItem> {
val items = mutableListOf<MessageListItem>()
val groupedMessages = messages.groupBy { extractDate(it.createTime ?: "") }
groupedMessages.forEach { (date, messageList) ->
val headerTitle = formatDate(date)
messageList.forEachIndexed { index, message ->
println(" 消息${index + 1}: id=${message.id}, categoryName=${message.categoryName}, createTime=${message.createTime}")
}
items.add(MessageListItem.Header(headerTitle))
messageList.forEach { message ->
items.add(
MessageListItem.Message(
time = extractTime(message.createTime ?: ""),
title = message.categoryName ?: "未知消息",
title = message.categoryName ?: "",
dateTime = message.createTime ?: "",
unread = false
)

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.home
package com.ckkj.defense_device.home
import android.content.Intent
import android.os.Bundle
@@ -9,21 +9,23 @@ import android.view.ViewGroup
import android.widget.Toast
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.example.defenseapplication.R
import com.example.defenseapplication.bean.UserInfoBean
import com.example.defenseapplication.databinding.PersonalFragmentBinding
import com.example.defenseapplication.liveVideo.LinkedUserActivity
import com.example.defenseapplication.personal.FaceManagementActivity
import com.example.defenseapplication.personal.PasswordManagementActivity
import com.example.defenseapplication.personal.PersonalProfileActivity
import com.example.defenseapplication.utils.AppLanguage
import com.example.defenseapplication.utils.LanguageUtil
import com.example.defenseapplication.utils.RetrofitNetwork
import com.example.defenseapplication.utils.UserinfoUtil
import com.example.defenseapplication.utils.ActivityManager
import com.example.defenseapplication.view.FamilySwitchDialog
import com.example.defenseapplication.view.LanguageDialog
import com.example.defenseapplication.home.HomeActivity
import com.ckkj.defense_device.R
import com.ckkj.defense_device.bean.UserInfoBean
import com.ckkj.defense_device.databinding.PersonalFragmentBinding
import com.ckkj.defense_device.liveVideo.LinkedUserActivity
import com.ckkj.defense_device.personal.FaceManagementActivity
import com.ckkj.defense_device.personal.PasswordManagementActivity
import com.ckkj.defense_device.personal.PersonalProfileActivity
import com.ckkj.defense_device.personal.SettingsMenusActivity
import com.ckkj.defense_device.utils.AppLanguage
import com.ckkj.defense_device.utils.LanguageUtil
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.ckkj.defense_device.utils.UserinfoUtil
import com.ckkj.defense_device.utils.ActivityManager
import com.ckkj.defense_device.view.CustomDialogFragmentText
import com.ckkj.defense_device.view.FamilySwitchDialog
import com.ckkj.defense_device.view.LanguageDialog
import com.ckkj.defense_device.view.LoadingDialog
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -34,6 +36,7 @@ class PersonalFragment : Fragment() {
// ViewBinding
private var _binding: PersonalFragmentBinding? = null
private val binding get() = _binding!!
private var loadingDialog: LoadingDialog? = null
override fun onResume() {
super.onResume()
fetchUserInfo()
@@ -49,10 +52,10 @@ class PersonalFragment : Fragment() {
.titleBar(binding.headerLayout)
.init()
Glide.with(this)
.load(R.drawable.img)
.load("")
.circleCrop()
.into(binding.ivAvatar)
binding.headerLayout.setOnClickListener {
binding.ivAvatar.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch {
try {
val response = RetrofitNetwork.getNetworkService().getUserInfo()
@@ -101,27 +104,40 @@ class PersonalFragment : Fragment() {
}
// 退出登录点击事件
binding.btnLogout.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch {
try {
val response = RetrofitNetwork.getNetworkService().logout()
withContext(Dispatchers.Main) {
if (response.code == 200) {
UserinfoUtil.clearUserInfo()
val intent = Intent(requireContext(), com.example.defenseapplication.login.LoginActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
requireActivity().finish()
} else {
Toast.makeText(requireContext(), getString(R.string.logout_fail), Toast.LENGTH_SHORT).show()
val dialog = CustomDialogFragmentText()
.setTitle(getString(R.string.tip))
.setMessage(getString(R.string.logout_confirm))
.setShowInput(false)
.setNegativeText(getString(R.string.cancel))
.setPositiveText(getString(R.string.confirm))
.setOnConfirmListener {
CoroutineScope(Dispatchers.IO).launch {
try {
val response = RetrofitNetwork.getNetworkService().logout()
withContext(Dispatchers.Main) {
if (response.code == 200) {
UserinfoUtil.clearUserInfo()
val intent = Intent(requireContext(), com.ckkj.defense_device.login.LoginActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
requireActivity().finish()
} else {
Toast.makeText(requireContext(), getString(R.string.logout_fail), Toast.LENGTH_SHORT).show()
}
}
} catch (e: Exception) {
e.printStackTrace()
withContext(Dispatchers.Main) {
Toast.makeText(requireContext(), getString(R.string.logout_fail), Toast.LENGTH_SHORT).show()
}
}
}
} catch (e: Exception) {
e.printStackTrace()
withContext(Dispatchers.Main) {
Toast.makeText(requireContext(), getString(R.string.logout_fail), Toast.LENGTH_SHORT).show()
}
}
}
dialog.show(childFragmentManager, "logout_dialog")
}
binding.ivMenu.setOnClickListener {
val intent = Intent(requireContext(), SettingsMenusActivity::class.java)
startActivity(intent)
}
fetchCurrentFamily()
return binding.root
@@ -220,6 +236,7 @@ class PersonalFragment : Fragment() {
private fun fetchUserInfo() {
loadingDialog = LoadingDialog(requireContext()).setMessage(getString(R.string.loading)).apply { show() }
CoroutineScope(Dispatchers.IO).launch {
try {
val response = RetrofitNetwork.getNetworkService().getUserInfo()
@@ -230,6 +247,11 @@ class PersonalFragment : Fragment() {
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
withContext(Dispatchers.Main) {
loadingDialog?.dismiss()
loadingDialog = null
}
}
}
}
@@ -243,8 +265,8 @@ class PersonalFragment : Fragment() {
}
userInfo.avatar?.let {
val requestOptions = RequestOptions()
.placeholder(R.drawable.img) // 加载中显示
.error(R.drawable.img) // 失败时显示
.placeholder(R.mipmap.img) // 加载中显示
.error(R.mipmap.img) // 失败时显示
Glide.with(this)
.load(it) // 如果 avatar 为 nullGlide 会直接回调 error
@@ -258,6 +280,7 @@ class PersonalFragment : Fragment() {
} else {
getString(R.string.member)
}
binding.tvRoleTag.visibility = View.VISIBLE
}
}

View File

@@ -1,14 +1,13 @@
package com.example.defenseapplication.home
package com.ckkj.defense_device.home
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.bean.AddDeviceBean
import com.example.defenseapplication.bean.DeviceBean
import com.example.defenseapplication.databinding.SetNameActivityBinding
import com.example.defenseapplication.liveVideo.LiveVideoActivity
import com.example.defenseapplication.utils.RetrofitNetwork
import com.ckkj.defense_device.bean.AddDeviceBean
import com.ckkj.defense_device.databinding.SetNameActivityBinding
import com.ckkj.defense_device.liveVideo.LiveVideoActivity
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -61,7 +60,9 @@ class SetNameActivity : AppCompatActivity() {
withContext(Dispatchers.Main) {
if (result.code == 200) {
Toast.makeText(this@SetNameActivity, "设备添加成功", Toast.LENGTH_SHORT).show()
startActivity(Intent(this@SetNameActivity, LiveVideoActivity::class.java))
startActivity(Intent(this@SetNameActivity, HomeActivity::class.java).apply {
putExtra(HomeActivity.EXTRA_REFRESH, true)
})
finish()
} else {
Toast.makeText(this@SetNameActivity, result.msg ?: "添加失败", Toast.LENGTH_SHORT).show()

View File

@@ -1,14 +1,15 @@
package com.example.defenseapplication.home
package com.ckkj.defense_device.home
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.databinding.ActivityStartBinding
import com.example.defenseapplication.login.LoginActivity
import com.example.defenseapplication.utils.ApiConfig
import com.example.defenseapplication.utils.UserinfoUtil
import com.ckkj.defense_device.databinding.ActivityStartBinding
import com.ckkj.defense_device.login.LoginActivity
import com.ckkj.defense_device.utils.ApiConfig
import com.ckkj.defense_device.utils.UserinfoUtil
import com.gyf.immersionbar.ImmersionBar
class StartActivity : AppCompatActivity() {
private lateinit var binding: ActivityStartBinding
@@ -17,6 +18,10 @@ class StartActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
binding = ActivityStartBinding.inflate(layoutInflater)
setContentView(binding.root)
ImmersionBar.with(this)
.statusBarDarkFont(true)
.titleBar(null)
.init()
// 延迟2秒后再判断登录状态
Handler(Looper.getMainLooper()).postDelayed({

View File

@@ -1,21 +1,22 @@
package com.example.defenseapplication.liveVideo
package com.ckkj.defense_device.liveVideo
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.defenseapplication.R
import com.example.defenseapplication.adapter.AddLinkedUserAdapter
import com.example.defenseapplication.adapter.UserItem
import com.example.defenseapplication.bean.AddDeviceUserRequest
import com.example.defenseapplication.bean.FamilyMembersBean
import com.example.defenseapplication.databinding.AddLinkedUserActivityBinding
import com.example.defenseapplication.utils.DeviceIdEvent
import com.example.defenseapplication.utils.DeviceUserUpdateEvent
import com.example.defenseapplication.utils.RetrofitNetwork
import com.ckkj.defense_device.R
import com.ckkj.defense_device.adapter.AddLinkedUserAdapter
import com.ckkj.defense_device.adapter.UserItem
import com.ckkj.defense_device.bean.AddDeviceUserRequest
import com.ckkj.defense_device.bean.FamilyMembersBean
import com.ckkj.defense_device.databinding.AddLinkedUserActivityBinding
import com.ckkj.defense_device.utils.DeviceIdEvent
import com.ckkj.defense_device.utils.DeviceUserUpdateEvent
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -95,19 +96,33 @@ class AddLinkedUserActivity : AppCompatActivity() {
Toast.makeText(this@AddLinkedUserActivity, "暂无家庭成员数据", Toast.LENGTH_SHORT).show()
}
} else {
hide()
Toast.makeText(this@AddLinkedUserActivity, "请求失败: ${response.msg}", Toast.LENGTH_SHORT).show()
}
}
} catch (e: Exception) {
android.util.Log.e("AddLinkedUserActivity", "网络请求异常", e)
withContext(Dispatchers.Main) {
binding.swipeRefresh.isRefreshing = false
noNetwork()
Toast.makeText(this@AddLinkedUserActivity, "网络请求失败: ${e.message}", Toast.LENGTH_SHORT).show()
}
}
}
}
private fun hide() {
binding.searchLayout.visibility = View.GONE
binding.rvAddLinkedUser.visibility = View.GONE
binding.butting?.visibility = View.GONE
binding.layoutNoPermission?.visibility = View.VISIBLE
}
private fun noNetwork() {
binding.searchLayout.visibility = View.GONE
binding.rvAddLinkedUser.visibility = View.GONE
binding.butting?.visibility = View.GONE
binding.layoutNoNetwork?.visibility = View.VISIBLE
}
private fun updateFamilyMemberList(familyMembersList: List<FamilyMembersBean>) {
fullUserItemList.clear()
familyMembersList.forEach { member ->

View File

@@ -1,9 +1,11 @@
package com.example.defenseapplication.liveVideo
package com.ckkj.defense_device.liveVideo
import android.content.Context
import android.graphics.Color
import android.media.AudioManager
import android.media.MediaScannerConnection
import android.os.Bundle
import android.os.Environment
import android.util.Log
import android.view.View
import android.widget.Toast
@@ -11,22 +13,28 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.lifecycle.lifecycleScope
import com.example.defenseapplication.R
import com.example.defenseapplication.adapter.AlarmLogAdapter
import com.example.defenseapplication.bean.DeviceAlarmBean
import com.example.defenseapplication.databinding.AlarmLogActivityBinding
import com.example.defenseapplication.utils.RetrofitNetwork
import com.ckkj.defense_device.R
import com.ckkj.defense_device.adapter.AlarmLogAdapter
import com.ckkj.defense_device.bean.DeviceAlarmBean
import com.ckkj.defense_device.databinding.AlarmLogActivityBinding
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder
import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack
import com.shuyu.gsyvideoplayer.utils.OrientationUtils
import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer
import com.bigkoo.pickerview.builder.TimePickerBuilder
import com.bigkoo.pickerview.listener.OnTimeSelectListener
import com.example.defenseapplication.view.MyGSYVideoPlayer
import com.shuyu.gsyvideoplayer.GSYVideoManager
import com.ckkj.defense_device.view.CustomDialogFragment
import com.ckkj.defense_device.view.LoadingDialog
import com.ckkj.defense_device.view.MyGSYVideoPlayer
import com.ckkj.defense_device.view.showDefenseDialog
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.launch
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
import android.net.Uri
import com.chiclaim.android.downloader.DownloadRequest
import com.chiclaim.android.downloader.DownloadListener
//告警记录
class AlarmLogActivity : AppCompatActivity() {
@@ -42,12 +50,16 @@ class AlarmLogActivity : AppCompatActivity() {
private var isMute = false
private lateinit var audioManager: AudioManager
private var isRightMenuVisible = false
private var currentAlarmItem: DeviceAlarmBean? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = AlarmLogActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
ImmersionBar.with(this)
.statusBarDarkFont(true)
.titleBar(null)
.init()
audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
deviceId = intent.getStringExtra("device_id")
@@ -77,8 +89,8 @@ class AlarmLogActivity : AppCompatActivity() {
.setLockLand(false)
.setShowFullAnimation(true)
.setNeedShowWifiTip(false)
.setEnlargeImageRes(R.drawable.full_size)
.setShrinkImageRes(R.drawable.full_screen)
.setEnlargeImageRes(R.mipmap.full_size)
.setShrinkImageRes(R.mipmap.full_screen)
.setBottomShowProgressBarDrawable(progressDrawable, thumbDrawable)
.setVideoAllCallBack(object : GSYSampleCallBack() {
override fun onPrepared(url: String?, vararg objects: Any?) {
@@ -132,8 +144,10 @@ class AlarmLogActivity : AppCompatActivity() {
}
private fun initRecyclerView() {
adapter = AlarmLogAdapter(alarmList) { item ->
currentAlarmItem = item
if (!item.video.isNullOrEmpty()) {
Toast.makeText(this, "该告警记录有视频", Toast.LENGTH_SHORT).show()
binding.exoPlayContextId.setUp(item.video, true, item.categoryName)
binding.exoPlayContextId.startPlayLogic()
} else {
Toast.makeText(this, "该告警记录没有视频", Toast.LENGTH_SHORT).show()
}
@@ -144,31 +158,24 @@ class AlarmLogActivity : AppCompatActivity() {
private fun fetchAlarmList() {
val currentDeviceId = deviceId ?: return
Log.d("AlarmLogActivity", "=== 开始请求设备告警日志 ===")
Log.d("AlarmLogActivity", "请求参数 - deviceId: $currentDeviceId")
isLoading = true
lifecycleScope.launch {
try {
Log.d("AlarmLogActivity", "正在发送网络请求...")
val response = RetrofitNetwork.getNetworkService().getDeviceAlarmList(
deviceId = currentDeviceId,
pageNum = "1",
pageSize = "10"
)
Log.d("AlarmLogActivity", "请求完成")
Log.d("AlarmLogActivity", "总条数: ${response.total}, 当前页数据条数: ${response.rows.size}")
val newData = response.rows
originalAlarmList.clear()
originalAlarmList.addAll(newData)
filterAlarmListByDate(calendar)
currentAlarmItem = alarmList.firstOrNull()
Log.d("AlarmLogActivity", "已获取 ${newData.size} 条数据")
} catch (e: Exception) {
Log.e("AlarmLogActivity", "请求异常: ${e.message}", e)
showAlarmListNetworkError()
} finally {
isLoading = false
Log.d("AlarmLogActivity", "请求结束")
@@ -176,14 +183,22 @@ class AlarmLogActivity : AppCompatActivity() {
}
}
private fun showEmptyView() {
binding.alarmListRecyclerView.visibility = View.GONE
binding.emptyLayout.visibility = View.VISIBLE
private fun updateAlarmListState() {
if (alarmList.isEmpty()) {
binding.alarmListRecyclerView.visibility = View.GONE
binding.layoutNoPermission.visibility = View.VISIBLE
binding.layoutNoNetwork.visibility = View.GONE
} else {
binding.alarmListRecyclerView.visibility = View.VISIBLE
binding.layoutNoPermission.visibility = View.GONE
binding.layoutNoNetwork.visibility = View.GONE
}
}
private fun hideEmptyView() {
binding.alarmListRecyclerView.visibility = View.VISIBLE
binding.emptyLayout.visibility = View.GONE
private fun showAlarmListNetworkError() {
binding.alarmListRecyclerView.visibility = View.GONE
binding.layoutNoPermission.visibility = View.GONE
binding.layoutNoNetwork.visibility = View.VISIBLE
}
private fun filterAlarmListByDate(selectedDate: Calendar) {
@@ -199,12 +214,13 @@ class AlarmLogActivity : AppCompatActivity() {
}
adapter?.notifyDataSetChanged()
Log.d("AlarmLogActivity", "日期筛选完成,筛选后条数: ${alarmList.size}")
if (alarmList.isEmpty()) {
showEmptyView()
currentAlarmItem = null
} else {
hideEmptyView()
currentAlarmItem = alarmList.firstOrNull()
}
updateAlarmListState()
}
private fun updateDateDisplay() {
@@ -220,22 +236,57 @@ class AlarmLogActivity : AppCompatActivity() {
}
binding.ivDownload.setOnClickListener {
Toast.makeText(this,"下载视频",Toast.LENGTH_SHORT).show()
// val item = currentAlarmItem
//
// if (item?.video.isNullOrEmpty()) {
// Toast.makeText(
// this,
// "没有可下载的视频",
// Toast.LENGTH_SHORT
// ).show()
// return@setOnClickListener
// }
showConfirmDialog(
getString(R.string.tip),
getString(R.string.download_alarm_video_confirm)
) {
//downloadVideo(item!!.video)
downloadVideo(
"https://media.w3.org/2010/05/sintel/trailer.mp4"
)
Toast.makeText(
this,
getString(R.string.download_start),
Toast.LENGTH_SHORT
).show()
}
}
binding.ivDelete.setOnClickListener {
val item = currentAlarmItem
if (item == null) {
Toast.makeText(this, "没有可删除的告警记录", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
showConfirmDialog(getString(R.string.tip), getString(R.string.delete_alarm_video_confirm)) {
val loadingDialog = LoadingDialog(this).setMessage("删除中...").apply { show() }
deleteAlarmItem(item.id, loadingDialog)
}
}
binding.ivMute.setOnClickListener {
isMute = !isMute
if (isMute) {
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 0, 0)
binding.ivMute.setImageResource(
R.drawable.mute
R.mipmap.mute
)
} else {
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) / 2, 0)
binding.ivMute.setImageResource(
R.drawable.un_mute
R.mipmap.un_mute
)
}
}
@@ -272,6 +323,102 @@ class AlarmLogActivity : AppCompatActivity() {
binding.exoPlayContextId.onVideoResume()
}
private fun showConfirmDialog(title: String, message: String, onConfirm: () -> Unit) {
val config = CustomDialogFragment.Config(
title = title,
message = message,
positiveText = getString(R.string.confirm),
negativeText = getString(R.string.cancel)
)
showDefenseDialog(config, onPositiveClick = { onConfirm() })
}
private fun downloadVideo(url: String) {
val dir = File(
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_MOVIES
),
"AlarmVideo"
)
if (!dir.exists()) {
dir.mkdirs()
}
val targetFile = File(
dir,
"${System.currentTimeMillis()}.mp4"
)
val request = DownloadRequest(
this,
url
)
.setDestinationUri(Uri.fromFile(targetFile))
.setNotificationTitle("${"视频名称"}:视频下载")
.registerListener(object : DownloadListener {
override fun onDownloadStart() {
Log.d("DOWNLOAD", "开始下载")
}
override fun onProgressUpdate(percent: Int) {
Log.d("DOWNLOAD", "进度:$percent%")
}
override fun onDownloadComplete(uri: Uri) {
MediaScannerConnection.scanFile(
this@AlarmLogActivity,
arrayOf(targetFile.absolutePath),
arrayOf("video/mp4"),
null
)
runOnUiThread {
ToastUtils.showSuccess(
this@AlarmLogActivity,
"下载成功"
)
}
}
override fun onDownloadFailed(e: Throwable) {
runOnUiThread {
ToastUtils.showError(
this@AlarmLogActivity,
"下载失败:${e.message}"
)
}
}
})
request.startDownload()
}
private fun deleteAlarmItem(id: String, loadingDialog: LoadingDialog) {
lifecycleScope.launch {
try {
val response = RetrofitNetwork.getNetworkService().deleteMessage(id)
if (response.code == 200) {
Toast.makeText(this@AlarmLogActivity, getString(R.string.delete_success), Toast.LENGTH_SHORT).show()
originalAlarmList.removeAll { it.id == id }
alarmList.removeAll { it.id == id }
adapter?.notifyDataSetChanged()
currentAlarmItem = alarmList.firstOrNull()
if (alarmList.isEmpty()) {
showAlarmListNetworkError()
}
} else {
Toast.makeText(this@AlarmLogActivity, response.msg, Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
Toast.makeText(this@AlarmLogActivity, "删除失败: ${e.message}", Toast.LENGTH_SHORT).show()
} finally {
loadingDialog.dismiss()
}
}
}
override fun onDestroy() {
super.onDestroy()

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.liveVideo
package com.ckkj.defense_device.liveVideo
import android.content.Intent
import android.graphics.Color
@@ -8,12 +8,12 @@ import java.util.Calendar
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.AutoModeActivityBinding
import com.example.defenseapplication.utils.DeviceIdEvent
import com.example.defenseapplication.utils.DeviceUpdateEvent
import com.example.defenseapplication.utils.RetrofitNetwork
import com.example.defenseapplication.view.AutoModeNoticeDialog
import com.ckkj.defense_device.R
import com.ckkj.defense_device.databinding.AutoModeActivityBinding
import com.ckkj.defense_device.utils.DeviceIdEvent
import com.ckkj.defense_device.utils.DeviceUpdateEvent
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.ckkj.defense_device.view.AutoModeNoticeDialog
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -31,6 +31,7 @@ class AutoModeActivity : AppCompatActivity() {
private var selectedStartMinute = 0
private var selectedEndHour = 10
private var selectedEndMinute = 0
private var optionPassword: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -42,6 +43,8 @@ class AutoModeActivity : AppCompatActivity() {
.titleBar(binding.topBar)
.init()
optionPassword = intent.getStringExtra("optionPassword")
initListener()
loadCurrentSettings()
@@ -173,11 +176,12 @@ class AutoModeActivity : AppCompatActivity() {
CoroutineScope(Dispatchers.IO).launch {
try {
val deviceBean = com.example.defenseapplication.bean.DeviceBean(
val deviceBean = com.ckkj.defense_device.bean.DeviceBean(
id = deviceId,
workMode = selectedMode,
startTime = startTime,
endTime = endTime
endTime = endTime,
optionPassword = optionPassword
)
val response = RetrofitNetwork.getNetworkService().updateDeviceInfo(deviceBean)
withContext(Dispatchers.Main) {

View File

@@ -1,12 +1,11 @@
package com.example.defenseapplication.liveVideo
package com.ckkj.defense_device.liveVideo
import android.os.Bundle
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.databinding.DeviceInfoActivityBinding
import com.example.defenseapplication.utils.DeviceIdEvent
import com.example.defenseapplication.utils.RetrofitNetwork
import com.ckkj.defense_device.databinding.DeviceInfoActivityBinding
import com.ckkj.defense_device.utils.DeviceIdEvent
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -55,9 +54,9 @@ class DeviceInfoActivity : AppCompatActivity() {
}
}
private fun updateDeviceInfo(device: com.example.defenseapplication.bean.DeviceBean) {
binding.tvDeviceModelValue.text = device.deviceNo.toString()
binding.tvDeviceNoValue.text = device.deviceSn.toString()
binding.tvFwVersionValue.text = device.fwVer.toString()
private fun updateDeviceInfo(device: com.ckkj.defense_device.bean.DeviceBean) {
binding.tvDeviceModelValue.text = device.deviceNo?.toString()?: ""
binding.tvDeviceNoValue.text = device.deviceSn?.toString() ?: ""
binding.tvFwVersionValue.text = device.fwVer?.toString()?: ""
}
}

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.liveVideo
package com.ckkj.defense_device.liveVideo
import android.content.Intent
import android.os.Bundle
@@ -11,22 +11,22 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.R
import com.example.defenseapplication.adapter.LinkedUser
import com.example.defenseapplication.adapter.LinkedUserAdapter
import com.example.defenseapplication.bean.DeleteDeviceUserRequest
import com.example.defenseapplication.bean.DeviceUserBean
import com.example.defenseapplication.bean.FamilyMembersBean
import com.example.defenseapplication.bean.VerifyOptionPasswordRequest
import com.example.defenseapplication.databinding.LinkedUserActivityBinding
import com.example.defenseapplication.personal.PasswordInputDialog
import com.example.defenseapplication.utils.DeviceIdEvent
import com.example.defenseapplication.utils.DeviceUserUpdateEvent
import com.example.defenseapplication.utils.RetrofitNetwork
import com.example.defenseapplication.view.CustomDialogFragmentText
import com.ckkj.defense_device.R
import com.ckkj.defense_device.adapter.LinkedUser
import com.ckkj.defense_device.adapter.LinkedUserAdapter
import com.ckkj.defense_device.bean.DeleteDeviceUserRequest
import com.ckkj.defense_device.bean.DeviceUserBean
import com.ckkj.defense_device.bean.FamilyMembersBean
import com.ckkj.defense_device.bean.VerifyOptionPasswordRequest
import com.ckkj.defense_device.databinding.LinkedUserActivityBinding
import com.ckkj.defense_device.personal.PasswordInputDialog
import com.ckkj.defense_device.utils.DeviceIdEvent
import com.ckkj.defense_device.utils.DeviceUserUpdateEvent
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.ckkj.defense_device.view.CustomDialogFragmentText
import com.ckkj.defense_device.view.PullRefreshLayout
import com.gyf.immersionbar.ImmersionBar
import com.yanzhenjie.recyclerview.SwipeMenuItem
import com.yanzhenjie.recyclerview.SwipeRecyclerView
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -96,9 +96,11 @@ class LinkedUserActivity : AppCompatActivity() {
(binding.rvLinkedUser as RecyclerView).layoutManager = LinearLayoutManager(this)
binding.swipeRefresh.setOnRefreshListener {
fetchUserList()
}
binding.swipeRefresh.setOnRefreshListener(object : PullRefreshLayout.OnRefreshListener {
override fun onRefresh() {
fetchUserList()
}
})
binding.rvLinkedUser.setSwipeMenuCreator { leftMenu, rightMenu, position ->
if (mode == MODE_SETTINGS) {
@@ -230,7 +232,6 @@ class LinkedUserActivity : AppCompatActivity() {
}
private fun fetchUserList() {
binding.swipeRefresh.isRefreshing = true
lifecycleScope.launch {
try {
var deviceId: String? = null
@@ -239,7 +240,7 @@ class LinkedUserActivity : AppCompatActivity() {
if (deviceId.isNullOrEmpty()) {
Toast.makeText(this@LinkedUserActivity, "设备 ID 为空", Toast.LENGTH_SHORT).show()
withContext(Dispatchers.Main) {
binding.swipeRefresh.isRefreshing = false
binding.swipeRefresh.finishRefresh()
}
return@launch
}
@@ -250,7 +251,7 @@ class LinkedUserActivity : AppCompatActivity() {
RetrofitNetwork.getNetworkService().getFamilyMembers()
}
withContext(Dispatchers.Main) {
binding.swipeRefresh.isRefreshing = false
binding.swipeRefresh.finishRefresh()
if (response.code == 200 && response.data != null) {
if (mode == MODE_SETTINGS) {
updateDeviceUserList(response.data as List<DeviceUserBean>)
@@ -258,18 +259,32 @@ class LinkedUserActivity : AppCompatActivity() {
updateFamilyMembersList(response.data as List<FamilyMembersBean>)
}
} else {
hide()
Toast.makeText(this@LinkedUserActivity, response.msg, Toast.LENGTH_SHORT).show()
}
}
} catch (e: Exception) {
e.printStackTrace()
withContext(Dispatchers.Main) {
binding.swipeRefresh.isRefreshing = false
Toast.makeText(this@LinkedUserActivity, "网络请求失败", Toast.LENGTH_SHORT).show()
binding.swipeRefresh.finishRefresh()
noNetwork()
Toast.makeText(this@LinkedUserActivity, R.string.network_request_failed, Toast.LENGTH_SHORT).show()
}
}
}
}
private fun hide() {
binding.searchLayout.visibility = View.GONE
binding.rvLinkedUser.visibility = View.GONE
binding.butting?.visibility = View.GONE
binding.layoutNoPermission?.visibility = View.VISIBLE
}
private fun noNetwork() {
binding.searchLayout.visibility = View.GONE
binding.rvLinkedUser.visibility = View.GONE
binding.butting?.visibility = View.GONE
binding.layoutNoNetwork?.visibility = View.VISIBLE
}
private fun updateDeviceUserList(deviceUserList: List<DeviceUserBean>) {
fullUserList.clear()
@@ -339,7 +354,7 @@ class LinkedUserActivity : AppCompatActivity() {
binding.fabAdd.setOnClickListener {
if (checkUserLimit()) {
val intent = Intent(this, com.example.defenseapplication.personal.InvitationCodeActivity::class.java)
val intent = Intent(this, com.ckkj.defense_device.personal.InvitationCodeActivity::class.java)
startActivity(intent)
}
}

View File

@@ -0,0 +1,484 @@
package com.ckkj.defense_device.liveVideo
import android.content.Intent
import android.content.res.Configuration
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.view.MotionEvent
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.ckkj.defense_device.R
import com.ckkj.defense_device.adapter.AlarmLogHorizontalAdapter
import com.ckkj.defense_device.base.BaseActivity
import com.ckkj.defense_device.bean.DeviceAlarmBean
import com.ckkj.defense_device.databinding.LiveVideoActivityBinding
import com.ckkj.defense_device.utils.ActivityManager
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.gyf.immersionbar.ImmersionBar
import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder
import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack
import com.shuyu.gsyvideoplayer.utils.OrientationUtils
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import androidx.lifecycle.lifecycleScope
import android.os.Handler
import android.os.Looper
import com.ckkj.defense_device.bean.VideoStreamInfo
import com.ckkj.defense_device.bean.VideoStreamRequest
import com.ckkj.defense_device.view.MyGSYVideoPlayerLive
class LiveVideoActivity : BaseActivity() {
private lateinit var binding: LiveVideoActivityBinding
private var isVoiceEnabled = false
private var isLightOn = false
private var isConsoleVisible = false
private var deviceId: String? = null
private var deviceNo: String? = null
private var alarmList: MutableList<DeviceAlarmBean> = mutableListOf()
private var alarmAdapter: AlarmLogHorizontalAdapter? = null
private var currentPage = 1
private var totalPage = 1
private val pageSize = 10
private var hasMore = true
private var isLoading = false
private var orientationUtils: OrientationUtils? = null
private val ptzHandler = Handler(Looper.getMainLooper())
private var currentPtzDirection: String? = null
private var streamUrl: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("onEnterFullscreen", "onCreate")
binding = LiveVideoActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
ImmersionBar.with(this)
.statusBarDarkFont(true)
.titleBar(binding.topBar)
.init()
deviceId = intent.getStringExtra("device_id")
val deviceName = intent.getStringExtra("device_name")
deviceNo = intent.getStringExtra("deviceNo")
val light = intent.getStringExtra("light")
if (!deviceName.isNullOrEmpty()) {
binding.tvTitle.text = deviceName
}
initVideoPlayer()
initAlarmRecyclerView()
initListener()
fetchAlarmList()
}
/*
* 这段代码重写了onConfigurationChanged方法用于监听屏幕方向变化
当屏幕旋转为横屏时隐藏顶部栏topBar
当屏幕为竖屏时,显示顶部栏
目的是在横屏观看视频时提供更沉浸的全屏体验。
* */
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
binding.topBar.visibility = View.GONE
} else {
binding.topBar.visibility = View.VISIBLE
}
}
private fun initVideoPlayer() {
orientationUtils = OrientationUtils(this, binding.exoPlayContextId)
orientationUtils?.isEnable = true
hidePlayerControls()
fetchStreamUrl()
}
private fun fetchStreamUrl() {
val no = deviceNo ?: return
lifecycleScope.launch {
try {
val response = RetrofitNetwork.getNetworkService().videoStart(VideoStreamRequest(no))
Log.d("直播流开始", "code=${response.code}, msg=${response.msg}")
if (response.code == 200 && response.data != null) {
//flv(http) 支持IjkPlayer最好
//hls(.m3u8) 支持ExoPlayer/Ijk都支持
//rtmp IjkPlayer支持Exo默认不支持
//rtsp IjkPlayer支持
//webrtcGSYVideoPlayer 不支持
streamUrl = response.data.playUrls.flv
Log.d("直播流开始", "获取地址:$streamUrl")
setupVideoPlayer(streamUrl!!)
} else {
Log.e("直播流开始", response.msg)
}
} catch (e: Exception) {
Log.e("直播流开始", "异常", e)
}
}
}
private fun setupVideoPlayer(videoUrl: String) {
GSYVideoOptionBuilder()
.setUrl(videoUrl)
.setCacheWithPlay(false)
.setRotateViewAuto(true)
.setLockLand(false)
.setShowFullAnimation(true)
.setNeedShowWifiTip(false)
.setEnlargeImageRes(R.drawable.full_size)
.setShrinkImageRes(R.drawable.full_screen)
.setVideoAllCallBack(object : GSYSampleCallBack() {
override fun onPrepared(url: String?, vararg objects: Any?) {
super.onPrepared(url, *objects)
orientationUtils?.isEnable = true
}
override fun onQuitFullscreen(url: String?, vararg objects: Any?) {
super.onQuitFullscreen(url, *objects)
orientationUtils?.backToProtVideo()
}
})
.build(binding.exoPlayContextId)
binding.exoPlayContextId.startPlayLogic()
binding.exoPlayContextId.fullscreenButton.setOnClickListener {
binding.exoPlayContextId.onPtzControlListener =
object : MyGSYVideoPlayerLive.OnPtzControlListener {
override fun onStartPtz(direction: String) {
val no = deviceNo ?: return
startPtz(deviceNo = no, direction = direction)
}
override fun onStopPtz() {
stopCurrentPtz()
}
override fun onShoot() {
deviceNo?.let { shoot(it) }
}
}
orientationUtils?.resolveByClick()
binding.exoPlayContextId.startWindowFullscreen(this, true, true)
}
}
private fun hidePlayerControls() {
binding.exoPlayContextId.backButton.visibility = View.GONE
binding.exoPlayContextId.titleTextView.visibility = View.GONE
binding.exoPlayContextId.startButton.visibility = View.GONE
binding.exoPlayContextId.findViewById<View>(
com.shuyu.gsyvideoplayer.R.id.current
)?.visibility = View.GONE
binding.exoPlayContextId.findViewById<View>(
com.shuyu.gsyvideoplayer.R.id.total
)?.visibility = View.GONE
binding.exoPlayContextId.findViewById<View>(
com.shuyu.gsyvideoplayer.R.id.progress
)?.visibility = View.INVISIBLE
binding.exoPlayContextId.findViewById<View>(
com.shuyu.gsyvideoplayer.R.id.start
)?.visibility = View.GONE
binding.exoPlayContextId.findViewById<View>(
com.shuyu.gsyvideoplayer.R.id.layout_bottom
)?.setBackgroundColor(Color.TRANSPARENT)
}
private fun initAlarmRecyclerView() {
val layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
binding.alarmLogRecyclerView.layoutManager = layoutManager
alarmAdapter = AlarmLogHorizontalAdapter(alarmList) { messageBean ->
val intent = Intent(this, AlarmLogActivity::class.java)
intent.putExtra("device_id", deviceId)
intent.putExtra("selected_id", messageBean.id)
intent.putExtra("video_url", messageBean.video)
intent.putExtra("create_time", messageBean.createTime)
intent.putExtra("from_live_video", true)
startActivity(intent)
}
binding.alarmLogRecyclerView.adapter = alarmAdapter
binding.alarmLogRecyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (dx > 0 && !isLoading && hasMore) {
val lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition()
if (lastVisibleItemPosition == alarmList.size - 1) {
loadMoreAlarms()
}
}
}
})
}
private fun loadMoreAlarms() {
if (!hasMore || isLoading) return
currentPage++
if (currentPage > totalPage) {
hasMore = false
return
}
fetchAlarmList(currentPage)
}
private fun initListener() {
binding.btnBack.setOnClickListener {
ActivityManager.finishExceptHome()
val intent = Intent(this, com.ckkj.defense_device.home.HomeActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
startActivity(intent)
finish()
}
binding.ivMenu.setOnClickListener {
val intent = Intent(this, SettingsActivity::class.java)
startActivity(intent)
}
binding.llLight.setOnClickListener {
isLightOn = !isLightOn
if (isLightOn) {
binding.ivLight.setImageResource(com.ckkj.defense_device.R.mipmap.light_on_open)
} else {
binding.ivLight.setImageResource(com.ckkj.defense_device.R.mipmap.light_on)
}
}
binding.xq.setOnClickListener {
val intent = Intent(this, AlarmLogActivity::class.java)
intent.putExtra("device_id", deviceId)
intent.putExtra("from_live_video", true)
startActivity(intent)
}
binding.llRecord.setOnClickListener {
isConsoleVisible = !isConsoleVisible
if (isConsoleVisible) {
binding.llAlarmLog.visibility = View.GONE
binding.consoleBar.visibility = View.VISIBLE
binding.ivRecord.setImageResource(R.mipmap.copy_open)
} else {
binding.llAlarmLog.visibility = View.VISIBLE
binding.consoleBar.visibility = View.GONE
binding.ivRecord.setImageResource(R.mipmap.copy)
}
}
binding.llVoice.setOnClickListener {
isVoiceEnabled = !isVoiceEnabled
if (isVoiceEnabled) {
Glide.with(this)
.asGif()
.load(R.mipmap.voice_open)
.into(binding.ivVoice)
} else {
binding.ivVoice.setImageResource(R.mipmap.voice)
}
}
binding.ivUp.setOnTouchListener { v, event ->
handlePtzTouch(
view = v,
event = event,
direction = "up",
action = { deviceNo }
)
}
binding.ivDown.setOnTouchListener { v, event ->
handlePtzTouch(
view = v,
event = event,
direction = "down",
action = { deviceNo }
)
}
binding.ivLeft.setOnTouchListener { v, event ->
handlePtzTouch(
view = v,
event = event,
direction = "left",
action = { deviceNo }
)
}
binding.ivRight.setOnTouchListener { v, event ->
handlePtzTouch(
view = v,
event = event,
direction = "right",
action = { deviceNo }
)
}
}
private fun handlePtzTouch(
view: View,
event: MotionEvent,
direction: String,
action: () -> String?
): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN -> {
view.isPressed = true
val deviceNo = action()
if (!deviceNo.isNullOrEmpty()) {
startPtz(deviceNo = deviceNo, direction = direction)
}
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
view.isPressed = false
stopCurrentPtz()
}
}
return true
}
private fun startPtz(deviceNo: String, direction: String) {
stopCurrentPtz()
currentPtzDirection = direction
lifecycleScope.launch {
try {
val response = when (direction) {
"up" -> RetrofitNetwork.getNetworkService().ptzUp(deviceNo)
"down" -> RetrofitNetwork.getNetworkService().ptzDown(deviceNo)
"left" -> RetrofitNetwork.getNetworkService().ptzLeft(deviceNo)
"right" -> RetrofitNetwork.getNetworkService().ptzRight(deviceNo)
else -> null
}
Log.d("LV", "PTZ $direction start response: ${response?.code}")
} catch (e: Exception) {
Log.e("LV", "PTZ $direction start failed", e)
}
}
}
private fun shoot(deviceNo: String) {
Log.d("LV", "btnCapture click, deviceNo=$deviceNo, duration=0")
lifecycleScope.launch {
try {
val response = RetrofitNetwork.getNetworkService().ptzShoot(
deviceNo = deviceNo,
duration = "0"
)
Log.d("LV", "PTZ shoot response: code=${response.code}, msg=${response.msg}")
} catch (e: Exception) {
Log.e("LV", "PTZ shoot failed", e)
}
}
}
private fun stopCurrentPtz() {
val direction = currentPtzDirection ?: return
currentPtzDirection = null
lifecycleScope.launch {
try {
val response = RetrofitNetwork.getNetworkService().ptzStop(deviceNo ?: return@launch)
Log.d("LV", "PTZ $direction stop response: ${response.code}")
} catch (e: Exception) {
Log.e("LV", "PTZ $direction stop failed", e)
}
}
}
private fun fetchAlarmList(page: Int = 1) {
val currentDeviceId = deviceId ?: return
isLoading = true
lifecycleScope.launch {
try {
val response = RetrofitNetwork.getNetworkService().getDeviceAlarmList(
deviceId = currentDeviceId,
pageNum = page.toString(),
pageSize = pageSize.toString()
)
Log.d("LiveVideoActivity", "总条数: ${response.total}, 当前页数据条数: ${response.rows.size}")
val newData = response.rows
totalPage = if (response.total % pageSize == 0) {
response.total / pageSize
} else {
response.total / pageSize + 1
}
if (page == 1) {
alarmList.clear()
hasMore = totalPage > 1
}
alarmList.addAll(newData)
alarmAdapter?.notifyDataSetChanged()
updateAlarmListState()
} catch (e: Exception) {
Log.e("LiveVideoActivity", "请求告警列表失败", e)
hasMore = false
showAlarmListNetworkError()
} finally {
isLoading = false
}
}
}
private fun updateAlarmListState() {
if (alarmList.isEmpty()) {
binding.alarmLogRecyclerView.visibility = View.GONE
binding.layoutNoPermission.visibility = View.VISIBLE
binding.layoutNoNetwork.visibility = View.GONE
} else {
binding.alarmLogRecyclerView.visibility = View.VISIBLE
binding.layoutNoPermission.visibility = View.GONE
binding.layoutNoNetwork.visibility = View.GONE
}
}
private fun showAlarmListNetworkError() {
binding.alarmLogRecyclerView.visibility = View.GONE
binding.layoutNoPermission.visibility = View.GONE
binding.layoutNoNetwork.visibility = View.VISIBLE
}
override fun onResume() {
super.onResume()
binding.exoPlayContextId.onVideoResume()
}
override fun onPause() {
super.onPause()
binding.exoPlayContextId.onVideoPause()
}
override fun onDestroy() {
super.onDestroy()
ptzHandler.removeCallbacksAndMessages(null)
orientationUtils?.releaseListener()
binding.exoPlayContextId.release()
stopStream()
}
private fun stopStream() {
val no = deviceNo ?: return
GlobalScope.launch {
try {
val response = RetrofitNetwork.getNetworkService().videoStop(no)
Log.d("直播流停止", "videoStop response: code=${response.code}, msg=${response.msg}")
} catch (e: Exception) {
Log.e("直播流停止", "停止推流异常", e)
}
}
}
}

View File

@@ -1,19 +1,19 @@
package com.example.defenseapplication.liveVideo
package com.ckkj.defense_device.liveVideo
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.lifecycle.lifecycleScope
import com.example.defenseapplication.R
import com.example.defenseapplication.base.BaseActivity
import com.example.defenseapplication.databinding.SettingsActivityBinding
import com.example.defenseapplication.utils.DeviceIdEvent
import com.example.defenseapplication.utils.RetrofitNetwork
import com.example.defenseapplication.view.CustomDialogFragmentText
import com.example.defenseapplication.view.RecognitionModeDialog
import com.example.defenseapplication.bean.VerifyOptionPasswordRequest
import com.example.defenseapplication.personal.PasswordInputDialog
import com.ckkj.defense_device.R
import com.ckkj.defense_device.base.BaseActivity
import com.ckkj.defense_device.databinding.SettingsActivityBinding
import com.ckkj.defense_device.utils.DeviceIdEvent
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.ckkj.defense_device.view.CustomDialogFragmentText
import com.ckkj.defense_device.view.RecognitionModeDialog
import com.ckkj.defense_device.bean.VerifyOptionPasswordRequest
import com.ckkj.defense_device.personal.PasswordInputDialog
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -27,6 +27,7 @@ class SettingsActivity : BaseActivity() {
private var alertAudio: String? = null
private var audioContent: String? = null
private var isPasswordVerified = false
private var verifiedPassword: String? = null
override fun onResume() {
super.onResume()
@@ -55,15 +56,15 @@ class SettingsActivity : BaseActivity() {
if (isPasswordVerified) {
val dialog = RecognitionModeDialog(this)
dialog.setOnConfirmListener { mode ->
updateRecognitionMode(mode)
updateRecognitionMode(mode, verifiedPassword)
}
dialog.show()
} else {
showPasswordDialog {
showPasswordDialog { inputPassword ->
isPasswordVerified = true
val dialog = RecognitionModeDialog(this)
dialog.setOnConfirmListener { mode ->
updateRecognitionMode(mode)
updateRecognitionMode(mode, inputPassword)
}
dialog.show()
}
@@ -94,22 +95,24 @@ class SettingsActivity : BaseActivity() {
}
binding.itemWaterGunSetting.setOnClickListener {
if (isPasswordVerified) {
navigateToWaterGunSettings()
navigateToWaterGunSettings(verifiedPassword)
} else {
showPasswordDialog {
showPasswordDialog { inputPassword ->
isPasswordVerified = true
navigateToWaterGunSettings()
navigateToWaterGunSettings(inputPassword)
}
}
}
binding.itemAutoMode.setOnClickListener {
if (isPasswordVerified) {
val intent = Intent(this, AutoModeActivity::class.java)
intent.putExtra("optionPassword", verifiedPassword)
startActivity(intent)
} else {
showPasswordDialog {
showPasswordDialog { inputPassword ->
isPasswordVerified = true
val intent = Intent(this, AutoModeActivity::class.java)
intent.putExtra("optionPassword", inputPassword)
startActivity(intent)
}
}
@@ -183,7 +186,7 @@ class SettingsActivity : BaseActivity() {
binding.tvRelatedUsers.text = "$count"
}
private fun updateDeviceInfo(device: com.example.defenseapplication.bean.DeviceBean) {
private fun updateDeviceInfo(device: com.ckkj.defense_device.bean.DeviceBean) {
binding.tvDeviceName.text = device.deviceName ?: "未设置"
binding.tvWifiName.text = device.wifiName ?: "未设置"
@@ -236,7 +239,7 @@ class SettingsActivity : BaseActivity() {
CoroutineScope(Dispatchers.IO).launch {
try {
val deviceBean = com.example.defenseapplication.bean.DeviceBean(
val deviceBean = com.ckkj.defense_device.bean.DeviceBean(
id = deviceId,
deviceName = name,
)
@@ -258,7 +261,7 @@ class SettingsActivity : BaseActivity() {
}
}
private fun updateRecognitionMode(mode: String) {
private fun updateRecognitionMode(mode: String, optionPassword: String?) {
val deviceId = DeviceIdEvent.getDeviceId()
if (deviceId.isNullOrEmpty()) {
Toast.makeText(this, "设备ID为空", Toast.LENGTH_SHORT).show()
@@ -273,9 +276,10 @@ class SettingsActivity : BaseActivity() {
CoroutineScope(Dispatchers.IO).launch {
try {
val deviceBean = com.example.defenseapplication.bean.DeviceBean(
val deviceBean = com.ckkj.defense_device.bean.DeviceBean(
id = deviceId,
patternPerception = patternPerception,
optionPassword = optionPassword
)
val response = RetrofitNetwork.getNetworkService().updateDeviceInfo(deviceBean)
withContext(Dispatchers.Main) {
@@ -305,13 +309,13 @@ class SettingsActivity : BaseActivity() {
CoroutineScope(Dispatchers.IO).launch {
try {
val deleteBean = com.example.defenseapplication.bean.DeleteBean()
val deleteBean = com.ckkj.defense_device.bean.DeleteBean()
deleteBean.deviceId = deviceId
val response = RetrofitNetwork.getNetworkService().deleteDevice(deleteBean)
withContext(Dispatchers.Main) {
if (response.code == 200) {
Toast.makeText(this@SettingsActivity, "解绑成功", Toast.LENGTH_SHORT).show()
val intent = Intent(this@SettingsActivity, com.example.defenseapplication.home.HomeActivity::class.java)
val intent = Intent(this@SettingsActivity, com.ckkj.defense_device.home.HomeActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
finish()
@@ -328,7 +332,7 @@ class SettingsActivity : BaseActivity() {
}
}
private fun showPasswordDialog(onVerified: () -> Unit) {
private fun showPasswordDialog(onVerified: (String) -> Unit) {
passwordDialog = PasswordInputDialog(this).apply {
setOnConfirmListener { inputPassword ->
CoroutineScope(Dispatchers.IO).launch {
@@ -338,7 +342,8 @@ class SettingsActivity : BaseActivity() {
withContext(Dispatchers.Main) {
if (response.code == 200) {
dismiss()
onVerified()
verifiedPassword = inputPassword
onVerified(inputPassword)
} else {
Toast.makeText(
this@SettingsActivity,
@@ -365,8 +370,9 @@ class SettingsActivity : BaseActivity() {
passwordDialog.show()
}
private fun navigateToWaterGunSettings() {
private fun navigateToWaterGunSettings(optionPassword: String? = null) {
val intent = Intent(this, WaterGunSettingsActivity::class.java)
intent.putExtra("optionPassword", optionPassword)
val deviceId = DeviceIdEvent.getDeviceId()
if (!deviceId.isNullOrEmpty()) {
CoroutineScope(Dispatchers.IO).launch {

View File

@@ -1,17 +1,17 @@
package com.example.defenseapplication.liveVideo
package com.ckkj.defense_device.liveVideo
import android.animation.ObjectAnimator
import android.os.Bundle
import android.widget.ImageView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.R
import com.example.defenseapplication.bean.DeviceBean
import com.example.defenseapplication.databinding.StrikePositionActivityBinding
import com.example.defenseapplication.utils.DeviceIdEvent
import com.example.defenseapplication.utils.RetrofitNetwork
import com.example.defenseapplication.view.CustomDialogFragment
import com.example.defenseapplication.view.showDefenseDialog
import com.ckkj.defense_device.R
import com.ckkj.defense_device.bean.DeviceBean
import com.ckkj.defense_device.databinding.StrikePositionActivityBinding
import com.ckkj.defense_device.utils.DeviceIdEvent
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.ckkj.defense_device.view.CustomDialogFragment
import com.ckkj.defense_device.view.showDefenseDialog
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -45,7 +45,7 @@ class StrikePositionActivity : AppCompatActivity() {
private var selectedZone: Zone = Zone.CHEST
// Touch tracking for ImageView (captured in onTouch, used in ACTION_UP for click detection)
// ImageView 的触控追踪(在 onTouch 中捕获ACTION_UP 用于点击检测)
private var lastTouchX = 0f
private var lastTouchY = 0f
@@ -67,7 +67,7 @@ class StrikePositionActivity : AppCompatActivity() {
binding.ivBack.setOnClickListener { finish() }
binding.btnSubmit.setOnClickListener { showConfirmDialog() }
// Use OnTouchListener to track touch coordinates
// 使用 OnTouchListen 来跟踪触摸坐标
binding.ivHumanBody.setOnTouchListener { _, event ->
lastTouchX = event.x
lastTouchY = event.y
@@ -77,7 +77,7 @@ class StrikePositionActivity : AppCompatActivity() {
false
}
// OnClick fires on ACTION_UP; coordinates captured from lastTouchX/Y
// OnClick 对ACTION_UP开火;坐标来自lastTouchXY
binding.ivHumanBody.setOnClickListener {
val imageView = it as ImageView
val (nx, ny) = resolveTapLocation(lastTouchX, lastTouchY, imageView)
@@ -100,10 +100,12 @@ class StrikePositionActivity : AppCompatActivity() {
}
/**
* Converts a screen coordinate (from onTouch) into a normalised [0..1] offset
* inside the drawable, accounting for:
* - ImageView scaling (scaleType="fitCenter" adds letterboxing)
* - Letterbox / pillarbox margins when image aspect view aspect
* 这段代码将触摸坐标转换为图片内部的归一化位置
*
* 1. 计算图片等比缩放后的实际尺寸
* 2. 计算letterbox/pillarbox的偏移量
* 3. 将触摸点限制在图片有效区域内
* 4. 返回相对于图片的归一化坐标(0-1范围)
*/
private fun resolveTapLocation(rawX: Float, rawY: Float, imageView: ImageView): Pair<Float, Float> {
val drawable = imageView.drawable ?: return Pair(0f, 0f)
@@ -114,22 +116,22 @@ class StrikePositionActivity : AppCompatActivity() {
val intrinsicWidth = drawable.intrinsicWidth.toFloat()
val intrinsicHeight = drawable.intrinsicHeight.toFloat()
// scale: the uniform factor the image is scaled by to fit the view
// 比例:图像被缩放以适应视图的均匀因子
val scale = min(ivWidth / intrinsicWidth, ivHeight / intrinsicHeight)
// Physical pixel size of the drawable after scaling
// 缩放后绘制的物理像素大小
val drawnW = intrinsicWidth * scale
val drawnH = intrinsicHeight * scale
// Letterbox offsets (top / left) when aspect ratios differ
// 当宽高比不同时,信箱偏移(左上角)
val drawableLeft = (ivWidth - drawnW) / 2f
val drawableTop = (ivHeight - drawnH) / 2f
// Clamp touch to the actual drawable area
// 夹紧触地接触实际可绘制区域
val clampedX = max(drawableLeft, min(rawX, drawableLeft + drawnW))
val clampedY = max(drawableTop, min(rawY, drawableTop + drawnH))
// Normalised offset [0..1] within the drawable
// 可绘制物内的归一化偏移 [0..1]
val normalizedX = (clampedX - drawableLeft) / drawnW
val normalizedY = (clampedY - drawableTop) / drawnH
@@ -137,14 +139,11 @@ class StrikePositionActivity : AppCompatActivity() {
}
/**
* Zones are divided by:
* - Horizontal boundary at ny = 0.5 top = HEAD, bottom = shoulders
* - Vertical boundary 1 at nx = 1/3 left = LEFT_SHOULDER
* - Vertical boundary 2 at nx = 2/3 right = RIGHT_SHOULDER, middle = CHEST
* 这段代码根据归一化坐标确定触摸区域
*
* If the touch falls within ±tolerance of any boundary line, the nearest
* zone centre (Euclidean distance in normalised space) is used to avoid
* arbitrary assignments at boundary pixels.
* 1. 将图片分为头部左肩胸部右肩四个区域
* 2. 边界附近±0.04范围内使用最近区域中心避免误判
* 3. 上半部分为头部下半部分按1/3和2/3垂直线划分
*/
private fun zoneForLocation(nx: Float, ny: Float): Zone {
val hBoundary = 0.5f
@@ -168,7 +167,14 @@ class StrikePositionActivity : AppCompatActivity() {
}
}
/** Returns the Zone whose normalised centre is closest (Euclidean) to (nx, ny). */
/**
* 这段代码找到距离触摸点最近的区域
*
* 1. 遍历所有Zone计算与触摸点的欧氏距离平方
* 2. 返回距离最小的Zone作为结果
* 3. 若无匹配则默认返回CHEST
* */
private fun nearestZone(nx: Float, ny: Float): Zone {
return Zone.values().minByOrNull { zone ->
val dx = nx - zone.normalizedX
@@ -178,12 +184,12 @@ class StrikePositionActivity : AppCompatActivity() {
}
/**
* Positions the marker (ivStrikeMarker) at the zone's centre, clamped so the
* marker never goes out of the ivHumanBody bounds.
*
* Because the marker is a child of ivHumanBody and starts at its center
* (layout_gravity="center"), we compute the offset from that center point
* and apply it via translationX/Y so the marker's layout bounds stay intact.
这段代码更新标记位置到区域中心
1. 根据Zone的归一化坐标计算目标位置
2. 限制标记不超出图片边界Y仅限制上限
3. 相对于ImageView中心计算偏移量并应用
4. 支持动画或即时移动两种方式
*/
private fun updateMarkerPosition(zone: Zone, animated: Boolean) {
if (humanBodyWidth <= 0 || humanBodyHeight <= 0) return
@@ -198,9 +204,7 @@ class StrikePositionActivity : AppCompatActivity() {
val rawX = humanBodyWidth * zone.normalizedX
val rawY = humanBodyHeight * zone.normalizedY
// Clamp X so the marker never extends beyond the drawable edges.
// Y clamp only has an upper bound — HEAD at normalizedY=0 is allowed to go
// all the way to the top (translationY can be negative).
//用X夹住使标记永远不会超出可绘制的边缘。Y钳只有一个上界——在归一化Y=0处的HEAD可以一直达到顶端平移Y可以为负
val clampedX = min(max(rawX, halfMarkerW), humanBodyWidth - halfMarkerW)
val clampedY = min(rawY, humanBodyHeight - halfMarkerH)

View File

@@ -1,20 +1,20 @@
package com.example.defenseapplication.liveVideo
package com.ckkj.defense_device.liveVideo
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.example.defenseapplication.R
import com.example.defenseapplication.bean.DeleteDeviceUserRequest
import com.example.defenseapplication.bean.ObtainInviterInformationRequest
import com.example.defenseapplication.bean.VerifyOptionPasswordRequest
import com.example.defenseapplication.personal.PasswordInputDialog
import com.example.defenseapplication.utils.DeviceIdEvent
import com.example.defenseapplication.utils.DeviceUserUpdateEvent
import com.example.defenseapplication.databinding.UserDetailsActivityBinding
import com.example.defenseapplication.utils.RetrofitNetwork
import com.example.defenseapplication.view.CustomDialogFragmentText
import com.ckkj.defense_device.R
import com.ckkj.defense_device.bean.DeleteDeviceUserRequest
import com.ckkj.defense_device.bean.ObtainInviterInformationRequest
import com.ckkj.defense_device.bean.UpdateFamilyUserRequest
import com.ckkj.defense_device.bean.VerifyOptionPasswordRequest
import com.ckkj.defense_device.personal.PasswordInputDialog
import com.ckkj.defense_device.utils.DeviceIdEvent
import com.ckkj.defense_device.utils.DeviceUserUpdateEvent
import com.ckkj.defense_device.databinding.UserDetailsActivityBinding
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.ckkj.defense_device.view.CustomDialogFragmentText
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -27,6 +27,7 @@ class UserDetailsActivity : AppCompatActivity() {
private var userId: String = ""
private var isPasswordVerified: Boolean = false
private lateinit var passwordDialog: PasswordInputDialog
private var optionPassword: String = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -73,8 +74,8 @@ class UserDetailsActivity : AppCompatActivity() {
}
}
private fun updateUI(data: com.example.defenseapplication.bean.ObtainInviterInformationBean) {
binding.tvContactName.text = data.nickName ?: "未知用户"
private fun updateUI(data: com.ckkj.defense_device.bean.ObtainInviterInformationBean) {
binding.tvContactName.text = data.nickName ?: ""
binding.tvPhone.text = data.phonenumber ?: ""
binding.tvIdCard.text = data.idCard ?: ""
binding.tvMacAddress.text = data.mac ?: ""
@@ -88,10 +89,12 @@ class UserDetailsActivity : AppCompatActivity() {
binding.swUserStatus.setOnCheckedChangeListener { _, isChecked ->
if (!isPasswordVerified) {
binding.swUserStatus.isChecked = !isChecked
showPasswordDialog {
showPasswordDialog(isChecked) {
isPasswordVerified = true
binding.swUserStatus.isChecked = isChecked
}
} else {
updateFamilyUserStatus(isChecked)
}
}
@@ -100,7 +103,7 @@ class UserDetailsActivity : AppCompatActivity() {
}
}
private fun showPasswordDialog(onVerified: () -> Unit) {
private fun showPasswordDialog(status: Boolean, onVerified: () -> Unit) {
passwordDialog = PasswordInputDialog(this).apply {
setOnConfirmListener { inputPassword ->
lifecycleScope.launch {
@@ -110,6 +113,7 @@ class UserDetailsActivity : AppCompatActivity() {
withContext(Dispatchers.Main) {
if (response.code == 200) {
dismiss()
updateFamilyUserStatus(status, inputPassword)
onVerified()
} else {
Toast.makeText(
@@ -136,6 +140,48 @@ class UserDetailsActivity : AppCompatActivity() {
}
private fun updateFamilyUserStatus(status: Boolean) {
updateFamilyUserStatus(status, optionPassword)
}
private fun updateFamilyUserStatus(status: Boolean, password: String) {
if (userId.isEmpty()) {
Toast.makeText(this, "用户ID为空", Toast.LENGTH_SHORT).show()
return
}
if (password.isNotEmpty()) {
optionPassword = password
}
lifecycleScope.launch {
try {
val request = UpdateFamilyUserRequest(
id = userId,
optionPassword = optionPassword,
optionStatus = "status",
status = if (status) "1" else "0"
)
val response = RetrofitNetwork.getNetworkService().updateFamilyUser(request)
withContext(Dispatchers.Main) {
if (response.code == 200) {
Toast.makeText(this@UserDetailsActivity, "状态修改成功", Toast.LENGTH_SHORT).show()
DeviceUserUpdateEvent.notifyUpdate()
} else {
Toast.makeText(this@UserDetailsActivity, response.msg ?: "状态修改失败", Toast.LENGTH_SHORT).show()
binding.swUserStatus.isChecked = !status
}
}
} catch (e: Exception) {
e.printStackTrace()
withContext(Dispatchers.Main) {
Toast.makeText(this@UserDetailsActivity, "网络请求失败", Toast.LENGTH_SHORT).show()
binding.swUserStatus.isChecked = !status
}
}
}
}
private fun showDeleteDialog() {
val dialog = CustomDialogFragmentText()
dialog.setTitle(getString(R.string.tip))
@@ -147,7 +193,7 @@ class UserDetailsActivity : AppCompatActivity() {
if (isPasswordVerified) {
deleteDeviceUser()
} else {
showPasswordDialog {
showPasswordDialog(false) {
isPasswordVerified = true
deleteDeviceUser()
}

View File

@@ -1,15 +1,15 @@
package com.example.defenseapplication.liveVideo
package com.ckkj.defense_device.liveVideo
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.bean.DeviceBean
import com.example.defenseapplication.databinding.VoiceSettingsActivityBinding
import com.example.defenseapplication.utils.ApiService
import com.example.defenseapplication.utils.DeviceIdEvent
import com.example.defenseapplication.utils.RetrofitNetwork
import com.ckkj.defense_device.bean.DeviceBean
import com.ckkj.defense_device.databinding.VoiceSettingsActivityBinding
import com.ckkj.defense_device.utils.ApiService
import com.ckkj.defense_device.utils.DeviceIdEvent
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -79,29 +79,31 @@ class VoiceSettingsActivity : AppCompatActivity() {
private fun updateDeviceAlertAudio() {
deviceId?.let { id ->
val newAlertAudio = if (binding.swWarningVoice.isChecked) "1" else "0"
// 只有状态发生变化时才请求
if (newAlertAudio != originalAlertAudio) {
CoroutineScope(Dispatchers.IO).launch {
try {
val deviceBean = DeviceBean(id = id, alertAudio = newAlertAudio)
val response = apiService.updateDeviceInfo(deviceBean)
withContext(Dispatchers.Main) {
if (response.code == 200 && response.data != null) {
Toast.makeText(this@VoiceSettingsActivity, "修改成功", Toast.LENGTH_SHORT).show()
} else {
// 点击返回时总是触发网络请求
CoroutineScope(Dispatchers.IO).launch {
try {
val deviceBean = DeviceBean(id = id, alertAudio = newAlertAudio)
val response = apiService.updateDeviceInfo(deviceBean)
withContext(Dispatchers.Main) {
if (response.code == 200 && response.data != null) {
Toast.makeText(this@VoiceSettingsActivity, "修改成功", Toast.LENGTH_SHORT).show()
} else {
// 仅在状态实际发生变化时才显示错误提示
if (newAlertAudio != originalAlertAudio) {
Toast.makeText(this@VoiceSettingsActivity, response.msg, Toast.LENGTH_SHORT).show()
}
finish()
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
finish()
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
// 仅在状态实际发生变化时才显示失败提示
if (newAlertAudio != originalAlertAudio) {
Toast.makeText(this@VoiceSettingsActivity, "修改失败", Toast.LENGTH_SHORT).show()
finish()
}
finish()
}
}
} else {
finish()
}
}
}

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.liveVideo
package com.ckkj.defense_device.liveVideo
import android.content.Intent
import android.graphics.Color
@@ -6,10 +6,10 @@ import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.widget.doAfterTextChanged
import com.example.defenseapplication.bean.DeviceBean
import com.example.defenseapplication.databinding.WarningVoiceContentActivityBinding
import com.example.defenseapplication.utils.ApiService
import com.example.defenseapplication.utils.RetrofitNetwork
import com.ckkj.defense_device.bean.DeviceBean
import com.ckkj.defense_device.databinding.WarningVoiceContentActivityBinding
import com.ckkj.defense_device.utils.ApiService
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers

View File

@@ -1,16 +1,15 @@
package com.example.defenseapplication.liveVideo
package com.ckkj.defense_device.liveVideo
import android.os.Bundle
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import com.example.defenseapplication.R
import com.example.defenseapplication.base.BaseActivity
import com.example.defenseapplication.bean.DeviceBean
import com.example.defenseapplication.databinding.WaterGunSettingsActivityBinding
import com.example.defenseapplication.utils.DeviceIdEvent
import com.example.defenseapplication.utils.RetrofitNetwork
import com.example.defenseapplication.view.ContainerSelectDialog
import com.example.defenseapplication.view.CustomDialogFragmentText
import com.ckkj.defense_device.R
import com.ckkj.defense_device.base.BaseActivity
import com.ckkj.defense_device.bean.DeviceBean
import com.ckkj.defense_device.databinding.WaterGunSettingsActivityBinding
import com.ckkj.defense_device.utils.DeviceIdEvent
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.ckkj.defense_device.view.ContainerSelectDialog
import com.ckkj.defense_device.view.CustomDialogFragmentText
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -25,6 +24,7 @@ class WaterGunSettingsActivity : BaseActivity() {
private var currentStrikeRange: String = "7"
private var currentStrikeInterval: String = "3"
private var currentContainer: String = "容器4"
private var optionPassword: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -42,6 +42,7 @@ class WaterGunSettingsActivity : BaseActivity() {
currentStrikeRange = intent.getStringExtra("strikeRange") ?: "7"
currentStrikeInterval = intent.getStringExtra("strikeInterval") ?: "3"
currentContainer = intent.getStringExtra("container") ?: "容器4"
optionPassword = intent.getStringExtra("optionPassword")
// 显示初始值
binding.tvDistance.text = "${currentStrikeRange}m"
@@ -101,7 +102,8 @@ class WaterGunSettingsActivity : BaseActivity() {
try {
val deviceBean = DeviceBean(
id = deviceId,
strikeRange = distance
strikeRange = distance,
optionPassword = optionPassword
)
val response = RetrofitNetwork.getNetworkService().updateDeviceInfo(deviceBean)
withContext(Dispatchers.Main) {
@@ -132,7 +134,8 @@ class WaterGunSettingsActivity : BaseActivity() {
try {
val deviceBean = DeviceBean(
id = deviceId,
strikeInterval = interval
strikeInterval = interval,
optionPassword = optionPassword
)
val response = RetrofitNetwork.getNetworkService().updateDeviceInfo(deviceBean)
withContext(Dispatchers.Main) {
@@ -163,7 +166,8 @@ class WaterGunSettingsActivity : BaseActivity() {
try {
val deviceBean = DeviceBean(
id = deviceId,
container = container
container = container,
optionPassword = optionPassword
)
val response = RetrofitNetwork.getNetworkService().updateDeviceInfo(deviceBean)
withContext(Dispatchers.Main) {

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.liveVideo
package com.ckkj.defense_device.liveVideo
import android.Manifest
import android.content.BroadcastReceiver
@@ -18,13 +18,13 @@ import android.widget.PopupWindow
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.defenseapplication.R
import com.example.defenseapplication.adapter.WifiListAdapter
import com.example.defenseapplication.bean.DeviceBean
import com.example.defenseapplication.databinding.DialogWifiListBinding
import com.example.defenseapplication.databinding.WifiManagementActivityBinding
import com.example.defenseapplication.utils.DeviceIdEvent
import com.example.defenseapplication.utils.RetrofitNetwork
import com.ckkj.defense_device.R
import com.ckkj.defense_device.adapter.WifiListAdapter
import com.ckkj.defense_device.bean.DeviceBean
import com.ckkj.defense_device.databinding.DialogWifiListBinding
import com.ckkj.defense_device.databinding.WifiManagementActivityBinding
import com.ckkj.defense_device.utils.DeviceIdEvent
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -202,14 +202,6 @@ class WiFiManagementActivity : AppCompatActivity() {
}
dialogBinding.rvWifiList.adapter = adapter
// 添加下拉刷新功能
dialogBinding.swipeRefreshLayout.setOnRefreshListener {
wifiManager.startScan()
// 延迟1秒后停止刷新动画
android.os.Handler().postDelayed({
dialogBinding.swipeRefreshLayout.isRefreshing = false
}, 1000)
}
}
private fun updateBottomButtonVisibility() {
@@ -229,9 +221,6 @@ class WiFiManagementActivity : AppCompatActivity() {
}
private fun updateWifiList() {
popupWindow?.contentView?.findViewById<androidx.swiperefreshlayout.widget.SwipeRefreshLayout>(R.id.swipeRefreshLayout)?.let { swipeRefreshLayout ->
swipeRefreshLayout.isRefreshing = false
}
popupWindow?.contentView?.findViewById<androidx.recyclerview.widget.RecyclerView>(R.id.rvWifiList)?.let { recyclerView ->
val wifiList = getWifiList()
recyclerView.adapter = WifiListAdapter(wifiList) { wifiName ->
@@ -253,4 +242,4 @@ class WiFiManagementActivity : AppCompatActivity() {
unregisterReceiver(wifiScanReceiver)
popupWindow?.dismiss()
}
}
}

View File

@@ -1,14 +1,9 @@
package com.example.defenseapplication.login
package com.ckkj.defense_device.login
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.FaceLoginActivityBinding
import com.ckkj.defense_device.databinding.FaceLoginActivityBinding
import com.gyf.immersionbar.ImmersionBar
//人脸识别
class FaceLoginActivity : AppCompatActivity() {

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.login
package com.ckkj.defense_device.login
import android.Manifest
import android.content.pm.PackageManager
@@ -13,8 +13,9 @@ import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.example.defenseapplication.databinding.FaceVerificationActivityBinding
import com.example.defenseapplication.view.FaceAnalyzer
import com.ckkj.defense_device.R
import com.ckkj.defense_device.databinding.FaceVerificationActivityBinding
import com.ckkj.defense_device.view.FaceAnalyzer
import com.google.mlkit.vision.face.FaceDetection
import com.google.mlkit.vision.face.FaceDetectorOptions
import com.gyf.immersionbar.ImmersionBar
@@ -106,7 +107,7 @@ class FaceVerificationActivity : AppCompatActivity() {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startCamera()
} else {
Toast.makeText(this, "需要相机权限才能进行人脸验证", Toast.LENGTH_SHORT).show()
Toast.makeText(this, R.string.need_camera_permission_for_face_verify, Toast.LENGTH_SHORT).show()
finish()
}
}

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.login
package com.ckkj.defense_device.login
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
@@ -7,9 +7,10 @@ import android.os.CountDownTimer
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import bean.ForgotRequest
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.ForgetPasswordActivityBinding
import com.example.defenseapplication.utils.RetrofitNetwork
import com.ckkj.defense_device.R
import com.ckkj.defense_device.databinding.ForgetPasswordActivityBinding
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.ckkj.defense_device.view.LoadingDialog
import com.google.firebase.crashlytics.buildtools.reloc.org.apache.http.util.TextUtils
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
@@ -20,6 +21,7 @@ import java.util.regex.Pattern
class ForgetPasswordActivity : AppCompatActivity() {
private lateinit var binding: ForgetPasswordActivityBinding
private var isLoading = false
private var countDownTimer: CountDownTimer? = null
private var isSendingCode = false
@@ -55,15 +57,17 @@ class ForgetPasswordActivity : AppCompatActivity() {
if (isPhoneNumberValid(phoneNumber)) {
sendVerificationCode(phoneNumber)
} else {
Toast.makeText(this, "请输入有效的11位手机号", Toast.LENGTH_SHORT).show()
Toast.makeText(this, getString(R.string.phone_tip), Toast.LENGTH_SHORT).show()
}
} else {
Toast.makeText(this, "请稍后再试", Toast.LENGTH_SHORT).show()
Toast.makeText(this, getString(R.string.please_try_later), Toast.LENGTH_SHORT).show()
}
}
binding.btnNext.setOnClickListener {
performResetPassword()
if (!isLoading) {
performResetPassword()
}
}
}
@@ -82,7 +86,7 @@ class ForgetPasswordActivity : AppCompatActivity() {
val response = RetrofitNetwork.getNetworkService().getCode(phoneNumber)
withContext(Dispatchers.Main) {
if (response.code == 200) {
Toast.makeText(this@ForgetPasswordActivity, "验证码已发送", Toast.LENGTH_SHORT).show()
Toast.makeText(this@ForgetPasswordActivity, getString(R.string.code_sent_to), Toast.LENGTH_SHORT).show()
startCountDown()
} else {
Toast.makeText(this@ForgetPasswordActivity, response.msg, Toast.LENGTH_SHORT).show()
@@ -104,11 +108,10 @@ class ForgetPasswordActivity : AppCompatActivity() {
* 开始验证码按钮倒计时
*/
private fun startCountDown() {
binding.sendCodeBtn.isEnabled = false
countDownTimer = object : CountDownTimer(COUNTDOWN_DURATION, COUNTDOWN_INTERVAL) {
override fun onTick(millisUntilFinished: Long) {
val secondsRemaining = (millisUntilFinished / 1000).toInt()
binding.sendCodeBtn.text = "${secondsRemaining}秒后重试"
binding.sendCodeBtn.isEnabled = false
binding.sendCodeBtn.text = getString(R.string.countdown_retry, millisUntilFinished / 1000)
}
override fun onFinish() {
@@ -123,7 +126,7 @@ class ForgetPasswordActivity : AppCompatActivity() {
private fun resetSendButton() {
countDownTimer?.cancel()
countDownTimer = null
binding.sendCodeBtn.text = "发送验证码"
binding.sendCodeBtn.text = getString(R.string.resend_code)
binding.sendCodeBtn.isEnabled = true
}
@@ -137,34 +140,38 @@ class ForgetPasswordActivity : AppCompatActivity() {
val confirmPassword = binding.etInviteCode.text.toString().trim()
if (!isPhoneNumberValid(phoneNumber)) {
Toast.makeText(this, "手机号格式不正确", Toast.LENGTH_SHORT).show()
Toast.makeText(this, getString(R.string.invalid_phone), Toast.LENGTH_SHORT).show()
return
}
if (TextUtils.isEmpty(smsCode)) {
Toast.makeText(this, "请输入验证码", Toast.LENGTH_SHORT).show()
Toast.makeText(this, getString(R.string.hint_code_zh), Toast.LENGTH_SHORT).show()
return
}
if (TextUtils.isEmpty(newPassword) || TextUtils.isEmpty(confirmPassword)) {
Toast.makeText(this, "密码不能为空", Toast.LENGTH_SHORT).show()
Toast.makeText(this, getString(R.string.password_cannot_empty), Toast.LENGTH_SHORT).show()
return
}
if (newPassword.length < MIN_PASSWORD_LENGTH || newPassword.length > MAX_PASSWORD_LENGTH) {
Toast.makeText(this, "密码长度需为${MIN_PASSWORD_LENGTH}-${MAX_PASSWORD_LENGTH}", Toast.LENGTH_SHORT).show()
val tip = getString(R.string.pwd_length_tip, MIN_PASSWORD_LENGTH, MAX_PASSWORD_LENGTH)
Toast.makeText(this, tip, Toast.LENGTH_SHORT).show()
return
}
if (!newPassword.matches(Regex(".*[A-Za-z].*")) || !newPassword.matches(Regex(".*[0-9].*"))) {
Toast.makeText(this, "密码需同时包含字母和数字", Toast.LENGTH_SHORT).show()
Toast.makeText(this, getString(R.string.password_letter_digit), Toast.LENGTH_SHORT).show()
return
}
if (newPassword != confirmPassword) {
Toast.makeText(this, "两次输入的密码不一致", Toast.LENGTH_SHORT).show()
Toast.makeText(this, getString(R.string.password_mismatch), Toast.LENGTH_SHORT).show()
return
}
isLoading = true
binding.btnNext.isEnabled = false
binding.btnNext.text = "重置中..."
val loadingDialog = LoadingDialog(this)
.setMessage(getString(R.string.resetting))
.apply { show() }
CoroutineScope(Dispatchers.IO).launch {
try {
@@ -175,8 +182,9 @@ class ForgetPasswordActivity : AppCompatActivity() {
)
val response = RetrofitNetwork.getNetworkService().forgotPassword(forgotRequest)
withContext(Dispatchers.Main) {
isLoading = false
loadingDialog.dismiss()
binding.btnNext.isEnabled = true
binding.btnNext.text = "确定"
if (response.code == 200) {
Toast.makeText(this@ForgetPasswordActivity, R.string.reset_success, Toast.LENGTH_SHORT).show()
@@ -187,8 +195,9 @@ class ForgetPasswordActivity : AppCompatActivity() {
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
isLoading = false
loadingDialog.dismiss()
binding.btnNext.isEnabled = true
binding.btnNext.text = "确定"
Toast.makeText(this@ForgetPasswordActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
}
}

View File

@@ -1,21 +1,23 @@
package com.example.defenseapplication.login
package com.ckkj.defense_device.login
import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.os.Bundle
import android.os.CountDownTimer
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import bean.LoginRequest
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.ActivityLoginBinding
import com.example.defenseapplication.home.HomeActivity
import com.example.defenseapplication.utils.RetrofitNetwork
import com.example.defenseapplication.utils.UserinfoUtil
import com.ckkj.defense_device.R
import com.ckkj.defense_device.databinding.ActivityLoginBinding
import com.ckkj.defense_device.home.HomeActivity
import com.ckkj.defense_device.utils.ApiConfig
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.ckkj.defense_device.utils.UserinfoUtil
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -26,11 +28,13 @@ class LoginActivity : AppCompatActivity() {
private lateinit var binding: ActivityLoginBinding
private var currentLoginMode = LoginMode.SMS
private var countDownTimer: CountDownTimer? = null
enum class LoginMode { SMS, PASSWORD }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ApiConfig.resetAuthRedirectFlag()
binding = ActivityLoginBinding.inflate(layoutInflater)
setContentView(binding.root)
@@ -73,7 +77,7 @@ class LoginActivity : AppCompatActivity() {
binding.registerText.visibility = View.VISIBLE
binding.forgetText.visibility = View.GONE
updateRegisterTextConstraints(center = false)
updateRegisterTextConstraints(center = true)
//需要正确的方法名和参数
updateLoginButtonTopConstraint(R.id.smsRowLayout)
@@ -98,7 +102,6 @@ class LoginActivity : AppCompatActivity() {
private fun updateLoginButtonTopConstraint(topTargetId: Int) {
val params = binding.loginBtn.layoutParams as ConstraintLayout.LayoutParams
params.topToBottom = topTargetId
params.topMargin = 32
binding.loginBtn.layoutParams = params
}
@@ -115,7 +118,6 @@ class LoginActivity : AppCompatActivity() {
params.endToEnd = ConstraintSet.UNSET
}
params.topToBottom = binding.loginBtn.id
params.topMargin = 20
binding.registerText.layoutParams = params
}
@@ -166,25 +168,24 @@ class LoginActivity : AppCompatActivity() {
binding.registerText.setOnClickListener {
val intent= Intent(this, RegisterActivity::class.java)
startActivity(intent)
Toast.makeText(this, R.string.redirect_register_page, Toast.LENGTH_SHORT).show()
}
binding.forgetText.setOnClickListener {
val intent= Intent(this, ForgetPasswordActivity::class.java)
startActivity(intent)
Toast.makeText(this, R.string.forgot_password_page, Toast.LENGTH_SHORT).show()
}
}
private fun startCountDown() {
binding.sendCodeBtn.isEnabled = false
object : CountDownTimer(60000, 1000) {
countDownTimer = object : CountDownTimer(60000, 1000) {
override fun onTick(millisUntilFinished: Long) {
binding.sendCodeBtn.text = getString(R.string.countdown_retry, millisUntilFinished / 1000)
}
override fun onFinish() {
binding.sendCodeBtn.text = getString(R.string.send_code)
binding.sendCodeBtn.text = getString(R.string.resend_code)
binding.sendCodeBtn.isEnabled = true
countDownTimer = null
}
}.start()
}
@@ -218,9 +219,7 @@ class LoginActivity : AppCompatActivity() {
phonenumber = phone,
smsCode = smsCode
)
android.util.Log.d("LoginActivity", "短信登录请求: $loginRequest")
val response = RetrofitNetwork.getNetworkService().login(loginRequest)
android.util.Log.d("LoginActivity", "短信登录响应: code=${response.code}, msg=${response.msg}")
withContext(Dispatchers.Main) {
if (response.code == 200 && response.data != null) {
UserinfoUtil.saveUserInfo(response.data)
@@ -234,7 +233,6 @@ class LoginActivity : AppCompatActivity() {
}
}
} catch (e: Exception) {
android.util.Log.e("LoginActivity", "短信登录异常", e)
withContext(Dispatchers.Main) {
Toast.makeText(this@LoginActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
}
@@ -251,14 +249,13 @@ class LoginActivity : AppCompatActivity() {
phonenumber = phone,
password = password
)
android.util.Log.d("LoginActivity", "密码登录请求: $loginRequest")
val response = RetrofitNetwork.getNetworkService().login(loginRequest)
android.util.Log.d("LoginActivity", "密码登录响应: code=${response.code}, msg=${response.msg}")
withContext(Dispatchers.Main) {
if (response.code == 200 && response.data != null) {
UserinfoUtil.saveUserInfo(response.data)
Toast.makeText(this@LoginActivity, R.string.password_login_success_title, Toast.LENGTH_SHORT).show()
val intent = Intent(this@LoginActivity, HomeActivity::class.java)
//清除任务栈
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
finish()
@@ -267,7 +264,6 @@ class LoginActivity : AppCompatActivity() {
}
}
} catch (e: Exception) {
android.util.Log.e("LoginActivity", "密码登录异常", e)
withContext(Dispatchers.Main) {
Toast.makeText(this@LoginActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
}
@@ -285,4 +281,10 @@ class LoginActivity : AppCompatActivity() {
gradientDrawable.gradientType = GradientDrawable.LINEAR_GRADIENT
view.background = gradientDrawable
}
override fun onDestroy() {
super.onDestroy()
countDownTimer?.cancel()
countDownTimer = null
}
}

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.login
package com.ckkj.defense_device.login
import android.content.Intent
import android.graphics.Color
@@ -8,9 +8,10 @@ import android.os.CountDownTimer
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import bean.RegisterRequest
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.RegisterActivityBinding
import com.example.defenseapplication.utils.RetrofitNetwork
import com.ckkj.defense_device.R
import com.ckkj.defense_device.databinding.RegisterActivityBinding
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.ckkj.defense_device.view.LoadingDialog
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -80,7 +81,7 @@ class RegisterActivity : AppCompatActivity() {
val response = RetrofitNetwork.getNetworkService().getCode(userName)
withContext(Dispatchers.Main) {
if (response.code == 200) {
Toast.makeText(this@RegisterActivity, "验证码已发送", Toast.LENGTH_SHORT).show()
Toast.makeText(this@RegisterActivity, R.string.code_already_sent, Toast.LENGTH_SHORT).show()
startCountDown()
} else {
Toast.makeText(this@RegisterActivity, response.msg, Toast.LENGTH_SHORT).show()
@@ -99,11 +100,10 @@ class RegisterActivity : AppCompatActivity() {
}
private fun startCountDown() {
binding.sendCodeBtn.isEnabled = false
countDownTimer = object : CountDownTimer(COUNTDOWN_DURATION, COUNTDOWN_INTERVAL) {
override fun onTick(millisUntilFinished: Long) {
val secondsRemaining = (millisUntilFinished / 1000).toInt()
binding.sendCodeBtn.text = "${secondsRemaining}秒后重试"
binding.sendCodeBtn.isEnabled = false
binding.sendCodeBtn.text = getString(R.string.countdown_retry, millisUntilFinished / 1000)
}
override fun onFinish() {
@@ -115,7 +115,7 @@ class RegisterActivity : AppCompatActivity() {
private fun resetSendButton() {
countDownTimer?.cancel()
countDownTimer = null
binding.sendCodeBtn.text = getString(R.string.send_code)
binding.sendCodeBtn.text = getString(R.string.resend_code)
binding.sendCodeBtn.isEnabled = true
isSendingCode = false
}
@@ -158,7 +158,9 @@ class RegisterActivity : AppCompatActivity() {
isLoading = true
binding.btnNext.isEnabled = false
binding.btnNext.text = getString(R.string.registering)
val loadingDialog = LoadingDialog(this)
.setMessage(getString(R.string.registering))
.apply { show() }
CoroutineScope(Dispatchers.IO).launch {
try {
@@ -174,12 +176,13 @@ class RegisterActivity : AppCompatActivity() {
val response = RetrofitNetwork.getNetworkService().register(registerRequest)
withContext(Dispatchers.Main) {
isLoading = false
loadingDialog.dismiss()
binding.btnNext.isEnabled = true
binding.btnNext.text = getString(R.string.next_step)
if (response.code == 200) {
Toast.makeText(this@RegisterActivity, R.string.register_success, Toast.LENGTH_SHORT).show()
val intent = Intent(this@RegisterActivity, LoginActivity::class.java)
val intent = Intent(this@RegisterActivity, RegisterSuccessActivity::class.java)
//清除任务栈
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
finish()
@@ -190,8 +193,8 @@ class RegisterActivity : AppCompatActivity() {
} catch (e: Exception) {
withContext(Dispatchers.Main) {
isLoading = false
loadingDialog.dismiss()
binding.btnNext.isEnabled = true
binding.btnNext.text = getString(R.string.next_step)
Toast.makeText(this@RegisterActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
}
}

View File

@@ -1,15 +1,11 @@
package com.example.defenseapplication.login
package com.ckkj.defense_device.login
import android.content.Intent
import android.os.Bundle
import android.os.CountDownTimer
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.RegisterSuccessActivityBinding
import com.example.defenseapplication.home.HomeActivity
import com.ckkj.defense_device.databinding.RegisterSuccessActivityBinding
import com.ckkj.defense_device.home.HomeActivity
import com.gyf.immersionbar.ImmersionBar
//注册成功界面
class RegisterSuccessActivity : AppCompatActivity() {

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.model
package com.ckkj.defense_device.model
data class FamilyItem(
val id: String,

View File

@@ -0,0 +1,144 @@
package com.ckkj.defense_device.personal
import android.content.Intent
import android.os.Bundle
import android.os.CountDownTimer
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.ckkj.defense_device.R
import com.ckkj.defense_device.databinding.CancelAccountActivityBinding
import com.ckkj.defense_device.login.LoginActivity
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.ckkj.defense_device.utils.UserinfoUtil
import com.ckkj.defense_device.view.CustomDialogFragment
import com.ckkj.defense_device.view.DefenseDialogs
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class CancelAccountActivity : AppCompatActivity() {
private lateinit var binding: CancelAccountActivityBinding
private var countDownTimer: CountDownTimer? = null
private var phoneNumber: String = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = CancelAccountActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
ImmersionBar.with(this)
.statusBarDarkFont(true)
.titleBar(binding.topBar)
.init()
getUserInfo()
initListener()
}
private fun getUserInfo() {
CoroutineScope(Dispatchers.IO).launch {
try {
val response = RetrofitNetwork.getNetworkService().getUserInfo()
withContext(Dispatchers.Main) {
if (response.code == 200 && response.data != null) {
phoneNumber = response.data?.phonenumber ?: ""
binding.tvPhoneNumber.text = maskPhoneNumber(phoneNumber)
}
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
Toast.makeText(this@CancelAccountActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
}
}
}
}
private fun maskPhoneNumber(phone: String): String {
if (phone.length != 11) {
return phone
}
return phone.substring(0, 3) + "****" + phone.substring(7)
}
private fun initListener() {
binding.ivBack.setOnClickListener {
finish()
}
binding.btnSendCode.setOnClickListener {
if (phoneNumber.isEmpty()) {
Toast.makeText(this, R.string.get_user_info_fail, Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
if (phoneNumber.length != 11) {
Toast.makeText(this, R.string.phone_format_invalid, Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
sendVerificationCode(phoneNumber)
}
binding.btnCancelAccount.setOnClickListener {
DefenseDialogs.showDialog(
this,
config = CustomDialogFragment.Config(
title = getString(R.string.tip),
message = getString(R.string.confirm_cancel_account_user_account),
positiveText = getString(R.string.confirm),
negativeText = getString(R.string.cancel)
),
onPositiveClick = {
Toast.makeText(this@CancelAccountActivity, getString(R.string.cancel_account), Toast.LENGTH_SHORT).show()
}
)
}
}
private fun sendVerificationCode(phone: String) {
binding.btnSendCode.isEnabled = false
CoroutineScope(Dispatchers.IO).launch {
try {
val response = RetrofitNetwork.getNetworkService().getCode(phone)
withContext(Dispatchers.Main) {
if (response.code == 200) {
Toast.makeText(this@CancelAccountActivity, getString(R.string.code_sent_to, phone), Toast.LENGTH_SHORT).show()
startCountdown()
} else {
binding.btnSendCode.isEnabled = true
Toast.makeText(this@CancelAccountActivity, response.msg, Toast.LENGTH_SHORT).show()
}
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
binding.btnSendCode.isEnabled = true
Toast.makeText(this@CancelAccountActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
}
}
}
}
private fun startCountdown() {
countDownTimer = object : CountDownTimer(60000, 1000) {
override fun onTick(millisUntilFinished: Long) {
binding.btnSendCode.text = getString(R.string.countdown_retry, millisUntilFinished / 1000)
}
override fun onFinish() {
binding.btnSendCode.text = getString(R.string.resend_code)
binding.btnSendCode.isEnabled = true
countDownTimer = null
}
}.start()
}
override fun onDestroy() {
super.onDestroy()
countDownTimer?.cancel()
}
}

View File

@@ -1,12 +1,12 @@
package com.example.defenseapplication.personal
package com.ckkj.defense_device.personal
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.R
import com.example.defenseapplication.bean.UpdatePassword
import com.example.defenseapplication.databinding.ChangePasswordActivityBinding
import com.example.defenseapplication.utils.RetrofitNetwork
import com.ckkj.defense_device.R
import com.ckkj.defense_device.bean.UpdatePassword
import com.ckkj.defense_device.databinding.ChangePasswordActivityBinding
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers

View File

@@ -1,10 +1,10 @@
package com.example.defenseapplication.personal
package com.ckkj.defense_device.personal
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.databinding.FaceManagementActivityBinding
import com.example.defenseapplication.login.FaceLoginActivity
import com.ckkj.defense_device.databinding.FaceManagementActivityBinding
import com.ckkj.defense_device.login.FaceLoginActivity
import com.gyf.immersionbar.ImmersionBar
//人脸管理页面

View File

@@ -1,32 +1,45 @@
package com.example.defenseapplication.personal
package com.ckkj.defense_device.personal
import android.Manifest
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.bottomsheet.BottomSheetDialog
import androidx.core.content.ContextCompat
import com.example.defenseapplication.R
import com.example.defenseapplication.bean.VerifyOptionPasswordRequest
import com.example.defenseapplication.databinding.DialogExpireTimeBinding
import com.example.defenseapplication.databinding.InvitationCodeActivityBinding
import com.example.defenseapplication.utils.RetrofitNetwork
import com.ckkj.defense_device.R
import com.ckkj.defense_device.bean.RecommendationCodeBean
import com.ckkj.defense_device.bean.SelectInviterInfoBean
import com.ckkj.defense_device.bean.VerifyOptionPasswordRequest
import com.ckkj.defense_device.databinding.DialogExpireTimeBinding
import com.ckkj.defense_device.databinding.InvitationCodeActivityBinding
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.ckkj.defense_device.view.LoadingDialog
import com.google.gson.Gson
import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType
import com.google.zxing.qrcode.QRCodeWriter
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import com.gyf.immersionbar.ImmersionBar
import com.maning.mlkitscanner.scan.MNScanManager
import com.maning.mlkitscanner.scan.callback.act.MNScanCallback
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.json.JSONObject
import java.io.File
import java.io.FileOutputStream
import java.util.Hashtable
@@ -44,7 +57,24 @@ class InvitationCodeActivity : AppCompatActivity() {
private var isLoading = false // 是否正在加载
private var hasGeneratedQrCode = false // 是否已经生成过二维码
private val requestPermissionsLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
val cameraGranted = permissions[Manifest.permission.CAMERA] ?: false
val storageGranted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
permissions[Manifest.permission.READ_MEDIA_IMAGES] ?: false
} else {
permissions[Manifest.permission.READ_EXTERNAL_STORAGE] ?: false
}
if (cameraGranted && storageGranted) {
startScan()
} else {
Toast.makeText(this, R.string.permission_denied, Toast.LENGTH_SHORT).show()
}
}
companion object {
private const val TAG = "InvitationCodeActivity"
const val EXPIRE_24H = 24 * 60 * 60 * 1000L
const val EXPIRE_7D = 7 * 24 * 60 * 60 * 1000L
}
@@ -90,15 +120,136 @@ class InvitationCodeActivity : AppCompatActivity() {
// 撤销邀请按钮
binding.btnCancelInvite.setOnClickListener {
showPasswordDialog {
cancelInvitation()
if (generatedInviteCode.isEmpty()) {
ToastUtils.showError(this, getString(R.string.qr_code_expired))
return@setOnClickListener
}
showPasswordDialog { password, dialog ->
cancelInvitation(password, dialog)
}
}
// 生成/重新生成按钮
binding.btnRegenerate.setOnClickListener {
showPasswordDialog {
generateOrRegenerateInvitation()
showPasswordDialog { password, dialog ->
generateOrRegenerateInvitation(password, dialog)
}
}
binding.sys.setOnClickListener {
checkPermissionsAndScan()
}
}
private fun checkPermissionsAndScan() {
val cameraPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
val storagePermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES)
} else {
ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
if (cameraPermission == PackageManager.PERMISSION_GRANTED &&
storagePermission == PackageManager.PERMISSION_GRANTED
) {
startScan()
} else {
val permissionsToRequest = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.READ_MEDIA_IMAGES
)
} else {
arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
}
requestPermissionsLauncher.launch(permissionsToRequest)
}
}
private fun startScan() {
MNScanManager.startScan(this, object : MNScanCallback {
override fun onActivityResult(resultCode: Int, data: Intent?) {
when (resultCode) {
MNScanManager.RESULT_SUCCESS -> {
val result = data?.getStringArrayListExtra(MNScanManager.INTENT_KEY_RESULT_SUCCESS)
if (!result.isNullOrEmpty()) {
val inviteCode = parseInviteCode(result[0])
if (inviteCode.isNullOrEmpty()) {
Toast.makeText(this@InvitationCodeActivity, "无效的邀请码", Toast.LENGTH_SHORT).show()
} else {
fetchInviterInfo(inviteCode)
}
} else {
Toast.makeText(this@InvitationCodeActivity, "扫码结果为空", Toast.LENGTH_SHORT).show()
}
}
MNScanManager.RESULT_FAIL -> {
val error = data?.getStringExtra(MNScanManager.INTENT_KEY_RESULT_ERROR)
Toast.makeText(this@InvitationCodeActivity, "扫码失败: $error", Toast.LENGTH_SHORT).show()
}
MNScanManager.RESULT_CANCLE -> {
Toast.makeText(this@InvitationCodeActivity, "扫码取消", Toast.LENGTH_SHORT).show()
}
}
}
})
}
private fun parseInviteCode(scanResult: String): String? {
val trimmed = scanResult.trim()
if (trimmed.isEmpty()) return null
return try {
if (trimmed.startsWith("{")) {
JSONObject(trimmed).optString("code").takeIf { it.isNotEmpty() }
} else {
trimmed
}
} catch (e: Exception) {
trimmed
}
}
private fun fetchInviterInfo(inviteCode: String) {
val loadingDialog = LoadingDialog(this).apply { show() }
CoroutineScope(Dispatchers.IO).launch {
try {
val response = RetrofitNetwork.getNetworkService()
.selectInviterInfo(SelectInviterInfoBean(code = inviteCode))
withContext(Dispatchers.Main) {
loadingDialog.dismiss()
if (response.code == 200 && response.data != null) {
val inviter = response.data
val parentId = inviter.resolveParentId()
if (parentId.isNullOrEmpty()) {
Toast.makeText(
this@InvitationCodeActivity,
getString(R.string.network_error),
Toast.LENGTH_SHORT
).show()
return@withContext
}
val intent = Intent(this@InvitationCodeActivity, JoinFamilyInviteActivity::class.java).apply {
putExtra(JoinFamilyInviteActivity.EXTRA_INVITE_CODE, inviteCode)
putExtra(JoinFamilyInviteActivity.EXTRA_NICK_NAME, inviter.nickName)
putExtra(JoinFamilyInviteActivity.EXTRA_AVATAR, inviter.avatar)
putExtra(JoinFamilyInviteActivity.EXTRA_PARENT_ID, parentId)
putExtra(JoinFamilyInviteActivity.EXTRA_USER_ID, inviter.userId)
}
startActivity(intent)
} else {
Toast.makeText(
this@InvitationCodeActivity,
response.msg.ifBlank { getString(R.string.network_error) },
Toast.LENGTH_SHORT
).show()
}
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
loadingDialog.dismiss()
Toast.makeText(this@InvitationCodeActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
}
}
}
}
@@ -106,14 +257,56 @@ class InvitationCodeActivity : AppCompatActivity() {
/**
* 生成或重新生成邀请码
*/
private fun generateOrRegenerateInvitation() {
// 根据当前选择的时效生成邀请码
generateQRCode()
showQrCode()
// 更新按钮文字为"重新生成"
binding.btnRegenerate.text = getString(R.string.regenerate)
hasGeneratedQrCode = true
ToastUtils.showSuccess(this, getString(R.string.operation_success))
private fun generateOrRegenerateInvitation(password: String, passwordDialog: PasswordInputDialog) {
if (isLoading) return
isLoading = true
val loadingDialog = LoadingDialog(this).apply { show() }
CoroutineScope(Dispatchers.IO).launch {
try {
val response = RetrofitNetwork.getNetworkService()
.generateRecommendationCode(VerifyOptionPasswordRequest(password))
Log.d(TAG, "生成推荐码响应: code=${response.code}, msg=${response.msg}, data=${response.data}")
withContext(Dispatchers.Main) {
isLoading = false
loadingDialog.dismiss()
if (response.code == 200) {
val parsed = parseRecommendationCode(response.data)
if (parsed != null) {
passwordDialog.dismiss()
generatedInviteCode = parsed.first
expireTimestamp = parsed.second
qrCodeContent =
"{\"type\":\"invite\",\"code\":\"$generatedInviteCode\",\"expire\":$expireTimestamp}"
Log.d(
TAG,
"推荐码生成成功: Code=$generatedInviteCode, expireTimestamp=$expireTimestamp, qrContent=$qrCodeContent"
)
generateQRCode()
showQrCode()
binding.btnRegenerate.text = getString(R.string.regenerate)
hasGeneratedQrCode = true
ToastUtils.showSuccess(this@InvitationCodeActivity, getString(R.string.operation_success))
} else {
Log.w(TAG, "推荐码解析失败, raw data=${response.data}")
passwordDialog.showError(getString(R.string.network_error))
}
} else {
Log.w(TAG, "生成推荐码失败: code=${response.code}, msg=${response.msg}")
passwordDialog.showError(
response.msg.ifEmpty { getString(R.string.password_error) }
)
}
}
} catch (e: Exception) {
Log.e(TAG, "生成推荐码异常", e)
withContext(Dispatchers.Main) {
isLoading = false
loadingDialog.dismiss()
passwordDialog.showError(getString(R.string.network_error))
}
}
}
}
private fun showExpireTimeDialog() {
@@ -151,9 +344,6 @@ class InvitationCodeActivity : AppCompatActivity() {
binding.tvExpireTime.text = getString(R.string.expire_7d)
}
}
// 显示二维码并生成
showQrCode()
generateQRCode()
expireTimeDialog?.dismiss()
}
@@ -173,22 +363,28 @@ class InvitationCodeActivity : AppCompatActivity() {
}
private fun generateQRCode() {
// 检查二维码是否过期,如果过期则生成新的邀请码
val isExpired = expireTimestamp > 0 && System.currentTimeMillis() > expireTimestamp
val content = if (qrCodeContent.isNotEmpty() && !isExpired) qrCodeContent else generateInviteCode()
val qrBitmap = createQRCodeWithLogo(content, 400, 400)
if (qrCodeContent.isEmpty()) return
val qrBitmap = createQRCodeWithLogo(qrCodeContent, 400, 400)
binding.ivQrCode.setImageBitmap(qrBitmap)
}
private fun generateInviteCode(): String {
val timestamp = System.currentTimeMillis()
expireTimestamp = timestamp + expireTimeInMillis
generatedInviteCode = "INV${timestamp}"
qrCodeContent = "{\"type\":\"invite\",\"code\":\"$generatedInviteCode\",\"expire\":$expireTimestamp}"
// 输出日志,方便调试验证
android.util.Log.d("InvitationCode", "生成的二维码内容: $qrCodeContent")
android.util.Log.d("InvitationCode", "推荐码: $generatedInviteCode, 过期时间戳: $expireTimestamp")
return qrCodeContent
private fun parseRecommendationCode(data: Any?): Pair<String, Long>? {
if (data == null) return null
return when (data) {
is String -> {
if (data.isEmpty()) null
else Pair(data, System.currentTimeMillis() + expireTimeInMillis)
}
else -> {
val bean = Gson().fromJson(Gson().toJson(data), RecommendationCodeBean::class.java)
val code = bean.inviteCode?.takeIf { it.isNotEmpty() }
?: bean.code?.takeIf { it.isNotEmpty() }
?: return null
val expire = bean.expireTime ?: bean.expire
?: (System.currentTimeMillis() + expireTimeInMillis)
Pair(code, expire)
}
}
}
/*
* 这段代码生成带Logo的二维码
@@ -232,7 +428,7 @@ class InvitationCodeActivity : AppCompatActivity() {
}
}
val logoDrawable = ContextCompat.getDrawable(this, R.mipmap.loge)
val logoDrawable = ContextCompat.getDrawable(this, R.mipmap.logo)
if (logoDrawable != null) {
val logoSize = width / 5
val logoX = (width - logoSize) / 2
@@ -415,56 +611,62 @@ class InvitationCodeActivity : AppCompatActivity() {
/**
* 撤销邀请
*/
private fun cancelInvitation() {
// 撤销邀请逻辑
hideQrCode()
generatedInviteCode = ""
qrCodeContent = ""
expireTimestamp = 0
hasGeneratedQrCode = false
// 恢复按钮文字为"生成邀请码"
binding.btnRegenerate.text = getString(R.string.generate_invite_code)
// 显示提示
ToastUtils.showSuccess(this, getString(R.string.operation_success))
}
/**
* 显示密码输入对话框
* @param onSuccess 验证成功后的回调
*/
private fun showPasswordDialog(onSuccess: () -> Unit) {
val dialog = PasswordInputDialog(this)
dialog.setTitle(getString(R.string.input_op_pwd))
dialog.setOnConfirmListener { password ->
verifyPassword(password, dialog, onSuccess)
private fun cancelInvitation(password: String, passwordDialog: PasswordInputDialog) {
if (isLoading) return
if (generatedInviteCode.isEmpty()) {
passwordDialog.showError(getString(R.string.qr_code_expired))
return
}
dialog.show()
}
isLoading = true
val loadingDialog = LoadingDialog(this).apply { show() }
/**
* 验证操作密码
*/
private fun verifyPassword(password: String, dialog: PasswordInputDialog, onSuccess: () -> Unit) {
CoroutineScope(Dispatchers.IO).launch {
try {
val response = RetrofitNetwork.getNetworkService()
.verifyOptionPassword(VerifyOptionPasswordRequest(password))
.revokeInvitation(VerifyOptionPasswordRequest(password))
Log.d(TAG, "撤销邀请响应: code=${response.code}, msg=${response.msg}")
withContext(Dispatchers.Main) {
isLoading = false
loadingDialog.dismiss()
if (response.code == 200) {
dialog.dismiss()
onSuccess.invoke()
passwordDialog.dismiss()
hideQrCode()
generatedInviteCode = ""
qrCodeContent = ""
expireTimestamp = 0
hasGeneratedQrCode = false
binding.btnRegenerate.text = getString(R.string.generate_invite_code)
ToastUtils.showSuccess(this@InvitationCodeActivity, getString(R.string.operation_success))
} else {
dialog.showError(getString(R.string.password_error))
passwordDialog.showError(
response.msg.ifEmpty { getString(R.string.password_error) }
)
}
}
} catch (e: Exception) {
Log.e(TAG, "撤销邀请异常", e)
withContext(Dispatchers.Main) {
dialog.showError(getString(R.string.network_error))
isLoading = false
loadingDialog.dismiss()
passwordDialog.showError(getString(R.string.network_error))
}
}
}
}
/**
* 显示密码输入对话框
*/
private fun showPasswordDialog(onConfirm: (String, PasswordInputDialog) -> Unit) {
val dialog = PasswordInputDialog(this)
dialog.setTitle(getString(R.string.input_op_pwd))
dialog.setOnConfirmListener { password ->
onConfirm(password, dialog)
}
dialog.show()
}
override fun onDestroy() {
super.onDestroy()
expireTimeDialog?.dismiss()

View File

@@ -0,0 +1,123 @@
package com.ckkj.defense_device.personal
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.ckkj.defense_device.R
import com.ckkj.defense_device.bean.JoinTheFamilyBean
import com.ckkj.defense_device.databinding.JoinFamilyInviteActivityBinding
import com.ckkj.defense_device.home.HomeActivity
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.ckkj.defense_device.view.LoadingDialog
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
// 邀请加入家庭
class JoinFamilyInviteActivity : AppCompatActivity() {
private lateinit var binding: JoinFamilyInviteActivityBinding
private var isLoading = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = JoinFamilyInviteActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
ImmersionBar.with(this)
.statusBarDarkFont(true)
.titleBar(binding.topBar)
.init()
binding.ivBack.setOnClickListener { finish() }
binding.btnJoinNow.setOnClickListener { joinFamily() }
displayInviterInfo()
}
private fun joinFamily() {
if (isLoading) return
val parentId = intent.getStringExtra(EXTRA_USER_ID).orEmpty()
val inviteCode = intent.getStringExtra(EXTRA_INVITE_CODE).orEmpty()
if (parentId.isEmpty() || inviteCode.isEmpty()) {
Log.e(TAG, "加入家庭参数无效: parentId=$parentId, inviteCode=$inviteCode")
Toast.makeText(this, R.string.network_error, Toast.LENGTH_SHORT).show()
return
}
Log.e(TAG, "加入家庭请求: parentId=$parentId, inviteCode=$inviteCode")
isLoading = true
val loadingDialog = LoadingDialog(this).apply { show() }
CoroutineScope(Dispatchers.IO).launch {
try {
val response = RetrofitNetwork.getNetworkService()
.joinTheFamily(JoinTheFamilyBean(parentId = parentId, inviteCode = inviteCode))
Log.e(TAG, "加入家庭响应: code=${response.code}, msg=${response.msg}, data=${response.data}")
withContext(Dispatchers.Main) {
isLoading = false
loadingDialog.dismiss()
if (response.code == 200) {
Log.e(TAG, "加入家庭成功,返回首页刷新")
ToastUtils.showSuccess(this@JoinFamilyInviteActivity, getString(R.string.operation_success))
val homeIntent = Intent(this@JoinFamilyInviteActivity, HomeActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
putExtra(HomeActivity.EXTRA_REFRESH, true)
}
startActivity(homeIntent)
finish()
} else {
Log.e(TAG, "加入家庭失败: code=${response.code}, msg=${response.msg}")
Toast.makeText(
this@JoinFamilyInviteActivity,
response.msg.ifBlank { getString(R.string.network_error) },
Toast.LENGTH_SHORT
).show()
}
}
} catch (e: Exception) {
Log.e(TAG, "加入家庭请求异常", e)
withContext(Dispatchers.Main) {
isLoading = false
loadingDialog.dismiss()
Toast.makeText(this@JoinFamilyInviteActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
}
}
}
}
private fun displayInviterInfo() {
val nickName = intent.getStringExtra(EXTRA_NICK_NAME).orEmpty()
val avatar = intent.getStringExtra(EXTRA_AVATAR)
binding.tvNickname.text = nickName.ifEmpty { getString(R.string.nickname_placeholder) }
binding.tvInviteMessage.text = getString(
R.string.invite_join_family_message,
nickName.ifEmpty { getString(R.string.nickname_placeholder) }
)
val requestOptions = RequestOptions()
.placeholder(R.mipmap.img)
.error(R.mipmap.img)
Glide.with(this)
.load(avatar)
.apply(requestOptions)
.circleCrop()
.into(binding.ivAvatar)
}
companion object {
private const val TAG = "JoinFamilyInviteActivity"
const val EXTRA_INVITE_CODE = "invite_code"
const val EXTRA_NICK_NAME = "nick_name"
const val EXTRA_AVATAR = "avatar"
const val EXTRA_PARENT_ID = "parent_id"
const val EXTRA_USER_ID = "user_id"
}
}

View File

@@ -1,14 +1,9 @@
package com.example.defenseapplication.personal
package com.ckkj.defense_device.personal
import android.content.Intent
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.LoginPasswordActivityBinding
import com.example.defenseapplication.databinding.PasswordManagementActivityBinding
import com.ckkj.defense_device.databinding.LoginPasswordActivityBinding
import com.gyf.immersionbar.ImmersionBar
//登录密码

View File

@@ -1,16 +1,16 @@
package com.example.defenseapplication.personal
package com.ckkj.defense_device.personal
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.R
import com.example.defenseapplication.bean.UpdateUserInfo
import com.example.defenseapplication.bean.VerifyOptionPasswordRequest
import com.example.defenseapplication.databinding.OperationPasswordActivityBinding
import com.example.defenseapplication.utils.RetrofitNetwork
import com.example.defenseapplication.view.CustomDialogFragment
import com.example.defenseapplication.view.LoadingDialog
import com.example.defenseapplication.view.showDefenseDialog
import com.ckkj.defense_device.R
import com.ckkj.defense_device.bean.UpdateUserInfo
import com.ckkj.defense_device.bean.VerifyOptionPasswordRequest
import com.ckkj.defense_device.databinding.OperationPasswordActivityBinding
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.ckkj.defense_device.view.CustomDialogFragment
import com.ckkj.defense_device.view.LoadingDialog
import com.ckkj.defense_device.view.showDefenseDialog
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers

View File

@@ -1,9 +1,9 @@
package com.example.defenseapplication.personal
package com.ckkj.defense_device.personal
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.databinding.PasswordManagementActivityBinding
import com.ckkj.defense_device.databinding.PasswordManagementActivityBinding
import com.gyf.immersionbar.ImmersionBar
//密码管理
class PasswordManagementActivity : AppCompatActivity() {

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.personal
package com.ckkj.defense_device.personal
import android.Manifest
import android.content.ContentResolver
@@ -11,24 +11,21 @@ import android.os.Environment
import android.provider.MediaStore
import android.util.Log
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.example.defenseapplication.R
import com.example.defenseapplication.bean.UpdateUserInfo
import com.example.defenseapplication.bean.UserInfoBean
import com.example.defenseapplication.databinding.PersonalProfileActivityBinding
import com.example.defenseapplication.utils.RetrofitNetwork
import com.example.defenseapplication.view.AvatarSelectDialog
import com.example.defenseapplication.view.CustomDialogFragmentText
import com.example.defenseapplication.view.LoadingDialog
import com.example.defenseapplication.view.PhoneModifyDialogFragment
import com.ckkj.defense_device.R
import com.ckkj.defense_device.bean.UpdateUserInfo
import com.ckkj.defense_device.bean.UserInfoBean
import com.ckkj.defense_device.databinding.PersonalProfileActivityBinding
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.ckkj.defense_device.view.AvatarSelectDialog
import com.ckkj.defense_device.view.CustomDialogFragmentText
import com.ckkj.defense_device.view.LoadingDialog
import com.ckkj.defense_device.view.PhoneModifyDialogFragment
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers

View File

@@ -1,13 +1,13 @@
package com.example.defenseapplication.personal
package com.ckkj.defense_device.personal
import android.os.Bundle
import android.os.CountDownTimer
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import bean.ForgotRequest
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.RetrievePasswordActivityBinding
import com.example.defenseapplication.utils.RetrofitNetwork
import com.ckkj.defense_device.R
import com.ckkj.defense_device.databinding.RetrievePasswordActivityBinding
import com.ckkj.defense_device.utils.RetrofitNetwork
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -163,7 +163,7 @@ class RetrievePasswordActivity : AppCompatActivity() {
override fun onFinish() {
isCountingDown = false
binding.btnGetCode.isEnabled = true
binding.btnGetCode.text = getString(R.string.get_verification_code)
binding.btnGetCode.text = getString(R.string.resend_code)
}
}.start()
}

View File

@@ -0,0 +1,111 @@
package com.ckkj.defense_device.personal
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import com.ckkj.defense_device.databinding.SettingsMenusActivityBinding
import com.gyf.immersionbar.ImmersionBar
import java.io.File
class SettingsMenusActivity : AppCompatActivity() {
private lateinit var binding: SettingsMenusActivityBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
binding = SettingsMenusActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
ImmersionBar.with(this)
.statusBarDarkFont(true)
.titleBar(binding.topBar)
.init()
val versionName = packageManager.getPackageInfo(packageName, 0).versionName
binding.tvVersion.text = versionName
// 显示缓存大小
displayCacheSize()
setupClickListeners()
}
private fun setupClickListeners() {
// 返回按钮
binding.ivBack.setOnClickListener {
finish()
}
// 检查更新
binding.itemCheckUpdate.setOnClickListener {
Toast.makeText(this, "正在检查更新...", Toast.LENGTH_SHORT).show()
}
// 清除缓存
binding.itemClearCache.setOnClickListener {
clearCache()
displayCacheSize() // 更新缓存大小显示
Toast.makeText(this, "缓存已清除", Toast.LENGTH_SHORT).show()
}
// 用户协议
binding.itemUserAgreement.setOnClickListener {
}
// 隐私政策
binding.itemPrivacyPolicy.setOnClickListener {
}
// 注销账号
binding.itemLogout.setOnClickListener {
val intent = Intent(this, CancelAccountActivity::class.java)
startActivity(intent)
}
}
//缓存方法
private fun displayCacheSize() {
val cacheSize = getCacheSize()
val sizeString = when {
cacheSize >= 1024 * 1024 -> String.format("%.2f MB", cacheSize / (1024.0 * 1024.0))
else -> String.format("%d KB", cacheSize / 1024)
}
binding.tvCacheSize.text = sizeString
}
private fun getCacheSize(): Long {
val cacheDir = cacheDir
return getFolderSize(cacheDir)
}
private fun getFolderSize(dir: File?): Long {
var size = 0L
if (dir != null && dir.isDirectory) {
dir.listFiles()?.forEach { file ->
size += if (file.isFile) {
file.length()
} else {
getFolderSize(file)
}
}
}
return size
}
private fun clearCache() {
val cacheDir = cacheDir
deleteDir(cacheDir)
}
private fun deleteDir(dir: File?): Boolean {
if (dir != null && dir.isDirectory) {
dir.listFiles()?.forEach { file ->
deleteDir(file)
}
}
return dir?.delete() ?: false
}
}

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.utils
package com.ckkj.defense_device.utils
import android.app.Activity
import java.lang.ref.WeakReference

View File

@@ -1,8 +1,14 @@
package com.example.defenseapplication.utils
package com.ckkj.defense_device.utils
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Handler
import android.os.Looper
import android.util.Log
import com.example.defenseapplication.bean.BaseInfo
import android.widget.Toast
import com.blankj.utilcode.util.Utils
import com.ckkj.defense_device.bean.BaseInfo
import com.ckkj.defense_device.login.LoginActivity
import com.google.gson.Gson
import com.google.gson.JsonParser
import okhttp3.Interceptor
@@ -24,10 +30,17 @@ object ApiConfig {
@Volatile
public var authToken: String = ""
@Volatile
private var isRedirectingToLogin = false
fun updateAuthToken(token: String) {
authToken = token
}
fun resetAuthRedirectFlag() {
isRedirectingToLogin = false
}
fun hasAuthToken(): Boolean {
return authToken.isNotBlank()
}
@@ -116,8 +129,8 @@ object ApiConfig {
val businessCode = if (jsonObject.has("code")) jsonObject.get("code").asInt else 0
if (httpCode == 401 || httpCode == 424 || businessCode == 401) {
clearUserLoginInfo()
val msg = if (jsonObject.has("msg")) jsonObject.get("msg").asString else "登录已过期,请重新登录"
redirectToLogin(msg)
return@Interceptor buildFakeErrorResponse(request, msg, code = if (businessCode != 0) businessCode else httpCode)
}
@@ -138,7 +151,7 @@ object ApiConfig {
*/
private fun buildFakeErrorResponse(request: Request, msg: String, code: Int = 1): Response {
val baseInfo = BaseInfo(
message = msg,
msg = msg,
code = code,
data = null,
)
@@ -179,12 +192,36 @@ object ApiConfig {
private fun buildAuthorizationValue(token: String): String {
return if (token.startsWith("Bearer ")) token else "Bearer $token"
}
//401跳转登录界面
private fun redirectToLogin(msg: String) {
Handler(Looper.getMainLooper()).post {
if (isRedirectingToLogin) return@post
val current = ActivityManager.getCurrentActivity()
if (current is LoginActivity) return@post
isRedirectingToLogin = true
clearUserLoginInfo()
val context = current ?: Utils.getApp()
ActivityManager.finishAllActivities()
val intent = Intent(context, LoginActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
context.startActivity(intent)
if (msg.isNotBlank()) {
Toast.makeText(Utils.getApp(), msg, Toast.LENGTH_SHORT).show()
}
}
}
private fun clearUserLoginInfo() {
try {
authToken = ""
UserinfoUtil.clearUserInfo()
} catch (e: Exception) {
e.printStackTrace()
authToken = ""
}
}
}

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