diff --git a/app/src/main/kotlin/com/imashnake/animite/features/MainActivity.kt b/app/src/main/kotlin/com/imashnake/animite/features/MainActivity.kt index af8bb3f6..550c82fa 100644 --- a/app/src/main/kotlin/com/imashnake/animite/features/MainActivity.kt +++ b/app/src/main/kotlin/com/imashnake/animite/features/MainActivity.kt @@ -50,11 +50,6 @@ class MainActivity : ComponentActivity() { enableEdgeToEdge() - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - window.attributes.layoutInDisplayCutoutMode = - WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES - } - setContent { AnimiteTheme { MainScreen( diff --git a/app/src/main/kotlin/com/imashnake/animite/features/home/HomeScreen.kt b/app/src/main/kotlin/com/imashnake/animite/features/home/HomeScreen.kt index df5f739a..a93220e4 100644 --- a/app/src/main/kotlin/com/imashnake/animite/features/home/HomeScreen.kt +++ b/app/src/main/kotlin/com/imashnake/animite/features/home/HomeScreen.kt @@ -16,13 +16,19 @@ import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.calculateEndPadding +import androidx.compose.foundation.layout.calculateStartPadding import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.requiredWidth +import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState @@ -53,6 +59,7 @@ import androidx.compose.ui.graphics.ShaderBrush import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -66,8 +73,8 @@ import com.imashnake.animite.api.anilist.sanitize.media.Media import com.imashnake.animite.api.anilist.sanitize.media.MediaList import com.imashnake.animite.api.anilist.type.MediaType import com.imashnake.animite.core.data.Resource +import com.imashnake.animite.core.extensions.Paddings import com.imashnake.animite.core.extensions.bannerParallax -import com.imashnake.animite.core.extensions.landscapeCutoutPadding import com.imashnake.animite.core.extensions.thenIf import com.imashnake.animite.core.ui.LocalPaddings import com.imashnake.animite.core.ui.MediaCard @@ -93,7 +100,10 @@ fun HomeScreen( sharedTransitionScope: SharedTransitionScope, animatedVisibilityScope: AnimatedVisibilityScope, viewModel: HomeViewModel = hiltViewModel(), + contentWindowInsets: WindowInsets = WindowInsets.safeDrawing, ) { + val insetPaddingValues = contentWindowInsets.asPaddingValues() + val homeMediaType = rememberSaveable { mutableStateOf(MediaType.ANIME) } viewModel.setMediaType(homeMediaType.value) @@ -126,11 +136,7 @@ fun HomeScreen( rows.all { it is Resource.Success } -> { val scrollState = rememberScrollState() TranslucentStatusBarLayout(scrollState) { - Box( - modifier = Modifier - .verticalScroll(scrollState) - .navigationBarsPadding() - ) { + Box(Modifier.verticalScroll(scrollState)) { BannerLayout( banner = { bannerModifier -> Box { @@ -143,29 +149,39 @@ fun HomeScreen( ) Row( - modifier = bannerModifier.thenIf(shader != null) { - drawWithCache @SuppressLint("NewApi") { - shader!!.run { - setFloatUniform( - "resolution", - size.width, - size.height - ) - setFloatUniform("time", time.floatValue) - setColorUniform( - "orb", - Color(0xFF6C408D).toArgb() - ) - setColorUniform( - "bg", - android.graphics.Color.TRANSPARENT - ) - onDrawBehind { - drawRect(ShaderBrush(this@run)) + modifier = bannerModifier + .thenIf(shader != null) { + drawWithCache @SuppressLint("NewApi") { + shader!!.run { + setFloatUniform( + "resolution", + size.width, + size.height + ) + setFloatUniform("time", time.floatValue) + setColorUniform( + "orb", + Color(0xFF6C408D).toArgb() + ) + setColorUniform( + "bg", + android.graphics.Color.TRANSPARENT + ) + onDrawBehind { + drawRect(ShaderBrush(this@run)) + } } } } - }, + .padding( + horizontal = LocalPaddings.current.large, + vertical = LocalPaddings.current.medium + ) + .padding( + start = insetPaddingValues.calculateStartPadding(LocalLayoutDirection.current), + top = insetPaddingValues.calculateTopPadding(), + end = insetPaddingValues.calculateEndPadding(LocalLayoutDirection.current), + ), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.Bottom, ) { @@ -177,22 +193,11 @@ fun HomeScreen( } ?: MaterialTheme.colorScheme.secondaryContainer, style = MaterialTheme.typography.displayMedium, modifier = Modifier - .padding( - start = LocalPaddings.current.large, - bottom = LocalPaddings.current.medium - ) - .landscapeCutoutPadding() .weight(1f, fill = false), maxLines = 1 ) MediaTypeSelector( - modifier = Modifier - .padding( - end = LocalPaddings.current.large, - bottom = LocalPaddings.current.medium - ) - .landscapeCutoutPadding(), selectedOption = homeMediaType, viewModel = viewModel ) @@ -210,15 +215,14 @@ fun HomeScreen( }, label = "animate_home_row" ) { mediaList -> - if (mediaList.list.isNotEmpty()) + if (mediaList.list.isNotEmpty()) { HomeRow( - list = mediaList.list, + items = mediaList.list, type = mediaList.type, onItemClicked = { media -> onNavigateToMediaItem( MediaPage( id = media.id, - // TODO: We can use the list's index instead. source = mediaList.type.name, mediaType = homeMediaType.value.rawValue, ) @@ -226,42 +230,53 @@ fun HomeScreen( }, sharedTransitionScope = sharedTransitionScope, animatedVisibilityScope = animatedVisibilityScope, - modifier = Modifier.padding( - vertical = LocalPaddings.current.large / 2 + contentPadding = Paddings( + horizontal = LocalPaddings.current.large, + vertical = LocalPaddings.current.large / 2, + ) + Paddings( + start = insetPaddingValues.calculateStartPadding(LocalLayoutDirection.current), + end = insetPaddingValues.calculateEndPadding(LocalLayoutDirection.current), ) ) - else - /* With this, AnimatedContent shrinks/expands the - `HomeRow` vertically. */ + } else { Box(Modifier.fillMaxWidth()) + } } } } }, - contentModifier = Modifier.padding( - top = LocalPaddings.current.large / 2, - bottom = LocalPaddings.current.large / 2 + - dimensionResource(navigationR.dimen.navigation_bar_height) - ), + contentModifier = Modifier + .padding( + top = LocalPaddings.current.large / 2, + bottom = LocalPaddings.current.large / 2 + + dimensionResource(navigationR.dimen.navigation_bar_height) + ) + .navigationBarsPadding(), verticalArrangement = Arrangement.spacedBy(0.dp) ) } } } - else -> ProgressIndicatorScreen() + else -> ProgressIndicatorScreen(Modifier.padding(insetPaddingValues)) } } @Composable fun HomeRow( - list: List, + items: List, type: MediaList.Type, onItemClicked: (Media.Small) -> Unit, sharedTransitionScope: SharedTransitionScope, animatedVisibilityScope: AnimatedVisibilityScope, modifier: Modifier = Modifier, + contentPadding: PaddingValues = PaddingValues() ) { - MediaSmallRow(type.title, list, modifier) { media -> + MediaSmallRow( + title = type.title, + mediaList = items, + modifier = modifier, + contentPadding = contentPadding, + ) { media -> with(sharedTransitionScope) { MediaCard( image = media.coverImage, diff --git a/app/src/main/kotlin/com/imashnake/animite/features/searchbar/SearchFab.kt b/app/src/main/kotlin/com/imashnake/animite/features/searchbar/SearchFab.kt index 408fc78d..dccde7d9 100644 --- a/app/src/main/kotlin/com/imashnake/animite/features/searchbar/SearchFab.kt +++ b/app/src/main/kotlin/com/imashnake/animite/features/searchbar/SearchFab.kt @@ -36,7 +36,6 @@ import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.input.ImeAction -import androidx.compose.ui.unit.dp import com.imashnake.animite.R /** diff --git a/app/src/main/kotlin/com/imashnake/animite/features/searchbar/SearchFrontDrop.kt b/app/src/main/kotlin/com/imashnake/animite/features/searchbar/SearchFrontDrop.kt index 2c301c5e..49ebca9d 100644 --- a/app/src/main/kotlin/com/imashnake/animite/features/searchbar/SearchFrontDrop.kt +++ b/app/src/main/kotlin/com/imashnake/animite/features/searchbar/SearchFrontDrop.kt @@ -7,21 +7,24 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.calculateEndPadding +import androidx.compose.foundation.layout.calculateStartPadding import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.imeNestedScroll import androidx.compose.foundation.layout.imePadding -import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.MaterialTheme @@ -35,6 +38,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow @@ -45,7 +49,7 @@ import com.imashnake.animite.R import com.imashnake.animite.api.anilist.sanitize.search.Search import com.imashnake.animite.api.anilist.type.MediaType import com.imashnake.animite.core.Constants -import com.imashnake.animite.core.extensions.landscapeCutoutPadding +import com.imashnake.animite.core.extensions.Paddings import com.imashnake.animite.core.ui.LocalPaddings import com.imashnake.animite.core.ui.MediaCard import com.imashnake.animite.core.R as coreR @@ -60,19 +64,23 @@ import com.imashnake.animite.navigation.R as navigationR * @param modifier the [Modifier] to be applied to this Front Drop. * @param viewModel [SearchViewModel] instance. */ +@OptIn(ExperimentalLayoutApi::class) @Composable fun SearchFrontDrop( hasExtraPadding: Boolean, onItemClick: (Int, MediaType) -> Unit, modifier: Modifier = Modifier, + contentWindowInsets: WindowInsets = WindowInsets.safeDrawing, viewModel: SearchViewModel = viewModel() ) { + val insetPaddingValues = contentWindowInsets.asPaddingValues() + val searchMediaType = MediaType.ANIME viewModel.setMediaType(searchMediaType) val searchList by viewModel.searchList.collectAsState() var isExpanded by rememberSaveable { mutableStateOf(false) } - val searchBarBottomPadding: Dp by animateDpAsState( + val searchBarBottomPadding by animateDpAsState( targetValue = if (hasExtraPadding) { dimensionResource(navigationR.dimen.navigation_bar_height) } else 0.dp, @@ -95,10 +103,9 @@ fun SearchFrontDrop( searchList.data?.let { SearchList( searchList = it, - modifier = Modifier - // TODO: Add this back; https://issuetracker.google.com/issues/323708850. - //.imeNestedScroll() - .landscapeCutoutPadding(), + modifier = Modifier.imeNestedScroll(), + contentPadding = insetPaddingValues, + searchBarBottomPadding = searchBarBottomPadding, onItemClick = { id -> isExpanded = false viewModel.setQuery(null) @@ -112,7 +119,11 @@ fun SearchFrontDrop( setExpanded = { isExpanded = it }, onSearched = viewModel::setQuery, modifier = modifier - .landscapeCutoutPadding() + .padding( + start = insetPaddingValues.calculateStartPadding(LocalLayoutDirection.current), + top = insetPaddingValues.calculateTopPadding(), + end = insetPaddingValues.calculateEndPadding(LocalLayoutDirection.current) + ) .padding(bottom = searchBarBottomPadding) .navigationBarsPadding() .consumeWindowInsets(PaddingValues(bottom = searchBarBottomPadding)) @@ -124,21 +135,26 @@ fun SearchFrontDrop( @Composable fun SearchList( searchList: List, + searchBarBottomPadding: Dp, + onItemClick: (Int) -> Unit, modifier: Modifier = Modifier, - onItemClick: (Int) -> Unit + contentPadding: PaddingValues = PaddingValues(), ) { LazyColumn( - modifier = modifier, - contentPadding = PaddingValues( - start = LocalPaddings.current.large, - end = LocalPaddings.current.large, - top = LocalPaddings.current.large - + WindowInsets.statusBars.asPaddingValues().calculateTopPadding(), - bottom = dimensionResource(R.dimen.search_bar_height) - + LocalPaddings.current.large - + LocalPaddings.current.large - + dimensionResource(navigationR.dimen.navigation_bar_height) - + WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + modifier = modifier + .padding(bottom = searchBarBottomPadding) + .navigationBarsPadding() + .consumeWindowInsets(PaddingValues(bottom = searchBarBottomPadding)) + .imePadding(), + contentPadding = Paddings( + all = LocalPaddings.current.large + ) + Paddings( + bottom = LocalPaddings.current.large + + dimensionResource(R.dimen.search_bar_height) + ) + Paddings( + start = contentPadding.calculateStartPadding(LocalLayoutDirection.current), + top = contentPadding.calculateTopPadding(), + end = contentPadding.calculateEndPadding(LocalLayoutDirection.current), ), verticalArrangement = Arrangement.spacedBy(LocalPaddings.current.small) ) { diff --git a/core/src/main/kotlin/com/imashnake/animite/core/extensions/ModifierExt.kt b/core/src/main/kotlin/com/imashnake/animite/core/extensions/ModifierExt.kt index 815437b4..2697a6d7 100644 --- a/core/src/main/kotlin/com/imashnake/animite/core/extensions/ModifierExt.kt +++ b/core/src/main/kotlin/com/imashnake/animite/core/extensions/ModifierExt.kt @@ -1,24 +1,12 @@ package com.imashnake.animite.core.extensions -import android.content.res.Configuration import androidx.compose.foundation.ScrollState -import androidx.compose.foundation.layout.displayCutoutPadding import androidx.compose.foundation.layout.heightIn import androidx.compose.ui.Modifier -import androidx.compose.ui.composed import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -fun Modifier.landscapeCutoutPadding() = composed { - if (LocalConfiguration.current.orientation == Configuration.ORIENTATION_LANDSCAPE) { - displayCutoutPadding() - } else { - this - } -} - fun Modifier.bannerParallax(scrollState: ScrollState) = graphicsLayer { translationY = 0.7f * scrollState.value } diff --git a/core/src/main/kotlin/com/imashnake/animite/core/extensions/PaddingValuesExt.kt b/core/src/main/kotlin/com/imashnake/animite/core/extensions/PaddingValuesExt.kt new file mode 100644 index 00000000..0859e021 --- /dev/null +++ b/core/src/main/kotlin/com/imashnake/animite/core/extensions/PaddingValuesExt.kt @@ -0,0 +1,79 @@ +@file:Suppress("FunctionName", "unused") + +package com.imashnake.animite.core.extensions + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.runtime.Stable +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp + +@Stable +fun Paddings(all: Dp) = PaddingValuesExt(all, all, all, all) + +@Stable +fun Paddings( + horizontal: Dp = 0.dp, + vertical: Dp = 0.dp +) = PaddingValuesExt(horizontal, vertical, horizontal, vertical) + +@Stable +fun Paddings( + start: Dp = 0.dp, + top: Dp = 0.dp, + end: Dp = 0.dp, + bottom: Dp = 0.dp +) = PaddingValuesExt(start, top, end, bottom) + +class PaddingValuesExt internal constructor( + @Stable + val start: Dp = 0.dp, + @Stable + val top: Dp = 0.dp, + @Stable + val end: Dp = 0.dp, + @Stable + val bottom: Dp = 0.dp, +) : PaddingValues { + init { + require(start.value >= 0) { "Start padding must be non-negative" } + require(top.value >= 0) { "Top padding must be non-negative" } + require(end.value >= 0) { "End padding must be non-negative" } + require(bottom.value >= 0) { "Bottom padding must be non-negative" } + } + + override fun calculateLeftPadding(layoutDirection: LayoutDirection) = + if (layoutDirection == LayoutDirection.Ltr) start else end + + override fun calculateTopPadding() = top + + override fun calculateRightPadding(layoutDirection: LayoutDirection) = + if (layoutDirection == LayoutDirection.Ltr) end else start + + override fun calculateBottomPadding() = bottom + + override fun equals(other: Any?): Boolean { + if (other !is PaddingValuesExt) return false + return start == other.start && + top == other.top && + end == other.end && + bottom == other.bottom + } + + override fun hashCode() = + ((start.hashCode() * 31 + top.hashCode()) * 31 + end.hashCode()) * 31 + bottom.hashCode() + + override fun toString() = "PaddingValues(start=$start, top=$top, end=$end, bottom=$bottom)" + + /** + * Add paddings without regard to the current [LayoutDirection]. + */ + operator fun plus(other: PaddingValuesExt): PaddingValuesExt { + return Paddings( + start = start + other.start, + top = top + other.top, + end = end + other.end, + bottom = bottom + other.bottom, + ) + } +} diff --git a/core/src/main/kotlin/com/imashnake/animite/core/ui/MediaSmall.kt b/core/src/main/kotlin/com/imashnake/animite/core/ui/MediaSmall.kt index d24691d7..b8f39fcf 100644 --- a/core/src/main/kotlin/com/imashnake/animite/core/ui/MediaSmall.kt +++ b/core/src/main/kotlin/com/imashnake/animite/core/ui/MediaSmall.kt @@ -1,13 +1,11 @@ package com.imashnake.animite.core.ui -import android.content.res.Configuration import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.asPaddingValues -import androidx.compose.foundation.layout.displayCutout +import androidx.compose.foundation.layout.calculateEndPadding +import androidx.compose.foundation.layout.calculateStartPadding import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -23,17 +21,15 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage import com.imashnake.animite.core.R import com.imashnake.animite.core.extensions.crossfadeModel -import com.imashnake.animite.core.extensions.landscapeCutoutPadding /** * A [LazyRow] of [MediaSmall]s. @@ -45,33 +41,35 @@ fun MediaSmallRow( title: String?, mediaList: List, modifier: Modifier = Modifier, + contentPadding: PaddingValues = PaddingValues(), content: @Composable (T) -> Unit ) { Column( - modifier = modifier, + modifier = modifier.padding( + top = contentPadding.calculateTopPadding(), + bottom = contentPadding.calculateBottomPadding() + ), verticalArrangement = Arrangement.spacedBy(LocalPaddings.current.medium) ) { - // TODO: Does this behave as expected if `title` is null? + val layoutDirection = LocalLayoutDirection.current + val startPadding = contentPadding.calculateStartPadding(layoutDirection) + val endPadding = contentPadding.calculateEndPadding(layoutDirection) if (title != null) { Text( text = title, color = MaterialTheme.colorScheme.onBackground, style = MaterialTheme.typography.titleMedium, - modifier = Modifier - .padding(start = LocalPaddings.current.large) - .landscapeCutoutPadding() + modifier = Modifier.padding( + start = startPadding, + end = endPadding, + ) ) } LazyRow( horizontalArrangement = Arrangement.spacedBy(LocalPaddings.current.small), contentPadding = PaddingValues( - start = LocalPaddings.current.large + if ( - LocalConfiguration.current.orientation == Configuration.ORIENTATION_LANDSCAPE - ) { - WindowInsets.displayCutout.asPaddingValues() - .calculateLeftPadding(LayoutDirection.Ltr) - } else 0.dp, - end = LocalPaddings.current.large + start = startPadding, + end = endPadding, ) ) { items(mediaList) { media -> diff --git a/core/src/main/kotlin/com/imashnake/animite/core/ui/layouts/BannerLayout.kt b/core/src/main/kotlin/com/imashnake/animite/core/ui/layouts/BannerLayout.kt index 40af740a..d8fd0e4c 100644 --- a/core/src/main/kotlin/com/imashnake/animite/core/ui/layouts/BannerLayout.kt +++ b/core/src/main/kotlin/com/imashnake/animite/core/ui/layouts/BannerLayout.kt @@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable @@ -50,7 +49,6 @@ fun BannerLayout( .fillMaxSize() .padding(top = bannerHeight) .background(MaterialTheme.colorScheme.background) - .navigationBarsPadding() .then(contentModifier), verticalArrangement = verticalArrangement ) { content() } diff --git a/media/src/main/kotlin/com/imashnake/animite/media/MediaPage.kt b/media/src/main/kotlin/com/imashnake/animite/media/MediaPage.kt index 68f38ac9..690ef1bd 100644 --- a/media/src/main/kotlin/com/imashnake/animite/media/MediaPage.kt +++ b/media/src/main/kotlin/com/imashnake/animite/media/MediaPage.kt @@ -1,7 +1,6 @@ package com.imashnake.animite.media import android.content.Intent -import android.content.res.Configuration import android.util.Log import androidx.compose.animation.AnimatedVisibilityScope import androidx.compose.animation.SharedTransitionScope @@ -18,13 +17,15 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.aspectRatio -import androidx.compose.foundation.layout.displayCutout +import androidx.compose.foundation.layout.calculateEndPadding +import androidx.compose.foundation.layout.calculateStartPadding 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.navigationBarsPadding import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.statusBars +import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.lazy.LazyRow @@ -54,15 +55,14 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.painter.ColorPainter import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.fromHtml import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.core.net.toUri import androidx.hilt.navigation.compose.hiltViewModel @@ -71,9 +71,9 @@ import coil3.request.ImageRequest import coil3.request.crossfade import com.imashnake.animite.api.anilist.sanitize.media.Media import com.imashnake.animite.core.Constants +import com.imashnake.animite.core.extensions.Paddings import com.imashnake.animite.core.extensions.bannerParallax import com.imashnake.animite.core.extensions.crossfadeModel -import com.imashnake.animite.core.extensions.landscapeCutoutPadding import com.imashnake.animite.core.ui.CharacterCard import com.imashnake.animite.core.ui.LocalPaddings import com.imashnake.animite.core.ui.MediaCard @@ -103,7 +103,15 @@ fun MediaPage( sharedTransitionScope: SharedTransitionScope, animatedVisibilityScope: AnimatedVisibilityScope, viewModel: MediaPageViewModel = hiltViewModel(), + contentWindowInsets: WindowInsets = WindowInsets.safeDrawing, ) { + val insetPaddingValues = contentWindowInsets.asPaddingValues() + val layoutDirection = LocalLayoutDirection.current + val horizontalInsets = Paddings( + start = insetPaddingValues.calculateStartPadding(layoutDirection), + end = insetPaddingValues.calculateEndPadding(layoutDirection), + ) + val scrollState = rememberScrollState() val media = viewModel.uiState @@ -154,13 +162,9 @@ fun MediaPage( description = media.description.orEmpty(), modifier = Modifier .skipToLookaheadSize() - .padding( - start = LocalPaddings.current.large / 2 - + dimensionResource(coreR.dimen.media_card_width) - + LocalPaddings.current.large, - end = LocalPaddings.current.large / 2 - ) - .landscapeCutoutPadding() + .padding(horizontal = LocalPaddings.current.large / 2) + .padding(start = dimensionResource(coreR.dimen.media_card_width) + LocalPaddings.current.large) + .padding(horizontalInsets) .height( dimensionResource(R.dimen.media_details_height) + LocalPaddings.current.medium / 2 ), @@ -183,7 +187,7 @@ fun MediaPage( modifier = Modifier .fillMaxWidth() .padding(horizontal = LocalPaddings.current.large) - .landscapeCutoutPadding() + .padding(horizontalInsets) ) { Text( text = it.type.name, @@ -206,14 +210,11 @@ fun MediaPage( if (!media.genres.isNullOrEmpty()) { MediaGenres( genres = media.genres, - contentPadding = PaddingValues( - start = LocalPaddings.current.large + if ( - LocalConfiguration.current.orientation == Configuration.ORIENTATION_LANDSCAPE - ) { - WindowInsets.displayCutout.asPaddingValues() - .calculateLeftPadding(LayoutDirection.Ltr) - } else 0.dp, - end = LocalPaddings.current.large + contentPadding = Paddings( + horizontal = LocalPaddings.current.large + ) + Paddings( + start = horizontalInsets.calculateStartPadding(LocalLayoutDirection.current), + end = horizontalInsets.calculateEndPadding(LocalLayoutDirection.current), ), color = Color(media.color ?: 0xFF152232.toInt()), ) @@ -222,6 +223,9 @@ fun MediaPage( if (!media.characters.isNullOrEmpty()) { MediaCharacters( characters = media.characters, + contentPadding = Paddings( + horizontal = LocalPaddings.current.large + ) + horizontalInsets, ) } @@ -230,11 +234,13 @@ fun MediaPage( trailer = media.trailer, modifier = Modifier .padding(horizontal = LocalPaddings.current.large) - .landscapeCutoutPadding() + .padding(horizontalInsets) ) } }, - contentModifier = Modifier.padding(top = LocalPaddings.current.medium / 2) + contentModifier = Modifier + .padding(top = LocalPaddings.current.medium / 2) + .navigationBarsPadding() ) // TODO: https://developer.android.com/jetpack/compose/animation/quick-guide#concurrent-animations @@ -255,14 +261,12 @@ fun MediaPage( top = dimensionResource(R.dimen.media_details_height) + LocalPaddings.current.medium + dimensionResource(coreR.dimen.banner_height) - - WindowInsets.statusBars - .asPaddingValues() - .calculateTopPadding() - dimensionResource(coreR.dimen.media_image_height) + - insetPaddingValues.calculateTopPadding() + offset, - start = LocalPaddings.current.large + start = LocalPaddings.current.large, ) - .landscapeCutoutPadding() + .padding(horizontalInsets) .height(dimensionResource(coreR.dimen.media_image_height) - offset) ) { MediaCard( @@ -417,11 +421,13 @@ fun MediaGenres( fun MediaCharacters( characters: List, modifier: Modifier = Modifier, + contentPadding: PaddingValues = PaddingValues() ) { MediaSmallRow( title = stringResource(R.string.characters), mediaList = characters, - modifier = modifier + modifier = modifier, + contentPadding = contentPadding, ) { character -> CharacterCard( image = character.image, diff --git a/navigation/src/main/kotlin/com/imashnake/animite/navigation/NavigationBar.kt b/navigation/src/main/kotlin/com/imashnake/animite/navigation/NavigationBar.kt index b33c2d83..74c8e19f 100644 --- a/navigation/src/main/kotlin/com/imashnake/animite/navigation/NavigationBar.kt +++ b/navigation/src/main/kotlin/com/imashnake/animite/navigation/NavigationBar.kt @@ -1,25 +1,31 @@ package com.imashnake.animite.navigation -import android.content.res.Configuration import androidx.annotation.StringRes +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.asPaddingValues -import androidx.compose.foundation.layout.displayCutout +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.navigationBars -import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.foundation.selection.selectableGroup import androidx.compose.material3.Icon -import androidx.compose.material3.NavigationBar +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.NavigationBarDefaults import androidx.compose.material3.NavigationBarItem +import androidx.compose.material3.Surface +import androidx.compose.material3.contentColorFor import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.navigation.NavBackStackEntry import androidx.navigation.NavController @@ -30,35 +36,42 @@ import androidx.navigation.compose.currentBackStackEntryAsState @Composable fun NavigationBar( - navController: NavController + navController: NavController, + modifier: Modifier = Modifier, + containerColor: Color = NavigationBarDefaults.containerColor, + contentColor: Color = MaterialTheme.colorScheme.contentColorFor(containerColor), + tonalElevation: Dp = NavigationBarDefaults.Elevation, + windowInsets: WindowInsets = NavigationBarDefaults.windowInsets, ) { val currentBackStackEntry by navController.currentBackStackEntryAsState() - // TODO: Can we use `navigationBarsPadding()` instead? - NavigationBar( - Modifier.height( - dimensionResource(R.dimen.navigation_bar_height) + WindowInsets - .navigationBars - .asPaddingValues() - .calculateBottomPadding() - ), - // TODO: Use a `NavigationRail` instead. - windowInsets = if (LocalConfiguration.current.orientation - == Configuration.ORIENTATION_LANDSCAPE - ) { WindowInsets.displayCutout } else { WindowInsets(0.dp) } + // This is a clone of Material3 NavigationBar, except we've shrunk the height from 80dp to 65dp + Surface( + color = containerColor, + contentColor = contentColor, + tonalElevation = tonalElevation, + modifier = modifier ) { - NavigationBarPaths.entries.forEach { destination -> - val selected = remember(destination, currentBackStackEntry) { - currentBackStackEntry?.let { destination.matchesDestination(it) } ?: false + Row( + modifier = Modifier + .fillMaxWidth() + .windowInsetsPadding(windowInsets) + .defaultMinSize(minHeight = dimensionResource(R.dimen.navigation_bar_height)) + .selectableGroup(), + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + NavigationBarPaths.entries.forEach { destination -> + val selected = remember(destination, currentBackStackEntry) { + currentBackStackEntry?.let { destination.matchesDestination(it) } == true + } + NavigationBarItem( + modifier = Modifier.height(dimensionResource(R.dimen.navigation_bar_height)), + selected = selected, + onClick = { if (!selected) destination.navigateTo(navController) }, + icon = destination.icon + ) } - NavigationBarItem( - modifier = Modifier.navigationBarsPadding(), - selected = selected, - onClick = { - if (!selected) destination.navigateTo(navController) - }, - icon = destination.icon - ) } } } @@ -122,4 +135,4 @@ enum class NavigationBarPaths( }, labelRes = R.string.profile ), -} \ No newline at end of file +} diff --git a/profile/src/main/kotlin/com/imashnake/animite/profile/ProfileScreen.kt b/profile/src/main/kotlin/com/imashnake/animite/profile/ProfileScreen.kt index eeb3656f..e2bfdfd2 100644 --- a/profile/src/main/kotlin/com/imashnake/animite/profile/ProfileScreen.kt +++ b/profile/src/main/kotlin/com/imashnake/animite/profile/ProfileScreen.kt @@ -3,11 +3,17 @@ package com.imashnake.animite.profile import androidx.compose.animation.AnimatedVisibilityScope import androidx.compose.animation.SharedTransitionScope import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.WindowInsets +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.padding +import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.size import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState @@ -27,6 +33,7 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow @@ -37,13 +44,12 @@ import com.boswelja.markdown.material3.MarkdownDocument import com.boswelja.markdown.material3.m3TextStyles import com.imashnake.animite.api.anilist.sanitize.profile.User import com.imashnake.animite.core.data.Resource +import com.imashnake.animite.core.extensions.Paddings import com.imashnake.animite.core.extensions.animiteBlockQuoteStyle import com.imashnake.animite.core.extensions.animiteCodeBlockStyle import com.imashnake.animite.core.extensions.crossfadeModel -import com.imashnake.animite.core.extensions.landscapeCutoutPadding import com.imashnake.animite.core.extensions.maxHeight import com.imashnake.animite.core.ui.FallbackMessage -import com.imashnake.animite.core.ui.FallbackScreen import com.imashnake.animite.core.ui.LocalPaddings import com.imashnake.animite.core.ui.NestedScrollableContent import com.imashnake.animite.core.ui.ProgressIndicatorScreen @@ -64,7 +70,15 @@ fun ProfileScreen( sharedTransitionScope: SharedTransitionScope, animatedVisibilityScope: AnimatedVisibilityScope, viewModel: ProfileViewModel = hiltViewModel(), + contentWindowInsets: WindowInsets = WindowInsets.safeDrawing, ) { + val insetPaddingValues = contentWindowInsets.asPaddingValues() + val layoutDirection = LocalLayoutDirection.current + val horizontalInsets = Paddings( + start = insetPaddingValues.calculateStartPadding(layoutDirection), + end = insetPaddingValues.calculateEndPadding(layoutDirection), + ) + val isLoggedIn by viewModel.isLoggedIn.collectAsState(initial = false) val viewer by viewModel.viewer.collectAsState() val viewerAnimeLists by viewModel.viewerAnimeLists.collectAsState() @@ -95,31 +109,29 @@ fun ProfileScreen( contentDescription = "avatar", modifier = Modifier .align(Alignment.BottomStart) - .landscapeCutoutPadding() .padding(start = LocalPaddings.current.medium) + .padding(horizontalInsets) .size(100.dp) ) } }, content = { - Column { - Text( - text = name, - color = MaterialTheme.colorScheme.onBackground, - style = MaterialTheme.typography.titleLarge, - overflow = TextOverflow.Ellipsis, - modifier = Modifier - .padding(horizontal = LocalPaddings.current.large) - .landscapeCutoutPadding() - ) - UserDescription( - description = description, - modifier = Modifier - .maxHeight(dimensionResource(R.dimen.user_about_height)) - .padding(horizontal = LocalPaddings.current.large) - .landscapeCutoutPadding() - ) - Spacer(Modifier.size(LocalPaddings.current.medium)) + Column(verticalArrangement = Arrangement.spacedBy(LocalPaddings.current.medium)) { + Column(Modifier.padding(horizontalInsets)) { + Text( + text = name, + color = MaterialTheme.colorScheme.onBackground, + style = MaterialTheme.typography.titleLarge, + overflow = TextOverflow.Ellipsis, + modifier = Modifier.padding(horizontal = LocalPaddings.current.large) + ) + UserDescription( + description = description, + modifier = Modifier + .maxHeight(dimensionResource(R.dimen.user_about_height)) + .padding(horizontal = LocalPaddings.current.large) + ) + } UserTabs( user = this@run, animeCollection = viewerAnimeLists.data, @@ -127,12 +139,14 @@ fun ProfileScreen( onNavigateToMediaItem = onNavigateToMediaItem, sharedTransitionScope = sharedTransitionScope, animatedVisibilityScope = animatedVisibilityScope, + contentInsetPadding = horizontalInsets ) } }, contentModifier = Modifier.padding( - top = LocalPaddings.current.large, - bottom = dimensionResource(navigationR.dimen.navigation_bar_height) + top = LocalPaddings.current.large / 2, + bottom = LocalPaddings.current.large / 2 + + dimensionResource(navigationR.dimen.navigation_bar_height) ) ) } @@ -175,6 +189,7 @@ private fun UserTabs( sharedTransitionScope: SharedTransitionScope, animatedVisibilityScope: AnimatedVisibilityScope, modifier: Modifier = Modifier, + contentInsetPadding: PaddingValues = PaddingValues(), ) { val coroutineScope = rememberCoroutineScope() val pagerState = rememberPagerState(pageCount = { ProfileTab.entries.size }) @@ -184,9 +199,9 @@ private fun UserTabs( Column(modifier) { PrimaryTabRow( selectedTabIndex = pagerState.currentPage, - modifier = Modifier.landscapeCutoutPadding(), containerColor = MaterialTheme.colorScheme.background, - divider = {} + divider = {}, + modifier = Modifier.padding(contentInsetPadding) ) { titles.forEachIndexed { index, tab -> Tab( @@ -229,23 +244,57 @@ private fun UserTabs( ) { page -> Box(Modifier.fillMaxSize()) { when (ProfileTab.entries[page]) { - ProfileTab.ABOUT -> AboutTab(user) + ProfileTab.ABOUT -> AboutTab( + user = user, + contentPadding = contentInsetPadding, + ) ProfileTab.ANIME -> MediaTab( mediaCollection = animeCollection, onNavigateToMediaItem = onNavigateToMediaItem, sharedTransitionScope = sharedTransitionScope, animatedVisibilityScope = animatedVisibilityScope, + contentPadding = Paddings( + horizontal = LocalPaddings.current.large, + vertical = LocalPaddings.current.large / 2, + ) + Paddings( + start = contentInsetPadding.calculateStartPadding(LocalLayoutDirection.current), + top = contentInsetPadding.calculateTopPadding(), + end = contentInsetPadding.calculateEndPadding(LocalLayoutDirection.current), + bottom = contentInsetPadding.calculateBottomPadding() + ), ) ProfileTab.MANGA -> MediaTab( mediaCollection = mangaCollection, onNavigateToMediaItem = onNavigateToMediaItem, sharedTransitionScope = sharedTransitionScope, animatedVisibilityScope = animatedVisibilityScope, + contentPadding = Paddings( + horizontal = LocalPaddings.current.large, + vertical = LocalPaddings.current.large / 2, + ) + Paddings( + start = contentInsetPadding.calculateStartPadding(LocalLayoutDirection.current), + top = contentInsetPadding.calculateTopPadding(), + end = contentInsetPadding.calculateEndPadding(LocalLayoutDirection.current), + bottom = contentInsetPadding.calculateBottomPadding() + ), + ) + ProfileTab.FAVOURITES -> FavouritesTab( + favouriteLists = user.favourites, + contentPadding = Paddings( + horizontal = LocalPaddings.current.large, + vertical = LocalPaddings.current.large / 2, + ) + Paddings( + start = contentInsetPadding.calculateStartPadding(LocalLayoutDirection.current), + top = contentInsetPadding.calculateTopPadding(), + end = contentInsetPadding.calculateEndPadding(LocalLayoutDirection.current), + bottom = contentInsetPadding.calculateBottomPadding() + ), ) - ProfileTab.FAVOURITES -> FavouritesTab(user.favourites) else -> FallbackMessage( message = stringResource(coreR.string.coming_soon), - modifier = Modifier.align(Alignment.Center), + modifier = Modifier + .align(Alignment.Center) + .padding(contentInsetPadding), ) } } diff --git a/profile/src/main/kotlin/com/imashnake/animite/profile/tabs/About.kt b/profile/src/main/kotlin/com/imashnake/animite/profile/tabs/About.kt index e4f87184..a3bc1c43 100644 --- a/profile/src/main/kotlin/com/imashnake/animite/profile/tabs/About.kt +++ b/profile/src/main/kotlin/com/imashnake/animite/profile/tabs/About.kt @@ -6,6 +6,7 @@ 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.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth @@ -30,7 +31,6 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import com.boswelja.markdown.material3.m3TextStyles import com.imashnake.animite.api.anilist.sanitize.profile.User -import com.imashnake.animite.core.extensions.landscapeCutoutPadding import com.imashnake.animite.core.ui.LocalPaddings import com.imashnake.animite.core.ui.StatsRow import com.imashnake.animite.profile.R @@ -44,7 +44,8 @@ import kotlinx.coroutines.launch @Composable fun AboutTab( user: User, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + contentPadding: PaddingValues = PaddingValues(), ) { val scrollState = rememberScrollState() @@ -58,8 +59,8 @@ fun AboutTab( Column( modifier .verticalScroll(scrollState) - .landscapeCutoutPadding() .padding(bottom = LocalPaddings.current.large) + .padding(contentPadding) ) { Column( modifier = Modifier.padding(LocalPaddings.current.large), @@ -69,7 +70,6 @@ fun AboutTab( stats = statsLabelToValue, modifier = Modifier .fillMaxWidth() - .landscapeCutoutPadding() ) { Text( text = it.first, diff --git a/profile/src/main/kotlin/com/imashnake/animite/profile/tabs/Favourites.kt b/profile/src/main/kotlin/com/imashnake/animite/profile/tabs/Favourites.kt index 865d2cda..b3891bde 100644 --- a/profile/src/main/kotlin/com/imashnake/animite/profile/tabs/Favourites.kt +++ b/profile/src/main/kotlin/com/imashnake/animite/profile/tabs/Favourites.kt @@ -1,8 +1,8 @@ package com.imashnake.animite.profile.tabs import android.util.Log -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll @@ -28,6 +28,7 @@ import com.imashnake.animite.profile.R fun FavouritesTab( favouriteLists: List, modifier: Modifier = Modifier, + contentPadding: PaddingValues = PaddingValues(), ) { val scrollState = rememberScrollState() @@ -36,22 +37,30 @@ fun FavouritesTab( else -> Column( modifier .verticalScroll(scrollState) - .padding(vertical = LocalPaddings.current.large) - ) { UserFavouriteLists(favouriteLists) } + .padding(vertical = LocalPaddings.current.large / 2) + .padding(bottom = contentPadding.calculateBottomPadding()) + ) { + UserFavouriteLists( + lists = favouriteLists, + contentPadding = contentPadding, + ) + } } } @Composable private fun UserFavouriteLists( lists: List, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + contentPadding: PaddingValues = PaddingValues(), ) { - Column( - verticalArrangement = Arrangement.spacedBy(LocalPaddings.current.large), - modifier = modifier - ) { + Column(modifier = modifier) { lists.fastForEach { namedList -> - MediaSmallRow(namedList.name, namedList.list) { item -> + MediaSmallRow( + title = namedList.name, + mediaList = namedList.list, + contentPadding = contentPadding, + ) { item -> when(item) { is Media.Small -> { MediaCard( diff --git a/profile/src/main/kotlin/com/imashnake/animite/profile/tabs/Media.kt b/profile/src/main/kotlin/com/imashnake/animite/profile/tabs/Media.kt index 38dc7bb2..c96475c0 100644 --- a/profile/src/main/kotlin/com/imashnake/animite/profile/tabs/Media.kt +++ b/profile/src/main/kotlin/com/imashnake/animite/profile/tabs/Media.kt @@ -2,8 +2,8 @@ package com.imashnake.animite.profile.tabs import androidx.compose.animation.AnimatedVisibilityScope import androidx.compose.animation.SharedTransitionScope -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll @@ -38,6 +38,7 @@ fun MediaTab( sharedTransitionScope: SharedTransitionScope, animatedVisibilityScope: AnimatedVisibilityScope, modifier: Modifier = Modifier, + contentPadding: PaddingValues = PaddingValues(), ) { val scrollState = rememberScrollState() @@ -50,22 +51,24 @@ fun MediaTab( Media.Small.Type.MANGA -> R.string.no_manga Media.Small.Type.UNKNOWN -> R.string.no_media } - ) + ), + modifier = Modifier.padding(contentPadding) ) } else -> Column( modifier .verticalScroll(scrollState) - .padding(vertical = LocalPaddings.current.large) + .padding(vertical = LocalPaddings.current.large / 2) + .padding(bottom = contentPadding.calculateBottomPadding()) ) { - // TODO: Why is this not smart-casting? if (!mediaCollection?.namedLists.isNullOrEmpty()) { UserMediaLists( - lists = mediaCollection!!.namedLists, + lists = mediaCollection.namedLists, onNavigateToMediaItem = onNavigateToMediaItem, sharedTransitionScope = sharedTransitionScope, animatedVisibilityScope = animatedVisibilityScope, modifier = modifier, + contentPadding = contentPadding, ) } } @@ -79,13 +82,15 @@ private fun UserMediaLists( sharedTransitionScope: SharedTransitionScope, animatedVisibilityScope: AnimatedVisibilityScope, modifier: Modifier = Modifier, + contentPadding: PaddingValues = PaddingValues(), ) { - Column( - verticalArrangement = Arrangement.spacedBy(LocalPaddings.current.large), - modifier = modifier, - ) { + Column(modifier = modifier) { lists.fastForEach { namedList -> - MediaSmallRow(namedList.name, namedList.list) { item -> + MediaSmallRow( + title = namedList.name, + mediaList = namedList.list, + contentPadding = contentPadding, + ) { item -> with(sharedTransitionScope) { val media = item as Media.Small MediaCard(