Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions app/src/main/java/de/pyryco/mobile/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
Expand All @@ -25,6 +26,7 @@ import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import de.pyryco.mobile.data.preferences.AppPreferences
import de.pyryco.mobile.data.preferences.ThemeMode
import de.pyryco.mobile.ui.conversations.list.ChannelListEvent
import de.pyryco.mobile.ui.conversations.list.ChannelListNavigation
import de.pyryco.mobile.ui.conversations.list.ChannelListScreen
Expand All @@ -48,9 +50,17 @@ class MainActivity : ComponentActivity() {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
PyrycodeMobileTheme {
val appPreferences = koinInject<AppPreferences>()
val themeMode by appPreferences.themeMode
.collectAsStateWithLifecycle(initialValue = ThemeMode.SYSTEM)
val darkTheme =
when (themeMode) {
ThemeMode.SYSTEM -> isSystemInDarkTheme()
ThemeMode.LIGHT -> false
ThemeMode.DARK -> true
}
PyrycodeMobileTheme(darkTheme = darkTheme) {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
val appPreferences = koinInject<AppPreferences>()
val paired: Boolean? by produceState<Boolean?>(
initialValue = null,
appPreferences,
Expand Down Expand Up @@ -180,9 +190,13 @@ private fun PyryNavHost(
Text("Conversation thread placeholder: $conversationId")
}
composable(Routes.SETTINGS) {
val appPreferences = koinInject<AppPreferences>()
val themeMode by appPreferences.themeMode
.collectAsStateWithLifecycle(initialValue = ThemeMode.SYSTEM)
SettingsScreen(
onBack = { navController.popBackStack() },
onOpenLicense = { navController.navigate(Routes.LICENSE) },
themeMode = themeMode,
)
}
composable(Routes.LICENSE) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map

Expand All @@ -17,7 +18,18 @@ class AppPreferences(
dataStore.edit { prefs -> prefs[PAIRED_SERVER_EXISTS] = value }
}

val themeMode: Flow<ThemeMode> =
dataStore.data.map { prefs ->
val stored = prefs[THEME_MODE]
ThemeMode.entries.firstOrNull { it.name == stored } ?: ThemeMode.SYSTEM
}

suspend fun setThemeMode(mode: ThemeMode) {
dataStore.edit { prefs -> prefs[THEME_MODE] = mode.name }
}

private companion object {
val PAIRED_SERVER_EXISTS = booleanPreferencesKey("paired_server_exists")
val THEME_MODE = stringPreferencesKey("theme_mode")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package de.pyryco.mobile.data.preferences

enum class ThemeMode { SYSTEM, LIGHT, DARK }
11 changes: 10 additions & 1 deletion app/src/main/java/de/pyryco/mobile/ui/settings/SettingsScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import de.pyryco.mobile.BuildConfig
import de.pyryco.mobile.R
import de.pyryco.mobile.data.preferences.ThemeMode
import de.pyryco.mobile.ui.theme.PyrycodeMobileTheme

@OptIn(ExperimentalMaterial3Api::class)
Expand All @@ -48,6 +49,7 @@ fun SettingsScreen(
onBack: () -> Unit,
onOpenLicense: () -> Unit,
modifier: Modifier = Modifier,
themeMode: ThemeMode = ThemeMode.SYSTEM,
) {
Scaffold(
modifier = modifier,
Expand Down Expand Up @@ -94,7 +96,7 @@ fun SettingsScreen(
SettingsSectionHeader("Appearance")
SettingsRow(
headline = "Theme",
supporting = "System",
supporting = themeMode.label(),
trailing = { ChevronIcon() },
onClick = {},
)
Expand Down Expand Up @@ -261,6 +263,13 @@ private fun AddPill(onClick: () -> Unit) {
}
}

private fun ThemeMode.label(): String =
when (this) {
ThemeMode.SYSTEM -> "System default"
ThemeMode.LIGHT -> "Light"
ThemeMode.DARK -> "Dark"
}

private const val SOURCE_REPO_URL = "https://github.com/pyrycode/pyrycode-mobile"

@Preview(name = "Settings — Light", showBackground = true, widthDp = 412)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package de.pyryco.mobile.data.preferences
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
Expand Down Expand Up @@ -52,4 +54,26 @@ class AppPreferencesTest {
prefs.setPairedServerExists(true)
assertEquals(true, prefs.pairedServerExists.first())
}

@Test
fun themeMode_defaultsToSystem() =
runBlocking {
assertEquals(ThemeMode.SYSTEM, prefs.themeMode.first())
}

@Test
fun setThemeMode_roundTripsAllValues() =
runBlocking {
for (mode in ThemeMode.entries) {
prefs.setThemeMode(mode)
assertEquals(mode, prefs.themeMode.first())
}
}

@Test
fun themeMode_unparseableStoredValue_fallsBackToSystem() =
runBlocking {
dataStore.edit { it[stringPreferencesKey("theme_mode")] = "PURPLE" }
assertEquals(ThemeMode.SYSTEM, prefs.themeMode.first())
}
}
Loading
Loading