import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:keyboard/module/keyboard_guide/keyboard_guide_controller.dart'; import 'package:keyboard/router/app_pages.dart'; import 'package:keyboard/utils/default_keyboard_helper.dart'; import 'package:keyboard/utils/keyboard_guide_record_util.dart' show KeyboardGuideRecordUtil; import 'package:keyboard/utils/method_chanel_ios_util.dart'; import 'package:keyboard/utils/toast_util.dart'; import 'package:keyboard/widget/platform_util.dart'; import 'package:lottie/lottie.dart'; import '../../base/base_page.dart'; import '../../data/bean/keyboard_guide_msg.dart'; import '../../data/consts/event_report.dart'; import '../../handler/event_handler.dart'; import '../../resource/assets.gen.dart'; import '../../resource/colors.gen.dart'; import '../../resource/string.gen.dart'; import '../../utils/clipboard_util.dart'; import '../../utils/url_launcher_util.dart'; import '../../widget/ai/ai_generate_tip_widget.dart'; import '../../widget/app_lifecycle_widget.dart'; import '../intimacy_scale/intimacy_scale_page.dart'; import 'enums/keyboard_guide_msg_type.dart'; /// 键盘引导页面 class KeyboardGuidePage extends BasePage { const KeyboardGuidePage({super.key}); /// 跳转到键盘引导页 static void start() { Get.toNamed(RoutePath.keyboardGuide); } /// 跳转并关闭当前页 static void startAndOffMe() { Get.offNamed(RoutePath.keyboardGuide); } @override immersive() { return false; } @override Widget buildBody(BuildContext context) { return Scaffold( backgroundColor: backgroundColor(), body: AppLifecycleWidget( onAppLifecycleCallback: (isForeground) { // 完成教程 controller.setNotFirstShowKeyboardTutorial(); if (isForeground) { // 切换到前台时,重新检查设置,更新按钮状态 controller.checkSetting(); // 如果选择为默认键盘了,则尝试显示引导弹窗 if (controller.isDefaultKeyboard.value && KeyboardGuideRecordUtil.isFirstShowKeyboardGuide()) { controller.showGuideOverlayDialog(); } } }, child: Column( children: [ // 使用 Obx 监听 isDefaultKeyboard 的变化 Obx(() { // 当 isDefaultKeyboard 变为 true 时,显示引导对话框 if (controller.isDefaultKeyboard.value) { // 使用 Future.microtask 确保在构建完成后调用 Future.microtask(() => controller.showGuideOverlayDialog()); } // 返回一个空的 SizedBox,不影响 UI return SizedBox.shrink(); }), // 标题栏 _buildTitleBar(), // 消息列表 Expanded(flex: 1, child: _buildContent()), // 底部输入栏 _buildBottomInput(), ], ), ), ); } // 标题栏 Widget _buildTitleBar() { return Container( color: backgroundColor(), height: kToolbarHeight, padding: EdgeInsets.symmetric(horizontal: 16.0), child: Row( children: [ // 返回按钮 GestureDetector( onTap: controller.clickBack, child: Assets.images.iconMineBackArrow.image( width: 24.w, height: 24.h, ), ), // 标题 Expanded( child: Container( alignment: Alignment.center, child: Text("", style: const TextStyle(fontSize: 18)), ), ), // 右侧按钮 GestureDetector( onTap: () async { bool result = await UrlLauncherUtil.openWeChat(); EventHandler.report(EventId.event_03007); if (!result) { ToastUtil.show(StringName.keyboardGuideWechatNotInstall); } }, child: Container( padding: EdgeInsets.only( left: 12.w, right: 14.w, top: 10.w, bottom: 10.w, ), decoration: BoxDecoration( image: DecorationImage( image: Assets.images.bgGoApp.provider(), fit: BoxFit.fill, ), ), child: Row( children: [ Assets.images.iconWechat.image(height: 22.w, width: 22.w), SizedBox(width: 1.0), Text( StringName.keyboardGuideGoWechat, style: TextStyle( color: ColorName.black80, fontSize: 12, fontWeight: FontWeight.w400, ), ), ], ), ), ), ], ), ); } /// 内容 Widget _buildContent() { return Obx(() { // 选择了默认键盘,显示聊天列表 if (controller.isDefaultKeyboard.value) { return _buildChatList(); } else { // 未选择,显示引导动画 return _buildGuideAnimation(); } }); } /// 引导动画 Widget _buildGuideAnimation() { Widget animationWidget; if (PlatformUtil.isIOS) { animationWidget = Lottie.asset( Assets.anim.animKeyboardFloatingWindowChooseKeyboardIos, repeat: true, ); } else if (PlatformUtil.isAndroid) { animationWidget = Lottie.asset( Assets.anim.animKeyboardFloatingWindowChooseKeyboardAndroid, repeat: true, ); } else { animationWidget = SizedBox.shrink(); } return Container(child: animationWidget); } /// 聊天列表 Widget _buildChatList() { return Obx(() { return ListView.builder( controller: controller.scrollController, itemCount: controller.msgList.length + 1, itemBuilder: (BuildContext context, int index) { if (index == controller.msgList.length) { return (controller.msgList.length > 5) ? Container( child: _buildAiGenerateTip(), ) : SizedBox(); } KeyboardGuideMsg msg = controller.msgList[index]; return _buildMsgItem(msg, index); }, ); }); } Widget _buildAiGenerateTip() { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ AiGenerateTipWidget.normalTip(textColor: Colors.black.withAlpha(92)), ], ); } /// 构建底部输入框 Widget _buildBottomInput() { return Center( child: Column( children: [ Container( color: ColorName.msgInputBar, padding: const EdgeInsets.symmetric( vertical: 11.0, horizontal: 12.0, ), child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Expanded( flex: 1, // 输入框的圆角边框 child: Container( decoration: BoxDecoration( color: ColorName.white, borderRadius: BorderRadius.circular(10.0), ), child: Obx(() { return TextField( // 是否可用,选择了默认键盘时,才可用 enabled: controller.isIOS.value ? true : controller.isDefaultKeyboard.value, // 是否自动获取焦点 autofocus: false, style: TextStyle( color: ColorName.black80, fontSize: 14.0, fontWeight: FontWeight.w500, ), // 设置光标颜色 cursorColor: ColorName.inputCursor, // 光标宽度 cursorWidth: 2.0, // 光标圆角 cursorRadius: Radius.circular(2), // 设置按钮显示为发送 textInputAction: TextInputAction.send, // 用户点击软键盘的发送按钮时,触发回调 onSubmitted: (value) { var msg = controller.editingController.text; controller.sendMsg(msg); // 保持输入框焦点获取,不降下键盘 controller.requestInputFocus(); }, // 输入框焦点 focusNode: controller.inputFocusNode, // 点击外部区域,关闭软键盘 onTapUpOutside: (event) { // if (PlatformUtil.isIOS) { // controller.clearInputFocus(); // } }, // 输入框控制器 controller: controller.editingController, decoration: InputDecoration( // 提示文字 hintText: StringName.keyboardGuideInputHint, hintStyle: TextStyle( fontSize: 14.0, fontWeight: FontWeight.w400, color: ColorName.black40, ), // 去掉默认的边框 border: InputBorder.none, // 设置输入框的内边距 contentPadding: EdgeInsets.symmetric( horizontal: 9.0, vertical: 13.0, ), ), ); }), ), ), ], ), ), ], ), ); } /// 构建聊天气泡 Widget _buildMsgBubble(KeyboardGuideMsg msg) { // 设置气泡的外边距,让气泡不易过长 double marginValue = 35.0; EdgeInsets marginEdgeInsets; if (msg.isMe) { marginEdgeInsets = EdgeInsets.only(left: marginValue); } else { marginEdgeInsets = EdgeInsets.only(right: marginValue); } // 圆角大小 double radiusSize = 14.0; // 背景圆角 BorderRadius bgBorderRadius; if (msg.isMe) { bgBorderRadius = BorderRadius.only( topLeft: Radius.circular(radiusSize), topRight: Radius.circular(0), bottomLeft: Radius.circular(radiusSize), bottomRight: Radius.circular(radiusSize), ); } else { bgBorderRadius = BorderRadius.only( topLeft: Radius.circular(0), topRight: Radius.circular(radiusSize), bottomLeft: Radius.circular(radiusSize), bottomRight: Radius.circular(0), ); } // Flexible,文本超过一行时,自动换行,并且不超过最大宽度,不超过一行时,则自动包裹内容 return Flexible( child: Container( padding: EdgeInsets.symmetric(vertical: 12.0, horizontal: 10.0), margin: marginEdgeInsets, decoration: BoxDecoration( color: msg.isMe ? ColorName.msgBubbleMe : ColorName.msgBubbleTa, borderRadius: bgBorderRadius, ), child: GestureDetector( onTap: () { // 复制内容到剪切板 if (msg.type == KeyboardGuideMsgType.copy.type) { ClipboardUtil.copyToClipboard(msg.content); ToastUtil.show(StringName.copySuccess); } else if (msg.type == KeyboardGuideMsgType.intimacySetting.type) { // 跳转到亲密度设置页 IntimacyScalePage.start(); } }, child: Row( // 宽高包裹内容 mainAxisSize: MainAxisSize.min, // 图标和文本,垂直居中 crossAxisAlignment: CrossAxisAlignment.center, children: [ Flexible( // 消息文本 child: Text( msg.content, style: TextStyle( fontSize: 14.0, color: ColorName.black80, fontWeight: FontWeight.w500, height: 1.5, ), softWrap: true, ), ), // 只有对方发送的,才有操作按钮 if (!msg.isMe) Visibility( visible: msg.type != KeyboardGuideMsgType.normal.type, child: Padding( padding: EdgeInsets.only(left: 8.0), child: _buildMsgActionBtn(msg), ), ), ], ), ), ), ); } /// 消息操作按钮 Widget _buildMsgActionBtn(KeyboardGuideMsg msg) { if (msg.type == KeyboardGuideMsgType.copy.type) { return Assets.images.iconCopy.image(width: 18.w, height: 18.w); } else if (msg.type == KeyboardGuideMsgType.intimacySetting.type) { return Assets.images.iconSetting.image(width: 18.w, height: 18.w); } else { return SizedBox.shrink(); } } /// 构建聊天消息列表项 Widget _buildMsgItem(KeyboardGuideMsg msg, int index) { return Obx(() { Widget content; // 自己发的 if (msg.isMe) { content = Row( // 如果是自己发的,则在右边 mainAxisAlignment: MainAxisAlignment.end, // 顶部对齐 crossAxisAlignment: CrossAxisAlignment.start, children: [ // 聊天气泡 _buildMsgBubble(msg), SizedBox(width: 9.w), // 头像 _buildAvatar(msg), ], ); } else { // 对方发的 content = Row( // 如果是自己发的,则在右边 mainAxisAlignment: MainAxisAlignment.start, // 顶部对齐 crossAxisAlignment: CrossAxisAlignment.start, children: [ // 头像 _buildAvatar(msg), SizedBox(width: 9.w), // 聊天气泡 _buildMsgBubble(msg), ], ); } bool isTargetGuildMsg = controller.guideMsgIndex.value == index; return Container( margin: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.0.h), child: isTargetGuildMsg ? Container(key: controller.guideMsgGlobalKey, child: content) : content, ); }); } /// 构建头像 Widget _buildAvatar(KeyboardGuideMsg msg) { double avatarSize = 36.0; return CircleAvatar( radius: 20, child: msg.isMe ? Assets.images.iconDefaultAvatar.image( height: avatarSize, width: avatarSize, ) : Assets.images.iconTaAvatar.image( height: avatarSize, width: avatarSize, ), ); } }