1 /* 2 * Copyright 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * https://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 @file:Suppress("ObjectLiteralToLambda") 18 19 package com.google.android.horologist.compose.layout 20 21 import androidx.compose.foundation.layout.Arrangement 22 import androidx.compose.foundation.layout.PaddingValues 23 import androidx.compose.runtime.Composable 24 import androidx.compose.runtime.remember 25 import androidx.compose.ui.Alignment 26 import androidx.compose.ui.platform.LocalConfiguration 27 import androidx.compose.ui.platform.LocalDensity 28 import androidx.compose.ui.unit.Dp 29 import androidx.compose.ui.unit.dp 30 import androidx.wear.compose.foundation.lazy.AutoCenteringParams 31 import androidx.wear.compose.foundation.lazy.ScalingLazyListAnchorType 32 import com.google.android.horologist.annotations.ExperimentalHorologistApi 33 import com.google.android.horologist.compose.layout.ScalingLazyColumnState.RotaryMode 34 35 /** 36 * Default layouts for ScalingLazyColumnState, based on UX guidance. 37 */ 38 public object ScalingLazyColumnDefaults { 39 /** 40 * Layout the first item, directly under the time text. 41 * This is positioned from the top of the screen instead of the 42 * center. 43 */ 44 @ExperimentalHorologistApi belowTimeTextnull45 public fun belowTimeText( 46 rotaryMode: RotaryMode = RotaryMode.Scroll, 47 firstItemIsFullWidth: Boolean = false, 48 verticalArrangement: Arrangement.Vertical = 49 Arrangement.spacedBy( 50 space = 4.dp, 51 alignment = Alignment.Top, 52 ), 53 horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally, 54 contentPadding: PaddingValues = PaddingValues(horizontal = 10.dp), 55 topPaddingDp: Dp = 32.dp + (if (firstItemIsFullWidth) 20.dp else 0.dp), 56 ): ScalingLazyColumnState.Factory { 57 return object : ScalingLazyColumnState.Factory { 58 @Composable 59 override fun create(): ScalingLazyColumnState { 60 val density = LocalDensity.current 61 val configuration = LocalConfiguration.current 62 63 return remember { 64 val screenHeightPx = 65 with(density) { configuration.screenHeightDp.dp.roundToPx() } 66 val topPaddingPx = with(density) { topPaddingDp.roundToPx() } 67 val topScreenOffsetPx = screenHeightPx / 2 - topPaddingPx 68 69 ScalingLazyColumnState( 70 initialScrollPosition = ScalingLazyColumnState.ScrollPosition( 71 index = 0, 72 offsetPx = topScreenOffsetPx, 73 ), 74 anchorType = ScalingLazyListAnchorType.ItemStart, 75 rotaryMode = rotaryMode, 76 verticalArrangement = verticalArrangement, 77 horizontalAlignment = horizontalAlignment, 78 contentPadding = contentPadding, 79 ) 80 } 81 } 82 } 83 } 84 85 /** 86 * Layout the item [initialCenterIndex] at [initialCenterOffset] from the 87 * center of the screen. 88 */ 89 @ExperimentalHorologistApi scalingLazyColumnDefaultsnull90 public fun scalingLazyColumnDefaults( 91 rotaryMode: RotaryMode = RotaryMode.Scroll, 92 initialCenterIndex: Int = 1, 93 initialCenterOffset: Int = 0, 94 verticalArrangement: Arrangement.Vertical = 95 Arrangement.spacedBy( 96 space = 4.dp, 97 alignment = Alignment.Top, 98 ), 99 horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally, 100 contentPadding: PaddingValues = PaddingValues(horizontal = 10.dp), 101 autoCentering: AutoCenteringParams? = AutoCenteringParams( 102 initialCenterIndex, 103 initialCenterOffset, 104 ), 105 anchorType: ScalingLazyListAnchorType = ScalingLazyListAnchorType.ItemCenter, 106 hapticsEnabled: Boolean = true, 107 reverseLayout: Boolean = false, 108 ): ScalingLazyColumnState.Factory { 109 return object : ScalingLazyColumnState.Factory { 110 @Composable 111 override fun create(): ScalingLazyColumnState { 112 return remember { 113 ScalingLazyColumnState( 114 initialScrollPosition = ScalingLazyColumnState.ScrollPosition( 115 index = initialCenterIndex, 116 offsetPx = initialCenterOffset, 117 ), 118 rotaryMode = rotaryMode, 119 verticalArrangement = verticalArrangement, 120 horizontalAlignment = horizontalAlignment, 121 contentPadding = contentPadding, 122 autoCentering = autoCentering, 123 anchorType = anchorType, 124 hapticsEnabled = hapticsEnabled, 125 reverseLayout = reverseLayout, 126 ) 127 } 128 } 129 } 130 } 131 } 132