This commit is contained in:
袁天才
2025-11-23 21:00:47 +08:00
parent 133941ed6a
commit 8c61688a26
25 changed files with 2068 additions and 4546 deletions

View File

@@ -10,7 +10,25 @@
"Bash(timeout:*)", "Bash(timeout:*)",
"Bash(nul)", "Bash(nul)",
"Bash(start \"\" \"f:\\cursor-auto\\focusBuddy\\icon-preview.html\")", "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": [], "deny": [],
"ask": [] "ask": []

View File

@@ -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 构建现在应该可以正常工作

View File

@@ -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" 按钮现在是否正常工作。** 🎉

View File

@@ -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 Screen3个时长选项
- [ ] 添加本地通知(计时完成提醒)
- [ ] 真机测试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` 查看效果!

View File

@@ -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
View 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
```

View File

@@ -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

View File

@@ -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) 了解更多测试指南。

View File

@@ -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)

View File

@@ -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!** 🎉

View File

@@ -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

View File

@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig" #include "Generated.xcconfig"

View File

@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig" #include "Generated.xcconfig"

43
ios/Podfile Normal file
View 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
View 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

View File

@@ -10,10 +10,12 @@
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 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 */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 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 */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@@ -42,9 +44,14 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; }; 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>"; }; 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>"; }; 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; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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 */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
510C2968BD4F957E687C54CE /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
4F21DDA732CE5EA3FD4BD227 /* Pods_RunnerTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EB1CF9000F007C117D /* Frameworks */ = { 97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
FFCEB2D462F39BF41BAFCABE /* Pods_Runner.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
01439B170118F84CA54C1FDC /* Frameworks */ = {
isa = PBXGroup;
children = (
3E276AD767481FD11C70B026 /* Pods_Runner.framework */,
F8ECA8E3F2419A8BC809DE90 /* Pods_RunnerTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
331C8082294A63A400263BE5 /* RunnerTests */ = { 331C8082294A63A400263BE5 /* RunnerTests */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -94,6 +122,8 @@
97C146F01CF9000F007C117D /* Runner */, 97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */, 97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */, 331C8082294A63A400263BE5 /* RunnerTests */,
DFDA229EBBEF45AD064A13DF /* Pods */,
01439B170118F84CA54C1FDC /* Frameworks */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
}; };
@@ -121,6 +151,20 @@
path = Runner; path = Runner;
sourceTree = "<group>"; 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 */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
@@ -128,8 +172,10 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = ( buildPhases = (
97BC673F17C73E284DC59D4B /* [CP] Check Pods Manifest.lock */,
331C807D294A63A400263BE5 /* Sources */, 331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */, 331C807F294A63A400263BE5 /* Resources */,
510C2968BD4F957E687C54CE /* Frameworks */,
); );
buildRules = ( buildRules = (
); );
@@ -145,12 +191,14 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = ( buildPhases = (
4ED45F3DF92002CC4B5E0221 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */, 9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */, 97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */, 97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */, 97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */, 9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
C5783D838864AB8D6AFB6900 /* [CP] Embed Pods Frameworks */,
); );
buildRules = ( buildRules = (
); );
@@ -238,6 +286,28 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 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 */ = { 9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1; alwaysOutOfDate = 1;
@@ -253,6 +323,45 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 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 */ /* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
@@ -378,6 +487,7 @@
}; };
331C8088294A63A400263BE5 /* Debug */ = { 331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 5D1A9F6676FCA54E97B916A0 /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
@@ -395,6 +505,7 @@
}; };
331C8089294A63A400263BE5 /* Release */ = { 331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = F474F144AE4C782893810FC3 /* Pods-RunnerTests.release.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
@@ -410,6 +521,7 @@
}; };
331C808A294A63A400263BE5 /* Profile */ = { 331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 676FCE9D693E27667F83610A /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;

View File

@@ -4,4 +4,7 @@
<FileRef <FileRef
location = "group:Runner.xcodeproj"> location = "group:Runner.xcodeproj">
</FileRef> </FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace> </Workspace>

View File

@@ -146,13 +146,20 @@ class _FocusScreenState extends State<FocusScreen> {
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
backgroundColor: AppColors.white, backgroundColor: AppColors.white,
isScrollControlled: true,
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(24)), borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
), ),
builder: (context) { builder: (context) {
return SafeArea( return SafeArea(
child: SingleChildScrollView(
child: Padding( 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( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@@ -221,6 +228,7 @@ class _FocusScreenState extends State<FocusScreen> {
], ],
), ),
), ),
),
); );
}, },
); );
@@ -260,12 +268,16 @@ class _FocusScreenState extends State<FocusScreen> {
return Scaffold( return Scaffold(
backgroundColor: AppColors.background, backgroundColor: AppColors.background,
body: SafeArea( body: SafeArea(
child: Padding( child: Column(
children: [
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.all(24.0), padding: const EdgeInsets.all(24.0),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
const Spacer(), SizedBox(
height: MediaQuery.of(context).size.height * 0.2,
),
// Timer Display // Timer Display
Text( 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) // Stop Button (text button at bottom)
TextButton( Padding(
padding: const EdgeInsets.only(bottom: 24.0),
child: TextButton(
onPressed: _stopEarly, onPressed: _stopEarly,
child: const Text( child: const Text(
'Stop session', 'Stop session',
@@ -349,8 +369,8 @@ class _FocusScreenState extends State<FocusScreen> {
), ),
), ),
), ),
],
), ),
],
), ),
), ),
); );

View File

@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig"

View File

@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig"

42
macos/Podfile Normal file
View 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
View 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

View File

@@ -21,12 +21,14 @@
/* End PBXAggregateTarget section */ /* End PBXAggregateTarget section */
/* Begin PBXBuildFile 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 */; }; 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; };
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; 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 */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@@ -60,11 +62,12 @@
/* End PBXCopyFilesBuildPhase section */ /* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference 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; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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 */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@@ -85,6 +95,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
12DDB076302A62DE195F7F77 /* Pods_RunnerTests.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -92,12 +103,27 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
5188293C12144F78779A8C31 /* Pods_Runner.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup 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 */ = { 331C80D6294CF71000263BE5 /* RunnerTests */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -125,6 +151,7 @@
331C80D6294CF71000263BE5 /* RunnerTests */, 331C80D6294CF71000263BE5 /* RunnerTests */,
33CC10EE2044A3C60003C045 /* Products */, 33CC10EE2044A3C60003C045 /* Products */,
D73912EC22F37F3D000D13A0 /* Frameworks */, D73912EC22F37F3D000D13A0 /* Frameworks */,
08D24E5EE93115F48655C185 /* Pods */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
}; };
@@ -175,6 +202,8 @@
D73912EC22F37F3D000D13A0 /* Frameworks */ = { D73912EC22F37F3D000D13A0 /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
FF0133E3EB04D8BDDA6B3049 /* Pods_Runner.framework */,
5E332783FE90BB2B8120EEE3 /* Pods_RunnerTests.framework */,
); );
name = Frameworks; name = Frameworks;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -186,6 +215,7 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = ( buildPhases = (
ABA4769891F909893C38B75F /* [CP] Check Pods Manifest.lock */,
331C80D1294CF70F00263BE5 /* Sources */, 331C80D1294CF70F00263BE5 /* Sources */,
331C80D2294CF70F00263BE5 /* Frameworks */, 331C80D2294CF70F00263BE5 /* Frameworks */,
331C80D3294CF70F00263BE5 /* Resources */, 331C80D3294CF70F00263BE5 /* Resources */,
@@ -204,11 +234,13 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = ( buildPhases = (
32C93CD8F3D0D706DC5ADA5B /* [CP] Check Pods Manifest.lock */,
33CC10E92044A3C60003C045 /* Sources */, 33CC10E92044A3C60003C045 /* Sources */,
33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EA2044A3C60003C045 /* Frameworks */,
33CC10EB2044A3C60003C045 /* Resources */, 33CC10EB2044A3C60003C045 /* Resources */,
33CC110E2044A8840003C045 /* Bundle Framework */, 33CC110E2044A8840003C045 /* Bundle Framework */,
3399D490228B24CF009A79C7 /* ShellScript */, 3399D490228B24CF009A79C7 /* ShellScript */,
188537C08472C94556A10B01 /* [CP] Embed Pods Frameworks */,
); );
buildRules = ( buildRules = (
); );
@@ -291,6 +323,45 @@
/* End PBXResourcesBuildPhase section */ /* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase 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 */ = { 3399D490228B24CF009A79C7 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1; alwaysOutOfDate = 1;
@@ -329,6 +400,28 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; 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 */ /* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
@@ -380,6 +473,7 @@
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
331C80DB294CF71000263BE5 /* Debug */ = { 331C80DB294CF71000263BE5 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = D91D5683968BC068A4DB7036 /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
@@ -394,6 +488,7 @@
}; };
331C80DC294CF71000263BE5 /* Release */ = { 331C80DC294CF71000263BE5 /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = B1DDCC2184A080B42C34C6A0 /* Pods-RunnerTests.release.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
@@ -408,6 +503,7 @@
}; };
331C80DD294CF71000263BE5 /* Profile */ = { 331C80DD294CF71000263BE5 /* Profile */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = E5BD3EA4A8FE454CBEAC804E /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;

View File

@@ -4,4 +4,7 @@
<FileRef <FileRef
location = "group:Runner.xcodeproj"> location = "group:Runner.xcodeproj">
</FileRef> </FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace> </Workspace>

View File

@@ -6,7 +6,7 @@ packages:
description: description:
name: _fe_analyzer_shared name: _fe_analyzer_shared
sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "67.0.0" version: "67.0.0"
analyzer: analyzer:
@@ -14,7 +14,7 @@ packages:
description: description:
name: analyzer name: analyzer
sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "6.4.1" version: "6.4.1"
args: args:
@@ -22,7 +22,7 @@ packages:
description: description:
name: args name: args
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.7.0" version: "2.7.0"
async: async:
@@ -30,7 +30,7 @@ packages:
description: description:
name: async name: async
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.13.0" version: "2.13.0"
boolean_selector: boolean_selector:
@@ -38,7 +38,7 @@ packages:
description: description:
name: boolean_selector name: boolean_selector
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.2" version: "2.1.2"
build: build:
@@ -46,7 +46,7 @@ packages:
description: description:
name: build name: build
sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.1" version: "2.4.1"
build_config: build_config:
@@ -54,7 +54,7 @@ packages:
description: description:
name: build_config name: build_config
sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.2" version: "1.1.2"
build_daemon: build_daemon:
@@ -62,7 +62,7 @@ packages:
description: description:
name: build_daemon name: build_daemon
sha256: bf05f6e12cfea92d3c09308d7bcdab1906cd8a179b023269eed00c071004b957 sha256: bf05f6e12cfea92d3c09308d7bcdab1906cd8a179b023269eed00c071004b957
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "4.1.1" version: "4.1.1"
build_resolvers: build_resolvers:
@@ -70,7 +70,7 @@ packages:
description: description:
name: build_resolvers name: build_resolvers
sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.2" version: "2.4.2"
build_runner: build_runner:
@@ -78,7 +78,7 @@ packages:
description: description:
name: build_runner name: build_runner
sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d" sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.13" version: "2.4.13"
build_runner_core: build_runner_core:
@@ -86,7 +86,7 @@ packages:
description: description:
name: build_runner_core name: build_runner_core
sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "7.3.2" version: "7.3.2"
built_collection: built_collection:
@@ -94,7 +94,7 @@ packages:
description: description:
name: built_collection name: built_collection
sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "5.1.1" version: "5.1.1"
built_value: built_value:
@@ -102,7 +102,7 @@ packages:
description: description:
name: built_value name: built_value
sha256: "426cf75afdb23aa74bd4e471704de3f9393f3c7b04c1e2d9c6f1073ae0b8b139" sha256: "426cf75afdb23aa74bd4e471704de3f9393f3c7b04c1e2d9c6f1073ae0b8b139"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "8.12.1" version: "8.12.1"
characters: characters:
@@ -110,7 +110,7 @@ packages:
description: description:
name: characters name: characters
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.0" version: "1.4.0"
checked_yaml: checked_yaml:
@@ -118,7 +118,7 @@ packages:
description: description:
name: checked_yaml name: checked_yaml
sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.4" version: "2.0.4"
clock: clock:
@@ -126,7 +126,7 @@ packages:
description: description:
name: clock name: clock
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.2" version: "1.1.2"
code_builder: code_builder:
@@ -134,7 +134,7 @@ packages:
description: description:
name: code_builder name: code_builder
sha256: "11654819532ba94c34de52ff5feb52bd81cba1de00ef2ed622fd50295f9d4243" sha256: "11654819532ba94c34de52ff5feb52bd81cba1de00ef2ed622fd50295f9d4243"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "4.11.0" version: "4.11.0"
collection: collection:
@@ -142,7 +142,7 @@ packages:
description: description:
name: collection name: collection
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.19.1" version: "1.19.1"
convert: convert:
@@ -150,7 +150,7 @@ packages:
description: description:
name: convert name: convert
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.2" version: "3.1.2"
crypto: crypto:
@@ -158,7 +158,7 @@ packages:
description: description:
name: crypto name: crypto
sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.7" version: "3.0.7"
cupertino_icons: cupertino_icons:
@@ -166,7 +166,7 @@ packages:
description: description:
name: cupertino_icons name: cupertino_icons
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.8" version: "1.0.8"
dart_style: dart_style:
@@ -174,7 +174,7 @@ packages:
description: description:
name: dart_style name: dart_style
sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.6" version: "2.3.6"
dbus: dbus:
@@ -182,7 +182,7 @@ packages:
description: description:
name: dbus name: dbus
sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.11" version: "0.7.11"
fake_async: fake_async:
@@ -190,7 +190,7 @@ packages:
description: description:
name: fake_async name: fake_async
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.3" version: "1.3.3"
ffi: ffi:
@@ -198,7 +198,7 @@ packages:
description: description:
name: ffi name: ffi
sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" version: "2.1.4"
file: file:
@@ -206,7 +206,7 @@ packages:
description: description:
name: file name: file
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.1" version: "7.0.1"
fixnum: fixnum:
@@ -214,7 +214,7 @@ packages:
description: description:
name: fixnum name: fixnum
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.1" version: "1.1.1"
flutter: flutter:
@@ -227,7 +227,7 @@ packages:
description: description:
name: flutter_lints name: flutter_lints
sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1" sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.0" version: "6.0.0"
flutter_local_notifications: flutter_local_notifications:
@@ -235,7 +235,7 @@ packages:
description: description:
name: flutter_local_notifications name: flutter_local_notifications
sha256: "674173fd3c9eda9d4c8528da2ce0ea69f161577495a9cc835a2a4ecd7eadeb35" sha256: "674173fd3c9eda9d4c8528da2ce0ea69f161577495a9cc835a2a4ecd7eadeb35"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "17.2.4" version: "17.2.4"
flutter_local_notifications_linux: flutter_local_notifications_linux:
@@ -243,7 +243,7 @@ packages:
description: description:
name: flutter_local_notifications_linux name: flutter_local_notifications_linux
sha256: c49bd06165cad9beeb79090b18cd1eb0296f4bf4b23b84426e37dd7c027fc3af sha256: c49bd06165cad9beeb79090b18cd1eb0296f4bf4b23b84426e37dd7c027fc3af
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.1" version: "4.0.1"
flutter_local_notifications_platform_interface: flutter_local_notifications_platform_interface:
@@ -251,7 +251,7 @@ packages:
description: description:
name: flutter_local_notifications_platform_interface name: flutter_local_notifications_platform_interface
sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66" sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "7.2.0" version: "7.2.0"
flutter_test: flutter_test:
@@ -269,7 +269,7 @@ packages:
description: description:
name: frontend_server_client name: frontend_server_client
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.0" version: "4.0.0"
glob: glob:
@@ -277,7 +277,7 @@ packages:
description: description:
name: glob name: glob
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.3" version: "2.1.3"
google_fonts: google_fonts:
@@ -285,7 +285,7 @@ packages:
description: description:
name: google_fonts name: google_fonts
sha256: "517b20870220c48752eafa0ba1a797a092fb22df0d89535fd9991e86ee2cdd9c" sha256: "517b20870220c48752eafa0ba1a797a092fb22df0d89535fd9991e86ee2cdd9c"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "6.3.2" version: "6.3.2"
graphs: graphs:
@@ -293,7 +293,7 @@ packages:
description: description:
name: graphs name: graphs
sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.2" version: "2.3.2"
hive: hive:
@@ -301,7 +301,7 @@ packages:
description: description:
name: hive name: hive
sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941" sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.3" version: "2.2.3"
hive_flutter: hive_flutter:
@@ -309,7 +309,7 @@ packages:
description: description:
name: hive_flutter name: hive_flutter
sha256: dca1da446b1d808a51689fb5d0c6c9510c0a2ba01e22805d492c73b68e33eecc sha256: dca1da446b1d808a51689fb5d0c6c9510c0a2ba01e22805d492c73b68e33eecc
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
hive_generator: hive_generator:
@@ -317,7 +317,7 @@ packages:
description: description:
name: hive_generator name: hive_generator
sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4" sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "2.0.1"
http: http:
@@ -325,7 +325,7 @@ packages:
description: description:
name: http name: http
sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.6.0" version: "1.6.0"
http_multi_server: http_multi_server:
@@ -333,7 +333,7 @@ packages:
description: description:
name: http_multi_server name: http_multi_server
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.2" version: "3.2.2"
http_parser: http_parser:
@@ -341,7 +341,7 @@ packages:
description: description:
name: http_parser name: http_parser
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "4.1.2" version: "4.1.2"
intl: intl:
@@ -349,7 +349,7 @@ packages:
description: description:
name: intl name: intl
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "0.19.0" version: "0.19.0"
io: io:
@@ -357,7 +357,7 @@ packages:
description: description:
name: io name: io
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.5" version: "1.0.5"
js: js:
@@ -365,7 +365,7 @@ packages:
description: description:
name: js name: js
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.2" version: "0.7.2"
json_annotation: json_annotation:
@@ -373,7 +373,7 @@ packages:
description: description:
name: json_annotation name: json_annotation
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "4.9.0" version: "4.9.0"
leak_tracker: leak_tracker:
@@ -381,7 +381,7 @@ packages:
description: description:
name: leak_tracker name: leak_tracker
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "11.0.2" version: "11.0.2"
leak_tracker_flutter_testing: leak_tracker_flutter_testing:
@@ -389,7 +389,7 @@ packages:
description: description:
name: leak_tracker_flutter_testing name: leak_tracker_flutter_testing
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.10" version: "3.0.10"
leak_tracker_testing: leak_tracker_testing:
@@ -397,7 +397,7 @@ packages:
description: description:
name: leak_tracker_testing name: leak_tracker_testing
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.2" version: "3.0.2"
lints: lints:
@@ -405,7 +405,7 @@ packages:
description: description:
name: lints name: lints
sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0 sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.0" version: "6.0.0"
logging: logging:
@@ -413,7 +413,7 @@ packages:
description: description:
name: logging name: logging
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.0" version: "1.3.0"
matcher: matcher:
@@ -421,7 +421,7 @@ packages:
description: description:
name: matcher name: matcher
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "0.12.17" version: "0.12.17"
material_color_utilities: material_color_utilities:
@@ -429,7 +429,7 @@ packages:
description: description:
name: material_color_utilities name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "0.11.1" version: "0.11.1"
meta: meta:
@@ -437,7 +437,7 @@ packages:
description: description:
name: meta name: meta
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.17.0" version: "1.17.0"
mime: mime:
@@ -445,7 +445,7 @@ packages:
description: description:
name: mime name: mime
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "2.0.0"
objective_c: objective_c:
@@ -453,7 +453,7 @@ packages:
description: description:
name: objective_c name: objective_c
sha256: "1f81ed9e41909d44162d7ec8663b2c647c202317cc0b56d3d56f6a13146a0b64" sha256: "1f81ed9e41909d44162d7ec8663b2c647c202317cc0b56d3d56f6a13146a0b64"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "9.1.0" version: "9.1.0"
package_config: package_config:
@@ -461,7 +461,7 @@ packages:
description: description:
name: package_config name: package_config
sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.0" version: "2.2.0"
path: path:
@@ -469,7 +469,7 @@ packages:
description: description:
name: path name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.9.1" version: "1.9.1"
path_provider: path_provider:
@@ -477,7 +477,7 @@ packages:
description: description:
name: path_provider name: path_provider
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.5" version: "2.1.5"
path_provider_android: path_provider_android:
@@ -485,7 +485,7 @@ packages:
description: description:
name: path_provider_android name: path_provider_android
sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.22" version: "2.2.22"
path_provider_foundation: path_provider_foundation:
@@ -493,7 +493,7 @@ packages:
description: description:
name: path_provider_foundation name: path_provider_foundation
sha256: "6192e477f34018ef1ea790c56fffc7302e3bc3efede9e798b934c252c8c105ba" sha256: "6192e477f34018ef1ea790c56fffc7302e3bc3efede9e798b934c252c8c105ba"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.5.0" version: "2.5.0"
path_provider_linux: path_provider_linux:
@@ -501,7 +501,7 @@ packages:
description: description:
name: path_provider_linux name: path_provider_linux
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.1" version: "2.2.1"
path_provider_platform_interface: path_provider_platform_interface:
@@ -509,7 +509,7 @@ packages:
description: description:
name: path_provider_platform_interface name: path_provider_platform_interface
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.2" version: "2.1.2"
path_provider_windows: path_provider_windows:
@@ -517,7 +517,7 @@ packages:
description: description:
name: path_provider_windows name: path_provider_windows
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0" version: "2.3.0"
petitparser: petitparser:
@@ -525,7 +525,7 @@ packages:
description: description:
name: petitparser name: petitparser
sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1" sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.1" version: "7.0.1"
platform: platform:
@@ -533,7 +533,7 @@ packages:
description: description:
name: platform name: platform
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.6" version: "3.1.6"
plugin_platform_interface: plugin_platform_interface:
@@ -541,7 +541,7 @@ packages:
description: description:
name: plugin_platform_interface name: plugin_platform_interface
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.8" version: "2.1.8"
pool: pool:
@@ -549,7 +549,7 @@ packages:
description: description:
name: pool name: pool
sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d" sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.5.2" version: "1.5.2"
pub_semver: pub_semver:
@@ -557,7 +557,7 @@ packages:
description: description:
name: pub_semver name: pub_semver
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.0" version: "2.2.0"
pubspec_parse: pubspec_parse:
@@ -565,7 +565,7 @@ packages:
description: description:
name: pubspec_parse name: pubspec_parse
sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.5.0" version: "1.5.0"
shared_preferences: shared_preferences:
@@ -573,7 +573,7 @@ packages:
description: description:
name: shared_preferences name: shared_preferences
sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.5.3" version: "2.5.3"
shared_preferences_android: shared_preferences_android:
@@ -581,7 +581,7 @@ packages:
description: description:
name: shared_preferences_android name: shared_preferences_android
sha256: "46a46fd64659eff15f4638bbe19de43f9483f0e0bf024a9fb6b3582064bacc7b" sha256: "46a46fd64659eff15f4638bbe19de43f9483f0e0bf024a9fb6b3582064bacc7b"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.17" version: "2.4.17"
shared_preferences_foundation: shared_preferences_foundation:
@@ -589,7 +589,7 @@ packages:
description: description:
name: shared_preferences_foundation name: shared_preferences_foundation
sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.5.6" version: "2.5.6"
shared_preferences_linux: shared_preferences_linux:
@@ -597,7 +597,7 @@ packages:
description: description:
name: shared_preferences_linux name: shared_preferences_linux
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.1" version: "2.4.1"
shared_preferences_platform_interface: shared_preferences_platform_interface:
@@ -605,7 +605,7 @@ packages:
description: description:
name: shared_preferences_platform_interface name: shared_preferences_platform_interface
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.1" version: "2.4.1"
shared_preferences_web: shared_preferences_web:
@@ -613,7 +613,7 @@ packages:
description: description:
name: shared_preferences_web name: shared_preferences_web
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.3" version: "2.4.3"
shared_preferences_windows: shared_preferences_windows:
@@ -621,7 +621,7 @@ packages:
description: description:
name: shared_preferences_windows name: shared_preferences_windows
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.1" version: "2.4.1"
shelf: shelf:
@@ -629,7 +629,7 @@ packages:
description: description:
name: shelf name: shelf
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.2" version: "1.4.2"
shelf_web_socket: shelf_web_socket:
@@ -637,7 +637,7 @@ packages:
description: description:
name: shelf_web_socket name: shelf_web_socket
sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67 sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "2.0.1"
sky_engine: sky_engine:
@@ -650,7 +650,7 @@ packages:
description: description:
name: source_gen name: source_gen
sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.5.0" version: "1.5.0"
source_helper: source_helper:
@@ -658,7 +658,7 @@ packages:
description: description:
name: source_helper name: source_helper
sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c" sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.5" version: "1.3.5"
source_span: source_span:
@@ -666,7 +666,7 @@ packages:
description: description:
name: source_span name: source_span
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.10.1" version: "1.10.1"
stack_trace: stack_trace:
@@ -674,7 +674,7 @@ packages:
description: description:
name: stack_trace name: stack_trace
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.12.1" version: "1.12.1"
stream_channel: stream_channel:
@@ -682,7 +682,7 @@ packages:
description: description:
name: stream_channel name: stream_channel
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" version: "2.1.4"
stream_transform: stream_transform:
@@ -690,7 +690,7 @@ packages:
description: description:
name: stream_transform name: stream_transform
sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.1"
string_scanner: string_scanner:
@@ -698,7 +698,7 @@ packages:
description: description:
name: string_scanner name: string_scanner
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.1" version: "1.4.1"
term_glyph: term_glyph:
@@ -706,7 +706,7 @@ packages:
description: description:
name: term_glyph name: term_glyph
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.2" version: "1.2.2"
test_api: test_api:
@@ -714,7 +714,7 @@ packages:
description: description:
name: test_api name: test_api
sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.7" version: "0.7.7"
timezone: timezone:
@@ -722,7 +722,7 @@ packages:
description: description:
name: timezone name: timezone
sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d" sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "0.9.4" version: "0.9.4"
timing: timing:
@@ -730,7 +730,7 @@ packages:
description: description:
name: timing name: timing
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.2" version: "1.0.2"
typed_data: typed_data:
@@ -738,7 +738,7 @@ packages:
description: description:
name: typed_data name: typed_data
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.0" version: "1.4.0"
vector_math: vector_math:
@@ -746,7 +746,7 @@ packages:
description: description:
name: vector_math name: vector_math
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.0" version: "2.2.0"
vm_service: vm_service:
@@ -754,7 +754,7 @@ packages:
description: description:
name: vm_service name: vm_service
sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "15.0.2" version: "15.0.2"
watcher: watcher:
@@ -762,7 +762,7 @@ packages:
description: description:
name: watcher name: watcher
sha256: "592ab6e2892f67760543fb712ff0177f4ec76c031f02f5b4ff8d3fc5eb9fb61a" sha256: "592ab6e2892f67760543fb712ff0177f4ec76c031f02f5b4ff8d3fc5eb9fb61a"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.4" version: "1.1.4"
web: web:
@@ -770,7 +770,7 @@ packages:
description: description:
name: web name: web
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.1" version: "1.1.1"
web_socket: web_socket:
@@ -778,7 +778,7 @@ packages:
description: description:
name: web_socket name: web_socket
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.1" version: "1.0.1"
web_socket_channel: web_socket_channel:
@@ -786,7 +786,7 @@ packages:
description: description:
name: web_socket_channel name: web_socket_channel
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.3" version: "3.0.3"
xdg_directories: xdg_directories:
@@ -794,7 +794,7 @@ packages:
description: description:
name: xdg_directories name: xdg_directories
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
xml: xml:
@@ -802,7 +802,7 @@ packages:
description: description:
name: xml name: xml
sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025"
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "6.6.1" version: "6.6.1"
yaml: yaml:
@@ -810,7 +810,7 @@ packages:
description: description:
name: yaml name: yaml
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.flutter-io.cn" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.3" version: "3.1.3"
sdks: sdks: