mirror of
https://github.com/Suwayomi/TachideskJUI.git
synced 2025-12-10 06:42:05 +01:00
Themeing improvements
- Add Tertiary color - Add theme display from Tachiyomi - Show color changes in theme display
This commit is contained in:
@@ -42,6 +42,14 @@ class UiPreferences(private val preferenceStore: PreferenceStore) {
|
||||
return preferenceStore.getInt("color_secondary_dark", 0)
|
||||
}
|
||||
|
||||
fun colorTertiaryLight(): Preference<Int> {
|
||||
return preferenceStore.getInt("color_tertiary_light", 0)
|
||||
}
|
||||
|
||||
fun colorTertiaryDark(): Preference<Int> {
|
||||
return preferenceStore.getInt("color_tertiary_dark", 0)
|
||||
}
|
||||
|
||||
fun startScreen(): Preference<StartScreen> {
|
||||
return preferenceStore.getJsonObject("start_screen", StartScreen.Library, StartScreen.serializer())
|
||||
}
|
||||
|
||||
@@ -198,10 +198,14 @@
|
||||
<string name="theme_dark">Dark</string>
|
||||
<string name="theme_text">Text</string>
|
||||
<string name="preset_themes">Preset themes</string>
|
||||
<string name="theme_default">Default</string>
|
||||
<string name="theme_legacy_blue">Legacy Blue</string>
|
||||
<string name="theme_amoled">AMOLED</string>
|
||||
<string name="color_primary">Primary</string>
|
||||
<string name="color_primary_sub">Displayed most frequently across your app</string>
|
||||
<string name="color_secondary">Secondary</string>
|
||||
<string name="color_secondary_sub">Accents select parts of the UI</string>
|
||||
<string name="color_tertiary">Tertiary</string>
|
||||
<string name="window_decorations">Window decorations</string>
|
||||
<string name="window_decorations_sub">Restart JUI when this setting is changed</string>
|
||||
|
||||
|
||||
@@ -16,31 +16,36 @@ import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
data class AppColorsPreference(
|
||||
val primary: Preference<Color>,
|
||||
val secondary: Preference<Color>
|
||||
val secondary: Preference<Color>,
|
||||
val tertiary: Preference<Color>
|
||||
)
|
||||
|
||||
class AppColorsPreferenceState(
|
||||
val primaryStateFlow: PreferenceMutableStateFlow<Color>,
|
||||
val secondaryStateFlow: PreferenceMutableStateFlow<Color>
|
||||
val secondaryStateFlow: PreferenceMutableStateFlow<Color>,
|
||||
val tertiaryStateFlow: PreferenceMutableStateFlow<Color>
|
||||
)
|
||||
|
||||
fun UiPreferences.getLightColors(): AppColorsPreference {
|
||||
return AppColorsPreference(
|
||||
colorPrimaryLight().asColor(),
|
||||
colorSecondaryLight().asColor()
|
||||
colorSecondaryLight().asColor(),
|
||||
colorTertiaryLight().asColor()
|
||||
)
|
||||
}
|
||||
|
||||
fun UiPreferences.getDarkColors(): AppColorsPreference {
|
||||
return AppColorsPreference(
|
||||
colorPrimaryDark().asColor(),
|
||||
colorSecondaryDark().asColor()
|
||||
colorSecondaryDark().asColor(),
|
||||
colorTertiaryDark().asColor()
|
||||
)
|
||||
}
|
||||
|
||||
fun AppColorsPreference.asStateFlow(scope: CoroutineScope): AppColorsPreferenceState {
|
||||
return AppColorsPreferenceState(
|
||||
primary.asStateIn(scope),
|
||||
secondary.asStateIn(scope)
|
||||
secondary.asStateIn(scope),
|
||||
tertiary.asStateIn(scope)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import ca.gosyer.jui.domain.ui.service.UiPreferences
|
||||
import ca.gosyer.jui.ui.base.LocalViewModels
|
||||
import ca.gosyer.jui.ui.base.theme.ThemeScrollbarStyle.getScrollbarStyle
|
||||
import ca.gosyer.jui.uicore.components.LocalScrollbarStyle
|
||||
import ca.gosyer.jui.uicore.theme.ExtraColors
|
||||
import ca.gosyer.jui.uicore.theme.Theme
|
||||
import ca.gosyer.jui.uicore.theme.themes
|
||||
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||
@@ -42,17 +43,19 @@ import me.tatarka.inject.annotations.Inject
|
||||
fun AppTheme(content: @Composable () -> Unit) {
|
||||
val viewModels = LocalViewModels.current
|
||||
val vm = remember { viewModels.appThemeViewModel() }
|
||||
val colors = vm.getColors()
|
||||
val (colors, extraColors) = vm.getColors()
|
||||
/*val systemUiController = rememberSystemUiController()*/
|
||||
DisposableEffect(vm) {
|
||||
onDispose(vm::onDispose)
|
||||
}
|
||||
|
||||
MaterialTheme(colors = colors) {
|
||||
CompositionLocalProvider(
|
||||
LocalScrollbarStyle provides getScrollbarStyle(),
|
||||
content = content
|
||||
)
|
||||
ExtraColors.WithExtraColors(extraColors) {
|
||||
CompositionLocalProvider(
|
||||
LocalScrollbarStyle provides getScrollbarStyle(),
|
||||
content = content
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +73,7 @@ class AppThemeViewModel @Inject constructor(
|
||||
private val baseThemeScope = CoroutineScope(baseThemeJob)
|
||||
|
||||
@Composable
|
||||
fun getColors(): Colors {
|
||||
fun getColors(): Pair<Colors, ExtraColors> {
|
||||
val themeMode by themeMode.collectAsState()
|
||||
val lightTheme by lightTheme.collectAsState()
|
||||
val darkTheme by darkTheme.collectAsState()
|
||||
@@ -88,8 +91,9 @@ class AppThemeViewModel @Inject constructor(
|
||||
|
||||
val primary by colors.primaryStateFlow.collectAsState()
|
||||
val secondary by colors.secondaryStateFlow.collectAsState()
|
||||
val tertiary by colors.tertiaryStateFlow.collectAsState()
|
||||
|
||||
return getMaterialColors(baseTheme.colors, primary, secondary)
|
||||
return getMaterialColors(baseTheme.colors, primary, secondary) to getExtraColors(baseTheme.extraColors, tertiary)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -131,6 +135,16 @@ class AppThemeViewModel @Inject constructor(
|
||||
)
|
||||
}
|
||||
|
||||
private fun getExtraColors(
|
||||
baseExtraColors: ExtraColors,
|
||||
colorTertiary: Color
|
||||
): ExtraColors {
|
||||
val tertiary = colorTertiary.takeOrElse { baseExtraColors.tertiary }
|
||||
return baseExtraColors.copy(
|
||||
tertiary = tertiary
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDispose() {
|
||||
baseThemeScope.cancel()
|
||||
scope.cancel()
|
||||
|
||||
@@ -24,6 +24,7 @@ import ca.gosyer.jui.domain.manga.model.Manga
|
||||
import ca.gosyer.jui.domain.source.model.Source
|
||||
import ca.gosyer.jui.i18n.MR
|
||||
import ca.gosyer.jui.uicore.resources.stringResource
|
||||
import ca.gosyer.jui.uicore.theme.extraColors
|
||||
|
||||
@Composable
|
||||
fun LibraryMangaBadges(
|
||||
@@ -52,9 +53,9 @@ fun LibraryMangaBadges(
|
||||
if (showUnread && unread != null && unread > 0) {
|
||||
Text(
|
||||
text = unread.toString(),
|
||||
modifier = Modifier.background(MaterialTheme.colors.primary).then(BadgesInnerPadding),
|
||||
modifier = Modifier.background(MaterialTheme.extraColors.tertiary).then(BadgesInnerPadding),
|
||||
style = MaterialTheme.typography.caption,
|
||||
color = MaterialTheme.colors.onPrimary
|
||||
color = MaterialTheme.extraColors.onTertiary
|
||||
)
|
||||
}
|
||||
if (showDownloaded && downloaded != null && downloaded > 0) {
|
||||
|
||||
@@ -6,39 +6,54 @@
|
||||
|
||||
package ca.gosyer.jui.ui.settings
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.add
|
||||
import androidx.compose.foundation.layout.asPaddingValues
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.CornerSize
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Colors
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.CheckCircle
|
||||
import androidx.compose.material.primarySurface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import ca.gosyer.jui.domain.ui.model.ThemeMode
|
||||
import ca.gosyer.jui.domain.ui.service.UiPreferences
|
||||
import ca.gosyer.jui.i18n.MR
|
||||
@@ -53,13 +68,16 @@ import ca.gosyer.jui.ui.base.theme.getLightColors
|
||||
import ca.gosyer.jui.ui.main.components.bottomNav
|
||||
import ca.gosyer.jui.ui.viewModel
|
||||
import ca.gosyer.jui.uicore.components.VerticalScrollbar
|
||||
import ca.gosyer.jui.uicore.components.mangaAspectRatio
|
||||
import ca.gosyer.jui.uicore.components.rememberScrollbarAdapter
|
||||
import ca.gosyer.jui.uicore.components.scrollbarPadding
|
||||
import ca.gosyer.jui.uicore.components.secondaryItemAlpha
|
||||
import ca.gosyer.jui.uicore.insets.navigationBars
|
||||
import ca.gosyer.jui.uicore.insets.statusBars
|
||||
import ca.gosyer.jui.uicore.prefs.PreferenceMutableStateFlow
|
||||
import ca.gosyer.jui.uicore.resources.stringResource
|
||||
import ca.gosyer.jui.uicore.theme.Theme
|
||||
import ca.gosyer.jui.uicore.theme.ExtraColors
|
||||
import ca.gosyer.jui.uicore.theme.extraColors
|
||||
import ca.gosyer.jui.uicore.theme.themes
|
||||
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.jui.uicore.vm.ViewModel
|
||||
@@ -75,12 +93,16 @@ class SettingsAppearanceScreen : Screen {
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val vm = viewModel { themesViewModel() }
|
||||
val appThemeVM = viewModel { appThemeViewModel() }
|
||||
val (colors, extraColors) = appThemeVM.getColors()
|
||||
SettingsAppearanceScreenContent(
|
||||
activeColors = vm.getActiveColors(),
|
||||
themeMode = vm.themeMode,
|
||||
lightTheme = vm.lightTheme,
|
||||
darkTheme = vm.darkTheme,
|
||||
windowDecorations = vm.windowDecorations
|
||||
windowDecorations = vm.windowDecorations,
|
||||
customColors = colors,
|
||||
customExtraColors = extraColors
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -112,12 +134,16 @@ fun SettingsAppearanceScreenContent(
|
||||
themeMode: PreferenceMutableStateFlow<ThemeMode>,
|
||||
lightTheme: PreferenceMutableStateFlow<Int>,
|
||||
darkTheme: PreferenceMutableStateFlow<Int>,
|
||||
windowDecorations: PreferenceMutableStateFlow<Boolean>
|
||||
windowDecorations: PreferenceMutableStateFlow<Boolean>,
|
||||
customColors: Colors,
|
||||
customExtraColors: ExtraColors
|
||||
) {
|
||||
val isLight = MaterialTheme.colors.isLight
|
||||
val themesForCurrentMode = remember(isLight) {
|
||||
themes.filter { it.colors.isLight == isLight }
|
||||
}
|
||||
val currentLightTheme by lightTheme.collectAsState()
|
||||
val currentDarkTheme by darkTheme.collectAsState()
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier.windowInsetsPadding(
|
||||
@@ -138,7 +164,7 @@ fun SettingsAppearanceScreenContent(
|
||||
WindowInsets.navigationBars.only(
|
||||
WindowInsetsSides.Bottom
|
||||
)
|
||||
).asPaddingValues()
|
||||
).asPaddingValues(),
|
||||
) {
|
||||
item {
|
||||
ChoicePreference(
|
||||
@@ -156,16 +182,51 @@ fun SettingsAppearanceScreenContent(
|
||||
stringResource(MR.strings.preset_themes),
|
||||
modifier = Modifier.padding(start = 16.dp, top = 16.dp, bottom = 4.dp)
|
||||
)
|
||||
LazyRow(modifier = Modifier.padding(horizontal = 8.dp)) {
|
||||
LazyRow(
|
||||
modifier = Modifier
|
||||
.animateContentSize()
|
||||
.padding(vertical = 8.dp),
|
||||
contentPadding = PaddingValues(horizontal = 8.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
items(themesForCurrentMode) { theme ->
|
||||
ThemeItem(
|
||||
theme,
|
||||
onClick = {
|
||||
(if (isLight) lightTheme else darkTheme).value = it.id
|
||||
activeColors.primaryStateFlow.value = it.colors.primary
|
||||
activeColors.secondaryStateFlow.value = it.colors.secondary
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.width(114.dp)
|
||||
.padding(top = 8.dp),
|
||||
) {
|
||||
val isSelected = (isLight && currentLightTheme == theme.id) ||
|
||||
(!isLight && currentDarkTheme == theme.id)
|
||||
MaterialTheme(
|
||||
colors = if (isSelected) customColors else theme.colors,
|
||||
) {
|
||||
ExtraColors.WithExtraColors(
|
||||
if (isSelected) customExtraColors else theme.extraColors
|
||||
) {
|
||||
AppThemePreviewItem(
|
||||
selected = isSelected,
|
||||
onClick = {
|
||||
(if (isLight) lightTheme else darkTheme).value = theme.id
|
||||
activeColors.primaryStateFlow.value = theme.colors.primary
|
||||
activeColors.secondaryStateFlow.value = theme.colors.secondary
|
||||
activeColors.tertiaryStateFlow.value = theme.extraColors.tertiary
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
Text(
|
||||
text = stringResource(theme.titleRes),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 8.dp)
|
||||
.secondaryItemAlpha(),
|
||||
color = MaterialTheme.colors.onSurface,
|
||||
textAlign = TextAlign.Center,
|
||||
maxLines = 2,
|
||||
style = MaterialTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -185,6 +246,14 @@ fun SettingsAppearanceScreenContent(
|
||||
unsetColor = MaterialTheme.colors.secondary
|
||||
)
|
||||
}
|
||||
item {
|
||||
ColorPreference(
|
||||
preference = activeColors.tertiaryStateFlow,
|
||||
title = stringResource(MR.strings.color_tertiary),
|
||||
subtitle = stringResource(MR.strings.color_secondary_sub),
|
||||
unsetColor = MaterialTheme.extraColors.tertiary
|
||||
)
|
||||
}
|
||||
if (showWindowDecorationsOption) {
|
||||
item {
|
||||
SwitchPreference(
|
||||
@@ -213,55 +282,132 @@ fun SettingsAppearanceScreenContent(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ThemeItem(
|
||||
theme: Theme,
|
||||
onClick: (Theme) -> Unit
|
||||
fun AppThemePreviewItem(
|
||||
selected: Boolean,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
val borders = MaterialTheme.shapes.small
|
||||
val borderColor = if (theme.colors.isLight) {
|
||||
Color.Black.copy(alpha = 0.25f)
|
||||
} else {
|
||||
Color.White.copy(alpha = 0.15f)
|
||||
}
|
||||
Surface(
|
||||
onClick = { onClick(theme) },
|
||||
elevation = 4.dp,
|
||||
color = theme.colors.background,
|
||||
shape = borders,
|
||||
val dividerColor = MaterialTheme.colors.onSurface.copy(alpha = 0.2F)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.size(100.dp, 160.dp)
|
||||
.padding(8.dp)
|
||||
.border(1.dp, borderColor, borders)
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(9f / 16f)
|
||||
.border(
|
||||
width = 4.dp,
|
||||
color = if (selected) {
|
||||
MaterialTheme.colors.primary
|
||||
} else {
|
||||
dividerColor
|
||||
},
|
||||
shape = RoundedCornerShape(17.dp),
|
||||
)
|
||||
.padding(4.dp)
|
||||
.clip(RoundedCornerShape(13.dp))
|
||||
.background(MaterialTheme.colors.background)
|
||||
.clickable(onClick = onClick),
|
||||
) {
|
||||
Column {
|
||||
// App Bar
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(40.dp)
|
||||
.padding(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f)
|
||||
.padding(6.dp)
|
||||
modifier = Modifier
|
||||
.fillMaxHeight(0.8f)
|
||||
.weight(0.7f)
|
||||
.padding(end = 4.dp)
|
||||
.background(
|
||||
color = MaterialTheme.colors.onSurface,
|
||||
shape = MaterialTheme.shapes.small,
|
||||
),
|
||||
)
|
||||
|
||||
Box(
|
||||
modifier = Modifier.weight(0.3f),
|
||||
contentAlignment = Alignment.CenterEnd,
|
||||
) {
|
||||
Text(stringResource(MR.strings.theme_text), fontSize = 11.sp)
|
||||
Button(
|
||||
onClick = {},
|
||||
enabled = false,
|
||||
contentPadding = PaddingValues(),
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomStart)
|
||||
.size(40.dp, 20.dp),
|
||||
content = {},
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
disabledBackgroundColor = theme.colors.primary
|
||||
if (selected) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.CheckCircle,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colors.primary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cover
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(start = 8.dp, top = 2.dp)
|
||||
.background(
|
||||
color = dividerColor,
|
||||
shape = MaterialTheme.shapes.small,
|
||||
)
|
||||
Surface(
|
||||
Modifier
|
||||
.size(24.dp)
|
||||
.align(Alignment.BottomEnd),
|
||||
shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)),
|
||||
color = theme.colors.secondary,
|
||||
elevation = 6.dp,
|
||||
content = { }
|
||||
.fillMaxWidth(0.5f)
|
||||
.aspectRatio(mangaAspectRatio),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(4.dp)
|
||||
.size(width = 24.dp, height = 16.dp)
|
||||
.clip(RoundedCornerShape(5.dp)),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.width(12.dp)
|
||||
.background(MaterialTheme.extraColors.tertiary),
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.width(12.dp)
|
||||
.background(MaterialTheme.colors.secondary),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom bar
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f),
|
||||
contentAlignment = Alignment.BottomCenter,
|
||||
) {
|
||||
Surface(
|
||||
elevation = 3.dp,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.height(32.dp)
|
||||
.fillMaxWidth()
|
||||
.background(MaterialTheme.colors.primarySurface)
|
||||
.padding(horizontal = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(17.dp)
|
||||
.background(
|
||||
color = MaterialTheme.colors.primary,
|
||||
shape = CircleShape,
|
||||
),
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(start = 8.dp)
|
||||
.alpha(0.6f)
|
||||
.height(17.dp)
|
||||
.weight(1f)
|
||||
.background(
|
||||
color = MaterialTheme.colors.onSurface,
|
||||
shape = MaterialTheme.shapes.small,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.jui.uicore.components
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
private val horizontal = 16.dp
|
||||
private val vertical = 8.dp
|
||||
|
||||
val horizontalPadding = horizontal
|
||||
val verticalPadding = vertical
|
||||
|
||||
val topPaddingValues = PaddingValues(top = vertical)
|
||||
|
||||
const val ReadItemAlpha = .38f
|
||||
const val SecondaryItemAlpha = .78f
|
||||
@@ -11,6 +11,7 @@ import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
import androidx.compose.ui.draw.alpha
|
||||
|
||||
fun Modifier.selectedBackground(isSelected: Boolean): Modifier = composed {
|
||||
if (isSelected) {
|
||||
@@ -20,3 +21,5 @@ fun Modifier.selectedBackground(isSelected: Boolean): Modifier = composed {
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
fun Modifier.secondaryItemAlpha(): Modifier = this.alpha(SecondaryItemAlpha)
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.jui.uicore.theme
|
||||
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
import androidx.compose.runtime.structuralEqualityPolicy
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
@Stable
|
||||
class ExtraColors(
|
||||
tertiary: Color,
|
||||
onTertiary: Color,
|
||||
) {
|
||||
var tertiary by mutableStateOf(tertiary, structuralEqualityPolicy())
|
||||
internal set
|
||||
var onTertiary by mutableStateOf(onTertiary, structuralEqualityPolicy())
|
||||
internal set
|
||||
|
||||
fun copy(
|
||||
tertiary: Color = this.tertiary,
|
||||
onTertiary: Color = this.onTertiary,
|
||||
): ExtraColors = ExtraColors(
|
||||
tertiary,
|
||||
onTertiary,
|
||||
)
|
||||
|
||||
override fun toString(): String {
|
||||
return "ExtraColors(" +
|
||||
"tertiary=$tertiary, " +
|
||||
"onTertiary=$onTertiary, " +
|
||||
")"
|
||||
}
|
||||
|
||||
companion object {
|
||||
@Composable
|
||||
fun WithExtraColors(extraColors: ExtraColors, content: @Composable () -> Unit) {
|
||||
CompositionLocalProvider(
|
||||
LocalExtraColors provides extraColors,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val MaterialTheme.extraColors: ExtraColors
|
||||
@Composable
|
||||
get() = LocalExtraColors.current
|
||||
|
||||
private val LocalExtraColors = staticCompositionLocalOf<ExtraColors> {
|
||||
error("The AppColors composable must be called before usage")
|
||||
}
|
||||
@@ -10,21 +10,92 @@ import androidx.compose.material.Colors
|
||||
import androidx.compose.material.darkColors
|
||||
import androidx.compose.material.lightColors
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import ca.gosyer.jui.i18n.MR
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
|
||||
data class Theme(
|
||||
val id: Int,
|
||||
val colors: Colors
|
||||
val titleRes: StringResource,
|
||||
val colors: Colors,
|
||||
val extraColors: ExtraColors
|
||||
)
|
||||
|
||||
fun tachiyomiLightColors(
|
||||
primary: Color = Color(0xFF0057CE),
|
||||
primaryVariant: Color = Color(0xFF001947),
|
||||
secondary: Color = Color(0xFF0057CE),
|
||||
secondaryVariant: Color = Color(0xFF018786),
|
||||
background: Color = Color(0xFFFDFBFF),
|
||||
surface: Color = Color(0xFFFDFBFF),
|
||||
error: Color = Color(0xFFB00020),
|
||||
onPrimary: Color = Color.White,
|
||||
onSecondary: Color = Color.White,
|
||||
onBackground: Color = Color(0xFF1B1B1E),
|
||||
onSurface: Color = Color(0xFF1B1B1E),
|
||||
onError: Color = Color.White
|
||||
) = lightColors(
|
||||
primary = primary,
|
||||
primaryVariant = primaryVariant,
|
||||
secondary = secondary,
|
||||
secondaryVariant = secondaryVariant,
|
||||
background = background,
|
||||
surface = surface,
|
||||
error = error,
|
||||
onPrimary = onPrimary,
|
||||
onSecondary = onSecondary,
|
||||
onBackground = onBackground,
|
||||
onSurface = onSurface,
|
||||
onError = onError
|
||||
)
|
||||
|
||||
fun tachiyomiDarkColors(
|
||||
primary: Color = Color(0xFFAEC6FF),
|
||||
primaryVariant: Color = Color(0xFF00419E),
|
||||
secondary: Color = Color(0xFFAEC6FF),
|
||||
secondaryVariant: Color = Color(0xFF00419E),
|
||||
background: Color = Color(0xFF1B1B1E),
|
||||
surface: Color = Color(0xFF1B1B1E),
|
||||
error: Color = Color(0xFFCF6679),
|
||||
onPrimary: Color = Color(0xFF002C71),
|
||||
onSecondary: Color = Color(0xFF002C71),
|
||||
onBackground: Color = Color(0xFFE4E2E6),
|
||||
onSurface: Color = Color(0xFFE4E2E6),
|
||||
onError: Color = Color.White
|
||||
) = darkColors(
|
||||
primary = primary,
|
||||
primaryVariant = primaryVariant,
|
||||
secondary = secondary,
|
||||
secondaryVariant = secondaryVariant,
|
||||
background = background,
|
||||
surface = surface,
|
||||
error = error,
|
||||
onPrimary = onPrimary,
|
||||
onSecondary = onSecondary,
|
||||
onBackground = onBackground,
|
||||
onSurface = onSurface,
|
||||
onError = onError
|
||||
)
|
||||
|
||||
fun extraColors(
|
||||
tertiary: Color = Color(0xFF006E17),
|
||||
onTertiary: Color = Color.White,
|
||||
) = ExtraColors(
|
||||
tertiary = tertiary,
|
||||
onTertiary = onTertiary
|
||||
)
|
||||
|
||||
val themes = listOf(
|
||||
// Pure white
|
||||
Theme(
|
||||
1,
|
||||
lightColors()
|
||||
),
|
||||
// Tachiyomi 0.x default colors
|
||||
Theme(
|
||||
1,
|
||||
MR.strings.theme_default,
|
||||
tachiyomiLightColors(),
|
||||
extraColors()
|
||||
),
|
||||
// Tachiyomi 0.x legacy blue theme
|
||||
Theme(
|
||||
2,
|
||||
MR.strings.theme_legacy_blue,
|
||||
lightColors(
|
||||
primary = Color(0xFF2979FF),
|
||||
primaryVariant = Color(0xFF2979FF),
|
||||
@@ -32,20 +103,29 @@ val themes = listOf(
|
||||
secondary = Color(0xFF2979FF),
|
||||
secondaryVariant = Color(0xFF2979FF),
|
||||
onSecondary = Color.White
|
||||
)
|
||||
),
|
||||
extraColors()
|
||||
),
|
||||
// Tachiyomi 0.x dark theme
|
||||
Theme(
|
||||
3,
|
||||
darkColors()
|
||||
MR.strings.theme_default,
|
||||
tachiyomiDarkColors(),
|
||||
extraColors(
|
||||
tertiary = Color(0xFF7ADC77),
|
||||
onTertiary = Color(0xFF003907)
|
||||
)
|
||||
),
|
||||
// AMOLED theme
|
||||
Theme(
|
||||
4,
|
||||
darkColors(
|
||||
MR.strings.theme_amoled,
|
||||
tachiyomiDarkColors(
|
||||
primary = Color.Black,
|
||||
onPrimary = Color.White,
|
||||
background = Color.Black
|
||||
)
|
||||
background = Color.Black,
|
||||
surface = Color.Black
|
||||
),
|
||||
extraColors()
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user