Przeglądaj źródła

[feat]增加定制人设弹窗,增加与原生对接的chatSuperReply,chatSuperSpeak,chatPrologue方法

云天逵 8 miesięcy temu
rodzic
commit
63ee8bca93
27 zmienionych plików z 1176 dodań i 36 usunięć
  1. BIN
      assets/images/icon_custom_character_add_market.webp
  2. 26 5
      lib/data/api/atmob_api.dart
  3. 99 0
      lib/data/api/atmob_api.g.dart
  4. 16 0
      lib/data/api/request/chat_prologue_request.dart
  5. 68 0
      lib/data/api/request/chat_prologue_request.g.dart
  6. 27 0
      lib/data/api/request/chat_super_reply_request.dart
  7. 76 0
      lib/data/api/request/chat_super_reply_request.g.dart
  8. 27 0
      lib/data/api/request/chat_super_speak_request.dart
  9. 76 0
      lib/data/api/request/chat_super_speak_request.g.dart
  10. 19 0
      lib/data/api/response/chat_prologue_response.dart
  11. 17 0
      lib/data/api/response/chat_prologue_response.g.dart
  12. 17 0
      lib/data/api/response/chat_super_reply_response.dart
  13. 15 0
      lib/data/api/response/chat_super_reply_response.g.dart
  14. 16 0
      lib/data/api/response/chat_super_speak_response.dart
  15. 17 0
      lib/data/api/response/chat_super_speak_response.g.dart
  16. 46 1
      lib/data/repository/chat_repository.dart
  17. 26 9
      lib/di/get_it.config.dart
  18. 126 0
      lib/dialog/custom_character/custom_character_add_controller.dart
  19. 82 0
      lib/dialog/custom_character/custom_character_add_dialog.dart
  20. 220 0
      lib/dialog/custom_character/custom_character_add_view.dart
  21. 8 0
      lib/module/keyboard_manage/keyboard_manage_controller.dart
  22. 1 0
      lib/module/profile/edit/profile_edit_controller.dart
  23. 17 1
      lib/module/profile/edit/profile_edit_page.dart
  24. 10 3
      lib/plugins/keyboard_android_platform.dart
  25. 117 17
      lib/plugins/keyboard_method_handler.dart
  26. 6 0
      lib/resource/assets.gen.dart
  27. 1 0
      lib/router/app_pages.dart

BIN
assets/images/icon_custom_character_add_market.webp


+ 26 - 5
lib/data/api/atmob_api.dart

@@ -8,6 +8,9 @@ import 'package:keyboard/data/api/request/character_custom_page_request.dart';
 import 'package:keyboard/data/api/request/character_custom_update_request.dart';
 import 'package:keyboard/data/api/request/character_page_request.dart';
 import 'package:keyboard/data/api/request/character_unlock_request.dart';
+import 'package:keyboard/data/api/request/chat_prologue_request.dart';
+import 'package:keyboard/data/api/request/chat_super_reply_request.dart';
+import 'package:keyboard/data/api/request/chat_super_speak_request.dart';
 import 'package:keyboard/data/api/request/complaint_submit_request.dart';
 import 'package:keyboard/data/api/request/config_request.dart';
 import 'package:keyboard/data/api/request/keyboard_character_list_request.dart';
@@ -28,6 +31,9 @@ import 'package:keyboard/data/api/response/character_custom_update_response.dart
 import 'package:keyboard/data/api/response/character_group_response.dart';
 import 'package:keyboard/data/api/response/character_page_response.dart';
 import 'package:keyboard/data/api/response/character_unlock_response.dart';
+import 'package:keyboard/data/api/response/chat_prologue_response.dart';
+import 'package:keyboard/data/api/response/chat_super_reply_response.dart';
+import 'package:keyboard/data/api/response/chat_super_speak_response.dart';
 import 'package:keyboard/data/api/response/config_response.dart';
 import 'package:keyboard/data/api/response/item_list_response.dart';
 import 'package:keyboard/data/api/response/item_retention_response.dart';
@@ -169,14 +175,13 @@ abstract class AtmobApi {
 
   // 选择键盘
   @POST("/project/keyboard/v1/keyboard/choose")
-  Future<BaseResponse>keyboardChoose(
-    @Body() KeyboardChooseRequest request,
-  );
+  Future<BaseResponse> keyboardChoose(@Body() KeyboardChooseRequest request);
+
   // 获取开场白列表
   @POST("/project/keyboard/v1/keyboard/prologue/list")
   Future<BaseResponse<KeyboardPrologueListResponse>> getPrologueList(
-      @Body() AppBaseRequest request,
-      );
+    @Body() AppBaseRequest request,
+  );
 
   //获取配置信息
   @POST("/project/keyboard/v1/confs")
@@ -206,5 +211,21 @@ abstract class AtmobApi {
     @Body() AppBaseRequest request,
   );
 
+  // 超会回
+  @POST("/project/keyboard/v1/chat/superReply")
+  Future<BaseResponse<ChatSuperReplyResponse>> chatSuperReply(
+    @Body() ChatSuperReplyRequest request,
+  );
+
+  //超会说
+  @POST("/project/keyboard/v1/chat/superSpeak")
+  Future<BaseResponse<ChatSuperSpeakResponse>> chatSuperSpeak(
+    @Body() ChatSuperSpeakRequest request,
+  );
 
+  //   开场白
+  @POST("/project/keyboard/v1/chat/prologue")
+  Future<BaseResponse<ChatPrologueResponse>> chatPrologue(
+    @Body() ChatPrologueRequest request,
+  );
 }

+ 99 - 0
lib/data/api/atmob_api.g.dart

@@ -964,6 +964,105 @@ class _AtmobApi implements AtmobApi {
     return _value;
   }
 
+  @override
+  Future<BaseResponse<ChatSuperReplyResponse>> chatSuperReply(
+    ChatSuperReplyRequest request,
+  ) async {
+    final _extra = <String, dynamic>{};
+    final queryParameters = <String, dynamic>{};
+    final _headers = <String, dynamic>{};
+    final _data = <String, dynamic>{};
+    _data.addAll(request.toJson());
+    final _options = _setStreamType<BaseResponse<ChatSuperReplyResponse>>(
+      Options(method: 'POST', headers: _headers, extra: _extra)
+          .compose(
+            _dio.options,
+            '/project/keyboard/v1/chat/superReply',
+            queryParameters: queryParameters,
+            data: _data,
+          )
+          .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)),
+    );
+    final _result = await _dio.fetch<Map<String, dynamic>>(_options);
+    late BaseResponse<ChatSuperReplyResponse> _value;
+    try {
+      _value = BaseResponse<ChatSuperReplyResponse>.fromJson(
+        _result.data!,
+        (json) => ChatSuperReplyResponse.fromJson(json as Map<String, dynamic>),
+      );
+    } on Object catch (e, s) {
+      errorLogger?.logError(e, s, _options);
+      rethrow;
+    }
+    return _value;
+  }
+
+  @override
+  Future<BaseResponse<ChatSuperSpeakResponse>> chatSuperSpeak(
+    ChatSuperSpeakRequest request,
+  ) async {
+    final _extra = <String, dynamic>{};
+    final queryParameters = <String, dynamic>{};
+    final _headers = <String, dynamic>{};
+    final _data = <String, dynamic>{};
+    _data.addAll(request.toJson());
+    final _options = _setStreamType<BaseResponse<ChatSuperSpeakResponse>>(
+      Options(method: 'POST', headers: _headers, extra: _extra)
+          .compose(
+            _dio.options,
+            '/project/keyboard/v1/chat/superSpeak',
+            queryParameters: queryParameters,
+            data: _data,
+          )
+          .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)),
+    );
+    final _result = await _dio.fetch<Map<String, dynamic>>(_options);
+    late BaseResponse<ChatSuperSpeakResponse> _value;
+    try {
+      _value = BaseResponse<ChatSuperSpeakResponse>.fromJson(
+        _result.data!,
+        (json) => ChatSuperSpeakResponse.fromJson(json as Map<String, dynamic>),
+      );
+    } on Object catch (e, s) {
+      errorLogger?.logError(e, s, _options);
+      rethrow;
+    }
+    return _value;
+  }
+
+  @override
+  Future<BaseResponse<ChatPrologueResponse>> chatPrologue(
+    ChatPrologueRequest request,
+  ) async {
+    final _extra = <String, dynamic>{};
+    final queryParameters = <String, dynamic>{};
+    final _headers = <String, dynamic>{};
+    final _data = <String, dynamic>{};
+    _data.addAll(request.toJson());
+    final _options = _setStreamType<BaseResponse<ChatPrologueResponse>>(
+      Options(method: 'POST', headers: _headers, extra: _extra)
+          .compose(
+            _dio.options,
+            '/project/keyboard/v1/chat/prologue',
+            queryParameters: queryParameters,
+            data: _data,
+          )
+          .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)),
+    );
+    final _result = await _dio.fetch<Map<String, dynamic>>(_options);
+    late BaseResponse<ChatPrologueResponse> _value;
+    try {
+      _value = BaseResponse<ChatPrologueResponse>.fromJson(
+        _result.data!,
+        (json) => ChatPrologueResponse.fromJson(json as Map<String, dynamic>),
+      );
+    } on Object catch (e, s) {
+      errorLogger?.logError(e, s, _options);
+      rethrow;
+    }
+    return _value;
+  }
+
   RequestOptions _setStreamType<T>(RequestOptions requestOptions) {
     if (T != dynamic &&
         !(requestOptions.responseType == ResponseType.bytes ||

+ 16 - 0
lib/data/api/request/chat_prologue_request.dart

@@ -0,0 +1,16 @@
+import 'package:json_annotation/json_annotation.dart';
+
+import '../../../base/app_base_request.dart';
+
+part 'chat_prologue_request.g.dart';
+
+@JsonSerializable()
+class ChatPrologueRequest extends AppBaseRequest {
+  @JsonKey(name: "name")
+  String name;
+
+  ChatPrologueRequest({required this.name});
+
+  @override
+  Map<String, dynamic> toJson() => _$ChatPrologueRequestToJson(this);
+}

+ 68 - 0
lib/data/api/request/chat_prologue_request.g.dart

@@ -0,0 +1,68 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'chat_prologue_request.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+ChatPrologueRequest _$ChatPrologueRequestFromJson(Map<String, dynamic> json) =>
+    ChatPrologueRequest(name: json['name'] as String)
+      ..appPlatform = (json['appPlatform'] as num).toInt()
+      ..os = json['os'] as String
+      ..osVersion = json['osVersion'] as String
+      ..packageName = json['packageName'] as String?
+      ..appVersionName = json['appVersionName'] as String?
+      ..appVersionCode = (json['appVersionCode'] as num?)?.toInt()
+      ..channelName = json['channelName'] as String?
+      ..appId = (json['appId'] as num?)?.toInt()
+      ..tgPlatform = (json['tgPlatform'] as num?)?.toInt()
+      ..oaid = json['oaid'] as String?
+      ..aaid = json['aaid'] as String?
+      ..androidId = json['androidId'] as String?
+      ..imei = json['imei'] as String?
+      ..simImei0 = json['simImei0'] as String?
+      ..simImei1 = json['simImei1'] as String?
+      ..mac = json['mac'] as String?
+      ..idfa = json['idfa'] as String?
+      ..idfv = json['idfv'] as String?
+      ..machineId = json['machineId'] as String?
+      ..brand = json['brand'] as String?
+      ..model = json['model'] as String?
+      ..wifiName = json['wifiName'] as String?
+      ..region = json['region'] as String?
+      ..locLng = (json['locLng'] as num?)?.toDouble()
+      ..locLat = (json['locLat'] as num?)?.toDouble()
+      ..authToken = json['authToken'] as String?;
+
+Map<String, dynamic> _$ChatPrologueRequestToJson(
+  ChatPrologueRequest instance,
+) => <String, dynamic>{
+  'appPlatform': instance.appPlatform,
+  'os': instance.os,
+  'osVersion': instance.osVersion,
+  'packageName': instance.packageName,
+  'appVersionName': instance.appVersionName,
+  'appVersionCode': instance.appVersionCode,
+  'channelName': instance.channelName,
+  'appId': instance.appId,
+  'tgPlatform': instance.tgPlatform,
+  'oaid': instance.oaid,
+  'aaid': instance.aaid,
+  'androidId': instance.androidId,
+  'imei': instance.imei,
+  'simImei0': instance.simImei0,
+  'simImei1': instance.simImei1,
+  'mac': instance.mac,
+  'idfa': instance.idfa,
+  'idfv': instance.idfv,
+  'machineId': instance.machineId,
+  'brand': instance.brand,
+  'model': instance.model,
+  'wifiName': instance.wifiName,
+  'region': instance.region,
+  'locLng': instance.locLng,
+  'locLat': instance.locLat,
+  'authToken': instance.authToken,
+  'name': instance.name,
+};

+ 27 - 0
lib/data/api/request/chat_super_reply_request.dart

@@ -0,0 +1,27 @@
+import 'package:json_annotation/json_annotation.dart';
+
+import '../../../base/app_base_request.dart';
+
+part 'chat_super_reply_request.g.dart';
+
+@JsonSerializable()
+class ChatSuperReplyRequest extends AppBaseRequest {
+  @JsonKey(name: "characterId")
+  String characterId;
+
+  @JsonKey(name: "keyboardId")
+  String keyboardId;
+
+  @JsonKey(name: "content")
+  String content;
+
+
+  ChatSuperReplyRequest({
+    required this.characterId,
+    required this.keyboardId,
+    required this.content,
+  });
+
+  @override
+  Map<String, dynamic> toJson() => _$ChatSuperReplyRequestToJson(this);
+}

+ 76 - 0
lib/data/api/request/chat_super_reply_request.g.dart

@@ -0,0 +1,76 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'chat_super_reply_request.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+ChatSuperReplyRequest _$ChatSuperReplyRequestFromJson(
+  Map<String, dynamic> json,
+) =>
+    ChatSuperReplyRequest(
+        characterId: json['characterId'] as String,
+        keyboardId: json['keyboardId'] as String,
+        content: json['content'] as String,
+      )
+      ..appPlatform = (json['appPlatform'] as num).toInt()
+      ..os = json['os'] as String
+      ..osVersion = json['osVersion'] as String
+      ..packageName = json['packageName'] as String?
+      ..appVersionName = json['appVersionName'] as String?
+      ..appVersionCode = (json['appVersionCode'] as num?)?.toInt()
+      ..channelName = json['channelName'] as String?
+      ..appId = (json['appId'] as num?)?.toInt()
+      ..tgPlatform = (json['tgPlatform'] as num?)?.toInt()
+      ..oaid = json['oaid'] as String?
+      ..aaid = json['aaid'] as String?
+      ..androidId = json['androidId'] as String?
+      ..imei = json['imei'] as String?
+      ..simImei0 = json['simImei0'] as String?
+      ..simImei1 = json['simImei1'] as String?
+      ..mac = json['mac'] as String?
+      ..idfa = json['idfa'] as String?
+      ..idfv = json['idfv'] as String?
+      ..machineId = json['machineId'] as String?
+      ..brand = json['brand'] as String?
+      ..model = json['model'] as String?
+      ..wifiName = json['wifiName'] as String?
+      ..region = json['region'] as String?
+      ..locLng = (json['locLng'] as num?)?.toDouble()
+      ..locLat = (json['locLat'] as num?)?.toDouble()
+      ..authToken = json['authToken'] as String?;
+
+Map<String, dynamic> _$ChatSuperReplyRequestToJson(
+  ChatSuperReplyRequest instance,
+) => <String, dynamic>{
+  'appPlatform': instance.appPlatform,
+  'os': instance.os,
+  'osVersion': instance.osVersion,
+  'packageName': instance.packageName,
+  'appVersionName': instance.appVersionName,
+  'appVersionCode': instance.appVersionCode,
+  'channelName': instance.channelName,
+  'appId': instance.appId,
+  'tgPlatform': instance.tgPlatform,
+  'oaid': instance.oaid,
+  'aaid': instance.aaid,
+  'androidId': instance.androidId,
+  'imei': instance.imei,
+  'simImei0': instance.simImei0,
+  'simImei1': instance.simImei1,
+  'mac': instance.mac,
+  'idfa': instance.idfa,
+  'idfv': instance.idfv,
+  'machineId': instance.machineId,
+  'brand': instance.brand,
+  'model': instance.model,
+  'wifiName': instance.wifiName,
+  'region': instance.region,
+  'locLng': instance.locLng,
+  'locLat': instance.locLat,
+  'authToken': instance.authToken,
+  'characterId': instance.characterId,
+  'keyboardId': instance.keyboardId,
+  'content': instance.content,
+};

+ 27 - 0
lib/data/api/request/chat_super_speak_request.dart

@@ -0,0 +1,27 @@
+import 'package:json_annotation/json_annotation.dart';
+
+import '../../../base/app_base_request.dart';
+
+part 'chat_super_speak_request.g.dart';
+
+@JsonSerializable()
+class ChatSuperSpeakRequest extends AppBaseRequest {
+  @JsonKey(name: "characterId")
+  String characterId;
+
+  @JsonKey(name: "keyboardId")
+  String keyboardId;
+
+  @JsonKey(name: "content")
+  String content;
+
+
+  ChatSuperSpeakRequest({
+    required this.characterId,
+    required this.keyboardId,
+    required this.content,
+  });
+
+  @override
+  Map<String, dynamic> toJson() => _$ChatSuperSpeakRequestToJson(this);
+}

+ 76 - 0
lib/data/api/request/chat_super_speak_request.g.dart

@@ -0,0 +1,76 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'chat_super_speak_request.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+ChatSuperSpeakRequest _$ChatSuperSpeakRequestFromJson(
+  Map<String, dynamic> json,
+) =>
+    ChatSuperSpeakRequest(
+        characterId: json['characterId'] as String,
+        keyboardId: json['keyboardId'] as String,
+        content: json['content'] as String,
+      )
+      ..appPlatform = (json['appPlatform'] as num).toInt()
+      ..os = json['os'] as String
+      ..osVersion = json['osVersion'] as String
+      ..packageName = json['packageName'] as String?
+      ..appVersionName = json['appVersionName'] as String?
+      ..appVersionCode = (json['appVersionCode'] as num?)?.toInt()
+      ..channelName = json['channelName'] as String?
+      ..appId = (json['appId'] as num?)?.toInt()
+      ..tgPlatform = (json['tgPlatform'] as num?)?.toInt()
+      ..oaid = json['oaid'] as String?
+      ..aaid = json['aaid'] as String?
+      ..androidId = json['androidId'] as String?
+      ..imei = json['imei'] as String?
+      ..simImei0 = json['simImei0'] as String?
+      ..simImei1 = json['simImei1'] as String?
+      ..mac = json['mac'] as String?
+      ..idfa = json['idfa'] as String?
+      ..idfv = json['idfv'] as String?
+      ..machineId = json['machineId'] as String?
+      ..brand = json['brand'] as String?
+      ..model = json['model'] as String?
+      ..wifiName = json['wifiName'] as String?
+      ..region = json['region'] as String?
+      ..locLng = (json['locLng'] as num?)?.toDouble()
+      ..locLat = (json['locLat'] as num?)?.toDouble()
+      ..authToken = json['authToken'] as String?;
+
+Map<String, dynamic> _$ChatSuperSpeakRequestToJson(
+  ChatSuperSpeakRequest instance,
+) => <String, dynamic>{
+  'appPlatform': instance.appPlatform,
+  'os': instance.os,
+  'osVersion': instance.osVersion,
+  'packageName': instance.packageName,
+  'appVersionName': instance.appVersionName,
+  'appVersionCode': instance.appVersionCode,
+  'channelName': instance.channelName,
+  'appId': instance.appId,
+  'tgPlatform': instance.tgPlatform,
+  'oaid': instance.oaid,
+  'aaid': instance.aaid,
+  'androidId': instance.androidId,
+  'imei': instance.imei,
+  'simImei0': instance.simImei0,
+  'simImei1': instance.simImei1,
+  'mac': instance.mac,
+  'idfa': instance.idfa,
+  'idfv': instance.idfv,
+  'machineId': instance.machineId,
+  'brand': instance.brand,
+  'model': instance.model,
+  'wifiName': instance.wifiName,
+  'region': instance.region,
+  'locLng': instance.locLng,
+  'locLat': instance.locLat,
+  'authToken': instance.authToken,
+  'characterId': instance.characterId,
+  'keyboardId': instance.keyboardId,
+  'content': instance.content,
+};

+ 19 - 0
lib/data/api/response/chat_prologue_response.dart

@@ -0,0 +1,19 @@
+import 'package:json_annotation/json_annotation.dart';
+
+part 'chat_prologue_response.g.dart';
+
+@JsonSerializable()
+class ChatPrologueResponse {
+  @JsonKey(name: "list")
+  List<String>? list;
+
+
+
+  ChatPrologueResponse({ this.list});
+
+
+  factory ChatPrologueResponse.fromJson(Map<String, dynamic> json) =>
+      _$ChatPrologueResponseFromJson(json);
+
+  Map<String, dynamic> toJson() => _$ChatPrologueResponseToJson(this);
+}

+ 17 - 0
lib/data/api/response/chat_prologue_response.g.dart

@@ -0,0 +1,17 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'chat_prologue_response.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+ChatPrologueResponse _$ChatPrologueResponseFromJson(
+  Map<String, dynamic> json,
+) => ChatPrologueResponse(
+  list: (json['list'] as List<dynamic>?)?.map((e) => e as String).toList(),
+);
+
+Map<String, dynamic> _$ChatPrologueResponseToJson(
+  ChatPrologueResponse instance,
+) => <String, dynamic>{'list': instance.list};

+ 17 - 0
lib/data/api/response/chat_super_reply_response.dart

@@ -0,0 +1,17 @@
+import 'package:json_annotation/json_annotation.dart';
+
+part 'chat_super_reply_response.g.dart';
+
+@JsonSerializable()
+class ChatSuperReplyResponse {
+  @JsonKey(name: "content")
+  String? content;
+
+  ChatSuperReplyResponse({ this.content});
+
+
+  factory ChatSuperReplyResponse.fromJson(Map<String, dynamic> json) =>
+      _$ChatSuperReplyResponseFromJson(json);
+
+  Map<String, dynamic> toJson() => _$ChatSuperReplyResponseToJson(this);
+}

+ 15 - 0
lib/data/api/response/chat_super_reply_response.g.dart

@@ -0,0 +1,15 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'chat_super_reply_response.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+ChatSuperReplyResponse _$ChatSuperReplyResponseFromJson(
+  Map<String, dynamic> json,
+) => ChatSuperReplyResponse(content: json['content'] as String?);
+
+Map<String, dynamic> _$ChatSuperReplyResponseToJson(
+  ChatSuperReplyResponse instance,
+) => <String, dynamic>{'content': instance.content};

+ 16 - 0
lib/data/api/response/chat_super_speak_response.dart

@@ -0,0 +1,16 @@
+import 'package:json_annotation/json_annotation.dart';
+
+part 'chat_super_speak_response.g.dart';
+
+@JsonSerializable()
+class ChatSuperSpeakResponse {
+  @JsonKey(name: "list")
+  List<String>? list;
+
+  ChatSuperSpeakResponse({ this.list});
+
+
+  factory ChatSuperSpeakResponse.fromJson(Map<String, dynamic> json) =>
+      _$ChatSuperSpeakResponseFromJson(json);
+  Map<String, dynamic> toJson() => _$ChatSuperSpeakResponseToJson(this);
+}

+ 17 - 0
lib/data/api/response/chat_super_speak_response.g.dart

@@ -0,0 +1,17 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'chat_super_speak_response.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+ChatSuperSpeakResponse _$ChatSuperSpeakResponseFromJson(
+  Map<String, dynamic> json,
+) => ChatSuperSpeakResponse(
+  list: (json['list'] as List<dynamic>?)?.map((e) => e as String).toList(),
+);
+
+Map<String, dynamic> _$ChatSuperSpeakResponseToJson(
+  ChatSuperSpeakResponse instance,
+) => <String, dynamic>{'list': instance.list};

+ 46 - 1
lib/data/repository/chat_repository.dart

@@ -1,24 +1,69 @@
+import 'dart:async';
 import 'dart:convert';
 
 import 'package:injectable/injectable.dart';
+import 'package:keyboard/data/api/request/chat_prologue_request.dart';
+import 'package:keyboard/data/api/response/chat_prologue_response.dart';
+import 'package:keyboard/data/api/response/chat_super_reply_response.dart';
+import 'package:keyboard/data/api/response/chat_super_speak_response.dart';
 
 import '../../base/base_response.dart';
 import '../../utils/atmob_log.dart';
 import '../../utils/http_handler.dart';
 import '../../utils/sse_parse_util.dart';
+import '../api/atmob_api.dart';
 import '../api/atmob_stream_api.dart';
+import '../api/request/chat_super_reply_request.dart';
+import '../api/request/chat_super_speak_request.dart';
 import '../api/request/deep_seek_chat_request.dart';
 
 @lazySingleton
 class ChatRepository {
   final AtmobStreamApi atmobStreamApi;
+  final AtmobApi atmobApi;
   var tag = "ChatRepository";
 
-  ChatRepository(this.atmobStreamApi) {
+  ChatRepository(this.atmobStreamApi, this.atmobApi) {
     AtmobLog.d(tag, '$tag....init');
   }
 
+  Future<ChatSuperReplyResponse> chatSuperReply({
+    required String content,
+    required String keyboardId,
+    required String characterId,
+  }) {
+    return atmobApi
+        .chatSuperReply(
+          ChatSuperReplyRequest(
+            content: content,
+            keyboardId: keyboardId,
+            characterId: characterId,
+          ),
+        )
+        .then(HttpHandler.handle(true));
+  }
+
+  Future<ChatSuperSpeakResponse> chatSuperSpeak({
+    required String content,
+    required String keyboardId,
+    required String characterId,
+  }) {
+    return atmobApi
+        .chatSuperSpeak(
+          ChatSuperSpeakRequest(
+            content: content,
+            keyboardId: keyboardId,
+            characterId: characterId,
+          ),
+        )
+        .then(HttpHandler.handle(true));
+  }
 
+  Future<ChatPrologueResponse> chatPrologue({required String name}) {
+    return atmobApi
+        .chatPrologue(ChatPrologueRequest(name: name))
+        .then(HttpHandler.handle(true));
+  }
 
   Future<Stream<Message>> streamDeepSeek(String chatContent) {
     return atmobStreamApi

+ 26 - 9
lib/di/get_it.config.dart

@@ -25,6 +25,8 @@ import '../data/repository/keyboard_repository.dart' as _i274;
 import '../data/repository/store_repository.dart' as _i987;
 import '../dialog/content/character_add_tab_controller.dart' as _i991;
 import '../dialog/content/character_tab_group_content_controller.dart' as _i293;
+import '../dialog/custom_character/custom_character_add_controller.dart'
+    as _i122;
 import '../module/about/about_controller.dart' as _i256;
 import '../module/browser/browser_controller.dart' as _i923;
 import '../module/character/character_controller.dart' as _i888;
@@ -75,9 +77,6 @@ extension GetItInjectableX on _i174.GetIt {
         gh<_i361.Dio>(instanceName: 'streamDio'),
       ),
     );
-    gh.lazySingleton<_i425.ChatRepository>(
-      () => _i425.ChatRepository(gh<_i329.AtmobStreamApi>()),
-    );
     gh.singleton<_i243.AtmobApi>(
       () => networkModule.provideAtmobApi(
         gh<_i361.Dio>(instanceName: 'defaultDio'),
@@ -107,6 +106,12 @@ extension GetItInjectableX on _i174.GetIt {
             currentKeyboardInfo: currentKeyboardInfo,
           ),
     );
+    gh.lazySingleton<_i425.ChatRepository>(
+      () => _i425.ChatRepository(
+        gh<_i329.AtmobStreamApi>(),
+        gh<_i243.AtmobApi>(),
+      ),
+    );
     gh.factory<_i244.ProfileController>(
       () => _i244.ProfileController(
         gh<_i274.KeyboardRepository>(),
@@ -119,19 +124,20 @@ extension GetItInjectableX on _i174.GetIt {
         gh<_i83.AccountRepository>(),
       ),
     );
+    gh.factory<_i935.GoodsSurpriseController>(
+      () => _i935.GoodsSurpriseController(gh<_i987.StoreRepository>()),
+    );
+    gh.lazySingleton<_i779.PaymentStatusManager>(
+      () => _i779.PaymentStatusManager(gh<_i987.StoreRepository>()),
+    );
     gh.lazySingleton<_i79.KeyboardAndroidPlatform>(
       () => _i79.KeyboardAndroidPlatform(
         gh<_i274.KeyboardRepository>(),
         gh<_i421.CharactersRepository>(),
         gh<_i83.AccountRepository>(),
+        gh<_i425.ChatRepository>(),
       ),
     );
-    gh.factory<_i935.GoodsSurpriseController>(
-      () => _i935.GoodsSurpriseController(gh<_i987.StoreRepository>()),
-    );
-    gh.lazySingleton<_i779.PaymentStatusManager>(
-      () => _i779.PaymentStatusManager(gh<_i987.StoreRepository>()),
-    );
     gh.factory<_i922.KeyboardManageController>(
       () => _i922.KeyboardManageController(gh<_i274.KeyboardRepository>()),
     );
@@ -158,6 +164,17 @@ extension GetItInjectableX on _i174.GetIt {
         currentKeyboardInfo: currentKeyboardInfo,
       ),
     );
+    gh.factoryParam<
+      _i122.CustomCharacterAddController,
+      _i497.KeyboardInfo,
+      dynamic
+    >(
+      (currentKeyboardInfo, _) => _i122.CustomCharacterAddController(
+        gh<_i421.CharactersRepository>(),
+        gh<_i274.KeyboardRepository>(),
+        currentKeyboardInfo: currentKeyboardInfo,
+      ),
+    );
     gh.factory<_i15.CharacterCustomController>(
       () => _i15.CharacterCustomController(gh<_i50.ConfigRepository>()),
     );

+ 126 - 0
lib/dialog/custom_character/custom_character_add_controller.dart

@@ -0,0 +1,126 @@
+import 'package:easy_refresh/easy_refresh.dart';
+import 'package:injectable/injectable.dart';
+import 'package:keyboard/base/base_controller.dart';
+import 'package:get/get.dart';
+import 'package:keyboard/data/repository/characters_repository.dart';
+import '../../data/api/response/character_custom_update_response.dart';
+import '../../data/bean/character_info.dart';
+import '../../data/bean/keyboard_info.dart';
+import '../../data/repository/keyboard_repository.dart';
+import '../../utils/atmob_log.dart';
+import '../../utils/http_handler.dart';
+import '../../utils/toast_util.dart';
+
+@injectable
+class CustomCharacterAddController extends BaseController {
+  final String tag = "CustomCharacterAddController";
+
+  final CharactersRepository charactersRepository;
+
+  final KeyboardRepository keyboardRepository;
+  final RxInt _currentPage = 1.obs;
+
+  final RxInt _currentListCount = 0.obs;
+
+  final RxList<CharacterInfo> _characterList = <CharacterInfo>[].obs;
+
+  List<CharacterInfo> get characterList => _characterList;
+
+  KeyboardInfo currentKeyboardInfo;
+
+  late EasyRefreshController refreshController;
+
+  @factoryMethod
+  CustomCharacterAddController(
+    this.charactersRepository,
+    this.keyboardRepository, {
+    @factoryParam required this.currentKeyboardInfo,
+  });
+
+  @override
+  void onInit() {
+    super.onInit();
+    refreshController = EasyRefreshController(
+      controlFinishLoad: true,
+      controlFinishRefresh: true,
+    );
+
+    refreshData();
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    AtmobLog.d(tag, "onReady");
+  }
+
+  // 下拉刷新
+  Future<void> refreshData() async {
+    _currentPage.value = 1;
+    await getCurrentCharacterListInfo(isRefresh: true);
+    refreshController.finishRefresh();
+    refreshController.resetFooter(); // 允许加载更多
+  }
+
+  // 上拉加载更多
+  Future<void> loadMoreData() async {
+    if (characterList.length >= _currentListCount.value) {
+      refreshController.finishLoad(IndicatorResult.noMore);
+      return;
+    }
+    _currentPage.value++;
+    await getCurrentCharacterListInfo(isRefresh: false);
+    refreshController.finishLoad(IndicatorResult.success);
+  }
+
+  @override
+  void onClose() {
+    super.onClose();
+    refreshController.dispose();
+  }
+
+  // 获取角色列表
+
+  Future<void> getCurrentCharacterListInfo({bool isRefresh = false}) async {
+    var response = await charactersRepository.getCustomCharactersPage(
+      pageSize: 10,
+      page: _currentPage.value,
+      keyboardId: currentKeyboardInfo.id.toString(),
+    );
+    if (response.characterInfos != null) {
+      if (isRefresh) {
+        _characterList.value = response.characterInfos!;
+      } else {
+        _characterList.addAll(response.characterInfos!);
+      }
+      if (response.count != null) {
+        _currentListCount.value = response.count!;
+      }
+    }
+  }
+
+  void itemButtonClick(CharacterInfo characterInfo) async {
+    AtmobLog.d(tag, 'characterInfo ${characterInfo.toJson()} ');
+    try {
+      if (characterInfo.id != null) {
+        CharacterCustomUpdateResponse characterCustomUpdateResponse =
+            await charactersRepository.addCustomCharacter(
+              characterId: characterInfo.id!,
+              keyboardId: currentKeyboardInfo.id.toString(),
+            );
+        int index = characterList.indexWhere(
+          (element) =>
+              element.id == characterCustomUpdateResponse.characterInfo.id,
+        );
+        if (index != -1) {
+          characterList[index] = characterCustomUpdateResponse.characterInfo;
+        }
+        ToastUtil.show("添加成功");
+      }
+    } catch (error) {
+      if (error is ServerErrorException) {
+        ToastUtil.show(error.message);
+      }
+    }
+  }
+}

+ 82 - 0
lib/dialog/custom_character/custom_character_add_dialog.dart

@@ -0,0 +1,82 @@
+import 'dart:ui';
+
+import 'package:flutter/cupertino.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+import 'package:keyboard/dialog/custom_character/custom_character_add_view.dart';
+
+import '../../data/bean/keyboard_info.dart';
+import '../../resource/assets.gen.dart';
+import '../../resource/colors.gen.dart';
+
+class CustomCharacterAddDialog {
+  static const String tag = 'CustomCharacterAddDialog';
+  static void show({
+    required KeyboardInfo currentKeyboardInfo,
+    required VoidCallback clickCallback,
+  }) {
+    SmartDialog.show(
+      tag: tag,
+      backType: SmartBackType.block,
+      clickMaskDismiss: false,
+      maskColor: ColorName.black70,
+      builder: (_) {
+        return SizedBox(
+          width: double.infinity,
+          height: double.infinity,
+          child: Column(
+            mainAxisAlignment: MainAxisAlignment.end,
+            children: [
+              Container(
+                padding: EdgeInsets.only(
+                  bottom: 28.h,
+                  left: 16.w,
+                  right: 16.w,
+                  top: 22.h,
+                ),
+                alignment: Alignment.topCenter,
+                width: double.infinity,
+                height: 712.h,
+                decoration: BoxDecoration(
+                  color: const Color(0xFFF6F5FA),
+                  borderRadius: BorderRadius.circular(20.r),
+                ),
+                child: Column(
+                  crossAxisAlignment: CrossAxisAlignment.start,
+                  mainAxisAlignment: MainAxisAlignment.start,
+                  children: [
+                    Row(
+                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                      children: [
+                        Assets.images.iconCustomCharacterAddMarket.image(
+                          width: 68.w,
+                          height: 20.h,
+                        ),
+                        GestureDetector(
+                          onTap: () {
+                            clickCallback();
+                            SmartDialog.dismiss();
+                          },
+                          child: Assets.images.iconDialogCloseBlack.image(
+                            width: 24.w,
+                            height: 24.w,
+                          ),
+                        ),
+                      ],
+                    ),
+                    SizedBox(height: 10.h),
+                    Expanded(
+                      child: CustomCharacterAddView(
+                        currentKeyboardInfo: currentKeyboardInfo,
+                      ),
+                    ),
+                  ],
+                ),
+              ),
+            ],
+          ),
+        );
+      },
+    );
+  }
+}

+ 220 - 0
lib/dialog/custom_character/custom_character_add_view.dart

@@ -0,0 +1,220 @@
+import 'package:cached_network_image/cached_network_image.dart';
+import 'package:easy_refresh/easy_refresh.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:flutter_slidable/flutter_slidable.dart';
+import 'package:keyboard/base/base_view.dart';
+import 'package:keyboard/dialog/custom_character/custom_character_add_controller.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+
+import '../../data/bean/character_info.dart';
+import '../../data/bean/keyboard_info.dart';
+import '../../data/repository/characters_repository.dart';
+import '../../data/repository/keyboard_repository.dart';
+import '../../di/get_it.dart';
+import '../../resource/assets.gen.dart';
+import '../../resource/string.gen.dart';
+import '../../utils/styles.dart';
+
+class CustomCharacterAddView extends BaseView<CustomCharacterAddController> {
+
+  final KeyboardInfo currentKeyboardInfo;
+
+
+  @override
+  String? get tag => "CustomCharacterAddController${currentKeyboardInfo.id}";
+
+  const CustomCharacterAddView({super.key, required this.currentKeyboardInfo});
+
+  @override
+  backgroundColor() => const Color(0xFFF6F5FA);
+
+  @override
+  Widget buildBody(BuildContext context) {
+    Get.delete<CustomCharacterAddController>(tag: tag);
+    Get.put(CustomCharacterAddController(
+        getIt.get<CharactersRepository>(),
+        getIt.get<KeyboardRepository>(),
+        currentKeyboardInfo: currentKeyboardInfo),
+        tag: tag);
+    return Column(
+      children: [
+        Expanded(
+          child: Obx(() {
+            return EasyRefresh(
+              controller: controller.refreshController,
+              header: const ClassicHeader(),
+              footer: ClassicFooter(
+                noMoreText: StringName.noMoreData,
+                failedText: StringName.loadFailed,
+                processedText: StringName.loadCompleted,
+                processingText: StringName.loading,
+              ),
+
+              // onRefresh: controller.refreshData,
+              onLoad: controller.loadMoreData,
+              child: ListView.separated(
+                itemCount: controller.characterList.length,
+                itemBuilder: (context, index) {
+                  return _buildListItem(
+                    characterInfo: controller.characterList[index],
+                  );
+                },
+                separatorBuilder: (BuildContext context, int index) {
+                  return SizedBox(
+                    width: double.infinity,
+                    height: 10.h,
+                    child: Container(color: const Color(0xFFF4F2FB)),
+                  );
+                },
+              ),
+            );
+          }),
+        ),
+      ],
+    );
+  }
+
+  Widget _buildListItem({required CharacterInfo characterInfo}) {
+    return GestureDetector(
+      onTap: () {
+        controller.itemButtonClick(characterInfo);
+      },
+      child: Container(
+        decoration: ShapeDecoration(
+          color: Colors.white,
+          shape: RoundedRectangleBorder(
+            borderRadius: BorderRadius.circular(12.r),
+          ),
+        ),
+        height: 88.h,
+        padding: EdgeInsets.symmetric(horizontal: 16.w),
+        child: Row(
+          children: [
+            _buildAvatar(imageUrl: characterInfo.imageUrl),
+            SizedBox(width: 8.w),
+            _buildCharacterInfo(characterInfo),
+            _buildActionButton(characterInfo),
+          ],
+        ),
+      ),
+    );
+  }
+
+
+  /// 角色头像
+  Widget _buildAvatar({required String? imageUrl}) {
+    return Container(
+      width: 60.r,
+      height: 60.r,
+      decoration: BoxDecoration(
+        borderRadius: BorderRadius.circular(8),
+        gradient: LinearGradient(
+          begin: Alignment.topCenter,
+          end: Alignment.bottomCenter,
+          colors: [Color(0xffebe6ff), Color(0xffffe6fe)],
+        ),
+      ),
+      child: CachedNetworkImage(
+        imageUrl: imageUrl ?? "",
+        width: 60.r,
+        height: 60.r,
+        fit: BoxFit.cover,
+      ),
+    );
+  }
+
+  /// 构建角色信息,包括名称、VIP标识和描述
+  Widget _buildCharacterInfo(CharacterInfo characterInfo) {
+    return Expanded(
+      child: Column(
+        mainAxisAlignment: MainAxisAlignment.center,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          Row(
+            children: [
+              Text(
+                characterInfo.name ?? "",
+                style: TextStyle(
+                  color: Colors.black.withAlpha(204),
+                  fontSize: 15.sp,
+                  fontWeight: FontWeight.w500,
+                ),
+              ),
+              SizedBox(width: 4.w),
+              characterInfo.isVip == true
+                  ? Assets.images.iconCharacterVip.image(
+                width: 38.w,
+                height: 16.h,
+              )
+                  : Container(),
+            ],
+          ),
+          Text(
+            characterInfo.description ?? "",
+            softWrap: true,
+            style: TextStyle(
+              color: Colors.black.withAlpha(153),
+              fontSize: 12.sp,
+              fontWeight: FontWeight.w400,
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+
+  ///  按钮
+  Widget _buildActionButton(CharacterInfo characterInfo) {
+    return InkWell(
+      onTap: () {
+        controller.itemButtonClick(characterInfo);
+      },
+      child: Container(
+        width: 72.w,
+        height: 28.h,
+        margin: EdgeInsets.only(left: 8.w),
+        decoration: BoxDecoration(
+          borderRadius: BorderRadius.circular(50.r),
+          gradient:
+          characterInfo.isAdd == true
+              ? null
+              : const LinearGradient(
+            colors: [Color(0xFF7D46FC), Color(0xFFBC87FF)],
+            begin: Alignment.topLeft,
+            end: Alignment.bottomRight,
+          ),
+          color: characterInfo.isAdd == true ? const Color(0xFFEDE8FF) : null,
+        ),
+        child: Row(
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: [
+            if (characterInfo.isLock == true && characterInfo.isVip == true)
+              Padding(
+                padding: EdgeInsets.only(right: 2.w),
+                child: Assets.images.iconCharacterLock.image(
+                  width: 18.r,
+                  height: 18.r,
+                ), // 锁定图标
+              ),
+            Text(
+              characterInfo.isLock == true && characterInfo.isVip == true
+                  ? StringName.characterUnlock
+                  : characterInfo.isAdd == true
+                  ? StringName.characterAdded
+                  : StringName.characterAdd,
+              style: TextStyle(
+                color:
+                characterInfo.isAdd == true
+                    ? const Color(0xFF7D46FC)
+                    : Colors.white,
+                fontSize: 14.sp,
+                fontWeight: FontWeight.w500,
+              ),
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}

+ 8 - 0
lib/module/keyboard_manage/keyboard_manage_controller.dart

@@ -6,6 +6,7 @@ import 'package:keyboard/base/base_controller.dart';
 import 'package:keyboard/data/bean/character_info.dart';
 import 'package:keyboard/data/repository/keyboard_repository.dart';
 import 'package:keyboard/dialog/character_add_dialog.dart';
+import 'package:keyboard/dialog/custom_character/custom_character_add_dialog.dart';
 import 'package:keyboard/module/character/content/character_group_content_controller.dart';
 import 'package:keyboard/resource/string.gen.dart';
 import 'package:keyboard/utils/atmob_log.dart';
@@ -501,6 +502,13 @@ class KeyboardManageController extends BaseController
 
   clickCustomCharacter() {
     AtmobLog.i(tag, 'clickCustomCharacter');
+    CustomCharacterAddDialog.show(currentKeyboardInfo: currentCustomKeyboardInfo, clickCallback: (){
+      getKeyboardCharacterList(
+        keyboardId: _currentCustomKeyboardInfo.value.id ?? "",
+        isCustom: true,
+      );
+
+    });
   }
 
   @override

+ 1 - 0
lib/module/profile/edit/profile_edit_controller.dart

@@ -58,6 +58,7 @@ class ProfileEditController extends BaseController {
     } else {
       _avatarUrl.value = _girlAvatars[0];
     }
+
   }
 
   clickSaveButton() {

+ 17 - 1
lib/module/profile/edit/profile_edit_page.dart

@@ -68,10 +68,11 @@ class ProfileEditPage extends BasePage<ProfileEditController> {
                               _buildIntimacySlider(),
                               SizedBox(height: 10.h),
                               _buildGenderCard(),
-
                               SizedBox(height: 10.h),
                               _buildBirthdayCard(),
                               SizedBox(height: 10.h),
+                              _buildRelationshipCard(),
+                              SizedBox(height: 10.h),
                             ],
                           ),
                         ),
@@ -205,6 +206,21 @@ class ProfileEditPage extends BasePage<ProfileEditController> {
     );
   }
 
+  Widget _buildRelationshipCard() {
+    return _buildListItem(
+      onTap: () {
+        debugPrint('点击了关系');
+      },
+      firstWidget: Text('关系', style: Styles.getTextStyleBlack204W400(14.sp)),
+      bottomWidget: Row(
+        children: [
+
+          Spacer(),
+          Assets.images.iconArrowRight.image(width: 24.w, height: 24.w),
+        ],
+      ),
+    );
+  }
   Widget _buildSaveButton() {
     return GestureDetector(
       onTap: () {

+ 10 - 3
lib/plugins/keyboard_android_platform.dart

@@ -7,6 +7,7 @@ import 'package:keyboard/data/repository/keyboard_repository.dart';
 import 'package:keyboard/utils/atmob_log.dart';
 
 import '../../di/get_it.dart';
+import '../data/repository/chat_repository.dart';
 import 'keyboard_android_service.dart';
 import 'keyboard_method_handler.dart';
 
@@ -18,16 +19,22 @@ class KeyboardAndroidPlatform {
   final KeyboardRepository keyboardRepository;
   final CharactersRepository charactersRepository;
   final AccountRepository accountRepository;
+  final ChatRepository chatRepository;
+
   final KeyboardAndroidService _keyboardAndroidService;
   final KeyboardMethodHandler _methodHandler;
 
-  KeyboardAndroidPlatform(this.keyboardRepository, this.charactersRepository,this.accountRepository)
-    : _keyboardAndroidService = KeyboardAndroidService(),
+  KeyboardAndroidPlatform(
+    this.keyboardRepository,
+    this.charactersRepository,
+    this.accountRepository,
+    this.chatRepository,
+  ) : _keyboardAndroidService = KeyboardAndroidService(),
       _methodHandler = KeyboardMethodHandler(
         keyboardRepository,
         charactersRepository,
         accountRepository,
-
+        chatRepository,
       ) {
     AtmobLog.d(_tag, '初始化 KeyboardAndroidPlatform');
     _init();

+ 117 - 17
lib/plugins/keyboard_method_handler.dart

@@ -1,17 +1,26 @@
 import 'dart:convert';
+
+import 'package:collection/collection.dart';
 import 'package:flutter/services.dart';
-import 'package:keyboard/data/bean/member_info.dart';
 import 'package:keyboard/data/repository/account_repository.dart';
 import 'package:keyboard/data/repository/characters_repository.dart';
+import 'package:keyboard/data/repository/chat_repository.dart';
 import 'package:keyboard/data/repository/keyboard_repository.dart';
+import 'package:keyboard/utils/atmob_log.dart';
+
+import '../data/api/response/chat_prologue_response.dart';
+import '../data/api/response/chat_super_speak_response.dart';
 import '../data/api/response/keyboard_list_response.dart';
-import '../data/bean/keyboard_info.dart';
+import '../utils/http_handler.dart';
 import '../utils/mmkv_util.dart';
+import '../utils/toast_util.dart';
 
 class KeyboardMethodHandler {
+  final tag = "KeyboardMethodHandler";
   final KeyboardRepository keyboardRepository;
   final CharactersRepository charactersRepository;
   final AccountRepository accountRepository;
+  final ChatRepository chatRepository;
 
   // 用处存储选中的键盘id
   static const String keyboardSelect = 'keyboard_select';
@@ -25,6 +34,7 @@ class KeyboardMethodHandler {
     this.keyboardRepository,
     this.charactersRepository,
     this.accountRepository,
+    this.chatRepository,
   );
 
   Future<dynamic> handleMethodCall(MethodCall call) async {
@@ -43,6 +53,12 @@ class KeyboardMethodHandler {
         return isLogin;
       case 'isMember':
         return isMember;
+      case 'chatSuperReply':
+        return _handleChatSuperReply(call);
+      case 'chatSuperSpeak':
+        return _handleChatSuperSpeak(call);
+      case 'chatPrologue':
+        return _handleChatPrologue(call);
 
       default:
         throw MissingPluginException('Not implemented: ${call.method}');
@@ -51,15 +67,25 @@ class KeyboardMethodHandler {
 
   Future<String> _handleGetKeyboardList(MethodCall call) async {
     String? type = call.arguments?['type'] as String?;
-    final keyboardList = await keyboardRepository.getKeyboardList(type: type);
-
-    final selectKeyboardId = KVUtil.getString(keyboardSelect, null);
 
-    if (selectKeyboardId != null) {
-      for (var element in keyboardList.keyboardInfos) {
-        if (element.id == selectKeyboardId) {
-          element.isSelect = true;
+    final keyboardList = await keyboardRepository.getKeyboardList(type: type);
+    final selectedKeyboardJson = KVUtil.getString(keyboardSelect, null);
+    if (selectedKeyboardJson != null) {
+      try {
+        final Map<String, dynamic> keyboardMap = jsonDecode(
+          selectedKeyboardJson,
+        );
+        final String? keyboardId = keyboardMap['id'] as String?;
+        if (keyboardId != null) {
+          for (var element in keyboardList.keyboardInfos) {
+            if (element.id == keyboardId) {
+              element.isSelect = true;
+              break;
+            }
+          }
         }
+      } catch (e) {
+        AtmobLog.e(tag, "解析本地选中键盘失败: $e");
       }
     }
     keyboardListResponse = keyboardList;
@@ -69,20 +95,28 @@ class KeyboardMethodHandler {
   Future<String> _handleSelectedKeyboard(MethodCall call) async {
     final String keyboardId = call.arguments['keyboardId'];
 
-    if ( keyboardListResponse.keyboardInfos.isEmpty) {
-      return jsonEncode({"error": "Keyboard list not initialized"});
+    if (keyboardListResponse.keyboardInfos.isEmpty) {
+      keyboardListResponse = await keyboardRepository.getKeyboardList();
+    }
+    final selectedKeyboard = keyboardListResponse.keyboardInfos
+        .firstWhereOrNull((element) => element.id == keyboardId);
+    if (selectedKeyboard != null) {
+      KVUtil.putString(keyboardSelect, jsonEncode(selectedKeyboard.toJson()));
     }
-    final selectedKeyboard = keyboardListResponse.keyboardInfos.firstWhere(
-      (element) => element.id == keyboardId,
-      orElse: () => KeyboardInfo(),
-    );
-    KVUtil.putString(keyboardSelect, jsonEncode(selectedKeyboard.toJson()));
     return "{}";
   }
 
   Future<String> _handleGetCurrentKeyboardInfo(MethodCall call) async {
     final String? keyboardJsonStr = KVUtil.getString(keyboardSelect, null);
-    return keyboardJsonStr ?? "{}";
+    if (keyboardJsonStr != null) {
+      try {
+        final jsonMap = jsonDecode(keyboardJsonStr);
+        return jsonEncode(jsonMap);
+      } catch (e) {
+        AtmobLog.e(tag, "Failed to decode keyboard JSON: $e");
+      }
+    }
+    return "{}";
   }
 
   Future<String> _handleGetCharacterList(MethodCall call) async {
@@ -98,4 +132,70 @@ class KeyboardMethodHandler {
     final prologueList = await keyboardRepository.getPrologueList();
     return jsonEncode(prologueList.toJson());
   }
+
+  // 超会回
+  Future<String> _handleChatSuperReply(MethodCall call) async {
+    final String content = call.arguments['content'];
+    final String keyboardId = call.arguments['keyboardId'];
+    final String characterId = call.arguments['characterId'];
+    try {
+      final chatSuperReplyResponse = await chatRepository.chatSuperReply(
+        content: content,
+        keyboardId: keyboardId,
+        characterId: characterId,
+      );
+
+      return jsonEncode(chatSuperReplyResponse.toJson());
+    } catch (error) {
+      if (error is ServerErrorException) {
+        AtmobLog.d(tag, "超会回失败: ${error.message}");
+        ToastUtil.show(error.message);
+      } else {
+        AtmobLog.d(tag, "超会回失败: $error");
+      }
+      return '{}';
+    }
+  }
+
+  // 超会说
+  Future<String> _handleChatSuperSpeak(MethodCall call) async {
+    final String content = call.arguments['content'];
+    final String keyboardId = call.arguments['keyboardId'];
+    final String characterId = call.arguments['characterId'];
+    final ChatSuperSpeakResponse chatSuperSpeakResponse;
+    try {
+      chatSuperSpeakResponse = await chatRepository.chatSuperSpeak(
+        content: content,
+        keyboardId: keyboardId,
+        characterId: characterId,
+      );
+      return jsonEncode(chatSuperSpeakResponse.toJson());
+    } catch (error) {
+      if (error is ServerErrorException) {
+        AtmobLog.d(tag, "超会说失败: ${error.message}");
+        ToastUtil.show(error.message);
+      } else {
+        AtmobLog.d(tag, "超会说失败: $error");
+      }
+      return '{}';
+    }
+  }
+
+  // 开场白
+  Future<String> _handleChatPrologue(MethodCall call) async {
+    final String name = call.arguments['name'];
+    final ChatPrologueResponse chatPrologueResponse;
+    try {
+      chatPrologueResponse = await chatRepository.chatPrologue(name: name);
+      return jsonEncode(chatPrologueResponse.toJson());
+    } catch (error) {
+      if (error is ServerErrorException) {
+        ToastUtil.show(error.message);
+        AtmobLog.i(tag, "开场白失败: ${error.message}");
+      } else {
+        AtmobLog.i(tag, "开场白失败: $error");
+      }
+      return '{}';
+    }
+  }
 }

+ 6 - 0
lib/resource/assets.gen.dart

@@ -271,6 +271,11 @@ class $AssetsImagesGen {
   AssetGenImage get iconCharacterVip =>
       const AssetGenImage('assets/images/icon_character_vip.webp');
 
+  /// File path: assets/images/icon_custom_character_add_market.webp
+  AssetGenImage get iconCustomCharacterAddMarket => const AssetGenImage(
+    'assets/images/icon_custom_character_add_market.webp',
+  );
+
   /// File path: assets/images/icon_custom_dialog_close.webp
   AssetGenImage get iconCustomDialogClose =>
       const AssetGenImage('assets/images/icon_custom_dialog_close.webp');
@@ -602,6 +607,7 @@ class $AssetsImagesGen {
     iconCharacterLock,
     iconCharacterMarket,
     iconCharacterVip,
+    iconCustomCharacterAddMarket,
     iconCustomDialogClose,
     iconDialogCloseBlack,
     iconDialogPayFail,

+ 1 - 0
lib/router/app_pages.dart

@@ -74,6 +74,7 @@ class AppBinding extends Bindings {
     lazyPut(() => getIt.get<DiscountController>());
     lazyPut(() => getIt.get<ProfileController>());
     lazyPut(() => getIt.get<ProfileEditController>());
+
   }
 
   void lazyPut<S>(InstanceBuilderCallback<S> builder) {