From 75421d4c95fef4bea90102a2feefcb7d7a282796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Mart=C3=ADnez=20Portela?= Date: Tue, 2 Jun 2020 13:12:25 +0200 Subject: [PATCH] Implement support for enum/callback arguments. --- .../bridge/ProgramakerBridgeService.java | 22 ++- .../parts/ProgramakerCustomBlockPart.java | 4 +- .../parts/connectors/ConnectorTypeInfo.java | 27 ++- .../parts/values/StaticValuePart.java | 177 ++++++++++++++---- .../minicards/utils/Serializations.java | 14 ++ .../com/programaker/api/ProgramakerApi.kt | 32 +++- .../data/ProgramakerCustomBlockArgument.kt | 22 ++- .../ProgramakerCustomBlockArgumentValue.kt | 67 +++++++ ...akerCustomBlockArgumentValuesReturnInfo.kt | 29 +++ ...ramakerGetCustomBlocksResultTypeAdapter.kt | 5 + .../main/java/com/programaker/api/utils.kt | 19 ++ app/src/main/res/values/strings.xml | 3 + 12 files changed, 371 insertions(+), 50 deletions(-) create mode 100644 app/src/main/java/com/programaker/api/data/ProgramakerCustomBlockArgumentValue.kt create mode 100644 app/src/main/java/com/programaker/api/data/ProgramakerCustomBlockArgumentValuesReturnInfo.kt create mode 100644 app/src/main/java/com/programaker/api/utils.kt diff --git a/app/src/main/java/com/codigoparallevar/minicards/bridge/ProgramakerBridgeService.java b/app/src/main/java/com/codigoparallevar/minicards/bridge/ProgramakerBridgeService.java index 91b3189..7234f23 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/bridge/ProgramakerBridgeService.java +++ b/app/src/main/java/com/codigoparallevar/minicards/bridge/ProgramakerBridgeService.java @@ -47,10 +47,10 @@ public class ProgramakerBridgeService extends Service { @Override 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); assert notificationManager != null; @@ -94,6 +94,10 @@ public class ProgramakerBridgeService extends Service { } } + if (description != null) { + builder.setContentText(description); + } + Notification notification = builder.build(); if (stopped) { @@ -164,7 +168,7 @@ public class ProgramakerBridgeService extends Service { bridgeId); ProgramakerBridgeService.this.bridge.start( () -> { // 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) { new DoAsync().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new Tuple2<>( @@ -183,25 +187,29 @@ public class ProgramakerBridgeService extends Service { } }, () -> { // On completed - ProgramakerBridgeService.this.bridge = null; onBridgeFailedAfterConnected(); }); } catch (Throwable ex) { Log.e(LogTag, "Error on bridge", ex); ProgramakerBridgeService.this.bridge = null; + setBridgeStatusNotification(getString(R.string.bridge_service_starting), + ServiceState.STOPPED, + getString(R.string.error_establishing_connection)); } }, "ServiceStartArguments"); 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(); } private void onBridgeFailedAfterConnected() { + ProgramakerBridgeService.this.bridge = null; + if (!stopped) { 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 { Thread.sleep(WAIT_TIME_BEFORE_RESTART_MILLIS); } catch (InterruptedException e) { @@ -224,6 +232,6 @@ public class ProgramakerBridgeService extends Service { if (bridge != null) { bridge.stop(); } - setBridgeStatusNotification(getString(R.string.bridge_service_failed_stopping), ServiceState.STOPPED); + setBridgeStatusNotification(getString(R.string.bridge_service_failed_stopping), ServiceState.STOPPED, 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 84edf1a..91f55f2 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/parts/ProgramakerCustomBlockPart.java +++ b/app/src/main/java/com/codigoparallevar/minicards/parts/ProgramakerCustomBlockPart.java @@ -187,7 +187,7 @@ public class ProgramakerCustomBlockPart implements Part, ProgramakerSignalListen savedTo = arg; } else { - ConnectorTypeInfo typeInfo = ConnectorTypeInfo.FromTypeName(arg.getType()); + ConnectorTypeInfo typeInfo = ConnectorTypeInfo.FromArgument(arg); inputs.add(new Tuple2<>(typeInfo, new ProgramakerCustomBlockInputConnector(this, _partGrid, 0, 0, @@ -199,7 +199,7 @@ public class ProgramakerCustomBlockPart implements Part, ProgramakerSignalListen Tuple2 saveToOutput = 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)); outputs.add(new Tuple2<>(saveToOutput.item1, saveToOutput.item2)); } 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 index 9ba9bb7..3dc1033 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/ConnectorTypeInfo.java +++ b/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/ConnectorTypeInfo.java @@ -1,6 +1,7 @@ package com.codigoparallevar.minicards.parts.connectors; import com.codigoparallevar.minicards.parts.style.CardTheme; +import com.programaker.api.data.ProgramakerCustomBlockArgument; import org.json.JSONException; import org.json.JSONObject; @@ -8,6 +9,9 @@ import org.json.JSONObject; public class ConnectorTypeInfo { private final Type _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) { if (type == null) { @@ -66,7 +70,20 @@ public class ConnectorTypeInfo { } 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() { @@ -120,12 +137,20 @@ public class ConnectorTypeInfo { JSONObject obj = new JSONObject(); try { obj.put(SERIALIZED_TYPE_KEY, ConnectorTypeInfo.typeToString(this._type)); + + if (_blockArgument != null) { + obj.put(SERIALIZED_ARGUMENT_KEY, _blockArgument.serialize()); + } } catch (JSONException e) { e.printStackTrace(); } return obj; } + public ProgramakerCustomBlockArgument getBlockArgument() { + return _blockArgument; + } + public enum Type { PULSE, BOOLEAN, diff --git a/app/src/main/java/com/codigoparallevar/minicards/parts/values/StaticValuePart.java b/app/src/main/java/com/codigoparallevar/minicards/parts/values/StaticValuePart.java index a91bdcd..3f42251 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/parts/values/StaticValuePart.java +++ b/app/src/main/java/com/codigoparallevar/minicards/parts/values/StaticValuePart.java @@ -1,14 +1,18 @@ package com.codigoparallevar.minicards.parts.values; import android.app.AlertDialog; +import android.app.Dialog; import android.content.Context; +import android.content.DialogInterface; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; +import android.os.AsyncTask; import android.text.InputType; import android.util.Log; import android.view.View; import android.widget.EditText; +import android.widget.ProgressBar; import com.codigoparallevar.minicards.R; 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.input.InputConnector; 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.Tuple3; 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.JSONException; @@ -51,12 +61,14 @@ public class StaticValuePart implements Part { private int _left; private int _top; 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._typeInfo = typeInfo; this._grid = grid; this._value = value; + this._valueId = valueId; this.updateWidthHeight(); @@ -66,6 +78,9 @@ public class StaticValuePart implements Part { this._left + _width / 2, 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) { this(id, grid, centerx, centery, typeInfo, null); @@ -80,9 +95,10 @@ public class StaticValuePart implements Part { JSONObject serialized = new JSONObject(); serialized.put("id", _id); - serialized.put("left", _left); - serialized.put("top", _top); + serialized.put("center_x", _left + _width / 2); + serialized.put("center_y", _top + _height / 2); serialized.put("value", _value == null ? JSONObject.NULL : _value); + serialized.put("value_id", _valueId == null ? JSONObject.NULL : _valueId); JSONObject jsonTypeInfo = _typeInfo.serialize(); serialized.put("type_info", jsonTypeInfo); @@ -109,13 +125,14 @@ public class StaticValuePart implements Part { 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"); - String value = data.optString("value"); + int centerx = data.getInt("center_x"); + int centery = data.getInt("center_y"); + String value = Serializations.getString(data, "value"); + String valueId = Serializations.getString(data, "value_id"); JSONObject jsonTypeInfo = data.getJSONObject("type_info"); 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 connections = new LinkedList<>(); @@ -177,6 +194,14 @@ public class StaticValuePart implements Part { } private String getMessage() { + if (_value == null) { + return "-"; + } else { + return _value; + } + } + + private String getMessageForEdit() { ConnectorTypeInfo.Type type = _typeInfo.get_type(); if (type == ConnectorTypeInfo.Type.INTEGER || type == ConnectorTypeInfo.Type.FLOAT) { if (_value == null) { @@ -192,10 +217,9 @@ public class StaticValuePart implements Part { } else { if (_value == null) { - return "-"; - } else { - return _value; + return ""; } + return _value; } } @@ -212,52 +236,131 @@ public class StaticValuePart implements Part { return; // Can't show dialog if can't retrieve context } + final Context ctx = ((View) this._grid).getContext(); ConnectorTypeInfo.Type type = this._typeInfo.get_type(); if (type == ConnectorTypeInfo.Type.PULSE) { 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) { case BOOLEAN: break; case INTEGER: - case FLOAT: - { + case FLOAT: { final EditText input = new EditText(ctx); - input.setText(getMessage()); + input.setText(getMessageForEdit()); input.setInputType(InputType.TYPE_CLASS_NUMBER); - builder.setView(input); - prepareOnAccept = () -> { - _value = input.getText().toString(); - }; + + dialogAskUserForValue(ctx, input, + () -> { + _value = input.getText().toString(); + }); break; } default: - case ENUM: - // TODO: Show enumerated values case ANY: case UNKNOWN: - case STRING: - { + case STRING: { final EditText input = new EditText(ctx); - input.setText(getMessage()); + input.setText(getMessageForEdit()); input.setInputType(InputType.TYPE_CLASS_TEXT); - builder.setView(input); - prepareOnAccept = () -> { - _value = input.getText().toString(); - }; + dialogAskUserForValue(ctx, input, + () -> { + _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; + } + } - final Runnable onAccept = prepareOnAccept; + 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>().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; + } + } + + private Dialog createItemDialog(Context ctx, CharSequence[] itemNames, Consumer 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 .setPositiveButton(R.string.ok_accept_changes, (dialog, which) -> { onAccept.run(); @@ -266,10 +369,12 @@ public class StaticValuePart implements Part { }) .setNegativeButton(R.string.cancel_discard_changes, (dialog, which) -> { // No change - } ); + }) + .setView(input); AlertDialog dialog = builder.create(); dialog.show(); + } @Override @@ -321,6 +426,10 @@ public class StaticValuePart implements Part { @Override public Object query(Object lastValue) { + if (this._valueId != null) { + return this._valueId; + } + return this._value; } diff --git a/app/src/main/java/com/codigoparallevar/minicards/utils/Serializations.java b/app/src/main/java/com/codigoparallevar/minicards/utils/Serializations.java index 858a959..a348c23 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/utils/Serializations.java +++ b/app/src/main/java/com/codigoparallevar/minicards/utils/Serializations.java @@ -72,4 +72,18 @@ public class Serializations { 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; + } + } } diff --git a/app/src/main/java/com/programaker/api/ProgramakerApi.kt b/app/src/main/java/com/programaker/api/ProgramakerApi.kt index 2b5de80..61b68cd 100644 --- a/app/src/main/java/com/programaker/api/ProgramakerApi.kt +++ b/app/src/main/java/com/programaker/api/ProgramakerApi.kt @@ -4,9 +4,7 @@ import android.os.Build import android.util.Log 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.* import com.programaker.api.data.api_results.* import com.programaker.api.exceptions.ProgramakerLoginRequiredException import com.programaker.api.exceptions.ProgramakerProtocolException @@ -138,6 +136,29 @@ class ProgramakerApi(private val ApiRoot: String="https://programaker.com/api") return result.result } + fun fetchAllowedValues(blockArg: ProgramakerCustomBlockArgument): List? { + val conn = URL(getArgumentValuesUrl(blockArg)).openConnection() as HttpURLConnection + + addAuthHeader(conn) + + var results: List? = null + try { + val serialized: HashMap = 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): ProgramakerFunctionCallResult { val conn = URL(getBlockUrl(block)).openConnection() as HttpURLConnection 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" } + 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? { this.withUserId() return userId; diff --git a/app/src/main/java/com/programaker/api/data/ProgramakerCustomBlockArgument.kt b/app/src/main/java/com/programaker/api/data/ProgramakerCustomBlockArgument.kt index 6ce8b79..0767e02 100644 --- a/app/src/main/java/com/programaker/api/data/ProgramakerCustomBlockArgument.kt +++ b/app/src/main/java/com/programaker/api/data/ProgramakerCustomBlockArgument.kt @@ -11,16 +11,28 @@ class ProgramakerCustomBlockArgument( // val class: String, val callback: String? ) { + var bridge_id: String? = null + fun serialize(): JSONObject { val serialized = hashMapOf( "type" to type, "default_value" to default_value, - "callback" to callback + "callback" to callback, + "bridge_id" to bridge_id ) return JSONObject(serialized as Map<*, *>) } + fun getComputedType(): String? { + if (callback != null && callback != "null") { + return "ENUM"; + } + else { + return type; + } + } + companion object { @JvmStatic fun deserialize(arguments: JSONArray?): List { @@ -45,12 +57,16 @@ class ProgramakerCustomBlockArgument( return results } - private fun deserialize(arguments: JSONObject): ProgramakerCustomBlockArgument { + @JvmStatic + fun deserialize(arguments: JSONObject): ProgramakerCustomBlockArgument { val type: String? = arguments.optString("type") val default_value: String? = arguments.optString("default_value") 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 } } diff --git a/app/src/main/java/com/programaker/api/data/ProgramakerCustomBlockArgumentValue.kt b/app/src/main/java/com/programaker/api/data/ProgramakerCustomBlockArgumentValue.kt new file mode 100644 index 0000000..902243c --- /dev/null +++ b/app/src/main/java/com/programaker/api/data/ProgramakerCustomBlockArgumentValue.kt @@ -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 { + 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 { + val results = LinkedList() + for (entry in value.asIterable()) { + var value = entry.value.toString() + if (entry.value is Map<*, *>) { + if ((entry.value as Map).containsKey("name")) { + value = (entry.value as Map<*, *>)["name"].toString() + } + } + + results.add(ProgramakerCustomBlockArgumentValue(entry.key.toString(), value)) + } + + return results + } + + @JvmStatic + fun deserialize(value: List<*>): List { + val results = LinkedList() + for (entry in value) { + if (entry is Map<*,*>) { + var name = (entry as Map).optGet("name") + var id = (entry as Map).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 + } + } +} diff --git a/app/src/main/java/com/programaker/api/data/ProgramakerCustomBlockArgumentValuesReturnInfo.kt b/app/src/main/java/com/programaker/api/data/ProgramakerCustomBlockArgumentValuesReturnInfo.kt new file mode 100644 index 0000000..f2334ad --- /dev/null +++ b/app/src/main/java/com/programaker/api/data/ProgramakerCustomBlockArgumentValuesReturnInfo.kt @@ -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 +) { + companion object { + @JvmStatic + fun deserialize(value: HashMap): 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 = Collections.emptyList() + if (_result != null) { + result = ProgramakerCustomBlockArgumentValue.deserializeList(_result) + } + + return ProgramakerCustomBlockArgumentValuesReturnInfo(success, result) + } + } +} 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 6a75806..1c73fcc 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 @@ -23,6 +23,11 @@ internal class ProgramakerGetCustomBlocksResultTypeAdapter : JsonSerializer java.util.HashMap.optGet(key: K): V? { + if (this.containsKey(key)) { + return this.get(key) + } + else { + return null + } +} + +internal fun Map.optGet(key: K): V? { + if (this.containsKey(key)) { + return this.get(key) + } + else { + return null + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 673cb65..bf23ad8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -29,4 +29,7 @@ Set block value OK Cancel + Error establishing connection + Error recovering allowed values + Loading available values...