Use correct fold size units and update content drawer logic (#80)

* Update content drawer to use custom separated column implementation

* Update gradle version

* Update content drawer and padding values

* Rename params with units

* Update UI tests

* Add missing content descriptions to CompanionPane

* Update dependencies

* Remove unnecessary dependency

* Remove redundant px/dp conversions

* Update readme

* Change to stable dependencies
This commit is contained in:
Kristen Halper 2022-02-02 18:00:40 -05:00 коммит произвёл GitHub
Родитель 289e116675
Коммит f79c108632
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
17 изменённых файлов: 262 добавлений и 108 удалений

Просмотреть файл

@ -29,9 +29,12 @@ android {
kotlinCompilerExtensionVersion composeVersion
}
packagingOptions {
exclude "META-INF/licenses/**"
exclude "META-INF/AL2.0"
exclude "META-INF/LGPL2.1"
jniLibs {
excludes += ['META-INF/licenses/**']
}
resources {
excludes += ['META-INF/licenses/**', 'META-INF/AL2.0', 'META-INF/LGPL2.1']
}
}
}

Просмотреть файл

@ -39,17 +39,19 @@ enum class Filters(@StringRes val title: Int, @DrawableRes val image: Int) {
LUDWIG(R.string.ludwig, R.drawable.ludwig)
}
enum class Effects(@StringRes val title: Int, @DrawableRes val image: Int) {
FILTER(R.string.filter, R.drawable.filter_icon),
HDR(R.string.hdr, R.drawable.hdr_icon),
ELLIPSE(R.string.ellipse, R.drawable.ecllipse_icon),
HORIZONTAL(R.string.vertical, R.drawable.vertical_icon),
VERTICAL(R.string.horizontal, R.drawable.horizontal_icon),
ZOOM(R.string.zoom, R.drawable.zoom_icon),
BRIGHTNESS(R.string.brightness, R.drawable.brightness_icon)
}
private val filterList = Filters.values()
private val fullIconList = listOf<@DrawableRes Int>(
R.drawable.filter_icon,
R.drawable.hdr_icon,
R.drawable.ecllipse_icon,
R.drawable.vertical_icon,
R.drawable.horizontal_icon,
R.drawable.zoom_icon,
R.drawable.brightness_icon
)
private val fullIconList = Effects.values().toList()
private val shortIconList = fullIconList.subList(2, 5)
@ -122,7 +124,7 @@ fun AdjustScale() {
.height(5.dp),
contentScale = ContentScale.Inside,
alignment = Alignment.Center,
contentDescription = null
contentDescription = stringResource(R.string.dot)
)
Image(
painter = painterResource(R.drawable.scale_icon),
@ -131,7 +133,7 @@ fun AdjustScale() {
.height(25.dp),
contentScale = ContentScale.Inside,
alignment = Alignment.Center,
contentDescription = null
contentDescription = stringResource(R.string.scale)
)
}
}
@ -146,8 +148,8 @@ fun FullIconsPanel() {
) {
fullIconList.forEach { icon ->
Image(
painter = painterResource(id = icon),
contentDescription = null,
painter = painterResource(id = icon.image),
contentDescription = stringResource(icon.title),
)
}
}
@ -163,8 +165,8 @@ fun ShortIconsPanel() {
) {
shortIconList.forEach { icon ->
Image(
painter = painterResource(id = icon),
contentDescription = null,
painter = painterResource(id = icon.image),
contentDescription = stringResource(icon.title),
)
}
}

Просмотреть файл

@ -11,6 +11,14 @@
<string name="definition">Definition</string>
<string name="vignette">Vignette</string>
<string name="brightness">Brightness</string>
<string name="dot">Dot</string>
<string name="scale">Scale</string>
<string name="filter">Filter</string>
<string name="hdr">HDR</string>
<string name="ellipse">Ellipse</string>
<string name="vertical">Vertical</string>
<string name="horizontal">Horizontal</string>
<string name="zoom">Zoom</string>
<!-- Filters -->
<string name="filters">Filters</string>

Просмотреть файл

@ -29,9 +29,12 @@ android {
kotlinCompilerExtensionVersion composeVersion
}
packagingOptions {
exclude "META-INF/licenses/**"
exclude "META-INF/AL2.0"
exclude "META-INF/LGPL2.1"
jniLibs {
excludes += ['META-INF/licenses/**']
}
resources {
excludes += ['META-INF/licenses/**', 'META-INF/AL2.0', 'META-INF/LGPL2.1']
}
}
}

Просмотреть файл

@ -29,9 +29,12 @@ android {
kotlinCompilerExtensionVersion composeVersion
}
packagingOptions {
exclude "META-INF/licenses/**"
exclude "META-INF/AL2.0"
exclude "META-INF/LGPL2.1"
jniLibs {
excludes += ['META-INF/licenses/**']
}
resources {
excludes += ['META-INF/licenses/**', 'META-INF/AL2.0', 'META-INF/LGPL2.1']
}
}
}

Просмотреть файл

@ -29,9 +29,12 @@ android {
kotlinCompilerExtensionVersion composeVersion
}
packagingOptions {
exclude "META-INF/licenses/**"
exclude "META-INF/AL2.0"
exclude "META-INF/LGPL2.1"
jniLibs {
excludes += ['META-INF/licenses/**']
}
resources {
excludes += ['META-INF/licenses/**', 'META-INF/AL2.0', 'META-INF/LGPL2.1']
}
}
}

Просмотреть файл

@ -45,7 +45,7 @@ dependencies {
implementation microsoftDependencies.twoPaneLayout
implementation microsoftDependencies.windowState
implementation composeDependencies.composeMaterialForNavRail
implementation composeDependencies.composeMaterial
implementation composeDependencies.composeRuntime
implementation composeDependencies.navigationCompose
implementation composeDependencies.composeAnimation

Просмотреть файл

@ -5,11 +5,13 @@
package com.microsoft.device.display.samples.navigationrail
import android.graphics.Rect
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.runtime.Composable
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.semantics.SemanticsProperties.HorizontalScrollAxisRange
import androidx.compose.ui.semantics.SemanticsProperties.VerticalScrollAxisRange
import androidx.compose.ui.test.SemanticsMatcher
@ -195,7 +197,9 @@ class DetailTest {
Pane2(
isDualPortrait = isDualPortrait,
isDualLandscape = isDualLandscape,
foldSize = 0.dp,
foldOccludes = false,
foldBounds = Rect(0, 0, 0, 0),
windowHeight = LocalConfiguration.current.screenHeightDp.dp,
imageId = 0,
updateImageId = {},
currentRoute = "plants"
@ -212,7 +216,9 @@ class DetailTest {
ItemDetailView(
isDualPortrait = false,
isDualLandscape = false,
foldSize = 0.dp,
foldOccludes = false,
foldBounds = Rect(0, 0, 0, 0),
windowHeight = LocalConfiguration.current.screenHeightDp.dp,
selectedImage = plantList[0],
currentRoute = "plants"
)

Просмотреть файл

@ -5,20 +5,25 @@
package com.microsoft.device.display.samples.navigationrail.ui.components
import android.graphics.RectF
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.BoxWithConstraintsScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.BottomSheetScaffoldDefaults
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.SwipeableState
import androidx.compose.material.rememberSwipeableState
import androidx.compose.material.swipeable
import androidx.compose.runtime.Composable
@ -34,6 +39,7 @@ import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.microsoft.device.display.samples.navigationrail.R
import java.lang.IllegalArgumentException
private const val CONTENT_HORIZ_PADDING_PERECENT = 0.06f
private val DrawerShape = RoundedCornerShape(
@ -53,61 +59,83 @@ enum class DrawerState { Collapsed, Expanded }
* Custom drawer (bottom aligned) with a rounded corner shape that swipes between a collapsed
* "peek" view and a more expanded view that displays all of the content
*
* Supports foldable displays by splitting the "peekContent" and "hiddenContent" around an occluding
* fold
*
* @param modifier: optional Modifier to be applied to the layout
* @param expandHeight: height of the drawer when expanded (in dp)
* @param collapseHeight: height of the drawer when collpased (in dp)
* @param hingeOccludes: optional param for foldable support, indicates whether there is a hinge
* @param expandedHeightPct: height of the drawer when expanded, expressed as percentage of maximum possible
* height (must be > 0, <= 1)
* @param collapsedHeightPct: height of the drawer when collapsed, expressed as percentage of maximum possible
* height (must be > 0, <= 1)
* @param foldOccludes: optional param for foldable support, indicates whether there is a hinge
* that occludes content in the current layout
* @param foldSize: optional param for foldable support, indicates the size of a fold
* @param foldBoundsDp: optional param for foldable support, indicates the coordinates of the boundary
* of a fold
* @param windowHeightDp: optional param for foldable support, indicates the full height of the window
* in which a fold and the content drawer are being displayed
* @param foldBottomPaddingDp: optional param for foldable support, will be added as padding below the fold to
* make content more accessible to users
* @param hiddenContent: the content that will only be shown when the drawer is expanded
* @param peekContent: the content that will be shown even when the drawer is collapsed
*/
@ExperimentalMaterialApi
@Composable
fun ContentDrawer(
fun BoxWithConstraintsScope.ContentDrawer(
modifier: Modifier = Modifier,
expandHeight: Dp,
collapseHeight: Dp,
hingeOccludes: Boolean = false,
foldSize: Dp = 0.dp,
expandedHeightPct: Float,
collapsedHeightPct: Float,
foldOccludes: Boolean = false,
foldBoundsDp: RectF = RectF(),
windowHeightDp: Dp = 0.dp,
foldBottomPaddingDp: Dp = 0.dp,
hiddenContent: @Composable ColumnScope.() -> Unit,
peekContent: @Composable ColumnScope.() -> Unit,
) {
// Calculate drawer y coordinates for the collapsed and expanded states
val expandHeightPx = with(LocalDensity.current) { expandHeight.toPx() }
val collapseHeightPx = with(LocalDensity.current) { collapseHeight.toPx() }
// Calculate drawer y coordinates for the collapsed and expanded states - pixels
if (!expandedHeightPct.isInPctRange() || !collapsedHeightPct.isInPctRange())
throw IllegalArgumentException("expandedHeightPct $expandedHeightPct or collapsedHeightPct $collapsedHeightPct is not in range (0, 1]")
val fullHeight = constraints.maxHeight.toFloat()
val expandHeightPx = expandedHeightPct * fullHeight
val collapseHeightPx = collapsedHeightPct * fullHeight
val swipeHeightPx = expandHeightPx - collapseHeightPx
// Set up swipeable modifier fields
val swipeableState = rememberSwipeableState(initialValue = DrawerState.Collapsed)
val anchors = mapOf(swipeHeightPx to DrawerState.Collapsed, 0f to DrawerState.Expanded)
// Calculate the height of each drawer component (top content, fold, bottom content) - dp
val expandHeightDp = with(LocalDensity.current) { expandHeightPx.toDp() }
val collapseHeightDp = with(LocalDensity.current) { collapseHeightPx.toDp() }
val foldSizeDp = foldBoundsDp.height().dp
val bottomContentMaxHeightDp = windowHeightDp - foldBoundsDp.bottom.dp
val topContentMaxHeightDp: Dp = if (foldOccludes) {
expandHeightDp - foldSizeDp - bottomContentMaxHeightDp
} else {
collapseHeightDp
}
BoxWithConstraints(
modifier = modifier
.align(Alignment.BottomCenter)
.swipeable(swipeableState, anchors, Orientation.Vertical)
.semantics { this.drawerState = swipeableState.currentValue }
.testTag(stringResource(R.string.content_drawer)),
contentAlignment = Alignment.TopStart,
) {
// Check if a spacer needs to be included to render content around an occluding hinge
val spacerHeight = if (hingeOccludes) {
val isExpanding = swipeableState.progress.to == DrawerState.Expanded
val progressHeight = (foldSize.value * swipeableState.progress.fraction).dp
if (isExpanding)
progressHeight
else
foldSize - progressHeight
} else {
0.dp
}
val minSpacerHeight = calculateSpacerHeight(
foldOccludes,
swipeableState,
foldSizeDp.value + foldBottomPaddingDp.value
).toInt().dp
// Calculate drawer height based on swipe state (height in dp)
// Calculate drawer height in dp based on swipe state
val swipeOffsetDp = with(LocalDensity.current) { swipeableState.offset.value.toDp() }
val drawerHeight = expandHeight - swipeOffsetDp
val drawerHeight = expandHeightDp - swipeOffsetDp
Surface(
modifier = Modifier
.heightIn(collapseHeight, expandHeight)
.heightIn(collapseHeightDp, expandHeightDp)
.height(drawerHeight)
.clip(DrawerShape)
.background(MaterialTheme.colors.surface),
@ -117,13 +145,48 @@ fun ContentDrawer(
val paddingPx = CONTENT_HORIZ_PADDING_PERECENT * constraints.maxWidth.toFloat()
val paddingDp = with(LocalDensity.current) { paddingPx.toDp() }
val fillWidth = Modifier.fillMaxWidth()
Column(
modifier = Modifier.padding(horizontal = paddingDp)
modifier = Modifier.padding(horizontal = paddingDp),
) {
peekContent()
Spacer(Modifier.height(spacerHeight))
Column(fillWidth.requiredHeight(topContentMaxHeightDp)) { peekContent() }
Spacer(Modifier.requiredHeight(minSpacerHeight))
hiddenContent()
}
}
}
}
/**
* Helper method to calculate the animated height of the spacer used for foldable support. Height
* is progressively increased or decreased based on the swipe state.
*
* @param foldOccludes: whether or not a fold is present and occluding content
* @param swipeableState: swipeable state of the component that contains a spacer
* @param fullHeight: the desired full height of the spacer when the parent component has been swiped
* to the expanded state
*
* @return the height of the spacer for the current swipe progress
*/
@ExperimentalMaterialApi
private fun calculateSpacerHeight(
foldOccludes: Boolean,
swipeableState: SwipeableState<DrawerState>,
fullHeight: Float
): Float {
if (!foldOccludes)
return 0f
val isExpanding = swipeableState.progress.to == DrawerState.Expanded
val progressHeight = (fullHeight * swipeableState.progress.fraction)
return if (isExpanding) progressHeight else fullHeight - progressHeight
}
/**
* Helper method that checks if a percentage is valid
*/
private fun Float.isInPctRange(): Boolean {
return this > 0f && this <= 1f
}

Просмотреть файл

@ -5,6 +5,7 @@
package com.microsoft.device.display.samples.navigationrail.ui.view
import android.graphics.Rect
import androidx.activity.compose.BackHandler
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.ExperimentalFoundationApi
@ -16,7 +17,6 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.ExperimentalUnitApi
import androidx.compose.ui.unit.dp
import com.microsoft.device.display.samples.navigationrail.models.DataProvider
import com.microsoft.device.display.samples.navigationrail.ui.components.ItemTopBar
import com.microsoft.device.dualscreen.twopanelayout.TwoPaneLayout
@ -43,8 +43,9 @@ fun NavigationRailApp(windowState: WindowState) {
isDualScreen = windowState.isDualScreen(),
isDualPortrait = windowState.isDualPortrait(),
isDualLandscape = windowState.isDualLandscape(),
// REVISIT: fix when addressing https://github.com/microsoft/surface-duo-compose-samples/issues/74
foldSize = windowState.foldSize.dp,
foldOccludes = windowState.foldOccludes,
foldBounds = windowState.foldBounds,
windowHeight = windowState.windowHeight,
imageId = imageId,
updateImageId = updateImageId,
currentRoute = currentRoute,
@ -61,7 +62,9 @@ fun NavigationRailAppContent(
isDualScreen: Boolean,
isDualPortrait: Boolean,
isDualLandscape: Boolean,
foldSize: Dp,
foldOccludes: Boolean,
foldBounds: Rect,
windowHeight: Dp,
imageId: Int?,
updateImageId: (Int?) -> Unit,
currentRoute: String,
@ -73,7 +76,16 @@ fun NavigationRailAppContent(
Pane1(isDualScreen, isDualPortrait, imageId, updateImageId, currentRoute, updateRoute)
},
pane2 = {
Pane2(isDualPortrait, isDualLandscape, foldSize, imageId, updateImageId, currentRoute)
Pane2(
isDualPortrait = isDualPortrait,
isDualLandscape = isDualLandscape,
foldOccludes = foldOccludes,
foldBounds = foldBounds,
windowHeight = windowHeight,
imageId = imageId,
updateImageId = updateImageId,
currentRoute = currentRoute
)
},
)
@ -107,7 +119,9 @@ fun Pane1(
fun Pane2(
isDualPortrait: Boolean,
isDualLandscape: Boolean,
foldSize: Dp,
foldOccludes: Boolean,
foldBounds: Rect,
windowHeight: Dp,
imageId: Int?,
updateImageId: (Int?) -> Unit,
currentRoute: String,
@ -122,7 +136,15 @@ fun Pane2(
}
BackHandler { if (!isDualPortrait) onBackPressed() }
ItemDetailView(isDualPortrait, isDualLandscape, foldSize, selectedImage, currentRoute)
ItemDetailView(
isDualPortrait = isDualPortrait,
isDualLandscape = isDualLandscape,
foldOccludes = foldOccludes,
foldBounds = foldBounds,
windowHeight = windowHeight,
selectedImage = selectedImage,
currentRoute = currentRoute
)
// If only one pane is being displayed, show a "back" icon
if (!isDualPortrait) {
ItemTopBar(

Просмотреть файл

@ -5,6 +5,7 @@
package com.microsoft.device.display.samples.navigationrail.ui.view
import android.graphics.Rect
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.fillMaxSize
@ -28,7 +29,9 @@ import com.microsoft.device.dualscreen.twopanelayout.navigateToPane1
*
* @param isDualPortrait: true if device is in dual portrait mode
* @param isDualLandscape: true if device is in dual landscape mode
* @param foldSize: size of fold in dp (0 if no fold)
* @param foldOccludes: true if a fold is present and it occludes content, false otherwise
* @param foldBounds: the bounds of a fold in the form of an Android Rect
* @param windowHeight: full height in dp of the window this view is being shown in
* @param selectedImage: currently selected image
* @param currentRoute: current route in gallery NavHost
*/
@ -38,7 +41,9 @@ import com.microsoft.device.dualscreen.twopanelayout.navigateToPane1
fun ItemDetailView(
isDualPortrait: Boolean,
isDualLandscape: Boolean,
foldSize: Dp,
foldOccludes: Boolean,
foldBounds: Rect,
windowHeight: Dp,
selectedImage: Image? = null,
currentRoute: String,
) {
@ -60,10 +65,12 @@ fun ItemDetailView(
) {
ItemImage(Modifier.align(Alignment.TopCenter), selectedImage)
ItemDetailsDrawer(
modifier = Modifier.align(Alignment.BottomCenter),
image = selectedImage,
isDualLandscape = isDualLandscape,
foldSize = foldSize,
isDualPortrait = isDualPortrait,
foldOccludes = foldOccludes,
foldBounds = foldBounds,
windowHeight = windowHeight,
gallerySection = gallerySection,
)
}

Просмотреть файл

@ -5,6 +5,9 @@
package com.microsoft.device.display.samples.navigationrail.ui.view
import android.content.res.Configuration
import android.graphics.Rect
import android.graphics.RectF
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.BoxWithConstraintsScope
import androidx.compose.foundation.layout.ColumnScope
@ -22,6 +25,7 @@ import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@ -41,9 +45,11 @@ import com.microsoft.device.display.samples.navigationrail.ui.components.InfoBox
private lateinit var BodyTextStyle: TextStyle
private lateinit var SubtitleTextStyle: TextStyle
private const val EXPANDED_HEIGHT_2PANE = 0.7f
private const val EXPANDED_HEIGHT_1PANE = 0.55f
private const val EXPANDED_HEIGHT_1PANE_PORTRAIT = 0.55f
private const val EXPANDED_HEIGHT_1PANE_LANDSCAPE = 0.65f
private const val COLLAPSED_HEIGHT_2PANE = 0.4f
private const val COLLAPSED_HEIGHT_1PANE = 0.28f
private const val COLLAPSED_HEIGHT_1PANE_PORTRAIT = 0.28f
private const val COLLAPSED_HEIGHT_1PANE_LANDSCAPE = 0.357f
private val PILL_TOP_PADDING = 8.dp
private val NAME_TOP_PADDING = 8.dp
private val LOCATION_TOP_PADDING = 10.dp
@ -57,18 +63,42 @@ private const val LONG_DETAILS_LINE_HEIGHT = 32f
@ExperimentalMaterialApi
@Composable
fun BoxWithConstraintsScope.ItemDetailsDrawer(
modifier: Modifier,
image: Image,
isDualLandscape: Boolean,
foldSize: Dp,
isDualPortrait: Boolean,
foldOccludes: Boolean,
foldBounds: Rect,
windowHeight: Dp,
gallerySection: GallerySections?,
) {
val isPortrait = LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT
// Set max/min height for drawer based on orientation
val expandedHeightPct = if (isDualLandscape) EXPANDED_HEIGHT_2PANE else EXPANDED_HEIGHT_1PANE
val collapsedHeightPct = if (isDualLandscape) COLLAPSED_HEIGHT_2PANE else COLLAPSED_HEIGHT_1PANE
val fullHeight = constraints.maxHeight.toFloat()
val expandedHeight = with(LocalDensity.current) { (expandedHeightPct * fullHeight).toDp() }
val collapsedHeight = with(LocalDensity.current) { (collapsedHeightPct * fullHeight).toDp() }
val expandedHeightPct: Float
val collapsedHeightPct: Float
when {
isDualLandscape -> {
expandedHeightPct = EXPANDED_HEIGHT_2PANE
collapsedHeightPct = COLLAPSED_HEIGHT_2PANE
}
isDualPortrait || isPortrait -> {
expandedHeightPct = EXPANDED_HEIGHT_1PANE_PORTRAIT
collapsedHeightPct = COLLAPSED_HEIGHT_1PANE_PORTRAIT
}
else -> {
expandedHeightPct = EXPANDED_HEIGHT_1PANE_LANDSCAPE
collapsedHeightPct = COLLAPSED_HEIGHT_1PANE_LANDSCAPE
}
}
val foldBoundsDp: RectF
with(LocalDensity.current) {
val leftDp = foldBounds.left.toDp().value
val topDp = foldBounds.top.toDp().value
val rightDp = foldBounds.right.toDp().value
val bottomDp = foldBounds.bottom.toDp().value
foldBoundsDp = RectF(leftDp, topDp, rightDp, bottomDp)
}
// Set text size for drawer based on orientation
if (isDualLandscape) {
@ -80,11 +110,12 @@ fun BoxWithConstraintsScope.ItemDetailsDrawer(
}
ContentDrawer(
modifier = modifier,
expandHeight = expandedHeight,
collapseHeight = collapsedHeight,
hingeOccludes = isDualLandscape,
foldSize = foldSize,
expandedHeightPct = expandedHeightPct,
collapsedHeightPct = collapsedHeightPct,
foldOccludes = foldOccludes && isDualLandscape,
foldBoundsDp = foldBoundsDp,
foldBottomPaddingDp = LONG_DETAILS_TOP_PADDING,
windowHeightDp = windowHeight,
hiddenContent = { ItemDetailsLong(image.details) }
) {
DrawerPill()
@ -162,7 +193,6 @@ private fun ItemConditions(gallerySection: GallerySections?, fact1: String, fact
private fun ItemDetailsLong(details: String) {
val scrollState = rememberScrollState()
Spacer(Modifier.height(LONG_DETAILS_TOP_PADDING))
Text(
modifier = Modifier
.padding(bottom = LONG_DETAILS_BOTTOM_PADDING)

Просмотреть файл

@ -8,7 +8,7 @@ products:
description: "Samples showing how to use Jetpack Compose to achieve dual-screen user interface patterns."
urlFragment: all
---
![build-test-check](https://github.com/microsoft/surface-duo-compose-samples/actions/workflows/build_test_check.yml/badge.svg) ![Compose Version](https://img.shields.io/badge/Jetpack%20Compose-1.0.5-brightgreen)
![build-test-check](https://github.com/microsoft/surface-duo-compose-samples/actions/workflows/build_test_check.yml/badge.svg) ![Compose Version](https://img.shields.io/badge/Jetpack%20Compose-1.1.0&#8208;rc03-brightgreen)
# Surface Duo Jetpack Compose Samples
@ -26,9 +26,11 @@ Please check out our page on [Jetpack Compose for Microsoft Surface Duo](https:/
## Prerequisites
- Jetpack Compose version: `1.0.5`
- Jetpack Compose version: `1.1.0-rc03`
- Jetpack WindowManager version: `1.0.0-rc01`
- Jetpack WindowManager version: `1.0.0`
- Android Studio version: Bumblebee `2021.1.1`
## Microsoft Compose Libraries
@ -55,6 +57,8 @@ The samples are built with Microsoft Compose libraries, [TwoPaneLayout](https://
## Social links
- [video: Jetpack Compose WindowState preview](https://www.twitch.tv/videos/1271211220)
- [blog: Jetpack Compose WindowState preview](https://devblogs.microsoft.com/surface-duo/jetpack-compose-windowstate-preview/)
- [video: Get started with Jetpack Compose Twitch](https://www.youtube.com/watch?v=ijXDWDtdiIE)
- [blog: Get started with Jetpack Compose](https://devblogs.microsoft.com/surface-duo/get-started-with-jetpack-compose/)
- [video: NavigationRail Compose sample Twitch](https://www.youtube.com/watch?v=pdoIyOU7Suk)

Просмотреть файл

@ -31,9 +31,12 @@ android {
kotlinCompilerExtensionVersion composeVersion
}
packagingOptions {
exclude "META-INF/licenses/**"
exclude "META-INF/AL2.0"
exclude "META-INF/LGPL2.1"
jniLibs {
excludes += ['META-INF/licenses/**']
}
resources {
excludes += ['META-INF/licenses/**', 'META-INF/AL2.0', 'META-INF/LGPL2.1']
}
}
}

Просмотреть файл

@ -4,8 +4,8 @@
*/
ext {
gradlePluginVersion = '7.0.4'
kotlinVersion = "1.5.31"
gradlePluginVersion = '7.1.0'
kotlinVersion = "1.6.10"
compileSdkVersion = 31
targetSdkVersion = compileSdkVersion
minSdkVersion = 23
@ -21,20 +21,18 @@ ext {
]
// AndroidX versions
appCompatVersion = "1.3.0"
ktxCoreVersion = "1.5.0"
windowVersion = "1.0.0-rc01"
appCompatVersion = '1.4.1'
ktxCoreVersion = '1.7.0'
windowVersion = '1.0.0'
androidxDependencies = [
appCompat : "androidx.appcompat:appcompat:$appCompatVersion",
ktxCore : "androidx.core:core-ktx:$ktxCoreVersion",
window : "androidx.window:window:$windowVersion",
appCompat : "androidx.appcompat:appcompat:$appCompatVersion",
ktxCore : "androidx.core:core-ktx:$ktxCoreVersion",
]
// Compose dependencies
composeVersion = "1.0.5"
composeUnstableVersion = "1.1.0-rc01"
composeVersion = "1.1.0-rc03"
activityComposeVersion = "1.4.0"
navigationComposeVersion = "2.4.0-rc01"
navigationComposeVersion = '2.4.0'
composeDependencies = [
composeAnimation : "androidx.compose.animation:animation:$composeVersion",
composeRuntime : "androidx.compose.runtime:runtime-livedata:$composeVersion",
@ -43,7 +41,6 @@ ext {
composeUITooling : "androidx.compose.ui:ui-tooling:$composeVersion",
activityCompose : "androidx.activity:activity-compose:$activityComposeVersion",
navigationCompose : "androidx.navigation:navigation-compose:$navigationComposeVersion",
composeMaterialForNavRail: "androidx.compose.material:material:$composeUnstableVersion",
]
// Testing versions
@ -67,7 +64,7 @@ ext {
]
// Google dependencies
materialVersion = "1.5.0-alpha01"
materialVersion = '1.5.0'
googleDependencies = [
material: "com.google.android.material:material:$materialVersion"
]
@ -76,7 +73,7 @@ ext {
twoPaneLayoutVersion = "1.0.0-alpha10"
windowStateVersion = "1.0.0-alpha1"
microsoftDependencies = [
twoPaneLayout: "com.microsoft.device.dualscreen:twopanelayout:$twoPaneLayoutVersion",
windowState: "com.microsoft.device.dualscreen:windowstate:$windowStateVersion",
twoPaneLayout : "com.microsoft.device.dualscreen:twopanelayout:$twoPaneLayoutVersion",
windowState : "com.microsoft.device.dualscreen:windowstate:$windowStateVersion",
]
}

2
gradle/wrapper/gradle-wrapper.properties поставляемый
Просмотреть файл

@ -5,7 +5,7 @@
#Thu Feb 25 11:36:45 PST 2021
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

Просмотреть файл

@ -18,7 +18,7 @@ dependencies {
task ktlint(type: JavaExec, group: "verification") {
description = "Check Kotlin code style."
classpath = configurations.ktlint
main = "com.pinterest.ktlint.Main"
mainClass.set("com.pinterest.ktlint.Main")
args "src/**/*.kt"
// to generate report in checkstyle format prepend following args:
// "--reporter=plain", "--reporter=checkstyle,output=${buildDir}/ktlint.xml"
@ -28,6 +28,6 @@ task ktlint(type: JavaExec, group: "verification") {
task ktlintFormat(type: JavaExec, group: "formatting") {
description = "Fix Kotlin code style deviations."
classpath = configurations.ktlint
main = "com.pinterest.ktlint.Main"
mainClass.set("com.pinterest.ktlint.Main")
args "-F", "src/**/*.kt"
}