diff --git a/app/src/main/java/dev/hossain/weatheralert/MainActivity.kt b/app/src/main/java/dev/hossain/weatheralert/MainActivity.kt index 2d488fe6..a4f60e9d 100644 --- a/app/src/main/java/dev/hossain/weatheralert/MainActivity.kt +++ b/app/src/main/java/dev/hossain/weatheralert/MainActivity.kt @@ -5,6 +5,7 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge +import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo import com.slack.circuit.backstack.rememberSaveableBackStack import com.slack.circuit.foundation.Circuit import com.slack.circuit.foundation.CircuitCompositionLocals @@ -17,6 +18,7 @@ import dev.hossain.weatheralert.di.AppScope import dev.hossain.weatheralert.network.NetworkMonitor import dev.hossain.weatheralert.ui.alertslist.CurrentWeatherAlertScreen import dev.hossain.weatheralert.ui.theme.WeatherAlertAppTheme +import dev.hossain.weatheralert.ui.theme.dimensions import javax.inject.Inject @ContributesMultibinding(AppScope::class, boundType = Activity::class) @@ -32,7 +34,8 @@ class MainActivity enableEdgeToEdge() setContent { - WeatherAlertAppTheme { + val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass + WeatherAlertAppTheme(dimensions = windowSizeClass.windowWidthSizeClass.dimensions()) { // See https://slackhq.github.io/circuit/navigation/ val backStack = rememberSaveableBackStack(root = CurrentWeatherAlertScreen("root")) val navigator = rememberCircuitNavigator(backStack) diff --git a/app/src/main/java/dev/hossain/weatheralert/ui/addalert/AddNewWeatherAlertScreen.kt b/app/src/main/java/dev/hossain/weatheralert/ui/addalert/AddNewWeatherAlertScreen.kt index ddfbc800..e905c835 100644 --- a/app/src/main/java/dev/hossain/weatheralert/ui/addalert/AddNewWeatherAlertScreen.kt +++ b/app/src/main/java/dev/hossain/weatheralert/ui/addalert/AddNewWeatherAlertScreen.kt @@ -94,6 +94,7 @@ import dev.hossain.weatheralert.di.AppScope import dev.hossain.weatheralert.ui.addapikey.BringYourOwnApiKeyScreen import dev.hossain.weatheralert.ui.serviceConfig import dev.hossain.weatheralert.ui.theme.WeatherAlertAppTheme +import dev.hossain.weatheralert.ui.theme.dimensions import dev.hossain.weatheralert.util.Analytics import kotlinx.coroutines.launch import kotlinx.parcelize.Parcelize @@ -376,7 +377,7 @@ fun AddNewWeatherAlertScreen( modifier .fillMaxSize() .padding(contentPaddingValues) - .padding(horizontal = 24.dp) + .padding(horizontal = MaterialTheme.dimensions.horizontalScreenPadding) .verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(24.dp), ) { diff --git a/app/src/main/java/dev/hossain/weatheralert/ui/addapikey/ByoApiKeyScreen.kt b/app/src/main/java/dev/hossain/weatheralert/ui/addapikey/ByoApiKeyScreen.kt index 4705313a..3d992231 100644 --- a/app/src/main/java/dev/hossain/weatheralert/ui/addapikey/ByoApiKeyScreen.kt +++ b/app/src/main/java/dev/hossain/weatheralert/ui/addapikey/ByoApiKeyScreen.kt @@ -71,6 +71,7 @@ import dev.hossain.weatheralert.ui.WeatherServiceLogoConfig import dev.hossain.weatheralert.ui.alertslist.CurrentWeatherAlertScreen import dev.hossain.weatheralert.ui.serviceConfig import dev.hossain.weatheralert.ui.theme.WeatherAlertAppTheme +import dev.hossain.weatheralert.ui.theme.dimensions import dev.hossain.weatheralert.util.Analytics import kotlinx.coroutines.launch import kotlinx.parcelize.Parcelize @@ -271,7 +272,7 @@ fun BringYourOwnApiKeyScreen( modifier .fillMaxSize() .padding(contentPaddingValues) - .padding(horizontal = 24.dp) + .padding(horizontal = MaterialTheme.dimensions.horizontalScreenPadding) .verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(24.dp), ) { diff --git a/app/src/main/java/dev/hossain/weatheralert/ui/alertslist/CurrentAlertScreen.kt b/app/src/main/java/dev/hossain/weatheralert/ui/alertslist/CurrentAlertScreen.kt index e18eecff..ad5a5846 100644 --- a/app/src/main/java/dev/hossain/weatheralert/ui/alertslist/CurrentAlertScreen.kt +++ b/app/src/main/java/dev/hossain/weatheralert/ui/alertslist/CurrentAlertScreen.kt @@ -94,6 +94,7 @@ import dev.hossain.weatheralert.network.NetworkMonitor import dev.hossain.weatheralert.ui.addalert.AddNewWeatherAlertScreen import dev.hossain.weatheralert.ui.details.WeatherAlertDetailsScreen import dev.hossain.weatheralert.ui.settings.UserSettingsScreen +import dev.hossain.weatheralert.ui.theme.dimensions import dev.hossain.weatheralert.util.Analytics import dev.hossain.weatheralert.util.formatUnit import dev.hossain.weatheralert.util.parseMarkdown @@ -377,7 +378,11 @@ fun AlertTileGrid( ) { LazyColumn( modifier = Modifier.fillMaxSize(), - contentPadding = PaddingValues(vertical = 12.dp, horizontal = 16.dp), + contentPadding = + PaddingValues( + vertical = MaterialTheme.dimensions.verticalScreenPadding, + horizontal = MaterialTheme.dimensions.horizontalScreenPadding, + ), ) { itemsIndexed( items = tiles, diff --git a/app/src/main/java/dev/hossain/weatheralert/ui/alertslist/EmptyAlertView.kt b/app/src/main/java/dev/hossain/weatheralert/ui/alertslist/EmptyAlertView.kt index be8afdf6..0f1f7a02 100644 --- a/app/src/main/java/dev/hossain/weatheralert/ui/alertslist/EmptyAlertView.kt +++ b/app/src/main/java/dev/hossain/weatheralert/ui/alertslist/EmptyAlertView.kt @@ -23,6 +23,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import dev.hossain.weatheralert.R import dev.hossain.weatheralert.ui.theme.WeatherAlertAppTheme +import dev.hossain.weatheralert.ui.theme.dimensions @Composable fun EmptyAlertState(modifier: Modifier = Modifier) { @@ -31,7 +32,7 @@ fun EmptyAlertState(modifier: Modifier = Modifier) { modifier .fillMaxSize() .verticalScroll(rememberScrollState()) - .padding(horizontal = 24.dp), + .padding(horizontal = MaterialTheme.dimensions.horizontalScreenPadding), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, ) { @@ -78,7 +79,11 @@ fun EmptyAlertState(modifier: Modifier = Modifier) { .alpha(0.9f), contentDescription = "Tomorrow.io Logo", ) - Image( + + // Open-Mateo is disabled due to some inconsistencies discovered + // See https://github.com/hossain-khan/android-weather-alert/pull/165 + + /*Image( painter = painterResource(id = R.drawable.open_mateo_logo), modifier = Modifier @@ -89,7 +94,7 @@ fun EmptyAlertState(modifier: Modifier = Modifier) { // Reduces intensity by a bit .alpha(0.9f), contentDescription = "Tomorrow.io Logo", - ) + )*/ } } } diff --git a/app/src/main/java/dev/hossain/weatheralert/ui/details/WeatherAlertDetails.kt b/app/src/main/java/dev/hossain/weatheralert/ui/details/WeatherAlertDetails.kt index d8730024..79233325 100644 --- a/app/src/main/java/dev/hossain/weatheralert/ui/details/WeatherAlertDetails.kt +++ b/app/src/main/java/dev/hossain/weatheralert/ui/details/WeatherAlertDetails.kt @@ -65,6 +65,7 @@ import dev.hossain.weatheralert.db.UserCityAlert import dev.hossain.weatheralert.di.AppScope import dev.hossain.weatheralert.ui.serviceConfig import dev.hossain.weatheralert.ui.theme.WeatherAlertAppTheme +import dev.hossain.weatheralert.ui.theme.dimensions import dev.hossain.weatheralert.util.Analytics import dev.hossain.weatheralert.util.formatToDate import dev.hossain.weatheralert.util.formatUnit @@ -211,7 +212,7 @@ fun WeatherAlertDetailsScreen( modifier .fillMaxSize() .padding(contentPaddingValues) - .padding(horizontal = 24.dp) + .padding(horizontal = MaterialTheme.dimensions.horizontalScreenPadding) .verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(16.dp), ) { diff --git a/app/src/main/java/dev/hossain/weatheralert/ui/settings/UserSettingsScreen.kt b/app/src/main/java/dev/hossain/weatheralert/ui/settings/UserSettingsScreen.kt index 76921f19..bccfa77b 100644 --- a/app/src/main/java/dev/hossain/weatheralert/ui/settings/UserSettingsScreen.kt +++ b/app/src/main/java/dev/hossain/weatheralert/ui/settings/UserSettingsScreen.kt @@ -69,6 +69,7 @@ import dev.hossain.weatheralert.di.AppScope import dev.hossain.weatheralert.ui.addapikey.BringYourOwnApiKeyScreen import dev.hossain.weatheralert.ui.serviceConfig import dev.hossain.weatheralert.ui.theme.WeatherAlertAppTheme +import dev.hossain.weatheralert.ui.theme.dimensions import dev.hossain.weatheralert.util.Analytics import dev.hossain.weatheralert.work.scheduleWeatherAlertsWork import dev.hossain.weatheralert.work.supportedWeatherUpdateInterval @@ -190,13 +191,13 @@ fun UserSettingsScreen( }, ) }, - ) { padding -> + ) { contentPaddingValues -> Column( modifier = modifier .fillMaxSize() - .padding(padding) - .padding(horizontal = 16.dp) + .padding(contentPaddingValues) + .padding(horizontal = MaterialTheme.dimensions.horizontalScreenPadding) .verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(16.dp), ) { diff --git a/app/src/main/java/dev/hossain/weatheralert/ui/theme/Dimension.kt b/app/src/main/java/dev/hossain/weatheralert/ui/theme/Dimension.kt new file mode 100644 index 00000000..b44b5d12 --- /dev/null +++ b/app/src/main/java/dev/hossain/weatheralert/ui/theme/Dimension.kt @@ -0,0 +1,86 @@ +package dev.hossain.weatheralert.ui.theme + +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.window.core.layout.WindowWidthSizeClass + +// For background, see: +// - https://github.com/hossain-khan/android-weather-alert/issues/126 +// - https://bsky.app/profile/hossain.dev/post/3lflhafgn622p + +/** + * Data class to hold dimension values for padding and screen spacing. + */ +data class Dimensions( + val smallPadding: Dp, + val mediumPadding: Dp, + val largePadding: Dp, + val horizontalScreenPadding: Dp, + val verticalScreenPadding: Dp, +) + +/** + * CompositionLocal to provide the current Dimensions instance. + */ +val LocalDimensions = + staticCompositionLocalOf { + Dimensions( + smallPadding = 16.dp, + mediumPadding = 24.dp, + largePadding = 32.dp, + horizontalScreenPadding = 16.dp, + verticalScreenPadding = 16.dp, + ) + } + +/** + * Extension property to access the current Dimensions instance from MaterialTheme. + */ +val MaterialTheme.dimensions: Dimensions + @Composable + get() = LocalDimensions.current + +/** + * Extension function to get Dimensions based on the WindowWidthSizeClass. + * + * @receiver WindowWidthSizeClass The current window size class. + * @return Dimensions The corresponding Dimensions instance. + */ +internal fun WindowWidthSizeClass.dimensions(): Dimensions = + when (this) { + WindowWidthSizeClass.COMPACT -> + Dimensions( + smallPadding = 8.dp, + mediumPadding = 16.dp, + largePadding = 24.dp, + horizontalScreenPadding = 16.dp, + verticalScreenPadding = 16.dp, + ) + WindowWidthSizeClass.MEDIUM -> + Dimensions( + smallPadding = 16.dp, + mediumPadding = 24.dp, + largePadding = 32.dp, + horizontalScreenPadding = 48.dp, + verticalScreenPadding = 24.dp, + ) + WindowWidthSizeClass.EXPANDED -> + Dimensions( + smallPadding = 24.dp, + mediumPadding = 32.dp, + largePadding = 40.dp, + horizontalScreenPadding = 64.dp, + verticalScreenPadding = 24.dp, + ) + else -> + Dimensions( + smallPadding = 16.dp, + mediumPadding = 24.dp, + largePadding = 32.dp, + horizontalScreenPadding = 16.dp, + verticalScreenPadding = 16.dp, + ) + } diff --git a/app/src/main/java/dev/hossain/weatheralert/ui/theme/Theme.kt b/app/src/main/java/dev/hossain/weatheralert/ui/theme/Theme.kt index fecc5b6a..b7430529 100644 --- a/app/src/main/java/dev/hossain/weatheralert/ui/theme/Theme.kt +++ b/app/src/main/java/dev/hossain/weatheralert/ui/theme/Theme.kt @@ -7,6 +7,7 @@ import androidx.compose.material3.dynamicDarkColorScheme import androidx.compose.material3.dynamicLightColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.platform.LocalContext private val DarkColorScheme = @@ -34,6 +35,7 @@ fun WeatherAlertAppTheme( darkTheme: Boolean = isSystemInDarkTheme(), // Dynamic color is available on Android 12+ dynamicColor: Boolean = true, + dimensions: Dimensions = LocalDimensions.current, content: @Composable () -> Unit, ) { val colorScheme = @@ -47,9 +49,15 @@ fun WeatherAlertAppTheme( else -> LightColorScheme } - MaterialTheme( - colorScheme = colorScheme, - typography = AppTypography, - content = content, - ) + // CompositionLocalProvider binds values to ProvidableCompositionLocal keys. + // https://developer.android.com/develop/ui/compose/compositionlocal + CompositionLocalProvider( + LocalDimensions provides dimensions, + ) { + MaterialTheme( + colorScheme = colorScheme, + typography = AppTypography, + content = content, + ) + } }