mirror of
https://github.com/status-im/status-react.git
synced 2025-02-17 13:28:04 +00:00
Fixed tabs component
This commit is contained in:
parent
aaa13b922b
commit
ad7c6b8542
@ -114,10 +114,11 @@
|
||||
creating? [:get :accounts/creating-account?]]
|
||||
[view
|
||||
[status-bar]
|
||||
[toolbar/toolbar2 {:hide-nav? (or (empty? accounts) show-actions? creating?)}
|
||||
toolbar/default-nav-back
|
||||
[toolbar-content-view]
|
||||
[toolbar-action]]
|
||||
(let [hide-nav? (or (empty? accounts) show-actions? creating?)]
|
||||
[toolbar/toolbar2 {}
|
||||
(when-not hide-nav? toolbar/default-nav-back)
|
||||
[toolbar-content-view]
|
||||
[toolbar-action]])
|
||||
[add-contact-bar]])
|
||||
|
||||
(defn get-intro-status-message [all-messages]
|
||||
|
@ -114,7 +114,7 @@
|
||||
"A wrapper for SectionList.
|
||||
See https://facebook.github.io/react-native/docs/sectionlist.html"
|
||||
[{:keys [sections render-fn empty-component render-section-header-fn] :or {render-section-header-fn default-render-section-header} :as props}]
|
||||
(if (and (empty? sections) empty-component)
|
||||
(if (and (every? #(empty? (:data %)) sections) empty-component)
|
||||
empty-component
|
||||
[section-list-class
|
||||
(merge (base-list-props render-fn empty-component)
|
||||
|
@ -46,6 +46,7 @@
|
||||
(def color-light-red2 "#f47979")
|
||||
(def color-green-1 "#a8f4d4")
|
||||
(def color-green-2 "#448469")
|
||||
(def color-cyan "#7adcfb")
|
||||
|
||||
(def color-separator "#D6D6D6")
|
||||
|
||||
|
@ -1,27 +1,33 @@
|
||||
(ns status-im.components.tabs.views
|
||||
(:require-macros [status-im.utils.views :refer [defview letsubs]])
|
||||
(:require [re-frame.core :refer [dispatch]]
|
||||
(:require-macros [status-im.utils.views :refer [defview]]
|
||||
[cljs.core.async.macros :as am])
|
||||
(:require [cljs.core.async :as async]
|
||||
[reagent.core :as r]
|
||||
[re-frame.core :refer [subscribe dispatch]]
|
||||
[status-im.components.react :as react]
|
||||
[status-im.components.icons.vector-icons :as vi]
|
||||
[status-im.components.tabs.styles :as styles]))
|
||||
[status-im.components.tabs.styles :as styles]
|
||||
[status-im.utils.platform :as p]))
|
||||
|
||||
(defn- tab [{:keys [view-id title icon-active icon-inactive selected-view-id]}]
|
||||
(defn- tab [{:keys [view-id title icon-active icon-inactive selected-view-id on-press]}]
|
||||
(let [active? (= view-id selected-view-id)]
|
||||
[react/touchable-highlight {:style styles/tab
|
||||
:disabled active?
|
||||
:on-press #(dispatch [:navigate-to-tab view-id])}
|
||||
:on-press #(if on-press (on-press view-id) (dispatch [:navigate-to-tab view-id]))}
|
||||
[react/view {:style styles/tab-container}
|
||||
(when-let [icon (if active? icon-active icon-inactive)]
|
||||
[react/view
|
||||
[vi/icon icon (styles/tab-icon active?)]])
|
||||
[react/view
|
||||
[react/text {:style (styles/tab-title active?)}
|
||||
[react/text (merge (if-not icon-active {:uppercase? (get-in p/platform-specific [:uppercase?])})
|
||||
{:style (styles/tab-title active?)})
|
||||
title]]]]))
|
||||
|
||||
(defn- create-tab [index data selected-view-id]
|
||||
(defn- create-tab [index data selected-view-id on-press]
|
||||
(let [data (merge data {:key index
|
||||
:index index
|
||||
:selected-view-id selected-view-id})]
|
||||
:selected-view-id selected-view-id
|
||||
:on-press on-press})]
|
||||
[tab data]))
|
||||
|
||||
(defview tabs-container [style children]
|
||||
@ -31,8 +37,78 @@
|
||||
:pointer-events (if tabs-hidden? :none :auto)}
|
||||
children]))
|
||||
|
||||
(defn tabs [{:keys [style tab-list selected-view-id]}]
|
||||
(defn tabs [{:keys [style tab-list selected-view-id on-press]}]
|
||||
[tabs-container style
|
||||
(into
|
||||
[react/view styles/tabs-inner-container]
|
||||
(map-indexed #(create-tab %1 %2 selected-view-id) tab-list))])
|
||||
(map-indexed #(create-tab %1 %2 selected-view-id on-press) tab-list))])
|
||||
|
||||
;; Swipable tabs
|
||||
|
||||
(defn- tab->index [tabs] (reduce #(assoc %1 (:view-id %2) (count %1)) {} tabs))
|
||||
|
||||
(defn get-tab-index [tabs view-id]
|
||||
(get (tab->index tabs) view-id 0))
|
||||
|
||||
(defn index->tab [tabs] (clojure.set/map-invert (tab->index tabs)))
|
||||
|
||||
(defn scroll-to [tab-list prev-view-id view-id]
|
||||
(let [p (get-tab-index tab-list prev-view-id)
|
||||
n (get-tab-index tab-list view-id)]
|
||||
(- n p)))
|
||||
|
||||
(defonce scrolling? (atom false))
|
||||
|
||||
(defn on-scroll-end [on-view-change tabs swiped? scroll-ended view-id]
|
||||
(fn [_ state]
|
||||
(when @scrolling?
|
||||
(async/put! scroll-ended true))
|
||||
(let [{:strs [index]} (js->clj state)
|
||||
new-view-id ((index->tab tabs) index)]
|
||||
(if new-view-id
|
||||
(when-not (= @view-id new-view-id)
|
||||
(reset! swiped? true)
|
||||
(on-view-change new-view-id))))))
|
||||
|
||||
(defn start-scrolling-loop
|
||||
"Loop that synchronizes tabs scrolling to avoid an inconsistent state."
|
||||
[scroll-start scroll-ended]
|
||||
(am/go-loop [[swiper to] (async/<! scroll-start)]
|
||||
;; start scrolling
|
||||
(reset! scrolling? true)
|
||||
(.scrollBy swiper to)
|
||||
;; lock loop until scroll ends
|
||||
(async/alts! [scroll-ended (async/timeout 2000)])
|
||||
(reset! scrolling? false)
|
||||
(recur (async/<! scroll-start))))
|
||||
|
||||
(defn swipable-tabs [{:keys [style on-view-change]} tab-list prev-view-id view-id]
|
||||
(let [swiped? (r/atom false)
|
||||
main-swiper (r/atom nil)
|
||||
scroll-start (async/chan 10)
|
||||
scroll-ended (async/chan 10)]
|
||||
(r/create-class
|
||||
{:component-did-mount
|
||||
#(start-scrolling-loop scroll-start scroll-ended)
|
||||
:component-will-update
|
||||
(fn []
|
||||
(if @swiped?
|
||||
(reset! swiped? false)
|
||||
(when @main-swiper
|
||||
(let [to (scroll-to tab-list @prev-view-id @view-id)]
|
||||
(async/put! scroll-start [@main-swiper to])))))
|
||||
:display-name "swipable-tabs"
|
||||
:reagent-render
|
||||
(fn []
|
||||
[react/view {:style style}
|
||||
[tabs {:selected-view-id @view-id
|
||||
:tab-list tab-list
|
||||
:on-press on-view-change}]
|
||||
[react/swiper (merge styles/swiper
|
||||
{:index (get-tab-index tab-list @view-id)
|
||||
:ref #(reset! main-swiper %)
|
||||
:loop false
|
||||
:on-momentum-scroll-end (on-scroll-end on-view-change tab-list swiped? scroll-ended view-id)})
|
||||
(doall
|
||||
(map-indexed (fn [index {screen :screen}]
|
||||
(with-meta screen {:key index})) tab-list))]])})))
|
@ -98,5 +98,7 @@
|
||||
{:color st/color-blue4
|
||||
:font-size 17})
|
||||
|
||||
(def toolbar-text-action-disabled {:color st/color-gray7})
|
||||
|
||||
(def item-text-white-background {:color st/color-blue4})
|
||||
|
||||
|
@ -51,8 +51,10 @@
|
||||
|
||||
;; Actions
|
||||
|
||||
(defn text-action [handler title]
|
||||
[rn/text {:style (merge tst/item tst/item-text) :on-press handler}
|
||||
(defn text-action [{:keys [style handler disabled?]} title]
|
||||
[rn/text {:style (merge tst/item tst/item-text style
|
||||
(when disabled? tst/toolbar-text-action-disabled))
|
||||
:on-press (when-not disabled? handler)}
|
||||
title])
|
||||
|
||||
(def blank-action [rn/view {:style (merge tst/item tst/toolbar-action)}])
|
||||
@ -88,7 +90,7 @@
|
||||
(defn toolbar2
|
||||
([title] (toolbar2 nil title))
|
||||
([props title] (toolbar2 props default-nav-back [content-title title]))
|
||||
([props nav-item content-item] (toolbar2 props nav-item content-item nil))
|
||||
([props nav-item content-item] (toolbar2 props nav-item content-item [actions [{:image :blank}]]))
|
||||
([{:keys [background-color
|
||||
hide-border?
|
||||
style
|
||||
|
@ -49,8 +49,7 @@
|
||||
(defn toolbar-edit []
|
||||
[toolbar/toolbar2 {}
|
||||
[toolbar/nav-button (act/back #(re-frame/dispatch [:set-in [:chat-list-ui-props :edit?] false]))]
|
||||
[toolbar/content-title (i18n/label :t/edit-chats)]
|
||||
[toolbar/actions [{:image :blank}]]])
|
||||
[toolbar/content-title (i18n/label :t/edit-chats)]])
|
||||
|
||||
(defview toolbar-search []
|
||||
(letsubs [search-text [:get-in [:toolbar-search :text]]]
|
||||
|
@ -40,8 +40,7 @@
|
||||
(defn toolbar-edit []
|
||||
[toolbar/toolbar2 {}
|
||||
[toolbar/nav-button (act/back #(dispatch [:set-in [:contacts/ui-props :edit?] false]))]
|
||||
[toolbar/content-title (label :t/edit-contacts)]
|
||||
[toolbar/actions [{:image :blank}]]])
|
||||
[toolbar/content-title (label :t/edit-contacts)]])
|
||||
|
||||
(defn contact-options [{:keys [unremovable?] :as contact} group]
|
||||
(let [delete-contact-opt {:value #(u/show-confirmation
|
||||
|
@ -5,7 +5,6 @@
|
||||
[status-im.components.checkbox.view :as checkbox]
|
||||
[status-im.components.list.views :as list]
|
||||
[status-im.components.react :as react]
|
||||
[status-im.components.tabs.styles :as tabs.styles]
|
||||
[status-im.components.tabs.views :as tabs]
|
||||
[status-im.components.toolbar-new.view :as toolbar]
|
||||
[status-im.i18n :as i18n]
|
||||
@ -24,21 +23,23 @@
|
||||
;; TODO(yenda) implement
|
||||
(utils/show-popup "TODO" "Delete Transaction"))
|
||||
|
||||
(defn unsigned-action []
|
||||
[toolbar/text-action #(re-frame/dispatch [:navigate-to-modal :wallet-transactions-sign-all])
|
||||
(defn unsigned-action [unsigned-transactions]
|
||||
[toolbar/text-action {:disabled? (zero? (count unsigned-transactions)) :handler #(re-frame/dispatch [:navigate-to-modal :wallet-transactions-sign-all])}
|
||||
(i18n/label :t/transactions-sign-all)])
|
||||
|
||||
(def history-action
|
||||
{:icon :icons/filter
|
||||
:icon-opts {}
|
||||
:handler #(utils/show-popup "TODO" "Not implemented") #_(re-frame/dispatch [:navigate-to-modal :wallet-transactions-sign-all])})
|
||||
|
||||
(defn toolbar-view [view-id]
|
||||
(defn toolbar-view [view-id unsigned-transactions]
|
||||
[toolbar/toolbar2 {}
|
||||
toolbar/default-nav-back
|
||||
[toolbar/content-title (i18n/label :t/transactions)]
|
||||
(if (= @view-id :wallet-transactions-unsigned)
|
||||
[unsigned-action]
|
||||
(case @view-id
|
||||
:wallet-transactions-unsigned
|
||||
[unsigned-action unsigned-transactions]
|
||||
|
||||
:wallet-transactions-history
|
||||
[toolbar/actions
|
||||
[history-action]])])
|
||||
|
||||
@ -74,8 +75,7 @@
|
||||
[list/item-icon {:icon :icons/forward}]])
|
||||
|
||||
;; TODO(yenda) hook with re-frame
|
||||
(defn empty-text [s]
|
||||
[react/text {:style history.styles/empty-text} s])
|
||||
(defn- empty-text [s] [react/text {:style history.styles/empty-text} s])
|
||||
|
||||
(defview history-list []
|
||||
(letsubs [transactions-history-list [:wallet/transactions-history-list]
|
||||
@ -109,11 +109,6 @@
|
||||
:title (i18n/label :t/transactions-history)
|
||||
:screen [history-list]}])
|
||||
|
||||
(defn- tab->index [tabs] (reduce #(assoc %1 (:view-id %2) (count %1)) {} tabs))
|
||||
|
||||
(defn get-tab-index [tabs view-id]
|
||||
(get (tab->index tabs) view-id 0))
|
||||
|
||||
;; Sign all
|
||||
|
||||
(defview sign-all []
|
||||
@ -136,7 +131,7 @@
|
||||
|
||||
(defn- item-tokens [{:keys [symbol label checked?]}]
|
||||
[list/item
|
||||
[list/item-icon (transaction-type->icon "pending")] ;; TODO add proper token data
|
||||
[list/item-icon (transaction-type->icon "pending")] ;; TODO(jeluard) add proper token data
|
||||
[list/item-content label symbol]
|
||||
[checkbox/checkbox {:checked? true #_checked?}]])
|
||||
|
||||
@ -168,34 +163,26 @@
|
||||
[toolbar/toolbar2 {}
|
||||
[toolbar/nav-clear-text (i18n/label :t/done)]
|
||||
[toolbar/content-title (i18n/label :t/transactions-filter-title)]
|
||||
[toolbar/text-action #(utils/show-popup "TODO" "Select All")
|
||||
[toolbar/text-action {:handler #(utils/show-popup "TODO" "Select All")}
|
||||
(i18n/label :t/transactions-filter-select-all)]]
|
||||
[react/scroll-view
|
||||
[list/section-list {:sections filter-data}]]])
|
||||
|
||||
;; TODO(jeluard) whole swipe logic
|
||||
;; extract navigate-tab action (on tap)
|
||||
(defn- main-section [view-id tabs ]
|
||||
(let [prev-view-id (reagent/atom @view-id)]
|
||||
[tabs/swipable-tabs {:style history.styles/main-section
|
||||
:on-view-change #(do (reset! prev-view-id @view-id)
|
||||
(reset! view-id %))}
|
||||
|
||||
(defn- main-section [view-id unsigned-transactions]
|
||||
(let [tabs (tab-list unsigned-transactions)]
|
||||
[react/view {:style history.styles/main-section}
|
||||
[tabs/tabs {:selected-view-id @view-id
|
||||
:tab-list tabs}]
|
||||
[react/swiper (merge tabs.styles/swiper
|
||||
{:index (get-tab-index tabs @view-id)
|
||||
:loop false})
|
||||
;:ref #(reset! swiper %)
|
||||
;:on-momentum-scroll-end (on-scroll-end swiped? scroll-ended @view-id)
|
||||
|
||||
(doall
|
||||
(map-indexed (fn [index {screen :screen}]
|
||||
(with-meta screen {:key index} )) tabs))]]))
|
||||
tabs prev-view-id view-id]))
|
||||
|
||||
;; TODO(yenda) must reflect selected wallet
|
||||
|
||||
(defview transactions []
|
||||
(letsubs [unsigned-transactions [:wallet/unsigned-transactions]]
|
||||
(let [view-id (reagent/atom :wallet-transactions-history)]
|
||||
[react/view {:style history.styles/wallet-transactions-container}
|
||||
[toolbar-view view-id]
|
||||
[main-section view-id unsigned-transactions]])))
|
||||
[unsigned-transactions [:wallet/unsigned-transactions]]
|
||||
(let [tabs (tab-list unsigned-transactions)
|
||||
default-view (get-in tabs [0 :view-id])
|
||||
view-id (reagent/atom default-view)]
|
||||
[react/view {:style history.styles/wallet-transactions-container}
|
||||
[toolbar-view view-id unsigned-transactions]
|
||||
[main-section view-id tabs]]))
|
||||
|
@ -48,7 +48,7 @@
|
||||
:flex-shrink 1
|
||||
:justify-content :space-between
|
||||
:width 68
|
||||
:margin-right 12})
|
||||
:padding 12})
|
||||
|
||||
;;;;;;;;;;;;;;;;;;
|
||||
;; Main section ;;
|
||||
@ -150,3 +150,12 @@
|
||||
|
||||
(defn asset-border [color]
|
||||
{:border-color color :border-width 1 :border-radius 32})
|
||||
|
||||
(def corner-dot
|
||||
{:position :absolute
|
||||
:top 12
|
||||
:right 6
|
||||
:width 4
|
||||
:height 4
|
||||
:border-radius 2
|
||||
:background-color styles/color-cyan})
|
@ -6,7 +6,7 @@
|
||||
[status-im.components.button.view :as btn]
|
||||
[status-im.components.drawer.view :as drawer]
|
||||
[status-im.components.list.views :as list]
|
||||
[status-im.components.react :as rn]
|
||||
[status-im.components.react :as react]
|
||||
[status-im.components.styles :as st]
|
||||
[status-im.components.icons.vector-icons :as vi]
|
||||
[status-im.components.toolbar-new.view :as toolbar]
|
||||
@ -24,10 +24,10 @@
|
||||
(utils/show-popup "TODO" "Not implemented yet!"))
|
||||
|
||||
(defn toolbar-title []
|
||||
[rn/touchable-highlight {:on-press #(rf/dispatch [:navigate-to :wallet-list])
|
||||
[react/touchable-highlight {:on-press #(rf/dispatch [:navigate-to :wallet-list])
|
||||
:style wallet-styles/toolbar-title-container}
|
||||
[rn/view {:style wallet-styles/toolbar-title-inner-container}
|
||||
[rn/text {:style wallet-styles/toolbar-title-text
|
||||
[react/view {:style wallet-styles/toolbar-title-inner-container}
|
||||
[react/text {:style wallet-styles/toolbar-title-text
|
||||
:font :toolbar-title}
|
||||
(i18n/label :t/main-wallet)]
|
||||
[vi/icon
|
||||
@ -48,19 +48,27 @@
|
||||
[(assoc (act/opts [{:text (i18n/label :t/wallet-settings) :value show-not-implemented!}]) :icon-opts {:color :white})
|
||||
transaction-history-action]]])
|
||||
|
||||
(defn- change-display [change]
|
||||
(let [pos-change? (pos? change)]
|
||||
[react/view {:style (if pos-change?
|
||||
wallet-styles/today-variation-container-positive
|
||||
wallet-styles/today-variation-container-negative)}
|
||||
[react/text {:style (if pos-change?
|
||||
wallet-styles/today-variation-positive
|
||||
wallet-styles/today-variation-negative)}
|
||||
(str (if pos-change? "+" "-") change)]]))
|
||||
|
||||
(defn main-section [usd-value change error-message]
|
||||
[rn/view {:style wallet-styles/main-section}
|
||||
[react/view {:style wallet-styles/main-section}
|
||||
(when error-message [wallet.views/error-message-view wallet-styles/error-container wallet-styles/error-message])
|
||||
[rn/view {:style wallet-styles/total-balance-container}
|
||||
[rn/view {:style wallet-styles/total-balance}
|
||||
[rn/text {:style wallet-styles/total-balance-value} usd-value]
|
||||
[rn/text {:style wallet-styles/total-balance-currency} "USD"]]
|
||||
[rn/view {:style wallet-styles/value-variation}
|
||||
[rn/text {:style wallet-styles/value-variation-title}
|
||||
[react/view {:style wallet-styles/total-balance-container}
|
||||
[react/view {:style wallet-styles/total-balance}
|
||||
[react/text {:style wallet-styles/total-balance-value} usd-value]
|
||||
[react/text {:style wallet-styles/total-balance-currency} "USD"]]
|
||||
[react/view {:style wallet-styles/value-variation}
|
||||
[react/text {:style wallet-styles/value-variation-title}
|
||||
(i18n/label :t/wallet-total-value)]
|
||||
[rn/view {:style (if (pos? change) wallet-styles/today-variation-container-positive wallet-styles/today-variation-container-negative)}
|
||||
[rn/text {:style (if (pos? change) wallet-styles/today-variation-positive wallet-styles/today-variation-negative)}
|
||||
change]]]
|
||||
[change-display change]]
|
||||
[btn/buttons wallet-styles/buttons
|
||||
[{:text (i18n/label :t/wallet-send)
|
||||
:on-press show-not-implemented! ;; #(rf/dispatch [:navigate-to :wallet-send-transaction])
|
||||
@ -79,38 +87,38 @@
|
||||
;; TODO(jeluard) Navigate to asset details screen
|
||||
#_
|
||||
[list/touchable-item show-not-implemented!
|
||||
[rn/view
|
||||
[react/view
|
||||
[list/item
|
||||
[list/item-image {:uri :launch_logo}]
|
||||
[rn/view {:style wallet-styles/asset-item-value-container}
|
||||
[rn/text {:style wallet-styles/asset-item-value} (str amount)]
|
||||
[rn/text {:style wallet-styles/asset-item-currency
|
||||
[react/view {:style wallet-styles/asset-item-value-container}
|
||||
[react/text {:style wallet-styles/asset-item-value} (str amount)]
|
||||
[react/text {:style wallet-styles/asset-item-currency
|
||||
:uppercase? true}
|
||||
id]]
|
||||
[list/item-icon {:style :icons/forward}]]]]
|
||||
[rn/view
|
||||
[react/view
|
||||
[list/item
|
||||
(let [{:keys [source style]} (token->image id)]
|
||||
[list/item-image source style])
|
||||
[rn/view {:style wallet-styles/asset-item-value-container}
|
||||
[rn/text {:style wallet-styles/asset-item-value} (str amount)]
|
||||
[rn/text {:style wallet-styles/asset-item-currency
|
||||
[react/view {:style wallet-styles/asset-item-value-container}
|
||||
[react/text {:style wallet-styles/asset-item-value} (str amount)]
|
||||
[react/text {:style wallet-styles/asset-item-currency
|
||||
:uppercase? true}
|
||||
id]]]])
|
||||
|
||||
(defn render-add-asset-fn [{:keys [id currency amount]}]
|
||||
[list/touchable-item show-not-implemented!
|
||||
[rn/view
|
||||
[react/view
|
||||
[list/item
|
||||
[list/item-icon {:icon :icons/add :style wallet-styles/add-asset-icon :icon-opts {:color :blue}}]
|
||||
[rn/view {:style wallet-styles/asset-item-value-container}
|
||||
[rn/text {:style wallet-styles/add-asset-text}
|
||||
[react/view {:style wallet-styles/asset-item-value-container}
|
||||
[react/text {:style wallet-styles/add-asset-text}
|
||||
(i18n/label :t/wallet-add-asset)]]]]])
|
||||
|
||||
(defn asset-section [eth prices-loading? balance-loading?]
|
||||
(let [assets [{:id "eth" :currency :eth :amount eth}]]
|
||||
[rn/view {:style wallet-styles/asset-section}
|
||||
[rn/text {:style wallet-styles/asset-section-title} (i18n/label :t/wallet-assets)]
|
||||
[react/view {:style wallet-styles/asset-section}
|
||||
[react/text {:style wallet-styles/asset-section-title} (i18n/label :t/wallet-assets)]
|
||||
[list/section-list
|
||||
{:sections [{:key :assets
|
||||
:data assets
|
||||
@ -129,8 +137,8 @@
|
||||
prices-loading? [:prices-loading?]
|
||||
balance-loading? [:wallet/balance-loading?]
|
||||
error-message [:wallet/error-message?]]
|
||||
[rn/view {:style wallet-styles/wallet-container}
|
||||
[react/view {:style wallet-styles/wallet-container}
|
||||
[toolbar-view]
|
||||
[rn/scroll-view
|
||||
[react/scroll-view
|
||||
[main-section portfolio-value portfolio-change error-message]
|
||||
[asset-section eth-balance prices-loading? balance-loading?]]]))
|
||||
|
Loading…
x
Reference in New Issue
Block a user