From d6bfb4eb2dd0324979e237059cf962efb9bd7040 Mon Sep 17 00:00:00 2001 From: Acclorite <140836141+Acclorite@users.noreply.github.com> Date: Thu, 19 Sep 2024 22:14:21 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=80=20Perception=20Expander=20option?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added Perception Expander option in Reader * May improve your reading speed when you focus on text in the center Resolves: #72 --- .../core/constants/DataStoreConstants.kt | 3 + .../book_story/presentation/data/MainEvent.kt | 3 + .../book_story/presentation/data/MainState.kt | 15 +++++ .../presentation/data/MainViewModel.kt | 42 ++++++++++++++ .../screens/reader/ReaderScreen.kt | 19 +++++++ .../components/ReaderPerceptionExpander.kt | 55 +++++++++++++++++++ .../ReaderSettingsBottomSheet.kt | 6 ++ .../components/ReaderSettingsCategory.kt | 6 ++ .../PerceptionExpanderPaddingSetting.kt | 30 ++++++++++ .../settings/PerceptionExpanderSetting.kt | 31 +++++++++++ .../PerceptionExpanderThicknessSetting.kt | 30 ++++++++++ .../subcategories/ReadingSpeedSubcategory.kt | 49 +++++++++++++++++ app/src/main/res/values-uk/strings.xml | 7 +++ app/src/main/res/values/strings.xml | 7 +++ 14 files changed, 303 insertions(+) create mode 100644 app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/ReaderPerceptionExpander.kt create mode 100644 app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/PerceptionExpanderPaddingSetting.kt create mode 100644 app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/PerceptionExpanderSetting.kt create mode 100644 app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/PerceptionExpanderThicknessSetting.kt create mode 100644 app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/subcategories/ReadingSpeedSubcategory.kt diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/core/constants/DataStoreConstants.kt b/app/src/main/java/ua/acclorite/book_story/presentation/core/constants/DataStoreConstants.kt index 8843662a..eafd2f31 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/core/constants/DataStoreConstants.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/core/constants/DataStoreConstants.kt @@ -34,6 +34,9 @@ object DataStoreConstants { val FULLSCREEN = booleanPreferencesKey("fullscreen") val KEEP_SCREEN_ON = booleanPreferencesKey("keep_screen_on") val HIDE_BARS_ON_FAST_SCROLL = booleanPreferencesKey("hide_bars_on_fast_scroll") + val PERCEPTION_EXPANDER = booleanPreferencesKey("perception_expander") + val PERCEPTION_EXPANDER_PADDING = intPreferencesKey("perception_expander_padding") + val PERCEPTION_EXPANDER_THICKNESS = intPreferencesKey("perception_expander_thickness") // Browse settings val BROWSE_FILES_STRUCTURE = stringPreferencesKey("browse_files_structure") diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/data/MainEvent.kt b/app/src/main/java/ua/acclorite/book_story/presentation/data/MainEvent.kt index 96a46a2b..8f843f09 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/data/MainEvent.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/data/MainEvent.kt @@ -37,4 +37,7 @@ sealed class MainEvent { data class OnChangeKeepScreenOn(val bool: Boolean) : MainEvent() data class OnChangeVerticalPadding(val padding: Int) : MainEvent() data class OnChangeHideBarsOnFastScroll(val bool: Boolean) : MainEvent() + data class OnChangePerceptionExpander(val bool: Boolean) : MainEvent() + data class OnChangePerceptionExpanderPadding(val padding: Int) : MainEvent() + data class OnChangePerceptionExpanderThickness(val thickness: Int) : MainEvent() } \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/data/MainState.kt b/app/src/main/java/ua/acclorite/book_story/presentation/data/MainState.kt index 4e7a59ae..9c5537da 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/data/MainState.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/data/MainState.kt @@ -74,6 +74,9 @@ data class MainState( val fullscreen: Boolean = provideDefaultValue { true }, val keepScreenOn: Boolean = provideDefaultValue { true }, val hideBarsOnFastScroll: Boolean = provideDefaultValue { true }, + val perceptionExpander: Boolean = provideDefaultValue { false }, + val perceptionExpanderPadding: Int = provideDefaultValue { 5 }, + val perceptionExpanderThickness: Int = provideDefaultValue { 4 }, // Browse Settings val browseFilesStructure: BrowseFilesStructure = provideDefaultValue { @@ -239,6 +242,18 @@ data class MainState( hideBarsOnFastScroll = provideValue( HIDE_BARS_ON_FAST_SCROLL ) { hideBarsOnFastScroll }, + + perceptionExpander = provideValue( + PERCEPTION_EXPANDER + ) { perceptionExpander }, + + perceptionExpanderPadding = provideValue( + PERCEPTION_EXPANDER_PADDING + ) { perceptionExpanderPadding }, + + perceptionExpanderThickness = provideValue( + PERCEPTION_EXPANDER_THICKNESS + ) { perceptionExpanderThickness }, ) } } diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/data/MainViewModel.kt b/app/src/main/java/ua/acclorite/book_story/presentation/data/MainViewModel.kt index b474e74c..766cbf27 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/data/MainViewModel.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/data/MainViewModel.kt @@ -460,6 +460,48 @@ class MainViewModel @Inject constructor( } } } + + is MainEvent.OnChangePerceptionExpander -> { + viewModelScope.launch(Dispatchers.IO) { + setDatastore.execute( + DataStoreConstants.PERCEPTION_EXPANDER, + event.bool + ) + updateStateWithSavedHandle { + it.copy( + perceptionExpander = event.bool + ) + } + } + } + + is MainEvent.OnChangePerceptionExpanderPadding -> { + viewModelScope.launch(Dispatchers.IO) { + setDatastore.execute( + DataStoreConstants.PERCEPTION_EXPANDER_PADDING, + event.padding + ) + updateStateWithSavedHandle { + it.copy( + perceptionExpanderPadding = event.padding + ) + } + } + } + + is MainEvent.OnChangePerceptionExpanderThickness -> { + viewModelScope.launch(Dispatchers.IO) { + setDatastore.execute( + DataStoreConstants.PERCEPTION_EXPANDER_THICKNESS, + event.thickness + ) + updateStateWithSavedHandle { + it.copy( + perceptionExpanderThickness = event.thickness + ) + } + } + } } } diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/ReaderScreen.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/ReaderScreen.kt index 6f079fd7..5cda8900 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/ReaderScreen.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/ReaderScreen.kt @@ -79,6 +79,7 @@ import ua.acclorite.book_story.presentation.screens.history.data.HistoryEvent import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent import ua.acclorite.book_story.presentation.screens.reader.components.ReaderChapter import ua.acclorite.book_story.presentation.screens.reader.components.ReaderChaptersDrawer +import ua.acclorite.book_story.presentation.screens.reader.components.ReaderPerceptionExpander import ua.acclorite.book_story.presentation.screens.reader.components.ReaderTextParagraph import ua.acclorite.book_story.presentation.screens.reader.components.app_bar.ReaderBottomBar import ua.acclorite.book_story.presentation.screens.reader.components.app_bar.ReaderTopBar @@ -267,6 +268,17 @@ private fun ReaderScreen(lazyListState: LazyListState) { } (mainState.value.paragraphIndentation * 6).sp } + val perceptionExpanderPadding = remember( + sidePadding, + mainState.value.perceptionExpanderPadding + ) { + sidePadding + (mainState.value.perceptionExpanderPadding * 8).dp + } + val perceptionExpanderThickness = remember( + mainState.value.perceptionExpanderThickness + ) { + (mainState.value.perceptionExpanderThickness * 0.25f).dp + } val density = LocalDensity.current val layoutDirection = LocalLayoutDirection.current @@ -499,6 +511,13 @@ private fun ReaderScreen(lazyListState: LazyListState) { } } } + + ReaderPerceptionExpander( + perceptionExpander = mainState.value.perceptionExpander, + sidePadding = perceptionExpanderPadding, + thickness = perceptionExpanderThickness, + lineColor = fontColor.value + ) } if (state.value.loading || state.value.errorMessage != null) { diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/ReaderPerceptionExpander.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/ReaderPerceptionExpander.kt new file mode 100644 index 00000000..dd4680be --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/components/ReaderPerceptionExpander.kt @@ -0,0 +1,55 @@ +package ua.acclorite.book_story.presentation.screens.reader.components + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.VerticalDivider +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.coerceAtMost +import androidx.compose.ui.unit.dp +import ua.acclorite.book_story.presentation.ui.DefaultTransition + +/** + * Reader Perception Expander. + * Shows two vertical lines on both sides which separate text. + * This can help you improve reading speed by focusing only on central side. + * + * @param perceptionExpander Whether perception expander is enabled. + * @param sidePadding Side padding applied on top of side text padding. + * @param thickness Thickness of the line. + * @param lineColor Color of the line. + */ +@Composable +fun ReaderPerceptionExpander( + perceptionExpander: Boolean, + sidePadding: Dp, + thickness: Dp, + lineColor: Color +) { + DefaultTransition(visible = perceptionExpander) { + Row( + modifier = Modifier + .fillMaxSize() + .padding( + horizontal = sidePadding.coerceAtMost( + LocalConfiguration.current.screenWidthDp.run { + this / 2f - (this * 0.1f) + }.dp + ) + ), + horizontalArrangement = Arrangement.SpaceBetween + ) { + repeat(2) { + VerticalDivider( + color = lineColor, + thickness = thickness + ) + } + } + } +} \ No newline at end of file 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 4029238e..27b99e09 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 @@ -28,6 +28,7 @@ import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.c 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.MiscSubcategory import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.subcategories.PaddingSubcategory +import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.subcategories.ReadingSpeedSubcategory 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 @@ -92,6 +93,11 @@ fun ReaderSettingsBottomSheet() { topPadding = 22.dp, bottomPadding = 0.dp ) + ReadingSpeedSubcategory( + titleColor = { MaterialTheme.colorScheme.onSurface }, + topPadding = 22.dp, + bottomPadding = 0.dp + ) MiscSubcategory( titleColor = { MaterialTheme.colorScheme.onSurface }, showDivider = false, 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 index 8de258e7..abfdc3c2 100644 --- 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 @@ -12,6 +12,7 @@ import ua.acclorite.book_story.presentation.core.components.CategoryTitle 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.MiscSubcategory import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.subcategories.PaddingSubcategory +import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.subcategories.ReadingSpeedSubcategory 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 @@ -43,6 +44,11 @@ fun LazyListScope.ReaderSettingsCategory( topPadding = 22.dp, bottomPadding = 0.dp ) + ReadingSpeedSubcategory( + titleColor = titleColor, + topPadding = 22.dp, + bottomPadding = 0.dp + ) TranslatorSubcategory( titleColor = titleColor, topPadding = 22.dp, diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/PerceptionExpanderPaddingSetting.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/PerceptionExpanderPaddingSetting.kt new file mode 100644 index 00000000..085d0ad4 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/PerceptionExpanderPaddingSetting.kt @@ -0,0 +1,30 @@ +package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings + +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import ua.acclorite.book_story.R +import ua.acclorite.book_story.presentation.core.components.LocalMainViewModel +import ua.acclorite.book_story.presentation.data.MainEvent +import ua.acclorite.book_story.presentation.screens.settings.components.SliderWithTitle + +/** + * Perception Expander Padding setting. + * Changes side padding applied to lines. + */ +@Composable +fun PerceptionExpanderPaddingSetting() { + val state = LocalMainViewModel.current.state + val onMainEvent = LocalMainViewModel.current.onEvent + + SliderWithTitle( + value = state.value.perceptionExpanderPadding to "pt", + fromValue = 0, + toValue = 24, + title = stringResource(id = R.string.perception_expander_padding_option), + onValueChange = { + onMainEvent( + MainEvent.OnChangePerceptionExpanderPadding(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/PerceptionExpanderSetting.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/PerceptionExpanderSetting.kt new file mode 100644 index 00000000..894e98f8 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/PerceptionExpanderSetting.kt @@ -0,0 +1,31 @@ +package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings + +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import ua.acclorite.book_story.R +import ua.acclorite.book_story.presentation.core.components.LocalMainViewModel +import ua.acclorite.book_story.presentation.data.MainEvent +import ua.acclorite.book_story.presentation.screens.settings.components.SwitchWithTitle + +/** + * Perception Expander setting. + * If true, shows vertical lines in Reader, which makes you read faster. + */ +@Composable +fun PerceptionExpanderSetting() { + val state = LocalMainViewModel.current.state + val onMainEvent = LocalMainViewModel.current.onEvent + + SwitchWithTitle( + selected = state.value.perceptionExpander, + title = stringResource(id = R.string.perception_expander_option), + description = stringResource(id = R.string.perception_expander_option_desc), + onClick = { + onMainEvent( + MainEvent.OnChangePerceptionExpander( + !state.value.perceptionExpander + ) + ) + } + ) +} \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/PerceptionExpanderThicknessSetting.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/PerceptionExpanderThicknessSetting.kt new file mode 100644 index 00000000..58bc0ce9 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/settings/PerceptionExpanderThicknessSetting.kt @@ -0,0 +1,30 @@ +package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings + +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import ua.acclorite.book_story.R +import ua.acclorite.book_story.presentation.core.components.LocalMainViewModel +import ua.acclorite.book_story.presentation.data.MainEvent +import ua.acclorite.book_story.presentation.screens.settings.components.SliderWithTitle + +/** + * Perception Expander Thickness setting. + * Changes thickness of the line. + */ +@Composable +fun PerceptionExpanderThicknessSetting() { + val state = LocalMainViewModel.current.state + val onMainEvent = LocalMainViewModel.current.onEvent + + SliderWithTitle( + value = state.value.perceptionExpanderThickness to "pt", + fromValue = 1, + toValue = 12, + title = stringResource(id = R.string.perception_expander_thickness_option), + onValueChange = { + onMainEvent( + MainEvent.OnChangePerceptionExpanderThickness(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/ReadingSpeedSubcategory.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/subcategories/ReadingSpeedSubcategory.kt new file mode 100644 index 00000000..c737996b --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/reader/components/subcategories/ReadingSpeedSubcategory.kt @@ -0,0 +1,49 @@ +@file:Suppress("FunctionName") + +package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.subcategories + +import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.Dp +import ua.acclorite.book_story.R +import ua.acclorite.book_story.presentation.screens.settings.components.SettingsSubcategory +import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings.PerceptionExpanderPaddingSetting +import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings.PerceptionExpanderSetting +import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings.PerceptionExpanderThicknessSetting + +/** + * Reading Speed subcategory. + * Contains all settings that can improve your reading speed. + */ +fun LazyListScope.ReadingSpeedSubcategory( + titleColor: @Composable () -> Color = { MaterialTheme.colorScheme.primary }, + title: @Composable () -> String = { stringResource(id = R.string.reading_speed_reader_settings) }, + showTitle: Boolean = true, + showDivider: Boolean = true, + topPadding: Dp, + bottomPadding: Dp +) { + SettingsSubcategory( + titleColor = titleColor, + title = title, + showTitle = showTitle, + showDivider = showDivider, + topPadding = topPadding, + bottomPadding = bottomPadding + ) { + item { + PerceptionExpanderSetting() + } + + item { + PerceptionExpanderPaddingSetting() + } + + item { + PerceptionExpanderThicknessSetting() + } + } +} \ No newline at end of file diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 6d62bea3..299d42a6 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -199,6 +199,7 @@ Перекладач Відступи Інше + Швидкість читання Налаштування теми Кольори Головні @@ -243,6 +244,12 @@ Сховати системні панелі та прибрати відступи Тримати екран увімкненим Ховати панелі при швидкому прокручуванні + Розширення сприйняття + + Збільшіть швидкість вашого читання, читаючи менше слів напряму + + Відступи розширення сприйняття + Товщина лінії розширення сприйняття Структура файлів diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3f4279ff..0e6c3190 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -202,6 +202,7 @@ Translator Padding Misc + Reading speed Theme preferences Colors General @@ -246,6 +247,12 @@ Hide system bars and remove padding Keep screen on Hide bars on fast scroll + Perception expander + + Increase your reading speed by reading less words directly + + Perception expander padding + Perception expander line thickness Files structure