Merge pull request #153 from status-im/feature/send-transaction
Send transaction
Former-commit-id: 8148b7e01f
This commit is contained in:
commit
bf02104495
|
@ -138,7 +138,7 @@ dependencies {
|
|||
compile project(':react-native-fs')
|
||||
compile project(':react-native-image-crop-picker')
|
||||
//compile(name:'statusgo-android-16', ext:'aar')
|
||||
compile(group: 'status-im', name: 'status-go', version: '0.1.0-201607011545-da53ec', ext: 'aar')
|
||||
compile(group: 'status-im', name: 'status-go', version: 'unlock', ext: 'aar')
|
||||
|
||||
compile fileTree(dir: "node_modules/realm/android/libs", include: ["*.jar"])
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ public class MainApplication extends Application implements ReactApplication {
|
|||
|
||||
@Override
|
||||
protected List<ReactPackage> getPackages() {
|
||||
return Arrays.<ReactPackage>asList(
|
||||
return Arrays.asList(
|
||||
new MainReactPackage(),
|
||||
new JailPackage(),
|
||||
new RealmReactPackage(),
|
||||
|
|
|
@ -30,8 +30,7 @@ public class RootUtil {
|
|||
try {
|
||||
process = Runtime.getRuntime().exec(new String[] { "/system/xbin/which", "su" });
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
if (in.readLine() != null) return true;
|
||||
return false;
|
||||
return in.readLine() != null;
|
||||
} catch (Throwable t) {
|
||||
return false;
|
||||
} finally {
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.statusim.geth.module;
|
|||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import com.facebook.react.bridge.*;
|
||||
import com.statusim.geth.service.ConnectorHandler;
|
||||
import com.statusim.geth.service.GethConnector;
|
||||
|
@ -13,20 +14,19 @@ import android.util.Log;
|
|||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
public class GethModule extends ReactContextBaseJavaModule implements LifecycleEventListener, ConnectorHandler {
|
||||
class GethModule extends ReactContextBaseJavaModule implements LifecycleEventListener, ConnectorHandler {
|
||||
|
||||
private static final String TAG = "GethModule";
|
||||
|
||||
protected GethConnector geth = null;
|
||||
protected String handlerIdentifier = createIdentifier();
|
||||
private GethConnector geth = null;
|
||||
|
||||
protected HashMap<String, Callback> startNodeCallbacks = new HashMap<>();
|
||||
protected HashMap<String, Callback> createAccountCallbacks = new HashMap<>();
|
||||
protected HashMap<String, Callback> addAccountCallbacks = new HashMap<>();
|
||||
protected HashMap<String, Callback> unlockAccountCallbacks = new HashMap<>();
|
||||
private HashMap<String, Callback> startNodeCallbacks = new HashMap<>();
|
||||
private HashMap<String, Callback> createAccountCallbacks = new HashMap<>();
|
||||
private HashMap<String, Callback> unlockAccountCallbacks = new HashMap<>();
|
||||
private HashMap<String, Callback> transactionCallbacks = new HashMap<>();
|
||||
|
||||
|
||||
public GethModule(ReactApplicationContext reactContext) {
|
||||
GethModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
reactContext.addLifecycleEventListener(this);
|
||||
}
|
||||
|
@ -67,12 +67,6 @@ public class GethModule extends ReactContextBaseJavaModule implements LifecycleE
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getID() {
|
||||
|
||||
return handlerIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectorConnected() {
|
||||
}
|
||||
|
@ -89,7 +83,7 @@ public class GethModule extends ReactContextBaseJavaModule implements LifecycleE
|
|||
Bundle data = message.getData();
|
||||
String callbackIdentifier = data.getString(GethConnector.CALLBACK_IDENTIFIER);
|
||||
Log.d(TAG, "callback identifier: " + callbackIdentifier);
|
||||
Callback callback = null;
|
||||
Callback callback;
|
||||
switch (message.what) {
|
||||
case GethMessages.MSG_NODE_STARTED:
|
||||
Log.d(TAG, "handle startNodeCallbacks size: " + startNodeCallbacks.size());
|
||||
|
@ -108,18 +102,20 @@ public class GethModule extends ReactContextBaseJavaModule implements LifecycleE
|
|||
callback.invoke(data.getString("data"));
|
||||
}
|
||||
break;
|
||||
case GethMessages.MSG_ACCOUNT_ADDED:
|
||||
callback = addAccountCallbacks.remove(callbackIdentifier);
|
||||
if (callback != null) {
|
||||
callback.invoke(null, "{ \"address\": \"" + data.getString("address") + "\"}");
|
||||
}
|
||||
break;
|
||||
case GethMessages.MSG_LOGGED_IN:
|
||||
callback = unlockAccountCallbacks.remove(callbackIdentifier);
|
||||
if (callback != null) {
|
||||
callback.invoke(data.getString("result"));
|
||||
}
|
||||
break;
|
||||
case GethMessages.MSG_TRANSACTION_COMPLETED:
|
||||
callback = transactionCallbacks.remove(callbackIdentifier);
|
||||
String result = data.getString("result");
|
||||
Log.d(TAG, "Send result: " + result + (callback == null));
|
||||
if (callback != null) {
|
||||
callback.invoke(result);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
isClaimed = false;
|
||||
}
|
||||
|
@ -130,7 +126,7 @@ public class GethModule extends ReactContextBaseJavaModule implements LifecycleE
|
|||
@ReactMethod
|
||||
public void startNode(Callback callback, Callback onAlreadyRunning) {
|
||||
|
||||
if(GethService.isRunning()){
|
||||
if (GethService.isRunning()) {
|
||||
onAlreadyRunning.invoke();
|
||||
return;
|
||||
}
|
||||
|
@ -197,9 +193,12 @@ public class GethModule extends ReactContextBaseJavaModule implements LifecycleE
|
|||
geth.createAccount(callbackIdentifier, password);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void addAccount(String privateKey, Callback callback) {
|
||||
private String createIdentifier() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void completeTransaction(String hash, Callback callback) {
|
||||
Activity currentActivity = getCurrentActivity();
|
||||
|
||||
if (currentActivity == null) {
|
||||
|
@ -212,13 +211,27 @@ public class GethModule extends ReactContextBaseJavaModule implements LifecycleE
|
|||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Complete transaction: " + hash);
|
||||
String callbackIdentifier = createIdentifier();
|
||||
addAccountCallbacks.put(callbackIdentifier, callback);
|
||||
geth.addAccount(callbackIdentifier, privateKey);
|
||||
transactionCallbacks.put(callbackIdentifier, callback);
|
||||
|
||||
geth.completeTransaction(callbackIdentifier, hash);
|
||||
}
|
||||
|
||||
protected String createIdentifier() {
|
||||
return UUID.randomUUID().toString();
|
||||
private static Callback signalEventCallback;
|
||||
|
||||
//todo: move this method to GethService
|
||||
public static void signalEvent(String jsonEvent) {
|
||||
Log.d(TAG, "Signal event: " + jsonEvent);
|
||||
if(signalEventCallback != null) {
|
||||
signalEventCallback.invoke(jsonEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void registerSignalEventCallback(Callback callback) {
|
||||
Log.d(TAG, "registerSignalEventCallback");
|
||||
signalEventCallback = callback;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,9 +4,7 @@ package com.statusim.geth.service;
|
|||
import android.os.Message;
|
||||
|
||||
public interface ConnectorHandler {
|
||||
|
||||
boolean handleMessage(Message message);
|
||||
void onConnectorConnected();
|
||||
void onConnectorDisconnected();
|
||||
String getID();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,22 +71,21 @@ public class GethConnector extends ServiceConnector {
|
|||
}
|
||||
}
|
||||
|
||||
public void addAccount(String callbackIdentifier, String privateKey) {
|
||||
|
||||
public void completeTransaction(String callbackIdentifier, String hash){
|
||||
if (checkBound()) {
|
||||
Bundle data = new Bundle();
|
||||
data.putString("privateKey", privateKey);
|
||||
Message msg = createMessage(callbackIdentifier, GethMessages.MSG_ADD_ACCOUNT, data);
|
||||
data.putString("hash", hash);
|
||||
Message msg = createMessage(callbackIdentifier, GethMessages.MSG_COMPLETE_TRANSACTION, data);
|
||||
try {
|
||||
serviceMessenger.send(msg);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Exception sending message(addAccount) to service: ", e);
|
||||
Log.e(TAG, "Exception sending message(completeTransaction) to service: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected boolean checkBound() {
|
||||
private boolean checkBound() {
|
||||
|
||||
if (!isBound) {
|
||||
Log.d(TAG, "GethConnector not bound!");
|
||||
|
@ -95,7 +94,7 @@ public class GethConnector extends ServiceConnector {
|
|||
return true;
|
||||
}
|
||||
|
||||
protected Message createMessage(String callbackIdentifier, int idMessage, Bundle data) {
|
||||
private Message createMessage(String callbackIdentifier, int idMessage, Bundle data) {
|
||||
|
||||
Log.d(TAG, "Client messenger: " + clientMessenger.toString());
|
||||
Message msg = Message.obtain(null, idMessage, 0, 0);
|
||||
|
|
|
@ -6,7 +6,7 @@ public class GethMessages {
|
|||
/**
|
||||
* Start the node
|
||||
*/
|
||||
public static final int MSG_START_NODE = 1;
|
||||
static final int MSG_START_NODE = 1;
|
||||
|
||||
/**
|
||||
* Node started event
|
||||
|
@ -16,7 +16,7 @@ public class GethMessages {
|
|||
/**
|
||||
* Stop the node
|
||||
*/
|
||||
public static final int MSG_STOP_NODE = 3;
|
||||
static final int MSG_STOP_NODE = 3;
|
||||
|
||||
/**
|
||||
* Node stopped event
|
||||
|
@ -26,7 +26,7 @@ public class GethMessages {
|
|||
/**
|
||||
* Unlock an account
|
||||
*/
|
||||
public static final int MSG_LOGIN = 5;
|
||||
static final int MSG_LOGIN = 5;
|
||||
|
||||
/**
|
||||
* Account unlocked event
|
||||
|
@ -36,7 +36,7 @@ public class GethMessages {
|
|||
/**
|
||||
* Create an account
|
||||
*/
|
||||
public static final int MSG_CREATE_ACCOUNT = 7;
|
||||
static final int MSG_CREATE_ACCOUNT = 7;
|
||||
|
||||
/**
|
||||
* Account created event
|
||||
|
@ -44,13 +44,13 @@ public class GethMessages {
|
|||
public static final int MSG_ACCOUNT_CREATED = 8;
|
||||
|
||||
/**
|
||||
* Add an account
|
||||
* Account complete transaction event
|
||||
*/
|
||||
public static final int MSG_ADD_ACCOUNT = 9;
|
||||
static final int MSG_COMPLETE_TRANSACTION = 11;
|
||||
|
||||
/**
|
||||
* Account added event
|
||||
* Account complete transaction event
|
||||
*/
|
||||
public static final int MSG_ACCOUNT_ADDED = 10;
|
||||
public static final int MSG_TRANSACTION_COMPLETED = 11;
|
||||
|
||||
}
|
||||
|
|
|
@ -16,19 +16,18 @@ public class GethService extends Service {
|
|||
|
||||
private static final String TAG = "GethService";
|
||||
|
||||
private static boolean isGethStarted = false;
|
||||
private static boolean isGethInitialized = false;
|
||||
private final Handler handler = new Handler();
|
||||
|
||||
private static String dataFolder;
|
||||
|
||||
static class IncomingHandler extends Handler {
|
||||
private static class IncomingHandler extends Handler {
|
||||
|
||||
private final WeakReference<GethService> service;
|
||||
|
||||
IncomingHandler(GethService service) {
|
||||
|
||||
this.service = new WeakReference<GethService>(service);
|
||||
this.service = new WeakReference<>(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -43,11 +42,14 @@ public class GethService extends Service {
|
|||
}
|
||||
}
|
||||
|
||||
final Messenger serviceMessenger = new Messenger(new IncomingHandler(this));
|
||||
private final Messenger serviceMessenger = new Messenger(new IncomingHandler(this));
|
||||
|
||||
|
||||
public static void signalEvent(String jsonEvent) {
|
||||
System.out.println("\n\n\nIT WOOOOOORKS1111!!!!!!\n\n\n");
|
||||
Log.d(TAG, "Signal event: " + jsonEvent);
|
||||
Bundle replyData = new Bundle();
|
||||
replyData.putString("event", jsonEvent);
|
||||
//createAndSendReply(message, GethMessages.MSG_SIGNAL_EVENT, replyData);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -68,7 +70,6 @@ public class GethService extends Service {
|
|||
super.onDestroy();
|
||||
//TODO: stop geth
|
||||
stopNode(null);
|
||||
isGethStarted = false;
|
||||
isGethInitialized = false;
|
||||
Log.d(TAG, "Geth Service stopped !");
|
||||
}
|
||||
|
@ -78,7 +79,7 @@ public class GethService extends Service {
|
|||
return Service.START_STICKY;
|
||||
}
|
||||
|
||||
protected boolean handleMessage(Message message) {
|
||||
private boolean handleMessage(Message message) {
|
||||
switch (message.what) {
|
||||
|
||||
case GethMessages.MSG_START_NODE:
|
||||
|
@ -94,14 +95,14 @@ public class GethService extends Service {
|
|||
createAccount(message);
|
||||
break;
|
||||
|
||||
case GethMessages.MSG_ADD_ACCOUNT:
|
||||
addAccount(message);
|
||||
break;
|
||||
|
||||
case GethMessages.MSG_LOGIN:
|
||||
login(message);
|
||||
break;
|
||||
|
||||
case GethMessages.MSG_COMPLETE_TRANSACTION:
|
||||
completeTransaction(message);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -109,7 +110,7 @@ public class GethService extends Service {
|
|||
return true;
|
||||
}
|
||||
|
||||
protected void startNode(Message message) {
|
||||
private void startNode(Message message) {
|
||||
if (!isGethInitialized) {
|
||||
isGethInitialized = true;
|
||||
Log.d(TAG, "Client messenger1: " + message.replyTo.toString());
|
||||
|
@ -120,12 +121,12 @@ public class GethService extends Service {
|
|||
}
|
||||
}
|
||||
|
||||
protected class StartTask extends AsyncTask<Void, Void, Void> {
|
||||
private class StartTask extends AsyncTask<Void, Void, Void> {
|
||||
|
||||
protected String callbackIdentifier;
|
||||
protected Messenger messenger;
|
||||
String callbackIdentifier;
|
||||
Messenger messenger;
|
||||
|
||||
public StartTask(Messenger messenger, String callbackIdentifier) {
|
||||
StartTask(Messenger messenger, String callbackIdentifier) {
|
||||
this.messenger = messenger;
|
||||
this.callbackIdentifier = callbackIdentifier;
|
||||
}
|
||||
|
@ -140,9 +141,8 @@ public class GethService extends Service {
|
|||
}
|
||||
}
|
||||
|
||||
protected void onGethStarted(Messenger messenger, String callbackIdentifier) {
|
||||
private void onGethStarted(Messenger messenger, String callbackIdentifier) {
|
||||
Log.d(TAG, "Geth Service started");
|
||||
isGethStarted = true;
|
||||
Message replyMessage = Message.obtain(null, GethMessages.MSG_NODE_STARTED, 0, 0, null);
|
||||
Bundle replyData = new Bundle();
|
||||
Log.d(TAG, "Callback identifier: " + callbackIdentifier);
|
||||
|
@ -151,7 +151,7 @@ public class GethService extends Service {
|
|||
sendReply(messenger, replyMessage);
|
||||
}
|
||||
|
||||
protected void startGeth() {
|
||||
private void startGeth() {
|
||||
|
||||
|
||||
File extStore = Environment.getExternalStorageDirectory();
|
||||
|
@ -160,28 +160,38 @@ public class GethService extends Service {
|
|||
extStore.getAbsolutePath() + "/ethereum" :
|
||||
getApplicationInfo().dataDir + "/ethereum";
|
||||
Log.d(TAG, "Starting background Geth Service in folder: " + dataFolder);
|
||||
|
||||
try {
|
||||
final File newFile = new File(dataFolder);
|
||||
// todo handle error?
|
||||
newFile.mkdir();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "error making folder: " + dataFolder, e);
|
||||
}
|
||||
|
||||
final Runnable addPeer = new Runnable() {
|
||||
public void run() {
|
||||
Log.w("Geth", "adding peer");
|
||||
Statusgo.addPeer("enode://409772c7dea96fa59a912186ad5bcdb5e51b80556b3fe447d940f99d9eaadb51d4f0ffedb68efad232b52475dd7bd59b51cee99968b3cc79e2d5684b33c4090c@139.162.166.59:30303");
|
||||
}
|
||||
};
|
||||
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
|
||||
Statusgo.StartNode(dataFolder);
|
||||
}
|
||||
}).start();
|
||||
|
||||
handler.postDelayed(addPeer, 5000);
|
||||
}
|
||||
|
||||
protected void stopNode(Message message) {
|
||||
private void stopNode(Message message) {
|
||||
// TODO: stop node
|
||||
|
||||
createAndSendReply(message, GethMessages.MSG_NODE_STOPPED, null);
|
||||
}
|
||||
|
||||
protected void createAccount(Message message) {
|
||||
private void createAccount(Message message) {
|
||||
Bundle data = message.getData();
|
||||
String password = data.getString("password");
|
||||
// TODO: remove second argument
|
||||
|
@ -194,21 +204,7 @@ public class GethService extends Service {
|
|||
createAndSendReply(message, GethMessages.MSG_ACCOUNT_CREATED, replyData);
|
||||
}
|
||||
|
||||
protected void addAccount(Message message) {
|
||||
Bundle data = message.getData();
|
||||
String privateKey = data.getString("privateKey");
|
||||
String password = data.getString("password");
|
||||
// TODO: add account
|
||||
//String address = Statusgo.doAddAccount(privateKey, password);
|
||||
String address = "added account address";
|
||||
Log.d(TAG, "Added account: " + address);
|
||||
|
||||
Bundle replyData = new Bundle();
|
||||
replyData.putString("address", address);
|
||||
createAndSendReply(message, GethMessages.MSG_ACCOUNT_ADDED, replyData);
|
||||
}
|
||||
|
||||
protected void login(Message message) {
|
||||
private void login(Message message) {
|
||||
Bundle data = message.getData();
|
||||
String address = data.getString("address");
|
||||
String password = data.getString("password");
|
||||
|
@ -221,11 +217,24 @@ public class GethService extends Service {
|
|||
createAndSendReply(message, GethMessages.MSG_LOGGED_IN, replyData);
|
||||
}
|
||||
|
||||
private void completeTransaction(Message message){
|
||||
Bundle data = message.getData();
|
||||
String hash = data.getString("hash");
|
||||
|
||||
Log.d(TAG, "Before CompleteTransaction: " + hash);
|
||||
String result = Statusgo.CompleteTransaction(hash);
|
||||
Log.d(TAG, "After CompleteTransaction: " + result);
|
||||
|
||||
Bundle replyData = new Bundle();
|
||||
replyData.putString("result", result);
|
||||
createAndSendReply(message, GethMessages.MSG_TRANSACTION_COMPLETED, replyData);
|
||||
}
|
||||
|
||||
public static boolean isRunning() {
|
||||
return isGethInitialized;
|
||||
}
|
||||
|
||||
protected void createAndSendReply(Message message, int replyIdMessage, Bundle replyData) {
|
||||
private static void createAndSendReply(Message message, int replyIdMessage, Bundle replyData) {
|
||||
|
||||
if (message == null) {
|
||||
return;
|
||||
|
@ -243,7 +252,7 @@ public class GethService extends Service {
|
|||
sendReply(message.replyTo, replyMessage);
|
||||
}
|
||||
|
||||
protected void sendReply(Messenger messenger, Message message) {
|
||||
private static void sendReply(Messenger messenger, Message message) {
|
||||
try {
|
||||
messenger.send(message);
|
||||
|
||||
|
|
|
@ -11,39 +11,27 @@ import java.util.ArrayList;
|
|||
|
||||
public class ServiceConnector {
|
||||
|
||||
private static final String TAG = "ServiceConnector";
|
||||
|
||||
/**
|
||||
* Incoming message handler. Calls to its binder are sequential!
|
||||
*/
|
||||
protected final IncomingHandler handler;
|
||||
|
||||
/**
|
||||
* Handler thread to avoid running on the main UI thread
|
||||
*/
|
||||
protected final HandlerThread handlerThread;
|
||||
|
||||
/** Context of the activity from which this connector was launched */
|
||||
protected Context context;
|
||||
private Context context;
|
||||
|
||||
/** The class of the service we want to connect to */
|
||||
protected Class serviceClass;
|
||||
private Class serviceClass;
|
||||
|
||||
/** Flag indicating if the service is bound. */
|
||||
protected boolean isBound;
|
||||
boolean isBound;
|
||||
|
||||
/** Sends messages to the service. */
|
||||
protected Messenger serviceMessenger = null;
|
||||
Messenger serviceMessenger = null;
|
||||
|
||||
/** Receives messages from the service. */
|
||||
protected Messenger clientMessenger = null;
|
||||
Messenger clientMessenger = null;
|
||||
|
||||
protected ArrayList<ConnectorHandler> handlers = new ArrayList<>();
|
||||
private ArrayList<ConnectorHandler> handlers = new ArrayList<>();
|
||||
|
||||
/** Handles incoming messages from service. */
|
||||
class IncomingHandler extends Handler {
|
||||
private class IncomingHandler extends Handler {
|
||||
|
||||
public IncomingHandler(HandlerThread thread) {
|
||||
IncomingHandler(HandlerThread thread) {
|
||||
|
||||
super(thread.getLooper());
|
||||
}
|
||||
|
@ -72,7 +60,7 @@ public class ServiceConnector {
|
|||
/**
|
||||
* Class for interacting with the main interface of the service.
|
||||
*/
|
||||
protected ServiceConnection serviceConnection = new ServiceConnection() {
|
||||
private ServiceConnection serviceConnection = new ServiceConnection() {
|
||||
|
||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
|
||||
|
@ -100,13 +88,14 @@ public class ServiceConnector {
|
|||
}
|
||||
};
|
||||
|
||||
public ServiceConnector(Context context, Class serviceClass) {
|
||||
|
||||
ServiceConnector(Context context, Class serviceClass) {
|
||||
this.context = context;
|
||||
this.serviceClass = serviceClass;
|
||||
handlerThread = new HandlerThread("HandlerThread");
|
||||
// Handler thread to avoid running on the main UI thread
|
||||
HandlerThread handlerThread = new HandlerThread("HandlerThread");
|
||||
handlerThread.start();
|
||||
handler = new IncomingHandler(handlerThread);
|
||||
// Incoming message handler. Calls to its binder are sequential!
|
||||
IncomingHandler handler = new IncomingHandler(handlerThread);
|
||||
clientMessenger = new Messenger(handler);
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 443 B |
Binary file not shown.
After Width: | Height: | Size: 307 B |
Binary file not shown.
After Width: | Height: | Size: 607 B |
Binary file not shown.
After Width: | Height: | Size: 886 B |
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -5,6 +5,8 @@
|
|||
|
||||
(enable-console-print!)
|
||||
|
||||
(set! js/console.disableYellowBox true)
|
||||
|
||||
(def cnt (r/atom 0))
|
||||
(defn reloader [] @cnt [core/app-root])
|
||||
(def root-el (r/as-element [reloader]))
|
||||
|
@ -14,4 +16,4 @@
|
|||
:heads-up-display false
|
||||
:jsload-callback #(swap! cnt inc))
|
||||
|
||||
(core/init)
|
||||
(core/init)
|
||||
|
|
11
project.clj
11
project.clj
|
@ -9,12 +9,15 @@
|
|||
[re-frame "0.7.0"]
|
||||
[prismatic/schema "1.0.4"]
|
||||
^{:voom {:repo "git@github.com:status-im/status-lib.git"
|
||||
:branch "discover-rework"}}
|
||||
[status-im/protocol "0.1.3-20160818_085900-gda79e8e"]
|
||||
:branch "master"}}
|
||||
[status-im/protocol "0.1.3-20160818_172519-g2f734a6"]
|
||||
[natal-shell "0.3.0"]
|
||||
[com.andrewmcveigh/cljs-time "0.4.0"]]
|
||||
[com.andrewmcveigh/cljs-time "0.4.0"]
|
||||
[tailrecursion/cljs-priority-map "1.2.0"]
|
||||
[cljsjs/web3 "0.16.0-0"]]
|
||||
:plugins [[lein-cljsbuild "1.1.1"]
|
||||
[lein-figwheel "0.5.0-2"]]
|
||||
[lein-figwheel "0.5.0-2"]
|
||||
[lein-voom "0.1.0-20160311_203101-g259fbfc"]]
|
||||
:clean-targets ["target/" "index.ios.js" "index.android.js"]
|
||||
:aliases {"prod-build" ^{:doc "Recompile code with prod profile."}
|
||||
["do" "clean"
|
||||
|
|
|
@ -260,3 +260,60 @@ status.command({
|
|||
type: status.types.TEXT
|
||||
}]
|
||||
});
|
||||
|
||||
function validateBalance(params) {
|
||||
try {
|
||||
var val = web3.toWei(params.value, "ether");
|
||||
} catch (err) {
|
||||
return {
|
||||
errors: [
|
||||
status.components.validationMessage(
|
||||
"Amount",
|
||||
"Amount is not valid number"//err.message
|
||||
)
|
||||
]
|
||||
};
|
||||
}
|
||||
var balance = web3.eth.getBalance(params.command.address);
|
||||
if (bn(val).greaterThan(bn(balance))) {
|
||||
return {
|
||||
errors: [
|
||||
status.components.validationMessage(
|
||||
"Amount",
|
||||
"Not enough ETH on balance ("
|
||||
+ web3.fromWei(balance, "ether")
|
||||
+ " ETH)"
|
||||
)
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function sendTransaction(params) {
|
||||
var data = {
|
||||
from: params.command.from,
|
||||
to: params.command.to,
|
||||
value: web3.toWei(params.value, "ether")
|
||||
};
|
||||
var hash = web3.eth.sendTransaction(data);
|
||||
|
||||
return {"transaction-hash": hash};
|
||||
}
|
||||
|
||||
status.command({
|
||||
name: "send",
|
||||
color: "#5fc48d",
|
||||
description: "Send transaction",
|
||||
params: [{
|
||||
name: "amount",
|
||||
type: status.types.NUMBER
|
||||
}],
|
||||
preview: function (params) {
|
||||
return status.components.text(
|
||||
{},
|
||||
params.value + " ETH"
|
||||
);
|
||||
},
|
||||
handler: sendTransaction,
|
||||
validator: validateBalance
|
||||
});
|
||||
|
|
|
@ -22,6 +22,7 @@ Command.prototype.create = function (com) {
|
|||
this.name = com.name;
|
||||
this.description = com.description;
|
||||
this.handler = com.handler;
|
||||
this["has-handler"] = com.handler != null;
|
||||
this.validator = com.validator;
|
||||
this.color = com.color;
|
||||
this.icon = com.icon;
|
||||
|
@ -110,7 +111,7 @@ function validationMessage(titleText, descriptionText) {
|
|||
};
|
||||
var description = status.components.text(descriptionStyle, descriptionText);
|
||||
|
||||
var message = status.components.view(
|
||||
return status.components.view(
|
||||
{
|
||||
backgroundColor: "red",
|
||||
height: 61,
|
||||
|
@ -119,8 +120,6 @@ function validationMessage(titleText, descriptionText) {
|
|||
},
|
||||
[title, description]
|
||||
);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
var status = {
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
:address address
|
||||
:name address
|
||||
:photo-path (identicon public-key)}]
|
||||
(log/debug "account-created: " account)
|
||||
(log/debug "account-created")
|
||||
(when (not (str/blank? public-key))
|
||||
(do
|
||||
(dispatch-sync [:add-account account])
|
||||
|
@ -90,7 +90,7 @@
|
|||
(defn logged-in [db address]
|
||||
(let [is-login-screen? (= (:view-id db) :login)
|
||||
new-account? (not is-login-screen?)]
|
||||
(log/debug "Logged in: " address)
|
||||
(log/debug "Logged in: ")
|
||||
(realm/change-account-realm address new-account?
|
||||
#(if (nil? %)
|
||||
(initialize-account db address)
|
||||
|
@ -98,16 +98,17 @@
|
|||
|
||||
(register-handler
|
||||
:login-account
|
||||
(-> (fn [db [_ address password]]
|
||||
(geth/login address password (fn [result]
|
||||
(let [data (json->clj result)
|
||||
error (:error data)
|
||||
success (zero? (count error))]
|
||||
(log/debug "Logged in account: " address result)
|
||||
(if success
|
||||
(logged-in db address)
|
||||
(dispatch [:set-in [:login :error] error])))))
|
||||
db)))
|
||||
(u/side-effect!
|
||||
(fn [db [_ address password]]
|
||||
(geth/login address password
|
||||
(fn [result]
|
||||
(let [data (json->clj result)
|
||||
error (:error data)
|
||||
success (zero? (count error))]
|
||||
(log/debug "Logged in account: ")
|
||||
(if success
|
||||
(logged-in db address)
|
||||
(dispatch [:set-in [:login :error] error]))))))))
|
||||
|
||||
(defn load-accounts! [db _]
|
||||
(let [accounts (->> (accounts/get-accounts)
|
||||
|
@ -120,7 +121,7 @@
|
|||
|
||||
(defn console-create-account [db _]
|
||||
(let [msg-id (random/id)]
|
||||
(dispatch [:received-msg
|
||||
(dispatch [:received-message
|
||||
{:msg-id msg-id
|
||||
:content {:command (name :keypair)
|
||||
:content (label :t/keypair-generated)}
|
||||
|
@ -130,4 +131,4 @@
|
|||
:to "me"}])
|
||||
db))
|
||||
|
||||
(register-handler :console-create-account console-create-account)
|
||||
(register-handler :console-create-account console-create-account)
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
[status-im.chat.screen :refer [chat]]
|
||||
[status-im.accounts.login.screen :refer [login]]
|
||||
[status-im.accounts.screen :refer [accounts]]
|
||||
[status-im.transactions.screen :refer [confirm]]
|
||||
[status-im.chats-list.screen :refer [chats-list]]
|
||||
[status-im.new-group.screen :refer [new-group]]
|
||||
[status-im.participants.views.add :refer [new-participants]]
|
||||
|
@ -98,6 +99,7 @@
|
|||
:profile-photo-capture profile-photo-capture
|
||||
:accounts accounts
|
||||
:login login
|
||||
:confirm confirm
|
||||
:my-profile my-profile)]
|
||||
[component {:platform-specific {:styles styles
|
||||
:list-selection-fn show-dialog}}])))})))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
(ns status-im.chat.handlers
|
||||
(:require [re-frame.core :refer [enrich after debug dispatch]]
|
||||
(:require-macros [cljs.core.async.macros :as am])
|
||||
(:require [re-frame.core :refer [enrich after debug dispatch path]]
|
||||
[status-im.models.commands :as commands]
|
||||
[clojure.string :as str]
|
||||
[status-im.components.styles :refer [default-chat-color]]
|
||||
|
@ -20,31 +21,39 @@
|
|||
[status-im.handlers.content-suggestions :refer [get-content-suggestions]]
|
||||
[status-im.utils.phone-number :refer [format-phone-number
|
||||
valid-mobile-number?]]
|
||||
[status-im.utils.datetime :as time]
|
||||
[status-im.components.jail :as j]
|
||||
[status-im.utils.types :refer [json->clj]]
|
||||
[status-im.commands.utils :refer [generate-hiccup]]
|
||||
[status-im.chat.handlers.commands :refer [command-prefix]]
|
||||
[status-im.chat.utils :refer [console? not-console?]]
|
||||
status-im.chat.handlers.animation
|
||||
status-im.chat.handlers.requests
|
||||
status-im.chat.handlers.unviewed-messages))
|
||||
status-im.chat.handlers.unviewed-messages
|
||||
status-im.chat.handlers.send-message
|
||||
status-im.chat.handlers.receive-message
|
||||
[cljs.core.async :as a]))
|
||||
|
||||
(register-handler :set-show-actions
|
||||
(fn [db [_ show-actions]]
|
||||
(assoc db :show-actions show-actions)))
|
||||
|
||||
(register-handler :load-more-messages
|
||||
(fn [{:keys [current-chat-id] :as db} _]
|
||||
(fn [{:keys [current-chat-id loading-allowed] :as db} _]
|
||||
(let [all-loaded? (get-in db [:chats current-chat-id :all-loaded?])]
|
||||
(if all-loaded?
|
||||
db
|
||||
(let [messages-path [:chats current-chat-id :messages]
|
||||
messages (get-in db messages-path)
|
||||
new-messages (messages/get-messages current-chat-id (count messages))
|
||||
all-loaded? (> default-number-of-messages (count new-messages))]
|
||||
(-> db
|
||||
(update-in messages-path concat new-messages)
|
||||
(assoc-in [:chats current-chat-id :all-loaded?] all-loaded?)))))))
|
||||
(if loading-allowed
|
||||
(do (am/go
|
||||
(<! (a/timeout 400))
|
||||
(dispatch [:set :loading-allowed true]))
|
||||
(if all-loaded?
|
||||
db
|
||||
(let [messages-path [:chats current-chat-id :messages]
|
||||
messages (get-in db messages-path)
|
||||
new-messages (messages/get-messages current-chat-id (count messages))
|
||||
all-loaded? (> default-number-of-messages (count new-messages))]
|
||||
(-> db
|
||||
(assoc :loading-allowed false)
|
||||
(update-in messages-path concat new-messages)
|
||||
(assoc-in [:chats current-chat-id :all-loaded?] all-loaded?)))))
|
||||
db))))
|
||||
|
||||
(defn safe-trim [s]
|
||||
(when (string? s)
|
||||
|
@ -99,12 +108,6 @@
|
|||
(dispatch [:set-chat-command (ffirst suggestions)])
|
||||
(dispatch [::set-text chat-id text]))))
|
||||
|
||||
(defn console? [s]
|
||||
(= "console" s))
|
||||
|
||||
(def not-console?
|
||||
(complement console?))
|
||||
|
||||
(register-handler :set-chat-input-text
|
||||
(u/side-effect!
|
||||
(fn [{:keys [current-chat-id]} [_ text]]
|
||||
|
@ -142,23 +145,6 @@
|
|||
|
||||
(register-handler ::set-text update-text)
|
||||
|
||||
(defn check-author-direction
|
||||
[db chat-id {:keys [from outgoing] :as message}]
|
||||
(let [previous-message (first (get-in db [:chats chat-id :messages]))]
|
||||
(merge message
|
||||
{:same-author (if previous-message
|
||||
(= (:from previous-message) from)
|
||||
true)
|
||||
:same-direction (if previous-message
|
||||
(= (:outgoing previous-message) outgoing)
|
||||
true)})))
|
||||
|
||||
(defn add-message-to-db
|
||||
[db chat-id message]
|
||||
(let [messages [:chats chat-id :messages]]
|
||||
(update-in db messages conj (assoc message :chat-id chat-id
|
||||
:new? true))))
|
||||
|
||||
(defn set-message-shown
|
||||
[db chat-id msg-id]
|
||||
(update-in db [:chats chat-id :messages] (fn [messages]
|
||||
|
@ -172,141 +158,14 @@
|
|||
(fn [db [_ {:keys [chat-id msg-id]}]]
|
||||
(set-message-shown db chat-id msg-id)))
|
||||
|
||||
(defn default-delivery-status [chat-id]
|
||||
(if (console? chat-id)
|
||||
:seen
|
||||
:pending))
|
||||
|
||||
(defn prepare-message
|
||||
[{:keys [identity current-chat-id] :as db} _]
|
||||
(let [text (get-in db [:chats current-chat-id :input-text])
|
||||
[command] (suggestions/check-suggestion db (str text " "))
|
||||
message (check-author-direction
|
||||
db current-chat-id
|
||||
{:msg-id (random/id)
|
||||
:chat-id current-chat-id
|
||||
:content text
|
||||
:to current-chat-id
|
||||
:from identity
|
||||
:content-type text-content-type
|
||||
:delivery-status (default-delivery-status current-chat-id)
|
||||
:outgoing true
|
||||
:timestamp (time/now-ms)})]
|
||||
_ (.log js/console "WOW3")
|
||||
(if command
|
||||
(commands/set-command-input db :commands command)
|
||||
(assoc db :new-message (when-not (str/blank? text) message)))))
|
||||
|
||||
(defn prepare-command
|
||||
[identity chat-id {:keys [preview preview-string content command to-message]}]
|
||||
(let [content {:command (command :name)
|
||||
:content content}]
|
||||
{:msg-id (random/id)
|
||||
:from identity
|
||||
:to chat-id
|
||||
:content content
|
||||
:content-type content-type-command
|
||||
:delivery-status (default-delivery-status chat-id)
|
||||
:outgoing true
|
||||
:preview preview-string
|
||||
:rendered-preview preview
|
||||
:to-message to-message}))
|
||||
|
||||
(defn prepare-staged-commans
|
||||
[{:keys [current-chat-id identity] :as db} _]
|
||||
(let [staged-commands (get-in db [:chats current-chat-id :staged-commands])]
|
||||
(->> staged-commands
|
||||
(map #(prepare-command identity current-chat-id %))
|
||||
;todo this is wrong :(
|
||||
(map #(check-author-direction db current-chat-id %))
|
||||
(assoc db :new-commands))))
|
||||
|
||||
(defn add-message
|
||||
[{:keys [new-message current-chat-id] :as db}]
|
||||
(if new-message
|
||||
(add-message-to-db db current-chat-id new-message)
|
||||
db))
|
||||
|
||||
(defn add-commands
|
||||
[{:keys [new-commands current-chat-id] :as db}]
|
||||
(reduce
|
||||
#(add-message-to-db %1 current-chat-id %2)
|
||||
db
|
||||
new-commands))
|
||||
|
||||
(defn clear-input
|
||||
[{:keys [current-chat-id new-message] :as db} _]
|
||||
(if new-message
|
||||
(assoc-in db [:chats current-chat-id :input-text] nil)
|
||||
db))
|
||||
|
||||
(defn clear-staged-commands
|
||||
[{:keys [current-chat-id] :as db} _]
|
||||
(assoc-in db [:chats current-chat-id :staged-commands] []))
|
||||
|
||||
(defn send-message!
|
||||
[{:keys [new-message current-chat-id] :as db} _]
|
||||
(when (and new-message (not-console? current-chat-id))
|
||||
(let [{:keys [group-chat]} (get-in db [:chats current-chat-id])
|
||||
message (select-keys new-message [:content :msg-id])]
|
||||
(if group-chat
|
||||
(api/send-group-user-msg (assoc message :group-id current-chat-id))
|
||||
(api/send-user-msg (assoc message :to current-chat-id))))))
|
||||
|
||||
(defn save-message-to-realm!
|
||||
[{:keys [new-message current-chat-id]} _]
|
||||
(when new-message
|
||||
(messages/save-message current-chat-id new-message)))
|
||||
|
||||
(defn save-commands-to-realm!
|
||||
[{:keys [new-commands current-chat-id]} _]
|
||||
(doseq [new-command new-commands]
|
||||
(messages/save-message
|
||||
current-chat-id
|
||||
(dissoc new-command :rendered-preview :to-message))))
|
||||
|
||||
(defn dispatch-responded-requests!
|
||||
[{:keys [new-commands current-chat-id]} _]
|
||||
(doseq [{:keys [to-message]} new-commands]
|
||||
(when to-message
|
||||
(dispatch [:request-answered! current-chat-id to-message]))))
|
||||
|
||||
(defn invoke-commands-handlers!
|
||||
[{:keys [new-commands current-chat-id]}]
|
||||
(doseq [{:keys [content] :as com} new-commands]
|
||||
(let [{:keys [command content]} content
|
||||
type (:type command)
|
||||
path [(if (= :command type) :commands :responses)
|
||||
command
|
||||
:handler]
|
||||
params {:value content}]
|
||||
(j/call current-chat-id
|
||||
path
|
||||
params
|
||||
#(dispatch [:command-handler! com %])))))
|
||||
|
||||
(register-handler :send-chat-msg
|
||||
(-> prepare-message
|
||||
((enrich prepare-staged-commans))
|
||||
((enrich add-message))
|
||||
((enrich add-commands))
|
||||
((enrich clear-input))
|
||||
((enrich clear-staged-commands))
|
||||
((after send-message!))
|
||||
((after save-message-to-realm!))
|
||||
((after save-commands-to-realm!))
|
||||
((after dispatch-responded-requests!))
|
||||
;; todo maybe it is better to track if it was handled or not
|
||||
((after invoke-commands-handlers!))))
|
||||
|
||||
(register-handler :init-console-chat
|
||||
(fn [db [_]]
|
||||
(sign-up-service/init db)))
|
||||
|
||||
(register-handler :save-password
|
||||
(fn [db [_ password]]
|
||||
(dispatch [:create-account password])
|
||||
(sign-up-service/save-password password)
|
||||
(dispatch [:create-account password])
|
||||
(assoc db :password-saved true)))
|
||||
|
||||
(register-handler :sign-up
|
||||
|
@ -372,35 +231,6 @@
|
|||
(after #(dispatch [:load-unviewed-messages!]))
|
||||
((enrich initialize-chats) load-chats!))
|
||||
|
||||
(defn store-message!
|
||||
[{:keys [new-message]} [_ {chat-id :from}]]
|
||||
(messages/save-message chat-id new-message))
|
||||
|
||||
(defn dispatch-request!
|
||||
[{:keys [new-message]} [_ {chat-id :from}]]
|
||||
(when (= (:content-type new-message) content-type-command-request)
|
||||
(dispatch [:add-request chat-id new-message])))
|
||||
|
||||
(defn receive-message
|
||||
[db [_ {chat-id :from :as message}]]
|
||||
(let [message' (-> db
|
||||
(check-author-direction chat-id message)
|
||||
(assoc :delivery-status :pending))]
|
||||
(-> db
|
||||
(add-message-to-db chat-id message')
|
||||
(assoc :new-message message'))))
|
||||
|
||||
(defn dispatch-unviewed-message!
|
||||
[{:keys [new-message]} [_ {chat-id :from}]]
|
||||
(let [{:keys [msg-id]} new-message]
|
||||
(dispatch [:add-unviewed-message chat-id msg-id])))
|
||||
|
||||
(register-handler :received-msg
|
||||
[(after store-message!)
|
||||
(after dispatch-request!)
|
||||
(after dispatch-unviewed-message!)]
|
||||
receive-message)
|
||||
|
||||
(register-handler :group-received-msg
|
||||
(u/side-effect!
|
||||
(fn [_ [_ {chat-id :group-id :as msg}]]
|
||||
|
@ -412,6 +242,7 @@
|
|||
messages (get-in db [:chats chat-id :messages])
|
||||
db' (assoc db :current-chat-id chat-id)]
|
||||
(dispatch [:load-requests! chat-id])
|
||||
(dispatch [:load-commands! chat-id])
|
||||
(if (seq messages)
|
||||
db'
|
||||
(-> db'
|
||||
|
@ -419,15 +250,15 @@
|
|||
init-chat))))
|
||||
|
||||
(defn prepare-chat
|
||||
[{:keys [contacts] :as db} [_ contcat-id]]
|
||||
(let [name (get-in contacts [contcat-id :name])
|
||||
chat {:chat-id contcat-id
|
||||
:name name
|
||||
[{:keys [contacts] :as db} [_ contact-id]]
|
||||
(let [name (get-in contacts [contact-id :name])
|
||||
chat {:chat-id contact-id
|
||||
:name (or name contact-id)
|
||||
:color default-chat-color
|
||||
:group-chat false
|
||||
:is-active true
|
||||
:timestamp (.getTime (js/Date.))
|
||||
:contacts [{:identity contcat-id}]
|
||||
:contacts [{:identity contact-id}]
|
||||
:dapp-url nil
|
||||
:dapp-hash nil}]
|
||||
(assoc db :new-chat chat)))
|
||||
|
@ -451,6 +282,11 @@
|
|||
((after save-chat!))
|
||||
((after open-chat!))))
|
||||
|
||||
(register-handler :add-chat
|
||||
(-> prepare-chat
|
||||
((enrich add-chat))
|
||||
((after save-chat!))))
|
||||
|
||||
(register-handler :switch-command-suggestions!
|
||||
(u/side-effect!
|
||||
(fn [db]
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
suggestion? (get-in db [:has-suggestions? current-chat-id])
|
||||
custom-errors (get-in db [:custom-validation-errors current-chat-id])
|
||||
validation-height (if (or (seq errors) (seq custom-errors))
|
||||
request-info-height
|
||||
(+ suggestions-header-height request-info-height)
|
||||
0)]
|
||||
(+ validation-height
|
||||
(if (= :response type)
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
[clojure.string :as str]
|
||||
[status-im.commands.utils :as cu]
|
||||
[status-im.utils.phone-number :as pn]
|
||||
[status-im.i18n :as i18n]))
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.utils.datetime :as time]
|
||||
[status-im.utils.random :as random]))
|
||||
|
||||
(def command-prefix "c ")
|
||||
|
||||
|
@ -61,7 +63,7 @@
|
|||
|
||||
(defn invoke-command-preview!
|
||||
[{:keys [staged-command]} [_ chat-id]]
|
||||
(let [{:keys [command content]} staged-command
|
||||
(let [{:keys [command content id]} staged-command
|
||||
{:keys [name type]} command
|
||||
path [(if (= :command type) :commands :responses)
|
||||
name
|
||||
|
@ -70,7 +72,7 @@
|
|||
(j/call chat-id
|
||||
path
|
||||
params
|
||||
#(dispatch [:command-preview chat-id %]))))
|
||||
#(dispatch [:command-preview chat-id id %]))))
|
||||
|
||||
(defn command-input
|
||||
([{:keys [current-chat-id] :as db}]
|
||||
|
@ -102,7 +104,8 @@
|
|||
path [(if (= :command type) :commands :responses)
|
||||
name
|
||||
:validator]
|
||||
params {:value content}]
|
||||
params {:value content
|
||||
:command data}]
|
||||
(j/call chat-id
|
||||
path
|
||||
params
|
||||
|
@ -110,13 +113,14 @@
|
|||
|
||||
(register-handler :stage-command
|
||||
(after start-validate!)
|
||||
(fn [{:keys [current-chat-id] :as db}]
|
||||
(fn [{:keys [current-chat-id current-account-id] :as db}]
|
||||
(let [{:keys [command content]} (command-input db)
|
||||
content' (content-by-command command content)]
|
||||
(-> db
|
||||
(assoc ::command {:content content'
|
||||
:command command
|
||||
:chat-id current-chat-id})
|
||||
:chat-id current-chat-id
|
||||
:address current-account-id})
|
||||
(assoc-in [:disable-staging current-chat-id] true)))))
|
||||
|
||||
(register-handler ::finish-command-staging
|
||||
|
@ -128,7 +132,9 @@
|
|||
content' (content-by-command command content)
|
||||
command-info {:command command
|
||||
:content content'
|
||||
:to-message to-msg-id}]
|
||||
:to-message to-msg-id
|
||||
:created-at (time/now-ms)
|
||||
:id (random/id)}]
|
||||
(-> db
|
||||
(commands/stage-command command-info)
|
||||
(assoc :staged-command command-info)
|
||||
|
@ -172,14 +178,19 @@
|
|||
(fn [db]
|
||||
(dissoc db :validation-errors :custom-validation-errors)))
|
||||
|
||||
(defn dispatch-error!
|
||||
[chat-id title description]
|
||||
(letfn [(wrap-params [p] (if (seqable? p) p [p]))]
|
||||
(dispatch [::set-validation-error
|
||||
chat-id
|
||||
{:title (apply i18n/label (wrap-params title))
|
||||
:description (apply i18n/label (wrap-params description))}])))
|
||||
|
||||
(def validation-handlers
|
||||
{:phone (fn [chat-id [number]]
|
||||
(if (pn/valid-mobile-number? number)
|
||||
(dispatch [::finish-command-staging chat-id])
|
||||
(dispatch [::set-validation-error
|
||||
chat-id
|
||||
{:title (i18n/label :t/phone-number)
|
||||
:description (i18n/label :t/invalid-phone)}])))})
|
||||
(dispatch-error! chat-id :t/phone-number :t/invalid-phone)))})
|
||||
|
||||
(defn validator [name]
|
||||
(validation-handlers (keyword name)))
|
||||
|
@ -190,7 +201,6 @@
|
|||
(when-let [handler (validator name)]
|
||||
(handler chat-id params)))))
|
||||
|
||||
|
||||
(register-handler ::set-validation-error
|
||||
(after #(dispatch [:fix-response-height]))
|
||||
(fn [db [_ chat-id error]]
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
(ns status-im.chat.handlers.receive-message
|
||||
(:require [status-im.utils.handlers :refer [register-handler] :as u]
|
||||
[re-frame.core :refer [enrich after debug dispatch path]]
|
||||
[status-im.models.messages :as messages]
|
||||
[status-im.chat.utils :as cu]
|
||||
[status-im.commands.utils :refer [generate-hiccup]]
|
||||
[status-im.constants :refer [content-type-command-request]]
|
||||
[cljs.reader :refer [read-string]]
|
||||
[status-im.models.chats :as c]))
|
||||
|
||||
(defn check-previev [{:keys [content] :as message}]
|
||||
(if-let [preview (:preview content)]
|
||||
(let [rendered-preview (generate-hiccup (read-string preview))]
|
||||
(assoc message
|
||||
:preview preview
|
||||
:rendered-preview rendered-preview))
|
||||
message))
|
||||
|
||||
(defn store-message [{chat-id :from :as message}]
|
||||
(messages/save-message chat-id (dissoc message :rendered-preview :new?)))
|
||||
|
||||
(register-handler :received-message
|
||||
(u/side-effect!
|
||||
(fn [{:keys [chats] :as db} [_ {chat-id :from :keys [msg-id] :as message}]]
|
||||
(let [same-message (messages/get-message msg-id)]
|
||||
(when-not same-message
|
||||
(let [message' (assoc (->> message
|
||||
(cu/check-author-direction db chat-id)
|
||||
(check-previev))
|
||||
:delivery-status :pending)]
|
||||
(store-message message')
|
||||
(when-not (c/chat-exists? chat-id)
|
||||
(dispatch [:add-chat chat-id]))
|
||||
(dispatch [::add-message message'])
|
||||
(when (= (:content-type message') content-type-command-request)
|
||||
(dispatch [:add-request chat-id message']))
|
||||
(dispatch [:add-unviewed-message chat-id msg-id])))))))
|
||||
|
||||
(register-handler ::add-message
|
||||
(fn [db [_ {chat-id :from :keys [new?] :as message}]]
|
||||
(cu/add-message-to-db db chat-id message new?)))
|
|
@ -1,9 +1,9 @@
|
|||
(ns status-im.chat.handlers.requests
|
||||
(:require [re-frame.core :refer [after dispatch enrich]]
|
||||
[status-im.utils.handlers :refer [register-handler]]
|
||||
[status-im.persistence.realm.core :as realm]
|
||||
[status-im.models.requests :as requests]
|
||||
[status-im.utils.handlers :as u]))
|
||||
[status-im.utils.handlers :refer [register-handler] :as u]
|
||||
[status-im.persistence.realm.core :as realm]))
|
||||
|
||||
(defn store-request!
|
||||
[{:keys [new-request] :as db}]
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
(ns status-im.chat.handlers.send-message
|
||||
(:require [status-im.utils.handlers :refer [register-handler] :as u]
|
||||
[clojure.string :as s]
|
||||
[status-im.models.messages :as messages]
|
||||
[status-im.components.jail :as j]
|
||||
[status-im.utils.random :as random]
|
||||
[status-im.utils.datetime :as time]
|
||||
[re-frame.core :refer [enrich after debug dispatch path]]
|
||||
[status-im.chat.suggestions :as suggestions]
|
||||
[status-im.models.commands :as commands]
|
||||
[status-im.chat.utils :as cu]
|
||||
[status-im.constants :refer [text-content-type
|
||||
content-type-command
|
||||
content-type-command-request
|
||||
default-number-of-messages]]
|
||||
[status-im.protocol.api :as api]))
|
||||
|
||||
(defn default-delivery-status [chat-id]
|
||||
(if (cu/console? chat-id)
|
||||
:seen
|
||||
:pending))
|
||||
|
||||
(defn prepare-message
|
||||
[{:keys [identity current-chat-id] :as db} _]
|
||||
(let [text (get-in db [:chats current-chat-id :input-text])
|
||||
[command] (suggestions/check-suggestion db (str text " "))
|
||||
message (cu/check-author-direction
|
||||
db current-chat-id
|
||||
{:msg-id (random/id)
|
||||
:chat-id current-chat-id
|
||||
:content text
|
||||
:to current-chat-id
|
||||
:from identity
|
||||
:content-type text-content-type
|
||||
:delivery-status (default-delivery-status current-chat-id)
|
||||
:outgoing true
|
||||
:timestamp (time/now-ms)})]
|
||||
(if command
|
||||
(commands/set-command-input db :commands command)
|
||||
(assoc db :new-message (when-not (s/blank? text) message)))))
|
||||
|
||||
(defn prepare-command
|
||||
[identity chat-id {:keys [preview preview-string content command to-message]}]
|
||||
(let [content {:command (command :name)
|
||||
:content content}]
|
||||
{:msg-id (random/id)
|
||||
:from identity
|
||||
:to chat-id
|
||||
:content (assoc content :preview preview-string)
|
||||
:content-type content-type-command
|
||||
:delivery-status (default-delivery-status chat-id)
|
||||
:outgoing true
|
||||
:preview preview-string
|
||||
:rendered-preview preview
|
||||
:to-message to-message
|
||||
:type (:type command)
|
||||
:has-handler (:has-handler command)}))
|
||||
|
||||
(register-handler :send-chat-msg
|
||||
(u/side-effect!
|
||||
(fn [{:keys [current-chat-id identity current-account-id] :as db}]
|
||||
(let [staged-commands (vals (get-in db [:chats current-chat-id :staged-commands]))
|
||||
text (get-in db [:chats current-chat-id :input-text])
|
||||
data {:commands staged-commands
|
||||
:message text
|
||||
:chat-id current-chat-id
|
||||
:identity identity
|
||||
:address current-account-id}]
|
||||
(dispatch [:clear-input current-chat-id])
|
||||
(cond
|
||||
(seq staged-commands)
|
||||
(dispatch [::check-commands-handlers! data])
|
||||
(not (s/blank? text))
|
||||
(dispatch [::prepare-message data]))))))
|
||||
|
||||
|
||||
(register-handler ::check-commands-handlers!
|
||||
(u/side-effect!
|
||||
(fn [_ [_ {:keys [commands message] :as params}]]
|
||||
(doseq [{:keys [command] :as message} commands]
|
||||
(let [params' (assoc params :command message)]
|
||||
(if (:pending message)
|
||||
(dispatch [:navigate-to :confirm])
|
||||
(if (:has-handler command)
|
||||
(dispatch [::invoke-command-handlers! params'])
|
||||
(dispatch [:prepare-command! params'])))))
|
||||
(when-not (s/blank? message)
|
||||
(dispatch [::prepare-message params])))))
|
||||
|
||||
(register-handler :clear-input
|
||||
(path :chats)
|
||||
(fn [db [_ chat-id]]
|
||||
(assoc-in db [chat-id :input-text] nil)))
|
||||
|
||||
(register-handler :prepare-command!
|
||||
(u/side-effect!
|
||||
(fn [db [_ {:keys [chat-id command identity] :as params}]]
|
||||
(let [command' (->> command
|
||||
(prepare-command identity chat-id)
|
||||
(cu/check-author-direction db chat-id))]
|
||||
(dispatch [::clear-command chat-id (:id command)])
|
||||
(dispatch [::send-command! (assoc params :command command')])))))
|
||||
|
||||
(register-handler ::clear-command
|
||||
(fn [db [_ chat-id id]]
|
||||
(update-in db [:chats chat-id :staged-commands] dissoc id)))
|
||||
|
||||
(register-handler ::send-command!
|
||||
(u/side-effect!
|
||||
(fn [_ [_ params]]
|
||||
(dispatch [::add-command params])
|
||||
(dispatch [::save-command! params])
|
||||
(dispatch [::dispatch-responded-requests! params])
|
||||
(dispatch [::send-command-protocol! params]))))
|
||||
|
||||
(register-handler ::add-command
|
||||
(after (fn [_ [_ {:keys [handler]}]]
|
||||
(when handler (handler))))
|
||||
(fn [db [_ {:keys [chat-id command]}]]
|
||||
(cu/add-message-to-db db chat-id command)))
|
||||
|
||||
(register-handler ::save-command!
|
||||
(u/side-effect!
|
||||
(fn [_ [_ {:keys [command chat-id]}]]
|
||||
(messages/save-message
|
||||
chat-id
|
||||
(dissoc command :rendered-preview :to-message :has-handler)))))
|
||||
|
||||
(register-handler ::dispatch-responded-requests!
|
||||
(u/side-effect!
|
||||
(fn [_ [_ {:keys [command chat-id]}]]
|
||||
(let [{:keys [to-message]} command]
|
||||
(when to-message
|
||||
(dispatch [:request-answered! chat-id to-message]))))))
|
||||
|
||||
(register-handler ::invoke-command-handlers!
|
||||
(u/side-effect!
|
||||
(fn [db [_ {:keys [chat-id address] :as parameters}]]
|
||||
(let [{:keys [command content]} (:command parameters)
|
||||
{:keys [type name]} command
|
||||
path [(if (= :command type) :commands :responses)
|
||||
name
|
||||
:handler]
|
||||
to (get-in db [:contacts chat-id :address])
|
||||
params {:value content
|
||||
:command {:from address
|
||||
:to to}}]
|
||||
(j/call chat-id
|
||||
path
|
||||
params
|
||||
#(dispatch [:command-handler! chat-id parameters %]))))))
|
||||
|
||||
(register-handler ::prepare-message
|
||||
(u/side-effect!
|
||||
(fn [db [_ {:keys [chat-id identity message] :as params}]]
|
||||
(let [message' (cu/check-author-direction
|
||||
db chat-id
|
||||
{:msg-id (random/id)
|
||||
:chat-id chat-id
|
||||
:content message
|
||||
:to chat-id
|
||||
:from identity
|
||||
:content-type text-content-type
|
||||
:delivery-status (default-delivery-status chat-id)
|
||||
:outgoing true
|
||||
:timestamp (time/now-ms)})
|
||||
params' (assoc params :message message')]
|
||||
(dispatch [::add-message params'])
|
||||
(dispatch [::save-message! params'])
|
||||
(dispatch [::send-message! params'])))))
|
||||
|
||||
(register-handler ::add-message
|
||||
(fn [db [_ {:keys [chat-id message]}]]
|
||||
(cu/add-message-to-db db chat-id message)))
|
||||
|
||||
(register-handler ::save-message!
|
||||
(u/side-effect!
|
||||
(fn [_ [_ {:keys [chat-id message]}]]
|
||||
(messages/save-message chat-id message))))
|
||||
|
||||
(register-handler ::send-message!
|
||||
(u/side-effect!
|
||||
(fn [db [_ {:keys [message chat-id]}]]
|
||||
(when (and message (cu/not-console? chat-id))
|
||||
(let [{:keys [group-chat]} (get-in db [:chats chat-id])
|
||||
message' (select-keys message [:content :msg-id])]
|
||||
(if group-chat
|
||||
(api/send-group-user-msg (assoc message' :group-id chat-id))
|
||||
(api/send-user-msg (assoc message' :to chat-id))))))))
|
||||
|
||||
(register-handler ::send-command-protocol!
|
||||
(u/side-effect!
|
||||
(fn [db [_ {:keys [chat-id command]}]]
|
||||
(let [{:keys [content]} command]
|
||||
(when (cu/not-console? chat-id)
|
||||
(let [{:keys [group-chat]} (get-in db [:chats chat-id])
|
||||
message {:content content
|
||||
:content-type content-type-command}]
|
||||
(if group-chat
|
||||
(api/send-group-user-msg (assoc message :group-id chat-id))
|
||||
(api/send-user-msg (assoc message :to chat-id)))))))))
|
|
@ -123,7 +123,7 @@
|
|||
|
||||
(defn actions-list-view [{styles :styles :as platform-specific}]
|
||||
(let [{:keys [group-chat chat-id]} (subscribe [:chat-properties [:group-chat :chat-id]])
|
||||
members (subscribe [:current-chat-contacts])
|
||||
members (subscribe [:current-chat-contacts])
|
||||
status-bar-height (get-in styles [:components :status-bar :default :height])]
|
||||
(when-let [actions (if @group-chat
|
||||
[{:title (label :t/members-title)
|
||||
|
@ -203,9 +203,10 @@
|
|||
(label :t/active-unknown))))
|
||||
|
||||
(defn toolbar-content [platform-specific]
|
||||
(let [{:keys [group-chat chat-id name contacts]} (subscribe [:chat-properties [:group-chat :chat-id :name :contacts]])
|
||||
contact (subscribe [:get-in [:contacts @chat-id]])
|
||||
show-actions (subscribe [:show-actions])]
|
||||
(let [{:keys [group-chat name contacts chat-id]}
|
||||
(subscribe [:chat-properties [:group-chat :name :contacts :chat-id]])
|
||||
show-actions (subscribe [:show-actions])
|
||||
contact (subscribe [:get-in [:contacts @chat-id]])]
|
||||
(fn []
|
||||
[view (st/chat-name-view @show-actions)
|
||||
[text {:style st/chat-name-text
|
||||
|
@ -242,7 +243,7 @@
|
|||
|
||||
(defn chat-toolbar [platform-specific]
|
||||
(let [{:keys [group-chat name contacts]} (subscribe [:chat-properties [:group-chat :name :contacts]])
|
||||
show-actions (subscribe [:show-actions])]
|
||||
show-actions (subscribe [:show-actions])]
|
||||
[view
|
||||
[status-bar {:platform-specific platform-specific}]
|
||||
[toolbar {:hide-nav? @show-actions
|
||||
|
@ -252,14 +253,15 @@
|
|||
|
||||
(defview messages-view [platform-specific group-chat]
|
||||
[messages [:chat :messages]
|
||||
contacts [:chat :contacts]]
|
||||
contacts [:chat :contacts]
|
||||
loaded? [:all-messages-loaded?]]
|
||||
(let [contacts' (contacts-by-identity contacts)]
|
||||
[list-view {:renderRow (message-row {:contact-by-identity contacts'
|
||||
:platform-specific platform-specific
|
||||
:group-chat group-chat
|
||||
:messages-count (count messages)})
|
||||
:renderScrollComponent #(invertible-scroll-view (js->clj %))
|
||||
:onEndReached #(dispatch [:load-more-messages])
|
||||
:onEndReached (when-not loaded? #(dispatch [:load-more-messages]))
|
||||
:enableEmptySections true
|
||||
:keyboardShouldPersistTaps true
|
||||
:dataSource (to-datasource-inverted messages)}]))
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
;; -- Send phone number ----------------------------------------
|
||||
(defn on-sign-up-response [& [message]]
|
||||
(let [msg-id (random/id)]
|
||||
(dispatch [:received-msg
|
||||
(dispatch [:received-message
|
||||
{:msg-id msg-id
|
||||
:content (command-content
|
||||
:confirmation-code
|
||||
|
@ -62,7 +62,7 @@
|
|||
|
||||
;; -- Send confirmation code and synchronize contacts---------------------------
|
||||
(defn on-sync-contacts []
|
||||
(dispatch [:received-msg
|
||||
(dispatch [:received-message
|
||||
{:msg-id (random/id)
|
||||
:content (label :t/contacts-syncronized)
|
||||
:content-type text-content-type
|
||||
|
@ -76,7 +76,7 @@
|
|||
(dispatch [:sync-contacts on-sync-contacts]))
|
||||
|
||||
(defn on-send-code-response [body]
|
||||
(dispatch [:received-msg
|
||||
(dispatch [:received-message
|
||||
{:msg-id (random/id)
|
||||
:content (:message body)
|
||||
:content-type text-content-type
|
||||
|
@ -96,47 +96,52 @@
|
|||
;; -- Saving password ----------------------------------------
|
||||
(defn save-password [password]
|
||||
;; TODO validate and save password
|
||||
(dispatch [:received-msg
|
||||
(dispatch [:received-message
|
||||
{:msg-id (random/id)
|
||||
:content (label :t/password-saved)
|
||||
:content-type text-content-type
|
||||
:outgoing false
|
||||
:from "console"
|
||||
:to "me"}])
|
||||
(dispatch [:received-msg
|
||||
:to "me"
|
||||
:new? false}])
|
||||
(dispatch [:received-message
|
||||
{:msg-id (random/id)
|
||||
:content (label :t/generate-passphrase)
|
||||
:content-type text-content-type
|
||||
:outgoing false
|
||||
:from "console"
|
||||
:to "me"}])
|
||||
(dispatch [:received-msg
|
||||
:to "me"
|
||||
:new? false}])
|
||||
(dispatch [:received-message
|
||||
{:msg-id (random/id)
|
||||
:content (label :t/passphrase)
|
||||
:content-type text-content-type
|
||||
:outgoing false
|
||||
:from "console"
|
||||
:to "me"}])
|
||||
:to "me"
|
||||
:new? false}])
|
||||
;; TODO generate passphrase
|
||||
(let [passphrase (str "The brash businessman's braggadocio and public squabbing with "
|
||||
"candidates in the US presidential election")]
|
||||
(dispatch [:received-msg
|
||||
(dispatch [:received-message
|
||||
{:msg-id (random/id)
|
||||
:content passphrase
|
||||
:content-type text-content-type
|
||||
:outgoing false
|
||||
:from "console"
|
||||
:to "me"}]))
|
||||
(dispatch [:received-msg
|
||||
:to "me"
|
||||
:new? false}]))
|
||||
(dispatch [:received-message
|
||||
{:msg-id "8"
|
||||
:content (label :t/written-down)
|
||||
:content-type text-content-type
|
||||
:outgoing false
|
||||
:from "console"
|
||||
:to "me"}])
|
||||
:to "me"
|
||||
:new? false}])
|
||||
;; TODO highlight '!phone'
|
||||
(let [msg-id (random/id)]
|
||||
(dispatch [:received-msg
|
||||
(dispatch [:received-message
|
||||
{:msg-id msg-id
|
||||
:content (command-content
|
||||
:phone
|
||||
|
@ -157,15 +162,15 @@
|
|||
:to "me"})
|
||||
|
||||
(defn intro [db]
|
||||
(dispatch [:received-msg intro-status])
|
||||
(dispatch [:received-msg
|
||||
(dispatch [:received-message intro-status])
|
||||
(dispatch [:received-message
|
||||
{:msg-id "intro-message1"
|
||||
:content (label :t/intro-message1)
|
||||
:content-type text-content-type
|
||||
:outgoing false
|
||||
:from "console"
|
||||
:to "me"}])
|
||||
(dispatch [:received-msg
|
||||
(dispatch [:received-message
|
||||
{:msg-id "intro-message2"
|
||||
:content (label :t/intro-message2)
|
||||
:content-type text-content-type
|
||||
|
@ -173,7 +178,7 @@
|
|||
:from "console"
|
||||
:to "me"}])
|
||||
(let [msg-id "into-message3"]
|
||||
(dispatch [:received-msg
|
||||
(dispatch [:received-message
|
||||
{:msg-id msg-id
|
||||
:content (command-content
|
||||
:keypair
|
||||
|
|
|
@ -3,15 +3,16 @@
|
|||
[status-im.chat.constants :as constants]))
|
||||
|
||||
(def messages-container
|
||||
{:background-color :red
|
||||
{:background-color :#d50000
|
||||
:height constants/request-info-height
|
||||
:padding-left 16
|
||||
:padding-top 14})
|
||||
:padding-top 12})
|
||||
|
||||
(def title
|
||||
{:color :white
|
||||
:font-size 12
|
||||
:font-size 14
|
||||
:font-family st/font})
|
||||
|
||||
(def description
|
||||
(assoc title :opacity 0.69))
|
||||
(assoc title :opacity 0.9
|
||||
:font-size 12))
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
(fn [db _]
|
||||
(->> [:chats (:current-chat-id @db) :staged-commands]
|
||||
(get-in @db)
|
||||
vals
|
||||
(reaction))))
|
||||
|
||||
(register-sub :valid-plain-message?
|
||||
|
@ -232,3 +233,8 @@
|
|||
20
|
||||
|
||||
:else 0)))))
|
||||
|
||||
(register-sub :all-messages-loaded?
|
||||
(fn [db]
|
||||
(let [chat-id (subscribe [:get-current-chat-id])]
|
||||
(reaction (get-in @db [:chats @chat-id :all-loaded?])))))
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
[status-im.db :as db]
|
||||
[status-im.models.commands :refer [get-commands
|
||||
get-chat-command-request
|
||||
get-chat-command-to-msg-id
|
||||
clear-staged-commands]]
|
||||
get-chat-command-to-msg-id]]
|
||||
[status-im.utils.utils :refer [log on-error http-get]]
|
||||
[clojure.string :as s]))
|
||||
|
||||
|
@ -39,15 +38,6 @@
|
|||
(fn []
|
||||
(command-handler to-msg-id command-key content)))))
|
||||
|
||||
(defn apply-staged-commands [db]
|
||||
(let [staged-commands (get-in db (db/chat-staged-commands-path
|
||||
(:current-chat-id db)))]
|
||||
(dorun (map (fn [staged-command]
|
||||
(when-let [handler (:handler staged-command)]
|
||||
(handler)))
|
||||
staged-commands))
|
||||
(clear-staged-commands db)))
|
||||
|
||||
(defn check-suggestion [db message]
|
||||
(when-let [suggestion-text (when (string? message)
|
||||
(re-matches #"^![^\s]+\s" message))]
|
||||
|
@ -60,7 +50,3 @@
|
|||
(-> db
|
||||
(get-in [:chats (:current-chat-id db) :input-text])
|
||||
suggestion?))
|
||||
|
||||
(defn switch-command-suggestions [db]
|
||||
(let [text (if (typing-command? db) nil "!")]
|
||||
(assoc-in db [:chats (:current-chat-id db) :input-text] text)))
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
(ns status-im.chat.utils)
|
||||
|
||||
(defn console? [s]
|
||||
(= "console" s))
|
||||
|
||||
(def not-console?
|
||||
(complement console?))
|
||||
|
||||
(defn add-message-to-db
|
||||
([db chat-id message] (add-message-to-db db chat-id message true))
|
||||
([db chat-id message new?]
|
||||
(let [messages [:chats chat-id :messages]]
|
||||
(update-in db messages conj (assoc message :chat-id chat-id
|
||||
:new? (if (nil? new?)
|
||||
true
|
||||
new?))))))
|
||||
|
||||
(defn check-author-direction
|
||||
[db chat-id {:keys [from outgoing] :as message}]
|
||||
(let [previous-message (first (get-in db [:chats chat-id :messages]))]
|
||||
(merge message
|
||||
{:same-author (if previous-message
|
||||
(= (:from previous-message) from)
|
||||
true)
|
||||
:same-direction (if previous-message
|
||||
(= (:outgoing previous-message) outgoing)
|
||||
true)})))
|
|
@ -88,7 +88,7 @@
|
|||
[text {:style st/command-text
|
||||
:platform-specific platform-specific
|
||||
:font :default}
|
||||
content])]))
|
||||
(str content)])]))
|
||||
|
||||
(defn set-chat-command [msg-id command]
|
||||
(dispatch [:set-response-chat-command msg-id (keyword (:name command))]))
|
||||
|
@ -114,7 +114,7 @@
|
|||
[text {:style (st/text-message message)
|
||||
:platform-specific platform-specific
|
||||
:font :default}
|
||||
content]])
|
||||
(str content)]])
|
||||
|
||||
(defmethod message-content text-content-type
|
||||
[wrapper message platform-specific]
|
||||
|
@ -213,9 +213,7 @@
|
|||
:callback anim-callback}
|
||||
on-update (message-container-animation-logic context)]
|
||||
(r/create-class
|
||||
{:component-did-mount
|
||||
on-update
|
||||
:component-did-update
|
||||
{:component-did-update
|
||||
on-update
|
||||
:reagent-render
|
||||
(fn [message & children]
|
||||
|
@ -241,7 +239,8 @@
|
|||
(dispatch [:send-seen! chat-id msg-id])))
|
||||
:reagent-render
|
||||
(fn [{:keys [outgoing delivery-status timestamp new-day group-chat]
|
||||
:as message}]
|
||||
:as message}
|
||||
platform-specific]
|
||||
[message-container message
|
||||
;; TODO there is no new-day info in message
|
||||
(when new-day
|
||||
|
|
|
@ -72,12 +72,14 @@
|
|||
[suggestions [:get-suggestions]
|
||||
requests [:get-requests]]
|
||||
[scroll-view {:keyboardShouldPersistTaps true}
|
||||
;; todo translations
|
||||
(when (seq requests) [title "Requests"])
|
||||
(when (seq requests)
|
||||
[view
|
||||
[list-view {:dataSource (to-datasource requests)
|
||||
:keyboardShouldPersistTaps true
|
||||
:renderRow render-request-row}]])
|
||||
;; todo translations
|
||||
[title "Commands"]
|
||||
[view
|
||||
[list-view {:dataSource (to-datasource suggestions)
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
[{:keys [chat-id name color new-messages-count
|
||||
online group-chat contacts] :as chat}]
|
||||
[unviewed-messages [:unviewed-messages-count chat-id]]
|
||||
(let [last-message (first (:messages chat))]
|
||||
(let [last-message (first (:messages chat))
|
||||
name (or name chat-id)]
|
||||
[view st/chat-container
|
||||
[view st/chat-icon-container
|
||||
[chat-icon-view-chat-list chat-id group-chat name color online]]
|
||||
|
|
|
@ -19,24 +19,37 @@
|
|||
(assoc-in db [:rendered-commands chat-id message-id] hiccup)))
|
||||
|
||||
(def console-events
|
||||
{:save-password #(dispatch [:save-password %])
|
||||
:sign-up #(dispatch [:sign-up %])
|
||||
:confirm-sign-up #(dispatch [:sign-up-confirm %])})
|
||||
{:save-password (fn [[parameter]]
|
||||
(dispatch [:save-password parameter]))
|
||||
:sign-up (fn [[parameter]]
|
||||
(dispatch [:sign-up parameter]))
|
||||
:confirm-sign-up (fn [[parameter]]
|
||||
(dispatch [:sign-up-confirm parameter]))})
|
||||
|
||||
(def regular-events {})
|
||||
|
||||
(defn command-hadler!
|
||||
[_ [{:keys [to]} {:keys [result]} ]]
|
||||
(when result
|
||||
(let [{:keys [event params]} result
|
||||
events (if (= "console" to)
|
||||
(merge regular-events console-events)
|
||||
regular-events)]
|
||||
(when-let [handler (events (keyword event))]
|
||||
(apply handler params)))))
|
||||
[_ [chat-id {:keys [command] :as parameters} {:keys [result error]}]]
|
||||
(cond
|
||||
result
|
||||
(let [{:keys [event params transaction-hash]} result
|
||||
command' (assoc command :handler-data result)
|
||||
parameters' (assoc parameters :command command')]
|
||||
(if transaction-hash
|
||||
(dispatch [:wait-for-transaction transaction-hash parameters'])
|
||||
(let [events (if (= "console" chat-id)
|
||||
(merge regular-events console-events)
|
||||
regular-events)
|
||||
parameters'' (if-let [handler (events (keyword event))]
|
||||
(assoc parameters' :handler #(handler params command'))
|
||||
parameters')]
|
||||
(dispatch [:prepare-command! parameters'']))))
|
||||
(not error)
|
||||
(dispatch [:prepare-command! parameters])
|
||||
:else nil))
|
||||
|
||||
(defn suggestions-handler!
|
||||
[db [{:keys [chat-id]} {:keys [result]} ]]
|
||||
[db [{:keys [chat-id]} {:keys [result]}]]
|
||||
(let [{:keys [markup webViewUrl]} result
|
||||
hiccup (generate-hiccup markup)]
|
||||
(-> db
|
||||
|
@ -52,13 +65,10 @@
|
|||
nil))
|
||||
|
||||
(defn command-preview
|
||||
[db [chat-id {:keys [result]}]]
|
||||
[db [chat-id command-id {:keys [result]}]]
|
||||
(if result
|
||||
(let [path [:chats chat-id :staged-commands]
|
||||
commands-cnt (count (get-in db path))]
|
||||
;; todo (dec commands-cnt) looks like hack have to find better way to
|
||||
;; do this
|
||||
(update-in db (conj path (dec commands-cnt)) assoc
|
||||
(let [path [:chats chat-id :staged-commands command-id]]
|
||||
(update-in db path assoc
|
||||
:preview (generate-hiccup result)
|
||||
:preview-string (str result)))
|
||||
db))
|
||||
|
@ -73,18 +83,20 @@
|
|||
(reg-handler ::render-command render-command)
|
||||
|
||||
(reg-handler :command-handler!
|
||||
(after (print-error-message! "Error on command handling"))
|
||||
(u/side-effect! command-hadler!))
|
||||
(after (print-error-message! "Error on command handling"))
|
||||
(u/side-effect! command-hadler!))
|
||||
|
||||
(reg-handler :suggestions-handler
|
||||
[(after #(dispatch [:animate-show-response]))
|
||||
(after (print-error-message! "Error on param suggestions"))
|
||||
(after (fn [_ [{:keys [command]} {:keys [result]}]]
|
||||
(when (= :on-send (keyword (:suggestions-trigger command)))
|
||||
(when (:webViewUrl result)
|
||||
(dispatch [:set-soft-input-mode :pan]))
|
||||
(r/dismiss-keyboard!))))]
|
||||
suggestions-handler!)
|
||||
[(after #(dispatch [:animate-show-response]))
|
||||
(after (print-error-message! "Error on param suggestions"))
|
||||
(after (fn [_ [{:keys [command]} {:keys [result]}]]
|
||||
(when (= :on-send (keyword (:suggestions-trigger command)))
|
||||
(when (:webViewUrl result)
|
||||
(dispatch [:set-soft-input-mode :pan]))
|
||||
(r/dismiss-keyboard!))))]
|
||||
suggestions-handler!)
|
||||
(reg-handler :suggestions-event! (u/side-effect! suggestions-events-handler!))
|
||||
|
||||
(reg-handler :command-preview
|
||||
(after (print-error-message! "Error on command preview"))
|
||||
command-preview)
|
||||
(after (print-error-message! "Error on command preview"))
|
||||
command-preview)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
(ns status-im.commands.handlers.loading
|
||||
(:require-macros [status-im.utils.slurp :refer [slurp]])
|
||||
(:require [re-frame.core :refer [after dispatch subscribe trim-v debug]]
|
||||
(:require [re-frame.core :refer [path after dispatch subscribe trim-v debug]]
|
||||
[status-im.utils.handlers :as u]
|
||||
[status-im.utils.utils :refer [http-get toast]]
|
||||
[clojure.string :as s]
|
||||
|
@ -22,10 +22,13 @@
|
|||
|
||||
(defn fetch-commands!
|
||||
[db [identity]]
|
||||
(when-let [url (:dapp-url (get-in db [:chats identity]))]
|
||||
(if (= "console" identity)
|
||||
(when true
|
||||
;;when-let [url (:dapp-url (get-in db [:chats identity]))]
|
||||
;; todo fix this after demo
|
||||
(if true
|
||||
;(= "console" identity)
|
||||
(dispatch [::validate-hash identity (slurp "resources/commands.js")])
|
||||
(http-get (s/join "/" [url commands-js])
|
||||
#_(http-get (s/join "/" [url commands-js])
|
||||
#(dispatch [::validate-hash identity %])
|
||||
#(dispatch [::loading-failed! identity ::file-was-not-found])))))
|
||||
|
||||
|
@ -68,8 +71,9 @@
|
|||
(defn add-commands
|
||||
[db [id _ {:keys [commands responses]}]]
|
||||
(-> db
|
||||
(update-in [:chats id :commands] merge (mark-as :command commands))
|
||||
(update-in [:chats id :responses] merge (mark-as :response responses))))
|
||||
(update-in [id :commands] merge (mark-as :command commands))
|
||||
(update-in [id :responses] merge (mark-as :response responses))
|
||||
(assoc-in [id :commands-loaded] true)))
|
||||
|
||||
(defn save-commands-js!
|
||||
[_ [id file]]
|
||||
|
@ -96,7 +100,8 @@
|
|||
(reg-handler ::parse-commands! (u/side-effect! parse-commands!))
|
||||
|
||||
(reg-handler ::add-commands
|
||||
(after save-commands-js!)
|
||||
[(path :chats)
|
||||
(after save-commands-js!)]
|
||||
add-commands)
|
||||
|
||||
(reg-handler ::loading-failed! (u/side-effect! loading-failed!))
|
||||
|
|
|
@ -20,8 +20,10 @@
|
|||
(defn get-active-page [data]
|
||||
(get data :activePage 0))
|
||||
|
||||
(defn get-sneak [data]
|
||||
(get data :sneak (:sneak defaults)))
|
||||
(defn get-sneak [{:keys [sneak count] }]
|
||||
(if (> (or count 2) 1)
|
||||
(or sneak (:sneak defaults))
|
||||
0))
|
||||
|
||||
(defn get-gap [data]
|
||||
(get data :gap (:gap defaults)))
|
||||
|
@ -64,7 +66,7 @@
|
|||
state (reagent.core/state component)
|
||||
page-width (get-page-width state)
|
||||
gap (get-gap state)
|
||||
page-position (* page (+ page-width gap))]
|
||||
page-position (+ (* page page-width) (* (- page 1) gap))]
|
||||
(log/debug "go-to-page: props-page-width=" page-width "; gap=" gap
|
||||
"; page-position=" page-position)
|
||||
(scroll-to component page-position 0)
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
{:flex 1})
|
||||
|
||||
(defn content-container [sneak gap]
|
||||
{:paddingLeft (+ sneak (quot gap 2))
|
||||
{:paddingLeft (+ 0 (quot gap 2))
|
||||
:paddingRight (+ sneak (quot gap 2))})
|
||||
|
||||
(defn page [page-width margin]
|
||||
|
|
|
@ -31,9 +31,9 @@
|
|||
:style st/photo-pencil}]])]))
|
||||
|
||||
(defview chat-icon-view [chat-id group-chat name online styles]
|
||||
[photo-path [:chat-photo chat-id]]
|
||||
[view (:container styles)
|
||||
(if-not (s/blank? photo-path)
|
||||
[photo-path [:chat-photo chat-id]]
|
||||
[view (:container styles)
|
||||
(if-not (or (s/blank? photo-path) (= chat-id "console"))
|
||||
[chat-icon photo-path styles]
|
||||
[default-chat-icon name styles])
|
||||
(when-not group-chat
|
||||
|
|
|
@ -1,10 +1,20 @@
|
|||
(ns status-im.components.geth
|
||||
(:require [status-im.components.react :as r]))
|
||||
(:require [status-im.components.react :as r]
|
||||
[re-frame.core :refer [dispatch]]))
|
||||
|
||||
(def geth
|
||||
(when (exists? (.-NativeModules r/react-native))
|
||||
(.-Geth (.-NativeModules r/react-native))))
|
||||
|
||||
(defn register-signal-callback []
|
||||
(when geth
|
||||
(.registerSignalEventCallback
|
||||
geth
|
||||
#(do (dispatch [:signal-event %])
|
||||
(register-signal-callback)))))
|
||||
|
||||
(register-signal-callback)
|
||||
|
||||
(defn start-node [on-result on-already-running]
|
||||
(when geth
|
||||
(.startNode geth on-result on-already-running)))
|
||||
|
@ -15,4 +25,9 @@
|
|||
|
||||
(defn login [address password on-result]
|
||||
(when geth
|
||||
(.login geth address password on-result)))
|
||||
(.login geth address password on-result)))
|
||||
|
||||
(defn complete-transaction
|
||||
[hash callback]
|
||||
(when geth
|
||||
(.completeTransaction geth hash callback)))
|
||||
|
|
|
@ -79,6 +79,10 @@
|
|||
{:width 18
|
||||
:height 18})
|
||||
|
||||
(def icon-close
|
||||
{:width 12
|
||||
:height 12})
|
||||
|
||||
(def form-text-input
|
||||
{:marginLeft -4
|
||||
:fontSize 14
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
:lineColor "#0000001f"
|
||||
:focusLineColor "#0000001f"
|
||||
:errorColor "#d50000"
|
||||
:secureTextEntry false
|
||||
:onFocus #()
|
||||
:onBlur #()
|
||||
:onChangeText #()
|
||||
|
@ -144,19 +145,19 @@
|
|||
label-font-size
|
||||
line-width
|
||||
max-line-width] :as state} (r/state component)
|
||||
{:keys [wrapperStyle inputStyle lineColor focusLineColor
|
||||
{:keys [wrapperStyle inputStyle lineColor focusLineColor secureTextEntry
|
||||
labelColor errorColor error label value onFocus onBlur
|
||||
onChangeText onChange editable] :as props} (merge default-props (r/props component))
|
||||
lineColor (if error errorColor lineColor)
|
||||
focusLineColor (if error errorColor focusLineColor)
|
||||
labelColor (if (and error (not float-label?)) errorColor labelColor)
|
||||
label (if error (str label " *") label)]
|
||||
;(log/debug "reagent-render: " data)
|
||||
[view (merge st/text-field-container wrapperStyle)
|
||||
[animated-text {:style (st/label label-top label-font-size labelColor)} label]
|
||||
[text-input {:style (merge st/text-input inputStyle)
|
||||
:placeholder ""
|
||||
:editable editable
|
||||
:secureTextEntry secureTextEntry
|
||||
:onFocus #(on-focus {:component component
|
||||
:animation {:top label-top
|
||||
:to-top (:label-top config)
|
||||
|
@ -192,4 +193,4 @@
|
|||
:display-name "text-field"
|
||||
:reagent-render reagent-render}]
|
||||
;(log/debug "Creating text-field component: " data)
|
||||
(r/create-class component-data)))
|
||||
(r/create-class component-data)))
|
||||
|
|
|
@ -78,9 +78,10 @@
|
|||
(into {})))
|
||||
|
||||
(defn add-identity [contacts-by-hash contacts]
|
||||
(map (fn [{:keys [phone-number-hash whisper-identity]}]
|
||||
(map (fn [{:keys [phone-number-hash whisper-identity address]}]
|
||||
(let [contact (contacts-by-hash phone-number-hash)]
|
||||
(assoc contact :whisper-identity whisper-identity)))
|
||||
(assoc contact :whisper-identity whisper-identity
|
||||
:address address)))
|
||||
(js->clj contacts)))
|
||||
|
||||
(defn request-stored-contacts [contacts]
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
(ns status-im.contacts.subs
|
||||
(:require-macros [reagent.ratom :refer [reaction]])
|
||||
(:require [re-frame.core :refer [register-sub subscribe]]))
|
||||
(:require [re-frame.core :refer [register-sub subscribe]]
|
||||
[status-im.utils.identicon :refer [identicon]]))
|
||||
|
||||
(register-sub :get-contacts
|
||||
(fn [db _]
|
||||
|
@ -87,4 +88,6 @@
|
|||
(if (:group-chat @chat)
|
||||
;; TODO return group chat icon
|
||||
nil
|
||||
(:photo-path (first @contacts))))))))
|
||||
(if (pos? (count @contacts))
|
||||
(:photo-path (first @contacts))
|
||||
(identicon chat-id))))))))
|
||||
|
|
|
@ -41,11 +41,10 @@
|
|||
:keyboard-height 0
|
||||
:disable-group-creation false
|
||||
:animations {;; todo clear this
|
||||
:tabs-bar-value (anim/create-value 0)}})
|
||||
:tabs-bar-value (anim/create-value 0)}
|
||||
:loading-allowed true})
|
||||
|
||||
(def protocol-initialized-path [:protocol-initialized])
|
||||
(defn chat-input-text-path [chat-id]
|
||||
[:chats chat-id :input-text])
|
||||
(defn chat-staged-commands-path [chat-id]
|
||||
[:chats chat-id :staged-commands])
|
||||
(defn chat-command-path [chat-id]
|
||||
|
|
|
@ -23,7 +23,8 @@
|
|||
status-im.qr-scanner.handlers
|
||||
status-im.accounts.handlers
|
||||
status-im.protocol.handlers
|
||||
[status-im.utils.datetime :as time]))
|
||||
[status-im.utils.datetime :as time]
|
||||
status-im.transactions.handlers))
|
||||
|
||||
;; -- Middleware ------------------------------------------------------------
|
||||
;;
|
||||
|
@ -103,7 +104,7 @@
|
|||
(dispatch [:crypt-initialized]))))))))
|
||||
|
||||
(defn node-started [db result]
|
||||
(log/debug "Started Node: " result))
|
||||
(log/debug "Started Node: "))
|
||||
|
||||
(register-handler :initialize-geth
|
||||
(u/side-effect!
|
||||
|
|
|
@ -101,11 +101,6 @@
|
|||
(r/single-cljs)
|
||||
(r/list-to-array :contacts)))
|
||||
|
||||
(defn chat-by-id2 [chat-id]
|
||||
(-> (r/get-by-field :account :chat :chat-id chat-id)
|
||||
r/collection->map
|
||||
first))
|
||||
|
||||
(defn chat-add-participants [chat-id identities]
|
||||
(r/write :account
|
||||
(fn []
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
(ns status-im.models.commands
|
||||
(:require [status-im.db :as db]))
|
||||
(:require [status-im.db :as db]
|
||||
[tailrecursion.priority-map :refer [priority-map-by]]))
|
||||
|
||||
(defn get-commands [{:keys [current-chat-id] :as db}]
|
||||
(or (get-in db [:chats current-chat-id :commands]) {}))
|
||||
|
@ -37,21 +38,22 @@
|
|||
[{:keys [current-chat-id] :as db}]
|
||||
(get-in db (db/chat-command-to-msg-id-path current-chat-id)))
|
||||
|
||||
(defn compare-commands
|
||||
[{created-at-1 :created-at} {created-at-2 :created-at}]
|
||||
(compare created-at-1 created-at-2))
|
||||
|
||||
(defn stage-command
|
||||
[{:keys [current-chat-id] :as db} command-info]
|
||||
(update-in db (db/chat-staged-commands-path current-chat-id)
|
||||
#(if %
|
||||
(conj % command-info)
|
||||
[command-info])))
|
||||
[{:keys [current-chat-id] :as db} {:keys [id] :as command-info}]
|
||||
(let [path (db/chat-staged-commands-path current-chat-id)
|
||||
staged-commands (get-in db path)
|
||||
staged-coomands' (if (seq staged-commands)
|
||||
staged-commands
|
||||
(priority-map-by compare-commands))]
|
||||
(assoc-in db path (assoc staged-coomands' id command-info))))
|
||||
|
||||
(defn unstage-command [db staged-command]
|
||||
(defn unstage-command [db {:keys [id]}]
|
||||
(update-in db (db/chat-staged-commands-path (:current-chat-id db))
|
||||
(fn [staged-commands]
|
||||
(filterv #(not= % staged-command) staged-commands))))
|
||||
|
||||
(defn clear-staged-commands
|
||||
[{:keys [current-chat-id] :as db}]
|
||||
(assoc-in db (db/chat-staged-commands-path current-chat-id) []))
|
||||
dissoc id))
|
||||
|
||||
(defn get-chat-command-request
|
||||
[{:keys [current-chat-id] :as db}]
|
||||
|
|
|
@ -57,9 +57,13 @@
|
|||
(r/collection->map))
|
||||
(into '())
|
||||
reverse
|
||||
(keep (fn [{:keys [content-type] :as message}]
|
||||
(keep (fn [{:keys [content-type preview] :as message}]
|
||||
(if (command-type? content-type)
|
||||
(update message :content str-to-map)
|
||||
(-> message
|
||||
(update :content str-to-map)
|
||||
(assoc :rendered-preview
|
||||
(when preview
|
||||
(generate-hiccup (read-string preview)))))
|
||||
message))))))
|
||||
|
||||
(defn update-message! [{:keys [msg-id] :as msg}]
|
||||
|
@ -68,3 +72,7 @@
|
|||
(fn []
|
||||
(when (r/exists? :account :message :msg-id msg-id)
|
||||
(r/create :account :message msg true)))))
|
||||
|
||||
(defn get-message [id]
|
||||
(r/get-one-by-field :account :message :msg-id id))
|
||||
|
||||
|
|
|
@ -25,8 +25,10 @@
|
|||
|
||||
(register-handler :navigate-to
|
||||
(enrich preload-data!)
|
||||
(fn [db [_ view-id]]
|
||||
(push-view db view-id)))
|
||||
(fn [{:keys [view-id] :as db} [_ new-view-id]]
|
||||
(if (= view-id new-view-id)
|
||||
db
|
||||
(push-view db new-view-id))))
|
||||
|
||||
(register-handler :navigation-replace
|
||||
(enrich preload-data!)
|
||||
|
|
|
@ -128,3 +128,8 @@
|
|||
(after (fn [_ [_ chat-id]]
|
||||
(dispatch [:remove-unviewed-messages chat-id])))]
|
||||
(update-message-status :seen))
|
||||
|
||||
(register-handler :send-transaction!
|
||||
(u/side-effect!
|
||||
(fn [_ [_ amount message]]
|
||||
(println :send-transacion! amount message))))
|
||||
|
|
|
@ -14,12 +14,11 @@
|
|||
:active-group-ids (active-group-chats)
|
||||
:storage kv/kv-store
|
||||
:handler (fn [{:keys [event-type] :as event}]
|
||||
(log/info "Event:" (clj->js event))
|
||||
(case event-type
|
||||
:initialized (let [{:keys [identity]} event]
|
||||
(dispatch [:protocol-initialized identity]))
|
||||
:new-msg (let [{:keys [from to payload]} event]
|
||||
(dispatch [:received-msg (assoc payload :from from :to to)]))
|
||||
(dispatch [:received-message (assoc payload :from from :to to)]))
|
||||
:msg-acked (let [{:keys [msg-id from]} event]
|
||||
(dispatch [:acked-msg from msg-id]))
|
||||
:msg-seen (let [{:keys [msg-id from]} event]
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
status-im.discovery.subs
|
||||
status-im.contacts.subs
|
||||
status-im.new-group.subs
|
||||
status-im.participants.subs))
|
||||
status-im.participants.subs
|
||||
status-im.transactions.subs))
|
||||
|
||||
(register-sub :get
|
||||
(fn [db [_ k]]
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
(ns status-im.transactions.handlers
|
||||
(:require [re-frame.core :refer [after dispatch debug enrich]]
|
||||
[status-im.utils.handlers :refer [register-handler]]
|
||||
[status-im.navigation.handlers :as nav]
|
||||
[status-im.utils.handlers :as u]
|
||||
[status-im.utils.types :as t]
|
||||
[status-im.components.geth :as g]
|
||||
cljsjs.web3
|
||||
[clojure.string :as s]))
|
||||
|
||||
(defmethod nav/preload-data! :confirm
|
||||
[{:keys [transactions-queue] :as db} _]
|
||||
(assoc db :transactions transactions-queue))
|
||||
|
||||
(defn on-unlock [hashes]
|
||||
(fn [result-str]
|
||||
(let [{:keys [error]} (t/json->clj result-str)]
|
||||
;; todo: add message about wrong password
|
||||
(if (s/blank? error)
|
||||
(do
|
||||
(dispatch [:set :wrong-password? false])
|
||||
(doseq [hash hashes]
|
||||
(g/complete-transaction
|
||||
hash
|
||||
#(dispatch [:transaction-completed hash %])))
|
||||
(dispatch [:navigate-back]))
|
||||
(dispatch [:set :wrong-password? true])))))
|
||||
|
||||
(register-handler :accept-transactions
|
||||
(u/side-effect!
|
||||
(fn [{:keys [transactions current-account-id]} [_ password]]
|
||||
(let [hashes (keys transactions)]
|
||||
(g/login current-account-id password (on-unlock hashes))))))
|
||||
|
||||
(register-handler :deny-transactions
|
||||
(u/side-effect!
|
||||
(fn [{:keys [transactions]}]
|
||||
(let [hashes (keys transactions)]
|
||||
(dispatch [::remove-pending-messages hashes])
|
||||
(dispatch [::remove-trqqansactions hashes])
|
||||
(dispatch [:navigate-back])))))
|
||||
|
||||
(register-handler :deny-transaction
|
||||
(u/side-effect!
|
||||
(fn [_ [_ hash]]
|
||||
(dispatch [::remove-pending-message hash])
|
||||
(dispatch [::remove-transaction hash]))))
|
||||
|
||||
(register-handler ::remove-transactions
|
||||
(fn [db [_ hashes]]
|
||||
(-> db
|
||||
(dissoc :transactions)
|
||||
(update :transactions-queue #(apply dissoc % hashes)))))
|
||||
|
||||
(register-handler ::remove-transaction
|
||||
(fn [db [_ hash]]
|
||||
(-> db
|
||||
(update :transactions dissoc hash)
|
||||
(update :transactions-queue dissoc hash))))
|
||||
|
||||
(register-handler :wait-for-transaction
|
||||
(fn [db [_ hash {:keys [chat-id command] :as params}]]
|
||||
(let [id (:id command)]
|
||||
(-> db
|
||||
(update-in [:chats chat-id :staged-commands id] assoc :pending true)
|
||||
(assoc-in [:transaction-subscribers hash] params)))))
|
||||
|
||||
(defn remove-pending-message [db hash]
|
||||
(let [{:keys [chat-id command]} (get-in db [:transaction-subscribers hash])
|
||||
path [:chats chat-id :staged-commands]]
|
||||
(-> db
|
||||
(update :transaction-subscribers dissoc hash)
|
||||
(update-in path dissoc (:id command)))))
|
||||
|
||||
(register-handler ::remove-pending-messages
|
||||
(fn [db [_ hashes]]
|
||||
(reduce remove-pending-message db hashes)))
|
||||
|
||||
(register-handler ::remove-pending-message
|
||||
(fn [db [_ hash]]
|
||||
(remove-pending-message db hash)))
|
||||
|
||||
(register-handler :signal-event
|
||||
(u/side-effect!
|
||||
(fn [_ [_ event-str]]
|
||||
(let [{:keys [type event]} (t/json->clj event-str)]
|
||||
(case type
|
||||
"sendTransactionQueued" (dispatch [:transaction-queued event]))))))
|
||||
|
||||
(register-handler :transaction-queued
|
||||
(after #(dispatch [:navigate-to :confirm]))
|
||||
(fn [db [_ {:keys [hash args]}]]
|
||||
(let [{:keys [from to value]} args
|
||||
transaction {:hash hash
|
||||
:from from
|
||||
:to to
|
||||
:value (.toDecimal js/Web3.prototype value)}]
|
||||
(assoc-in db [:transactions-queue hash] transaction))))
|
||||
|
||||
(register-handler :transaction-completed
|
||||
(u/side-effect!
|
||||
(fn [db [_ old-hash result-str]]
|
||||
(let [{:keys [hash error]} (t/json->clj result-str)]
|
||||
;; todo: handle error
|
||||
(when hash
|
||||
(dispatch [::send-pending-message old-hash hash])
|
||||
(dispatch [::remove-transaction old-hash]))))))
|
||||
|
||||
(register-handler ::send-pending-message
|
||||
(u/side-effect!
|
||||
(fn [{:keys [transaction-subscribers] :as db} [_ old-hash new-hash]]
|
||||
(when-let [params (transaction-subscribers old-hash)]
|
||||
(let [params' (assoc-in params [:handler-data :transaction-hash] new-hash)]
|
||||
(dispatch [:prepare-command! params']))
|
||||
(dispatch [::remove-transaction-subscriber old-hash])))))
|
||||
|
||||
(register-handler ::remove-transaction-subscriber
|
||||
(fn [db [_ old-hash]]
|
||||
(update db :transaction-subscribers dissoc old-hash)))
|
|
@ -0,0 +1,62 @@
|
|||
(ns status-im.transactions.screen
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[status-im.components.react :refer [view
|
||||
text
|
||||
image
|
||||
icon
|
||||
scroll-view
|
||||
touchable-highlight
|
||||
touchable-opacity]]
|
||||
[status-im.components.styles :refer [icon-ok
|
||||
icon-close
|
||||
toolbar-title-container]]
|
||||
[status-im.components.carousel.carousel :refer [carousel]]
|
||||
[status-im.components.toolbar :refer [toolbar]]
|
||||
[status-im.components.text-field.view :refer [text-field]]
|
||||
[status-im.transactions.views.transaction-page :refer [transaction-page]]
|
||||
[status-im.transactions.styles :as st]
|
||||
[status-im.i18n :refer [label label-pluralize]]
|
||||
[clojure.string :as s]))
|
||||
|
||||
|
||||
(defview confirm []
|
||||
[transactions [:transactions]
|
||||
{:keys [password]} [:get :confirm-transactions]
|
||||
wrong-password? [:wrong-password?]]
|
||||
[view st/transactions-screen
|
||||
[toolbar
|
||||
{:style st/transactions-toolbar
|
||||
:nav-action {:image {:source {:uri :icon_close_white}
|
||||
:style icon-close}
|
||||
:handler #(dispatch [:deny-transactions])}
|
||||
:custom-content [view {:style toolbar-title-container}
|
||||
[text {:style st/toolbar-title-text}
|
||||
(label-pluralize (count transactions) :t/confirm-transactions)]]
|
||||
:action {:image {:source {:uri (if-not (s/blank? password)
|
||||
:icon_ok
|
||||
:icon_ok_disabled_inversed)}
|
||||
:style icon-ok}
|
||||
:handler #(dispatch [:accept-transactions password])}}]
|
||||
[view st/carousel-container
|
||||
[carousel {:pageStyle st/carousel-page-style
|
||||
:gap 16
|
||||
:count (count transactions)
|
||||
:sneak 20}
|
||||
(when transactions
|
||||
(for [transaction transactions]
|
||||
[transaction-page transaction]))]]
|
||||
[view st/form-container
|
||||
[text-field
|
||||
{:inputStyle st/password-style
|
||||
:secureTextEntry true
|
||||
:error (when wrong-password? (label :t/wrong-password))
|
||||
:errorColor :#ffffff80 #_:#7099e6
|
||||
:lineColor :white
|
||||
:labelColor :#ffffff80
|
||||
:value password
|
||||
:label (label :t/password)
|
||||
:onChangeText #(dispatch [:set-in [:confirm-transactions :password] %])}]]])
|
||||
|
||||
|
||||
;(re-frame.core/dispatch [:set :view-id :confirm])
|
|
@ -0,0 +1,107 @@
|
|||
(ns status-im.transactions.styles
|
||||
(:require [status-im.components.styles :refer [toolbar-height
|
||||
color-white]]))
|
||||
|
||||
|
||||
(def transactions-screen
|
||||
{:flex 1
|
||||
:backgroundColor "#828b92"})
|
||||
|
||||
(def transactions-toolbar
|
||||
{:backgroundColor "#828b92"
|
||||
:elevation 0})
|
||||
|
||||
(def toolbar-title-text
|
||||
{:color :white
|
||||
:fontSize 16})
|
||||
|
||||
(def carousel-page-style
|
||||
{})
|
||||
|
||||
(def form-container
|
||||
{:flex 1
|
||||
:paddingLeft 16})
|
||||
|
||||
(def password-style
|
||||
{:color :white})
|
||||
|
||||
;transaction-page
|
||||
|
||||
(def transaction-page
|
||||
{:flex 1
|
||||
:backgroundColor "#f3f4f4"})
|
||||
|
||||
(def title-bar
|
||||
{:backgroundColor :white
|
||||
:height 39
|
||||
:justifyContent :center})
|
||||
|
||||
(def title-bar-text
|
||||
{:fontFamily "sans-serif-medium"
|
||||
:color "#838c93"
|
||||
:fontSize 13
|
||||
:marginLeft 12})
|
||||
|
||||
(def icon-close-container
|
||||
{:position :absolute
|
||||
:right 12
|
||||
:top 13})
|
||||
|
||||
(def icon-close
|
||||
{:width 12
|
||||
:height 12})
|
||||
|
||||
(def transaction-info-container
|
||||
{:flex 1
|
||||
:paddingTop 6})
|
||||
|
||||
(def scroll-view-container
|
||||
{:flex 1})
|
||||
|
||||
(def scroll-view
|
||||
{:flex 1
|
||||
:height 175})
|
||||
|
||||
(def scroll-view-content
|
||||
{:paddingVertical 6})
|
||||
|
||||
(def transaction-info-row
|
||||
{:flex 1
|
||||
:flexDirection :row
|
||||
:height 20
|
||||
})
|
||||
|
||||
(def transaction-info-column-title
|
||||
{:flex 0.4
|
||||
:flexDirection :column
|
||||
:paddingHorizontal 6})
|
||||
|
||||
(def transaction-info-column-value
|
||||
{:flex 0.6
|
||||
:flexDirection :column
|
||||
:paddingHorizontal 6})
|
||||
|
||||
(def transaction-info-item
|
||||
{:flex 1
|
||||
:padding 6})
|
||||
|
||||
(def transaction-info-title
|
||||
{:textAlign :right
|
||||
:color "#838c93de"
|
||||
:fontSize 14
|
||||
:lineHeight 20})
|
||||
|
||||
(def transaction-info-value
|
||||
{:color "#000000de"
|
||||
:fontSize 14
|
||||
:lineHeight 20
|
||||
})
|
||||
|
||||
(def scroll-view-item
|
||||
{:flex 1
|
||||
:height 20
|
||||
:padding 6 })
|
||||
|
||||
(def carousel-container
|
||||
{:min-height 215
|
||||
:flex 1})
|
|
@ -0,0 +1,28 @@
|
|||
(ns status-im.transactions.subs
|
||||
(:require-macros [reagent.ratom :refer [reaction]])
|
||||
(:require [re-frame.core :refer [register-sub subscribe]]
|
||||
[clojure.string :as s]))
|
||||
|
||||
(register-sub :transactions
|
||||
(fn [db]
|
||||
(reaction (vals (:transactions @db)))))
|
||||
|
||||
(register-sub :contacts-by-address
|
||||
(fn [db]
|
||||
(reaction (into {} (map (fn [[_ {:keys [address] :as contact}]]
|
||||
[address contact])
|
||||
|
||||
(:contacts @db)
|
||||
)))))
|
||||
|
||||
(register-sub :contact-by-address
|
||||
(fn [_ [_ address]]
|
||||
(let [contacts (subscribe [:contacts-by-address])
|
||||
address' (when address
|
||||
(if (s/starts-with? address "0x")
|
||||
(subs address 2)
|
||||
address))]
|
||||
(reaction (@contacts address')))))
|
||||
|
||||
(register-sub :wrong-password?
|
||||
(fn [db] (reaction (:wrong-password? @db))))
|
|
@ -0,0 +1,49 @@
|
|||
(ns status-im.transactions.views.transaction-page
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[status-im.components.react :refer [view
|
||||
text
|
||||
image
|
||||
icon
|
||||
scroll-view
|
||||
touchable-highlight
|
||||
touchable-opacity]]
|
||||
[status-im.components.styles :refer [icon-ok
|
||||
icon-close]]
|
||||
[status-im.transactions.styles :as st]
|
||||
[status-im.i18n :refer [label label-pluralize]]
|
||||
cljsjs.web3))
|
||||
|
||||
(defn title-bar [title hash]
|
||||
[view st/title-bar
|
||||
[text {:style st/title-bar-text} title]
|
||||
[touchable-highlight {:style st/icon-close-container
|
||||
:on-press #(dispatch [:deny-transaction hash])}
|
||||
[view [image {:source {:uri :icon_close_gray}
|
||||
:style st/icon-close}]]]])
|
||||
|
||||
(defn transaction-info [index [name value]]
|
||||
[view {:style st/transaction-info-item
|
||||
:key index}
|
||||
[view {:style st/transaction-info-row}
|
||||
[view st/transaction-info-column-title
|
||||
[text {:style st/transaction-info-title} name]]
|
||||
[view st/transaction-info-column-value
|
||||
[text {:style st/transaction-info-value} value]]]])
|
||||
|
||||
(defview transaction-page [{:keys [hash from to value] :as transaction}]
|
||||
[{:keys [name] :as contact} [:contact-by-address to]]
|
||||
(let [eth-value (.fromWei js/Web3.prototype value "ether")
|
||||
title (str eth-value " ETH to " name)
|
||||
transactions-info [[(label :t/status) (label :t/pending-confirmation)]
|
||||
[(label :t/recipient) name]
|
||||
[(label :t/value) (str eth-value " ETH")]]]
|
||||
[view {:style st/transaction-page
|
||||
:key hash}
|
||||
[title-bar title hash]
|
||||
[view st/scroll-view-container
|
||||
[scroll-view {:style st/scroll-view
|
||||
:contentContainerStyle st/scroll-view-content
|
||||
:showsVerticalScrollIndicator true
|
||||
:scrollEnabled true}
|
||||
(map-indexed transaction-info transactions-info)]]]))
|
|
@ -160,9 +160,22 @@
|
|||
:login "Login"
|
||||
:wrong-password "Wrong password"
|
||||
|
||||
;users
|
||||
;accounts
|
||||
:add-account "Add account"
|
||||
|
||||
;validation
|
||||
:invalid-phone "Invalid phone number"
|
||||
:amount "Amount"
|
||||
:not-enough-eth (str "Not enough ETH on balance "
|
||||
"({{balance}} ETH)")
|
||||
;transactions
|
||||
:confirm-transactions {:one "Confirm transaction"
|
||||
:other "Confirm {{count}} transactions"
|
||||
:zero "No transactions"}
|
||||
:status "Status"
|
||||
:pending-confirmation "Pending confirmation"
|
||||
:recipient "Recipient"
|
||||
:one-more-item "One more item"
|
||||
:fee "Fee"
|
||||
:value "Value"
|
||||
})
|
||||
|
|
|
@ -4,15 +4,17 @@
|
|||
[cljs-time.format :refer [formatters
|
||||
formatter
|
||||
unparse]]
|
||||
[status-im.i18n :refer [label label-pluralize]]))
|
||||
[status-im.i18n :refer [label label-pluralize]]
|
||||
[goog.string :as gstring]
|
||||
goog.string.format))
|
||||
|
||||
(def hour (* 1000 60 60))
|
||||
(def day (* hour 24))
|
||||
(def week (* 7 day))
|
||||
(def units [{:name (label :t/datetime-second) :limit 60 :in-second 1}
|
||||
{:name (label :t/datetime-minute) :limit 3600 :in-second 60}
|
||||
{:name (label :t/datetime-hour) :limit 86400 :in-second 3600}
|
||||
{:name (label :t/datetime-day) :limit nil :in-second 86400}])
|
||||
(def units [{:name :t/datetime-second :limit 60 :in-second 1}
|
||||
{:name :t/datetime-minute :limit 3600 :in-second 60}
|
||||
{:name :t/datetime-hour :limit 86400 :in-second 3600}
|
||||
{:name :t/datetime-day :limit nil :in-second 86400}])
|
||||
|
||||
(def time-zone-offset (hours (- (/ (.getTimezoneOffset (js/Date.)) 60))))
|
||||
|
||||
|
@ -29,6 +31,10 @@
|
|||
(before? local today) (label :t/datetime-yesterday)
|
||||
:else (unparse (formatters :hour-minute) local))))
|
||||
|
||||
(defn format-time-ago [diff unit]
|
||||
(let [name (label-pluralize diff (:name unit))]
|
||||
(gstring/format "%s %s %s" diff name (label :t/datetime-ago))))
|
||||
|
||||
(defn time-ago [time]
|
||||
(let [diff (t/in-seconds (t/interval time (t/now)))]
|
||||
(if (< diff 60)
|
||||
|
@ -39,7 +45,7 @@
|
|||
(-> (/ diff (:in-second unit))
|
||||
Math/floor
|
||||
int
|
||||
(#(str % " " (label-pluralize % (:name unit)) " " (label :t/datetime-ago))))))))
|
||||
(format-time-ago unit))))))
|
||||
|
||||
(defn to-date [ms]
|
||||
(from-long ms))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
(ns status-im.utils.handlers
|
||||
(:require [re-frame.core :refer [after dispatch debug] :as re-core]))
|
||||
(:require [re-frame.core :refer [after dispatch debug] :as re-core]
|
||||
[re-frame.utils :refer [log]]))
|
||||
|
||||
(defn side-effect!
|
||||
"Middleware for handlers that will not affect db."
|
||||
|
@ -8,7 +9,18 @@
|
|||
(handler db params)
|
||||
db))
|
||||
|
||||
(defn debug-handlers-names
|
||||
"Middleware which logs debug information to js/console for each event.
|
||||
Includes a clojure.data/diff of the db, before vs after, showing the changes
|
||||
caused by the event."
|
||||
[handler]
|
||||
(fn debug-handler
|
||||
[db v]
|
||||
(log "Handling re-frame event: " (first v))
|
||||
(let [new-db (handler db v)]
|
||||
new-db)))
|
||||
|
||||
(defn register-handler
|
||||
([name handler] (register-handler name nil handler))
|
||||
([name middleware handler]
|
||||
(re-core/register-handler name [#_debug middleware] handler)))
|
||||
(re-core/register-handler name [debug-handlers-names middleware] handler)))
|
||||
|
|
Loading…
Reference in New Issue