Compare commits

...

42 Commits

Author SHA1 Message Date
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
478 changed files with 3317 additions and 2019 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

@@ -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,30 @@
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=".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 +103,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"
@@ -108,7 +122,8 @@
android:exported="false" /> android:exported="false" />
<activity <activity
android:name=".home.HomeActivity" android:name=".home.HomeActivity"
android:exported="false" /> android:exported="false">
</activity>
<activity <activity
android:name=".login.RegisterSuccessActivity" android:name=".login.RegisterSuccessActivity"
android:exported="false" /> android:exported="false" />
@@ -126,13 +141,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

@@ -1,25 +1,15 @@
package com.example.defenseapplication package com.ckkj.defense_device
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
import bean.LoginBean
import com.blankj.utilcode.util.Utils import com.blankj.utilcode.util.Utils
import com.example.defenseapplication.bean.BaseInfo import com.ckkj.defense_device.utils.LanguageUtil
import com.example.defenseapplication.utils.ApiConfig
import com.example.defenseapplication.utils.LanguageUtil
import com.example.defenseapplication.utils.UserinfoUtil
import com.google.gson.Gson
class MyApplication : Application() { class MyApplication : Application() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
Utils.init(this) // 初始化 AndroidUtilCode Utils.init(this) // 初始化 AndroidUtilCode
var token = UserinfoUtil.getUserInfo()?.access_token;
if (token != null) {
ApiConfig.authToken = token
};
LanguageUtil.init(this) LanguageUtil.init(this)
} }

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,9 @@
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.databinding.ItemWifiBinding import com.ckkj.defense_device.databinding.ItemWifiBinding
class WifiListAdapter( class WifiListAdapter(
wifiList: List<String>, wifiList: List<String>,

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,//告警播放
@@ -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

@@ -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() {

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,25 @@ 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.ckkj.defense_device.R
import com.example.defenseapplication.adapter.DeviceAdapter import com.ckkj.defense_device.adapter.DeviceAdapter
import com.example.defenseapplication.adapter.DeviceUi import com.ckkj.defense_device.adapter.FamilyAdapter
import com.example.defenseapplication.adapter.FamilyAdapter import com.ckkj.defense_device.bean.DeviceBean
import com.example.defenseapplication.bean.DeviceBean import com.ckkj.defense_device.bean.FamilyBean
import com.example.defenseapplication.bean.FamilyBean import com.ckkj.defense_device.bean.SwitchFamilyRequest
import com.example.defenseapplication.bean.SwitchFamilyRequest import com.ckkj.defense_device.bean.SelectInviterInfoBean
import com.example.defenseapplication.databinding.HomeMenuFragmentBinding import com.ckkj.defense_device.databinding.HomeMenuFragmentBinding
import com.example.defenseapplication.liveVideo.LiveVideoActivity import com.ckkj.defense_device.liveVideo.LiveVideoActivity
import com.example.defenseapplication.utils.DeviceIdEvent import com.ckkj.defense_device.personal.JoinFamilyInviteActivity
import com.example.defenseapplication.utils.DeviceUpdateEvent import com.ckkj.defense_device.utils.DeviceIdEvent
import com.example.defenseapplication.utils.FamilySwitchEvent import com.ckkj.defense_device.utils.DeviceUpdateEvent
import com.example.defenseapplication.utils.MessageStatusManager import com.ckkj.defense_device.utils.FamilySwitchEvent
import com.example.defenseapplication.utils.RetrofitNetwork import com.ckkj.defense_device.utils.MessageStatusManager
import com.example.defenseapplication.utils.UserinfoUtil import com.ckkj.defense_device.utils.RetrofitNetwork
import com.example.defenseapplication.view.DefenseDialogs import com.ckkj.defense_device.utils.UserinfoUtil
import com.example.defenseapplication.view.showDefenseDialog import com.ckkj.defense_device.view.DefenseDialogs
import com.ckkj.defense_device.view.LoadingDialog
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 +47,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
@@ -122,23 +125,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()).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,12 +263,7 @@ 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(
view = binding.gradientLayout,
startColor = Color.parseColor("#EBDCED"),
endColor = Color.parseColor("#CAF4FF")
)
binding.message.setOnClickListener { binding.message.setOnClickListener {
val intent = Intent(requireContext(), MessageActivity::class.java) val intent = Intent(requireContext(), MessageActivity::class.java)
startActivity(intent) startActivity(intent)
@@ -285,6 +346,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 +386,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
} }
} }
@@ -390,9 +459,12 @@ 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
} }
@@ -401,6 +473,7 @@ class HomeMenuFragment : Fragment() {
} }
} catch (e: Exception) { } catch (e: Exception) {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
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) {
@@ -445,21 +518,31 @@ 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)
@@ -501,17 +584,6 @@ 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()
binding.rvFamilyList.adapter = null binding.rvFamilyList.adapter = null

View File

@@ -1,15 +1,15 @@
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.adapter.MessageListAdapter
import com.example.defenseapplication.adapter.MessageListItem import com.ckkj.defense_device.adapter.MessageListItem
import com.example.defenseapplication.databinding.MessageActivityBinding import com.ckkj.defense_device.databinding.MessageActivityBinding
import com.example.defenseapplication.utils.MessageStatusManager import com.ckkj.defense_device.utils.MessageStatusManager
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
@@ -24,7 +24,7 @@ class MessageActivity : AppCompatActivity() {
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 private var lastLoadedCount = 0
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@@ -125,7 +125,7 @@ class MessageActivity : AppCompatActivity() {
e.printStackTrace() e.printStackTrace()
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if (allMessages.isEmpty()) { if (allMessages.isEmpty()) {
showEmptyState() noNetwork()
} }
} }
} finally { } finally {
@@ -152,6 +152,12 @@ class MessageActivity : AppCompatActivity() {
binding.emptyLayout.visibility = View.GONE binding.emptyLayout.visibility = View.GONE
} }
private fun noNetwork() {
binding.rvMessageList.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,7 +166,7 @@ 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) ->

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,21 @@ 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.utils.AppLanguage
import com.example.defenseapplication.utils.LanguageUtil import com.ckkj.defense_device.utils.LanguageUtil
import com.example.defenseapplication.utils.RetrofitNetwork import com.ckkj.defense_device.utils.RetrofitNetwork
import com.example.defenseapplication.utils.UserinfoUtil import com.ckkj.defense_device.utils.UserinfoUtil
import com.example.defenseapplication.utils.ActivityManager import com.ckkj.defense_device.utils.ActivityManager
import com.example.defenseapplication.view.FamilySwitchDialog import com.ckkj.defense_device.view.CustomDialogFragmentText
import com.example.defenseapplication.view.LanguageDialog import com.ckkj.defense_device.view.FamilySwitchDialog
import com.example.defenseapplication.home.HomeActivity import com.ckkj.defense_device.view.LanguageDialog
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
@@ -49,7 +49,7 @@ 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.headerLayout.setOnClickListener {
@@ -101,27 +101,36 @@ 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")
} }
fetchCurrentFamily() fetchCurrentFamily()
return binding.root return binding.root
@@ -243,8 +252,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 +267,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,429 @@
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
Log.d("AlarmLogActivity", "=== 开始请求设备告警日志 ===")
Log.d("AlarmLogActivity", "请求参数 - deviceId: $currentDeviceId")
isLoading = true
lifecycleScope.launch {
try {
Log.d("AlarmLogActivity", "正在发送网络请求...")
val response = RetrofitNetwork.getNetworkService().getDeviceAlarmList(
deviceId = currentDeviceId,
pageNum = "1",
pageSize = "10"
)
Log.d("AlarmLogActivity", "请求完成")
Log.d("AlarmLogActivity", "总条数: ${response.total}, 当前页数据条数: ${response.rows.size}")
val newData = response.rows
originalAlarmList.clear()
originalAlarmList.addAll(newData)
filterAlarmListByDate(calendar)
currentAlarmItem = alarmList.firstOrNull()
Log.d("AlarmLogActivity", "已获取 ${newData.size} 条数据")
} catch (e: Exception) {
Log.e("AlarmLogActivity", "请求异常: ${e.message}", e)
} finally {
isLoading = false
Log.d("AlarmLogActivity", "请求结束")
}
}
}
private fun showEmptyView() {
binding.alarmListRecyclerView.visibility = View.GONE
binding.emptyLayout.visibility = View.VISIBLE
}
private fun hideEmptyView() {
binding.alarmListRecyclerView.visibility = View.VISIBLE
binding.emptyLayout.visibility = View.GONE
}
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()) {
showEmptyView()
currentAlarmItem = null
} else {
hideEmptyView()
currentAlarmItem = alarmList.firstOrNull()
}
}
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()) {
showEmptyView()
}
} 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,7 +54,7 @@ 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,21 @@ 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.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
@@ -258,6 +257,7 @@ 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()
} }
} }
@@ -265,11 +265,24 @@ class LinkedUserActivity : AppCompatActivity() {
e.printStackTrace() e.printStackTrace()
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
binding.swipeRefresh.isRefreshing = false binding.swipeRefresh.isRefreshing = false
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 +352,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,290 @@
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.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.launch
import androidx.lifecycle.lifecycleScope
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 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
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")
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() {
val videoUrl ="http://220.203.23.195:9090/live/test001.live.flv"
orientationUtils = OrientationUtils(this, binding.exoPlayContextId)
orientationUtils?.isEnable = true
GSYVideoOptionBuilder()
.setUrl(videoUrl)
.setCacheWithPlay(false)
.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)
hidePlayerControls()
binding.exoPlayContextId.startPlayLogic()
binding.exoPlayContextId.fullscreenButton.setOnClickListener {
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)
}
}
}
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()
} catch (e: Exception) {
hasMore = false
} finally {
isLoading = false
}
}
}
override fun onResume() {
super.onResume()
binding.exoPlayContextId.onVideoResume()
}
override fun onPause() {
super.onPause()
binding.exoPlayContextId.onVideoPause()
}
override fun onDestroy() {
super.onDestroy()
orientationUtils?.releaseListener()
binding.exoPlayContextId.release()
}
}

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,7 +74,7 @@ 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 ?: ""
@@ -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

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,8 @@ 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.databinding.FaceVerificationActivityBinding
import com.example.defenseapplication.view.FaceAnalyzer 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

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
@@ -63,7 +65,9 @@ class ForgetPasswordActivity : AppCompatActivity() {
} }
binding.btnNext.setOnClickListener { binding.btnNext.setOnClickListener {
performResetPassword() if (!isLoading) {
performResetPassword()
}
} }
} }
@@ -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
} }
@@ -163,8 +166,11 @@ class ForgetPasswordActivity : AppCompatActivity() {
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 +181,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 +194,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)
@@ -174,25 +170,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()
} }
@@ -202,6 +197,7 @@ class LoginActivity : AppCompatActivity() {
try { try {
val response = RetrofitNetwork.getNetworkService().getCode(phone) val response = RetrofitNetwork.getNetworkService().getCode(phone)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
Log.d("VerificationCode", "code = ${response.code}, msg = ${response.msg}")
if (response.code == 200) { if (response.code == 200) {
Toast.makeText(this@LoginActivity, getString(R.string.code_sent_to, phone), Toast.LENGTH_SHORT).show() Toast.makeText(this@LoginActivity, getString(R.string.code_sent_to, phone), Toast.LENGTH_SHORT).show()
startCountDown() startCountDown()
@@ -293,4 +289,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
@@ -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,8 +176,8 @@ 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()
@@ -190,8 +192,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

@@ -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

@@ -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 = ""
} }
} }
} }

View File

@@ -1,32 +1,36 @@
package com.example.defenseapplication.utils package com.ckkj.defense_device.utils
import android.R
import bean.ForgotRequest import bean.ForgotRequest
import com.example.defenseapplication.bean.DeviceBean import com.ckkj.defense_device.bean.DeviceBean
import com.example.defenseapplication.bean.DeviceUserBean import com.ckkj.defense_device.bean.DeviceUserBean
import com.example.defenseapplication.bean.FamilyBean import com.ckkj.defense_device.bean.FamilyBean
import com.example.defenseapplication.bean.GetCodeBean import com.ckkj.defense_device.bean.GetCodeBean
import bean.LoginBean import bean.LoginBean
import bean.LoginRequest import bean.LoginRequest
import bean.RegisterRequest import bean.RegisterRequest
import com.example.defenseapplication.bean.AddDeviceBean import com.ckkj.defense_device.bean.AddDeviceBean
import com.example.defenseapplication.bean.AddDeviceUserRequest import com.ckkj.defense_device.bean.AddDeviceUserRequest
import com.example.defenseapplication.bean.DeleteBean import com.ckkj.defense_device.bean.DeleteBean
import com.example.defenseapplication.bean.DeleteDeviceUserRequest import com.ckkj.defense_device.bean.DeleteDeviceUserRequest
import com.example.defenseapplication.bean.DeviceAlarmResponse import com.ckkj.defense_device.bean.DeviceAlarmResponse
import com.example.defenseapplication.bean.FamilyMembersBean import com.ckkj.defense_device.bean.FamilyMembersBean
import com.example.defenseapplication.bean.MessageBean import com.ckkj.defense_device.bean.InviterInfoBean
import com.example.defenseapplication.bean.MessageListResponse import com.ckkj.defense_device.bean.JoinTheFamilyBean
import com.example.defenseapplication.bean.ObtainInviterInformationBean import com.ckkj.defense_device.bean.MessageBean
import com.example.defenseapplication.bean.ObtainInviterInformationRequest import com.ckkj.defense_device.bean.MessageListResponse
import com.example.defenseapplication.bean.SwitchFamilyRequest import com.ckkj.defense_device.bean.ObtainInviterInformationBean
import com.example.defenseapplication.bean.UpdatePassword import com.ckkj.defense_device.bean.ObtainInviterInformationRequest
import com.example.defenseapplication.bean.UpdateUserInfo import com.ckkj.defense_device.bean.SelectInviterInfoBean
import com.example.defenseapplication.bean.UploadResponse import com.ckkj.defense_device.bean.SwitchFamilyRequest
import com.example.defenseapplication.bean.UserInfoBean import com.ckkj.defense_device.bean.UpdateFamilyUserRequest
import com.example.defenseapplication.bean.VerifyOptionPasswordRequest import com.ckkj.defense_device.bean.UpdatePassword
import com.ckkj.defense_device.bean.UpdateUserInfo
import com.ckkj.defense_device.bean.UploadResponse
import com.ckkj.defense_device.bean.UserInfoBean
import com.ckkj.defense_device.bean.VerifyOptionPasswordRequest
import okhttp3.MultipartBody import okhttp3.MultipartBody
import retrofit2.http.Body import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET import retrofit2.http.GET
import retrofit2.http.Multipart import retrofit2.http.Multipart
import retrofit2.http.POST import retrofit2.http.POST
@@ -191,7 +195,7 @@ interface ApiService {
/** /**
* 获取邀请人信息 * 获取家庭成员信息
*/ */
@POST("/app/obtainInviterInformation") @POST("/app/obtainInviterInformation")
suspend fun obtainInviterInformation(@Body request: ObtainInviterInformationRequest): GetCodeBean<ObtainInviterInformationBean> suspend fun obtainInviterInformation(@Body request: ObtainInviterInformationRequest): GetCodeBean<ObtainInviterInformationBean>
@@ -236,15 +240,36 @@ interface ApiService {
/** /**
* 查看告警消息 * 查看告警消息
*/ */
//@GET("/app/appMessageInfo/{id}") @GET("/app/appMessageInfo/{id}")
//suspend fun getMessageInfo(@retrofit2.http.Path("id") id: String): GetCodeBean<MessageBean> suspend fun getMessageInfo(@retrofit2.http.Path("id") id: String): GetCodeBean<MessageBean>
/**
* 删除告警消息
*/
@DELETE("/app/deleteMessage/{id}")
suspend fun deleteMessage(@retrofit2.http.Path("id") id: String): GetCodeBean<Any>
/** /**
* 修改家庭用户状态 * 修改家庭用户状态
*/ */
//@POST("/app/updateFamilyUser") @POST("/app/updateFamilyUser")
suspend fun updateFamilyUser(@Body request: UpdateFamilyUserRequest): GetCodeBean<Any>
/**
* 获取邀请人信息
*/
@POST("/app/selectInviterInfo")
suspend fun selectInviterInfo(@Body request: SelectInviterInfoBean): GetCodeBean<InviterInfoBean>
/**
* 加入xxx家庭
*/
@POST("/app/joinTheFamily")
suspend fun joinTheFamily(@Body request: JoinTheFamilyBean): GetCodeBean<Any>
} }

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.utils package com.ckkj.defense_device.utils
object DeviceIdEvent { object DeviceIdEvent {
private val listeners = mutableListOf<DeviceIdListener>() private val listeners = mutableListOf<DeviceIdListener>()

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.utils package com.ckkj.defense_device.utils
object DeviceUpdateEvent { object DeviceUpdateEvent {
private val listeners = mutableListOf<DeviceUpdateListener>() private val listeners = mutableListOf<DeviceUpdateListener>()

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.utils package com.ckkj.defense_device.utils
object DeviceUserUpdateEvent { object DeviceUserUpdateEvent {
private val listeners = mutableListOf<DeviceUserUpdateListener>() private val listeners = mutableListOf<DeviceUserUpdateListener>()

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.utils package com.ckkj.defense_device.utils
object FamilySwitchEvent { object FamilySwitchEvent {
private val listeners = mutableListOf<FamilySwitchListener>() private val listeners = mutableListOf<FamilySwitchListener>()

View File

@@ -1,6 +1,4 @@
package com.example.defenseapplication.utils package com.ckkj.defense_device.utils
import android.content.Context
/** /**
* HTTP 请求头的语言值管理统一由 LanguageUtil 提供 * HTTP 请求头的语言值管理统一由 LanguageUtil 提供

View File

@@ -1,8 +1,6 @@
package com.example.defenseapplication.utils package com.ckkj.defense_device.utils
import android.content.Context import android.content.Context
import android.content.SharedPreferences
import android.content.res.Configuration
import android.os.Build import android.os.Build
import android.os.LocaleList import android.os.LocaleList
import java.util.Locale import java.util.Locale

View File

@@ -1,7 +1,7 @@
package com.smart.data.repository package com.smart.data.repository
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
class MainRepository(val apiService: ApiService = RetrofitNetwork.getNetworkService()) { class MainRepository(val apiService: ApiService = RetrofitNetwork.getNetworkService()) {

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.utils package com.ckkj.defense_device.utils
object MessageStatusManager { object MessageStatusManager {
private var unreadCount = 0 private var unreadCount = 0

View File

@@ -1,4 +1,4 @@
package com.example.defenseapplication.utils package com.ckkj.defense_device.utils
import com.google.gson.Gson import com.google.gson.Gson
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@@ -13,6 +13,7 @@ object RetrofitNetwork {
private const val DEFAULT_TIMEOUT = 30L private const val DEFAULT_TIMEOUT = 30L
const val BASE_URL = "https://stem-boozy-margarine.ngrok-free.dev" const val BASE_URL = "https://stem-boozy-margarine.ngrok-free.dev"
//const val BASE_URL = "http://service.reinkun.com:8001"
private var retrofit: Retrofit? = null private var retrofit: Retrofit? = null
private val gson = Gson() private val gson = Gson()

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