Introduced tab switching for wallet transactions screen

This commit is contained in:
Julien Eluard 2017-08-22 09:53:15 +02:00 committed by Roman Volosovskyi
parent 2ff20eb830
commit 55fd200c71
26 changed files with 308 additions and 95 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 629 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 625 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 654 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1017 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "icon_wallet_active.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "icon_wallet_gray.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,12 +1,14 @@
(ns status-im.components.button.styles
(:require-macros [status-im.utils.styles :refer [defstyle]])
(:require [status-im.components.styles :as st]))
(def border-color st/color-white-transparent-2)
(def button-borders
{:background-color border-color
:margin 5
:border-radius 8})
(defstyle button-borders
{:background-color border-color
:margin-horizontal 5
:android {:border-radius 4}
:ios {:border-radius 8}})
(def action-buttons-container
(merge

View File

@ -1,7 +1,8 @@
(ns status-im.components.button.view
(:require [cljs.spec.alpha :as s]
[status-im.components.button.styles :as cst]
[status-im.components.react :as rn]))
[status-im.components.react :as rn]
[status-im.utils.platform :as p]))
(defn button [{:keys [on-press style text text-style disabled?]
:or {style cst/action-button}}]
@ -10,7 +11,7 @@
[rn/text {:style (or text-style
(if disabled? cst/action-button-text-disabled cst/action-button-text))
:font :medium
:uppercase? false}
:uppercase? p/android?}
text]]])
(defn primary-button [m]

View File

@ -11,24 +11,45 @@
:flex-direction :column})
(def primary-text
{:font-size 20
:color st/color-black
:margin-top 13})
{:font-size 20
:color st/color-black
:padding-top 13})
(def secondary-text
{:font-size 16
:color st/color-gray4
:margin-top 6})
{:font-size 16
:color st/color-gray4
:padding-top 6})
(def item-icon
{:width 40
:height 40
:margin 14})
{:width 40
:height 40
:margin 14})
(def primary-action item-icon)
(def secondary-action item-icon)
(def action-buttons
{:flex 1
:flex-direction :row})
{:flex 1
:flex-direction :row
:padding-vertical 12})
(def base-separator
{:height 1
:background-color st/color-gray5
:opacity 0.5
:margin-top 12
:margin-bottom 16})
(def separator
(merge
base-separator
{:margin-left 70}))
(def section-separator base-separator)
(def section-header
{:margin-vertical 2
:margin-bottom 12
:margin-top 16
:margin-left 16})

View File

@ -1,23 +1,62 @@
(ns status-im.components.list.views
(:require [status-im.components.react :as rn]
[reagent.core :as r]
[status-im.components.common.common :as common]
(:require [reagent.core :as r]
[status-im.components.list.styles :as lst]
[status-im.components.react :as rn]
[status-im.utils.platform :as p]))
(def flat-list-class (rn/get-class "FlatList"))
(def section-list-class (rn/get-class "SectionList"))
(defn- wrap-render-fn [f]
(fn [o]
(let [{:keys [item index separators]} (js->clj o :keywordize-keys true)]
(fn [data]
;; For details on passed data
;; https://facebook.github.io/react-native/docs/sectionlist.html#rendersectionheader
(let [{:keys [item index separators]} (js->clj data :keywordize-keys true)]
(r/as-element (f item index separators)))))
(defn- separator []
[rn/view lst/separator])
(defn- section-separator []
[rn/view lst/section-separator])
(defn base-list-props [render-fn empty-component]
(merge {:renderItem (wrap-render-fn render-fn)
:keyExtractor (fn [_ i] i)}
(when p/ios? {:ItemSeparatorComponent (fn [] (r/as-element [separator]))})
; TODO(jeluard) Does not work with our current ReactNative version
(when empty-component {:ListEmptyComponent (r/as-element [empty-component])})))
(defn flat-list
"A wrapper for FlatList.
See https://facebook.github.io/react-native/docs/flatlist.html"
([data render-fn] (flat-list data render-fn {}))
([data render-fn props]
[flat-list-class (merge {:data (clj->js data)
:renderItem (wrap-render-fn render-fn)
:keyExtractor (fn [_ i] i)}
(when p/ios? {:ItemSeparatorComponent (fn [] (r/as-element [common/list-separator]))})
props)]))
([data render-fn {:keys [empty-component] :as props}]
(if (and (empty? data) empty-component)
;; TODO(jeluard) remove when native :ListEmptyComponent is supported
empty-component
[flat-list-class
(merge (base-list-props render-fn empty-component)
{:data (clj->js data)}
props)])))
(defn- wrap-render-section-header-fn [f]
(fn [data]
;; For details on passed data
;; https://facebook.github.io/react-native/docs/sectionlist.html#rendersectionheader
(let [{:keys [isection]} (js->clj data :keywordize-keys true)]
(r/as-element (f section)))))
(defn section-list
"A wrapper for SectionList.
See https://facebook.github.io/react-native/docs/sectionlist.html"
([data render-fn render-section-header-fn] (section-list data render-fn render-section-header-fn {}))
([data render-fn render-section-header-fn {:keys [empty-component] :as props}]
(if (and (empty? data) empty-component)
empty-component
[section-list-class
(merge (base-list-props render-fn empty-component)
{:sections (clj->js data)
:renderSectionHeader (wrap-render-section-header-fn render-section-header-fn)}
(when p/ios? {:SectionSeparatorComponent (fn [] (r/as-element [section-separator]))})
props)])))

View File

@ -20,6 +20,12 @@
(def tab-list
(concat
(when config/wallet-tab-enabled?
[{:view-id :wallet
:title (label :t/wallet)
:screen wallet
:icon-inactive :icon_wallet_gray
:icon-active :icon_wallet_active}])
[{:view-id :chat-list
:title (label :t/chats)
:screen chats-list
@ -34,13 +40,7 @@
:title (label :t/contacts)
:screen contact-groups-list
:icon-inactive :icon_contacts
:icon-active :icon_contacts_active}]
(when config/wallet-tab-enabled?
[{:view-id :wallet
:title "Wallet"
:screen wallet
:icon-inactive :icon_contacts
:icon-active :icon_contacts_active}])))
:icon-active :icon_contacts_active}]))
(def tab->index (reduce #(assoc %1 (:view-id %2) (count %1)) {} tab-list))
@ -115,8 +115,8 @@
(doall
(map-indexed (fn [index {vid :view-id screen :screen}]
^{:key index} [screen (= @view-id vid)]) tab-list))]
[tabs {:selected-view-id @view-id
:prev-view-id @prev-view-id
[tabs {:style (st/tabs-container @tabs-hidden?)
:selected-view-id @view-id
:tab-list tab-list}]
(when-not @tabs-hidden?
[bottom-shadow-view])]]]])})))

View File

@ -40,7 +40,6 @@
(defn tab-title [active?]
{:font-size (if-not (or active? p/ios?) 12 14)
:height 16
:min-width 60
:text-align :center
:color (if active? st/color-light-blue st/color-gray4)})
@ -52,15 +51,19 @@
:align-self :center})
(def tab-container
{:flex 1
:height tab-height
:justifyContent :center
:alignItems :center})
{:flex 1
:height tab-height
:justifyContent :center
:alignItems :center})
(def swiper
{:shows-pagination false})
(defn main-swiper [tabs-hidden?]
{:position :absolute
:top 0
:left 0
:right 0
:bottom (if tabs-hidden? 0 tabs-height)
:shows-pagination false})
(merge
swiper
{:position :absolute
:top 0
:left 0
:right 0
:bottom (if tabs-hidden? 0 tabs-height)}))

View File

@ -12,38 +12,37 @@
[status-im.components.animation :as anim]
[status-im.utils.platform :as p]))
(defn tab [{:keys [view-id title icon-active icon-inactive selected-view-id prev-view-id]}]
(let [active? (= view-id selected-view-id)
previous? (= view-id prev-view-id)]
(defn tab [{:keys [view-id title icon-active icon-inactive selected-view-id]}]
(let [active? (= view-id selected-view-id)]
[touchable-highlight {:style st/tab
:disabled active?
:onPress #(dispatch [:navigate-to-tab view-id])}
[view {:style st/tab-container}
[view
[image {:source {:uri (if active? icon-active icon-inactive)}
:style st/tab-icon}]]
(when-let [icon (if active? icon-active icon-inactive)]
[view
[image {:source {:uri icon}
:style st/tab-icon}]])
[view
[text {:style (st/tab-title active?)
:font (if (and p/ios? active?) :medium :regular)}
title]]]]))
(defn- create-tab [index data selected-view-id prev-view-id]
(defn- create-tab [index data selected-view-id]
(let [data (merge data {:key index
:index index
:selected-view-id selected-view-id
:prev-view-id prev-view-id})]
:selected-view-id selected-view-id})]
[tab data]))
(defn- tabs-container [& children]
(defn- tabs-container [style children]
(let [tabs-hidden? (subscribe [:tabs-hidden?])
shadows? (get-in p/platform-specific [:tabs :tab-shadows?])]
(into [animated-view {:style (merge (st/tabs-container @tabs-hidden?)
(if-not shadows? st/tabs-container-line))
:pointerEvents (if @tabs-hidden? :none :auto)}]
children)))
[animated-view {:style (merge style
(when-not shadows? st/tabs-container-line))
:pointerEvents (if @tabs-hidden? :none :auto)}
children]))
(defn tabs [{:keys [tab-list selected-view-id prev-view-id]}]
[tabs-container
(defn tabs [{:keys [style tab-list selected-view-id]}]
[tabs-container style
(into
[view st/tabs-inner-container]
(map-indexed #(create-tab %1 %2 selected-view-id prev-view-id) tab-list))])
(map-indexed #(create-tab %1 %2 selected-view-id) tab-list))])

View File

@ -44,7 +44,8 @@
(defstyle toolbar-title-text
{:color text1-color
:letter-spacing -0.2
:font-size 17})
:font-size 17
:ios {:text-align "center"}})
(def toolbar-border-container
(get-in p/platform-specific [:component-styles :toolbar-border-container]))

View File

@ -329,8 +329,13 @@
:testfairy-message "You are using app installed from a nightly build. For testing purposes this build includes session recording if wifi connection is used, so all your interaction with app is saved (as video and log) and might be used by development team to investigate possible issues. Saved video/log do not include your passwords. Recording is done only if app is installed from a nightly build. Nothing is recorded if app is installed from PlayStore or TestFlight."
;; wallet
:wallet "Wallet"
:transactions "Transactions"
:transactions-to "To"
:transactions-sign "Sign"
:transactions-sign-all "Sign all"
:transactions-delete "Delete"})
:transactions-delete "Delete"
:transactions-history "History"
:transactions-unsigned "Unsigned"
:transactions-history-empty "You don't have a history transactions"
:transactions-unsigned-empty "You don't have unsigned transactions"})

View File

@ -58,6 +58,8 @@
(when view-id
(let [current-view (validate-current-view view-id signed-up?)]
(let [component (case current-view
:wallet-transactions-unsigned wallet-transactions
:wallet-transactions-history wallet-transactions
:wallet main-tabs
:wallet-send-transaction send-transaction
:discover main-tabs
@ -85,7 +87,8 @@
:profile-photo-capture profile-photo-capture
:accounts accounts
:login login
:recover recover)]
:recover recover
(throw (str "Unknown view: " current-view)))]
[(if android? menu-context view) common-styles/flex
[view common-styles/flex
@ -102,5 +105,6 @@
:transaction-details transaction-details
:confirmation-success confirmation-success
:contact-list-modal contact-list-modal
:wallet-transactions wallet-transactions)]
:wallet-transactions wallet-transactions
(throw (str "Unknown modal view: " modal-view)))]
[component])]])]])))))

View File

@ -7,8 +7,15 @@
(def toolbar-right-action
{:color st/color-blue4
:font-size 18
:font-size 17
:margin-right 12})
(def main-section
{:background-color st/color-white})
{:flex 1
:position :relative
:background-color st/color-white})
(def empty-text
{:text-align :center
:margin-top 22
:margin-horizontal 92})

View File

@ -1,55 +1,144 @@
(ns status-im.ui.screens.wallet.history.views
(:require-macros [status-im.utils.views :refer [defview]])
(:require [status-im.components.button.view :as btn]
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [reagent.core :as r]
[status-im.components.button.view :as btn]
[status-im.components.react :as rn]
[status-im.components.list.styles :as list-st]
[status-im.components.list.views :as list]
[status-im.components.tabs.styles :as tst]
[status-im.components.tabs.views :as tabs]
[status-im.components.toolbar-new.view :as toolbar]
[status-im.ui.screens.wallet.history.styles :as st]
[status-im.utils.utils :as utils]
[status-im.i18n :as i18n]))
(defn on-sign-transaction
[m]
;; TODO(yenda) implement
(utils/show-popup "TODO" "Sign Transaction"))
(defn on-sign-all-transactions
[m]
;; TODO(yenda) implement
(utils/show-popup "TODO" "Sign All Transactions"))
(defn on-delete-transaction
[m]
;; TODO(yenda) implement
(utils/show-popup "TODO" "Delete Transaction"))
(defn unsigned-action []
[rn/text {:style st/toolbar-right-action}
[rn/text {:style st/toolbar-right-action :onPress on-sign-all-transactions}
(i18n/label :t/transactions-sign-all)])
(defn toolbar-view []
(defn history-action []
;; TODO(jeluard)
[rn/text {:style st/toolbar-right-action}
"AAAAA"])
(defn toolbar-view [view-id]
[toolbar/toolbar
{:title (i18n/label :t/transactions)
:title-style {:text-align "center"}
:custom-action [unsigned-action]}])
:custom-action
[(if (= @view-id :wallet-transactions-unsigned) unsigned-action history-action)]}])
(defn- icon-status [k]
(case k
:pending :dropdown_white
:dropdown_white))
(defn render-transaction
[item]
(defn action-buttons [m ]
[rn/view {:style list-st/action-buttons}
[btn/primary-button {:text (i18n/label :t/transactions-sign) :on-press #(on-sign-transaction m)}]
[btn/secondary-button {:text (i18n/label :t/transactions-delete) :on-press #(on-delete-transaction m)}]])
(defn- unsigned? [state] (= "unsigned" state))
(defn transaction-details [{:keys [to state] {:keys [value symbol]} :content :as m}]
[rn/view {:style list-st/item-text-view}
[rn/text {:style list-st/primary-text} (str value " " symbol)]
[rn/text {:style list-st/secondary-text :ellipsize-mode "middle" :number-of-lines 1} (str (i18n/label :t/transactions-to) " " to)]
(if (unsigned? state)
[action-buttons m])])
(defn render-transaction [m]
[rn/view {:style list-st/item}
[rn/image {:source {:uri :console}
:style list-st/item-icon}]
[rn/view {:style list-st/item-text-view}
(let [m (:content item)]
[rn/text {:style list-st/primary-text} (str (:value m) " " (:symbol m))])
[rn/text {:style list-st/secondary-text} (str (i18n/label :t/transactions-to) " " (:to item))]
[rn/view {:style list-st/action-buttons}
[btn/primary-button {:text (i18n/label :t/transactions-sign)}]
[btn/secondary-button {:text (i18n/label :t/transactions-delete)}]]]
[transaction-details m]
[rn/icon :forward_gray list-st/secondary-action]])
(defn render-section-header [m]
[rn/text {:style list-st/section-header} (:title m)])
(def dummy-transaction-data
[{:to "0xAAAAA" :content {:value "0,4909" :symbol "ETH"}}
{:to "0xAAAAA" :content {:value "10000" :symbol "SGT"}}])
[{:to "0x829bd824b016326a401d083b33d092293333a830" :content {:value "0,4909" :symbol "ETH"} :state :unsigned}
{:to "0x829bd824b016326a401d083b33d092293333a830" :content {:value "10000" :symbol "SGT"} :state :unsigned}
{:to "0x829bd824b016326a401d083b33d092293333a830" :content {:value "10000" :symbol "SGT"} :state :unsigned}])
(defn main-section []
(def dummy-transaction-data-sorted
[{:title "Postponed"
:key :postponed
:data [{:to "0x829bd824b016326a401d083b33d092293333a830" :content {:value "0,4909" :symbol "ETH"} :state :pending}
{:to "0x829bd824b016326a401d083b33d092293333a830" :content {:value "10000" :symbol "SGT"} :state :pending}
{:to "0x829bd824b016326a401d083b33d092293333a830" :content {:value "10000" :symbol "SGT"} :state :sent}]}
{:title "Pending"
:key :pending
:data [{:to "0x829bd824b016326a401d083b33d092293333a830" :content {:value "0,4909" :symbol "ETH"} :state :pending}
{:to "0x829bd824b016326a401d083b33d092293333a830" :content {:value "10000" :symbol "SGT"} :state :pending}
{:to "0x829bd824b016326a401d083b33d092293333a830" :content {:value "10000" :symbol "SGT"} :state :sent}]}])
;; TODO(yenda) hook with re-frame
(defn empty-text [s]
[rn/text {:style st/empty-text} s])
(defview history-list []
[list/section-list dummy-transaction-data-sorted render-transaction render-section-header
{:empty-component (empty-text (i18n/label :t/transactions-history-empty))}])
(defview unsigned-list []
[list/flat-list dummy-transaction-data render-transaction
{:empty-component (empty-text (i18n/label :t/transactions-unsigned-empty))}])
(def tab-list
[{:view-id :wallet-transactions-unsigned
:title (i18n/label :t/transactions-unsigned)
:screen unsigned-list}
{:view-id :wallet-transactions-history
:title (i18n/label :t/transactions-history)
:screen history-list}])
(def tab->index (reduce #(assoc %1 (:view-id %2) (count %1)) {} tab-list))
(defn get-tab-index [view-id]
(get tab->index view-id 0))
;; TODO(jeluard) whole swipe logic
;; extract navigate-tab action (on tap)
(defn main-section [view-id]
[rn/view {:style st/main-section}
[list/flat-list dummy-transaction-data render-transaction]])
[tabs/tabs {:selected-view-id @view-id
:tab-list tab-list}]
[rn/swiper (merge tst/swiper
{:index (get-tab-index @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}]
^{:key index} [screen]) tab-list))]])
;; TODO must reflect selected wallet
;; TODO(yenda) must reflect selected wallet
(def initial-tab (-> tab-list first :view-id))
(defview wallet-transactions []
[]
[rn/view {:style st/wallet-transactions-container}
[toolbar-view]
[rn/scroll-view
[main-section]]])
(let [view-id (r/atom initial-tab)]
[rn/view {:style st/wallet-transactions-container}
[toolbar-view view-id]
[rn/scroll-view
[main-section view-id]]]))