diff --git a/src/quo/foundations/colors.cljs b/src/quo/foundations/colors.cljs index 622d888d67a5..af9242ab6590 100644 --- a/src/quo/foundations/colors.cljs +++ b/src/quo/foundations/colors.cljs @@ -148,7 +148,7 @@ (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 "#475060") ;; Simulate blur transparent avatar's border in light mode ;;;;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 000000000000..e3121817f7d6 --- /dev/null +++ b/src/status_im2/contexts/profile/settings/header/avatar.cljs @@ -0,0 +1,44 @@ +(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])) + +(defonce ^:const 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 index c5ff227e1e6b..548d571852e7 100644 --- a/src/status_im2/contexts/profile/settings/header/header_shape.cljs +++ b/src/status_im2/contexts/profile/settings/header/header_shape.cljs @@ -1,28 +1,39 @@ (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-shape +(defonce ^:const scroll-animation-input-range [0 45 50]) + +(defn left-radius [background-color] - [svg/svg {:width "109" :height "68" :viewBox "0 0 109 68" :fill "none"} + [svg/svg {:width "20" :height "20" :viewBox "0 0 20 20" :fill "none"} [svg/path - {:d - "M0 0H109V48H103.821C101.8 25.574 82.9522 8 60 8C36.9215 8 17.993 25.768 16.1475 48.3707C6.94517 50.1664 0 58.2721 0 68V0Z" + {:d "M20 0C7 2 0 10 0 20V0H15Z" :fill background-color}]]) -(defn right-shape +(defn right-radius [background-color] - [svg/svg {:width "25" :height "68" :viewBox "0 0 25 68" :fill "none"} + [svg/svg {:width "20" :height "21" :viewBox "0 0 20 21" :fill "none"} [svg/path - {:d "M0.000610352 0H24.5005V68L24.5003 68C24.5003 56.9543 15.546 48 4.50031 48H0.000610352V0Z" + {:d "M20 20V0H0C11 0 20 9 20 20Z" :fill background-color}]]) -(defn view - [customization-color theme] - (let [background-color (colors/resolve-color customization-color theme 40)] - [rn/view {:style style/header-shape-container} - [left-shape 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 + scroll-animation-input-range + [1 1 0])] + [rn/view [rn/view {:style (style/header-middle-shape background-color)}] - [right-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 index 9cbd381bb11a..8958137a0637 100644 --- a/src/status_im2/contexts/profile/settings/header/style.cljs +++ b/src/status_im2/contexts/profile/settings/header/style.cljs @@ -1,7 +1,6 @@ (ns status-im2.contexts.profile.settings.header.style - (:require [quo.foundations.colors :as colors])) -(defonce ^:const navigation-bar-height 100) -(defonce ^:const header-offset 56) + (:require [quo.foundations.colors :as colors] + [react-native.reanimated :as reanimated])) (defn header-view [customization-color theme] @@ -9,11 +8,12 @@ :min-height 100 :flex 1}) -(def avatar-container +(def avatar-row-wrapper {:display :flex - :padding-left 20 + :padding-left 16 :padding-right 12 - :margin-top -56 + :margin-top -60 + :margin-bottom -4 :align-items :flex-end :justify-content :space-between :flex-direction :row}) @@ -22,11 +22,27 @@ {:padding-horizontal 20 :padding-vertical 12}) -(def header-shape-container - {:flex-direction :row}) - (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 index f0182c11af0f..8de72eb8c041 100644 --- a/src/status_im2/contexts/profile/settings/header/view.cljs +++ b/src/status_im2/contexts/profile/settings/header/view.cljs @@ -1,8 +1,9 @@ (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] @@ -10,7 +11,7 @@ [utils.re-frame :as rf])) (defn- f-view - [theme] + [{: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]) @@ -19,29 +20,31 @@ profile-picture (profile.utils/photo profile) emoji-string (string/join emoji-hash)] [rn/view - [header.shape/view customization-color theme] - [rn/view {:style style/avatar-container} - [quo/user-avatar - {:full-name full-name + [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? - :profile-picture profile-picture - :status-indicator? true - :ring? true :customization-color customization-color - :size :big}] - [quo/dropdown - {:background :blur - :size :size-32 - :type :outline - :icon? true - :icon-name :i/online} - (i18n/label :t/status-always-online)]] + :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}]])) -(defn- internal-header-view +(defn view [params] [:f> f-view params]) -(def view (quo.theme/with-theme internal-header-view)) diff --git a/src/status_im2/contexts/profile/settings/view.cljs b/src/status_im2/contexts/profile/settings/view.cljs index 7d42a9fbd83c..24c60170009e 100644 --- a/src/status_im2/contexts/profile/settings/view.cljs +++ b/src/status_im2/contexts/profile/settings/view.cljs @@ -1,7 +1,9 @@ (ns status-im2.contexts.profile.settings.view - (:require [quo.core :as quo] + (: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.constants :as settings.constants] @@ -13,16 +15,26 @@ (defn- f-settings-item-view [data] - (println 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))) + +(def footer + [rn/view {:style style/footer-container} + [quo/button {: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])] + customization-color (rf/sub [:profile/customization-color]) + scroll-y (reanimated/use-shared-value 0)] [quo/overlay {:type :shell} [rn/view {:style {:flex 1}} [rn/view @@ -38,14 +50,18 @@ {:icon-name :i/share :on-press #(debounce/dispatch-and-chill [:open-modal :share-shell] 1000)}]}]] [rn/flat-list - {:header [settings.header/view] + {:header [settings.header/view {:scroll-y scroll-y}] :data settings.constants/settings-items :key-fn str :shows-vertical-scroll-indicator false :render-fn f-settings-item-view - :footer [rn/view {:style style/footer-container} - [quo/button {:type :danger :icon-left :i/log-out} - (i18n/label :t/logout)]] + :footer footer + :scroll-event-throttle 16 + :on-scroll #(scroll-handler % scroll-y) :bounces false}]]])) -(def view (quo.theme/with-theme settings-view)) +(defn- internal-view + [props] + [:f> settings-view props]) + +(def view (quo.theme/with-theme internal-view))