Skip to content

Commit 4aae4d1

Browse files
committed
Remember your theme selection in the sample app
1 parent 2dcec64 commit 4aae4d1

File tree

7 files changed

+80
-22
lines changed

7 files changed

+80
-22
lines changed

gradle/libs.versions.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ agp = "8.11.1"
44
amplify = "2.29.2"
55
appcompat = "1.6.1"
66
androidx-core = "1.9.0"
7+
androidx-datastore = "1.1.7"
78
androidx-junit = "1.1.4"
89
androidx-activity = "1.6.1"
910
androidx-navigation = "2.5.3"
@@ -83,6 +84,9 @@ test-roborazzi = { module = "io.github.takahirom.roborazzi:roborazzi", version.r
8384
test-roborazzi-compose = { module = "io.github.takahirom.roborazzi:roborazzi-compose", version.ref = "roborazzi" }
8485
test-turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" }
8586

87+
# Dependencies for sample apps
88+
samples-androidx-datastore-prefs = { module = "androidx.datastore:datastore-preferences", version.ref = "androidx-datastore" }
89+
8690
# Dependencies for convention plugins
8791
plugin-android-gradle = { module = "com.android.tools.build:gradle", version.ref = "agp" }
8892
plugin-binary-compatibility = { module = "org.jetbrains.kotlinx:binary-compatibility-validator", version.ref = "binary-compatibility" }
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
/build
22
/buildNative
33
**/awsconfiguration.json
4-
**/amplifyconfiguration.json
4+
**/amplifyconfiguration**.json

samples/authenticator/app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ dependencies {
1515
implementation(libs.bundles.compose)
1616
implementation(libs.androidx.lifecycle)
1717
implementation(libs.androidx.activity.compose)
18+
implementation(libs.samples.androidx.datastore.prefs)
1819

1920
coreLibraryDesugaring(libs.android.desugar)
2021
}

samples/authenticator/app/src/main/java/com/amplifyframework/ui/sample/authenticator/MainActivity.kt

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package com.amplifyframework.ui.sample.authenticator
1818
import android.os.Bundle
1919
import androidx.activity.ComponentActivity
2020
import androidx.activity.compose.setContent
21-
import androidx.compose.foundation.isSystemInDarkTheme
2221
import androidx.compose.foundation.layout.Arrangement
2322
import androidx.compose.foundation.layout.Column
2423
import androidx.compose.foundation.layout.fillMaxHeight
@@ -40,28 +39,28 @@ import androidx.compose.material3.Text
4039
import androidx.compose.material3.TopAppBar
4140
import androidx.compose.material3.rememberDrawerState
4241
import androidx.compose.runtime.Composable
42+
import androidx.compose.runtime.collectAsState
4343
import androidx.compose.runtime.getValue
44-
import androidx.compose.runtime.mutableStateOf
45-
import androidx.compose.runtime.remember
4644
import androidx.compose.runtime.rememberCoroutineScope
47-
import androidx.compose.runtime.setValue
4845
import androidx.compose.ui.Modifier
4946
import androidx.compose.ui.unit.dp
5047
import com.amplifyframework.ui.authenticator.AuthenticatorState
5148
import com.amplifyframework.ui.authenticator.SignedInState
5249
import com.amplifyframework.ui.authenticator.rememberAuthenticatorState
5350
import com.amplifyframework.ui.authenticator.ui.Authenticator
51+
import com.amplifyframework.ui.sample.authenticator.data.ThemeDatastore
5452
import kotlinx.coroutines.launch
5553

5654
class MainActivity : ComponentActivity() {
57-
@OptIn(ExperimentalMaterial3Api::class)
55+
private val themeDatastore by lazy { ThemeDatastore(this) }
56+
5857
override fun onCreate(savedInstanceState: Bundle?) {
5958
super.onCreate(savedInstanceState)
6059
setContent {
61-
val inDarkMode = isSystemInDarkTheme()
62-
var currentTheme by remember { mutableStateOf(SupportedTheme.Default) }
63-
var darkMode by remember { mutableStateOf(inDarkMode) }
60+
val currentTheme by themeDatastore.theme.collectAsState(SupportedTheme.Default)
61+
val darkMode by themeDatastore.darkMode.collectAsState(false)
6462
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
63+
val scope = rememberCoroutineScope()
6564

6665
val authenticatorState = rememberAuthenticatorState()
6766

@@ -75,8 +74,8 @@ class MainActivity : ComponentActivity() {
7574
modifier = Modifier.padding(16.dp),
7675
currentTheme = currentTheme,
7776
darkMode = darkMode,
78-
onChangeCurrentTheme = { currentTheme = it },
79-
onChangeDarkMode = { darkMode = it }
77+
onChangeCurrentTheme = { scope.launch { themeDatastore.saveTheme(it) } },
78+
onChangeDarkMode = { scope.launch { themeDatastore.saveDarkMode(it) } }
8079
)
8180
}
8281
}
@@ -91,10 +90,7 @@ class MainActivity : ComponentActivity() {
9190

9291
@OptIn(ExperimentalMaterial3Api::class)
9392
@Composable
94-
fun SampleAppContent(
95-
drawerState: DrawerState,
96-
authenticatorState: AuthenticatorState
97-
) {
93+
fun SampleAppContent(drawerState: DrawerState, authenticatorState: AuthenticatorState) {
9894
val scope = rememberCoroutineScope()
9995
Scaffold(
10096
topBar = {

samples/authenticator/app/src/main/java/com/amplifyframework/ui/sample/authenticator/ThemeSelector.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package com.amplifyframework.ui.sample.authenticator
1818
import androidx.compose.foundation.layout.Column
1919
import androidx.compose.foundation.layout.Row
2020
import androidx.compose.foundation.layout.padding
21+
import androidx.compose.material3.MaterialTheme
2122
import androidx.compose.material3.RadioButton
2223
import androidx.compose.material3.Switch
2324
import androidx.compose.material3.Text
@@ -30,7 +31,8 @@ import com.amplifyframework.ui.sample.authenticator.theme.default.AppTheme
3031

3132
enum class SupportedTheme {
3233
Default,
33-
Amplify
34+
Amplify,
35+
Dynamic
3436
}
3537

3638
@Composable
@@ -42,7 +44,8 @@ fun ThemeSelector(
4244
onChangeDarkMode: (Boolean) -> Unit
4345
) {
4446
Column(modifier = modifier) {
45-
SupportedTheme.values().forEach { theme ->
47+
Text("Theme", style = MaterialTheme.typography.titleMedium)
48+
SupportedTheme.entries.forEach { theme ->
4649
Row(verticalAlignment = Alignment.CenterVertically) {
4750
RadioButton(selected = theme == currentTheme, onClick = { onChangeCurrentTheme(theme) })
4851
Text(modifier = Modifier.padding(start = 8.dp), text = theme.name)
@@ -58,7 +61,8 @@ fun ThemeSelector(
5861
@Composable
5962
fun ApplyTheme(theme: SupportedTheme, darkMode: Boolean, content: @Composable () -> Unit) {
6063
when (theme) {
61-
SupportedTheme.Default -> AppTheme(darkTheme = darkMode, content = content)
64+
SupportedTheme.Default -> AppTheme(darkTheme = darkMode, dynamicColor = false, content = content)
6265
SupportedTheme.Amplify -> AmplifyTheme(useDarkTheme = darkMode, content = content)
66+
SupportedTheme.Dynamic -> AppTheme(darkTheme = darkMode, dynamicColor = true, content = content)
6367
}
6468
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.amplifyframework.ui.sample.authenticator.data
2+
3+
import android.content.Context
4+
import androidx.datastore.core.DataStore
5+
import androidx.datastore.preferences.core.Preferences
6+
import androidx.datastore.preferences.core.booleanPreferencesKey
7+
import androidx.datastore.preferences.core.edit
8+
import androidx.datastore.preferences.core.stringPreferencesKey
9+
import androidx.datastore.preferences.preferencesDataStore
10+
import com.amplifyframework.ui.sample.authenticator.SupportedTheme
11+
import kotlinx.coroutines.flow.Flow
12+
import kotlinx.coroutines.flow.map
13+
14+
class ThemeDatastore(context: Context) {
15+
16+
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "theme")
17+
18+
private val datastore = context.dataStore
19+
20+
private val darkModeKey = booleanPreferencesKey("darkMode")
21+
private val themeKey = stringPreferencesKey("theme")
22+
23+
suspend fun saveTheme(theme: SupportedTheme) {
24+
datastore.edit { settings ->
25+
settings[themeKey] = theme.name
26+
}
27+
}
28+
29+
suspend fun saveDarkMode(darkMode: Boolean) {
30+
datastore.edit { settings ->
31+
settings[darkModeKey] = darkMode
32+
}
33+
}
34+
35+
val darkMode: Flow<Boolean> = datastore.data.map { settings ->
36+
settings[darkModeKey] ?: false
37+
}
38+
val theme: Flow<SupportedTheme> = datastore.data.map { settings ->
39+
val name = settings[themeKey] ?: SupportedTheme.Default.name
40+
SupportedTheme.valueOf(name)
41+
}
42+
43+
}

samples/authenticator/app/src/main/java/com/amplifyframework/ui/sample/authenticator/theme/amplifytheme/Theme.kt

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,16 @@
1515

1616
package com.amplifyframework.ui.sample.authenticator.theme.amplifytheme
1717

18+
import android.app.Activity
1819
import androidx.compose.foundation.isSystemInDarkTheme
1920
import androidx.compose.material3.MaterialTheme
2021
import androidx.compose.material3.darkColorScheme
2122
import androidx.compose.material3.lightColorScheme
2223
import androidx.compose.runtime.Composable
24+
import androidx.compose.runtime.SideEffect
25+
import androidx.compose.ui.graphics.toArgb
26+
import androidx.compose.ui.platform.LocalView
27+
import androidx.core.view.ViewCompat
2328

2429
private val LightColors = lightColorScheme(
2530
primary = md_theme_light_primary,
@@ -82,16 +87,21 @@ private val DarkColors = darkColorScheme(
8287
)
8388

8489
@Composable
85-
fun AmplifyTheme(
86-
useDarkTheme: Boolean = isSystemInDarkTheme(),
87-
content: @Composable () -> Unit
88-
) {
90+
fun AmplifyTheme(useDarkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
8991
val colors = if (!useDarkTheme) {
9092
LightColors
9193
} else {
9294
DarkColors
9395
}
9496

97+
val view = LocalView.current
98+
if (!view.isInEditMode) {
99+
SideEffect {
100+
(view.context as Activity).window.statusBarColor = colors.primary.toArgb()
101+
ViewCompat.getWindowInsetsController(view)?.isAppearanceLightStatusBars = useDarkTheme
102+
}
103+
}
104+
95105
MaterialTheme(
96106
colorScheme = colors,
97107
content = content

0 commit comments

Comments
 (0)