diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 3e0b5a2..72a7185 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -65,6 +65,13 @@ android { } } +dependencies { + // AndroidX libraries for edge-to-edge support + implementation("androidx.activity:activity:1.9.2") + implementation("androidx.core:core:1.13.1") + implementation("androidx.activity:activity-ktx:1.9.2") +} + flutter { source = "../.." } diff --git a/android/app/src/main/kotlin/app/cogwheel/conduit/MainActivity.kt b/android/app/src/main/kotlin/app/cogwheel/conduit/MainActivity.kt index fd5fe0f..ab2c0cd 100644 --- a/android/app/src/main/kotlin/app/cogwheel/conduit/MainActivity.kt +++ b/android/app/src/main/kotlin/app/cogwheel/conduit/MainActivity.kt @@ -2,6 +2,7 @@ package app.cogwheel.conduit import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine +import android.os.Build import android.os.Bundle import androidx.core.view.WindowCompat @@ -10,7 +11,23 @@ class MainActivity : FlutterActivity() { override fun onCreate(savedInstanceState: Bundle?) { // Enable edge-to-edge display for Android 15+ compatibility - WindowCompat.setDecorFitsSystemWindows(window, false) + // This ensures proper handling of system bars and insets + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { + // For Android 15+ (API 35), try to use enableEdgeToEdge if available + try { + // Use reflection to call EdgeToEdge.enable() for forward compatibility + val edgeToEdgeClass = Class.forName("androidx.activity.EdgeToEdge") + val enableMethod = edgeToEdgeClass.getMethod("enable", android.app.Activity::class.java) + enableMethod.invoke(null, this) + } catch (e: Exception) { + // Fallback to WindowCompat if EdgeToEdge is not available + WindowCompat.setDecorFitsSystemWindows(window, false) + } + } else { + // For older versions, use WindowCompat for backward compatibility + WindowCompat.setDecorFitsSystemWindows(window, false) + } + super.onCreate(savedInstanceState) } diff --git a/lib/core/services/platform_service.dart b/lib/core/services/platform_service.dart index 95529a4..4119cd4 100644 --- a/lib/core/services/platform_service.dart +++ b/lib/core/services/platform_service.dart @@ -334,21 +334,74 @@ class PlatformService { // Avoid deprecated setStatusBarColor, setNavigationBarColor, setNavigationBarDividerColor SystemChrome.setSystemUIOverlayStyle( SystemUiOverlayStyle( - // Only set icon brightness, avoid deprecated color properties + // Only set icon brightness for edge-to-edge compatibility statusBarIconBrightness: isDarkContent ? Brightness.dark : Brightness.light, systemNavigationBarIconBrightness: isDarkContent ? Brightness.dark : Brightness.light, - // Use transparent colors for edge-to-edge + // Use transparent colors for proper edge-to-edge display statusBarColor: Colors.transparent, systemNavigationBarColor: Colors.transparent, + systemNavigationBarDividerColor: Colors.transparent, ), ); } } + /// Get proper inset handling for edge-to-edge display + static EdgeInsets getSystemInsets(BuildContext context) { + final mediaQuery = MediaQuery.of(context); + return EdgeInsets.only( + top: mediaQuery.viewPadding.top, + bottom: mediaQuery.viewPadding.bottom, + left: mediaQuery.viewPadding.left, + right: mediaQuery.viewPadding.right, + ); + } + + /// Get safe area insets for edge-to-edge display + static EdgeInsets getSafeAreaInsets(BuildContext context) { + final mediaQuery = MediaQuery.of(context); + return EdgeInsets.only( + top: mediaQuery.padding.top, + bottom: mediaQuery.padding.bottom, + left: mediaQuery.padding.left, + right: mediaQuery.padding.right, + ); + } + + /// Apply edge-to-edge safe area to widget + static Widget wrapWithEdgeToEdgeSafeArea( + Widget child, { + bool top = true, + bool bottom = true, + bool left = true, + bool right = true, + }) { + return SafeArea( + top: top, + bottom: bottom, + left: left, + right: right, + child: child, + ); + } + + /// Check if device supports edge-to-edge display + static bool supportsEdgeToEdge() { + if (isAndroid) { + // Android supports edge-to-edge from API 21+, but it's automatically + // enabled for apps targeting API 35+ (Android 15) + return true; + } else if (isIOS) { + // iOS supports edge-to-edge display + return true; + } + return false; + } + /// Check if device supports dynamic colors (Android 12+) static bool supportsDynamicColors() { // This would require platform channel implementation diff --git a/lib/main.dart b/lib/main.dart index 98b8461..9010e74 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -115,11 +115,19 @@ class _ConduitAppState extends ConsumerState { return supported.first; }, builder: (context, child) { - // Keep a subtle fade for navigation transitions only - final wrapped = OfflineIndicator( - child: child ?? const SizedBox.shrink(), + // Apply edge-to-edge inset handling and responsive design + return MediaQuery( + data: MediaQuery.of(context).copyWith( + // Ensure proper text scaling for edge-to-edge + textScaler: MediaQuery.of(context).textScaler.clamp( + minScaleFactor: 0.8, + maxScaleFactor: 1.3, + ), + ), + child: OfflineIndicator( + child: child ?? const SizedBox.shrink(), + ), ); - return wrapped; }, home: _getInitialPageWithReactiveState(), onGenerateRoute: NavigationService.generateRoute,