Procházet zdrojové kódy

[feat]完成首页ui

云天逵 před 7 měsíci
rodič
revize
096727125e
35 změnil soubory, kde provedl 852 přidání a 491 odebrání
  1. binární
      assets/images/bg_keyboard_easy_reply.webp
  2. binární
      assets/images/bg_keyboard_intimacy_analyze.webp
  3. binární
      assets/images/bg_keyboard_screenshot_reply.webp
  4. binární
      assets/images/icon_keyboard_banner.webp
  5. binární
      assets/images/icon_keyboard_banner_close.webp
  6. binární
      assets/images/icon_keyboard_current_character_title.webp
  7. binární
      assets/images/icon_keyboard_current_go.webp
  8. binární
      assets/images/icon_keyboard_explosive_play.webp
  9. binární
      assets/images/icon_keyboard_hit_play.webp
  10. binární
      assets/images/icon_keyboard_initmacy_title.webp
  11. binární
      assets/images/icon_keyboard_intimacy_logo.webp
  12. binární
      assets/images/icon_keyboard_screenshot_logo.webp
  13. binární
      assets/images/icon_keyboard_screenshot_title.webp
  14. binární
      assets/images/icon_keyboard_triangle.webp
  15. 6 0
      assets/string/base/string.xml
  16. 7 0
      lib/data/api/atmob_api.dart
  17. 34 0
      lib/data/api/atmob_api.g.dart
  18. 42 0
      lib/data/api/response/keyboard_home_info_response.dart
  19. 34 0
      lib/data/api/response/keyboard_home_info_response.g.dart
  20. 34 0
      lib/data/api/response/keyboard_love_index_response.dart
  21. 25 0
      lib/data/api/response/keyboard_love_index_response.g.dart
  22. 2 2
      lib/data/model/intimacy_analyse_report.dart
  23. 7 11
      lib/data/model/intimacy_analyse_report.g.dart
  24. 10 4
      lib/data/repository/account_repository.dart
  25. 33 7
      lib/data/repository/keyboard_repository.dart
  26. 12 15
      lib/di/get_it.config.dart
  27. 60 36
      lib/module/keyboard/keyboard_controller.dart
  28. 387 407
      lib/module/keyboard/keyboard_view.dart
  29. 2 2
      lib/module/mine/mine_controller.dart
  30. 5 6
      lib/module/profile/profile_controller.dart
  31. 1 1
      lib/module/profile/profile_page.dart
  32. 1 0
      lib/module/store/store_controller.dart
  33. 66 0
      lib/resource/assets.gen.dart
  34. 10 0
      lib/resource/string.gen.dart
  35. 74 0
      lib/widget/pargress_bar.dart

binární
assets/images/bg_keyboard_easy_reply.webp


binární
assets/images/bg_keyboard_intimacy_analyze.webp


binární
assets/images/bg_keyboard_screenshot_reply.webp


binární
assets/images/icon_keyboard_banner.webp


binární
assets/images/icon_keyboard_banner_close.webp


binární
assets/images/icon_keyboard_current_character_title.webp


binární
assets/images/icon_keyboard_current_go.webp


binární
assets/images/icon_keyboard_explosive_play.webp


binární
assets/images/icon_keyboard_hit_play.webp


binární
assets/images/icon_keyboard_initmacy_title.webp


binární
assets/images/icon_keyboard_intimacy_logo.webp


binární
assets/images/icon_keyboard_screenshot_logo.webp


binární
assets/images/icon_keyboard_screenshot_title.webp


binární
assets/images/icon_keyboard_triangle.webp


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

@@ -203,6 +203,11 @@
 
 
     <string name="keyboard_member_open">开通会员</string>
+    <string name="keyboard_intimacy_subtitle">探索人格/情感特质</string>
+    <string name="keyboard_screenshot_subtitle">上下文语义分析</string>
+    <string name="keyboard_go_to_manage">去管理</string>
+    <string name="keyboard_add">添加</string>
+    <string name="keyboard_no_login">自己</string>
 
     <!-- 键盘引导页 -->
     <string name="keyboard_guide_go_wechat">去微信体验</string>
@@ -215,4 +220,5 @@
 
     <string name="intimacy_analyse_tab_report">亲密分析报告</string>
     <string name="intimacy_analyse_tab_screenshot_reply">截图回复</string>
+
 </resources>

+ 7 - 0
lib/data/api/atmob_api.dart

@@ -38,6 +38,7 @@ 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';
 import 'package:keyboard/data/api/response/keyboard_character_list_response.dart';
+import 'package:keyboard/data/api/response/keyboard_home_info_response.dart' show KeyboardHomeInfoResponse;
 import 'package:keyboard/data/api/response/keyboard_list_response.dart';
 import 'package:keyboard/data/api/response/keyboard_prologue_list_response.dart';
 import 'package:keyboard/data/api/response/login_response.dart';
@@ -151,6 +152,12 @@ abstract class AtmobApi {
     @Body() CharacterCustomDeleteRequest request,
   );
 
+  // 获取首页信息
+  @POST("/project/keyboard/v1/keyboard/home/info")
+  Future<BaseResponse<KeyboardHomeInfoResponse>> getKeyboardHomeInfo(
+    @Body() AppBaseRequest request,
+  );
+
   // 获取键盘人设列表
   @POST("/project/keyboard/v1/character/list")
   Future<BaseResponse<KeyboardCharacterListResponse>> getKeyboardCharacterList(

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

@@ -598,6 +598,40 @@ class _AtmobApi implements AtmobApi {
   }
 
   @override
+  Future<BaseResponse<KeyboardHomeInfoResponse>> getKeyboardHomeInfo(
+    AppBaseRequest 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<KeyboardHomeInfoResponse>>(
+      Options(method: 'POST', headers: _headers, extra: _extra)
+          .compose(
+            _dio.options,
+            '/project/keyboard/v1/keyboard/home/info',
+            queryParameters: queryParameters,
+            data: _data,
+          )
+          .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)),
+    );
+    final _result = await _dio.fetch<Map<String, dynamic>>(_options);
+    late BaseResponse<KeyboardHomeInfoResponse> _value;
+    try {
+      _value = BaseResponse<KeyboardHomeInfoResponse>.fromJson(
+        _result.data!,
+        (json) =>
+            KeyboardHomeInfoResponse.fromJson(json as Map<String, dynamic>),
+      );
+    } on Object catch (e, s) {
+      errorLogger?.logError(e, s, _options);
+      rethrow;
+    }
+    return _value;
+  }
+
+  @override
   Future<BaseResponse<KeyboardCharacterListResponse>> getKeyboardCharacterList(
     KeyboardCharacterListRequest request,
   ) async {

+ 42 - 0
lib/data/api/response/keyboard_home_info_response.dart

@@ -0,0 +1,42 @@
+import 'package:json_annotation/json_annotation.dart';
+
+import '../../bean/character_info.dart';
+
+part 'keyboard_home_info_response.g.dart';
+
+@JsonSerializable()
+class KeyboardHomeInfoResponse {
+  @JsonKey(name: "name")
+  String? name;
+  @JsonKey(name: "imageUrl")
+  String? imageUrl;
+
+  @JsonKey(name: "targetName")
+  String? targetName;
+
+  @JsonKey(name: "targetImageUrl")
+  String? targetImageUrl;
+
+  @JsonKey(name: "intimacy")
+  int? intimacy;
+
+  @JsonKey(name: "intimacyName")
+  String? intimacyName;
+
+  @JsonKey(name: "characterInfos")
+  List<CharacterInfo>? characterInfos;
+
+  KeyboardHomeInfoResponse({
+     this.name,
+     this.imageUrl,
+     this.targetName,
+     this.targetImageUrl,
+     this.intimacy,
+     this.intimacyName,
+     this.characterInfos,
+  });
+
+  factory KeyboardHomeInfoResponse.fromJson(Map<String, dynamic> json) =>
+      _$KeyboardHomeInfoResponseFromJson(json);
+
+}

+ 34 - 0
lib/data/api/response/keyboard_home_info_response.g.dart

@@ -0,0 +1,34 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'keyboard_home_info_response.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+KeyboardHomeInfoResponse _$KeyboardHomeInfoResponseFromJson(
+  Map<String, dynamic> json,
+) => KeyboardHomeInfoResponse(
+  name: json['name'] as String?,
+  imageUrl: json['imageUrl'] as String?,
+  targetName: json['targetName'] as String?,
+  targetImageUrl: json['targetImageUrl'] as String?,
+  intimacy: (json['intimacy'] as num?)?.toInt(),
+  intimacyName: json['intimacyName'] as String?,
+  characterInfos:
+      (json['characterInfos'] as List<dynamic>?)
+          ?.map((e) => CharacterInfo.fromJson(e as Map<String, dynamic>))
+          .toList(),
+);
+
+Map<String, dynamic> _$KeyboardHomeInfoResponseToJson(
+  KeyboardHomeInfoResponse instance,
+) => <String, dynamic>{
+  'name': instance.name,
+  'imageUrl': instance.imageUrl,
+  'targetName': instance.targetName,
+  'targetImageUrl': instance.targetImageUrl,
+  'intimacy': instance.intimacy,
+  'intimacyName': instance.intimacyName,
+  'characterInfos': instance.characterInfos,
+};

+ 34 - 0
lib/data/api/response/keyboard_love_index_response.dart

@@ -0,0 +1,34 @@
+import 'package:json_annotation/json_annotation.dart';
+
+import '../../bean/keyboard_info.dart';
+
+part 'keyboard_love_index_response.g.dart';
+
+@JsonSerializable()
+class KeyboardLoveIndexResponse {
+  // 默契数值
+  @JsonKey(name: "rapport")
+  int? rapport;
+
+  //激情数值
+  @JsonKey(name: "passion")
+  int? passion;
+
+  @JsonKey(name: "fetter")
+  int? fetter;
+
+  @JsonKey(name: "promise")
+  int? promise;
+
+  KeyboardLoveIndexResponse({
+    this.rapport,
+    this.passion,
+    this.fetter,
+    this.promise,
+  });
+
+  factory KeyboardLoveIndexResponse.fromJson(Map<String, dynamic> json) =>
+      _$KeyboardLoveIndexResponseFromJson(json);
+
+  Map<String, dynamic> toJson() => _$KeyboardLoveIndexResponseToJson(this);
+}

+ 25 - 0
lib/data/api/response/keyboard_love_index_response.g.dart

@@ -0,0 +1,25 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'keyboard_love_index_response.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+KeyboardLoveIndexResponse _$KeyboardLoveIndexResponseFromJson(
+  Map<String, dynamic> json,
+) => KeyboardLoveIndexResponse(
+  rapport: (json['rapport'] as num?)?.toInt(),
+  passion: (json['passion'] as num?)?.toInt(),
+  fetter: (json['fetter'] as num?)?.toInt(),
+  promise: (json['promise'] as num?)?.toInt(),
+);
+
+Map<String, dynamic> _$KeyboardLoveIndexResponseToJson(
+  KeyboardLoveIndexResponse instance,
+) => <String, dynamic>{
+  'rapport': instance.rapport,
+  'passion': instance.passion,
+  'fetter': instance.fetter,
+  'promise': instance.promise,
+};

+ 2 - 2
lib/data/model/intimacy_analyse_report.dart

@@ -29,7 +29,7 @@ class AnalyseItem {
   });
 
   factory AnalyseItem.fromJson(Map<String, dynamic> json) =>
-      _$AnalyseSectionFromJson(json);
+      _$AnalyseItemFromJson(json);
 
-  Map<String, dynamic> toJson() => _$AnalyseSectionToJson(this);
+  Map<String, dynamic> toJson() => _$AnalyseItemToJson(this);
 }

+ 7 - 11
lib/data/model/intimacy_analyse_report.g.dart

@@ -19,15 +19,11 @@ Map<String, dynamic> _$IntimacyAnalyseReportToJson(
   IntimacyAnalyseReport instance,
 ) => <String, dynamic>{'list': instance.list};
 
-AnalyseItem _$AnalyseSectionFromJson(Map<String, dynamic> json) =>
-    AnalyseItem(
-      title: json['title'] as String,
-      sections:
-          (json['sections'] as List<dynamic>).map((e) => e as String).toList(),
-    );
+AnalyseItem _$AnalyseItemFromJson(Map<String, dynamic> json) => AnalyseItem(
+  title: json['title'] as String,
+  sections:
+      (json['sections'] as List<dynamic>).map((e) => e as String).toList(),
+);
 
-Map<String, dynamic> _$AnalyseSectionToJson(AnalyseItem instance) =>
-    <String, dynamic>{
-      'title': instance.title,
-      'sections': instance.sections,
-    };
+Map<String, dynamic> _$AnalyseItemToJson(AnalyseItem instance) =>
+    <String, dynamic>{'title': instance.title, 'sections': instance.sections};

+ 10 - 4
lib/data/repository/account_repository.dart

@@ -5,6 +5,7 @@ import 'package:injectable/injectable.dart';
 import 'package:keyboard/data/api/atmob_api.dart';
 import 'package:keyboard/data/api/request/user_info_setting_request.dart';
 import 'package:keyboard/data/bean/member_info.dart';
+import 'package:keyboard/data/repository/keyboard_repository.dart';
 
 import '../../base/app_base_request.dart';
 import '../../di/get_it.dart';
@@ -27,7 +28,6 @@ class AccountRepository {
   static final String keyAccountLoginPhoneNum = 'key_account_login_phone_num';
   static final String keyAccountLoginToken = 'key_account_login_token';
 
-
   final Rxn<UserInfoResponse> _userInfo = Rxn<UserInfoResponse>();
 
   Rxn<UserInfoResponse> get userInfo => _userInfo;
@@ -37,7 +37,6 @@ class AccountRepository {
 
   Rxn<MemberInfo> memberStatusInfo = Rxn<MemberInfo>();
 
-
   int? _lastRequestCodeTime;
   int _errorCodeTimes = 0;
 
@@ -46,6 +45,9 @@ class AccountRepository {
 
   static String? token = KVUtil.getString(keyAccountLoginToken, null);
 
+  final KeyboardRepository keyboardRepository =
+      KeyboardRepository.getInstance();
+
   AccountRepository(this.atmobApi) {
     AtmobLog.d(tag, '$tag....init $hashCode');
     isLogin.bindStream(
@@ -128,9 +130,11 @@ class AccountRepository {
           _userInfo.value = response;
           memberStatusInfo.value = response.memberInfo;
           if (response.memberInfo != null) {
-            KVUtil.putBool(Constants.keyIsMember, response.memberInfo!.isMember);
+            KVUtil.putBool(
+              Constants.keyIsMember,
+              response.memberInfo!.isMember,
+            );
           }
-
           return response;
         });
   }
@@ -163,6 +167,7 @@ class AccountRepository {
     refreshUserInfo();
     KVUtil.putString(keyAccountLoginPhoneNum, phoneNum);
     KVUtil.putString(keyAccountLoginToken, authToken);
+    keyboardRepository.refreshData();
   }
 
   void logout() {
@@ -173,6 +178,7 @@ class AccountRepository {
     memberStatusInfo.value = null;
     KVUtil.putBool(Constants.keyIsMember, false);
     loginPhoneNum.value = null;
+    keyboardRepository.cleanData();
   }
 
   // 意见反馈

+ 33 - 7
lib/data/repository/keyboard_repository.dart

@@ -13,6 +13,7 @@ import '../api/request/keyboard_character_list_request.dart';
 import '../api/request/keyboard_choose_request.dart';
 import '../api/request/keyboard_update_request.dart';
 import '../api/response/keyboard_character_list_response.dart';
+import '../api/response/keyboard_home_info_response.dart';
 import '../api/response/keyboard_list_response.dart';
 import '../bean/keyboard_info.dart';
 
@@ -25,13 +26,30 @@ class KeyboardRepository {
 
   RxList<KeyboardInfo> get keyboardInfoList => _keyboardInfoList;
 
+  final Rxn<KeyboardHomeInfoResponse> _homeInfo =
+      Rxn<KeyboardHomeInfoResponse>();
+
+  Rxn<KeyboardHomeInfoResponse> get homeInfo => _homeInfo;
+
   KeyboardRepository(this.atmobApi) {
     print('$tag....init');
+    refreshData();
+  }
+
+  Future refreshData() async {
     refreshKeyboardList();
+
+    await Future.delayed(const Duration(milliseconds: 500));
+    // 延迟为了保证首页数据能够正常获取,不然保存的时候,获取太快了,导致还是拉到旧的数值
+    getKeyboardHomeInfo();
   }
 
-  Future refreshKeyboardList() async {
+  Future cleanData() async {
+    _keyboardInfoList.clear();
+    getKeyboardHomeInfo();
+  }
 
+  Future refreshKeyboardList() async {
     return getKeyboardList().then((response) {
       _keyboardInfoList.value = response.keyboardInfos;
       print('$tag refreshKeyboardList: ${response.keyboardInfos.first.id}');
@@ -93,14 +111,11 @@ class KeyboardRepository {
         )
         .then(HttpHandler.handle(true));
   }
+
   // 选择键盘
-  Future<void> keyboardChoose({
-    required String keyboardId,
-  }) {
+  Future<void> keyboardChoose({required String keyboardId}) {
     return atmobApi
-        .keyboardChoose(
-      KeyboardChooseRequest(keyboardId: keyboardId),
-        )
+        .keyboardChoose(KeyboardChooseRequest(keyboardId: keyboardId))
         .then(HttpHandler.handle(true));
   }
 
@@ -111,5 +126,16 @@ class KeyboardRepository {
         .then(HttpHandler.handle(true));
   }
 
+  // 获取首页信息
+  Future<KeyboardHomeInfoResponse> getKeyboardHomeInfo() {
+    return atmobApi
+        .getKeyboardHomeInfo(AppBaseRequest())
+        .then(HttpHandler.handle(true))
+        .then((response) {
+          _homeInfo.value = response;
+          return response;
+        });
+  }
+
   static KeyboardRepository getInstance() => getIt.get<KeyboardRepository>();
 }

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

@@ -68,6 +68,15 @@ extension GetItInjectableX on _i174.GetIt {
     final networkModule = _$NetworkModule();
     gh.factory<_i256.AboutController>(() => _i256.AboutController());
     gh.factory<_i923.BrowserController>(() => _i923.BrowserController());
+    gh.factory<_i987.IntimacyAnalyseReportController>(
+      () => _i987.IntimacyAnalyseReportController(),
+    );
+    gh.factory<_i977.IntimacyAnalyseController>(
+      () => _i977.IntimacyAnalyseController(),
+    );
+    gh.factory<_i279.IntimacyAnalyseScreenshotReplyController>(
+      () => _i279.IntimacyAnalyseScreenshotReplyController(),
+    );
     gh.factory<_i248.KeyboardGuidePageController>(
       () => _i248.KeyboardGuidePageController(),
     );
@@ -77,15 +86,6 @@ extension GetItInjectableX on _i174.GetIt {
     gh.factory<_i415.KeyboardMethodHandler>(
       () => _i415.KeyboardMethodHandler(),
     );
-    gh.factory<_i977.IntimacyAnalyseController>(
-      () => _i977.IntimacyAnalyseController(),
-    );
-    gh.factory<_i987.IntimacyAnalyseReportController>(
-      () => _i987.IntimacyAnalyseReportController(),
-    );
-    gh.factory<_i279.IntimacyAnalyseScreenshotReplyController>(
-      () => _i279.IntimacyAnalyseScreenshotReplyController(),
-    );
     gh.singleton<_i361.Dio>(
       () => networkModule.createStreamDio(),
       instanceName: 'streamDio',
@@ -152,15 +152,12 @@ extension GetItInjectableX on _i174.GetIt {
     gh.lazySingleton<_i779.PaymentStatusManager>(
       () => _i779.PaymentStatusManager(gh<_i987.StoreRepository>()),
     );
+    gh.factory<_i161.KeyBoardController>(
+      () => _i161.KeyBoardController(gh<_i274.KeyboardRepository>()),
+    );
     gh.factory<_i922.KeyboardManageController>(
       () => _i922.KeyboardManageController(gh<_i274.KeyboardRepository>()),
     );
-    gh.factory<_i161.KeyBoardController>(
-      () => _i161.KeyBoardController(
-        gh<_i83.AccountRepository>(),
-        gh<_i274.KeyboardRepository>(),
-      ),
-    );
     gh.factory<_i970.CharacterGroupContentController>(
       () => _i970.CharacterGroupContentController(
         gh<_i421.CharactersRepository>(),

+ 60 - 36
lib/module/keyboard/keyboard_controller.dart

@@ -1,24 +1,24 @@
+import 'dart:async';
+
+import 'package:flutter/widgets.dart';
+import 'package:get/get.dart';
 import 'package:injectable/injectable.dart';
 import 'package:keyboard/base/base_controller.dart';
-import 'package:get/get.dart';
-import 'package:keyboard/data/bean/keyboard_info.dart';
-import 'package:keyboard/data/repository/account_repository.dart';
+import 'package:keyboard/data/api/response/keyboard_home_info_response.dart';
 import 'package:keyboard/data/repository/keyboard_repository.dart';
-
-import '../../data/api/response/user_info_response.dart';
-import '../../utils/atmob_log.dart';
+import 'package:keyboard/module/keyboard_manage/keyboard_manage_page.dart';
+import 'package:keyboard/module/store/store_page.dart';
 
 @injectable
 class KeyBoardController extends BaseController {
   final tag = "KeyBoardController";
-  final AccountRepository accountRepository;
 
   final KeyboardRepository keyboardRepository;
 
-  Rxn<UserInfoResponse> get userInfo => accountRepository.userInfo;
-
-  // 爱情指数相关数据
-  final lovePercentage = 30.obs;
+  KeyboardHomeInfoResponse? get homeInfo => keyboardRepository.homeInfo.value;
+  static const int countdownTime = 10 * 60 * 100;
+  final RxInt timeLeft = countdownTime.obs;
+  Timer? _timer;
 
   // 各项指标数据
   final moodPercentage = 20.obs;
@@ -26,36 +26,60 @@ class KeyBoardController extends BaseController {
   final wealthPercentage = 30.obs;
   final cleanlinessPercentage = 50.obs;
 
-  // 是否已添加伴侣
-  final hasPartner = false.obs;
-
-  final Rx<KeyboardInfo> currentChooseKeyboard = KeyboardInfo().obs;
-
-  KeyBoardController(this.accountRepository, this.keyboardRepository);
+  KeyBoardController(this.keyboardRepository);
 
   @override
   void onInit() {
     super.onInit();
-    getCustomKeyboard();
-  }
-
-  void getCustomKeyboard() {
-    AtmobLog.i(tag, 'getCustomKeyboard');
-    keyboardRepository.getKeyboardList(type: "custom").then((
-      keyboardListResponse,
-    ) {
-      AtmobLog.i(
-        tag,
-        'keyboardListResponse: ${keyboardListResponse.keyboardInfos}',
-      );
-
-      for (var element in keyboardListResponse.keyboardInfos) {
-        if (element.isChoose == true) {
-          currentChooseKeyboard.value = element;
-          hasPartner.value = true;
-          break;
-        }
+    startCountdown();
+  }
+
+  void clickVip() {
+    StorePage.start();
+  }
+
+  void clickIntimacyAnalyze() {
+    debugPrint("click intimacy analyze");
+  }
+
+  void clickScreenshotReply() {
+    debugPrint("click screenshot reply");
+  }
+
+  void clickEasyReply() {
+    debugPrint("click easy reply");
+  }
+
+  void clickGoKeyboardManage() {
+    KeyboardManagePage.start();
+  }
+
+  void startCountdown() {
+    _timer = Timer.periodic(const Duration(milliseconds: 10), (timer) {
+      if (timeLeft.value > 0) {
+        timeLeft.value--;
+      } else {
+        timer.cancel();
       }
     });
   }
+
+  @override
+  void onClose() {
+    super.onClose();
+    _timer?.cancel();
+  }
+
+  String get formattedTime {
+    final totalMillis = timeLeft.value * 10;
+    final duration = Duration(milliseconds: totalMillis);
+
+    final minutes = duration.inMinutes.toString().padLeft(2, '0');
+    final seconds = (duration.inSeconds % 60).toString().padLeft(2, '0');
+    final milliseconds = ((duration.inMilliseconds % 1000) ~/ 10)
+        .toString()
+        .padLeft(2, '0');
+
+    return "$minutes:$seconds:$milliseconds";
+  }
 }

+ 387 - 407
lib/module/keyboard/keyboard_view.dart

@@ -2,11 +2,14 @@ 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:keyboard/base/base_view.dart';
 import 'package:get/get.dart';
+import 'package:keyboard/base/base_view.dart';
+import 'package:keyboard/data/bean/character_info.dart';
 import 'package:keyboard/resource/string.gen.dart';
+
 import '../../resource/assets.gen.dart';
 import '../../utils/styles.dart';
+import '../../widget/pargress_bar.dart';
 import 'keyboard_controller.dart';
 
 class KeyBoardView extends BaseView<KeyBoardController> {
@@ -23,12 +26,31 @@ class KeyBoardView extends BaseView<KeyBoardController> {
               _buildTitle(),
               Expanded(
                 child: SingleChildScrollView(
+                  physics: NeverScrollableScrollPhysics(),
                   child: Column(
                     children: [
                       _buildAvatarCard(),
+                      SizedBox(height: 10.h),
                       _buildLoveIndexCard(),
-                      _buildPopularFeatures(),
-                      _buildKeyboardSettings(),
+                      SizedBox(height: 10.h),
+                      Container(
+                        padding: EdgeInsets.only(top: 16.h),
+                        decoration: BoxDecoration(
+                          color: Colors.white,
+                          borderRadius: BorderRadius.only(
+                            topLeft: Radius.circular(16.r),
+                            topRight: Radius.circular(16.r),
+                          ),
+                        ),
+                        child: Column(
+                          children: [
+                            _buildHitCard(),
+                            SizedBox(height: 10.h),
+                            _buildKeyboardSettings(),
+                            _buildBanner(),
+                          ],
+                        ),
+                      ),
                     ],
                   ),
                 ),
@@ -43,7 +65,7 @@ class KeyBoardView extends BaseView<KeyBoardController> {
   // 顶部标题栏
   Widget _buildTitle() {
     return Container(
-      padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h),
+      padding: EdgeInsets.only(left: 16.w, right: 16.w, bottom: 12.h),
       color: Colors.transparent,
       child: Row(
         children: [
@@ -53,32 +75,39 @@ class KeyBoardView extends BaseView<KeyBoardController> {
             fit: BoxFit.cover,
           ),
           const Spacer(),
-          Container(
-            padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 6.w),
-            decoration: ShapeDecoration(
-              color: Colors.white.withAlpha(204),
-              shape: RoundedRectangleBorder(
-                side: BorderSide(width: 1, color: Colors.white),
-                borderRadius: BorderRadius.circular(13.r),
-              ),
-            ),
-            child: Row(
-              children: [
-                Assets.images.iconKeyboardVipLogo.image(
-                  width: 12.w,
-                  height: 12.w,
+          GestureDetector(
+            onTap: controller.clickVip,
+            child: Container(
+              padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 6.w),
+              decoration: ShapeDecoration(
+                color: Colors.white.withAlpha(204),
+                shape: RoundedRectangleBorder(
+                  side: BorderSide(width: 1, color: Colors.white),
+                  borderRadius: BorderRadius.circular(13.r),
                 ),
-                const SizedBox(width: 2),
-                Text(
-                  StringName.keyboardMemberOpen,
-                  style: TextStyle(
+              ),
+              child: Row(
+                children: [
+                  Assets.images.iconKeyboardVipLogo.image(
+                    width: 12.w,
+                    height: 12.w,
+                  ),
+                  const SizedBox(width: 2),
+                  Text(
+                    StringName.keyboardMemberOpen,
+                    style: TextStyle(
+                      color: Color(0xFFA85600),
+                      fontSize: 12,
+                      fontWeight: FontWeight.w400,
+                    ),
+                  ),
+                  Icon(
+                    Icons.chevron_right,
                     color: Color(0xFFA85600),
-                    fontSize: 12,
-                    fontWeight: FontWeight.w400,
+                    size: 11.r,
                   ),
-                ),
-                Icon(Icons.chevron_right, color: Color(0xFFA85600), size: 11.r),
-              ],
+                ],
+              ),
             ),
           ),
         ],
@@ -102,12 +131,9 @@ class KeyBoardView extends BaseView<KeyBoardController> {
                 const SizedBox(width: 16),
                 _buildLovePercentage(),
                 const SizedBox(width: 16),
-                controller.hasPartner.value
-                    ? _buildUserAvatar(false)
-                    : _buildAddPartnerButton(),
+                _buildUserAvatar(false),
               ],
             ),
-            SizedBox(height: 10.h),
           ],
         ),
       );
@@ -116,66 +142,88 @@ class KeyBoardView extends BaseView<KeyBoardController> {
 
   // 爱情指数卡片
   Widget _buildLoveIndexCard() {
-    return Container(
-      margin: EdgeInsets.symmetric(horizontal: 16.w),
-      padding: EdgeInsets.symmetric(vertical: 5.h, horizontal: 11.w),
-      decoration: BoxDecoration(
-        color: Colors.white,
-        borderRadius: BorderRadius.circular(12.r),
-      ),
-      child: Row(
-        children: [
-          Assets.images.iconKeyboardLoveIndex.image(width: 72.w, height: 23.h),
-          Container(
-            height: 42.w,
-            width: 215.h,
-            decoration: BoxDecoration(
-              color: Color(0xFFFAFAFC),
-              borderRadius: BorderRadius.circular(12.r),
-            ),
-            child: Column(
-              children: [
-                Row(
-                  children: [
-                    Expanded(
-                      child: ProgressBar(
-                        title: "爱情",
-                        value: controller.appearancePercentage,
-                        color: Colors.pink.shade100,
-                      ),
-                    ),
-                    Expanded(
-                      child: ProgressBar(
-                        title: "爱情",
-                        value: controller.appearancePercentage,
-                        color: Colors.pink.shade100,
-                      ),
-                    ),
-                  ],
-                ),
-                Row(
-                  children: [
-                    Expanded(
-                      child: ProgressBar(
-                        title: "爱情",
-                        value: controller.appearancePercentage,
-                        color: Colors.pink.shade100,
+    return Stack(
+      clipBehavior: Clip.none,
+      children: [
+        Positioned(
+          left: 0,
+          right: 0,
+          top: -12.h,
+          child: Assets.images.iconKeyboardTriangle.image(
+            color: Colors.white,
+            width: 20.w,
+            height: 16.h,
+          ),
+        ),
+        Container(
+          margin: EdgeInsets.symmetric(horizontal: 22.w),
+          padding: EdgeInsets.symmetric(vertical: 5.h, horizontal: 5.w),
+          decoration: BoxDecoration(
+            color: Colors.white,
+            borderRadius: BorderRadius.circular(12.r),
+          ),
+          child: Row(
+            children: [
+              Assets.images.iconKeyboardLoveIndex.image(
+                width: 72.w,
+                height: 23.h,
+              ),
+              SizedBox(width: 10.w),
+              Expanded(
+                child: Container(
+                  padding: EdgeInsets.symmetric(
+                    horizontal: 10.w,
+                    vertical: 8.h,
+                  ),
+                  decoration: BoxDecoration(
+                    color: Color(0xFFFAFAFC),
+                    borderRadius: BorderRadius.circular(12.r),
+                  ),
+                  child: Row(
+                    children: [
+                      Expanded(
+                        child: Column(
+                          children: [
+                            ProgressBar(
+                              title: "激情",
+                              value: controller.appearancePercentage,
+                              color: Color(0xFFFF637D),
+                            ),
+                            SizedBox(height: 6.h),
+                            ProgressBar(
+                              title: "默契",
+                              value: controller.appearancePercentage,
+                              color: Color(0xFFF5E8FC),
+                            ),
+                          ],
+                        ),
                       ),
-                    ),
-                    Expanded(
-                      child: ProgressBar(
-                        title: "爱情",
-                        value: controller.appearancePercentage,
-                        color: Colors.pink.shade100,
+                      SizedBox(width: 21.w),
+                      Expanded(
+                        child: Column(
+                          children: [
+                            ProgressBar(
+                              title: "羁绊",
+                              value: controller.appearancePercentage,
+                              color: Color(0xFFFFC954),
+                            ),
+                            SizedBox(height: 6.h),
+                            ProgressBar(
+                              title: "承诺",
+                              value: controller.appearancePercentage,
+                              color: Color(0xFF6382FF),
+                            ),
+                          ],
+                        ),
                       ),
-                    ),
-                  ],
+                    ],
+                  ),
                 ),
-              ],
-            ),
+              ),
+            ],
           ),
-        ],
-      ),
+        ),
+      ],
     );
   }
 
@@ -199,9 +247,8 @@ class KeyBoardView extends BaseView<KeyBoardController> {
                   child: CachedNetworkImage(
                     imageUrl:
                         isUser
-                            ? controller.userInfo.value?.imageUrl ?? ""
-                            : controller.currentChooseKeyboard.value.avatar ??
-                                "",
+                            ? controller.homeInfo?.imageUrl ?? ""
+                            : controller.homeInfo?.targetImageUrl ?? "",
                     placeholder: (_, __) => const CupertinoActivityIndicator(),
                     errorWidget:
                         (context, url, error) => CircleAvatar(
@@ -230,12 +277,24 @@ class KeyBoardView extends BaseView<KeyBoardController> {
                 color: Colors.white,
                 borderRadius: BorderRadius.circular(22.r),
               ),
-              child: Text(
-                isUser
-                    ? controller.userInfo.value?.name ?? ""
-                    : controller.currentChooseKeyboard.value.name ?? "",
-                style: Styles.getTextStyleBlack204W400(14.sp),
-              ),
+              child:
+                  isUser
+                      ? Text(
+                        controller.homeInfo?.name ?? StringName.keyboardNoLogin,
+                        style: Styles.getTextStyleBlack204W400(14.sp),
+                      )
+                      : Text(
+                        controller.homeInfo?.targetName ??
+                            StringName.keyboardAdd,
+                        style:
+                            controller.homeInfo?.targetName != null
+                                ? Styles.getTextStyleBlack204W400(14.sp)
+                                : TextStyle(
+                                  color: const Color(0xFF8651FF),
+                                  fontSize: 14.sp,
+                                  fontWeight: FontWeight.w500,
+                                ),
+                      ),
             ),
           ],
         ),
@@ -268,7 +327,7 @@ class KeyBoardView extends BaseView<KeyBoardController> {
                     height: 18.w,
                   ),
                   Text(
-                    '追爱ing',
+                    controller.homeInfo?.intimacyName ?? "",
                     textAlign: TextAlign.center,
                     style: Styles.getTextStyleBlack153W400(14.sp),
                   ),
@@ -290,16 +349,8 @@ class KeyBoardView extends BaseView<KeyBoardController> {
                             children: [
                               TextSpan(
                                 text:
-                                    controller.hasPartner.value &&
-                                            controller
-                                                    .currentChooseKeyboard
-                                                    .value
-                                                    .intimacy !=
-                                                null
-                                        ? controller
-                                            .currentChooseKeyboard
-                                            .value
-                                            .intimacy
+                                    controller.homeInfo?.intimacy != null
+                                        ? controller.homeInfo?.intimacy
                                             .toString()
                                         : "?",
                                 style: TextStyle(
@@ -349,285 +400,276 @@ class KeyBoardView extends BaseView<KeyBoardController> {
     );
   }
 
-  // 添加伴侣按钮
-  Widget _buildAddPartnerButton() {
+  // 爆款玩法区域
+  Widget _buildHitCard() {
     return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
       children: [
-        Container(
-          width: 60,
-          height: 60,
-          decoration: BoxDecoration(
-            shape: BoxShape.circle,
-            color: Colors.grey.shade200,
+        Padding(
+          padding: EdgeInsets.symmetric(horizontal: 16.r),
+          child: Assets.images.iconKeyboardHitPlay.image(
+            width: 83.w,
+            height: 22.h,
+            fit: BoxFit.cover,
           ),
-          child: const Icon(Icons.mail_outline, color: Colors.grey),
         ),
-        const SizedBox(height: 4),
-        const Text('添加', style: TextStyle(fontSize: 12)),
-      ],
-    );
-  }
-
-  // 爱情指数项目
-  Widget _buildLoveIndexItems() {
-    return Obx(() {
-      return Row(
-        children: [
-          _buildIndexItem(
-            '心情',
-            controller.moodPercentage.value,
-            Colors.pink.shade100,
-          ),
-          _buildIndexItem(
-            '颜值',
-            controller.appearancePercentage.value,
-            Colors.purple.shade100,
-          ),
-          _buildIndexItem(
-            '财富',
-            controller.wealthPercentage.value,
-            Colors.amber.shade100,
-          ),
-          _buildIndexItem(
-            '洁净',
-            controller.cleanlinessPercentage.value,
-            Colors.blue.shade100,
-          ),
-        ],
-      );
-    });
-  }
-
-  // 单个指数项
-  Widget _buildIndexItem(String title, int percentage, Color color) {
-    return Expanded(
-      child: Column(
-        crossAxisAlignment: CrossAxisAlignment.start,
-        children: [
-          Text(title, style: const TextStyle(fontSize: 12)),
-          const SizedBox(height: 4),
-          Stack(
+        const SizedBox(height: 5),
+        Padding(
+          padding: EdgeInsets.only(left: 12.w, right: 12.w),
+          child: Row(
             children: [
-              Container(
-                height: 6,
-                decoration: BoxDecoration(
-                  color: Colors.grey.shade200,
-                  borderRadius: BorderRadius.circular(3),
-                ),
-              ),
-              FractionallySizedBox(
-                widthFactor: percentage / 100,
+              GestureDetector(
+                onTap: controller.clickEasyReply,
                 child: Container(
-                  height: 6,
+                  width: 166.w,
+                  height: 155.h,
                   decoration: BoxDecoration(
-                    color: color,
-                    borderRadius: BorderRadius.circular(3),
+                    boxShadow: [
+                      BoxShadow(
+                        color: Colors.black.withValues(alpha: 0.10),
+                        offset: Offset(0, 6),
+                        blurRadius: 20,
+                        spreadRadius: 0,
+                      ),
+                    ],
+                  ),
+                  child: Assets.images.bgKeyboardEasyReply.image(
+                    fit: BoxFit.fill,
                   ),
                 ),
               ),
+              SizedBox(width: 11.w),
+              Column(
+                children: [
+                  _buildFeatureCard(
+                    bg: Assets.images.bgKeyboardIntimacyAnalyze.image(),
+                    title: Assets.images.iconKeyboardInitmacyTitle.image(
+                      width: 80.w,
+                      height: 19.h,
+                    ),
+                    subtitle: StringName.keyboardIntimacySubtitle,
+                    logo: Assets.images.iconKeyboardIntimacyLogo.image(
+                      width: 69.w,
+                      height: 68.w,
+                      fit: BoxFit.cover,
+                    ),
+                    onTap: controller.clickIntimacyAnalyze,
+                  ),
+                  SizedBox(height: 10.h),
+                  _buildFeatureCard(
+                    bg: Assets.images.bgKeyboardScreenshotReply.image(),
+                    title: Assets.images.iconKeyboardScreenshotTitle.image(
+                      width: 72.w,
+                      height: 22.h,
+                    ),
+                    subtitle: StringName.keyboardScreenshotSubtitle,
+                    logo: Assets.images.iconKeyboardScreenshotLogo.image(
+                      width: 67.w,
+                      height: 59.w,
+                      fit: BoxFit.cover,
+                    ),
+                    onTap: controller.clickScreenshotReply,
+                  ),
+                ],
+              ),
             ],
           ),
-          const SizedBox(height: 2),
-          Text(
-            '$percentage%',
-            style: TextStyle(fontSize: 10, color: Colors.grey.shade600),
-          ),
-        ],
-      ),
+        ),
+      ],
     );
   }
 
-  // 爆款玩法区域
-  Widget _buildPopularFeatures() {
-    return Container(
-      margin: const EdgeInsets.symmetric(horizontal: 16),
-      padding: const EdgeInsets.all(16),
-      decoration: BoxDecoration(
-        color: Colors.white,
-        borderRadius: BorderRadius.circular(16),
-      ),
-      child: Column(
-        crossAxisAlignment: CrossAxisAlignment.start,
-        children: [
-          Row(
-            children: [
-              Container(
-                width: 8,
-                height: 8,
+  // 功能卡片
+  Widget _buildFeatureCard({
+    required Widget bg,
+    required Widget title,
+    required String subtitle,
+    required Widget logo,
+    required VoidCallback onTap,
+  }) {
+    return GestureDetector(
+      onTap: onTap,
+      child: SizedBox(
+        height: 73.h,
+        width: 159.w,
+        child: Stack(
+          clipBehavior: Clip.none,
+          children: [
+            Positioned(
+              child: Container(
                 decoration: BoxDecoration(
-                  shape: BoxShape.circle,
-                  color: Colors.purple.shade200,
+                  boxShadow: [
+                    BoxShadow(
+                      color: Colors.black.withValues(alpha: 0.10),
+                      offset: Offset(0, 6),
+                      blurRadius: 20,
+                      spreadRadius: 0,
+                    ),
+                  ],
                 ),
+                child: bg,
               ),
-              const SizedBox(width: 8),
-              const Text(
-                '爆款玩法',
-                style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
-              ),
-            ],
-          ),
-          const SizedBox(height: 16),
-          Row(
-            children: [
-              _buildFeatureCard(
-                '追爱小键盘',
-                '轻松回复TA',
-                Colors.purple.shade50,
-                Icons.keyboard,
-                Colors.purple.shade200,
-              ),
-              const SizedBox(width: 12),
-              _buildFeatureCard(
-                '亲密度分析',
-                '探索人格密码',
-                Colors.orange.shade50,
-                Icons.favorite_border,
-                Colors.orange.shade200,
-              ),
-            ],
-          ),
-          const SizedBox(height: 12),
-          Row(
-            children: [
-              _buildFeatureCard(
-                '截图回复',
-                '上下文义分析',
-                Colors.blue.shade50,
-                Icons.screenshot_monitor,
-                Colors.blue.shade200,
-              ),
-              const SizedBox(width: 12),
-              _buildFeatureCard(
-                '截图回复',
-                '上下文义分析',
-                Colors.green.shade50,
-                Icons.message,
-                Colors.green.shade200,
-              ),
-            ],
-          ),
-        ],
+            ),
+            Row(
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [
+                Container(
+                  padding: EdgeInsets.only(top: 12.h, left: 8.w),
+                  child: Column(
+                    crossAxisAlignment: CrossAxisAlignment.start,
+                    children: [
+                      title,
+                      Padding(
+                        padding: EdgeInsets.only(left: 2.w),
+                        child: Text(
+                          subtitle,
+                          style: TextStyle(
+                            color: Colors.black.withAlpha(128),
+                            fontSize: 10.sp,
+                            fontWeight: FontWeight.w400,
+                          ),
+                        ),
+                      ),
+                    ],
+                  ),
+                ),
+              ],
+            ),
+            Positioned(top: -5.h, right: 5.w, child: logo),
+          ],
+        ),
       ),
     );
   }
 
-  // 功能卡片
-  Widget _buildFeatureCard(
-    String title,
-    String subtitle,
-    Color bgColor,
-    IconData icon,
-    Color iconColor,
-  ) {
-    return Expanded(
+  // 当前键盘人设信息
+  Widget _buildKeyboardSettings() {
+    return GestureDetector(
+      onTap: controller.clickGoKeyboardManage,
       child: Container(
-        padding: const EdgeInsets.all(12),
-        decoration: BoxDecoration(
-          color: bgColor,
-          borderRadius: BorderRadius.circular(12),
+        margin: EdgeInsets.symmetric(horizontal: 16.w),
+        padding: EdgeInsets.only(
+          left: 11.w,
+          right: 11.w,
+          top: 15.h,
+          bottom: 15.h,
+        ),
+        decoration: ShapeDecoration(
+          color: Colors.white,
+          shape: RoundedRectangleBorder(
+            side: BorderSide(width: 2, color: const Color(0xFFF5F4F9)),
+            borderRadius: BorderRadius.only(
+              topLeft: Radius.circular(16.r),
+              topRight: Radius.circular(16.r),
+              bottomLeft: Radius.circular(16.r),
+              bottomRight: Radius.circular(16.r),
+            ),
+          ),
         ),
-        child: Row(
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
           children: [
-            Expanded(
-              child: Column(
-                crossAxisAlignment: CrossAxisAlignment.start,
-                children: [
-                  Text(
-                    title,
-                    style: const TextStyle(
-                      fontSize: 14,
-                      fontWeight: FontWeight.bold,
+            Row(
+              mainAxisAlignment: MainAxisAlignment.spaceBetween,
+              children: [
+                Assets.images.iconKeyboardCurrentCharacterTitle.image(
+                  width: 90.w,
+                  height: 20.h,
+                  fit: BoxFit.cover,
+                ),
+                Row(
+                  children: [
+                    Text(
+                      StringName.keyboardGoToManage,
+                      style: TextStyle(
+                        color: Colors.black.withAlpha(102),
+                        fontSize: 12.sp,
+                        fontWeight: FontWeight.w500,
+                      ),
                     ),
-                  ),
-                  const SizedBox(height: 4),
-                  Text(
-                    subtitle,
-                    style: TextStyle(fontSize: 12, color: Colors.grey.shade700),
-                  ),
-                ],
-              ),
-            ),
-            Container(
-              width: 40,
-              height: 40,
-              decoration: BoxDecoration(
-                color: Colors.white,
-                borderRadius: BorderRadius.circular(8),
-              ),
-              child: Icon(icon, color: iconColor),
+                    Assets.images.iconKeyboardCurrentGo.image(
+                      width: 7.w,
+                      height: 7.w,
+                    ),
+                  ],
+                ),
+              ],
             ),
+            const SizedBox(height: 16),
+            Obx(() {
+              final list = controller.homeInfo?.characterInfos;
+              if (list == null) {
+                return const Center(child: CircularProgressIndicator());
+              }
+              final showList = list.take(9).toList();
+
+              return SizedBox(
+                height: 32.h * 3 + 8.h * 2, // 三行高度 + 两个间距
+                child: GridView.builder(
+                  padding: EdgeInsets.zero,
+                  physics: const NeverScrollableScrollPhysics(),
+                  // 禁止滑动
+                  itemCount: showList.length,
+                  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
+                    crossAxisCount: 3, // 每行3个
+                    mainAxisSpacing: 8.h,
+                    crossAxisSpacing: 8.w,
+                    childAspectRatio: 96.w / 32.h, // 控制宽高比
+                  ),
+                  itemBuilder: (context, index) {
+                    return _buildCharacterItem(showList[index]);
+                  },
+                ),
+              );
+            }),
           ],
         ),
       ),
     );
   }
 
-  // 键盘设置区域
-  Widget _buildKeyboardSettings() {
+  // 人设标签
+  Widget _buildCharacterItem(CharacterInfo character) {
     return Container(
-      margin: const EdgeInsets.all(16),
-      padding: const EdgeInsets.all(16),
-      decoration: BoxDecoration(
-        color: Colors.white,
-        borderRadius: BorderRadius.circular(16),
+      alignment: Alignment.center,
+      decoration: ShapeDecoration(
+        color: const Color(0xFFF5F4F9),
+        shape: RoundedRectangleBorder(
+          borderRadius: BorderRadius.circular(31.r),
+        ),
       ),
-      child: Column(
-        crossAxisAlignment: CrossAxisAlignment.start,
-        children: [
-          Row(
-            mainAxisAlignment: MainAxisAlignment.spaceBetween,
-            children: [
-              const Text(
-                '当前键盘人设',
-                style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
-              ),
-              Row(
-                children: [
-                  const Text(
-                    '去管理',
-                    style: TextStyle(fontSize: 12, color: Colors.grey),
-                  ),
-                  Icon(
-                    Icons.chevron_right,
-                    size: 16,
-                    color: Colors.grey.shade400,
-                  ),
-                ],
-              ),
-            ],
-          ),
-          const SizedBox(height: 16),
-          Wrap(
-            spacing: 8,
-            runSpacing: 8,
-            children: [
-              _buildPersonaTag('高冷'),
-              _buildPersonaTag('幽默搞笑'),
-              _buildPersonaTag('粘心暖男'),
-              _buildPersonaTag('温柔体贴'),
-              _buildPersonaTag('阳光大男孩'),
-              _buildPersonaTag('都市精英'),
-            ],
-          ),
-        ],
+      child: Text(
+        '${character.emoji}${character.name}',
+        style: Styles.getTextStyleBlack204W400(12.sp),
+        maxLines: 1,
+        overflow: TextOverflow.fade,
       ),
     );
   }
 
-  // 人设标签
-  Widget _buildPersonaTag(String text) {
+  // 活动banner
+  Widget _buildBanner() {
     return Container(
-      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
-      decoration: BoxDecoration(
-        color: Colors.grey.shade100,
-        borderRadius: BorderRadius.circular(16),
-      ),
-      child: Row(
-        mainAxisSize: MainAxisSize.min,
+      width: 328.w,
+      height: 64.h,
+      child: Stack(
         children: [
-          const Icon(Icons.emoji_emotions, size: 16, color: Colors.amber),
-          const SizedBox(width: 4),
-          Text(text, style: const TextStyle(fontSize: 12)),
+          Assets.images.iconKeyboardBanner.image(width: 328.w, height: 64.h),
+
+          Positioned(
+            right: 53.w,
+            bottom: 18.h,
+            child: Obx(
+              () => Text(
+                controller.formattedTime,
+                style: TextStyle(
+                  color: Colors.white,
+                  fontSize: 12.sp,
+                  fontWeight: FontWeight.w500,
+                ),
+              ),
+            ),
+          ),
         ],
       ),
     );
@@ -638,65 +680,3 @@ class KeyBoardView extends BaseView<KeyBoardController> {
     return const Color(0xFFF5F5F5);
   }
 }
-
-class ProgressBar extends StatelessWidget {
-  final String title;
-  final RxInt value; // 例如传入 50,代表 50%
-  final Color color;
-
-  const ProgressBar({
-    super.key,
-    required this.title,
-    required this.value,
-    required this.color,
-  });
-
-  @override
-  Widget build(BuildContext context) {
-    return Obx(() {
-      final double progress = (value.value / 100).clamp(0.0, 1.0); // 保证 0~1 范围
-      return Container(
-        child: Row(
-          children: [
-            SizedBox(width: 40, child: Text(title)),
-            const SizedBox(width: 8),
-            Expanded(
-              child: Stack(
-                children: [
-                  Container(
-                    height: 20,
-                    decoration: BoxDecoration(
-                      color: color.withOpacity(0.15), // 修正:用 withOpacity
-                      borderRadius: BorderRadius.circular(20.r),
-                    ),
-                  ),
-                  FractionallySizedBox(
-                    widthFactor: progress,
-                    child: Container(
-                      height: 20.h,
-                      decoration: BoxDecoration(
-                        color: color,
-                        borderRadius: BorderRadius.circular(20.r),
-                      ),
-                    ),
-                  ),
-                  Positioned.fill(
-                    child: Center(
-                      child: Text(
-                        "${value.value}%",
-                        style: const TextStyle(
-                          color: Colors.white,
-                          fontSize: 12,
-                        ),
-                      ),
-                    ),
-                  ),
-                ],
-              ),
-            ),
-          ],
-        ),
-      );
-    });
-  }
-}

+ 2 - 2
lib/module/mine/mine_controller.dart

@@ -62,10 +62,10 @@ class MineController extends BaseController {
     debugPrint('clickOnlineCustomerService');
     isTest?
     accountRepository
-        .loginUserLogin("11223344551", "1122")
+        .loginUserLogin("11223344553", "1122")
         .then((data) {
           Get.back();
-
+          ToastUtil.show(StringName.loginSuccess);
 
         })
         .catchError((error) {

+ 5 - 6
lib/module/profile/profile_controller.dart

@@ -37,8 +37,6 @@ class ProfileController extends BaseController {
     AtmobLog.d(tag, '....init');
   }
 
-
-
   @override
   void onInit() {
     super.onInit();
@@ -79,22 +77,23 @@ class ProfileController extends BaseController {
 
   clickAddButton() {
     AtmobLog.d(tag, "clickAddButton");
-    ProfileEditPage.start(
-
-    );
+    ProfileEditPage.start();
   }
 
   clickSaveButton() {
     AtmobLog.d(tag, "clickSaveButton");
     final keyboardInfo = _currentCustomKeyboardInfo.value;
-    if(_currentCustomKeyboardInfo.value.isChoose==true){
+    if (_currentCustomKeyboardInfo.value.isChoose == true) {
       ToastUtil.show("当前键盘已选择");
+      clickBack();
       return;
     }
     if (keyboardInfo.id?.isNotEmpty == true) {
       try {
         keyboardRepository.keyboardChoose(keyboardId: keyboardInfo.id!);
+        keyboardRepository.refreshData();
         ToastUtil.show("当前键盘已选择");
+        clickBack();
       } catch (error) {
         if (error is ServerErrorException) {
           ToastUtil.show(error.message);

+ 1 - 1
lib/module/profile/profile_page.dart

@@ -70,7 +70,7 @@ class ProfilePage extends BasePage<ProfileController> {
           bottom: 20.h,
           left: 16.w,
           right: 16.w,
-          child: GestureDetector(
+          child: InkWell(
             onTap: () {
               controller.clickSaveButton();
             },

+ 1 - 0
lib/module/store/store_controller.dart

@@ -460,6 +460,7 @@ class StoreController extends BaseController implements PaymentStatusCallback {
     PayWayInfo payWayInfo,
     GoodsInfo goodsInfo,
   ) {
+    LoadingDialog.hide();
     PaymentSuccessDialog.show(
       infoText:
           memberStatusInfo?.permanent == true

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

@@ -124,6 +124,14 @@ class $AssetsImagesGen {
   AssetGenImage get bgKeyboard =>
       const AssetGenImage('assets/images/bg_keyboard.webp');
 
+  /// File path: assets/images/bg_keyboard_easy_reply.webp
+  AssetGenImage get bgKeyboardEasyReply =>
+      const AssetGenImage('assets/images/bg_keyboard_easy_reply.webp');
+
+  /// File path: assets/images/bg_keyboard_intimacy_analyze.webp
+  AssetGenImage get bgKeyboardIntimacyAnalyze =>
+      const AssetGenImage('assets/images/bg_keyboard_intimacy_analyze.webp');
+
   /// File path: assets/images/bg_keyboard_love.webp
   AssetGenImage get bgKeyboardLove =>
       const AssetGenImage('assets/images/bg_keyboard_love.webp');
@@ -136,6 +144,10 @@ class $AssetsImagesGen {
   AssetGenImage get bgKeyboardManageIntimacy =>
       const AssetGenImage('assets/images/bg_keyboard_manage_intimacy.webp');
 
+  /// File path: assets/images/bg_keyboard_screenshot_reply.webp
+  AssetGenImage get bgKeyboardScreenshotReply =>
+      const AssetGenImage('assets/images/bg_keyboard_screenshot_reply.webp');
+
   /// File path: assets/images/bg_mine.webp
   AssetGenImage get bgMine => const AssetGenImage('assets/images/bg_mine.webp');
 
@@ -408,10 +420,39 @@ class $AssetsImagesGen {
   AssetGenImage get iconIntimacyAnalyseUnlock =>
       const AssetGenImage('assets/images/icon_intimacy_analyse_unlock.webp');
 
+  /// File path: assets/images/icon_keyboard_banner.webp
+  AssetGenImage get iconKeyboardBanner =>
+      const AssetGenImage('assets/images/icon_keyboard_banner.webp');
+
+  /// File path: assets/images/icon_keyboard_current_character_title.webp
+  AssetGenImage get iconKeyboardCurrentCharacterTitle => const AssetGenImage(
+    'assets/images/icon_keyboard_current_character_title.webp',
+  );
+
+  /// File path: assets/images/icon_keyboard_current_go.webp
+  AssetGenImage get iconKeyboardCurrentGo =>
+      const AssetGenImage('assets/images/icon_keyboard_current_go.webp');
+
   /// File path: assets/images/icon_keyboard_default_avatar.webp
   AssetGenImage get iconKeyboardDefaultAvatar =>
       const AssetGenImage('assets/images/icon_keyboard_default_avatar.webp');
 
+  /// File path: assets/images/icon_keyboard_explosive_play.webp
+  AssetGenImage get iconKeyboardExplosivePlay =>
+      const AssetGenImage('assets/images/icon_keyboard_explosive_play.webp');
+
+  /// File path: assets/images/icon_keyboard_hit_play.webp
+  AssetGenImage get iconKeyboardHitPlay =>
+      const AssetGenImage('assets/images/icon_keyboard_hit_play.webp');
+
+  /// File path: assets/images/icon_keyboard_initmacy_title.webp
+  AssetGenImage get iconKeyboardInitmacyTitle =>
+      const AssetGenImage('assets/images/icon_keyboard_initmacy_title.webp');
+
+  /// File path: assets/images/icon_keyboard_intimacy_logo.webp
+  AssetGenImage get iconKeyboardIntimacyLogo =>
+      const AssetGenImage('assets/images/icon_keyboard_intimacy_logo.webp');
+
   /// File path: assets/images/icon_keyboard_love_Index.webp
   AssetGenImage get iconKeyboardLoveIndex =>
       const AssetGenImage('assets/images/icon_keyboard_love_Index.webp');
@@ -441,10 +482,22 @@ class $AssetsImagesGen {
   AssetGenImage get iconKeyboardManageX =>
       const AssetGenImage('assets/images/icon_keyboard_manage_x.webp');
 
+  /// File path: assets/images/icon_keyboard_screenshot_logo.webp
+  AssetGenImage get iconKeyboardScreenshotLogo =>
+      const AssetGenImage('assets/images/icon_keyboard_screenshot_logo.webp');
+
+  /// File path: assets/images/icon_keyboard_screenshot_title.webp
+  AssetGenImage get iconKeyboardScreenshotTitle =>
+      const AssetGenImage('assets/images/icon_keyboard_screenshot_title.webp');
+
   /// File path: assets/images/icon_keyboard_title.webp
   AssetGenImage get iconKeyboardTitle =>
       const AssetGenImage('assets/images/icon_keyboard_title.webp');
 
+  /// File path: assets/images/icon_keyboard_triangle.webp
+  AssetGenImage get iconKeyboardTriangle =>
+      const AssetGenImage('assets/images/icon_keyboard_triangle.webp');
+
   /// File path: assets/images/icon_keyboard_vip_logo.webp
   AssetGenImage get iconKeyboardVipLogo =>
       const AssetGenImage('assets/images/icon_keyboard_vip_logo.webp');
@@ -679,9 +732,12 @@ class $AssetsImagesGen {
     bgIntimacyAnalyseReportPreviewBubble,
     bgIntimacyAnalyseReportPreviewMask,
     bgKeyboard,
+    bgKeyboardEasyReply,
+    bgKeyboardIntimacyAnalyze,
     bgKeyboardLove,
     bgKeyboardManage,
     bgKeyboardManageIntimacy,
+    bgKeyboardScreenshotReply,
     bgMine,
     bgMineVipCard,
     bgProfileEditIntimacy,
@@ -747,7 +803,14 @@ class $AssetsImagesGen {
     iconIntimacyAnalyseReportPreviewLove,
     iconIntimacyAnalyseReportPreviewTitle,
     iconIntimacyAnalyseUnlock,
+    iconKeyboardBanner,
+    iconKeyboardCurrentCharacterTitle,
+    iconKeyboardCurrentGo,
     iconKeyboardDefaultAvatar,
+    iconKeyboardExplosivePlay,
+    iconKeyboardHitPlay,
+    iconKeyboardInitmacyTitle,
+    iconKeyboardIntimacyLogo,
     iconKeyboardLoveIndex,
     iconKeyboardLoveLogo,
     iconKeyboardManageCustom,
@@ -755,7 +818,10 @@ class $AssetsImagesGen {
     iconKeyboardManageIntimacyText,
     iconKeyboardManagePlus,
     iconKeyboardManageX,
+    iconKeyboardScreenshotLogo,
+    iconKeyboardScreenshotTitle,
     iconKeyboardTitle,
+    iconKeyboardTriangle,
     iconKeyboardVipLogo,
     iconMemberRetainClose,
     iconMineAbout,

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

@@ -144,6 +144,11 @@ class StringName {
   static final String profileSave = 'profile_save'.tr; // 完成
   static final String profileEditSave = 'profile_edit_save'.tr; // 保存
   static final String keyboardMemberOpen = 'keyboard_member_open'.tr; // 开通会员
+  static final String keyboardIntimacySubtitle = 'keyboard_intimacy_subtitle'.tr; // 探索人格/情感特质
+  static final String keyboardScreenshotSubtitle = 'keyboard_screenshot_subtitle'.tr; // 上下文语义分析
+  static final String keyboardGoToManage = 'keyboard_go_to_manage'.tr; // 去管理
+  static final String keyboardAdd = 'keyboard_add'.tr; // 添加
+  static final String keyboardNoLogin = 'keyboard_no_login'.tr; // 自己
   static final String keyboardGuideGoWechat = 'keyboard_guide_go_wechat'.tr; // 去微信体验
   static final String keyboardGuideWechatNotInstall = 'keyboard_guide_wechat_not_install'.tr; // 未安装微信
   static final String keyboardGuideInputHint = 'keyboard_guide_input_hint'.tr; // 选择粘贴TA的话,选择人设风格回复
@@ -299,6 +304,11 @@ class StringMultiSource {
       'profile_save': '完成',
       'profile_edit_save': '保存',
       'keyboard_member_open': '开通会员',
+      'keyboard_intimacy_subtitle': '探索人格/情感特质',
+      'keyboard_screenshot_subtitle': '上下文语义分析',
+      'keyboard_go_to_manage': '去管理',
+      'keyboard_add': '添加',
+      'keyboard_no_login': '自己',
       'keyboard_guide_go_wechat': '去微信体验',
       'keyboard_guide_wechat_not_install': '未安装微信',
       'keyboard_guide_input_hint': '选择粘贴TA的话,选择人设风格回复',

+ 74 - 0
lib/widget/pargress_bar.dart

@@ -0,0 +1,74 @@
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:get/get.dart';
+import 'package:flutter/material.dart';
+
+class ProgressBar extends StatelessWidget {
+  final String title;
+  final RxInt value;
+  final Color color;
+
+  const ProgressBar({
+    super.key,
+    required this.title,
+    required this.value,
+    required this.color,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Obx(() {
+      final double progress = (value.value / 100).clamp(0.0, 1.0);
+      return Container(
+        child: Row(
+          children: [
+            Text(title),
+            SizedBox(width: 3.w),
+            Expanded(
+              child: Stack(
+                children: [
+                  Container(
+                    height: 11.h,
+                    decoration: BoxDecoration(
+                      color: color.withValues(alpha: 0.3),
+                      borderRadius: BorderRadius.circular(53.r),
+                    ),
+                  ),
+                  FractionallySizedBox(
+                    widthFactor: progress,
+                    child: Container(
+                      height: 11.h,
+                      decoration: BoxDecoration(
+                        color: color,
+                        borderRadius: BorderRadius.circular(53.r),
+                      ),
+                    ),
+                  ),
+                  Positioned.fill(
+                    child: Center(
+                      child: Text(
+                        "${value.value}%",
+                        textAlign: TextAlign.center,
+                        style: TextStyle(
+                          color: Colors.white,
+                          fontSize: 7.sp,
+                          fontWeight: FontWeight.w500,
+                          shadows: [
+                            Shadow(
+                              color: Colors.black.withValues(alpha: 0.6),
+                              offset: Offset(1, 1),
+                              blurRadius: 3.r,
+                            ),
+                          ],
+                        ),
+                      ),
+                    ),
+                  ),
+                ],
+              ),
+            ),
+          ],
+        ),
+      );
+    });
+  }
+}