Merge pull request #158 from status-im/feature/browser

Browser
This commit is contained in:
Jarrad 2016-07-22 12:30:25 +02:00 committed by GitHub
commit 365b4e8ad7
22 changed files with 230 additions and 86 deletions

View File

@ -104,7 +104,7 @@ public class MainActivity extends ReactActivity {
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new JailPackage(),
new JailPackage(this),
new RealmReactPackage(),
new VectorIconsPackage(),
new ReactNativeContacts(),

View File

@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.1'
classpath 'com.android.tools.build:gradle:2.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files

View File

@ -1,5 +1,6 @@
#Wed Jul 20 10:42:35 EEST 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip

View File

@ -25,6 +25,8 @@
"react-native-randombytes": "^2.1.0",
"react-native-status": "git+ssh://git@github.com/status-im/react-native-status",
"react-native-vector-icons": "^1.3.4",
"realm": "^0.14.0"
"react-native-orientation": "^1.17.0",
"realm": "^0.11.1",
"react-native-status": "git+ssh://git@github.com/status-im/react-native-status.git#set-soft-input-mode"
}
}

View File

@ -128,10 +128,12 @@ function phoneSuggestions(params) {
);
});
return status.components.scrollView(
var view = status.components.scrollView(
suggestionsContainerStyle(ph.length),
suggestions
);
return {markup: view};
}
status.response({
@ -163,15 +165,15 @@ status.command({
description: "Help",
color: "#7099e6",
/* Validator example
validator: function (params) {
if (params.value != "3") {
var error = status.components.view(
{backgroundColor: "red"},
[status.components.text({}, "ooops :(")]
);
return {errors: [error]}
}
},*/
validator: function (params) {
if (params.value != "3") {
var error = status.components.view(
{backgroundColor: "red"},
[status.components.text({}, "ooops :(")]
);
return {errors: [error]}
}
},*/
params: [{
name: "query",
type: status.types.TEXT
@ -223,3 +225,26 @@ status.response({
}
});
function walletView(params) {
if (params.value != "") {
var url = params.value;
if (!/^[a-zA-Z-_]+:/.test(url)) {
url = 'http://' + url;
}
return {webViewUrl: url};
}
}
status.command({
name: "browse",
description: "browser",
color: "#ffa500",
fullscreen: true,
suggestionsTrigger: 'on-send',
params: [{
name: "webpage",
suggestions: walletView,
type: status.types.TEXT
}]
});

View File

@ -27,6 +27,8 @@ Command.prototype.create = function (com) {
this.icon = com.icon;
this.params = com.params || [];
this.preview = com.preview;
this["suggestions-trigger"] = com.suggestionsTrigger || "on-change";
this.fullscreen = com.fullscreen;
this.addToCatalog();
return this;
@ -83,6 +85,15 @@ function scrollView(options, elements) {
return ['scroll-view', options].concat(elements);
}
function webView(url) {
return ['web-view', {
source: {
uri: url
},
javaScriptEnabled: true
}];
}
var status = {
command: function (h) {
var command = new Command();
@ -106,6 +117,7 @@ var status = {
text: text,
image: image,
touchable: touchable,
scrollView: scrollView
scrollView: scrollView,
webView: webView
}
};

View File

@ -25,7 +25,8 @@
[status-im.utils.utils :refer [toast]]
[status-im.utils.encryption]
status-im.persistence.realm.core
[status-im.utils.logging :as log]))
[status-im.utils.logging :as log]
[status-im.components.jail :as j]))
(defn init-back-button-handler! []
(let [new-listener (fn []
@ -65,8 +66,8 @@
(dispatch [:set :keyboard-height h])))))
(.addListener device-event-emitter
"keyboardDidHide"
(when-not (= 0 @keyboard-height)
#(dispatch [:set :keyboard-height 0]))))
#(when-not (= 0 @keyboard-height)
(dispatch [:set :keyboard-height 0]))))
:render
(fn []
(let [startup-view (if @account
@ -99,6 +100,7 @@
(dispatch-sync [:reset-app])
(dispatch [:initialize-crypt])
(dispatch [:initialize-geth])
(.setSoftInputMode j/jail j/adjust-resize)
(dispatch [:load-user-phone-number])
(init-back-button-handler!)
(.registerComponent app-registry "StatusIm" #(r/reactify-component app-root)))

View File

@ -57,6 +57,7 @@
(update-in [:chats current-chat-id :input-text] safe-trim))))
(register-handler :start-cancel-command
(after #(dispatch [:set-soft-input-mode :resize]))
(u/side-effect!
(fn [db _]
(dispatch [:animate-cancel-command]))))
@ -483,16 +484,16 @@
(register-handler :set-layout-height
[(after
(fn [{:keys [current-chat-id] :as db}]
(let [suggestions (get-in db [:suggestions current-chat-id])
(let [suggestions (get-in db [:has-suggestions? current-chat-id])
mode (get-in db [:edit-mode current-chat-id])]
(when (and (= :command mode) (seq suggestions))
(dispatch [:fix-response-height])))))
(when (and (= :command mode) suggestions)
(dispatch [:fix-response-height nil nil true])))))
(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])))))]
(when (and (not= :command mode) (seq suggestions))
(dispatch [:fix-commands-suggestions-height nil nil true])))))]
(fn [db [_ h]]
(assoc db :layout-height h)))
@ -505,3 +506,17 @@
(fn [_ [_ chat-id message-id]]
(when-not (console? chat-id)
(api/send-seen chat-id message-id)))))
(register-handler :set-web-view-url
(fn [{:keys [current-chat-id] :as db} [_ url]]
(assoc-in db [:web-view-url current-chat-id] url)))
(register-handler :set-soft-input-mode
(after
(fn [{:keys [current-chat-id]} [_ mode chat-id]]
(when (or (nil? chat-id) (= current-chat-id chat-id))
(.setSoftInputMode j/jail (if (= :pan mode)
j/adjust-pan
j/adjust-resize)))))
(fn [db [_ chat-id mode]]
(assoc-in db [:kb-mode chat-id] mode)))

View File

@ -45,6 +45,7 @@
(let [path [:chats current-chat-id :command-input :command :type]
type (get-in db path)
errors (get-in db [:validation-errors current-chat-id])
suggestion? (get-in db [:has-suggestions? current-chat-id])
custom-errors (get-in db [:custom-validation-errors current-chat-id])
validation-height (if (or (seq errors) (seq custom-errors))
request-info-height
@ -52,22 +53,26 @@
(+ validation-height
(if (= :response type)
minimum-suggestion-height
(if (zero? validation-height)
(if-not suggestion?
input-height
(+ input-height suggestions-header-height))))))
(register-handler :animate-show-response
;[(after #(dispatch [:command-edit-mode]))]
(fn [{:keys [current-chat-id] :as db}]
(let [suggestions? (seq (get-in db [:suggestions current-chat-id]))
(let [suggestions? (get-in db [:has-suggestions? current-chat-id])
fullscreen? (get-in db [:chats current-chat-id :command-input :command :fullscreen])
max-height (get-in db [:layout-height])
height (if suggestions?
middle-height
(if fullscreen?
max-height
middle-height)
(get-minimum-height db))]
(assoc-in db [:animations :to-response-height current-chat-id] height))))
(defn fix-height
[height-key height-signal-key suggestions-key minimum]
(fn [{:keys [current-chat-id] :as db} [_ vy current]]
(fn [{:keys [current-chat-id] :as db} [_ vy current no-animation]]
(let [max-height (get-in db [:layout-height])
moving-down? (pos? vy)
moving-up? (not moving-down?)
@ -100,7 +105,8 @@
(minimum db))]
(-> db
(assoc-in [:animations height-key current-chat-id] new-fixed)
(update-in [:animations height-signal-key] inc)))))
(update-in [:animations height-signal-key] inc)
(assoc-in [:animate? current-chat-id] (not no-animation))))))
(defn commands-min-height
[{:keys [current-chat-id] :as db}]
@ -118,5 +124,5 @@
(register-handler :fix-response-height
(fix-height :to-response-height
:response-height-changed
:suggestions
:has-suggestions?
get-minimum-height))

View File

@ -2,6 +2,7 @@
(:require [re-frame.core :refer [enrich after dispatch]]
[status-im.utils.handlers :refer [register-handler] :as u]
[status-im.components.jail :as j]
[status-im.components.react :as r]
[status-im.models.commands :as commands]
[clojure.string :as str]
[status-im.commands.utils :as cu]
@ -10,6 +11,12 @@
(def command-prefix "c ")
(defn content-by-command
[{:keys [type]} content]
(if (and (= :command type) content)
(subs content (count command-prefix))
content))
(defn invoke-suggestions-handler!
[{:keys [current-chat-id canceled-command] :as db} _]
(when-not canceled-command
@ -20,7 +27,7 @@
:params
0
:suggestions]
params {:value content}]
params {:value (content-by-command command content)}]
(j/call current-chat-id
path
params
@ -33,14 +40,20 @@
(when canceled-command
(dispatch [:start-cancel-command])))
(defn current-command
[{:keys [current-chat-id] :as db} k]
(get-in db [:chats current-chat-id :command-input :command k]))
(register-handler :set-chat-command-content
[(after invoke-suggestions-handler!)
[(after (fn [db]
(let [trigger (keyword (current-command db :suggestions-trigger))]
(when (= :on-change trigger)
(invoke-suggestions-handler! db nil)))))
(after cancel-command!)
(after #(dispatch [:clear-validation-errors]))]
(fn [{:keys [current-chat-id] :as db} [_ content]]
(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))]
command? (= :command (current-command db :type))]
(as-> db db
(commands/set-chat-command-content db content)
(assoc-in db [:chats current-chat-id :input-text] nil)
@ -59,12 +72,6 @@
params
#(dispatch [:command-preview chat-id %]))))
(defn content-by-command
[{:keys [type]} content]
(if (= :command type)
(subs content 2)
content))
(defn command-input
([{:keys [current-chat-id] :as db}]
(command-input db current-chat-id))
@ -140,6 +147,7 @@
(register-handler :set-chat-command
[(after invoke-suggestions-handler!)
(after #(dispatch [:set-soft-input-mode :resize]))
(after #(dispatch [:command-edit-mode]))]
set-chat-command)
@ -186,3 +194,7 @@
(after #(dispatch [:fix-response-height]))
(fn [db [_ chat-id error]]
(assoc-in db [:validation-errors chat-id] [error])))
(register-handler :invoke-commands-suggestions!
(u/side-effect!
invoke-suggestions-handler!))

View File

@ -326,6 +326,7 @@
(defn message-container [height]
{:height height})
(def new-message-container
(defn new-message-container [margin]
{:backgroundColor color-white
:elevation 4})
:elevation 4
:margin-bottom margin})

View File

@ -198,3 +198,34 @@
(let [chat-id (subscribe [:get-current-chat-id])]
(reaction
(get-in @db [:animations :to-response-height @chat-id])))))
(register-sub :web-view-url
(fn [db]
(let [chat-id (subscribe [:get-current-chat-id])]
(reaction (get-in @db [:web-view-url @chat-id])))))
(register-sub :animate?
(fn [db]
(let [chat-id (subscribe [:get-current-chat-id])]
(reaction (get-in @db [:animate? @chat-id])))))
(register-sub :kb-mode
(fn [db]
(let [chat-id (subscribe [:get-current-chat-id])]
(reaction (get-in @db [:kb-mode @chat-id])))))
(register-sub :input-margin
(fn []
(let [kb-height (subscribe [:get :keyboard-height])
command (subscribe [:get-chat-command])
focused (subscribe [:get :focused])
mode (subscribe [:kb-mode])]
(reaction (cond (and (not @focused)
(= :on-send (keyword (:suggestions-trigger @command)))
(pos? @kb-height))
@kb-height
(and @focused (= :pan @mode) (pos? @kb-height))
20
:else 0)))))

View File

@ -8,19 +8,10 @@
(defn enough-dy [gesture]
(> (Math/abs (.-dy gesture)) 10))
(defn on-move [response-height kb-height orientation]
(defn on-move [response-height layout-height]
(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))]
(let [to-value (- @layout-height (.-moveY gesture))]
(anim/start
(anim/spring response-height {:toValue to-value}))))))
@ -33,7 +24,7 @@
;; better to find another way...
(.-_value response-height)]))))
(defn pan-responder [response-height kb-height orientation handler-name]
(defn pan-responder [response-height layout-height handler-name]
(drag/create-pan-responder
{:on-move (on-move response-height kb-height orientation)
{:on-move (on-move response-height layout-height)
:on-release (on-release response-height handler-name)}))

View File

@ -1,6 +1,6 @@
(ns status-im.chat.views.message-input
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe]]
(:require [re-frame.core :refer [subscribe dispatch]]
[status-im.components.react :refer [view
text
animated-view
@ -28,12 +28,18 @@
:editable (not disbale?)
:onSubmitEditing plain-message/send})
(defn command-input-options [icon-width disbale?]
(defn on-press-commands-handler
[{:keys [suggestions-trigger]}]
(if (= :on-send (keyword suggestions-trigger))
#(dispatch [:invoke-commands-suggestions!])
command/send-command))
(defn command-input-options [command icon-width disbale?]
{:style (st-response/command-input icon-width disbale?)
:onChangeText (when-not disbale? command/set-input-message)
:onSubmitEditing command/send-command})
:onSubmitEditing (on-press-commands-handler command)})
(defview message-input [input-options]
(defview message-input [input-options {:keys [suggestions-trigger] :as command}]
[command? [:command?]
input-message [:get-chat-input-text]
input-command [:get-chat-command-content]
@ -41,11 +47,13 @@
disbale? [:get :disable-input]]
[text-input (merge
(if command?
(command-input-options icon-width disbale?)
(command-input-options command icon-width disbale?)
(plain-input-options disbale?))
{:autoFocus false
:blurOnSubmit false
:accessibility-label :input}
:accessibility-label :input
:on-focus #(dispatch [:set :focused true])
:on-blur #(dispatch [:set :focused false])}
input-options)
(if command? input-command input-message)])
@ -58,12 +66,12 @@
[view st/input-view
[plain-message/commands-button]
[message-input-container
[message-input input-options]]
[message-input input-options command]]
;; TODO emoticons: not implemented
[plain-message/smile-button]
(when (or command? valid-plain-message?)
(let [on-press (if command?
command/send-command
(on-press-commands-handler command)
plain-message/send)]
[send-button {:on-press on-press
:accessibility-label :send-message}]))

View File

@ -37,8 +37,9 @@
(when command? (get-options parameter type))])
(defview chat-message-new []
[staged-commands [:get-chat-staged-commands]]
[view st/new-message-container
[staged-commands [:get-chat-staged-commands]
margin [:input-margin]]
[view (st/new-message-container margin)
(when (seq staged-commands)
[staged-commands-view staged-commands])
[show-input]])

View File

@ -9,7 +9,9 @@
image
text
text-input
touchable-highlight]]
touchable-highlight
web-view
scroll-view]]
[status-im.components.drag-drop :as drag]
[status-im.chat.styles.response :as st]
[status-im.chat.styles.dragdown :as ddst]
@ -36,11 +38,9 @@
"By ???, MMM 1st at HH:mm"]])
(defn request-info [response-height]
(let [orientation (subscribe [:get :orientation])
kb-height (subscribe [:get :keyboard-height])
(let [layout-height (subscribe [:get :layout-height])
pan-responder (resp/pan-responder response-height
kb-height
orientation
layout-height
:fix-response-height)
command (subscribe [:get-chat-command])]
(fn [response-height]
@ -58,18 +58,22 @@
{:style ddst/drag-down-touchable})
[icon :drag_down ddst/drag-down-icon]]))))
(defn container-animation-logic [{:keys [to-value val]}]
(defn container-animation-logic [{:keys [to-value val animate?]}]
(when-let [to-value @to-value]
(when-not (= to-value (.-_value val))
(anim/start (anim/spring val {:toValue to-value})))))
(if (or (nil? @animate?) @animate?)
(anim/start (anim/spring val {:toValue to-value}))
(anim/set-value val 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 [:response-height])
changed (subscribe [:animations :response-height-changed])
animate? (subscribe [:animate?])
context {:to-value to-response-height
:val response-height}
:val response-height
:animate? animate?}
on-update #(container-animation-logic context)]
(r/create-class
{:component-did-mount
@ -82,6 +86,21 @@
(into [animated-view {:style (st/response-view response-height)}]
children))})))
(defn on-navigation-change
[event]
(let [{:strs [loading url]} (js->clj event)]
(when-not (= "about:blank" url)
(if loading
(dispatch [:set-web-view-url url])
(dispatch [:set-chat-command-content (str "c " url)])))))
(defview suggestions-web-view []
[url [:web-view-url]]
[web-view {:source {:uri url}
:java-script-enabled true
:style {:height 300}
:on-navigation-state-change on-navigation-change}])
(defview placeholder []
[suggestions [:get-content-suggestions]]
[view st/input-placeholder])
@ -94,6 +113,7 @@
(let [response-height (anim/create-value c/input-height)]
[container response-height
[request-info response-height]
[suggestions-web-view]
[response-suggestions-view]
[cv/validation-messages]
[placeholder]]))

View File

@ -84,11 +84,9 @@
:renderRow render-row}]]])
(defn header [h]
(let [orientation (subscribe [:get :orientation])
kb-height (subscribe [:get :keyboard-height])
(let [layout-height (subscribe [:get :layout-height])
pan-responder (resp/pan-responder h
kb-height
orientation
layout-height
:fix-commands-suggestions-height)]
(fn [_]
[view
@ -96,18 +94,22 @@
{:style ddst/drag-down-touchable})
[view st/header-icon]])))
(defn container-animation-logic [{:keys [to-value val]}]
(defn container-animation-logic [{:keys [to-value val animate?]}]
(when-let [to-value @to-value]
(when-not (= to-value (.-_value val))
(anim/start (anim/spring val {:toValue to-value})))))
(if (or (nil? @animate?) @animate?)
(anim/start (anim/spring val {:toValue to-value}))
(anim/set-value val to-value)))))
(defn container [h & elements]
(let [;; todo to-response-height, cur-response-height must be specific
;; for each chat
to-response-height (subscribe [:command-suggestions-height])
changed (subscribe [:animations :commands-height-changed])
animate? (subscribe [:animate?])
context {:to-value to-response-height
:val h}
:val h
:animate? animate?}
on-update #(container-animation-logic context)]
(r/create-class
{:component-did-mount

View File

@ -5,7 +5,8 @@
[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]))
[clojure.string :as s]
[status-im.components.react :as r]))
(defn init-render-command!
[_ [chat-id command message-id data]]
@ -36,7 +37,12 @@
(defn suggestions-handler!
[db [{:keys [chat-id]} {:keys [result]} ]]
(assoc-in db [:suggestions chat-id] (generate-hiccup result)))
(let [{:keys [markup webViewUrl]} result
hiccup (generate-hiccup markup)]
(-> db
(assoc-in [:suggestions chat-id] (generate-hiccup markup))
(assoc-in [:web-view-url chat-id] webViewUrl)
(assoc-in [:has-suggestions? chat-id] (or hiccup webViewUrl)))))
(defn suggestions-events-handler!
[db [[n data]]]
@ -71,7 +77,12 @@
(u/side-effect! command-hadler!))
(reg-handler :suggestions-handler
[(after #(dispatch [:animate-show-response]))
(after (print-error-message! "Error on param suggestions"))]
(after (print-error-message! "Error on param suggestions"))
(after (fn [_ [{:keys [command]} {:keys [result]}]]
(when (= :on-send (keyword (:suggestions-trigger command)))
(when (:webViewUrl result)
(dispatch [:set-soft-input-mode :pan]))
(r/dismiss-keyboard!))))]
suggestions-handler!)
(reg-handler :suggestions-event! (u/side-effect! suggestions-events-handler!))
(reg-handler :command-preview

View File

@ -1,20 +1,20 @@
(ns status-im.commands.utils
(:require [clojure.set :as set]
[clojure.walk :as w]
[status-im.components.react :refer [text scroll-view view
[status-im.components.react :refer [text scroll-view view web-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
(when-not (= json "undefined")
(js->clj (.parse js/JSON json) :keywordize-keys true)))
(def elements
{:text text
:view view
:scroll-view scroll-view
:web-view web-view
:image image
:touchable touchable-highlight})

View File

@ -25,3 +25,6 @@
(println r')
(callback r')))]
(.call jail chat-id (cljs->json path) (cljs->json params) cb)))
(def adjust-resize 16)
(def adjust-pan 32)

View File

@ -34,6 +34,7 @@
(defn list-view [props]
[list-view-class (merge {:enableEmptySections true} props)])
(def scroll-view (get-class "ScrollView"))
(def web-view (get-class "WebView"))
(def touchable-without-feedback (get-class "TouchableWithoutFeedback"))
(def text-input-class (get-class "TextInput"))
(defn text-input [props text]

View File

@ -52,6 +52,6 @@
(toast (str error))))))))
(defn truncate-str [s max]
(if (< max (count s))
(if (and (< max (count s)) s)
(str (subs s 0 (- max 3)) "...")
s))