Skip to content

Commit

Permalink
Fix bug with placement of variants
Browse files Browse the repository at this point in the history
Variants that changed due to customizations were being rendered at 0, 0 when positioned absolutely. Fix this by moving variant resolution from DesignFrame into DesignView, finding the correct variant view to render, and calling DesignFrame with it in the same way that we call DesignFrame when an interaction has changed the variant. This passes the base variant view as well, which is used during layout subscription to keep the new variant at the same location as the base variant.
  • Loading branch information
rylin8 committed Sep 26, 2023
1 parent 9000576 commit 64caa2b
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import com.android.designcompose.serdegen.ComponentInfo
import com.android.designcompose.serdegen.GridLayoutType
import com.android.designcompose.serdegen.GridSpan
import com.android.designcompose.serdegen.ItemSpacing
Expand All @@ -53,21 +52,18 @@ import com.android.designcompose.serdegen.View
import com.android.designcompose.serdegen.ViewData
import com.android.designcompose.serdegen.ViewShape
import com.android.designcompose.serdegen.ViewStyle
import java.util.Optional

@Composable
internal fun DesignFrame(
modifier: Modifier = Modifier,
view: View,
baseVariantView: View?,
style: ViewStyle,
variantParentName: String,
layoutInfo: SimplifiedLayoutInfo,
document: DocContent,
customizations: CustomizationContext,
parentLayout: ParentLayoutInfo?,
layoutId: Int,
componentInfo: Optional<ComponentInfo>,
parentComponents: List<ParentComponentInfo>,
maskInfo: MaskInfo?,
content: @Composable () -> Unit,
Expand Down Expand Up @@ -132,17 +128,13 @@ internal fun DesignFrame(
}
}

// 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
// name of the node with all the variants set to the @DesignVariant parameters
val variantNodeName = customizations.getMatchingVariant(componentInfo)
// Check for a customization that replaces this component completely
val replacementComponent = customizations.getComponent(name)
var m = Modifier as Modifier

// Only render the frame if we don't have a custom variant node that we are about to
// render instead
// Only render the frame if we don't have a replacement node
val shape = (view.data as ViewData.Container).shape
if (variantNodeName.isNullOrEmpty() && replacementComponent == null)
if (replacementComponent == null)
m = m.frameRender(style, shape, customImage, document, name, customizations, maskInfo)
m = m.then(modifier)
val customModifier = customizations.getModifier(name)
Expand All @@ -169,23 +161,6 @@ internal fun DesignFrame(
return true
}

// If we a custom variant, compose it instead and then return.
if (variantNodeName != null) {
// Get the generated CustomVariantComponent() function and call it with variantNodeName
val customComposable = customizations.getCustomComposable()
if (customComposable != null) {
val tapCallback = customizations.getTapCallback(name)
customComposable(
layoutInfo.selfModifier.then(m),
variantNodeName,
NodeQuery.NodeVariant(variantNodeName, variantParentName.ifEmpty { name }),
parentComponents,
tapCallback
)
return true
}
}

val lazyContent = customizations.getListContent(name)

// Select the appropriate representation for ourselves based on our layout style;
Expand Down Expand Up @@ -584,19 +559,18 @@ internal fun DesignFrame(
}
}
is LayoutInfoAbsolute -> {
println("### DesignFrame $name layoutId $layoutId isWidgetChild ${parentLayout?.isWidgetChild}")
println(
"### DesignFrame $name layoutId $layoutId isWidgetChild ${parentLayout?.isWidgetChild}"
)

if (parentLayout?.isWidgetChild == true) {
// For direct children of a widget, render the frame as a box with the calculated
// layout size, then compose the frame's children with our custom layout
val layout = LayoutManager.getLayout(layoutId)
Box(m.layoutSizeToModifier(layout)) {
DesignFrameLayout(modifier, name, layoutId, layoutState) {
content()
}
DesignFrameLayout(modifier, name, layoutId, layoutState) { content() }
}
}
else {
} else {
// Otherwise, use our custom layout to render the frame and to place its children
m = m.then(Modifier.layoutStyle(name, layoutId))
DesignFrameLayout(m, name, layoutId, layoutState) {
Expand Down
52 changes: 35 additions & 17 deletions designcompose/src/main/java/com/android/designcompose/DesignView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ import com.android.designcompose.serdegen.Trigger
import com.android.designcompose.serdegen.View
import com.android.designcompose.serdegen.ViewData
import com.android.designcompose.serdegen.ViewStyle
import java.util.Optional
import kotlin.math.min
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
Expand Down Expand Up @@ -358,8 +357,31 @@ internal fun DesignView(
}

// See if we've got a replacement node from an interaction
val view = interactionState.nodeVariant(v.id, customizations.getKey(), document) ?: v
val hasVariantReplacement = view.name != v.name
var view = interactionState.nodeVariant(v.id, customizations.getKey(), document) ?: v
var hasVariantReplacement = view.name != v.name
var variantParentName = variantParentName
if (!hasVariantReplacement) {
// 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
// name of the node with all the variants set to the @DesignVariant parameters
var variantNodeName = customizations.getMatchingVariant(view.component_info)
if (variantNodeName != null) {
// Find the view associated with the variant name
val variantNodeQuery =
NodeQuery.NodeVariant(variantNodeName, variantParentName.ifEmpty { view.name })
val isRoot = LocalDesignIsRootContext.current.isRoot
val variantView = interactionState.rootNode(variantNodeQuery, document, isRoot)
if (variantView != null) {
view = variantView
hasVariantReplacement = true
variantView.component_info.ifPresent {
variantParentName = it.component_set_name
}
}
}
}

var m = Modifier as Modifier

// Use the recompose highlighter to show what is being recomposed, if the design switcher
Expand Down Expand Up @@ -670,17 +692,11 @@ internal fun DesignView(
view,
if (hasVariantReplacement) v else null,
style,
variantParentName,
viewLayoutInfo,
document,
customizations,
parentLayout,
layoutId,
// Check to see whether an interaction has changed the current variant. If it did,
// then
// we ignore any variant properties set from @DesignVariant annotations by passing
// Optional.empty into DesignFrame's componentInfo parameter.
if (hasVariantReplacement) Optional.empty() else view.component_info,
parentComponents,
MaskInfo(parentSize, maskViewType),
) {
Expand Down Expand Up @@ -953,10 +969,11 @@ internal fun DesignDocInternal(
CompositionLocalProvider(LocalDesignIsRootContext provides DesignIsRoot(false)) {
// Whenever the root view changes, call newDoc() so that we defer layout calculation
// until all views have been added
if (isRoot) DisposableEffect(startFrame) {
LayoutManager.newDoc()
onDispose { }
}
if (isRoot)
DisposableEffect(startFrame) {
LayoutManager.newDoc()
onDispose {}
}

DesignView(
modifier,
Expand Down Expand Up @@ -999,10 +1016,11 @@ internal fun DesignDocInternal(

// For root views, tell the layout manager that it is done loading after all
// child composables have been called so that it can trigger a layout compute.
if (isRoot) DisposableEffect(startFrame) {
LayoutManager.docLoaded()
onDispose { }
}
if (isRoot)
DisposableEffect(startFrame) {
LayoutManager.docLoaded()
onDispose {}
}
}

return
Expand Down
13 changes: 5 additions & 8 deletions designcompose/src/main/java/com/android/designcompose/Layout.kt
Original file line number Diff line number Diff line change
Expand Up @@ -513,8 +513,11 @@ internal fun Modifier.layoutStyle(name: String, layoutId: Int) =
this.then(DesignLayoutData(name, layoutId))

internal fun Layout.width() = this.width.roundToInt()

internal fun Layout.height() = this.height.roundToInt()

internal fun Layout.left() = this.left.roundToInt()

internal fun Layout.top() = this.top.roundToInt()

// Layout function for DesignFrame
Expand All @@ -533,10 +536,7 @@ internal inline fun DesignFrameLayout(
// Measure policy for DesignFrame.
internal fun designMeasurePolicy(name: String, layoutId: Int) =
MeasurePolicy { measurables, constraints ->
val placeables =
measurables.map { measurable ->
measurable.measure(constraints)
}
val placeables = measurables.map { measurable -> measurable.measure(constraints) }

var myLayout = LayoutManager.getLayout(layoutId)
if (myLayout == null) {
Expand All @@ -559,10 +559,7 @@ internal fun designMeasurePolicy(name: String, layoutId: Int) =
if (childLayout == null) {
println("### ERROR childLayout NULL layoutId $layoutId")
} else {
placeable.place(
x = childLayout.left(),
y = childLayout.top()
)
placeable.place(x = childLayout.left(), y = childLayout.top())
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ interface HelloWorld {
widgetItems: ListContent,
@Design(node = "#Rect1") showRect1: Boolean,
@Design(node = "#Rect2") showRect2: Boolean,
@Design(node = "#media/now-playing/skip-prev-button") showPrev: Boolean,
@Design(node = "#media/now-playing/skip-next-button") showNext: Boolean,
@DesignVariant(property = "#media/now-playing/play-state-button") playState: PlayState,
@Design(node = "#media/now-playing/play-state-button") onPlayPauseTap: TapCallback,
)
@DesignComponent(node = "#BlueSquare") fun BlueSquare()
@DesignComponent(node = "#RedSquare") fun RedSquare()
Expand Down Expand Up @@ -279,6 +283,12 @@ fun HelloWorld() {
},
showRect1 = showRect1,
showRect2 = showRect2,
showPrev = false,
showNext = true,
playState = PlayState.Play,
onPlayPauseTap = {
println("### Tap")
},
designComposeCallbacks =
DesignComposeCallbacks(
docReadyCallback = { id ->
Expand Down

0 comments on commit 64caa2b

Please sign in to comment.