refactor: settings viewmodel
This commit is contained in:
parent
2ab62e629f
commit
b0c567bdc9
13 changed files with 359 additions and 444 deletions
|
|
@ -10,7 +10,6 @@ import android.graphics.Bitmap
|
||||||
|
|
||||||
typealias CoverImage = Bitmap
|
typealias CoverImage = Bitmap
|
||||||
typealias Selected = Boolean
|
typealias Selected = Boolean
|
||||||
typealias ID = Int
|
|
||||||
typealias BottomSheet = String
|
typealias BottomSheet = String
|
||||||
typealias Dialog = String
|
typealias Dialog = String
|
||||||
typealias Drawer = String
|
typealias Drawer = String
|
||||||
|
|
@ -40,6 +40,7 @@ import ua.acclorite.book_story.ui.common.helpers.ProvideSettings
|
||||||
import ua.acclorite.book_story.ui.main.MainActivityKeyboardManager
|
import ua.acclorite.book_story.ui.main.MainActivityKeyboardManager
|
||||||
import ua.acclorite.book_story.ui.navigator.Navigator
|
import ua.acclorite.book_story.ui.navigator.Navigator
|
||||||
import ua.acclorite.book_story.ui.navigator.NavigatorTabs
|
import ua.acclorite.book_story.ui.navigator.NavigatorTabs
|
||||||
|
import ua.acclorite.book_story.ui.settings.SettingsEffects
|
||||||
import ua.acclorite.book_story.ui.theme.BookStoryTheme
|
import ua.acclorite.book_story.ui.theme.BookStoryTheme
|
||||||
import ua.acclorite.book_story.ui.theme.Transitions
|
import ua.acclorite.book_story.ui.theme.Transitions
|
||||||
import java.lang.reflect.Field
|
import java.lang.reflect.Field
|
||||||
|
|
@ -56,7 +57,7 @@ class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
installSplashScreen().setKeepOnScreenCondition {
|
installSplashScreen().setKeepOnScreenCondition {
|
||||||
!settings.initialized.value || !settingsModel.isReady.value
|
!settings.initialized.value || !settingsModel.initialized.value
|
||||||
}
|
}
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
@ -80,6 +81,10 @@ class MainActivity : AppCompatActivity() {
|
||||||
val historyModel = hiltViewModel<HistoryModel>()
|
val historyModel = hiltViewModel<HistoryModel>()
|
||||||
val browseModel = hiltViewModel<BrowseModel>()
|
val browseModel = hiltViewModel<BrowseModel>()
|
||||||
|
|
||||||
|
SettingsEffects(
|
||||||
|
effects = settingsModel.effects
|
||||||
|
)
|
||||||
|
|
||||||
ProvideSettings(settings) {
|
ProvideSettings(settings) {
|
||||||
val tabs = persistentListOf(
|
val tabs = persistentListOf(
|
||||||
NavigatorItem(
|
NavigatorItem(
|
||||||
|
|
|
||||||
|
|
@ -438,8 +438,7 @@ data class ReaderScreen(val bookId: Int) : Screen, Parcelable {
|
||||||
letterSpacing = letterSpacing,
|
letterSpacing = letterSpacing,
|
||||||
paragraphIndentation = paragraphIndentation,
|
paragraphIndentation = paragraphIndentation,
|
||||||
doubleClickTranslation = settings.doubleClickTranslation.value,
|
doubleClickTranslation = settings.doubleClickTranslation.value,
|
||||||
selectPreviousPreset = settingsModel::onEvent,
|
switchColorPreset = settingsModel::onEvent,
|
||||||
selectNextPreset = settingsModel::onEvent,
|
|
||||||
leave = screenModel::onEvent,
|
leave = screenModel::onEvent,
|
||||||
restoreCheckpoint = screenModel::onEvent,
|
restoreCheckpoint = screenModel::onEvent,
|
||||||
scroll = screenModel::onEvent,
|
scroll = screenModel::onEvent,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import ua.acclorite.book_story.domain.model.reader.ColorPreset
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
sealed class SettingsEffect {
|
||||||
|
data class OnScroll(
|
||||||
|
val listState: LazyListState,
|
||||||
|
val index: Int,
|
||||||
|
val offset: Int
|
||||||
|
) : SettingsEffect()
|
||||||
|
|
||||||
|
data class OnSwitchedColorPreset(
|
||||||
|
val newColorPreset: ColorPreset
|
||||||
|
) : SettingsEffect()
|
||||||
|
}
|
||||||
|
|
@ -6,11 +6,8 @@
|
||||||
|
|
||||||
package ua.acclorite.book_story.presentation.settings
|
package ua.acclorite.book_story.presentation.settings
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.net.Uri
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import ua.acclorite.book_story.core.ID
|
|
||||||
import ua.acclorite.book_story.core.language.Language
|
import ua.acclorite.book_story.core.language.Language
|
||||||
import ua.acclorite.book_story.domain.model.library.Category
|
import ua.acclorite.book_story.domain.model.library.Category
|
||||||
import ua.acclorite.book_story.presentation.library.model.LibrarySortOrder
|
import ua.acclorite.book_story.presentation.library.model.LibrarySortOrder
|
||||||
|
|
@ -22,11 +19,11 @@ sealed class SettingsEvent {
|
||||||
) : SettingsEvent()
|
) : SettingsEvent()
|
||||||
|
|
||||||
data class OnGrantPersistableUriPermission(
|
data class OnGrantPersistableUriPermission(
|
||||||
val uri: Uri
|
val uri: String
|
||||||
) : SettingsEvent()
|
) : SettingsEvent()
|
||||||
|
|
||||||
data class OnReleasePersistableUriPermission(
|
data class OnReleasePersistableUriPermission(
|
||||||
val uri: Uri
|
val uri: String
|
||||||
) : SettingsEvent()
|
) : SettingsEvent()
|
||||||
|
|
||||||
data class OnCreateCategory(
|
data class OnCreateCategory(
|
||||||
|
|
@ -53,28 +50,24 @@ sealed class SettingsEvent {
|
||||||
) : SettingsEvent()
|
) : SettingsEvent()
|
||||||
|
|
||||||
data class OnSelectColorPreset(
|
data class OnSelectColorPreset(
|
||||||
val id: ID
|
val id: Int,
|
||||||
) : SettingsEvent()
|
) : SettingsEvent()
|
||||||
|
|
||||||
data class OnSelectPreviousPreset(
|
data class OnSwitchColorPreset(
|
||||||
val context: Context
|
val previous: Boolean
|
||||||
) : SettingsEvent()
|
|
||||||
|
|
||||||
data class OnSelectNextPreset(
|
|
||||||
val context: Context
|
|
||||||
) : SettingsEvent()
|
) : SettingsEvent()
|
||||||
|
|
||||||
data class OnDeleteColorPreset(
|
data class OnDeleteColorPreset(
|
||||||
val id: ID
|
val id: Int
|
||||||
) : SettingsEvent()
|
) : SettingsEvent()
|
||||||
|
|
||||||
data class OnUpdateColorPresetTitle(
|
data class OnUpdateColorPresetTitle(
|
||||||
val id: ID,
|
val id: Int,
|
||||||
val title: String
|
val title: String
|
||||||
) : SettingsEvent()
|
) : SettingsEvent()
|
||||||
|
|
||||||
data class OnShuffleColorPreset(
|
data class OnShuffleColorPreset(
|
||||||
val id: ID
|
val id: Int
|
||||||
) : SettingsEvent()
|
) : SettingsEvent()
|
||||||
|
|
||||||
data class OnAddColorPreset(
|
data class OnAddColorPreset(
|
||||||
|
|
@ -82,20 +75,16 @@ sealed class SettingsEvent {
|
||||||
val fontColor: Color
|
val fontColor: Color
|
||||||
) : SettingsEvent()
|
) : SettingsEvent()
|
||||||
|
|
||||||
|
data class OnUpdateColorPresetColor(
|
||||||
|
val id: Int,
|
||||||
|
val backgroundColor: Color?,
|
||||||
|
val fontColor: Color?
|
||||||
|
) : SettingsEvent()
|
||||||
|
|
||||||
data class OnReorderColorPresets(
|
data class OnReorderColorPresets(
|
||||||
val from: Int,
|
val from: Int,
|
||||||
val to: Int
|
val to: Int
|
||||||
) : SettingsEvent()
|
) : SettingsEvent()
|
||||||
|
|
||||||
data class OnUpdateColorPresetColor(
|
|
||||||
val id: ID,
|
|
||||||
val backgroundColor: Color?,
|
|
||||||
val fontColor: Color?
|
|
||||||
) : SettingsEvent()
|
|
||||||
|
|
||||||
data object OnConfirmReorderColorPresets : SettingsEvent()
|
data object OnConfirmReorderColorPresets : SettingsEvent()
|
||||||
|
|
||||||
data class OnScrollToColorPreset(
|
|
||||||
val index: Int
|
|
||||||
) : SettingsEvent()
|
|
||||||
}
|
}
|
||||||
|
|
@ -6,20 +6,20 @@
|
||||||
|
|
||||||
package ua.acclorite.book_story.presentation.settings
|
package ua.acclorite.book_story.presentation.settings
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.ensureActive
|
||||||
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.asSharedFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.coroutines.yield
|
|
||||||
import ua.acclorite.book_story.R
|
|
||||||
import ua.acclorite.book_story.domain.model.library.CategorySort
|
import ua.acclorite.book_story.domain.model.library.CategorySort
|
||||||
import ua.acclorite.book_story.domain.model.reader.ColorPreset
|
import ua.acclorite.book_story.domain.model.reader.ColorPreset
|
||||||
import ua.acclorite.book_story.domain.use_case.category.AddCategoryUseCase
|
import ua.acclorite.book_story.domain.use_case.category.AddCategoryUseCase
|
||||||
|
|
@ -37,8 +37,8 @@ import ua.acclorite.book_story.domain.use_case.color_preset.UpdateColorPresetUse
|
||||||
import ua.acclorite.book_story.domain.use_case.permission.GrantPersistableUriPermissionUseCase
|
import ua.acclorite.book_story.domain.use_case.permission.GrantPersistableUriPermissionUseCase
|
||||||
import ua.acclorite.book_story.domain.use_case.permission.ReleasePersistableUriPermissionUseCase
|
import ua.acclorite.book_story.domain.use_case.permission.ReleasePersistableUriPermissionUseCase
|
||||||
import ua.acclorite.book_story.domain.use_case.settings.UpdateLanguageUseCase
|
import ua.acclorite.book_story.domain.use_case.settings.UpdateLanguageUseCase
|
||||||
import ua.acclorite.book_story.ui.common.helpers.showToast
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import kotlin.coroutines.coroutineContext
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
|
|
@ -65,75 +65,64 @@ class SettingsModel @Inject constructor(
|
||||||
private val _state = MutableStateFlow(SettingsState())
|
private val _state = MutableStateFlow(SettingsState())
|
||||||
val state = _state.asStateFlow()
|
val state = _state.asStateFlow()
|
||||||
|
|
||||||
private val _isReady = MutableStateFlow(false)
|
private val _effects = MutableSharedFlow<SettingsEffect>()
|
||||||
val isReady = _isReady.asStateFlow()
|
val effects = _effects.asSharedFlow()
|
||||||
|
|
||||||
private var selectColorPresetJob: Job? = null
|
private val _initialized = MutableStateFlow(false)
|
||||||
private var addColorPresetJob: Job? = null
|
val initialized = _initialized.asStateFlow()
|
||||||
private var deleteColorPresetJob: Job? = null
|
|
||||||
private var updateColorColorPresetJob: Job? = null
|
private var colorPresetJob: Job? = null
|
||||||
private var updateTitleColorPresetJob: Job? = null
|
|
||||||
private var shuffleColorPresetJob: Job? = null
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch {
|
||||||
var colorPresets = getColorPresetsUseCase()
|
var colorPresets = getColorPresetsUseCase()
|
||||||
|
|
||||||
if (colorPresets.isEmpty()) {
|
if (colorPresets.isEmpty()) {
|
||||||
updateColorPresetUseCase(ColorPreset.default)
|
updateColorPresetUseCase(ColorPreset.default)
|
||||||
getColorPresetsUseCase().first().select()
|
getColorPresetsUseCase().first().selectColorPreset()
|
||||||
colorPresets = getColorPresetsUseCase()
|
colorPresets = getColorPresetsUseCase()
|
||||||
}
|
}
|
||||||
|
|
||||||
val scrollIndex = colorPresets.indexOfFirst {
|
val scrollIndex = colorPresets.indexOfFirst { it.isSelected }
|
||||||
it.isSelected
|
|
||||||
}
|
|
||||||
if (scrollIndex != -1) {
|
if (scrollIndex != -1) {
|
||||||
launch(Dispatchers.Main) {
|
_effects.emit(
|
||||||
try {
|
SettingsEffect.OnScroll(
|
||||||
_state.value.colorPresetListState.requestScrollToItem(index = scrollIndex)
|
listState = _state.value.colorPresetListState,
|
||||||
} catch (e: Exception) {
|
index = scrollIndex,
|
||||||
e.printStackTrace()
|
offset = 0
|
||||||
}
|
)
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
_state.update {
|
_state.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
selectedColorPreset = colorPresets.selected(),
|
selectedColorPreset = colorPresets.getSelectedColorPreset(),
|
||||||
colorPresets = colorPresets,
|
colorPresets = colorPresets,
|
||||||
categories = getCategoriesUseCase(), // Getting categories
|
categories = getCategoriesUseCase(),
|
||||||
categoriesSort = getCategorySortingUseCase()
|
categoriesSort = getCategorySortingUseCase()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i("SETTINGS", "SettingsModel is ready.")
|
_initialized.update { true }
|
||||||
_isReady.update { true }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onEvent(event: SettingsEvent) {
|
fun onEvent(event: SettingsEvent) {
|
||||||
|
viewModelScope.launch {
|
||||||
when (event) {
|
when (event) {
|
||||||
is SettingsEvent.OnUpdateLanguage -> updateLanguageUseCase(event.language)
|
is SettingsEvent.OnUpdateLanguage -> {
|
||||||
|
updateLanguageUseCase(event.language)
|
||||||
|
}
|
||||||
|
|
||||||
is SettingsEvent.OnGrantPersistableUriPermission -> {
|
is SettingsEvent.OnGrantPersistableUriPermission -> {
|
||||||
viewModelScope.launch {
|
grantPersistableUriPermissionUseCase(event.uri)
|
||||||
grantPersistableUriPermissionUseCase(
|
|
||||||
event.uri.toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is SettingsEvent.OnReleasePersistableUriPermission -> {
|
is SettingsEvent.OnReleasePersistableUriPermission -> {
|
||||||
viewModelScope.launch {
|
releasePersistableUriPermissionUseCase(event.uri)
|
||||||
releasePersistableUriPermissionUseCase(
|
|
||||||
event.uri.toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is SettingsEvent.OnCreateCategory -> {
|
is SettingsEvent.OnCreateCategory -> {
|
||||||
viewModelScope.launch {
|
|
||||||
addCategoryUseCase(event.title)
|
addCategoryUseCase(event.title)
|
||||||
_state.update {
|
_state.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
|
|
@ -141,10 +130,8 @@ class SettingsModel @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
is SettingsEvent.OnUpdateCategoryTitle -> {
|
is SettingsEvent.OnUpdateCategoryTitle -> {
|
||||||
viewModelScope.launch {
|
|
||||||
updateCategoryUseCase(
|
updateCategoryUseCase(
|
||||||
categoryId = event.id,
|
categoryId = event.id,
|
||||||
newTitle = event.title
|
newTitle = event.title
|
||||||
|
|
@ -155,10 +142,8 @@ class SettingsModel @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
is SettingsEvent.OnUpdateCategoryOrder -> {
|
is SettingsEvent.OnUpdateCategoryOrder -> {
|
||||||
viewModelScope.launch {
|
|
||||||
updateCategoriesOrderUseCase(
|
updateCategoriesOrderUseCase(
|
||||||
categories = event.categories
|
categories = event.categories
|
||||||
)
|
)
|
||||||
|
|
@ -168,10 +153,8 @@ class SettingsModel @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
is SettingsEvent.OnRemoveCategory -> {
|
is SettingsEvent.OnRemoveCategory -> {
|
||||||
viewModelScope.launch {
|
|
||||||
deleteCategoryUseCase(
|
deleteCategoryUseCase(
|
||||||
category = event.category
|
category = event.category
|
||||||
)
|
)
|
||||||
|
|
@ -181,10 +164,8 @@ class SettingsModel @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
is SettingsEvent.OnUpdateCategorySort -> {
|
is SettingsEvent.OnUpdateCategorySort -> {
|
||||||
viewModelScope.launch {
|
|
||||||
updateCategorySortingUseCase(
|
updateCategorySortingUseCase(
|
||||||
categorySort = CategorySort(
|
categorySort = CategorySort(
|
||||||
categoryId = event.categoryId,
|
categoryId = event.categoryId,
|
||||||
|
|
@ -198,24 +179,23 @@ class SettingsModel @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
is SettingsEvent.OnSelectColorPreset -> {
|
is SettingsEvent.OnSelectColorPreset -> {
|
||||||
viewModelScope.launch {
|
withContext(Dispatchers.IO) {
|
||||||
cancelColorPresetJobs()
|
colorPresetJob?.join()
|
||||||
selectColorPresetJob = launch {
|
colorPresetJob = viewModelScope.launch(Dispatchers.Default) {
|
||||||
val colorPreset = _state.value.colorPresets.getColorPresetById(event.id)
|
val colorPreset = _state.value.colorPresets.getColorPresetById(event.id)
|
||||||
?: return@launch
|
?: return@launch
|
||||||
|
|
||||||
yield()
|
ensureActive()
|
||||||
|
|
||||||
colorPreset.select(animate = true)
|
colorPreset.selectColorPreset(animate = true)
|
||||||
val colorPresets = _state.value.colorPresets.map {
|
val colorPresets = _state.value.colorPresets.map {
|
||||||
it.copy(isSelected = colorPreset.id == it.id)
|
it.copy(isSelected = colorPreset.id == it.id)
|
||||||
}
|
}
|
||||||
_state.update {
|
_state.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
selectedColorPreset = colorPresets.selected(),
|
selectedColorPreset = colorPresets.getSelectedColorPreset(),
|
||||||
colorPresets = colorPresets
|
colorPresets = colorPresets
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -223,162 +203,88 @@ class SettingsModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is SettingsEvent.OnSelectPreviousPreset -> {
|
is SettingsEvent.OnSwitchColorPreset -> {
|
||||||
viewModelScope.launch {
|
withContext(Dispatchers.IO) {
|
||||||
cancelColorPresetJobs()
|
colorPresetJob?.join()
|
||||||
selectColorPresetJob = launch {
|
colorPresetJob = viewModelScope.launch(Dispatchers.Default) {
|
||||||
val colorPresets = _state.value.colorPresets
|
val colorPresets = _state.value.colorPresets
|
||||||
|
if (colorPresets.size == 1) return@launch
|
||||||
|
|
||||||
val selectedPreset = _state.value.selectedColorPreset
|
val selectedPreset = _state.value.selectedColorPreset
|
||||||
|
|
||||||
if (colorPresets.size == 1) {
|
|
||||||
return@launch
|
|
||||||
}
|
|
||||||
|
|
||||||
val selectedPresetIndex = colorPresets.indexOf(selectedPreset)
|
val selectedPresetIndex = colorPresets.indexOf(selectedPreset)
|
||||||
if (selectedPresetIndex == -1) {
|
if (selectedPresetIndex == -1) return@launch
|
||||||
return@launch
|
|
||||||
}
|
|
||||||
|
|
||||||
val previousColorPresetIndex = when (selectedPresetIndex) {
|
val newColorPresetIndex = if (event.previous) {
|
||||||
0 -> {
|
when (selectedPresetIndex) {
|
||||||
colorPresets.lastIndex
|
0 -> colorPresets.lastIndex
|
||||||
|
else -> selectedPresetIndex - 1
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
else -> {
|
when (selectedPresetIndex) {
|
||||||
selectedPresetIndex - 1
|
colorPresets.lastIndex -> 0
|
||||||
|
else -> selectedPresetIndex + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val previousColorPreset = colorPresets.getOrNull(previousColorPresetIndex)
|
val newColorPreset = colorPresets.getOrNull(newColorPresetIndex)
|
||||||
?: return@launch
|
?: return@launch
|
||||||
|
|
||||||
yield()
|
ensureActive()
|
||||||
|
|
||||||
previousColorPreset.select()
|
newColorPreset.selectColorPreset()
|
||||||
val updatedColorPresets = _state.value.colorPresets.map {
|
val updatedColorPresets = _state.value.colorPresets.map {
|
||||||
it.copy(isSelected = previousColorPreset.id == it.id)
|
it.copy(isSelected = newColorPreset.id == it.id)
|
||||||
}
|
}
|
||||||
_state.update {
|
_state.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
selectedColorPreset = updatedColorPresets.selected(),
|
selectedColorPreset = updatedColorPresets.getSelectedColorPreset(),
|
||||||
colorPresets = updatedColorPresets
|
colorPresets = updatedColorPresets
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
_effects.emit(SettingsEffect.OnSwitchedColorPreset(newColorPreset))
|
||||||
event.context.getString(
|
|
||||||
R.string.color_preset_selected_query,
|
|
||||||
if (previousColorPreset.name.isNullOrBlank()) {
|
|
||||||
event.context.getString(
|
|
||||||
R.string.color_preset_query,
|
|
||||||
previousColorPreset.id.toString()
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
previousColorPreset.name
|
|
||||||
}.trim()
|
|
||||||
).showToast(event.context, longToast = false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
is SettingsEvent.OnSelectNextPreset -> {
|
|
||||||
viewModelScope.launch {
|
|
||||||
cancelColorPresetJobs()
|
|
||||||
selectColorPresetJob = launch {
|
|
||||||
val colorPresets = _state.value.colorPresets
|
|
||||||
val selectedPreset = _state.value.selectedColorPreset
|
|
||||||
|
|
||||||
if (colorPresets.size == 1) {
|
|
||||||
return@launch
|
|
||||||
}
|
|
||||||
|
|
||||||
val selectedPresetIndex = colorPresets.indexOf(selectedPreset)
|
|
||||||
if (selectedPresetIndex == -1) {
|
|
||||||
return@launch
|
|
||||||
}
|
|
||||||
|
|
||||||
val nextColorPresetIndex = when (selectedPresetIndex) {
|
|
||||||
colorPresets.lastIndex -> {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
selectedPresetIndex + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val nextColorPreset = colorPresets.getOrNull(nextColorPresetIndex)
|
|
||||||
?: return@launch
|
|
||||||
|
|
||||||
yield()
|
|
||||||
|
|
||||||
nextColorPreset.select()
|
|
||||||
val updatedColorPresets = _state.value.colorPresets.map {
|
|
||||||
it.copy(isSelected = nextColorPreset.id == it.id)
|
|
||||||
}
|
|
||||||
_state.update {
|
|
||||||
it.copy(
|
|
||||||
selectedColorPreset = updatedColorPresets.selected(),
|
|
||||||
colorPresets = updatedColorPresets
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
event.context.getString(
|
|
||||||
R.string.color_preset_selected_query,
|
|
||||||
if (nextColorPreset.name.isNullOrBlank()) {
|
|
||||||
event.context.getString(
|
|
||||||
R.string.color_preset_query,
|
|
||||||
nextColorPreset.id.toString()
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
nextColorPreset.name
|
|
||||||
}.trim()
|
|
||||||
).showToast(event.context, longToast = false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is SettingsEvent.OnDeleteColorPreset -> {
|
is SettingsEvent.OnDeleteColorPreset -> {
|
||||||
viewModelScope.launch {
|
withContext(Dispatchers.IO) {
|
||||||
cancelColorPresetJobs()
|
colorPresetJob?.join()
|
||||||
deleteColorPresetJob = launch {
|
colorPresetJob = viewModelScope.launch(Dispatchers.Default) {
|
||||||
if (_state.value.colorPresets.size == 1) return@launch
|
if (_state.value.colorPresets.size == 1) return@launch
|
||||||
val colorPreset = _state.value.colorPresets.getColorPresetById(event.id)
|
val colorPreset = _state.value.colorPresets.getColorPresetById(event.id)
|
||||||
?: return@launch
|
?: return@launch
|
||||||
|
|
||||||
yield()
|
|
||||||
|
|
||||||
val position = _state.value.colorPresets.indexOf(colorPreset)
|
val position = _state.value.colorPresets.indexOf(colorPreset)
|
||||||
if (position == -1) {
|
if (position == -1) return@launch
|
||||||
return@launch
|
|
||||||
}
|
|
||||||
|
|
||||||
val nextPosition = if (position == _state.value.colorPresets.lastIndex) {
|
val nextPosition =
|
||||||
|
if (position == _state.value.colorPresets.lastIndex) {
|
||||||
position - 1
|
position - 1
|
||||||
} else {
|
} else {
|
||||||
position
|
position
|
||||||
}
|
}
|
||||||
|
|
||||||
yield()
|
ensureActive()
|
||||||
|
|
||||||
deleteColorPresetUseCase(colorPreset)
|
deleteColorPresetUseCase(colorPreset)
|
||||||
val nextColorPreset = getColorPresetsUseCase().getOrNull(nextPosition)
|
val nextColorPreset = getColorPresetsUseCase().getOrNull(nextPosition)
|
||||||
?: return@launch
|
?: return@launch
|
||||||
|
|
||||||
nextColorPreset.select()
|
nextColorPreset.selectColorPreset()
|
||||||
val colorPresets = getColorPresetsUseCase()
|
val colorPresets = getColorPresetsUseCase()
|
||||||
|
|
||||||
_state.update {
|
_state.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
selectedColorPreset = colorPresets.selected(),
|
selectedColorPreset = colorPresets.getSelectedColorPreset(),
|
||||||
colorPresets = colorPresets
|
colorPresets = colorPresets
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
onEvent(
|
_effects.emit(
|
||||||
SettingsEvent.OnScrollToColorPreset(
|
SettingsEffect.OnScroll(
|
||||||
index = nextPosition
|
listState = _state.value.colorPresetListState,
|
||||||
|
index = nextPosition,
|
||||||
|
offset = 0
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -386,19 +292,14 @@ class SettingsModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
is SettingsEvent.OnUpdateColorPresetTitle -> {
|
is SettingsEvent.OnUpdateColorPresetTitle -> {
|
||||||
viewModelScope.launch {
|
withContext(Dispatchers.IO) {
|
||||||
cancelColorPresetJobs()
|
colorPresetJob?.join()
|
||||||
updateTitleColorPresetJob = launch {
|
colorPresetJob = viewModelScope.launch(Dispatchers.Default) {
|
||||||
val colorPreset = _state.value.colorPresets.getColorPresetById(event.id)
|
val colorPreset = _state.value.colorPresets.getColorPresetById(event.id)
|
||||||
?: return@launch
|
?: return@launch
|
||||||
|
val updatedColorPreset = colorPreset.copy(name = event.title)
|
||||||
|
|
||||||
yield()
|
ensureActive()
|
||||||
|
|
||||||
val updatedColorPreset = colorPreset.copy(
|
|
||||||
name = event.title
|
|
||||||
)
|
|
||||||
|
|
||||||
yield()
|
|
||||||
|
|
||||||
updateColorPresetUseCase(updatedColorPreset)
|
updateColorPresetUseCase(updatedColorPreset)
|
||||||
_state.update {
|
_state.update {
|
||||||
|
|
@ -414,14 +315,11 @@ class SettingsModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
is SettingsEvent.OnShuffleColorPreset -> {
|
is SettingsEvent.OnShuffleColorPreset -> {
|
||||||
viewModelScope.launch {
|
withContext(Dispatchers.IO) {
|
||||||
cancelColorPresetJobs()
|
colorPresetJob?.join()
|
||||||
shuffleColorPresetJob = launch {
|
colorPresetJob = viewModelScope.launch(Dispatchers.Default) {
|
||||||
val colorPreset = _state.value.colorPresets.getColorPresetById(event.id)
|
val colorPreset = _state.value.colorPresets.getColorPresetById(event.id)
|
||||||
?: return@launch
|
?: return@launch
|
||||||
|
|
||||||
yield()
|
|
||||||
|
|
||||||
val shuffledColorPreset = colorPreset.copy(
|
val shuffledColorPreset = colorPreset.copy(
|
||||||
backgroundColor = colorPreset.backgroundColor.copy(
|
backgroundColor = colorPreset.backgroundColor.copy(
|
||||||
red = Random.nextFloat(),
|
red = Random.nextFloat(),
|
||||||
|
|
@ -435,7 +333,7 @@ class SettingsModel @Inject constructor(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
yield()
|
ensureActive()
|
||||||
|
|
||||||
updateColorPresetUseCase(shuffledColorPreset)
|
updateColorPresetUseCase(shuffledColorPreset)
|
||||||
_state.update {
|
_state.update {
|
||||||
|
|
@ -451,41 +349,44 @@ class SettingsModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
is SettingsEvent.OnAddColorPreset -> {
|
is SettingsEvent.OnAddColorPreset -> {
|
||||||
viewModelScope.launch {
|
withContext(Dispatchers.IO) {
|
||||||
cancelColorPresetJobs()
|
colorPresetJob?.join()
|
||||||
addColorPresetJob = launch {
|
colorPresetJob = viewModelScope.launch(Dispatchers.Default) {
|
||||||
yield()
|
|
||||||
|
|
||||||
val newColorPreset = ColorPreset.default.copy(
|
val newColorPreset = ColorPreset.default.copy(
|
||||||
backgroundColor = event.backgroundColor,
|
backgroundColor = event.backgroundColor,
|
||||||
fontColor = event.fontColor
|
fontColor = event.fontColor
|
||||||
)
|
)
|
||||||
updateColorPresetUseCase(newColorPreset)
|
|
||||||
|
|
||||||
getColorPresetsUseCase().last().select()
|
ensureActive()
|
||||||
|
|
||||||
|
updateColorPresetUseCase(newColorPreset)
|
||||||
|
getColorPresetsUseCase().last().selectColorPreset()
|
||||||
val colorPresets = getColorPresetsUseCase()
|
val colorPresets = getColorPresetsUseCase()
|
||||||
|
|
||||||
_state.update {
|
_state.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
selectedColorPreset = colorPresets.selected(),
|
selectedColorPreset = colorPresets.getSelectedColorPreset(),
|
||||||
colorPresets = colorPresets
|
colorPresets = colorPresets
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
onEvent(SettingsEvent.OnScrollToColorPreset(colorPresets.lastIndex))
|
_effects.emit(
|
||||||
|
SettingsEffect.OnScroll(
|
||||||
|
listState = _state.value.colorPresetListState,
|
||||||
|
index = colorPresets.lastIndex,
|
||||||
|
offset = 0
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is SettingsEvent.OnUpdateColorPresetColor -> {
|
is SettingsEvent.OnUpdateColorPresetColor -> {
|
||||||
viewModelScope.launch {
|
withContext(Dispatchers.IO) {
|
||||||
cancelColorPresetJobs()
|
colorPresetJob?.join()
|
||||||
updateColorColorPresetJob = launch {
|
colorPresetJob = viewModelScope.launch(Dispatchers.Default) {
|
||||||
val colorPreset = _state.value.colorPresets.getColorPresetById(event.id)
|
val colorPreset = _state.value.colorPresets.getColorPresetById(event.id)
|
||||||
?: return@launch
|
?: return@launch
|
||||||
|
|
||||||
yield()
|
|
||||||
|
|
||||||
val updatedColorPreset = colorPreset.copy(
|
val updatedColorPreset = colorPreset.copy(
|
||||||
backgroundColor = event.backgroundColor
|
backgroundColor = event.backgroundColor
|
||||||
?: colorPreset.backgroundColor,
|
?: colorPreset.backgroundColor,
|
||||||
|
|
@ -493,7 +394,7 @@ class SettingsModel @Inject constructor(
|
||||||
?: colorPreset.fontColor
|
?: colorPreset.fontColor
|
||||||
)
|
)
|
||||||
|
|
||||||
yield()
|
ensureActive()
|
||||||
|
|
||||||
updateColorPresetUseCase(updatedColorPreset)
|
updateColorPresetUseCase(updatedColorPreset)
|
||||||
_state.update {
|
_state.update {
|
||||||
|
|
@ -509,13 +410,13 @@ class SettingsModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
is SettingsEvent.OnReorderColorPresets -> {
|
is SettingsEvent.OnReorderColorPresets -> {
|
||||||
viewModelScope.launch {
|
withContext(Dispatchers.IO) {
|
||||||
cancelColorPresetJobs()
|
colorPresetJob?.join()
|
||||||
launch {
|
withContext(Dispatchers.Default) {
|
||||||
val reorderedColorPresets = _state.value.colorPresets
|
val reorderedColorPresets = _state.value.colorPresets
|
||||||
.toMutableList()
|
.toMutableList()
|
||||||
.apply {
|
.also { colorPresets ->
|
||||||
add(event.to, removeAt(event.from))
|
colorPresets.add(event.to, colorPresets.removeAt(event.from))
|
||||||
}
|
}
|
||||||
|
|
||||||
_state.update {
|
_state.update {
|
||||||
|
|
@ -528,29 +429,18 @@ class SettingsModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
is SettingsEvent.OnConfirmReorderColorPresets -> {
|
is SettingsEvent.OnConfirmReorderColorPresets -> {
|
||||||
viewModelScope.launch {
|
withContext(Dispatchers.IO) {
|
||||||
cancelColorPresetJobs()
|
colorPresetJob?.join()
|
||||||
launch {
|
withContext(Dispatchers.Default) {
|
||||||
reorderColorPresetsUseCase(_state.value.colorPresets)
|
reorderColorPresetsUseCase(_state.value.colorPresets)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is SettingsEvent.OnScrollToColorPreset -> {
|
|
||||||
viewModelScope.launch {
|
|
||||||
try {
|
|
||||||
_state.value.colorPresetListState.requestScrollToItem(
|
|
||||||
index = event.index
|
|
||||||
)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun ColorPreset.select(animate: Boolean = false) {
|
private suspend fun ColorPreset.selectColorPreset(animate: Boolean = false) {
|
||||||
selectColorPresetUseCase(this)
|
selectColorPresetUseCase(this)
|
||||||
_state.update {
|
_state.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
|
|
@ -560,53 +450,28 @@ class SettingsModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun List<ColorPreset>.getColorPresetById(id: Int): ColorPreset? {
|
private fun List<ColorPreset>.getColorPresetById(id: Int): ColorPreset? {
|
||||||
return firstOrNull {
|
return find {
|
||||||
it.id == id
|
it.id == id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun List<ColorPreset>?.selected(): ColorPreset {
|
private fun List<ColorPreset>.getSelectedColorPreset(): ColorPreset {
|
||||||
val presets = this ?: _state.value.colorPresets
|
if (size == 1) return first()
|
||||||
|
find { it.isSelected }?.also { return it }
|
||||||
if (presets.size == 1) {
|
|
||||||
return presets.first()
|
|
||||||
}
|
|
||||||
|
|
||||||
val selectedPreset = presets.firstOrNull { it.isSelected }
|
|
||||||
|
|
||||||
if (selectedPreset == null) {
|
|
||||||
return ColorPreset.default
|
return ColorPreset.default
|
||||||
}
|
}
|
||||||
|
|
||||||
return selectedPreset
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun List<ColorPreset>.updateColorPreset(colorPreset: ColorPreset): List<ColorPreset> {
|
private fun List<ColorPreset>.updateColorPreset(colorPreset: ColorPreset): List<ColorPreset> {
|
||||||
if (size == 1) {
|
if (size == 1) return listOf(colorPreset)
|
||||||
return listOf(colorPreset)
|
return map {
|
||||||
|
if (it.isSelected) colorPreset
|
||||||
|
else it
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.map {
|
|
||||||
if (it.isSelected) {
|
|
||||||
colorPreset
|
|
||||||
} else {
|
|
||||||
it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun cancelColorPresetJobs() {
|
|
||||||
selectColorPresetJob?.cancel()
|
|
||||||
addColorPresetJob?.cancel()
|
|
||||||
updateTitleColorPresetJob?.cancel()
|
|
||||||
shuffleColorPresetJob?.cancel()
|
|
||||||
updateColorColorPresetJob?.cancel()
|
|
||||||
deleteColorPresetJob?.cancel()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend inline fun <T> MutableStateFlow<T>.update(function: (T) -> T) {
|
private suspend inline fun <T> MutableStateFlow<T>.update(function: (T) -> T) {
|
||||||
mutex.withLock {
|
mutex.withLock {
|
||||||
yield()
|
coroutineContext.ensureActive()
|
||||||
this.value = function(this.value)
|
this.value = function(this.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,11 +28,10 @@ import androidx.compose.runtime.Composable
|
||||||
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.lerp
|
import androidx.compose.ui.graphics.lerp
|
||||||
import ua.acclorite.book_story.core.ID
|
|
||||||
import ua.acclorite.book_story.ui.common.components.common.AnimatedVisibility
|
import ua.acclorite.book_story.ui.common.components.common.AnimatedVisibility
|
||||||
|
|
||||||
data class TopAppBarData(
|
data class TopAppBarData(
|
||||||
val contentID: ID,
|
val contentID: Int,
|
||||||
val contentNavigationIcon: @Composable () -> Unit,
|
val contentNavigationIcon: @Composable () -> Unit,
|
||||||
val contentTitle: @Composable () -> Unit,
|
val contentTitle: @Composable () -> Unit,
|
||||||
val contentActions: @Composable RowScope.() -> Unit
|
val contentActions: @Composable RowScope.() -> Unit
|
||||||
|
|
@ -46,7 +45,7 @@ data class TopAppBarData(
|
||||||
* @param scrolledContainerColor Scrolled container color of the TopBar.
|
* @param scrolledContainerColor Scrolled container color of the TopBar.
|
||||||
* @param scrollBehavior [TopAppBarScrollBehavior].
|
* @param scrollBehavior [TopAppBarScrollBehavior].
|
||||||
* @param isTopBarScrolled Whether isScrolled state should be forced or not.
|
* @param isTopBarScrolled Whether isScrolled state should be forced or not.
|
||||||
* @param shownTopBar [ID] of the top bar to show.
|
* @param shownTopBar ID of the top bar to show.
|
||||||
* @param topBars Pass a list of all [TopAppBarData] to show.
|
* @param topBars Pass a list of all [TopAppBarData] to show.
|
||||||
* @param customContent Custom content below [TopAppBar].
|
* @param customContent Custom content below [TopAppBar].
|
||||||
*/
|
*/
|
||||||
|
|
@ -59,7 +58,7 @@ fun TopAppBar(
|
||||||
scrollBehavior: TopAppBarScrollBehavior?,
|
scrollBehavior: TopAppBarScrollBehavior?,
|
||||||
isTopBarScrolled: Boolean?,
|
isTopBarScrolled: Boolean?,
|
||||||
|
|
||||||
shownTopBar: ID,
|
shownTopBar: Int,
|
||||||
topBars: List<TopAppBarData>,
|
topBars: List<TopAppBarData>,
|
||||||
customContent: @Composable ColumnScope.() -> Unit = {}
|
customContent: @Composable ColumnScope.() -> Unit = {}
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -12,17 +12,14 @@ import androidx.compose.runtime.mutableFloatStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.input.pointer.pointerInput
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import ua.acclorite.book_story.presentation.settings.SettingsEvent
|
import ua.acclorite.book_story.presentation.settings.SettingsEvent
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Modifier.readerColorPresetChange(
|
fun Modifier.readerColorPresetChange(
|
||||||
colorPresetChangeEnabled: Boolean,
|
colorPresetChangeEnabled: Boolean,
|
||||||
isLoading: Boolean,
|
isLoading: Boolean,
|
||||||
selectPreviousPreset: (SettingsEvent.OnSelectPreviousPreset) -> Unit,
|
switchColorPreset: (SettingsEvent.OnSwitchColorPreset) -> Unit
|
||||||
selectNextPreset: (SettingsEvent.OnSelectNextPreset) -> Unit
|
|
||||||
): Modifier {
|
): Modifier {
|
||||||
val context = LocalContext.current
|
|
||||||
val offset = remember { mutableFloatStateOf(0f) }
|
val offset = remember { mutableFloatStateOf(0f) }
|
||||||
return this.then(
|
return this.then(
|
||||||
if (colorPresetChangeEnabled && !isLoading) {
|
if (colorPresetChangeEnabled && !isLoading) {
|
||||||
|
|
@ -33,17 +30,17 @@ fun Modifier.readerColorPresetChange(
|
||||||
onDragEnd = {
|
onDragEnd = {
|
||||||
when {
|
when {
|
||||||
offset.floatValue > 200 -> {
|
offset.floatValue > 200 -> {
|
||||||
selectPreviousPreset(
|
switchColorPreset(
|
||||||
SettingsEvent.OnSelectPreviousPreset(
|
SettingsEvent.OnSwitchColorPreset(
|
||||||
context = context
|
previous = true
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
offset.floatValue < -200 -> {
|
offset.floatValue < -200 -> {
|
||||||
selectNextPreset(
|
switchColorPreset(
|
||||||
SettingsEvent.OnSelectNextPreset(
|
SettingsEvent.OnSwitchColorPreset(
|
||||||
context = context
|
previous = false
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,8 +88,7 @@ fun ReaderContent(
|
||||||
letterSpacing: TextUnit,
|
letterSpacing: TextUnit,
|
||||||
paragraphIndentation: TextUnit,
|
paragraphIndentation: TextUnit,
|
||||||
doubleClickTranslation: Boolean,
|
doubleClickTranslation: Boolean,
|
||||||
selectPreviousPreset: (SettingsEvent.OnSelectPreviousPreset) -> Unit,
|
switchColorPreset: (SettingsEvent.OnSwitchColorPreset) -> Unit,
|
||||||
selectNextPreset: (SettingsEvent.OnSelectNextPreset) -> Unit,
|
|
||||||
menuVisibility: (ReaderEvent.OnMenuVisibility) -> Unit,
|
menuVisibility: (ReaderEvent.OnMenuVisibility) -> Unit,
|
||||||
leave: (ReaderEvent.OnLeave) -> Unit,
|
leave: (ReaderEvent.OnLeave) -> Unit,
|
||||||
restoreCheckpoint: (ReaderEvent.OnRestoreCheckpoint) -> Unit,
|
restoreCheckpoint: (ReaderEvent.OnRestoreCheckpoint) -> Unit,
|
||||||
|
|
@ -165,8 +164,7 @@ fun ReaderContent(
|
||||||
letterSpacing = letterSpacing,
|
letterSpacing = letterSpacing,
|
||||||
paragraphIndentation = paragraphIndentation,
|
paragraphIndentation = paragraphIndentation,
|
||||||
doubleClickTranslation = doubleClickTranslation,
|
doubleClickTranslation = doubleClickTranslation,
|
||||||
selectPreviousPreset = selectPreviousPreset,
|
switchColorPreset = switchColorPreset,
|
||||||
selectNextPreset = selectNextPreset,
|
|
||||||
menuVisibility = menuVisibility,
|
menuVisibility = menuVisibility,
|
||||||
leave = leave,
|
leave = leave,
|
||||||
restoreCheckpoint = restoreCheckpoint,
|
restoreCheckpoint = restoreCheckpoint,
|
||||||
|
|
|
||||||
|
|
@ -92,8 +92,7 @@ fun ReaderScaffold(
|
||||||
letterSpacing: TextUnit,
|
letterSpacing: TextUnit,
|
||||||
paragraphIndentation: TextUnit,
|
paragraphIndentation: TextUnit,
|
||||||
doubleClickTranslation: Boolean,
|
doubleClickTranslation: Boolean,
|
||||||
selectPreviousPreset: (SettingsEvent.OnSelectPreviousPreset) -> Unit,
|
switchColorPreset: (SettingsEvent.OnSwitchColorPreset) -> Unit,
|
||||||
selectNextPreset: (SettingsEvent.OnSelectNextPreset) -> Unit,
|
|
||||||
menuVisibility: (ReaderEvent.OnMenuVisibility) -> Unit,
|
menuVisibility: (ReaderEvent.OnMenuVisibility) -> Unit,
|
||||||
leave: (ReaderEvent.OnLeave) -> Unit,
|
leave: (ReaderEvent.OnLeave) -> Unit,
|
||||||
restoreCheckpoint: (ReaderEvent.OnRestoreCheckpoint) -> Unit,
|
restoreCheckpoint: (ReaderEvent.OnRestoreCheckpoint) -> Unit,
|
||||||
|
|
@ -127,8 +126,7 @@ fun ReaderScaffold(
|
||||||
isLoading = isLoading,
|
isLoading = isLoading,
|
||||||
lockMenu = lockMenu,
|
lockMenu = lockMenu,
|
||||||
leave = leave,
|
leave = leave,
|
||||||
selectPreviousPreset = selectPreviousPreset,
|
switchColorPreset = switchColorPreset,
|
||||||
selectNextPreset = selectNextPreset,
|
|
||||||
showSettingsBottomSheet = showSettingsBottomSheet,
|
showSettingsBottomSheet = showSettingsBottomSheet,
|
||||||
showChaptersDrawer = showChaptersDrawer,
|
showChaptersDrawer = showChaptersDrawer,
|
||||||
navigateBack = navigateBack,
|
navigateBack = navigateBack,
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,7 @@ fun ReaderTopBar(
|
||||||
isLoading: Boolean,
|
isLoading: Boolean,
|
||||||
lockMenu: Boolean,
|
lockMenu: Boolean,
|
||||||
leave: (ReaderEvent.OnLeave) -> Unit,
|
leave: (ReaderEvent.OnLeave) -> Unit,
|
||||||
selectPreviousPreset: (SettingsEvent.OnSelectPreviousPreset) -> Unit,
|
switchColorPreset: (SettingsEvent.OnSwitchColorPreset) -> Unit,
|
||||||
selectNextPreset: (SettingsEvent.OnSelectNextPreset) -> Unit,
|
|
||||||
showSettingsBottomSheet: (ReaderEvent.OnShowSettingsBottomSheet) -> Unit,
|
showSettingsBottomSheet: (ReaderEvent.OnShowSettingsBottomSheet) -> Unit,
|
||||||
showChaptersDrawer: (ReaderEvent.OnShowChaptersDrawer) -> Unit,
|
showChaptersDrawer: (ReaderEvent.OnShowChaptersDrawer) -> Unit,
|
||||||
navigateToBookInfo: (ReaderEvent.OnNavigateToBookInfo) -> Unit,
|
navigateToBookInfo: (ReaderEvent.OnNavigateToBookInfo) -> Unit,
|
||||||
|
|
@ -68,8 +67,7 @@ fun ReaderTopBar(
|
||||||
.readerColorPresetChange(
|
.readerColorPresetChange(
|
||||||
colorPresetChangeEnabled = fastColorPresetChange,
|
colorPresetChangeEnabled = fastColorPresetChange,
|
||||||
isLoading = isLoading,
|
isLoading = isLoading,
|
||||||
selectPreviousPreset = selectPreviousPreset,
|
switchColorPreset = switchColorPreset
|
||||||
selectNextPreset = selectNextPreset
|
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* 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.ui.settings
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
|
import ua.acclorite.book_story.R
|
||||||
|
import ua.acclorite.book_story.presentation.settings.SettingsEffect
|
||||||
|
import ua.acclorite.book_story.ui.common.helpers.showToast
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SettingsEffects(effects: SharedFlow<SettingsEffect>) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
LaunchedEffect(effects) {
|
||||||
|
effects.collect { effect ->
|
||||||
|
when (effect) {
|
||||||
|
is SettingsEffect.OnScroll -> {
|
||||||
|
effect.listState.requestScrollToItem(effect.index, effect.offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
is SettingsEffect.OnSwitchedColorPreset -> {
|
||||||
|
context.getString(
|
||||||
|
R.string.color_preset_selected_query,
|
||||||
|
if (effect.newColorPreset.name.isNullOrBlank()) {
|
||||||
|
context.getString(
|
||||||
|
R.string.color_preset_query,
|
||||||
|
effect.newColorPreset.id.toString()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
effect.newColorPreset.name
|
||||||
|
}.trim()
|
||||||
|
).showToast(context, longToast = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -73,7 +73,7 @@ fun BrowseScanOption() {
|
||||||
if (uri == null) return@rememberLauncherForActivityResult
|
if (uri == null) return@rememberLauncherForActivityResult
|
||||||
settingsModel.onEvent(
|
settingsModel.onEvent(
|
||||||
SettingsEvent.OnGrantPersistableUriPermission(
|
SettingsEvent.OnGrantPersistableUriPermission(
|
||||||
uri = uri
|
uri = uri.toString()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -95,7 +95,7 @@ fun BrowseScanOption() {
|
||||||
releasePersistableUriPermission = {
|
releasePersistableUriPermission = {
|
||||||
settingsModel.onEvent(
|
settingsModel.onEvent(
|
||||||
SettingsEvent.OnReleasePersistableUriPermission(
|
SettingsEvent.OnReleasePersistableUriPermission(
|
||||||
uri = permission.uri
|
uri = permission.uri.toString()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue