🚀 Images Color Effects option

* Different color effects (Grayscale, Font Color, Background Color)

Part-of: #69
This commit is contained in:
Acclorite 2025-01-10 16:00:35 +02:00
parent 76a1cc6f96
commit 67a5f12b6a
15 changed files with 151 additions and 2 deletions

View file

@ -0,0 +1,12 @@
package ua.acclorite.book_story.domain.reader
enum class ReaderColorEffects {
OFF,
GRAYSCALE,
FONT,
BACKGROUND
}
fun String.toColorEffects(): ReaderColorEffects {
return ReaderColorEffects.valueOf(this)
}

View file

@ -52,6 +52,7 @@ object DataStoreConstants {
val IMAGES_CORNERS_ROUNDNESS = intPreferencesKey("images_corners_roundness") val IMAGES_CORNERS_ROUNDNESS = intPreferencesKey("images_corners_roundness")
val IMAGES_ALIGNMENT = stringPreferencesKey("images_alignment") val IMAGES_ALIGNMENT = stringPreferencesKey("images_alignment")
val IMAGES_WIDTH = doublePreferencesKey("images_width") val IMAGES_WIDTH = doublePreferencesKey("images_width")
val IMAGES_COLOR_EFFECTS = stringPreferencesKey("images_color_effects")
// Browse settings // Browse settings
val BROWSE_FILES_STRUCTURE = stringPreferencesKey("browse_files_structure") val BROWSE_FILES_STRUCTURE = stringPreferencesKey("browse_files_structure")

View file

@ -6,6 +6,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
@ -60,6 +61,7 @@ fun ReaderContent(
imagesCornersRoundness: Dp, imagesCornersRoundness: Dp,
imagesAlignment: ReaderImagesAlignment, imagesAlignment: ReaderImagesAlignment,
imagesWidth: Float, imagesWidth: Float,
imagesColorEffects: ColorFilter?,
fontFamily: FontWithName, fontFamily: FontWithName,
lineHeight: TextUnit, lineHeight: TextUnit,
fontStyle: FontStyle, fontStyle: FontStyle,
@ -129,6 +131,7 @@ fun ReaderContent(
imagesCornersRoundness = imagesCornersRoundness, imagesCornersRoundness = imagesCornersRoundness,
imagesAlignment = imagesAlignment, imagesAlignment = imagesAlignment,
imagesWidth = imagesWidth, imagesWidth = imagesWidth,
imagesColorEffects = imagesColorEffects,
fontFamily = fontFamily, fontFamily = fontFamily,
lineHeight = lineHeight, lineHeight = lineHeight,
fontStyle = fontStyle, fontStyle = fontStyle,

View file

@ -14,6 +14,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
@ -53,6 +54,7 @@ fun ReaderLayout(
imagesCornersRoundness: Dp, imagesCornersRoundness: Dp,
imagesAlignment: ReaderImagesAlignment, imagesAlignment: ReaderImagesAlignment,
imagesWidth: Float, imagesWidth: Float,
imagesColorEffects: ColorFilter?,
fontFamily: FontWithName, fontFamily: FontWithName,
lineHeight: TextUnit, lineHeight: TextUnit,
fontStyle: FontStyle, fontStyle: FontStyle,
@ -172,6 +174,7 @@ fun ReaderLayout(
imagesCornersRoundness = imagesCornersRoundness, imagesCornersRoundness = imagesCornersRoundness,
imagesAlignment = imagesAlignment, imagesAlignment = imagesAlignment,
imagesWidth = imagesWidth, imagesWidth = imagesWidth,
imagesColorEffects = imagesColorEffects,
fontFamily = fontFamily, fontFamily = fontFamily,
fontColor = fontColor, fontColor = fontColor,
lineHeight = lineHeight, lineHeight = lineHeight,

View file

@ -5,6 +5,7 @@ import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
@ -23,6 +24,7 @@ fun LazyItemScope.ReaderLayoutText(
imagesCornersRoundness: Dp, imagesCornersRoundness: Dp,
imagesAlignment: ReaderImagesAlignment, imagesAlignment: ReaderImagesAlignment,
imagesWidth: Float, imagesWidth: Float,
imagesColorEffects: ColorFilter?,
fontFamily: FontWithName, fontFamily: FontWithName,
fontColor: Color, fontColor: Color,
lineHeight: TextUnit, lineHeight: TextUnit,
@ -49,7 +51,8 @@ fun LazyItemScope.ReaderLayoutText(
sidePadding = sidePadding, sidePadding = sidePadding,
imagesCornersRoundness = imagesCornersRoundness, imagesCornersRoundness = imagesCornersRoundness,
imagesAlignment = imagesAlignment, imagesAlignment = imagesAlignment,
imagesWidth = imagesWidth imagesWidth = imagesWidth,
imagesColorEffects = imagesColorEffects
) )
} }

View file

@ -9,6 +9,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import ua.acclorite.book_story.domain.reader.ReaderImagesAlignment import ua.acclorite.book_story.domain.reader.ReaderImagesAlignment
@ -20,7 +21,8 @@ fun LazyItemScope.ReaderLayoutTextImage(
sidePadding: Dp, sidePadding: Dp,
imagesCornersRoundness: Dp, imagesCornersRoundness: Dp,
imagesAlignment: ReaderImagesAlignment, imagesAlignment: ReaderImagesAlignment,
imagesWidth: Float imagesWidth: Float,
imagesColorEffects: ColorFilter?
) { ) {
Box( Box(
modifier = Modifier modifier = Modifier
@ -38,6 +40,7 @@ fun LazyItemScope.ReaderLayoutTextImage(
.fillMaxWidth(imagesWidth), .fillMaxWidth(imagesWidth),
bitmap = entry.imageBitmap, bitmap = entry.imageBitmap,
contentDescription = null, contentDescription = null,
colorFilter = imagesColorEffects,
contentScale = ContentScale.FillWidth contentScale = ContentScale.FillWidth
) )
} }

View file

@ -13,6 +13,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontStyle
@ -64,6 +65,7 @@ fun ReaderScaffold(
imagesCornersRoundness: Dp, imagesCornersRoundness: Dp,
imagesAlignment: ReaderImagesAlignment, imagesAlignment: ReaderImagesAlignment,
imagesWidth: Float, imagesWidth: Float,
imagesColorEffects: ColorFilter?,
fontFamily: FontWithName, fontFamily: FontWithName,
lineHeight: TextUnit, lineHeight: TextUnit,
fontStyle: FontStyle, fontStyle: FontStyle,
@ -160,6 +162,7 @@ fun ReaderScaffold(
imagesCornersRoundness = imagesCornersRoundness, imagesCornersRoundness = imagesCornersRoundness,
imagesAlignment = imagesAlignment, imagesAlignment = imagesAlignment,
imagesWidth = imagesWidth, imagesWidth = imagesWidth,
imagesColorEffects = imagesColorEffects,
fontFamily = fontFamily, fontFamily = fontFamily,
lineHeight = lineHeight, lineHeight = lineHeight,
fontStyle = fontStyle, fontStyle = fontStyle,

View file

@ -10,6 +10,7 @@ import androidx.compose.ui.res.stringResource
import ua.acclorite.book_story.R import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.settings.components.SettingsSubcategory import ua.acclorite.book_story.presentation.settings.components.SettingsSubcategory
import ua.acclorite.book_story.presentation.settings.reader.images.components.ImagesAlignmentOption import ua.acclorite.book_story.presentation.settings.reader.images.components.ImagesAlignmentOption
import ua.acclorite.book_story.presentation.settings.reader.images.components.ImagesColorEffectsOption
import ua.acclorite.book_story.presentation.settings.reader.images.components.ImagesCornersRoundnessOption import ua.acclorite.book_story.presentation.settings.reader.images.components.ImagesCornersRoundnessOption
import ua.acclorite.book_story.presentation.settings.reader.images.components.ImagesOption import ua.acclorite.book_story.presentation.settings.reader.images.components.ImagesOption
import ua.acclorite.book_story.presentation.settings.reader.images.components.ImagesWidthOption import ua.acclorite.book_story.presentation.settings.reader.images.components.ImagesWidthOption
@ -30,6 +31,10 @@ fun LazyListScope.ImagesSubcategory(
ImagesOption() ImagesOption()
} }
item {
ImagesColorEffectsOption()
}
item { item {
ImagesCornersRoundnessOption() ImagesCornersRoundnessOption()
} }

View file

@ -0,0 +1,57 @@
package ua.acclorite.book_story.presentation.settings.reader.images.components
import androidx.compose.material3.MaterialTheme
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.ReaderColorEffects
import ua.acclorite.book_story.domain.ui.ButtonItem
import ua.acclorite.book_story.presentation.core.components.settings.ChipsWithTitle
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 ImagesColorEffectsOption() {
val mainModel = hiltViewModel<MainModel>()
val state = mainModel.state.collectAsStateWithLifecycle()
ExpandingTransition(visible = state.value.images) {
ChipsWithTitle(
title = stringResource(id = R.string.images_color_effects_option),
chips = ReaderColorEffects.entries.map {
ButtonItem(
id = it.toString(),
title = when (it) {
ReaderColorEffects.OFF -> {
stringResource(R.string.color_effects_off)
}
ReaderColorEffects.GRAYSCALE -> {
stringResource(R.string.color_effects_grayscale)
}
ReaderColorEffects.FONT -> {
stringResource(R.string.color_effects_font)
}
ReaderColorEffects.BACKGROUND -> {
stringResource(R.string.color_effects_background)
}
},
textStyle = MaterialTheme.typography.labelLarge,
selected = it == state.value.imagesColorEffects
)
},
onClick = {
mainModel.onEvent(
MainEvent.OnChangeImagesColorEffects(
it.id
)
)
}
)
}
}

View file

@ -54,4 +54,5 @@ sealed class MainEvent {
data class OnChangeImagesCornersRoundness(val value: Int) : MainEvent() data class OnChangeImagesCornersRoundness(val value: Int) : MainEvent()
data class OnChangeImagesAlignment(val value: String) : MainEvent() data class OnChangeImagesAlignment(val value: String) : MainEvent()
data class OnChangeImagesWidth(val value: Float) : MainEvent() data class OnChangeImagesWidth(val value: Float) : MainEvent()
data class OnChangeImagesColorEffects(val value: String) : MainEvent()
} }

View file

@ -19,6 +19,7 @@ import kotlinx.coroutines.yield
import ua.acclorite.book_story.domain.browse.toBrowseFilesStructure import ua.acclorite.book_story.domain.browse.toBrowseFilesStructure
import ua.acclorite.book_story.domain.browse.toBrowseLayout import ua.acclorite.book_story.domain.browse.toBrowseLayout
import ua.acclorite.book_story.domain.browse.toBrowseSortOrder import ua.acclorite.book_story.domain.browse.toBrowseSortOrder
import ua.acclorite.book_story.domain.reader.toColorEffects
import ua.acclorite.book_story.domain.reader.toHorizontalGesture import ua.acclorite.book_story.domain.reader.toHorizontalGesture
import ua.acclorite.book_story.domain.reader.toImagesAlignment import ua.acclorite.book_story.domain.reader.toImagesAlignment
import ua.acclorite.book_story.domain.reader.toReaderScreenOrientation import ua.acclorite.book_story.domain.reader.toReaderScreenOrientation
@ -455,6 +456,14 @@ class MainModel @Inject constructor(
it.copy(imagesWidth = this.toFloat()) it.copy(imagesWidth = this.toFloat())
} }
) )
is MainEvent.OnChangeImagesColorEffects -> handleDatastoreUpdate(
key = DataStoreConstants.IMAGES_COLOR_EFFECTS,
value = event.value,
updateState = {
it.copy(imagesColorEffects = this.toColorEffects())
}
)
} }
} }

View file

@ -13,10 +13,12 @@ import ua.acclorite.book_story.domain.browse.BrowseSortOrder
import ua.acclorite.book_story.domain.browse.toBrowseFilesStructure import ua.acclorite.book_story.domain.browse.toBrowseFilesStructure
import ua.acclorite.book_story.domain.browse.toBrowseLayout import ua.acclorite.book_story.domain.browse.toBrowseLayout
import ua.acclorite.book_story.domain.browse.toBrowseSortOrder import ua.acclorite.book_story.domain.browse.toBrowseSortOrder
import ua.acclorite.book_story.domain.reader.ReaderColorEffects
import ua.acclorite.book_story.domain.reader.ReaderHorizontalGesture import ua.acclorite.book_story.domain.reader.ReaderHorizontalGesture
import ua.acclorite.book_story.domain.reader.ReaderImagesAlignment import ua.acclorite.book_story.domain.reader.ReaderImagesAlignment
import ua.acclorite.book_story.domain.reader.ReaderScreenOrientation import ua.acclorite.book_story.domain.reader.ReaderScreenOrientation
import ua.acclorite.book_story.domain.reader.ReaderTextAlignment import ua.acclorite.book_story.domain.reader.ReaderTextAlignment
import ua.acclorite.book_story.domain.reader.toColorEffects
import ua.acclorite.book_story.domain.reader.toHorizontalGesture import ua.acclorite.book_story.domain.reader.toHorizontalGesture
import ua.acclorite.book_story.domain.reader.toImagesAlignment import ua.acclorite.book_story.domain.reader.toImagesAlignment
import ua.acclorite.book_story.domain.reader.toReaderScreenOrientation import ua.acclorite.book_story.domain.reader.toReaderScreenOrientation
@ -99,6 +101,7 @@ data class MainState(
val imagesCornersRoundness: Int = provideDefaultValue { 8 }, val imagesCornersRoundness: Int = provideDefaultValue { 8 },
val imagesAlignment: ReaderImagesAlignment = provideDefaultValue { ReaderImagesAlignment.START }, val imagesAlignment: ReaderImagesAlignment = provideDefaultValue { ReaderImagesAlignment.START },
val imagesWidth: Float = provideDefaultValue { 0.8f }, val imagesWidth: Float = provideDefaultValue { 0.8f },
val imagesColorEffects: ReaderColorEffects = provideDefaultValue { ReaderColorEffects.OFF },
// Browse Settings // Browse Settings
val browseFilesStructure: BrowseFilesStructure = provideDefaultValue { val browseFilesStructure: BrowseFilesStructure = provideDefaultValue {
@ -332,6 +335,10 @@ data class MainState(
imagesWidth = provideValue( imagesWidth = provideValue(
IMAGES_WIDTH, convert = { toFloat() } IMAGES_WIDTH, convert = { toFloat() }
) { imagesWidth }, ) { imagesWidth },
imagesColorEffects = provideValue(
IMAGES_COLOR_EFFECTS, convert = { toColorEffects() }
) { imagesColorEffects },
) )
} }
} }

View file

@ -21,6 +21,9 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.ColorMatrix
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
@ -36,6 +39,7 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import ua.acclorite.book_story.domain.navigator.Screen import ua.acclorite.book_story.domain.navigator.Screen
import ua.acclorite.book_story.domain.reader.ReaderColorEffects
import ua.acclorite.book_story.domain.reader.ReaderTextAlignment import ua.acclorite.book_story.domain.reader.ReaderTextAlignment
import ua.acclorite.book_story.presentation.core.constants.Constants import ua.acclorite.book_story.presentation.core.constants.Constants
import ua.acclorite.book_story.presentation.core.constants.provideFonts import ua.acclorite.book_story.presentation.core.constants.provideFonts
@ -193,6 +197,29 @@ data class ReaderScreen(val bookId: Int) : Screen, Parcelable {
) { ) {
(mainState.value.imagesCornersRoundness * 3 * imagesWidth).dp (mainState.value.imagesCornersRoundness * 3 * imagesWidth).dp
} }
val imagesColorEffects = remember(
mainState.value.imagesColorEffects,
fontColor.value,
backgroundColor.value
) {
when (mainState.value.imagesColorEffects) {
ReaderColorEffects.OFF -> null
ReaderColorEffects.GRAYSCALE -> ColorFilter.colorMatrix(
ColorMatrix().apply { setToSaturation(0f) }
)
ReaderColorEffects.FONT -> ColorFilter.tint(
color = fontColor.value,
blendMode = BlendMode.Color
)
ReaderColorEffects.BACKGROUND -> ColorFilter.tint(
color = backgroundColor.value,
blendMode = BlendMode.Color
)
}
}
val layoutDirection = LocalLayoutDirection.current val layoutDirection = LocalLayoutDirection.current
val cutoutInsets = WindowInsets.displayCutout val cutoutInsets = WindowInsets.displayCutout
@ -350,6 +377,7 @@ data class ReaderScreen(val bookId: Int) : Screen, Parcelable {
imagesCornersRoundness = imagesCornersRoundness, imagesCornersRoundness = imagesCornersRoundness,
imagesAlignment = mainState.value.imagesAlignment, imagesAlignment = mainState.value.imagesAlignment,
imagesWidth = imagesWidth, imagesWidth = imagesWidth,
imagesColorEffects = imagesColorEffects,
fontFamily = fontFamily, fontFamily = fontFamily,
lineHeight = lineHeight, lineHeight = lineHeight,
fontStyle = fontStyle, fontStyle = fontStyle,

View file

@ -202,6 +202,7 @@
<string name="images_corners_roundness_option">Округлість кутків</string> <string name="images_corners_roundness_option">Округлість кутків</string>
<string name="images_alignment_option">Розташування</string> <string name="images_alignment_option">Розташування</string>
<string name="images_width_option">Розмір</string> <string name="images_width_option">Розмір</string>
<string name="images_color_effects_option">Ефекти кольору</string>
<!-- Browse --> <!-- Browse -->
<string name="browse_files_structure_option">Структура файлів</string> <string name="browse_files_structure_option">Структура файлів</string>
@ -275,6 +276,12 @@
<!-- Highlighted Reading properties --> <!-- Highlighted Reading properties -->
<string name="highlighted_reading_level">рівень</string> <string name="highlighted_reading_level">рівень</string>
<!-- Color Effects properties -->
<string name="color_effects_off">Вимкнені</string>
<string name="color_effects_grayscale">Відтінки сірого</string>
<string name="color_effects_font">Колір шрифта</string>
<string name="color_effects_background">Колір фона</string>
<!-- Themes --> <!-- Themes -->
<string name="dynamic_theme">Меркурій</string> <string name="dynamic_theme">Меркурій</string>
<string name="blue_theme">Нептун</string> <string name="blue_theme">Нептун</string>

View file

@ -257,6 +257,7 @@
<string name="images_corners_roundness_option">Corners roundness</string> <string name="images_corners_roundness_option">Corners roundness</string>
<string name="images_alignment_option">Alignment</string> <string name="images_alignment_option">Alignment</string>
<string name="images_width_option">Size</string> <string name="images_width_option">Size</string>
<string name="images_color_effects_option">Color effects</string>
<!-- Browse --> <!-- Browse -->
<string name="browse_files_structure_option">Files structure</string> <string name="browse_files_structure_option">Files structure</string>
@ -332,6 +333,12 @@
<!-- Highlighted Reading properties --> <!-- Highlighted Reading properties -->
<string name="highlighted_reading_level">level</string> <string name="highlighted_reading_level">level</string>
<!-- Color Effect properties -->
<string name="color_effects_off">Off</string>
<string name="color_effects_grayscale">Grayscale</string>
<string name="color_effects_font">Font color</string>
<string name="color_effects_background">Background color</string>
<!-- Themes --> <!-- Themes -->
<string name="dynamic_theme">Mercury</string> <string name="dynamic_theme">Mercury</string>
<string name="blue_theme">Neptune</string> <string name="blue_theme">Neptune</string>