Bladeren bron

[feat]新增人设api,添加人设弹窗

云天逵 8 maanden geleden
bovenliggende
commit
f98361a0c6
47 gewijzigde bestanden met toevoegingen van 1415 en 70 verwijderingen
  1. BIN
      assets/images/bg_character_dialog.webp
  2. BIN
      assets/images/bg_character_dialog_image.webp
  3. BIN
      assets/images/icon_character_dialog_close.webp
  4. BIN
      assets/images/icon_character_dialog_logo.webp
  5. BIN
      assets/images/icon_character_lock.webp
  6. BIN
      assets/images/icon_character_vip.webp
  7. 22 0
      assets/string/base/string.xml
  8. 24 2
      lib/data/api/atmob_api.dart
  9. 100 0
      lib/data/api/atmob_api.g.dart
  10. 23 0
      lib/data/api/request/character_add_request.dart
  11. 72 0
      lib/data/api/request/character_add_request.g.dart
  12. 23 0
      lib/data/api/request/character_unlock_request.dart
  13. 74 0
      lib/data/api/request/character_unlock_request.g.dart
  14. 16 0
      lib/data/api/request/keyboard_list_request.dart
  15. 68 0
      lib/data/api/request/keyboard_list_request.g.dart
  16. 18 0
      lib/data/api/response/character_add_response.dart
  17. 20 0
      lib/data/api/response/character_add_response.g.dart
  18. 2 2
      lib/data/api/response/character_page_response.dart
  19. 5 2
      lib/data/api/response/character_page_response.g.dart
  20. 18 0
      lib/data/api/response/character_unlock_response.dart
  21. 20 0
      lib/data/api/response/character_unlock_response.g.dart
  22. 16 0
      lib/data/api/response/keyboard_list_response.dart
  23. 20 0
      lib/data/api/response/keyboard_list_response.g.dart
  24. 1 1
      lib/data/api/response/new_user_get_character_response.dart
  25. 2 2
      lib/data/api/response/new_user_get_character_response.g.dart
  26. 3 1
      lib/data/api/response/user_info_response.dart
  27. 2 1
      lib/data/api/response/user_info_response.g.dart
  28. 5 4
      lib/data/bean/character_group_info.dart
  29. 2 2
      lib/data/bean/character_group_info.g.dart
  30. 2 2
      lib/data/bean/character_info.dart
  31. 1 1
      lib/data/bean/character_info.g.dart
  32. 49 0
      lib/data/bean/keyboard_info.dart
  33. 28 0
      lib/data/bean/keyboard_info.g.dart
  34. 45 7
      lib/data/repository/characters_repository.dart
  35. 1 0
      lib/data/repository/config_repository.dart
  36. 37 0
      lib/data/repository/keyboard_repository.dart
  37. 12 0
      lib/di/get_it.config.dart
  38. 221 0
      lib/dialog/character_details_dialog.dart
  39. 38 24
      lib/module/character/character_controller.dart
  40. 17 18
      lib/module/character/character_view.dart
  41. 130 0
      lib/module/character/content/character_group_content_controller.dart
  42. 198 0
      lib/module/character/content/character_group_content_view.dart
  43. 30 0
      lib/resource/assets.gen.dart
  44. 26 0
      lib/resource/string.gen.dart
  45. 4 0
      lib/router/app_pages.dart
  46. 17 1
      pubspec.lock
  47. 3 0
      pubspec.yaml

BIN
assets/images/bg_character_dialog.webp


BIN
assets/images/bg_character_dialog_image.webp


BIN
assets/images/icon_character_dialog_close.webp


BIN
assets/images/icon_character_dialog_logo.webp


BIN
assets/images/icon_character_lock.webp


BIN
assets/images/icon_character_vip.webp


+ 22 - 0
assets/string/base/string.xml

@@ -66,4 +66,26 @@
     <string name="go_customize_character">去定制人设</string>
     <string name="go_customize_character_desc">定制你自己的专属人设</string>
     <string name="my_keyboard">我的键盘</string>
+    <string name="character_add">添加</string>
+    <string name="character_add_success">添加成功</string>
+    <string name="character_add_failed">添加失败</string>
+    <string name="character_added">已添加</string>
+    <string name="character_unlock">解锁</string>
+    <string name="character_unlock_success">已解锁</string>
+    <string name="character_unlock_failed">解锁失败</string>
+
+    <!--    下拉刷新-->
+    <string name="no_more_data">没有更多了</string>
+    <string name="loading">加载中...</string>
+    <string name="load_failed">请重试</string>
+    <string name="load_completed">加载完成</string>
+
+    <!--    人设详情弹窗-->
+    <string name="add_to_keyboard">添加到键盘</string>
+    <string name="added_to_keyboard">已添加到键盘</string>
+
+
+
+
+
 </resources>

+ 24 - 2
lib/data/api/atmob_api.dart

@@ -1,14 +1,20 @@
 import 'package:dio/dio.dart';
 import 'package:keyboard/base/base_response.dart';
+import 'package:keyboard/data/api/request/character_add_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/complaint_submit_request.dart';
 import 'package:keyboard/data/api/request/config_request.dart';
+import 'package:keyboard/data/api/request/keyboard_list_request.dart';
 import 'package:keyboard/data/api/request/login_request.dart';
 import 'package:keyboard/data/api/request/send_code_request.dart';
 import 'package:keyboard/data/api/request/user_info_setting_request.dart';
+import 'package:keyboard/data/api/response/character_add_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/config_response.dart';
+import 'package:keyboard/data/api/response/keyboard_list_response.dart';
 import 'package:keyboard/data/api/response/login_response.dart';
 import 'package:keyboard/data/api/response/new_user_get_character_response.dart';
 import 'package:keyboard/data/api/response/user_info_response.dart';
@@ -52,7 +58,7 @@ abstract class AtmobApi {
   @POST("/project/keyboard/v1/user/info/setting")
   Future<BaseResponse> setUserInfo(@Body() UserInfoSettingRequest request);
 
-//  获取新人流程人设列表
+  //  获取新人流程人设列表
   @POST("/project/keyboard/v1/character/newUser/getCharacter")
   Future<BaseResponse<NewUserGetCharacterResponse>> getNewUserCharactersPage(
     @Body() AppBaseRequest request,
@@ -64,12 +70,28 @@ abstract class AtmobApi {
     @Body() AppBaseRequest request,
   );
 
-  // 获取人设列表
+  // 分页查询系统人设列表
   @POST("/project/keyboard/v1/character/page")
   Future<BaseResponse<CharacterPageResponse>> getCharactersPage(
     @Body() CharacterPageRequest request,
   );
 
+  //  解锁系统人设
+  @POST("/project/keyboard/v1/character/unlock")
+  Future<BaseResponse<CharacterUnlockResponse>> unlockCharacter(
+    @Body() CharacterUnlockRequest request,
+  );
+
+  // 添加系统人设
+  @POST("/project/keyboard/v1/character/add")
+  Future<BaseResponse<CharacterAddResponse>> addCharacter(
+    @Body() CharacterAddRequest request,
+  );
+
+  // 获取键盘列表
+  @POST("/project/keyboard/v1/keyboard/list")
+  Future<BaseResponse<KeyboardListResponse>> getKeyboardList(@Body() KeyboardListRequest request);
+
   //获取配置信息
   @POST("/project/keyboard/v1/confs")
   Future<BaseResponse<ConfigResponse>> confs(@Body() ConfigRequest request);

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

@@ -312,6 +312,106 @@ class _AtmobApi implements AtmobApi {
   }
 
   @override
+  Future<BaseResponse<CharacterUnlockResponse>> unlockCharacter(
+    CharacterUnlockRequest 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<CharacterUnlockResponse>>(
+      Options(method: 'POST', headers: _headers, extra: _extra)
+          .compose(
+            _dio.options,
+            '/project/keyboard/v1/character/unlock',
+            queryParameters: queryParameters,
+            data: _data,
+          )
+          .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)),
+    );
+    final _result = await _dio.fetch<Map<String, dynamic>>(_options);
+    late BaseResponse<CharacterUnlockResponse> _value;
+    try {
+      _value = BaseResponse<CharacterUnlockResponse>.fromJson(
+        _result.data!,
+        (json) =>
+            CharacterUnlockResponse.fromJson(json as Map<String, dynamic>),
+      );
+    } on Object catch (e, s) {
+      errorLogger?.logError(e, s, _options);
+      rethrow;
+    }
+    return _value;
+  }
+
+  @override
+  Future<BaseResponse<CharacterAddResponse>> addCharacter(
+    CharacterAddRequest 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<CharacterAddResponse>>(
+      Options(method: 'POST', headers: _headers, extra: _extra)
+          .compose(
+            _dio.options,
+            '/project/keyboard/v1/character/add',
+            queryParameters: queryParameters,
+            data: _data,
+          )
+          .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)),
+    );
+    final _result = await _dio.fetch<Map<String, dynamic>>(_options);
+    late BaseResponse<CharacterAddResponse> _value;
+    try {
+      _value = BaseResponse<CharacterAddResponse>.fromJson(
+        _result.data!,
+        (json) => CharacterAddResponse.fromJson(json as Map<String, dynamic>),
+      );
+    } on Object catch (e, s) {
+      errorLogger?.logError(e, s, _options);
+      rethrow;
+    }
+    return _value;
+  }
+
+  @override
+  Future<BaseResponse<KeyboardListResponse>> getKeyboardList(
+    KeyboardListRequest 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<KeyboardListResponse>>(
+      Options(method: 'POST', headers: _headers, extra: _extra)
+          .compose(
+            _dio.options,
+            '/project/keyboard/v1/keyboard/list',
+            queryParameters: queryParameters,
+            data: _data,
+          )
+          .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)),
+    );
+    final _result = await _dio.fetch<Map<String, dynamic>>(_options);
+    late BaseResponse<KeyboardListResponse> _value;
+    try {
+      _value = BaseResponse<KeyboardListResponse>.fromJson(
+        _result.data!,
+        (json) => KeyboardListResponse.fromJson(json as Map<String, dynamic>),
+      );
+    } on Object catch (e, s) {
+      errorLogger?.logError(e, s, _options);
+      rethrow;
+    }
+    return _value;
+  }
+
+  @override
   Future<BaseResponse<ConfigResponse>> confs(ConfigRequest request) async {
     final _extra = <String, dynamic>{};
     final queryParameters = <String, dynamic>{};

+ 23 - 0
lib/data/api/request/character_add_request.dart

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

+ 72 - 0
lib/data/api/request/character_add_request.g.dart

@@ -0,0 +1,72 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'character_add_request.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+CharacterAddRequest _$CharacterAddRequestFromJson(Map<String, dynamic> json) =>
+    CharacterAddRequest(
+        characterId: json['characterId'] as String,
+        keyboardId: json['keyboardId'] 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> _$CharacterAddRequestToJson(
+  CharacterAddRequest 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,
+};

+ 23 - 0
lib/data/api/request/character_unlock_request.dart

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

+ 74 - 0
lib/data/api/request/character_unlock_request.g.dart

@@ -0,0 +1,74 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'character_unlock_request.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+CharacterUnlockRequest _$CharacterUnlockRequestFromJson(
+  Map<String, dynamic> json,
+) =>
+    CharacterUnlockRequest(
+        characterId: json['characterId'] as String,
+        keyboardId: json['keyboardId'] 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> _$CharacterUnlockRequestToJson(
+  CharacterUnlockRequest 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,
+};

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

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

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

@@ -0,0 +1,68 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'keyboard_list_request.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+KeyboardListRequest _$KeyboardListRequestFromJson(Map<String, dynamic> json) =>
+    KeyboardListRequest(type: json['type'] 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> _$KeyboardListRequestToJson(
+  KeyboardListRequest 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,
+  'type': instance.type,
+};

+ 18 - 0
lib/data/api/response/character_add_response.dart

@@ -0,0 +1,18 @@
+import 'package:json_annotation/json_annotation.dart';
+
+import '../../bean/character_info.dart';
+
+
+part 'character_add_response.g.dart';
+
+@JsonSerializable()
+class CharacterAddResponse {
+
+  @JsonKey(name: "characterInfos")
+  late final List<CharacterInfo> characterInfo;
+
+  CharacterAddResponse({ required this.characterInfo});
+
+  factory CharacterAddResponse.fromJson(Map<String, dynamic> json) =>
+      _$CharacterAddResponseFromJson(json);
+}

+ 20 - 0
lib/data/api/response/character_add_response.g.dart

@@ -0,0 +1,20 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'character_add_response.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+CharacterAddResponse _$CharacterAddResponseFromJson(
+  Map<String, dynamic> json,
+) => CharacterAddResponse(
+  characterInfo:
+      (json['characterInfos'] as List<dynamic>)
+          .map((e) => CharacterInfo.fromJson(e as Map<String, dynamic>))
+          .toList(),
+);
+
+Map<String, dynamic> _$CharacterAddResponseToJson(
+  CharacterAddResponse instance,
+) => <String, dynamic>{'characterInfos': instance.characterInfo};

+ 2 - 2
lib/data/api/response/character_page_response.dart

@@ -10,9 +10,9 @@ class CharacterPageResponse {
   @JsonKey(name: "count")
   late final int count;
   @JsonKey(name: "list")
-  late final List<CharacterInfo> characterInfo;
+  late final List<CharacterInfo> characterInfos;
 
-  CharacterPageResponse({required this.count, required this.characterInfo});
+  CharacterPageResponse({required this.count, required this.characterInfos});
 
   factory CharacterPageResponse.fromJson(Map<String, dynamic> json) =>
       _$CharacterPageResponseFromJson(json);

+ 5 - 2
lib/data/api/response/character_page_response.g.dart

@@ -10,7 +10,7 @@ CharacterPageResponse _$CharacterPageResponseFromJson(
   Map<String, dynamic> json,
 ) => CharacterPageResponse(
   count: (json['count'] as num).toInt(),
-  characterInfo:
+  characterInfos:
       (json['list'] as List<dynamic>)
           .map((e) => CharacterInfo.fromJson(e as Map<String, dynamic>))
           .toList(),
@@ -18,4 +18,7 @@ CharacterPageResponse _$CharacterPageResponseFromJson(
 
 Map<String, dynamic> _$CharacterPageResponseToJson(
   CharacterPageResponse instance,
-) => <String, dynamic>{'count': instance.count, 'list': instance.characterInfo};
+) => <String, dynamic>{
+  'count': instance.count,
+  'list': instance.characterInfos,
+};

+ 18 - 0
lib/data/api/response/character_unlock_response.dart

@@ -0,0 +1,18 @@
+import 'package:json_annotation/json_annotation.dart';
+
+import '../../bean/character_info.dart';
+
+
+part 'character_unlock_response.g.dart';
+
+@JsonSerializable()
+class CharacterUnlockResponse {
+
+  @JsonKey(name: "characterInfos")
+  late final List<CharacterInfo> characterInfo;
+
+  CharacterUnlockResponse({ required this.characterInfo});
+
+  factory CharacterUnlockResponse.fromJson(Map<String, dynamic> json) =>
+      _$CharacterUnlockResponseFromJson(json);
+}

+ 20 - 0
lib/data/api/response/character_unlock_response.g.dart

@@ -0,0 +1,20 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'character_unlock_response.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+CharacterUnlockResponse _$CharacterUnlockResponseFromJson(
+  Map<String, dynamic> json,
+) => CharacterUnlockResponse(
+  characterInfo:
+      (json['characterInfos'] as List<dynamic>)
+          .map((e) => CharacterInfo.fromJson(e as Map<String, dynamic>))
+          .toList(),
+);
+
+Map<String, dynamic> _$CharacterUnlockResponseToJson(
+  CharacterUnlockResponse instance,
+) => <String, dynamic>{'characterInfos': instance.characterInfo};

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

@@ -0,0 +1,16 @@
+import 'package:json_annotation/json_annotation.dart';
+
+import '../../bean/keyboard_info.dart';
+
+part 'keyboard_list_response.g.dart';
+
+@JsonSerializable()
+class KeyboardListResponse {
+  @JsonKey(name: "keyboardInfos")
+  List<KeyboardInfo>keyboardInfos;
+
+  KeyboardListResponse({required this.keyboardInfos});
+
+  factory KeyboardListResponse.fromJson(Map<String, dynamic> json) =>
+      _$KeyboardListResponseFromJson(json);
+}

+ 20 - 0
lib/data/api/response/keyboard_list_response.g.dart

@@ -0,0 +1,20 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'keyboard_list_response.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+KeyboardListResponse _$KeyboardListResponseFromJson(
+  Map<String, dynamic> json,
+) => KeyboardListResponse(
+  keyboardInfos:
+      (json['keyboardInfos'] as List<dynamic>)
+          .map((e) => KeyboardInfo.fromJson(e as Map<String, dynamic>))
+          .toList(),
+);
+
+Map<String, dynamic> _$KeyboardListResponseToJson(
+  KeyboardListResponse instance,
+) => <String, dynamic>{'keyboardInfos': instance.keyboardInfos};

+ 1 - 1
lib/data/api/response/new_user_get_character_response.dart

@@ -8,7 +8,7 @@ part 'new_user_get_character_response.g.dart';
 @JsonSerializable()
 class NewUserGetCharacterResponse {
 
-  @JsonKey(name: "list")
+  @JsonKey(name: "characterInfos")
   late final List<CharacterInfo> characterInfo;
 
   NewUserGetCharacterResponse({ required this.characterInfo});

+ 2 - 2
lib/data/api/response/new_user_get_character_response.g.dart

@@ -10,11 +10,11 @@ NewUserGetCharacterResponse _$NewUserGetCharacterResponseFromJson(
   Map<String, dynamic> json,
 ) => NewUserGetCharacterResponse(
   characterInfo:
-      (json['list'] as List<dynamic>)
+      (json['characterInfos'] as List<dynamic>)
           .map((e) => CharacterInfo.fromJson(e as Map<String, dynamic>))
           .toList(),
 );
 
 Map<String, dynamic> _$NewUserGetCharacterResponseToJson(
   NewUserGetCharacterResponse instance,
-) => <String, dynamic>{'list': instance.characterInfo};
+) => <String, dynamic>{'characterInfos': instance.characterInfo};

+ 3 - 1
lib/data/api/response/user_info_response.dart

@@ -4,7 +4,6 @@ import '../../bean/member_info.dart';
 
 part 'user_info_response.g.dart';
 
-
 @JsonSerializable()
 class UserInfoResponse {
   @JsonKey(name: 'userId')
@@ -37,6 +36,9 @@ class UserInfoResponse {
   @JsonKey(name: 'userIdOrSsid')
   String? userIdOrSsid;
 
+  @JsonKey(name: 'imageUrl')
+  String? imageUrl;
+
   @JsonKey(name: 'memberInfo')
   MemberInfo? memberInfo;
 

+ 2 - 1
lib/data/api/response/user_info_response.g.dart

@@ -21,7 +21,7 @@ UserInfoResponse _$UserInfoResponseFromJson(Map<String, dynamic> json) =>
       json['memberInfo'] == null
           ? null
           : MemberInfo.fromJson(json['memberInfo'] as Map<String, dynamic>),
-    );
+    )..imageUrl = json['imageUrl'] as String?;
 
 Map<String, dynamic> _$UserInfoResponseToJson(UserInfoResponse instance) =>
     <String, dynamic>{
@@ -35,5 +35,6 @@ Map<String, dynamic> _$UserInfoResponseToJson(UserInfoResponse instance) =>
       'birthday': instance.birthday,
       'intimacy': instance.intimacy,
       'userIdOrSsid': instance.userIdOrSsid,
+      'imageUrl': instance.imageUrl,
       'memberInfo': instance.memberInfo,
     };

+ 5 - 4
lib/data/bean/character_group_info.dart

@@ -1,3 +1,4 @@
+import 'package:injectable/injectable.dart';
 import 'package:json_annotation/json_annotation.dart';
 
 part 'character_group_info.g.dart';
@@ -6,19 +7,19 @@ part 'character_group_info.g.dart';
 class CharacterGroupInfo {
   //主题id
   @JsonKey(name: 'id')
-  late String id;
+   String? id;
 
   //主题名称
   @JsonKey(name: 'name')
-  late String name;
+   String? name;
 
   //icon
   @JsonKey(name: 'iconUrl')
   String? iconUrl;
 
   CharacterGroupInfo({
-    required this.id,
-    required this.name,
+     this.id,
+     this.name,
     this.iconUrl,
   });
 

+ 2 - 2
lib/data/bean/character_group_info.g.dart

@@ -8,8 +8,8 @@ part of 'character_group_info.dart';
 
 CharacterGroupInfo _$CharacterGroupInfoFromJson(Map<String, dynamic> json) =>
     CharacterGroupInfo(
-      id: json['id'] as String,
-      name: json['name'] as String,
+      id: json['id'] as String?,
+      name: json['name'] as String?,
       iconUrl: json['iconUrl'] as String?,
     );
 

+ 2 - 2
lib/data/bean/character_info.dart

@@ -6,7 +6,7 @@ part 'character_info.g.dart';
 class CharacterInfo {
   //人设id
   @JsonKey(name: 'id')
-  String? id;
+  String id;
 
   //人设名称
   @JsonKey(name: 'name')
@@ -34,7 +34,7 @@ class CharacterInfo {
   bool? isAdd;
 
   CharacterInfo({
-    this.id,
+    required this.id,
     this.name,
     this.imageUrl,
     this.description,

+ 1 - 1
lib/data/bean/character_info.g.dart

@@ -8,7 +8,7 @@ part of 'character_info.dart';
 
 CharacterInfo _$CharacterInfoFromJson(Map<String, dynamic> json) =>
     CharacterInfo(
-      id: json['id'] as String?,
+      id: json['id'] as String,
       name: json['name'] as String?,
       imageUrl: json['imageUrl'] as String?,
       description: json['description'] as String?,

+ 49 - 0
lib/data/bean/keyboard_info.dart

@@ -0,0 +1,49 @@
+import 'package:json_annotation/json_annotation.dart';
+
+part 'keyboard_info.g.dart';
+
+@JsonSerializable()
+class KeyboardInfo {
+  //键盘id
+  @JsonKey(name: 'id')
+  String? id;
+
+  //键盘类型 默认值 定制键盘
+  @JsonKey(name: 'type')
+  String? type;
+
+  // 名称
+  @JsonKey(name: 'name')
+  String? name;
+
+  // 性别
+  @JsonKey(name: 'gender')
+  int? gender;
+
+  // 生日
+  @JsonKey(name: 'birthday')
+  String? birthday;
+
+  // 亲密度
+  @JsonKey(name: 'intimacy')
+  int? intimacy;
+
+  //头像
+  @JsonKey(name: 'imageUrl')
+  String? imageUrl;
+
+  KeyboardInfo({
+    this.id,
+    this.type,
+    this.name,
+    this.gender,
+    this.birthday,
+    this.intimacy,
+    this.imageUrl,
+  });
+
+  factory KeyboardInfo.fromJson(Map<String, dynamic> json) =>
+      _$KeyboardInfoFromJson(json);
+
+  Map<String, dynamic> toJson() => _$KeyboardInfoToJson(this);
+}

+ 28 - 0
lib/data/bean/keyboard_info.g.dart

@@ -0,0 +1,28 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'keyboard_info.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+KeyboardInfo _$KeyboardInfoFromJson(Map<String, dynamic> json) => KeyboardInfo(
+  id: json['id'] as String?,
+  type: json['type'] as String?,
+  name: json['name'] as String?,
+  gender: (json['gender'] as num?)?.toInt(),
+  birthday: json['birthday'] as String?,
+  intimacy: (json['intimacy'] as num?)?.toInt(),
+  imageUrl: json['imageUrl'] as String?,
+);
+
+Map<String, dynamic> _$KeyboardInfoToJson(KeyboardInfo instance) =>
+    <String, dynamic>{
+      'id': instance.id,
+      'type': instance.type,
+      'name': instance.name,
+      'gender': instance.gender,
+      'birthday': instance.birthday,
+      'intimacy': instance.intimacy,
+      'imageUrl': instance.imageUrl,
+    };

+ 45 - 7
lib/data/repository/characters_repository.dart

@@ -1,11 +1,15 @@
 import 'package:injectable/injectable.dart';
 
 import 'package:get/get.dart';
+import 'package:keyboard/data/repository/keyboard_repository.dart';
 import '../../base/app_base_request.dart';
+import '../../di/get_it.dart';
 import '../../utils/atmob_log.dart';
 import '../../utils/http_handler.dart';
 import '../api/atmob_api.dart';
+import '../api/request/character_add_request.dart';
 import '../api/request/character_page_request.dart';
+import '../api/request/character_unlock_request.dart';
 import '../api/response/character_group_response.dart';
 import '../api/response/character_page_response.dart';
 import '../bean/character_group_info.dart';
@@ -15,6 +19,7 @@ class CharactersRepository {
   final AtmobApi atmobApi;
   final String tag = "CharactersRepository";
 
+  // 人设主题
   final RxList<CharacterGroupInfo> _characterGroupList =
       RxList<CharacterGroupInfo>();
 
@@ -22,10 +27,11 @@ class CharactersRepository {
 
   CharactersRepository(this.atmobApi) {
     AtmobLog.d(tag, '$tag....init');
+    getCharactersGroup();
   }
 
   // 获取主题
-  Future<CharacterGroupResponse> getCharactersGroup() {
+  Future<CharacterGroupResponse> getCharactersGroup() async {
     return atmobApi
         .getCharactersGroup(AppBaseRequest())
         .then(HttpHandler.handle(true))
@@ -36,12 +42,12 @@ class CharactersRepository {
   }
 
   //   获取人设列表
-  Future<CharacterPageResponse> getCharactersPage(
-    String groupId,
-    int page,
-    String keyboardId,
-    int pageSize,
-  ) {
+  Future<CharacterPageResponse> getCharactersPage({
+    required String groupId,
+    required String keyboardId,
+    int page = 1,
+    int pageSize = 5,
+  }) {
     return atmobApi
         .getCharactersPage(
           CharacterPageRequest(
@@ -53,4 +59,36 @@ class CharactersRepository {
         )
         .then(HttpHandler.handle(true));
   }
+
+  // 添加人设
+  Future<void> characterAdd({
+    required String characterId,
+    required String keyboardId,
+  }) {
+    return atmobApi
+        .addCharacter(
+          CharacterAddRequest(characterId: characterId, keyboardId: keyboardId),
+        )
+        .then(HttpHandler.handle(true));
+  }
+
+  // 解锁人设
+  Future<void> characterUnlock({
+    required String characterId,
+    required String keyboardId,
+  }) {
+    return atmobApi
+        .unlockCharacter(
+          CharacterUnlockRequest(
+            characterId: characterId,
+            keyboardId: keyboardId,
+          ),
+        )
+        .then(HttpHandler.handle(false));
+  }
+
+
+
+  static CharactersRepository getInstance() =>
+      getIt.get<CharactersRepository>();
 }

+ 1 - 0
lib/data/repository/config_repository.dart

@@ -1,5 +1,6 @@
 import 'package:injectable/injectable.dart';
 
+import '../../di/get_it.dart';
 import '../../utils/async_util.dart';
 import '../../utils/atmob_log.dart';
 import '../../utils/http_handler.dart';

+ 37 - 0
lib/data/repository/keyboard_repository.dart

@@ -0,0 +1,37 @@
+import 'package:get/get.dart';
+import 'package:injectable/injectable.dart';
+import 'package:keyboard/data/api/request/keyboard_list_request.dart';
+
+import '../../di/get_it.dart';
+import '../../utils/http_handler.dart';
+import '../api/atmob_api.dart';
+import '../api/response/keyboard_list_response.dart';
+import '../bean/keyboard_info.dart';
+
+@lazySingleton
+class KeyboardRepository {
+  final tag = "KeyboardRepository";
+  final AtmobApi atmobApi;
+  final RxList<KeyboardInfo> _keyboardInfoList = RxList();
+
+  RxList<KeyboardInfo> get keyboardInfoList => _keyboardInfoList;
+
+  KeyboardRepository(this.atmobApi) {
+    print('$tag....init');
+    refreshKeyboardList();
+  }
+
+  Future refreshKeyboardList() async {
+    return getKeyboardList().then((response) {
+      _keyboardInfoList.value = response.keyboardInfos;
+    });
+  }
+
+  Future<KeyboardListResponse> getKeyboardList({String? type}) {
+    return atmobApi
+        .getKeyboardList(KeyboardListRequest(type: type))
+        .then(HttpHandler.handle(true));
+  }
+
+  static KeyboardRepository getInstance() => getIt.get<KeyboardRepository>();
+}

+ 12 - 0
lib/di/get_it.config.dart

@@ -19,9 +19,12 @@ import '../data/repository/account_repository.dart' as _i83;
 import '../data/repository/characters_repository.dart' as _i421;
 import '../data/repository/chat_repository.dart' as _i425;
 import '../data/repository/config_repository.dart' as _i50;
+import '../data/repository/keyboard_repository.dart' as _i274;
 import '../module/about/about_controller.dart' as _i256;
 import '../module/browser/browser_controller.dart' as _i923;
 import '../module/character/character_controller.dart' as _i888;
+import '../module/character/content/character_group_content_controller.dart'
+    as _i970;
 import '../module/feedback/feedback_controller.dart' as _i876;
 import '../module/login/login_controller.dart' as _i1008;
 import '../module/main/main_controller.dart' as _i731;
@@ -74,6 +77,9 @@ extension GetItInjectableX on _i174.GetIt {
     gh.lazySingleton<_i50.ConfigRepository>(
       () => _i50.ConfigRepository(gh<_i243.AtmobApi>()),
     );
+    gh.lazySingleton<_i274.KeyboardRepository>(
+      () => _i274.KeyboardRepository(gh<_i243.AtmobApi>()),
+    );
     gh.factory<_i876.FeedbackController>(
       () => _i876.FeedbackController(gh<_i83.AccountRepository>()),
     );
@@ -84,6 +90,12 @@ extension GetItInjectableX on _i174.GetIt {
       () => _i888.CharacterController(
         gh<_i421.CharactersRepository>(),
         gh<_i50.ConfigRepository>(),
+        gh<_i274.KeyboardRepository>(),
+      ),
+    );
+    gh.factory<_i970.CharacterGroupContentController>(
+      () => _i970.CharacterGroupContentController(
+        gh<_i421.CharactersRepository>(),
       ),
     );
     return this;

+ 221 - 0
lib/dialog/character_details_dialog.dart

@@ -0,0 +1,221 @@
+import 'package:cached_network_image/cached_network_image.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+import 'package:keyboard/resource/string.gen.dart';
+
+import '../data/bean/character_info.dart';
+import '../resource/assets.gen.dart';
+import '../resource/colors.gen.dart';
+
+class CharacterDetailsDialog {
+  static const String tag = 'CharacterDetailsDialog';
+
+  static void show({
+    required CharacterInfo characterInfo,
+    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.center,
+            children: [
+              Container(
+                margin: EdgeInsets.only(left: 30.w, right: 30.w),
+                padding: EdgeInsets.only(bottom: 28.h),
+                alignment: Alignment.topCenter,
+                width: double.infinity,
+                decoration: BoxDecoration(
+                  image: DecorationImage(
+                    image: Assets.images.bgCharacterDialog.provider(),
+                    fit: BoxFit.cover,
+                  ),
+                  borderRadius: BorderRadius.circular(20.r),
+                ),
+                child: Column(
+                  children: [
+                    Container(
+                      padding: EdgeInsets.only(
+                        top: 12.h,
+                        left: 12.w,
+                        right: 12.w,
+                        bottom: 12.h,
+                      ),
+                      margin: EdgeInsets.only(
+                        left: 20.w,
+                        right: 20.w,
+                        top: 20.h,
+                      ),
+                      width: double.infinity,
+                      decoration: ShapeDecoration(
+                        color: Colors.white,
+                        shape: RoundedRectangleBorder(
+                          borderRadius: BorderRadius.circular(20.r),
+                        ),
+                        shadows: [
+                          BoxShadow(
+                            color: const Color(0xFFDDE2F9),
+                            blurRadius: 10.r,
+                            offset: Offset(0, 4),
+                            spreadRadius: 0,
+                          ),
+                        ],
+                      ),
+                      child: Column(
+                        crossAxisAlignment: CrossAxisAlignment.center,
+                        mainAxisAlignment: MainAxisAlignment.start,
+                        children: [
+                          Container(
+                            padding: EdgeInsets.only(
+                              top: 20.h,
+                              left: 20.w,
+                              right: 20.w,
+                            ),
+                            height: 236.w,
+                            width: 236.w,
+                            decoration: BoxDecoration(
+                              image: DecorationImage(
+                                image:
+                                    Assets.images.bgCharacterDialogImage
+                                        .provider(),
+                                fit: BoxFit.fill,
+                              ),
+                              borderRadius: BorderRadius.circular(20.r),
+                            ),
+                            child: CachedNetworkImage(
+                              imageUrl: characterInfo.imageUrl ?? "",
+                              fit: BoxFit.fill,
+                            ),
+                          ),
+                          SizedBox(height: 10.h),
+                          Row(
+                            crossAxisAlignment: CrossAxisAlignment.start,
+
+                            children: [
+                              Assets.images.iconCharacterDialogLogo.image(
+                                width: 32.r,
+                                height: 32.r,
+                              ),
+                              SizedBox(width: 10.w),
+                              Column(
+                                crossAxisAlignment: CrossAxisAlignment.start,
+                                children: [
+                                  Row(
+                                    children: [
+                                      Text(
+                                        characterInfo.name ?? "",
+                                        style: TextStyle(
+                                          color: Colors.black.withAlpha(204),
+                                          fontSize: 14.sp,
+                                          fontWeight: FontWeight.w700,
+                                        ),
+                                      ),
+                                      SizedBox(width: 4.w),
+                                      characterInfo.isVip == true
+                                          ? Assets.images.iconCharacterVip
+                                              .image(width: 38.w, height: 16.h)
+                                          : Container(),
+                                    ],
+                                  ),
+                                  Text(
+                                    characterInfo.description ?? "",
+                                    style: TextStyle(
+                                      color: Colors.black.withAlpha(153),
+                                      fontSize: 12.sp,
+                                      fontWeight: FontWeight.w400,
+                                    ),
+                                  ),
+                                ],
+                              ),
+                            ],
+                          ),
+                        ],
+                      ),
+                    ),
+                    SizedBox(height: 24.h),
+                    GestureDetector(
+                      onTap: () {
+                        clickCallback.call();
+                        SmartDialog.dismiss(tag: tag);
+                      },
+                      child: Container(
+                        margin: EdgeInsets.symmetric(horizontal: 30.w),
+                        width: double.infinity,
+                        height: 48.h,
+                        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.isAdd == true
+                                  ? StringName.addedToKeyboard
+                                  : StringName.addToKeyboard,
+                              style: TextStyle(
+                                color:
+                                    characterInfo.isAdd == true
+                                        ? const Color(0xFF7D46FC)
+                                        : Colors.white,
+                                fontSize: 14.sp,
+                                fontWeight: FontWeight.w500,
+                              ),
+                            ),
+                          ],
+                        ),
+                      ),
+                    ),
+                  ],
+                ),
+              ),
+              Container(
+                margin: EdgeInsets.only(top: 24.h),
+                child: GestureDetector(
+                  onTap: () {
+                    SmartDialog.dismiss(tag: tag);
+                  },
+                  child: Assets.images.iconCharacterDialogClose.image(
+                    width: 40.r,
+                    height: 40.r,
+                  ),
+                ),
+              ),
+            ],
+          ),
+        );
+      },
+    );
+  }
+}

+ 38 - 24
lib/module/character/character_controller.dart

@@ -2,11 +2,13 @@ import 'package:flutter/material.dart';
 import 'package:get/get.dart';
 import 'package:injectable/injectable.dart';
 import 'package:keyboard/base/base_controller.dart';
+import 'package:keyboard/data/bean/keyboard_info.dart';
 import 'package:keyboard/data/repository/config_repository.dart';
 import 'package:keyboard/utils/atmob_log.dart';
 
 import '../../data/bean/character_group_info.dart';
 import '../../data/repository/characters_repository.dart';
+import '../../data/repository/keyboard_repository.dart';
 
 @injectable
 class CharacterController extends BaseController
@@ -14,19 +16,30 @@ class CharacterController extends BaseController
   final String tag = "CharacterController";
   final CharactersRepository charactersRepository;
   final ConfigRepository configRepository;
+  final KeyboardRepository keyboardRepository;
 
-  CharacterController(this.charactersRepository,this.configRepository);
+  CharacterController(
+    this.charactersRepository,
+    this.configRepository,
+    this.keyboardRepository,
+  );
 
+  // 人设主题
   RxList<CharacterGroupInfo> get characterGroupList =>
       charactersRepository.characterGroupList;
 
+  // 键盘列表
+  RxList<KeyboardInfo> get keyboardInfoList =>
+      keyboardRepository.keyboardInfoList;
+
   late Rx<TabController> tabController;
   late PageController pageController;
+
   RxInt currentTabBarIndex = 0.obs;
 
-  RxList<String> keyboardOptions = ["默认键盘", "新建键盘1"].obs;
+  Rx<CharacterGroupInfo> currentCharacterGroupInfo = CharacterGroupInfo().obs;
 
-  Rx<String?> selectedValue = Rx<String?>(null);
+  Rx<KeyboardInfo> currentKeyboardInfo = KeyboardInfo().obs;
 
   @override
   void onInit() {
@@ -34,11 +47,9 @@ class CharacterController extends BaseController
     _dataLoad();
   }
 
-
-
   void _dataLoad() async {
-    charactersRepository.getCharactersGroup();
     pageController = PageController();
+
     tabController =
         TabController(
           length: characterGroupList.length,
@@ -49,11 +60,25 @@ class CharacterController extends BaseController
     ever(charactersRepository.characterGroupList, (value) {
       AtmobLog.d(tag, "characterGroupList changed");
       if (value.isNotEmpty) {
+        tabController.value.dispose();
         tabController.value = TabController(
           length: characterGroupList.length,
           vsync: this,
           initialIndex: 0,
         );
+        currentCharacterGroupInfo.value = characterGroupList.first;
+        AtmobLog.d(
+          tag,
+          "currentCharacterGroupInfo.value: ${characterGroupList.first.id}",
+        );
+      }
+    });
+
+    ever(keyboardRepository.keyboardInfoList, (value) {
+      AtmobLog.d(tag, "keyboardInfoList1 changed");
+      if (value.isNotEmpty) {
+        currentKeyboardInfo.value = keyboardInfoList.first;
+        print("currentKeyboardInfo.value: ${currentKeyboardInfo.value}");
       }
     });
   }
@@ -62,7 +87,7 @@ class CharacterController extends BaseController
     if (index >= characterGroupList.length) {
       return;
     }
-    AtmobLog.d(tag, "onTabChanged index:$index");
+
     pageController.animateToPage(
       index,
       duration: const Duration(milliseconds: 300),
@@ -71,12 +96,11 @@ class CharacterController extends BaseController
   }
 
   void onPageChanged(int index) {
-
     if (index >= characterGroupList.length) {
       return;
     }
-    AtmobLog.d(tag, "onPageChanged index:$index");
     currentTabBarIndex.value = index;
+    currentCharacterGroupInfo.value = characterGroupList[index];
     tabController.value.animateTo(
       index,
       duration: const Duration(milliseconds: 300),
@@ -99,22 +123,12 @@ class CharacterController extends BaseController
     AtmobLog.d(tag, "clickMyKeyboard");
   }
 
-  void updateSelectedValue(String? newValue) {
-    selectedValue.value = newValue;
-  }
 
-  // 添加一个新的键盘
-  void addKeyboard(String name) {
-    keyboardOptions.add(name);
-  }
 
-  // 删除某个键盘
-  void removeKeyboard(String name) {
-    keyboardOptions.remove(name);
-    // 如果删除的是当前选中的值,则重置
-    if (selectedValue.value == name) {
-      selectedValue.value =
-          keyboardOptions.isNotEmpty ? keyboardOptions.first : null;
-    }
+  void updateSelectedValue(String? newValue) {
+    currentKeyboardInfo.value = keyboardInfoList.firstWhere(
+      (element) => element.name == newValue,
+      orElse: () => keyboardInfoList.first,
+    );
   }
 }

+ 17 - 18
lib/module/character/character_view.dart

@@ -1,7 +1,9 @@
+import 'package:cached_network_image/cached_network_image.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
 import 'package:keyboard/base/base_view.dart';
+import 'package:keyboard/module/character/content/character_group_content_view.dart';
 import 'package:keyboard/resource/string.gen.dart';
 
 import '../../resource/assets.gen.dart';
@@ -22,6 +24,7 @@ class CharacterView extends BaseView<CharacterController> {
       body: Builder(
         builder: (context) {
           return NestedScrollView(
+
             headerSliverBuilder: (context, innerBoxIsScrolled) {
               return [
                 /// **🔹 让背景图滑动时裁剪掉上方部分**
@@ -92,33 +95,29 @@ class CharacterView extends BaseView<CharacterController> {
                     fontSize: 14.sp,
                     fontWeight: FontWeight.w400,
                   ),
-
                   icon: Assets.images.iconCharacterArrowDown.image(
                     width: 20.r,
                     height: 20.r,
                   ),
-                  value: controller.selectedValue.value,
-                  // 绑定 selectedValue
+                  value: controller.currentKeyboardInfo.value?.name,
                   onChanged: (String? newValue) {
-                    controller.updateSelectedValue(newValue); // 更新选中的值
+                    controller.updateSelectedValue(newValue);
                   },
 
-                  items: List.generate(controller.keyboardOptions.length, (
+                  items: List.generate(controller.keyboardInfoList.length, (
                     index,
                   ) {
-                    String value = controller.keyboardOptions[index];
+                    String? value = controller.keyboardInfoList[index].name;
                     return DropdownMenuItem<String>(
                       value: value,
                       child: Column(
                         crossAxisAlignment: CrossAxisAlignment.start,
-                        // 让选项文本左对齐
                         mainAxisSize: MainAxisSize.min,
-                        // 让 Column 适配内容
                         children: [
                           Padding(
                             padding: EdgeInsets.symmetric(vertical: 8),
                             child: Text(
-                              value,
+                              value ?? "",
                               style: TextStyle(
                                 color: Colors.black.withAlpha(204),
                                 fontSize: 14.sp,
@@ -126,7 +125,7 @@ class CharacterView extends BaseView<CharacterController> {
                               ),
                             ),
                           ),
-                          if (index != controller.keyboardOptions.length - 1)
+                          if (index != controller.keyboardInfoList.length - 1)
                             Divider(
                               color: Color(0xFFF6F6F6),
                               thickness: 1,
@@ -248,9 +247,14 @@ class CharacterView extends BaseView<CharacterController> {
               mainAxisAlignment: MainAxisAlignment.center,
               children: [
                 if (e.iconUrl != null)
-                  Image.network(e.iconUrl!, width: 20.r, height: 20.r),
+                  CachedNetworkImage(
+                    imageUrl: e.iconUrl!,
+                    width: 20.r,
+                    height: 20.r,
+                  ),
+
                 Text(
-                  e.name,
+                  e.name ?? "",
                   style: TextStyle(
                     color:
                         isSelected ? Colors.black : Colors.black.withAlpha(104),
@@ -278,12 +282,7 @@ class CharacterView extends BaseView<CharacterController> {
         },
         children:
             controller.characterGroupList.map((group) {
-              return ListView.builder(
-                itemCount: controller.characterGroupList.length,
-                itemBuilder: (context, index) {
-                  return ListTile(title: Text(group.name));
-                },
-              );
+              return CharacterGroupContentView();
             }).toList(),
       );
     });

+ 130 - 0
lib/module/character/content/character_group_content_controller.dart

@@ -0,0 +1,130 @@
+import 'package:easy_refresh/easy_refresh.dart';
+import 'package:flutter/cupertino.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 'package:keyboard/dialog/character_details_dialog.dart';
+import 'package:keyboard/module/character/character_controller.dart';
+import 'package:keyboard/utils/atmob_log.dart';
+import 'package:keyboard/utils/toast_util.dart';
+
+import '../../../data/bean/character_group_info.dart';
+import '../../../data/bean/character_info.dart';
+import '../../../data/bean/keyboard_info.dart';
+
+@injectable
+class CharacterGroupContentController extends BaseController {
+  final tag = "CharacterGroupContentController";
+
+  Rx<KeyboardInfo> get currentKeyboardInfo =>
+      Get.find<CharacterController>().currentKeyboardInfo;
+
+  Rx<CharacterGroupInfo> get currentCharacterGroupInfo =>
+      Get.find<CharacterController>().currentCharacterGroupInfo;
+  final CharactersRepository charactersRepository;
+
+  CharacterGroupContentController(this.charactersRepository);
+
+  RxList<CharacterInfo> characterList = <CharacterInfo>[].obs;
+  RxInt currentListCount = 0.obs;
+
+  RxInt currentPage = 1.obs;
+  late EasyRefreshController refreshController;
+
+  @override
+  void onInit() async {
+    super.onInit();
+    refreshController = EasyRefreshController(
+      controlFinishLoad: true,
+      controlFinishRefresh: true,
+    );
+    // 等待页面渲染完成后再加载数据
+    WidgetsBinding.instance.addPostFrameCallback((_) {
+      refreshData();
+    });
+    everAll([currentCharacterGroupInfo, currentKeyboardInfo], (_) async {
+      await refreshData();
+    });
+  }
+
+  @override
+  onReady() {
+    super.onReady();
+  }
+
+  // 下拉刷新
+  Future<void> refreshData() async {
+    AtmobLog.d(
+      tag,
+      'refreshData ${currentCharacterGroupInfo.value.id}, ${currentKeyboardInfo.value.id}',
+    );
+    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);
+  }
+
+  // 获取角色列表
+  Future<void> getCurrentCharacterListInfo({bool isRefresh = false}) async {
+    var response = await charactersRepository.getCharactersPage(
+      groupId: currentCharacterGroupInfo.value.id.toString(),
+      page: currentPage.value,
+      keyboardId: currentKeyboardInfo.value.id.toString(),
+    );
+    if (isRefresh) {
+      characterList.value = response.characterInfos;
+    } else {
+      characterList.addAll(response.characterInfos);
+    }
+    currentListCount.value = response.count;
+  }
+
+  @override
+  void onClose() {
+    refreshController.dispose();
+    super.onClose();
+  }
+
+  void itemButtonClick(CharacterInfo characterInfo) {
+    AtmobLog.d(tag, 'characterInfo ${characterInfo.toJson()} ');
+
+    CharacterDetailsDialog.show(
+      characterInfo: characterInfo,
+      clickCallback: () {
+        if (characterInfo.isLock == true) {
+          // addCharacter(characterInfo);
+        } else if (characterInfo.isAdd == false) {
+          // unlockCharacter(characterInfo);
+        } else {
+          ToastUtil.show('该人设已添加');
+        }
+      },
+    );
+  }
+
+  void addCharacter(CharacterInfo characterInfo) {
+    charactersRepository.characterAdd(
+      characterId: characterInfo.id.toString(),
+      keyboardId: currentKeyboardInfo.value.id.toString(),
+    );
+  }
+
+  void unlockCharacter(CharacterInfo characterInfo) {
+    charactersRepository.characterUnlock(
+      characterId: characterInfo.id.toString(),
+      keyboardId: currentKeyboardInfo.value.id.toString(),
+    );
+  }
+}

+ 198 - 0
lib/module/character/content/character_group_content_view.dart

@@ -0,0 +1,198 @@
+import 'package:cached_network_image/cached_network_image.dart';
+import 'package:easy_refresh/easy_refresh.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:keyboard/base/base_view.dart';
+import 'package:get/get.dart';
+import 'package:keyboard/module/character/content/character_group_content_controller.dart';
+import 'package:keyboard/resource/string.gen.dart';
+
+import '../../../data/bean/character_info.dart';
+import '../../../resource/assets.gen.dart';
+
+class CharacterGroupContentView
+    extends BaseView<CharacterGroupContentController> {
+  const CharacterGroupContentView({super.key});
+
+  @override
+  backgroundColor() => const Color(0xFFF4F2FB);
+
+  @override
+  Widget buildBody(BuildContext context) {
+    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: null,
+              // 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 Container(
+      margin: EdgeInsets.symmetric(horizontal: 16.w),
+      padding: EdgeInsets.all(14.r),
+      decoration: ShapeDecoration(
+        color: Colors.white,
+        shape: RoundedRectangleBorder(
+          borderRadius: BorderRadius.circular(12.r),
+        ),
+      ),
+      height: 88.h,
+      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,
+              ),
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}

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

@@ -16,6 +16,14 @@ class $AssetsImagesGen {
   AssetGenImage get bgCharacterBoyBanner =>
       const AssetGenImage('assets/images/bg_character_boy_banner.webp');
 
+  /// File path: assets/images/bg_character_dialog.webp
+  AssetGenImage get bgCharacterDialog =>
+      const AssetGenImage('assets/images/bg_character_dialog.webp');
+
+  /// File path: assets/images/bg_character_dialog_image.webp
+  AssetGenImage get bgCharacterDialogImage =>
+      const AssetGenImage('assets/images/bg_character_dialog_image.webp');
+
   /// File path: assets/images/bg_character_girl_banner.webp
   AssetGenImage get bgCharacterGirlBanner =>
       const AssetGenImage('assets/images/bg_character_girl_banner.webp');
@@ -47,6 +55,14 @@ class $AssetsImagesGen {
   AssetGenImage get iconCharacterCustomized =>
       const AssetGenImage('assets/images/icon_character_customized.webp');
 
+  /// File path: assets/images/icon_character_dialog_close.webp
+  AssetGenImage get iconCharacterDialogClose =>
+      const AssetGenImage('assets/images/icon_character_dialog_close.webp');
+
+  /// File path: assets/images/icon_character_dialog_logo.webp
+  AssetGenImage get iconCharacterDialogLogo =>
+      const AssetGenImage('assets/images/icon_character_dialog_logo.webp');
+
   /// File path: assets/images/icon_character_group_selected.webp
   AssetGenImage get iconCharacterGroupSelected =>
       const AssetGenImage('assets/images/icon_character_group_selected.webp');
@@ -55,10 +71,18 @@ class $AssetsImagesGen {
   AssetGenImage get iconCharacterKeyboard =>
       const AssetGenImage('assets/images/icon_character_keyboard.webp');
 
+  /// File path: assets/images/icon_character_lock.webp
+  AssetGenImage get iconCharacterLock =>
+      const AssetGenImage('assets/images/icon_character_lock.webp');
+
   /// File path: assets/images/icon_character_market.webp
   AssetGenImage get iconCharacterMarket =>
       const AssetGenImage('assets/images/icon_character_market.webp');
 
+  /// File path: assets/images/icon_character_vip.webp
+  AssetGenImage get iconCharacterVip =>
+      const AssetGenImage('assets/images/icon_character_vip.webp');
+
   /// File path: assets/images/icon_mine_about.webp
   AssetGenImage get iconMineAbout =>
       const AssetGenImage('assets/images/icon_mine_about.webp');
@@ -143,6 +167,8 @@ class $AssetsImagesGen {
   /// List of all assets
   List<AssetGenImage> get values => [
     bgCharacterBoyBanner,
+    bgCharacterDialog,
+    bgCharacterDialogImage,
     bgCharacterGirlBanner,
     bgMine,
     bgMineVipCard,
@@ -151,9 +177,13 @@ class $AssetsImagesGen {
     iconCharacterArrowDown,
     iconCharacterArrowRight,
     iconCharacterCustomized,
+    iconCharacterDialogClose,
+    iconCharacterDialogLogo,
     iconCharacterGroupSelected,
     iconCharacterKeyboard,
+    iconCharacterLock,
     iconCharacterMarket,
+    iconCharacterVip,
     iconMineAbout,
     iconMineArrow,
     iconMineBackArrow,

+ 26 - 0
lib/resource/string.gen.dart

@@ -49,6 +49,19 @@ class StringName {
   static final String goCustomizeCharacter = 'go_customize_character'.tr; // 去定制人设
   static final String goCustomizeCharacterDesc = 'go_customize_character_desc'.tr; // 定制你自己的专属人设
   static final String myKeyboard = 'my_keyboard'.tr; // 我的键盘
+  static final String characterAdd = 'character_add'.tr; // 添加
+  static final String characterAddSuccess = 'character_add_success'.tr; // 添加成功
+  static final String characterAddFailed = 'character_add_failed'.tr; // 添加失败
+  static final String characterAdded = 'character_added'.tr; // 已添加
+  static final String characterUnlock = 'character_unlock'.tr; // 解锁
+  static final String characterUnlockSuccess = 'character_unlock_success'.tr; // 已解锁
+  static final String characterUnlockFailed = 'character_unlock_failed'.tr; // 解锁失败
+  static final String noMoreData = 'no_more_data'.tr; // 没有更多了
+  static final String loading = 'loading'.tr; // 加载中...
+  static final String loadFailed = 'load_failed'.tr; // 请重试
+  static final String loadCompleted = 'load_completed'.tr; // 加载完成
+  static final String addToKeyboard = 'add_to_keyboard'.tr; // 添加到键盘
+  static final String addedToKeyboard = 'added_to_keyboard'.tr; // 已添加到键盘
 }
 class StringMultiSource {
   StringMultiSource._();
@@ -101,6 +114,19 @@ class StringMultiSource {
       'go_customize_character': '去定制人设',
       'go_customize_character_desc': '定制你自己的专属人设',
       'my_keyboard': '我的键盘',
+      'character_add': '添加',
+      'character_add_success': '添加成功',
+      'character_add_failed': '添加失败',
+      'character_added': '已添加',
+      'character_unlock': '解锁',
+      'character_unlock_success': '已解锁',
+      'character_unlock_failed': '解锁失败',
+      'no_more_data': '没有更多了',
+      'loading': '加载中...',
+      'load_failed': '请重试',
+      'load_completed': '加载完成',
+      'add_to_keyboard': '添加到键盘',
+      'added_to_keyboard': '已添加到键盘',
     },
   };
 }

+ 4 - 0
lib/router/app_pages.dart

@@ -1,12 +1,15 @@
 import 'package:get/get.dart';
 import 'package:keyboard/module/about/about_controller.dart';
 import 'package:keyboard/module/browser/browser_controller.dart';
+import 'package:keyboard/module/character/content/character_group_content_controller.dart';
 import 'package:keyboard/module/feedback/feedback_controller.dart';
 import 'package:keyboard/module/keyboard/keyboard_controller.dart';
 
 import 'package:keyboard/module/login/login_controller.dart';
 import 'package:keyboard/module/mine/mine_controller.dart';
 
+import '../data/bean/character_group_info.dart';
+import '../data/repository/characters_repository.dart';
 import '../di/get_it.dart';
 import '../module/about/about_page.dart';
 import '../module/browser/browser_page.dart';
@@ -41,6 +44,7 @@ class AppBinding extends Bindings {
     lazyPut(() => getIt.get<FeedbackController>());
     lazyPut(() => getIt.get<AboutController>());
     lazyPut(() => getIt.get<BrowserController>());
+    lazyPut(() => getIt.get<CharacterGroupContentController>());
   }
 
   void lazyPut<S>(InstanceBuilderCallback<S> builder) {

+ 17 - 1
pubspec.lock

@@ -154,7 +154,7 @@ packages:
     source: hosted
     version: "8.9.4"
   cached_network_image:
-    dependency: transitive
+    dependency: "direct main"
     description:
       name: cached_network_image
       sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916"
@@ -321,6 +321,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.1.1"
+  easy_refresh:
+    dependency: "direct main"
+    description:
+      name: easy_refresh
+      sha256: "486e30abfcaae66c0f2c2798a10de2298eb9dc5e0bb7e1dba9328308968cae0c"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.4.0"
   fake_async:
     dependency: transitive
     description:
@@ -836,6 +844,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.9.1"
+  path_drawing:
+    dependency: transitive
+    description:
+      name: path_drawing
+      sha256: bbb1934c0cbb03091af082a6389ca2080345291ef07a5fa6d6e078ba8682f977
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.1"
   path_parsing:
     dependency: transitive
     description:

+ 3 - 0
pubspec.yaml

@@ -49,6 +49,9 @@ dependencies:
   flutter_localizations:
     sdk: flutter
 
+  #上、下拉刷新
+  easy_refresh: ^3.4.0
+
   #网络图片
   cached_network_image: ^3.4.1