Move Litho Flipper Plugin to Litho
Summary: The current ownership and release model prevents cleanly releasing new versions of the plugin while the code is split between two repos. This diff moves the flipper-litho plugin to the Litho repository. You'll find new releases as `litho-editor-flipper` that'll be reexported via gradle's `api` to the old artifact. Reviewed By: colriot Differential Revision: D23962234 fbshipit-source-id: 7884423342904219ae9b41632c6df90cda870798
This commit is contained in:
committed by
Facebook GitHub Bot
parent
08fee986bd
commit
51293406d6
@@ -21,8 +21,8 @@ android {
|
||||
compileOnly deps.lithoAnnotations
|
||||
implementation project(':android')
|
||||
implementation deps.lithoCore
|
||||
implementation deps.lithoEditorCore
|
||||
implementation(deps.lithoEditorFlipper) {
|
||||
api deps.lithoEditorCore
|
||||
api(deps.lithoEditorFlipper) {
|
||||
exclude group:'com.facebook.flipper', module:'flipper'
|
||||
}
|
||||
implementation deps.lithoSectionsDebug
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its 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.litho;
|
||||
|
||||
import static com.facebook.flipper.plugins.inspector.InspectorValue.Type.Color;
|
||||
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import com.facebook.flipper.core.FlipperObject;
|
||||
import com.facebook.flipper.plugins.inspector.InspectorValue;
|
||||
import com.facebook.flipper.plugins.inspector.Named;
|
||||
import com.facebook.litho.StateContainer;
|
||||
import com.facebook.litho.annotations.Prop;
|
||||
import com.facebook.litho.annotations.State;
|
||||
import com.facebook.litho.drawable.ComparableColorDrawable;
|
||||
import com.facebook.litho.editor.flipper.FlipperEditor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class DataUtils {
|
||||
|
||||
static List<Named<FlipperObject>> getPropData(Object node) throws Exception {
|
||||
final FlipperObject.Builder props = new FlipperObject.Builder();
|
||||
List<Named<FlipperObject>> data = new ArrayList<>();
|
||||
|
||||
boolean hasProps = false;
|
||||
|
||||
for (Field f : node.getClass().getDeclaredFields()) {
|
||||
f.setAccessible(true);
|
||||
|
||||
final Prop annotation = f.getAnnotation(Prop.class);
|
||||
if (annotation != null) {
|
||||
if (f.get(node) != null
|
||||
&& PropWithInspectorSection.class.isAssignableFrom(f.get(node).getClass())) {
|
||||
final AbstractMap.SimpleEntry<String, String> datum =
|
||||
((PropWithInspectorSection) f.get(node)).getFlipperLayoutInspectorSection();
|
||||
if (datum != null) {
|
||||
data.add(new Named<>(datum.getKey(), new FlipperObject(datum.getValue())));
|
||||
}
|
||||
}
|
||||
|
||||
switch (annotation.resType()) {
|
||||
case COLOR:
|
||||
props.put(f.getName(), f.get(node) == null ? "null" : fromColor((Integer) f.get(node)));
|
||||
break;
|
||||
case DRAWABLE:
|
||||
props.put(
|
||||
f.getName(), f.get(node) == null ? "null" : fromDrawable((Drawable) f.get(node)));
|
||||
break;
|
||||
default:
|
||||
if (f.get(node) != null
|
||||
&& PropWithDescription.class.isAssignableFrom(f.get(node).getClass())) {
|
||||
final Object description =
|
||||
((PropWithDescription) f.get(node)).getFlipperLayoutInspectorPropDescription();
|
||||
// Treat the description as immutable for now, because it's a "translation" of the
|
||||
// actual prop,
|
||||
// mutating them is not going to change the original prop.
|
||||
if (description instanceof Map<?, ?>) {
|
||||
final Map<?, ?> descriptionMap = (Map<?, ?>) description;
|
||||
for (Map.Entry<?, ?> entry : descriptionMap.entrySet()) {
|
||||
props.put(entry.getKey().toString(), InspectorValue.immutable(entry.getValue()));
|
||||
}
|
||||
} else {
|
||||
props.put(f.getName(), InspectorValue.immutable(description));
|
||||
}
|
||||
} else {
|
||||
props.put(f.getName(), FlipperEditor.makeFlipperField(node, f));
|
||||
}
|
||||
break;
|
||||
}
|
||||
hasProps = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasProps) {
|
||||
data.add(new Named<>("Props", props.build()));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static FlipperObject getStateData(StateContainer stateContainer) {
|
||||
if (stateContainer == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final FlipperObject.Builder state = new FlipperObject.Builder();
|
||||
|
||||
boolean hasState = false;
|
||||
for (Field f : stateContainer.getClass().getDeclaredFields()) {
|
||||
f.setAccessible(true);
|
||||
|
||||
final State annotation = f.getAnnotation(State.class);
|
||||
if (annotation != null) {
|
||||
state.put(f.getName(), FlipperEditor.makeFlipperField(stateContainer, f));
|
||||
hasState = true;
|
||||
}
|
||||
}
|
||||
|
||||
return hasState ? state.build() : null;
|
||||
}
|
||||
|
||||
static InspectorValue fromDrawable(Drawable d) {
|
||||
int color = 0;
|
||||
if (d instanceof ColorDrawable) {
|
||||
color = ((ColorDrawable) d).getColor();
|
||||
} else if (d instanceof ComparableColorDrawable) {
|
||||
color = ((ComparableColorDrawable) d).getColor();
|
||||
}
|
||||
return InspectorValue.mutable(Color, color);
|
||||
}
|
||||
|
||||
static InspectorValue fromColor(int color) {
|
||||
return InspectorValue.mutable(Color, color);
|
||||
}
|
||||
}
|
||||
@@ -1,598 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its 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.litho;
|
||||
|
||||
import static com.facebook.flipper.plugins.inspector.InspectorValue.Type.Boolean;
|
||||
import static com.facebook.flipper.plugins.inspector.InspectorValue.Type.Enum;
|
||||
import static com.facebook.flipper.plugins.inspector.InspectorValue.Type.Number;
|
||||
import static com.facebook.flipper.plugins.inspector.InspectorValue.Type.Picker;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import androidx.core.util.Pair;
|
||||
import com.facebook.flipper.core.FlipperDynamic;
|
||||
import com.facebook.flipper.core.FlipperObject;
|
||||
import com.facebook.flipper.plugins.inspector.HighlightedOverlay;
|
||||
import com.facebook.flipper.plugins.inspector.InspectorValue;
|
||||
import com.facebook.flipper.plugins.inspector.Named;
|
||||
import com.facebook.flipper.plugins.inspector.NodeDescriptor;
|
||||
import com.facebook.flipper.plugins.inspector.SetDataOperations;
|
||||
import com.facebook.flipper.plugins.inspector.Touch;
|
||||
import com.facebook.flipper.plugins.inspector.descriptors.ObjectDescriptor;
|
||||
import com.facebook.flipper.plugins.inspector.descriptors.utils.ContextDescriptorUtils;
|
||||
import com.facebook.litho.Component;
|
||||
import com.facebook.litho.DebugComponent;
|
||||
import com.facebook.litho.DebugLayoutNode;
|
||||
import com.facebook.litho.LithoView;
|
||||
import com.facebook.litho.StateContainer;
|
||||
import com.facebook.litho.editor.flipper.FlipperEditor;
|
||||
import com.facebook.yoga.YogaAlign;
|
||||
import com.facebook.yoga.YogaDirection;
|
||||
import com.facebook.yoga.YogaEdge;
|
||||
import com.facebook.yoga.YogaFlexDirection;
|
||||
import com.facebook.yoga.YogaJustify;
|
||||
import com.facebook.yoga.YogaPositionType;
|
||||
import com.facebook.yoga.YogaValue;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class DebugComponentDescriptor extends NodeDescriptor<DebugComponent> {
|
||||
|
||||
private Map<
|
||||
String, List<Pair<String[], Pair<SetDataOperations.FlipperValueHint, FlipperDynamic>>>>
|
||||
mOverrides = new HashMap<>();
|
||||
private DebugComponent.Overrider mOverrider =
|
||||
new DebugComponent.Overrider() {
|
||||
@Override
|
||||
public void applyComponentOverrides(String key, Component component) {
|
||||
final List<Pair<String[], Pair<SetDataOperations.FlipperValueHint, FlipperDynamic>>>
|
||||
overrides = mOverrides.get(key);
|
||||
if (overrides == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Pair<String[], Pair<SetDataOperations.FlipperValueHint, FlipperDynamic>> override :
|
||||
overrides) {
|
||||
if (override.first[0].equals("Props")) {
|
||||
applyReflectiveOverride(
|
||||
component, override.first, override.second.first, override.second.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyStateOverrides(String key, StateContainer stateContainer) {
|
||||
final List<Pair<String[], Pair<SetDataOperations.FlipperValueHint, FlipperDynamic>>>
|
||||
overrides = mOverrides.get(key);
|
||||
if (overrides == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Pair<String[], Pair<SetDataOperations.FlipperValueHint, FlipperDynamic>> override :
|
||||
overrides) {
|
||||
if (override.first[0].equals("State")) {
|
||||
applyReflectiveOverride(
|
||||
stateContainer, override.first, override.second.first, override.second.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyLayoutOverrides(String key, DebugLayoutNode node) {
|
||||
final List<Pair<String[], Pair<SetDataOperations.FlipperValueHint, FlipperDynamic>>>
|
||||
overrides = mOverrides.get(key);
|
||||
if (overrides == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Pair<String[], Pair<SetDataOperations.FlipperValueHint, FlipperDynamic>> override :
|
||||
overrides) {
|
||||
if (override.first[0].equals("Layout")) {
|
||||
try {
|
||||
applyLayoutOverride(
|
||||
node,
|
||||
Arrays.copyOfRange(override.first, 1, override.first.length),
|
||||
override.second.second);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void init(DebugComponent node) {
|
||||
// We rely on the LithoView being invalidated when a component hierarchy changes.
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId(DebugComponent node) {
|
||||
return node.getGlobalKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName(DebugComponent node) throws Exception {
|
||||
NodeDescriptor componentDescriptor = descriptorForClass(node.getComponent().getClass());
|
||||
if (componentDescriptor.getClass() != ObjectDescriptor.class) {
|
||||
return componentDescriptor.getName(node.getComponent());
|
||||
}
|
||||
return node.getComponent().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildCount(DebugComponent node) {
|
||||
if (node.getMountedView() != null || node.getMountedDrawable() != null) {
|
||||
return 1;
|
||||
} else {
|
||||
return node.getChildComponents().size();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getChildAt(DebugComponent node, int index) {
|
||||
final View mountedView = node.getMountedView();
|
||||
final Drawable mountedDrawable = node.getMountedDrawable();
|
||||
|
||||
if (mountedView != null) {
|
||||
return mountedView;
|
||||
} else if (mountedDrawable != null) {
|
||||
return mountedDrawable;
|
||||
} else {
|
||||
return node.getChildComponents().get(index);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Named<FlipperObject>> getData(DebugComponent node) throws Exception {
|
||||
NodeDescriptor componentDescriptor = descriptorForClass(node.getComponent().getClass());
|
||||
if (componentDescriptor.getClass() != ObjectDescriptor.class) {
|
||||
return componentDescriptor.getData(node.getComponent());
|
||||
}
|
||||
|
||||
final List<Named<FlipperObject>> data = new ArrayList<>();
|
||||
|
||||
final FlipperObject layoutData = getLayoutData(node);
|
||||
if (layoutData != null) {
|
||||
data.add(new Named<>("Layout", layoutData));
|
||||
}
|
||||
|
||||
final List<Named<FlipperObject>> propData = getPropData(node);
|
||||
if (propData != null) {
|
||||
data.addAll(propData);
|
||||
}
|
||||
|
||||
final FlipperObject stateData = getStateData(node);
|
||||
if (stateData != null) {
|
||||
data.add(new Named<>("State", stateData));
|
||||
}
|
||||
|
||||
data.add(
|
||||
new Named<>(
|
||||
"Theme", ContextDescriptorUtils.themeData(node.getContext().getAndroidContext())));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static FlipperObject getLayoutData(DebugComponent node) {
|
||||
final DebugLayoutNode layout = node.getLayoutNode();
|
||||
if (layout == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final FlipperObject.Builder data = new FlipperObject.Builder();
|
||||
data.put("<PLAYGROUND>", InspectorValue.immutable("https://yogalayout.com/playground/"));
|
||||
|
||||
data.put("background", DataUtils.fromDrawable(layout.getBackground()));
|
||||
data.put("foreground", DataUtils.fromDrawable(layout.getForeground()));
|
||||
|
||||
data.put(
|
||||
"direction",
|
||||
InspectorValue.mutable(
|
||||
Picker,
|
||||
new InspectorValue.Picker(
|
||||
enumToSet(YogaDirection.values()), layout.getLayoutDirection().name())));
|
||||
data.put(
|
||||
"flex-direction",
|
||||
InspectorValue.mutable(
|
||||
Picker,
|
||||
new InspectorValue.Picker(
|
||||
enumToSet(YogaFlexDirection.values()), layout.getFlexDirection().name())));
|
||||
data.put(
|
||||
"justify-content",
|
||||
InspectorValue.mutable(
|
||||
Picker,
|
||||
new InspectorValue.Picker(
|
||||
enumToSet(YogaJustify.values()), layout.getJustifyContent().name())));
|
||||
data.put(
|
||||
"align-items",
|
||||
InspectorValue.mutable(
|
||||
Picker,
|
||||
new InspectorValue.Picker(
|
||||
enumToSet(YogaAlign.values()), layout.getAlignItems().name())));
|
||||
data.put(
|
||||
"align-self",
|
||||
InspectorValue.mutable(
|
||||
Picker,
|
||||
new InspectorValue.Picker(
|
||||
enumToSet(YogaAlign.values()), layout.getAlignSelf().name())));
|
||||
data.put(
|
||||
"align-content",
|
||||
InspectorValue.mutable(
|
||||
Picker,
|
||||
new InspectorValue.Picker(
|
||||
enumToSet(YogaAlign.values()), layout.getAlignContent().name())));
|
||||
data.put(
|
||||
"position-type",
|
||||
InspectorValue.mutable(
|
||||
Picker,
|
||||
new InspectorValue.Picker(
|
||||
enumToSet(YogaPositionType.values()), layout.getPositionType().name())));
|
||||
|
||||
data.put("flex-grow", fromFloat(layout.getFlexGrow()));
|
||||
data.put("flex-shrink", fromFloat(layout.getFlexShrink()));
|
||||
data.put("flex-basis", fromYogaValue(layout.getFlexBasis()));
|
||||
|
||||
data.put("width", fromYogaValue(layout.getWidth()));
|
||||
data.put("min-width", fromYogaValue(layout.getMinWidth()));
|
||||
data.put("max-width", fromYogaValue(layout.getMaxWidth()));
|
||||
|
||||
data.put("height", fromYogaValue(layout.getHeight()));
|
||||
data.put("min-height", fromYogaValue(layout.getMinHeight()));
|
||||
data.put("max-height", fromYogaValue(layout.getMaxHeight()));
|
||||
|
||||
data.put("aspect-ratio", fromFloat(layout.getAspectRatio()));
|
||||
|
||||
data.put(
|
||||
"margin",
|
||||
new FlipperObject.Builder()
|
||||
.put("left", fromYogaValue(layout.getMargin(YogaEdge.LEFT)))
|
||||
.put("top", fromYogaValue(layout.getMargin(YogaEdge.TOP)))
|
||||
.put("right", fromYogaValue(layout.getMargin(YogaEdge.RIGHT)))
|
||||
.put("bottom", fromYogaValue(layout.getMargin(YogaEdge.BOTTOM)))
|
||||
.put("start", fromYogaValue(layout.getMargin(YogaEdge.START)))
|
||||
.put("end", fromYogaValue(layout.getMargin(YogaEdge.END)))
|
||||
.put("horizontal", fromYogaValue(layout.getMargin(YogaEdge.HORIZONTAL)))
|
||||
.put("vertical", fromYogaValue(layout.getMargin(YogaEdge.VERTICAL)))
|
||||
.put("all", fromYogaValue(layout.getMargin(YogaEdge.ALL))));
|
||||
|
||||
data.put(
|
||||
"padding",
|
||||
new FlipperObject.Builder()
|
||||
.put("left", fromYogaValue(layout.getPadding(YogaEdge.LEFT)))
|
||||
.put("top", fromYogaValue(layout.getPadding(YogaEdge.TOP)))
|
||||
.put("right", fromYogaValue(layout.getPadding(YogaEdge.RIGHT)))
|
||||
.put("bottom", fromYogaValue(layout.getPadding(YogaEdge.BOTTOM)))
|
||||
.put("start", fromYogaValue(layout.getPadding(YogaEdge.START)))
|
||||
.put("end", fromYogaValue(layout.getPadding(YogaEdge.END)))
|
||||
.put("horizontal", fromYogaValue(layout.getPadding(YogaEdge.HORIZONTAL)))
|
||||
.put("vertical", fromYogaValue(layout.getPadding(YogaEdge.VERTICAL)))
|
||||
.put("all", fromYogaValue(layout.getPadding(YogaEdge.ALL))));
|
||||
|
||||
data.put(
|
||||
"border",
|
||||
new FlipperObject.Builder()
|
||||
.put("left", fromFloat(layout.getBorderWidth(YogaEdge.LEFT)))
|
||||
.put("top", fromFloat(layout.getBorderWidth(YogaEdge.TOP)))
|
||||
.put("right", fromFloat(layout.getBorderWidth(YogaEdge.RIGHT)))
|
||||
.put("bottom", fromFloat(layout.getBorderWidth(YogaEdge.BOTTOM)))
|
||||
.put("start", fromFloat(layout.getBorderWidth(YogaEdge.START)))
|
||||
.put("end", fromFloat(layout.getBorderWidth(YogaEdge.END)))
|
||||
.put("horizontal", fromFloat(layout.getBorderWidth(YogaEdge.HORIZONTAL)))
|
||||
.put("vertical", fromFloat(layout.getBorderWidth(YogaEdge.VERTICAL)))
|
||||
.put("all", fromFloat(layout.getBorderWidth(YogaEdge.ALL))));
|
||||
|
||||
data.put(
|
||||
"position",
|
||||
new FlipperObject.Builder()
|
||||
.put("left", fromYogaValue(layout.getPosition(YogaEdge.LEFT)))
|
||||
.put("top", fromYogaValue(layout.getPosition(YogaEdge.TOP)))
|
||||
.put("right", fromYogaValue(layout.getPosition(YogaEdge.RIGHT)))
|
||||
.put("bottom", fromYogaValue(layout.getPosition(YogaEdge.BOTTOM)))
|
||||
.put("start", fromYogaValue(layout.getPosition(YogaEdge.START)))
|
||||
.put("end", fromYogaValue(layout.getPosition(YogaEdge.END)))
|
||||
.put("horizontal", fromYogaValue(layout.getPosition(YogaEdge.HORIZONTAL)))
|
||||
.put("vertical", fromYogaValue(layout.getPosition(YogaEdge.VERTICAL)))
|
||||
.put("all", fromYogaValue(layout.getPosition(YogaEdge.ALL))));
|
||||
|
||||
data.put("hasViewOutput", InspectorValue.immutable(Boolean, layout.hasViewOutput()));
|
||||
if (layout.hasViewOutput()) {
|
||||
data.put("alpha", fromFloat(layout.getAlpha()));
|
||||
data.put("scale", fromFloat(layout.getScale()));
|
||||
data.put("rotation", fromFloat(layout.getRotation()));
|
||||
}
|
||||
|
||||
return data.build();
|
||||
}
|
||||
|
||||
private static <E extends Enum<E>> HashSet<String> enumToSet(Enum<E>[] enums) {
|
||||
final HashSet<String> names = new HashSet<>();
|
||||
for (Enum<E> aEnum : enums) {
|
||||
names.add(aEnum.name());
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static List<Named<FlipperObject>> getPropData(DebugComponent node) throws Exception {
|
||||
if (node.canResolve()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Component component = node.getComponent();
|
||||
return DataUtils.getPropData(component);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static FlipperObject getStateData(DebugComponent node) {
|
||||
return DataUtils.getStateData(node.getStateContainer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(
|
||||
DebugComponent node,
|
||||
String[] path,
|
||||
@Nullable SetDataOperations.FlipperValueHint kind,
|
||||
FlipperDynamic value) {
|
||||
List<Pair<String[], Pair<SetDataOperations.FlipperValueHint, FlipperDynamic>>> overrides =
|
||||
mOverrides.get(node.getGlobalKey());
|
||||
if (overrides == null) {
|
||||
overrides = new ArrayList<>();
|
||||
mOverrides.put(node.getGlobalKey(), overrides);
|
||||
}
|
||||
overrides.add(new Pair<>(path, new Pair<>(kind, value)));
|
||||
|
||||
node.setOverrider(mOverrider);
|
||||
node.rerender();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Named<String>> getAttributes(DebugComponent node) {
|
||||
final List<Named<String>> attributes = new ArrayList<>();
|
||||
final String key = node.getKey();
|
||||
final String testKey = node.getTestKey();
|
||||
|
||||
if (key != null && key.trim().length() > 0) {
|
||||
attributes.add(new Named<>("key", key));
|
||||
}
|
||||
|
||||
if (testKey != null && testKey.trim().length() > 0) {
|
||||
attributes.add(new Named<>("testKey", testKey));
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlipperObject getExtraInfo(DebugComponent node) {
|
||||
FlipperObject.Builder extraInfo = new FlipperObject.Builder();
|
||||
final NodeDescriptor descriptor = descriptorForClass(View.class);
|
||||
final View hostView = node.getComponentHost();
|
||||
final View lithoView = node.getLithoView();
|
||||
|
||||
if (hostView != null) {
|
||||
try {
|
||||
extraInfo.put("linkedNode", descriptor.getId(hostView));
|
||||
} catch (Exception ignored) {
|
||||
// doesn't have linked node descriptor
|
||||
}
|
||||
} else if (lithoView != null) {
|
||||
try {
|
||||
extraInfo.put("linkedNode", descriptor.getId(lithoView)).put("expandWithParent", true);
|
||||
} catch (Exception ignored) {
|
||||
// doesn't add linked node descriptor
|
||||
}
|
||||
}
|
||||
final FlipperObject.Builder metaData = new FlipperObject.Builder();
|
||||
metaData.put("className", node.getComponent().getClass().getName());
|
||||
metaData.put("framework", "LITHO");
|
||||
|
||||
extraInfo.put("metaData", metaData);
|
||||
|
||||
return extraInfo.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHighlighted(DebugComponent node, boolean selected, boolean isAlignmentMode) {
|
||||
final LithoView lithoView = node.getLithoView();
|
||||
if (lithoView == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!selected) {
|
||||
HighlightedOverlay.removeHighlight(lithoView);
|
||||
return;
|
||||
}
|
||||
|
||||
final DebugLayoutNode layout = node.getLayoutNode();
|
||||
final boolean hasNode = layout != null;
|
||||
final Rect margin;
|
||||
if (!node.isRoot()) {
|
||||
margin =
|
||||
new Rect(
|
||||
hasNode ? (int) layout.getResultMargin(YogaEdge.START) : 0,
|
||||
hasNode ? (int) layout.getResultMargin(YogaEdge.TOP) : 0,
|
||||
hasNode ? (int) layout.getResultMargin(YogaEdge.END) : 0,
|
||||
hasNode ? (int) layout.getResultMargin(YogaEdge.BOTTOM) : 0);
|
||||
} else {
|
||||
// Margin not applied if you're at the root
|
||||
margin = new Rect();
|
||||
}
|
||||
|
||||
final Rect padding =
|
||||
new Rect(
|
||||
hasNode ? (int) layout.getResultPadding(YogaEdge.START) : 0,
|
||||
hasNode ? (int) layout.getResultPadding(YogaEdge.TOP) : 0,
|
||||
hasNode ? (int) layout.getResultPadding(YogaEdge.END) : 0,
|
||||
hasNode ? (int) layout.getResultPadding(YogaEdge.BOTTOM) : 0);
|
||||
|
||||
final Rect contentBounds = node.getBoundsInLithoView();
|
||||
HighlightedOverlay.setHighlighted(lithoView, margin, padding, contentBounds, isAlignmentMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hitTest(DebugComponent node, Touch touch) {
|
||||
boolean finish = true;
|
||||
for (int i = getChildCount(node) - 1; i >= 0; i--) {
|
||||
final Object child = getChildAt(node, i);
|
||||
if (child instanceof DebugComponent) {
|
||||
final DebugComponent componentChild = (DebugComponent) child;
|
||||
final Rect bounds = componentChild.getBounds();
|
||||
|
||||
if (touch.containedIn(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
|
||||
touch.continueWithOffset(i, bounds.left, bounds.top);
|
||||
finish = false;
|
||||
}
|
||||
} else if (child instanceof View || child instanceof Drawable) {
|
||||
// Components can only mount one view or drawable and its bounds are the same as the
|
||||
// hosting component.
|
||||
touch.continueWithOffset(i, 0, 0);
|
||||
finish = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (finish) touch.finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDecoration(DebugComponent node) throws Exception {
|
||||
if (node.getComponent() != null) {
|
||||
NodeDescriptor componentDescriptor = descriptorForClass(node.getComponent().getClass());
|
||||
if (componentDescriptor.getClass() != ObjectDescriptor.class) {
|
||||
return componentDescriptor.getDecoration(node.getComponent());
|
||||
}
|
||||
}
|
||||
return "litho";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(String query, DebugComponent node) throws Exception {
|
||||
NodeDescriptor descriptor = descriptorForClass(Object.class);
|
||||
return descriptor.matches(query, node) || getId(node).equals(query);
|
||||
}
|
||||
|
||||
private static void applyLayoutOverride(
|
||||
DebugLayoutNode node, String[] path, FlipperDynamic value) {
|
||||
switch (path[0]) {
|
||||
case "background":
|
||||
node.setBackgroundColor(value.asInt());
|
||||
break;
|
||||
case "foreground":
|
||||
node.setForegroundColor(value.asInt());
|
||||
break;
|
||||
case "direction":
|
||||
node.setLayoutDirection(YogaDirection.valueOf(value.asString().toUpperCase()));
|
||||
break;
|
||||
case "flex-direction":
|
||||
node.setFlexDirection(YogaFlexDirection.valueOf(value.asString().toUpperCase()));
|
||||
break;
|
||||
case "justify-content":
|
||||
node.setJustifyContent(YogaJustify.valueOf(value.asString().toUpperCase()));
|
||||
break;
|
||||
case "align-items":
|
||||
node.setAlignItems(YogaAlign.valueOf(value.asString().toUpperCase()));
|
||||
break;
|
||||
case "align-self":
|
||||
node.setAlignSelf(YogaAlign.valueOf(value.asString().toUpperCase()));
|
||||
break;
|
||||
case "align-content":
|
||||
node.setAlignContent(YogaAlign.valueOf(value.asString().toUpperCase()));
|
||||
break;
|
||||
case "position-type":
|
||||
node.setPositionType(YogaPositionType.valueOf(value.asString().toUpperCase()));
|
||||
break;
|
||||
case "flex-grow":
|
||||
node.setFlexGrow(value.asFloat());
|
||||
break;
|
||||
case "flex-shrink":
|
||||
node.setFlexShrink(value.asFloat());
|
||||
break;
|
||||
case "flex-basis":
|
||||
node.setFlexBasis(YogaValue.parse(value.asString()));
|
||||
break;
|
||||
case "width":
|
||||
node.setWidth(YogaValue.parse(value.asString()));
|
||||
break;
|
||||
case "min-width":
|
||||
node.setMinWidth(YogaValue.parse(value.asString()));
|
||||
break;
|
||||
case "max-width":
|
||||
node.setMaxWidth(YogaValue.parse(value.asString()));
|
||||
break;
|
||||
case "height":
|
||||
node.setHeight(YogaValue.parse(value.asString()));
|
||||
break;
|
||||
case "min-height":
|
||||
node.setMinHeight(YogaValue.parse(value.asString()));
|
||||
break;
|
||||
case "max-height":
|
||||
node.setMaxHeight(YogaValue.parse(value.asString()));
|
||||
break;
|
||||
case "aspect-ratio":
|
||||
node.setAspectRatio(value.asFloat());
|
||||
break;
|
||||
case "margin":
|
||||
node.setMargin(edgeFromString(path[1]), YogaValue.parse(value.asString()));
|
||||
break;
|
||||
case "padding":
|
||||
node.setPadding(edgeFromString(path[1]), YogaValue.parse(value.asString()));
|
||||
break;
|
||||
case "border":
|
||||
node.setBorderWidth(edgeFromString(path[1]), value.asFloat());
|
||||
break;
|
||||
case "position":
|
||||
node.setPosition(edgeFromString(path[1]), YogaValue.parse(value.asString()));
|
||||
break;
|
||||
case "alpha":
|
||||
node.setAlpha(value.asFloat());
|
||||
break;
|
||||
case "scale":
|
||||
node.setScale(value.asFloat());
|
||||
break;
|
||||
case "rotation":
|
||||
node.setRotation(value.asFloat());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static YogaEdge edgeFromString(String s) {
|
||||
return YogaEdge.valueOf(s.toUpperCase());
|
||||
}
|
||||
|
||||
// The path follows the pattern (Props|State)/field/(field|index)*
|
||||
private static void applyReflectiveOverride(
|
||||
Object o,
|
||||
final String[] path,
|
||||
@Nullable SetDataOperations.FlipperValueHint hint,
|
||||
final FlipperDynamic dynamic) {
|
||||
try {
|
||||
final Field field = o.getClass().getDeclaredField(path[1]);
|
||||
FlipperEditor.updateComponent(path, field, o, hint, dynamic);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private static InspectorValue fromFloat(float f) {
|
||||
if (Float.isNaN(f)) {
|
||||
return InspectorValue.mutable(Enum, "undefined");
|
||||
}
|
||||
return InspectorValue.mutable(Number, f);
|
||||
}
|
||||
|
||||
static InspectorValue fromYogaValue(YogaValue v) {
|
||||
// TODO add support for Type.Dimension or similar
|
||||
return InspectorValue.mutable(Enum, v.toString());
|
||||
}
|
||||
}
|
||||
@@ -1,238 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its 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.litho;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.core.view.MarginLayoutParamsCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import com.facebook.flipper.core.ErrorReportingRunnable;
|
||||
import com.facebook.flipper.core.FlipperDynamic;
|
||||
import com.facebook.flipper.core.FlipperObject;
|
||||
import com.facebook.flipper.plugins.inspector.HighlightedOverlay;
|
||||
import com.facebook.flipper.plugins.inspector.Named;
|
||||
import com.facebook.flipper.plugins.inspector.NodeDescriptor;
|
||||
import com.facebook.flipper.plugins.inspector.SetDataOperations;
|
||||
import com.facebook.flipper.plugins.inspector.Touch;
|
||||
import com.facebook.litho.sections.Section;
|
||||
import com.facebook.litho.sections.debug.DebugSection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class DebugSectionDescriptor extends NodeDescriptor<DebugSection> {
|
||||
|
||||
@Override
|
||||
public void invalidate(final DebugSection debugSection) {
|
||||
super.invalidate(debugSection);
|
||||
|
||||
new ErrorReportingRunnable(mConnection) {
|
||||
@Override
|
||||
protected void runOrThrow() throws Exception {
|
||||
for (int i = 0; i < getChildCount(debugSection); i++) {
|
||||
Object child = getChildAt(debugSection, i);
|
||||
if (child instanceof DebugSection) {
|
||||
invalidate((DebugSection) child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(DebugSection node) throws Exception {}
|
||||
|
||||
@Override
|
||||
public String getId(DebugSection node) throws Exception {
|
||||
return node.getGlobalKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName(DebugSection node) throws Exception {
|
||||
return node.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildCount(DebugSection node) throws Exception {
|
||||
return node.getSectionChildren().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getChildAt(DebugSection node, int index) throws Exception {
|
||||
return node.getSectionChildren().get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Named<FlipperObject>> getData(DebugSection node) throws Exception {
|
||||
// TODO T39526148 add changeset info
|
||||
final List<Named<FlipperObject>> data = new ArrayList<>();
|
||||
|
||||
final List<Named<FlipperObject>> propData = getPropData(node);
|
||||
if (propData != null) {
|
||||
data.addAll(propData);
|
||||
}
|
||||
|
||||
final FlipperObject stateData = getStateData(node);
|
||||
if (stateData != null) {
|
||||
data.add(new Named<>("State", stateData));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private static @Nullable List<Named<FlipperObject>> getPropData(DebugSection node)
|
||||
throws Exception {
|
||||
final Section section = node.getSection();
|
||||
return DataUtils.getPropData(section);
|
||||
}
|
||||
|
||||
private static @Nullable FlipperObject getStateData(DebugSection node) {
|
||||
return DataUtils.getStateData(node.getStateContainer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(
|
||||
DebugSection node,
|
||||
String[] path,
|
||||
@Nullable SetDataOperations.FlipperValueHint kind,
|
||||
FlipperDynamic value)
|
||||
throws Exception {
|
||||
// TODO T39526148
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Named<String>> getAttributes(DebugSection node) throws Exception {
|
||||
// TODO T39526148
|
||||
final List<Named<String>> attrs = new ArrayList<>();
|
||||
return attrs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlipperObject getExtraInfo(DebugSection node) {
|
||||
FlipperObject.Builder extraInfo = new FlipperObject.Builder();
|
||||
|
||||
final FlipperObject.Builder metaData = new FlipperObject.Builder();
|
||||
metaData.put("className", node.getSection().getClass().getName());
|
||||
metaData.put("framework", "LITHO");
|
||||
|
||||
extraInfo.put("metaData", metaData);
|
||||
|
||||
return extraInfo.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHighlighted(DebugSection node, boolean selected, boolean isAlignmentMode)
|
||||
throws Exception {
|
||||
final int childCount = getChildCount(node);
|
||||
|
||||
if (node.isDiffSectionSpec()) {
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View view = (View) getChildAt(node, i);
|
||||
highlightChildView(view, selected, isAlignmentMode);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final Object child = getChildAt(node, i);
|
||||
final NodeDescriptor descriptor = descriptorForClass(child.getClass());
|
||||
descriptor.setHighlighted(child, selected, isAlignmentMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is similar to the implementation in ViewDescriptor but doesn't
|
||||
// target the parent view.
|
||||
private void highlightChildView(View node, boolean selected, boolean isAlignmentMode) {
|
||||
if (!selected) {
|
||||
HighlightedOverlay.removeHighlight(node);
|
||||
return;
|
||||
}
|
||||
|
||||
final Rect padding =
|
||||
new Rect(
|
||||
ViewCompat.getPaddingStart(node),
|
||||
node.getPaddingTop(),
|
||||
ViewCompat.getPaddingEnd(node),
|
||||
node.getPaddingBottom());
|
||||
|
||||
final Rect margin;
|
||||
final ViewGroup.LayoutParams params = node.getLayoutParams();
|
||||
if (params instanceof ViewGroup.MarginLayoutParams) {
|
||||
final ViewGroup.MarginLayoutParams marginParams = (ViewGroup.MarginLayoutParams) params;
|
||||
margin =
|
||||
new Rect(
|
||||
MarginLayoutParamsCompat.getMarginStart(marginParams),
|
||||
marginParams.topMargin,
|
||||
MarginLayoutParamsCompat.getMarginEnd(marginParams),
|
||||
marginParams.bottomMargin);
|
||||
} else {
|
||||
margin = new Rect();
|
||||
}
|
||||
|
||||
final int left = node.getLeft();
|
||||
final int top = node.getTop();
|
||||
|
||||
final Rect contentBounds = new Rect(left, top, left + node.getWidth(), top + node.getHeight());
|
||||
|
||||
contentBounds.offset(-left, -top);
|
||||
|
||||
HighlightedOverlay.setHighlighted(node, margin, padding, contentBounds, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hitTest(DebugSection node, Touch touch) throws Exception {
|
||||
final int childCount = getChildCount(node);
|
||||
|
||||
// For a DiffSectionSpec, check if child view to see if the touch is in its bounds.
|
||||
// For a GroupSectionSpec, check the bounds of the entire section.
|
||||
boolean finish = true;
|
||||
if (node.isDiffSectionSpec()) {
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
View child = (View) getChildAt(node, i);
|
||||
int left = child.getLeft() + (int) child.getTranslationX();
|
||||
int top = (child.getTop() + (int) child.getTranslationY());
|
||||
int right = (child.getRight() + (int) child.getTranslationX());
|
||||
int bottom = (child.getBottom() + (int) child.getTranslationY());
|
||||
|
||||
final boolean hit = touch.containedIn(left, top, right, bottom);
|
||||
if (hit) {
|
||||
touch.continueWithOffset(i, left, top);
|
||||
finish = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
DebugSection child = (DebugSection) getChildAt(node, i);
|
||||
Rect bounds = child.getBounds();
|
||||
final boolean hit = touch.containedIn(bounds.left, bounds.top, bounds.right, bounds.bottom);
|
||||
if (hit) {
|
||||
touch.continueWithOffset(i, 0, 0);
|
||||
finish = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (finish) touch.finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDecoration(DebugSection node) throws Exception {
|
||||
// TODO T39526148
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(String query, DebugSection node) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(Object.class);
|
||||
return descriptor.matches(query, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAXChildCount(DebugSection node) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its 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.litho;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import com.facebook.flipper.core.FlipperConnection;
|
||||
import com.facebook.flipper.core.FlipperObject;
|
||||
import com.facebook.flipper.core.FlipperReceiver;
|
||||
import com.facebook.flipper.core.FlipperResponder;
|
||||
import com.facebook.flipper.plugins.common.MainThreadFlipperReceiver;
|
||||
import com.facebook.flipper.plugins.inspector.ApplicationWrapper;
|
||||
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.inspector.ObjectTracker;
|
||||
import com.facebook.litho.LithoView;
|
||||
import java.util.Stack;
|
||||
|
||||
public final class GenerateLithoAccessibilityRenderExtensionCommand
|
||||
implements InspectorFlipperPlugin.ExtensionCommand {
|
||||
|
||||
@Override
|
||||
public String command() {
|
||||
return "forceLithoAXRender";
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlipperReceiver receiver(final ObjectTracker tracker, final FlipperConnection connection) {
|
||||
return new MainThreadFlipperReceiver() {
|
||||
@Override
|
||||
public void onReceiveOnMainThread(
|
||||
final FlipperObject params, final FlipperResponder responder) throws Exception {
|
||||
final String applicationId = params.getString("applicationId");
|
||||
|
||||
// check that the application is valid
|
||||
if (applicationId == null) {
|
||||
return;
|
||||
}
|
||||
final Object obj = tracker.get(applicationId);
|
||||
if (obj != null && !(obj instanceof ApplicationWrapper)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ApplicationWrapper applicationWrapper = ((ApplicationWrapper) obj);
|
||||
final boolean forceLithoAXRender = params.getBoolean("forceLithoAXRender");
|
||||
final boolean prevForceLithoAXRender = Boolean.getBoolean("is_accessibility_enabled");
|
||||
|
||||
// nothing has changed, so return
|
||||
if (forceLithoAXRender == prevForceLithoAXRender) {
|
||||
return;
|
||||
}
|
||||
|
||||
// change property and rerender
|
||||
System.setProperty("is_accessibility_enabled", forceLithoAXRender + "");
|
||||
forceRerenderAllLithoViews(forceLithoAXRender, applicationWrapper);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void forceRerenderAllLithoViews(
|
||||
boolean forceLithoAXRender, ApplicationWrapper applicationWrapper) {
|
||||
|
||||
// iterate through tree and rerender all litho views
|
||||
Stack<ViewGroup> lithoViewSearchStack = new Stack<>();
|
||||
for (View root : applicationWrapper.getViewRoots()) {
|
||||
if (root instanceof ViewGroup) {
|
||||
lithoViewSearchStack.push((ViewGroup) root);
|
||||
}
|
||||
}
|
||||
|
||||
while (!lithoViewSearchStack.isEmpty()) {
|
||||
ViewGroup v = lithoViewSearchStack.pop();
|
||||
if (v instanceof LithoView) {
|
||||
((LithoView) v).rerenderForAccessibility(forceLithoAXRender);
|
||||
} else {
|
||||
for (int i = 0; i < v.getChildCount(); i++) {
|
||||
View child = v.getChildAt(i);
|
||||
if (child instanceof ViewGroup) {
|
||||
lithoViewSearchStack.push((ViewGroup) child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its 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.litho;
|
||||
|
||||
import com.facebook.flipper.plugins.inspector.DescriptorMapping;
|
||||
import com.facebook.litho.DebugComponent;
|
||||
import com.facebook.litho.LithoView;
|
||||
import com.facebook.litho.sections.debug.DebugSection;
|
||||
import com.facebook.litho.widget.LithoRecylerView;
|
||||
|
||||
public final class LithoFlipperDescriptors {
|
||||
|
||||
public static void add(DescriptorMapping descriptorMapping) {
|
||||
descriptorMapping.register(LithoView.class, new LithoViewDescriptor());
|
||||
descriptorMapping.register(DebugComponent.class, new DebugComponentDescriptor());
|
||||
}
|
||||
|
||||
public static void addWithSections(DescriptorMapping descriptorMapping) {
|
||||
add(descriptorMapping);
|
||||
descriptorMapping.register(LithoRecylerView.class, new LithoRecyclerViewDescriptor());
|
||||
descriptorMapping.register(DebugSection.class, new DebugSectionDescriptor());
|
||||
}
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its 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.litho;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import com.facebook.flipper.core.FlipperDynamic;
|
||||
import com.facebook.flipper.core.FlipperObject;
|
||||
import com.facebook.flipper.plugins.inspector.Named;
|
||||
import com.facebook.flipper.plugins.inspector.NodeDescriptor;
|
||||
import com.facebook.flipper.plugins.inspector.SetDataOperations;
|
||||
import com.facebook.flipper.plugins.inspector.Touch;
|
||||
import com.facebook.litho.sections.debug.DebugSection;
|
||||
import com.facebook.litho.widget.LithoRecylerView;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class LithoRecyclerViewDescriptor extends NodeDescriptor<LithoRecylerView> {
|
||||
|
||||
@Override
|
||||
public void invalidate(final LithoRecylerView node) {
|
||||
super.invalidate(node);
|
||||
|
||||
new com.facebook.flipper.core.ErrorReportingRunnable(mConnection) {
|
||||
@Override
|
||||
protected void runOrThrow() throws Exception {
|
||||
final Object child;
|
||||
child = getChildAt(node, 0);
|
||||
if (child instanceof DebugSection) {
|
||||
DebugSection childSection = (DebugSection) child;
|
||||
final NodeDescriptor descriptor = descriptorForClass(DebugSection.class);
|
||||
descriptor.invalidate(childSection);
|
||||
}
|
||||
}
|
||||
}.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(final LithoRecylerView node) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
descriptor.init(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId(LithoRecylerView node) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getId(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName(LithoRecylerView node) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getName(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildCount(LithoRecylerView node) throws Exception {
|
||||
// TODO T39526148 this might not always be true when using the RecyclerBinder manually.
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAXChildCount(LithoRecylerView node) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getAXChildCount(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getChildAt(LithoRecylerView node, int index) throws Exception {
|
||||
// TODO T39526148 account for the case above
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
int count = descriptor.getChildCount(node);
|
||||
|
||||
final List<View> childrenViews = new ArrayList<>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
childrenViews.add((View) descriptor.getChildAt(node, i));
|
||||
}
|
||||
|
||||
return DebugSection.getRootInstance(childrenViews);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAXChildAt(LithoRecylerView node, int index) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getAXChildAt(node, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Named<FlipperObject>> getData(LithoRecylerView node) throws Exception {
|
||||
final List<Named<FlipperObject>> props = new ArrayList<>();
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
props.addAll(descriptor.getData(node));
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Named<FlipperObject>> getAXData(LithoRecylerView node) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getAXData(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(
|
||||
LithoRecylerView node,
|
||||
String[] path,
|
||||
@Nullable SetDataOperations.FlipperValueHint kind,
|
||||
FlipperDynamic value)
|
||||
throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
descriptor.setValue(node, path, kind, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Named<String>> getAttributes(LithoRecylerView node) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getAttributes(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlipperObject getExtraInfo(LithoRecylerView node) {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getExtraInfo(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hitTest(LithoRecylerView node, Touch touch) throws Exception {
|
||||
touch.continueWithOffset(0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void axHitTest(LithoRecylerView node, Touch touch) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
descriptor.axHitTest(node, touch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAXName(LithoRecylerView node) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getAXName(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Named<String>> getAXAttributes(LithoRecylerView node) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getAXAttributes(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHighlighted(LithoRecylerView node, boolean selected, boolean isAlignmentMode)
|
||||
throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
descriptor.setHighlighted(node, selected, isAlignmentMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDecoration(LithoRecylerView node) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getDecoration(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAXDecoration(LithoRecylerView node) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getAXDecoration(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(String query, LithoRecylerView node) throws Exception {
|
||||
NodeDescriptor descriptor = descriptorForClass(Object.class);
|
||||
return descriptor.matches(query, node);
|
||||
}
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its 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.litho;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.view.ViewGroup;
|
||||
import com.facebook.flipper.core.FlipperDynamic;
|
||||
import com.facebook.flipper.core.FlipperObject;
|
||||
import com.facebook.flipper.plugins.inspector.Named;
|
||||
import com.facebook.flipper.plugins.inspector.NodeDescriptor;
|
||||
import com.facebook.flipper.plugins.inspector.SetDataOperations;
|
||||
import com.facebook.flipper.plugins.inspector.Touch;
|
||||
import com.facebook.litho.DebugComponent;
|
||||
import com.facebook.litho.LithoView;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class LithoViewDescriptor extends NodeDescriptor<LithoView> {
|
||||
|
||||
@Override
|
||||
public void init(LithoView node) throws Exception {
|
||||
node.setOnDirtyMountListener(
|
||||
new LithoView.OnDirtyMountListener() {
|
||||
@Override
|
||||
public void onDirtyMount(LithoView view) {
|
||||
invalidate(view);
|
||||
invalidateAX(view);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId(LithoView node) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getId(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName(LithoView node) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getName(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAXName(LithoView node) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getAXName(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildCount(LithoView node) {
|
||||
return DebugComponent.getRootInstance(node) == null ? 0 : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAXChildCount(LithoView node) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getAXChildCount(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getChildAt(LithoView node, int index) {
|
||||
return DebugComponent.getRootInstance(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Object getAXChildAt(LithoView node, int index) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getChildAt(node, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Named<FlipperObject>> getData(LithoView node) throws Exception {
|
||||
final List<Named<FlipperObject>> props = new ArrayList<>();
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
final Rect mountedBounds = node.getPreviousMountBounds();
|
||||
|
||||
props.add(
|
||||
0,
|
||||
new Named<>(
|
||||
"LithoView",
|
||||
new FlipperObject.Builder()
|
||||
.put(
|
||||
"mountbounds",
|
||||
new FlipperObject.Builder()
|
||||
.put("left", mountedBounds.left)
|
||||
.put("top", mountedBounds.top)
|
||||
.put("right", mountedBounds.right)
|
||||
.put("bottom", mountedBounds.bottom))
|
||||
.build()));
|
||||
|
||||
props.addAll(descriptor.getData(node));
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Named<FlipperObject>> getAXData(LithoView node) throws Exception {
|
||||
final List<Named<FlipperObject>> props = new ArrayList<>();
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
props.addAll(descriptor.getAXData(node));
|
||||
return props;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(
|
||||
LithoView node,
|
||||
String[] path,
|
||||
@Nullable SetDataOperations.FlipperValueHint kind,
|
||||
FlipperDynamic value)
|
||||
throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
descriptor.setValue(node, path, kind, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Named<String>> getAttributes(LithoView node) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getAttributes(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Named<String>> getAXAttributes(LithoView node) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getAXAttributes(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlipperObject getExtraInfo(LithoView node) {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getExtraInfo(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHighlighted(LithoView node, boolean selected, boolean isAlignmentMode)
|
||||
throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
descriptor.setHighlighted(node, selected, isAlignmentMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hitTest(LithoView node, Touch touch) {
|
||||
touch.continueWithOffset(0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void axHitTest(LithoView node, Touch touch) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
descriptor.axHitTest(node, touch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDecoration(LithoView node) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getDecoration(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAXDecoration(LithoView node) throws Exception {
|
||||
final NodeDescriptor descriptor = descriptorForClass(ViewGroup.class);
|
||||
return descriptor.getAXDecoration(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(String query, LithoView node) throws Exception {
|
||||
NodeDescriptor descriptor = descriptorForClass(Object.class);
|
||||
return descriptor.matches(query, node);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its 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.litho;
|
||||
|
||||
public interface PropWithDescription {
|
||||
|
||||
Object getFlipperLayoutInspectorPropDescription();
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its 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.litho;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import javax.annotation.CheckForNull;
|
||||
|
||||
public interface PropWithInspectorSection {
|
||||
@CheckForNull
|
||||
AbstractMap.SimpleEntry<String, String> getFlipperLayoutInspectorSection();
|
||||
}
|
||||
Reference in New Issue
Block a user