Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unspecified ItemType padding #2075

Merged
merged 4 commits into from
Feb 28, 2024
Merged
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
1 change: 1 addition & 0 deletions compose-layout/api/current.api
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ package com.google.android.horologist.compose.layout {
method @com.google.android.horologist.annotations.ExperimentalHorologistApi public com.google.android.horologist.compose.layout.ScalingLazyColumnState.Factory belowTimeText(optional com.google.android.horologist.compose.layout.ScalingLazyColumnState.RotaryMode rotaryMode, optional boolean firstItemIsFullWidth, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Horizontal horizontalAlignment, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional float topPaddingDp);
method @androidx.compose.runtime.Composable public kotlin.jvm.functions.Function0<androidx.compose.foundation.layout.PaddingValues> padding(optional com.google.android.horologist.compose.layout.ScalingLazyColumnDefaults.ItemType first, optional com.google.android.horologist.compose.layout.ScalingLazyColumnDefaults.ItemType last, optional float horizontalPercent);
method @com.google.android.horologist.annotations.ExperimentalHorologistApi public com.google.android.horologist.compose.layout.ScalingLazyColumnState.Factory responsive(optional boolean firstItemIsFullWidth, optional float additionalPaddingAtBottom, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional float horizontalPaddingPercent, optional com.google.android.horologist.compose.layout.ScalingLazyColumnState.RotaryMode? rotaryMode, optional boolean hapticsEnabled, optional boolean reverseLayout, optional boolean userScrollEnabled);
method public androidx.wear.compose.foundation.lazy.ScalingParams responsiveScalingParams(float screenWidthDp);
method @com.google.android.horologist.annotations.ExperimentalHorologistApi public com.google.android.horologist.compose.layout.ScalingLazyColumnState.Factory scalingLazyColumnDefaults(optional com.google.android.horologist.compose.layout.ScalingLazyColumnState.RotaryMode rotaryMode, optional int initialCenterIndex, optional int initialCenterOffset, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Horizontal horizontalAlignment, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.wear.compose.foundation.lazy.AutoCenteringParams? autoCentering, optional int anchorType, optional boolean hapticsEnabled, optional boolean reverseLayout);
field public static final com.google.android.horologist.compose.layout.ScalingLazyColumnDefaults INSTANCE;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import androidx.compose.ui.util.lerp
import androidx.wear.compose.foundation.lazy.AutoCenteringParams
import androidx.wear.compose.foundation.lazy.ScalingLazyColumnDefaults
import androidx.wear.compose.foundation.lazy.ScalingLazyListAnchorType
import androidx.wear.compose.foundation.lazy.ScalingParams
import androidx.wear.compose.material.ChipDefaults
import com.google.android.horologist.annotations.ExperimentalHorologistApi
import com.google.android.horologist.compose.layout.ScalingLazyColumnState.RotaryMode
Expand Down Expand Up @@ -167,22 +168,6 @@ public object ScalingLazyColumnDefaults {
reverseLayout: Boolean = false,
userScrollEnabled: Boolean = true,
): ScalingLazyColumnState.Factory {
fun calculateVerticalOffsetForChip(
viewportDiameter: Float,
horizontalPaddingPercent: Float,
): Dp {
val childViewHeight: Float = ChipDefaults.Height.value
val childViewWidth: Float = viewportDiameter * (1.0f - (2f * horizontalPaddingPercent))
val radius = viewportDiameter / 2f
return (
radius -
sqrt(
(radius - childViewHeight + childViewWidth * 0.5f) * (radius - childViewWidth * 0.5f),
) -
childViewHeight * 0.5f
).dp
}

return object : ScalingLazyColumnState.Factory {
@Composable
override fun create(): ScalingLazyColumnState {
Expand Down Expand Up @@ -214,22 +199,7 @@ public object ScalingLazyColumnDefaults {
bottom = bottomPaddingDp,
)

val sizeRatio =
((screenWidthDp - 192) / (233 - 192).toFloat()).coerceIn(0f, 1.5f)
val presetRatio = 0f

val minElementHeight = lerp(0.2f, 0.157f, sizeRatio)
val maxElementHeight =
lerp(0.6f, 0.472f, sizeRatio).coerceAtLeast(minElementHeight)
val minTransitionArea = lerp(0.35f, lerp(0.35f, 0.393f, presetRatio), sizeRatio)
val maxTransitionArea = lerp(0.55f, lerp(0.55f, 0.593f, presetRatio), sizeRatio)

val scalingParams = ScalingLazyColumnDefaults.scalingParams(
minElementHeight = minElementHeight,
maxElementHeight = maxElementHeight,
minTransitionArea = minTransitionArea,
maxTransitionArea = maxTransitionArea,
)
val scalingParams = responsiveScalingParams(screenWidthDp)

val screenHeightPx =
with(density) { screenHeightDp.dp.roundToPx() }
Expand Down Expand Up @@ -258,16 +228,60 @@ public object ScalingLazyColumnDefaults {
}
}

internal fun calculateVerticalOffsetForChip(
viewportDiameter: Float,
horizontalPaddingPercent: Float,
): Dp {
val childViewHeight: Float = ChipDefaults.Height.value
val childViewWidth: Float = viewportDiameter * (1.0f - (2f * horizontalPaddingPercent))
val radius = viewportDiameter / 2f
return (
radius -
sqrt(
(radius - childViewHeight + childViewWidth * 0.5f) * (radius - childViewWidth * 0.5f),
) -
childViewHeight * 0.5f
).dp
}

fun responsiveScalingParams(screenWidthDp: Float): ScalingParams {
val sizeRatio =
((screenWidthDp - 192) / (233 - 192).toFloat()).coerceIn(0f, 1.5f)
val presetRatio = 0f

val minElementHeight = lerp(0.2f, 0.157f, sizeRatio)
val maxElementHeight =
lerp(0.6f, 0.472f, sizeRatio).coerceAtLeast(minElementHeight)
val minTransitionArea = lerp(0.35f, lerp(0.35f, 0.393f, presetRatio), sizeRatio)
val maxTransitionArea = lerp(0.55f, lerp(0.55f, 0.593f, presetRatio), sizeRatio)

val scalingParams = ScalingLazyColumnDefaults.scalingParams(
minElementHeight = minElementHeight,
maxElementHeight = maxElementHeight,
minTransitionArea = minTransitionArea,
maxTransitionArea = maxTransitionArea,
)
return scalingParams
}

internal val Padding12Pct = 0.1248f
internal val Padding16Pct = 0.1664f
internal val Padding20Pct = 0.2083f
internal val Padding21Pct = 0.2188f
internal val Padding31Pct = 0.3646f

enum class ItemType(val topPaddingDp: Float, val bottomPaddingDp: Float, val paddingCorrection: Dp = 0.dp) {
enum class ItemType(
val topPaddingDp: Float,
val bottomPaddingDp: Float,
val paddingCorrection: Dp = 0.dp,
) {
Card(Padding21Pct, Padding31Pct),
Chip(Padding21Pct, Padding31Pct),
CompactChip(topPaddingDp = Padding12Pct, bottomPaddingDp = Padding20Pct, paddingCorrection = (-8).dp),
CompactChip(
topPaddingDp = Padding12Pct,
bottomPaddingDp = Padding20Pct,
paddingCorrection = (-8).dp,
),
Icon(Padding12Pct, Padding21Pct),
MultiButton(Padding21Pct, Padding20Pct),
SingleButton(Padding12Pct, Padding20Pct),
Expand All @@ -281,12 +295,40 @@ public object ScalingLazyColumnDefaults {
last: ItemType = ItemType.Unspecified,
horizontalPercent: Float = 0.052f,
): @Composable () -> PaddingValues {
val configuration = LocalConfiguration.current
val screenWidthDp = configuration.screenWidthDp.toFloat()
val screenHeightDp = configuration.screenHeightDp.toFloat()

return {
val height = LocalConfiguration.current.screenWidthDp.dp
val horizontalPadding = LocalConfiguration.current.screenWidthDp.dp * horizontalPercent
val height = screenHeightDp.dp
val horizontalPadding = screenWidthDp.dp * horizontalPercent

val topPadding = if (first != ItemType.Unspecified) {
first.topPaddingDp * height + first.paddingCorrection
} else {
if (configuration.isScreenRound) {
calculateVerticalOffsetForChip(screenWidthDp, horizontalPercent)
} else {
32.dp
}
}

val bottomPadding = if (last != ItemType.Unspecified) {
last.bottomPaddingDp * height + first.paddingCorrection
} else {
if (configuration.isScreenRound) {
calculateVerticalOffsetForChip(
screenWidthDp,
horizontalPercent,
) + 10.dp
} else {
0.dp
}
}

PaddingValues(
top = first.topPaddingDp * height + first.paddingCorrection,
bottom = last.bottomPaddingDp * height + first.paddingCorrection,
top = topPadding,
bottom = bottomPadding,
start = horizontalPadding,
end = horizontalPadding,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.lerp
import androidx.wear.compose.foundation.ExperimentalWearFoundationApi
import androidx.wear.compose.foundation.lazy.AutoCenteringParams
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
Expand All @@ -44,6 +43,7 @@ import androidx.wear.compose.foundation.lazy.ScalingLazyListState
import androidx.wear.compose.foundation.lazy.ScalingParams
import androidx.wear.compose.foundation.rememberActiveFocusRequester
import com.google.android.horologist.annotations.ExperimentalHorologistApi
import com.google.android.horologist.compose.layout.ScalingLazyColumnDefaults.responsiveScalingParams
import com.google.android.horologist.compose.layout.ScalingLazyColumnState.RotaryMode
import com.google.android.horologist.compose.rotaryinput.rememberDisabledHaptic
import com.google.android.horologist.compose.rotaryinput.rememberRotaryHapticHandler
Expand Down Expand Up @@ -159,22 +159,7 @@ public fun rememberResponsiveColumnState(
val screenWidthDp = configuration.screenWidthDp.toFloat()
val screenHeightDp = configuration.screenHeightDp.toFloat()

val sizeRatio =
((screenWidthDp - 192) / (233 - 192).toFloat()).coerceIn(0f, 1.5f)
val presetRatio = 0f

val minElementHeight = lerp(0.2f, 0.157f, sizeRatio)
val maxElementHeight =
lerp(0.6f, 0.472f, sizeRatio).coerceAtLeast(minElementHeight)
val minTransitionArea = lerp(0.35f, lerp(0.35f, 0.393f, presetRatio), sizeRatio)
val maxTransitionArea = lerp(0.55f, lerp(0.55f, 0.593f, presetRatio), sizeRatio)

val scalingParams = androidx.wear.compose.foundation.lazy.ScalingLazyColumnDefaults.scalingParams(
minElementHeight = minElementHeight,
maxElementHeight = maxElementHeight,
minTransitionArea = minTransitionArea,
maxTransitionArea = maxTransitionArea,
)
val scalingParams = responsiveScalingParams(screenWidthDp)

val contentPaddingCalculated = contentPadding()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,25 @@ fun BottomOtherCards() {
}
}

@Composable
fun BottomUnspecified() {
SampleMenu(
columnState = rememberResponsiveColumnState(
contentPadding = padding(
last = ItemType.Unspecified,
),
),
borders = null,
) {
item {
MessagesCard()
}
item {
BofACard()
}
}
}

// @WearCustomPreviews
@Composable
fun BottomOtherText() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,17 @@ fun SampleOtherChips() {
)
}

@Composable
fun SampleUnspecified() {
SampleMenu(
columnState = rememberResponsiveColumnState(
contentPadding = ScalingLazyColumnDefaults.padding(
first = ItemType.Unspecified,
),
),
)
}

// @WearCustomPreviews
@Composable
fun SampleOtherCards() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@ class ScalingLazyColumnExamplesTest(device: Device) : ScreenSizeTest(
}
}

@Test
fun titleUnspecified() {
runTest {
SampleUnspecified()
}
}

@Test
fun titleOtherCards() {
runTest {
Expand Down Expand Up @@ -144,6 +151,15 @@ class ScalingLazyColumnExamplesTest(device: Device) : ScreenSizeTest(
}
}

@Test
fun bottomUnspecified() {
runTest(preScreenshotInteractions = {
scrollToBottom(1)
}) {
BottomUnspecified()
}
}

@Test
fun bottomOtherText() {
runTest(preScreenshotInteractions = {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading