Export android plugin to OSS (#5109)
Summary: Changelog: UI Debugger is now available for Litho in Open Source Pull Request resolved: https://github.com/facebook/flipper/pull/5109 Remove the stub, replace with the real thing. Reviewed By: lblasa Differential Revision: D46859213 fbshipit-source-id: 74c59a53d1d22e046254f4bca202da17a0b0e5d8
This commit is contained in:
committed by
Facebook GitHub Bot
parent
d4065aba12
commit
0900a2a41d
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.flipper.plugins.uidebugger.litho
|
||||
|
||||
import com.facebook.flipper.plugins.uidebugger.core.ConnectionListener
|
||||
import com.facebook.flipper.plugins.uidebugger.core.UIDContext
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister
|
||||
import com.facebook.flipper.plugins.uidebugger.litho.descriptors.*
|
||||
import com.facebook.flipper.plugins.uidebugger.model.FrameworkEvent
|
||||
import com.facebook.flipper.plugins.uidebugger.model.FrameworkEventMetadata
|
||||
import com.facebook.litho.ComponentTree
|
||||
import com.facebook.litho.DebugComponent
|
||||
import com.facebook.litho.LithoView
|
||||
import com.facebook.litho.MatrixDrawable
|
||||
import com.facebook.litho.debug.LithoDebugEvent
|
||||
import com.facebook.litho.widget.TextDrawable
|
||||
import com.facebook.rendercore.debug.DebugEvent
|
||||
import com.facebook.rendercore.debug.DebugEventAttribute
|
||||
import com.facebook.rendercore.debug.DebugEventBus
|
||||
import com.facebook.rendercore.debug.DebugEventSubscriber
|
||||
import com.facebook.rendercore.debug.DebugMarkerEvent
|
||||
import com.facebook.rendercore.debug.DebugProcessEvent
|
||||
import com.facebook.rendercore.debug.Duration
|
||||
|
||||
const val LithoTag = "Litho"
|
||||
const val LithoMountableTag = "LithoMountable"
|
||||
|
||||
object UIDebuggerLithoSupport {
|
||||
|
||||
fun enable(context: UIDContext) {
|
||||
addDescriptors(context.descriptorRegister)
|
||||
|
||||
val eventMeta =
|
||||
listOf(
|
||||
// Litho
|
||||
FrameworkEventMetadata(
|
||||
LithoDebugEvent.StateUpdateEnqueued,
|
||||
"Set state was called, this will trigger resolve and then possibly layout and mount"),
|
||||
FrameworkEventMetadata(
|
||||
LithoDebugEvent.RenderRequest,
|
||||
"A request to render the component tree again. It can be requested due to 1) set root 2) state update 3) size change or measurement"),
|
||||
FrameworkEventMetadata(
|
||||
LithoDebugEvent.ComponentTreeResolve,
|
||||
"ComponentTree resolved the hierarchy into a LayoutState, non layout nodes are removed, see attributes for source of execution"),
|
||||
FrameworkEventMetadata(
|
||||
LithoDebugEvent.LayoutCommitted,
|
||||
"A new layout state created (resolved and measured result) being committed; this layout state could get mounted next."),
|
||||
|
||||
// RenderCore
|
||||
|
||||
FrameworkEventMetadata(
|
||||
DebugEvent.RenderTreeMounted, "The mount phase for the entire render tree"),
|
||||
FrameworkEventMetadata(
|
||||
DebugEvent.RenderUnitMounted,
|
||||
"Component was added into the view hierarchy (this doesn't mean it is visible)"),
|
||||
FrameworkEventMetadata(
|
||||
DebugEvent.RenderUnitUpdated,
|
||||
"The properties of a component's content were were rebinded"),
|
||||
FrameworkEventMetadata(
|
||||
DebugEvent.RenderUnitUnmounted, "Component was removed from the view hierarchy"),
|
||||
FrameworkEventMetadata(DebugEvent.RenderUnitOnVisible, "Component became visible"),
|
||||
FrameworkEventMetadata(DebugEvent.RenderUnitOnInvisible, "Component became invisible"),
|
||||
)
|
||||
|
||||
val eventForwarder =
|
||||
object : DebugEventSubscriber(*eventMeta.map { it.type }.toTypedArray()) {
|
||||
override fun onEvent(event: DebugEvent) {
|
||||
val timestamp =
|
||||
when (event) {
|
||||
is DebugMarkerEvent -> event.timestamp
|
||||
is DebugProcessEvent -> event.timestamp
|
||||
}
|
||||
val treeId = event.renderStateId.toIntOrNull() ?: -1
|
||||
|
||||
val globalKey =
|
||||
event.attributeOrNull<String>(DebugEventAttribute.GlobalKey)?.let {
|
||||
DebugComponent.generateGlobalKey(treeId, it).hashCode()
|
||||
}
|
||||
val duration = event.attributeOrNull<Duration>(DebugEventAttribute.duration)
|
||||
|
||||
val attributes = mutableMapOf<String, String>()
|
||||
val source = event.attributeOrNull<String>(DebugEventAttribute.source)
|
||||
if (source != null) {
|
||||
attributes["source"] = source
|
||||
}
|
||||
context.addFrameworkEvent(
|
||||
FrameworkEvent(
|
||||
treeId,
|
||||
globalKey ?: treeId,
|
||||
event.type,
|
||||
timestamp,
|
||||
duration?.value,
|
||||
event.threadName,
|
||||
attributes))
|
||||
}
|
||||
}
|
||||
|
||||
context.connectionListeners.add(
|
||||
object : ConnectionListener {
|
||||
override fun onConnect() {
|
||||
DebugEventBus.subscribe(eventForwarder)
|
||||
}
|
||||
|
||||
override fun onDisconnect() {
|
||||
DebugEventBus.unsubscribe(eventForwarder)
|
||||
}
|
||||
})
|
||||
|
||||
context.frameworkEventMetadata.addAll(eventMeta)
|
||||
}
|
||||
|
||||
private fun addDescriptors(register: DescriptorRegister) {
|
||||
register.register(LithoView::class.java, LithoViewDescriptor)
|
||||
register.register(DebugComponent::class.java, DebugComponentDescriptor(register))
|
||||
register.register(TextDrawable::class.java, TextDrawableDescriptor)
|
||||
register.register(MatrixDrawable::class.java, MatrixDrawableDescriptor)
|
||||
register.register(ComponentTree::class.java, ComponentTreeDescriptor(register))
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.flipper.plugins.uidebugger.litho
|
||||
|
||||
import com.facebook.flipper.plugins.uidebugger.core.UIDContext
|
||||
|
||||
// this is not used internally
|
||||
object UIDebuggerLithoSupport {
|
||||
|
||||
fun enable(context: UIDContext) {}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.flipper.plugins.uidebugger.litho.descriptors
|
||||
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.Id
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.NodeDescriptor
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.OffsetChild
|
||||
import com.facebook.flipper.plugins.uidebugger.litho.LithoTag
|
||||
import com.facebook.flipper.plugins.uidebugger.model.Bounds
|
||||
import com.facebook.flipper.plugins.uidebugger.model.InspectableObject
|
||||
import com.facebook.flipper.plugins.uidebugger.model.MetadataId
|
||||
import com.facebook.flipper.plugins.uidebugger.util.Immediate
|
||||
import com.facebook.flipper.plugins.uidebugger.util.MaybeDeferred
|
||||
import com.facebook.litho.ComponentTree
|
||||
import com.facebook.litho.DebugComponent
|
||||
|
||||
class ComponentTreeDescriptor(val register: DescriptorRegister) : NodeDescriptor<ComponentTree> {
|
||||
|
||||
private val qualifiedName = ComponentTree::class.qualifiedName ?: ""
|
||||
|
||||
override fun getId(node: ComponentTree): Id = node.id
|
||||
|
||||
override fun getBounds(node: ComponentTree): Bounds {
|
||||
val rootComponent = DebugComponent.getRootInstance(node)
|
||||
return if (rootComponent != null) {
|
||||
Bounds.fromRect(rootComponent.boundsInParentDebugComponent)
|
||||
} else {
|
||||
Bounds(0, 0, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getName(node: ComponentTree): String = "ComponentTree"
|
||||
|
||||
override fun getQualifiedName(node: ComponentTree): String = qualifiedName
|
||||
|
||||
override fun getChildren(node: ComponentTree): List<Any> {
|
||||
val result = mutableListOf<Any>()
|
||||
val debugComponent = DebugComponent.getRootInstance(node)
|
||||
if (debugComponent != null) {
|
||||
result.add(
|
||||
// we want the component tree to take the size and any offset so we reset this one
|
||||
OffsetChild.zero(
|
||||
debugComponent, register.descriptorForClassUnsafe(debugComponent.javaClass)))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun getActiveChild(node: ComponentTree): Any? = null
|
||||
|
||||
override fun getAttributes(
|
||||
node: ComponentTree
|
||||
): MaybeDeferred<Map<MetadataId, InspectableObject>> {
|
||||
return Immediate(mapOf())
|
||||
}
|
||||
|
||||
override fun getTags(node: ComponentTree): Set<String> = setOf(LithoTag, "TreeRoot")
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.flipper.plugins.uidebugger.litho.descriptors
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.Id
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.MetadataRegister
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.NodeDescriptor
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.OffsetChild
|
||||
import com.facebook.flipper.plugins.uidebugger.litho.LithoMountableTag
|
||||
import com.facebook.flipper.plugins.uidebugger.litho.LithoTag
|
||||
import com.facebook.flipper.plugins.uidebugger.litho.descriptors.props.ComponentDataExtractor
|
||||
import com.facebook.flipper.plugins.uidebugger.litho.descriptors.props.LayoutPropExtractor
|
||||
import com.facebook.flipper.plugins.uidebugger.model.Bounds
|
||||
import com.facebook.flipper.plugins.uidebugger.model.Inspectable
|
||||
import com.facebook.flipper.plugins.uidebugger.model.InspectableObject
|
||||
import com.facebook.flipper.plugins.uidebugger.model.InspectableValue
|
||||
import com.facebook.flipper.plugins.uidebugger.model.MetadataId
|
||||
import com.facebook.flipper.plugins.uidebugger.util.Deferred
|
||||
import com.facebook.flipper.plugins.uidebugger.util.MaybeDeferred
|
||||
import com.facebook.litho.Component
|
||||
import com.facebook.litho.DebugComponent
|
||||
import com.facebook.rendercore.FastMath
|
||||
import com.facebook.yoga.YogaEdge
|
||||
|
||||
class DebugComponentDescriptor(val register: DescriptorRegister) : NodeDescriptor<DebugComponent> {
|
||||
private val NAMESPACE = "DebugComponent"
|
||||
|
||||
/*
|
||||
* Debug component is generated on the fly so use the underlying component instance which is
|
||||
* immutable
|
||||
*/
|
||||
override fun getId(node: DebugComponent): Id = node.globalKey.hashCode()
|
||||
|
||||
override fun getName(node: DebugComponent): String = node.component.simpleName
|
||||
|
||||
override fun getQualifiedName(node: com.facebook.litho.DebugComponent): String =
|
||||
node.component::class.qualifiedName ?: ""
|
||||
|
||||
override fun getChildren(node: DebugComponent): List<Any> {
|
||||
val result = mutableListOf<Any>()
|
||||
|
||||
val mountedContent = node.mountedContent
|
||||
|
||||
if (mountedContent == null) {
|
||||
for (child in node.childComponents) {
|
||||
result.add(child)
|
||||
}
|
||||
} else {
|
||||
|
||||
val layoutNode = node.layoutNode
|
||||
val descriptor: NodeDescriptor<Any> =
|
||||
register.descriptorForClassUnsafe(mountedContent.javaClass)
|
||||
// mountables are always layout nodes
|
||||
if (layoutNode != null) {
|
||||
/**
|
||||
* We need to override the mounted contents offset since the mounted contents android bounds
|
||||
* are w.r.t its native parent but we want it w.r.t to the mountable.
|
||||
*
|
||||
* However padding on a mountable means that the content is inset within the mountables
|
||||
* bounds so we need to adjust for this
|
||||
*/
|
||||
result.add(
|
||||
OffsetChild(
|
||||
child = mountedContent,
|
||||
descriptor = descriptor,
|
||||
x = layoutNode.getLayoutPadding(YogaEdge.LEFT).let { FastMath.round(it) },
|
||||
y = layoutNode.getLayoutPadding(YogaEdge.TOP).let { FastMath.round(it) },
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
override fun getActiveChild(node: DebugComponent): Any? = null
|
||||
|
||||
private val LayoutId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "Litho Layout")
|
||||
|
||||
private val UserPropsId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "Litho Props")
|
||||
|
||||
private val StateId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "Litho State")
|
||||
|
||||
private val MountingDataId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "Mount State")
|
||||
|
||||
private val isMountedAttributeId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "mounted")
|
||||
|
||||
private val isVisibleAttributeId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "visible")
|
||||
|
||||
override fun getAttributes(
|
||||
node: DebugComponent
|
||||
): MaybeDeferred<Map<MetadataId, InspectableObject>> {
|
||||
return Deferred {
|
||||
val attributeSections = mutableMapOf<MetadataId, InspectableObject>()
|
||||
|
||||
val mountingData = getMountingData(node)
|
||||
attributeSections[MountingDataId] = InspectableObject(mountingData)
|
||||
|
||||
val layoutProps = LayoutPropExtractor.getProps(node)
|
||||
attributeSections[LayoutId] = InspectableObject(layoutProps.toMap())
|
||||
|
||||
if (!node.canResolve()) {
|
||||
val stateContainer = node.stateContainer
|
||||
if (stateContainer != null) {
|
||||
attributeSections[StateId] =
|
||||
ComponentDataExtractor.getState(stateContainer, node.component.simpleName)
|
||||
}
|
||||
|
||||
val props = ComponentDataExtractor.getProps(node.component)
|
||||
|
||||
attributeSections[UserPropsId] = InspectableObject(props.toMap())
|
||||
}
|
||||
|
||||
attributeSections
|
||||
}
|
||||
}
|
||||
|
||||
override fun getBounds(node: DebugComponent): Bounds =
|
||||
Bounds.fromRect(node.boundsInParentDebugComponent)
|
||||
|
||||
override fun getTags(node: DebugComponent): Set<String> {
|
||||
val tags = mutableSetOf(LithoTag)
|
||||
|
||||
if (node.component.mountType != Component.MountType.NONE) {
|
||||
tags.add(LithoMountableTag)
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
override fun getSnapshot(node: DebugComponent, bitmap: Bitmap?): Bitmap? = null
|
||||
|
||||
override fun getInlineAttributes(node: DebugComponent): Map<String, String> {
|
||||
val attributes = mutableMapOf<String, String>()
|
||||
val key = node.key
|
||||
val testKey = node.testKey
|
||||
if (key != null && key.trim { it <= ' ' }.length > 0) {
|
||||
attributes["key"] = key
|
||||
}
|
||||
if (testKey != null && testKey.trim { it <= ' ' }.length > 0) {
|
||||
attributes["testKey"] = testKey
|
||||
}
|
||||
return attributes
|
||||
}
|
||||
|
||||
private fun getMountingData(node: DebugComponent): Map<Id, Inspectable> {
|
||||
|
||||
val lithoView = node.lithoView
|
||||
val mountingData = mutableMapOf<MetadataId, Inspectable>()
|
||||
|
||||
if (lithoView == null) {
|
||||
return mountingData
|
||||
}
|
||||
|
||||
val mountState = lithoView.mountDelegateTarget ?: return mountingData
|
||||
val componentTree = lithoView.componentTree ?: return mountingData
|
||||
|
||||
val component = node.component
|
||||
|
||||
if (component.mountType != Component.MountType.NONE) {
|
||||
val renderUnit = DebugComponent.getRenderUnit(node, componentTree)
|
||||
if (renderUnit != null) {
|
||||
val renderUnitId = renderUnit.id
|
||||
val isMounted = mountState.getContentById(renderUnitId) != null
|
||||
mountingData[isMountedAttributeId] = InspectableValue.Boolean(isMounted)
|
||||
}
|
||||
}
|
||||
|
||||
val visibilityOutput = DebugComponent.getVisibilityOutput(node, componentTree)
|
||||
if (visibilityOutput != null) {
|
||||
val isVisible = DebugComponent.isVisible(node, lithoView)
|
||||
mountingData[isVisibleAttributeId] = InspectableValue.Boolean(isVisible)
|
||||
}
|
||||
|
||||
return mountingData
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.flipper.plugins.uidebugger.litho.descriptors
|
||||
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.ChainedDescriptor
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.MetadataRegister
|
||||
import com.facebook.flipper.plugins.uidebugger.model.InspectableObject
|
||||
import com.facebook.flipper.plugins.uidebugger.model.InspectableValue
|
||||
import com.facebook.flipper.plugins.uidebugger.model.MetadataId
|
||||
import com.facebook.litho.LithoView
|
||||
|
||||
object LithoViewDescriptor : ChainedDescriptor<LithoView>() {
|
||||
|
||||
private const val NAMESPACE = "LithoView"
|
||||
private val SectionId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, NAMESPACE)
|
||||
|
||||
override fun onGetName(node: LithoView): String = node.javaClass.simpleName
|
||||
|
||||
override fun onGetChildren(node: LithoView): List<Any> {
|
||||
val componentTree = node.componentTree
|
||||
if (componentTree != null) {
|
||||
return listOf(componentTree)
|
||||
}
|
||||
|
||||
return listOf()
|
||||
}
|
||||
|
||||
private val IsIncrementalMountEnabledAttributeId =
|
||||
MetadataRegister.register(
|
||||
MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "isIncrementalMountEnabled")
|
||||
|
||||
override fun onGetAttributes(
|
||||
node: LithoView,
|
||||
attributeSections: MutableMap<MetadataId, InspectableObject>
|
||||
) {
|
||||
attributeSections[SectionId] =
|
||||
InspectableObject(
|
||||
mapOf(
|
||||
IsIncrementalMountEnabledAttributeId to
|
||||
InspectableValue.Boolean(node.isIncrementalMountEnabled)))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.flipper.plugins.uidebugger.litho.descriptors
|
||||
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.ChainedDescriptor
|
||||
import com.facebook.litho.MatrixDrawable
|
||||
|
||||
object MatrixDrawableDescriptor : ChainedDescriptor<MatrixDrawable<*>>() {
|
||||
|
||||
override fun onGetChildren(node: MatrixDrawable<*>): List<Any>? {
|
||||
val mountedDrawable = node.mountedDrawable
|
||||
return if (mountedDrawable != null) {
|
||||
listOf(mountedDrawable)
|
||||
} else {
|
||||
listOf()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onGetName(node: MatrixDrawable<*>): String = node.javaClass.simpleName
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.flipper.plugins.uidebugger.litho.descriptors
|
||||
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.ChainedDescriptor
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.MetadataRegister
|
||||
import com.facebook.flipper.plugins.uidebugger.model.Inspectable
|
||||
import com.facebook.flipper.plugins.uidebugger.model.InspectableObject
|
||||
import com.facebook.flipper.plugins.uidebugger.model.InspectableValue
|
||||
import com.facebook.flipper.plugins.uidebugger.model.MetadataId
|
||||
import com.facebook.litho.widget.TextDrawable
|
||||
|
||||
object TextDrawableDescriptor : ChainedDescriptor<TextDrawable>() {
|
||||
|
||||
private const val NAMESPACE = "TextDrawable"
|
||||
private val SectionId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, NAMESPACE)
|
||||
|
||||
override fun onGetName(node: TextDrawable): String = node.javaClass.simpleName
|
||||
|
||||
private val TextAttributeId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "text")
|
||||
|
||||
override fun onGetAttributes(
|
||||
node: TextDrawable,
|
||||
attributeSections: MutableMap<MetadataId, InspectableObject>
|
||||
) {
|
||||
val props =
|
||||
mapOf<Int, Inspectable>(TextAttributeId to InspectableValue.Text(node.text.toString()))
|
||||
|
||||
attributeSections[SectionId] = InspectableObject(props)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.flipper.plugins.uidebugger.litho.descriptors.props
|
||||
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.Log
|
||||
import com.facebook.flipper.plugins.uidebugger.LogTag
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.MetadataRegister
|
||||
import com.facebook.flipper.plugins.uidebugger.model.*
|
||||
import com.facebook.litho.Component
|
||||
import com.facebook.litho.SpecGeneratedComponent
|
||||
import com.facebook.litho.StateContainer
|
||||
import com.facebook.litho.annotations.Prop
|
||||
import com.facebook.litho.annotations.ResType
|
||||
import com.facebook.litho.annotations.State
|
||||
import com.facebook.litho.editor.EditorRegistry
|
||||
import com.facebook.litho.editor.model.EditorArray
|
||||
import com.facebook.litho.editor.model.EditorBool
|
||||
import com.facebook.litho.editor.model.EditorColor
|
||||
import com.facebook.litho.editor.model.EditorNumber
|
||||
import com.facebook.litho.editor.model.EditorPick
|
||||
import com.facebook.litho.editor.model.EditorShape
|
||||
import com.facebook.litho.editor.model.EditorString
|
||||
import com.facebook.litho.editor.model.EditorValue
|
||||
import com.facebook.litho.editor.model.EditorValue.EditorVisitor
|
||||
|
||||
object ComponentDataExtractor {
|
||||
|
||||
fun getProps(component: Component): Map<MetadataId, Inspectable> {
|
||||
val props = mutableMapOf<MetadataId, Inspectable>()
|
||||
|
||||
val isSpecComponent = component is SpecGeneratedComponent
|
||||
|
||||
for (declaredField in component.javaClass.declaredFields) {
|
||||
declaredField.isAccessible = true
|
||||
|
||||
val name = declaredField.name
|
||||
val declaredFieldAnnotation = declaredField.getAnnotation(Prop::class.java)
|
||||
|
||||
// Only expose `@Prop` annotated fields for Spec components
|
||||
if (isSpecComponent && declaredFieldAnnotation == null) {
|
||||
continue
|
||||
}
|
||||
|
||||
val prop =
|
||||
try {
|
||||
declaredField[component]
|
||||
} catch (e: IllegalAccessException) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (declaredFieldAnnotation != null) {
|
||||
val resType = declaredFieldAnnotation.resType
|
||||
if (resType == ResType.COLOR) {
|
||||
if (prop != null) {
|
||||
val identifier = getMetadataId(component.simpleName, name)
|
||||
props[identifier] = InspectableValue.Color(Color.fromColor(prop as Int))
|
||||
}
|
||||
continue
|
||||
} else if (resType == ResType.DRAWABLE) {
|
||||
val identifier = getMetadataId(component.simpleName, name)
|
||||
props[identifier] = fromDrawable(prop as Drawable?)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
val editorValue =
|
||||
try {
|
||||
EditorRegistry.read(declaredField.type, declaredField, component)
|
||||
} catch (e: Exception) {
|
||||
Log.d(
|
||||
LogTag,
|
||||
"Unable to retrieve prop ${declaredField.name} on type ${component.simpleName}")
|
||||
EditorString("error fetching prop")
|
||||
}
|
||||
|
||||
if (editorValue != null) {
|
||||
addProp(props, component.simpleName, name, editorValue)
|
||||
}
|
||||
}
|
||||
|
||||
return props
|
||||
}
|
||||
|
||||
fun getState(stateContainer: StateContainer, componentName: String): InspectableObject {
|
||||
|
||||
val stateFields = mutableMapOf<MetadataId, Inspectable>()
|
||||
for (field in stateContainer.javaClass.declaredFields) {
|
||||
field.isAccessible = true
|
||||
val stateAnnotation = field.getAnnotation(State::class.java)
|
||||
val isKStateField = field.name == "states"
|
||||
if (stateAnnotation != null || isKStateField) {
|
||||
val id = getMetadataId(componentName, field.name)
|
||||
val editorValue: EditorValue? = EditorRegistry.read(field.type, field, stateContainer)
|
||||
if (editorValue != null) {
|
||||
stateFields[id] = toInspectable(field.name, editorValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
return InspectableObject(stateFields)
|
||||
}
|
||||
|
||||
private fun getMetadataId(
|
||||
namespace: String,
|
||||
key: String,
|
||||
mutable: Boolean = false,
|
||||
possibleValues: Set<InspectableValue>? = emptySet()
|
||||
): MetadataId {
|
||||
val metadata = MetadataRegister.get(namespace, key)
|
||||
val identifier =
|
||||
metadata?.id
|
||||
?: MetadataRegister.register(
|
||||
MetadataRegister.TYPE_ATTRIBUTE, namespace, key, mutable, possibleValues)
|
||||
return identifier
|
||||
}
|
||||
|
||||
private fun addProp(
|
||||
props: MutableMap<MetadataId, Inspectable>,
|
||||
namespace: String,
|
||||
name: String,
|
||||
value: EditorValue
|
||||
) {
|
||||
var possibleValues: MutableSet<InspectableValue>? = null
|
||||
if (value is EditorPick) {
|
||||
possibleValues = mutableSetOf()
|
||||
value.values.forEach { possibleValues.add(InspectableValue.Text(it)) }
|
||||
}
|
||||
|
||||
val identifier = getMetadataId(namespace, name, false, possibleValues)
|
||||
props[identifier] = toInspectable(name, value)
|
||||
}
|
||||
|
||||
private fun toInspectable(name: String, editorValue: EditorValue): Inspectable {
|
||||
return editorValue.`when`(
|
||||
object : EditorVisitor<Inspectable> {
|
||||
override fun isShape(shape: EditorShape): Inspectable {
|
||||
|
||||
val fields = mutableMapOf<MetadataId, Inspectable>()
|
||||
shape.value.entries.forEach { entry ->
|
||||
val value = toInspectable(entry.key, entry.value)
|
||||
|
||||
val shapeEditorValue = entry.value
|
||||
var possibleValues: MutableSet<InspectableValue>? = null
|
||||
if (shapeEditorValue is EditorPick) {
|
||||
possibleValues = mutableSetOf()
|
||||
shapeEditorValue.values.forEach { possibleValues.add(InspectableValue.Text(it)) }
|
||||
}
|
||||
|
||||
val identifier = getMetadataId(name, entry.key, false, possibleValues)
|
||||
fields[identifier] = value
|
||||
}
|
||||
|
||||
return InspectableObject(fields)
|
||||
}
|
||||
|
||||
override fun isArray(array: EditorArray?): Inspectable {
|
||||
val values = array?.value?.map { value -> toInspectable(name, value) }
|
||||
return InspectableArray(values ?: listOf())
|
||||
}
|
||||
|
||||
override fun isPick(pick: EditorPick): Inspectable = InspectableValue.Enum(pick.selected)
|
||||
|
||||
override fun isNumber(number: EditorNumber): Inspectable =
|
||||
InspectableValue.Number(number.value)
|
||||
|
||||
override fun isColor(number: EditorColor): Inspectable =
|
||||
InspectableValue.Color(number.value.toInt().let { Color.fromColor(it) })
|
||||
|
||||
override fun isString(string: EditorString): Inspectable =
|
||||
InspectableValue.Text(string.value ?: "")
|
||||
|
||||
override fun isBool(bool: EditorBool): Inspectable = InspectableValue.Boolean(bool.value)
|
||||
})
|
||||
}
|
||||
|
||||
private fun fromDrawable(d: Drawable?): Inspectable =
|
||||
when (d) {
|
||||
is ColorDrawable -> InspectableValue.Color(Color.fromColor(d.color))
|
||||
else -> InspectableValue.Unknown(d.toString())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,432 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.flipper.plugins.uidebugger.litho.descriptors.props
|
||||
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import com.facebook.flipper.plugins.uidebugger.common.enumToInspectableSet
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.MetadataRegister
|
||||
import com.facebook.flipper.plugins.uidebugger.model.*
|
||||
import com.facebook.litho.DebugComponent
|
||||
import com.facebook.yoga.*
|
||||
|
||||
object LayoutPropExtractor {
|
||||
private const val NAMESPACE = "LayoutPropExtractor"
|
||||
|
||||
private var BackgroundId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "background")
|
||||
private var ForegroundId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "foreground")
|
||||
|
||||
private val DirectionId =
|
||||
MetadataRegister.register(
|
||||
MetadataRegister.TYPE_ATTRIBUTE,
|
||||
NAMESPACE,
|
||||
"direction",
|
||||
false,
|
||||
enumToInspectableSet<YogaDirection>())
|
||||
private val FlexDirectionId =
|
||||
MetadataRegister.register(
|
||||
MetadataRegister.TYPE_ATTRIBUTE,
|
||||
NAMESPACE,
|
||||
"flexDirection",
|
||||
false,
|
||||
enumToInspectableSet<YogaFlexDirection>())
|
||||
private val JustifyContentId =
|
||||
MetadataRegister.register(
|
||||
MetadataRegister.TYPE_ATTRIBUTE,
|
||||
NAMESPACE,
|
||||
"justifyContent",
|
||||
false,
|
||||
enumToInspectableSet<YogaJustify>())
|
||||
private val AlignItemsId =
|
||||
MetadataRegister.register(
|
||||
MetadataRegister.TYPE_ATTRIBUTE,
|
||||
NAMESPACE,
|
||||
"alignItems",
|
||||
false,
|
||||
enumToInspectableSet<YogaAlign>())
|
||||
private val AlignSelfId =
|
||||
MetadataRegister.register(
|
||||
MetadataRegister.TYPE_ATTRIBUTE,
|
||||
NAMESPACE,
|
||||
"alignSelf",
|
||||
false,
|
||||
enumToInspectableSet<YogaAlign>())
|
||||
private val AlignContentId =
|
||||
MetadataRegister.register(
|
||||
MetadataRegister.TYPE_ATTRIBUTE,
|
||||
NAMESPACE,
|
||||
"alignContent",
|
||||
false,
|
||||
enumToInspectableSet<YogaAlign>())
|
||||
private val PositionTypeId =
|
||||
MetadataRegister.register(
|
||||
MetadataRegister.TYPE_ATTRIBUTE,
|
||||
NAMESPACE,
|
||||
"positionType",
|
||||
false,
|
||||
enumToInspectableSet<YogaPositionType>())
|
||||
|
||||
private val FlexGrowId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "flexGrow")
|
||||
private val FlexShrinkId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "flexShrink")
|
||||
private val FlexBasisId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "flexBasis")
|
||||
private val WidthId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "width")
|
||||
private val HeightId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "height")
|
||||
private val MinWidthId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "minWidth")
|
||||
private val MinHeightId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "minHeight")
|
||||
private val MaxWidthId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "maxWidth")
|
||||
private val MaxHeightId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "maxHeight")
|
||||
private val AspectRatioId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "aspectRatio")
|
||||
|
||||
private val MarginId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "margin")
|
||||
private val PaddingId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "padding")
|
||||
private val BorderId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "border")
|
||||
private val PositionId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "position")
|
||||
|
||||
private val LeftId = MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "left")
|
||||
private val TopId = MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "top")
|
||||
private val RightId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "right")
|
||||
private val BottomId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "bottom")
|
||||
private val StartId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "start")
|
||||
private val EndId = MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "end")
|
||||
private val HorizontalId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "horizontal")
|
||||
private val VerticalId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "vertical")
|
||||
private val AllId = MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "all")
|
||||
|
||||
private val HasViewOutputId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "hasViewOutput")
|
||||
private val AlphaId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "alpha")
|
||||
private val ScaleId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "scale")
|
||||
private val RotationId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "rotation")
|
||||
|
||||
private val EmptyId = MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "")
|
||||
private val NoneId = MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "none")
|
||||
private val SizeId = MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "size")
|
||||
private val ViewOutputId =
|
||||
MetadataRegister.register(MetadataRegister.TYPE_ATTRIBUTE, NAMESPACE, "viewOutput")
|
||||
|
||||
fun getInspectableBox(
|
||||
left: YogaValue?,
|
||||
top: YogaValue?,
|
||||
right: YogaValue?,
|
||||
bottom: YogaValue?,
|
||||
horizontal: YogaValue?,
|
||||
vertical: YogaValue?,
|
||||
all: YogaValue?,
|
||||
start: YogaValue?,
|
||||
end: YogaValue?
|
||||
): InspectableObject {
|
||||
val props = mutableMapOf<MetadataId, Inspectable>()
|
||||
|
||||
var actualLeft = 0
|
||||
var actualTop = 0
|
||||
var actualRight = 0
|
||||
var actualBottom = 0
|
||||
|
||||
all?.let { yogaValue ->
|
||||
if (yogaValue.unit != YogaUnit.UNDEFINED) {
|
||||
if (yogaValue.unit == YogaUnit.POINT || yogaValue.unit == YogaUnit.PERCENT) {
|
||||
val intValue = yogaValue.value.toInt()
|
||||
actualLeft = intValue
|
||||
actualTop = intValue
|
||||
actualRight = intValue
|
||||
actualBottom = intValue
|
||||
}
|
||||
|
||||
props[AllId] = InspectableValue.Text(yogaValue.toString())
|
||||
}
|
||||
}
|
||||
|
||||
horizontal?.let { yogaValue ->
|
||||
if (yogaValue.unit != YogaUnit.UNDEFINED) {
|
||||
if (yogaValue.unit == YogaUnit.POINT || yogaValue.unit == YogaUnit.PERCENT) {
|
||||
val intValue = yogaValue.value.toInt()
|
||||
actualLeft = intValue
|
||||
actualRight = intValue
|
||||
}
|
||||
|
||||
props[HorizontalId] = InspectableValue.Text(yogaValue.toString())
|
||||
}
|
||||
}
|
||||
|
||||
vertical?.let { yogaValue ->
|
||||
if (yogaValue.unit != YogaUnit.UNDEFINED) {
|
||||
if (yogaValue.unit == YogaUnit.POINT || yogaValue.unit == YogaUnit.PERCENT) {
|
||||
val intValue = yogaValue.value.toInt()
|
||||
actualTop = intValue
|
||||
actualBottom = intValue
|
||||
}
|
||||
|
||||
props[VerticalId] = InspectableValue.Text(yogaValue.toString())
|
||||
}
|
||||
}
|
||||
|
||||
left?.let { yogaValue ->
|
||||
if (yogaValue.unit != YogaUnit.UNDEFINED) {
|
||||
if (yogaValue.unit == YogaUnit.POINT || yogaValue.unit == YogaUnit.PERCENT) {
|
||||
val intValue = yogaValue.value.toInt()
|
||||
actualLeft = intValue
|
||||
}
|
||||
|
||||
props[LeftId] = InspectableValue.Text(yogaValue.toString())
|
||||
}
|
||||
}
|
||||
|
||||
right?.let { yogaValue ->
|
||||
if (yogaValue.unit != YogaUnit.UNDEFINED) {
|
||||
if (yogaValue.unit == YogaUnit.POINT || yogaValue.unit == YogaUnit.PERCENT) {
|
||||
val intValue = yogaValue.value.toInt()
|
||||
actualRight = intValue
|
||||
}
|
||||
|
||||
props[RightId] = InspectableValue.Text(yogaValue.toString())
|
||||
}
|
||||
}
|
||||
|
||||
top?.let { yogaValue ->
|
||||
if (yogaValue.unit != YogaUnit.UNDEFINED) {
|
||||
if (yogaValue.unit == YogaUnit.POINT || yogaValue.unit == YogaUnit.PERCENT) {
|
||||
val intValue = yogaValue.value.toInt()
|
||||
actualTop = intValue
|
||||
}
|
||||
|
||||
props[TopId] = InspectableValue.Text(yogaValue.toString())
|
||||
}
|
||||
}
|
||||
|
||||
bottom?.let { yogaValue ->
|
||||
if (yogaValue.unit != YogaUnit.UNDEFINED) {
|
||||
if (yogaValue.unit == YogaUnit.POINT || yogaValue.unit == YogaUnit.PERCENT) {
|
||||
val intValue = yogaValue.value.toInt()
|
||||
actualBottom = intValue
|
||||
}
|
||||
|
||||
props[BottomId] = InspectableValue.Text(yogaValue.toString())
|
||||
}
|
||||
}
|
||||
|
||||
props[EmptyId] =
|
||||
InspectableValue.SpaceBox(SpaceBox(actualTop, actualRight, actualBottom, actualLeft))
|
||||
|
||||
return InspectableObject(props)
|
||||
}
|
||||
|
||||
fun getInspectableBoxRaw(
|
||||
left: Float?,
|
||||
top: Float?,
|
||||
right: Float?,
|
||||
bottom: Float?,
|
||||
horizontal: Float?,
|
||||
vertical: Float?,
|
||||
all: Float?,
|
||||
start: Float?,
|
||||
end: Float?
|
||||
): InspectableObject {
|
||||
val props = mutableMapOf<MetadataId, Inspectable>()
|
||||
|
||||
var actualLeft = 0
|
||||
var actualTop = 0
|
||||
var actualRight = 0
|
||||
var actualBottom = 0
|
||||
|
||||
all?.let { value ->
|
||||
if (!value.isNaN()) {
|
||||
val intValue = value.toInt()
|
||||
actualLeft = intValue
|
||||
actualTop = intValue
|
||||
actualRight = intValue
|
||||
actualBottom = intValue
|
||||
props[AllId] = InspectableValue.Number(value)
|
||||
}
|
||||
}
|
||||
|
||||
horizontal?.let { value ->
|
||||
if (!value.isNaN()) {
|
||||
val intValue = value.toInt()
|
||||
actualLeft = intValue
|
||||
actualRight = intValue
|
||||
props[HorizontalId] = InspectableValue.Number(value)
|
||||
}
|
||||
}
|
||||
|
||||
vertical?.let { value ->
|
||||
if (!value.isNaN()) {
|
||||
val intValue = value.toInt()
|
||||
actualTop = intValue
|
||||
actualBottom = intValue
|
||||
props[VerticalId] = InspectableValue.Number(value)
|
||||
}
|
||||
}
|
||||
|
||||
left?.let { value ->
|
||||
if (!value.isNaN()) {
|
||||
val intValue = value.toInt()
|
||||
actualLeft = intValue
|
||||
props[LeftId] = InspectableValue.Number(value)
|
||||
}
|
||||
}
|
||||
|
||||
right?.let { value ->
|
||||
if (!value.isNaN()) {
|
||||
val intValue = value.toInt()
|
||||
actualRight = intValue
|
||||
props[RightId] = InspectableValue.Number(value)
|
||||
}
|
||||
}
|
||||
|
||||
top?.let { value ->
|
||||
if (!value.isNaN()) {
|
||||
val intValue = value.toInt()
|
||||
actualTop = intValue
|
||||
props[TopId] = InspectableValue.Number(value)
|
||||
}
|
||||
}
|
||||
|
||||
bottom?.let { value ->
|
||||
if (!value.isNaN()) {
|
||||
val intValue = value.toInt()
|
||||
actualBottom = intValue
|
||||
props[BottomId] = InspectableValue.Number(value)
|
||||
}
|
||||
}
|
||||
|
||||
props[EmptyId] =
|
||||
InspectableValue.SpaceBox(SpaceBox(actualTop, actualRight, actualBottom, actualLeft))
|
||||
|
||||
return InspectableObject(props)
|
||||
}
|
||||
|
||||
fun getProps(component: DebugComponent): Map<MetadataId, Inspectable> {
|
||||
val props = mutableMapOf<MetadataId, Inspectable>()
|
||||
|
||||
val layout = component.layoutNode ?: return props
|
||||
|
||||
props[AlignItemsId] = InspectableValue.Enum(layout.alignItems.name)
|
||||
props[AlignSelfId] = InspectableValue.Enum(layout.alignSelf.name)
|
||||
props[AlignContentId] = InspectableValue.Enum(layout.alignContent.name)
|
||||
|
||||
props[AspectRatioId] = InspectableValue.Text(layout.aspectRatio.toString())
|
||||
|
||||
layout.background?.let { drawable -> props[BackgroundId] = fromDrawable(drawable) }
|
||||
|
||||
props[DirectionId] = InspectableValue.Enum(layout.layoutDirection.name)
|
||||
|
||||
props[FlexBasisId] = InspectableValue.Text(layout.flexBasis.toString())
|
||||
props[FlexDirectionId] = InspectableValue.Enum(layout.flexDirection.name)
|
||||
props[FlexGrowId] = InspectableValue.Text(layout.flexGrow.toString())
|
||||
props[FlexShrinkId] = InspectableValue.Text(layout.flexShrink.toString())
|
||||
|
||||
layout.foreground?.let { drawable -> props[ForegroundId] = fromDrawable(drawable) }
|
||||
|
||||
props[JustifyContentId] = InspectableValue.Enum(layout.justifyContent.name)
|
||||
|
||||
props[PositionTypeId] = InspectableValue.Enum(layout.positionType.name)
|
||||
|
||||
val size: MutableMap<MetadataId, Inspectable> = mutableMapOf()
|
||||
size[WidthId] = InspectableValue.Text(layout.width.toString())
|
||||
if (layout.minWidth.unit != YogaUnit.UNDEFINED)
|
||||
size[MinWidthId] = InspectableValue.Text(layout.minWidth.toString())
|
||||
if (layout.maxWidth.unit != YogaUnit.UNDEFINED)
|
||||
size[MaxWidthId] = InspectableValue.Text(layout.maxWidth.toString())
|
||||
size[HeightId] = InspectableValue.Text(layout.height.toString())
|
||||
if (layout.minHeight.unit != YogaUnit.UNDEFINED)
|
||||
size[MinHeightId] = InspectableValue.Text(layout.minHeight.toString())
|
||||
if (layout.maxHeight.unit != YogaUnit.UNDEFINED)
|
||||
size[MaxHeightId] = InspectableValue.Text(layout.maxHeight.toString())
|
||||
|
||||
props[SizeId] = InspectableObject(size)
|
||||
|
||||
props[MarginId] =
|
||||
getInspectableBox(
|
||||
layout.getMargin(YogaEdge.LEFT),
|
||||
layout.getMargin(YogaEdge.TOP),
|
||||
layout.getMargin(YogaEdge.RIGHT),
|
||||
layout.getMargin(YogaEdge.BOTTOM),
|
||||
layout.getMargin(YogaEdge.HORIZONTAL),
|
||||
layout.getMargin(YogaEdge.VERTICAL),
|
||||
layout.getMargin(YogaEdge.ALL),
|
||||
layout.getMargin(YogaEdge.START),
|
||||
layout.getMargin(YogaEdge.END))
|
||||
|
||||
props[PaddingId] =
|
||||
getInspectableBox(
|
||||
layout.getPadding(YogaEdge.LEFT),
|
||||
layout.getPadding(YogaEdge.TOP),
|
||||
layout.getPadding(YogaEdge.RIGHT),
|
||||
layout.getPadding(YogaEdge.BOTTOM),
|
||||
layout.getPadding(YogaEdge.HORIZONTAL),
|
||||
layout.getPadding(YogaEdge.VERTICAL),
|
||||
layout.getPadding(YogaEdge.ALL),
|
||||
layout.getPadding(YogaEdge.START),
|
||||
layout.getPadding(YogaEdge.END))
|
||||
|
||||
props[BorderId] =
|
||||
getInspectableBoxRaw(
|
||||
layout.getBorderWidth(YogaEdge.LEFT),
|
||||
layout.getBorderWidth(YogaEdge.TOP),
|
||||
layout.getBorderWidth(YogaEdge.RIGHT),
|
||||
layout.getBorderWidth(YogaEdge.BOTTOM),
|
||||
layout.getBorderWidth(YogaEdge.HORIZONTAL),
|
||||
layout.getBorderWidth(YogaEdge.VERTICAL),
|
||||
layout.getBorderWidth(YogaEdge.ALL),
|
||||
layout.getBorderWidth(YogaEdge.START),
|
||||
layout.getBorderWidth(YogaEdge.END))
|
||||
|
||||
props[PositionId] =
|
||||
getInspectableBox(
|
||||
layout.getPosition(YogaEdge.LEFT),
|
||||
layout.getPosition(YogaEdge.TOP),
|
||||
layout.getPosition(YogaEdge.RIGHT),
|
||||
layout.getPosition(YogaEdge.BOTTOM),
|
||||
layout.getPosition(YogaEdge.HORIZONTAL),
|
||||
layout.getPosition(YogaEdge.VERTICAL),
|
||||
layout.getPosition(YogaEdge.ALL),
|
||||
layout.getPosition(YogaEdge.START),
|
||||
layout.getPosition(YogaEdge.END))
|
||||
|
||||
val viewOutput: MutableMap<MetadataId, Inspectable> = mutableMapOf()
|
||||
viewOutput[HasViewOutputId] = InspectableValue.Boolean(layout.hasViewOutput())
|
||||
if (layout.hasViewOutput()) {
|
||||
viewOutput[AlphaId] = InspectableValue.Number(layout.alpha)
|
||||
viewOutput[RotationId] = InspectableValue.Number(layout.rotation)
|
||||
viewOutput[ScaleId] = InspectableValue.Number(layout.scale)
|
||||
}
|
||||
props[ViewOutputId] = InspectableObject(viewOutput)
|
||||
|
||||
return props
|
||||
}
|
||||
|
||||
private fun fromDrawable(d: Drawable?): Inspectable =
|
||||
when (d) {
|
||||
is ColorDrawable -> InspectableValue.Color(Color.fromColor(d.color))
|
||||
else -> InspectableValue.Unknown(d.toString())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user