🚀 Horizontal gesture "Animate visibility" option

* Option to change how much (in %) the visibility animates when using horizontal gesture
This commit is contained in:
Acclorite 2025-03-11 09:06:04 +02:00
parent 0fec497c1b
commit 78e7d710ea
15 changed files with 78 additions and 5 deletions

View file

@ -17,7 +17,6 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlin.collections.plus
@HiltViewModel(assistedFactory = Navigator.Factory::class)
class Navigator @AssistedInject constructor(

View file

@ -50,6 +50,7 @@ object DataStoreConstants {
val HORIZONTAL_GESTURE = stringPreferencesKey("horizontal_gesture")
val HORIZONTAL_GESTURE_SCROLL = doublePreferencesKey("horizontal_gesture_scroll")
val HORIZONTAL_GESTURE_SENSITIVITY = doublePreferencesKey("horizontal_gesture_sensitivity")
val HORIZONTAL_GESTURE_ALPHA_ANIM = doublePreferencesKey("horizontal_gesture_alpha_anim")
val BOTTOM_BAR_PADDING = intPreferencesKey("bottom_bar_padding")
val HIGHLIGHTED_READING = booleanPreferencesKey("highlighted_reading")
val HIGHLIGHTED_READING_THICKNESS = intPreferencesKey("highlighted_reading_thickness")

View file

@ -57,6 +57,7 @@ fun ReaderContent(
horizontalGesture: ReaderHorizontalGesture,
horizontalGestureScroll: Float,
horizontalGestureSensitivity: Dp,
horizontalGestureAlphaAnim: Float,
highlightedReading: Boolean,
highlightedReadingThickness: FontWeight,
progress: String,
@ -133,6 +134,7 @@ fun ReaderContent(
horizontalGesture = horizontalGesture,
horizontalGestureScroll = horizontalGestureScroll,
horizontalGestureSensitivity = horizontalGestureSensitivity,
horizontalGestureAlphaAnim = horizontalGestureAlphaAnim,
highlightedReading = highlightedReading,
highlightedReadingThickness = highlightedReadingThickness,
progress = progress,

View file

@ -34,11 +34,13 @@ fun Modifier.readerHorizontalGesture(
horizontalGesture: ReaderHorizontalGesture,
horizontalGestureScroll: Float,
horizontalGestureSensitivity: Dp,
horizontalGestureAlphaAnim: Float,
isLoading: Boolean
): Modifier {
if (horizontalGesture == ReaderHorizontalGesture.OFF || isLoading) return this
val inverted = rememberUpdatedState(horizontalGesture == ReaderHorizontalGesture.INVERSE)
val sensitivity = rememberUpdatedState(horizontalGestureSensitivity)
val alphaAnim = rememberUpdatedState(horizontalGestureAlphaAnim)
val scope = rememberCoroutineScope()
val density = LocalDensity.current
@ -69,7 +71,9 @@ fun Modifier.readerHorizontalGesture(
@Composable
fun calculateAlpha(): Float {
return animateFloatAsState(
1f - (abs(with(density) { horizontalOffset.floatValue.toDp() }.value) / sensitivity.value.value)
1f - abs(with(density) { horizontalOffset.floatValue.toDp() }.value)
.div(sensitivity.value.value)
.times(alphaAnim.value)
).value
}
@ -89,7 +93,7 @@ fun Modifier.readerHorizontalGesture(
onDragStart = {
horizontalOffset.floatValue = 0f
},
onHorizontalDrag = { change, dragAmount ->
onHorizontalDrag = { _, dragAmount ->
horizontalOffset.floatValue += (dragAmount * 0.15f)
},
onDragCancel = {

View file

@ -57,6 +57,7 @@ fun ReaderLayout(
horizontalGesture: ReaderHorizontalGesture,
horizontalGestureScroll: Float,
horizontalGestureSensitivity: Dp,
horizontalGestureAlphaAnim: Float,
highlightedReading: Boolean,
highlightedReadingThickness: FontWeight,
progress: String,
@ -162,6 +163,7 @@ fun ReaderLayout(
horizontalGesture = horizontalGesture,
horizontalGestureScroll = horizontalGestureScroll,
horizontalGestureSensitivity = horizontalGestureSensitivity,
horizontalGestureAlphaAnim = horizontalGestureAlphaAnim,
isLoading = isLoading
)
) {
@ -181,7 +183,7 @@ fun ReaderLayout(
) {
itemsIndexed(
text,
key = { index, entry -> index }
key = { index, _ -> index }
) { index, entry ->
when {
!images && entry is ReaderText.Image -> return@itemsIndexed

View file

@ -61,6 +61,7 @@ fun ReaderScaffold(
horizontalGesture: ReaderHorizontalGesture,
horizontalGestureScroll: Float,
horizontalGestureSensitivity: Dp,
horizontalGestureAlphaAnim: Float,
highlightedReading: Boolean,
highlightedReadingThickness: FontWeight,
progress: String,
@ -164,6 +165,7 @@ fun ReaderScaffold(
horizontalGesture = horizontalGesture,
horizontalGestureScroll = horizontalGestureScroll,
horizontalGestureSensitivity = horizontalGestureSensitivity,
horizontalGestureAlphaAnim = horizontalGestureAlphaAnim,
highlightedReading = highlightedReading,
highlightedReadingThickness = highlightedReadingThickness,
progress = progress,

View file

@ -15,6 +15,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.settings.components.SettingsSubcategory
import ua.acclorite.book_story.presentation.settings.reader.reading_mode.components.HorizontalGestureAlphaAnimOption
import ua.acclorite.book_story.presentation.settings.reader.reading_mode.components.HorizontalGestureOption
import ua.acclorite.book_story.presentation.settings.reader.reading_mode.components.HorizontalGestureScrollOption
import ua.acclorite.book_story.presentation.settings.reader.reading_mode.components.HorizontalGestureSensitivityOption
@ -42,5 +43,9 @@ fun LazyListScope.ReadingModeSubcategory(
item {
HorizontalGestureSensitivityOption()
}
item {
HorizontalGestureAlphaAnimOption()
}
}
}

View file

@ -0,0 +1,42 @@
/*
* Book's Story free and open-source Material You eBook reader.
* Copyright (C) 2024-2025 Acclorite
* SPDX-License-Identifier: GPL-3.0-only
*/
package ua.acclorite.book_story.presentation.settings.reader.reading_mode.components
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.reader.ReaderHorizontalGesture
import ua.acclorite.book_story.presentation.core.components.settings.SliderWithTitle
import ua.acclorite.book_story.ui.main.MainEvent
import ua.acclorite.book_story.ui.main.MainModel
import ua.acclorite.book_story.ui.theme.ExpandingTransition
@Composable
fun HorizontalGestureAlphaAnimOption() {
val mainModel = hiltViewModel<MainModel>()
val state = mainModel.state.collectAsStateWithLifecycle()
ExpandingTransition(
visible = when (state.value.horizontalGesture) {
ReaderHorizontalGesture.OFF -> false
else -> true
}
) {
SliderWithTitle(
value = state.value.horizontalGestureAlphaAnim to "%",
toValue = 100,
title = stringResource(id = R.string.horizontal_gesture_alpha_anim_option),
onValueChange = {
mainModel.onEvent(
MainEvent.OnChangeHorizontalGestureAlphaAnim(it)
)
}
)
}
}

View file

@ -32,7 +32,6 @@ import ua.acclorite.book_story.domain.use_case.file_system.GetFiles
import ua.acclorite.book_story.presentation.core.util.showToast
import ua.acclorite.book_story.ui.library.LibraryScreen
import javax.inject.Inject
import kotlin.collections.map
@HiltViewModel
class BrowseModel @Inject constructor(

View file

@ -65,4 +65,5 @@ sealed class MainEvent {
data class OnChangeBrowsePinnedPaths(val value: String) : MainEvent()
data class OnChangeFontThickness(val value: String) : MainEvent()
data class OnChangeProgressCount(val value: String) : MainEvent()
data class OnChangeHorizontalGestureAlphaAnim(val value: Float) : MainEvent()
}

View file

@ -499,6 +499,14 @@ class MainModel @Inject constructor(
it.copy(progressCount = this.toProgressCount())
}
)
is MainEvent.OnChangeHorizontalGestureAlphaAnim -> handleDatastoreUpdate(
key = DataStoreConstants.HORIZONTAL_GESTURE_ALPHA_ANIM,
value = event.value.toDouble(),
updateState = {
it.copy(horizontalGestureAlphaAnim = this.toFloat())
}
)
}
}

View file

@ -101,6 +101,7 @@ data class MainState(
},
val horizontalGestureScroll: Float = provideDefaultValue { 0.7f },
val horizontalGestureSensitivity: Float = provideDefaultValue { 0.6f },
val horizontalGestureAlphaAnim: Float = provideDefaultValue { 1f },
val bottomBarPadding: Int = provideDefaultValue { 0 },
val highlightedReading: Boolean = provideDefaultValue { false },
val highlightedReadingThickness: Int = provideDefaultValue { 2 },
@ -365,6 +366,10 @@ data class MainState(
progressCount = provideValue(
PROGRESS_COUNT, convert = { toProgressCount() }
) { progressCount },
horizontalGestureAlphaAnim = provideValue(
HORIZONTAL_GESTURE_ALPHA_ANIM, convert = { toFloat() }
) { horizontalGestureAlphaAnim },
)
}
}

View file

@ -425,6 +425,7 @@ data class ReaderScreen(val bookId: Int) : Screen, Parcelable {
horizontalGesture = mainState.value.horizontalGesture,
horizontalGestureScroll = mainState.value.horizontalGestureScroll,
horizontalGestureSensitivity = horizontalGestureSensitivity,
horizontalGestureAlphaAnim = mainState.value.horizontalGestureAlphaAnim,
highlightedReading = mainState.value.highlightedReading,
highlightedReadingThickness = highlightedReadingThickness,
progress = progress,

View file

@ -186,6 +186,7 @@
<string name="horizontal_gesture_option">Горизонтальний жест</string>
<string name="horizontal_gesture_scroll_option">Частка прокрутки</string>
<string name="horizontal_gesture_sensitivity_option">Чутливість</string>
<string name="horizontal_gesture_alpha_anim_option">Анімувати видимість</string>
<string name="bottom_bar_padding_option">Відступ нижньої панелі</string>
<string name="highlighted_reading_option">Підсвічування слів</string>
<string name="highlighted_reading_option_desc">Підсвічувати початок кожного слова</string>

View file

@ -217,6 +217,7 @@
<string name="horizontal_gesture_option">Horizontal gesture</string>
<string name="horizontal_gesture_scroll_option">Scroll fraction</string>
<string name="horizontal_gesture_sensitivity_option">Sensitivity</string>
<string name="horizontal_gesture_alpha_anim_option">Animate visibility</string>
<string name="bottom_bar_padding_option">Bottom bar margin</string>
<string name="highlighted_reading_option">Highlight words</string>
<string name="highlighted_reading_option_desc">Highlight the beginning of each word</string>