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:
committed by
Facebook GitHub Bot
parent
0414e145a9
commit
6deedabfb2
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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) {}
|
||||
}
|
||||
@@ -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) {}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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)))
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user