From a644075310cc7d132f3de040154c906db1b4a93b Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Fri, 6 Jul 2018 22:47:59 +0300 Subject: [PATCH] No browsing history kept on iOS [#5078] Signed-off-by: Andrey Shovkoplyas --- resources/js/webview.js | 11 ++ .../realm/schemas/account/core.cljs | 8 +- .../realm/schemas/account/v8/browser.cljs | 36 +++--- .../realm/schemas/account/v8/core.cljs | 25 ++++ src/status_im/models/browser.cljs | 38 ++++++ src/status_im/models/browser_history.cljs | 56 --------- .../ui/components/list_selection.cljs | 4 +- .../ui/screens/add_new/open_dapp/views.cljs | 2 +- src/status_im/ui/screens/browser/db.cljs | 8 +- src/status_im/ui/screens/browser/events.cljs | 94 +++++++------- .../ui/screens/browser/navigation.cljs | 8 +- src/status_im/ui/screens/browser/views.cljs | 87 +++++++------ src/status_im/ui/screens/db.cljs | 2 +- .../ui/screens/home/views/inner_item.cljs | 8 +- .../collectibles/cryptokitties/views.cljs | 2 +- .../collectibles/cryptostrikers/views.cljs | 2 +- .../wallet/collectibles/etheremon/views.cljs | 2 +- .../screens/wallet/collectibles/events.cljs | 2 +- src/status_im/utils/http.cljs | 4 +- test/cljs/status_im/test/browser/events.cljs | 109 ++++++++++++++++ .../test/models/browser_history.cljs | 117 ------------------ test/cljs/status_im/test/runner.cljs | 6 +- 22 files changed, 331 insertions(+), 300 deletions(-) create mode 100644 src/status_im/data_store/realm/schemas/account/v8/core.cljs create mode 100644 src/status_im/models/browser.cljs delete mode 100644 src/status_im/models/browser_history.cljs create mode 100644 test/cljs/status_im/test/browser/events.cljs delete mode 100644 test/cljs/status_im/test/models/browser_history.cljs diff --git a/resources/js/webview.js b/resources/js/webview.js index 14c6814325..9aa513f041 100644 --- a/resources/js/webview.js +++ b/resources/js/webview.js @@ -1,4 +1,15 @@ (function () { + var history = window.history; + var pushState = history.pushState; + history.pushState = function(state) { + setTimeout(function () { + WebViewBridge.send(JSON.stringify({ + type: 'navStateChange', + navState: { url: location.href, title: document.title } + })) + }, 100); + return pushState.apply(history, arguments); + }; WebViewBridge.onMessage = function (messageString) { console.log("received from react-native: " + messageString); diff --git a/src/status_im/data_store/realm/schemas/account/core.cljs b/src/status_im/data_store/realm/schemas/account/core.cljs index 4d80ced62b..f1100ee90a 100644 --- a/src/status_im/data_store/realm/schemas/account/core.cljs +++ b/src/status_im/data_store/realm/schemas/account/core.cljs @@ -6,7 +6,8 @@ [status-im.data-store.realm.schemas.account.v4.core :as v4] [status-im.data-store.realm.schemas.account.v5.core :as v5] [status-im.data-store.realm.schemas.account.v6.core :as v6] - [status-im.data-store.realm.schemas.account.v7.core :as v7])) + [status-im.data-store.realm.schemas.account.v7.core :as v7] + [status-im.data-store.realm.schemas.account.v8.core :as v8])) ;; TODO(oskarth): Add failing test if directory vXX exists but isn't in schemas. @@ -31,4 +32,7 @@ :migration v6/migration} {:schema v7/schema :schemaVersion 7 - :migration v7/migration}]) + :migration v7/migration} + {:schema v8/schema + :schemaVersion 8 + :migration v8/migration}]) diff --git a/src/status_im/data_store/realm/schemas/account/v8/browser.cljs b/src/status_im/data_store/realm/schemas/account/v8/browser.cljs index 7617274667..24e88108eb 100644 --- a/src/status_im/data_store/realm/schemas/account/v8/browser.cljs +++ b/src/status_im/data_store/realm/schemas/account/v8/browser.cljs @@ -1,17 +1,25 @@ -(ns status-im.data-store.realm.schemas.account.v8.browser) +(ns status-im.data-store.realm.schemas.account.v8.browser + (:require [taoensso.timbre :as log])) (def schema {:name :browser :primaryKey :browser-id - :properties {:browser-id :string - :name :string - :timestamp :int - :dapp? {:type :bool - :default false} - :url {:type :string - :optional true} - :contact {:type :string - :optional true} - :history-index {:type :int - :optional true} - :history {:type :vector - :optional true}}}) + :properties {:browser-id :string + :name :string + :timestamp :int + :dapp? {:type :bool + :default false} + :history-index {:type :int + :optional true} + :history {:type "string[]" + :optional true}}}) + +(defn migration [old-realm new-realm] + (log/debug "migrating browser schema v8") + (let [browsers (.objects new-realm "browser") + old-browsers (.objects old-realm "browser")] + (dotimes [i (.-length browsers)] + (let [browser (aget browsers i) + old-browser (aget old-browsers i) + url (aget old-browser "url")] + (aset browser "history-index" 0) + (aset browser "history" (clj->js [url])))))) \ No newline at end of file diff --git a/src/status_im/data_store/realm/schemas/account/v8/core.cljs b/src/status_im/data_store/realm/schemas/account/v8/core.cljs new file mode 100644 index 0000000000..3342bf8d13 --- /dev/null +++ b/src/status_im/data_store/realm/schemas/account/v8/core.cljs @@ -0,0 +1,25 @@ +(ns status-im.data-store.realm.schemas.account.v8.core + (:require [status-im.data-store.realm.schemas.account.v5.chat :as chat] + [status-im.data-store.realm.schemas.account.v6.transport :as transport] + [status-im.data-store.realm.schemas.account.v1.contact :as contact] + [status-im.data-store.realm.schemas.account.v7.message :as message] + [status-im.data-store.realm.schemas.account.v1.request :as request] + [status-im.data-store.realm.schemas.account.v1.user-status :as user-status] + [status-im.data-store.realm.schemas.account.v1.local-storage :as local-storage] + [status-im.data-store.realm.schemas.account.v2.mailserver :as mailserver] + [status-im.data-store.realm.schemas.account.v8.browser :as browser] + [taoensso.timbre :as log])) + +(def schema [chat/schema + transport/schema + contact/schema + message/schema + request/schema + mailserver/schema + user-status/schema + local-storage/schema + browser/schema]) + +(defn migration [old-realm new-realm] + (log/debug "migrating v8 account database: " old-realm new-realm) + (browser/migration old-realm new-realm)) diff --git a/src/status_im/models/browser.cljs b/src/status_im/models/browser.cljs new file mode 100644 index 0000000000..249ddadabe --- /dev/null +++ b/src/status_im/models/browser.cljs @@ -0,0 +1,38 @@ +(ns status-im.models.browser + (:require [status-im.data-store.browser :as browser-store])) + +(defn get-current-url [{:keys [history history-index]}] + (when (and history-index history) + (nth history history-index))) + +(defn can-go-back? [{:keys [history-index]}] + (pos? history-index)) + +(defn can-go-forward? [{:keys [history-index history]}] + (< history-index (dec (count history)))) + +(defn update-browser-fx [{:keys [db now]} browser] + (let [updated-browser (assoc browser :timestamp now)] + {:db (update-in db [:browser/browsers (:browser-id updated-browser)] + merge updated-browser) + :data-store/tx [(browser-store/save-browser-tx updated-browser)]})) + +(defn update-browser-history-fx [cofx browser url loading?] + (when-not loading? + (let [history-index (:history-index browser) + history (:history browser) + history-url (try (nth history history-index) (catch js/Error _))] + (when (not= history-url url) + (let [slash? (= url (str history-url "/")) + new-history (if slash? + (assoc history history-index url) + (conj (subvec history 0 (inc history-index)) url)) + new-index (if slash? + history-index + (dec (count new-history)))] + (update-browser-fx cofx + (assoc browser :history new-history :history-index new-index))))))) + +(defn update-browser-and-navigate [cofx browser] + (merge (update-browser-fx cofx browser) + {:dispatch [:navigate-to :browser (:browser-id browser)]})) \ No newline at end of file diff --git a/src/status_im/models/browser_history.cljs b/src/status_im/models/browser_history.cljs deleted file mode 100644 index 52c3c9737d..0000000000 --- a/src/status_im/models/browser_history.cljs +++ /dev/null @@ -1,56 +0,0 @@ -(ns status-im.models.browser-history - (:require [re-frame.core :as re-frame])) - -(defn dont-store-history-on-nav-change? [db] - (get-in db [:browser/options :dont-store-history-on-nav-change?])) - -(defn dont-store-history-on-nav-change! [] - (re-frame/dispatch [:update-browser-options {:dont-store-history-on-nav-change? true}])) - -(defn clear-dont-store-history-on-nav-change! [] - (re-frame/dispatch [:update-browser-options {:dont-store-history-on-nav-change? false}])) - -(defn dont-store-history-on-nav-change-if-history-exists [db browser-id] - (let [browsers (get-in db [:browser/browsers]) - browser (get browsers browser-id)] - (hash-map :dont-store-history-on-nav-change? (some? (:history browser))))) - -(defn back [browser] - (let [back-index (dec (:history-index browser)) - back-url (nth (:history browser) back-index)] - (dont-store-history-on-nav-change!) - (re-frame/dispatch [:update-browser (-> browser (assoc :url back-url :history-index back-index))]))) - -(defn forward [browser] - (let [forward-index (inc (:history-index browser)) - forward-url (nth (:history browser) forward-index)] - (dont-store-history-on-nav-change!) - (re-frame/dispatch [:update-browser (-> browser (assoc :url forward-url :history-index forward-index))]))) - -(defn can-go-back? [browser] - (let [hi (:history-index browser)] - (and (some? hi) (not= hi 0)))) - -(defn can-go-forward? [browser] - (let [hi (:history-index browser)] - (and (some? hi) - (< hi (dec (count (:history browser))))))) - -(defn record-history-in-browser-if-needed [db raw-browser url loading] - (let [browser (assoc raw-browser :url url)] - (cond - loading - browser - - (dont-store-history-on-nav-change? db) - (do (clear-dont-store-history-on-nav-change!) - browser) - - :else - (let [history-index (:history-index browser) - history (or (:history browser) []) - history-url (if history-index (nth history history-index) nil) - history-to-index (if history-index (subvec history 0 (inc history-index)) []) - new-history (if (not= history-url url) (conj history-to-index url) history) - new-index (dec (count new-history))] - (assoc browser :history new-history :history-index new-index))))) diff --git a/src/status_im/ui/components/list_selection.cljs b/src/status_im/ui/components/list_selection.cljs index 11563a60c1..f6a3845505 100644 --- a/src/status_im/ui/components/list_selection.cljs +++ b/src/status_im/ui/components/list_selection.cljs @@ -31,7 +31,7 @@ (defn browse [link] (show {:title (i18n/label :t/browsing-title) :options [{:label (i18n/label :t/browsing-open-in-browser) - :action #(re-frame/dispatch [:open-browser {:url link}])} + :action #(re-frame/dispatch [:open-url-in-browser link])} {:label (i18n/label :t/browsing-open-in-web-browser) :action #(.openURL react/linking (http/normalize-url link))}] :cancel-text (i18n/label :t/browsing-cancel)})) @@ -39,5 +39,5 @@ (defn browse-dapp [link] (show {:title (i18n/label :t/browsing-title) :options [{:label (i18n/label :t/browsing-open-in-browser) - :action #(re-frame/dispatch [:open-browser {:url link}])}] + :action #(re-frame/dispatch [:open-url-in-browser link])}] :cancel-text (i18n/label :t/browsing-cancel)})) diff --git a/src/status_im/ui/screens/add_new/open_dapp/views.cljs b/src/status_im/ui/screens/add_new/open_dapp/views.cljs index 13f06575b6..12563547c5 100644 --- a/src/status_im/ui/screens/add_new/open_dapp/views.cljs +++ b/src/status_im/ui/screens/add_new/open_dapp/views.cljs @@ -31,7 +31,7 @@ [react/text-input {:on-change-text #(reset! url-text %) :on-submit-editing #(do (re-frame/dispatch [:navigate-to-clean :home]) - (re-frame/dispatch [:open-browser {:url @url-text}])) + (re-frame/dispatch [:open-url-in-browser @url-text])) :placeholder (i18n/label :t/enter-url) :auto-capitalize :none :auto-correct false diff --git a/src/status_im/ui/screens/browser/db.cljs b/src/status_im/ui/screens/browser/db.cljs index aa2e1fd99f..5967eb3409 100644 --- a/src/status_im/ui/screens/browser/db.cljs +++ b/src/status_im/ui/screens/browser/db.cljs @@ -9,18 +9,14 @@ (spec/def :browser/photo-path (spec/nilable string?)) (spec/def :browser/name (spec/nilable string?)) (spec/def :browser/dapp? (spec/nilable boolean?)) -(spec/def :browser/fullscreen? (spec/nilable boolean?)) (spec/def :browser/error? (spec/nilable boolean?)) (spec/def :browser/history (spec/nilable vector?)) (spec/def :browser/history-index (spec/nilable int?)) -(spec/def :browser/dont-store-history-on-nav-change? (spec/nilable boolean?)) (spec/def :browser/options (allowed-keys :opt-un [:browser/browser-id - :browser/fullscreen? - :browser/error? - :browser/dont-store-history-on-nav-change?])) + :browser/error?])) (spec/def :browser/browser (allowed-keys @@ -28,8 +24,6 @@ :browser/timestamp] :opt-un [:browser/name :browser/dapp? - :browser/url - :browser/contact :browser/history :browser/history-index])) diff --git a/src/status_im/ui/screens/browser/events.cljs b/src/status_im/ui/screens/browser/events.cljs index 5a14132802..b148567159 100644 --- a/src/status_im/ui/screens/browser/events.cljs +++ b/src/status_im/ui/screens/browser/events.cljs @@ -1,6 +1,5 @@ (ns status-im.ui.screens.browser.events (:require status-im.ui.screens.browser.navigation - [status-im.models.browser-history :as browser-history] [status-im.utils.handlers :as handlers] [re-frame.core :as re-frame] [status-im.utils.random :as random] @@ -8,7 +7,15 @@ [status-im.ui.components.list-selection :as list-selection] [status-im.utils.universal-links.core :as utils.universal-links] [status-im.data-store.browser :as browser-store] - [status-im.utils.http :as http])) + [status-im.utils.http :as http] + [status-im.models.browser :as model])) + +(re-frame/reg-fx + :browse + (fn [link] + (if (utils.universal-links/universal-link? link) + (utils.universal-links/open! link) + (list-selection/browse link)))) (handlers/register-handler-fx :initialize-browsers @@ -17,71 +24,49 @@ (let [browsers (into {} (map #(vector (:browser-id %) %) all-stored-browsers))] {:db (assoc db :browser/browsers browsers)}))) -(re-frame/reg-fx - :browse - (fn [link] - (if (utils.universal-links/universal-link? link) - (do - (utils.universal-links/open! link)) - (list-selection/browse link)))) - (handlers/register-handler-fx :browse-link-from-message (fn [_ [_ link]] {:browse link})) -(defn get-new-browser [browser now] - (cond-> browser - true - (assoc :timestamp now) - (not (:browser-id browser)) - (assoc :browser-id (random/id)) - (not (:name browser)) - (assoc :name (i18n/label :t/browser)) - (:url browser) - (update :url (comp js/decodeURI http/normalize-url)))) - -(defn add-browser-fx [{:keys [db now]} browser] - (let [new-browser (get-new-browser browser now)] - {:db (update-in db [:browser/browsers (:browser-id new-browser)] - merge new-browser) - :data-store/tx [(browser-store/save-browser-tx new-browser)]})) - (handlers/register-handler-fx :open-dapp-in-browser [re-frame/trim-v] (fn [cofx [{:keys [name dapp-url]}]] - (let [browser {:browser-id name - :name name - :dapp? true - :url dapp-url}] - (merge (add-browser-fx cofx browser) - {:dispatch [:navigate-to :browser {:browser/browser-id (:browser-id browser)}]})))) + (let [browser {:browser-id name + :name name + :dapp? true + :history-index 0 + :history [(http/normalize-and-decode-url dapp-url)]}] + (model/update-browser-and-navigate cofx browser)))) + +(handlers/register-handler-fx + :open-url-in-browser + [re-frame/trim-v] + (fn [cofx [url]] + (let [browser {:browser-id (random/id) + :name (i18n/label :t/browser) + :history-index 0 + :history [(http/normalize-and-decode-url url)]}] + (model/update-browser-and-navigate cofx browser)))) (handlers/register-handler-fx :open-browser [re-frame/trim-v] - (fn [{:keys [now] :as cofx} [browser]] - (let [new-browser (get-new-browser browser now)] - (merge (add-browser-fx cofx new-browser) - {:dispatch [:navigate-to :browser {:browser/browser-id (:browser-id new-browser)}]})))) + (fn [cofx [browser]] + (model/update-browser-and-navigate cofx browser))) (handlers/register-handler-fx :update-browser [re-frame/trim-v] - (fn [{:keys [now] :as cofx} [browser]] - (let [new-browser (get-new-browser browser now)] - (-> (add-browser-fx cofx new-browser) - (update-in [:db :browser/options] #(assoc % :browser-id (:browser-id new-browser))))))) + (fn [cofx [browser]] + (model/update-browser-fx cofx browser))) (handlers/register-handler-fx :update-browser-on-nav-change [re-frame/trim-v] - (fn [{:keys [db now] :as cofx} [browser url loading]] - (let [new-browser (get-new-browser browser now) - new-browser-with-history-updated (browser-history/record-history-in-browser-if-needed db new-browser url loading)] - (-> (add-browser-fx cofx new-browser-with-history-updated) - (update-in [:db :browser/options] assoc :browser-id (:browser-id new-browser-with-history-updated)))))) + (fn [cofx [browser url loading]] + (model/update-browser-history-fx cofx browser url loading))) (handlers/register-handler-fx :update-browser-options @@ -95,3 +80,20 @@ (fn [{:keys [db]} [browser-id]] {:db (update-in db [:browser/browsers] dissoc browser-id) :data-store/tx [(browser-store/remove-browser-tx browser-id)]})) + +(defn nav-update-browser [cofx browser history-index] + (model/update-browser-fx cofx (assoc browser :history-index history-index))) + +(handlers/register-handler-fx + :browser-nav-back + [re-frame/trim-v] + (fn [cofx [{:keys [history-index] :as browser}]] + (when (pos? history-index) + (nav-update-browser cofx browser (dec history-index))))) + +(handlers/register-handler-fx + :browser-nav-forward + [re-frame/trim-v] + (fn [cofx [{:keys [history-index] :as browser}]] + (when (< history-index (dec (count (:history browser)))) + (nav-update-browser cofx browser (inc history-index))))) \ No newline at end of file diff --git a/src/status_im/ui/screens/browser/navigation.cljs b/src/status_im/ui/screens/browser/navigation.cljs index c838e7e414..2105b794cb 100644 --- a/src/status_im/ui/screens/browser/navigation.cljs +++ b/src/status_im/ui/screens/browser/navigation.cljs @@ -1,8 +1,6 @@ (ns status-im.ui.screens.browser.navigation - (:require [status-im.ui.screens.navigation :as navigation] - [status-im.models.browser-history :as browser-history])) + (:require [status-im.ui.screens.navigation :as navigation])) (defmethod navigation/preload-data! :browser - [db [_ _ {:keys [browser/browser-id]}]] - (let [dont-store (browser-history/dont-store-history-on-nav-change-if-history-exists db browser-id)] - (assoc db :browser/options (assoc dont-store :browser-id browser-id)))) + [db [_ _ browser-id]] + (assoc db :browser/options {:browser-id browser-id})) diff --git a/src/status_im/ui/screens/browser/views.cljs b/src/status_im/ui/screens/browser/views.cljs index 65ad41f392..411591ac54 100644 --- a/src/status_im/ui/screens/browser/views.cljs +++ b/src/status_im/ui/screens/browser/views.cljs @@ -3,7 +3,6 @@ [status-im.utils.views :as views]) (:require [cljs.reader :as reader] [re-frame.core :as re-frame] - [status-im.models.browser-history :as browser-history] [status-im.ui.components.react :as react] [status-im.ui.screens.browser.styles :as styles] [status-im.ui.components.status-bar.view :as status-bar] @@ -17,7 +16,9 @@ [status-im.i18n :as i18n] [status-im.utils.ethereum.core :as ethereum] [status-im.ui.components.toolbar.actions :as actions] - [status-im.ui.components.tooltip.views :as tooltip])) + [status-im.ui.components.tooltip.views :as tooltip] + [status-im.models.browser :as model] + [status-im.utils.platform :as platform])) (views/defview toolbar-content-dapp [name] (views/letsubs [dapp [:get-dapp-by-name name]] @@ -36,7 +37,7 @@ (def browser-config (reader/read-string (slurp "./src/status_im/utils/browser_config.edn"))) -(defn toolbar-content [{:keys [url] :as browser}] +(defn toolbar-content [url browser] (let [url-text (atom url)] [react/view [react/view (styles/toolbar-content false) @@ -64,6 +65,13 @@ [react/view styles/web-view-loading [components/activity-indicator {:animating true}]])) +(defn on-bridge-message [message browser] + (let [{:strs [type navState]} (js->clj (.parse js/JSON message)) + {:strs [url]} navState] + (when (and platform/ios? (= type "navStateChange")) + (when (not= "about:blank" url) + (re-frame/dispatch [:update-browser-on-nav-change browser url false]))))) + (defn on-navigation-change [event browser] (let [{:strs [url loading]} (js->clj event)] (when (not= "about:blank" url) @@ -74,25 +82,28 @@ (get (:inject-js browser-config) domain-name))) (views/defview browser [] - (views/letsubs [webview (atom nil) + (views/letsubs [webview (atom nil) {:keys [address]} [:get-current-account] - {:keys [dapp? url browser-id name] :as browser} [:get-current-browser] - {:keys [can-go-back? can-go-forward? error?]} [:get :browser/options] - rpc-url [:get :rpc-url] + {:keys [dapp? browser-id name] :as browser} [:get-current-browser] + {:keys [error?]} [:get :browser/options] + rpc-url [:get :rpc-url] network-id [:get-network-id]] - [react/keyboard-avoiding-view styles/browser - [status-bar/status-bar] - [toolbar.view/toolbar {} - [toolbar.view/nav-button-with-count - (actions/close (fn [] - (.sendToBridge @webview "navigate-to-blank") - (re-frame/dispatch [:navigate-back]) - (when error? - (re-frame/dispatch [:remove-browser browser-id]))))] - (if dapp? - [toolbar-content-dapp name] - [toolbar-content browser])] - (if url + (let [can-go-back? (model/can-go-back? browser) + can-go-forward? (model/can-go-forward? browser) + url (model/get-current-url browser)] + [react/keyboard-avoiding-view styles/browser + [status-bar/status-bar] + [toolbar.view/toolbar {} + [toolbar.view/nav-button-with-count + (actions/close (fn [] + (when @webview + (.sendToBridge @webview "navigate-to-blank")) + (re-frame/dispatch [:navigate-back]) + (when error? + (re-frame/dispatch [:remove-browser browser-id]))))] + (if dapp? + [toolbar-content-dapp name] + [toolbar-content url browser])] [components.webview-bridge/webview-bridge {:ref #(reset! webview %) :source {:uri url} @@ -103,6 +114,7 @@ :render-error web-view-error :render-loading web-view-loading :on-navigation-state-change #(on-navigation-change % browser) + :on-bridge-message #(on-bridge-message % browser) :on-load #(re-frame/dispatch [:update-browser-options {:error? false}]) :on-error #(re-frame/dispatch [:update-browser-options {:error? true}]) :injected-on-start-loading-java-script (str js-res/web3 @@ -112,21 +124,20 @@ (ethereum/normalized-address address) (str network-id))) :injected-java-script js-res/webview-js}] - [react/view styles/background - [react/text (i18n/label :t/enter-dapp-url)]]) - [react/view styles/toolbar - [react/touchable-highlight {:on-press #(browser-history/back browser) - :disabled (not (browser-history/can-go-back? browser)) - :style (if (not (browser-history/can-go-back? browser)) styles/disabled-button) - :accessibility-label :previou-page-button} - [react/view - [vector-icons/icon :icons/arrow-left]]] - [react/touchable-highlight {:on-press #(browser-history/forward browser) - :disabled (not (browser-history/can-go-forward? browser)) - :style (merge styles/forward-button (if (not (browser-history/can-go-forward? browser)) styles/disabled-button)) - :accessibility-label :next-page-button} - [react/view - [vector-icons/icon :icons/arrow-right]]]] - (when-not dapp? - [tooltip/bottom-tooltip-info - (i18n/label :t/browser-warning)])])) + [react/view styles/toolbar + [react/touchable-highlight {:on-press #(re-frame/dispatch [:browser-nav-back browser]) + :disabled (not can-go-back?) + :style (when-not can-go-back? styles/disabled-button) + :accessibility-label :previou-page-button} + [react/view + [vector-icons/icon :icons/arrow-left]]] + [react/touchable-highlight {:on-press #(re-frame/dispatch [:browser-nav-forward browser]) + :disabled (not can-go-forward?) + :style (merge styles/forward-button + (when-not can-go-forward? styles/disabled-button)) + :accessibility-label :next-page-button} + [react/view + [vector-icons/icon :icons/arrow-right]]]] + (when-not dapp? + [tooltip/bottom-tooltip-info + (i18n/label :t/browser-warning)])]))) diff --git a/src/status_im/ui/screens/db.cljs b/src/status_im/ui/screens/db.cljs index 1ca2bf574f..1848415748 100644 --- a/src/status_im/ui/screens/db.cljs +++ b/src/status_im/ui/screens/db.cljs @@ -93,7 +93,7 @@ (spec/def :navigation/prev-view-id (spec/nilable keyword?)) ;; navigation screen params (spec/def :navigation.screen-params/network-details (allowed-keys :req [:networks/selected-network])) -(spec/def :navigation.screen-params/browser (allowed-keys :req [:browser/browser-id])) +(spec/def :navigation.screen-params/browser (spec/nilable string?)) (spec/def :navigation.screen-params.profile-qr-viewer/contact (spec/nilable map?)) (spec/def :navigation.screen-params.profile-qr-viewer/source (spec/nilable keyword?)) (spec/def :navigation.screen-params.profile-qr-viewer/value (spec/nilable string?)) diff --git a/src/status_im/ui/screens/home/views/inner_item.cljs b/src/status_im/ui/screens/home/views/inner_item.cljs index 4ac1d1aaeb..3c968f2844 100644 --- a/src/status_im/ui/screens/home/views/inner_item.cljs +++ b/src/status_im/ui/screens/home/views/inner_item.cljs @@ -16,7 +16,8 @@ [status-im.ui.components.chat-preview :as chat-preview] [status-im.ui.components.icons.vector-icons :as vector-icons] [status-im.ui.components.chat-icon.screen :as chat-icon.screen] - [status-im.ui.components.common.common :as components.common])) + [status-im.ui.components.common.common :as components.common] + [status-im.models.browser :as model])) (defn command-short-preview [{:keys [command] {:keys [amount asset]} :params}] @@ -111,8 +112,9 @@ [message-content-text last-message] [unviewed-indicator chat-id]]]]]))) -(defview home-list-browser-item-inner-view [{:keys [name url] :as browser}] - (letsubs [dapp [:get-dapp-by-name name]] +(defview home-list-browser-item-inner-view [{:keys [name] :as browser}] + (letsubs [dapp [:get-dapp-by-name name] + url (model/get-current-url browser)] [react/touchable-highlight {:on-press #(re-frame/dispatch [:open-browser browser])} [react/view styles/chat-container [react/view styles/chat-icon-container diff --git a/src/status_im/ui/screens/wallet/collectibles/cryptokitties/views.cljs b/src/status_im/ui/screens/wallet/collectibles/cryptokitties/views.cljs index 4c30771781..638d941fa9 100644 --- a/src/status_im/ui/screens/wallet/collectibles/cryptokitties/views.cljs +++ b/src/status_im/ui/screens/wallet/collectibles/cryptokitties/views.cljs @@ -25,4 +25,4 @@ :icon-opts {:color colors/blue} :accessibility-label :open-collectible-button :on-press #(re-frame/dispatch [:open-collectible-in-browser - {:url (str "https://www.cryptokitties.co/kitty/" id)}])}]]) \ No newline at end of file + (str "https://www.cryptokitties.co/kitty/" id)])}]]) \ No newline at end of file diff --git a/src/status_im/ui/screens/wallet/collectibles/cryptostrikers/views.cljs b/src/status_im/ui/screens/wallet/collectibles/cryptostrikers/views.cljs index 61b64920d3..158b404828 100644 --- a/src/status_im/ui/screens/wallet/collectibles/cryptostrikers/views.cljs +++ b/src/status_im/ui/screens/wallet/collectibles/cryptostrikers/views.cljs @@ -24,4 +24,4 @@ :icon :icons/address :icon-opts {:color colors/blue} :accessibility-label :open-collectible-button - :on-press #(re-frame/dispatch [:open-collectible-in-browser {:url external_url}])}]]) + :on-press #(re-frame/dispatch [:open-collectible-in-browser external_url])}]]) diff --git a/src/status_im/ui/screens/wallet/collectibles/etheremon/views.cljs b/src/status_im/ui/screens/wallet/collectibles/etheremon/views.cljs index 8a871ce020..3742b626bc 100644 --- a/src/status_im/ui/screens/wallet/collectibles/etheremon/views.cljs +++ b/src/status_im/ui/screens/wallet/collectibles/etheremon/views.cljs @@ -24,4 +24,4 @@ :icon-opts {:color colors/blue} :accessibility-label :open-collectible-button :on-press #(re-frame/dispatch [:open-collectible-in-browser - {:url (str "https://www.etheremon.com/#/mons/" class_id)}])}]]) + (str "https://www.etheremon.com/#/mons/" class_id)])}]]) diff --git a/src/status_im/ui/screens/wallet/collectibles/events.cljs b/src/status_im/ui/screens/wallet/collectibles/events.cljs index 02983c55f3..a702bfdb39 100644 --- a/src/status_im/ui/screens/wallet/collectibles/events.cljs +++ b/src/status_im/ui/screens/wallet/collectibles/events.cljs @@ -63,4 +63,4 @@ :open-collectible-in-browser [re-frame/trim-v] (fn [_ [data]] - {:dispatch [:open-browser data]})) \ No newline at end of file + {:dispatch [:open-url-in-browser data]})) \ No newline at end of file diff --git a/src/status_im/utils/http.cljs b/src/status_im/utils/http.cljs index 1f57e901bc..522dc45d69 100644 --- a/src/status_im/utils/http.cljs +++ b/src/status_im/utils/http.cljs @@ -61,7 +61,9 @@ (utils/show-popup "Error" (str error)))))))) (defn normalize-url [url] - (str (when (and url (not (re-find #"^[a-zA-Z-_]+:/" url))) "http://") url)) + (str (when (and (string? url) (not (re-find #"^[a-zA-Z-_]+:/" url))) "http://") url)) + +(def normalize-and-decode-url (comp js/decodeURI normalize-url)) (defn parse-payload [o] (when o diff --git a/test/cljs/status_im/test/browser/events.cljs b/test/cljs/status_im/test/browser/events.cljs new file mode 100644 index 0000000000..a360815b67 --- /dev/null +++ b/test/cljs/status_im/test/browser/events.cljs @@ -0,0 +1,109 @@ +(ns status-im.test.browser.events + (:require [cljs.test :refer-macros [deftest is testing]] + [day8.re-frame.test :refer-macros [run-test-sync]] + [status-im.ui.screens.events :as events] + status-im.ui.screens.db + status-im.ui.screens.subs + [re-frame.core :as re-frame] + [status-im.models.browser :as model])) + +(defn test-fixtures [] + + (re-frame/reg-fx ::events/init-store #()) + + (re-frame/reg-fx :browse #()) + (re-frame/reg-fx :data-store/tx #()) + + (re-frame/reg-cofx + :data-store/all-browsers + (fn [coeffects _] + (assoc coeffects :all-stored-browsers [])))) + +(deftest browser-events + + (run-test-sync + + (test-fixtures) + + (re-frame/dispatch [:initialize-db]) + (re-frame/dispatch [:initialize-browsers]) + + (let [browsers (re-frame/subscribe [:browsers]) + dapp1-url "test.com" + dapp2-url "http://test2.com"] + + (testing "open and remove dapps" + + (is (zero? (count @browsers))) + + (re-frame/dispatch [:open-dapp-in-browser {:name "Test Dapp" + :dapp-url dapp1-url + :description "Test description"}]) + + (is (= 1 (count @browsers))) + + (re-frame/dispatch [:open-url-in-browser dapp2-url]) + + (is (= 2 (count @browsers))) + + (let [browser1 (first (vals @browsers)) + browser2 (second (vals @browsers))] + (is (and (:dapp? browser1) + (not (:dapp? browser2)))) + (is (and (zero? (:history-index browser1)) + (zero? (:history-index browser2)))) + (is (and (= [(str "http://" dapp1-url) (:history browser1)]) + (= [dapp2-url] (:history browser2))))) + + (re-frame/dispatch [:remove-browser "Test Dapp"]) + + (is (= 1 (count @browsers)))) + + (testing "navigate dapp" + + (re-frame/dispatch [:open-browser (first (vals @browsers))]) + + (let [browser (re-frame/subscribe [:get-current-browser]) + options (re-frame/subscribe [:get :browser/options]) + dapp2-url2 (str dapp2-url "/nav2") + dapp2-url3 (str dapp2-url "/nav3")] + + (is (zero? (:history-index @browser))) + (is (= [dapp2-url] (:history @browser))) + + (is (and (not (model/can-go-back? @browser)) + (not (model/can-go-forward? @browser)))) + + (re-frame/dispatch [:browser-nav-back]) + (re-frame/dispatch [:browser-nav-forward]) + + (re-frame/dispatch [:update-browser-on-nav-change @browser dapp2-url2 false]) + + (is (= 1 (:history-index @browser))) + (is (= [dapp2-url dapp2-url2] (:history @browser))) + + (is (and (model/can-go-back? @browser) + (not (model/can-go-forward? @browser)))) + + (re-frame/dispatch [:browser-nav-back @browser]) + + (is (zero? (:history-index @browser))) + (is (= [dapp2-url dapp2-url2] (:history @browser))) + + (is (and (not (model/can-go-back? @browser)) + (model/can-go-forward? @browser))) + + (re-frame/dispatch [:update-browser-on-nav-change @browser dapp2-url3 false]) + + (is (= 1 (:history-index @browser))) + (is (= [dapp2-url dapp2-url3] (:history @browser))) + + (re-frame/dispatch [:browser-nav-back @browser]) + + (is (zero? (:history-index @browser))) + (is (= [dapp2-url dapp2-url3] (:history @browser))) + + (re-frame/dispatch [:browser-nav-forward @browser]) + + (is (= 1 (:history-index @browser))) + (is (= [dapp2-url dapp2-url3] (:history @browser)))))))) \ No newline at end of file diff --git a/test/cljs/status_im/test/models/browser_history.cljs b/test/cljs/status_im/test/models/browser_history.cljs deleted file mode 100644 index 2df3e40a3a..0000000000 --- a/test/cljs/status_im/test/models/browser_history.cljs +++ /dev/null @@ -1,117 +0,0 @@ -(ns status-im.test.models.browser-history - (:require [cljs.test :refer-macros [deftest is testing]] - [status-im.models.browser-history :as model] - [re-frame.core :as re-frame])) - -(def test-history ["http://oldest-site-visited.com", "http://most-recent-site-visited.com"]) -(def test-browser-id "1234567890") - -(deftest dont-store-history-on-nav-change?-test - (testing "dont-store-history-on-nav-change?" - (let [db {:browser/options {:dont-store-history-on-nav-change? true}}] - (is (model/dont-store-history-on-nav-change? db))))) - -(defn fake-dispatch-dont-store-history-on-nav-change! [event] - (is (= :update-browser-options (get event 0))) - (let [eventMap (get event 1)] - (is (= (:dont-store-history-on-nav-change? eventMap) true)))) - -(deftest dont-store-history-on-nav-change!-test - (testing "dont-store-history-on-nav-change!" - (with-redefs [re-frame/dispatch fake-dispatch-dont-store-history-on-nav-change!] - (model/dont-store-history-on-nav-change!)))) - -(defn fake-dispatch-clear-dont-store-history-on-nav-change! [event] - (is (= :update-browser-options (get event 0))) - (let [eventMap (get event 1)] - (is (= (:dont-store-history-on-nav-change? eventMap) false)))) - -(deftest clear-dont-store-history-on-nav-change-test - (testing "clear-dont-store-history-on-nav-change!" - (with-redefs [re-frame/dispatch fake-dispatch-clear-dont-store-history-on-nav-change!] - (model/clear-dont-store-history-on-nav-change!)))) - -(deftest dont-store-history-on-nav-change-if-history-exists-test - (testing "dont-store-history-on-nav-change-if-history-exists" - (let [browser {:browser-id test-browser-id :history test-history} - db {:browser/browsers {test-browser-id browser}} - browser-no-history {:browser-id test-browser-id} - db-no-history {:browser/browsers {test-browser-id browser-no-history}} - result (model/dont-store-history-on-nav-change-if-history-exists db test-browser-id) - result-no-history (model/dont-store-history-on-nav-change-if-history-exists db-no-history test-browser-id)] - (is (get result :dont-store-history-on-nav-change?)) - (is (not (get result-no-history :dont-store-history-on-nav-change?)))))) - -(defn dispatch-on-back-forwards [event expected-index] - (let [eventType (get event 0) - eventMap (get event 1)] - (if (= :update-browser eventType) - (do (is (= (:history-index eventMap) expected-index)) - (is (= (:url eventMap) (get test-history expected-index)))) - (do (is (= eventType :update-browser-options)) - (is (= (:dont-store-history-on-nav-change? eventMap) true)))))) - -(defn dispatch-on-back [event] - (dispatch-on-back-forwards event 0)) - -(deftest back-test - (testing "back" - (let [browser {:browser-id test-browser-id :history-index 1 :history test-history}] - (with-redefs [re-frame/dispatch dispatch-on-back] - (model/back browser))))) - -(defn dispatch-on-forward [event] - (dispatch-on-back-forwards event 1)) - -(deftest forward-test - (testing "forward" - (let [browser {:browser-id test-browser-id :history-index 0 :history test-history}] - (with-redefs [re-frame/dispatch dispatch-on-forward] - (model/forward browser))))) - -(deftest can-go-back?-test - (testing "can-go-back?" - (let [browser {:history-index 0 :history test-history}] - (is (= (model/can-go-back? browser) false))) - (let [browser {:history-index 1 :history test-history}] - (is (= (model/can-go-back? browser) true))))) - -(deftest can-go-forward?-test - (testing "can-go-forward?" - (let [browser {:history-index 0 :history test-history}] - (is (= (model/can-go-forward? browser) true))) - (let [browser {:history-index 1 :history test-history}] - (is (= (model/can-go-forward? browser) false))))) - -(deftest record-history-in-browser-if-needed-test-1 - (testing "record-history-in-browser-if-needed: dont record when still loading" - (let [raw-browser {:history-index 1 :history test-history} - url "http://third-site.com" - db {:browser/browsers {test-browser-id raw-browser}}] - (let [browser (model/record-history-in-browser-if-needed db raw-browser url true)] - (is (= (:history-index browser) 1)) - (is (= (count (:history browser)) 2)))))) - -(defn record-history-in-browser-if-needed-test-2-dispatch [event] - (is (= :update-browser-options (get event 0))) - (let [eventMap (get event 1)] - (is (= (:dont-store-history-on-nav-change? eventMap) false)))) - -(deftest record-history-in-browser-if-needed-test-2 - (testing "record-history-in-browser-if-needed: dont record if :dont-store-history-on-nav-change? true" - (let [raw-browser {:history-index 1 :history test-history} - url "http://third-site.com" - db {:browser/browsers {test-browser-id raw-browser} :browser/options {:dont-store-history-on-nav-change? true}}] - (with-redefs [re-frame/dispatch record-history-in-browser-if-needed-test-2-dispatch] - (let [browser (model/record-history-in-browser-if-needed db raw-browser url false)] - (is (= (:history-index browser) 1)) - (is (= (count (:history browser)) 2))))))) - -(deftest record-history-in-browser-if-needed-test-3 - (testing "record-history-in-browser-if-needed: record if not loading and allowed" - (let [raw-browser {:history-index 1 :history test-history} - url "http://third-site.com" - db {:browser/browsers {test-browser-id raw-browser} :browser/options {:dont-store-history-on-nav-change? false}}] - (let [browser (model/record-history-in-browser-if-needed db raw-browser url false)] - (is (= (:history-index browser) 2)) - (is (= (count (:history browser)) 3)))))) diff --git a/test/cljs/status_im/test/runner.cljs b/test/cljs/status_im/test/runner.cljs index 9d83d3930f..81c3919cc6 100644 --- a/test/cljs/status_im/test/runner.cljs +++ b/test/cljs/status_im/test/runner.cljs @@ -5,6 +5,7 @@ [status-im.test.contacts.subs] [status-im.test.accounts.events] [status-im.test.data-store.realm.core] + [status-im.test.browser.events] [status-im.test.wallet.subs] [status-im.test.wallet.transactions.subs] [status-im.test.wallet.transactions.views] @@ -12,7 +13,6 @@ [status-im.test.bots.events] [status-im.test.models.mailserver] [status-im.test.models.bootnode] - [status-im.test.models.browser-history] [status-im.test.models.account] [status-im.test.models.contact] [status-im.test.models.network] @@ -70,7 +70,6 @@ 'status-im.test.models.mailserver 'status-im.test.models.bootnode 'status-im.test.models.account - 'status-im.test.models.browser-history 'status-im.test.models.contact 'status-im.test.models.network 'status-im.test.models.wallet @@ -105,4 +104,5 @@ 'status-im.test.utils.universal-links.core 'status-im.test.utils.http 'status-im.test.ui.screens.events - 'status-im.test.ui.screens.accounts.login.events) + 'status-im.test.ui.screens.accounts.login.events + 'status-im.test.browser.events) \ No newline at end of file