Implement wallet/transactions basic skeleton

This commit is contained in:
Julien Eluard 2017-08-11 12:07:10 +02:00 committed by Roman Volosovskyi
parent 69a84c8315
commit 9bacc65c8d
20 changed files with 268 additions and 165 deletions

1
.env
View File

@ -1 +1,2 @@
TESTFAIRY_ENABLED=0 TESTFAIRY_ENABLED=0
WALLET_TAB_ENABLED=0

View File

@ -6,9 +6,7 @@
animated-view animated-view
text text
icon icon
touchable-highlight touchable-highlight]]
list-view
list-item]]
[status-im.components.chat-icon.screen :refer [chat-icon-view-menu-item]] [status-im.components.chat-icon.screen :refer [chat-icon-view-menu-item]]
[status-im.chat.styles.screen :as st] [status-im.chat.styles.screen :as st]
[status-im.i18n :refer [label label-pluralize]] [status-im.i18n :refer [label label-pluralize]]

View File

@ -11,42 +11,38 @@
[status-im.ui.screens.discover.views :refer [discover]] [status-im.ui.screens.discover.views :refer [discover]]
[status-im.ui.screens.contacts.views :refer [contact-groups-list]] [status-im.ui.screens.contacts.views :refer [contact-groups-list]]
[status-im.ui.screens.wallet.main-screen.views :refer [wallet]] [status-im.ui.screens.wallet.main-screen.views :refer [wallet]]
[status-im.components.tabs.tabs :refer [tabs]] [status-im.utils.config :as config]
[status-im.components.tabs.views :refer [tabs]]
[status-im.components.tabs.styles :as st] [status-im.components.tabs.styles :as st]
[status-im.components.styles :as common-st] [status-im.components.styles :as common-st]
[status-im.i18n :refer [label]] [status-im.i18n :refer [label]]
[cljs.core.async :as a])) [cljs.core.async :as a]))
(def tab-list (def tab-list
[{:view-id :chat-list (concat
:title (label :t/chats) [{:view-id :chat-list
:screen chats-list :title (label :t/chats)
:icon-inactive :icon_chats :screen chats-list
:icon-active :icon_chats_active :icon-inactive :icon_chats
:index 0} :icon-active :icon_chats_active}
{:view-id :discover {:view-id :discover
:title (label :t/discover) :title (label :t/discover)
:screen discover :screen discover
:icon-inactive :icon_discover :icon-inactive :icon_discover
:icon-active :icon_discover_active :icon-active :icon_discover_active}
:index 1} {:view-id :contact-list
{:view-id :contact-list :title (label :t/contacts)
:title (label :t/contacts) :screen contact-groups-list
:screen contact-groups-list :icon-inactive :icon_contacts
:icon-inactive :icon_contacts :icon-active :icon_contacts_active}]
:icon-active :icon_contacts_active (when config/wallet-tab-enabled?
:index 2} [{:view-id :wallet
{:view-id :wallet :title "Wallet"
:title "Wallet" :screen wallet
:screen wallet :icon-inactive :icon_contacts
:icon-inactive :icon_contacts :icon-active :icon_contacts_active}])))
:icon-active :icon_contacts_active
:index 3}])
(def tab->index {:chat-list 0 (def tab->index (reduce #(assoc %1 (:view-id %2) (count %1)) {} tab-list))
:discover 1
:contact-list 2
:wallet 3})
(def index->tab (clojure.set/map-invert tab->index)) (def index->tab (clojure.set/map-invert tab->index))
@ -116,12 +112,9 @@
:loop false :loop false
:ref #(reset! main-swiper %) :ref #(reset! main-swiper %)
:on-momentum-scroll-end (on-scroll-end swiped? scroll-ended @view-id)}) :on-momentum-scroll-end (on-scroll-end swiped? scroll-ended @view-id)})
[chats-list] (doall
[discover (= @view-id :discover)] (map-indexed (fn [index {vid :view-id screen :screen}]
[contact-groups-list (= @view-id :contact-list)]] ^{:key index} [screen (= @view-id vid)]) tab-list))]
;; TODO(oskarth): While wallet is in WIP we hide the wallet component
;;[wallet (= @view-id :wallet)]
[tabs {:selected-view-id @view-id [tabs {:selected-view-id @view-id
:prev-view-id @prev-view-id :prev-view-id @prev-view-id
:tab-list tab-list}] :tab-list tab-list}]

View File

@ -40,6 +40,7 @@
(def list-view-class (get-class "ListView")) (def list-view-class (get-class "ListView"))
(def scroll-view (get-class "ScrollView")) (def scroll-view (get-class "ScrollView"))
(def flat-list-class (get-class "FlatList"))
(def web-view (get-class "WebView")) (def web-view (get-class "WebView"))
(def keyboard-avoiding-view-class (get-class "KeyboardAvoidingView")) (def keyboard-avoiding-view-class (get-class "KeyboardAvoidingView"))
@ -105,6 +106,20 @@
:resizeMode "contain" :resizeMode "contain"
:style style}])) :style style}]))
(defn- wrap-render-fn [f]
(fn [o]
(let [{:keys [item index separators]} (js->clj o :keywordize-keys true)]
(r/as-element (f item index separators)))))
(defn flat-list
"A function wrapping the creation of 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)} props)]))
;; TODO Migrate to new FlatList and SectionList when appropriate. ListView will eventually get deprecated
;; see https://facebook.github.io/react-native/docs/using-a-listview.html
(defn list-view [props] (defn list-view [props]
[list-view-class (merge {:enableEmptySections true} props)]) [list-view-class (merge {:enableEmptySections true} props)])

View File

@ -1,23 +0,0 @@
(ns status-im.components.tabs.tab
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
[status-im.components.react :refer [view
text
image
touchable-highlight]]
[status-im.utils.platform :as p]
[status-im.components.tabs.styles :as st]))
(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)]
[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}]]
[view
[text {:style (st/tab-title active?)
:font (if (and p/ios? active?) :medium :regular)}
title]]]]))

View File

@ -1,4 +1,4 @@
(ns status-im.components.tabs.tabs (ns status-im.components.tabs.views
(:require-macros [status-im.utils.views :refer [defview]]) (:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
[status-im.components.react :refer [view [status-im.components.react :refer [view
@ -9,20 +9,34 @@
touchable-highlight]] touchable-highlight]]
[reagent.core :as r] [reagent.core :as r]
[status-im.components.tabs.styles :as st] [status-im.components.tabs.styles :as st]
[status-im.components.tabs.tab :refer [tab]]
[status-im.components.animation :as anim] [status-im.components.animation :as anim]
[status-im.utils.platform :refer [platform-specific]])) [status-im.utils.platform :as p]))
(defn create-tab [index data selected-view-id prev-view-id] (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)]
[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}]]
[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]
(let [data (merge data {:key index (let [data (merge data {:key index
:index index :index index
:selected-view-id selected-view-id :selected-view-id selected-view-id
:prev-view-id prev-view-id})] :prev-view-id prev-view-id})]
[tab data])) [tab data]))
(defn tabs-container [& children] (defn- tabs-container [& children]
(let [tabs-hidden? (subscribe [:tabs-hidden?]) (let [tabs-hidden? (subscribe [:tabs-hidden?])
shadows? (get-in platform-specific [:tabs :tab-shadows?])] shadows? (get-in p/platform-specific [:tabs :tab-shadows?])]
(into [animated-view {:style (merge (st/tabs-container @tabs-hidden?) (into [animated-view {:style (merge (st/tabs-container @tabs-hidden?)
(if-not shadows? st/tabs-container-line)) (if-not shadows? st/tabs-container-line))
:pointerEvents (if @tabs-hidden? :none :auto)}] :pointerEvents (if @tabs-hidden? :none :auto)}]
@ -32,12 +46,4 @@
[tabs-container [tabs-container
(into (into
[view st/tabs-inner-container] [view st/tabs-inner-container]
(let [tabs (into [] tab-list)] (map-indexed #(create-tab %1 %2 selected-view-id prev-view-id) tab-list))])
[[create-tab 0 (nth tabs 0) selected-view-id prev-view-id]
[create-tab 1 (nth tabs 1) selected-view-id prev-view-id]
[create-tab 2 (nth tabs 2) selected-view-id prev-view-id]
;; WALLET TAB
;;[create-tab 3 (nth tabs 3) selected-view-id prev-view-id]
])
;; todo: figure why it doesn't work on iOS release build
#_(map-indexed #(create-tab %1 %2 selected-view-id prev-view-id) tab-list))])

View File

@ -14,6 +14,8 @@
[status-im.accessibility-ids :as id] [status-im.accessibility-ids :as id]
[status-im.utils.platform :refer [platform-specific]])) [status-im.utils.platform :refer [platform-specific]]))
;; TODO This is our old toolbar component. Please do not use it and consider moving legacy usage to the new toolbar_new component.
(defn toolbar [{title :title (defn toolbar [{title :title
nav-action :nav-action nav-action :nav-action
hide-nav? :hide-nav? hide-nav? :hide-nav?

View File

@ -1,5 +1,7 @@
(ns status-im.components.toolbar-new.actions (ns status-im.components.toolbar-new.actions
(:require [status-im.components.toolbar-new.styles :as st])) (:require [re-frame.core :refer [dispatch]]
[status-im.accessibility-ids :as id]
[status-im.components.toolbar-new.styles :as st]))
(def nothing (def nothing
{:image {:source nil {:image {:source nil
@ -25,7 +27,7 @@
:style st/action-default} :style st/action-default}
:handler handler}) :handler handler})
(defn search-icon [] (def search-icon
{:image {:source {:uri :icon_search_dark} {:image {:source {:uri :icon_search_dark}
:style (merge st/action-default :style (merge st/action-default
{:opacity 0.4})}}) {:opacity 0.4})}})
@ -33,7 +35,11 @@
(defn back [handler] (defn back [handler]
{:image {:source {:uri :icon_back_dark} {:image {:source {:uri :icon_back_dark}
:style st/action-default} :style st/action-default}
:handler handler}) :handler handler
:accessibility-label id/toolbar-back-button})
(def default-back
(back #(dispatch [:navigate-back])))
(defn back-white [handler] (defn back-white [handler]
{:image {:source {:uri :icon_back_white} {:image {:source {:uri :icon_back_white}

View File

@ -1,81 +1,70 @@
(ns status-im.components.toolbar-new.view (ns status-im.components.toolbar-new.view
(:require [re-frame.core :refer [subscribe dispatch]] (:require [re-frame.core :refer [subscribe dispatch]]
[status-im.components.react :refer [view [status-im.components.react :as rn]
icon
text
text-input
image
touchable-highlight]]
[status-im.components.sync-state.gradient :refer [sync-state-gradient-view]] [status-im.components.sync-state.gradient :refer [sync-state-gradient-view]]
[status-im.components.styles :refer [icon-default [status-im.components.styles :as st]
icon-search
color-gray4]]
[status-im.components.context-menu :refer [context-menu]] [status-im.components.context-menu :refer [context-menu]]
[status-im.components.toolbar-new.actions :as act] [status-im.components.toolbar-new.actions :as act]
[status-im.components.toolbar-new.styles :as st] [status-im.components.toolbar-new.styles :as tst]
[status-im.accessibility-ids :as id]
[status-im.utils.platform :refer [platform-specific]]
[reagent.core :as r])) [reagent.core :as r]))
(defn toolbar [{title :title (defn nav-button
nav-action :nav-action [{:keys [handler accessibility-label image]}]
hide-nav? :hide-nav? [rn/touchable-highlight
actions :actions (merge {:style tst/toolbar-button
custom-action :custom-action :on-press handler}
background-color :background-color (when accessibility-label
custom-content :custom-content {:accessibility-label accessibility-label}))
hide-border? :hide-border? [rn/view
border-style :border-style [rn/image image]]])
title-style :title-style
style :style}]
(let [style (merge (st/toolbar-wrapper background-color) style)]
[view {:style style}
[view st/toolbar
[view (st/toolbar-nav-actions-container actions)
(when-not hide-nav?
(if nav-action
[touchable-highlight {:style st/toolbar-button
:on-press (:handler nav-action)}
[view
[image (:image nav-action)]]]
[touchable-highlight {:style st/toolbar-button
:on-press #(dispatch [:navigate-back])
:accessibility-label id/toolbar-back-button}
[view
[image {:source {:uri :icon_back_dark}
:style icon-default}]]]))]
(or custom-content
[view {:style st/toolbar-title-container}
[text {:style (merge st/toolbar-title-text title-style)
:font :toolbar-title}
title]])
[view (st/toolbar-actions-container (count actions) custom-action)
(if actions
(for [{action-image :image
action-options :options
action-handler :handler} actions]
(with-meta
(cond (= action-image :blank)
[view st/toolbar-action]
action-options (defn toolbar [{:keys [title
nav-action
hide-nav?
actions
custom-action
background-color
custom-content
hide-border?
border-style
title-style
style]}]
(let [style (merge (tst/toolbar-wrapper background-color) style)]
[rn/view {:style style}
[rn/view tst/toolbar
(when-not hide-nav?
[rn/view (tst/toolbar-nav-actions-container actions)
[nav-button (or nav-action act/default-back)]])
(or custom-content
[rn/view {:style tst/toolbar-title-container}
[rn/text {:style (merge tst/toolbar-title-text title-style)
:font :toolbar-title}
title]])
[rn/view (tst/toolbar-actions-container (count actions) custom-action)
(if actions
(for [{:keys [image options handler]} actions]
(with-meta
(cond (= image :blank)
[rn/view tst/toolbar-action]
options
[context-menu [context-menu
[view st/toolbar-action [image action-image]] [rn/view tst/toolbar-action [rn/image image]]
action-options options
nil nil
st/toolbar-button] tst/toolbar-button]
:else :else
[touchable-highlight {:style st/toolbar-button [rn/touchable-highlight {:style tst/toolbar-button
:on-press action-handler} :on-press handler}
[view st/toolbar-action [rn/view tst/toolbar-action
[image action-image]]]) [rn/image image]]])
{:key (str "action-" action-image)})) {:key (str "action-" image)}))
custom-action)]] custom-action)]]
[sync-state-gradient-view] [sync-state-gradient-view]
(when-not hide-border? (when-not hide-border?
[view (merge st/toolbar-border-container border-style) [rn/view (merge tst/toolbar-border-container border-style)
[view st/toolbar-border]])])) [rn/view tst/toolbar-border]])]))
(def search-text-input (r/atom nil)) (def search-text-input (r/atom nil))
@ -89,21 +78,21 @@
title title
custom-title custom-title
on-search-submit]}] on-search-submit]}]
[view st/toolbar-with-search-content [rn/view tst/toolbar-with-search-content
(if show-search? (if show-search?
[text-input [rn/text-input
{:style st/toolbar-search-input {:style tst/toolbar-search-input
:ref #(reset! search-text-input %) :ref #(reset! search-text-input %)
:auto-focus true :auto-focus true
:placeholder search-placeholder :placeholder search-placeholder
:placeholder-text-color color-gray4 :placeholder-text-color st/color-gray4
:on-change-text #(dispatch [:set-in [:toolbar-search :text] %]) :on-change-text #(dispatch [:set-in [:toolbar-search :text] %])
:on-submit-editing (when on-search-submit :on-submit-editing (when on-search-submit
#(toolbar-search-submit on-search-submit))}] #(toolbar-search-submit on-search-submit))}]
(or custom-title (or custom-title
[view [rn/view
[text {:style st/toolbar-title-text [rn/text {:style tst/toolbar-title-text
:font :toolbar-title} :font :toolbar-title}
title]]))]) title]]))])
(defn toolbar-with-search [{:keys [show-search? (defn toolbar-with-search [{:keys [show-search?
@ -122,7 +111,7 @@
[(act/close #(do [(act/close #(do
(.clear @search-text-input) (.clear @search-text-input)
(dispatch [:set-in [:toolbar-search :text] ""])))] (dispatch [:set-in [:toolbar-search :text] ""])))]
[(act/search-icon)]) [act/search-icon])
(into [(act/search #(toggle-search-fn search-key))] actions))] (into [(act/search #(toggle-search-fn search-key))] actions))]
[toolbar {:style style [toolbar {:style style
:nav-action (if show-search? :nav-action (if show-search?

View File

@ -326,4 +326,8 @@
;;testfairy warning ;;testfairy warning
:testfairy-title "Warning!" :testfairy-title "Warning!"
: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."}) :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
:transactions "Transactions"
:transactions-sign-all "Sign all"})

View File

@ -41,8 +41,8 @@
[status-im.ui.screens.profile.edit.views :refer [edit-my-profile]] [status-im.ui.screens.profile.edit.views :refer [edit-my-profile]]
[status-im.ui.screens.profile.photo-capture.views :refer [profile-photo-capture]] [status-im.ui.screens.profile.photo-capture.views :refer [profile-photo-capture]]
[status-im.ui.screens.profile.qr-code.views :refer [qr-code-view]] [status-im.ui.screens.profile.qr-code.views :refer [qr-code-view]]
[status-im.ui.screens.wallet.send.views :refer [send-transaction]])) [status-im.ui.screens.wallet.send.views :refer [send-transaction]]
;;[status-im.ui.screens.wallet.receive.views :refer [receive-transaction]] [status-im.ui.screens.wallet.history.views :refer [wallet-transactions]]))
(defn validate-current-view (defn validate-current-view
[current-view signed-up?] [current-view signed-up?]
@ -60,7 +60,6 @@
(let [component (case current-view (let [component (case current-view
:wallet main-tabs :wallet main-tabs
:wallet-send-transaction send-transaction :wallet-send-transaction send-transaction
;;:wallet-receive-transaction receive-transaction
:discover main-tabs :discover main-tabs
:discover-search-results discover-search-results :discover-search-results discover-search-results
:chat-list main-tabs :chat-list main-tabs
@ -102,5 +101,6 @@
:unsigned-transactions unsigned-transactions :unsigned-transactions unsigned-transactions
:transaction-details transaction-details :transaction-details transaction-details
:confirmation-success confirmation-success :confirmation-success confirmation-success
:contact-list-modal contact-list-modal)] :contact-list-modal contact-list-modal
:wallet-transactions wallet-transactions)]
[component])]])]]))))) [component])]])]])))))

View File

@ -0,0 +1,46 @@
(ns status-im.ui.screens.wallet.history.styles
(:require-macros [status-im.utils.styles :refer [defnstyle]])
(:require [status-im.components.styles :as common]))
(def wallet-transactions-container
{:flex 1
:background-color common/color-white})
(def toolbar-buttons-container
{:flex-direction :row
:flex-shrink 1
:justify-content :space-between
:width 68
:margin-right 12})
(def item
{:flex-direction :row
:flex 1})
(def item-text-view
{:flex 1
:flex-direction :column})
(def primary-text
{:flex 1
:font-size 16
:color common/color-black})
(def secondary-text
{:font-size 16
:color common/color-gray4})
(def item-icon
{:width 40
:height 40})
(def secondary-action
(merge item-icon {:align-self "flex-end"}))
;;;;;;;;;;;;;;;;;;
;; Main section ;;
;;;;;;;;;;;;;;;;;;
(def main-section
{:padding 16
:background-color common/color-white})

View File

@ -0,0 +1,49 @@
(ns status-im.ui.screens.wallet.history.views
(:require-macros [status-im.utils.views :refer [defview]])
(:require [status-im.components.react :as rn]
[status-im.components.toolbar-new.view :as toolbar]
[status-im.ui.screens.wallet.history.styles :as st]
[status-im.i18n :as i18n]))
(defn unsigned-action []
[rn/view {:style st/toolbar-buttons-container}
[rn/text (i18n/label :t/transactions-sign-all)]])
(defn toolbar-view []
[toolbar/toolbar
{:title (i18n/label :t/transactions)
:title-style {:text-align "center"}
:custom-action [unsigned-action]}])
(defn- icon-status [k]
(case k
:pending :dropdown_white
:dropdown_white))
(defn render-transaction
[item]
[rn/view {:style st/item}
[rn/image {:source {:uri :console}
:style st/item-icon}]
#_
[rn/icon :dropdown-white #_(icon-status (:status item)) st/item-icon]
[rn/view {:style st/item-text-view}
(let [m (:content item)]
[rn/text {:style st/primary-text} (str (:value m) " " (:symbol m))])
[rn/text {:style st/secondary-text} (:to item)]]
[rn/icon :forward_gray st/secondary-action]])
(defn main-section []
[rn/view {:style st/main-section}
(rn/flat-list [{:to "0xAAAAA" :content {:value "5" :symbol "ETH"} :status :pending}
{:from "0xAAAAA" :content {:value "5" :symbol "ETH"} :status :sent}
{:to "0xAAAAA" :content {:value "5" :symbol "ETH"} :status :pending}] render-transaction)])
(defview wallet-transactions []
[]
[rn/view {:style st/wallet-transactions-container}
[toolbar-view]
[rn/scroll-view
[main-section]]])

View File

@ -26,7 +26,7 @@
(defn toolbar-view [] (defn toolbar-view []
[toolbar/toolbar {:style st/toolbar [toolbar/toolbar {:style st/toolbar
:nav-action (act/list-white #(rf/dispatch [:navigate-to-modal :unsigned-transactions])) :nav-action (act/list-white #(rf/dispatch [:navigate-to-modal :wallet-transactions]))
:custom-content [toolbar-title] :custom-content [toolbar-title]
:custom-action [toolbar-buttons]}]) :custom-action [toolbar-buttons]}])

View File

@ -3,7 +3,11 @@
(def config (js->clj (.-default rn-dependencies/config) :keywordize-keys true)) (def config (js->clj (.-default rn-dependencies/config) :keywordize-keys true))
(defn get-config [k] (defn get-config
(get config k)) ([k] (get config k))
([k not-found] (get config k not-found)))
(def testfairy-enabled? (= "1" (get-config :TESTFAIRY_ENABLED))) (defn enabled? [v] (= "1" v))
(def testfairy-enabled? (enabled? (get-config :TESTFAIRY_ENABLED)))
(def wallet-tab-enabled? (enabled? (get-config :WALLET_TAB_ENABLED 0)))

View File

@ -4,13 +4,13 @@
(.cloneWithRows ds (reduce (fn [ac el] (.push ac el) ac) (.cloneWithRows ds (reduce (fn [ac el] (.push ac el) ac)
(clj->js []) rows))) (clj->js []) rows)))
(defn data-source [config] (defn- data-source [config]
(js/ReactNative.ListView.DataSource. (clj->js config))) (js/ReactNative.ListView.DataSource. (clj->js config)))
(defn to-datasource [items] (defn to-datasource [items]
(clone-with-rows (data-source {:rowHasChanged not=}) items)) (clone-with-rows (data-source {:rowHasChanged not=}) items))
(defn clone-with-rows-inverted [ds rows] (defn- clone-with-rows-inverted [ds rows]
(let [rows (reduce (fn [ac el] (.push ac el) ac) (let [rows (reduce (fn [ac el] (.push ac el) ac)
(clj->js []) (reverse rows)) (clj->js []) (reverse rows))
row-ids (.reverse (.map rows (fn [_ index] index)))] row-ids (.reverse (.map rows (fn [_ index] index)))]

View File

@ -1,6 +1,6 @@
(ns status-im.react-native.js-dependencies) (ns status-im.react-native.js-dependencies)
(def action-button #js {}) (def action-button #js {:default #js {:Item #js {}}})
(def android-sms-listener #js {}) (def android-sms-listener #js {})
(def autolink #js {:default #js {}}) (def autolink #js {:default #js {}})
(def config #js {:default #js {}}) (def config #js {:default #js {}})
@ -29,12 +29,13 @@
#js {:NativeModules #js {} #js {:NativeModules #js {}
:Animated #js {:View #js {} :Animated #js {:View #js {}
:Text #js {}} :Text #js {}}
:DeviceEventEmitter #js {:addListener (fn [])}}) :DeviceEventEmitter #js {:addListener (fn [])}
:Dimensions #js {:get (fn [])}})
(def realm #js {:schemaVersion (fn []) (def realm #js {:schemaVersion (fn [])
:close (fn [])}) :close (fn [])})
(def sortable-listview #js {}) (def sortable-listview #js {})
(def swiper #js {}) (def swiper #js {})
(def vector-icons #js {}) (def vector-icons #js {:default #js {}})
(def webview-bridge #js {:default #js {}}) (def webview-bridge #js {:default #js {}})

View File

@ -0,0 +1,8 @@
(ns status-im.test.components.main-tabs
(:require [cljs.test :refer-macros [deftest is testing]]
[status-im.components.main-tabs :as tabs]))
(deftest tab->index
(is (contains? tabs/tab->index :chat-list))
(is (= 1 (:discover tabs/tab->index))))

View File

@ -2,6 +2,7 @@
(:require [doo.runner :refer-macros [doo-tests]] (:require [doo.runner :refer-macros [doo-tests]]
[status-im.test.contacts.handlers] [status-im.test.contacts.handlers]
[status-im.test.chat.models.input] [status-im.test.chat.models.input]
[status-im.test.components.main-tabs]
[status-im.test.handlers] [status-im.test.handlers]
[status-im.test.utils.utils] [status-im.test.utils.utils]
[status-im.test.utils.money] [status-im.test.utils.money]
@ -17,6 +18,7 @@
(doo-tests 'status-im.test.contacts.handlers (doo-tests 'status-im.test.contacts.handlers
'status-im.test.chat.models.input 'status-im.test.chat.models.input
'status-im.test.components.main-tabs
'status-im.test.handlers 'status-im.test.handlers
'status-im.test.utils.utils 'status-im.test.utils.utils
'status-im.test.utils.money 'status-im.test.utils.money

View File

@ -10,6 +10,8 @@
(def b (atom {:identity "b"})) (def b (atom {:identity "b"}))
(def c (atom {:identity "c"})) (def c (atom {:identity "c"}))
(declare recv!)
;; The network is unreliable. ;; The network is unreliable.
(defn random-broadcast! [chat-id message] (defn random-broadcast! [chat-id message]
(when (> (rand-int 10) 5) (recv! a chat-id message)) (when (> (rand-int 10) 5) (recv! a chat-id message))