Fixes #3639 Persist browser history
Signed-off-by: Andrey Shovkoplyas <motor4ik@gmail.com>
This commit is contained in:
parent
ff4071b7b5
commit
5e3f65eac8
|
@ -0,0 +1,17 @@
|
|||
(ns status-im.data-store.realm.schemas.account.v8.browser)
|
||||
|
||||
(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}}})
|
|
@ -0,0 +1,56 @@
|
|||
(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)))))
|
|
@ -10,17 +10,17 @@
|
|||
(spec/def :browser/name (spec/nilable string?))
|
||||
(spec/def :browser/dapp? (spec/nilable boolean?))
|
||||
(spec/def :browser/fullscreen? (spec/nilable boolean?))
|
||||
(spec/def :browser/can-go-back? (spec/nilable boolean?))
|
||||
(spec/def :browser/can-go-forward? (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/can-go-back?
|
||||
:browser/can-go-forward?
|
||||
:browser/fullscreen?
|
||||
:browser/error?]))
|
||||
:browser/error?
|
||||
:browser/dont-store-history-on-nav-change?]))
|
||||
|
||||
(spec/def :browser/browser
|
||||
(allowed-keys
|
||||
|
@ -29,6 +29,8 @@
|
|||
:opt-un [:browser/name
|
||||
:browser/dapp?
|
||||
:browser/url
|
||||
:browser/contact]))
|
||||
:browser/contact
|
||||
:browser/history
|
||||
:browser/history-index]))
|
||||
|
||||
(spec/def :browser/browsers (spec/nilable (spec/map-of :global/not-empty-string :browser/browser)))
|
||||
(spec/def :browser/browsers (spec/nilable (spec/map-of :global/not-empty-string :browser/browser)))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
(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]
|
||||
|
@ -73,6 +74,15 @@
|
|||
(-> (add-browser-fx cofx new-browser)
|
||||
(update-in [:db :browser/options] #(assoc % :browser-id (:browser-id new-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))))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:update-browser-options
|
||||
[re-frame/trim-v]
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
(ns status-im.ui.screens.browser.navigation
|
||||
(:require [status-im.ui.screens.navigation :as navigation]))
|
||||
(:require [status-im.ui.screens.navigation :as navigation]
|
||||
[status-im.models.browser-history :as browser-history]))
|
||||
|
||||
(defmethod navigation/preload-data! :browser
|
||||
[db [_ _ {:keys [browser/browser-id]}]]
|
||||
(assoc db :browser/options {:browser-id 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))))
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
:align-items :center
|
||||
:padding-horizontal 32})
|
||||
|
||||
(def disabled-button
|
||||
{:opacity 0.4})
|
||||
|
||||
(def forward-button
|
||||
{:margin-left 72})
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
[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]
|
||||
|
@ -64,10 +65,9 @@
|
|||
[components/activity-indicator {:animating true}]]))
|
||||
|
||||
(defn on-navigation-change [event browser]
|
||||
(let [{:strs [url canGoBack canGoForward]} (js->clj event)]
|
||||
(when (and (not (:dapp? browser)) (not= "about:blank" url))
|
||||
(re-frame/dispatch [:update-browser (assoc browser :url url)]))
|
||||
(re-frame/dispatch [:update-browser-options {:can-go-back? canGoBack :can-go-forward? canGoForward}])))
|
||||
(let [{:strs [url loading]} (js->clj event)]
|
||||
(when (not= "about:blank" url)
|
||||
(re-frame/dispatch [:update-browser-on-nav-change browser url loading]))))
|
||||
|
||||
(defn get-inject-js [url]
|
||||
(let [domain-name (nth (re-find #"^\w+://(www\.)?([^/:]+)" url) 2)]
|
||||
|
@ -115,16 +115,17 @@
|
|||
[react/view styles/background
|
||||
[react/text (i18n/label :t/enter-dapp-url)]])
|
||||
[react/view styles/toolbar
|
||||
[react/touchable-highlight {:on-press #(.goBack @webview)
|
||||
:disabled (not can-go-back?)
|
||||
[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 (when (not can-go-back?) {:opacity 0.4})
|
||||
[react/view
|
||||
[vector-icons/icon :icons/arrow-left]]]
|
||||
[react/touchable-highlight {:on-press #(.goForward @webview)
|
||||
:disabled (not can-go-forward?)
|
||||
:style styles/forward-button
|
||||
[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 (when (not can-go-forward?) {:opacity 0.4})
|
||||
[react/view
|
||||
[vector-icons/icon :icons/arrow-right]]]]
|
||||
(when-not dapp?
|
||||
[tooltip/bottom-tooltip-info
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
(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))))))
|
|
@ -12,6 +12,7 @@
|
|||
[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]
|
||||
|
@ -68,6 +69,7 @@
|
|||
'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
|
||||
|
|
Loading…
Reference in New Issue