diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/settings_bottom_sheet/ReaderSettingsBottomSheet.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/settings_bottom_sheet/ReaderSettingsBottomSheet.kt index 3ae59952..d50144d7 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/settings_bottom_sheet/ReaderSettingsBottomSheet.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/settings_bottom_sheet/ReaderSettingsBottomSheet.kt @@ -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 ) } } diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/components/ChipsWithTitle.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/components/ChipsWithTitle.kt index 26bda740..ab2d51c6 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/components/ChipsWithTitle.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/components/ChipsWithTitle.kt @@ -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, horizontalPadding: Dp = 18.dp, @@ -30,7 +31,7 @@ fun ChipsWithTitle( onClick: (ButtonItem) -> Unit ) { Column( - Modifier + modifier .fillMaxWidth() .padding(horizontal = horizontalPadding, vertical = verticalPadding) ) { diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/components/SwitchWIthTitle.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/components/SwitchWIthTitle.kt index 244dac28..7a141b7b 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/components/SwitchWIthTitle.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/components/SwitchWIthTitle.kt @@ -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 diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/AppearanceSettings.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/AppearanceSettings.kt index 56375762..17b25d80 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/AppearanceSettings.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/AppearanceSettings.kt @@ -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(), - 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) - ) - } + AppearanceSettingsCategory( + state = state, + onMainEvent = onMainEvent + ) } } } \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/AppearanceSettingsCategory.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/AppearanceSettingsCategory.kt new file mode 100644 index 00000000..68e5e907 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/AppearanceSettingsCategory.kt @@ -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, + 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 + ) +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/settings/DarkThemeSetting.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/settings/DarkThemeSetting.kt new file mode 100644 index 00000000..b661da8c --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/settings/DarkThemeSetting.kt @@ -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, + 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 + ) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/settings/PureDarkSetting.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/settings/PureDarkSetting.kt new file mode 100644 index 00000000..0b1815ee --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/settings/PureDarkSetting.kt @@ -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, + 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 + ) + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/settings/ThemeContrastSetting.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/settings/ThemeContrastSetting.kt new file mode 100644 index 00000000..7b21d698 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/settings/ThemeContrastSetting.kt @@ -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, + 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 + ) + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/theme_switcher/AppearanceSettingsThemeSwitcherItem.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/settings/ThemeSetting.kt similarity index 70% rename from app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/theme_switcher/AppearanceSettingsThemeSwitcherItem.kt rename to app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/settings/ThemeSetting.kt index 3c6f44b0..b47b13e0 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/theme_switcher/AppearanceSettingsThemeSwitcherItem.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/settings/ThemeSetting.kt @@ -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, + 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, darkTheme: Boolean, isPureDark: Boolean, diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/subcategories/ColorsSubcategory.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/subcategories/ColorsSubcategory.kt new file mode 100644 index 00000000..6a24b68e --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/subcategories/ColorsSubcategory.kt @@ -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, + 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) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/subcategories/ThemePreferencesSubcategory.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/subcategories/ThemePreferencesSubcategory.kt new file mode 100644 index 00000000..0e0f4ec5 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/subcategories/ThemePreferencesSubcategory.kt @@ -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, + 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) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/theme_switcher/AppearanceSettingsThemeSwitcher.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/theme_switcher/AppearanceSettingsThemeSwitcher.kt deleted file mode 100644 index 2d8650ef..00000000 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/appearance/components/theme_switcher/AppearanceSettingsThemeSwitcher.kt +++ /dev/null @@ -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, - 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)) - } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/general/GeneralSettings.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/general/GeneralSettings.kt index e0e2d4db..a3e6d820 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/general/GeneralSettings.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/general/GeneralSettings.kt @@ -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, @@ -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 - ) - }.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)) } + GeneralSettingsCategory( + state = state, + onMainEvent = onMainEvent, + onSettingsEvent = onSettingsEvent + ) } } } \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/general/components/GeneralSettingsCategory.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/general/components/GeneralSettingsCategory.kt new file mode 100644 index 00000000..3d1417ee --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/general/components/GeneralSettingsCategory.kt @@ -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, + 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) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/general/components/settings/AppLanguageSetting.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/general/components/settings/AppLanguageSetting.kt new file mode 100644 index 00000000..63288d9f --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/general/components/settings/AppLanguageSetting.kt @@ -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, + 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 + ) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/general/components/settings/CheckForUpdatesSetting.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/general/components/settings/CheckForUpdatesSetting.kt new file mode 100644 index 00000000..59567680 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/general/components/settings/CheckForUpdatesSetting.kt @@ -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, + 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 + ) + ) + } + ) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/ReaderSettings.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/ReaderSettings.kt index c0771c9c..ef18aec5 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/ReaderSettings.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/ReaderSettings.kt @@ -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 - ) - } - 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)) } + ReaderSettingsCategory( + state = state, + onMainEvent = onMainEvent + ) } } } \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/ReaderSettingsCategory.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/ReaderSettingsCategory.kt new file mode 100644 index 00000000..18841159 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/ReaderSettingsCategory.kt @@ -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, + 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 + ) +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/DoubleClickTranslationSetting.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/DoubleClickTranslationSetting.kt new file mode 100644 index 00000000..45197da2 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/DoubleClickTranslationSetting.kt @@ -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, + 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!! + ) + ) + } + ) +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/FontFamilySetting.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/FontFamilySetting.kt new file mode 100644 index 00000000..9f89d94a --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/FontFamilySetting.kt @@ -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, + 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)) + } + ) +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/FontSizeSetting.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/FontSizeSetting.kt new file mode 100644 index 00000000..3b52c62d --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/FontSizeSetting.kt @@ -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, + 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) + ) + } + ) +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/FontStyleSetting.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/FontStyleSetting.kt new file mode 100644 index 00000000..57044070 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/FontStyleSetting.kt @@ -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, + 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 + } + ) + ) + } + ) +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/LineHeightSetting.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/LineHeightSetting.kt new file mode 100644 index 00000000..b6bebb92 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/LineHeightSetting.kt @@ -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, + 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) + ) + } + ) +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/ParagraphHeightSetting.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/ParagraphHeightSetting.kt new file mode 100644 index 00000000..7fbef726 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/ParagraphHeightSetting.kt @@ -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, + 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) + ) + } + ) +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/ParagraphIndentationSetting.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/ParagraphIndentationSetting.kt new file mode 100644 index 00000000..fe90cf71 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/ParagraphIndentationSetting.kt @@ -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, + 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!!) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/SidePaddingSetting.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/SidePaddingSetting.kt new file mode 100644 index 00000000..f4c5e417 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/SidePaddingSetting.kt @@ -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, + 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) + ) + } + ) +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/subcategories/FontSubcategory.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/subcategories/FontSubcategory.kt new file mode 100644 index 00000000..814d14c8 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/subcategories/FontSubcategory.kt @@ -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, + 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) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/subcategories/TextSubcategory.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/subcategories/TextSubcategory.kt new file mode 100644 index 00000000..986578a6 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/subcategories/TextSubcategory.kt @@ -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, + 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) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/subcategories/TranslatorSubcategory.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/subcategories/TranslatorSubcategory.kt new file mode 100644 index 00000000..fdf79de1 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/subcategories/TranslatorSubcategory.kt @@ -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, + 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) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/start/components/StartAppearanceScreen.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/start/components/StartAppearanceScreen.kt index 76bc98e9..13f0856b 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/start/components/StartAppearanceScreen.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/start/components/StartAppearanceScreen.kt @@ -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, - onMainEvent: (MainEvent) -> Unit, - themeContrastTheme: State + 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(), - state = mainState, - onMainEvent = onMainEvent - ) - } - - 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) - ) - } + ThemePreferencesSubcategory( + state = mainState, + onMainEvent = onMainEvent, + title = { stringResource(id = R.string.start_theme_preferences) }, + topPadding = 16.dp, + bottomPadding = 8.dp + ) } \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/start/components/StartSettings.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/start/components/StartSettings.kt index b7311ee3..d3ebae96 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/start/components/StartSettings.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/start/components/StartSettings.kt @@ -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 ) }