Add support for fetching custom blocks.
This commit is contained in:
parent
cca4b70b90
commit
8507e868d8
@ -2,15 +2,27 @@ package com.codigoparallevar.minicards;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.codigoparallevar.minicards.types.functional.Consumer;
|
||||
import com.codigoparallevar.minicards.types.functional.Producer;
|
||||
import com.codigoparallevar.minicards.types.functional.Tuple2;
|
||||
import com.codigoparallevar.minicards.ui_helpers.GetAsync;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.programaker.api.ProgramakerApi;
|
||||
import com.programaker.api.data.ProgramakerCustomBlock;
|
||||
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;
|
||||
|
||||
public class CardActivity extends AppCompatActivity {
|
||||
|
||||
@ -19,7 +31,6 @@ public class CardActivity extends AppCompatActivity {
|
||||
public static final String VISUALIZATION_MODE_KEY = "VISUALIZATION_MODE";
|
||||
public static final String DEVELOPER_VISUALIZATION_MODE = "DEVELOPER_VISUALIZATION_MODE";
|
||||
|
||||
|
||||
CanvasView canvasView;
|
||||
com.getbase.floatingactionbutton.AddFloatingActionButton AddPartButton;
|
||||
com.getbase.floatingactionbutton.FloatingActionButton SetDevModeButton;
|
||||
@ -34,11 +45,39 @@ public class CardActivity extends AppCompatActivity {
|
||||
boolean devMode = false;
|
||||
FloatingActionButton removePartFab;
|
||||
private PartsHolder partsHolder;
|
||||
private ProgramakerApi ProgramakerApi;
|
||||
private ConfigManager Config;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
this.Config = new ConfigManager(this);
|
||||
this.ProgramakerApi = new ProgramakerApi();
|
||||
String token = this.Config.getToken();
|
||||
if (token != null) {
|
||||
this.ProgramakerApi.setToken(token);
|
||||
}
|
||||
|
||||
new GetAsync<ProgramakerGetCustomBlocksResult>().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
|
||||
new Tuple2<>(new Producer<ProgramakerGetCustomBlocksResult>() {
|
||||
@Override
|
||||
public ProgramakerGetCustomBlocksResult get() {
|
||||
return CardActivity.this.ProgramakerApi.fetchCustomBlocks();
|
||||
}
|
||||
}, new Consumer<ProgramakerGetCustomBlocksResult>() {
|
||||
@Override
|
||||
public void apply(ProgramakerGetCustomBlocksResult result) {
|
||||
if (result == null) {
|
||||
Log.e("CARDActivity", "error retrieving custom blocks");
|
||||
}
|
||||
else {
|
||||
Log.d("CARDActivity", "custom blocks: " + result.toString());
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
// Hide action bar
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
|
@ -0,0 +1,35 @@
|
||||
package com.codigoparallevar.minicards;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.view.View;
|
||||
|
||||
import static android.content.Context.MODE_PRIVATE;
|
||||
|
||||
public class ConfigManager {
|
||||
private final Context context;
|
||||
private static final String TOKEN_KEY = "PROGRAMAKER_API_TOKEN";
|
||||
private static final String PREFERENCES_NAME = "MINICARDS_PREFERENCES";
|
||||
|
||||
public ConfigManager(Context ctx) {
|
||||
this.context = ctx;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
SharedPreferences preferences = this.context.getSharedPreferences(PREFERENCES_NAME, MODE_PRIVATE);
|
||||
SharedPreferences.Editor edit = preferences.edit();
|
||||
|
||||
edit.putString(TOKEN_KEY, token);
|
||||
edit.commit();
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
SharedPreferences preferences = this.context.getSharedPreferences(PREFERENCES_NAME, MODE_PRIVATE);
|
||||
if (!preferences.contains(TOKEN_KEY)) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return preferences.getString(TOKEN_KEY, null);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,11 +2,10 @@ package com.codigoparallevar.minicards;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.codigoparallevar.minicards.types.functional.Function;
|
||||
import com.codigoparallevar.minicards.types.functional.Consumer;
|
||||
import com.codigoparallevar.minicards.types.functional.Tuple2;
|
||||
import com.codigoparallevar.minicards.types.functional.Tuple3;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
@ -32,13 +31,11 @@ import java.util.Vector;
|
||||
import com.programaker.api.ProgramakerApi;
|
||||
|
||||
public class DeckPreviewActivity extends ReloadableAppCompatActivity {
|
||||
private static final String TOKEN_KEY = "PROGRAMAKER_API_TOKEN";
|
||||
private static final String PREFERENCES_NAME = "MINICARDS_PREFERENCES";
|
||||
|
||||
public static final String INTENT = "com.codigoparallevar.minicards.DECK";
|
||||
private ListView listView;
|
||||
private CardPreviewArrayAdapter cardArrayAdapter;
|
||||
private ProgramakerApi ProgramakerApi = new ProgramakerApi();
|
||||
private ProgramakerApi ProgramakerApi;
|
||||
private ConfigManager Config;
|
||||
|
||||
protected void openLoginDialog(View view) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
@ -95,12 +92,13 @@ public class DeckPreviewActivity extends ReloadableAppCompatActivity {
|
||||
new Tuple3<>(
|
||||
loginUsernameText.getText().toString(),
|
||||
loginPasswordText.getText().toString(),
|
||||
new Function<String>() {
|
||||
new Consumer<String>() {
|
||||
public void apply(String token) {
|
||||
if (token == null) {
|
||||
messageLabel.setText(R.string.invalid_user_pass);
|
||||
} else {
|
||||
DeckPreviewActivity.this.setToken(token);
|
||||
DeckPreviewActivity.this.Config.setToken(token);
|
||||
DeckPreviewActivity.this.ProgramakerApi.setToken(token);
|
||||
final Button loginToProgramakerButton = findViewById(R.id.login_in_programaker_button);
|
||||
|
||||
loginToProgramakerButton.setVisibility(View.GONE);
|
||||
@ -116,30 +114,10 @@ public class DeckPreviewActivity extends ReloadableAppCompatActivity {
|
||||
});
|
||||
}
|
||||
|
||||
private void setToken(String token) {
|
||||
SharedPreferences preferences = getSharedPreferences(PREFERENCES_NAME, MODE_PRIVATE);
|
||||
SharedPreferences.Editor edit = preferences.edit();
|
||||
|
||||
edit.putString(TOKEN_KEY, token);
|
||||
edit.commit();
|
||||
|
||||
this.ProgramakerApi.setToken(token);
|
||||
}
|
||||
|
||||
private String getToken() {
|
||||
SharedPreferences preferences = getSharedPreferences(PREFERENCES_NAME, MODE_PRIVATE);
|
||||
if (!preferences.contains(TOKEN_KEY)) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return preferences.getString(TOKEN_KEY, null);
|
||||
}
|
||||
}
|
||||
|
||||
static class CheckLogin extends AsyncTask<Tuple3<String, String, Function<String>>,
|
||||
Void, Tuple2<String, Function<String>>>{
|
||||
static class CheckLogin extends AsyncTask<Tuple3<String, String, Consumer<String>>,
|
||||
Void, Tuple2<String, Consumer<String>>>{
|
||||
@Override
|
||||
protected Tuple2<String, Function<String>> doInBackground(Tuple3<String, String, Function<String>>... tuples) {
|
||||
protected Tuple2<String, Consumer<String>> doInBackground(Tuple3<String, String, Consumer<String>>... tuples) {
|
||||
ProgramakerApi api = new ProgramakerApi();
|
||||
boolean logged = false;
|
||||
String token = null;
|
||||
@ -149,11 +127,11 @@ public class DeckPreviewActivity extends ReloadableAppCompatActivity {
|
||||
catch (Exception e) {
|
||||
Log.e("Login to PrograMaker", e.toString());
|
||||
}
|
||||
return new Tuple2<String, Function<String>>(token, tuples[0]._z);
|
||||
return new Tuple2<String, Consumer<String>>(token, tuples[0]._z);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Tuple2<String, Function<String>> result) {
|
||||
protected void onPostExecute(Tuple2<String, Consumer<String>> result) {
|
||||
result.item2.apply(result.item1);
|
||||
}
|
||||
}
|
||||
@ -175,6 +153,10 @@ public class DeckPreviewActivity extends ReloadableAppCompatActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
this.Config = new ConfigManager(this);
|
||||
this.ProgramakerApi = new ProgramakerApi();
|
||||
|
||||
setContentView(R.layout.activity_deck_preview);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
@ -196,17 +178,16 @@ public class DeckPreviewActivity extends ReloadableAppCompatActivity {
|
||||
});
|
||||
|
||||
listView = findViewById(R.id.card_deck_list);
|
||||
|
||||
String token = getToken();
|
||||
String token = this.Config.getToken();
|
||||
if (token == null) {
|
||||
loginButton.setVisibility(View.VISIBLE);
|
||||
}
|
||||
else {
|
||||
loginButton.setVisibility(View.GONE);
|
||||
this.ProgramakerApi.setToken(token);
|
||||
// Double check that is not needed
|
||||
loginButton.setVisibility(View.GONE);
|
||||
// Double check that is not needed, token might have been deleted
|
||||
new CheckNeededLoginButton().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
|
||||
new Tuple2<>(this.ProgramakerApi, loginButton));
|
||||
new Tuple2<>(this.ProgramakerApi, loginButton));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
package com.codigoparallevar.minicards.types.functional;
|
||||
|
||||
public abstract class Function<T> {
|
||||
public abstract class Consumer<T> {
|
||||
public abstract void apply(T param);
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package com.codigoparallevar.minicards.types.functional;
|
||||
|
||||
public abstract class Producer<T> {
|
||||
public abstract T get();
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.codigoparallevar.minicards.ui_helpers;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import com.codigoparallevar.minicards.types.functional.Consumer;
|
||||
import com.codigoparallevar.minicards.types.functional.Producer;
|
||||
import com.codigoparallevar.minicards.types.functional.Tuple2;
|
||||
|
||||
public class GetAsync<T> extends AsyncTask<Tuple2<Producer<T>, Consumer<T>>,
|
||||
Void,
|
||||
Tuple2<T, Consumer<T>>> {
|
||||
|
||||
@Override
|
||||
protected Tuple2<T, Consumer<T>> doInBackground(Tuple2<Producer<T>, Consumer<T>>... data) {
|
||||
try {
|
||||
return new Tuple2<>(data[0].item1.get(), data[0].item2);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.e("GetAsync", ex.toString());
|
||||
return new Tuple2<>(null, data[0].item2);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Tuple2<T, Consumer<T>> result) {
|
||||
result.item2.apply(result.item1);
|
||||
}
|
||||
}
|
@ -3,6 +3,15 @@ package com.programaker.api
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.programaker.api.data.ProgramakerCustomBlock
|
||||
import com.programaker.api.data.api_results.ProgramakerCheckResult
|
||||
import com.programaker.api.data.api_results.ProgramakerGetCustomBlocksResult
|
||||
import com.programaker.api.data.api_results.ProgramakerGetCustomBlocksResultTypeAdapter
|
||||
import com.programaker.api.data.api_results.ProgramakerLoginResult
|
||||
import com.programaker.api.exceptions.ProgramakerLoginRequiredException
|
||||
import com.programaker.api.exceptions.ProgramakerProtocolException
|
||||
import com.programaker.api.exceptions.TokenNotFoundException
|
||||
import org.json.JSONObject
|
||||
import java.io.DataOutputStream
|
||||
import java.io.FileNotFoundException
|
||||
@ -16,6 +25,9 @@ import java.net.URLConnection
|
||||
|
||||
class ProgramakerApi(private val ApiRoot: String="https://programaker.com/api") {
|
||||
private val LogTag: String = "ProgramakerApi"
|
||||
|
||||
private var userId: String? = null
|
||||
private var userName: String? = null
|
||||
var token: String? = null
|
||||
|
||||
// API
|
||||
@ -41,9 +53,16 @@ class ProgramakerApi(private val ApiRoot: String="https://programaker.com/api")
|
||||
ex.logError(LogTag)
|
||||
return false
|
||||
}
|
||||
|
||||
if (result.success) {
|
||||
this.userId = result.user_id;
|
||||
this.userName = result.username;
|
||||
}
|
||||
|
||||
return result.success
|
||||
}
|
||||
|
||||
|
||||
fun login(user: String, password: String): String {
|
||||
val conn = URL(getLoginUrl()).openConnection() as HttpURLConnection
|
||||
conn.setRequestProperty("Content-Type", "application/json")
|
||||
@ -65,6 +84,31 @@ class ProgramakerApi(private val ApiRoot: String="https://programaker.com/api")
|
||||
return result.token
|
||||
}
|
||||
|
||||
fun fetchCustomBlocks(): ProgramakerGetCustomBlocksResult {
|
||||
val conn = URL(getCustomBlocksUrl()).openConnection() as HttpURLConnection
|
||||
|
||||
addAuthHeader(conn)
|
||||
|
||||
val result: ProgramakerGetCustomBlocksResult
|
||||
|
||||
try {
|
||||
val builder = GsonBuilder()
|
||||
builder.registerTypeAdapter(ProgramakerGetCustomBlocksResult::class.java, ProgramakerGetCustomBlocksResultTypeAdapter())
|
||||
|
||||
val gson = builder.create()
|
||||
val reader = InputStreamReader(conn.inputStream)
|
||||
|
||||
result = gson.fromJson(reader, ProgramakerGetCustomBlocksResult::class.java)
|
||||
} catch(ex: JsonParseException) {
|
||||
ex.logError(LogTag)
|
||||
throw ProgramakerProtocolException()
|
||||
} catch (ex: FileNotFoundException) {
|
||||
ex.logError(LogTag)
|
||||
throw ProgramakerProtocolException()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Initialization
|
||||
init {
|
||||
// Disable connection reuse if necessary
|
||||
@ -83,6 +127,21 @@ class ProgramakerApi(private val ApiRoot: String="https://programaker.com/api")
|
||||
return "$ApiRoot/v0/sessions/login"
|
||||
}
|
||||
|
||||
private fun getCustomBlocksUrl(): String {
|
||||
if (userName == null) {
|
||||
if (token == null) {
|
||||
throw ProgramakerLoginRequiredException()
|
||||
}
|
||||
|
||||
this.check();
|
||||
if (userName == null) {
|
||||
throw ProgramakerProtocolException()
|
||||
}
|
||||
}
|
||||
|
||||
return "$ApiRoot/v0/users/$userName/custom-blocks/"
|
||||
}
|
||||
|
||||
private fun addAuthHeader(conn: URLConnection) {
|
||||
if (token != null) {
|
||||
conn.setRequestProperty("Authorization", token)
|
||||
|
@ -1,5 +0,0 @@
|
||||
package com.programaker.api
|
||||
|
||||
class ProgramakerCheckResult(val success: Boolean) {
|
||||
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
package com.programaker.api
|
||||
|
||||
class TokenNotFoundException : ProgramakerConfigurationException() {
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.programaker.api.data
|
||||
|
||||
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,
|
||||
) {
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package com.programaker.api.data.api_results
|
||||
|
||||
import com.programaker.api.data.ProgramakerCustomBlock
|
||||
|
||||
class ProgramakerBridgeCustomBlockResult(val bridge_id: String, val blocks: List<ProgramakerCustomBlock>) {
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package com.programaker.api.data.api_results
|
||||
|
||||
class ProgramakerCheckResult(val success: Boolean, val user_id: String, val username: String) {
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package com.programaker.api.data.api_results
|
||||
|
||||
class ProgramakerGetCustomBlocksResult(val result: List<ProgramakerBridgeCustomBlockResult>) {
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.programaker.api.data.api_results
|
||||
|
||||
import com.google.gson.*
|
||||
import com.programaker.api.data.ProgramakerCustomBlock
|
||||
import java.lang.reflect.Type
|
||||
import java.util.*
|
||||
|
||||
class ProgramakerGetCustomBlocksResultTypeAdapter : JsonSerializer<ProgramakerGetCustomBlocksResult?>, JsonDeserializer<ProgramakerGetCustomBlocksResult> {
|
||||
var gson = Gson()
|
||||
override fun serialize(customBlock: ProgramakerGetCustomBlocksResult?, typeOfT: Type, context: JsonSerializationContext): JsonElement {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
@Throws(JsonParseException::class)
|
||||
override fun deserialize(element: JsonElement, typeOfT: Type, context: JsonDeserializationContext): ProgramakerGetCustomBlocksResult {
|
||||
val json = element.asJsonObject
|
||||
val bridges: MutableList<ProgramakerBridgeCustomBlockResult> = LinkedList()
|
||||
|
||||
for ((bridgeId, value1) in json.entrySet()) {
|
||||
|
||||
val blocks: MutableList<ProgramakerCustomBlock> = LinkedList()
|
||||
|
||||
for (value in value1.asJsonArray) {
|
||||
val block = gson.fromJson(value, ProgramakerCustomBlock::class.java)
|
||||
blocks.add(block)
|
||||
}
|
||||
|
||||
val bridge = ProgramakerBridgeCustomBlockResult(bridgeId, blocks)
|
||||
bridges.add(bridge)
|
||||
}
|
||||
|
||||
return ProgramakerGetCustomBlocksResult(bridges)
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.programaker.api
|
||||
package com.programaker.api.data.api_results
|
||||
|
||||
class ProgramakerLoginResult(val user_id: String, val token: String, val success: Boolean) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.programaker.api
|
||||
package com.programaker.api.exceptions
|
||||
|
||||
open class ProgramakerConfigurationException : Exception() {
|
||||
|
@ -0,0 +1,5 @@
|
||||
package com.programaker.api.exceptions
|
||||
|
||||
class ProgramakerLoginRequiredException : Throwable() {
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.programaker.api
|
||||
package com.programaker.api.exceptions
|
||||
|
||||
class ProgramakerNetworkException : Throwable() {
|
||||
|
@ -0,0 +1,5 @@
|
||||
package com.programaker.api.exceptions
|
||||
|
||||
class ProgramakerProtocolException : Throwable() {
|
||||
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package com.programaker.api.exceptions
|
||||
|
||||
import com.programaker.api.exceptions.ProgramakerConfigurationException
|
||||
|
||||
class TokenNotFoundException : ProgramakerConfigurationException() {
|
||||
}
|
Loading…
Reference in New Issue
Block a user