mirror of
https://github.com/status-im/status-react.git
synced 2025-01-26 19:01:17 +00:00
merge develop
This commit is contained in:
commit
4fca2507da
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "StatusIm",
|
||||
"interface": "reagent",
|
||||
"androidHost": "localhost",
|
||||
"androidHost": "10.0.3.2",
|
||||
"modules": [
|
||||
"react-native-contacts",
|
||||
"react-native-invertible-scroll-view",
|
||||
@ -17,6 +17,7 @@
|
||||
"dismissKeyboard",
|
||||
"react-native-linear-gradient",
|
||||
"react-native-android-sms-listener",
|
||||
"react-native-status",
|
||||
"react-native-camera",
|
||||
"react-native-qrcode",
|
||||
"react-native-orientation",
|
||||
@ -30,4 +31,4 @@
|
||||
"dev": "env/dev",
|
||||
"prod": "env/prod"
|
||||
}
|
||||
}
|
||||
}
|
@ -131,9 +131,10 @@ dependencies {
|
||||
compile project(':react-native-linear-gradient')
|
||||
compile project(':ReactNativeAndroidSmsListener')
|
||||
compile project(':react-native-camera')
|
||||
compile project(':react-native-status')
|
||||
compile project(':react-native-orientation')
|
||||
compile(name:'statusgo-android-16', ext:'aar')
|
||||
//compile(group: 'status-im', name: 'status-go', version: '0.1.0-test-callback', ext: 'aar')
|
||||
//compile(group: 'status-im', name: 'status-go', version: '0.1.0-201606231357-85abe1', ext: 'aar')
|
||||
|
||||
compile fileTree(dir: "node_modules/realm/android/libs", include: ["*.jar"])
|
||||
}
|
||||
@ -143,3 +144,4 @@ task copyDownloadableDepsToLibs(type: Copy) {
|
||||
from configurations.compile
|
||||
into 'libs'
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,8 @@ import com.github.yamill.orientation.OrientationPackage;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.io.File;
|
||||
import com.statusim.Jail.JailPackage;
|
||||
|
||||
import com.lwansbrough.RCTCamera.*;
|
||||
import com.i18n.reactnativei18n.ReactNativeI18n;
|
||||
@ -100,6 +102,7 @@ public class MainActivity extends ReactActivity {
|
||||
protected List<ReactPackage> getPackages() {
|
||||
return Arrays.<ReactPackage>asList(
|
||||
new MainReactPackage(),
|
||||
new JailPackage(),
|
||||
new RealmReactPackage(),
|
||||
new VectorIconsPackage(),
|
||||
new ReactNativeContacts(),
|
||||
|
BIN
android/app/src/main/res/drawable-hdpi/icon_input_list.png
Normal file
BIN
android/app/src/main/res/drawable-hdpi/icon_input_list.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 469 B |
BIN
android/app/src/main/res/drawable-mdpi/icon_input_list.png
Normal file
BIN
android/app/src/main/res/drawable-mdpi/icon_input_list.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 247 B |
BIN
android/app/src/main/res/drawable-xhdpi/icon_input_list.png
Normal file
BIN
android/app/src/main/res/drawable-xhdpi/icon_input_list.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 333 B |
BIN
android/app/src/main/res/drawable-xxhdpi/icon_input_list.png
Normal file
BIN
android/app/src/main/res/drawable-xxhdpi/icon_input_list.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 651 B |
BIN
android/app/src/main/res/drawable-xxxhdpi/icon_input_list.png
Normal file
BIN
android/app/src/main/res/drawable-xxxhdpi/icon_input_list.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 823 B |
@ -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')
|
||||
include ':ReactNativeAndroidSmsListener'
|
||||
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'
|
||||
project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android')
|
||||
|
||||
include ':react-native-orientation', ':app'
|
||||
project(':react-native-orientation').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-orientation/android')
|
||||
|
@ -23,6 +23,7 @@
|
||||
"react-native-randombytes": "^2.1.0",
|
||||
"react-native-vector-icons": "^1.3.4",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
209
resources/commands.js
Normal file
209
resources/commands.js
Normal file
@ -0,0 +1,209 @@
|
||||
status.command({
|
||||
name: "location",
|
||||
description: "Send location",
|
||||
color: "#9a5dcf",
|
||||
preview: function (params) {
|
||||
var text = status.components.text(
|
||||
{
|
||||
style: {
|
||||
marginTop: 5,
|
||||
marginHorizontal: 0,
|
||||
fontSize: 14,
|
||||
fontFamily: "font",
|
||||
color: "black"
|
||||
}
|
||||
}, params.value);
|
||||
var uri = "https://maps.googleapis.com/maps/api/staticmap?center="
|
||||
+ params.value
|
||||
+ "&size=100x100&maptype=roadmap&key=AIzaSyBNsj1qoQEYPb3IllmWMAscuXW0eeuYqAA&language=en"
|
||||
+ "&markers=size:mid%7Ccolor:0xff0000%7Clabel:%7C"
|
||||
+ params.value;
|
||||
|
||||
var image = status.components.image(
|
||||
{
|
||||
source: {uri: uri},
|
||||
style: {
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return status.components.view({}, [text, image]);
|
||||
}
|
||||
}).param({
|
||||
name: "address",
|
||||
type: status.types.TEXT,
|
||||
placeholder: "Address"
|
||||
});
|
||||
|
||||
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,
|
||||
suggestions: phoneSuggestions,
|
||||
placeholder: "Phone number"
|
||||
}],
|
||||
handler: function (params) {
|
||||
return {
|
||||
event: "sign-up",
|
||||
params: [params.value]
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
status.command({
|
||||
name: "help",
|
||||
description: "Help",
|
||||
color: "#7099e6",
|
||||
params: [{
|
||||
name: "query",
|
||||
type: status.types.TEXT
|
||||
}]
|
||||
});
|
||||
|
||||
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"
|
||||
}
|
||||
}, "*****");
|
||||
}
|
||||
});
|
||||
|
110
resources/status.js
Normal file
110
resources/status.js
Normal file
@ -0,0 +1,110 @@
|
||||
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: {
|
||||
TEXT: 'text',
|
||||
NUMBER: 'number',
|
||||
PHONE: 'phone',
|
||||
PASSWORD: 'password'
|
||||
},
|
||||
events: {
|
||||
SET_VALUE: 'set-value'
|
||||
},
|
||||
components: {
|
||||
view: view,
|
||||
text: text,
|
||||
image: image,
|
||||
touchable: touchable,
|
||||
scrollView: scrollView
|
||||
}
|
||||
};
|
@ -39,7 +39,8 @@
|
||||
|
||||
(defn app-root []
|
||||
(let [signed-up (subscribe [:get :signed-up])
|
||||
view-id (subscribe [:get :view-id])]
|
||||
view-id (subscribe [:get :view-id])
|
||||
keyboard-height (subscribe [:get :keyboard-height])]
|
||||
(r/create-class
|
||||
{:component-will-mount
|
||||
(fn []
|
||||
@ -53,10 +54,12 @@
|
||||
"keyboardDidShow"
|
||||
(fn [e]
|
||||
(let [h (.. e -endCoordinates -height)]
|
||||
(dispatch [:set :keyboard-height h]))))
|
||||
(when-not (= h keyboard-height)
|
||||
(dispatch [:set :keyboard-height h])))))
|
||||
(.addListener device-event-emitter
|
||||
"keyboardDidHide"
|
||||
#(dispatch [:set :keyboard-height 0])))
|
||||
(when-not (= 0 keyboard-height)
|
||||
#(dispatch [:set :keyboard-height 0]))))
|
||||
:render
|
||||
(fn []
|
||||
(case (if @signed-up @view-id :chat)
|
||||
@ -84,8 +87,6 @@
|
||||
;(dispatch [:initialize-protocol])
|
||||
(dispatch [:load-user-phone-number])
|
||||
(dispatch [:load-contacts])
|
||||
;; load commands from remote server (todo: uncomment)
|
||||
;; (dispatch [:load-commands])
|
||||
(dispatch [:init-console-chat])
|
||||
(dispatch [:init-chat])
|
||||
(init-back-button-handler!)
|
||||
|
9
src/status_im/chat/constants.cljs
Normal file
9
src/status_im/chat/constants.cljs
Normal file
@ -0,0 +1,9 @@
|
||||
(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))
|
||||
(def suggestions-header-height 22)
|
||||
(def minimum-command-suggestions-height
|
||||
(+ input-height suggestions-header-height))
|
@ -1,19 +1,20 @@
|
||||
(ns status-im.chat.handlers
|
||||
(:require [re-frame.core :refer [register-handler enrich after debug dispatch]]
|
||||
(:require [re-frame.core :refer [enrich after debug dispatch]]
|
||||
[status-im.models.commands :as commands]
|
||||
[clojure.string :as str]
|
||||
[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.protocol.api :as api]
|
||||
[status-im.models.messages :as messages]
|
||||
[status-im.constants :refer [text-content-type
|
||||
content-type-command]]
|
||||
content-type-command
|
||||
content-type-command-request
|
||||
default-number-of-messages]]
|
||||
[status-im.utils.random :as random]
|
||||
[status-im.chat.sign-up :as sign-up-service]
|
||||
[status-im.models.chats :as chats]
|
||||
[status-im.navigation.handlers :as nav]
|
||||
[status-im.utils.handlers :as u]
|
||||
[status-im.utils.handlers :refer [register-handler] :as u]
|
||||
[status-im.persistence.realm :as r]
|
||||
[status-im.handlers.server :as server]
|
||||
[status-im.handlers.content-suggestions :refer [get-content-suggestions]]
|
||||
@ -21,21 +22,26 @@
|
||||
[status-im.utils.datetime :as time]
|
||||
[status-im.components.react :refer [geth]]
|
||||
[status-im.utils.logging :as log]
|
||||
[status-im.components.jail :as j]
|
||||
[status-im.utils.types :refer [json->clj]]
|
||||
[status-im.chat.handlers.animation :refer [update-response-height
|
||||
get-response-height]]))
|
||||
[status-im.commands.utils :refer [generate-hiccup]]))
|
||||
|
||||
(register-handler :set-show-actions
|
||||
(fn [db [_ show-actions]]
|
||||
(assoc db :show-actions show-actions)))
|
||||
|
||||
(register-handler :load-more-messages
|
||||
debug
|
||||
(fn [{:keys [current-chat-id] :as 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))]
|
||||
(update-in db messages-path concat new-messages))))
|
||||
(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?)))))))
|
||||
|
||||
(defn safe-trim [s]
|
||||
(when (string? s)
|
||||
@ -47,35 +53,80 @@
|
||||
(assoc-in [:chats current-chat-id :command-input] {})
|
||||
(update-in [:chats current-chat-id :input-text] safe-trim))))
|
||||
|
||||
(defn invoke-suggestions-handler!
|
||||
[{:keys [current-chat-id canceled-command] :as db} _]
|
||||
(when-not canceled-command
|
||||
(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
|
||||
(u/side-effect!
|
||||
(fn [db _]
|
||||
(dispatch [:animate-cancel-command]))))
|
||||
|
||||
(def command-prefix "c ")
|
||||
|
||||
(defn cancel-command!
|
||||
[{:keys [canceled-command]}]
|
||||
(when canceled-command
|
||||
(dispatch [:start-cancel-command])))
|
||||
|
||||
(register-handler :set-chat-command-content
|
||||
[(after invoke-suggestions-handler!)
|
||||
(after cancel-command!)]
|
||||
(fn [{:keys [current-chat-id] :as db} [_ content]]
|
||||
(as-> db db
|
||||
(commands/set-chat-command-content db content)
|
||||
(assoc-in db [:chats current-chat-id :input-text] nil)
|
||||
(if (commands/get-chat-command-to-msg-id db)
|
||||
(update-response-height db)
|
||||
db))))
|
||||
(let [starts-as-command? (str/starts-with? content command-prefix)
|
||||
path [:chats current-chat-id :command-input :command :type]
|
||||
command? (= :command (get-in db path))]
|
||||
(as-> db db
|
||||
(commands/set-chat-command-content db content)
|
||||
(assoc-in db [:chats current-chat-id :input-text] nil)
|
||||
(assoc db :canceled-command (and command? (not starts-as-command?)))))))
|
||||
|
||||
(defn update-input-text
|
||||
[{:keys [current-chat-id] :as db} 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
|
||||
(after invoke-command-preview!)
|
||||
(fn [{:keys [current-chat-id] :as db} _]
|
||||
(let [db (update-input-text db nil)
|
||||
{:keys [command content]}
|
||||
{:keys [command content to-msg-id]}
|
||||
(get-in db [:chats current-chat-id :command-input])
|
||||
command-info {:command command
|
||||
:content content
|
||||
:handler (:handler command)}]
|
||||
content' (if (= :command (:type command))
|
||||
(subs content 2)
|
||||
content)
|
||||
command-info {:command command
|
||||
:content content'
|
||||
:to-message to-msg-id}]
|
||||
(-> db
|
||||
(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 []
|
||||
(fn [db [_ input]]
|
||||
@ -88,14 +139,20 @@
|
||||
(.blur message-input)))))
|
||||
|
||||
(register-handler :set-response-chat-command
|
||||
[(after #(dispatch [:command-edit-mode]))
|
||||
(after #(dispatch [:animate-show-response]))]
|
||||
[(after invoke-suggestions-handler!)
|
||||
(after #(dispatch [:command-edit-mode]))
|
||||
(after #(dispatch [:set-chat-input-text ""]))]
|
||||
(fn [db [_ to-msg-id command-key]]
|
||||
(commands/set-response-chat-command db to-msg-id command-key)))
|
||||
(-> db
|
||||
(commands/set-response-chat-command to-msg-id command-key)
|
||||
(assoc :canceled-command false))))
|
||||
|
||||
(defn update-text
|
||||
[db [_ text]]
|
||||
(update-input-text db text))
|
||||
[{:keys [current-chat-id] :as db} [_ text]]
|
||||
(let [suggestions (get-in db [:command-suggestions current-chat-id])]
|
||||
(if-not (= 1 (count suggestions))
|
||||
(update-input-text db text)
|
||||
(assoc db :disable-input true))))
|
||||
|
||||
(defn update-command [db [_ text]]
|
||||
(if-not (commands/get-chat-command db)
|
||||
@ -105,8 +162,22 @@
|
||||
db))
|
||||
db))
|
||||
|
||||
(defn check-suggestions
|
||||
[{:keys [current-chat-id] :as db} [_ text]]
|
||||
(let [suggestions (suggestions/get-suggestions db text)]
|
||||
(assoc-in db [:command-suggestions current-chat-id] suggestions)))
|
||||
|
||||
(defn select-suggestion!
|
||||
[{:keys [current-chat-id] :as db} [_ text]]
|
||||
(let [suggestions (get-in db [:command-suggestions current-chat-id])]
|
||||
(when (= 1 (count suggestions))
|
||||
(dispatch [:set-chat-command (ffirst suggestions)]))))
|
||||
|
||||
(register-handler :set-chat-input-text
|
||||
((enrich update-command) update-text))
|
||||
[(enrich update-command)
|
||||
(after select-suggestion!)
|
||||
(after #(dispatch [:animate-command-suggestions]))]
|
||||
((enrich update-text) check-suggestions))
|
||||
|
||||
(defn console? [s]
|
||||
(= "console" s))
|
||||
@ -147,7 +218,7 @@
|
||||
(defn prepare-message
|
||||
[{:keys [identity current-chat-id] :as db} _]
|
||||
(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
|
||||
db current-chat-id
|
||||
{:msg-id (random/id)
|
||||
@ -162,17 +233,19 @@
|
||||
(commands/set-chat-command db command)
|
||||
(assoc db :new-message (when-not (str/blank? text) message)))))
|
||||
|
||||
(defn prepare-command [identity chat-id staged-command]
|
||||
(let [command-key (get-in staged-command [:command :command])
|
||||
content {:command (name command-key)
|
||||
:content (:content staged-command)}]
|
||||
{:msg-id (random/id)
|
||||
:from identity
|
||||
:to chat-id
|
||||
:content content
|
||||
:content-type content-type-command
|
||||
:outgoing true
|
||||
:handler (:handler staged-command)}))
|
||||
(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
|
||||
:outgoing true
|
||||
:preview preview-string
|
||||
:rendered-preview preview
|
||||
:to-message to-message}))
|
||||
|
||||
(defn prepare-staged-commans
|
||||
[{:keys [current-chat-id identity] :as db} _]
|
||||
@ -225,7 +298,29 @@
|
||||
(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 :handler))))
|
||||
(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 %])))))
|
||||
|
||||
(defn handle-commands
|
||||
[{:keys [new-commands]}]
|
||||
@ -244,6 +339,9 @@
|
||||
((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!))
|
||||
((after handle-commands))))
|
||||
|
||||
(register-handler :unstage-command
|
||||
@ -251,10 +349,13 @@
|
||||
(commands/unstage-command db staged-command)))
|
||||
|
||||
(register-handler :set-chat-command
|
||||
[(after #(dispatch [:command-edit-mode]))
|
||||
(after #(dispatch [:animate-show-response]))]
|
||||
(fn [db [_ command-key]]
|
||||
(commands/set-chat-command db command-key)))
|
||||
[(after invoke-suggestions-handler!)
|
||||
(after #(dispatch [:command-edit-mode]))]
|
||||
(fn [{:keys [current-chat-id] :as db} [_ command-key]]
|
||||
(-> db
|
||||
(commands/set-chat-command command-key)
|
||||
(assoc-in [:chats current-chat-id :command-input :content] "c ")
|
||||
(assoc :disable-input true))))
|
||||
|
||||
(register-handler :init-console-chat
|
||||
(fn [db [_]]
|
||||
@ -298,10 +399,15 @@
|
||||
([{:keys [messages current-chat-id] :as db} _]
|
||||
(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
|
||||
(after #(dispatch [:load-requests!]))
|
||||
(-> load-messages!
|
||||
((enrich init-chat))
|
||||
debug))
|
||||
((after load-commands!))))
|
||||
|
||||
(defn initialize-chats
|
||||
[{:keys [loaded-chats] :as db} _]
|
||||
@ -326,6 +432,11 @@
|
||||
[{: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' (check-author-direction db chat-id message)]
|
||||
@ -334,8 +445,9 @@
|
||||
(assoc :new-message message'))))
|
||||
|
||||
(register-handler :received-msg
|
||||
(-> receive-message
|
||||
((after store-message!))))
|
||||
[(after store-message!)
|
||||
(after dispatch-request!)]
|
||||
receive-message)
|
||||
|
||||
(register-handler :group-received-msg
|
||||
(u/side-effect!
|
||||
@ -347,6 +459,7 @@
|
||||
(let [chat-id (or id current-chat-id)
|
||||
messages (get-in db [:chats chat-id :messages])
|
||||
db' (assoc db :current-chat-id chat-id)]
|
||||
(dispatch [:load-requests! chat-id])
|
||||
(if (seq messages)
|
||||
db'
|
||||
(-> db'
|
||||
@ -384,9 +497,11 @@
|
||||
((after save-chat!))
|
||||
((after open-chat!))))
|
||||
|
||||
(register-handler :switch-command-suggestions
|
||||
(fn [db [_]]
|
||||
(suggestions/switch-command-suggestions db)))
|
||||
(register-handler :switch-command-suggestions!
|
||||
(u/side-effect!
|
||||
(fn [db]
|
||||
(let [text (if (suggestions/typing-command? db) "" "!")]
|
||||
(dispatch [:set-chat-input-text text])))))
|
||||
|
||||
(defn remove-chat
|
||||
[{:keys [current-chat-id] :as db} _]
|
||||
@ -438,4 +553,21 @@
|
||||
(edit-mode-handler :command))
|
||||
|
||||
(register-handler :text-edit-mode
|
||||
(after #(dispatch [:set-chat-input-text ""]))
|
||||
(edit-mode-handler :text))
|
||||
|
||||
(register-handler :set-layout-height
|
||||
[(after
|
||||
(fn [{:keys [current-chat-id] :as db}]
|
||||
(let [suggestions (get-in db [:suggestions current-chat-id])
|
||||
mode (get-in db [:edit-mode current-chat-id])]
|
||||
(when (and (= :command mode) (seq suggestions))
|
||||
(dispatch [:fix-response-height])))))
|
||||
(after
|
||||
(fn [{:keys [current-chat-id] :as db}]
|
||||
(let [suggestions (get-in db [:command-suggestions current-chat-id])
|
||||
mode (get-in db [:edit-mode current-chat-id])]
|
||||
(when (and (= :text mode)) (seq suggestions)
|
||||
(dispatch [:fix-commands-suggestions-height])))))]
|
||||
(fn [db [_ h]]
|
||||
(assoc db :layout-height h)))
|
||||
|
@ -1,14 +1,14 @@
|
||||
(ns status-im.chat.handlers.animation
|
||||
(:require [re-frame.core :refer [register-handler after dispatch]]
|
||||
[re-frame.middleware :refer [path]]
|
||||
[status-im.models.commands :as commands]
|
||||
(:require [re-frame.core :refer [after dispatch debug path]]
|
||||
[status-im.utils.handlers :refer [register-handler]]
|
||||
[status-im.handlers.content-suggestions :refer [get-content-suggestions]]
|
||||
[status-im.chat.styles.message-input :refer [input-height]]
|
||||
[status-im.chat.styles.response :refer [request-info-height response-height-normal]]
|
||||
[status-im.chat.styles.response-suggestions :as response-suggestions-styles]
|
||||
[status-im.chat.constants :refer [input-height request-info-height
|
||||
minimum-command-suggestions-height
|
||||
response-height-normal minimum-suggestion-height]]
|
||||
[status-im.constants :refer [response-input-hiding-duration]]))
|
||||
|
||||
(def zero-height input-height)
|
||||
;; todo magic value
|
||||
(def middle-height 270)
|
||||
|
||||
(defn animation-handler
|
||||
([name handler] (animation-handler name nil handler))
|
||||
@ -18,62 +18,95 @@
|
||||
(animation-handler :animate-cancel-command
|
||||
(after #(dispatch [:text-edit-mode]))
|
||||
(fn [db _]
|
||||
(assoc db
|
||||
:to-response-height zero-height
|
||||
:messages-offset 0)))
|
||||
(assoc db :to-response-height input-height)))
|
||||
|
||||
(defn get-response-height [db]
|
||||
(let [command (commands/get-chat-command db)
|
||||
text (commands/get-chat-command-content db)
|
||||
suggestions (get-content-suggestions command text)
|
||||
suggestions-height (reduce + 0 (map #(if (:header %)
|
||||
response-suggestions-styles/header-height
|
||||
response-suggestions-styles/suggestion-height)
|
||||
suggestions))]
|
||||
(+ zero-height
|
||||
(min response-height-normal (+ suggestions-height request-info-height)))))
|
||||
(def response-height (+ input-height response-height-normal))
|
||||
|
||||
(defn update-response-height [db]
|
||||
(assoc-in db [:animations :to-response-height] (get-response-height db)))
|
||||
(assoc-in db [:animations :to-response-height] response-height))
|
||||
|
||||
(register-handler :animate-command-suggestions
|
||||
(fn [{:keys [current-chat-id] :as db} _]
|
||||
(let [suggestions? (seq (get-in db [:command-suggestions current-chat-id]))
|
||||
current (get-in db [:animations :command-suggestions-height])
|
||||
height (if suggestions? middle-height 30)
|
||||
changed? (if (and suggestions?
|
||||
(not (nil? current))
|
||||
(not= 30 current))
|
||||
identity inc)]
|
||||
(-> db
|
||||
(update :animations assoc :command-suggestions-height height)
|
||||
(update-in [:animations :commands-height-changed] changed?)))))
|
||||
|
||||
(defn get-minimum-height
|
||||
[{:keys [current-chat-id] :as db}]
|
||||
(let [path [:chats current-chat-id :command-input :command :type]
|
||||
type (get-in db path)]
|
||||
(if (= :response type)
|
||||
minimum-suggestion-height
|
||||
30)))
|
||||
|
||||
(register-handler :animate-show-response
|
||||
(after #(dispatch [:command-edit-mode]))
|
||||
(fn [db _]
|
||||
(-> db
|
||||
(assoc-in [:animations :messages-offset] request-info-height)
|
||||
(update-response-height))))
|
||||
[(after #(dispatch [:command-edit-mode]))]
|
||||
(fn [{:keys [current-chat-id] :as db}]
|
||||
(let [suggestions? (seq (get-in db [:suggestions current-chat-id]))
|
||||
height (if suggestions?
|
||||
middle-height
|
||||
(get-minimum-height db))]
|
||||
(assoc-in db [:animations :to-response-height] height))))
|
||||
|
||||
(animation-handler :set-response-max-height
|
||||
(fn [db [_ height]]
|
||||
(let [prev-height (:response-height-max db)]
|
||||
(if (not= height prev-height)
|
||||
(let [db (assoc db :response-height-max height)]
|
||||
(if (= prev-height (:to-response-height db))
|
||||
(assoc db :to-response-height height)
|
||||
db))
|
||||
db))))
|
||||
(defn fix-height
|
||||
[height-key height-signal-key suggestions-key minimum]
|
||||
(fn [{:keys [current-chat-id] :as db} [_ vy current]]
|
||||
(let [max-height (get-in db [:layout-height])
|
||||
moving-down? (pos? vy)
|
||||
moving-up? (not moving-down?)
|
||||
under-middle-position? (<= current middle-height)
|
||||
over-middle-position? (not under-middle-position?)
|
||||
suggestions (get-in db [suggestions-key current-chat-id])
|
||||
old-fixed (get-in db [:animations height-key])
|
||||
|
||||
new-fixed (cond (not suggestions)
|
||||
(minimum db)
|
||||
|
||||
(and (nil? vy) (nil? current)
|
||||
(> old-fixed middle-height))
|
||||
max-height
|
||||
|
||||
(and (nil? vy) (nil? current)
|
||||
(< old-fixed middle-height))
|
||||
(minimum db)
|
||||
|
||||
(and under-middle-position? moving-up?)
|
||||
middle-height
|
||||
|
||||
(and over-middle-position? moving-down?)
|
||||
middle-height
|
||||
|
||||
(and over-middle-position? moving-up?)
|
||||
max-height
|
||||
|
||||
(and under-middle-position? moving-down?)
|
||||
(minimum db))]
|
||||
(-> db
|
||||
(assoc-in [:animations height-key] new-fixed)
|
||||
(update-in [:animations height-signal-key] inc)))))
|
||||
|
||||
(defn commands-min-height
|
||||
[{:keys [current-chat-id] :as db}]
|
||||
(let [suggestions (get-in db [:command-suggestions current-chat-id])]
|
||||
(if (seq suggestions)
|
||||
minimum-command-suggestions-height
|
||||
0.1)))
|
||||
|
||||
(register-handler :fix-commands-suggestions-height
|
||||
(fix-height :command-suggestions-height
|
||||
:commands-height-changed
|
||||
:command-suggestions
|
||||
commands-min-height))
|
||||
|
||||
(register-handler :fix-response-height
|
||||
(fn [db [_ vy current]]
|
||||
(let [max-height (get-in db [:animations :response-height-max])
|
||||
;; todo magic value
|
||||
middle 270
|
||||
moving-down? (pos? vy)
|
||||
moving-up? (not moving-down?)
|
||||
under-middle-position? (<= current middle)
|
||||
over-middle-position? (not under-middle-position?)
|
||||
min-height (+ zero-height request-info-height)
|
||||
new-fixed (cond (and under-middle-position? moving-down?)
|
||||
min-height
|
||||
|
||||
(and under-middle-position? moving-up?)
|
||||
middle
|
||||
|
||||
(and over-middle-position? moving-down?)
|
||||
middle
|
||||
|
||||
(and over-middle-position? moving-up?)
|
||||
max-height)]
|
||||
(-> db
|
||||
(assoc-in [:animations :to-response-height] new-fixed)
|
||||
(update-in [:animations :response-height-changed] inc)))))
|
||||
(fix-height :to-response-height
|
||||
:response-height-changed
|
||||
:suggestions
|
||||
get-minimum-height))
|
||||
|
57
src/status_im/chat/handlers/requests.cljs
Normal file
57
src/status_im/chat/handlers/requests.cljs
Normal file
@ -0,0 +1,57 @@
|
||||
(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 :as realm]
|
||||
[status-im.utils.handlers :as u]))
|
||||
|
||||
(defn store-request!
|
||||
[{:keys [new-request]}]
|
||||
(realm/write
|
||||
(fn []
|
||||
(realm/create :requests new-request))))
|
||||
|
||||
(defn add-request
|
||||
[db [_ chat-id {:keys [msg-id content]}]]
|
||||
(let [request {:chat-id chat-id
|
||||
:message-id msg-id
|
||||
:type (:command content)
|
||||
:added (js/Date.)}
|
||||
request' (update request :type keyword)]
|
||||
(-> db
|
||||
(update-in [:chats chat-id :requests] conj request')
|
||||
(assoc :new-request request))))
|
||||
|
||||
(defn load-requests!
|
||||
[{:keys [current-chat-id] :as db} [_ chat-id]]
|
||||
(let [chat-id' (or chat-id current-chat-id)
|
||||
requests (-> :requests
|
||||
;; todo maybe limit is needed
|
||||
(realm/get-by-fields {:chat-id chat-id'
|
||||
:status "open"})
|
||||
(realm/sorted :added :desc)
|
||||
(realm/collection->map))
|
||||
requests' (map #(update % :type keyword) requests)]
|
||||
(assoc-in db [:chats chat-id' :requests] requests')))
|
||||
|
||||
(defn mark-request-as-answered!
|
||||
[_ [_ chat-id message-id]]
|
||||
(realm/write
|
||||
(fn []
|
||||
(-> :requests
|
||||
(realm/get-by-fields
|
||||
{:chat-id chat-id
|
||||
:message-id message-id})
|
||||
(realm/single)
|
||||
(.-status)
|
||||
(set! "answered")))))
|
||||
|
||||
(register-handler :add-request
|
||||
(after store-request!)
|
||||
add-request)
|
||||
|
||||
(register-handler :load-requests! load-requests!)
|
||||
|
||||
(register-handler :request-answered!
|
||||
(after (fn [_ [_ chat-id]]
|
||||
(dispatch [:load-requests! chat-id])))
|
||||
(u/side-effect! mark-request-as-answered!))
|
@ -18,8 +18,7 @@
|
||||
[status-im.components.invertible-scroll-view :refer [invertible-scroll-view]]
|
||||
[status-im.components.toolbar :refer [toolbar]]
|
||||
[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 [suggestion-container]]
|
||||
[status-im.chat.views.response :refer [response-view]]
|
||||
[status-im.chat.views.new-message :refer [chat-message-new]]
|
||||
[status-im.i18n :refer [label label-pluralize]]
|
||||
@ -42,10 +41,10 @@
|
||||
:background-color background-color))))
|
||||
|
||||
(defview chat-icon []
|
||||
[chat-id [:chat :chat-id]
|
||||
[chat-id [:chat :chat-id]
|
||||
group-chat [:chat :group-chat]
|
||||
name [:chat :name]
|
||||
color [:chat :color]]
|
||||
name [:chat :name]
|
||||
color [:chat :color]]
|
||||
;; TODO stub data ('online' property)
|
||||
[chat-icon-view-action chat-id group-chat name color true])
|
||||
|
||||
@ -99,10 +98,10 @@
|
||||
subtitle])]]])
|
||||
|
||||
(defview menu-item-icon-profile []
|
||||
[chat-id [:chat :chat-id]
|
||||
[chat-id [:chat :chat-id]
|
||||
group-chat [:chat :group-chat]
|
||||
name [:chat :name]
|
||||
color [:chat :color]]
|
||||
name [:chat :name]
|
||||
color [:chat :color]]
|
||||
;; TODO stub data ('online' property)
|
||||
[chat-icon-view-menu-item chat-id group-chat name color true])
|
||||
|
||||
@ -141,12 +140,12 @@
|
||||
:icon-style {:width 20
|
||||
:height 13}
|
||||
:handler #(dispatch [:show-group-settings])}]
|
||||
[{:title (label :t/profile)
|
||||
[{:title (label :t/profile)
|
||||
:custom-icon [menu-item-icon-profile]
|
||||
:icon :menu_group
|
||||
:icon-style {:width 25
|
||||
:height 19}
|
||||
:handler #(dispatch [:show-profile @chat-id])}
|
||||
:icon :menu_group
|
||||
:icon-style {:width 25
|
||||
:height 19}
|
||||
:handler #(dispatch [:show-profile @chat-id])}
|
||||
{:title (label :t/search-chat)
|
||||
:subtitle (label :t/not-implemented)
|
||||
:icon :search_gray_copy
|
||||
@ -219,30 +218,26 @@
|
||||
:custom-action [toolbar-action]}])))
|
||||
|
||||
(defview messages-view [group-chat]
|
||||
[messages [:chat :messages]
|
||||
contacts [:chat :contacts]]
|
||||
(let [contacts' (contacts-by-identity contacts)]
|
||||
[list-view {:renderRow (message-row contacts' group-chat (count messages))
|
||||
:renderScrollComponent #(invertible-scroll-view (js->clj %))
|
||||
:onEndReached #(dispatch [:load-more-messages])
|
||||
:enableEmptySections true
|
||||
:keyboardShouldPersistTaps true
|
||||
:dataSource (to-datasource-inverted messages)}]))
|
||||
[messages [:chat :messages]
|
||||
contacts [:chat :contacts]]
|
||||
(let [contacts' (contacts-by-identity contacts)]
|
||||
[list-view {:renderRow (message-row contacts' group-chat (count messages))
|
||||
:renderScrollComponent #(invertible-scroll-view (js->clj %))
|
||||
:onEndReached #(dispatch [:load-more-messages])
|
||||
:enableEmptySections true
|
||||
:keyboardShouldPersistTaps true
|
||||
:dataSource (to-datasource-inverted messages)}]))
|
||||
|
||||
(defn messages-container-animation-logic [{:keys [to-value val]}]
|
||||
(defn messages-container-animation-logic
|
||||
[{:keys [offset val]}]
|
||||
(fn [_]
|
||||
(let [to-value @to-value]
|
||||
(anim/start (anim/spring val {:toValue to-value})
|
||||
(fn [arg]
|
||||
(when (.-finished arg)
|
||||
(dispatch [:set-animation ::messages-offset-current to-value])))))))
|
||||
(anim/start (anim/spring val {:toValue @offset}))))
|
||||
|
||||
(defn messages-container [messages]
|
||||
(let [to-messages-offset (subscribe [:animations :messages-offset])
|
||||
cur-messages-offset (subscribe [:animations ::messages-offset-current])
|
||||
messages-offset (anim/create-value (or @cur-messages-offset 0))
|
||||
context {:to-value to-messages-offset
|
||||
:val messages-offset}
|
||||
(let [offset (subscribe [:messages-offset])
|
||||
messages-offset (anim/create-value 0)
|
||||
context {:offset offset
|
||||
:val messages-offset}
|
||||
on-update (messages-container-animation-logic context)]
|
||||
(r/create-class
|
||||
{:component-did-mount
|
||||
@ -251,7 +246,7 @@
|
||||
on-update
|
||||
:reagent-render
|
||||
(fn [messages]
|
||||
@to-messages-offset
|
||||
@offset
|
||||
[animated-view {:style (st/messages-container messages-offset)}
|
||||
messages])})))
|
||||
|
||||
@ -260,16 +255,19 @@
|
||||
show-actions-atom [:show-actions]
|
||||
command [:get-chat-command]
|
||||
command? [:command?]
|
||||
to-msg-id [:get-chat-command-to-msg-id]]
|
||||
[view {:style st/chat-view
|
||||
suggestions [:get-suggestions]
|
||||
to-msg-id [:get-chat-command-to-msg-id]
|
||||
layout-height [:get :layout-height]]
|
||||
[view {:style st/chat-view
|
||||
:onLayout (fn [event]
|
||||
(let [height (.. event -nativeEvent -layout -height)]
|
||||
(dispatch [:set-response-max-height height])))}
|
||||
(when (not= height layout-height)
|
||||
(dispatch [:set-layout-height height]))))}
|
||||
[chat-toolbar]
|
||||
[messages-container
|
||||
[messages-view group-chat]]
|
||||
(when group-chat [typing-all])
|
||||
[response-view]
|
||||
(when-not command? [suggestions-view])
|
||||
(when-not command? [suggestion-container])
|
||||
[chat-message-new]
|
||||
(when show-actions-atom [actions-view])])
|
||||
|
@ -173,7 +173,7 @@
|
||||
(dispatch [:received-msg
|
||||
{:msg-id msg-id
|
||||
:content (command-content
|
||||
:keypair-password
|
||||
:keypair
|
||||
(label :t/keypair-generated))
|
||||
:content-type content-type-command-request
|
||||
:outgoing false
|
||||
@ -184,6 +184,9 @@
|
||||
(def console-chat
|
||||
{:chat-id "console"
|
||||
:name "console"
|
||||
; todo remove/change dapp config fot console
|
||||
:dapp-url "http://localhost:8185/resources"
|
||||
:dapp-hash 858845357
|
||||
:color default-chat-color
|
||||
:group-chat false
|
||||
:is-active true
|
||||
|
@ -1,22 +1,21 @@
|
||||
(ns status-im.chat.styles.content-suggestions
|
||||
(:require [status-im.components.styles :refer [font
|
||||
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]]))
|
||||
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 suggestion-height 56)
|
||||
|
||||
(def suggestion-container
|
||||
{:flexDirection :column
|
||||
:paddingLeft 16
|
||||
{:paddingLeft 16
|
||||
:backgroundColor color-white})
|
||||
|
||||
(def suggestion-sub-container
|
||||
@ -37,7 +36,7 @@
|
||||
:color text2-color})
|
||||
|
||||
(defn suggestions-container [suggestions-count]
|
||||
{:flexDirection :row
|
||||
{:flex 1
|
||||
:marginVertical 1
|
||||
:marginHorizontal 0
|
||||
:height (min 150 (* suggestion-height suggestions-count))
|
||||
@ -46,12 +45,3 @@
|
||||
|
||||
(def container
|
||||
{:backgroundColor color-white})
|
||||
|
||||
(def drag-down-touchable
|
||||
{:height 22
|
||||
:alignItems :center
|
||||
:justifyContent :center})
|
||||
|
||||
(def drag-down-icon
|
||||
{:width 16
|
||||
:height 16})
|
||||
|
12
src/status_im/chat/styles/dragdown.cljs
Normal file
12
src/status_im/chat/styles/dragdown.cljs
Normal file
@ -0,0 +1,12 @@
|
||||
(ns status-im.chat.styles.dragdown
|
||||
(:require [status-im.components.styles :refer [color-white]]))
|
||||
|
||||
(def drag-down-touchable
|
||||
{:height 22
|
||||
:background-color color-white
|
||||
:alignItems :center
|
||||
:justifyContent :center})
|
||||
|
||||
(def drag-down-icon
|
||||
{:width 16
|
||||
:height 16})
|
@ -16,13 +16,18 @@
|
||||
:backgroundColor color-white
|
||||
:elevation 4})
|
||||
|
||||
(def command-container
|
||||
{:left 0
|
||||
:backgroundColor :white
|
||||
:position :absolute})
|
||||
|
||||
(defn command-text-container
|
||||
[{:keys [color]}]
|
||||
{:flexDirection :column
|
||||
:marginTop 16
|
||||
:marginBottom 16
|
||||
:marginLeft 16
|
||||
:marginRight 0
|
||||
:marginRight 8
|
||||
:backgroundColor color
|
||||
:height 24
|
||||
:borderRadius 50})
|
||||
|
@ -1,15 +1,15 @@
|
||||
(ns status-im.chat.styles.message
|
||||
(:require [status-im.components.styles :refer [font
|
||||
color-light-blue-transparent
|
||||
color-white
|
||||
color-black
|
||||
color-blue
|
||||
selected-message-color
|
||||
online-color
|
||||
text1-color
|
||||
text2-color]]
|
||||
color-light-blue-transparent
|
||||
color-white
|
||||
color-black
|
||||
color-blue
|
||||
selected-message-color
|
||||
online-color
|
||||
text1-color
|
||||
text2-color]]
|
||||
[status-im.constants :refer [text-content-type
|
||||
content-type-command]]))
|
||||
content-type-command]]))
|
||||
|
||||
(def style-message-text
|
||||
{:fontSize 14
|
||||
@ -153,6 +153,14 @@
|
||||
:backgroundColor (:color command)
|
||||
:transform [{:scale scale}]})
|
||||
|
||||
(def command-image-view
|
||||
{:position :absolute
|
||||
:top 0
|
||||
:right 0
|
||||
:width 24
|
||||
:height 24
|
||||
:alignItems :center})
|
||||
|
||||
(def command-request-image
|
||||
{:position :absolute
|
||||
:top 9
|
||||
@ -185,11 +193,10 @@
|
||||
:color color-white})
|
||||
|
||||
(def command-image
|
||||
{:position :absolute
|
||||
:top 4
|
||||
:right 0
|
||||
:width 12
|
||||
:height 13})
|
||||
{:margin-top 5
|
||||
:width 12
|
||||
:height 13
|
||||
:tint-color :#a9a9a9cc})
|
||||
|
||||
(def command-text
|
||||
(merge style-message-text
|
||||
|
@ -1,11 +1,10 @@
|
||||
(ns status-im.chat.styles.message-input
|
||||
(:require [status-im.components.styles :refer [color-white
|
||||
color-blue]]))
|
||||
|
||||
(def input-height 56)
|
||||
color-blue]]
|
||||
[status-im.chat.constants :refer [input-height]]))
|
||||
|
||||
(def message-input-container
|
||||
{:flex 1
|
||||
{:flex 1
|
||||
:marginRight 0})
|
||||
|
||||
(def input-container
|
||||
|
@ -9,11 +9,24 @@
|
||||
:justifyContent :center})
|
||||
|
||||
(defn message-input-button [scale]
|
||||
{:transform [{:scale scale}]})
|
||||
{:transform [{:scale scale}]
|
||||
:width 24
|
||||
:height 24
|
||||
:alignItems :center
|
||||
:justifyContent :center})
|
||||
|
||||
(def list-icon
|
||||
{:width 13
|
||||
:height 12})
|
||||
{:width 16
|
||||
:height 16})
|
||||
|
||||
(def requests-icon
|
||||
{:background-color :#7099e6
|
||||
:width 8
|
||||
:height 8
|
||||
:border-radius 8
|
||||
:left 0
|
||||
:top 0
|
||||
:position :absolute})
|
||||
|
||||
(def close-icon
|
||||
{:width 12
|
||||
|
@ -6,10 +6,8 @@
|
||||
text2-color
|
||||
chat-background
|
||||
color-black]]
|
||||
[status-im.chat.styles.message-input :refer [input-height]]))
|
||||
|
||||
(def response-height-normal 211)
|
||||
(def request-info-height 61)
|
||||
[status-im.chat.constants :refer [input-height request-info-height
|
||||
response-height-normal]]))
|
||||
|
||||
(def drag-container
|
||||
{:height 16
|
||||
@ -85,11 +83,12 @@
|
||||
:width 12
|
||||
:height 12})
|
||||
|
||||
(def command-input
|
||||
(defn command-input [ml disbale?]
|
||||
{:flex 1
|
||||
:marginRight 16
|
||||
:margin-left (- ml 5)
|
||||
:marginTop -2
|
||||
:padding 0
|
||||
:fontSize 14
|
||||
:fontFamily font
|
||||
:color text1-color})
|
||||
:color (if disbale? color-white text1-color)})
|
||||
|
@ -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})
|
@ -1,33 +1,44 @@
|
||||
(ns status-im.chat.styles.suggestions
|
||||
(:require [status-im.components.styles :refer [font
|
||||
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]]))
|
||||
color-light-blue-transparent
|
||||
color-white
|
||||
color-black
|
||||
color-gray
|
||||
color-blue
|
||||
color-blue-transparent
|
||||
selected-message-color
|
||||
online-color
|
||||
separator-color
|
||||
text1-color
|
||||
text2-color
|
||||
text3-color]]))
|
||||
|
||||
(def suggestion-height 88)
|
||||
(def suggestion-height 60)
|
||||
|
||||
(def suggestion-highlight
|
||||
{:margin-left 57})
|
||||
|
||||
(def suggestion-container
|
||||
{:flexDirection :column
|
||||
:paddingLeft 16
|
||||
:backgroundColor color-white})
|
||||
{:backgroundColor color-white})
|
||||
|
||||
(def suggestion-sub-container
|
||||
{:height suggestion-height
|
||||
:borderBottomWidth 1
|
||||
:borderBottomColor separator-color})
|
||||
:borderBottomColor separator-color
|
||||
:flex-direction :row})
|
||||
|
||||
(def command-description-container
|
||||
{:flex 0.6})
|
||||
|
||||
(def command-label-container
|
||||
{:flex 0.4
|
||||
:flex-direction :column
|
||||
:align-items :flex-end
|
||||
:margin-right 16})
|
||||
|
||||
(defn suggestion-background
|
||||
[{:keys [color]}]
|
||||
{:alignSelf :flex-start
|
||||
:marginTop 10
|
||||
{:marginTop 10
|
||||
:height 24
|
||||
:backgroundColor color
|
||||
:borderRadius 50})
|
||||
@ -39,6 +50,14 @@
|
||||
:fontFamily font
|
||||
:color color-white})
|
||||
|
||||
(def title-container
|
||||
{:margin-left 57
|
||||
:margin-bottom 16})
|
||||
|
||||
(def title-text
|
||||
{:font-size 13
|
||||
:color :#8f838c93})
|
||||
|
||||
(def value-text
|
||||
{:marginTop 6
|
||||
:fontSize 14
|
||||
@ -51,22 +70,53 @@
|
||||
:fontFamily font
|
||||
:color text2-color})
|
||||
|
||||
(defn suggestions-container [suggestions-count]
|
||||
{:flexDirection :row
|
||||
:marginVertical 1
|
||||
:marginHorizontal 0
|
||||
:height (min 168 (* suggestion-height suggestions-count))
|
||||
:backgroundColor color-white
|
||||
:borderRadius 5})
|
||||
(defn container [height]
|
||||
{:flexDirection :column
|
||||
:position :absolute
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
:height height
|
||||
:backgroundColor color-white
|
||||
:elevation 2})
|
||||
|
||||
(def container
|
||||
{:backgroundColor color-white})
|
||||
(def request-container
|
||||
{:height 56
|
||||
:flex-direction :row})
|
||||
|
||||
(def drag-down-touchable
|
||||
{:height 22
|
||||
:alignItems :center
|
||||
(def request-icon-container
|
||||
{:height 56
|
||||
:width 57
|
||||
:align-items :center
|
||||
:justifyContent :center})
|
||||
|
||||
(def drag-down-icon
|
||||
{:width 16
|
||||
:height 16})
|
||||
(defn request-icon-background [color]
|
||||
{:height 32
|
||||
:width 32
|
||||
:border-radius 32
|
||||
:background-color color
|
||||
:align-items :center
|
||||
:justifyContent :center})
|
||||
|
||||
(def request-icon
|
||||
{:width 12
|
||||
:height 12})
|
||||
|
||||
(def request-info-container
|
||||
{:height 56
|
||||
:padding-top 10})
|
||||
|
||||
(def request-info-description
|
||||
{:font-size 12
|
||||
:color color-black})
|
||||
|
||||
(def request-message-info
|
||||
{:font-size 12
|
||||
:margin-top 2
|
||||
:color color-gray})
|
||||
|
||||
(def header-icon
|
||||
{:background-color :#838c93
|
||||
:width 14
|
||||
:border-radius 1
|
||||
:height 3})
|
||||
|
@ -1,12 +1,9 @@
|
||||
(ns status-im.chat.subs
|
||||
(:require-macros [reagent.ratom :refer [reaction]])
|
||||
(:require [re-frame.core :refer [register-sub dispatch subscribe]]
|
||||
[status-im.db :as db]
|
||||
;todo handlers in subs?...
|
||||
[status-im.chat.suggestions :refer
|
||||
[get-suggestions typing-command?]]
|
||||
(:require [re-frame.core :refer [register-sub dispatch subscribe path]]
|
||||
[status-im.models.commands :as commands]
|
||||
[status-im.constants :refer [response-suggesstion-resize-duration]]
|
||||
[status-im.chat.constants :as c]
|
||||
[status-im.handlers.content-suggestions :refer [get-content-suggestions]]
|
||||
[status-im.chat.views.plain-message :as plain-message]
|
||||
[status-im.chat.views.command :as command]))
|
||||
@ -43,16 +40,25 @@
|
||||
|
||||
(register-sub :get-suggestions
|
||||
(fn [db _]
|
||||
(let [input-text (->> (:current-chat-id @db)
|
||||
db/chat-input-text-path
|
||||
(get-in @db)
|
||||
(reaction))]
|
||||
(reaction (get-suggestions @db @input-text)))))
|
||||
(let [chat-id (subscribe [:get-current-chat-id])]
|
||||
(reaction (get-in @db [:command-suggestions @chat-id])))))
|
||||
|
||||
(register-sub :get-commands
|
||||
(fn [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
|
||||
(fn [db _]
|
||||
(->> [:chats (:current-chat-id @db) :input-text]
|
||||
@ -67,7 +73,7 @@
|
||||
|
||||
(register-sub :valid-plain-message?
|
||||
(fn [_ _]
|
||||
(let [input-message (subscribe [:get-chat-input-text])
|
||||
(let [input-message (subscribe [:get-chat-input-text])
|
||||
staged-commands (subscribe [:get-chat-staged-commands])]
|
||||
(reaction
|
||||
(plain-message/message-valid? @staged-commands @input-message)))))
|
||||
@ -81,6 +87,15 @@
|
||||
(fn [db _]
|
||||
(reaction (commands/get-chat-command @db))))
|
||||
|
||||
(register-sub :get-command-parameter
|
||||
(fn [db]
|
||||
(let [command (subscribe [:get-chat-command])
|
||||
chat-id (subscribe [:get-current-chat-id])]
|
||||
(reaction
|
||||
(let [path [:chats @chat-id :command-input :parameter-idx]
|
||||
n (get-in @db path)]
|
||||
(when n (nth (:params @command) n)))))))
|
||||
|
||||
(register-sub :get-chat-command-content
|
||||
(fn [db _]
|
||||
(reaction (commands/get-chat-command-content @db))))
|
||||
@ -102,18 +117,58 @@
|
||||
(fn [db [_ chat-id]]
|
||||
(reaction (get-in @db [:chats chat-id]))))
|
||||
|
||||
(register-sub :typing-command?
|
||||
(fn [db _]
|
||||
(reaction (typing-command? @db))))
|
||||
|
||||
(register-sub :get-content-suggestions
|
||||
(fn [db _]
|
||||
(let [command (reaction (commands/get-chat-command @db))
|
||||
text (reaction (commands/get-chat-command-content @db))]
|
||||
(reaction (get-content-suggestions @command @text)))))
|
||||
(reaction (get-in @db [:suggestions (:current-chat-id @db)]))))
|
||||
|
||||
(register-sub :command?
|
||||
(fn [db ]
|
||||
(fn [db]
|
||||
(->> (get-in @db [:edit-mode (:current-chat-id @db)])
|
||||
(= :command)
|
||||
(reaction))))
|
||||
|
||||
(register-sub :command-type
|
||||
(fn []
|
||||
(let [command (subscribe [:get-chat-command])]
|
||||
(reaction (:type @command)))))
|
||||
|
||||
(register-sub :messages-offset
|
||||
(fn []
|
||||
(let [command? (subscribe [:command?])
|
||||
type (subscribe [:command-type])
|
||||
command-suggestions (subscribe [:get-content-suggestions])
|
||||
suggestions (subscribe [:get-suggestions])]
|
||||
(reaction
|
||||
(cond (and @command? (= @type :response))
|
||||
c/request-info-height
|
||||
|
||||
(and @command? (= @type :command) (seq @command-suggestions))
|
||||
c/suggestions-header-height
|
||||
|
||||
(and (not @command?) (seq @suggestions))
|
||||
c/suggestions-header-height
|
||||
|
||||
:else 0)))))
|
||||
|
||||
(register-sub :command-icon-width
|
||||
(fn []
|
||||
(let [width (subscribe [:get :command-icon-width])
|
||||
type (subscribe [:command-type])]
|
||||
(reaction (if (= :command @type)
|
||||
@width
|
||||
0)))))
|
||||
|
||||
(register-sub :get-requests
|
||||
(fn [db]
|
||||
(let [chat-id (subscribe [:get-current-chat-id])]
|
||||
(reaction (get-in @db [:chats @chat-id :requests])))))
|
||||
|
||||
(register-sub :get-response
|
||||
(fn [db [_ n]]
|
||||
(let [chat-id (subscribe [:get-current-chat-id])]
|
||||
(reaction (get-in @db [:chats @chat-id :responses n])))))
|
||||
|
||||
(register-sub :is-request-answered?
|
||||
(fn [_ [_ message-id]]
|
||||
(let [requests (subscribe [:get-requests])]
|
||||
(reaction (not (some #(= message-id (:message-id %)) @requests))))))
|
||||
|
@ -1,23 +1,26 @@
|
||||
(ns status-im.chat.suggestions
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[status-im.db :as db]
|
||||
[status-im.models.commands :refer [commands
|
||||
suggestions
|
||||
get-commands
|
||||
get-chat-command-request
|
||||
get-chat-command-to-msg-id
|
||||
clear-staged-commands]]
|
||||
[status-im.models.commands :refer [get-commands
|
||||
get-chat-command-request
|
||||
get-chat-command-to-msg-id
|
||||
clear-staged-commands]]
|
||||
[status-im.utils.utils :refer [log on-error http-get]]
|
||||
[clojure.string :as s]))
|
||||
|
||||
(defn suggestion? [text]
|
||||
(= (get text 0) "!"))
|
||||
|
||||
(defn get-suggestions [db text]
|
||||
(if (suggestion? text)
|
||||
;; TODO change 'commands' to 'suggestions'
|
||||
(filterv #(.startsWith (:text %) text) (get-commands db))
|
||||
[]))
|
||||
(defn can-be-suggested? [text]
|
||||
(fn [{:keys [name]}]
|
||||
(.startsWith (str "!" name) text)))
|
||||
|
||||
(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]
|
||||
(when (suggestion? text)
|
||||
@ -45,22 +48,13 @@
|
||||
staged-commands))
|
||||
(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]
|
||||
(when-let [suggestion-text (when (string? message)
|
||||
(re-matches #"^![^\s]+\s" message))]
|
||||
(let [suggestion-text' (s/trim suggestion-text)
|
||||
[suggestion] (filter #(= suggestion-text' (:text %))
|
||||
(get-commands db))]
|
||||
suggestion)))
|
||||
(let [suggestion-text' (s/trim suggestion-text)]
|
||||
(->> (get-commands db)
|
||||
(filter #(= suggestion-text' (->> % second :name (str "!"))))
|
||||
first))))
|
||||
|
||||
(defn typing-command? [db]
|
||||
(-> db
|
||||
|
39
src/status_im/chat/suggestions_responder.cljs
Normal file
39
src/status_im/chat/suggestions_responder.cljs
Normal file
@ -0,0 +1,39 @@
|
||||
(ns status-im.chat.suggestions-responder
|
||||
(:require [status-im.components.drag-drop :as drag]
|
||||
[status-im.components.animation :as anim]
|
||||
[status-im.components.react :as react]
|
||||
[re-frame.core :refer [dispatch]]))
|
||||
|
||||
;; todo bad name. Ideas?
|
||||
(defn enough-dy [gesture]
|
||||
(> (Math/abs (.-dy gesture)) 10))
|
||||
|
||||
(defn on-move [response-height kb-height orientation]
|
||||
(fn [_ gesture]
|
||||
(when (enough-dy gesture)
|
||||
(let [w (react/get-dimensions "window")
|
||||
;; depending on orientation use height or width of screen
|
||||
prop (if (= :portrait @orientation)
|
||||
:height
|
||||
:width)
|
||||
;; subtract keyboard height to get "real height" of screen
|
||||
;; then subtract gesture position to get suggestions height
|
||||
;; todo maybe it is better to use margin-top instead height
|
||||
;; it is not obvious
|
||||
to-value (- (prop w) @kb-height (.-moveY gesture))]
|
||||
(anim/start
|
||||
(anim/spring response-height {:toValue to-value}))))))
|
||||
|
||||
(defn on-release [response-height handler-name]
|
||||
(fn [_ gesture]
|
||||
(when (enough-dy gesture)
|
||||
(dispatch [handler-name
|
||||
(.-vy gesture)
|
||||
;; todo access to "private" property
|
||||
;; better to find another way...
|
||||
(.-_value response-height)]))))
|
||||
|
||||
(defn pan-responder [response-height kb-height orientation handler-name]
|
||||
(drag/create-pan-responder
|
||||
{:on-move (on-move response-height kb-height orientation)
|
||||
:on-release (on-release response-height handler-name)}))
|
@ -27,11 +27,18 @@
|
||||
(when (valid? message validator)
|
||||
(send-command)))
|
||||
|
||||
(defn command-icon [command]
|
||||
[view (st/command-text-container command)
|
||||
[text {:style st/command-text} (:text command)]])
|
||||
(defview command-icon [command]
|
||||
[icon-width [:get :command-icon-width]]
|
||||
[view st/command-container
|
||||
[view {:style (st/command-text-container command)
|
||||
:onLayout (fn [event]
|
||||
(let [width (.. event -nativeEvent -layout -width)]
|
||||
(when (not= icon-width width)
|
||||
(dispatch [:set :command-icon-width width]))))}
|
||||
[text {:style st/command-text} (str "!" (:name command))]]])
|
||||
|
||||
(defn cancel-button []
|
||||
[touchable-highlight {:on-press cancel-command-input}
|
||||
[view st/cancel-container
|
||||
[icon :close-gray st/cancel-icon]]])
|
||||
|
||||
|
@ -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}]]]))
|
@ -1,11 +1,12 @@
|
||||
(ns status-im.chat.views.message
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [clojure.string :as s]
|
||||
[re-frame.core :refer [subscribe dispatch]]
|
||||
[reagent.core :as r]
|
||||
[status-im.components.react :refer [view
|
||||
animated-view
|
||||
text
|
||||
image
|
||||
animated-view
|
||||
touchable-highlight]]
|
||||
[status-im.components.animation :as anim]
|
||||
[status-im.chat.views.request-message :refer [message-content-command-request]]
|
||||
@ -55,24 +56,29 @@
|
||||
[view st/track-mark]
|
||||
[text {:style st/track-duration-text} "03:39"]]])
|
||||
|
||||
(defn message-content-command [content]
|
||||
(let [commands-atom (subscribe [:get-commands])]
|
||||
(fn [content]
|
||||
(let [commands @commands-atom
|
||||
{:keys [command content]}
|
||||
(parse-command-msg-content commands content)]
|
||||
[view st/content-command-view
|
||||
[view st/command-container
|
||||
[view (st/command-view command)
|
||||
[text {:style st/command-name}
|
||||
(:text command)]]]
|
||||
[image {:source (:icon command)
|
||||
:style st/command-image}]
|
||||
[text {:style st/command-text}
|
||||
;; TODO isn't smart
|
||||
(if (= (:command command) :keypair-password)
|
||||
"******"
|
||||
content)]]))))
|
||||
(defview message-content-command [content preview]
|
||||
[commands [:get-commands-and-responses]]
|
||||
(let [{:keys [command content]} (parse-command-msg-content commands content)
|
||||
{:keys [name icon type]} command]
|
||||
[view st/content-command-view
|
||||
[view st/command-container
|
||||
[view (st/command-view command)
|
||||
[text {:style st/command-name}
|
||||
(str (if (= :command type) "!" "") name)]]]
|
||||
(when icon
|
||||
[view st/command-image-view
|
||||
[image {:source {:uri icon}
|
||||
:style st/command-image}]])
|
||||
(if preview
|
||||
preview
|
||||
[text {:style st/command-text} 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-")))
|
||||
|
||||
(defn message-view
|
||||
[message content]
|
||||
@ -103,9 +109,9 @@
|
||||
[message-content-status message])
|
||||
|
||||
(defmethod message-content content-type-command
|
||||
[wrapper {:keys [content] :as message}]
|
||||
[wrapper {:keys [content rendered-preview] :as message}]
|
||||
[wrapper message
|
||||
[message-view message [message-content-command content]]])
|
||||
[message-view message [message-content-command content rendered-preview]]])
|
||||
|
||||
(defmethod message-content :default
|
||||
[wrapper {:keys [content-type content] :as message}]
|
||||
|
@ -6,7 +6,6 @@
|
||||
icon
|
||||
touchable-highlight
|
||||
text-input]]
|
||||
[status-im.components.animation :as anim]
|
||||
[status-im.chat.views.plain-message :as plain-message]
|
||||
[status-im.chat.views.command :as command]
|
||||
[status-im.chat.styles.message-input :as st]
|
||||
@ -22,24 +21,27 @@
|
||||
(defn message-input-container [input]
|
||||
[view st/message-input-container input])
|
||||
|
||||
(def plain-input-options
|
||||
(defn plain-input-options [disbale?]
|
||||
{:style st-message/message-input
|
||||
:onChangeText plain-message/set-input-message
|
||||
:onChangeText (when-not disbale? plain-message/set-input-message)
|
||||
:editable (not disbale?)
|
||||
:onSubmitEditing plain-message/send})
|
||||
|
||||
(def command-input-options
|
||||
{:style st-response/command-input
|
||||
:onChangeText command/set-input-message
|
||||
(defn command-input-options [icon-width disbale?]
|
||||
{:style (st-response/command-input icon-width disbale?)
|
||||
:onChangeText (when-not disbale? command/set-input-message)
|
||||
:onSubmitEditing command/send-command})
|
||||
|
||||
(defview message-input [input-options]
|
||||
[command? [:command?]
|
||||
input-message [:get-chat-input-text]
|
||||
input-command [:get-chat-command-content]]
|
||||
input-command [:get-chat-command-content]
|
||||
icon-width [:command-icon-width]
|
||||
disbale? [:get :disable-input]]
|
||||
[text-input (merge
|
||||
(if command?
|
||||
command-input-options
|
||||
plain-input-options)
|
||||
(command-input-options icon-width disbale?)
|
||||
(plain-input-options disbale?))
|
||||
{:autoFocus false
|
||||
:blurOnSubmit false
|
||||
:accessibility-label :input}
|
||||
@ -48,6 +50,7 @@
|
||||
|
||||
(defview plain-message-input-view [{:keys [input-options validator]}]
|
||||
[command? [:command?]
|
||||
{:keys [type] :as command} [:get-chat-command]
|
||||
input-command [:get-chat-command-content]
|
||||
valid-plain-message? [:valid-plain-message?]
|
||||
valid-command? [:valid-command? validator]]
|
||||
@ -63,4 +66,6 @@
|
||||
command/send-command
|
||||
plain-message/send)]
|
||||
[send-button {:on-press on-press
|
||||
:accessibility-label :send-message}]))]])
|
||||
:accessibility-label :send-message}]))
|
||||
(when (and command? (= :command type))
|
||||
[command/command-icon command])]])
|
||||
|
@ -16,23 +16,30 @@
|
||||
(for [command staged-commands]
|
||||
^{:key command} [staged-command-view command])])
|
||||
|
||||
(defn get-options [{:keys [type placeholder]} command-type]
|
||||
(let [options (case (keyword type)
|
||||
:phone {:input-options {:keyboardType :phone-pad}
|
||||
:validator valid-mobile-number?}
|
||||
:password {:input-options {:secureTextEntry true}}
|
||||
:number {:input-options {:keyboardType :numeric}}
|
||||
;; todo maybe nil is fine for now :)
|
||||
nil #_(throw (js/Error. "Uknown command type")))]
|
||||
(if (= :response command-type)
|
||||
(if placeholder
|
||||
(assoc-in options [:input-options :placeholder] placeholder)
|
||||
options)
|
||||
(assoc-in options [:input-options :placeholder] ""))))
|
||||
|
||||
(defview show-input []
|
||||
[command [:get-chat-command]
|
||||
command? [:command?]]
|
||||
[parameter [:get-command-parameter]
|
||||
command? [:command?]
|
||||
type [:command-type]]
|
||||
[plain-message-input-view
|
||||
(when command?
|
||||
(case (:command command)
|
||||
:phone {:input-options {:keyboardType :phone-pad}
|
||||
:validator valid-mobile-number?}
|
||||
:keypair-password {:input-options {:secureTextEntry true}}
|
||||
:confirmation-code {:input-options {:keyboardType :numeric}}
|
||||
:money {:input-options {:keyboardType :numeric}}
|
||||
:request {:input-options {:keyboardType :numeric}}
|
||||
(throw (js/Error. "Uknown command type"))))])
|
||||
(when command? (get-options parameter type))])
|
||||
|
||||
(defview chat-message-new []
|
||||
[staged-commands [:get-chat-staged-commands]]
|
||||
[view st/new-message-container
|
||||
(when (and staged-commands (pos? (count staged-commands)))
|
||||
(when (seq staged-commands)
|
||||
[staged-commands-view staged-commands])
|
||||
[show-input]])
|
||||
|
@ -5,6 +5,7 @@
|
||||
[status-im.components.react :refer [view
|
||||
animated-view
|
||||
icon
|
||||
text
|
||||
touchable-highlight]]
|
||||
[status-im.components.animation :as anim]
|
||||
[status-im.chat.styles.plain-message :as st]
|
||||
@ -24,7 +25,8 @@
|
||||
(defn button-animation-logic [{:keys [command? val]}]
|
||||
(fn [_]
|
||||
(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]
|
||||
(fn [{:keys [command? width]}]
|
||||
@ -32,18 +34,21 @@
|
||||
delay (if @command? 100 0)]
|
||||
(anim/start (anim/timing width {:toValue n-width
|
||||
:duration response-input-hiding-duration
|
||||
:delay delay})))))
|
||||
:delay delay})
|
||||
#(dispatch [:set :disable-input false])))))
|
||||
|
||||
(defn commands-button []
|
||||
(let [command? (subscribe [:command?])
|
||||
buttons-scale (anim/create-value (if @command? 1 0))
|
||||
(let [command? (subscribe [:command?])
|
||||
requests (subscribe [:get-requests])
|
||||
suggestions (subscribe [:get-suggestions])
|
||||
buttons-scale (anim/create-value (if @command? 1 0))
|
||||
container-width (anim/create-value (if @command? 20 56))
|
||||
context {:command? command?
|
||||
:val buttons-scale
|
||||
:width container-width}
|
||||
on-update (fn [_]
|
||||
((button-animation-logic context))
|
||||
((list-container 20) context))]
|
||||
context {:command? command?
|
||||
:val buttons-scale
|
||||
:width container-width}
|
||||
on-update (fn [_]
|
||||
((button-animation-logic context))
|
||||
((list-container 20) context))]
|
||||
(r/create-class
|
||||
{:component-did-mount
|
||||
on-update
|
||||
@ -51,29 +56,35 @@
|
||||
on-update
|
||||
:reagent-render
|
||||
(fn []
|
||||
[touchable-highlight {:on-press #(dispatch [:switch-command-suggestions])
|
||||
[touchable-highlight {:on-press #(dispatch [:switch-command-suggestions!])
|
||||
:disabled @command?}
|
||||
[animated-view {:style (st/message-input-button-touchable
|
||||
container-width)}
|
||||
[animated-view {:style (st/message-input-button buttons-scale)}
|
||||
[icon :list st/list-icon]]]])})))
|
||||
(if (seq @suggestions)
|
||||
[icon :close_gray st/close-icon]
|
||||
[icon :input_list st/list-icon])
|
||||
(when (and (seq @requests)
|
||||
(not (seq @suggestions)))
|
||||
[view st/requests-icon])]]])})))
|
||||
|
||||
(defn smile-animation-logic [{:keys [command? val width]}]
|
||||
(fn [_]
|
||||
(let [to-scale (if @command? 0 1)]
|
||||
(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]
|
||||
(when (and @command? (.-finished e))
|
||||
(anim/set-value width 0.1)))))))
|
||||
|
||||
(defn smile-button []
|
||||
(let [command? (subscribe [:command?])
|
||||
(let [command? (subscribe [:command?])
|
||||
buttons-scale (anim/create-value (if @command? 1 0))
|
||||
container-width (anim/create-value (if @command? 0.1 56))
|
||||
context {:command? command?
|
||||
:val buttons-scale
|
||||
:width container-width}
|
||||
context {:command? command?
|
||||
:val buttons-scale
|
||||
:width container-width}
|
||||
on-update (smile-animation-logic context)]
|
||||
(r/create-class
|
||||
{:component-did-mount
|
||||
|
@ -13,61 +13,60 @@
|
||||
(def request-message-icon-scale-delay 600)
|
||||
|
||||
(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]}]
|
||||
(->> (name command)
|
||||
(str "request-")))
|
||||
|
||||
(defn request-button-animation-logic [{:keys [to-value val loop?]}]
|
||||
(fn [_]
|
||||
(let [loop? @loop?
|
||||
minimum 1
|
||||
maximum 1.3
|
||||
to-scale (if loop?
|
||||
(or @to-value maximum)
|
||||
minimum)]
|
||||
(def min-scale 1)
|
||||
(def max-scale 1.3)
|
||||
|
||||
(defn button-animation [val to-value loop? answered?]
|
||||
(anim/anim-sequence
|
||||
[(anim/anim-delay
|
||||
(if (and @loop? (not @answered?))
|
||||
request-message-icon-scale-delay
|
||||
0))
|
||||
(anim/spring val {:toValue to-value})]))
|
||||
|
||||
(defn request-button-animation-logic
|
||||
[{:keys [to-value val loop? answered?] :as context}]
|
||||
(anim/start
|
||||
(button-animation val to-value loop? answered?)
|
||||
#(if (and @loop? (not @answered?))
|
||||
(let [new-value (if (= to-value min-scale) max-scale min-scale)
|
||||
context' (assoc context :to-value new-value)]
|
||||
(request-button-animation-logic context'))
|
||||
(anim/start
|
||||
(anim/anim-sequence
|
||||
[(anim/anim-delay (if loop? request-message-icon-scale-delay 0))
|
||||
(anim/spring val {:toValue to-scale})])
|
||||
(fn [arg]
|
||||
(when (.-finished arg)
|
||||
(dispatch [:set-animation ::request-button-scale-current to-scale])
|
||||
(when loop?
|
||||
(dispatch [:set-animation ::request-button-scale (if (= to-scale minimum)
|
||||
maximum
|
||||
minimum)]))))))))
|
||||
(button-animation val min-scale loop? answered?)))))
|
||||
|
||||
(defn request-button [msg-id command]
|
||||
(let [to-scale (subscribe [:animations ::request-button-scale])
|
||||
cur-scale (subscribe [:animations ::request-button-scale-current])
|
||||
scale-anim-val (anim/create-value (or @cur-scale 1))
|
||||
(let [scale-anim-val (anim/create-value min-scale)
|
||||
answered? (subscribe [:is-request-answered? msg-id])
|
||||
loop? (r/atom true)
|
||||
context {:to-value to-scale
|
||||
:val scale-anim-val
|
||||
:loop? loop?}
|
||||
on-update (request-button-animation-logic context)]
|
||||
context {:to-value max-scale
|
||||
:val scale-anim-val
|
||||
:answered? answered?
|
||||
:loop? loop?}]
|
||||
(r/create-class
|
||||
{:component-did-mount
|
||||
on-update
|
||||
:component-did-update
|
||||
on-update
|
||||
(when-not @answered? #(request-button-animation-logic context))
|
||||
:component-will-unmount
|
||||
#(reset! loop? false)
|
||||
:reagent-render
|
||||
(fn [msg-id command]
|
||||
@to-scale
|
||||
[touchable-highlight {:on-press (fn []
|
||||
(reset! loop? false)
|
||||
(set-chat-command msg-id command))
|
||||
:style st/command-request-image-touchable
|
||||
:accessibility-label (label command)}
|
||||
[touchable-highlight
|
||||
{:on-press (when-not @answered?
|
||||
#(set-chat-command msg-id command))
|
||||
:style st/command-request-image-touchable}
|
||||
[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}]]])})))
|
||||
|
||||
(defn message-content-command-request
|
||||
[{: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]}]
|
||||
(let [commands @commands-atom
|
||||
{:keys [command content]} (parse-command-request commands content)]
|
||||
|
@ -11,11 +11,10 @@
|
||||
text-input
|
||||
touchable-highlight]]
|
||||
[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.message-input :refer [input-height]]
|
||||
[status-im.chat.styles.dragdown :as ddst]
|
||||
[status-im.components.animation :as anim]
|
||||
[status-im.components.react :as react]))
|
||||
[status-im.chat.suggestions-responder :as resp]))
|
||||
|
||||
(defn drag-icon []
|
||||
[view st/drag-container
|
||||
@ -34,70 +33,41 @@
|
||||
;; TODO stub data: request message info
|
||||
"By ???, MMM 1st at HH:mm"]])
|
||||
|
||||
;; todo bad name. Ideas?
|
||||
(defn enough-dy [gesture]
|
||||
(> (Math/abs (.-dy gesture)) 10))
|
||||
|
||||
(defn on-move [response-height kb-height orientation]
|
||||
(fn [_ gesture]
|
||||
(when (enough-dy gesture)
|
||||
(let [w (react/get-dimensions "window")
|
||||
;; depending on orientation use height or width of screen
|
||||
prop (if (= :portrait @orientation)
|
||||
:height
|
||||
:width)
|
||||
;; subtract keyboard height to get "real height" of screen
|
||||
;; then subtract gesture position to get suggestions height
|
||||
;; todo maybe it is better to use margin-top instead height
|
||||
;; it is not obvious
|
||||
to-value (- (prop w) @kb-height (.-moveY gesture))]
|
||||
(println to-value )
|
||||
(anim/start
|
||||
(anim/spring response-height {:toValue to-value}))))))
|
||||
|
||||
(defn on-release [response-height]
|
||||
(fn [_ gesture]
|
||||
(when (enough-dy gesture)
|
||||
(dispatch [:fix-response-height
|
||||
(.-vy gesture)
|
||||
;; todo access to "private" property
|
||||
;; better to find another way...
|
||||
(.-_value response-height)]))))
|
||||
|
||||
(defn pan-responder [response-height kb-height orientation]
|
||||
(drag/create-pan-responder
|
||||
{:on-move (on-move response-height kb-height orientation)
|
||||
:on-release (on-release response-height)}))
|
||||
|
||||
(defn request-info [response-height]
|
||||
(let [orientation (subscribe [:get :orientation])
|
||||
kb-height (subscribe [:get :keyboard-height])
|
||||
pan-responder (pan-responder response-height kb-height orientation)
|
||||
command (subscribe [:get-chat-command])]
|
||||
(let [orientation (subscribe [:get :orientation])
|
||||
kb-height (subscribe [:get :keyboard-height])
|
||||
pan-responder (resp/pan-responder response-height
|
||||
kb-height
|
||||
orientation
|
||||
:fix-response-height)
|
||||
command (subscribe [:get-chat-command])]
|
||||
(fn [response-height]
|
||||
[view (merge (drag/pan-handlers pan-responder)
|
||||
{:style (st/request-info (:color @command))})
|
||||
[drag-icon]
|
||||
[view st/inner-container
|
||||
[command-icon nil]
|
||||
[info-container @command]
|
||||
[touchable-highlight {:on-press #(dispatch [:start-cancel-command])}
|
||||
[view st/cancel-container
|
||||
[icon :close-white st/cancel-icon]]]]])))
|
||||
(if (= :response (:type @command))
|
||||
[view (merge (drag/pan-handlers pan-responder)
|
||||
{:style (st/request-info (:color @command))})
|
||||
[drag-icon]
|
||||
[view st/inner-container
|
||||
[command-icon nil]
|
||||
[info-container @command]
|
||||
[touchable-highlight {:on-press #(dispatch [:start-cancel-command])}
|
||||
[view st/cancel-container
|
||||
[icon :close-white st/cancel-icon]]]]]
|
||||
[view (merge (drag/pan-handlers pan-responder)
|
||||
{:style ddst/drag-down-touchable})
|
||||
[icon :drag_down ddst/drag-down-icon]]))))
|
||||
|
||||
(defn container-animation-logic [{:keys [to-value val]}]
|
||||
(fn [_]
|
||||
(let [to-value @to-value]
|
||||
(anim/start (anim/spring val {:toValue to-value})))))
|
||||
(let [to-value @to-value]
|
||||
(anim/start (anim/spring val {:toValue to-value}))))
|
||||
|
||||
(defn container [response-height & children]
|
||||
(let [;; todo to-response-height, cur-response-height must be specific
|
||||
;; for each chat
|
||||
to-response-height (subscribe [:animations :to-response-height])
|
||||
changed (subscribe [:animations :response-height-changed])
|
||||
context {:to-value to-response-height
|
||||
:val response-height}
|
||||
on-update (container-animation-logic context)]
|
||||
changed (subscribe [:animations :response-height-changed])
|
||||
context {:to-value to-response-height
|
||||
:val response-height}
|
||||
on-update #(container-animation-logic context)]
|
||||
(r/create-class
|
||||
{:component-did-mount
|
||||
on-update
|
||||
@ -109,9 +79,18 @@
|
||||
(into [animated-view {:style (st/response-view response-height)}]
|
||||
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 []
|
||||
(let [response-height (anim/create-value 0)]
|
||||
[container response-height
|
||||
[request-info response-height]
|
||||
[response-suggestions-view]
|
||||
[view st/input-placeholder]]))
|
||||
[placeholder]]))
|
||||
|
@ -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}]]))
|
@ -1,9 +1,9 @@
|
||||
(ns status-im.chat.views.staged-command
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[status-im.components.react :refer [view
|
||||
image
|
||||
text
|
||||
touchable-highlight]]
|
||||
image
|
||||
text
|
||||
touchable-highlight]]
|
||||
[status-im.resources :as res]
|
||||
[status-im.chat.styles.input :as st]))
|
||||
|
||||
@ -16,13 +16,12 @@
|
||||
[view st/staged-command-background
|
||||
[view st/staged-command-info-container
|
||||
[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
|
||||
:onPress #(cancel-command-input staged-command)}
|
||||
[image {:source res/icon-close-gray
|
||||
:style st/staged-command-cancel-icon}]]]
|
||||
[text {:style st/staged-command-content}
|
||||
;; TODO isn't smart
|
||||
(if (= (:command command) :keypair-password)
|
||||
"******"
|
||||
(:content staged-command))]]]))
|
||||
(if-let [preview (:preview staged-command)]
|
||||
preview
|
||||
[text {:style st/staged-command-content}
|
||||
(:content staged-command)])]]))
|
||||
|
@ -1,47 +1,128 @@
|
||||
(ns status-im.chat.views.suggestions
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[status-im.components.react :refer [view
|
||||
scroll-view
|
||||
text
|
||||
icon
|
||||
image
|
||||
touchable-highlight
|
||||
list-view
|
||||
list-item]]
|
||||
list-item
|
||||
animated-view]]
|
||||
[status-im.utils.listview :refer [to-datasource]]
|
||||
[status-im.chat.styles.suggestions :as st]))
|
||||
[status-im.chat.styles.suggestions :as st]
|
||||
[status-im.chat.styles.dragdown :as ddst]
|
||||
[reagent.core :as r]
|
||||
[status-im.components.animation :as anim]
|
||||
[status-im.components.drag-drop :as drag]
|
||||
[status-im.chat.suggestions-responder :as resp]
|
||||
[status-im.chat.constants :as c]))
|
||||
|
||||
(defn set-command-input [command]
|
||||
(dispatch [:set-chat-command command]))
|
||||
|
||||
(defn suggestion-list-item
|
||||
[{:keys [description command]
|
||||
label :text
|
||||
:as suggestion}]
|
||||
(defview request-item [{:keys [type message-id]}]
|
||||
[{:keys [color icon description] :as response} [:get-response type]]
|
||||
[touchable-highlight
|
||||
{:onPress #(set-command-input (keyword command))}
|
||||
[view st/suggestion-container
|
||||
[view st/suggestion-sub-container
|
||||
[view (st/suggestion-background suggestion)
|
||||
[text {:style st/suggestion-text} label]]
|
||||
[text {:style st/value-text} label]
|
||||
[text {:style st/description-text} description]]]])
|
||||
{:on-press #(dispatch [:set-response-chat-command message-id type])}
|
||||
[view st/request-container
|
||||
[view st/request-icon-container
|
||||
[view (st/request-icon-background color)
|
||||
[image {:source {:uri icon}
|
||||
:style st/request-icon}]]]
|
||||
[view st/request-info-container
|
||||
[text {:style st/request-info-description} description]
|
||||
;; todo stub
|
||||
[text {:style st/request-message-info}
|
||||
"By console, today at 14:50"]]]])
|
||||
|
||||
(defn render-request-row
|
||||
[{:keys [chat-id message-id] :as row} _ _]
|
||||
(list-item
|
||||
^{:key [chat-id message-id]}
|
||||
[request-item row]))
|
||||
|
||||
(defn suggestion-list-item
|
||||
[[command {:keys [description]
|
||||
name :name
|
||||
:as suggestion}]]
|
||||
(let [label (str "!" name)]
|
||||
[touchable-highlight
|
||||
{:onPress #(set-command-input command)
|
||||
:style st/suggestion-highlight}
|
||||
[view st/suggestion-container
|
||||
[view st/suggestion-sub-container
|
||||
[view st/command-description-container
|
||||
[text {:style st/value-text} label]
|
||||
[text {:style st/description-text} description]]
|
||||
[view st/command-label-container
|
||||
[view (st/suggestion-background suggestion)
|
||||
[text {:style st/suggestion-text} label]]]]]]))
|
||||
|
||||
(defn render-row [row _ _]
|
||||
(list-item [suggestion-list-item row]))
|
||||
|
||||
(defn suggestions-view []
|
||||
(let [suggestions-atom (subscribe [:get-suggestions])]
|
||||
(fn []
|
||||
(let [suggestions @suggestions-atom]
|
||||
(when (seq suggestions)
|
||||
[view st/container
|
||||
[touchable-highlight {:style st/drag-down-touchable
|
||||
:onPress (fn []
|
||||
;; TODO hide suggestions?
|
||||
)}
|
||||
[view
|
||||
[icon :drag_down st/drag-down-icon]]]
|
||||
[view (st/suggestions-container (count suggestions))
|
||||
[list-view {:dataSource (to-datasource suggestions)
|
||||
:enableEmptySections true
|
||||
:keyboardShouldPersistTaps true
|
||||
:renderRow render-row}]]])))))
|
||||
(defn title [s]
|
||||
[view st/title-container
|
||||
[text {:style st/title-text} s]])
|
||||
|
||||
(defview suggestions-view []
|
||||
[suggestions [:get-suggestions]
|
||||
requests [:get-requests]]
|
||||
[scroll-view {:keyboardShouldPersistTaps true}
|
||||
(when (seq requests) [title "Requests"])
|
||||
(when (seq requests)
|
||||
[view
|
||||
[list-view {:dataSource (to-datasource requests)
|
||||
:keyboardShouldPersistTaps true
|
||||
:renderRow render-request-row}]])
|
||||
[title "Commands"]
|
||||
[view
|
||||
[list-view {:dataSource (to-datasource suggestions)
|
||||
:keyboardShouldPersistTaps true
|
||||
:renderRow render-row}]]])
|
||||
|
||||
(defn header [h]
|
||||
(let [orientation (subscribe [:get :orientation])
|
||||
kb-height (subscribe [:get :keyboard-height])
|
||||
pan-responder (resp/pan-responder h
|
||||
kb-height
|
||||
orientation
|
||||
:fix-commands-suggestions-height)]
|
||||
(fn [_]
|
||||
[view
|
||||
(merge (drag/pan-handlers pan-responder)
|
||||
{:style ddst/drag-down-touchable})
|
||||
[view st/header-icon]])))
|
||||
|
||||
(defn container-animation-logic [{:keys [to-value val]}]
|
||||
(when-let [to-value @to-value]
|
||||
(anim/start (anim/spring val {:toValue to-value}))))
|
||||
|
||||
(defn container [h & elements]
|
||||
(let [;; todo to-response-height, cur-response-height must be specific
|
||||
;; for each chat
|
||||
to-response-height (subscribe [:animations :command-suggestions-height])
|
||||
changed (subscribe [:animations :commands-height-changed])
|
||||
context {:to-value to-response-height
|
||||
:val h}
|
||||
on-update #(container-animation-logic context)]
|
||||
(r/create-class
|
||||
{:component-did-mount
|
||||
on-update
|
||||
:component-did-update
|
||||
on-update
|
||||
:reagent-render
|
||||
(fn [h & elements]
|
||||
@changed
|
||||
(into [animated-view {:style (st/container h)}] elements))})))
|
||||
|
||||
(defn suggestion-container []
|
||||
(let [h (anim/create-value 0.1)
|
||||
command? (subscribe [:command?])]
|
||||
(when-not @command?
|
||||
[container h
|
||||
[header h]
|
||||
[suggestions-view]
|
||||
[view {:height c/input-height}]])))
|
||||
|
79
src/status_im/commands/handlers/jail.cljs
Normal file
79
src/status_im/commands/handlers/jail.cljs
Normal file
@ -0,0 +1,79 @@
|
||||
(ns status-im.commands.handlers.jail
|
||||
(:require [re-frame.core :refer [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)
|
102
src/status_im/commands/handlers/loading.cljs
Normal file
102
src/status_im/commands/handlers/loading.cljs
Normal file
@ -0,0 +1,102 @@
|
||||
(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]]
|
||||
[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!))
|
48
src/status_im/commands/utils.cljs
Normal file
48
src/status_im/commands/utils.cljs
Normal file
@ -0,0 +1,48 @@
|
||||
(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 [dispatch trim-v debug]]
|
||||
[status-im.utils.handlers :refer [register-handler]]))
|
||||
|
||||
(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 [trim-v middleware] handler)))
|
27
src/status_im/components/jail.cljs
Normal file
27
src/status_im/components/jail.cljs
Normal 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)))
|
@ -16,4 +16,4 @@
|
||||
(def response-input-hiding-duration 100)
|
||||
(def response-suggesstion-resize-duration 100)
|
||||
|
||||
(def default-number-of-messages 10)
|
||||
(def default-number-of-messages 5)
|
||||
|
@ -1,5 +1,6 @@
|
||||
(ns status-im.contacts.handlers
|
||||
(:require [re-frame.core :refer [register-handler after dispatch]]
|
||||
(:require [re-frame.core :refer [after dispatch]]
|
||||
[status-im.utils.handlers :refer [register-handler]]
|
||||
[status-im.models.contacts :as contacts]
|
||||
[status-im.utils.crypt :refer [encrypt]]
|
||||
[clojure.string :as s]
|
||||
@ -96,7 +97,6 @@
|
||||
(remove #(identities (:whisper-identity %)))
|
||||
(map #(vector (:whisper-identity %) %))
|
||||
(into {}))]
|
||||
(println new-contacts')
|
||||
(-> db
|
||||
(update :contacts merge new-contacts')
|
||||
(assoc :new-contacts (vals new-contacts')))))
|
||||
|
@ -39,7 +39,6 @@
|
||||
:phone-number ""}
|
||||
:disable-group-creation false
|
||||
:animations {:to-response-height 0.1
|
||||
:messages-offset 0
|
||||
;; todo clear this
|
||||
:tabs-bar-value (anim/create-value 0)}})
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
(ns status-im.discovery.handlers
|
||||
(:require [re-frame.core :refer [register-handler after dispatch enrich]]
|
||||
(:require [re-frame.core :refer [after dispatch enrich]]
|
||||
[status-im.utils.handlers :refer [register-handler]]
|
||||
[status-im.protocol.api :as api]
|
||||
[status-im.navigation.handlers :as nav]
|
||||
[status-im.discovery.model :as discoveries]
|
||||
|
@ -1,6 +1,6 @@
|
||||
(ns status-im.group-settings.handlers
|
||||
(:require [re-frame.core :refer [register-handler debug dispatch after
|
||||
enrich]]
|
||||
(:require [re-frame.core :refer [debug dispatch after enrich]]
|
||||
[status-im.utils.handlers :refer [register-handler]]
|
||||
[status-im.persistence.realm :as r]
|
||||
[status-im.chat.handlers :refer [delete-messages!]]
|
||||
[status-im.protocol.api :as api]
|
||||
|
@ -1,26 +1,32 @@
|
||||
(ns status-im.handlers
|
||||
(:require
|
||||
[re-frame.core :refer [register-handler after dispatch debug]]
|
||||
[re-frame.core :refer [after dispatch debug]]
|
||||
[schema.core :as s :include-macros true]
|
||||
[status-im.db :refer [app-db schema]]
|
||||
[status-im.persistence.simple-kv-store :as kv]
|
||||
[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.crypt :refer [gen-random-bytes]]
|
||||
<<<<<<< HEAD
|
||||
[status-im.utils.handlers :as u]
|
||||
[status-im.components.react :refer [geth]]
|
||||
=======
|
||||
[status-im.utils.handlers :refer [register-handler] :as u]
|
||||
>>>>>>> origin/develop
|
||||
status-im.chat.handlers
|
||||
status-im.chat.handlers.animation
|
||||
status-im.group-settings.handlers
|
||||
status-im.navigation.handlers
|
||||
status-im.contacts.handlers
|
||||
status-im.discovery.handlers
|
||||
status-im.new-group.handlers
|
||||
status-im.participants.handlers
|
||||
status-im.commands.handlers.loading
|
||||
status-im.commands.handlers.jail
|
||||
status-im.qr-scanner.handlers
|
||||
status-im.accounts.handlers
|
||||
status-im.protocol.handlers))
|
||||
status-im.protocol.handlers
|
||||
status-im.chat.handlers.requests))
|
||||
|
||||
;; -- Middleware ------------------------------------------------------------
|
||||
;;
|
||||
@ -41,16 +47,12 @@
|
||||
(defn set-el [db [_ k v]]
|
||||
(assoc db k v))
|
||||
|
||||
(register-handler :set
|
||||
debug
|
||||
set-el)
|
||||
(register-handler :set set-el)
|
||||
|
||||
(defn set-in [db [_ path v]]
|
||||
(assoc-in db path v))
|
||||
|
||||
(register-handler :set-in
|
||||
debug
|
||||
set-in)
|
||||
(register-handler :set-in set-in)
|
||||
|
||||
(register-handler :set-animation
|
||||
(fn [db [_ k v]]
|
||||
@ -87,17 +89,6 @@
|
||||
(fn [_ _]
|
||||
(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 --------------------------------------------------------------
|
||||
(register-handler :load-user-phone-number
|
||||
(fn [db [_]]
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
(defn get-content-suggestions [command text]
|
||||
(or (when command
|
||||
(when-let [command-suggestions ((:command command) suggestions)]
|
||||
(when-let [command-suggestions ((keyword (:name command)) suggestions)]
|
||||
(filterv (fn [s]
|
||||
(or (:header s)
|
||||
(and (.startsWith (:value s) (or text ""))
|
||||
|
@ -7,72 +7,14 @@
|
||||
[status-im.components.styles :refer [color-blue color-dark-mint]]
|
||||
[status-im.i18n :refer [label]]))
|
||||
|
||||
;; todo delete
|
||||
(def commands [{:command :money
|
||||
: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 [{:keys [current-chat-id] :as db}]
|
||||
(or (get-in db [:chats current-chat-id :commands]) {}))
|
||||
|
||||
(defn get-commands [db]
|
||||
;; todo: temp. must be '(get db :commands)'
|
||||
;; (get db :commands)
|
||||
commands)
|
||||
|
||||
(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 get-command [{:keys [current-chat-id] :as db} command-key]
|
||||
((or (->> (get-in db [:chats current-chat-id])
|
||||
((juxt :commands :responses))
|
||||
(apply merge))
|
||||
{}) command-key))
|
||||
|
||||
(defn find-command [commands command-key]
|
||||
(first (filter #(= command-key (:command %)) commands)))
|
||||
@ -92,9 +34,10 @@
|
||||
(defn set-response-chat-command
|
||||
[{:keys [current-chat-id] :as db} msg-id command-key]
|
||||
(update-in db [:chats current-chat-id :command-input] merge
|
||||
{:content nil
|
||||
:command (get-command db command-key)
|
||||
:to-msg-id msg-id}))
|
||||
{:content nil
|
||||
:command (get-command db command-key)
|
||||
:parameter-idx 0
|
||||
:to-msg-id msg-id}))
|
||||
|
||||
(defn set-chat-command [db command-key]
|
||||
(set-response-chat-command db nil command-key))
|
||||
@ -130,7 +73,7 @@
|
||||
#(assoc % msg-id handler)))
|
||||
|
||||
(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]
|
||||
(update content :command #(find-command commands (keyword %))))
|
||||
(update content :command #((keyword %) commands)))
|
||||
|
@ -6,7 +6,8 @@
|
||||
[status-im.utils.logging :as log]
|
||||
[clojure.string :refer [join split]]
|
||||
[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
|
||||
[m]
|
||||
@ -20,7 +21,8 @@
|
||||
{:outgoing false
|
||||
:to nil
|
||||
:same-author false
|
||||
:same-direction false})
|
||||
:same-direction false
|
||||
:preview nil})
|
||||
|
||||
(defn save-message
|
||||
;; todo remove chat-id parameter
|
||||
@ -54,7 +56,7 @@
|
||||
(r/collection->map))
|
||||
(into '())
|
||||
reverse
|
||||
(map (fn [{:keys [content-type] :as message}]
|
||||
(keep (fn [{:keys [content-type] :as message}]
|
||||
(if (command-type? content-type)
|
||||
(update message :content str-to-map)
|
||||
message))))))
|
||||
|
@ -1,6 +1,6 @@
|
||||
(ns status-im.navigation.handlers
|
||||
(:require [re-frame.core :refer [register-handler dispatch debug enrich
|
||||
after]]))
|
||||
(:require [re-frame.core :refer [dispatch debug enrich after]]
|
||||
[status-im.utils.handlers :refer [register-handler]]))
|
||||
|
||||
(defn push-view [db view-id]
|
||||
(-> db
|
||||
|
@ -1,6 +1,7 @@
|
||||
(ns status-im.new-group.handlers
|
||||
(:require [status-im.protocol.api :as api]
|
||||
[re-frame.core :refer [register-handler after dispatch debug enrich]]
|
||||
[re-frame.core :refer [after dispatch debug enrich]]
|
||||
[status-im.utils.handlers :refer [register-handler]]
|
||||
[status-im.components.styles :refer [default-chat-color]]
|
||||
[status-im.models.chats :as chats]
|
||||
[clojure.string :as s]))
|
||||
|
@ -1,6 +1,7 @@
|
||||
(ns status-im.participants.handlers
|
||||
(:require [status-im.navigation.handlers :as nav]
|
||||
[re-frame.core :refer [register-handler debug]]))
|
||||
[re-frame.core :refer [debug]]
|
||||
[status-im.utils.handlers :refer [register-handler]]))
|
||||
|
||||
(defmethod nav/preload-data! :add-participants
|
||||
[db _]
|
||||
|
@ -1,9 +1,9 @@
|
||||
(ns status-im.persistence.realm
|
||||
(:require [cljs.reader :refer [read-string]]
|
||||
[status-im.components.styles :refer [default-chat-color]]
|
||||
[status-im.utils.logging :as log]
|
||||
[status-im.utils.types :refer [to-string]]
|
||||
[status-im.utils.utils :as u])
|
||||
[status-im.utils.utils :as u]
|
||||
[clojure.string :as str])
|
||||
(:refer-clojure :exclude [exists?]))
|
||||
|
||||
(def opts {:schema [{:name :contacts
|
||||
@ -19,6 +19,13 @@
|
||||
:primaryKey :address
|
||||
:properties {:address "string"
|
||||
:public-key "string"}}
|
||||
{:name :requests
|
||||
:properties {:message-id :string
|
||||
:chat-id :string
|
||||
:type :string
|
||||
:status {:type :string
|
||||
:default "open"}
|
||||
:added :date}}
|
||||
{:name :kv-store
|
||||
:primaryKey :key
|
||||
:properties {:key "string"
|
||||
@ -38,7 +45,9 @@
|
||||
:delivery-status {:type "string"
|
||||
:optional true}
|
||||
:same-author "bool"
|
||||
:same-direction "bool"}}
|
||||
:same-direction "bool"
|
||||
:preview {:type :string
|
||||
:optional true}}}
|
||||
{:name :chat-contact
|
||||
:properties {:identity "string"
|
||||
:is-in-chat {:type "bool"
|
||||
@ -55,7 +64,15 @@
|
||||
:timestamp "int"
|
||||
:contacts {:type "list"
|
||||
:objectType "chat-contact"}
|
||||
:dapp-url {:type :string
|
||||
:optional true}
|
||||
:dapp-hash {:type :int
|
||||
:optional true}
|
||||
:last-msg-id "string"}}
|
||||
{:name :commands
|
||||
:primaryKey :chat-id
|
||||
:properties {:chat-id "string"
|
||||
:file "string"}}
|
||||
{:name :tag
|
||||
:primaryKey :name
|
||||
:properties {:name "string"
|
||||
@ -98,12 +115,20 @@
|
||||
([schema-name 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))))
|
||||
|
||||
(defn and-q [queries]
|
||||
(str/join " and " queries))
|
||||
|
||||
(defmulti to-query (fn [schema-name operator field value]
|
||||
operator))
|
||||
|
||||
(defmethod to-query :eq [schema-name operator field value]
|
||||
(let [value (to-string value)
|
||||
query (str (name field) "=" (if (= "string" (field-type schema-name field))
|
||||
query (str (name field) "=" (if (= "string" (name (field-type
|
||||
schema-name field)))
|
||||
(str "\"" value "\"")
|
||||
value))]
|
||||
query))
|
||||
@ -116,6 +141,12 @@
|
||||
(let [q (to-query schema-name :eq field value)]
|
||||
(.filtered (.objects realm (name schema-name)) q)))
|
||||
|
||||
(defn get-by-fields [schema-name fields]
|
||||
(let [queries (map (fn [[k v]]
|
||||
(to-query schema-name :eq k v))
|
||||
fields)]
|
||||
(.filtered (.objects realm (name schema-name)) (and-q queries))))
|
||||
|
||||
(defn get-all [schema-name]
|
||||
(.objects realm (to-string schema-name)))
|
||||
|
||||
@ -162,3 +193,6 @@
|
||||
(defn collection->map [collection]
|
||||
(-> (.map collection (fn [object _ _] object))
|
||||
(js->clj :keywordize-keys true)))
|
||||
|
||||
(defn get-one-by-field [schema-name field value]
|
||||
(single-cljs (get-by-field schema-name field value)))
|
||||
|
@ -4,7 +4,8 @@
|
||||
(:require [status-im.utils.handlers :as u]
|
||||
[status-im.utils.logging :as log]
|
||||
[status-im.protocol.api :as api]
|
||||
[re-frame.core :refer [register-handler dispatch debug]]
|
||||
[re-frame.core :refer [dispatch debug]]
|
||||
[status-im.utils.handlers :refer [register-handler]]
|
||||
[status-im.models.contacts :as contacts]
|
||||
[status-im.protocol.api :refer [init-protocol]]
|
||||
[status-im.protocol.protocol-handler :refer [make-handler]]
|
||||
|
@ -1,5 +1,6 @@
|
||||
(ns status-im.qr-scanner.handlers
|
||||
(:require [re-frame.core :refer [register-handler after dispatch debug enrich]]
|
||||
(: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]))
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
(ns status-im.utils.handlers)
|
||||
(ns status-im.utils.handlers
|
||||
(:require [re-frame.core :refer [after dispatch debug] :as re-core]))
|
||||
|
||||
(defn side-effect!
|
||||
"Middleware for handlers that will not affect db."
|
||||
@ -6,3 +7,8 @@
|
||||
(fn [db params]
|
||||
(handler db params)
|
||||
db))
|
||||
|
||||
(defn register-handler
|
||||
([name handler] (register-handler name nil handler))
|
||||
([name middleware handler]
|
||||
(re-core/register-handler name [#_debug middleware] handler)))
|
||||
|
5
src/status_im/utils/slurp.clj
Normal file
5
src/status_im/utils/slurp.clj
Normal file
@ -0,0 +1,5 @@
|
||||
(ns status-im.utils.slurp
|
||||
(:refer-clojure :exclude [slurp]))
|
||||
|
||||
(defmacro slurp [file]
|
||||
(clojure.core/slurp file))
|
@ -11,5 +11,6 @@
|
||||
(defn clj->json [data]
|
||||
(.stringify js/JSON (clj->js data)))
|
||||
|
||||
(defn json->clj [data]
|
||||
(js->clj (.parse js/JSON data) :keywordize-keys true))
|
||||
(defn json->clj [json]
|
||||
(when-not (= json "undefined")
|
||||
(js->clj (.parse js/JSON json) :keywordize-keys true)))
|
||||
|
@ -41,10 +41,8 @@
|
||||
(toast (str error))))))))
|
||||
|
||||
(defn http-get
|
||||
([action on-success on-error]
|
||||
(-> (.fetch js/window
|
||||
(str const/server-address action)
|
||||
(clj->js {:method "GET"}))
|
||||
([url on-success on-error]
|
||||
(-> (.fetch js/window url (clj->js {:method "GET"}))
|
||||
(.then (fn [response]
|
||||
(log response)
|
||||
(.text response)))
|
||||
|
20
test/cljs/status_im/test/commands/handlers.cljs
Normal file
20
test/cljs/status_im/test/commands/handlers.cljs
Normal 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])))))
|
@ -1,5 +1,7 @@
|
||||
(ns status-im.test.runner
|
||||
(: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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user