Signed-off-by: yenda <eric@status.im>
This commit is contained in:
tbenr 2019-09-19 19:12:58 +02:00 committed by yenda
parent da120feef8
commit f7076016d8
No known key found for this signature in database
GPG Key ID: 0095623C0069DCE6
22 changed files with 424 additions and 312 deletions

View File

@ -80,6 +80,9 @@
(def animated-view-class (def animated-view-class
(reagent/adapt-react-class (.-View animated))) (reagent/adapt-react-class (.-View animated)))
(def animated-flat-list-class
(reagent/adapt-react-class (.-FlatList animated)))
(defn animated-view [props & content] (defn animated-view [props & content]
(vec (conj content props animated-view-class))) (vec (conj content props animated-view-class)))

View File

@ -522,6 +522,7 @@ var TopLevel = {
"version" : function () {}, "version" : function () {},
"vibrate" : function () {}, "vibrate" : function () {},
"View" : function () {}, "View" : function () {},
"FlatList" : function () {},
"warn" : function () {}, "warn" : function () {},
"WebView" : function () {}, "WebView" : function () {},
"WebViewBridgeModule" : function () {}, "WebViewBridgeModule" : function () {},

View File

@ -15,6 +15,7 @@
(def react-native (def react-native
#js {:NativeModules #js {} #js {:NativeModules #js {}
:Animated #js {:View #js {} :Animated #js {:View #js {}
:FlatList #js {}
:Text #js {}} :Text #js {}}
:DeviceEventEmitter #js {:addListener (fn [])} :DeviceEventEmitter #js {:addListener (fn [])}
:Dimensions #js {:get (fn [])}}) :Dimensions #js {:get (fn [])}})

View File

Before

Width:  |  Height:  |  Size: 223 B

After

Width:  |  Height:  |  Size: 223 B

View File

Before

Width:  |  Height:  |  Size: 391 B

After

Width:  |  Height:  |  Size: 391 B

View File

Before

Width:  |  Height:  |  Size: 537 B

After

Width:  |  Height:  |  Size: 537 B

View File

@ -87,11 +87,3 @@
(update :contacts/blocked disj public-key) (update :contacts/blocked disj public-key)
(assoc-in [:contacts/contacts public-key] contact))} (assoc-in [:contacts/contacts public-key] contact))}
(contacts-store/save-contact contact)))) (contacts-store/save-contact contact))))
(fx/defn block-contact-confirmation
[cofx public-key]
{:utils/show-confirmation
{:title (i18n/label :t/block-contact)
:content (i18n/label :t/block-contact-details)
:confirm-button-text (i18n/label :t/to-block)
:on-accept #(re-frame/dispatch [:contact.ui/block-contact-confirmed public-key])}})

View File

@ -81,6 +81,17 @@
(send-contact-request contact) (send-contact-request contact)
(mailserver/process-next-messages-request))))) (mailserver/process-next-messages-request)))))
(fx/defn remove-contact
"Remove a contact from current account's contact list"
{:events [:contact.ui/remove-contact-pressed]}
[{:keys [db] :as cofx} {:keys [public-key] :as contact}]
(let [new-contact (update contact
:system-tags
(fnil #(disj % :contact/added) #{}))]
(fx/merge cofx
{:db (assoc-in db [:contacts/contacts public-key] new-contact)}
(contacts-store/save-contact new-contact))))
(fx/defn create-contact (fx/defn create-contact
"Create entry in contacts" "Create entry in contacts"
[{:keys [db] :as cofx} public-key] [{:keys [db] :as cofx} public-key]

View File

@ -1327,11 +1327,6 @@
(fn [cofx [_ public-key]] (fn [cofx [_ public-key]]
(contact/add-contact cofx public-key))) (contact/add-contact cofx public-key)))
(handlers/register-handler-fx
:contact.ui/block-contact-pressed
(fn [cofx [_ public-key]]
(contact.block/block-contact-confirmation cofx public-key)))
(handlers/register-handler-fx (handlers/register-handler-fx
:contact.ui/block-contact-confirmed :contact.ui/block-contact-confirmed
(fn [cofx [_ public-key]] (fn [cofx [_ public-key]]

View File

@ -42,8 +42,8 @@
(defn anim-delay [duration] (defn anim-delay [duration]
(.delay react/animated duration)) (.delay react/animated duration))
(defn event [config] (defn event [mapping config]
(.event react/animated (clj->js [nil, config]))) (.event react/animated (clj->js mapping) (clj->js config)))
(defn add-listener [anim-value listener] (defn add-listener [anim-value listener]
(.addListener anim-value listener)) (.addListener anim-value listener))
@ -60,6 +60,12 @@
(defn create-value [value] (defn create-value [value]
(js/ReactNative.Animated.Value. value)) (js/ReactNative.Animated.Value. value))
(defn add [anim-x anim-y]
(js/ReactNative.Animated.add. anim-x anim-y))
(defn subtract [anim-x anim-y]
(js/ReactNative.Animated.subtract. anim-x anim-y))
(defn x [value-xy] (defn x [value-xy]
(.-x value-xy)) (.-x value-xy))

View File

@ -1,151 +0,0 @@
(ns status-im.ui.components.large-toolbar
(:require-macros [status-im.utils.views :as views])
(:require [cljs-bean.core :refer [->clj ->js]]
[reagent.core :as reagent]
[status-im.ui.components.animation :as animation]
[status-im.ui.components.colors :as colors]
[status-im.ui.components.list.views :as list.views]
[status-im.ui.components.list-item.views :as list-item]
[status-im.ui.components.react :as react]
[status-im.ui.components.toolbar.styles :as toolbar.styles]
[status-im.ui.components.toolbar.view :as toolbar]
[status-im.utils.platform :as platform]))
(def hidden (reagent/atom 0))
(def shown (reagent/atom 100))
(def minimized-header-visible? (reagent/atom false))
(def initial-on-show-done? (volatile! false))
(defn animated-content-wrapper [header-in-toolbar has-nav? show?]
(let [anim-opacity (animation/create-value 0)
to-hide (reagent/atom false)]
(reagent/create-class
{:component-did-update
(fn [comp]
(let [new-argv (rest (reagent/argv comp))
show? (last new-argv)]
(cond
(and (not @to-hide) show?)
(animation/start
(animation/timing
anim-opacity
{:toValue 1
:duration 200
:easing (.-ease (animation/easing))
:useNativeDriver true})
#(reset! to-hide true))
(and @to-hide (not show?))
(animation/start
(animation/timing
anim-opacity
{:toValue 0
:duration 200
:easing (.-ease (animation/easing))
:useNativeDriver true})
#(reset! to-hide false)))))
:reagent-render
(fn [header-in-toolbar has-nav? _]
[react/animated-view
{:style (cond-> {:flex 1
:align-self :stretch
:opacity anim-opacity}
(false? has-nav?)
(assoc :margin-left -40 :margin-right 40))}
header-in-toolbar])})))
(defn on-viewable-items-changed [threshold interporlation-step]
(fn [info]
(let [changed (->> (->clj info)
:changed
(filter #(= 1 (:index %))))
viewable? (when (seq changed)
(->> changed
first
:isViewable))]
(when (and @initial-on-show-done? (not (nil? viewable?)))
(if (= threshold 0)
(if viewable?
(reset! minimized-header-visible? false)
(reset! minimized-header-visible? true))
(if viewable?
(do (swap! hidden - interporlation-step) (swap! shown + interporlation-step))
(do (swap! hidden + interporlation-step) (swap! shown - interporlation-step))))))))
(defonce viewability-config-callback-pairs
(let [interporlation-step 20]
(->js
(vec
(for [threshold (range 0 (+ 100 interporlation-step) interporlation-step)]
{:viewabilityConfig {:itemVisiblePercentThreshold threshold}
:onViewableItemsChanged (on-viewable-items-changed threshold interporlation-step)})))))
;; header-in-toolbar - component - small header in toolbar
;; nav-item - component/nil - if nav-item like back button is needed, else nil
;; action-items - status-im.ui.components.toolbar.view/actions
(defn minimized-toolbar [header-in-toolbar nav-item action-items]
(let [has-nav? (boolean nav-item)]
[toolbar/toolbar
{:transparent? true
:style {:z-index 100
:elevation 9}}
nav-item
[animated-content-wrapper header-in-toolbar has-nav? @minimized-header-visible?]
action-items]))
;; header - component that serves as large header without any top/bottom padding
;; top(4px high) and bottom(16px high and with border) padding
;; are assumed to be constant
;; this is wrapped with padding components and merged with content
;; content - vector - of the rest(from header) of the list components
;; wrapped header and content form the data prop of flat-list
;; list-ref - atom - a reference to flat-list for the purpose of invoking its
;; methods
(views/defview flat-list-with-large-header [header content list-ref]
(views/letsubs [window-width [:dimensions/window-width]]
{:component-did-mount #(do (reset! hidden 0) (reset! shown 100)
(reset! minimized-header-visible? false)
(vreset! initial-on-show-done? false))}
(let [header-top-padding [react/view {:height 4}]
;; header bottom padding with border-bottom
;; fades out as it approaches toolbar shadow
header-bottom [react/animated-view
{:style {:height 16
:opacity (/ @shown 100)
:border-bottom-width 1
:border-bottom-color colors/gray-lighter}}]
wrapped-data (into [header-top-padding header header-bottom] content)
status-bar-height (get platform/platform-specific :status-bar-default-height)
toolbar-shadow-component-height
(+ 50 toolbar.styles/toolbar-height (if (zero? status-bar-height) 50 status-bar-height))]
[react/view {:flex 1}
;; toolbar shadow
[react/animated-view
{:style
(cond-> {:flex 1
:align-self :stretch
:position :absolute
:height toolbar-shadow-component-height
:width window-width
:top (- toolbar-shadow-component-height)
:shadow-radius 8
:shadow-offset {:width 0 :height 2}
:shadow-opacity 1
:shadow-color "rgba(0, 9, 26, 0.12)"
:elevation (if (>= @hidden 40) (- (/ @hidden 10) 2) 0)
:background-color colors/white}
platform/ios?
(assoc :opacity (if (>= @hidden 40) (/ @hidden 100) 0)))}]
[list.views/flat-list
{:style {:z-index -1}
:data wrapped-data
:initial-num-to-render 3
:ref #(reset! list-ref %)
:render-fn list.views/flat-list-generic-render-fn
:key-fn (fn [item idx] (str idx))
:on-scroll-begin-drag #(when (false? @initial-on-show-done?)
(vreset! initial-on-show-done? true))
:viewabilityConfigCallbackPairs viewability-config-callback-pairs
:keyboard-should-persist-taps :handled}]])))

View File

@ -0,0 +1,84 @@
(ns status-im.ui.components.large-toolbar.styles
(:require [status-im.ui.components.colors :as colors]
[status-im.ui.components.animation :as animation]
[status-im.ui.components.toolbar.styles :as toolbar.styles]
[status-im.utils.platform :as platform]))
(defonce toolbar-shadow-component-height
(let [status-bar-height (get platform/platform-specific :status-bar-default-height)]
(+ 50 toolbar.styles/toolbar-height (if (zero? status-bar-height) 50 status-bar-height))))
(defonce toolbar-statusbar-height
(+ (get platform/platform-specific :status-bar-default-height) toolbar.styles/toolbar-height))
(defn minimized-toolbar-fade-in [anim-opacity]
(animation/timing
anim-opacity
{:toValue 1
:duration 200
:easing (.-ease (animation/easing))
:useNativeDriver true}))
(defn minimized-toolbar-fade-out [anim-opacity]
(animation/timing
anim-opacity
{:toValue 0
:duration 200
:easing (.-ease (animation/easing))
:useNativeDriver true}))
(defn- ios-shadow-opacity-anim [scroll-y]
(if platform/ios?
(animation/interpolate scroll-y
{:inputRange [0 toolbar-statusbar-height]
:outputRange [0 1]
:extrapolate "clamp"})
0))
(defn- android-shadow-elevation-anim [scroll-y]
(if platform/android?
(animation/interpolate scroll-y
{:inputRange [0 toolbar-statusbar-height]
:outputRange [0 9]
:extrapolate "clamp"})
0))
(defn bottom-border-opacity-anim [scroll-y]
(animation/interpolate scroll-y
{:inputRange [0 toolbar-statusbar-height]
:outputRange [1 0]
:extrapolate "clamp"}))
(defn animated-content-wrapper [anim-opacity]
{:flex 1
:align-self :stretch
:opacity anim-opacity})
(def minimized-toolbar
{:z-index 100
:elevation 9})
(defn flat-list-with-large-header-bottom [scroll-y]
{:height 16
:opacity (bottom-border-opacity-anim scroll-y)
:border-bottom-width 1
:border-bottom-color colors/gray-lighter})
(defn flat-list-with-large-header-shadow [window-width scroll-y]
(cond-> {:flex 1
:align-self :stretch
:position :absolute
:height toolbar-shadow-component-height
:width window-width
:top (- toolbar-shadow-component-height)
:shadow-radius 8
:shadow-offset {:width 0 :height 2}
:shadow-opacity 1
:shadow-color "rgba(0, 9, 26, 0.12)"
:elevation (android-shadow-elevation-anim scroll-y)
:background-color colors/white}
platform/ios?
(assoc :opacity (ios-shadow-opacity-anim scroll-y))))
(def flat-list
{:z-index -1})

View File

@ -0,0 +1,85 @@
(ns status-im.ui.components.large-toolbar.view
(:require [reagent.core :as reagent]
[cljs-bean.core :refer [->clj ->js]]
[status-im.ui.components.list.views :as list.views]
[status-im.ui.components.react :as react]
[status-im.ui.components.toolbar.view :as toolbar]
[status-im.ui.components.large-toolbar.styles :as styles]
[status-im.utils.platform :as platform]
[status-im.ui.components.animation :as animation])
(:require-macros [status-im.utils.views :as views]))
;; header-in-toolbar - component - small header in toolbar
;; nav-item - component/nil - if nav-item like back button is needed, else nil
;; action-items - status-im.ui.components.toolbar.view/actions
(defn minimized-toolbar [header-in-toolbar nav-item action-items anim-opacity]
(let [has-nav? (boolean nav-item)]
[toolbar/toolbar
{:transparent? true
:style styles/minimized-toolbar}
nav-item
[react/animated-view
{:style (cond-> (styles/animated-content-wrapper anim-opacity)
(false? has-nav?)
(assoc :margin-left -40 :margin-right 40))}
header-in-toolbar]
action-items]))
;; header - component that serves as large header without any top/bottom padding
;; top(4px high) and bottom(16px high and with border) padding
;; are assumed to be constant
;; this is wrapped with padding components and merged with content
;; content - vector - of the rest(from header) of the list components
;; wrapped header and content form the data prop of flat-list
;; list-ref - atom - a reference to flat-list for the purpose of invoking its
;; methods
;; scroll-y - animated value tracking the y scoll of the main content in flat-list-view
(views/defview flat-list-with-large-header [header content list-ref scroll-y]
(views/letsubs [window-width [:dimensions/window-width]]
(let [header-top-padding [react/view {:height 4}]
;; header bottom padding with border-bottom
;; fades out as it approaches toolbar shadow
header-bottom [react/animated-view
{:style (styles/flat-list-with-large-header-bottom scroll-y)}]
wrapped-data (into [header-top-padding header header-bottom] content)]
[react/view {:flex 1}
;; toolbar shadow
[react/animated-view
{:style (styles/flat-list-with-large-header-shadow window-width scroll-y)}]
[list.views/flat-list
{:style styles/flat-list
:data wrapped-data
:initial-num-to-render 3
:ref #(when % (reset! list-ref (.getNode %)))
:render-fn list.views/flat-list-generic-render-fn
:key-fn (fn [item idx] (str idx))
:scrollEventThrottle 16
:on-scroll (animation/event
[{:nativeEvent {:contentOffset {:y scroll-y}}}]
{:useNativeDriver true})
:keyboard-should-persist-taps :handled}
{:animated? true}]])))
(defn generate-view
"main function which generates views.
- it will generate and return back:
- minimized-toolbar
- flat-list-with-large-header"
[header-in-toolbar nav-item toolbar-action-items header content list-ref]
(let [to-hide (reagent/atom false)
anim-opacity (animation/create-value 0)
scroll-y (animation/create-value 0)]
(animation/add-listener scroll-y (fn [anim]
(cond
(and (>= (.-value anim) 40) (not @to-hide))
(animation/start
(styles/minimized-toolbar-fade-in anim-opacity)
#(reset! to-hide true))
(and (< (.-value anim) 40) @to-hide)
(animation/start
(styles/minimized-toolbar-fade-out anim-opacity)
#(reset! to-hide false)))))
{:minimized-toolbar [minimized-toolbar header-in-toolbar nav-item toolbar-action-items anim-opacity]
:content-with-header [flat-list-with-large-header header content list-ref scroll-y]}))

View File

@ -223,13 +223,15 @@
(defn flat-list (defn flat-list
"A wrapper for FlatList. "A wrapper for FlatList.
See https://facebook.github.io/react-native/docs/flatlist.html" See https://facebook.github.io/react-native/docs/flatlist.html"
[{:keys [data] :as props}] ([props] (flat-list props nil))
([{:keys [data] :as props} {:keys [animated?]}]
(let [class (if animated? react/animated-flat-list-class flat-list-class)]
{:pre [(or (nil? data) {:pre [(or (nil? data)
(sequential? data))]} (sequential? data))]}
[flat-list-class [class
(merge (base-list-props props) (merge (base-list-props props)
props props
{:data (wrap-data data)})]) {:data (wrap-data data)})])))
(defn flat-list-generic-render-fn (defn flat-list-generic-render-fn
"A generic status-react specific `render-fn` for `list-item`. "A generic status-react specific `render-fn` for `list-item`.
@ -283,13 +285,14 @@
[react/touchable-highlight {:on-press action} [react/touchable-highlight {:on-press action}
[react/view {:accessibility-label accessibility-label} [react/view {:accessibility-label accessibility-label}
[item [item
(when icon
[item-icon {:icon icon [item-icon {:icon icon
:style (merge styles/action :style (merge styles/action
action-style action-style
(when disabled? styles/action-disabled)) (when disabled? styles/action-disabled))
:icon-opts (merge {:color :white} :icon-opts (merge {:color :white}
icon-opts icon-opts
(when disabled? {:color colors/gray}))}] (when disabled? {:color colors/gray}))}])
(if-not subtext (if-not subtext
[item-primary-only {:style (merge styles/action-label [item-primary-only {:style (merge styles/action-label
(action-label-style false) (action-label-style false)

View File

@ -0,0 +1,44 @@
(ns status-im.ui.screens.profile.components.sheets
(:require [re-frame.core :as re-frame]
[status-im.ui.components.react :as react]
[status-im.i18n :as i18n]
[status-im.ui.components.colors :as colors]
[status-im.ui.components.list-item.views :as list-item]
[status-im.ui.screens.profile.components.styles :as styles])
(:require-macros [status-im.utils.views :as views]))
(defn hide-sheet-and-dispatch [event]
(re-frame/dispatch [:bottom-sheet/hide-sheet])
(re-frame/dispatch event))
(views/defview add-contact []
(views/letsubs [{:keys [public-key]} [:bottom-sheet/options]]
[react/view
[react/text {:style styles/sheet-text}
(i18n/label :t/add-to-contacts-text)]
[list-item/list-item
{:theme :action
:title :t/add-to-contacts
:icon :main-icons/add-contact
:on-press #(hide-sheet-and-dispatch [:contact.ui/add-to-contact-pressed public-key])}]]))
(views/defview remove-contact []
(views/letsubs [contact [:bottom-sheet/options]]
[react/view
[react/text {:style styles/sheet-text}
(i18n/label :t/remove-from-contacts-text)]
[list-item/list-item
{:theme :action-destructive
:title :t/remove-from-contacts
:icon :main-icons/remove-contact
:on-press #(hide-sheet-and-dispatch [:contact.ui/remove-contact-pressed contact])}]]))
(views/defview block-contact []
(views/letsubs [{:keys [public-key]} [:bottom-sheet/options]]
[react/view
[react/text {:style styles/sheet-text}
(i18n/label :t/block-contact-details)]
[list-item/list-item
{:theme :action-destructive
:title :t/block-contact
:on-press #(hide-sheet-and-dispatch [:contact.ui/block-contact-confirmed public-key])}]]))

View File

@ -113,3 +113,11 @@
(def profile-form (def profile-form
{:padding-vertical 16}) {:padding-vertical 16})
;; sheets
(def sheet-text
{:color colors/gray
:padding 24
:line-height 22
:font-size 15})

View File

@ -2,28 +2,6 @@
(:require-macros [status-im.utils.styles :refer [defstyle]]) (:require-macros [status-im.utils.styles :refer [defstyle]])
(:require [status-im.ui.components.colors :as colors])) (:require [status-im.ui.components.colors :as colors]))
(def network-info {:background-color :white})
(def profile-info-item
{:flex-direction :row
:align-items :center
:padding-left 16})
(defn profile-info-text-container [options]
{:flex 1
:padding-right (if options 16 40)})
(def profile-info-title
{:color colors/gray
:font-size 14})
(defstyle profile-setting-spacing
{:ios {:height 10}
:android {:height 7}})
(def profile-setting-text
{:font-size 17})
(def action-container (def action-container
{:background-color colors/white}) {:background-color colors/white})
@ -51,20 +29,14 @@
(def action-icon-opts (def action-icon-opts
{:color colors/blue}) {:color colors/blue})
(def block-action (def block-action-label
{:background-color colors/red-transparent-10 {:color colors/red
:border-radius 50}) :padding-top 26
:margin-left 16})
(defn block-action-label [with-subtext?] (def contact-profile-details-container
{:color colors/red})
(def block-action-icon-opts
{:color colors/red})
(def profile-setting-text-empty
(merge profile-setting-text
{:color colors/gray}))
(def contact-profile-info-container
{:padding-top 26 {:padding-top 26
:background-color colors/white}) :background-color colors/white})
(def contact-profile-detail-share-icon
{:color colors/gray-transparent-40})

View File

@ -1,105 +1,145 @@
(ns status-im.ui.screens.profile.contact.views (ns status-im.ui.screens.profile.contact.views
(:require [re-frame.core :as re-frame] (:require [re-frame.core :as re-frame]
[reagent.core :as reagent]
[status-im.i18n :as i18n] [status-im.i18n :as i18n]
[status-im.ui.components.list.views :as list] [status-im.ui.components.list.views :as list]
[status-im.utils.utils :as utils]
[status-im.utils.platform :as platform]
[status-im.ui.components.tabbar.styles :as tabs.styles]
[status-im.ui.components.icons.vector-icons :as icons]
[status-im.ui.components.react :as react] [status-im.ui.components.react :as react]
[status-im.ui.components.status-bar.view :as status-bar] [status-im.ui.components.status-bar.view :as status-bar]
[status-im.ui.components.large-toolbar.view :as large-toolbar]
[status-im.ui.components.toolbar.view :as toolbar] [status-im.ui.components.toolbar.view :as toolbar]
[status-im.ui.screens.profile.components.styles :as profile.components.styles]
[status-im.ui.screens.profile.components.views :as profile.components] [status-im.ui.screens.profile.components.views :as profile.components]
[status-im.ui.screens.profile.contact.styles :as styles] [status-im.ui.screens.profile.contact.styles :as styles]
[status-im.utils.platform :as platform]) [status-im.ui.components.list-item.views :as list-item]
(:require-macros [status-im.utils.views :refer [defview letsubs]])) [status-im.ui.components.chat-icon.screen :as chat-icon]
[status-im.ui.screens.profile.components.sheets :as sheets]
(defn profile-contact-toolbar [] [status-im.ui.screens.chat.photos :as photos]
[toolbar/toolbar {} [status-im.multiaccounts.core :as multiaccounts])
toolbar/default-nav-back (:require-macros [status-im.utils.views :as views]))
[toolbar/content-title ""]])
(defn actions (defn actions
[{:keys [public-key added? tribute-to-talk] :as contact}] [{:keys [public-key added? tribute-to-talk] :as contact}]
(let [{:keys [tribute-status tribute-label]} tribute-to-talk] (let [{:keys [tribute-status tribute-label]} tribute-to-talk]
(concat (if added? (concat [(cond-> {:label (i18n/label :t/send-message)
[{:label (i18n/label :t/in-contacts)
:icon :main-icons/in-contacts
:disabled? true
:accessibility-label :in-contacts-button}]
[{:label (i18n/label :t/add-to-contacts)
:icon :main-icons/add-contact
:action #(re-frame/dispatch [:contact.ui/add-to-contact-pressed public-key])
:accessibility-label :add-to-contacts-button}])
[(cond-> {:label (i18n/label :t/send-message)
:icon :main-icons/message :icon :main-icons/message
:action #(re-frame/dispatch [:contact.ui/send-message-pressed {:public-key public-key}]) :action #(re-frame/dispatch [:contact.ui/send-message-pressed {:public-key public-key}])
:accessibility-label :start-conversation-button} :accessibility-label :start-conversation-button}
(not (#{:none :paid} tribute-status)) (not (#{:none :paid} tribute-status))
(assoc :subtext tribute-label)) (assoc :subtext tribute-label))]
;;TODO hide temporary for v1 ;;TODO hide temporary for v1
#_{:label (i18n/label :t/send-transaction) #_{:label (i18n/label :t/send-transaction)
:icon :main-icons/send :icon :main-icons/send
:action #(re-frame/dispatch [:profile/send-transaction public-key]) :action #(re-frame/dispatch [:profile/send-transaction public-key])
:accessibility-label :send-transaction-button} :accessibility-label :send-transaction-button}
{:label (i18n/label :t/share-profile-link) (if added?
:icon :main-icons/share [{:label (i18n/label :t/remove-from-contacts)
:action #(re-frame/dispatch [:profile/share-profile-link public-key]) :icon :main-icons/remove-contact
:accessibility-label :share-profile-link}]))) :accessibility-label :in-contacts-button
:action #(re-frame/dispatch [:contact.ui/remove-contact-pressed contact])}]
;; TODO sheets temporary disabled
;:action #(re-frame/dispatch [:bottom-sheet/show-sheet
; {:content sheets/remove-contact
; :content-height 150}
; contact])
[{:label (i18n/label :t/add-to-contacts)
:icon :main-icons/add-contact
:accessibility-label :add-to-contacts-button
:action #(re-frame/dispatch [:contact.ui/add-to-contact-pressed public-key])}]))))
;; TODO sheets temporary disabled
;:action #(re-frame/dispatch [:bottom-sheet/show-sheet
; {:content sheets/add-contact
; :content-height 150}
; contact])
(defn profile-info-item [{:keys [label value options accessibility-label]}] (defn render-detail [{:keys [name public-key] :as detail}]
[react/view styles/profile-info-item [list-item/list-item
[react/view (styles/profile-info-text-container options) {:title name
[react/text {:style styles/profile-info-title} :subtitle (utils/get-shortened-address public-key)
label] :icon [chat-icon/contact-icon-contacts-tab detail]
[react/view styles/profile-setting-spacing]
[react/text {:style styles/profile-setting-text
:accessibility-label accessibility-label
:selectable true}
value]]])
(defn profile-info-contact-code-item [public-key]
[profile-info-item
{:label (i18n/label :t/contact-code)
:accessibility-label :profile-public-key :accessibility-label :profile-public-key
:value public-key}]) :on-press #(re-frame/dispatch [:show-popover {:view :share-chat-key :address public-key}])
:accessories [[icons/icon :main-icons/share styles/contact-profile-detail-share-icon]]}])
(defn profile-info [{:keys [public-key]}] (defn profile-details-list-view [contact]
[list/flat-list {:data [contact]
:default-separator? true
:key-fn :public-key
:render-fn render-detail}])
(defn profile-details [contact]
[react/view [react/view
[profile-info-contact-code-item public-key]]) [list-item/list-item {:type :section-header
:title :t/profile-details
:title-accessibility-label :profile-details}]
[profile-details-list-view contact]])
(defn block-contact-action [{:keys [blocked? public-key]}] (defn block-contact-action [{:keys [blocked? public-key] :as contact}]
[list/render-action [react/touchable-highlight {:on-press (if blocked?
{:label (if blocked?
(i18n/label :t/unblock-contact)
(i18n/label :t/block-contact))
:icon :main-icons/cancel
:action (if blocked?
#(re-frame/dispatch [:contact.ui/unblock-contact-pressed public-key]) #(re-frame/dispatch [:contact.ui/unblock-contact-pressed public-key])
#(re-frame/dispatch [:contact.ui/block-contact-pressed public-key])) #(re-frame/dispatch [:bottom-sheet/show-sheet
{:content sheets/block-contact
:content-height 160}
contact]))}
[react/text {:style styles/block-action-label
:accessibility-label (if blocked? :accessibility-label (if blocked?
:unblock-contact :unblock-contact
:block-contact)} :block-contact)}
{:action-style styles/block-action (if blocked?
:action-label-style styles/block-action-label (i18n/label :t/unblock-contact)
:icon-opts styles/block-action-icon-opts}]) (i18n/label :t/block-contact))]])
(defview profile [] (defn- header-in-toolbar [{:keys [photo-path] :as account}]
(letsubs [contact [:contacts/current-contact]] (let [displayed-name (multiaccounts/displayed-name account)]
[react/view profile.components.styles/profile [react/view {:flex 1
[status-bar/status-bar] :flex-direction :row
[profile-contact-toolbar] :align-items :center
[react/scroll-view :align-self :stretch}
[react/view profile.components.styles/profile-form [photos/photo photo-path {:size 40}]
[react/text {:style {:typography :title-bold
:line-height 21
:margin-right 40
:margin-left 16
:text-align :left}
:accessibility-label :account-name}
displayed-name]]))
(defn- header [account]
[profile.components/profile-header [profile.components/profile-header
{:contact contact {:contact account
:editing? false :allow-icon-change? false
:allow-icon-change? false}]] :include-remove-action? false}])
[list/action-list (actions contact)
(views/defview profile []
(views/letsubs [list-ref (reagent/atom nil)
contact [:contacts/current-contact]]
(let [header-in-toolbar (header-in-toolbar contact)
header (header contact)
content
[[list/action-list (actions contact)
{:container-style styles/action-container {:container-style styles/action-container
:action-style styles/action :action-style styles/action
:action-label-style styles/action-label :action-label-style styles/action-label
:action-subtext-style styles/action-subtext :action-subtext-style styles/action-subtext
:action-separator-style styles/action-separator :action-separator-style styles/action-separator
:icon-opts styles/action-icon-opts}] :icon-opts styles/action-icon-opts}]
[react/view {:style {:height 16}}] [react/view styles/contact-profile-details-container
[block-contact-action contact] [profile-details contact]]
[react/view styles/contact-profile-info-container [block-contact-action contact]]
[profile-info contact]]]])) generated-view (large-toolbar/generate-view
header-in-toolbar
toolbar/default-nav-back
nil
header
content
list-ref)]
[react/safe-area-view
{:style
(merge {:flex 1}
(when platform/ios?
{:margin-bottom tabs.styles/tabs-diff}))}
[status-bar/status-bar {:type :main}]
(:minimized-toolbar generated-view)
(:content-with-header generated-view)])))

View File

@ -9,7 +9,8 @@
[status-im.ui.components.colors :as colors] [status-im.ui.components.colors :as colors]
[status-im.ui.components.common.common :as components.common] [status-im.ui.components.common.common :as components.common]
[status-im.ui.components.copyable-text :as copyable-text] [status-im.ui.components.copyable-text :as copyable-text]
[status-im.ui.components.large-toolbar :as large-toolbar] [status-im.ui.components.large-toolbar.view :as large-toolbar]
[status-im.ui.components.list-item.views :as list-item]
[status-im.ui.components.list-selection :as list-selection] [status-im.ui.components.list-selection :as list-selection]
[status-im.ui.components.list.views :as list.views] [status-im.ui.components.list.views :as list.views]
[status-im.ui.components.qr-code-viewer.views :as qr-code-viewer] [status-im.ui.components.qr-code-viewer.views :as qr-code-viewer]
@ -203,18 +204,30 @@
registrar [:ens.stateofus/registrar]] registrar [:ens.stateofus/registrar]]
(let [show-backup-seed? (and (not seed-backed-up?) (let [show-backup-seed? (and (not seed-backed-up?)
(not (string/blank? mnemonic))) (not (string/blank? mnemonic)))
;; toolbar-contents
header-in-toolbar (header-in-toolbar multiaccount)
toolbar-action-items (toolbar-action-items public-key)
;; flatlist contents
header (header multiaccount)
content (flat-list-content content (flat-list-content
preferred-name registrar tribute-to-talk preferred-name registrar tribute-to-talk
active-contacts-count show-backup-seed?)] active-contacts-count show-backup-seed?)
;; generated toolbar and content with header
generated-view (large-toolbar/generate-view
header-in-toolbar
nil
toolbar-action-items
header
content
list-ref)]
[react/safe-area-view [react/safe-area-view
{:style {:style
(merge {:flex 1} (merge {:flex 1}
(when platform/ios? (when platform/ios?
{:margin-bottom tabs.styles/tabs-diff}))} {:margin-bottom tabs.styles/tabs-diff}))}
[status-bar/status-bar {:type :main}] [status-bar/status-bar {:type :main}]
[large-toolbar/minimized-toolbar (:minimized-toolbar generated-view)
(header-in-toolbar multiaccount) (:content-with-header generated-view)])))
nil
(toolbar-action-items public-key)]
[large-toolbar/flat-list-with-large-header
(header multiaccount) content list-ref]])))

View File

@ -17,6 +17,7 @@
(def react-native (def react-native
#js {:NativeModules #js {} #js {:NativeModules #js {}
:Animated #js {:View #js {} :Animated #js {:View #js {}
:FlatList #js {}
:Text #js {}} :Text #js {}}
:DeviceEventEmitter #js {:addListener (fn [])} :DeviceEventEmitter #js {:addListener (fn [])}
:Dimensions #js {:get (fn [])}}) :Dimensions #js {:get (fn [])}})

View File

@ -26,6 +26,7 @@
"add-members": "Add members", "add-members": "Add members",
"add-network": "Add network", "add-network": "Add network",
"add-to-contacts": "Add to contacts", "add-to-contacts": "Add to contacts",
"add-to-contacts-text": "By adding a user to your contact list, you share your wallet address",
"address": "Address", "address": "Address",
"advanced": "Advanced", "advanced": "Advanced",
"advanced-settings": "Advanced settings", "advanced-settings": "Advanced settings",
@ -70,7 +71,7 @@
"blank-keycard-text": "You can proceed with your keycard once you've generated your keys and name", "blank-keycard-text": "You can proceed with your keycard once you've generated your keys and name",
"blank-keycard-title": "Looks like youve tapped \na blank keycard", "blank-keycard-title": "Looks like youve tapped \na blank keycard",
"block": "Block", "block": "Block",
"block-contact": "Block contact", "block-contact": "Block this user",
"block-contact-details": "Blocking will delete this user's previous messages and stop new ones from reaching you", "block-contact-details": "Blocking will delete this user's previous messages and stop new ones from reaching you",
"blocked-users": "Blocked users", "blocked-users": "Blocked users",
"bootnode-address": "Bootnode address", "bootnode-address": "Bootnode address",
@ -782,6 +783,7 @@
"processing": "Processing", "processing": "Processing",
"product-information": "Product Information", "product-information": "Product Information",
"profile": "Profile", "profile": "Profile",
"profile-details": "Profile details",
"public-chat": "Public chat", "public-chat": "Public chat",
"public-chats": "Public chats", "public-chats": "Public chats",
"public-group-status": "Public", "public-group-status": "Public",
@ -825,6 +827,8 @@
"remind-me-later": "Remind me later", "remind-me-later": "Remind me later",
"remove": "Remove", "remove": "Remove",
"remove-from-chat": "Remove from chat", "remove-from-chat": "Remove from chat",
"remove-from-contacts": "Remove from contacts",
"remove-from-contacts-text": "By removing a user from your contact list you do not hide your wallet address from them",
"remove-network": "Remove network", "remove-network": "Remove network",
"remove-token": "Remove token", "remove-token": "Remove token",
"removed": "removed", "removed": "removed",
@ -1007,7 +1011,7 @@
"type-a-message": "Type a message...", "type-a-message": "Type a message...",
"ulc-enabled": "ULC enabled", "ulc-enabled": "ULC enabled",
"unable-to-read-this-code": "Unable to read this code", "unable-to-read-this-code": "Unable to read this code",
"unblock-contact": "Unblock contact", "unblock-contact": "Unblock this user",
"unknown-status-go-error": "Unknown status-go error", "unknown-status-go-error": "Unknown status-go error",
"unlock": "Unlock", "unlock": "Unlock",
"unpair-card": "Unpair card", "unpair-card": "Unpair card",