diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md deleted file mode 100644 index 744582f7..00000000 --- a/.github/copilot-instructions.md +++ /dev/null @@ -1,216 +0,0 @@ -# Copilot Instructions for Frosty - -## Project Overview - -Frosty is a cross-platform Flutter app for Twitch that supports third-party emotes (7TV, BTTV, FFZ). The architecture is built around **MobX state management** with strict code generation requirements and a **shared HTTP client pattern** for API efficiency. - -## Critical Development Workflow - -### Essential Commands - -**Dependencies and Development:** - -- `flutter pub get` - Install dependencies -- `flutter run` - Run the app on connected device/emulator -- `flutter build apk` - Build Android APK -- `flutter build ios` - Build iOS app -- `flutter analyze` - Run static analysis and lint checks -- `flutter test` - Run all tests - -### Code Generation (REQUIRED) - -All MobX stores and JSON models require code generation. **Always run after any MobX or model changes:** - -```bash -dart run build_runner build --delete-conflicting-outputs -``` - -**Alternative commands:** - -- `dart run build_runner build` - Generate code once -- `dart run build_runner watch` - Watch and regenerate code on changes - -Generated `.g.dart` files are excluded from linting but must be committed to source control. - -### Environment Setup - -Twitch API requires client credentials via `--dart-define`: - -```bash -flutter run --dart-define=clientId=YOUR_TWITCH_CLIENT_ID --dart-define=secret=YOUR_TWITCH_CLIENT_SECRET -``` - -## Architecture Patterns - -### State Management (MobX) - -- **Store Pattern**: Each feature has stores in `lib/screens/{feature}/stores/` (not at screen root) -- **Naming**: All stores end with `Store` suffix and have corresponding `.g.dart` files -- **Global Stores**: - - `AuthStore`, `SettingsStore` in `lib/screens/settings/stores/` - - `GlobalAssetsStore` (shared emote/badge cache) in `lib/stores/` -- **Dependency Injection**: Stores are provided via Provider in `main.dart` with shared HTTP client - -### API Service Architecture - -- **Shared HTTP Client**: Single Dio instance configured in `DioClient.createClient()` with: - - Connection pooling and keep-alive headers for efficiency - - Optimized timeouts: 8s connect, 15s receive, 10s send - - Global Twitch User-Agent header - - Simple logging in debug mode (not verbose to avoid log spam) -- **API Services**: `TwitchApi`, `BTTVApi`, `FFZApi`, `SevenTVApi` in `lib/apis/` -- **Authentication Interceptor**: `TwitchAuthInterceptor` automatically injects auth headers: - - Detects Twitch API URLs and adds Authorization + Client-Id headers - - Updates automatically when user authentication changes - - Eliminates manual header passing throughout the codebase -- **Error Handling**: `UnauthorizedInterceptor` catches 401 errors for token refresh -- **Service Pattern**: All API services extend `BaseApiClient` for consistent error handling - -### Project Structure - -**Key Directories:** - -- `lib/screens/` - UI screens organized by feature (home, channel, settings, onboarding) - - Each screen has its own MobX stores in a `stores/` subdirectory -- `lib/models/` - Data models with JSON serialization (uses `.g.dart` files) -- `lib/apis/` - API services for Twitch, BTTV, FFZ, and 7TV -- `lib/widgets/` - Reusable UI components -- `lib/cache_manager.dart` - Custom cache management for images/media -- `lib/utils.dart` - Utility functions and helpers -- `lib/utils/` - Additional utility modules including context extensions - -### Screen Organization - -``` -lib/screens/{feature}/ -├── {feature}.dart # Main UI -├── stores/ # Feature stores directory -│ ├── {feature}_store.dart -│ └── {feature}_store.g.dart -└── subdirectories/ # Feature sub-components -``` - -**Main Application Flow:** - -1. App starts in `main.dart` with Firebase initialization and dependency injection via Provider -2. Authentication handled by `AuthStore` using Twitch OAuth -3. Settings persisted via `SettingsStore` with SharedPreferences -4. API services inject common HTTP client for efficient connection reuse - -### Model Generation - -- **JSON Serialization**: Models use `@JsonSerializable()` with `.g.dart` companions -- **Emote Architecture**: Base `Emote` class with platform-specific factories (`Emote.fromTwitch()`, `Emote.fromBTTV()`, `Emote.fromFFZ()`, `Emote.from7TV()`) - -## Key Integration Points - -### Firebase Services - -Initialized in `main.dart` with error handling: - -- Crashlytics for uncaught errors -- Performance monitoring -- Analytics - -### Chat System - -- **IRC Connection**: WebSocket to Twitch IRC for real-time chat -- **Emote Loading**: Asynchronous third-party emote fetching (BTTV/FFZ/7TV) -- **Message Parsing**: Custom rendering with emote/badge support -- **Real-time IRC**: WebSocket connection to Twitch IRC with custom `IRCMessage` parsing -- **Third-party Emotes**: Asynchronous loading of BTTV, FFZ, and 7TV assets via dedicated APIs -- **Message Management**: 5000 message limit with 20% batch removal optimization for performance -- **Assets Store**: Separate `ChatAssetsStore` manages emotes, badges, and chat-related data -- **User interaction features**: Blocking, reporting, moderation capabilities - -### Authentication Flow - -- **OAuth**: Twitch OAuth via WebView in `AuthStore` -- **Token Storage**: FlutterSecureStorage for secure token persistence -- **Auto-refresh**: Token validation and refresh logic in `AuthStore` -- **Two-tier Token System**: - - Default app token for unauthenticated requests - - Optional user token stored in Flutter Secure Storage - - Automatic token validation on startup with fallback -- **WebView OAuth Flow**: Custom JavaScript injection in WebView for seamless Twitch login experience without opening external browsers -- **Secure Storage Cleanup**: First-run detection clears secure storage to handle Android/iOS uninstall scenarios where secure storage persists - -## Code Style Enforcement - -Analysis rules in `analysis_options.yaml`: - -- Single quotes: `prefer_single_quotes` -- Package imports: `always_use_package_imports` -- Trailing commas: `require_trailing_commas` -- Final locals: `prefer_final_locals` -- Additional rules: `directives_ordering`, `avoid_void_async`, `always_declare_return_types`, `avoid_redundant_argument_values`, `unnecessary_parenthesis` - -**Important**: `.g.dart` files are excluded from analysis but must be committed to source control. - -## Common Patterns - -### MobX Reactions - -```dart -late final ReactionDisposer _disposeReaction; -_disposeReaction = reaction( - (_) => authStore.isLoggedIn, - (_) => _selectedIndex = 0, -); -``` - -### Settings Persistence - -Auto-saving pattern in `main.dart`: - -```dart -autorun((_) => prefs.setString('settings', jsonEncode(settingsStore))); -``` - -### Error Handling - -API services use typed exceptions via `BaseApiClient` (`lib/apis/base_api_client.dart`): -- `ApiException`, `NetworkException`, `TimeoutException`, `ServerException`, `NotFoundException`, `UnauthorizedException` - -## MobX Store Implementation - -### Store Pattern - -All stores follow `StoreBase with _$StoreName` pattern: - -- Generate `.g.dart` files with `dart run build_runner build` -- Use `@observable`, `@action`, and `@computed` annotations -- Settings store uses `@JsonSerializable()` with automatic persistence via `autorun()` - -### Authentication Headers - -Generated as `@computed` properties that automatically update when tokens change. - -### State Persistence - -Settings automatically saved to SharedPreferences via MobX `autorun()` reaction. - -## Custom Cache Management - -- **Orphaned File Cleanup**: `CustomCacheManager.removeOrphanedCacheFiles()` runs on startup to remove files not in database -- **Optimized Settings**: 30-day stale period, 10,000 max objects for efficient image caching across the app - -## Code Style Guidelines - -- **Prefer modern Flutter/Dart features and type-safety** -- **Use consistent naming, comments, and styles matching the existing codebase** -- **Single quotes, trailing commas, and final locals per lint rules** -- **Package imports over relative imports** -- **Observer widgets only wrap necessary UI components for MobX optimization** - -## Platform Support - -- **iOS/Android**: Native platform features via plugins -- **Custom Cache**: `CustomCacheManager` for media caching -- **PiP Mode**: Custom implementation via git dependency - -## Commit Convention - -Commits use lowercase, descriptive messages without prefixes (e.g., `fix landscape bottom padding in chat bottom bar`, `add swipe pip gesture support`). Keep commits tightly scoped. - -When working with this codebase, always consider MobX code generation requirements and the shared HTTP client pattern for API efficiency. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..66762750 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,131 @@ +# AGENTS.md + +## Development Workflow + +**Plan Mode**: When in plan mode, interview thoroughly before coding: +- Ask detailed questions about technical implementation, UI/UX concerns, tradeoffs, and edge cases +- Continue asking questions until all requirements and non-obvious decisions are clear +- Don't begin implementation until all important details are resolved + +**Pattern Consistency**: When implementing new code: +- Search the codebase to find existing usages and implementations +- Prefer following established patterns, styles, and practices for consistency + +## Development Commands + +**Common Commands:** +- `flutter pub get` - Install dependencies +- `flutter run --dart-define=clientId=YOUR_CLIENT_ID --dart-define=secret=YOUR_CLIENT_SECRET` - Run with Twitch API credentials +- `flutter analyze` - Run static analysis and lint checks +- `flutter test` - Run all tests +- `flutter test test/path/to/test.dart` - Run a single test file +- `flutter build apk` / `flutter build ios` - Build release binaries + +**Code Generation** (required after changing MobX stores or `@JsonSerializable` models): +- `dart run build_runner build` - Generate once +- `dart run build_runner build --delete-conflicting-outputs` - Force rebuild all +- `dart run build_runner watch` - Watch mode for development + +Generated `.g.dart` files are excluded from linting but must be committed to source control. + +## Architecture Overview + +**State Management**: MobX with code generation. All stores end with `Store` and have corresponding `.g.dart` generated files. + +**Key Directories**: +- `lib/screens/` - UI screens organized by feature (home, channel, settings, onboarding) +- `lib/models/` - Data models with JSON serialization (uses .g.dart files) +- `lib/apis/` - API services for Twitch, BTTV, FFZ, and 7TV +- `lib/widgets/` - Reusable UI components +- `lib/utils/` - Utility modules including context extensions + +**Screen Organization**: `lib/screens/{feature}/` contains `{feature}.dart` (main UI), `stores/` subdirectory with MobX stores, and feature sub-components. + +**Main Application Flow**: +1. App starts in `main.dart` with Firebase initialization and dependency injection via Provider +2. Authentication handled by `AuthStore` using Twitch OAuth +3. Settings persisted via `SettingsStore` with SharedPreferences and MobX `autorun()` +4. API services share a common Dio HTTP client for efficient connection reuse + +**Global Stores** (injected via Provider in `main.dart`): +- `AuthStore` (`lib/screens/settings/stores/`) - Authentication state and token management +- `SettingsStore` (`lib/screens/settings/stores/`) - User preferences with automatic persistence via MobX `autorun()` +- `GlobalAssetsStore` (`lib/stores/`) - Shared cache for global emotes and badges across all chat tabs + +## HTTP & API Architecture + +**Shared HTTP Client**: Single Dio instance configured in `DioClient.createClient()` with: +- Connection pooling and keep-alive headers for efficiency +- Optimized timeouts: 8s connect, 15s receive, 10s send +- Frosty User-Agent header for Twitch API compatibility + +**Authentication Interceptor**: `TwitchAuthInterceptor` automatically injects auth headers for Twitch API URLs. `UnauthorizedInterceptor` catches 401 errors for token refresh. + +**Two-tier Token System**: Default app token for unauthenticated requests + optional user token in Flutter Secure Storage. + +**BaseApiClient Pattern**: All API services (`TwitchApi`, `BTTVApi`, `FFZApi`, `SevenTVApi`) extend `BaseApiClient` which provides: +- Generic GET/POST/PUT/DELETE methods with centralized error handling +- Automatic conversion of `DioException` to typed exceptions + +**Exception Hierarchy**: `ApiException` base class with `NetworkException`, `TimeoutException`, `ServerException`, `NotFoundException`, `UnauthorizedException` (see `lib/apis/base_api_client.dart`). + +## MobX Store Implementation + +**Store Pattern**: All stores follow `StoreBase with _$StoreName` pattern: + +```dart +class SomeStore = SomeStoreBase with _$SomeStore; + +abstract class SomeStoreBase with Store { + @observable + var someValue = ''; + + @action + void updateValue(String value) => someValue = value; + + @computed + String get derivedValue => someValue.toUpperCase(); +} +``` + +**MobX Reactions** (for side effects and persistence): + +```dart +// Auto-save settings whenever they change (in main.dart) +autorun((_) => prefs.setString('settings', jsonEncode(settingsStore))); + +// React to specific state changes +reaction((_) => authStore.isLoggedIn, (_) => _selectedIndex = 0); +``` + +## Chat System Architecture + +- **Real-time IRC**: WebSocket connection to Twitch IRC with custom `IRCMessage` parsing +- **Third-party Emotes**: Asynchronous loading of BTTV, FFZ, and 7TV assets via dedicated APIs +- **Message Management**: 5000 message limit with 20% batch removal optimization +- **Assets Store**: `ChatAssetsStore` manages channel-specific emotes/badges +- **User Interaction**: Blocking, reporting, and moderation capabilities + +## Additional Patterns + +**Emote Architecture**: Base `Emote` class with platform-specific factories: `Emote.fromTwitch()`, `Emote.fromBTTV()`, `Emote.fromFFZ()`, `Emote.from7TV()`. + +**Custom Cache Manager**: Uses 30-day stale period and 10k max objects. `CustomCacheManager.removeOrphanedCacheFiles()` runs on startup to clean files not in database. + +**Secure Storage Cleanup**: First-run detection clears Flutter Secure Storage to handle Android/iOS uninstall edge case where secure storage persists but app data is wiped. + +**Authentication Flow**: +- OAuth via WebView with custom JavaScript injection for seamless Twitch login +- Token storage in FlutterSecureStorage +- Auto-refresh and validation logic in `AuthStore` + +## Code Style + +**Lint Rules** (from `analysis_options.yaml`): +- `prefer_single_quotes`, `always_use_package_imports`, `require_trailing_commas` +- `prefer_final_locals`, `prefer_final_in_for_each`, `avoid_redundant_argument_values` +- `directives_ordering`, `avoid_void_async`, `always_declare_return_types`, `unnecessary_parenthesis` + +## Commit Convention + +Commits use lowercase, descriptive messages without prefixes (e.g., `fix landscape bottom padding in chat bottom bar`, `add swipe pip gesture support`). Keep commits tightly scoped. diff --git a/CLAUDE.md b/CLAUDE.md index b9d22e4e..078c29c4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,127 +2,4 @@ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. -## Development Workflow - -**Plan Mode**: When in plan mode, interview thoroughly before coding: -- Ask detailed questions about technical implementation, UI/UX concerns, tradeoffs, and edge cases -- Continue asking questions until all requirements and non-obvious decisions are clear -- Don't begin implementation until all important details are resolved - -**Pattern Consistency**: When implementing new code: -- Search the codebase to find existing usages and implementations -- Prefer following established patterns, styles, and practices for consistency - -## Development Commands - -**Common Commands:** -- `flutter pub get` - Install dependencies -- `flutter run --dart-define=clientId=YOUR_CLIENT_ID --dart-define=secret=YOUR_CLIENT_SECRET` - Run with Twitch API credentials -- `flutter analyze` - Run static analysis and lint checks -- `flutter test` - Run all tests -- `flutter build apk` / `flutter build ios` - Build release binaries - -**Code Generation** (required after changing MobX stores or `@JsonSerializable` models): -- `dart run build_runner build` - Generate once -- `dart run build_runner build --delete-conflicting-outputs` - Force rebuild all -- `dart run build_runner watch` - Watch mode for development - -## Architecture Overview - -**State Management**: MobX with code generation. All stores end with `Store` and have corresponding `.g.dart` generated files. - -**Key Directories**: - -- `lib/screens/` - UI screens organized by feature (home, channel, settings, onboarding) - - Each screen has its own MobX stores in a `stores/` subdirectory -- `lib/models/` - Data models with JSON serialization (uses .g.dart files) -- `lib/apis/` - API services for Twitch, BTTV, FFZ, and 7TV -- `lib/widgets/` - Reusable UI components -- `lib/utils/` - Utility modules including context extensions - -**Main Application Flow**: - -1. App starts in `main.dart` with Firebase initialization and dependency injection via Provider -2. Authentication handled by `AuthStore` using Twitch OAuth -3. Settings persisted via `SettingsStore` with SharedPreferences and MobX `autorun()` -4. API services share a common Dio HTTP client for efficient connection reuse - -**Global Stores** (injected via Provider in `main.dart`): - -- `AuthStore` (`lib/screens/settings/stores/`) - Authentication state and token management -- `SettingsStore` (`lib/screens/settings/stores/`) - User preferences with automatic persistence via MobX `autorun()` -- `GlobalAssetsStore` (`lib/stores/`) - Shared cache for global emotes and badges across all chat tabs - -**HTTP & Auth**: Centralized Dio client (`DioClient.createClient()`) with connection pooling and optimized timeouts. `TwitchAuthInterceptor` auto-injects auth headers for Twitch API URLs. `UnauthorizedInterceptor` catches 401 errors for token refresh. Two-tier token system: default app token + optional user token in Flutter Secure Storage. - -## MobX Store Implementation - -**Store Pattern**: All stores follow `StoreBase with _$StoreName` pattern: - -```dart -class SomeStore = SomeStoreBase with _$SomeStore; - -abstract class SomeStoreBase with Store { - @observable - var someValue = ''; - - @action - void updateValue(String value) => someValue = value; - - @computed - String get derivedValue => someValue.toUpperCase(); -} -``` - -**MobX Reactions** (for side effects and persistence): - -```dart -// Auto-save settings whenever they change (in main.dart) -autorun((_) => prefs.setString('settings', jsonEncode(settingsStore))); - -// React to specific state changes -reaction((_) => authStore.isLoggedIn, (_) => _selectedIndex = 0); -``` - -## Chat System Architecture - -- **Real-time IRC**: WebSocket connection to Twitch IRC with custom `IRCMessage` parsing -- **Third-party Emotes**: Asynchronous loading of BTTV, FFZ, and 7TV assets via dedicated APIs -- **Message Management**: 5000 message limit with 20% batch removal optimization -- **Assets Store**: `ChatAssetsStore` manages channel-specific emotes/badges - -## Additional Patterns - -**Emote Architecture**: Base `Emote` class with platform-specific factories: `Emote.fromTwitch()`, `Emote.fromBTTV()`, `Emote.fromFFZ()`, `Emote.from7TV()`. - -**Custom Cache Manager**: Uses 30-day stale period and 10k max objects. `CustomCacheManager.removeOrphanedCacheFiles()` runs on startup to clean files not in database. - -**Secure Storage Cleanup**: First-run detection clears Flutter Secure Storage to handle Android/iOS uninstall edge case where secure storage persists but app data is wiped. - -## API Architecture - -**BaseApiClient Pattern**: All API services (`TwitchApi`, `BTTVApi`, `FFZApi`, `SevenTVApi`) extend `BaseApiClient` which provides: -- Generic GET/POST/PUT/DELETE methods with centralized error handling -- Automatic conversion of `DioException` to typed exceptions - -**Exception Hierarchy** (in `lib/apis/base_api_client.dart`): -- `ApiException` - Base class for all API errors -- `NetworkException` - Connection errors (no internet) -- `TimeoutException` - Request timeouts -- `ServerException` - 5xx server errors -- `NotFoundException` - 404 errors -- `UnauthorizedException` - 401 errors (triggers token refresh) - -## Code Style - -**Lint Rules** (from `analysis_options.yaml`): -- `prefer_single_quotes`, `always_use_package_imports`, `require_trailing_commas` -- `prefer_final_locals`, `prefer_final_in_for_each`, `avoid_redundant_argument_values` -- `directives_ordering`, `avoid_void_async`, `always_declare_return_types`, `unnecessary_parenthesis` - -**Other**: -- Generated `.g.dart` files must be committed alongside source changes - -## Commit Convention - -Commits use lowercase, descriptive messages without prefixes (e.g., `fix landscape bottom padding in chat bottom bar`, `add swipe pip gesture support`). Keep commits tightly scoped. +@AGENTS.md