From fde2c8776596cd18a37598181591e744ed1190b2 Mon Sep 17 00:00:00 2001 From: Tim Froehlich Date: Thu, 26 Dec 2024 22:04:03 +0000 Subject: [PATCH] Resolve various warnings in the code This should help us track down some of the bugs we're having with the proto conversion. # Conflicts: # designcompose/src/main/java/com/android/designcompose/squoosh/SquooshText.kt # designcompose/src/main/java/com/android/designcompose/squoosh/SquooshTreeBuilder.kt # integration-tests/validation/src/main/java/com/android/designcompose/testapp/validation/examples/AllExamples.kt # integration-tests/validation/src/main/java/com/android/designcompose/testapp/validation/examples/VariantAnimationTimelineTest.kt --- crates/figma_import/src/design_definition.rs | 1 - .../figma_import/tests/layout-unit-tests.dcf | Bin 22657 -> 22657 bytes crates/figma_import/tests/test_fetches.rs | 4 +- ...signSwitcherDoc_Ljph4e3sC0lHcynfXpoh9f.dcf | Bin 247603 -> 247603 bytes .../android/designcompose/ApiKeyService.kt | 4 +- .../designcompose/CustomizationContext.kt | 10 - .../android/designcompose/DesignSwitcher.kt | 32 +- .../com/android/designcompose/DocServer.kt | 2 +- .../com/android/designcompose/FrameRender.kt | 20 +- .../android/designcompose/InteractionState.kt | 14 +- .../android/designcompose/KeyInjectManager.kt | 4 +- .../designcompose/LiveUpdateExceptions.kt | 8 +- .../android/designcompose/VariableManager.kt | 31 +- .../designcompose/squoosh/SquooshLayout.kt | 4 +- .../designcompose/squoosh/SquooshRender.kt | 12 +- .../designcompose/squoosh/SquooshText.kt | 23 +- .../squoosh/SquooshTreeBuilder.kt | 54 ++-- .../designcompose/utils/GraphicUtils.kt | 2 - .../designcompose/utils/LayoutUtils.kt | 125 -------- .../designcompose/utils/ViewStyleUtils.kt | 15 +- .../validation/examples/AllExamples.kt | 11 +- .../examples/VariantAnimationTimelineTest.kt | 282 +++++------------- .../testapp/validation/AnimationTimelines.kt | 170 +++++------ .../TutorialDoc_3z4xExq0INrL9vxPhj9tl7.dcf | Bin 34364 -> 34364 bytes 24 files changed, 251 insertions(+), 577 deletions(-) diff --git a/crates/figma_import/src/design_definition.rs b/crates/figma_import/src/design_definition.rs index d7ea1d4f5..96342c1a6 100644 --- a/crates/figma_import/src/design_definition.rs +++ b/crates/figma_import/src/design_definition.rs @@ -44,7 +44,6 @@ where #[cfg(test)] mod serialized_document_tests { - use dc_bundle::definition_file::{load_design_def, save_design_def}; use std::fs::File; use std::io::Write; diff --git a/crates/figma_import/tests/layout-unit-tests.dcf b/crates/figma_import/tests/layout-unit-tests.dcf index ece51f9f1843e649cd92fabb14fd6540f59c92bf..7a4dacebd5cec65f495a37c9d053ef389d0e9933 100644 GIT binary patch delta 533 zcmXw$J7|+}6vaLH+B|C$zot!-G|ksM&BLa7RS9BEOC{9OD#6AC8XH0gg*1UsP%%qu zadFV(kK$-IEw&O5bZ`_G7jbvd!KITpI0^b8Ivx03IOpDbcKX=q%H zwOV_7vs!87tL;{!vDvK4J*!^J?{f}7M^m;4yHTk}czn0wqII*${ zXxLb_YasE#b-xA!e3dT(gVf%*D~Wi(k0c9$D3Ib_@E(xvg??l9O}Gj1-sHq2znDe= zH-8SPTPrLN&jVB3H(vuh{9(yT@G@mBN$~NJt&8ru58?i91c>kmuYn-T(l~IIw+FU> z5WfxXLMV0xHfHTEV4SxcCBV+N&JGL?S*KQ%&LqS}t|TlTisi|=(fOZV5S3i=Xrix4Qw?~J1?@+VT|(9^e_-- zZRRE5;pE9~z{}#PD&XUr)3+h+DB(Xxe}BX&8jE#w2_GOOQ8*- zHsBH4`7tpw=Z3f{AjtL3I}m#v zesr+a9);CzmW&%2aVr{N$*~OY2d|>8%vZ}sp}e-fv@l;ezEr7byIz|{t;-2G8F8C7 zI=S6F3Ap&qQvkXc@nvPWdAawTjBf4*>cF%51+P@=Y;1bb0#J*db81<;>$d3(4fX*E9v#X7Ns3{QgcP60`X!|KezXW=7}KxIQgGj2RI!?L diff --git a/crates/figma_import/tests/test_fetches.rs b/crates/figma_import/tests/test_fetches.rs index dd3afd363..fe4392390 100644 --- a/crates/figma_import/tests/test_fetches.rs +++ b/crates/figma_import/tests/test_fetches.rs @@ -16,9 +16,7 @@ #![cfg(feature = "fetch")] use dc_bundle::definition::DesignComposeDefinitionHeader; -use dc_bundle::definition_file::{ - load_design_def, save_design_def, -}; +use dc_bundle::definition_file::{load_design_def, save_design_def}; use figma_import::tools::fetch::{build_definition, load_figma_token}; use figma_import::{Document, ProxyConfig}; use tempfile::NamedTempFile; diff --git a/designcompose/src/main/assets/figma/DesignSwitcherDoc_Ljph4e3sC0lHcynfXpoh9f.dcf b/designcompose/src/main/assets/figma/DesignSwitcherDoc_Ljph4e3sC0lHcynfXpoh9f.dcf index bcd29fb82a407653f0f409928156ab51299c696a..6c9e5d4724bb5e6e8686e829c15455bd538c550e 100644 GIT binary patch delta 6813 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 JY*@>G{2#4IH>&^u delta 6773 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 c.visibleState = Optional.ofNullable(visible) } } -fun CustomizationContext.setTextStyle(nodeName: String, textStyle: TextStyle) { - customize(nodeName) { c -> c.textStyle = Optional.ofNullable(textStyle) } -} - fun CustomizationContext.setMeterValue(nodeName: String, value: Float) { customize(nodeName) { c -> c.meterValue = Optional.ofNullable(value) } } @@ -389,10 +383,6 @@ fun CustomizationContext.getTextState(nodeName: String): State? { return cs[nodeName]?.textState?.getOrNull() } -fun CustomizationContext.getModifier(nodeName: String): Modifier? { - return cs[nodeName]?.modifier?.getOrNull() -} - fun CustomizationContext.getTapCallback(nodeName: String): TapCallback? { return cs[nodeName]?.tapCallback?.getOrNull() } diff --git a/designcompose/src/main/java/com/android/designcompose/DesignSwitcher.kt b/designcompose/src/main/java/com/android/designcompose/DesignSwitcher.kt index 4b8ee3bbf..7ccba54f0 100644 --- a/designcompose/src/main/java/com/android/designcompose/DesignSwitcher.kt +++ b/designcompose/src/main/java/com/android/designcompose/DesignSwitcher.kt @@ -59,36 +59,6 @@ private interface DesignSwitcher { ) } - private fun nodeCustomizations(): Array { - return arrayOf( - "#MiniViewMessage", - "#CurrentlyLoaded", - "#ChangingCurrent", - "#CurrentFileName", - "#ModDate", - "#BranchFileCount", - "#ProjectFileCount", - "#BranchList", - "#BranchSection", - "#ProjectFileList", - "#StatusMessageList", - "#DocIdTextEdit", - "#HelpText", - "#GoButton", - "#NodeNamesCheckbox", - "#MiniMessagesCheckbox", - "#ShowRecompositionCheckbox", - "#UseLocalResCheckbox", - "#Name", - "#Id", - "#Text", - "#TimeStamp", - "#Logout", - "#LiveMode", - "#TopStatusBar", - ) - } - private fun ignoredImages(): HashMap> { return hashMapOf( "#SettingsView" to @@ -374,7 +344,7 @@ private fun GetBranches( } private fun GetProjectFileCount(doc: DocContent?): String { - var count = doc?.c?.project_files?.size ?: 0 + val count = doc?.c?.project_files?.size ?: 0 return count.toString() } diff --git a/designcompose/src/main/java/com/android/designcompose/DocServer.kt b/designcompose/src/main/java/com/android/designcompose/DocServer.kt index fd22ae637..374e67652 100644 --- a/designcompose/src/main/java/com/android/designcompose/DocServer.kt +++ b/designcompose/src/main/java/com/android/designcompose/DocServer.kt @@ -371,7 +371,7 @@ internal fun DocServer.fetchDocuments(firstFetch: Boolean): Boolean { SpanCache.clear() for (subscriber in subs) { subscriber.onUpdate(doc) - subscriber.docUpdateCallback?.invoke(id, doc.c?.toSerializedBytes(Feedback)) + subscriber.docUpdateCallback?.invoke(id, doc.c.toSerializedBytes(Feedback)) } } Feedback.documentUpdated(id, subs.size) diff --git a/designcompose/src/main/java/com/android/designcompose/FrameRender.kt b/designcompose/src/main/java/com/android/designcompose/FrameRender.kt index 39529e342..ac0fa0dd0 100644 --- a/designcompose/src/main/java/com/android/designcompose/FrameRender.kt +++ b/designcompose/src/main/java/com/android/designcompose/FrameRender.kt @@ -194,7 +194,7 @@ private fun calculateProgressBarData( var endY = progressBarData.endY parent?.let { p -> val parentSize = p.computedLayout?.let { Size(it.width, it.height) } - parentSize?.let { pSize -> + parentSize?.let { val parentRenderSize = getNodeRenderSize(null, parentSize, p.style, p.layoutId, 1f) endY = parentRenderSize.height } @@ -212,7 +212,7 @@ private fun calculateProgressBarData( var endX = progressBarData.endX parent?.let { p -> val parentSize = p.computedLayout?.let { Size(it.width, it.height) } - parentSize?.let { pSize -> + parentSize?.let { val parentRenderSize = getNodeRenderSize(null, parentSize, p.style, p.layoutId, 1f) endX = parentRenderSize.width } @@ -251,15 +251,15 @@ private fun calculateProgressMarkerData( // along the x or y axis depending on whether it is horizontal or vertical val overrideTransform = style.getTransform(density) if (markerData.vertical) { - var startY = + val startY = parentSize?.let { it.height - (mySize?.height ?: 0f) / 2f } ?: markerData.startY val endY = mySize?.let { -it.height / 2f } ?: markerData.endY val moveY = lerp(startY, endY, discretizedMeterValue, density) val topOffset = style.layoutStyle.margin.top.pointsAsDp(density).value overrideTransform.setYTranslation(moveY - topOffset) } else { - var startX = mySize?.let { -it.width / 2f } ?: markerData.startX - var endX = parentSize?.let { it.width - (mySize?.width ?: 0f) / 2f } ?: markerData.endX + val startX = mySize?.let { -it.width / 2f } ?: markerData.startX + val endX = parentSize?.let { it.width - (mySize?.width ?: 0f) / 2f } ?: markerData.endX val moveX = lerp(startX, endX, discretizedMeterValue, density) val leftOffset = style.layoutStyle.margin.start.pointsAsDp(density).value overrideTransform.setXTranslation(moveX - leftOffset) @@ -418,12 +418,7 @@ internal fun ContentDrawScope.render( // Push any transforms val transform = overrideTransform ?: style.nodeStyle.transform.asComposeTransform(density) - var vectorScaleX = 1F - var vectorScaleY = 1F if (transform != null) { - val decomposed = style.nodeStyle.transform.decompose(density) - vectorScaleX = abs(decomposed.scaleX) - vectorScaleY = abs(decomposed.scaleY) drawContext.transform.transform(transform) } @@ -706,12 +701,7 @@ internal fun ContentDrawScope.squooshShapeRender( // Push any transforms val transform = overrideTransform ?: style.nodeStyle.transform.asComposeTransform(density) - var vectorScaleX = 1F - var vectorScaleY = 1F if (transform != null) { - val decomposed = style.nodeStyle.transform.decompose(density) - vectorScaleX = abs(decomposed.scaleX) - vectorScaleY = abs(decomposed.scaleY) drawContext.transform.transform(transform) } diff --git a/designcompose/src/main/java/com/android/designcompose/InteractionState.kt b/designcompose/src/main/java/com/android/designcompose/InteractionState.kt index f1b16d8ac..0a0521ac9 100644 --- a/designcompose/src/main/java/com/android/designcompose/InteractionState.kt +++ b/designcompose/src/main/java/com/android/designcompose/InteractionState.kt @@ -57,34 +57,34 @@ private fun getInstanceIdWithKey(instanceId: String, key: String?): String { internal open class DeferredAction { /// Navigate back, and restore the `overlay_memory`. This is used when a "navigate" /// action has to be undone. - class NavigateBack(val overlayMemory: List) : DeferredAction() {} + class NavigateBack(val overlayMemory: List) : DeferredAction() /// The temporary action was a "swap navigation" (where the top of the navigation /// stack is swapped, rather than being appended to), so we need to swap back to /// the previous entry. We keep a NodeQuery instead of a String, because we could /// be swapping the first entry in the navigation stack which comes from application /// code and is normally a node name (and NodeQuery contains names or IDs). - class SwapNavigation(val nodeQuery: NodeQuery) : DeferredAction() {} + class SwapNavigation(val nodeQuery: NodeQuery) : DeferredAction() /// Close the top-most overlay - class CloseTopOverlay(val transition: Transition?) : DeferredAction() {} + class CloseTopOverlay(val transition: Transition?) : DeferredAction() /// The temporary action was to open an overlay, so we need to close the same overlay - class CloseOverlay(val overlayId: String, val transition: Transition?) : DeferredAction() {} + class CloseOverlay(val overlayId: String, val transition: Transition?) : DeferredAction() /// The temporary action was to close an overlay, so we need to open the overlay /// again to undo the action (and the ID of the overlay to open is the String). - class OpenOverlay(val overlayId: String, val transition: Transition?) : DeferredAction() {} + class OpenOverlay(val overlayId: String, val transition: Transition?) : DeferredAction() /// The temporary action was a "swap overlay", so we need to swap back to the /// previously displayed overlay. - class SwapOverlay(val overlayId: String, val transition: Transition?) : DeferredAction() {} + class SwapOverlay(val overlayId: String, val transition: Transition?) : DeferredAction() /// The temporary action was a "change to" on a component variant. We need to change /// back to the variant we were showing before, which could be the default (in which /// case the value is null), or could be some other specific variant (in which case /// the value will be the node ID). - class ChangeTo(val nodeId: String?) : DeferredAction() {} + class ChangeTo(val nodeId: String?) : DeferredAction() } /// Execute a DeferredAction. An optional key is used to differentiate multiple component instances diff --git a/designcompose/src/main/java/com/android/designcompose/KeyInjectManager.kt b/designcompose/src/main/java/com/android/designcompose/KeyInjectManager.kt index 60af02b16..5e6bcf927 100644 --- a/designcompose/src/main/java/com/android/designcompose/KeyInjectManager.kt +++ b/designcompose/src/main/java/com/android/designcompose/KeyInjectManager.kt @@ -27,8 +27,8 @@ data class DesignKeyEvent(val key: Char, val metaKeys: List) { companion object { // Construct a DesignKeyEvent from a list of javascript key codes fun fromJsKeyCodes(jsKeyCodes: List): DesignKeyEvent { - var metaKeys: ArrayList = arrayListOf() - var key: Char = '0' + val metaKeys: ArrayList = arrayListOf() + var key = '0' jsKeyCodes .map { it.toInt() } .forEach { diff --git a/designcompose/src/main/java/com/android/designcompose/LiveUpdateExceptions.kt b/designcompose/src/main/java/com/android/designcompose/LiveUpdateExceptions.kt index 388083779..bf5cd976b 100644 --- a/designcompose/src/main/java/com/android/designcompose/LiveUpdateExceptions.kt +++ b/designcompose/src/main/java/com/android/designcompose/LiveUpdateExceptions.kt @@ -16,12 +16,12 @@ package com.android.designcompose -open class FetchException() : RuntimeException() +open class FetchException : RuntimeException() class AccessDeniedException : FetchException() -class FigmaFileNotFoundException() : FetchException() +class FigmaFileNotFoundException : FetchException() -class RateLimitedException() : FetchException() +class RateLimitedException : FetchException() -class InternalFigmaErrorException() : FetchException() +class InternalFigmaErrorException : FetchException() diff --git a/designcompose/src/main/java/com/android/designcompose/VariableManager.kt b/designcompose/src/main/java/com/android/designcompose/VariableManager.kt index f66b4924c..dc5808279 100644 --- a/designcompose/src/main/java/com/android/designcompose/VariableManager.kt +++ b/designcompose/src/main/java/com/android/designcompose/VariableManager.kt @@ -171,21 +171,22 @@ internal object VariableManager { internal fun init(docId: DesignDocId, map: VariableMap) { - varMap = varMap.copy { - // Remove old entries for docId - val oldVarMap = docVarMap[docId.id] - oldVarMap?.collectionsMap?.forEach { this.collections.remove(it.key) } - oldVarMap?.collectionNameMapMap?.forEach { this.collectionNameMap.remove(it.key) } - oldVarMap?.variablesMap?.forEach { this.variables.remove(it.key) } - oldVarMap?.variableNameMapMap?.forEach { this.variableNameMap.remove(it.key) } - - // Add new entries for docId - docVarMap[docId.id] = map - this.collections.putAll(map.collectionsMap) - this.collectionNameMap.putAll(map.collectionNameMapMap) - this.variables.putAll(map.variablesMap) - this.variableNameMap.putAll(map.variableNameMapMap) - } + varMap = + varMap.copy { + // Remove old entries for docId + val oldVarMap = docVarMap[docId.id] + oldVarMap?.collectionsMap?.forEach { this.collections.remove(it.key) } + oldVarMap?.collectionNameMapMap?.forEach { this.collectionNameMap.remove(it.key) } + oldVarMap?.variablesMap?.forEach { this.variables.remove(it.key) } + oldVarMap?.variableNameMapMap?.forEach { this.variableNameMap.remove(it.key) } + + // Add new entries for docId + docVarMap[docId.id] = map + this.collections.putAll(map.collectionsMap) + this.collectionNameMap.putAll(map.collectionNameMapMap) + this.variables.putAll(map.variablesMap) + this.variableNameMap.putAll(map.variableNameMapMap) + } currentDocId = docId } diff --git a/designcompose/src/main/java/com/android/designcompose/squoosh/SquooshLayout.kt b/designcompose/src/main/java/com/android/designcompose/squoosh/SquooshLayout.kt index 25c041601..9277e215a 100644 --- a/designcompose/src/main/java/com/android/designcompose/squoosh/SquooshLayout.kt +++ b/designcompose/src/main/java/com/android/designcompose/squoosh/SquooshLayout.kt @@ -246,8 +246,8 @@ private fun updateLayoutTree( if (updateLayoutChildren) layoutParentChildren.add( layoutParentChildren { - layoutId - layoutChildren + this.parentLayoutId = layoutId + this.childLayoutIds.addAll(layoutChildren) } ) diff --git a/designcompose/src/main/java/com/android/designcompose/squoosh/SquooshRender.kt b/designcompose/src/main/java/com/android/designcompose/squoosh/SquooshRender.kt index 0875ba469..627c2a623 100644 --- a/designcompose/src/main/java/com/android/designcompose/squoosh/SquooshRender.kt +++ b/designcompose/src/main/java/com/android/designcompose/squoosh/SquooshRender.kt @@ -103,7 +103,7 @@ internal fun Modifier.squooshRender( fun renderNode(node: SquooshResolvedNode, parentVariableState: VariableState) { // If there is no programmatic mode override and this node has explicitly set // mode values, update variablestate with these values - val variableState = + val newVariableState = if (!hasModeOverride && node.view.explicitVariableModesMap.isNotEmpty()) { val explicitModeValues = node.view.explicitVariableModesMap parentVariableState.copyWithModeValues(explicitModeValues) @@ -134,7 +134,7 @@ internal fun Modifier.squooshRender( computedLayout, customizations, node.view.name, - variableState, + newVariableState, appContext = appContext, ) nodeRenderCount++ @@ -182,7 +182,7 @@ internal fun Modifier.squooshRender( shape, document, customizations, - variableState, + newVariableState, computedPathCache, appContext, ) { @@ -202,7 +202,7 @@ internal fun Modifier.squooshRender( pendingMask.computedLayout!!.left * density, pendingMask.computedLayout!!.top * density, ) { - renderNode(pendingMask!!, variableState) + renderNode(pendingMask!!, newVariableState) } drawContext.canvas.restore() @@ -228,7 +228,7 @@ internal fun Modifier.squooshRender( childLayout.left * density, childLayout.top * density, ) { - renderNode(child!!, variableState) + renderNode(child!!, newVariableState) } } child = child.nextSibling @@ -247,7 +247,7 @@ internal fun Modifier.squooshRender( pendingMask.computedLayout!!.left * density, pendingMask.computedLayout!!.top * density, ) { - renderNode(pendingMask, variableState) + renderNode(pendingMask, newVariableState) } drawContext.canvas.restore() diff --git a/designcompose/src/main/java/com/android/designcompose/squoosh/SquooshText.kt b/designcompose/src/main/java/com/android/designcompose/squoosh/SquooshText.kt index b5aae8f6e..ce6f8d13f 100644 --- a/designcompose/src/main/java/com/android/designcompose/squoosh/SquooshText.kt +++ b/designcompose/src/main/java/com/android/designcompose/squoosh/SquooshText.kt @@ -151,24 +151,23 @@ internal fun squooshComputeTextInfo( for (run in getTextContent(appContext, v.data.styledText)) { val style = run.styleOrNull!! val textBrushAndOpacity = - style.textColorOrNull!! - .asBrush(appContext, document, density.density, variableState) - val fontWeight = - style.fontWeightOrNull!! - .weight - .getValue(variableState) + style.textColorOrNull!!.asBrush( + appContext, + document, + density.density, + variableState, + ) + val fontWeight = style.fontWeightOrNull!!.weight.getValue(variableState) builder.pushStyle( (SpanStyle( brush = textBrushAndOpacity?.first, alpha = textBrushAndOpacity?.second ?: 1.0f, - fontSize = - style.fontSizeOrNull!! - .getValue(variableState) - .sp, + fontSize = style.fontSizeOrNull!!.getValue(variableState).sp, fontWeight = FontWeight(fontWeight.roundToInt()), fontStyle = when (style.fontStyle) { - com.android.designcompose.definition.element.FontStyle.FONT_STYLE_ITALIC -> FontStyle.Italic + com.android.designcompose.definition.element.FontStyle + .FONT_STYLE_ITALIC -> FontStyle.Italic else -> FontStyle.Normal }, fontFamily = @@ -192,7 +191,7 @@ internal fun squooshComputeTextInfo( else -> androidx.compose.ui.text.style.TextDecoration.None }, // platformStyle = PlatformSpanStyle(includeFontPadding = false), - )), + )) ) builder.append(run.text) builder.pop() diff --git a/designcompose/src/main/java/com/android/designcompose/squoosh/SquooshTreeBuilder.kt b/designcompose/src/main/java/com/android/designcompose/squoosh/SquooshTreeBuilder.kt index d8da21ef6..bb809e3f9 100644 --- a/designcompose/src/main/java/com/android/designcompose/squoosh/SquooshTreeBuilder.kt +++ b/designcompose/src/main/java/com/android/designcompose/squoosh/SquooshTreeBuilder.kt @@ -31,6 +31,7 @@ import com.android.designcompose.VariableState import com.android.designcompose.common.NodeQuery import com.android.designcompose.definition.element.ViewShapeKt.box import com.android.designcompose.definition.element.background +import com.android.designcompose.definition.element.color import com.android.designcompose.definition.element.colorOrVar import com.android.designcompose.definition.element.dimensionProto import com.android.designcompose.definition.element.viewShape @@ -164,7 +165,7 @@ internal fun resolveVariantsRecursively( ): SquooshResolvedNode? { if (!customizations.getVisible(viewFromTree.name)) return null customizations.getVisibleState(viewFromTree.name)?.let { if (!it.value) return null } - var componentLayoutId = componentLayoutId + var thisLayoutId = componentLayoutId var parentComps = parentComponents var overrideStyle: ViewStyle? = null var view = viewFromTree @@ -177,11 +178,8 @@ internal fun resolveVariantsRecursively( // Ensure that the children of this component get unique layout ids, even though there // may be multiple instances of the same component in one tree. - componentLayoutId = - computeComponentLayoutId( - componentLayoutId, - layoutIdAllocator.componentLayoutId(parentComps), - ) + thisLayoutId = + computeComponentLayoutId(thisLayoutId, layoutIdAllocator.componentLayoutId(parentComps)) // Do we have an override style? This is style data which we should apply to the final style // even if we're swapping out our view definition for a variant. @@ -197,7 +195,9 @@ internal fun resolveVariantsRecursively( // If we didn't replace the component because of an interaction, we might want to replace it // because of a variant customization. - if (view.name == viewFromTree.name) { // TODO: why we don't check if view == viewFromTree???? + if ( + view.name == viewFromTree.name + ) { // TODO: why we don't check if view == viewFromTree???? // If an interaction has not changed the current variant, then check to see if this node // is part of a component set with variants and if any @DesignVariant annotations // set variant properties that match. If so, variantNodeName will be set to the @@ -249,7 +249,7 @@ internal fun resolveVariantsRecursively( // Now we know the view we want to render, the style we want to use, etc. We can create // a record of it. After this, another pass can be done to build a layout tree. Finally, // layout can be performed and rendering done. - val layoutId = computeLayoutId(componentLayoutId, viewFromTree.uniqueId) + val layoutId = computeLayoutId(thisLayoutId, viewFromTree.uniqueId) layoutIdAllocator.visitLayoutId(layoutId) // XXX-PERF: computeTextInfo is *super* slow. It needs to use a cache between frames. @@ -397,7 +397,7 @@ internal fun resolveVariantsRecursively( textMeasureCache = textMeasureCache, textHash = textHash, customVariantTransition = customVariantTransition, - componentLayoutId = componentLayoutId, + componentLayoutId = thisLayoutId, ) ?: continue childResolvedNode.parent = resolvedView @@ -443,7 +443,7 @@ internal fun resolveVariantsRecursively( textMeasureCache = textMeasureCache, textHash = textHash, customVariantTransition = customVariantTransition, - componentLayoutId = componentLayoutId, + componentLayoutId = thisLayoutId, ) ?: continue // Make a synthetic parent for the overlay. @@ -567,22 +567,26 @@ private fun generateOverlayNode( } } - val newNodeStyle = node.style.nodeStyle.copy { - this.overflow = Overflow.OVERFLOW_VISIBLE - this.backgrounds.clear() - - overlay.overlayBackgroundOrNull?.colorOrNull?.let { - val bgColor = - com.android.designcompose.definition.element.color { - r = (it.r * 255.0).toInt() - g = (it.g * 255.0).toInt() - b = (it.b * 255.0).toInt() - a = (it.a * 255.0).toInt() - } - this.backgrounds.add(background { solid = colorOrVar { color = bgColor } }) + val newNodeStyle = + node.style.nodeStyle.copy { + this.overflow = Overflow.OVERFLOW_VISIBLE + this.backgrounds.clear() + + overlay.overlayBackgroundOrNull?.colorOrNull?.let { + this.backgrounds.add( + background { + solid = colorOrVar { + color = color { + r = (it.r * 255.0).toInt() + g = (it.g * 255.0).toInt() + b = (it.b * 255.0).toInt() + a = (it.a * 255.0).toInt() + } + } + } + ) + } } - } - val overlayStyle = viewStyle { this.layoutStyle = layoutStyleBuilder.build() diff --git a/designcompose/src/main/java/com/android/designcompose/utils/GraphicUtils.kt b/designcompose/src/main/java/com/android/designcompose/utils/GraphicUtils.kt index dd8782e57..59ee24741 100644 --- a/designcompose/src/main/java/com/android/designcompose/utils/GraphicUtils.kt +++ b/designcompose/src/main/java/com/android/designcompose/utils/GraphicUtils.kt @@ -23,7 +23,6 @@ import android.graphics.Matrix import android.graphics.Shader import android.os.Build import android.util.Log -import androidx.annotation.RequiresApi import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.geometry.center @@ -375,7 +374,6 @@ internal fun AffineTransform.asSkiaMatrix(): Matrix { } /** Convert a Background to a Brush, returning a Pair of Brush and Opacity */ -@RequiresApi(Build.VERSION_CODES.N) internal fun Background.asBrush( appContext: Context, document: DocContent, diff --git a/designcompose/src/main/java/com/android/designcompose/utils/LayoutUtils.kt b/designcompose/src/main/java/com/android/designcompose/utils/LayoutUtils.kt index 711ee28f7..17f0db6cd 100644 --- a/designcompose/src/main/java/com/android/designcompose/utils/LayoutUtils.kt +++ b/designcompose/src/main/java/com/android/designcompose/utils/LayoutUtils.kt @@ -16,142 +16,17 @@ package com.android.designcompose.utils -import android.graphics.Rect import androidx.compose.ui.geometry.Size -import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.android.designcompose.LayoutManager import com.android.designcompose.definition.element.DimensionProto import com.android.designcompose.definition.view.ViewStyle -import kotlin.math.roundToInt - -/** Multiply out a dimension against available space */ -internal fun DimensionProto.resolve(available: Int, density: Float): Int? { - if (hasPercent()) { - return (available * percent).roundToInt() - } - if (hasPoints()) { - return (points * density).roundToInt() - } - return null -} internal fun DimensionProto.pointsAsDp(density: Float): Dp { return if (hasPoints()) (points * density).dp else 0.dp } -internal fun DimensionProto.isFixed(): Boolean { - return hasPoints() -} - -/** Evaluate an absolute layout within the given constraints */ -internal fun absoluteLayout(style: ViewStyle, constraints: Constraints, density: Float): Rect { - val pw = - if (constraints.hasBoundedWidth) { - constraints.maxWidth - } else { - 0 - } - val ph = - if (constraints.hasBoundedHeight) { - constraints.maxHeight - } else { - 0 - } - - val left = style.layoutStyle.left.resolve(pw, density) - val top = style.layoutStyle.top.resolve(ph, density) - // Right and bottom are insets from the right/bottom edge, so convert them to be relative to - // the top/left corner. - val right = style.layoutStyle.right.resolve(pw, density)?.let { r -> pw - r } - val bottom = style.layoutStyle.bottom.resolve(ph, density)?.let { b -> ph - b } - val width = style.layoutStyle.width.resolve(pw, density) - val height = style.layoutStyle.height.resolve(ph, density) - // We use the top and left margins for center anchored items, so they can be safely applied - // as an offset here. - val leftMargin = style.layoutStyle.margin.start.resolve(pw, density) ?: 0 - val topMargin = style.layoutStyle.margin.end.resolve(ph, density) ?: 0 - - // XXX: Need layoutDirection; when left, right and width are specified we use left and - // width in LtoR direction, and use right and width in RtoL direction. - val x = - leftMargin + - (left - ?: if (right != null && width != null) { - right - width - } else { - 0 - }) - val y = - topMargin + - (top - ?: if (bottom != null && height != null) { - bottom - height - } else { - 0 - }) - var w = - width - ?: if (left != null && right != null) { - right - left - } else { - 0 - } - var h = - height - ?: if (top != null && bottom != null) { - bottom - top - } else { - 0 - } - - val minWidth = style.layoutStyle.minWidth.resolve(pw, density) - val minHeight = style.layoutStyle.minHeight.resolve(ph, density) - if (minWidth != null && w < minWidth) { - w = minWidth - } - if (minHeight != null && h < minHeight) { - h = minHeight - } - - return Rect(x, y, x + w, y + h) -} - -/** Evaluate a relative layout against the given constraints */ -internal fun relativeLayout(style: ViewStyle, constraints: Constraints, density: Float): Rect { - val pw = - if (constraints.hasBoundedWidth) { - constraints.maxWidth - } else { - 0 - } - val ph = - if (constraints.hasBoundedHeight) { - constraints.maxHeight - } else { - 0 - } - - var w = style.layoutStyle.width.resolve(pw, density) ?: 0 - var h = style.layoutStyle.height.resolve(ph, density) ?: 0 - // We use the top and left margins for center anchored items, so they can be safely applied - // as an offset here. - val x = style.layoutStyle.margin.start.resolve(pw, density) ?: 0 - val y = style.layoutStyle.margin.top.resolve(ph, density) ?: 0 - - val minWidth = style.layoutStyle.minWidth.resolve(pw, density) - val minHeight = style.layoutStyle.minHeight.resolve(ph, density) - if (minWidth != null && w < minWidth) { - w = minWidth - } - if (minHeight != null && h < minHeight) { - h = minHeight - } - - return Rect(x, y, x + w, y + h) -} - // Return the size of a node used to render the node. internal fun getNodeRenderSize( overrideSize: Size?, diff --git a/designcompose/src/main/java/com/android/designcompose/utils/ViewStyleUtils.kt b/designcompose/src/main/java/com/android/designcompose/utils/ViewStyleUtils.kt index 61f45ce57..3c11654b3 100644 --- a/designcompose/src/main/java/com/android/designcompose/utils/ViewStyleUtils.kt +++ b/designcompose/src/main/java/com/android/designcompose/utils/ViewStyleUtils.kt @@ -206,14 +206,9 @@ internal fun mergeStyles(base: ViewStyle, override: ViewStyle): ViewStyle { if (override.nodeStyle.fontFeaturesCount > 0) override.nodeStyle.fontFeaturesList else base.nodeStyle.fontFeaturesList ) - filters.addAll( - if (override.nodeStyle.filtersList.isNotEmpty()) override.nodeStyle.filtersList - else base.nodeStyle.filtersList - ) + filters.addAll(override.nodeStyle.filtersList.ifEmpty { base.nodeStyle.filtersList }) backdropFilters.addAll( - if (override.nodeStyle.backdropFiltersList.isNotEmpty()) - override.nodeStyle.backdropFiltersList - else base.nodeStyle.backdropFiltersList + override.nodeStyle.backdropFiltersList.ifEmpty { base.nodeStyle.backdropFiltersList } ) blendMode = if ( @@ -267,11 +262,7 @@ internal fun mergeStyles(base: ViewStyle, override: ViewStyle): ViewStyle { base.nodeStyle.gridAdaptiveMinSize } gridSpanContents.addAll( - if (override.nodeStyle.gridSpanContentsList.isNotEmpty()) { - override.nodeStyle.gridSpanContentsList - } else { - base.nodeStyle.gridSpanContentsList - } + override.nodeStyle.gridSpanContentsList.ifEmpty { base.nodeStyle.gridSpanContentsList } ) overflow = if ( diff --git a/integration-tests/validation/src/main/java/com/android/designcompose/testapp/validation/examples/AllExamples.kt b/integration-tests/validation/src/main/java/com/android/designcompose/testapp/validation/examples/AllExamples.kt index cb963b87e..c37120837 100644 --- a/integration-tests/validation/src/main/java/com/android/designcompose/testapp/validation/examples/AllExamples.kt +++ b/integration-tests/validation/src/main/java/com/android/designcompose/testapp/validation/examples/AllExamples.kt @@ -133,13 +133,10 @@ val EXAMPLES: ArrayList Unit, String?>> = // Animations Triple("SA", { SmartAnimateTest() }, SmartAnimateTestDoc.javaClass.name), Triple("SA Variant", { VariantAnimationTest() }, VariantAnimationTestDoc.javaClass.name), - /** Temporarily disabled: GH-1945 - Triple( - "SA Variant Timelines", - { VariantAnimationTimelineTest() }, - VariantAnimationTimelineTestDoc.javaClass.name, - ), - */ + /** + * Temporarily disabled: GH-1945 Triple( "SA Variant Timelines", { + * VariantAnimationTimelineTest() }, VariantAnimationTimelineTestDoc.javaClass.name, ), + */ // No support for hyperlinks in squoosh. Triple("Hyperlink", { HyperlinkTest() }, HyperlinkValidationDoc.javaClass.name), // GH-636: Test takes too long to execute. diff --git a/integration-tests/validation/src/main/java/com/android/designcompose/testapp/validation/examples/VariantAnimationTimelineTest.kt b/integration-tests/validation/src/main/java/com/android/designcompose/testapp/validation/examples/VariantAnimationTimelineTest.kt index 9fc82e3f5..a842d74f6 100644 --- a/integration-tests/validation/src/main/java/com/android/designcompose/testapp/validation/examples/VariantAnimationTimelineTest.kt +++ b/integration-tests/validation/src/main/java/com/android/designcompose/testapp/validation/examples/VariantAnimationTimelineTest.kt @@ -15,203 +15,85 @@ */ package com.android.designcompose.testapp.validation.examples - -import androidx.compose.animation.core.CubicBezierEasing -import androidx.compose.animation.core.tween -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.absoluteOffset -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import com.android.designcompose.DesignDocSettings -import com.android.designcompose.LocalDesignDocSettings -import com.android.designcompose.annotation.DesignComponent -import com.android.designcompose.annotation.DesignDoc -import com.android.designcompose.annotation.DesignVariant -import com.android.designcompose.squoosh.SmartAnimateTransition -import kotlin.math.roundToInt - -enum class AnimType { - Normal, // Everything animates immediately over 1 second - OneByOne, // Each square has a different delay so they animate one by one - DifferentDurations, // Each square has a different duration so they end at different times -} - -enum class ChildAnimType { - Normal, // Child animates with parent - Early, // Child animates before parent, if parent has delay - Late, // Child animates after parent -} - -enum class SceneState { - CenterAll, - BeforeWelcome, - Open, - Closed, -} - -/** Temporarily disabled: GH-1945 - -@DesignDoc(id = "vJRf4zxY4QX4zzSSUd1nJ5") -interface VariantAnimationTimelineTest { - @DesignComponent(node = "root/display_1") - fun Main(@DesignVariant(property = "SceneState") sceneState: SceneState) -} - -@Composable -fun VariantAnimationTimelineTest() { - val animType = remember { mutableStateOf(AnimType.Normal) } - val childAnimType = remember { mutableStateOf(ChildAnimType.Normal) } - val sceneState = remember { mutableStateOf(SceneState.Closed) } - val tNumRegex = Regex("T([1-8])") - - CompositionLocalProvider( - LocalDesignDocSettings provides - DesignDocSettings( - customVariantTransition = { context -> - val defaultEasing = CubicBezierEasing(0.37f, 0f, 0.63f, 1f) - val regexMatch = tNumRegex.find(context.from?.name ?: "") - val tNum = regexMatch?.let { it.groupValues[1].toInt() } - if ( - context.from?.name == "T3Rect" && - childAnimType.value != ChildAnimType.Normal - ) { - val delayMillis = - if (childAnimType.value == ChildAnimType.Early) 0 else 1500 - SmartAnimateTransition( - tween(durationMillis = 500, easing = defaultEasing), - delayMillis, - ) - } else if (tNum != null) { - val durationMillis = - when (animType.value) { - AnimType.Normal -> 1000 - AnimType.OneByOne -> 500 - AnimType.DifferentDurations -> (0.25f * 1000f * tNum).roundToInt() - } - val delayMillis = - when (animType.value) { - AnimType.Normal -> 0 - AnimType.OneByOne -> (0.25f * 1000f * tNum).roundToInt() - AnimType.DifferentDurations -> 0 - } - SmartAnimateTransition( - tween(durationMillis = durationMillis, easing = defaultEasing), - delayMillis, - ) - } else { - SmartAnimateTransition( - tween( - durationMillis = (1f * 1000.0).roundToInt(), - easing = defaultEasing, - ), - 0, - ) - } - } - ) - ) { - VariantAnimationTimelineTestDoc.Main(sceneState = sceneState.value) - } - - Column(Modifier.absoluteOffset(y = 750.dp)) { - Row( - horizontalArrangement = Arrangement.spacedBy(10.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - Text("Animation Type:", fontSize = 30.sp, color = Color.Black) - com.android.designcompose.testapp.validation.TestButton( - name = "Normal", - tag = "Normal", - selected = animType.value == AnimType.Normal, - ) { - animType.value = AnimType.Normal - } - com.android.designcompose.testapp.validation.TestButton( - name = "OneByOne", - tag = "OneByOne", - selected = animType.value == AnimType.OneByOne, - ) { - animType.value = AnimType.OneByOne - } - com.android.designcompose.testapp.validation.TestButton( - name = "DifferentDurations", - tag = "DifferentDurations", - selected = animType.value == AnimType.DifferentDurations, - ) { - animType.value = AnimType.DifferentDurations - } - } - Row( - horizontalArrangement = Arrangement.spacedBy(10.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - Text("Child Animation Type:", fontSize = 30.sp, color = Color.Black) - com.android.designcompose.testapp.validation.TestButton( - name = "Normal", - tag = "ChildNormal", - selected = childAnimType.value == ChildAnimType.Normal, - ) { - childAnimType.value = ChildAnimType.Normal - } - com.android.designcompose.testapp.validation.TestButton( - name = "Early", - tag = "ChildEarly", - selected = childAnimType.value == ChildAnimType.Early, - ) { - childAnimType.value = ChildAnimType.Early - } - com.android.designcompose.testapp.validation.TestButton( - name = "Late", - tag = "ChildLate", - selected = childAnimType.value == ChildAnimType.Late, - ) { - childAnimType.value = ChildAnimType.Late - } - } - Row( - horizontalArrangement = Arrangement.spacedBy(10.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - Text("Variant:", fontSize = 30.sp, color = Color.Black) - com.android.designcompose.testapp.validation.TestButton( - name = "Columns", - tag = "Columns", - selected = sceneState.value == SceneState.Closed, - ) { - sceneState.value = SceneState.Closed - } - com.android.designcompose.testapp.validation.TestButton( - name = "Spread", - tag = "Spread", - selected = sceneState.value == SceneState.BeforeWelcome, - ) { - sceneState.value = SceneState.BeforeWelcome - } - com.android.designcompose.testapp.validation.TestButton( - name = "Center", - tag = "Center", - selected = sceneState.value == SceneState.CenterAll, - ) { - sceneState.value = SceneState.CenterAll - } - com.android.designcompose.testapp.validation.TestButton( - name = "Cluster", - tag = "Cluster", - selected = sceneState.value == SceneState.Open, - ) { - sceneState.value = SceneState.Open - } - } - } -} -*/ +/** + * Temporarily disabled: GH-1945 + * + * import androidx.compose.animation.core.CubicBezierEasing import + * androidx.compose.animation.core.tween import androidx.compose.foundation.layout.Arrangement + * import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row + * import androidx.compose.foundation.layout.absoluteOffset import androidx.compose.material.Text + * import androidx.compose.runtime.Composable import + * androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.mutableStateOf + * import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import + * androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import + * androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import + * com.android.designcompose.DesignDocSettings import + * com.android.designcompose.LocalDesignDocSettings import + * com.android.designcompose.annotation.DesignComponent import + * com.android.designcompose.annotation.DesignDoc import + * com.android.designcompose.annotation.DesignVariant import + * com.android.designcompose.squoosh.SmartAnimateTransition import kotlin.math.roundToInt + * + * enum class AnimType { Normal, // Everything animates immediately over 1 second OneByOne, // Each + * square has a different delay so they animate one by one DifferentDurations, // Each square has a + * different duration so they end at different times } + * + * enum class ChildAnimType { Normal, // Child animates with parent Early, // Child animates before + * parent, if parent has delay Late, // Child animates after parent } + * + * enum class SceneState { CenterAll, BeforeWelcome, Open, Closed, } + * + * @DesignDoc(id = "vJRf4zxY4QX4zzSSUd1nJ5") interface VariantAnimationTimelineTest { + * @DesignComponent(node = "root/display_1") fun Main(@DesignVariant(property = "SceneState") + * sceneState: SceneState) } + * @Composable fun VariantAnimationTimelineTest() { val animType = remember { + * mutableStateOf(AnimType.Normal) } val childAnimType = remember { + * mutableStateOf(ChildAnimType.Normal) } val sceneState = remember { + * mutableStateOf(SceneState.Closed) } val tNumRegex = Regex("T([1-8])") + * + * CompositionLocalProvider( LocalDesignDocSettings provides DesignDocSettings( + * customVariantTransition = { context -> val defaultEasing = CubicBezierEasing(0.37f, 0f, 0.63f, + * 1f) val regexMatch = tNumRegex.find(context.from?.name ?: "") val tNum = regexMatch?.let { + * it.groupValues[1].toInt() } if ( context.from?.name == "T3Rect" && childAnimType.value != + * ChildAnimType.Normal ) { val delayMillis = if (childAnimType.value == ChildAnimType.Early) 0 else + * 1500 SmartAnimateTransition( tween(durationMillis = 500, easing = defaultEasing), delayMillis, ) + * } else if (tNum != null) { val durationMillis = when (animType.value) { AnimType.Normal -> 1000 + * AnimType.OneByOne -> 500 AnimType.DifferentDurations -> (0.25f * 1000f * tNum).roundToInt() } val + * delayMillis = when (animType.value) { AnimType.Normal -> 0 AnimType.OneByOne -> (0.25f * 1000f * + * tNum).roundToInt() AnimType.DifferentDurations -> 0 } SmartAnimateTransition( + * tween(durationMillis = durationMillis, easing = defaultEasing), delayMillis, ) } else { + * SmartAnimateTransition( tween( durationMillis = (1f * 1000.0).roundToInt(), easing = + * defaultEasing, ), 0, ) } } ) ) { VariantAnimationTimelineTestDoc.Main(sceneState = + * sceneState.value) } + * + * Column(Modifier.absoluteOffset(y = 750.dp)) { Row( horizontalArrangement = + * Arrangement.spacedBy(10.dp), verticalAlignment = Alignment.CenterVertically, ) { Text("Animation + * Type:", fontSize = 30.sp, color = Color.Black) + * com.android.designcompose.testapp.validation.TestButton( name = "Normal", tag = "Normal", + * selected = animType.value == AnimType.Normal, ) { animType.value = AnimType.Normal } + * com.android.designcompose.testapp.validation.TestButton( name = "OneByOne", tag = "OneByOne", + * selected = animType.value == AnimType.OneByOne, ) { animType.value = AnimType.OneByOne } + * com.android.designcompose.testapp.validation.TestButton( name = "DifferentDurations", tag = + * "DifferentDurations", selected = animType.value == AnimType.DifferentDurations, ) { + * animType.value = AnimType.DifferentDurations } } Row( horizontalArrangement = + * Arrangement.spacedBy(10.dp), verticalAlignment = Alignment.CenterVertically, ) { Text("Child + * Animation Type:", fontSize = 30.sp, color = Color.Black) + * com.android.designcompose.testapp.validation.TestButton( name = "Normal", tag = "ChildNormal", + * selected = childAnimType.value == ChildAnimType.Normal, ) { childAnimType.value = + * ChildAnimType.Normal } com.android.designcompose.testapp.validation.TestButton( name = "Early", + * tag = "ChildEarly", selected = childAnimType.value == ChildAnimType.Early, ) { + * childAnimType.value = ChildAnimType.Early } + * com.android.designcompose.testapp.validation.TestButton( name = "Late", tag = "ChildLate", + * selected = childAnimType.value == ChildAnimType.Late, ) { childAnimType.value = + * ChildAnimType.Late } } Row( horizontalArrangement = Arrangement.spacedBy(10.dp), + * verticalAlignment = Alignment.CenterVertically, ) { Text("Variant:", fontSize = 30.sp, color = + * Color.Black) com.android.designcompose.testapp.validation.TestButton( name = "Columns", tag = + * "Columns", selected = sceneState.value == SceneState.Closed, ) { sceneState.value = + * SceneState.Closed } com.android.designcompose.testapp.validation.TestButton( name = "Spread", tag + * = "Spread", selected = sceneState.value == SceneState.BeforeWelcome, ) { sceneState.value = + * SceneState.BeforeWelcome } com.android.designcompose.testapp.validation.TestButton( name = + * "Center", tag = "Center", selected = sceneState.value == SceneState.CenterAll, ) { + * sceneState.value = SceneState.CenterAll } + * com.android.designcompose.testapp.validation.TestButton( name = "Cluster", tag = "Cluster", + * selected = sceneState.value == SceneState.Open, ) { sceneState.value = SceneState.Open } } } } + */ diff --git a/integration-tests/validation/src/testDebug/kotlin/com/android/designcompose/testapp/validation/AnimationTimelines.kt b/integration-tests/validation/src/testDebug/kotlin/com/android/designcompose/testapp/validation/AnimationTimelines.kt index 5c7fdaca9..0ef4d692f 100644 --- a/integration-tests/validation/src/testDebug/kotlin/com/android/designcompose/testapp/validation/AnimationTimelines.kt +++ b/integration-tests/validation/src/testDebug/kotlin/com/android/designcompose/testapp/validation/AnimationTimelines.kt @@ -15,98 +15,78 @@ */ package com.android.designcompose.testapp.validation -/** Temporarily disabled: GH-1945 - -import androidx.activity.ComponentActivity -import androidx.compose.ui.test.junit4.createAndroidComposeRule -import androidx.compose.ui.test.onNodeWithTag -import androidx.compose.ui.test.performClick -import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.android.designcompose.TestUtils -import com.android.designcompose.test.internal.captureRootRoboImage -import com.android.designcompose.test.internal.designComposeRoborazziRule -import com.android.designcompose.test.waitForContent -import com.android.designcompose.testapp.common.InterFontTestRule -import com.android.designcompose.testapp.validation.examples.VariantAnimationTimelineTest -import com.android.designcompose.testapp.validation.examples.VariantAnimationTimelineTestDoc -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.annotation.Config -import org.robolectric.annotation.GraphicsMode - -@RunWith(AndroidJUnit4::class) -@GraphicsMode(GraphicsMode.Mode.NATIVE) -@Config(qualifiers = "w1920dp-h1500dp-xlarge-long-notround-any-xhdpi-keyshidden-nonav") -class AnimationTimelines { - @get:Rule val clearStateTestRule = TestUtils.ClearStateTestRule() - @get:Rule val composeTestRule = createAndroidComposeRule() - @get:Rule val roborazziRule = designComposeRoborazziRule(javaClass.simpleName) - @get:Rule val interFontRule = InterFontTestRule() - - @Test - fun oneByOne() { - // Because we're testing animation, we will manually advance the animation clock. - composeTestRule.mainClock.autoAdvance = false - - composeTestRule.setContent { VariantAnimationTimelineTest() } - - composeTestRule.waitForContent(VariantAnimationTimelineTestDoc.javaClass.name) - - composeTestRule.onNodeWithTag("OneByOne").performClick() - composeTestRule.onNodeWithTag("Spread").performClick() - - recordAnimation("OneByOne") - } - - @Test - fun differentDurations() { - // Because we're testing animation, we will manually advance the animation clock. - composeTestRule.mainClock.autoAdvance = false - - composeTestRule.setContent { VariantAnimationTimelineTest() } - - composeTestRule.waitForContent(VariantAnimationTimelineTestDoc.javaClass.name) - - composeTestRule.onNodeWithTag("DifferentDurations").performClick() - composeTestRule.onNodeWithTag("Spread").performClick() - - recordAnimation("DifferentDurations") - } - - @Test - fun childCustomAnim() { - // Because we're testing animation, we will manually advance the animation clock. - composeTestRule.mainClock.autoAdvance = false - - composeTestRule.setContent { VariantAnimationTimelineTest() } - - composeTestRule.waitForContent(VariantAnimationTimelineTestDoc.javaClass.name) - - composeTestRule.onNodeWithTag("OneByOne").performClick() - composeTestRule.onNodeWithTag("ChildEarly").performClick() - composeTestRule.onNodeWithTag("Spread").performClick() - - recordAnimation("ChildCustomAnim") - } - - private fun recordAnimation(name: String) { - // We need to both "advanceTimeByFrame" and then "waitForIdle" to capture the output after - // recomposition. - composeTestRule.mainClock.advanceTimeByFrame() - composeTestRule.waitForIdle() - - composeTestRule.captureRootRoboImage("${name}Animation-Start") - - composeTestRule.mainClock.advanceTimeByFrame() - composeTestRule.mainClock.advanceTimeBy(1000L) - composeTestRule.waitForIdle() - - composeTestRule.captureRootRoboImage("${name}Animation-MidPoint") - - composeTestRule.mainClock.advanceTimeBy(2000L) - composeTestRule.waitForIdle() - composeTestRule.captureRootRoboImage("${name}Animation-End") - } -} -*/ +/** + * Temporarily disabled: GH-1945 + * + * import androidx.activity.ComponentActivity import + * androidx.compose.ui.test.junit4.createAndroidComposeRule import + * androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.performClick import + * androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.designcompose.TestUtils import + * com.android.designcompose.test.internal.captureRootRoboImage import + * com.android.designcompose.test.internal.designComposeRoborazziRule import + * com.android.designcompose.test.waitForContent import + * com.android.designcompose.testapp.common.InterFontTestRule import + * com.android.designcompose.testapp.validation.examples.VariantAnimationTimelineTest import + * com.android.designcompose.testapp.validation.examples.VariantAnimationTimelineTestDoc import + * org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import + * org.robolectric.annotation.Config import org.robolectric.annotation.GraphicsMode + * + * @RunWith(AndroidJUnit4::class) + * @GraphicsMode(GraphicsMode.Mode.NATIVE) + * @Config(qualifiers = "w1920dp-h1500dp-xlarge-long-notround-any-xhdpi-keyshidden-nonav") class + * AnimationTimelines { @get:Rule val clearStateTestRule = + * TestUtils.ClearStateTestRule() @get:Rule val composeTestRule = + * createAndroidComposeRule() @get:Rule val roborazziRule = + * designComposeRoborazziRule(javaClass.simpleName) @get:Rule val interFontRule = + * InterFontTestRule() + * @Test fun oneByOne() { // Because we're testing animation, we will manually advance the animation + * clock. composeTestRule.mainClock.autoAdvance = false + * + * composeTestRule.setContent { VariantAnimationTimelineTest() } + * + * composeTestRule.waitForContent(VariantAnimationTimelineTestDoc.javaClass.name) + * + * composeTestRule.onNodeWithTag("OneByOne").performClick() + * composeTestRule.onNodeWithTag("Spread").performClick() + * + * recordAnimation("OneByOne") } + * + * @Test fun differentDurations() { // Because we're testing animation, we will manually advance the + * animation clock. composeTestRule.mainClock.autoAdvance = false + * + * composeTestRule.setContent { VariantAnimationTimelineTest() } + * + * composeTestRule.waitForContent(VariantAnimationTimelineTestDoc.javaClass.name) + * + * composeTestRule.onNodeWithTag("DifferentDurations").performClick() + * composeTestRule.onNodeWithTag("Spread").performClick() + * + * recordAnimation("DifferentDurations") } + * + * @Test fun childCustomAnim() { // Because we're testing animation, we will manually advance the + * animation clock. composeTestRule.mainClock.autoAdvance = false + * + * composeTestRule.setContent { VariantAnimationTimelineTest() } + * + * composeTestRule.waitForContent(VariantAnimationTimelineTestDoc.javaClass.name) + * + * composeTestRule.onNodeWithTag("OneByOne").performClick() + * composeTestRule.onNodeWithTag("ChildEarly").performClick() + * composeTestRule.onNodeWithTag("Spread").performClick() + * + * recordAnimation("ChildCustomAnim") } + * + * private fun recordAnimation(name: String) { // We need to both "advanceTimeByFrame" and then + * "waitForIdle" to capture the output after // recomposition. + * composeTestRule.mainClock.advanceTimeByFrame() composeTestRule.waitForIdle() + * + * composeTestRule.captureRootRoboImage("${name}Animation-Start") + * + * composeTestRule.mainClock.advanceTimeByFrame() composeTestRule.mainClock.advanceTimeBy(1000L) + * composeTestRule.waitForIdle() + * + * composeTestRule.captureRootRoboImage("${name}Animation-MidPoint") + * + * composeTestRule.mainClock.advanceTimeBy(2000L) composeTestRule.waitForIdle() + * composeTestRule.captureRootRoboImage("${name}Animation-End") } } + */ diff --git a/reference-apps/tutorial/app/src/main/assets/figma/TutorialDoc_3z4xExq0INrL9vxPhj9tl7.dcf b/reference-apps/tutorial/app/src/main/assets/figma/TutorialDoc_3z4xExq0INrL9vxPhj9tl7.dcf index 75f61d5cb520c482c676239b6b5e0afd3e2bdf5c..1a2f475cf45a078b9c537357fd40b9e6d5b61fb5 100644 GIT binary patch delta 801 zcmZ9JJxo(!6o!32xp2MZr(6pCp-2HOSm=LyZK7ICd7Xfpo(SE5=UIW5!MiYXior*-r#}OJG8NUca_MD-q#GGXr<&`!G6R=} z<)sR-oFb!6pn`_RY8Z@k|F()S(b}E&c`(z9iA9*D?@p;iJBw$Al8J08?UUD?V$ITU z9H`~}iE4U_35Gh&W1r@+f6K$ZP4Ixx z%#ERlu39coe7;gvY=;(`E!HoxT7BX?5ftpiuXXDw28N{Yrt!84H>G}FUK2XvADvK3lZ84ju0jzW;Xied}b zx7SfF`ih}dJ?1cP3X)#SaPV3#wf*)NK`bLr@FHNK2g($9+~vSA%DBz|F|FG+t=smk zZVeV$+9`G0AQrk5`)o!XZ94Y2*1*hC-j>`+I$L(pDS@ KhyQHV?)nXXu;n`d delta 759 zcmY+?Ur3Wt7zXg3qsy;lo6djxrsj11$?0@{+rIoZOU;>PAfY(|lWI6baT7%e9GPaW z1fk?ybRl?Scq{pKDM&Y6lu=!HQ4j{M2)YdFCaI4dg}OUD=fL~$d(YMq+gf6ed#%4* zMsw^|G~#!3ObicRnv6sh%f3s>r($adP_R5(Ligo)1}jNLy?{*Di~9f@&80Um6s{%h z3`O*%ED03TtMVF#)AX})m7#>>**U;YD|7FGQi{$WfPbx%3-p1e{|8!NY$70QH+)`+%F0mz@j^WbWQzP-y##KFdR`J?{W7 zjST$;H-%)rGUG%uy`1R*T11~#(dR;{kIi^sFlLD|;nAr`cxrNTEN1y;klN^Z{3Z~j zygLc-KXn1LQ=tASaFIT{=tpTc@#)=%(C(`(0OA*CFZXjK#8ieX`p_-9Wl~SrFbk$16 zABL-OmYch6v=iv;eKXu#JAG|{>`1e_yN<0Ifa zt!m2#{vtC6Wwe{=0vwcPDrG3AiY)yfRZu+pLpmy{FMmT{S;Ed)!pc7`