feat(monisuo-dev): 重构开发流程为五阶段并优化Agent协作机制
- 更新开发流程描述,细化为需求定义→架构设计→模块化开发→精简测试→功能验证→构建六个环节 - 重构Phase 3为精简+测试,移除构建步骤,新增独立的Phase 5构建阶段 - 优化Agent协作流程:Phase 3输出审查报告供Phase 4使用,避免重复读取代码 - 明确各阶段职责分工,增加Spec同步要求确保Agent间信息一致性 - 添加Phase 5构建阶段,专门处理后端和Flutter构建任务 - 完善Bug修复循环,明确各Agent失败时的修复流程
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: monisuo-dev
|
name: monisuo-dev
|
||||||
description: Monisuo 项目结构化开发流程。需求分析 → 架构设计 → 开发 → 测试构建。
|
description: Monisuo 项目结构化开发流程。需求分析 → 架构设计 → 模块化开发 → 精简测试 → 功能验证 → 构建。
|
||||||
---
|
---
|
||||||
|
|
||||||
# Monisuo 开发工作流
|
# Monisuo 开发工作流
|
||||||
@@ -8,18 +8,25 @@ description: Monisuo 项目结构化开发流程。需求分析 → 架构设计
|
|||||||
## 流程概览
|
## 流程概览
|
||||||
|
|
||||||
```
|
```
|
||||||
Phase 1: 需求定义 → Phase 1.5: 架构设计 → Phase 2: 模块化开发
|
Phase 1: 需求定义 → Phase 1.5: 架构设计 → Phase 2: 模块化开发(子任务逐步推进)
|
||||||
↑ │
|
↑ │
|
||||||
│ ↓
|
│ ↓
|
||||||
│ [Agent A] Phase 3: 精简 + 测试 + 构建
|
│ 主对话:同步更新 Spec
|
||||||
|
│ │
|
||||||
|
│ ↓
|
||||||
|
│ [Agent A] Phase 3: 精简 + 测试 → 输出审查报告
|
||||||
│ │
|
│ │
|
||||||
│ ↓ (通过)
|
│ ↓ (通过)
|
||||||
│ [Agent B] Phase 4: 功能验证(用例驱动)
|
│ [Agent B] Phase 4: 功能验证(接收审查报告)
|
||||||
|
│ │
|
||||||
|
│ ↓ (通过)
|
||||||
|
│ [Agent C] Phase 5: 构建
|
||||||
│ │
|
│ │
|
||||||
└──────────────── Bug 修复 ←──────────────────┘
|
└──────────────── Bug 修复 ←──────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
**Phase 1-1.5-2 在主对话完成,Phase 3 和 Phase 4 分别启动独立 Agent。**
|
**Phase 1/1.5/2 在主对话完成,Phase 3/4/5 分别启动独立 Agent。**
|
||||||
|
**所有 Agent prompt 中的 `[feature-name]` 由主对话替换为实际值后再传入。**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -86,28 +93,38 @@ Phase 1: 需求定义 → Phase 1.5: 架构设计 → Phase 2: 模块化开发
|
|||||||
|
|
||||||
## Phase 2: 模块化开发
|
## Phase 2: 模块化开发
|
||||||
|
|
||||||
依据 Spec 中的 API 契约和数据模型,自底向上开发:
|
依据 Spec 中的 API 契约和数据模型,**按子模块逐步推进**,自底向上开发:
|
||||||
|
|
||||||
```
|
```
|
||||||
1. 数据层 → 2. 后端 API → 3. 前端实现
|
2a. 数据层 → 2b. 后端 API → 2c. Flutter 前端 → 2d. Admin 前端(如有)
|
||||||
DDL/Entity Controller/Service Model/Provider/UI
|
DDL/Entity Controller/Service Model/Provider/UI Vue Pages
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 子模块执行方式
|
||||||
|
- 每个子模块独立完成,不与其他子模块混在一起
|
||||||
|
- 每完成一个子模块,确认无编译错误再进入下一个
|
||||||
|
- 后端子模块完成后可先验证 API,前端再对接
|
||||||
|
|
||||||
### 代码规范
|
### 代码规范
|
||||||
- Flutter: `flutter analyze` 无错,用 AppSpacing/AppRadius/AppColorScheme,禁止硬编码颜色
|
- Flutter: `flutter analyze` 无错,用 AppSpacing/AppRadius/AppColorScheme,禁止硬编码颜色
|
||||||
- Java: Lombok 简化,资金变动方法加 `@Transactional(rollbackFor = Exception.class)`,RESTful 设计
|
- Java: Lombok 简化,资金变动方法加 `@Transactional(rollbackFor = Exception.class)`,RESTful 设计
|
||||||
|
|
||||||
|
### Spec 同步
|
||||||
|
Phase 2 全部完成后、启动 Agent 前,**主对话必须更新 Spec**:
|
||||||
|
- 实际实现与设计有差异时,以实现为准更新 Spec
|
||||||
|
- 确保 Phase 3/4 的 Agent 读到的是最新状态
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Phase 3: 精简 + 测试 + 构建(Agent A)
|
## Phase 3: 精简 + 测试(Agent A)
|
||||||
|
|
||||||
Phase 2 完成后,启动独立 Agent 执行代码精简、自动化测试和构建。
|
Phase 2 完成且 Spec 已同步后,启动独立 Agent 执行代码精简和自动化测试。
|
||||||
|
|
||||||
### 启动 Agent A
|
### 启动 Agent A
|
||||||
|
|
||||||
```
|
```
|
||||||
Agent(
|
Agent(
|
||||||
description: "精简+测试验证与构建",
|
description: "精简+测试验证",
|
||||||
prompt: |
|
prompt: |
|
||||||
你是 Monisuo 项目质量 Agent,独立完成以下任务,不要询问用户。
|
你是 Monisuo 项目质量 Agent,独立完成以下任务,不要询问用户。
|
||||||
|
|
||||||
@@ -129,19 +146,19 @@ Agent(
|
|||||||
- Flutter: cd flutter_monisuo && flutter test
|
- Flutter: cd flutter_monisuo && flutter test
|
||||||
- API: ./tests/api/test-[feature].sh(如存在)
|
- API: ./tests/api/test-[feature].sh(如存在)
|
||||||
|
|
||||||
## 5. 构建
|
## 5. 输出审查报告(供 Agent B 使用)
|
||||||
- 后端: mvn clean package -DskipTests → target/monisuo-*.jar
|
### 代码审查摘要
|
||||||
- Flutter: cd flutter_monisuo && flutter build web --release --dart-define=ENV=prod → build/web/
|
- 变更文件列表及每个文件的核心改动
|
||||||
|
- 代码规范检查结果
|
||||||
|
- 精简改动摘要(改了什么、为什么改)
|
||||||
|
|
||||||
## 6. 输出报告
|
### 测试结果
|
||||||
| 项目 | 状态 | 备注 |
|
| 项目 | 状态 | 备注 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| 代码审查 | ✅/❌ | |
|
| 代码审查 | ✅/❌ | |
|
||||||
| 代码精简 | ✅/❌ | 改动摘要 |
|
| 代码精简 | ✅/❌ | 改动摘要 |
|
||||||
| 后端测试 | ✅/❌ | |
|
| 后端测试 | ✅/❌ | |
|
||||||
| Flutter 测试 | ✅/❌ | |
|
| Flutter 测试 | ✅/❌ | |
|
||||||
| 后端构建 | ✅/❌ | |
|
|
||||||
| Flutter 构建 | ✅/❌ | |
|
|
||||||
|
|
||||||
如有 Bug,列出:文件、原因、修复建议。返回主对话修复后重新验证。
|
如有 Bug,列出:文件、原因、修复建议。返回主对话修复后重新验证。
|
||||||
)
|
)
|
||||||
@@ -151,7 +168,7 @@ Agent(
|
|||||||
|
|
||||||
## Phase 4: 功能验证(Agent B)
|
## Phase 4: 功能验证(Agent B)
|
||||||
|
|
||||||
**Agent A 全部通过后**,启动第二个独立 Agent,基于 Spec 中的测试用例验证功能正确性。
|
**Agent A 全部通过后**,启动独立 Agent。Agent B 接收 Agent A 的审查报告,避免重复读代码。
|
||||||
|
|
||||||
### 启动 Agent B
|
### 启动 Agent B
|
||||||
|
|
||||||
@@ -165,9 +182,9 @@ Agent(
|
|||||||
- 路径: docs/features/[feature-name].md
|
- 路径: docs/features/[feature-name].md
|
||||||
- 提取「测试用例」和「验收标准」
|
- 提取「测试用例」和「验收标准」
|
||||||
|
|
||||||
## 2. 读取变更代码
|
## 2. 利用审查报告
|
||||||
- git diff 查看本次变更的文件列表
|
- Agent A 已完成代码审查,变更文件列表和核心改动见报告
|
||||||
- 阅读变更的 Controller、Service、Provider、UI 代码
|
- 仅对报告未覆盖的逻辑路径做补充阅读
|
||||||
- 对照 Spec 中的 API 设计,确认实现与契约一致
|
- 对照 Spec 中的 API 设计,确认实现与契约一致
|
||||||
|
|
||||||
## 3. 逐条验证测试用例
|
## 3. 逐条验证测试用例
|
||||||
@@ -199,8 +216,37 @@ Agent(
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Phase 5: 构建(Agent C)
|
||||||
|
|
||||||
|
**Agent A 和 Agent B 全部通过后**,启动独立 Agent 执行构建。
|
||||||
|
|
||||||
|
### 启动 Agent C
|
||||||
|
|
||||||
|
```
|
||||||
|
Agent(
|
||||||
|
description: "项目构建",
|
||||||
|
prompt: |
|
||||||
|
你是 Monisuo 项目构建 Agent,独立完成构建任务,不要询问用户。
|
||||||
|
|
||||||
|
## 1. 构建
|
||||||
|
- 后端: mvn clean package -DskipTests → target/monisuo-*.jar
|
||||||
|
- Flutter: cd flutter_monisuo && flutter build web --release --dart-define=ENV=prod → build/web/
|
||||||
|
|
||||||
|
## 2. 输出报告
|
||||||
|
| 项目 | 状态 | 备注 |
|
||||||
|
|------|------|------|
|
||||||
|
| 后端构建 | ✅/❌ | 产物路径 |
|
||||||
|
| Flutter 构建 | ✅/❌ | 产物路径 |
|
||||||
|
|
||||||
|
如有构建失败,列出:模块、错误信息、修复建议。返回主对话修复后重新构建。
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Bug 修复循环
|
## Bug 修复循环
|
||||||
|
|
||||||
- **Agent A 失败**(测试/构建不通过)→ 主对话修复 Bug → 重新启动 Agent A
|
- **Agent A 失败**(测试不通过)→ 主对话修复 Bug → 重新启动 Agent A
|
||||||
- **Agent B 失败**(功能验证不通过)→ 主对话修复逻辑 → 重新启动 Agent B
|
- **Agent B 失败**(功能验证不通过)→ 主对话修复逻辑 → 重新启动 Agent B
|
||||||
|
- **Agent C 失败**(构建不通过)→ 主对话修复构建问题 → 重新启动 Agent C
|
||||||
- **全部通过** → 开发完成
|
- **全部通过** → 开发完成
|
||||||
|
|||||||
@@ -1,621 +0,0 @@
|
|||||||
---
|
|
||||||
name: superdesign-flutter
|
|
||||||
description: Flutter Design Skill - SuperDesign adapted for Flutter/Dart development. Optimized for Material Design 3 and Flutter widgets.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Flutter Design Skill
|
|
||||||
|
|
||||||
Use this skill when creating Flutter UI components, screens, or any Flutter UI design work.
|
|
||||||
|
|
||||||
This is an adapted version of SuperDesign for Flutter, converting web/CSS patterns to Flutter/Dart equivalents.
|
|
||||||
|
|
||||||
## Design Workflow
|
|
||||||
|
|
||||||
Follow this structured approach for Flutter UI design:
|
|
||||||
|
|
||||||
- **Layout Design** — Think through widget structure, create ASCII wireframes
|
|
||||||
- **Theme Design** — Define colors, text styles, spacing, shadows
|
|
||||||
- **Animation Design** — Plan micro-interactions and transitions
|
|
||||||
- **Implementation** — Generate Flutter/Dart code
|
|
||||||
|
|
||||||
### 1. Layout Design
|
|
||||||
|
|
||||||
Before coding, sketch the widget tree in ASCII format:
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────┐
|
|
||||||
│ Scaffold / AppBar │
|
|
||||||
├─────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ Hero Section (Column) │
|
|
||||||
│ - Title Text │
|
|
||||||
│ - CTA ElevatedButton │
|
|
||||||
│ │
|
|
||||||
├─────────────────────────────────────┤
|
|
||||||
│ Row (3x Feature Cards) │
|
|
||||||
│ ┌─────┐ ┌─────┐ ┌─────┐ │
|
|
||||||
│ │Card │ │Card │ │Card │ │
|
|
||||||
│ └─────┘ └─────┘ └─────┘ │
|
|
||||||
├─────────────────────────────────────┤
|
|
||||||
│ BottomNavigationBar │
|
|
||||||
└─────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Theme Guidelines
|
|
||||||
|
|
||||||
#### Color Rules:
|
|
||||||
|
|
||||||
- NEVER use generic blue (Colors.blue) — it looks dated
|
|
||||||
- Prefer Material Design 3 color system (ColorScheme)
|
|
||||||
- Use Theme.of(context).colorScheme for semantic colors
|
|
||||||
- Support both light and dark mode with ColorScheme
|
|
||||||
|
|
||||||
#### OKLCH to Flutter Color Conversion:
|
|
||||||
|
|
||||||
Convert OKLCH values to Flutter Color using this helper:
|
|
||||||
|
|
||||||
```dart
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
/// Convert OKLCH to Flutter Color
|
|
||||||
/// Example: oklch(0.205 0 0) → Color
|
|
||||||
Color oklchToColor(double l, double c, double h) {
|
|
||||||
// Simplified conversion - for accurate conversion use a color library
|
|
||||||
// This is a placeholder implementation
|
|
||||||
final hue = h;
|
|
||||||
final chroma = c;
|
|
||||||
final lightness = l;
|
|
||||||
|
|
||||||
// Convert to HSL then to RGB
|
|
||||||
// For production, use package:flutter_color or similar
|
|
||||||
return HSLColor.fromAHSL(1.0, hue, chroma, lightness).toColor();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Modern Dark Mode Colors (Vercel/Linear style)
|
|
||||||
class ModernDarkColors {
|
|
||||||
static const background = Color(0xFFFFFFFF); // oklch(1 0 0)
|
|
||||||
static const foreground = Color(0xFF252525); // oklch(0.145 0 0)
|
|
||||||
static const primary = Color(0xFF343434); // oklch(0.205 0 0)
|
|
||||||
static const secondary = Color(0xFFF7F7F7); // oklch(0.970 0 0)
|
|
||||||
static const muted = Color(0xFFF7F7F7); // oklch(0.970 0 0)
|
|
||||||
static const border = Color(0xFFEBEBEB); // oklch(0.922 0 0)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Flutter Theme Setup:
|
|
||||||
|
|
||||||
```dart
|
|
||||||
MaterialApp(
|
|
||||||
theme: ThemeData(
|
|
||||||
useMaterial3: true,
|
|
||||||
colorScheme: ColorScheme.fromSeed(
|
|
||||||
seedColor: Color(0xFF343434), // Modern neutral
|
|
||||||
brightness: Brightness.light,
|
|
||||||
),
|
|
||||||
fontFamily: 'Inter',
|
|
||||||
),
|
|
||||||
darkTheme: ThemeData(
|
|
||||||
useMaterial3: true,
|
|
||||||
colorScheme: ColorScheme.fromSeed(
|
|
||||||
seedColor: Color(0xFF343434),
|
|
||||||
brightness: Brightness.dark,
|
|
||||||
),
|
|
||||||
fontFamily: 'Inter',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Font Selection (Google Fonts):
|
|
||||||
|
|
||||||
Use `google_fonts` package:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# pubspec.yaml
|
|
||||||
dependencies:
|
|
||||||
google_fonts: ^6.1.0
|
|
||||||
```
|
|
||||||
|
|
||||||
```dart
|
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
|
||||||
|
|
||||||
// Sans-serif fonts
|
|
||||||
final inter = GoogleFonts.inter();
|
|
||||||
final roboto = GoogleFonts.roboto();
|
|
||||||
final poppins = GoogleFonts.poppins();
|
|
||||||
final montserrat = GoogleFonts.montserrat();
|
|
||||||
final outfit = GoogleFonts.outfit();
|
|
||||||
final dmSans = GoogleFonts.dmSans();
|
|
||||||
|
|
||||||
// Monospace fonts
|
|
||||||
final jetBrainsMono = GoogleFonts.jetBrainsMono();
|
|
||||||
final firaCode = GoogleFonts.firaCode();
|
|
||||||
final sourceCodePro = GoogleFonts.sourceCodePro();
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Spacing System:
|
|
||||||
|
|
||||||
```dart
|
|
||||||
/// Spacing scale based on 4.0 (instead of 0.25rem)
|
|
||||||
class Spacing {
|
|
||||||
static const double xs = 4.0;
|
|
||||||
static const double sm = 8.0;
|
|
||||||
static const double md = 16.0;
|
|
||||||
static const double lg = 24.0;
|
|
||||||
static const double xl = 32.0;
|
|
||||||
static const double xxl = 48.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Usage
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.all(Spacing.md), // 16.0
|
|
||||||
child: Text('Content'),
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Theme Patterns
|
|
||||||
|
|
||||||
#### Modern Dark Mode (Vercel/Linear style):
|
|
||||||
|
|
||||||
```dart
|
|
||||||
ThemeData(
|
|
||||||
useMaterial3: true,
|
|
||||||
colorScheme: ColorScheme(
|
|
||||||
brightness: Brightness.light,
|
|
||||||
background: Color(0xFFFFFFFF),
|
|
||||||
onBackground: Color(0xFF252525),
|
|
||||||
primary: Color(0xFF343434),
|
|
||||||
onPrimary: Color(0xFFFBFBFB),
|
|
||||||
secondary: Color(0xFFF7F7F7),
|
|
||||||
onSecondary: Color(0xFF252525),
|
|
||||||
surface: Color(0xFFFFFFFF),
|
|
||||||
onSurface: Color(0xFF252525),
|
|
||||||
outline: Color(0xFFEBEBEB),
|
|
||||||
),
|
|
||||||
cardTheme: CardTheme(
|
|
||||||
elevation: 0,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(10.0), // 0.625rem
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Neo-Brutalism (90s revival):
|
|
||||||
|
|
||||||
```dart
|
|
||||||
ThemeData(
|
|
||||||
useMaterial3: true,
|
|
||||||
colorScheme: ColorScheme(
|
|
||||||
brightness: Brightness.light,
|
|
||||||
background: Color(0xFFFFFFFF),
|
|
||||||
onBackground: Color(0xFF000000),
|
|
||||||
primary: Color(0xFFFF6B35), // Vibrant orange
|
|
||||||
secondary: Color(0xFF4ECDC4), // Teal
|
|
||||||
tertiary: Color(0xFF5B5F97), // Purple
|
|
||||||
outline: Color(0xFF000000),
|
|
||||||
),
|
|
||||||
cardTheme: CardTheme(
|
|
||||||
elevation: 0,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(0), // No radius
|
|
||||||
side: BorderSide(color: Colors.black, width: 2),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
elevation: 0,
|
|
||||||
shadowColor: Colors.transparent,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(0),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Glassmorphism:
|
|
||||||
|
|
||||||
```dart
|
|
||||||
class GlassCard extends StatelessWidget {
|
|
||||||
final Widget child;
|
|
||||||
|
|
||||||
const GlassCard({required this.child});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(16.0),
|
|
||||||
child: BackdropFilter(
|
|
||||||
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white.withOpacity(0.1),
|
|
||||||
border: Border.all(
|
|
||||||
color: Colors.white.withOpacity(0.2),
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.circular(16.0),
|
|
||||||
),
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. Animation Guidelines
|
|
||||||
|
|
||||||
#### Flutter Animation Equivalents:
|
|
||||||
|
|
||||||
```dart
|
|
||||||
// Button press animation (150ms)
|
|
||||||
class AnimatedButton extends StatefulWidget {
|
|
||||||
@override
|
|
||||||
_AnimatedButtonState createState() => _AnimatedButtonState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _AnimatedButtonState extends State<AnimatedButton>
|
|
||||||
with SingleTickerProviderStateMixin {
|
|
||||||
late AnimationController _controller;
|
|
||||||
late Animation<double> _scaleAnimation;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_controller = AnimationController(
|
|
||||||
duration: Duration(milliseconds: 150),
|
|
||||||
vsync: this,
|
|
||||||
);
|
|
||||||
_scaleAnimation = Tween<double>(begin: 1.0, end: 0.95).animate(
|
|
||||||
CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return GestureDetector(
|
|
||||||
onTapDown: (_) => _controller.forward(),
|
|
||||||
onTapUp: (_) => _controller.reverse(),
|
|
||||||
onTapCancel: () => _controller.reverse(),
|
|
||||||
child: ScaleTransition(
|
|
||||||
scale: _scaleAnimation,
|
|
||||||
child: ElevatedButton(...),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fade in animation (400ms)
|
|
||||||
class FadeInWidget extends StatefulWidget {
|
|
||||||
final Widget child;
|
|
||||||
const FadeInWidget({required this.child});
|
|
||||||
@override
|
|
||||||
_FadeInWidgetState createState() => _FadeInWidgetState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _FadeInWidgetState extends State<FadeInWidget>
|
|
||||||
with SingleTickerProviderStateMixin {
|
|
||||||
late AnimationController _controller;
|
|
||||||
late Animation<double> _opacity;
|
|
||||||
late Animation<Offset> _slide;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_controller = AnimationController(
|
|
||||||
duration: Duration(milliseconds: 400),
|
|
||||||
vsync: this,
|
|
||||||
);
|
|
||||||
_opacity = Tween<double>(begin: 0.0, end: 1.0).animate(_controller);
|
|
||||||
_slide = Tween<Offset>(begin: Offset(0, 0.05), end: Offset.zero)
|
|
||||||
.animate(CurvedAnimation(parent: _controller, curve: Curves.easeOut));
|
|
||||||
_controller.forward();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return SlideTransition(
|
|
||||||
position: _slide,
|
|
||||||
child: FadeTransition(opacity: _opacity, child: widget.child),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Common Animation Durations:
|
|
||||||
|
|
||||||
```dart
|
|
||||||
class AnimationDurations {
|
|
||||||
static const Duration buttonPress = Duration(milliseconds: 150);
|
|
||||||
static const Duration hover = Duration(milliseconds: 200);
|
|
||||||
static const Duration fadeIn = Duration(milliseconds: 400);
|
|
||||||
static const Duration slideIn = Duration(milliseconds: 350);
|
|
||||||
static const Duration bounce = Duration(milliseconds: 600);
|
|
||||||
static const Duration pageTransition = Duration(milliseconds: 300);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Widget Patterns
|
|
||||||
|
|
||||||
#### Responsive Layout:
|
|
||||||
|
|
||||||
```dart
|
|
||||||
class ResponsiveLayout extends StatelessWidget {
|
|
||||||
final Widget mobile;
|
|
||||||
final Widget? tablet;
|
|
||||||
final Widget? desktop;
|
|
||||||
|
|
||||||
const ResponsiveLayout({
|
|
||||||
required this.mobile,
|
|
||||||
this.tablet,
|
|
||||||
this.desktop,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return LayoutBuilder(
|
|
||||||
builder: (context, constraints) {
|
|
||||||
if (constraints.maxWidth >= 1024) {
|
|
||||||
return desktop ?? tablet ?? mobile;
|
|
||||||
} else if (constraints.maxWidth >= 768) {
|
|
||||||
return tablet ?? mobile;
|
|
||||||
} else {
|
|
||||||
return mobile;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Usage
|
|
||||||
ResponsiveLayout(
|
|
||||||
mobile: MobileLayout(),
|
|
||||||
tablet: TabletLayout(),
|
|
||||||
desktop: DesktopLayout(),
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Icons:
|
|
||||||
|
|
||||||
```dart
|
|
||||||
// Use Material Icons (built-in)
|
|
||||||
Icon(Icons.home)
|
|
||||||
Icon(Icons.settings)
|
|
||||||
|
|
||||||
// Or use Cupertino Icons
|
|
||||||
Icon(CupertinoIcons.house)
|
|
||||||
Icon(CupertinoIcons.settings)
|
|
||||||
|
|
||||||
// For custom icons, use flutter_svg
|
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
|
||||||
SvgPicture.asset('assets/icons/custom_icon.svg')
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Images:
|
|
||||||
|
|
||||||
```dart
|
|
||||||
// Network images with error handling
|
|
||||||
Image.network(
|
|
||||||
'https://images.unsplash.com/photo-xxx?w=800&h=600',
|
|
||||||
errorBuilder: (context, error, stackTrace) {
|
|
||||||
return Icon(Icons.error);
|
|
||||||
},
|
|
||||||
loadingBuilder: (context, child, loadingProgress) {
|
|
||||||
if (loadingProgress == null) return child;
|
|
||||||
return CircularProgressIndicator();
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
// Asset images
|
|
||||||
Image.asset('assets/images/placeholder.png')
|
|
||||||
|
|
||||||
// Use cached_network_image for better performance
|
|
||||||
CachedNetworkImage(
|
|
||||||
imageUrl: 'https://images.unsplash.com/photo-xxx?w=800&h=600',
|
|
||||||
placeholder: (context, url) => CircularProgressIndicator(),
|
|
||||||
errorWidget: (context, url, error) => Icon(Icons.error),
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6. Accessibility
|
|
||||||
|
|
||||||
```dart
|
|
||||||
// Semantic labels for screen readers
|
|
||||||
Semantics(
|
|
||||||
label: 'Submit button',
|
|
||||||
button: true,
|
|
||||||
enabled: true,
|
|
||||||
child: ElevatedButton(...),
|
|
||||||
)
|
|
||||||
|
|
||||||
// Minimum touch target (44x44)
|
|
||||||
MaterialButton(
|
|
||||||
minWidth: 44,
|
|
||||||
height: 44,
|
|
||||||
child: Text('Button'),
|
|
||||||
onPressed: () {},
|
|
||||||
)
|
|
||||||
|
|
||||||
// Sufficient color contrast (4.5:1 minimum)
|
|
||||||
// Use tools like https://webaim.org/resources/contrastchecker/
|
|
||||||
```
|
|
||||||
|
|
||||||
### 7. Component Design Tips
|
|
||||||
|
|
||||||
#### Cards:
|
|
||||||
|
|
||||||
```dart
|
|
||||||
Card(
|
|
||||||
elevation: 2, // Subtle shadow
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(12.0),
|
|
||||||
),
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.all(16.0), // p-4
|
|
||||||
child: Column(...),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
// Hover effect (web only)
|
|
||||||
InkWell(
|
|
||||||
onTap: () {},
|
|
||||||
hoverColor: Colors.transparent,
|
|
||||||
splashColor: Colors.transparent,
|
|
||||||
child: MouseRegion(
|
|
||||||
cursor: SystemMouseCursors.click,
|
|
||||||
child: AnimatedContainer(
|
|
||||||
duration: Duration(milliseconds: 200),
|
|
||||||
transform: Matrix4.identity()..translate(0.0, _isHovered ? -2.0 : 0.0),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: Colors.black.withOpacity(_isHovered ? 0.15 : 0.1),
|
|
||||||
blurRadius: _isHovered ? 12 : 8,
|
|
||||||
offset: Offset(0, _isHovered ? 4 : 2),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: Card(...),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Buttons:
|
|
||||||
|
|
||||||
```dart
|
|
||||||
// Primary button
|
|
||||||
ElevatedButton(
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
minimumSize: Size(44, 44), // Touch target
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
|
||||||
),
|
|
||||||
onPressed: () {},
|
|
||||||
child: Text('Primary'),
|
|
||||||
)
|
|
||||||
|
|
||||||
// Secondary button
|
|
||||||
OutlinedButton(
|
|
||||||
style: OutlinedButton.styleFrom(
|
|
||||||
minimumSize: Size(44, 44),
|
|
||||||
),
|
|
||||||
onPressed: () {},
|
|
||||||
child: Text('Secondary'),
|
|
||||||
)
|
|
||||||
|
|
||||||
// Ghost button
|
|
||||||
TextButton(
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
minimumSize: Size(44, 44),
|
|
||||||
),
|
|
||||||
onPressed: () {},
|
|
||||||
child: Text('Ghost'),
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Forms:
|
|
||||||
|
|
||||||
```dart
|
|
||||||
TextFormField(
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: 'Email', // Clear label above input
|
|
||||||
border: OutlineInputBorder(),
|
|
||||||
focusedBorder: OutlineInputBorder(
|
|
||||||
borderSide: BorderSide(color: Theme.of(context).colorScheme.primary, width: 2),
|
|
||||||
),
|
|
||||||
errorBorder: OutlineInputBorder(
|
|
||||||
borderSide: BorderSide(color: Theme.of(context).colorScheme.error),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return 'Please enter email';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
// Spacing between fields
|
|
||||||
SizedBox(height: 16.0)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Navigation:
|
|
||||||
|
|
||||||
```dart
|
|
||||||
// Bottom navigation bar
|
|
||||||
BottomNavigationBar(
|
|
||||||
currentIndex: _currentIndex,
|
|
||||||
onTap: (index) => setState(() => _currentIndex = index),
|
|
||||||
items: [
|
|
||||||
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
|
|
||||||
BottomNavigationBarItem(icon: Icon(Icons.settings), label: 'Settings'),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
// Navigation Rail (for tablets)
|
|
||||||
NavigationRail(
|
|
||||||
selectedIndex: _selectedIndex,
|
|
||||||
onDestinationSelected: (index) => setState(() => _selectedIndex = index),
|
|
||||||
destinations: [
|
|
||||||
NavigationRailDestination(icon: Icon(Icons.home), label: Text('Home')),
|
|
||||||
NavigationRailDestination(icon: Icon(Icons.settings), label: Text('Settings')),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 8. Flutter-Specific Best Practices
|
|
||||||
|
|
||||||
#### Performance:
|
|
||||||
|
|
||||||
```dart
|
|
||||||
// Use const constructors when possible
|
|
||||||
const Text('Static text')
|
|
||||||
const SizedBox(height: 16)
|
|
||||||
|
|
||||||
// Use ListView.builder for long lists
|
|
||||||
ListView.builder(
|
|
||||||
itemCount: items.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
return ListTile(title: Text(items[index]));
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
// Avoid rebuilding widgets with const
|
|
||||||
const MyStaticWidget()
|
|
||||||
```
|
|
||||||
|
|
||||||
#### State Management:
|
|
||||||
|
|
||||||
```dart
|
|
||||||
// Simple state with StatefulWidget
|
|
||||||
setState(() {
|
|
||||||
_counter++;
|
|
||||||
});
|
|
||||||
|
|
||||||
// For complex state, use provider, riverpod, or bloc
|
|
||||||
// Example with provider:
|
|
||||||
Consumer<MyModel>(
|
|
||||||
builder: (context, model, child) {
|
|
||||||
return Text('${model.value}');
|
|
||||||
},
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Quick Reference
|
|
||||||
|
|
||||||
| Element | Flutter Recommendation |
|
|
||||||
|---------|------------------------|
|
|
||||||
| Primary font | Inter, Outfit, DM Sans (google_fonts) |
|
|
||||||
| Code font | JetBrains Mono, Fira Code (google_fonts) |
|
|
||||||
| Border radius | 8.0 - 16.0 (modern), 0 (brutalist) |
|
|
||||||
| Shadow | BoxShadow with elevation 2-4 |
|
|
||||||
| Spacing | 4.0 base unit (Spacing class) |
|
|
||||||
| Animation | 150-400ms, Curves.easeOut |
|
|
||||||
| Colors | ColorScheme.fromSeed (Material 3) |
|
|
||||||
| Touch targets | Minimum 44x44 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Based on SuperDesign patterns — https://superdesign.dev
|
|
||||||
Adapted for Flutter/Dart — Material Design 3
|
|
||||||
Reference in New Issue
Block a user