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