Track sheet fixes (#8673)

* Fix Track sheet not being disposed properly

* Change insets handling
This commit is contained in:
Ivan Iskandar 2022-12-04 22:27:02 +07:00 committed by GitHub
parent 696dc59ea5
commit 47f079891f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 81 additions and 73 deletions

View file

@ -3,6 +3,9 @@ package eu.kanade.presentation.components
import androidx.activity.compose.BackHandler
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.with
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.Orientation
@ -13,6 +16,7 @@ import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.consumedWindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.offset
@ -48,6 +52,10 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.core.lifecycle.DisposableEffectIgnoringConfiguration
import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.transitions.ScreenTransition
import eu.kanade.presentation.util.isTabletUi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest
@ -62,6 +70,49 @@ private val SheetAnimationSpec = tween<Float>(durationMillis = SheetAnimationDur
private const val ScrimAnimationDuration = 350
private val ScrimAnimationSpec = tween<Float>(durationMillis = ScrimAnimationDuration)
@Composable
fun NavigatorAdaptiveSheet(
screen: Screen,
tonalElevation: Dp = 1.dp,
enableSwipeDismiss: (Navigator) -> Boolean = { true },
onDismissRequest: () -> Unit,
) {
Navigator(
screen = screen,
content = { sheetNavigator ->
AdaptiveSheet(
tonalElevation = tonalElevation,
enableSwipeDismiss = enableSwipeDismiss(sheetNavigator),
onDismissRequest = onDismissRequest,
) {
ScreenTransition(
navigator = sheetNavigator,
transition = {
fadeIn(animationSpec = tween(220, delayMillis = 90)) with
fadeOut(animationSpec = tween(90))
},
)
BackHandler(
enabled = sheetNavigator.size > 1,
onBack = sheetNavigator::pop,
)
}
// Make sure screens are disposed no matter what
if (sheetNavigator.parent?.disposeBehavior?.disposeNestedNavigators == false) {
DisposableEffectIgnoringConfiguration {
onDispose {
sheetNavigator.items
.asReversed()
.forEach(sheetNavigator::dispose)
}
}
}
},
)
}
/**
* Sheet with adaptive position aligned to bottom on small screen, otherwise aligned to center
* and will not be able to dismissed with swipe gesture.
@ -212,6 +263,10 @@ fun AdaptiveSheetImpl(
.windowInsetsPadding(
WindowInsets.systemBars
.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
)
.consumedWindowInsets(
WindowInsets.systemBars
.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
),
shape = MaterialTheme.shapes.extraLarge.copy(bottomStart = ZeroCornerSize, bottomEnd = ZeroCornerSize),
tonalElevation = tonalElevation,

View file

@ -8,11 +8,13 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
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.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
@ -54,7 +56,6 @@ private const val UnsetStatusTextAlpha = 0.5F
fun TrackInfoDialogHome(
trackItems: List<TrackItem>,
dateFormat: DateFormat,
contentPadding: PaddingValues = PaddingValues(),
onStatusClick: (TrackItem) -> Unit,
onChapterClick: (TrackItem) -> Unit,
onScoreClick: (TrackItem) -> Unit,
@ -70,7 +71,7 @@ fun TrackInfoDialogHome(
.fillMaxWidth()
.verticalScroll(rememberScrollState())
.padding(16.dp)
.padding(contentPadding),
.windowInsetsPadding(WindowInsets.systemBars),
verticalArrangement = Arrangement.spacedBy(24.dp),
) {
trackItems.forEach { item ->

View file

@ -3,12 +3,14 @@ package eu.kanade.presentation.manga
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.shape.RoundedCornerShape
@ -41,7 +43,6 @@ import java.time.format.TextStyle
@Composable
fun TrackStatusSelector(
contentPadding: PaddingValues,
selection: Int,
onSelectionChange: (Int) -> Unit,
selections: Map<Int, String>,
@ -49,7 +50,6 @@ fun TrackStatusSelector(
onDismissRequest: () -> Unit,
) {
BaseSelector(
contentPadding = contentPadding,
title = stringResource(R.string.status),
content = {
val state = rememberLazyListState()
@ -91,7 +91,6 @@ fun TrackStatusSelector(
@Composable
fun TrackChapterSelector(
contentPadding: PaddingValues,
selection: Int,
onSelectionChange: (Int) -> Unit,
range: Iterable<Int>,
@ -99,7 +98,6 @@ fun TrackChapterSelector(
onDismissRequest: () -> Unit,
) {
BaseSelector(
contentPadding = contentPadding,
title = stringResource(R.string.chapters),
content = {
WheelTextPicker(
@ -119,7 +117,6 @@ fun TrackChapterSelector(
@Composable
fun TrackScoreSelector(
contentPadding: PaddingValues,
selection: String,
onSelectionChange: (String) -> Unit,
selections: List<String>,
@ -127,7 +124,6 @@ fun TrackScoreSelector(
onDismissRequest: () -> Unit,
) {
BaseSelector(
contentPadding = contentPadding,
title = stringResource(R.string.score),
content = {
WheelTextPicker(
@ -147,7 +143,6 @@ fun TrackScoreSelector(
@Composable
fun TrackDateSelector(
contentPadding: PaddingValues,
title: String,
selection: LocalDate,
onSelectionChange: (LocalDate) -> Unit,
@ -156,7 +151,6 @@ fun TrackDateSelector(
onDismissRequest: () -> Unit,
) {
BaseSelector(
contentPadding = contentPadding,
title = title,
content = {
Row(
@ -198,7 +192,6 @@ fun TrackDateSelector(
@Composable
private fun BaseSelector(
contentPadding: PaddingValues = PaddingValues(),
title: String,
content: @Composable BoxScope.() -> Unit,
thirdButton: @Composable (RowScope.() -> Unit)? = null,
@ -206,7 +199,7 @@ private fun BaseSelector(
onDismissRequest: () -> Unit,
) {
AlertDialogContent(
modifier = Modifier.padding(contentPadding),
modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars),
title = { Text(text = title) },
text = {
Box(

View file

@ -16,9 +16,11 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.paddingFromBaseline
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.shape.RoundedCornerShape
@ -34,7 +36,6 @@ import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
@ -47,7 +48,6 @@ import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.capitalize
import androidx.compose.ui.text.input.ImeAction
@ -60,6 +60,7 @@ import eu.kanade.presentation.components.Divider
import eu.kanade.presentation.components.EmptyScreen
import eu.kanade.presentation.components.LoadingScreen
import eu.kanade.presentation.components.MangaCover
import eu.kanade.presentation.components.Scaffold
import eu.kanade.presentation.components.ScrollbarLazyColumn
import eu.kanade.presentation.util.plus
import eu.kanade.presentation.util.runOnEnterKeyPressed
@ -69,7 +70,6 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch
@Composable
fun TrackServiceSearch(
contentPadding: PaddingValues = PaddingValues(),
query: TextFieldValue,
onQueryChange: (TextFieldValue) -> Unit,
onDispatchQuery: () -> Unit,
@ -87,12 +87,6 @@ fun TrackServiceSearch(
}
Scaffold(
contentWindowInsets = WindowInsets(
left = contentPadding.calculateLeftPadding(LocalLayoutDirection.current),
top = contentPadding.calculateTopPadding(),
right = contentPadding.calculateRightPadding(LocalLayoutDirection.current),
bottom = contentPadding.calculateBottomPadding(),
),
topBar = {
Column {
TopAppBar(
@ -161,7 +155,7 @@ fun TrackServiceSearch(
onClick = { onConfirmSelection() },
modifier = Modifier
.padding(12.dp)
.padding(bottom = contentPadding.calculateBottomPadding())
.windowInsetsPadding(WindowInsets.navigationBars)
.fillMaxWidth(),
elevation = ButtonDefaults.elevatedButtonElevation(),
) {

View file

@ -1,8 +1,6 @@
package eu.kanade.presentation.util
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.runtime.ProvidableCompositionLocal
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.staticCompositionLocalOf
import cafe.adriel.voyager.navigator.Navigator
@ -11,8 +9,6 @@ import cafe.adriel.voyager.navigator.Navigator
*/
val LocalBackPress: ProvidableCompositionLocal<(() -> Unit)?> = staticCompositionLocalOf { null }
val LocalNavigatorContentPadding: ProvidableCompositionLocal<PaddingValues> = compositionLocalOf { PaddingValues() }
interface Tab : cafe.adriel.voyager.navigator.tab.Tab {
suspend fun onReselect(navigator: Navigator) {}
}

View file

@ -5,19 +5,12 @@ import android.content.Intent
import android.net.Uri
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.with
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalContext
@ -28,21 +21,19 @@ import cafe.adriel.voyager.core.screen.uniqueScreenKey
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.navigator.currentOrThrow
import cafe.adriel.voyager.transitions.ScreenTransition
import eu.kanade.domain.chapter.model.Chapter
import eu.kanade.domain.manga.model.Manga
import eu.kanade.domain.manga.model.hasCustomCover
import eu.kanade.presentation.components.AdaptiveSheet
import eu.kanade.presentation.components.ChangeCategoryDialog
import eu.kanade.presentation.components.DuplicateMangaDialog
import eu.kanade.presentation.components.LoadingScreen
import eu.kanade.presentation.components.NavigatorAdaptiveSheet
import eu.kanade.presentation.manga.ChapterSettingsDialog
import eu.kanade.presentation.manga.EditCoverAction
import eu.kanade.presentation.manga.MangaScreen
import eu.kanade.presentation.manga.components.DeleteChaptersDialog
import eu.kanade.presentation.manga.components.DownloadCustomAmountDialog
import eu.kanade.presentation.manga.components.MangaCoverDialog
import eu.kanade.presentation.util.LocalNavigatorContentPadding
import eu.kanade.presentation.util.isTabletUi
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.source.Source
@ -170,31 +161,15 @@ class MangaScreen(
onSetAsDefault = screenModel::setCurrentSettingsAsDefault,
)
MangaInfoScreenModel.Dialog.TrackSheet -> {
var enableSwipeDismiss by remember { mutableStateOf(true) }
AdaptiveSheet(
enableSwipeDismiss = enableSwipeDismiss,
NavigatorAdaptiveSheet(
screen = TrackInfoDialogHomeScreen(
mangaId = successState.manga.id,
mangaTitle = successState.manga.title,
sourceId = successState.source.id,
),
enableSwipeDismiss = { it.lastItem is TrackInfoDialogHomeScreen },
onDismissRequest = onDismissRequest,
) { contentPadding ->
Navigator(
screen = TrackInfoDialogHomeScreen(
mangaId = successState.manga.id,
mangaTitle = successState.manga.title,
sourceId = successState.source.id,
),
content = {
enableSwipeDismiss = it.lastItem is TrackInfoDialogHomeScreen
CompositionLocalProvider(LocalNavigatorContentPadding provides contentPadding) {
ScreenTransition(
navigator = it,
transition = {
fadeIn(animationSpec = tween(220, delayMillis = 90)) with
fadeOut(animationSpec = tween(90))
},
)
}
},
)
}
)
}
MangaInfoScreenModel.Dialog.FullCover -> {
val sm = rememberScreenModel { MangaCoverScreenModel(successState.manga.id) }

View file

@ -4,8 +4,10 @@ import android.app.Application
import android.content.Context
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.ButtonDefaults
@ -51,7 +53,6 @@ import eu.kanade.presentation.manga.TrackInfoDialogHome
import eu.kanade.presentation.manga.TrackScoreSelector
import eu.kanade.presentation.manga.TrackServiceSearch
import eu.kanade.presentation.manga.TrackStatusSelector
import eu.kanade.presentation.util.LocalNavigatorContentPadding
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.track.EnhancedTrackService
@ -95,7 +96,6 @@ data class TrackInfoDialogHomeScreen(
TrackInfoDialogHome(
trackItems = state.trackItems,
dateFormat = dateFormat,
contentPadding = LocalNavigatorContentPadding.current,
onStatusClick = {
navigator.push(
TrackStatusSelectorScreen(
@ -153,8 +153,7 @@ data class TrackInfoDialogHomeScreen(
}
},
onOpenInBrowser = { openTrackerInBrowser(context, it) },
onRemoved = { sm.unregisterTracking(it.service.id) },
)
) { sm.unregisterTracking(it.service.id) }
}
/**
@ -257,7 +256,6 @@ private data class TrackStatusSelectorScreen(
}
val state by sm.state.collectAsState()
TrackStatusSelector(
contentPadding = LocalNavigatorContentPadding.current,
selection = state.selection,
onSelectionChange = sm::setSelection,
selections = remember { sm.getSelections() },
@ -308,7 +306,6 @@ private data class TrackChapterSelectorScreen(
val state by sm.state.collectAsState()
TrackChapterSelector(
contentPadding = LocalNavigatorContentPadding.current,
selection = state.selection,
onSelectionChange = sm::setSelection,
range = remember { sm.getRange() },
@ -364,7 +361,6 @@ private data class TrackScoreSelectorScreen(
val state by sm.state.collectAsState()
TrackScoreSelector(
contentPadding = LocalNavigatorContentPadding.current,
selection = state.selection,
onSelectionChange = sm::setSelection,
selections = remember { sm.getSelections() },
@ -422,7 +418,6 @@ private data class TrackDateSelectorScreen(
track.finished_reading_date > 0
}
TrackDateSelector(
contentPadding = LocalNavigatorContentPadding.current,
title = if (start) {
stringResource(R.string.track_started_reading_date)
} else {
@ -497,7 +492,7 @@ private data class TrackDateRemoverScreen(
)
}
AlertDialogContent(
modifier = Modifier.padding(LocalNavigatorContentPadding.current),
modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars),
icon = {
Icon(
imageVector = Icons.Default.Delete,
@ -585,7 +580,6 @@ data class TrackServiceSearchScreen(
var textFieldValue by remember { mutableStateOf(TextFieldValue(initialQuery)) }
TrackServiceSearch(
contentPadding = LocalNavigatorContentPadding.current,
query = textFieldValue,
onQueryChange = { textFieldValue = it },
onDispatchQuery = { sm.trackingSearch(textFieldValue.text) },