show connectivity issues & retry sending of phone/confirmation code to server if application is offline

Former-commit-id: 2580b0a9d9
This commit is contained in:
Roman Volosovskyi 2016-10-19 15:22:05 +03:00
parent cc04e18252
commit 8439407520
18 changed files with 174 additions and 109 deletions

View File

@ -6,6 +6,7 @@
<uses-permission android:name="android.permission.WRITE_CONTACTS"/> <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.READ_PROFILE"/> <uses-permission android:name="android.permission.READ_PROFILE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application <application
android:allowBackup="true" android:allowBackup="true"

View File

@ -101,24 +101,12 @@ var phoneConfig = {
name: "phone", name: "phone",
description: "Send phone number", description: "Send phone number",
color: "#5fc48d", color: "#5fc48d",
validator: function (params) {
return {
validationHandler: "phone",
parameters: [params.phone]
};
},
params: [{ params: [{
name: "phone", name: "phone",
type: status.types.PHONE, type: status.types.PHONE,
suggestions: phoneSuggestions, suggestions: phoneSuggestions,
placeholder: "Phone number" placeholder: "Phone number"
}], }]
handler: function (params) {
return {
event: "sign-up",
params: [params.phone, params]
};
}
}; };
status.response(phoneConfig); status.response(phoneConfig);
status.command(phoneConfig); status.command(phoneConfig);
@ -128,16 +116,6 @@ status.command({
name: "help", name: "help",
description: "Help", description: "Help",
color: "#7099e6", 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]}
}
},*/
params: [{ params: [{
name: "query", name: "query",
type: status.types.TEXT type: status.types.TEXT
@ -152,12 +130,6 @@ status.response({
name: "code", name: "code",
type: status.types.NUMBER type: status.types.NUMBER
}], }],
handler: function (params) {
return {
event: "confirm-sign-up",
params: [params.code]
};
},
validator: function (params) { validator: function (params) {
if (!/^[\d]{4}$/.test(params.code)) { if (!/^[\d]{4}$/.test(params.code)) {
var error = status.components.validationMessage( var error = status.components.validationMessage(
@ -184,12 +156,6 @@ status.response({
type: status.types.PASSWORD, type: status.types.PASSWORD,
placeholder: "Please re-enter password to confirm" placeholder: "Please re-enter password to confirm"
}], }],
handler: function (params) {
return {
event: "save-password",
params: [params.password]
};
},
validator: function (params, context) { validator: function (params, context) {
var errorMessages = []; var errorMessages = [];
var currentParameter = context["current-parameter"]; var currentParameter = context["current-parameter"];

View File

@ -105,6 +105,7 @@
(defn init [& [env]] (defn init [& [env]]
(dispatch-sync [:reset-app]) (dispatch-sync [:reset-app])
(dispatch [:listen-to-network-status!])
(dispatch [:initialize-crypt]) (dispatch [:initialize-crypt])
(dispatch [:initialize-geth]) (dispatch [:initialize-geth])
(status/set-soft-input-mode status/adjust-resize) (status/set-soft-input-mode status/adjust-resize)

View File

@ -36,7 +36,7 @@
[cljs.core.async :as a] [cljs.core.async :as a]
status-im.chat.handlers.webview-bridge status-im.chat.handlers.webview-bridge
status-im.chat.handlers.wallet-chat status-im.chat.handlers.wallet-chat
[taoensso.timbre :as log])) status-im.chat.handlers.console))
(register-handler :set-chat-ui-props (register-handler :set-chat-ui-props
(fn [db [_ ui-element value]] (fn [db [_ ui-element value]]
@ -204,12 +204,14 @@
(register-handler :sign-up (register-handler :sign-up
(after (fn [_ [_ phone-number]] (after (fn [_ [_ phone-number]]
(dispatch [:account-update {:phone phone-number}]))) (dispatch [:account-update {:phone phone-number}])))
(fn [db [_ phone-number]] (fn [db [_ phone-number message-id]]
(let [formatted (format-phone-number phone-number)] (let [formatted (format-phone-number phone-number)]
(-> db (-> db
(assoc :user-phone-number formatted) (assoc :user-phone-number formatted)
sign-up-service/start-listening-confirmation-code-sms sign-up-service/start-listening-confirmation-code-sms
(server/sign-up formatted sign-up-service/on-sign-up-response))))) (server/sign-up formatted
message-id
sign-up-service/on-sign-up-response)))))
(register-handler :stop-listening-confirmation-code-sms (register-handler :stop-listening-confirmation-code-sms
(fn [db [_]] (fn [db [_]]
@ -219,8 +221,11 @@
(register-handler :sign-up-confirm (register-handler :sign-up-confirm
(u/side-effect! (u/side-effect!
(fn [_ [_ confirmation-code]] (fn [_ [_ confirmation-code message-id]]
(server/sign-up-confirm confirmation-code sign-up-service/on-send-code-response)))) (server/sign-up-confirm
confirmation-code
message-id
sign-up-service/on-send-code-response))))
(register-handler :set-signed-up (register-handler :set-signed-up
(u/side-effect! (u/side-effect!
@ -274,9 +279,9 @@
(defmethod nav/preload-data! :chat (defmethod nav/preload-data! :chat
[{:keys [current-chat-id] :as db} [_ _ id]] [{:keys [current-chat-id] :as db} [_ _ id]]
(let [chat-id (or id current-chat-id) (let [chat-id (or id current-chat-id)
messages (get-in db [:chats chat-id :messages]) messages (get-in db [:chats chat-id :messages])
db' (assoc db :current-chat-id chat-id) db' (assoc db :current-chat-id chat-id)
commands-loaded? (get-in db [:chats chat-id :commands-loaded])] commands-loaded? (get-in db [:chats chat-id :commands-loaded])]
(when (= current-chat-id wallet-chat-id) (when (= current-chat-id wallet-chat-id)
(dispatch [:cancel-command])) (dispatch [:cancel-command]))

View File

@ -0,0 +1,39 @@
(ns status-im.chat.handlers.console
(:require [re-frame.core :refer [dispatch dispatch-sync after]]
[status-im.utils.handlers :refer [register-handler] :as u]
[status-im.constants :refer [console-chat-id]]
[status-im.data-store.messages :as messages]))
(def console-commands
{:password
(fn [params _]
(dispatch [:create-account (params "password")]))
:phone
(fn [params id]
(dispatch [:sign-up (params "phone") id]))
:confirmation-code
(fn [params id]
(dispatch [:sign-up-confirm (params "code") id]))})
(def commands-names (set (keys console-commands)))
(def commands-with-delivery-status
(disj commands-names :password))
(register-handler :invoke-console-command-handler!
(u/side-effect!
(fn [_ [_ {:keys [staged-command] :as parameters}]]
(let [{:keys [id command params]} staged-command
{:keys [name]} command]
(dispatch [:prepare-command! parameters])
((console-commands (keyword name)) params id)))))
(register-handler :set-message-status
(after
(fn [_ [_ message-id status]]
(messages/update {:message-id message-id
:message-status status})))
(fn [db [_ message-id status]]
(assoc-in db [:message-statuses message-id] {:status status})))

View File

@ -13,8 +13,9 @@
default-number-of-messages]] default-number-of-messages]]
[status-im.utils.datetime :as datetime] [status-im.utils.datetime :as datetime]
[status-im.protocol.core :as protocol] [status-im.protocol.core :as protocol]
[taoensso.timbre :refer-macros [debug]] [taoensso.timbre :refer-macros [debug] :as log]
[taoensso.timbre :as log])) [status-im.constants :refer [console-chat-id]]
[status-im.chat.handlers.console :as console]))
(defn prepare-command (defn prepare-command
[identity chat-id clock-value [identity chat-id clock-value
@ -53,18 +54,28 @@
(not (s/blank? text)) (not (s/blank? text))
(dispatch [::prepare-message data])))))) (dispatch [::prepare-message data]))))))
(defn console-command? [chat-id command-name]
(and (= console-chat-id chat-id)
(console/commands-names (keyword command-name))))
(register-handler ::check-commands-handlers! (register-handler ::check-commands-handlers!
(u/side-effect! (u/side-effect!
(fn [_ [_ {:keys [commands message] :as params}]] (fn [_ [_ {:keys [commands message chat-id] :as params}]]
(doseq [{:keys [command] :as message} commands] (doseq [{:keys [command] :as message} commands]
(let [params' (assoc params :staged-command message)] (let [params' (assoc params :staged-command message)
command-name (:name (:command message))]
(if (:sent-to-jail? message) (if (:sent-to-jail? message)
;; todo there could be other reasons for "long-running" ;; todo there could be other reasons for "long-running"
;; hanling of the command besides sendTransaction ;; hanling of the command besides sendTransaction
(dispatch [:navigate-to :confirm]) (dispatch [:navigate-to :confirm])
(if (:has-handler command) (cond
(console-command? chat-id command-name)
(dispatch [:invoke-console-command-handler! params'])
(:has-handler command)
(dispatch [::invoke-command-handlers! params']) (dispatch [::invoke-command-handlers! params'])
:else
(dispatch [:prepare-command! params']))))) (dispatch [:prepare-command! params'])))))
(when-not (s/blank? message) (when-not (s/blank? message)
(dispatch [::prepare-message params]))))) (dispatch [::prepare-message params])))))

View File

@ -29,7 +29,8 @@
[status-im.utils.gfycat.core :refer [generate-gfy]] [status-im.utils.gfycat.core :refer [generate-gfy]]
[status-im.i18n :refer [label]] [status-im.i18n :refer [label]]
[status-im.chat.utils :as cu] [status-im.chat.utils :as cu]
[clojure.string :as str])) [clojure.string :as str]
[status-im.chat.handlers.console :as console]))
(defn message-content-status [_] (defn message-content-status [_]
(let [{:keys [chat-id group-chat name color]} (subscribe [:chat-properties [:chat-id :group-chat :name :color]]) (let [{:keys [chat-id group-chat name color]} (subscribe [:chat-properties [:chat-id :group-chat :name :color]])
@ -200,10 +201,13 @@
:font :default} :font :default}
(str "+ " (- (count user-statuses) 3))])]]))) (str "+ " (- (count user-statuses) 3))])]])))
(defview message-delivery-status [{:keys [message-id chat-id message-status user-statuses]}] (defview message-delivery-status
[{:keys [message-id chat-id message-status user-statuses content]}]
[app-db-message-status-value [:get-in [:message-statuses message-id :status]]] [app-db-message-status-value [:get-in [:message-statuses message-id :status]]]
(let [delivery-status (get-in user-statuses [chat-id :status]) (let [delivery-status (get-in user-statuses [chat-id :status])
status (if (cu/console? chat-id) command-name (keyword (:command content))
status (if (and (not (console/commands-with-delivery-status command-name))
(cu/console? chat-id))
:seen :seen
(or delivery-status message-status app-db-message-status-value :sending))] (or delivery-status message-status app-db-message-status-value :sending))]
[view st/delivery-view [view st/delivery-view

View File

@ -15,23 +15,12 @@
(let [hiccup (generate-hiccup markup)] (let [hiccup (generate-hiccup markup)]
(assoc-in db [:rendered-commands chat-id message-id] hiccup))) (assoc-in db [:rendered-commands chat-id message-id] hiccup)))
(def console-events
{:save-password (fn [[parameter]]
(dispatch [:create-account parameter]))
:sign-up (fn [[parameter]]
(dispatch [:sign-up parameter]))
:confirm-sign-up (fn [[parameter]]
(dispatch [:sign-up-confirm parameter]))})
(def regular-events {})
(defn command-hadler! (defn command-hadler!
[_ [chat-id [_ [chat-id
{:keys [staged-command] :as parameters} {:keys [staged-command] :as parameters}
{:keys [result error]}]] {:keys [result error]}]]
(let [{:keys [context returned]} result (let [{:keys [context returned]} result
{:keys [event params] {handler-error :error} returned]
handler-error :error} returned]
(cond (cond
handler-error handler-error
(log/debug :error-from-handler handler-error (log/debug :error-from-handler handler-error
@ -39,18 +28,11 @@
:command staged-command) :command staged-command)
result result
(let [{:keys [event params]} returned (let [command' (assoc staged-command :handler-data returned)
command' (assoc staged-command :handler-data returned)
parameters' (assoc parameters :command command')] parameters' (assoc parameters :command command')]
(if (:eth_sendTransaction context) (if (:eth_sendTransaction context)
(dispatch [:wait-for-transaction (:id staged-command) parameters']) (dispatch [:wait-for-transaction (:id staged-command) parameters'])
(let [events (if (= console-chat-id chat-id) (dispatch [:prepare-command! parameters'])))
(merge regular-events console-events)
regular-events)
parameters'' (if-let [handler (events (keyword event))]
(assoc parameters' :handler #(handler params command'))
parameters')]
(dispatch [:prepare-command! parameters'']))))
(not (or error handler-error)) (not (or error handler-error))
(dispatch [:prepare-command! parameters]) (dispatch [:prepare-command! parameters])

View File

@ -1,32 +1,19 @@
(ns status-im.components.react (ns status-im.components.react
(:require [reagent.core :as r] (:require [reagent.core :as r]
[status-im.components.styles :as st] [status-im.components.styles :as st]
[status-im.utils.utils :as u] [status-im.utils.utils :as u
:refer [get-react-property get-class adapt-class]]
[status-im.utils.platform :refer [platform-specific]])) [status-im.utils.platform :refer [platform-specific]]))
(def react-native (u/require "react-native")) (def react-native (u/require "react-native"))
(def native-modules (.-NativeModules react-native)) (def native-modules (.-NativeModules react-native))
(def device-event-emitter (.-DeviceEventEmitter react-native)) (def device-event-emitter (.-DeviceEventEmitter react-native))
(def geth (.-Geth native-modules))
(def linear-gradient-module (u/require "react-native-linear-gradient")) (def linear-gradient-module (u/require "react-native-linear-gradient"))
(def dismiss-keyboard! (u/require "dismissKeyboard")) (def dismiss-keyboard! (u/require "dismissKeyboard"))
(def orientation (u/require "react-native-orientation")) (def orientation (u/require "react-native-orientation"))
(def drawer (u/require "react-native-drawer-layout")) (def drawer (u/require "react-native-drawer-layout"))
;; Getters
(defn- get-react-property [name]
(aget react-native name))
(defn- adapt-class [class]
(when class
(r/adapt-react-class class)))
(defn- get-class [name]
(adapt-class (get-react-property name)))
;; React Components ;; React Components
(def app-registry (get-react-property "AppRegistry")) (def app-registry (get-react-property "AppRegistry"))

View File

@ -18,12 +18,13 @@
:duration 250}))) :duration 250})))
(defn offline-view [_] (defn offline-view [_]
(let [sync-state (subscribe [:get :sync-state]) (let [sync-state (subscribe [:get :sync-state])
offline-opacity (anim/create-value 0.0) network-status (subscribe [:get :network-status])
on-update (fn [_ _] offline-opacity (anim/create-value 0.0)
(anim/set-value offline-opacity 0) on-update (fn [_ _]
(when (= @sync-state :offline) (anim/set-value offline-opacity 0)
(start-offline-animation offline-opacity)))] (when (or (= @network-status :offline) (= @sync-state :offline))
(start-offline-animation offline-opacity)))]
(r/create-class (r/create-class
{:component-did-mount {:component-did-mount
on-update on-update
@ -31,7 +32,7 @@
on-update on-update
:reagent-render :reagent-render
(fn [{:keys [top]}] (fn [{:keys [top]}]
(when (= @sync-state :offline) (when (or (= @network-status :offline) (= @sync-state :offline))
[animated-view {:style (st/offline-wrapper top offline-opacity window-width)} [animated-view {:style (st/offline-wrapper top offline-opacity window-width)}
[view [view
[text {:style st/offline-text} [text {:style st/offline-text}

View File

@ -22,6 +22,7 @@
status-im.accounts.handlers status-im.accounts.handlers
status-im.protocol.handlers status-im.protocol.handlers
status-im.transactions.handlers status-im.transactions.handlers
status-im.network.handlers
[status-im.utils.types :as t] [status-im.utils.types :as t]
[status-im.constants :refer [console-chat-id]])) [status-im.constants :refer [console-chat-id]]))

View File

@ -1,10 +1,12 @@
(ns status-im.handlers.server (ns status-im.handlers.server
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
[status-im.utils.utils :refer [http-post]] [status-im.utils.utils :refer [http-post]]
[taoensso.timbre :as log])) [taoensso.timbre :as log]
[status-im.utils.scheduler :as sch]
[status-im.data-store.messages :as messages]))
(defn sign-up (defn sign-up
[db phone-number handler] [db phone-number message-id handler]
(let [current-account-id (get db :current-account-id) (let [current-account-id (get db :current-account-id)
{:keys [public-key address]} (get-in db [:accounts current-account-id])] {:keys [public-key address]} (get-in db [:accounts current-account-id])]
;(user-data/save-phone-number phone-number) ;(user-data/save-phone-number phone-number)
@ -14,11 +16,22 @@
:address address} :address address}
(fn [body] (fn [body]
(log/debug body) (log/debug body)
(handler))) (dispatch [:set-message-status message-id :seen])
(handler))
(fn [_]
(sch/execute-later
#(dispatch [:sign-up phone-number message-id])
(sch/s->ms 1))))
db)) db))
(defn sign-up-confirm (defn sign-up-confirm
[confirmation-code handler] [confirmation-code message-id handler]
(http-post "sign-up-confirm" (http-post "sign-up-confirm"
{:code confirmation-code} {:code confirmation-code}
handler)) (fn [body]
(dispatch [:set-message-status message-id :seen])
(handler body))
(fn [_]
(sch/execute-later
#(dispatch [:sign-up-confirm confirmation-code message-id])
(sch/s->ms 1)))))

View File

@ -0,0 +1,18 @@
(ns status-im.network.handlers
(:require [re-frame.core :refer [dispatch debug enrich after]]
[status-im.utils.handlers :refer [register-handler]]
[status-im.utils.handlers :as u]
[status-im.network.net-info :as ni]
[clojure.string :as s]))
(register-handler :listen-to-network-status!
(u/side-effect!
(fn []
(let [handler #(dispatch [:update-network-status %])]
(ni/init handler)
(ni/add-listener handler)))))
(register-handler :update-network-status
(fn [db [_ is-connected?]]
(let [status (if is-connected? :online :offline)]
(assoc db :network-status status))))

View File

@ -0,0 +1,16 @@
(ns status-im.network.net-info
(:require [status-im.utils.utils :as u]
[taoensso.timbre :as log]))
(def net-info (u/get-react-property "NetInfo"))
(defn init [callback]
(when net-info
(.then (.fetch (.-isConnected net-info))
(fn [is-connected?]
(log/debug "Is connected?" is-connected?)
(callback is-connected?)))))
(defn add-listener [listener]
(when net-info
(.addEventListener (.-isConnected net-info) "change" listener)))

View File

@ -184,7 +184,7 @@
(register-handler :participant-invited-to-group (register-handler :participant-invited-to-group
(u/side-effect! (u/side-effect!
(fn [{:keys [current-public-key]} (fn [{:keys [current-public-key]}
[_ {:keys [from] [_ {:keys [from]
{:keys [group-id identity message-id]} :payload}]] {:keys [group-id identity message-id]} :payload}]]
(participant-invited-to-group-message group-id current-public-key identity from message-id) (participant-invited-to-group-message group-id current-public-key identity from message-id)
(when-not (= current-public-key identity) (when-not (= current-public-key identity)
@ -232,11 +232,11 @@
[_ {:keys [from] [_ {:keys [from]
{:keys [message-id ack-of-message group-id]} :payload}]] {:keys [message-id ack-of-message group-id]} :payload}]]
(if (chats/is-active? (or group-id from)) (if (chats/is-active? (or group-id from))
(let [message-id' (or ack-of-message message-id) (let [message-id' (or ack-of-message message-id)
group? (boolean group-id) group? (boolean group-id)
status-path (if (and group? (not= status :sent)) status-path (if (and group? (not= status :sent))
[:message-user-statuses message-id' from] [:message-user-statuses message-id' from]
[:message-statuses message-id']) [:message-statuses message-id'])
{current-status :status} (get-in db status-path)] {current-status :status} (get-in db status-path)]
(if-not (= :seen current-status) (if-not (= :seen current-status)
(assoc-in db status-path {:whisper-identity from (assoc-in db status-path {:whisper-identity from

View File

@ -0,0 +1,10 @@
(ns status-im.utils.scheduler
(:require-macros [cljs.core.async.macros :refer [go]])
(:require [cljs.core.async :refer [<! timeout]]))
(defn s->ms [s] (* 1000 s))
(defn execute-later
[function timeout-ms]
(go (<! (timeout timeout-ms))
(function)))

View File

@ -1,7 +1,8 @@
(ns status-im.utils.utils (ns status-im.utils.utils
(:require-macros (:require-macros
[natal-shell.async-storage :refer [get-item set-item]]) [natal-shell.async-storage :refer [get-item set-item]])
(:require [status-im.constants :as const])) (:require [status-im.constants :as const]
[reagent.core :as r]))
(defn require [module] (defn require [module]
(if (exists? js/window) (if (exists? js/window)
@ -64,3 +65,13 @@
(if (cond (first coll)) (if (cond (first coll))
index index
(recur (inc index) cond (next coll)))))) (recur (inc index) cond (next coll))))))
(defn get-react-property [name]
(aget react-native name))
(defn adapt-class [class]
(when class
(r/adapt-react-class class)))
(defn get-class [name]
(adapt-class (get-react-property name)))

View File

@ -8,7 +8,6 @@
(defn init-stubs [] (defn init-stubs []
(register-handler :sign-up (register-handler :sign-up
(fn [] (fn []
(println :ohh)
;; todo save phone number to db ;; todo save phone number to db
(sign-up-service/on-sign-up-response))) (sign-up-service/on-sign-up-response)))