Skip to content

Commit

Permalink
Feature/7 dark color theme (#13)
Browse files Browse the repository at this point in the history
Add theme selection [Light / Dark / System]
  • Loading branch information
GrakovNe authored Oct 29, 2024
1 parent 1ffaa5d commit 240eb64
Show file tree
Hide file tree
Showing 20 changed files with 355 additions and 156 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ android {
applicationId = "org.grakovne.lissen"
minSdk = 28
targetSdk = 35
versionCode = 8
versionName = "1.0.7"
versionCode = 9
versionName = "1.0.8"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/java/org/grakovne/lissen/common/ColorScheme.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.grakovne.lissen.common

enum class ColorScheme {
FOLLOW_SYSTEM,
LIGHT,
DARK
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import android.util.Base64
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import org.grakovne.lissen.channel.common.ChannelCode
import org.grakovne.lissen.common.ColorScheme
import org.grakovne.lissen.domain.Library
import java.security.KeyStore
import java.util.UUID
Expand Down Expand Up @@ -81,12 +86,31 @@ class LissenSharedPreferences @Inject constructor(@ApplicationContext context: C
saveActiveLibraryName(library.title)
}

fun saveColorScheme(colorScheme: ColorScheme) =
sharedPreferences.edit().putString(KEY_PREFERRED_COLOR_SCHEME, colorScheme.name).apply()

fun getColorScheme(): ColorScheme =
sharedPreferences.getString(KEY_PREFERRED_COLOR_SCHEME, ColorScheme.FOLLOW_SYSTEM.name)
?.let { ColorScheme.valueOf(it) }
?: ColorScheme.FOLLOW_SYSTEM

fun savePlaybackSpeed(factor: Float) =
sharedPreferences.edit().putFloat(KEY_PREFERRED_PLAYBACK_SPEED, factor).apply()

fun getPlaybackSpeed(): Float =
sharedPreferences.getFloat(KEY_PREFERRED_PLAYBACK_SPEED, 1f)

val colorSchemeFlow: Flow<ColorScheme> = callbackFlow {
val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
if (key == KEY_PREFERRED_COLOR_SCHEME) {
trySend(getColorScheme())
}
}
sharedPreferences.registerOnSharedPreferenceChangeListener(listener)
trySend(getColorScheme())
awaitClose { sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener) }
}.distinctUntilChanged()

private fun saveActiveLibraryId(host: String) =
sharedPreferences.edit().putString(KEY_PREFERRED_LIBRARY_ID, host).apply()

Expand Down Expand Up @@ -139,6 +163,8 @@ class LissenSharedPreferences @Inject constructor(@ApplicationContext context: C

private const val KEY_PREFERRED_PLAYBACK_SPEED = "preferred_playback_speed"

private const val KEY_PREFERRED_COLOR_SCHEME = "preferred_color_scheme"

private const val ANDROID_KEYSTORE = "AndroidKeyStore"
private const val TRANSFORMATION = "AES/GCM/NoPadding"

Expand Down
13 changes: 12 additions & 1 deletion app/src/main/java/org/grakovne/lissen/ui/activity/AppActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.navigation.compose.rememberNavController
import coil.ImageLoader
import dagger.hilt.android.AndroidEntryPoint
Expand All @@ -26,12 +28,21 @@ class AppActivity : ComponentActivity() {
@Inject
lateinit var networkQualityService: NetworkQualityService

@Inject
lateinit var sharedPreferences: LissenSharedPreferences

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()

setContent {
LissenTheme {
val colorScheme by sharedPreferences
.colorSchemeFlow
.collectAsState(initial = sharedPreferences.getColorScheme())

LissenTheme(colorScheme) {
val navController = rememberNavController()

AppNavHost(
navController = navController,
navigationService = AppNavigationService(navController),
Expand Down
77 changes: 42 additions & 35 deletions app/src/main/java/org/grakovne/lissen/ui/navigation/AppNavHost.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package org.grakovne.lissen.ui.navigation

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
Expand Down Expand Up @@ -35,45 +38,49 @@ fun AppNavHost(
else -> "login_screen"
}

NavHost(
navController = navController,
startDestination = startDestination
) {
composable("library_screen") {
LibraryScreen(
navController = navigationService,
imageLoader = imageLoader,
networkQualityService = networkQualityService
)
}
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
println(innerPadding)

composable(
"player_screen/{bookId}?bookTitle={bookTitle}",
arguments = listOf(
navArgument("bookId") { type = NavType.StringType },
navArgument("bookTitle") { type = NavType.StringType; nullable = true }
)
) { navigationStack ->
val bookId = navigationStack.arguments?.getString("bookId")
val bookTitle = navigationStack.arguments?.getString("bookTitle")
NavHost(
navController = navController,
startDestination = startDestination
) {
composable("library_screen") {
LibraryScreen(
navController = navigationService,
imageLoader = imageLoader,
networkQualityService = networkQualityService
)
}

PlayerScreen(
navController = navigationService,
imageLoader = imageLoader,
bookId = bookId,
bookTitle = bookTitle
)
}
composable(
"player_screen/{bookId}?bookTitle={bookTitle}",
arguments = listOf(
navArgument("bookId") { type = NavType.StringType },
navArgument("bookTitle") { type = NavType.StringType; nullable = true }
)
) { navigationStack ->
val bookId = navigationStack.arguments?.getString("bookId")
val bookTitle = navigationStack.arguments?.getString("bookTitle")

composable("login_screen") {
LoginScreen(navigationService)
}
PlayerScreen(
navController = navigationService,
imageLoader = imageLoader,
bookId = bookId,
bookTitle = bookTitle
)
}

composable("login_screen") {
LoginScreen(navigationService)
}

composable("settings_screen") {
SettingsScreen(
onBack = { navController.popBackStack() },
navController = navigationService
)
composable("settings_screen") {
SettingsScreen(
onBack = { navController.popBackStack() },
navController = navigationService
)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ import org.grakovne.lissen.domain.BookCachedState
import org.grakovne.lissen.ui.components.AsyncShimmeringImage
import org.grakovne.lissen.ui.extensions.formatShortly
import org.grakovne.lissen.ui.navigation.AppNavigationService
import org.grakovne.lissen.ui.theme.backgroundColor
import org.grakovne.lissen.viewmodel.BookCacheAction
import org.grakovne.lissen.viewmodel.CachingModelView

Expand Down Expand Up @@ -172,7 +171,7 @@ fun BookComposable(
Text(stringResource(R.string.dialog_dismiss_cancel))
}
},
containerColor = backgroundColor
containerColor = MaterialTheme.colorScheme.background
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import org.grakovne.lissen.R
import org.grakovne.lissen.common.NetworkQualityService
import org.grakovne.lissen.ui.theme.ItemAccented
import org.grakovne.lissen.viewmodel.CachingModelView

@Composable
Expand Down Expand Up @@ -66,7 +65,7 @@ fun LibraryFallbackComposable(
modifier = Modifier
.size(120.dp)
.clip(CircleShape)
.background(ItemAccented),
.background(MaterialTheme.colorScheme.surfaceContainer),
contentAlignment = Alignment.Center
) {
Icon(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import androidx.compose.material.icons.outlined.Headset
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material.icons.outlined.Speed
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.NavigationBar
Expand All @@ -30,7 +31,6 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import org.grakovne.lissen.R
import org.grakovne.lissen.ui.navigation.AppNavigationService
import org.grakovne.lissen.ui.theme.ItemAccented
import org.grakovne.lissen.viewmodel.PlayerViewModel

@Composable
Expand Down Expand Up @@ -77,7 +77,7 @@ fun NavigationBarComposable(
onClick = { navController.showLibrary() },
colors = NavigationBarItemDefaults.colors(
selectedIconColor = colorScheme.primary,
indicatorColor = ItemAccented
indicatorColor = MaterialTheme.colorScheme.surfaceContainer
)
)

Expand All @@ -101,7 +101,7 @@ fun NavigationBarComposable(
onClick = { onChaptersClick() },
colors = NavigationBarItemDefaults.colors(
selectedIconColor = colorScheme.primary,
indicatorColor = ItemAccented
indicatorColor = MaterialTheme.colorScheme.surfaceContainer
)
)

Expand All @@ -126,7 +126,7 @@ fun NavigationBarComposable(
enabled = true,
colors = NavigationBarItemDefaults.colors(
selectedIconColor = colorScheme.primary,
indicatorColor = ItemAccented
indicatorColor = MaterialTheme.colorScheme.surfaceContainer
)
)

Expand All @@ -150,7 +150,7 @@ fun NavigationBarComposable(
onClick = { navController.showSettings() },
colors = NavigationBarItemDefaults.colors(
selectedIconColor = colorScheme.primary,
indicatorColor = ItemAccented
indicatorColor = MaterialTheme.colorScheme.surfaceContainer
)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,11 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight.Companion.SemiBold
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import org.grakovne.lissen.R
import org.grakovne.lissen.ui.theme.ItemAccented

@SuppressLint("DefaultLocale")
@OptIn(ExperimentalMaterial3Api::class)
Expand All @@ -47,7 +45,7 @@ fun PlaybackSpeedComposable(
var selectedPlaybackSpeed by remember { mutableFloatStateOf(currentSpeed) }

ModalBottomSheet(
containerColor = Color(0xFFFAFAFA),
containerColor = colorScheme.background,
onDismissRequest = onDismissRequest,
content = {
Column(
Expand Down Expand Up @@ -110,14 +108,13 @@ fun PlaybackSpeedComposable(
colors = ButtonDefaults.buttonColors(
containerColor = when (selectedPlaybackSpeed == value) {
true -> colorScheme.primary
else -> ItemAccented
else -> colorScheme.surfaceContainer
}
),
modifier = Modifier.fillMaxSize()
) {}
Text(
text = String.format("%.2f", value),
color = Color.Black,
style = when (selectedPlaybackSpeed == value) {
true -> typography.labelMedium.copy(fontWeight = SemiBold)
false -> typography.labelMedium
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api
Expand All @@ -27,7 +29,7 @@ import androidx.hilt.navigation.compose.hiltViewModel
import org.grakovne.lissen.R
import org.grakovne.lissen.ui.navigation.AppNavigationService
import org.grakovne.lissen.ui.screens.settings.composable.AdditionalComposable
import org.grakovne.lissen.ui.screens.settings.composable.PreferredLibraryComposable
import org.grakovne.lissen.ui.screens.settings.composable.GeneralSettingsComposable
import org.grakovne.lissen.ui.screens.settings.composable.ServerComposable
import org.grakovne.lissen.viewmodel.SettingsViewModel

Expand Down Expand Up @@ -78,12 +80,12 @@ fun SettingsScreen(
) {
Column(
modifier = Modifier
.weight(1f)
.fillMaxWidth(),
.fillMaxWidth()
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally
) {
ServerComposable(navController, viewModel)
PreferredLibraryComposable(viewModel)
GeneralSettingsComposable(viewModel)
}
AdditionalComposable()
}
Expand Down
Loading

0 comments on commit 240eb64

Please sign in to comment.