Skip to content

Commit 3e08091

Browse files
committed
dynamic dark mode
1 parent 4ec274e commit 3e08091

File tree

11 files changed

+121
-14
lines changed

11 files changed

+121
-14
lines changed

.idea/misc.xml

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/src/main/java/com/hoc081098/datastoresample/Locator.kt

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import androidx.datastore.preferences.createDataStore
55
import com.hoc081098.datastoresample.data.TaskRepositoryImpl
66
import com.hoc081098.datastoresample.data.UserPreferencesRepositoryImpl
77
import com.hoc081098.datastoresample.domain.ChangeShowCompleted
8+
import com.hoc081098.datastoresample.domain.ChangeTheme
89
import com.hoc081098.datastoresample.domain.EnableSortByDeadline
10+
import com.hoc081098.datastoresample.domain.GetTheme
911
import com.hoc081098.datastoresample.domain.model.FilterSortTasks
1012
import com.hoc081098.datastoresample.ui.MainViewModel
1113

@@ -21,9 +23,11 @@ object Locator {
2123

2224
val mainViewModelFactory
2325
get() = MainViewModel.Factory(
24-
filterSortTasks,
25-
changeShowCompleted,
26-
enableSortByDeadline,
26+
filterSortTasks = filterSortTasks,
27+
getTheme = getTheme,
28+
changeShowCompleted = changeShowCompleted,
29+
enableSortByDeadline = enableSortByDeadline,
30+
changeTheme = changeTheme,
2731
)
2832

2933
private val filterSortTasks
@@ -32,6 +36,10 @@ object Locator {
3236
userPreferencesRepository = userPreferencesRepository
3337
)
3438

39+
private val changeTheme get() = ChangeTheme(userPreferencesRepository)
40+
41+
private val getTheme get() = GetTheme(userPreferencesRepository)
42+
3543
private val changeShowCompleted get() = ChangeShowCompleted(userPreferencesRepository)
3644

3745
private val enableSortByDeadline get() = EnableSortByDeadline(userPreferencesRepository)

app/src/main/java/com/hoc081098/datastoresample/data/UserPreferencesRepositoryImpl.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import androidx.datastore.preferences.core.emptyPreferences
99
import androidx.datastore.preferences.core.stringPreferencesKey
1010
import com.hoc081098.datastoresample.domain.model.SortOrder
1111
import com.hoc081098.datastoresample.domain.model.SortOrder.*
12+
import com.hoc081098.datastoresample.domain.model.Theme
1213
import com.hoc081098.datastoresample.domain.model.UserPreferences
1314
import com.hoc081098.datastoresample.domain.repo.UserPreferencesRepository
1415
import kotlinx.coroutines.flow.Flow
@@ -24,6 +25,7 @@ class UserPreferencesRepositoryImpl(
2425
private object Keys {
2526
val showCompleted = booleanPreferencesKey("show_completed")
2627
val sortOrder = stringPreferencesKey("sort_order")
28+
val theme = booleanPreferencesKey("theme")
2729
}
2830

2931
private inline val Preferences.showCompleted
@@ -101,4 +103,27 @@ class UserPreferencesRepositoryImpl(
101103
dataStore.edit { it[Keys.showCompleted] = showCompleted }
102104
Log.d("UserPreferencesRepo", "updateShowCompleted $showCompleted")
103105
}
106+
107+
override val theme: Flow<Theme> = dataStore.data
108+
.catch {
109+
// throws an IOException when an error is encountered when reading data
110+
if (it is IOException) {
111+
emit(emptyPreferences())
112+
} else {
113+
throw it
114+
}
115+
}
116+
.map {
117+
when (it[Keys.theme]) {
118+
true -> Theme.NIGHT_YES
119+
false -> Theme.NIGHT_NO
120+
null -> Theme.NIGHT_UNSPECIFIED
121+
}
122+
}
123+
.distinctUntilChanged()
124+
125+
override suspend fun changeTheme(lightTheme: Boolean) {
126+
dataStore.edit { it[Keys.theme] = lightTheme }
127+
Log.d("UserPreferencesRepo", "changeTheme $lightTheme")
128+
}
104129
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.hoc081098.datastoresample.domain
2+
3+
import com.hoc081098.datastoresample.domain.repo.UserPreferencesRepository
4+
5+
class ChangeTheme(private val userPreferencesRepository: UserPreferencesRepository) {
6+
suspend operator fun invoke(lightTheme: Boolean) =
7+
userPreferencesRepository.changeTheme(lightTheme)
8+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.hoc081098.datastoresample.domain
2+
3+
import com.hoc081098.datastoresample.domain.model.Theme
4+
import com.hoc081098.datastoresample.domain.repo.UserPreferencesRepository
5+
import kotlinx.coroutines.flow.Flow
6+
7+
class GetTheme(private val userPreferencesRepository: UserPreferencesRepository) {
8+
operator fun invoke(): Flow<Theme> = userPreferencesRepository.theme
9+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.hoc081098.datastoresample.domain.model
2+
3+
enum class Theme {
4+
NIGHT_YES,
5+
NIGHT_NO,
6+
NIGHT_UNSPECIFIED,
7+
}

app/src/main/java/com/hoc081098/datastoresample/domain/model/UserPreferences.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.hoc081098.datastoresample.domain.model
22

3-
import com.hoc081098.datastoresample.domain.model.SortOrder
4-
53
data class UserPreferences(
64
val showCompleted: Boolean,
75
val sortOrder: SortOrder,

app/src/main/java/com/hoc081098/datastoresample/domain/repo/UserPreferencesRepository.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.hoc081098.datastoresample.domain.repo
22

3+
import com.hoc081098.datastoresample.domain.model.Theme
34
import com.hoc081098.datastoresample.domain.model.UserPreferences
45
import kotlinx.coroutines.flow.Flow
56

@@ -11,4 +12,8 @@ interface UserPreferencesRepository {
1112
suspend fun enableSortByPriority(enabled: Boolean)
1213

1314
suspend fun updateShowCompleted(showCompleted: Boolean)
15+
16+
suspend fun changeTheme(lightTheme: Boolean)
17+
18+
val theme: Flow<Theme>
1419
}

app/src/main/java/com/hoc081098/datastoresample/ui/MainActivity.kt

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import android.os.Bundle
44
import androidx.activity.compose.setContent
55
import androidx.activity.viewModels
66
import androidx.appcompat.app.AppCompatActivity
7+
import androidx.compose.foundation.isSystemInDarkTheme
78
import androidx.compose.material.MaterialTheme
89
import androidx.compose.material.Surface
910
import androidx.compose.runtime.collectAsState
1011
import androidx.compose.runtime.getValue
1112
import com.hoc081098.datastoresample.Locator
13+
import com.hoc081098.datastoresample.domain.model.Theme
1214
import com.hoc081098.datastoresample.ui.theme.DataStoreSampleTheme
1315

1416
class MainActivity : AppCompatActivity() {
@@ -18,15 +20,26 @@ class MainActivity : AppCompatActivity() {
1820
super.onCreate(savedInstanceState)
1921

2022
setContent {
21-
DataStoreSampleTheme(true) {
23+
val theme by viewModel.theme.collectAsState()
24+
25+
val darkTheme = when (theme) {
26+
Theme.NIGHT_YES -> false
27+
Theme.NIGHT_NO -> true
28+
Theme.NIGHT_UNSPECIFIED -> isSystemInDarkTheme()
29+
null -> return@setContent
30+
}
31+
32+
DataStoreSampleTheme(darkTheme = darkTheme) {
2233
// A surface container using the 'background' color from the theme
2334
Surface(color = MaterialTheme.colors.background) {
2435
val state by viewModel.state.collectAsState()
2536

2637
MainScreen(
27-
state,
28-
viewModel::changeShowCompleted,
29-
viewModel::enableSortByDeadline,
38+
state = state,
39+
changeShowCompleted = viewModel::changeShowCompleted,
40+
enableSortByDeadline = viewModel::enableSortByDeadline,
41+
lightTheme = !darkTheme,
42+
changeTheme = viewModel::changeTheme,
3043
)
3144
}
3245
}

app/src/main/java/com/hoc081098/datastoresample/ui/MainScreen.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ import androidx.compose.material.Checkbox
2121
import androidx.compose.material.CircularProgressIndicator
2222
import androidx.compose.material.Divider
2323
import androidx.compose.material.Icon
24+
import androidx.compose.material.IconToggleButton
2425
import androidx.compose.material.LocalContentColor
2526
import androidx.compose.material.MaterialTheme
2627
import androidx.compose.material.Scaffold
2728
import androidx.compose.material.Surface
29+
import androidx.compose.material.Switch
2830
import androidx.compose.material.Text
2931
import androidx.compose.material.TopAppBar
3032
import androidx.compose.material.icons.Icons
@@ -47,15 +49,23 @@ fun MainScreen(
4749
state: FilteredSortedTasks?,
4850
changeShowCompleted: (Boolean) -> Unit,
4951
enableSortByDeadline: (Boolean) -> Unit,
52+
lightTheme: Boolean,
53+
changeTheme: (Boolean) -> Unit,
5054
) {
5155
Scaffold(
5256
topBar = {
5357
TopAppBar(
5458
title = {
5559
Text(text = "Jetpack DataStore sample")
60+
},
61+
actions = {
62+
Switch(
63+
checked = lightTheme,
64+
onCheckedChange = changeTheme,
65+
)
5666
}
5767
)
58-
}
68+
},
5969
) {
6070
if (state == null) {
6171
Column(
@@ -219,6 +229,8 @@ fun MainScreenPreview() {
219229
null,
220230
{},
221231
{},
232+
false,
233+
{}
222234
)
223235
}
224236
}

0 commit comments

Comments
 (0)