🚀 Elevate Settings category icon background

* Material3 style Settings items
* Reformatted code
This commit is contained in:
Acclorite 2025-02-17 20:40:06 +02:00
parent 30a0febf03
commit a6b340c0c8
34 changed files with 261 additions and 182 deletions

View file

@ -6,6 +6,9 @@
package ua.acclorite.book_story.domain.browse package ua.acclorite.book_story.domain.browse
import androidx.compose.runtime.Immutable
@Immutable
enum class BrowseLayout { enum class BrowseLayout {
LIST, GRID LIST, GRID
} }

View file

@ -6,6 +6,9 @@
package ua.acclorite.book_story.domain.browse package ua.acclorite.book_story.domain.browse
import androidx.compose.runtime.Immutable
@Immutable
enum class BrowseSortOrder { enum class BrowseSortOrder {
NAME, NAME,
FILE_FORMAT, FILE_FORMAT,

View file

@ -6,9 +6,11 @@
package ua.acclorite.book_story.domain.library.category package ua.acclorite.book_story.domain.library.category
import androidx.compose.runtime.Immutable
import ua.acclorite.book_story.domain.library.book.SelectableBook import ua.acclorite.book_story.domain.library.book.SelectableBook
import ua.acclorite.book_story.domain.ui.UIText import ua.acclorite.book_story.domain.ui.UIText
@Immutable
data class CategoryWithBooks( data class CategoryWithBooks(
val category: Category, val category: Category,
val title: UIText, val title: UIText,

View file

@ -6,6 +6,9 @@
package ua.acclorite.book_story.domain.reader package ua.acclorite.book_story.domain.reader
import androidx.compose.runtime.Immutable
@Immutable
enum class ReaderColorEffects { enum class ReaderColorEffects {
OFF, OFF,
GRAYSCALE, GRAYSCALE,

View file

@ -6,6 +6,9 @@
package ua.acclorite.book_story.domain.reader package ua.acclorite.book_story.domain.reader
import androidx.compose.runtime.Immutable
@Immutable
enum class ReaderHorizontalGesture { enum class ReaderHorizontalGesture {
OFF, OFF,
ON, ON,

View file

@ -7,7 +7,9 @@
package ua.acclorite.book_story.domain.reader package ua.acclorite.book_story.domain.reader
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import androidx.compose.runtime.Immutable
@Immutable
enum class ReaderScreenOrientation(val code: Int) { enum class ReaderScreenOrientation(val code: Int) {
DEFAULT(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED), DEFAULT(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED),
FREE(ActivityInfo.SCREEN_ORIENTATION_USER), FREE(ActivityInfo.SCREEN_ORIENTATION_USER),

View file

@ -0,0 +1,31 @@
/*
* Book's Story free and open-source Material You eBook reader.
* Copyright (C) 2024-2025 Acclorite
* SPDX-License-Identifier: GPL-3.0-only
*/
package ua.acclorite.book_story.domain.ui
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
@Immutable
enum class DarkTheme {
FOLLOW_SYSTEM,
OFF,
ON
}
fun String.toDarkTheme(): DarkTheme {
return DarkTheme.valueOf(this)
}
@Composable
fun DarkTheme.isDark(): Boolean {
return when (this) {
DarkTheme.FOLLOW_SYSTEM -> isSystemInDarkTheme()
DarkTheme.ON -> true
DarkTheme.OFF -> false
}
}

View file

@ -0,0 +1,34 @@
/*
* Book's Story free and open-source Material You eBook reader.
* Copyright (C) 2024-2025 Acclorite
* SPDX-License-Identifier: GPL-3.0-only
*/
package ua.acclorite.book_story.domain.ui
import android.content.Context
import android.os.PowerManager
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
@Immutable
enum class PureDark {
OFF,
ON,
SAVER
}
fun String.toPureDark(): PureDark {
return PureDark.valueOf(this)
}
@Composable
fun PureDark.isPureDark(context: Context): Boolean {
val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
return when (this) {
PureDark.OFF -> false
PureDark.ON -> true
PureDark.SAVER -> powerManager.isPowerSaveMode
}
}

View file

@ -0,0 +1,20 @@
/*
* Book's Story free and open-source Material You eBook reader.
* Copyright (C) 2024-2025 Acclorite
* SPDX-License-Identifier: GPL-3.0-only
*/
package ua.acclorite.book_story.domain.ui
import androidx.compose.runtime.Immutable
@Immutable
enum class ThemeContrast {
STANDARD,
MEDIUM,
HIGH
}
fun String.toThemeContrast(): ThemeContrast {
return ThemeContrast.valueOf(this)
}

View file

@ -38,8 +38,8 @@ import ua.acclorite.book_story.presentation.core.components.common.IconButton
import ua.acclorite.book_story.presentation.core.components.common.StyledText import ua.acclorite.book_story.presentation.core.components.common.StyledText
import ua.acclorite.book_story.presentation.core.util.noRippleClickable import ua.acclorite.book_story.presentation.core.util.noRippleClickable
import ua.acclorite.book_story.ui.reader.ReaderEvent import ua.acclorite.book_story.ui.reader.ReaderEvent
import ua.acclorite.book_story.ui.theme.Colors
import ua.acclorite.book_story.ui.theme.HorizontalExpandingTransition import ua.acclorite.book_story.ui.theme.HorizontalExpandingTransition
import ua.acclorite.book_story.ui.theme.readerBarsColor
@Composable @Composable
fun ReaderBottomBar( fun ReaderBottomBar(
@ -75,7 +75,7 @@ fun ReaderBottomBar(
Column( Column(
Modifier Modifier
.fillMaxWidth() .fillMaxWidth()
.background(Colors.readerSystemBarsColor) .background(MaterialTheme.colorScheme.readerBarsColor)
.noRippleClickable(onClick = {}) .noRippleClickable(onClick = {})
.navigationBarsPadding() .navigationBarsPadding()
.padding(horizontal = 18.dp), .padding(horizontal = 18.dp),

View file

@ -37,7 +37,7 @@ import ua.acclorite.book_story.presentation.core.util.LocalActivity
import ua.acclorite.book_story.presentation.core.util.noRippleClickable import ua.acclorite.book_story.presentation.core.util.noRippleClickable
import ua.acclorite.book_story.ui.reader.ReaderEvent import ua.acclorite.book_story.ui.reader.ReaderEvent
import ua.acclorite.book_story.ui.settings.SettingsEvent import ua.acclorite.book_story.ui.settings.SettingsEvent
import ua.acclorite.book_story.ui.theme.Colors import ua.acclorite.book_story.ui.theme.readerBarsColor
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable @Composable
@ -64,7 +64,7 @@ fun ReaderTopBar(
Column( Column(
Modifier Modifier
.fillMaxWidth() .fillMaxWidth()
.background(Colors.readerSystemBarsColor) .background(MaterialTheme.colorScheme.readerBarsColor)
.readerColorPresetChange( .readerColorPresetChange(
colorPresetChangeEnabled = fastColorPresetChange, colorPresetChangeEnabled = fastColorPresetChange,
isLoading = isLoading, isLoading = isLoading,

View file

@ -40,6 +40,7 @@ fun SettingsLayout(
) { ) {
item { item {
SettingsLayoutItem( SettingsLayoutItem(
index = 0,
icon = Icons.Outlined.DisplaySettings, icon = Icons.Outlined.DisplaySettings,
title = stringResource(id = R.string.general_settings), title = stringResource(id = R.string.general_settings),
description = stringResource(id = R.string.general_settings_desc) description = stringResource(id = R.string.general_settings_desc)
@ -50,6 +51,7 @@ fun SettingsLayout(
item { item {
SettingsLayoutItem( SettingsLayoutItem(
index = 1,
icon = Icons.Outlined.Palette, icon = Icons.Outlined.Palette,
title = stringResource(id = R.string.appearance_settings), title = stringResource(id = R.string.appearance_settings),
description = stringResource(id = R.string.appearance_settings_desc) description = stringResource(id = R.string.appearance_settings_desc)
@ -60,6 +62,7 @@ fun SettingsLayout(
item { item {
SettingsLayoutItem( SettingsLayoutItem(
index = 2,
icon = Icons.Outlined.LocalLibrary, icon = Icons.Outlined.LocalLibrary,
title = stringResource(id = R.string.reader_settings), title = stringResource(id = R.string.reader_settings),
description = stringResource(id = R.string.reader_settings_desc) description = stringResource(id = R.string.reader_settings_desc)
@ -70,6 +73,7 @@ fun SettingsLayout(
item { item {
SettingsLayoutItem( SettingsLayoutItem(
index = 3,
icon = Icons.Outlined.Explore, icon = Icons.Outlined.Explore,
title = stringResource(id = R.string.browse_settings), title = stringResource(id = R.string.browse_settings),
description = stringResource(id = R.string.browse_settings_desc) description = stringResource(id = R.string.browse_settings_desc)

View file

@ -6,6 +6,7 @@
package ua.acclorite.book_story.presentation.settings package ua.acclorite.book_story.presentation.settings
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@ -13,6 +14,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@ -24,9 +26,11 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import ua.acclorite.book_story.presentation.core.components.common.StyledText import ua.acclorite.book_story.presentation.core.components.common.StyledText
import ua.acclorite.book_story.ui.theme.dynamicListItemColor
@Composable @Composable
fun SettingsLayoutItem( fun SettingsLayoutItem(
index: Int,
icon: ImageVector, icon: ImageVector,
title: String, title: String,
description: String, description: String,
@ -37,16 +41,21 @@ fun SettingsLayoutItem(
.fillMaxWidth() .fillMaxWidth()
.clip(MaterialTheme.shapes.extraLarge) .clip(MaterialTheme.shapes.extraLarge)
.clickable { onClick() } .clickable { onClick() }
.padding(vertical = 20.dp, horizontal = 24.dp), .padding(vertical = 18.dp, horizontal = 24.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(18.dp) horizontalArrangement = Arrangement.spacedBy(18.dp)
) { ) {
Icon( Icon(
imageVector = icon, imageVector = icon,
contentDescription = null, contentDescription = null,
modifier = Modifier.size(24.dp), modifier = Modifier
tint = MaterialTheme.colorScheme.onSurfaceVariant .clip(CircleShape)
.background(MaterialTheme.colorScheme.dynamicListItemColor(index))
.padding(12.dp)
.size(24.dp),
tint = MaterialTheme.colorScheme.onSurface
) )
Column { Column {
StyledText( StyledText(
text = title, text = title,

View file

@ -12,12 +12,12 @@ import androidx.compose.ui.res.stringResource
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import ua.acclorite.book_story.R import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.ui.isDark
import ua.acclorite.book_story.domain.ui.isPureDark
import ua.acclorite.book_story.presentation.core.components.settings.SwitchWithTitle import ua.acclorite.book_story.presentation.core.components.settings.SwitchWithTitle
import ua.acclorite.book_story.ui.main.MainEvent import ua.acclorite.book_story.ui.main.MainEvent
import ua.acclorite.book_story.ui.main.MainModel import ua.acclorite.book_story.ui.main.MainModel
import ua.acclorite.book_story.ui.theme.ExpandingTransition import ua.acclorite.book_story.ui.theme.ExpandingTransition
import ua.acclorite.book_story.ui.theme.isDark
import ua.acclorite.book_story.ui.theme.isPureDark
@Composable @Composable
fun AbsoluteDarkOption() { fun AbsoluteDarkOption() {

View file

@ -42,16 +42,16 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import ua.acclorite.book_story.R import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.ui.ThemeContrast
import ua.acclorite.book_story.domain.ui.isDark
import ua.acclorite.book_story.domain.ui.isPureDark
import ua.acclorite.book_story.presentation.core.components.common.AnimatedVisibility import ua.acclorite.book_story.presentation.core.components.common.AnimatedVisibility
import ua.acclorite.book_story.presentation.core.components.common.StyledText import ua.acclorite.book_story.presentation.core.components.common.StyledText
import ua.acclorite.book_story.presentation.settings.components.SettingsSubcategoryTitle import ua.acclorite.book_story.presentation.settings.components.SettingsSubcategoryTitle
import ua.acclorite.book_story.ui.main.MainEvent import ua.acclorite.book_story.ui.main.MainEvent
import ua.acclorite.book_story.ui.main.MainModel import ua.acclorite.book_story.ui.main.MainModel
import ua.acclorite.book_story.ui.theme.Theme import ua.acclorite.book_story.ui.theme.Theme
import ua.acclorite.book_story.ui.theme.ThemeContrast
import ua.acclorite.book_story.ui.theme.animatedColorScheme import ua.acclorite.book_story.ui.theme.animatedColorScheme
import ua.acclorite.book_story.ui.theme.isDark
import ua.acclorite.book_story.ui.theme.isPureDark
@Composable @Composable
fun AppThemeOption() { fun AppThemeOption() {

View file

@ -13,10 +13,10 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import ua.acclorite.book_story.R import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.ui.ButtonItem import ua.acclorite.book_story.domain.ui.ButtonItem
import ua.acclorite.book_story.domain.ui.DarkTheme
import ua.acclorite.book_story.presentation.core.components.settings.SegmentedButtonWithTitle import ua.acclorite.book_story.presentation.core.components.settings.SegmentedButtonWithTitle
import ua.acclorite.book_story.ui.main.MainEvent import ua.acclorite.book_story.ui.main.MainEvent
import ua.acclorite.book_story.ui.main.MainModel import ua.acclorite.book_story.ui.main.MainModel
import ua.acclorite.book_story.ui.theme.DarkTheme
@Composable @Composable
fun DarkThemeOption() { fun DarkThemeOption() {

View file

@ -13,12 +13,12 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import ua.acclorite.book_story.R import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.ui.ButtonItem import ua.acclorite.book_story.domain.ui.ButtonItem
import ua.acclorite.book_story.domain.ui.PureDark
import ua.acclorite.book_story.domain.ui.isDark
import ua.acclorite.book_story.presentation.core.components.settings.SegmentedButtonWithTitle import ua.acclorite.book_story.presentation.core.components.settings.SegmentedButtonWithTitle
import ua.acclorite.book_story.ui.main.MainEvent import ua.acclorite.book_story.ui.main.MainEvent
import ua.acclorite.book_story.ui.main.MainModel import ua.acclorite.book_story.ui.main.MainModel
import ua.acclorite.book_story.ui.theme.ExpandingTransition import ua.acclorite.book_story.ui.theme.ExpandingTransition
import ua.acclorite.book_story.ui.theme.PureDark
import ua.acclorite.book_story.ui.theme.isDark
@Composable @Composable
fun PureDarkOption() { fun PureDarkOption() {

View file

@ -17,14 +17,14 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import ua.acclorite.book_story.R import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.ui.ButtonItem import ua.acclorite.book_story.domain.ui.ButtonItem
import ua.acclorite.book_story.domain.ui.ThemeContrast
import ua.acclorite.book_story.domain.ui.isDark
import ua.acclorite.book_story.domain.ui.isPureDark
import ua.acclorite.book_story.presentation.core.components.settings.SegmentedButtonWithTitle import ua.acclorite.book_story.presentation.core.components.settings.SegmentedButtonWithTitle
import ua.acclorite.book_story.ui.main.MainEvent import ua.acclorite.book_story.ui.main.MainEvent
import ua.acclorite.book_story.ui.main.MainModel import ua.acclorite.book_story.ui.main.MainModel
import ua.acclorite.book_story.ui.theme.BookStoryTheme import ua.acclorite.book_story.ui.theme.BookStoryTheme
import ua.acclorite.book_story.ui.theme.ExpandingTransition import ua.acclorite.book_story.ui.theme.ExpandingTransition
import ua.acclorite.book_story.ui.theme.ThemeContrast
import ua.acclorite.book_story.ui.theme.isDark
import ua.acclorite.book_story.ui.theme.isPureDark
@Composable @Composable
fun ThemeContrastOption() { fun ThemeContrastOption() {

View file

@ -25,6 +25,8 @@ import okhttp3.internal.immutableListOf
import ua.acclorite.book_story.R import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.navigator.NavigatorItem import ua.acclorite.book_story.domain.navigator.NavigatorItem
import ua.acclorite.book_story.domain.navigator.StackEvent import ua.acclorite.book_story.domain.navigator.StackEvent
import ua.acclorite.book_story.domain.ui.isDark
import ua.acclorite.book_story.domain.ui.isPureDark
import ua.acclorite.book_story.presentation.core.components.navigation_bar.NavigationBar import ua.acclorite.book_story.presentation.core.components.navigation_bar.NavigationBar
import ua.acclorite.book_story.presentation.core.components.navigation_rail.NavigationRail import ua.acclorite.book_story.presentation.core.components.navigation_rail.NavigationRail
import ua.acclorite.book_story.presentation.main.MainActivityKeyboardManager import ua.acclorite.book_story.presentation.main.MainActivityKeyboardManager
@ -40,8 +42,6 @@ import ua.acclorite.book_story.ui.settings.SettingsModel
import ua.acclorite.book_story.ui.start.StartScreen import ua.acclorite.book_story.ui.start.StartScreen
import ua.acclorite.book_story.ui.theme.BookStoryTheme import ua.acclorite.book_story.ui.theme.BookStoryTheme
import ua.acclorite.book_story.ui.theme.Transitions import ua.acclorite.book_story.ui.theme.Transitions
import ua.acclorite.book_story.ui.theme.isDark
import ua.acclorite.book_story.ui.theme.isPureDark
import java.lang.reflect.Field import java.lang.reflect.Field

View file

@ -30,6 +30,9 @@ import ua.acclorite.book_story.domain.reader.toHorizontalGesture
import ua.acclorite.book_story.domain.reader.toProgressCount import ua.acclorite.book_story.domain.reader.toProgressCount
import ua.acclorite.book_story.domain.reader.toReaderScreenOrientation import ua.acclorite.book_story.domain.reader.toReaderScreenOrientation
import ua.acclorite.book_story.domain.reader.toTextAlignment import ua.acclorite.book_story.domain.reader.toTextAlignment
import ua.acclorite.book_story.domain.ui.toDarkTheme
import ua.acclorite.book_story.domain.ui.toPureDark
import ua.acclorite.book_story.domain.ui.toThemeContrast
import ua.acclorite.book_story.domain.use_case.data_store.ChangeLanguage import ua.acclorite.book_story.domain.use_case.data_store.ChangeLanguage
import ua.acclorite.book_story.domain.use_case.data_store.GetAllSettings import ua.acclorite.book_story.domain.use_case.data_store.GetAllSettings
import ua.acclorite.book_story.domain.use_case.data_store.SetDatastore import ua.acclorite.book_story.domain.use_case.data_store.SetDatastore
@ -38,10 +41,7 @@ import ua.acclorite.book_story.presentation.core.constants.Constants
import ua.acclorite.book_story.presentation.core.constants.DataStoreConstants import ua.acclorite.book_story.presentation.core.constants.DataStoreConstants
import ua.acclorite.book_story.presentation.core.constants.provideFonts import ua.acclorite.book_story.presentation.core.constants.provideFonts
import ua.acclorite.book_story.presentation.core.constants.provideMainState import ua.acclorite.book_story.presentation.core.constants.provideMainState
import ua.acclorite.book_story.ui.theme.toDarkTheme
import ua.acclorite.book_story.ui.theme.toPureDark
import ua.acclorite.book_story.ui.theme.toTheme import ua.acclorite.book_story.ui.theme.toTheme
import ua.acclorite.book_story.ui.theme.toThemeContrast
import javax.inject.Inject import javax.inject.Inject

View file

@ -29,20 +29,20 @@ import ua.acclorite.book_story.domain.reader.toHorizontalGesture
import ua.acclorite.book_story.domain.reader.toProgressCount import ua.acclorite.book_story.domain.reader.toProgressCount
import ua.acclorite.book_story.domain.reader.toReaderScreenOrientation import ua.acclorite.book_story.domain.reader.toReaderScreenOrientation
import ua.acclorite.book_story.domain.reader.toTextAlignment import ua.acclorite.book_story.domain.reader.toTextAlignment
import ua.acclorite.book_story.domain.ui.DarkTheme
import ua.acclorite.book_story.domain.ui.PureDark
import ua.acclorite.book_story.domain.ui.ThemeContrast
import ua.acclorite.book_story.domain.ui.toDarkTheme
import ua.acclorite.book_story.domain.ui.toPureDark
import ua.acclorite.book_story.domain.ui.toThemeContrast
import ua.acclorite.book_story.domain.util.HorizontalAlignment import ua.acclorite.book_story.domain.util.HorizontalAlignment
import ua.acclorite.book_story.domain.util.toHorizontalAlignment import ua.acclorite.book_story.domain.util.toHorizontalAlignment
import ua.acclorite.book_story.presentation.core.constants.Constants import ua.acclorite.book_story.presentation.core.constants.Constants
import ua.acclorite.book_story.presentation.core.constants.DataStoreConstants import ua.acclorite.book_story.presentation.core.constants.DataStoreConstants
import ua.acclorite.book_story.presentation.core.constants.provideFonts import ua.acclorite.book_story.presentation.core.constants.provideFonts
import ua.acclorite.book_story.presentation.core.constants.provideLanguages import ua.acclorite.book_story.presentation.core.constants.provideLanguages
import ua.acclorite.book_story.ui.theme.DarkTheme
import ua.acclorite.book_story.ui.theme.PureDark
import ua.acclorite.book_story.ui.theme.Theme import ua.acclorite.book_story.ui.theme.Theme
import ua.acclorite.book_story.ui.theme.ThemeContrast
import ua.acclorite.book_story.ui.theme.toDarkTheme
import ua.acclorite.book_story.ui.theme.toPureDark
import ua.acclorite.book_story.ui.theme.toTheme import ua.acclorite.book_story.ui.theme.toTheme
import ua.acclorite.book_story.ui.theme.toThemeContrast
import java.util.Locale import java.util.Locale
/** /**

View file

@ -0,0 +1,82 @@
/*
* Book's Story free and open-source Material You eBook reader.
* Copyright (C) 2024-2025 Acclorite
* SPDX-License-Identifier: GPL-3.0-only
*/
package ua.acclorite.book_story.ui.theme
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.tween
import androidx.compose.material3.ColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import ua.acclorite.book_story.domain.ui.ThemeContrast
@Composable
private fun animateColor(targetColor: Color): Color {
return animateColorAsState(
targetValue = targetColor,
animationSpec = tween(300),
label = ""
).value
}
@Composable
fun animateColorScheme(targetColorScheme: ColorScheme): ColorScheme {
return ColorScheme(
primary = animateColor(targetColor = targetColorScheme.primary),
onPrimary = animateColor(targetColor = targetColorScheme.onPrimary),
primaryContainer = animateColor(targetColor = targetColorScheme.primaryContainer),
onPrimaryContainer = animateColor(targetColor = targetColorScheme.onPrimaryContainer),
secondary = animateColor(targetColor = targetColorScheme.secondary),
onSecondary = animateColor(targetColor = targetColorScheme.onSecondary),
secondaryContainer = animateColor(targetColor = targetColorScheme.secondaryContainer),
onSecondaryContainer = animateColor(targetColor = targetColorScheme.onSecondaryContainer),
tertiary = animateColor(targetColor = targetColorScheme.tertiary),
onTertiary = animateColor(targetColor = targetColorScheme.onTertiary),
tertiaryContainer = animateColor(targetColor = targetColorScheme.tertiaryContainer),
onTertiaryContainer = animateColor(targetColor = targetColorScheme.onTertiaryContainer),
error = animateColor(targetColor = targetColorScheme.error),
errorContainer = animateColor(targetColor = targetColorScheme.errorContainer),
onError = animateColor(targetColor = targetColorScheme.onError),
onErrorContainer = animateColor(targetColor = targetColorScheme.onErrorContainer),
background = animateColor(targetColor = targetColorScheme.background),
onBackground = animateColor(targetColor = targetColorScheme.onBackground),
surface = animateColor(targetColor = targetColorScheme.surface),
onSurface = animateColor(targetColor = targetColorScheme.onSurface),
surfaceVariant = animateColor(targetColor = targetColorScheme.surfaceVariant),
onSurfaceVariant = animateColor(targetColor = targetColorScheme.onSurfaceVariant),
outline = animateColor(targetColor = targetColorScheme.outline),
inverseOnSurface = animateColor(targetColor = targetColorScheme.inverseOnSurface),
inverseSurface = animateColor(targetColor = targetColorScheme.inverseSurface),
inversePrimary = animateColor(targetColor = targetColorScheme.inversePrimary),
surfaceTint = animateColor(targetColor = targetColorScheme.surfaceTint),
outlineVariant = animateColor(targetColor = targetColorScheme.outlineVariant),
scrim = animateColor(targetColor = targetColorScheme.scrim),
surfaceBright = animateColor(targetColor = targetColorScheme.surfaceBright),
surfaceDim = animateColor(targetColor = targetColorScheme.surfaceDim),
surfaceContainer = animateColor(targetColor = targetColorScheme.surfaceContainer),
surfaceContainerHigh = animateColor(targetColor = targetColorScheme.surfaceContainerHigh),
surfaceContainerHighest = animateColor(targetColor = targetColorScheme.surfaceContainerHighest),
surfaceContainerLow = animateColor(targetColor = targetColorScheme.surfaceContainerLow),
surfaceContainerLowest = animateColor(targetColor = targetColorScheme.surfaceContainerLowest),
)
}
@Composable
fun animatedColorScheme(
theme: Theme,
isDark: Boolean,
isPureDark: Boolean,
themeContrast: ThemeContrast
): ColorScheme {
val colorScheme = colorScheme(
theme = theme,
darkTheme = isDark,
isPureDark = isPureDark,
themeContrast = themeContrast
)
return animateColorScheme(targetColorScheme = colorScheme)
}

View file

@ -12,6 +12,7 @@ import androidx.compose.material3.ColorScheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Immutable
import ua.acclorite.book_story.R import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.ui.ThemeContrast
import ua.acclorite.book_story.ui.theme.color.aquaTheme import ua.acclorite.book_story.ui.theme.color.aquaTheme
import ua.acclorite.book_story.ui.theme.color.blackTheme import ua.acclorite.book_story.ui.theme.color.blackTheme
import ua.acclorite.book_story.ui.theme.color.blueTheme import ua.acclorite.book_story.ui.theme.color.blueTheme

View file

@ -7,85 +7,16 @@
package ua.acclorite.book_story.ui.theme package ua.acclorite.book_story.ui.theme
import android.app.Activity import android.app.Activity
import android.content.Context
import android.os.Build import android.os.Build
import android.os.Parcelable
import android.os.PowerManager
import android.view.View import android.view.View
import androidx.annotation.Keep
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Shapes import androidx.compose.material3.Shapes
import androidx.compose.material3.Typography import androidx.compose.material3.Typography
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.SideEffect import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import kotlinx.parcelize.Parcelize import ua.acclorite.book_story.domain.ui.ThemeContrast
@Immutable
@Keep
@Parcelize
enum class PureDark : Parcelable {
OFF,
ON,
SAVER
}
@Immutable
@Keep
@Parcelize
enum class ThemeContrast : Parcelable {
STANDARD,
MEDIUM,
HIGH
}
@Immutable
@Keep
@Parcelize
enum class DarkTheme : Parcelable {
FOLLOW_SYSTEM,
OFF,
ON
}
fun String.toDarkTheme(): DarkTheme {
return DarkTheme.valueOf(this)
}
fun String.toPureDark(): PureDark {
return PureDark.valueOf(this)
}
fun String.toThemeContrast(): ThemeContrast {
return ThemeContrast.valueOf(this)
}
@Composable
fun DarkTheme.isDark(): Boolean {
return when (this) {
DarkTheme.FOLLOW_SYSTEM -> isSystemInDarkTheme()
DarkTheme.ON -> true
DarkTheme.OFF -> false
}
}
@Composable
fun PureDark.isPureDark(context: Context): Boolean {
val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
return when (this) {
PureDark.OFF -> false
PureDark.ON -> true
PureDark.SAVER -> powerManager.isPowerSaveMode
}
}
@Composable @Composable
fun BookStoryTheme( fun BookStoryTheme(
@ -128,78 +59,4 @@ fun BookStoryTheme(
typography = Typography(), typography = Typography(),
content = content content = content
) )
}
object Colors {
val readerSystemBarsColor: Color
@Composable
get() = MaterialTheme.colorScheme.surfaceContainer.copy(0.9f)
}
@Composable
private fun animateColor(targetColor: Color): Color {
return animateColorAsState(
targetValue = targetColor,
animationSpec = tween(300),
label = ""
).value
}
@Composable
private fun animateColorScheme(targetColorScheme: ColorScheme): ColorScheme {
return ColorScheme(
primary = animateColor(targetColor = targetColorScheme.primary),
onPrimary = animateColor(targetColor = targetColorScheme.onPrimary),
primaryContainer = animateColor(targetColor = targetColorScheme.primaryContainer),
onPrimaryContainer = animateColor(targetColor = targetColorScheme.onPrimaryContainer),
secondary = animateColor(targetColor = targetColorScheme.secondary),
onSecondary = animateColor(targetColor = targetColorScheme.onSecondary),
secondaryContainer = animateColor(targetColor = targetColorScheme.secondaryContainer),
onSecondaryContainer = animateColor(targetColor = targetColorScheme.onSecondaryContainer),
tertiary = animateColor(targetColor = targetColorScheme.tertiary),
onTertiary = animateColor(targetColor = targetColorScheme.onTertiary),
tertiaryContainer = animateColor(targetColor = targetColorScheme.tertiaryContainer),
onTertiaryContainer = animateColor(targetColor = targetColorScheme.onTertiaryContainer),
error = animateColor(targetColor = targetColorScheme.error),
errorContainer = animateColor(targetColor = targetColorScheme.errorContainer),
onError = animateColor(targetColor = targetColorScheme.onError),
onErrorContainer = animateColor(targetColor = targetColorScheme.onErrorContainer),
background = animateColor(targetColor = targetColorScheme.background),
onBackground = animateColor(targetColor = targetColorScheme.onBackground),
surface = animateColor(targetColor = targetColorScheme.surface),
onSurface = animateColor(targetColor = targetColorScheme.onSurface),
surfaceVariant = animateColor(targetColor = targetColorScheme.surfaceVariant),
onSurfaceVariant = animateColor(targetColor = targetColorScheme.onSurfaceVariant),
outline = animateColor(targetColor = targetColorScheme.outline),
inverseOnSurface = animateColor(targetColor = targetColorScheme.inverseOnSurface),
inverseSurface = animateColor(targetColor = targetColorScheme.inverseSurface),
inversePrimary = animateColor(targetColor = targetColorScheme.inversePrimary),
surfaceTint = animateColor(targetColor = targetColorScheme.surfaceTint),
outlineVariant = animateColor(targetColor = targetColorScheme.outlineVariant),
scrim = animateColor(targetColor = targetColorScheme.scrim),
surfaceBright = animateColor(targetColor = targetColorScheme.surfaceBright),
surfaceDim = animateColor(targetColor = targetColorScheme.surfaceDim),
surfaceContainer = animateColor(targetColor = targetColorScheme.surfaceContainer),
surfaceContainerHigh = animateColor(targetColor = targetColorScheme.surfaceContainerHigh),
surfaceContainerHighest = animateColor(targetColor = targetColorScheme.surfaceContainerHighest),
surfaceContainerLow = animateColor(targetColor = targetColorScheme.surfaceContainerLow),
surfaceContainerLowest = animateColor(targetColor = targetColorScheme.surfaceContainerLowest),
)
}
@Composable
fun animatedColorScheme(
theme: Theme,
isDark: Boolean,
isPureDark: Boolean,
themeContrast: ThemeContrast
): ColorScheme {
val colorScheme = colorScheme(
theme = theme,
darkTheme = isDark,
isPureDark = isPureDark,
themeContrast = themeContrast
)
return animateColorScheme(targetColorScheme = colorScheme)
} }

View file

@ -0,0 +1,25 @@
/*
* Book's Story free and open-source Material You eBook reader.
* Copyright (C) 2024-2025 Acclorite
* SPDX-License-Identifier: GPL-3.0-only
*/
package ua.acclorite.book_story.ui.theme
import androidx.compose.material3.ColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
val ColorScheme.readerBarsColor: Color
get() = surfaceContainer.copy(0.9f)
@Composable
fun ColorScheme.dynamicListItemColor(
index: Int
): Color {
return when (index % 3) {
0 -> surfaceContainerLow
1 -> surfaceContainerHigh
else -> surfaceContainer
}
}

View file

@ -11,7 +11,7 @@ import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import ua.acclorite.book_story.ui.theme.ThemeContrast import ua.acclorite.book_story.domain.ui.ThemeContrast
private val primaryLight = Color(0xFF116682) private val primaryLight = Color(0xFF116682)

View file

@ -11,7 +11,7 @@ import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import ua.acclorite.book_story.ui.theme.ThemeContrast import ua.acclorite.book_story.domain.ui.ThemeContrast
private val primaryLight = Color(0xFF485D92) private val primaryLight = Color(0xFF485D92)

View file

@ -11,7 +11,7 @@ import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import ua.acclorite.book_story.ui.theme.ThemeContrast import ua.acclorite.book_story.domain.ui.ThemeContrast
private val primaryLight = Color(0xFF306A42) private val primaryLight = Color(0xFF306A42)
private val onPrimaryLight = Color(0xFFFFFFFF) private val onPrimaryLight = Color(0xFFFFFFFF)

View file

@ -11,7 +11,7 @@ import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import ua.acclorite.book_story.ui.theme.ThemeContrast import ua.acclorite.book_story.domain.ui.ThemeContrast
private val primaryLight = Color(0xFF824C76) private val primaryLight = Color(0xFF824C76)
private val onPrimaryLight = Color(0xFFFFFFFF) private val onPrimaryLight = Color(0xFFFFFFFF)

View file

@ -11,7 +11,7 @@ import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import ua.acclorite.book_story.ui.theme.ThemeContrast import ua.acclorite.book_story.domain.ui.ThemeContrast
private val primaryLight = Color(0xFF006A65) private val primaryLight = Color(0xFF006A65)
private val onPrimaryLight = Color(0xFFFFFFFF) private val onPrimaryLight = Color(0xFFFFFFFF)

View file

@ -11,7 +11,7 @@ import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import ua.acclorite.book_story.ui.theme.ThemeContrast import ua.acclorite.book_story.domain.ui.ThemeContrast
private val primaryLight = Color(0xFF8C4A60) private val primaryLight = Color(0xFF8C4A60)
private val onPrimaryLight = Color(0xFFFFFFFF) private val onPrimaryLight = Color(0xFFFFFFFF)

View file

@ -11,7 +11,7 @@ import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import ua.acclorite.book_story.ui.theme.ThemeContrast import ua.acclorite.book_story.domain.ui.ThemeContrast
private val primaryLight = Color(0xFF725188) private val primaryLight = Color(0xFF725188)
private val onPrimaryLight = Color(0xFFFFFFFF) private val onPrimaryLight = Color(0xFFFFFFFF)

View file

@ -11,7 +11,7 @@ import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import ua.acclorite.book_story.ui.theme.ThemeContrast import ua.acclorite.book_story.domain.ui.ThemeContrast
private val primaryLight = Color(0xFF904A42) private val primaryLight = Color(0xFF904A42)
private val onPrimaryLight = Color(0xFFFFFFFF) private val onPrimaryLight = Color(0xFFFFFFFF)

View file

@ -11,7 +11,7 @@ import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import ua.acclorite.book_story.ui.theme.ThemeContrast import ua.acclorite.book_story.domain.ui.ThemeContrast
private val primaryLight = Color(0xFF845415) private val primaryLight = Color(0xFF845415)
private val onPrimaryLight = Color(0xFFFFFFFF) private val onPrimaryLight = Color(0xFFFFFFFF)