diff --git a/.kotlin/errors/errors-1779069271079.log b/.kotlin/errors/errors-1779069271079.log
new file mode 100644
index 0000000..f4eaaba
--- /dev/null
+++ b/.kotlin/errors/errors-1779069271079.log
@@ -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-tsmarker6991050182705719677.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)
+
+
diff --git a/.kotlin/errors/errors-1779069271454.log b/.kotlin/errors/errors-1779069271454.log
new file mode 100644
index 0000000..851a6ce
--- /dev/null
+++ b/.kotlin/errors/errors-1779069271454.log
@@ -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-tsmarker12435304630805089217.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)
+
+
diff --git a/.kotlin/errors/errors-1779076156547.log b/.kotlin/errors/errors-1779076156547.log
new file mode 100644
index 0000000..06db542
--- /dev/null
+++ b/.kotlin/errors/errors-1779076156547.log
@@ -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-tsmarker2598867699647644462.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)
+
+
diff --git a/.kotlin/errors/errors-1779076431780.log b/.kotlin/errors/errors-1779076431780.log
new file mode 100644
index 0000000..191bdca
--- /dev/null
+++ b/.kotlin/errors/errors-1779076431780.log
@@ -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-tsmarker2855013762498601656.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)
+
+
diff --git a/.kotlin/errors/errors-1779076653885.log b/.kotlin/errors/errors-1779076653885.log
new file mode 100644
index 0000000..a999809
--- /dev/null
+++ b/.kotlin/errors/errors-1779076653885.log
@@ -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-tsmarker13008540186998185482.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)
+
+
diff --git a/.kotlin/errors/errors-1779076803949.log b/.kotlin/errors/errors-1779076803949.log
new file mode 100644
index 0000000..62ac2a4
--- /dev/null
+++ b/.kotlin/errors/errors-1779076803949.log
@@ -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-tsmarker11095554519114844963.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)
+
+
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index e8dbd07..d817e22 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -98,5 +98,7 @@ dependencies {
implementation("androidx.camera:camera-camera2:1.0.2")
implementation("androidx.camera:camera-lifecycle:1.0.2")
implementation("androidx.camera:camera-view:1.0.0-alpha25")
+ //上拉刷新下拉加载
+ implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 69a7842..ad93b4a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -8,6 +8,7 @@
+
diff --git a/app/src/main/java/com/example/defenseapplication/adapter/DeviceAdapter.kt b/app/src/main/java/com/example/defenseapplication/adapter/DeviceAdapter.kt
index a3d7bb2..38675c5 100644
--- a/app/src/main/java/com/example/defenseapplication/adapter/DeviceAdapter.kt
+++ b/app/src/main/java/com/example/defenseapplication/adapter/DeviceAdapter.kt
@@ -8,8 +8,12 @@ import com.example.defenseapplication.databinding.ItemDeviceBinding
data class DeviceUi(
val name: String,
+ val status: String,
+ val deviceId: String = ""
+) {
val isOnline: Boolean
-)
+ get() = status == "1"
+}
class DeviceAdapter(
private val onItemClick: (DeviceUi) -> Unit = {}
@@ -39,12 +43,27 @@ class DeviceAdapter(
fun bind(item: DeviceUi) {
binding.tvDeviceType.text = item.name
- if (item.isOnline) {
- binding.tvDeviceName.setTextColor(binding.root.context.getColor(R.color.green))
- binding.tvDeviceName.text = "\u25CF 正在运行"
- } else {
- binding.tvDeviceName.setTextColor(binding.root.context.getColor(R.color.red))
- binding.tvDeviceName.text = "\u25CF 离线"
+ when (item.status) {
+ "1" -> {
+ binding.tvDeviceName.setTextColor(binding.root.context.getColor(R.color.green))
+ binding.tvDeviceName.text = "\u25CF 在线"
+ }
+ "0" -> {
+ binding.tvDeviceName.setTextColor(binding.root.context.getColor(R.color.red))
+ binding.tvDeviceName.text = "\u25CF 离线"
+ }
+ "2" -> {
+ binding.tvDeviceName.setTextColor(binding.root.context.getColor(R.color.orange))
+ binding.tvDeviceName.text = "\u25CF 故障"
+ }
+ "3" -> {
+ binding.tvDeviceName.setTextColor(binding.root.context.getColor(R.color.gray))
+ binding.tvDeviceName.text = "\u25CF 到期"
+ }
+ else -> {
+ binding.tvDeviceName.setTextColor(binding.root.context.getColor(R.color.gray))
+ binding.tvDeviceName.text = "\u25CF 未知"
+ }
}
binding.root.setOnClickListener {
onItemClick(item)
diff --git a/app/src/main/java/com/example/defenseapplication/base/BaseActivity.kt b/app/src/main/java/com/example/defenseapplication/base/BaseActivity.kt
index aba4456..590076c 100644
--- a/app/src/main/java/com/example/defenseapplication/base/BaseActivity.kt
+++ b/app/src/main/java/com/example/defenseapplication/base/BaseActivity.kt
@@ -1,38 +1,18 @@
package com.example.defenseapplication.base
-import android.content.Context
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
-import com.example.defenseapplication.utils.LanguageUtil
+import com.example.defenseapplication.utils.ActivityManager
-/**
- * 支持语言切换的 Activity 基类
- * 所有需要支持多语言的 Activity 都应该继承此类
- */
-abstract class BaseActivity : AppCompatActivity() {
-
- override fun attachBaseContext(newBase: Context) {
- // 在 Activity 创建前应用语言设置
- val context = LanguageUtil.attachBaseContext(newBase)
- super.attachBaseContext(context)
- }
+open class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- // 确保语言设置被应用
- LanguageUtil.updateResources(this)
+ ActivityManager.addActivity(this)
}
- /**
- * 切换语言
- * 调用后会重新创建 Activity 以应用新语言
- */
- protected fun switchLanguage(language: String) {
- val currentLang = LanguageUtil.getCurrentLanguage(this)
- if (currentLang != language) {
- LanguageUtil.switchLanguage(this, language)
- // 重新创建 Activity 以应用新语言
- recreate()
- }
+ override fun onDestroy() {
+ super.onDestroy()
+ ActivityManager.removeActivity(this)
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/defenseapplication/home/AddDeviceActivity.kt b/app/src/main/java/com/example/defenseapplication/home/AddDeviceActivity.kt
index 997ffd1..aecc6a4 100644
--- a/app/src/main/java/com/example/defenseapplication/home/AddDeviceActivity.kt
+++ b/app/src/main/java/com/example/defenseapplication/home/AddDeviceActivity.kt
@@ -1,18 +1,26 @@
package com.example.defenseapplication.home
+import android.Manifest
+import android.app.Activity
import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.View
import android.widget.Toast
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.GridLayoutManager
import com.example.defenseapplication.R
import com.example.defenseapplication.adapter.AddDeviceAdapter
import com.example.defenseapplication.adapter.Device
import com.example.defenseapplication.databinding.AddDeviceActivityBinding
import com.gyf.immersionbar.ImmersionBar
+import com.maning.mlkitscanner.scan.MNScanManager
+import com.maning.mlkitscanner.scan.callback.act.MNScanCallback
//添加设备页面
class AddDeviceActivity : AppCompatActivity() {
@@ -20,6 +28,86 @@ class AddDeviceActivity : AppCompatActivity() {
private lateinit var binding: AddDeviceActivityBinding
private lateinit var adapter: AddDeviceAdapter
private val mainHandler = Handler(Looper.getMainLooper())
+
+ 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()
+ }
+ }
+
+ 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()) {
+ ToastUtils.showToast(this@AddDeviceActivity, "扫码成功: $result")
+ } else {
+ ToastUtils.showToast(this@AddDeviceActivity, "扫码结果为空")
+ }
+ }
+ MNScanManager.RESULT_FAIL -> {
+ val error = data?.getStringExtra(MNScanManager.INTENT_KEY_RESULT_ERROR)
+ ToastUtils.showToast(this@AddDeviceActivity, "扫码失败: $error")
+ }
+ MNScanManager.RESULT_CANCLE -> {
+ ToastUtils.showToast(this@AddDeviceActivity, "扫码取消")
+ }
+ }
+ }
+ })
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = AddDeviceActivityBinding.inflate(layoutInflater)
@@ -32,6 +120,10 @@ class AddDeviceActivity : AppCompatActivity() {
finish()
}
+ binding.btnScanAdd.setOnClickListener {
+ checkPermissionsAndScan()
+ }
+
// 开始播放扫描动画,动画结束后再显示设备列表
startScanAnimationThenShowList()
}
diff --git a/app/src/main/java/com/example/defenseapplication/home/AddFamilyActivity.kt b/app/src/main/java/com/example/defenseapplication/home/AddFamilyActivity.kt
index f3cf3f0..853ddab 100644
--- a/app/src/main/java/com/example/defenseapplication/home/AddFamilyActivity.kt
+++ b/app/src/main/java/com/example/defenseapplication/home/AddFamilyActivity.kt
@@ -6,15 +6,23 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
+import android.net.ConnectivityManager
+import android.net.Network
+import android.net.NetworkCapabilities
+import android.net.NetworkRequest
import android.net.wifi.ScanResult
+import android.net.wifi.WifiConfiguration
import android.net.wifi.WifiManager
import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
import android.text.Editable
import android.text.TextWatcher
import android.view.Gravity
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.PopupWindow
+import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.recyclerview.widget.LinearLayoutManager
@@ -29,8 +37,13 @@ class AddFamilyActivity : AppCompatActivity() {
private lateinit var binding: AddFamilyActivityBinding
private lateinit var wifiManager: WifiManager
+ private lateinit var connectivityManager: ConnectivityManager
private lateinit var wifiScanReceiver: BroadcastReceiver
private var popupWindow: PopupWindow? = null
+ private val handler = Handler(Looper.getMainLooper())
+ private var isConnecting = false
+ private var targetWifiName: String = ""
+ private var networkCallback: ConnectivityManager.NetworkCallback? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -58,6 +71,7 @@ class AddFamilyActivity : AppCompatActivity() {
}
})
wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
+ connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
wifiScanReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
@@ -68,11 +82,161 @@ class AddFamilyActivity : AppCompatActivity() {
}
}
binding.btnConfirm.setOnClickListener {
- val intent=Intent(this, ConnectDeviceActivity::class.java)
- startActivity( intent)
+ //startActivity(Intent(this, ConnectDeviceActivity::class.java))
+ if (isConnecting) {
+ return@setOnClickListener
+ }
+
+ val wifiName = binding.etWifiName.text.toString().trim()
+ val wifiPassword = binding.etWifiPassword.text.toString()
+
+ if (wifiName.isEmpty()) {
+ Toast.makeText(this, R.string.enter_wifi_name, Toast.LENGTH_SHORT).show()
+ return@setOnClickListener
+ }
+
+ if (wifiPassword.isEmpty()) {
+ Toast.makeText(this, R.string.enter_wifi_password, Toast.LENGTH_SHORT).show()
+ return@setOnClickListener
+ }
+
+ isConnecting = true
+ binding.btnConfirm.isEnabled = false
+
+ verifyWifiPassword(wifiName, wifiPassword)
}
}
+ private fun verifyWifiPassword(wifiName: String, wifiPassword: String) {
+ if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
+ != PackageManager.PERMISSION_GRANTED ||
+ ActivityCompat.checkSelfPermission(this, Manifest.permission.CHANGE_WIFI_STATE)
+ != PackageManager.PERMISSION_GRANTED ||
+ ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_NETWORK_STATE)
+ != PackageManager.PERMISSION_GRANTED) {
+ ActivityCompat.requestPermissions(this,
+ arrayOf(Manifest.permission.ACCESS_FINE_LOCATION,
+ Manifest.permission.CHANGE_WIFI_STATE,
+ Manifest.permission.ACCESS_NETWORK_STATE),
+ 1002)
+ return
+ }
+
+ targetWifiName = wifiName
+
+ if (!wifiManager.isWifiEnabled) {
+ wifiManager.isWifiEnabled = true
+ }
+
+ val existingConfig = findExistingWifiConfig(wifiName)
+ var netId: Int
+
+ if (existingConfig != null) {
+ netId = existingConfig.networkId
+ existingConfig.preSharedKey = "\"$wifiPassword\""
+ wifiManager.updateNetwork(existingConfig)
+ } else {
+ val wifiConfig = createWifiConfig(wifiName, wifiPassword)
+ netId = wifiManager.addNetwork(wifiConfig)
+ }
+
+ if (netId == -1) {
+ isConnecting = false
+ binding.btnConfirm.isEnabled = true
+ ToastUtils.showError(this, getString(R.string.wifi_connection_failed))
+ return
+ }
+
+ networkCallback = object : ConnectivityManager.NetworkCallback() {
+ override fun onAvailable(network: Network) {
+ super.onAvailable(network)
+ checkWifiConnected()
+ }
+
+ override fun onCapabilitiesChanged(network: Network, capabilities: NetworkCapabilities) {
+ super.onCapabilitiesChanged(network, capabilities)
+ if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+ checkWifiConnected()
+ }
+ }
+ }
+
+ val request = NetworkRequest.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .build()
+
+ connectivityManager.registerNetworkCallback(request, networkCallback!!)
+
+ wifiManager.enableNetwork(netId, true)
+ wifiManager.saveConfiguration()
+
+ handler.postDelayed({
+ if (isConnecting) {
+ isConnecting = false
+ binding.btnConfirm.isEnabled = true
+ networkCallback?.let {
+ try {
+ connectivityManager.unregisterNetworkCallback(it)
+ } catch (e: Exception) {
+ }
+ }
+ networkCallback = null
+ ToastUtils.showError(this, getString(R.string.wifi_connection_failed))
+ }
+ }, 15000)
+ }
+
+ private fun findExistingWifiConfig(wifiName: String): WifiConfiguration? {
+ if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
+ != PackageManager.PERMISSION_GRANTED) {
+ return null
+ }
+ val configuredNetworks = wifiManager.configuredNetworks
+ configuredNetworks?.forEach { config ->
+ if (config.SSID == "\"$wifiName\"") {
+ return config
+ }
+ }
+ return null
+ }
+
+ private fun checkWifiConnected() {
+ if (!isConnecting) return
+
+ val info = wifiManager.connectionInfo
+ if (info.ssid == "\"$targetWifiName\"" && info.networkId != -1) {
+ isConnecting = false
+ binding.btnConfirm.isEnabled = true
+ networkCallback?.let {
+ try {
+ connectivityManager.unregisterNetworkCallback(it)
+ } catch (e: Exception) {
+ }
+ }
+ networkCallback = null
+ runOnUiThread {
+ ToastUtils.showSuccess(this@AddFamilyActivity, getString(R.string.wifi_connection_success))
+ val intent = Intent(this@AddFamilyActivity, ConnectDeviceActivity::class.java)
+ intent.putExtra("wifi_name", targetWifiName)
+ startActivity(intent)
+ }
+ }
+ }
+
+ private fun createWifiConfig(ssid: String, password: String): WifiConfiguration {
+ val config = WifiConfiguration()
+ config.SSID = "\"$ssid\""
+ config.preSharedKey = "\"$password\""
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK)
+ config.allowedProtocols.set(WifiConfiguration.Protocol.RSN)
+ config.allowedProtocols.set(WifiConfiguration.Protocol.WPA)
+ config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP)
+ config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP)
+ config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP)
+ config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP)
+ return config
+ }
+
private fun showWifiListDialog() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED ||
@@ -151,5 +315,34 @@ class AddFamilyActivity : AppCompatActivity() {
super.onStop()
unregisterReceiver(wifiScanReceiver)
popupWindow?.dismiss()
+ networkCallback?.let {
+ try {
+ connectivityManager.unregisterNetworkCallback(it)
+ } catch (e: Exception) {
+ }
+ }
+ networkCallback = null
+ handler.removeCallbacksAndMessages(null)
+ }
+
+ override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ when (requestCode) {
+ 1002 -> {
+ if (grantResults.isNotEmpty() &&
+ grantResults.size >= 3 &&
+ grantResults[0] == PackageManager.PERMISSION_GRANTED &&
+ grantResults[1] == PackageManager.PERMISSION_GRANTED &&
+ grantResults[2] == PackageManager.PERMISSION_GRANTED) {
+ val wifiName = binding.etWifiName.text.toString().trim()
+ val wifiPassword = binding.etWifiPassword.text.toString()
+ verifyWifiPassword(wifiName, wifiPassword)
+ } else {
+ isConnecting = false
+ binding.btnConfirm.isEnabled = true
+ Toast.makeText(this, R.string.permission_denied, Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/defenseapplication/home/HomeMenuFragment.kt b/app/src/main/java/com/example/defenseapplication/home/HomeMenuFragment.kt
index f8f5b8d..eef8b17 100644
--- a/app/src/main/java/com/example/defenseapplication/home/HomeMenuFragment.kt
+++ b/app/src/main/java/com/example/defenseapplication/home/HomeMenuFragment.kt
@@ -29,6 +29,7 @@ import com.example.defenseapplication.bean.DeviceBean
import com.example.defenseapplication.bean.FamilyBean
import com.example.defenseapplication.bean.SwitchFamilyRequest
import com.example.defenseapplication.databinding.HomeMenuFragmentBinding
+import com.example.defenseapplication.utils.DeviceIdEvent
import com.example.defenseapplication.utils.FamilySwitchEvent
import com.example.defenseapplication.utils.MessageStatusManager
import com.example.defenseapplication.utils.RetrofitNetwork
@@ -52,6 +53,10 @@ class HomeMenuFragment : Fragment() {
private var isFamilyExpanded = false
private lateinit var currentFamily: String
+ private var currentPage = 1
+ private val pageSize = 10
+ private var hasMore = true
+ private var isLoading = false
private val requestPermissionsLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
@@ -222,6 +227,23 @@ class HomeMenuFragment : Fragment() {
)
}
+ binding.swipeRefreshLayout.setOnRefreshListener {
+ refreshDeviceList()
+ }
+
+ binding.rvDeviceList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
+ override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
+ super.onScrolled(recyclerView, dx, dy)
+ val layoutManager = recyclerView.layoutManager as GridLayoutManager
+ val lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition()
+ val totalItemCount = layoutManager.itemCount
+
+ if (!isLoading && hasMore && lastVisibleItemPosition >= totalItemCount - 1 && dy > 0) {
+ loadMoreDevices()
+ }
+ }
+ })
+
binding.familyHeaderLayout.setOnClickListener {
toggleFamilyList()
}
@@ -349,8 +371,10 @@ class HomeMenuFragment : Fragment() {
}
}
- private fun fetchDeviceList() {
- if (!canViewDevice) return
+ private fun fetchDeviceList(page: Int = 1, isLoadMore: Boolean = false) {
+ if (!canViewDevice || isLoading) return
+
+ isLoading = true
CoroutineScope(Dispatchers.IO).launch {
try {
@@ -358,21 +382,49 @@ class HomeMenuFragment : Fragment() {
withContext(Dispatchers.Main) {
Log.d("DeviceList", "code = ${response.code}, data = ${response.data}")
if (response.code == 200 && response.data != null) {
- deviceBeanList = response.data
+ val newDevices = response.data
+ if (isLoadMore) {
+ deviceBeanList = deviceBeanList + newDevices
+ hasMore = newDevices.size >= pageSize
+ } else {
+ deviceBeanList = newDevices
+ hasMore = newDevices.size >= pageSize
+ }
Log.d("DeviceList", "deviceBeanList size = ${deviceBeanList.size}")
updateDeviceList()
} else {
Toast.makeText(requireContext(), response.msg, Toast.LENGTH_SHORT).show()
+ if (isLoadMore) {
+ hasMore = false
+ }
}
+ isLoading = false
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
Toast.makeText(requireContext(), R.string.network_error, Toast.LENGTH_SHORT).show()
+ isLoading = false
+ if (isLoadMore) {
+ hasMore = false
+ }
}
}
}
}
+ private fun refreshDeviceList() {
+ currentPage = 1
+ hasMore = true
+ fetchDeviceList(currentPage, false)
+ binding.swipeRefreshLayout.isRefreshing = false
+ }
+
+ private fun loadMoreDevices() {
+ if (isLoading || !hasMore) return
+ currentPage++
+ fetchDeviceList(currentPage, true)
+ }
+
private fun toggleFamilyList() {
isFamilyExpanded = !isFamilyExpanded
val visibility = if (isFamilyExpanded) View.VISIBLE else View.GONE
@@ -396,12 +448,12 @@ class HomeMenuFragment : Fragment() {
private fun updateDeviceList() {
val deviceUiList = deviceBeanList.map {
- DeviceUi(it.deviceName, it.status == "0")
+ DeviceUi(it.deviceName, it.status, it.id)
}
if (deviceUiList.isEmpty()) {
deviceAdapter.submitList(listOf(
- DeviceUi(getString(R.string.no_device), false)
+ DeviceUi(getString(R.string.no_device), "0")
))
} else {
deviceAdapter.submitList(deviceUiList)
@@ -409,10 +461,16 @@ class HomeMenuFragment : Fragment() {
}
private fun onDeviceClicked(device: DeviceUi) {
- if (device.isOnline) return
- showDefenseDialog(
- config = DefenseDialogs.deviceOfflineConfig(requireContext())
- )
+ if (device.isOnline) {
+ DeviceIdEvent.setDeviceId(device.deviceId)
+ val intent = Intent(requireContext(), com.example.defenseapplication.liveVideo.LiveVideoActivity::class.java)
+ intent.putExtra("device_name", device.name)
+ startActivity(intent)
+ } else {
+ showDefenseDialog(
+ config = DefenseDialogs.deviceOfflineConfig(requireContext())
+ )
+ }
}
private fun dpToPx(dp: Int): Int {
diff --git a/app/src/main/java/com/example/defenseapplication/liveVideo/DeviceInfoActivity.kt b/app/src/main/java/com/example/defenseapplication/liveVideo/DeviceInfoActivity.kt
index ef7b449..9ca8d62 100644
--- a/app/src/main/java/com/example/defenseapplication/liveVideo/DeviceInfoActivity.kt
+++ b/app/src/main/java/com/example/defenseapplication/liveVideo/DeviceInfoActivity.kt
@@ -1,14 +1,17 @@
package com.example.defenseapplication.liveVideo
import android.os.Bundle
-import androidx.activity.enableEdgeToEdge
+import android.widget.TextView
+import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
-import androidx.core.view.ViewCompat
-import androidx.core.view.WindowInsetsCompat
-import com.example.defenseapplication.R
-import com.example.defenseapplication.databinding.AlarmLogActivityBinding
import com.example.defenseapplication.databinding.DeviceInfoActivityBinding
+import com.example.defenseapplication.utils.DeviceIdEvent
+import com.example.defenseapplication.utils.RetrofitNetwork
import com.gyf.immersionbar.ImmersionBar
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
//设备信息
class DeviceInfoActivity : AppCompatActivity() {
private lateinit var binding: DeviceInfoActivityBinding
@@ -23,5 +26,38 @@ class DeviceInfoActivity : AppCompatActivity() {
binding.ivBack.setOnClickListener {
finish()
}
+ fetchDeviceInfo()
+ }
+
+ private fun fetchDeviceInfo() {
+ val deviceId = DeviceIdEvent.getDeviceId()
+ if (deviceId.isNullOrEmpty()) {
+ Toast.makeText(this, "设备ID为空", Toast.LENGTH_SHORT).show()
+ return
+ }
+
+ CoroutineScope(Dispatchers.IO).launch {
+ try {
+ val response = RetrofitNetwork.getNetworkService().getDeviceInfo(deviceId)
+ withContext(Dispatchers.Main) {
+ if (response.code == 200 && response.data != null) {
+ updateDeviceInfo(response.data)
+ } else {
+ Toast.makeText(this@DeviceInfoActivity, response.msg, Toast.LENGTH_SHORT).show()
+ }
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ withContext(Dispatchers.Main) {
+ Toast.makeText(this@DeviceInfoActivity, "网络请求失败", Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+ }
+
+ private fun updateDeviceInfo(device: com.example.defenseapplication.bean.DeviceBean) {
+ binding.tvDeviceModelValue.text = device.deviceNo.toString() ?: "未知型号"
+ binding.tvDeviceNoValue.text = device.startTime.toString() ?: "自动布防开始时间"
+ binding.tvFwVersionValue.text = device.endTime.toString() ?: "自动布防结束时间"
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/defenseapplication/liveVideo/LiveVideoActivity.kt b/app/src/main/java/com/example/defenseapplication/liveVideo/LiveVideoActivity.kt
index 3b42226..aa67c87 100644
--- a/app/src/main/java/com/example/defenseapplication/liveVideo/LiveVideoActivity.kt
+++ b/app/src/main/java/com/example/defenseapplication/liveVideo/LiveVideoActivity.kt
@@ -21,11 +21,12 @@ import android.view.animation.ScaleAnimation
import android.widget.Toast
import androidx.activity.OnBackPressedDispatcher
import androidx.activity.result.contract.ActivityResultContracts
-import androidx.appcompat.app.AppCompatActivity
-import androidx.compose.ui.test.isEnabled
import androidx.core.content.ContextCompat
import com.example.defenseapplication.R
+import com.example.defenseapplication.base.BaseActivity
import com.example.defenseapplication.databinding.LiveVideoActivityBinding
+import com.example.defenseapplication.utils.ActivityManager
+import com.example.defenseapplication.utils.DeviceIdEvent
import com.gyf.immersionbar.ImmersionBar
import com.gyf.immersionbar.ktx.destroyImmersionBar
import java.io.File
@@ -33,7 +34,7 @@ import java.io.IOException
private const val TAG = "LiveVideoActivity"
//智能防御机A1
-class LiveVideoActivity : AppCompatActivity(), SurfaceHolder.Callback {
+class LiveVideoActivity : BaseActivity(), SurfaceHolder.Callback {
private lateinit var binding: LiveVideoActivityBinding
private var mediaPlayer: MediaPlayer? = null
@@ -72,6 +73,11 @@ class LiveVideoActivity : AppCompatActivity(), SurfaceHolder.Callback {
.titleBar(binding.topBar)
.init()
+ val deviceName = intent.getStringExtra("device_name")
+ if (!deviceName.isNullOrEmpty()) {
+ binding.tvTitle.text = deviceName
+ }
+
initSurfaceView()
initListener()
}
@@ -163,6 +169,10 @@ class LiveVideoActivity : AppCompatActivity(), SurfaceHolder.Callback {
private fun initListener() {
binding.btnBack.setOnClickListener {
+ ActivityManager.finishExceptHome()
+ val intent = Intent(this, com.example.defenseapplication.home.HomeActivity::class.java)
+ intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
+ startActivity(intent)
finish()
}
diff --git a/app/src/main/java/com/example/defenseapplication/utils/ActivityManager.kt b/app/src/main/java/com/example/defenseapplication/utils/ActivityManager.kt
new file mode 100644
index 0000000..13e501c
--- /dev/null
+++ b/app/src/main/java/com/example/defenseapplication/utils/ActivityManager.kt
@@ -0,0 +1,92 @@
+package com.example.defenseapplication.utils
+
+import android.app.Activity
+import java.lang.ref.WeakReference
+import java.util.Stack
+
+object ActivityManager {
+ private val activityStack = Stack>()
+
+ fun addActivity(activity: Activity) {
+ activityStack.push(WeakReference(activity))
+ }
+
+ fun removeActivity(activity: Activity) {
+ activityStack.removeIf { it.get() == activity }
+ }
+
+ fun finishActivity(activity: Activity) {
+ activity.finish()
+ removeActivity(activity)
+ }
+
+ fun finishAllActivities() {
+ while (activityStack.isNotEmpty()) {
+ val activityRef = activityStack.pop()
+ activityRef.get()?.finish()
+ }
+ activityStack.clear()
+ }
+
+ fun finishToActivity(cls: Class<*>) {
+ val tempStack = Stack>()
+
+ while (activityStack.isNotEmpty()) {
+ val activityRef = activityStack.pop()
+ val activity = activityRef.get()
+
+ if (activity != null && activity.javaClass == cls) {
+ tempStack.push(activityRef)
+ break
+ } else if (activity != null) {
+ activity.finish()
+ }
+ }
+
+ while (tempStack.isNotEmpty()) {
+ activityStack.push(tempStack.pop())
+ }
+ }
+
+ fun finishExceptHome() {
+ val tempStack = Stack>()
+ var foundHome = false
+
+ while (activityStack.isNotEmpty()) {
+ val activityRef = activityStack.pop()
+ val activity = activityRef.get()
+
+ if (activity != null) {
+ val className = activity.javaClass.simpleName
+ if (className == "HomeActivity" || className == "MainActivity") {
+ tempStack.push(activityRef)
+ foundHome = true
+ break
+ } else {
+ activity.finish()
+ }
+ }
+ }
+
+ if (!foundHome) {
+ while (tempStack.isNotEmpty()) {
+ activityStack.push(tempStack.pop())
+ }
+ } else {
+ while (tempStack.isNotEmpty()) {
+ activityStack.push(tempStack.pop())
+ }
+ }
+ }
+
+ fun getCurrentActivity(): Activity? {
+ if (activityStack.isEmpty()) {
+ return null
+ }
+ return activityStack.peek().get()
+ }
+
+ fun getActivityCount(): Int {
+ return activityStack.size
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/defenseapplication/utils/ApiService.kt b/app/src/main/java/com/example/defenseapplication/utils/ApiService.kt
index 51dd9e4..a632e1b 100644
--- a/app/src/main/java/com/example/defenseapplication/utils/ApiService.kt
+++ b/app/src/main/java/com/example/defenseapplication/utils/ApiService.kt
@@ -62,6 +62,19 @@ interface ApiService {
@GET("/app/appMessage/list")
suspend fun getMessage(): GetCodeBean>
+ /**
+ * 获取设备信息
+ */
+ @PUT("/app/updateDeviceInfo")
+ suspend fun updateDeviceInfo(@Body deviceBean: DeviceBean): GetCodeBean
+
+
+ /**
+ * 获取设备信息
+ */
+ @GET("/app/deviceInfo/{id}")
+ suspend fun getDeviceInfo(@retrofit2.http.Path("id") id: String): GetCodeBean
+
}
diff --git a/app/src/main/java/com/example/defenseapplication/utils/DeviceIdEvent.kt b/app/src/main/java/com/example/defenseapplication/utils/DeviceIdEvent.kt
new file mode 100644
index 0000000..a75affe
--- /dev/null
+++ b/app/src/main/java/com/example/defenseapplication/utils/DeviceIdEvent.kt
@@ -0,0 +1,30 @@
+package com.example.defenseapplication.utils
+
+object DeviceIdEvent {
+ private val listeners = mutableListOf()
+ private var currentDeviceId: String? = null
+
+ interface DeviceIdListener {
+ fun onDeviceIdChanged(deviceId: String)
+ }
+
+ fun addListener(listener: DeviceIdListener) {
+ if (!listeners.contains(listener)) {
+ listeners.add(listener)
+ currentDeviceId?.let { listener.onDeviceIdChanged(it) }
+ }
+ }
+
+ fun removeListener(listener: DeviceIdListener) {
+ listeners.remove(listener)
+ }
+
+ fun setDeviceId(deviceId: String) {
+ currentDeviceId = deviceId
+ listeners.forEach { it.onDeviceIdChanged(deviceId) }
+ }
+
+ fun getDeviceId(): String? {
+ return currentDeviceId
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/device_info_activity.xml b/app/src/main/res/layout/device_info_activity.xml
index 8fa76d8..b77c877 100644
--- a/app/src/main/res/layout/device_info_activity.xml
+++ b/app/src/main/res/layout/device_info_activity.xml
@@ -45,6 +45,7 @@
android:textSize="14dp"/>
-
+ android:layout_weight="1">
+
+
+
快来加入我!扫码下载APP
分享至
暂无可用分享应用
+ 设备编号
+ 固件版本
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index cb2f24f..0488174 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -19,5 +19,6 @@
#111111
#E8F7F7
#E5E5E5
+ #FF9800
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a4f4a6f..1c5df6e 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -188,6 +188,8 @@
Enter warning voice content, system will generate voice automatically.
Device info
Device model
+ Device No
+ FW Version
Auto arm start time
Auto arm End time
Please select at least one user