From ea8bf402d7f6dad9e227823b21ddc4179c2b5f4e Mon Sep 17 00:00:00 2001 From: Volodymyr Kozieiev Date: Fri, 5 Jul 2019 12:05:36 +0300 Subject: [PATCH] Two pane ui on large screens Signed-off-by: Volodymyr Kozieiev --- clj-rn.conf.edn | 2 + desktop_files/package.json.orig | 1 + desktop_files/yarn.lock | 4 + mobile_files/package.json.orig | 1 + mobile_files/yarn.lock | 4 + .../react_native/js_dependencies.cljs | 1 + .../react_native/js_dependencies.cljs | 1 + src/status_im/constants.cljs | 2 + src/status_im/events.cljs | 12 +++ src/status_im/subs.cljs | 1 + .../ui/components/connectivity/view.cljs | 9 +- .../screens/add_new/new_public_chat/view.cljs | 11 +-- .../ui/screens/chat/stickers/views.cljs | 10 ++- src/status_im/ui/screens/chat/views.cljs | 11 ++- src/status_im/ui/screens/db.cljs | 7 +- src/status_im/ui/screens/events.cljs | 11 ++- src/status_im/ui/screens/home/views.cljs | 89 ++++++++++--------- .../ui/screens/home/views/inner_item.cljs | 4 +- .../ui/screens/routing/chat_stack.cljs | 4 +- src/status_im/ui/screens/routing/core.cljs | 85 +++++++++++------- src/status_im/ui/screens/routing/screens.cljs | 1 + src/status_im/ui/screens/views.cljs | 58 ++++++++---- src/status_im/utils/dimensions.cljs | 12 ++- src/status_im/utils/navigation.cljs | 8 +- .../react_native/js_dependencies.cljs | 1 + translations/en.json | 1 + 26 files changed, 232 insertions(+), 119 deletions(-) diff --git a/clj-rn.conf.edn b/clj-rn.conf.edn index ecb18e57ab..a80905e079 100644 --- a/clj-rn.conf.edn +++ b/clj-rn.conf.edn @@ -45,6 +45,7 @@ "text-encoding" "js-sha3" "react-navigation" + "react-native-navigation-twopane" "hi-base32" "react-native-mail" "react-native-shake"] @@ -87,6 +88,7 @@ "js-sha3" "web3-utils" "react-navigation" + "react-native-navigation-twopane" "hi-base32"] ;; Resoures diff --git a/desktop_files/package.json.orig b/desktop_files/package.json.orig index c4c4a21bf0..4409b374e8 100644 --- a/desktop_files/package.json.orig +++ b/desktop_files/package.json.orig @@ -91,6 +91,7 @@ "react-native-tcp": "3.3.0", "react-native-udp": "2.2.1", "react-native-webview-bridge": "git+https://github.com/status-im/react-native-webview-bridge.git#0.33.16-status-rn049-desktop", + "react-native-navigation-twopane": "git+https://github.com/status-im/react-native-navigation-twopane.git#v0.0.2-status", "react-navigation": "^2.12.1", "realm": "git+https://github.com/status-im/realm-js.git#v2.20.1", "rn-snoopy": "git+https://github.com/status-im/rn-snoopy.git#v2.0.2-status", diff --git a/desktop_files/yarn.lock b/desktop_files/yarn.lock index 6a762ef926..8a9ed57cf3 100644 --- a/desktop_files/yarn.lock +++ b/desktop_files/yarn.lock @@ -7146,6 +7146,10 @@ react-native-invertible-scroll-view@1.1.0: version "3.0.2" resolved "git+https://github.com/status-im/react-native-languages.git#60338ff3040b8af68d33233aebeb36db4d31aed0" +"react-native-navigation-twopane@git+https://github.com/status-im/react-native-navigation-twopane.git#v0.0.2-status": + version "0.0.2" + resolved "git+https://github.com/status-im/react-native-navigation-twopane.git#04ed5fddfb46a6a3ee30776987acb4d3b11c27d4" + react-native-os@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/react-native-os/-/react-native-os-1.1.0.tgz#bfbe1c44d8a5b14a6f3a3a405d8ada6f547a516e" diff --git a/mobile_files/package.json.orig b/mobile_files/package.json.orig index 4c62c2cfe6..18c1745867 100644 --- a/mobile_files/package.json.orig +++ b/mobile_files/package.json.orig @@ -66,6 +66,7 @@ "react-native-udp": "git+https://github.com/status-im/react-native-udp.git#v2.3.1-1-status", "react-native-webview": "^5.2.1", "react-native-webview-bridge": "git+https://github.com/status-im/react-native-webview-bridge.git#fix/classnames-colision", + "react-native-navigation-twopane": "git+https://github.com/status-im/react-native-navigation-twopane.git#v0.0.2-status", "react-navigation": "^3.11.0", "realm": "2.28.1", "rn-snoopy": "git+https://github.com/status-im/rn-snoopy.git#v2.0.2-status", diff --git a/mobile_files/yarn.lock b/mobile_files/yarn.lock index 4d0e6209ef..045047ea5e 100644 --- a/mobile_files/yarn.lock +++ b/mobile_files/yarn.lock @@ -5619,6 +5619,10 @@ react-native-languages@^3.0.2: version "3.0.7" resolved "git+https://github.com/status-im/react-native-mail.git#5dd2d4e92fa696a9dd0efebdc530df22772326fe" +"react-native-navigation-twopane@git+https://github.com/status-im/react-native-navigation-twopane.git#v0.0.2-status": + version "0.0.2" + resolved "git+https://github.com/status-im/react-native-navigation-twopane.git#04ed5fddfb46a6a3ee30776987acb4d3b11c27d4" + "react-native-os@git+https://github.com/status-im/react-native-os.git#v1.1.0-1-status": version "1.1.0" resolved "git+https://github.com/status-im/react-native-os.git#1a6d0835f919cb075793ad7c602f2724eee4702d" diff --git a/react-native/src/desktop/status_im/react_native/js_dependencies.cljs b/react-native/src/desktop/status_im/react_native/js_dependencies.cljs index 79d1708fd4..94165795a2 100644 --- a/react-native/src/desktop/status_im/react_native/js_dependencies.cljs +++ b/react-native/src/desktop/status_im/react_native/js_dependencies.cljs @@ -36,5 +36,6 @@ (def snoopy-buffer (fn [] #js {})) (def background-timer (fn [] #js {:setTimeout (fn [cb ms] (js/setTimeout cb ms))})) (def react-navigation (js/require "react-navigation")) +(def react-native-navigation-twopane (js/require "react-native-navigation-twopane")) (def react-native-shake (fn [] #js {})) (def react-native-mail (fn [] #js {:mail (fn [])})) diff --git a/react-native/src/mobile/status_im/react_native/js_dependencies.cljs b/react-native/src/mobile/status_im/react_native/js_dependencies.cljs index e1c4b21c32..8f56fc3195 100644 --- a/react-native/src/mobile/status_im/react_native/js_dependencies.cljs +++ b/react-native/src/mobile/status_im/react_native/js_dependencies.cljs @@ -34,6 +34,7 @@ (def background-timer-class (js-require/js-require "react-native-background-timer")) (defn background-timer [] (.-default (background-timer-class))) (def react-navigation (js/require "react-navigation")) +(def react-native-navigation-twopane (js/require "react-native-navigation-twopane")) (def react-native-shake (js-require/js-require "react-native-shake")) (def react-native-screens (js-require/js-require "react-native-screens")) (def mail-class (js-require/js-require "react-native-mail")) diff --git a/src/status_im/constants.cljs b/src/status_im/constants.cljs index 141ab36bbe..67f9dd48df 100644 --- a/src/status_im/constants.cljs +++ b/src/status_im/constants.cljs @@ -24,6 +24,8 @@ (def default-number-of-messages 20) (def blocks-per-hour 120) (def one-earth-day 86400) +(def two-pane-min-width 640) +(def left-pane-min-width 320) (def mailserver-password "status-offline-inbox") diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index c121caa596..9365693a39 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -804,6 +804,18 @@ current-param-position value)))) +(defn- mark-messages-seen + [{:keys [db] :as cofx}] + (let [{:keys [current-chat-id]} db] + (chat/mark-messages-seen cofx current-chat-id))) + +(handlers/register-handler-fx + :chat.ui/mark-messages-seen + (fn [{:keys [db] :as cofx} [_ view-id]] + (fx/merge cofx + {:db (assoc db :view-id view-id)} + #(mark-messages-seen %)))) + (handlers/register-handler-fx :chat/send-plain-text-message (fn [{{:keys [current-chat-id]} :db :as cofx} [_ message-text]] diff --git a/src/status_im/subs.cljs b/src/status_im/subs.cljs index 0db629a457..68e94d196c 100644 --- a/src/status_im/subs.cljs +++ b/src/status_im/subs.cljs @@ -59,6 +59,7 @@ (reg-root-key-sub :view-id :view-id) (reg-root-key-sub :navigation-stack :navigation-stack) (reg-root-key-sub :screen-params :navigation/screen-params) +(reg-root-key-sub :two-pane-ui-enabled? :two-pane-ui-enabled?) ;;bottom sheet (reg-root-key-sub :bottom-sheet/show? :bottom-sheet/show?) diff --git a/src/status_im/ui/components/connectivity/view.cljs b/src/status_im/ui/components/connectivity/view.cljs index 87f85ffb96..64a7a48c4b 100644 --- a/src/status_im/ui/components/connectivity/view.cljs +++ b/src/status_im/ui/components/connectivity/view.cljs @@ -150,13 +150,14 @@ (defview connectivity-view [anim-translate-y] (letsubs [status-properties [:connectivity/status-properties] view-id [:view-id] - window-width [:dimensions/window-width]] + window-width (reagent/atom 0)] (let [{:keys [loading-indicator?]} status-properties] - [react/view {:style {:align-self :flex-start}} + [react/view {:style {:align-items :stretch} + :on-layout #(reset! window-width (-> % .-nativeEvent .-layout .-width))} (when loading-indicator? - [loading-indicator window-width]) + [loading-indicator @window-width]) [connectivity-status (merge status-properties {:view-id view-id - :window-width window-width}) + :window-width @window-width}) anim-translate-y]]))) diff --git a/src/status_im/ui/screens/add_new/new_public_chat/view.cljs b/src/status_im/ui/screens/add_new/new_public_chat/view.cljs index d4805ea246..7046d04a5c 100644 --- a/src/status_im/ui/screens/add_new/new_public_chat/view.cljs +++ b/src/status_im/ui/screens/add_new/new_public_chat/view.cljs @@ -18,6 +18,10 @@ [status-im.utils.slurp :refer [slurp]] [status-im.utils.views :as views])) +(defn- start-chat [topic] + (re-frame/dispatch [:chat.ui/start-public-chat topic {:navigation-reset? true}]) + (re-frame/dispatch [:set :public-group-topic nil])) + (defn- chat-name-input [topic error] [react/view [react/view (merge add-new.styles/input-container {:margin-top 8}) @@ -26,8 +30,7 @@ [text-input.view/text-input-with-label {:container styles/input-container :on-change-text #(re-frame/dispatch [:set :public-group-topic %]) - :on-submit-editing #(when (db/valid-topic? topic) - (re-frame/dispatch [:chat.ui/start-public-chat topic {:navigation-reset? true}])) + :on-submit-editing #(when (db/valid-topic? topic) (start-chat topic)) :auto-capitalize :none :auto-focus false :accessibility-label :chat-name-input @@ -43,9 +46,7 @@ (first topic)]]) (defn- render-topic [topic] - [react/touchable-highlight {:on-press #(re-frame/dispatch [:chat.ui/start-public-chat - topic - {:navigation-reset? true}]) + [react/touchable-highlight {:on-press #(start-chat topic) :accessibility-label :chat-item} [react/view [list/item diff --git a/src/status_im/ui/screens/chat/stickers/views.cljs b/src/status_im/ui/screens/chat/stickers/views.cljs index 9f24e4f758..a795363a72 100644 --- a/src/status_im/ui/screens/chat/stickers/views.cljs +++ b/src/status_im/ui/screens/chat/stickers/views.cljs @@ -78,7 +78,8 @@ (defview stickers-paging-panel [installed-packs selected-pack] (letsubs [ref (atom nil) - window-width [:dimensions/window-width]] + window-width [:dimensions/window-width] + content-width (reagent/atom 0)] {:component-will-update (fn [_ [_ installed-packs selected-pack]] (update-scroll-position @ref installed-packs selected-pack window-width)) :component-did-mount #(update-scroll-position @ref installed-packs selected-pack window-width)} @@ -87,12 +88,13 @@ :shows-horizontal-scroll-indicator false :on-momentum-scroll-end #(on-scroll % installed-packs window-width) :scrollEventThrottle 8 - :on-scroll #(reset! scroll-x (.-nativeEvent.contentOffset.x %))} + :on-scroll #(reset! scroll-x (.-nativeEvent.contentOffset.x %)) + :on-layout #(reset! content-width (-> % .-nativeEvent .-layout .-width))} ^{:key "recent"} - [recent-stickers-panel window-width] + [recent-stickers-panel @content-width] (for [{:keys [stickers id]} installed-packs] ^{:key (str "sticker" id)} - [stickers-panel (map #(assoc % :pack id) stickers) window-width])])) + [stickers-panel (map #(assoc % :pack id) stickers) @content-width])])) (defn pack-icon [{:keys [id on-press background-color] :or {on-press #(re-frame/dispatch [:stickers/select-pack id])}} diff --git a/src/status_im/ui/screens/chat/views.cljs b/src/status_im/ui/screens/chat/views.cljs index 930a76ec84..d33f2c49e5 100644 --- a/src/status_im/ui/screens/chat/views.cljs +++ b/src/status_im/ui/screens/chat/views.cljs @@ -432,7 +432,8 @@ current-chat-id [:chats/current-chat-id] show-message-options? [:chats/current-chat-ui-prop :show-message-options?] show-stickers? [:chats/current-chat-ui-prop :show-stickers?] - anim-translate-y (animation/create-value -35)] + two-pane-ui-enabled? [:two-pane-ui-enabled?] + anim-translate-y (animation/create-value (if two-pane-ui-enabled? 0 -35))] ;; this check of current-chat-id is necessary only because in a fresh public chat creation sometimes ;; this component renders before current-chat-id is set to current chat-id. Hence further down in sub ;; components (e.g. chat-toolbar) there can be a brief visual inconsistancy like showing 'add contact' @@ -443,7 +444,8 @@ (re-frame/dispatch [:set :layout-height (-> e .-nativeEvent .-layout .-height)]))} ^{:key current-chat-id} [chat-toolbar current-chat public? modal?] - [connectivity/connectivity-view anim-translate-y] + (when-not two-pane-ui-enabled? + [connectivity/connectivity-view anim-translate-y]) [connectivity/connectivity-animation-wrapper {} anim-translate-y @@ -464,3 +466,8 @@ (defview chat-modal [] [chat-root true]) + +(defview select-chat [] + [react/view {:style {:align-items :center :justify-content :center :flex 1}} + [react/text {:style style/decline-chat} + (i18n/label :t/select-chat)]]) diff --git a/src/status_im/ui/screens/db.cljs b/src/status_im/ui/screens/db.cljs index ed6e5a85fb..6586faf535 100644 --- a/src/status_im/ui/screens/db.cljs +++ b/src/status_im/ui/screens/db.cljs @@ -68,7 +68,8 @@ :current [] :puk [] :enter-step :original}} - :chats/loading? true}) + :chats/loading? true + :two-pane-ui-enabled? (dimensions/fit-two-pane?)}) ;;;;GLOBAL @@ -151,6 +152,7 @@ (spec/def :desktop/desktop (spec/nilable any?)) (spec/def ::tooltips (spec/nilable any?)) (spec/def ::initial-props (spec/nilable any?)) +(spec/def ::two-pane-ui-enabled? (spec/nilable boolean?)) ;;;;NETWORK @@ -352,4 +354,5 @@ ::collectible ::collectibles ::extensions-store - :registry/registry])) + :registry/registry + ::two-pane-ui-enabled?])) diff --git a/src/status_im/ui/screens/events.cljs b/src/status_im/ui/screens/events.cljs index 573369c9a3..a8475ae76b 100644 --- a/src/status_im/ui/screens/events.cljs +++ b/src/status_im/ui/screens/events.cljs @@ -65,11 +65,6 @@ :http-post http-post) -(defn- mark-messages-seen - [{:keys [db] :as cofx}] - (let [{:keys [current-chat-id]} db] - (chat/mark-messages-seen cofx current-chat-id))) - (defn- http-raw-post [{:keys [url body response-validator success-event-creator failure-event-creator timeout-ms opts]}] (let [on-success #(re-frame/dispatch (success-event-creator %)) on-error (when failure-event-creator #(re-frame/dispatch (failure-event-creator %))) @@ -204,6 +199,11 @@ (fn [{:keys [db]} [_ dimensions]] {:db (assoc db :dimensions/window (dimensions/window dimensions))})) +(handlers/register-handler-fx + :set-two-pane-ui-enabled + (fn [{:keys [db]} [_ enabled?]] + {:db (assoc db :two-pane-ui-enabled? enabled?)})) + (handlers/register-handler-fx :screens/on-will-focus (fn [{:keys [db] :as cofx} [_ view-id]] @@ -222,5 +222,4 @@ :hardwallet-connect-modal (hardwallet/hardwallet-connect-screen-did-load %) :hardwallet-authentication-method (hardwallet/authentication-method-screen-did-load %) :accounts (hardwallet/accounts-screen-did-load %) - :chat (mark-messages-seen %) nil)))) diff --git a/src/status_im/ui/screens/home/views.cljs b/src/status_im/ui/screens/home/views.cljs index 8f915842c9..cbe728a87c 100644 --- a/src/status_im/ui/screens/home/views.cljs +++ b/src/status_im/ui/screens/home/views.cljs @@ -16,7 +16,9 @@ [status-im.ui.screens.home.views.inner-item :as inner-item] [status-im.ui.components.common.common :as components.common] [status-im.ui.components.list-selection :as list-selection] - [status-im.ui.components.animation :as animation]) + [status-im.ui.components.animation :as animation] + [status-im.constants :as constants] + [status-im.ui.components.colors :as colors]) (:require-macros [status-im.utils.views :as views])) (views/defview les-debug-info [] @@ -121,49 +123,54 @@ (views/defview home [loading?] (views/letsubs [anim-translate-y (animation/create-value -35) - {:keys [search-filter chats all-home-items]} [:home-items]] + {:keys [search-filter chats all-home-items]} [:home-items] + window-width [:dimensions/window-width] + two-pane-ui-enabled? [:two-pane-ui-enabled?]] {:component-did-mount (fn [this] (let [[_ loading?] (.. this -props -argv)] (when loading? (utils/set-timeout #(re-frame/dispatch [:init-rest-of-chats]) 100))))} - [react/view {:flex 1} - [status-bar/status-bar {:type :main}] - [react/keyboard-avoiding-view {:style {:flex 1 - :align-items :center} - :on-layout (fn [e] - (re-frame/dispatch - [:set-once :content-layout-height - (-> e .-nativeEvent .-layout .-height)]))} - [react/view {:style {:flex 1 - :align-self :stretch}} - [toolbar/toolbar nil nil [toolbar/content-title (i18n/label :t/chat)]] - [les-debug-info] - (cond loading? - [react/view {:style {:flex 1 - :justify-content :center - :align-items :center}} - [connectivity/connectivity-view anim-translate-y] - [connectivity/connectivity-animation-wrapper - {} - anim-translate-y - [react/activity-indicator {:flex 1 - :animating true}]]] - - :else - [react/view {:style {:flex 1}} - [connectivity/connectivity-view anim-translate-y] - [connectivity/connectivity-animation-wrapper - {} - anim-translate-y - [filter.views/search-input-wrapper search-filter] - (if (and (not search-filter) - (empty? all-home-items)) - [home-empty-view] - [home-items-view - search-filter - chats - all-home-items - filter.views/search-input-state])]])] - [home-action-button]]])) + (let [home-width (if (> window-width constants/two-pane-min-width) + (max constants/left-pane-min-width (/ window-width 3)) + window-width)] + [react/view (merge {:flex 1 :width home-width} + (when two-pane-ui-enabled? + {:border-right-width 1 :border-right-color colors/gray-light})) + [status-bar/status-bar {:type :main}] + [react/keyboard-avoiding-view {:style {:flex 1 + :align-items :center} + :on-layout (fn [e] + (re-frame/dispatch + [:set-once :content-layout-height + (-> e .-nativeEvent .-layout .-height)]))} + [react/view {:style {:flex 1 + :align-self :stretch}} + [toolbar/toolbar nil nil [toolbar/content-title (i18n/label :t/chat)]] + [les-debug-info] + (cond loading? + [react/view {:style {:flex 1 + :justify-content :center + :align-items :center}} + [connectivity/connectivity-view anim-translate-y] + [connectivity/connectivity-animation-wrapper + {} + anim-translate-y + [react/activity-indicator {:flex 1 + :animating true}]]] :else + [react/view {:style {:flex 1}} + [connectivity/connectivity-view anim-translate-y] + [connectivity/connectivity-animation-wrapper + {} + anim-translate-y + [filter.views/search-input-wrapper search-filter] + (if (and (not search-filter) + (empty? all-home-items)) + [home-empty-view] + [home-items-view + search-filter + chats + all-home-items + filter.views/search-input-state])]])] + [home-action-button]]]))) (views/defview home-wrapper [] (views/letsubs [loading? [:chats/loading?]] 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 44c760ebb2..7ad716702a 100644 --- a/src/status_im/ui/screens/home/views/inner_item.cljs +++ b/src/status_im/ui/screens/home/views/inner_item.cljs @@ -98,7 +98,9 @@ (and group-chat public?) :public-chat-actions (and group-chat (not public?)) :group-chat-actions :else :private-chat-actions)] - [react/touchable-highlight {:on-press #(re-frame/dispatch [:chat.ui/navigate-to-chat chat-id]) + [react/touchable-highlight {:on-press #(do + (re-frame/dispatch [:chat.ui/navigate-to-chat chat-id]) + (re-frame/dispatch [:chat.ui/mark-messages-seen :chat])) :on-long-press #(re-frame/dispatch [:bottom-sheet/show-sheet chat-actions {:chat-id chat-id}])} [react/view styles/chat-container [react/view styles/chat-icon-container diff --git a/src/status_im/ui/screens/routing/chat_stack.cljs b/src/status_im/ui/screens/routing/chat_stack.cljs index 03f54dbff6..eabc39d78d 100644 --- a/src/status_im/ui/screens/routing/chat_stack.cljs +++ b/src/status_im/ui/screens/routing/chat_stack.cljs @@ -4,6 +4,7 @@ {:name :chat-stack :screens [:home :chat + :select-chat :profile :new :new-chat @@ -17,4 +18,5 @@ :new-public-chat :stickers :stickers-pack] - :config {:initialRouteName :home}}) + :config {:initialRouteName :home + :emptyRightPaneName :select-chat}}) diff --git a/src/status_im/ui/screens/routing/core.cljs b/src/status_im/ui/screens/routing/core.cljs index 91bcd18f1a..bcfeed7ef1 100644 --- a/src/status_im/ui/screens/routing/core.cljs +++ b/src/status_im/ui/screens/routing/core.cljs @@ -114,26 +114,45 @@ (defn stack-navigator [routes config] (nav-reagent/stack-navigator routes - (cond-> - (merge {:headerMode "none" - :cardStyle {:backgroundColor :white} - #_:transitionConfig - #_(fn [] - #js {:transitionSpec #js{:duration 10}}) - :onTransitionStart (fn [n] - (let [idx (.. n - -navigation - -state - -index) - routes (.. n - -navigation - -state - -routes)] - (when (and (array? routes) (int? idx)) - (let [route (aget routes idx) - route-name (keyword (.-routeName route))] - (bottom-bar/minimize-bar route-name)))))} - (prepare-config config))))) + (merge {:headerMode "none" + :cardStyle {:backgroundColor :white} + #_:transitionConfig + #_(fn [] + #js {:transitionSpec #js{:duration 10}}) + :onTransitionStart (fn [n] + (let [idx (.. n + -navigation + -state + -index) + routes (.. n + -navigation + -state + -routes)] + (when (and (array? routes) (int? idx)) + (let [route (aget routes idx) + route-name (keyword (.-routeName route))] + (bottom-bar/minimize-bar route-name)))))} + (prepare-config config)))) + +(defn twopane-navigator [routes config] + (navigation/twopane-navigator + routes + (merge {:headerMode "none" + :cardStyle {:backgroundColor :white} + :onTransitionStart (fn [n] + (let [idx (.. n + -navigation + -state + -index) + routes (.. n + -navigation + -state + -routes)] + (when (and (array? routes) (int? idx)) + (let [route (aget routes idx) + route-name (keyword (.-routeName route))] + (bottom-bar/minimize-bar route-name)))))} + (prepare-config config)))) (defn switch-navigator [routes config] (nav-reagent/switch-navigator @@ -147,7 +166,7 @@ (declare stack-screens) -(defn build-screen [screen] +(defn build-screen [navigator screen] "Builds screen from specified configuration. Currently screen can be - keyword, which points to some specific route - vector of [:modal :screen-key] type when screen should be wrapped as modal @@ -162,8 +181,8 @@ (let [res (cond (map? screen-config) (let [{:keys [screens config]} screen-config] - (stack-navigator - (stack-screens screens) + (navigator + (stack-screens navigator screens) config)) (vector? screen-config) @@ -178,9 +197,9 @@ (assoc :navigationOptions (:navigation screen-config)))]))) -(defn stack-screens [screens-map] +(defn stack-screens [navigator screens-map] (->> screens-map - (map build-screen) + (map (partial build-screen navigator)) (into {}))) (defn wrap-bottom-bar @@ -190,28 +209,28 @@ (defn app-container [navigator] (.createAppContainer js-dependencies/react-navigation navigator)) -(defn get-main-component [view-id] +(defn get-main-component [view-id two-pane?] (log/debug :component view-id) (app-container (switch-navigator (into {} - [(build-screen (intro-login-stack/login-stack view-id)) - (build-screen (intro-login-stack/intro-stack)) + [(build-screen stack-navigator (intro-login-stack/login-stack view-id)) + (build-screen stack-navigator (intro-login-stack/intro-stack)) [:tabs-and-modals {:screen (stack-navigator (merge {:tabs {:screen (tab-navigator - (->> [(build-screen chat-stack/chat-stack) - (build-screen browser-stack/browser-stack) - (build-screen wallet-stack/wallet-stack) - (build-screen profile-stack/profile-stack)] + (->> [(build-screen (if two-pane? twopane-navigator stack-navigator) chat-stack/chat-stack) + (build-screen stack-navigator browser-stack/browser-stack) + (build-screen stack-navigator wallet-stack/wallet-stack) + (build-screen stack-navigator profile-stack/profile-stack)] (into {})) {:initialRouteName :chat-stack :tabBarComponent (reagent.core/reactify-component wrap-bottom-bar)})}} - (stack-screens modals/modal-screens)) + (stack-screens stack-navigator modals/modal-screens)) {:mode :modal :initialRouteName :tabs :onTransitionStart (fn [])})}]]) diff --git a/src/status_im/ui/screens/routing/screens.cljs b/src/status_im/ui/screens/routing/screens.cljs index 4756aae94c..49e31b9bd6 100644 --- a/src/status_im/ui/screens/routing/screens.cljs +++ b/src/status_im/ui/screens/routing/screens.cljs @@ -97,6 +97,7 @@ :keycard-onboarding-recovery-phrase-confirm-word2 keycard.onboarding/recovery-phrase-confirm-word :home home/home-wrapper :chat chat/chat + :select-chat chat/select-chat :profile profile.contact/profile :new add-new/add-new :new-chat new-chat/new-chat diff --git a/src/status_im/ui/screens/views.cljs b/src/status_im/ui/screens/views.cljs index dfccaeed2b..173c13ac12 100644 --- a/src/status_im/ui/screens/views.cljs +++ b/src/status_im/ui/screens/views.cljs @@ -15,6 +15,7 @@ [status-im.ui.screens.home.sheet.views :as home.sheet] [status-im.ui.screens.routing.core :as routing] [status-im.ui.screens.signing.views :as signing] + [status-im.utils.dimensions :as dimensions] status-im.ui.screens.wallet.collectibles.etheremon.views status-im.ui.screens.wallet.collectibles.cryptostrikers.views status-im.ui.screens.wallet.collectibles.cryptokitties.views @@ -53,6 +54,25 @@ [bottom-sheet/bottom-sheet opts]))) +(defn reset-component-on-mount [view-id component two-pane?] + (when (and @initial-view-id + (or + js/goog.DEBUG + (not @component))) + (reset! component (routing/get-main-component + (if js/goog.DEBUG + @initial-view-id + @view-id) + two-pane?)))) + +(defn reset-component-on-update [view-id component two-pane?] + (when (and @initial-view-id (not @component)) + (reset! component (routing/get-main-component + (if js/goog.DEBUG + @initial-view-id + @view-id) + two-pane?)))) + (defonce state (atom nil)) (defn persist-state [state-obj] @@ -67,36 +87,40 @@ (resolve @state)))) (defn main [] - (let [view-id (re-frame/subscribe [:view-id]) - main-component (atom nil)] + (let [view-id (re-frame/subscribe [:view-id]) + main-component (atom nil) + main-component-two-pane (atom nil) + two-pane? (reagent/atom (dimensions/fit-two-pane?))] (reagent/create-class {:component-did-mount (fn [] + (re-frame/dispatch [:set-two-pane-ui-enabled @two-pane?]) (log/debug :main-component-did-mount @view-id) (utils.universal-links/initialize)) :component-will-mount (fn [] + (.addEventListener (react/dimensions) + "change" + (fn [dimensions] + (let [two-pane-enabled? (dimensions/fit-two-pane?)] + (do + (re-frame/dispatch [:set-two-pane-ui-enabled two-pane-enabled?]) + (log/debug ":set-two-pane " two-pane-enabled?) + (reset! two-pane? two-pane-enabled?))))) + (when-not @initial-view-id (reset! initial-view-id @view-id)) - (when (and @initial-view-id - (or - js/goog.DEBUG - (not @main-component))) - (reset! main-component (routing/get-main-component - (if js/goog.DEBUG - @initial-view-id - @view-id))))) + (reset-component-on-mount view-id main-component false) + (reset-component-on-mount view-id main-component-two-pane true)) :component-will-unmount utils.universal-links/finalize :component-will-update (fn [] (when-not @initial-view-id (reset! initial-view-id @view-id)) - (when (and @initial-view-id (not @main-component)) - (reset! main-component (routing/get-main-component - (if js/goog.DEBUG - @initial-view-id - @view-id)))) + + (reset-component-on-update view-id main-component false) + (reset-component-on-update view-id main-component-two-pane true) (when-not platform/desktop? (react/dismiss-keyboard!))) :component-did-update @@ -106,7 +130,7 @@ (fn [] (when (and @view-id main-component) [react/view {:flex 1} - [:> @main-component + [:> (if @two-pane? @main-component-two-pane @main-component) {:ref (fn [r] (navigation/set-navigator-ref r) (when (and @@ -114,7 +138,7 @@ (not js/goog.DEBUG) (not (contains? #{:intro :login :progress} @view-id))) (navigation/navigate-to @view-id nil))) - ;; see https://reactnavigation.org/docs/en/state-persistence.html#development-mode + ;; see https://reactnavigation.org/docs/en/state-persistence.html#development-mode :persistNavigationState (when js/goog.DEBUG persist-state) :loadNavigationState (when js/goog.DEBUG load-state)}] [signing/signing] diff --git a/src/status_im/utils/dimensions.cljs b/src/status_im/utils/dimensions.cljs index 32fde81084..a3d4d6b1d7 100644 --- a/src/status_im/utils/dimensions.cljs +++ b/src/status_im/utils/dimensions.cljs @@ -1,11 +1,15 @@ (ns status-im.utils.dimensions (:require [re-frame.core :as re-frame] - [status-im.ui.components.react :as react])) + [status-im.ui.components.react :as react] + [status-im.constants :as constants])) + +(declare window) (defn add-event-listener [] (.addEventListener (react/dimensions) "change" - #(re-frame/dispatch [:update-window-dimensions %]))) + #(do + (re-frame/dispatch [:update-window-dimensions %])))) (defn window ([] @@ -14,3 +18,7 @@ (-> m (js->clj :keywordize-keys true) :window))) + +(defn fit-two-pane? [] + (let [width (get (window) :width)] + (>= width constants/two-pane-min-width))) diff --git a/src/status_im/utils/navigation.cljs b/src/status_im/utils/navigation.cljs index 0a6285c647..fb9d4afb91 100644 --- a/src/status_im/utils/navigation.cljs +++ b/src/status_im/utils/navigation.cljs @@ -1,6 +1,7 @@ (ns status-im.utils.navigation (:require [status-im.react-native.js-dependencies :as js-dependencies] - [status-im.utils.platform :as platform])) + [status-im.utils.platform :as platform] + [goog.object :as gobj])) (def navigation-actions (.-NavigationActions js-dependencies/react-navigation)) @@ -46,3 +47,8 @@ (.dispatch @navigator-ref (.back navigation-actions)))) + +(defonce TwoPaneNavigator (gobj/get js-dependencies/react-native-navigation-twopane #js ["createTwoPaneNavigator"])) + +(defn twopane-navigator [routeConfigs stackNavigatorConfig] + (TwoPaneNavigator (clj->js routeConfigs) (clj->js stackNavigatorConfig))) diff --git a/test/cljs/status_im/react_native/js_dependencies.cljs b/test/cljs/status_im/react_native/js_dependencies.cljs index 99d5e57eec..d612d650ca 100644 --- a/test/cljs/status_im/react_native/js_dependencies.cljs +++ b/test/cljs/status_im/react_native/js_dependencies.cljs @@ -53,4 +53,5 @@ (def desktop-menu #js {}) (def desktop-config #js {}) (def react-native-mail (fn [] #js {:mail #js {}})) +(def react-native-navigation-twopane #js {}) diff --git a/translations/en.json b/translations/en.json index 19e0aecbbb..662521d3fd 100644 --- a/translations/en.json +++ b/translations/en.json @@ -1077,6 +1077,7 @@ "network-fee" : "Network fee", "sign-with-password" : "Sign with password", "signing-a-message" : "Signing a message", + "select-chat" : "Select chat to start messaging", "etherscan-lookup": "Look up on Etherscan", "retry": "Retry", "ens-deposit": "Deposit",