6.1 KiB
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 dependenciesflutter run --dart-define=clientId=YOUR_CLIENT_ID --dart-define=secret=YOUR_CLIENT_SECRET- Run with Twitch API credentialsflutter analyze- Run static analysis and lint checksflutter test- Run all testsflutter test test/path/to/test.dart- Run a single test fileflutter build apk/flutter build ios- Build release binaries
Code Generation (required after changing MobX stores or @JsonSerializable models):
dart run build_runner build- Generate oncedart run build_runner build --delete-conflicting-outputs- Force rebuild alldart 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 7TVlib/widgets/- Reusable UI componentslib/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:
- App starts in
main.dartwith Firebase initialization and dependency injection via Provider - Authentication handled by
AuthStoreusing Twitch OAuth - Settings persisted via
SettingsStorewith SharedPreferences and MobXautorun() - 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 managementSettingsStore(lib/screens/settings/stores/) - User preferences with automatic persistence via MobXautorun()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
DioExceptionto 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:
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):
// 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
IRCMessageparsing - 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:
ChatAssetsStoremanages 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_commasprefer_final_locals,prefer_final_in_for_each,avoid_redundant_argument_valuesdirectives_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.