Remove UI Debugger litho components from open source build

Summary:
I created a separate folder under src called facedbook, which
1.  isnt synced to github
2.  isnt build by gradle

I also needed to exclude the file with the duplicate symbol from buck. I seemed to have to move both the src/facebook and src/main under one buck file to get the exclude to work

Reviewed By: lblasa

Differential Revision: D41612114

fbshipit-source-id: a8386e1b1eabdeca2a800d98d8732b2ca694836b
This commit is contained in:
Luke De Feo
2022-12-19 09:20:27 -08:00
committed by Facebook GitHub Bot
parent 0414e145a9
commit 6deedabfb2
9 changed files with 19 additions and 1039 deletions

View File

@@ -1,126 +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 android.annotation.SuppressLint
import android.util.Log
import android.view.ViewTreeObserver
import com.facebook.flipper.plugins.uidebugger.LogTag
import com.facebook.flipper.plugins.uidebugger.core.Context
import com.facebook.flipper.plugins.uidebugger.descriptors.ViewDescriptor
import com.facebook.flipper.plugins.uidebugger.litho.descriptors.LithoViewDescriptor
import com.facebook.flipper.plugins.uidebugger.model.Bounds
import com.facebook.flipper.plugins.uidebugger.model.Coordinate
import com.facebook.flipper.plugins.uidebugger.observers.CoordinateUpdate
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserver
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverBuilder
import com.facebook.flipper.plugins.uidebugger.scheduler.throttleLatest
import com.facebook.flipper.plugins.uidebugger.util.objectIdentity
import com.facebook.litho.LithoView
import com.facebook.rendercore.extensions.ExtensionState
import com.facebook.rendercore.extensions.MountExtension
import kotlinx.coroutines.*
/**
* There are 2 ways a litho view can update:
* 1. A view was added / updated / removed through a mount, This should be refelected in a change in
* props / state so we use the mount extension to capture these including the entire component
* tree
* 2. The coordinate of the litho view changes externally and doesn't cause a mount, examples:
* - Sibling changed size or position and shifted this view
* - User scrolled
*
* These are not interesting from UI debugger perspective, we don't want to send the whole subtree
* as only the Coordinate of the root litho view has changed. For this situation we send a
* lightweight coordinate update event to distinguish these 2 cases
*
* If an external event such as a scroll does does lead to a mount (new view in recycler view) this
* will be picked up by the mount extension
*/
class LithoViewTreeObserver(val context: Context) : TreeObserver<LithoView>() {
override val type = "Litho"
private val throttleTimeMs = 100L
private val waitScope = CoroutineScope(Dispatchers.IO)
private val mainScope = CoroutineScope(Dispatchers.Main)
var lastBounds: Bounds? = null
var nodeRef: LithoView? = null
private var preDrawListener: ViewTreeObserver.OnPreDrawListener? = null
@SuppressLint("PrivateApi")
override fun subscribe(node: Any) {
nodeRef = node as LithoView
Log.d(LogTag, "Subscribing to litho view ${nodeRef?.objectIdentity()}")
val lithoDebuggerExtension = LithoDebuggerExtension(this)
node.registerUIDebugger(lithoDebuggerExtension)
val throttledCordinateUpdate =
throttleLatest<LithoView>(throttleTimeMs, waitScope, mainScope) { node ->
// use the descriptor to get the bounds since we do some magic in there
val bounds = ViewDescriptor.onGetBounds(node)
if (bounds != lastBounds) {
context.treeObserverManager.enqueueUpdate(
CoordinateUpdate(
this.type, LithoViewDescriptor.getId(node), Coordinate(bounds.x, bounds.y)))
lastBounds = bounds
}
}
preDrawListener =
ViewTreeObserver.OnPreDrawListener {
// this cases case 2
throttledCordinateUpdate(node)
true
}
node.viewTreeObserver.addOnPreDrawListener(preDrawListener)
// we have already missed the first mount so we trigger it manually on subscribe
lastBounds = LithoViewDescriptor.onGetBounds(node)
processUpdate(context, node)
}
override fun unsubscribe() {
Log.d(LogTag, "Unsubscribing from litho view ${nodeRef?.objectIdentity()}")
nodeRef?.viewTreeObserver?.removeOnPreDrawListener(preDrawListener)
nodeRef?.unregisterUIDebugger()
nodeRef = null
}
}
class LithoDebuggerExtension(val observer: LithoViewTreeObserver) : MountExtension<Void?, Void?>() {
override fun createState(): Void? {
return null
}
/**
* The call guaranteed to be called after new layout mounted completely on the main thread.
* mounting includes adding updating or removing views from the heriachy
*/
override fun afterMount(state: ExtensionState<Void?>) {
Log.i(LogTag, "After mount called for litho view ${observer.nodeRef?.objectIdentity()}")
observer.lastBounds = ViewDescriptor.onGetBounds(state.rootHost)
observer.processUpdate(observer.context, state.rootHost as Any)
}
}
object LithoViewTreeObserverBuilder : TreeObserverBuilder<LithoView> {
override fun canBuildFor(node: Any): Boolean {
return node is LithoView
}
override fun build(context: Context): TreeObserver<LithoView> {
return LithoViewTreeObserver(context)
}
}

View File

@@ -1,30 +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.descriptors.DescriptorRegister
import com.facebook.flipper.plugins.uidebugger.litho.descriptors.*
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverFactory
import com.facebook.litho.DebugComponent
import com.facebook.litho.LithoView
import com.facebook.litho.MatrixDrawable
import com.facebook.litho.widget.TextDrawable
const val LithoTag = "Litho"
object UIDebuggerLithoSupport {
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)
}
fun addObserver(observerFactory: TreeObserverFactory) {}
}

View File

@@ -0,0 +1,19 @@
/*
* 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.descriptors.DescriptorRegister
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverFactory
// this is not used internally
object UIDebuggerLithoSupport {
fun addDescriptors(register: DescriptorRegister) {}
fun addObserver(observerFactory: TreeObserverFactory) {}
}

View File

@@ -1,167 +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.descriptors
import android.graphics.Bitmap
import com.facebook.flipper.plugins.uidebugger.descriptors.*
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
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 mountedView = node.mountedView
val mountedDrawable = node.mountedDrawable
if (mountedView != null) {
val descriptor: NodeDescriptor<Any> = register.descriptorForClassUnsafe(mountedView.javaClass)
/**
* When we ask android for the bounds the x,y offset is w.r.t to the nearest android parent
* view group. From UI debuggers perspective using the raw android offset will double the
* total offset of this native view as the offset is included by the litho components between
* the mounted view and its native parent
*/
result.add(OffsetChild.zero(mountedView, descriptor))
} else if (mountedDrawable != null) {
/**
* don't emit mounted drawables since they are leaf nodes and its somewhat tricky to get the
* wireframe bounds to play nice. Something to address later if there is feedback
*/
} else {
for (child in node.childComponents) {
result.add(child)
}
}
return result
}
override fun getActiveChild(node: DebugComponent): Any? = null
private val LayoutId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, 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> = setOf(BaseTags.Declarative, LithoTag)
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
}
}

View File

@@ -1,49 +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.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.DebugComponent
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 result = mutableListOf<Any>()
val debugComponent = DebugComponent.getRootInstance(node)
if (debugComponent != null) {
result.add(debugComponent)
}
return result
}
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)))
}
}

View File

@@ -1,24 +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.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
}

View File

@@ -1,37 +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.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)
}
}

View File

@@ -1,179 +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.descriptors.props
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
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: EditorValue? =
EditorRegistry.read(declaredField.type, declaredField, component)
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 == "mStates"
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())
}
}

View File

@@ -1,427 +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.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_LAYOUT, NAMESPACE, "background")
private var ForegroundId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "foreground")
private val DirectionId =
MetadataRegister.register(
MetadataRegister.TYPE_LAYOUT,
NAMESPACE,
"direction",
false,
enumToInspectableSet<YogaDirection>())
private val FlexDirectionId =
MetadataRegister.register(
MetadataRegister.TYPE_LAYOUT,
NAMESPACE,
"flexDirection",
false,
enumToInspectableSet<YogaFlexDirection>())
private val JustifyContentId =
MetadataRegister.register(
MetadataRegister.TYPE_LAYOUT,
NAMESPACE,
"justifyContent",
false,
enumToInspectableSet<YogaJustify>())
private val AlignItemsId =
MetadataRegister.register(
MetadataRegister.TYPE_LAYOUT,
NAMESPACE,
"alignItems",
false,
enumToInspectableSet<YogaAlign>())
private val AlignSelfId =
MetadataRegister.register(
MetadataRegister.TYPE_LAYOUT,
NAMESPACE,
"alignSelf",
false,
enumToInspectableSet<YogaAlign>())
private val AlignContentId =
MetadataRegister.register(
MetadataRegister.TYPE_LAYOUT,
NAMESPACE,
"alignContent",
false,
enumToInspectableSet<YogaAlign>())
private val PositionTypeId =
MetadataRegister.register(
MetadataRegister.TYPE_LAYOUT,
NAMESPACE,
"positionType",
false,
enumToInspectableSet<YogaPositionType>())
private val FlexGrowId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "flexGrow")
private val FlexShrinkId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "flexShrink")
private val FlexBasisId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "flexBasis")
private val WidthId = MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "width")
private val HeightId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "height")
private val MinWidthId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "minWidth")
private val MinHeightId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "minHeight")
private val MaxWidthId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "maxWidth")
private val MaxHeightId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "maxHeight")
private val AspectRatioId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "aspectRatio")
private val MarginId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "margin")
private val PaddingId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "padding")
private val BorderId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "border")
private val PositionId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "position")
private val LeftId = MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "left")
private val TopId = MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "top")
private val RightId = MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "right")
private val BottomId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "bottom")
private val StartId = MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "start")
private val EndId = MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "end")
private val HorizontalId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "horizontal")
private val VerticalId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "vertical")
private val AllId = MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "all")
private val HasViewOutputId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "hasViewOutput")
private val AlphaId = MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "alpha")
private val ScaleId = MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "scale")
private val RotationId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "rotation")
private val EmptyId = MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "")
private val NoneId = MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "none")
private val SizeId = MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, NAMESPACE, "size")
private val ViewOutputId =
MetadataRegister.register(MetadataRegister.TYPE_LAYOUT, 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())
}
}