From 51ae862394d1d52bc22afbe53ea660bfbfd59596 Mon Sep 17 00:00:00 2001 From: Mike Kell Date: Sat, 11 Jul 2026 16:48:31 -0400 Subject: [PATCH] fix(mobile): resolve 8 Android debug errors and Kotlin migration - Migrate to Flutter built-in Kotlin: set builtInKotlin=true and newDsl=true in gradle.properties; remove id(kotlin-android) from app/build.gradle.kts. Eliminates the Kotlin Gradle Plugin WARNING that caused 8 stderr lines in the VS Code Debug console. - Fix DashboardController lifecycle in MobileShell: move controller creation from _buildBody() (called on every rebuild) to didChangeDependencies() so it is initialised once and reused. Prevents repeated data loads on every tab switch and resolves the 203 skipped frames Choreographer warning. - Fix KcSummaryCard RenderFlex overflow (8 cards, 19px each): reduce icon size 28->22px, switch spacing to xs, wrap value Text in FittedBox(scaleDown) with fontSize 28, use bodySmall + maxLines for label. Cards now fit within the GridView childAspectRatio:1.6 constraint on all phone screen sizes. All tests pass: 27 kell_mobile + 41 design_system. --- .../kell_mobile/android/app/build.gradle.kts | 1 - .../kell_mobile/android/gradle.properties | 4 ++ .../kell_mobile/lib/shell/mobile_shell.dart | 40 ++++++++++++++----- .../lib/src/widgets/kc_summary_card.dart | 17 ++++++-- 4 files changed, 48 insertions(+), 14 deletions(-) diff --git a/kell_creations_apps/apps/kell_mobile/android/app/build.gradle.kts b/kell_creations_apps/apps/kell_mobile/android/app/build.gradle.kts index 79fbcaa..fc6138e 100644 --- a/kell_creations_apps/apps/kell_mobile/android/app/build.gradle.kts +++ b/kell_creations_apps/apps/kell_mobile/android/app/build.gradle.kts @@ -1,6 +1,5 @@ plugins { id("com.android.application") - id("kotlin-android") // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. id("dev.flutter.flutter-gradle-plugin") } diff --git a/kell_creations_apps/apps/kell_mobile/android/gradle.properties b/kell_creations_apps/apps/kell_mobile/android/gradle.properties index fbee1d8..b2d843d 100644 --- a/kell_creations_apps/apps/kell_mobile/android/gradle.properties +++ b/kell_creations_apps/apps/kell_mobile/android/gradle.properties @@ -1,2 +1,6 @@ org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true +# This builtInKotlin flag was added automatically by Flutter migrator +android.builtInKotlin=true +# This newDsl flag was added automatically by Flutter migrator +android.newDsl=true diff --git a/kell_creations_apps/apps/kell_mobile/lib/shell/mobile_shell.dart b/kell_creations_apps/apps/kell_mobile/lib/shell/mobile_shell.dart index fa85697..7530bc8 100644 --- a/kell_creations_apps/apps/kell_mobile/lib/shell/mobile_shell.dart +++ b/kell_creations_apps/apps/kell_mobile/lib/shell/mobile_shell.dart @@ -30,8 +30,38 @@ class MobileShell extends StatefulWidget { class _MobileShellState extends State { int _selectedIndex = 0; + /// Dashboard controller is created once and reused across rebuilds to avoid + /// re-triggering data loads on every [setState] call (e.g. tab switches). + late DashboardController _dashboardController; + static const _titles = ['Dashboard', 'Inventory', 'Products', 'Orders', 'More']; + @override + void didChangeDependencies() { + super.didChangeDependencies(); + // Initialise the controller here (not in initState) because it needs + // KcAppScope which requires an inherited widget lookup. + if (!_dashboardControllerInitialised) { + final services = KcAppScope.of(context); + _dashboardController = DashboardController( + GetDashboardSummary( + inventoryRepository: services.inventoryRepository, + productPublishingRepository: services.productPublishingRepository, + ordersRepository: services.ordersRepository, + ), + ); + _dashboardControllerInitialised = true; + } + } + + bool _dashboardControllerInitialised = false; + + @override + void dispose() { + _dashboardController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { final config = KcAppScope.configOf(context); @@ -86,15 +116,7 @@ class _MobileShellState extends State { switch (_selectedIndex) { case 0: - return MobileDashboardPage( - controller: DashboardController( - GetDashboardSummary( - inventoryRepository: services.inventoryRepository, - productPublishingRepository: services.productPublishingRepository, - ordersRepository: services.ordersRepository, - ), - ), - ); + return MobileDashboardPage(controller: _dashboardController); case 1: return MobileInventoryPage( repository: services.inventoryRepository, diff --git a/kell_creations_apps/packages/design_system/lib/src/widgets/kc_summary_card.dart b/kell_creations_apps/packages/design_system/lib/src/widgets/kc_summary_card.dart index 764311f..6766304 100644 --- a/kell_creations_apps/packages/design_system/lib/src/widgets/kc_summary_card.dart +++ b/kell_creations_apps/packages/design_system/lib/src/widgets/kc_summary_card.dart @@ -36,11 +36,20 @@ class KcSummaryCard extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - Icon(icon, color: iconColor, size: 28), - const SizedBox(height: KcSpacing.sm), - Text(value, style: theme.textTheme.headlineMedium?.copyWith(fontSize: 32)), + Icon(icon, color: iconColor, size: 22), const SizedBox(height: KcSpacing.xs), - Text(label, style: theme.textTheme.bodyMedium?.copyWith(color: KcColors.neutral)), + FittedBox( + fit: BoxFit.scaleDown, + alignment: Alignment.centerLeft, + child: Text(value, style: theme.textTheme.headlineMedium?.copyWith(fontSize: 28)), + ), + const SizedBox(height: KcSpacing.xs), + Text( + label, + style: theme.textTheme.bodySmall?.copyWith(color: KcColors.neutral), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), ], ), );