diff --git a/ui/flutter_v2/.github/copilot-instructions.md b/ui/flutter_v2/.github/copilot-instructions.md
new file mode 100644
index 00000000..174abd62
--- /dev/null
+++ b/ui/flutter_v2/.github/copilot-instructions.md
@@ -0,0 +1,169 @@
+# Gopeed Flutter V2 UI - AI Coding Instructions
+
+## Response Rules
+
+Respond in the same language as user's question
+
+## Project Overview
+
+This is the Flutter V2 UI for **Gopeed** (Go Speed), a high-speed download manager built with Golang + Flutter. This Flutter app is a **desktop-focused UI redesign** with cross-platform support (macOS, Windows, Linux, iOS, Android, Web).
+
+**Critical Context**: This Flutter UI communicates with a Go backend REST API (not in this workspace). The backend handles download operations, task management, and file I/O. The UI is purely presentational with future API integration planned.
+
+## Architecture & Structure
+
+### Module Organization (Feature-First)
+
+```
+lib/
+├── main.dart # App entry, window config, router setup
+├── routes/ # Centralized routing
+│ ├── app_routes.dart # go_router configuration
+│ └── route_names.dart # Route path constants
+├── modules/ # Feature modules (screens + widgets)
+│ ├── home/ # Shell layout with sidebar
+│ ├── task/ # Download task management UI
+│ └── settings/ # Settings screen
+└── components/ # Shared UI components (gp_* prefix)
+```
+
+**Key Pattern**: Features are organized in `modules/` with `screens/` and `widgets/` subdirectories. Shared components use `gp_` prefix (e.g., `GpGradientButton`, `GpIconButton`).
+
+### Routing Architecture
+
+- Uses `go_router` with `ShellRoute` for persistent sidebar navigation
+- `HomeScreen` wraps all routes and provides the sidebar layout
+- Route paths defined in `RouteNames` class (prevents magic strings)
+- Current route detection via `GoRouterState.of(context).matchedLocation`
+
+## Critical Patterns & Conventions
+
+### Component Design System
+
+1. **Gradient Buttons** (`GpGradientButton`): Primary actions, teal-to-green gradient (Colors: `0xFF3ACBBE` → `0xFF2CDB90`)
+2. **Outline Buttons** (`GpOutlineButton`): Secondary actions, border-only with teal accent (`0xFF39CDB9`)
+3. **Icon Buttons** (`GpIconButton`): Tertiary actions with hover effects (`0xFF4883A2` on hover)
+
+### Design Implementation
+
+- **Glass Morphism**: `TaskItem` widget uses `BackdropFilter` with blur (24px) and layered gradients
+- **Color Palette**: Dark blue theme (`0xFF131956` background, `0xFF000E4B` sidebar, teal/green accents)
+- **Comments Reference Design Specs**: Many widgets have detailed comments like "Rectangle 82: 主容器" mapping to Figma/design files
+
+### Widget Documentation Style
+
+Components use triple-slash (`///`) documentation:
+
+```dart
+/// TaskItem - 任务项组件
+///
+/// 一个带有毛玻璃效果和渐变边框的任务项容器
+class TaskItem extends StatelessWidget {
+ /// 左侧图标
+ final dynamic icon;
+```
+
+**Convention**: Document widget purpose, parameters, and design intent in Chinese. Keep inline comments for implementation details.
+
+### State Management
+
+- Currently uses `StatefulWidget` with local state (e.g., `TaskScreen._selectedTabIndex`)
+- **Future Integration**: Will integrate with backend API - prepare for state management library (GetX/Riverpod likely based on Gopeed ecosystem)
+
+### Window Management
+
+Desktop apps use `window_manager` package:
+
+- Initial size: 1024x768, minimum: 800x600
+- Hidden title bar (`TitleBarStyle.hidden`) for custom UI
+- Configured in `main.dart` before `runApp()`
+
+## Development Workflows
+
+### Running the App
+
+```bash
+# Desktop (macOS/Windows/Linux)
+flutter run -d macos # or windows/linux
+
+# Mobile
+flutter run -d ios # requires Xcode
+flutter run -d android
+
+# Web
+flutter run -d chrome
+```
+
+### Building
+
+```bash
+flutter build macos --release
+flutter build windows --release
+flutter build linux --release
+```
+
+### Dependencies
+
+Key packages in `pubspec.yaml`:
+
+- `window_manager: ^0.4.3` - Desktop window control
+- `flutter_svg: ^2.0.17` - SVG asset support
+- `go_router: ^14.8.1` - Declarative routing
+
+Assets in `assets/icons/` (e.g., `gopeed_sidebar.svg`, `pause.png`)
+
+## Backend Integration (Future)
+
+**Not Yet Implemented**: Based on parent project structure, this UI will connect to Go REST API:
+
+- API endpoints: `/api/task`, `/api/resolve`, `/api/config` (reference: `pkg/rest/api.go` in parent)
+- Task operations: create, pause, continue, delete
+- Real-time progress updates via events/WebSocket
+
+**When Implementing API**:
+
+1. Create `lib/api/` or `lib/services/` directory
+2. Use `http` or `dio` package for REST calls
+3. Models should match Go backend structs (e.g., `Task`, `Progress`)
+4. Replace mock data in `TaskScreen._buildTaskList()` with API calls
+
+## Testing & Quality
+
+- Lints: Uses `package:flutter_lints/flutter.yaml` (standard Flutter best practices)
+- No tests currently - **add tests when backend integration begins**
+- Desktop focus: Prioritize macOS/Windows, mobile is secondary
+
+## Common Tasks
+
+### Adding a New Screen
+
+1. Create `lib/modules/[feature]/screens/[screen_name].dart`
+2. Add route to `RouteNames` constant
+3. Register route in `AppRoutes.getRouter()` under `ShellRoute.routes`
+
+### Adding Shared Component
+
+1. Create `lib/components/gp_[component_name].dart`
+2. Follow naming: `Gp` prefix + PascalCase
+3. Document with `///` comments
+4. Support flexible sizing/theming via parameters
+
+### Design-to-Code Workflow
+
+When implementing from design files:
+
+- Preserve design layer names in comments (e.g., "Rectangle 82")
+- Use exact hex colors from specs
+- Document gradient stops and blur sigma values
+- Stack layers match design hierarchy (bottom-to-top)
+
+## Important Notes
+
+- **Language**: UI text is in Chinese (e.g., "下载中", "已完成", "任务失败")
+- **Branch Context**: Current branch is `feat/new_ui` - this is a redesign
+- **Desktop First**: Window management, mouse hover states prioritized
+- **Parent Project**: Part of larger Gopeed monorepo with Go backend (outside this workspace)
+
+---
+
+**When uncertain**: Check `lib/modules/task/widgets/task_item.dart` for complex widget patterns, `lib/routes/app_routes.dart` for routing examples, or `lib/main.dart` for app initialization.
diff --git a/ui/flutter_v2/assets/icons/delete.svg b/ui/flutter_v2/assets/icons/delete.svg
new file mode 100644
index 00000000..27490950
--- /dev/null
+++ b/ui/flutter_v2/assets/icons/delete.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ui/flutter_v2/assets/icons/item_delete.svg b/ui/flutter_v2/assets/icons/item_delete.svg
new file mode 100644
index 00000000..9a905ddf
--- /dev/null
+++ b/ui/flutter_v2/assets/icons/item_delete.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ui/flutter_v2/assets/icons/item_info.svg b/ui/flutter_v2/assets/icons/item_info.svg
new file mode 100644
index 00000000..4420f34b
--- /dev/null
+++ b/ui/flutter_v2/assets/icons/item_info.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ui/flutter_v2/assets/icons/item_more.svg b/ui/flutter_v2/assets/icons/item_more.svg
new file mode 100644
index 00000000..6da67da4
--- /dev/null
+++ b/ui/flutter_v2/assets/icons/item_more.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ui/flutter_v2/assets/icons/item_pause.svg b/ui/flutter_v2/assets/icons/item_pause.svg
new file mode 100644
index 00000000..b9eac269
--- /dev/null
+++ b/ui/flutter_v2/assets/icons/item_pause.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ui/flutter_v2/assets/icons/item_resume.svg b/ui/flutter_v2/assets/icons/item_resume.svg
new file mode 100644
index 00000000..3cd475e8
--- /dev/null
+++ b/ui/flutter_v2/assets/icons/item_resume.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ui/flutter_v2/assets/icons/item_reveal.svg b/ui/flutter_v2/assets/icons/item_reveal.svg
new file mode 100644
index 00000000..370772dc
--- /dev/null
+++ b/ui/flutter_v2/assets/icons/item_reveal.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ui/flutter_v2/assets/icons/item_speed.svg b/ui/flutter_v2/assets/icons/item_speed.svg
new file mode 100644
index 00000000..26018742
--- /dev/null
+++ b/ui/flutter_v2/assets/icons/item_speed.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ui/flutter_v2/assets/icons/pause.png b/ui/flutter_v2/assets/icons/pause.png
deleted file mode 100644
index caaa71b4..00000000
Binary files a/ui/flutter_v2/assets/icons/pause.png and /dev/null differ
diff --git a/ui/flutter_v2/assets/icons/pause.svg b/ui/flutter_v2/assets/icons/pause.svg
new file mode 100644
index 00000000..6aaa98a3
--- /dev/null
+++ b/ui/flutter_v2/assets/icons/pause.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ui/flutter_v2/assets/icons/resume.svg b/ui/flutter_v2/assets/icons/resume.svg
new file mode 100644
index 00000000..acf32e6b
--- /dev/null
+++ b/ui/flutter_v2/assets/icons/resume.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ui/flutter_v2/lib/components/gp_icon_button.dart b/ui/flutter_v2/lib/components/gp_icon_button.dart
index 8dd46bf3..972a04bd 100644
--- a/ui/flutter_v2/lib/components/gp_icon_button.dart
+++ b/ui/flutter_v2/lib/components/gp_icon_button.dart
@@ -1,11 +1,12 @@
import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
/// GpIconButton - 简单的图标按钮组件
///
/// 用于TaskItem的操作按钮,支持鼠标悬浮效果
class GpIconButton extends StatefulWidget {
- /// 图标
- final IconData icon;
+ /// 图标(支持 IconData 或 String 路径)
+ final dynamic icon;
/// 点击回调
final VoidCallback? onTap;
@@ -53,13 +54,57 @@ class _GpIconButtonState extends State {
? const Color(0xFF4883A2)
: Colors.transparent, // 悬浮背景色
),
- child: Icon(
- widget.icon,
- color: widget.color ?? Colors.white,
- size: widget.size ?? 20.0,
- ),
+ child: _buildIcon(),
),
),
);
}
+
+ Widget _buildIcon() {
+ // 如果是字符串,认为是资源路径
+ if (widget.icon is String) {
+ final String path = widget.icon as String;
+ // 支持 svg 资源
+ if (path.toLowerCase().endsWith('.svg')) {
+ return Center(
+ child: SvgPicture.asset(
+ path,
+ width: widget.size ?? 20.0,
+ height: widget.size ?? 20.0,
+ fit: BoxFit.contain,
+ colorFilter: ColorFilter.mode(
+ widget.color ?? Colors.white,
+ BlendMode.srcIn,
+ ),
+ ),
+ );
+ }
+
+ return Center(
+ child: Image.asset(
+ path,
+ width: widget.size ?? 20.0,
+ height: widget.size ?? 20.0,
+ color: widget.color,
+ fit: BoxFit.contain,
+ ),
+ );
+ }
+
+ // 如果是IconData,使用Icon组件
+ if (widget.icon is IconData) {
+ return Icon(
+ widget.icon as IconData,
+ color: widget.color ?? Colors.white,
+ size: widget.size ?? 20.0,
+ );
+ }
+
+ // 如果是Widget,直接使用
+ if (widget.icon is Widget) {
+ return Center(child: widget.icon as Widget);
+ }
+
+ return const SizedBox.shrink();
+ }
}
diff --git a/ui/flutter_v2/lib/components/gp_outline_button.dart b/ui/flutter_v2/lib/components/gp_outline_button.dart
index ae294ea6..f9079542 100644
--- a/ui/flutter_v2/lib/components/gp_outline_button.dart
+++ b/ui/flutter_v2/lib/components/gp_outline_button.dart
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
/// GpOutlineButton - 线框按钮组件
///
@@ -74,9 +75,26 @@ class GpOutlineButton extends StatelessWidget {
// 如果是字符串,认为是资源路径
if (icon is String) {
+ final String path = icon as String;
+ // 支持 svg 资源
+ if (path.toLowerCase().endsWith('.svg')) {
+ return Center(
+ child: SvgPicture.asset(
+ path,
+ width: iconSize,
+ height: iconSize,
+ fit: BoxFit.contain,
+ colorFilter:
+ iconColor != null
+ ? ColorFilter.mode(iconColor!, BlendMode.srcIn)
+ : null,
+ ),
+ );
+ }
+
return Center(
child: Image.asset(
- icon as String,
+ path,
width: iconSize,
height: iconSize,
color: iconColor,
diff --git a/ui/flutter_v2/lib/modules/task/screens/task.dart b/ui/flutter_v2/lib/modules/task/screens/task.dart
index 0af5c871..37b3c13e 100644
--- a/ui/flutter_v2/lib/modules/task/screens/task.dart
+++ b/ui/flutter_v2/lib/modules/task/screens/task.dart
@@ -60,21 +60,21 @@ class _TaskScreenState extends State {
mainAxisAlignment: MainAxisAlignment.end,
children: [
GpOutlineButton(
- icon: 'assets/icons/pause.png',
+ icon: 'assets/icons/resume.svg',
onTap: () {
// 处理开始按钮点击事件
},
),
const SizedBox(width: 12),
GpOutlineButton(
- icon: 'assets/icons/pause.png',
+ icon: 'assets/icons/pause.svg',
onTap: () {
// 处理暂停按钮点击事件
},
),
const SizedBox(width: 12),
GpOutlineButton(
- icon: 'assets/icons/pause.png',
+ icon: 'assets/icons/delete.svg',
onTap: () {
// 处理删除按钮点击事件
},
@@ -109,23 +109,23 @@ class _TaskScreenState extends State {
bottomRightStatusText: '下载中', // 状态文本
actionButtons: [
GpIconButton(
- icon: Icons.pause,
+ icon: 'assets/icons/item_pause.svg',
onTap: () => print('暂停任务 $index'),
),
GpIconButton(
- icon: Icons.delete,
+ icon: 'assets/icons/item_delete.svg',
onTap: () => print('删除任务 $index'),
),
GpIconButton(
- icon: Icons.folder_open,
- onTap: () => print('打开所在位置 $index'),
+ icon: 'assets/icons/item_reveal.svg',
+ onTap: () => print('打开所在·位置 $index'),
),
GpIconButton(
- icon: Icons.info,
+ icon: 'assets/icons/item_info.svg',
onTap: () => print('查看信息 $index'),
),
GpIconButton(
- icon: Icons.more_vert,
+ icon: 'assets/icons/item_more.svg',
onTap: () => print('更多操作 $index'),
),
],
@@ -149,23 +149,23 @@ class _TaskScreenState extends State {
bottomRightStatusText: '已完成', // 状态文本
actionButtons: [
GpIconButton(
- icon: Icons.pause,
- onTap: () => print('暂停任务 $index'),
+ icon: 'assets/icons/item_resume.svg',
+ onTap: () => print('重新下载任务 $index'),
),
GpIconButton(
- icon: Icons.delete,
+ icon: 'assets/icons/item_delete.svg',
onTap: () => print('删除任务 $index'),
),
GpIconButton(
- icon: Icons.folder_open,
+ icon: 'assets/icons/item_reveal.svg',
onTap: () => print('打开所在位置 $index'),
),
GpIconButton(
- icon: Icons.info,
+ icon: 'assets/icons/item_info.svg',
onTap: () => print('查看信息 $index'),
),
GpIconButton(
- icon: Icons.more_vert,
+ icon: 'assets/icons/item_more.svg',
onTap: () => print('更多操作 $index'),
),
],
@@ -189,23 +189,23 @@ class _TaskScreenState extends State {
bottomRightStatusText: '失败', // 状态文本
actionButtons: [
GpIconButton(
- icon: Icons.pause,
- onTap: () => print('暂停任务 $index'),
+ icon: 'assets/icons/item_resume.svg',
+ onTap: () => print('重试任务 $index'),
),
GpIconButton(
- icon: Icons.delete,
+ icon: 'assets/icons/item_delete.svg',
onTap: () => print('删除任务 $index'),
),
GpIconButton(
- icon: Icons.folder_open,
+ icon: 'assets/icons/item_reveal.svg',
onTap: () => print('打开所在位置 $index'),
),
GpIconButton(
- icon: Icons.info,
+ icon: 'assets/icons/item_info.svg',
onTap: () => print('查看信息 $index'),
),
GpIconButton(
- icon: Icons.more_vert,
+ icon: 'assets/icons/item_more.svg',
onTap: () => print('更多操作 $index'),
),
],
diff --git a/ui/flutter_v2/macos/Podfile.lock b/ui/flutter_v2/macos/Podfile.lock
index f6f0ae1b..7b42b4e6 100644
--- a/ui/flutter_v2/macos/Podfile.lock
+++ b/ui/flutter_v2/macos/Podfile.lock
@@ -19,7 +19,7 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos
SPEC CHECKSUMS:
- FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
+ FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
screen_retriever_macos: 776e0fa5d42c6163d2bf772d22478df4b302b161
window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8
diff --git a/ui/flutter_v2/pubspec.lock b/ui/flutter_v2/pubspec.lock
index a1e69f4b..42f9b1a5 100644
--- a/ui/flutter_v2/pubspec.lock
+++ b/ui/flutter_v2/pubspec.lock
@@ -13,10 +13,10 @@ packages:
dependency: transitive
description:
name: async
- sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
+ sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
url: "https://pub.dev"
source: hosted
- version: "2.13.0"
+ version: "2.12.0"
boolean_selector:
dependency: transitive
description:
@@ -61,10 +61,10 @@ packages:
dependency: transitive
description:
name: fake_async
- sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
+ sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
url: "https://pub.dev"
source: hosted
- version: "1.3.3"
+ version: "1.3.2"
flutter:
dependency: "direct main"
description: flutter
@@ -132,26 +132,26 @@ packages:
dependency: transitive
description:
name: leak_tracker
- sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
+ sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
url: "https://pub.dev"
source: hosted
- version: "11.0.2"
+ version: "10.0.8"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
- sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
+ sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
url: "https://pub.dev"
source: hosted
- version: "3.0.10"
+ version: "3.0.9"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
- sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
+ sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.dev"
source: hosted
- version: "3.0.2"
+ version: "3.0.1"
lints:
dependency: transitive
description:
@@ -212,10 +212,10 @@ packages:
dependency: transitive
description:
name: petitparser
- sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1"
+ sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646"
url: "https://pub.dev"
source: hosted
- version: "7.0.1"
+ version: "6.1.0"
plugin_platform_interface:
dependency: transitive
description:
@@ -313,10 +313,10 @@ packages:
dependency: transitive
description:
name: test_api
- sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
+ sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
url: "https://pub.dev"
source: hosted
- version: "0.7.6"
+ version: "0.7.4"
typed_data:
dependency: transitive
description:
@@ -353,18 +353,18 @@ packages:
dependency: transitive
description:
name: vector_math
- sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
+ sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.dev"
source: hosted
- version: "2.2.0"
+ version: "2.1.4"
vm_service:
dependency: transitive
description:
name: vm_service
- sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
+ sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
url: "https://pub.dev"
source: hosted
- version: "15.0.2"
+ version: "14.3.1"
web:
dependency: transitive
description:
@@ -385,10 +385,10 @@ packages:
dependency: transitive
description:
name: xml
- sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025"
+ sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
url: "https://pub.dev"
source: hosted
- version: "6.6.1"
+ version: "6.5.0"
sdks:
- dart: ">=3.8.0 <4.0.0"
+ dart: ">=3.7.2 <4.0.0"
flutter: ">=3.29.0"