🚀 Perception Expander option

* Added Perception Expander option in Reader
* May improve your reading speed when you focus on text in the center

Resolves: #72
This commit is contained in:
Acclorite 2024-09-19 22:14:21 +03:00
parent d0c79879ad
commit d6bfb4eb2d
14 changed files with 303 additions and 0 deletions

View file

@ -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")

View file

@ -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()
}

View file

@ -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 },
)
}
}

View file

@ -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
)
}
}
}
}
}

View file

@ -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) {

View file

@ -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
)
}
}
}
}

View file

@ -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,

View file

@ -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,

View file

@ -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)
)
}
)
}

View file

@ -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
)
)
}
)
}

View file

@ -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)
)
}
)
}

View file

@ -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()
}
}
}

View file

@ -199,6 +199,7 @@
<string name="translator_reader_settings">Перекладач</string>
<string name="padding_reader_settings">Відступи</string>
<string name="misc_reader_settings">Інше</string>
<string name="reading_speed_reader_settings">Швидкість читання</string>
<string name="theme_appearance_settings">Налаштування теми</string>
<string name="colors_appearance_settings">Кольори</string>
<string name="general_browse_settings">Головні</string>
@ -243,6 +244,12 @@
<string name="fullscreen_option_desc">Сховати системні панелі та прибрати відступи</string>
<string name="keep_screen_on_option">Тримати екран увімкненим</string>
<string name="hide_bars_on_fast_scroll_option">Ховати панелі при швидкому прокручуванні</string>
<string name="perception_expander_option">Розширення сприйняття</string>
<string name="perception_expander_option_desc">
Збільшіть швидкість вашого читання, читаючи менше слів напряму
</string>
<string name="perception_expander_padding_option">Відступи розширення сприйняття</string>
<string name="perception_expander_thickness_option">Товщина лінії розширення сприйняття</string>
<!-- Browse -->
<string name="browse_files_structure_option">Структура файлів</string>

View file

@ -202,6 +202,7 @@
<string name="translator_reader_settings">Translator</string>
<string name="padding_reader_settings">Padding</string>
<string name="misc_reader_settings">Misc</string>
<string name="reading_speed_reader_settings">Reading speed</string>
<string name="theme_appearance_settings">Theme preferences</string>
<string name="colors_appearance_settings">Colors</string>
<string name="general_browse_settings">General</string>
@ -246,6 +247,12 @@
<string name="fullscreen_option_desc">Hide system bars and remove padding</string>
<string name="keep_screen_on_option">Keep screen on</string>
<string name="hide_bars_on_fast_scroll_option">Hide bars on fast scroll</string>
<string name="perception_expander_option">Perception expander</string>
<string name="perception_expander_option_desc">
Increase your reading speed by reading less words directly
</string>
<string name="perception_expander_padding_option">Perception expander padding</string>
<string name="perception_expander_thickness_option">Perception expander line thickness</string>
<!-- Browse -->
<string name="browse_files_structure_option">Files structure</string>