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
(reagent/adapt-react-class (.-View animated)))
(def animated-flat-list-class
(reagent/adapt-react-class (.-FlatList animated)))
(defn animated-view [props & content]
(vec (conj content props animated-view-class)))

View File

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

View File

@ -14,8 +14,9 @@
(def qr-code (fn [] #js {}))
(def react-native
#js {:NativeModules #js {}
:Animated #js {:View #js {}
:Text #js {}}
:Animated #js {:View #js {}
:FlatList #js {}
:Text #js {}}
:DeviceEventEmitter #js {:addListener (fn [])}
:Dimensions #js {:get (fn [])}})
(def vector-icons (fn [] #js {:default #js {}}))

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)
(assoc-in [:contacts/contacts public-key] 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)
(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
"Create entry in contacts"
[{:keys [db] :as cofx} public-key]

View File

@ -1327,11 +1327,6 @@
(fn [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
:contact.ui/block-contact-confirmed
(fn [cofx [_ public-key]]

View File

@ -42,8 +42,8 @@
(defn anim-delay [duration]
(.delay react/animated duration))
(defn event [config]
(.event react/animated (clj->js [nil, config])))
(defn event [mapping config]
(.event react/animated (clj->js mapping) (clj->js config)))
(defn add-listener [anim-value listener]
(.addListener anim-value listener))
@ -60,6 +60,12 @@
(defn create-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]
(.-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
"A wrapper for FlatList.
See https://facebook.github.io/react-native/docs/flatlist.html"
[{:keys [data] :as props}]
{:pre [(or (nil? data)
(sequential? data))]}
[flat-list-class
(merge (base-list-props props)
props
{:data (wrap-data data)})])
([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)
(sequential? data))]}
[class
(merge (base-list-props props)
props
{:data (wrap-data data)})])))
(defn flat-list-generic-render-fn
"A generic status-react specific `render-fn` for `list-item`.
@ -283,13 +285,14 @@
[react/touchable-highlight {:on-press action}
[react/view {:accessibility-label accessibility-label}
[item
[item-icon {:icon icon
:style (merge styles/action
action-style
(when disabled? styles/action-disabled))
:icon-opts (merge {:color :white}
icon-opts
(when disabled? {:color colors/gray}))}]
(when icon
[item-icon {:icon icon
:style (merge styles/action
action-style
(when disabled? styles/action-disabled))
:icon-opts (merge {:color :white}
icon-opts
(when disabled? {:color colors/gray}))}])
(if-not subtext
[item-primary-only {:style (merge styles/action-label
(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
{: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 [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
{:background-color colors/white})
@ -51,20 +29,14 @@
(def action-icon-opts
{:color colors/blue})
(def block-action
{:background-color colors/red-transparent-10
:border-radius 50})
(def block-action-label
{:color colors/red
:padding-top 26
:margin-left 16})
(defn block-action-label [with-subtext?]
{: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
(def contact-profile-details-container
{:padding-top 26
: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
(:require [re-frame.core :as re-frame]
[reagent.core :as reagent]
[status-im.i18n :as i18n]
[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.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.screens.profile.components.styles :as profile.components.styles]
[status-im.ui.screens.profile.components.views :as profile.components]
[status-im.ui.screens.profile.contact.styles :as styles]
[status-im.utils.platform :as platform])
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
(defn profile-contact-toolbar []
[toolbar/toolbar {}
toolbar/default-nav-back
[toolbar/content-title ""]])
[status-im.ui.components.list-item.views :as list-item]
[status-im.ui.components.chat-icon.screen :as chat-icon]
[status-im.ui.screens.profile.components.sheets :as sheets]
[status-im.ui.screens.chat.photos :as photos]
[status-im.multiaccounts.core :as multiaccounts])
(:require-macros [status-im.utils.views :as views]))
(defn actions
[{:keys [public-key added? tribute-to-talk] :as contact}]
(let [{:keys [tribute-status tribute-label]} tribute-to-talk]
(concat (if added?
[{: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)
(concat [(cond-> {:label (i18n/label :t/send-message)
:icon :main-icons/message
:action #(re-frame/dispatch [:contact.ui/send-message-pressed {:public-key public-key}])
:accessibility-label :start-conversation-button}
(not (#{:none :paid} tribute-status))
(assoc :subtext tribute-label))
(assoc :subtext tribute-label))]
;;TODO hide temporary for v1
#_{:label (i18n/label :t/send-transaction)
:icon :main-icons/send
:action #(re-frame/dispatch [:profile/send-transaction public-key])
:accessibility-label :send-transaction-button}
{:label (i18n/label :t/share-profile-link)
:icon :main-icons/share
:action #(re-frame/dispatch [:profile/share-profile-link public-key])
:accessibility-label :share-profile-link}])))
#_{:label (i18n/label :t/send-transaction)
:icon :main-icons/send
:action #(re-frame/dispatch [:profile/send-transaction public-key])
:accessibility-label :send-transaction-button}
(if added?
[{:label (i18n/label :t/remove-from-contacts)
:icon :main-icons/remove-contact
: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]}]
[react/view styles/profile-info-item
[react/view (styles/profile-info-text-container options)
[react/text {:style styles/profile-info-title}
label]
[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)
(defn render-detail [{:keys [name public-key] :as detail}]
[list-item/list-item
{:title name
:subtitle (utils/get-shortened-address public-key)
:icon [chat-icon/contact-icon-contacts-tab detail]
: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
[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]}]
[list/render-action
{: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/block-contact-pressed public-key]))
:accessibility-label (if blocked?
:unblock-contact
:block-contact)}
{:action-style styles/block-action
:action-label-style styles/block-action-label
:icon-opts styles/block-action-icon-opts}])
(defn block-contact-action [{:keys [blocked? public-key] :as contact}]
[react/touchable-highlight {:on-press (if blocked?
#(re-frame/dispatch [:contact.ui/unblock-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?
:unblock-contact
:block-contact)}
(if blocked?
(i18n/label :t/unblock-contact)
(i18n/label :t/block-contact))]])
(defview profile []
(letsubs [contact [:contacts/current-contact]]
[react/view profile.components.styles/profile
[status-bar/status-bar]
[profile-contact-toolbar]
[react/scroll-view
[react/view profile.components.styles/profile-form
[profile.components/profile-header
{:contact contact
:editing? false
:allow-icon-change? false}]]
[list/action-list (actions contact)
{:container-style styles/action-container
:action-style styles/action
:action-label-style styles/action-label
:action-subtext-style styles/action-subtext
:action-separator-style styles/action-separator
:icon-opts styles/action-icon-opts}]
[react/view {:style {:height 16}}]
[block-contact-action contact]
[react/view styles/contact-profile-info-container
[profile-info contact]]]]))
(defn- header-in-toolbar [{:keys [photo-path] :as account}]
(let [displayed-name (multiaccounts/displayed-name account)]
[react/view {:flex 1
:flex-direction :row
:align-items :center
:align-self :stretch}
[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
{:contact account
:allow-icon-change? false
:include-remove-action? false}])
(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
:action-style styles/action
:action-label-style styles/action-label
:action-subtext-style styles/action-subtext
:action-separator-style styles/action-separator
:icon-opts styles/action-icon-opts}]
[react/view styles/contact-profile-details-container
[profile-details contact]]
[block-contact-action 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.common.common :as components.common]
[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.views :as list.views]
[status-im.ui.components.qr-code-viewer.views :as qr-code-viewer]
@ -203,18 +204,30 @@
registrar [:ens.stateofus/registrar]]
(let [show-backup-seed? (and (not seed-backed-up?)
(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
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
{:style
(merge {:flex 1}
(when platform/ios?
{:margin-bottom tabs.styles/tabs-diff}))}
[status-bar/status-bar {:type :main}]
[large-toolbar/minimized-toolbar
(header-in-toolbar multiaccount)
nil
(toolbar-action-items public-key)]
[large-toolbar/flat-list-with-large-header
(header multiaccount) content list-ref]])))
(:minimized-toolbar generated-view)
(:content-with-header generated-view)])))

View File

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

View File

@ -26,6 +26,7 @@
"add-members": "Add members",
"add-network": "Add network",
"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",
"advanced": "Advanced",
"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-title": "Looks like youve tapped \na blank keycard",
"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",
"blocked-users": "Blocked users",
"bootnode-address": "Bootnode address",
@ -782,6 +783,7 @@
"processing": "Processing",
"product-information": "Product Information",
"profile": "Profile",
"profile-details": "Profile details",
"public-chat": "Public chat",
"public-chats": "Public chats",
"public-group-status": "Public",
@ -825,6 +827,8 @@
"remind-me-later": "Remind me later",
"remove": "Remove",
"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-token": "Remove token",
"removed": "removed",
@ -1007,7 +1011,7 @@
"type-a-message": "Type a message...",
"ulc-enabled": "ULC enabled",
"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",
"unlock": "Unlock",
"unpair-card": "Unpair card",