通知栏图标优化
This commit is contained in:
@@ -43,7 +43,8 @@
|
|||||||
"Bash(flutter clean:*)",
|
"Bash(flutter clean:*)",
|
||||||
"Bash(start ms-settings:developers)",
|
"Bash(start ms-settings:developers)",
|
||||||
"Bash(gradlew.bat --stop:*)",
|
"Bash(gradlew.bat --stop:*)",
|
||||||
"Bash(call gradlew.bat:*)"
|
"Bash(call gradlew.bat:*)",
|
||||||
|
"Bash(where:*)"
|
||||||
],
|
],
|
||||||
"deny": [],
|
"deny": [],
|
||||||
"ask": []
|
"ask": []
|
||||||
|
|||||||
284
CLAUDE.md
Normal file
284
CLAUDE.md
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
FocusBuddy is a Flutter-based focus timer app designed for neurodivergent minds, implementing a "no-punishment" philosophy. The core concept is that distractions during focus sessions are tracked but don't interrupt the timer, providing a gentler approach to productivity tracking.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
### Development Setup
|
||||||
|
```bash
|
||||||
|
# Check Flutter version and environment
|
||||||
|
flutter doctor
|
||||||
|
|
||||||
|
# Get dependencies
|
||||||
|
flutter pub get
|
||||||
|
|
||||||
|
# Generate localization files (required after editing .arb files)
|
||||||
|
flutter gen-l10n
|
||||||
|
|
||||||
|
# Generate Hive adapters (required after modifying model classes)
|
||||||
|
flutter pub run build_runner build
|
||||||
|
|
||||||
|
# Clean build artifacts
|
||||||
|
flutter clean
|
||||||
|
```
|
||||||
|
|
||||||
|
### Running the App
|
||||||
|
```bash
|
||||||
|
# List available devices/emulators
|
||||||
|
flutter devices
|
||||||
|
|
||||||
|
# Run on default device
|
||||||
|
flutter run
|
||||||
|
|
||||||
|
# Run on specific device
|
||||||
|
flutter run -d <device_id>
|
||||||
|
|
||||||
|
# Run on Chrome (web)
|
||||||
|
flutter run -d chrome
|
||||||
|
|
||||||
|
# Run with hot reload (default in debug mode)
|
||||||
|
flutter run --hot
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building
|
||||||
|
```bash
|
||||||
|
# Build APK for Android
|
||||||
|
flutter build apk
|
||||||
|
|
||||||
|
# Build App Bundle for Google Play
|
||||||
|
flutter build appbundle
|
||||||
|
|
||||||
|
# Build for iOS (requires macOS)
|
||||||
|
flutter build ios
|
||||||
|
|
||||||
|
# Build for Windows
|
||||||
|
flutter build windows
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing & Analysis
|
||||||
|
```bash
|
||||||
|
# Run static analysis
|
||||||
|
flutter analyze
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
flutter test
|
||||||
|
|
||||||
|
# Check for outdated packages
|
||||||
|
flutter pub outdated
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Core Philosophy
|
||||||
|
The app follows a **no-punishment approach** to focus tracking:
|
||||||
|
- Timer continues running even when user reports a distraction
|
||||||
|
- Distractions are tracked via "I got distracted" button
|
||||||
|
- Encouragement messages replace negative feedback
|
||||||
|
- All distraction counts are for awareness, not judgment
|
||||||
|
|
||||||
|
### Key Technical Decisions
|
||||||
|
|
||||||
|
**State Management**: Simple `StatefulWidget` approach (no external state management)
|
||||||
|
- Focus session state managed locally in `FocusScreen`
|
||||||
|
- Settings and preferences stored in `shared_preferences`
|
||||||
|
- Historical data stored in Hive local database
|
||||||
|
|
||||||
|
**Data Persistence**:
|
||||||
|
- **Hive** for focus session history (typeId 0 for `FocusSession`)
|
||||||
|
- **SharedPreferences** for app settings (onboarding status, default duration, locale)
|
||||||
|
- Sessions stored with full distraction tracking but continue regardless of interruptions
|
||||||
|
|
||||||
|
**Notifications**:
|
||||||
|
- Background notifications when app is inactive during focus session
|
||||||
|
- Uses `flutter_local_notifications` with `WidgetsBindingObserver` lifecycle tracking
|
||||||
|
- Notification updates every 30 seconds when app is backgrounded
|
||||||
|
|
||||||
|
**Internationalization (i18n)**:
|
||||||
|
- Uses Flutter's official `intl` package with ARB files
|
||||||
|
- 13 supported languages (en, zh, ja, ko, es, de, fr, pt, ru, hi, id, it, ar)
|
||||||
|
- Locale can be changed at runtime without app restart via `MyApp.updateLocale()`
|
||||||
|
- Localization files generated in `lib/l10n/` via `flutter gen-l10n`
|
||||||
|
|
||||||
|
### Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
lib/
|
||||||
|
├── main.dart # Entry point, app initialization
|
||||||
|
├── models/ # Data models
|
||||||
|
│ ├── focus_session.dart # Hive model for session data
|
||||||
|
│ ├── focus_session.g.dart # Generated Hive adapter
|
||||||
|
│ └── distraction_type.dart # Enum for distraction categories
|
||||||
|
├── screens/ # UI screens
|
||||||
|
│ ├── onboarding_screen.dart # First-time user guide
|
||||||
|
│ ├── home_screen.dart # Main screen with "Start Focus" button
|
||||||
|
│ ├── focus_screen.dart # Active timer + distraction button
|
||||||
|
│ ├── complete_screen.dart # Post-session summary
|
||||||
|
│ ├── history_screen.dart # Past sessions list
|
||||||
|
│ └── settings_screen.dart # Duration & locale settings
|
||||||
|
├── services/ # Business logic
|
||||||
|
│ ├── storage_service.dart # Hive database operations
|
||||||
|
│ ├── encouragement_service.dart # Random message picker
|
||||||
|
│ └── notification_service.dart # Background notifications
|
||||||
|
├── theme/ # Design system
|
||||||
|
│ ├── app_theme.dart # Material theme config
|
||||||
|
│ ├── app_colors.dart # Color palette constants
|
||||||
|
│ └── app_text_styles.dart # Typography definitions
|
||||||
|
└── l10n/ # Generated localization files
|
||||||
|
├── app_localizations.dart
|
||||||
|
└── app_localizations_*.dart
|
||||||
|
```
|
||||||
|
|
||||||
|
### Data Flow
|
||||||
|
|
||||||
|
**Focus Session Lifecycle**:
|
||||||
|
1. User selects duration in `HomeScreen` (loads from SharedPreferences)
|
||||||
|
2. `FocusScreen` starts countdown timer with `Timer.periodic`
|
||||||
|
3. User can tap "I got distracted" → adds to `_distractions` list, timer continues
|
||||||
|
4. Timer completion or manual stop → `FocusSession` saved to Hive via `StorageService`
|
||||||
|
5. `CompleteScreen` shows stats fetched from `StorageService.getTodaySessions()`
|
||||||
|
6. `HistoryScreen` displays all sessions from `StorageService.getAllSessions()`
|
||||||
|
|
||||||
|
**Critical Implementation**: The distraction button **never** pauses the timer - this is the app's core differentiator.
|
||||||
|
|
||||||
|
### FocusSession Model
|
||||||
|
|
||||||
|
```dart
|
||||||
|
@HiveType(typeId: 0)
|
||||||
|
class FocusSession {
|
||||||
|
DateTime startTime;
|
||||||
|
int durationMinutes; // Planned (e.g., 25)
|
||||||
|
int actualMinutes; // May be less if stopped early
|
||||||
|
int distractionCount; // Total distractions logged
|
||||||
|
bool completed; // True if timer reached zero
|
||||||
|
List<String> distractionTypes; // Categories selected
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Theme System
|
||||||
|
|
||||||
|
Uses Google Fonts (Nunito) with centralized design tokens:
|
||||||
|
- **Primary Color**: `#6C63FF` (Purple)
|
||||||
|
- **Background**: `#F5F7FA` (Light Gray)
|
||||||
|
- **Text Primary**: `#2D3748` (Dark Gray)
|
||||||
|
- **Success**: `#48BB78` (Green - used sparingly)
|
||||||
|
|
||||||
|
All UI components reference `AppTextStyles` and `AppColors` constants - never use hardcoded values.
|
||||||
|
|
||||||
|
## MVP Feature Set
|
||||||
|
|
||||||
|
**Current Implementation** (as of git commit `005ad8d`):
|
||||||
|
- ✅ Onboarding flow with "no-punishment" philosophy explanation
|
||||||
|
- ✅ Configurable session duration (15/25/45 minutes)
|
||||||
|
- ✅ Background notifications during active sessions
|
||||||
|
- ✅ Distraction tracking with 4 categories
|
||||||
|
- ✅ Today's stats on completion screen
|
||||||
|
- ✅ History view (today's sessions only in MVP)
|
||||||
|
- ✅ Multi-language support (13 languages)
|
||||||
|
- ✅ Settings for duration and locale
|
||||||
|
|
||||||
|
**Intentionally Deferred** (see [README.md](README.md)):
|
||||||
|
- ⏸️ Variable duration slider (fixed presets preferred for MVP)
|
||||||
|
- ⏸️ White noise audio playback
|
||||||
|
- ⏸️ Weekly trend charts
|
||||||
|
- ⏸️ PDF report export
|
||||||
|
- ⏸️ AdMob integration (monetization post-validation)
|
||||||
|
|
||||||
|
## Working with Localization
|
||||||
|
|
||||||
|
### Adding/Editing Translations
|
||||||
|
1. Translations are defined in `l10n/app_en.arb` (source locale) and other `app_*.arb` files
|
||||||
|
2. After editing ARB files, regenerate code:
|
||||||
|
```bash
|
||||||
|
flutter gen-l10n
|
||||||
|
```
|
||||||
|
3. Use in code:
|
||||||
|
```dart
|
||||||
|
final l10n = AppLocalizations.of(context)!;
|
||||||
|
Text(l10n.appTitle);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adding a New Language
|
||||||
|
1. Create `l10n/app_<locale>.arb` (copy from `app_en.arb`)
|
||||||
|
2. Add locale to `supportedLocales` in [main.dart](lib/main.dart:97-111)
|
||||||
|
3. Add to language picker in [settings_screen.dart](lib/screens/settings_screen.dart)
|
||||||
|
4. Run `flutter gen-l10n`
|
||||||
|
|
||||||
|
## Modifying Data Models
|
||||||
|
|
||||||
|
When changing Hive models (e.g., `FocusSession`):
|
||||||
|
1. Update model class with `@HiveField` annotations
|
||||||
|
2. Regenerate adapters:
|
||||||
|
```bash
|
||||||
|
flutter pub run build_runner build --delete-conflicting-outputs
|
||||||
|
```
|
||||||
|
3. Consider migration strategy if changing existing fields (current MVP has no migration logic)
|
||||||
|
|
||||||
|
## Code Generation
|
||||||
|
|
||||||
|
This project uses code generation for:
|
||||||
|
- **Hive adapters**: `*.g.dart` files for model serialization
|
||||||
|
- **Localization**: `lib/l10n/app_localizations*.dart` from ARB files
|
||||||
|
|
||||||
|
Never edit generated files manually - always modify source files and regenerate.
|
||||||
|
|
||||||
|
## Platform-Specific Notes
|
||||||
|
|
||||||
|
### Android
|
||||||
|
- Minimum SDK: 21 (Android 5.0)
|
||||||
|
- Target SDK: 34 (Android 14)
|
||||||
|
- Notification permission auto-requested on Android 13+ via `permission_handler`
|
||||||
|
|
||||||
|
### iOS
|
||||||
|
- Requires Xcode for building
|
||||||
|
- Notification permissions requested via `DarwinInitializationSettings`
|
||||||
|
- See [MACOS_BUILD_GUIDE.md](MACOS_BUILD_GUIDE.md) for macOS-specific instructions
|
||||||
|
|
||||||
|
### Web
|
||||||
|
- Notifications explicitly disabled on web platform (see `NotificationService._initialized`)
|
||||||
|
- Uses responsive layout but primarily designed for mobile
|
||||||
|
|
||||||
|
## Design System Guidelines
|
||||||
|
|
||||||
|
When adding new UI components:
|
||||||
|
1. Use `AppColors` constants - never hardcode colors
|
||||||
|
2. Use `AppTextStyles` for typography - never inline text styles
|
||||||
|
3. Border radius should be 16px for cards/buttons (consistency)
|
||||||
|
4. Button minimum height: 56px (touch-friendly)
|
||||||
|
5. Padding: Use multiples of 8 (8, 16, 24, 32, 48, 60)
|
||||||
|
6. Never use red/destructive colors for distractions (core philosophy)
|
||||||
|
|
||||||
|
## Testing Strategy
|
||||||
|
|
||||||
|
Current implementation focuses on manual testing:
|
||||||
|
- Test timer countdown accuracy across different durations
|
||||||
|
- Verify background notifications appear when app is minimized
|
||||||
|
- Test distraction button during active session (ensure timer continues)
|
||||||
|
- Verify data persists after app restart (Hive)
|
||||||
|
- Test locale switching without app restart
|
||||||
|
|
||||||
|
## Known Constraints
|
||||||
|
|
||||||
|
1. **No backend server** - All data stored locally (intentional for privacy)
|
||||||
|
2. **No analytics** - No Firebase/Amplitude in MVP (intentional)
|
||||||
|
3. **Single-device only** - No cross-device sync
|
||||||
|
4. **Today-focused** - History screen shows minimal data in MVP
|
||||||
|
|
||||||
|
## Important Implementation Rules
|
||||||
|
|
||||||
|
1. **Never pause timer on distraction** - This would violate the core philosophy
|
||||||
|
2. **Never show negative/punitive messaging** - Use encouragement instead
|
||||||
|
3. **Always use localized strings** - No hardcoded English text
|
||||||
|
4. **Always save sessions to Hive** - Even if stopped early (actualMinutes < durationMinutes)
|
||||||
|
5. **Background notifications required** - Users need countdown visibility when multitasking
|
||||||
|
|
||||||
|
## Related Documentation
|
||||||
|
|
||||||
|
- [README.md](README.md) - Product optimization strategy and MVP scope
|
||||||
|
- [ui-design-spec.md](ui-design-spec.md) - Complete UI/UX specifications
|
||||||
|
- [mvp-launch-checklist.md](mvp-launch-checklist.md) - 4-week development roadmap
|
||||||
|
- [product-design.md](product-design.md) - Original product vision
|
||||||
|
- [MACOS_BUILD_GUIDE.md](MACOS_BUILD_GUIDE.md) - macOS/iOS build instructions
|
||||||
15
android/app/src/main/res/drawable/ic_notification.xml
Normal file
15
android/app/src/main/res/drawable/ic_notification.xml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<!-- Simple timer/focus icon for notifications (white silhouette) -->
|
||||||
|
<!-- Circle representing focus/timer -->
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M12,2C6.48,2 2,6.48 2,12C2,17.52 6.48,22 12,22C17.52,22 22,17.52 22,12C22,6.48 17.52,2 12,2ZM12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20Z"/>
|
||||||
|
<!-- Clock hand pointing up (12 o'clock - focus start position) -->
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M11,7L11,12.41L14.29,15.71L15.71,14.29L13,11.59L13,7Z"/>
|
||||||
|
</vector>
|
||||||
@@ -28,7 +28,7 @@ class NotificationService {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Android initialization settings
|
// Android initialization settings
|
||||||
const androidSettings = AndroidInitializationSettings('@mipmap/ic_launcher');
|
const androidSettings = AndroidInitializationSettings('@drawable/ic_notification');
|
||||||
|
|
||||||
// iOS initialization settings
|
// iOS initialization settings
|
||||||
const iosSettings = DarwinInitializationSettings(
|
const iosSettings = DarwinInitializationSettings(
|
||||||
@@ -147,6 +147,7 @@ class NotificationService {
|
|||||||
priority: Priority.high,
|
priority: Priority.high,
|
||||||
enableVibration: true,
|
enableVibration: true,
|
||||||
playSound: true,
|
playSound: true,
|
||||||
|
icon: '@drawable/ic_notification',
|
||||||
);
|
);
|
||||||
|
|
||||||
const iosDetails = DarwinNotificationDetails(
|
const iosDetails = DarwinNotificationDetails(
|
||||||
@@ -198,6 +199,7 @@ class NotificationService {
|
|||||||
channelDescription: 'Gentle reminders to focus',
|
channelDescription: 'Gentle reminders to focus',
|
||||||
importance: Importance.defaultImportance,
|
importance: Importance.defaultImportance,
|
||||||
priority: Priority.defaultPriority,
|
priority: Priority.defaultPriority,
|
||||||
|
icon: '@drawable/ic_notification',
|
||||||
);
|
);
|
||||||
|
|
||||||
const iosDetails = DarwinNotificationDetails();
|
const iosDetails = DarwinNotificationDetails();
|
||||||
@@ -274,6 +276,7 @@ class NotificationService {
|
|||||||
playSound: false,
|
playSound: false,
|
||||||
// Show in status bar
|
// Show in status bar
|
||||||
showProgress: false,
|
showProgress: false,
|
||||||
|
icon: '@drawable/ic_notification',
|
||||||
);
|
);
|
||||||
|
|
||||||
const iosDetails = DarwinNotificationDetails(
|
const iosDetails = DarwinNotificationDetails(
|
||||||
|
|||||||
Reference in New Issue
Block a user