diff --git a/android/.kotlin/errors/errors-1772609249618.log b/android/.kotlin/errors/errors-1772609249618.log new file mode 100644 index 00000000..946871c4 --- /dev/null +++ b/android/.kotlin/errors/errors-1772609249618.log @@ -0,0 +1,220 @@ +kotlin version: 2.2.20 +error message: Daemon compilation failed: null +java.lang.Exception + at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:69) + at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:65) + at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:240) + 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:63) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:66) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:62) + at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:100) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:62) + 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:210) + at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54) + at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:59) + at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:174) + at java.base/java.util.concurrent.FutureTask.run(Unknown Source) + 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:31) + at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:263) + 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(Unknown Source) + at java.base/java.util.concurrent.FutureTask.run(Unknown Source) + at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) + at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:48) + at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) + at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) + at java.base/java.lang.Thread.run(Unknown Source) +Caused by: java.lang.AssertionError: java.lang.Exception: Could not close incremental caches in D:\code\FlutterApp\build\mobile_scanner\kotlin\compileDebugKotlin\cacheable\caches-jvm\jvm\kotlin: class-fq-name-to-source.tab, source-to-typealias-fq-name.tab, source-to-classes.tab, internal-name-to-source.tab + at org.jetbrains.kotlin.com.google.common.io.Closer.close(Closer.java:218) + at org.jetbrains.kotlin.incremental.IncrementalCachesManager.close(IncrementalCachesManager.kt:55) + at kotlin.io.CloseableKt.closeFinally(Closeable.kt:46) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:293) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:128) + at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:684) + at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:94) + at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1810) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source) + at java.base/java.lang.reflect.Method.invoke(Unknown Source) + at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(Unknown Source) + at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source) + at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source) + at java.base/java.security.AccessController.doPrivileged(Unknown Source) + at java.rmi/sun.rmi.transport.Transport.serviceCall(Unknown Source) + at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source) + at java.base/java.security.AccessController.doPrivileged(Unknown Source) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source) + ... 3 more +Caused by: java.lang.Exception: Could not close incremental caches in D:\code\FlutterApp\build\mobile_scanner\kotlin\compileDebugKotlin\cacheable\caches-jvm\jvm\kotlin: class-fq-name-to-source.tab, source-to-typealias-fq-name.tab, source-to-classes.tab, internal-name-to-source.tab + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:95) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.close(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.com.google.common.io.Closer.close(Closer.java:205) + ... 22 more + Suppressed: java.lang.IllegalArgumentException: this and base files have different roots: C:\Users\15563\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\mobile_scanner-3.5.7\android\src\main\kotlin\dev\steenbakker\mobile_scanner\BarcodeHandler.kt and D:\code\FlutterApp\android. + at kotlin.io.FilesKt__UtilsKt.toRelativeString(Utils.kt:117) + at kotlin.io.FilesKt__UtilsKt.relativeTo(Utils.kt:128) + at org.jetbrains.kotlin.incremental.storage.RelocatableFileToPathConverter.toPath(RelocatableFileToPathConverter.kt:24) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.save(FileToPathConverter.kt:33) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.save(FileToPathConverter.kt:30) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.doPut(PersistentMapImpl.java:447) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.put(PersistentMapImpl.java:426) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.put(PersistentHashMap.java:106) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136) + at org.jetbrains.kotlin.incremental.storage.PersistentStorageWrapper.close(PersistentStorage.kt:124) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87) + ... 24 more + Suppressed: java.lang.IllegalArgumentException: this and base files have different roots: C:\Users\15563\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\mobile_scanner-3.5.7\android\src\main\kotlin\dev\steenbakker\mobile_scanner\MobileScannerCallbacks.kt and D:\code\FlutterApp\android. + at kotlin.io.FilesKt__UtilsKt.toRelativeString(Utils.kt:117) + at kotlin.io.FilesKt__UtilsKt.relativeTo(Utils.kt:128) + at org.jetbrains.kotlin.incremental.storage.RelocatableFileToPathConverter.toPath(RelocatableFileToPathConverter.kt:24) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.getHashCode(FileToPathConverter.kt:50) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.getHashCode(FileToPathConverter.kt:30) + at org.jetbrains.kotlin.com.intellij.util.containers.LinkedCustomHashMap.hashKey(LinkedCustomHashMap.java:109) + at org.jetbrains.kotlin.com.intellij.util.containers.LinkedCustomHashMap.remove(LinkedCustomHashMap.java:153) + at org.jetbrains.kotlin.com.intellij.util.containers.SLRUMap.remove(SLRUMap.java:89) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.flushAppendCache(PersistentMapImpl.java:1007) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.doPut(PersistentMapImpl.java:455) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.put(PersistentMapImpl.java:426) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.put(PersistentHashMap.java:106) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108) + at org.jetbrains.kotlin.incremental.storage.AppendableInMemoryStorage.applyChanges(InMemoryStorage.kt:179) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136) + at org.jetbrains.kotlin.incremental.AbstractIncrementalCache$SourceToTypealiasFqNameTwoWayMap.close(AbstractIncrementalCache.kt:297) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87) + ... 24 more + Suppressed: java.lang.IllegalArgumentException: this and base files have different roots: C:\Users\15563\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\mobile_scanner-3.5.7\android\src\main\kotlin\dev\steenbakker\mobile_scanner\BarcodeHandler.kt and D:\code\FlutterApp\android. + at kotlin.io.FilesKt__UtilsKt.toRelativeString(Utils.kt:117) + at kotlin.io.FilesKt__UtilsKt.relativeTo(Utils.kt:128) + at org.jetbrains.kotlin.incremental.storage.RelocatableFileToPathConverter.toPath(RelocatableFileToPathConverter.kt:24) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.getHashCode(FileToPathConverter.kt:50) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.getHashCode(FileToPathConverter.kt:30) + at org.jetbrains.kotlin.com.intellij.util.containers.LinkedCustomHashMap.hashKey(LinkedCustomHashMap.java:109) + at org.jetbrains.kotlin.com.intellij.util.containers.LinkedCustomHashMap.remove(LinkedCustomHashMap.java:153) + at org.jetbrains.kotlin.com.intellij.util.containers.SLRUMap.remove(SLRUMap.java:89) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.flushAppendCache(PersistentMapImpl.java:1007) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.doPut(PersistentMapImpl.java:455) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.put(PersistentMapImpl.java:426) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.put(PersistentHashMap.java:106) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108) + at org.jetbrains.kotlin.incremental.storage.AppendableInMemoryStorage.applyChanges(InMemoryStorage.kt:179) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136) + at org.jetbrains.kotlin.incremental.storage.AppendableSetBasicMap.close(BasicMap.kt:157) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87) + ... 24 more + Suppressed: java.lang.IllegalArgumentException: this and base files have different roots: C:\Users\15563\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\mobile_scanner-3.5.7\android\src\main\kotlin\dev\steenbakker\mobile_scanner\BarcodeHandler.kt and D:\code\FlutterApp\android. + at kotlin.io.FilesKt__UtilsKt.toRelativeString(Utils.kt:117) + at kotlin.io.FilesKt__UtilsKt.relativeTo(Utils.kt:128) + at org.jetbrains.kotlin.incremental.storage.RelocatableFileToPathConverter.toPath(RelocatableFileToPathConverter.kt:24) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.save(FileToPathConverter.kt:33) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.save(FileToPathConverter.kt:30) + at org.jetbrains.kotlin.incremental.storage.AppendableCollectionExternalizer.save(LazyStorage.kt:151) + at org.jetbrains.kotlin.incremental.storage.AppendableCollectionExternalizer.save(LazyStorage.kt:142) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.doPut(PersistentMapImpl.java:447) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.put(PersistentMapImpl.java:426) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.put(PersistentHashMap.java:106) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108) + at org.jetbrains.kotlin.incremental.storage.AppendableInMemoryStorage.applyChanges(InMemoryStorage.kt:179) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136) + at org.jetbrains.kotlin.incremental.storage.PersistentStorageWrapper.close(PersistentStorage.kt:124) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87) + ... 24 more + Suppressed: java.lang.Exception: Could not close incremental caches in D:\code\FlutterApp\build\mobile_scanner\kotlin\compileDebugKotlin\cacheable\caches-jvm\lookups: id-to-file.tab, file-to-id.tab + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:95) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.close(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.LookupStorage.close(LookupStorage.kt:155) + ... 23 more + Suppressed: java.lang.IllegalArgumentException: this and base files have different roots: C:\Users\15563\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\mobile_scanner-3.5.7\android\src\main\kotlin\dev\steenbakker\mobile_scanner\BarcodeHandler.kt and D:\code\FlutterApp\android. + at kotlin.io.FilesKt__UtilsKt.toRelativeString(Utils.kt:117) + at kotlin.io.FilesKt__UtilsKt.relativeTo(Utils.kt:128) + at org.jetbrains.kotlin.incremental.storage.RelocatableFileToPathConverter.toPath(RelocatableFileToPathConverter.kt:24) + at org.jetbrains.kotlin.incremental.storage.LegacyFileExternalizer.save(IdToFileMap.kt:51) + at org.jetbrains.kotlin.incremental.storage.LegacyFileExternalizer.save(IdToFileMap.kt:48) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.doPut(PersistentMapImpl.java:447) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.put(PersistentMapImpl.java:426) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.put(PersistentHashMap.java:106) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136) + at org.jetbrains.kotlin.incremental.storage.PersistentStorageWrapper.close(PersistentStorage.kt:124) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87) + ... 25 more + Suppressed: java.lang.IllegalArgumentException: this and base files have different roots: C:\Users\15563\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\mobile_scanner-3.5.7\android\src\main\kotlin\dev\steenbakker\mobile_scanner\BarcodeHandler.kt and D:\code\FlutterApp\android. + at kotlin.io.FilesKt__UtilsKt.toRelativeString(Utils.kt:117) + at kotlin.io.FilesKt__UtilsKt.relativeTo(Utils.kt:128) + at org.jetbrains.kotlin.incremental.storage.RelocatableFileToPathConverter.toPath(RelocatableFileToPathConverter.kt:24) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.getHashCode(FileToPathConverter.kt:50) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.getHashCode(FileToPathConverter.kt:30) + at org.jetbrains.kotlin.com.intellij.util.containers.LinkedCustomHashMap.hashKey(LinkedCustomHashMap.java:109) + at org.jetbrains.kotlin.com.intellij.util.containers.LinkedCustomHashMap.remove(LinkedCustomHashMap.java:153) + at org.jetbrains.kotlin.com.intellij.util.containers.SLRUMap.remove(SLRUMap.java:89) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.flushAppendCache(PersistentMapImpl.java:1007) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.doPut(PersistentMapImpl.java:455) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.put(PersistentMapImpl.java:426) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.put(PersistentHashMap.java:106) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136) + at org.jetbrains.kotlin.incremental.storage.PersistentStorageWrapper.close(PersistentStorage.kt:124) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87) + ... 25 more + Suppressed: java.lang.Exception: Could not close incremental caches in D:\code\FlutterApp\build\mobile_scanner\kotlin\compileDebugKotlin\cacheable\caches-jvm\inputs: source-to-output.tab + ... 25 more + Suppressed: java.lang.IllegalArgumentException: this and base files have different roots: C:\Users\15563\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\mobile_scanner-3.5.7\android\src\main\kotlin\dev\steenbakker\mobile_scanner\BarcodeHandler.kt and D:\code\FlutterApp\android. + at kotlin.io.FilesKt__UtilsKt.toRelativeString(Utils.kt:117) + at kotlin.io.FilesKt__UtilsKt.relativeTo(Utils.kt:128) + at org.jetbrains.kotlin.incremental.storage.RelocatableFileToPathConverter.toPath(RelocatableFileToPathConverter.kt:24) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.getHashCode(FileToPathConverter.kt:50) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.getHashCode(FileToPathConverter.kt:30) + at org.jetbrains.kotlin.com.intellij.util.containers.LinkedCustomHashMap.hashKey(LinkedCustomHashMap.java:109) + at org.jetbrains.kotlin.com.intellij.util.containers.LinkedCustomHashMap.remove(LinkedCustomHashMap.java:153) + at org.jetbrains.kotlin.com.intellij.util.containers.SLRUMap.remove(SLRUMap.java:89) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.flushAppendCache(PersistentMapImpl.java:1007) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.doPut(PersistentMapImpl.java:455) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.put(PersistentMapImpl.java:426) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.put(PersistentHashMap.java:106) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108) + at org.jetbrains.kotlin.incremental.storage.AppendableInMemoryStorage.applyChanges(InMemoryStorage.kt:179) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136) + at org.jetbrains.kotlin.incremental.storage.AppendableSetBasicMap.close(BasicMap.kt:157) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87) + ... 24 more + + diff --git a/lib/core/di/injection.dart b/lib/core/di/injection.dart index 85a19f28..a4ea8c02 100644 --- a/lib/core/di/injection.dart +++ b/lib/core/di/injection.dart @@ -11,6 +11,10 @@ import 'package:maibu_satabot_v2/features/devices/domain/usecases/select_work_re import 'package:maibu_satabot_v2/features/devices/domain/usecases/unbind_device_usecase.dart'; import 'package:maibu_satabot_v2/features/devices/domain/usecases/update_devicename_usecase.dart'; import 'package:maibu_satabot_v2/features/devices/presentation/bloc/devices_cubit.dart'; +import 'package:maibu_satabot_v2/features/my/presentation/bloc/my_cubit.dart'; +import 'package:maibu_satabot_v2/features/my/repository/my_repository.dart'; +import 'package:maibu_satabot_v2/features/my/repository/my_repository_impl.dart'; +import 'package:maibu_satabot_v2/features/my/usecases/updatename_usecase.dart'; import 'package:maibu_satabot_v2/features/remote_control/data/repositories/remote_control_repository_impl.dart'; import 'package:maibu_satabot_v2/features/remote_control/domain/repositories/remote_control_repository.dart'; import 'package:maibu_satabot_v2/features/remote_control/domain/usecase/diff_steer_usecase.dart'; @@ -64,9 +68,9 @@ Future init() async { sl.registerLazySingleton(() => DioClient.create()); /// 1.1.2 TcpClient:TCP客户端 - sl.registerLazySingleton(() => TcpClient( sl(), - getUserDeviceUseCase: sl(), - switchDeviceUseCase: sl(),)); + sl.registerLazySingleton( + () => TcpClient(sl(), getUserDeviceUseCase: sl(), switchDeviceUseCase: sl()), + ); /// 1.1.3 NetMessageDispatcher:消息调度器,并将 TcpClient 注入给它 sl.registerLazySingleton(() => NetMessageDispatcher(sl())); @@ -86,11 +90,9 @@ Future init() async { sl.registerLazySingleton(() => SentryLoggerImpl()); /// 2. 数据源 (DataSource) - sl.registerLazySingleton( - () => AuthHttpDataSourceImpl(sl()), - ); + sl.registerLazySingleton(() => AuthHttpDataSourceImpl(sl())); sl.registerLazySingleton( - () => DeviceHttpDatasourceImpl(sl(), sl()), // + () => DeviceHttpDatasourceImpl(sl(), sl()), // ); /// 3. 仓库 (Repository) @@ -101,16 +103,32 @@ Future init() async { ), ); + // 1. 注册 UpdateNameUsecase + sl.registerLazySingleton( + () => UpdateNameUsecase(sl()), // 注入 MyRepository 实例 + ); + sl.registerLazySingleton( + () => MyRepositoryImpl( + userStorage: sl(), // 注入 UserStorage + ), + ); + + // 2. 注册 MyCubit + sl.registerLazySingleton( + () => MyCubit( + sl(), // 注入仓库 + sl(), // 注入 UseCase + ), + ); + sl.registerLazySingleton( - () => RoutePlanningRepositoryImpl(tcp: sl()), // + () => RoutePlanningRepositoryImpl(tcp: sl()), // ); sl.registerLazySingleton( - () => RoutePlanningUseCase(sl()), // + () => RoutePlanningUseCase(sl()), // ); - - //工作历史 sl.registerLazySingleton( () => DeviceHostrityWorkRepositoryImpl( @@ -120,9 +138,7 @@ Future init() async { ); sl.registerLazySingleton(() => DeviceRepositoryImpl(sl())); - sl.registerLazySingleton( - () => RemoteControlRepositoryImpl(sl(), sl()), - ); + sl.registerLazySingleton(() => RemoteControlRepositoryImpl(sl(), sl())); /// 4. 用例 (UseCase) sl.registerLazySingleton(() => LoginUseCase(sl())); @@ -137,7 +153,7 @@ Future init() async { sl.registerLazySingleton(() => SwitchDeviceUseCase(sl())); sl.registerLazySingleton( - () => AuthTcpDatasourceImpl( + () => AuthTcpDatasourceImpl( sl(), sl(), getUserDeviceUseCase: sl(), @@ -145,15 +161,12 @@ Future init() async { ), ); - /// 5. 状态管理 (Cubit/Bloc) sl.registerLazySingleton(() => AppUserCubit()); // AuthCubit 依赖它,必须先注册 sl.registerLazySingleton(() => GetDeviceLocationUseCase(sl())); - sl.registerLazySingleton( - () => DevicesCubit(sl(), sl(), sl(), sl(), sl(), sl(), sl(), sl(), sl(),sl(),sl(), sl()), - ); + sl.registerLazySingleton(() => DevicesCubit(sl(), sl(), sl(), sl(), sl(), sl(), sl(), sl(), sl(), sl(), sl(), sl())); sl.registerFactory(() => RemoteControlCubit(sl())); - /* // 工厂模式(留存,每次获取新实例) + /* // 工厂模式(留存,每次获取新实例) sl.registerFactory(() => DeviceStatusBloc(sl())); */ //单例模式(全局共享一个实例) @@ -161,16 +174,13 @@ Future init() async { /// . 路径生成 sl.registerLazySingleton( - () => PathHttpDatasourceImpl(// 需先注册 http.Client(见下方) + () => PathHttpDatasourceImpl( + // 需先注册 http.Client(见下方) sl(), ), ); - sl.registerLazySingleton( - () => PathRepositoryImpl(datasource: sl()), - ); - sl.registerLazySingleton( - () => GeneratePathUseCaseImpl(sl()), - ); + sl.registerLazySingleton(() => PathRepositoryImpl(datasource: sl())); + sl.registerLazySingleton(() => GeneratePathUseCaseImpl(sl())); ///.路径获取和删除 sl.registerLazySingleton(() => GetWorkRecordUseCase(sl())); @@ -178,15 +188,7 @@ Future init() async { /// 6. 认证 (Auth) // --- 关键修改点 1: AuthCubit 必须在 GoRouter 之前注册,并传入参数 --- - sl.registerLazySingleton( - () => AuthCubit( - sl(), - sl(), - sl(), - sl(), - sl(), - ), - ); + sl.registerLazySingleton(() => AuthCubit(sl(), sl(), sl(), sl(), sl())); /// 7. 路由 (Router) sl.registerSingleton(createRouter(sl())); diff --git a/lib/core/storage/impl/user_storage_impl.dart b/lib/core/storage/impl/user_storage_impl.dart index f77b8314..602c205e 100644 --- a/lib/core/storage/impl/user_storage_impl.dart +++ b/lib/core/storage/impl/user_storage_impl.dart @@ -33,7 +33,6 @@ class UserStorageImpl implements UserStorage { Future deleteUser() async { await _prefs.remove(_userKey); //返回登陆页面 - } @override diff --git a/lib/core/storage/user_storage.dart b/lib/core/storage/user_storage.dart index 801a035d..0ed75a6a 100644 --- a/lib/core/storage/user_storage.dart +++ b/lib/core/storage/user_storage.dart @@ -5,4 +5,5 @@ abstract class UserStorage { Future getUser(); Future deleteUser(); Future hasUser(); + //Future updateUser(); } diff --git a/lib/features/home/presentation/pages/running_status_page.dart b/lib/features/home/presentation/pages/running_status_page.dart index f0183765..c3145836 100644 --- a/lib/features/home/presentation/pages/running_status_page.dart +++ b/lib/features/home/presentation/pages/running_status_page.dart @@ -392,7 +392,12 @@ class _RunningStatusPageState extends State { // ====================== 图表视图 ====================== Widget _buildChartContentView(DeviceStatusState state) { if (state is! DeviceStatusUpdated) { - return const Center(child: CircularProgressIndicator()); + return const Center( + child: CircularProgressIndicator( + color: Color(0xFF1677FF), // 统一使用项目主题蓝色 + strokeWidth: 4, // 加粗加载圈,视觉更清晰 + ), + ); } final status = state.status; @@ -623,7 +628,12 @@ class _RunningStatusPageState extends State { child: Text("数据加载失败", style: TextStyle(color: Colors.red, fontSize: 16)), ); } else { - return const Center(child: CircularProgressIndicator()); + return const Center( + child: CircularProgressIndicator( + color: Color(0xFF1677FF), // 统一使用项目主题蓝色 + strokeWidth: 4, // 加粗加载圈,视觉更清晰 + ), + ); } } diff --git a/lib/features/my/presentation/bloc/my_cubit.dart b/lib/features/my/presentation/bloc/my_cubit.dart new file mode 100644 index 00000000..8c92e768 --- /dev/null +++ b/lib/features/my/presentation/bloc/my_cubit.dart @@ -0,0 +1,48 @@ +import 'dart:collection'; + +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:maibu_satabot_v2/core/di/injection.dart'; +import 'package:maibu_satabot_v2/core/storage/user_storage.dart'; + +import 'package:maibu_satabot_v2/features/devices/domain/usecases/unbind_device_usecase.dart'; +import 'package:maibu_satabot_v2/features/my/presentation/bloc/my_state.dart'; +import 'package:maibu_satabot_v2/features/my/repository/my_repository.dart'; +import 'package:maibu_satabot_v2/features/my/usecases/updatename_usecase.dart'; + +class MyCubit extends Cubit { + // 1. 修正变量命名:小驼峰规范(_updateNameUsecase) + final UpdateNameUsecase _updateNameUsecase; + final MyRepository repository; + + // 2. 构造函数参数顺序与命名对齐 + MyCubit(this.repository, this._updateNameUsecase) : super(const MyState()); + + Future updateName(String nickName) async { + emit(state.copyWith(isLoading: true, errorMessage: '')); + + try { + final params = UpdateNameParams(nickName); + final result = await _updateNameUsecase(params); + print("$result 修改名称结构"); + + // 4. 恢复 fold 逻辑,处理 UseCase 返回结果(关键:更新 UI 状态) + result.fold((failure) => emit(state.copyWith(isLoading: false, errorMessage: failure.message ?? '修改昵称失败')), (successCode) { + print("$successCode 修改名称结构"); + final isSuccess = successCode == 200; + if (isSuccess) { + emit(state.copyWith(isLoading: false, errorMessage: '', nickName: nickName)); + } else { + emit(state.copyWith(isLoading: false, errorMessage: '修改昵称失败:状态码 $successCode')); + } + }); + } catch (e) { + emit(state.copyWith(isLoading: false, errorMessage: '修改昵称异常:${e.toString()}')); + } + } + + // 保留解绑设备方法(如果需要) + Future unbindDevice(String deviceId, String deviceName) async { + emit(state.copyWith(isLoading: true, errorMessage: '')); + // 解绑逻辑(如需保留,需补充 UnbindDeviceUsecase 依赖注入) + } +} diff --git a/lib/features/my/presentation/bloc/my_state.dart b/lib/features/my/presentation/bloc/my_state.dart new file mode 100644 index 00000000..9f903a5b --- /dev/null +++ b/lib/features/my/presentation/bloc/my_state.dart @@ -0,0 +1,22 @@ +import 'package:equatable/equatable.dart'; +import 'package:maibu_satabot_v2/features/devices/domain/entities/device_entity.dart'; + +class MyState extends Equatable { + final bool isLoading; // 是否正在加载 + final String? errorMessage; // 错误信息 + final String? nickName; + + const MyState({this.isLoading = false, this.errorMessage, this.nickName}); + + // 使用 copyWith 方便局部更新状态 + MyState copyWith({bool? isLoading, String? errorMessage, String? nickName}) { + return MyState( + isLoading: isLoading ?? this.isLoading, + errorMessage: errorMessage, // 错误信息通常每次更新都要重新赋值或清空 + nickName: nickName, + ); + } + + @override + List get props => [isLoading, errorMessage, nickName]; +} diff --git a/lib/features/my/presentation/pages/my_page.dart b/lib/features/my/presentation/pages/my_page.dart index de81b3dc..ee7e8b69 100644 --- a/lib/features/my/presentation/pages/my_page.dart +++ b/lib/features/my/presentation/pages/my_page.dart @@ -3,6 +3,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:get_it/get_it.dart'; import 'package:go_router/go_router.dart'; +import 'package:maibu_satabot_v2/core/di/injection.dart'; +import 'package:maibu_satabot_v2/features/my/presentation/bloc/my_cubit.dart'; +import 'package:maibu_satabot_v2/features/my/repository/my_repository.dart'; +import 'package:maibu_satabot_v2/features/my/usecases/updatename_usecase.dart'; import '../../../../core/router/route_paths.dart'; import '../../../../core/storage/user_storage.dart'; import '../../../auth/presentation/bloc/auth_cubit.dart'; @@ -24,7 +28,7 @@ class MyPage extends StatelessWidget { if (authState is AuthAuthenticated) { final user = authState.user; - userName = user.username ?? '未知用户'; + userName = user.nickname ?? '未知用户'; userId = user.userId ?? '未知ID'; } @@ -36,7 +40,10 @@ class MyPage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ // 顶部用户信息 - UserInfoCard(userName: userName, userId: userId), + BlocProvider( + create: (context) => MyCubit(sl(), sl()), + child: UserInfoCard(userName: userName, userId: userId), + ), SizedBox(height: 16), @@ -63,24 +70,14 @@ class MyPage extends StatelessWidget { // 添加 context 参数 return GestureDetector( onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => WebViewPage(url: 'https://www.satabot.com/'), - ), - ); + Navigator.push(context, MaterialPageRoute(builder: (context) => WebViewPage(url: 'https://www.satabot.com/'))); }, child: Container( width: double.infinity, height: 160, decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), - image: DecorationImage( - image: NetworkImage( - 'https://c.53326.com/d/file/lan20221010/fyhj0ibovbp.jpg', - ), - fit: BoxFit.cover, - ), + image: DecorationImage(image: NetworkImage('https://c.53326.com/d/file/lan20221010/fyhj0ibovbp.jpg'), fit: BoxFit.cover), ), child: Stack( children: [ @@ -89,23 +86,14 @@ class MyPage extends StatelessWidget { right: 12, child: Container( padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: Colors.black.withOpacity(0.5), - borderRadius: BorderRadius.circular(4), - ), - child: Text( - '了解我们', - style: TextStyle(color: Colors.white, fontSize: 14), - ), + decoration: BoxDecoration(color: Colors.black.withOpacity(0.5), borderRadius: BorderRadius.circular(4)), + child: Text('了解我们', style: TextStyle(color: Colors.white, fontSize: 14)), ), ), Positioned( left: 12, bottom: 12, - child: Text( - 'AI赋能农业', - style: TextStyle(color: Colors.white, fontSize: 16), - ), + child: Text('AI赋能农业', style: TextStyle(color: Colors.white, fontSize: 16)), ), ], ), @@ -115,35 +103,17 @@ class MyPage extends StatelessWidget { Widget _buildFunctionList(BuildContext context) { final items = [ - { - 'icon': Icons.play_arrow, - 'title': '操作视频', - 'url': 'https://www.satabot.com/Support/index.html', - }, - { - 'icon': Icons.car_rental, - 'title': '租赁服务', - 'url': 'https://www.satabot.com/Leasing.html', - }, - { - 'icon': Icons.help_outline, - 'title': '帮助与支持', - 'url': 'https://www.satabot.com/support/index.html', - }, - { - 'icon': Icons.policy, - 'title': '售后政策', - 'url': 'https://www.satabot.com/Aftersales-Service.html', - }, + {'icon': Icons.play_arrow, 'title': '操作视频', 'url': 'https://www.satabot.com/Support/index.html'}, + {'icon': Icons.car_rental, 'title': '租赁服务', 'url': 'https://www.satabot.com/Leasing.html'}, + {'icon': Icons.help_outline, 'title': '帮助与支持', 'url': 'https://www.satabot.com/support/index.html'}, + {'icon': Icons.policy, 'title': '售后政策', 'url': 'https://www.satabot.com/Aftersales-Service.html'}, ]; return Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow(color: Colors.grey.withOpacity(0.1), blurRadius: 4), - ], + boxShadow: [BoxShadow(color: Colors.grey.withOpacity(0.1), blurRadius: 4)], ), child: Column( children: [ @@ -159,13 +129,7 @@ class MyPage extends StatelessWidget { title: Text(item['title'] as String), trailing: Icon(Icons.arrow_forward), onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - WebViewPage(url: item['url'] as String), - ), - ); + Navigator.push(context, MaterialPageRoute(builder: (context) => WebViewPage(url: item['url'] as String))); }, ); }, diff --git a/lib/features/my/presentation/web_view/user_info_pages.dart b/lib/features/my/presentation/web_view/user_info_pages.dart index 184b07d3..6dbbd3de 100644 --- a/lib/features/my/presentation/web_view/user_info_pages.dart +++ b/lib/features/my/presentation/web_view/user_info_pages.dart @@ -1,17 +1,224 @@ -// user_info_card.dart import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_webrtc/flutter_webrtc.dart'; import 'package:maibu_satabot_v2/features/devices/presentation/bloc/devices_cubit.dart'; -import 'package:mobile_scanner/mobile_scanner.dart'; // 1. 导入扫码库 -import 'package:get_it/get_it.dart'; // 用于获取 Cubit 实例 -// 2. 导入你的 Cubit 文件,请根据实际路径调整 +import 'package:maibu_satabot_v2/features/my/presentation/bloc/my_cubit.dart'; +import 'package:maibu_satabot_v2/features/my/presentation/bloc/my_state.dart'; +import 'package:mobile_scanner/mobile_scanner.dart'; +import 'package:get_it/get_it.dart'; import '../../../auth/presentation/bloc/auth_cubit.dart'; -class UserInfoCard extends StatelessWidget { +class UserInfoCard extends StatefulWidget { final String userName; final String userId; const UserInfoCard({super.key, required this.userName, required this.userId}); + @override + State createState() => _UserInfoCardState(); +} + +class _UserInfoCardState extends State { + late TextEditingController _nicknameController; + final GetIt _getIt = GetIt.I; + MyCubit? _myCubit; // 可空类型 + + @override + void initState() { + super.initState(); + // 优先从 BlocProvider 获取,获取失败则从 GetIt 兜底 + try { + _myCubit = BlocProvider.of(context); + } catch (e) { + debugPrint('从 BlocProvider 获取 MyCubit 失败:$e,尝试从 GetIt 获取'); + try { + _myCubit = _getIt(); + } catch (e) { + debugPrint('从 GetIt 获取 MyCubit 也失败:$e'); + } + } + _nicknameController = TextEditingController(text: widget.userName); + } + + @override + void dispose() { + _nicknameController.dispose(); + super.dispose(); + } + + // 打开修改昵称的底部抽屉 + void _openEditNicknameBottomSheet() { + // 修复1:先校验 _myCubit 是否为 null,避免空断言 + final myCubit = _myCubit; + if (myCubit == null) { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Cubit 初始化失败,无法修改昵称'), backgroundColor: Colors.red)); + return; + } + + showModalBottomSheet( + context: context, + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(16))), + isScrollControlled: true, + backgroundColor: Colors.transparent, + constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.8), + builder: (context) => BlocProvider.value( + // 使用非空的局部变量,无需空断言 + value: myCubit, + child: BlocBuilder( + builder: (context, myState) { + final cubit = context.read(); + + return Padding( + padding: EdgeInsets.only(left: 16, right: 16, top: 20, bottom: MediaQuery.of(context).viewInsets.bottom + 80), + child: Container( + decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(16)), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text('修改昵称', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)), + IconButton(padding: EdgeInsets.zero, icon: const Icon(Icons.close, size: 20), onPressed: () => Navigator.pop(context)), + ], + ), + const SizedBox(height: 16), + const Text('新昵称', style: TextStyle(fontSize: 12, color: Colors.grey)), + const SizedBox(height: 8), + TextField( + controller: _nicknameController, + style: const TextStyle(fontSize: 16), + decoration: InputDecoration( + border: const OutlineInputBorder(), + contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + ), + autofocus: true, + enabled: !myState.isLoading, + ), + const SizedBox(height: 20), + + // 核心:根据 MyState 显示加载/按钮/错误提示 + if (myState.isLoading) + const Center( + child: Column( + children: [ + CircularProgressIndicator(color: Colors.blue), + SizedBox(height: 8), + Text("修改中...", style: TextStyle(color: Colors.grey)), + ], + ), + ) + else + Column( + children: [ + // 修复2:使用 ?. 和 ?? 避免空断言,安全判断错误信息 + if (myState.errorMessage?.isNotEmpty ?? false) + Padding( + padding: const EdgeInsets.only(bottom: 12), + child: Text(myState.errorMessage ?? "修改失败", style: const TextStyle(color: Colors.red, fontSize: 14)), + ), + + // 确定修改按钮 + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: () => _submitNewNickname(context), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, + padding: const EdgeInsets.symmetric(vertical: 14), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + ), + child: const Text('确定修改', style: TextStyle(fontSize: 16, color: Colors.white)), + ), + ), + ], + ), + ], + ), + ), + ), + ); + }, + ), + ), + ); + } + + // 提交新昵称的业务逻辑 + Future _submitNewNickname(BuildContext context) async { + final newNickname = _nicknameController.text.trim(); + if (newNickname.isEmpty ) { + Navigator.pop(context); + return; + } + + final myCubit = _myCubit; + if (myCubit == null) { + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Cubit 初始化失败'), backgroundColor: Colors.red)); + } + Navigator.pop(context); + return; + } + + // 移除重复的加载弹窗(由 BlocBuilder 显示加载状态) + await myCubit.updateName(newNickname); + + // 成功后由 BlocBuilder 监听状态并处理弹窗关闭和提示 + if (context.mounted && myCubit.state.errorMessage!.isEmpty ?? true) { + setState(() { + _nicknameController.text = newNickname; + }); + Navigator.pop(context); + // 触发 AuthCubit 重新获取用户信息 + } + } + + // 扫码绑定设备逻辑(保留) + Future _handleScanAndBind(BuildContext context) async { + final String? qrCode = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => MobileScanner( + onDetect: (capture) { + final List barcodes = capture.barcodes; + if (barcodes.isNotEmpty) { + final String? code = barcodes.first.rawValue; + if (code != null && code.isNotEmpty) { + Navigator.pop(context, code); + } + } + }, + ), + ), + ); + + if (qrCode == null || qrCode.isEmpty) return; + + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => const Center(child: CircularProgressIndicator(color: Color(0xFF1677FF), strokeWidth: 4)), + ); + + try { + final devicesCubit = _getIt(); + // await devicesCubit.bindDevice(qrCode); + if (context.mounted) Navigator.pop(context); + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('设备绑定成功!'), backgroundColor: Colors.green)); + } + } catch (e) { + if (context.mounted) Navigator.pop(context); + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('绑定失败:$e'), backgroundColor: Colors.red)); + } + } + } + @override Widget build(BuildContext context) { return Row( @@ -21,97 +228,23 @@ class UserInfoCard extends StatelessWidget { height: 48, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), - image: DecorationImage( - image: NetworkImage('https://pic4.zhimg.com/v2-c34c61a90095abb8713de9d1dca7ec7b_r.jpg'), - fit: BoxFit.cover, - ), + image: DecorationImage(image: NetworkImage('https://pic4.zhimg.com/v2-c34c61a90095abb8713de9d1dca7ec7b_r.jpg'), fit: BoxFit.cover), ), ), - SizedBox(width: 12), + const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(userName, style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), - Text('用户 id:$userId', style: TextStyle(fontSize: 12, color: Colors.grey)), + Text(_nicknameController.text, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + Text('用户 id:${widget.userId}', style: const TextStyle(fontSize: 12, color: Colors.grey)), ], ), ), - IconButton( - icon: Icon(Icons.edit), - onPressed: () {}, - ), - Spacer(), - IconButton( - icon: Icon(Icons.add), - // 3. 绑定点击事件 - onPressed: () => _handleScanAndBind(context), - ), + IconButton(icon: const Icon(Icons.edit), onPressed: _openEditNicknameBottomSheet), + const Spacer(), + IconButton(icon: const Icon(Icons.add), onPressed: () => _handleScanAndBind(context)), ], ); } - - // 4. 定义扫码与绑定逻辑 - Future _handleScanAndBind(BuildContext context) async { - // 跳转到扫码页面 - final String? qrCode = await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => MobileScanner( - onDetect: (capture) { - final List barcodes = capture.barcodes; - if (barcodes.isNotEmpty) { - debugPrint('识别到的数据: $barcodes'); - final String? code = barcodes.first.rawValue; - if (code != null && code.isNotEmpty) { - // 识别成功,立即返回结果并关闭页面 - debugPrint('扫码成功,识别到的数据: $code'); - // Navigator.pop(context, code); - } - } - }, - ), - ), - ); - - // 如果用户取消或未扫到码,直接返回 - if (qrCode == null || qrCode.isEmpty) { - return; - } - - // 显示加载对话框 - showDialog( - context: context, - barrierDismissible: false, - builder: (context) => Center(child: CircularProgressIndicator()), - ); - - try { - // 5. 获取 Cubit 实例并调用绑定接口 - final Cubit = GetIt.I(); - - // 执行绑定逻辑 - //await Cubit.bindDevice(qrCode); - - // 关闭加载框 - if (context.mounted) Navigator.pop(context); - - // 成功提示 - if (context.mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('设备绑定成功!'), backgroundColor: Colors.green), - ); - } - } catch (e) { - // 关闭加载框 - if (context.mounted) Navigator.pop(context); - - // 失败提示 - if (context.mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('绑定失败:$e'), backgroundColor: Colors.red), - ); - } - } - } } diff --git a/lib/features/my/repository/my_repository.dart b/lib/features/my/repository/my_repository.dart new file mode 100644 index 00000000..4212a5c0 --- /dev/null +++ b/lib/features/my/repository/my_repository.dart @@ -0,0 +1,8 @@ +// lib/features/devices/domain/repositories/route_planning_repository.dart +import 'package:fpdart/fpdart.dart'; +import 'package:maibu_satabot_v2/features/devices/domain/errors/device_failure.dart'; + +abstract class MyRepository { + // 抽象方法定义:参数是 String nickName,返回 Future> + Future> updateName(String nickName); +} diff --git a/lib/features/my/repository/my_repository_impl.dart b/lib/features/my/repository/my_repository_impl.dart new file mode 100644 index 00000000..0013eeb3 --- /dev/null +++ b/lib/features/my/repository/my_repository_impl.dart @@ -0,0 +1,61 @@ +import 'dart:math'; +import 'package:fpdart/fpdart.dart'; +import 'package:http/http.dart' as http; +import 'package:maibu_satabot_v2/features/my/repository/my_repository.dart'; +import 'dart:convert'; + +import '../../../../core/di/injection.dart'; +import '../../../../core/storage/user_storage.dart'; +// 必须导入 DeviceFailure 类 +import '../../../../features/devices/domain/errors/device_failure.dart'; + +class MyRepositoryImpl implements MyRepository { + // 可选:注入 UserStorage(如果需要获取 token 等用户信息) + final UserStorage _userStorage; + + MyRepositoryImpl({UserStorage? userStorage}) : _userStorage = userStorage ?? sl(); + // 🔥 辅助方法:获取 Token + Future _getToken() async { + final user = await _userStorage.getUser(); + return user?.token; + } + + // 核心修复:严格匹配抽象类的方法签名 + @override + Future> updateName(String nickName) async { + final url = Uri.parse('https://serviceri.satabot.com/system/user/profile'); + + // 补充:从 UserStorage 获取 token(接口通常需要认证) + final token = await _getToken(); + final headers = { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', // 按需添加认证头 + }; + + final body = jsonEncode({'nickName': nickName}); + + try { + final response = await http.put(url, headers: headers, body: body); + + // 1. 处理成功响应(statusCode 200) + if (response.statusCode == 200) { + final data = jsonDecode(response.body) as Map; + + // 根据接口返回值,返回 Either.right(成功码,比如 1 表示成功) + // 示例:假设接口返回 code=200 表示成功 + final int successCode = data['code'] ?? 1; + return Right(successCode); + } + // 2. 处理失败响应(非 200 状态码) + else { + final String errorMsg = '修改昵称失败:状态码 ${response.statusCode}'; + return Left(DeviceFailure.serverError(message: errorMsg)); + } + } + // 3. 处理网络异常 + catch (e) { + final String errorMsg = '网络异常:${e.toString()}'; + return Left(DeviceFailure.serverError(message: errorMsg)); + } + } +} diff --git a/lib/features/my/usecases/updatename_usecase.dart b/lib/features/my/usecases/updatename_usecase.dart new file mode 100644 index 00000000..ae77ed2a --- /dev/null +++ b/lib/features/my/usecases/updatename_usecase.dart @@ -0,0 +1,26 @@ +import 'package:fpdart/fpdart.dart'; +import 'package:maibu_satabot_v2/core/domain/usecases/base_usecase.dart'; +import 'package:maibu_satabot_v2/features/devices/domain/errors/device_failure.dart'; // 必须导入 +import 'package:maibu_satabot_v2/features/my/repository/my_repository.dart'; + +// 1. 泛型严格匹配:BaseUseCase<成功类型int, 参数类型UpdateNameParams> +class UpdateNameUsecase implements BaseUseCase { + final MyRepository myRepository; + + UpdateNameUsecase(this.myRepository); + + // 2. 核心修复:返回值类型从 dynamic 改为 Either + // 严格覆盖 BaseUseCase 的 call 方法 + @override + Future> call(UpdateNameParams params) async { + // 3. 调用仓库方法(返回值已匹配 Either) + return await myRepository.updateName(params.nickName); + } +} + +// 参数类保持不变(不可变,语义清晰) +class UpdateNameParams { + final String nickName; + + const UpdateNameParams(this.nickName); +}