From b619f04e7c80e8b1ed1fab62e15213008a731eb3 Mon Sep 17 00:00:00 2001 From: Ryan Cheung Date: Wed, 2 Sep 2026 18:16:53 -0400 Subject: [PATCH 1/7] fix: update gitignore and add a temp reroute for user not found error when logging in --- .gitignore | 5 +++-- .../android/viewmodel/onboarding/LandingViewModel.kt | 7 +++++++ gradlew | 0 3 files changed, 10 insertions(+), 2 deletions(-) mode change 100644 => 100755 gradlew diff --git a/.gitignore b/.gitignore index 62c68b19..56b7ebd7 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ local.properties # Log/OS Files *.log +.DS_Store # Android Studio generated files and folders captures/ @@ -28,11 +29,11 @@ render.experimental.xml *.keystore # Google Services (e.g. APIs or Firebase) -app/google-services.json +google-services.json # Android Profiling *.hprof # Secrets secrets.properties -app/src/main/assets/resell-service.json +resell-service.json diff --git a/app/src/main/java/com/cornellappdev/resell/android/viewmodel/onboarding/LandingViewModel.kt b/app/src/main/java/com/cornellappdev/resell/android/viewmodel/onboarding/LandingViewModel.kt index 4fb09394..811b0080 100644 --- a/app/src/main/java/com/cornellappdev/resell/android/viewmodel/onboarding/LandingViewModel.kt +++ b/app/src/main/java/com/cornellappdev/resell/android/viewmodel/onboarding/LandingViewModel.kt @@ -28,6 +28,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import retrofit2.HttpException import javax.inject.Inject @HiltViewModel @@ -171,6 +172,12 @@ class LandingViewModel @Inject constructor( rootNavigationRepository.navigate(ResellRootRoute.MAIN) } } catch (e: Exception) { + if (e is HttpException && e.code() == 403) { + Log.d("LandingViewModel", "User not found on backend; routing to onboarding.") + rootNavigationRepository.navigate(ResellRootRoute.ONBOARDING) + return@launch + } + Log.e("LandingViewModel", "Error getting user: ", e) onSignInFailed(showSheet = false) rootConfirmationRepository.showError( diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 From 17c9fc57e3011862244093dc7feac585e5aa131a Mon Sep 17 00:00:00 2001 From: Ryan Cheung Date: Thu, 3 Sep 2026 23:00:43 -0400 Subject: [PATCH 2/7] fix: move bookmark FAB to bottom right and reduce padding from the sheet --- .../android/ui/screens/pdp/PostDetailPage.kt | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt b/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt index 4e6a3c72..737a1040 100644 --- a/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt +++ b/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt @@ -19,7 +19,9 @@ import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.layout.width import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.BottomSheetScaffold import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon @@ -144,7 +146,8 @@ private fun Content( val screenHeight = LocalConfiguration.current.screenHeightDp.dp // TODO the plus at the end seems wrong. Test on other devices. - val peekHeight = screenHeight - imageHeight + 96.dp +// val peekHeight = screenHeight - imageHeight + 96.dp + val peekHeight = screenHeight - imageHeight Box( modifier = Modifier.fillMaxWidth() @@ -225,7 +228,7 @@ private fun Content( selected = bookmarked, onClick = onBookmarkClick, modifier = Modifier - .align(Alignment.BottomStart) + .align(Alignment.BottomEnd) .defaultHorizontalPadding() .padding(bottom = sheetHeightFromBottom) ) @@ -315,11 +318,14 @@ private fun BottomSheetContent( // Calculate maximum height for the sheet content based on padding from top val maxSheetHeight = screenHeight - paddingTop +// val scrollState = rememberScrollState() + Column( modifier = Modifier .fillMaxWidth() .background(Color.White) - .height(maxSheetHeight) + .heightIn(max = maxSheetHeight) +// .verticalScroll(scrollState) ) { Row( modifier = Modifier @@ -335,8 +341,12 @@ private fun BottomSheetContent( val distanceFromBottomPx = screenHeightPx - (textPosition + textHeight) val textDistanceFromBottom = with(density) { distanceFromBottomPx.toDp() } + //Bookmark FAB size = 72.dp, plus 24 dp for bottom padding + val bookmarkSize = 72.dp + val bookmarkPadding = bookmarkSize + 24.dp + // Tell the parent that the height has changed. - onHeightChanged(textDistanceFromBottom + 170.dp) + onHeightChanged(textDistanceFromBottom + bookmarkPadding) }, verticalAlignment = Alignment.CenterVertically ) { From cc852aa83fc600e7ce1902920c7aca54cee202ad Mon Sep 17 00:00:00 2001 From: Ryan Cheung Date: Fri, 4 Sep 2026 00:05:03 -0400 Subject: [PATCH 3/7] fix: use top of bottomsheet as anchor for bookmark FAB and picture selection dot. Allow bottomsheet content to be scrollable for longer descriptions. Bottomsheet content now uses a fixed height that relates to the content size instead of a size based on how much possible space it could use. --- .../android/ui/screens/pdp/PostDetailPage.kt | 123 +++++++++--------- 1 file changed, 64 insertions(+), 59 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt b/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt index 737a1040..f5671aeb 100644 --- a/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt +++ b/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt @@ -7,11 +7,15 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -25,13 +29,15 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material3.BottomSheetScaffold import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon +import androidx.compose.material3.SheetValue import androidx.compose.material3.Text +import androidx.compose.material3.rememberBottomSheetScaffoldState +import androidx.compose.material3.rememberStandardBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.BlurredEdgeTreatment.Companion.Rectangle @@ -41,8 +47,6 @@ import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.layout.onGloballyPositioned -import androidx.compose.ui.layout.positionInRoot import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.painterResource @@ -50,6 +54,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.max import androidx.hilt.navigation.compose.hiltViewModel import coil.compose.AsyncImage import com.cornellappdev.resell.android.R @@ -73,21 +78,9 @@ fun PostDetailPage( ) { val uiState = postDetailViewModel.collectUiStateValue() - // Image will take up at most this proportion of the screen + // When the sheet is peeked (collapsed), the image may grow up to this fraction of the screen. val imageProp = .75f val maxImageHeight = LocalConfiguration.current.screenHeightDp.dp * imageProp - val minAspectRatio = uiState.minAspectRatio - val screenWidth = LocalConfiguration.current.screenWidthDp.dp - - // Preferred height of the tallest image, given the aspect ratio - val aspectRatioPreferredHeight = screenWidth / minAspectRatio - - // Cap at the max image height. - val imageHeight = if (aspectRatioPreferredHeight > maxImageHeight) { - maxImageHeight - } else { - aspectRatioPreferredHeight - } LaunchedEffect(uiState.hideSheetEvent) { uiState.hideSheetEvent?.consumeSuspend { @@ -100,7 +93,7 @@ fun PostDetailPage( onContactClick = postDetailViewModel::onContactClick, onEllipseClick = postDetailViewModel::onEllipseClick, images = uiState.images, - imageHeight = imageHeight, + maxImageHeight = maxImageHeight, userPfp = uiState.profileImageUrl, username = uiState.username, title = uiState.title, @@ -122,7 +115,7 @@ fun PostDetailPage( @Preview @Composable private fun Content( - imageHeight: Dp = 500.dp, + maxImageHeight: Dp = 500.dp, images: List = emptyList(), similarImageUrls: ResellApiResponse> = ResellApiResponse.Pending, onContactClick: () -> Unit = {}, @@ -139,20 +132,45 @@ private fun Content( onUserClick: () -> Unit = {}, showContact: Boolean = false, ) { - var sheetHeightFromBottom by remember { mutableStateOf(0.dp) } val pagerState = rememberPagerState(pageCount = { images.size }) - - // Derive peekHeight as screen height minus image height: + val density = LocalDensity.current val screenHeight = LocalConfiguration.current.screenHeightDp.dp - // TODO the plus at the end seems wrong. Test on other devices. -// val peekHeight = screenHeight - imageHeight + 96.dp - val peekHeight = screenHeight - imageHeight + // Sheet starts collapsed so only a strip of details is visible; image fills the rest. + val peekHeight = max(screenHeight - maxImageHeight, 200.dp) + val peekedImageHeight = screenHeight - peekHeight + + val scaffoldState = rememberBottomSheetScaffoldState( + bottomSheetState = rememberStandardBottomSheetState( + initialValue = SheetValue.PartiallyExpanded, + skipHiddenState = true, + ) + ) + + // requireOffset() is the Y of the sheet top. Drive image height and overlay + // positions from that so they stay glued to the sheet while dragging. + val sheetTopOffsetPx by remember { + derivedStateOf { + runCatching { scaffoldState.bottomSheetState.requireOffset() }.getOrDefault(0f) + } + } + val liveImageHeight = if (sheetTopOffsetPx == 0f) { + peekedImageHeight + } else { + with(density) { sheetTopOffsetPx.toDp() } + } + // Bottom padding so overlays sit just above the sheet top. + val overlayBottomPadding = if (sheetTopOffsetPx == 0f) { + peekHeight + 24.dp + } else { + with(density) { (screenHeight.toPx() - sheetTopOffsetPx).toDp() } + 24.dp + } Box( modifier = Modifier.fillMaxWidth() ) { BottomSheetScaffold( + scaffoldState = scaffoldState, sheetContent = { BottomSheetContent( profilePictureUrl = userPfp, @@ -160,12 +178,10 @@ private fun Content( title = title, price = price, description = description, - onHeightChanged = { - sheetHeightFromBottom = it - }, onSimilarClick = onSimilarClick, similarImageUrls = similarImageUrls, - onUserClick = onUserClick + onUserClick = onUserClick, + showContact = showContact, ) }, sheetPeekHeight = peekHeight, @@ -184,7 +200,7 @@ private fun Content( ) { Column(modifier = Modifier.fillMaxHeight()) { PdpImageBlurredBackground( - imageHeight = imageHeight, + imageHeight = liveImageHeight, bitmap = images[it] ) @@ -220,7 +236,7 @@ private fun Content( WhichPage( pagerState = pagerState, modifier = Modifier - .padding(bottom = sheetHeightFromBottom) + .padding(bottom = overlayBottomPadding) .align(Alignment.BottomCenter) ) @@ -230,7 +246,7 @@ private fun Content( modifier = Modifier .align(Alignment.BottomEnd) .defaultHorizontalPadding() - .padding(bottom = sheetHeightFromBottom) + .padding(bottom = overlayBottomPadding) ) } } @@ -260,7 +276,7 @@ private fun PdpImageBlurredBackground( modifier = Modifier .fillMaxWidth() .height(imageHeight), - contentScale = ContentScale.FillWidth + contentScale = ContentScale.Crop ) } } @@ -306,48 +322,35 @@ private fun BottomSheetContent( username: String, paddingTop: Dp = 116.dp, similarImageUrls: ResellApiResponse>, - onHeightChanged: (Dp) -> Unit, onSimilarClick: (Int) -> Unit, onUserClick: () -> Unit, + showContact: Boolean = false, ) { - - // Get screen height val screenHeight = LocalConfiguration.current.screenHeightDp.dp - val density = LocalDensity.current - - // Calculate maximum height for the sheet content based on padding from top val maxSheetHeight = screenHeight - paddingTop -// val scrollState = rememberScrollState() + // Clear the floating Contact Seller button: nav bars + 46.dp offset for below button + // + ~52.dp button itself + gap between button and similar items. + val navBottom = WindowInsets.navigationBars + .asPaddingValues() + .calculateBottomPadding() + val bottomClearance = if (showContact) { + navBottom + 46.dp + 52.dp + 24.dp + } else { + navBottom + 16.dp + } Column( modifier = Modifier .fillMaxWidth() .background(Color.White) .heightIn(max = maxSheetHeight) -// .verticalScroll(scrollState) + .verticalScroll(rememberScrollState()) ) { Row( modifier = Modifier .fillMaxWidth() - .defaultHorizontalPadding() - .onGloballyPositioned { layoutCoordinates -> - val textPosition = layoutCoordinates.positionInRoot().y - val textHeight = layoutCoordinates.size.height - - val screenHeightPx = with(density) { screenHeight.toPx() } - - // Calculate distance from bottom in px and convert to dp - val distanceFromBottomPx = screenHeightPx - (textPosition + textHeight) - val textDistanceFromBottom = with(density) { distanceFromBottomPx.toDp() } - - //Bookmark FAB size = 72.dp, plus 24 dp for bottom padding - val bookmarkSize = 72.dp - val bookmarkPadding = bookmarkSize + 24.dp - - // Tell the parent that the height has changed. - onHeightChanged(textDistanceFromBottom + bookmarkPadding) - }, + .defaultHorizontalPadding(), verticalAlignment = Alignment.CenterVertically ) { Text( @@ -417,6 +420,8 @@ private fun BottomSheetContent( ) } } + + Spacer(Modifier.height(bottomClearance)) } } From 504b505da4be99a079876727e161dbd8ca061e7c Mon Sep 17 00:00:00 2001 From: Ryan Cheung Date: Wed, 9 Sep 2026 01:03:14 -0400 Subject: [PATCH 4/7] fix: address coderabbit issue where imagepeekheight could reach negative values in rare case --- .../resell/android/ui/screens/pdp/PostDetailPage.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt b/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt index f5671aeb..e41d826e 100644 --- a/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt +++ b/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt @@ -138,7 +138,7 @@ private fun Content( // Sheet starts collapsed so only a strip of details is visible; image fills the rest. val peekHeight = max(screenHeight - maxImageHeight, 200.dp) - val peekedImageHeight = screenHeight - peekHeight + val peekedImageHeight = max(screenHeight - peekHeight, 0.dp) val scaffoldState = rememberBottomSheetScaffoldState( bottomSheetState = rememberStandardBottomSheetState( From d93674aa4cdaa9f720a3125afce3c11f08b3dd45 Mon Sep 17 00:00:00 2001 From: Ryan Cheung Date: Sat, 19 Sep 2026 21:22:51 -0400 Subject: [PATCH 5/7] fix: use ResellPreview wrapper around PostDetailPage content composable to show Preview without error from missing value for shimmer (provided by ResellPreview). --- .../android/ui/screens/pdp/PostDetailPage.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt b/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt index e41d826e..c83b274b 100644 --- a/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt +++ b/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt @@ -65,6 +65,7 @@ import com.cornellappdev.resell.android.ui.components.main.ProfilePictureView import com.cornellappdev.resell.android.ui.components.newpost.WhichPage import com.cornellappdev.resell.android.ui.components.pdp.BookmarkFAB import com.cornellappdev.resell.android.ui.theme.IconInactive +import com.cornellappdev.resell.android.ui.theme.ResellPreview import com.cornellappdev.resell.android.ui.theme.Secondary import com.cornellappdev.resell.android.ui.theme.Style import com.cornellappdev.resell.android.util.clickableNoIndication @@ -114,6 +115,19 @@ fun PostDetailPage( @OptIn(ExperimentalMaterial3Api::class) @Preview @Composable +private fun PostDetailPagePreview() = ResellPreview { + Content( + title = "Vintage lamp", + price = "$45", + description = "Barely used. Pickup on North Campus.", + username = "ava.shop", + showContact = true, + similarImageUrls = ResellApiResponse.Success(emptyList()), + ) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable private fun Content( maxImageHeight: Dp = 500.dp, images: List = emptyList(), From 9cf7b9ad3cd69ad239173f5ff161acdf40171136 Mon Sep 17 00:00:00 2001 From: Ryan Cheung Date: Sat, 19 Sep 2026 21:37:46 -0400 Subject: [PATCH 6/7] fix: image is no longer dynamically sized. Background of the sheet in its initial start state matches the sheet background, so there is no visual disparity aat the rounded corners. --- .../android/ui/screens/pdp/PostDetailPage.kt | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt b/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt index c83b274b..e8cafc11 100644 --- a/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt +++ b/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt @@ -10,7 +10,6 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.aspectRatio -import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -149,10 +148,12 @@ private fun Content( val pagerState = rememberPagerState(pageCount = { images.size }) val density = LocalDensity.current val screenHeight = LocalConfiguration.current.screenHeightDp.dp + val sheetBackground = Color.White - // Sheet starts collapsed so only a strip of details is visible; image fills the rest. + // Sheet starts collapsed so only a strip of details is visible; image fills the rest + // and stays that size while the sheet slides over it. val peekHeight = max(screenHeight - maxImageHeight, 200.dp) - val peekedImageHeight = max(screenHeight - peekHeight, 0.dp) + val imageHeight = max(screenHeight - peekHeight, 0.dp) val scaffoldState = rememberBottomSheetScaffoldState( bottomSheetState = rememberStandardBottomSheetState( @@ -161,19 +162,13 @@ private fun Content( ) ) - // requireOffset() is the Y of the sheet top. Drive image height and overlay - // positions from that so they stay glued to the sheet while dragging. + // requireOffset() is the Y of the sheet top. Drive overlay positions from that so + // bookmark / pager dots stay glued to the sheet while dragging. val sheetTopOffsetPx by remember { derivedStateOf { runCatching { scaffoldState.bottomSheetState.requireOffset() }.getOrDefault(0f) } } - val liveImageHeight = if (sheetTopOffsetPx == 0f) { - peekedImageHeight - } else { - with(density) { sheetTopOffsetPx.toDp() } - } - // Bottom padding so overlays sit just above the sheet top. val overlayBottomPadding = if (sheetTopOffsetPx == 0f) { peekHeight + 24.dp } else { @@ -199,27 +194,33 @@ private fun Content( ) }, sheetPeekHeight = peekHeight, - sheetContainerColor = Color.White, + sheetContainerColor = sheetBackground, sheetShadowElevation = 12.dp, - containerColor = Color.White, + containerColor = sheetBackground, modifier = Modifier .fillMaxSize() - .background(Color.White) + .background(sheetBackground) ) { - HorizontalPager( - state = pagerState, - modifier = Modifier - .fillMaxSize() - .background(IconInactive), - ) { - Column(modifier = Modifier.fillMaxHeight()) { + Column(modifier = Modifier.fillMaxSize()) { + HorizontalPager( + state = pagerState, + modifier = Modifier + .fillMaxWidth() + .height(imageHeight) + .background(IconInactive), + ) { PdpImageBlurredBackground( - imageHeight = liveImageHeight, + imageHeight = imageHeight, bitmap = images[it] ) - - Spacer(modifier = Modifier.weight(1f)) } + + Spacer( + modifier = Modifier + .weight(1f) + .fillMaxWidth() + .background(sheetBackground) + ) } } From 271639c972c61c38ce09843d265f144a898f31c8 Mon Sep 17 00:00:00 2001 From: Ryan Cheung Date: Sat, 19 Sep 2026 21:54:01 -0400 Subject: [PATCH 7/7] fix: use correct padding values, and extract hard-coded dp values into private vals at top of file. --- .../android/ui/screens/pdp/PostDetailPage.kt | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt b/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt index e8cafc11..4b8ca6cc 100644 --- a/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt +++ b/app/src/main/java/com/cornellappdev/resell/android/ui/screens/pdp/PostDetailPage.kt @@ -71,6 +71,13 @@ import com.cornellappdev.resell.android.util.clickableNoIndication import com.cornellappdev.resell.android.util.defaultHorizontalPadding import com.cornellappdev.resell.android.viewmodel.pdp.PostDetailViewModel +private val MinSheetPeekHeight = 200.dp +private val OverlayAboveSheetGap = 24.dp +private val ContactSellerTopPadding = 24.dp +private val ContactSellerBottomPadding = 45.dp +// 14.dp vertical padding + 24.dp (18.sp text with font padding) + 14.dp = 52.dp +private val ContactSellerButtonHeight = 52.dp + @OptIn(ExperimentalMaterial3Api::class) @Composable fun PostDetailPage( @@ -152,7 +159,7 @@ private fun Content( // Sheet starts collapsed so only a strip of details is visible; image fills the rest // and stays that size while the sheet slides over it. - val peekHeight = max(screenHeight - maxImageHeight, 200.dp) + val peekHeight = max(screenHeight - maxImageHeight, MinSheetPeekHeight) val imageHeight = max(screenHeight - peekHeight, 0.dp) val scaffoldState = rememberBottomSheetScaffoldState( @@ -170,9 +177,9 @@ private fun Content( } } val overlayBottomPadding = if (sheetTopOffsetPx == 0f) { - peekHeight + 24.dp + peekHeight + OverlayAboveSheetGap } else { - with(density) { (screenHeight.toPx() - sheetTopOffsetPx).toDp() } + 24.dp + with(density) { (screenHeight.toPx() - sheetTopOffsetPx).toDp() } + OverlayAboveSheetGap } Box( @@ -242,7 +249,7 @@ private fun Content( onClick = onContactClick, modifier = Modifier .align(Alignment.BottomCenter) - .padding(bottom = 46.dp) + .padding(bottom = ContactSellerBottomPadding) .navigationBarsPadding(), state = contactButtonState ) @@ -344,13 +351,13 @@ private fun BottomSheetContent( val screenHeight = LocalConfiguration.current.screenHeightDp.dp val maxSheetHeight = screenHeight - paddingTop - // Clear the floating Contact Seller button: nav bars + 46.dp offset for below button + // Clear the floating Contact Seller button: nav bars + ContactSellerBottomPadding // + ~52.dp button itself + gap between button and similar items. val navBottom = WindowInsets.navigationBars .asPaddingValues() .calculateBottomPadding() val bottomClearance = if (showContact) { - navBottom + 46.dp + 52.dp + 24.dp + navBottom + ContactSellerBottomPadding + ContactSellerButtonHeight + ContactSellerTopPadding } else { navBottom + 16.dp }