Skip to content

Commit eef261d

Browse files
feat: add light theme
1 parent 0ed9858 commit eef261d

19 files changed

Lines changed: 294 additions & 34 deletions

app/src/main/java/org/bitcoindevkit/devkitwallet/domain/UserPreferencesRepository.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,16 @@ class UserPreferencesRepository(
3333
}
3434
}
3535

36+
suspend fun fetchDarkTheme(): Boolean {
37+
return userPreferencesStore.data.first().darkTheme
38+
}
39+
40+
suspend fun setDarkTheme(isDark: Boolean) {
41+
userPreferencesStore.updateData { currentPreferences ->
42+
currentPreferences.toBuilder().setDarkTheme(isDark).build()
43+
}
44+
}
45+
3646
suspend fun setFullScanCompleted(walletId: String) {
3747
userPreferencesStore.updateData { currentPreferences ->
3848
val updatedWalletsList =

app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/DevkitWalletActivity.kt

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
package org.bitcoindevkit.devkitwallet.presentation
77

88
import android.content.Context
9+
import android.graphics.drawable.ColorDrawable
910
import android.os.Bundle
1011
import android.util.Log
1112
import androidx.activity.ComponentActivity
1213
import androidx.activity.compose.setContent
1314
import androidx.compose.runtime.getValue
1415
import androidx.compose.runtime.mutableStateOf
1516
import androidx.compose.runtime.setValue
17+
import androidx.core.graphics.drawable.toDrawable
1618
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
1719
import androidx.datastore.core.DataStore
1820
import androidx.datastore.dataStore
@@ -30,6 +32,7 @@ import org.bitcoindevkit.devkitwallet.domain.UserPreferencesRepository
3032
import org.bitcoindevkit.devkitwallet.domain.Wallet
3133
import org.bitcoindevkit.devkitwallet.presentation.navigation.AppNavigation
3234
import org.bitcoindevkit.devkitwallet.presentation.theme.DevkitTheme
35+
import org.bitcoindevkit.devkitwallet.presentation.theme.themeSurfaceColor
3336
import org.bitcoindevkit.devkitwallet.presentation.ui.screens.intro.OnboardingScreen
3437

3538
private const val TAG = "DevkitWalletActivity"
@@ -52,6 +55,7 @@ class DevkitWalletActivity : ComponentActivity() {
5255
var activeWallet: Wallet? by mutableStateOf(null)
5356
var activeWallets: List<SingleWallet> by mutableStateOf(emptyList())
5457
var onboardingDone: Boolean by mutableStateOf(false)
58+
var useDarkTheme: Boolean by mutableStateOf(true)
5559
var preferencesLoaded: Boolean by mutableStateOf(false)
5660

5761
val onBuildWalletButtonClicked: (WalletCreateType) -> Unit = { walletCreateType ->
@@ -87,6 +91,15 @@ class DevkitWalletActivity : ComponentActivity() {
8791
}
8892
}
8993

94+
val onToggleTheme: () -> Unit = {
95+
useDarkTheme = !useDarkTheme
96+
// Keep the window background in sync with the Compose theme. Navigation transitions
97+
// include a fade-out, which causes the window background to show through briefly.
98+
// Updating it here (synchronously, before Compose recomposes) prevents a color flash.
99+
window.setBackgroundDrawable(themeSurfaceColor(useDarkTheme).toDrawable())
100+
lifecycleScope.launch { userPreferencesRepository.setDarkTheme(useDarkTheme) }
101+
}
102+
90103
lifecycleScope.launch {
91104
activeWallets =
92105
async {
@@ -98,6 +111,14 @@ class DevkitWalletActivity : ComponentActivity() {
98111
userPreferencesRepository.fetchIntroDone()
99112
}.await()
100113

114+
useDarkTheme =
115+
async {
116+
userPreferencesRepository.fetchDarkTheme()
117+
}.await()
118+
119+
// Set the window background before allowing the UI to render for the first time,
120+
// so the correct surface color is already in place when Compose draws its first frame.
121+
window.setBackgroundDrawable(ColorDrawable(themeSurfaceColor(useDarkTheme)))
101122
preferencesLoaded = true
102123
}
103124

@@ -113,11 +134,13 @@ class DevkitWalletActivity : ComponentActivity() {
113134
DwLogger.log(INFO, "First time opening the app, triggering onboarding screen")
114135
OnboardingScreen(onFinishOnboarding)
115136
} else {
116-
DevkitTheme {
137+
DevkitTheme(darkTheme = useDarkTheme) {
117138
AppNavigation(
118139
activeWallet = activeWallet,
119140
activeWallets = activeWallets,
120141
onBuildWalletButtonClicked = onBuildWalletButtonClicked,
142+
useDarkTheme = useDarkTheme,
143+
onToggleTheme = onToggleTheme,
121144
)
122145
}
123146
}

app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/navigation/AppNavigation.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import org.bitcoindevkit.devkitwallet.presentation.ui.screens.settings.Blockchai
3333
import org.bitcoindevkit.devkitwallet.presentation.ui.screens.settings.LogsScreen
3434
import org.bitcoindevkit.devkitwallet.presentation.ui.screens.settings.RecoveryDataScreen
3535
import org.bitcoindevkit.devkitwallet.presentation.ui.screens.settings.SettingsScreen
36+
import org.bitcoindevkit.devkitwallet.presentation.ui.screens.settings.ThemeScreen
3637
import org.bitcoindevkit.devkitwallet.presentation.ui.screens.wallet.RBFScreen
3738
import org.bitcoindevkit.devkitwallet.presentation.ui.screens.wallet.ReceiveScreen
3839
import org.bitcoindevkit.devkitwallet.presentation.ui.screens.wallet.SendScreen
@@ -94,6 +95,8 @@ fun AppNavigation(
9495
activeWallet: Wallet?,
9596
activeWallets: List<SingleWallet>,
9697
onBuildWalletButtonClicked: (WalletCreateType) -> Unit,
98+
useDarkTheme: Boolean,
99+
onToggleTheme: () -> Unit,
97100
) {
98101
val navController: NavHostController = rememberNavController()
99102

@@ -187,5 +190,13 @@ fun AppNavigation(
187190
}
188191

189192
composable<LogsScreen> { LogsScreen(navController = navController) }
193+
194+
composable<ThemeScreen> {
195+
ThemeScreen(
196+
useDarkTheme = useDarkTheme,
197+
onToggleTheme = onToggleTheme,
198+
navController = navController,
199+
)
200+
}
190201
}
191202
}

app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/navigation/Destinations.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ object BlockchainClientScreen
3636
@Serializable
3737
object LogsScreen
3838

39+
@Serializable
40+
object ThemeScreen
41+
3942
// Wallet navigation destinations
4043
@Serializable
4144
object HomeScreen

app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/theme/DevkitWalletColors.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ package org.bitcoindevkit.devkitwallet.presentation.theme
77

88
import androidx.compose.ui.graphics.Color
99

10-
// Accent colors not covered by the MaterialTheme colorScheme
10+
// NightGlow (dark theme) accent colors
1111
val NightGlowHistoryAccent: Color = Color(0xFFE3D082)
1212
val NightGlowSubtle: Color = Color(0xFF79747E)
13+
14+
// DayGlow (light theme) accent colors
15+
val DayGlowHistoryAccent: Color = Color(0xFF816C2A)
16+
val DayGlowSubtle: Color = Color(0xFF79747E)

app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/theme/Theme.kt

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ package org.bitcoindevkit.devkitwallet.presentation.theme
77

88
import androidx.compose.material3.MaterialTheme
99
import androidx.compose.material3.darkColorScheme
10+
import androidx.compose.material3.lightColorScheme
1011
import androidx.compose.runtime.Composable
1112
import androidx.compose.ui.graphics.Color
1213

13-
private val DevkitDarkColorScheme = darkColorScheme(
14+
private val NightGlowColorScheme = darkColorScheme(
1415
surface = Color(0xFF1C1B1F),
1516
onSurface = Color(0xFFE6E1E5),
1617
surfaceVariant = Color(0xFF49454F),
@@ -27,10 +28,32 @@ private val DevkitDarkColorScheme = darkColorScheme(
2728
onTertiary = Color(0xFF1C1B1F),
2829
)
2930

31+
private val DayGlowColorScheme = lightColorScheme(
32+
surface = Color(0xFFFFF8F4),
33+
onSurface = Color(0xFF1C1B1F),
34+
surfaceVariant = Color(0xFFEDE5DF),
35+
onSurfaceVariant = Color(0xFF49454F),
36+
background = Color(0xFFFFF8F4),
37+
onBackground = Color(0xFF1C1B1F),
38+
outline = Color(0xFF79747E),
39+
outlineVariant = Color(0xFFCAC4D0),
40+
primary = Color(0xFF7D5260),
41+
onPrimary = Color(0xFFFFFFFF),
42+
secondary = Color(0xFF625B71),
43+
onSecondary = Color(0xFFFFFFFF),
44+
tertiary = Color(0xFF2E6A3C),
45+
onTertiary = Color(0xFFFFFFFF),
46+
)
47+
48+
// Returns the surface color for the given theme as an ARGB int for use outside of Compose (e.g.
49+
// setting the window background from the Activity). Keeps the values co-located with the color
50+
// schemes above so there is a single source of truth for each theme's surface color.
51+
fun themeSurfaceColor(darkTheme: Boolean): Int = if (darkTheme) 0xFF1C1B1F.toInt() else 0xFFFFF8F4.toInt()
52+
3053
@Composable
31-
fun DevkitTheme(content: @Composable () -> Unit) {
54+
fun DevkitTheme(darkTheme: Boolean = true, content: @Composable () -> Unit) {
3255
MaterialTheme(
33-
colorScheme = DevkitDarkColorScheme,
56+
colorScheme = if (darkTheme) NightGlowColorScheme else DayGlowColorScheme,
3457
typography = devkitTypography,
3558
content = content,
3659
)

app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/components/TransactionCards.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import androidx.compose.ui.unit.sp
2828
import androidx.navigation.NavController
2929
import org.bitcoindevkit.devkitwallet.data.TxDetails
3030
import org.bitcoindevkit.devkitwallet.domain.utils.timestampToString
31-
import org.bitcoindevkit.devkitwallet.presentation.theme.NightGlowHistoryAccent
31+
import org.bitcoindevkit.devkitwallet.presentation.theme.DayGlowHistoryAccent
3232
import org.bitcoindevkit.devkitwallet.presentation.theme.inter
3333
import org.bitcoindevkit.devkitwallet.presentation.ui.screens.wallet.viewTransaction
3434

@@ -84,7 +84,7 @@ fun PendingTransactionCard(details: TxDetails, navController: NavController) {
8484
shape = RoundedCornerShape(16.dp),
8585
).border(
8686
width = 1.5.dp,
87-
color = NightGlowHistoryAccent.copy(alpha = 0.5f),
87+
color = DayGlowHistoryAccent.copy(alpha = 0.5f),
8888
shape = RoundedCornerShape(16.dp),
8989
).clickable {
9090
viewTransaction(
@@ -108,7 +108,7 @@ fun PendingTransactionCard(details: TxDetails, navController: NavController) {
108108
.padding(top = 16.dp, end = 16.dp)
109109
.size(24.dp)
110110
.clip(shape = CircleShape)
111-
.background(NightGlowHistoryAccent.copy(alpha = 0.6f))
111+
.background(DayGlowHistoryAccent.copy(alpha = 0.6f))
112112
.align(Alignment.Top),
113113
)
114114
}

app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/intro/CreateNewWallet.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,8 @@ internal fun CreateNewWalletScreen(
145145
.height(56.dp),
146146
shape = RoundedCornerShape(20.dp),
147147
colors = ButtonDefaults.buttonColors(
148-
containerColor = colorScheme.primary,
149-
contentColor = colorScheme.onPrimary,
148+
containerColor = colorScheme.tertiary,
149+
contentColor = colorScheme.onTertiary,
150150
),
151151
) {
152152
Text(
@@ -199,14 +199,14 @@ internal fun ThemedRadioOption(label: String, isSelected: Boolean, onSelect: ()
199199
modifier = Modifier
200200
.fillMaxWidth()
201201
.selectable(selected = isSelected, onClick = onSelect)
202-
.padding(horizontal = 16.dp, vertical = 14.dp),
202+
.padding(horizontal = 16.dp, vertical = 12.dp),
203203
) {
204204
Box(
205205
modifier = Modifier
206206
.size(22.dp)
207207
.border(
208208
width = 2.dp,
209-
color = if (isSelected) colorScheme.primary else colorScheme.outlineVariant,
209+
color = if (isSelected) colorScheme.tertiary else colorScheme.outlineVariant,
210210
shape = CircleShape,
211211
),
212212
contentAlignment = Alignment.Center,
@@ -215,7 +215,7 @@ internal fun ThemedRadioOption(label: String, isSelected: Boolean, onSelect: ()
215215
Box(
216216
modifier = Modifier
217217
.size(10.dp)
218-
.background(colorScheme.primary, CircleShape),
218+
.background(colorScheme.tertiary, CircleShape),
219219
)
220220
}
221221
}

app/src/main/java/org/bitcoindevkit/devkitwallet/presentation/ui/screens/settings/SettingsScreen.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ import com.composables.icons.lucide.Palette
3939
import com.composables.icons.lucide.ScrollText
4040
import org.bitcoindevkit.devkitwallet.presentation.navigation.AboutScreen
4141
import org.bitcoindevkit.devkitwallet.presentation.navigation.LogsScreen
42-
import org.bitcoindevkit.devkitwallet.presentation.theme.NightGlowHistoryAccent
42+
import org.bitcoindevkit.devkitwallet.presentation.navigation.ThemeScreen
43+
import org.bitcoindevkit.devkitwallet.presentation.theme.DayGlowHistoryAccent
4344
import org.bitcoindevkit.devkitwallet.presentation.theme.inter
4445
import org.bitcoindevkit.devkitwallet.presentation.ui.components.SecondaryScreensAppBar
4546

@@ -84,7 +85,7 @@ internal fun SettingsScreen(navController: NavController) {
8485
)
8586
SettingsItem(
8687
icon = Lucide.ScrollText,
87-
iconTint = NightGlowHistoryAccent,
88+
iconTint = DayGlowHistoryAccent,
8889
title = "Logs",
8990
description = "View application logs",
9091
onClick = { navController.navigate(LogsScreen) },
@@ -98,7 +99,7 @@ internal fun SettingsScreen(navController: NavController) {
9899
iconTint = colorScheme.tertiary,
99100
title = "Theme",
100101
description = "Appearance and display",
101-
onClick = { },
102+
onClick = { navController.navigate(ThemeScreen) },
102103
)
103104
}
104105
}

0 commit comments

Comments
 (0)