66 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
5cafd2ac1d 登录启动页优化 2026-06-08 10:39:30 +08:00
c2b947c630 实时视频组件优化 2026-06-05 17:17:33 +08:00
d60322cbc2 视频组件 2026-06-05 09:33:30 +08:00
88c791a520 视频组件更换StandardGSYVideoPlayer 2026-06-04 17:51:19 +08:00
508 changed files with 6253 additions and 2871 deletions

View File

@@ -3,6 +3,17 @@
<component name="deploymentTargetSelector"> <component name="deploymentTargetSelector">
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <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" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2026-05-18T09:18:19.023586Z"> <DropdownSelection timestamp="2026-05-18T09:18:19.023586Z">
<Target type="DEFAULT_BOOT"> <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 { android {
namespace = "com.example.defenseapplication" namespace = "com.ckkj.defense_device"
compileSdk { compileSdk {
version = release(36) { version = release(36) {
minorApiLevel = 1 minorApiLevel = 1
@@ -11,9 +11,9 @@ android {
} }
defaultConfig { defaultConfig {
applicationId = "com.example.defenseapplication" applicationId = "com.ckkj.defense_device"
minSdk = 24 minSdk = 24
targetSdk = 36 targetSdk = 30
versionCode = 1 versionCode = 1
versionName = "1.0" versionName = "1.0"
@@ -36,6 +36,11 @@ android {
buildFeatures { buildFeatures {
viewBinding=true viewBinding=true
} }
lint {
disable += "ExpiredTargetSdkVersion"
checkReleaseBuilds = false
abortOnError = false
}
} }
dependencies { dependencies {
@@ -69,14 +74,8 @@ dependencies {
// Kotlin 协程 // Kotlin 协程
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3") 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 人脸检测 // Google ML Kit 人脸检测
implementation("com.google.mlkit:face-detection:16.1.5") implementation("com.google.mlkit:face-detection:16.1.5")
// 图形绘制库(绘制人脸框)
implementation("com.github.bumptech.glide:glide:4.15.1")
//Glide 依赖 //Glide 依赖
implementation("com.github.bumptech.glide:glide:4.16.0") implementation("com.github.bumptech.glide:glide:4.16.0")
// ZXing 二维码扫描库 // ZXing 二维码扫描库
@@ -87,8 +86,6 @@ dependencies {
implementation("com.geyifeng.immersionbar:immersionbar-ktx:3.2.2") implementation("com.geyifeng.immersionbar:immersionbar-ktx:3.2.2")
implementation("com.wdullaer:materialdatetimepicker:4.2.3") // 经典稳定 implementation("com.wdullaer:materialdatetimepicker:4.2.3") // 经典稳定
implementation("androidx.core:core-ktx:1.12.0") 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.github.maning0303:MNMLKitScanner:V1.0.4")
implementation("com.google.mlkit:barcode-scanning:17.0.2") implementation("com.google.mlkit:barcode-scanning:17.0.2")
@@ -101,8 +98,10 @@ dependencies {
implementation("com.yanzhenjie.recyclerview:x:1.3.2") implementation("com.yanzhenjie.recyclerview:x:1.3.2")
//Android-PickerView-时间弹窗 //Android-PickerView-时间弹窗
implementation("com.contrarywind:Android-PickerView:4.1.9") implementation("com.contrarywind:Android-PickerView:4.1.9")
//基于exoPlayer 自定义播放器 JPlayer支持功能 // GSYVideoPlayer
implementation("com.ycjiang:VideoPlayModule-Lite:2.3.61") 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.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4

View File

@@ -22,17 +22,36 @@
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/loge" android:icon="@mipmap/logo"
android:label="@string/app_name" android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.DefenseApplication"> 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">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity <activity
android:name=".personal.LoginPasswordActivity" android:name=".personal.LoginPasswordActivity"
android:exported="false" /> android:exported="false" />
<activity <activity
android:name=".personal.InvitationCodeActivity" android:name=".personal.InvitationCodeActivity"
android:exported="false" /> android:exported="false" />
<activity
android:name=".personal.JoinFamilyInviteActivity"
android:exported="false" />
<activity <activity
android:name=".liveVideo.StrikePositionActivity" android:name=".liveVideo.StrikePositionActivity"
android:exported="false" /> android:exported="false" />
@@ -90,6 +109,7 @@
android:exported="false" /> android:exported="false" />
<activity <activity
android:name=".liveVideo.LiveVideoActivity" android:name=".liveVideo.LiveVideoActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:exported="false" /> android:exported="false" />
<activity <activity
android:name=".home.SetNameActivity" android:name=".home.SetNameActivity"
@@ -126,13 +146,7 @@
android:exported="false" /> android:exported="false" />
<activity <activity
android:name=".login.LoginActivity" android:name=".login.LoginActivity"
android:exported="true"> android:exported="false" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider <provider
android:name="androidx.core.content.FileProvider" android:name="androidx.core.content.FileProvider"

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.LayoutInflater
import android.view.View import android.view.View
@@ -6,7 +6,7 @@ import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.R import com.ckkj.defense_device.R
data class Device( data class Device(
val name: String, val name: String,
@@ -18,6 +18,8 @@ class AddDeviceAdapter(
private val onItemClick: (Device) -> Unit private val onItemClick: (Device) -> Unit
) : RecyclerView.Adapter<AddDeviceAdapter.ViewHolder>() { ) : 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) { inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val ivIcon: ImageView = itemView.findViewById(R.id.ivDeviceIcon2) val ivIcon: ImageView = itemView.findViewById(R.id.ivDeviceIcon2)
val tvName: TextView = itemView.findViewById(R.id.tvDeviceName2) val tvName: TextView = itemView.findViewById(R.id.tvDeviceName2)
@@ -47,7 +49,9 @@ class AddDeviceAdapter(
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val device = devices[position] val device = devices[position]
holder.tvName.text = device.name 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) } 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.graphics.Color
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.R import com.ckkj.defense_device.databinding.ItemAddLinkedUserBinding
import com.example.defenseapplication.databinding.ItemAddLinkedUserBinding
data class UserItem(val name: String, val phone: String, val userId: String = "") 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.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.bean.DeviceAlarmBean import com.ckkj.defense_device.bean.DeviceAlarmBean
import com.example.defenseapplication.databinding.ItemAlarmLogBinding import com.ckkj.defense_device.databinding.ItemAlarmLogBinding
class AlarmLogAdapter( class AlarmLogAdapter(
private val items: List<DeviceAlarmBean>, 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.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.example.defenseapplication.bean.DeviceAlarmBean import com.ckkj.defense_device.bean.DeviceAlarmBean
import com.example.defenseapplication.databinding.ItemAlarmLogHorizontalBinding import com.ckkj.defense_device.databinding.ItemAlarmLogHorizontalBinding
class AlarmLogHorizontalAdapter( class AlarmLogHorizontalAdapter(
private val items: List<DeviceAlarmBean>, 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.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.R import com.bumptech.glide.Glide
import com.example.defenseapplication.databinding.ItemDeviceBinding import com.ckkj.defense_device.R
import com.ckkj.defense_device.bean.DeviceBean
data class DeviceUi( import com.ckkj.defense_device.databinding.ItemDeviceBinding
val name: String,
val status: String,
val deviceId: String = ""
) {
val isOnline: Boolean
get() = status == "1"
}
class DeviceAdapter( class DeviceAdapter(
private val onItemClick: (DeviceUi) -> Unit = {} private val onItemClick: (DeviceBean) -> Unit = {}
) : RecyclerView.Adapter<DeviceAdapter.DeviceViewHolder>() { ) : 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.clear()
items.addAll(deviceList) items.addAll(deviceList)
notifyDataSetChanged() notifyDataSetChanged()
@@ -33,15 +26,25 @@ class DeviceAdapter(
} }
override fun onBindViewHolder(holder: DeviceViewHolder, position: Int) { override fun onBindViewHolder(holder: DeviceViewHolder, position: Int) {
holder.bind(items[position]) holder.bind(items[position], position)
} }
override fun getItemCount(): Int = items.size 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) : inner class DeviceViewHolder(private val binding: ItemDeviceBinding) :
RecyclerView.ViewHolder(binding.root) { 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 binding.tvDeviceType.text = item.name
when (item.status) { when (item.status) {
"1" -> { "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.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.bean.FamilyBean import com.ckkj.defense_device.bean.FamilyBean
import com.example.defenseapplication.databinding.ItemFamilyBinding import com.ckkj.defense_device.databinding.ItemFamilyBinding
class FamilyAdapter( class FamilyAdapter(
private val onItemClick: (String) -> Unit private val onItemClick: (String) -> Unit
@@ -64,7 +64,7 @@ class FamilyAdapter(
binding.tvFamilyName.setTextColor(binding.root.context.getColor(R.color.white)) binding.tvFamilyName.setTextColor(binding.root.context.getColor(R.color.white))
binding.tvFamilyRole.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.visibility = View.VISIBLE
binding.ivCheck.setImageResource(R.drawable.ic_check_white) binding.ivCheck.setImageResource(R.mipmap.ic_check_white)
} else { } else {
binding.layoutFamilyItem.setBackgroundResource(0) binding.layoutFamilyItem.setBackgroundResource(0)
binding.tvFamilyName.setTextColor(binding.root.context.getColor(R.color.black)) 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.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.databinding.ItemSwitchFamilyBinding import com.ckkj.defense_device.databinding.ItemSwitchFamilyBinding
import com.example.defenseapplication.model.FamilyItem import com.ckkj.defense_device.model.FamilyItem
class FamilySwitchAdapter( class FamilySwitchAdapter(
private var familyList: List<FamilyItem>, 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.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.databinding.ItemLinkedUserBinding import com.ckkj.defense_device.databinding.ItemLinkedUserBinding
data class LinkedUser( data class LinkedUser(
val userId: String, 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.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.databinding.ItemMessageGroupTitleBinding import com.ckkj.defense_device.databinding.ItemMessageGroupTitleBinding
import com.example.defenseapplication.databinding.ItemMessageNoticeBinding import com.ckkj.defense_device.databinding.ItemMessageNoticeBinding
sealed class MessageListItem { sealed class MessageListItem {
data class Header(val title: String) : 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.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.databinding.ItemWifiBinding import com.ckkj.defense_device.databinding.ItemWifiBinding
class WifiListAdapter( class WifiListAdapter(
wifiList: List<String>, wifiList: List<String>,
@@ -39,14 +40,25 @@ class WifiListAdapter(
override fun getItemCount(): Int = wifiList.size override fun getItemCount(): Int = wifiList.size
fun updateData(newList: List<String>) { 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.clear()
wifiList.addAll(newList) wifiList.addAll(newList)
notifyDataSetChanged() diffResult.dispatchUpdatesTo(this)
} }
fun addData(newList: List<String>) { fun addData(newList: List<String>) {
val startPosition = wifiList.size val startPosition = wifiList.size
val newItems = newList.filter { !wifiList.contains(it) } val newItems = newList.filter { !wifiList.contains(it) }
if (newItems.isEmpty()) return
wifiList.addAll(newItems) wifiList.addAll(newItems)
notifyItemRangeInserted(startPosition, newItems.size) 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.content.Context
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.utils.ActivityManager import com.ckkj.defense_device.utils.ActivityManager
import com.example.defenseapplication.utils.LanguageUtil import com.ckkj.defense_device.utils.LanguageUtil
open class BaseActivity : AppCompatActivity() { open class BaseActivity : AppCompatActivity() {

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean package com.ckkj.defense_device.bean
data class DeleteDeviceUserRequest( data class DeleteDeviceUserRequest(
val userId: String, 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.Parcel
import android.os.Parcelable import android.os.Parcelable

View File

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

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean package com.ckkj.defense_device.bean
data class DeviceBean( data class DeviceBean(
val alertAudio: String? = null,//告警播放 val alertAudio: String? = null,//告警播放
@@ -9,11 +9,11 @@ data class DeviceBean(
val deviceFamilyId: String? = null, val deviceFamilyId: String? = null,
val deviceImg: String? = null, val deviceImg: String? = null,
val deviceName: String? = null,//设备名称 val deviceName: String? = null,//设备名称
val deviceNo: String? = null,//设备编号 val deviceNo: String = "",//设备编号
val deviceSn: String? = null,//设备序列号 val deviceSn: String = "",//设备序列号
val endTime: String? = null,//自动布放结束时间 val endTime: String? = null,//自动布放结束时间
val expirationTime: String? = null, val expirationTime: String? = null,
val fwVer: String? = null,//固件版本 val fwVer: String= "",//固件版本
val id: String? = null, val id: String? = null,
val light: String? = null,//强光开启 val light: String? = null,//强光开启
val patternPerception: String? = null,//识别模式 val patternPerception: String? = null,//识别模式
@@ -27,4 +27,13 @@ data class DeviceBean(
val wifiPassword: String? = null,//WiFi密码 val wifiPassword: String? = null,//WiFi密码
val workMode: String? = null,//工作模式 0-自动 1-半自动 val workMode: String? = null,//工作模式 0-自动 1-半自动
val optionPassword: String? = null, //操作密码 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( data class DeviceUserBean(
val createDept: Int ? = null, //创建部门 val createDept: Int ? = null, //创建部门

View File

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

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean package com.ckkj.defense_device.bean
data class FamilyMembersBean( data class FamilyMembersBean(
val id: String? = null, // ID 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> ( data class GetCodeBean<T> (
val code:Int, 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.Parcel
import android.os.Parcelable import android.os.Parcelable

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean package com.ckkj.defense_device.bean
data class ObtainInviterInformationRequest( data class ObtainInviterInformationRequest(
val childId: String 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( data class SwitchFamilyRequest(
val clientId: String, 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( data class UpdatePassword(
val oldPassword: String, val oldPassword: String,

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.bean package com.ckkj.defense_device.bean
data class VerifyOptionPasswordRequest( data class VerifyOptionPasswordRequest(
val optionPassword: String 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.Manifest
import android.app.Activity
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Build import android.os.Build
@@ -14,10 +13,10 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.adapter.AddDeviceAdapter import com.ckkj.defense_device.adapter.AddDeviceAdapter
import com.example.defenseapplication.adapter.Device import com.ckkj.defense_device.adapter.Device
import com.example.defenseapplication.databinding.AddDeviceActivityBinding import com.ckkj.defense_device.databinding.AddDeviceActivityBinding
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import com.maning.mlkitscanner.scan.MNScanManager import com.maning.mlkitscanner.scan.MNScanManager
import com.maning.mlkitscanner.scan.callback.act.MNScanCallback 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.Manifest
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
@@ -23,10 +23,10 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.adapter.WifiListAdapter import com.ckkj.defense_device.adapter.WifiListAdapter
import com.example.defenseapplication.databinding.AddFamilyActivityBinding import com.ckkj.defense_device.databinding.AddFamilyActivityBinding
import com.example.defenseapplication.databinding.DialogWifiListBinding import com.ckkj.defense_device.databinding.DialogWifiListBinding
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
//选择Wi-Fi //选择Wi-Fi
class AddFamilyActivity : AppCompatActivity() { class AddFamilyActivity : AppCompatActivity() {
@@ -144,10 +144,6 @@ class AddFamilyActivity : AppCompatActivity() {
} }
dialogBinding.rvWifiList.adapter = wifiListAdapter dialogBinding.rvWifiList.adapter = wifiListAdapter
dialogBinding.swipeRefreshLayout.setOnRefreshListener {
refreshWifiList(dialogBinding)
}
dialogBinding.rvWifiList.addOnScrollListener(object : RecyclerView.OnScrollListener() { dialogBinding.rvWifiList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy) super.onScrolled(recyclerView, dx, dy)
@@ -168,16 +164,6 @@ class AddFamilyActivity : AppCompatActivity() {
return rect.height() 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() { private fun loadMoreWifiList() {
isLoadingMore = true isLoadingMore = true
handler.postDelayed({ handler.postDelayed({
@@ -204,12 +190,8 @@ class AddFamilyActivity : AppCompatActivity() {
} }
private fun updateWifiList() { private fun updateWifiList() {
popupWindow?.contentView?.findViewById<androidx.recyclerview.widget.RecyclerView>(R.id.rvWifiList)?.let { recyclerView -> popupWindow?.contentView?.findViewById<androidx.recyclerview.widget.RecyclerView>(R.id.rvWifiList)?.let {
val wifiList = getWifiList() wifiListAdapter?.updateData(getWifiList())
recyclerView.adapter = WifiListAdapter(wifiList) { wifiName ->
binding.etWifiName.setText(wifiName)
popupWindow?.dismiss()
}
} }
} }

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.home package com.ckkj.defense_device.home
import android.content.Intent import android.content.Intent
import android.graphics.drawable.AnimationDrawable import android.graphics.drawable.AnimationDrawable
@@ -6,14 +6,9 @@ import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.view.View import android.view.View
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat import com.ckkj.defense_device.R
import androidx.core.view.WindowInsetsCompat import com.ckkj.defense_device.databinding.ConnectDeviceActivityBinding
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.AddDeviceActivityBinding
import com.example.defenseapplication.databinding.ConnectDeviceActivityBinding
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
//连接设备 //连接设备
class ConnectDeviceActivity : AppCompatActivity() { 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 android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.base.BaseActivity import com.ckkj.defense_device.base.BaseActivity
import com.example.defenseapplication.databinding.HomeActivityBinding import com.ckkj.defense_device.databinding.HomeActivityBinding
import com.example.defenseapplication.databinding.HomeMenuFragmentBinding
import com.gyf.immersionbar.ImmersionBar
class HomeActivity : BaseActivity() { class HomeActivity : BaseActivity() {
companion object {
const val EXTRA_REFRESH = "extra_refresh"
}
// ViewBinding 核心对象 // ViewBinding 核心对象
private lateinit var binding: HomeActivityBinding private lateinit var binding: HomeActivityBinding
@@ -37,10 +37,10 @@ class HomeActivity : BaseActivity() {
binding.tabHome.setOnClickListener { binding.tabHome.setOnClickListener {
switchFragment(homeMenuFragment) 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.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)) binding.tvProfile.setTextColor(resources.getColor(R.color.ic_normal))
} }
@@ -48,12 +48,34 @@ class HomeActivity : BaseActivity() {
binding.tabProfile.setOnClickListener { binding.tabProfile.setOnClickListener {
switchFragment(personalFragment) switchFragment(personalFragment)
// 切换图标 + 文字颜色 // 切换图标 + 文字颜色
binding.ivHome.setImageResource(R.drawable.home) binding.ivHome.setImageResource(R.mipmap.home)
binding.tvHome.setTextColor(resources.getColor(R.color.ic_normal)) 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)) 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.Manifest
import android.app.Activity import android.app.Activity
@@ -7,7 +7,7 @@ import android.content.pm.PackageManager
import android.graphics.Color import android.graphics.Color
import android.os.Build import android.os.Build
import android.graphics.Rect import android.graphics.Rect
import android.graphics.drawable.GradientDrawable
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.util.TypedValue import android.util.TypedValue
@@ -21,23 +21,27 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.R import com.alibaba.sdk.android.emas.g
import com.example.defenseapplication.adapter.DeviceAdapter import com.ckkj.defense_device.R
import com.example.defenseapplication.adapter.DeviceUi import com.ckkj.defense_device.adapter.DeviceAdapter
import com.example.defenseapplication.adapter.FamilyAdapter import com.ckkj.defense_device.adapter.FamilyAdapter
import com.example.defenseapplication.bean.DeviceBean import com.ckkj.defense_device.bean.DeviceBean
import com.example.defenseapplication.bean.FamilyBean import com.ckkj.defense_device.bean.FamilyBean
import com.example.defenseapplication.bean.SwitchFamilyRequest import com.ckkj.defense_device.bean.SwitchFamilyRequest
import com.example.defenseapplication.databinding.HomeMenuFragmentBinding import com.ckkj.defense_device.bean.SelectInviterInfoBean
import com.example.defenseapplication.liveVideo.LiveVideoActivity import com.ckkj.defense_device.databinding.HomeMenuFragmentBinding
import com.example.defenseapplication.utils.DeviceIdEvent import com.ckkj.defense_device.liveVideo.LiveVideoActivity
import com.example.defenseapplication.utils.DeviceUpdateEvent import com.ckkj.defense_device.personal.JoinFamilyInviteActivity
import com.example.defenseapplication.utils.FamilySwitchEvent import com.ckkj.defense_device.utils.DeviceIdEvent
import com.example.defenseapplication.utils.MessageStatusManager import com.ckkj.defense_device.utils.DeviceUpdateEvent
import com.example.defenseapplication.utils.RetrofitNetwork import com.ckkj.defense_device.utils.FamilySwitchEvent
import com.example.defenseapplication.utils.UserinfoUtil import com.ckkj.defense_device.utils.MessageStatusManager
import com.example.defenseapplication.view.DefenseDialogs import com.ckkj.defense_device.utils.RetrofitNetwork
import com.example.defenseapplication.view.showDefenseDialog 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.gyf.immersionbar.ImmersionBar
import com.maning.mlkitscanner.scan.MNScanManager import com.maning.mlkitscanner.scan.MNScanManager
import com.maning.mlkitscanner.scan.callback.act.MNScanCallback import com.maning.mlkitscanner.scan.callback.act.MNScanCallback
@@ -45,6 +49,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.json.JSONObject
//主页碎片 //主页碎片
class HomeMenuFragment : Fragment() { class HomeMenuFragment : Fragment() {
// ViewBinding // ViewBinding
@@ -59,18 +64,21 @@ class HomeMenuFragment : Fragment() {
private val pageSize = 10 private val pageSize = 10
private var hasMore = true private var hasMore = true
private var isLoading = false private var isLoading = false
private var loadingDialog: LoadingDialog? = null
private var lastNoMoreToastTime: Long = 0L
private val noMoreToastInterval: Long = 1500L
private val requestPermissionsLauncher = registerForActivityResult( private val requestPermissionsLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions() ActivityResultContracts.RequestMultiplePermissions()
) { permissions -> ) { permissions ->
val cameraGranted = permissions[Manifest.permission.CAMERA] ?: false val cameraGranted = permissions[Manifest.permission.CAMERA] ?: false
val storageGranted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { val storageGranted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
permissions[Manifest.permission.READ_MEDIA_IMAGES] ?: false permissions[Manifest.permission.READ_MEDIA_IMAGES] ?: false
} else { } else {
permissions[Manifest.permission.READ_EXTERNAL_STORAGE] ?: false permissions[Manifest.permission.READ_EXTERNAL_STORAGE] ?: false
} }
if (cameraGranted && storageGranted) { if (cameraGranted && storageGranted) {
startScan() startScan()
} else { } else {
@@ -83,7 +91,7 @@ class HomeMenuFragment : Fragment() {
requireContext(), requireContext(),
Manifest.permission.CAMERA Manifest.permission.CAMERA
) )
val storagePermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { val storagePermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
ContextCompat.checkSelfPermission( ContextCompat.checkSelfPermission(
requireContext(), requireContext(),
@@ -96,7 +104,7 @@ class HomeMenuFragment : Fragment() {
) )
} }
if (cameraPermission == PackageManager.PERMISSION_GRANTED && if (cameraPermission == PackageManager.PERMISSION_GRANTED &&
storagePermission == PackageManager.PERMISSION_GRANTED) { storagePermission == PackageManager.PERMISSION_GRANTED) {
startScan() startScan()
} else { } else {
@@ -122,23 +130,86 @@ class HomeMenuFragment : Fragment() {
MNScanManager.RESULT_SUCCESS -> { MNScanManager.RESULT_SUCCESS -> {
val result = data?.getStringArrayListExtra(MNScanManager.INTENT_KEY_RESULT_SUCCESS) val result = data?.getStringArrayListExtra(MNScanManager.INTENT_KEY_RESULT_SUCCESS)
if (!result.isNullOrEmpty()) { 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 { } else {
ToastUtils.showToast(requireContext(), "扫码结果为空") Toast.makeText(requireContext(), "扫码结果为空", Toast.LENGTH_SHORT).show()
} }
} }
MNScanManager.RESULT_FAIL -> { MNScanManager.RESULT_FAIL -> {
val error = data?.getStringExtra(MNScanManager.INTENT_KEY_RESULT_ERROR) val error = data?.getStringExtra(MNScanManager.INTENT_KEY_RESULT_ERROR)
ToastUtils.showToast(requireContext(), "扫码失败: $error") Toast.makeText(requireContext(), "扫码失败: $error", Toast.LENGTH_SHORT).show()
} }
MNScanManager.RESULT_CANCLE -> { 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 { private val unreadCountChangeListener = object : MessageStatusManager.UnreadCountChangeListener {
override fun onUnreadCountChanged(count: Int) { override fun onUnreadCountChanged(count: Int) {
updateUnreadCountUI(count) updateUnreadCountUI(count)
@@ -197,13 +268,8 @@ class HomeMenuFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
// 为 LinearLayout 设置渐变背景 binding.gradientLayout.setBackgroundColor(Color.TRANSPARENT)
setGradientBackground( binding.message.setOnClickListener {
view = binding.gradientLayout,
startColor = Color.parseColor("#EBDCED"),
endColor = Color.parseColor("#CAF4FF")
)
binding.message.setOnClickListener {
val intent = Intent(requireContext(), MessageActivity::class.java) val intent = Intent(requireContext(), MessageActivity::class.java)
startActivity(intent) startActivity(intent)
} }
@@ -236,9 +302,11 @@ class HomeMenuFragment : Fragment() {
) )
} }
binding.swipeRefreshLayout.setOnRefreshListener { binding.swipeRefreshLayout.setOnRefreshListener(object : PullRefreshLayout.OnRefreshListener {
refreshDeviceList() override fun onRefresh() {
} refreshDeviceList()
}
})
binding.rvDeviceList.addOnScrollListener(object : RecyclerView.OnScrollListener() { binding.rvDeviceList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
@@ -246,9 +314,24 @@ class HomeMenuFragment : Fragment() {
val layoutManager = recyclerView.layoutManager as GridLayoutManager val layoutManager = recyclerView.layoutManager as GridLayoutManager
val lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition() val lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition()
val totalItemCount = layoutManager.itemCount 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) { if (!isLoading && hasMore && lastVisibleItemPosition >= totalItemCount - 1 && dy > 0) {
loadMoreDevices() 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() { private fun fetchFamilyList() {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
try { try {
@@ -321,18 +408,22 @@ class HomeMenuFragment : Fragment() {
Log.d("HomeMenuFragment", "canViewDevice = $canViewDevice") Log.d("HomeMenuFragment", "canViewDevice = $canViewDevice")
if (canViewDevice) { if (canViewDevice) {
binding.tvDeviceTitle.visibility = View.VISIBLE binding.tvDeviceTitle.visibility = View.VISIBLE
binding.swipeRefreshLayout.visibility = View.VISIBLE
binding.rvDeviceList.visibility = View.VISIBLE binding.rvDeviceList.visibility = View.VISIBLE
binding.message.visibility = View.VISIBLE binding.message.visibility = View.VISIBLE
binding.addFamily.visibility = View.VISIBLE binding.addFamily.visibility = View.VISIBLE
binding.add.visibility = View.VISIBLE binding.add.visibility = View.VISIBLE
binding.layoutNoPermission.visibility = View.GONE binding.layoutNoPermission.visibility = View.GONE
binding.layoutNoNetwork.visibility = View.GONE
} else { } else {
binding.tvDeviceTitle.visibility = View.GONE binding.tvDeviceTitle.visibility = View.GONE
binding.swipeRefreshLayout.visibility = View.GONE
binding.rvDeviceList.visibility = View.GONE binding.rvDeviceList.visibility = View.GONE
binding.message.visibility = View.GONE binding.message.visibility = View.GONE
binding.addFamily.visibility = View.GONE binding.addFamily.visibility = View.GONE
binding.add.visibility = View.GONE binding.add.visibility = View.GONE
binding.layoutNoPermission.visibility = View.VISIBLE binding.layoutNoPermission.visibility = View.VISIBLE
binding.layoutNoNetwork.visibility = View.GONE
} }
} }
@@ -356,7 +447,7 @@ class HomeMenuFragment : Fragment() {
canViewDevice = userInfo?.role == "appadmin" && familyBean.role != "member" canViewDevice = userInfo?.role == "appadmin" && familyBean.role != "member"
updateAdminUI() updateAdminUI()
updateFamilyDisplayText(familyName) updateFamilyDisplayText(familyName)
fetchDeviceList() fetchDeviceList(showLoading = true)
FamilySwitchEvent.notifyFamilySwitched(familyName) FamilySwitchEvent.notifyFamilySwitched(familyName)
} else { } else {
Toast.makeText(requireContext(), response.msg, Toast.LENGTH_SHORT).show() 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 if (!canViewDevice || isLoading) return
isLoading = true isLoading = true
loadingDialog = if (showLoading) LoadingDialog(requireActivity()).setMessage(getString(R.string.loading)).apply { show() } else null
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
try { try {
val response = RetrofitNetwork.getNetworkService().getDeviceList() val response = RetrofitNetwork.getNetworkService().getDeviceList()
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if (!isAdded) return@withContext
loadingDialog?.dismiss()
loadingDialog = null
Log.d("DeviceList", "code = ${response.code}, data = ${response.data}") Log.d("DeviceList", "code = ${response.code}, data = ${response.data}")
if (response.code == 200 && response.data != null) { if (response.code == 200 && response.data != null) {
val newDevices = response.data val newDevices = response.data
@@ -390,32 +486,47 @@ class HomeMenuFragment : Fragment() {
hasMore = newDevices.size >= pageSize hasMore = newDevices.size >= pageSize
} }
Log.d("DeviceList", "deviceBeanList size = ${deviceBeanList.size}") Log.d("DeviceList", "deviceBeanList size = ${deviceBeanList.size}")
showDeviceContent()
updateDeviceList() updateDeviceList()
} else { } 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) { if (isLoadMore) {
hasMore = false hasMore = false
} }
} }
isLoading = false isLoading = false
binding.swipeRefreshLayout.finishRefresh()
} }
} catch (e: Exception) { } catch (e: Exception) {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if (!isAdded) return@withContext
loadingDialog?.dismiss()
loadingDialog = null
noNetwork()
Toast.makeText(requireContext(), R.string.network_error, Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), R.string.network_error, Toast.LENGTH_SHORT).show()
isLoading = false isLoading = false
if (isLoadMore) { if (isLoadMore) {
hasMore = false 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() { private fun refreshDeviceList() {
currentPage = 1 currentPage = 1
hasMore = true hasMore = true
fetchDeviceList(currentPage, false) fetchDeviceList(currentPage, false)
binding.swipeRefreshLayout.isRefreshing = false
} }
private fun loadMoreDevices() { private fun loadMoreDevices() {
@@ -445,26 +556,38 @@ class HomeMenuFragment : Fragment() {
} }
} }
private fun updateDeviceList() { private fun showDeviceContent() {
val deviceUiList = deviceBeanList.map { binding.swipeRefreshLayout.visibility = View.VISIBLE
DeviceUi(it.deviceName ?: "", it.status ?: "", it.id ?: "") 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( deviceAdapter.submitList(listOf(
DeviceUi(getString(R.string.no_device), "0") DeviceBean(deviceName = getString(R.string.no_device), status = "0")
)) ))
} else { } else {
deviceAdapter.submitList(deviceUiList) deviceAdapter.submitList(deviceBeanList)
} }
} }
private fun onDeviceClicked(device: DeviceUi) { private fun onDeviceClicked(device: DeviceBean) {
if (device.isOnline) { if (device.isOnline) {
DeviceIdEvent.setDeviceId(device.deviceId) DeviceIdEvent.setDeviceId(device.deviceId)
val intent = Intent(requireContext(), LiveVideoActivity::class.java) val intent = Intent(requireContext(), LiveVideoActivity::class.java)
intent.putExtra("device_id", device.deviceId) intent.putExtra("device_id", device.deviceId)
intent.putExtra("device_name", device.name) intent.putExtra("device_name", device.name)
intent.putExtra("deviceNo", device.deviceNo)
intent.putExtra("light", device.light)
startActivity(intent) startActivity(intent)
} else { } else {
showDefenseDialog( showDefenseDialog(
@@ -481,6 +604,14 @@ class HomeMenuFragment : Fragment() {
).toInt() ).toInt()
} }
private fun dpToPx(dp: Float): Float {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dp,
resources.displayMetrics
)
}
private class GridHorizontalSpaceItemDecoration( private class GridHorizontalSpaceItemDecoration(
private val horizontalSpace: Int private val horizontalSpace: Int
) : RecyclerView.ItemDecoration() { ) : 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() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
loadingDialog?.dismiss()
loadingDialog = null
binding.rvFamilyList.adapter = null binding.rvFamilyList.adapter = null
binding.rvDeviceList.adapter = null binding.rvDeviceList.adapter = null
MessageStatusManager.removeListener(unreadCountChangeListener) 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.os.Bundle
import android.view.View import android.view.View
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.adapter.MessageListAdapter import com.ckkj.defense_device.R
import com.example.defenseapplication.adapter.MessageListItem import com.ckkj.defense_device.adapter.MessageListAdapter
import com.example.defenseapplication.databinding.MessageActivityBinding import com.ckkj.defense_device.adapter.MessageListItem
import com.example.defenseapplication.utils.MessageStatusManager import com.ckkj.defense_device.databinding.MessageActivityBinding
import com.example.defenseapplication.utils.RetrofitNetwork 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 com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -19,13 +22,13 @@ import kotlinx.coroutines.withContext
class MessageActivity : AppCompatActivity() { class MessageActivity : AppCompatActivity() {
private lateinit var binding: MessageActivityBinding private lateinit var binding: MessageActivityBinding
private val messageAdapter by lazy { MessageListAdapter() } private val messageAdapter by lazy { MessageListAdapter() }
private lateinit var loadingDialog: LoadingDialog
private var currentPage = 1 private var currentPage = 1
private val pageSize = 10 private val pageSize = 10
private var isLoading = false private var isLoading = false
private var hasMoreData = true private var hasMoreData = true
private val allMessages = mutableListOf<com.example.defenseapplication.bean.MessageBean>() private val allMessages = mutableListOf<com.ckkj.defense_device.bean.MessageBean>()
private var lastLoadedCount = 0
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -41,9 +44,18 @@ class MessageActivity : AppCompatActivity() {
} }
private fun initView() { private fun initView() {
loadingDialog = LoadingDialog(this).setMessage(getString(R.string.loading))
binding.ivBack.setOnClickListener { finish() } binding.ivBack.setOnClickListener { finish() }
binding.rvMessageList.layoutManager = LinearLayoutManager(this) binding.rvMessageList.layoutManager = LinearLayoutManager(this)
binding.rvMessageList.adapter = messageAdapter binding.rvMessageList.adapter = messageAdapter
binding.swipeRefreshLayout.setOnRefreshListener(object : PullRefreshLayout.OnRefreshListener {
override fun onRefresh() {
currentPage = 1
hasMoreData = true
loadMessageList()
}
})
binding.rvMessageList.addOnScrollListener(object : RecyclerView.OnScrollListener() { binding.rvMessageList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
@@ -70,20 +82,21 @@ class MessageActivity : AppCompatActivity() {
if (isLoading) return if (isLoading) return
isLoading = true isLoading = true
if (currentPage == 1) {
showLoading()
}
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
try { try {
val messageResponse = RetrofitNetwork.getNetworkService().getMessage( val messageResponse = RetrofitNetwork.getNetworkService().getMessage(
pageNum = currentPage, pageNum = currentPage,
pageSize = pageSize pageSize = pageSize
) )
println("total: ${messageResponse.total}")
println("rows size: ${messageResponse.rows.size}")
println("当前页:$currentPage, 加载条数:${messageResponse.rows.size}")
val newMessages = messageResponse.rows val newMessages = messageResponse.rows
val loadedCount = newMessages.size
if (loadedCount < pageSize) { if (newMessages.size < pageSize) {
hasMoreData = false hasMoreData = false
} }
@@ -98,11 +111,11 @@ class MessageActivity : AppCompatActivity() {
allMessages.clear() allMessages.clear()
} }
allMessages.addAll(newMessages) allMessages.addAll(newMessages)
lastLoadedCount = loadedCount
val items = convertToMessageListItems(allMessages) val items = convertToMessageListItems(allMessages)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
hideLoading()
hideEmptyState() hideEmptyState()
messageAdapter.submitList(items) messageAdapter.submitList(items)
@@ -116,20 +129,24 @@ class MessageActivity : AppCompatActivity() {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if (allMessages.isEmpty()) { if (allMessages.isEmpty()) {
println("items is empty, showing empty state")
showEmptyState() showEmptyState()
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
println("Exception: ${e.message}")
e.printStackTrace() e.printStackTrace()
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if (allMessages.isEmpty()) { if (allMessages.isEmpty()) {
showEmptyState() noNetwork()
} }
} }
} finally { } finally {
isLoading = false isLoading = false
if (currentPage == 1) {
withContext(Dispatchers.Main) {
hideLoading()
binding.swipeRefreshLayout.finishRefresh()
}
}
} }
} }
} }
@@ -141,16 +158,34 @@ class MessageActivity : AppCompatActivity() {
loadMessageList() 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() { private fun showEmptyState() {
binding.rvMessageList.visibility = View.GONE binding.swipeRefreshLayout.visibility = View.GONE
binding.emptyLayout.visibility = View.VISIBLE binding.emptyLayout.visibility = View.VISIBLE
binding.tvNoMoreData.visibility = View.GONE binding.tvNoMoreData.visibility = View.GONE
} }
private fun hideEmptyState() { private fun hideEmptyState() {
binding.rvMessageList.visibility = View.VISIBLE binding.swipeRefreshLayout.visibility = View.VISIBLE
binding.emptyLayout.visibility = View.GONE 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() { private fun showNoMoreDataHint() {
binding.tvNoMoreData.visibility = View.VISIBLE binding.tvNoMoreData.visibility = View.VISIBLE
@@ -160,20 +195,17 @@ class MessageActivity : AppCompatActivity() {
binding.tvNoMoreData.visibility = View.GONE 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 items = mutableListOf<MessageListItem>()
val groupedMessages = messages.groupBy { extractDate(it.createTime ?: "") } val groupedMessages = messages.groupBy { extractDate(it.createTime ?: "") }
groupedMessages.forEach { (date, messageList) -> groupedMessages.forEach { (date, messageList) ->
val headerTitle = formatDate(date) 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)) items.add(MessageListItem.Header(headerTitle))
messageList.forEach { message -> messageList.forEach { message ->
items.add( items.add(
MessageListItem.Message( MessageListItem.Message(
time = extractTime(message.createTime ?: ""), time = extractTime(message.createTime ?: ""),
title = message.categoryName ?: "未知消息", title = message.categoryName ?: "",
dateTime = message.createTime ?: "", dateTime = message.createTime ?: "",
unread = false 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.content.Intent
import android.os.Bundle import android.os.Bundle
@@ -9,21 +9,23 @@ import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.bean.UserInfoBean import com.ckkj.defense_device.bean.UserInfoBean
import com.example.defenseapplication.databinding.PersonalFragmentBinding import com.ckkj.defense_device.databinding.PersonalFragmentBinding
import com.example.defenseapplication.liveVideo.LinkedUserActivity import com.ckkj.defense_device.liveVideo.LinkedUserActivity
import com.example.defenseapplication.personal.FaceManagementActivity import com.ckkj.defense_device.personal.FaceManagementActivity
import com.example.defenseapplication.personal.PasswordManagementActivity import com.ckkj.defense_device.personal.PasswordManagementActivity
import com.example.defenseapplication.personal.PersonalProfileActivity import com.ckkj.defense_device.personal.PersonalProfileActivity
import com.example.defenseapplication.utils.AppLanguage import com.ckkj.defense_device.personal.SettingsMenusActivity
import com.example.defenseapplication.utils.LanguageUtil import com.ckkj.defense_device.utils.AppLanguage
import com.example.defenseapplication.utils.RetrofitNetwork import com.ckkj.defense_device.utils.LanguageUtil
import com.example.defenseapplication.utils.UserinfoUtil import com.ckkj.defense_device.utils.RetrofitNetwork
import com.example.defenseapplication.utils.ActivityManager import com.ckkj.defense_device.utils.UserinfoUtil
import com.example.defenseapplication.view.FamilySwitchDialog import com.ckkj.defense_device.utils.ActivityManager
import com.example.defenseapplication.view.LanguageDialog import com.ckkj.defense_device.view.CustomDialogFragmentText
import com.example.defenseapplication.home.HomeActivity 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 com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -34,6 +36,7 @@ class PersonalFragment : Fragment() {
// ViewBinding // ViewBinding
private var _binding: PersonalFragmentBinding? = null private var _binding: PersonalFragmentBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private var loadingDialog: LoadingDialog? = null
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
fetchUserInfo() fetchUserInfo()
@@ -49,10 +52,10 @@ class PersonalFragment : Fragment() {
.titleBar(binding.headerLayout) .titleBar(binding.headerLayout)
.init() .init()
Glide.with(this) Glide.with(this)
.load(R.drawable.img) .load("")
.circleCrop() .circleCrop()
.into(binding.ivAvatar) .into(binding.ivAvatar)
binding.headerLayout.setOnClickListener { binding.ivAvatar.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
try { try {
val response = RetrofitNetwork.getNetworkService().getUserInfo() val response = RetrofitNetwork.getNetworkService().getUserInfo()
@@ -101,27 +104,40 @@ class PersonalFragment : Fragment() {
} }
// 退出登录点击事件 // 退出登录点击事件
binding.btnLogout.setOnClickListener { binding.btnLogout.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch { val dialog = CustomDialogFragmentText()
try { .setTitle(getString(R.string.tip))
val response = RetrofitNetwork.getNetworkService().logout() .setMessage(getString(R.string.logout_confirm))
withContext(Dispatchers.Main) { .setShowInput(false)
if (response.code == 200) { .setNegativeText(getString(R.string.cancel))
UserinfoUtil.clearUserInfo() .setPositiveText(getString(R.string.confirm))
val intent = Intent(requireContext(), com.example.defenseapplication.login.LoginActivity::class.java) .setOnConfirmListener {
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK CoroutineScope(Dispatchers.IO).launch {
startActivity(intent) try {
requireActivity().finish() val response = RetrofitNetwork.getNetworkService().logout()
} else { withContext(Dispatchers.Main) {
Toast.makeText(requireContext(), getString(R.string.logout_fail), Toast.LENGTH_SHORT).show() 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() fetchCurrentFamily()
return binding.root return binding.root
@@ -220,6 +236,7 @@ class PersonalFragment : Fragment() {
private fun fetchUserInfo() { private fun fetchUserInfo() {
loadingDialog = LoadingDialog(requireContext()).setMessage(getString(R.string.loading)).apply { show() }
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
try { try {
val response = RetrofitNetwork.getNetworkService().getUserInfo() val response = RetrofitNetwork.getNetworkService().getUserInfo()
@@ -230,6 +247,11 @@ class PersonalFragment : Fragment() {
} }
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} finally {
withContext(Dispatchers.Main) {
loadingDialog?.dismiss()
loadingDialog = null
}
} }
} }
} }
@@ -243,8 +265,8 @@ class PersonalFragment : Fragment() {
} }
userInfo.avatar?.let { userInfo.avatar?.let {
val requestOptions = RequestOptions() val requestOptions = RequestOptions()
.placeholder(R.drawable.img) // 加载中显示 .placeholder(R.mipmap.img) // 加载中显示
.error(R.drawable.img) // 失败时显示 .error(R.mipmap.img) // 失败时显示
Glide.with(this) Glide.with(this)
.load(it) // 如果 avatar 为 nullGlide 会直接回调 error .load(it) // 如果 avatar 为 nullGlide 会直接回调 error
@@ -258,6 +280,7 @@ class PersonalFragment : Fragment() {
} else { } else {
getString(R.string.member) 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.content.Intent
import android.os.Bundle import android.os.Bundle
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.bean.AddDeviceBean import com.ckkj.defense_device.bean.AddDeviceBean
import com.example.defenseapplication.bean.DeviceBean import com.ckkj.defense_device.databinding.SetNameActivityBinding
import com.example.defenseapplication.databinding.SetNameActivityBinding import com.ckkj.defense_device.liveVideo.LiveVideoActivity
import com.example.defenseapplication.liveVideo.LiveVideoActivity import com.ckkj.defense_device.utils.RetrofitNetwork
import com.example.defenseapplication.utils.RetrofitNetwork
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -61,7 +60,9 @@ class SetNameActivity : AppCompatActivity() {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if (result.code == 200) { if (result.code == 200) {
Toast.makeText(this@SetNameActivity, "设备添加成功", Toast.LENGTH_SHORT).show() 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() finish()
} else { } else {
Toast.makeText(this@SetNameActivity, result.msg ?: "添加失败", Toast.LENGTH_SHORT).show() Toast.makeText(this@SetNameActivity, result.msg ?: "添加失败", Toast.LENGTH_SHORT).show()

View File

@@ -0,0 +1,41 @@
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.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
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityStartBinding.inflate(layoutInflater)
setContentView(binding.root)
ImmersionBar.with(this)
.statusBarDarkFont(true)
.titleBar(null)
.init()
// 延迟2秒后再判断登录状态
Handler(Looper.getMainLooper()).postDelayed({
val userInfo = UserinfoUtil.getUserInfo()
if (userInfo != null) {
// 设置token
ApiConfig.authToken = userInfo.access_token
val intent = Intent(this, HomeActivity::class.java)
startActivity(intent)
} else {
val intent = Intent(this, LoginActivity::class.java)
startActivity(intent)
}
finish()
}, 2000) // 2秒延迟
}
}

View File

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

View File

@@ -0,0 +1,428 @@
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
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.lifecycle.lifecycleScope
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.bigkoo.pickerview.builder.TimePickerBuilder
import com.bigkoo.pickerview.listener.OnTimeSelectListener
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() {
private lateinit var binding: AlarmLogActivityBinding
private lateinit var calendar: Calendar
private var adapter: AlarmLogAdapter? = null
private val alarmList = mutableListOf<DeviceAlarmBean>()
private val originalAlarmList = mutableListOf<DeviceAlarmBean>()
private var deviceId: String? = null
private var isLoading = false
private var videoUrl: String? = null
private var orientationUtils: OrientationUtils? = null
private var isMute = false
private lateinit var audioManager: AudioManager
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")
videoUrl = intent.getStringExtra("video_url")
calendar = Calendar.getInstance()
updateDateDisplay()
initVideoPlayer()
initRecyclerView()
fetchAlarmList()
initListener()
}
private fun initVideoPlayer() {
val videoUrl = intent.getStringExtra("video_url") ?: "https://media.w3.org/2010/05/sintel/trailer.mp4"
val progressDrawable = ContextCompat.getDrawable(this, R.drawable.progress_video)
val thumbDrawable = ContextCompat.getDrawable(this, R.drawable.thumb_video)
orientationUtils = OrientationUtils(this, binding.exoPlayContextId)
orientationUtils?.isEnable = true
GSYVideoOptionBuilder()
.setUrl(videoUrl)
.setVideoTitle("")
.setNeedLockFull(true)
.setCacheWithPlay(false)
.setRotateViewAuto(true)
.setLockLand(false)
.setShowFullAnimation(true)
.setNeedShowWifiTip(false)
.setEnlargeImageRes(R.mipmap.full_size)
.setShrinkImageRes(R.mipmap.full_screen)
.setBottomShowProgressBarDrawable(progressDrawable, thumbDrawable)
.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.backButton.setOnClickListener {
if (orientationUtils?.isLand == 1) {
// 当前全屏,先退出全屏
binding.exoPlayContextId.fullscreenButton.performClick()
} else {
finish()
}
}
binding.exoPlayContextId.onControlVisibilityChanged = { show ->
Log.e("GSY_TEST", "Activity收到回调 show=$show")
val visible = if (show) View.VISIBLE else View.GONE
binding.ivDownload.visibility = visible
binding.ivDelete.visibility = visible
binding.ivMute.visibility = visible
}
binding.exoPlayContextId.startPlayLogic()
binding.exoPlayContextId.fullscreenButton.setOnClickListener {
orientationUtils?.resolveByClick()
binding.exoPlayContextId.startWindowFullscreen(this, true, true)?.let { fullPlayer ->
if (fullPlayer is MyGSYVideoPlayer) {
fullPlayer.onControlVisibilityChanged = { show ->
val visible = if (show) View.VISIBLE else View.GONE
binding.ivDownload.visibility = visible
binding.ivDelete.visibility = visible
binding.ivMute.visibility = visible
}
}
}
}
}
private fun initRecyclerView() {
adapter = AlarmLogAdapter(alarmList) { item ->
currentAlarmItem = item
if (!item.video.isNullOrEmpty()) {
binding.exoPlayContextId.setUp(item.video, true, item.categoryName)
binding.exoPlayContextId.startPlayLogic()
} else {
Toast.makeText(this, "该告警记录没有视频", Toast.LENGTH_SHORT).show()
}
}
binding.alarmListRecyclerView.layoutManager = LinearLayoutManager(this)
binding.alarmListRecyclerView.adapter = adapter
}
private fun fetchAlarmList() {
val currentDeviceId = deviceId ?: return
isLoading = true
lifecycleScope.launch {
try {
val response = RetrofitNetwork.getNetworkService().getDeviceAlarmList(
deviceId = currentDeviceId,
pageNum = "1",
pageSize = "10"
)
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", "请求结束")
}
}
}
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 showAlarmListNetworkError() {
binding.alarmListRecyclerView.visibility = View.GONE
binding.layoutNoPermission.visibility = View.GONE
binding.layoutNoNetwork.visibility = View.VISIBLE
}
private fun filterAlarmListByDate(selectedDate: Calendar) {
val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
val selectedDateStr = dateFormat.format(selectedDate.time)
alarmList.clear()
originalAlarmList.forEach { item ->
val itemDateStr = item.createTime.substring(0, 10)
if (itemDateStr == selectedDateStr) {
alarmList.add(item)
}
}
adapter?.notifyDataSetChanged()
Log.d("AlarmLogActivity", "日期筛选完成,筛选后条数: ${alarmList.size}")
if (alarmList.isEmpty()) {
currentAlarmItem = null
} else {
currentAlarmItem = alarmList.firstOrNull()
}
updateAlarmListState()
}
private fun updateDateDisplay() {
val month = calendar.get(Calendar.MONTH) + 1
val day = calendar.get(Calendar.DAY_OF_MONTH)
binding.tvDate.text = "${month}${day}"
}
private fun initListener() {
binding.expandImg.setOnClickListener {
showDatePicker()
}
binding.ivDownload.setOnClickListener {
// 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.mipmap.mute
)
} else {
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) / 2, 0)
binding.ivMute.setImageResource(
R.mipmap.un_mute
)
}
}
}
private fun showDatePicker() {
val timePicker = TimePickerBuilder(this, OnTimeSelectListener { date, _ ->
calendar.time = date
updateDateDisplay()
filterAlarmListByDate(calendar)
})
.setType(booleanArrayOf(true, true, true, false, false, false)) // 年月日
.setTitleText(getString(R.string.select_date))
.setSubmitColor(Color.parseColor("#09C2BD"))//确定按钮文字颜色
.setCancelColor(Color.parseColor("#09C2BD"))//取消按钮文字颜色
.setSubCalSize(18)//确定和取消文字大小
.setTextColorCenter(Color.parseColor("#09C2BD"))//选中颜色
.setLineSpacingMultiplier(2.5f)//行间距倍数
.setItemVisibleCount(5)//可见项数量
.setDate(calendar) // 设置默认选中日期为tvDate显示的日期
.build()
timePicker.show()
}
override fun onPause() {
super.onPause()
binding.exoPlayContextId.onVideoPause()
}
override fun onResume() {
super.onResume()
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()
orientationUtils?.releaseListener()
binding.exoPlayContextId.release()
}
}

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.liveVideo package com.ckkj.defense_device.liveVideo
import android.content.Intent import android.content.Intent
import android.graphics.Color import android.graphics.Color
@@ -8,12 +8,12 @@ import java.util.Calendar
import android.os.Bundle import android.os.Bundle
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.databinding.AutoModeActivityBinding import com.ckkj.defense_device.databinding.AutoModeActivityBinding
import com.example.defenseapplication.utils.DeviceIdEvent import com.ckkj.defense_device.utils.DeviceIdEvent
import com.example.defenseapplication.utils.DeviceUpdateEvent import com.ckkj.defense_device.utils.DeviceUpdateEvent
import com.example.defenseapplication.utils.RetrofitNetwork import com.ckkj.defense_device.utils.RetrofitNetwork
import com.example.defenseapplication.view.AutoModeNoticeDialog import com.ckkj.defense_device.view.AutoModeNoticeDialog
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -31,6 +31,7 @@ class AutoModeActivity : AppCompatActivity() {
private var selectedStartMinute = 0 private var selectedStartMinute = 0
private var selectedEndHour = 10 private var selectedEndHour = 10
private var selectedEndMinute = 0 private var selectedEndMinute = 0
private var optionPassword: String? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -42,6 +43,8 @@ class AutoModeActivity : AppCompatActivity() {
.titleBar(binding.topBar) .titleBar(binding.topBar)
.init() .init()
optionPassword = intent.getStringExtra("optionPassword")
initListener() initListener()
loadCurrentSettings() loadCurrentSettings()
@@ -173,11 +176,12 @@ class AutoModeActivity : AppCompatActivity() {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
try { try {
val deviceBean = com.example.defenseapplication.bean.DeviceBean( val deviceBean = com.ckkj.defense_device.bean.DeviceBean(
id = deviceId, id = deviceId,
workMode = selectedMode, workMode = selectedMode,
startTime = startTime, startTime = startTime,
endTime = endTime endTime = endTime,
optionPassword = optionPassword
) )
val response = RetrofitNetwork.getNetworkService().updateDeviceInfo(deviceBean) val response = RetrofitNetwork.getNetworkService().updateDeviceInfo(deviceBean)
withContext(Dispatchers.Main) { 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.os.Bundle
import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.databinding.DeviceInfoActivityBinding import com.ckkj.defense_device.databinding.DeviceInfoActivityBinding
import com.example.defenseapplication.utils.DeviceIdEvent import com.ckkj.defense_device.utils.DeviceIdEvent
import com.example.defenseapplication.utils.RetrofitNetwork import com.ckkj.defense_device.utils.RetrofitNetwork
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -55,9 +54,9 @@ class DeviceInfoActivity : AppCompatActivity() {
} }
} }
private fun updateDeviceInfo(device: com.example.defenseapplication.bean.DeviceBean) { private fun updateDeviceInfo(device: com.ckkj.defense_device.bean.DeviceBean) {
binding.tvDeviceModelValue.text = device.deviceNo.toString() binding.tvDeviceModelValue.text = device.deviceNo?.toString()?: ""
binding.tvDeviceNoValue.text = device.deviceSn.toString() binding.tvDeviceNoValue.text = device.deviceSn?.toString() ?: ""
binding.tvFwVersionValue.text = device.fwVer.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.content.Intent
import android.os.Bundle import android.os.Bundle
@@ -11,22 +11,22 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.adapter.LinkedUser import com.ckkj.defense_device.adapter.LinkedUser
import com.example.defenseapplication.adapter.LinkedUserAdapter import com.ckkj.defense_device.adapter.LinkedUserAdapter
import com.example.defenseapplication.bean.DeleteDeviceUserRequest import com.ckkj.defense_device.bean.DeleteDeviceUserRequest
import com.example.defenseapplication.bean.DeviceUserBean import com.ckkj.defense_device.bean.DeviceUserBean
import com.example.defenseapplication.bean.FamilyMembersBean import com.ckkj.defense_device.bean.FamilyMembersBean
import com.example.defenseapplication.bean.VerifyOptionPasswordRequest import com.ckkj.defense_device.bean.VerifyOptionPasswordRequest
import com.example.defenseapplication.databinding.LinkedUserActivityBinding import com.ckkj.defense_device.databinding.LinkedUserActivityBinding
import com.example.defenseapplication.personal.PasswordInputDialog import com.ckkj.defense_device.personal.PasswordInputDialog
import com.example.defenseapplication.utils.DeviceIdEvent import com.ckkj.defense_device.utils.DeviceIdEvent
import com.example.defenseapplication.utils.DeviceUserUpdateEvent import com.ckkj.defense_device.utils.DeviceUserUpdateEvent
import com.example.defenseapplication.utils.RetrofitNetwork import com.ckkj.defense_device.utils.RetrofitNetwork
import com.example.defenseapplication.view.CustomDialogFragmentText import com.ckkj.defense_device.view.CustomDialogFragmentText
import com.ckkj.defense_device.view.PullRefreshLayout
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import com.yanzhenjie.recyclerview.SwipeMenuItem import com.yanzhenjie.recyclerview.SwipeMenuItem
import com.yanzhenjie.recyclerview.SwipeRecyclerView
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -96,9 +96,11 @@ class LinkedUserActivity : AppCompatActivity() {
(binding.rvLinkedUser as RecyclerView).layoutManager = LinearLayoutManager(this) (binding.rvLinkedUser as RecyclerView).layoutManager = LinearLayoutManager(this)
binding.swipeRefresh.setOnRefreshListener { binding.swipeRefresh.setOnRefreshListener(object : PullRefreshLayout.OnRefreshListener {
fetchUserList() override fun onRefresh() {
} fetchUserList()
}
})
binding.rvLinkedUser.setSwipeMenuCreator { leftMenu, rightMenu, position -> binding.rvLinkedUser.setSwipeMenuCreator { leftMenu, rightMenu, position ->
if (mode == MODE_SETTINGS) { if (mode == MODE_SETTINGS) {
@@ -230,7 +232,6 @@ class LinkedUserActivity : AppCompatActivity() {
} }
private fun fetchUserList() { private fun fetchUserList() {
binding.swipeRefresh.isRefreshing = true
lifecycleScope.launch { lifecycleScope.launch {
try { try {
var deviceId: String? = null var deviceId: String? = null
@@ -239,7 +240,7 @@ class LinkedUserActivity : AppCompatActivity() {
if (deviceId.isNullOrEmpty()) { if (deviceId.isNullOrEmpty()) {
Toast.makeText(this@LinkedUserActivity, "设备 ID 为空", Toast.LENGTH_SHORT).show() Toast.makeText(this@LinkedUserActivity, "设备 ID 为空", Toast.LENGTH_SHORT).show()
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
binding.swipeRefresh.isRefreshing = false binding.swipeRefresh.finishRefresh()
} }
return@launch return@launch
} }
@@ -250,7 +251,7 @@ class LinkedUserActivity : AppCompatActivity() {
RetrofitNetwork.getNetworkService().getFamilyMembers() RetrofitNetwork.getNetworkService().getFamilyMembers()
} }
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
binding.swipeRefresh.isRefreshing = false binding.swipeRefresh.finishRefresh()
if (response.code == 200 && response.data != null) { if (response.code == 200 && response.data != null) {
if (mode == MODE_SETTINGS) { if (mode == MODE_SETTINGS) {
updateDeviceUserList(response.data as List<DeviceUserBean>) updateDeviceUserList(response.data as List<DeviceUserBean>)
@@ -258,18 +259,32 @@ class LinkedUserActivity : AppCompatActivity() {
updateFamilyMembersList(response.data as List<FamilyMembersBean>) updateFamilyMembersList(response.data as List<FamilyMembersBean>)
} }
} else { } else {
hide()
Toast.makeText(this@LinkedUserActivity, response.msg, Toast.LENGTH_SHORT).show() Toast.makeText(this@LinkedUserActivity, response.msg, Toast.LENGTH_SHORT).show()
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
binding.swipeRefresh.isRefreshing = false binding.swipeRefresh.finishRefresh()
Toast.makeText(this@LinkedUserActivity, "网络请求失败", Toast.LENGTH_SHORT).show() 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>) { private fun updateDeviceUserList(deviceUserList: List<DeviceUserBean>) {
fullUserList.clear() fullUserList.clear()
@@ -339,7 +354,7 @@ class LinkedUserActivity : AppCompatActivity() {
binding.fabAdd.setOnClickListener { binding.fabAdd.setOnClickListener {
if (checkUserLimit()) { 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) 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.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.widget.Toast import android.widget.Toast
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.base.BaseActivity import com.ckkj.defense_device.base.BaseActivity
import com.example.defenseapplication.databinding.SettingsActivityBinding import com.ckkj.defense_device.databinding.SettingsActivityBinding
import com.example.defenseapplication.utils.DeviceIdEvent import com.ckkj.defense_device.utils.DeviceIdEvent
import com.example.defenseapplication.utils.RetrofitNetwork import com.ckkj.defense_device.utils.RetrofitNetwork
import com.example.defenseapplication.view.CustomDialogFragmentText import com.ckkj.defense_device.view.CustomDialogFragmentText
import com.example.defenseapplication.view.RecognitionModeDialog import com.ckkj.defense_device.view.RecognitionModeDialog
import com.example.defenseapplication.bean.VerifyOptionPasswordRequest import com.ckkj.defense_device.bean.VerifyOptionPasswordRequest
import com.example.defenseapplication.personal.PasswordInputDialog import com.ckkj.defense_device.personal.PasswordInputDialog
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -27,6 +27,7 @@ class SettingsActivity : BaseActivity() {
private var alertAudio: String? = null private var alertAudio: String? = null
private var audioContent: String? = null private var audioContent: String? = null
private var isPasswordVerified = false private var isPasswordVerified = false
private var verifiedPassword: String? = null
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
@@ -55,15 +56,15 @@ class SettingsActivity : BaseActivity() {
if (isPasswordVerified) { if (isPasswordVerified) {
val dialog = RecognitionModeDialog(this) val dialog = RecognitionModeDialog(this)
dialog.setOnConfirmListener { mode -> dialog.setOnConfirmListener { mode ->
updateRecognitionMode(mode) updateRecognitionMode(mode, verifiedPassword)
} }
dialog.show() dialog.show()
} else { } else {
showPasswordDialog { showPasswordDialog { inputPassword ->
isPasswordVerified = true isPasswordVerified = true
val dialog = RecognitionModeDialog(this) val dialog = RecognitionModeDialog(this)
dialog.setOnConfirmListener { mode -> dialog.setOnConfirmListener { mode ->
updateRecognitionMode(mode) updateRecognitionMode(mode, inputPassword)
} }
dialog.show() dialog.show()
} }
@@ -94,22 +95,24 @@ class SettingsActivity : BaseActivity() {
} }
binding.itemWaterGunSetting.setOnClickListener { binding.itemWaterGunSetting.setOnClickListener {
if (isPasswordVerified) { if (isPasswordVerified) {
navigateToWaterGunSettings() navigateToWaterGunSettings(verifiedPassword)
} else { } else {
showPasswordDialog { showPasswordDialog { inputPassword ->
isPasswordVerified = true isPasswordVerified = true
navigateToWaterGunSettings() navigateToWaterGunSettings(inputPassword)
} }
} }
} }
binding.itemAutoMode.setOnClickListener { binding.itemAutoMode.setOnClickListener {
if (isPasswordVerified) { if (isPasswordVerified) {
val intent = Intent(this, AutoModeActivity::class.java) val intent = Intent(this, AutoModeActivity::class.java)
intent.putExtra("optionPassword", verifiedPassword)
startActivity(intent) startActivity(intent)
} else { } else {
showPasswordDialog { showPasswordDialog { inputPassword ->
isPasswordVerified = true isPasswordVerified = true
val intent = Intent(this, AutoModeActivity::class.java) val intent = Intent(this, AutoModeActivity::class.java)
intent.putExtra("optionPassword", inputPassword)
startActivity(intent) startActivity(intent)
} }
} }
@@ -183,7 +186,7 @@ class SettingsActivity : BaseActivity() {
binding.tvRelatedUsers.text = "$count" 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.tvDeviceName.text = device.deviceName ?: "未设置"
binding.tvWifiName.text = device.wifiName ?: "未设置" binding.tvWifiName.text = device.wifiName ?: "未设置"
@@ -236,7 +239,7 @@ class SettingsActivity : BaseActivity() {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
try { try {
val deviceBean = com.example.defenseapplication.bean.DeviceBean( val deviceBean = com.ckkj.defense_device.bean.DeviceBean(
id = deviceId, id = deviceId,
deviceName = name, 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() val deviceId = DeviceIdEvent.getDeviceId()
if (deviceId.isNullOrEmpty()) { if (deviceId.isNullOrEmpty()) {
Toast.makeText(this, "设备ID为空", Toast.LENGTH_SHORT).show() Toast.makeText(this, "设备ID为空", Toast.LENGTH_SHORT).show()
@@ -273,9 +276,10 @@ class SettingsActivity : BaseActivity() {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
try { try {
val deviceBean = com.example.defenseapplication.bean.DeviceBean( val deviceBean = com.ckkj.defense_device.bean.DeviceBean(
id = deviceId, id = deviceId,
patternPerception = patternPerception, patternPerception = patternPerception,
optionPassword = optionPassword
) )
val response = RetrofitNetwork.getNetworkService().updateDeviceInfo(deviceBean) val response = RetrofitNetwork.getNetworkService().updateDeviceInfo(deviceBean)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
@@ -305,13 +309,13 @@ class SettingsActivity : BaseActivity() {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
try { try {
val deleteBean = com.example.defenseapplication.bean.DeleteBean() val deleteBean = com.ckkj.defense_device.bean.DeleteBean()
deleteBean.deviceId = deviceId deleteBean.deviceId = deviceId
val response = RetrofitNetwork.getNetworkService().deleteDevice(deleteBean) val response = RetrofitNetwork.getNetworkService().deleteDevice(deleteBean)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if (response.code == 200) { if (response.code == 200) {
Toast.makeText(this@SettingsActivity, "解绑成功", Toast.LENGTH_SHORT).show() 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 intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent) startActivity(intent)
finish() finish()
@@ -328,7 +332,7 @@ class SettingsActivity : BaseActivity() {
} }
} }
private fun showPasswordDialog(onVerified: () -> Unit) { private fun showPasswordDialog(onVerified: (String) -> Unit) {
passwordDialog = PasswordInputDialog(this).apply { passwordDialog = PasswordInputDialog(this).apply {
setOnConfirmListener { inputPassword -> setOnConfirmListener { inputPassword ->
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
@@ -338,7 +342,8 @@ class SettingsActivity : BaseActivity() {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if (response.code == 200) { if (response.code == 200) {
dismiss() dismiss()
onVerified() verifiedPassword = inputPassword
onVerified(inputPassword)
} else { } else {
Toast.makeText( Toast.makeText(
this@SettingsActivity, this@SettingsActivity,
@@ -365,8 +370,9 @@ class SettingsActivity : BaseActivity() {
passwordDialog.show() passwordDialog.show()
} }
private fun navigateToWaterGunSettings() { private fun navigateToWaterGunSettings(optionPassword: String? = null) {
val intent = Intent(this, WaterGunSettingsActivity::class.java) val intent = Intent(this, WaterGunSettingsActivity::class.java)
intent.putExtra("optionPassword", optionPassword)
val deviceId = DeviceIdEvent.getDeviceId() val deviceId = DeviceIdEvent.getDeviceId()
if (!deviceId.isNullOrEmpty()) { if (!deviceId.isNullOrEmpty()) {
CoroutineScope(Dispatchers.IO).launch { 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.animation.ObjectAnimator
import android.os.Bundle import android.os.Bundle
import android.widget.ImageView import android.widget.ImageView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.bean.DeviceBean import com.ckkj.defense_device.bean.DeviceBean
import com.example.defenseapplication.databinding.StrikePositionActivityBinding import com.ckkj.defense_device.databinding.StrikePositionActivityBinding
import com.example.defenseapplication.utils.DeviceIdEvent import com.ckkj.defense_device.utils.DeviceIdEvent
import com.example.defenseapplication.utils.RetrofitNetwork import com.ckkj.defense_device.utils.RetrofitNetwork
import com.example.defenseapplication.view.CustomDialogFragment import com.ckkj.defense_device.view.CustomDialogFragment
import com.example.defenseapplication.view.showDefenseDialog import com.ckkj.defense_device.view.showDefenseDialog
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -45,7 +45,7 @@ class StrikePositionActivity : AppCompatActivity() {
private var selectedZone: Zone = Zone.CHEST 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 lastTouchX = 0f
private var lastTouchY = 0f private var lastTouchY = 0f
@@ -67,7 +67,7 @@ class StrikePositionActivity : AppCompatActivity() {
binding.ivBack.setOnClickListener { finish() } binding.ivBack.setOnClickListener { finish() }
binding.btnSubmit.setOnClickListener { showConfirmDialog() } binding.btnSubmit.setOnClickListener { showConfirmDialog() }
// Use OnTouchListener to track touch coordinates // 使用 OnTouchListen 来跟踪触摸坐标
binding.ivHumanBody.setOnTouchListener { _, event -> binding.ivHumanBody.setOnTouchListener { _, event ->
lastTouchX = event.x lastTouchX = event.x
lastTouchY = event.y lastTouchY = event.y
@@ -77,7 +77,7 @@ class StrikePositionActivity : AppCompatActivity() {
false false
} }
// OnClick fires on ACTION_UP; coordinates captured from lastTouchX/Y // OnClick 对ACTION_UP开火;坐标来自lastTouchXY
binding.ivHumanBody.setOnClickListener { binding.ivHumanBody.setOnClickListener {
val imageView = it as ImageView val imageView = it as ImageView
val (nx, ny) = resolveTapLocation(lastTouchX, lastTouchY, 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) * 1. 计算图片等比缩放后的实际尺寸
* - Letterbox / pillarbox margins when image aspect view aspect * 2. 计算letterbox/pillarbox的偏移量
* 3. 将触摸点限制在图片有效区域内
* 4. 返回相对于图片的归一化坐标(0-1范围)
*/ */
private fun resolveTapLocation(rawX: Float, rawY: Float, imageView: ImageView): Pair<Float, Float> { private fun resolveTapLocation(rawX: Float, rawY: Float, imageView: ImageView): Pair<Float, Float> {
val drawable = imageView.drawable ?: return Pair(0f, 0f) val drawable = imageView.drawable ?: return Pair(0f, 0f)
@@ -114,22 +116,22 @@ class StrikePositionActivity : AppCompatActivity() {
val intrinsicWidth = drawable.intrinsicWidth.toFloat() val intrinsicWidth = drawable.intrinsicWidth.toFloat()
val intrinsicHeight = drawable.intrinsicHeight.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) val scale = min(ivWidth / intrinsicWidth, ivHeight / intrinsicHeight)
// Physical pixel size of the drawable after scaling // 缩放后绘制的物理像素大小
val drawnW = intrinsicWidth * scale val drawnW = intrinsicWidth * scale
val drawnH = intrinsicHeight * scale val drawnH = intrinsicHeight * scale
// Letterbox offsets (top / left) when aspect ratios differ // 当宽高比不同时,信箱偏移(左上角)
val drawableLeft = (ivWidth - drawnW) / 2f val drawableLeft = (ivWidth - drawnW) / 2f
val drawableTop = (ivHeight - drawnH) / 2f val drawableTop = (ivHeight - drawnH) / 2f
// Clamp touch to the actual drawable area // 夹紧触地接触实际可绘制区域
val clampedX = max(drawableLeft, min(rawX, drawableLeft + drawnW)) val clampedX = max(drawableLeft, min(rawX, drawableLeft + drawnW))
val clampedY = max(drawableTop, min(rawY, drawableTop + drawnH)) val clampedY = max(drawableTop, min(rawY, drawableTop + drawnH))
// Normalised offset [0..1] within the drawable // 可绘制物内的归一化偏移 [0..1]
val normalizedX = (clampedX - drawableLeft) / drawnW val normalizedX = (clampedX - drawableLeft) / drawnW
val normalizedY = (clampedY - drawableTop) / drawnH 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 * 1. 将图片分为头部左肩胸部右肩四个区域
* zone centre (Euclidean distance in normalised space) is used to avoid * 2. 边界附近±0.04范围内使用最近区域中心避免误判
* arbitrary assignments at boundary pixels. * 3. 上半部分为头部下半部分按1/3和2/3垂直线划分
*/ */
private fun zoneForLocation(nx: Float, ny: Float): Zone { private fun zoneForLocation(nx: Float, ny: Float): Zone {
val hBoundary = 0.5f 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 { private fun nearestZone(nx: Float, ny: Float): Zone {
return Zone.values().minByOrNull { zone -> return Zone.values().minByOrNull { zone ->
val dx = nx - zone.normalizedX 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.
* 1. 根据Zone的归一化坐标计算目标位置
* Because the marker is a child of ivHumanBody and starts at its center 2. 限制标记不超出图片边界Y仅限制上限
* (layout_gravity="center"), we compute the offset from that center point 3. 相对于ImageView中心计算偏移量并应用
* and apply it via translationX/Y so the marker's layout bounds stay intact. 4. 支持动画或即时移动两种方式
*/ */
private fun updateMarkerPosition(zone: Zone, animated: Boolean) { private fun updateMarkerPosition(zone: Zone, animated: Boolean) {
if (humanBodyWidth <= 0 || humanBodyHeight <= 0) return if (humanBodyWidth <= 0 || humanBodyHeight <= 0) return
@@ -198,9 +204,7 @@ class StrikePositionActivity : AppCompatActivity() {
val rawX = humanBodyWidth * zone.normalizedX val rawX = humanBodyWidth * zone.normalizedX
val rawY = humanBodyHeight * zone.normalizedY val rawY = humanBodyHeight * zone.normalizedY
// Clamp X so the marker never extends beyond the drawable edges. //用X夹住使标记永远不会超出可绘制的边缘。Y钳只有一个上界——在归一化Y=0处的HEAD可以一直达到顶端平移Y可以为负
// 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).
val clampedX = min(max(rawX, halfMarkerW), humanBodyWidth - halfMarkerW) val clampedX = min(max(rawX, halfMarkerW), humanBodyWidth - halfMarkerW)
val clampedY = min(rawY, humanBodyHeight - halfMarkerH) 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.os.Bundle
import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.bean.DeleteDeviceUserRequest import com.ckkj.defense_device.bean.DeleteDeviceUserRequest
import com.example.defenseapplication.bean.ObtainInviterInformationRequest import com.ckkj.defense_device.bean.ObtainInviterInformationRequest
import com.example.defenseapplication.bean.VerifyOptionPasswordRequest import com.ckkj.defense_device.bean.UpdateFamilyUserRequest
import com.example.defenseapplication.personal.PasswordInputDialog import com.ckkj.defense_device.bean.VerifyOptionPasswordRequest
import com.example.defenseapplication.utils.DeviceIdEvent import com.ckkj.defense_device.personal.PasswordInputDialog
import com.example.defenseapplication.utils.DeviceUserUpdateEvent import com.ckkj.defense_device.utils.DeviceIdEvent
import com.example.defenseapplication.databinding.UserDetailsActivityBinding import com.ckkj.defense_device.utils.DeviceUserUpdateEvent
import com.example.defenseapplication.utils.RetrofitNetwork import com.ckkj.defense_device.databinding.UserDetailsActivityBinding
import com.example.defenseapplication.view.CustomDialogFragmentText import com.ckkj.defense_device.utils.RetrofitNetwork
import com.ckkj.defense_device.view.CustomDialogFragmentText
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -27,6 +27,7 @@ class UserDetailsActivity : AppCompatActivity() {
private var userId: String = "" private var userId: String = ""
private var isPasswordVerified: Boolean = false private var isPasswordVerified: Boolean = false
private lateinit var passwordDialog: PasswordInputDialog private lateinit var passwordDialog: PasswordInputDialog
private var optionPassword: String = ""
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -73,8 +74,8 @@ class UserDetailsActivity : AppCompatActivity() {
} }
} }
private fun updateUI(data: com.example.defenseapplication.bean.ObtainInviterInformationBean) { private fun updateUI(data: com.ckkj.defense_device.bean.ObtainInviterInformationBean) {
binding.tvContactName.text = data.nickName ?: "未知用户" binding.tvContactName.text = data.nickName ?: ""
binding.tvPhone.text = data.phonenumber ?: "" binding.tvPhone.text = data.phonenumber ?: ""
binding.tvIdCard.text = data.idCard ?: "" binding.tvIdCard.text = data.idCard ?: ""
binding.tvMacAddress.text = data.mac ?: "" binding.tvMacAddress.text = data.mac ?: ""
@@ -88,10 +89,12 @@ class UserDetailsActivity : AppCompatActivity() {
binding.swUserStatus.setOnCheckedChangeListener { _, isChecked -> binding.swUserStatus.setOnCheckedChangeListener { _, isChecked ->
if (!isPasswordVerified) { if (!isPasswordVerified) {
binding.swUserStatus.isChecked = !isChecked binding.swUserStatus.isChecked = !isChecked
showPasswordDialog { showPasswordDialog(isChecked) {
isPasswordVerified = true isPasswordVerified = true
binding.swUserStatus.isChecked = isChecked 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 { passwordDialog = PasswordInputDialog(this).apply {
setOnConfirmListener { inputPassword -> setOnConfirmListener { inputPassword ->
lifecycleScope.launch { lifecycleScope.launch {
@@ -110,6 +113,7 @@ class UserDetailsActivity : AppCompatActivity() {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if (response.code == 200) { if (response.code == 200) {
dismiss() dismiss()
updateFamilyUserStatus(status, inputPassword)
onVerified() onVerified()
} else { } else {
Toast.makeText( 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() { private fun showDeleteDialog() {
val dialog = CustomDialogFragmentText() val dialog = CustomDialogFragmentText()
dialog.setTitle(getString(R.string.tip)) dialog.setTitle(getString(R.string.tip))
@@ -147,7 +193,7 @@ class UserDetailsActivity : AppCompatActivity() {
if (isPasswordVerified) { if (isPasswordVerified) {
deleteDeviceUser() deleteDeviceUser()
} else { } else {
showPasswordDialog { showPasswordDialog(false) {
isPasswordVerified = true isPasswordVerified = true
deleteDeviceUser() deleteDeviceUser()
} }

View File

@@ -1,15 +1,15 @@
package com.example.defenseapplication.liveVideo package com.ckkj.defense_device.liveVideo
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.bean.DeviceBean import com.ckkj.defense_device.bean.DeviceBean
import com.example.defenseapplication.databinding.VoiceSettingsActivityBinding import com.ckkj.defense_device.databinding.VoiceSettingsActivityBinding
import com.example.defenseapplication.utils.ApiService import com.ckkj.defense_device.utils.ApiService
import com.example.defenseapplication.utils.DeviceIdEvent import com.ckkj.defense_device.utils.DeviceIdEvent
import com.example.defenseapplication.utils.RetrofitNetwork import com.ckkj.defense_device.utils.RetrofitNetwork
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -79,29 +79,31 @@ class VoiceSettingsActivity : AppCompatActivity() {
private fun updateDeviceAlertAudio() { private fun updateDeviceAlertAudio() {
deviceId?.let { id -> deviceId?.let { id ->
val newAlertAudio = if (binding.swWarningVoice.isChecked) "1" else "0" val newAlertAudio = if (binding.swWarningVoice.isChecked) "1" else "0"
// 只有状态发生变化时才请求 // 点击返回时总是触发网络请求
if (newAlertAudio != originalAlertAudio) { CoroutineScope(Dispatchers.IO).launch {
CoroutineScope(Dispatchers.IO).launch { try {
try { val deviceBean = DeviceBean(id = id, alertAudio = newAlertAudio)
val deviceBean = DeviceBean(id = id, alertAudio = newAlertAudio) val response = apiService.updateDeviceInfo(deviceBean)
val response = apiService.updateDeviceInfo(deviceBean) withContext(Dispatchers.Main) {
withContext(Dispatchers.Main) { if (response.code == 200 && response.data != null) {
if (response.code == 200 && response.data != null) { Toast.makeText(this@VoiceSettingsActivity, "修改成功", Toast.LENGTH_SHORT).show()
Toast.makeText(this@VoiceSettingsActivity, "修改成功", Toast.LENGTH_SHORT).show() } else {
} else { // 仅在状态实际发生变化时才显示错误提示
if (newAlertAudio != originalAlertAudio) {
Toast.makeText(this@VoiceSettingsActivity, response.msg, Toast.LENGTH_SHORT).show() Toast.makeText(this@VoiceSettingsActivity, response.msg, Toast.LENGTH_SHORT).show()
} }
finish()
} }
} catch (e: Exception) { finish()
withContext(Dispatchers.Main) { }
} catch (e: Exception) {
withContext(Dispatchers.Main) {
// 仅在状态实际发生变化时才显示失败提示
if (newAlertAudio != originalAlertAudio) {
Toast.makeText(this@VoiceSettingsActivity, "修改失败", Toast.LENGTH_SHORT).show() 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.content.Intent
import android.graphics.Color import android.graphics.Color
@@ -6,10 +6,10 @@ import android.os.Bundle
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.widget.doAfterTextChanged import androidx.core.widget.doAfterTextChanged
import com.example.defenseapplication.bean.DeviceBean import com.ckkj.defense_device.bean.DeviceBean
import com.example.defenseapplication.databinding.WarningVoiceContentActivityBinding import com.ckkj.defense_device.databinding.WarningVoiceContentActivityBinding
import com.example.defenseapplication.utils.ApiService import com.ckkj.defense_device.utils.ApiService
import com.example.defenseapplication.utils.RetrofitNetwork import com.ckkj.defense_device.utils.RetrofitNetwork
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers 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.os.Bundle
import android.widget.Toast import android.widget.Toast
import androidx.activity.enableEdgeToEdge import com.ckkj.defense_device.R
import com.example.defenseapplication.R import com.ckkj.defense_device.base.BaseActivity
import com.example.defenseapplication.base.BaseActivity import com.ckkj.defense_device.bean.DeviceBean
import com.example.defenseapplication.bean.DeviceBean import com.ckkj.defense_device.databinding.WaterGunSettingsActivityBinding
import com.example.defenseapplication.databinding.WaterGunSettingsActivityBinding import com.ckkj.defense_device.utils.DeviceIdEvent
import com.example.defenseapplication.utils.DeviceIdEvent import com.ckkj.defense_device.utils.RetrofitNetwork
import com.example.defenseapplication.utils.RetrofitNetwork import com.ckkj.defense_device.view.ContainerSelectDialog
import com.example.defenseapplication.view.ContainerSelectDialog import com.ckkj.defense_device.view.CustomDialogFragmentText
import com.example.defenseapplication.view.CustomDialogFragmentText
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -25,6 +24,7 @@ class WaterGunSettingsActivity : BaseActivity() {
private var currentStrikeRange: String = "7" private var currentStrikeRange: String = "7"
private var currentStrikeInterval: String = "3" private var currentStrikeInterval: String = "3"
private var currentContainer: String = "容器4" private var currentContainer: String = "容器4"
private var optionPassword: String? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -42,6 +42,7 @@ class WaterGunSettingsActivity : BaseActivity() {
currentStrikeRange = intent.getStringExtra("strikeRange") ?: "7" currentStrikeRange = intent.getStringExtra("strikeRange") ?: "7"
currentStrikeInterval = intent.getStringExtra("strikeInterval") ?: "3" currentStrikeInterval = intent.getStringExtra("strikeInterval") ?: "3"
currentContainer = intent.getStringExtra("container") ?: "容器4" currentContainer = intent.getStringExtra("container") ?: "容器4"
optionPassword = intent.getStringExtra("optionPassword")
// 显示初始值 // 显示初始值
binding.tvDistance.text = "${currentStrikeRange}m" binding.tvDistance.text = "${currentStrikeRange}m"
@@ -101,7 +102,8 @@ class WaterGunSettingsActivity : BaseActivity() {
try { try {
val deviceBean = DeviceBean( val deviceBean = DeviceBean(
id = deviceId, id = deviceId,
strikeRange = distance strikeRange = distance,
optionPassword = optionPassword
) )
val response = RetrofitNetwork.getNetworkService().updateDeviceInfo(deviceBean) val response = RetrofitNetwork.getNetworkService().updateDeviceInfo(deviceBean)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
@@ -132,7 +134,8 @@ class WaterGunSettingsActivity : BaseActivity() {
try { try {
val deviceBean = DeviceBean( val deviceBean = DeviceBean(
id = deviceId, id = deviceId,
strikeInterval = interval strikeInterval = interval,
optionPassword = optionPassword
) )
val response = RetrofitNetwork.getNetworkService().updateDeviceInfo(deviceBean) val response = RetrofitNetwork.getNetworkService().updateDeviceInfo(deviceBean)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
@@ -163,7 +166,8 @@ class WaterGunSettingsActivity : BaseActivity() {
try { try {
val deviceBean = DeviceBean( val deviceBean = DeviceBean(
id = deviceId, id = deviceId,
container = container container = container,
optionPassword = optionPassword
) )
val response = RetrofitNetwork.getNetworkService().updateDeviceInfo(deviceBean) val response = RetrofitNetwork.getNetworkService().updateDeviceInfo(deviceBean)
withContext(Dispatchers.Main) { 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.Manifest
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
@@ -18,13 +18,13 @@ import android.widget.PopupWindow
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.adapter.WifiListAdapter import com.ckkj.defense_device.adapter.WifiListAdapter
import com.example.defenseapplication.bean.DeviceBean import com.ckkj.defense_device.bean.DeviceBean
import com.example.defenseapplication.databinding.DialogWifiListBinding import com.ckkj.defense_device.databinding.DialogWifiListBinding
import com.example.defenseapplication.databinding.WifiManagementActivityBinding import com.ckkj.defense_device.databinding.WifiManagementActivityBinding
import com.example.defenseapplication.utils.DeviceIdEvent import com.ckkj.defense_device.utils.DeviceIdEvent
import com.example.defenseapplication.utils.RetrofitNetwork import com.ckkj.defense_device.utils.RetrofitNetwork
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -202,14 +202,6 @@ class WiFiManagementActivity : AppCompatActivity() {
} }
dialogBinding.rvWifiList.adapter = adapter dialogBinding.rvWifiList.adapter = adapter
// 添加下拉刷新功能
dialogBinding.swipeRefreshLayout.setOnRefreshListener {
wifiManager.startScan()
// 延迟1秒后停止刷新动画
android.os.Handler().postDelayed({
dialogBinding.swipeRefreshLayout.isRefreshing = false
}, 1000)
}
} }
private fun updateBottomButtonVisibility() { private fun updateBottomButtonVisibility() {
@@ -229,9 +221,6 @@ class WiFiManagementActivity : AppCompatActivity() {
} }
private fun updateWifiList() { 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 -> popupWindow?.contentView?.findViewById<androidx.recyclerview.widget.RecyclerView>(R.id.rvWifiList)?.let { recyclerView ->
val wifiList = getWifiList() val wifiList = getWifiList()
recyclerView.adapter = WifiListAdapter(wifiList) { wifiName -> recyclerView.adapter = WifiListAdapter(wifiList) { wifiName ->
@@ -253,4 +242,4 @@ class WiFiManagementActivity : AppCompatActivity() {
unregisterReceiver(wifiScanReceiver) unregisterReceiver(wifiScanReceiver)
popupWindow?.dismiss() 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.content.Intent
import android.os.Bundle import android.os.Bundle
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat import com.ckkj.defense_device.databinding.FaceLoginActivityBinding
import androidx.core.view.WindowInsetsCompat
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.FaceLoginActivityBinding
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
//人脸识别 //人脸识别
class FaceLoginActivity : AppCompatActivity() { 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.Manifest
import android.content.pm.PackageManager import android.content.pm.PackageManager
@@ -13,8 +13,9 @@ import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.example.defenseapplication.databinding.FaceVerificationActivityBinding import com.ckkj.defense_device.R
import com.example.defenseapplication.view.FaceAnalyzer 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.FaceDetection
import com.google.mlkit.vision.face.FaceDetectorOptions import com.google.mlkit.vision.face.FaceDetectorOptions
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
@@ -106,7 +107,7 @@ class FaceVerificationActivity : AppCompatActivity() {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startCamera() startCamera()
} else { } else {
Toast.makeText(this, "需要相机权限才能进行人脸验证", Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.need_camera_permission_for_face_verify, Toast.LENGTH_SHORT).show()
finish() 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.Color
import android.graphics.drawable.GradientDrawable import android.graphics.drawable.GradientDrawable
@@ -7,9 +7,10 @@ import android.os.CountDownTimer
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import bean.ForgotRequest import bean.ForgotRequest
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.databinding.ForgetPasswordActivityBinding import com.ckkj.defense_device.databinding.ForgetPasswordActivityBinding
import com.example.defenseapplication.utils.RetrofitNetwork 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.google.firebase.crashlytics.buildtools.reloc.org.apache.http.util.TextUtils
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@@ -20,6 +21,7 @@ import java.util.regex.Pattern
class ForgetPasswordActivity : AppCompatActivity() { class ForgetPasswordActivity : AppCompatActivity() {
private lateinit var binding: ForgetPasswordActivityBinding private lateinit var binding: ForgetPasswordActivityBinding
private var isLoading = false
private var countDownTimer: CountDownTimer? = null private var countDownTimer: CountDownTimer? = null
private var isSendingCode = false private var isSendingCode = false
@@ -55,15 +57,17 @@ class ForgetPasswordActivity : AppCompatActivity() {
if (isPhoneNumberValid(phoneNumber)) { if (isPhoneNumberValid(phoneNumber)) {
sendVerificationCode(phoneNumber) sendVerificationCode(phoneNumber)
} else { } else {
Toast.makeText(this, "请输入有效的11位手机号", Toast.LENGTH_SHORT).show() Toast.makeText(this, getString(R.string.phone_tip), Toast.LENGTH_SHORT).show()
} }
} else { } else {
Toast.makeText(this, "请稍后再试", Toast.LENGTH_SHORT).show() Toast.makeText(this, getString(R.string.please_try_later), Toast.LENGTH_SHORT).show()
} }
} }
binding.btnNext.setOnClickListener { binding.btnNext.setOnClickListener {
performResetPassword() if (!isLoading) {
performResetPassword()
}
} }
} }
@@ -82,7 +86,7 @@ class ForgetPasswordActivity : AppCompatActivity() {
val response = RetrofitNetwork.getNetworkService().getCode(phoneNumber) val response = RetrofitNetwork.getNetworkService().getCode(phoneNumber)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if (response.code == 200) { 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() startCountDown()
} else { } else {
Toast.makeText(this@ForgetPasswordActivity, response.msg, Toast.LENGTH_SHORT).show() Toast.makeText(this@ForgetPasswordActivity, response.msg, Toast.LENGTH_SHORT).show()
@@ -104,11 +108,10 @@ class ForgetPasswordActivity : AppCompatActivity() {
* 开始验证码按钮倒计时 * 开始验证码按钮倒计时
*/ */
private fun startCountDown() { private fun startCountDown() {
binding.sendCodeBtn.isEnabled = false
countDownTimer = object : CountDownTimer(COUNTDOWN_DURATION, COUNTDOWN_INTERVAL) { countDownTimer = object : CountDownTimer(COUNTDOWN_DURATION, COUNTDOWN_INTERVAL) {
override fun onTick(millisUntilFinished: Long) { override fun onTick(millisUntilFinished: Long) {
val secondsRemaining = (millisUntilFinished / 1000).toInt() binding.sendCodeBtn.text = getString(R.string.countdown_retry, millisUntilFinished / 1000)
binding.sendCodeBtn.text = "${secondsRemaining}秒后重试"
binding.sendCodeBtn.isEnabled = false
} }
override fun onFinish() { override fun onFinish() {
@@ -123,7 +126,7 @@ class ForgetPasswordActivity : AppCompatActivity() {
private fun resetSendButton() { private fun resetSendButton() {
countDownTimer?.cancel() countDownTimer?.cancel()
countDownTimer = null countDownTimer = null
binding.sendCodeBtn.text = "发送验证码" binding.sendCodeBtn.text = getString(R.string.resend_code)
binding.sendCodeBtn.isEnabled = true binding.sendCodeBtn.isEnabled = true
} }
@@ -137,34 +140,38 @@ class ForgetPasswordActivity : AppCompatActivity() {
val confirmPassword = binding.etInviteCode.text.toString().trim() val confirmPassword = binding.etInviteCode.text.toString().trim()
if (!isPhoneNumberValid(phoneNumber)) { if (!isPhoneNumberValid(phoneNumber)) {
Toast.makeText(this, "手机号格式不正确", Toast.LENGTH_SHORT).show() Toast.makeText(this, getString(R.string.invalid_phone), Toast.LENGTH_SHORT).show()
return return
} }
if (TextUtils.isEmpty(smsCode)) { 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 return
} }
if (TextUtils.isEmpty(newPassword) || TextUtils.isEmpty(confirmPassword)) { 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 return
} }
if (newPassword.length < MIN_PASSWORD_LENGTH || newPassword.length > MAX_PASSWORD_LENGTH) { 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 return
} }
if (!newPassword.matches(Regex(".*[A-Za-z].*")) || !newPassword.matches(Regex(".*[0-9].*"))) { 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 return
} }
if (newPassword != confirmPassword) { if (newPassword != confirmPassword) {
Toast.makeText(this, "两次输入的密码不一致", Toast.LENGTH_SHORT).show() Toast.makeText(this, getString(R.string.password_mismatch), Toast.LENGTH_SHORT).show()
return return
} }
isLoading = true
binding.btnNext.isEnabled = false binding.btnNext.isEnabled = false
binding.btnNext.text = "重置中..." val loadingDialog = LoadingDialog(this)
.setMessage(getString(R.string.resetting))
.apply { show() }
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
try { try {
@@ -175,8 +182,9 @@ class ForgetPasswordActivity : AppCompatActivity() {
) )
val response = RetrofitNetwork.getNetworkService().forgotPassword(forgotRequest) val response = RetrofitNetwork.getNetworkService().forgotPassword(forgotRequest)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
isLoading = false
loadingDialog.dismiss()
binding.btnNext.isEnabled = true binding.btnNext.isEnabled = true
binding.btnNext.text = "确定"
if (response.code == 200) { if (response.code == 200) {
Toast.makeText(this@ForgetPasswordActivity, R.string.reset_success, Toast.LENGTH_SHORT).show() Toast.makeText(this@ForgetPasswordActivity, R.string.reset_success, Toast.LENGTH_SHORT).show()
@@ -187,8 +195,9 @@ class ForgetPasswordActivity : AppCompatActivity() {
} }
} catch (e: Exception) { } catch (e: Exception) {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
isLoading = false
loadingDialog.dismiss()
binding.btnNext.isEnabled = true binding.btnNext.isEnabled = true
binding.btnNext.text = "确定"
Toast.makeText(this@ForgetPasswordActivity, R.string.network_error, Toast.LENGTH_SHORT).show() 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.content.Intent
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.GradientDrawable import android.graphics.drawable.GradientDrawable
import android.os.Bundle import android.os.Bundle
import android.os.CountDownTimer import android.os.CountDownTimer
import android.util.Log
import android.view.View import android.view.View
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet import androidx.constraintlayout.widget.ConstraintSet
import bean.LoginRequest import bean.LoginRequest
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.databinding.ActivityLoginBinding import com.ckkj.defense_device.databinding.ActivityLoginBinding
import com.example.defenseapplication.home.HomeActivity import com.ckkj.defense_device.home.HomeActivity
import com.example.defenseapplication.utils.RetrofitNetwork import com.ckkj.defense_device.utils.ApiConfig
import com.example.defenseapplication.utils.UserinfoUtil import com.ckkj.defense_device.utils.RetrofitNetwork
import com.ckkj.defense_device.utils.UserinfoUtil
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -26,19 +28,13 @@ class LoginActivity : AppCompatActivity() {
private lateinit var binding: ActivityLoginBinding private lateinit var binding: ActivityLoginBinding
private var currentLoginMode = LoginMode.SMS private var currentLoginMode = LoginMode.SMS
private var countDownTimer: CountDownTimer? = null
enum class LoginMode { SMS, PASSWORD } enum class LoginMode { SMS, PASSWORD }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
ApiConfig.resetAuthRedirectFlag()
if (UserinfoUtil.getUserInfo() != null) {
val intent = Intent(this, HomeActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
finish()
return
}
binding = ActivityLoginBinding.inflate(layoutInflater) binding = ActivityLoginBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
@@ -81,7 +77,7 @@ class LoginActivity : AppCompatActivity() {
binding.registerText.visibility = View.VISIBLE binding.registerText.visibility = View.VISIBLE
binding.forgetText.visibility = View.GONE binding.forgetText.visibility = View.GONE
updateRegisterTextConstraints(center = false) updateRegisterTextConstraints(center = true)
//需要正确的方法名和参数 //需要正确的方法名和参数
updateLoginButtonTopConstraint(R.id.smsRowLayout) updateLoginButtonTopConstraint(R.id.smsRowLayout)
@@ -106,7 +102,6 @@ class LoginActivity : AppCompatActivity() {
private fun updateLoginButtonTopConstraint(topTargetId: Int) { private fun updateLoginButtonTopConstraint(topTargetId: Int) {
val params = binding.loginBtn.layoutParams as ConstraintLayout.LayoutParams val params = binding.loginBtn.layoutParams as ConstraintLayout.LayoutParams
params.topToBottom = topTargetId params.topToBottom = topTargetId
params.topMargin = 32
binding.loginBtn.layoutParams = params binding.loginBtn.layoutParams = params
} }
@@ -123,7 +118,6 @@ class LoginActivity : AppCompatActivity() {
params.endToEnd = ConstraintSet.UNSET params.endToEnd = ConstraintSet.UNSET
} }
params.topToBottom = binding.loginBtn.id params.topToBottom = binding.loginBtn.id
params.topMargin = 20
binding.registerText.layoutParams = params binding.registerText.layoutParams = params
} }
@@ -174,25 +168,24 @@ class LoginActivity : AppCompatActivity() {
binding.registerText.setOnClickListener { binding.registerText.setOnClickListener {
val intent= Intent(this, RegisterActivity::class.java) val intent= Intent(this, RegisterActivity::class.java)
startActivity(intent) startActivity(intent)
Toast.makeText(this, R.string.redirect_register_page, Toast.LENGTH_SHORT).show()
} }
binding.forgetText.setOnClickListener { binding.forgetText.setOnClickListener {
val intent= Intent(this, ForgetPasswordActivity::class.java) val intent= Intent(this, ForgetPasswordActivity::class.java)
startActivity(intent) startActivity(intent)
Toast.makeText(this, R.string.forgot_password_page, Toast.LENGTH_SHORT).show()
} }
} }
private fun startCountDown() { private fun startCountDown() {
binding.sendCodeBtn.isEnabled = false binding.sendCodeBtn.isEnabled = false
object : CountDownTimer(60000, 1000) { countDownTimer = object : CountDownTimer(60000, 1000) {
override fun onTick(millisUntilFinished: Long) { override fun onTick(millisUntilFinished: Long) {
binding.sendCodeBtn.text = getString(R.string.countdown_retry, millisUntilFinished / 1000) binding.sendCodeBtn.text = getString(R.string.countdown_retry, millisUntilFinished / 1000)
} }
override fun onFinish() { override fun onFinish() {
binding.sendCodeBtn.text = getString(R.string.send_code) binding.sendCodeBtn.text = getString(R.string.resend_code)
binding.sendCodeBtn.isEnabled = true binding.sendCodeBtn.isEnabled = true
countDownTimer = null
} }
}.start() }.start()
} }
@@ -226,9 +219,7 @@ class LoginActivity : AppCompatActivity() {
phonenumber = phone, phonenumber = phone,
smsCode = smsCode smsCode = smsCode
) )
android.util.Log.d("LoginActivity", "短信登录请求: $loginRequest")
val response = RetrofitNetwork.getNetworkService().login(loginRequest) val response = RetrofitNetwork.getNetworkService().login(loginRequest)
android.util.Log.d("LoginActivity", "短信登录响应: code=${response.code}, msg=${response.msg}")
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if (response.code == 200 && response.data != null) { if (response.code == 200 && response.data != null) {
UserinfoUtil.saveUserInfo(response.data) UserinfoUtil.saveUserInfo(response.data)
@@ -242,7 +233,6 @@ class LoginActivity : AppCompatActivity() {
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
android.util.Log.e("LoginActivity", "短信登录异常", e)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
Toast.makeText(this@LoginActivity, R.string.network_error, Toast.LENGTH_SHORT).show() Toast.makeText(this@LoginActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
} }
@@ -259,14 +249,13 @@ class LoginActivity : AppCompatActivity() {
phonenumber = phone, phonenumber = phone,
password = password password = password
) )
android.util.Log.d("LoginActivity", "密码登录请求: $loginRequest")
val response = RetrofitNetwork.getNetworkService().login(loginRequest) val response = RetrofitNetwork.getNetworkService().login(loginRequest)
android.util.Log.d("LoginActivity", "密码登录响应: code=${response.code}, msg=${response.msg}")
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if (response.code == 200 && response.data != null) { if (response.code == 200 && response.data != null) {
UserinfoUtil.saveUserInfo(response.data) UserinfoUtil.saveUserInfo(response.data)
Toast.makeText(this@LoginActivity, R.string.password_login_success_title, Toast.LENGTH_SHORT).show() Toast.makeText(this@LoginActivity, R.string.password_login_success_title, Toast.LENGTH_SHORT).show()
val intent = Intent(this@LoginActivity, HomeActivity::class.java) val intent = Intent(this@LoginActivity, HomeActivity::class.java)
//清除任务栈
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent) startActivity(intent)
finish() finish()
@@ -275,7 +264,6 @@ class LoginActivity : AppCompatActivity() {
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
android.util.Log.e("LoginActivity", "密码登录异常", e)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
Toast.makeText(this@LoginActivity, R.string.network_error, Toast.LENGTH_SHORT).show() Toast.makeText(this@LoginActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
} }
@@ -293,4 +281,10 @@ class LoginActivity : AppCompatActivity() {
gradientDrawable.gradientType = GradientDrawable.LINEAR_GRADIENT gradientDrawable.gradientType = GradientDrawable.LINEAR_GRADIENT
view.background = gradientDrawable 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.content.Intent
import android.graphics.Color import android.graphics.Color
@@ -8,9 +8,10 @@ import android.os.CountDownTimer
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import bean.RegisterRequest import bean.RegisterRequest
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.databinding.RegisterActivityBinding import com.ckkj.defense_device.databinding.RegisterActivityBinding
import com.example.defenseapplication.utils.RetrofitNetwork import com.ckkj.defense_device.utils.RetrofitNetwork
import com.ckkj.defense_device.view.LoadingDialog
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -80,7 +81,7 @@ class RegisterActivity : AppCompatActivity() {
val response = RetrofitNetwork.getNetworkService().getCode(userName) val response = RetrofitNetwork.getNetworkService().getCode(userName)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if (response.code == 200) { 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() startCountDown()
} else { } else {
Toast.makeText(this@RegisterActivity, response.msg, Toast.LENGTH_SHORT).show() Toast.makeText(this@RegisterActivity, response.msg, Toast.LENGTH_SHORT).show()
@@ -99,11 +100,10 @@ class RegisterActivity : AppCompatActivity() {
} }
private fun startCountDown() { private fun startCountDown() {
binding.sendCodeBtn.isEnabled = false
countDownTimer = object : CountDownTimer(COUNTDOWN_DURATION, COUNTDOWN_INTERVAL) { countDownTimer = object : CountDownTimer(COUNTDOWN_DURATION, COUNTDOWN_INTERVAL) {
override fun onTick(millisUntilFinished: Long) { override fun onTick(millisUntilFinished: Long) {
val secondsRemaining = (millisUntilFinished / 1000).toInt() binding.sendCodeBtn.text = getString(R.string.countdown_retry, millisUntilFinished / 1000)
binding.sendCodeBtn.text = "${secondsRemaining}秒后重试"
binding.sendCodeBtn.isEnabled = false
} }
override fun onFinish() { override fun onFinish() {
@@ -115,7 +115,7 @@ class RegisterActivity : AppCompatActivity() {
private fun resetSendButton() { private fun resetSendButton() {
countDownTimer?.cancel() countDownTimer?.cancel()
countDownTimer = null countDownTimer = null
binding.sendCodeBtn.text = getString(R.string.send_code) binding.sendCodeBtn.text = getString(R.string.resend_code)
binding.sendCodeBtn.isEnabled = true binding.sendCodeBtn.isEnabled = true
isSendingCode = false isSendingCode = false
} }
@@ -158,7 +158,9 @@ class RegisterActivity : AppCompatActivity() {
isLoading = true isLoading = true
binding.btnNext.isEnabled = false 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 { CoroutineScope(Dispatchers.IO).launch {
try { try {
@@ -174,12 +176,13 @@ class RegisterActivity : AppCompatActivity() {
val response = RetrofitNetwork.getNetworkService().register(registerRequest) val response = RetrofitNetwork.getNetworkService().register(registerRequest)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
isLoading = false isLoading = false
loadingDialog.dismiss()
binding.btnNext.isEnabled = true binding.btnNext.isEnabled = true
binding.btnNext.text = getString(R.string.next_step)
if (response.code == 200) { if (response.code == 200) {
Toast.makeText(this@RegisterActivity, R.string.register_success, Toast.LENGTH_SHORT).show() 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 intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent) startActivity(intent)
finish() finish()
@@ -190,8 +193,8 @@ class RegisterActivity : AppCompatActivity() {
} catch (e: Exception) { } catch (e: Exception) {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
isLoading = false isLoading = false
loadingDialog.dismiss()
binding.btnNext.isEnabled = true binding.btnNext.isEnabled = true
binding.btnNext.text = getString(R.string.next_step)
Toast.makeText(this@RegisterActivity, R.string.network_error, Toast.LENGTH_SHORT).show() 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.content.Intent
import android.os.Bundle import android.os.Bundle
import android.os.CountDownTimer import android.os.CountDownTimer
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat import com.ckkj.defense_device.databinding.RegisterSuccessActivityBinding
import androidx.core.view.WindowInsetsCompat import com.ckkj.defense_device.home.HomeActivity
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.RegisterSuccessActivityBinding
import com.example.defenseapplication.home.HomeActivity
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
//注册成功界面 //注册成功界面
class RegisterSuccessActivity : AppCompatActivity() { class RegisterSuccessActivity : AppCompatActivity() {

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.model package com.ckkj.defense_device.model
data class FamilyItem( data class FamilyItem(
val id: String, 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.os.Bundle
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.bean.UpdatePassword import com.ckkj.defense_device.bean.UpdatePassword
import com.example.defenseapplication.databinding.ChangePasswordActivityBinding import com.ckkj.defense_device.databinding.ChangePasswordActivityBinding
import com.example.defenseapplication.utils.RetrofitNetwork import com.ckkj.defense_device.utils.RetrofitNetwork
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers 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.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.databinding.FaceManagementActivityBinding import com.ckkj.defense_device.databinding.FaceManagementActivityBinding
import com.example.defenseapplication.login.FaceLoginActivity import com.ckkj.defense_device.login.FaceLoginActivity
import com.gyf.immersionbar.ImmersionBar 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.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Color import android.graphics.Color
import android.graphics.Paint import android.graphics.Paint
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Environment import android.os.Environment
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialog
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.bean.VerifyOptionPasswordRequest import com.ckkj.defense_device.bean.RecommendationCodeBean
import com.example.defenseapplication.databinding.DialogExpireTimeBinding import com.ckkj.defense_device.bean.SelectInviterInfoBean
import com.example.defenseapplication.databinding.InvitationCodeActivityBinding import com.ckkj.defense_device.bean.VerifyOptionPasswordRequest
import com.example.defenseapplication.utils.RetrofitNetwork 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.BarcodeFormat
import com.google.zxing.EncodeHintType import com.google.zxing.EncodeHintType
import com.google.zxing.qrcode.QRCodeWriter import com.google.zxing.qrcode.QRCodeWriter
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import com.gyf.immersionbar.ImmersionBar 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.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.json.JSONObject
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import java.util.Hashtable import java.util.Hashtable
@@ -44,7 +57,24 @@ class InvitationCodeActivity : AppCompatActivity() {
private var isLoading = false // 是否正在加载 private var isLoading = false // 是否正在加载
private var hasGeneratedQrCode = 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 { companion object {
private const val TAG = "InvitationCodeActivity"
const val EXPIRE_24H = 24 * 60 * 60 * 1000L const val EXPIRE_24H = 24 * 60 * 60 * 1000L
const val EXPIRE_7D = 7 * 24 * 60 * 60 * 1000L const val EXPIRE_7D = 7 * 24 * 60 * 60 * 1000L
} }
@@ -90,15 +120,136 @@ class InvitationCodeActivity : AppCompatActivity() {
// 撤销邀请按钮 // 撤销邀请按钮
binding.btnCancelInvite.setOnClickListener { binding.btnCancelInvite.setOnClickListener {
showPasswordDialog { if (generatedInviteCode.isEmpty()) {
cancelInvitation() ToastUtils.showError(this, getString(R.string.qr_code_expired))
return@setOnClickListener
}
showPasswordDialog { password, dialog ->
cancelInvitation(password, dialog)
} }
} }
// 生成/重新生成按钮 // 生成/重新生成按钮
binding.btnRegenerate.setOnClickListener { binding.btnRegenerate.setOnClickListener {
showPasswordDialog { showPasswordDialog { password, dialog ->
generateOrRegenerateInvitation() 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() { private fun generateOrRegenerateInvitation(password: String, passwordDialog: PasswordInputDialog) {
// 根据当前选择的时效生成邀请码 if (isLoading) return
generateQRCode() isLoading = true
showQrCode() val loadingDialog = LoadingDialog(this).apply { show() }
// 更新按钮文字为"重新生成"
binding.btnRegenerate.text = getString(R.string.regenerate) CoroutineScope(Dispatchers.IO).launch {
hasGeneratedQrCode = true try {
ToastUtils.showSuccess(this, getString(R.string.operation_success)) 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() { private fun showExpireTimeDialog() {
@@ -151,9 +344,6 @@ class InvitationCodeActivity : AppCompatActivity() {
binding.tvExpireTime.text = getString(R.string.expire_7d) binding.tvExpireTime.text = getString(R.string.expire_7d)
} }
} }
// 显示二维码并生成
showQrCode()
generateQRCode()
expireTimeDialog?.dismiss() expireTimeDialog?.dismiss()
} }
@@ -173,22 +363,28 @@ class InvitationCodeActivity : AppCompatActivity() {
} }
private fun generateQRCode() { private fun generateQRCode() {
// 检查二维码是否过期,如果过期则生成新的邀请码 if (qrCodeContent.isEmpty()) return
val isExpired = expireTimestamp > 0 && System.currentTimeMillis() > expireTimestamp val qrBitmap = createQRCodeWithLogo(qrCodeContent, 400, 400)
val content = if (qrCodeContent.isNotEmpty() && !isExpired) qrCodeContent else generateInviteCode()
val qrBitmap = createQRCodeWithLogo(content, 400, 400)
binding.ivQrCode.setImageBitmap(qrBitmap) binding.ivQrCode.setImageBitmap(qrBitmap)
} }
private fun generateInviteCode(): String { private fun parseRecommendationCode(data: Any?): Pair<String, Long>? {
val timestamp = System.currentTimeMillis() if (data == null) return null
expireTimestamp = timestamp + expireTimeInMillis return when (data) {
generatedInviteCode = "INV${timestamp}" is String -> {
qrCodeContent = "{\"type\":\"invite\",\"code\":\"$generatedInviteCode\",\"expire\":$expireTimestamp}" if (data.isEmpty()) null
// 输出日志,方便调试验证 else Pair(data, System.currentTimeMillis() + expireTimeInMillis)
android.util.Log.d("InvitationCode", "生成的二维码内容: $qrCodeContent") }
android.util.Log.d("InvitationCode", "推荐码: $generatedInviteCode, 过期时间戳: $expireTimestamp") else -> {
return qrCodeContent 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的二维码 * 这段代码生成带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) { if (logoDrawable != null) {
val logoSize = width / 5 val logoSize = width / 5
val logoX = (width - logoSize) / 2 val logoX = (width - logoSize) / 2
@@ -415,56 +611,62 @@ class InvitationCodeActivity : AppCompatActivity() {
/** /**
* 撤销邀请 * 撤销邀请
*/ */
private fun cancelInvitation() { private fun cancelInvitation(password: String, passwordDialog: PasswordInputDialog) {
// 撤销邀请逻辑 if (isLoading) return
hideQrCode() if (generatedInviteCode.isEmpty()) {
generatedInviteCode = "" passwordDialog.showError(getString(R.string.qr_code_expired))
qrCodeContent = "" return
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)
} }
dialog.show() isLoading = true
} val loadingDialog = LoadingDialog(this).apply { show() }
/**
* 验证操作密码
*/
private fun verifyPassword(password: String, dialog: PasswordInputDialog, onSuccess: () -> Unit) {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
try { try {
val response = RetrofitNetwork.getNetworkService() val response = RetrofitNetwork.getNetworkService()
.verifyOptionPassword(VerifyOptionPasswordRequest(password)) .revokeInvitation(VerifyOptionPasswordRequest(password))
Log.d(TAG, "撤销邀请响应: code=${response.code}, msg=${response.msg}")
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
isLoading = false
loadingDialog.dismiss()
if (response.code == 200) { if (response.code == 200) {
dialog.dismiss() passwordDialog.dismiss()
onSuccess.invoke() 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 { } else {
dialog.showError(getString(R.string.password_error)) passwordDialog.showError(
response.msg.ifEmpty { getString(R.string.password_error) }
)
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "撤销邀请异常", e)
withContext(Dispatchers.Main) { 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() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
expireTimeDialog?.dismiss() 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.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat import com.ckkj.defense_device.databinding.LoginPasswordActivityBinding
import androidx.core.view.WindowInsetsCompat
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.LoginPasswordActivityBinding
import com.example.defenseapplication.databinding.PasswordManagementActivityBinding
import com.gyf.immersionbar.ImmersionBar 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.os.Bundle
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.bean.UpdateUserInfo import com.ckkj.defense_device.bean.UpdateUserInfo
import com.example.defenseapplication.bean.VerifyOptionPasswordRequest import com.ckkj.defense_device.bean.VerifyOptionPasswordRequest
import com.example.defenseapplication.databinding.OperationPasswordActivityBinding import com.ckkj.defense_device.databinding.OperationPasswordActivityBinding
import com.example.defenseapplication.utils.RetrofitNetwork import com.ckkj.defense_device.utils.RetrofitNetwork
import com.example.defenseapplication.view.CustomDialogFragment import com.ckkj.defense_device.view.CustomDialogFragment
import com.example.defenseapplication.view.LoadingDialog import com.ckkj.defense_device.view.LoadingDialog
import com.example.defenseapplication.view.showDefenseDialog import com.ckkj.defense_device.view.showDefenseDialog
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers 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.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.databinding.PasswordManagementActivityBinding import com.ckkj.defense_device.databinding.PasswordManagementActivityBinding
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
//密码管理 //密码管理
class PasswordManagementActivity : AppCompatActivity() { 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.Manifest
import android.content.ContentResolver import android.content.ContentResolver
@@ -11,24 +11,21 @@ import android.os.Environment
import android.provider.MediaStore import android.provider.MediaStore
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.bean.UpdateUserInfo import com.ckkj.defense_device.bean.UpdateUserInfo
import com.example.defenseapplication.bean.UserInfoBean import com.ckkj.defense_device.bean.UserInfoBean
import com.example.defenseapplication.databinding.PersonalProfileActivityBinding import com.ckkj.defense_device.databinding.PersonalProfileActivityBinding
import com.example.defenseapplication.utils.RetrofitNetwork import com.ckkj.defense_device.utils.RetrofitNetwork
import com.example.defenseapplication.view.AvatarSelectDialog import com.ckkj.defense_device.view.AvatarSelectDialog
import com.example.defenseapplication.view.CustomDialogFragmentText import com.ckkj.defense_device.view.CustomDialogFragmentText
import com.example.defenseapplication.view.LoadingDialog import com.ckkj.defense_device.view.LoadingDialog
import com.example.defenseapplication.view.PhoneModifyDialogFragment import com.ckkj.defense_device.view.PhoneModifyDialogFragment
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers 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.Bundle
import android.os.CountDownTimer import android.os.CountDownTimer
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import bean.ForgotRequest import bean.ForgotRequest
import com.example.defenseapplication.R import com.ckkj.defense_device.R
import com.example.defenseapplication.databinding.RetrievePasswordActivityBinding import com.ckkj.defense_device.databinding.RetrievePasswordActivityBinding
import com.example.defenseapplication.utils.RetrofitNetwork import com.ckkj.defense_device.utils.RetrofitNetwork
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -163,7 +163,7 @@ class RetrievePasswordActivity : AppCompatActivity() {
override fun onFinish() { override fun onFinish() {
isCountingDown = false isCountingDown = false
binding.btnGetCode.isEnabled = true binding.btnGetCode.isEnabled = true
binding.btnGetCode.text = getString(R.string.get_verification_code) binding.btnGetCode.text = getString(R.string.resend_code)
} }
}.start() }.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 android.app.Activity
import java.lang.ref.WeakReference 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.annotation.SuppressLint
import android.content.Intent
import android.os.Handler
import android.os.Looper
import android.util.Log 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.Gson
import com.google.gson.JsonParser import com.google.gson.JsonParser
import okhttp3.Interceptor import okhttp3.Interceptor
@@ -24,10 +30,17 @@ object ApiConfig {
@Volatile @Volatile
public var authToken: String = "" public var authToken: String = ""
@Volatile
private var isRedirectingToLogin = false
fun updateAuthToken(token: String) { fun updateAuthToken(token: String) {
authToken = token authToken = token
} }
fun resetAuthRedirectFlag() {
isRedirectingToLogin = false
}
fun hasAuthToken(): Boolean { fun hasAuthToken(): Boolean {
return authToken.isNotBlank() return authToken.isNotBlank()
} }
@@ -116,8 +129,8 @@ object ApiConfig {
val businessCode = if (jsonObject.has("code")) jsonObject.get("code").asInt else 0 val businessCode = if (jsonObject.has("code")) jsonObject.get("code").asInt else 0
if (httpCode == 401 || httpCode == 424 || businessCode == 401) { if (httpCode == 401 || httpCode == 424 || businessCode == 401) {
clearUserLoginInfo()
val msg = if (jsonObject.has("msg")) jsonObject.get("msg").asString else "登录已过期,请重新登录" 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) 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 { private fun buildFakeErrorResponse(request: Request, msg: String, code: Int = 1): Response {
val baseInfo = BaseInfo( val baseInfo = BaseInfo(
message = msg, msg = msg,
code = code, code = code,
data = null, data = null,
) )
@@ -179,12 +192,36 @@ object ApiConfig {
private fun buildAuthorizationValue(token: String): String { private fun buildAuthorizationValue(token: String): String {
return if (token.startsWith("Bearer ")) token else "Bearer $token" 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() { private fun clearUserLoginInfo() {
try { try {
authToken = "" UserinfoUtil.clearUserInfo()
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
authToken = ""
} }
} }
} }

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