diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1268a7faa..972ee2f18 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -277,6 +277,11 @@ dependencies { implementation(libs.compose.ui.tooling.preview) } +// TODO: Remove once Annotation 1.8.0 is out +configurations.all { + resolutionStrategy.force("androidx.annotation:annotation:1.8.0-rc01") +} + kotlin { jvmToolchain(21) } diff --git a/app/src/main/kotlin/androidx/compose/material3/SideDrawer.kt b/app/src/main/kotlin/androidx/compose/material3/SideDrawer.kt index 7464a8d27..8b408c320 100644 --- a/app/src/main/kotlin/androidx/compose/material3/SideDrawer.kt +++ b/app/src/main/kotlin/androidx/compose/material3/SideDrawer.kt @@ -46,7 +46,7 @@ import androidx.compose.ui.input.pointer.positionChange import androidx.compose.ui.input.pointer.util.VelocityTracker import androidx.compose.ui.input.pointer.util.addPointerInputChange import androidx.compose.ui.layout.layout -import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.Constraints @@ -364,8 +364,8 @@ fun ModalSideDrawer( } } } else { - Modifier.onGloballyPositioned { - val width = it.size.width + Modifier.onSizeChanged { + val width = it.width if (width != 0) { maxValue = width.toFloat() drawerState.anchoredDraggableState.updateAnchors( diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/MainActivity.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/MainActivity.kt index 9327afdc5..c7561a6de 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/MainActivity.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/MainActivity.kt @@ -77,6 +77,7 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.currentCompositeKeyHash import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -93,6 +94,7 @@ import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalViewConfiguration @@ -370,13 +372,15 @@ class MainActivity : EhActivity() { }, ) { LocalTouchSlopProvider(Settings.touchSlopFactor.toFloat()) { - // TODO: Correctly calculate it after https://android-review.googlesource.com/3017366 - val minOffset = -with(density) { DrawerDefaults.MaximumDrawerWidth.toPx() } + var minOffset by remember { + mutableFloatStateOf(-with(density) { DrawerDefaults.MaximumDrawerWidth.toPx() }) + } ModalNavigationDrawer( drawerContent = { ModalDrawerSheet( drawerState = navDrawerState, - modifier = Modifier.widthIn(max = (configuration.screenWidthDp - 56).dp), + modifier = Modifier.widthIn(max = (configuration.screenWidthDp - 56).dp) + .onSizeChanged { minOffset = -it.width.toFloat() }, windowInsets = WindowInsets.systemBars.only(WindowInsetsSides.Start), ) { val scrollState = rememberScrollState() @@ -425,7 +429,7 @@ class MainActivity : EhActivity() { ModalDrawerSheet( modifier = Modifier.widthIn(max = (configuration.screenWidthDp - 112).dp), drawerShape = ShapeDefaults.Large.copy(topEnd = CornerSize(0), bottomEnd = CornerSize(0)), - windowInsets = WindowInsets.systemBars.only(WindowInsetsSides.Vertical + WindowInsetsSides.End), + windowInsets = WindowInsets.systemBars.only(WindowInsetsSides.Top + WindowInsetsSides.End), ) { CompositionLocalProvider(LocalViewConfiguration provides viewConfiguration) { sheet(sideSheetState) diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/main/GalleryList.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/main/GalleryList.kt index 780cfb805..cec9895eb 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/main/GalleryList.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/main/GalleryList.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.widthIn @@ -25,19 +26,24 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ShapeDefaults import androidx.compose.material3.Surface import androidx.compose.material3.Text -import androidx.compose.material3.pulltorefresh.PullToRefreshState +import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults +import androidx.compose.material3.pulltorefresh.pullToRefresh +import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.paging.LoadState @@ -54,7 +60,10 @@ import com.hippo.ehviewer.ui.screen.collectDetailSizeAsState import com.hippo.ehviewer.ui.tools.FastScrollLazyVerticalGrid import com.hippo.ehviewer.ui.tools.FastScrollLazyVerticalStaggeredGrid import com.hippo.ehviewer.util.displayString +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.drop +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.launch @Stable operator fun PaddingValues.plus(r: PaddingValues) = object : PaddingValues { @@ -65,6 +74,7 @@ operator fun PaddingValues.plus(r: PaddingValues) = object : PaddingValues { override fun calculateTopPadding() = l.calculateTopPadding() + r.calculateTopPadding() } +context(CoroutineScope) @Composable fun GalleryList( modifier: Modifier = Modifier, @@ -76,20 +86,41 @@ fun GalleryList( detailItemContent: @Composable (LazyGridItemScope.(BaseGalleryInfo) -> Unit), thumbListState: LazyStaggeredGridState = rememberLazyStaggeredGridState(), thumbItemContent: @Composable (LazyStaggeredGridItemScope.(BaseGalleryInfo) -> Unit), - refreshState: PullToRefreshState, + searchBarOffsetY: () -> Int, scrollToTopOnRefresh: Boolean = true, onRefresh: () -> Unit, onLoading: () -> Unit, ) { val marginH = dimensionResource(id = R.dimen.gallery_list_margin_h) val marginV = dimensionResource(id = R.dimen.gallery_list_margin_v) - val combinedModifier = contentModifier.nestedScroll(refreshState.nestedScrollConnection) - Box(modifier = modifier.fillMaxSize()) { + + var isRefreshing by remember { mutableStateOf(false) } + val refreshState = rememberPullToRefreshState() + Box( + modifier = modifier.fillMaxSize().pullToRefresh( + isRefreshing = isRefreshing, + state = refreshState, + enabled = { data.loadState.refresh is LoadState.NotLoading }, + ) { + isRefreshing = true + launch { + if (data.loadState.prepend.endOfPaginationReached) { + onRefresh() + } else { + data.retry() + } + snapshotFlow { data.loadState }.drop(1).first { state -> + state.prepend !is LoadState.Loading && state.refresh !is LoadState.Loading + } + isRefreshing = false + } + }, + ) { if (listMode == 0) { val columnWidth by collectDetailSizeAsState() FastScrollLazyVerticalGrid( columns = GridCells.Adaptive(columnWidth), - modifier = combinedModifier, + modifier = contentModifier, state = detailListState, contentPadding = contentPadding + PaddingValues(marginH, marginV), verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.gallery_list_interval)), @@ -118,7 +149,7 @@ fun GalleryList( val thumbColumns by Settings.thumbColumns.collectAsState() FastScrollLazyVerticalStaggeredGrid( columns = StaggeredGridCells.Fixed(thumbColumns), - modifier = combinedModifier, + modifier = contentModifier, state = thumbListState, verticalItemSpacing = gridInterval, horizontalArrangement = Arrangement.spacedBy(gridInterval), @@ -144,23 +175,8 @@ fun GalleryList( } } - if (refreshState.isRefreshing) { - LaunchedEffect(Unit) { - if (data.loadState.prepend.endOfPaginationReached) { - onRefresh() - } else { - data.retry() - } - snapshotFlow { data.loadState }.drop(1).collect { state -> - if (state.prepend !is LoadState.Loading && state.refresh !is LoadState.Loading) { - refreshState.endRefresh() - } - } - } - } - when (val state = data.loadState.refresh) { - is LoadState.Loading -> if (!refreshState.isRefreshing && scrollToTopOnRefresh) { + is LoadState.Loading -> if (!isRefreshing && scrollToTopOnRefresh) { LaunchedEffect(Unit) { onLoading() } @@ -195,6 +211,13 @@ fun GalleryList( ErrorTip(modifier = Modifier.widthIn(max = 228.dp), text = stringResource(id = R.string.gallery_list_empty_hit)) } } + + PullToRefreshDefaults.Indicator( + state = refreshState, + isRefreshing = isRefreshing, + modifier = Modifier.align(Alignment.TopCenter).padding(top = contentPadding.calculateTopPadding()) + .offset { IntOffset(0, searchBarOffsetY()) }, + ) } } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/main/SearchFilter.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/main/SearchFilter.kt index c23d96789..1f20b9622 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/main/SearchFilter.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/main/SearchFilter.kt @@ -3,8 +3,8 @@ package com.hippo.ehviewer.ui.main import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyRow @@ -74,16 +74,12 @@ fun SearchFilter( fun isCategoryChecked(bit: Int) = category and bit != 0 val categories = remember(category) { categoryTable.sortedBy { !isCategoryChecked(it.first) } } LazyRow( - // Workaround for https://issuetracker.google.com/332939169 - // contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp), - modifier = Modifier.padding(top = 8.dp), + contentPadding = PaddingValues(start = 8.dp, top = 8.dp, end = 16.dp), horizontalArrangement = Arrangement.spacedBy(8.dp), ) { // Workaround for the first item's animation // https://github.com/Calvin-LL/Reorderable/issues/4#issuecomment-1853131769 - item { - Spacer(modifier = Modifier.width(8.dp)) - } + item {} items(categories, { it.first }) { FilterChip( selected = isCategoryChecked(it.first), @@ -92,9 +88,6 @@ fun SearchFilter( modifier = Modifier.thenIf(animateItems) { animateItem() }, ) } - item { - Spacer(modifier = Modifier.width(8.dp)) - } } var languageFilter by Settings.languageFilter.asMutableState() val languages = remember { diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/ReaderScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/ReaderScreen.kt index b8638b230..184e27b42 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/ReaderScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/reader/ReaderScreen.kt @@ -5,9 +5,12 @@ import androidx.compose.foundation.background import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.navigationBarsPadding -import androidx.compose.foundation.layout.statusBarsIgnoringVisibility +import androidx.compose.foundation.layout.only +import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material3.BottomSheetDefaults @@ -102,8 +105,9 @@ fun ReaderScreen(info: BaseGalleryInfo, page: Int = -1, navigator: DestinationsN val state = rememberModalBottomSheetState() ModalBottomSheet( onDismissRequest = { dispose() }, + modifier = Modifier.windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Top)), sheetState = state, - windowInsets = WindowInsets.statusBarsIgnoringVisibility, + contentWindowInsets = { WindowInsets(0) }, ) { ReaderPageSheetMeta( retry = { pageLoader.retryPage(page.index) }, @@ -170,10 +174,11 @@ fun ReaderScreen(info: BaseGalleryInfo, page: Int = -1, navigator: DestinationsN ) ModalBottomSheet( onDismissRequest = { dispose() }, + modifier = Modifier.windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Top)), // Yeah, I know color state should not be read here, but we have to do it... scrimColor = scrim, dragHandle = null, - windowInsets = WindowInsets.statusBarsIgnoringVisibility, + contentWindowInsets = { WindowInsets(0) }, ) { SettingsPager(modifier = Modifier.fillMaxSize()) { page -> isColorFilter = page == 2 diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/DownloadsScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/DownloadsScreen.kt index 4d64e2fa3..d31e69ba9 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/DownloadsScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/DownloadsScreen.kt @@ -12,9 +12,13 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.itemsIndexed @@ -299,8 +303,7 @@ fun DownloadsScreen(navigator: DestinationsNavigator) = composing(navigator) { LazyColumn( modifier = Modifier.fillMaxSize(), state = labelsListState, - // Workaround for https://issuetracker.google.com/332939169 - // contentPadding = WindowInsets.systemBars.only(WindowInsetsSides.Bottom).asPaddingValues(), + contentPadding = WindowInsets.systemBars.only(WindowInsetsSides.Bottom).asPaddingValues(), ) { item { ListItem( diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/FavoritesScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/FavoritesScreen.kt index 9e50490f3..39403baac 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/FavoritesScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/FavoritesScreen.kt @@ -27,7 +27,6 @@ import androidx.compose.material3.ListItem import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar -import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState @@ -47,7 +46,6 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.stringResource import androidx.lifecycle.viewModelScope -import androidx.paging.LoadState import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingSource @@ -212,10 +210,6 @@ fun FavouritesScreen(navigator: DestinationsNavigator) = composing(navigator) { } } - val refreshState = rememberPullToRefreshState { - data.loadState.refresh is LoadState.NotLoading - } - var fabExpanded by remember { mutableStateOf(false) } var fabHidden by remember { mutableStateOf(false) } val checkedInfoMap = remember { mutableStateMapOf() } @@ -231,7 +225,6 @@ fun FavouritesScreen(navigator: DestinationsNavigator) = composing(navigator) { fabHidden = true }, onSearchHidden = { fabHidden = false }, - refreshState = refreshState, tagNamespace = !isLocalFav, searchBarOffsetY = { searchBarOffsetY }, trailingIcon = { @@ -320,7 +313,7 @@ fun FavouritesScreen(navigator: DestinationsNavigator) = composing(navigator) { ) } }, - refreshState = refreshState, + searchBarOffsetY = { searchBarOffsetY }, scrollToTopOnRefresh = urlBuilder.favCat != FavListUrlBuilder.FAV_CAT_LOCAL, onRefresh = { refresh() }, onLoading = { searchBarOffsetY = 0 }, diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryCommentsScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryCommentsScreen.kt index c14ba5bcf..7b05d5dff 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryCommentsScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryCommentsScreen.kt @@ -14,7 +14,6 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -41,8 +40,7 @@ import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.pulltorefresh.PullToRefreshContainer -import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState +import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect @@ -90,6 +88,7 @@ import com.hippo.ehviewer.ui.composing import com.hippo.ehviewer.ui.jumpToReaderByPage import com.hippo.ehviewer.ui.legacy.CoilImageGetter import com.hippo.ehviewer.ui.main.GalleryCommentCard +import com.hippo.ehviewer.ui.main.plus import com.hippo.ehviewer.ui.openBrowser import com.hippo.ehviewer.ui.tools.animateFloatMergePredictiveBackAsState import com.hippo.ehviewer.ui.tools.normalizeSpan @@ -106,7 +105,6 @@ import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.RootGraph import com.ramcosta.composedestinations.navigation.DestinationsNavigator import eu.kanade.tachiyomi.util.lang.launchIO -import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.lang.withUIContext import eu.kanade.tachiyomi.util.system.logcat import kotlin.math.roundToInt @@ -279,20 +277,28 @@ fun GalleryCommentsScreen(gid: Long, navigator: DestinationsNavigator) = composi ) { paddingValues -> val keylineMargin = dimensionResource(id = R.dimen.keyline_margin) var editTextMeasured by remember { mutableStateOf(MinimumContentPaddingEditText) } - val refreshState = rememberPullToRefreshState() - if (refreshState.isRefreshing) { - LaunchedEffect(Unit) { - runSuspendCatching { - withIOContext { refreshComment(true) } + var isRefreshing by remember { mutableStateOf(false) } + PullToRefreshBox( + isRefreshing = isRefreshing, + onRefresh = { + isRefreshing = true + launchIO { + runSuspendCatching { + refreshComment(true) + } + isRefreshing = false } - refreshState.endRefresh() - } - } - Box(modifier = Modifier.fillMaxSize().imePadding().nestedScroll(refreshState.nestedScrollConnection)) { + }, + modifier = Modifier.fillMaxSize().imePadding(), + ) { val additionalPadding = if (commenting) { editTextMeasured } else { - 0.dp + if (!comments.hasMore) { + MinimumContentPaddingEditText + } else { + 0.dp + } } val voteUpSucceed = stringResource(R.string.vote_up_successfully) val cancelVoteUpSucceed = stringResource(R.string.cancel_vote_up_successfully) @@ -302,14 +308,8 @@ fun GalleryCommentsScreen(gid: Long, navigator: DestinationsNavigator) = composi LazyColumn( modifier = Modifier.padding(horizontal = keylineMargin), verticalArrangement = Arrangement.spacedBy(8.dp), - contentPadding = PaddingValues( - // top = paddingValues.calculateTopPadding(), - bottom = paddingValues.calculateBottomPadding() + additionalPadding, - ), + contentPadding = paddingValues + PaddingValues(bottom = additionalPadding), ) { - item { - Spacer(modifier = Modifier.height(paddingValues.calculateTopPadding())) - } items( items = comments.comments, key = { it.id }, @@ -406,18 +406,8 @@ fun GalleryCommentsScreen(gid: Long, navigator: DestinationsNavigator) = composi } } } - } else { - // Workaround for comment list lagging when reaching the bottom - // https://github.com/FooIbar/EhViewer/issues/994 - item { - Spacer(modifier = Modifier.height(MinimumContentPaddingEditText)) - } } } - PullToRefreshContainer( - state = refreshState, - modifier = Modifier.align(Alignment.TopCenter).padding(top = paddingValues.calculateTopPadding()), - ) Surface( modifier = Modifier.align(Alignment.BottomCenter).layout { measurable, constraints -> val origin = measurable.measure(constraints) diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryDetailScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryDetailScreen.kt index a360706c6..7a8e37a49 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryDetailScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryDetailScreen.kt @@ -803,7 +803,7 @@ fun GalleryDetailScreen(args: GalleryDetailScreenArgs, navigator: DestinationsNa if (showBottomSheet && galleryDetail != null) { ModalBottomSheet( onDismissRequest = { showBottomSheet = false }, - windowInsets = WindowInsets(0, 0, 0, 0), + contentWindowInsets = { WindowInsets(0, 0, 0, 0) }, ) { GalleryInfoBottomSheet(galleryDetail, navigator) } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryListScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryListScreen.kt index 55b0f5a60..d5f34fd90 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryListScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryListScreen.kt @@ -11,12 +11,16 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.calculateEndPadding import androidx.compose.foundation.layout.calculateStartPadding import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.lazy.itemsIndexed @@ -34,6 +38,7 @@ import androidx.compose.material.icons.filled.Shuffle import androidx.compose.material.icons.outlined.Bookmarks import androidx.compose.material3.ElevatedCard import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.ListItem @@ -43,7 +48,6 @@ import androidx.compose.material3.SwipeToDismissBoxState import androidx.compose.material3.SwipeToDismissBoxValue import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar -import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.Stable @@ -76,7 +80,6 @@ import androidx.compose.ui.util.fastAny import androidx.compose.ui.util.fastForEach import androidx.compose.ui.util.lerp import androidx.lifecycle.viewModelScope -import androidx.paging.LoadState import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingSource @@ -373,11 +376,12 @@ fun GalleryListScreen(lub: ListUrlBuilder, navigator: DestinationsNavigator) = c LazyColumn( modifier = Modifier.fillMaxSize(), state = quickSearchListState, - // Workaround for https://issuetracker.google.com/332939169 - // contentPadding = WindowInsets.systemBars.only(WindowInsetsSides.Bottom).asPaddingValues(), + contentPadding = WindowInsets.systemBars.only(WindowInsetsSides.Bottom).asPaddingValues(), ) { // Fix the first item's reorder animation - item {} + stickyHeader { + HorizontalDivider() + } itemsIndexed(quickSearchList, key = { _, item -> item.id!! }) { index, item -> ReorderableItem(reorderableLazyListState, key = item.id!!) { isDragging -> // Not using rememberSwipeToDismissBoxState to prevent LazyColumn from reusing it @@ -468,10 +472,6 @@ fun GalleryListScreen(lub: ListUrlBuilder, navigator: DestinationsNavigator) = c } } - val refreshState = rememberPullToRefreshState { - data.loadState.refresh is LoadState.NotLoading - } - var fabExpanded by remember { mutableStateOf(false) } var fabHidden by remember { mutableStateOf(false) } @@ -537,7 +537,6 @@ fun GalleryListScreen(lub: ListUrlBuilder, navigator: DestinationsNavigator) = c onApplySearch = ::onApplySearch, onSearchExpanded = { fabHidden = true }, onSearchHidden = { fabHidden = false }, - refreshState = refreshState, suggestionProvider = { GalleryDetailUrlParser.parse(it, false)?.run { GalleryDetailUrlSuggestion(gid, token) @@ -677,7 +676,7 @@ fun GalleryListScreen(lub: ListUrlBuilder, navigator: DestinationsNavigator) = c info = info, ) }, - refreshState = refreshState, + searchBarOffsetY = { searchBarOffsetY }, onRefresh = { urlBuilder.setRange(0) data.refresh() diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/SearchBarScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/SearchBarScreen.kt index f33a397df..db433aaef 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/SearchBarScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/screen/SearchBarScreen.kt @@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.displayCutoutPadding import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height @@ -16,8 +17,6 @@ import androidx.compose.foundation.layout.ime import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.only -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.safeDrawingPadding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.union @@ -44,8 +43,6 @@ import androidx.compose.material3.SearchBarDefaults import androidx.compose.material3.SearchBarHorizontalPadding import androidx.compose.material3.SearchBarInputField import androidx.compose.material3.Text -import androidx.compose.material3.pulltorefresh.PullToRefreshContainer -import androidx.compose.material3.pulltorefresh.PullToRefreshState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -110,7 +107,6 @@ fun SearchBarScreen( onApplySearch: (String) -> Unit, onSearchExpanded: () -> Unit, onSearchHidden: () -> Unit, - refreshState: PullToRefreshState? = null, suggestionProvider: SuggestionProvider? = null, tagNamespace: Boolean = false, searchBarOffsetY: () -> Int, @@ -222,12 +218,6 @@ fun SearchBarScreen( } } - val scrollAwayModifier = if (!expanded) { - Modifier.offset { IntOffset(0, searchBarOffsetY()) } - } else { - Modifier - } - BoxWithConstraints(modifier = Modifier.fillMaxSize()) { Scaffold( topBar = { @@ -240,13 +230,6 @@ fun SearchBarScreen( floatingActionButton = floatingActionButton, content = content, ) - if (refreshState != null) { - PullToRefreshContainer( - state = refreshState, - modifier = Modifier.align(Alignment.TopCenter).safeDrawingPadding() - .padding(top = 48.dp) then scrollAwayModifier, - ) - } // https://issuetracker.google.com/337191298 // Workaround for can't exit SearchBar due to refocus in non-touch mode Box(Modifier.size(1.dp).focusable()) @@ -260,7 +243,7 @@ fun SearchBarScreen( } val activeState = rememberCompositionActiveState() SearchBar( - modifier = Modifier.align(Alignment.TopCenter) then scrollAwayModifier + modifier = Modifier.align(Alignment.TopCenter).thenIf(!expanded) { offset { IntOffset(0, searchBarOffsetY()) } } .windowInsetsPadding(WindowInsets.navigationBars.only(WindowInsetsSides.Horizontal)), inputField = { SearchBarInputField( @@ -312,11 +295,9 @@ fun SearchBarScreen( activeState.Anchor() filter?.invoke() LazyColumn( - modifier = Modifier.fillMaxSize() - .windowInsetsPadding(WindowInsets.navigationBars.union(WindowInsets.ime).only(WindowInsetsSides.Bottom)), - // Workaround for https://issuetracker.google.com/332939169 - // contentPadding = WindowInsets.navigationBars.union(WindowInsets.ime) - // .only(WindowInsetsSides.Bottom).asPaddingValues(), + modifier = Modifier.fillMaxSize(), + contentPadding = WindowInsets.navigationBars.union(WindowInsets.ime) + .only(WindowInsetsSides.Bottom).asPaddingValues(), ) { // Workaround for prepending before the first item item {} diff --git a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/FilterScreen.kt b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/FilterScreen.kt index 586108e84..e6ccd5d02 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/FilterScreen.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/ui/settings/FilterScreen.kt @@ -215,9 +215,8 @@ fun FilterScreen(navigator: DestinationsNavigator) { ) { paddingValues -> Deferred({ allFilterMap.await() }) { filters -> LazyColumn( - modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection).padding(paddingValues), - // Workaround for https://issuetracker.google.com/332939169 - // contentPadding = paddingValues, + modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), + contentPadding = paddingValues, ) { var showTip = true filters.forEach { (filterMode, filters) -> diff --git a/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index 5a85499f9..3e6177ddd 100644 --- a/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/kotlin/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -44,8 +44,11 @@ import androidx.annotation.StringRes import androidx.compose.animation.animateColorAsState import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.statusBarsIgnoringVisibility +import androidx.compose.foundation.layout.only +import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.material3.BottomSheetDefaults import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme @@ -315,10 +318,11 @@ class ReaderActivity : EhActivity() { ) ModalBottomSheet( onDismissRequest = { dispose() }, + modifier = Modifier.windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Top)), dragHandle = null, // Yeah, I know color state should not be read here, but we have to do it... scrimColor = scrim, - windowInsets = WindowInsets.statusBarsIgnoringVisibility, + contentWindowInsets = { WindowInsets(0) }, ) { SettingsPager(modifier = Modifier.fillMaxSize()) { page -> isColorFilter = page == 2 @@ -648,7 +652,8 @@ class ReaderActivity : EhActivity() { dialogState.dialog { ModalBottomSheet( onDismissRequest = { it.cancel() }, - windowInsets = WindowInsets.statusBarsIgnoringVisibility, + modifier = Modifier.windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Top)), + contentWindowInsets = { WindowInsets(0) }, ) { ReaderPageSheet(page) { it.cancel() } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 69ed9331f..c73d126bb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -67,9 +67,9 @@ coil-gif = { module = "io.coil-kt.coil3:coil-gif" } coil-network = { module = "io.coil-kt.coil3:coil-network-ktor" } compose-bom = { module = "dev.chrisbanes.compose:compose-bom", version.ref = "compose-bom" } -compose-foundation = { module = "androidx.compose.foundation:foundation" } +compose-foundation = { module = "androidx.compose.foundation:foundation", version = "1.7.0-SNAPSHOT" } compose-material-icons-extended = { module = "androidx.compose.material:material-icons-extended" } -compose-material3 = { module = "androidx.compose.material3:material3" } +compose-material3 = { module = "androidx.compose.material3:material3", version = "1.3.0-SNAPSHOT" } compose-material3-windowsizeclass = { module = "androidx.compose.material3:material3-window-size-class" } compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" } compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 4bba947cd..dc5d2c181 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -12,6 +12,8 @@ dependencyResolutionManagement { google() mavenCentral() maven("https://jitpack.io") + // TODO: Remove on Compose 1.7.0-beta01 + maven("https://androidx.dev/snapshots/builds/11800816/artifacts/repository") } }