From 6deedabfb2034685e5d8afecaa89ecc4f8aeaf2e Mon Sep 17 00:00:00 2001 From: Luke De Feo Date: Mon, 19 Dec 2022 09:20:27 -0800 Subject: [PATCH] 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 --- .../plugins/uidebugger/litho/LithoObserver.kt | 126 ------ .../litho/UIDebuggerLithoSupport.kt | 30 -- .../litho/UIDebuggerLithoSupportStub.kt | 19 + .../descriptors/DebugComponentDescriptor.kt | 167 ------- .../litho/descriptors/LithoViewDescriptor.kt | 49 -- .../descriptors/MatrixDrawableDescriptor.kt | 24 - .../descriptors/TextDrawableDescriptor.kt | 37 -- .../props/ComponentDataExtractor.kt | 179 -------- .../descriptors/props/LayoutPropExtractor.kt | 427 ------------------ 9 files changed, 19 insertions(+), 1039 deletions(-) delete mode 100644 android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/LithoObserver.kt delete mode 100644 android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/UIDebuggerLithoSupport.kt create mode 100644 android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/UIDebuggerLithoSupportStub.kt delete mode 100644 android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/DebugComponentDescriptor.kt delete mode 100644 android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/LithoViewDescriptor.kt delete mode 100644 android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/MatrixDrawableDescriptor.kt delete mode 100644 android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/TextDrawableDescriptor.kt delete mode 100644 android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/props/ComponentDataExtractor.kt delete mode 100644 android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/props/LayoutPropExtractor.kt diff --git a/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/LithoObserver.kt b/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/LithoObserver.kt deleted file mode 100644 index af048f84b..000000000 --- a/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/LithoObserver.kt +++ /dev/null @@ -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() { - - 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(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() { - - 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) { - 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 { - override fun canBuildFor(node: Any): Boolean { - return node is LithoView - } - - override fun build(context: Context): TreeObserver { - return LithoViewTreeObserver(context) - } -} diff --git a/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/UIDebuggerLithoSupport.kt b/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/UIDebuggerLithoSupport.kt deleted file mode 100644 index d2bb0234a..000000000 --- a/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/UIDebuggerLithoSupport.kt +++ /dev/null @@ -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) {} -} diff --git a/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/UIDebuggerLithoSupportStub.kt b/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/UIDebuggerLithoSupportStub.kt new file mode 100644 index 000000000..ba428ef3b --- /dev/null +++ b/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/UIDebuggerLithoSupportStub.kt @@ -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) {} +} diff --git a/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/DebugComponentDescriptor.kt b/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/DebugComponentDescriptor.kt deleted file mode 100644 index 960fe56b6..000000000 --- a/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/DebugComponentDescriptor.kt +++ /dev/null @@ -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 { - 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 { - val result = mutableListOf() - - val mountedView = node.mountedView - val mountedDrawable = node.mountedDrawable - - if (mountedView != null) { - val descriptor: NodeDescriptor = 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> { - return Deferred { - val attributeSections = mutableMapOf() - - 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 = setOf(BaseTags.Declarative, LithoTag) - - override fun getSnapshot(node: DebugComponent, bitmap: Bitmap?): Bitmap? = null - - override fun getInlineAttributes(node: DebugComponent): Map { - val attributes = mutableMapOf() - 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 { - - val lithoView = node.lithoView - val mountingData = mutableMapOf() - - 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 - } -} diff --git a/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/LithoViewDescriptor.kt b/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/LithoViewDescriptor.kt deleted file mode 100644 index 48ae601e0..000000000 --- a/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/LithoViewDescriptor.kt +++ /dev/null @@ -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() { - - 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 { - val result = mutableListOf() - 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 - ) { - attributeSections[SectionId] = - InspectableObject( - mapOf( - IsIncrementalMountEnabledAttributeId to - InspectableValue.Boolean(node.isIncrementalMountEnabled))) - } -} diff --git a/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/MatrixDrawableDescriptor.kt b/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/MatrixDrawableDescriptor.kt deleted file mode 100644 index f6368c200..000000000 --- a/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/MatrixDrawableDescriptor.kt +++ /dev/null @@ -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>() { - - override fun onGetChildren(node: MatrixDrawable<*>): List? { - val mountedDrawable = node.mountedDrawable - return if (mountedDrawable != null) { - listOf(mountedDrawable) - } else { - listOf() - } - } - override fun onGetName(node: MatrixDrawable<*>): String = node.javaClass.simpleName -} diff --git a/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/TextDrawableDescriptor.kt b/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/TextDrawableDescriptor.kt deleted file mode 100644 index 842603704..000000000 --- a/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/TextDrawableDescriptor.kt +++ /dev/null @@ -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() { - - 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 - ) { - val props = - mapOf(TextAttributeId to InspectableValue.Text(node.text.toString())) - - attributeSections[SectionId] = InspectableObject(props) - } -} diff --git a/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/props/ComponentDataExtractor.kt b/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/props/ComponentDataExtractor.kt deleted file mode 100644 index 8808b17ae..000000000 --- a/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/props/ComponentDataExtractor.kt +++ /dev/null @@ -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 { - val props = mutableMapOf() - - 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() - 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? = 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, - namespace: String, - name: String, - value: EditorValue - ) { - var possibleValues: MutableSet? = 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 { - override fun isShape(shape: EditorShape): Inspectable { - - val fields = mutableMapOf() - shape.value.entries.forEach { entry -> - val value = toInspectable(entry.key, entry.value) - - val shapeEditorValue = entry.value - var possibleValues: MutableSet? = 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()) - } -} diff --git a/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/props/LayoutPropExtractor.kt b/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/props/LayoutPropExtractor.kt deleted file mode 100644 index 602bbd019..000000000 --- a/android/plugins/litho/src/main/java/com/facebook/flipper/plugins/uidebugger/litho/descriptors/props/LayoutPropExtractor.kt +++ /dev/null @@ -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()) - private val FlexDirectionId = - MetadataRegister.register( - MetadataRegister.TYPE_LAYOUT, - NAMESPACE, - "flexDirection", - false, - enumToInspectableSet()) - private val JustifyContentId = - MetadataRegister.register( - MetadataRegister.TYPE_LAYOUT, - NAMESPACE, - "justifyContent", - false, - enumToInspectableSet()) - private val AlignItemsId = - MetadataRegister.register( - MetadataRegister.TYPE_LAYOUT, - NAMESPACE, - "alignItems", - false, - enumToInspectableSet()) - private val AlignSelfId = - MetadataRegister.register( - MetadataRegister.TYPE_LAYOUT, - NAMESPACE, - "alignSelf", - false, - enumToInspectableSet()) - private val AlignContentId = - MetadataRegister.register( - MetadataRegister.TYPE_LAYOUT, - NAMESPACE, - "alignContent", - false, - enumToInspectableSet()) - private val PositionTypeId = - MetadataRegister.register( - MetadataRegister.TYPE_LAYOUT, - NAMESPACE, - "positionType", - false, - enumToInspectableSet()) - - 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() - - 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() - - 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 { - val props = mutableMapOf() - - 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 = 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 = 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()) - } -}