From 89caae3681a09ff694594ceab761244b9b039e69 Mon Sep 17 00:00:00 2001 From: Syer10 Date: Sun, 19 Dec 2021 13:54:21 -0500 Subject: [PATCH] Add scrollbars everywhere! Closes #35 --- .../ui/base/prefs/PreferencesUiBuilder.kt | 60 ++- .../ca/gosyer/ui/base/theme/AppTheme.kt | 4 +- .../ca/gosyer/ui/categories/CategoriesMenu.kt | 13 +- .../ca/gosyer/ui/downloads/DownloadsMenu.kt | 30 +- .../ca/gosyer/ui/extensions/ExtensionsMenu.kt | 12 +- .../ca/gosyer/ui/library/MangaCompactGrid.kt | 42 ++- .../kotlin/ca/gosyer/ui/manga/MangaMenu.kt | 49 ++- .../ca/gosyer/ui/reader/viewer/Continuous.kt | 17 + .../ui/settings/SettingsAdvancedScreen.kt | 25 +- .../ui/settings/SettingsAppearanceScreen.kt | 114 +++--- .../ui/settings/SettingsBackupScreen.kt | 54 ++- .../ui/settings/SettingsBrowseScreen.kt | 21 +- .../ui/settings/SettingsDownloadsScreen.kt | 21 +- .../ui/settings/SettingsGeneralScreen.kt | 76 ++-- .../ui/settings/SettingsLibraryScreen.kt | 42 ++- .../SettingsParentalControlsScreen.kt | 21 +- .../ui/settings/SettingsReaderScreen.kt | 161 ++++---- .../ca/gosyer/ui/settings/SettingsScreen.kt | 187 +++++----- .../ui/settings/SettingsSecurityScreen.kt | 21 +- .../ui/settings/SettingsServerScreen.kt | 347 ++++++++++-------- .../ui/settings/SettingsTrackingScreen.kt | 21 +- .../ca/gosyer/ui/sources/SourcesMenu.kt | 92 +++-- .../ui/sources/components/SourceHomeScreen.kt | 4 +- .../ui/sources/components/SourceScreen.kt | 71 ++-- .../components/filter/SourceFiltersMenu.kt | 36 +- .../ui/sources/settings/SourceSettingsMenu.kt | 45 ++- .../ca/gosyer/ui/updates/UpdatesMenu.kt | 45 ++- 27 files changed, 1038 insertions(+), 593 deletions(-) diff --git a/src/main/kotlin/ca/gosyer/ui/base/prefs/PreferencesUiBuilder.kt b/src/main/kotlin/ca/gosyer/ui/base/prefs/PreferencesUiBuilder.kt index 5c9fc5e3..fbe9a680 100644 --- a/src/main/kotlin/ca/gosyer/ui/base/prefs/PreferencesUiBuilder.kt +++ b/src/main/kotlin/ca/gosyer/ui/base/prefs/PreferencesUiBuilder.kt @@ -20,6 +20,7 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.VerticalScrollbar import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable @@ -32,6 +33,7 @@ import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -41,6 +43,8 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.Checkbox import androidx.compose.material.ContentAlpha @@ -242,7 +246,8 @@ fun ChoiceDialog( buttons = buttons, title = title ) { - LazyColumn(Modifier.fillMaxSize()) { + val state = rememberLazyListState() + LazyColumn(Modifier.fillMaxSize(), state) { items(items) { (value, text) -> Row( modifier = Modifier.requiredHeight(48.dp).fillMaxWidth().clickable( @@ -264,6 +269,12 @@ fun ChoiceDialog( } } } + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } @@ -283,28 +294,37 @@ fun MultiSelectDialog( } ) { val checked by checkedFlow.collectAsState() - LazyColumn(Modifier.fillMaxSize()) { - items(items) { (value, text) -> - Row( - modifier = Modifier.requiredHeight(48.dp).fillMaxWidth().clickable( - onClick = { - if (value in checked) { - checkedFlow.value -= value - } else { - checkedFlow.value += value + val state = rememberLazyListState() + Box { + LazyColumn(Modifier.fillMaxSize(), state) { + items(items) { (value, text) -> + Row( + modifier = Modifier.requiredHeight(48.dp).fillMaxWidth().clickable( + onClick = { + if (value in checked) { + checkedFlow.value -= value + } else { + checkedFlow.value += value + } } - } - ), - verticalAlignment = Alignment.CenterVertically - ) { - Checkbox( - checked = value in checked, - onCheckedChange = null, - ) - Text(text = text, modifier = Modifier.padding(start = 24.dp)) + ), + verticalAlignment = Alignment.CenterVertically + ) { + Checkbox( + checked = value in checked, + onCheckedChange = null, + ) + Text(text = text, modifier = Modifier.padding(start = 24.dp)) + } } + item { Spacer(Modifier.height(80.dp)) } } - item { Spacer(Modifier.height(80.dp)) } + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/base/theme/AppTheme.kt b/src/main/kotlin/ca/gosyer/ui/base/theme/AppTheme.kt index 0c7e807a..c5986ea8 100644 --- a/src/main/kotlin/ca/gosyer/ui/base/theme/AppTheme.kt +++ b/src/main/kotlin/ca/gosyer/ui/base/theme/AppTheme.kt @@ -48,8 +48,8 @@ fun AppTheme(content: @Composable () -> Unit) { thickness = 8.dp, shape = MaterialTheme.shapes.small, hoverDurationMillis = 300, - unhoverColor = MaterialTheme.colors.onSurface.copy(alpha = 0.12f), - hoverColor = MaterialTheme.colors.onSurface.copy(alpha = 0.50f) + unhoverColor = MaterialTheme.colors.onSurface.copy(alpha = 0.30f), + hoverColor = MaterialTheme.colors.onSurface.copy(alpha = 0.70f) ), content = content ) diff --git a/src/main/kotlin/ca/gosyer/ui/categories/CategoriesMenu.kt b/src/main/kotlin/ca/gosyer/ui/categories/CategoriesMenu.kt index b412c57c..66d54f21 100644 --- a/src/main/kotlin/ca/gosyer/ui/categories/CategoriesMenu.kt +++ b/src/main/kotlin/ca/gosyer/ui/categories/CategoriesMenu.kt @@ -6,16 +6,20 @@ package ca.gosyer.ui.categories +import androidx.compose.foundation.VerticalScrollbar import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.material.Card import androidx.compose.material.ContentAlpha import androidx.compose.material.ExtendedFloatingActionButton @@ -84,7 +88,8 @@ fun CategoriesMenu(notifyFinished: (() -> Unit)? = null) { Surface { Box { - LazyColumn(modifier = Modifier.fillMaxSize()) { + val state = rememberLazyListState() + LazyColumn(modifier = Modifier.fillMaxSize(), state = state,) { itemsIndexed(categories) { i, category -> CategoryRow( category = category, @@ -118,6 +123,12 @@ fun CategoriesMenu(notifyFinished: (() -> Unit)? = null) { } } ) + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/downloads/DownloadsMenu.kt b/src/main/kotlin/ca/gosyer/ui/downloads/DownloadsMenu.kt index ac608cd9..17078516 100644 --- a/src/main/kotlin/ca/gosyer/ui/downloads/DownloadsMenu.kt +++ b/src/main/kotlin/ca/gosyer/ui/downloads/DownloadsMenu.kt @@ -7,7 +7,9 @@ package ca.gosyer.ui.downloads import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.foundation.VerticalScrollbar import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.aspectRatio @@ -19,6 +21,8 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.material.DropdownMenuItem import androidx.compose.material.Icon import androidx.compose.material.LinearProgressIndicator @@ -34,6 +38,7 @@ import androidx.compose.material.icons.rounded.PlayArrow import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.FilterQuality @@ -90,15 +95,24 @@ fun DownloadsMenu(onMangaClick: (Long) -> Unit) { ActionIcon(onClick = vm::clear, stringResource("action_clear_queue"), Icons.Rounded.ClearAll) } ) - LazyColumn(Modifier.fillMaxSize()) { - items(downloadQueue) { - DownloadsItem( - it, - { onMangaClick(it.mangaId) }, - vm::stopDownload, - vm::moveToBottom - ) + Box { + val state = rememberLazyListState() + LazyColumn(Modifier.fillMaxSize(), state) { + items(downloadQueue) { + DownloadsItem( + it, + { onMangaClick(it.mangaId) }, + vm::stopDownload, + vm::moveToBottom + ) + } } + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenu.kt b/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenu.kt index 73d1b5fc..89cfbbc1 100644 --- a/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenu.kt +++ b/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenu.kt @@ -6,7 +6,6 @@ package ca.gosyer.ui.extensions -import androidx.compose.foundation.ScrollbarAdapter import androidx.compose.foundation.VerticalScrollbar import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box @@ -129,7 +128,9 @@ fun ExtensionsMenu() { } } VerticalScrollbar( - modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight(), + modifier = Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp), adapter = rememberScrollbarAdapter(state) ) } @@ -244,7 +245,12 @@ fun LanguageDialog(enabledLangsFlow: MutableStateFlow>, availableLan } item { Spacer(Modifier.height(70.dp)) } } - VerticalScrollbar(ScrollbarAdapter(state), Modifier.align(Alignment.CenterEnd).padding(8.dp)) + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/library/MangaCompactGrid.kt b/src/main/kotlin/ca/gosyer/ui/library/MangaCompactGrid.kt index 708b3cef..315b17df 100644 --- a/src/main/kotlin/ca/gosyer/ui/library/MangaCompactGrid.kt +++ b/src/main/kotlin/ca/gosyer/ui/library/MangaCompactGrid.kt @@ -7,14 +7,18 @@ package ca.gosyer.ui.library import androidx.compose.foundation.ContextMenuItem +import androidx.compose.foundation.VerticalScrollbar import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.GridCells import androidx.compose.foundation.lazy.LazyVerticalGrid import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.material.LocalTextStyle import androidx.compose.material.MaterialTheme import androidx.compose.material.Text @@ -43,22 +47,32 @@ fun LibraryMangaCompactGrid( onClickManga: (Long) -> Unit = {}, onRemoveMangaClicked: (Long) -> Unit = {} ) { - LazyVerticalGrid( - cells = GridCells.Adaptive(160.dp), - modifier = Modifier.fillMaxSize().padding(4.dp) - ) { - items(library) { manga -> - LibraryMangaCompactGridItem( - manga = manga, - unread = manga.unreadCount, - downloaded = manga.downloadCount, - onClick = { onClickManga(manga.id) } - ) { - listOf( - ContextMenuItem("Unfavorite") { onRemoveMangaClicked(manga.id) } - ) + Box { + val state = rememberLazyListState() + LazyVerticalGrid( + cells = GridCells.Adaptive(160.dp), + state = state, + modifier = Modifier.fillMaxSize().padding(4.dp) + ) { + items(library) { manga -> + LibraryMangaCompactGridItem( + manga = manga, + unread = manga.unreadCount, + downloaded = manga.downloadCount, + onClick = { onClickManga(manga.id) } + ) { + listOf( + ContextMenuItem("Unfavorite") { onRemoveMangaClicked(manga.id) } + ) + } } } + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } diff --git a/src/main/kotlin/ca/gosyer/ui/manga/MangaMenu.kt b/src/main/kotlin/ca/gosyer/ui/manga/MangaMenu.kt index 1e663bdd..a5bb837c 100644 --- a/src/main/kotlin/ca/gosyer/ui/manga/MangaMenu.kt +++ b/src/main/kotlin/ca/gosyer/ui/manga/MangaMenu.kt @@ -164,7 +164,9 @@ fun MangaMenu(mangaId: Long, menuController: MenuController? = LocalMenuControll } } VerticalScrollbar( - modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight(), + modifier = Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp), adapter = rememberScrollbarAdapter(state) ) } @@ -262,26 +264,35 @@ fun openCategorySelectDialog( onPositiveButton = { onPositiveClick(enabledCategoriesFlow.value, oldCategories) } ) { val enabledCategories by enabledCategoriesFlow.collectAsState() - LazyColumn { - items(categories) { category -> - Row( - Modifier.fillMaxWidth().padding(8.dp) - .clickable { - if (category in enabledCategories) { - enabledCategoriesFlow.value -= category - } else { - enabledCategoriesFlow.value += category - } - }, - horizontalArrangement = Arrangement.SpaceBetween - ) { - Text(category.name, style = MaterialTheme.typography.subtitle1) - Checkbox( - category in enabledCategories, - onCheckedChange = null - ) + val state = rememberLazyListState() + Box { + LazyColumn(state = state) { + items(categories) { category -> + Row( + Modifier.fillMaxWidth().padding(8.dp) + .clickable { + if (category in enabledCategories) { + enabledCategoriesFlow.value -= category + } else { + enabledCategoriesFlow.value += category + } + }, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text(category.name, style = MaterialTheme.typography.subtitle1) + Checkbox( + category in enabledCategories, + onCheckedChange = null + ) + } } } + VerticalScrollbar( + modifier = Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp), + adapter = rememberScrollbarAdapter(state) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/reader/viewer/Continuous.kt b/src/main/kotlin/ca/gosyer/ui/reader/viewer/Continuous.kt index a94ad373..0f6debd8 100644 --- a/src/main/kotlin/ca/gosyer/ui/reader/viewer/Continuous.kt +++ b/src/main/kotlin/ca/gosyer/ui/reader/viewer/Continuous.kt @@ -6,6 +6,8 @@ package ca.gosyer.ui.reader.viewer +import androidx.compose.foundation.HorizontalScrollbar +import androidx.compose.foundation.VerticalScrollbar import androidx.compose.foundation.gestures.animateScrollBy import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxWithConstraints @@ -21,6 +23,7 @@ import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect @@ -124,6 +127,13 @@ fun ContinuousReader( progress ) } + VerticalScrollbar( + modifier = Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp), + adapter = rememberScrollbarAdapter(state), + reverseLayout = direction == Direction.Up + ) } Direction.Left, Direction.Right -> { LazyRow( @@ -145,6 +155,13 @@ fun ContinuousReader( progress ) } + HorizontalScrollbar( + modifier = Modifier.align(Alignment.BottomCenter) + .fillMaxWidth() + .padding(horizontal = 8.dp, vertical = 4.dp), + adapter = rememberScrollbarAdapter(state), + reverseLayout = direction == Direction.Left + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/settings/SettingsAdvancedScreen.kt b/src/main/kotlin/ca/gosyer/ui/settings/SettingsAdvancedScreen.kt index bab508c2..6f6191f4 100644 --- a/src/main/kotlin/ca/gosyer/ui/settings/SettingsAdvancedScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/settings/SettingsAdvancedScreen.kt @@ -6,9 +6,19 @@ package ca.gosyer.ui.settings +import androidx.compose.foundation.VerticalScrollbar +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import ca.gosyer.data.update.UpdatePreferences import ca.gosyer.ui.base.components.MenuController import ca.gosyer.ui.base.components.Toolbar @@ -29,10 +39,19 @@ fun SettingsAdvancedScreen(menuController: MenuController) { val vm = viewModel() Column { Toolbar(stringResource("settings_advanced_screen"), menuController, true) - LazyColumn { - item { - SwitchPreference(preference = vm.updatesEnabled, title = stringResource("update_checker")) + Box { + val state = rememberLazyListState() + LazyColumn(Modifier.fillMaxSize(), state) { + item { + SwitchPreference(preference = vm.updatesEnabled, title = stringResource("update_checker")) + } } + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/settings/SettingsAppearanceScreen.kt b/src/main/kotlin/ca/gosyer/ui/settings/SettingsAppearanceScreen.kt index 944fe0b0..e2780e2d 100644 --- a/src/main/kotlin/ca/gosyer/ui/settings/SettingsAppearanceScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/settings/SettingsAppearanceScreen.kt @@ -6,16 +6,21 @@ package ca.gosyer.ui.settings +import androidx.compose.foundation.VerticalScrollbar import androidx.compose.foundation.border import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.foundation.shape.CornerSize import androidx.compose.material.Button import androidx.compose.material.ButtonDefaults @@ -77,59 +82,68 @@ fun SettingsAppearance(menuController: MenuController) { Column { Toolbar(stringResource("settings_appearance_screen"), menuController, true) - LazyColumn { - item { - ChoicePreference( - preference = vm.themeMode, - choices = mapOf( - ThemeMode.System to stringResource("theme_follow_system"), - ThemeMode.Light to stringResource("theme_light"), - ThemeMode.Dark to stringResource("theme_dark") - ), - title = stringResource("theme") - ) - } - item { - Text( - stringResource("preset_themes"), - modifier = Modifier.padding(start = 16.dp, top = 16.dp, bottom = 4.dp) - ) - LazyRow(modifier = Modifier.padding(horizontal = 8.dp)) { - items(themesForCurrentMode) { theme -> - ThemeItem( - theme, - onClick = { - (if (isLight) vm.lightTheme else vm.darkTheme).value = it.id - activeColors.primaryStateFlow.value = it.colors.primary - activeColors.secondaryStateFlow.value = it.colors.secondary - } - ) + Box { + val state = rememberLazyListState() + LazyColumn(Modifier.fillMaxSize(), state) { + item { + ChoicePreference( + preference = vm.themeMode, + choices = mapOf( + ThemeMode.System to stringResource("theme_follow_system"), + ThemeMode.Light to stringResource("theme_light"), + ThemeMode.Dark to stringResource("theme_dark") + ), + title = stringResource("theme") + ) + } + item { + Text( + stringResource("preset_themes"), + modifier = Modifier.padding(start = 16.dp, top = 16.dp, bottom = 4.dp) + ) + LazyRow(modifier = Modifier.padding(horizontal = 8.dp)) { + items(themesForCurrentMode) { theme -> + ThemeItem( + theme, + onClick = { + (if (isLight) vm.lightTheme else vm.darkTheme).value = it.id + activeColors.primaryStateFlow.value = it.colors.primary + activeColors.secondaryStateFlow.value = it.colors.secondary + } + ) + } } } + item { + ColorPreference( + preference = activeColors.primaryStateFlow, + title = stringResource("color_primary"), + subtitle = stringResource("color_primary_sub"), + unsetColor = MaterialTheme.colors.primary + ) + } + item { + ColorPreference( + preference = activeColors.secondaryStateFlow, + title = stringResource("color_secondary"), + subtitle = stringResource("color_secondary_sub"), + unsetColor = MaterialTheme.colors.secondary + ) + } + item { + SwitchPreference( + vm.windowDecorations, + stringResource("window_decorations"), + stringResource("window_decorations_sub") + ) + } } - item { - ColorPreference( - preference = activeColors.primaryStateFlow, - title = stringResource("color_primary"), - subtitle = stringResource("color_primary_sub"), - unsetColor = MaterialTheme.colors.primary - ) - } - item { - ColorPreference( - preference = activeColors.secondaryStateFlow, - title = stringResource("color_secondary"), - subtitle = stringResource("color_secondary_sub"), - unsetColor = MaterialTheme.colors.secondary - ) - } - item { - SwitchPreference( - vm.windowDecorations, - stringResource("window_decorations"), - stringResource("window_decorations_sub") - ) - } + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/settings/SettingsBackupScreen.kt b/src/main/kotlin/ca/gosyer/ui/settings/SettingsBackupScreen.kt index 9b393736..ded70cb6 100644 --- a/src/main/kotlin/ca/gosyer/ui/settings/SettingsBackupScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/settings/SettingsBackupScreen.kt @@ -6,10 +6,17 @@ package ca.gosyer.ui.settings +import androidx.compose.foundation.VerticalScrollbar +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.material.CircularProgressIndicator import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme @@ -200,28 +207,37 @@ fun SettingsBackupScreen(menuController: MenuController) { Column { Toolbar(stringResource("settings_backup_screen"), menuController, true) - LazyColumn { - item { - PreferenceFile( - stringResource("backup_restore"), - stringResource("backup_restore_sub"), - restoring, - restoringProgress, - restoreStatus - ) { - filePicker("gz") { - vm.restoreFile(it.selectedFile.toPath()) + Box { + val state = rememberLazyListState() + LazyColumn(Modifier.fillMaxSize(), state) { + item { + PreferenceFile( + stringResource("backup_restore"), + stringResource("backup_restore_sub"), + restoring, + restoringProgress, + restoreStatus + ) { + filePicker("gz") { + vm.restoreFile(it.selectedFile.toPath()) + } } + PreferenceFile( + stringResource("backup_create"), + stringResource("backup_create_sub"), + creating, + creatingProgress, + creatingStatus, + vm::exportBackup + ) } - PreferenceFile( - stringResource("backup_create"), - stringResource("backup_create_sub"), - creating, - creatingProgress, - creatingStatus, - vm::exportBackup - ) } + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/settings/SettingsBrowseScreen.kt b/src/main/kotlin/ca/gosyer/ui/settings/SettingsBrowseScreen.kt index 1355f6fc..01108b62 100644 --- a/src/main/kotlin/ca/gosyer/ui/settings/SettingsBrowseScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/settings/SettingsBrowseScreen.kt @@ -6,9 +6,19 @@ package ca.gosyer.ui.settings +import androidx.compose.foundation.VerticalScrollbar +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import ca.gosyer.ui.base.components.MenuController import ca.gosyer.ui.base.components.Toolbar import ca.gosyer.ui.base.resources.stringResource @@ -17,7 +27,16 @@ import ca.gosyer.ui.base.resources.stringResource fun SettingsBrowseScreen(menuController: MenuController) { Column { Toolbar(stringResource("settings_browse_screen"), menuController, true) - LazyColumn { + Box { + val state = rememberLazyListState() + LazyColumn(Modifier.fillMaxSize(), state) { + } + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/settings/SettingsDownloadsScreen.kt b/src/main/kotlin/ca/gosyer/ui/settings/SettingsDownloadsScreen.kt index cb7425b6..359c1f0b 100644 --- a/src/main/kotlin/ca/gosyer/ui/settings/SettingsDownloadsScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/settings/SettingsDownloadsScreen.kt @@ -6,9 +6,19 @@ package ca.gosyer.ui.settings +import androidx.compose.foundation.VerticalScrollbar +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import ca.gosyer.ui.base.components.MenuController import ca.gosyer.ui.base.components.Toolbar import ca.gosyer.ui.base.resources.stringResource @@ -17,7 +27,16 @@ import ca.gosyer.ui.base.resources.stringResource fun SettingsDownloadsScreen(menuController: MenuController) { Column { Toolbar(stringResource("settings_download_screen"), menuController, true) - LazyColumn { + Box { + val state = rememberLazyListState() + LazyColumn(Modifier.fillMaxSize(), state) { + } + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/settings/SettingsGeneralScreen.kt b/src/main/kotlin/ca/gosyer/ui/settings/SettingsGeneralScreen.kt index 6e2b86e4..a7003962 100644 --- a/src/main/kotlin/ca/gosyer/ui/settings/SettingsGeneralScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/settings/SettingsGeneralScreen.kt @@ -6,10 +6,20 @@ package ca.gosyer.ui.settings +import androidx.compose.foundation.VerticalScrollbar +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.material.Divider import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import ca.gosyer.build.BuildResources import ca.gosyer.data.ui.UiPreferences import ca.gosyer.data.ui.model.StartScreen @@ -82,34 +92,46 @@ fun SettingsGeneralScreen(menuController: MenuController) { val vm = viewModel() Column { Toolbar(stringResource("settings_general_screen"), menuController, closable = true) - LazyColumn { - item { - ChoicePreference( - preference = vm.startScreen, - title = stringResource("start_screen"), - choices = vm.getStartScreenChoices() - ) - } - item { - SwitchPreference(preference = vm.confirmExit, title = stringResource("confirm_exit")) - } - item { - Divider() - } - item { - ChoicePreference( - preference = vm.language, - title = stringResource("language"), - choices = vm.getLanguageChoices(), - ) - } - item { - ChoicePreference( - preference = vm.dateFormat, - title = stringResource("date_format"), - choices = vm.getDateChoices() - ) + Box { + val state = rememberLazyListState() + LazyColumn(Modifier.fillMaxSize(), state) { + item { + ChoicePreference( + preference = vm.startScreen, + title = stringResource("start_screen"), + choices = vm.getStartScreenChoices() + ) + } + item { + SwitchPreference( + preference = vm.confirmExit, + title = stringResource("confirm_exit") + ) + } + item { + Divider() + } + item { + ChoicePreference( + preference = vm.language, + title = stringResource("language"), + choices = vm.getLanguageChoices(), + ) + } + item { + ChoicePreference( + preference = vm.dateFormat, + title = stringResource("date_format"), + choices = vm.getDateChoices() + ) + } } + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/settings/SettingsLibraryScreen.kt b/src/main/kotlin/ca/gosyer/ui/settings/SettingsLibraryScreen.kt index 04278900..6f7be19b 100644 --- a/src/main/kotlin/ca/gosyer/ui/settings/SettingsLibraryScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/settings/SettingsLibraryScreen.kt @@ -6,10 +6,20 @@ package ca.gosyer.ui.settings +import androidx.compose.foundation.VerticalScrollbar +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import ca.gosyer.data.library.LibraryPreferences import ca.gosyer.data.server.interactions.CategoryInteractionHandler import ca.gosyer.ui.base.components.MenuController @@ -51,17 +61,29 @@ fun SettingsLibraryScreen(menuController: MenuController) { Column { Toolbar(stringResource("settings_library_screen"), menuController, true) - LazyColumn { - item { - SwitchPreference(preference = vm.showAllCategory, title = stringResource("show_all_category")) - } - item { - PreferenceRow( - stringResource("location_categories"), - onClick = { openCategoriesMenu(vm::refreshCategoryCount) }, - subtitle = vm.categories.collectAsState().value.toString() - ) + Box { + val state = rememberLazyListState() + LazyColumn(Modifier.fillMaxSize(), state) { + item { + SwitchPreference( + preference = vm.showAllCategory, + title = stringResource("show_all_category") + ) + } + item { + PreferenceRow( + stringResource("location_categories"), + onClick = { openCategoriesMenu(vm::refreshCategoryCount) }, + subtitle = vm.categories.collectAsState().value.toString() + ) + } } + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/settings/SettingsParentalControlsScreen.kt b/src/main/kotlin/ca/gosyer/ui/settings/SettingsParentalControlsScreen.kt index f8cfa1d3..690ea04e 100644 --- a/src/main/kotlin/ca/gosyer/ui/settings/SettingsParentalControlsScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/settings/SettingsParentalControlsScreen.kt @@ -6,9 +6,19 @@ package ca.gosyer.ui.settings +import androidx.compose.foundation.VerticalScrollbar +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import ca.gosyer.ui.base.components.MenuController import ca.gosyer.ui.base.components.Toolbar import ca.gosyer.ui.base.resources.stringResource @@ -17,7 +27,16 @@ import ca.gosyer.ui.base.resources.stringResource fun SettingsParentalControlsScreen(menuController: MenuController) { Column { Toolbar(stringResource("settings_parental_control_screen"), menuController, true) - LazyColumn { + Box { + val state = rememberLazyListState() + LazyColumn(Modifier.fillMaxSize(), state) { + } + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/settings/SettingsReaderScreen.kt b/src/main/kotlin/ca/gosyer/ui/settings/SettingsReaderScreen.kt index ac605787..023b9ca9 100644 --- a/src/main/kotlin/ca/gosyer/ui/settings/SettingsReaderScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/settings/SettingsReaderScreen.kt @@ -6,12 +6,22 @@ package ca.gosyer.ui.settings +import androidx.compose.foundation.VerticalScrollbar +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.material.Divider import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastForEach import ca.gosyer.data.reader.ReaderModePreferences import ca.gosyer.data.reader.ReaderPreferences @@ -121,80 +131,95 @@ fun SettingsReaderScreen(menuController: MenuController) { val modeSettings by vm.modeSettings.collectAsState() Column { Toolbar(stringResource("settings_reader"), menuController, true) - LazyColumn { - item { - ChoicePreference( - vm.selectedMode, - vm.modes.collectAsState().value.associateWith { it }, - stringResource("reader_mode") - ) - } - item { - Divider() - } - modeSettings.fastForEach { + Box { + val state = rememberLazyListState() + LazyColumn(Modifier.fillMaxSize(), state) { item { - ExpandablePreference(it.mode) { - ChoicePreference( - it.direction, - vm.getDirectionChoices(), - stringResource("direction"), - enabled = !it.defaultMode - ) - SwitchPreference( - it.continuous, - stringResource("continuous"), - stringResource("continuous_sub"), - enabled = !it.defaultMode - ) - val continuous by it.continuous.collectAsState() - if (continuous) { - ChoicePreference( - it.padding, - vm.getPaddingChoices(), - stringResource("page_padding") - ) - val direction by it.direction.collectAsState() - val (title, subtitle) = if (direction == Direction.Up || direction == Direction.Down) { - stringResource("force_fit_width") to stringResource("force_fit_width_sub") - } else { - stringResource("force_fit_height") to stringResource("force_fit_height_sub") - } - SwitchPreference( - it.fitSize, - title, - subtitle - ) - val maxSize by it.maxSize.collectAsState() - val (maxSizeTitle, maxSizeSubtitle) = if (direction == Direction.Up || direction == Direction.Down) { - stringResource("max_width") to stringResource("max_width_sub", maxSize) - } else { - stringResource("max_height") to stringResource("max_height_sub", maxSize) - } - ChoicePreference( - it.maxSize, - vm.getMaxSizeChoices(direction), - maxSizeTitle, - maxSizeSubtitle - ) - } else { - ChoicePreference( - it.imageScale, - vm.getImageScaleChoices(), - stringResource("image_scale") - ) - } - ChoicePreference( - it.navigationMode, - vm.getNavigationModeChoices(), - stringResource("navigation_mode") - ) - } + ChoicePreference( + vm.selectedMode, + vm.modes.collectAsState().value.associateWith { it }, + stringResource("reader_mode") + ) } item { Divider() } + modeSettings.fastForEach { + item { + ExpandablePreference(it.mode) { + ChoicePreference( + it.direction, + vm.getDirectionChoices(), + stringResource("direction"), + enabled = !it.defaultMode + ) + SwitchPreference( + it.continuous, + stringResource("continuous"), + stringResource("continuous_sub"), + enabled = !it.defaultMode + ) + val continuous by it.continuous.collectAsState() + if (continuous) { + ChoicePreference( + it.padding, + vm.getPaddingChoices(), + stringResource("page_padding") + ) + val direction by it.direction.collectAsState() + val (title, subtitle) = if (direction == Direction.Up || direction == Direction.Down) { + stringResource("force_fit_width") to stringResource("force_fit_width_sub") + } else { + stringResource("force_fit_height") to stringResource("force_fit_height_sub") + } + SwitchPreference( + it.fitSize, + title, + subtitle + ) + val maxSize by it.maxSize.collectAsState() + val (maxSizeTitle, maxSizeSubtitle) = if (direction == Direction.Up || direction == Direction.Down) { + stringResource("max_width") to stringResource( + "max_width_sub", + maxSize + ) + } else { + stringResource("max_height") to stringResource( + "max_height_sub", + maxSize + ) + } + ChoicePreference( + it.maxSize, + vm.getMaxSizeChoices(direction), + maxSizeTitle, + maxSizeSubtitle + ) + } else { + ChoicePreference( + it.imageScale, + vm.getImageScaleChoices(), + stringResource("image_scale") + ) + } + ChoicePreference( + it.navigationMode, + vm.getNavigationModeChoices(), + stringResource("navigation_mode") + ) + } + } + item { + Divider() + } + } } + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/settings/SettingsScreen.kt b/src/main/kotlin/ca/gosyer/ui/settings/SettingsScreen.kt index ab324d14..305671a1 100644 --- a/src/main/kotlin/ca/gosyer/ui/settings/SettingsScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/settings/SettingsScreen.kt @@ -6,8 +6,15 @@ package ca.gosyer.ui.settings +import androidx.compose.foundation.VerticalScrollbar +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Backup import androidx.compose.material.icons.rounded.ChromeReaderMode @@ -18,6 +25,9 @@ import androidx.compose.material.icons.rounded.Explore import androidx.compose.material.icons.rounded.Palette import androidx.compose.material.icons.rounded.Tune import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import ca.gosyer.ui.base.components.MenuController import ca.gosyer.ui.base.components.Toolbar import ca.gosyer.ui.base.prefs.PreferenceRow @@ -28,91 +38,100 @@ import ca.gosyer.ui.main.Routes fun SettingsScreen(menuController: MenuController) { Column { Toolbar(stringResource("location_settings"), closable = false) - LazyColumn { - item { - PreferenceRow( - title = stringResource("settings_general"), - icon = Icons.Rounded.Tune, - onClick = { menuController.push(Routes.SettingsGeneral) } - ) - } - item { - PreferenceRow( - title = stringResource("settings_appearance"), - icon = Icons.Rounded.Palette, - onClick = { menuController.push(Routes.SettingsAppearance) } - ) - } - item { - PreferenceRow( - title = stringResource("settings_server"), - icon = Icons.Rounded.Computer, - onClick = { menuController.push(Routes.SettingsServer) } - ) - } - item { - PreferenceRow( - title = stringResource("settings_library"), - icon = Icons.Rounded.CollectionsBookmark, - onClick = { menuController.push(Routes.SettingsLibrary) } - ) - } - item { - PreferenceRow( - title = stringResource("settings_reader"), - icon = Icons.Rounded.ChromeReaderMode, - onClick = { menuController.push(Routes.SettingsReader) } - ) - } - /*item { - Pref( - title = stringResource("settings_download"), - icon = Icons.Rounded.GetApp, - onClick = { navController.push(Route.SettingsDownloads) } - ) - } - item { - Pref( - title = stringResource("settings_tracking"), - icon = Icons.Rounded.Sync, - onClick = { navController.push(Route.SettingsTracking) } - ) - }*/ - item { - PreferenceRow( - title = stringResource("settings_browse"), - icon = Icons.Rounded.Explore, - onClick = { menuController.push(Routes.SettingsBrowse) } - ) - } - item { - PreferenceRow( - title = stringResource("settings_backup"), - icon = Icons.Rounded.Backup, - onClick = { menuController.push(Routes.SettingsBackup) } - ) - } - /*item { - Pref( - title = stringResource("settings_security"), - icon = Icons.Rounded.Security, - onClick = { navController.push(Route.SettingsSecurity) } - ) - } - item { - Pref( - title = stringResource("settings_parental_controls"), - icon = Icons.Rounded.PeopleOutline, - onClick = { navController.push(Route.SettingsParentalControls) } - ) - }*/ - item { - PreferenceRow( - title = stringResource("settings_advanced"), - icon = Icons.Rounded.Code, - onClick = { menuController.push(Routes.SettingsAdvanced) } - ) + Box { + val state = rememberLazyListState() + LazyColumn(Modifier.fillMaxSize(), state) { + item { + PreferenceRow( + title = stringResource("settings_general"), + icon = Icons.Rounded.Tune, + onClick = { menuController.push(Routes.SettingsGeneral) } + ) + } + item { + PreferenceRow( + title = stringResource("settings_appearance"), + icon = Icons.Rounded.Palette, + onClick = { menuController.push(Routes.SettingsAppearance) } + ) + } + item { + PreferenceRow( + title = stringResource("settings_server"), + icon = Icons.Rounded.Computer, + onClick = { menuController.push(Routes.SettingsServer) } + ) + } + item { + PreferenceRow( + title = stringResource("settings_library"), + icon = Icons.Rounded.CollectionsBookmark, + onClick = { menuController.push(Routes.SettingsLibrary) } + ) + } + item { + PreferenceRow( + title = stringResource("settings_reader"), + icon = Icons.Rounded.ChromeReaderMode, + onClick = { menuController.push(Routes.SettingsReader) } + ) + } + /*item { + Pref( + title = stringResource("settings_download"), + icon = Icons.Rounded.GetApp, + onClick = { navController.push(Route.SettingsDownloads) } + ) + } + item { + Pref( + title = stringResource("settings_tracking"), + icon = Icons.Rounded.Sync, + onClick = { navController.push(Route.SettingsTracking) } + ) + }*/ + item { + PreferenceRow( + title = stringResource("settings_browse"), + icon = Icons.Rounded.Explore, + onClick = { menuController.push(Routes.SettingsBrowse) } + ) + } + item { + PreferenceRow( + title = stringResource("settings_backup"), + icon = Icons.Rounded.Backup, + onClick = { menuController.push(Routes.SettingsBackup) } + ) + } + /*item { + Pref( + title = stringResource("settings_security"), + icon = Icons.Rounded.Security, + onClick = { navController.push(Route.SettingsSecurity) } + ) + } + item { + Pref( + title = stringResource("settings_parental_controls"), + icon = Icons.Rounded.PeopleOutline, + onClick = { navController.push(Route.SettingsParentalControls) } + ) + }*/ + item { + PreferenceRow( + title = stringResource("settings_advanced"), + icon = Icons.Rounded.Code, + onClick = { menuController.push(Routes.SettingsAdvanced) } + ) + } } + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/settings/SettingsSecurityScreen.kt b/src/main/kotlin/ca/gosyer/ui/settings/SettingsSecurityScreen.kt index ca77813d..7599ee5e 100644 --- a/src/main/kotlin/ca/gosyer/ui/settings/SettingsSecurityScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/settings/SettingsSecurityScreen.kt @@ -6,9 +6,19 @@ package ca.gosyer.ui.settings +import androidx.compose.foundation.VerticalScrollbar +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import ca.gosyer.ui.base.components.MenuController import ca.gosyer.ui.base.components.Toolbar import ca.gosyer.ui.base.resources.stringResource @@ -17,7 +27,16 @@ import ca.gosyer.ui.base.resources.stringResource fun SettingsSecurityScreen(menuController: MenuController) { Column { Toolbar(stringResource("settings_security_screen"), menuController, true) - LazyColumn { + Box { + val state = rememberLazyListState() + LazyColumn(Modifier.fillMaxSize(), state) { + } + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/settings/SettingsServerScreen.kt b/src/main/kotlin/ca/gosyer/ui/settings/SettingsServerScreen.kt index 192929d7..4716f21f 100644 --- a/src/main/kotlin/ca/gosyer/ui/settings/SettingsServerScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/settings/SettingsServerScreen.kt @@ -6,8 +6,15 @@ package ca.gosyer.ui.settings +import androidx.compose.foundation.VerticalScrollbar +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.material.Divider import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Info @@ -16,7 +23,10 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.unit.dp import ca.gosyer.data.server.ServerHostPreferences import ca.gosyer.data.server.ServerPreferences import ca.gosyer.data.server.ServerService @@ -138,171 +148,208 @@ fun SettingsServerScreen(menuController: MenuController) { } Column { Toolbar(stringResource("settings_server_screen"), menuController, true) - LazyColumn { - item { - SwitchPreference(preference = vm.host, title = stringResource("host_server")) - } - if (host) { + Box { + val state = rememberLazyListState() + LazyColumn(Modifier.fillMaxSize(), state) { + item { + SwitchPreference(preference = vm.host, title = stringResource("host_server")) + } + if (host) { + item { + PreferenceRow( + stringResource("host_settings"), + Icons.Rounded.Info, + subtitle = stringResource("host_settings_sub") + ) + } + item { + val ip by vm.ip.collectAsState() + EditTextPreference( + preference = vm.ip, + title = stringResource("host_ip"), + subtitle = stringResource("host_ip_sub", ip), + changeListener = vm::serverSettingChanged + ) + } + item { + val port by vm.port.collectAsState() + EditTextPreference( + preference = vm.port, + title = stringResource("host_port"), + subtitle = stringResource("host_port_sub", port), + changeListener = vm::serverSettingChanged + ) + } + item { + SwitchPreference( + preference = vm.socksProxyEnabled, + title = stringResource("host_socks_enabled"), + changeListener = vm::serverSettingChanged + ) + } + item { + val proxyHost by vm.socksProxyHost.collectAsState() + EditTextPreference( + preference = vm.socksProxyHost, + title = stringResource("host_socks_host"), + subtitle = stringResource("host_socks_host_sub", proxyHost), + changeListener = vm::serverSettingChanged + ) + } + item { + val proxyPort by vm.socksProxyPort.collectAsState() + EditTextPreference( + preference = vm.socksProxyPort, + title = stringResource("host_socks_port"), + subtitle = stringResource("host_socks_port_sub", proxyPort), + changeListener = vm::serverSettingChanged + ) + } + item { + SwitchPreference( + preference = vm.debugLogsEnabled, + title = stringResource("host_debug_logging"), + subtitle = stringResource("host_debug_logging_sub"), + changeListener = vm::serverSettingChanged + ) + } + item { + SwitchPreference( + preference = vm.systemTrayEnabled, + title = stringResource("host_system_tray"), + subtitle = stringResource("host_system_tray_sub"), + changeListener = vm::serverSettingChanged + ) + } + item { + SwitchPreference( + preference = vm.webUIEnabled, + title = stringResource("host_webui"), + subtitle = stringResource("host_webui_sub"), + changeListener = vm::serverSettingChanged + ) + } + item { + val webUIEnabled by vm.webUIEnabled.collectAsState() + SwitchPreference( + preference = vm.openInBrowserEnabled, + title = stringResource("host_open_in_browser"), + subtitle = stringResource("host_open_in_browser_sub"), + changeListener = vm::serverSettingChanged, + enabled = webUIEnabled + ) + } + item { + SwitchPreference( + preference = vm.basicAuthEnabled, + title = stringResource("basic_auth"), + subtitle = stringResource("host_basic_auth_sub"), + changeListener = vm::serverSettingChanged + ) + } + item { + EditTextPreference( + preference = vm.basicAuthUsername, + title = stringResource("host_basic_auth_username"), + changeListener = vm::serverSettingChanged, + enabled = basicAuthEnabled + ) + } + item { + EditTextPreference( + preference = vm.basicAuthPassword, + title = stringResource("host_basic_auth_password"), + changeListener = vm::serverSettingChanged, + visualTransformation = PasswordVisualTransformation(), + enabled = basicAuthEnabled + ) + } + } + item { + Divider() + } + item { + EditTextPreference( + vm.serverUrl, + stringResource("server_url"), + subtitle = vm.serverUrl.collectAsState().value + ) + } + item { + EditTextPreference( + vm.serverPort, + stringResource("server_port"), + subtitle = vm.serverPort.collectAsState().value + ) + } + item { PreferenceRow( - stringResource("host_settings"), - Icons.Rounded.Info, - subtitle = stringResource("host_settings_sub") + stringResource("server_preference_warning"), + Icons.Rounded.Warning, + subtitle = stringResource("server_preference_warning_sub") ) } item { - val ip by vm.ip.collectAsState() - EditTextPreference( - preference = vm.ip, - title = stringResource("host_ip"), - subtitle = stringResource("host_ip_sub", ip), - changeListener = vm::serverSettingChanged - ) + ChoicePreference(vm.proxy, vm.getProxyChoices(), stringResource("server_proxy")) } - item { - val port by vm.port.collectAsState() - EditTextPreference( - preference = vm.port, - title = stringResource("host_port"), - subtitle = stringResource("host_port_sub", port), - changeListener = vm::serverSettingChanged - ) - } - item { - SwitchPreference( - preference = vm.socksProxyEnabled, - title = stringResource("host_socks_enabled"), - changeListener = vm::serverSettingChanged - ) - } - item { - val proxyHost by vm.socksProxyHost.collectAsState() - EditTextPreference( - preference = vm.socksProxyHost, - title = stringResource("host_socks_host"), - subtitle = stringResource("host_socks_host_sub", proxyHost), - changeListener = vm::serverSettingChanged - ) - } - item { - val proxyPort by vm.socksProxyPort.collectAsState() - EditTextPreference( - preference = vm.socksProxyPort, - title = stringResource("host_socks_port"), - subtitle = stringResource("host_socks_port_sub", proxyPort), - changeListener = vm::serverSettingChanged - ) - } - item { - SwitchPreference( - preference = vm.debugLogsEnabled, - title = stringResource("host_debug_logging"), - subtitle = stringResource("host_debug_logging_sub"), - changeListener = vm::serverSettingChanged - ) - } - item { - SwitchPreference( - preference = vm.systemTrayEnabled, - title = stringResource("host_system_tray"), - subtitle = stringResource("host_system_tray_sub"), - changeListener = vm::serverSettingChanged - ) - } - item { - SwitchPreference( - preference = vm.webUIEnabled, - title = stringResource("host_webui"), - subtitle = stringResource("host_webui_sub"), - changeListener = vm::serverSettingChanged - ) - } - item { - val webUIEnabled by vm.webUIEnabled.collectAsState() - SwitchPreference( - preference = vm.openInBrowserEnabled, - title = stringResource("host_open_in_browser"), - subtitle = stringResource("host_open_in_browser_sub"), - changeListener = vm::serverSettingChanged, - enabled = webUIEnabled - ) - } - item { - SwitchPreference( - preference = vm.basicAuthEnabled, - title = stringResource("basic_auth"), - subtitle = stringResource("host_basic_auth_sub"), - changeListener = vm::serverSettingChanged - ) - } - item { - EditTextPreference( - preference = vm.basicAuthUsername, - title = stringResource("host_basic_auth_username"), - changeListener = vm::serverSettingChanged, - enabled = basicAuthEnabled - ) - } - item { - EditTextPreference( - preference = vm.basicAuthPassword, - title = stringResource("host_basic_auth_password"), - changeListener = vm::serverSettingChanged, - visualTransformation = PasswordVisualTransformation(), - enabled = basicAuthEnabled - ) - } - } - item { - Divider() - } - item { - EditTextPreference(vm.serverUrl, stringResource("server_url"), subtitle = vm.serverUrl.collectAsState().value) - } - item { - EditTextPreference(vm.serverPort, stringResource("server_port"), subtitle = vm.serverPort.collectAsState().value) - } - - item { - PreferenceRow( - stringResource("server_preference_warning"), - Icons.Rounded.Warning, - subtitle = stringResource("server_preference_warning_sub") - ) - } - item { - ChoicePreference(vm.proxy, vm.getProxyChoices(), stringResource("server_proxy")) - } - when (proxy) { - Proxy.NO_PROXY -> Unit - Proxy.HTTP_PROXY -> { - item { - EditTextPreference(vm.httpHost, stringResource("http_proxy"), vm.httpHost.collectAsState().value) + when (proxy) { + Proxy.NO_PROXY -> Unit + Proxy.HTTP_PROXY -> { + item { + EditTextPreference( + vm.httpHost, + stringResource("http_proxy"), + vm.httpHost.collectAsState().value + ) + } + item { + EditTextPreference( + vm.httpPort, + stringResource("http_port"), + vm.httpPort.collectAsState().value + ) + } } - item { - EditTextPreference(vm.httpPort, stringResource("http_port"), vm.httpPort.collectAsState().value) + Proxy.SOCKS_PROXY -> { + item { + EditTextPreference( + vm.socksHost, + stringResource("socks_proxy"), + vm.socksHost.collectAsState().value + ) + } + item { + EditTextPreference( + vm.socksPort, + stringResource("socks_port"), + vm.socksPort.collectAsState().value + ) + } } } - Proxy.SOCKS_PROXY -> { + item { + ChoicePreference(vm.auth, vm.getAuthChoices(), stringResource("authentication")) + } + if (auth != Auth.NONE) { item { - EditTextPreference(vm.socksHost, stringResource("socks_proxy"), vm.socksHost.collectAsState().value) + EditTextPreference(vm.authUsername, stringResource("auth_username")) } item { - EditTextPreference(vm.socksPort, stringResource("socks_port"), vm.socksPort.collectAsState().value) + EditTextPreference( + vm.authPassword, + stringResource("auth_password"), + visualTransformation = PasswordVisualTransformation() + ) } } } - item { - ChoicePreference(vm.auth, vm.getAuthChoices(), stringResource("authentication")) - } - if (auth != Auth.NONE) { - item { - EditTextPreference(vm.authUsername, stringResource("auth_username")) - } - item { - EditTextPreference(vm.authPassword, stringResource("auth_password"), visualTransformation = PasswordVisualTransformation()) - } - } + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/settings/SettingsTrackingScreen.kt b/src/main/kotlin/ca/gosyer/ui/settings/SettingsTrackingScreen.kt index 0809ca30..7f512937 100644 --- a/src/main/kotlin/ca/gosyer/ui/settings/SettingsTrackingScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/settings/SettingsTrackingScreen.kt @@ -6,9 +6,19 @@ package ca.gosyer.ui.settings +import androidx.compose.foundation.VerticalScrollbar +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import ca.gosyer.ui.base.components.MenuController import ca.gosyer.ui.base.components.Toolbar import ca.gosyer.ui.base.resources.stringResource @@ -17,7 +27,16 @@ import ca.gosyer.ui.base.resources.stringResource fun SettingsTrackingScreen(menuController: MenuController) { Column { Toolbar(stringResource("settings_tracking_screen"), menuController, true) - LazyColumn { + Box { + val state = rememberLazyListState() + LazyColumn(Modifier.fillMaxSize(), state) { + } + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/sources/SourcesMenu.kt b/src/main/kotlin/ca/gosyer/ui/sources/SourcesMenu.kt index 2d4787af..0c5d2078 100644 --- a/src/main/kotlin/ca/gosyer/ui/sources/SourcesMenu.kt +++ b/src/main/kotlin/ca/gosyer/ui/sources/SourcesMenu.kt @@ -9,6 +9,7 @@ package ca.gosyer.ui.sources import androidx.compose.animation.Crossfade import androidx.compose.foundation.TooltipArea import androidx.compose.foundation.TooltipPlacement +import androidx.compose.foundation.VerticalScrollbar import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight @@ -19,6 +20,8 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Icon import androidx.compose.material.Surface @@ -108,51 +111,60 @@ fun SourcesSideMenu( onCloseSourceTabClick: (Source) -> Unit ) { Surface(elevation = 1.dp) { - LazyColumn(Modifier.fillMaxHeight().width(64.dp)) { - items(sourceTabs) { source -> - TooltipArea( - { - Surface( - modifier = Modifier.shadow(4.dp), - shape = RoundedCornerShape(4.dp), - elevation = 4.dp - ) { - Text(source?.name ?: stringResource("sources_home"), modifier = Modifier.padding(10.dp)) - } - }, - modifier = Modifier.size(64.dp), - tooltipPlacement = TooltipPlacement.CursorPoint( - offset = DpOffset(0.dp, 16.dp) - ) - ) { - Box(Modifier.fillMaxSize()) { - val modifier = Modifier - .combinedMouseClickable( - onClick = { - onSourceTabClick(source) - }, - onMiddleClick = { - if (source != null) { - onCloseSourceTabClick(source) - } - } - ) - .requiredSize(50.dp) - .align(Alignment.Center) - if (source != null) { - Box(Modifier.align(Alignment.Center)) { - KamelImage( - lazyPainterResource(source, filterQuality = FilterQuality.Medium), - source.displayName, - modifier - ) + Box { + val state = rememberLazyListState() + LazyColumn(Modifier.fillMaxHeight().width(64.dp), state) { + items(sourceTabs) { source -> + TooltipArea( + { + Surface( + modifier = Modifier.shadow(4.dp), + shape = RoundedCornerShape(4.dp), + elevation = 4.dp + ) { + Text(source?.name ?: stringResource("sources_home"), modifier = Modifier.padding(10.dp)) + } + }, + modifier = Modifier.size(64.dp), + tooltipPlacement = TooltipPlacement.CursorPoint( + offset = DpOffset(0.dp, 16.dp) + ) + ) { + Box(Modifier.fillMaxSize()) { + val modifier = Modifier + .combinedMouseClickable( + onClick = { + onSourceTabClick(source) + }, + onMiddleClick = { + if (source != null) { + onCloseSourceTabClick(source) + } + } + ) + .requiredSize(50.dp) + .align(Alignment.Center) + if (source != null) { + Box(Modifier.align(Alignment.Center)) { + KamelImage( + lazyPainterResource(source, filterQuality = FilterQuality.Medium), + source.displayName, + modifier + ) + } + } else { + Icon(Icons.Rounded.Home, stringResource("sources_home"), modifier = modifier) } - } else { - Icon(Icons.Rounded.Home, stringResource("sources_home"), modifier = modifier) } } } } + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/sources/components/SourceHomeScreen.kt b/src/main/kotlin/ca/gosyer/ui/sources/components/SourceHomeScreen.kt index 1c775f69..05ac3990 100644 --- a/src/main/kotlin/ca/gosyer/ui/sources/components/SourceHomeScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/sources/components/SourceHomeScreen.kt @@ -96,7 +96,9 @@ fun SourceHomeScreen( }*/ VerticalScrollbar( - modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight(), + modifier = Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp), adapter = rememberScrollbarAdapter(state) ) } diff --git a/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreen.kt b/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreen.kt index 40dc064f..d09cfcc1 100644 --- a/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreen.kt @@ -6,11 +6,15 @@ package ca.gosyer.ui.sources.components +import androidx.compose.foundation.VerticalScrollbar import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.GridCells import androidx.compose.foundation.lazy.LazyVerticalGrid import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Explore import androidx.compose.material.icons.rounded.FilterList @@ -35,6 +39,7 @@ import ca.gosyer.ui.base.vm.viewModel import ca.gosyer.ui.sources.components.filter.SourceFiltersMenu import ca.gosyer.util.compose.persistentLazyListState import com.github.zsoltk.compose.savedinstancestate.Bundle +import com.github.zsoltk.compose.savedinstancestate.BundleScope import io.kamel.image.lazyPainterResource @Composable @@ -85,23 +90,25 @@ fun SourceScreen( onLoadNextPage = vm::loadNextPage, onMangaClick = onMangaClick, ) - SourceFiltersMenu( - bundle = bundle, - modifier = Modifier.align(Alignment.TopEnd), - sourceId = source.id, - showFilters = showingFilters && !isLatest, - onSearchClicked = { - vm.setUsingFilters(true) - vm.showingFilters(false) - vm.submitSearch() - }, - onResetClicked = { - vm.setUsingFilters(false) - vm.showingFilters(false) - vm.submitSearch() - }, - showFiltersButton = vm::enableFilters - ) + BundleScope("filters", autoDispose = false) { + SourceFiltersMenu( + bundle = bundle, + modifier = Modifier.align(Alignment.TopEnd), + sourceId = source.id, + showFilters = showingFilters && !isLatest, + onSearchClicked = { + vm.setUsingFilters(true) + vm.showingFilters(false) + vm.submitSearch() + }, + onResetClicked = { + vm.setUsingFilters(false) + vm.showingFilters(false) + vm.submitSearch() + }, + showFiltersButton = vm::enableFilters + ) + } } } } @@ -186,19 +193,27 @@ private fun MangaTable( LoadingScreen(isLoading) } else { val persistentState = persistentLazyListState(bundle) - LazyVerticalGrid(GridCells.Adaptive(160.dp), state = persistentState) { - itemsIndexed(mangas) { index, manga -> - if (hasNextPage && index == mangas.lastIndex) { - LaunchedEffect(Unit) { onLoadNextPage() } - } - MangaGridItem( - title = manga.title, - cover = lazyPainterResource(manga, filterQuality = FilterQuality.Medium), - onClick = { - onMangaClick(manga.id) + Box { + LazyVerticalGrid(GridCells.Adaptive(160.dp), state = persistentState) { + itemsIndexed(mangas) { index, manga -> + if (hasNextPage && index == mangas.lastIndex) { + LaunchedEffect(Unit) { onLoadNextPage() } } - ) + MangaGridItem( + title = manga.title, + cover = lazyPainterResource(manga, filterQuality = FilterQuality.Medium), + onClick = { + onMangaClick(manga.id) + } + ) + } } + VerticalScrollbar( + rememberScrollbarAdapter(persistentState), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/sources/components/filter/SourceFiltersMenu.kt b/src/main/kotlin/ca/gosyer/ui/sources/components/filter/SourceFiltersMenu.kt index 8382de39..c9e847a9 100644 --- a/src/main/kotlin/ca/gosyer/ui/sources/components/filter/SourceFiltersMenu.kt +++ b/src/main/kotlin/ca/gosyer/ui/sources/components/filter/SourceFiltersMenu.kt @@ -14,6 +14,7 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideOutHorizontally +import androidx.compose.foundation.VerticalScrollbar import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.FocusInteraction import androidx.compose.foundation.interaction.MutableInteractionSource @@ -31,6 +32,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.material.Button import androidx.compose.material.Checkbox import androidx.compose.material.ContentAlpha @@ -68,6 +70,7 @@ import ca.gosyer.ui.base.prefs.ExpandablePreference import ca.gosyer.ui.base.resources.stringResource import ca.gosyer.ui.base.vm.viewModel import ca.gosyer.ui.sources.components.filter.model.SourceFiltersView +import ca.gosyer.util.compose.persistentLazyListState import com.github.zsoltk.compose.savedinstancestate.Bundle import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.filterIsInstance @@ -105,8 +108,8 @@ fun SourceFiltersMenu( exit = fadeOut() + slideOutHorizontally(targetOffsetX = { it * 2 }), modifier = modifier ) { - Surface(elevation = 1.dp) { - Column(Modifier.width(360.dp).fillMaxHeight()) { + Surface(elevation = 1.dp, modifier = Modifier.width(360.dp).fillMaxHeight()) { + Column(Modifier.fillMaxSize()) { Surface(elevation = 4.dp) { Row( Modifier.height(56.dp).fillMaxWidth().padding(horizontal = 16.dp), @@ -122,19 +125,28 @@ fun SourceFiltersMenu( } } val expandedGroups = remember { mutableStateListOf() } - LazyColumn(Modifier.fillMaxSize()) { - items( - items = filters, - key = { it.filter.hashCode() } - ) { item -> - item.toView(startExpanded = item.index in expandedGroups) { expanded, index -> - if (expanded) { - expandedGroups += index - } else { - expandedGroups -= index + Box { + val lazyListState = persistentLazyListState() + LazyColumn(Modifier.fillMaxSize(), lazyListState) { + items( + items = filters, + key = { it.filter.hashCode() } + ) { item -> + item.toView(startExpanded = item.index in expandedGroups) { expanded, index -> + if (expanded) { + expandedGroups += index + } else { + expandedGroups -= index + } } } } + VerticalScrollbar( + rememberScrollbarAdapter(lazyListState), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/sources/settings/SourceSettingsMenu.kt b/src/main/kotlin/ca/gosyer/ui/sources/settings/SourceSettingsMenu.kt index 8238f701..67a5ace4 100644 --- a/src/main/kotlin/ca/gosyer/ui/sources/settings/SourceSettingsMenu.kt +++ b/src/main/kotlin/ca/gosyer/ui/sources/settings/SourceSettingsMenu.kt @@ -6,11 +6,18 @@ package ca.gosyer.ui.sources.settings +import androidx.compose.foundation.VerticalScrollbar +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.material.Checkbox import androidx.compose.material.OutlinedTextField import androidx.compose.material.Switch @@ -19,6 +26,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.unit.dp @@ -61,23 +69,32 @@ fun SourceSettingsMenu(sourceId: Long, menuController: MenuController? = LocalMe Column { Toolbar(stringResource("location_settings"), menuController, menuController != null) - LazyColumn { - items(settings, { it.props.hashCode() }) { - when (it) { - is CheckBox, is Switch -> { - TwoStatePreference(it as TwoState, it is CheckBox) - } - is List -> { - ListPreference(it) - } - is EditText -> { - EditTextPreference(it) - } - is MultiSelect -> { - MultiSelectPreference(it) + Box { + val state = rememberLazyListState() + LazyColumn(Modifier.fillMaxSize(), state) { + items(settings, { it.props.hashCode() }) { + when (it) { + is CheckBox, is Switch -> { + TwoStatePreference(it as TwoState, it is CheckBox) + } + is List -> { + ListPreference(it) + } + is EditText -> { + EditTextPreference(it) + } + is MultiSelect -> { + MultiSelectPreference(it) + } } } } + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/updates/UpdatesMenu.kt b/src/main/kotlin/ca/gosyer/ui/updates/UpdatesMenu.kt index 4cd39aca..0e058577 100644 --- a/src/main/kotlin/ca/gosyer/ui/updates/UpdatesMenu.kt +++ b/src/main/kotlin/ca/gosyer/ui/updates/UpdatesMenu.kt @@ -6,20 +6,26 @@ package ca.gosyer.ui.updates +import androidx.compose.foundation.VerticalScrollbar import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.rememberScrollbarAdapter import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip @@ -54,24 +60,33 @@ fun UpdatesMenu( if (isLoading || updates.isEmpty()) { LoadingScreen(isLoading) } else { - LazyColumn { - itemsIndexed(updates) { index, item -> - LaunchedEffect(Unit) { - if (index == updates.lastIndex) { - vm.loadNextPage() + Box { + val state = rememberLazyListState() + LazyColumn(Modifier.fillMaxSize(), state) { + itemsIndexed(updates) { index, item -> + LaunchedEffect(Unit) { + if (index == updates.lastIndex) { + vm.loadNextPage() + } } + val manga = item.manga!! + val chapter = item.chapter + UpdatesItem( + item, + onClickItem = { openChapter(chapter.index, chapter.mangaId) }, + onClickCover = { openManga(manga.id) }, + onClickDownload = vm::downloadChapter, + onClickDeleteDownload = vm::deleteDownloadedChapter, + onClickStopDownload = vm::stopDownloadingChapter + ) } - val manga = item.manga!! - val chapter = item.chapter - UpdatesItem( - item, - onClickItem = { openChapter(chapter.index, chapter.mangaId) }, - onClickCover = { openManga(manga.id) }, - onClickDownload = vm::downloadChapter, - onClickDeleteDownload = vm::deleteDownloadedChapter, - onClickStopDownload = vm::stopDownloadingChapter - ) } + VerticalScrollbar( + rememberScrollbarAdapter(state), + Modifier.align(Alignment.CenterEnd) + .fillMaxHeight() + .padding(horizontal = 4.dp, vertical = 8.dp) + ) } } }