Changed SettingsScreen structure. (more scalable way)

This commit is contained in:
acclorite 2024-07-19 01:48:24 +03:00
parent 3aefb37935
commit 0665ff62e9
31 changed files with 1338 additions and 940 deletions

View file

@ -4,10 +4,8 @@ import androidx.activity.ComponentActivity
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
@ -23,21 +21,13 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.unit.dp
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.model.ButtonItem
import ua.acclorite.book_story.domain.util.Constants
import ua.acclorite.book_story.presentation.components.CategoryTitle
import ua.acclorite.book_story.presentation.components.CustomBottomSheet
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.reader.data.ReaderEvent
import ua.acclorite.book_story.presentation.screens.settings.components.ChipsWithTitle
import ua.acclorite.book_story.presentation.screens.settings.components.ColorPickerWithTitle
import ua.acclorite.book_story.presentation.screens.settings.components.SliderWithTitle
import ua.acclorite.book_story.presentation.screens.settings.components.SwitchWithTitle
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.subcategories.ColorsSubcategory
import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.ReaderSettingsCategory
/**
* Settings bottom sheet. Has General and Colors categories.
@ -57,12 +47,6 @@ fun ReaderSettingsBottomSheet(
val currentPage by remember { derivedStateOf { pagerState.currentPage } }
val context = LocalContext.current
val fontFamily = remember(mainState.value.fontFamily) {
Constants.FONTS.find {
it.id == mainState.value.fontFamily
} ?: Constants.FONTS[0]
}
val scrimColor = if (currentPage == 1) Color.Transparent
else BottomSheetDefaults.ScrimColor
@ -109,213 +93,24 @@ fun ReaderSettingsBottomSheet(
HorizontalPager(state = pagerState) { page ->
LazyColumn {
if (page == 0) {
item {
Spacer(modifier = Modifier.height(22.dp))
}
item {
CategoryTitle(
title = stringResource(id = R.string.font_reader_settings),
color = MaterialTheme.colorScheme.onSurface
)
}
item {
Spacer(modifier = Modifier.height(8.dp))
}
item {
ChipsWithTitle(
title = stringResource(id = R.string.font_family_option),
chips = Constants.FONTS
.map {
ButtonItem(
it.id,
it.fontName.asString(),
MaterialTheme.typography.labelLarge.copy(
fontFamily = it.font
),
it.id == fontFamily.id
)
},
onClick = {
onMainEvent(MainEvent.OnChangeFontFamily(it.id))
}
)
}
item {
ChipsWithTitle(
title = stringResource(id = R.string.font_style_option),
chips = listOf(
ButtonItem(
"normal",
stringResource(id = R.string.font_style_normal),
MaterialTheme.typography.labelLarge.copy(
fontFamily = fontFamily.font,
fontStyle = FontStyle.Normal
),
!mainState.value.isItalic!!
),
ButtonItem(
"italic",
stringResource(id = R.string.font_style_italic),
MaterialTheme.typography.labelLarge.copy(
fontFamily = fontFamily.font,
fontStyle = FontStyle.Italic
),
mainState.value.isItalic!!
),
),
onClick = {
onMainEvent(
MainEvent.OnChangeFontStyle(
when (it.id) {
"italic" -> true
else -> false
}
)
)
}
)
}
item {
SliderWithTitle(
value = mainState.value.fontSize!! to "pt",
fromValue = 10,
toValue = 35,
title = stringResource(id = R.string.font_size_option),
onValueChange = {
onMainEvent(
MainEvent.OnChangeFontSize(it)
)
}
)
}
item {
Spacer(modifier = Modifier.height(22.dp))
}
item {
CategoryTitle(
title = stringResource(id = R.string.text_reader_settings),
color = MaterialTheme.colorScheme.onSurface
)
}
item {
Spacer(modifier = Modifier.height(8.dp))
}
item {
SliderWithTitle(
value = mainState.value.sidePadding!! to "pt",
fromValue = 1,
toValue = 20,
title = stringResource(id = R.string.side_padding_option),
onValueChange = {
onMainEvent(
MainEvent.OnChangeSidePadding(it)
)
}
)
}
item {
SliderWithTitle(
value = mainState.value.lineHeight!! to "pt",
fromValue = 1,
toValue = 16,
title = stringResource(id = R.string.line_height_option),
onValueChange = {
onMainEvent(
MainEvent.OnChangeLineHeight(it)
)
}
)
}
item {
SliderWithTitle(
value = mainState.value.paragraphHeight!! to "pt",
fromValue = 0,
toValue = 24,
title = stringResource(id = R.string.paragraph_height_option),
onValueChange = {
onMainEvent(
MainEvent.OnChangeParagraphHeight(it)
)
}
)
}
item {
SwitchWithTitle(
selected = mainState.value.paragraphIndentation!!,
title = stringResource(id = R.string.paragraph_indentation_option)
) {
onMainEvent(
MainEvent.OnChangeParagraphIndentation(!mainState.value.paragraphIndentation!!)
)
}
}
item {
Spacer(modifier = Modifier.height(22.dp))
}
item {
CategoryTitle(
title = stringResource(id = R.string.translator_reader_settings),
color = MaterialTheme.colorScheme.onSurface
)
}
item {
Spacer(modifier = Modifier.height(8.dp))
}
item {
SwitchWithTitle(
selected = mainState.value.doubleClickTranslation!!,
title = stringResource(id = R.string.translator_double_click_to_translate_option),
description = stringResource(id = R.string.translator_double_click_to_translate_option_desc),
onClick = {
onMainEvent(
MainEvent.OnChangeDoubleClickTranslation(
!mainState.value.doubleClickTranslation!!
)
)
}
ReaderSettingsCategory(
state = mainState,
onMainEvent = onMainEvent,
titleColor = { MaterialTheme.colorScheme.onSurface },
topPadding = 16.dp,
bottomPadding = 8.dp + it
)
}
}
LazyColumn {
if (page == 1) {
item {
Spacer(modifier = Modifier.height(14.dp))
}
item {
ColorPickerWithTitle(
value = Color(mainState.value.backgroundColor!!.toULong()),
title = stringResource(id = R.string.background_color_option),
onValueChange = {
onMainEvent(
MainEvent.OnChangeBackgroundColor(
it.value.toLong()
)
)
}
)
}
item {
ColorPickerWithTitle(
value = Color(mainState.value.fontColor!!.toULong()),
title = stringResource(id = R.string.font_color_option),
onValueChange = {
onMainEvent(
MainEvent.OnChangeFontColor(
it.value.toLong()
)
)
}
)
}
}
item {
Spacer(
modifier = Modifier.height(
8.dp + it
)
ColorsSubcategory(
state = mainState,
onMainEvent = onMainEvent,
showTitle = false,
topPadding = 16.dp,
bottomPadding = 8.dp + it
)
}
}

View file

@ -23,6 +23,7 @@ import ua.acclorite.book_story.presentation.components.CategoryTitle
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun ChipsWithTitle(
modifier: Modifier = Modifier,
title: String,
chips: List<ButtonItem>,
horizontalPadding: Dp = 18.dp,
@ -30,7 +31,7 @@ fun ChipsWithTitle(
onClick: (ButtonItem) -> Unit
) {
Column(
Modifier
modifier
.fillMaxWidth()
.padding(horizontal = horizontalPadding, vertical = verticalPadding)
) {

View file

@ -30,6 +30,7 @@ import androidx.compose.ui.unit.dp
*/
@Composable
fun SwitchWithTitle(
modifier: Modifier = Modifier,
selected: Boolean,
title: String,
description: String? = null,
@ -38,7 +39,7 @@ fun SwitchWithTitle(
onClick: () -> Unit
) {
Row(
modifier = Modifier
modifier = modifier
.clickable { onClick() }
.padding(horizontal = horizontalPadding, vertical = verticalPadding),
verticalAlignment = Alignment.CenterVertically

View file

@ -1,9 +1,7 @@
package ua.acclorite.book_story.presentation.screens.settings.nested.appearance
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.windowInsetsPadding
@ -15,39 +13,21 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.model.ButtonItem
import ua.acclorite.book_story.domain.util.OnNavigate
import ua.acclorite.book_story.presentation.components.CategoryTitle
import ua.acclorite.book_story.presentation.components.GoBackButton
import ua.acclorite.book_story.presentation.components.collapsibleUntilExitScrollBehaviorWithLazyListState
import ua.acclorite.book_story.presentation.data.LocalNavigator
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.data.MainViewModel
import ua.acclorite.book_story.presentation.screens.settings.components.ColorPickerWithTitle
import ua.acclorite.book_story.presentation.screens.settings.components.SegmentedButtonWithTitle
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.theme_switcher.AppearanceSettingsThemeSwitcher
import ua.acclorite.book_story.presentation.ui.BookStoryTheme
import ua.acclorite.book_story.presentation.ui.DarkTheme
import ua.acclorite.book_story.presentation.ui.PureDark
import ua.acclorite.book_story.presentation.ui.SlidingTransition
import ua.acclorite.book_story.presentation.ui.Theme
import ua.acclorite.book_story.presentation.ui.ThemeContrast
import ua.acclorite.book_story.presentation.ui.isDark
import ua.acclorite.book_story.presentation.ui.isPureDark
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.AppearanceSettingsCategory
@Composable
fun AppearanceSettingsRoot() {
@ -71,13 +51,6 @@ private fun AppearanceSettings(
onMainEvent: (MainEvent) -> Unit
) {
val scrollState = TopAppBarDefaults.collapsibleUntilExitScrollBehaviorWithLazyListState()
val themeContrastTheme = remember { mutableStateOf(state.value.theme!!) }
LaunchedEffect(state.value.theme) {
if (themeContrastTheme.value != state.value.theme && state.value.theme != Theme.DYNAMIC) {
themeContrastTheme.value = state.value.theme!!
}
}
Scaffold(
Modifier
@ -107,189 +80,10 @@ private fun AppearanceSettings(
.padding(top = paddingValues.calculateTopPadding()),
state = scrollState.second
) {
item {
Spacer(
modifier = Modifier
.animateItem()
.height(16.dp)
)
}
item {
CategoryTitle(
modifier = Modifier.animateItem(),
title = stringResource(id = R.string.theme_appearance_settings),
color = MaterialTheme.colorScheme.primary
)
}
item {
Spacer(
modifier = Modifier
.animateItem()
.height(8.dp)
)
}
item {
SegmentedButtonWithTitle(
modifier = Modifier.animateItem(),
title = stringResource(id = R.string.dark_theme_option),
locked = true,
buttons = DarkTheme.entries.map {
ButtonItem(
it.toString(),
when (it) {
DarkTheme.OFF -> stringResource(id = R.string.dark_theme_off)
DarkTheme.ON -> stringResource(id = R.string.dark_theme_on)
DarkTheme.FOLLOW_SYSTEM -> stringResource(id = R.string.dark_theme_follow_system)
},
MaterialTheme.typography.labelLarge,
it == state.value.darkTheme
)
}
) {
onMainEvent(
MainEvent.OnChangeDarkTheme(
it.id
)
)
}
}
item {
AppearanceSettingsThemeSwitcher(
modifier = Modifier.animateItem(),
AppearanceSettingsCategory(
state = state,
onMainEvent = onMainEvent
)
}
item {
BookStoryTheme(
theme = themeContrastTheme.value,
isDark = state.value.darkTheme!!.isDark(),
isPureDark = state.value.pureDark!!.isPureDark(context = LocalContext.current),
themeContrast = state.value.themeContrast!!
) {
SlidingTransition(
modifier = Modifier.animateItem(
fadeInSpec = null,
fadeOutSpec = null
),
visible = state.value.theme != Theme.DYNAMIC,
) {
SegmentedButtonWithTitle(
title = stringResource(id = R.string.theme_contrast_option),
locked = state.value.theme != Theme.DYNAMIC,
buttons = ThemeContrast.entries.map {
ButtonItem(
it.toString(),
when (it) {
ThemeContrast.STANDARD -> stringResource(id = R.string.theme_contrast_standard)
ThemeContrast.MEDIUM -> stringResource(id = R.string.theme_contrast_medium)
ThemeContrast.HIGH -> stringResource(id = R.string.theme_contrast_high)
},
MaterialTheme.typography.labelLarge,
it == state.value.themeContrast
)
}
) {
onMainEvent(
MainEvent.OnChangeThemeContrast(
it.id
)
)
}
}
}
}
item {
SlidingTransition(
modifier = Modifier.animateItem(
fadeInSpec = null,
fadeOutSpec = null
),
visible = state.value.darkTheme!!.isDark(),
) {
SegmentedButtonWithTitle(
title = stringResource(id = R.string.pure_dark_option),
locked = true,
buttons = PureDark.entries.map {
ButtonItem(
it.toString(),
when (it) {
PureDark.OFF -> stringResource(id = R.string.pure_dark_off)
PureDark.ON -> stringResource(id = R.string.pure_dark_on)
PureDark.SAVER -> stringResource(id = R.string.pure_dark_power_saver)
},
MaterialTheme.typography.labelLarge,
it == state.value.pureDark
)
}
) {
onMainEvent(
MainEvent.OnChangePureDark(
it.id
)
)
}
}
}
item {
Spacer(
modifier = Modifier
.animateItem()
.height(22.dp)
)
CategoryTitle(
title = stringResource(id = R.string.colors_appearance_settings),
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.animateItem()
)
Spacer(
modifier = Modifier
.animateItem()
.height(8.dp)
)
}
item {
ColorPickerWithTitle(
modifier = Modifier.animateItem(),
value = Color(state.value.backgroundColor!!.toULong()),
title = stringResource(id = R.string.background_color_option),
onValueChange = {
onMainEvent(
MainEvent.OnChangeBackgroundColor(
it.value.toLong()
)
)
}
)
}
item {
ColorPickerWithTitle(
modifier = Modifier.animateItem(),
value = Color(state.value.fontColor!!.toULong()),
title = stringResource(id = R.string.font_color_option),
onValueChange = {
onMainEvent(
MainEvent.OnChangeFontColor(
it.value.toLong()
)
)
}
)
}
item {
Spacer(
modifier = Modifier
.animateItem()
.height(48.dp)
)
}
}
}
}

View file

@ -0,0 +1,48 @@
@file:Suppress("FunctionName")
package ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.subcategories.ColorsSubcategory
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.subcategories.ThemePreferencesSubcategory
/**
* Appearance Settings Category.
* Contains all Appearance settings such as Theme.
*
* @param state [MainState] instance.
* @param onMainEvent [MainEvent] callback.
* @param titleColor Title's color.
* @param topPadding Top padding to be applied.
* @param bottomPadding Bottom padding to be applied.
*/
fun LazyListScope.AppearanceSettingsCategory(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit,
titleColor: @Composable () -> Color = { MaterialTheme.colorScheme.primary },
topPadding: Dp = 16.dp,
bottomPadding: Dp = 48.dp
) {
ThemePreferencesSubcategory(
state = state,
onMainEvent = onMainEvent,
titleColor = titleColor,
topPadding = topPadding,
bottomPadding = 0.dp
)
ColorsSubcategory(
state,
onMainEvent = onMainEvent,
titleColor = titleColor,
topPadding = 22.dp,
bottomPadding = bottomPadding
)
}

View file

@ -0,0 +1,48 @@
package ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.settings
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.model.ButtonItem
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.components.SegmentedButtonWithTitle
import ua.acclorite.book_story.presentation.ui.DarkTheme
/**
* Dark Theme setting.
* If true, dark theme applied to the app's theme.
*/
@Composable
fun LazyItemScope.DarkThemeSetting(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit
) {
SegmentedButtonWithTitle(
title = stringResource(id = R.string.dark_theme_option),
modifier = Modifier.animateItem(),
locked = true,
buttons = DarkTheme.entries.map {
ButtonItem(
it.toString(),
when (it) {
DarkTheme.OFF -> stringResource(id = R.string.dark_theme_off)
DarkTheme.ON -> stringResource(id = R.string.dark_theme_on)
DarkTheme.FOLLOW_SYSTEM -> stringResource(id = R.string.dark_theme_follow_system)
},
MaterialTheme.typography.labelLarge,
it == state.value.darkTheme
)
}
) {
onMainEvent(
MainEvent.OnChangeDarkTheme(
it.id
)
)
}
}

View file

@ -0,0 +1,57 @@
package ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.settings
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.model.ButtonItem
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.components.SegmentedButtonWithTitle
import ua.acclorite.book_story.presentation.ui.PureDark
import ua.acclorite.book_story.presentation.ui.SlidingTransition
import ua.acclorite.book_story.presentation.ui.isDark
/**
* Pure Dark setting.
* If true, enables Pure Dark (OLED) theme.
*/
@Composable
fun LazyItemScope.PureDarkSetting(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit
) {
SlidingTransition(
modifier = Modifier.animateItem(
fadeInSpec = null,
fadeOutSpec = null
),
visible = state.value.darkTheme!!.isDark(),
) {
SegmentedButtonWithTitle(
title = stringResource(id = R.string.pure_dark_option),
locked = true,
buttons = PureDark.entries.map {
ButtonItem(
it.toString(),
when (it) {
PureDark.OFF -> stringResource(id = R.string.pure_dark_off)
PureDark.ON -> stringResource(id = R.string.pure_dark_on)
PureDark.SAVER -> stringResource(id = R.string.pure_dark_power_saver)
},
MaterialTheme.typography.labelLarge,
it == state.value.pureDark
)
}
) {
onMainEvent(
MainEvent.OnChangePureDark(
it.id
)
)
}
}
}

View file

@ -0,0 +1,79 @@
package ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.settings
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.model.ButtonItem
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.components.SegmentedButtonWithTitle
import ua.acclorite.book_story.presentation.ui.BookStoryTheme
import ua.acclorite.book_story.presentation.ui.SlidingTransition
import ua.acclorite.book_story.presentation.ui.Theme
import ua.acclorite.book_story.presentation.ui.ThemeContrast
import ua.acclorite.book_story.presentation.ui.isDark
import ua.acclorite.book_story.presentation.ui.isPureDark
/**
* Theme Contrast setting.
* Lets user change theme contrast levels.
*/
@Composable
fun LazyItemScope.ThemeContrastSetting(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit
) {
val themeContrastTheme = remember { mutableStateOf(state.value.theme!!) }
LaunchedEffect(state.value.theme) {
if (themeContrastTheme.value != state.value.theme && state.value.theme != Theme.DYNAMIC) {
themeContrastTheme.value = state.value.theme!!
}
}
BookStoryTheme(
theme = themeContrastTheme.value,
isDark = state.value.darkTheme!!.isDark(),
isPureDark = state.value.pureDark!!.isPureDark(context = LocalContext.current),
themeContrast = state.value.themeContrast!!
) {
SlidingTransition(
modifier = Modifier.animateItem(
fadeInSpec = null,
fadeOutSpec = null
),
visible = state.value.theme != Theme.DYNAMIC,
) {
SegmentedButtonWithTitle(
title = stringResource(id = R.string.theme_contrast_option),
locked = state.value.theme != Theme.DYNAMIC,
buttons = ThemeContrast.entries.map {
ButtonItem(
it.toString(),
when (it) {
ThemeContrast.STANDARD -> stringResource(id = R.string.theme_contrast_standard)
ThemeContrast.MEDIUM -> stringResource(id = R.string.theme_contrast_medium)
ThemeContrast.HIGH -> stringResource(id = R.string.theme_contrast_high)
},
MaterialTheme.typography.labelLarge,
it == state.value.themeContrast
)
}
) {
onMainEvent(
MainEvent.OnChangeThemeContrast(
it.id
)
)
}
}
}
}

View file

@ -1,5 +1,6 @@
package ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.theme_switcher
package ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.settings
import android.os.Build
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
@ -10,6 +11,7 @@ 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.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
@ -17,6 +19,8 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
@ -25,21 +29,80 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.util.Constants
import ua.acclorite.book_story.domain.util.UIText
import ua.acclorite.book_story.presentation.components.CategoryTitle
import ua.acclorite.book_story.presentation.components.CustomAnimatedVisibility
import ua.acclorite.book_story.presentation.components.customItems
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.ui.Theme
import ua.acclorite.book_story.presentation.ui.ThemeContrast
import ua.acclorite.book_story.presentation.ui.animatedColorScheme
import ua.acclorite.book_story.presentation.ui.isDark
import ua.acclorite.book_story.presentation.ui.isPureDark
/**
* Theme switcher item. Used to change app theme.
* Theme setting.
* Lets user change app's theme from available in [Constants.THEMES].
*/
@Composable
fun LazyItemScope.ThemeSetting(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit,
verticalPadding: Dp = 8.dp,
horizontalPadding: Dp = 18.dp
) {
val themes = remember {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) Constants.THEMES
else Constants.THEMES.dropWhile { it.first == Theme.DYNAMIC }
}
Column(
Modifier
.animateItem()
.fillMaxWidth()
.padding(vertical = verticalPadding)
) {
CategoryTitle(
title = stringResource(id = R.string.app_theme_option),
padding = horizontalPadding
)
Spacer(modifier = Modifier.height(8.dp))
LazyRow(
Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(8.dp),
contentPadding = PaddingValues(horizontal = horizontalPadding)
) {
customItems(themes, key = { it.first.name }) { themeEntry ->
ThemeSettingItem(
theme = themeEntry,
darkTheme = state.value.darkTheme!!.isDark(),
themeContrast = state.value.themeContrast!!,
isPureDark = state.value.pureDark!!.isPureDark(context = LocalContext.current),
selected = state.value.theme == themeEntry.first
) {
onMainEvent(MainEvent.OnChangeTheme(themeEntry.first.toString()))
}
}
}
}
}
/**
* Theme Setting item.
* Used to switch between different themes.
*
* @param theme Target [Theme].
* @param darkTheme Whether should be shown in Dark Theme.
@ -49,7 +112,7 @@ import ua.acclorite.book_story.presentation.ui.animatedColorScheme
* @param onClick OnClick callback.
*/
@Composable
fun AppearanceSettingsThemeSwitcherItem(
private fun ThemeSettingItem(
theme: Pair<Theme, UIText>,
darkTheme: Boolean,
isPureDark: Boolean,

View file

@ -0,0 +1,96 @@
@file:Suppress("FunctionName")
package ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.subcategories
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.coerceAtLeast
import androidx.compose.ui.unit.dp
import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.components.CategoryTitle
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.components.ColorPickerWithTitle
/**
* Colors subcategory.
* Contains all settings from Colors.
*/
fun LazyListScope.ColorsSubcategory(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit,
titleColor: @Composable () -> Color = { MaterialTheme.colorScheme.primary },
title: @Composable () -> String = { stringResource(id = R.string.colors_appearance_settings) },
showTitle: Boolean = true,
topPadding: Dp,
bottomPadding: Dp
) {
item {
if (showTitle) {
CategoryTitle(
title = title.invoke(),
color = titleColor.invoke(),
modifier = Modifier
.animateItem()
.padding(
top = topPadding,
bottom = 8.dp
)
)
} else {
Spacer(
modifier = Modifier
.animateItem()
.height((topPadding - 8.dp).coerceAtLeast(0.dp))
)
}
}
// todo: This will be replaced with ColorPresets
item {
ColorPickerWithTitle(
modifier = Modifier.animateItem(),
value = Color(state.value.backgroundColor!!.toULong()),
title = stringResource(id = R.string.background_color_option),
onValueChange = {
onMainEvent(
MainEvent.OnChangeBackgroundColor(
it.value.toLong()
)
)
}
)
}
item {
ColorPickerWithTitle(
modifier = Modifier.animateItem(),
value = Color(state.value.fontColor!!.toULong()),
title = stringResource(id = R.string.font_color_option),
onValueChange = {
onMainEvent(
MainEvent.OnChangeFontColor(
it.value.toLong()
)
)
}
)
}
// ---------
item {
Spacer(
modifier = Modifier
.animateItem()
.height(bottomPadding)
)
}
}

View file

@ -0,0 +1,96 @@
@file:Suppress("FunctionName")
package ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.subcategories
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.coerceAtLeast
import androidx.compose.ui.unit.dp
import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.components.CategoryTitle
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.settings.DarkThemeSetting
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.settings.PureDarkSetting
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.settings.ThemeContrastSetting
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.settings.ThemeSetting
/**
* Theme Preferences subcategory.
* Contains all settings from Theme Preferences.
*/
fun LazyListScope.ThemePreferencesSubcategory(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit,
titleColor: @Composable () -> Color = { MaterialTheme.colorScheme.primary },
title: @Composable () -> String = { stringResource(id = R.string.theme_appearance_settings) },
showTitle: Boolean = true,
topPadding: Dp,
bottomPadding: Dp
) {
item {
if (showTitle) {
CategoryTitle(
title = title.invoke(),
color = titleColor.invoke(),
modifier = Modifier
.animateItem()
.padding(
top = topPadding,
bottom = 8.dp
)
)
} else {
Spacer(
modifier = Modifier
.animateItem()
.height((topPadding - 8.dp).coerceAtLeast(0.dp))
)
}
}
item {
DarkThemeSetting(
state = state,
onMainEvent = onMainEvent
)
}
item {
ThemeSetting(
state = state,
onMainEvent = onMainEvent
)
}
item {
ThemeContrastSetting(
state = state,
onMainEvent = onMainEvent
)
}
item {
PureDarkSetting(
state = state,
onMainEvent = onMainEvent
)
}
item {
Spacer(
modifier = Modifier
.animateItem()
.height(bottomPadding)
)
}
}

View file

@ -1,80 +0,0 @@
package ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.theme_switcher
import android.os.Build
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.util.Constants
import ua.acclorite.book_story.presentation.components.CategoryTitle
import ua.acclorite.book_story.presentation.components.customItemsIndexed
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.ui.Theme
import ua.acclorite.book_story.presentation.ui.isDark
import ua.acclorite.book_story.presentation.ui.isPureDark
/**
* Theme switcher.
*/
@Composable
fun AppearanceSettingsThemeSwitcher(
modifier: Modifier = Modifier,
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit,
verticalPadding: Dp = 8.dp
) {
val themes = remember {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) Constants.THEMES
else Constants.THEMES.dropWhile { it.first == Theme.DYNAMIC }
}
Column(
modifier
.fillMaxWidth()
.padding(vertical = verticalPadding)
) {
CategoryTitle(
title = stringResource(id = R.string.app_theme_option)
)
Spacer(modifier = Modifier.height(10.dp))
LazyRow(
Modifier
.fillMaxWidth(),
) {
customItemsIndexed(themes, key = { it.first.name }) { index, themeEntry ->
if (index == 0) {
Spacer(modifier = Modifier.width(18.dp))
} else {
Spacer(modifier = Modifier.width(8.dp))
}
AppearanceSettingsThemeSwitcherItem(
theme = themeEntry,
darkTheme = state.value.darkTheme!!.isDark(),
themeContrast = state.value.themeContrast!!,
isPureDark = state.value.pureDark!!.isPureDark(context = LocalContext.current),
selected = state.value.theme == themeEntry.first
) {
onMainEvent(MainEvent.OnChangeTheme(themeEntry.first.toString()))
}
if (index == themes.lastIndex) {
Spacer(modifier = Modifier.width(18.dp))
}
}
}
}
}

View file

@ -1,12 +1,7 @@
package ua.acclorite.book_story.presentation.screens.settings.nested.general
import android.Manifest
import android.annotation.SuppressLint
import androidx.activity.ComponentActivity
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.windowInsetsPadding
@ -22,15 +17,9 @@ import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.rememberPermissionState
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.model.ButtonItem
import ua.acclorite.book_story.domain.util.Constants
import ua.acclorite.book_story.domain.util.OnNavigate
import ua.acclorite.book_story.presentation.components.GoBackButton
import ua.acclorite.book_story.presentation.components.collapsibleUntilExitScrollBehaviorWithLazyListState
@ -38,10 +27,9 @@ import ua.acclorite.book_story.presentation.data.LocalNavigator
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.data.MainViewModel
import ua.acclorite.book_story.presentation.screens.settings.components.ChipsWithTitle
import ua.acclorite.book_story.presentation.screens.settings.components.SwitchWithTitle
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsEvent
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsViewModel
import ua.acclorite.book_story.presentation.screens.settings.nested.general.components.GeneralSettingsCategory
@Composable
fun GeneralSettingsRoot() {
@ -59,8 +47,8 @@ fun GeneralSettingsRoot() {
)
}
@SuppressLint("InlinedApi")
@OptIn(ExperimentalMaterial3Api::class, ExperimentalPermissionsApi::class)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun GeneralSettings(
state: State<MainState>,
@ -69,11 +57,6 @@ private fun GeneralSettings(
onMainEvent: (MainEvent) -> Unit
) {
val scrollState = TopAppBarDefaults.collapsibleUntilExitScrollBehaviorWithLazyListState()
val activity = LocalContext.current as ComponentActivity
val notificationsPermissionState = rememberPermissionState(
permission = Manifest.permission.POST_NOTIFICATIONS
)
Scaffold(
Modifier
@ -103,53 +86,11 @@ private fun GeneralSettings(
.padding(top = paddingValues.calculateTopPadding()),
state = scrollState.second
) {
item {
Spacer(modifier = Modifier.height(8.dp))
}
item {
ChipsWithTitle(
title = stringResource(id = R.string.language_option),
chips = Constants.LANGUAGES.sortedBy { it.second }.map {
ButtonItem(
it.first,
it.second,
MaterialTheme.typography.labelLarge,
it.first == state.value.language
GeneralSettingsCategory(
state = state,
onMainEvent = onMainEvent,
onSettingsEvent = onSettingsEvent
)
}.sortedBy { it.title }
) {
onMainEvent(
MainEvent.OnChangeLanguage(
it.id
)
)
}
}
item {
SwitchWithTitle(
selected = state.value.checkForUpdates!!,
title = stringResource(id = R.string.check_for_updates_option),
description = stringResource(id = R.string.check_for_updates_option_desc)
) {
onSettingsEvent(
SettingsEvent.OnGeneralChangeCheckForUpdates(
enable = !state.value.checkForUpdates!!,
activity = activity,
notificationsPermissionState = notificationsPermissionState,
onChangeCheckForUpdates = {
onMainEvent(
MainEvent.OnChangeCheckForUpdates(
it
)
)
}
)
)
}
}
item { Spacer(modifier = Modifier.height(48.dp)) }
}
}
}

View file

@ -0,0 +1,66 @@
@file:Suppress("FunctionName")
package ua.acclorite.book_story.presentation.screens.settings.nested.general.components
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.coerceAtLeast
import androidx.compose.ui.unit.dp
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsEvent
import ua.acclorite.book_story.presentation.screens.settings.nested.general.components.settings.AppLanguageSetting
import ua.acclorite.book_story.presentation.screens.settings.nested.general.components.settings.CheckForUpdatesSetting
/**
* General Settings Category.
* Contains all General settings such as App Language.
*
* @param state [MainState] instance.
* @param onMainEvent [MainEvent] callback.
* @param onSettingsEvent [SettingsEvent] callback.
* @param topPadding Top padding to be applied.
* @param bottomPadding Bottom padding to be applied.
*/
fun LazyListScope.GeneralSettingsCategory(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit,
onSettingsEvent: (SettingsEvent) -> Unit,
topPadding: Dp = 16.dp,
bottomPadding: Dp = 48.dp
) {
item {
Spacer(
modifier = Modifier
.animateItem()
.height((topPadding - 8.dp).coerceAtLeast(0.dp))
)
}
item {
AppLanguageSetting(
state = state,
onMainEvent = onMainEvent
)
}
item {
CheckForUpdatesSetting(
state = state,
onMainEvent = onMainEvent,
onSettingsEvent = onSettingsEvent
)
}
item {
Spacer(
modifier = Modifier
.animateItem()
.height(bottomPadding)
)
}
}

View file

@ -0,0 +1,43 @@
package ua.acclorite.book_story.presentation.screens.settings.nested.general.components.settings
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.model.ButtonItem
import ua.acclorite.book_story.domain.util.Constants
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.components.ChipsWithTitle
/**
* App Language setting.
* Changes app's language.
*/
@Composable
fun LazyItemScope.AppLanguageSetting(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit
) {
ChipsWithTitle(
title = stringResource(id = R.string.language_option),
modifier = Modifier.animateItem(),
chips = Constants.LANGUAGES.sortedBy { it.second }.map {
ButtonItem(
it.first,
it.second,
MaterialTheme.typography.labelLarge,
it.first == state.value.language
)
}.sortedBy { it.title }
) {
onMainEvent(
MainEvent.OnChangeLanguage(
it.id
)
)
}
}

View file

@ -0,0 +1,58 @@
package ua.acclorite.book_story.presentation.screens.settings.nested.general.components.settings
import android.Manifest
import android.annotation.SuppressLint
import androidx.activity.ComponentActivity
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.rememberPermissionState
import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.components.SwitchWithTitle
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsEvent
/**
* Check For Updates setting.
* If true, checks for the update on app start.
*/
@OptIn(ExperimentalPermissionsApi::class)
@SuppressLint("InlinedApi")
@Composable
fun LazyItemScope.CheckForUpdatesSetting(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit,
onSettingsEvent: (SettingsEvent) -> Unit
) {
val activity = LocalContext.current as ComponentActivity
val notificationsPermissionState = rememberPermissionState(
permission = Manifest.permission.POST_NOTIFICATIONS
)
SwitchWithTitle(
selected = state.value.checkForUpdates!!,
modifier = Modifier.animateItem(),
title = stringResource(id = R.string.check_for_updates_option),
description = stringResource(id = R.string.check_for_updates_option_desc)
) {
onSettingsEvent(
SettingsEvent.OnGeneralChangeCheckForUpdates(
enable = !state.value.checkForUpdates!!,
activity = activity,
notificationsPermissionState = notificationsPermissionState,
onChangeCheckForUpdates = {
onMainEvent(
MainEvent.OnChangeCheckForUpdates(
it
)
)
}
)
)
}
}

View file

@ -1,9 +1,7 @@
package ua.acclorite.book_story.presentation.screens.settings.nested.reader
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.windowInsetsPadding
@ -17,27 +15,19 @@ import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.model.ButtonItem
import ua.acclorite.book_story.domain.util.Constants
import ua.acclorite.book_story.domain.util.OnNavigate
import ua.acclorite.book_story.presentation.components.CategoryTitle
import ua.acclorite.book_story.presentation.components.GoBackButton
import ua.acclorite.book_story.presentation.components.collapsibleUntilExitScrollBehaviorWithLazyListState
import ua.acclorite.book_story.presentation.data.LocalNavigator
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.data.MainViewModel
import ua.acclorite.book_story.presentation.screens.settings.components.ChipsWithTitle
import ua.acclorite.book_story.presentation.screens.settings.components.SliderWithTitle
import ua.acclorite.book_story.presentation.screens.settings.components.SwitchWithTitle
import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.ReaderSettingsCategory
@Composable
fun ReaderSettingsRoot() {
@ -62,12 +52,6 @@ private fun ReaderSettings(
) {
val scrollState = TopAppBarDefaults.collapsibleUntilExitScrollBehaviorWithLazyListState()
val fontFamily = remember(state.value.fontFamily) {
Constants.FONTS.find {
it.id == state.value.fontFamily
} ?: Constants.FONTS[0]
}
Scaffold(
Modifier
.fillMaxSize()
@ -96,177 +80,10 @@ private fun ReaderSettings(
.padding(top = paddingValues.calculateTopPadding()),
state = scrollState.second
) {
item {
Spacer(modifier = Modifier.height(16.dp))
}
item {
CategoryTitle(
title = stringResource(id = R.string.font_reader_settings),
color = MaterialTheme.colorScheme.primary
ReaderSettingsCategory(
state = state,
onMainEvent = onMainEvent
)
}
item {
Spacer(modifier = Modifier.height(8.dp))
}
item {
ChipsWithTitle(
title = stringResource(id = R.string.font_family_option),
chips = Constants.FONTS
.map {
ButtonItem(
it.id,
it.fontName.asString(),
MaterialTheme.typography.labelLarge.copy(
fontFamily = it.font
),
it.id == fontFamily.id
)
},
onClick = {
onMainEvent(MainEvent.OnChangeFontFamily(it.id))
}
)
}
item {
ChipsWithTitle(
title = stringResource(id = R.string.font_style_option),
chips = listOf(
ButtonItem(
"normal",
stringResource(id = R.string.font_style_normal),
MaterialTheme.typography.labelLarge.copy(
fontFamily = fontFamily.font,
fontStyle = FontStyle.Normal
),
!state.value.isItalic!!
),
ButtonItem(
"italic",
stringResource(id = R.string.font_style_italic),
MaterialTheme.typography.labelLarge.copy(
fontFamily = fontFamily.font,
fontStyle = FontStyle.Italic
),
state.value.isItalic!!
),
),
onClick = {
onMainEvent(
MainEvent.OnChangeFontStyle(
when (it.id) {
"italic" -> true
else -> false
}
)
)
}
)
}
item {
SliderWithTitle(
value = state.value.fontSize!! to "pt",
fromValue = 10,
toValue = 35,
title = stringResource(id = R.string.font_size_option),
onValueChange = {
onMainEvent(
MainEvent.OnChangeFontSize(it)
)
}
)
}
item {
Spacer(modifier = Modifier.height(22.dp))
}
item {
CategoryTitle(
title = stringResource(id = R.string.text_reader_settings),
color = MaterialTheme.colorScheme.primary
)
}
item {
Spacer(modifier = Modifier.height(8.dp))
}
item {
SliderWithTitle(
value = state.value.sidePadding!! to "pt",
fromValue = 1,
toValue = 20,
title = stringResource(id = R.string.side_padding_option),
onValueChange = {
onMainEvent(
MainEvent.OnChangeSidePadding(it)
)
}
)
}
item {
SliderWithTitle(
value = state.value.lineHeight!! to "pt",
fromValue = 1,
toValue = 16,
title = stringResource(id = R.string.line_height_option),
onValueChange = {
onMainEvent(
MainEvent.OnChangeLineHeight(it)
)
}
)
}
item {
SliderWithTitle(
value = state.value.paragraphHeight!! to "pt",
fromValue = 0,
toValue = 24,
title = stringResource(id = R.string.paragraph_height_option),
onValueChange = {
onMainEvent(
MainEvent.OnChangeParagraphHeight(it)
)
}
)
}
item {
SwitchWithTitle(
selected = state.value.paragraphIndentation!!,
title = stringResource(id = R.string.paragraph_indentation_option)
) {
onMainEvent(
MainEvent.OnChangeParagraphIndentation(!state.value.paragraphIndentation!!)
)
}
}
item {
Spacer(modifier = Modifier.height(22.dp))
}
item {
CategoryTitle(
title = stringResource(id = R.string.translator_reader_settings),
color = MaterialTheme.colorScheme.primary
)
}
item {
Spacer(modifier = Modifier.height(8.dp))
}
item {
SwitchWithTitle(
selected = state.value.doubleClickTranslation!!,
title = stringResource(id = R.string.translator_double_click_to_translate_option),
description = stringResource(id = R.string.translator_double_click_to_translate_option_desc),
onClick = {
onMainEvent(
MainEvent.OnChangeDoubleClickTranslation(
!state.value.doubleClickTranslation!!
)
)
}
)
}
item { Spacer(modifier = Modifier.height(48.dp)) }
}
}
}

View file

@ -0,0 +1,57 @@
@file:Suppress("FunctionName")
package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import ua.acclorite.book_story.presentation.components.CategoryTitle
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.subcategories.FontSubcategory
import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.subcategories.TextSubcategory
import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.subcategories.TranslatorSubcategory
/**
* Reader Settings Category.
* Contains all Reader settings.
*
* @param state [MainState] instance.
* @param onMainEvent [MainEvent] callback.
* @param titleColor Color that [CategoryTitle] has.
* @param topPadding Top padding to be applied.
* @param bottomPadding Bottom padding to be applied.
*/
fun LazyListScope.ReaderSettingsCategory(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit,
titleColor: @Composable () -> Color = { MaterialTheme.colorScheme.primary },
topPadding: Dp = 16.dp,
bottomPadding: Dp = 48.dp
) {
FontSubcategory(
state = state,
onMainEvent = onMainEvent,
titleColor = titleColor,
topPadding = topPadding,
bottomPadding = 0.dp
)
TextSubcategory(
state,
onMainEvent = onMainEvent,
titleColor = titleColor,
topPadding = 22.dp,
bottomPadding = 0.dp
)
TranslatorSubcategory(
state,
onMainEvent = onMainEvent,
titleColor = titleColor,
topPadding = 22.dp,
bottomPadding = bottomPadding
)
}

View file

@ -0,0 +1,35 @@
package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.components.SwitchWithTitle
/**
* Double Click Translation setting.
* Changes Reader's double click translation.
*/
@Composable
fun LazyItemScope.DoubleClickTranslationSetting(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit
) {
SwitchWithTitle(
selected = state.value.doubleClickTranslation!!,
modifier = Modifier.animateItem(),
title = stringResource(id = R.string.translator_double_click_to_translate_option),
description = stringResource(id = R.string.translator_double_click_to_translate_option_desc),
onClick = {
onMainEvent(
MainEvent.OnChangeDoubleClickTranslation(
!state.value.doubleClickTranslation!!
)
)
}
)
}

View file

@ -0,0 +1,50 @@
package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.model.ButtonItem
import ua.acclorite.book_story.domain.util.Constants
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.components.ChipsWithTitle
/**
* Font Family setting.
* Changes Reader's font, uses fonts from [Constants.FONTS].
*/
@Composable
fun LazyItemScope.FontFamilySetting(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit
) {
val fontFamily = remember(state.value.fontFamily) {
Constants.FONTS.find {
it.id == state.value.fontFamily
} ?: Constants.FONTS[0]
}
ChipsWithTitle(
title = stringResource(id = R.string.font_family_option),
modifier = Modifier.animateItem(),
chips = Constants.FONTS
.map {
ButtonItem(
it.id,
it.fontName.asString(),
MaterialTheme.typography.labelLarge.copy(
fontFamily = it.font
),
it.id == fontFamily.id
)
},
onClick = {
onMainEvent(MainEvent.OnChangeFontFamily(it.id))
}
)
}

View file

@ -0,0 +1,34 @@
package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.components.SliderWithTitle
/**
* Font Size setting.
* Changes Reader's font size.
*/
@Composable
fun LazyItemScope.FontSizeSetting(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit
) {
SliderWithTitle(
value = state.value.fontSize!! to "pt",
modifier = Modifier.animateItem(),
fromValue = 10,
toValue = 35,
title = stringResource(id = R.string.font_size_option),
onValueChange = {
onMainEvent(
MainEvent.OnChangeFontSize(it)
)
}
)
}

View file

@ -0,0 +1,67 @@
package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.model.ButtonItem
import ua.acclorite.book_story.domain.util.Constants
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.components.ChipsWithTitle
/**
* Font Style setting.
* Changes Reader's font style (Normal/Italic).
*/
@Composable
fun LazyItemScope.FontStyleSetting(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit
) {
val fontFamily = remember(state.value.fontFamily) {
Constants.FONTS.find {
it.id == state.value.fontFamily
} ?: Constants.FONTS[0]
}
ChipsWithTitle(
title = stringResource(id = R.string.font_style_option),
modifier = Modifier.animateItem(),
chips = listOf(
ButtonItem(
"normal",
stringResource(id = R.string.font_style_normal),
MaterialTheme.typography.labelLarge.copy(
fontFamily = fontFamily.font,
fontStyle = FontStyle.Normal
),
!state.value.isItalic!!
),
ButtonItem(
"italic",
stringResource(id = R.string.font_style_italic),
MaterialTheme.typography.labelLarge.copy(
fontFamily = fontFamily.font,
fontStyle = FontStyle.Italic
),
state.value.isItalic!!
),
),
onClick = {
onMainEvent(
MainEvent.OnChangeFontStyle(
when (it.id) {
"italic" -> true
else -> false
}
)
)
}
)
}

View file

@ -0,0 +1,34 @@
package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.components.SliderWithTitle
/**
* Line Height setting.
* Changes Reader's line height.
*/
@Composable
fun LazyItemScope.LineHeightSetting(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit
) {
SliderWithTitle(
value = state.value.lineHeight!! to "pt",
modifier = Modifier.animateItem(),
fromValue = 1,
toValue = 16,
title = stringResource(id = R.string.line_height_option),
onValueChange = {
onMainEvent(
MainEvent.OnChangeLineHeight(it)
)
}
)
}

View file

@ -0,0 +1,34 @@
package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.components.SliderWithTitle
/**
* Paragraph Height setting.
* Changes Reader's paragraph height.
*/
@Composable
fun LazyItemScope.ParagraphHeightSetting(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit
) {
SliderWithTitle(
value = state.value.paragraphHeight!! to "pt",
modifier = Modifier.animateItem(),
fromValue = 0,
toValue = 24,
title = stringResource(id = R.string.paragraph_height_option),
onValueChange = {
onMainEvent(
MainEvent.OnChangeParagraphHeight(it)
)
}
)
}

View file

@ -0,0 +1,31 @@
package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.components.SwitchWithTitle
/**
* Paragraph Indentation setting.
* Changes Reader's paragraph indentation.
*/
@Composable
fun LazyItemScope.ParagraphIndentationSetting(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit
) {
SwitchWithTitle(
selected = state.value.paragraphIndentation!!,
modifier = Modifier.animateItem(),
title = stringResource(id = R.string.paragraph_indentation_option)
) {
onMainEvent(
MainEvent.OnChangeParagraphIndentation(!state.value.paragraphIndentation!!)
)
}
}

View file

@ -0,0 +1,34 @@
package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.components.SliderWithTitle
/**
* Side Padding setting.
* Changes Reader's side padding.
*/
@Composable
fun LazyItemScope.SidePaddingSetting(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit
) {
SliderWithTitle(
value = state.value.sidePadding!! to "pt",
modifier = Modifier.animateItem(),
fromValue = 1,
toValue = 20,
title = stringResource(id = R.string.side_padding_option),
onValueChange = {
onMainEvent(
MainEvent.OnChangeSidePadding(it)
)
}
)
}

View file

@ -0,0 +1,88 @@
@file:Suppress("FunctionName")
package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.subcategories
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.coerceAtLeast
import androidx.compose.ui.unit.dp
import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.components.CategoryTitle
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings.FontFamilySetting
import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings.FontSizeSetting
import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings.FontStyleSetting
/**
* Font subcategory.
* Contains all settings from Font.
*/
fun LazyListScope.FontSubcategory(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit,
titleColor: @Composable () -> Color = { MaterialTheme.colorScheme.primary },
title: @Composable () -> String = { stringResource(id = R.string.font_reader_settings) },
showTitle: Boolean = true,
topPadding: Dp,
bottomPadding: Dp
) {
item {
if (showTitle) {
CategoryTitle(
title = title.invoke(),
color = titleColor.invoke(),
modifier = Modifier
.animateItem()
.padding(
top = topPadding,
bottom = 8.dp
)
)
} else {
Spacer(
modifier = Modifier
.animateItem()
.height((topPadding - 8.dp).coerceAtLeast(0.dp))
)
}
}
item {
FontFamilySetting(
state = state,
onMainEvent = onMainEvent
)
}
item {
FontStyleSetting(
state = state,
onMainEvent = onMainEvent
)
}
item {
FontSizeSetting(
state = state,
onMainEvent = onMainEvent
)
}
item {
Spacer(
modifier = Modifier
.animateItem()
.height(bottomPadding)
)
}
}

View file

@ -0,0 +1,96 @@
@file:Suppress("FunctionName")
package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.subcategories
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.coerceAtLeast
import androidx.compose.ui.unit.dp
import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.components.CategoryTitle
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings.LineHeightSetting
import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings.ParagraphHeightSetting
import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings.ParagraphIndentationSetting
import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings.SidePaddingSetting
/**
* Text subcategory.
* Contains all settings from Text.
*/
fun LazyListScope.TextSubcategory(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit,
titleColor: @Composable () -> Color = { MaterialTheme.colorScheme.primary },
title: @Composable () -> String = { stringResource(id = R.string.text_reader_settings) },
showTitle: Boolean = true,
topPadding: Dp,
bottomPadding: Dp
) {
item {
if (showTitle) {
CategoryTitle(
title = title.invoke(),
color = titleColor.invoke(),
modifier = Modifier
.animateItem()
.padding(
top = topPadding,
bottom = 8.dp
)
)
} else {
Spacer(
modifier = Modifier
.animateItem()
.height((topPadding - 8.dp).coerceAtLeast(0.dp))
)
}
}
item {
SidePaddingSetting(
state = state,
onMainEvent = onMainEvent
)
}
item {
LineHeightSetting(
state = state,
onMainEvent = onMainEvent
)
}
item {
ParagraphHeightSetting(
state = state,
onMainEvent = onMainEvent
)
}
item {
ParagraphIndentationSetting(
state = state,
onMainEvent = onMainEvent
)
}
item {
Spacer(
modifier = Modifier
.animateItem()
.height(bottomPadding)
)
}
}

View file

@ -0,0 +1,72 @@
@file:Suppress("FunctionName")
package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.subcategories
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.coerceAtLeast
import androidx.compose.ui.unit.dp
import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.components.CategoryTitle
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings.DoubleClickTranslationSetting
/**
* Translator subcategory.
* Contains all settings from Translator.
*/
fun LazyListScope.TranslatorSubcategory(
state: State<MainState>,
onMainEvent: (MainEvent) -> Unit,
titleColor: @Composable () -> Color = { MaterialTheme.colorScheme.primary },
title: @Composable () -> String = { stringResource(id = R.string.translator_reader_settings) },
showTitle: Boolean = true,
topPadding: Dp,
bottomPadding: Dp
) {
item {
if (showTitle) {
CategoryTitle(
title = title.invoke(),
color = titleColor.invoke(),
modifier = Modifier
.animateItem()
.padding(
top = topPadding,
bottom = 8.dp
)
)
} else {
Spacer(
modifier = Modifier
.animateItem()
.height((topPadding - 8.dp).coerceAtLeast(0.dp))
)
}
}
item {
DoubleClickTranslationSetting(
state = state,
onMainEvent
)
}
item {
Spacer(
modifier = Modifier
.animateItem()
.height(bottomPadding)
)
}
}

View file

@ -1,172 +1,26 @@
package ua.acclorite.book_story.presentation.screens.start.components
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.model.ButtonItem
import ua.acclorite.book_story.presentation.components.CategoryTitle
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainState
import ua.acclorite.book_story.presentation.screens.settings.components.SegmentedButtonWithTitle
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.theme_switcher.AppearanceSettingsThemeSwitcher
import ua.acclorite.book_story.presentation.ui.BookStoryTheme
import ua.acclorite.book_story.presentation.ui.DarkTheme
import ua.acclorite.book_story.presentation.ui.PureDark
import ua.acclorite.book_story.presentation.ui.SlidingTransition
import ua.acclorite.book_story.presentation.ui.Theme
import ua.acclorite.book_story.presentation.ui.ThemeContrast
import ua.acclorite.book_story.presentation.ui.isDark
import ua.acclorite.book_story.presentation.ui.isPureDark
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.subcategories.ThemePreferencesSubcategory
/**
* Appearance settings.
*/
fun LazyListScope.startAppearanceScreen(
mainState: State<MainState>,
onMainEvent: (MainEvent) -> Unit,
themeContrastTheme: State<Theme>
onMainEvent: (MainEvent) -> Unit
) {
item {
Spacer(
modifier = Modifier
.animateItem()
.height(16.dp)
)
}
item {
CategoryTitle(
modifier = Modifier.animateItem(),
title = stringResource(id = R.string.start_theme_preferences),
color = MaterialTheme.colorScheme.primary
)
}
item {
Spacer(
modifier = Modifier
.animateItem()
.height(8.dp)
)
}
item {
SegmentedButtonWithTitle(
modifier = Modifier.animateItem(),
title = stringResource(id = R.string.dark_theme_option),
locked = true,
buttons = DarkTheme.entries.map {
ButtonItem(
it.toString(),
when (it) {
DarkTheme.OFF -> stringResource(id = R.string.dark_theme_off)
DarkTheme.ON -> stringResource(id = R.string.dark_theme_on)
DarkTheme.FOLLOW_SYSTEM -> stringResource(id = R.string.dark_theme_follow_system)
},
MaterialTheme.typography.labelLarge,
it == mainState.value.darkTheme
)
}
) {
onMainEvent(
MainEvent.OnChangeDarkTheme(
it.id
)
)
}
}
item {
AppearanceSettingsThemeSwitcher(
modifier = Modifier.animateItem(),
ThemePreferencesSubcategory(
state = mainState,
onMainEvent = onMainEvent
onMainEvent = onMainEvent,
title = { stringResource(id = R.string.start_theme_preferences) },
topPadding = 16.dp,
bottomPadding = 8.dp
)
}
item {
BookStoryTheme(
theme = themeContrastTheme.value,
isDark = mainState.value.darkTheme!!.isDark(),
isPureDark = mainState.value.pureDark!!.isPureDark(context = LocalContext.current),
themeContrast = mainState.value.themeContrast!!
) {
SlidingTransition(
modifier = Modifier.animateItem(
fadeInSpec = null,
fadeOutSpec = null
),
visible = mainState.value.theme != Theme.DYNAMIC,
) {
SegmentedButtonWithTitle(
title = stringResource(id = R.string.theme_contrast_option),
locked = mainState.value.theme != Theme.DYNAMIC,
buttons = ThemeContrast.entries.map {
ButtonItem(
it.toString(),
when (it) {
ThemeContrast.STANDARD -> stringResource(id = R.string.theme_contrast_standard)
ThemeContrast.MEDIUM -> stringResource(id = R.string.theme_contrast_medium)
ThemeContrast.HIGH -> stringResource(id = R.string.theme_contrast_high)
},
MaterialTheme.typography.labelLarge,
it == mainState.value.themeContrast
)
}
) {
onMainEvent(
MainEvent.OnChangeThemeContrast(
it.id
)
)
}
}
}
}
item {
SlidingTransition(
modifier = Modifier.animateItem(
fadeInSpec = null,
fadeOutSpec = null
),
visible = mainState.value.darkTheme!!.isDark(),
) {
SegmentedButtonWithTitle(
title = stringResource(id = R.string.pure_dark_option),
locked = true,
buttons = PureDark.entries.map {
ButtonItem(
it.toString(),
when (it) {
PureDark.OFF -> stringResource(id = R.string.pure_dark_off)
PureDark.ON -> stringResource(id = R.string.pure_dark_on)
PureDark.SAVER -> stringResource(id = R.string.pure_dark_power_saver)
},
MaterialTheme.typography.labelLarge,
it == mainState.value.pureDark
)
}
) {
onMainEvent(
MainEvent.OnChangePureDark(
it.id
)
)
}
}
}
item {
Spacer(
modifier = Modifier
.animateItem()
.height(8.dp)
)
}
}

View file

@ -19,9 +19,7 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
@ -40,7 +38,6 @@ import ua.acclorite.book_story.presentation.screens.start.components.permissions
import ua.acclorite.book_story.presentation.screens.start.data.StartEvent
import ua.acclorite.book_story.presentation.screens.start.data.StartNavigationScreen
import ua.acclorite.book_story.presentation.screens.start.data.StartState
import ua.acclorite.book_story.presentation.ui.Theme
/**
* Start Settings.
@ -74,13 +71,6 @@ fun StartSettings(
)
}.sortedBy { it.title }
}
val themeContrastTheme = remember { mutableStateOf(mainState.value.theme!!) }
LaunchedEffect(mainState.value.theme) {
if (themeContrastTheme.value != mainState.value.theme && mainState.value.theme != Theme.DYNAMIC) {
themeContrastTheme.value = mainState.value.theme!!
}
}
StartNavigationTransition(
modifier = Modifier.padding(horizontal = 18.dp),
@ -148,8 +138,7 @@ fun StartSettings(
) {
startAppearanceScreen(
mainState = mainState,
onMainEvent = onMainEvent,
themeContrastTheme = themeContrastTheme
onMainEvent = onMainEvent
)
}