fix bug
This commit is contained in:
@@ -10,7 +10,25 @@
|
||||
"Bash(timeout:*)",
|
||||
"Bash(nul)",
|
||||
"Bash(start \"\" \"f:\\cursor-auto\\focusBuddy\\icon-preview.html\")",
|
||||
"Bash(dir:*)"
|
||||
"Bash(dir:*)",
|
||||
"Bash(echo:*)",
|
||||
"Bash(cat:*)",
|
||||
"Bash(code --locate-extension:*)",
|
||||
"Bash(~/sdk/flutter/bin/flutter --version)",
|
||||
"Bash(ruby:*)",
|
||||
"Bash(pod --version:*)",
|
||||
"Bash(gem environment:*)",
|
||||
"Bash(brew:*)",
|
||||
"Bash(sudo gem uninstall:*)",
|
||||
"Bash(rbenv --version:*)",
|
||||
"Bash(rbenv install:*)",
|
||||
"Bash(/opt/homebrew/bin/rbenv install:*)",
|
||||
"Bash(/opt/homebrew/bin/rbenv global:*)",
|
||||
"Bash(/opt/homebrew/bin/rbenv version:*)",
|
||||
"Bash(gem install:*)",
|
||||
"Bash(export PATH=\"$PATH:$HOME/sdk/flutter/bin\")",
|
||||
"Bash(flutter doctor:*)",
|
||||
"Bash(flutter analyze:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
# 🔧 Android 构建修复 - Core Library Desugaring
|
||||
|
||||
**日期**: 2025-11-22
|
||||
**问题**: flutter_local_notifications 需要 core library desugaring
|
||||
|
||||
---
|
||||
|
||||
## ❌ 错误信息
|
||||
|
||||
```
|
||||
FAILURE: Build failed with an exception.
|
||||
|
||||
* What went wrong:
|
||||
Execution failed for task ':app:checkDebugAarMetadata'.
|
||||
> A failure occurred while executing com.android.build.gradle.internal.tasks.CheckAarMetadataWorkAction
|
||||
> An issue was found when checking AAR metadata:
|
||||
|
||||
1. Dependency ':flutter_local_notifications' requires core library desugaring to be enabled
|
||||
for :app.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 问题原因
|
||||
|
||||
`flutter_local_notifications` 包使用了 Java 8+ 的新 API(例如 `java.time` 包),这些 API 在较旧的 Android 版本上不可用。
|
||||
|
||||
Core library desugaring 允许应用使用这些新 API,同时保持对旧版 Android 的兼容性。
|
||||
|
||||
---
|
||||
|
||||
## ✅ 解决方案
|
||||
|
||||
修改 `android/app/build.gradle.kts` 文件:
|
||||
|
||||
### 1. 启用 desugaring
|
||||
|
||||
在 `compileOptions` 中添加:
|
||||
|
||||
```kotlin
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
isCoreLibraryDesugaringEnabled = true // ✨ 新增
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 添加 desugaring 库依赖
|
||||
|
||||
在文件末尾添加:
|
||||
|
||||
```kotlin
|
||||
dependencies {
|
||||
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4")
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 完整修改
|
||||
|
||||
### 修改前
|
||||
```kotlin
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
flutter {
|
||||
source = "../.."
|
||||
}
|
||||
```
|
||||
|
||||
### 修改后
|
||||
```kotlin
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
isCoreLibraryDesugaringEnabled = true // ✨ 新增
|
||||
}
|
||||
|
||||
flutter {
|
||||
source = "../.."
|
||||
}
|
||||
|
||||
dependencies { // ✨ 新增
|
||||
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4")
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 验证修复
|
||||
|
||||
运行以下命令测试:
|
||||
|
||||
```bash
|
||||
flutter clean
|
||||
flutter build apk --debug
|
||||
```
|
||||
|
||||
或直接运行:
|
||||
|
||||
```bash
|
||||
flutter run -d <android-device>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 相关信息
|
||||
|
||||
### 什么是 Core Library Desugaring?
|
||||
|
||||
Desugaring 是一个过程,它将使用较新 Java API 的代码转换为在旧版 Android 上可运行的等效代码。
|
||||
|
||||
### 支持的 API
|
||||
|
||||
启用 desugaring 后,可以使用:
|
||||
- `java.time.*` (日期和时间 API)
|
||||
- `java.util.stream.*` (Stream API)
|
||||
- `java.util.function.*` (函数式接口)
|
||||
- 以及其他 Java 8+ 的核心库 API
|
||||
|
||||
### 版本说明
|
||||
|
||||
- `desugar_jdk_libs:2.0.4` 是当前稳定版本
|
||||
- 最低支持 Android API 21 (Android 5.0)
|
||||
|
||||
---
|
||||
|
||||
## 🔗 参考链接
|
||||
|
||||
- [Android Developer - Java 8+ Support](https://developer.android.com/studio/write/java8-support.html)
|
||||
- [Core Library Desugaring Guide](https://developer.android.com/studio/write/java8-support#library-desugaring)
|
||||
|
||||
---
|
||||
|
||||
**状态**: ✅ 已修复
|
||||
**文件**: `android/app/build.gradle.kts`
|
||||
**影响**: Android 构建现在应该可以正常工作
|
||||
137
BUG_FIX_001.md
137
BUG_FIX_001.md
@@ -1,137 +0,0 @@
|
||||
# 🐛 Bug 修复报告
|
||||
|
||||
## Bug #1: "View Full Report" 按钮无功能
|
||||
|
||||
**日期**: 2025-11-22
|
||||
**发现者**: 用户测试
|
||||
**优先级**: 中等
|
||||
|
||||
---
|
||||
|
||||
### 问题描述
|
||||
|
||||
在 Complete Screen(完成页面)点击 "View Full Report" 按钮时,显示 "History screen coming soon!" 的占位提示,而不是导航到 History 页面。
|
||||
|
||||
**重现步骤**:
|
||||
1. 完成一次 focus session
|
||||
2. 到达 Complete Screen
|
||||
3. 点击 "View Full Report" 按钮
|
||||
4. 看到 SnackBar 提示 "History screen coming soon!"
|
||||
|
||||
---
|
||||
|
||||
### 根本原因
|
||||
|
||||
在 `complete_screen.dart` 中,"View Full Report" 按钮的 `onPressed` 处理函数只是显示一个占位的 SnackBar,而没有实际导航到 HistoryScreen。
|
||||
|
||||
```dart
|
||||
// 问题代码
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('History screen coming soon!'),
|
||||
duration: Duration(seconds: 1),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const Text('View Full Report'),
|
||||
),
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 修复方案
|
||||
|
||||
1. **添加导入**: 在文件顶部添加 `import 'history_screen.dart';`
|
||||
2. **修改按钮行为**: 使用 `Navigator.pushAndRemoveUntil` 导航到 HistoryScreen
|
||||
3. **更新按钮文本**: 将 "View Full Report" 改为更准确的 "View History"
|
||||
|
||||
```dart
|
||||
// 修复后的代码
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pushAndRemoveUntil(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const HistoryScreen(),
|
||||
),
|
||||
(route) => route.isFirst, // Keep only the home screen in stack
|
||||
);
|
||||
},
|
||||
child: const Text('View History'),
|
||||
),
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 修复详情
|
||||
|
||||
**修改的文件**:
|
||||
- `lib/screens/complete_screen.dart`
|
||||
|
||||
**修改内容**:
|
||||
1. 第 7 行:添加 `import 'history_screen.dart';`
|
||||
2. 第 110-122 行:重写 TextButton 的 onPressed 处理函数
|
||||
|
||||
**导航逻辑**:
|
||||
- 使用 `pushAndRemoveUntil` 而不是简单的 `push`
|
||||
- 保留 Home screen 在导航栈底部
|
||||
- 这样从 History 点击返回会回到 Home,而不是 Complete screen
|
||||
|
||||
---
|
||||
|
||||
### 测试验证
|
||||
|
||||
**测试步骤**:
|
||||
1. 完成一次 focus session
|
||||
2. 在 Complete Screen 点击 "View History" 按钮
|
||||
3. 验证:成功导航到 History Screen
|
||||
4. 验证:可以看到刚刚完成的 session
|
||||
5. 点击返回按钮
|
||||
6. 验证:返回到 Home Screen(不是 Complete Screen)
|
||||
|
||||
**预期结果**: ✅ 所有步骤通过
|
||||
|
||||
---
|
||||
|
||||
### 影响范围
|
||||
|
||||
**影响的功能**:
|
||||
- Complete Screen 到 History Screen 的导航流程
|
||||
|
||||
**不影响的功能**:
|
||||
- 其他页面的导航
|
||||
- 数据保存
|
||||
- History Screen 自身的显示逻辑
|
||||
|
||||
---
|
||||
|
||||
### 部署方式
|
||||
|
||||
**Hot Reload**: ✅ 支持
|
||||
**需要重启**: ❌ 不需要
|
||||
|
||||
用户在浏览器中应该会自动看到更新(Flutter 会自动热重载)。如果没有自动更新,按 `R` 进行热重启。
|
||||
|
||||
---
|
||||
|
||||
### 后续改进建议
|
||||
|
||||
可选的 UI 优化:
|
||||
1. 将 "View History" 改为图标按钮(更简洁)
|
||||
2. 添加一个简短的过渡动画
|
||||
3. 在 History Screen 顶部突出显示刚刚完成的 session
|
||||
|
||||
---
|
||||
|
||||
## 状态
|
||||
|
||||
- [x] Bug 已识别
|
||||
- [x] 代码已修复
|
||||
- [x] 已触发热重载
|
||||
- [ ] 等待用户验证
|
||||
|
||||
---
|
||||
|
||||
**修复完成!请在浏览器中测试 "View History" 按钮现在是否正常工作。** 🎉
|
||||
@@ -1,243 +0,0 @@
|
||||
# FocusBuddy - 开发进度报告
|
||||
|
||||
**日期**: 2025年11月22日
|
||||
**状态**: ✅ MVP 核心功能已完成
|
||||
|
||||
---
|
||||
|
||||
## 📦 已完成的工作
|
||||
|
||||
### 1. 项目初始化 ✅
|
||||
- ✅ Flutter 项目创建
|
||||
- ✅ 依赖包配置(Hive, Flutter Local Notifications, Path Provider, Shared Preferences)
|
||||
- ✅ 项目文件夹结构搭建
|
||||
|
||||
### 2. 数据模型 ✅
|
||||
- ✅ `FocusSession` 模型(包含开始时间、时长、分心次数等)
|
||||
- ✅ `DistractionType` 类型定义(4种分心类型)
|
||||
- ✅ Hive 适配器自动生成
|
||||
|
||||
### 3. 主题系统 ✅
|
||||
- ✅ `AppColors` - 莫兰迪色系配色
|
||||
- ✅ `AppTextStyles` - Nunito 字体样式系统
|
||||
- ✅ `AppTheme` - Material 3 主题配置
|
||||
|
||||
### 4. 核心服务 ✅
|
||||
- ✅ `StorageService` - Hive 本地数据存储
|
||||
- ✅ `EncouragementService` - 鼓励文案管理
|
||||
|
||||
### 5. 核心页面 ✅
|
||||
- ✅ **HomeScreen** - 启动页(固定25分钟)
|
||||
- ✅ **FocusScreen** - 计时器页面
|
||||
- 倒计时功能
|
||||
- "I got distracted" 按钮
|
||||
- 暂停/恢复功能
|
||||
- 提前停止确认
|
||||
- 分心类型选择(Bottom Sheet)
|
||||
- ✅ **CompleteScreen** - 完成页面
|
||||
- 显示本次专注时长
|
||||
- 显示今日总计
|
||||
- 随机鼓励文案
|
||||
|
||||
### 6. 核心功能 ✅
|
||||
- ✅ 25分钟固定计时器
|
||||
- ✅ 分心追踪(不中断计时)
|
||||
- ✅ 4种分心类型分类
|
||||
- ✅ 本地数据持久化
|
||||
- ✅ 今日统计(总时长、分心次数)
|
||||
- ✅ 随机鼓励文案
|
||||
|
||||
---
|
||||
|
||||
## 📱 可以运行了!
|
||||
|
||||
### 当前可用设备:
|
||||
- ✅ Windows (desktop)
|
||||
- ✅ Edge (web)
|
||||
|
||||
### 运行命令:
|
||||
```bash
|
||||
# Windows 桌面版
|
||||
flutter run -d windows
|
||||
|
||||
# Web 版(用于快速测试)
|
||||
flutter run -d edge
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 待完成事项
|
||||
|
||||
### 高优先级(影响使用):
|
||||
1. **字体** ⚠️
|
||||
- 当前使用系统默认字体
|
||||
- 需要下载 Nunito 字体或使用 google_fonts 包
|
||||
- 参见 `FONT_SETUP.md`
|
||||
|
||||
### 中优先级(MVP 后续):
|
||||
2. **History Screen** - 历史记录页面
|
||||
3. **Settings Screen** - 设置页面(时长选择)
|
||||
4. **Onboarding** - 首次启动引导
|
||||
5. **本地通知** - 计时完成提醒
|
||||
|
||||
### 低优先级(V1.1+):
|
||||
6. 白噪音播放
|
||||
7. PDF 报告导出
|
||||
8. 成就系统优化
|
||||
9. 主题皮肤
|
||||
|
||||
---
|
||||
|
||||
## 🐛 已知问题
|
||||
|
||||
### 1. 字体缺失
|
||||
**问题**: Nunito 字体文件未下载
|
||||
**影响**: 使用系统默认字体,视觉效果不符合设计
|
||||
**解决方案**:
|
||||
- 方案A: 下载字体文件到 `assets/fonts/`
|
||||
- 方案B: 使用 `google_fonts` 包
|
||||
|
||||
### 2. TODO 占位符
|
||||
**影响**: History 和 Settings 按钮点击显示 "coming soon"
|
||||
**解决**: 后续实现这些页面
|
||||
|
||||
---
|
||||
|
||||
## 📊 代码统计
|
||||
|
||||
| 类型 | 数量 | 文件 |
|
||||
|------|------|------|
|
||||
| 模型 | 2 | focus_session.dart, distraction_type.dart |
|
||||
| 服务 | 2 | storage_service.dart, encouragement_service.dart |
|
||||
| 主题 | 3 | app_colors.dart, app_text_styles.dart, app_theme.dart |
|
||||
| 页面 | 3 | home_screen.dart, focus_screen.dart, complete_screen.dart |
|
||||
| 总代码行数 | ~600+ | (不含生成代码) |
|
||||
|
||||
---
|
||||
|
||||
## 🚀 下一步行动
|
||||
|
||||
### 立即可做:
|
||||
1. **运行测试**:
|
||||
```bash
|
||||
cd f:\cursor-auto\focusBuddy
|
||||
flutter run -d windows
|
||||
```
|
||||
|
||||
2. **体验核心流程**:
|
||||
- 点击 "Start Focusing"
|
||||
- 等待或点击 "I got distracted"
|
||||
- 选择分心类型
|
||||
- 查看完成页面
|
||||
|
||||
3. **验证数据持久化**:
|
||||
- 完成一次专注
|
||||
- 重启 app
|
||||
- 开始新一次专注
|
||||
- 在完成页查看"Total Today"是否累加
|
||||
|
||||
### 本周任务(按 MVP 清单):
|
||||
- [ ] 下载并配置 Nunito 字体
|
||||
- [ ] 实现 History Screen(简单列表)
|
||||
- [ ] 实现 Settings Screen(3个时长选项)
|
||||
- [ ] 添加本地通知(计时完成提醒)
|
||||
- [ ] 真机测试(Android/iOS)
|
||||
|
||||
### 下周任务:
|
||||
- [ ] 上架准备(图标、截图、描述文案)
|
||||
- [ ] 注册开发者账号
|
||||
- [ ] 准备隐私政策和服务条款托管
|
||||
- [ ] Beta 测试
|
||||
|
||||
---
|
||||
|
||||
## 💡 设计亮点
|
||||
|
||||
### 1. 无惩罚机制 ✅
|
||||
- "I got distracted" 不中断计时
|
||||
- 提前停止有友好提示
|
||||
- 鼓励文案代替批评
|
||||
|
||||
### 2. 数据结构简洁 ✅
|
||||
- FocusSession 包含所有核心信息
|
||||
- 分心类型用字符串列表存储
|
||||
- 易于扩展
|
||||
|
||||
### 3. 用户体验友好 ✅
|
||||
- 大按钮,易点击
|
||||
- 柔和配色(莫兰迪色系)
|
||||
- 鼓励性文案随机展示
|
||||
|
||||
---
|
||||
|
||||
## 🎨 技术亮点
|
||||
|
||||
### 1. 架构清晰
|
||||
```
|
||||
lib/
|
||||
├── models/ # 数据模型
|
||||
├── services/ # 业务逻辑
|
||||
├── theme/ # UI 主题
|
||||
├── screens/ # 页面
|
||||
└── main.dart # 入口
|
||||
```
|
||||
|
||||
### 2. 状态管理简单
|
||||
- 使用 StatefulWidget 管理计时器状态
|
||||
- 服务单例模式(StorageService)
|
||||
- 依赖注入(EncouragementService)
|
||||
|
||||
### 3. 数据持久化
|
||||
- Hive 本地数据库
|
||||
- 自动生成适配器
|
||||
- 快速读写
|
||||
|
||||
---
|
||||
|
||||
## 📝 代码质量
|
||||
|
||||
### 优点:
|
||||
- ✅ 代码结构清晰
|
||||
- ✅ 注释完整
|
||||
- ✅ 遵循 Flutter 最佳实践
|
||||
- ✅ Material 3 设计
|
||||
|
||||
### 可改进:
|
||||
- ⚠️ 缺少单元测试
|
||||
- ⚠️ 错误处理可以更健壮
|
||||
- ⚠️ 可以添加更多边界情况处理
|
||||
|
||||
---
|
||||
|
||||
## 🎯 MVP 完成度
|
||||
|
||||
| 功能 | 状态 | 备注 |
|
||||
|------|------|------|
|
||||
| 25分钟固定计时器 | ✅ 100% | |
|
||||
| "I got distracted" 按钮 | ✅ 100% | |
|
||||
| 4种分心分类 | ✅ 100% | |
|
||||
| 鼓励文案反馈 | ✅ 100% | |
|
||||
| 本地数据存储 | ✅ 100% | |
|
||||
| 今日统计 | ✅ 100% | |
|
||||
| 完成页面 | ✅ 100% | |
|
||||
| History 页面 | ⏳ 0% | 下一步 |
|
||||
| Settings 页面 | ⏳ 0% | 下一步 |
|
||||
| 本地通知 | ⏳ 0% | 下一步 |
|
||||
|
||||
**总体完成度**: **70%** (7/10 核心功能)
|
||||
|
||||
---
|
||||
|
||||
## 🎉 总结
|
||||
|
||||
✅ **核心价值已实现**: "无惩罚的专注追踪"功能完整可用
|
||||
|
||||
✅ **可以开始测试**: 主流程已打通,可以体验完整专注循环
|
||||
|
||||
⚠️ **仍需完善**: History、Settings 和通知功能需要补充
|
||||
|
||||
📅 **预计完成 MVP**: 本周末(还需 2-3 天开发时间)
|
||||
|
||||
---
|
||||
|
||||
**下一步**: 运行 `flutter run -d windows` 查看效果!
|
||||
506
FIGMA设计教程.md
506
FIGMA设计教程.md
@@ -1,506 +0,0 @@
|
||||
# 🎨 FocusBuddy 图标设计教程(Figma 中文版)
|
||||
|
||||
**日期**: 2025年11月22日
|
||||
**工具**: Figma(免费)
|
||||
**所需时间**: 20-30分钟
|
||||
**难度**: ⭐⭐☆☆☆ 简单
|
||||
|
||||
---
|
||||
|
||||
## 📋 准备工作
|
||||
|
||||
### 1. 注册 Figma 账号
|
||||
1. 打开浏览器,访问 **https://www.figma.com**
|
||||
2. 点击右上角 **"Sign up"**(注册)
|
||||
3. 使用 Google 账号或邮箱注册(完全免费)
|
||||
4. 验证邮箱后登录
|
||||
|
||||
### 2. 准备颜色代码
|
||||
把这些颜色复制到记事本,待会要用:
|
||||
```
|
||||
主色调(平静的绿色): #A7C4BC
|
||||
成功色(明亮的绿色): #88C9A1
|
||||
背景色(温暖的米白): #F8F6F2
|
||||
文字色(柔和的灰色): #5B6D6D
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 推荐设计方案:温柔专注圈
|
||||
|
||||
这个设计最符合 FocusBuddy 的理念:
|
||||
- 同心圆代表专注的力量
|
||||
- 可选的笑脸让图标更友善
|
||||
- 柔和的配色传达温暖支持
|
||||
|
||||
---
|
||||
|
||||
## 📐 第一步:创建画布(2分钟)
|
||||
|
||||
### 1.1 新建文件
|
||||
1. 登录 Figma 后,点击左上角 **"New design file"**(新建设计文件)
|
||||
2. 会自动打开一个空白画布
|
||||
|
||||
### 1.2 创建正方形画框
|
||||
1. 按键盘 **F** 键(Frame 工具)
|
||||
2. 在右侧属性面板找到 **"Frame"** 区域
|
||||
3. 在宽度(W)输入:**1024**
|
||||
4. 在高度(H)输入:**1024**
|
||||
5. 按 **Enter** 确认
|
||||
|
||||
**✅ 检查点**:你应该看到一个白色的正方形
|
||||
|
||||
### 1.3 命名画框
|
||||
1. 双击画框名称(左侧图层面板)
|
||||
2. 改名为:**FocusBuddy 图标**
|
||||
|
||||
---
|
||||
|
||||
## 🎨 第二步:创建背景渐变(3分钟)
|
||||
|
||||
### 2.1 绘制背景矩形
|
||||
1. 按键盘 **R** 键(矩形工具)
|
||||
2. 在画框内拖拽,绘制一个矩形
|
||||
3. 在右侧属性面板输入:
|
||||
- **W**(宽度):1024
|
||||
- **H**(高度):1024
|
||||
- **X**:0
|
||||
- **Y**:0
|
||||
|
||||
### 2.2 添加渐变色
|
||||
1. 右侧找到 **"Fill"**(填充)
|
||||
2. 点击颜色方块,打开颜色选择器
|
||||
3. 在颜色选择器顶部,找到填充类型图标区域
|
||||
4. 点击渐变图标(通常是第二个图标,有渐变效果的图标)
|
||||
5. 或者直接在颜色方块上看到一个方形图标,点击它切换到 **Linear gradient**(线性渐变)
|
||||
|
||||
### 2.3 设置渐变颜色
|
||||
**第一个色块(顶部)**:
|
||||
1. 点击渐变条上的第一个圆点
|
||||
2. 删除原来的代码,输入:**A7C4BC**
|
||||
3. 按 Enter
|
||||
|
||||
**第二个色块(底部)**:
|
||||
1. 点击渐变条上的第二个圆点
|
||||
2. 删除原来的代码,输入:**88C9A1**
|
||||
3. 按 Enter
|
||||
|
||||
### 2.4 调整渐变方向
|
||||
1. 将渐变条旋转为竖直方向(从上到下)
|
||||
2. 确保顶部是 #A7C4BC(浅绿色)
|
||||
3. 底部是 #88C9A1(明绿色)
|
||||
|
||||
**✅ 检查点**:背景应该是从上到下的绿色渐变
|
||||
|
||||
---
|
||||
|
||||
## 🔵 第三步:绘制外圆环(5分钟)
|
||||
|
||||
### 3.1 创建圆环
|
||||
1. 按键盘 **O** 键(椭圆工具)
|
||||
2. **按住 Shift 键**,在画布中心拖拽出一个正圆
|
||||
3. 在右侧输入尺寸:
|
||||
- **W**:800
|
||||
- **H**:800
|
||||
|
||||
### 3.2 居中对齐
|
||||
1. 选中这个圆(点击它)
|
||||
2. 同时按住 **Ctrl**(Windows)或 **Cmd**(Mac),点击背景画框
|
||||
3. 顶部工具栏会出现对齐按钮
|
||||
4. 点击 **居中对齐** 和 **垂直居中**
|
||||
|
||||
### 3.3 设置圆环样式
|
||||
**填充(Fill)**:
|
||||
1. 点击 Fill 右边的减号 **-**,删除填充
|
||||
|
||||
**描边(Stroke)**:
|
||||
1. 点击 **"Stroke"** 旁边的 **+** 号
|
||||
2. 点击颜色方块,输入:**F8F6F2**(米白色)
|
||||
3. 找到 **"Stroke weight"**(描边粗细)
|
||||
4. 输入:**60**
|
||||
|
||||
**透明度**:
|
||||
1. 找到右上角的 **"Pass through"** 下拉菜单
|
||||
2. 拖动下方的透明度滑块到 **90%**
|
||||
|
||||
**✅ 检查点**:应该看到一个粗粗的白色圆环
|
||||
|
||||
---
|
||||
|
||||
### 💾 随时保存你的工作
|
||||
|
||||
**Figma 会自动保存**,但你也可以手动保存:
|
||||
|
||||
1. **快捷键保存**:
|
||||
- Windows: 按 **Ctrl + S**
|
||||
- Mac: 按 **Cmd + S**
|
||||
|
||||
2. **查看保存状态**:
|
||||
- 文件名旁边会显示 **"Saved"**(已保存)
|
||||
- 如果显示 **"Saving..."**(保存中),等几秒即可
|
||||
|
||||
3. **重命名文件**:
|
||||
- 点击顶部的文件名("Untitled")
|
||||
- 输入新名字,如:**"FocusBuddy 图标"**
|
||||
- 按 Enter
|
||||
|
||||
4. **下次继续**:
|
||||
- 关闭浏览器后,你的设计会保存在云端
|
||||
- 下次登录 Figma,在首页找到你的文件
|
||||
- 点击即可继续编辑
|
||||
|
||||
**💡 提示**:可以随时暂停,Figma 会自动保存你的进度!
|
||||
|
||||
---
|
||||
|
||||
## 🔵 第四步:绘制内圆(4分钟)
|
||||
|
||||
### 4.1 创建内圆
|
||||
1. 按 **O** 键
|
||||
2. **按住 Shift** 拖拽出一个圆
|
||||
3. 设置尺寸:
|
||||
- **W**:560
|
||||
- **H**:560
|
||||
|
||||
### 4.2 居中对齐
|
||||
1. 选中内圆
|
||||
2. 按住 **Ctrl/Cmd**,点击画框
|
||||
3. 点击居中对齐按钮
|
||||
|
||||
### 4.3 设置内圆颜色
|
||||
1. **Fill**(填充):**F8F6F2**(米白色)
|
||||
2. **Opacity**(不透明度):**95%**
|
||||
|
||||
**✅ 检查点**:中间有一个大大的白色圆
|
||||
|
||||
---
|
||||
|
||||
## 😊 第五步:添加笑脸(可选,8分钟)
|
||||
|
||||
### 5.1 绘制左眼
|
||||
1. 按 **O** 键
|
||||
2. 按住 Shift 画一个小圆
|
||||
3. 尺寸:**W: 48, H: 48**
|
||||
4. 位置:**X: 445, Y: 465**
|
||||
5. 填充颜色:**5B6D6D**(灰色)
|
||||
6. 不透明度:**70%**
|
||||
|
||||
### 5.2 绘制右眼
|
||||
1. 按 **Ctrl/Cmd + D** 复制左眼
|
||||
2. 拖动到右边对称位置
|
||||
3. 或直接设置 **X: 530**
|
||||
|
||||
### 5.3 绘制微笑
|
||||
1. 按 **P** 键(钢笔工具)
|
||||
2. 在左眼下方点一下(起点)
|
||||
3. 在中间点一下,**向下拖动** 形成弧度
|
||||
4. 在右眼下方点一下(终点)
|
||||
5. 按 **Esc** 退出钢笔工具
|
||||
|
||||
### 5.4 调整微笑样式
|
||||
1. 选中刚画的曲线
|
||||
2. 删除 **Fill**(填充)
|
||||
3. 添加 **Stroke**(描边):
|
||||
- 颜色:**5B6D6D**
|
||||
- 粗细:**24**
|
||||
- 不透明度:**70%**
|
||||
4. 找到 **Cap** 选项,选择 **Round**(圆角)
|
||||
|
||||
**💡 提示**:如果微笑弧度不满意,可以用 **A** 键(选择工具)拖动中间的点调整
|
||||
|
||||
**✅ 检查点**:应该看到一个温柔的笑脸
|
||||
|
||||
---
|
||||
|
||||
## 🎯 第六步:添加中心点(2分钟)
|
||||
|
||||
### 6.1 绘制中心圆点
|
||||
1. 按 **O** 键
|
||||
2. 按住 Shift 画圆
|
||||
3. 尺寸:**W: 160, H: 160**
|
||||
4. 居中对齐
|
||||
5. 填充颜色:**A7C4BC**(主色)
|
||||
6. 不透明度:**30%**
|
||||
|
||||
**✅ 检查点**:中心有一个淡淡的圆点
|
||||
|
||||
---
|
||||
|
||||
## 🎨 第七步:整体优化(3分钟)
|
||||
|
||||
### 7.1 添加阴影(可选)
|
||||
1. 选中内圆(大白圆)
|
||||
2. 右侧找到 **"Effects"**
|
||||
3. 点击 **+** 号
|
||||
4. 选择 **"Drop Shadow"**(投影)
|
||||
5. 设置:
|
||||
- **X**: 0
|
||||
- **Y**: 4
|
||||
- **Blur**: 20
|
||||
- **Color**: 黑色,透明度 10%
|
||||
|
||||
### 7.2 检查整体效果
|
||||
1. 按 **Ctrl/Cmd + 0**(数字零)缩放到适合大小
|
||||
2. 查看整体是否和谐
|
||||
3. 确保所有元素都居中对齐
|
||||
|
||||
---
|
||||
|
||||
## 📤 第八步:导出图标(5分钟)
|
||||
|
||||
### 8.1 选择导出对象
|
||||
1. 点击最外层的画框(FocusBuddy 图标)
|
||||
2. 确保左侧图层面板中画框名称高亮
|
||||
|
||||
### 8.2 设置导出参数
|
||||
1. 右侧滚动到最底部
|
||||
2. 找到 **"Export"**(导出)区域
|
||||
3. 点击 **+** 号
|
||||
|
||||
### 8.3 导出 PNG
|
||||
1. 格式选择:**PNG**
|
||||
2. 尺寸选择:**1x**(保持 1024×1024)
|
||||
3. 点击 **"Export FocusBuddy 图标"** 按钮
|
||||
4. 保存到电脑,文件名:**icon-1024.png**
|
||||
|
||||
**✅ 检查点**:你应该得到一个 1024×1024 的 PNG 文件
|
||||
|
||||
---
|
||||
|
||||
## 🔧 第九步:生成所有尺寸(5分钟)
|
||||
|
||||
### 9.1 使用在线工具
|
||||
1. 打开浏览器,访问:**https://appicon.co**
|
||||
2. 点击 **"Choose File"**
|
||||
3. 上传刚才导出的 **icon-1024.png**
|
||||
|
||||
### 9.2 生成图标包
|
||||
1. 等待上传完成(几秒钟)
|
||||
2. 勾选 **iOS** 和 **Android**
|
||||
3. 点击 **"Generate"**(生成)
|
||||
|
||||
### 9.3 下载
|
||||
1. 点击 **"Download"** 按钮
|
||||
2. 会下载一个 ZIP 文件
|
||||
3. 解压到桌面
|
||||
|
||||
---
|
||||
|
||||
## 📱 第十步:安装到项目(10分钟)
|
||||
|
||||
### 10.1 iOS 图标安装
|
||||
1. 打开项目文件夹:
|
||||
```
|
||||
f:\cursor-auto\focusBuddy\ios\Runner\Assets.xcassets\AppIcon.appiconset
|
||||
```
|
||||
|
||||
2. 删除原有的图标文件
|
||||
|
||||
3. 从下载的 ZIP 中找到 **iOS** 文件夹
|
||||
|
||||
4. 复制所有图标文件到上面的文件夹
|
||||
|
||||
### 10.2 Android 图标安装
|
||||
1. 打开项目文件夹:
|
||||
```
|
||||
f:\cursor-auto\focusBuddy\android\app\src\main\res
|
||||
```
|
||||
|
||||
2. 你会看到多个文件夹:
|
||||
- mipmap-mdpi
|
||||
- mipmap-hdpi
|
||||
- mipmap-xhdpi
|
||||
- mipmap-xxhdpi
|
||||
- mipmap-xxxhdpi
|
||||
|
||||
3. 从 ZIP 中的 **Android** 文件夹,找到对应尺寸的图标
|
||||
|
||||
4. 复制到对应文件夹,全部命名为:**ic_launcher.png**
|
||||
|
||||
### 10.3 测试
|
||||
```bash
|
||||
# 打开终端,运行:
|
||||
flutter clean
|
||||
flutter run -d edge
|
||||
```
|
||||
|
||||
**✅ 检查点**:浏览器标签页应该显示新图标
|
||||
|
||||
---
|
||||
|
||||
## 🎯 快速参考表
|
||||
|
||||
### 常用快捷键
|
||||
| 快捷键 | 功能 |
|
||||
|--------|------|
|
||||
| F | 创建画框 |
|
||||
| R | 矩形工具 |
|
||||
| O | 椭圆/圆形工具 |
|
||||
| P | 钢笔工具 |
|
||||
| V 或 A | 选择工具 |
|
||||
| Ctrl/Cmd + D | 复制 |
|
||||
| Ctrl/Cmd + 0 | 缩放到适合大小 |
|
||||
| Shift + 拖动 | 保持等比例 |
|
||||
|
||||
### 元素尺寸速查
|
||||
| 元素 | 宽度 | 高度 | 位置 |
|
||||
|------|------|------|------|
|
||||
| 画框 | 1024 | 1024 | - |
|
||||
| 背景 | 1024 | 1024 | 0, 0 |
|
||||
| 外圆环 | 800 | 800 | 居中 |
|
||||
| 内圆 | 560 | 560 | 居中 |
|
||||
| 眼睛 | 48 | 48 | 左眼 X:445, 右眼 X:530 |
|
||||
| 中心点 | 160 | 160 | 居中 |
|
||||
|
||||
### 颜色速查
|
||||
| 用途 | 颜色代码 | 说明 |
|
||||
|------|----------|------|
|
||||
| 渐变顶部 | #A7C4BC | 主色调 |
|
||||
| 渐变底部 | #88C9A1 | 成功色 |
|
||||
| 圆环/内圆 | #F8F6F2 | 背景色 |
|
||||
| 笑脸 | #5B6D6D | 文字色 |
|
||||
|
||||
---
|
||||
|
||||
## ❓ 常见问题
|
||||
|
||||
### Q1: 渐变色看起来不对?
|
||||
**A**: 确保渐变方向是竖直的,顶部浅色 (#A7C4BC),底部深色 (#88C9A1)
|
||||
|
||||
### Q2: 圆形不居中怎么办?
|
||||
**A**:
|
||||
1. 选中圆形
|
||||
2. 按住 Ctrl/Cmd,点击背景画框
|
||||
3. 点击顶部的居中对齐按钮(两个都要点)
|
||||
|
||||
### Q3: 笑脸的弧度不满意?
|
||||
**A**:
|
||||
1. 用 **A** 键选择钢笔工具画的线
|
||||
2. 拖动中间的点上下移动
|
||||
3. 或者删除重画
|
||||
|
||||
### Q4: 颜色输入在哪里?
|
||||
**A**:
|
||||
1. 选中对象
|
||||
2. 右侧 Fill 或 Stroke 区域
|
||||
3. 点击颜色方块
|
||||
4. 在 **HEX** 输入框输入颜色代码
|
||||
|
||||
### Q5: 导出的图片太小?
|
||||
**A**:
|
||||
1. 确保选中的是最外层的画框
|
||||
2. 导出尺寸选择 **1x**
|
||||
3. 不要选择 0.5x 或其他缩放
|
||||
|
||||
---
|
||||
|
||||
## 💡 设计技巧
|
||||
|
||||
### 技巧 1: 使用网格对齐
|
||||
1. 按 **Ctrl/Cmd + '**(单引号)显示网格
|
||||
2. 确保所有元素对齐到网格
|
||||
|
||||
### 技巧 2: 组合元素
|
||||
1. 选中笑脸的所有元素(两个眼睛+嘴巴)
|
||||
2. 按 **Ctrl/Cmd + G** 组合
|
||||
3. 方便统一移动和调整
|
||||
|
||||
### 技巧 3: 保存备份
|
||||
1. 按 **Ctrl/Cmd + S** 保存
|
||||
2. Figma 会自动保存到云端
|
||||
3. 下次可以直接打开继续编辑
|
||||
|
||||
### 技巧 4: 快速测试小尺寸
|
||||
1. 选中画框
|
||||
2. 按 **Ctrl/Cmd + D** 复制
|
||||
3. 将复制的画框缩小到 48×48
|
||||
4. 查看小尺寸效果
|
||||
|
||||
---
|
||||
|
||||
## 📝 完成清单
|
||||
|
||||
制作过程:
|
||||
- [ ] 创建 1024×1024 画框
|
||||
- [ ] 添加绿色渐变背景
|
||||
- [ ] 绘制外圆环(800×800)
|
||||
- [ ] 绘制内圆(560×560)
|
||||
- [ ] 添加笑脸(可选)
|
||||
- [ ] 添加中心点
|
||||
- [ ] 导出 PNG 文件
|
||||
|
||||
生成和安装:
|
||||
- [ ] 上传到 appicon.co
|
||||
- [ ] 下载生成的图标包
|
||||
- [ ] 安装 iOS 图标
|
||||
- [ ] 安装 Android 图标
|
||||
- [ ] 运行测试
|
||||
|
||||
---
|
||||
|
||||
## 🎉 完成效果
|
||||
|
||||
完成后你应该得到:
|
||||
1. ✅ 一个温柔友善的图标
|
||||
2. ✅ 符合 FocusBuddy 品牌色
|
||||
3. ✅ 在小尺寸下依然清晰
|
||||
4. ✅ iOS 和 Android 所有尺寸
|
||||
|
||||
---
|
||||
|
||||
## 📚 学习资源
|
||||
|
||||
如果遇到困难,可以看这些教程:
|
||||
|
||||
### 视频教程(搜索关键词)
|
||||
- Bilibili: "Figma 入门教程"
|
||||
- Bilibili: "如何用 Figma 设计 App 图标"
|
||||
- YouTube: "Figma tutorial for beginners"
|
||||
|
||||
### 文字教程
|
||||
- Figma 官方文档(有中文): https://help.figma.com
|
||||
- 设计导航网站搜索 "Figma 教程"
|
||||
|
||||
---
|
||||
|
||||
## ⏱️ 时间估算
|
||||
|
||||
| 步骤 | 时间 |
|
||||
|------|------|
|
||||
| 注册登录 Figma | 3 分钟 |
|
||||
| 创建画布和背景 | 5 分钟 |
|
||||
| 绘制圆环和圆形 | 9 分钟 |
|
||||
| 添加笑脸 | 8 分钟(可选) |
|
||||
| 整体优化 | 3 分钟 |
|
||||
| 导出和生成 | 10 分钟 |
|
||||
| 安装测试 | 10 分钟 |
|
||||
| **总计** | **30-40 分钟** |
|
||||
|
||||
---
|
||||
|
||||
## 🚀 下一步
|
||||
|
||||
完成图标后:
|
||||
1. 📸 准备应用商店截图(6张)
|
||||
2. 🧪 在真机上测试
|
||||
3. 📝 完善应用描述
|
||||
4. 🚀 提交到应用商店
|
||||
|
||||
---
|
||||
|
||||
## 💬 需要帮助?
|
||||
|
||||
如果在设计过程中遇到问题:
|
||||
|
||||
1. **重新查看本教程** - 确保每一步都按顺序完成
|
||||
2. **查看预览文件** - 打开 `icon-preview.html` 对比效果
|
||||
3. **简化设计** - 可以不加笑脸,只保留圆环
|
||||
4. **使用模板** - 搜索 "Figma app icon template" 找现成模板
|
||||
|
||||
---
|
||||
|
||||
**祝你设计顺利!** 🎨
|
||||
|
||||
你正在创作一个温暖、友善、支持性的图标,它完美代表了 FocusBuddy 的理念:一个温柔的专注伙伴,而不是严格的任务监工。
|
||||
|
||||
**加油!** 💪
|
||||
88
MACOS_BUILD_GUIDE.md
Normal file
88
MACOS_BUILD_GUIDE.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# macOS 编译测试指南
|
||||
|
||||
## 快速开始
|
||||
|
||||
```bash
|
||||
cd /Users/yuantiancai/work/FocusBuddy
|
||||
flutter pub get
|
||||
flutter run -d macos
|
||||
```
|
||||
|
||||
## 环境要求
|
||||
|
||||
### Flutter
|
||||
Flutter 已安装在 `/Users/yuantiancai/sdk/flutter`
|
||||
|
||||
```bash
|
||||
# 添加到 PATH
|
||||
export PATH="$PATH:$HOME/sdk/flutter/bin"
|
||||
source ~/.zshrc
|
||||
```
|
||||
|
||||
### Xcode
|
||||
从 Mac App Store 安装 Xcode,然后:
|
||||
```bash
|
||||
sudo xcodebuild -license accept
|
||||
```
|
||||
|
||||
### CocoaPods
|
||||
使用 rbenv 安装 Ruby 3.x 和 CocoaPods:
|
||||
|
||||
```bash
|
||||
# 安装 rbenv
|
||||
brew install rbenv ruby-build
|
||||
echo 'eval "$(rbenv init - zsh)"' >> ~/.zshrc
|
||||
source ~/.zshrc
|
||||
|
||||
# 安装 Ruby 3.3.8
|
||||
rbenv install 3.3.8
|
||||
rbenv global 3.3.8
|
||||
|
||||
# 安装 CocoaPods
|
||||
gem install cocoapods
|
||||
```
|
||||
|
||||
## 编译运行
|
||||
|
||||
```bash
|
||||
# macOS 桌面
|
||||
flutter run -d macos
|
||||
|
||||
# iOS 模拟器
|
||||
open -a Simulator
|
||||
flutter run -d ios
|
||||
|
||||
# Release 版本
|
||||
flutter build macos --release
|
||||
# 输出:build/macos/Build/Products/Release/focus_buddy.app
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
### CocoaPods 错误
|
||||
```bash
|
||||
cd ios && pod install && cd ..
|
||||
flutter clean && flutter pub get
|
||||
```
|
||||
|
||||
### 构建缓存问题
|
||||
```bash
|
||||
flutter clean
|
||||
flutter pub get
|
||||
```
|
||||
|
||||
### Xcode 签名
|
||||
打开 `ios/Runner.xcworkspace`,在 "Signing & Capabilities" 配置开发团队
|
||||
|
||||
## 开发提示
|
||||
|
||||
运行时快捷键:
|
||||
- `r` - 热重载
|
||||
- `R` - 热重启
|
||||
- `q` - 退出
|
||||
|
||||
代码检查:
|
||||
```bash
|
||||
flutter analyze
|
||||
flutter test
|
||||
```
|
||||
@@ -1,530 +0,0 @@
|
||||
# 📱 本地通知功能 - 实现文档
|
||||
|
||||
**实现日期**: 2025-11-22
|
||||
**状态**: ✅ 完成
|
||||
**平台支持**: Android, iOS (Web不支持)
|
||||
|
||||
---
|
||||
|
||||
## 📋 功能概述
|
||||
|
||||
FocusBuddy 现在支持本地通知,在专注计时完成时自动提醒用户,即使应用在后台运行。
|
||||
|
||||
### 核心特性
|
||||
- ✅ 计时完成时自动发送通知
|
||||
- ✅ 显示专注时长和分心次数
|
||||
- ✅ 支持震动和声音
|
||||
- ✅ 自动请求权限
|
||||
- ✅ Web 平台优雅降级(不报错)
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ 架构设计
|
||||
|
||||
### 文件结构
|
||||
```
|
||||
lib/services/notification_service.dart # 通知服务(新增)
|
||||
lib/main.dart # 初始化通知服务(已修改)
|
||||
lib/screens/focus_screen.dart # 计时完成时调用通知(已修改)
|
||||
android/app/src/main/AndroidManifest.xml # Android权限(已修改)
|
||||
```
|
||||
|
||||
### 服务设计
|
||||
- **单例模式**: 全局只有一个 NotificationService 实例
|
||||
- **延迟初始化**: 首次调用时才初始化
|
||||
- **平台检测**: 自动识别 Web 平台并跳过
|
||||
|
||||
---
|
||||
|
||||
## 📝 代码实现
|
||||
|
||||
### 1. NotificationService 类
|
||||
|
||||
**位置**: `lib/services/notification_service.dart`
|
||||
|
||||
**关键方法**:
|
||||
|
||||
#### `initialize()` - 初始化服务
|
||||
```dart
|
||||
Future<void> initialize() async {
|
||||
if (_initialized) return;
|
||||
|
||||
// Web 平台跳过
|
||||
if (kIsWeb) return;
|
||||
|
||||
// Android/iOS 配置
|
||||
const androidSettings = AndroidInitializationSettings('@mipmap/ic_launcher');
|
||||
const iosSettings = DarwinInitializationSettings(...);
|
||||
|
||||
await _notifications.initialize(initSettings);
|
||||
}
|
||||
```
|
||||
|
||||
#### `requestPermissions()` - 请求权限(iOS)
|
||||
```dart
|
||||
Future<bool> requestPermissions() async {
|
||||
// iOS 需要显式请求,Android 自动授予
|
||||
final result = await _notifications
|
||||
.resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>()
|
||||
?.requestPermissions(...);
|
||||
return result ?? true;
|
||||
}
|
||||
```
|
||||
|
||||
#### `showFocusCompletedNotification()` - 显示完成通知
|
||||
```dart
|
||||
Future<void> showFocusCompletedNotification({
|
||||
required int minutes,
|
||||
required int distractionCount,
|
||||
}) async {
|
||||
final title = '🎉 Focus session complete!';
|
||||
final body = distractionCount == 0
|
||||
? 'You focused for $minutes minutes without distractions!'
|
||||
: 'You focused for $minutes minutes. Great effort!';
|
||||
|
||||
await _notifications.show(0, title, body, details);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. main.dart 初始化
|
||||
|
||||
**修改内容**:
|
||||
```dart
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
await StorageService.init();
|
||||
|
||||
// 新增:初始化通知服务
|
||||
final notificationService = NotificationService();
|
||||
await notificationService.initialize();
|
||||
await notificationService.requestPermissions();
|
||||
|
||||
runApp(MyApp(...));
|
||||
}
|
||||
```
|
||||
|
||||
**何时调用**:
|
||||
- 应用启动时自动初始化
|
||||
- 自动请求权限(iOS 会弹出权限对话框)
|
||||
|
||||
---
|
||||
|
||||
### 3. FocusScreen 计时完成
|
||||
|
||||
**修改位置**: `lib/screens/focus_screen.dart` 第 56-79 行
|
||||
|
||||
**修改内容**:
|
||||
```dart
|
||||
void _onTimerComplete() async {
|
||||
_timer.cancel();
|
||||
_saveFocusSession(completed: true);
|
||||
|
||||
// 新增:发送通知
|
||||
final notificationService = NotificationService();
|
||||
await notificationService.showFocusCompletedNotification(
|
||||
minutes: widget.durationMinutes,
|
||||
distractionCount: _distractions.length,
|
||||
);
|
||||
|
||||
if (!mounted) return;
|
||||
Navigator.pushReplacement(...);
|
||||
}
|
||||
```
|
||||
|
||||
**触发时机**:
|
||||
- 计时器倒数到 0 时
|
||||
- 在导航到 Complete Screen 之前
|
||||
- 保存数据之后
|
||||
|
||||
---
|
||||
|
||||
## 📱 Android 配置
|
||||
|
||||
### AndroidManifest.xml
|
||||
|
||||
**文件位置**: `android/app/src/main/AndroidManifest.xml`
|
||||
|
||||
**添加的权限**:
|
||||
```xml
|
||||
<!-- Android 13+ 通知权限(必需)-->
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
|
||||
<!-- 震动权限(可选,增强体验)-->
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
|
||||
<!-- Wake Lock(可选,后台计时)-->
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
```
|
||||
|
||||
### 权限说明
|
||||
|
||||
| 权限 | 必需性 | 用途 | Android版本 |
|
||||
|------|--------|------|------------|
|
||||
| POST_NOTIFICATIONS | **必需** | 发送通知 | 13+ (API 33+) |
|
||||
| VIBRATE | 可选 | 通知震动 | 所有版本 |
|
||||
| WAKE_LOCK | 可选 | 后台计时 | 所有版本 |
|
||||
|
||||
### Android 权限流程
|
||||
|
||||
**Android 12 及以下**:
|
||||
1. 自动授予通知权限
|
||||
2. 无需用户确认
|
||||
|
||||
**Android 13+**:
|
||||
1. 首次发送通知时,系统自动弹出权限对话框
|
||||
2. 用户可以选择"允许"或"拒绝"
|
||||
3. 拒绝后可在设置中手动开启
|
||||
|
||||
---
|
||||
|
||||
## 🍎 iOS 配置
|
||||
|
||||
### Info.plist
|
||||
|
||||
**不需要修改** - iOS 通知权限在运行时请求,无需配置文件声明。
|
||||
|
||||
### iOS 权限流程
|
||||
|
||||
1. **首次启动**:
|
||||
- App 启动时调用 `requestPermissions()`
|
||||
- 系统弹出权限对话框:
|
||||
```
|
||||
"FocusBuddy" Would Like to Send You Notifications
|
||||
Notifications may include alerts, sounds, and icon badges.
|
||||
[Don't Allow] [Allow]
|
||||
```
|
||||
|
||||
2. **用户选择**:
|
||||
- **允许**: 正常发送通知
|
||||
- **拒绝**: 静默失败(不影响应用运行)
|
||||
|
||||
3. **后续修改**:
|
||||
- 用户可在 设置 > FocusBuddy > 通知 中修改
|
||||
|
||||
---
|
||||
|
||||
## 🌐 Web 平台处理
|
||||
|
||||
### 策略:优雅降级
|
||||
|
||||
**为什么 Web 不支持**:
|
||||
- `flutter_local_notifications` 不支持 Web
|
||||
- Web 使用不同的通知 API(需要 Service Worker)
|
||||
|
||||
**如何处理**:
|
||||
```dart
|
||||
if (kIsWeb) {
|
||||
print('Notifications not supported on web platform');
|
||||
return; // 静默跳过,不报错
|
||||
}
|
||||
```
|
||||
|
||||
**用户体验**:
|
||||
- Web 版用户不会看到通知
|
||||
- 不会报错或崩溃
|
||||
- 计时完成后仍正常跳转到 Complete Screen
|
||||
|
||||
**未来改进** (可选):
|
||||
- 使用 Web Notification API
|
||||
- 或显示应用内弹窗提示
|
||||
|
||||
---
|
||||
|
||||
## 🧪 测试指南
|
||||
|
||||
### Android 测试
|
||||
|
||||
#### 准备工作
|
||||
```bash
|
||||
# 1. 连接 Android 设备或启动模拟器
|
||||
flutter devices
|
||||
|
||||
# 2. 运行应用
|
||||
flutter run -d <android-device-id>
|
||||
```
|
||||
|
||||
#### 测试步骤
|
||||
|
||||
**测试 1: 首次权限请求(Android 13+)**
|
||||
```
|
||||
1. 卸载应用(清除权限状态)
|
||||
2. 重新安装并启动
|
||||
3. 开始一次专注(设置为 1 分钟测试)
|
||||
4. 等待计时完成
|
||||
5. 预期:系统弹出权限对话框
|
||||
6. 点击"允许"
|
||||
7. 预期:看到通知
|
||||
```
|
||||
|
||||
**测试 2: 前台通知**
|
||||
```
|
||||
1. 应用在前台
|
||||
2. 开始专注(1分钟)
|
||||
3. 等待完成
|
||||
4. 预期:
|
||||
- 顶部通知栏出现通知
|
||||
- 有震动(如果手机未静音)
|
||||
- 有声音(如果手机未静音)
|
||||
- 自动跳转到 Complete Screen
|
||||
```
|
||||
|
||||
**测试 3: 后台通知**
|
||||
```
|
||||
1. 开始专注(1分钟)
|
||||
2. 按 Home 键,应用进入后台
|
||||
3. 等待计时完成
|
||||
4. 预期:
|
||||
- 收到通知
|
||||
- 点击通知可回到应用
|
||||
- 看到 Complete Screen
|
||||
```
|
||||
|
||||
**测试 4: 拒绝权限**
|
||||
```
|
||||
1. 在设置中禁用通知权限
|
||||
2. 开始专注
|
||||
3. 完成后不会有通知
|
||||
4. 但应用正常跳转到 Complete Screen
|
||||
5. 预期:无崩溃
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### iOS 测试
|
||||
|
||||
#### 准备工作
|
||||
```bash
|
||||
# 需要 macOS + Xcode
|
||||
# 1. 连接 iPhone 或启动模拟器
|
||||
flutter devices
|
||||
|
||||
# 2. 运行应用
|
||||
flutter run -d <ios-device-id>
|
||||
```
|
||||
|
||||
#### 测试步骤
|
||||
|
||||
**测试 1: 权限对话框**
|
||||
```
|
||||
1. 首次启动应用
|
||||
2. 预期:立即看到权限对话框
|
||||
"FocusBuddy Would Like to Send You Notifications"
|
||||
3. 点击 "Allow"
|
||||
```
|
||||
|
||||
**测试 2: 通知内容**
|
||||
```
|
||||
1. 完成一次专注(0次分心)
|
||||
2. 预期通知内容:
|
||||
标题: 🎉 Focus session complete!
|
||||
正文: You focused for 15 minutes without distractions!
|
||||
|
||||
3. 完成一次专注(3次分心)
|
||||
4. 预期通知内容:
|
||||
标题: 🎉 Focus session complete!
|
||||
正文: You focused for 15 minutes. Great effort!
|
||||
```
|
||||
|
||||
**测试 3: 后台通知**
|
||||
```
|
||||
1. 开始专注
|
||||
2. 滑回主屏幕
|
||||
3. 等待完成
|
||||
4. 预期:锁屏/顶部有通知
|
||||
5. 点击通知打开应用
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Web 测试
|
||||
|
||||
#### 测试步骤
|
||||
```
|
||||
1. 运行 Web 版:flutter run -d edge
|
||||
2. 开始专注
|
||||
3. 等待完成
|
||||
4. 预期:
|
||||
- 控制台输出:Notifications not supported on web platform
|
||||
- 无通知
|
||||
- 正常跳转到 Complete Screen
|
||||
- 无报错
|
||||
```
|
||||
|
||||
✅ **通过标准**: 应用正常运行,无崩溃
|
||||
|
||||
---
|
||||
|
||||
## 📊 通知内容逻辑
|
||||
|
||||
### 标题
|
||||
固定内容:`🎉 Focus session complete!`
|
||||
|
||||
### 正文
|
||||
动态内容,根据分心次数变化:
|
||||
|
||||
```dart
|
||||
if (distractionCount == 0) {
|
||||
body = 'You focused for $minutes minutes without distractions!';
|
||||
} else {
|
||||
body = 'You focused for $minutes minutes. Great effort!';
|
||||
}
|
||||
```
|
||||
|
||||
**示例**:
|
||||
- 25分钟,0次分心: "You focused for 25 minutes without distractions!"
|
||||
- 15分钟,3次分心: "You focused for 15 minutes. Great effort!"
|
||||
|
||||
### 设计理念
|
||||
- **正向鼓励**: 即使有分心,也用"Great effort"
|
||||
- **无惩罚**: 不会说"但你分心了3次"
|
||||
- **符合产品价值观**: 温柔、支持、无评判
|
||||
|
||||
---
|
||||
|
||||
## 🔧 配置选项
|
||||
|
||||
### 当前实现
|
||||
|
||||
| 特性 | Android | iOS |
|
||||
|------|---------|-----|
|
||||
| 声音 | ✅ | ✅ |
|
||||
| 震动 | ✅ | ✅ |
|
||||
| Badge | ❌ | ✅ |
|
||||
| 优先级 | High | Default |
|
||||
| Channel | focus_completed | - |
|
||||
|
||||
### 可调整的参数
|
||||
|
||||
在 `notification_service.dart` 中:
|
||||
|
||||
```dart
|
||||
// Android 配置
|
||||
const androidDetails = AndroidNotificationDetails(
|
||||
'focus_completed', // Channel ID(不建议改)
|
||||
'Focus Session Completed', // Channel Name(用户可见)
|
||||
channelDescription: '...', // Channel描述
|
||||
importance: Importance.high, // 重要性(改为 max 会横幅提示)
|
||||
priority: Priority.high, // 优先级
|
||||
enableVibration: true, // 震动开关
|
||||
playSound: true, // 声音开关
|
||||
);
|
||||
|
||||
// iOS 配置
|
||||
const iosDetails = DarwinNotificationDetails(
|
||||
presentAlert: true, // 显示提示
|
||||
presentBadge: true, // 显示角标
|
||||
presentSound: true, // 播放声音
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 未来改进建议
|
||||
|
||||
### 优先级低(可选)
|
||||
|
||||
1. **自定义通知声音**
|
||||
- 添加温柔的提示音
|
||||
- 替换系统默认声音
|
||||
- 需要音频资源
|
||||
|
||||
2. **定时提醒**
|
||||
- "你已经2小时没专注了,要来一次吗?"
|
||||
- 使用 `showReminderNotification()`
|
||||
- 需要后台任务(WorkManager)
|
||||
|
||||
3. **通知操作按钮**
|
||||
- Android: 通知上添加 "再来一次" 按钮
|
||||
- 点击直接开始新的专注
|
||||
- 需要额外配置
|
||||
|
||||
4. **通知统计**
|
||||
- "本周你已经专注了 12 小时!"
|
||||
- 定期(如周日)发送总结
|
||||
- 需要调度逻辑
|
||||
|
||||
5. **Web 通知支持**
|
||||
- 使用 Web Notification API
|
||||
- 需要 Service Worker
|
||||
- 需要用户手动授权
|
||||
|
||||
---
|
||||
|
||||
## ❗ 常见问题
|
||||
|
||||
### Q1: 为什么 Android 13 没有弹出权限对话框?
|
||||
**A**: Android 13+ 权限会在**首次发送通知时**自动弹出,不是应用启动时。
|
||||
|
||||
**解决方案**:
|
||||
- 完成一次完整的专注会话
|
||||
- 或在设置中手动开启
|
||||
|
||||
---
|
||||
|
||||
### Q2: iOS 模拟器收不到通知?
|
||||
**A**: iOS 模拟器通知功能有限制。
|
||||
|
||||
**解决方案**:
|
||||
- 使用真机测试
|
||||
- 或检查模拟器的通知设置
|
||||
|
||||
---
|
||||
|
||||
### Q3: Web 版为什么没有通知?
|
||||
**A**: `flutter_local_notifications` 不支持 Web。
|
||||
|
||||
**当前方案**: 优雅降级,不报错
|
||||
**未来方案**: 实现 Web Notification API
|
||||
|
||||
---
|
||||
|
||||
### Q4: 通知没有声音?
|
||||
**A**: 检查以下设置:
|
||||
1. 手机是否静音/勿扰模式
|
||||
2. 应用通知权限是否开启
|
||||
3. 通知重要性是否足够高
|
||||
|
||||
---
|
||||
|
||||
### Q5: 后台计时不准确?
|
||||
**A**: Android 后台限制可能影响计时。
|
||||
|
||||
**建议**:
|
||||
- 添加前台服务(Foreground Service)
|
||||
- 或使用 WorkManager
|
||||
- 当前 MVP 不实现,用户应在前台使用
|
||||
|
||||
---
|
||||
|
||||
## 📝 总结
|
||||
|
||||
### ✅ 已实现
|
||||
- [x] 通知服务架构
|
||||
- [x] 计时完成通知
|
||||
- [x] Android 权限配置
|
||||
- [x] iOS 权限请求
|
||||
- [x] Web 平台兼容
|
||||
- [x] 完整文档
|
||||
|
||||
### 📊 影响
|
||||
- **代码变更**: 3 个文件(新增1个,修改2个)
|
||||
- **新增行数**: ~200 行
|
||||
- **配置变更**: Android + iOS 权限
|
||||
- **测试时间**: ~15 分钟(手动测试)
|
||||
|
||||
### 🎯 MVP 完成度
|
||||
```
|
||||
██████████████████▓░ 95% → 98%
|
||||
```
|
||||
|
||||
**新增功能**: 本地通知 ✅
|
||||
**待完成**: 应用图标、截图、上架准备
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: 1.0
|
||||
**最后更新**: 2025-11-22
|
||||
**维护者**: Claude
|
||||
@@ -1,222 +0,0 @@
|
||||
# 🎉 FocusBuddy 开发进度更新
|
||||
|
||||
**更新时间**: 2025年11月22日
|
||||
**当前状态**: ✅ MVP 主要功能已完成!
|
||||
|
||||
---
|
||||
|
||||
## 🚀 新增功能
|
||||
|
||||
### 1. History Screen ✅
|
||||
完整的历史记录页面,包含:
|
||||
- 📊 今日总结卡片(总时长、分心次数、完成会话数)
|
||||
- 📅 按日期分组的会话列表
|
||||
- ⏱️ 每个会话的详细信息(时间、时长、状态)
|
||||
- ✨ 空状态提示(无记录时)
|
||||
|
||||
### 2. Settings Screen ✅
|
||||
实用的设置页面,包含:
|
||||
- ⏰ 默认专注时长选择(15/25/45分钟)
|
||||
- 📱 使用 SharedPreferences 持久化设置
|
||||
- 📋 隐私政策快速查看
|
||||
- ℹ️ 关于 FocusBuddy 介绍
|
||||
- 🔄 设置变更后自动更新首页
|
||||
|
||||
### 3. 动态时长支持 ✅
|
||||
- 首页显示从设置中读取的默认时长
|
||||
- 返回首页时自动刷新时长显示
|
||||
- 所有页面互联互通
|
||||
|
||||
---
|
||||
|
||||
## 📱 完整功能清单
|
||||
|
||||
### ✅ 已完成(90%)
|
||||
|
||||
| 功能模块 | 状态 | 备注 |
|
||||
|---------|------|------|
|
||||
| **核心计时** | ✅ | 完整倒计时 + 暂停/恢复 |
|
||||
| **分心追踪** | ✅ | 4种类型 + 不中断计时 |
|
||||
| **数据持久化** | ✅ | Hive 本地数据库 |
|
||||
| **鼓励系统** | ✅ | 15条随机文案 |
|
||||
| **完成页面** | ✅ | 统计 + 鼓励 |
|
||||
| **History 页面** | ✅ | 完整历史记录 |
|
||||
| **Settings 页面** | ✅ | 时长设置 + 关于 |
|
||||
| **页面导航** | ✅ | 所有页面互联 |
|
||||
| **主题系统** | ✅ | 莫兰迪配色 |
|
||||
| **UI/UX** | ✅ | 符合设计规范 |
|
||||
|
||||
### ⏳ 待完成(10%)
|
||||
|
||||
| 功能 | 优先级 | 预计时间 |
|
||||
|------|--------|---------|
|
||||
| 本地通知 | 中 | 1小时 |
|
||||
| Nunito 字体 | 低 | 30分钟 |
|
||||
| App 图标 | 中 | 1小时 |
|
||||
| 真机测试 | 高 | 2小时 |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 MVP 完成度
|
||||
|
||||
```
|
||||
███████████████████░ 95%
|
||||
```
|
||||
|
||||
**距离可上线版本**: 仅差通知功能和真机测试!
|
||||
|
||||
---
|
||||
|
||||
## 📊 代码统计更新
|
||||
|
||||
| 文件类型 | 数量 | 代码行数 |
|
||||
|---------|------|---------|
|
||||
| Screens | 5 | ~900 行 |
|
||||
| Models | 2 | ~80 行 |
|
||||
| Services | 3 | ~150 行 |
|
||||
| Theme | 4 | ~150 行 |
|
||||
| **总计** | **14** | **~1,280 行** |
|
||||
|
||||
---
|
||||
|
||||
## 🎨 新增的 UI 特性
|
||||
|
||||
### History Screen
|
||||
- ✅ 今日总结卡片带徽章
|
||||
- ✅ 按日期分组的时间线
|
||||
- ✅ 完成/停止状态标识
|
||||
- ✅ 空状态友好提示
|
||||
|
||||
### Settings Screen
|
||||
- ✅ 自定义选择样式(单选按钮)
|
||||
- ✅ 选中状态高亮
|
||||
- ✅ "Default" 标签提示
|
||||
- ✅ 弹窗式隐私政策和关于页面
|
||||
|
||||
---
|
||||
|
||||
## 🧪 测试建议
|
||||
|
||||
### 立即可测试的完整流程:
|
||||
|
||||
1. **首页 → 设置**
|
||||
- 打开 Settings
|
||||
- 更改默认时长为 15 分钟
|
||||
- 返回首页
|
||||
- ✅ 验证: 首页显示 "15 minutes"
|
||||
|
||||
2. **完整专注流程**
|
||||
- 点击 Start Focusing
|
||||
- 点击 2-3 次 "I got distracted"
|
||||
- 选择不同分心类型
|
||||
- 完成或提前停止
|
||||
- 查看完成页统计
|
||||
|
||||
3. **历史记录查看**
|
||||
- 点击 History
|
||||
- 查看今日总结
|
||||
- 查看会话列表
|
||||
- ✅ 验证: 数据正确显示
|
||||
|
||||
4. **多次循环**
|
||||
- 连续完成 2-3 次专注
|
||||
- 查看 History 中的累计数据
|
||||
- ✅ 验证: 今日总时长正确累加
|
||||
|
||||
---
|
||||
|
||||
## 🚀 运行测试
|
||||
|
||||
### Windows 桌面版
|
||||
```bash
|
||||
cd f:\cursor-auto\focusBuddy
|
||||
flutter run -d windows
|
||||
```
|
||||
|
||||
### Web 版
|
||||
```bash
|
||||
flutter run -d edge
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 下一步行动
|
||||
|
||||
### 今天可以完成:
|
||||
1. ✅ 运行并测试所有新功能
|
||||
2. ✅ 验证页面导航流畅性
|
||||
3. ✅ 检查数据持久化是否正常
|
||||
|
||||
### 明天任务:
|
||||
1. ⏰ 添加本地通知(计时完成提醒)
|
||||
2. 🎨 准备应用图标
|
||||
3. 📱 准备真机测试环境
|
||||
|
||||
### 本周末前:
|
||||
1. 🔍 真机测试(Android/iOS)
|
||||
2. 🐛 修复发现的 bug
|
||||
3. 📸 准备应用商店截图
|
||||
|
||||
---
|
||||
|
||||
## 🎊 重要里程碑
|
||||
|
||||
### 已达成:
|
||||
- ✅ 核心差异化功能完整(无惩罚分心追踪)
|
||||
- ✅ 三大核心页面全部完成
|
||||
- ✅ 数据持久化稳定运行
|
||||
- ✅ 用户体验流畅
|
||||
|
||||
### 即将达成:
|
||||
- 🎯 完整 MVP 功能(95% → 100%)
|
||||
- 🎯 准备提交 App Store/Play Store
|
||||
|
||||
---
|
||||
|
||||
## 💡 亮点功能展示
|
||||
|
||||
### 1. 智能时长设置
|
||||
```
|
||||
Home → Settings → 选择 15/25/45 分钟
|
||||
→ 自动保存 → 返回首页 → 时长已更新
|
||||
```
|
||||
|
||||
### 2. 完整历史追踪
|
||||
```
|
||||
今日总结: 47 mins, 2 sessions, 3 distractions
|
||||
↓
|
||||
按日期查看: Today, Yesterday, ...
|
||||
↓
|
||||
每个会话详情: 时间 + 状态 + 分心次数
|
||||
```
|
||||
|
||||
### 3. 无缝导航
|
||||
```
|
||||
Home ⇄ Focus ⇄ Complete
|
||||
↓ ↓
|
||||
History Settings
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎉 恭喜!
|
||||
|
||||
**FocusBuddy 的 MVP 已经 95% 完成!**
|
||||
|
||||
现在你有一个功能完整、可以实际使用的专注应用了。
|
||||
|
||||
接下来只需要:
|
||||
1. 添加通知功能(可选但推荐)
|
||||
2. 真机测试
|
||||
3. 准备上架资料
|
||||
|
||||
**立即运行测试,体验完整功能吧!** 🚀
|
||||
|
||||
---
|
||||
|
||||
**运行命令**:
|
||||
```bash
|
||||
flutter run -d windows
|
||||
```
|
||||
|
||||
或查看 [QUICK_START.md](QUICK_START.md) 了解更多测试指南。
|
||||
@@ -1,334 +0,0 @@
|
||||
# 📝 开发会话总结 - 2025年11月22日
|
||||
|
||||
## 🎯 今日目标
|
||||
从 95% MVP 完成度 → 99% MVP 完成度
|
||||
|
||||
---
|
||||
|
||||
## ✅ 完成的任务
|
||||
|
||||
### 1. 🐛 Bug 修复:Complete Screen 导航问题
|
||||
|
||||
**问题**: 点击 "View Full Report" 按钮显示 "History screen coming soon" 提示
|
||||
|
||||
**修复内容**:
|
||||
- 添加 `history_screen.dart` 导入
|
||||
- 将按钮从 SnackBar 改为正确的导航
|
||||
- 使用 `Navigator.pushAndRemoveUntil` 保持导航栈清晰
|
||||
- 按钮文本改为 "View History"
|
||||
|
||||
**文件**: [complete_screen.dart:110-122](lib/screens/complete_screen.dart#L110-L122)
|
||||
|
||||
**文档**: [BUG_FIX_001.md](BUG_FIX_001.md)
|
||||
|
||||
---
|
||||
|
||||
### 2. 🔔 本地通知系统完整实现
|
||||
|
||||
**功能亮点**:
|
||||
- ✅ 专注完成后自动发送通知
|
||||
- ✅ 基于分心次数的智能文案
|
||||
- 无分心:"You focused for X minutes without distractions!"
|
||||
- 有分心:"You focused for X minutes. Great effort!"
|
||||
- ✅ 跨平台支持
|
||||
- Android: 支持 Android 13+ 的 POST_NOTIFICATIONS 权限
|
||||
- iOS: 运行时权限请求
|
||||
- Web: 优雅降级(不报错)
|
||||
- ✅ 单例模式设计
|
||||
|
||||
**新增文件**:
|
||||
- [lib/services/notification_service.dart](lib/services/notification_service.dart) - 200行完整实现
|
||||
|
||||
**修改文件**:
|
||||
- [lib/main.dart](lib/main.dart) - 添加通知初始化
|
||||
- [lib/screens/focus_screen.dart](lib/screens/focus_screen.dart) - 计时器完成时发送通知
|
||||
- [android/app/src/main/AndroidManifest.xml](android/app/src/main/AndroidManifest.xml) - 添加3个权限
|
||||
- [pubspec.yaml](pubspec.yaml) - 添加 `flutter_local_notifications: ^17.0.0`
|
||||
|
||||
**文档**:
|
||||
- [NOTIFICATION_IMPLEMENTATION.md](NOTIFICATION_IMPLEMENTATION.md) - 200行技术文档
|
||||
- [NOTIFICATION_COMPLETE.md](NOTIFICATION_COMPLETE.md) - 实现总结
|
||||
|
||||
**测试结果**:
|
||||
```
|
||||
✅ Web: "Notifications not supported on web platform" - 优雅降级成功
|
||||
⏳ Android/iOS: 需要真机测试
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. 🎨 Google Fonts (Nunito) 字体集成
|
||||
|
||||
**实现方式**:
|
||||
- 使用 `google_fonts: ^6.1.0` 包
|
||||
- 自动从 Google CDN 下载并缓存字体
|
||||
- 无需手动管理 `assets/fonts/` 目录
|
||||
|
||||
**字体变体**:
|
||||
| 字重 | 用途 | 代码位置 |
|
||||
|------|------|----------|
|
||||
| Light (300) | Helper text | `AppTextStyles.helperText` |
|
||||
| Regular (400) | Body text, quotes | `AppTextStyles.bodyText` |
|
||||
| SemiBold (600) | Headlines, buttons | `AppTextStyles.headline` |
|
||||
| Bold (700) | App title | `AppTextStyles.appTitle` |
|
||||
| ExtraBold (800) | Timer display | `AppTextStyles.timerDisplay` |
|
||||
|
||||
**修改文件**:
|
||||
- [lib/theme/app_text_styles.dart](lib/theme/app_text_styles.dart) - 所有样式使用 `GoogleFonts.nunito()`
|
||||
- [lib/theme/app_theme.dart](lib/theme/app_theme.dart) - 默认字体族设置
|
||||
- [pubspec.yaml](pubspec.yaml) - 添加 `google_fonts: ^6.1.0`
|
||||
|
||||
**遇到的问题**:
|
||||
- ❌ Google Fonts 返回的 TextStyle 不是 `const`
|
||||
- ❌ 代码中有 10 处 `const Text(...style: AppTextStyles.*)` 导致编译错误
|
||||
|
||||
**解决方案**:
|
||||
系统性删除了 10 处 `const` 关键字:
|
||||
- [home_screen.dart](lib/screens/home_screen.dart) - 2处 (第 49, 115 行)
|
||||
- [history_screen.dart](lib/screens/history_screen.dart) - 2处 (第 86, 92 行)
|
||||
- [settings_screen.dart](lib/screens/settings_screen.dart) - 5处 (第 63, 84, 100, 251, 276 行)
|
||||
- [complete_screen.dart](lib/screens/complete_screen.dart) - 1处 (第 46 行)
|
||||
|
||||
**测试结果**:
|
||||
```bash
|
||||
✅ flutter pub get && flutter run -d edge
|
||||
✅ "Starting application from main method"
|
||||
✅ 所有字体正确渲染
|
||||
```
|
||||
|
||||
**文档**:
|
||||
- [GOOGLE_FONTS_SETUP.md](GOOGLE_FONTS_SETUP.md) - 完整实现指南
|
||||
|
||||
---
|
||||
|
||||
## 📊 今日统计
|
||||
|
||||
### 代码变更
|
||||
- **新增代码**: ~250 行
|
||||
- notification_service.dart: 200 行
|
||||
- 其他修改: 50 行
|
||||
- **修改文件**: 9 个
|
||||
- **新增依赖**: 2 个 (flutter_local_notifications, google_fonts)
|
||||
- **新增服务**: 1 个 (NotificationService)
|
||||
|
||||
### 文档更新
|
||||
- **新增文档**: 4 个
|
||||
- BUG_FIX_001.md
|
||||
- NOTIFICATION_IMPLEMENTATION.md
|
||||
- NOTIFICATION_COMPLETE.md
|
||||
- GOOGLE_FONTS_SETUP.md
|
||||
- **更新文档**: 1 个
|
||||
- FINAL_SUMMARY.md (95% → 99%)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 MVP 完成度对比
|
||||
|
||||
### 开始 (95%)
|
||||
```
|
||||
███████████████████░ 95%
|
||||
```
|
||||
- ✅ 所有核心功能
|
||||
- ✅ 所有核心页面
|
||||
- ✅ 数据持久化
|
||||
- ❌ 本地通知
|
||||
- ❌ Nunito 字体
|
||||
- ❌ 应用图标
|
||||
|
||||
### 结束 (99%)
|
||||
```
|
||||
███████████████████▓ 99%
|
||||
```
|
||||
- ✅ 所有核心功能
|
||||
- ✅ 所有核心页面
|
||||
- ✅ 数据持久化
|
||||
- ✅ 本地通知系统 ✨
|
||||
- ✅ Google Fonts (Nunito) ✨
|
||||
- ✅ Bug 修复(Complete Screen 导航)✨
|
||||
- ⏳ 应用图标(1%)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 技术亮点
|
||||
|
||||
### 1. 通知服务单例模式
|
||||
```dart
|
||||
class NotificationService {
|
||||
static final NotificationService _instance = NotificationService._internal();
|
||||
factory NotificationService() => _instance;
|
||||
NotificationService._internal();
|
||||
|
||||
// 防止重复初始化
|
||||
bool _initialized = false;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 平台检测与优雅降级
|
||||
```dart
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
if (kIsWeb) {
|
||||
print('Notifications not supported on web platform');
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Google Fonts 集成
|
||||
```dart
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
static final appTitle = GoogleFonts.nunito(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.textPrimary,
|
||||
);
|
||||
```
|
||||
|
||||
### 4. 智能通知文案
|
||||
```dart
|
||||
final body = distractionCount == 0
|
||||
? 'You focused for $minutes minutes without distractions!'
|
||||
: 'You focused for $minutes minutes. Great effort!';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 测试状态
|
||||
|
||||
### Web 平台 ✅
|
||||
- ✅ 应用成功启动
|
||||
- ✅ 数据库初始化成功
|
||||
- ✅ 通知服务优雅降级
|
||||
- ✅ 字体正确渲染
|
||||
- ✅ 所有页面导航正常
|
||||
|
||||
### Android/iOS ⏳
|
||||
- ⏳ 需要连接真机测试
|
||||
- ⏳ 验证通知权限请求
|
||||
- ⏳ 验证通知显示和交互
|
||||
- ⏳ 验证字体在移动设备上的渲染
|
||||
|
||||
---
|
||||
|
||||
## 📝 遗留任务
|
||||
|
||||
### 立即任务(1%)
|
||||
1. 🎨 设计应用图标
|
||||
- iOS: 1024×1024
|
||||
- Android: 512×512
|
||||
- 生成所有尺寸变体
|
||||
|
||||
### 短期任务
|
||||
2. 📸 准备应用商店截图
|
||||
- 6张截图展示核心功能
|
||||
- iOS 和 Android 两种格式
|
||||
|
||||
3. 🧪 真机测试
|
||||
- Android 设备测试
|
||||
- iOS 设备测试(需要 Mac)
|
||||
- 验证所有功能
|
||||
|
||||
### 中期任务
|
||||
4. 📝 完善应用描述
|
||||
5. 🌐 部署隐私政策页面
|
||||
6. 📋 填写应用商店上架表单
|
||||
|
||||
---
|
||||
|
||||
## 💡 经验总结
|
||||
|
||||
### 成功经验
|
||||
1. **系统性问题解决**:
|
||||
- 遇到 const 关键字冲突后,立即搜索所有相关位置
|
||||
- 一次性修复所有问题,避免重复编译错误
|
||||
|
||||
2. **完整文档记录**:
|
||||
- 每个重要功能都创建独立文档
|
||||
- 包含问题背景、解决方案、测试步骤
|
||||
- 便于后续回顾和团队协作
|
||||
|
||||
3. **优雅降级设计**:
|
||||
- 通知系统在 Web 平台上不报错
|
||||
- 使用 `kIsWeb` 进行平台检测
|
||||
- 保证跨平台一致的用户体验
|
||||
|
||||
### 遇到的挑战
|
||||
1. **const 优化与运行时计算的冲突**
|
||||
- Google Fonts 返回的是运行时计算的 TextStyle
|
||||
- 需要删除所有相关的 const 关键字
|
||||
- 解决方案:系统性搜索和修复
|
||||
|
||||
2. **跨平台兼容性**
|
||||
- Web 不支持本地通知
|
||||
- 需要在服务层做平台检测
|
||||
- 避免在 UI 层暴露平台差异
|
||||
|
||||
---
|
||||
|
||||
## 🎉 里程碑
|
||||
|
||||
- ✅ **Bug 修复**: Complete Screen 导航恢复正常
|
||||
- ✅ **本地通知**: 完整的通知系统实现(200行)
|
||||
- ✅ **字体优化**: Google Fonts 集成成功
|
||||
- ✅ **编译成功**: 所有 const 冲突解决
|
||||
- ✅ **Web 运行**: 应用在浏览器中成功运行
|
||||
|
||||
---
|
||||
|
||||
## 📈 项目进度
|
||||
|
||||
### 总体完成度: 99%
|
||||
|
||||
| 模块 | 完成度 | 状态 |
|
||||
|------|--------|------|
|
||||
| 核心功能 | 100% | ✅ |
|
||||
| 页面系统 | 100% | ✅ |
|
||||
| 数据管理 | 100% | ✅ |
|
||||
| 通知系统 | 100% | ✅ |
|
||||
| 字体优化 | 100% | ✅ |
|
||||
| 应用图标 | 0% | ⏳ |
|
||||
| 商店截图 | 0% | ⏳ |
|
||||
| 真机测试 | 0% | ⏳ |
|
||||
|
||||
---
|
||||
|
||||
## 🚀 下一步行动
|
||||
|
||||
### 明天计划
|
||||
1. **设计应用图标** (2小时)
|
||||
- 使用 Figma/Canva 设计
|
||||
- 导出所有需要的尺寸
|
||||
- 更新 iOS 和 Android 配置
|
||||
|
||||
2. **准备商店截图** (2小时)
|
||||
- 捕获 6 张关键截图
|
||||
- 添加简短说明文字
|
||||
- 准备多语言版本(中英文)
|
||||
|
||||
3. **真机测试** (3小时)
|
||||
- 在 Android 设备上测试
|
||||
- 验证通知功能
|
||||
- 记录并修复 bug
|
||||
|
||||
### 本周计划
|
||||
- 完成上架前的所有准备工作
|
||||
- 提交到 Google Play 和 App Store
|
||||
- 准备市场推广材料
|
||||
|
||||
---
|
||||
|
||||
## 🎊 总结
|
||||
|
||||
**今天是非常成功的一天!**
|
||||
|
||||
从 95% 到 99% 的进展,不仅完成了关键的功能实现(通知系统),还解决了重要的质量问题(字体优化、bug 修复)。
|
||||
|
||||
应用现在已经具备了完整的 MVP 功能,并且在 Web 平台上成功运行。只需要完成最后的润色工作(图标、截图、真机测试),就可以提交到应用商店了。
|
||||
|
||||
**你已经非常接近目标了!** 🚀
|
||||
|
||||
---
|
||||
|
||||
**会话时间**: 2025年11月22日
|
||||
**开发者**: FocusBuddy 团队
|
||||
**版本**: v1.0-rc1 (Release Candidate 1)
|
||||
@@ -1,270 +0,0 @@
|
||||
# 🚀 Quick Testing Guide - Start Here!
|
||||
|
||||
Your FocusBuddy app is **running successfully** in Edge browser!
|
||||
|
||||
## ✅ Current Status
|
||||
|
||||
```
|
||||
✅ App compiled successfully
|
||||
✅ Running in Edge browser
|
||||
✅ Database initialized (Hive)
|
||||
✅ Hot reload enabled
|
||||
✅ All 5 screens implemented
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Quick 10-Minute Test Flow
|
||||
|
||||
Follow this streamlined test to verify all core features work:
|
||||
|
||||
### **Test 1: Check Home Screen (30 seconds)**
|
||||
1. Open your Edge browser
|
||||
2. You should see "FocusBuddy" title
|
||||
3. Check: "25 minutes" is displayed
|
||||
4. ✅ **Pass if**: UI looks good, buttons visible
|
||||
|
||||
---
|
||||
|
||||
### **Test 2: Change Settings (1 minute)**
|
||||
1. Click **"Settings"** button
|
||||
2. Click **"15 minutes"** option
|
||||
3. Observe the green checkmark
|
||||
4. Click **back arrow** to return home
|
||||
5. ✅ **Pass if**: Home now shows "15 minutes"
|
||||
|
||||
---
|
||||
|
||||
### **Test 3: Quick Focus Session (2 minutes)**
|
||||
|
||||
⚠️ **Important**: To test quickly without waiting 15 minutes, I can modify the timer to use seconds instead. Should I do that?
|
||||
|
||||
For now, let's test the UI:
|
||||
1. Click **"Start Focusing"**
|
||||
2. Observe timer screen
|
||||
3. Check timer is counting down from 15:00
|
||||
4. ✅ **Pass if**: Timer updates every second
|
||||
|
||||
---
|
||||
|
||||
### **Test 4: Distraction Button - Critical! (1 minute)**
|
||||
**This is the core feature - must work perfectly:**
|
||||
|
||||
1. While timer is running, click **"I got distracted"**
|
||||
2. **Critical check**: Timer should KEEP RUNNING (not pause!)
|
||||
3. Look for message: "It happens. Let's gently come back."
|
||||
4. Bottom sheet appears with 4 distraction types
|
||||
5. Click **"📱 Scrolling social media"**
|
||||
6. Click **"I got distracted"** again
|
||||
7. Select **"💭 Just zoned out"**
|
||||
8. Observe distraction counter increases
|
||||
9. ✅ **Pass if**: Timer NEVER stops, distractions recorded
|
||||
|
||||
---
|
||||
|
||||
### **Test 5: Pause/Resume (30 seconds)**
|
||||
1. Click **"Pause"** button
|
||||
2. Observe timer stops
|
||||
3. Wait 5 seconds
|
||||
4. Click **"Resume"**
|
||||
5. ✅ **Pass if**: Timer continues from paused time
|
||||
|
||||
---
|
||||
|
||||
### **Test 6: Stop Early (1 minute)**
|
||||
1. Click **"Stop session"** button
|
||||
2. Read confirmation dialog
|
||||
3. Click **"Yes, stop"**
|
||||
4. You should land on **Complete Screen**
|
||||
5. Check: Shows actual minutes focused (e.g., "2 minutes")
|
||||
6. Check: Shows distraction count (should be 2 from Test 4)
|
||||
7. Check: Shows random encouragement message
|
||||
8. ✅ **Pass if**: All stats are correct
|
||||
|
||||
---
|
||||
|
||||
### **Test 7: View History (1 minute)**
|
||||
1. Click **"View History"** button
|
||||
2. Observe **"📅 Today"** summary card
|
||||
3. Check: Total minutes displayed
|
||||
4. Check: Distraction count displayed
|
||||
5. Scroll down to see your session listed
|
||||
6. Session should show: time, duration, "⏸️ Stopped early" badge
|
||||
7. ✅ **Pass if**: Data matches what you just did
|
||||
|
||||
---
|
||||
|
||||
### **Test 8: Complete Another Session (2 minutes)**
|
||||
1. Go back to **Home**
|
||||
2. Click **"Start Focusing"** again
|
||||
3. Let it run for 30 seconds (no distractions this time)
|
||||
4. Click **"Stop session"** → **"Yes, stop"**
|
||||
5. Go to **History**
|
||||
6. Check: Now shows **2 sessions**
|
||||
7. Check: Total minutes increased
|
||||
8. ✅ **Pass if**: Both sessions listed
|
||||
|
||||
---
|
||||
|
||||
### **Test 9: Data Persistence (1 minute)**
|
||||
1. In the terminal, press **`R`** (capital R) to hot restart
|
||||
2. Or close and reopen browser tab
|
||||
3. Go to **History**
|
||||
4. ✅ **Pass if**: Your sessions are still there!
|
||||
|
||||
---
|
||||
|
||||
### **Test 10: About & Privacy (30 seconds)**
|
||||
1. Go to **Settings**
|
||||
2. Click **"Privacy Policy"**
|
||||
3. Read dialog, click **"Close"**
|
||||
4. Click **"About FocusBuddy"**
|
||||
5. Read dialog, click **"Close"**
|
||||
6. ✅ **Pass if**: Dialogs display properly
|
||||
|
||||
---
|
||||
|
||||
## 🎊 If All Tests Pass
|
||||
|
||||
**Congratulations!** Your MVP is working perfectly.
|
||||
|
||||
### ✅ What This Means:
|
||||
- All core features work
|
||||
- Data persistence works
|
||||
- UI is functional
|
||||
- No critical bugs
|
||||
|
||||
### 📋 Next Steps:
|
||||
1. See [TEST_REPORT.md](TEST_REPORT.md) for 20 detailed test cases
|
||||
2. Test on Android/iOS devices
|
||||
3. Polish UI if needed
|
||||
4. Add notifications (optional)
|
||||
5. Prepare app store assets
|
||||
|
||||
---
|
||||
|
||||
## 🐛 If Something Doesn't Work
|
||||
|
||||
### How to Report Issues:
|
||||
|
||||
**For each problem, note:**
|
||||
1. **Which test failed?** (Test 1-10)
|
||||
2. **What happened?** (exact error message or behavior)
|
||||
3. **What did you expect?** (correct behavior)
|
||||
|
||||
### Common Issues & Fixes:
|
||||
|
||||
#### **Issue**: Timer doesn't update every second
|
||||
**Fix**: Check browser console (F12) for JavaScript errors
|
||||
|
||||
#### **Issue**: Distraction button pauses timer
|
||||
**Fix**: This is a critical bug - needs code fix in focus_screen.dart
|
||||
|
||||
#### **Issue**: History is empty after restart
|
||||
**Fix**: Hive database issue - check initialization
|
||||
|
||||
#### **Issue**: Settings don't persist
|
||||
**Fix**: SharedPreferences issue
|
||||
|
||||
---
|
||||
|
||||
## 🔥 Hot Reload Commands
|
||||
|
||||
While testing, you can use these in the terminal:
|
||||
|
||||
- **`r`** - Hot reload (fast, keeps state)
|
||||
- **`R`** - Hot restart (full reset)
|
||||
- **`c`** - Clear console
|
||||
- **`q`** - Quit app
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Speed Up Testing
|
||||
|
||||
### Option 1: Modify Timer to Use Seconds (Temporary)
|
||||
I can change the timer to count seconds instead of minutes so you don't have to wait 15 minutes per test.
|
||||
|
||||
**Would you like me to do this?**
|
||||
|
||||
### Option 2: Test at 1x Speed
|
||||
Just test the UI interactions (pause, distraction, etc.) and trust the timer logic works. You can do one full session overnight.
|
||||
|
||||
---
|
||||
|
||||
## 📊 Quick Checklist
|
||||
|
||||
After testing, fill this out:
|
||||
|
||||
```
|
||||
✅ Home screen displays correctly
|
||||
✅ Settings change duration
|
||||
✅ Settings persist after reload
|
||||
✅ Focus timer counts down
|
||||
✅ Pause/Resume works
|
||||
✅ "I got distracted" doesn't stop timer ⚠️ CRITICAL
|
||||
✅ Distraction types can be selected
|
||||
✅ Stop early saves partial session
|
||||
✅ Complete screen shows correct stats
|
||||
✅ History shows all sessions
|
||||
✅ Today's summary is accurate
|
||||
✅ Data persists after restart
|
||||
✅ Privacy/About dialogs work
|
||||
✅ Navigation works (all screens)
|
||||
✅ UI looks good (colors, fonts, spacing)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 The Most Important Test
|
||||
|
||||
**Test 4** (Distraction Button) is **THE MOST CRITICAL TEST**.
|
||||
|
||||
This is the core differentiator of FocusBuddy:
|
||||
> "I got distracted" must NEVER pause the timer.
|
||||
|
||||
If this doesn't work, everything else doesn't matter. Please test this carefully!
|
||||
|
||||
---
|
||||
|
||||
## 💡 Pro Tips
|
||||
|
||||
1. **Keep the terminal visible** - you'll see console logs and can hot reload
|
||||
2. **Test distraction button multiple times** - try 10+ distractions in one session
|
||||
3. **Try edge cases** - What if you tap distraction 20 times rapidly?
|
||||
4. **Check responsive design** - Resize browser window to mobile size
|
||||
5. **Read encouragement messages** - Are they emotionally appropriate?
|
||||
|
||||
---
|
||||
|
||||
## 📱 Browser Access
|
||||
|
||||
If you closed the browser, open a new tab and go to:
|
||||
```
|
||||
http://localhost:<port>/
|
||||
```
|
||||
|
||||
The port number is shown in the terminal output. Look for:
|
||||
```
|
||||
Debug service listening on ws://127.0.0.1:XXXXX/...
|
||||
```
|
||||
|
||||
Or just press `R` in the terminal to restart the app.
|
||||
|
||||
---
|
||||
|
||||
## ✨ Current State
|
||||
|
||||
```
|
||||
🟢 App Running: Yes
|
||||
🟢 Database: Initialized
|
||||
🟢 Hot Reload: Enabled
|
||||
⚪ Testing: Ready to start
|
||||
```
|
||||
|
||||
**You can start testing now!**
|
||||
|
||||
Follow Tests 1-10 above, and report back any issues. If everything works, we'll move on to preparing for launch! 🚀
|
||||
|
||||
---
|
||||
|
||||
**Happy Testing!** 🎉
|
||||
595
TEST_REPORT.md
595
TEST_REPORT.md
@@ -1,595 +0,0 @@
|
||||
# 🧪 FocusBuddy - Test Report
|
||||
|
||||
**Date**: 2025-11-22
|
||||
**Build**: MVP v1.0.0
|
||||
**Platform**: Web (Edge Browser)
|
||||
**Status**: ✅ Running Successfully
|
||||
|
||||
---
|
||||
|
||||
## 📋 Test Environment
|
||||
|
||||
### System Information
|
||||
- **Platform**: Windows (Web fallback due to Developer Mode requirement)
|
||||
- **Browser**: Microsoft Edge
|
||||
- **Flutter Version**: 3.10.0-290.4.beta
|
||||
- **SDK**: Dart ^3.10.0-290.4.beta
|
||||
|
||||
### Build Status
|
||||
- ✅ **Web Build**: Success
|
||||
- ❌ **Windows Desktop**: Blocked (requires Developer Mode for symlink support)
|
||||
- ⏳ **Android**: Not tested yet (requires device/emulator)
|
||||
- ⏳ **iOS**: Not tested yet (requires macOS + device/simulator)
|
||||
|
||||
### Database Initialization
|
||||
```
|
||||
Got object store box in database focus_sessions.
|
||||
```
|
||||
✅ **Hive database initialized successfully**
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Test Plan
|
||||
|
||||
### Test Coverage Matrix
|
||||
|
||||
| Feature | Status | Priority | Notes |
|
||||
|---------|--------|----------|-------|
|
||||
| Home Screen | 🟡 Ready | P0 | Manual testing required |
|
||||
| Settings Screen | 🟡 Ready | P0 | Manual testing required |
|
||||
| Focus Timer | 🟡 Ready | P0 | Manual testing required |
|
||||
| Distraction Tracking | 🟡 Ready | P0 | Manual testing required |
|
||||
| Complete Screen | 🟡 Ready | P0 | Manual testing required |
|
||||
| History Screen | 🟡 Ready | P0 | Manual testing required |
|
||||
| Data Persistence | 🟡 Ready | P0 | Manual testing required |
|
||||
| Navigation Flow | 🟡 Ready | P0 | Manual testing required |
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Detailed Test Cases
|
||||
|
||||
### Test 1: Home Screen - Initial Load
|
||||
**Objective**: Verify default state and UI elements
|
||||
|
||||
**Steps**:
|
||||
1. Open app in browser
|
||||
2. Observe home screen
|
||||
|
||||
**Expected Results**:
|
||||
- ✅ "FocusBuddy" title displayed
|
||||
- ✅ "25 minutes" duration displayed (default)
|
||||
- ✅ "Start Focusing" button visible
|
||||
- ✅ Helper text: "Tap 'I got distracted' anytime — no guilt."
|
||||
- ✅ "History" and "Settings" buttons at bottom
|
||||
|
||||
**Actual Results**: [TO BE TESTED]
|
||||
|
||||
---
|
||||
|
||||
### Test 2: Settings Screen - Change Duration
|
||||
**Objective**: Verify settings persistence and UI updates
|
||||
|
||||
**Steps**:
|
||||
1. From Home screen, tap "Settings"
|
||||
2. Select "15 minutes" option
|
||||
3. Tap back button to return to Home
|
||||
4. Observe duration display
|
||||
|
||||
**Expected Results**:
|
||||
- ✅ Settings screen opens
|
||||
- ✅ Duration options: 15, 25 (Default), 45 minutes
|
||||
- ✅ Radio button UI indicates selection
|
||||
- ✅ Home screen updates to "15 minutes"
|
||||
- ✅ Duration persists in SharedPreferences
|
||||
|
||||
**Actual Results**: [TO BE TESTED]
|
||||
|
||||
---
|
||||
|
||||
### Test 3: Settings Screen - Privacy Policy
|
||||
**Objective**: Verify dialogs display correctly
|
||||
|
||||
**Steps**:
|
||||
1. Go to Settings
|
||||
2. Tap "Privacy Policy"
|
||||
3. Read content
|
||||
4. Close dialog
|
||||
5. Tap "About FocusBuddy"
|
||||
6. Close dialog
|
||||
|
||||
**Expected Results**:
|
||||
- ✅ Privacy dialog shows offline commitment
|
||||
- ✅ About dialog shows app description
|
||||
- ✅ Close button works
|
||||
- ✅ Returns to Settings screen
|
||||
|
||||
**Actual Results**: [TO BE TESTED]
|
||||
|
||||
---
|
||||
|
||||
### Test 4: Focus Session - Complete Flow
|
||||
**Objective**: Verify full 15-minute session (accelerated testing recommended)
|
||||
|
||||
**Steps**:
|
||||
1. Set duration to 15 minutes
|
||||
2. Tap "Start Focusing"
|
||||
3. Observe timer countdown
|
||||
4. Wait until timer reaches 00:00
|
||||
|
||||
**Expected Results**:
|
||||
- ✅ Focus screen displays timer
|
||||
- ✅ Timer counts down from 15:00
|
||||
- ✅ "I got distracted" button visible
|
||||
- ✅ "Pause" button visible
|
||||
- ✅ Timer reaches 00:00
|
||||
- ✅ Automatically navigates to Complete screen
|
||||
- ✅ Complete screen shows: "15 minutes", today's total, encouragement
|
||||
|
||||
**Actual Results**: [TO BE TESTED]
|
||||
|
||||
**⚠️ Testing Note**: For rapid testing, consider temporarily modifying timer to use seconds instead of minutes.
|
||||
|
||||
---
|
||||
|
||||
### Test 5: Focus Session - Pause/Resume
|
||||
**Objective**: Verify pause functionality
|
||||
|
||||
**Steps**:
|
||||
1. Start a focus session
|
||||
2. After 30 seconds, tap "Pause"
|
||||
3. Wait 10 seconds
|
||||
4. Tap "Resume"
|
||||
5. Verify timer continues
|
||||
|
||||
**Expected Results**:
|
||||
- ✅ Timer pauses immediately
|
||||
- ✅ Button changes to "Resume"
|
||||
- ✅ Timer resumes from paused time
|
||||
- ✅ No time is lost
|
||||
|
||||
**Actual Results**: [TO BE TESTED]
|
||||
|
||||
---
|
||||
|
||||
### Test 6: Focus Session - Distraction Tracking
|
||||
**Objective**: Verify "no punishment" distraction mechanism
|
||||
|
||||
**Steps**:
|
||||
1. Start a focus session
|
||||
2. Tap "I got distracted" (DO NOT pause timer)
|
||||
3. Observe SnackBar message
|
||||
4. Select "📱 Scrolling social media" from bottom sheet
|
||||
5. Observe timer continues
|
||||
6. Tap "I got distracted" again
|
||||
7. Select "🌪️ Felt overwhelmed"
|
||||
8. Tap "I got distracted" a third time
|
||||
9. Select "💭 Just zoned out"
|
||||
10. Let session complete
|
||||
|
||||
**Expected Results**:
|
||||
- ✅ SnackBar shows: "It happens. Let's gently come back."
|
||||
- ✅ Bottom sheet appears with 4 distraction types
|
||||
- ✅ Timer NEVER stops or pauses
|
||||
- ✅ Distraction counter updates
|
||||
- ✅ Session completes normally
|
||||
- ✅ Complete screen shows 3 distractions
|
||||
- ✅ All distraction types are recorded
|
||||
|
||||
**Critical Verification**: Timer must continue running throughout all distraction clicks.
|
||||
|
||||
**Actual Results**: [TO BE TESTED]
|
||||
|
||||
---
|
||||
|
||||
### Test 7: Focus Session - Stop Early
|
||||
**Objective**: Verify early stop with confirmation
|
||||
|
||||
**Steps**:
|
||||
1. Start a session
|
||||
2. After 2 minutes, tap "Stop session" button
|
||||
3. Observe confirmation dialog
|
||||
4. Tap "Yes, stop"
|
||||
5. Observe navigation to Complete screen
|
||||
|
||||
**Expected Results**:
|
||||
- ✅ Confirmation dialog appears
|
||||
- ✅ Dialog message: "Are you sure you want to stop this focus session early?"
|
||||
- ✅ Two buttons: "Yes, stop" and "No, continue"
|
||||
- ✅ "Yes, stop" saves partial session
|
||||
- ✅ Complete screen shows actual minutes (e.g., "2 minutes")
|
||||
- ✅ Session marked as incomplete
|
||||
|
||||
**Actual Results**: [TO BE TESTED]
|
||||
|
||||
---
|
||||
|
||||
### Test 8: Focus Session - Cancel Early Stop
|
||||
**Objective**: Verify "No, continue" returns to timer
|
||||
|
||||
**Steps**:
|
||||
1. Start a session
|
||||
2. Tap "Stop session"
|
||||
3. In confirmation dialog, tap "No, continue"
|
||||
|
||||
**Expected Results**:
|
||||
- ✅ Dialog closes
|
||||
- ✅ Timer continues from where it was
|
||||
- ✅ No session is saved
|
||||
|
||||
**Actual Results**: [TO BE TESTED]
|
||||
|
||||
---
|
||||
|
||||
### Test 9: Complete Screen - Statistics Display
|
||||
**Objective**: Verify post-session summary accuracy
|
||||
|
||||
**Steps**:
|
||||
1. Complete a 15-minute session with 3 distractions
|
||||
2. Observe Complete screen
|
||||
|
||||
**Expected Results**:
|
||||
- ✅ "You focused for" section shows "15 minutes"
|
||||
- ✅ "Today's Total" shows cumulative minutes
|
||||
- ✅ Distraction count displayed
|
||||
- ✅ Random encouragement message shown
|
||||
- ✅ "Start Another" button visible
|
||||
- ✅ "View History" button visible
|
||||
|
||||
**Actual Results**: [TO BE TESTED]
|
||||
|
||||
---
|
||||
|
||||
### Test 10: Complete Screen - Start Another Session
|
||||
**Objective**: Verify quick restart flow
|
||||
|
||||
**Steps**:
|
||||
1. From Complete screen, tap "Start Another"
|
||||
2. Observe navigation
|
||||
|
||||
**Expected Results**:
|
||||
- ✅ Navigates directly to Focus screen (not Home)
|
||||
- ✅ Timer starts with same duration
|
||||
- ✅ Previous session is saved
|
||||
|
||||
**Actual Results**: [TO BE TESTED]
|
||||
|
||||
---
|
||||
|
||||
### Test 11: History Screen - Empty State
|
||||
**Objective**: Verify first-time user experience
|
||||
|
||||
**Steps**:
|
||||
1. Clear all data (if needed: delete Hive box)
|
||||
2. Open History screen
|
||||
|
||||
**Expected Results**:
|
||||
- ✅ Empty state message: "No focus sessions yet"
|
||||
- ✅ Helper text: "Start your first session to see your progress here!"
|
||||
- ✅ "Start Focusing" button visible
|
||||
|
||||
**Actual Results**: [TO BE TESTED]
|
||||
|
||||
---
|
||||
|
||||
### Test 12: History Screen - Today's Summary
|
||||
**Objective**: Verify today's statistics accuracy
|
||||
|
||||
**Steps**:
|
||||
1. Complete 2 sessions:
|
||||
- Session 1: 15 mins, 3 distractions, completed
|
||||
- Session 2: 25 mins, 1 distraction, stopped early at 20 mins
|
||||
2. Open History screen
|
||||
3. Observe "📅 Today" summary card
|
||||
|
||||
**Expected Results**:
|
||||
- ✅ Total: 35 mins (15 + 20)
|
||||
- ✅ Distractions: 4 times (3 + 1)
|
||||
- ✅ Sessions badge: "2 sessions"
|
||||
- ✅ Summary card at top of screen
|
||||
|
||||
**Actual Results**: [TO BE TESTED]
|
||||
|
||||
---
|
||||
|
||||
### Test 13: History Screen - Session List
|
||||
**Objective**: Verify session detail display
|
||||
|
||||
**Steps**:
|
||||
1. After Test 12, scroll down in History screen
|
||||
2. Observe session list under "Today"
|
||||
|
||||
**Expected Results**:
|
||||
- ✅ Two session cards displayed
|
||||
- ✅ Each shows: time (HH:mm), duration, distraction count
|
||||
- ✅ Session 1: "✅ Completed" badge (green)
|
||||
- ✅ Session 2: "⏸️ Stopped early" badge (gray)
|
||||
- ✅ Newest session at top
|
||||
|
||||
**Actual Results**: [TO BE TESTED]
|
||||
|
||||
---
|
||||
|
||||
### Test 14: Data Persistence - App Reload
|
||||
**Objective**: Verify Hive database persists across sessions
|
||||
|
||||
**Steps**:
|
||||
1. Complete 2 focus sessions
|
||||
2. Change settings to 45 minutes
|
||||
3. Close browser tab (or hot restart: press 'R' in terminal)
|
||||
4. Reopen app
|
||||
5. Check History screen
|
||||
6. Check Home screen duration
|
||||
|
||||
**Expected Results**:
|
||||
- ✅ History shows all previous sessions
|
||||
- ✅ Today's total is correct
|
||||
- ✅ Settings duration is 45 minutes
|
||||
- ✅ No data loss
|
||||
|
||||
**Actual Results**: [TO BE TESTED]
|
||||
|
||||
---
|
||||
|
||||
### Test 15: Navigation Flow - Complete Journey
|
||||
**Objective**: Verify all navigation paths work
|
||||
|
||||
**Steps**:
|
||||
1. Home → Settings → Back to Home
|
||||
2. Home → History → Back to Home
|
||||
3. Home → Focus → Complete → View History → Back to Home
|
||||
4. Home → Focus → Complete → Start Another → Focus again
|
||||
|
||||
**Expected Results**:
|
||||
- ✅ All back buttons work
|
||||
- ✅ All forward navigations work
|
||||
- ✅ No navigation errors
|
||||
- ✅ State preserved correctly
|
||||
|
||||
**Actual Results**: [TO BE TESTED]
|
||||
|
||||
---
|
||||
|
||||
### Test 16: UI/UX - Color & Typography
|
||||
**Objective**: Verify design system implementation
|
||||
|
||||
**Visual Checks**:
|
||||
- ✅ Morandi color palette (calm greens, warm off-white)
|
||||
- ✅ Primary color: #A7C4BC visible in buttons
|
||||
- ✅ Background: #F8F6F2 (warm off-white)
|
||||
- ✅ Nunito font used (or fallback system font if not installed)
|
||||
- ✅ Consistent padding/spacing (24px)
|
||||
- ✅ Rounded corners (16px cards, 12px buttons)
|
||||
- ✅ Button height: 56px
|
||||
|
||||
**Actual Results**: [TO BE TESTED]
|
||||
|
||||
---
|
||||
|
||||
### Test 17: Responsive Design
|
||||
**Objective**: Verify app works at different viewport sizes
|
||||
|
||||
**Steps**:
|
||||
1. Browser: normal desktop size (1920x1080)
|
||||
2. Browser: narrow desktop (1024x768)
|
||||
3. Browser: tablet simulation (768x1024)
|
||||
4. Browser: mobile simulation (375x667)
|
||||
|
||||
**Expected Results**:
|
||||
- ✅ UI adapts to all sizes
|
||||
- ✅ No horizontal scrolling
|
||||
- ✅ Buttons remain accessible
|
||||
- ✅ Text remains readable
|
||||
|
||||
**Actual Results**: [TO BE TESTED]
|
||||
|
||||
---
|
||||
|
||||
### Test 18: Performance - Timer Accuracy
|
||||
**Objective**: Verify timer countdown is accurate
|
||||
|
||||
**Steps**:
|
||||
1. Start a 1-minute focus session (temporary modification)
|
||||
2. Use stopwatch on phone
|
||||
3. Compare when timer reaches 00:00
|
||||
|
||||
**Expected Results**:
|
||||
- ✅ Timer completes in exactly 60 seconds (±1 second tolerance)
|
||||
- ✅ UI updates every second
|
||||
- ✅ No freezing or stuttering
|
||||
|
||||
**Actual Results**: [TO BE TESTED]
|
||||
|
||||
---
|
||||
|
||||
### Test 19: Edge Cases - Multiple Distractions
|
||||
**Objective**: Verify app handles high distraction counts
|
||||
|
||||
**Steps**:
|
||||
1. Start a session
|
||||
2. Tap "I got distracted" 20 times rapidly
|
||||
3. Select different distraction types
|
||||
4. Complete session
|
||||
|
||||
**Expected Results**:
|
||||
- ✅ All 20 distractions recorded
|
||||
- ✅ No UI freeze
|
||||
- ✅ Complete screen shows correct count
|
||||
- ✅ History shows correct count
|
||||
|
||||
**Actual Results**: [TO BE TESTED]
|
||||
|
||||
---
|
||||
|
||||
### Test 20: Edge Cases - Zero Duration Sessions
|
||||
**Objective**: Verify app handles edge case
|
||||
|
||||
**Steps**:
|
||||
1. Start a session
|
||||
2. Immediately tap "Stop session"
|
||||
3. Confirm stop
|
||||
|
||||
**Expected Results**:
|
||||
- ✅ Session saves with 0 minutes
|
||||
- ✅ Complete screen shows "0 minutes" (or "Less than a minute")
|
||||
- ✅ History records session
|
||||
- ✅ No crash
|
||||
|
||||
**Actual Results**: [TO BE TESTED]
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Known Issues
|
||||
|
||||
### Critical Issues (Blocking Launch)
|
||||
*None identified yet - requires testing*
|
||||
|
||||
### High Priority Issues (Should fix before launch)
|
||||
*None identified yet - requires testing*
|
||||
|
||||
### Medium Priority Issues (Nice to fix)
|
||||
1. **Nunito Font Not Loaded**
|
||||
- **Impact**: Using system fallback fonts
|
||||
- **Fix**: Download Nunito fonts or use google_fonts package
|
||||
- **Workaround**: Acceptable for MVP, fonts load fine in production
|
||||
|
||||
### Low Priority Issues (Post-launch)
|
||||
1. **Windows Requires Developer Mode**
|
||||
- **Impact**: Cannot test Windows desktop version
|
||||
- **Fix**: Enable Developer Mode in Windows settings
|
||||
- **Workaround**: Test using Web and mobile platforms
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Visual Testing Checklist
|
||||
|
||||
### Home Screen
|
||||
- [ ] App title "FocusBuddy" is prominent
|
||||
- [ ] Duration display is in white rounded card
|
||||
- [ ] "Start Focusing" button is primary green color
|
||||
- [ ] Helper text is subtle gray color
|
||||
- [ ] Bottom navigation buttons are evenly spaced
|
||||
- [ ] Overall spacing feels balanced
|
||||
|
||||
### Settings Screen
|
||||
- [ ] Duration options have clear radio buttons
|
||||
- [ ] Selected option has green border
|
||||
- [ ] "Default" badge shows on 25 minutes
|
||||
- [ ] Privacy/About list items have arrow icons
|
||||
- [ ] Version number displays at bottom
|
||||
- [ ] Cards have subtle shadows
|
||||
|
||||
### Focus Screen
|
||||
- [ ] Timer display is very large (64px)
|
||||
- [ ] "I got distracted" button is not red/alarming
|
||||
- [ ] Pause/Resume button is clear
|
||||
- [ ] Stop button is less prominent
|
||||
- [ ] Distraction counter is visible but not intrusive
|
||||
- [ ] Overall feeling is calm, not stressful
|
||||
|
||||
### Complete Screen
|
||||
- [ ] Congratulatory feeling (success green)
|
||||
- [ ] Statistics are easy to read
|
||||
- [ ] Encouragement quote is emphasized
|
||||
- [ ] Call-to-action buttons are clear
|
||||
- [ ] Today's summary is informative
|
||||
|
||||
### History Screen
|
||||
- [ ] Today's summary card stands out
|
||||
- [ ] Session cards are scannable
|
||||
- [ ] Date grouping is clear
|
||||
- [ ] Empty state is friendly
|
||||
- [ ] Stats use appropriate emojis
|
||||
|
||||
### Distraction Bottom Sheet
|
||||
- [ ] All 4 types are listed
|
||||
- [ ] Emojis make types recognizable
|
||||
- [ ] Text is clear
|
||||
- [ ] Easy to dismiss
|
||||
|
||||
---
|
||||
|
||||
## 📊 Test Metrics
|
||||
|
||||
### Code Coverage
|
||||
- **Unit Tests**: Not implemented (MVP)
|
||||
- **Integration Tests**: Not implemented (MVP)
|
||||
- **Manual Tests**: 20 test cases defined
|
||||
|
||||
### Quality Gates
|
||||
- [ ] All P0 tests passing
|
||||
- [ ] No critical bugs
|
||||
- [ ] Data persistence working
|
||||
- [ ] UI matches design spec
|
||||
- [ ] Navigation flow complete
|
||||
|
||||
---
|
||||
|
||||
## ✅ Test Sign-off
|
||||
|
||||
### Testing Completed By
|
||||
**Name**: [To be filled]
|
||||
**Date**: [To be filled]
|
||||
**Environment**: Web (Edge), [other platforms]
|
||||
|
||||
### Issues Found
|
||||
- **Critical**: 0
|
||||
- **High**: 0
|
||||
- **Medium**: 0
|
||||
- **Low**: 0
|
||||
|
||||
### Recommendation
|
||||
- [ ] **Ready for Launch** - All tests passing
|
||||
- [ ] **Needs Fixes** - Critical/high issues found
|
||||
- [ ] **Needs Retesting** - Fixes implemented, retest required
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Hot Reload Testing
|
||||
|
||||
The app supports Flutter hot reload for rapid testing:
|
||||
|
||||
### Quick Commands (in terminal)
|
||||
- `r` - Hot reload (preserves app state)
|
||||
- `R` - Hot restart (resets app state)
|
||||
- `h` - List all commands
|
||||
- `c` - Clear console
|
||||
- `q` - Quit app
|
||||
|
||||
### Hot Reload Test
|
||||
1. Make a small UI change (e.g., change button text)
|
||||
2. Save file
|
||||
3. Press `r` in terminal
|
||||
4. Verify change appears in browser (2-3 seconds)
|
||||
|
||||
---
|
||||
|
||||
## 📱 Next Platform Testing
|
||||
|
||||
### Android Testing (Planned)
|
||||
1. Connect Android device or start emulator
|
||||
2. Run: `flutter devices`
|
||||
3. Run: `flutter run -d <android-device-id>`
|
||||
4. Repeat all 20 test cases
|
||||
5. Additional checks: back button, notifications, permissions
|
||||
|
||||
### iOS Testing (Planned)
|
||||
1. Open project in Xcode (macOS required)
|
||||
2. Configure signing
|
||||
3. Run: `flutter run -d <ios-device-id>`
|
||||
4. Repeat all 20 test cases
|
||||
5. Additional checks: gestures, notifications, privacy prompts
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Test Summary
|
||||
|
||||
**Current Status**: ✅ App running successfully in browser
|
||||
**Test Execution**: ⏳ Manual testing required
|
||||
**Recommendation**: Proceed with Test Cases 1-20 in sequence
|
||||
|
||||
**Estimated Testing Time**: 2-3 hours for complete test suite
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-11-22
|
||||
**Document Version**: 1.0
|
||||
@@ -1 +1,2 @@
|
||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
||||
43
ios/Podfile
Normal file
43
ios/Podfile
Normal file
@@ -0,0 +1,43 @@
|
||||
# Uncomment this line to define a global platform for your project
|
||||
# platform :ios, '13.0'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
project 'Runner', {
|
||||
'Debug' => :debug,
|
||||
'Profile' => :release,
|
||||
'Release' => :release,
|
||||
}
|
||||
|
||||
def flutter_root
|
||||
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
|
||||
unless File.exist?(generated_xcode_build_settings_path)
|
||||
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
||||
end
|
||||
|
||||
File.foreach(generated_xcode_build_settings_path) do |line|
|
||||
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
||||
return matches[1].strip if matches
|
||||
end
|
||||
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
|
||||
end
|
||||
|
||||
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
||||
|
||||
flutter_ios_podfile_setup
|
||||
|
||||
target 'Runner' do
|
||||
use_frameworks!
|
||||
|
||||
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
||||
target 'RunnerTests' do
|
||||
inherit! :search_paths
|
||||
end
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_ios_build_settings(target)
|
||||
end
|
||||
end
|
||||
35
ios/Podfile.lock
Normal file
35
ios/Podfile.lock
Normal file
@@ -0,0 +1,35 @@
|
||||
PODS:
|
||||
- Flutter (1.0.0)
|
||||
- flutter_local_notifications (0.0.1):
|
||||
- Flutter
|
||||
- objective_c (0.0.1):
|
||||
- Flutter
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
|
||||
DEPENDENCIES:
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
||||
- objective_c (from `.symlinks/plugins/objective_c/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
flutter_local_notifications:
|
||||
:path: ".symlinks/plugins/flutter_local_notifications/ios"
|
||||
objective_c:
|
||||
:path: ".symlinks/plugins/objective_c/ios"
|
||||
shared_preferences_foundation:
|
||||
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
|
||||
flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086
|
||||
objective_c: 77e887b5ba1827970907e10e832eec1683f3431d
|
||||
shared_preferences_foundation: 5086985c1d43c5ba4d5e69a4e8083a389e2909e6
|
||||
|
||||
PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
@@ -10,10 +10,12 @@
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
4F21DDA732CE5EA3FD4BD227 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8ECA8E3F2419A8BC809DE90 /* Pods_RunnerTests.framework */; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
FFCEB2D462F39BF41BAFCABE /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E276AD767481FD11C70B026 /* Pods_Runner.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -42,9 +44,14 @@
|
||||
/* Begin PBXFileReference section */
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||
2881EAAC21813692B4AC2F49 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
3E276AD767481FD11C70B026 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
415B4DBE2E2506ADAAAD1865 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
5D1A9F6676FCA54E97B916A0 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
676FCE9D693E27667F83610A /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
@@ -55,19 +62,40 @@
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
D381B0F26A7F11974654A2CE /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
F474F144AE4C782893810FC3 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
F8ECA8E3F2419A8BC809DE90 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
510C2968BD4F957E687C54CE /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4F21DDA732CE5EA3FD4BD227 /* Pods_RunnerTests.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
FFCEB2D462F39BF41BAFCABE /* Pods_Runner.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
01439B170118F84CA54C1FDC /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3E276AD767481FD11C70B026 /* Pods_Runner.framework */,
|
||||
F8ECA8E3F2419A8BC809DE90 /* Pods_RunnerTests.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
331C8082294A63A400263BE5 /* RunnerTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -94,6 +122,8 @@
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||
DFDA229EBBEF45AD064A13DF /* Pods */,
|
||||
01439B170118F84CA54C1FDC /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -121,6 +151,20 @@
|
||||
path = Runner;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DFDA229EBBEF45AD064A13DF /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D381B0F26A7F11974654A2CE /* Pods-Runner.debug.xcconfig */,
|
||||
2881EAAC21813692B4AC2F49 /* Pods-Runner.release.xcconfig */,
|
||||
415B4DBE2E2506ADAAAD1865 /* Pods-Runner.profile.xcconfig */,
|
||||
5D1A9F6676FCA54E97B916A0 /* Pods-RunnerTests.debug.xcconfig */,
|
||||
F474F144AE4C782893810FC3 /* Pods-RunnerTests.release.xcconfig */,
|
||||
676FCE9D693E27667F83610A /* Pods-RunnerTests.profile.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@@ -128,8 +172,10 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||
buildPhases = (
|
||||
97BC673F17C73E284DC59D4B /* [CP] Check Pods Manifest.lock */,
|
||||
331C807D294A63A400263BE5 /* Sources */,
|
||||
331C807F294A63A400263BE5 /* Resources */,
|
||||
510C2968BD4F957E687C54CE /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -145,12 +191,14 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
4ED45F3DF92002CC4B5E0221 /* [CP] Check Pods Manifest.lock */,
|
||||
9740EEB61CF901F6004384FC /* Run Script */,
|
||||
97C146EA1CF9000F007C117D /* Sources */,
|
||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||
97C146EC1CF9000F007C117D /* Resources */,
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
C5783D838864AB8D6AFB6900 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -238,6 +286,28 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||
};
|
||||
4ED45F3DF92002CC4B5E0221 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
@@ -253,6 +323,45 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||
};
|
||||
97BC673F17C73E284DC59D4B /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
C5783D838864AB8D6AFB6900 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
@@ -378,6 +487,7 @@
|
||||
};
|
||||
331C8088294A63A400263BE5 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 5D1A9F6676FCA54E97B916A0 /* Pods-RunnerTests.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
@@ -395,6 +505,7 @@
|
||||
};
|
||||
331C8089294A63A400263BE5 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = F474F144AE4C782893810FC3 /* Pods-RunnerTests.release.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
@@ -410,6 +521,7 @@
|
||||
};
|
||||
331C808A294A63A400263BE5 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 676FCE9D693E27667F83610A /* Pods-RunnerTests.profile.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
|
||||
3
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
3
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
@@ -4,4 +4,7 @@
|
||||
<FileRef
|
||||
location = "group:Runner.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
||||
@@ -146,13 +146,20 @@ class _FocusScreenState extends State<FocusScreen> {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
backgroundColor: AppColors.white,
|
||||
isScrollControlled: true,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
|
||||
),
|
||||
builder: (context) {
|
||||
return SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
padding: EdgeInsets.only(
|
||||
left: 24.0,
|
||||
right: 24.0,
|
||||
top: 24.0,
|
||||
bottom: 24.0 + MediaQuery.of(context).viewInsets.bottom,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -221,6 +228,7 @@ class _FocusScreenState extends State<FocusScreen> {
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -260,12 +268,16 @@ class _FocusScreenState extends State<FocusScreen> {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.background,
|
||||
body: SafeArea(
|
||||
child: Padding(
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Spacer(),
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.2,
|
||||
),
|
||||
|
||||
// Timer Display
|
||||
Text(
|
||||
@@ -336,10 +348,18 @@ class _FocusScreenState extends State<FocusScreen> {
|
||||
),
|
||||
),
|
||||
|
||||
const Spacer(),
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.2,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Stop Button (text button at bottom)
|
||||
TextButton(
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 24.0),
|
||||
child: TextButton(
|
||||
onPressed: _stopEarly,
|
||||
child: const Text(
|
||||
'Stop session',
|
||||
@@ -349,8 +369,8 @@ class _FocusScreenState extends State<FocusScreen> {
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||
#include "ephemeral/Flutter-Generated.xcconfig"
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||
#include "ephemeral/Flutter-Generated.xcconfig"
|
||||
|
||||
42
macos/Podfile
Normal file
42
macos/Podfile
Normal file
@@ -0,0 +1,42 @@
|
||||
platform :osx, '10.15'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
project 'Runner', {
|
||||
'Debug' => :debug,
|
||||
'Profile' => :release,
|
||||
'Release' => :release,
|
||||
}
|
||||
|
||||
def flutter_root
|
||||
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
|
||||
unless File.exist?(generated_xcode_build_settings_path)
|
||||
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
|
||||
end
|
||||
|
||||
File.foreach(generated_xcode_build_settings_path) do |line|
|
||||
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
||||
return matches[1].strip if matches
|
||||
end
|
||||
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
|
||||
end
|
||||
|
||||
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
||||
|
||||
flutter_macos_podfile_setup
|
||||
|
||||
target 'Runner' do
|
||||
use_frameworks!
|
||||
|
||||
flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
|
||||
target 'RunnerTests' do
|
||||
inherit! :search_paths
|
||||
end
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_macos_build_settings(target)
|
||||
end
|
||||
end
|
||||
35
macos/Podfile.lock
Normal file
35
macos/Podfile.lock
Normal file
@@ -0,0 +1,35 @@
|
||||
PODS:
|
||||
- flutter_local_notifications (0.0.1):
|
||||
- FlutterMacOS
|
||||
- FlutterMacOS (1.0.0)
|
||||
- objective_c (0.0.1):
|
||||
- FlutterMacOS
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
|
||||
DEPENDENCIES:
|
||||
- flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`)
|
||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||
- objective_c (from `Flutter/ephemeral/.symlinks/plugins/objective_c/macos`)
|
||||
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
flutter_local_notifications:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos
|
||||
FlutterMacOS:
|
||||
:path: Flutter/ephemeral
|
||||
objective_c:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/objective_c/macos
|
||||
shared_preferences_foundation:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
flutter_local_notifications: 4b427ffabf278fc6ea9484c97505e231166927a5
|
||||
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
|
||||
objective_c: e5f8194456e8fc943e034d1af00510a1bc29c067
|
||||
shared_preferences_foundation: 5086985c1d43c5ba4d5e69a4e8083a389e2909e6
|
||||
|
||||
PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
@@ -21,12 +21,14 @@
|
||||
/* End PBXAggregateTarget section */
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
12DDB076302A62DE195F7F77 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E332783FE90BB2B8120EEE3 /* Pods_RunnerTests.framework */; };
|
||||
331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; };
|
||||
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
|
||||
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
|
||||
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
|
||||
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
|
||||
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
|
||||
5188293C12144F78779A8C31 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF0133E3EB04D8BDDA6B3049 /* Pods_Runner.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -60,11 +62,12 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
207D36439035889740B9108F /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
|
||||
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
|
||||
33CC10ED2044A3C60003C045 /* focus_buddy.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "focus_buddy.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
33CC10ED2044A3C60003C045 /* focus_buddy.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = focus_buddy.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
|
||||
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||
@@ -76,8 +79,15 @@
|
||||
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
|
||||
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
|
||||
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
|
||||
5D2FB4A0DFBEFD6DB1B945E7 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
5E332783FE90BB2B8120EEE3 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
|
||||
B1DDCC2184A080B42C34C6A0 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
D91D5683968BC068A4DB7036 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
DA80A10E8BEAB07C4D0F6C0A /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
E5BD3EA4A8FE454CBEAC804E /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
FF0133E3EB04D8BDDA6B3049 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -85,6 +95,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
12DDB076302A62DE195F7F77 /* Pods_RunnerTests.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -92,12 +103,27 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5188293C12144F78779A8C31 /* Pods_Runner.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
08D24E5EE93115F48655C185 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DA80A10E8BEAB07C4D0F6C0A /* Pods-Runner.debug.xcconfig */,
|
||||
207D36439035889740B9108F /* Pods-Runner.release.xcconfig */,
|
||||
5D2FB4A0DFBEFD6DB1B945E7 /* Pods-Runner.profile.xcconfig */,
|
||||
D91D5683968BC068A4DB7036 /* Pods-RunnerTests.debug.xcconfig */,
|
||||
B1DDCC2184A080B42C34C6A0 /* Pods-RunnerTests.release.xcconfig */,
|
||||
E5BD3EA4A8FE454CBEAC804E /* Pods-RunnerTests.profile.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
331C80D6294CF71000263BE5 /* RunnerTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -125,6 +151,7 @@
|
||||
331C80D6294CF71000263BE5 /* RunnerTests */,
|
||||
33CC10EE2044A3C60003C045 /* Products */,
|
||||
D73912EC22F37F3D000D13A0 /* Frameworks */,
|
||||
08D24E5EE93115F48655C185 /* Pods */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -175,6 +202,8 @@
|
||||
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FF0133E3EB04D8BDDA6B3049 /* Pods_Runner.framework */,
|
||||
5E332783FE90BB2B8120EEE3 /* Pods_RunnerTests.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
@@ -186,6 +215,7 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||
buildPhases = (
|
||||
ABA4769891F909893C38B75F /* [CP] Check Pods Manifest.lock */,
|
||||
331C80D1294CF70F00263BE5 /* Sources */,
|
||||
331C80D2294CF70F00263BE5 /* Frameworks */,
|
||||
331C80D3294CF70F00263BE5 /* Resources */,
|
||||
@@ -204,11 +234,13 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
32C93CD8F3D0D706DC5ADA5B /* [CP] Check Pods Manifest.lock */,
|
||||
33CC10E92044A3C60003C045 /* Sources */,
|
||||
33CC10EA2044A3C60003C045 /* Frameworks */,
|
||||
33CC10EB2044A3C60003C045 /* Resources */,
|
||||
33CC110E2044A8840003C045 /* Bundle Framework */,
|
||||
3399D490228B24CF009A79C7 /* ShellScript */,
|
||||
188537C08472C94556A10B01 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -291,6 +323,45 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
188537C08472C94556A10B01 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
32C93CD8F3D0D706DC5ADA5B /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
3399D490228B24CF009A79C7 /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
@@ -329,6 +400,28 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
|
||||
};
|
||||
ABA4769891F909893C38B75F /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
@@ -380,6 +473,7 @@
|
||||
/* Begin XCBuildConfiguration section */
|
||||
331C80DB294CF71000263BE5 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = D91D5683968BC068A4DB7036 /* Pods-RunnerTests.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
@@ -394,6 +488,7 @@
|
||||
};
|
||||
331C80DC294CF71000263BE5 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = B1DDCC2184A080B42C34C6A0 /* Pods-RunnerTests.release.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
@@ -408,6 +503,7 @@
|
||||
};
|
||||
331C80DD294CF71000263BE5 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = E5BD3EA4A8FE454CBEAC804E /* Pods-RunnerTests.profile.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
|
||||
@@ -4,4 +4,7 @@
|
||||
<FileRef
|
||||
location = "group:Runner.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
||||
198
pubspec.lock
198
pubspec.lock
@@ -6,7 +6,7 @@ packages:
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "67.0.0"
|
||||
analyzer:
|
||||
@@ -14,7 +14,7 @@ packages:
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.4.1"
|
||||
args:
|
||||
@@ -22,7 +22,7 @@ packages:
|
||||
description:
|
||||
name: args
|
||||
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.7.0"
|
||||
async:
|
||||
@@ -30,7 +30,7 @@ packages:
|
||||
description:
|
||||
name: async
|
||||
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.13.0"
|
||||
boolean_selector:
|
||||
@@ -38,7 +38,7 @@ packages:
|
||||
description:
|
||||
name: boolean_selector
|
||||
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
build:
|
||||
@@ -46,7 +46,7 @@ packages:
|
||||
description:
|
||||
name: build
|
||||
sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
build_config:
|
||||
@@ -54,7 +54,7 @@ packages:
|
||||
description:
|
||||
name: build_config
|
||||
sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
build_daemon:
|
||||
@@ -62,7 +62,7 @@ packages:
|
||||
description:
|
||||
name: build_daemon
|
||||
sha256: bf05f6e12cfea92d3c09308d7bcdab1906cd8a179b023269eed00c071004b957
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.1"
|
||||
build_resolvers:
|
||||
@@ -70,7 +70,7 @@ packages:
|
||||
description:
|
||||
name: build_resolvers
|
||||
sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.2"
|
||||
build_runner:
|
||||
@@ -78,7 +78,7 @@ packages:
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.13"
|
||||
build_runner_core:
|
||||
@@ -86,7 +86,7 @@ packages:
|
||||
description:
|
||||
name: build_runner_core
|
||||
sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.3.2"
|
||||
built_collection:
|
||||
@@ -94,7 +94,7 @@ packages:
|
||||
description:
|
||||
name: built_collection
|
||||
sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.1"
|
||||
built_value:
|
||||
@@ -102,7 +102,7 @@ packages:
|
||||
description:
|
||||
name: built_value
|
||||
sha256: "426cf75afdb23aa74bd4e471704de3f9393f3c7b04c1e2d9c6f1073ae0b8b139"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.12.1"
|
||||
characters:
|
||||
@@ -110,7 +110,7 @@ packages:
|
||||
description:
|
||||
name: characters
|
||||
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
checked_yaml:
|
||||
@@ -118,7 +118,7 @@ packages:
|
||||
description:
|
||||
name: checked_yaml
|
||||
sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.4"
|
||||
clock:
|
||||
@@ -126,7 +126,7 @@ packages:
|
||||
description:
|
||||
name: clock
|
||||
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
code_builder:
|
||||
@@ -134,7 +134,7 @@ packages:
|
||||
description:
|
||||
name: code_builder
|
||||
sha256: "11654819532ba94c34de52ff5feb52bd81cba1de00ef2ed622fd50295f9d4243"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.11.0"
|
||||
collection:
|
||||
@@ -142,7 +142,7 @@ packages:
|
||||
description:
|
||||
name: collection
|
||||
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.19.1"
|
||||
convert:
|
||||
@@ -150,7 +150,7 @@ packages:
|
||||
description:
|
||||
name: convert
|
||||
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
crypto:
|
||||
@@ -158,7 +158,7 @@ packages:
|
||||
description:
|
||||
name: crypto
|
||||
sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.7"
|
||||
cupertino_icons:
|
||||
@@ -166,7 +166,7 @@ packages:
|
||||
description:
|
||||
name: cupertino_icons
|
||||
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.8"
|
||||
dart_style:
|
||||
@@ -174,7 +174,7 @@ packages:
|
||||
description:
|
||||
name: dart_style
|
||||
sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.6"
|
||||
dbus:
|
||||
@@ -182,7 +182,7 @@ packages:
|
||||
description:
|
||||
name: dbus
|
||||
sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.11"
|
||||
fake_async:
|
||||
@@ -190,7 +190,7 @@ packages:
|
||||
description:
|
||||
name: fake_async
|
||||
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.3"
|
||||
ffi:
|
||||
@@ -198,7 +198,7 @@ packages:
|
||||
description:
|
||||
name: ffi
|
||||
sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
file:
|
||||
@@ -206,7 +206,7 @@ packages:
|
||||
description:
|
||||
name: file
|
||||
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.1"
|
||||
fixnum:
|
||||
@@ -214,7 +214,7 @@ packages:
|
||||
description:
|
||||
name: fixnum
|
||||
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
flutter:
|
||||
@@ -227,7 +227,7 @@ packages:
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.0"
|
||||
flutter_local_notifications:
|
||||
@@ -235,7 +235,7 @@ packages:
|
||||
description:
|
||||
name: flutter_local_notifications
|
||||
sha256: "674173fd3c9eda9d4c8528da2ce0ea69f161577495a9cc835a2a4ecd7eadeb35"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "17.2.4"
|
||||
flutter_local_notifications_linux:
|
||||
@@ -243,7 +243,7 @@ packages:
|
||||
description:
|
||||
name: flutter_local_notifications_linux
|
||||
sha256: c49bd06165cad9beeb79090b18cd1eb0296f4bf4b23b84426e37dd7c027fc3af
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.1"
|
||||
flutter_local_notifications_platform_interface:
|
||||
@@ -251,7 +251,7 @@ packages:
|
||||
description:
|
||||
name: flutter_local_notifications_platform_interface
|
||||
sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.2.0"
|
||||
flutter_test:
|
||||
@@ -269,7 +269,7 @@ packages:
|
||||
description:
|
||||
name: frontend_server_client
|
||||
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
glob:
|
||||
@@ -277,7 +277,7 @@ packages:
|
||||
description:
|
||||
name: glob
|
||||
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
google_fonts:
|
||||
@@ -285,7 +285,7 @@ packages:
|
||||
description:
|
||||
name: google_fonts
|
||||
sha256: "517b20870220c48752eafa0ba1a797a092fb22df0d89535fd9991e86ee2cdd9c"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.2"
|
||||
graphs:
|
||||
@@ -293,7 +293,7 @@ packages:
|
||||
description:
|
||||
name: graphs
|
||||
sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
hive:
|
||||
@@ -301,7 +301,7 @@ packages:
|
||||
description:
|
||||
name: hive
|
||||
sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.3"
|
||||
hive_flutter:
|
||||
@@ -309,7 +309,7 @@ packages:
|
||||
description:
|
||||
name: hive_flutter
|
||||
sha256: dca1da446b1d808a51689fb5d0c6c9510c0a2ba01e22805d492c73b68e33eecc
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
hive_generator:
|
||||
@@ -317,7 +317,7 @@ packages:
|
||||
description:
|
||||
name: hive_generator
|
||||
sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
http:
|
||||
@@ -325,7 +325,7 @@ packages:
|
||||
description:
|
||||
name: http
|
||||
sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.6.0"
|
||||
http_multi_server:
|
||||
@@ -333,7 +333,7 @@ packages:
|
||||
description:
|
||||
name: http_multi_server
|
||||
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.2"
|
||||
http_parser:
|
||||
@@ -341,7 +341,7 @@ packages:
|
||||
description:
|
||||
name: http_parser
|
||||
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.2"
|
||||
intl:
|
||||
@@ -349,7 +349,7 @@ packages:
|
||||
description:
|
||||
name: intl
|
||||
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.19.0"
|
||||
io:
|
||||
@@ -357,7 +357,7 @@ packages:
|
||||
description:
|
||||
name: io
|
||||
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
js:
|
||||
@@ -365,7 +365,7 @@ packages:
|
||||
description:
|
||||
name: js
|
||||
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.2"
|
||||
json_annotation:
|
||||
@@ -373,7 +373,7 @@ packages:
|
||||
description:
|
||||
name: json_annotation
|
||||
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.9.0"
|
||||
leak_tracker:
|
||||
@@ -381,7 +381,7 @@ packages:
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "11.0.2"
|
||||
leak_tracker_flutter_testing:
|
||||
@@ -389,7 +389,7 @@ packages:
|
||||
description:
|
||||
name: leak_tracker_flutter_testing
|
||||
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.10"
|
||||
leak_tracker_testing:
|
||||
@@ -397,7 +397,7 @@ packages:
|
||||
description:
|
||||
name: leak_tracker_testing
|
||||
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
lints:
|
||||
@@ -405,7 +405,7 @@ packages:
|
||||
description:
|
||||
name: lints
|
||||
sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.0"
|
||||
logging:
|
||||
@@ -413,7 +413,7 @@ packages:
|
||||
description:
|
||||
name: logging
|
||||
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
matcher:
|
||||
@@ -421,7 +421,7 @@ packages:
|
||||
description:
|
||||
name: matcher
|
||||
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.17"
|
||||
material_color_utilities:
|
||||
@@ -429,7 +429,7 @@ packages:
|
||||
description:
|
||||
name: material_color_utilities
|
||||
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.11.1"
|
||||
meta:
|
||||
@@ -437,7 +437,7 @@ packages:
|
||||
description:
|
||||
name: meta
|
||||
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.17.0"
|
||||
mime:
|
||||
@@ -445,7 +445,7 @@ packages:
|
||||
description:
|
||||
name: mime
|
||||
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
objective_c:
|
||||
@@ -453,7 +453,7 @@ packages:
|
||||
description:
|
||||
name: objective_c
|
||||
sha256: "1f81ed9e41909d44162d7ec8663b2c647c202317cc0b56d3d56f6a13146a0b64"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.1.0"
|
||||
package_config:
|
||||
@@ -461,7 +461,7 @@ packages:
|
||||
description:
|
||||
name: package_config
|
||||
sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
path:
|
||||
@@ -469,7 +469,7 @@ packages:
|
||||
description:
|
||||
name: path
|
||||
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.1"
|
||||
path_provider:
|
||||
@@ -477,7 +477,7 @@ packages:
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.5"
|
||||
path_provider_android:
|
||||
@@ -485,7 +485,7 @@ packages:
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.22"
|
||||
path_provider_foundation:
|
||||
@@ -493,7 +493,7 @@ packages:
|
||||
description:
|
||||
name: path_provider_foundation
|
||||
sha256: "6192e477f34018ef1ea790c56fffc7302e3bc3efede9e798b934c252c8c105ba"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.0"
|
||||
path_provider_linux:
|
||||
@@ -501,7 +501,7 @@ packages:
|
||||
description:
|
||||
name: path_provider_linux
|
||||
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
path_provider_platform_interface:
|
||||
@@ -509,7 +509,7 @@ packages:
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
path_provider_windows:
|
||||
@@ -517,7 +517,7 @@ packages:
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
petitparser:
|
||||
@@ -525,7 +525,7 @@ packages:
|
||||
description:
|
||||
name: petitparser
|
||||
sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.1"
|
||||
platform:
|
||||
@@ -533,7 +533,7 @@ packages:
|
||||
description:
|
||||
name: platform
|
||||
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.6"
|
||||
plugin_platform_interface:
|
||||
@@ -541,7 +541,7 @@ packages:
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.8"
|
||||
pool:
|
||||
@@ -549,7 +549,7 @@ packages:
|
||||
description:
|
||||
name: pool
|
||||
sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.2"
|
||||
pub_semver:
|
||||
@@ -557,7 +557,7 @@ packages:
|
||||
description:
|
||||
name: pub_semver
|
||||
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
pubspec_parse:
|
||||
@@ -565,7 +565,7 @@ packages:
|
||||
description:
|
||||
name: pubspec_parse
|
||||
sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.0"
|
||||
shared_preferences:
|
||||
@@ -573,7 +573,7 @@ packages:
|
||||
description:
|
||||
name: shared_preferences
|
||||
sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.3"
|
||||
shared_preferences_android:
|
||||
@@ -581,7 +581,7 @@ packages:
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: "46a46fd64659eff15f4638bbe19de43f9483f0e0bf024a9fb6b3582064bacc7b"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.17"
|
||||
shared_preferences_foundation:
|
||||
@@ -589,7 +589,7 @@ packages:
|
||||
description:
|
||||
name: shared_preferences_foundation
|
||||
sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.6"
|
||||
shared_preferences_linux:
|
||||
@@ -597,7 +597,7 @@ packages:
|
||||
description:
|
||||
name: shared_preferences_linux
|
||||
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shared_preferences_platform_interface:
|
||||
@@ -605,7 +605,7 @@ packages:
|
||||
description:
|
||||
name: shared_preferences_platform_interface
|
||||
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shared_preferences_web:
|
||||
@@ -613,7 +613,7 @@ packages:
|
||||
description:
|
||||
name: shared_preferences_web
|
||||
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.3"
|
||||
shared_preferences_windows:
|
||||
@@ -621,7 +621,7 @@ packages:
|
||||
description:
|
||||
name: shared_preferences_windows
|
||||
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shelf:
|
||||
@@ -629,7 +629,7 @@ packages:
|
||||
description:
|
||||
name: shelf
|
||||
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.2"
|
||||
shelf_web_socket:
|
||||
@@ -637,7 +637,7 @@ packages:
|
||||
description:
|
||||
name: shelf_web_socket
|
||||
sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
sky_engine:
|
||||
@@ -650,7 +650,7 @@ packages:
|
||||
description:
|
||||
name: source_gen
|
||||
sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.0"
|
||||
source_helper:
|
||||
@@ -658,7 +658,7 @@ packages:
|
||||
description:
|
||||
name: source_helper
|
||||
sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.5"
|
||||
source_span:
|
||||
@@ -666,7 +666,7 @@ packages:
|
||||
description:
|
||||
name: source_span
|
||||
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.10.1"
|
||||
stack_trace:
|
||||
@@ -674,7 +674,7 @@ packages:
|
||||
description:
|
||||
name: stack_trace
|
||||
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.12.1"
|
||||
stream_channel:
|
||||
@@ -682,7 +682,7 @@ packages:
|
||||
description:
|
||||
name: stream_channel
|
||||
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
stream_transform:
|
||||
@@ -690,7 +690,7 @@ packages:
|
||||
description:
|
||||
name: stream_transform
|
||||
sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
string_scanner:
|
||||
@@ -698,7 +698,7 @@ packages:
|
||||
description:
|
||||
name: string_scanner
|
||||
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.1"
|
||||
term_glyph:
|
||||
@@ -706,7 +706,7 @@ packages:
|
||||
description:
|
||||
name: term_glyph
|
||||
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.2"
|
||||
test_api:
|
||||
@@ -714,7 +714,7 @@ packages:
|
||||
description:
|
||||
name: test_api
|
||||
sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.7"
|
||||
timezone:
|
||||
@@ -722,7 +722,7 @@ packages:
|
||||
description:
|
||||
name: timezone
|
||||
sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.4"
|
||||
timing:
|
||||
@@ -730,7 +730,7 @@ packages:
|
||||
description:
|
||||
name: timing
|
||||
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
typed_data:
|
||||
@@ -738,7 +738,7 @@ packages:
|
||||
description:
|
||||
name: typed_data
|
||||
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
vector_math:
|
||||
@@ -746,7 +746,7 @@ packages:
|
||||
description:
|
||||
name: vector_math
|
||||
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
vm_service:
|
||||
@@ -754,7 +754,7 @@ packages:
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "15.0.2"
|
||||
watcher:
|
||||
@@ -762,7 +762,7 @@ packages:
|
||||
description:
|
||||
name: watcher
|
||||
sha256: "592ab6e2892f67760543fb712ff0177f4ec76c031f02f5b4ff8d3fc5eb9fb61a"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.4"
|
||||
web:
|
||||
@@ -770,7 +770,7 @@ packages:
|
||||
description:
|
||||
name: web
|
||||
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
web_socket:
|
||||
@@ -778,7 +778,7 @@ packages:
|
||||
description:
|
||||
name: web_socket
|
||||
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
web_socket_channel:
|
||||
@@ -786,7 +786,7 @@ packages:
|
||||
description:
|
||||
name: web_socket_channel
|
||||
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
xdg_directories:
|
||||
@@ -794,7 +794,7 @@ packages:
|
||||
description:
|
||||
name: xdg_directories
|
||||
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
xml:
|
||||
@@ -802,7 +802,7 @@ packages:
|
||||
description:
|
||||
name: xml
|
||||
sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.6.1"
|
||||
yaml:
|
||||
@@ -810,7 +810,7 @@ packages:
|
||||
description:
|
||||
name: yaml
|
||||
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.3"
|
||||
sdks:
|
||||
|
||||
Reference in New Issue
Block a user