diff --git a/docs/superpowers/plans/2026-04-28-hide-ai-assistant.md b/docs/superpowers/plans/2026-04-28-hide-ai-assistant.md new file mode 100644 index 000000000..4f644f509 --- /dev/null +++ b/docs/superpowers/plans/2026-04-28-hide-ai-assistant.md @@ -0,0 +1,416 @@ +# 隐藏"AI 全能助手"模块 实施计划 + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 通过新增全局开关 `AppConfig.hideAiAssistant`,在 true 时让首页和发现页切换为隐藏"AI 全能助手"的精简布局。 + +**Architecture:** 单一全局静态 bool 控制 UI 分支。两个 View 各新增一个 `_buildSimplifiedAILayout()` 方法,原有方法和 controller 数据完全不动。新布局使用现有的卡片样式语言(渐变色、圆角、阴影),保持视觉一致性。 + +**Tech Stack:** Flutter, GetX, flutter_screenutil, flutter_intro + +**Spec:** [`docs/superpowers/specs/2026-04-28-hide-ai-assistant-design.md`](../specs/2026-04-28-hide-ai-assistant-design.md) + +--- + +## 文件清单 + +| 文件 | 改动 | 说明 | +|---|---|---| +| `lib/data/models/appconfig.dart` | 修改 | 新增静态字段 `hideAiAssistant` | +| `lib/modules/home/views/home_view.dart` | 修改 | 新增 `_buildSimplifiedAILayout()`;`build()` 中按开关分发 | +| `lib/modules/explore/views/explore_view.dart` | 修改 | 新增 `_buildSimplifiedAILayout()`;`build()` 中按开关分发 | + +无需新建文件,无需修改 controller、路由、翻译资源。 + +--- + +## 关于测试策略 + +本项目 `test/` 目录只有翻译资源测试,没有 widget test 体系。本次为纯 UI 布局调整,强行写 widget test 既不符合项目惯例又脆弱。验证手段为: + +- **静态校验**:`flutter analyze` 不引入新 warning +- **手动验证**:在两种开关值下分别启动应用,肉眼比对首页和发现页 + +每个 Task 末尾会包含静态校验步骤。手动验证集中放在最后的 Task 4。 + +--- + +## Task 1: 新增配置开关 + +**Files:** +- Modify: `lib/data/models/appconfig.dart` + +- [ ] **Step 1: 在 AppConfig 类中新增静态字段** + +打开 `lib/data/models/appconfig.dart`,找到 `class AppConfig {` 后第一行(`static late UserGetAppConfigResp config;` 上方),插入字段。 + +最终类的开头部分应是: + +```dart +class AppConfig { + // 中文注释:是否隐藏"AI全能助手"模块。 + // true => 首页/发现页切换为精简布局,新手引导跳过 AI 引导步骤 + // false => 保持原有布局 + // TODO: 后续接入 BLE PID 判断逻辑,B017 设备连接时自动置 true + static bool hideAiAssistant = false; + + static late UserGetAppConfigResp config; + + // 新增一个私有的静态布尔值来跟踪初始化状态 + static bool _isInitialized = false; + + // ... 其余方法保持不变 +``` + +- [ ] **Step 2: 静态校验** + +Run: `cd /Users/liuxiamin/work/flutter_projects/deep_voice && flutter analyze lib/data/models/appconfig.dart` +Expected: 无新增 warning/error + +- [ ] **Step 3: 提交** + +```bash +git add lib/data/models/appconfig.dart +git commit -m "feat: 新增 AppConfig.hideAiAssistant 全局开关" +``` + +--- + +## Task 2: 首页新增精简布局 + +**Files:** +- Modify: `lib/modules/home/views/home_view.dart` + +- [ ] **Step 1: 新增 import** + +确认 `home_view.dart` 顶部已 import `'../../../data/models/appconfig.dart'`。该文件第 9 行已有 `import '../../../data/models/appconfig_model.dart';`,需要**追加**一行: + +```dart +import '../../../data/models/appconfig.dart'; +``` + +- [ ] **Step 2: 在 build() 中按开关分发** + +在 `home_view.dart` 找到 `build()` 方法中以下代码(约 145-147 行): + +```dart + // 热门AI体验 + _buildSectionTitle(isDarkMode), + SizedBox(height: 16.h), + _buildPremiumAILayout(), +``` + +替换为: + +```dart + // 热门AI体验 + _buildSectionTitle(isDarkMode), + SizedBox(height: 16.h), + AppConfig.hideAiAssistant + ? _buildSimplifiedAILayout() + : _buildPremiumAILayout(), +``` + +- [ ] **Step 3: 在文件末尾(HomeView 类的最后一个方法 `_buildFeatureCard` 之后、类闭合 `}` 之前)新增精简布局方法** + +在 `_buildFeatureCard` 方法结束后,类闭合大括号之前,添加: + +```dart + // 精简布局:隐藏"AI全能助手",仅保留翻译 + 会议助手,左右等宽 + // 注意:本布局不包裹 IntroStepBuilder(order: 3),新手引导走完唤醒后自然结束 + Widget _buildSimplifiedAILayout() { + final bool isDarkMode = Get.isDarkMode; + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 左侧:翻译 + Expanded( + flex: 1, + child: _buildFeatureCard( + title: 'interpretation'.tr, + description: 'simultaneousInterpretationInfo'.tr, + icon: Icons.translate, + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + const Color(0xFF4CAF50).withOpacity(0.3), + const Color(0xFF009688).withOpacity(0.3), + ], + ), + onTap: controller.openTranslation, + iconOnTop: true, + height: 140.h, + isDarkMode: isDarkMode, + iconColor: const Color(0xFF4CAF50), + ), + ), + SizedBox(width: 16.w), + // 右侧:会议助手 + Expanded( + flex: 1, + child: _buildFeatureCard( + title: 'conferenceAssistant'.tr, + description: 'conferenceAssistantInfo'.tr, + icon: Icons.people, + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + const Color(0xFFab47bc).withOpacity(0.3), + const Color(0xFFec407a).withOpacity(0.3), + ], + ), + onTap: () => controller.openMeet(), + iconOnTop: true, + height: 140.h, + isDarkMode: isDarkMode, + iconColor: const Color(0xFFd81b60), + ), + ), + ], + ); + } +``` + +- [ ] **Step 4: 静态校验** + +Run: `cd /Users/liuxiamin/work/flutter_projects/deep_voice && flutter analyze lib/modules/home/views/home_view.dart` +Expected: 无新增 warning/error + +- [ ] **Step 5: 提交** + +```bash +git add lib/modules/home/views/home_view.dart +git commit -m "feat(home): 新增精简布局,隐藏 AI 全能助手时使用" +``` + +--- + +## Task 3: 发现页新增精简布局 + +**Files:** +- Modify: `lib/modules/explore/views/explore_view.dart` + +- [ ] **Step 1: 新增 import** + +在 `explore_view.dart` 顶部 import 区追加: + +```dart +import '../../../data/models/appconfig.dart'; +``` + +- [ ] **Step 2: 在 build() 中按开关分发** + +找到 `explore_view.dart` 中以下代码(约第 67-68 行): + +```dart + // AI功能列表 + SizedBox(height: 24.h), + _buildCustomAILayout(isDarkMode), +``` + +替换为: + +```dart + // AI功能列表 + SizedBox(height: 24.h), + AppConfig.hideAiAssistant + ? _buildSimplifiedAILayout(isDarkMode) + : _buildCustomAILayout(isDarkMode), +``` + +- [ ] **Step 3: 在文件末尾(`_buildAIFeatureItemWide` 方法之后、ExploreView 类闭合 `}` 之前)新增精简布局方法** + +```dart + // 精简布局:隐藏"AI全能助手",仅保留翻译 + 会议助手,上下堆叠 banner 卡 + // 复用 controller.aiFeatures 中索引 1(翻译)和 2(会议助手)的数据 + Widget _buildSimplifiedAILayout(bool isDarkMode) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'aiFunction'.tr, // AI功能 + style: TextStyle( + fontSize: 18.sp, + fontWeight: FontWeight.w600, + color: isDarkMode ? Colors.white : Colors.grey[800], + ), + ), + SizedBox(height: 16.h), + // 翻译(banner 卡) + _buildSimplifiedBannerCard(controller.aiFeatures[1], 1, isDarkMode), + SizedBox(height: 12.h), + // 会议助手(banner 卡) + _buildSimplifiedBannerCard(controller.aiFeatures[2], 2, isDarkMode), + ], + ); + } + + // 精简布局下的 banner 卡(图标右上角,标题/描述左下角) + Widget _buildSimplifiedBannerCard( + AIFeature feature, int index, bool isDarkMode) { + return GestureDetector( + onTap: () => controller.onAIFeatureTap(index), + child: Container( + height: 130.h, + padding: EdgeInsets.all(16.w), + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + feature.startColor.withOpacity(0.3), + feature.endColor.withOpacity(0.3), + ], + ), + borderRadius: BorderRadius.circular(20.r), + boxShadow: [ + BoxShadow( + color: isDarkMode + ? Colors.black.withOpacity(0.2) + : Colors.grey.withOpacity(0.1), + blurRadius: 8, + offset: const Offset(0, 4), + ), + ], + ), + child: Stack( + children: [ + // 图标右上角 + Positioned( + top: 0, + right: 0, + child: Container( + width: 44.w, + height: 44.w, + decoration: BoxDecoration( + color: feature.iconColor.withOpacity(0.2), + shape: BoxShape.circle, + ), + child: Icon( + feature.icon, + size: 22.sp, + color: feature.iconColor, + ), + ), + ), + // 标题 + 描述左下角 + Align( + alignment: Alignment.bottomLeft, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + feature.title, + style: TextStyle( + fontSize: 16.sp, + fontWeight: FontWeight.w600, + color: isDarkMode ? Colors.white : Colors.grey[800], + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + SizedBox(height: 4.h), + Text( + feature.description, + style: TextStyle( + fontSize: 12.sp, + color: isDarkMode ? Colors.grey[400] : Colors.grey[600], + ), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ), + ], + ), + ), + ); + } +``` + +- [ ] **Step 4: 静态校验** + +Run: `cd /Users/liuxiamin/work/flutter_projects/deep_voice && flutter analyze lib/modules/explore/views/explore_view.dart` +Expected: 无新增 warning/error + +- [ ] **Step 5: 提交** + +```bash +git add lib/modules/explore/views/explore_view.dart +git commit -m "feat(explore): 新增精简布局,隐藏 AI 全能助手时使用" +``` + +--- + +## Task 4: 全量校验与手动验证 + +- [ ] **Step 1: 整个项目静态校验** + +Run: `cd /Users/liuxiamin/work/flutter_projects/deep_voice && flutter analyze` +Expected: 无新增 warning/error(项目已有的告警可忽略) + +- [ ] **Step 2: 跑现有测试** + +Run: `cd /Users/liuxiamin/work/flutter_projects/deep_voice && flutter test` +Expected: 全部 PASS(应不受本次改动影响) + +- [ ] **Step 3: 默认场景手动验证(hideAiAssistant = false)** + +确认 `AppConfig.hideAiAssistant` 为 `false`(默认值),启动应用: + +Run: `cd /Users/liuxiamin/work/flutter_projects/deep_voice && flutter run` + +肉眼检查: +- 首页"热门AI体验"区域:左大卡(AI 全能助手)+ 右两小卡(翻译、会议助手),与改动前一致 +- 发现页"AI 功能"区域:上层 2 方卡(AI 全能助手 + 同声传译)+ 下层 1 宽卡(商务会议助手),与改动前一致 +- 新手引导走完三步:设备状态 → 唤醒 → AI 全能助手 +- 暗色主题切换正常 + +- [ ] **Step 4: 精简场景手动验证(hideAiAssistant = true)** + +临时修改 `lib/data/models/appconfig.dart` 中: +```dart +static bool hideAiAssistant = true; +``` + +重启应用,肉眼检查: +- 首页"热门AI体验":仅显示翻译 + 会议助手,左右等宽,高度约 140.h,绿色/紫粉渐变 +- 发现页"AI 功能":上下堆叠两张 banner 卡,高度约 130.h,图标右上、标题左下 +- 新手引导走完两步后正常结束(不再被引到 AI 全能助手) +- 翻译卡和会议助手卡点击能正常跳转 +- 暗色主题切换正常 + +- [ ] **Step 5: 还原默认值** + +把 `hideAiAssistant` 改回 `false`: + +```dart +static bool hideAiAssistant = false; +``` + +确认本次改动**不修改默认值**进入仓库。 + +- [ ] **Step 6: 最终提交(如 Step 5 有改动)** + +```bash +git status # 确认无未提交改动 +``` + +如果有,则: +```bash +git add lib/data/models/appconfig.dart +git commit -m "chore: 还原 hideAiAssistant 默认值为 false" +``` + +--- + +## 完成标准 + +- 三次提交(Task 1/2/3 各一次),代码符合 spec 中的"文件改动清单" +- `flutter analyze` 通过 +- 手动验证两种开关值下首页和发现页表现符合预期 +- 新手引导在两种值下都能走完不卡顿 diff --git a/docs/superpowers/specs/2026-04-28-hide-ai-assistant-design.md b/docs/superpowers/specs/2026-04-28-hide-ai-assistant-design.md new file mode 100644 index 000000000..6492151d5 --- /dev/null +++ b/docs/superpowers/specs/2026-04-28-hide-ai-assistant-design.md @@ -0,0 +1,171 @@ +# 隐藏"AI 全能助手"模块 · UI 排版重设计 + +**日期**:2026-04-28 +**背景**:某客户(对应 BLE 设备 PID 为 `B017`)的产品定位上不需要"AI 全能助手"模块,需要在 UI 上屏蔽该入口,并对首页和发现页的"翻译 / 会议助手"两个剩余模块重新排版。 + +--- + +## 一、目标与范围 + +### 范围内 +- 新增一个全局开关 `AppConfig.hideAiAssistant` +- 当开关为 `true` 时,**首页(HomeView)** 与 **发现页(ExploreView)** 切换为新的 UI 排版(隐藏 AI 全能助手入口) +- 当开关为 `true` 时,**新手引导(novice guide)** 跳过引导用户点开 AI 全能助手的步骤 +- 当开关为 `false`(默认)时,所有 UI 行为与当前一致 + +### 范围外 +- AI agent 模块本身(`lib/modules/agent/`)的代码、路由、controller **保持原样**,不做删除 +- 翻译资源 key(`aiAssistant`、`aiAssistantInfo` 等)**全部保留** +- 开关与 BLE PID 的联动逻辑(即"连接 B017 设备时自动设置开关为 true")**留待后续单独实现** +- 其它可能与 AI 全能助手相关的次要露出(如设置页、付费页面)目前未发现,后续如发现再补 + +--- + +## 二、配置开关 + +### 位置与定义 + +在已有的 `lib/data/models/appconfig.dart` 的 `AppConfig` 类中新增一个静态字段: + +```dart +class AppConfig { + static late UserGetAppConfigResp config; + static bool _isInitialized = false; + + // 中文注释:是否隐藏"AI全能助手"模块。 + // true => 首页/发现页切换为精简布局,新手引导跳过 AI 引导步骤 + // false => 保持原有布局 + // TODO: 后续接入 BLE PID 判断逻辑,B017 设备连接时自动置 true + static bool hideAiAssistant = false; + + // ... 其它已有方法 +} +``` + +### 调用方式 + +UI 层直接读取:`AppConfig.hideAiAssistant`,不引入新的 service 或新文件。 + +### 默认值 + +`false`(保持当前所有用户的体验不变)。 + +需要为 B017 客户验证新布局时,临时把默认值改为 `true` 重新编译即可,或在测试入口手动赋值。 + +--- + +## 三、首页(HomeView)改造 + +### 当前布局 + +`_buildPremiumAILayout()` 当前是 **左侧大卡片(AI 全能助手)+ 右侧两个小卡片(翻译 + 会议助手)** 的 1+2 结构。 + +### 新布局(开关为 true 时) + +**方案 A:左右等宽方形双卡** + +- 删除"AI 全能助手"卡片 +- 翻译 / 会议助手两张卡片**等宽并列**,高度统一约 `140.h`(介于原大卡片 175 和小卡片 85 之间) +- 卡片样式延用现有渐变色方案: + - 翻译:`#4CAF50 → #009688` 绿色系 + - 会议助手:`#ab47bc → #ec407a` 紫粉系 +- 图标置左上角,标题加粗、描述 2 行省略,与原小卡片保持一致的视觉语言但放大 + +### 实现方式 + +在 `home_view.dart` 中: +- 保留原 `_buildPremiumAILayout()` 方法不动 +- 新增 `_buildSimplifiedAILayout()` 方法返回新布局 +- 在 `build()` 中按开关分发: + +```dart +AppConfig.hideAiAssistant + ? _buildSimplifiedAILayout() + : _buildPremiumAILayout(), +``` + +区域标题"热门AI体验"(`topAiExperiences`)继续保留,不修改。 + +--- + +## 四、发现页(ExploreView)改造 + +### 当前布局 + +`_buildCustomAILayout()` 当前是 **2x2 网格**:上层左 AI 全能助手 + 上层右 同声传译,下层会议助手占满整行。`controller.aiFeatures` 列表有 3 项,索引 0 是 AI 全能助手。 + +### 新布局(开关为 true 时) + +**方案 C:上下堆叠大型 banner 卡** + +- 删除 AI 全能助手卡片 +- 翻译 / 会议助手两张卡片**上下堆叠**,每张占满整行 +- 每张卡片高度约 `130.h`,padding 加大(`16.w`) +- 图标置右上角约 `44.w`,标题左下角加粗放大(`16.sp`),描述放在标题下方 +- 渐变色与首页保持一致(绿色系 / 紫粉系) + +### 实现方式 + +在 `explore_view.dart` 中: + +**a. 不改动 `controller.aiFeatures` 列表本身**(保持向后兼容) + +**b. 在 view 中根据开关分支**: +- 保留原 `_buildCustomAILayout()` 方法不动 +- 新增 `_buildSimplifiedAILayout()` 方法返回新布局,内部直接使用 `controller.aiFeatures[1]`(翻译)和 `controller.aiFeatures[2]`(会议助手),跳过索引 0 +- 在 `build()` 中按开关分发 + +区域标题"AI 功能"(`aiFunction`)继续保留。 + +--- + +## 五、新手引导(novice guide)调整 + +### 现状 + +`home_view.dart` 中 `IntroStepBuilder(group: 'home', order: 3)` 包裹了 AI 全能助手大卡片,引导用户在唤醒成功后点开 AI 全能助手。 + +### 调整 + +当 `AppConfig.hideAiAssistant == true` 时: +- 精简布局中**不渲染 order:3 的 IntroStepBuilder** +- 用户完成 order:1(设备状态)和 order:2(唤醒)后,引导自然结束 + +### 实现方式 + +在 `_buildSimplifiedAILayout()` 中**不包裹任何 IntroStepBuilder**,引导框架找不到 order:3 的目标 widget 后会自动跳过。 + +也可以在 `NoviceGuideService` 的 `home` group 流程中加判断,但前者改动更小、更稳。 + +--- + +## 六、风险与注意事项 + +1. **GlobalKey 缺失**:原 `IntroStepBuilder(order: 3)` 不渲染时,必须确认引导服务不会因找不到目标 widget 报错或卡住。需要在测试时验证 B017 用户的引导走完是否顺畅。 +2. **后续 PID 联动**:`AppConfig.hideAiAssistant` 现在是普通静态字段,赋值后不会触发 `Obx` 重建。如果后续做 PID 联动并要求"插拔 B017 实时切换 UI",需要把字段改造成 `Rx` 或在赋值时主动触发 controller 刷新。本次设计不引入响应式包装。 +3. **页面缓存**:GetX 的 controller 默认是单例,UI 切换是在 `build()` 阶段判断的。第一次进入页面后,开关变化需要重新构建页面才能生效。本次场景下开关在编译期/启动期就已确定,不存在运行时切换问题。 +4. **资源未删除**:AI 全能助手相关的图标/文案/路由都保留,包体积无变化。 + +--- + +## 七、文件改动清单 + +| 文件 | 改动类型 | 说明 | +|---|---|---| +| `lib/data/models/appconfig.dart` | 修改 | 新增静态字段 `hideAiAssistant` | +| `lib/modules/home/views/home_view.dart` | 修改 | 新增 `_buildSimplifiedAILayout()`;`build()` 中按开关分发 | +| `lib/modules/explore/views/explore_view.dart` | 修改 | 新增 `_buildSimplifiedAILayout()`;`build()` 中按开关分发 | + +无需新建文件,无需修改 controller、route、translations。 + +--- + +## 八、验证清单 + +- [ ] `AppConfig.hideAiAssistant = false` 时,首页和发现页 UI 与当前完全一致 +- [ ] `AppConfig.hideAiAssistant = false` 时,新手引导走完 3 步并跳到 AI 全能助手 +- [ ] `AppConfig.hideAiAssistant = true` 时,首页"热门AI体验"区域显示翻译 + 会议助手等宽并列 +- [ ] `AppConfig.hideAiAssistant = true` 时,发现页"AI 功能"区域显示翻译 + 会议助手上下堆叠 banner +- [ ] `AppConfig.hideAiAssistant = true` 时,新手引导走完 2 步后正常结束,无卡顿/异常 +- [ ] 暗色主题下两种布局的渐变和文字对比度符合预期 +- [ ] 翻译/会议助手卡片的点击仍然能跳转到对应页面 diff --git a/lib/data/models/appconfig.dart b/lib/data/models/appconfig.dart index 8ce31d29f..d24941c85 100644 --- a/lib/data/models/appconfig.dart +++ b/lib/data/models/appconfig.dart @@ -7,7 +7,7 @@ class AppConfig { // true => 首页/发现页切换为精简布局,新手引导跳过 AI 引导步骤 // false => 保持原有布局 // TODO: 后续接入 BLE PID 判断逻辑,B017 设备连接时自动置 true - static bool hideAiAssistant = false; + static bool hideAiAssistant = true; static late UserGetAppConfigResp config; diff --git a/lib/modules/explore/views/explore_view.dart b/lib/modules/explore/views/explore_view.dart index 464aa67e8..2748855fa 100644 --- a/lib/modules/explore/views/explore_view.dart +++ b/lib/modules/explore/views/explore_view.dart @@ -467,14 +467,14 @@ class ExploreView extends GetView { ); } - // 精简布局下的 banner 卡(图标右上角,标题/描述左下角) + // 精简布局下的 banner 卡:Row 布局,图标在左,文字在右占满剩余空间 Widget _buildSimplifiedBannerCard( AIFeature feature, int index, bool isDarkMode) { return GestureDetector( onTap: () => controller.onAIFeatureTap(index), child: Container( - height: 130.h, - padding: EdgeInsets.all(16.w), + height: 110.h, + padding: EdgeInsets.symmetric(horizontal: 18.w, vertical: 16.h), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, @@ -495,38 +495,36 @@ class ExploreView extends GetView { ), ], ), - child: Stack( + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, children: [ - // 图标右上角 - Positioned( - top: 0, - right: 0, - child: Container( - width: 44.w, - height: 44.w, - decoration: BoxDecoration( - color: feature.iconColor.withOpacity(0.2), - shape: BoxShape.circle, - ), - child: Icon( - feature.icon, - size: 22.sp, - color: feature.iconColor, - ), + // 左侧图标 + Container( + width: 56.w, + height: 56.w, + decoration: BoxDecoration( + color: feature.iconColor.withOpacity(0.2), + shape: BoxShape.circle, + ), + child: Icon( + feature.icon, + size: 30.sp, + color: feature.iconColor, ), ), - // 标题 + 描述左下角 - Align( - alignment: Alignment.bottomLeft, + SizedBox(width: 16.w), + // 中间标题 + 描述 + Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ Text( feature.title, style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w600, + fontSize: 18.sp, + fontWeight: FontWeight.bold, color: isDarkMode ? Colors.white : Colors.grey[800], ), maxLines: 1, @@ -536,7 +534,8 @@ class ExploreView extends GetView { Text( feature.description, style: TextStyle( - fontSize: 12.sp, + fontSize: 13.sp, + height: 1.35, color: isDarkMode ? Colors.grey[400] : Colors.grey[600], ), maxLines: 2, @@ -545,6 +544,13 @@ class ExploreView extends GetView { ], ), ), + SizedBox(width: 8.w), + // 右侧"›"指示符 + Icon( + Icons.chevron_right, + size: 24.sp, + color: feature.iconColor, + ), ], ), ), diff --git a/lib/modules/home/views/home_view.dart b/lib/modules/home/views/home_view.dart index 762956589..77e162948 100644 --- a/lib/modules/home/views/home_view.dart +++ b/lib/modules/home/views/home_view.dart @@ -148,7 +148,6 @@ class HomeView extends GetView { AppConfig.hideAiAssistant ? _buildSimplifiedAILayout() : _buildPremiumAILayout(), - ], ), ), @@ -1044,7 +1043,8 @@ class HomeView extends GetView { ); } - // 精简布局:隐藏"AI全能助手",仅保留翻译 + 会议助手,左右等宽 + // 精简布局:隐藏"AI全能助手",仅保留翻译 + 会议助手,左右等宽方形 + // 用 AspectRatio 强制 1:1 让高度跟随宽度,避免渲染成矩形 // 注意:本布局不包裹 IntroStepBuilder(order: 3),新手引导走完唤醒后自然结束 Widget _buildSimplifiedAILayout() { final bool isDarkMode = Get.isDarkMode; @@ -1054,49 +1054,126 @@ class HomeView extends GetView { // 左侧:翻译 Expanded( flex: 1, - child: _buildFeatureCard( - title: 'interpretation'.tr, - description: 'simultaneousInterpretationInfo'.tr, - icon: Icons.translate, - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - const Color(0xFF4CAF50).withOpacity(0.3), - const Color(0xFF009688).withOpacity(0.3), - ], + child: AspectRatio( + aspectRatio: 1.0, + child: _buildSimplifiedFeatureCard( + title: 'interpretation'.tr, + description: 'simultaneousInterpretationInfo'.tr, + icon: Icons.translate, + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + const Color(0xFF4CAF50).withOpacity(0.3), + const Color(0xFF009688).withOpacity(0.3), + ], + ), + onTap: controller.openTranslation, + isDarkMode: isDarkMode, + iconColor: const Color(0xFF4CAF50), ), - onTap: controller.openTranslation, - iconOnTop: true, - height: 140.h, - isDarkMode: isDarkMode, - iconColor: const Color(0xFF4CAF50), ), ), SizedBox(width: 16.w), // 右侧:会议助手 Expanded( flex: 1, - child: _buildFeatureCard( - title: 'conferenceAssistant'.tr, - description: 'conferenceAssistantInfo'.tr, - icon: Icons.people, - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - const Color(0xFFab47bc).withOpacity(0.3), - const Color(0xFFec407a).withOpacity(0.3), - ], + child: AspectRatio( + aspectRatio: 1.0, + child: _buildSimplifiedFeatureCard( + title: 'conferenceAssistant'.tr, + description: 'conferenceAssistantInfo'.tr, + icon: Icons.people, + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + const Color(0xFFab47bc).withOpacity(0.3), + const Color(0xFFec407a).withOpacity(0.3), + ], + ), + onTap: () => controller.openMeet(), + isDarkMode: isDarkMode, + iconColor: const Color(0xFFd81b60), ), - onTap: () => controller.openMeet(), - iconOnTop: true, - height: 140.h, - isDarkMode: isDarkMode, - iconColor: const Color(0xFFd81b60), ), ), ], ); } + + // 精简布局专用方形卡片:不写死 height,由外部 AspectRatio 决定尺寸 + Widget _buildSimplifiedFeatureCard({ + required String title, + required String description, + required IconData icon, + required LinearGradient gradient, + required VoidCallback onTap, + bool isDarkMode = false, + Color iconColor = Colors.white, + }) { + return GestureDetector( + onTap: onTap, + child: Container( + padding: EdgeInsets.all(14.w), + decoration: BoxDecoration( + gradient: gradient, + borderRadius: BorderRadius.circular(16.r), + boxShadow: [ + BoxShadow( + color: isDarkMode + ? Colors.black.withOpacity(0.2) + : Colors.grey.withOpacity(0.1), + blurRadius: 8, + offset: const Offset(0, 4), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 图标 + Container( + width: 45.w, + height: 45.w, + decoration: BoxDecoration( + color: iconColor.withOpacity(0.2), + shape: BoxShape.circle, + ), + child: Icon( + icon, + color: iconColor, + size: 24.w, + ), + ), + SizedBox(height: 10.h), + // 标题 + Text( + title, + style: TextStyle( + color: isDarkMode ? Colors.white : Colors.grey[800], + fontSize: 16.sp, + fontWeight: FontWeight.bold, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + SizedBox(height: 4.h), + // 描述 + Expanded( + child: Text( + description, + style: TextStyle( + color: isDarkMode ? Colors.grey[400] : Colors.grey[600], + fontSize: 12.sp, + ), + maxLines: 3, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + ); + } }