🛠️ ViewModel passing code reformat
* Provided all viewModels through LocalComposition * Removed passing viewModels as parameters
This commit is contained in:
parent
3b287ff1a0
commit
b135ed301c
112 changed files with 802 additions and 1451 deletions
|
|
@ -19,6 +19,7 @@ import androidx.compose.ui.platform.LocalFocusManager
|
|||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.core.view.WindowCompat
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.components.bottom_navigation_bar.BottomNavigationBar
|
||||
import ua.acclorite.book_story.presentation.components.custom_navigation_rail.CustomNavigationRail
|
||||
import ua.acclorite.book_story.presentation.data.MainViewModel
|
||||
|
|
@ -89,8 +90,8 @@ class Activity : AppCompatActivity() {
|
|||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
|
||||
setContent {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val isLoaded = mainViewModel.isReady.collectAsState()
|
||||
val state = mainViewModel.state.collectAsState()
|
||||
|
||||
val density = LocalDensity.current
|
||||
val imeInsets = WindowInsets.ime
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
package ua.acclorite.book_story.domain.util
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
abstract class BaseViewModel<S, E> : ViewModel() {
|
||||
abstract val state: StateFlow<S>
|
||||
abstract fun onEvent(event: E)
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
package ua.acclorite.book_story.presentation.components
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ProvidableCompositionLocal
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import ua.acclorite.book_story.domain.util.BaseViewModel
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.data.MainViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.about.data.AboutEvent
|
||||
import ua.acclorite.book_story.presentation.screens.about.data.AboutState
|
||||
import ua.acclorite.book_story.presentation.screens.about.data.AboutViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.about.nested.license_info.data.LicenseInfoEvent
|
||||
import ua.acclorite.book_story.presentation.screens.about.nested.license_info.data.LicenseInfoState
|
||||
import ua.acclorite.book_story.presentation.screens.about.nested.license_info.data.LicenseInfoViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.about.nested.licenses.data.LicensesEvent
|
||||
import ua.acclorite.book_story.presentation.screens.about.nested.licenses.data.LicensesState
|
||||
import ua.acclorite.book_story.presentation.screens.about.nested.licenses.data.LicensesViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoEvent
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoState
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseEvent
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseState
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.help.data.HelpEvent
|
||||
import ua.acclorite.book_story.presentation.screens.help.data.HelpState
|
||||
import ua.acclorite.book_story.presentation.screens.help.data.HelpViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.history.data.HistoryEvent
|
||||
import ua.acclorite.book_story.presentation.screens.history.data.HistoryState
|
||||
import ua.acclorite.book_story.presentation.screens.history.data.HistoryViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryState
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.reader.data.ReaderEvent
|
||||
import ua.acclorite.book_story.presentation.screens.reader.data.ReaderState
|
||||
import ua.acclorite.book_story.presentation.screens.reader.data.ReaderViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsEvent
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.start.data.StartEvent
|
||||
import ua.acclorite.book_story.presentation.screens.start.data.StartState
|
||||
import ua.acclorite.book_story.presentation.screens.start.data.StartViewModel
|
||||
|
||||
data class ViewModelComposition<S, E, V>(
|
||||
val state: State<S>,
|
||||
val onEvent: (E) -> Unit,
|
||||
val viewModel: V
|
||||
)
|
||||
|
||||
@Composable
|
||||
inline fun <reified V : BaseViewModel<S, E>, S, E> viewModelComposition(
|
||||
): ProvidableCompositionLocal<ViewModelComposition<S, E, V>> {
|
||||
val viewModel: V = hiltViewModel()
|
||||
val state = viewModel.state.collectAsState()
|
||||
|
||||
return compositionLocalOf {
|
||||
ViewModelComposition(
|
||||
state = state,
|
||||
onEvent = viewModel::onEvent,
|
||||
viewModel = viewModel
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val LocalMainViewModel
|
||||
@Composable get() = viewModelComposition<MainViewModel, MainState, MainEvent>()
|
||||
val LocalLibraryViewModel
|
||||
@Composable get() = viewModelComposition<LibraryViewModel, LibraryState, LibraryEvent>()
|
||||
val LocalHistoryViewModel
|
||||
@Composable get() = viewModelComposition<HistoryViewModel, HistoryState, HistoryEvent>()
|
||||
val LocalBrowseViewModel
|
||||
@Composable get() = viewModelComposition<BrowseViewModel, BrowseState, BrowseEvent>()
|
||||
val LocalBookInfoViewModel
|
||||
@Composable get() = viewModelComposition<BookInfoViewModel, BookInfoState, BookInfoEvent>()
|
||||
val LocalReaderViewModel
|
||||
@Composable get() = viewModelComposition<ReaderViewModel, ReaderState, ReaderEvent>()
|
||||
val LocalSettingsViewModel
|
||||
@Composable get() = viewModelComposition<SettingsViewModel, SettingsState, SettingsEvent>()
|
||||
val LocalAboutViewModel
|
||||
@Composable get() = viewModelComposition<AboutViewModel, AboutState, AboutEvent>()
|
||||
val LocalLicensesViewModel
|
||||
@Composable get() = viewModelComposition<LicensesViewModel, LicensesState, LicensesEvent>()
|
||||
val LocalLicenseInfoViewModel
|
||||
@Composable get() = viewModelComposition<LicenseInfoViewModel, LicenseInfoState, LicenseInfoEvent>()
|
||||
val LocalHelpViewModel
|
||||
@Composable get() = viewModelComposition<HelpViewModel, HelpState, HelpEvent>()
|
||||
val LocalStartViewModel
|
||||
@Composable get() = viewModelComposition<StartViewModel, StartState, StartEvent>()
|
||||
|
|
@ -82,6 +82,10 @@ data class MainState(
|
|||
val browseIncludedFilterItems: List<String> = provideDefaultValue { emptyList() },
|
||||
) : Parcelable {
|
||||
companion object {
|
||||
private fun <D> provideDefaultValue(calculation: () -> D): D {
|
||||
return calculation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes [MainState] by given [Map].
|
||||
* If no value provided in [data], assigns default value.
|
||||
|
|
@ -209,8 +213,4 @@ data class MainState(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <D> provideDefaultValue(calculation: () -> D): D {
|
||||
return calculation()
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package ua.acclorite.book_story.presentation.data
|
||||
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -16,6 +15,7 @@ import ua.acclorite.book_story.domain.use_case.ChangeLanguage
|
|||
import ua.acclorite.book_story.domain.use_case.CheckForUpdates
|
||||
import ua.acclorite.book_story.domain.use_case.GetAllSettings
|
||||
import ua.acclorite.book_story.domain.use_case.SetDatastore
|
||||
import ua.acclorite.book_story.domain.util.BaseViewModel
|
||||
import ua.acclorite.book_story.domain.util.Constants
|
||||
import ua.acclorite.book_story.domain.util.DataStoreConstants
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryViewModel
|
||||
|
|
@ -41,7 +41,7 @@ class MainViewModel @Inject constructor(
|
|||
private val changeLanguage: ChangeLanguage,
|
||||
private val checkForUpdates: CheckForUpdates,
|
||||
private val getAllSettings: GetAllSettings
|
||||
) : ViewModel() {
|
||||
) : BaseViewModel<MainState, MainEvent>() {
|
||||
|
||||
private val _isReady = MutableStateFlow(false)
|
||||
val isReady = _isReady.asStateFlow()
|
||||
|
|
@ -52,9 +52,9 @@ class MainViewModel @Inject constructor(
|
|||
private val _state: MutableStateFlow<MainState> = MutableStateFlow(
|
||||
stateHandle[Constants.MAIN_STATE] ?: MainState()
|
||||
)
|
||||
val state = _state.asStateFlow()
|
||||
override val state = _state.asStateFlow()
|
||||
|
||||
fun onEvent(event: MainEvent) {
|
||||
override fun onEvent(event: MainEvent) {
|
||||
when (event) {
|
||||
is MainEvent.OnChangeLanguage -> {
|
||||
viewModelScope.launch(Dispatchers.Main) {
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ import kotlinx.coroutines.Dispatchers
|
|||
import kotlinx.coroutines.launch
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.serialization.Serializable
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.domain.util.Route
|
||||
import ua.acclorite.book_story.presentation.components.CustomAnimatedVisibility
|
||||
import ua.acclorite.book_story.presentation.ui.Transitions
|
||||
|
|
@ -54,11 +55,14 @@ private const val USE_BACK_ANIM = "use_back_animation"
|
|||
private const val SCREENS = "screens"
|
||||
|
||||
/**
|
||||
* Passed in [CompositionLocalProvider] and can be accessed through [LocalNavigator].current.
|
||||
* Passed in [CompositionLocalProvider].
|
||||
*/
|
||||
val LocalNavigator = compositionLocalOf<Navigator> {
|
||||
error("Cannot initialize Navigator.")
|
||||
}
|
||||
val LocalOnNavigate = compositionLocalOf<OnNavigate> {
|
||||
error("Cannot initialize Navigator.")
|
||||
}
|
||||
|
||||
/**
|
||||
* Screens. Should be [Serializable] to be able to pass them inside [SavedStateHandle].
|
||||
|
|
@ -434,7 +438,10 @@ fun NavigationHost(
|
|||
.background(colorBetweenAnimations)
|
||||
)
|
||||
|
||||
CompositionLocalProvider(LocalNavigator provides navigator) {
|
||||
CompositionLocalProvider(
|
||||
LocalNavigator provides navigator,
|
||||
LocalOnNavigate provides { navigator.it() }
|
||||
) {
|
||||
content(navigator)
|
||||
}
|
||||
}
|
||||
|
|
@ -19,8 +19,6 @@ import androidx.compose.material3.Scaffold
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
|
|
@ -29,51 +27,36 @@ import androidx.compose.ui.res.painterResource
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.presentation.components.CustomLazyColumn
|
||||
import ua.acclorite.book_story.presentation.components.GoBackButton
|
||||
import ua.acclorite.book_story.presentation.components.LocalAboutViewModel
|
||||
import ua.acclorite.book_story.presentation.components.collapsibleUntilExitScrollBehaviorWithLazyListState
|
||||
import ua.acclorite.book_story.presentation.data.LocalNavigator
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.data.Screen
|
||||
import ua.acclorite.book_story.presentation.data.showToast
|
||||
import ua.acclorite.book_story.presentation.screens.about.components.AboutItem
|
||||
import ua.acclorite.book_story.presentation.screens.about.components.AboutUpdateDialog
|
||||
import ua.acclorite.book_story.presentation.screens.about.components.badges.AboutBadges
|
||||
import ua.acclorite.book_story.presentation.screens.about.data.AboutEvent
|
||||
import ua.acclorite.book_story.presentation.screens.about.data.AboutState
|
||||
import ua.acclorite.book_story.presentation.screens.about.data.AboutViewModel
|
||||
|
||||
@Composable
|
||||
fun AboutScreenRoot() {
|
||||
val navigator = LocalNavigator.current
|
||||
val aboutViewModel: AboutViewModel = hiltViewModel()
|
||||
|
||||
val state = aboutViewModel.state.collectAsState()
|
||||
|
||||
AboutScreen(
|
||||
state = state,
|
||||
onNavigate = { navigator.it() },
|
||||
onEvent = aboutViewModel::onEvent
|
||||
)
|
||||
AboutScreen()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun AboutScreen(
|
||||
state: State<AboutState>,
|
||||
onNavigate: OnNavigate,
|
||||
onEvent: (AboutEvent) -> Unit
|
||||
) {
|
||||
private fun AboutScreen() {
|
||||
val state = LocalAboutViewModel.current.state
|
||||
val onEvent = LocalAboutViewModel.current.onEvent
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
val context = LocalContext.current
|
||||
|
||||
val scrollState = TopAppBarDefaults.collapsibleUntilExitScrollBehaviorWithLazyListState()
|
||||
|
||||
if (state.value.showUpdateDialog) {
|
||||
AboutUpdateDialog(
|
||||
state = state,
|
||||
onEvent = onEvent
|
||||
)
|
||||
AboutUpdateDialog()
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
|
|
@ -245,7 +228,7 @@ private fun AboutScreen(
|
|||
}
|
||||
|
||||
item {
|
||||
AboutBadges(onEvent = onEvent)
|
||||
AboutBadges()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,24 +3,22 @@ package ua.acclorite.book_story.presentation.screens.about.components
|
|||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Update
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalAboutViewModel
|
||||
import ua.acclorite.book_story.presentation.components.custom_dialog.CustomDialogWithContent
|
||||
import ua.acclorite.book_story.presentation.data.showToast
|
||||
import ua.acclorite.book_story.presentation.screens.about.data.AboutEvent
|
||||
import ua.acclorite.book_story.presentation.screens.about.data.AboutState
|
||||
|
||||
/**
|
||||
* Update dialog. If there is app update transfers to the download page.
|
||||
*/
|
||||
@Composable
|
||||
fun AboutUpdateDialog(
|
||||
state: State<AboutState>,
|
||||
onEvent: (AboutEvent) -> Unit
|
||||
) {
|
||||
fun AboutUpdateDialog() {
|
||||
val state = LocalAboutViewModel.current.state
|
||||
val onEvent = LocalAboutViewModel.current.onEvent
|
||||
val context = LocalContext.current
|
||||
|
||||
val update = remember(state.value.showUpdateDialog) {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import androidx.compose.ui.unit.Dp
|
|||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.util.Constants
|
||||
import ua.acclorite.book_story.presentation.components.LocalAboutViewModel
|
||||
import ua.acclorite.book_story.presentation.components.customItems
|
||||
import ua.acclorite.book_story.presentation.data.showToast
|
||||
import ua.acclorite.book_story.presentation.screens.about.data.AboutEvent
|
||||
|
|
@ -21,14 +22,11 @@ import ua.acclorite.book_story.presentation.screens.about.data.AboutEvent
|
|||
* About Badges.
|
||||
* Links all ways to contact me.
|
||||
*
|
||||
* @param onEvent [AboutEvent] callback.
|
||||
* @param verticalPadding Vertical item padding.
|
||||
*/
|
||||
@Composable
|
||||
fun AboutBadges(
|
||||
onEvent: (AboutEvent) -> Unit,
|
||||
verticalPadding: Dp = 18.dp
|
||||
) {
|
||||
fun AboutBadges(verticalPadding: Dp = 18.dp) {
|
||||
val onEvent = LocalAboutViewModel.current.onEvent
|
||||
val context = LocalContext.current
|
||||
|
||||
Box(
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package ua.acclorite.book_story.presentation.screens.about.data
|
|||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
|
@ -12,18 +11,19 @@ import kotlinx.coroutines.flow.update
|
|||
import kotlinx.coroutines.launch
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.use_case.CheckForUpdates
|
||||
import ua.acclorite.book_story.domain.util.BaseViewModel
|
||||
import ua.acclorite.book_story.presentation.data.launchActivity
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class AboutViewModel @Inject constructor(
|
||||
private val checkForUpdates: CheckForUpdates,
|
||||
) : ViewModel() {
|
||||
) : BaseViewModel<AboutState, AboutEvent>() {
|
||||
|
||||
private val _state = MutableStateFlow(AboutState())
|
||||
val state = _state.asStateFlow()
|
||||
override val state = _state.asStateFlow()
|
||||
|
||||
fun onEvent(event: AboutEvent) {
|
||||
override fun onEvent(event: AboutEvent) {
|
||||
when (event) {
|
||||
is AboutEvent.OnNavigateToBrowserPage -> {
|
||||
viewModelScope.launch {
|
||||
|
|
|
|||
|
|
@ -16,40 +16,32 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.util.Constants
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.presentation.components.CustomLazyColumn
|
||||
import ua.acclorite.book_story.presentation.components.GoBackButton
|
||||
import ua.acclorite.book_story.presentation.components.LocalAboutViewModel
|
||||
import ua.acclorite.book_story.presentation.components.collapsibleUntilExitScrollBehaviorWithLazyListState
|
||||
import ua.acclorite.book_story.presentation.components.customItems
|
||||
import ua.acclorite.book_story.presentation.data.LocalNavigator
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.data.showToast
|
||||
import ua.acclorite.book_story.presentation.screens.about.data.AboutEvent
|
||||
import ua.acclorite.book_story.presentation.screens.about.data.AboutViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.about.nested.credits.components.CreditItem
|
||||
|
||||
@Composable
|
||||
fun CreditsScreenRoot() {
|
||||
val navigator = LocalNavigator.current
|
||||
val aboutViewModel: AboutViewModel = hiltViewModel()
|
||||
|
||||
CreditsScreen(
|
||||
onNavigate = { navigator.it() },
|
||||
onAboutNavigateEvent = aboutViewModel::onEvent
|
||||
)
|
||||
CreditsScreen()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun CreditsScreen(
|
||||
onNavigate: OnNavigate,
|
||||
onAboutNavigateEvent: (AboutEvent.OnNavigateToBrowserPage) -> Unit
|
||||
) {
|
||||
val scrollState = TopAppBarDefaults.collapsibleUntilExitScrollBehaviorWithLazyListState()
|
||||
private fun CreditsScreen() {
|
||||
val onEvent = LocalAboutViewModel.current.onEvent
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
val context = LocalContext.current
|
||||
|
||||
val scrollState = TopAppBarDefaults.collapsibleUntilExitScrollBehaviorWithLazyListState()
|
||||
|
||||
Scaffold(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
|
|
@ -81,7 +73,7 @@ private fun CreditsScreen(
|
|||
customItems(Constants.CREDITS, key = { it.name }) {
|
||||
CreditItem(credit = it) {
|
||||
it.website?.let { website ->
|
||||
onAboutNavigateEvent(
|
||||
onEvent(
|
||||
AboutEvent.OnNavigateToBrowserPage(
|
||||
page = website,
|
||||
context = context,
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@ import androidx.compose.material3.Text
|
|||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -33,56 +31,46 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
|
|||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.presentation.components.CustomIconButton
|
||||
import ua.acclorite.book_story.presentation.components.CustomLazyColumn
|
||||
import ua.acclorite.book_story.presentation.components.GoBackButton
|
||||
import ua.acclorite.book_story.presentation.components.LocalLicenseInfoViewModel
|
||||
import ua.acclorite.book_story.presentation.components.collapsibleUntilExitScrollBehaviorWithLazyListState
|
||||
import ua.acclorite.book_story.presentation.components.customItems
|
||||
import ua.acclorite.book_story.presentation.data.LocalNavigator
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.data.Screen
|
||||
import ua.acclorite.book_story.presentation.data.showToast
|
||||
import ua.acclorite.book_story.presentation.screens.about.nested.license_info.data.LicenseInfoEvent
|
||||
import ua.acclorite.book_story.presentation.screens.about.nested.license_info.data.LicenseInfoState
|
||||
import ua.acclorite.book_story.presentation.screens.about.nested.license_info.data.LicenseInfoViewModel
|
||||
import ua.acclorite.book_story.presentation.ui.DefaultTransition
|
||||
import ua.acclorite.book_story.presentation.ui.SlidingTransition
|
||||
|
||||
@Composable
|
||||
fun LicenseInfoScreenRoot(screen: Screen.About.LicenseInfo) {
|
||||
val navigator = LocalNavigator.current
|
||||
val viewModel = LocalLicenseInfoViewModel.current.viewModel
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
val context = LocalContext.current
|
||||
val licenseInfoViewModel: LicenseInfoViewModel = hiltViewModel()
|
||||
|
||||
val state = licenseInfoViewModel.state.collectAsState()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
licenseInfoViewModel.init(
|
||||
viewModel.init(
|
||||
screen = screen,
|
||||
onNavigate = { navigator.it() },
|
||||
onNavigate = onNavigate,
|
||||
context = context
|
||||
)
|
||||
}
|
||||
|
||||
LicenseInfoScreen(
|
||||
state = state,
|
||||
onNavigate = { navigator.it() },
|
||||
onEvent = licenseInfoViewModel::onEvent
|
||||
)
|
||||
LicenseInfoScreen()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun LicenseInfoScreen(
|
||||
state: State<LicenseInfoState>,
|
||||
onNavigate: OnNavigate,
|
||||
onEvent: (LicenseInfoEvent) -> Unit
|
||||
) {
|
||||
val scrollState = TopAppBarDefaults.collapsibleUntilExitScrollBehaviorWithLazyListState()
|
||||
private fun LicenseInfoScreen() {
|
||||
val state = LocalLicenseInfoViewModel.current.state
|
||||
val onEvent = LocalLicenseInfoViewModel.current.onEvent
|
||||
val context = LocalContext.current
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
|
||||
val scrollState = TopAppBarDefaults.collapsibleUntilExitScrollBehaviorWithLazyListState()
|
||||
val licenses = remember(state.value.license?.licenses) {
|
||||
state.value.license?.licenses?.toList()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.mikepenz.aboutlibraries.Libs
|
||||
import com.mikepenz.aboutlibraries.util.withContext
|
||||
|
|
@ -14,18 +13,21 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
|||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import ua.acclorite.book_story.domain.util.BaseViewModel
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.presentation.data.Screen
|
||||
import ua.acclorite.book_story.presentation.data.launchActivity
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class LicenseInfoViewModel @Inject constructor() : ViewModel() {
|
||||
class LicenseInfoViewModel @Inject constructor(
|
||||
|
||||
) : BaseViewModel<LicenseInfoState, LicenseInfoEvent>() {
|
||||
|
||||
private val _state = MutableStateFlow(LicenseInfoState())
|
||||
val state = _state.asStateFlow()
|
||||
override val state = _state.asStateFlow()
|
||||
|
||||
fun onEvent(event: LicenseInfoEvent) {
|
||||
override fun onEvent(event: LicenseInfoEvent) {
|
||||
when (event) {
|
||||
is LicenseInfoEvent.OnOpenLicensePage -> {
|
||||
viewModelScope.launch {
|
||||
|
|
|
|||
|
|
@ -18,51 +18,40 @@ import androidx.compose.material3.Text
|
|||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.presentation.components.CustomAnimatedVisibility
|
||||
import ua.acclorite.book_story.presentation.components.CustomLazyColumn
|
||||
import ua.acclorite.book_story.presentation.components.GoBackButton
|
||||
import ua.acclorite.book_story.presentation.components.LocalLicensesViewModel
|
||||
import ua.acclorite.book_story.presentation.components.collapsibleUntilExitScrollBehaviorWithLazyListState
|
||||
import ua.acclorite.book_story.presentation.components.customItems
|
||||
import ua.acclorite.book_story.presentation.data.LocalNavigator
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.data.Screen
|
||||
import ua.acclorite.book_story.presentation.screens.about.nested.licenses.components.LicenseItem
|
||||
import ua.acclorite.book_story.presentation.screens.about.nested.licenses.data.LicensesState
|
||||
import ua.acclorite.book_story.presentation.screens.about.nested.licenses.data.LicensesViewModel
|
||||
|
||||
@Composable
|
||||
fun LicensesScreenRoot() {
|
||||
val navigator = LocalNavigator.current
|
||||
val viewModel = LocalLicensesViewModel.current.viewModel
|
||||
val context = LocalContext.current
|
||||
val licensesViewModel: LicensesViewModel = hiltViewModel()
|
||||
|
||||
val state = licensesViewModel.state.collectAsState()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
licensesViewModel.init(context)
|
||||
viewModel.init(context)
|
||||
}
|
||||
|
||||
LicensesScreen(
|
||||
state = state,
|
||||
onNavigate = { navigator.it() }
|
||||
)
|
||||
LicensesScreen()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun LicensesScreen(
|
||||
state: State<LicensesState>,
|
||||
onNavigate: OnNavigate
|
||||
) {
|
||||
private fun LicensesScreen() {
|
||||
val state = LocalLicensesViewModel.current.state
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
|
||||
val scrollState = TopAppBarDefaults.collapsibleUntilExitScrollBehaviorWithLazyListState(
|
||||
state.value.listState
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
package ua.acclorite.book_story.presentation.screens.about.nested.licenses.data
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
|
||||
@Immutable
|
||||
sealed class LicensesEvent
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package ua.acclorite.book_story.presentation.screens.about.nested.licenses.data
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.mikepenz.aboutlibraries.Libs
|
||||
import com.mikepenz.aboutlibraries.util.withJson
|
||||
|
|
@ -12,15 +11,18 @@ import kotlinx.coroutines.flow.asStateFlow
|
|||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.util.BaseViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class LicensesViewModel @Inject constructor(
|
||||
|
||||
) : ViewModel() {
|
||||
) : BaseViewModel<LicensesState, LicensesEvent>() {
|
||||
|
||||
private val _state = MutableStateFlow(LicensesState())
|
||||
val state = _state.asStateFlow()
|
||||
override val state = _state.asStateFlow()
|
||||
|
||||
override fun onEvent(event: LicensesEvent) {}
|
||||
|
||||
fun init(context: Context) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
|
|
|
|||
|
|
@ -37,20 +37,17 @@ import androidx.compose.material3.Text
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.presentation.components.CustomAnimatedVisibility
|
||||
import ua.acclorite.book_story.presentation.components.CustomSnackbar
|
||||
import ua.acclorite.book_story.presentation.data.LocalNavigator
|
||||
import ua.acclorite.book_story.presentation.components.LocalBookInfoViewModel
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.data.Screen
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.components.BookInfoBackground
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.components.BookInfoDescriptionSection
|
||||
|
|
@ -63,60 +60,36 @@ import ua.acclorite.book_story.presentation.screens.book_info.components.details
|
|||
import ua.acclorite.book_story.presentation.screens.book_info.components.dialog.BookInfoDeleteDialog
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.components.dialog.BookInfoMoveDialog
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoEvent
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoState
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseEvent
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.history.data.HistoryEvent
|
||||
import ua.acclorite.book_story.presentation.screens.history.data.HistoryViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryViewModel
|
||||
|
||||
@Composable
|
||||
fun BookInfoScreenRoot(screen: Screen.BookInfo) {
|
||||
val navigator = LocalNavigator.current
|
||||
|
||||
val viewModel: BookInfoViewModel = hiltViewModel()
|
||||
val libraryViewModel: LibraryViewModel = hiltViewModel()
|
||||
val historyViewModel: HistoryViewModel = hiltViewModel()
|
||||
val browseViewModel: BrowseViewModel = hiltViewModel()
|
||||
|
||||
val state = viewModel.state.collectAsState()
|
||||
val viewModel = LocalBookInfoViewModel.current.viewModel
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.init(
|
||||
screen = screen,
|
||||
onNavigate = { navigator.it() }
|
||||
onNavigate = onNavigate
|
||||
)
|
||||
}
|
||||
|
||||
BookInfoScreen()
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
viewModel.clearViewModel()
|
||||
}
|
||||
}
|
||||
|
||||
BookInfoScreen(
|
||||
state = state,
|
||||
onNavigate = { navigator.it() },
|
||||
onEvent = viewModel::onEvent,
|
||||
onLibraryEvent = libraryViewModel::onEvent,
|
||||
onBrowseEvent = browseViewModel::onEvent,
|
||||
onHistoryEvent = historyViewModel::onEvent
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
private fun BookInfoScreen(
|
||||
state: State<BookInfoState>,
|
||||
onNavigate: OnNavigate,
|
||||
onEvent: (BookInfoEvent) -> Unit,
|
||||
onLibraryEvent: (LibraryEvent) -> Unit,
|
||||
onBrowseEvent: (BrowseEvent) -> Unit,
|
||||
onHistoryEvent: (HistoryEvent) -> Unit
|
||||
) {
|
||||
private fun BookInfoScreen() {
|
||||
val context = LocalContext.current
|
||||
val state = LocalBookInfoViewModel.current.state
|
||||
val onEvent = LocalBookInfoViewModel.current.onEvent
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
|
||||
val listState = rememberLazyListState()
|
||||
val snackbarState = remember { SnackbarHostState() }
|
||||
val refreshState = rememberPullRefreshState(
|
||||
|
|
@ -132,42 +105,19 @@ private fun BookInfoScreen(
|
|||
)
|
||||
|
||||
if (state.value.showChangeCoverBottomSheet) {
|
||||
BookInfoChangeCoverBottomSheet(
|
||||
state = state,
|
||||
onEvent = onEvent,
|
||||
onLibraryUpdateEvent = onLibraryEvent,
|
||||
onHistoryUpdateEvent = onHistoryEvent
|
||||
)
|
||||
BookInfoChangeCoverBottomSheet()
|
||||
}
|
||||
if (state.value.showDetailsBottomSheet) {
|
||||
BookInfoDetailsBottomSheet(
|
||||
state = state,
|
||||
onEvent = onEvent
|
||||
)
|
||||
BookInfoDetailsBottomSheet()
|
||||
}
|
||||
if (state.value.showDeleteDialog) {
|
||||
BookInfoDeleteDialog(
|
||||
onEvent = onEvent,
|
||||
onLibraryLoadEvent = onLibraryEvent,
|
||||
onHistoryLoadEvent = onHistoryEvent,
|
||||
onBrowseLoadEvent = onBrowseEvent
|
||||
)
|
||||
BookInfoDeleteDialog()
|
||||
}
|
||||
if (state.value.showMoveDialog) {
|
||||
BookInfoMoveDialog(
|
||||
state = state,
|
||||
onEvent = onEvent,
|
||||
onLibraryEvent = onLibraryEvent,
|
||||
onHistoryUpdateEvent = onHistoryEvent
|
||||
)
|
||||
BookInfoMoveDialog()
|
||||
}
|
||||
if (state.value.showConfirmUpdateDialog) {
|
||||
BookInfoConfirmUpdateDialog(
|
||||
snackbarHostState = snackbarState,
|
||||
onEvent = onEvent,
|
||||
onLibraryUpdateEvent = onLibraryEvent,
|
||||
onHistoryUpdateEvent = onHistoryEvent
|
||||
)
|
||||
BookInfoConfirmUpdateDialog(snackbarHostState = snackbarState)
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
|
|
@ -179,11 +129,6 @@ private fun BookInfoScreen(
|
|||
containerColor = MaterialTheme.colorScheme.surface,
|
||||
topBar = {
|
||||
BookInfoTopBar(
|
||||
state = state,
|
||||
onEvent = onEvent,
|
||||
onLibraryEvent = onLibraryEvent,
|
||||
onHistoryEvent = onHistoryEvent,
|
||||
onNavigate = onNavigate,
|
||||
listState = listState,
|
||||
snackbarState = snackbarState
|
||||
)
|
||||
|
|
@ -216,7 +161,7 @@ private fun BookInfoScreen(
|
|||
Column(Modifier.fillMaxWidth()) {
|
||||
Spacer(modifier = Modifier.height(paddingValues.calculateTopPadding() + 12.dp))
|
||||
// Info
|
||||
BookInfoInfoSection(state = state, onEvent = onEvent)
|
||||
BookInfoInfoSection()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -224,16 +169,13 @@ private fun BookInfoScreen(
|
|||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
// Statistic
|
||||
BookInfoStatisticSection(state = state)
|
||||
BookInfoStatisticSection()
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
// Description
|
||||
BookInfoDescriptionSection(
|
||||
state = state,
|
||||
onEvent = onEvent
|
||||
)
|
||||
BookInfoDescriptionSection()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import androidx.compose.foundation.text.KeyboardOptions
|
|||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -26,21 +25,18 @@ import androidx.compose.ui.text.input.KeyboardCapitalization
|
|||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalBookInfoViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoEvent
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoState
|
||||
|
||||
/**
|
||||
* Description section.
|
||||
*
|
||||
* @param state [BookInfoState].
|
||||
* @param onEvent [BookInfoEvent] callback.
|
||||
*/
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun BookInfoDescriptionSection(
|
||||
state: State<BookInfoState>,
|
||||
onEvent: (BookInfoEvent) -> Unit
|
||||
) {
|
||||
fun BookInfoDescriptionSection() {
|
||||
val state = LocalBookInfoViewModel.current.state
|
||||
val onEvent = LocalBookInfoViewModel.current.onEvent
|
||||
|
||||
val descriptionFocusRequester = remember { FocusRequester() }
|
||||
|
||||
if (!state.value.editDescription) {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import androidx.compose.material3.Icon
|
|||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -40,21 +39,18 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.CustomCoverImage
|
||||
import ua.acclorite.book_story.presentation.components.LocalBookInfoViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoEvent
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoState
|
||||
|
||||
/**
|
||||
* BookInfo's Info section.
|
||||
*
|
||||
* @param state [BookInfoState] instance.
|
||||
* @param onEvent [BookInfoEvent] callback.
|
||||
*/
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun BookInfoInfoSection(
|
||||
state: State<BookInfoState>,
|
||||
onEvent: (BookInfoEvent) -> Unit
|
||||
) {
|
||||
fun BookInfoInfoSection() {
|
||||
val state = LocalBookInfoViewModel.current.state
|
||||
val onEvent = LocalBookInfoViewModel.current.onEvent
|
||||
|
||||
val titleFocusRequester = remember { FocusRequester() }
|
||||
val authorFocusRequester = remember { FocusRequester() }
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import androidx.compose.material.icons.outlined.Info
|
|||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
|
|
@ -20,18 +19,17 @@ import androidx.compose.ui.unit.dp
|
|||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.CustomDropDownMenuItem
|
||||
import ua.acclorite.book_story.presentation.components.CustomIconButton
|
||||
import ua.acclorite.book_story.presentation.components.LocalBookInfoViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoEvent
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoState
|
||||
|
||||
/**
|
||||
* Book info more dropdown. Has three options: Delete, Move and Details.
|
||||
*/
|
||||
@Composable
|
||||
fun BookInfoMoreDropDown(
|
||||
state: State<BookInfoState>,
|
||||
onEvent: (BookInfoEvent) -> Unit,
|
||||
snackbarState: SnackbarHostState
|
||||
) {
|
||||
fun BookInfoMoreDropDown(snackbarState: SnackbarHostState) {
|
||||
val state = LocalBookInfoViewModel.current.state
|
||||
val onEvent = LocalBookInfoViewModel.current.onEvent
|
||||
|
||||
var showDropDown by remember { mutableStateOf(false) }
|
||||
|
||||
Box {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import androidx.compose.material3.LinearProgressIndicator
|
|||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.StrokeCap
|
||||
|
|
@ -17,15 +16,17 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalBookInfoViewModel
|
||||
import ua.acclorite.book_story.presentation.data.removeDigits
|
||||
import ua.acclorite.book_story.presentation.data.removeTrailingZero
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoState
|
||||
|
||||
/**
|
||||
* Statistic section.
|
||||
*/
|
||||
@Composable
|
||||
fun BookInfoStatisticSection(state: State<BookInfoState>) {
|
||||
fun BookInfoStatisticSection() {
|
||||
val state = LocalBookInfoViewModel.current.state
|
||||
|
||||
val progress = remember(state.value.book) {
|
||||
"${
|
||||
(state.value.book.progress * 100)
|
||||
|
|
|
|||
|
|
@ -13,20 +13,21 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.presentation.components.AnimatedTopAppBar
|
||||
import ua.acclorite.book_story.presentation.components.CustomAnimatedVisibility
|
||||
import ua.acclorite.book_story.presentation.components.CustomIconButton
|
||||
import ua.acclorite.book_story.presentation.components.GoBackButton
|
||||
import ua.acclorite.book_story.presentation.components.LocalBookInfoViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalHistoryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalLibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoEvent
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoState
|
||||
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.ui.DefaultTransition
|
||||
|
|
@ -35,26 +36,22 @@ import ua.acclorite.book_story.presentation.ui.Transitions
|
|||
/**
|
||||
* Book Info Top Bar.
|
||||
*
|
||||
* @param state [BookInfoState].
|
||||
* @param onEvent [BookInfoEvent] callback.
|
||||
* @param onLibraryEvent [LibraryEvent] callback.
|
||||
* @param onHistoryEvent [HistoryEvent] callback.
|
||||
* @param onNavigate Navigator callback.
|
||||
* @param listState [LazyListState].
|
||||
* @param snackbarState [SnackbarHostState].
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun BookInfoTopBar(
|
||||
state: State<BookInfoState>,
|
||||
onEvent: (BookInfoEvent) -> Unit,
|
||||
onLibraryEvent: (LibraryEvent) -> Unit,
|
||||
onHistoryEvent: (HistoryEvent) -> Unit,
|
||||
onNavigate: OnNavigate,
|
||||
listState: LazyListState,
|
||||
snackbarState: SnackbarHostState
|
||||
) {
|
||||
val state = LocalBookInfoViewModel.current.state
|
||||
val onEvent = LocalBookInfoViewModel.current.onEvent
|
||||
val onLibraryEvent = LocalLibraryViewModel.current.onEvent
|
||||
val onHistoryEvent = LocalHistoryViewModel.current.onEvent
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
val context = LocalContext.current
|
||||
|
||||
val firstVisibleItemIndex by remember { derivedStateOf { listState.firstVisibleItemIndex } }
|
||||
|
||||
AnimatedTopAppBar(
|
||||
|
|
@ -125,11 +122,7 @@ fun BookInfoTopBar(
|
|||
!state.value.editAuthor &&
|
||||
!state.value.editDescription
|
||||
) {
|
||||
BookInfoMoreDropDown(
|
||||
state = state,
|
||||
onEvent = onEvent,
|
||||
snackbarState = snackbarState
|
||||
)
|
||||
BookInfoMoreDropDown(snackbarState = snackbarState)
|
||||
}
|
||||
CustomAnimatedVisibility(
|
||||
visible = state.value.editTitle ||
|
||||
|
|
@ -175,7 +168,8 @@ fun BookInfoTopBar(
|
|||
onLibraryEvent(LibraryEvent.OnUpdateBook(it))
|
||||
onHistoryEvent(HistoryEvent.OnUpdateBook(it))
|
||||
}
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,35 +13,31 @@ import androidx.compose.material.icons.filled.ImageSearch
|
|||
import androidx.compose.material.icons.filled.Restore
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.CustomBottomSheet
|
||||
import ua.acclorite.book_story.presentation.components.LocalBookInfoViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalHistoryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalLibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.data.showToast
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoEvent
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoState
|
||||
import ua.acclorite.book_story.presentation.screens.history.data.HistoryEvent
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
|
||||
|
||||
/**
|
||||
* Change cover bottom sheet. Lets user select photo from the gallery and replaces old one.
|
||||
*
|
||||
* @param state [BookInfoState] instance.
|
||||
* @param onEvent [BookInfoEvent] callback.
|
||||
* @param onLibraryUpdateEvent [LibraryEvent] callback.
|
||||
* @param onHistoryUpdateEvent [HistoryEvent] callback.
|
||||
*/
|
||||
@Composable
|
||||
fun BookInfoChangeCoverBottomSheet(
|
||||
state: State<BookInfoState>,
|
||||
onEvent: (BookInfoEvent) -> Unit,
|
||||
onLibraryUpdateEvent: (LibraryEvent.OnUpdateBook) -> Unit,
|
||||
onHistoryUpdateEvent: (HistoryEvent.OnUpdateBook) -> Unit
|
||||
) {
|
||||
fun BookInfoChangeCoverBottomSheet() {
|
||||
val state = LocalBookInfoViewModel.current.state
|
||||
val onLibraryEvent = LocalLibraryViewModel.current.onEvent
|
||||
val onHistoryEvent = LocalHistoryViewModel.current.onEvent
|
||||
val onEvent = LocalBookInfoViewModel.current.onEvent
|
||||
val context = LocalContext.current
|
||||
|
||||
val photoPicker = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.PickVisualMedia(),
|
||||
onResult = { uri ->
|
||||
|
|
@ -51,8 +47,8 @@ fun BookInfoChangeCoverBottomSheet(
|
|||
uri,
|
||||
context,
|
||||
refreshList = {
|
||||
onLibraryUpdateEvent(LibraryEvent.OnUpdateBook(it))
|
||||
onHistoryUpdateEvent(HistoryEvent.OnUpdateBook(it))
|
||||
onLibraryEvent(LibraryEvent.OnUpdateBook(it))
|
||||
onHistoryEvent(HistoryEvent.OnUpdateBook(it))
|
||||
}
|
||||
)
|
||||
)
|
||||
|
|
@ -83,8 +79,8 @@ fun BookInfoChangeCoverBottomSheet(
|
|||
onEvent(
|
||||
BookInfoEvent.OnResetCoverImage(
|
||||
refreshList = {
|
||||
onLibraryUpdateEvent(LibraryEvent.OnUpdateBook(it))
|
||||
onHistoryUpdateEvent(HistoryEvent.OnUpdateBook(it))
|
||||
onLibraryEvent(LibraryEvent.OnUpdateBook(it))
|
||||
onHistoryEvent(HistoryEvent.OnUpdateBook(it))
|
||||
},
|
||||
showResult = {
|
||||
it.asString(context).showToast(context = context)
|
||||
|
|
@ -117,8 +113,8 @@ fun BookInfoChangeCoverBottomSheet(
|
|||
onEvent(
|
||||
BookInfoEvent.OnDeleteCover(
|
||||
refreshList = {
|
||||
onLibraryUpdateEvent(LibraryEvent.OnUpdateBook(it))
|
||||
onHistoryUpdateEvent(HistoryEvent.OnUpdateBook(it))
|
||||
onLibraryEvent(LibraryEvent.OnUpdateBook(it))
|
||||
onHistoryEvent(HistoryEvent.OnUpdateBook(it))
|
||||
}
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalBookInfoViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalHistoryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalLibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.custom_dialog.CustomDialogWithContent
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoEvent
|
||||
import ua.acclorite.book_story.presentation.screens.history.data.HistoryEvent
|
||||
|
|
@ -17,17 +20,12 @@ import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
|
|||
* Updates book if action clicked.
|
||||
*
|
||||
* @param snackbarHostState [SnackbarHostState].
|
||||
* @param onEvent [BookInfoEvent] callback.
|
||||
* @param onLibraryUpdateEvent [LibraryEvent] callback.
|
||||
* @param onHistoryUpdateEvent [HistoryEvent] callback.
|
||||
*/
|
||||
@Composable
|
||||
fun BookInfoConfirmUpdateDialog(
|
||||
snackbarHostState: SnackbarHostState,
|
||||
onEvent: (BookInfoEvent) -> Unit,
|
||||
onLibraryUpdateEvent: (LibraryEvent.OnUpdateBook) -> Unit,
|
||||
onHistoryUpdateEvent: (HistoryEvent.OnUpdateBook) -> Unit,
|
||||
) {
|
||||
fun BookInfoConfirmUpdateDialog(snackbarHostState: SnackbarHostState) {
|
||||
val onEvent = LocalBookInfoViewModel.current.onEvent
|
||||
val onLibraryEvent = LocalLibraryViewModel.current.onEvent
|
||||
val onHistoryEvent = LocalHistoryViewModel.current.onEvent
|
||||
val context = LocalContext.current
|
||||
|
||||
CustomDialogWithContent(
|
||||
|
|
@ -45,20 +43,12 @@ fun BookInfoConfirmUpdateDialog(
|
|||
snackbarState = snackbarHostState,
|
||||
context = context,
|
||||
refreshList = {
|
||||
onLibraryUpdateEvent(LibraryEvent.OnUpdateBook(it))
|
||||
onHistoryUpdateEvent(HistoryEvent.OnUpdateBook(it))
|
||||
onLibraryEvent(LibraryEvent.OnUpdateBook(it))
|
||||
onHistoryEvent(HistoryEvent.OnUpdateBook(it))
|
||||
}
|
||||
)
|
||||
)
|
||||
},
|
||||
withDivider = false
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.Spacer
|
|||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
|
|
@ -12,9 +11,9 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.CustomBottomSheet
|
||||
import ua.acclorite.book_story.presentation.components.LocalBookInfoViewModel
|
||||
import ua.acclorite.book_story.presentation.data.showToast
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoEvent
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoState
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
|
|
@ -22,15 +21,11 @@ import java.util.Locale
|
|||
|
||||
/**
|
||||
* Details bottom sheet. Displays name, path, last opened and size of the file.
|
||||
*
|
||||
* @param state [BookInfoState] instance.
|
||||
* @param onEvent [BookInfoEvent] callback.
|
||||
*/
|
||||
@Composable
|
||||
fun BookInfoDetailsBottomSheet(
|
||||
state: State<BookInfoState>,
|
||||
onEvent: (BookInfoEvent) -> Unit
|
||||
) {
|
||||
fun BookInfoDetailsBottomSheet() {
|
||||
val state = LocalBookInfoViewModel.current.state
|
||||
val onEvent = LocalBookInfoViewModel.current.onEvent
|
||||
val context = LocalContext.current
|
||||
|
||||
val pattern = remember {
|
||||
|
|
|
|||
|
|
@ -6,8 +6,12 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalBookInfoViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalBrowseViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalHistoryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalLibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.custom_dialog.CustomDialogWithContent
|
||||
import ua.acclorite.book_story.presentation.data.LocalNavigator
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.data.showToast
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoEvent
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseEvent
|
||||
|
|
@ -16,20 +20,14 @@ import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
|
|||
|
||||
/**
|
||||
* Delete dialog. Deletes current book.
|
||||
*
|
||||
* @param onEvent [BookInfoEvent] callback.
|
||||
* @param onLibraryLoadEvent [LibraryEvent] callback.
|
||||
* @param onHistoryLoadEvent [HistoryEvent] callback.
|
||||
* @param onBrowseLoadEvent [BrowseEvent] callback.
|
||||
*/
|
||||
@Composable
|
||||
fun BookInfoDeleteDialog(
|
||||
onEvent: (BookInfoEvent) -> Unit,
|
||||
onLibraryLoadEvent: (LibraryEvent.OnLoadList) -> Unit,
|
||||
onHistoryLoadEvent: (HistoryEvent.OnLoadList) -> Unit,
|
||||
onBrowseLoadEvent: (BrowseEvent.OnLoadList) -> Unit
|
||||
) {
|
||||
val navigator = LocalNavigator.current
|
||||
fun BookInfoDeleteDialog() {
|
||||
val onEvent = LocalBookInfoViewModel.current.onEvent
|
||||
val onLibraryEvent = LocalLibraryViewModel.current.onEvent
|
||||
val onHistoryEvent = LocalHistoryViewModel.current.onEvent
|
||||
val onBrowseEvent = LocalBrowseViewModel.current.onEvent
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
val context = LocalContext.current
|
||||
|
||||
CustomDialogWithContent(
|
||||
|
|
@ -45,11 +43,11 @@ fun BookInfoDeleteDialog(
|
|||
onAction = {
|
||||
onEvent(
|
||||
BookInfoEvent.OnDeleteBook(
|
||||
onNavigate = { navigator.it() },
|
||||
onNavigate = onNavigate,
|
||||
refreshList = {
|
||||
onLibraryLoadEvent(LibraryEvent.OnLoadList)
|
||||
onBrowseLoadEvent(BrowseEvent.OnLoadList)
|
||||
onHistoryLoadEvent(HistoryEvent.OnLoadList)
|
||||
onLibraryEvent(LibraryEvent.OnLoadList)
|
||||
onBrowseEvent(BrowseEvent.OnLoadList)
|
||||
onHistoryEvent(HistoryEvent.OnLoadList)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,39 +4,34 @@ import androidx.compose.material.icons.Icons
|
|||
import androidx.compose.material.icons.automirrored.outlined.DriveFileMove
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.model.Category
|
||||
import ua.acclorite.book_story.presentation.components.LocalBookInfoViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalHistoryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalLibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.customItems
|
||||
import ua.acclorite.book_story.presentation.components.custom_dialog.CustomDialogWithLazyColumn
|
||||
import ua.acclorite.book_story.presentation.components.custom_dialog.SelectableDialogItem
|
||||
import ua.acclorite.book_story.presentation.data.LocalNavigator
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.data.showToast
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoEvent
|
||||
import ua.acclorite.book_story.presentation.screens.book_info.data.BookInfoState
|
||||
import ua.acclorite.book_story.presentation.screens.history.data.HistoryEvent
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
|
||||
|
||||
/**
|
||||
* Move dialog.
|
||||
* Moves current book to the selected category.
|
||||
*
|
||||
* @param state [BookInfoState].
|
||||
* @param onEvent [BookInfoEvent] callback.
|
||||
* @param onLibraryEvent [LibraryEvent] callback.
|
||||
* @param onHistoryUpdateEvent [HistoryEvent] callback.
|
||||
*/
|
||||
@Composable
|
||||
fun BookInfoMoveDialog(
|
||||
state: State<BookInfoState>,
|
||||
onEvent: (BookInfoEvent) -> Unit,
|
||||
onLibraryEvent: (LibraryEvent) -> Unit,
|
||||
onHistoryUpdateEvent: (HistoryEvent.OnUpdateBook) -> Unit
|
||||
) {
|
||||
val navigator = LocalNavigator.current
|
||||
fun BookInfoMoveDialog() {
|
||||
val state = LocalBookInfoViewModel.current.state
|
||||
val onEvent = LocalBookInfoViewModel.current.onEvent
|
||||
val onLibraryEvent = LocalLibraryViewModel.current.onEvent
|
||||
val onHistoryEvent = LocalHistoryViewModel.current.onEvent
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
val context = LocalContext.current
|
||||
|
||||
val categories = remember {
|
||||
|
|
@ -61,12 +56,12 @@ fun BookInfoMoveDialog(
|
|||
BookInfoEvent.OnMoveBook(
|
||||
refreshList = {
|
||||
onLibraryEvent(LibraryEvent.OnUpdateBook(it))
|
||||
onHistoryUpdateEvent(HistoryEvent.OnUpdateBook(it))
|
||||
onHistoryEvent(HistoryEvent.OnUpdateBook(it))
|
||||
},
|
||||
updatePage = {
|
||||
onLibraryEvent(LibraryEvent.OnUpdateCurrentPage(it))
|
||||
},
|
||||
onNavigate = { navigator.it() }
|
||||
onNavigate = onNavigate
|
||||
)
|
||||
)
|
||||
context.getString(R.string.book_moved)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import android.content.Context.CLIPBOARD_SERVICE
|
|||
import android.graphics.BitmapFactory
|
||||
import android.os.Build
|
||||
import androidx.compose.material3.SnackbarResult
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -34,6 +33,7 @@ import ua.acclorite.book_story.domain.use_case.ResetCoverImage
|
|||
import ua.acclorite.book_story.domain.use_case.UpdateBookWithText
|
||||
import ua.acclorite.book_story.domain.use_case.UpdateBooks
|
||||
import ua.acclorite.book_story.domain.use_case.UpdateCoverImageOfBook
|
||||
import ua.acclorite.book_story.domain.util.BaseViewModel
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.domain.util.UIText
|
||||
import ua.acclorite.book_story.presentation.data.Screen
|
||||
|
|
@ -54,17 +54,17 @@ class BookInfoViewModel @Inject constructor(
|
|||
private val getText: GetText,
|
||||
private val canResetCover: CanResetCover,
|
||||
private val resetCoverImage: ResetCoverImage,
|
||||
) : ViewModel() {
|
||||
) : BaseViewModel<BookInfoState, BookInfoEvent>() {
|
||||
|
||||
private val _state = MutableStateFlow(BookInfoState())
|
||||
val state = _state.asStateFlow()
|
||||
override val state = _state.asStateFlow()
|
||||
|
||||
private var eventJob = SupervisorJob()
|
||||
|
||||
private var snackBarJob: Job? = null
|
||||
private var updateJob: Job? = null
|
||||
|
||||
fun onEvent(event: BookInfoEvent) {
|
||||
override fun onEvent(event: BookInfoEvent) {
|
||||
viewModelScope.launch(eventJob + Dispatchers.Main) {
|
||||
when (event) {
|
||||
is BookInfoEvent.OnShowHideChangeCoverBottomSheet -> {
|
||||
|
|
|
|||
|
|
@ -14,24 +14,19 @@ import androidx.compose.material3.Scaffold
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.PermissionState
|
||||
import com.google.accompanist.permissions.rememberPermissionState
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.model.SelectableFile
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.presentation.data.LocalNavigator
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.data.MainViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalBrowseViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.data.Screen
|
||||
import ua.acclorite.book_story.presentation.data.showToast
|
||||
import ua.acclorite.book_story.presentation.screens.browse.components.BrowseEmptyPlaceholder
|
||||
|
|
@ -41,23 +36,16 @@ import ua.acclorite.book_story.presentation.screens.browse.components.filter_bot
|
|||
import ua.acclorite.book_story.presentation.screens.browse.components.layout.BrowseLayout
|
||||
import ua.acclorite.book_story.presentation.screens.browse.components.top_bar.BrowseTopBar
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseEvent
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseState
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.data.BrowseFilesStructure
|
||||
import ua.acclorite.book_story.presentation.ui.DefaultTransition
|
||||
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@Composable
|
||||
fun BrowseScreenRoot() {
|
||||
val navigator = LocalNavigator.current
|
||||
val viewModel: BrowseViewModel = hiltViewModel()
|
||||
val libraryViewModel: LibraryViewModel = hiltViewModel()
|
||||
val mainViewModel: MainViewModel = hiltViewModel()
|
||||
|
||||
val state = viewModel.state.collectAsState()
|
||||
val mainState = mainViewModel.state.collectAsState()
|
||||
val state = LocalBrowseViewModel.current.state
|
||||
val mainState = LocalMainViewModel.current.state
|
||||
val onEvent = LocalBrowseViewModel.current.onEvent
|
||||
val viewModel = LocalBrowseViewModel.current.viewModel
|
||||
|
||||
val permissionState = rememberPermissionState(
|
||||
permission = Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
|
|
@ -72,22 +60,14 @@ fun BrowseScreenRoot() {
|
|||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.onEvent(BrowseEvent.OnUpdateScrollOffset)
|
||||
viewModel.onEvent(
|
||||
BrowseEvent.OnPermissionCheck(permissionState)
|
||||
)
|
||||
onEvent(BrowseEvent.OnUpdateScrollOffset)
|
||||
onEvent(BrowseEvent.OnPermissionCheck(permissionState))
|
||||
}
|
||||
|
||||
|
||||
BrowseScreen(
|
||||
state = state,
|
||||
mainState = mainState,
|
||||
permissionState = permissionState,
|
||||
filteredFiles = filteredFiles.value,
|
||||
onNavigate = { navigator.it() },
|
||||
onEvent = viewModel::onEvent,
|
||||
onMainEvent = mainViewModel::onEvent,
|
||||
onLibraryEvent = libraryViewModel::onEvent
|
||||
)
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
|
|
@ -103,16 +83,15 @@ fun BrowseScreenRoot() {
|
|||
)
|
||||
@Composable
|
||||
private fun BrowseScreen(
|
||||
state: State<BrowseState>,
|
||||
mainState: State<MainState>,
|
||||
permissionState: PermissionState,
|
||||
filteredFiles: List<SelectableFile>,
|
||||
onNavigate: OnNavigate,
|
||||
onEvent: (BrowseEvent) -> Unit,
|
||||
onMainEvent: (MainEvent) -> Unit,
|
||||
onLibraryEvent: (LibraryEvent) -> Unit
|
||||
filteredFiles: List<SelectableFile>
|
||||
) {
|
||||
val state = LocalBrowseViewModel.current.state
|
||||
val mainState = LocalMainViewModel.current.state
|
||||
val onEvent = LocalBrowseViewModel.current.onEvent
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
val context = LocalContext.current
|
||||
|
||||
val refreshState = rememberPullRefreshState(
|
||||
refreshing = state.value.isRefreshing,
|
||||
onRefresh = {
|
||||
|
|
@ -121,22 +100,13 @@ private fun BrowseScreen(
|
|||
)
|
||||
|
||||
if (state.value.requestPermissionDialog) {
|
||||
BrowseStoragePermissionDialog(onEvent, permissionState)
|
||||
BrowseStoragePermissionDialog(permissionState)
|
||||
}
|
||||
if (state.value.showAddingDialog) {
|
||||
BrowseAddingDialog(
|
||||
state = state,
|
||||
onEvent = onEvent,
|
||||
onLibraryEvent = onLibraryEvent
|
||||
)
|
||||
BrowseAddingDialog()
|
||||
}
|
||||
if (state.value.showFilterBottomSheet) {
|
||||
BrowseFilterBottomSheet(
|
||||
state = state,
|
||||
mainState = mainState,
|
||||
onMainEvent = onMainEvent,
|
||||
onEvent = onEvent
|
||||
)
|
||||
BrowseFilterBottomSheet()
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
|
|
@ -145,12 +115,7 @@ private fun BrowseScreen(
|
|||
.pullRefresh(refreshState),
|
||||
containerColor = MaterialTheme.colorScheme.surface,
|
||||
topBar = {
|
||||
BrowseTopBar(
|
||||
state = state,
|
||||
mainState = mainState,
|
||||
filteredFiles = filteredFiles,
|
||||
onEvent = onEvent
|
||||
)
|
||||
BrowseTopBar(filteredFiles = filteredFiles)
|
||||
}
|
||||
) { padding ->
|
||||
Box(
|
||||
|
|
@ -160,8 +125,6 @@ private fun BrowseScreen(
|
|||
) {
|
||||
DefaultTransition(visible = !state.value.isLoading) {
|
||||
BrowseLayout(
|
||||
state = state,
|
||||
mainState = mainState,
|
||||
filteredFiles = filteredFiles,
|
||||
onLongItemClick = { selectableFile ->
|
||||
when (selectableFile.isDirectory) {
|
||||
|
|
@ -223,11 +186,8 @@ private fun BrowseScreen(
|
|||
}
|
||||
|
||||
BrowseEmptyPlaceholder(
|
||||
state = state,
|
||||
isFilesEmpty = filteredFiles.isEmpty(),
|
||||
storagePermissionState = permissionState,
|
||||
onNavigate = onNavigate,
|
||||
onEvent = onEvent
|
||||
)
|
||||
|
||||
PullRefreshIndicator(
|
||||
|
|
@ -255,9 +215,7 @@ private fun BrowseScreen(
|
|||
state.value.inNestedDirectory
|
||||
&& mainState.value.browseFilesStructure != BrowseFilesStructure.ALL_FILES
|
||||
) {
|
||||
onEvent(
|
||||
BrowseEvent.OnGoBackDirectory
|
||||
)
|
||||
onEvent(BrowseEvent.OnGoBackDirectory)
|
||||
return@BackHandler
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package ua.acclorite.book_story.presentation.screens.browse.components
|
|||
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
|
|
@ -10,34 +9,32 @@ import androidx.compose.ui.res.stringResource
|
|||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.PermissionState
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.presentation.components.CustomAnimatedVisibility
|
||||
import ua.acclorite.book_story.presentation.components.LocalBrowseViewModel
|
||||
import ua.acclorite.book_story.presentation.components.is_messages.IsEmpty
|
||||
import ua.acclorite.book_story.presentation.components.is_messages.IsError
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.data.Screen
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseEvent
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseState
|
||||
import ua.acclorite.book_story.presentation.ui.Transitions
|
||||
|
||||
/**
|
||||
* Browse Empty Placeholder.
|
||||
* Shows error or empty message.
|
||||
*
|
||||
* @param state [BrowseState].
|
||||
* @param isFilesEmpty Whether the list is empty.
|
||||
* @param storagePermissionState Storage [PermissionState].
|
||||
* @param onNavigate Navigator callback.
|
||||
* @param onEvent [BrowseEvent] callback.
|
||||
*/
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@Composable
|
||||
fun BoxScope.BrowseEmptyPlaceholder(
|
||||
state: State<BrowseState>,
|
||||
isFilesEmpty: Boolean,
|
||||
storagePermissionState: PermissionState,
|
||||
onNavigate: OnNavigate,
|
||||
onEvent: (BrowseEvent) -> Unit
|
||||
storagePermissionState: PermissionState
|
||||
) {
|
||||
val state = LocalBrowseViewModel.current.state
|
||||
val onEvent = LocalBrowseViewModel.current.onEvent
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
|
||||
CustomAnimatedVisibility(
|
||||
visible = state.value.isError,
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
|
|
|
|||
|
|
@ -9,22 +9,22 @@ import androidx.compose.ui.res.stringResource
|
|||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.PermissionState
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalBrowseViewModel
|
||||
import ua.acclorite.book_story.presentation.components.custom_dialog.CustomDialogWithContent
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseEvent
|
||||
|
||||
/**
|
||||
* Storage permission dialog.
|
||||
*
|
||||
* @param onEvent [BrowseEvent] callback.
|
||||
* @param permissionState Storage [PermissionState].
|
||||
*/
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@Composable
|
||||
fun BrowseStoragePermissionDialog(
|
||||
onEvent: (BrowseEvent) -> Unit,
|
||||
permissionState: PermissionState
|
||||
) {
|
||||
val activity = LocalContext.current as ComponentActivity
|
||||
val onEvent = LocalBrowseViewModel.current.onEvent
|
||||
|
||||
CustomDialogWithContent(
|
||||
title = stringResource(id = R.string.storage_permission),
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import androidx.compose.material.icons.filled.AddChart
|
|||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.StrokeCap
|
||||
|
|
@ -18,30 +17,26 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.model.NullableBook
|
||||
import ua.acclorite.book_story.presentation.components.LocalBrowseViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalLibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.customItems
|
||||
import ua.acclorite.book_story.presentation.components.custom_dialog.CustomDialogWithLazyColumn
|
||||
import ua.acclorite.book_story.presentation.data.LocalNavigator
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.data.showToast
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseEvent
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseState
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
|
||||
|
||||
/**
|
||||
* Adding dialog.
|
||||
* Adds all selected books to the Library.
|
||||
*
|
||||
* @param state [BrowseState].
|
||||
* @param onEvent [BrowseEvent] callback.
|
||||
* @param onLibraryEvent [LibraryEvent] callback.
|
||||
*/
|
||||
@Composable
|
||||
fun BrowseAddingDialog(
|
||||
state: State<BrowseState>,
|
||||
onEvent: (BrowseEvent) -> Unit,
|
||||
onLibraryEvent: (LibraryEvent) -> Unit
|
||||
) {
|
||||
fun BrowseAddingDialog() {
|
||||
val context = LocalContext.current
|
||||
val navigator = LocalNavigator.current
|
||||
val state = LocalBrowseViewModel.current.state
|
||||
val onEvent = LocalBrowseViewModel.current.onEvent
|
||||
val onLibraryEvent = LocalLibraryViewModel.current.onEvent
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
|
||||
CustomDialogWithLazyColumn(
|
||||
title = stringResource(id = R.string.add_books),
|
||||
|
|
@ -54,7 +49,7 @@ fun BrowseAddingDialog(
|
|||
onAction = {
|
||||
onEvent(
|
||||
BrowseEvent.OnAddBooks(
|
||||
onNavigate = { navigator.it() },
|
||||
onNavigate = onNavigate,
|
||||
resetScroll = {
|
||||
onLibraryEvent(LibraryEvent.OnUpdateCurrentPage(0))
|
||||
onLibraryEvent(LibraryEvent.OnLoadList)
|
||||
|
|
|
|||
|
|
@ -8,14 +8,11 @@ import androidx.compose.foundation.pager.HorizontalPager
|
|||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.presentation.components.CustomBottomSheet
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.components.LocalBrowseViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseEvent
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.components.subcategories.BrowseFilterSubcategory
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.components.subcategories.BrowseGeneralSubcategory
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.components.subcategories.BrowseSortSubcategory
|
||||
|
|
@ -23,19 +20,12 @@ import ua.acclorite.book_story.presentation.screens.settings.nested.browse.compo
|
|||
/**
|
||||
* Browse Filter Bottom Sheet.
|
||||
* Lets user sort, filter and change appearance of the Browse.
|
||||
*
|
||||
* @param state [BrowseState].
|
||||
* @param mainState [MainState].
|
||||
* @param onMainEvent [MainEvent] callback.
|
||||
* @param onEvent [BrowseEvent] callback.
|
||||
*/
|
||||
@Composable
|
||||
fun BrowseFilterBottomSheet(
|
||||
state: State<BrowseState>,
|
||||
mainState: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit,
|
||||
onEvent: (BrowseEvent) -> Unit
|
||||
) {
|
||||
fun BrowseFilterBottomSheet() {
|
||||
val state = LocalBrowseViewModel.current.state
|
||||
val onEvent = LocalBrowseViewModel.current.onEvent
|
||||
|
||||
val pagerState = rememberPagerState(state.value.currentPage) { 3 }
|
||||
|
||||
LaunchedEffect(pagerState.currentPage) {
|
||||
|
|
@ -67,8 +57,6 @@ fun BrowseFilterBottomSheet(
|
|||
0 -> {
|
||||
LazyColumn(Modifier.fillMaxSize()) {
|
||||
BrowseGeneralSubcategory(
|
||||
state = mainState,
|
||||
onMainEvent = onMainEvent,
|
||||
showTitle = false,
|
||||
topPadding = 16.dp,
|
||||
bottomPadding = 8.dp + it
|
||||
|
|
@ -79,8 +67,6 @@ fun BrowseFilterBottomSheet(
|
|||
1 -> {
|
||||
LazyColumn(Modifier.fillMaxSize()) {
|
||||
BrowseFilterSubcategory(
|
||||
state = mainState,
|
||||
onMainEvent = onMainEvent,
|
||||
showTitle = false,
|
||||
topPadding = 16.dp,
|
||||
bottomPadding = 8.dp + it
|
||||
|
|
@ -91,8 +77,6 @@ fun BrowseFilterBottomSheet(
|
|||
2 -> {
|
||||
LazyColumn(Modifier.fillMaxSize()) {
|
||||
BrowseSortSubcategory(
|
||||
state = mainState,
|
||||
onMainEvent = onMainEvent,
|
||||
showTitle = false,
|
||||
topPadding = 16.dp,
|
||||
bottomPadding = 8.dp + it
|
||||
|
|
|
|||
|
|
@ -1,20 +1,16 @@
|
|||
package ua.acclorite.book_story.presentation.screens.browse.components.layout
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import ua.acclorite.book_story.domain.model.SelectableFile
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.browse.components.layout.grid.BrowseGridLayout
|
||||
import ua.acclorite.book_story.presentation.screens.browse.components.layout.list.BrowseListLayout
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.data.BrowseLayout
|
||||
|
||||
/**
|
||||
* Browse Layout.
|
||||
* Shows Grid or List.
|
||||
*
|
||||
* @param state [BrowseState].
|
||||
* @param mainState [MainState].
|
||||
* @param filteredFiles Filtered items.
|
||||
* @param onLongItemClick OnLongItemClick callback.
|
||||
* @param onFavoriteItemClick OnFavoriteItemClick callback.
|
||||
|
|
@ -22,17 +18,16 @@ import ua.acclorite.book_story.presentation.screens.settings.nested.browse.data.
|
|||
*/
|
||||
@Composable
|
||||
fun BrowseLayout(
|
||||
state: State<BrowseState>,
|
||||
mainState: State<MainState>,
|
||||
filteredFiles: List<SelectableFile>,
|
||||
onLongItemClick: (SelectableFile) -> Unit,
|
||||
onFavoriteItemClick: (SelectableFile) -> Unit,
|
||||
onItemClick: (SelectableFile) -> Unit
|
||||
) {
|
||||
val mainState = LocalMainViewModel.current.state
|
||||
|
||||
when (mainState.value.browseLayout) {
|
||||
BrowseLayout.LIST -> {
|
||||
BrowseListLayout(
|
||||
state = state,
|
||||
filteredFiles = filteredFiles,
|
||||
onLongItemClick = onLongItemClick,
|
||||
onFavoriteItemClick = onFavoriteItemClick,
|
||||
|
|
@ -42,7 +37,6 @@ fun BrowseLayout(
|
|||
|
||||
BrowseLayout.GRID -> {
|
||||
BrowseGridLayout(
|
||||
state = state,
|
||||
gridSize = mainState.value.browseGridSize,
|
||||
autoGridSize = mainState.value.browseAutoGridSize,
|
||||
filteredFiles = filteredFiles,
|
||||
|
|
|
|||
|
|
@ -7,19 +7,17 @@ import androidx.compose.foundation.layout.height
|
|||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.domain.model.SelectableFile
|
||||
import ua.acclorite.book_story.presentation.components.LocalBrowseViewModel
|
||||
import ua.acclorite.book_story.presentation.components.customItems
|
||||
import ua.acclorite.book_story.presentation.components.header
|
||||
import ua.acclorite.book_story.presentation.screens.browse.components.layout.BrowseItem
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.data.BrowseLayout
|
||||
|
||||
@Composable
|
||||
fun BrowseGridLayout(
|
||||
state: State<BrowseState>,
|
||||
gridSize: Int,
|
||||
autoGridSize: Boolean,
|
||||
filteredFiles: List<SelectableFile>,
|
||||
|
|
@ -27,6 +25,8 @@ fun BrowseGridLayout(
|
|||
onFavoriteItemClick: (SelectableFile) -> Unit,
|
||||
onItemClick: (SelectableFile) -> Unit,
|
||||
) {
|
||||
val state = LocalBrowseViewModel.current.state
|
||||
|
||||
LazyVerticalGrid(
|
||||
columns = if (autoGridSize) GridCells.Adaptive(170.dp)
|
||||
else GridCells.Fixed(gridSize.coerceAtLeast(1)),
|
||||
|
|
|
|||
|
|
@ -5,23 +5,23 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.domain.model.SelectableFile
|
||||
import ua.acclorite.book_story.presentation.components.LocalBrowseViewModel
|
||||
import ua.acclorite.book_story.presentation.components.customItems
|
||||
import ua.acclorite.book_story.presentation.screens.browse.components.layout.BrowseItem
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.data.BrowseLayout
|
||||
|
||||
@Composable
|
||||
fun BrowseListLayout(
|
||||
state: State<BrowseState>,
|
||||
filteredFiles: List<SelectableFile>,
|
||||
onLongItemClick: (SelectableFile) -> Unit,
|
||||
onFavoriteItemClick: (SelectableFile) -> Unit,
|
||||
onItemClick: (SelectableFile) -> Unit,
|
||||
) {
|
||||
val state = LocalBrowseViewModel.current.state
|
||||
|
||||
LazyColumn(
|
||||
state = state.value.listState,
|
||||
modifier = Modifier
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
|
|
@ -39,10 +38,10 @@ import ua.acclorite.book_story.presentation.components.AnimatedTopAppBar
|
|||
import ua.acclorite.book_story.presentation.components.CustomAnimatedVisibility
|
||||
import ua.acclorite.book_story.presentation.components.CustomIconButton
|
||||
import ua.acclorite.book_story.presentation.components.CustomSearchTextField
|
||||
import ua.acclorite.book_story.presentation.components.LocalBrowseViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.components.MoreDropDown
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseEvent
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.data.BrowseFilesStructure
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.data.BrowseLayout
|
||||
import ua.acclorite.book_story.presentation.ui.FadeTransitionPreservingSpace
|
||||
|
|
@ -50,19 +49,15 @@ import ua.acclorite.book_story.presentation.ui.FadeTransitionPreservingSpace
|
|||
/**
|
||||
* Browse Top Bar.
|
||||
*
|
||||
* @param state [BrowseState].
|
||||
* @param mainState [MainState].
|
||||
* @param filteredFiles Filtered files.
|
||||
* @param onEvent [BrowseEvent] callback.
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun BrowseTopBar(
|
||||
state: State<BrowseState>,
|
||||
mainState: State<MainState>,
|
||||
filteredFiles: List<SelectableFile>,
|
||||
onEvent: (BrowseEvent) -> Unit
|
||||
) {
|
||||
fun BrowseTopBar(filteredFiles: List<SelectableFile>) {
|
||||
val state = LocalBrowseViewModel.current.state
|
||||
val mainState = LocalMainViewModel.current.state
|
||||
val onEvent = LocalBrowseViewModel.current.onEvent
|
||||
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
val selectedDirectoryName = remember {
|
||||
mutableStateOf(state.value.selectedDirectory.name)
|
||||
|
|
@ -245,11 +240,7 @@ fun BrowseTopBar(
|
|||
},
|
||||
|
||||
customContent = {
|
||||
BrowseTopBarDirectoryPath(
|
||||
state = state,
|
||||
mainState = mainState,
|
||||
onEvent = onEvent
|
||||
)
|
||||
BrowseTopBarDirectoryPath()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
@ -19,7 +19,6 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -28,20 +27,20 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.CustomAnimatedVisibility
|
||||
import ua.acclorite.book_story.presentation.components.LocalBrowseViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.components.customItemsIndexed
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseEvent
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.data.BrowseFilesStructure
|
||||
import java.io.File
|
||||
|
||||
@Composable
|
||||
fun BrowseTopBarDirectoryPath(
|
||||
state: State<BrowseState>,
|
||||
mainState: State<MainState>,
|
||||
onEvent: (BrowseEvent) -> Unit
|
||||
) {
|
||||
fun BrowseTopBarDirectoryPath() {
|
||||
val state = LocalBrowseViewModel.current.state
|
||||
val mainState = LocalMainViewModel.current.state
|
||||
val onEvent = LocalBrowseViewModel.current.onEvent
|
||||
val context = LocalContext.current
|
||||
|
||||
val rootDirectory = remember {
|
||||
Environment.getExternalStorageDirectory()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import android.os.Environment
|
|||
import android.provider.Settings
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.lazy.grid.LazyGridState
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.isGranted
|
||||
|
|
@ -29,6 +28,7 @@ import ua.acclorite.book_story.domain.use_case.GetBookFromFile
|
|||
import ua.acclorite.book_story.domain.use_case.GetFilesFromDevice
|
||||
import ua.acclorite.book_story.domain.use_case.InsertBook
|
||||
import ua.acclorite.book_story.domain.use_case.UpdateFavoriteDirectory
|
||||
import ua.acclorite.book_story.domain.util.BaseViewModel
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.data.Screen
|
||||
import ua.acclorite.book_story.presentation.data.launchActivity
|
||||
|
|
@ -43,10 +43,10 @@ class BrowseViewModel @Inject constructor(
|
|||
private val getFilesFromDevice: GetFilesFromDevice,
|
||||
private val insertBook: InsertBook,
|
||||
private val updateFavoriteDirectory: UpdateFavoriteDirectory,
|
||||
) : ViewModel() {
|
||||
) : BaseViewModel<BrowseState, BrowseEvent>() {
|
||||
|
||||
private val _state = MutableStateFlow(BrowseState())
|
||||
val state = _state.asStateFlow()
|
||||
override val state = _state.asStateFlow()
|
||||
|
||||
private var searchQueryJob: Job? = null
|
||||
private var refreshListJob: Job? = null
|
||||
|
|
@ -67,7 +67,7 @@ class BrowseViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun onEvent(event: BrowseEvent) {
|
||||
override fun onEvent(event: BrowseEvent) {
|
||||
when (event) {
|
||||
is BrowseEvent.OnStoragePermissionRequest -> {
|
||||
val legacyStoragePermission = Build.VERSION.SDK_INT < Build.VERSION_CODES.R
|
||||
|
|
|
|||
|
|
@ -22,68 +22,51 @@ import androidx.compose.material3.Text
|
|||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.util.Constants
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.presentation.components.CustomIconButton
|
||||
import ua.acclorite.book_story.presentation.components.CustomLazyColumn
|
||||
import ua.acclorite.book_story.presentation.components.GoBackButton
|
||||
import ua.acclorite.book_story.presentation.components.LocalBrowseViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalHelpViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalStartViewModel
|
||||
import ua.acclorite.book_story.presentation.components.collapsibleUntilExitScrollBehaviorWithLazyListState
|
||||
import ua.acclorite.book_story.presentation.components.customItems
|
||||
import ua.acclorite.book_story.presentation.data.LocalNavigator
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.Screen
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseEvent
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.help.components.HelpItem
|
||||
import ua.acclorite.book_story.presentation.screens.help.components.items.HelpClickMeNoteItem
|
||||
import ua.acclorite.book_story.presentation.screens.help.data.HelpState
|
||||
import ua.acclorite.book_story.presentation.screens.help.data.HelpViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.start.data.StartEvent
|
||||
import ua.acclorite.book_story.presentation.screens.start.data.StartViewModel
|
||||
|
||||
@Composable
|
||||
fun HelpScreenRoot(screen: Screen.Help) {
|
||||
val navigator = LocalNavigator.current
|
||||
val helpViewModel: HelpViewModel = hiltViewModel()
|
||||
val browseViewModel: BrowseViewModel = hiltViewModel()
|
||||
val mainViewModel: MainViewModel = hiltViewModel()
|
||||
val startViewModel: StartViewModel = hiltViewModel()
|
||||
|
||||
val state = helpViewModel.state.collectAsState()
|
||||
val viewModel = LocalHelpViewModel.current.viewModel
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
helpViewModel.init(screen = screen)
|
||||
viewModel.init(screen = screen)
|
||||
}
|
||||
|
||||
HelpScreen(
|
||||
state = state,
|
||||
onNavigate = { navigator.it() },
|
||||
onMainEvent = mainViewModel::onEvent,
|
||||
onBrowseEvent = browseViewModel::onEvent,
|
||||
onStartEvent = startViewModel::onEvent
|
||||
)
|
||||
HelpScreen()
|
||||
}
|
||||
|
||||
@OptIn(
|
||||
ExperimentalMaterial3Api::class
|
||||
)
|
||||
@Composable
|
||||
private fun HelpScreen(
|
||||
state: State<HelpState>,
|
||||
onNavigate: OnNavigate,
|
||||
onMainEvent: (MainEvent) -> Unit,
|
||||
onBrowseEvent: (BrowseEvent) -> Unit,
|
||||
onStartEvent: (StartEvent) -> Unit
|
||||
) {
|
||||
private fun HelpScreen() {
|
||||
val state = LocalHelpViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
val onBrowseEvent = LocalBrowseViewModel.current.onEvent
|
||||
val onStartEvent = LocalStartViewModel.current.onEvent
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
|
||||
val scrollState = TopAppBarDefaults.collapsibleUntilExitScrollBehaviorWithLazyListState()
|
||||
|
||||
Scaffold(
|
||||
|
|
@ -171,7 +154,6 @@ private fun HelpScreen(
|
|||
customItems(Constants.HELP_TIPS, key = { it.title }) { helpTip ->
|
||||
HelpItem(
|
||||
helpTip = helpTip,
|
||||
onNavigate = onNavigate,
|
||||
fromStart = state.value.fromStart
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ import androidx.compose.ui.text.buildAnnotatedString
|
|||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.model.HelpTip
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.ui.ExpandingTransition
|
||||
|
||||
/**
|
||||
|
|
@ -39,15 +39,15 @@ import ua.acclorite.book_story.presentation.ui.ExpandingTransition
|
|||
* Can be Expanded or Collapsed.
|
||||
*
|
||||
* @param helpTip [HelpTip] to be shown.
|
||||
* @param onNavigate Navigator callback.
|
||||
* @param fromStart Whether user came from Start screen.
|
||||
*/
|
||||
@Composable
|
||||
fun HelpItem(
|
||||
helpTip: HelpTip,
|
||||
onNavigate: OnNavigate,
|
||||
fromStart: Boolean
|
||||
) {
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
|
||||
val showDescription = rememberSaveable {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
package ua.acclorite.book_story.presentation.screens.help.data
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
|
||||
@Immutable
|
||||
sealed class HelpEvent
|
||||
|
|
@ -1,22 +1,24 @@
|
|||
package ua.acclorite.book_story.presentation.screens.help.data
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import ua.acclorite.book_story.domain.util.BaseViewModel
|
||||
import ua.acclorite.book_story.presentation.data.Screen
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class HelpViewModel @Inject constructor(
|
||||
|
||||
) : ViewModel() {
|
||||
) : BaseViewModel<HelpState, HelpEvent>() {
|
||||
|
||||
private val _state = MutableStateFlow(HelpState())
|
||||
val state = _state.asStateFlow()
|
||||
override val state = _state.asStateFlow()
|
||||
|
||||
override fun onEvent(event: HelpEvent) {}
|
||||
|
||||
fun init(screen: Screen.Help) {
|
||||
viewModelScope.launch {
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@ import androidx.compose.material3.SnackbarHostState
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -36,44 +34,36 @@ import androidx.compose.ui.platform.LocalContext
|
|||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.presentation.components.AnimatedTopAppBar
|
||||
import ua.acclorite.book_story.presentation.components.CategoryTitle
|
||||
import ua.acclorite.book_story.presentation.components.CustomAnimatedVisibility
|
||||
import ua.acclorite.book_story.presentation.components.CustomIconButton
|
||||
import ua.acclorite.book_story.presentation.components.CustomSearchTextField
|
||||
import ua.acclorite.book_story.presentation.components.CustomSnackbar
|
||||
import ua.acclorite.book_story.presentation.components.LocalHistoryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalLibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.MoreDropDown
|
||||
import ua.acclorite.book_story.presentation.components.customItems
|
||||
import ua.acclorite.book_story.presentation.components.is_messages.IsEmpty
|
||||
import ua.acclorite.book_story.presentation.data.LocalNavigator
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.data.Screen
|
||||
import ua.acclorite.book_story.presentation.screens.history.components.HistoryDeleteWholeHistoryDialog
|
||||
import ua.acclorite.book_story.presentation.screens.history.components.HistoryItem
|
||||
import ua.acclorite.book_story.presentation.screens.history.data.HistoryEvent
|
||||
import ua.acclorite.book_story.presentation.screens.history.data.HistoryState
|
||||
import ua.acclorite.book_story.presentation.screens.history.data.HistoryViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.ui.DefaultTransition
|
||||
import ua.acclorite.book_story.presentation.ui.Transitions
|
||||
|
||||
@Composable
|
||||
fun HistoryScreenRoot() {
|
||||
val navigator = LocalNavigator.current
|
||||
val viewModel: HistoryViewModel = hiltViewModel()
|
||||
val libraryViewModel: LibraryViewModel = hiltViewModel()
|
||||
val onEvent = LocalHistoryViewModel.current.onEvent
|
||||
|
||||
val state = viewModel.state.collectAsState()
|
||||
LaunchedEffect(Unit) {
|
||||
onEvent(HistoryEvent.OnUpdateScrollOffset)
|
||||
}
|
||||
|
||||
HistoryScreen(
|
||||
state = state,
|
||||
onNavigate = { navigator.it() },
|
||||
onEvent = viewModel::onEvent,
|
||||
onLibraryEvent = libraryViewModel::onEvent
|
||||
)
|
||||
HistoryScreen()
|
||||
}
|
||||
|
||||
@OptIn(
|
||||
|
|
@ -81,13 +71,13 @@ fun HistoryScreenRoot() {
|
|||
ExperimentalMaterialApi::class
|
||||
)
|
||||
@Composable
|
||||
private fun HistoryScreen(
|
||||
state: State<HistoryState>,
|
||||
onNavigate: OnNavigate,
|
||||
onEvent: (HistoryEvent) -> Unit,
|
||||
onLibraryEvent: (LibraryEvent) -> Unit
|
||||
) {
|
||||
private fun HistoryScreen() {
|
||||
val context = LocalContext.current
|
||||
val state = LocalHistoryViewModel.current.state
|
||||
val onEvent = LocalHistoryViewModel.current.onEvent
|
||||
val onLibraryEvent = LocalLibraryViewModel.current.onEvent
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
|
||||
val refreshState = rememberPullRefreshState(
|
||||
refreshing = state.value.isRefreshing,
|
||||
onRefresh = {
|
||||
|
|
@ -97,15 +87,8 @@ private fun HistoryScreen(
|
|||
val focusRequester = remember { FocusRequester() }
|
||||
val snackbarState = remember { SnackbarHostState() }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
onEvent(HistoryEvent.OnUpdateScrollOffset)
|
||||
}
|
||||
|
||||
if (state.value.showDeleteWholeHistoryDialog) {
|
||||
HistoryDeleteWholeHistoryDialog(
|
||||
onEvent = onEvent,
|
||||
onLibraryLoadEvent = onLibraryEvent
|
||||
)
|
||||
HistoryDeleteWholeHistoryDialog()
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
|
|
@ -303,16 +286,4 @@ private fun HistoryScreen(
|
|||
navigate(Screen.Library)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -6,6 +6,8 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalHistoryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalLibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.custom_dialog.CustomDialogWithContent
|
||||
import ua.acclorite.book_story.presentation.data.showToast
|
||||
import ua.acclorite.book_story.presentation.screens.history.data.HistoryEvent
|
||||
|
|
@ -15,11 +17,10 @@ import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
|
|||
* Delete whole history dialog.
|
||||
*/
|
||||
@Composable
|
||||
fun HistoryDeleteWholeHistoryDialog(
|
||||
onEvent: (HistoryEvent) -> Unit,
|
||||
onLibraryLoadEvent: (LibraryEvent.OnLoadList) -> Unit
|
||||
) {
|
||||
fun HistoryDeleteWholeHistoryDialog() {
|
||||
val context = LocalContext.current
|
||||
val onEvent = LocalHistoryViewModel.current.onEvent
|
||||
val onLibraryEvent = LocalLibraryViewModel.current.onEvent
|
||||
|
||||
CustomDialogWithContent(
|
||||
title = stringResource(id = R.string.delete_history),
|
||||
|
|
@ -34,7 +35,7 @@ fun HistoryDeleteWholeHistoryDialog(
|
|||
onAction = {
|
||||
onEvent(
|
||||
HistoryEvent.OnDeleteWholeHistory {
|
||||
onLibraryLoadEvent(LibraryEvent.OnLoadList)
|
||||
onLibraryEvent(LibraryEvent.OnLoadList)
|
||||
}
|
||||
)
|
||||
context.getString(R.string.history_deleted)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package ua.acclorite.book_story.presentation.screens.history.data
|
|||
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.material3.SnackbarResult
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -21,6 +20,7 @@ import ua.acclorite.book_story.domain.use_case.DeleteWholeHistory
|
|||
import ua.acclorite.book_story.domain.use_case.GetBooksById
|
||||
import ua.acclorite.book_story.domain.use_case.GetHistory
|
||||
import ua.acclorite.book_story.domain.use_case.InsertHistory
|
||||
import ua.acclorite.book_story.domain.util.BaseViewModel
|
||||
import ua.acclorite.book_story.domain.util.Resource
|
||||
import ua.acclorite.book_story.presentation.data.Screen
|
||||
import java.text.SimpleDateFormat
|
||||
|
|
@ -36,10 +36,10 @@ class HistoryViewModel @Inject constructor(
|
|||
private val deleteWholeHistory: DeleteWholeHistory,
|
||||
private val deleteHistory: DeleteHistory,
|
||||
private val getBooksById: GetBooksById
|
||||
) : ViewModel() {
|
||||
) : BaseViewModel<HistoryState, HistoryEvent>() {
|
||||
|
||||
private val _state = MutableStateFlow(HistoryState())
|
||||
val state = _state.asStateFlow()
|
||||
override val state = _state.asStateFlow()
|
||||
|
||||
private var job: Job? = null
|
||||
private var job2: Job? = null
|
||||
|
|
@ -56,7 +56,7 @@ class HistoryViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun onEvent(event: HistoryEvent) {
|
||||
override fun onEvent(event: HistoryEvent) {
|
||||
when (event) {
|
||||
is HistoryEvent.OnRefreshList -> {
|
||||
job3?.cancel()
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
|
|
@ -41,47 +39,33 @@ import androidx.compose.ui.platform.LocalContext
|
|||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.model.Book
|
||||
import ua.acclorite.book_story.domain.model.Category
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.domain.util.Selected
|
||||
import ua.acclorite.book_story.presentation.components.CustomAnimatedVisibility
|
||||
import ua.acclorite.book_story.presentation.components.LocalLibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.components.customItems
|
||||
import ua.acclorite.book_story.presentation.components.header
|
||||
import ua.acclorite.book_story.presentation.components.is_messages.IsEmpty
|
||||
import ua.acclorite.book_story.presentation.data.LocalNavigator
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.data.MainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.data.Screen
|
||||
import ua.acclorite.book_story.presentation.data.showToast
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseEvent
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.history.data.HistoryEvent
|
||||
import ua.acclorite.book_story.presentation.screens.history.data.HistoryViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.library.components.LibraryBookItem
|
||||
import ua.acclorite.book_story.presentation.screens.library.components.LibraryTopBar
|
||||
import ua.acclorite.book_story.presentation.screens.library.components.dialog.LibraryDeleteDialog
|
||||
import ua.acclorite.book_story.presentation.screens.library.components.dialog.LibraryMoveDialog
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryState
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.ui.DefaultTransition
|
||||
import ua.acclorite.book_story.presentation.ui.Transitions
|
||||
|
||||
@Composable
|
||||
fun LibraryScreenRoot() {
|
||||
val navigator = LocalNavigator.current
|
||||
val viewModel: LibraryViewModel = hiltViewModel()
|
||||
val mainViewModel: MainViewModel = hiltViewModel()
|
||||
val browseViewModel: BrowseViewModel = hiltViewModel()
|
||||
val historyViewModel: HistoryViewModel = hiltViewModel()
|
||||
|
||||
val state = viewModel.state.collectAsState()
|
||||
val mainState = mainViewModel.state.collectAsState()
|
||||
val state = LocalLibraryViewModel.current.state
|
||||
val onEvent = LocalLibraryViewModel.current.onEvent
|
||||
|
||||
val pagerState = rememberPagerState(
|
||||
initialPage = state.value.currentPage,
|
||||
|
|
@ -90,60 +74,43 @@ fun LibraryScreenRoot() {
|
|||
val refreshState = rememberPullRefreshState(
|
||||
refreshing = state.value.isRefreshing,
|
||||
onRefresh = {
|
||||
viewModel.onEvent(LibraryEvent.OnRefreshList)
|
||||
onEvent(LibraryEvent.OnRefreshList)
|
||||
}
|
||||
)
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.onEvent(LibraryEvent.OnScrollToPage(state.value.currentPage, pagerState))
|
||||
onEvent(LibraryEvent.OnScrollToPage(state.value.currentPage, pagerState))
|
||||
}
|
||||
LaunchedEffect(pagerState.currentPage) {
|
||||
if (pagerState.currentPage != state.value.currentPage) {
|
||||
viewModel.onEvent(LibraryEvent.OnUpdateCurrentPage(pagerState.currentPage))
|
||||
onEvent(LibraryEvent.OnUpdateCurrentPage(pagerState.currentPage))
|
||||
}
|
||||
}
|
||||
|
||||
LibraryScreen(
|
||||
state = state,
|
||||
mainState = mainState,
|
||||
onNavigate = { navigator.it() },
|
||||
pagerState = pagerState,
|
||||
refreshState = refreshState,
|
||||
onEvent = viewModel::onEvent,
|
||||
onBrowseEvent = browseViewModel::onEvent,
|
||||
onHistoryEvent = historyViewModel::onEvent
|
||||
refreshState = refreshState
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
private fun LibraryScreen(
|
||||
state: State<LibraryState>,
|
||||
mainState: State<MainState>,
|
||||
onNavigate: OnNavigate,
|
||||
pagerState: PagerState,
|
||||
refreshState: PullRefreshState,
|
||||
onEvent: (LibraryEvent) -> Unit,
|
||||
onHistoryEvent: (HistoryEvent) -> Unit,
|
||||
onBrowseEvent: (BrowseEvent) -> Unit
|
||||
refreshState: PullRefreshState
|
||||
) {
|
||||
val state = LocalLibraryViewModel.current.state
|
||||
val mainState = LocalMainViewModel.current.state
|
||||
val onEvent = LocalLibraryViewModel.current.onEvent
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
|
||||
var isScrollInProgress by remember { mutableStateOf(false) }
|
||||
|
||||
if (state.value.showMoveDialog) {
|
||||
LibraryMoveDialog(
|
||||
state = state,
|
||||
onEvent = onEvent,
|
||||
onHistoryLoadEvent = onHistoryEvent,
|
||||
pagerState = pagerState
|
||||
)
|
||||
LibraryMoveDialog(pagerState = pagerState)
|
||||
}
|
||||
if (state.value.showDeleteDialog) {
|
||||
LibraryDeleteDialog(
|
||||
state = state,
|
||||
onEvent = onEvent,
|
||||
onBrowseLoadEvent = onBrowseEvent,
|
||||
onHistoryLoadEvent = onHistoryEvent
|
||||
)
|
||||
LibraryDeleteDialog()
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
|
|
@ -152,11 +119,7 @@ private fun LibraryScreen(
|
|||
.pullRefresh(refreshState),
|
||||
containerColor = MaterialTheme.colorScheme.surface,
|
||||
topBar = {
|
||||
LibraryTopBar(
|
||||
state = state,
|
||||
pagerState = pagerState,
|
||||
onEvent = onEvent
|
||||
)
|
||||
LibraryTopBar(pagerState = pagerState)
|
||||
}
|
||||
) { paddingValues ->
|
||||
Box(
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api
|
|||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -35,25 +34,21 @@ import ua.acclorite.book_story.R
|
|||
import ua.acclorite.book_story.presentation.components.AnimatedTopAppBar
|
||||
import ua.acclorite.book_story.presentation.components.CustomIconButton
|
||||
import ua.acclorite.book_story.presentation.components.CustomSearchTextField
|
||||
import ua.acclorite.book_story.presentation.components.LocalLibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.MoreDropDown
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryState
|
||||
|
||||
/**
|
||||
* Library Top Bar.
|
||||
* Contains [AnimatedTopAppBar] and [LibraryTabRow].
|
||||
*
|
||||
* @param state [LibraryState].
|
||||
* @param pagerState [PagerState].
|
||||
* @param onEvent [LibraryEvent] callback.
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun LibraryTopBar(
|
||||
state: State<LibraryState>,
|
||||
pagerState: PagerState,
|
||||
onEvent: (LibraryEvent) -> Unit
|
||||
) {
|
||||
fun LibraryTopBar(pagerState: PagerState) {
|
||||
val state = LocalLibraryViewModel.current.state
|
||||
val onEvent = LocalLibraryViewModel.current.onEvent
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
|
||||
AnimatedTopAppBar(
|
||||
|
|
|
|||
|
|
@ -3,28 +3,28 @@ package ua.acclorite.book_story.presentation.screens.library.components.dialog
|
|||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.DeleteOutline
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalBrowseViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalHistoryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalLibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.custom_dialog.CustomDialogWithContent
|
||||
import ua.acclorite.book_story.presentation.data.showToast
|
||||
import ua.acclorite.book_story.presentation.screens.browse.data.BrowseEvent
|
||||
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.library.data.LibraryState
|
||||
|
||||
/**
|
||||
* Delete dialog. Deletes all selected books.
|
||||
*/
|
||||
@Composable
|
||||
fun LibraryDeleteDialog(
|
||||
state: State<LibraryState>,
|
||||
onEvent: (LibraryEvent) -> Unit,
|
||||
onBrowseLoadEvent: (BrowseEvent.OnLoadList) -> Unit,
|
||||
onHistoryLoadEvent: (HistoryEvent.OnLoadList) -> Unit
|
||||
) {
|
||||
fun LibraryDeleteDialog() {
|
||||
val context = LocalContext.current
|
||||
val state = LocalLibraryViewModel.current.state
|
||||
val onEvent = LocalLibraryViewModel.current.onEvent
|
||||
val onBrowseEvent = LocalBrowseViewModel.current.onEvent
|
||||
val onHistoryEvent = LocalHistoryViewModel.current.onEvent
|
||||
|
||||
CustomDialogWithContent(
|
||||
title = stringResource(id = R.string.delete_books),
|
||||
|
|
@ -40,8 +40,8 @@ fun LibraryDeleteDialog(
|
|||
onAction = {
|
||||
onEvent(
|
||||
LibraryEvent.OnDeleteBooks {
|
||||
onBrowseLoadEvent(BrowseEvent.OnLoadList)
|
||||
onHistoryLoadEvent(HistoryEvent.OnLoadList)
|
||||
onBrowseEvent(BrowseEvent.OnLoadList)
|
||||
onHistoryEvent(HistoryEvent.OnLoadList)
|
||||
}
|
||||
)
|
||||
context.getString(R.string.books_deleted)
|
||||
|
|
|
|||
|
|
@ -4,30 +4,28 @@ import androidx.compose.foundation.pager.PagerState
|
|||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.DriveFileMove
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.model.Category
|
||||
import ua.acclorite.book_story.presentation.components.LocalHistoryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalLibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.customItems
|
||||
import ua.acclorite.book_story.presentation.components.custom_dialog.CustomDialogWithLazyColumn
|
||||
import ua.acclorite.book_story.presentation.components.custom_dialog.SelectableDialogItem
|
||||
import ua.acclorite.book_story.presentation.data.showToast
|
||||
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.library.data.LibraryState
|
||||
|
||||
/**
|
||||
* Move dialog. Moves all selected books to the selected category.
|
||||
*/
|
||||
@Composable
|
||||
fun LibraryMoveDialog(
|
||||
state: State<LibraryState>,
|
||||
onEvent: (LibraryEvent) -> Unit,
|
||||
onHistoryLoadEvent: (HistoryEvent.OnLoadList) -> Unit,
|
||||
pagerState: PagerState
|
||||
) {
|
||||
fun LibraryMoveDialog(pagerState: PagerState) {
|
||||
val context = LocalContext.current
|
||||
val state = LocalLibraryViewModel.current.state
|
||||
val onEvent = LocalLibraryViewModel.current.onEvent
|
||||
val onHistoryEvent = LocalHistoryViewModel.current.onEvent
|
||||
|
||||
CustomDialogWithLazyColumn(
|
||||
title = stringResource(id = R.string.move_books),
|
||||
|
|
@ -44,7 +42,7 @@ fun LibraryMoveDialog(
|
|||
LibraryEvent.OnMoveBooks(
|
||||
pagerState,
|
||||
refreshList = {
|
||||
onHistoryLoadEvent(HistoryEvent.OnLoadList)
|
||||
onHistoryEvent(HistoryEvent.OnLoadList)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package ua.acclorite.book_story.presentation.screens.library.data
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -18,6 +17,7 @@ import ua.acclorite.book_story.domain.use_case.DeleteBooks
|
|||
import ua.acclorite.book_story.domain.use_case.GetBooks
|
||||
import ua.acclorite.book_story.domain.use_case.InsertHistory
|
||||
import ua.acclorite.book_story.domain.use_case.UpdateBooks
|
||||
import ua.acclorite.book_story.domain.util.BaseViewModel
|
||||
import ua.acclorite.book_story.presentation.data.Screen
|
||||
import java.util.Date
|
||||
import javax.inject.Inject
|
||||
|
|
@ -28,10 +28,10 @@ class LibraryViewModel @Inject constructor(
|
|||
private val updateBooks: UpdateBooks,
|
||||
private val deleteBooks: DeleteBooks,
|
||||
private val insertHistory: InsertHistory
|
||||
) : ViewModel() {
|
||||
) : BaseViewModel<LibraryState, LibraryEvent>() {
|
||||
|
||||
private val _state = MutableStateFlow(LibraryState())
|
||||
val state = _state.asStateFlow()
|
||||
override val state = _state.asStateFlow()
|
||||
|
||||
private val _isReady = MutableStateFlow(false)
|
||||
val isReady = _isReady.asStateFlow()
|
||||
|
|
@ -53,7 +53,7 @@ class LibraryViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun onEvent(event: LibraryEvent) {
|
||||
override fun onEvent(event: LibraryEvent) {
|
||||
when (event) {
|
||||
is LibraryEvent.OnScrollToPage -> {
|
||||
viewModelScope.launch {
|
||||
|
|
|
|||
|
|
@ -26,8 +26,6 @@ import androidx.compose.material3.Text
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
|
|
@ -49,24 +47,22 @@ import androidx.compose.ui.unit.em
|
|||
import androidx.compose.ui.unit.sp
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.util.Constants
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.presentation.components.CustomAnimatedVisibility
|
||||
import ua.acclorite.book_story.presentation.components.CustomSelectionContainer
|
||||
import ua.acclorite.book_story.presentation.components.LocalHistoryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalLibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalReaderViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalSettingsViewModel
|
||||
import ua.acclorite.book_story.presentation.components.customItemsIndexed
|
||||
import ua.acclorite.book_story.presentation.components.is_messages.IsError
|
||||
import ua.acclorite.book_story.presentation.data.LocalNavigator
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.data.MainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.data.Screen
|
||||
import ua.acclorite.book_story.presentation.data.showToast
|
||||
import ua.acclorite.book_story.presentation.screens.history.data.HistoryEvent
|
||||
import ua.acclorite.book_story.presentation.screens.history.data.HistoryViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.reader.components.ReaderEndItem
|
||||
import ua.acclorite.book_story.presentation.screens.reader.components.ReaderTextParagraph
|
||||
import ua.acclorite.book_story.presentation.screens.reader.components.app_bar.ReaderBottomBar
|
||||
|
|
@ -75,26 +71,16 @@ import ua.acclorite.book_story.presentation.screens.reader.components.readerFast
|
|||
import ua.acclorite.book_story.presentation.screens.reader.components.settings_bottom_sheet.ReaderSettingsBottomSheet
|
||||
import ua.acclorite.book_story.presentation.screens.reader.components.start_item.ReaderStartItem
|
||||
import ua.acclorite.book_story.presentation.screens.reader.data.ReaderEvent
|
||||
import ua.acclorite.book_story.presentation.screens.reader.data.ReaderState
|
||||
import ua.acclorite.book_story.presentation.screens.reader.data.ReaderViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsEvent
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsViewModel
|
||||
|
||||
@Composable
|
||||
fun ReaderScreenRoot(screen: Screen.Reader) {
|
||||
val navigator = LocalNavigator.current
|
||||
val state = LocalReaderViewModel.current.state
|
||||
val onLibraryEvent = LocalLibraryViewModel.current.onEvent
|
||||
val onHistoryEvent = LocalHistoryViewModel.current.onEvent
|
||||
val viewModel = LocalReaderViewModel.current.viewModel
|
||||
val context = LocalContext.current as ComponentActivity
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
|
||||
val viewModel: ReaderViewModel = hiltViewModel()
|
||||
val mainViewModel: MainViewModel = hiltViewModel()
|
||||
val libraryViewModel: LibraryViewModel = hiltViewModel()
|
||||
val historyViewModel: HistoryViewModel = hiltViewModel()
|
||||
val settingsViewModel: SettingsViewModel = hiltViewModel()
|
||||
|
||||
val state = viewModel.state.collectAsState()
|
||||
val mainState = mainViewModel.state.collectAsState()
|
||||
val settingsState = settingsViewModel.state.collectAsState()
|
||||
|
||||
val lazyListState = rememberSaveable(
|
||||
state.value.listState,
|
||||
|
|
@ -111,11 +97,11 @@ fun ReaderScreenRoot(screen: Screen.Reader) {
|
|||
LaunchedEffect(Unit) {
|
||||
viewModel.init(
|
||||
screen = screen,
|
||||
onNavigate = { navigator.it() },
|
||||
onNavigate = onNavigate,
|
||||
context = context,
|
||||
refreshList = {
|
||||
libraryViewModel.onEvent(LibraryEvent.OnUpdateBook(it))
|
||||
historyViewModel.onEvent(HistoryEvent.OnLoadList)
|
||||
onLibraryEvent(LibraryEvent.OnUpdateBook(it))
|
||||
onHistoryEvent(HistoryEvent.OnLoadList)
|
||||
},
|
||||
onError = {
|
||||
it.asString(context)
|
||||
|
|
@ -129,12 +115,14 @@ fun ReaderScreenRoot(screen: Screen.Reader) {
|
|||
}
|
||||
}
|
||||
LaunchedEffect(lazyListState) {
|
||||
viewModel.onUpdateProgress(
|
||||
onLibraryEvent = libraryViewModel::onEvent,
|
||||
onHistoryEvent = historyViewModel::onEvent
|
||||
)
|
||||
viewModel.onUpdateProgress {
|
||||
onLibraryEvent(LibraryEvent.OnUpdateBook(it))
|
||||
onHistoryEvent(HistoryEvent.OnUpdateBook(it))
|
||||
}
|
||||
}
|
||||
|
||||
ReaderScreen(lazyListState = lazyListState)
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
viewModel.clearViewModel()
|
||||
|
|
@ -145,36 +133,19 @@ fun ReaderScreenRoot(screen: Screen.Reader) {
|
|||
context.window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
}
|
||||
}
|
||||
|
||||
ReaderScreen(
|
||||
state = state,
|
||||
mainState = mainState,
|
||||
settingsState = settingsState,
|
||||
lazyListState = lazyListState,
|
||||
onNavigate = { navigator.it() },
|
||||
onEvent = viewModel::onEvent,
|
||||
onMainEvent = mainViewModel::onEvent,
|
||||
onSettingsEvent = settingsViewModel::onEvent,
|
||||
onLibraryEvent = libraryViewModel::onEvent,
|
||||
onHistoryEvent = historyViewModel::onEvent
|
||||
)
|
||||
}
|
||||
|
||||
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
|
||||
@Composable
|
||||
private fun ReaderScreen(
|
||||
state: State<ReaderState>,
|
||||
mainState: State<MainState>,
|
||||
settingsState: State<SettingsState>,
|
||||
lazyListState: LazyListState,
|
||||
onNavigate: OnNavigate,
|
||||
onEvent: (ReaderEvent) -> Unit,
|
||||
onMainEvent: (MainEvent) -> Unit,
|
||||
onSettingsEvent: (SettingsEvent) -> Unit,
|
||||
onLibraryEvent: (LibraryEvent) -> Unit,
|
||||
onHistoryEvent: (HistoryEvent) -> Unit,
|
||||
) {
|
||||
private fun ReaderScreen(lazyListState: LazyListState) {
|
||||
val state = LocalReaderViewModel.current.state
|
||||
val mainState = LocalMainViewModel.current.state
|
||||
val settingsState = LocalSettingsViewModel.current.state
|
||||
val onEvent = LocalReaderViewModel.current.onEvent
|
||||
val onLibraryEvent = LocalLibraryViewModel.current.onEvent
|
||||
val onHistoryEvent = LocalHistoryViewModel.current.onEvent
|
||||
val context = LocalContext.current as ComponentActivity
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
|
||||
val nestedScrollConnection = remember(state) {
|
||||
object : NestedScrollConnection {
|
||||
|
|
@ -230,13 +201,7 @@ private fun ReaderScreen(
|
|||
}
|
||||
|
||||
if (state.value.showSettingsBottomSheet) {
|
||||
ReaderSettingsBottomSheet(
|
||||
mainState = mainState,
|
||||
settingsState = settingsState,
|
||||
onEvent = onEvent,
|
||||
onMainEvent = onMainEvent,
|
||||
onSettingsEvent = onSettingsEvent
|
||||
)
|
||||
ReaderSettingsBottomSheet()
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
|
|
@ -250,13 +215,7 @@ private fun ReaderScreen(
|
|||
enter = slideInVertically { -it },
|
||||
exit = slideOutVertically { -it }
|
||||
) {
|
||||
ReaderTopBar(
|
||||
state = state,
|
||||
onNavigate = onNavigate,
|
||||
onEvent = onEvent,
|
||||
onLibraryUpdateEvent = onLibraryEvent,
|
||||
onHistoryUpdateEvent = onHistoryEvent
|
||||
)
|
||||
ReaderTopBar()
|
||||
}
|
||||
},
|
||||
bottomBar = {
|
||||
|
|
@ -266,12 +225,7 @@ private fun ReaderScreen(
|
|||
enter = slideInVertically { it },
|
||||
exit = slideOutVertically { it }
|
||||
) {
|
||||
ReaderBottomBar(
|
||||
state = state,
|
||||
onEvent = onEvent,
|
||||
onLibraryUpdateEvent = onLibraryEvent,
|
||||
onHistoryUpdateEvent = onHistoryEvent
|
||||
)
|
||||
ReaderBottomBar()
|
||||
}
|
||||
}
|
||||
) {
|
||||
|
|
@ -357,7 +311,6 @@ private fun ReaderScreen(
|
|||
fastColorPresetChangeEnabled = mainState.value.fastColorPresetChange,
|
||||
isLoading = state.value.loading,
|
||||
toolbarHidden = toolbarHidden,
|
||||
onSettingsEvent = onSettingsEvent,
|
||||
presetChanged = {
|
||||
context
|
||||
.getString(
|
||||
|
|
@ -373,7 +326,7 @@ private fun ReaderScreen(
|
|||
) {
|
||||
item {
|
||||
DisableSelection {
|
||||
ReaderStartItem(state = state)
|
||||
ReaderStartItem()
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(18.dp))
|
||||
|
|
@ -395,8 +348,7 @@ private fun ReaderScreen(
|
|||
sidePadding = sidePadding,
|
||||
paragraphIndentation = mainState.value.paragraphIndentation,
|
||||
doubleClickTranslationEnabled = mainState.value.doubleClickTranslation,
|
||||
toolbarHidden = toolbarHidden,
|
||||
onEvent = onEvent
|
||||
toolbarHidden = toolbarHidden
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -404,13 +356,7 @@ private fun ReaderScreen(
|
|||
Spacer(modifier = Modifier.height(18.dp))
|
||||
|
||||
DisableSelection {
|
||||
ReaderEndItem(
|
||||
state = state,
|
||||
onNavigate = onNavigate,
|
||||
onEvent = onEvent,
|
||||
onLibraryEvent = onLibraryEvent,
|
||||
onHistoryUpdateEvent = onHistoryEvent,
|
||||
)
|
||||
ReaderEndItem()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -29,33 +28,30 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.model.Category
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.presentation.components.LocalHistoryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalLibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalReaderViewModel
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.data.Screen
|
||||
import ua.acclorite.book_story.presentation.data.showToast
|
||||
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.data.ReaderEvent
|
||||
import ua.acclorite.book_story.presentation.screens.reader.data.ReaderState
|
||||
|
||||
/**
|
||||
* Reader end item. Displays at the end of the book.
|
||||
*
|
||||
* @param state [ReaderState].
|
||||
* @param onNavigate Navigator callback.
|
||||
* @param onEvent [ReaderEvent] callback.
|
||||
* @param onLibraryEvent [LibraryEvent] callback.
|
||||
* @param onHistoryUpdateEvent [HistoryEvent] callback.
|
||||
*/
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
fun ReaderEndItem(
|
||||
state: State<ReaderState>,
|
||||
onNavigate: OnNavigate,
|
||||
onEvent: (ReaderEvent) -> Unit,
|
||||
onLibraryEvent: (LibraryEvent) -> Unit,
|
||||
onHistoryUpdateEvent: (HistoryEvent.OnUpdateBook) -> Unit,
|
||||
) {
|
||||
val state = LocalReaderViewModel.current.state
|
||||
val onEvent = LocalReaderViewModel.current.onEvent
|
||||
val onLibraryEvent = LocalLibraryViewModel.current.onEvent
|
||||
val onHistoryEvent = LocalHistoryViewModel.current.onEvent
|
||||
val context = LocalContext.current as ComponentActivity
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
|
||||
val buttonText = remember {
|
||||
context.getString(
|
||||
if (state.value.book.category != Category.ALREADY_READ) R.string.move_to_read
|
||||
|
|
@ -102,7 +98,7 @@ fun ReaderEndItem(
|
|||
context = context,
|
||||
onUpdateCategories = {
|
||||
onLibraryEvent(LibraryEvent.OnUpdateBook(it))
|
||||
onHistoryUpdateEvent(HistoryEvent.OnUpdateBook(it))
|
||||
onHistoryEvent(HistoryEvent.OnUpdateBook(it))
|
||||
},
|
||||
updatePage = {
|
||||
onLibraryEvent(LibraryEvent.OnUpdateCurrentPage(it))
|
||||
|
|
@ -119,7 +115,7 @@ fun ReaderEndItem(
|
|||
context = context,
|
||||
refreshList = {
|
||||
onLibraryEvent(LibraryEvent.OnUpdateBook(it))
|
||||
onHistoryUpdateEvent(HistoryEvent.OnUpdateBook(it))
|
||||
onHistoryEvent(HistoryEvent.OnUpdateBook(it))
|
||||
},
|
||||
navigate = {
|
||||
onNavigate {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import ua.acclorite.book_story.domain.util.UIText
|
||||
import ua.acclorite.book_story.presentation.components.LocalSettingsViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsEvent
|
||||
|
||||
/**
|
||||
|
|
@ -16,7 +17,6 @@ import ua.acclorite.book_story.presentation.screens.settings.data.SettingsEvent
|
|||
* @param fastColorPresetChangeEnabled Whether this is enabled.
|
||||
* @param isLoading Whether Reader is loading.
|
||||
* @param toolbarHidden Whether toolbar(selection) is hidden.
|
||||
* @param onSettingsEvent [SettingsEvent] callback.
|
||||
* @param presetChanged Callback when Color Preset was changed.
|
||||
*/
|
||||
@Composable
|
||||
|
|
@ -24,9 +24,10 @@ fun Modifier.readerFastColorPresetChange(
|
|||
fastColorPresetChangeEnabled: Boolean,
|
||||
isLoading: Boolean,
|
||||
toolbarHidden: Boolean,
|
||||
onSettingsEvent: (SettingsEvent) -> Unit,
|
||||
presetChanged: (UIText) -> Unit
|
||||
): Modifier {
|
||||
val onSettingsEvent = LocalSettingsViewModel.current.onEvent
|
||||
|
||||
val offset = remember { mutableFloatStateOf(0f) }
|
||||
return this.then(
|
||||
if (fastColorPresetChangeEnabled && toolbarHidden && !isLoading) {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import androidx.compose.ui.unit.Dp
|
|||
import androidx.compose.ui.unit.TextUnit
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.model.FontWithName
|
||||
import ua.acclorite.book_story.presentation.components.LocalReaderViewModel
|
||||
import ua.acclorite.book_story.presentation.data.showToast
|
||||
import ua.acclorite.book_story.presentation.screens.reader.data.ReaderEvent
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.reader.data.ReaderTextAlignment
|
||||
|
|
@ -43,7 +44,6 @@ import ua.acclorite.book_story.presentation.screens.settings.nested.reader.data.
|
|||
* @param paragraphIndentation Whether Paragraph Indentation is enabled for this line.
|
||||
* @param doubleClickTranslationEnabled Whether Double Click Translation is enabled.
|
||||
* @param toolbarHidden Whether selection toolBar is hidden.
|
||||
* @param onEvent [ReaderEvent] callback.
|
||||
*/
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
|
|
@ -60,9 +60,10 @@ fun LazyItemScope.ReaderTextParagraph(
|
|||
sidePadding: Dp,
|
||||
paragraphIndentation: Boolean,
|
||||
doubleClickTranslationEnabled: Boolean,
|
||||
toolbarHidden: Boolean,
|
||||
onEvent: (ReaderEvent) -> Unit
|
||||
toolbarHidden: Boolean
|
||||
) {
|
||||
val onEvent = LocalReaderViewModel.current.onEvent
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.animateItem(fadeInSpec = null, fadeOutSpec = null)
|
||||
|
|
|
|||
|
|
@ -14,36 +14,32 @@ import androidx.compose.material3.Slider
|
|||
import androidx.compose.material3.SliderDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.presentation.components.LocalHistoryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalLibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalReaderViewModel
|
||||
import ua.acclorite.book_story.presentation.data.removeDigits
|
||||
import ua.acclorite.book_story.presentation.data.removeTrailingZero
|
||||
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.data.ReaderEvent
|
||||
import ua.acclorite.book_story.presentation.screens.reader.data.ReaderState
|
||||
import ua.acclorite.book_story.presentation.ui.Colors
|
||||
|
||||
/**
|
||||
* Reader bottom bar. Has a slider to change progress.
|
||||
*
|
||||
* @param state [ReaderState].
|
||||
* @param onEvent [ReaderEvent] callback.
|
||||
* @param onLibraryUpdateEvent [LibraryEvent] callback.
|
||||
* @param onHistoryUpdateEvent [HistoryEvent] callback.
|
||||
*/
|
||||
@Composable
|
||||
fun ReaderBottomBar(
|
||||
state: State<ReaderState>,
|
||||
onEvent: (ReaderEvent) -> Unit,
|
||||
onLibraryUpdateEvent: (LibraryEvent.OnUpdateBook) -> Unit,
|
||||
onHistoryUpdateEvent: (HistoryEvent.OnUpdateBook) -> Unit
|
||||
) {
|
||||
fun ReaderBottomBar() {
|
||||
val state = LocalReaderViewModel.current.state
|
||||
val onEvent = LocalReaderViewModel.current.onEvent
|
||||
val onLibraryEvent = LocalLibraryViewModel.current.onEvent
|
||||
val onHistoryEvent = LocalHistoryViewModel.current.onEvent
|
||||
|
||||
val progress by remember(state.value.book.progress) {
|
||||
derivedStateOf {
|
||||
(state.value.book.progress * 100)
|
||||
|
|
@ -87,8 +83,8 @@ fun ReaderBottomBar(
|
|||
firstVisibleItemIndex = state.value.listState.firstVisibleItemIndex,
|
||||
firstVisibleItemOffset = 0,
|
||||
refreshList = { book ->
|
||||
onLibraryUpdateEvent(LibraryEvent.OnUpdateBook(book))
|
||||
onHistoryUpdateEvent(HistoryEvent.OnUpdateBook(book))
|
||||
onLibraryEvent(LibraryEvent.OnUpdateBook(book))
|
||||
onHistoryEvent(HistoryEvent.OnUpdateBook(book))
|
||||
}
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import androidx.compose.material3.Text
|
|||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
|
|
@ -22,34 +21,29 @@ import androidx.compose.ui.text.font.FontWeight
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.sp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.presentation.components.CustomIconButton
|
||||
import ua.acclorite.book_story.presentation.components.LocalHistoryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalLibraryViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalReaderViewModel
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.data.Screen
|
||||
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.data.ReaderEvent
|
||||
import ua.acclorite.book_story.presentation.screens.reader.data.ReaderState
|
||||
import ua.acclorite.book_story.presentation.ui.Colors
|
||||
|
||||
/**
|
||||
* Reader top bar. Displays title of the book.
|
||||
*
|
||||
* @param state [ReaderState].
|
||||
* @param onNavigate Navigator callback.
|
||||
* @param onEvent [ReaderEvent] callback.
|
||||
* @param onLibraryUpdateEvent [LibraryEvent] callback.
|
||||
* @param onHistoryUpdateEvent [HistoryEvent] callback.
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ReaderTopBar(
|
||||
state: State<ReaderState>,
|
||||
onNavigate: OnNavigate,
|
||||
onEvent: (ReaderEvent) -> Unit,
|
||||
onLibraryUpdateEvent: (LibraryEvent.OnUpdateBook) -> Unit,
|
||||
onHistoryUpdateEvent: (HistoryEvent.OnUpdateBook) -> Unit
|
||||
) {
|
||||
fun ReaderTopBar() {
|
||||
val state = LocalReaderViewModel.current.state
|
||||
val onEvent = LocalReaderViewModel.current.onEvent
|
||||
val onLibraryEvent = LocalLibraryViewModel.current.onEvent
|
||||
val onHistoryEvent = LocalHistoryViewModel.current.onEvent
|
||||
val context = LocalContext.current as ComponentActivity
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
|
||||
TopAppBar(
|
||||
navigationIcon = {
|
||||
|
|
@ -62,8 +56,8 @@ fun ReaderTopBar(
|
|||
ReaderEvent.OnGoBack(
|
||||
context = context,
|
||||
refreshList = {
|
||||
onLibraryUpdateEvent(LibraryEvent.OnUpdateBook(it))
|
||||
onHistoryUpdateEvent(HistoryEvent.OnUpdateBook(it))
|
||||
onLibraryEvent(LibraryEvent.OnUpdateBook(it))
|
||||
onHistoryEvent(HistoryEvent.OnUpdateBook(it))
|
||||
},
|
||||
navigate = {
|
||||
onNavigate {
|
||||
|
|
@ -94,8 +88,8 @@ fun ReaderTopBar(
|
|||
ReaderEvent.OnGoBack(
|
||||
context = context,
|
||||
refreshList = {
|
||||
onLibraryUpdateEvent(LibraryEvent.OnUpdateBook(it))
|
||||
onHistoryUpdateEvent(HistoryEvent.OnUpdateBook(it))
|
||||
onLibraryEvent(LibraryEvent.OnUpdateBook(it))
|
||||
onHistoryEvent(HistoryEvent.OnUpdateBook(it))
|
||||
},
|
||||
navigate = {
|
||||
onNavigate {
|
||||
|
|
|
|||
|
|
@ -14,67 +14,49 @@ import androidx.compose.material3.ExperimentalMaterial3Api
|
|||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.presentation.components.CustomBottomSheet
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.components.LocalReaderViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.reader.data.ReaderEvent
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsEvent
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.subcategories.ColorsSubcategory
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.ReaderSettingsCategory
|
||||
|
||||
/**
|
||||
* Settings bottom sheet. Has General and Colors categories.
|
||||
*
|
||||
* @param mainState [MainState].
|
||||
* @param settingsState [SettingsState].
|
||||
* @param onEvent [ReaderEvent] callback.
|
||||
* @param onMainEvent [MainEvent] callback.
|
||||
* @param onSettingsEvent [SettingsEvent] callback.
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ReaderSettingsBottomSheet(
|
||||
mainState: State<MainState>,
|
||||
settingsState: State<SettingsState>,
|
||||
onEvent: (ReaderEvent) -> Unit,
|
||||
onMainEvent: (MainEvent) -> Unit,
|
||||
onSettingsEvent: (SettingsEvent) -> Unit
|
||||
) {
|
||||
val pagerState = rememberPagerState { 2 }
|
||||
val currentPage by remember { derivedStateOf { pagerState.currentPage } }
|
||||
fun ReaderSettingsBottomSheet() {
|
||||
val state = LocalReaderViewModel.current.state
|
||||
val onEvent = LocalReaderViewModel.current.onEvent
|
||||
val context = LocalContext.current
|
||||
|
||||
val scrimColor = if (currentPage == 1) Color.Transparent
|
||||
else BottomSheetDefaults.ScrimColor
|
||||
val pagerState = rememberPagerState(state.value.currentPage) { 3 }
|
||||
|
||||
val animatedScrimColor by animateColorAsState(
|
||||
targetValue = scrimColor,
|
||||
animationSpec = tween(300),
|
||||
label = "Scrim animation"
|
||||
targetValue = if (pagerState.currentPage == 2) Color.Transparent
|
||||
else BottomSheetDefaults.ScrimColor,
|
||||
animationSpec = tween(300)
|
||||
)
|
||||
|
||||
val height = remember(currentPage) {
|
||||
if (currentPage == 1) 0.6f else 0.7f
|
||||
}
|
||||
val animatedHeight by animateFloatAsState(
|
||||
targetValue = height,
|
||||
animationSpec = tween(300),
|
||||
label = "Height animation"
|
||||
targetValue = if (pagerState.currentPage == 2) 0.6f else 0.7f,
|
||||
animationSpec = tween(300)
|
||||
)
|
||||
|
||||
LaunchedEffect(currentPage) {
|
||||
LaunchedEffect(pagerState.currentPage) {
|
||||
onEvent(
|
||||
ReaderEvent.OnScrollToSettingsPage(
|
||||
page = pagerState.currentPage,
|
||||
pagerState = null
|
||||
)
|
||||
)
|
||||
onEvent(
|
||||
ReaderEvent.OnShowHideMenu(
|
||||
currentPage != 1,
|
||||
pagerState.currentPage != 2,
|
||||
context as ComponentActivity
|
||||
)
|
||||
)
|
||||
|
|
@ -91,17 +73,14 @@ fun ReaderSettingsBottomSheet(
|
|||
onEvent(ReaderEvent.OnShowHideSettingsBottomSheet)
|
||||
}
|
||||
) {
|
||||
ReaderSettingsBottomSheetTabRow(
|
||||
onEvent = onEvent,
|
||||
pagerState = pagerState
|
||||
)
|
||||
ReaderSettingsBottomSheetTabRow(pagerState = pagerState)
|
||||
|
||||
HorizontalPager(state = pagerState) { page ->
|
||||
LazyColumn {
|
||||
if (page == 0) {
|
||||
if (page == 1) {
|
||||
LazyColumn {
|
||||
ReaderSettingsCategory(
|
||||
state = mainState,
|
||||
onMainEvent = onMainEvent,
|
||||
titleColor = { MaterialTheme.colorScheme.onSurface },
|
||||
topPadding = 16.dp,
|
||||
bottomPadding = 8.dp + it
|
||||
|
|
@ -109,13 +88,9 @@ fun ReaderSettingsBottomSheet(
|
|||
}
|
||||
}
|
||||
|
||||
LazyColumn {
|
||||
if (page == 1) {
|
||||
if (page == 2) {
|
||||
LazyColumn {
|
||||
ColorsSubcategory(
|
||||
state = mainState,
|
||||
settingsState = settingsState,
|
||||
onMainEvent = onMainEvent,
|
||||
onSettingsEvent = onSettingsEvent,
|
||||
showTitle = false,
|
||||
backgroundColor = { MaterialTheme.colorScheme.surfaceContainer },
|
||||
topPadding = 16.dp,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalReaderViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.reader.data.ReaderEvent
|
||||
|
||||
/**
|
||||
|
|
@ -24,6 +25,9 @@ fun ReaderSettingsBottomSheetTabRow(
|
|||
pagerState: PagerState
|
||||
) {
|
||||
val tabItems = listOf(
|
||||
fun ReaderSettingsBottomSheetTabRow(pagerState: PagerState) {
|
||||
val onEvent = LocalReaderViewModel.current.onEvent
|
||||
|
||||
stringResource(id = R.string.general_tab),
|
||||
stringResource(id = R.string.color_tab)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import androidx.compose.material3.Icon
|
|||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -33,16 +32,16 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.CustomCoverImage
|
||||
import ua.acclorite.book_story.presentation.screens.reader.data.ReaderState
|
||||
import ua.acclorite.book_story.presentation.components.LocalReaderViewModel
|
||||
|
||||
/**
|
||||
* Reader start item. Displays at the beginning of the book.
|
||||
*
|
||||
* @param state [ReaderState].
|
||||
*/
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
fun ReaderStartItem(state: State<ReaderState>) {
|
||||
fun ReaderStartItem() {
|
||||
val state = LocalReaderViewModel.current.state
|
||||
|
||||
val statusBarHeight = WindowInsets
|
||||
.statusBarsIgnoringVisibility
|
||||
.asPaddingValues()
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ sealed class ReaderEvent {
|
|||
|
||||
data class OnScroll(val progress: Float) : ReaderEvent()
|
||||
data object OnShowHideSettingsBottomSheet : ReaderEvent()
|
||||
data class OnScrollToSettingsPage(val page: Int, val pagerState: PagerState) : ReaderEvent()
|
||||
data class OnScrollToSettingsPage(val page: Int, val pagerState: PagerState?) : ReaderEvent()
|
||||
data class OnMoveBookToAlreadyRead(
|
||||
val context: ComponentActivity,
|
||||
val onUpdateCategories: (Book) -> Unit,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import androidx.compose.runtime.snapshotFlow
|
|||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -32,12 +31,11 @@ import ua.acclorite.book_story.domain.use_case.GetBookById
|
|||
import ua.acclorite.book_story.domain.use_case.GetLatestHistory
|
||||
import ua.acclorite.book_story.domain.use_case.GetText
|
||||
import ua.acclorite.book_story.domain.use_case.UpdateBooks
|
||||
import ua.acclorite.book_story.domain.util.BaseViewModel
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.domain.util.UIText
|
||||
import ua.acclorite.book_story.presentation.data.Screen
|
||||
import ua.acclorite.book_story.presentation.data.launchActivity
|
||||
import ua.acclorite.book_story.presentation.screens.history.data.HistoryEvent
|
||||
import ua.acclorite.book_story.presentation.screens.library.data.LibraryEvent
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
|
@ -48,14 +46,14 @@ class ReaderViewModel @Inject constructor(
|
|||
private val getText: GetText,
|
||||
private val getLatestHistory: GetLatestHistory,
|
||||
private val getBookById: GetBookById
|
||||
) : ViewModel() {
|
||||
) : BaseViewModel<ReaderState, ReaderEvent>() {
|
||||
|
||||
private val _state = MutableStateFlow(ReaderState())
|
||||
val state = _state.asStateFlow()
|
||||
override val state = _state.asStateFlow()
|
||||
|
||||
private var eventJob = SupervisorJob()
|
||||
|
||||
fun onEvent(event: ReaderEvent) {
|
||||
override fun onEvent(event: ReaderEvent) {
|
||||
viewModelScope.launch(eventJob + Dispatchers.Main) {
|
||||
when (event) {
|
||||
is ReaderEvent.OnTextIsEmpty -> {
|
||||
|
|
@ -269,7 +267,6 @@ class ReaderViewModel @Inject constructor(
|
|||
launch(Dispatchers.IO) {
|
||||
_state.update {
|
||||
it.copy(
|
||||
currentPage = if (it.showSettingsBottomSheet) it.currentPage else 0,
|
||||
showSettingsBottomSheet = !it.showSettingsBottomSheet
|
||||
)
|
||||
}
|
||||
|
|
@ -278,7 +275,13 @@ class ReaderViewModel @Inject constructor(
|
|||
|
||||
is ReaderEvent.OnScrollToSettingsPage -> {
|
||||
launch {
|
||||
event.pagerState.scrollToPage(event.page)
|
||||
_state.update {
|
||||
event.pagerState?.scrollToPage(event.page)
|
||||
|
||||
it.copy(
|
||||
currentPage = event.page
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -498,10 +501,7 @@ class ReaderViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
fun onUpdateProgress(
|
||||
onLibraryEvent: (LibraryEvent) -> Unit,
|
||||
onHistoryEvent: (HistoryEvent) -> Unit
|
||||
) {
|
||||
fun onUpdateProgress(refreshList: (Book) -> Unit) {
|
||||
viewModelScope.launch {
|
||||
snapshotFlow {
|
||||
_state.value.listState.firstVisibleItemIndex to _state.value.listState.firstVisibleItemScrollOffset
|
||||
|
|
@ -538,8 +538,7 @@ class ReaderViewModel @Inject constructor(
|
|||
firstVisibleItemIndex = firstVisibleItemIndex,
|
||||
firstVisibleItemOffset = firstVisibleItemScrollOffset,
|
||||
refreshList = { book ->
|
||||
onLibraryEvent(LibraryEvent.OnUpdateBook(book))
|
||||
onHistoryEvent(HistoryEvent.OnUpdateBook(book))
|
||||
refreshList(book)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -24,26 +24,22 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.presentation.components.CustomLazyColumn
|
||||
import ua.acclorite.book_story.presentation.components.GoBackButton
|
||||
import ua.acclorite.book_story.presentation.components.collapsibleUntilExitScrollBehaviorWithLazyListState
|
||||
import ua.acclorite.book_story.presentation.data.LocalNavigator
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.data.Screen
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.SettingsCategoryItem
|
||||
|
||||
@Composable
|
||||
fun SettingsScreenRoot() {
|
||||
val navigator = LocalNavigator.current
|
||||
|
||||
SettingsScreen(onNavigate = { navigator.it() })
|
||||
SettingsScreen()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun SettingsScreen(
|
||||
onNavigate: OnNavigate
|
||||
) {
|
||||
private fun SettingsScreen() {
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
val scrollState = TopAppBarDefaults.collapsibleUntilExitScrollBehaviorWithLazyListState()
|
||||
|
||||
Scaffold(
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package ua.acclorite.book_story.presentation.screens.settings.data
|
|||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.isGranted
|
||||
|
|
@ -24,6 +23,7 @@ import ua.acclorite.book_story.domain.use_case.GetColorPresets
|
|||
import ua.acclorite.book_story.domain.use_case.ReorderColorPresets
|
||||
import ua.acclorite.book_story.domain.use_case.SelectColorPreset
|
||||
import ua.acclorite.book_story.domain.use_case.UpdateColorPreset
|
||||
import ua.acclorite.book_story.domain.util.BaseViewModel
|
||||
import ua.acclorite.book_story.domain.util.Constants
|
||||
import ua.acclorite.book_story.domain.util.ID
|
||||
import ua.acclorite.book_story.domain.util.UIText
|
||||
|
|
@ -39,10 +39,10 @@ class SettingsViewModel @Inject constructor(
|
|||
private val deleteColorPreset: DeleteColorPreset,
|
||||
private val selectColorPreset: SelectColorPreset,
|
||||
private val reorderColorPresets: ReorderColorPresets
|
||||
) : ViewModel() {
|
||||
) : BaseViewModel<SettingsState, SettingsEvent>() {
|
||||
|
||||
private val _state = MutableStateFlow(SettingsState())
|
||||
val state = _state.asStateFlow()
|
||||
override val state = _state.asStateFlow()
|
||||
|
||||
private val _isReady = MutableStateFlow(false)
|
||||
val isReady = _isReady.asStateFlow()
|
||||
|
|
@ -93,7 +93,7 @@ class SettingsViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
@Suppress("LABEL_NAME_CLASH")
|
||||
fun onEvent(event: SettingsEvent) {
|
||||
override fun onEvent(event: SettingsEvent) {
|
||||
when (event) {
|
||||
is SettingsEvent.OnGeneralChangeCheckForUpdates -> {
|
||||
if (!event.enable) {
|
||||
|
|
|
|||
|
|
@ -13,53 +13,25 @@ import androidx.compose.material3.Scaffold
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.presentation.components.CustomLazyColumn
|
||||
import ua.acclorite.book_story.presentation.components.GoBackButton
|
||||
import ua.acclorite.book_story.presentation.components.collapsibleUntilExitScrollBehaviorWithLazyListState
|
||||
import ua.acclorite.book_story.presentation.data.LocalNavigator
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.data.MainViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsEvent
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsViewModel
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.AppearanceSettingsCategory
|
||||
|
||||
@Composable
|
||||
fun AppearanceSettingsRoot() {
|
||||
val navigator = LocalNavigator.current
|
||||
val mainViewModel: MainViewModel = hiltViewModel()
|
||||
val settingsViewModel: SettingsViewModel = hiltViewModel()
|
||||
|
||||
val state = mainViewModel.state.collectAsState()
|
||||
val settingsState = settingsViewModel.state.collectAsState()
|
||||
|
||||
AppearanceSettings(
|
||||
state = state,
|
||||
settingsState = settingsState,
|
||||
onNavigate = { navigator.it() },
|
||||
onMainEvent = mainViewModel::onEvent,
|
||||
onSettingsEvent = settingsViewModel::onEvent
|
||||
)
|
||||
AppearanceSettings()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun AppearanceSettings(
|
||||
state: State<MainState>,
|
||||
settingsState: State<SettingsState>,
|
||||
onNavigate: OnNavigate,
|
||||
onMainEvent: (MainEvent) -> Unit,
|
||||
onSettingsEvent: (SettingsEvent) -> Unit
|
||||
) {
|
||||
private fun AppearanceSettings() {
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
val scrollState = TopAppBarDefaults.collapsibleUntilExitScrollBehaviorWithLazyListState()
|
||||
|
||||
Scaffold(
|
||||
|
|
@ -91,12 +63,7 @@ private fun AppearanceSettings(
|
|||
.padding(top = paddingValues.calculateTopPadding()),
|
||||
state = scrollState.second
|
||||
) {
|
||||
AppearanceSettingsCategory(
|
||||
state = state,
|
||||
settingsState = settingsState,
|
||||
onMainEvent = onMainEvent,
|
||||
onSettingsEvent = onSettingsEvent
|
||||
)
|
||||
AppearanceSettingsCategory()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,14 +5,9 @@ package ua.acclorite.book_story.presentation.screens.settings.nested.appearance.
|
|||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsEvent
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.subcategories.ColorsSubcategory
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.subcategories.ThemePreferencesSubcategory
|
||||
|
||||
|
|
@ -20,34 +15,21 @@ import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.c
|
|||
* Appearance Settings Category.
|
||||
* Contains all Appearance settings such as Theme.
|
||||
*
|
||||
* @param state [MainState] instance.
|
||||
* @param onMainEvent [MainEvent] callback.
|
||||
* @param onSettingsEvent [SettingsEvent] callback.
|
||||
* @param titleColor Title's color.
|
||||
* @param topPadding Top padding to be applied.
|
||||
* @param bottomPadding Bottom padding to be applied.
|
||||
*/
|
||||
fun LazyListScope.AppearanceSettingsCategory(
|
||||
state: State<MainState>,
|
||||
settingsState: State<SettingsState>,
|
||||
onMainEvent: (MainEvent) -> Unit,
|
||||
onSettingsEvent: (SettingsEvent) -> Unit,
|
||||
titleColor: @Composable () -> Color = { MaterialTheme.colorScheme.primary },
|
||||
topPadding: Dp = 16.dp,
|
||||
bottomPadding: Dp = 48.dp
|
||||
) {
|
||||
ThemePreferencesSubcategory(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent,
|
||||
titleColor = titleColor,
|
||||
topPadding = topPadding,
|
||||
bottomPadding = 0.dp
|
||||
)
|
||||
ColorsSubcategory(
|
||||
state = state,
|
||||
settingsState = settingsState,
|
||||
onMainEvent = onMainEvent,
|
||||
onSettingsEvent = onSettingsEvent,
|
||||
titleColor = titleColor,
|
||||
topPadding = 22.dp,
|
||||
bottomPadding = bottomPadding
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
|
|
@ -64,10 +63,10 @@ import ua.acclorite.book_story.domain.util.Selected
|
|||
import ua.acclorite.book_story.presentation.components.CategoryTitle
|
||||
import ua.acclorite.book_story.presentation.components.CustomAnimatedVisibility
|
||||
import ua.acclorite.book_story.presentation.components.CustomIconButton
|
||||
import ua.acclorite.book_story.presentation.components.LocalSettingsViewModel
|
||||
import ua.acclorite.book_story.presentation.components.customItemsIndexed
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.ColorPickerWithTitle
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsEvent
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsState
|
||||
import ua.acclorite.book_story.presentation.ui.FadeTransitionPreservingSpace
|
||||
import ua.acclorite.book_story.presentation.ui.Transitions
|
||||
|
||||
|
|
@ -78,13 +77,14 @@ import ua.acclorite.book_story.presentation.ui.Transitions
|
|||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun ColorPresetSetting(
|
||||
state: State<SettingsState>,
|
||||
onEvent: (SettingsEvent) -> Unit,
|
||||
backgroundColor: Color,
|
||||
verticalPadding: Dp = 8.dp,
|
||||
horizontalPadding: Dp = 18.dp
|
||||
) {
|
||||
val state = LocalSettingsViewModel.current.state
|
||||
val onEvent = LocalSettingsViewModel.current.onEvent
|
||||
val context = LocalContext.current
|
||||
|
||||
val reorderableListState = rememberReorderableLazyListState(
|
||||
lazyListState = state.value.colorPresetsListState
|
||||
) { from, to ->
|
||||
|
|
|
|||
|
|
@ -2,12 +2,11 @@ package ua.acclorite.book_story.presentation.screens.settings.nested.appearance.
|
|||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.model.ButtonItem
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.SegmentedButtonWithTitle
|
||||
import ua.acclorite.book_story.presentation.ui.DarkTheme
|
||||
|
||||
|
|
@ -16,10 +15,10 @@ import ua.acclorite.book_story.presentation.ui.DarkTheme
|
|||
* If true, dark theme applied to the app's theme.
|
||||
*/
|
||||
@Composable
|
||||
fun DarkThemeSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
fun DarkThemeSetting() {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
SegmentedButtonWithTitle(
|
||||
title = stringResource(id = R.string.dark_theme_option),
|
||||
buttons = DarkTheme.entries.map {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
package ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.settings
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.SwitchWithTitle
|
||||
|
||||
/**
|
||||
|
|
@ -13,10 +12,10 @@ import ua.acclorite.book_story.presentation.screens.settings.components.SwitchWi
|
|||
* If true, user can fast change color presets in Reader with swipes.
|
||||
*/
|
||||
@Composable
|
||||
fun FastColorPresetChangeSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
fun FastColorPresetChangeSetting() {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
SwitchWithTitle(
|
||||
selected = state.value.fastColorPresetChange,
|
||||
title = stringResource(id = R.string.fast_color_preset_change_option),
|
||||
|
|
|
|||
|
|
@ -2,12 +2,11 @@ package ua.acclorite.book_story.presentation.screens.settings.nested.appearance.
|
|||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.model.ButtonItem
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.SegmentedButtonWithTitle
|
||||
import ua.acclorite.book_story.presentation.ui.ExpandingTransition
|
||||
import ua.acclorite.book_story.presentation.ui.PureDark
|
||||
|
|
@ -18,10 +17,10 @@ import ua.acclorite.book_story.presentation.ui.isDark
|
|||
* If true, enables Pure Dark (OLED) theme.
|
||||
*/
|
||||
@Composable
|
||||
fun PureDarkSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
fun PureDarkSetting() {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
ExpandingTransition(visible = state.value.darkTheme.isDark()) {
|
||||
SegmentedButtonWithTitle(
|
||||
title = stringResource(id = R.string.pure_dark_option),
|
||||
|
|
|
|||
|
|
@ -3,15 +3,14 @@ package ua.acclorite.book_story.presentation.screens.settings.nested.appearance.
|
|||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.model.ButtonItem
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.SegmentedButtonWithTitle
|
||||
import ua.acclorite.book_story.presentation.ui.BookStoryTheme
|
||||
import ua.acclorite.book_story.presentation.ui.ExpandingTransition
|
||||
|
|
@ -25,10 +24,10 @@ import ua.acclorite.book_story.presentation.ui.isPureDark
|
|||
* Lets user change theme contrast levels.
|
||||
*/
|
||||
@Composable
|
||||
fun ThemeContrastSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
fun ThemeContrastSetting() {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
val themeContrastTheme = remember { mutableStateOf(state.value.theme) }
|
||||
|
||||
LaunchedEffect(state.value.theme) {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import androidx.compose.material3.Icon
|
|||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -42,9 +41,9 @@ import ua.acclorite.book_story.domain.util.Constants
|
|||
import ua.acclorite.book_story.domain.util.UIText
|
||||
import ua.acclorite.book_story.presentation.components.CategoryTitle
|
||||
import ua.acclorite.book_story.presentation.components.CustomAnimatedVisibility
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.components.customItemsIndexed
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.ui.Theme
|
||||
import ua.acclorite.book_story.presentation.ui.ThemeContrast
|
||||
import ua.acclorite.book_story.presentation.ui.animatedColorScheme
|
||||
|
|
@ -57,11 +56,12 @@ import ua.acclorite.book_story.presentation.ui.isPureDark
|
|||
*/
|
||||
@Composable
|
||||
fun ThemeSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit,
|
||||
verticalPadding: Dp = 8.dp,
|
||||
horizontalPadding: Dp = 18.dp
|
||||
) {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
val themes = remember {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) Constants.THEMES
|
||||
else Constants.THEMES.dropWhile { it.first == Theme.DYNAMIC }
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
|
@ -17,10 +16,6 @@ import androidx.compose.ui.unit.coerceAtLeast
|
|||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.CategoryTitle
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsEvent
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.settings.ColorPresetSetting
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.settings.FastColorPresetChangeSetting
|
||||
|
||||
|
|
@ -29,10 +24,6 @@ import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.c
|
|||
* Contains all settings from Colors.
|
||||
*/
|
||||
fun LazyListScope.ColorsSubcategory(
|
||||
state: State<MainState>,
|
||||
settingsState: State<SettingsState>,
|
||||
onMainEvent: (MainEvent) -> Unit,
|
||||
onSettingsEvent: (SettingsEvent) -> Unit,
|
||||
titleColor: @Composable () -> Color = { MaterialTheme.colorScheme.primary },
|
||||
title: @Composable () -> String = { stringResource(id = R.string.colors_appearance_settings) },
|
||||
backgroundColor: @Composable () -> Color = { MaterialTheme.colorScheme.surfaceContainerLow },
|
||||
|
|
@ -59,18 +50,11 @@ fun LazyListScope.ColorsSubcategory(
|
|||
}
|
||||
|
||||
item {
|
||||
ColorPresetSetting(
|
||||
state = settingsState,
|
||||
backgroundColor = backgroundColor.invoke(),
|
||||
onEvent = onSettingsEvent
|
||||
)
|
||||
ColorPresetSetting(backgroundColor = backgroundColor.invoke())
|
||||
}
|
||||
|
||||
item {
|
||||
FastColorPresetChangeSetting(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent
|
||||
)
|
||||
FastColorPresetChangeSetting()
|
||||
}
|
||||
|
||||
item {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
|
@ -17,8 +16,6 @@ import androidx.compose.ui.unit.coerceAtLeast
|
|||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.CategoryTitle
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.settings.DarkThemeSetting
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.settings.PureDarkSetting
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.components.settings.ThemeContrastSetting
|
||||
|
|
@ -29,8 +26,6 @@ import ua.acclorite.book_story.presentation.screens.settings.nested.appearance.c
|
|||
* Contains all settings from Theme Preferences.
|
||||
*/
|
||||
fun LazyListScope.ThemePreferencesSubcategory(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit,
|
||||
titleColor: @Composable () -> Color = { MaterialTheme.colorScheme.primary },
|
||||
title: @Composable () -> String = { stringResource(id = R.string.theme_appearance_settings) },
|
||||
showTitle: Boolean = true,
|
||||
|
|
@ -56,31 +51,19 @@ fun LazyListScope.ThemePreferencesSubcategory(
|
|||
}
|
||||
|
||||
item {
|
||||
DarkThemeSetting(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent
|
||||
)
|
||||
DarkThemeSetting()
|
||||
}
|
||||
|
||||
item {
|
||||
ThemeSetting(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent
|
||||
)
|
||||
ThemeSetting()
|
||||
}
|
||||
|
||||
item {
|
||||
ThemeContrastSetting(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent
|
||||
)
|
||||
ThemeContrastSetting()
|
||||
}
|
||||
|
||||
item {
|
||||
PureDarkSetting(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent
|
||||
)
|
||||
PureDarkSetting()
|
||||
}
|
||||
|
||||
item {
|
||||
|
|
|
|||
|
|
@ -13,44 +13,25 @@ import androidx.compose.material3.Scaffold
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.presentation.components.CustomLazyColumn
|
||||
import ua.acclorite.book_story.presentation.components.GoBackButton
|
||||
import ua.acclorite.book_story.presentation.components.collapsibleUntilExitScrollBehaviorWithLazyListState
|
||||
import ua.acclorite.book_story.presentation.data.LocalNavigator
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.data.MainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.components.BrowseSettingsCategory
|
||||
|
||||
@Composable
|
||||
fun BrowseSettingsRoot() {
|
||||
val navigator = LocalNavigator.current
|
||||
val mainViewModel: MainViewModel = hiltViewModel()
|
||||
|
||||
val state = mainViewModel.state.collectAsState()
|
||||
|
||||
BrowseSettings(
|
||||
state = state,
|
||||
onNavigate = { navigator.it() },
|
||||
onMainEvent = mainViewModel::onEvent
|
||||
)
|
||||
BrowseSettings()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun BrowseSettings(
|
||||
state: State<MainState>,
|
||||
onNavigate: OnNavigate,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
private fun BrowseSettings() {
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
val scrollState = TopAppBarDefaults.collapsibleUntilExitScrollBehaviorWithLazyListState()
|
||||
|
||||
Scaffold(
|
||||
|
|
@ -82,10 +63,7 @@ private fun BrowseSettings(
|
|||
.padding(top = paddingValues.calculateTopPadding()),
|
||||
state = scrollState.second
|
||||
) {
|
||||
BrowseSettingsCategory(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent
|
||||
)
|
||||
BrowseSettingsCategory()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,11 +3,8 @@
|
|||
package ua.acclorite.book_story.presentation.screens.settings.nested.browse.components
|
||||
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.components.subcategories.BrowseFilterSubcategory
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.components.subcategories.BrowseGeneralSubcategory
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.components.subcategories.BrowseSortSubcategory
|
||||
|
|
@ -16,32 +13,22 @@ import ua.acclorite.book_story.presentation.screens.settings.nested.browse.compo
|
|||
* Browse Settings Category.
|
||||
* Contains all Browse settings.
|
||||
*
|
||||
* @param state [MainState] instance.
|
||||
* @param onMainEvent [MainEvent] callback.
|
||||
* @param topPadding Top padding to be applied.
|
||||
* @param bottomPadding Bottom padding to be applied.
|
||||
*/
|
||||
fun LazyListScope.BrowseSettingsCategory(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit,
|
||||
topPadding: Dp = 16.dp,
|
||||
bottomPadding: Dp = 48.dp
|
||||
) {
|
||||
BrowseGeneralSubcategory(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent,
|
||||
topPadding = topPadding,
|
||||
bottomPadding = 0.dp
|
||||
)
|
||||
BrowseFilterSubcategory(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent,
|
||||
topPadding = 22.dp,
|
||||
bottomPadding = 0.dp
|
||||
)
|
||||
BrowseSortSubcategory(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent,
|
||||
topPadding = 22.dp,
|
||||
bottomPadding = bottomPadding
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,12 +2,11 @@ package ua.acclorite.book_story.presentation.screens.settings.nested.browse.comp
|
|||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.model.ButtonItem
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.SegmentedButtonWithTitle
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.data.BrowseFilesStructure
|
||||
|
||||
|
|
@ -16,10 +15,10 @@ import ua.acclorite.book_story.presentation.screens.settings.nested.browse.data.
|
|||
* Lets user choose between all and folders structure for Browse.
|
||||
*/
|
||||
@Composable
|
||||
fun BrowseFilesStructureSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
fun BrowseFilesStructureSetting() {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
SegmentedButtonWithTitle(
|
||||
title = stringResource(id = R.string.browse_files_structure_option),
|
||||
buttons = BrowseFilesStructure.entries.map {
|
||||
|
|
|
|||
|
|
@ -13,25 +13,24 @@ import androidx.compose.material3.Checkbox
|
|||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.domain.util.Constants
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.components.customItems
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
|
||||
/**
|
||||
* Browse Filter setting.
|
||||
* Lets user choose which items to filter in Browse.
|
||||
*/
|
||||
fun LazyListScope.BrowseFilterSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
fun LazyListScope.BrowseFilterSetting() {
|
||||
customItems(Constants.EXTENSIONS, key = { it }) {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
FilterItem(
|
||||
item = it,
|
||||
isSelected = state.value.browseIncludedFilterItems.any { item ->
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
package ua.acclorite.book_story.presentation.screens.settings.nested.browse.components.settings
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.SliderWithTitle
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.data.BrowseLayout
|
||||
import ua.acclorite.book_story.presentation.ui.ExpandingTransition
|
||||
|
|
@ -15,10 +14,10 @@ import ua.acclorite.book_story.presentation.ui.ExpandingTransition
|
|||
* Lets user specify grid size to be displayed.
|
||||
*/
|
||||
@Composable
|
||||
fun BrowseGridSizeSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
fun BrowseGridSizeSetting() {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
ExpandingTransition(visible = state.value.browseLayout == BrowseLayout.GRID) {
|
||||
SliderWithTitle(
|
||||
value = state.value.browseGridSize
|
||||
|
|
|
|||
|
|
@ -2,12 +2,11 @@ package ua.acclorite.book_story.presentation.screens.settings.nested.browse.comp
|
|||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.model.ButtonItem
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.SegmentedButtonWithTitle
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.data.BrowseLayout
|
||||
|
||||
|
|
@ -16,10 +15,10 @@ import ua.acclorite.book_story.presentation.screens.settings.nested.browse.data.
|
|||
* Lets user choose between layouts(list, grid).
|
||||
*/
|
||||
@Composable
|
||||
fun BrowseLayoutSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
fun BrowseLayoutSetting() {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
SegmentedButtonWithTitle(
|
||||
title = stringResource(id = R.string.browse_layout_option),
|
||||
buttons = BrowseLayout.entries.map {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
package ua.acclorite.book_story.presentation.screens.settings.nested.browse.components.settings
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.SwitchWithTitle
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.data.BrowseFilesStructure
|
||||
import ua.acclorite.book_story.presentation.ui.ExpandingTransition
|
||||
|
|
@ -15,10 +14,10 @@ import ua.acclorite.book_story.presentation.ui.ExpandingTransition
|
|||
* If true, shows all favorite directories in root directory and moves them to the top in nested directories.
|
||||
*/
|
||||
@Composable
|
||||
fun BrowsePinFavoriteDirectoriesSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
fun BrowsePinFavoriteDirectoriesSetting() {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
ExpandingTransition(visible = state.value.browseFilesStructure == BrowseFilesStructure.DIRECTORIES) {
|
||||
SwitchWithTitle(
|
||||
selected = state.value.browsePinFavoriteDirectories,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import androidx.compose.material3.Icon
|
|||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
|
@ -25,20 +24,20 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.components.customItems
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.data.BrowseSortOrder
|
||||
|
||||
/**
|
||||
* Browse Sort Order setting.
|
||||
* Lets user choose how to sort files in Browse.
|
||||
*/
|
||||
fun LazyListScope.BrowseSortOrderSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
fun LazyListScope.BrowseSortOrderSetting() {
|
||||
customItems(BrowseSortOrder.entries, key = { it.name }) {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
SortItem(
|
||||
item = it,
|
||||
isSelected = state.value.browseSortOrder == it,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
|
@ -17,8 +16,6 @@ import androidx.compose.ui.unit.coerceAtLeast
|
|||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.CategoryTitle
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.components.settings.BrowseFilterSetting
|
||||
|
||||
/**
|
||||
|
|
@ -26,8 +23,6 @@ import ua.acclorite.book_story.presentation.screens.settings.nested.browse.compo
|
|||
* Contains all settings from Filter Browse settings.
|
||||
*/
|
||||
fun LazyListScope.BrowseFilterSubcategory(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit,
|
||||
titleColor: @Composable () -> Color = { MaterialTheme.colorScheme.primary },
|
||||
title: @Composable () -> String = { stringResource(id = R.string.filter_browse_settings) },
|
||||
showTitle: Boolean = true,
|
||||
|
|
@ -52,10 +47,7 @@ fun LazyListScope.BrowseFilterSubcategory(
|
|||
}
|
||||
}
|
||||
|
||||
BrowseFilterSetting(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent
|
||||
)
|
||||
BrowseFilterSetting()
|
||||
|
||||
item {
|
||||
Spacer(
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
|
@ -17,8 +16,6 @@ import androidx.compose.ui.unit.coerceAtLeast
|
|||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.CategoryTitle
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.components.settings.BrowseFilesStructureSetting
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.components.settings.BrowseGridSizeSetting
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.components.settings.BrowseLayoutSetting
|
||||
|
|
@ -29,8 +26,6 @@ import ua.acclorite.book_story.presentation.screens.settings.nested.browse.compo
|
|||
* Contains all settings from General Browse settings.
|
||||
*/
|
||||
fun LazyListScope.BrowseGeneralSubcategory(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit,
|
||||
titleColor: @Composable () -> Color = { MaterialTheme.colorScheme.primary },
|
||||
title: @Composable () -> String = { stringResource(id = R.string.general_browse_settings) },
|
||||
showTitle: Boolean = true,
|
||||
|
|
@ -56,31 +51,19 @@ fun LazyListScope.BrowseGeneralSubcategory(
|
|||
}
|
||||
|
||||
item {
|
||||
BrowseFilesStructureSetting(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent
|
||||
)
|
||||
BrowseFilesStructureSetting()
|
||||
}
|
||||
|
||||
item {
|
||||
BrowsePinFavoriteDirectoriesSetting(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent
|
||||
)
|
||||
BrowsePinFavoriteDirectoriesSetting()
|
||||
}
|
||||
|
||||
item {
|
||||
BrowseLayoutSetting(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent
|
||||
)
|
||||
BrowseLayoutSetting()
|
||||
}
|
||||
|
||||
item {
|
||||
BrowseGridSizeSetting(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent
|
||||
)
|
||||
BrowseGridSizeSetting()
|
||||
}
|
||||
|
||||
item {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
|
@ -17,8 +16,6 @@ import androidx.compose.ui.unit.coerceAtLeast
|
|||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.CategoryTitle
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.browse.components.settings.BrowseSortOrderSetting
|
||||
|
||||
/**
|
||||
|
|
@ -26,8 +23,6 @@ import ua.acclorite.book_story.presentation.screens.settings.nested.browse.compo
|
|||
* Contains all settings from Sort Browse settings.
|
||||
*/
|
||||
fun LazyListScope.BrowseSortSubcategory(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit,
|
||||
titleColor: @Composable () -> Color = { MaterialTheme.colorScheme.primary },
|
||||
title: @Composable () -> String = { stringResource(id = R.string.sort_browse_settings) },
|
||||
showTitle: Boolean = true,
|
||||
|
|
@ -52,10 +47,7 @@ fun LazyListScope.BrowseSortSubcategory(
|
|||
}
|
||||
}
|
||||
|
||||
BrowseSortOrderSetting(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent
|
||||
)
|
||||
BrowseSortOrderSetting()
|
||||
|
||||
item {
|
||||
Spacer(
|
||||
|
|
|
|||
|
|
@ -12,50 +12,26 @@ import androidx.compose.material3.Scaffold
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.presentation.components.CustomLazyColumn
|
||||
import ua.acclorite.book_story.presentation.components.GoBackButton
|
||||
import ua.acclorite.book_story.presentation.components.collapsibleUntilExitScrollBehaviorWithLazyListState
|
||||
import ua.acclorite.book_story.presentation.data.LocalNavigator
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.data.MainViewModel
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsEvent
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsViewModel
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.general.components.GeneralSettingsCategory
|
||||
|
||||
@Composable
|
||||
fun GeneralSettingsRoot() {
|
||||
val navigator = LocalNavigator.current
|
||||
val settingsViewModel: SettingsViewModel = hiltViewModel()
|
||||
val mainViewModel: MainViewModel = hiltViewModel()
|
||||
|
||||
val state = mainViewModel.state.collectAsState()
|
||||
|
||||
GeneralSettings(
|
||||
state = state,
|
||||
onNavigate = { navigator.it() },
|
||||
onSettingsEvent = settingsViewModel::onEvent,
|
||||
onMainEvent = mainViewModel::onEvent
|
||||
)
|
||||
GeneralSettings()
|
||||
}
|
||||
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun GeneralSettings(
|
||||
state: State<MainState>,
|
||||
onNavigate: OnNavigate,
|
||||
onSettingsEvent: (SettingsEvent) -> Unit,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
private fun GeneralSettings() {
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
val scrollState = TopAppBarDefaults.collapsibleUntilExitScrollBehaviorWithLazyListState()
|
||||
|
||||
Scaffold(
|
||||
|
|
@ -86,11 +62,7 @@ private fun GeneralSettings(
|
|||
.padding(top = paddingValues.calculateTopPadding()),
|
||||
state = scrollState.second
|
||||
) {
|
||||
GeneralSettingsCategory(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent,
|
||||
onSettingsEvent = onSettingsEvent
|
||||
)
|
||||
GeneralSettingsCategory()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,14 +5,10 @@ package ua.acclorite.book_story.presentation.screens.settings.nested.general.com
|
|||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.coerceAtLeast
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsEvent
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.general.components.settings.AppLanguageSetting
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.general.components.settings.CheckForUpdatesSetting
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.general.components.settings.DoublePressExitSetting
|
||||
|
|
@ -21,16 +17,10 @@ import ua.acclorite.book_story.presentation.screens.settings.nested.general.comp
|
|||
* General Settings Category.
|
||||
* Contains all General settings such as App Language.
|
||||
*
|
||||
* @param state [MainState] instance.
|
||||
* @param onMainEvent [MainEvent] callback.
|
||||
* @param onSettingsEvent [SettingsEvent] callback.
|
||||
* @param topPadding Top padding to be applied.
|
||||
* @param bottomPadding Bottom padding to be applied.
|
||||
*/
|
||||
fun LazyListScope.GeneralSettingsCategory(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit,
|
||||
onSettingsEvent: (SettingsEvent) -> Unit,
|
||||
topPadding: Dp = 16.dp,
|
||||
bottomPadding: Dp = 48.dp
|
||||
) {
|
||||
|
|
@ -41,25 +31,15 @@ fun LazyListScope.GeneralSettingsCategory(
|
|||
}
|
||||
|
||||
item {
|
||||
AppLanguageSetting(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent
|
||||
)
|
||||
AppLanguageSetting()
|
||||
}
|
||||
|
||||
item {
|
||||
CheckForUpdatesSetting(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent,
|
||||
onSettingsEvent = onSettingsEvent
|
||||
)
|
||||
CheckForUpdatesSetting()
|
||||
}
|
||||
|
||||
item {
|
||||
DoublePressExitSetting(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent
|
||||
)
|
||||
DoublePressExitSetting()
|
||||
}
|
||||
|
||||
item {
|
||||
|
|
|
|||
|
|
@ -2,13 +2,12 @@ package ua.acclorite.book_story.presentation.screens.settings.nested.general.com
|
|||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.model.ButtonItem
|
||||
import ua.acclorite.book_story.domain.util.Constants
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.ChipsWithTitle
|
||||
|
||||
/**
|
||||
|
|
@ -16,10 +15,10 @@ import ua.acclorite.book_story.presentation.screens.settings.components.ChipsWit
|
|||
* Changes app's language.
|
||||
*/
|
||||
@Composable
|
||||
fun AppLanguageSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
fun AppLanguageSetting() {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
ChipsWithTitle(
|
||||
title = stringResource(id = R.string.language_option),
|
||||
chips = Constants.LANGUAGES.sortedBy { it.second }.map {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import androidx.activity.ComponentActivity
|
|||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Security
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
|
|
@ -14,9 +13,10 @@ import androidx.compose.ui.res.stringResource
|
|||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.rememberPermissionState
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.components.LocalSettingsViewModel
|
||||
import ua.acclorite.book_story.presentation.components.custom_dialog.CustomDialogWithContent
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.SwitchWithTitle
|
||||
import ua.acclorite.book_story.presentation.screens.settings.data.SettingsEvent
|
||||
|
||||
|
|
@ -27,12 +27,12 @@ import ua.acclorite.book_story.presentation.screens.settings.data.SettingsEvent
|
|||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@SuppressLint("InlinedApi")
|
||||
@Composable
|
||||
fun CheckForUpdatesSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit,
|
||||
onSettingsEvent: (SettingsEvent) -> Unit
|
||||
) {
|
||||
fun CheckForUpdatesSetting() {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
val onSettingsEvent = LocalSettingsViewModel.current.onEvent
|
||||
val activity = LocalContext.current as ComponentActivity
|
||||
|
||||
val notificationsPermissionState = rememberPermissionState(
|
||||
permission = Manifest.permission.POST_NOTIFICATIONS
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@ package ua.acclorite.book_story.presentation.screens.settings.nested.general.com
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.SwitchWithTitle
|
||||
|
||||
/**
|
||||
|
|
@ -15,10 +14,10 @@ import ua.acclorite.book_story.presentation.screens.settings.components.SwitchWi
|
|||
*/
|
||||
@SuppressLint("InlinedApi")
|
||||
@Composable
|
||||
fun DoublePressExitSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
fun DoublePressExitSetting() {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
SwitchWithTitle(
|
||||
selected = state.value.doublePressExit,
|
||||
title = stringResource(id = R.string.double_press_exit_option),
|
||||
|
|
|
|||
|
|
@ -12,44 +12,25 @@ import androidx.compose.material3.Scaffold
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.util.OnNavigate
|
||||
import ua.acclorite.book_story.presentation.components.CustomLazyColumn
|
||||
import ua.acclorite.book_story.presentation.components.GoBackButton
|
||||
import ua.acclorite.book_story.presentation.components.collapsibleUntilExitScrollBehaviorWithLazyListState
|
||||
import ua.acclorite.book_story.presentation.data.LocalNavigator
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.data.MainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.LocalOnNavigate
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.ReaderSettingsCategory
|
||||
|
||||
@Composable
|
||||
fun ReaderSettingsRoot() {
|
||||
val navigator = LocalNavigator.current
|
||||
val mainViewModel: MainViewModel = hiltViewModel()
|
||||
|
||||
val state = mainViewModel.state.collectAsState()
|
||||
|
||||
ReaderSettings(
|
||||
state = state,
|
||||
onNavigate = { navigator.it() },
|
||||
onMainEvent = mainViewModel::onEvent
|
||||
)
|
||||
ReaderSettings()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun ReaderSettings(
|
||||
state: State<MainState>,
|
||||
onNavigate: OnNavigate,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
private fun ReaderSettings() {
|
||||
val onNavigate = LocalOnNavigate.current
|
||||
val scrollState = TopAppBarDefaults.collapsibleUntilExitScrollBehaviorWithLazyListState()
|
||||
|
||||
Scaffold(
|
||||
|
|
@ -80,10 +61,7 @@ private fun ReaderSettings(
|
|||
.padding(top = paddingValues.calculateTopPadding()),
|
||||
state = scrollState.second
|
||||
) {
|
||||
ReaderSettingsCategory(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent
|
||||
)
|
||||
ReaderSettingsCategory()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,13 +5,10 @@ package ua.acclorite.book_story.presentation.screens.settings.nested.reader.comp
|
|||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ua.acclorite.book_story.presentation.components.CategoryTitle
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
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.TextSubcategory
|
||||
import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.subcategories.TranslatorSubcategory
|
||||
|
|
@ -20,36 +17,26 @@ import ua.acclorite.book_story.presentation.screens.settings.nested.reader.compo
|
|||
* Reader Settings Category.
|
||||
* Contains all Reader settings.
|
||||
*
|
||||
* @param state [MainState] instance.
|
||||
* @param onMainEvent [MainEvent] callback.
|
||||
* @param titleColor Color that [CategoryTitle] has.
|
||||
* @param topPadding Top padding to be applied.
|
||||
* @param bottomPadding Bottom padding to be applied.
|
||||
*/
|
||||
fun LazyListScope.ReaderSettingsCategory(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit,
|
||||
titleColor: @Composable () -> Color = { MaterialTheme.colorScheme.primary },
|
||||
topPadding: Dp = 16.dp,
|
||||
bottomPadding: Dp = 48.dp
|
||||
) {
|
||||
FontSubcategory(
|
||||
state = state,
|
||||
onMainEvent = onMainEvent,
|
||||
titleColor = titleColor,
|
||||
topPadding = topPadding,
|
||||
bottomPadding = 0.dp
|
||||
)
|
||||
TextSubcategory(
|
||||
state,
|
||||
onMainEvent = onMainEvent,
|
||||
titleColor = titleColor,
|
||||
topPadding = 22.dp,
|
||||
bottomPadding = 0.dp
|
||||
)
|
||||
TranslatorSubcategory(
|
||||
state,
|
||||
onMainEvent = onMainEvent,
|
||||
titleColor = titleColor,
|
||||
topPadding = 22.dp,
|
||||
bottomPadding = bottomPadding
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.SwitchWithTitle
|
||||
|
||||
/**
|
||||
|
|
@ -13,10 +12,10 @@ import ua.acclorite.book_story.presentation.screens.settings.components.SwitchWi
|
|||
* Changes Reader's double click translation.
|
||||
*/
|
||||
@Composable
|
||||
fun DoubleClickTranslationSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
fun DoubleClickTranslationSetting() {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
SwitchWithTitle(
|
||||
selected = state.value.doubleClickTranslation,
|
||||
title = stringResource(id = R.string.double_click_translation_option),
|
||||
|
|
|
|||
|
|
@ -2,14 +2,13 @@ package ua.acclorite.book_story.presentation.screens.settings.nested.reader.comp
|
|||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.model.ButtonItem
|
||||
import ua.acclorite.book_story.domain.util.Constants
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.ChipsWithTitle
|
||||
|
||||
/**
|
||||
|
|
@ -17,10 +16,10 @@ import ua.acclorite.book_story.presentation.screens.settings.components.ChipsWit
|
|||
* Changes Reader's font, uses fonts from [Constants.FONTS].
|
||||
*/
|
||||
@Composable
|
||||
fun FontFamilySetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
fun FontFamilySetting() {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
val fontFamily = remember(state.value.fontFamily) {
|
||||
Constants.FONTS.find {
|
||||
it.id == state.value.fontFamily
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.SliderWithTitle
|
||||
|
||||
/**
|
||||
|
|
@ -13,10 +12,10 @@ import ua.acclorite.book_story.presentation.screens.settings.components.SliderWi
|
|||
* Changes Reader's font size.
|
||||
*/
|
||||
@Composable
|
||||
fun FontSizeSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
fun FontSizeSetting() {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
SliderWithTitle(
|
||||
value = state.value.fontSize to "pt",
|
||||
fromValue = 10,
|
||||
|
|
|
|||
|
|
@ -2,15 +2,14 @@ package ua.acclorite.book_story.presentation.screens.settings.nested.reader.comp
|
|||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.domain.model.ButtonItem
|
||||
import ua.acclorite.book_story.domain.util.Constants
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.SegmentedButtonWithTitle
|
||||
|
||||
/**
|
||||
|
|
@ -18,10 +17,10 @@ import ua.acclorite.book_story.presentation.screens.settings.components.Segmente
|
|||
* Changes Reader's font style (Normal/Italic).
|
||||
*/
|
||||
@Composable
|
||||
fun FontStyleSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
fun FontStyleSetting() {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
val fontFamily = remember(state.value.fontFamily) {
|
||||
Constants.FONTS.find {
|
||||
it.id == state.value.fontFamily
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.SliderWithTitle
|
||||
|
||||
/**
|
||||
|
|
@ -13,10 +12,10 @@ import ua.acclorite.book_story.presentation.screens.settings.components.SliderWi
|
|||
* Changes Reader's letter spacing.
|
||||
*/
|
||||
@Composable
|
||||
fun LetterSpacingSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
fun LetterSpacingSetting() {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
SliderWithTitle(
|
||||
value = state.value.letterSpacing to "pt",
|
||||
fromValue = -8,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.SliderWithTitle
|
||||
|
||||
/**
|
||||
|
|
@ -13,10 +12,10 @@ import ua.acclorite.book_story.presentation.screens.settings.components.SliderWi
|
|||
* Changes Reader's line height.
|
||||
*/
|
||||
@Composable
|
||||
fun LineHeightSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
fun LineHeightSetting() {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
SliderWithTitle(
|
||||
value = state.value.lineHeight to "pt",
|
||||
fromValue = 1,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.SliderWithTitle
|
||||
|
||||
/**
|
||||
|
|
@ -13,10 +12,10 @@ import ua.acclorite.book_story.presentation.screens.settings.components.SliderWi
|
|||
* Changes Reader's paragraph height.
|
||||
*/
|
||||
@Composable
|
||||
fun ParagraphHeightSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
fun ParagraphHeightSetting() {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
SliderWithTitle(
|
||||
value = state.value.paragraphHeight to "pt",
|
||||
fromValue = 0,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import ua.acclorite.book_story.R
|
||||
import ua.acclorite.book_story.presentation.components.LocalMainViewModel
|
||||
import ua.acclorite.book_story.presentation.data.MainEvent
|
||||
import ua.acclorite.book_story.presentation.data.MainState
|
||||
import ua.acclorite.book_story.presentation.screens.settings.components.SwitchWithTitle
|
||||
|
||||
/**
|
||||
|
|
@ -13,10 +12,10 @@ import ua.acclorite.book_story.presentation.screens.settings.components.SwitchWi
|
|||
* Changes Reader's paragraph indentation.
|
||||
*/
|
||||
@Composable
|
||||
fun ParagraphIndentationSetting(
|
||||
state: State<MainState>,
|
||||
onMainEvent: (MainEvent) -> Unit
|
||||
) {
|
||||
fun ParagraphIndentationSetting() {
|
||||
val state = LocalMainViewModel.current.state
|
||||
val onMainEvent = LocalMainViewModel.current.onEvent
|
||||
|
||||
SwitchWithTitle(
|
||||
selected = state.value.paragraphIndentation,
|
||||
title = stringResource(id = R.string.paragraph_indentation_option)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue