diff --git a/app/src/main/java/ua/acclorite/book_story/domain/util/DataStoreConstants.kt b/app/src/main/java/ua/acclorite/book_story/domain/util/DataStoreConstants.kt index 27dc86d3..0c262624 100644 --- a/app/src/main/java/ua/acclorite/book_story/domain/util/DataStoreConstants.kt +++ b/app/src/main/java/ua/acclorite/book_story/domain/util/DataStoreConstants.kt @@ -14,6 +14,7 @@ object DataStoreConstants { val THEME_CONTRAST = stringPreferencesKey("theme_contrast") val SHOW_START_SCREEN = booleanPreferencesKey("guide") val CHECK_FOR_UPDATES = booleanPreferencesKey("check_for_updates") + val DOUBLE_PRESS_EXIT = booleanPreferencesKey("double_press_exit") // Reader settings val DOUBLE_CLICK_TRANSLATION = booleanPreferencesKey("double_click_translation") diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/data/MainEvent.kt b/app/src/main/java/ua/acclorite/book_story/presentation/data/MainEvent.kt index e7b22175..bed48b01 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/data/MainEvent.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/data/MainEvent.kt @@ -29,4 +29,5 @@ sealed class MainEvent { data class OnChangeBrowseSortOrderDescending(val bool: Boolean) : MainEvent() data class OnChangeBrowseIncludedFilterItem(val item: String) : MainEvent() data class OnChangeTextAlignment(val alignment: String) : MainEvent() + data class OnChangeDoublePressExit(val bool: Boolean) : MainEvent() } \ No newline at end of file diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/data/MainState.kt b/app/src/main/java/ua/acclorite/book_story/presentation/data/MainState.kt index 83f19e73..b2df2a23 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/data/MainState.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/data/MainState.kt @@ -36,22 +36,29 @@ import java.util.Locale @Keep @Parcelize data class MainState( + // General Settings val language: String? = null, val theme: Theme? = null, val darkTheme: DarkTheme? = null, val pureDark: PureDark? = null, val themeContrast: ThemeContrast? = null, + val showStartScreen: Boolean? = null, + val checkForUpdates: Boolean? = null, + val doublePressExit: Boolean? = null, + + // Reader Settings val fontFamily: String? = null, val isItalic: Boolean? = null, val fontSize: Int? = null, val lineHeight: Int? = null, val paragraphHeight: Int? = null, val paragraphIndentation: Boolean? = null, - val showStartScreen: Boolean? = null, - val checkForUpdates: Boolean? = null, val sidePadding: Int? = null, val doubleClickTranslation: Boolean? = null, val fastColorPresetChange: Boolean? = null, + val textAlignment: ReaderTextAlignment? = null, + + // Browse Settings val browseFilesStructure: BrowseFilesStructure? = null, val browseLayout: BrowseLayout? = null, val browseAutoGridSize: Boolean? = null, @@ -60,7 +67,6 @@ data class MainState( val browseSortOrder: BrowseSortOrder? = null, val browseSortOrderDescending: Boolean? = null, val browseIncludedFilterItems: List? = null, - val textAlignment: ReaderTextAlignment? = null, ) : Parcelable { companion object { /** @@ -157,6 +163,9 @@ data class MainState( val textAlignment = data[TEXT_ALIGNMENT.name] as? String ?: ReaderTextAlignment.START.name + val doublePressExit = data[DOUBLE_PRESS_EXIT.name] as? Boolean + ?: false + return MainState( language = language, theme = theme.toTheme(), @@ -182,7 +191,8 @@ data class MainState( browseSortOrder = browseSortOrder.toBrowseSortOrder(), browseSortOrderDescending = browseSortOrderDescending, browseIncludedFilterItems = browseIncludedFilterItems, - textAlignment = textAlignment.toTextAlignment() + textAlignment = textAlignment.toTextAlignment(), + doublePressExit = doublePressExit ) } } diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/data/MainViewModel.kt b/app/src/main/java/ua/acclorite/book_story/presentation/data/MainViewModel.kt index 63b7077b..b48da7d9 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/data/MainViewModel.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/data/MainViewModel.kt @@ -345,6 +345,20 @@ class MainViewModel @Inject constructor( } } } + + is MainEvent.OnChangeDoublePressExit -> { + viewModelScope.launch(Dispatchers.IO) { + setDatastore.execute( + DataStoreConstants.DOUBLE_PRESS_EXIT, + event.bool + ) + updateStateWithSavedHandle { + it.copy( + doublePressExit = event.bool + ) + } + } + } } } diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/library/LibraryScreen.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/library/LibraryScreen.kt index 555f01b0..36cfb3c4 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/library/LibraryScreen.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/library/LibraryScreen.kt @@ -34,6 +34,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -54,6 +55,8 @@ 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.Screen import ua.acclorite.book_story.presentation.screens.browse.data.BrowseEvent import ua.acclorite.book_story.presentation.screens.browse.data.BrowseViewModel @@ -73,10 +76,12 @@ import ua.acclorite.book_story.presentation.ui.Transitions 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 pagerState = rememberPagerState( initialPage = state.value.currentPage, @@ -100,6 +105,7 @@ fun LibraryScreenRoot() { LibraryScreen( state = state, + mainState = mainState, onNavigate = { navigator.it() }, pagerState = pagerState, refreshState = refreshState, @@ -113,6 +119,7 @@ fun LibraryScreenRoot() { @Composable private fun LibraryScreen( state: State, + mainState: State, onNavigate: OnNavigate, pagerState: PagerState, refreshState: PullRefreshState, @@ -264,7 +271,7 @@ private fun LibraryScreen( val activity = LocalContext.current as ComponentActivity val scope = rememberCoroutineScope() - var shouldExit = remember { false } + var shouldExit = rememberSaveable { false } BackHandler { if (state.value.hasSelectedItems) { onEvent(LibraryEvent.OnClearSelectedBooks) @@ -281,7 +288,7 @@ private fun LibraryScreen( return@BackHandler } - if (shouldExit) { + if (shouldExit || !mainState.value.doublePressExit!!) { activity.finish() return@BackHandler } diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/general/components/GeneralSettingsCategory.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/general/components/GeneralSettingsCategory.kt index 3d1417ee..b3886d16 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/general/components/GeneralSettingsCategory.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/general/components/GeneralSettingsCategory.kt @@ -15,6 +15,7 @@ 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 /** * General Settings Category. @@ -56,6 +57,13 @@ fun LazyListScope.GeneralSettingsCategory( ) } + item { + DoublePressExitSetting( + state = state, + onMainEvent = onMainEvent + ) + } + item { Spacer( modifier = Modifier diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/general/components/settings/DoublePressExitSetting.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/general/components/settings/DoublePressExitSetting.kt new file mode 100644 index 00000000..ab0668e9 --- /dev/null +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/settings/nested/general/components/settings/DoublePressExitSetting.kt @@ -0,0 +1,34 @@ +package ua.acclorite.book_story.presentation.screens.settings.nested.general.components.settings + +import android.annotation.SuppressLint +import androidx.compose.foundation.lazy.LazyItemScope +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import ua.acclorite.book_story.R +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 + +/** + * Double Press Exit setting. + * If true, to close the app you need to press back twice. + */ +@SuppressLint("InlinedApi") +@Composable +fun LazyItemScope.DoublePressExitSetting( + state: State, + onMainEvent: (MainEvent) -> Unit +) { + SwitchWithTitle( + selected = state.value.doublePressExit!!, + modifier = Modifier.animateItem(), + title = stringResource(id = R.string.double_press_exit_option), + description = stringResource(id = R.string.double_press_exit_option_desc) + ) { + onMainEvent( + MainEvent.OnChangeDoublePressExit(!state.value.doublePressExit!!) + ) + } +} \ No newline at end of file diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 7f58221e..a78b037f 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -211,11 +211,18 @@ Сотрування + Мова застосунка Темна тема Суцільна темрява (ОЛЕД) Контрастність теми Тема застосунка + Перевіряти на оновлення + Перевіряти на новішу версію застосунку при запуску + Подвійне натискання для виходу + Натисніть назад двічі, щоб вийти з застосунку + + Сімейство шрифтів Стиль шрифта Розмір шрифта @@ -225,14 +232,14 @@ Пресет кольорів Колір фона Колір шрифта - Перевіряти на оновлення - Перевіряти на новішу версію застосунку при запуску Бокові відступи Переклад подвійним кліком Двічі клацніть на абзац, щоб перекласти його Швидка зміна пресета кольорів Проведіть вліво або вправо, щоб змінити пресет кольорів Розташування текста + + Структура файлів Режим відображення Кількість комірок diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 91b4f345..74cc5c6c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -230,11 +230,18 @@ Sort + App language Dark theme Pure dark (OLED) Theme contrast App theme + Check for updates + Check for newer app version on startup + Double back press to exit + Press back twice to exit the app + + Font family Font style Font size @@ -244,14 +251,14 @@ Color preset Background color Font color - Check for updates - Check for newer app version on startup Side padding Double click translation Double click on paragraph to translate it Fast color preset change Swipe left or right to change color preset Text alignment + + Files structure Display mode Grid size