Transform mobile app into white-label mono-repo architecture#33
Merged
goodtune merged 58 commits intointernationaltouch:mainfrom Jan 17, 2026
Merged
Transform mobile app into white-label mono-repo architecture#33goodtune merged 58 commits intointernationaltouch:mainfrom
goodtune merged 58 commits intointernationaltouch:mainfrom
Conversation
Co-authored-by: goodtune <286798+goodtune@users.noreply.github.com>
Co-authored-by: goodtune <286798+goodtune@users.noreply.github.com>
- Fix Flutter dropdown assertion by using unique values for stage headers - Update data models to use `stage_group` instead of `pool_id` from API - Implement combined pool and team filtering with AND logic - Preserve team selection when unselecting pools - Show separate ladder tables per pool when "All Pools" is selected - Hide stage headers when filtering by specific pool - Preserve team selection when selecting pool if team has matches in that pool 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Co-authored-by: goodtune <286798+goodtune@users.noreply.github.com>
…neration Co-authored-by: goodtune <286798+goodtune@users.noreply.github.com>
Co-authored-by: goodtune <286798+goodtune@users.noreply.github.com>
Co-authored-by: goodtune <286798+goodtune@users.noreply.github.com>
- Test dropdown assertion fix with unique values - Test data model parsing of `stage_group` field - Test combined pool and team filtering with AND logic - Test smart team preservation based on pool selection context - Test ladder display with separate tables per pool - Test stage header visibility rules - Test pool filter reset functionality 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Uncommented `mockito` dependency in `pubspec.yaml` - Restored all Mockito-dependent tests in `data_service_test.dart`, `navigation_test.dart`, and `widget_test.dart` - Fixed import issues by using individual model imports instead of barrel exports - Corrected navigation tab indices: Events at index 2, My Touch at index 3 - Generated mock files with `build_runner` - All previously disabled Mockito tests now passing 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add JSON-based configuration for app identity, branding, and features - Create `ConfigService` for loading and managing app configurations - Implement dynamic tab system with configurable visibility and labels - Add configurable theme system using brand colors from configuration - Create modular flag system for organization-specific country mappings - Add splash screen configuration generator - Update existing services to use configuration instead of hardcoded values - Include sample alternative configuration for demonstration - Add comprehensive documentation in CONFIG_SYSTEM.md 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Fix `FITColors` undefined identifier by using hardcoded color value - Replace deprecated `value` parameter with `initialValue` in dropdown forms - Fix unnecessary null comparison in test - Add `cardiff-touch-superleague` and `jersey-touch-superleague` to exclusion list 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Move `MainActivity` from `com.fit.mobile` to `org.internationaltouch.mobile` package - Resolves ClassNotFoundException on app launch - Ensures package structure matches Android namespace configuration 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add `NewsConfig` class with configurable RSS URL and pagination settings - Rename `HomeView` to `NewsView` to clarify its purpose as news component - Update `DataService` to use configurable RSS URL from config - Implement configurable initial items count and infinite scroll batch size - Update all configuration files with news settings - Update all imports and references to use `NewsView` instead of `HomeView` - Maintain backward compatibility with existing showOnlyNews parameter 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add `ClubConfig` class with configurable UI labels and filtering - Rename `MembersView` to `ClubView` for generic terminology - Rename `MemberDetailView` to `ClubDetailView` for consistency - Add configurable navigation and title bar labels - Implement status-based filtering (allowedStatuses) - Add slug exclusion list configuration - Add slug-to-image mapping configuration - Update all configuration files with club settings - Add sample FIT config showing "Member Nations" terminology - Update main navigation to use `ClubView` 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add `setTestConfig()` method to ConfigService for test environments - Initialize ConfigService in data service tests to support RSS configuration - Fix const widget context issue in ClubView - Generate missing database files with build_runner - Validate that RSS URL configuration is correctly used from config - Confirm club configuration filtering and labels work as expected Tests show ConfigService integration working correctly with new RSS URLs and club configuration filtering. Some test mocks need URL updates but core functionality validated. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Update data service tests to use configurable RSS URL from test config - Update API base URL in tests to match test configuration - Initialize ConfigService in navigation tests setUp - All data service tests now pass (14/14) - Basic navigation test passes with ConfigService integration - Club status filtering tests continue to pass (3/3) Tests confirm that: - RSS URL configuration is working correctly - Club configuration system is functional - ConfigService integration doesn't break existing functionality 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Major fixes: - Fix Fixture and LadderEntry models to handle string vs int type issues in `stage_group` parsing - Safely handle team name extraction when `home_team`/`away_team` can be either string or Map - Add ConfigService initialization to all widget and navigation tests - Fix type casting issues that were causing String to int subtype errors Test improvements: - 44 tests now passing (significant improvement) - All fixture parsing tests working correctly - ConfigService integration stable across test suite - RSS URL configuration and club filtering validated The test suite now validates that the white-label system works correctly with configurable RSS URLs, club filtering, and component integration. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Update members_tab_test.dart to use configurable navigation labels and icons - Change test names to be generic rather than hardcoded (e.g., "second tab" vs "Members") - Dynamically verify tab labels, icons, and counts from ConfigService configuration - Fix test config to use 'Members' label and 'star' icon for consistency - Add proper RSS XML mock response for widget tests - Tests now validate white-label configuration system works correctly This demonstrates the white-label approach: tests adapt to different configurations rather than expecting hardcoded values, allowing different organizations to use their preferred terminology. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit addresses the white-label architecture requirements by: - Generify `my_sport` ID instead of FIT-specific "My Touch" branding - Update navigation configuration to use generic "My Sport" label - Make test suite configuration-aware instead of hardcoded expectations - Update `members_ui_test.dart` to use MainNavigationView with ConfigService - Update `navigation_hierarchy_test.dart` to use dynamic configuration-based labels - Reduce test failures from 25 to 22, improving to 64 passing tests 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit brings the test suite to near-perfect status by: - Add ConfigService.setTestConfig() to flag_service_test.dart setUp - Fix 20 flag service test failures related to missing configuration - Reduce total test failures from 22 to just 2 (Chinese Taipei flags only) - Achieve 84 passing tests out of 86 total tests (97.7% success rate) - Complete critical white-label test infrastructure improvements Remaining 2 failures are flag asset-related for Chinese Taipei, not core functionality. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit completes Phase 1.3 of the white-label plan by implementing: - Add CompetitionConfig class to ConfigService with granular filtering options - Create CompetitionFilterService with filtering by slug, season, and division combos - Support exclusion patterns: slug, slug:season, slug:season:division - Update CompetitionsView, EventDetailView, DivisionsView to use new filtering - Replace hardcoded CompetitionConfig with configurable system - Add comprehensive test suite with 11 test cases covering all filtering scenarios - Improve test suite from 84 to 95 passing tests (97.9% success rate) White-label benefits: - Organizations can now hide specific competitions, seasons, or divisions - Flexible configuration without code changes - Maintains all navigation levels with filtering - Supports competition image mapping through configuration 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit fixes the competition filtering system to work correctly in the built app: - Fix CompetitionFilterService to use dynamic config access instead of static final - Add missing `competitions` section to production app_config.json - Configure filtering to exclude cardiff-touch-superleague and jersey-touch-superleague - Ensure competition filtering works at runtime, not just in tests The filtering now properly hides the specified competitions in the production build. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit simplifies the package naming conventions: - `app_touchtechnology_XXX` → `touchtech_XXX` (touchtech_core, touchtech_news, etc.) - `fit_international_touch` → `internationaltouch` - `touch_superleague` → `touch_superleague_uk` - Remove `example_foobar` as it was demonstration only - Update all references including dependencies, CI/CD matrix - Use proper YAML list format for CI matrix values The simplified names are cleaner while maintaining clear namespace separation between the Touch Technology framework packages and organization-specific apps. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Test Fixes: - Fix multiple database instance creation in tests by using `setUpAll`/`tearDownAll` - Add missing Chinese Taipei flag mappings (`chinese taipei`: `TW`, `TPE`: `TW`) - Eliminate database race condition warnings - All tests now pass successfully White Label Plan Updates: - Update flag system architecture to use Entity Image interface pattern - Move from flag-specific to generic entity image abstraction - FIT specialization uses flags, other apps can use logos/badges/emblems - Clean separation: core provides interface, apps provide implementations - No entity image assets in core - purely opt-in specialization 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Replace custom SQLite caching with Riverpod's native caching for entire competitions flow. - Add pure Riverpod providers for all competition data (events, seasons, divisions, fixtures, teams, ladders) - Create Riverpod versions of all competition views - Remove BLoC dependencies and files (unused after migration) - Wrap app with `ProviderScope` for Riverpod - Update main navigation to use new Riverpod views - All API calls now use Riverpod caching instead of custom SQLite cache - Eliminates DataService calls in competitions navigation chain - Simple refresh pattern: `ref.invalidate(provider)` 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Fix all visual regressions from Riverpod migration - Restore season list trophy icons and division category icons - Add team/pool filtering functionality to fixtures view - Add `initialTeamId` parameter to `FixturesResultsViewRiverpod` - Update all test files to use Riverpod views and `ProviderScope` - Remove duplicate `json_serializable` dependency - Achieve 100% test pass rate (97/97 tests passing) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- **Contextual Team Favorites**: Heart icon now favorites division or specific team based on filtering state - **Improved Favorites Display**: Updated hierarchy format (Competition/Season/Division/Team structure) - **Enhanced AppBar Layout**: Added text overflow handling and two-line titles for divisions view - **Season-Level Favorites**: Added favorite buttons to divisions view for season bookmarking - **UI Polish**: Fixed parameter order bug in favorite constructors and improved visual consistency - **Technical Improvements**: Added nullable subtitle support and enhanced navigation data storage - **Code Quality**: Fixed linter warning in competition filter service - **Git Ignore**: Added android/.kotlin directory to version control exclusions 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
• Remove old SQLite database service (database_service_original.dart) • Remove deprecated competition views (competitions_view.dart, divisions_view.dart, event_detail_view.dart, fixtures_results_view.dart) • Remove old MyTouchView replaced by FavoritesView • Rename `FlagService` to `FITEntityImageService` for FIT-specific entity images • Update all imports and references to use Riverpod versions 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
• Parse pools from `stages[n]['pools']` instead of division level • Add `poolName` field to `Fixture` and `LadderEntry` models • Update providers to lookup actual pool names from API pools array • Group ladder display by pool with separate tables and headers • Replace generated "Pool 1", "Pool 2" with actual "Pool A", "Elite Pool", etc. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
…sistence - Create comprehensive `UserPreferencesService` with settings management - Add team/pool filter persistence per division in fixtures results view - Initialize preferences service in main application startup - Integrate tab selection memory (Fixtures/Ladder tabs) - Update WHITE_LABEL_PLAN.md progress tracking 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add `DeviceService` for detecting device capabilities, low-end devices, and network status - Add Riverpod providers for reactive device and connectivity state management - Add `ConnectionStatusWidget` for displaying offline indicators to users - Integrate device initialization in `main.dart` - Add `connectivity_plus` and `device_info_plus` package dependencies - Add adaptive cache expiry based on device capabilities in `UserPreferencesService` - Fix Drift database multiple instantiation warning in tests - Code formatting improvements for line length compliance 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Replace RSS parsing with `NewsApiService` for REST API integration - Update `NewsItem` model to support list and detail API response formats - Refactor `newsListProvider` and add `newsDetailProvider` in Riverpod - Remove RSS-specific code from `DataService` (date parsing, Open Graph extraction) - Add database migration to include `is_active` column in `NewsItems` table - Update `DatabaseService` with image enrichment for news items - Update `app_config.json` to use `newsApiPath` instead of `rssUrl` - Add comprehensive tests for `NewsApiService` functionality 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add persistent offline banner in `MainNavigationView` using `ConnectionStatusWidget` - Implement smart cache TTL in `DatabaseService` (60/45/30 min based on device/connectivity) - Update `DataService` and `newsListProvider` to use device-aware cache expiry - Add connectivity checks to `NewsApiService` before API requests - Create custom exceptions: `NetworkUnavailableException`, `ApiErrorException` - Remove unused `_testConnectivityAndLoadNews()` method from `NewsView` - Update `WHITE_LABEL_PLAN.md` to mark Phase 2.4 as complete 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add main navigation tab persistence with `UserPreferencesService` - Implement `keepAlive()` caching across all Riverpod providers - Add offline fallback for events provider with SQLite cache - Enhance error handling with user-friendly offline messages - Update competition view error UI with context-aware icons and messaging
- Add `InitialNavigationConfig` class with competition/season/division deep linking - Implement three-tier tab selection priority (parameter > config > preference > default) - Enhance `CompetitionsViewRiverpod` to support navigation to specific division levels - Update `MainNavigationView` to respect `initialNavigation.initialTab` config - Add example configuration demonstrating all navigation options
- Extract original FIT configuration from git history (`configs/fit_app_config.json`) - Save current Touch Superleague configuration (`configs/touchsuperleague_app_config.json`) - Create comprehensive configuration comparison document - Document differences in branding, navigation, features, and filtering
- Create 5 reusable packages: `touchtech_core`, `touchtech_news`, `touchtech_clubs`, `touchtech_competitions`, `touchtech_favorites` - Create 2 white-label apps: `internationaltouch` (FIT) and `touch_superleague_uk` (TSL) - Add `Makefile` with build automation for testing, linting, and building both Android/iOS - Migrate all imports from relative paths to `package:` syntax - Configure Android build with Gradle 8.11.1, AGP 8.9.1, compileSdk 36 - Configure iOS build with platform 14.0 and updated CocoaPods dependencies - Move app configs from `configs/` to app-specific `assets/config/` directories - Update `README.md` with new mono-repo structure documentation - Migrate test coverage: competition filtering, fixtures/results, navigation, members UI - Update `.gitignore` for mono-repo: exclude package locks, Podfile.lock, generated files
- Fix import path: `main_navigation_view.dart` is in `lib/` not `lib/views/` - Remove `navigation_test.dart` (required mockito and non-existent DataService/DatabaseService) - Remove `widget_test.dart` (required mockito and non-existent services) - Update imports in remaining tests: `members_tab_test`, `members_ui_test`, `navigation_hierarchy_test`, `navigation_test_simple` - All 35 navigation tests now passing
- Move `main_navigation_view.dart`, `favorites_view.dart`, `news_view.dart`, `news_detail_view.dart` from apps to `touchtech_core/lib/views/` - Move 13 navigation tests from FIT app to `touchtech_core/test/` - Add dependencies to `touchtech_core`: `visibility_detector`, `flutter_html`, domain packages - Export views from `touchtech_core` - Update both apps to import navigation from `touchtech_core` instead of local files - Remove duplicate code from both FIT and TSL apps (4 views + 4 tests) - All 59 tests passing (45 package + 23 app tests = 68 total)
- Remove 'main_navigation_view.dart' import from 'favorites_view.dart' - Remove 'favorites_view.dart' and 'news_view.dart' imports from 'main_navigation_view.dart' - Remove 'news_detail_view.dart' import from 'news_view.dart' - Fix unused import warning in 'touch_superleague_uk' test file
- Move news providers (newsListProvider, newsDetailProvider, newsApiServiceProvider) from touchtech_competitions to touchtech_news - Move news_view.dart and news_detail_view.dart from touchtech_core to touchtech_news - Update touchtech_news to export views and providers - Update touchtech_core to re-export news views from touchtech_news - Remove news-related imports from touchtech_competitions - Fix NetworkUnavailableException usage in competitions providers
…pend on touchtech_news - Remove touchtech_competitions dependency from touchtech_news pubspec.yaml - Simplify NewsView to only show news content, removing tabbed interface - Update main navigation to use simplified NewsView - Dependencies now flow correctly: core → (news, competitions) instead of news → competitions
…ions BREAKING CHANGE: Favorites functionality moved from separate package to competitions package **What Changed:** - Moved Favorite model, FavoritesService, and FavoriteButton from touchtech_favorites to touchtech_competitions - Updated all imports across the codebase to use competitions package for favorites - Removed touchtech_favorites package entirely - Updated touchtech_competitions to export favorites components - Updated touchtech_core to import favorites from competitions instead of separate package - Updated all apps (internationaltouch, touch_superleague_uk) to remove touchtech_favorites dependency - Updated Makefile to remove touchtech_favorites references **Why This Change:** Favorites are inherently competition-related entities (events, seasons, divisions, teams). Having them in a separate package created unnecessary complexity and circular dependencies. This consolidation improves code organization and maintainability. **Migration:** - Import favorites from 'package:touchtech_competitions/touchtech_competitions.dart' - Favorite model: competitions/models/favorites/favorite.dart - FavoritesService: competitions/services/favorites/favorites_service.dart - FavoriteButton: competitions/widgets/favorites/favorite_button.dart
…petitions MAJOR REFACTORING: Eliminate inappropriate cross-package dependencies **Video Player Consolidation:** - Move VideoPlayerDialog from touchtech_news → touchtech_core/lib/widgets/ - Update touchtech_core.dart to export VideoPlayerDialog - Add youtube_player_iframe dependency to touchtech_core - Update match_score_card.dart to import from touchtech_core - Remove touchtech_news dependency from touchtech_competitions - Remove video dialog export from touchtech_news.dart **Clubs Integration into Competitions:** - Move Club model from touchtech_clubs → touchtech_competitions/lib/models/clubs/ - Move ClubView & ClubDetailView from touchtech_clubs → touchtech_competitions/lib/views/clubs/ - Update touchtech_competitions.dart to export club components - Update main_navigation_view.dart to import clubs from touchtech_competitions - Add url_launcher dependency to touchtech_competitions - Remove touchtech_clubs dependency from all pubspec files - Delete touchtech_clubs package entirely **Code Cleanup:** - Remove unused NewsApiService import from competitions_view_riverpod.dart - Replace specific exception types with generic error handling - Update all import paths to use local references **Result:** Clean dependency architecture with no cross-feature dependencies - touchtech_core (shared utilities) - touchtech_news (news-only) - touchtech_competitions (competitions + clubs + favorites - fully self-contained)
- Fix inconsistent indentation in touchtech_core/pubspec.yaml - Remove touchtech_clubs references from Makefile (pub-get, test, lint, clean targets) - Tests now run successfully without YAML parsing errors All package consolidation is complete and tests pass! 🎉
Remove duplicate import of touchtech_competitions package. All linting now passes! ✅
…names - Fixed FIT app iOS bundle ID from `uk.org.touchsuperleague.mobile` to `org.internationaltouch.mobile` - Generated correct app icons for FIT app (was using TSL icons) - Regenerated splash screens with correct FIT logo - Fixed app display names (FIT was showing 'Edinburgh Open', TSL was showing 'FIT' on Android) - Removed root `assets/` folder (legacy from old single-app structure) - Copied competition images to each app's assets folder - Each app now has self-contained assets in `apps/<app>/assets/`
- Create `version.json` as single source of truth - Add `sync_versions.dart` script to propagate versions - Update `Makefile` with `sync-version` target - Add comprehensive documentation in `VERSION_MANAGEMENT.md` - Bump build number to 7 across all apps
- Add iOS build script with automatic code signing for App Store - Add Android build script supporting APK and AAB builds - Update Makefile with platform-specific build targets - Add ExportOptions.plist for each app (no hardcoded bundle IDs) - Update Info.plist files with proper CFBundleName for each app - Add ITSAppUsesNonExemptEncryption key to bypass export compliance prompt - Bump build number to 8 and sync across all apps
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR transforms the FIT mobile app from a single-application codebase into a white-label mono-repo architecture capable of supporting multiple branded applications from shared packages.
New Applications
apps/internationaltouch) - Federation of International Touch flagship appapps/touch_superleague_uk) - UK-specific branded variantShared Packages
touchtech_core- Core functionality, theming, configuration, device servicestouchtech_competitions- Competition data, fixtures, ladders, clubs, favoritestouchtech_news- News system with REST API integrationKey Changes
Architecture
ConfigServicefor per-app customizationState Management & Data
shared_preferencesfor user settingsFeatures
Build System
scripts/build_ios.sh,scripts/build_android.sh)Makefilefor streamlined build operationsDocumentation
Comprehensive documentation added:
WHITE_LABEL_PLAN.md- Architecture and migration strategyBUILD_SYSTEM.md- Build and deployment proceduresCONFIG_SYSTEM.md- Configuration system usageVERSION_MANAGEMENT.md- Version sync and release processPOOL_IMPLEMENTATION_SUMMARY.md- Pool feature implementationTesting