From eff6ee7ef47ebc9f3a4487f0e3b105ed7d1a690e Mon Sep 17 00:00:00 2001 From: Mohsen Date: Wed, 29 Nov 2023 20:54:11 +0300 Subject: [PATCH] [#17986] feat: implement new settings ui, header section (#17991) --- src/quo/components/overlay/style.cljs | 22 +++++ src/quo/components/overlay/view.cljs | 20 +++++ .../components/text_combinations/style.cljs | 5 ++ .../components/text_combinations/view.cljs | 10 ++- src/quo/core.cljs | 4 + src/quo/foundations/colors.cljs | 4 +- .../profile/settings/header/avatar.cljs | 43 ++++++++++ .../profile/settings/header/header_shape.cljs | 36 ++++++++ .../profile/settings/header/style.cljs | 48 +++++++++++ .../profile/settings/header/view.cljs | 49 +++++++++++ .../contexts/profile/settings/list_items.cljs | 83 +++++++++++++++++++ .../contexts/profile/settings/style.cljs | 11 +++ .../contexts/profile/settings/view.cljs | 71 ++++++++++++++++ .../text_combinations/preview.cljs | 7 +- src/status_im2/navigation/screens.cljs | 5 ++ translations/en.json | 5 +- 16 files changed, 416 insertions(+), 7 deletions(-) create mode 100644 src/quo/components/overlay/style.cljs create mode 100644 src/quo/components/overlay/view.cljs create mode 100644 src/status_im2/contexts/profile/settings/header/avatar.cljs create mode 100644 src/status_im2/contexts/profile/settings/header/header_shape.cljs create mode 100644 src/status_im2/contexts/profile/settings/header/style.cljs create mode 100644 src/status_im2/contexts/profile/settings/header/view.cljs create mode 100644 src/status_im2/contexts/profile/settings/list_items.cljs create mode 100644 src/status_im2/contexts/profile/settings/style.cljs create mode 100644 src/status_im2/contexts/profile/settings/view.cljs diff --git a/src/quo/components/overlay/style.cljs b/src/quo/components/overlay/style.cljs new file mode 100644 index 00000000000..471bbebe091 --- /dev/null +++ b/src/quo/components/overlay/style.cljs @@ -0,0 +1,22 @@ +(ns quo.components.overlay.style + (:require [quo.foundations.colors :as colors])) + +(defn overlay-background + [type] + (let [background-color (case type + :shell colors/neutral-80-opa-80-blur + :drawer colors/neutral-100-opa-70-blur + nil)] + {:position :absolute + :top 0 + :left 0 + :right 0 + :bottom 0 + :background-color background-color})) + +(def container + {:flex 1}) + +(def blur-container + {:flex 1 + :background-color :transparent}) diff --git a/src/quo/components/overlay/view.cljs b/src/quo/components/overlay/view.cljs new file mode 100644 index 00000000000..7b35f87a939 --- /dev/null +++ b/src/quo/components/overlay/view.cljs @@ -0,0 +1,20 @@ +(ns quo.components.overlay.view + (:require + [quo.components.overlay.style :as style] + [react-native.blur :as blur] + [react-native.core :as rn])) + +(defn view + [{:keys [type]} & children] + [rn/view {:style (style/overlay-background type)} + (if (= type :shell) + [blur/view + {:blur-amount 20 + :blur-radius 25 + :blur-type :transparent + :overlay-color :transparent + :style style/container} + [rn/view {:style style/blur-container} + children]] + [rn/view {:style style/container} + children])]) diff --git a/src/quo/components/text_combinations/style.cljs b/src/quo/components/text_combinations/style.cljs index dc06fb28f4c..37103d13f6a 100644 --- a/src/quo/components/text_combinations/style.cljs +++ b/src/quo/components/text_combinations/style.cljs @@ -9,3 +9,8 @@ (def description-description-text {:margin-top 8}) + +(def emoji-hash + {:margin-top 8 + :letter-spacing 0.5 + :line-height 20.5}) diff --git a/src/quo/components/text_combinations/view.cljs b/src/quo/components/text_combinations/view.cljs index 534b00419ce..e9bdae350c1 100644 --- a/src/quo/components/text_combinations/view.cljs +++ b/src/quo/components/text_combinations/view.cljs @@ -27,7 +27,8 @@ description-accessibility-label button-icon button-on-press - customization-color]}] + customization-color + emoji-hash]}] [rn/view {:style container-style} [rn/view {:style {:flex-direction :row @@ -55,6 +56,11 @@ :weight :regular :size :paragraph-1 :style style/description-description-text} - description])]) + description]) + (when emoji-hash + [text/text + {:number-of-lines 1 + :style style/emoji-hash} + emoji-hash])]) (def view (theme/with-theme view-internal)) diff --git a/src/quo/core.cljs b/src/quo/core.cljs index 04b06108071..88ab14de0f6 100644 --- a/src/quo/core.cljs +++ b/src/quo/core.cljs @@ -101,6 +101,7 @@ quo.components.numbered-keyboard.keyboard-key.view quo.components.numbered-keyboard.numbered-keyboard.view quo.components.onboarding.small-option-card.view + quo.components.overlay.view quo.components.password.tips.view quo.components.profile.collectible.view quo.components.profile.profile-card.view @@ -316,6 +317,9 @@ (def notification quo.components.notifications.notification.view/notification) (def toast quo.components.notifications.toast.view/toast) +;;;; Overlay +(def overlay quo.components.overlay.view/view) + ;;;; Password (def tips quo.components.password.tips.view/view) diff --git a/src/quo/foundations/colors.cljs b/src/quo/foundations/colors.cljs index 622d888d67a..1dd1348736e 100644 --- a/src/quo/foundations/colors.cljs +++ b/src/quo/foundations/colors.cljs @@ -148,7 +148,9 @@ (def black-opa-30 (alpha black 0.3)) (def black-opa-60 (alpha black 0.6)) (def onboarding-header-black "#000716") - +(def border-avatar-light + "Simulates a blurred, transparent border for avatars in light mode" + "#475060") ;;;;Primary ;;Solid diff --git a/src/status_im2/contexts/profile/settings/header/avatar.cljs b/src/status_im2/contexts/profile/settings/header/avatar.cljs new file mode 100644 index 00000000000..821ea2627bf --- /dev/null +++ b/src/status_im2/contexts/profile/settings/header/avatar.cljs @@ -0,0 +1,43 @@ +(ns status-im2.contexts.profile.settings.header.avatar + (:require [quo.core :as quo] + [quo.theme :as quo.theme] + [react-native.reanimated :as reanimated] + [status-im2.contexts.profile.settings.header.style :as style])) + +(def scroll-animation-input-range [0 50]) +(def header-extrapolation-option + {:extrapolateLeft "clamp" + :extrapolateRight "clamp"}) + +(defn f-avatar + [{:keys [scroll-y full-name online? profile-picture customization-color]}] + (let [image-scale-animation (reanimated/interpolate scroll-y + scroll-animation-input-range + [1 0.5] + header-extrapolation-option) + image-top-margin-animation (reanimated/interpolate scroll-y + scroll-animation-input-range + [0 20] + header-extrapolation-option) + image-side-margin-animation (reanimated/interpolate scroll-y + scroll-animation-input-range + [0 -20] + header-extrapolation-option) + theme (quo.theme/get-theme)] + [reanimated/view + {:style (style/avatar-container theme + image-scale-animation + image-top-margin-animation + image-side-margin-animation)} + [quo/user-avatar + {:full-name full-name + :online? online? + :profile-picture profile-picture + :status-indicator? true + :ring? true + :customization-color customization-color + :size :big}]])) + +(defn view + [props] + [:f> f-avatar props]) diff --git a/src/status_im2/contexts/profile/settings/header/header_shape.cljs b/src/status_im2/contexts/profile/settings/header/header_shape.cljs new file mode 100644 index 00000000000..ff5ef92c741 --- /dev/null +++ b/src/status_im2/contexts/profile/settings/header/header_shape.cljs @@ -0,0 +1,36 @@ +(ns status-im2.contexts.profile.settings.header.header-shape + (:require [quo.foundations.colors :as colors] + [react-native.core :as rn] + [react-native.reanimated :as reanimated] + [react-native.svg :as svg] + [status-im2.contexts.profile.settings.header.style :as style])) + +(defn left-radius + [background-color] + [svg/svg {:width "20" :height "20" :viewBox "0 0 20 20" :fill "none"} + [svg/path + {:d "M20 0C7 2 0 10 0 20V0H15Z" + :fill background-color}]]) + +(defn right-radius + [background-color] + [svg/svg {:width "20" :height "21" :viewBox "0 0 20 21" :fill "none"} + [svg/path + {:d "M20 20V0H0C11 0 20 9 20 20Z" + :fill background-color}]]) + +(defn f-view + [{:keys [scroll-y customization-color theme]}] + (let [background-color (colors/resolve-color customization-color theme 40) + opacity-animation (reanimated/interpolate scroll-y + [0 45 50] + [1 1 0])] + [:<> + [rn/view {:style (style/header-middle-shape background-color)}] + [reanimated/view {:style (style/radius-container opacity-animation)} + [left-radius background-color] + [right-radius background-color]]])) + +(defn view + [props] + [:f> f-view props]) diff --git a/src/status_im2/contexts/profile/settings/header/style.cljs b/src/status_im2/contexts/profile/settings/header/style.cljs new file mode 100644 index 00000000000..8958137a063 --- /dev/null +++ b/src/status_im2/contexts/profile/settings/header/style.cljs @@ -0,0 +1,48 @@ +(ns status-im2.contexts.profile.settings.header.style + (:require [quo.foundations.colors :as colors] + [react-native.reanimated :as reanimated])) + +(defn header-view + [customization-color theme] + {:background-color (colors/resolve-color customization-color theme 40) + :min-height 100 + :flex 1}) + +(def avatar-row-wrapper + {:display :flex + :padding-left 16 + :padding-right 12 + :margin-top -60 + :margin-bottom -4 + :align-items :flex-end + :justify-content :space-between + :flex-direction :row}) + +(def title-container + {:padding-horizontal 20 + :padding-vertical 12}) + +(defn header-middle-shape + [background-color] + {:background-color background-color + :height 48 + :flex-grow 1}) + +(defn radius-container + [opacity-animation] + (reanimated/apply-animations-to-style + {:opacity opacity-animation} + {:flex-direction :row + :justify-content :space-between})) + +(defn avatar-container + [theme scale-animation top-margin-animation side-margin-animation] + (reanimated/apply-animations-to-style + {:transform [{:scale scale-animation}] + :margin-top top-margin-animation + :margin-left side-margin-animation + :margin-bottom side-margin-animation} + {:align-items :flex-start + :border-width 4 + :border-color (colors/theme-colors colors/border-avatar-light colors/neutral-80-opa-80 theme) + :border-radius 100})) diff --git a/src/status_im2/contexts/profile/settings/header/view.cljs b/src/status_im2/contexts/profile/settings/header/view.cljs new file mode 100644 index 00000000000..4ddec3253d5 --- /dev/null +++ b/src/status_im2/contexts/profile/settings/header/view.cljs @@ -0,0 +1,49 @@ +(ns status-im2.contexts.profile.settings.header.view + (:require [clojure.string :as string] + [quo.core :as quo] + [quo.theme :as quo.theme] + [react-native.core :as rn] + [status-im2.common.not-implemented :as not-implemented] + [status-im2.contexts.profile.settings.header.avatar :as header.avatar] + [status-im2.contexts.profile.settings.header.header-shape :as header.shape] + [status-im2.contexts.profile.settings.header.style :as style] + [status-im2.contexts.profile.utils :as profile.utils] + [utils.i18n :as i18n] + [utils.re-frame :as rf])) + +(defn- f-view + [{:keys [theme scroll-y]}] + (let [{:keys [public-key emoji-hash] :as profile} (rf/sub [:profile/profile-with-image]) + online? (rf/sub [:visibility-status-updates/online? + public-key]) + customization-color (rf/sub [:profile/customization-color]) + full-name (profile.utils/displayed-name profile) + profile-picture (profile.utils/photo profile) + emoji-string (string/join emoji-hash)] + [:<> + [header.shape/view + {:scroll-y scroll-y + :customization-color customization-color + :theme theme}] + [rn/view {:style style/avatar-row-wrapper} + [header.avatar/view + {:scroll-y scroll-y + :display-name full-name + :online? online? + :customization-color customization-color + :profile-picture profile-picture}] + [rn/view {:style {:margin-bottom 4}} + [quo/dropdown + {:background :blur + :size :size-32 + :type :outline + :icon? true + :icon-name :i/online + :on-press not-implemented/alert} + (i18n/label :t/online)]]] + [quo/text-combinations + {:container-style style/title-container + :emoji-hash emoji-string + :title full-name}]])) + +(def view (quo.theme/with-theme f-view)) diff --git a/src/status_im2/contexts/profile/settings/list_items.cljs b/src/status_im2/contexts/profile/settings/list_items.cljs new file mode 100644 index 00000000000..069adf8b96b --- /dev/null +++ b/src/status_im2/contexts/profile/settings/list_items.cljs @@ -0,0 +1,83 @@ +(ns status-im2.contexts.profile.settings.list-items + (:require [status-im2.common.not-implemented :as not-implemented] + [utils.i18n :as i18n] + [utils.re-frame :as rf])) + +(def items + [[{:title (i18n/label :t/edit-profile) + :on-press not-implemented/alert + :image-props :i/edit + :image :icon + :action :arrow} + {:title (i18n/label :t/password) + :on-press not-implemented/alert + :image-props :i/password + :image :icon + :action :arrow}] + [{:title (i18n/label :t/messages) + :on-press not-implemented/alert + :image-props :i/messages + :image :icon + :action :arrow} + {:title (i18n/label :t/wallet) + :on-press not-implemented/alert + :image-props :i/wallet + :image :icon + :action :arrow} + {:title (i18n/label :t/dapps) + :on-press not-implemented/alert + :image-props :i/placeholder + :image :icon + :action :arrow} + {:title "Browser" + :on-press not-implemented/alert + :image-props :i/browser + :image :icon + :action :arrow} + {:title (i18n/label :t/keycard) + :on-press not-implemented/alert + :image-props :i/keycard + :image :icon + :action :arrow}] + [{:title (i18n/label :t/syncing) + :on-press not-implemented/alert + :image-props :i/syncing + :image :icon + :action :arrow} + {:title (i18n/label :t/notifications) + :on-press not-implemented/alert + :image-props :i/notifications + :image :icon + :action :arrow} + {:title (i18n/label :t/appearance) + :on-press not-implemented/alert + :image-props :i/light + :image :icon + :action :arrow} + {:title (i18n/label :t/language-and-currency) + :on-press not-implemented/alert + :image-props :i/globe + :image :icon + :action :arrow}] + [{:title (i18n/label :t/data-usage) + :on-press not-implemented/alert + :image-props :i/mobile + :image :icon + :action :arrow} + {:title (i18n/label :t/advanced) + :on-press not-implemented/alert + :image-props :i/settings + :image :icon + :action :arrow}] + ;; temporary link to legacy settings + [{:title "Legacy settings" + :on-press #(rf/dispatch [:navigate-to :my-profile]) + :action :arrow + :image :icon + :image-props :i/toggle}] + [{:title (i18n/label :t/about) + :on-press not-implemented/alert + :action :arrow} + {:title (i18n/label :t/status-help) + :on-press not-implemented/alert + :action :arrow}]]) diff --git a/src/status_im2/contexts/profile/settings/style.cljs b/src/status_im2/contexts/profile/settings/style.cljs new file mode 100644 index 00000000000..d60f70a4756 --- /dev/null +++ b/src/status_im2/contexts/profile/settings/style.cljs @@ -0,0 +1,11 @@ +(ns status-im2.contexts.profile.settings.style + (:require [quo.foundations.colors :as colors])) + +(defn navigation-wrapper + [{:keys [customization-color inset theme]}] + {:padding-top inset + :background-color (colors/resolve-color customization-color theme 40)}) + +(def footer-container + {:padding-horizontal 20 + :padding-vertical 12}) diff --git a/src/status_im2/contexts/profile/settings/view.cljs b/src/status_im2/contexts/profile/settings/view.cljs new file mode 100644 index 00000000000..819a1243f78 --- /dev/null +++ b/src/status_im2/contexts/profile/settings/view.cljs @@ -0,0 +1,71 @@ +(ns status-im2.contexts.profile.settings.view + (:require [oops.core :as oops] + [quo.core :as quo] + [quo.theme :as quo.theme] + [react-native.core :as rn] + [react-native.reanimated :as reanimated] + [react-native.safe-area :as safe-area] + [status-im2.common.not-implemented :as not-implemented] + [status-im2.contexts.profile.settings.header.view :as settings.header] + [status-im2.contexts.profile.settings.list-items :as settings.items] + [status-im2.contexts.profile.settings.style :as style] + [utils.debounce :as debounce] + [utils.i18n :as i18n] + [utils.re-frame :as rf])) + +(defn- settings-item-view + [data] + [quo/category + {:list-type :settings + :blur? true + :data data}]) + +(defn scroll-handler + [event scroll-y] + (let [current-y (oops/oget event "nativeEvent.contentOffset.y")] + (reanimated/set-shared-value scroll-y current-y))) + +(defn- footer + [logout-press] + [rn/view {:style style/footer-container} + [quo/button + {:on-press logout-press + :type :danger + :icon-left :i/log-out} + (i18n/label :t/logout)]]) + +(defn- settings-view + [theme] + (let [insets (safe-area/get-insets) + customization-color (rf/sub [:profile/customization-color]) + scroll-y (reanimated/use-shared-value 0) + logout-press #(rf/dispatch [:multiaccounts.logout.ui/logout-pressed])] + [quo/overlay {:type :shell} + [rn/view + {:style (style/navigation-wrapper {:customization-color customization-color + :inset (:top insets) + :theme theme})} + [quo/page-nav + {:background :blur + :icon-name :i/close + :on-press #(rf/dispatch [:navigate-back]) + :right-side [{:icon-name :i/multi-profile :on-press #(rf/dispatch [:open-modal :sign-in])} + {:icon-name :i/qr-code :on-press not-implemented/alert} + {:icon-name :i/share + :on-press #(debounce/dispatch-and-chill [:open-modal :share-shell] 1000)}]}]] + [rn/flat-list + {:header [settings.header/view {:scroll-y scroll-y}] + :data settings.items/items + :key-fn :title + :shows-vertical-scroll-indicator false + :render-fn settings-item-view + :footer [footer logout-press] + :scroll-event-throttle 16 + :on-scroll #(scroll-handler % scroll-y) + :bounces false}]])) + +(defn- internal-view + [props] + [:f> settings-view props]) + +(def view (quo.theme/with-theme internal-view)) diff --git a/src/status_im2/contexts/quo_preview/text_combinations/preview.cljs b/src/status_im2/contexts/quo_preview/text_combinations/preview.cljs index 3288ad12a60..661b39c07e6 100644 --- a/src/status_im2/contexts/quo_preview/text_combinations/preview.cljs +++ b/src/status_im2/contexts/quo_preview/text_combinations/preview.cljs @@ -8,8 +8,8 @@ (def descriptor [{:key :title :type :text} {:key :avatar :type :boolean} - {:key :description - :type :text}]) + {:key :description :type :text} + {:key :emoji-hash :type :text}]) (defn state->text-combinations-props [state] @@ -22,7 +22,8 @@ (let [state (reagent/atom {:title "Title" :title-accessibility-label :title :description "" - :description-accessibility-label :subtitle})] + :description-accessibility-label :subtitle + :emoji-hash "🐲🍀🎭🌟🚀🐠🌈🏰🔮🦉🐼🍉🎨🚲🌙🍔🌵"})] (fn [] [preview/preview-container {:state state diff --git a/src/status_im2/navigation/screens.cljs b/src/status_im2/navigation/screens.cljs index 5642ce18f9b..a9ee762e358 100644 --- a/src/status_im2/navigation/screens.cljs +++ b/src/status_im2/navigation/screens.cljs @@ -27,6 +27,7 @@ [status-im2.contexts.onboarding.syncing.results.view :as syncing-results] [status-im2.contexts.onboarding.welcome.view :as welcome] [status-im2.contexts.profile.profiles.view :as profiles] + [status-im2.contexts.profile.settings.view :as settings] [status-im2.contexts.quo-preview.component-preview.view :as component-preview] [status-im2.contexts.quo-preview.main :as quo.preview] [status-im2.contexts.shell.activity-center.view :as activity-center] @@ -118,6 +119,10 @@ {:name :community-overview :component communities.overview/overview} + {:name :settings + :options options/transparent-screen-options + :component settings/view} + {:name :settings-syncing :options (merge options/dark-screen {:insets {:top? true}}) :component settings-syncing/view} diff --git a/translations/en.json b/translations/en.json index 23efdefd4e3..8ade8f936dc 100644 --- a/translations/en.json +++ b/translations/en.json @@ -480,7 +480,7 @@ "done": "Done", "edit": "Edit", "edit-group": "Edit group", - "edit-profile": "Edit profile", + "edit-profile": "Edit Profile", "emojihash": "Emojihash", "emojihash-description": "A visual representation of your chat key. It will help other users recognize your profile.", "emojis": "Emojis", @@ -1005,6 +1005,8 @@ "buy-crypto": "Buy crypto", "buy-crypto-choose-a-service": "Choose a service you'd like to use to buy crypto", "buy-crypto-leaving": "You are leaving Status and entering a third party website to complete your purchase", + "data-usage": "Data usage", + "language-and-currency": "Language and currency", "opening-buy-crypto": "Opening {{site}}...", "network": "Network", "network-chain": "Network chain", @@ -1313,6 +1315,7 @@ "status-pending": "Pending", "status-tx-not-found": "TX not found", "status-sent": "Sent", + "status-help": "Status Help", "status-not-sent-tap": "Not confirmed. Tap for options", "status-not-sent-click": "Not confirmed. Click for options", "step-i-of-n": "Step {{step}} of {{number}}",