Shell navigation and animations

This commit is contained in:
Parvesh Monu 2023-06-13 00:51:58 +05:30
parent fbe4b0a36c
commit bcc20c7458
No known key found for this signature in database
GPG Key ID: F399696520817DE9
46 changed files with 1475 additions and 931 deletions

View File

@ -1,186 +0,0 @@
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 stackZIndex (stackId, selectedStackId) {
return useDerivedValue(
function () {
'worklet'
return selectedStackId.value == stackId ? 10 : 9;
}
);
}
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;
}
}
);
}

View File

@ -0,0 +1,46 @@
import { useDerivedValue, withTiming } from 'react-native-reanimated';
import * as constants from './constants';
export function bottomTabIconColor(stackId, selectedStackId, homeStackState,
passThrough, selectedTabColor, defaultColor,
passThroughColor) {
return useDerivedValue(
function () {
'worklet'
var homeStackStateValue = homeStackState.value;
if (selectedStackId.value == stackId &&
(homeStackStateValue == constants.OPEN_WITH_ANIMATION ||
homeStackStateValue == constants.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 constants.OPEN_WITH_ANIMATION:
return withTiming(extendedHeight, constants.LINEAR_EASING);
break;
case constants.CLOSE_WITH_ANIMATION:
return withTiming(height, constants.LINEAR_EASING);
break;
case constants.OPEN_WITHOUT_ANIMATION:
return extendedHeight;
break;
case constants.CLOSE_WITHOUT_ANIMATION:
return height;
break;
}
}
)
}

View File

@ -0,0 +1,27 @@
import { Easing } from 'react-native-reanimated';
// Home Stack States
export const CLOSE_WITH_ANIMATION = 0;
export const OPEN_WITH_ANIMATION = 1;
export const CLOSE_WITHOUT_ANIMATION = 2;
export const OPEN_WITHOUT_ANIMATION = 3;
// Floating Screen States
export const CLOSE_SCREEN_WITH_SLIDE_ANIMATION = 0;
export const OPEN_SCREEN_WITH_SLIDE_ANIMATION = 1;
export const CLOSE_SCREEN_WITH_SHELL_ANIMATION = 2;
export const OPEN_SCREEN_WITH_SHELL_ANIMATION = 3;
export const CLOSE_SCREEN_WITHOUT_ANIMATION = 4;
export const OPEN_SCREEN_WITHOUT_ANIMATION = 5;
export const SHELL_ANIMATION_TIME = 200;
export const LINEAR_EASING = {
duration: SHELL_ANIMATION_TIME,
easing: Easing.bezier(0, 0, 1, 1),
}
export const EASE_OUT_EASING = {
duration: SHELL_ANIMATION_TIME,
easing: Easing.bezier(0, 0, 0.58, 1),
}

View File

@ -0,0 +1,89 @@
import { useDerivedValue, withTiming, withSequence, withDelay, Easing } from 'react-native-reanimated';
import * as constants from './constants';
// Derived Values
export function screenLeft (screenState, screenWidth, switcherCardLeftPosition) {
return useDerivedValue(
function () {
'worklet'
switch (screenState.value) {
case constants.CLOSE_SCREEN_WITH_SLIDE_ANIMATION:
return withTiming(screenWidth, constants.EASE_OUT_EASING);
case constants.OPEN_SCREEN_WITH_SLIDE_ANIMATION:
return withTiming(0, constants.EASE_OUT_EASING);
case constants.CLOSE_SCREEN_WITHOUT_ANIMATION:
return screenWidth;
case constants.OPEN_SCREEN_WITHOUT_ANIMATION:
// Note - don't use return 0; its not working in ios
// https://github.com/software-mansion/react-native-reanimated/issues/3296#issuecomment-1573900172
return withSequence(withTiming(-1, {duration: 0}), withTiming(0, {duration: 0}));
case constants.CLOSE_SCREEN_WITH_SHELL_ANIMATION:
return withTiming(switcherCardLeftPosition, constants.EASE_OUT_EASING);
case constants.OPEN_SCREEN_WITH_SHELL_ANIMATION:
return withTiming(0, constants.EASE_OUT_EASING);
default:
return screenWidth;
}
});
}
export function screenTop (screenState, switcherCardTopPosition) {
return useDerivedValue(
function () {
'worklet'
switch (screenState.value) {
case constants.CLOSE_SCREEN_WITH_SHELL_ANIMATION:
return withTiming(switcherCardTopPosition, constants.EASE_OUT_EASING);
case constants.OPEN_SCREEN_WITH_SHELL_ANIMATION:
return withTiming(0, constants.EASE_OUT_EASING);
default:
return 0;
}
});
}
export function screenWidth (screenState, screenWidth, switcherCardSize) {
return useDerivedValue(
function () {
'worklet'
switch (screenState.value) {
case constants.CLOSE_SCREEN_WITH_SHELL_ANIMATION:
return withTiming(switcherCardSize, constants.EASE_OUT_EASING);
case constants.OPEN_SCREEN_WITH_SHELL_ANIMATION:
return withSequence(withTiming(switcherCardSize, {duration: 0}), withTiming(screenWidth, constants.EASE_OUT_EASING));
default:
return screenWidth;
}
});
}
export function screenHeight (screenState, screenHeight, switcherCardSize) {
return useDerivedValue(
function () {
'worklet'
switch (screenState.value) {
case constants.CLOSE_SCREEN_WITH_SHELL_ANIMATION:
return withTiming(switcherCardSize, constants.EASE_OUT_EASING);
case constants.OPEN_SCREEN_WITH_SHELL_ANIMATION:
return withSequence(withTiming(switcherCardSize, {duration: 0}), withTiming(screenHeight, constants.EASE_OUT_EASING));
default:
return screenHeight;
}
});
}
export function screenZIndex (screenState) {
return useDerivedValue(
function () {
'worklet'
switch (screenState.value) {
case constants.CLOSE_SCREEN_WITH_SHELL_ANIMATION:
case constants.CLOSE_SCREEN_WITH_SLIDE_ANIMATION:
return withDelay(constants.SHELL_ANIMATION_TIME, withTiming(-1, {duration: 0}));
case constants.CLOSE_SCREEN_WITHOUT_ANIMATION:
return -1;
default:
return 1;
}
});
}

View File

@ -0,0 +1,126 @@
import { useDerivedValue, withTiming, withSequence } from 'react-native-reanimated';
import * as constants from './constants';
// Derived values for each stack (communities, chat, wallet, browser)
export function stackOpacity (stackId, selectedStackId) {
return useDerivedValue(
function () {
'worklet'
return selectedStackId.value == stackId ? 1 : 0;
}
);
}
export function stackZIndex (stackId, selectedStackId) {
return useDerivedValue(
function () {
'worklet'
return selectedStackId.value == stackId ? 10 : 9;
}
);
}
// Derived values for home stack (container)
export function homeStackOpacity (homeStackState) {
return useDerivedValue(
function () {
'worklet'
switch (homeStackState.value) {
case constants.OPEN_WITH_ANIMATION:
return withTiming(1, constants.LINEAR_EASING);
break;
case constants.CLOSE_WITH_ANIMATION:
return withTiming(0, constants.LINEAR_EASING);
break;
case constants.OPEN_WITHOUT_ANIMATION:
return 1;
break;
case constants.CLOSE_WITHOUT_ANIMATION:
return 0;
break;
}
}
);
}
export function homeStackTop (homeStackState, top) {
return useDerivedValue(
function () {
'worklet'
switch (homeStackState.value) {
case constants.OPEN_WITH_ANIMATION:
return withTiming(0, constants.LINEAR_EASING);
break;
case constants.CLOSE_WITH_ANIMATION:
return withTiming(top, constants.LINEAR_EASING);
break;
case constants.OPEN_WITHOUT_ANIMATION:
return 0;
break;
case constants.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 constants.OPEN_WITH_ANIMATION:
return withSequence(withTiming(leftValue, {duration: 0}), withTiming(0, constants.LINEAR_EASING))
break;
case constants.CLOSE_WITH_ANIMATION:
return withTiming(leftValue, constants.LINEAR_EASING);
break;
case constants.OPEN_WITHOUT_ANIMATION:
return 0;
break;
case constants.CLOSE_WITHOUT_ANIMATION:
return leftValue;
break;
}
} else {
return 0;
}
}
);
}
export function homeStackPointer (homeStackState) {
return useDerivedValue(
function () {
'worklet'
var homeStackStateValue = homeStackState.value;
return (homeStackStateValue == constants.OPEN_WITH_ANIMATION ||
homeStackStateValue == constants.OPEN_WITHOUT_ANIMATION) ? "auto" : "none";
}
);
}
export function homeStackScale (homeStackState, minimizeScale) {
return useDerivedValue(
function () {
'worklet'
switch (homeStackState.value) {
case constants.OPEN_WITH_ANIMATION:
return withTiming(1, constants.LINEAR_EASING);
break;
case constants.CLOSE_WITH_ANIMATION:
return withTiming(minimizeScale, constants.LINEAR_EASING);
break;
case constants.OPEN_WITHOUT_ANIMATION:
return 1;
break;
case constants.CLOSE_WITHOUT_ANIMATION:
return minimizeScale;
break;
}
}
);
}

View File

@ -405,7 +405,9 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
"react-native-svg" react-native-svg
"react-native-orientation-locker" react-native-orientation-locker
"../src/js/worklets/core.js" worklet-factory
"../src/js/worklets/shell.js" #js {}
"../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 {}

View File

@ -296,7 +296,7 @@
(vals (get-in db [:communities community-id :chats])))]
(when (and id
(not= (:current-chat-id db) (str community-id id)))
(chat.events/navigate-to-chat cofx (str community-id id)))))
(chat.events/navigate-to-chat cofx (str community-id id) nil))))
(rf/defn fetch
[_]

View File

@ -232,11 +232,6 @@
[{:keys [db]} k v]
{:db (assoc db k v)})
(rf/defn set-view-id
{:events [:set-view-id]}
[{:keys [db]} view-id]
{:db (assoc db :view-id view-id)})
;;TODO :replace by named events
(rf/defn set-once-event
{:events [:set-once]}

View File

@ -15,7 +15,7 @@
{:events [:navigate-chat-updated]}
[cofx chat-id]
(when (get-in cofx [:db :chats chat-id])
(chat.events/navigate-to-chat cofx chat-id)))
(chat.events/navigate-to-chat cofx chat-id nil)))
(rf/defn handle-chat-removed
{:events [:chat-removed]}

View File

@ -12,7 +12,7 @@
[status-im2.setup.hot-reload :as hot-reload]
[status-im2.common.theme.core :as theme]
[taoensso.timbre :as log]
[status-im2.contexts.shell.animation :as shell.animation]
[status-im2.contexts.shell.utils :as shell.utils]
[status-im.contact.db :as contact.db]))
;; validate that the given mnemonic was generated from Status Dictionary
@ -135,7 +135,7 @@
[:light :dark colors/white])]
(theme/set-theme theme)
(re-frame/dispatch [:change-shell-status-bar-style
(if (shell.animation/home-stack-open?) status-bar-theme :light)])
(if (shell.utils/home-stack-open?) status-bar-theme :light)])
(when reload-ui?
(rf/dispatch [:dissmiss-all-overlays])
(hot-reload/reload)

View File

@ -42,9 +42,10 @@
[status-im2.contexts.chat.messages.link-preview.events :as link-preview]
[status-im2.contexts.contacts.events :as contacts]
[status-im2.navigation.events :as navigation]
[status-im2.contexts.shell.constants :as shell.constants]
[status-im2.common.log :as logging]
[taoensso.timbre :as log]
[status-im2.contexts.shell.animation :as shell.animation]
[status-im2.contexts.shell.utils :as shell.utils]
[utils.security.core :as security]))
(re-frame/reg-fx
@ -458,7 +459,8 @@
:key-uid
(fn [stored-key-uid]
(when (= stored-key-uid key-uid)
(re-frame/dispatch [:chat/navigate-to-chat chat-id])))))))))
(re-frame/dispatch [:chat/navigate-to-chat chat-id
shell.constants/open-screen-without-animation])))))))))
(rf/defn check-last-chat
{:events [::check-last-chat]}
@ -552,7 +554,7 @@
tos-accepted? (get db :tos/accepted?)
{:networks/keys [current-network networks]} db
network-id (str (get-in networks [current-network :config :NetworkId]))]
(shell.animation/change-selected-stack-id :communities-stack true)
(shell.utils/change-selected-stack-id :communities-stack true nil)
(rf/merge cofx
{:db (-> db
(dissoc :multiaccounts/login)

View File

@ -16,7 +16,7 @@
(rf/merge cofx
{:set-root :progress
:chat.ui/clear-inputs nil
:shell/reset-bottom-tabs nil
:shell/reset-state nil
:hide-popover nil
::logout nil
::multiaccounts/webview-debug-changed false

View File

@ -30,6 +30,7 @@
(defn calculate-button-height-and-dispatch-popover
[]
(.measure
^js
@button-ref
(fn [_ _ _ _ _ page-y]
(dispatch-popover page-y))))

View File

@ -168,16 +168,7 @@
(when-let [chat-id (:current-chat-id db)]
(chat.state/reset-visible-item)
(rf/merge cofx
(merge
{:db (dissoc db :current-chat-id)}
(let [community-id (get-in db [:chats chat-id :community-id])]
;; When navigating back from community chat to community, update switcher card
;; A close chat event is also called while opening any chat.
;; That might lead to duplicate :dispatch keys in fx/merge, that's why dispatch-n is
;; used here.
(when (and community-id (not navigate-to-shell?))
{:dispatch-n [[:shell/add-switcher-card
:community-overview community-id]]})))
{:db (dissoc db :current-chat-id)}
(link-preview/reset-all)
(delete-for-me/sync-all)
(delete-message/send-all)
@ -206,9 +197,9 @@
(rf/defn navigate-to-chat
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
{:events [:chat/navigate-to-chat]}
[{db :db :as cofx} chat-id]
[{db :db :as cofx} chat-id animation]
(rf/merge cofx
{:dispatch [:navigate-to :chat chat-id]}
{:dispatch [(if animation :shell/navigate-to :navigate-to) :chat chat-id animation]}
(when-not (or (= (:view-id db) :community) (= (:view-id db) :community-overview))
(navigation/pop-to-root :shell-stack))
(close-chat false)

View File

@ -87,5 +87,5 @@
(let [chat-id "test_chat"
db {:pagination-info {chat-id {:all-loaded? true}}}]
(testing "Pagination info should be reset on navigation"
(let [res (chat/navigate-to-chat {:db db} chat-id)]
(let [res (chat/navigate-to-chat {:db db} chat-id nil)]
(is (nil? (get-in res [:db :pagination-info chat-id :all-loaded?])))))))

View File

@ -110,13 +110,13 @@
:extrapolateRight "clamp"})
(defn loading-view
[chat-id]
[chat-id shell-animation-complete?]
(let [loading-messages? (rf/sub [:chats/loading-messages? chat-id])
all-loaded? (rf/sub [:chats/all-loaded? chat-id])
messages (rf/sub [:chats/raw-chat-messages-stream chat-id])
loading-first-page? (= (count messages) 0)
top-spacing (if loading-first-page? 0 navigation.style/navigation-bar-height)]
(when (or loading-messages? (not all-loaded?))
(when (or (not shell-animation-complete?) loading-messages? (not all-loaded?))
[rn/view {:padding-top top-spacing}
[quo/skeleton
(if loading-first-page?
@ -174,7 +174,7 @@
(assoc :scale-y -1)))
(defn f-list-footer
[{:keys [chat scroll-y cover-bg-color on-layout]}]
[{:keys [chat scroll-y cover-bg-color on-layout shell-animation-complete?]}]
(let [{:keys [chat-id chat-name emoji chat-type
group-chat]} chat
all-loaded? (rf/sub [:chats/all-loaded? chat-id])
@ -217,7 +217,7 @@
(when bio
[quo/text {:style style/bio}
bio])]]]
[loading-view chat-id]]))
[loading-view chat-id shell-animation-complete?]]))
(defn list-footer
[props]
@ -258,10 +258,15 @@
(defn messages-list-content
[{:keys [chat insets scroll-y cover-bg-color keyboard-shown?]}]
(let [context (rf/sub [:chats/current-chat-message-list-view-context])
messages (rf/sub [:chats/raw-chat-messages-stream (:chat-id chat)])
recording? (rf/sub [:chats/recording?])
all-loaded? (rf/sub [:chats/all-loaded? (:chat-id chat)])]
(let [shell-animation-complete? (rf/sub [:shell/animation-complete? (:chat-type chat)])
context (when shell-animation-complete?
(rf/sub [:chats/current-chat-message-list-view-context]))
messages (when shell-animation-complete?
(rf/sub [:chats/raw-chat-messages-stream (:chat-id chat)]))
recording? (when shell-animation-complete?
(rf/sub [:chats/recording?]))
all-loaded? (when shell-animation-complete?
(rf/sub [:chats/all-loaded? (:chat-id chat)]))]
[rn/view {:style {:flex 1}}
[rn/flat-list
{:key-fn list-key-fn
@ -271,10 +276,11 @@
[list-group-chat-header chat])
[list-header insets]]
:footer [list-footer
{:chat chat
:scroll-y scroll-y
:cover-bg-color cover-bg-color
:on-layout footer-on-layout}]
{:chat chat
:scroll-y scroll-y
:cover-bg-color cover-bg-color
:on-layout footer-on-layout
:shell-animation-complete? shell-animation-complete?}]
:data messages
:render-data {:context context
:keyboard-shown? keyboard-shown?}
@ -323,7 +329,8 @@
[keyboard-shown keyboard-height])
[rn/keyboard-avoiding-view
{:style (style/keyboard-avoiding-container insets)
:keyboard-vertical-offset (- (:bottom insets))}
:keyboard-vertical-offset (- (:bottom insets))
:behavior :height}
(when header-comp
[header-comp {:scroll-y scroll-y}])

View File

@ -1,29 +1,23 @@
(ns status-im2.contexts.chat.messages.view
(:require [quo2.foundations.colors :as colors]
[re-frame.db]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.contexts.chat.composer.view :as composer]
[status-im2.contexts.chat.messages.contact-requests.bottom-drawer :as
contact-requests.bottom-drawer]
[status-im2.contexts.chat.messages.list.view :as messages.list]
[status-im2.contexts.chat.messages.navigation.view :as messages.navigation]
[status-im2.navigation.state :as navigation.state]
[utils.re-frame :as rf]))
(defn navigate-back-handler
[]
(when (and (not @navigation.state/curr-modal) (= (get @re-frame.db/app-db :view-id) :chat))
(rn/hw-back-remove-listener navigate-back-handler)
(rf/dispatch [:chat/close])
(rf/dispatch [:navigate-back])
;; If true is not returned back button event will bubble up,
;; and will call system back button action
true))
(defn load-composer
[insets chat-type]
(let [shell-animation-complete? (rf/sub [:shell/animation-complete? chat-type])]
(when shell-animation-complete?
[:f> composer/composer insets])))
(defn chat-render
(defn chat
[]
(let [{:keys [chat-id
chat-type
contact-request-state
group-chat
able-to-send-message?]
@ -35,14 +29,6 @@
[messages.navigation/navigation-view {:scroll-y scroll-y}])
:footer-comp (fn [{:keys [insets]}]
(if-not able-to-send-message?
[contact-requests.bottom-drawer/view chat-id contact-request-state group-chat]
[:f> composer/composer insets]))}]))
(defn chat
[]
(reagent/create-class
{:component-did-mount (fn []
(rn/hw-back-remove-listener navigate-back-handler)
(rn/hw-back-add-listener navigate-back-handler))
:component-will-unmount (fn [] (rn/hw-back-remove-listener navigate-back-handler))
:reagent-render chat-render}))
[contact-requests.bottom-drawer/view chat-id contact-request-state
group-chat]
[load-composer insets chat-type]))}]))

View File

@ -303,53 +303,54 @@
category)))))
(defn community-card-page-view
[{:keys [name images id]}]
[]
(let [categories-heights (reagent/atom {})
first-channel-height (reagent/atom 0)
scroll-height (reagent/atom 0)
cover {:uri (get-in images [:banner :uri])}
logo {:uri (get-in images [:thumbnail :uri])}]
(fn [community pending?]
[scroll-page/scroll-page
{:cover-image cover
:logo logo
:page-nav-right-section-buttons (page-nav-right-section-buttons id)
:name name
:on-scroll #(reset! scroll-height %)
:navigate-back? true
:background-color (colors/theme-colors
colors/white
colors/neutral-90)
:height (if platform/ios?
100
148)}
scroll-height (reagent/atom 0)]
(fn [id]
(let [{:keys [name images id] :as community}
(rf/sub [:communities/community id])
pending? (rf/sub [:communities/my-pending-request-to-join id])
cover {:uri (get-in images [:banner :uri])}
logo {:uri (get-in images [:thumbnail :uri])}]
[scroll-page/scroll-page
{:cover-image cover
:logo logo
:page-nav-right-section-buttons (page-nav-right-section-buttons id)
:name name
:on-scroll #(reset! scroll-height %)
:navigate-back? true
:background-color (colors/theme-colors
colors/white
colors/neutral-90)
:height (if platform/ios?
100
148)}
[sticky-category-header
{:enabled (> @scroll-height @first-channel-height)
:label (pick-first-category-by-height
@scroll-height
@first-channel-height
@categories-heights)}]
[sticky-category-header
{:enabled (> @scroll-height @first-channel-height)
:label (pick-first-category-by-height
@scroll-height
@first-channel-height
@categories-heights)}]
[community-content
community
pending?
{:on-category-layout (partial add-category-height categories-heights)
:on-first-channel-height-changed
;; Here we set the height of the component
;; and we filter out the categories, as some might have been removed
(fn [height categories]
(swap! categories-heights select-keys categories)
(reset! first-channel-height height))}]])))
[community-content
community
pending?
{:on-category-layout (partial add-category-height categories-heights)
:on-first-channel-height-changed
;; Here we set the height of the component
;; and we filter out the categories, as some might have been removed
(fn [height categories]
(swap! categories-heights select-keys categories)
(reset! first-channel-height height))}]]))))
(defn overview
[]
(let [id (rf/sub [:get-screen-params :community-overview])
community (rf/sub [:communities/community id])
pending? (rf/sub [:communities/my-pending-request-to-join id])]
[id]
(let [id (or id (rf/sub [:get-screen-params :community-overview]))]
[rn/view
{:style style/community-overview-container}
[community-card-page-view community pending?]
[community-card-page-view id]
[floating-shell-button/floating-shell-button
{:jump-to {:on-press #(rf/dispatch [:shell/navigate-to-jump-to])
:label (i18n/label :t/jump-to)}}

View File

@ -6,7 +6,7 @@
[oops.core :refer [oget]]
[status-im2.common.resources :as resources]
[status-im.async-storage.core :as async-storage]
[status-im2.contexts.shell.animation :as shell.animation]
[status-im2.contexts.shell.state :as shell.state]
[status-im2.contexts.onboarding.common.carousel.view :as carousel]
[status-im2.contexts.onboarding.common.background.style :as style]
[react-native.reanimated :as reanimated]
@ -50,8 +50,8 @@
;; but actual values differ in some pixels, so arbitrary 5 pixels is allowed
(when (and (> height width)
(>= (+ height 5) (or window-height 0))
(not= height @shell.animation/screen-height))
(reset! shell.animation/screen-height height)
(not= height @shell.state/screen-height))
(reset! shell.state/screen-height height)
(async-storage/set-item! :screen-height height))))
(defn f-view

View File

@ -11,7 +11,7 @@
[status-im2.contexts.onboarding.common.background.view :as background]
[status-im2.contexts.onboarding.common.navigation-bar.view :as navigation-bar]
[status-im2.contexts.onboarding.enable-notifications.style :as style]
[status-im2.contexts.shell.animation :as shell.animation]))
[status-im2.contexts.shell.utils :as shell.utils]))
(defn page-title
[]
@ -28,7 +28,7 @@
[rn/view {:style (style/buttons insets)}
[quo/button
{:on-press (fn []
(shell.animation/change-selected-stack-id :communities-stack true)
(shell.utils/change-selected-stack-id :communities-stack true nil)
(rf/dispatch [::notifications/switch true platform/ios?])
(rf/dispatch [:init-root :welcome]))
:type :primary
@ -38,7 +38,7 @@
(i18n/label :t/intro-wizard-title6)]
[quo/button
{:on-press (fn []
(shell.animation/change-selected-stack-id :communities-stack true)
(shell.utils/change-selected-stack-id :communities-stack true nil)
(rf/dispatch [:init-root :welcome]))
:accessibility-label :enable-notifications-later-button
:override-background-color colors/white-opa-5

View File

@ -5,7 +5,7 @@
[status-im2.constants :as constants]
[status-im2.common.resources :as resources]
[status-im2.contexts.quo-preview.preview :as preview]
[status-im2.contexts.shell.cards.view :as switcher-cards]
[status-im2.contexts.shell.components.switcher-cards.view :as switcher-cards]
[status-im2.contexts.shell.constants :as shell.constants]))
(def descriptor

View File

@ -1,177 +1,86 @@
(ns status-im2.contexts.shell.animation
(:require [quo2.foundations.colors :as colors]
[utils.re-frame :as rf]
(:require [utils.re-frame :as rf]
[react-native.reanimated :as reanimated]
[reagent.core :as reagent]
[status-im.async-storage.core :as async-storage] ;;TODO remove when not used anymore
[status-im2.contexts.shell.constants :as shell.constants]
[utils.worklets.shell :as worklets.shell]))
;; Atoms
(def selected-stack-id (atom nil))
(def screen-height (atom nil))
(def home-stack-state (atom shell.constants/close-with-animation))
(def shared-values-atom (atom nil))
;; 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 shell.constants/open-with-animation)
(= state shell.constants/open-without-animation))))
(defn calculate-home-stack-state-value
[stack-id & animate?]
(if animate?
(if (some? stack-id)
shell.constants/open-with-animation
shell.constants/close-with-animation)
(if (some? stack-id)
shell.constants/open-without-animation
shell.constants/close-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 change-selected-stack-id
[stack-id & [store? home-stack-state-value]]
(let [home-stack-state-value (or home-stack-state-value
(calculate-home-stack-state-value stack-id))]
(reset! selected-stack-id stack-id)
(reset! home-stack-state home-stack-state-value)
(rf/dispatch [:set-view-id (or stack-id :shell)])
(when store?
(async-storage/set-item! :selected-stack-id stack-id))))
(defn calculate-home-stack-position
[]
(let [{:keys [width height]} (shell.constants/dimensions)
height (or @screen-height height)
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)
left-empty-space (* empty-space-half-scale width)
top-empty-space (* empty-space-half-scale
(- height (shell.constants/bottom-tabs-container-height)))]
{:left (reduce
(fn [acc stack-id]
(assoc acc
stack-id
(+ (- left-margin left-empty-space)
(* (.indexOf shell.constants/stacks-ids stack-id)
bottom-nav-tab-width))))
{:none 0}
shell.constants/stacks-ids)
:top (+ top-empty-space (shell.constants/bottom-tabs-container-height))
:scale minimize-scale}))
;; 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 false)
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)]
(reset! shared-values-atom
(reduce
(fn [acc id]
(let [tabs-icon-color-keyword (get shell.constants/tabs-icon-color-keywords id)
stack-opacity-keyword (get shell.constants/stacks-opacity-keywords id)
stack-z-index-keyword (get shell.constants/stacks-z-index-keywords id)]
(assoc
acc
stack-opacity-keyword
(worklets.shell/stack-opacity (name id) selected-stack-id-sv)
stack-z-index-keyword
(worklets.shell/stack-z-index (name id) selected-stack-id-sv)
tabs-icon-color-keyword
(worklets.shell/bottom-tab-icon-color
(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 (worklets.shell/home-stack-left
selected-stack-id-sv
animate-home-stack-left
home-stack-state-sv
(clj->js (:left home-stack-position)))
:home-stack-top (worklets.shell/home-stack-top
home-stack-state-sv
(:top home-stack-position))
:home-stack-opacity (worklets.shell/home-stack-opacity home-stack-state-sv)
:home-stack-pointer (worklets.shell/home-stack-pointer home-stack-state-sv)
:home-stack-scale (worklets.shell/home-stack-scale home-stack-state-sv
(:scale home-stack-position))
:bottom-tabs-height (worklets.shell/bottom-tabs-height
home-stack-state-sv
(shell.constants/bottom-tabs-container-height)
(shell.constants/bottom-tabs-extended-container-height))}
shell.constants/stacks-ids)))
@shared-values-atom)
;; Animations
(defn change-shell-status-bar-style
[]
(rf/dispatch [:change-shell-status-bar-style
(if (or (colors/dark?)
(not (home-stack-open?)))
:light
:dark)]))
[status-im2.contexts.shell.utils :as utils]
[status-im2.contexts.shell.state :as state]
[status-im2.contexts.shell.constants :as shell.constants]))
;; Home stack
(defn open-home-stack
[stack-id animate?]
(let [home-stack-state-value (calculate-home-stack-state-value stack-id animate?)]
(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)
(change-selected-stack-id stack-id true home-stack-state-value)
(js/setTimeout change-shell-status-bar-style shell.constants/shell-animation-time)))
(let [home-stack-state-value (utils/calculate-home-stack-state-value stack-id animate?)]
(reanimated/set-shared-value (:selected-stack-id @state/shared-values-atom) (name stack-id))
(reanimated/set-shared-value (:home-stack-state @state/shared-values-atom) home-stack-state-value)
(utils/change-selected-stack-id stack-id true home-stack-state-value)
(js/setTimeout
(fn []
(utils/load-stack stack-id)
(utils/change-shell-status-bar-style))
(if animate? shell.constants/shell-animation-time 0))))
(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))
(change-selected-stack-id stack-id true))
(reanimated/set-shared-value (:animate-home-stack-left @state/shared-values-atom) false)
(reanimated/set-shared-value (:selected-stack-id @state/shared-values-atom) (name stack-id))
(utils/load-stack stack-id)
(utils/change-selected-stack-id stack-id true nil))
(defn bottom-tab-on-press
[stack-id]
(when (and @shared-values-atom (not= stack-id @selected-stack-id))
(let [stack-load-delay (if (home-stack-open?)
0
shell.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))))
[stack-id animate?]
(when (and @state/shared-values-atom (not= stack-id @state/selected-stack-id))
(if (utils/home-stack-open?)
(change-tab stack-id)
(open-home-stack stack-id animate?))
(when animate? (utils/update-view-id (or stack-id :shell)))))
(defn close-home-stack
[animate?]
(let [stack-id nil
home-stack-state-value (calculate-home-stack-state-value stack-id animate?)]
(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)
(change-selected-stack-id stack-id true home-stack-state-value)
(change-shell-status-bar-style)))
home-stack-state-value (utils/calculate-home-stack-state-value stack-id animate?)]
(reanimated/set-shared-value (:animate-home-stack-left @state/shared-values-atom) true)
(reanimated/set-shared-value (:home-stack-state @state/shared-values-atom) home-stack-state-value)
(utils/change-selected-stack-id stack-id true home-stack-state-value)
(utils/change-shell-status-bar-style)
(when animate? (utils/update-view-id (or stack-id :shell)))))
;; Floating Screen
(defn animate-floating-screen
[screen-id {:keys [id animation community-id hidden-screen?]}]
(when (not= animation (get @state/floating-screens-state screen-id))
;; Animate Floating Screen
(reanimated/set-shared-value
(get-in @state/shared-values-atom [screen-id :screen-state])
animation)
(reset! state/floating-screens-state
(assoc @state/floating-screens-state screen-id animation)))
(js/setTimeout
(fn [floating-screen-open?]
(if floating-screen-open?
;; Events realted to opening of a screen
(rf/dispatch [:shell/floating-screen-opened screen-id
id community-id hidden-screen?])
;; Events realted to closing of a screen
(rf/dispatch [:shell/floating-screen-closed screen-id])))
shell.constants/shell-animation-time
(utils/floating-screen-open? screen-id)))
(defn set-floating-screen-position
[left top card-type]
(let [screen-id (cond
(#{shell.constants/one-to-one-chat-card
shell.constants/private-group-chat-card
shell.constants/community-channel-card}
card-type)
shell.constants/chat-screen
(= card-type shell.constants/community-card)
shell.constants/community-screen
:else nil)]
(when screen-id
(reanimated/set-shared-value
(get-in @state/shared-values-atom [screen-id :screen-left])
left)
(reanimated/set-shared-value
(get-in @state/shared-values-atom [screen-id :screen-top])
top))))

View File

@ -0,0 +1,36 @@
(ns status-im2.contexts.shell.components.bottom-tabs.style
(:require [quo2.foundations.colors :as colors]
[react-native.platform :as platform]
[react-native.reanimated :as reanimated]
[status-im2.contexts.shell.utils :as utils]))
(defn bottom-tabs-container
[pass-through? height]
(reanimated/apply-animations-to-style
{:height height}
{:background-color (if pass-through? :transparent colors/neutral-100)
:flex 1
:align-items :center
:height (utils/bottom-tabs-container-height)
:position :absolute
:bottom 0
:right 0
:left 0
:overflow :hidden
:accessibility-label :bottom-tabs-container}))
(defn bottom-tabs
[]
{:flex-direction :row
:position :absolute
:bottom (if platform/android? 8 34)
:flex 1
:accessibility-label :bottom-tabs})
(def bottom-tabs-blur-overlay
{:position :absolute
:left 0
:right 0
:bottom 0
:height (utils/bottom-tabs-extended-container-height)
:background-color colors/neutral-100-opa-70})

View File

@ -1,13 +1,15 @@
(ns status-im2.contexts.shell.bottom-tabs
(ns status-im2.contexts.shell.components.bottom-tabs.view
(:require [utils.re-frame :as rf]
[react-native.core :as rn]
[react-native.blur :as blur]
[react-native.gesture :as gesture]
[react-native.reanimated :as reanimated]
[status-im2.contexts.shell.style :as style]
[status-im2.contexts.shell.utils :as utils]
[status-im2.contexts.shell.state :as state]
[status-im2.contexts.shell.animation :as animation]
[status-im2.contexts.shell.constants :as shell.constants]
[quo2.components.navigation.bottom-nav-tab :as bottom-nav-tab]
[react-native.gesture :as gesture]))
[status-im2.contexts.shell.components.bottom-tabs.style :as style]))
(defn blur-overlay-params
[style]
@ -26,18 +28,14 @@
:icon-color-anim (get
shared-values
(get shell.constants/tabs-icon-color-keywords stack-id))
:on-press #(animation/bottom-tab-on-press stack-id)
:on-press #(animation/bottom-tab-on-press stack-id true)
:accessibility-label (str (name stack-id) "-tab"))])
(defn- f-bottom-tabs
(defn f-bottom-tabs
[]
(let [notifications-data (rf/sub [:shell/bottom-tabs-notifications-data])
pass-through? (rf/sub [:shell/shell-pass-through?])
shared-values @animation/shared-values-atom
original-style (style/bottom-tabs-container pass-through?)
animated-style (reanimated/apply-animations-to-style
{:height (:bottom-tabs-height shared-values)}
original-style)
shared-values @state/shared-values-atom
communities-double-tab-gesture (-> (gesture/gesture-tap)
(gesture/number-of-taps 2)
(gesture/on-start
@ -48,9 +46,10 @@
(gesture/on-start
(fn [_event]
(rf/dispatch [:messages-home/select-tab :tab/recent]))))]
(animation/load-stack @animation/selected-stack-id)
(utils/load-stack @state/selected-stack-id)
(reanimated/set-shared-value (:pass-through? shared-values) pass-through?)
[reanimated/view {:style animated-style}
[reanimated/view
{:style (style/bottom-tabs-container pass-through? (:bottom-tabs-height shared-values))}
(when pass-through?
[blur/view (blur-overlay-params style/bottom-tabs-blur-overlay)])
[rn/view {:style (style/bottom-tabs)}
@ -60,7 +59,3 @@
[bottom-tab :i/messages :chats-stack shared-values notifications-data]]
[bottom-tab :i/wallet :wallet-stack shared-values notifications-data]
[bottom-tab :i/browser :browser-stack shared-values notifications-data]]]))
(defn bottom-tabs
[]
[:f> f-bottom-tabs])

View File

@ -0,0 +1,20 @@
(ns status-im2.contexts.shell.components.floating-screens.style
(:require [quo2.foundations.colors :as colors]
[react-native.reanimated :as reanimated]))
(defn screen
[{:keys [screen-left screen-top screen-width screen-height screen-z-index]}]
(reanimated/apply-animations-to-style
{:left screen-left
:top screen-top
:width screen-width
:height screen-height
:z-index screen-z-index}
{:background-color (colors/theme-colors colors/white colors/neutral-95)
:overflow :hidden
:position :absolute}))
(defn screen-container
[{:keys [width height]}]
{:width width
:height height})

View File

@ -0,0 +1,43 @@
(ns status-im2.contexts.shell.components.floating-screens.view
(:require [utils.re-frame :as rf]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]
[status-im2.contexts.shell.state :as state]
[status-im2.contexts.shell.utils :as utils]
[status-im2.contexts.chat.messages.view :as chat]
[status-im2.contexts.shell.animation :as animation]
[status-im2.contexts.shell.constants :as shell.constants]
[status-im2.contexts.shell.components.floating-screens.style :as style]
[status-im2.contexts.communities.overview.view :as communities.overview]))
(def screens-map
{shell.constants/community-screen communities.overview/overview
shell.constants/chat-screen chat/chat})
(defn f-screen
[screen-id {:keys [id animation] :as screen-param}]
;; First render screen, then animate (smoother animation)
(rn/use-effect
(fn []
(animation/animate-floating-screen screen-id screen-param))
[animation id])
[reanimated/view
{:style (style/screen (get @state/shared-values-atom screen-id))}
[rn/view
{:style (style/screen-container (utils/dimensions))
:key id}
[(get screens-map screen-id) id]]])
;; Currently chat screen and events both depends on current-chat-id, once we remove
;; use of current-chat-id from view then we can keep last chat loaded, for fast navigation
(defn lazy-screen
[screen-id]
(let [screen-param (rf/sub [:shell/floating-screen screen-id])]
(when screen-param
[:f> f-screen screen-id screen-param])))
(defn view
[]
[:<>
[lazy-screen shell.constants/community-screen]
[lazy-screen shell.constants/chat-screen]])

View File

@ -0,0 +1,32 @@
(ns status-im2.contexts.shell.components.home-stack.style
(:require [quo2.foundations.colors :as colors]
[react-native.reanimated :as reanimated]
[status-im2.contexts.shell.utils :as utils]))
(defn home-stack
[shared-values {:keys [width height]}]
(reanimated/apply-animations-to-style
{:top (:home-stack-top shared-values)
:left (:home-stack-left shared-values)
:opacity (:home-stack-opacity shared-values)
:pointer-events (:home-stack-pointer shared-values)
:transform [{:scale (:home-stack-scale shared-values)}]}
{:border-bottom-left-radius 20
:border-bottom-right-radius 20
:background-color (colors/theme-colors colors/white colors/neutral-95)
:overflow :hidden
:position :absolute
:width width
:height (- height (utils/bottom-tabs-container-height))}))
(defn stack-view
[stack-id {:keys [opacity z-index]}]
(reanimated/apply-animations-to-style
{:opacity opacity
:z-index z-index}
{:position :absolute
:top 0
:bottom 0
:left 0
:right 0
:accessibility-label stack-id}))

View File

@ -0,0 +1,48 @@
(ns status-im2.contexts.shell.components.home-stack.view
(:require [react-native.reanimated :as reanimated]
[status-im.ui.screens.wallet.accounts.views :as wallet.accounts]
[status-im2.contexts.chat.home.view :as chat]
[status-im2.contexts.shell.state :as state]
[status-im2.contexts.shell.utils :as utils]
[status-im2.contexts.communities.home.view :as communities]
[status-im2.contexts.shell.constants :as shell.constants]
[status-im2.contexts.shell.components.home-stack.style :as style]
[status-im.ui.screens.browser.stack :as browser.stack]))
(defn load-stack?
[stack-id]
(case stack-id
:communities-stack @state/load-communities-stack?
:chats-stack @state/load-chats-stack?
:browser-stack @state/load-browser-stack?
:wallet-stack @state/load-wallet-stack?))
(defn- f-stack-view
[stack-id shared-values]
[reanimated/view
{:style (style/stack-view
stack-id
{:opacity (get shared-values
(get shell.constants/stacks-opacity-keywords stack-id))
:z-index (get shared-values
(get shell.constants/stacks-z-index-keywords stack-id))})}
(case stack-id
:communities-stack [communities/home]
:chats-stack [chat/home]
:wallet-stack [wallet.accounts/accounts-overview-old]
:browser-stack [browser.stack/browser-stack]
[:<>])])
(defn lazy-screen
[stack-id shared-values]
(when (load-stack? stack-id)
[:f> f-stack-view stack-id shared-values]))
(defn f-home-stack
[]
(let [shared-values @state/shared-values-atom]
[reanimated/view {:style (style/home-stack shared-values (utils/dimensions))}
[lazy-screen :communities-stack shared-values]
[lazy-screen :chats-stack shared-values]
[lazy-screen :browser-stack shared-values]
[lazy-screen :wallet-stack shared-values]]))

View File

@ -0,0 +1,64 @@
(ns status-im2.contexts.shell.components.shell-screen.style
(:require [quo2.foundations.colors :as colors]
[status-im2.contexts.shell.utils :as utils]))
;;;; Placeholder
(defn placeholder-container
[status-bar-height]
{:position :absolute
:top (+ 112 status-bar-height)
:left 0
:right 0
:bottom (utils/bottom-tabs-container-height)
:align-items :center
:accessibility-label :shell-placeholder-view})
(def placeholder-image
{:margin-top 186
:width 120
:height 120
;; Code to remove once placeholder image/vector will be available
:border-width 5
:border-radius 10
:border-color :red})
(def placeholder-title
{:margin-top 20
:color colors/white})
(def placeholder-subtitle
{:margin-top 4
:color colors/white})
;;;; Shell
(defn jump-to-text
[status-bar-height]
{:color colors/white
:margin-top (+ 68 status-bar-height)
:margin-bottom 20
:margin-left 20})
(def jump-to-list
{:top 0
:left 0
:right 0
:bottom 0
:position :absolute})
(defn top-nav-blur-overlay-container
[height pass-through?]
{:height height
:position :absolute
:left 0
:top 0
:right 0
:overflow :hidden
:background-color (if pass-through? :transparent colors/neutral-100)})
(def top-nav-blur-overlay
{:height 100
:position :absolute
:left 0
:right 0
:top 0
:background-color colors/neutral-100-opa-70})

View File

@ -0,0 +1,113 @@
(ns status-im2.contexts.shell.components.shell-screen.view
(:require [utils.i18n :as i18n]
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[utils.re-frame :as rf]
[react-native.core :as rn]
[react-native.blur :as blur]
[react-native.linear-gradient :as linear-gradient]
[react-native.safe-area :as safe-area]
[status-im2.contexts.shell.state :as state]
[status-im2.contexts.shell.utils :as utils]
[status-im2.common.home.view :as common.home]
[status-im2.contexts.shell.constants :as shell.constants]
[status-im2.contexts.shell.components.shell-screen.style :as style]
[status-im2.contexts.shell.components.bottom-tabs.view :as bottom-tabs]
[status-im2.contexts.shell.components.switcher-cards.view :as switcher-cards]))
(defn placeholder
[]
[linear-gradient/linear-gradient
{:colors [colors/neutral-100-opa-0 colors/neutral-100-opa-100]
:start {:x 0 :y 0}
:end {:x 0 :y 1}
:style (style/placeholder-container (safe-area/get-top))}
[rn/image
{:source nil ;; TODO(parvesh) - add placeholder image
:style style/placeholder-image}]
[quo/text
{:size :paragraph-1
:weight :semi-bold
:style style/placeholder-title}
(i18n/label :t/shell-placeholder-title)]
[quo/text
{:size :paragraph-2
:weight :regular
:align :center
:style style/placeholder-subtitle}
(i18n/label :t/shell-placeholder-subtitle)]])
(defn jump-to-text
[]
[quo/text
{:size :heading-1
:weight :semi-bold
:style (style/jump-to-text (safe-area/get-top))}
(i18n/label :t/jump-to)])
(defn render-card
[{:keys [type screen-id] :as card}]
(let [card-data (cond
(= type shell.constants/one-to-one-chat-card)
(rf/sub [:shell/one-to-one-chat-card screen-id])
(= type shell.constants/private-group-chat-card)
(rf/sub [:shell/private-group-chat-card screen-id])
(= type shell.constants/community-card)
(rf/sub [:shell/community-card screen-id])
(= type shell.constants/community-channel-card)
(rf/sub [:shell/community-channel-card screen-id])
:else nil)]
[switcher-cards/card (merge card card-data)]))
(def empty-cards (repeat 6 {:type shell.constants/empty-card}))
(defn jump-to-list
[switcher-cards shell-margin]
(let [data (if (seq switcher-cards) switcher-cards empty-cards)]
[:<>
[rn/flat-list
{:data data
:render-fn render-card
:key-fn :id
:header (jump-to-text)
:ref #(reset! state/jump-to-list-ref %)
:num-columns 2
:column-wrapper-style {:margin-horizontal shell-margin
:justify-content :space-between
:margin-bottom 16}
:style style/jump-to-list
:content-container-style {:padding-bottom (utils/bottom-tabs-container-height)}}]
(when-not (seq switcher-cards)
[placeholder])]))
(defn top-nav-blur-overlay
[top]
(let [pass-through? (rf/sub [:shell/shell-pass-through?])]
[rn/view {:style (style/top-nav-blur-overlay-container (+ 56 top) pass-through?)}
(when pass-through?
[blur/view (bottom-tabs/blur-overlay-params style/top-nav-blur-overlay)])]))
(defn view
[customization-color]
(let [switcher-cards (rf/sub [:shell/sorted-switcher-cards])
width (rf/sub [:dimensions/window-width])
top (safe-area/get-top)
shell-margin (/ (- width (* 2 shell.constants/switcher-card-size)) 3)]
[rn/view
{:style {:top 0
:left 0
:right 0
:bottom -1
:position :absolute
:background-color colors/neutral-100}}
[jump-to-list switcher-cards shell-margin]
[top-nav-blur-overlay top]
[common.home/top-nav
{:type :shell
:avatar {:customization-color customization-color}
:style {:margin-top top
:z-index 2}}]]))

View File

@ -1,4 +1,4 @@
(ns status-im2.contexts.shell.cards.style
(ns status-im2.contexts.shell.components.switcher-cards.style
(:require [quo2.foundations.colors :as colors]))
(def colors-map

View File

@ -1,13 +1,15 @@
(ns status-im2.contexts.shell.cards.view
(ns status-im2.contexts.shell.components.switcher-cards.view
(:require [clojure.string :as string]
[utils.i18n :as i18n]
[quo2.core :as quo]
[utils.re-frame :as rf]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.fast-image :as fast-image]
[status-im2.constants :as constants]
[status-im2.contexts.shell.cards.style :as style]
[status-im2.contexts.shell.animation :as animation]
[status-im2.contexts.shell.constants :as shell.constants]
[status-im2.contexts.shell.components.switcher-cards.style :as style]
[status-im2.contexts.chat.messages.resolver.message-resolver :as resolver]))
(defn content-container
@ -180,43 +182,76 @@
"")))
(defn open-screen
[card-type id]
(cond
(#{shell.constants/one-to-one-chat-card
shell.constants/private-group-chat-card
shell.constants/community-channel-card}
card-type)
(rf/dispatch [:chat/navigate-to-chat id])
(= card-type shell.constants/community-card)
(rf/dispatch [:navigate-to :community-overview id])))
(defn calculate-card-position-and-open-screen
[card-ref card-type id]
(when @card-ref
(.measure
^js
@card-ref
(fn [_ _ _ _ page-x page-y]
(animation/set-floating-screen-position
page-x
page-y
card-type)
(open-screen card-type id)))))
;; Screens Card
(defn screens-card
[{:keys [avatar-params title type customization-color
on-press on-close content banner]}]
(let [color-50 (colors/custom-color customization-color 50)
color-60 (colors/custom-color customization-color 60)]
[rn/touchable-without-feedback {:on-press on-press}
[rn/view {:style (style/base-container color-50)}
(when banner
[rn/image
{:source (:source banner)
:style {:width 160}}])
[rn/view {:style style/secondary-container}
[quo/text
{:size :paragraph-1
:weight :semi-bold
:number-of-lines 1
:ellipsize-mode :tail
:style style/title}
title]
[quo/text
{:size :paragraph-2
:weight :medium
:style style/subtitle}
(subtitle type content)]
[bottom-container type (merge {:color-50 color-50 :color-60 color-60} content)]]
(when avatar-params
[rn/view {:style style/avatar-container}
[avatar avatar-params type customization-color]])
[quo/button
{:size 24
:type :grey
:icon true
:on-press on-close
:override-theme :dark
:style style/close-button}
:i/close]]]))
[]
(let [card-ref (atom nil)]
(fn [{:keys [avatar-params title type customization-color
content banner id channel-id]}]
(let [color-50 (colors/custom-color customization-color 50)
color-60 (colors/custom-color customization-color 60)]
[rn/touchable-opacity
{:on-press #(calculate-card-position-and-open-screen
card-ref
type
(or channel-id id))
:ref #(reset! card-ref %)
:active-opacity 1}
[rn/view {:style (style/base-container color-50)}
(when banner
[rn/image
{:source (:source banner)
:style {:width 160}}])
[rn/view {:style style/secondary-container}
[quo/text
{:size :paragraph-1
:weight :semi-bold
:number-of-lines 1
:ellipsize-mode :tail
:style style/title}
title]
[quo/text
{:size :paragraph-2
:weight :medium
:style style/subtitle}
(subtitle type content)]
[bottom-container type (merge {:color-50 color-50 :color-60 color-60} content)]]
(when avatar-params
[rn/view {:style style/avatar-container}
[avatar avatar-params type customization-color]])
[quo/button
{:size 24
:type :grey
:icon true
:on-press #(rf/dispatch [:shell/close-switcher-card id])
:override-theme :dark
:style style/close-button}
:i/close]]]))))
;; browser Card
(defn browser-card

View File

@ -1,59 +1,42 @@
(ns status-im2.contexts.shell.constants
(:require [react-native.platform :as platform]
[utils.re-frame :as rf]
[react-native.safe-area :as safe-area]))
(ns status-im2.contexts.shell.constants)
(def shell-animation-time 200)
(def ^:const shell-animation-time 200)
(def ^:const switcher-card-size 160)
(defn bottom-tabs-container-height
[]
(if platform/android? 57 82))
;; Bottom tabs
(def ^:const bottom-tabs-container-height-android 57)
(def ^:const bottom-tabs-container-height-ios 82)
(def ^:const bottom-tabs-container-extended-height-android 90)
(def ^:const bottom-tabs-container-extended-height-ios 120)
(def ^:const bottom-tab-width 90)
(defn bottom-tabs-extended-container-height
[]
(if platform/android? 90 120))
;; Stacks
(def ^:const stacks-ids [:communities-stack :chats-stack :wallet-stack :browser-stack])
(defn status-bar-offset
[]
(if platform/android? (safe-area/get-top) 0))
;; status bar height is not included in : the dimensions/window for devices with a notch
;; https://github.com/facebook/react-native/issues/23693#issuecomment-662860819
;; More info - https://github.com/status-im/status-mobile/issues/14633
(defn dimensions
[]
(let [{:keys [width height]} (rf/sub [:dimensions/window])]
{:width width
:height (if (> (status-bar-offset) 28)
(+ height (status-bar-offset))
height)}))
(def stacks-ids [:communities-stack :chats-stack :wallet-stack :browser-stack])
(def stacks-opacity-keywords
;; Keywords
(def ^:const stacks-opacity-keywords
{:communities-stack :communities-stack-opacity
:chats-stack :chats-stack-opacity
:wallet-stack :wallet-stack-opacity
:browser-stack :browser-stack-opacity})
(def tabs-icon-color-keywords
(def ^:const tabs-icon-color-keywords
{:communities-stack :communities-tab-icon-color
:chats-stack :chats-tab-icon-opacity
:wallet-stack :wallet-tab-icon-opacity
:browser-stack :browser-tab-icon-opacity})
(def stacks-z-index-keywords
(def ^:const stacks-z-index-keywords
{:communities-stack :communities-stack-z-index
:chats-stack :chats-stack-z-index
:wallet-stack :wallet-stack-z-index
:browser-stack :browser-stack-z-index})
;; 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)
(def ^:const close-without-animation 2)
(def ^:const open-without-animation 3)
;; Switcher Cards
(def ^:const empty-card 0)
@ -66,3 +49,15 @@
(def ^:const wallet-collectible 7)
(def ^:const wallet-graph 8)
(def ^:const communities-discover 9)
;; Floating Screens
(def ^:const community-screen :community-overview)
(def ^:const chat-screen :chat)
;; Floating Screen states
(def ^:const close-screen-with-slide-animation 0)
(def ^:const open-screen-with-slide-animation 1)
(def ^:const close-screen-with-shell-animation 2)
(def ^:const open-screen-with-shell-animation 3)
(def ^:const close-screen-without-animation 4)
(def ^:const open-screen-without-animation 5)

View File

@ -3,42 +3,42 @@
[re-frame.core :as re-frame]
[status-im.utils.core :as utils]
[status-im2.constants :as constants]
[status-im2.navigation.events :as navigation]
[status-im.async-storage.core :as async-storage]
[status-im2.contexts.shell.state :as state]
[status-im2.contexts.shell.utils :as shell.utils]
[status-im2.navigation.state :as navigation.state]
[status-im2.contexts.shell.animation :as animation]
[status-im2.contexts.shell.constants :as shell.constants]
[status-im.data-store.switcher-cards :as switcher-cards-store]))
;; Effects
;;;; Effects
;; Navigation
(re-frame/reg-fx
:shell/change-tab-fx
(fn [stack-id]
(when (some #(= stack-id %) shell.constants/stacks-ids)
(animation/bottom-tab-on-press stack-id))))
(animation/bottom-tab-on-press stack-id false))))
(re-frame/reg-fx
:shell/navigate-to-jump-to-fx
(fn []
(animation/close-home-stack false)))
(animation/close-home-stack false)
(some-> ^js @state/jump-to-list-ref
(.scrollToOffset #js {:y 0 :animated false}))))
(re-frame/reg-fx
:shell/navigate-from-shell-fx
(fn [stack-id]
(animation/bottom-tab-on-press stack-id)))
(re-frame/reg-fx
:shell/reset-bottom-tabs
:shell/pop-to-root-fx
(fn []
(let [selected-stack-id @animation/selected-stack-id]
(async-storage/set-item! :selected-stack-id nil)
(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)))))
(reset! state/floating-screens-state {})))
;; Events
(re-frame/reg-fx
:shell/reset-state
(fn []
(reset! state/floating-screens-state {})))
;;;; Events
;; Switcher
(rf/defn switcher-cards-loaded
{:events [:shell/switcher-cards-loaded]}
[{:keys [db]} loaded-switcher-cards]
@ -53,24 +53,21 @@
(let [chat (get-in db [:chats id])]
(case (:chat-type chat)
constants/one-to-one-chat-type
{:navigate-from :chats-stack
:card-id id
{:card-id id
:switcher-card {:type shell.constants/one-to-one-chat-card
:card-id id
:clock now
:screen-id id}}
constants/private-group-chat-type
{:navigate-from :chats-stack
:card-id id
{:card-id id
:switcher-card {:type shell.constants/private-group-chat-card
:card-id id
:clock now
:screen-id id}}
constants/community-chat-type
{:navigate-from :communities-stack
:card-id (:community-id chat)
{:card-id (:community-id chat)
:switcher-card {:type shell.constants/community-channel-card
:card-id (:community-id chat)
:clock now
@ -79,8 +76,7 @@
nil))
:community-overview
{:navigate-from :communities-stack
:card-id id
{:card-id id
:switcher-card {:type shell.constants/community-card
:card-id id
:clock now
@ -95,11 +91,10 @@
(when card-data
(rf/merge
cofx
{:db (assoc-in
db
[:shell/switcher-cards (:card-id card-data)]
switcher-card)
:shell/navigate-from-shell-fx (:navigate-from card-data)}
{:db (assoc-in
db
[:shell/switcher-cards (:card-id card-data)]
switcher-card)}
(switcher-cards-store/upsert-switcher-card-rpc switcher-card)))))
(rf/defn close-switcher-card
@ -110,13 +105,29 @@
{:db (update db :shell/switcher-cards dissoc card-id)}
(switcher-cards-store/delete-switcher-card-rpc card-id)))
;; Navigation
(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 :shell-stack)))
[{:keys [db]}]
(let [chat-screen-open? (shell.utils/floating-screen-open? shell.constants/chat-screen)
community-screen-open? (shell.utils/floating-screen-open? shell.constants/community-screen)]
{:db
(cond-> db
chat-screen-open?
(assoc-in [:shell/floating-screens shell.constants/chat-screen :animation]
shell.constants/close-screen-with-shell-animation)
(and chat-screen-open? community-screen-open?)
(assoc-in [:shell/floating-screens shell.constants/community-screen :animation]
shell.constants/close-screen-without-animation)
(and (not chat-screen-open?) community-screen-open?)
(assoc-in [:shell/floating-screens shell.constants/community-screen :animation]
shell.constants/close-screen-with-shell-animation))
:dispatch [:set-view-id :shell]
:shell/navigate-to-jump-to-fx nil}))
(rf/defn change-shell-status-bar-style
{:events [:change-shell-status-bar-style]}
@ -127,3 +138,85 @@
{:events [:change-shell-nav-bar-color]}
[_ color]
{:merge-options {:id "shell-stack" :options {:navigationBar {:backgroundColor color}}}})
(rf/defn shell-navigate-to
{:events [:shell/navigate-to]}
[{:keys [db]} go-to-view-id screen-params animation hidden-screen?]
(if (shell.utils/shell-navigation? go-to-view-id)
(let [current-view-id (:view-id db)
community-id (get-in db [:chats screen-params :community-id])]
{:db (assoc-in
db
[:shell/floating-screens go-to-view-id]
{:id screen-params
:community-id community-id
:hidden-screen? hidden-screen?
:animation (or animation
(case current-view-id
:shell shell.constants/open-screen-with-shell-animation
:chat shell.constants/open-screen-without-animation
shell.constants/open-screen-with-slide-animation))})
:dispatch-n (cond-> []
(not hidden-screen?)
(conj [:set-view-id go-to-view-id])
(and (= go-to-view-id shell.constants/community-screen)
(not hidden-screen?)
(:current-chat-id db))
(conj [:chat/close]))})
{:db (assoc db :view-id go-to-view-id)
:navigate-to go-to-view-id}))
(rf/defn shell-navigate-back
{:events [:shell/navigate-back]}
[{:keys [db]}]
(let [chat-screen-open? (shell.utils/floating-screen-open? shell.constants/chat-screen)
community-screen-open? (shell.utils/floating-screen-open? shell.constants/community-screen)
current-chat-id (:current-chat-id db)
community-id (when current-chat-id
(get-in db [:chats current-chat-id :community-id]))]
(if (and (not @navigation.state/curr-modal)
(or chat-screen-open? community-screen-open?))
{:db (assoc-in
db
[:shell/floating-screens
(if chat-screen-open? shell.constants/chat-screen shell.constants/community-screen)
:animation]
shell.constants/close-screen-with-slide-animation)
:dispatch-n (cond-> [[:set-view-id
(cond
(and chat-screen-open? community-screen-open?)
shell.constants/community-screen
community-screen-open?
:communities-stack
:else :chats-stack)]]
;; When navigating back from community chat to community, update switcher card
(and chat-screen-open? community-screen-open? community-id)
(conj [:shell/add-switcher-card shell.constants/community-screen community-id]))}
{:navigate-back nil})))
(rf/defn floating-screen-opened
{:events [:shell/floating-screen-opened]}
[{:keys [db]} screen-id id community-id hidden-screen?]
(merge
{:db (assoc-in db [:shell/loaded-screens screen-id] true)
:shell/change-tab-fx (if (or (= screen-id shell.constants/community-screen)
community-id)
:communities-stack
:chats-stack)}
(when community-id
;; When opening community chat, open community screen in background
{:dispatch [:shell/navigate-to shell.constants/community-screen
community-id shell.constants/open-screen-without-animation true]})
;; Only update switcher cards for top screen
(when-not hidden-screen?
{:dispatch-later [{:ms (* 2 shell.constants/shell-animation-time)
:dispatch [:shell/add-switcher-card screen-id id]}]})))
(rf/defn floating-screen-closed
{:events [:shell/floating-screen-closed]}
[{:keys [db]} screen-id]
(merge
{:db (-> (update db :shell/floating-screens dissoc screen-id)
(update :shell/loaded-screens dissoc screen-id))}
(when (= screen-id shell.constants/chat-screen)
{:dispatch [:chat/close]})))

View File

@ -1,59 +0,0 @@
(ns status-im2.contexts.shell.home-stack
(:require [react-native.reanimated :as reanimated]
[status-im.ui.screens.wallet.accounts.views :as wallet.accounts]
[status-im2.contexts.chat.home.view :as chat]
[status-im2.contexts.communities.home.view :as communities]
[status-im2.contexts.shell.animation :as animation]
[status-im2.contexts.shell.constants :as shell.constants]
[status-im2.contexts.shell.style :as styles]
[status-im.ui.screens.browser.stack :as browser.stack]))
(defn load-stack?
[stack-id]
(case stack-id
: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- f-stack-view
[stack-id shared-values]
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:opacity (get shared-values
(get shell.constants/stacks-opacity-keywords stack-id))
:z-index (get shared-values
(get shell.constants/stacks-z-index-keywords stack-id))}
{:position :absolute
:top 0
:bottom 0
:left 0
:right 0
:accessibility-label stack-id})}
(case stack-id
:communities-stack [communities/home]
:chats-stack [chat/home]
:wallet-stack [wallet.accounts/accounts-overview-old]
:browser-stack [browser.stack/browser-stack])])
(defn lazy-screen
[stack-id shared-values]
(when (load-stack? stack-id)
[:f> f-stack-view stack-id shared-values]))
(defn f-home-stack
[]
(let [shared-values @animation/shared-values-atom
home-stack-original-style (styles/home-stack @animation/screen-height)
home-stack-animated-style (reanimated/apply-animations-to-style
{:top (:home-stack-top shared-values)
:left (:home-stack-left shared-values)
:opacity (:home-stack-opacity shared-values)
:pointer-events (:home-stack-pointer shared-values)
:transform [{:scale (:home-stack-scale shared-values)}]}
home-stack-original-style)]
[reanimated/view {:style home-stack-animated-style}
[lazy-screen :communities-stack shared-values]
[lazy-screen :chats-stack shared-values]
[lazy-screen :browser-stack shared-values]
[lazy-screen :wallet-stack shared-values]]))

View File

@ -0,0 +1,127 @@
(ns status-im2.contexts.shell.shared-values
(:require [quo2.foundations.colors :as colors]
[react-native.safe-area :as safe-area]
[react-native.reanimated :as reanimated]
[utils.worklets.shell :as worklets.shell]
[status-im2.contexts.shell.utils :as utils]
[status-im2.contexts.shell.state :as state]
[status-im2.contexts.shell.constants :as shell.constants]))
(defn calculate-home-stack-position
[{:keys [width height]}]
(let [bottom-nav-tab-width shell.constants/bottom-tab-width
minimize-scale (/ bottom-nav-tab-width width)
empty-space-half-scale (/ (- 1 minimize-scale) 2)
left-margin (/ (- width (* 4 bottom-nav-tab-width)) 2)
left-empty-space (* empty-space-half-scale width)
top-empty-space (* empty-space-half-scale
(- height (utils/bottom-tabs-container-height)))]
{:left (reduce
(fn [acc stack-id]
(assoc acc
stack-id
(+ (- left-margin left-empty-space)
(* (.indexOf shell.constants/stacks-ids stack-id)
bottom-nav-tab-width))))
{:none 0}
shell.constants/stacks-ids)
:top (+ top-empty-space (utils/bottom-tabs-container-height))
:scale minimize-scale}))
(defn stacks-and-bottom-tabs-derived-values
[{:keys [selected-stack-id home-stack-state]}]
(let [pass-through (reanimated/use-shared-value false)]
(reduce
(fn [acc id]
(let [tabs-icon-color-keyword (get shell.constants/tabs-icon-color-keywords id)
stack-opacity-keyword (get shell.constants/stacks-opacity-keywords id)
stack-z-index-keyword (get shell.constants/stacks-z-index-keywords id)]
(assoc
acc
stack-opacity-keyword
(worklets.shell/stack-opacity (name id) selected-stack-id)
stack-z-index-keyword
(worklets.shell/stack-z-index (name id) selected-stack-id)
tabs-icon-color-keyword
(worklets.shell/bottom-tab-icon-color
(name id)
selected-stack-id
home-stack-state
pass-through
colors/white
colors/neutral-50
colors/white-opa-40))))
{:bottom-tabs-height (worklets.shell/bottom-tabs-height
home-stack-state
(utils/bottom-tabs-container-height)
(utils/bottom-tabs-extended-container-height))
:pass-through pass-through}
shell.constants/stacks-ids)))
(defn home-stack-derived-values
[{:keys [selected-stack-id home-stack-state]} dimensions]
(let [home-stack-position (calculate-home-stack-position dimensions)
animate-home-stack-left (reanimated/use-shared-value (not (utils/home-stack-open?)))]
{:animate-home-stack-left animate-home-stack-left
:home-stack-left (worklets.shell/home-stack-left
selected-stack-id
animate-home-stack-left
home-stack-state
(clj->js (:left home-stack-position)))
:home-stack-top (worklets.shell/home-stack-top
home-stack-state
(:top home-stack-position))
:home-stack-opacity (worklets.shell/home-stack-opacity home-stack-state)
:home-stack-pointer (worklets.shell/home-stack-pointer home-stack-state)
:home-stack-scale (worklets.shell/home-stack-scale
home-stack-state
(:scale home-stack-position))}))
(defn floating-screen-derived-values
[screen-id {:keys [width height]} switcher-card-left-position switcher-card-top-position]
(let [screen-state (reanimated/use-shared-value
(if (utils/floating-screen-open? screen-id)
shell.constants/open-screen-without-animation
shell.constants/close-screen-without-animation))]
{:screen-state screen-state
:screen-left (worklets.shell/floating-screen-left screen-state width switcher-card-left-position)
:screen-top (worklets.shell/floating-screen-top screen-state switcher-card-top-position)
:screen-z-index (worklets.shell/floating-screen-z-index screen-state)
:screen-width (worklets.shell/floating-screen-width screen-state
width
shell.constants/switcher-card-size)
:screen-height (worklets.shell/floating-screen-height screen-state
height
shell.constants/switcher-card-size)}))
(defn calculate-and-set-shared-values
[]
(let [{:keys [width] :as dimensions} (utils/dimensions)
switcher-card-left-position (/ (- width (* 2 shell.constants/switcher-card-size)) 3)
switcher-card-top-position (+ (safe-area/get-top) 120)
shared-values
{:selected-stack-id (reanimated/use-shared-value
(name (or @state/selected-stack-id :communities-stack)))
:home-stack-state (reanimated/use-shared-value @state/home-stack-state)}]
;; Whenever shell stack is created, calculate shared values function is called
;; Means On login and on UI reloading (like changing theme)
;; So we are also resetting bottom tabs here (disabling loading of unselected tabs),
;; for Speed up UI reloading
(utils/reset-bottom-tabs)
(reset!
state/shared-values-atom
(merge
shared-values
(stacks-and-bottom-tabs-derived-values shared-values)
(home-stack-derived-values shared-values dimensions)
{shell.constants/community-screen (floating-screen-derived-values
shell.constants/community-screen
dimensions
switcher-card-left-position
switcher-card-top-position)
shell.constants/chat-screen (floating-screen-derived-values
shell.constants/chat-screen
dimensions
switcher-card-left-position
switcher-card-top-position)}))
@state/shared-values-atom))

View File

@ -0,0 +1,18 @@
(ns status-im2.contexts.shell.state
(:require [reagent.core :as reagent]
[status-im2.contexts.shell.constants :as shell.constants]))
;; Atoms
(def selected-stack-id (atom nil))
(def screen-height (atom nil))
(def shared-values-atom (atom nil))
(def jump-to-list-ref (atom nil))
(def home-stack-state (atom shell.constants/close-with-animation))
(def floating-screens-state (atom {}))
;; 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))

View File

@ -1,108 +0,0 @@
(ns status-im2.contexts.shell.style
(:require [quo2.foundations.colors :as colors]
[react-native.platform :as platform]
[status-im2.contexts.shell.constants :as shell.constants]))
;; Bottom Tabs
(defn bottom-tabs-container
[pass-through?]
{:background-color (if pass-through? :transparent colors/neutral-100)
:flex 1
:align-items :center
:height (shell.constants/bottom-tabs-container-height)
:position :absolute
:bottom 0
:right 0
:left 0
:overflow :hidden
:accessibility-label :bottom-tabs-container})
(defn bottom-tabs
[]
{:flex-direction :row
:position :absolute
:bottom (if platform/android? 8 34)
:flex 1
:accessibility-label :bottom-tabs})
(def bottom-tabs-blur-overlay
{:position :absolute
:left 0
:right 0
:bottom 0
:height (shell.constants/bottom-tabs-extended-container-height)
:background-color colors/neutral-100-opa-70})
;; Home Stack
(defn home-stack
[screen-height]
(let [{:keys [width height]} (shell.constants/dimensions)
height (or screen-height height)]
{:border-bottom-left-radius 20
:border-bottom-right-radius 20
:background-color (colors/theme-colors colors/white colors/neutral-95)
:overflow :hidden
:position :absolute
:width width
:height (- height (shell.constants/bottom-tabs-container-height))}))
;; Placeholder
(defn placeholder-container
[status-bar-height]
{:position :absolute
:top (+ 112 status-bar-height)
:left 0
:right 0
:bottom (shell.constants/bottom-tabs-container-height)
:align-items :center
:accessibility-label :shell-placeholder-view})
(def placeholder-image
{:margin-top 186
:width 120
:height 120
;; Code to remove once placeholder image/vector will be available
:border-width 5
:border-radius 10
:border-color :red})
(def placeholder-title
{:margin-top 20
:color colors/white})
(def placeholder-subtitle
{:margin-top 4
:color colors/white})
;; Shell
(defn jump-to-text
[status-bar-height]
{:color colors/white
:margin-top (+ 68 status-bar-height)
:margin-bottom 20
:margin-left 20})
(def jump-to-list
{:top 0
:left 0
:right 0
:bottom 0
:position :absolute})
(defn top-nav-blur-overlay-container
[height pass-through?]
{:height height
:position :absolute
:left 0
:top 0
:right 0
:overflow :hidden
:background-color (if pass-through? :transparent colors/neutral-100)})
(def top-nav-blur-overlay
{:height 100
:position :absolute
:left 0
:right 0
:top 0
:background-color colors/neutral-100-opa-70})

View File

@ -0,0 +1,120 @@
(ns status-im2.contexts.shell.utils
(:require [utils.re-frame :as rf]
[react-native.core :as rn]
[quo2.foundations.colors :as colors]
[react-native.platform :as platform]
[react-native.safe-area :as safe-area]
[status-im2.contexts.shell.state :as state]
[status-im.async-storage.core :as async-storage]
[status-im2.contexts.shell.constants :as shell.constants]))
;;;; Helper Functions
;;; UI
(defn bottom-tabs-container-height
[]
(if platform/android?
shell.constants/bottom-tabs-container-height-android
shell.constants/bottom-tabs-container-height-ios))
(defn bottom-tabs-extended-container-height
[]
(if platform/android?
shell.constants/bottom-tabs-container-extended-height-android
shell.constants/bottom-tabs-container-extended-height-ios))
(defn status-bar-offset
[]
(if platform/android? (safe-area/get-top) 0))
;; status bar height is not included in : the dimensions/window for devices with a notch
;; https://github.com/facebook/react-native/issues/23693#issuecomment-662860819
;; More info - https://github.com/status-im/status-mobile/issues/14633
(defn dimensions
[]
(let [{:keys [width height]} (rn/get-window)]
{:width width
:height (or @state/screen-height
(if (> (status-bar-offset) 28)
(+ height (status-bar-offset))
height))}))
;;;; State
;;; Home Stack
(defn home-stack-open?
[]
(let [state @state/home-stack-state]
(or (= state shell.constants/open-with-animation)
(= state shell.constants/open-without-animation))))
(defn calculate-home-stack-state-value
[stack-id animate?]
(if animate?
(if (some? stack-id)
shell.constants/open-with-animation
shell.constants/close-with-animation)
(if (some? stack-id)
shell.constants/open-without-animation
shell.constants/close-without-animation)))
(defn load-stack
[stack-id]
(case stack-id
:communities-stack (reset! state/load-communities-stack? true)
:chats-stack (reset! state/load-chats-stack? true)
:wallet-stack (reset! state/load-wallet-stack? true)
:browser-stack (reset! state/load-browser-stack? true)
""))
(defn change-selected-stack-id
[stack-id store? home-stack-state-value]
(let [home-stack-state-value (or home-stack-state-value
(calculate-home-stack-state-value stack-id nil))]
(reset! state/selected-stack-id stack-id)
(reset! state/home-stack-state home-stack-state-value)
(when store?
(async-storage/set-item! :selected-stack-id stack-id))))
(defn reset-bottom-tabs
[]
(let [selected-stack-id @state/selected-stack-id]
(reset! state/load-communities-stack? (= selected-stack-id :communities-stack))
(reset! state/load-chats-stack? (= selected-stack-id :chats-stack))
(reset! state/load-wallet-stack? (= selected-stack-id :wallet-stack))
(reset! state/load-browser-stack? (= selected-stack-id :browser-stack))))
;;; Floating screen
(defn floating-screen-open?
[screen-id]
(let [state (get @state/floating-screens-state screen-id)]
(or (= state shell.constants/open-screen-with-slide-animation)
(= state shell.constants/open-screen-with-shell-animation)
(= state shell.constants/open-screen-without-animation))))
;;; Navigation
(defn shell-navigation?
[view-id]
(#{:chat :community-overview} view-id))
(defn calculate-view-id
[]
(cond
(floating-screen-open? shell.constants/chat-screen)
shell.constants/chat-screen
(floating-screen-open? shell.constants/community-screen)
shell.constants/community-screen
:else (or @state/selected-stack-id :shell)))
(defn update-view-id
[view-id]
(rf/dispatch [:set-view-id view-id]))
;;; Misc
(defn change-shell-status-bar-style
[]
(rf/dispatch [:change-shell-status-bar-style
(if (or (colors/dark?)
(not (home-stack-open?)))
:light
:dark)]))

View File

@ -1,136 +1,53 @@
(ns status-im2.contexts.shell.view
(:require [utils.i18n :as i18n]
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
(:require [quo2.core :as quo]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[react-native.core :as rn]
[react-native.blur :as blur]
[react-native.linear-gradient :as linear-gradient]
[react-native.safe-area :as safe-area]
[status-im2.common.home.view :as common.home]
[status-im2.contexts.shell.utils :as utils]
[status-im2.navigation.state :as navigation.state]
[status-im2.contexts.shell.animation :as animation]
[status-im2.contexts.shell.bottom-tabs :as bottom-tabs]
[status-im2.contexts.shell.cards.view :as switcher-cards]
[status-im2.contexts.shell.constants :as shell.constants]
[status-im2.contexts.shell.home-stack :as home-stack]
[status-im2.contexts.shell.style :as style]
[utils.re-frame :as rf]))
[status-im2.contexts.shell.shared-values :as shared-values]
[status-im2.contexts.shell.components.home-stack.view :as home-stack]
[status-im2.contexts.shell.components.bottom-tabs.view :as bottom-tabs]
[status-im2.contexts.shell.components.shell-screen.view :as shell-screen]
[status-im2.contexts.shell.components.floating-screens.view :as floating-screens]))
(defn placeholder
(defn navigate-back-handler
[]
[linear-gradient/linear-gradient
{:colors [colors/neutral-100-opa-0 colors/neutral-100-opa-100]
:start {:x 0 :y 0}
:end {:x 0 :y 1}
:style (style/placeholder-container (safe-area/get-top))}
[rn/image
{:source nil ;; TODO(parvesh) - add placeholder image
:style style/placeholder-image}]
[quo/text
{:size :paragraph-1
:weight :semi-bold
:style style/placeholder-title}
(i18n/label :t/shell-placeholder-title)]
[quo/text
{:size :paragraph-2
:weight :regular
:align :center
:style style/placeholder-subtitle}
(i18n/label :t/shell-placeholder-subtitle)]])
(defn jump-to-text
[]
[quo/text
{:size :heading-1
:weight :semi-bold
:style (style/jump-to-text (safe-area/get-top))}
(i18n/label :t/jump-to)])
(defn render-card
[{:keys [type screen-id] :as card}]
(let [card-data (case type
shell.constants/one-to-one-chat-card
(rf/sub [:shell/one-to-one-chat-card screen-id])
shell.constants/private-group-chat-card
(rf/sub [:shell/private-group-chat-card screen-id])
shell.constants/community-card
(rf/sub [:shell/community-card screen-id])
shell.constants/community-channel-card
(rf/sub [:shell/community-channel-card screen-id])
nil)]
[switcher-cards/card (merge card card-data)]))
(def empty-cards (repeat 6 {:type shell.constants/empty-card}))
(defn jump-to-list
[switcher-cards shell-margin]
(let [data (if (seq switcher-cards) switcher-cards empty-cards)]
[:<>
[rn/flat-list
{:data data
: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 style/jump-to-list
:content-container-style {:padding-bottom (shell.constants/bottom-tabs-container-height)}}]
(when-not (seq switcher-cards)
[placeholder])]))
(defn top-nav-blur-overlay
[top]
(let [pass-through? (rf/sub [:shell/shell-pass-through?])]
[rn/view {:style (style/top-nav-blur-overlay-container (+ 56 top) pass-through?)}
(when pass-through?
[blur/view (bottom-tabs/blur-overlay-params style/top-nav-blur-overlay)])]))
(defn shell
[customization-color]
(let [switcher-cards (rf/sub [:shell/sorted-switcher-cards])
width (rf/sub [:dimensions/window-width])
top (safe-area/get-top)
shell-margin (/ (- width 320) 3)] ;; 320 - two cards width
[rn/view
{:style {:top 0
:left 0
:right 0
:bottom -1
:position :absolute
:background-color colors/neutral-100}}
[jump-to-list switcher-cards shell-margin]
[top-nav-blur-overlay top]
[common.home/top-nav
{:type :shell
:avatar {:customization-color customization-color}
:style {:margin-top top
:z-index 2}}]]))
(if (and (not @navigation.state/curr-modal)
(or
(utils/floating-screen-open? shell.constants/community-screen)
(utils/floating-screen-open? shell.constants/chat-screen)))
(do (rf/dispatch [:navigate-back])
true)
false))
(defn f-shell-stack
[]
(let [shared-values (animation/calculate-shared-values)
(let [shared-values (shared-values/calculate-and-set-shared-values)
{:keys [key-uid]} (rf/sub [:multiaccount])
profile-color (:color (rf/sub [:onboarding-2/profile]))
customization-color (if profile-color
profile-color
customization-color (if profile-color ;; Todo - 1. Use single sub for customization color
profile-color ;; Todo - 2. Move sub to child view
(rf/sub [:profile/customization-color key-uid]))]
[rn/view
{:style {:flex 1}}
[shell customization-color]
[bottom-tabs/bottom-tabs]
(rn/use-effect
(fn []
(rn/hw-back-add-listener navigate-back-handler)
#(rn/hw-back-remove-listener navigate-back-handler))
[])
[:<>
[shell-screen/view customization-color]
[:f> bottom-tabs/f-bottom-tabs]
[:f> home-stack/f-home-stack]
[quo/floating-shell-button
{:jump-to {:on-press #(animation/close-home-stack true)
:label (i18n/label :t/jump-to)
:customization-color customization-color}}
{:position :absolute
:bottom (+ (shell.constants/bottom-tabs-container-height) 12)}
(:home-stack-opacity shared-values)]]))
:bottom (+ (utils/bottom-tabs-container-height) 12)}
(:home-stack-opacity shared-values)]
[floating-screens/view]]))
(defn shell-stack
[]

View File

@ -9,7 +9,8 @@
[react-native.platform :as platform]
[react-native.shake :as react-native-shake]
[reagent.impl.batching :as batching]
[status-im2.contexts.shell.animation :as animation]
[status-im2.contexts.shell.utils :as shell.utils]
[status-im2.contexts.shell.state :as shell.state]
[status-im2.config :as config]
[status-im2.setup.dev :as dev]
[status-im2.setup.global-error :as global-error]
@ -44,10 +45,9 @@
(react-native-shake/add-shake-listener #(re-frame/dispatch [:shake-event]))
(utils.universal-links/initialize)
;; TODO(parvesh) - Remove while moving functionality to status-go
(async-storage/get-item :selected-stack-id #(animation/change-selected-stack-id %))
(async-storage/get-item :screen-height #(reset! animation/screen-height %))
;; Shell
(async-storage/get-item :selected-stack-id #(shell.utils/change-selected-stack-id % nil nil))
(async-storage/get-item :screen-height #(reset! shell.state/screen-height %))
(dev/setup)

View File

@ -4,7 +4,6 @@
[react-native.gesture :as gesture]
[react-native.navigation :as navigation]
[status-im.multiaccounts.login.core :as login-core]
[status-im2.contexts.shell.animation :as shell.animation]
[status-im2.navigation.roots :as roots]
[status-im2.navigation.state :as state]
[status-im2.navigation.view :as views]
@ -36,14 +35,16 @@
(defn set-view-id
[view-id]
(when-let [{:keys [on-focus]} (get views/screens view-id)]
(re-frame/dispatch [:screens/on-will-focus view-id])
(re-frame/dispatch [:set-view-id
(if (= view-id :shell-stack)
(or @shell.animation/selected-stack-id :shell)
view-id)])
(when on-focus
(re-frame/dispatch on-focus))))
(when (get views/screens view-id)
(re-frame/dispatch [:set-view-id view-id])))
(re-frame/reg-fx
:set-view-id-fx
(fn [view-id]
(re-frame/dispatch [:screens/on-will-focus view-id])
(when-let [{:keys [on-focus]} (get views/screens view-id)]
(when on-focus
(re-frame/dispatch on-focus)))))
(navigation/reg-component-did-appear-listener
(fn [view-id]
@ -106,7 +107,12 @@
(dissmissModal)
(navigation/pop (name @state/root-id)))))
(re-frame/reg-fx :pop-to-root-fx navigation/pop-to-root)
(defn pop-to-root
[root-id]
(navigation/pop-to-root root-id)
(dismiss-all-modals))
(re-frame/reg-fx :pop-to-root-fx pop-to-root)
;; MODAL
(defn open-modal

View File

@ -1,5 +1,7 @@
(ns status-im2.navigation.events
(:require [utils.re-frame :as rf]))
(:require [utils.re-frame :as rf]
[status-im2.contexts.shell.utils :as shell.utils]
[status-im2.contexts.shell.events :as shell.events]))
(defn- all-screens-params
[db view screen-params]
@ -12,17 +14,12 @@
(rf/defn navigate-to
{:events [:navigate-to]}
[{:keys [db]} go-to-view-id screen-params]
(merge
{:db (-> (assoc db :view-id go-to-view-id)
(all-screens-params go-to-view-id screen-params))
:navigate-to go-to-view-id
:dispatch [:hide-bottom-sheet]}
(when (#{:chat :community-overview} go-to-view-id)
{:dispatch-later
;; 300 ms delay because, navigation is priority over shell card update
[{:dispatch [:shell/add-switcher-card go-to-view-id screen-params]
:ms 300}]})))
[{:keys [db] :as cofx} go-to-view-id screen-params]
(rf/merge
cofx
{:db (all-screens-params db go-to-view-id screen-params)
:dispatch-n [[:hide-bottom-sheet]]}
(shell.events/shell-navigate-to go-to-view-id screen-params nil nil)))
(rf/defn open-modal
{:events [:open-modal]}
@ -34,13 +31,15 @@
(rf/defn navigate-back
{:events [:navigate-back]}
[_]
{:navigate-back nil})
[cofx]
(shell.events/shell-navigate-back cofx))
(rf/defn pop-to-root
{:events [:pop-to-root]}
[_ tab]
{:pop-to-root-fx tab})
[{:keys [db]} tab]
{:pop-to-root-fx tab
:db (dissoc db :shell/floating-screens)
:shell/pop-to-root-fx nil})
(rf/defn init-root
{:events [:init-root]}
@ -54,8 +53,9 @@
(rf/defn change-tab
{:events [:navigate-change-tab]}
[_ stack-id]
{:shell/change-tab-fx stack-id})
[{:keys [db]} stack-id]
{:db (assoc db :view-id stack-id)
:shell/change-tab-fx stack-id})
(rf/defn navigate-replace
{:events [:navigate-replace]}
@ -154,3 +154,10 @@
[:hide-select-acc-sheet]
[:bottom-sheet/hide-old-navigation-overlay]
[:toasts/close-all-toasts]]})
(rf/defn set-view-id
{:events [:set-view-id]}
[{:keys [db]} view-id]
(let [view-id (if (= view-id :shell-stack) (shell.utils/calculate-view-id) view-id)]
{:db (assoc db :view-id view-id)
:set-view-id-fx view-id}))

View File

@ -75,6 +75,8 @@
(reg-root-key-sub :visibility-status-updates :visibility-status-updates)
(reg-root-key-sub :shell/switcher-cards :shell/switcher-cards)
(reg-root-key-sub :password-authentication :password-authentication)
(reg-root-key-sub :shell/floating-screens :shell/floating-screens)
(reg-root-key-sub :shell/loaded-screens :shell/loaded-screens)
;;NOTE this one is not related to ethereum network
;; it is about cellular network/ wifi network

View File

@ -2,8 +2,11 @@
(:require [re-frame.core :as re-frame]
[utils.datetime :as datetime]
[status-im2.constants :as constants]
[status-im2.common.resources :as resources]))
[react-native.platform :as platform]
[status-im2.common.resources :as resources]
[status-im2.contexts.shell.constants :as shell.constants]))
;; Helper Functions
(defn community-avatar
[community]
(let [images (:images community)]
@ -66,18 +69,16 @@
: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/navigate-to-chat id])
:content (get-card-content chat communities)}))
:content (get-card-content chat communities)
:id id}))
(defn private-group-chat-card
[chat id communities]
{: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/navigate-to-chat id])
:content (get-card-content chat communities)})
:content (get-card-content chat communities)
:id id})
(defn community-card
[community id]
@ -87,22 +88,18 @@
{: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 :community-overview id])
:content {:community-info {:type :permission}}}))
:content {:community-info {:type :permission}}
:id id}))
(defn community-channel-card
[community community-id channel channel-id]
(merge
(community-card community community-id)
{:content {:community-channel {:emoji (:emoji channel)
:channel-name (str "# " (:name channel))}}
:on-press (fn []
(re-frame/dispatch [:navigate-to :community-overview community-id])
(js/setTimeout
#(re-frame/dispatch [:chat/navigate-to-chat channel-id])
100))}))
{:content {:community-channel {:emoji (:emoji channel)
:channel-name (str "# " (:name channel))}}
:channel-id channel-id}))
;;;; Subscriptions
(def memo-shell-cards (atom nil))
(re-frame/reg-sub
@ -122,6 +119,7 @@
(fn [stacks]
(> (count stacks) 6)))
;; Switcher Cards
(re-frame/reg-sub
:shell/one-to-one-chat-card
(fn [[_ id] _]
@ -157,6 +155,7 @@
community (get communities (:community-id channel))]
(community-channel-card community community-id channel channel-id))))
;; Bottom tabs
(re-frame/reg-sub
:shell/bottom-tabs-notifications-data
:<- [:chats/chats]
@ -191,3 +190,19 @@
{:new-notifications? (pos? (:unviewed-messages-count chats-stack))
:notification-indicator (if (pos? (:unviewed-mentions-count chats-stack)) :counter :unread-dot)
:counter-label (:unviewed-mentions-count chats-stack)}})))
;; Floating screens
(re-frame/reg-sub
:shell/floating-screen
:<- [:shell/floating-screens]
(fn [screens [_ screen-id]]
(get screens screen-id)))
(re-frame/reg-sub
:shell/animation-complete?
:<- [:shell/loaded-screens]
(fn [screens [_ chat-type]]
(or platform/ios?
(cond-> (get screens shell.constants/chat-screen)
(= chat-type constants/community-chat-type)
(and (get screens shell.constants/community-screen))))))

View File

@ -1,23 +1,21 @@
(ns utils.worklets.shell)
(def shell-worklets (js/require "../src/js/worklets/shell.js"))
(defn stack-opacity
[id selected-stack-id]
(.stackOpacity ^js shell-worklets id selected-stack-id))
(defn stack-z-index
[id selected-stack-id]
(.stackZIndex ^js shell-worklets id selected-stack-id))
(def bottom-tabs-worklets (js/require "../src/js/worklets/shell/bottom_tabs.js"))
(def home-stack-worklets (js/require "../src/js/worklets/shell/home_stack.js"))
(def floating-screen-worklets (js/require "../src/js/worklets/shell/floating_screen.js"))
;; Derived values for Bottom tabs
(defn bottom-tabs-height
[home-stack-state-sv container-height extended-container-height]
(.bottomTabsHeight ^js shell-worklets home-stack-state-sv container-height extended-container-height))
(.bottomTabsHeight ^js bottom-tabs-worklets
home-stack-state-sv
container-height
extended-container-height))
(defn bottom-tab-icon-color
[id selected-stack-id-sv home-stack-state-sv pass-through-sv selected-tab-color default-color
pass-through-color]
(.bottomTabIconColor ^js shell-worklets
(.bottomTabIconColor ^js bottom-tabs-worklets
id
selected-stack-id-sv
home-stack-state-sv
@ -26,22 +24,32 @@
default-color
pass-through-color))
;; Derived values for stacks (communities, chat, wallet, browser)
(defn stack-opacity
[id selected-stack-id]
(.stackOpacity ^js home-stack-worklets id selected-stack-id))
(defn stack-z-index
[id selected-stack-id]
(.stackZIndex ^js home-stack-worklets id selected-stack-id))
;; Derived values for Home stack (container)
(defn home-stack-opacity
[home-stack-state-sv]
(.homeStackOpacity ^js shell-worklets home-stack-state-sv))
(.homeStackOpacity ^js home-stack-worklets home-stack-state-sv))
(defn home-stack-pointer
[home-stack-state-sv]
(.homeStackPointer ^js shell-worklets home-stack-state-sv))
(.homeStackPointer ^js home-stack-worklets home-stack-state-sv))
(defn home-stack-scale
[home-stack-state-sv scale]
(.homeStackScale ^js shell-worklets home-stack-state-sv scale))
(.homeStackScale ^js home-stack-worklets home-stack-state-sv scale))
(defn home-stack-left
[selected-stack-id-sv animate-home-stack-left home-stack-state-sv left-home-stack-position]
(.homeStackLeft
^js shell-worklets
^js home-stack-worklets
selected-stack-id-sv
animate-home-stack-left
home-stack-state-sv
@ -49,4 +57,25 @@
(defn home-stack-top
[home-stack-state-sv top-home-stack-position]
(.homeStackTop ^js shell-worklets home-stack-state-sv top-home-stack-position))
(.homeStackTop ^js home-stack-worklets home-stack-state-sv top-home-stack-position))
;; Derived values for floating screen
(defn floating-screen-left
[screen-state screen-width switcher-card-left-position]
(.screenLeft ^js floating-screen-worklets screen-state screen-width switcher-card-left-position))
(defn floating-screen-top
[screen-state switcher-card-top-position]
(.screenTop ^js floating-screen-worklets screen-state switcher-card-top-position))
(defn floating-screen-width
[screen-state screen-width switcher-card-size]
(.screenWidth ^js floating-screen-worklets screen-state screen-width switcher-card-size))
(defn floating-screen-height
[screen-state screen-height switcher-card-size]
(.screenHeight ^js floating-screen-worklets screen-state screen-height switcher-card-size))
(defn floating-screen-z-index
[screen-state]
(.screenZIndex ^js floating-screen-worklets screen-state))