Skip to content
This repository has been archived by the owner on Aug 2, 2024. It is now read-only.

Fix scroll with image visibility. #963

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,25 @@ import androidx.annotation.RawRes
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot
import androidx.compose.ui.test.performTouchInput
import androidx.compose.ui.test.swipeUp
import androidx.core.net.toUri
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.samples.apps.sunflower.compose.plantdetail.PlantDetails
import com.google.samples.apps.sunflower.compose.plantdetail.PlantDetailsCallbacks
import com.google.samples.apps.sunflower.data.Plant
import com.google.samples.apps.sunflower.test.R
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

/**
* Instrumented test for [PlantDetails]
*/
@RunWith(AndroidJUnit4::class)
class PlantDetailComposeTest {

Expand Down Expand Up @@ -67,6 +73,23 @@ class PlantDetailComposeTest {
composeTestRule.onNodeWithContentDescription("Gallery Icon").assertIsDisplayed()
}

@Test
fun plantDetails_scrollDown_visibleToolbar() {
startPlantDetails(isPlanted = false)
val headerAction = composeTestRule.onNodeWithTag("Header Action")
val detailToolbar = composeTestRule.onNodeWithTag("Detail Toolbar")

headerAction.assertIsDisplayed()
detailToolbar.assertIsNotDisplayed()

composeTestRule.onRoot().performTouchInput {
swipeUp()
}

headerAction.assertIsNotDisplayed()
detailToolbar.assertIsDisplayed()
}

private fun startPlantDetails(isPlanted: Boolean, hasUnsplashKey: Boolean = false) {
composeTestRule.setContent {
PlantDetails(
Expand Down Expand Up @@ -98,4 +121,4 @@ internal fun plantForTesting(): Plant {
private fun rawUri(@RawRes id: Int): Uri {
return "${ContentResolver.SCHEME_ANDROID_RESOURCE}://${LocalContext.current.packageName}/$id"
.toUri()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package com.google.samples.apps.sunflower.compose.plantdetail
import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.foundation.ScrollState
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp

// Value obtained empirically so that the header buttons don't surpass the header container
Expand All @@ -29,15 +30,15 @@ private val HeaderTransitionOffset = 190.dp
*/
data class PlantDetailsScroller(
val scrollState: ScrollState,
val namePosition: Float
val detailAppbarHeight: Dp,
) {
val toolbarTransitionState = MutableTransitionState(ToolbarState.HIDDEN)

fun getToolbarState(density: Density): ToolbarState {
// When the namePosition is placed correctly on the screen (position > 1f) and it's
// position is close to the header, then show the toolbar.
return if (namePosition > 1f &&
scrollState.value > (namePosition - getTransitionOffset(density))
return if (scrollState.value > 0 &&
scrollState.value > getTransitionOffset(density, detailAppbarHeight)
) {
toolbarTransitionState.targetState = ToolbarState.SHOWN
ToolbarState.SHOWN
Expand All @@ -47,9 +48,10 @@ data class PlantDetailsScroller(
}
}

private fun getTransitionOffset(density: Density): Float = with(density) {
HeaderTransitionOffset.toPx()
}
private fun getTransitionOffset(density: Density, detailAppbarHeight: Dp): Float =
with(density) {
(detailAppbarHeight - HeaderTransitionOffset).toPx()
}
}

// Toolbar state related classes and functions to achieve the CollapsingToolbarLayout animation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.positionInWindow
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
Expand Down Expand Up @@ -153,10 +152,11 @@ fun PlantDetails(
callbacks: PlantDetailsCallbacks,
modifier: Modifier = Modifier
) {
val detailAppbarHeight = Dimens.PlantDetailAppBarHeight
// PlantDetails owns the scrollerPosition to simulate CollapsingToolbarLayout's behavior
val scrollState = rememberScrollState()
var plantScroller by remember {
mutableStateOf(PlantDetailsScroller(scrollState, Float.MIN_VALUE))
val plantScroller by remember {
mutableStateOf(PlantDetailsScroller(scrollState, detailAppbarHeight))
}
val transitionState =
remember(plantScroller) { plantScroller.toolbarTransitionState }
Expand All @@ -179,14 +179,6 @@ fun PlantDetails(
PlantDetailsContent(
scrollState = scrollState,
toolbarState = toolbarState,
onNamePosition = { newNamePosition ->
// Comparing to Float.MIN_VALUE as we are just interested on the original
// position of name on the screen
if (plantScroller.namePosition == Float.MIN_VALUE) {
plantScroller =
plantScroller.copy(namePosition = newNamePosition)
}
},
plant = plant,
isPlanted = isPlanted,
hasValidUnsplashKey = hasValidUnsplashKey,
Expand Down Expand Up @@ -217,7 +209,6 @@ private fun PlantDetailsContent(
isPlanted: Boolean,
hasValidUnsplashKey: Boolean,
imageHeight: Dp,
onNamePosition: (Float) -> Unit,
onFabClick: () -> Unit,
onGalleryClick: () -> Unit,
contentAlpha: () -> Float,
Expand Down Expand Up @@ -255,7 +246,6 @@ private fun PlantDetailsContent(
wateringInterval = plant.wateringInterval,
description = plant.description,
hasValidUnsplashKey = hasValidUnsplashKey,
onNamePosition = { onNamePosition(it) },
toolbarState = toolbarState,
onGalleryClick = onGalleryClick,
modifier = Modifier.constrainAs(info) {
Expand Down Expand Up @@ -359,13 +349,17 @@ private fun PlantToolbar(
plantName = plantName,
onBackClick = callbacks.onBackClick,
onShareClick = onShareClick,
modifier = Modifier.alpha(toolbarAlpha())
modifier = Modifier
.alpha(toolbarAlpha())
.testTag("Detail Toolbar")
)
} else {
PlantHeaderActions(
onBackClick = callbacks.onBackClick,
onShareClick = onShareClick,
modifier = Modifier.alpha(contentAlpha())
modifier = Modifier
.alpha(contentAlpha())
.testTag("Header Action")
)
}
}
Expand Down Expand Up @@ -483,7 +477,6 @@ private fun PlantInformation(
wateringInterval: Int,
description: String,
hasValidUnsplashKey: Boolean,
onNamePosition: (Float) -> Unit,
toolbarState: ToolbarState,
onGalleryClick: () -> Unit,
modifier: Modifier = Modifier
Expand All @@ -499,7 +492,6 @@ private fun PlantInformation(
bottom = Dimens.PaddingNormal
)
.align(Alignment.CenterHorizontally)
.onGloballyPositioned { onNamePosition(it.positionInWindow().y) }
.visible { toolbarState == ToolbarState.HIDDEN }
)
Box(
Expand Down