diff --git a/nix/mobile/android/release.nix b/nix/mobile/android/release.nix index 35d327e861..392eada1e3 100644 --- a/nix/mobile/android/release.nix +++ b/nix/mobile/android/release.nix @@ -46,7 +46,7 @@ in stdenv.mkDerivation rec { root = path; include = [ "package.json" "yarn.lock" "metro.config.js" "babel.config.js" - "resources/.*" "translations/.*" "src/js/worklet_factory.js" + "resources/.*" "translations/.*" "src/js/.*" "modules/react-native-status/android.*" "android/.*" envFileName "VERSION" "status-go-version.json" "react-native.config.js" ]; diff --git a/resources/images/icons2/12x12/group@2x.png b/resources/images/icons2/12x12/group@2x.png new file mode 100644 index 0000000000..834569a502 Binary files /dev/null and b/resources/images/icons2/12x12/group@2x.png differ diff --git a/resources/images/icons2/12x12/group@3x.png b/resources/images/icons2/12x12/group@3x.png new file mode 100644 index 0000000000..9ac4b56689 Binary files /dev/null and b/resources/images/icons2/12x12/group@3x.png differ diff --git a/resources/images/icons2/20x20/group@2x.png b/resources/images/icons2/20x20/group@2x.png new file mode 100644 index 0000000000..a74433a640 Binary files /dev/null and b/resources/images/icons2/20x20/group@2x.png differ diff --git a/resources/images/icons2/20x20/group@3x.png b/resources/images/icons2/20x20/group@3x.png new file mode 100644 index 0000000000..f798aaf608 Binary files /dev/null and b/resources/images/icons2/20x20/group@3x.png differ diff --git a/resources/images/ui/switcher@2x.png b/resources/images/ui/switcher@2x.png deleted file mode 100644 index 7db491b627..0000000000 Binary files a/resources/images/ui/switcher@2x.png and /dev/null differ diff --git a/resources/images/ui/switcher@3x.png b/resources/images/ui/switcher@3x.png deleted file mode 100644 index dc105dbc21..0000000000 Binary files a/resources/images/ui/switcher@3x.png and /dev/null differ diff --git a/src/js/shell_worklets.js b/src/js/shell_worklets.js new file mode 100644 index 0000000000..5d0fb06baf --- /dev/null +++ b/src/js/shell_worklets.js @@ -0,0 +1,186 @@ +import { useDerivedValue, withTiming, withSequence, withDelay, Easing } from 'react-native-reanimated'; + +// Shell Worklets + +// Home Stack States +const CLOSE_WITH_ANIMATION = 0; +const OPEN_WITH_ANIMATION = 1; +const CLOSE_WITHOUT_ANIMATION = 3; +const OPEN_WITHOUT_ANIMATION = 4; + +// Derived Values +export function stackOpacity (stackId, selectedStackId) { + return useDerivedValue( + function () { + 'worklet' + return selectedStackId.value == stackId ? 1 : 0; + } + ); +} + +export function stackPointer (stackId, selectedStackId) { + return useDerivedValue( + function () { + 'worklet' + return selectedStackId.value == stackId ? "auto" : "none"; + } + ); +} + +export function bottomTabIconColor (stackId, selectedStackId, homeStackState, + passThrough, selectedTabColor, defaultColor, + passThroughColor) { + return useDerivedValue( + function () { + 'worklet' + var homeStackStateValue = homeStackState.value; + if (selectedStackId.value == stackId && + (homeStackStateValue == OPEN_WITH_ANIMATION || + homeStackStateValue == OPEN_WITHOUT_ANIMATION)){ + return selectedTabColor; + } + else if (passThrough.value){ + return passThroughColor; + } + else { + return defaultColor; + } + } + ); +} + +export function bottomTabsHeight(homeStackState, height, extendedHeight) { + return useDerivedValue( + function () { + 'worklet' + switch (homeStackState.value) { + case OPEN_WITH_ANIMATION: + return withTiming(extendedHeight, defaultDurationAndEasing); + break; + case CLOSE_WITH_ANIMATION: + return withTiming(height, defaultDurationAndEasing); + break; + case OPEN_WITHOUT_ANIMATION: + return extendedHeight; + break; + case CLOSE_WITHOUT_ANIMATION: + return height; + break; + } + } + ) +} + + +// Home Stack + +const shellAnimationTime = 200; + +const defaultDurationAndEasing = { + duration: shellAnimationTime, + easing: Easing.bezier(0, 0, 1, 1), +} + +export function homeStackOpacity (homeStackState) { + return useDerivedValue( + function () { + 'worklet' + switch (homeStackState.value) { + case OPEN_WITH_ANIMATION: + return withTiming(1, defaultDurationAndEasing); + break; + case CLOSE_WITH_ANIMATION: + return withTiming(0, defaultDurationAndEasing); + break; + case OPEN_WITHOUT_ANIMATION: + return 1; + break; + case CLOSE_WITHOUT_ANIMATION: + return 0; + break; + } + } + ); +} + +export function homeStackTop (homeStackState, top) { + return useDerivedValue( + function () { + 'worklet' + switch (homeStackState.value) { + case OPEN_WITH_ANIMATION: + return withTiming(0, defaultDurationAndEasing); + break; + case CLOSE_WITH_ANIMATION: + return withTiming(top, defaultDurationAndEasing); + break; + case OPEN_WITHOUT_ANIMATION: + return 0; + break; + case CLOSE_WITHOUT_ANIMATION: + return top; + break; + } + } + ); +} + +export function homeStackLeft (selectedStackId, animateHomeStackLeft, homeStackState, left) { + return useDerivedValue( + function () { + 'worklet' + if (animateHomeStackLeft.value) { + var leftValue = left[selectedStackId.value]; + switch (homeStackState.value) { + case OPEN_WITH_ANIMATION: + return withSequence(withTiming(leftValue, {duration: 0}), withTiming(0, defaultDurationAndEasing)) + break; + case CLOSE_WITH_ANIMATION: + return withTiming(leftValue, defaultDurationAndEasing); + break; + case OPEN_WITHOUT_ANIMATION: + return 0; + break; + case CLOSE_WITHOUT_ANIMATION: + return leftValue; + break; + } + } else { + return 0; + } + } + ); +} + +export function homeStackPointer (homeStackState) { + return useDerivedValue( + function () { + 'worklet' + var homeStackStateValue = homeStackState.value; + return (homeStackStateValue == OPEN_WITH_ANIMATION || + homeStackStateValue == OPEN_WITHOUT_ANIMATION) ? "auto" : "none"; + } + ); +} + +export function homeStackScale (homeStackState, minimizeScale) { + return useDerivedValue( + function () { + 'worklet' + switch (homeStackState.value) { + case OPEN_WITH_ANIMATION: + return withTiming(1, defaultDurationAndEasing); + break; + case CLOSE_WITH_ANIMATION: + return withTiming(minimizeScale, defaultDurationAndEasing); + break; + case OPEN_WITHOUT_ANIMATION: + return 1; + break; + case CLOSE_WITHOUT_ANIMATION: + return minimizeScale; + break; + } + } + ); +} diff --git a/src/js/worklet_factory.js b/src/js/worklet_factory.js index fadc3d4f7b..9886191fd8 100644 --- a/src/js/worklet_factory.js +++ b/src/js/worklet_factory.js @@ -1,5 +1,3 @@ -import { useDerivedValue, withTiming, withSequence, withDelay, Easing } from 'react-native-reanimated'; - // Generic Worklets export function applyAnimationsToStyle(animations, style) { @@ -29,106 +27,3 @@ export function applyAnimationsToStyle(animations, style) { return Object.assign(animatedStyle, style); }; }; - -// Switcher Worklets - -export function stackOpacity (stackId, selectedStackId) { - return useDerivedValue( - function () { - 'worklet' - return selectedStackId.value == stackId ? 1 : 0; - } - ); -} - -export function stackPointer (stackId, selectedStackId) { - return useDerivedValue( - function () { - 'worklet' - return selectedStackId.value == stackId ? "auto" : "none"; - } - ); -} - -export function bottomTabIconColor (stackId, selectedStackId, homeStackOpen, - passThrough, selectedTabColor, defaultColor, - passThroughColor) { - return useDerivedValue( - function () { - 'worklet' - if (selectedStackId.value == stackId && homeStackOpen.value){ - return selectedTabColor; - } - else if (passThrough.value){ - return passThroughColor; - } - else { - return defaultColor; - } - } - ); -} - - -// Home Stack - -const shellAnimationTime = 200; - -const defaultDurationAndEasing = { - duration: shellAnimationTime, - easing: Easing.bezier(0, 0, 1, 1), -} - -export function homeStackOpacity (homeStackOpen) { - return useDerivedValue( - function () { - 'worklet' - return withTiming(homeStackOpen.value ? 1 : 0, defaultDurationAndEasing); - } - ); -} - -export function homeStackTop (homeStackOpen, top) { - return useDerivedValue( - function () { - 'worklet' - return withTiming(homeStackOpen.value ? 0 : top, defaultDurationAndEasing); - } - ); -} - -export function homeStackLeft (selectedStackId, animateHomeStackLeft, homeStackOpen, left) { - return useDerivedValue( - function () { - 'worklet' - if (animateHomeStackLeft.value) { - var leftValue = left[selectedStackId.value]; - if (homeStackOpen.value) { - return withSequence(withTiming(leftValue, {duration: 0}), withTiming(0, defaultDurationAndEasing)) - } else { - return withTiming(leftValue, defaultDurationAndEasing); - } - } else { - return 0; - } - } - ); -} - -export function homeStackPointer (homeStackOpen) { - return useDerivedValue( - function () { - 'worklet' - return homeStackOpen.value ? "auto" : "none"; - } - ); -} - -export function homeStackScale (homeStackOpen, minimizeScale) { - return useDerivedValue( - function () { - 'worklet' - return withTiming(homeStackOpen.value ? 1 : minimizeScale, defaultDurationAndEasing); - } - ); -} diff --git a/src/mocks/js_dependencies.cljs b/src/mocks/js_dependencies.cljs index edf7c5c98c..a97a571362 100644 --- a/src/mocks/js_dependencies.cljs +++ b/src/mocks/js_dependencies.cljs @@ -282,6 +282,8 @@ (def worklet-factory #js {:applyAnimationsToStyle (fn [])}) +(def shell-worklets #js {}) + ;; Update i18n_resources.cljs (defn mock [module] (case module @@ -328,6 +330,7 @@ "@react-native-async-storage/async-storage" async-storage "react-native-svg" react-native-svg "../src/js/worklet_factory.js" worklet-factory + "../src/js/shell_worklets.js" shell-worklets "./fleets.js" default-fleets "./chats.js" default-chats "@walletconnect/client" wallet-connect-client diff --git a/src/quo2/components/avatars/group_avatar.cljs b/src/quo2/components/avatars/group_avatar.cljs index 6b773ad48f..d5fab5ac39 100644 --- a/src/quo2/components/avatars/group_avatar.cljs +++ b/src/quo2/components/avatars/group_avatar.cljs @@ -21,6 +21,6 @@ :align-items :center :justify-content :center :border-radius (/ container-size 2) - :background-color (colors/theme-alpha color 0.5 0.6)} - [icon/icon :i/group {:size icon-size ; TODO: group icon sizes 12 and 20 (small and large) are missing + :background-color (colors/custom-color-by-theme color 50 60)} + [icon/icon :i/group {:size icon-size :color colors/white-opa-70}]]))) diff --git a/src/quo2/components/navigation/floating_shell_button.cljs b/src/quo2/components/navigation/floating_shell_button.cljs index 6000744262..00f8a3ca0f 100644 --- a/src/quo2/components/navigation/floating_shell_button.cljs +++ b/src/quo2/components/navigation/floating_shell_button.cljs @@ -14,31 +14,35 @@ :customization-color customization-color}])) (defn floating-shell-button - "[floating-shell-button dynamic-buttons style] - dynamic-buttons - {:button-type {:on-press on-press :count count}}" - [dynamic-buttons style opacity-anim pointer-anim] - [:f> - (fn [] - (let [original-style (merge {:flex-direction :row - :margin-horizontal 12} style) - animated-style (reanimated/apply-animations-to-style - {:opacity opacity-anim - :pointer-events pointer-anim} - original-style)] - [reanimated/view {:style animated-style} - ;; Left Section - [rn/view {:style {:flex 1}} - [dynamic-button-view :search dynamic-buttons {:position :absolute - :right 8}]] - ;; Mid Section (jump-to) - [dynamic-button-view :jump-to dynamic-buttons nil] + "[floating-shell-button dynamic-buttons style opacity-anim pointer-anim] + dynamic-buttons {:button-type {:on-press on-press :count count}} + style override style + opacity-anim reanimated value (optional)" + ([dynamic-button style] + (floating-shell-button dynamic-button style nil)) + ([dynamic-buttons style opacity-anim] + [:f> + (fn [] + (let [original-style (merge {:flex-direction :row + :margin-horizontal 12 + :pointer-events :box-none} style) + animated-style (reanimated/apply-animations-to-style + (if opacity-anim + {:opacity opacity-anim} {}) + original-style)] + [reanimated/view {:style animated-style} + ;; Left Section + [rn/view {:style {:flex 1}} + [dynamic-button-view :search dynamic-buttons {:position :absolute + :right 8}]] + ;; Mid Section (jump-to) + [dynamic-button-view :jump-to dynamic-buttons nil] ;; Right Section - [rn/view {:style {:flex 1}} - [rn/view {:style {:position :absolute - :flex-direction :row - :right 0}} - [dynamic-button-view :mention dynamic-buttons {:margin-left 8}] - [dynamic-button-view :notification-down dynamic-buttons {:margin-left 8}] - [dynamic-button-view :notification-up dynamic-buttons {:margin-left 8}] - [dynamic-button-view :bottom dynamic-buttons {:margin-left 8}]]]]))]) + [rn/view {:style {:flex 1}} + [rn/view {:style {:position :absolute + :flex-direction :row + :right 0}} + [dynamic-button-view :mention dynamic-buttons {:margin-left 8}] + [dynamic-button-view :notification-down dynamic-buttons {:margin-left 8}] + [dynamic-button-view :notification-up dynamic-buttons {:margin-left 8}] + [dynamic-button-view :bottom dynamic-buttons {:margin-left 8}]]]]))])) diff --git a/src/status_im/chat/models.cljs b/src/status_im/chat/models.cljs index fea2b28d80..15856c5a67 100644 --- a/src/status_im/chat/models.cljs +++ b/src/status_im/chat/models.cljs @@ -265,12 +265,18 @@ (fx/defn navigate-to-chat-nav2 "Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data" {:events [:chat.ui/navigate-to-chat-nav2]} - [{db :db :as cofx} chat-id from-switcher?] + [{db :db :as cofx} chat-id from-shell?] (fx/merge cofx - {:db (assoc db :current-chat-id chat-id)} - (offload-messages chat-id) + {:dispatch [:navigate-to-nav2 :chat chat-id from-shell?]} + (when-not (= (:view-id db) :community) + (navigation/pop-to-root-tab :shell-stack)) + (close-chat) + (force-close-chat chat-id) + (fn [{:keys [db]}] + {:db (assoc db :current-chat-id chat-id)}) (preload-chat-data chat-id) - (navigation/navigate-to-nav2 :chat chat-id nil from-switcher?))) + #(when (group-chat? cofx chat-id) + (loading/load-chat % chat-id)))) (fx/defn handle-clear-history-response {:events [::history-cleared]} diff --git a/src/status_im/communities/core.cljs b/src/status_im/communities/core.cljs index 44803d4f65..94dcc29462 100644 --- a/src/status_im/communities/core.cljs +++ b/src/status_im/communities/core.cljs @@ -672,3 +672,10 @@ {::async-storage/get {:keys keys :cb #(re-frame/dispatch [::category-states-loaded community-id hashes %])}})) + +(fx/defn navigate-to-community + {:events [:communities/navigate-to-community]} + [cofx community-id] + (fx/merge cofx + (navigation/pop-to-root-tab :shell-stack) + (navigation/navigate-to-nav2 :community community-id true))) diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index d7f4230f0b..43e45e8e16 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -58,6 +58,7 @@ status-im.wallet-connect-legacy.core status-im.network.net-info status-im.visibility-status-popover.core + status-im2.contexts.shell.events [status-im.multiaccounts.model :as multiaccounts.model])) (re-frame/reg-fx diff --git a/src/status_im/multiaccounts/logout/core.cljs b/src/status_im/multiaccounts/logout/core.cljs index d3ad7ad351..882dd1b2e5 100644 --- a/src/status_im/multiaccounts/logout/core.cljs +++ b/src/status_im/multiaccounts/logout/core.cljs @@ -17,7 +17,7 @@ {:init-root-fx :progress :chat.ui/clear-inputs nil :chat.ui/clear-inputs-old nil - :new-ui/reset-bottom-tabs nil + :shell/reset-bottom-tabs nil :hide-popover nil ::logout nil ::multiaccounts/webview-debug-changed false diff --git a/src/status_im/react_native/resources.cljs b/src/status_im/react_native/resources.cljs index 5f4d1ca51c..47a79c0188 100644 --- a/src/status_im/react_native/resources.cljs +++ b/src/status_im/react_native/resources.cljs @@ -47,7 +47,6 @@ :collectible-dark (js/require "../resources/images/ui/collectible-dark.png") :hand-wave (js/require "../resources/images/ui/hand-wave.png") :graph (js/require "../resources/images/ui/graph.png") - :switcher (js/require "../resources/images/ui/switcher.png") :discover (js/require "../resources/images/ui/discover.png") :community-cover (js/require "../resources/images/ui/community-cover.png") :lifestyle (js/require "../resources/images/ui/lifestyle.png") diff --git a/src/status_im/ui/screens/communities/community.cljs b/src/status_im/ui/screens/communities/community.cljs index 343f8d1978..48355fd7a5 100644 --- a/src/status_im/ui/screens/communities/community.cljs +++ b/src/status_im/ui/screens/communities/community.cljs @@ -22,6 +22,7 @@ [status-im.ui.components.accordion :as accordion] [status-im.ui.components.list.views :as list] [status-im.ui.components.react :as react] + [quo2.components.navigation.floating-shell-button :as floating-shell-button] [quo.core :as quo] [quo.design-system.colors :as colors])) @@ -155,7 +156,7 @@ (assoc home-item :public? true) {:on-press (fn [] (rf/dispatch [:dismiss-keyboard]) - (rf/dispatch [:chat.ui/navigate-to-chat chat-id]) + (rf/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id]) (rf/dispatch [:search/home-filter-changed nil]) (rf/dispatch [:accept-all-activity-center-notifications-from-chat chat-id])) :on-long-press #(rf/dispatch [:bottom-sheet/show-sheet @@ -244,7 +245,7 @@ (i18n/label :t/fetch-community))]]])) (defn community [] - (let [{:keys [community-id from-chat]} (rf/sub [:get-screen-params])] + (let [{:keys [community-id from-chat]} (rf/sub [:get-screen-params :community])] (fn [] (let [{:keys [id chats name images members permissions color joined can-request-access? can-join? requested-to-join-at admin] @@ -301,5 +302,10 @@ {:show-border? true :center [quo/button {:on-press #(rf/dispatch [:communities/join id]) :type :secondary} - (i18n/label :t/follow)]}]))] + (i18n/label :t/follow)]}])) + [floating-shell-button/floating-shell-button + {:jump-to {:on-press #(rf/dispatch [:shell/navigate-to-jump-to]) + :label (i18n/label :t/jump-to)}} + {:position :absolute + :bottom 70}]] [unknown-community community-id]))))) diff --git a/src/status_im/ui/screens/home/views.cljs b/src/status_im/ui/screens/home/views.cljs index 01db525adc..2376f38880 100644 --- a/src/status_im/ui/screens/home/views.cljs +++ b/src/status_im/ui/screens/home/views.cljs @@ -12,7 +12,6 @@ [status-im.ui.screens.home.views.inner-item :as inner-item] [quo.design-system.colors :as colors] [quo.core :as quo] - [quo.platform :as platform] [status-im.add-new.core :as new-chat] [status-im.ui.components.search-input.view :as search-input] [status-im.add-new.db :as db] @@ -131,7 +130,7 @@ home-item {:on-press (fn [] (re-frame/dispatch [:dismiss-keyboard]) - (if (and config/new-ui-enabled? platform/android?) + (if config/new-ui-enabled? (re-frame/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id]) (re-frame/dispatch [:chat.ui/navigate-to-chat chat-id])) (re-frame/dispatch [:search/home-filter-changed nil]) @@ -148,7 +147,7 @@ home-item {:on-press (fn [] (re-frame/dispatch [:dismiss-keyboard]) - (if (and config/new-ui-enabled? platform/android?) + (if config/new-ui-enabled? (re-frame/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id]) (re-frame/dispatch [:chat.ui/navigate-to-chat chat-id])) (re-frame/dispatch [:search/home-filter-changed nil]) diff --git a/src/status_im/ui/screens/profile/user/views.cljs b/src/status_im/ui/screens/profile/user/views.cljs index 0c49ea92d9..24fa0034a6 100644 --- a/src/status_im/ui/screens/profile/user/views.cljs +++ b/src/status_im/ui/screens/profile/user/views.cljs @@ -110,13 +110,6 @@ :accessory (when mnemonic [components.common/counter {:size 22} 1]) :on-press #(re-frame/dispatch [:navigate-to :privacy-and-security])}] - (when config/quo-preview-enabled? - [quo/list-item - {:icon :main-icons/appearance - :title "Quo Preview" - :accessibility-label :appearance-settings-button - :chevron true - :on-press #(re-frame/dispatch [:navigate-to :quo-preview])}]) (when config/quo-preview-enabled? [quo/list-item {:icon :main-icons/appearance diff --git a/src/status_im/ui2/screens/chat/composer/view.cljs b/src/status_im/ui2/screens/chat/composer/view.cljs index 17a66d43a9..f1eb36c72f 100644 --- a/src/status_im/ui2/screens/chat/composer/view.cljs +++ b/src/status_im/ui2/screens/chat/composer/view.cljs @@ -170,7 +170,7 @@ (re-frame/dispatch [:dismiss-keyboard])) edit) [reanimated/view {:style (reanimated/apply-animations-to-style {:height shared-height} - {})} + {:z-index 2})} ;;INPUT MESSAGE bottom sheet [gesture/gesture-detector {:gesture bottom-sheet-gesture} [reanimated/view {:style (reanimated/apply-animations-to-style diff --git a/src/status_im/ui2/screens/chat/messages/message.cljs b/src/status_im/ui2/screens/chat/messages/message.cljs index c7b6ee255c..0ca6c51bcd 100644 --- a/src/status_im/ui2/screens/chat/messages/message.cljs +++ b/src/status_im/ui2/screens/chat/messages/message.cljs @@ -274,9 +274,9 @@ name] [rn/text description]]] [rn/view (style/community-view-button) - [rn/touchable-opacity {:on-press #(re-frame/dispatch [:navigate-to - :community - {:community-id (:id community)}])} + [rn/touchable-opacity {:on-press #(re-frame/dispatch + [:communities/navigate-to-community + {:community-id (:id community)}])} [rn/text {:style {:text-align :center :color quo.colors/blue}} (i18n/label :t/view)]]]]))) diff --git a/src/status_im/ui2/screens/chat/view.cljs b/src/status_im/ui2/screens/chat/view.cljs index d5745c01c3..4f145e8bca 100644 --- a/src/status_im/ui2/screens/chat/view.cljs +++ b/src/status_im/ui2/screens/chat/view.cljs @@ -5,6 +5,8 @@ [status-im.ui2.screens.chat.composer.view :as composer] [status-im.utils.debounce :as debounce] [quo.react-native :as rn] + [re-frame.core :as re-frame] + [status-im.i18n.i18n :as i18n] [quo2.components.buttons.button :as quo2.button] [quo2.foundations.colors :as colors] [status-im.ui.components.react :as react] @@ -14,6 +16,7 @@ [status-im.ui.components.icons.icons :as icons] [status-im.ui2.screens.chat.messages.pinned-message :as pinned-message] [re-frame.db] + [quo2.components.navigation.floating-shell-button :as floating-shell-button] [status-im.ui2.screens.chat.messages.message :as message])) (defn topbar-content [] @@ -77,10 +80,16 @@ [messages/messages-view {:chat chat :mutual-contact-requests-enabled? mutual-contact-requests-enabled? - :show-input? show-input?}] + :show-input? show-input? + :bottom-space 15}] ;;INPUT COMPOSER (when show-input? - [composer/composer chat-id])])) + [composer/composer chat-id]) + [floating-shell-button/floating-shell-button + {:jump-to {:on-press #(re-frame/dispatch [:shell/navigate-to-jump-to]) + :label (i18n/label :t/jump-to)}} + {:position :absolute + :bottom 117}]])) (defn chat [] (reagent/create-class diff --git a/src/status_im2/contexts/communities/home/view.cljs b/src/status_im2/contexts/communities/home/view.cljs index ed3e71c453..ff6fa6a7c7 100644 --- a/src/status_im2/contexts/communities/home/view.cljs +++ b/src/status_im2/contexts/communities/home/view.cljs @@ -14,7 +14,7 @@ {:on-press (fn [] (rf/dispatch [:communities/load-category-states id]) (rf/dispatch [:dismiss-keyboard]) - (rf/dispatch [:navigate-to :community {:community-id id}])) + (rf/dispatch [:navigate-to-nav2 :community {:community-id id}])) :on-long-press #(rf/dispatch [:bottom-sheet/show-sheet {:content (fn [] [home.actions/actions community-item])}])} diff --git a/src/status_im2/contexts/quo_preview/navigation/floating_shell_button.cljs b/src/status_im2/contexts/quo_preview/navigation/floating_shell_button.cljs index a5c0308eb0..4e5766aca1 100644 --- a/src/status_im2/contexts/quo_preview/navigation/floating_shell_button.cljs +++ b/src/status_im2/contexts/quo_preview/navigation/floating_shell_button.cljs @@ -52,8 +52,7 @@ [rn/view {:padding-vertical 60 :align-items :center} [quo2/floating-shell-button (mock-data @state) - nil (reanimated/use-shared-value 1) - (reanimated/use-shared-value "auto")]]]])])) + nil (reanimated/use-shared-value 1)]]]])])) (defn preview-floating-shell-button [] [rn/view {:background-color (colors/theme-colors colors/white colors/neutral-90) diff --git a/src/status_im2/contexts/quo_preview/switcher/switcher_cards.cljs b/src/status_im2/contexts/quo_preview/switcher/switcher_cards.cljs index 462573fd14..e419167be6 100644 --- a/src/status_im2/contexts/quo_preview/switcher/switcher_cards.cljs +++ b/src/status_im2/contexts/quo_preview/switcher/switcher_cards.cljs @@ -1,6 +1,7 @@ (ns status-im2.contexts.quo-preview.switcher.switcher-cards (:require [react-native.core :as rn] [reagent.core :as reagent] + [status-im2.contexts.shell.constants :as constants] [status-im2.contexts.quo-preview.preview :as preview] [quo2.foundations.colors :as colors] [status-im.react-native.resources :as resources] @@ -9,21 +10,21 @@ (def descriptor [{:label "Type" :key :type :type :select - :options [{:key :communities-discover + :options [{:key constants/communities-discover :value "Communities Discover"} - {:key :messaging + {:key constants/one-to-one-chat-card :value "Messaging"} - {:key :group-messaging + {:key constants/private-group-chat-card :value "Group Messaging"} - {:key :community-card + {:key constants/community-card :value "Community Card"} - {:key :browser-card + {:key constants/browser-card :value "Browser Card"} - {:key :wallet-card + {:key constants/wallet-card :value "Wallet Card"} - {:key :wallet-collectible + {:key constants/wallet-collectible :value "Wallet Collectible"} - {:key :wallet-graph + {:key constants/wallet-graph :value "Wallet Graph"}]} {:label "Title" :key :title @@ -105,23 +106,24 @@ :community-info {:type :kicked} (:audio :community :link :code) nil)) -(defn get-mock-data [data] +(defn get-mock-data [{:keys [type] :as data}] (merge data - {:banner (when (:banner? data) banner) + {:type type + :banner (when (:banner? data) banner) :content {:new-notifications? (:new-notifications? data) :notification-indicator (:notification-indicator data) :counter-label (:counter-label data) :content-type (:content-type data) :data (get-mock-content data)}} - (case (:type data) - :messaging {:avatar-params {:full-name (:title data)}} - :group-messaging {} - :community-card {:avatar-params community-avatar} + (case type + constants/one-to-one-chat-card {:avatar-params {:full-name (:title data)}} + constants/private-group-chat-card {} + constants/community-card {:avatar-params community-avatar} {}))) (defn cool-preview [] - (let [state (reagent/atom {:type :group-messaging + (let [state (reagent/atom {:type constants/private-group-chat-card :title "Alisher Yakupov" :customization-color :turquoise :new-notifications? true @@ -137,7 +139,7 @@ [preview/customizer state descriptor] [rn/view {:padding-vertical 60 :align-items :center} - [switcher-cards/card (:type @state) (get-mock-data @state)]]]]))) + [switcher-cards/card (get-mock-data @state)]]]]))) (defn preview-switcher-cards [] [rn/view {:background-color colors/neutral-100 diff --git a/src/status_im2/contexts/shell/animation.cljs b/src/status_im2/contexts/shell/animation.cljs index 8f61738644..a52d7023a5 100644 --- a/src/status_im2/contexts/shell/animation.cljs +++ b/src/status_im2/contexts/shell/animation.cljs @@ -1,5 +1,6 @@ (ns status-im2.contexts.shell.animation - (:require [re-frame.core :as re-frame] + (:require [reagent.core :as reagent] + [re-frame.core :as re-frame] [react-native.reanimated :as reanimated] [quo2.foundations.colors :as colors] [status-im2.contexts.shell.constants :as constants] @@ -7,20 +8,43 @@ ;;TODO remove when not used anymore [status-im.async-storage.core :as async-storage])) -;;;; Bottom Tabs & Home Stack Animations - +;; Atoms (def selected-stack-id (atom nil)) -(def home-stack-open? (atom false)) -(def pass-through? (atom false)) +(def home-stack-state (atom constants/close-with-animation)) +(def pass-through? (atom false)) ;; TODO - Use dynamic pass-through for transparent bottom tabs +(def shared-values-atom (atom nil)) -(def bottom-nav-tab-width 90) +;; Reagent atoms used for lazily loading home screen tabs +(def load-communities-stack? (reagent/atom false)) +(def load-chats-stack? (reagent/atom false)) +(def load-wallet-stack? (reagent/atom false)) +(def load-browser-stack? (reagent/atom false)) + +;; Helper Functions +(defn home-stack-open? [] + (let [state @home-stack-state] + (or (= state constants/open-with-animation) + (= state constants/open-without-animation)))) + +(defn load-stack [stack-id] + (case stack-id + :communities-stack (reset! load-communities-stack? true) + :chats-stack (reset! load-chats-stack? true) + :wallet-stack (reset! load-wallet-stack? true) + :browser-stack (reset! load-browser-stack? true) + "")) (defn selected-stack-id-loaded [stack-id] (reset! selected-stack-id stack-id) - (reset! home-stack-open? (some? stack-id))) + (reset! + home-stack-state + (if (some? stack-id) + constants/open-with-animation + constants/close-with-animation))) (defn calculate-home-stack-position [] (let [{:keys [width height]} (constants/dimensions) + bottom-nav-tab-width 90 minimize-scale (/ bottom-nav-tab-width width) empty-space-half-scale (/ (- 1 minimize-scale) 2) left-margin (/ (- width (* 4 bottom-nav-tab-width)) 2) @@ -36,81 +60,105 @@ :top (+ top-empty-space (constants/bottom-tabs-container-height)) :scale minimize-scale})) -(defn get-shared-values [] +(def shell-worklets (js/require "../src/js/shell_worklets.js")) + +;; Shared Values +(defn calculate-shared-values [] (let [selected-stack-id-sv (reanimated/use-shared-value ;; passing keywords or nil is not working with reanimated (name (or @selected-stack-id :communities-stack))) pass-through-sv (reanimated/use-shared-value @pass-through?) - home-stack-open-sv (reanimated/use-shared-value @home-stack-open?) - animate-home-stack-left (reanimated/use-shared-value (not @home-stack-open?)) + home-stack-state-sv (reanimated/use-shared-value @home-stack-state) + animate-home-stack-left (reanimated/use-shared-value (not (home-stack-open?))) home-stack-position (calculate-home-stack-position)] - (reduce - (fn [acc id] - (let [tabs-icon-color-keyword (get constants/tabs-icon-color-keywords id) - stack-opacity-keyword (get constants/stacks-opacity-keywords id) - stack-pointer-keyword (get constants/stacks-pointer-keywords id)] - (assoc - acc - stack-opacity-keyword (.stackOpacity - ^js reanimated/worklet-factory - (name id) selected-stack-id-sv) - stack-pointer-keyword (.stackPointer - ^js reanimated/worklet-factory - (name id) selected-stack-id-sv) - tabs-icon-color-keyword (.bottomTabIconColor - ^js reanimated/worklet-factory - (name id) selected-stack-id-sv home-stack-open-sv - pass-through-sv colors/white colors/neutral-50 - colors/white-opa-40)))) - {:selected-stack-id selected-stack-id-sv - :pass-through? pass-through-sv - :home-stack-open? home-stack-open-sv - :animate-home-stack-left animate-home-stack-left - :home-stack-left (.homeStackLeft - ^js reanimated/worklet-factory - selected-stack-id-sv animate-home-stack-left home-stack-open-sv - (clj->js (:left home-stack-position))) - :home-stack-top (.homeStackTop - ^js reanimated/worklet-factory - home-stack-open-sv (:top home-stack-position)) - :home-stack-opacity (.homeStackOpacity - ^js reanimated/worklet-factory home-stack-open-sv) - :home-stack-pointer (.homeStackPointer - ^js reanimated/worklet-factory home-stack-open-sv) - :home-stack-scale (.homeStackScale - ^js reanimated/worklet-factory home-stack-open-sv - (:scale home-stack-position))} - constants/stacks-ids))) + (reset! shared-values-atom + (reduce + (fn [acc id] + (let [tabs-icon-color-keyword (get constants/tabs-icon-color-keywords id) + stack-opacity-keyword (get constants/stacks-opacity-keywords id) + stack-pointer-keyword (get constants/stacks-pointer-keywords id)] + (assoc + acc + stack-opacity-keyword (.stackOpacity + ^js shell-worklets + (name id) selected-stack-id-sv) + stack-pointer-keyword (.stackPointer + ^js shell-worklets + (name id) selected-stack-id-sv) + tabs-icon-color-keyword (.bottomTabIconColor + ^js shell-worklets + (name id) selected-stack-id-sv home-stack-state-sv + pass-through-sv colors/white colors/neutral-50 + colors/white-opa-40)))) + {:selected-stack-id selected-stack-id-sv + :pass-through? pass-through-sv + :home-stack-state home-stack-state-sv + :animate-home-stack-left animate-home-stack-left + :home-stack-left (.homeStackLeft + ^js shell-worklets + selected-stack-id-sv animate-home-stack-left + home-stack-state-sv + (clj->js (:left home-stack-position))) + :home-stack-top (.homeStackTop + ^js shell-worklets + home-stack-state-sv (:top home-stack-position)) + :home-stack-opacity (.homeStackOpacity + ^js shell-worklets home-stack-state-sv) + :home-stack-pointer (.homeStackPointer + ^js shell-worklets home-stack-state-sv) + :home-stack-scale (.homeStackScale + ^js shell-worklets home-stack-state-sv + (:scale home-stack-position)) + :bottom-tabs-height (.bottomTabsHeight + ^js shell-worklets home-stack-state-sv + (constants/bottom-tabs-container-height) + (constants/bottom-tabs-extended-container-height))} + constants/stacks-ids))) + @shared-values-atom) -;; Animation +;; Animations -(defn open-home-stack [shared-values stack-id] - (reanimated/set-shared-value (:selected-stack-id shared-values) (name stack-id)) - (reanimated/set-shared-value (:home-stack-open? shared-values) true) - (when-not (colors/dark?) - (js/setTimeout - #(re-frame/dispatch [:change-root-status-bar-style :dark]) - constants/shell-animation-time)) - (reset! home-stack-open? true) +(defn open-home-stack [stack-id animate?] + (let [home-stack-state-value (if animate? + constants/open-with-animation + constants/open-without-animation)] + (reanimated/set-shared-value + (:selected-stack-id @shared-values-atom) (name stack-id)) + (reanimated/set-shared-value + (:home-stack-state @shared-values-atom) home-stack-state-value) + (when-not (colors/dark?) + (js/setTimeout + #(re-frame/dispatch [:change-root-status-bar-style :dark]) + constants/shell-animation-time)) + (reset! home-stack-state home-stack-state-value) + (reset! selected-stack-id stack-id) + (async-storage/set-item! :selected-stack-id stack-id))) + +(defn change-tab [stack-id] + (reanimated/set-shared-value (:animate-home-stack-left @shared-values-atom) false) + (reanimated/set-shared-value (:selected-stack-id @shared-values-atom) (name stack-id)) (reset! selected-stack-id stack-id) (async-storage/set-item! :selected-stack-id stack-id)) -(defn change-tab [shared-values stack-id] - (reanimated/set-shared-value (:animate-home-stack-left shared-values) false) - (reanimated/set-shared-value (:selected-stack-id shared-values) (name stack-id)) - (reset! selected-stack-id stack-id) - (async-storage/set-item! :selected-stack-id stack-id)) +(defn bottom-tab-on-press [stack-id] + (when-not (= stack-id @selected-stack-id) + (let [stack-load-delay (if (home-stack-open?) + 0 constants/shell-animation-time)] + (if (home-stack-open?) + (change-tab stack-id) + (open-home-stack stack-id true)) + (js/setTimeout #(load-stack stack-id) stack-load-delay)))) -(defn bottom-tab-on-press [shared-values stack-id] - (if @home-stack-open? - (change-tab shared-values stack-id) - (open-home-stack shared-values stack-id))) - -(defn close-home-stack [shared-values] - (reanimated/set-shared-value (:animate-home-stack-left shared-values) true) - (reanimated/set-shared-value (:home-stack-open? shared-values) false) - (when-not (colors/dark?) - (re-frame/dispatch [:change-root-status-bar-style :light])) - (reset! home-stack-open? false) - (reset! selected-stack-id nil) - (async-storage/set-item! :selected-stack-id nil)) +(defn close-home-stack [animate?] + (let [home-stack-state-value (if animate? + constants/close-with-animation + constants/close-without-animation)] + (reanimated/set-shared-value + (:animate-home-stack-left @shared-values-atom) true) + (reanimated/set-shared-value + (:home-stack-state @shared-values-atom) home-stack-state-value) + (when-not (colors/dark?) + (re-frame/dispatch [:change-root-status-bar-style :light])) + (reset! home-stack-state home-stack-state-value) + (reset! selected-stack-id nil) + (async-storage/set-item! :selected-stack-id nil))) diff --git a/src/status_im2/contexts/shell/bottom_tabs.cljs b/src/status_im2/contexts/shell/bottom_tabs.cljs index e10e944c3e..0e631bb384 100644 --- a/src/status_im2/contexts/shell/bottom_tabs.cljs +++ b/src/status_im2/contexts/shell/bottom_tabs.cljs @@ -1,41 +1,11 @@ (ns status-im2.contexts.shell.bottom-tabs - (:require [reagent.core :as reagent] - [re-frame.core :as re-frame] - [react-native.core :as rn] + (:require [react-native.core :as rn] + [react-native.reanimated :as reanimated] [status-im2.contexts.shell.style :as styles] [status-im2.contexts.shell.constants :as constants] [status-im2.contexts.shell.animation :as animation] [quo2.components.navigation.bottom-nav-tab :as bottom-nav-tab])) -;; Reagent atoms used for lazily loading home screen tabs -(def load-communities-tab? (reagent/atom false)) -(def load-chats-tab? (reagent/atom false)) -(def load-wallet-tab? (reagent/atom false)) -(def load-browser-tab? (reagent/atom false)) - -(defn load-selected-stack [stack-id] - (case stack-id - :communities-stack (reset! load-communities-tab? true) - :chats-stack (reset! load-chats-tab? true) - :wallet-stack (reset! load-wallet-tab? true) - :browser-stack (reset! load-browser-tab? true) - "")) - -(re-frame/reg-fx - :new-ui/reset-bottom-tabs - (fn [] - (let [selected-stack-id @animation/selected-stack-id] - (reset! load-communities-tab? (= selected-stack-id :communities-stack)) - (reset! load-chats-tab? (= selected-stack-id :chats-stack)) - (reset! load-wallet-tab? (= selected-stack-id :wallet-stack)) - (reset! load-browser-tab? (= selected-stack-id :browser-stack))))) - -(defn bottom-tab-on-press [shared-values stack-id] - (when-not (= stack-id @animation/selected-stack-id) - (let [stack-load-delay (if @animation/home-stack-open? 0 constants/shell-animation-time)] - (animation/bottom-tab-on-press shared-values stack-id) - (js/setTimeout #(load-selected-stack stack-id) stack-load-delay)))) - (defn bottom-tab [icon stack-id shared-values] [bottom-nav-tab/bottom-nav-tab {:test-ID stack-id @@ -43,14 +13,21 @@ :icon-color-anim (get shared-values (get constants/tabs-icon-color-keywords stack-id)) - :on-press #(bottom-tab-on-press shared-values stack-id) + :on-press #(animation/bottom-tab-on-press stack-id) :accessibility-label (str (name stack-id) "-tab")}]) -(defn bottom-tabs [shared-values] - (load-selected-stack @animation/selected-stack-id) - [rn/view {:style (styles/bottom-tabs-container false)} - [rn/view {:style (styles/bottom-tabs)} - [bottom-tab :i/communities :communities-stack shared-values] - [bottom-tab :i/messages :chats-stack shared-values] - [bottom-tab :i/wallet :wallet-stack shared-values] - [bottom-tab :i/browser :browser-stack shared-values]]]) +(defn bottom-tabs [] + [:f> + (fn [] + (let [shared-values @animation/shared-values-atom + original-style (styles/bottom-tabs-container @animation/pass-through?) + animated-style (reanimated/apply-animations-to-style + {:height (:bottom-tabs-height shared-values)} + original-style)] + (animation/load-stack @animation/selected-stack-id) + [reanimated/view {:style animated-style} + [rn/view {:style (styles/bottom-tabs)} + [bottom-tab :i/communities :communities-stack shared-values] + [bottom-tab :i/messages :chats-stack shared-values] + [bottom-tab :i/wallet :wallet-stack shared-values] + [bottom-tab :i/browser :browser-stack shared-values]]]))]) diff --git a/src/status_im2/contexts/shell/cards/style.cljs b/src/status_im2/contexts/shell/cards/style.cljs index 6975c09abd..6dedcc6840 100644 --- a/src/status_im2/contexts/shell/cards/style.cljs +++ b/src/status_im2/contexts/shell/cards/style.cljs @@ -16,7 +16,7 @@ :border-radius 16 :background-color (colors/alpha background-color 0.4)}) -(defn secondary-container [] +(def secondary-container {:width 160 :height 120 :border-radius 16 @@ -24,29 +24,29 @@ :position :absolute :background-color (:secondary-container-bg-color colors-map)}) -(defn title [] +(def title {:position :absolute :top 28 :margin-horizontal 12 :color (:title-color colors-map)}) -(defn title-props [] +(def title-props {:size :paragraph-1 :weight :semi-bold :number-of-lines 1 :ellipsize-mode :tail - :style (title)}) + :style title}) -(defn subtitle [] +(def subtitle {:position :absolute :top 50 :margin-horizontal 12 :color (:subtitle-color colors-map)}) -(defn subtitle-props [] +(def subtitle-props {:size :paragraph-2 :weight :medium - :style (subtitle)}) + :style subtitle}) (defn content-container [new-notifications?] {:position :absolute @@ -56,7 +56,7 @@ :margin-left 12 :margin-right (if new-notifications? 8 12)}) -(defn notification-container [] +(def notification-container {:position :absolute :width 20 :height 20 @@ -65,17 +65,17 @@ :justify-content :center :align-items :center}) -(defn last-message-text [] +(def last-message-text {:color (:last-message-text-color colors-map)}) -(defn last-message-text-props [] +(def last-message-text-props {:size :paragraph-2 :weight :regular :number-of-lines 1 :ellipsize-mode :tail - :style (last-message-text)}) + :style last-message-text}) -(defn close-button [] +(def close-button {:position :absolute :right 8 :top 8 @@ -88,14 +88,19 @@ :icon true :on-press on-press :override-theme :dark - :style (close-button)}) + :style close-button}) -(defn avatar-container [] - {:width 48 - :height 48 - :left 12 - :top 12 - :position :absolute}) +(def avatar-container + {:width 48 + :height 48 + :left 12 + :top 12 + :border-radius 26 + :border-width 26 + :border-color colors/neutral-95 + :justify-content :center + :align-items :center + :position :absolute}) (defn unread-dot [background-color] {:width 8 @@ -105,27 +110,33 @@ ;; Supporting Components -(defn sticker [] +(def sticker {:width 24 :height 24}) -(defn gif [] +(def gif {:width 24 :height 24 :border-radius 8}) -(defn community-avatar [] - {:width 48 - :height 48 - :border-radius 24}) +(defn community-avatar [customization-color] + {:width 48 + :height 48 + :border-radius 24 + ;; TODO - Update to fall back community avatar once designs are available + :justify-content :center + :align-items :center + :background-color (colors/custom-color + (or customization-color :primary) + 60)}) -(defn community-channel [] +(def community-channel {:margin-left 8 :color (:community-channel colors-map)}) -(defn community-channel-props [] +(def community-channel-props {:size :paragraph-2 :weight :medium :number-of-lines 1 :ellipsize-mode :tail - :style (community-channel)}) + :style community-channel}) diff --git a/src/status_im2/contexts/shell/cards/view.cljs b/src/status_im2/contexts/shell/cards/view.cljs index 399cfc03f6..284284501e 100644 --- a/src/status_im2/contexts/shell/cards/view.cljs +++ b/src/status_im2/contexts/shell/cards/view.cljs @@ -1,44 +1,40 @@ (ns status-im2.contexts.shell.cards.view - (:require [i18n.i18n :as i18n] + (:require [quo2.core :as quo] + [i18n.i18n :as i18n] [react-native.core :as rn] - [react-native.fast-image :as fast-image] + [clojure.string :as string] [quo2.foundations.colors :as colors] - [quo2.components.markdown.text :as text] - [quo2.components.buttons.button :as button] - [quo2.components.counter.counter :as counter] - [quo2.components.tags.status-tags :as status-tags] - [quo2.components.avatars.user-avatar :as user-avatar] - [quo2.components.avatars.group-avatar :as group-avatar] - [quo2.components.list-items.preview-list :as preview-list] - [quo2.components.avatars.channel-avatar :as channel-avatar] - [status-im2.contexts.shell.cards.style :as style])) + [react-native.fast-image :as fast-image] + [status-im2.contexts.shell.cards.style :as style] + [status-im2.contexts.shell.constants :as constants])) (defn content-container [{:keys [content-type data new-notifications? color-50]}] [rn/view {:style (style/content-container new-notifications?)} + ;; TODO - Use status-im.constants for content type (case content-type - :text [text/text (style/last-message-text-props) data] - :photo [preview-list/preview-list {:type :photo - :more-than-99-label (i18n/label :counter-99-plus) - :size 24 - :override-theme :dark} data] + :text [quo/text style/last-message-text-props data] + :photo [quo/preview-list {:type :photo + :more-than-99-label (i18n/label :counter-99-plus) + :size 24 + :override-theme :dark} data] :sticker [fast-image/fast-image {:source (:source data) - :style (style/sticker)}] + :style style/sticker}] :gif [fast-image/fast-image {:source (:source data) - :style (style/gif)}] + :style style/gif}] :channel [rn/view {:style {:flex-direction :row :align-items :center}} - [channel-avatar/channel-avatar + [quo/channel-avatar {:emoji (:emoji data) :emoji-background-color (colors/alpha color-50 0.1)}] - [text/text (style/community-channel-props) (:channel-name data)]] + [quo/text style/community-channel-props (:channel-name data)]] :community-info (case (:type data) - :pending [status-tags/status-tag - {:status :pending + :pending [quo/status-tag + {:status {:type :pending} :label (i18n/label :t/pending) :size :small :override-theme :dark}] - :kicked [status-tags/status-tag - {:status :negative + :kicked [quo/status-tag + {:status {:type :negative} :size :small :override-theme :dark :label (i18n/label :t/kicked)}] @@ -47,11 +43,11 @@ [:<>])]) (defn notification-container [{:keys [notification-indicator counter-label color-60]}] - [rn/view {:style (style/notification-container)} + [rn/view {:style style/notification-container} (if (= notification-indicator :counter) - [counter/counter {:outline false - :override-text-color colors/white - :override-bg-color color-60} counter-label] + [quo/counter {:outline false + :override-text-color colors/white + :override-bg-color color-60} counter-label] [rn/view {:style (style/unread-dot color-60)}])]) (defn bottom-container [{:keys [new-notifications?] :as content}] @@ -62,16 +58,29 @@ (defn avatar [avatar-params type customization-color] (case type - :messaging [user-avatar/user-avatar - (merge {:ring? false - :size :medium - :status-indicator? false} - avatar-params)] - :group-messaging [group-avatar/group-avatar {:color customization-color - :size :large - :override-theme :dark}] - :community-card [fast-image/fast-image {:source (:source avatar-params) - :style (style/community-avatar)}])) + constants/one-to-one-chat-card + [quo/user-avatar + (merge {:ring? false + :size :medium + :status-indicator? false} + avatar-params)] + + constants/private-group-chat-card + [quo/group-avatar {:color customization-color + :size :large + :override-theme :dark}] + + constants/community-card + (if (:source avatar-params) + [fast-image/fast-image + {:source (:source avatar-params) + :style (style/community-avatar customization-color)}] + ;; TODO - Update to fall back community avatar once designs are available + [rn/view {:style (style/community-avatar customization-color)} + [quo/text {:weight :semi-bold + :size :heading-2 + :style {:color colors/white-opa-70}} + (string/upper-case (first (:name avatar-params)))]]))) (defn subtitle [{:keys [content-type data]}] (case content-type @@ -84,7 +93,8 @@ :link (i18n/label :t/external-link) :code (i18n/label :t/code-snippet) :channel (i18n/label :t/community-channel) - :community-info (i18n/label :t/community))) + :community-info (i18n/label :t/community) + (i18n/label :t/community))) ;; Screens Card (defn screens-card [{:keys [avatar-params title type customization-color @@ -96,14 +106,14 @@ (when banner [rn/image {:source (:source banner) :style {:width 160}}]) - [rn/view {:style (style/secondary-container)} - [text/text (style/title-props) title] - [text/text (style/subtitle-props) (subtitle content)] + [rn/view {:style style/secondary-container} + [quo/text style/title-props title] + [quo/text style/subtitle-props (subtitle content)] [bottom-container (merge {:color-50 color-50 :color-60 color-60} content)]] - (when avatar - [rn/view {:style (style/avatar-container)} + (when avatar-params + [rn/view {:style style/avatar-container} [avatar avatar-params type customization-color]]) - [button/button (style/close-button-props on-close) :i/close]]])) + [quo/button (style/close-button-props on-close) :i/close]]])) ;; browser Card (defn browser-card [_] @@ -123,13 +133,28 @@ (defn communities-discover [_] [:<>]) -(defn card [type data] +(defn card [{:keys [type] :as data}] (case type - :communities-discover [communities-discover data] ;; Home Card - :messaging [screens-card data] ;; Screens Card - :group-messaging [screens-card data] ;; Screens Card - :community-card [screens-card data] ;; Screens Card - :browser-card [browser-card data] ;; Browser Card - :wallet-card [wallet-card data] ;; Wallet Card - :wallet-collectible [wallet-collectible data] ;; Wallet Card - :wallet-graph [wallet-graph data])) ;; Wallet Card + constants/one-to-one-chat-card ;; Screens Card + [screens-card data] + + constants/private-group-chat-card ;; Screens Card + [screens-card data] + + constants/community-card ;; Screens Card + [screens-card data] + + constants/browser-card ;; Browser Card + [browser-card data] + + constants/wallet-card ;; Wallet Card + [wallet-card data] + + constants/wallet-collectible ;; Wallet Card + [wallet-collectible data] + + constants/wallet-graph ;; Wallet Card + [wallet-graph data] + + constants/communities-discover ;; Home Card + [communities-discover data])) diff --git a/src/status_im2/contexts/shell/constants.cljs b/src/status_im2/contexts/shell/constants.cljs index 1ecffea652..514c76a4b1 100644 --- a/src/status_im2/contexts/shell/constants.cljs +++ b/src/status_im2/contexts/shell/constants.cljs @@ -8,6 +8,9 @@ (defn bottom-tabs-container-height [] (if platform/android? 57 82)) +(defn bottom-tabs-extended-container-height [] + (if platform/android? 90 120)) + (defn status-bar-offset [] (if platform/android? (.-currentHeight ^js rn/status-bar) 0)) @@ -39,3 +42,20 @@ :chats-stack :chats-tab-icon-opacity :wallet-stack :wallet-tab-icon-opacity :browser-stack :browser-tab-icon-opacity}) + +;; Home stack states + +(def ^:const close-with-animation 0) +(def ^:const open-with-animation 1) +(def ^:const close-without-animation 3) +(def ^:const open-without-animation 4) + +;; Switcher Cards +(def ^:const one-to-one-chat-card 0) +(def ^:const private-group-chat-card 1) +(def ^:const community-card 2) +(def ^:const browser-card 3) +(def ^:const wallet-card 4) +(def ^:const wallet-collectible 5) +(def ^:const wallet-graph 6) +(def ^:const communities-discover 7) diff --git a/src/status_im2/contexts/shell/events.cljs b/src/status_im2/contexts/shell/events.cljs new file mode 100644 index 0000000000..c92f215ee4 --- /dev/null +++ b/src/status_im2/contexts/shell/events.cljs @@ -0,0 +1,90 @@ +(ns status-im2.contexts.shell.events + (:require [utils.re-frame :as rf] + [re-frame.core :as re-frame] + [status-im2.navigation.events :as navigation] + [status-im.constants :as constants] + [status-im2.contexts.shell.animation :as animation] + [status-im2.contexts.shell.constants :as shell.constants])) + +;; Effects + +(re-frame/reg-fx + :shell/navigate-to-jump-to-fx + (fn [] + (animation/close-home-stack false))) + +(re-frame/reg-fx + :shell/navigate-from-shell-fx + (fn [stack-id] + (js/setTimeout #(animation/bottom-tab-on-press stack-id) 500))) + +(re-frame/reg-fx + :shell/reset-bottom-tabs + (fn [] + (let [selected-stack-id @animation/selected-stack-id] + (reset! animation/load-communities-stack? (= selected-stack-id :communities-stack)) + (reset! animation/load-chats-stack? (= selected-stack-id :chats-stack)) + (reset! animation/load-wallet-stack? (= selected-stack-id :wallet-stack)) + (reset! animation/load-browser-stack? (= selected-stack-id :browser-stack))))) + +;; Events + +(rf/defn add-switcher-card + {:events [:shell/add-switcher-card]} + [{:keys [db now] :as cofx} view-id id] + (case view-id + :chat + (let [chat (get-in db [:chats id])] + (case (:chat-type chat) + constants/one-to-one-chat-type + {:shell/navigate-from-shell-fx :chats-stack + :db (assoc-in + db [:shell/switcher-cards id] + {:type shell.constants/one-to-one-chat-card + :id id + :clock now})} + + constants/private-group-chat-type + {:shell/navigate-from-shell-fx :chats-stack + :db (assoc-in + db [:shell/switcher-cards id] + {:type shell.constants/private-group-chat-card + :id id + :clock now})} + + constants/community-chat-type + {:shell/navigate-from-shell-fx :communities-stack + :db (assoc-in + db [:shell/switcher-cards (:community-id chat)] + {:type shell.constants/community-card + :id (:community-id chat) + :clock now + :content {:content-type :channel + :data {:emoji (:emoji chat) + :channel-id (:chat-id chat) + :channel-name (:chat-name chat)}}})} + + nil)) + + :community + {:shell/navigate-from-shell-fx :communities-stack + :db (assoc-in + db [:shell/switcher-cards (:community-id id)] + {:type shell.constants/community-card + :id (:community-id id) + :clock now})} + + nil)) + +(rf/defn close-switcher-card + {:events [:shell/close-switcher-card]} + [{:keys [db]} id] + {:db (update-in db [:shell/switcher-cards] dissoc id)}) + +(rf/defn navigate-to-jump-to + {:events [:shell/navigate-to-jump-to]} + [cofx] + (rf/merge + cofx + {:shell/navigate-to-jump-to-fx nil} + (navigation/pop-to-root-tab :shell-stack))) diff --git a/src/status_im2/contexts/shell/home_stack.cljs b/src/status_im2/contexts/shell/home_stack.cljs index 67be1f5c60..edd9fc5559 100644 --- a/src/status_im2/contexts/shell/home_stack.cljs +++ b/src/status_im2/contexts/shell/home_stack.cljs @@ -2,8 +2,8 @@ (:require [react-native.reanimated :as reanimated] [react-native.core :as rn] [status-im2.contexts.shell.style :as styles] + [status-im2.contexts.shell.animation :as animation] [status-im2.contexts.shell.constants :as constants] - [status-im2.contexts.shell.bottom-tabs :as bottom-tabs] [status-im2.contexts.communities.home.view :as communities] [status-im2.contexts.chat.home.view :as chat] @@ -14,10 +14,10 @@ (defn load-stack? [stack-id] (case stack-id - :communities-stack @bottom-tabs/load-communities-tab? - :chats-stack @bottom-tabs/load-chats-tab? - :browser-stack @bottom-tabs/load-browser-tab? - :wallet-stack @bottom-tabs/load-wallet-tab?)) + :communities-stack @animation/load-communities-stack? + :chats-stack @animation/load-chats-stack? + :browser-stack @animation/load-browser-stack? + :wallet-stack @animation/load-wallet-stack?)) (defn stack-view [stack-id shared-values] (when (load-stack? stack-id) @@ -39,12 +39,13 @@ :wallet-stack [wallet.accounts/accounts-overview] :browser-stack [profile.user/my-profile])])])) -(defn home-stack [shared-values] +(defn home-stack [] [safe-area/consumer (fn [insets] [:f> (fn [] - (let [home-stack-original-style (styles/home-stack) + (let [shared-values @animation/shared-values-atom + home-stack-original-style (styles/home-stack) home-stack-animated-style (reanimated/apply-animations-to-style {:top (:home-stack-top shared-values) :left (:home-stack-left shared-values) diff --git a/src/status_im2/contexts/shell/view.cljs b/src/status_im2/contexts/shell/view.cljs index 5006abc808..de2d6e1c9e 100644 --- a/src/status_im2/contexts/shell/view.cljs +++ b/src/status_im2/contexts/shell/view.cljs @@ -1,17 +1,20 @@ (ns status-im2.contexts.shell.view - (:require [i18n.i18n :as i18n] + (:require [quo2.core :as quo] + [i18n.i18n :as i18n] + [utils.re-frame :as rf] [react-native.core :as rn] - [react-native.safe-area :as safe-area] - [quo2.core :as quo] [quo2.foundations.colors :as colors] + [react-native.safe-area :as safe-area] + [status-im2.common.home.view :as common.home] [status-im2.contexts.shell.constants :as constants] [status-im2.contexts.shell.animation :as animation] [status-im2.contexts.shell.home-stack :as home-stack] [status-im2.contexts.shell.bottom-tabs :as bottom-tabs] - [status-im2.common.home.view :as common.home])) - -;;TODO move styles to style namespace + [status-im2.contexts.shell.cards.view :as switcher-cards])) +;; TODO +;; 1 : Update Placeholder screen as per new designs +;; 2 : Move styles to style namespace (defn placeholder [] [rn/view {:style {:position :absolute :top 0 @@ -38,38 +41,77 @@ :color colors/white}} (i18n/label :t/shell-placeholder-subtitle)]]) +(defn jump-to-text [] + [quo/text {:size :heading-1 + :weight :semi-bold + :style {:color colors/white + :margin-top (+ 68 (.-currentHeight ^js rn/status-bar)) + :margin-bottom 20 + :margin-left 20}} + (i18n/label :t/jump-to)]) + +(defn render-card [{:keys [id type content] :as card}] + (let [card-data (case type + constants/one-to-one-chat-card + (rf/sub [:shell/one-to-one-chat-card id]) + + constants/private-group-chat-card + (rf/sub [:shell/private-group-chat-card id]) + + constants/community-card + (if content + (rf/sub [:shell/community-channel-card + id (get-in content [:data :channel-id]) + content]) + (rf/sub [:shell/community-card id])))] + [switcher-cards/card (merge card card-data)])) + +(defn jump-to-list [switcher-cards shell-margin] + (if (seq switcher-cards) + [rn/flat-list + {:data switcher-cards + :render-fn render-card + :key-fn :id + :header (jump-to-text) + :num-columns 2 + :column-wrapper-style {:margin-horizontal shell-margin + :justify-content :space-between + :margin-bottom 16} + :style {:top 0 + :left 0 + :right 0 + :bottom -1 + :position :absolute}}] + [placeholder])) + (defn shell [] - [safe-area/consumer - (fn [insets] - [rn/view {:style {:top 0 - :left 0 - :right 0 - :bottom -1 - :position :absolute - :background-color colors/neutral-100}} - [common.home/top-nav {:type :shell - :style {:margin-top (:top insets)}}] - [placeholder] - [rn/scroll-view {:style {:padding-horizontal 20 - :flex-direction :row}} - [quo/text {:size :heading-1 - :weight :semi-bold - :style {:color colors/white - :margin-top 12}} - (i18n/label :t/jump-to)]]])]) + (let [switcher-cards (rf/sub [:shell/sorted-switcher-cards]) + width (rf/sub [:dimensions/window-width]) + shell-margin (/ (- width 320) 3)] ;; 320 - two cards width + [safe-area/consumer + (fn [insets] + [rn/view {:style {:top 0 + :left 0 + :right 0 + :bottom -1 + :position :absolute + :background-color colors/neutral-100}} + [common.home/top-nav {:type :shell + :style {:margin-top (:top insets) + :z-index 2}}] + [jump-to-list switcher-cards shell-margin]])])) (defn shell-stack [] [:f> (fn [] - (let [shared-values (animation/get-shared-values)] + (let [shared-values (animation/calculate-shared-values)] [:<> [shell] - [bottom-tabs/bottom-tabs shared-values] - [home-stack/home-stack shared-values] + [bottom-tabs/bottom-tabs] + [home-stack/home-stack] [quo/floating-shell-button - {:jump-to {:on-press #(animation/close-home-stack shared-values) - :label (i18n/label :t/jump-to)}} + {:jump-to {:on-press #(animation/close-home-stack true) + :label (i18n/label :t/jump-to)}} {:position :absolute :bottom (+ (constants/bottom-tabs-container-height) 7)} ;; bottom offset is 12 = 7 + 5(padding on button) - (:home-stack-opacity shared-values) - (:home-stack-pointer shared-values)]]))]) + (:home-stack-opacity shared-values)]]))]) diff --git a/src/status_im2/navigation/events.cljs b/src/status_im2/navigation/events.cljs index e2eced61a5..561f1b7c01 100644 --- a/src/status_im2/navigation/events.cljs +++ b/src/status_im2/navigation/events.cljs @@ -104,34 +104,16 @@ (rf/defn reload-new-ui {:events [:reload-new-ui]} [_] - {:new-ui/reset-bottom-tabs nil + {:shell/reset-bottom-tabs nil :dispatch [:init-root :shell-stack]}) -(defn navigate-from-shell-stack [go-to-view-id id db now] - {:navigate-to-fx go-to-view-id - :db (assoc-in db [:navigation2/navigation2-stacks id] {:type go-to-view-id - :id id - :clock now})}) - -(defn navigate-from-switcher [go-to-view-id id db from-home? now] - (merge (if from-home? - {:navigate-to-fx go-to-view-id} - {:set-stack-root-fx [go-to-view-id id]}) - {:db (assoc-in db [:navigation2/navigation2-stacks id] {:type go-to-view-id - :id id - :clock now})})) - (rf/defn navigate-to-nav2 {:events [:navigate-to-nav2]} - [{:keys [db now]} go-to-view-id id _ from-switcher?] - (let [view-id (:view-id db) - from-home? (= view-id :chat-stack)] - (if from-switcher? - (navigate-from-switcher go-to-view-id id db from-home? now) - (if from-home? - (navigate-from-shell-stack go-to-view-id id db now) - ;; TODO(parvesh) - new stacks created from other screens should be stacked on current stack, instead of creating new entry - (navigate-from-shell-stack go-to-view-id id db now))))) + [cofx view-id screen-params from-shell?] + (rf/merge + cofx + {:dispatch [:shell/add-switcher-card view-id screen-params from-shell?]} + (navigate-to-cofx view-id screen-params))) (rf/defn change-root-status-bar-style {:events [:change-root-status-bar-style]} diff --git a/src/status_im2/subs/general.cljs b/src/status_im2/subs/general.cljs index 434df97750..a316ad48ad 100644 --- a/src/status_im2/subs/general.cljs +++ b/src/status_im2/subs/general.cljs @@ -286,21 +286,6 @@ (fn [{:keys [mnemonic]}] (if mnemonic 1 0))) -;; NAVIGATION2 - -(re-frame/reg-sub - :navigation2/switcher-cards - :<- [:navigation2/navigation2-stacks] - (fn [stacks [_ toggle-switcher-screen]] - (sort-by :clock > - (reduce (fn [acc stack-vector] - (let [{:keys [type clock id]} (get stack-vector 1)] - (conj acc {:type type - :clock clock - :id id - :toggle-switcher-screen toggle-switcher-screen}))) - '() stacks)))) - (re-frame/reg-sub :mobile-network/syncing-allowed? :<- [:network/type] diff --git a/src/status_im2/subs/root.cljs b/src/status_im2/subs/root.cljs index e25617da8e..a9cfed6da0 100644 --- a/src/status_im2/subs/root.cljs +++ b/src/status_im2/subs/root.cljs @@ -18,6 +18,7 @@ status-im2.subs.pairing status-im2.subs.search status-im2.subs.stickers + status-im2.subs.shell status-im2.subs.wallet.signing status-im2.subs.wallet.transactions status-im2.subs.wallet.wallet)) @@ -64,7 +65,7 @@ (reg-root-key-sub :home-items-show-number :home-items-show-number) (reg-root-key-sub :waku/v2-peer-stats :peer-stats) (reg-root-key-sub :visibility-status-updates :visibility-status-updates) -(reg-root-key-sub :navigation2/navigation2-stacks :navigation2/navigation2-stacks) +(reg-root-key-sub :shell/switcher-cards :shell/switcher-cards) ;;NOTE this one is not related to ethereum network ;; it is about cellular network/ wifi network diff --git a/src/status_im2/subs/shell.cljs b/src/status_im2/subs/shell.cljs new file mode 100644 index 0000000000..0b4063920e --- /dev/null +++ b/src/status_im2/subs/shell.cljs @@ -0,0 +1,99 @@ +(ns status-im2.subs.shell + (:require [re-frame.core :as re-frame] + [status-im.constants :as status-constants] + [status-im.react-native.resources :as resources])) + +(defn get-card-content [chat] + (let [last-message (:last-message chat)] + (case (:content-type last-message) + status-constants/content-type-text + {:content-type :text + :data (get-in last-message [:content :text])} + + {:content-type :text + :data "Todo: Implement"}))) + +(defn one-to-one-chat-card [contact names chat id] + (let [images (:images contact) + profile-picture (:uri (or (:thumbnail images) (:large images) (first images)))] + {:title (first names) + :avatar-params {:full-name (last names) + :profile-picture (when profile-picture + (str profile-picture "&addRing=0"))} + :customization-color (or (:customization-color contact) :primary) + :on-close #(re-frame/dispatch [:shell/close-switcher-card id]) + :on-press #(re-frame/dispatch [:chat.ui/navigate-to-chat-nav2 id true]) + :content (get-card-content chat)})) + +(defn private-group-chat-card [chat id] + {:title (:chat-name chat) + :avatar-params {} + :customization-color (or (:customization-color chat) :primary) + :on-close #(re-frame/dispatch [:shell/close-switcher-card id]) + :on-press #(re-frame/dispatch [:chat.ui/navigate-to-chat-nav2 id true]) + :content (get-card-content chat)}) + +(defn community-card [community id content] + (let [images (:images community) + profile-picture (if (= id status-constants/status-community-id) + (resources/get-image :status-logo) + (when images + {:uri (:uri (or (:thumbnail images) + (:large images) + (first images)))}))] + {:title (:name community) + :avatar-params (if profile-picture + {:source profile-picture} + {:name (:name community)}) + :customization-color (or (:customization-color community) :primary) + :on-close #(re-frame/dispatch [:shell/close-switcher-card id]) + :on-press #(re-frame/dispatch [:navigate-to-nav2 :community + {:community-id id} true]) + :content (or content {:content-type :community-info + :data {:type :permission}})})) + +(defn community-channel-card [community community-id _ channel-id content] + (merge + (community-card community community-id content) + {:on-press (fn [] + (re-frame/dispatch [:navigate-to :community {:community-id community-id}]) + (js/setTimeout + #(re-frame/dispatch [:chat.ui/navigate-to-chat-nav2 channel-id true]) + 100))})) + +(re-frame/reg-sub + :shell/sorted-switcher-cards + :<- [:shell/switcher-cards] + (fn [stacks] + (sort-by :clock > (map val stacks)))) + +(re-frame/reg-sub + :shell/one-to-one-chat-card + (fn [[_ id] _] + [(re-frame/subscribe [:contacts/contact-by-identity id]) + (re-frame/subscribe [:contacts/contact-two-names-by-identity id]) + (re-frame/subscribe [:chats/chat id])]) + (fn [[contact names chat] [_ id]] + (one-to-one-chat-card contact names chat id))) + +(re-frame/reg-sub + :shell/private-group-chat-card + (fn [[_ id] _] + [(re-frame/subscribe [:chats/chat id])]) + (fn [[chat] [_ id]] + (private-group-chat-card chat id))) + +(re-frame/reg-sub + :shell/community-card + (fn [[_ id] _] + [(re-frame/subscribe [:communities/community id])]) + (fn [[community] [_ id]] + (community-card community id nil))) + +(re-frame/reg-sub + :shell/community-channel-card + (fn [[_ community-id channel-id _] _] + [(re-frame/subscribe [:communities/community community-id]) + (re-frame/subscribe [:chats/chat channel-id])]) + (fn [[community channel] [_ community-id channel-id content]] + (community-channel-card community community-id channel channel-id content)))