diff --git a/app/actions/local/thread.ts b/app/actions/local/thread.ts index 035f34ed01..edcf9623c6 100644 --- a/app/actions/local/thread.ts +++ b/app/actions/local/thread.ts @@ -119,6 +119,7 @@ export const switchToThread = async (serverUrl: string, rootId: string) => { subtitle = subtitle.replace('{channelName}', channel.displayName); } + EphemeralStore.setLastViewedThreadId(rootId); goToScreen(Screens.THREAD, '', {rootId}, { topBar: { title: { diff --git a/app/components/formatted_date/index.tsx b/app/components/formatted_date/index.tsx index cd7b7a958e..877213f35b 100644 --- a/app/components/formatted_date/index.tsx +++ b/app/components/formatted_date/index.tsx @@ -6,6 +6,8 @@ import React from 'react'; import {useIntl} from 'react-intl'; import {Text, TextProps} from 'react-native'; +import {getLocaleFromLanguage} from '@i18n'; + type FormattedDateProps = TextProps & { format?: string; timezone?: string | UserTimezone | null; @@ -14,7 +16,7 @@ type FormattedDateProps = TextProps & { const FormattedDate = ({format = 'MMM DD, YYYY', timezone, value, ...props}: FormattedDateProps) => { const {locale} = useIntl(); - moment.locale(locale); + moment.locale(getLocaleFromLanguage(locale).toLowerCase()); let formattedDate = moment(value).format(format); if (timezone) { let zone: string; diff --git a/app/components/formatted_time/index.tsx b/app/components/formatted_time/index.tsx index 2d64b7c4ad..f2a1c2ead5 100644 --- a/app/components/formatted_time/index.tsx +++ b/app/components/formatted_time/index.tsx @@ -3,8 +3,11 @@ import moment from 'moment-timezone'; import React from 'react'; +import {useIntl} from 'react-intl'; import {Text, TextProps} from 'react-native'; +import {getLocaleFromLanguage} from '@i18n'; + type FormattedTimeProps = TextProps & { isMilitaryTime: boolean; timezone: UserTimezone | string; @@ -12,6 +15,8 @@ type FormattedTimeProps = TextProps & { } const FormattedTime = ({isMilitaryTime, timezone, value, ...props}: FormattedTimeProps) => { + const {locale} = useIntl(); + moment.locale(getLocaleFromLanguage(locale).toLowerCase()); const getFormattedTime = () => { let format = 'H:mm'; if (!isMilitaryTime) { diff --git a/app/components/post_draft/archived/index.tsx b/app/components/post_draft/archived/index.tsx index 375121c3f0..f7bc68cbd2 100644 --- a/app/components/post_draft/archived/index.tsx +++ b/app/components/post_draft/archived/index.tsx @@ -2,8 +2,8 @@ // See LICENSE.txt for license information. import React, {useCallback} from 'react'; -import {View} from 'react-native'; import Button from 'react-native-button'; +import {Edge, SafeAreaView} from 'react-native-safe-area-context'; import {switchToPenultimateChannel} from '@actions/remote/channel'; import FormattedMarkdownText from '@components/formatted_markdown_text'; @@ -47,6 +47,8 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => ({ }, })); +const edges: Edge[] = ['bottom']; + export default function Archived({ testID, deactivated, @@ -78,7 +80,8 @@ export default function Archived({ } return ( - @@ -98,6 +101,6 @@ export default function Archived({ style={style.closeButtonText} /> - + ); } diff --git a/app/components/post_draft/read_only/index.tsx b/app/components/post_draft/read_only/index.tsx index e09cdb2b03..88c4d60a65 100644 --- a/app/components/post_draft/read_only/index.tsx +++ b/app/components/post_draft/read_only/index.tsx @@ -3,7 +3,7 @@ import React from 'react'; import {View} from 'react-native'; -import {SafeAreaView} from 'react-native-safe-area-context'; +import {Edge, SafeAreaView} from 'react-native-safe-area-context'; import CompassIcon from '@components/compass_icon'; import FormattedText from '@components/formatted_text'; @@ -40,14 +40,14 @@ const getStyle = makeStyleSheetFromTheme((theme: Theme) => ({ }, })); -const safeAreaEdges = ['bottom' as const]; +const edges: Edge[] = ['bottom']; const ReadOnlyChannnel = ({testID}: ReadOnlyProps) => { const theme = useTheme(); const style = getStyle(theme); return ( { //TODO Create team screen https://mattermost.atlassian.net/browse/MM-43622 dismissBottomSheet(); }, []); - const onTeamAdded = useCallback(() => { - dismissBottomSheet(); - }, []); + const onTeamAdded = useCallback(async (teamId: string) => { + await dismissBottomSheet(); + handleTeamChange(serverUrl, teamId); + }, [serverUrl]); return ( { - await addUserToTeam(serverUrl, team.id, currentUserId); - onTeamAdded(team.id); + const {error} = await addUserToTeam(serverUrl, team.id, currentUserId); + if (!error) { + onTeamAdded(team.id); + } }, [onTeamAdded]); const displayName = 'displayName' in team ? team.displayName : team.display_name; @@ -75,13 +77,13 @@ export default function TeamListItem({team, currentUserId, textColor, iconTextCo displayName={displayName} lastIconUpdate={lastTeamIconUpdateAt} selected={false} - textColor={iconTextColor} - backgroundColor={iconBackgroundColor} + textColor={iconTextColor || theme.centerChannelColor} + backgroundColor={iconBackgroundColor || changeOpacity(theme.centerChannelColor, 0.16)} testID={`${teamListItemTestId}.team_icon`} /> {displayName} diff --git a/app/i18n/index.ts b/app/i18n/index.ts index 1056a983b0..c7fa0d835e 100644 --- a/app/i18n/index.ts +++ b/app/i18n/index.ts @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import moment from 'moment'; +import moment from 'moment-timezone'; import {getLocales} from 'react-native-localize'; import en from '@assets/i18n/en.json'; @@ -149,7 +149,8 @@ function loadTranslation(locale?: string) { } if (momentData && locale) { - moment.updateLocale(locale.toLowerCase(), momentData); + const lang = getLocaleFromLanguage(locale).toLowerCase(); + moment.updateLocale(lang, momentData); } else { resetMomentLocale(); } @@ -173,10 +174,11 @@ export function getLocaleFromLanguage(lang: string) { } export function resetMomentLocale(locale?: string) { - moment.locale(locale || DEFAULT_LOCALE.split('-')[0]); + moment.locale(locale?.split('-')[0] || DEFAULT_LOCALE.split('-')[0]); } -export function getTranslations(locale?: string) { +export function getTranslations(lang: string) { + const locale = getLocaleFromLanguage(lang); return loadTranslation(locale); } diff --git a/app/init/push_notifications.ts b/app/init/push_notifications.ts index 509f31ec0a..bc6691421b 100644 --- a/app/init/push_notifications.ts +++ b/app/init/push_notifications.ts @@ -147,12 +147,13 @@ class PushNotifications { } const isDifferentChannel = payload?.channel_id !== channelId; + const isVisibleThread = payload?.root_id === EphemeralStore.getLastViewedThreadId() && EphemeralStore.getNavigationTopComponentId() === Screens.THREAD; let isChannelScreenVisible = EphemeralStore.getNavigationTopComponentId() === Screens.CHANNEL; if (isTabletDevice) { isChannelScreenVisible = EphemeralStore.getVisibleTab() === Screens.HOME; } - if (isDifferentChannel || !isChannelScreenVisible) { + if (isDifferentChannel || (!isChannelScreenVisible && !isVisibleThread)) { DeviceEventEmitter.emit(Navigation.NAVIGATION_SHOW_OVERLAY); const screen = Screens.IN_APP_NOTIFICATION; diff --git a/app/screens/bottom_sheet/index.tsx b/app/screens/bottom_sheet/index.tsx index 6b6afbd369..9d3ee68559 100644 --- a/app/screens/bottom_sheet/index.tsx +++ b/app/screens/bottom_sheet/index.tsx @@ -12,6 +12,7 @@ import {Events} from '@constants'; import {useTheme} from '@context/theme'; import {useIsTablet} from '@hooks/device'; import {dismissModal} from '@screens/navigation'; +import EphemeralStore from '@store/ephemeral_store'; import {hapticFeedback} from '@utils/general'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; @@ -55,12 +56,15 @@ const BottomSheet = ({closeButtonId, componentId, initialSnapIndex = 0, renderCo useEffect(() => { const listener = BackHandler.addEventListener('hardwareBackPress', () => { - if (sheetRef.current) { - sheetRef.current.snapTo(1); - } else { - close(); + if (EphemeralStore.getNavigationTopComponentId() === componentId) { + if (sheetRef.current) { + sheetRef.current.snapTo(1); + } else { + close(); + } + return true; } - return true; + return false; }); return () => listener.remove(); diff --git a/app/screens/channel/channel.tsx b/app/screens/channel/channel.tsx index dd52980a18..7225c93140 100644 --- a/app/screens/channel/channel.tsx +++ b/app/screens/channel/channel.tsx @@ -14,6 +14,7 @@ import {useAppState, useIsTablet} from '@hooks/device'; import {useDefaultHeaderHeight} from '@hooks/header'; import {useTeamSwitch} from '@hooks/team_switch'; import {popTopScreen} from '@screens/navigation'; +import EphemeralStore from '@store/ephemeral_store'; import ChannelPostList from './channel_post_list'; import ChannelHeader from './header'; @@ -57,8 +58,12 @@ const Channel = ({channelId, componentId}: ChannelProps) => { let back: NativeEventSubscription|undefined; if (!isTablet && componentId) { back = BackHandler.addEventListener('hardwareBackPress', () => { - popTopScreen(componentId); - return true; + if (EphemeralStore.getNavigationTopComponentId() === componentId) { + popTopScreen(componentId); + return true; + } + + return false; }); } diff --git a/app/screens/custom_status/index.tsx b/app/screens/custom_status/index.tsx index 18e360912b..9a7f917b24 100644 --- a/app/screens/custom_status/index.tsx +++ b/app/screens/custom_status/index.tsx @@ -23,6 +23,7 @@ import {withTheme} from '@context/theme'; import {observeConfig, observeRecentCustomStatus} from '@queries/servers/system'; import {observeCurrentUser} from '@queries/servers/user'; import {dismissModal, goToScreen, showModal} from '@screens/navigation'; +import EphemeralStore from '@store/ephemeral_store'; import {getCurrentMomentForTimezone, getRoundedTime, isCustomStatusExpirySupported} from '@utils/helpers'; import {mergeNavigationOptions} from '@utils/navigation'; import {preventDoubleTap} from '@utils/tap'; @@ -164,12 +165,16 @@ class CustomStatusModal extends NavigationComponent { } onBackPress = () => { - if (this.props.isTablet) { - DeviceEventEmitter.emit(Events.ACCOUNT_SELECT_TABLET_VIEW, ''); - } else { - dismissModal(); + const {componentId} = this.props; + if (EphemeralStore.getNavigationTopComponentId() === componentId) { + if (this.props.isTablet) { + DeviceEventEmitter.emit(Events.ACCOUNT_SELECT_TABLET_VIEW, ''); + } else { + dismissModal({componentId}); + } + return true; } - return true; + return false; }; handleSetStatus = async () => { diff --git a/app/screens/custom_status_clear_after/index.tsx b/app/screens/custom_status_clear_after/index.tsx index 7c7b7ff47a..443295fada 100644 --- a/app/screens/custom_status_clear_after/index.tsx +++ b/app/screens/custom_status_clear_after/index.tsx @@ -18,6 +18,7 @@ import { import {CustomStatusDuration} from '@constants/custom_status'; import {observeCurrentUser} from '@queries/servers/user'; import {dismissModal, popTopScreen} from '@screens/navigation'; +import EphemeralStore from '@store/ephemeral_store'; import {mergeNavigationOptions} from '@utils/navigation'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; @@ -111,24 +112,28 @@ class ClearAfterModal extends NavigationComponent { } onBackPress = () => { - if (this.props.isModal) { - dismissModal(); - } else { - popTopScreen(); - } + const {componentId} = this.props; + if (EphemeralStore.getNavigationTopComponentId() === componentId) { + if (this.props.isModal) { + dismissModal({componentId}); + } else { + popTopScreen(componentId); + } - return true; + return true; + } + return false; }; onDone = () => { - const {handleClearAfterClick, isModal} = this.props; + const {componentId, handleClearAfterClick, isModal} = this.props; handleClearAfterClick(this.state.duration, this.state.expiresAt); if (isModal) { - dismissModal(); + dismissModal({componentId}); return; } - popTopScreen(); + popTopScreen(componentId); }; handleItemClick = (duration: CustomStatusDuration, expiresAt: string) => diff --git a/app/screens/edit_profile/edit_profile.tsx b/app/screens/edit_profile/edit_profile.tsx index bc8171d499..b4acc1441c 100644 --- a/app/screens/edit_profile/edit_profile.tsx +++ b/app/screens/edit_profile/edit_profile.tsx @@ -16,6 +16,7 @@ import {Events} from '@constants'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; import {dismissModal, popTopScreen, setButtons} from '@screens/navigation'; +import EphemeralStore from '@store/ephemeral_store'; import {preventDoubleTap} from '@utils/tap'; import ProfileForm from './components/form'; @@ -104,7 +105,14 @@ const EditProfile = ({ }, [userInfo]); useEffect(() => { - const backHandler = BackHandler.addEventListener('hardwareBackPress', close); + const backHandler = BackHandler.addEventListener('hardwareBackPress', () => { + if (EphemeralStore.getNavigationTopComponentId() === componentId) { + close(); + return true; + } + + return false; + }); return () => { backHandler.remove(); }; @@ -127,8 +135,6 @@ const EditProfile = ({ } else { popTopScreen(componentId); } - - return true; }, []); const enableSaveButton = useCallback((value: boolean) => { diff --git a/app/screens/home/channel_list/channel_list.tsx b/app/screens/home/channel_list/channel_list.tsx index b5d2586e85..f4186b297d 100644 --- a/app/screens/home/channel_list/channel_list.tsx +++ b/app/screens/home/channel_list/channel_list.tsx @@ -5,13 +5,13 @@ import {useManagedConfig} from '@mattermost/react-native-emm'; import {useIsFocused, useNavigation, useRoute} from '@react-navigation/native'; import React, {useCallback, useEffect} from 'react'; import {useIntl} from 'react-intl'; -import {BackHandler, StyleSheet, ToastAndroid} from 'react-native'; +import {BackHandler, DeviceEventEmitter, StyleSheet, ToastAndroid} from 'react-native'; import Animated, {useAnimatedStyle, withTiming} from 'react-native-reanimated'; import {Edge, SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context'; import FreezeScreen from '@components/freeze_screen'; import TeamSidebar from '@components/team_sidebar'; -import {Screens} from '@constants'; +import {Navigation as NavigationConstants, Screens} from '@constants'; import {useTheme} from '@context/theme'; import {useIsTablet} from '@hooks/device'; import {resetToTeams} from '@screens/navigation'; @@ -54,7 +54,9 @@ const ChannelListScreen = (props: ChannelProps) => { const canAddOtherServers = managedConfig?.allowOtherServers !== 'false'; const handleBackPress = useCallback(() => { - const focused = navigation.isFocused() && EphemeralStore.getNavigationTopComponentId() === Screens.HOME; + const isHomeScreen = EphemeralStore.getNavigationTopComponentId() === Screens.HOME; + const homeTab = EphemeralStore.getVisibleTab() === Screens.HOME; + const focused = navigation.isFocused() && isHomeScreen && homeTab; if (!backPressedCount && focused) { backPressedCount++; ToastAndroid.show(intl.formatMessage({ @@ -70,6 +72,9 @@ const ChannelListScreen = (props: ChannelProps) => { backPressedCount = 0; }, 2000); return true; + } else if (isHomeScreen && !homeTab) { + DeviceEventEmitter.emit(NavigationConstants.NAVIGATION_HOME); + return true; } return false; }, [intl]); diff --git a/app/screens/home/index.tsx b/app/screens/home/index.tsx index bd8fc5c945..fb79a22190 100644 --- a/app/screens/home/index.tsx +++ b/app/screens/home/index.tsx @@ -103,6 +103,7 @@ export default function HomeScreen(props: HomeProps) { > ( { return ( diff --git a/app/screens/navigation.ts b/app/screens/navigation.ts index 4310304808..65c0587f61 100644 --- a/app/screens/navigation.ts +++ b/app/screens/navigation.ts @@ -581,12 +581,11 @@ export async function dismissAllModals() { } try { - const modals = EphemeralStore.navigationModalStack; + const modals = [...EphemeralStore.getAllNavigationModals()]; for await (const modal of modals) { + EphemeralStore.removeNavigationModal(modal); await Navigation.dismissModal(modal, {animations: {dismissModal: {enabled: false}}}); } - - EphemeralStore.clearNavigationModals(); } catch (error) { // RNN returns a promise rejection if there are no modals to // dismiss. We'll do nothing in this case. diff --git a/app/screens/permalink/permalink.tsx b/app/screens/permalink/permalink.tsx index be424a74d6..c052729735 100644 --- a/app/screens/permalink/permalink.tsx +++ b/app/screens/permalink/permalink.tsx @@ -4,7 +4,7 @@ import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {BackHandler, Text, TouchableOpacity, View} from 'react-native'; import Animated from 'react-native-reanimated'; -import {SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context'; +import {Edge, SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context'; import {switchToChannelById} from '@actions/remote/channel'; import {fetchPostsAround} from '@actions/remote/post'; @@ -16,17 +16,21 @@ import {Screens} from '@constants'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; import {dismissModal} from '@screens/navigation'; -import ChannelModel from '@typings/database/models/servers/channel'; -import PostModel from '@typings/database/models/servers/post'; +import EphemeralStore from '@store/ephemeral_store'; import {closePermalink} from '@utils/permalink'; import {preventDoubleTap} from '@utils/tap'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import type ChannelModel from '@typings/database/models/servers/channel'; +import type PostModel from '@typings/database/models/servers/post'; + type Props = { postId: PostModel['id']; channel?: ChannelModel; } +const edges: Edge[] = ['left', 'right', 'top']; + const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ container: { flex: 1, @@ -145,8 +149,12 @@ function Permalink({channel, postId}: Props) { useEffect(() => { const listener = BackHandler.addEventListener('hardwareBackPress', () => { - handleClose(); - return true; + if (EphemeralStore.getNavigationTopComponentId() === Screens.PERMALINK) { + handleClose(); + return true; + } + + return false; }); return () => { @@ -164,6 +172,7 @@ function Permalink({channel, postId}: Props) { diff --git a/app/screens/post_options/post_options.tsx b/app/screens/post_options/post_options.tsx index ba2f177342..7a4a84a9d8 100644 --- a/app/screens/post_options/post_options.tsx +++ b/app/screens/post_options/post_options.tsx @@ -81,7 +81,7 @@ const PostOptions = ({ return ( <> {canAddReaction && } - {canReply && } + {canReply && sourceScreen !== Screens.THREAD && } {shouldRenderFollow && } diff --git a/app/screens/saved_posts/saved_posts.tsx b/app/screens/saved_posts/saved_posts.tsx index f5933c871c..3ba20e5da4 100644 --- a/app/screens/saved_posts/saved_posts.tsx +++ b/app/screens/saved_posts/saved_posts.tsx @@ -16,6 +16,7 @@ import {Events, Screens} from '@constants'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; import {dismissModal} from '@screens/navigation'; +import EphemeralStore from '@store/ephemeral_store'; import {isDateLine, getDateForDateLine, selectOrderedPosts} from '@utils/post_list'; import EmptyState from './components/empty'; @@ -72,10 +73,7 @@ function SavedMessages({ const close = () => { if (componentId) { dismissModal({componentId}); - return true; } - - return false; }; useEffect(() => { @@ -106,7 +104,14 @@ function SavedMessages({ useEffect(() => { let listener: EventSubscription|undefined; if (!isTablet && componentId) { - listener = BackHandler.addEventListener('hardwareBackPress', close); + listener = BackHandler.addEventListener('hardwareBackPress', () => { + if (EphemeralStore.getNavigationTopComponentId() === componentId) { + close(); + return true; + } + + return false; + }); } return () => listener?.remove(); diff --git a/app/screens/settings/settings.tsx b/app/screens/settings/settings.tsx index c3393379b3..0cbf5c37e6 100644 --- a/app/screens/settings/settings.tsx +++ b/app/screens/settings/settings.tsx @@ -12,6 +12,7 @@ import {Screens} from '@constants'; import {useServerDisplayName} from '@context/server'; import {useTheme} from '@context/theme'; import {dismissModal, goToScreen, setButtons} from '@screens/navigation'; +import EphemeralStore from '@store/ephemeral_store'; import {preventDoubleTap} from '@utils/tap'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; @@ -84,8 +85,6 @@ const Settings = ({componentId, showHelp, siteName}: SettingsProps) => { const close = useCallback(() => { dismissModal({componentId}); - - return true; }, []); useEffect(() => { @@ -95,7 +94,14 @@ const Settings = ({componentId, showHelp, siteName}: SettingsProps) => { }, []); useEffect(() => { - const backHandler = BackHandler.addEventListener('hardwareBackPress', close); + const backHandler = BackHandler.addEventListener('hardwareBackPress', () => { + if (EphemeralStore.getNavigationTopComponentId() === componentId) { + close(); + return true; + } + + return false; + }); return () => { backHandler.remove(); }; diff --git a/app/store/ephemeral_store.ts b/app/store/ephemeral_store.ts index dff03f2f23..6ce90d489c 100644 --- a/app/store/ephemeral_store.ts +++ b/app/store/ephemeral_store.ts @@ -21,6 +21,7 @@ class EphemeralStore { private leavingChannels = new Set(); private archivingChannels = new Set(); private convertingChannels = new Set(); + private lastViewedThreadId = ''; addNavigationComponentId = (componentId: string) => { this.addToNavigationComponentIdStack(componentId); @@ -36,7 +37,7 @@ class EphemeralStore { addToNavigationComponentIdStack = (componentId: string) => { const index = this.navigationComponentIdStack.indexOf(componentId); if (index >= 0) { - this.navigationComponentIdStack = this.navigationComponentIdStack.slice(index, 1); + this.navigationComponentIdStack.splice(index, 1); } this.navigationComponentIdStack.unshift(componentId); @@ -58,6 +59,8 @@ class EphemeralStore { getAllNavigationComponents = () => this.allNavigationComponentIds; + getAllNavigationModals = () => this.navigationModalStack; + getNavigationTopComponentId = () => { return this.navigationComponentIdStack[0]; }; @@ -90,7 +93,7 @@ class EphemeralStore { }; removeNavigationModal = (componentId: string) => { - this.removeNavigationComponent(componentId); + this.removeNavigationComponentId(componentId); const index = this.navigationModalStack.indexOf(componentId); if (index >= 0) { @@ -209,6 +212,15 @@ class EphemeralStore { getPushProxyVerificationState = (serverUrl: string) => { return this.pushProxyVerification[serverUrl]; }; + + // Ephemeral for the last viewed thread + getLastViewedThreadId = () => { + return this.lastViewedThreadId; + }; + + setLastViewedThreadId = (id: string) => { + this.lastViewedThreadId = id; + }; } export default new EphemeralStore(); diff --git a/app/utils/permalink/index.ts b/app/utils/permalink/index.ts index 70c573ff4c..106eff8c49 100644 --- a/app/utils/permalink/index.ts +++ b/app/utils/permalink/index.ts @@ -2,6 +2,7 @@ // See LICENSE.txt for license information. import {Keyboard} from 'react-native'; +import {OptionsModalPresentationStyle} from 'react-native-navigation'; import {dismissAllModals, showModalOverCurrentContext} from '@screens/navigation'; import {changeOpacity} from '@utils/theme'; @@ -22,6 +23,7 @@ export const displayPermalink = async (teamName: string, postId: string, openAsP }; const options = { + modalPresentationStyle: OptionsModalPresentationStyle.fullScreen, layout: { componentBackgroundColor: changeOpacity('#000', 0.2), }, diff --git a/index.ts b/index.ts index bdc439f7a6..4435ca34ab 100644 --- a/index.ts +++ b/index.ts @@ -4,7 +4,7 @@ import {DeviceEventEmitter, LogBox} from 'react-native'; import {RUNNING_E2E} from 'react-native-dotenv'; import 'react-native-gesture-handler'; -import {ComponentDidAppearEvent, ComponentDidDisappearEvent, Navigation} from 'react-native-navigation'; +import {ComponentDidAppearEvent, ComponentDidDisappearEvent, ModalDismissedEvent, Navigation, ScreenPoppedEvent} from 'react-native-navigation'; import {Events, Screens} from './app/constants'; import DatabaseManager from './app/database/manager'; @@ -75,12 +75,14 @@ Navigation.events().registerAppLaunchedListener(async () => { }); const registerNavigationListeners = () => { - Navigation.events().registerComponentDidAppearListener(componentDidAppearListener); - Navigation.events().registerComponentDidDisappearListener(componentDidDisappearListener); - Navigation.events().registerComponentWillAppearListener(componentWillAppear); + Navigation.events().registerComponentDidAppearListener(screenDidAppearListener); + Navigation.events().registerComponentDidDisappearListener(screenDidDisappearListener); + Navigation.events().registerComponentWillAppearListener(screenWillAppear); + Navigation.events().registerScreenPoppedListener(screenPoppedListener); + Navigation.events().registerModalDismissedListener(modalDismissedListener); }; -function componentWillAppear({componentId}: ComponentDidAppearEvent) { +function screenWillAppear({componentId}: ComponentDidAppearEvent) { if (componentId === Screens.HOME) { DeviceEventEmitter.emit(Events.TAB_BAR_VISIBLE, true); } else if ([Screens.EDIT_POST, Screens.THREAD].includes(componentId)) { @@ -88,16 +90,14 @@ function componentWillAppear({componentId}: ComponentDidAppearEvent) { } } -function componentDidAppearListener({componentId, passProps}: ComponentDidAppearEvent) { - if (!(passProps as any)?.overlay) { +function screenDidAppearListener({componentId, passProps, componentType}: ComponentDidAppearEvent) { + if (!(passProps as any)?.overlay && componentType === 'Component') { EphemeralStore.addNavigationComponentId(componentId); } } -function componentDidDisappearListener({componentId}: ComponentDidDisappearEvent) { +function screenDidDisappearListener({componentId}: ComponentDidDisappearEvent) { if (componentId !== Screens.HOME) { - EphemeralStore.removeNavigationComponentId(componentId); - if ([Screens.EDIT_POST, Screens.THREAD].includes(componentId)) { DeviceEventEmitter.emit(Events.PAUSE_KEYBOARD_TRACKING_VIEW, false); } @@ -107,3 +107,20 @@ function componentDidDisappearListener({componentId}: ComponentDidDisappearEvent } } } + +function screenPoppedListener({componentId}: ScreenPoppedEvent) { + EphemeralStore.removeNavigationComponentId(componentId); + if (EphemeralStore.getNavigationTopComponentId() === Screens.HOME) { + DeviceEventEmitter.emit(Events.TAB_BAR_VISIBLE, true); + } +} + +function modalDismissedListener({componentId}: ModalDismissedEvent) { + const topScreen = EphemeralStore.getNavigationTopComponentId(); + const topModal = EphemeralStore.getNavigationTopModalId(); + const toRemove = topScreen === topModal ? topModal : componentId; + EphemeralStore.removeNavigationModal(toRemove); + if (EphemeralStore.getNavigationTopComponentId() === Screens.HOME) { + DeviceEventEmitter.emit(Events.TAB_BAR_VISIBLE, true); + } +}