Jolie 2 months ago
parent
commit
6d6a9b78be
33 changed files with 700 additions and 848 deletions
  1. 3
      .fvmrc
  2. 2
      .gitignore
  3. 3
      .vscode/settings.json
  4. 198
      android/.kotlin/errors/errors-1767939772073.log
  5. 9
      lib/controller/discover/room_controller.dart
  6. 2
      lib/controller/home/user_information_controller.dart
  7. 11
      lib/controller/message/call_controller.dart
  8. 35
      lib/controller/mine/auth_controller.dart
  9. 12
      lib/controller/mine/edit_info_controller.dart
  10. 31
      lib/controller/mine/matchmaker_update_controller.dart
  11. 16
      lib/controller/mine/mine_controller.dart
  12. 11
      lib/controller/mine/rose_controller.dart
  13. 7
      lib/controller/setting/spread_controller.dart
  14. 2
      lib/im/im_manager.dart
  15. 3
      lib/model/discover/rtc_channel_model.dart
  16. 13
      lib/network/network_config.dart
  17. 18
      lib/pages/discover/live_item_widget.dart
  18. 2
      lib/pages/discover/visitor_list_page.dart
  19. 4
      lib/pages/home/user_information_page.dart
  20. 32
      lib/pages/message/chat_page.dart
  21. 321
      lib/pages/mine/matchmaker_update_page.dart
  22. 316
      lib/pages/mine/mine_page.dart
  23. 1
      lib/pages/mine/my_wallet_page.dart
  24. 41
      lib/pages/mine/rose_history_page.dart
  25. 107
      lib/pages/mine/signature_page.dart
  26. 12
      lib/pages/mine/withdraw_history_page.dart
  27. 8
      lib/pages/mine/withdraw_page.dart
  28. 7
      lib/pages/setting/setting_page.dart
  29. 24
      lib/rtc/rtc_manager.dart
  30. 4
      lib/service/live_chat_message_service.dart
  31. 287
      lib/widget/message/chat_input_bar.dart
  32. 2
      lib/widget/message/video_call_invite_dialog.dart
  33. 4
      pubspec.yaml

3
.fvmrc

@ -0,0 +1,3 @@
{
"flutter": "3.35.2"
}

2
.gitignore

@ -30,3 +30,5 @@ doc/api/
/android/app/profile
/android/app/release
# FVM Version Cache
.fvm/

3
.vscode/settings.json

@ -0,0 +1,3 @@
{
"dart.flutterSdkPath": ".fvm/versions/3.35.2"
}

198
android/.kotlin/errors/errors-1767939772073.log

@ -0,0 +1,198 @@
kotlin version: 2.1.0
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:76)
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: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: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:\www\dating_touchme_app\build\emoji_picker_flutter\kotlin\compileReleaseKotlin\cacheable\caches-jvm\jvm\kotlin: class-fq-name-to-source.tab, source-to-classes.tab, internal-name-to-source.tab
at org.jetbrains.kotlin.com.google.common.io.Closer.close(Closer.java:236)
at org.jetbrains.kotlin.incremental.IncrementalCachesManager.close(IncrementalCachesManager.kt:55)
at kotlin.io.CloseableKt.closeFinally(Closeable.kt:56)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:293)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:674)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:91)
at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1659)
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:\www\dating_touchme_app\build\emoji_picker_flutter\kotlin\compileReleaseKotlin\cacheable\caches-jvm\jvm\kotlin: class-fq-name-to-source.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:223)
... 22 more
Suppressed: java.lang.IllegalArgumentException: this and base files have different roots: C:\Users\Administrator\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\emoji_picker_flutter-4.4.0\android\src\main\kotlin\com\fintasys\emoji_picker_flutter\EmojiPickerFlutterPlugin.kt and D:\www\dating_touchme_app\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:443)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.put(PersistentMapImpl.java:422)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.put(PersistentHashMap.java:105)
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\Administrator\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\emoji_picker_flutter-4.4.0\android\src\main\kotlin\com\fintasys\emoji_picker_flutter\EmojiPickerFlutterPlugin.kt and D:\www\dating_touchme_app\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:999)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.doPut(PersistentMapImpl.java:451)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.put(PersistentMapImpl.java:422)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.put(PersistentHashMap.java:105)
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\Administrator\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\emoji_picker_flutter-4.4.0\android\src\main\kotlin\com\fintasys\emoji_picker_flutter\EmojiPickerFlutterPlugin.kt and D:\www\dating_touchme_app\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:443)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.put(PersistentMapImpl.java:422)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.put(PersistentHashMap.java:105)
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:\www\dating_touchme_app\build\emoji_picker_flutter\kotlin\compileReleaseKotlin\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\Administrator\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\emoji_picker_flutter-4.4.0\android\src\main\kotlin\com\fintasys\emoji_picker_flutter\EmojiPickerFlutterPlugin.kt and D:\www\dating_touchme_app\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:443)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.put(PersistentMapImpl.java:422)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.put(PersistentHashMap.java:105)
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\Administrator\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\emoji_picker_flutter-4.4.0\android\src\main\kotlin\com\fintasys\emoji_picker_flutter\EmojiPickerFlutterPlugin.kt and D:\www\dating_touchme_app\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:999)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.doPut(PersistentMapImpl.java:451)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.put(PersistentMapImpl.java:422)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.put(PersistentHashMap.java:105)
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:\www\dating_touchme_app\build\emoji_picker_flutter\kotlin\compileReleaseKotlin\cacheable\caches-jvm\inputs: source-to-output.tab
... 25 more
Suppressed: java.lang.IllegalArgumentException: this and base files have different roots: C:\Users\Administrator\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\emoji_picker_flutter-4.4.0\android\src\main\kotlin\com\fintasys\emoji_picker_flutter\EmojiPickerFlutterPlugin.kt and D:\www\dating_touchme_app\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:999)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.doPut(PersistentMapImpl.java:451)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.put(PersistentMapImpl.java:422)
at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.put(PersistentHashMap.java:105)
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

9
lib/controller/discover/room_controller.dart

@ -23,6 +23,7 @@ import '../../pages/mine/real_name_page.dart';
import '../../pages/setting/match_spread_page.dart';
import '../../widget/live/live_recharge_popup.dart';
import '../message/call_controller.dart';
import 'discover_controller.dart';
import 'svga_player_manager.dart';
//
@ -262,11 +263,15 @@ class RoomController extends GetxController with WidgetsBindingObserver {
};
final response = await _networkService.rtcApi.connectRtcChannel(data);
if (!response.data.isSuccess) {
// DiscoverController.loadRtcChannelPage
if (Get.isRegistered<DiscoverController>()) {
final discoverController = Get.find<DiscoverController>();
discoverController.loadRtcChannelPage();
}
SmartDialog.showToast(response.data.message);
return;
}
if (!response.data.data['success']) {
SmartDialog.showToast('积分不足');
return;
}
currentRole = role;
@ -276,6 +281,8 @@ class RoomController extends GetxController with WidgetsBindingObserver {
} else {
await RTCManager.instance.publishAudio();
}
//
await getUserPropLinkMicCard();
RtcSeatUserInfo userInfo = RtcSeatUserInfo(
uid: rtcChannel.value?.uid,
miId: GlobalData().userData?.id ?? '',

2
lib/controller/home/user_information_controller.dart

@ -31,7 +31,7 @@ class UserInformationController extends GetxController {
@override
void onInit() {
super.onInit();
myUserData.value = GlobalData().userData;
//
if (miId.isEmpty) {
errorMessage.value = '用户ID无效';

11
lib/controller/message/call_controller.dart

@ -57,6 +57,12 @@ class CallSession {
final end = endTime ?? DateTime.now();
return end.difference(startTime).inSeconds;
}
@override
String toString() {
return '{callType: $callType, status: $status, isInitiator: $isInitiator}';
}
}
///
@ -184,6 +190,11 @@ class CallController extends GetxController {
});
return null;
}
if (!response.data.data!.success && response.data.data!.code == 'E0003') {
SmartDialog.showToast('对方忙线中');
isCreatingChannel.value = false;
return null;
}
rtcChannel.value = response.data.data;
print('✅ 创建一对一RTC频道成功: ${response.data.data?.channelId}');
isCreatingChannel.value = false;

35
lib/controller/mine/auth_controller.dart

@ -1,10 +1,13 @@
import 'dart:async';
import 'package:dating_touchme_app/controller/home/home_controller.dart';
import 'package:get/get.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get_storage/get_storage.dart';
import '../../generated/assets.dart';
import '../../network/user_api.dart';
import '../../pages/setting/match_league_page.dart';
import '../../pages/setting/match_spread_page.dart';
import '../discover/room_controller.dart';
import '../global.dart';
class AuthController extends GetxController {
@ -112,6 +115,18 @@ class AuthController extends GetxController {
GlobalData().userData!.identityCard = idcard.value;
GlobalData().userData!.name = name.value;
SmartDialog.showToast('认证成功');
getInfo();
final RoomController _roomController;
_roomController = Get.isRegistered<RoomController>()
? Get.find<RoomController>()
: Get.put(RoomController());
_roomController.matchmakerFlag.value = GlobalData().userData!.matchmakerFlag!;
final HomeController hController = Get.find<HomeController>();
hController.refreshRecommendData();
hController.refreshNearbyData();
if(type == 1){
// ;
Get.off(() => MatchSpreadPage());
@ -122,12 +137,30 @@ class AuthController extends GetxController {
SmartDialog.showToast(response.data.message);
}
} catch (e) {
SmartDialog.showToast('网络请求失败,请检查网络连接');
// SmartDialog.showToast('网络请求失败,请检查网络连接');
// SmartDialog.showToast(response.data.message);
} finally {
}
}
getInfo() async {
final result = await _userApi.getMarriageInformationDetail();
// print(result.data);
if (result.data.isSuccess) {
final information = result.data.data!;
information.matchmakerFlag = GlobalData().userData?.matchmakerFlag ?? false;
information.realName = GlobalData().userData?.realName;
information.phone = GlobalData().userData?.phone;
GlobalData().userData = information;
await GetStorage().write('userId', GlobalData().userId);
}
}
}
class AuthCard {

12
lib/controller/mine/edit_info_controller.dart

@ -607,11 +607,10 @@ class EditInfoController extends GetxController {
savaDescribeInfo() async {
try{
final originImg = userData.value!.photoList!.map((e) => e.photoUrl).toSet();
final result = imgList
.where((e) => !originImg.contains(e))
.toList();
if(message.value.isEmpty){
SmartDialog.showToast("请输入交友心声");
return;
}
final imgPayload = {
'miId': userData.value?.id ?? 0,
'authenticationCode': '7',
@ -624,15 +623,12 @@ class EditInfoController extends GetxController {
realDescribe.value = message.value;
getInfo();
SmartDialog.showToast("交友心声已提交审核");
Get.back();
} else{
SmartDialog.showToast(imgAuditResp.data.message);
return;
}
} catch(e){
print('相册提交审核失败: $e');
SmartDialog.showToast('交友心声提交审核失败,请重试');
return;

31
lib/controller/mine/matchmaker_update_controller.dart

@ -1,31 +0,0 @@
import 'package:get/get.dart';
class MatchmakerUpdateController extends GetxController {
final sum = 0.obs;
final select = 0.obs;
final deal = [
{"title": "实习红娘", "price": "0", "revenue": [
"礼物收益范围15%-30%,嘉宾消费的分成3%;",
"每天前5人连麦的礼物收益15%,第6-10人连麦的礼物收益20%,第11-15人连麦的礼物收益25%,第16人以上连麦的礼物收益30%;",
"红娘推荐的嘉宾成为红娘,赚取入驻费的20%分成;",
"新徒弟首月收益的10%(平台奖励)",
]},
{"title": "在线红娘", "price": "99", "revenue": [
"礼物收益范围30%-40%,嘉宾消费的分成6%;",
"每天前5人连麦的礼物收益30%,第6-10人连麦的礼物收益35%,第11人以上连麦的礼物收益40%;",
"红娘推荐的嘉宾成为红娘,赚取入驻费的20%分成;",
"新徒弟首月收益的10%(平台奖励)",
]},
{"title": "签约红娘", "price": "399", "revenue": [
"礼物收益固定40%,邀请嘉宾,嘉宾消费的分成10%",
"红娘推荐的嘉宾成为红娘,赚取入驻费的20%分成;",
"新徒弟首月收益的10%(平台奖励)",
]},
].obs;
changeActive(int i){
select.value = i;
}
}

16
lib/controller/mine/mine_controller.dart

@ -4,9 +4,11 @@ import 'package:dating_touchme_app/model/mine/user_count_data.dart';
import 'package:dating_touchme_app/network/user_api.dart';
import 'package:dating_touchme_app/pages/mine/auth_center_page.dart';
import 'package:dating_touchme_app/pages/mine/my_wallet_page.dart';
import 'package:dating_touchme_app/pages/mine/real_name_page.dart';
import 'package:dating_touchme_app/pages/mine/rose_page.dart';
import 'package:dating_touchme_app/pages/mine/user_help_center_page.dart';
import 'package:dating_touchme_app/pages/setting/match_spread_page.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import '../../pages/setting/setting_page.dart';
@ -20,7 +22,7 @@ class MineController extends GetxController {
{"icon": Assets.imagesWallet, "title": "我的钱包", "subTitle": "提现无门槛", "path": () => MyWalletPage()},
// {"icon": Assets.imagesShop, "title": "商城中心", "subTitle": "不定期更新商品", "path": () => null},
{"icon": Assets.imagesCert, "title": "认证中心", "subTitle": GlobalData().userData?.identityCard == null || GlobalData().userData?.profilePhoto == null ? "未认证" : "已认证", "path": () => AuthCenterPage()},
{"icon": Assets.imagesMatchmaker, "title": "红娘等级", "subTitle": "实习红娘", "path": () => MatchSpreadPage()},
{"icon": Assets.imagesMatchmaker, "title": "红娘等级", "subTitle": "实习红娘", "path": 'MatchSpreadPage'},
].obs;
final settingList = <Map>[
@ -36,6 +38,8 @@ class MineController extends GetxController {
late UserApi _userApi;
@override
void onInit() {
super.onInit();
@ -44,4 +48,14 @@ class MineController extends GetxController {
_userApi = Get.find<UserApi>();
}
void registerMatch() async {
if (GlobalData().userData!.identityCard != null &&
GlobalData().userData!.identityCard!.isNotEmpty) {
await Get.to(() => MatchSpreadPage());
} else {
SmartDialog.showToast('请先进行实名认证');
await Get.to(() => RealNamePage(type: 1));
}
}
}

11
lib/controller/mine/rose_controller.dart

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:fluwx/fluwx.dart';
import 'package:get/get.dart';
import '../discover/room_controller.dart';
class RoseController extends GetxController with WidgetsBindingObserver {
@ -96,6 +97,16 @@ class RoseController extends GetxController with WidgetsBindingObserver {
launchWX.value = false;
count.value = 0;
getRoseNum();
// RoomController
if (Get.isRegistered<RoomController>()) {
try {
final roomController = Get.find<RoomController>();
await roomController.getVirtualAccount();
print('✅ 已刷新 RoomController 的玫瑰余额');
} catch (e) {
print('⚠️ 刷新 RoomController 余额失败: $e');
}
}
} else {
count.value += 1;
if(count.value < 3){

7
lib/controller/setting/spread_controller.dart

@ -65,14 +65,15 @@ class SpreadController extends GetxController with WidgetsBindingObserver {
];
} else if(roseList[activePay.value].subCategory == 88802){
revenue.value = [
{'icon': '1', 'desc': '礼物收益固定40%,邀请嘉宾,嘉宾消费的分成10%'},
{'icon': '1', 'desc': '礼物收益范围40%,嘉宾消费的分成10%;'},
// {'icon': '2', 'desc': '每天前5人连麦的礼物收益15%,第6-10人连麦的礼物收益20%,第11-15人连麦的礼物收益25%,第16人以上连麦的礼物收益30%;'},
{'icon': '3', 'desc': '红娘推荐的嘉宾成为红娘,赚取入驻费的20%分成;'},
{'icon': '4', 'desc': '新徒弟首月收益的10%(平台奖励)'},
];
} else if(roseList[activePay.value].subCategory == 88801){
revenue.value = [
{'icon': '1', 'desc': '礼物收益范围15%-30%,嘉宾消费的分成3%;'},
{'icon': '2', 'desc': '每天前5人连麦的礼物收益15%,第6-10人连麦的礼物收益20%,第11-15人连麦的礼物收益25%,第16人以上连麦的礼物收益30%;'},
{'icon': '1', 'desc': '礼物收益范围40%,嘉宾消费的分成10%;'},
// {'icon': '2', 'desc': '每天前5人连麦的礼物收益15%,第6-10人连麦的礼物收益20%,第11-15人连麦的礼物收益25%,第16人以上连麦的礼物收益30%;'},
{'icon': '3', 'desc': '红娘推荐的嘉宾成为红娘,赚取入驻费的20%分成;'},
{'icon': '4', 'desc': '新徒弟首月收益的10%(平台奖励)'},
];

2
lib/im/im_manager.dart

@ -1902,7 +1902,6 @@ class IMManager {
return;
}
RTMManager.instance.subscribe(channelId ?? '');
//
Map<String, dynamic>? attributes;
try {
@ -1953,6 +1952,7 @@ class IMManager {
tag: 'video_call_invite_dialog',
builder: (context) {
return VideoCallInviteDialog(
callType: callType,
avatarUrl: finalAvatarUrl,
nickName: finalNickName,
onTap: () async {

3
lib/model/discover/rtc_channel_model.dart

@ -3,11 +3,13 @@ class RtcChannelModel {
final String channelId;
final String channelPic;
final String channelName;
final int age;
RtcChannelModel({
required this.channelId,
required this.channelPic,
required this.channelName,
required this.age,
});
factory RtcChannelModel.fromJson(Map<String, dynamic> json) {
@ -15,6 +17,7 @@ class RtcChannelModel {
channelId: json['channelId']?.toString() ?? '',
channelPic: json['channelPic']?.toString() ?? '',
channelName: json['channelName']?.toString() ?? '',
age: json['age'] ?? 0,
);
}

13
lib/network/network_config.dart

@ -1,8 +1,10 @@
import 'package:dating_touchme_app/controller/global.dart';
import 'package:dating_touchme_app/controller/message/conversation_controller.dart';
import 'package:dating_touchme_app/controller/discover/discover_controller.dart';
import 'package:dating_touchme_app/controller/discover/room_controller.dart';
import 'package:dating_touchme_app/controller/overlay_controller.dart';
import 'package:dating_touchme_app/im/im_manager.dart';
import 'package:dating_touchme_app/network/api_urls.dart';
import 'package:dio/dio.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart' hide Response;
@ -100,6 +102,13 @@ class ResponseInterceptor extends Interceptor {
_showError("登录已过期,请重新登录");
_handleTokenExpired();
} else {
if(response.realUri.path.contains(ApiUrls.getSwRtcToken)){
// DiscoverController.loadRtcChannelPage
if (Get.isRegistered<DiscoverController>()) {
final discoverController = Get.find<DiscoverController>();
discoverController.loadRtcChannelPage();
}
}
//
final message = data['message'] ?? '请求失败';
_showError(message);
@ -145,10 +154,12 @@ class ResponseInterceptor extends Interceptor {
case DioExceptionType.cancel:
errorMessage = '请求已取消';
break;
case DioExceptionType.connectionError:
errorMessage = '网络连接失败';
break;
default:
errorMessage = err.message ?? '未知错误';
}
_showError(errorMessage);
handler.reject(err);
}

18
lib/pages/discover/live_item_widget.dart

@ -187,27 +187,11 @@ class _LiveItemWidgetState extends State<LiveItemWidget> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 64.w,
child: Text(
widget.channel != null && widget.channel!.channelName.isNotEmpty
? widget.channel!.channelName
: "一直一直在等你一直一直在等你......",
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 8.w,
color: Colors.white,
fontWeight: FontWeight.w500,
),
),
),
SizedBox(height: 2.w),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"福州 | 28岁",
widget.channel?.age != 0 && widget.channel?.age != null ? "${widget.channel?.channelName} | ${widget.channel?.age}" : widget.channel?.channelName ?? '',
style: TextStyle(
fontSize: 11.w,
color: Colors.white,

2
lib/pages/discover/visitor_list_page.dart

@ -196,7 +196,7 @@ class VisitorItem extends StatelessWidget {
)
],
).onTap((){
Get.to(() => UserInformationPage(miId: visitor.miId, userId: GlobalData().userId!));
Get.to(() => UserInformationPage(miId: visitor.miId, userId: visitor.userId!));
});
}

4
lib/pages/home/user_information_page.dart

@ -179,7 +179,7 @@ class UserInformationPage extends StatelessWidget {
),
),
SizedBox(width: 13.w,),
if(controller.myUserData.value?.genderCode == 0) Container(
if(controller.userData.value?.genderCode == 1) Container(
width: 33.w,
height: 13.w,
decoration: BoxDecoration(
@ -257,7 +257,7 @@ class UserInformationPage extends StatelessWidget {
),
),
SizedBox(width: 4.w,),
if(controller.myUserData.value?.genderCode == 1) Container(
if(controller.userData.value?.genderCode == 0) Container(
width: 33.w,
height: 13.w,
decoration: BoxDecoration(

32
lib/pages/message/chat_page.dart

@ -62,6 +62,9 @@ class _ChatPageState extends State<ChatPage> {
//
final activeGift = ValueNotifier<int?>(null);
final giftNum = ValueNotifier<int>(1);
// ChatInputBar GlobalKey
final GlobalKey<State<ChatInputBar>> _chatInputBarKey = GlobalKey<State<ChatInputBar>>();
@override
void initState() {
@ -305,18 +308,20 @@ class _ChatPageState extends State<ChatPage> {
},
),
),
body: Column(
children: [
//
Expanded(
child: Container(
color: Color(0xffF5F5F5),
child: GestureDetector(
onTap: () {
//
FocusManager.instance.primaryFocus?.unfocus();
},
behavior: HitTestBehavior.opaque,
body: GestureDetector(
onTap: () {
//
FocusManager.instance.primaryFocus?.unfocus();
//
ChatInputBar.closePanels(_chatInputBarKey);
},
behavior: HitTestBehavior.opaque,
child: Column(
children: [
//
Expanded(
child: Container(
color: Color(0xffF5F5F5),
child: ListView.builder(
controller: _scrollController,
reverse: false,
@ -375,9 +380,9 @@ class _ChatPageState extends State<ChatPage> {
),
),
),
),
// 使
ChatInputBar(
key: _chatInputBarKey,
onSendMessage: (message) async {
await controller.sendMessage(message);
},
@ -404,6 +409,7 @@ class _ChatPageState extends State<ChatPage> {
},
),
],
),
),
),
);

321
lib/pages/mine/matchmaker_update_page.dart

@ -1,321 +0,0 @@
import 'package:dating_touchme_app/components/page_appbar.dart';
import 'package:dating_touchme_app/controller/mine/matchmaker_update_controller.dart';
import 'package:dating_touchme_app/extension/ex_widget.dart';
import 'package:dating_touchme_app/generated/assets.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
class MatchmakerUpdatePage extends StatelessWidget {
const MatchmakerUpdatePage({super.key});
@override
Widget build(BuildContext context) {
return GetX<MatchmakerUpdateController>(
init: MatchmakerUpdateController(),
builder: (controller){
return Stack(
children: [
Positioned(
child: Container(
width: 375.w,
height: 812.h,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color.fromRGBO(172, 89, 255, 1), // 100%
Color.fromRGBO(117, 98, 249, 1), // 64.87%
Color.fromRGBO(117, 98, 249, 1), // 43.03%
Color.fromRGBO(255, 255, 255, 1), // 0%
],
stops: [
0.0,
0.2303,
0.4487,
0.6,
],
),
),
),
),
Scaffold(
backgroundColor: Colors.transparent,
appBar: PageAppbar(title: "升级红娘", backgroundColor: Colors.transparent, color: Colors.white,),
body: SingleChildScrollView(
child: Container(
padding: EdgeInsets.symmetric(
vertical: 20.w,
horizontal: 12.w
),
child: Column(
children: [
Container(
padding: EdgeInsets.symmetric(
vertical: 20.w,
horizontal: 12.w
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(18.w)),
),
child: Column(
children: [
Row(
children: [
Text(
"趣恋恋,让婚恋服务更高效",
style: TextStyle(
fontSize: 16.w,
fontWeight: FontWeight.w500
),
)
],
),
SizedBox(height: 15.w,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
...controller.deal.asMap().entries.map((entry){
return SelectItem(
item: entry.value,
index: entry.key,
active: controller.select.value,
changeActive: controller.changeActive,
);
}),
],
),
SizedBox(height: 30.w,),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"新红娘入驻权益",
style: TextStyle(
fontSize: 22.w,
color: const Color.fromRGBO(48, 48, 48, 1),
fontWeight: FontWeight.w500
),
),
SizedBox(width: 10.w,),
Image.asset(
Assets.imagesLimitTime,
width: 30.w,
height: 16.w,
)
],
),
SizedBox(height: 15.w,),
...(controller.deal[controller.select.value]["revenue"] as List).asMap().entries.map((entry){
return RevenueItem(
index: controller.select.value == 2 && entry.key >= 1 ? entry.key + 1 : entry.key,
title: entry.value,
);
})
],
),
),
Container(
width: 325.w,
height: 45.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(45.w)),
gradient: LinearGradient(
begin: Alignment.centerLeft, // 0%
end: Alignment.centerRight, // 100%
colors: [
Color.fromRGBO(131, 89, 255, 1), //
Color.fromRGBO(77, 127, 231, 1), //
Color.fromRGBO(61, 138, 224, 1), //
],
stops: [0.0, 0.7753, 1.0], // CSS 0%77.53%100%
),
),
child: Center(
child: Text(
"确认",
style: TextStyle(
fontSize: 18.w,
color: Colors.white,
fontWeight: FontWeight.w500
),
),
),
)
],
),
),
),
)
],
);
},
);
}
}
class SelectItem extends StatefulWidget {
final Map item;
final int index;
final int active;
final Function(int) changeActive;
const SelectItem({super.key, required this.item, required this.index, required this.active, required this.changeActive});
@override
State<SelectItem> createState() => _SelectItemState();
}
class _SelectItemState extends State<SelectItem> {
@override
Widget build(BuildContext context) {
return Stack(
children: [
Container(
width: 103.w,
height: 109.w,
padding: EdgeInsets.only(
top: 32.w,
bottom: 9.w
),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(17.w)),
border: Border.all(width: 1, color: widget.active == widget.index ? const Color.fromRGBO(117, 98, 249, 1) : const Color.fromRGBO(222, 222, 222, 1)),
gradient: widget.active == widget.index ? LinearGradient(
begin: Alignment.centerLeft, // 90deg
end: Alignment.centerRight,
colors: [
Color.fromRGBO(232, 199, 255, 0.2), // 0%
Color.fromRGBO(194, 195, 255, 0.2), // 100%
],
stops: [
0.0,
1.0,
],
) : null,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"年费",
style: TextStyle(
fontSize: 11.w,
fontWeight: FontWeight.w700
),
),
RichText(
text: TextSpan(
style: TextStyle(
color: const Color.fromRGBO(248, 85, 66, 1),
fontWeight: FontWeight.w700
),
children: [
TextSpan(
text: "",
style: TextStyle(
fontSize: 11.w
)
),
TextSpan(
text: "${widget.item["price"]}",
style: TextStyle(
fontSize: 21.w
)
)
]
),
),
Text(
"+10小时视频相亲",
style: TextStyle(
color: Color.fromRGBO(144, 144, 144, widget.index == 0 ? 1 : 0),
fontSize: 9.w
),
)
],
),
),
Positioned(
top: 0,
left: 0,
child: Container(
width: 63.w,
height: 16.w,
decoration: BoxDecoration(
color: widget.active == widget.index ? const Color.fromRGBO(117, 98, 249, 1) : const Color.fromRGBO(191, 191, 191, 1),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16.w),
bottomRight: Radius.circular(16.w),
)
),
child: Center(
child: Text(
"${widget.item["title"]}",
style: TextStyle(
fontSize: 9.w,
color: Colors.white,
fontWeight: FontWeight.w500
),
),
),
),
)
],
).onTap((){
widget.changeActive(widget.index);
});
}
}
class RevenueItem extends StatefulWidget {
final int index;
final String title;
const RevenueItem({super.key, required this.index, required this.title});
@override
State<RevenueItem> createState() => _RevenueItemState();
}
class _RevenueItemState extends State<RevenueItem> {
final matchmakerIcons = {
0: Assets.imagesMatchmakerIcon1,
1: Assets.imagesMatchmakerIcon2,
2: Assets.imagesMatchmakerIcon3,
3: Assets.imagesMatchmakerIcon4,
};
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(17.w),
margin: EdgeInsets.only(bottom: 4.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(18.w)),
color: const Color.fromRGBO(117, 98, 249, .1)
),
child: Row(
children: [
Image.asset(
matchmakerIcons[widget.index]!,
width: 26.w,
height: 26.w,
),
SizedBox(width: 14.w,),
Expanded(
child: Text(
widget.title,
style: TextStyle(
fontSize: 11.w,
fontWeight: FontWeight.w500
),
),
)
],
),
);
}
}

316
lib/pages/mine/mine_page.dart

@ -4,14 +4,20 @@ import 'package:dating_touchme_app/controller/mine/mine_controller.dart';
import 'package:dating_touchme_app/extension/ex_widget.dart';
import 'package:dating_touchme_app/model/mine/user_count_data.dart';
import 'package:dating_touchme_app/network/user_api.dart';
import 'package:dating_touchme_app/pages/mine/auth_center_page.dart';
import 'package:dating_touchme_app/pages/mine/edit_info_page.dart';
import 'package:dating_touchme_app/pages/mine/my_friend_page.dart';
import 'package:dating_touchme_app/pages/mine/my_wallet_page.dart';
import 'package:dating_touchme_app/pages/mine/rose_page.dart';
import 'package:dating_touchme_app/pages/mine/user_help_center_page.dart';
import 'package:dating_touchme_app/pages/mine/vip_page.dart';
import 'package:dating_touchme_app/pages/setting/setting_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:dating_touchme_app/generated/assets.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart';
import '../discover/visitor_list_page.dart';
@ -80,9 +86,13 @@ class _MinePageState extends State<MinePage> with AutomaticKeepAliveClientMixin{
}
}
@override
Widget build(BuildContext context) {
super.build(context);
var cellStyle = TDCellStyle.cellStyle(context);
cellStyle.cardPadding = EdgeInsets.symmetric(horizontal: 0);
cellStyle.padding = EdgeInsets.only(left: 16, top: 12, bottom: 12, right: 12);
return GetX<MineController>(
init: MineController(),
builder: (controller) {
@ -223,7 +233,7 @@ class _MinePageState extends State<MinePage> with AutomaticKeepAliveClientMixin{
),
SizedBox(height: 16.w,),
Container(
height: 57.w,
// height: 57.w,
padding: EdgeInsets.only(
top: 11.w,
right: 42.w,
@ -266,27 +276,132 @@ class _MinePageState extends State<MinePage> with AutomaticKeepAliveClientMixin{
],
),
SizedBox(height: 12.w,),
ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(9.w)),
child: Column(
children: [
...controller.blockList.map((e){
return BlockItem(item: e, showWaring: e["title"] == "认证中心" && (GlobalData().userData?.identityCard == null || GlobalData().userData?.profilePhoto == null), path: e["path"],);
}),
],
),
// ClipRRect(
// borderRadius: BorderRadius.all(Radius.circular(9.w)),
// child: Column(
// children: [
// ...controller.blockList.map((e){
// return BlockItem(item: e, showWaring: e["title"] == "认证中心" && (GlobalData().userData?.identityCard == null || GlobalData().userData?.profilePhoto == null), path: e["path"],);
// }),
// ],
// ),
// ),
TDCellGroup(
theme: TDCellGroupTheme.cardTheme,
style: cellStyle,
cells: [
TDCell(arrow: true,
leftIconWidget: Image.asset(Assets.imagesRose, height: 22.w, width: 22.w),
titleWidget: Text(
"我的玫瑰",
style: TextStyle(
fontSize: 14.w
),
), onClick: (cell) {
Get.to(() => RosePage());
}
),
TDCell(arrow: true,
leftIconWidget: Image.asset(Assets.imagesWallet, height: 22.w, width: 22.w),
titleWidget: Text(
"我的钱包",
style: TextStyle(
fontSize: 14.w
),
), onClick: (cell) {
Get.to(() => MyWalletPage());
}
),
TDCell(arrow: true,
leftIconWidget: Image.asset(Assets.imagesCert, height: 22.w, width: 22.w),
titleWidget: Text(
"认证中心",
style: TextStyle(
fontSize: 14.w
),
),
noteWidget: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if(GlobalData().userData?.identityCard == null || GlobalData().userData?.profilePhoto == null) TDBadge(TDBadgeType.redPoint),
SizedBox(width: 5.w, height: 9.w),
Text(
GlobalData().userData?.identityCard == null || GlobalData().userData?.profilePhoto == null ? "未认证" : "已认证",
style: TextStyle(fontSize: 12.w, color: const Color.fromRGBO(166, 166, 166, 1)),
)
],
),
onClick: (cell) {
Get.to(() => AuthCenterPage());
}
),
TDCell(arrow: true,
leftIconWidget: Image.asset(Assets.imagesMatchmaker, height: 22.w, width: 22.w),
titleWidget: Text(
"红娘等级",
style: TextStyle(
fontSize: 14.w
),
), onClick: (cell) {
controller.registerMatch();
}
),
],
),
SizedBox(height: 12.w,),
ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(9.w)),
child: Column(
children: [
...controller.settingList.map((e){
return SettingItem(item: e, path: e["path"],);
})
],
),
TDCellGroup(
theme: TDCellGroupTheme.cardTheme,
style: cellStyle,
cells: [
TDCell(arrow: true,
leftIconWidget: Image.asset(Assets.imagesSetting, height: 22.w, width: 22.w),
titleWidget: Text(
"设置",
style: TextStyle(
fontSize: 14.w
),
), onClick: (cell) {
Get.to(() => SettingPage());
}
),
TDCell(arrow: true,
leftIconWidget: Image.asset(Assets.imagesCustomer, height: 22.w, width: 22.w),
titleWidget: Text(
"联系客服",
style: TextStyle(
fontSize: 14.w
),
), onClick: (cell) {
SmartDialog.showToast('功能暂未开放');
}
),
TDCell(arrow: true,
leftIconWidget: Image.asset(Assets.imagesMail, height: 22.w, width: 22.w),
titleWidget: Text(
"意见反馈",
style: TextStyle(
fontSize: 14.w
),
), onClick: (cell) {
Get.to(() => UserHelpCenterPage());
}
),
],
),
// ClipRRect(
// borderRadius: BorderRadius.all(Radius.circular(9.w)),
// child: Column(
// children: [
// ...controller.settingList.map((e){
// return SettingItem(item: e, path: e["path"],);
// })
// ],
// ),
// ),
],
),
);
@ -294,18 +409,11 @@ class _MinePageState extends State<MinePage> with AutomaticKeepAliveClientMixin{
);
}
@override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
}
class InfoItem extends StatefulWidget {
final Map item;
final Function getUserCount;
@ -329,7 +437,7 @@ class _InfoItemState extends State<InfoItem> {
Text(
"${widget.item["num"]}",
style: TextStyle(
fontSize: 15.w,
fontSize: 18.w,
color: Colors.black,
fontWeight: FontWeight.w700
),
@ -376,158 +484,4 @@ class _InfoItemState extends State<InfoItem> {
})
);
}
}
class BlockItem extends StatefulWidget {
final Map item;
final bool showWaring;
final Function path;
const BlockItem({super.key, required this.item, this.showWaring = false, required this.path});
@override
State<BlockItem> createState() => _BlockItemState();
}
class _BlockItemState extends State<BlockItem> {
@override
Widget build(BuildContext context) {
return InkWell(
onTap: (){
// context.pushNamed(widget.path);
if(widget.path() != null){
Get.to(widget.path)?.then((e){
setState(() {
});
});
} else {
SmartDialog.showToast('功能暂未开放');
}
// RouteGuardService.to.toWithAuth(widget.path, null);
},
child: Container(
height: 48.w,
padding: EdgeInsets.only(left: 16.w),
decoration: BoxDecoration(
color: Colors.white
),
child: Container(
padding: EdgeInsets.only(right: 16.w),
decoration: BoxDecoration(
border: widget.item["title"] != "红娘等级" ? Border(
bottom: BorderSide(width: 1, color: const Color.fromRGBO(238, 238, 238, 1))
) : null
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Image.asset(
widget.item["icon"],
height: 22.w,
width: 22.w,
),
SizedBox(width: 16.w,),
Text(
widget.item["title"],
style: TextStyle(
fontSize: 14.w,
color: Colors.black,
fontWeight: FontWeight.w500
),
)
],
),
Row(
children: [
if(widget.showWaring) Container(
width: 5.w,
height: 5.w,
margin: EdgeInsets.only(right: 4.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.w)),
color: const Color.fromRGBO(255, 87, 51, 1)
),
),
if(widget.item["title"] == "认证中心") Text(
widget.item["subTitle"],
style: TextStyle(
fontSize: 11.w,
color: const Color.fromRGBO(166, 166, 166, 1)
),
),
SizedBox(width: 10.w,),
Image.asset(
Assets.imagesArrow,
width: 4.w,
)
],
)
],
),
),
),
);
}
}
class SettingItem extends StatefulWidget {
final Map item;
final Function path;
const SettingItem({super.key, required this.item, required this.path});
@override
State<SettingItem> createState() => _SettingItemState();
}
class _SettingItemState extends State<SettingItem> {
@override
Widget build(BuildContext context) {
return InkWell(
onTap: (){
if(widget.path() == null){
SmartDialog.showToast('功能暂未开放');
return;
}
// context.pushNamed(widget.path);
Get.to(widget.path);
// RouteGuardService.to.toWithAuth(widget.path, null);
},
child: Container(
height: 48.w,
padding: EdgeInsets.symmetric(horizontal: 16.w),
color: Colors.white,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Image.asset(
widget.item["icon"],
width: 24.w,
height: 24.w,
),
SizedBox(width: 14.w,),
Text(
widget.item["title"],
style: TextStyle(
fontSize: 14.w,
fontWeight: FontWeight.w500,
color: Colors.black
),
)
],
),
Image.asset(
Assets.imagesArrow,
width: 4.w,
height: 8.w,
)
],
),
),
);
}
}

1
lib/pages/mine/my_wallet_page.dart

@ -357,6 +357,7 @@ class _InfoItemState extends State<InfoItem> {
widget.item.tradeType == 113 ? "邀请分成" :
widget.item.tradeType == 114 ? "1V1语音" :
widget.item.tradeType == 115 ? "1V1视频" :
widget.item.tradeType == 116 ? "连麦收益" :
widget.item.tradeType == 201 ? "平台服务费" :
widget.item.tradeType == 202 ? "提现" : ""}",
style: TextStyle(

41
lib/pages/mine/rose_history_page.dart

@ -237,8 +237,8 @@ class ChatCouponItem extends StatefulWidget {
class _ChatCouponItemState extends State<ChatCouponItem> {
@override
Widget build(BuildContext context) {
return SizedBox(
height: 70.w,
return Container(
padding: EdgeInsets.symmetric(vertical: 15.w),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@ -272,25 +272,28 @@ class _ChatCouponItemState extends State<ChatCouponItem> {
)
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
widget.item.type == 1 ? "主动发起聊天" : "主动发起连麦",
style: TextStyle(
fontSize: 13.w,
color: const Color.fromRGBO(144, 144, 144, 1)
SizedBox(width: 10.w,),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
widget.item.remark ?? "",
style: TextStyle(
fontSize: 13.w,
color: const Color.fromRGBO(144, 144, 144, 1)
),
),
),
Text(
"-${widget.item.num}",
style: TextStyle(
fontSize: 13.w,
color: const Color.fromRGBO(227, 84, 84, 1)
Text(
"-${widget.item.num}",
style: TextStyle(
fontSize: 13.w,
color: const Color.fromRGBO(227, 84, 84, 1)
),
),
),
],
],
),
),
],
),

107
lib/pages/mine/signature_page.dart

@ -1,14 +1,12 @@
import 'package:dating_touchme_app/components/page_appbar.dart';
import 'package:dating_touchme_app/controller/mine/edit_info_controller.dart';
import 'package:dating_touchme_app/extension/ex_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart';
class SignaturePage extends StatelessWidget {
const SignaturePage({super.key});
@override
Widget build(BuildContext context) {
return GetX<EditInfoController>(
@ -16,75 +14,42 @@ class SignaturePage extends StatelessWidget {
builder: (controller) {
return Scaffold(
appBar: PageAppbar(title: "交友心声",),
body: Container(
padding: EdgeInsets.all(17.w),
child: TextField(
controller: controller.messageController.value,
maxLength: 50, //
minLines: 5, //
maxLines: 5, //
style: TextStyle(
fontSize: ScreenUtil().setWidth(13),
height: 1
),
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
vertical: 0,
horizontal: 0
),
hintText: "请输入交友心声",
border: const OutlineInputBorder(
borderSide: BorderSide.none, // //
),
// focusedBorder enabledBorder
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.all(Radius.circular(8.0)),
),
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.all(Radius.circular(8.0)),
),
),
onChanged: (value){
controller.message.value = value;
print(value);
},
),
),
bottomNavigationBar: Container(
margin: EdgeInsets.only(bottom: 30.w),
child: Container(
width: 350.w,
height: 45.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(45.w)),
gradient: LinearGradient(
begin: Alignment.centerLeft, // 90deg:
end: Alignment.centerRight,
colors: [
Color.fromRGBO(131, 89, 255, 1), //
Color.fromRGBO(77, 127, 231, 1), //
Color.fromRGBO(61, 138, 224, 1), //
],
stops: [0.0, 0.7753, 1.0], // 0%77.53%100%
),
),
child: Center(
child: Text(
"保存",
style: TextStyle(
fontSize: 18.w,
color: Colors.white,
fontWeight: FontWeight.w500
body: Column(
children: [
TDTextarea(
controller: controller.messageController.value,
hintText: '请输入交友心声',
maxLines: 5,
minLines: 5,
maxLength: 80,
indicator: true,
layout: TDTextareaLayout.vertical,
bordered: true,
onChanged: (value) {
controller.message.value = value;
},
),
),
),
).onTap(() async {
controller.savaDescribeInfo();
}),
),
const SizedBox(height: 48),
TDButton(
text: '保存',
width: MediaQuery.of(context).size.width - 50,
size: TDButtonSize.large,
type: TDButtonType.fill,
shape: TDButtonShape.round,
style: TDButtonStyle(
textColor: Colors.white,
backgroundColor: Color(0xFF7562F9),
),
activeStyle: TDButtonStyle(
textColor: Colors.white,
backgroundColor: Color(0xC37562F9),
),
onTap: (){
controller.savaDescribeInfo();
},
),
],
),
);
},
);

12
lib/pages/mine/withdraw_history_page.dart

@ -137,7 +137,11 @@ class WithdrawHistoryPage extends StatelessWidget {
color: (item.remitStatus ?? false) ? const Color.fromRGBO(25, 114, 248, 1) : const Color.fromRGBO(238, 129, 27, 1)
),
child: Text(
(item.remitStatus ?? false) ? "提现成功" :"处理中",
item.status == 1 ? "待审核" :
item.status == 2 && item.remitStatus == true ? "提现成功" :
item.status == 2 && (item.remitStatus ?? false) == false ? "待打款" :
item.status == 3 ? "审核失败" :
"",
style: TextStyle(
fontSize: 10.w,
color: Colors.white
@ -147,8 +151,8 @@ class WithdrawHistoryPage extends StatelessWidget {
],
),
SizedBox(height: 8.w,),
Text(
"${item.extDetailsInfo?.bankName}${item.extDetailsInfo?.cardNum!.substring(item.extDetailsInfo!.cardNum!.length - 4)}",
if(item.extDetailsInfo?.bankName != null && item.extDetailsInfo?.cardNum!.substring(item.extDetailsInfo!.cardNum!.length - 4) != null) Text(
"${item.extDetailsInfo?.bankName ?? ""}${item.extDetailsInfo?.cardNum!.substring(item.extDetailsInfo!.cardNum!.length - 4) ?? ""}",
style: TextStyle(
fontSize: 12.w,
),
@ -172,7 +176,7 @@ class WithdrawHistoryPage extends StatelessWidget {
color: const Color.fromRGBO(153, 153, 153, 1)
),
),
Text(
if(item.remitUrl != "" && item.remitUrl != null)Text(
"查看打款凭证",
style: TextStyle(
fontSize: 12.w,

8
lib/pages/mine/withdraw_page.dart

@ -63,14 +63,6 @@ class WithdrawPage extends StatelessWidget {
fontWeight: FontWeight.w500
),
),
SizedBox(height: 6.w,),
Text(
"1个工作日内到账",
style: TextStyle(
fontSize: 12.w,
color: const Color.fromRGBO(153, 153, 153, 1)
),
)
],
),
if(controller.nowBankCard.value.id == null) Text(

7
lib/pages/setting/setting_page.dart

@ -26,6 +26,9 @@ class SettingPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
var cellStyle = TDCellStyle.cellStyle(context);
cellStyle.cardPadding = EdgeInsets.symmetric(horizontal: 10);
cellStyle.padding = EdgeInsets.only(left: 16, top: 12, bottom: 12, right: 12);
return Scaffold(
backgroundColor: Color(0xffF5F5F5),
appBar: PageAppbar(title: "设置"),
@ -36,6 +39,7 @@ class SettingPage extends StatelessWidget {
children: [
TDCellGroup(
theme: TDCellGroupTheme.cardTheme,
style: cellStyle,
cells: [
TDCell(
arrow: false,
@ -71,6 +75,7 @@ class SettingPage extends StatelessWidget {
const SizedBox(height: 12),
TDCellGroup(
theme: TDCellGroupTheme.cardTheme,
style: cellStyle,
cells: [
TDCell(arrow: true,
titleWidget: Text(
@ -113,6 +118,7 @@ class SettingPage extends StatelessWidget {
const SizedBox(height: 12),
TDCellGroup(
theme: TDCellGroupTheme.cardTheme,
style: cellStyle,
cells: [
TDCell(arrow: true,
titleWidget: Text(
@ -173,6 +179,7 @@ class SettingPage extends StatelessWidget {
const SizedBox(height: 12),
TDCellGroup(
theme: TDCellGroupTheme.cardTheme,
style: cellStyle,
cells: [
TDCell(arrow: true,
titleWidget: Text(

24
lib/rtc/rtc_manager.dart

@ -9,6 +9,7 @@ import 'package:get/get.dart';
import '../controller/discover/room_controller.dart';
import '../controller/message/call_controller.dart';
import '../pages/discover/live_room_page.dart';
import '../service/live_chat_message_service.dart';
enum RTCType {
call, // /
@ -208,6 +209,11 @@ class RTCManager {
channelId != null &&
channelId.isNotEmpty) {
final roomController = Get.find<RoomController>();
if(remoteUid == roomController.rtcChannelDetail.value?.anchorInfo?.uid){
await roomController.leaveChannel();
// LiveChatMessageService
LiveChatMessageService.instance.handleEndLiveMessage();
}
await roomController.fetchRtcChannelDetail(channelId);
}
}
@ -232,8 +238,22 @@ class RTCManager {
RtcConnection connection,
ConnectionStateType state,
ConnectionChangedReasonType reason,
) {
print('连接状态改变:$state,原因:$reason');
) async{
if(state == ConnectionStateType.connectionStateFailed &&
reason == ConnectionChangedReasonType.connectionChangedBannedByServer){
if (Get.isRegistered<RoomController>()) {
final roomController = Get.find<RoomController>();
// RoomController.currentRole
final isNotBroadcaster = roomController.currentRole != CurrentRole.broadcaster;
if (isNotBroadcaster) {
await roomController.leaveChannel();
// LiveChatMessageService
LiveChatMessageService.instance.handleEndLiveMessage();
}
}
return;
}
print('连接状态改变:$state,原因:$reason, localUid: ${connection.localUid}');
if (onConnectionStateChanged != null) {
onConnectionStateChanged!(connection, state, reason);
}

4
lib/service/live_chat_message_service.dart

@ -72,7 +72,7 @@ class LiveChatMessageService {
if (messageData['type'] == 'end_live') {
RoomController controller = Get.find<RoomController>();
await controller.leaveChannel();
_handleEndLiveMessage();
handleEndLiveMessage();
return;
}
@ -119,7 +119,7 @@ class LiveChatMessageService {
}
///
void _handleEndLiveMessage() {
void handleEndLiveMessage() {
try {
// overlay
if (Get.isRegistered<OverlayController>()) {

287
lib/widget/message/chat_input_bar.dart

@ -1,8 +1,9 @@
import 'package:dating_touchme_app/extension/ex_widget.dart';
import 'package:extended_text/extended_text.dart';
import 'package:extended_text_field/extended_text_field.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:extended_text_field/extended_text_field.dart';
import '../../generated/assets.dart';
import '../../config/emoji_config.dart';
@ -10,135 +11,6 @@ import '../emoji_panel.dart';
import 'more_options_view.dart';
import 'voice_input_view.dart';
/// - ExtendedTextField
class EmojiSpecialTextSpanBuilder extends SpecialTextSpanBuilder {
@override
SpecialText? createSpecialText(
String flag, {
TextStyle? textStyle,
SpecialTextGestureTapCallback? onTap,
required int index,
}) {
// [emoji:xxx]
if (flag.startsWith('[emoji:')) {
return EmojiSpecialText(
textStyle: textStyle,
onTap: onTap,
);
}
return null;
}
}
///
class EmojiSpecialText extends SpecialText {
EmojiSpecialText({
TextStyle? textStyle,
SpecialTextGestureTapCallback? onTap,
}) : super(
'[emoji:',
']',
textStyle,
onTap: onTap,
);
@override
InlineSpan finishText() {
// ID
final emojiId = toString().replaceAll('[emoji:', '').replaceAll(']', '');
final emoji = EmojiConfig.getEmojiById(emojiId);
if (emoji != null) {
// WidgetSpan
return WidgetSpan(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 2.w),
child: Image.asset(
emoji.path,
width: 24.w,
height: 24.w,
fit: BoxFit.contain,
),
),
);
}
//
return TextSpan(
text: toString(),
style: textStyle,
);
}
}
/// -
class EmojiTextInputFormatter extends TextInputFormatter {
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue,
TextEditingValue newValue,
) {
//
if (newValue.text.length < oldValue.text.length) {
final oldSelection = oldValue.selection;
final cursorOffset = oldSelection.baseOffset;
final deletedLength = oldValue.text.length - newValue.text.length;
//
final emojiRegex = RegExp(r'\[emoji:\d+\]');
final allMatches = emojiRegex.allMatches(oldValue.text);
//
for (final match in allMatches) {
final emojiStart = match.start;
final emojiEnd = match.end;
//
if (cursorOffset > emojiStart && cursorOffset <= emojiEnd) {
//
final beforeEmoji = oldValue.text.substring(0, emojiStart);
final afterEmoji = oldValue.text.substring(emojiEnd);
final newText = beforeEmoji + afterEmoji;
//
//
// = -
final emojiLength = emojiEnd - emojiStart;
int newCursorOffset = (cursorOffset - emojiLength).clamp(0, newText.length);
return TextEditingValue(
text: newText,
selection: TextSelection.collapsed(offset: newCursorOffset),
);
}
//
if (cursorOffset == emojiStart) {
//
if (cursorOffset + deletedLength <= emojiEnd) {
//
final beforeEmoji = oldValue.text.substring(0, emojiStart);
final afterEmoji = oldValue.text.substring(emojiEnd);
final newText = beforeEmoji + afterEmoji;
//
// = -
final emojiLength = emojiEnd - emojiStart;
int newCursorOffset = (cursorOffset - emojiLength).clamp(0, newText.length);
return TextEditingValue(
text: newText,
selection: TextSelection.collapsed(offset: newCursorOffset),
);
}
}
}
}
return newValue;
}
}
class ChatInputBar extends StatefulWidget {
final ValueChanged<String> onSendMessage;
final ValueChanged<List<String>>? onImageSelected;
@ -159,6 +31,14 @@ class ChatInputBar extends StatefulWidget {
@override
State<ChatInputBar> createState() => _ChatInputBarState();
// key
static void closePanels(GlobalKey? key) {
final state = key?.currentState;
if (state != null && state is _ChatInputBarState) {
state.closeAllPanels();
}
}
}
class _ChatInputBarState extends State<ChatInputBar> {
@ -237,6 +117,11 @@ class _ChatInputBarState extends State<ChatInputBar> {
}
}
//
void closeAllPanels() {
_closeAllPanels();
}
@override
void initState() {
super.initState();
@ -260,11 +145,10 @@ class _ChatInputBarState extends State<ChatInputBar> {
//
final currentText = _textController.text;
final emojiText = '[emoji:${emoji.id}]';
final newText = currentText + emojiText;
_textController.text = newText;
_textController.text = currentText + emojiText;
//
_textController.selection = TextSelection.fromPosition(
TextPosition(offset: newText.length),
TextPosition(offset: _textController.text.length),
);
setState(() {}); //
}
@ -290,32 +174,37 @@ class _ChatInputBarState extends State<ChatInputBar> {
borderRadius: BorderRadius.circular(5.h),
),
padding: EdgeInsets.symmetric(horizontal: 16.w),
alignment: Alignment.center,
child: ExtendedTextField(
controller: _textController,
focusNode: _focusNode,
specialTextSpanBuilder: EmojiSpecialTextSpanBuilder(),
inputFormatters: [
EmojiTextInputFormatter(),
],
textAlignVertical: TextAlignVertical.center,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "请输入聊天内容~",
hintStyle: TextStyle(
fontSize: 14.sp,
color: Colors.grey,
child: Stack(
children: [
//
ExtendedTextField(
controller: _textController,
focusNode: _focusNode,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "请输入聊天内容~",
hintStyle: TextStyle(
fontSize: 14.sp,
color: Colors.grey,
),
contentPadding: EdgeInsets.only(
bottom: 10
),
),
inputFormatters: [
// Unicode的规则
FilteringTextInputFormatter.deny(RegExp(r'[\u200B]')), //
],
specialTextSpanBuilder: MySpecialTextSpanBuilder(),
style: TextStyle(
fontSize: 14.sp,
color: Colors.black, // specialTextSpanBuilder
),
onChanged: (value) {
setState(() {}); //
},
),
isDense: true,
contentPadding: EdgeInsets.symmetric(vertical: 0),
),
style: TextStyle(
fontSize: 14.sp,
color: Colors.black,
),
onChanged: (value) {
setState(() {}); //
},
],
),
),
),
@ -405,3 +294,85 @@ class _ChatInputBarState extends State<ChatInputBar> {
);
}
}
/// - TIMUIKitTextField
class MySpecialTextSpanBuilder extends SpecialTextSpanBuilder {
@override
SpecialText? createSpecialText(
String flag, {
TextStyle? textStyle,
SpecialTextGestureTapCallback? onTap,
required int index,
}) {
if (flag.isEmpty) {
return null;
}
// index start flag index - (flag.length - 1)
// 使 '[' startFlag EmojiText.flag = '['
if (isStart(flag, MyEmojiText.flag)) {
return MyEmojiText(
textStyle,
start: index - (MyEmojiText.flag.length - 1),
);
}
return null;
}
}
/// - TIMUIKitTextField EmojiText
class MyEmojiText extends SpecialText {
static const String flag = '[';
final int start;
MyEmojiText(
TextStyle? textStyle, {
required this.start,
}) : super(MyEmojiText.flag, ']', textStyle);
@override
InlineSpan finishText() {
// toString() "[emoji:11]"
final String key = toString();
// [emoji:]
final RegExp emojiPattern = RegExp(r'^\[emoji:(\d+)\]$');
final match = emojiPattern.firstMatch(key);
if (match != null && match.groupCount > 0) {
final emojiId = match.group(1);
if (emojiId != null && emojiId.isNotEmpty) {
final emoji = EmojiConfig.getEmojiById(emojiId);
if (emoji != null && emoji.path.isNotEmpty) {
// 使 ImageSpan TIMUIKitTextField
double size = 16;
final TextStyle ts = textStyle!;
if (ts.fontSize != null) {
// TIMUIKitTextField: size = ts.fontSize! * 1.44
// 使 flutter_screenutil
// fontSize 14.sp
size = ts.fontSize! * 1.44;
// sp ImageSpan
// flutter_screenutil .sp 使
} else {
// fontSize使 14.sp * 1.44
size = 14.w * 1.44;
}
return ImageSpan(
AssetImage(emoji.path),
actualText: key,
imageWidth: size,
imageHeight: size,
start: start,
margin: const EdgeInsets.all(0), //
);
}
}
}
//
return TextSpan(text: key, style: textStyle);
}
}

2
lib/widget/message/video_call_invite_dialog.dart

@ -2,6 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:dating_touchme_app/generated/assets.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
///
class VideoCallInviteDialog extends StatelessWidget {
@ -26,6 +27,7 @@ class VideoCallInviteDialog extends StatelessWidget {
@override
Widget build(BuildContext context) {
Get.log('VideoCallInviteDialog$callType');
return GestureDetector(
onTap: onTap,
child: Container(

4
pubspec.yaml

@ -81,7 +81,9 @@ dependencies:
ota_update: ^7.1.0
flutter_local_notifications: ^19.5.0
app_badge_plus: ^1.2.6
extended_text: ^15.0.2
extended_text_field: ^16.0.2
emoji_text_field: ^1.0.0
dev_dependencies:
flutter_test:
@ -148,4 +150,4 @@ flutter_launcher_icons:
ios: true
image_path: "assets/images/app_logo.jpg"
min_sdk_android: 21
remove_alpha_ios: true
remove_alpha_ios: true
Loading…
Cancel
Save