[ISSUE #1840] Migrated to FlatList

This commit is contained in:
Julien Eluard 2017-10-24 15:22:38 +02:00 committed by Julien Eluard
parent 558fc8fd62
commit 7c8aa75724
30 changed files with 480 additions and 586 deletions

View File

@ -13,7 +13,6 @@
},
"modules": [
"react-native-contacts",
"react-native-invertible-scroll-view",
"awesome-phonenumber",
"realm",
"react-native-i18n",

11
package-lock.json generated
View File

@ -7586,17 +7586,6 @@
"resolved": "https://registry.npmjs.org/react-native-image-resizer/-/react-native-image-resizer-1.0.0.tgz",
"integrity": "sha1-1H4UlDw3k44of71jnk23zrf9iRc="
},
"react-native-invertible-scroll-view": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/react-native-invertible-scroll-view/-/react-native-invertible-scroll-view-1.1.0.tgz",
"integrity": "sha1-v9UKP11myhJjm3x6mETO3dHRaJA=",
"requires": {
"create-react-class": "15.6.2",
"prop-types": "15.6.0",
"react-clone-referenced-element": "1.0.1",
"react-native-scrollable-mixin": "1.0.1"
}
},
"react-native-level-fs": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/react-native-level-fs/-/react-native-level-fs-3.0.0.tgz",

View File

@ -19,7 +19,6 @@
(def image-crop-picker (js/require "react-native-image-crop-picker"))
(def image-resizer (js/require "react-native-image-resizer"))
(def instabug (js/require "instabug-reactnative"))
(def invertible-scroll-view (js/require "react-native-invertible-scroll-view"))
(def linear-gradient (js/require "react-native-linear-gradient"))
(def mapbox-gl (js/require "react-native-mapbox-gl"))
(def nfc (js/require "nfc-react-native"))

View File

@ -6,5 +6,5 @@
:margin-bottom 0})
(def contacts-list
{:backgroundColor common/color-light-gray})
{:background-color common/color-light-gray})

View File

@ -2,75 +2,72 @@
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [re-frame.core :refer [dispatch]]
[status-im.ui.components.common.common :as common]
[status-im.ui.components.renderers.renderers :as renderers]
[status-im.ui.components.action-button.action-button :refer [action-button
action-separator]]
[status-im.ui.components.action-button.styles :refer [actions-list]]
[status-im.ui.components.react :refer [view text list-view list-item]]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.contact.contact :refer [contact-view]]
[status-im.ui.components.react :as react]
[status-im.ui.components.status-bar.view :refer [status-bar]]
[status-im.ui.components.toolbar.view :refer [toolbar-with-search]]
[status-im.ui.components.drawer.view :refer [drawer-view]]
[status-im.ui.components.drawer.view :as drawer]
[status-im.chat.new-chat.styles :as styles]
[status-im.utils.listview :as lw]
[status-im.i18n :refer [label]]))
[status-im.i18n :as i18n]))
(defn options-list []
[view actions-list
[action-button {:label (label :t/new-group-chat)
[react/view actions-list
[action-button {:label (i18n/label :t/new-group-chat)
:icon :icons/group-big
:icon-opts {:color :blue}
:on-press #(dispatch [:open-contact-toggle-list :chat-group])}]
[action-separator]
[action-button {:label (label :t/new-public-group-chat)
[action-button {:label (i18n/label :t/new-public-group-chat)
:icon :icons/public
:icon-opts {:color :blue}
:on-press #(dispatch [:navigate-to :new-public-chat])}]
[action-separator]
[action-button {:label (label :t/add-new-contact)
[action-button {:label (i18n/label :t/add-new-contact)
:icon :icons/add
:icon-opts {:color :blue}
:on-press #(dispatch [:navigate-to :new-contact])}]])
(defn contact-list-row []
(fn [row _ _]
(list-item ^{:key row}
[contact-view {:contact row
:on-press #(dispatch [:open-chat-with-contact %])}])))
(defn contact-list-row [contact]
[contact-view {:contact contact
:on-press #(dispatch [:open-chat-with-contact %])}])
(defview new-chat-toolbar []
(letsubs [show-search [:get-in [:toolbar-search :show]]
search-text [:get-in [:toolbar-search :text]]]
[view
[react/view
[status-bar]
(toolbar-with-search
{:show-search? (= show-search :contact-list)
:search-text search-text
:search-key :contact-list
:title (label :t/contacts-group-new-chat)
:search-placeholder (label :t/search-for)})]))
:title (i18n/label :t/contacts-group-new-chat)
:search-placeholder (i18n/label :t/search-for)})]))
(defn- header [contacts]
[react/view
[options-list]
[common/bottom-shadow]
[common/form-title (i18n/label :t/choose-from-contacts)
{:count-value (count contacts)}]
[common/list-header]])
(defview new-chat []
(letsubs [contacts [:all-added-group-contacts-filtered]
params [:get :contacts/click-params]]
[drawer-view
[view styles/contacts-list-container
[drawer/drawer-view
[react/view styles/contacts-list-container
[new-chat-toolbar]
(when contacts
[list-view {:dataSource (lw/to-datasource contacts)
:enableEmptySections true
:renderRow (contact-list-row)
:bounces false
:keyboardShouldPersistTaps :always
:renderHeader #(list-item
[view
[options-list]
[common/bottom-shadow]
[common/form-title (label :t/choose-from-contacts)
{:count-value (count contacts)}]
[common/list-header]])
:renderSeparator renderers/list-separator-renderer
:renderFooter #(list-item [view
[common/list-footer]
[common/bottom-shadow]])
:style styles/contacts-list}])]]))
[list/flat-list {:style styles/contacts-list
:data contacts
:render-fn contact-list-row
:bounces false
:keyboardShouldPersistTaps :always
:header (header contacts)
:footer [react/view
[common/list-footer]
[common/bottom-shadow]]}])]]))

View File

@ -1,16 +1,10 @@
(ns status-im.chat.screen
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [re-frame.core :as re-frame]
[status-im.ui.components.react :as react]
[status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.ui.components.status-bar.view :as status-bar]
[status-im.ui.components.chat-icon.screen :as chat-icon-screen]
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.chat.styles.screen :as style]
[status-im.utils.listview :as listview]
[status-im.utils.datetime :as time]
[status-im.utils.platform :as platform]
[status-im.ui.components.invertible-scroll-view :as scroll-view]
[status-im.ui.components.toolbar.view :as toolbar]
[status-im.chat.views.toolbar-content :as toolbar-content]
[status-im.chat.views.message.message :as message]
[status-im.chat.views.message.datemark :as message-datemark]
@ -18,9 +12,15 @@
[status-im.chat.views.actions :as actions]
[status-im.chat.views.bottom-info :as bottom-info]
[status-im.i18n :as i18n]
[status-im.ui.components.react :as react]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.ui.components.status-bar.view :as status-bar]
[status-im.ui.components.chat-icon.screen :as chat-icon-screen]
[status-im.ui.components.animation :as anim]
[status-im.ui.components.animation :as anim]
[status-im.ui.components.sync-state.offline :as offline]
[clojure.string :as string]))
[status-im.ui.components.toolbar.view :as toolbar]))
(defview chat-icon []
(letsubs [{:keys [chat-id group-chat name color]} [:get-current-chat]]
@ -65,26 +65,25 @@
(defmethod message-row :datemark
[{{:keys [value]} :row}]
(react/list-item [message-datemark/chat-datemark value]))
[message-datemark/chat-datemark value])
(defmethod message-row :default
[{:keys [group-chat current-public-key row]}]
(react/list-item [message/chat-message (assoc row
:group-chat group-chat
:current-public-key current-public-key)]))
[message/chat-message (assoc row
:group-chat group-chat
:current-public-key current-public-key)])
(defview messages-view [chat-id group-chat]
(letsubs [messages [:get-chat-messages chat-id]
current-public-key [:get-current-public-key]]
[react/list-view {:renderRow (fn [row _ index]
(message-row {:group-chat group-chat
:current-public-key current-public-key
:row row}))
:renderScrollComponent #(scroll-view/invertible-scroll-view (js->clj %))
:onEndReached #(re-frame/dispatch [:load-more-messages])
:enableEmptySections true
:keyboardShouldPersistTaps (if platform/android? :always :handled)
:dataSource (listview/to-datasource-inverted messages)}]))
[list/flat-list {:data messages
:render-fn #(message-row {:group-chat group-chat
:current-public-key current-public-key
:row %1})
:inverted true
:onEndReached #(re-frame/dispatch [:load-more-messages])
:enableEmptySections true
:keyboardShouldPersistTaps (if platform/android? :always :handled)}]))
(defview chat []
(letsubs [{:keys [chat-id group-chat input-text]} [:get-current-chat]

View File

@ -1,40 +1,33 @@
(ns status-im.chat.views.api.choose-contact
(:require-macros [status-im.utils.views :refer [defview]])
(:require [reagent.core :as r]
[re-frame.core :refer [dispatch subscribe]]
[status-im.ui.components.react :refer [view
text
list-view
list-item]]
(:require [re-frame.core :as re-frame]
[status-im.ui.components.contact.contact :refer [contact-view]]
[status-im.ui.components.renderers.renderers :as renderers]
[status-im.utils.listview :as lw]))
[status-im.ui.components.list.views :as list]
[status-im.ui.components.react :as react]))
(defn render-row [arg-index bot-db-key]
(fn [contact _ _]
(list-item
^{:key contact}
[contact-view {:contact contact
:on-press #(dispatch
(defn- render-contact [arg-index bot-db-key]
(fn [contact]
[contact-view {:contact contact
:on-press #(re-frame/dispatch
[:set-contact-as-command-argument {:arg-index arg-index
:bot-db-key bot-db-key
:contact contact}])}])))
:contact contact}])}]))
(defview choose-contact-view [{title :title
arg-index :index
bot-db-key :bot-db-key}]
[contacts [:contacts-filtered :people-in-current-chat]]
[view {:flex 1}
[text {:style {:font-size 14
:color "rgb(147, 155, 161)"
:padding-top 12
:padding-left 16
:padding-right 16
:padding-bottom 12}}
[react/view {:flex 1}
[react/text {:style {:font-size 14
:color "rgb(147, 155, 161)"
:padding-top 12
:padding-left 16
:padding-right 16
:padding-bottom 12}}
title]
[list-view {:dataSource (lw/to-datasource contacts)
:enableEmptySections true
:renderRow (render-row arg-index bot-db-key)
:bounces false
:keyboardShouldPersistTaps :always
:renderSeparator renderers/list-separator-renderer}]])
[list/flat-list {:data contacts
:render-fn (render-contact arg-index bot-db-key)
:enableEmptySections true
:keyboardShouldPersistTaps :always
:bounces false}]])

View File

@ -1,23 +1,15 @@
(ns status-im.chat.views.bottom-info
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch]]
[reagent.core :as r]
[status-im.ui.components.react :refer [view
animated-view
image
text
icon
touchable-highlight
list-view
list-item]]
[status-im.ui.components.chat-icon.screen :refer [chat-icon-view-menu-item]]
[status-im.chat.styles.screen :as st]
[status-im.i18n :refer [label label-pluralize message-status-label]]
(:require [re-frame.core :as re-frame]
[reagent.core :as reagent]
[clojure.string :as string]
[status-im.ui.components.react :as react]
[status-im.chat.styles.screen :as styles]
[status-im.i18n :as i18n]
[status-im.ui.components.animation :as anim]
[status-im.utils.utils :refer [truncate-str]]
[status-im.utils.identicon :refer [identicon]]
[status-im.utils.listview :as lw]
[clojure.string :as str]))
[status-im.ui.components.list.views :as list]
[status-im.utils.utils :as utils]
[status-im.utils.identicon :as identicon]))
(defn- container-animation-logic [{:keys [to-value val]}]
(fn [_]
@ -26,50 +18,50 @@
:friction 6
:tension 40}))))
(defn overlay [{:keys [on-click-outside]} items]
[view {:style st/bottom-info-overlay}
[touchable-highlight {:on-press on-click-outside
:style st/overlay-highlight}
[view nil]]
(defn- overlay [{:keys [on-click-outside]} items]
[react/view styles/bottom-info-overlay
[react/touchable-highlight {:on-press on-click-outside
:style styles/overlay-highlight}
[react/view nil]]
items])
(defn container [height & _]
(defn- container [height & _]
(let [anim-value (anim/create-value 1)
context {:to-value height
:val anim-value}
on-update (container-animation-logic context)]
(r/create-class
(reagent/create-class
{:component-did-update
on-update
:display-name "container"
:reagent-render
(fn [height & children]
[animated-view {:style (st/bottom-info-container height)}
(into [view] children)])})))
[react/animated-view {:style (styles/bottom-info-container height)}
(into [react/view] children)])})))
(defn message-status-row [{:keys [photo-path name]} {:keys [whisper-identity status]}]
[view st/bottom-info-row
[image {:source {:uri (or photo-path (identicon whisper-identity))}
:style st/bottom-info-row-photo}]
[view st/bottom-info-row-text-container
[text {:style st/bottom-info-row-text1
:number-of-lines 1}
(truncate-str (if-not (str/blank? name)
name
whisper-identity) 30)]
[text {:style st/bottom-info-row-text2
:number-of-lines 1}
(message-status-label (or status :sending))]]])
(defn- message-status-row [{:keys [photo-path name]} {:keys [whisper-identity status]}]
[react/view styles/bottom-info-row
[react/image {:source {:uri (or photo-path (identicon/identicon whisper-identity))}
:style styles/bottom-info-row-photo}]
[react/view styles/bottom-info-row-text-container
[react/text {:style styles/bottom-info-row-text1
:number-of-lines 1}
(utils/truncate-str (if-not (string/blank? name)
name
whisper-identity) 30)]
[react/text {:style styles/bottom-info-row-text2
:number-of-lines 1}
(i18n/message-status-label (or status :sending))]]])
(defn render-row [contacts]
(defn- render-status [contacts]
(fn [{:keys [whisper-identity] :as row} _ _]
(let [contact (get contacts whisper-identity)]
(list-item [message-status-row contact row]))))
[message-status-row contact row])))
(defn bottom-info-view []
(let [bottom-info (subscribe [:get-current-chat-ui-prop :bottom-info])
contacts (subscribe [:get-contacts])]
(r/create-class
(let [bottom-info (re-frame/subscribe [:get-current-chat-ui-prop :bottom-info])
contacts (re-frame/subscribe [:get-contacts])]
(reagent/create-class
{:display-name "bottom-info-view"
:reagent-render
(fn []
@ -80,9 +72,9 @@
:status message-status}]))
(into {}))
statuses (vals (merge participants user-statuses))]
[overlay {:on-click-outside #(dispatch [:set-chat-ui-props {:show-bottom-info? false}])}
[container (* st/item-height (count statuses))
[list-view {:dataSource (lw/to-datasource statuses)
:enableEmptySections true
:renderRow (render-row @contacts)
:contentContainerStyle st/bottom-info-list-container}]]]))})))
[overlay {:on-click-outside #(re-frame/dispatch [:set-chat-ui-props {:show-bottom-info? false}])}
[container (* styles/item-height (count statuses))
[list/flat-list {:contentContainerStyle styles/bottom-info-list-container
:data statuses
:render-fn (render-status @contacts)
:enableEmptySections true}]]]))})))

View File

@ -1,20 +1,19 @@
(ns status-im.chat.views.input.validation-messages
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [re-frame.core :as re-frame]
[status-im.ui.components.react :as c]
[status-im.ui.components.react :as react]
[status-im.chat.styles.input.validation-message :as style]
[status-im.utils.listview :as lw]
[status-im.i18n :as i18n]))
(defn validation-message [{:keys [title description]}]
[c/view style/message-container
[c/text {:style style/message-title}
[react/view style/message-container
[react/text {:style style/message-title}
title]
[c/text {:style style/message-description}
[react/text {:style style/message-description}
description]])
(defn messages-list [markup]
[c/view {:flex 1}
(defn- messages-list [markup]
[react/view {:flex 1}
markup])
(defview validation-messages-view []
@ -22,7 +21,7 @@
input-height [:get-current-chat-ui-prop :input-height]
messages [:validation-messages]]
(when messages
[c/view (style/root (+ input-height chat-input-margin))
[react/view (style/root (+ input-height chat-input-margin))
(if (string? messages)
[messages-list [validation-message {:title (i18n/label :t/error)
:description messages}]]

View File

@ -1,30 +1,19 @@
(ns status-im.ui.components.drawer.view
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [cljs.spec.alpha :as s]
[clojure.string :as str]
[reagent.core :as r]
[re-frame.core :as rf]
(:require [clojure.string :as string]
[reagent.core :as reagent]
[re-frame.core :as re-frame]
[status-im.ui.components.chat-icon.screen :as ci]
[status-im.ui.components.common.common :as common]
[status-im.ui.components.context-menu :as context-menu]
[status-im.ui.components.drawer.styles :as st]
[status-im.ui.components.react :refer [view
text
text-input
list-item
list-view
drawer-layout
touchable-without-feedback
touchable-highlight
touchable-opacity
dismiss-keyboard!]]
[status-im.ui.components.react :as react]
[status-im.ui.components.icons.vector-icons :as vi]
[status-im.ui.components.status-view.view :as status-view]
[status-im.i18n :as i18n]
[status-im.ui.screens.profile.db :as profile.db]
[status-im.utils.datetime :as time]
[status-im.utils.gfycat.core :as gfycat]
[status-im.utils.listview :as lw]
[status-im.utils.platform :as platform]
[status-im.utils.utils :as utils]
[status-im.utils.money :as money]
@ -39,26 +28,26 @@
;; editing the name or status field
(defn save-profile! []
(when-let [save-event @(rf/subscribe [:my-profile.drawer/save-event])]
(rf/dispatch [save-event])))
(when-let [save-event @(re-frame/subscribe [:my-profile.drawer/save-event])]
(re-frame/dispatch [save-event])))
(defn navigate-to-profile []
(close-drawer!)
(save-profile!)
(rf/dispatch [:navigate-to :my-profile]))
(re-frame/dispatch [:navigate-to :my-profile]))
(defn navigate-to-accounts []
(close-drawer!)
(save-profile!)
;; TODO(rasom): probably not the best place for this call
(protocol/stop-whisper!)
(rf/dispatch [:navigate-to :accounts]))
(re-frame/dispatch [:navigate-to :accounts]))
(defview profile-picture []
(letsubs [account [:get-current-account]]
[touchable-opacity {:on-press navigate-to-profile
:style st/user-photo-container}
[view
[react/touchable-opacity {:on-press navigate-to-profile
:style st/user-photo-container}
[react/view
[ci/chat-icon (:photo-path account) {:size 52
:accessibility-label :drawer-profile-icon}]]]))
@ -66,88 +55,79 @@
(letsubs [profile-name [:my-profile.drawer/get :name]
valid-name? [:my-profile.drawer/valid-name?]
placeholder [:get :my-profile/default-name]]
[view st/name-input-wrapper
[text-input
[react/view st/name-input-wrapper
[react/text-input
{:placeholder placeholder
:style (st/name-input-text valid-name?)
:font :medium
:default-value profile-name
:on-focus #(rf/dispatch [:my-profile.drawer/edit-name])
:on-change-text #(rf/dispatch [:my-profile.drawer/update-name %])
:on-end-editing #(rf/dispatch [:my-profile.drawer/save-name])}]]))
:default-value profile-name
:on-focus #(re-frame/dispatch [:my-profile.drawer/edit-name])
:on-change-text #(re-frame/dispatch [:my-profile.drawer/update-name %])
:on-end-editing #(re-frame/dispatch [:my-profile.drawer/save-name])}]]))
(defview status-input []
(letsubs [edit-status? [:my-profile.drawer/get :edit-status?]
status [:my-profile.drawer/get :status]]
(let [placeholder (i18n/label :t/update-status)]
[view st/status-container
[react/view st/status-container
(if edit-status?
[text-input {:style st/status-input-view
:multiline true
:auto-focus true
:focus edit-status?
:max-length 140
:accessibility-label :drawer-status-input
:placeholder placeholder
:default-value status
:on-change-text #(rf/dispatch [:my-profile.drawer/update-status %])
:on-end-editing #(when edit-status?
(rf/dispatch [:my-profile.drawer/save-status]))}]
[status-view/status-view {:style (st/status-view (str/blank? status))
[react/text-input {:style st/status-input-view
:multiline true
:auto-focus true
:focus edit-status?
:max-length 140
:accessibility-label :drawer-status-input
:placeholder placeholder
:default-value status
:on-change-text #(re-frame/dispatch [:my-profile.drawer/update-status %])
:on-end-editing #(when edit-status?
(re-frame/dispatch [:my-profile.drawer/save-status]))}]
[status-view/status-view {:style (st/status-view (string/blank? status))
:number-of-lines 3
:status (if (str/blank? status)
:status (if (string/blank? status)
placeholder
status)
:on-press #(rf/dispatch [:my-profile.drawer/edit-status])}])])))
(defn render-separator-fn [transactions-count]
(fn [_ row-id _]
(when (< row-id (dec transactions-count))
(list-item
^{:key row-id}
[common/separator {} st/transactions-list-separator]))))
:on-press #(re-frame/dispatch [:my-profile.drawer/edit-status])}])])))
(defview current-network []
(letsubs [network [:get-current-account-network]]
[view {:style st/network-label-container}
[text {:style st/network-label} (i18n/label :t/current-network)]
[text {:style st/network-title} (:name network)]]))
[react/view {:style st/network-label-container}
[react/text {:style st/network-label} (i18n/label :t/current-network)]
[react/text {:style st/network-title} (:name network)]]))
(defn options-btn []
[view {:style st/options-button}
[touchable-highlight
{:on-press navigate-to-profile}
[view [vi/icon :icons/options]]]])
[react/view {:style st/options-button}
[react/touchable-highlight {:on-press navigate-to-profile}
[react/view [vi/icon :icons/options]]]])
(defn switch-account []
[view st/switch-account-container
[touchable-highlight
[react/view st/switch-account-container
[react/touchable-highlight
{:on-press navigate-to-accounts}
[view
[text {:style st/switch-account-text
:font (if platform/android? :medium :default)
:uppercase? platform/android?}
[react/view
[react/text {:style st/switch-account-text
:font (if platform/android? :medium :default)
:uppercase? platform/android?}
(i18n/label :t/switch-users)]]]])
(defn drawer []
(fn []
[touchable-without-feedback {:on-press #(dismiss-keyboard!)}
[view st/drawer
[view st/upper-container
[view st/profile-container
[react/touchable-without-feedback {:on-press #(react/dismiss-keyboard!)}
[react/view st/drawer
[react/view st/upper-container
[react/view st/profile-container
[profile-picture]
[name-input]
[status-input]
[options-btn]]
[current-network]]
[view
[react/view
[switch-account]]]]))
(defn drawer-view [items]
[drawer-layout {:drawerWidth 300
:renderNavigationView #(r/as-element [drawer])
:onDrawerSlide dismiss-keyboard!
:ref (fn [drawer]
(reset! drawer-atom drawer))}
[react/drawer-layout {:drawerWidth 300
:renderNavigationView #(reagent/as-element [drawer])
:onDrawerSlide react/dismiss-keyboard!
:ref (fn [drawer]
(reset! drawer-atom drawer))}
items])

View File

@ -1,8 +0,0 @@
(ns status-im.ui.components.invertible-scroll-view
(:require [reagent.core :as r]
[status-im.react-native.js-dependencies :as rn-dependencies]))
(defn invertible-scroll-view [props]
(r/create-element rn-dependencies/invertible-scroll-view
(clj->js (merge {:inverted true} props))))

View File

@ -62,6 +62,10 @@
base-separator
{:margin-left 70}))
(defstyle list-header-footer-spacing
{:android {:background-color styles/color-white
:height 8}})
(defstyle section-separator
(merge base-separator
{:android {:margin-top 12}

View File

@ -18,129 +18,147 @@
[section-list {:sections [{:title \"\" :key :unik :render-fn render :data {:title \"\" :subtitle \"\"}}]}]
"
(:require [reagent.core :as r]
[status-im.ui.components.list.styles :as lst]
(:require [reagent.core :as reagent]
[reagent.impl.template :as temp]
[status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.ui.components.checkbox.view :as checkbox]
[status-im.ui.components.react :as rn]
[status-im.ui.components.icons.vector-icons :as vi]
[status-im.utils.platform :as p]))
[status-im.ui.components.list.styles :as styles]
[status-im.ui.components.react :as react]
[status-im.utils.platform :as platform]))
(def flat-list-class (rn/get-class "FlatList"))
(def section-list-class (rn/get-class "SectionList"))
(def flat-list-class (react/get-class "FlatList"))
(def section-list-class (react/get-class "SectionList"))
(defn item
([content] (item nil content))
([left-action content] (item left-action content nil))
([left-action content right-action]
[rn/view {:style lst/item}
[rn/view {:style lst/left-item-wrapper}
[react/view {:style styles/item}
[react/view {:style styles/left-item-wrapper}
left-action]
[rn/view {:style lst/content-item-wrapper}
[react/view {:style styles/content-item-wrapper}
content]
(when right-action
[rn/view {:style lst/right-item-wrapper}
[react/view {:style styles/right-item-wrapper}
right-action])]))
(defn touchable-item [handler item]
[rn/touchable-highlight {:on-press handler}
[react/touchable-highlight {:on-press handler}
item])
(defn item-icon
[{:keys [icon style icon-opts]}]
[rn/view {:style style}
[vi/icon icon (merge icon-opts {:style lst/item-icon})]])
[react/view {:style style}
[vector-icons/icon icon (merge icon-opts {:style styles/item-icon})]])
(defn item-image
[{:keys [source style]}]
[rn/view {:style style}
[rn/image {:source source
:style lst/item-image}]])
[{:keys[source style]}]
[react/view {:style style}
[react/image {:source source
:style styles/item-image}]])
(defn item-primary
[primary]
[rn/text {:style lst/primary-text} primary])
[react/text {:style styles/primary-text} primary])
(defn item-primary-only
[primary]
[rn/text {:style lst/primary-text-only} primary])
[react/text {:style styles/primary-text-only} primary])
(defn item-secondary
[secondary]
[rn/text {:style lst/secondary-text :ellipsize-mode "middle" :number-of-lines 1} secondary])
[react/text {:style styles/secondary-text :ellipsize-mode :middle :number-of-lines 1} secondary])
(defn item-content
[& children]
(into [rn/view {:style lst/item-text-view}] (keep identity children)))
(into [react/view {:style styles/item-text-view}] (keep identity children)))
(defn item-checkbox
[{:keys [style] :as props}]
[rn/view {:style (merge style lst/item-checkbox)}
[react/view {:style (merge style styles/item-checkbox)}
[checkbox/checkbox props]])
(defn- wrap-render-fn [f]
(fn [data]
;; For details on passed data
;; https://facebook.github.io/react-native/docs/sectionlist.html#renderitem
(let [{:keys [item index separators]} (js->clj data :keywordize-keys true)]
(r/as-element (f (js->clj item) index separators)))))
(reagent/as-element (f (.-item data) (.-index data) (.-separators data)))))
(defn- separator []
[rn/view lst/separator])
(def default-separator [react/view styles/separator])
(defn- section-separator []
[rn/view lst/section-separator])
(def default-header [react/view styles/list-header-footer-spacing])
(defn- base-list-props [render-fn empty-component separator?]
(merge {:keyExtractor (fn [_ i] i)}
(when render-fn {:renderItem (wrap-render-fn render-fn)})
(when (and p/ios? separator?) {: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])})))
(def default-footer [react/view styles/list-header-footer-spacing])
(def section-separator [react/view styles/section-separator])
(defn- base-list-props
[{:keys [render-fn empty-component header separator default-separator?]}]
(let [separator (or separator (when (and platform/ios? default-separator?) default-separator))]
(merge {:keyExtractor (fn [_ i] i)}
(when render-fn {:renderItem (wrap-render-fn render-fn)})
(when separator {:ItemSeparatorComponent (fn [] (reagent/as-element [separator]))})
(when empty-component {:ListEmptyComponent (fn [] (reagent/as-element empty-component))})
(when header {:ListHeaderComponent (fn [] (reagent/as-element header))}))))
;; Workaround an issue in reagent that does not consider JS array as JS value
;; This forces clj <-> js serialization and breaks clj semantic
;; See https://github.com/reagent-project/reagent/issues/335
(deftype Item [value]
IEncodeJS
(-clj->js [x] (.-value x))
(-key->js [x] (.-value x))
IEncodeClojure
(-js->clj [x options] (.-value x)))
(defn- to-js-array
"Converts a collection to a JS array (but leave content as is)"
[coll]
(let [arr (array)]
(doseq [x coll]
(.push arr x))
arr))
(defn- wrap-data [o]
(Item. (to-js-array o)))
(defn flat-list
"A wrapper for FlatList.
See https://facebook.github.io/react-native/docs/flatlist.html"
[{:keys [data render-fn empty-component separator?] :as props
:or {separator? true}}]
[{:keys [data empty-component] :as props}]
{:pre [(or (nil? data)
(sequential? data))]}
(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 separator?)
{:data (clj->js data)}
props)]))
[flat-list-class
(merge (base-list-props props)
props
{:data (wrap-data data)})])
(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 [section]} (js->clj data :keywordize-keys true)]
(r/as-element (f section)))))
(reagent/as-element (f (.-section data)))))
(defn- default-render-section-header [{:keys [title data]}]
(when (seq data)
[rn/text {:style lst/section-header}
[react/text {:style styles/section-header}
title]))
(defn- wrap-per-section-render-fn [props]
;; TODO(jeluard) Somehow wrapping `:render-fn` does not work
(if-let [f (:render-fn props)]
(assoc (dissoc props :render-fn) :renderItem (wrap-render-fn f))
props))
(update
(if-let [f (:render-fn props)]
(assoc (dissoc props :render-fn) :renderItem (wrap-render-fn f))
props)
:data wrap-data))
(defn section-list
"A wrapper for SectionList.
See https://facebook.github.io/react-native/docs/sectionlist.html"
[{:keys [sections render-fn empty-component render-section-header-fn separator?] :as props
:or {render-section-header-fn default-render-section-header
separator? true}}]
[{:keys [sections empty-component render-section-header-fn] :as props
:or {render-section-header-fn default-render-section-header}}]
(if (and (every? #(empty? (:data %)) sections) empty-component)
empty-component
[section-list-class
(merge (base-list-props render-fn empty-component separator?)
(merge (base-list-props props)
props
{:sections (clj->js (map wrap-per-section-render-fn sections))
:renderSectionHeader (wrap-render-section-header-fn render-section-header-fn)}
(when p/ios? {:SectionSeparatorComponent (fn [] (r/as-element [section-separator]))})
props)]))
(when platform/ios? {:SectionSeparatorComponent (fn [] (reagent/as-element [section-separator]))}))]))

View File

@ -1,6 +1,7 @@
(ns status-im.ui.components.react
(:require-macros [status-im.utils.views :as views])
(:require [reagent.core :as r]
(:require [clojure.string :as string]
[reagent.core :as r]
[status-im.ui.components.styles :as st]
[status-im.utils.utils :as u]
[status-im.utils.platform :refer [platform-specific ios?]]
@ -40,7 +41,6 @@
(def status-bar (get-class "StatusBar"))
(def drawer-layout (adapt-class (.-default drawer)))
(def list-view-class (get-class "ListView"))
(def scroll-view (get-class "ScrollView"))
(def web-view (get-class "WebView"))
(def keyboard-avoiding-view-class (get-class "KeyboardAvoidingView"))
@ -82,7 +82,7 @@
([{:keys [uppercase?] :as opts} t & ts]
(r/as-element
(let [ts (cond->> (conj ts t)
uppercase? (map clojure.string/upper-case))]
uppercase? (map #(when % (string/upper-case %))))]
(vec (concat
[text-class (add-font-style :style opts)]
ts))))))
@ -106,11 +106,6 @@
:resizeMode "contain"
:style style}]))
;; TODO Migrate to new FlatList and SectionList when appropriate (see components.list). ListView will eventually get deprecated
;; see https://facebook.github.io/react-native/docs/using-a-listview.html
(defn list-view [props]
[list-view-class (merge {:enableEmptySections true} props)])
(defn touchable-highlight [props content]
[touchable-highlight-class
(merge {:underlay-color :transparent} props)

View File

@ -1,14 +0,0 @@
(ns status-im.ui.components.renderers.renderers
(:require [status-im.ui.components.react :refer [list-item]]
[status-im.ui.components.common.common :as common]))
(defn list-separator-renderer [_ row-id _]
(list-item
^{:key row-id}
[common/list-separator]))
(defn list-header-renderer [& _]
(list-item [common/list-header]))
(defn list-footer-renderer [& _]
(list-item [common/list-footer]))

View File

@ -1,60 +1,56 @@
(ns status-im.ui.screens.accounts.views
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [dispatch dispatch-sync]]
[status-im.ui.screens.accounts.styles :as st]
[status-im.ui.components.status-bar.view :refer [status-bar]]
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.ui.screens.accounts.styles :as styles]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.status-bar.view :as status-bar]
[status-im.ui.components.toolbar.actions :as act]
[status-im.ui.components.common.common :as common]
[status-im.ui.components.action-button.action-button :refer [action-button]]
[status-im.utils.listview :as lw]
[status-im.constants :refer [console-chat-id]]
[status-im.ui.components.react :refer [view
text
list-view
list-item
image
touchable-highlight]]
[status-im.i18n :as i18n]
[clojure.string :as str]))
[status-im.ui.components.react :as react]
[status-im.i18n :as i18n]))
(defn account-badge [address photo-path name]
[view st/account-badge
[image {:source {:uri (if (str/blank? photo-path) :avatar photo-path)}
:style st/photo-image}]
[view st/account-badge-text-view
[text {:style st/account-badge-text
:numberOfLines 1}
[react/view styles/account-badge
[react/image {:source {:uri (if (string/blank? photo-path) :avatar photo-path)}
:style styles/photo-image}]
[react/view styles/account-badge-text-view
[react/text {:style styles/account-badge-text
:numberOfLines 1}
(or name address)]]])
(defn account-view [{:keys [address photo-path name] :as account}]
[view
[touchable-highlight {:on-press #(dispatch [:open-login address photo-path name])}
[view st/account-view
[react/view
[react/touchable-highlight {:on-press #(re-frame/dispatch [:open-login address photo-path name])}
[react/view styles/account-view
[account-badge address photo-path name]]]])
(defview accounts []
[accounts [:get-accounts]]
[view st/accounts-container
[status-bar {:type :transparent}]
[view st/account-title-conatiner
[text {:style st/account-title-text
:font :toolbar-title}
[react/view styles/accounts-container
[status-bar/status-bar {:type :transparent}]
[react/view styles/account-title-conatiner
[react/text {:style styles/account-title-text
:font :toolbar-title}
(i18n/label :t/sign-in-to-status)]]
[view st/accounts-list-container
[list-view {:dataSource (lw/to-datasource (vals accounts))
:renderSeparator #(list-item ^{:key %2} [view {:height 10}])
:renderRow #(list-item [account-view %])}]]
[view st/bottom-actions-container
[react/view styles/accounts-list-container
[list/flat-list {:data (vals accounts)
:render-fn (fn [account] [account-view account])
:separator [react/view {:height 10}]}]]
[react/view styles/bottom-actions-container
[action-button (merge
{:label (i18n/label :t/create-new-account)
:icon :icons/add
:icon-opts {:color :white}
:on-press #(dispatch [:create-new-account-handler])}
st/accounts-action-button)]
[common/separator st/accounts-separator st/accounts-separator-wrapper]
:on-press #(re-frame/dispatch [:create-new-account-handler])}
styles/accounts-action-button)]
[common/separator styles/accounts-separator styles/accounts-separator-wrapper]
[action-button (merge
{:label (i18n/label :t/recover-access)
:icon :icons/dots-horizontal
:icon-opts {:color :white}
:on-press #(dispatch [:navigate-to :recover])}
st/accounts-action-button)]]])
:on-press #(re-frame/dispatch [:navigate-to :recover])}
styles/accounts-action-button)]]])

View File

@ -2,7 +2,7 @@
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [re-frame.core :as re-frame]
[status-im.ui.components.common.common :as common]
[status-im.ui.components.renderers.renderers :as renderers]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.react :as react]
[status-im.ui.components.native-action-button :refer [native-action-button]]
[status-im.ui.components.drawer.view :as drawer]
@ -15,7 +15,6 @@
[status-im.ui.components.sync-state.offline :refer [offline-view]]
[status-im.ui.components.context-menu :refer [context-menu]]
[status-im.ui.components.tabs.styles :refer [tabs-height]]
[status-im.utils.listview :refer [to-datasource]]
[status-im.ui.screens.chats-list.views.inner-item :as inner-item]
[status-im.ui.screens.chats-list.styles :as st]
[status-im.i18n :as i18n]
@ -84,18 +83,17 @@
edit? [toolbar-edit]
(= show-search :chat-list) [toolbar-search]
:else [toolbar-view])
[react/list-view {:dataSource (to-datasource chats)
:renderRow (fn [[id :as row] _ _]
(react/list-item ^{:key id} [chat-list-item row edit?]))
:renderHeader (when-not (empty? chats) renderers/list-header-renderer)
:renderFooter (when-not (empty? chats)
#(react/list-item [react/view
[common/list-footer]
[common/bottom-shadow]]))
:renderSeparator renderers/list-separator-renderer
:style st/list-container}]
[list/flat-list {:style st/list-container
:data chats
:render-fn (fn [chat] [chat-list-item chat edit?])
:header (when-not (empty? chats) list/default-header)
:footer (when-not (empty? chats)
[react/view
[common/list-footer]
[common/bottom-shadow]])}]
(when (and (not edit?)
(not= show-search :chat-list)
(not= show-search :chat-list)
(get-in platform-specific [:chats :action-button?]))
[chats-action-button])
[offline-view]]))

View File

@ -1,34 +1,32 @@
(ns status-im.ui.screens.contacts.contact-list.views
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [re-frame.core :refer [dispatch]]
[status-im.ui.components.renderers.renderers :as renderers]
[status-im.ui.components.contact.contact :refer [contact-view]]
[status-im.ui.screens.contacts.views :refer [contact-options]]
[status-im.ui.components.react :refer [view list-view list-item]]
[status-im.ui.components.status-bar.view :refer [status-bar]]
(:require [re-frame.core :as re-frame]
[status-im.ui.components.contact.contact :as contact-view]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.react :as react]
[status-im.ui.components.status-bar.view :as status-bar]
[status-im.ui.components.toolbar.view :as toolbar]
[status-im.ui.components.toolbar.actions :as act]
[status-im.ui.components.drawer.view :refer [drawer-view]]
[status-im.ui.screens.contacts.styles :as st]
[status-im.utils.listview :as lw]
[status-im.i18n :refer [label]]))
[status-im.ui.components.drawer.view :as drawer-view]
[status-im.ui.screens.contacts.styles :as styles]
[status-im.ui.screens.contacts.views :as contact-options]
[status-im.i18n :as i18n]))
(defn render-row [group edit?]
(fn [row _ _]
(list-item
^{:key row}
[contact-view {:contact row
:on-press #(dispatch [:open-chat-with-contact %])
:extended? edit?
:extend-options (contact-options row group)}])))
[contact-view/contact-view {:contact row
:on-press #(re-frame/dispatch [:open-chat-with-contact %])
:extended? edit?
:extend-options (contact-options/contact-options row group)}]))
(defview contact-list-toolbar-edit [group]
[toolbar/toolbar {}
[toolbar/nav-button (act/back #(dispatch [:set-in [:contacts/list-ui-props :edit?] false]))]
[toolbar/nav-button (act/back #(re-frame/dispatch [:set-in [:contacts/list-ui-props :edit?] false]))]
[toolbar/content-title
(if-not group
(label :t/contacts)
(or (:name group) (label :t/contacts-group-new-chat)))]])
(i18n/label :t/contacts)
(or (:name group) (i18n/label :t/contacts-group-new-chat)))]])
(defview contact-list-toolbar [group]
(letsubs [show-search [:get-in [:toolbar-search :show]]
@ -38,30 +36,29 @@
:search-text search-text
:search-key :contact-list
:title (if-not group
(label :t/contacts)
(or (:name group) (label :t/contacts-group-new-chat)))
:search-placeholder (label :t/search-contacts)
:actions [(act/opts [{:text (label :t/edit)
:value #(dispatch [:set-in [:contacts/list-ui-props :edit?] true])}])]})))
(i18n/label :t/contacts)
(or (:name group) (i18n/label :t/contacts-group-new-chat)))
:search-placeholder (i18n/label :t/search-contacts)
:actions [(act/opts [{:text (i18n/label :t/edit)
:value #(re-frame/dispatch [:set-in [:contacts/list-ui-props :edit?] true])}])]})))
(defview contacts-list-view [group edit?]
(letsubs [contacts [:all-added-group-contacts-filtered (:group-id group)]]
[list-view {:dataSource (lw/to-datasource contacts)
:enableEmptySections true
:renderRow (render-row group edit?)
:keyboardShouldPersistTaps :always
:renderHeader renderers/list-header-renderer
:renderFooter renderers/list-footer-renderer
:renderSeparator renderers/list-separator-renderer
:style st/contacts-list}]))
[list/flat-list {:style styles/contacts-list
:data contacts
:render-fn (render-row group edit?)
:enableEmptySections true
:keyboardShouldPersistTaps :always
:header list/default-header
:footer list/default-footer}]))
(defview contact-list []
(letsubs [edit? [:get-in [:contacts/list-ui-props :edit?]]
group [:get-contact-group]]
[drawer-view
[view {:flex 1}
[view
[status-bar]
[drawer-view/drawer-view
[react/view {:flex 1}
[react/view
[status-bar/status-bar]
(if edit?
[contact-list-toolbar-edit group]
[contact-list-toolbar group])]

View File

@ -2,18 +2,17 @@
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [re-frame.core :refer [dispatch]]
[status-im.ui.components.common.common :as common]
[status-im.ui.components.renderers.renderers :as renderers]
[status-im.ui.components.react :refer [view list-view list-item]]
[status-im.ui.components.contact.contact :refer [contact-view]]
[status-im.ui.components.action-button.action-button :refer [action-button
action-separator]]
[status-im.ui.components.action-button.styles :refer [actions-list]]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.react :as react]
[status-im.ui.components.status-bar.view :refer [status-bar]]
[status-im.ui.components.toolbar.view :refer [toolbar-with-search]]
[status-im.ui.components.drawer.view :refer [drawer-view]]
[status-im.ui.screens.contacts.styles :as st]
[status-im.utils.listview :as lw]
[status-im.i18n :refer [label]]))
[status-im.i18n :as i18n]))
(defview contact-list-modal-toolbar []
(letsubs [show-search [:get-in [:toolbar-search :show]]
@ -23,13 +22,13 @@
:show-search? (= show-search :contact-list)
:search-text search-text
:search-key :contact-list
:title (label :t/contacts)
:search-placeholder (label :t/search-contacts)})))
:title (i18n/label :t/contacts)
:search-placeholder (i18n/label :t/search-contacts)})))
(defn actions-view [action click-handler]
[view actions-list
[react/view actions-list
[action-button
{:label (label :t/enter-address)
{:label (i18n/label :t/enter-address)
:icon :icons/address
:icon-opts {:color :blue}
:on-press #(do
@ -38,22 +37,21 @@
(dispatch [:navigate-back]))}]
[action-separator]
(if (= :request action)
[action-button {:label (label :t/show-qr)
[action-button {:label (i18n/label :t/show-qr)
:icon :icons/qr
:icon-opts {:color :blue}
:on-press #(click-handler :qr-scan action)}]
[action-button {:label (label :t/scan-qr)
[action-button {:label (i18n/label :t/scan-qr)
:icon :icons/fullscreen
:icon-opts {:color :blue}
:on-press #(click-handler :qr-scan action)}])])
(defn render-row [click-handler action params]
(fn [row _ _]
(list-item
^{:key row}
[contact-view {:contact row
:on-press #(when click-handler
(click-handler row action params))}])))
[contact-view {:contact row
:on-press #(when click-handler
(click-handler row action params))}]))
(defview contact-list-modal []
(letsubs [contacts [:contacts-filtered :all-added-people-contacts]
@ -61,24 +59,22 @@
action [:get :contacts/click-action]
params [:get :contacts/click-params]]
[drawer-view
[view {:flex 1}
[react/view {:flex 1}
[status-bar {:type :modal-white}]
[contact-list-modal-toolbar]
[list-view {:dataSource (lw/to-datasource contacts)
:enableEmptySections true
:renderRow (render-row click-handler action params)
:bounces false
:keyboardShouldPersistTaps :always
:renderHeader (when-not (:hide-actions? params)
#(list-item
[view
[actions-view action click-handler]
[common/bottom-shadow]
[common/form-title (label :t/choose-from-contacts)
{:count-value (count contacts)}]
[common/list-header]]))
:renderFooter #(list-item [view
[common/list-footer]
[common/bottom-shadow]])
:renderSeparator renderers/list-separator-renderer
:style st/contacts-list-modal}]]]))
[list/flat-list {:style st/contacts-list-modal
:data contacts
:render-fn (render-row click-handler action params)
:header (when-not (:hide-actions? params)
[react/view
[actions-view action click-handler]
[common/bottom-shadow]
[common/form-title (i18n/label :t/choose-from-contacts)
{:count-value (count contacts)}]
[common/list-header]])
:footer [react/view
[common/list-footer]
[common/bottom-shadow]]
:enableEmptySections true
:bounces false
:keyboardShouldPersistTaps :always}]]]))

View File

@ -40,7 +40,7 @@
[list/flat-list {:data (vals dapps)
:render-fn render-dapp
:horizontal true
:separator? false
:default-separator? false
:shows-horizontal-scroll-indicator false
:content-container-style styles/dapp-preview-flat-list}]
[react/text (i18n/label :t/none)])])

View File

@ -22,7 +22,7 @@
:render-fn render-tag
:horizontal true
:shows-horizontal-scroll-indicator false
:separator? false}]])
:default-separator? false}]])
(defview discover-all-hashtags []
(letsubs [current-account [:get-current-account]

View File

@ -2,11 +2,11 @@
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [status-im.ui.components.react :as react]
[status-im.ui.components.icons.vector-icons :as vi]
[status-im.ui.components.toolbar.view :as toolbar]
[status-im.ui.screens.discover.components.views :as components]
[status-im.i18n :as i18n]
[status-im.ui.screens.discover.styles :as styles]
[status-im.ui.screens.contacts.styles :as contacts-styles]
[status-im.ui.components.toolbar.view :as toolbar]))
[status-im.ui.screens.contacts.styles :as contacts-styles]))
;; TOOD(oskarth): Refactor this, very similar to discover-all-hashtags view
(defview discover-search-results []

View File

@ -1,24 +1,26 @@
(ns status-im.ui.screens.group.add-contacts.views
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [re-frame.core :refer [dispatch]]
[status-im.ui.components.renderers.renderers :as renderers]
(:require [re-frame.core :as re-frame]
[status-im.ui.components.contact.contact :refer [toogle-contact-view]]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.react :as react]
[status-im.ui.components.sticky-button :refer [sticky-button]]
[status-im.ui.components.status-bar.view :refer [status-bar]]
[status-im.ui.components.toolbar.view :refer [toolbar-with-search]]
[status-im.utils.listview :refer [to-datasource]]
[status-im.ui.screens.group.styles :as styles]
[status-im.ui.screens.contacts.styles :as contacts.styles]
[status-im.i18n :as i18n]
[status-im.ui.screens.contacts.styles :as cstyles]
[status-im.i18n :refer [label]]
[status-im.ui.components.contact.contact :refer [toogle-contact-view]]))
(defn on-toggle [checked? whisper-identity]
(let [action (if checked? :deselect-contact :select-contact)]
(dispatch [action whisper-identity])))
(re-frame/dispatch [action whisper-identity])))
(defn on-toggle-participant [checked? whisper-identity]
(let [action (if checked? :deselect-participant :select-participant)]
(dispatch [action whisper-identity])))
(re-frame/dispatch [action whisper-identity])))
(defn group-toggle-contact [{:keys [whisper-identity] :as contact}]
[toogle-contact-view contact :is-contact-selected? on-toggle])
@ -45,19 +47,16 @@
:search-text search-text
:search-key :contact-group-list
:custom-title (title-with-count title contacts-count)
:search-placeholder (label :t/search-contacts)})))
:search-placeholder (i18n/label :t/search-contacts)})))
(defn toggle-list [contacts render-function]
[react/view {:flex 1}
[react/list-view
{:dataSource (to-datasource contacts)
:renderRow (fn [row _ _]
(react/list-item ^{:key row} [render-function row]))
:renderSeparator renderers/list-separator-renderer
:renderFooter renderers/list-footer-renderer
:renderHeader renderers/list-header-renderer
:style cstyles/contacts-list
:keyboardShouldPersistTaps :always}]])
[list/flat-list {:style contacts.styles/contacts-list
:data contacts
:render-fn (fn [contact] [render-function contact])
:footer list/default-footer
:header list/default-header
:keyboardShouldPersistTaps :always}]])
(defview contact-toggle-list []
(letsubs [contacts [:all-added-group-contacts-filtered]
@ -66,13 +65,13 @@
[react/keyboard-avoiding-view {:style styles/group-container}
[status-bar]
[toggle-list-toolbar
(label (if (= group-type :contact-group)
:t/new-group
:t/new-group-chat))
(i18n/label (if (= group-type :contact-group)
:t/new-group
:t/new-group-chat))
selected-contacts-count]
[toggle-list contacts group-toggle-contact]
(when (pos? selected-contacts-count)
[sticky-button (label :t/next) #(dispatch [:navigate-to :new-group])])]))
[sticky-button (i18n/label :t/next) #(re-frame/dispatch [:navigate-to :new-group])])]))
(defview add-contacts-toggle-list []
(letsubs [contacts [:all-group-not-added-contacts-filtered]
@ -83,9 +82,9 @@
[toggle-list-toolbar (:name group) selected-contacts-count]
[toggle-list contacts group-toggle-contact]
(when (pos? selected-contacts-count)
[sticky-button (label :t/save) #(do
(dispatch [:add-selected-contacts-to-group])
(dispatch [:navigate-back]))])]))
[sticky-button (i18n/label :t/save) #(do
(re-frame/dispatch [:add-selected-contacts-to-group])
(re-frame/dispatch [:navigate-back]))])]))
(defview add-participants-toggle-list []
(letsubs [contacts [:contacts-filtered :all-new-contacts]
@ -96,6 +95,6 @@
[toggle-list-toolbar chat-name selected-contacts-count]
[toggle-list contacts group-toggle-participant]
(when (pos? selected-contacts-count)
[sticky-button (label :t/save) #(do
(dispatch [:add-new-group-chat-participants])
(dispatch [:navigate-back]))])]))
[sticky-button (i18n/label :t/save) #(do
(re-frame/dispatch [:add-new-group-chat-participants])
(re-frame/dispatch [:navigate-back]))])]))

View File

@ -1,14 +1,13 @@
(ns status-im.ui.screens.group.edit-contacts.views
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [re-frame.core :refer [dispatch]]
(:require [re-frame.core :as re-frame]
[status-im.ui.components.contact.contact :refer [contact-view]]
[status-im.ui.components.renderers.renderers :as renderers]
[status-im.ui.components.react :refer [view list-view list-item]]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.react :as react]
[status-im.ui.components.status-bar.view :refer [status-bar]]
[status-im.ui.components.toolbar.view :refer [toolbar-with-search]]
[status-im.utils.listview :refer [to-datasource]]
[status-im.ui.screens.group.styles :as styles]
[status-im.i18n :refer [label]]))
[status-im.i18n :as i18n]))
(defview contact-list-toolbar [title]
(letsubs [show-search [:get-in [:toolbar-search :show]]
@ -18,35 +17,33 @@
:search-text search-text
:search-key :contact-list
:title title
:search-placeholder (label :t/search-contacts)})))
:search-placeholder (i18n/label :t/search-contacts)})))
(defn contacts-list [contacts extended? extend-options]
[view {:flex 1}
[list-view {:dataSource (to-datasource contacts)
:enableEmptySections true
:renderRow (fn [row _ _]
(list-item
^{:key row}
[contact-view {:contact row
:extended? extended?
:extend-options (extend-options row)}]))
:bounces false
:keyboardShouldPersistTaps :always
:renderSeparator renderers/list-separator-renderer
:renderFooter renderers/list-footer-renderer
:renderHeader renderers/list-header-renderer}]])
[react/view {:flex 1}
[list/flat-list {:data contacts
:enableEmptySections true
:renderRow (fn [contact]
[contact-view {:contact contact
:extended? extended?
:extend-options (extend-options contact)}])
:bounces false
:keyboardShouldPersistTaps :always
:footer list/default-footer
:header list/default-header}]])
(defn chat-extended-options [item]
[{:value #(dispatch [:remove-group-chat-participants #{(:whisper-identity item)}])
:text (label :t/remove)}])
[{:value #(re-frame/dispatch [:remove-group-chat-participants #{(:whisper-identity item)}])
:text (i18n/label :t/remove)}])
(defn contact-extended-options [group-id]
(fn [item]
[{:value #(dispatch [:remove-contact-from-group
(:whisper-identity item)
group-id])
[{:value #(re-frame/dispatch [:remove-contact-from-group
(:whisper-identity item)
group-id])
:accessibility-label :remove-button
:text (label :t/remove-from-group)}]))
:text (i18n/label :t/remove-from-group)}]))
(defview edit-chat-group-contact-list []
(letsubs [chat-name [:chat :name]
@ -54,7 +51,7 @@
current-pk [:get :current-public-key]
group-admin [:chat :group-admin]]
(let [admin? (= current-pk group-admin)]
[view styles/group-container
[react/view styles/group-container
[status-bar]
[contact-list-toolbar chat-name]
[contacts-list
@ -71,7 +68,7 @@
(defview edit-contact-group-contact-list []
(letsubs [group [:get-contact-group]]
[view styles/group-container
[react/view styles/group-container
[status-bar]
[contact-list-toolbar (:name group)]
[contacts-list-view (:group-id group)]]))

View File

@ -5,15 +5,14 @@
[status-im.ui.components.common.common :as common]
[status-im.ui.components.action-button.action-button :refer [action-button action-separator]]
[status-im.ui.components.react :refer [view text touchable-highlight
keyboard-avoiding-view list-view list-item]]
keyboard-avoiding-view]]
[status-im.ui.components.icons.vector-icons :as vi]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.text-input-with-label.view :refer [text-input-with-label]]
[status-im.ui.components.status-bar.view :refer [status-bar]]
[status-im.ui.components.toolbar.view :as toolbar]
[status-im.utils.platform :refer [platform-specific ios?]]
[status-im.ui.components.sticky-button :refer [sticky-button]]
[status-im.utils.listview :refer [to-datasource]]
[status-im.ui.components.renderers.renderers :as renderers]
[status-im.ui.components.contact.contact :refer [contact-view]]
[status-im.ui.screens.group.styles :as styles]
[status-im.i18n :refer [label]]
@ -139,10 +138,9 @@
(when save-btn-enabled?
[sticky-button (label :t/save) #(dispatch [:set-contact-group-name])])])))
(defn render-row [row _ _]
(list-item
^{:key row}
[contact-view {:contact row}]))
(defn- render-contact [contact]
[contact-view {:contact contact}])
(defview new-group []
(letsubs [contacts [:selected-group-contacts]
@ -154,12 +152,11 @@
[group-toolbar group-type false]
[group-name-view]
[view styles/list-view-container
[list-view {:dataSource (to-datasource contacts)
:enableEmptySections true
:renderRow render-row
:bounces false
:keyboardShouldPersistTaps :always
:renderSeparator renderers/list-separator-renderer}]]
[list/flat-list {:data contacts
:render-fn render-contact
:bounces false
:keyboardShouldPersistTaps :always
:enableEmptySections true}]]
(when save-btn-enabled?
[sticky-button (label :t/save)
(if (= group-type :contact-group)

View File

@ -1,31 +1,29 @@
(ns status-im.ui.screens.network-settings.views
(:require-macros [status-im.utils.views :as views])
(:require
[status-im.utils.listview :as lw]
[re-frame.core :as rf]
[status-im.ui.components.status-bar.view :as status-bar]
[status-im.ui.components.toolbar.view :as toolbar]
[status-im.ui.components.action-button.action-button :as action-button]
[status-im.ui.components.action-button.styles :as action-button-styles]
[status-im.ui.components.react :as react]
[status-im.ui.components.icons.vector-icons :as vi]
[status-im.ui.components.common.common :as common]
[status-im.ui.components.renderers.renderers :as renderers]
[status-im.ui.screens.network-settings.styles :as st]
[status-im.i18n :as i18n]))
(:require [re-frame.core :as re-frame]
[status-im.ui.components.action-button.action-button :as action-button]
[status-im.ui.components.action-button.styles :as action-button-styles]
[status-im.ui.components.react :as react]
[status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.ui.components.list.views :as list]
[status-im.ui.components.common.common :as common]
[status-im.ui.screens.network-settings.styles :as styles]
[status-im.ui.components.status-bar.view :as status-bar]
[status-im.ui.components.toolbar.view :as toolbar]
[status-im.i18n :as i18n]))
(defn network-icon [connected? size]
[react/view (st/network-icon connected? size)
[vi/icon :icons/network {:color (if connected? :white :gray)}]])
[react/view (styles/network-icon connected? size)
[vector-icons/icon :icons/network {:color (if connected? :white :gray)}]])
(defn network-badge [& [{:keys [name connected? options]}]]
[react/view st/network-badge
[react/view styles/network-badge
[network-icon connected? 56]
[react/view {:padding-left 16}
[react/text {:style st/badge-name-text}
[react/text {:style styles/badge-name-text}
(or name (i18n/label :t/new-network))]
(when connected?
[react/text {:style st/badge-connected-text}
[react/text {:style styles/badge-connected-text}
(i18n/label :t/connected)])]])
(defn actions-view []
@ -43,21 +41,19 @@
{:text (i18n/label :t/paste-json-as-text) :value #(dispatch [:navigate-to :paste-json-text])}
{:text (i18n/label :t/specify-rpc-url) :value #(dispatch [:navigate-to :add-rpc-url])}]]])
(defn render-row [current-network]
(fn [{:keys [id name config] :as row} _ _]
(defn render-network [current-network]
(fn [{:keys [id name config] :as network}]
(let [connected? (= id current-network)]
(react/list-item
^{:key row}
[react/touchable-highlight
{:on-press #(rf/dispatch [:navigate-to :network-details row])}
[react/view st/network-item
[network-icon connected? 40]
[react/view {:padding-horizontal 16}
[react/text {:style st/network-item-name-text}
name]
(when connected?
[react/text {:style st/network-item-connected-text}
(i18n/label :t/connected)])]]]))))
[react/touchable-highlight
{:on-press #(re-frame/dispatch [:navigate-to :network-details network])}
[react/view styles/network-item
[network-icon connected? 40]
[react/view {:padding-horizontal 16}
[react/text {:style styles/network-item-name-text}
name]
(when connected?
[react/text {:style styles/network-item-connected-text}
(i18n/label :t/connected)])]]])))
(views/defview network-settings []
(views/letsubs [{:keys [network networks]} [:get-current-account]]
@ -66,17 +62,15 @@
[toolbar/simple-toolbar
(i18n/label :t/network-settings)]
[react/view {:flex 1}
[react/list-view {:dataSource (lw/to-datasource (vals networks))
:renderRow (render-row network)
:renderHeader #(react/list-item
[react/view
[actions-view]
[common/bottom-shadow]
[common/form-title (i18n/label :t/existing-networks)
{:count-value (count networks)}]
[common/list-header]])
:renderFooter #(react/list-item [react/view
[common/list-footer]
[common/bottom-shadow]])
:renderSeparator renderers/list-separator-renderer
:style st/networks-list}]]]))
[list/flat-list {:style styles/networks-list
:data (vals networks)
:render-fn (render-network network)
:header [react/view
[actions-view
[common/bottom-shadow]
[common/form-title (i18n/label :t/existing-networks)
{:count-value (count networks)}]
[common/list-header]]]
:footer [react/view
[common/list-footer]
[common/bottom-shadow]]}]]]))

View File

@ -101,7 +101,7 @@
[react/text {:style styles/asset-item-currency
:uppercase? true
:number-of-lines 1}
symbol]]
(clojure.core/name symbol)]]
[list/item-icon {:icon :icons/forward}]]]]
[add-asset]))

View File

@ -146,17 +146,16 @@
[list/item-primary label]
[list/item-secondary symbol]]])
(defn- item-filter-type [{:keys [id label checked?]}]
(let [kid (keyword id)]
[item-filter {:icon (transaction-type->icon kid) :checked? checked? :path {:type kid}}
[list/item-content
[list/item-primary-only label]]]))
(defn- render-item-filter [{:keys [id label checked?]}]
[item-filter {:icon (transaction-type->icon id) :checked? checked? :path {:type id}}
[list/item-content
[list/item-primary-only label]]])
(defn- wrap-filter-data [m]
;; TODO(jeluard) Restore tokens filtering once token support is added
[{:title (i18n/label :t/transactions-filter-type)
:key :type
:renderItem (list/wrap-render-fn item-filter-type)
:render-fn render-item-filter ;(list/wrap-render-fn item-filter-type)
:data (:type m)}])
(defview filter-history []

View File

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

View File

@ -16,7 +16,6 @@
(def image-crop-picker #js {})
(def image-resizer #js {})
(def instabug #js {})
(def invertible-scroll-view #js {})
(def linear-gradient #js {})
(def mapbox-gl #js {:setAccessToken (fn [])})
(def nfc #js {})