Implement support for enum/callback arguments.

This commit is contained in:
Sergio Martínez Portela 2020-06-02 13:12:25 +02:00
parent 4ecd4936bd
commit 75421d4c95
12 changed files with 371 additions and 50 deletions

View File

@ -47,10 +47,10 @@ public class ProgramakerBridgeService extends Service {
@Override @Override
public void onCreate() { public void onCreate() {
setBridgeStatusNotification(getString(R.string.bridge_service_not_started), ServiceState.LOADING); setBridgeStatusNotification(getString(R.string.bridge_service_not_started), ServiceState.LOADING, null);
} }
private void setBridgeStatusNotification(String title, ServiceState state) { private void setBridgeStatusNotification(String title, ServiceState state, String description) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
assert notificationManager != null; assert notificationManager != null;
@ -94,6 +94,10 @@ public class ProgramakerBridgeService extends Service {
} }
} }
if (description != null) {
builder.setContentText(description);
}
Notification notification = builder.build(); Notification notification = builder.build();
if (stopped) { if (stopped) {
@ -164,7 +168,7 @@ public class ProgramakerBridgeService extends Service {
bridgeId); bridgeId);
ProgramakerBridgeService.this.bridge.start( ProgramakerBridgeService.this.bridge.start(
() -> { // On ready () -> { // On ready
setBridgeStatusNotification(getString(R.string.bridge_service_online), ServiceState.RUNNING); setBridgeStatusNotification(getString(R.string.bridge_service_online), ServiceState.RUNNING, null);
if (config.getBridgeConnectionId() == null) { if (config.getBridgeConnectionId() == null) {
new DoAsync().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new DoAsync().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
new Tuple2<>( new Tuple2<>(
@ -183,25 +187,29 @@ public class ProgramakerBridgeService extends Service {
} }
}, },
() -> { // On completed () -> { // On completed
ProgramakerBridgeService.this.bridge = null;
onBridgeFailedAfterConnected(); onBridgeFailedAfterConnected();
}); });
} }
catch (Throwable ex) { catch (Throwable ex) {
Log.e(LogTag, "Error on bridge", ex); Log.e(LogTag, "Error on bridge", ex);
ProgramakerBridgeService.this.bridge = null; ProgramakerBridgeService.this.bridge = null;
setBridgeStatusNotification(getString(R.string.bridge_service_starting),
ServiceState.STOPPED,
getString(R.string.error_establishing_connection));
} }
}, "ServiceStartArguments"); }, "ServiceStartArguments");
thread.setPriority(Process.THREAD_PRIORITY_BACKGROUND); thread.setPriority(Process.THREAD_PRIORITY_BACKGROUND);
setBridgeStatusNotification(getString(R.string.bridge_service_starting), ServiceState.LOADING); setBridgeStatusNotification(getString(R.string.bridge_service_starting), ServiceState.LOADING, null);
thread.start(); thread.start();
} }
private void onBridgeFailedAfterConnected() { private void onBridgeFailedAfterConnected() {
ProgramakerBridgeService.this.bridge = null;
if (!stopped) { if (!stopped) {
Log.e(LogTag, "Bridge stopped after connected. Waiting 10s then restarting"); Log.e(LogTag, "Bridge stopped after connected. Waiting 10s then restarting");
setBridgeStatusNotification(getString(R.string.bridge_service_failed_restarting), ServiceState.LOADING); setBridgeStatusNotification(getString(R.string.bridge_service_failed_restarting), ServiceState.LOADING, null);
try { try {
Thread.sleep(WAIT_TIME_BEFORE_RESTART_MILLIS); Thread.sleep(WAIT_TIME_BEFORE_RESTART_MILLIS);
} catch (InterruptedException e) { } catch (InterruptedException e) {
@ -224,6 +232,6 @@ public class ProgramakerBridgeService extends Service {
if (bridge != null) { if (bridge != null) {
bridge.stop(); bridge.stop();
} }
setBridgeStatusNotification(getString(R.string.bridge_service_failed_stopping), ServiceState.STOPPED); setBridgeStatusNotification(getString(R.string.bridge_service_failed_stopping), ServiceState.STOPPED, null);
} }
} }

View File

@ -187,7 +187,7 @@ public class ProgramakerCustomBlockPart implements Part, ProgramakerSignalListen
savedTo = arg; savedTo = arg;
} }
else { else {
ConnectorTypeInfo typeInfo = ConnectorTypeInfo.FromTypeName(arg.getType()); ConnectorTypeInfo typeInfo = ConnectorTypeInfo.FromArgument(arg);
inputs.add(new Tuple2<>(typeInfo, inputs.add(new Tuple2<>(typeInfo,
new ProgramakerCustomBlockInputConnector(this, _partGrid, new ProgramakerCustomBlockInputConnector(this, _partGrid,
0, 0, 0, 0,
@ -199,7 +199,7 @@ public class ProgramakerCustomBlockPart implements Part, ProgramakerSignalListen
Tuple2<ConnectorTypeInfo, AnyRoundOutputConnector> saveToOutput = null; Tuple2<ConnectorTypeInfo, AnyRoundOutputConnector> saveToOutput = null;
if (savedTo != null) { if (savedTo != null) {
saveToOutput = new Tuple2<>(ConnectorTypeInfo.FromTypeName(savedTo.getType()), saveToOutput = new Tuple2<>(ConnectorTypeInfo.FromTypeName(savedTo.getComputedType()),
new AnyRoundOutputConnector(this, this._partGrid, 0, 0, IO_RADIUS)); new AnyRoundOutputConnector(this, this._partGrid, 0, 0, IO_RADIUS));
outputs.add(new Tuple2<>(saveToOutput.item1, saveToOutput.item2)); outputs.add(new Tuple2<>(saveToOutput.item1, saveToOutput.item2));
} }

View File

@ -1,6 +1,7 @@
package com.codigoparallevar.minicards.parts.connectors; package com.codigoparallevar.minicards.parts.connectors;
import com.codigoparallevar.minicards.parts.style.CardTheme; import com.codigoparallevar.minicards.parts.style.CardTheme;
import com.programaker.api.data.ProgramakerCustomBlockArgument;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@ -8,6 +9,9 @@ import org.json.JSONObject;
public class ConnectorTypeInfo { public class ConnectorTypeInfo {
private final Type _type; private final Type _type;
private static final String SERIALIZED_TYPE_KEY = "type"; private static final String SERIALIZED_TYPE_KEY = "type";
private static final String SERIALIZED_ARGUMENT_KEY = "argument";
private ProgramakerCustomBlockArgument _blockArgument = null;
public static ConnectorTypeInfo FromTypeName(String type) { public static ConnectorTypeInfo FromTypeName(String type) {
if (type == null) { if (type == null) {
@ -66,7 +70,20 @@ public class ConnectorTypeInfo {
} }
public static ConnectorTypeInfo deserialize(JSONObject jsonTypeInfo) { public static ConnectorTypeInfo deserialize(JSONObject jsonTypeInfo) {
return ConnectorTypeInfo.FromTypeName(jsonTypeInfo.optString(SERIALIZED_TYPE_KEY)); ConnectorTypeInfo type = ConnectorTypeInfo.FromTypeName(jsonTypeInfo.optString(SERIALIZED_TYPE_KEY));
JSONObject arg = jsonTypeInfo.optJSONObject(SERIALIZED_ARGUMENT_KEY);
if (arg != null) {
type._blockArgument = ProgramakerCustomBlockArgument.deserialize(arg);
}
return type;
}
public static ConnectorTypeInfo FromArgument(ProgramakerCustomBlockArgument arg) {
ConnectorTypeInfo type = ConnectorTypeInfo.FromTypeName(arg.getComputedType());
type._blockArgument = arg;
return type;
} }
public int getOuterColor() { public int getOuterColor() {
@ -120,12 +137,20 @@ public class ConnectorTypeInfo {
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
try { try {
obj.put(SERIALIZED_TYPE_KEY, ConnectorTypeInfo.typeToString(this._type)); obj.put(SERIALIZED_TYPE_KEY, ConnectorTypeInfo.typeToString(this._type));
if (_blockArgument != null) {
obj.put(SERIALIZED_ARGUMENT_KEY, _blockArgument.serialize());
}
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
} }
return obj; return obj;
} }
public ProgramakerCustomBlockArgument getBlockArgument() {
return _blockArgument;
}
public enum Type { public enum Type {
PULSE, PULSE,
BOOLEAN, BOOLEAN,

View File

@ -1,14 +1,18 @@
package com.codigoparallevar.minicards.parts.values; package com.codigoparallevar.minicards.parts.values;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.AsyncTask;
import android.text.InputType; import android.text.InputType;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ProgressBar;
import com.codigoparallevar.minicards.R; import com.codigoparallevar.minicards.R;
import com.codigoparallevar.minicards.ScrolledCanvas; import com.codigoparallevar.minicards.ScrolledCanvas;
@ -21,8 +25,14 @@ import com.codigoparallevar.minicards.types.PartGrid;
import com.codigoparallevar.minicards.types.connectors.Wiring.AnyWire; import com.codigoparallevar.minicards.types.connectors.Wiring.AnyWire;
import com.codigoparallevar.minicards.types.connectors.input.InputConnector; import com.codigoparallevar.minicards.types.connectors.input.InputConnector;
import com.codigoparallevar.minicards.types.connectors.output.OutputConnector; import com.codigoparallevar.minicards.types.connectors.output.OutputConnector;
import com.codigoparallevar.minicards.types.functional.Consumer;
import com.codigoparallevar.minicards.types.functional.Tuple2; import com.codigoparallevar.minicards.types.functional.Tuple2;
import com.codigoparallevar.minicards.types.functional.Tuple3;
import com.codigoparallevar.minicards.types.wireData.WireDataType; import com.codigoparallevar.minicards.types.wireData.WireDataType;
import com.codigoparallevar.minicards.ui_helpers.GetAsync;
import com.codigoparallevar.minicards.utils.Serializations;
import com.programaker.api.data.ProgramakerCustomBlockArgument;
import com.programaker.api.data.ProgramakerCustomBlockArgumentValue;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
@ -51,12 +61,14 @@ public class StaticValuePart implements Part {
private int _left; private int _left;
private int _top; private int _top;
private String _value = null; private String _value = null;
private String _valueId = null;
public StaticValuePart(String id, PartGrid grid, int centerx, int centery, ConnectorTypeInfo typeInfo, String value) { public StaticValuePart(String id, PartGrid grid, int centerx, int centery, ConnectorTypeInfo typeInfo, String value, String valueId) {
this._id = id; this._id = id;
this._typeInfo = typeInfo; this._typeInfo = typeInfo;
this._grid = grid; this._grid = grid;
this._value = value; this._value = value;
this._valueId = valueId;
this.updateWidthHeight(); this.updateWidthHeight();
@ -66,6 +78,9 @@ public class StaticValuePart implements Part {
this._left + _width / 2, this._left + _width / 2,
this._top + _height, IO_RADIUS); this._top + _height, IO_RADIUS);
} }
public StaticValuePart(String id, PartGrid grid, int centerx, int centery, ConnectorTypeInfo typeInfo, String value) {
this(id, grid, centerx, centery, typeInfo, value, null);
}
public StaticValuePart(String id, PartGrid grid, int centerx, int centery, ConnectorTypeInfo typeInfo) { public StaticValuePart(String id, PartGrid grid, int centerx, int centery, ConnectorTypeInfo typeInfo) {
this(id, grid, centerx, centery, typeInfo, null); this(id, grid, centerx, centery, typeInfo, null);
@ -80,9 +95,10 @@ public class StaticValuePart implements Part {
JSONObject serialized = new JSONObject(); JSONObject serialized = new JSONObject();
serialized.put("id", _id); serialized.put("id", _id);
serialized.put("left", _left); serialized.put("center_x", _left + _width / 2);
serialized.put("top", _top); serialized.put("center_y", _top + _height / 2);
serialized.put("value", _value == null ? JSONObject.NULL : _value); serialized.put("value", _value == null ? JSONObject.NULL : _value);
serialized.put("value_id", _valueId == null ? JSONObject.NULL : _valueId);
JSONObject jsonTypeInfo = _typeInfo.serialize(); JSONObject jsonTypeInfo = _typeInfo.serialize();
serialized.put("type_info", jsonTypeInfo); serialized.put("type_info", jsonTypeInfo);
@ -109,13 +125,14 @@ public class StaticValuePart implements Part {
public static Tuple2<Part, List<PartConnection>> deserialize(PartGrid grid, JSONObject data) throws JSONException { public static Tuple2<Part, List<PartConnection>> deserialize(PartGrid grid, JSONObject data) throws JSONException {
String id = data.getString("id"); String id = data.getString("id");
int left = data.getInt("left"); int centerx = data.getInt("center_x");
int top = data.getInt("top"); int centery = data.getInt("center_y");
String value = data.optString("value"); String value = Serializations.getString(data, "value");
String valueId = Serializations.getString(data, "value_id");
JSONObject jsonTypeInfo = data.getJSONObject("type_info"); JSONObject jsonTypeInfo = data.getJSONObject("type_info");
ConnectorTypeInfo typeInfo = ConnectorTypeInfo.deserialize(jsonTypeInfo); ConnectorTypeInfo typeInfo = ConnectorTypeInfo.deserialize(jsonTypeInfo);
StaticValuePart part = new StaticValuePart(id, grid, left, top, typeInfo, value); StaticValuePart part = new StaticValuePart(id, grid, centerx, centery, typeInfo, value, valueId);
List<PartConnection> connections = new LinkedList<>(); List<PartConnection> connections = new LinkedList<>();
@ -177,6 +194,14 @@ public class StaticValuePart implements Part {
} }
private String getMessage() { private String getMessage() {
if (_value == null) {
return "-";
} else {
return _value;
}
}
private String getMessageForEdit() {
ConnectorTypeInfo.Type type = _typeInfo.get_type(); ConnectorTypeInfo.Type type = _typeInfo.get_type();
if (type == ConnectorTypeInfo.Type.INTEGER || type == ConnectorTypeInfo.Type.FLOAT) { if (type == ConnectorTypeInfo.Type.INTEGER || type == ConnectorTypeInfo.Type.FLOAT) {
if (_value == null) { if (_value == null) {
@ -192,10 +217,9 @@ public class StaticValuePart implements Part {
} }
else { else {
if (_value == null) { if (_value == null) {
return "-"; return "";
} else {
return _value;
} }
return _value;
} }
} }
@ -212,52 +236,131 @@ public class StaticValuePart implements Part {
return; // Can't show dialog if can't retrieve context return; // Can't show dialog if can't retrieve context
} }
final Context ctx = ((View) this._grid).getContext();
ConnectorTypeInfo.Type type = this._typeInfo.get_type(); ConnectorTypeInfo.Type type = this._typeInfo.get_type();
if (type == ConnectorTypeInfo.Type.PULSE) { if (type == ConnectorTypeInfo.Type.PULSE) {
return; // Nothing to do here return; // Nothing to do here
} }
Context ctx = ((View) this._grid).getContext();
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
builder.setTitle(R.string.set_value);
Runnable prepareOnAccept = () -> {};
switch (type) { switch (type) {
case BOOLEAN: case BOOLEAN:
break; break;
case INTEGER: case INTEGER:
case FLOAT: case FLOAT: {
{
final EditText input = new EditText(ctx); final EditText input = new EditText(ctx);
input.setText(getMessage()); input.setText(getMessageForEdit());
input.setInputType(InputType.TYPE_CLASS_NUMBER); input.setInputType(InputType.TYPE_CLASS_NUMBER);
builder.setView(input);
prepareOnAccept = () -> { dialogAskUserForValue(ctx, input,
() -> {
_value = input.getText().toString(); _value = input.getText().toString();
}; });
break; break;
} }
default: default:
case ENUM:
// TODO: Show enumerated values
case ANY: case ANY:
case UNKNOWN: case UNKNOWN:
case STRING: case STRING: {
{
final EditText input = new EditText(ctx); final EditText input = new EditText(ctx);
input.setText(getMessage()); input.setText(getMessageForEdit());
input.setInputType(InputType.TYPE_CLASS_TEXT); input.setInputType(InputType.TYPE_CLASS_TEXT);
builder.setView(input); dialogAskUserForValue(ctx, input,
prepareOnAccept = () -> { () -> {
_value = input.getText().toString(); _value = input.getText().toString();
}; });
break;
}
case ENUM:
ProgramakerCustomBlockArgument blockArg = _typeInfo.getBlockArgument();
String callback = null;
if (blockArg != null) {
callback = blockArg.getCallback();
if (callback.equals("null")) { // TODO: Fix this on server
callback = null;
}
}
if (callback == null) {
new AlertDialog.Builder(ctx)
.setMessage(R.string.error_recovering_allowed_values)
.create()
.show();
break;
}
Dialog loadingDialog = createLoadingDialog(ctx);
loadingDialog.show();
new GetAsync<List<ProgramakerCustomBlockArgumentValue>>().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
new Tuple3<>(
() -> _grid.getApi().fetchAllowedValues(blockArg),
results -> {
Log.i(LogTag, "Result: " + results);
loadingDialog.cancel();
String[] names = new String[results.size()];
int i = 0;
for (ProgramakerCustomBlockArgumentValue value : results) {
names[i] = value.getName();
i++;
}
Dialog d = createItemDialog(ctx, names, idx -> {
StaticValuePart.this._value = results.get(idx).getName();
StaticValuePart.this._valueId = results.get(idx).getId();
StaticValuePart.this._grid.update();
});
d.show();
},
ex -> {
Log.e(LogTag, "Error retrieving values: " + ex, ex);
new AlertDialog.Builder(ctx)
.setMessage(R.string.error_recovering_allowed_values)
.create()
.show();
}
));
break; break;
} }
} }
final Runnable onAccept = prepareOnAccept; private Dialog createItemDialog(Context ctx, CharSequence[] itemNames, Consumer<Integer> onSelected) {
final AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
builder.setTitle(R.string.loading_available_values);
final ProgressBar progressBar = new ProgressBar(ctx);
progressBar.setIndeterminate(true);
builder.setItems(itemNames, (DialogInterface.OnClickListener) (dialog, which) -> {
try {
onSelected.apply(which);
} catch (Exception e) {
e.printStackTrace();
}
});
AlertDialog dialog = builder.create();
return dialog;
}
private Dialog createLoadingDialog(Context ctx) {
final AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
builder.setTitle(R.string.loading_available_values);
final ProgressBar progressBar = new ProgressBar(ctx);
progressBar.setIndeterminate(true);
builder.setView(progressBar);
AlertDialog dialog = builder.create();
return dialog;
}
private void dialogAskUserForValue(Context ctx, EditText input, Runnable onAccept) {
final AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
builder.setTitle(R.string.set_value);
builder builder
.setPositiveButton(R.string.ok_accept_changes, (dialog, which) -> { .setPositiveButton(R.string.ok_accept_changes, (dialog, which) -> {
onAccept.run(); onAccept.run();
@ -266,10 +369,12 @@ public class StaticValuePart implements Part {
}) })
.setNegativeButton(R.string.cancel_discard_changes, (dialog, which) -> { .setNegativeButton(R.string.cancel_discard_changes, (dialog, which) -> {
// No change // No change
} ); })
.setView(input);
AlertDialog dialog = builder.create(); AlertDialog dialog = builder.create();
dialog.show(); dialog.show();
} }
@Override @Override
@ -321,6 +426,10 @@ public class StaticValuePart implements Part {
@Override @Override
public Object query(Object lastValue) { public Object query(Object lastValue) {
if (this._valueId != null) {
return this._valueId;
}
return this._value; return this._value;
} }

View File

@ -72,4 +72,18 @@ public class Serializations {
return obj; return obj;
} }
} }
public static String getString(JSONObject map, String key) {
if (!map.has(key)) {
return null;
}
if (map.opt(key) == JSONObject.NULL) {
return null;
}
try {
return map.getString(key);
} catch (JSONException e) {
return null;
}
}
} }

View File

@ -4,9 +4,7 @@ import android.os.Build
import android.util.Log import android.util.Log
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import com.programaker.api.data.ProgramakerBridgeInfo import com.programaker.api.data.*
import com.programaker.api.data.ProgramakerCustomBlock
import com.programaker.api.data.ProgramakerFunctionCallResult
import com.programaker.api.data.api_results.* import com.programaker.api.data.api_results.*
import com.programaker.api.exceptions.ProgramakerLoginRequiredException import com.programaker.api.exceptions.ProgramakerLoginRequiredException
import com.programaker.api.exceptions.ProgramakerProtocolException import com.programaker.api.exceptions.ProgramakerProtocolException
@ -138,6 +136,29 @@ class ProgramakerApi(private val ApiRoot: String="https://programaker.com/api")
return result.result return result.result
} }
fun fetchAllowedValues(blockArg: ProgramakerCustomBlockArgument): List<ProgramakerCustomBlockArgumentValue>? {
val conn = URL(getArgumentValuesUrl(blockArg)).openConnection() as HttpURLConnection
addAuthHeader(conn)
var results: List<ProgramakerCustomBlockArgumentValue>? = null
try {
val serialized: HashMap<String,*> = parseJson(conn.inputStream, HashMap::class.java)
val returnInfo = ProgramakerCustomBlockArgumentValuesReturnInfo.deserialize(serialized)
if (!returnInfo.success) {
return null
}
results = returnInfo.values
} catch (ex: FileNotFoundException) {
ex.logError(LogTag)
return null
} catch(ex: Exception) {
Log.e(LogTag, ex.toString(), ex)
return null
}
return results
}
fun callBlock(block: ProgramakerCustomBlock, arguments: List<String>): ProgramakerFunctionCallResult { fun callBlock(block: ProgramakerCustomBlock, arguments: List<String>): ProgramakerFunctionCallResult {
val conn = URL(getBlockUrl(block)).openConnection() as HttpURLConnection val conn = URL(getBlockUrl(block)).openConnection() as HttpURLConnection
conn.setRequestProperty("Content-Type", "application/json") conn.setRequestProperty("Content-Type", "application/json")
@ -278,6 +299,11 @@ class ProgramakerApi(private val ApiRoot: String="https://programaker.com/api")
return "$ApiRoot/v0/users/id/$userId/bridges/id/$bridgeId/signals/$key" return "$ApiRoot/v0/users/id/$userId/bridges/id/$bridgeId/signals/$key"
} }
private fun getArgumentValuesUrl(blockArg: ProgramakerCustomBlockArgument): String {
this.withUserId()
return "$ApiRoot/v0/users/id/$userId/bridges/id/${blockArg.bridge_id}/callback/${blockArg.callback}"
}
fun getUserId(): String? { fun getUserId(): String? {
this.withUserId() this.withUserId()
return userId; return userId;

View File

@ -11,16 +11,28 @@ class ProgramakerCustomBlockArgument(
// val class: String, // val class: String,
val callback: String? val callback: String?
) { ) {
var bridge_id: String? = null
fun serialize(): JSONObject { fun serialize(): JSONObject {
val serialized = hashMapOf<String, String?>( val serialized = hashMapOf<String, String?>(
"type" to type, "type" to type,
"default_value" to default_value, "default_value" to default_value,
"callback" to callback "callback" to callback,
"bridge_id" to bridge_id
) )
return JSONObject(serialized as Map<*, *>) return JSONObject(serialized as Map<*, *>)
} }
fun getComputedType(): String? {
if (callback != null && callback != "null") {
return "ENUM";
}
else {
return type;
}
}
companion object { companion object {
@JvmStatic @JvmStatic
fun deserialize(arguments: JSONArray?): List<ProgramakerCustomBlockArgument> { fun deserialize(arguments: JSONArray?): List<ProgramakerCustomBlockArgument> {
@ -45,12 +57,16 @@ class ProgramakerCustomBlockArgument(
return results return results
} }
private fun deserialize(arguments: JSONObject): ProgramakerCustomBlockArgument { @JvmStatic
fun deserialize(arguments: JSONObject): ProgramakerCustomBlockArgument {
val type: String? = arguments.optString("type") val type: String? = arguments.optString("type")
val default_value: String? = arguments.optString("default_value") val default_value: String? = arguments.optString("default_value")
val callback: String? = arguments.optString("callback") val callback: String? = arguments.optString("callback")
val bridge_id: String? = arguments.optString("bridge_id")
return ProgramakerCustomBlockArgument(type, default_value, callback) val arg = ProgramakerCustomBlockArgument(type, default_value, callback)
arg.bridge_id = bridge_id
return arg
} }
} }

View File

@ -0,0 +1,67 @@
package com.programaker.api.data
import com.programaker.api.optGet
import java.util.*
class ProgramakerCustomBlockArgumentValue (
val id: String,
val name: String
) {
companion object {
@JvmStatic
fun deserializeList(value: Object): List<ProgramakerCustomBlockArgumentValue> {
if (value is Map<*, *>) {
return deserialize(value as Map<*, *>)
} else if (value is List<*>) {
return deserialize(value as List<*>)
} else {
throw IllegalArgumentException("Error deserializing: $value")
}
}
@JvmStatic
fun deserialize(value: Map<*, *>): List<ProgramakerCustomBlockArgumentValue> {
val results = LinkedList<ProgramakerCustomBlockArgumentValue>()
for (entry in value.asIterable()) {
var value = entry.value.toString()
if (entry.value is Map<*, *>) {
if ((entry.value as Map<String, *>).containsKey("name")) {
value = (entry.value as Map<*, *>)["name"].toString()
}
}
results.add(ProgramakerCustomBlockArgumentValue(entry.key.toString(), value))
}
return results
}
@JvmStatic
fun deserialize(value: List<*>): List<ProgramakerCustomBlockArgumentValue> {
val results = LinkedList<ProgramakerCustomBlockArgumentValue>()
for (entry in value) {
if (entry is Map<*,*>) {
var name = (entry as Map<String, *>).optGet("name")
var id = (entry as Map<String, *>).optGet("id")
if (name == null && id == null) {
throw IllegalArgumentException("Error deserializing: $entry")
}
else if (name == null) {
name = id
}
else if (id == null) {
id = name
}
results.add(ProgramakerCustomBlockArgumentValue(id.toString(), name.toString()))
}
else {
throw IllegalArgumentException("Error deserializing: $entry")
}
}
return results
}
}
}

View File

@ -0,0 +1,29 @@
package com.programaker.api.data
import com.programaker.api.optGet
import java.util.*
class ProgramakerCustomBlockArgumentValuesReturnInfo(
val success: Boolean,
val values: List<ProgramakerCustomBlockArgumentValue>
) {
companion object {
@JvmStatic
fun deserialize(value: HashMap<String,*>): ProgramakerCustomBlockArgumentValuesReturnInfo {
val _success: Boolean? = value.optGet("success") as Boolean?
val _result: Object? = value.optGet("result") as Object
var success = false
if (_success != null) {
success = _success
}
var result: List<ProgramakerCustomBlockArgumentValue> = Collections.emptyList<ProgramakerCustomBlockArgumentValue>()
if (_result != null) {
result = ProgramakerCustomBlockArgumentValue.deserializeList(_result)
}
return ProgramakerCustomBlockArgumentValuesReturnInfo(success, result)
}
}
}

View File

@ -23,6 +23,11 @@ internal class ProgramakerGetCustomBlocksResultTypeAdapter : JsonSerializer<Prog
for (value in value1.asJsonArray) { for (value in value1.asJsonArray) {
val block = gson.fromJson(value, ProgramakerCustomBlock::class.java) val block = gson.fromJson(value, ProgramakerCustomBlock::class.java)
block.bridge_id = bridgeId block.bridge_id = bridgeId
if (block.arguments != null) {
for (arg in block.arguments) {
arg.bridge_id = bridgeId
}
}
blocks.add(block) blocks.add(block)
} }

View File

@ -0,0 +1,19 @@
package com.programaker.api
internal fun <K, V> java.util.HashMap<K, V>.optGet(key: K): V? {
if (this.containsKey(key)) {
return this.get(key)
}
else {
return null
}
}
internal fun <K, V> Map<K, V>.optGet(key: K): V? {
if (this.containsKey(key)) {
return this.get(key)
}
else {
return null
}
}

View File

@ -29,4 +29,7 @@
<string name="set_value">Set block value</string> <string name="set_value">Set block value</string>
<string name="ok_accept_changes">OK</string> <string name="ok_accept_changes">OK</string>
<string name="cancel_discard_changes">Cancel</string> <string name="cancel_discard_changes">Cancel</string>
<string name="error_establishing_connection">Error establishing connection</string>
<string name="error_recovering_allowed_values">Error recovering allowed values</string>
<string name="loading_available_values">Loading available values...</string>
</resources> </resources>