diff --git a/src/js/worklets/identifiers_highlighting.js b/src/js/worklets/identifiers_highlighting.js new file mode 100644 index 0000000000..2098d2b5dd --- /dev/null +++ b/src/js/worklets/identifiers_highlighting.js @@ -0,0 +1,92 @@ +import { useAnimatedStyle, useDerivedValue } from 'react-native-reanimated'; + +export function background(color, progress) { + return useDerivedValue(function () { + 'worklet'; + const r = parseInt(color.substring(1, 3), 16); + const g = parseInt(color.substring(3, 5), 16); + const b = parseInt(color.substring(5, 7), 16); + + return progress.value <= 25 ? `rgba(${r}, ${g}, ${b}, .4)` : `rgba(${r}, ${g}, ${b}, .2)`; + }); +} + +export function opacity(progress) { + return useDerivedValue(function () { + 'worklet'; + return progress.value <= 25 ? 1 : 0.3; + }); +} + +export function avatarOpacity(progress) { + return useDerivedValue(function () { + 'worklet'; + const progressValue = progress.value; + + switch (true) { + case progressValue <= 25: + return 1; + case progressValue <= 50: + return 0.1; + default: + return 0.3; + } + }); +} + +export function ringOpacity(progress) { + return useDerivedValue(function () { + 'worklet'; + return progress.value <= 50 ? 1 : 0.3; + }); +} + +export function userHashOpacity(progress) { + return useDerivedValue(function () { + 'worklet'; + const progressValue = progress.value; + switch (true) { + case progressValue <= 25: + return 1; + case progressValue <= 50: + return 0.3; + case progressValue <= 75: + return 1; + default: + return 0.3; + } + }); +} + +export function userHashColor(progress) { + return useDerivedValue(function () { + 'worklet'; + const progressValue = progress.value; + switch (true) { + case progressValue <= 25: + return 'rgba(255, 255, 255, .6)'; + case progressValue <= 50: + return 'rgba(255, 255, 255, .6)'; + case progressValue <= 75: + return 'rgb(255, 255, 255)'; + default: + return 'rgba(255, 255, 255, .6)'; + } + }); +} + +export function emojiHashStyle(progress) { + return useAnimatedStyle(function () { + 'worklet'; + const progressValue = progress.value; + + switch (true) { + case progressValue <= 25: + return { opacity: 1 }; + case progressValue <= 75: + return { opacity: 0.3 }; + default: + return { opacity: 1 }; + } + }); +} diff --git a/src/mocks/js_dependencies.cljs b/src/mocks/js_dependencies.cljs index 4b24be10a8..809460b9e5 100644 --- a/src/mocks/js_dependencies.cljs +++ b/src/mocks/js_dependencies.cljs @@ -364,77 +364,79 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return ( (defn mock [module] (case module - "react-native-languages" react-native-languages - "react-native-background-timer" background-timer - "react-native-image-crop-picker" image-crop-picker - "react-native-gesture-handler" react-native-gesture-handler - "react-native-static-safe-area-insets" react-native-static-safe-area-insets - "react-native-config" config - "react-native-iphone-x-helper" (clj->js {:getStatusBarHeight (fn []) - :getBottomSpace (fn [])}) - "react-native-screens" (clj->js {}) - "react-native-reanimated" react-native-reanimated - "react-native-redash/lib/module/v1" react-native-redash - "react-native-redash" react-native-redash - "react-native-fetch-polyfill" fetch - "react-native-status-keycard" status-keycard - "react-native-keychain" keychain - "react-native-touch-id" touchid - "@react-native-community/netinfo" net-info - "react-native-dialogs" dialogs - "react-native" react-native - "react-native-fs" fs - "react-native-mail" react-native-mail - "react-native-image-resizer" image-resizer - "react-native-haptic-feedback" react-native-haptic-feedback - "react-native-device-info" react-native-device-info - "react-native-push-notification" react-native-push-notification - "react-native-linear-gradient" react-native-gradien - "@react-native-community/masked-view" masked-view - "react-native-blob-util" react-native-blob-util - "react-native-navigation" react-native-navigation - "@react-native-community/push-notification-ios" push-notification-ios - "@react-native-community/blur" react-native-blur - "@react-native-community/cameraroll" react-native-camera-roll - "react-native-camera-kit" react-native-camera-kit - "react-native-permissions" react-native-permissions - "rn-emoji-keyboard" rn-emoji-keyboard - "react-native-hole-view" react-native-hole-view - "react-native-draggable-flatlist" react-native-draggable-flatlist - "react-native-webview" react-native-webview - "@react-native-community/audio-toolkit" react-native-audio-toolkit - "react-native-image-viewing" react-native-image-viewing - "react-native-share" react-native-share - "@react-native-async-storage/async-storage" async-storage - "react-native-svg" react-native-svg - "react-native-transparent-video" react-native-transparent-video - "react-native-orientation-locker" react-native-orientation-locker - "../src/js/worklets/core.js" worklet-factory - "../src/js/worklets/shell/bottom_tabs.js" #js {} - "../src/js/worklets/shell/home_stack.js" #js {} - "../src/js/worklets/shell/floating_screen.js" #js {} - "../src/js/worklets/bottom_sheet.js" #js {} - "../src/js/worklets/record_audio.js" #js {} - "../src/js/worklets/scroll_view.js" #js {} - "../src/js/worklets/onboarding_carousel.js" #js {} - "../src/js/worklets/lightbox.js" #js {} - "../src/js/worklets/parallax.js" #js {} - "./fleets.js" default-fleets - "@walletconnect/client" wallet-connect-client - "../translations/ar.json" (js/JSON.parse (slurp "./translations/ar.json")) - "../translations/de.json" (js/JSON.parse (slurp "./translations/de.json")) - "../translations/en.json" (js/JSON.parse (slurp "./translations/en.json")) - "../translations/es.json" (js/JSON.parse (slurp "./translations/es.json")) - "../translations/es_419.json" (js/JSON.parse (slurp "./translations/es_419.json")) - "../translations/fil.json" (js/JSON.parse (slurp "./translations/fil.json")) - "../translations/fr.json" (js/JSON.parse (slurp "./translations/fr.json")) - "../translations/id.json" (js/JSON.parse (slurp "./translations/id.json")) - "../translations/it.json" (js/JSON.parse (slurp "./translations/it.json")) - "../translations/ko.json" (js/JSON.parse (slurp "./translations/ko.json")) - "../translations/pt_BR.json" (js/JSON.parse (slurp "./translations/pt_BR.json")) - "../translations/ru.json" (js/JSON.parse (slurp "./translations/ru.json")) - "../translations/tr.json" (js/JSON.parse (slurp "./translations/tr.json")) - "../translations/zh.json" (js/JSON.parse (slurp "./translations/zh.json")) - "../translations/zh_hant.json" (js/JSON.parse (slurp "./translations/zh_hant.json")) - "../translations/zh_TW.json" (js/JSON.parse (slurp "./translations/zh_TW.json")) + "react-native-languages" react-native-languages + "react-native-background-timer" background-timer + "react-native-image-crop-picker" image-crop-picker + "react-native-gesture-handler" react-native-gesture-handler + "react-native-static-safe-area-insets" react-native-static-safe-area-insets + "react-native-config" config + "react-native-iphone-x-helper" (clj->js {:getStatusBarHeight (fn []) + :getBottomSpace (fn [])}) + "react-native-screens" (clj->js {}) + "react-native-reanimated" react-native-reanimated + "react-native-redash/lib/module/v1" react-native-redash + "react-native-redash" react-native-redash + "react-native-fetch-polyfill" fetch + "react-native-status-keycard" status-keycard + "react-native-keychain" keychain + "react-native-touch-id" touchid + "@react-native-community/netinfo" net-info + "react-native-dialogs" dialogs + "react-native" react-native + "react-native-fs" fs + "react-native-mail" react-native-mail + "react-native-image-resizer" image-resizer + "react-native-haptic-feedback" react-native-haptic-feedback + "react-native-device-info" react-native-device-info + "react-native-push-notification" react-native-push-notification + "react-native-linear-gradient" react-native-gradien + "@react-native-community/masked-view" masked-view + "react-native-blob-util" react-native-blob-util + "react-native-navigation" react-native-navigation + "@react-native-community/push-notification-ios" push-notification-ios + "@react-native-community/blur" react-native-blur + "@react-native-community/cameraroll" react-native-camera-roll + "react-native-camera-kit" react-native-camera-kit + "react-native-permissions" react-native-permissions + "rn-emoji-keyboard" rn-emoji-keyboard + "react-native-hole-view" react-native-hole-view + "react-native-draggable-flatlist" react-native-draggable-flatlist + "react-native-webview" react-native-webview + "@react-native-community/audio-toolkit" react-native-audio-toolkit + "react-native-image-viewing" react-native-image-viewing + "react-native-share" react-native-share + "@react-native-async-storage/async-storage" async-storage + "react-native-svg" react-native-svg + "react-native-transparent-video" react-native-transparent-video + "react-native-orientation-locker" react-native-orientation-locker + "../src/js/worklets/core.js" worklet-factory + "../src/js/worklets/shell/bottom_tabs.js" #js {} + "../src/js/worklets/shell/home_stack.js" #js {} + "../src/js/worklets/shell/floating_screen.js" #js {} + "../src/js/worklets/bottom_sheet.js" #js {} + "../src/js/worklets/record_audio.js" #js {} + "../src/js/worklets/scroll_view.js" #js {} + "../src/js/worklets/onboarding_carousel.js" #js {} + "../src/js/worklets/lightbox.js" #js {} + "../src/js/worklets/parallax.js" #js {} + "../src/js/worklets/identifiers_highlighting.js" #js {} + "./fleets.js" default-fleets + "@walletconnect/client" wallet-connect-client + "../translations/ar.json" (js/JSON.parse (slurp "./translations/ar.json")) + "../translations/de.json" (js/JSON.parse (slurp "./translations/de.json")) + "../translations/en.json" (js/JSON.parse (slurp "./translations/en.json")) + "../translations/es.json" (js/JSON.parse (slurp "./translations/es.json")) + "../translations/es_419.json" (js/JSON.parse (slurp "./translations/es_419.json")) + "../translations/fil.json" (js/JSON.parse (slurp "./translations/fil.json")) + "../translations/fr.json" (js/JSON.parse (slurp "./translations/fr.json")) + "../translations/id.json" (js/JSON.parse (slurp "./translations/id.json")) + "../translations/it.json" (js/JSON.parse (slurp "./translations/it.json")) + "../translations/ko.json" (js/JSON.parse (slurp "./translations/ko.json")) + "../translations/pt_BR.json" (js/JSON.parse (slurp "./translations/pt_BR.json")) + "../translations/ru.json" (js/JSON.parse (slurp "./translations/ru.json")) + "../translations/tr.json" (js/JSON.parse (slurp "./translations/tr.json")) + "../translations/zh.json" (js/JSON.parse (slurp "./translations/zh.json")) + "../translations/zh_hant.json" (js/JSON.parse (slurp + "./translations/zh_hant.json")) + "../translations/zh_TW.json" (js/JSON.parse (slurp "./translations/zh_TW.json")) nil)) diff --git a/src/react_native/reanimated.cljs b/src/react_native/reanimated.cljs index fb911dcc41..fc34787a80 100644 --- a/src/react_native/reanimated.cljs +++ b/src/react_native/reanimated.cljs @@ -34,6 +34,7 @@ (def create-animated-component (comp reagent/adapt-react-class (.-createAnimatedComponent reanimated))) (def view (reagent/adapt-react-class (.-View reanimated))) +(def text (reagent/adapt-react-class (.-Text reanimated))) (def scroll-view (reagent/adapt-react-class (.-ScrollView reanimated))) (def image (reagent/adapt-react-class (.-Image reanimated))) diff --git a/src/status_im2/contexts/onboarding/identifiers/profile_card/style.cljs b/src/status_im2/contexts/onboarding/identifiers/profile_card/style.cljs new file mode 100644 index 0000000000..5a50e09d66 --- /dev/null +++ b/src/status_im2/contexts/onboarding/identifiers/profile_card/style.cljs @@ -0,0 +1,69 @@ +(ns status-im2.contexts.onboarding.identifiers.profile-card.style + (:require [quo2.foundations.colors :as colors] + [react-native.reanimated :as reanimated] + [quo2.foundations.typography :as typography])) + +(def card-view + {:margin-horizontal 20 + :margin-bottom :auto + :flex-direction :row}) + +(defn card-container + [background-color] + (reanimated/apply-animations-to-style + {:background-color background-color} + {:padding-horizontal 12 + :padding-top 12 + :padding-bottom 12 + :flex 1 + :border-radius 16})) + +(def card-header + {:flex-direction :row + :justify-content :space-between}) + +(defn avatar + [opacity] + (reanimated/apply-animations-to-style + {:opacity opacity} + {})) + +(defn mask-view + [opacity] + (reanimated/apply-animations-to-style + {:opacity opacity} + {:width 48 + :background-color :transparent + :height 48 + :border-color :black + :border-width 2 + :border-radius 44})) + +(def picture-avatar-mask + {:width 48 + :height 48 + :border-radius 48}) + +(defn user-name-container + [opacity] + (reanimated/apply-animations-to-style + {:opacity opacity} + {:flex-direction :row + :margin-top 8 + :align-items :center + :padding-right 12})) + +(def user-name + {:color colors/white}) + +(defn user-hash + [user-hash-color user-hash-opacity] + (reanimated/apply-animations-to-style + {:color user-hash-color + :opacity user-hash-opacity} + (merge typography/monospace + typography/paragraph-1 + {:margin-top 2}))) + +(def emoji-hash + {:margin-top 12}) diff --git a/src/status_im2/contexts/onboarding/identifiers/profile_card/view.cljs b/src/status_im2/contexts/onboarding/identifiers/profile_card/view.cljs new file mode 100644 index 0000000000..aca94e591e --- /dev/null +++ b/src/status_im2/contexts/onboarding/identifiers/profile_card/view.cljs @@ -0,0 +1,68 @@ +(ns status-im2.contexts.onboarding.identifiers.profile-card.view + (:require [react-native.core :as rn] + [react-native.reanimated :as reanimated] + [react-native.masked-view :as masked-view] + [reagent.core :as reagent] + [quo2.core :as quo] + [quo2.foundations.colors :as colors] + [utils.worklets.identifiers-highlighting :as worklets.identifiers-highlighting] + [status-im2.contexts.onboarding.identifiers.profile-card.style :as style])) + +(defn- f-profile-card-component + [{:keys [profile-picture name hash emoji-hash + customization-color progress] + :or {customization-color :turquoise}}] + (let [container-background (worklets.identifiers-highlighting/background + (colors/custom-color customization-color 50) + @progress) + opacity (worklets.identifiers-highlighting/opacity @progress) + avatar-opacity (worklets.identifiers-highlighting/avatar-opacity @progress) + ring-opacity (worklets.identifiers-highlighting/ring-opacity @progress) + user-hash-color (worklets.identifiers-highlighting/user-hash-color @progress) + user-hash-opacity (worklets.identifiers-highlighting/user-hash-opacity @progress) + emoji-hash-style (worklets.identifiers-highlighting/emoji-hash-style @progress)] + [rn/view + {:style style/card-view} + [reanimated/view + {:style (style/card-container container-background)} + [rn/view {:style style/card-header} + [reanimated/view + {:style (style/avatar avatar-opacity)} + [quo/user-avatar + {:full-name name + :profile-picture profile-picture + :override-theme :dark + :size :medium + :status-indicator? false + :customization-color customization-color}]] + [masked-view/masked-view + {:style {:position :absolute} + :mask-element (reagent/as-element + [reanimated/view {:style (style/mask-view ring-opacity)}])} + (when profile-picture + [rn/image + {:accessibility-label :ring-background + :style style/picture-avatar-mask + :source profile-picture}])]] + [reanimated/view + {:style (style/user-name-container opacity)} + [quo/text + {:size :heading-2 + :weight :semi-bold + :number-of-lines 1 + :style style/user-name} name]] + [reanimated/text + {:number-of-lines 3 + :style (style/user-hash user-hash-color user-hash-opacity)} + hash] + [reanimated/view + {:style [emoji-hash-style]} + [quo/text + {:weight :monospace + :number-of-lines 1 + :style style/emoji-hash} + emoji-hash]]]])) + +(defn profile-card + [props] + [:f> f-profile-card-component props]) diff --git a/src/status_im2/contexts/onboarding/identifiers/style.cljs b/src/status_im2/contexts/onboarding/identifiers/style.cljs index 05571084e3..481959b83b 100644 --- a/src/status_im2/contexts/onboarding/identifiers/style.cljs +++ b/src/status_im2/contexts/onboarding/identifiers/style.cljs @@ -5,15 +5,11 @@ (def content-container {:position :absolute - :top 170 + :top 166 :bottom 0 :left 0 :right 0}) -(def card-style - {:margin-horizontal 20 - :margin-bottom :auto}) - (def button {:justify-self :flex-end :margin-bottom 46 diff --git a/src/status_im2/contexts/onboarding/identifiers/view.cljs b/src/status_im2/contexts/onboarding/identifiers/view.cljs index d9ce2d7b8b..1bf6821a10 100644 --- a/src/status_im2/contexts/onboarding/identifiers/view.cljs +++ b/src/status_im2/contexts/onboarding/identifiers/view.cljs @@ -5,6 +5,7 @@ [utils.re-frame :as rf] [quo2.core :as quo] [quo2.foundations.colors :as colors] + [status-im2.contexts.onboarding.identifiers.profile-card.view :as profile-card] [status-im2.contexts.onboarding.identifiers.style :as style] [status-im2.contexts.onboarding.common.background.view :as background] [status-im2.contexts.onboarding.common.carousel.view :as carousel] @@ -44,15 +45,13 @@ :gesture :tappable :header-text header-text}] [rn/view {:style style/content-container} - [quo/profile-card + [profile-card/profile-card {:profile-picture photo-path :name display-name :hash compressed-key - :customization-color color :emoji-hash emoji-string - :show-emoji-hash? true - :show-user-hash? true - :card-style style/card-style}] + :customization-color color + :progress progress}] [quo/button {:accessibility-label :skip-identifiers :on-press #(rf/dispatch [:navigate-to :enable-notifications]) diff --git a/src/utils/worklets/identifiers_highlighting.cljs b/src/utils/worklets/identifiers_highlighting.cljs new file mode 100644 index 0000000000..76e02fe0c5 --- /dev/null +++ b/src/utils/worklets/identifiers_highlighting.cljs @@ -0,0 +1,31 @@ +(ns utils.worklets.identifiers-highlighting) + +(def worklets (js/require "../src/js/worklets/identifiers_highlighting.js")) + +(defn background + [color progress] + (.background ^js worklets color progress)) + +(defn opacity + [progress] + (.opacity ^js worklets progress)) + +(defn avatar-opacity + [progress] + (.avatarOpacity ^js worklets progress)) + +(defn ring-opacity + [progress] + (.ringOpacity ^js worklets progress)) + +(defn user-hash-color + [progress] + (.userHashColor ^js worklets progress)) + +(defn user-hash-opacity + [progress] + (.userHashOpacity ^js worklets progress)) + +(defn emoji-hash-style + [progress] + (.emojiHashStyle ^js worklets progress))