diff --git a/android/src/main/java/com/facebook/flipper/nativeplugins/NativePlugin.java b/android/src/main/java/com/facebook/flipper/nativeplugins/NativePlugin.java new file mode 100644 index 000000000..6a2ec8a12 --- /dev/null +++ b/android/src/main/java/com/facebook/flipper/nativeplugins/NativePlugin.java @@ -0,0 +1,31 @@ +package com.facebook.flipper.nativeplugins; + +import com.facebook.flipper.core.FlipperPlugin; + +/** + * Subclass of {@link FlipperPlugin} for mobile-defined plugins that conform to a template. + * Implementations should call {@link #NativePlugin(String, String)} to specify which template will + * be used. See {@link com.facebook.flipper.nativeplugins.table.TablePlugin} for an example + * subclass. + */ +public abstract class NativePlugin implements FlipperPlugin { + private final String pluginType; + private final String id; + + /** + * Call super() inside subclass constructors to provide the template name and id of the concrete + * plugin instance. + * + * @param pluginType This needs to correspond to a plugin template defined in Flipper. + * @param id This will uniquely + */ + public NativePlugin(final String pluginType, final String id) { + this.pluginType = pluginType; + this.id = id; + } + + @Override + public final String getId() { + return "_nativeplugin_" + pluginType + "_" + id; + } +} diff --git a/android/src/main/java/com/facebook/flipper/nativeplugins/components/Sidebar.java b/android/src/main/java/com/facebook/flipper/nativeplugins/components/Sidebar.java new file mode 100644 index 000000000..0216788b7 --- /dev/null +++ b/android/src/main/java/com/facebook/flipper/nativeplugins/components/Sidebar.java @@ -0,0 +1,17 @@ +package com.facebook.flipper.nativeplugins.components; + +import com.facebook.flipper.core.FlipperArray; + +public class Sidebar { + + private final FlipperArray.Builder sections = new FlipperArray.Builder(); + + public Sidebar addSection(SidebarSection section) { + sections.put(section.serialize()); + return this; + } + + public FlipperArray serialize() { + return sections.build(); + } +} diff --git a/android/src/main/java/com/facebook/flipper/nativeplugins/components/SidebarSection.java b/android/src/main/java/com/facebook/flipper/nativeplugins/components/SidebarSection.java new file mode 100644 index 000000000..0d3c4d9b4 --- /dev/null +++ b/android/src/main/java/com/facebook/flipper/nativeplugins/components/SidebarSection.java @@ -0,0 +1,8 @@ +package com.facebook.flipper.nativeplugins.components; + +import com.facebook.flipper.core.FlipperObject; + +interface SidebarSection { + + FlipperObject serialize(); +} diff --git a/android/src/main/java/com/facebook/flipper/nativeplugins/table/TableMetadata.java b/android/src/main/java/com/facebook/flipper/nativeplugins/table/TableMetadata.java new file mode 100644 index 000000000..9a4288f95 --- /dev/null +++ b/android/src/main/java/com/facebook/flipper/nativeplugins/table/TableMetadata.java @@ -0,0 +1,26 @@ +package com.facebook.flipper.nativeplugins.table; + +public class TableMetadata { + + final TablePlugin.Column[] mColumns; + + private TableMetadata(TablePlugin.Column[] columns) { + if (columns == null) { + throw new IllegalArgumentException("columns must not be null"); + } + this.mColumns = columns; + } + + public static class Builder { + private TablePlugin.Column[] columns; + + public Builder columns(TablePlugin.Column... columns) { + this.columns = columns; + return this; + } + + public TableMetadata build() { + return new TableMetadata(columns); + } + } +} diff --git a/android/src/main/java/com/facebook/flipper/nativeplugins/table/TablePlugin.java b/android/src/main/java/com/facebook/flipper/nativeplugins/table/TablePlugin.java new file mode 100644 index 000000000..99ccf44e6 --- /dev/null +++ b/android/src/main/java/com/facebook/flipper/nativeplugins/table/TablePlugin.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2018-present, Facebook, Inc. + * + * 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.nativeplugins.table; + +import com.facebook.flipper.core.FlipperArray; +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.nativeplugins.NativePlugin; +import java.util.List; + +public abstract class TablePlugin extends NativePlugin { + + public static class Column { + public final String id; + final String displayName; + final String displayWidth; + final boolean showByDefault; + final boolean isFilterable; + + Column( + String id, + String displayName, + String displayWidth, + boolean showByDefault, + boolean isFilterable) { + if (id == null) { + throw new IllegalArgumentException("id must not be null"); + } + if (displayName == null) { + throw new IllegalArgumentException("displayName must not be null"); + } + this.id = id; + this.displayName = displayName; + this.displayWidth = displayWidth; + this.showByDefault = showByDefault; + this.isFilterable = isFilterable; + } + + public static class Builder { + private final String id; + private String displayName; + private String displayWidth; + private boolean showByDefault = true; + private boolean isFilterable = false; + + public Builder(String id) { + this.id = id; + } + + public Builder displayName(String displayName) { + this.displayName = displayName; + return this; + } + + public Builder displayWidthPx(int displayWidth) { + this.displayWidth = Integer.toString(displayWidth); + return this; + } + + public Builder displayWidthPercent(int displayWidth) { + this.displayWidth = Integer.toString(displayWidth) + "%"; + return this; + } + + public Builder showByDefault(boolean showByDefault) { + this.showByDefault = showByDefault; + return this; + } + + public Builder isFilterable(boolean isFilterable) { + this.isFilterable = isFilterable; + return this; + } + + public Column build() { + return new Column(id, displayName, displayWidth, showByDefault, isFilterable); + } + } + } + + private FlipperConnection mConnection; + + public TablePlugin(final String id) { + super("Table", id); + } + + @Override + public final void onConnect(FlipperConnection connection) { + this.mConnection = connection; + connection.receive( + "getMetadata", + new FlipperReceiver() { + @Override + public void onReceive(FlipperObject params, FlipperResponder responder) throws Exception { + final FlipperObject.Builder columns = new FlipperObject.Builder(); + final FlipperObject.Builder columnSizes = new FlipperObject.Builder(); + final FlipperArray.Builder columnOrder = new FlipperArray.Builder(); + final FlipperArray.Builder filterableColumns = new FlipperArray.Builder(); + for (Column c : getMetadata().mColumns) { + columns.put(c.id, new FlipperObject.Builder().put("value", c.displayName).build()); + columnSizes.put(c.id, c.displayWidth); + columnOrder.put( + new FlipperObject.Builder().put("key", c.id).put("visible", c.showByDefault)); + if (c.isFilterable) { + filterableColumns.put(c.id); + } + } + + responder.success( + new FlipperObject.Builder() + .put("columns", columns.build()) + .put("columnSizes", columnSizes.build()) + .put("columnOrder", columnOrder.build()) + .put("filterableColumns", filterableColumns.build()) + .build()); + } + }); + } + + protected abstract void onConnected(); + + protected abstract void onDisconnected(); + + protected final void updateRows(List rows) { + final FlipperArray.Builder array = new FlipperArray.Builder(); + for (TableRow r : rows) { + array.put(r.serialize()); + } + this.mConnection.send("updateRows", array.build()); + } + + public abstract TableMetadata getMetadata(); + + public List getRows() { + throw new UnsupportedOperationException( + "getRows not implemented in " + + getClass().getSimpleName() + + ". Perhaps this is a streaming plugin?"); + } + + @Override + public void onDisconnect() throws Exception { + this.onDisconnected(); + } + + @Override + public final boolean runInBackground() { + return false; + } +} diff --git a/android/src/main/java/com/facebook/flipper/nativeplugins/table/TableRow.java b/android/src/main/java/com/facebook/flipper/nativeplugins/table/TableRow.java new file mode 100644 index 000000000..bea22630e --- /dev/null +++ b/android/src/main/java/com/facebook/flipper/nativeplugins/table/TableRow.java @@ -0,0 +1,86 @@ +package com.facebook.flipper.nativeplugins.table; + +import com.facebook.flipper.core.FlipperObject; +import com.facebook.flipper.nativeplugins.components.Sidebar; +import java.util.Map; + +public abstract class TableRow { + interface Value { + FlipperObject serialize(); + } + + public static class StringValue implements Value { + private String val; + + public StringValue(String s) { + this.val = s; + } + + @Override + public FlipperObject serialize() { + return new FlipperObject.Builder().put("type", "string").put("value", val).build(); + } + } + + public static class IntValue implements Value { + private int val; + + public IntValue(int i) { + this.val = i; + } + + @Override + public FlipperObject serialize() { + return new FlipperObject.Builder().put("type", "int").put("value", val).build(); + } + } + + public static class TimeValue implements Value { + private long millis; + + public TimeValue(long millis) { + this.millis = millis; + } + + @Override + public FlipperObject serialize() { + return new FlipperObject.Builder().put("type", "time").put("value", millis).build(); + } + } + + public static class DurationValue implements Value { + private long millis; + + public DurationValue(long millis) { + this.millis = millis; + } + + @Override + public FlipperObject serialize() { + return new FlipperObject.Builder().put("type", "duration").put("value", millis).build(); + } + } + + final String id; + final Map values; + final Sidebar sidebar; + + public TableRow(String id, Map values, Sidebar sidebar) { + this.id = id; + this.values = values; + this.sidebar = sidebar; + } + + FlipperObject serialize() { + FlipperObject.Builder columnsObject = new FlipperObject.Builder(); + for (Map.Entry e : values.entrySet()) { + columnsObject.put(e.getKey().id, e.getValue().serialize()); + } + columnsObject.put("id", id); + return new FlipperObject.Builder() + .put("columns", columnsObject.build()) + .put("sidebar", sidebar.serialize()) + .put("id", id) + .build(); + } +}