Merge pull request #128 from status-im/feature/#123

Fetch/store commands.js

Former-commit-id: d00e6405c4
This commit is contained in:
Jarrad 2016-06-28 17:43:38 +02:00 committed by GitHub
commit 2daf477954
48 changed files with 962 additions and 459 deletions

View File

@ -1,7 +1,7 @@
{ {
"name": "StatusIm", "name": "StatusIm",
"interface": "reagent", "interface": "reagent",
"androidHost": "localhost", "androidHost": "10.0.3.2",
"modules": [ "modules": [
"react-native-contacts", "react-native-contacts",
"react-native-invertible-scroll-view", "react-native-invertible-scroll-view",
@ -17,6 +17,7 @@
"dismissKeyboard", "dismissKeyboard",
"react-native-linear-gradient", "react-native-linear-gradient",
"react-native-android-sms-listener", "react-native-android-sms-listener",
"react-native-status",
"react-native-camera", "react-native-camera",
"react-native-qrcode", "react-native-qrcode",
"react-native-orientation", "react-native-orientation",

View File

@ -131,9 +131,9 @@ dependencies {
compile project(':react-native-linear-gradient') compile project(':react-native-linear-gradient')
compile project(':ReactNativeAndroidSmsListener') compile project(':ReactNativeAndroidSmsListener')
compile project(':react-native-camera') compile project(':react-native-camera')
compile project(':react-native-status')
compile project(':react-native-orientation') compile project(':react-native-orientation')
// compile(name:'geth', ext:'aar') compile(group: 'status-im', name: 'status-go', version: '0.1.0-201606231357-85abe1', ext: 'aar')
compile(group: 'status-im', name: 'android-geth', version: '1.4.0-201604110816-a97a114', ext: 'aar')
compile fileTree(dir: "node_modules/realm/android/libs", include: ["*.jar"]) compile fileTree(dir: "node_modules/realm/android/libs", include: ["*.jar"])
} }
@ -143,3 +143,4 @@ task copyDownloadableDepsToLibs(type: Copy) {
from configurations.compile from configurations.compile
into 'libs' into 'libs'
} }

View File

@ -5,7 +5,6 @@ import android.content.Intent;
import android.os.Handler; import android.os.Handler;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.os.Messenger; import android.os.Messenger;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@ -14,7 +13,7 @@ import android.os.Environment;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import com.github.ethereum.go_ethereum.cmd.Geth; import com.github.status_im.status_go.Statusgo;
import java.io.File; import java.io.File;
@ -78,20 +77,11 @@ public class GethService extends Service {
extStore.getAbsolutePath() : extStore.getAbsolutePath() :
getApplicationInfo().dataDir; getApplicationInfo().dataDir;
final Runnable addPeer = new Runnable() {
public void run() {
Log.w("Geth", "adding peer");
Geth.run("--exec admin.addPeer(\"enode://e2f28126720452aa82f7d3083e49e6b3945502cb94d9750a15e27ee310eed6991618199f878e5fbc7dfa0e20f0af9554b41f491dc8f1dbae8f0f2d37a3a613aa@139.162.13.89:55555\") attach http://localhost:8545");
}
};
new Thread(new Runnable() { new Thread(new Runnable() {
public void run() { public void run() {
Geth.run("--shh --ipcdisable --nodiscover --rpc --rpcapi db,eth,net,web3,shh,admin --fast --datadir=" + dataFolder); Statusgo.doStartNode(dataFolder);
} }
}).start(); }).start();
handler.postDelayed(addPeer, 5000);
} }
public void signalEvent(String jsonEvent) { public void signalEvent(String jsonEvent) {
@ -107,8 +97,7 @@ public class GethService extends Service {
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
System.loadLibrary("gethraw"); System.loadLibrary("statusgo");
System.loadLibrary("geth");
if (!isGethInitialized) { if (!isGethInitialized) {
isGethInitialized = true; isGethInitialized = true;

View File

@ -32,6 +32,7 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.io.File; import java.io.File;
import com.statusim.Jail.JailPackage;
import com.lwansbrough.RCTCamera.*; import com.lwansbrough.RCTCamera.*;
import com.i18n.reactnativei18n.ReactNativeI18n; import com.i18n.reactnativei18n.ReactNativeI18n;
@ -176,6 +177,7 @@ public class MainActivity extends ReactActivity {
protected List<ReactPackage> getPackages() { protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList( return Arrays.<ReactPackage>asList(
new MainReactPackage(), new MainReactPackage(),
new JailPackage(),
new RealmReactPackage(), new RealmReactPackage(),
new VectorIconsPackage(), new VectorIconsPackage(),
new ReactNativeContacts(), new ReactNativeContacts(),

View File

@ -18,7 +18,11 @@ include ':react-native-linear-gradient'
project(':react-native-linear-gradient').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-linear-gradient/android') project(':react-native-linear-gradient').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-linear-gradient/android')
include ':ReactNativeAndroidSmsListener' include ':ReactNativeAndroidSmsListener'
project(':ReactNativeAndroidSmsListener').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-android-sms-listener/android') project(':ReactNativeAndroidSmsListener').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-android-sms-listener/android')
include ':react-native-status'
project(':react-native-status').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-status/android')
include ':react-native-camera' include ':react-native-camera'
project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android') project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android')
include ':react-native-orientation', ':app' include ':react-native-orientation', ':app'
project(':react-native-orientation').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-orientation/android') project(':react-native-orientation').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-orientation/android')

View File

@ -23,6 +23,7 @@
"react-native-randombytes": "^2.1.0", "react-native-randombytes": "^2.1.0",
"react-native-vector-icons": "^1.3.4", "react-native-vector-icons": "^1.3.4",
"react-native-orientation": "^1.17.0", "react-native-orientation": "^1.17.0",
"realm": "^0.11.1" "realm": "^0.11.1",
"react-native-status": "git+ssh://git@github.com/status-im/react-native-status"
} }
} }

178
resources/commands.js Normal file
View File

@ -0,0 +1,178 @@
status.command({
name: "location",
description: "Send location",
color: "#9a5dcf"
}).param({
name: "address",
type: status.types.STRING
});
var phones = [
{
number: "89171111111",
description: "Number format 1"
},
{
number: "89371111111",
description: "Number format 1"
},
{
number: "+79171111111",
description: "Number format 2"
},
{
number: "9171111111",
description: "Number format 3"
}
];
function suggestionsContainerStyle(suggestionsCount) {
return {
marginVertical: 1,
marginHorizontal: 0,
height: Math.min(150, (56 * suggestionsCount)),
backgroundColor: "white",
borderRadius: 5
};
}
var suggestionContainerStyle = {
paddingLeft: 16,
backgroundColor: "white"
};
var suggestionSubContainerStyle = {
height: 56,
borderBottomWidth: 1,
borderBottomColor: "#0000001f"
};
var valueStyle = {
marginTop: 9,
fontSize: 14,
fontFamily: "font",
color: "#000000de"
};
var descriptionStyle = {
marginTop: 1.5,
fontSize: 14,
fontFamily: "font",
color: "#838c93de"
};
function startsWith(str1, str2) {
// String.startsWith(...) doesn't work in otto
return str1.lastIndexOf(str2, 0) == 0 && str1 != str2;
}
function phoneSuggestions(params) {
var ph, suggestions;
if (!params.value || params.value == "") {
ph = phones;
} else {
ph = phones.filter(function (phone) {
return startsWith(phone.number, params.value);
});
}
if (ph.length == 0) {
return;
}
suggestions = ph.map(function (phone) {
return status.components.touchable(
{onPress: [status.events.SET_VALUE, phone.number]},
status.components.view(suggestionContainerStyle,
[status.components.view(suggestionSubContainerStyle,
[
status.components.text(
{style: valueStyle},
phone.number
),
status.components.text(
{style: descriptionStyle},
phone.description
)
])])
);
});
return status.components.scrollView(
suggestionsContainerStyle(ph.length),
suggestions
);
}
status.response({
name: "phone",
description: "Send phone number",
color: "#5fc48d",
params: [{
name: "phone",
type: status.types.PHONE_NUMBER,
suggestions: phoneSuggestions
}],
handler: function (params) {
return {
event: "sign-up",
params: [params.value]
};
}
});
status.command({
name: "help",
description: "Help",
color: "#7099e6",
params: [{
name: "query",
type: status.types.STRING
}]
});
status.response({
name: "confirmation-code",
color: "#7099e6",
description: "Confirmation code",
params: [{
name: "code",
type: status.types.NUMBER
}],
handler: function (params) {
return {
event: "confirm-sign-up",
params: [params.value]
};
}
});
status.response({
name: "keypair",
color: "#7099e6",
description: "Keypair password",
icon: "icon_lock_white",
params: [{
name: "password",
type: status.types.PASSWORD
}],
handler: function (params) {
return {
event: "save-password",
params: [params.value]
};
},
preview: function (params) {
return status.components.text(
{
style: {
marginTop: 5,
marginHorizontal: 0,
fontSize: 14,
fontFamily: "font",
color: "black"
}
}, "*****");
}
});

109
resources/status.js Normal file
View File

@ -0,0 +1,109 @@
var _status_catalog = {
commands: {},
responses: {}
};
function Command() {
}
function Response() {
}
Command.prototype.addToCatalog = function () {
_status_catalog.commands[this.name] = this;
};
Command.prototype.param = function (parameter) {
this.params.push(parameter);
return this;
};
Command.prototype.create = function (com) {
this.name = com.name;
this.description = com.description;
this.handler = com.handler;
this.color = com.color;
this.icon = com.icon;
this.params = com.params || [];
this.preview = com.preview;
this.addToCatalog();
return this;
};
Response.prototype = Object.create(Command.prototype);
Response.prototype.addToCatalog = function () {
_status_catalog.responses[this.name] = this;
};
Response.prototype.onReceiveResponse = function (handler) {
this.onReceive = handler;
};
function call(pathStr, paramsStr) {
var params = JSON.parse(paramsStr),
path = JSON.parse(pathStr),
fn, res;
fn = path.reduce(function (catalog, name) {
if (catalog && catalog[name]) {
return catalog[name];
}
},
_status_catalog
);
if(!fn) {
return null;
}
res = fn(params);
return JSON.stringify(res);
}
function text(options, s) {
return ['text', options, s];
}
function view(options, elements) {
return ['view', options].concat(elements);
}
function image(options) {
return ['image', options];
}
function touchable(options, element) {
return ['touchable', options, element];
}
function scrollView(options, elements) {
return ['scroll-view', options].concat(elements);
}
var status = {
command: function (n, d, h) {
var command = new Command();
return command.create(n, d, h);
},
response: function (n, d, h) {
var response = new Response();
return response.create(n, d, h);
},
types: {
STRING: 'string',
PHONE_NUMBER: 'phone-number',
PASSWORD: 'password'
},
events: {
SET_VALUE: 'set-value'
},
components: {
view: view,
text: text,
image: image,
touchable: touchable,
scrollView: scrollView
}
};

View File

@ -83,7 +83,6 @@
(dispatch [:load-user-phone-number]) (dispatch [:load-user-phone-number])
(dispatch [:load-contacts]) (dispatch [:load-contacts])
;; load commands from remote server (todo: uncomment) ;; load commands from remote server (todo: uncomment)
;; (dispatch [:load-commands])
(dispatch [:init-console-chat]) (dispatch [:init-console-chat])
(dispatch [:init-chat]) (dispatch [:init-chat])
(init-back-button-handler!) (init-back-button-handler!)

View File

@ -0,0 +1,6 @@
(ns status-im.chat.constants)
(def input-height 56)
(def request-info-height 61)
(def response-height-normal 211)
(def minimum-suggestion-height (+ input-height request-info-height))

View File

@ -3,7 +3,6 @@
[status-im.models.commands :as commands] [status-im.models.commands :as commands]
[clojure.string :as str] [clojure.string :as str]
[status-im.components.styles :refer [default-chat-color]] [status-im.components.styles :refer [default-chat-color]]
[status-im.chat.styles.response :refer [request-info-height response-height-normal]]
[status-im.chat.suggestions :as suggestions] [status-im.chat.suggestions :as suggestions]
[status-im.protocol.api :as api] [status-im.protocol.api :as api]
[status-im.models.messages :as messages] [status-im.models.messages :as messages]
@ -19,8 +18,8 @@
[status-im.handlers.content-suggestions :refer [get-content-suggestions]] [status-im.handlers.content-suggestions :refer [get-content-suggestions]]
[status-im.utils.phone-number :refer [format-phone-number]] [status-im.utils.phone-number :refer [format-phone-number]]
[status-im.utils.datetime :as time] [status-im.utils.datetime :as time]
[status-im.chat.handlers.animation :refer [update-response-height [status-im.components.jail :as j]
get-response-height]])) [status-im.commands.utils :refer [generate-hiccup]]))
(register-handler :set-show-actions (register-handler :set-show-actions
(fn [db [_ show-actions]] (fn [db [_ show-actions]]
@ -44,35 +43,64 @@
(assoc-in [:chats current-chat-id :command-input] {}) (assoc-in [:chats current-chat-id :command-input] {})
(update-in [:chats current-chat-id :input-text] safe-trim)))) (update-in [:chats current-chat-id :input-text] safe-trim))))
(defn invoke-suggestions-handler!
[{:keys [current-chat-id] :as db} _]
(let [{:keys [command content]} (get-in db [:chats current-chat-id :command-input])
{:keys [name type]} command
path [(if (= :command type) :commands :responses)
name
:params
0
:suggestions]
params {:value content}]
(j/call current-chat-id
path
params
#(dispatch [:suggestions-handler {:command command
:content content
:chat-id current-chat-id} %]))))
(register-handler :start-cancel-command (register-handler :start-cancel-command
(u/side-effect! (u/side-effect!
(fn [db _] (fn [db _]
(dispatch [:animate-cancel-command])))) (dispatch [:animate-cancel-command]))))
(register-handler :set-chat-command-content (register-handler :set-chat-command-content
[(after invoke-suggestions-handler!)]
(fn [{:keys [current-chat-id] :as db} [_ content]] (fn [{:keys [current-chat-id] :as db} [_ content]]
(as-> db db (as-> db db
(commands/set-chat-command-content db content) (commands/set-chat-command-content db content)
(assoc-in db [:chats current-chat-id :input-text] nil) (assoc-in db [:chats current-chat-id :input-text] nil))))
(if (commands/get-chat-command-to-msg-id db)
(update-response-height db)
db))))
(defn update-input-text (defn update-input-text
[{:keys [current-chat-id] :as db} text] [{:keys [current-chat-id] :as db} text]
(assoc-in db [:chats current-chat-id :input-text] text)) (assoc-in db [:chats current-chat-id :input-text] text))
(defn invoke-command-preview!
[{:keys [current-chat-id staged-command]} _]
(let [{:keys [command content]} staged-command
{:keys [name type]} command
path [(if (= :command type) :commands :responses)
name
:preview]
params {:value content}]
(j/call current-chat-id
path
params
#(dispatch [:command-preview current-chat-id %]))))
(register-handler :stage-command (register-handler :stage-command
(after invoke-command-preview!)
(fn [{:keys [current-chat-id] :as db} _] (fn [{:keys [current-chat-id] :as db} _]
(let [db (update-input-text db nil) (let [db (update-input-text db nil)
{:keys [command content]} {:keys [command content]}
(get-in db [:chats current-chat-id :command-input]) (get-in db [:chats current-chat-id :command-input])
command-info {:command command command-info {:command command
:content content :content content}]
:handler (:handler command)}]
(-> db (-> db
(assoc-in [:chats current-chat-id :command-input :command] nil) ;(assoc-in [:chats current-chat-id :command-input :command] nil)
(commands/stage-command command-info))))) (commands/stage-command command-info)
(assoc :staged-command command-info)))))
(register-handler :set-message-input [] (register-handler :set-message-input []
(fn [db [_ input]] (fn [db [_ input]]
@ -85,8 +113,10 @@
(.blur message-input))))) (.blur message-input)))))
(register-handler :set-response-chat-command (register-handler :set-response-chat-command
[(after #(dispatch [:command-edit-mode])) [(after invoke-suggestions-handler!)
(after #(dispatch [:animate-show-response]))] (after #(dispatch [:command-edit-mode]))
;(after #(dispatch [:animate-show-response]))
]
(fn [db [_ to-msg-id command-key]] (fn [db [_ to-msg-id command-key]]
(commands/set-response-chat-command db to-msg-id command-key))) (commands/set-response-chat-command db to-msg-id command-key)))
@ -143,8 +173,8 @@
(defn prepare-message (defn prepare-message
[{:keys [identity current-chat-id] :as db} _] [{:keys [identity current-chat-id] :as db} _]
(let [text (get-in db [:chats current-chat-id :input-text]) (let [text (get-in db [:chats current-chat-id :input-text])
{:keys [command]} (suggestions/check-suggestion db (str text " ")) [command] (suggestions/check-suggestion db (str text " "))
message (check-author-direction message (check-author-direction
db current-chat-id db current-chat-id
{:msg-id (random/id) {:msg-id (random/id)
@ -159,17 +189,18 @@
(commands/set-chat-command db command) (commands/set-chat-command db command)
(assoc db :new-message (when-not (str/blank? text) message))))) (assoc db :new-message (when-not (str/blank? text) message)))))
(defn prepare-command [identity chat-id staged-command] (defn prepare-command
(let [command-key (get-in staged-command [:command :command]) [identity chat-id {:keys [preview preview-string content command]}]
content {:command (name command-key) (let [content {:command (command :name)
:content (:content staged-command)}] :content content}]
{:msg-id (random/id) {:msg-id (random/id)
:from identity :from identity
:to chat-id :to chat-id
:content content :content content
:content-type content-type-command :content-type content-type-command
:outgoing true :outgoing true
:handler (:handler staged-command)})) :preview preview-string
:rendered-preview preview}))
(defn prepare-staged-commans (defn prepare-staged-commans
[{:keys [current-chat-id identity] :as db} _] [{:keys [current-chat-id identity] :as db} _]
@ -222,7 +253,22 @@
(defn save-commands-to-realm! (defn save-commands-to-realm!
[{:keys [new-commands current-chat-id]} _] [{:keys [new-commands current-chat-id]} _]
(doseq [new-command new-commands] (doseq [new-command new-commands]
(messages/save-message current-chat-id (dissoc new-command :handler)))) (messages/save-message current-chat-id
(dissoc new-command :rendered-preview))))
(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 %])))))
(defn handle-commands (defn handle-commands
[{:keys [new-commands]}] [{:keys [new-commands]}]
@ -241,6 +287,8 @@
((after send-message!)) ((after send-message!))
((after save-message-to-realm!)) ((after save-message-to-realm!))
((after save-commands-to-realm!)) ((after save-commands-to-realm!))
;; todo maybe it is better to track if it was handled or not
((after invoke-commands-handlers!))
((after handle-commands)))) ((after handle-commands))))
(register-handler :unstage-command (register-handler :unstage-command
@ -249,7 +297,8 @@
(register-handler :set-chat-command (register-handler :set-chat-command
[(after #(dispatch [:command-edit-mode])) [(after #(dispatch [:command-edit-mode]))
(after #(dispatch [:animate-show-response]))] ;(after #(dispatch [:animate-show-response]))
]
(fn [db [_ command-key]] (fn [db [_ command-key]]
(commands/set-chat-command db command-key))) (commands/set-chat-command db command-key)))
@ -294,9 +343,14 @@
([{:keys [messages current-chat-id] :as db} _] ([{:keys [messages current-chat-id] :as db} _]
(assoc-in db [:chats current-chat-id :messages] messages))) (assoc-in db [:chats current-chat-id :messages] messages)))
(defn load-commands!
[{:keys [current-chat-id]}]
(dispatch [:load-commands! current-chat-id]))
(register-handler :init-chat (register-handler :init-chat
(-> load-messages! (-> load-messages!
((enrich init-chat)) ((enrich init-chat))
((after load-commands!))
debug)) debug))
(defn initialize-chats (defn initialize-chats
@ -340,9 +394,9 @@
(defmethod nav/preload-data! :chat (defmethod nav/preload-data! :chat
[{:keys [current-chat-id] :as db} [_ _ id]] [{:keys [current-chat-id] :as db} [_ _ id]]
(let [chat-id (or id current-chat-id) (let [chat-id (or id current-chat-id)
messages (get-in db [:chats chat-id :messages]) messages (get-in db [:chats chat-id :messages])
db' (assoc db :current-chat-id chat-id)] db' (assoc db :current-chat-id chat-id)]
(if (seq messages) (if (seq messages)
db' db'
(-> db' (-> db'

View File

@ -1,14 +1,13 @@
(ns status-im.chat.handlers.animation (ns status-im.chat.handlers.animation
(:require [re-frame.core :refer [register-handler after dispatch]] (:require [re-frame.core :refer [register-handler after dispatch debug]]
[re-frame.middleware :refer [path]] [re-frame.middleware :refer [path]]
[status-im.models.commands :as commands]
[status-im.handlers.content-suggestions :refer [get-content-suggestions]] [status-im.handlers.content-suggestions :refer [get-content-suggestions]]
[status-im.chat.styles.message-input :refer [input-height]] [status-im.chat.constants :refer [input-height request-info-height
[status-im.chat.styles.response :refer [request-info-height response-height-normal]] response-height-normal minimum-suggestion-height]]
[status-im.chat.styles.response-suggestions :as response-suggestions-styles]
[status-im.constants :refer [response-input-hiding-duration]])) [status-im.constants :refer [response-input-hiding-duration]]))
(def zero-height input-height) ;; todo magic value
(def middle-height 270)
(defn animation-handler (defn animation-handler
([name handler] (animation-handler name nil handler)) ([name handler] (animation-handler name nil handler))
@ -19,25 +18,21 @@
(after #(dispatch [:text-edit-mode])) (after #(dispatch [:text-edit-mode]))
(fn [db _] (fn [db _]
(assoc db (assoc db
:to-response-height zero-height :to-response-height input-height
:messages-offset 0))) :messages-offset 0)))
(defn get-response-height [db] (defn get-response-height
(let [command (commands/get-chat-command db) [{:keys [current-chat-id] :as db}]
text (commands/get-chat-command-content db) (let [suggestions (get-in db [:suggestions current-chat-id])
suggestions (get-content-suggestions command text) suggestions-height (if suggestions middle-height 0)]
suggestions-height (reduce + 0 (map #(if (:header %) (+ input-height
response-suggestions-styles/header-height
response-suggestions-styles/suggestion-height)
suggestions))]
(+ zero-height
(min response-height-normal (+ suggestions-height request-info-height))))) (min response-height-normal (+ suggestions-height request-info-height)))))
(defn update-response-height [db] (defn update-response-height [db]
(assoc-in db [:animations :to-response-height] (get-response-height db))) (assoc-in db [:animations :to-response-height] (get-response-height db)))
(register-handler :animate-show-response (register-handler :animate-show-response
(after #(dispatch [:command-edit-mode])) [(after #(dispatch [:command-edit-mode]))]
(fn [db _] (fn [db _]
(-> db (-> db
(assoc-in [:animations :messages-offset] request-info-height) (assoc-in [:animations :messages-offset] request-info-height)
@ -54,26 +49,28 @@
db)))) db))))
(register-handler :fix-response-height (register-handler :fix-response-height
(fn [db [_ vy current]] (fn [{:keys [current-chat-id] :as db} [_ vy current]]
(let [max-height (get-in db [:animations :response-height-max]) (let [max-height (get-in db [:animations :response-height-max])
;; todo magic value
middle 270
moving-down? (pos? vy) moving-down? (pos? vy)
moving-up? (not moving-down?) moving-up? (not moving-down?)
under-middle-position? (<= current middle) under-middle-position? (<= current middle-height)
over-middle-position? (not under-middle-position?) over-middle-position? (not under-middle-position?)
min-height (+ zero-height request-info-height) suggestions (get-in db [:suggestions current-chat-id])
new-fixed (cond (and under-middle-position? moving-down?) new-fixed (cond (not suggestions)
min-height minimum-suggestion-height
(and under-middle-position? moving-up?) (and under-middle-position? moving-up?)
middle middle-height
(and over-middle-position? moving-down?) (and over-middle-position? moving-down?)
middle middle-height
(and over-middle-position? moving-up?) (and over-middle-position? moving-up?)
max-height)] max-height
(and under-middle-position?
moving-down?)
minimum-suggestion-height)]
(-> db (-> db
(assoc-in [:animations :to-response-height] new-fixed) (assoc-in [:animations :to-response-height] new-fixed)
(update-in [:animations :response-height-changed] inc))))) (update-in [:animations :response-height-changed] inc)))))

View File

@ -18,7 +18,6 @@
[status-im.components.invertible-scroll-view :refer [invertible-scroll-view]] [status-im.components.invertible-scroll-view :refer [invertible-scroll-view]]
[status-im.components.toolbar :refer [toolbar]] [status-im.components.toolbar :refer [toolbar]]
[status-im.chat.views.message :refer [chat-message]] [status-im.chat.views.message :refer [chat-message]]
[status-im.chat.views.content-suggestions :refer [content-suggestions-view]]
[status-im.chat.views.suggestions :refer [suggestions-view]] [status-im.chat.views.suggestions :refer [suggestions-view]]
[status-im.chat.views.response :refer [response-view]] [status-im.chat.views.response :refer [response-view]]
[status-im.chat.views.new-message :refer [chat-message-new]] [status-im.chat.views.new-message :refer [chat-message-new]]

View File

@ -173,7 +173,7 @@
(dispatch [:received-msg (dispatch [:received-msg
{:msg-id msg-id {:msg-id msg-id
:content (command-content :content (command-content
:keypair-password :keypair
(label :t/keypair-generated)) (label :t/keypair-generated))
:content-type content-type-command-request :content-type content-type-command-request
:outgoing false :outgoing false
@ -184,6 +184,9 @@
(def console-chat (def console-chat
{:chat-id "console" {:chat-id "console"
:name "console" :name "console"
; todo remove/change dapp config fot console
:dapp-url "http://localhost:8185/resources"
:dapp-hash 858845357
:color default-chat-color :color default-chat-color
:group-chat false :group-chat false
:is-active true :is-active true

View File

@ -1,22 +1,21 @@
(ns status-im.chat.styles.content-suggestions (ns status-im.chat.styles.content-suggestions
(:require [status-im.components.styles :refer [font (:require [status-im.components.styles :refer [font
color-light-blue-transparent color-light-blue-transparent
color-white color-white
color-black color-black
color-blue color-blue
color-blue-transparent color-blue-transparent
selected-message-color selected-message-color
online-color online-color
separator-color separator-color
text1-color text1-color
text2-color text2-color
text3-color]])) text3-color]]))
(def suggestion-height 56) (def suggestion-height 56)
(def suggestion-container (def suggestion-container
{:flexDirection :column {:paddingLeft 16
:paddingLeft 16
:backgroundColor color-white}) :backgroundColor color-white})
(def suggestion-sub-container (def suggestion-sub-container
@ -37,7 +36,7 @@
:color text2-color}) :color text2-color})
(defn suggestions-container [suggestions-count] (defn suggestions-container [suggestions-count]
{:flexDirection :row {:flex 1
:marginVertical 1 :marginVertical 1
:marginHorizontal 0 :marginHorizontal 0
:height (min 150 (* suggestion-height suggestions-count)) :height (min 150 (* suggestion-height suggestions-count))

View File

@ -1,15 +1,15 @@
(ns status-im.chat.styles.message (ns status-im.chat.styles.message
(:require [status-im.components.styles :refer [font (:require [status-im.components.styles :refer [font
color-light-blue-transparent color-light-blue-transparent
color-white color-white
color-black color-black
color-blue color-blue
selected-message-color selected-message-color
online-color online-color
text1-color text1-color
text2-color]] text2-color]]
[status-im.constants :refer [text-content-type [status-im.constants :refer [text-content-type
content-type-command]])) content-type-command]]))
(def style-message-text (def style-message-text
{:fontSize 14 {:fontSize 14
@ -153,6 +153,14 @@
:backgroundColor (:color command) :backgroundColor (:color command)
:transform [{:scale scale}]}) :transform [{:scale scale}]})
(def command-image-view
{:position :absolute
:top 0
:right 0
:width 24
:height 24
:alignItems :center})
(def command-request-image (def command-request-image
{:position :absolute {:position :absolute
:top 9 :top 9
@ -185,11 +193,10 @@
:color color-white}) :color color-white})
(def command-image (def command-image
{:position :absolute {:margin-top 5
:top 4 :width 12
:right 0 :height 13
:width 12 :tint-color :#a9a9a9cc})
:height 13})
(def command-text (def command-text
(merge style-message-text (merge style-message-text

View File

@ -1,8 +1,7 @@
(ns status-im.chat.styles.message-input (ns status-im.chat.styles.message-input
(:require [status-im.components.styles :refer [color-white (:require [status-im.components.styles :refer [color-white
color-blue]])) color-blue]]
[status-im.chat.constants :refer [input-height]]))
(def input-height 56)
(def message-input-container (def message-input-container
{:flex 1 {:flex 1

View File

@ -6,10 +6,8 @@
text2-color text2-color
chat-background chat-background
color-black]] color-black]]
[status-im.chat.styles.message-input :refer [input-height]])) [status-im.chat.constants :refer [input-height request-info-height
response-height-normal]]))
(def response-height-normal 211)
(def request-info-height 61)
(def drag-container (def drag-container
{:height 16 {:height 16

View File

@ -1,59 +0,0 @@
(ns status-im.chat.styles.response-suggestions
(:require [status-im.components.styles :refer [font
font-medium
color-light-blue-transparent
color-white
color-black
color-blue
color-blue-transparent
selected-message-color
online-color
separator-color
text1-color
text2-color
text3-color]]))
(def header-height 50)
(def suggestion-height 56)
(def header-container
{:paddingLeft 16
:height header-height
:backgroundColor color-white})
(def header-text
{:marginTop 18
:fontSize 13
:fontFamily font-medium
:color text2-color})
(def suggestion-container
{:flexDirection :column
:paddingLeft 16
:height suggestion-height
:backgroundColor color-white})
(def suggestion-sub-container
{:height suggestion-height
:borderBottomWidth 1
:borderBottomColor separator-color})
(def value-text
{:marginTop 10
:fontSize 12
:fontFamily font
:color text1-color})
(def description-text
{:marginTop 2
:fontSize 12
:fontFamily font
:color text2-color})
(def suggestions-container
{:flexDirection :row
:flex 1
:marginVertical 1
:marginHorizontal 0
:backgroundColor color-white
:borderRadius 5})

View File

@ -1,15 +1,15 @@
(ns status-im.chat.subs (ns status-im.chat.subs
(:require-macros [reagent.ratom :refer [reaction]]) (:require-macros [reagent.ratom :refer [reaction]])
(:require [re-frame.core :refer [register-sub dispatch subscribe]] (:require [re-frame.core :refer [register-sub dispatch subscribe path]]
[status-im.db :as db] [status-im.db :as db]
;todo handlers in subs?...
[status-im.chat.suggestions :refer [status-im.chat.suggestions :refer
[get-suggestions typing-command?]] [get-suggestions typing-command?]]
[status-im.models.commands :as commands] [status-im.models.commands :as commands]
[status-im.constants :refer [response-suggesstion-resize-duration]] [status-im.constants :refer [response-suggesstion-resize-duration]]
[status-im.handlers.content-suggestions :refer [get-content-suggestions]] [status-im.handlers.content-suggestions :refer [get-content-suggestions]]
[status-im.chat.views.plain-message :as plain-message] [status-im.chat.views.plain-message :as plain-message]
[status-im.chat.views.command :as command])) [status-im.chat.views.command :as command]
[status-im.chat.constants :as c]))
(register-sub :chat-properties (register-sub :chat-properties
(fn [db [_ properties]] (fn [db [_ properties]]
@ -53,6 +53,18 @@
(fn [db _] (fn [db _]
(reaction (commands/get-commands @db)))) (reaction (commands/get-commands @db))))
(register-sub :get-responses
(fn [db _]
(let [current-chat (@db :current-chat-id)]
(reaction (or (get-in @db [:chats current-chat :responses]) {})))))
(register-sub :get-commands-and-responses
(fn [db _]
(let [current-chat (@db :current-chat-id)]
(reaction _ (or (->> (get-in @db [:chats current-chat])
((juxt :commands :responses))
(apply merge)) {})))))
(register-sub :get-chat-input-text (register-sub :get-chat-input-text
(fn [db _] (fn [db _]
(->> [:chats (:current-chat-id @db) :input-text] (->> [:chats (:current-chat-id @db) :input-text]
@ -108,12 +120,10 @@
(register-sub :get-content-suggestions (register-sub :get-content-suggestions
(fn [db _] (fn [db _]
(let [command (reaction (commands/get-chat-command @db)) (reaction (get-in @db [:suggestions (:current-chat-id @db)]))))
text (reaction (commands/get-chat-command-content @db))]
(reaction (get-content-suggestions @command @text)))))
(register-sub :command? (register-sub :command?
(fn [db ] (fn [db]
(->> (get-in @db [:edit-mode (:current-chat-id @db)]) (->> (get-in @db [:edit-mode (:current-chat-id @db)])
(= :command) (= :command)
(reaction)))) (reaction))))

View File

@ -1,23 +1,26 @@
(ns status-im.chat.suggestions (ns status-im.chat.suggestions
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
[status-im.db :as db] [status-im.db :as db]
[status-im.models.commands :refer [commands [status-im.models.commands :refer [get-commands
suggestions get-chat-command-request
get-commands get-chat-command-to-msg-id
get-chat-command-request clear-staged-commands]]
get-chat-command-to-msg-id
clear-staged-commands]]
[status-im.utils.utils :refer [log on-error http-get]] [status-im.utils.utils :refer [log on-error http-get]]
[clojure.string :as s])) [clojure.string :as s]))
(defn suggestion? [text] (defn suggestion? [text]
(= (get text 0) "!")) (= (get text 0) "!"))
(defn get-suggestions [db text] (defn can-be-suggested? [text]
(if (suggestion? text) (fn [{:keys [name]}]
;; TODO change 'commands' to 'suggestions' (.startsWith (str "!" name) text)))
(filterv #(.startsWith (:text %) text) (get-commands db))
[])) (defn get-suggestions
[{:keys [current-chat-id] :as db} text]
(let [commands (get-in db [:chats current-chat-id :commands])]
(if (suggestion? text)
(filter (fn [[_ v]] ((can-be-suggested? text) v)) commands)
[])))
(defn get-command [db text] (defn get-command [db text]
(when (suggestion? text) (when (suggestion? text)
@ -45,22 +48,13 @@
staged-commands)) staged-commands))
(clear-staged-commands db))) (clear-staged-commands db)))
(defn execute-commands-js [body]
(.eval js/window body)
(let [commands (.-commands js/window)]
(dispatch [:set-commands (map #(update % :command keyword)
(js->clj commands :keywordize-keys true))])))
(defn load-commands []
(http-get "chat-commands.js" execute-commands-js nil))
(defn check-suggestion [db message] (defn check-suggestion [db message]
(when-let [suggestion-text (when (string? message) (when-let [suggestion-text (when (string? message)
(re-matches #"^![^\s]+\s" message))] (re-matches #"^![^\s]+\s" message))]
(let [suggestion-text' (s/trim suggestion-text) (let [suggestion-text' (s/trim suggestion-text)]
[suggestion] (filter #(= suggestion-text' (:text %)) (->> (get-commands db)
(get-commands db))] (filter #(= suggestion-text' (->> % second :name (str "!"))))
suggestion))) first))))
(defn typing-command? [db] (defn typing-command? [db]
(-> db (-> db

View File

@ -35,3 +35,4 @@
[touchable-highlight {:on-press cancel-command-input} [touchable-highlight {:on-press cancel-command-input}
[view st/cancel-container [view st/cancel-container
[icon :close-gray st/cancel-icon]]]) [icon :close-gray st/cancel-icon]]])

View File

@ -1,37 +0,0 @@
(ns status-im.chat.views.content-suggestions
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch]]
[status-im.components.react :refer [view
icon
text
touchable-highlight
list-view
list-item]]
[status-im.chat.styles.content-suggestions :as st]
[status-im.utils.listview :refer [to-datasource]]))
(defn set-command-content [content]
(dispatch [:set-chat-command-content content]))
(defn suggestion-list-item [{:keys [value description]}]
[touchable-highlight {:onPress #(set-command-content value)}
[view st/suggestion-container
[view st/suggestion-sub-container
[text {:style st/value-text} value]
[text {:style st/description-text} description]]]])
(defn render-row [row _ _]
(list-item [suggestion-list-item row]))
(defview content-suggestions-view []
[suggestions [:get-content-suggestions]]
(when-let [values (not-empty (filter :value suggestions))]
[view st/container
[touchable-highlight {:style st/drag-down-touchable
;; TODO hide suggestions?
:onPress (fn [])}
[view [icon :drag_down st/drag-down-icon]]]
[view (st/suggestions-container (count values))
[list-view {:dataSource (to-datasource values)
:keyboardShouldPersistTaps true
:renderRow render-row}]]]))

View File

@ -1,11 +1,12 @@
(ns status-im.chat.views.message (ns status-im.chat.views.message
(:require-macros [status-im.utils.views :refer [defview]])
(:require [clojure.string :as s] (:require [clojure.string :as s]
[re-frame.core :refer [subscribe dispatch]] [re-frame.core :refer [subscribe dispatch]]
[reagent.core :as r] [reagent.core :as r]
[status-im.components.react :refer [view [status-im.components.react :refer [view
animated-view
text text
image image
animated-view
touchable-highlight]] touchable-highlight]]
[status-im.components.animation :as anim] [status-im.components.animation :as anim]
[status-im.chat.views.request-message :refer [message-content-command-request]] [status-im.chat.views.request-message :refer [message-content-command-request]]
@ -55,24 +56,48 @@
[view st/track-mark] [view st/track-mark]
[text {:style st/track-duration-text} "03:39"]]]) [text {:style st/track-duration-text} "03:39"]]])
(defn message-content-command [content] (defview message-content-command [content preview]
(let [commands-atom (subscribe [:get-commands])] [commands [:get-commands-and-responses]]
(fn [content] (let [{:keys [command content]} (parse-command-msg-content commands content)
(let [commands @commands-atom {:keys [name icon type]} command]
{:keys [command content]} [view st/content-command-view
(parse-command-msg-content commands content)] [view st/command-container
[view st/content-command-view [view (st/command-view command)
[view st/command-container [text {:style st/command-name}
[view (st/command-view command) (str (if (= :command type) "!" "") name)]]]
[text {:style st/command-name} (when icon
(:text command)]]] [view st/command-image-view
[image {:source (:icon command) [image {:source {:uri icon}
:style st/command-image}] :style st/command-image}]])
[text {:style st/command-text} (if preview
;; TODO isn't smart preview
(if (= (:command command) :keypair-password) [text {:style st/command-text} content])]))
"******"
content)]])))) (defn set-chat-command [msg-id command]
(dispatch [:set-response-chat-command msg-id (keyword (:name command))]))
(defn label [{:keys [command]}]
(->> (when command (name command))
(str "request-")))
;; todo remove (merging leftover)
#_(defview message-content-command-request
[{:keys [msg-id content from incoming-group]}]
[commands [:get-responses]]
(let [{:keys [command content]} (parse-command-request commands content)]
[touchable-highlight {:onPress #(set-chat-command msg-id command)
:accessibility-label (label command)}
[view st/comand-request-view
[view st/command-request-message-view
(when incoming-group
[text {:style st/command-request-from-text} from])
[text {:style st/style-message-text} content]]
[view (st/command-request-image-view command)
[image {:source {:uri (:icon command)}
:style st/command-request-image}]]
(when-let [request-text (:request-text command)]
[view st/command-request-text-view
[text {:style st/style-sub-text} request-text]])]]))
(defn message-view (defn message-view
[message content] [message content]
@ -103,9 +128,9 @@
[message-content-status message]) [message-content-status message])
(defmethod message-content content-type-command (defmethod message-content content-type-command
[wrapper {:keys [content] :as message}] [wrapper {:keys [content rendered-preview] :as message}]
[wrapper message [wrapper message
[message-view message [message-content-command content]]]) [message-view message [message-content-command content rendered-preview]]])
(defmethod message-content :default (defmethod message-content :default
[wrapper {:keys [content-type content] :as message}] [wrapper {:keys [content-type content] :as message}]

View File

@ -6,7 +6,6 @@
icon icon
touchable-highlight touchable-highlight
text-input]] text-input]]
[status-im.components.animation :as anim]
[status-im.chat.views.plain-message :as plain-message] [status-im.chat.views.plain-message :as plain-message]
[status-im.chat.views.command :as command] [status-im.chat.views.command :as command]
[status-im.chat.styles.message-input :as st] [status-im.chat.styles.message-input :as st]

View File

@ -24,11 +24,12 @@
(case (:command command) (case (:command command)
:phone {:input-options {:keyboardType :phone-pad} :phone {:input-options {:keyboardType :phone-pad}
:validator valid-mobile-number?} :validator valid-mobile-number?}
:keypair-password {:input-options {:secureTextEntry true}} :keypair {:input-options {:secureTextEntry true}}
:confirmation-code {:input-options {:keyboardType :numeric}} :confirmation-code {:input-options {:keyboardType :numeric}}
:money {:input-options {:keyboardType :numeric}} :money {:input-options {:keyboardType :numeric}}
:request {:input-options {:keyboardType :numeric}} :request {:input-options {:keyboardType :numeric}}
(throw (js/Error. "Uknown command type"))))]) ;; todo maybe nil is finr for now :)
nil #_(throw (js/Error. "Uknown command type"))))])
(defview chat-message-new [] (defview chat-message-new []
[staged-commands [:get-chat-staged-commands]] [staged-commands [:get-chat-staged-commands]]

View File

@ -24,15 +24,16 @@
(defn button-animation-logic [{:keys [command? val]}] (defn button-animation-logic [{:keys [command? val]}]
(fn [_] (fn [_]
(let [to-scale (if @command? 0 1)] (let [to-scale (if @command? 0 1)]
(anim/start (anim/spring val {:toValue to-scale}))))) (anim/start (anim/spring val {:toValue to-scale
:tension 30})))))
(defn list-container [min] (defn list-container [min]
(fn [{:keys [command? width]}] (fn [{:keys [command? width]}]
(let [n-width (if @command? min 56) (let [n-width (if @command? min 56)
delay (if @command? 100 0)] delay (if @command? 100 0)]
(anim/start (anim/timing width {:toValue n-width (anim/start (anim/timing width {:toValue n-width
:duration response-input-hiding-duration :duration response-input-hiding-duration
:delay delay}))))) :delay delay})))))
(defn commands-button [] (defn commands-button []
(let [command? (subscribe [:command?]) (let [command? (subscribe [:command?])
@ -62,19 +63,20 @@
(fn [_] (fn [_]
(let [to-scale (if @command? 0 1)] (let [to-scale (if @command? 0 1)]
(when-not @command? (anim/set-value width 56)) (when-not @command? (anim/set-value width 56))
(anim/start (anim/spring val {:toValue to-scale}) (anim/start (anim/spring val {:toValue to-scale
:tension 30})
(fn [e] (fn [e]
(when (and @command? (.-finished e)) (when (and @command? (.-finished e))
(anim/set-value width 0.1))))))) (anim/set-value width 0.1)))))))
(defn smile-button [] (defn smile-button []
(let [command? (subscribe [:command?]) (let [command? (subscribe [:command?])
buttons-scale (anim/create-value (if @command? 1 0)) buttons-scale (anim/create-value (if @command? 1 0))
container-width (anim/create-value (if @command? 0.1 56)) container-width (anim/create-value (if @command? 0.1 56))
context {:command? command? context {:command? command?
:val buttons-scale :val buttons-scale
:width container-width} :width container-width}
on-update (smile-animation-logic context)] on-update (smile-animation-logic context)]
(r/create-class (r/create-class
{:component-did-mount {:component-did-mount
on-update on-update

View File

@ -13,7 +13,7 @@
(def request-message-icon-scale-delay 600) (def request-message-icon-scale-delay 600)
(defn set-chat-command [msg-id command] (defn set-chat-command [msg-id command]
(dispatch [:set-response-chat-command msg-id (:command command)])) (dispatch [:set-response-chat-command msg-id (keyword (:name command))]))
(defn label [{:keys [command]}] (defn label [{:keys [command]}]
(->> (name command) (->> (name command)
@ -56,18 +56,19 @@
:reagent-render :reagent-render
(fn [msg-id command] (fn [msg-id command]
@to-scale @to-scale
[touchable-highlight {:on-press (fn [] [touchable-highlight {:on-press (fn []
(reset! loop? false) (reset! loop? false)
(set-chat-command msg-id command)) (set-chat-command msg-id command))
:style st/command-request-image-touchable :style st/command-request-image-touchable}
:accessibility-label (label command)} ;:accessibility-label (label command)
[animated-view {:style (st/command-request-image-view command scale-anim-val)} [animated-view {:style (st/command-request-image-view command scale-anim-val)}
[image {:source (:request-icon command) [image {:source {:uri (:icon command)}
:style st/command-request-image}]]])}))) :style st/command-request-image}]]])})))
(defn message-content-command-request (defn message-content-command-request
[{:keys [msg-id content from incoming-group]}] [{:keys [msg-id content from incoming-group]}]
(let [commands-atom (subscribe [:get-commands])] (let [commands-atom (subscribe [:get-responses])]
(fn [{:keys [msg-id content from incoming-group]}] (fn [{:keys [msg-id content from incoming-group]}]
(let [commands @commands-atom (let [commands @commands-atom
{:keys [command content]} (parse-command-request commands content)] {:keys [command content]} (parse-command-request commands content)]

View File

@ -11,9 +11,7 @@
text-input text-input
touchable-highlight]] touchable-highlight]]
[status-im.components.drag-drop :as drag] [status-im.components.drag-drop :as drag]
[status-im.chat.views.response-suggestions :refer [response-suggestions-view]]
[status-im.chat.styles.response :as st] [status-im.chat.styles.response :as st]
[status-im.chat.styles.message-input :refer [input-height]]
[status-im.components.animation :as anim] [status-im.components.animation :as anim]
[status-im.components.react :as react])) [status-im.components.react :as react]))
@ -51,7 +49,6 @@
;; todo maybe it is better to use margin-top instead height ;; todo maybe it is better to use margin-top instead height
;; it is not obvious ;; it is not obvious
to-value (- (prop w) @kb-height (.-moveY gesture))] to-value (- (prop w) @kb-height (.-moveY gesture))]
(println to-value )
(anim/start (anim/start
(anim/spring response-height {:toValue to-value})))))) (anim/spring response-height {:toValue to-value}))))))
@ -88,7 +85,9 @@
(defn container-animation-logic [{:keys [to-value val]}] (defn container-animation-logic [{:keys [to-value val]}]
(fn [_] (fn [_]
(let [to-value @to-value] (let [to-value @to-value]
(anim/start (anim/spring val {:toValue to-value}))))) (anim/start (anim/spring val {:toValue to-value
:tension 50
:friction 10})))))
(defn container [response-height & children] (defn container [response-height & children]
(let [;; todo to-response-height, cur-response-height must be specific (let [;; todo to-response-height, cur-response-height must be specific
@ -109,9 +108,18 @@
(into [animated-view {:style (st/response-view response-height)}] (into [animated-view {:style (st/response-view response-height)}]
children))}))) children))})))
(defview placeholder []
[suggestions [:get-content-suggestions]]
(when (seq suggestions)
[view st/input-placeholder]))
(defview response-suggestions-view []
[suggestions [:get-content-suggestions]]
(when (seq suggestions) suggestions))
(defn response-view [] (defn response-view []
(let [response-height (anim/create-value 0)] (let [response-height (anim/create-value 0)]
[container response-height [container response-height
[request-info response-height] [request-info response-height]
[response-suggestions-view] [response-suggestions-view]
[view st/input-placeholder]])) [placeholder]]))

View File

@ -1,38 +0,0 @@
(ns status-im.chat.views.response-suggestions
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch]]
[status-im.components.react :refer [view
icon
text
touchable-highlight
list-view
list-item]]
[status-im.chat.styles.response-suggestions :as st]
[status-im.utils.listview :refer [to-datasource]]))
(defn set-command-content [content]
(dispatch [:set-chat-command-content content]))
(defn header-list-item [{:keys [header]}]
[view st/header-container
[text {:style st/header-text} header]])
(defn suggestion-list-item [{:keys [value description]}]
[touchable-highlight {:onPress #(set-command-content value)}
[view st/suggestion-container
[view st/suggestion-sub-container
[text {:style st/value-text} value]
[text {:style st/description-text} description]]]])
(defn render-row [row _ _]
(list-item (if (:header row)
[header-list-item row]
[suggestion-list-item row])))
(defview response-suggestions-view []
[suggestions [:get-content-suggestions]]
(when (seq suggestions)
[view st/suggestions-container
[list-view {:dataSource (to-datasource suggestions)
:keyboardShouldPersistTaps true
:renderRow render-row}]]))

View File

@ -1,9 +1,9 @@
(ns status-im.chat.views.staged-command (ns status-im.chat.views.staged-command
(:require [re-frame.core :refer [subscribe dispatch]] (:require [re-frame.core :refer [subscribe dispatch]]
[status-im.components.react :refer [view [status-im.components.react :refer [view
image image
text text
touchable-highlight]] touchable-highlight]]
[status-im.resources :as res] [status-im.resources :as res]
[status-im.chat.styles.input :as st])) [status-im.chat.styles.input :as st]))
@ -16,13 +16,12 @@
[view st/staged-command-background [view st/staged-command-background
[view st/staged-command-info-container [view st/staged-command-info-container
[view (st/staged-command-text-container command) [view (st/staged-command-text-container command)
[text {:style st/staged-command-text} (:text command)]] [text {:style st/staged-command-text} (str "!" (:name command))]]
[touchable-highlight {:style st/staged-command-cancel [touchable-highlight {:style st/staged-command-cancel
:onPress #(cancel-command-input staged-command)} :onPress #(cancel-command-input staged-command)}
[image {:source res/icon-close-gray [image {:source res/icon-close-gray
:style st/staged-command-cancel-icon}]]] :style st/staged-command-cancel-icon}]]]
[text {:style st/staged-command-content} (if-let [preview (:preview staged-command)]
;; TODO isn't smart preview
(if (= (:command command) :keypair-password) [text {:style st/staged-command-content}
"******" (:content staged-command)])]]))
(:content staged-command))]]]))

View File

@ -1,4 +1,5 @@
(ns status-im.chat.views.suggestions (ns status-im.chat.views.suggestions
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch]] (:require [re-frame.core :refer [subscribe dispatch]]
[status-im.components.react :refer [view [status-im.components.react :refer [view
text text
@ -13,35 +14,35 @@
(dispatch [:set-chat-command command])) (dispatch [:set-chat-command command]))
(defn suggestion-list-item (defn suggestion-list-item
[{:keys [description command] [[command {:keys [description]
label :text name :name
:as suggestion}] :as suggestion}]]
[touchable-highlight (let [label (str "!" name)]
{:onPress #(set-command-input (keyword command))} [touchable-highlight
[view st/suggestion-container {:onPress #(set-command-input command)}
[view st/suggestion-sub-container [view st/suggestion-container
[view (st/suggestion-background suggestion) [view st/suggestion-sub-container
[text {:style st/suggestion-text} label]] [view (st/suggestion-background suggestion)
[text {:style st/value-text} label] [text {:style st/suggestion-text} label]]
[text {:style st/description-text} description]]]]) [text {:style st/value-text} label]
[text {:style st/description-text} description]]]]))
(defn render-row [row _ _] (defn render-row [row _ _]
(list-item [suggestion-list-item row])) (list-item [suggestion-list-item row]))
(defn suggestions-view []
(let [suggestions-atom (subscribe [:get-suggestions])] (defview suggestions-view []
(fn [] [suggestions [:get-suggestions]]
(let [suggestions @suggestions-atom] (when (seq suggestions)
(when (seq suggestions) [view st/container
[view st/container [touchable-highlight {:style st/drag-down-touchable
[touchable-highlight {:style st/drag-down-touchable :onPress (fn []
:onPress (fn [] ;; TODO hide suggestions?
;; TODO hide suggestions? )}
)} [view
[view [icon :drag_down st/drag-down-icon]]]
[icon :drag_down st/drag-down-icon]]] [view (st/suggestions-container (count suggestions))
[view (st/suggestions-container (count suggestions)) [list-view {:dataSource (to-datasource suggestions)
[list-view {:dataSource (to-datasource suggestions) :enableEmptySections true
:enableEmptySections true :keyboardShouldPersistTaps true
:keyboardShouldPersistTaps true :renderRow render-row}]]]))
:renderRow render-row}]]])))))

View File

@ -0,0 +1,80 @@
(ns status-im.commands.handlers.jail
(:require [re-frame.core :refer [register-handler after dispatch subscribe
trim-v debug]]
[status-im.utils.handlers :as u]
[status-im.utils.utils :refer [http-get toast]]
[status-im.components.jail :as j]
[status-im.utils.types :refer [json->clj]]
[status-im.commands.utils :refer [generate-hiccup reg-handler]]
[clojure.string :as s]))
(defn init-render-command!
[_ [chat-id command message-id data]]
(j/call chat-id [command :render] data
#(dispatch [::render-command chat-id message-id %])))
(defn render-command
[db [chat-id message-id markup]]
(let [hiccup (generate-hiccup markup)]
(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 %])})
(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)))))
(defn suggestions-handler!
[db [{:keys [chat-id]} {:keys [result]} ]]
(assoc-in db [:suggestions chat-id] (generate-hiccup result)))
(defn suggestions-events-handler!
[db [[n data]]]
(case (keyword n)
:set-value (dispatch [:set-chat-command-content data])
;; todo show error?
nil))
(defn command-preview
[db [chat-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
:preview (generate-hiccup result)
:preview-string (str result)))
db))
(defn print-error-message! [message]
(fn [_ params]
(when (:error (last params))
(toast (s/join "\n" [message params]))
(println message params))))
(reg-handler :init-render-command! init-render-command!)
(reg-handler ::render-command render-command)
(reg-handler :command-handler!
(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"))]
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)

View File

@ -0,0 +1,103 @@
(ns status-im.commands.handlers.loading
(:require-macros [status-im.utils.slurp :refer [slurp]])
(:require [re-frame.core :refer [register-handler after dispatch subscribe
trim-v debug]]
[status-im.utils.handlers :as u]
[status-im.utils.utils :refer [http-get toast]]
[clojure.string :as s]
[status-im.persistence.realm :as realm]
[status-im.components.jail :as j]
[status-im.utils.types :refer [json->clj]]
[status-im.commands.utils :refer [reg-handler]]))
(def commands-js "commands.js")
(defn load-commands!
[_ [identity]]
(dispatch [::fetch-commands! identity])
;; todo uncomment
#_(if-let [{:keys [file]} (realm/get-one-by-field :commands :chat-id
identity)]
(dispatch [::parse-commands! identity file])
(dispatch [::fetch-commands! identity])))
(defn fetch-commands!
[db [identity]]
(when-let [url (:dapp-url (get-in db [:chats identity]))]
(if (= "console" identity)
(dispatch [::validate-hash identity (slurp "resources/commands.js")])
(http-get (s/join "/" [url commands-js])
#(dispatch [::validate-hash identity %])
#(dispatch [::loading-failed! identity ::file-was-not-found])))))
(defn dispatch-loaded!
[db [identity file]]
(if (::valid-hash db)
(dispatch [::parse-commands! identity file])
(dispatch [::loading-failed! identity ::wrong-hash])))
(defn get-hash-by-identity
[db identity]
(get-in db [:chats identity :dapp-hash]))
(defn get-hash-by-file
[file]
;; todo tbd hashing algorithm
(hash file))
(defn parse-commands! [_ [identity file]]
(j/parse identity file
(fn [result]
(let [{:keys [error result]} (json->clj result)]
(if error
(dispatch [::loading-failed! identity ::error-in-jail error])
(dispatch [::add-commands identity file result]))))))
(defn validate-hash
[db [identity file]]
(let [valid? true
;; todo check
#_(= (get-hash-by-identity db identity)
(get-hash-by-file file))]
(assoc db ::valid-hash valid?)))
(defn mark-as [as coll]
(->> coll
(map (fn [[k v]] [k (assoc v :type as)]))
(into {})))
(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))))
(defn save-commands-js!
[_ [id file]]
(realm/create-object :commands {:chat-id id :file file}))
(defn loading-failed!
[db [id reason details]]
(let [url (get-in db [:chats id :dapp-url])]
(let [m (s/join "\n" ["commands.js loading failed"
url
id
(name reason)
details])]
(toast m)
(println m))))
(reg-handler :load-commands! (u/side-effect! load-commands!))
(reg-handler ::fetch-commands! (u/side-effect! fetch-commands!))
(reg-handler ::validate-hash
(after dispatch-loaded!)
validate-hash)
(reg-handler ::parse-commands! (u/side-effect! parse-commands!))
(reg-handler ::add-commands
(after save-commands-js!)
add-commands)
(reg-handler ::loading-failed! (u/side-effect! loading-failed!))

View File

@ -0,0 +1,47 @@
(ns status-im.commands.utils
(:require [clojure.set :as set]
[clojure.walk :as w]
[status-im.components.react :refer [text scroll-view view
image touchable-highlight]]
[re-frame.core :refer [register-handler dispatch trim-v debug]]))
(defn json->clj [json]
(if (= json "undefined")
nil
(js->clj (.parse js/JSON json) :keywordize-keys true)))
(def elements
{:text text
:view view
:scroll-view scroll-view
:image image
:touchable touchable-highlight})
(defn get-element [n]
(elements (keyword (.toLowerCase n))))
(def events #{:onPress})
(defn wrap-event [event]
#(dispatch [:suggestions-event! event]))
(defn check-events [m]
(let [ks (set (keys m))
evs (set/intersection ks events)]
(reduce #(update %1 %2 wrap-event) m evs)))
(defn generate-hiccup [markup]
;; todo implement validation
(w/prewalk
(fn [el]
(if (and (vector? el) (string? (first el)))
(-> el
(update 0 get-element)
(update 1 check-events))
el))
markup))
(defn reg-handler
([name handler] (reg-handler name nil handler))
([name middleware handler]
(register-handler name [#_debug trim-v middleware] handler)))

View File

@ -0,0 +1,27 @@
(ns status-im.components.jail
(:require-macros [status-im.utils.slurp :refer [slurp]])
(:require [status-im.components.react :as r]
[status-im.utils.types :as t]))
(def status-js (slurp "resources/status.js"))
(def jail
(when (exists? (.-NativeModules r/react))
(.-Jail (.-NativeModules r/react))))
(when jail
(.init jail status-js))
(defn parse [chat-id file callback]
(.parse jail chat-id file callback))
(defn cljs->json [data]
(.stringify js/JSON (clj->js data)))
(defn call [chat-id path params callback]
(println :call chat-id (cljs->json path) (cljs->json params))
(let [cb (fn [r]
(let [r' (t/json->clj r)]
(println r')
(callback r')))]
(.call jail chat-id (cljs->json path) (cljs->json params) cb)))

View File

@ -96,7 +96,6 @@
(remove #(identities (:whisper-identity %))) (remove #(identities (:whisper-identity %)))
(map #(vector (:whisper-identity %) %)) (map #(vector (:whisper-identity %) %))
(into {}))] (into {}))]
(println new-contacts')
(-> db (-> db
(update :contacts merge new-contacts') (update :contacts merge new-contacts')
(assoc :new-contacts (vals new-contacts'))))) (assoc :new-contacts (vals new-contacts')))))

View File

@ -5,18 +5,19 @@
[status-im.db :refer [app-db schema]] [status-im.db :refer [app-db schema]]
[status-im.persistence.simple-kv-store :as kv] [status-im.persistence.simple-kv-store :as kv]
[status-im.protocol.state.storage :as storage] [status-im.protocol.state.storage :as storage]
[status-im.models.commands :refer [set-commands]]
[status-im.chat.suggestions :refer [load-commands]]
[status-im.utils.logging :as log] [status-im.utils.logging :as log]
[status-im.utils.crypt :refer [gen-random-bytes]] [status-im.utils.crypt :refer [gen-random-bytes]]
[status-im.utils.handlers :as u] [status-im.utils.handlers :as u]
status-im.chat.handlers status-im.chat.handlers
status-im.chat.handlers.animation
status-im.group-settings.handlers status-im.group-settings.handlers
status-im.navigation.handlers status-im.navigation.handlers
status-im.contacts.handlers status-im.contacts.handlers
status-im.discovery.handlers status-im.discovery.handlers
status-im.new-group.handlers status-im.new-group.handlers
status-im.participants.handlers status-im.participants.handlers
status-im.commands.handlers.loading
status-im.commands.handlers.jail
status-im.qr-scanner.handlers status-im.qr-scanner.handlers
status-im.protocol.handlers)) status-im.protocol.handlers))
@ -80,17 +81,6 @@
(fn [_ _] (fn [_ _]
(log/debug "crypt initialized")))) (log/debug "crypt initialized"))))
(register-handler :load-commands
(u/side-effect!
(fn [_ [action]]
(log/debug action)
(load-commands))))
(register-handler :set-commands
(fn [db [action commands]]
(log/debug action commands)
(set-commands db commands)))
;; -- User data -------------------------------------------------------------- ;; -- User data --------------------------------------------------------------
(register-handler :load-user-phone-number (register-handler :load-user-phone-number
(fn [db [_]] (fn [db [_]]

View File

@ -16,7 +16,7 @@
(defn get-content-suggestions [command text] (defn get-content-suggestions [command text]
(or (when command (or (when command
(when-let [command-suggestions ((:command command) suggestions)] (when-let [command-suggestions ((keyword (:name command)) suggestions)]
(filterv (fn [s] (filterv (fn [s]
(or (:header s) (or (:header s)
(and (.startsWith (:value s) (or text "")) (and (.startsWith (:value s) (or text ""))

View File

@ -7,72 +7,14 @@
[status-im.components.styles :refer [color-blue color-dark-mint]] [status-im.components.styles :refer [color-blue color-dark-mint]]
[status-im.i18n :refer [label]])) [status-im.i18n :refer [label]]))
;; todo delete (defn get-commands [{:keys [current-chat-id] :as db}]
(def commands [{:command :money (or (get-in db [:chats current-chat-id :commands]) {}))
:text "!money"
:description (label :t/money-command-description)
:color color-dark-mint
:request-icon {:uri "icon_lock_white"}
:icon {:uri "icon_lock_gray"}
:suggestion true}
{:command :location
:text "!location"
:description (label :t/location-command-description)
:color "#9a5dcf"
:suggestion true}
{:command :phone
:text "!phone"
:description (label :t/phone-command-description)
:color color-dark-mint
:request-text (label :t/phone-request-text)
:suggestion true
:handler #(dispatch [:sign-up %])}
{:command :confirmation-code
:text "!confirmationCode"
:description (label :t/confirmation-code-command-description)
:request-text (label :t/confirmation-code-request-text)
:color color-blue
:request-icon {:uri "icon_lock_white"}
:icon {:uri "icon_lock_gray"}
:suggestion true
:handler #(dispatch [:sign-up-confirm %])}
{:command :send
:text "!send"
:description (label :t/send-command-description)
:color "#9a5dcf"
:suggestion true}
{:command :request
:text "!request"
:description (label :t/request-command-description)
:color "#48ba30"
:suggestion true}
{:command :keypair-password
:text "!keypair-password"
:description (label :t/keypair-password-command-description)
:color color-blue
:request-icon {:uri "icon_lock_white"}
:icon {:uri "icon_lock_gray"}
:suggestion false
:handler #(dispatch [:save-password %])}
{:command :help
:text "!help"
:description (label :t/help-command-description)
:color "#9a5dcf"
:suggestion true}])
(defn get-commands [db] (defn get-command [{:keys [current-chat-id] :as db} command-key]
;; todo: temp. must be '(get db :commands)' ((or (->> (get-in db [:chats current-chat-id])
;; (get db :commands) ((juxt :commands :responses))
commands) (apply merge))
{}) command-key))
(defn set-commands [db commands]
(assoc db :commands commands))
;; todo delete
(def suggestions (filterv :suggestion commands))
(defn get-command [db command-key]
(first (filter #(= command-key (:command %)) (get-commands db))))
(defn find-command [commands command-key] (defn find-command [commands command-key]
(first (filter #(= command-key (:command %)) commands))) (first (filter #(= command-key (:command %)) commands)))
@ -130,7 +72,7 @@
#(assoc % msg-id handler))) #(assoc % msg-id handler)))
(defn parse-command-msg-content [commands content] (defn parse-command-msg-content [commands content]
(update content :command #(find-command commands (keyword %)))) (update content :command #((keyword %) commands)))
(defn parse-command-request [commands content] (defn parse-command-request [commands content]
(update content :command #(find-command commands (keyword %)))) (update content :command #((keyword %) commands)))

View File

@ -6,7 +6,8 @@
[status-im.utils.logging :as log] [status-im.utils.logging :as log]
[clojure.string :refer [join split]] [clojure.string :refer [join split]]
[clojure.walk :refer [stringify-keys keywordize-keys]] [clojure.walk :refer [stringify-keys keywordize-keys]]
[status-im.constants :as c])) [status-im.constants :as c]
[status-im.commands.utils :refer [generate-hiccup]]))
(defn- map-to-str (defn- map-to-str
[m] [m]
@ -20,7 +21,8 @@
{:outgoing false {:outgoing false
:to nil :to nil
:same-author false :same-author false
:same-direction false}) :same-direction false
:preview nil})
(defn save-message (defn save-message
;; todo remove chat-id parameter ;; todo remove chat-id parameter
@ -45,6 +47,24 @@
#{c/content-type-command c/content-type-command-request} #{c/content-type-command c/content-type-command-request}
type)) type))
<<<<<<< HEAD
(defn get-messages [chat-id]
(->> (-> (r/get-by-field :msgs :chat-id chat-id)
(r/sorted :timestamp :desc)
(r/collection->map))
(into '())
;; todo why reverse?
reverse
(map (fn [{:keys [content-type preview] :as message}]
(if (command-type? content-type)
(-> message
(update :content str-to-map)
(assoc :rendered-preview (when preview
(generate-hiccup
(read-string preview))))
(dissoc :preview))
message)))))
=======
(defn get-messages (defn get-messages
([chat-id] (get-messages chat-id 0)) ([chat-id] (get-messages chat-id 0))
([chat-id from] ([chat-id from]
@ -58,6 +78,7 @@
(if (command-type? content-type) (if (command-type? content-type)
(update message :content str-to-map) (update message :content str-to-map)
message)))))) message))))))
>>>>>>> develop
(defn update-message! [{:keys [msg-id] :as msg}] (defn update-message! [{:keys [msg-id] :as msg}]
(log/debug "update-message!" msg) (log/debug "update-message!" msg)

View File

@ -1,6 +1,5 @@
(ns status-im.navigation.handlers (ns status-im.navigation.handlers
(:require [re-frame.core :refer [register-handler dispatch debug enrich (:require [re-frame.core :refer [register-handler dispatch debug enrich after]]))
after]]))
(defn push-view [db view-id] (defn push-view [db view-id]
(-> db (-> db

View File

@ -1,7 +1,6 @@
(ns status-im.persistence.realm (ns status-im.persistence.realm
(:require [cljs.reader :refer [read-string]] (:require [cljs.reader :refer [read-string]]
[status-im.components.styles :refer [default-chat-color]] [status-im.components.styles :refer [default-chat-color]]
[status-im.utils.logging :as log]
[status-im.utils.types :refer [to-string]] [status-im.utils.types :refer [to-string]]
[status-im.utils.utils :as u]) [status-im.utils.utils :as u])
(:refer-clojure :exclude [exists?])) (:refer-clojure :exclude [exists?]))
@ -34,7 +33,9 @@
:delivery-status {:type "string" :delivery-status {:type "string"
:optional true} :optional true}
:same-author "bool" :same-author "bool"
:same-direction "bool"}} :same-direction "bool"
:preview {:type :string
:optional true}}}
{:name :chat-contact {:name :chat-contact
:properties {:identity "string" :properties {:identity "string"
:is-in-chat {:type "bool" :is-in-chat {:type "bool"
@ -51,7 +52,15 @@
:timestamp "int" :timestamp "int"
:contacts {:type "list" :contacts {:type "list"
:objectType "chat-contact"} :objectType "chat-contact"}
:dapp-url {:type :string
:optional true}
:dapp-hash {:type :int
:optional true}
:last-msg-id "string"}} :last-msg-id "string"}}
{:name :commands
:primaryKey :chat-id
:properties {:chat-id "string"
:file "string"}}
{:name :tag {:name :tag
:primaryKey :name :primaryKey :name
:properties {:name "string" :properties {:name "string"
@ -94,6 +103,10 @@
([schema-name obj update?] ([schema-name obj update?]
(.create realm (to-string schema-name) (clj->js obj) update?))) (.create realm (to-string schema-name) (clj->js obj) update?)))
(defn create-object
[schema-name obj]
(write (fn [] (create schema-name obj true))))
(defmulti to-query (fn [schema-name operator field value] (defmulti to-query (fn [schema-name operator field value]
operator)) operator))
@ -158,3 +171,6 @@
(defn collection->map [collection] (defn collection->map [collection]
(-> (.map collection (fn [object _ _] object)) (-> (.map collection (fn [object _ _] object))
(js->clj :keywordize-keys true))) (js->clj :keywordize-keys true)))
(defn get-one-by-field [schema-name field value]
(single-cljs (get-by-field schema-name field value)))

View File

@ -0,0 +1,5 @@
(ns status-im.utils.slurp
(:refer-clojure :exclude [slurp]))
(defmacro slurp [file]
(clojure.core/slurp file))

View File

@ -11,5 +11,6 @@
(defn clj->json [data] (defn clj->json [data]
(.stringify js/JSON (clj->js data))) (.stringify js/JSON (clj->js data)))
(defn json->clj [data] (defn json->clj [json]
(js->clj (.parse js/JSON data) :keywordize-keys true)) (when-not (= json "undefined")
(js->clj (.parse js/JSON json) :keywordize-keys true)))

View File

@ -41,10 +41,8 @@
(toast (str error)))))))) (toast (str error))))))))
(defn http-get (defn http-get
([action on-success on-error] ([url on-success on-error]
(-> (.fetch js/window (-> (.fetch js/window url (clj->js {:method "GET"}))
(str const/server-address action)
(clj->js {:method "GET"}))
(.then (fn [response] (.then (fn [response]
(log response) (log response)
(.text response))) (.text response)))

View File

@ -0,0 +1,20 @@
(ns status-im.test.commands.handlers
(:require [cljs.test :refer-macros [deftest is]]
[status-im.commands.handlers.loading :as h]))
(deftest test-validate-hash
(let [file "some-js"
db (-> {}
(assoc-in [:chats :user :dapp-hash] -731917028)
(assoc-in [:chats :user2 :dapp-hash] 123))]
(is (::h/valid-hash (h/validate-hash db [:user file])))
(is (not (::h/valid-hash (h/validate-hash db [:user2 file]))))
(is (not (::h/valid-hash (h/validate-hash db [:user3 file]))))))
(deftest test-add-commands
(let [obj {:commands {:test {:name "name"
:description "desc"}}
:responses {:test-r {:name "r"
:description "desc-r"}}}
db (h/add-commands {} [:user nil obj])]
(is (= obj (select-keys (get-in db [:chats :user]) [:commands :responses])))))

View File

@ -1,5 +1,7 @@
(ns status-im.test.runner (ns status-im.test.runner
(:require [doo.runner :refer-macros [doo-tests]] (:require [doo.runner :refer-macros [doo-tests]]
[status-im.test.handlers])) [status-im.test.handlers]
[status-im.test.commands.handlers]))
(doo-tests 'status-im.test.handlers) (doo-tests 'status-im.test.handlers
'status-im.test.commands.handlers)