diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 52e5073f..5fd3c7ba 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -21,6 +21,7 @@ dependencies { implementation(libs.voyagerNavigation) implementation(libs.voyagerTransitions) implementation(libs.accompanistPager) + implementation(libs.accompanistPagerIndicators) implementation(libs.accompanistFlowLayout) implementation(libs.kamel) implementation(libs.materialDialogsCore) diff --git a/desktop/build.gradle.kts b/desktop/build.gradle.kts index f00bc3bf..6a937701 100644 --- a/desktop/build.gradle.kts +++ b/desktop/build.gradle.kts @@ -31,6 +31,7 @@ dependencies { implementation(libs.voyagerNavigation) implementation(libs.voyagerTransitions) implementation(libs.accompanistPager) + implementation(libs.accompanistPagerIndicators) implementation(libs.accompanistFlowLayout) implementation(libs.kamel) implementation(libs.materialDialogsCore) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ba4cb561..ee327ac3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -68,6 +68,7 @@ voyagerCore = { module = "cafe.adriel.voyager:voyager-core", version.ref = "voya voyagerNavigation = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" } voyagerTransitions = { module = "cafe.adriel.voyager:voyager-transitions", version.ref = "voyager" } accompanistPager = { module = "ca.gosyer:accompanist-pager", version.ref = "accompanist" } +accompanistPagerIndicators = { module = "ca.gosyer:accompanist-pager-indicators", version.ref = "accompanist" } accompanistFlowLayout = { module = "ca.gosyer:accompanist-flowlayout", version.ref = "accompanist" } kamel = { module = "com.alialbaali.kamel:kamel-image", version.ref = "kamel" } materialDialogsCore = { module = "ca.gosyer:compose-material-dialogs-core", version.ref = "materialDialogs" } diff --git a/presentation/build.gradle.kts b/presentation/build.gradle.kts index b07a9559..2eae8e22 100644 --- a/presentation/build.gradle.kts +++ b/presentation/build.gradle.kts @@ -47,6 +47,7 @@ kotlin { api(libs.voyagerTransitions) api(libs.materialDialogsCore) api(libs.accompanistPager) + api(libs.accompanistPagerIndicators) api(libs.accompanistFlowLayout) api(libs.krokiCoroutines) api(projects.core) diff --git a/presentation/src/jvmMain/kotlin/ca/gosyer/ui/library/components/LibraryPager.kt b/presentation/src/jvmMain/kotlin/ca/gosyer/ui/library/components/LibraryPager.kt index ea7accb0..2a420af8 100644 --- a/presentation/src/jvmMain/kotlin/ca/gosyer/ui/library/components/LibraryPager.kt +++ b/presentation/src/jvmMain/kotlin/ca/gosyer/ui/library/components/LibraryPager.kt @@ -8,39 +8,26 @@ package ca.gosyer.ui.library.components import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.State import androidx.compose.runtime.getValue import ca.gosyer.data.library.model.DisplayMode import ca.gosyer.data.models.Category import ca.gosyer.data.models.Manga import com.google.accompanist.pager.HorizontalPager -import com.google.accompanist.pager.rememberPagerState +import com.google.accompanist.pager.PagerState @Composable fun LibraryPager( + pagerState: PagerState, categories: List, displayMode: DisplayMode, - selectedPage: Int, getLibraryForPage: @Composable (Long) -> State>, - onPageChanged: (Int) -> Unit, onClickManga: (Long) -> Unit, onRemoveMangaClicked: (Long) -> Unit ) { if (categories.isEmpty()) return - val state = rememberPagerState(selectedPage) - LaunchedEffect(state.currentPage) { - if (state.currentPage != selectedPage) { - onPageChanged(state.currentPage) - } - } - LaunchedEffect(selectedPage) { - if (state.currentPage != selectedPage) { - state.animateScrollToPage(selectedPage) - } - } - HorizontalPager(categories.size, state = state) { + HorizontalPager(categories.size, state = pagerState) { val library by getLibraryForPage(categories[it].id) when (displayMode) { DisplayMode.CompactGrid -> LibraryMangaCompactGrid( diff --git a/presentation/src/jvmMain/kotlin/ca/gosyer/ui/library/components/LibraryScreenContent.kt b/presentation/src/jvmMain/kotlin/ca/gosyer/ui/library/components/LibraryScreenContent.kt index 93158736..eca2a71c 100644 --- a/presentation/src/jvmMain/kotlin/ca/gosyer/ui/library/components/LibraryScreenContent.kt +++ b/presentation/src/jvmMain/kotlin/ca/gosyer/ui/library/components/LibraryScreenContent.kt @@ -6,11 +6,18 @@ package ca.gosyer.ui.library.components +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material.BottomSheetScaffold +import androidx.compose.material.Scaffold +import androidx.compose.material.rememberBottomSheetScaffoldState 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 ca.gosyer.data.library.model.DisplayMode import ca.gosyer.data.models.Category import ca.gosyer.data.models.Manga @@ -18,6 +25,8 @@ import ca.gosyer.i18n.MR import ca.gosyer.ui.base.navigation.Toolbar import ca.gosyer.uicore.components.LoadingScreen import ca.gosyer.uicore.resources.stringResource +import com.google.accompanist.pager.PagerState +import com.google.accompanist.pager.rememberPagerState @Composable fun LibraryScreenContent( @@ -33,52 +42,154 @@ fun LibraryScreenContent( onClickManga: (Long) -> Unit, onRemoveMangaClicked: (Long) -> Unit ) { - // val sheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden) - - if (categories.isEmpty()) { - LoadingScreen(isLoading, errorMessage = error) - } else { - /*ModalBottomSheetLayout( - sheetState = sheetState, - sheetContent = { *//*LibrarySheet()*//* } - ) {*/ - Column(Modifier.fillMaxWidth()) { - /*Toolbar( - title = { - val text = if (vm.showCategoryTabs) { - stringResource(R.string.library_label) - } else { - vm.selectedCategory?.visibleName.orEmpty() - } - Text(text) - }, - actions = { - IconButton(onClick = { scope.launch { sheetState.show() }}) { - Icon(Icons.Rounded.FilterList, contentDescription = null) - } - } - )*/ - Toolbar( - stringResource(MR.strings.location_library), - searchText = query, - search = updateQuery - ) - LibraryTabs( - visible = true, // vm.showCategoryTabs, - categories = categories, - selectedPage = selectedCategoryIndex, - onPageChanged = onPageChanged - ) - LibraryPager( + BoxWithConstraints { + val pagerState = rememberPagerState(selectedCategoryIndex) + LaunchedEffect(pagerState.isScrollInProgress to pagerState.currentPage) { + if (!pagerState.isScrollInProgress && pagerState.currentPage != selectedCategoryIndex) { + onPageChanged(pagerState.currentPage) + } + } + LaunchedEffect(selectedCategoryIndex) { + if (pagerState.currentPage != selectedCategoryIndex) { + pagerState.animateScrollToPage(selectedCategoryIndex) + } + } + if (maxWidth > 720.dp) { + WideLibraryScreenContent( + pagerState = pagerState, categories = categories, + selectedCategoryIndex = selectedCategoryIndex, displayMode = displayMode, - selectedPage = selectedCategoryIndex, + isLoading = isLoading, + error = error, + query = query, + updateQuery = updateQuery, + getLibraryForPage = getLibraryForPage, + onPageChanged = onPageChanged, + onClickManga = onClickManga, + onRemoveMangaClicked = onRemoveMangaClicked + ) + } else { + ThinLibraryScreenContent( + pagerState = pagerState, + categories = categories, + selectedCategoryIndex = selectedCategoryIndex, + displayMode = displayMode, + isLoading = isLoading, + error = error, + query = query, + updateQuery = updateQuery, getLibraryForPage = getLibraryForPage, onPageChanged = onPageChanged, onClickManga = onClickManga, onRemoveMangaClicked = onRemoveMangaClicked ) } - // } + } +} + +@Composable +fun WideLibraryScreenContent( + pagerState: PagerState, + categories: List, + selectedCategoryIndex: Int, + displayMode: DisplayMode, + isLoading: Boolean, + error: String?, + query: String, + updateQuery: (String) -> Unit, + getLibraryForPage: @Composable (Long) -> State>, + onPageChanged: (Int) -> Unit, + onClickManga: (Long) -> Unit, + onRemoveMangaClicked: (Long) -> Unit +) { + Scaffold( + topBar = { + Column { + Toolbar( + stringResource(MR.strings.location_library), + searchText = query, + search = updateQuery + ) + LibraryTabs( + visible = true, // vm.showCategoryTabs, + pagerState = pagerState, + categories = categories, + selectedPage = selectedCategoryIndex, + onPageChanged = onPageChanged + ) + } + } + ) { + Box(Modifier.padding(it)) { + if (categories.isEmpty()) { + LoadingScreen(isLoading, errorMessage = error) + } else { + LibraryPager( + pagerState = pagerState, + categories = categories, + displayMode = displayMode, + getLibraryForPage = getLibraryForPage, + onClickManga = onClickManga, + onRemoveMangaClicked = onRemoveMangaClicked + ) + } + } + } +} + +@Composable +fun ThinLibraryScreenContent( + pagerState: PagerState, + categories: List, + selectedCategoryIndex: Int, + displayMode: DisplayMode, + isLoading: Boolean, + error: String?, + query: String, + updateQuery: (String) -> Unit, + getLibraryForPage: @Composable (Long) -> State>, + onPageChanged: (Int) -> Unit, + onClickManga: (Long) -> Unit, + onRemoveMangaClicked: (Long) -> Unit +) { + val sheetState = rememberBottomSheetScaffoldState() + BottomSheetScaffold( + scaffoldState = sheetState, + topBar = { + Column { + Toolbar( + stringResource(MR.strings.location_library), + searchText = query, + search = updateQuery + ) + LibraryTabs( + visible = true, // vm.showCategoryTabs, + pagerState = pagerState, + categories = categories, + selectedPage = selectedCategoryIndex, + onPageChanged = onPageChanged + ) + } + }, + sheetContent = { + // LibrarySheetContent() + }, + sheetPeekHeight = 0.dp + ) { + Box(Modifier.padding(it)) { + if (categories.isEmpty()) { + LoadingScreen(isLoading, errorMessage = error) + } else { + LibraryPager( + pagerState = pagerState, + categories = categories, + displayMode = displayMode, + getLibraryForPage = getLibraryForPage, + onClickManga = onClickManga, + onRemoveMangaClicked = onRemoveMangaClicked + ) + } + } } } diff --git a/presentation/src/jvmMain/kotlin/ca/gosyer/ui/library/components/LibraryTabs.kt b/presentation/src/jvmMain/kotlin/ca/gosyer/ui/library/components/LibraryTabs.kt index 0b26d6a3..807211d5 100644 --- a/presentation/src/jvmMain/kotlin/ca/gosyer/ui/library/components/LibraryTabs.kt +++ b/presentation/src/jvmMain/kotlin/ca/gosyer/ui/library/components/LibraryTabs.kt @@ -12,15 +12,20 @@ import androidx.compose.animation.shrinkVertically import androidx.compose.material.MaterialTheme import androidx.compose.material.ScrollableTabRow import androidx.compose.material.Tab +import androidx.compose.material.TabRowDefaults import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastForEachIndexed import ca.gosyer.data.models.Category +import com.google.accompanist.pager.PagerState +import com.google.accompanist.pager.pagerTabIndicatorOffset @Composable fun LibraryTabs( visible: Boolean, + pagerState: PagerState, categories: List, selectedPage: Int, onPageChanged: (Int) -> Unit @@ -36,7 +41,12 @@ fun LibraryTabs( selectedTabIndex = selectedPage, backgroundColor = MaterialTheme.colors.surface, // contentColor = CustomColors.current.onBars, - edgePadding = 0.dp + edgePadding = 0.dp, + indicator = { tabPositions -> + TabRowDefaults.Indicator( + Modifier.pagerTabIndicatorOffset(pagerState, tabPositions) + ) + } ) { categories.fastForEachIndexed { i, category -> Tab(