From 2c88dd4b03275f815dae2e08b65228096f075e1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Mart=C3=ADnez=20Portela?= Date: Mon, 25 May 2020 20:20:26 +0200 Subject: [PATCH] Draw all block parameters, call bridge when activated. --- .../minicards/CanvasView.java | 42 +- .../minicards/CardActivity.java | 23 +- .../codigoparallevar/minicards/CardFile.java | 11 +- .../minicards/StubPartGrid.java | 6 + .../parts/ProgramakerCustomBlockPart.java | 435 +++++++++++++++++- .../minicards/parts/buttons/RoundButton.java | 14 +- .../connectors/AnyRoundInputConnector.java | 4 + .../parts/connectors/ConnectorTypeInfo.java | 105 +++++ .../parts/connectors/RoundInputConnector.java | 5 +- .../connectors/RoundOutputConnector.java | 12 + .../minicards/parts/logic/Ticker.java | 15 +- .../minicards/parts/logic/Toggle.java | 32 +- .../minicards/parts/samples/ColorBox.java | 16 +- .../parts/strings/ConvertToString.java | 32 +- .../minicards/parts/style/CardTheme.java | 31 ++ .../minicards/types/PartGrid.java | 2 + .../minicards/types/functional/Action.java | 5 + .../minicards/types/functional/Consumer.java | 4 +- .../minicards/types/functional/Producer.java | 4 +- .../minicards/ui_helpers/DoAsync.java | 22 + .../com/programaker/api/ProgramakerApi.kt | 45 ++ .../api/data/ProgramakerCustomBlock.kt | 64 ++- .../data/ProgramakerCustomBlockArgument.kt | 63 +++ .../api/data/ProgramakerCustomBlockSaveTo.kt | 28 ++ .../api/data/ProgramakerFunctionCallResult.kt | 10 + ...ramakerGetCustomBlocksResultTypeAdapter.kt | 2 + app/src/main/res/drawable/ic_exit_to_app.xml | 5 + app/src/main/res/layout/activity_main.xml | 8 +- app/src/main/res/values/strings.xml | 2 + build.gradle | 2 +- 30 files changed, 971 insertions(+), 78 deletions(-) create mode 100644 app/src/main/java/com/codigoparallevar/minicards/parts/connectors/ConnectorTypeInfo.java create mode 100644 app/src/main/java/com/codigoparallevar/minicards/parts/style/CardTheme.java create mode 100644 app/src/main/java/com/codigoparallevar/minicards/types/functional/Action.java create mode 100644 app/src/main/java/com/codigoparallevar/minicards/ui_helpers/DoAsync.java create mode 100644 app/src/main/java/com/programaker/api/data/ProgramakerCustomBlockArgument.kt create mode 100644 app/src/main/java/com/programaker/api/data/ProgramakerCustomBlockSaveTo.kt create mode 100644 app/src/main/java/com/programaker/api/data/ProgramakerFunctionCallResult.kt create mode 100644 app/src/main/res/drawable/ic_exit_to_app.xml diff --git a/app/src/main/java/com/codigoparallevar/minicards/CanvasView.java b/app/src/main/java/com/codigoparallevar/minicards/CanvasView.java index e04b030..8130d90 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/CanvasView.java +++ b/app/src/main/java/com/codigoparallevar/minicards/CanvasView.java @@ -4,27 +4,29 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.codigoparallevar.minicards.motion.MotionMode; import com.codigoparallevar.minicards.types.Part; import com.codigoparallevar.minicards.types.PartConnection; import com.codigoparallevar.minicards.types.PartGrid; import com.codigoparallevar.minicards.types.Position; import com.codigoparallevar.minicards.types.Selectable; -import com.codigoparallevar.minicards.types.functional.Tuple2; -import com.codigoparallevar.minicards.types.functional.Tuple4; import com.codigoparallevar.minicards.types.connectors.input.AnyInputConnector; import com.codigoparallevar.minicards.types.connectors.input.BooleanInputConnector; import com.codigoparallevar.minicards.types.connectors.input.InputConnector; import com.codigoparallevar.minicards.types.connectors.input.SignalInputConnector; import com.codigoparallevar.minicards.types.connectors.input.StringInputConnector; import com.codigoparallevar.minicards.types.connectors.output.OutputConnector; +import com.codigoparallevar.minicards.types.functional.Tuple2; +import com.codigoparallevar.minicards.types.functional.Tuple4; +import com.programaker.api.ProgramakerApi; import java.io.IOException; import java.util.ArrayList; @@ -51,6 +53,7 @@ public class CanvasView extends View implements PartGrid { @NonNull private String name = "default"; + private ProgramakerApi api = null; private final static float touchTimeForLongTouchInMillis = 500; private boolean _isDragging = false; private CardActivity parentActivity = null; @@ -142,7 +145,7 @@ public class CanvasView extends View implements PartGrid { part.draw(scrolledCanvas, _devMode); } - Log.d("Render time", System.currentTimeMillis() - renderStartTime + "ms"); + // Log.d("Render time", System.currentTimeMillis() - renderStartTime + "ms"); } private void drawBackground(ScrolledCanvas canvas) { @@ -236,6 +239,7 @@ public class CanvasView extends View implements PartGrid { break; } + Log.d("CanvasView", "Moving part="+selectedPart); if (selectedPart == null){ int xMovement = _mouseDownPoint.item1 - xInScreen; int yMovement = _mouseDownPoint.item2 - yInScreen; @@ -323,15 +327,22 @@ public class CanvasView extends View implements PartGrid { for (int i = parts.size() - 1; i >= 0; i--){ final Part part = parts.get(i); // First try with output connectors - for (OutputConnector outputConnector : part.getOutputConnectors()){ - if (outputConnector.containsPoint(x, y)){ - return outputConnector; + List outputConnectors = part.getOutputConnectors(); + if (outputConnectors != null) { + for (OutputConnector outputConnector : outputConnectors) { + if (outputConnector.containsPoint(x, y)) { + return outputConnector; + } } } + // Then with input ones - for (InputConnector inputConnector : part.getInputConnectors()){ - if (inputConnector.containsPoint(x, y)){ - return inputConnector; + List inputConnectors = part.getInputConnectors(); + if (inputConnectors != null) { + for (InputConnector inputConnector : inputConnectors) { + if (inputConnector.containsPoint(x, y)) { + return inputConnector; + } } } } @@ -339,6 +350,15 @@ public class CanvasView extends View implements PartGrid { return null; } + @Override + public ProgramakerApi getApi() { + if (api == null) { + api = new ProgramakerApi(); + api.setToken(new ConfigManager(this.getContext()).getToken()); + } + return api; + } + @Override @Nullable public SignalInputConnector getSignalInputConnectorOn(int x, int y) { diff --git a/app/src/main/java/com/codigoparallevar/minicards/CardActivity.java b/app/src/main/java/com/codigoparallevar/minicards/CardActivity.java index 1b86b80..3e4be53 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/CardActivity.java +++ b/app/src/main/java/com/codigoparallevar/minicards/CardActivity.java @@ -2,6 +2,14 @@ package com.codigoparallevar.minicards; import android.content.Context; import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; + +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; import com.codigoparallevar.minicards.toolbox.PartsHolder; import com.codigoparallevar.minicards.types.functional.Consumer; @@ -15,15 +23,6 @@ import com.programaker.api.data.ProgramakerBridgeInfo; import com.programaker.api.data.api_results.ProgramakerBridgeCustomBlockResult; import com.programaker.api.data.api_results.ProgramakerGetCustomBlocksResult; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; - -import android.os.AsyncTask; -import android.os.Bundle; -import android.util.Log; -import android.view.MotionEvent; -import android.view.View; - import java.io.IOException; import java.util.List; @@ -146,8 +145,7 @@ public class CardActivity extends AppCompatActivity { ShowDeckFromDevModeButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - Intent i = new Intent(DeckPreviewActivity.INTENT); - CardActivity.this.startActivity(i); + finish(); } }); @@ -156,8 +154,7 @@ public class CardActivity extends AppCompatActivity { ShowDeckFromUserModeButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - Intent i = new Intent(DeckPreviewActivity.INTENT); - CardActivity.this.startActivity(i); + finish(); } }); diff --git a/app/src/main/java/com/codigoparallevar/minicards/CardFile.java b/app/src/main/java/com/codigoparallevar/minicards/CardFile.java index 5f2c7af..0aa786f 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/CardFile.java +++ b/app/src/main/java/com/codigoparallevar/minicards/CardFile.java @@ -4,9 +4,11 @@ import android.annotation.TargetApi; import android.content.Context; import android.graphics.Color; import android.os.Build; -import androidx.annotation.NonNull; import android.util.Log; +import androidx.annotation.NonNull; + +import com.codigoparallevar.minicards.parts.ProgramakerCustomBlockPart; import com.codigoparallevar.minicards.parts.buttons.RoundButton; import com.codigoparallevar.minicards.parts.logic.Ticker; import com.codigoparallevar.minicards.parts.logic.Toggle; @@ -284,6 +286,13 @@ public class CardFile { return convertToStringInfo; } + else if (type.equals(ProgramakerCustomBlockPart.class.getName())){ + Tuple2> customBlockPartInfo = ProgramakerCustomBlockPart.deserialize( + grid, + jsonObject.getJSONObject("_data")); + + return customBlockPartInfo; + } else { throw new JSONException("Expected known class, found " + type); } diff --git a/app/src/main/java/com/codigoparallevar/minicards/StubPartGrid.java b/app/src/main/java/com/codigoparallevar/minicards/StubPartGrid.java index 6649ed3..2d75446 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/StubPartGrid.java +++ b/app/src/main/java/com/codigoparallevar/minicards/StubPartGrid.java @@ -6,6 +6,7 @@ import com.codigoparallevar.minicards.types.functional.Tuple2; import com.codigoparallevar.minicards.types.connectors.input.BooleanInputConnector; import com.codigoparallevar.minicards.types.connectors.input.SignalInputConnector; import com.codigoparallevar.minicards.types.connectors.input.StringInputConnector; +import com.programaker.api.ProgramakerApi; class StubPartGrid implements PartGrid { @Override @@ -13,6 +14,11 @@ class StubPartGrid implements PartGrid { return null; } + @Override + public ProgramakerApi getApi() { + return null; + } + @Override public SignalInputConnector getSignalInputConnectorOn(int x, int y) { return null; diff --git a/app/src/main/java/com/codigoparallevar/minicards/parts/ProgramakerCustomBlockPart.java b/app/src/main/java/com/codigoparallevar/minicards/parts/ProgramakerCustomBlockPart.java index 41223e4..62144c0 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/parts/ProgramakerCustomBlockPart.java +++ b/app/src/main/java/com/codigoparallevar/minicards/parts/ProgramakerCustomBlockPart.java @@ -1,38 +1,82 @@ package com.codigoparallevar.minicards.parts; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.os.AsyncTask; import android.util.Log; import com.codigoparallevar.minicards.ScrolledCanvas; +import com.codigoparallevar.minicards.parts.connectors.AnyRoundInputConnector; +import com.codigoparallevar.minicards.parts.connectors.ConnectorTypeInfo; +import com.codigoparallevar.minicards.parts.connectors.RoundOutputConnector; import com.codigoparallevar.minicards.types.Moveable; import com.codigoparallevar.minicards.types.Part; +import com.codigoparallevar.minicards.types.PartConnection; import com.codigoparallevar.minicards.types.PartGrid; import com.codigoparallevar.minicards.types.connectors.input.InputConnector; import com.codigoparallevar.minicards.types.connectors.output.OutputConnector; import com.codigoparallevar.minicards.types.functional.Tuple2; import com.codigoparallevar.minicards.types.wireData.WireDataType; +import com.codigoparallevar.minicards.ui_helpers.DoAsync; +import com.programaker.api.ProgramakerApi; import com.programaker.api.data.ProgramakerCustomBlock; +import com.programaker.api.data.ProgramakerCustomBlockArgument; +import com.programaker.api.data.ProgramakerCustomBlockSaveTo; +import com.programaker.api.data.ProgramakerFunctionCallResult; import org.json.JSONException; import org.json.JSONObject; +import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; import java.util.UUID; public class ProgramakerCustomBlockPart implements Part { + private static final int WIDTH_PADDING = 50; + private static final int HEIGHT_PADDING = 50; + private static final int IO_RADIUS = 50; + private static final int IO_PADDING = 20; + private static final String LogTag = "PM Custom block part"; + private List> inputConnectors = null; + private List> outputConnectors = null; private final PartGrid _partGrid; private final String _id; - private int _xCenter; - private int _yCenter; private final ProgramakerCustomBlock _block; + private int _left; + private int _top; + private int width = 100; + private int height = 100; + private String token = null; + private Object[] lastValues; + + public ProgramakerCustomBlockPart(String id, PartGrid grid, Tuple2 center, ProgramakerCustomBlock block) { this._id = id; this._partGrid = grid; - this._xCenter = center.item1; - this._yCenter = center.item2; this._block = block; + + this.updateWidthHeight(); + + this._left = center.item1 - width / 2; + this._top = center.item2 - height / 2; + this.initialize(); + } + + private ProgramakerCustomBlockPart(String id, PartGrid grid, int left, int top, ProgramakerCustomBlock block) { + this._id = id; + this._partGrid = grid; + this._block = block; + + this.updateWidthHeight(); + + this._left = left; + this._top = top; + this.initialize(); } public ProgramakerCustomBlockPart(PartGrid grid, Tuple2 center, ProgramakerCustomBlock block) { @@ -41,49 +85,296 @@ public class ProgramakerCustomBlockPart implements Part { @Override public int get_left() { - return 0; // TODO: Implement + return _left; } @Override public int get_right() { - return 0; // TODO: Implement + return _left + width; } @Override public int get_top() { - return 0; // TODO: Implement + return _top; } @Override public int get_bottom() { - return 0; // TODO: Implement + return _top + height; + } + + private Paint getTextPaint() { + Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); + p.setColor(Color.BLACK); + p.setTextSize(50); + return p; + } + + private void updateWidthHeight() { + Paint p = getTextPaint(); + String message = getMessage(); + Rect bounds = new Rect(); + p.getTextBounds(message, 0, message.length(), bounds); + + this.height = bounds.height() + HEIGHT_PADDING * 2; + this.width = bounds.width() + WIDTH_PADDING * 2; + } + + private void initialize() { + this.updatePorts(); + lastValues = new Object[this.inputConnectors.size()]; + } + + private void updatePorts() { + String type = this._block.getBlock_type() == null ? "" : this._block.getBlock_type(); + boolean has_pulse_input = type.equals("operation"); + boolean has_pulse_output = has_pulse_input || type.equals("trigger"); + boolean hasImplicitOutput = type.equals("getter"); + + List> inputs = new LinkedList<>(); + List> outputs = new LinkedList<>(); + + // Add pulses + if (has_pulse_input) { + inputs.add(new Tuple2<>(new ConnectorTypeInfo(ConnectorTypeInfo.Type.PULSE), + new AnyRoundInputConnector(this, 0, 0, + IO_RADIUS)) + ); + } + if (has_pulse_output) { + outputs.add(new Tuple2<>(new ConnectorTypeInfo(ConnectorTypeInfo.Type.PULSE), + new RoundOutputConnector(this, this._partGrid, 0, 0, + IO_RADIUS)) + ); + } + + // Add block IO + ProgramakerCustomBlockArgument savedTo = null; + + if (_block.getArguments() != null) { + ProgramakerCustomBlockSaveTo saveTo = _block.getSave_to(); + int skip = -1; + + if (saveTo != null) { + if (saveTo.getType() != null + && saveTo.getType().equals("argument")) { + skip = saveTo.getIndex(); + } + else { + Log.w(LogTag, "Unknown save-to type=" + saveTo.getType()); + } + } + + int index = -1; + for (ProgramakerCustomBlockArgument arg : _block.getArguments()) { + index++; + if (skip == index) { + savedTo = arg; + } + else { + inputs.add(new Tuple2<>(ConnectorTypeInfo.FromTypeName(arg.getType()), + new AnyRoundInputConnector(this, 0, 0, IO_RADIUS))); + } + } + } + + if (savedTo != null) { + outputs.add(new Tuple2<>(ConnectorTypeInfo.FromTypeName(savedTo.getType()), + new RoundOutputConnector(this, this._partGrid, 0, 0, IO_RADIUS))); + } + + if (hasImplicitOutput) { + outputs.add(new Tuple2<>(ConnectorTypeInfo.FromTypeName(_block.getBlock_result_type()), + new RoundOutputConnector(this, this._partGrid, 0, 0, IO_RADIUS))); + } + + // Tie everything + inputConnectors = inputs; + outputConnectors = outputs; + + this.updatePortPositions(); + } + + private void updatePortPositions() { + { + // Update inputs + int y = get_top(); + int x = get_left() + IO_PADDING; + for (Tuple2 entry : inputConnectors) { + InputConnector input = entry.item2; + int new_x = x + IO_PADDING + IO_RADIUS / 2; + input.updatePosition(new_x, y); + x = x + IO_RADIUS * 2 + IO_PADDING * 2; + } + } + { + // Update outputs + int y = get_bottom(); + int x = get_left() + IO_PADDING; + for (Tuple2 entry : outputConnectors) { + OutputConnector output = entry.item2; + int new_x = x + IO_PADDING + IO_RADIUS / 2; + output.updatePosition(new_x, y); + x = x + IO_RADIUS * 2 + IO_PADDING * 2; + } + } + } + + private String getMessage() { + return this._block.getMessage(); } @Override public void touched() { - Log.i("CustomBlockPart", "Part touched (block_fun=" + this._block.getFunction_name() + ")"); + Log.i(LogTag, "Part touched (block_fun=" + this._block.getFunction_name() + ")"); } @Override public List getInputConnectors() { - return null; + List result = new ArrayList<>(inputConnectors.size()); + for (Tuple2 entry : inputConnectors) { + result.add(entry.item2); + } + + return result; } @Override public List getOutputConnectors() { - return null; + List result = new ArrayList<>(outputConnectors.size()); + for (Tuple2 entry : outputConnectors) { + result.add(entry.item2); + } + + return result; } @Override public JSONObject serialize() throws JSONException { - return null; + JSONObject serialized = new JSONObject(); + + serialized.put("id", _id); + serialized.put("left", _left); + serialized.put("top", _top); + + JSONObject blockData = _block.serialize(); + serialized.put("block", blockData); + +// serialized.put("on_string_output_connector", +// Serializations.serialize(serializeConnectionEndpoints())); + + return serialized; } + public static Tuple2> deserialize(PartGrid grid, JSONObject data) throws JSONException { + String id = data.getString("id"); + int left = data.getInt("left"); + int top = data.getInt("top"); + + JSONObject el = data.getJSONObject("block"); + ProgramakerCustomBlock block = ProgramakerCustomBlock.deserialize(el); + ProgramakerCustomBlockPart part = new ProgramakerCustomBlockPart(id, grid, left, top, block); + + List connections = new LinkedList<>(); + +// JSONArray connectorOuts = data.getJSONArray("on_string_output_connector"); +// for (int i = 0; i < connectorOuts.length(); i++) { +// connections.add(PartConnection.deserialize( +// toggle._stringOutputConnector, +// connectorOuts.getJSONObject(i))); +// } + + return new Tuple2<>(part, connections); + } + + @Override public void send(InputConnector inputConnector, WireDataType signal) { + Log.i(LogTag, "Received signal from Input="+inputConnector); + ConnectorTypeInfo info = getConnectorInfo(inputConnector); + if (info == null) { + Log.e(LogTag, "Unknown connector" + inputConnector); + return; + } + if (info.get_type() == ConnectorTypeInfo.Type.PULSE) { + wrappedRunOperation(); + } + else { + int index = getConnectorIndex(inputConnector); + if (index < 0) { + return; + } + this.lastValues[index] = signal.get(); + } } + private void wrappedRunOperation() { + Log.i(LogTag, "Running block function=" + this._block.getFunction_name()); + String token = this.prepareStart(); + + if (token != null) { + try { + new DoAsync().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, + new Tuple2<>(() -> { + ProgramakerCustomBlockPart.this.runBlockOperation(); + + ProgramakerCustomBlockPart.this.freeBlock(token); + }, param -> { + Log.e(LogTag, "Error executing function=" + this._block.getFunction_name() + + "; Error=" + param); + ProgramakerCustomBlockPart.this.freeBlock(token); + })); + } + catch (Exception ex) { + Log.e(LogTag, "Error executing function=" + this._block.getFunction_name() + + "; Error=" + ex); + this.freeBlock(token); + } + } else { + // An execution is in progress, so nothing is done + } + } + + private void runBlockOperation() { + ProgramakerApi api = this._partGrid.getApi(); + List arguments = new LinkedList<>(); + + int index = -1; + for (Tuple2 entry : inputConnectors) { + index++; + if (entry.item1.get_type() == ConnectorTypeInfo.Type.PULSE) { + continue; + } + + arguments.add(lastValues[index].toString()); // TODO: Do proper type formatting + } + + ProgramakerFunctionCallResult result = api.callBlock(this._block, arguments); + Log.d(LogTag, "Execution result="+result); + } + + private void freeBlock(String token) { + tryUpdateBlock(token, null); + } + + private String prepareStart() { + String token = UUID.randomUUID().toString(); + if (tryUpdateBlock(null, token)) { + return token; + } + return null; + } + + private synchronized boolean tryUpdateBlock(String oldVal, String newVal) { + if (this.token == oldVal) { + this.token = newVal; + return true; + } + return false; + } + + @Override public String get_id() { return _id; @@ -91,11 +382,54 @@ public class ProgramakerCustomBlockPart implements Part { @Override public InputConnector getConnectorWithId(String inputConnectorId) { + if (inputConnectorId.startsWith("index=")) { + String[] chunks = inputConnectorId.split("="); + if (chunks.length > 1) { + Integer index = null; + try { + index = Integer.parseInt(chunks[1]); + } + catch (NumberFormatException ex) { + Log.e(LogTag, "Error parsing connector id="+inputConnectorId); + } + + if (index != null && index < inputConnectors.size()) { + return inputConnectors.get(index).item2; + } + } + } return null; } + private int getConnectorIndex(InputConnector inputConnector) { + int index = 0; + for (Tuple2 entry : inputConnectors) { + if (entry.item2 == inputConnector) { + return index; + } + index++; + } + + return -1; + } + @Override public String getConnectorId(InputConnector inputConnector) { + int index = getConnectorIndex(inputConnector); + if (index < 0 ) { + return null; + } + + return "index=" + index; + } + + public ConnectorTypeInfo getConnectorInfo(InputConnector inputConnector) { + for (Tuple2 entry : inputConnectors) { + if (entry.item2 == inputConnector) { + return entry.item1; + } + } + return null; } @@ -111,12 +445,82 @@ public class ProgramakerCustomBlockPart implements Part { @Override public void draw(ScrolledCanvas canvas, boolean devMode) { - // TODO: Implement + + updateWidthHeight(); // TODO: Remove after the calculations have stabilized + + if (!devMode) { + return; // Logic block, don't show on user-mode + } + + drawConnectors(canvas); +// drawWires(canvas, devMode); // TODO: Implement + + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setColor(Color.WHITE); + canvas.drawRect( + new Rect(get_left(), get_top(), + get_right(), get_bottom()), + paint); + + Paint textPaint = getTextPaint(); + canvas.drawText(getMessage(), + get_left() + WIDTH_PADDING, + get_bottom() - HEIGHT_PADDING, + textPaint); + } + + private void drawConnectors(ScrolledCanvas canvas) { + if (inputConnectors != null) { + for (Tuple2 entry : inputConnectors) { + Paint outerInputConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + outerInputConnectorPaint.setColor(entry.item1.getOuterColor()); + + canvas.drawCircle( + entry.item2.getX(), + entry.item2.getY(), + entry.item2.getRadius(), + outerInputConnectorPaint); + + Paint innerInputConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + innerInputConnectorPaint.setColor(entry.item1.getInnerColor()); + + canvas.drawCircle( + entry.item2.getX(), + entry.item2.getY(), + entry.item2.getRadius() / 2, + innerInputConnectorPaint); + } + } + + if (outputConnectors != null) { + for (Tuple2 entry : outputConnectors) { + Paint outerOutputConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + outerOutputConnectorPaint.setColor(entry.item1.getOuterColor()); + + canvas.drawCircle( + entry.item2.getX(), + entry.item2.getY(), + entry.item2.getRadius(), + outerOutputConnectorPaint); + + Paint innerOutputConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + innerOutputConnectorPaint.setColor(entry.item1.getInnerColor()); + + canvas.drawCircle( + entry.item2.getX(), + entry.item2.getY(), + entry.item2.getRadius() / 2, + innerOutputConnectorPaint); + } + } } @Override public void moveEnd(int x, int y) { - // TODO: Implement moving connectors + _left = x - width / 2; + _top = y - height / 2; + + this.updatePortPositions(); } @Override @@ -126,8 +530,9 @@ public class ProgramakerCustomBlockPart implements Part { @Override public boolean containsPoint(int x, int y) { + Log.d(LogTag, "Contains (" +x+","+y+") in {left=" +get_left()+",right="+get_right()+",top="+get_top()+",bottom=" + get_bottom() + "}"); return ((x >= this.get_left()) && (x <= this.get_right()) - && (y >= this.get_top()) && (y <= this.get_top())); + && (y >= this.get_top()) && (y <= this.get_bottom())); } @Override diff --git a/app/src/main/java/com/codigoparallevar/minicards/parts/buttons/RoundButton.java b/app/src/main/java/com/codigoparallevar/minicards/parts/buttons/RoundButton.java index c421613..1e2eefe 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/parts/buttons/RoundButton.java +++ b/app/src/main/java/com/codigoparallevar/minicards/parts/buttons/RoundButton.java @@ -7,6 +7,7 @@ import android.util.Log; import com.codigoparallevar.minicards.PartInstantiator; import com.codigoparallevar.minicards.ScrolledCanvas; import com.codigoparallevar.minicards.parts.connectors.RoundOutputConnector; +import com.codigoparallevar.minicards.parts.style.CardTheme; import com.codigoparallevar.minicards.types.Moveable; import com.codigoparallevar.minicards.types.Part; import com.codigoparallevar.minicards.types.PartConnection; @@ -106,12 +107,19 @@ public class RoundButton implements Part { } private void drawConnector(ScrolledCanvas canvas) { - Paint connectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - connectorPaint.setColor(Color.RED); + Paint outerConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + outerConnectorPaint.setColor(CardTheme.PULSE_CONNECTOR_COLOR_OUTER); canvas.drawCircle(getOutputConnectorCenterX(), getOutputConnectorCenterY(), getOutputConnectRadius(), - connectorPaint); + outerConnectorPaint); + + Paint innerConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + innerConnectorPaint.setColor(CardTheme.PULSE_CONNECTOR_COLOR_INNER); + + canvas.drawCircle(getOutputConnectorCenterX(), getOutputConnectorCenterY(), + getOutputConnectRadius() / 2, + innerConnectorPaint); } private int getOutputConnectorCenterX() { diff --git a/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/AnyRoundInputConnector.java b/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/AnyRoundInputConnector.java index fbf5888..7fd5fa4 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/AnyRoundInputConnector.java +++ b/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/AnyRoundInputConnector.java @@ -65,6 +65,10 @@ public class AnyRoundInputConnector extends AnyInputConnector { return _yposition; } + public float getRadius() { + return _radius; + } + @Override public void send(WireDataType signal) { _part.send(this, signal); diff --git a/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/ConnectorTypeInfo.java b/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/ConnectorTypeInfo.java new file mode 100644 index 0000000..edee041 --- /dev/null +++ b/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/ConnectorTypeInfo.java @@ -0,0 +1,105 @@ +package com.codigoparallevar.minicards.parts.connectors; + +import com.codigoparallevar.minicards.parts.style.CardTheme; + +public class ConnectorTypeInfo { + private final Type _type; + + public static ConnectorTypeInfo FromTypeName(String type) { + if (type == null) { + return new ConnectorTypeInfo(Type.UNKNOWN); + } + + type = type.toLowerCase(); + if (type.equals("string")) { + return new ConnectorTypeInfo(Type.STRING); + } + else if (type.equals("integer")) { + return new ConnectorTypeInfo(Type.INTEGER); + } + else if (type.equals("float")) { + return new ConnectorTypeInfo(Type.FLOAT); + } + else if (type.equals("boolean")) { + return new ConnectorTypeInfo(Type.BOOLEAN); + } + else if (type.equals("pulse")) { + return new ConnectorTypeInfo(Type.PULSE); + } + else if (type.equals("enum")) { + return new ConnectorTypeInfo(Type.ENUM); + } + else if (type.equals("any")) { + return new ConnectorTypeInfo(Type.ANY); + } + else { + return new ConnectorTypeInfo(Type.UNKNOWN); + } + } + + public int getOuterColor() { + switch (_type) { + case ANY: + return CardTheme.ANY_CONNECTOR_COLOR_OUTER; + case ENUM: + return CardTheme.ENUM_CONNECTOR_COLOR_OUTER; + case FLOAT: + return CardTheme.FLOAT_CONNECTOR_COLOR_OUTER; + case PULSE: + return CardTheme.PULSE_CONNECTOR_COLOR_OUTER; + case STRING: + return CardTheme.STRING_CONNECTOR_COLOR_OUTER; + case BOOLEAN: + return CardTheme.BOOLEAN_CONNECTOR_COLOR_OUTER; + case INTEGER: + return CardTheme.INTEGER_CONNECTOR_COLOR_OUTER; + case UNKNOWN: + return CardTheme.UNKNOWN_CONNECTOR_COLOR_OUTER; + default: + return CardTheme.UNKNOWN_CONNECTOR_COLOR_OUTER; + } + } + + + public int getInnerColor() { + switch (_type) { + case ANY: + return CardTheme.ANY_CONNECTOR_COLOR_INNER; + case ENUM: + return CardTheme.ENUM_CONNECTOR_COLOR_INNER; + case FLOAT: + return CardTheme.FLOAT_CONNECTOR_COLOR_INNER; + case PULSE: + return CardTheme.PULSE_CONNECTOR_COLOR_INNER; + case STRING: + return CardTheme.STRING_CONNECTOR_COLOR_INNER; + case BOOLEAN: + return CardTheme.BOOLEAN_CONNECTOR_COLOR_INNER; + case INTEGER: + return CardTheme.INTEGER_CONNECTOR_COLOR_INNER; + case UNKNOWN: + return CardTheme.UNKNOWN_CONNECTOR_COLOR_INNER; + default: + return CardTheme.UNKNOWN_CONNECTOR_COLOR_INNER; + } + } + + public enum Type { + PULSE, + BOOLEAN, + STRING, + ANY, + ENUM, + UNKNOWN, + FLOAT, + INTEGER, + } + + public ConnectorTypeInfo(ConnectorTypeInfo.Type type) { + this._type = type; + } + + public Type get_type() { + return _type; + } +} diff --git a/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/RoundInputConnector.java b/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/RoundInputConnector.java index 14a0de3..55f55e0 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/RoundInputConnector.java +++ b/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/RoundInputConnector.java @@ -65,12 +65,15 @@ public class RoundInputConnector implements SignalInputConnector { return _yposition; } + public float getRadius() { + return _radius; + } + @Override public void send(Signal signal) { _part.send(this, signal); } - @Override public void getAttachment(Wire wire) { _attachments.add(wire); diff --git a/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/RoundOutputConnector.java b/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/RoundOutputConnector.java index 94956bb..b3adb82 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/RoundOutputConnector.java +++ b/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/RoundOutputConnector.java @@ -155,4 +155,16 @@ public class RoundOutputConnector implements Drawable, SignalOutputConnector { wire.send(signal); } } + + public float getX() { + return _centerX; + } + + public float getY() { + return _centerY; + } + + public float getRadius() { + return _radius; + } } diff --git a/app/src/main/java/com/codigoparallevar/minicards/parts/logic/Ticker.java b/app/src/main/java/com/codigoparallevar/minicards/parts/logic/Ticker.java index c99db56..d78078b 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/parts/logic/Ticker.java +++ b/app/src/main/java/com/codigoparallevar/minicards/parts/logic/Ticker.java @@ -8,6 +8,7 @@ import android.util.Log; import com.codigoparallevar.minicards.PartInstantiator; import com.codigoparallevar.minicards.ScrolledCanvas; import com.codigoparallevar.minicards.parts.connectors.RoundOutputConnector; +import com.codigoparallevar.minicards.parts.style.CardTheme; import com.codigoparallevar.minicards.types.Moveable; import com.codigoparallevar.minicards.types.Part; import com.codigoparallevar.minicards.types.PartConnection; @@ -144,13 +145,21 @@ public class Ticker implements Part { } private void drawConnector(ScrolledCanvas canvas) { - Paint connectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - connectorPaint.setColor(Color.RED); + Paint outerConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + outerConnectorPaint.setColor(CardTheme.PULSE_CONNECTOR_COLOR_OUTER); canvas.drawCircle(getOutputConnectorCenterX(), getOutputConnectorCenterY(), getOutputConnectRadius(), - connectorPaint); + outerConnectorPaint); + + Paint innerConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + innerConnectorPaint.setColor(CardTheme.PULSE_CONNECTOR_COLOR_INNER); + + canvas.drawCircle(getOutputConnectorCenterX(), + getOutputConnectorCenterY(), + getOutputConnectRadius() / 2, + innerConnectorPaint); } private void drawWires(ScrolledCanvas canvas, boolean devMode) { diff --git a/app/src/main/java/com/codigoparallevar/minicards/parts/logic/Toggle.java b/app/src/main/java/com/codigoparallevar/minicards/parts/logic/Toggle.java index f7b6dd7..371960e 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/parts/logic/Toggle.java +++ b/app/src/main/java/com/codigoparallevar/minicards/parts/logic/Toggle.java @@ -9,6 +9,7 @@ import com.codigoparallevar.minicards.PartInstantiator; import com.codigoparallevar.minicards.ScrolledCanvas; import com.codigoparallevar.minicards.parts.connectors.BooleanRoundOutputConnector; import com.codigoparallevar.minicards.parts.connectors.RoundInputConnector; +import com.codigoparallevar.minicards.parts.style.CardTheme; import com.codigoparallevar.minicards.types.Moveable; import com.codigoparallevar.minicards.types.Part; import com.codigoparallevar.minicards.types.PartConnection; @@ -128,22 +129,41 @@ public class Toggle implements Part { } private void drawConnector(ScrolledCanvas canvas) { - Paint inputConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - inputConnectorPaint.setColor(Color.YELLOW); + // Input + Paint outerInputConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + outerInputConnectorPaint.setColor(CardTheme.PULSE_CONNECTOR_COLOR_OUTER); canvas.drawCircle( getInputConnectorCenterX(), getInputConnectorCenterY(), getInputConnectRadius(), - inputConnectorPaint); + outerInputConnectorPaint); - Paint outputConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - outputConnectorPaint.setColor(Color.RED); + Paint innerInputConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + innerInputConnectorPaint.setColor(CardTheme.PULSE_CONNECTOR_COLOR_INNER); + + canvas.drawCircle( + getInputConnectorCenterX(), + getInputConnectorCenterY(), + getInputConnectRadius() / 2, + innerInputConnectorPaint); + + // Output + Paint outerOutputConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + outerOutputConnectorPaint.setColor(CardTheme.BOOLEAN_CONNECTOR_COLOR_OUTER); canvas.drawCircle(getOutputConnectorCenterX(), getOutputConnectorCenterY(), getOutputConnectRadius(), - outputConnectorPaint); + outerOutputConnectorPaint); + + Paint innerOutputConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + innerOutputConnectorPaint.setColor(CardTheme.BOOLEAN_CONNECTOR_COLOR_INNER); + + canvas.drawCircle(getOutputConnectorCenterX(), + getOutputConnectorCenterY(), + getOutputConnectRadius() / 2, + innerOutputConnectorPaint); } private void drawWires(ScrolledCanvas canvas, boolean devMode) { diff --git a/app/src/main/java/com/codigoparallevar/minicards/parts/samples/ColorBox.java b/app/src/main/java/com/codigoparallevar/minicards/parts/samples/ColorBox.java index 0b16e36..aa7c880 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/parts/samples/ColorBox.java +++ b/app/src/main/java/com/codigoparallevar/minicards/parts/samples/ColorBox.java @@ -8,6 +8,7 @@ import android.util.Log; import com.codigoparallevar.minicards.PartInstantiator; import com.codigoparallevar.minicards.ScrolledCanvas; import com.codigoparallevar.minicards.parts.connectors.BooleanRoundInputConnector; +import com.codigoparallevar.minicards.parts.style.CardTheme; import com.codigoparallevar.minicards.types.Moveable; import com.codigoparallevar.minicards.types.Part; import com.codigoparallevar.minicards.types.PartGrid; @@ -105,14 +106,23 @@ public class ColorBox implements Part { } private void drawConnector(ScrolledCanvas canvas) { - Paint connectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - connectorPaint.setColor(Color.YELLOW); + Paint outerInputConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + outerInputConnectorPaint.setColor(CardTheme.BOOLEAN_CONNECTOR_COLOR_OUTER); canvas.drawCircle( getInputConnectorCenterX(), getInputConnectorCenterY(), getInputConnectRadius(), - connectorPaint); + outerInputConnectorPaint); + + Paint innerInputConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + innerInputConnectorPaint.setColor(CardTheme.BOOLEAN_CONNECTOR_COLOR_INNER); + + canvas.drawCircle( + getInputConnectorCenterX(), + getInputConnectorCenterY(), + getInputConnectRadius() / 2, + innerInputConnectorPaint); } @Override diff --git a/app/src/main/java/com/codigoparallevar/minicards/parts/strings/ConvertToString.java b/app/src/main/java/com/codigoparallevar/minicards/parts/strings/ConvertToString.java index 09491d2..27d1d59 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/parts/strings/ConvertToString.java +++ b/app/src/main/java/com/codigoparallevar/minicards/parts/strings/ConvertToString.java @@ -10,6 +10,7 @@ import com.codigoparallevar.minicards.PartInstantiator; import com.codigoparallevar.minicards.ScrolledCanvas; import com.codigoparallevar.minicards.parts.connectors.AnyRoundInputConnector; import com.codigoparallevar.minicards.parts.connectors.StringRoundOutputConnector; +import com.codigoparallevar.minicards.parts.style.CardTheme; import com.codigoparallevar.minicards.types.Moveable; import com.codigoparallevar.minicards.types.Part; import com.codigoparallevar.minicards.types.PartConnection; @@ -127,22 +128,41 @@ public class ConvertToString implements Part { } private void drawConnector(ScrolledCanvas canvas) { - Paint inputConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - inputConnectorPaint.setColor(Color.YELLOW); + // Input + Paint inputOuterConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + inputOuterConnectorPaint.setColor(CardTheme.ANY_CONNECTOR_COLOR_OUTER); canvas.drawCircle( getInputConnectorCenterX(), getInputConnectorCenterY(), getInputConnectRadius(), - inputConnectorPaint); + inputOuterConnectorPaint); - Paint outputConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - outputConnectorPaint.setColor(Color.RED); + Paint inputInnerConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + inputInnerConnectorPaint.setColor(CardTheme.ANY_CONNECTOR_COLOR_INNER); + + canvas.drawCircle( + getInputConnectorCenterX(), + getInputConnectorCenterY(), + getInputConnectRadius() / 2, + inputInnerConnectorPaint); + + // Output + Paint outputOuterConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + outputOuterConnectorPaint.setColor(CardTheme.STRING_CONNECTOR_COLOR_OUTER); canvas.drawCircle(getOutputConnectorCenterX(), getOutputConnectorCenterY(), getOutputConnectRadius(), - outputConnectorPaint); + outputOuterConnectorPaint); + + Paint outputInnerConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + outputInnerConnectorPaint.setColor(CardTheme.STRING_CONNECTOR_COLOR_INNER); + + canvas.drawCircle(getOutputConnectorCenterX(), + getOutputConnectorCenterY(), + getOutputConnectRadius() / 2, + outputInnerConnectorPaint); } private void drawWires(ScrolledCanvas canvas, boolean devMode) { diff --git a/app/src/main/java/com/codigoparallevar/minicards/parts/style/CardTheme.java b/app/src/main/java/com/codigoparallevar/minicards/parts/style/CardTheme.java new file mode 100644 index 0000000..f1d051d --- /dev/null +++ b/app/src/main/java/com/codigoparallevar/minicards/parts/style/CardTheme.java @@ -0,0 +1,31 @@ +package com.codigoparallevar.minicards.parts.style; + +import android.graphics.Color; + +public class CardTheme { + public static final int DEFAULT_COLOR_INNER = Color.parseColor("#000000"); + + public static final int PULSE_CONNECTOR_COLOR_OUTER = Color.parseColor("#f0c000"); + public static final int PULSE_CONNECTOR_COLOR_INNER = DEFAULT_COLOR_INNER; + + public static final int BOOLEAN_CONNECTOR_COLOR_OUTER = Color.parseColor("#dd4444"); + public static final int BOOLEAN_CONNECTOR_COLOR_INNER = DEFAULT_COLOR_INNER; + + public static final int STRING_CONNECTOR_COLOR_OUTER = Color.parseColor("#44dd44"); + public static final int STRING_CONNECTOR_COLOR_INNER = DEFAULT_COLOR_INNER; + + public static final int ANY_CONNECTOR_COLOR_OUTER = Color.parseColor("#dd44dd"); + public static final int ANY_CONNECTOR_COLOR_INNER = DEFAULT_COLOR_INNER; + + public static final int ENUM_CONNECTOR_COLOR_OUTER = Color.parseColor("#888888"); + public static final int ENUM_CONNECTOR_COLOR_INNER = DEFAULT_COLOR_INNER; + + public static final int FLOAT_CONNECTOR_COLOR_OUTER = Color.parseColor("#44dddd"); + public static final int FLOAT_CONNECTOR_COLOR_INNER = DEFAULT_COLOR_INNER; + + public static final int INTEGER_CONNECTOR_COLOR_OUTER = Color.parseColor("#4444ff"); + public static final int INTEGER_CONNECTOR_COLOR_INNER = DEFAULT_COLOR_INNER; + + public static final int UNKNOWN_CONNECTOR_COLOR_OUTER = Color.parseColor("#7f7f7f"); + public static final int UNKNOWN_CONNECTOR_COLOR_INNER = DEFAULT_COLOR_INNER; +} diff --git a/app/src/main/java/com/codigoparallevar/minicards/types/PartGrid.java b/app/src/main/java/com/codigoparallevar/minicards/types/PartGrid.java index 60061ca..36d5a9c 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/types/PartGrid.java +++ b/app/src/main/java/com/codigoparallevar/minicards/types/PartGrid.java @@ -4,9 +4,11 @@ import com.codigoparallevar.minicards.types.connectors.input.BooleanInputConnect import com.codigoparallevar.minicards.types.connectors.input.SignalInputConnector; import com.codigoparallevar.minicards.types.connectors.input.StringInputConnector; import com.codigoparallevar.minicards.types.functional.Tuple2; +import com.programaker.api.ProgramakerApi; public interface PartGrid { Selectable getPartOn(int x, int y); + ProgramakerApi getApi(); SignalInputConnector getSignalInputConnectorOn(int x, int y); BooleanInputConnector getBooleanInputConnectorOn(int x, int y); diff --git a/app/src/main/java/com/codigoparallevar/minicards/types/functional/Action.java b/app/src/main/java/com/codigoparallevar/minicards/types/functional/Action.java new file mode 100644 index 0000000..2250774 --- /dev/null +++ b/app/src/main/java/com/codigoparallevar/minicards/types/functional/Action.java @@ -0,0 +1,5 @@ +package com.codigoparallevar.minicards.types.functional; + +public interface Action { + void run() throws InterruptedException; +} diff --git a/app/src/main/java/com/codigoparallevar/minicards/types/functional/Consumer.java b/app/src/main/java/com/codigoparallevar/minicards/types/functional/Consumer.java index e321ace..d90a981 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/types/functional/Consumer.java +++ b/app/src/main/java/com/codigoparallevar/minicards/types/functional/Consumer.java @@ -1,5 +1,5 @@ package com.codigoparallevar.minicards.types.functional; -public abstract class Consumer { - public abstract void apply(T param); +public interface Consumer { + void apply(T param); } diff --git a/app/src/main/java/com/codigoparallevar/minicards/types/functional/Producer.java b/app/src/main/java/com/codigoparallevar/minicards/types/functional/Producer.java index c61a648..b82d3d7 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/types/functional/Producer.java +++ b/app/src/main/java/com/codigoparallevar/minicards/types/functional/Producer.java @@ -1,5 +1,5 @@ package com.codigoparallevar.minicards.types.functional; -public abstract class Producer { - public abstract T get(); +public interface Producer { + T get(); } diff --git a/app/src/main/java/com/codigoparallevar/minicards/ui_helpers/DoAsync.java b/app/src/main/java/com/codigoparallevar/minicards/ui_helpers/DoAsync.java new file mode 100644 index 0000000..cb0eefe --- /dev/null +++ b/app/src/main/java/com/codigoparallevar/minicards/ui_helpers/DoAsync.java @@ -0,0 +1,22 @@ +package com.codigoparallevar.minicards.ui_helpers; + +import android.os.AsyncTask; + +import com.codigoparallevar.minicards.types.functional.Action; +import com.codigoparallevar.minicards.types.functional.Consumer; +import com.codigoparallevar.minicards.types.functional.Tuple2; + +public class DoAsync extends AsyncTask>, + Void, Void> { + + @Override + protected Void doInBackground(Tuple2>... data) { + try { + data[0].item1.run(); + } + catch (Throwable ex) { + data[0].item2.apply(ex); + } + return null; + } +} diff --git a/app/src/main/java/com/programaker/api/ProgramakerApi.kt b/app/src/main/java/com/programaker/api/ProgramakerApi.kt index d8a70f0..aad148e 100644 --- a/app/src/main/java/com/programaker/api/ProgramakerApi.kt +++ b/app/src/main/java/com/programaker/api/ProgramakerApi.kt @@ -6,10 +6,12 @@ import com.google.gson.Gson import com.google.gson.GsonBuilder import com.programaker.api.data.ProgramakerBridgeInfo import com.programaker.api.data.ProgramakerCustomBlock +import com.programaker.api.data.ProgramakerFunctionCallResult import com.programaker.api.data.api_results.* import com.programaker.api.exceptions.ProgramakerLoginRequiredException import com.programaker.api.exceptions.ProgramakerProtocolException import com.programaker.api.exceptions.TokenNotFoundException +import org.json.JSONArray import org.json.JSONObject import java.io.DataOutputStream import java.io.FileNotFoundException @@ -104,6 +106,10 @@ class ProgramakerApi(private val ApiRoot: String="https://programaker.com/api") ex.logError(LogTag) throw ProgramakerProtocolException() } + catch (ex: Exception) { + Log.e(LogTag, "Unexpected exception: " + ex) + throw ProgramakerProtocolException() + } return result.result } @@ -131,6 +137,27 @@ class ProgramakerApi(private val ApiRoot: String="https://programaker.com/api") } return result.result } + fun callBlock(block: ProgramakerCustomBlock, arguments: List): ProgramakerFunctionCallResult { + val conn = URL(getBlockUrl(block)).openConnection() as HttpURLConnection + conn.setRequestProperty("Content-Type", "application/json") + addAuthHeader(conn) + + conn.requestMethod = "POST"; + conn.doOutput = true; + + val postData = JSONObject(hashMapOf( + "arguments" to JSONArray(arguments) + ) as Map<*, *>) + + val wr = DataOutputStream(conn.outputStream) + wr.writeBytes(postData.toString()); + wr.flush(); + wr.close(); + + val result: ProgramakerFunctionCallResult + result = parseJson(conn.inputStream, ProgramakerFunctionCallResult::class.java) + return result + } // Initialization init { @@ -160,6 +187,11 @@ class ProgramakerApi(private val ApiRoot: String="https://programaker.com/api") return "$ApiRoot/v0/users/$userName/bridges/" } + private fun getBlockUrl(block: ProgramakerCustomBlock): String { + this.withUserId() + return "$ApiRoot/v0/users/id/$userId/bridges/id/${block.bridge_id}/functions/${block.function_name}" + } + private fun withUserName() { if (userName == null) { if (token == null) { @@ -173,6 +205,19 @@ class ProgramakerApi(private val ApiRoot: String="https://programaker.com/api") } } + private fun withUserId() { + if (userId == null) { + if (token == null) { + throw ProgramakerLoginRequiredException() + } + + this.check(); + if (userId == null) { + throw ProgramakerProtocolException() + } + } + } + private fun addAuthHeader(conn: URLConnection) { if (token != null) { conn.setRequestProperty("Authorization", token) diff --git a/app/src/main/java/com/programaker/api/data/ProgramakerCustomBlock.kt b/app/src/main/java/com/programaker/api/data/ProgramakerCustomBlock.kt index 8ca16df..fb1050c 100644 --- a/app/src/main/java/com/programaker/api/data/ProgramakerCustomBlock.kt +++ b/app/src/main/java/com/programaker/api/data/ProgramakerCustomBlock.kt @@ -1,14 +1,62 @@ package com.programaker.api.data +import org.json.JSONArray +import org.json.JSONObject + class ProgramakerCustomBlock( - val id: String, - val service_port_id: String, val block_id: String, - val block_type: String, - val block_result_type: String, val function_name: String, - val message: String -// val arguments: BlockArgument[], -// val save_to: undefined | string, + val message: String, + val arguments: List?, + val block_type: String?, + val block_result_type: String?, + var bridge_id: String?, + val save_to: ProgramakerCustomBlockSaveTo? ) { -} \ No newline at end of file + fun serialize(): JSONObject { + + val serializedArguments = JSONArray() + if (arguments != null) { + for (value in arguments) { + serializedArguments.put(value.serialize()) + } + } + + var saveToSerialized: JSONObject? = null + if (save_to != null) { + saveToSerialized = save_to.serialize() + } + + val serialized = hashMapOf( + "block_id" to block_id, + "function_name" to function_name, + "message" to message, + "arguments" to serializedArguments, + "block_type" to block_type, + "block_result_type" to block_result_type, + "bridge_id" to bridge_id, + "save_to" to saveToSerialized + ); + + return JSONObject(serialized as Map<*, *>) + } + companion object { + @JvmStatic + fun deserialize(obj: JSONObject): ProgramakerCustomBlock { + var block = ProgramakerCustomBlock( + obj.getString("block_id"), + obj.getString("function_name"), + obj.getString("message"), + ProgramakerCustomBlockArgument.deserialize(obj.optJSONArray("arguments")), + obj.getString("block_type"), + obj.getString("block_result_type"), + obj.optString("bridge_id"), + ProgramakerCustomBlockSaveTo.deserialize(obj.optJSONObject("save_to")) + ) + + return block + } + } + +} + diff --git a/app/src/main/java/com/programaker/api/data/ProgramakerCustomBlockArgument.kt b/app/src/main/java/com/programaker/api/data/ProgramakerCustomBlockArgument.kt new file mode 100644 index 0000000..4cf2d0b --- /dev/null +++ b/app/src/main/java/com/programaker/api/data/ProgramakerCustomBlockArgument.kt @@ -0,0 +1,63 @@ +package com.programaker.api.data + +import android.util.Log +import org.json.JSONArray +import org.json.JSONObject +import java.util.* + +class ProgramakerCustomBlockArgument( + val type: String?, + val default_value: String?, + // val class: String, + val callback: String? +) { + fun serialize(): JSONObject { + val serialized = hashMapOf() + + return JSONObject(serialized as Map<*, *>) + } + + companion object { + @JvmStatic + fun deserialize(arguments: JSONArray?): List { + if (arguments == null) { + return listOf(); + } + val results: MutableList = LinkedList() + + var i = 0; + while (i < arguments.length()) { + val obj = arguments.getJSONObject(i) + if (obj == null) { + Log.e("PMCustomBlockArgument", "Looped into a null value!?") + } + else { + results.add(deserialize(obj)) + } + + i += 1; + } + + return results + } + + private fun deserialize(arguments: JSONObject): ProgramakerCustomBlockArgument { + var type: String? = null + var default_value: String? = null + var callback: String? = null + + if (arguments.has("type")) { + type = arguments.getString("type") + } + if (arguments.has("default_value")) { + default_value = arguments.getString("default_value") + } + if (arguments.has("callback")) { + callback = arguments.getString("callback") + } + + return ProgramakerCustomBlockArgument(type, default_value, callback) + } + } + +} diff --git a/app/src/main/java/com/programaker/api/data/ProgramakerCustomBlockSaveTo.kt b/app/src/main/java/com/programaker/api/data/ProgramakerCustomBlockSaveTo.kt new file mode 100644 index 0000000..e359c33 --- /dev/null +++ b/app/src/main/java/com/programaker/api/data/ProgramakerCustomBlockSaveTo.kt @@ -0,0 +1,28 @@ +package com.programaker.api.data + +import org.json.JSONObject + +class ProgramakerCustomBlockSaveTo ( + val type: String, + val index: Int +) { + fun serialize(): JSONObject { + return JSONObject(hashMapOf( + "type" to type, + "index" to index + ) as Map<*, *>) + } + + companion object { + @JvmStatic + fun deserialize(save_to: JSONObject?): ProgramakerCustomBlockSaveTo? { + if (save_to == null) { + return null; + } + + return ProgramakerCustomBlockSaveTo(save_to.getString("type"), + save_to.getInt("index")) + } + } + +} diff --git a/app/src/main/java/com/programaker/api/data/ProgramakerFunctionCallResult.kt b/app/src/main/java/com/programaker/api/data/ProgramakerFunctionCallResult.kt new file mode 100644 index 0000000..8a6b870 --- /dev/null +++ b/app/src/main/java/com/programaker/api/data/ProgramakerFunctionCallResult.kt @@ -0,0 +1,10 @@ +package com.programaker.api.data + +import java.util.* + +class ProgramakerFunctionCallResult ( + var success: Boolean, + var result: Object +) { + +} diff --git a/app/src/main/java/com/programaker/api/data/api_results/ProgramakerGetCustomBlocksResultTypeAdapter.kt b/app/src/main/java/com/programaker/api/data/api_results/ProgramakerGetCustomBlocksResultTypeAdapter.kt index 4344b42..6a75806 100644 --- a/app/src/main/java/com/programaker/api/data/api_results/ProgramakerGetCustomBlocksResultTypeAdapter.kt +++ b/app/src/main/java/com/programaker/api/data/api_results/ProgramakerGetCustomBlocksResultTypeAdapter.kt @@ -22,10 +22,12 @@ internal class ProgramakerGetCustomBlocksResultTypeAdapter : JsonSerializer + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 68c0e2e..bdbfa99 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -63,7 +63,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" fab:fab_colorNormal="@color/white" - fab:fab_title="Show deck" + app:fab_icon="@drawable/ic_exit_to_app" + app:fab_title="@string/go_back" fab:fab_colorPressed="@color/white_pressed"/> + fab:fab_colorPressed="@color/white_pressed" /> Loading... Invalid username/password Placeholder text + Back to card Deck + Go back diff --git a/build.gradle b/build.gradle index c899a95..3c8f96b 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.6.1' + classpath 'com.android.tools.build:gradle:3.6.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"