- Added partial support for the 'get_objects' API call in the single connection mode
- Changed the layout of the sample app in order to present a list of all supported API calls in the first activity - Introducing a specific activity to perform the API calls in the sample app
This commit is contained in:
parent
c5ffc614f4
commit
222fd88afa
15 changed files with 720 additions and 12 deletions
|
@ -22,7 +22,7 @@ public class RPC {
|
||||||
public static final String CALL_GET_ACCOUNT_HISTORY = "get_account_history";
|
public static final String CALL_GET_ACCOUNT_HISTORY = "get_account_history";
|
||||||
public static final String CALL_LOOKUP_ACCOUNTS = "lookup_accounts";
|
public static final String CALL_LOOKUP_ACCOUNTS = "lookup_accounts";
|
||||||
public static final String CALL_LIST_ASSETS = "list_assets";
|
public static final String CALL_LIST_ASSETS = "list_assets";
|
||||||
public static final String GET_OBJECTS = "get_objects";
|
public static final String CALL_GET_OBJECTS = "get_objects";
|
||||||
public static final String GET_ACCOUNT_BALANCES = "get_account_balances";
|
public static final String GET_ACCOUNT_BALANCES = "get_account_balances";
|
||||||
public static final String CALL_LOOKUP_ASSET_SYMBOLS = "lookup_asset_symbols";
|
public static final String CALL_LOOKUP_ASSET_SYMBOLS = "lookup_asset_symbols";
|
||||||
public static final String CALL_GET_BLOCK_HEADER = "get_block_header";
|
public static final String CALL_GET_BLOCK_HEADER = "get_block_header";
|
||||||
|
|
|
@ -75,11 +75,9 @@ public class GetObjects extends BaseGrapheneHandler {
|
||||||
public void onConnected(WebSocket websocket, Map<String, List<String>> headers) throws Exception {
|
public void onConnected(WebSocket websocket, Map<String, List<String>> headers) throws Exception {
|
||||||
ArrayList<Serializable> params = new ArrayList<>();
|
ArrayList<Serializable> params = new ArrayList<>();
|
||||||
ArrayList<Serializable> subParams = new ArrayList<>();
|
ArrayList<Serializable> subParams = new ArrayList<>();
|
||||||
for(String id : this.ids){
|
subParams.addAll(this.ids);
|
||||||
subParams.add(id);
|
|
||||||
}
|
|
||||||
params.add(subParams);
|
params.add(subParams);
|
||||||
ApiCall apiCall = new ApiCall(0, RPC.GET_OBJECTS, params, RPC.VERSION, 0);
|
ApiCall apiCall = new ApiCall(0, RPC.CALL_GET_OBJECTS, params, RPC.VERSION, 0);
|
||||||
websocket.sendText(apiCall.toJsonString());
|
websocket.sendText(apiCall.toJsonString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -188,7 +188,7 @@ public class SubscriptionMessagesHub extends BaseGrapheneHandler implements Subs
|
||||||
}
|
}
|
||||||
|
|
||||||
payload.add(objects);
|
payload.add(objects);
|
||||||
ApiCall subscribe = new ApiCall(databaseApiId, RPC.GET_OBJECTS, payload, RPC.VERSION, MANUAL_SUBSCRIPTION_ID);
|
ApiCall subscribe = new ApiCall(databaseApiId, RPC.CALL_GET_OBJECTS, payload, RPC.VERSION, MANUAL_SUBSCRIPTION_ID);
|
||||||
websocket.sendText(subscribe.toJsonString());
|
websocket.sendText(subscribe.toJsonString());
|
||||||
subscriptionCounter++;
|
subscriptionCounter++;
|
||||||
}else{
|
}else{
|
||||||
|
|
|
@ -18,6 +18,7 @@ import cy.agorise.graphenej.api.calls.GetAccounts;
|
||||||
import cy.agorise.graphenej.api.calls.GetBlock;
|
import cy.agorise.graphenej.api.calls.GetBlock;
|
||||||
import cy.agorise.graphenej.api.calls.GetBlockHeader;
|
import cy.agorise.graphenej.api.calls.GetBlockHeader;
|
||||||
import cy.agorise.graphenej.api.calls.GetMarketHistory;
|
import cy.agorise.graphenej.api.calls.GetMarketHistory;
|
||||||
|
import cy.agorise.graphenej.api.calls.GetObjects;
|
||||||
import cy.agorise.graphenej.api.calls.GetRelativeAccountHistory;
|
import cy.agorise.graphenej.api.calls.GetRelativeAccountHistory;
|
||||||
import cy.agorise.graphenej.api.calls.GetRequiredFees;
|
import cy.agorise.graphenej.api.calls.GetRequiredFees;
|
||||||
import cy.agorise.graphenej.api.calls.LookupAssetSymbols;
|
import cy.agorise.graphenej.api.calls.LookupAssetSymbols;
|
||||||
|
@ -101,6 +102,13 @@ public class DeserializationMap {
|
||||||
.registerTypeAdapter(Asset.class, new Asset.AssetDeserializer())
|
.registerTypeAdapter(Asset.class, new Asset.AssetDeserializer())
|
||||||
.create();
|
.create();
|
||||||
mGsonMap.put(LookupAssetSymbols.class, lookupAssetSymbolGson);
|
mGsonMap.put(LookupAssetSymbols.class, lookupAssetSymbolGson);
|
||||||
|
|
||||||
|
// GetObjects
|
||||||
|
mClassMap.put(GetObjects.class, List.class);
|
||||||
|
Gson getObjectsGson = new GsonBuilder()
|
||||||
|
.registerTypeAdapter(Asset.class, new Asset.AssetDeserializer())
|
||||||
|
.create();
|
||||||
|
mGsonMap.put(GetObjects.class, getObjectsGson);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class getReceivedClass(Class _class){
|
public Class getReceivedClass(Class _class){
|
||||||
|
|
|
@ -25,6 +25,7 @@ import cy.agorise.graphenej.api.bitshares.Nodes;
|
||||||
import cy.agorise.graphenej.api.calls.ApiCallable;
|
import cy.agorise.graphenej.api.calls.ApiCallable;
|
||||||
import cy.agorise.graphenej.api.calls.GetAccounts;
|
import cy.agorise.graphenej.api.calls.GetAccounts;
|
||||||
import cy.agorise.graphenej.api.calls.GetMarketHistory;
|
import cy.agorise.graphenej.api.calls.GetMarketHistory;
|
||||||
|
import cy.agorise.graphenej.api.calls.GetObjects;
|
||||||
import cy.agorise.graphenej.api.calls.GetRelativeAccountHistory;
|
import cy.agorise.graphenej.api.calls.GetRelativeAccountHistory;
|
||||||
import cy.agorise.graphenej.api.calls.GetRequiredFees;
|
import cy.agorise.graphenej.api.calls.GetRequiredFees;
|
||||||
import cy.agorise.graphenej.models.AccountProperties;
|
import cy.agorise.graphenej.models.AccountProperties;
|
||||||
|
@ -314,6 +315,8 @@ public class NetworkService extends Service {
|
||||||
}else if(requestClass == GetMarketHistory.class){
|
}else if(requestClass == GetMarketHistory.class){
|
||||||
Type GetMarketHistoryResponse = new TypeToken<JsonRpcResponse<List<BucketObject>>>(){}.getType();
|
Type GetMarketHistoryResponse = new TypeToken<JsonRpcResponse<List<BucketObject>>>(){}.getType();
|
||||||
parsedResponse = gson.fromJson(text, GetMarketHistoryResponse);
|
parsedResponse = gson.fromJson(text, GetMarketHistoryResponse);
|
||||||
|
}else if(requestClass == GetObjects.class){
|
||||||
|
parsedResponse = handleGetObject(text);
|
||||||
}else{
|
}else{
|
||||||
Log.w(TAG,"Unknown request class");
|
Log.w(TAG,"Unknown request class");
|
||||||
}
|
}
|
||||||
|
@ -331,6 +334,26 @@ public class NetworkService extends Service {
|
||||||
RxBus.getBusInstance().send(parsedResponse);
|
RxBus.getBusInstance().send(parsedResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method used to try to deserialize a 'get_objects' API call. Since this request can be used
|
||||||
|
* for several types of objects, the de-serialization procedure can be a bit more complex.
|
||||||
|
*
|
||||||
|
* @param response Response to a 'get_objects' API call
|
||||||
|
*/
|
||||||
|
private JsonRpcResponse handleGetObject(String response){
|
||||||
|
//TODO: Implement a proper de-serialization logic
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method used to check all possible API accesses.
|
||||||
|
*
|
||||||
|
* The service will try to obtain sequentially API access ids for the following APIs:
|
||||||
|
*
|
||||||
|
* - Database
|
||||||
|
* - History
|
||||||
|
* - Network broadcast
|
||||||
|
*/
|
||||||
private void checkNextRequestedApiAccess(){
|
private void checkNextRequestedApiAccess(){
|
||||||
if( (mRequestedApis & ApiAccess.API_DATABASE) == ApiAccess.API_DATABASE &&
|
if( (mRequestedApis & ApiAccess.API_DATABASE) == ApiAccess.API_DATABASE &&
|
||||||
mApiIds.get(ApiAccess.API_DATABASE) == null){
|
mApiIds.get(ApiAccess.API_DATABASE) == null){
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package cy.agorise.graphenej.api.calls;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import cy.agorise.graphenej.RPC;
|
||||||
|
import cy.agorise.graphenej.api.ApiAccess;
|
||||||
|
import cy.agorise.graphenej.models.ApiCall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper around the "get_objects" API call.
|
||||||
|
*/
|
||||||
|
public class GetObjects implements ApiCallable {
|
||||||
|
public static final int REQUIRED_API = ApiAccess.API_DATABASE;
|
||||||
|
private List<String> ids;
|
||||||
|
|
||||||
|
public GetObjects(List<String> ids){
|
||||||
|
this.ids = ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiCall toApiCall(int apiId, long sequenceId) {
|
||||||
|
ArrayList<Serializable> params = new ArrayList<>();
|
||||||
|
ArrayList<String> subParams = new ArrayList<>(ids);
|
||||||
|
params.add(subParams);
|
||||||
|
return new ApiCall(apiId, RPC.CALL_GET_OBJECTS, params, RPC.VERSION, sequenceId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,24 +1,27 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="cy.agorise.labs.sample">
|
package="cy.agorise.labs.sample">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
android:name=".SampleApplication"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme">
|
||||||
android:name=".SampleApplication">
|
<activity android:name=".MainActivity"></activity>
|
||||||
<activity android:name=".MainActivity">
|
<activity android:name=".SecondActivity" />
|
||||||
|
<activity android:name=".CallsActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity android:name=".PerformCallActivity"></activity>
|
||||||
<activity android:name=".SecondActivity"></activity>
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
|
@ -0,0 +1,83 @@
|
||||||
|
package cy.agorise.labs.sample;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.support.v7.widget.DividerItemDecoration;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
import cy.agorise.graphenej.RPC;
|
||||||
|
|
||||||
|
public class CallsActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
@BindView(R.id.call_list)
|
||||||
|
RecyclerView mRecyclerView;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_calls);
|
||||||
|
ButterKnife.bind(this);
|
||||||
|
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
|
||||||
|
mRecyclerView.setHasFixedSize(true);
|
||||||
|
mRecyclerView.setLayoutManager(linearLayoutManager);
|
||||||
|
mRecyclerView.addItemDecoration(new DividerItemDecoration(this, linearLayoutManager.getOrientation()));
|
||||||
|
mRecyclerView.setAdapter(new CallAdapter());
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class CallAdapter extends RecyclerView.Adapter<CallAdapter.ViewHolder> {
|
||||||
|
|
||||||
|
private String[] supportedCalls = new String[]{
|
||||||
|
RPC.CALL_GET_OBJECTS,
|
||||||
|
RPC.CALL_GET_ACCOUNTS,
|
||||||
|
RPC.CALL_GET_BLOCK,
|
||||||
|
RPC.CALL_GET_BLOCK_HEADER,
|
||||||
|
RPC.CALL_GET_MARKET_HISTORY,
|
||||||
|
RPC.CALL_GET_RELATIVE_ACCOUNT_HISTORY,
|
||||||
|
RPC.CALL_GET_REQUIRED_FEES,
|
||||||
|
RPC.CALL_LOOKUP_ASSET_SYMBOLS
|
||||||
|
};
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
TextView v = (TextView) LayoutInflater.from(parent.getContext())
|
||||||
|
.inflate(R.layout.item_call, parent, false);
|
||||||
|
return new ViewHolder(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||||
|
String name = supportedCalls[position];
|
||||||
|
String formattedName = name.replace("_", " ").toUpperCase();
|
||||||
|
holder.mCallNameView.setText(formattedName);
|
||||||
|
holder.mCallNameView.setOnClickListener((view) -> {
|
||||||
|
Intent intent = new Intent(CallsActivity.this, PerformCallActivity.class);
|
||||||
|
String selectedCall = ((TextView)view).getText().toString().replace(" ", "_").toLowerCase();
|
||||||
|
intent.putExtra(Constants.KEY_SELECTED_CALL, selectedCall);
|
||||||
|
startActivity(intent);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return supportedCalls.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
public TextView mCallNameView;
|
||||||
|
|
||||||
|
public ViewHolder(TextView view) {
|
||||||
|
super(view);
|
||||||
|
this.mCallNameView = view;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package cy.agorise.labs.sample;
|
||||||
|
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.ServiceConnection;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import cy.agorise.graphenej.api.android.NetworkService;
|
||||||
|
|
||||||
|
public abstract class ConnectedActivity extends AppCompatActivity implements ServiceConnection {
|
||||||
|
private final String TAG = this.getClass().getName();
|
||||||
|
|
||||||
|
/* Network service connection */
|
||||||
|
protected NetworkService mNetworkService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag used to keep track of the NetworkService binding state
|
||||||
|
*/
|
||||||
|
private boolean mShouldUnbindNetwork;
|
||||||
|
|
||||||
|
private ServiceConnection mNetworkServiceConnection = new ServiceConnection() {
|
||||||
|
@Override
|
||||||
|
public void onServiceConnected(ComponentName className,
|
||||||
|
IBinder service) {
|
||||||
|
// We've bound to LocalService, cast the IBinder and get LocalService instance
|
||||||
|
NetworkService.LocalBinder binder = (NetworkService.LocalBinder) service;
|
||||||
|
mNetworkService = binder.getService();
|
||||||
|
|
||||||
|
ConnectedActivity.this.onServiceConnected(className, service);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceDisconnected(ComponentName componentName) {
|
||||||
|
ConnectedActivity.this.onServiceDisconnected(componentName);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
// Binding to NetworkService
|
||||||
|
Intent intent = new Intent(this, NetworkService.class);
|
||||||
|
if(bindService(intent, mNetworkServiceConnection, Context.BIND_AUTO_CREATE)){
|
||||||
|
mShouldUnbindNetwork = true;
|
||||||
|
}else{
|
||||||
|
Log.e(TAG,"Binding to the network service failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
// Unbinding from network service
|
||||||
|
if(mShouldUnbindNetwork){
|
||||||
|
unbindService(mNetworkServiceConnection);
|
||||||
|
mShouldUnbindNetwork = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package cy.agorise.labs.sample;
|
||||||
|
|
||||||
|
public class Constants {
|
||||||
|
/**
|
||||||
|
* Key used to pass the selected call as an intent extra
|
||||||
|
*/
|
||||||
|
public static final String KEY_SELECTED_CALL = "key_call";
|
||||||
|
}
|
|
@ -0,0 +1,322 @@
|
||||||
|
package cy.agorise.labs.sample;
|
||||||
|
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.support.design.widget.TextInputEditText;
|
||||||
|
import android.support.design.widget.TextInputLayout;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
import butterknife.OnClick;
|
||||||
|
import cy.agorise.graphenej.RPC;
|
||||||
|
import cy.agorise.graphenej.UserAccount;
|
||||||
|
import cy.agorise.graphenej.api.ConnectionStatusUpdate;
|
||||||
|
import cy.agorise.graphenej.api.android.DeserializationMap;
|
||||||
|
import cy.agorise.graphenej.api.android.RxBus;
|
||||||
|
import cy.agorise.graphenej.api.calls.GetAccounts;
|
||||||
|
import cy.agorise.graphenej.api.calls.GetBlock;
|
||||||
|
import cy.agorise.graphenej.api.calls.GetObjects;
|
||||||
|
import cy.agorise.graphenej.models.JsonRpcResponse;
|
||||||
|
import cy.agorise.graphenej.objects.Memo;
|
||||||
|
import cy.agorise.graphenej.operations.TransferOperation;
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.disposables.Disposable;
|
||||||
|
import io.reactivex.functions.Consumer;
|
||||||
|
|
||||||
|
public class PerformCallActivity extends ConnectedActivity {
|
||||||
|
private final String TAG = this.getClass().getName();
|
||||||
|
|
||||||
|
@BindView(R.id.response)
|
||||||
|
TextView mResponseView;
|
||||||
|
|
||||||
|
@BindView(R.id.container_param1)
|
||||||
|
TextInputLayout mParam1View;
|
||||||
|
|
||||||
|
@BindView(R.id.container_param2)
|
||||||
|
TextInputLayout mParam2View;
|
||||||
|
|
||||||
|
@BindView(R.id.container_param3)
|
||||||
|
TextInputLayout mParam3View;
|
||||||
|
|
||||||
|
@BindView(R.id.container_param4)
|
||||||
|
TextInputLayout mParam4View;
|
||||||
|
|
||||||
|
@BindView(R.id.param1)
|
||||||
|
TextInputEditText param1;
|
||||||
|
|
||||||
|
@BindView(R.id.param2)
|
||||||
|
TextInputEditText param2;
|
||||||
|
|
||||||
|
@BindView(R.id.param3)
|
||||||
|
TextInputEditText param3;
|
||||||
|
|
||||||
|
@BindView(R.id.param4)
|
||||||
|
TextInputEditText param4;
|
||||||
|
|
||||||
|
@BindView(R.id.button_send)
|
||||||
|
Button mButtonSend;
|
||||||
|
|
||||||
|
// Field used to map a request id to its type
|
||||||
|
private HashMap<Long, String> responseMap = new HashMap<>();
|
||||||
|
|
||||||
|
// Current request type. Ex: 'get_objects', 'get_accounts', etc
|
||||||
|
private String mRPC;
|
||||||
|
|
||||||
|
private Disposable mDisposable;
|
||||||
|
|
||||||
|
private Gson gson = new GsonBuilder()
|
||||||
|
.setExclusionStrategies(new DeserializationMap.SkipAccountOptionsStrategy(), new DeserializationMap.SkipAssetOptionsStrategy())
|
||||||
|
.registerTypeAdapter(TransferOperation.class, new TransferOperation.TransferDeserializer())
|
||||||
|
.registerTypeAdapter(Memo.class, new Memo.MemoSerializer())
|
||||||
|
.create();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_perform_call);
|
||||||
|
ButterKnife.bind(this);
|
||||||
|
|
||||||
|
mRPC = getIntent().getStringExtra(Constants.KEY_SELECTED_CALL);
|
||||||
|
Log.d(TAG,"Selected call: "+mRPC);
|
||||||
|
switch (mRPC){
|
||||||
|
case RPC.CALL_GET_OBJECTS:
|
||||||
|
setupGetObjects();
|
||||||
|
break;
|
||||||
|
case RPC.CALL_GET_ACCOUNTS:
|
||||||
|
setupGetAccounts();
|
||||||
|
break;
|
||||||
|
case RPC.CALL_GET_BLOCK:
|
||||||
|
setupGetBlock();
|
||||||
|
break;
|
||||||
|
case RPC.CALL_GET_BLOCK_HEADER:
|
||||||
|
setupGetBlockHeader();
|
||||||
|
break;
|
||||||
|
case RPC.CALL_GET_MARKET_HISTORY:
|
||||||
|
setupGetMarketHistory();
|
||||||
|
break;
|
||||||
|
case RPC.CALL_GET_RELATIVE_ACCOUNT_HISTORY:
|
||||||
|
setupGetRelativeAccountHistory();
|
||||||
|
break;
|
||||||
|
case RPC.CALL_GET_REQUIRED_FEES:
|
||||||
|
break;
|
||||||
|
case RPC.CALL_LOOKUP_ASSET_SYMBOLS:
|
||||||
|
setupLookupAssetSymbols();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.d(TAG,"Default called");
|
||||||
|
}
|
||||||
|
|
||||||
|
mDisposable = RxBus.getBusInstance()
|
||||||
|
.asFlowable()
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(new Consumer<Object>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(Object message) throws Exception {
|
||||||
|
Log.d(TAG,"accept. Msg class: "+message.getClass());
|
||||||
|
if(message instanceof ConnectionStatusUpdate){
|
||||||
|
// TODO: Update UI ?
|
||||||
|
}else if(message instanceof JsonRpcResponse){
|
||||||
|
handleJsonRpcResponse((JsonRpcResponse) message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupGetObjects(){
|
||||||
|
requiredInput(1);
|
||||||
|
mParam1View.setHint(getResources().getString(R.string.get_objects_arg1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupGetAccounts(){
|
||||||
|
requiredInput(1);
|
||||||
|
mParam1View.setHint(getResources().getString(R.string.get_accounts_arg1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupGetBlock(){
|
||||||
|
requiredInput(1);
|
||||||
|
mParam1View.setHint(getResources().getString(R.string.get_block_arg1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupGetBlockHeader(){
|
||||||
|
requiredInput(1);
|
||||||
|
mParam1View.setHint(getResources().getString(R.string.get_block_arg1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupGetMarketHistory(){
|
||||||
|
requiredInput(4);
|
||||||
|
Resources resources = getResources();
|
||||||
|
mParam1View.setHint(resources.getString(R.string.get_market_history_arg1));
|
||||||
|
mParam2View.setHint(resources.getString(R.string.get_market_history_arg2));
|
||||||
|
mParam3View.setHint(resources.getString(R.string.get_market_history_arg3));
|
||||||
|
mParam4View.setHint(resources.getString(R.string.get_market_history_arg4));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupGetRelativeAccountHistory(){
|
||||||
|
requiredInput(4);
|
||||||
|
Resources resources = getResources();
|
||||||
|
mParam1View.setHint(resources.getString(R.string.get_relative_account_history_arg1));
|
||||||
|
mParam2View.setHint(resources.getString(R.string.get_relative_account_history_arg2));
|
||||||
|
mParam3View.setHint(resources.getString(R.string.get_relative_account_history_arg3));
|
||||||
|
mParam4View.setHint(resources.getString(R.string.get_relative_account_history_arg4));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupLookupAssetSymbols(){
|
||||||
|
requiredInput(4);
|
||||||
|
Resources resources = getResources();
|
||||||
|
mParam1View.setHint(resources.getString(R.string.lookup_asset_symbols_arg1));
|
||||||
|
mParam2View.setHint(resources.getString(R.string.lookup_asset_symbols_arg2));
|
||||||
|
mParam3View.setHint(resources.getString(R.string.lookup_asset_symbols_arg3));
|
||||||
|
mParam4View.setHint(resources.getString(R.string.lookup_asset_symbols_arg4));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requiredInput(int inputCount){
|
||||||
|
if(inputCount == 1){
|
||||||
|
mParam1View.setVisibility(View.VISIBLE);
|
||||||
|
mParam2View.setVisibility(View.GONE);
|
||||||
|
mParam3View.setVisibility(View.GONE);
|
||||||
|
mParam4View.setVisibility(View.GONE);
|
||||||
|
}else if(inputCount == 2){
|
||||||
|
mParam1View.setVisibility(View.VISIBLE);
|
||||||
|
mParam2View.setVisibility(View.VISIBLE);
|
||||||
|
mParam3View.setVisibility(View.GONE);
|
||||||
|
mParam4View.setVisibility(View.GONE);
|
||||||
|
}else if(inputCount == 3){
|
||||||
|
mParam1View.setVisibility(View.VISIBLE);
|
||||||
|
mParam2View.setVisibility(View.VISIBLE);
|
||||||
|
mParam3View.setVisibility(View.VISIBLE);
|
||||||
|
mParam4View.setVisibility(View.GONE);
|
||||||
|
}else if(inputCount == 4){
|
||||||
|
mParam1View.setVisibility(View.VISIBLE);
|
||||||
|
mParam2View.setVisibility(View.VISIBLE);
|
||||||
|
mParam3View.setVisibility(View.VISIBLE);
|
||||||
|
mParam4View.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnClick(R.id.button_send)
|
||||||
|
public void onSendClicked(Button v){
|
||||||
|
switch (mRPC){
|
||||||
|
case RPC.CALL_GET_OBJECTS:
|
||||||
|
sendGetObjectsRequest();
|
||||||
|
break;
|
||||||
|
case RPC.CALL_GET_ACCOUNTS:
|
||||||
|
sendGetAccountsRequest();
|
||||||
|
break;
|
||||||
|
case RPC.CALL_GET_BLOCK:
|
||||||
|
break;
|
||||||
|
case RPC.CALL_GET_BLOCK_HEADER:
|
||||||
|
break;
|
||||||
|
case RPC.CALL_GET_MARKET_HISTORY:
|
||||||
|
break;
|
||||||
|
case RPC.CALL_GET_RELATIVE_ACCOUNT_HISTORY:
|
||||||
|
break;
|
||||||
|
case RPC.CALL_GET_REQUIRED_FEES:
|
||||||
|
break;
|
||||||
|
case RPC.CALL_LOOKUP_ASSET_SYMBOLS:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.d(TAG,"Default called");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendGetObjectsRequest(){
|
||||||
|
String objectId = param1.getText().toString();
|
||||||
|
if(objectId.matches("\\d\\.\\d{1,3}\\.\\d{1,10}")){
|
||||||
|
ArrayList<String> array = new ArrayList<>();
|
||||||
|
array.add(objectId);
|
||||||
|
GetObjects getObjects = new GetObjects(array);
|
||||||
|
long id = mNetworkService.sendMessage(getObjects, GetObjects.REQUIRED_API);
|
||||||
|
responseMap.put(id, mRPC);
|
||||||
|
}else{
|
||||||
|
param1.setError(getResources().getString(R.string.error_input_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendGetAccountsRequest(){
|
||||||
|
String userId = param1.getText().toString();
|
||||||
|
if(userId.matches("\\d\\.\\d{1,3}\\.\\d{1,10}")){
|
||||||
|
GetAccounts getAccounts = new GetAccounts(new UserAccount(userId));
|
||||||
|
long id = mNetworkService.sendMessage(getAccounts, GetBlock.REQUIRED_API);
|
||||||
|
responseMap.put(id, mRPC);
|
||||||
|
}else{
|
||||||
|
param1.setError(getResources().getString(R.string.error_input_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal method that will decide what to do with each JSON-RPC response
|
||||||
|
*
|
||||||
|
* @param response The JSON-RPC api call response
|
||||||
|
*/
|
||||||
|
private void handleJsonRpcResponse(JsonRpcResponse response){
|
||||||
|
long id = response.id;
|
||||||
|
if(responseMap.get(id) != null){
|
||||||
|
String request = responseMap.get(id);
|
||||||
|
switch(request){
|
||||||
|
case RPC.CALL_GET_ACCOUNTS:
|
||||||
|
mResponseView.setText(mResponseView.getText() + gson.toJson(response, JsonRpcResponse.class) + "\n");
|
||||||
|
break;
|
||||||
|
case RPC.CALL_GET_BLOCK:
|
||||||
|
mResponseView.setText(mResponseView.getText() + gson.toJson(response, JsonRpcResponse.class) + "\n");
|
||||||
|
break;
|
||||||
|
case RPC.CALL_GET_BLOCK_HEADER:
|
||||||
|
mResponseView.setText(mResponseView.getText() + gson.toJson(response, JsonRpcResponse.class) + "\n");
|
||||||
|
break;
|
||||||
|
case RPC.CALL_GET_MARKET_HISTORY:
|
||||||
|
mResponseView.setText(mResponseView.getText() + gson.toJson(response, JsonRpcResponse.class) + "\n");
|
||||||
|
break;
|
||||||
|
case RPC.CALL_GET_ACCOUNT_HISTORY:
|
||||||
|
mResponseView.setText(mResponseView.getText() + gson.toJson(response, JsonRpcResponse.class) + "\n");
|
||||||
|
break;
|
||||||
|
case RPC.CALL_GET_RELATIVE_ACCOUNT_HISTORY:
|
||||||
|
mResponseView.setText(mResponseView.getText() + gson.toJson(response, JsonRpcResponse.class) + "\n");
|
||||||
|
break;
|
||||||
|
case RPC.CALL_GET_REQUIRED_FEES:
|
||||||
|
mResponseView.setText(mResponseView.getText() + gson.toJson(response, JsonRpcResponse.class) + "\n");
|
||||||
|
break;
|
||||||
|
case RPC.CALL_LOOKUP_ASSET_SYMBOLS:
|
||||||
|
mResponseView.setText(mResponseView.getText() + gson.toJson(response, JsonRpcResponse.class) + "\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.w(TAG,"Case not handled");
|
||||||
|
mResponseView.setText(mResponseView.getText() + response.result.toString());
|
||||||
|
}
|
||||||
|
// Remember to remove the used id entry from the map, as it would
|
||||||
|
// otherwise just increase the app's memory usage
|
||||||
|
responseMap.remove(id);
|
||||||
|
}else{
|
||||||
|
Log.d(TAG,"No entry");
|
||||||
|
mResponseView.setText(mResponseView.getText() + gson.toJson(response, JsonRpcResponse.class) + "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
if(!mDisposable.isDisposed())
|
||||||
|
mDisposable.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
|
||||||
|
// Called upon NetworkService connection
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceDisconnected(ComponentName componentName) {
|
||||||
|
// Called upon NetworkService disconnection
|
||||||
|
}
|
||||||
|
}
|
9
sample/src/main/res/layout/activity_calls.xml
Normal file
9
sample/src/main/res/layout/activity_calls.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/call_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".CallsActivity">
|
||||||
|
|
||||||
|
</android.support.v7.widget.RecyclerView>
|
118
sample/src/main/res/layout/activity_perform_call.xml
Normal file
118
sample/src/main/res/layout/activity_perform_call.xml
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".PerformCallActivity">
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:id="@+id/output_text_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/container_param1"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/response"
|
||||||
|
tools:text="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputLayout
|
||||||
|
android:id="@+id/container_param1"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/container_param2"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/output_text_container">
|
||||||
|
<android.support.design.widget.TextInputEditText
|
||||||
|
android:id="@+id/param1"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputLayout
|
||||||
|
android:id="@+id/container_param2"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/container_param3"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/container_param1">
|
||||||
|
<android.support.design.widget.TextInputEditText
|
||||||
|
android:id="@+id/param2"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputLayout
|
||||||
|
android:id="@+id/container_param3"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/container_param4"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/container_param2">
|
||||||
|
<android.support.design.widget.TextInputEditText
|
||||||
|
android:id="@+id/param3"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputLayout
|
||||||
|
android:id="@+id/container_param4"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/button_send"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/container_param3">
|
||||||
|
<android.support.design.widget.TextInputEditText
|
||||||
|
android:id="@+id/param4"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/button_send"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:text="@string/action_send"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/container_param4" />
|
||||||
|
|
||||||
|
</android.support.constraint.ConstraintLayout>
|
13
sample/src/main/res/layout/item_call.xml
Normal file
13
sample/src/main/res/layout/item_call.xml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
tools:text="Sample">
|
||||||
|
</TextView>
|
|
@ -1,3 +1,35 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Sample</string>
|
<string name="app_name">Sample</string>
|
||||||
|
|
||||||
|
<string name="error_input_id">The entered value doesn\'t seem to be an object id</string>
|
||||||
|
|
||||||
|
<!-- Actions, buttons, etc -->
|
||||||
|
<string name="action_send">Send</string>
|
||||||
|
|
||||||
|
<!-- GetObjects input field -->
|
||||||
|
<string name="get_objects_arg1">Object id</string>
|
||||||
|
|
||||||
|
<!-- GetAccounts input field -->
|
||||||
|
<string name="get_accounts_arg1">Account id</string>
|
||||||
|
|
||||||
|
<!-- GetBlock & GetBlockHeader input field -->
|
||||||
|
<string name="get_block_arg1">Block id</string>
|
||||||
|
|
||||||
|
<!-- GetMarketHistory input fields -->
|
||||||
|
<string name="get_market_history_arg1">Base asset</string>
|
||||||
|
<string name="get_market_history_arg2">Quote asset</string>
|
||||||
|
<string name="get_market_history_arg3">Start timestamp (Latest)</string>
|
||||||
|
<string name="get_market_history_arg4">End timestamp (Earliest)</string>
|
||||||
|
|
||||||
|
<!-- GetRelativeAccountHistory input fields -->
|
||||||
|
<string name="get_relative_account_history_arg1">User account</string>
|
||||||
|
<string name="get_relative_account_history_arg2">Stop timestamp (Latest)</string>
|
||||||
|
<string name="get_relative_account_history_arg3">Limit</string>
|
||||||
|
<string name="get_relative_account_history_arg4">Start timestamp (Earliest)</string>
|
||||||
|
|
||||||
|
<!-- LookupAssetSymbols input fields -->
|
||||||
|
<string name="lookup_asset_symbols_arg1">Asset 1 id</string>
|
||||||
|
<string name="lookup_asset_symbols_arg2">Asset 2 id</string>
|
||||||
|
<string name="lookup_asset_symbols_arg3">Asset 3 id</string>
|
||||||
|
<string name="lookup_asset_symbols_arg4">Asset 4 id</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue