diff --git a/native/account/logged-out-modal.react.js b/native/account/logged-out-modal.react.js index 49a65d077..cc28cbbc0 100644 --- a/native/account/logged-out-modal.react.js +++ b/native/account/logged-out-modal.react.js @@ -1,621 +1,621 @@ // @flow import Icon from '@expo/vector-icons/FontAwesome.js'; import * as React from 'react'; import { View, Text, TouchableOpacity, Image, Keyboard, Platform, BackHandler, ActivityIndicator, } from 'react-native'; import { Easing, useSharedValue, withTiming, useAnimatedStyle, runOnJS, } from 'react-native-reanimated'; import { SafeAreaView } from 'react-native-safe-area-context'; import { useIsLoggedInToAuthoritativeKeyserver } from 'lib/hooks/account-hooks.js'; import { setActiveSessionRecoveryActionType } from 'lib/keyserver-conn/keyserver-conn-types.js'; import { usePersistedStateLoaded } from 'lib/selectors/app-state-selectors.js'; import { isLoggedIn } from 'lib/selectors/user-selectors.js'; import { recoveryFromReduxActionSources } from 'lib/types/account-types.js'; import { useDispatch } from 'lib/utils/redux-utils.js'; import { usingCommServicesAccessToken, usingRestoreFlow, } from 'lib/utils/services-utils.js'; import { splashBackgroundURI } from './background-info.js'; import FullscreenSIWEPanel from './fullscreen-siwe-panel.react.js'; import LogInPanel from './log-in-panel.react.js'; import type { LogInState } from './log-in-panel.react.js'; import LoggedOutStaffInfo from './logged-out-staff-info.react.js'; import PromptButton from './prompt-button.react.js'; import { authoritativeKeyserverID } from '../authoritative-keyserver.js'; import KeyboardAvoidingView from '../components/keyboard-avoiding-view.react.js'; import ConnectedStatusBar from '../connected-status-bar.react.js'; import { useRatchetingKeyboardHeight } from '../keyboard/animated-keyboard.js'; import { createIsForegroundSelector } from '../navigation/nav-selectors.js'; import { NavContext } from '../navigation/navigation-context.js'; import type { RootNavigationProp } from '../navigation/root-navigator.react.js'; import { type NavigationRoute, LoggedOutModalRouteName, RegistrationRouteName, SignInNavigatorRouteName, } from '../navigation/route-names.js'; import { useSelector } from '../redux/redux-utils.js'; import { derivedDimensionsInfoSelector } from '../selectors/dimensions-selectors.js'; import { splashStyleSelector } from '../splash.js'; import { useStyles } from '../themes/colors.js'; import { AnimatedView } from '../types/styles.js'; let initialAppLoad = true; const safeAreaEdges = ['top', 'bottom']; export type LoggedOutMode = 'loading' | 'prompt' | 'log-in' | 'siwe'; const timingConfig = { duration: 250, easing: Easing.out(Easing.ease), }; // prettier-ignore function getPanelPaddingTop( modeValue /*: string */, keyboardHeightValue /*: number */, contentHeightValue /*: number */, ) /*: number */ { 'worklet'; const headerHeight = Platform.OS === 'ios' ? 62.33 : 58.54; let containerSize = headerHeight; if (modeValue === 'loading' || modeValue === 'prompt') { containerSize += Platform.OS === 'ios' ? 40 : 61; } else if (modeValue === 'log-in') { containerSize += 140; } else if (modeValue === 'siwe') { containerSize += 250; } const freeSpace = contentHeightValue - keyboardHeightValue - containerSize; const targetPanelPaddingTop = Math.max(freeSpace, 0) / 2; return withTiming(targetPanelPaddingTop, timingConfig); } // prettier-ignore function getPanelOpacity( modeValue /*: string */, finishResettingToPrompt/*: () => void */, ) /*: number */ { 'worklet'; const targetPanelOpacity = modeValue === 'loading' || modeValue === 'prompt' ? 0 : 1; return withTiming( targetPanelOpacity, timingConfig, (succeeded /*?: boolean */) => { if (succeeded && targetPanelOpacity === 0) { runOnJS(finishResettingToPrompt)(); } }, ); } const unboundStyles = { animationContainer: { flex: 1, }, backButton: { position: 'absolute', top: 13, }, buttonContainer: { bottom: 0, left: 0, marginLeft: 26, marginRight: 26, paddingBottom: 20, position: 'absolute', right: 0, }, signInButtons: { flexDirection: 'row', }, firstSignInButton: { marginRight: 8, flex: 1, }, lastSignInButton: { marginLeft: 8, flex: 1, }, container: { backgroundColor: 'transparent', flex: 1, }, header: { color: 'white', fontFamily: Platform.OS === 'ios' ? 'IBMPlexSans' : 'IBMPlexSans-Medium', fontSize: 56, fontWeight: '500', lineHeight: 66, textAlign: 'center', }, loadingIndicator: { paddingTop: 15, }, modalBackground: { bottom: 0, left: 0, position: 'absolute', right: 0, top: 0, }, siweOr: { flex: 1, flexDirection: 'row', marginBottom: 18, marginTop: 14, }, siweOrLeftHR: { borderColor: 'logInSpacer', borderTopWidth: 1, flex: 1, marginRight: 18, marginTop: 10, }, siweOrRightHR: { borderColor: 'logInSpacer', borderTopWidth: 1, flex: 1, marginLeft: 18, marginTop: 10, }, siweOrText: { color: 'whiteText', fontSize: 17, textAlign: 'center', }, }; const isForegroundSelector = createIsForegroundSelector( LoggedOutModalRouteName, ); const backgroundSource = { uri: splashBackgroundURI }; const initialLogInState = { usernameInputText: null, passwordInputText: null, }; type Mode = { +curMode: LoggedOutMode, +nextMode: LoggedOutMode, }; type Props = { +navigation: RootNavigationProp<'LoggedOutModal'>, +route: NavigationRoute<'LoggedOutModal'>, }; function LoggedOutModal(props: Props) { const mountedRef = React.useRef(false); React.useEffect(() => { mountedRef.current = true; return () => { mountedRef.current = false; }; }, []); const [logInState, baseSetLogInState] = React.useState(initialLogInState); const setLogInState = React.useCallback( (newLogInState: Partial) => { if (!mountedRef.current) { return; } baseSetLogInState(prevLogInState => ({ ...prevLogInState, ...newLogInState, })); }, [], ); const logInStateContainer = React.useMemo( () => ({ state: logInState, setState: setLogInState, }), [logInState, setLogInState], ); const persistedStateLoaded = usePersistedStateLoaded(); const initialMode = persistedStateLoaded ? 'prompt' : 'loading'; const [mode, baseSetMode] = React.useState(() => ({ curMode: initialMode, nextMode: initialMode, })); const setMode = React.useCallback((newMode: Partial) => { if (!mountedRef.current) { return; } baseSetMode(prevMode => ({ ...prevMode, ...newMode, })); }, []); const nextModeRef = React.useRef(initialMode); const dimensions = useSelector(derivedDimensionsInfoSelector); const contentHeight = useSharedValue(dimensions.safeAreaHeight); const modeValue = useSharedValue(initialMode); const buttonOpacity = useSharedValue(persistedStateLoaded ? 1 : 0); const onPrompt = mode.curMode === 'prompt'; const prevOnPromptRef = React.useRef(onPrompt); React.useEffect(() => { if (onPrompt && !prevOnPromptRef.current) { buttonOpacity.value = withTiming(1, { easing: Easing.out(Easing.ease), }); } prevOnPromptRef.current = onPrompt; }, [onPrompt, buttonOpacity]); const curContentHeight = dimensions.safeAreaHeight; const prevContentHeightRef = React.useRef(curContentHeight); React.useEffect(() => { if (curContentHeight === prevContentHeightRef.current) { return; } prevContentHeightRef.current = curContentHeight; contentHeight.value = curContentHeight; }, [curContentHeight, contentHeight]); const combinedSetMode = React.useCallback( (newMode: LoggedOutMode) => { nextModeRef.current = newMode; setMode({ curMode: newMode, nextMode: newMode }); modeValue.value = newMode; }, [setMode, modeValue], ); const goBackToPrompt = React.useCallback(() => { nextModeRef.current = 'prompt'; setMode({ nextMode: 'prompt' }); modeValue.value = 'prompt'; Keyboard.dismiss(); }, [setMode, modeValue]); const loadingCompleteRef = React.useRef(persistedStateLoaded); React.useEffect(() => { if (!loadingCompleteRef.current && persistedStateLoaded) { combinedSetMode('prompt'); loadingCompleteRef.current = true; } }, [persistedStateLoaded, combinedSetMode]); const [activeAlert, setActiveAlert] = React.useState(false); const navContext = React.useContext(NavContext); const isForeground = isForegroundSelector(navContext); const ratchetingKeyboardHeightInput = React.useMemo( () => ({ ignoreKeyboardDismissal: activeAlert, disabled: !isForeground, }), [activeAlert, isForeground], ); const keyboardHeightValue = useRatchetingKeyboardHeight( ratchetingKeyboardHeightInput, ); // We remove the password from the TextInput on iOS before dismissing it, // because otherwise iOS will prompt the user to save the password if the // iCloud password manager is enabled. We'll put the password back after the // dismissal concludes. const temporarilyHiddenPassword = React.useRef(); const curLogInPassword = logInState.passwordInputText; const resetToPrompt = React.useCallback(() => { if (nextModeRef.current === 'prompt') { return false; } if (Platform.OS === 'ios' && curLogInPassword) { temporarilyHiddenPassword.current = curLogInPassword; setLogInState({ passwordInputText: null }); } goBackToPrompt(); return true; }, [goBackToPrompt, curLogInPassword, setLogInState]); const finishResettingToPrompt = React.useCallback(() => { setMode({ curMode: nextModeRef.current }); if (temporarilyHiddenPassword.current) { setLogInState({ passwordInputText: temporarilyHiddenPassword.current }); temporarilyHiddenPassword.current = null; } }, [setMode, setLogInState]); React.useEffect(() => { if (!isForeground) { return undefined; } BackHandler.addEventListener('hardwareBackPress', resetToPrompt); return () => { BackHandler.removeEventListener('hardwareBackPress', resetToPrompt); }; }, [isForeground, resetToPrompt]); const rehydrateConcluded = useSelector( state => !!(state._persist && state._persist.rehydrated && navContext), ); const isLoggedInToAuthKeyserver = useIsLoggedInToAuthoritativeKeyserver(); const loggedIn = useSelector(isLoggedIn); const dispatch = useDispatch(); React.useEffect(() => { // This gets triggered when an app is killed and restarted // Not when it is returned from being backgrounded if (!initialAppLoad || !rehydrateConcluded) { return; } initialAppLoad = false; if (usingCommServicesAccessToken || __DEV__) { return; } if (loggedIn === isLoggedInToAuthKeyserver) { return; } const actionSource = loggedIn ? recoveryFromReduxActionSources.appStartReduxLoggedInButInvalidCookie : recoveryFromReduxActionSources.appStartCookieLoggedInButInvalidRedux; dispatch({ type: setActiveSessionRecoveryActionType, payload: { activeSessionRecovery: actionSource, keyserverID: authoritativeKeyserverID, }, }); }, [rehydrateConcluded, loggedIn, isLoggedInToAuthKeyserver, dispatch]); const onPressSIWE = React.useCallback(() => { combinedSetMode('siwe'); }, [combinedSetMode]); const onPressLogIn = React.useCallback(() => { combinedSetMode('log-in'); }, [combinedSetMode]); const { navigate } = props.navigation; const onPressQRCodeSignIn = React.useCallback(() => { navigate(SignInNavigatorRouteName); }, [navigate]); const onPressNewRegister = React.useCallback(() => { navigate(RegistrationRouteName); }, [navigate]); const opacityStyle = useAnimatedStyle(() => ({ opacity: getPanelOpacity(modeValue.value, finishResettingToPrompt), })); const styles = useStyles(unboundStyles); const panel = React.useMemo(() => { if (mode.curMode === 'log-in') { return ( ); } else if (mode.curMode === 'loading') { return ( ); } return null; }, [ mode.curMode, setActiveAlert, opacityStyle, logInStateContainer, styles.loadingIndicator, ]); const buttonsViewOpacity = useAnimatedStyle(() => ({ opacity: buttonOpacity.value, })); const buttonsViewStyle = React.useMemo( () => [styles.buttonContainer, buttonsViewOpacity], [styles.buttonContainer, buttonsViewOpacity], ); const buttons = React.useMemo(() => { if (mode.curMode !== 'prompt') { return null; } const signInButtons: Array> = []; if (!usingRestoreFlow) { signInButtons.push( , ); } if (__DEV__ || usingRestoreFlow) { const buttonText = usingRestoreFlow ? 'Sign in' : 'Sign in (QR)'; signInButtons.push( , ); } if (signInButtons.length === 2) { signInButtons[0] = ( {signInButtons[0]} ); signInButtons[1] = ( {signInButtons[1]} ); } let siweSection = null; if (!usingRestoreFlow) { siweSection = ( <> or ); } return ( {siweSection} {signInButtons} ); }, [ mode.curMode, onPressNewRegister, onPressLogIn, onPressQRCodeSignIn, onPressSIWE, buttonsViewStyle, styles.firstSignInButton, styles.lastSignInButton, styles.siweOr, styles.siweOrLeftHR, styles.siweOrText, styles.siweOrRightHR, styles.signInButtons, ]); const windowWidth = dimensions.width; const backButtonStyle = React.useMemo( () => [ styles.backButton, opacityStyle, { left: windowWidth < 360 ? 28 : 40 }, ], [styles.backButton, opacityStyle, windowWidth], ); const paddingTopStyle = useAnimatedStyle(() => ({ paddingTop: getPanelPaddingTop( modeValue.value, keyboardHeightValue.value, contentHeight.value, ), })); const animatedContentStyle = React.useMemo( () => [styles.animationContainer, paddingTopStyle], [styles.animationContainer, paddingTopStyle], ); const animatedContent = React.useMemo( () => ( Comm {panel} ), [ animatedContentStyle, styles.header, backButtonStyle, resetToPrompt, panel, ], ); const curModeIsSIWE = mode.curMode === 'siwe'; const nextModeIsPrompt = mode.nextMode === 'prompt'; const siwePanel = React.useMemo(() => { if (!curModeIsSIWE) { return null; } return ( ); }, [curModeIsSIWE, goBackToPrompt, nextModeIsPrompt]); const splashStyle = useSelector(splashStyleSelector); const backgroundStyle = React.useMemo( () => [styles.modalBackground, splashStyle], [styles.modalBackground, splashStyle], ); return React.useMemo( () => ( <> {animatedContent} {buttons} {siwePanel} ), [backgroundStyle, styles.container, animatedContent, buttons, siwePanel], ); } const MemoizedLoggedOutModal: React.ComponentType = React.memo(LoggedOutModal); export default MemoizedLoggedOutModal; diff --git a/native/account/prompt-button.react.js b/native/account/prompt-button.react.js index 2574682ab..4b38faf87 100644 --- a/native/account/prompt-button.react.js +++ b/native/account/prompt-button.react.js @@ -1,58 +1,58 @@ // @flow import * as React from 'react'; import { Text, View } from 'react-native'; import PrimaryButton from '../components/primary-button.react.js'; import { useStyles } from '../themes/colors.js'; import EthereumLogo from '../vectors/ethereum-logo.react.js'; type Props = { +text: string, +onPress: () => mixed, - +variant: 'regular' | 'siwe', + +variant: 'enabled' | 'disabled' | 'loading' | 'siwe', }; function PromptButton(props: Props): React.Node { const styles = useStyles(unboundStyles); const { text, onPress, variant } = props; - if (variant === 'regular') { + if (variant === 'siwe') { return ( - + + + + + {text} + + + ); + } else { + return ( + + ); } - - return ( - - - - - - {text} - - - ); } const unboundStyles = { container: { flex: 1 }, buttonText: { fontSize: 18, textAlign: 'center', color: 'siweButtonText', }, siweButton: { backgroundColor: 'siweButton', flexDirection: 'row', justifyContent: 'center', padding: 12, }, siweIcon: { paddingRight: 10, }, }; export default PromptButton; diff --git a/native/account/restore-password-account-screen.react.js b/native/account/restore-password-account-screen.react.js new file mode 100644 index 000000000..57a6b0a48 --- /dev/null +++ b/native/account/restore-password-account-screen.react.js @@ -0,0 +1,92 @@ +// @flow + +import * as React from 'react'; +import { Text, TextInput, View } from 'react-native'; + +import PromptButton from './prompt-button.react.js'; +import RegistrationButtonContainer from './registration/registration-button-container.react.js'; +import RegistrationContainer from './registration/registration-container.react.js'; +import RegistrationContentContainer from './registration/registration-content-container.react.js'; +import RegistrationTextInput from './registration/registration-text-input.react.js'; +import type { SignInNavigationProp } from './sign-in-navigator.react.js'; +import type { NavigationRoute } from '../navigation/route-names.js'; +import { useStyles } from '../themes/colors.js'; + +type Props = { + +navigation: SignInNavigationProp<'RestorePasswordAccountScreen'>, + +route: NavigationRoute<'RestorePasswordAccountScreen'>, +}; + +// eslint-disable-next-line no-unused-vars +function RestorePasswordAccountScreen(props: Props): React.Node { + const [username, setUsername] = React.useState(''); + const [password, setPassword] = React.useState(''); + + const passwordInputRef = React.useRef>(); + const focusPasswordInput = React.useCallback(() => { + passwordInputRef.current?.focus(); + }, []); + + const areCredentialsPresent = !!username && !!password; + const onProceed = React.useCallback(() => {}, []); + + const styles = useStyles(unboundStyles); + return ( + + + Restore with password + + + + + + + + + + ); +} + +const unboundStyles = { + header: { + fontSize: 24, + color: 'panelForegroundLabel', + paddingBottom: 16, + }, + buttonContainer: { + flexDirection: 'row', + }, + password: { + marginTop: 16, + }, +}; + +export default RestorePasswordAccountScreen; diff --git a/native/account/restore-prompt-screen.react.js b/native/account/restore-prompt-screen.react.js index 066cbdae8..0b7c13339 100644 --- a/native/account/restore-prompt-screen.react.js +++ b/native/account/restore-prompt-screen.react.js @@ -1,91 +1,95 @@ // @flow import * as React from 'react'; import { Text, View } from 'react-native'; import PromptButton from './prompt-button.react.js'; import RegistrationButtonContainer from './registration/registration-button-container.react.js'; import RegistrationContainer from './registration/registration-container.react.js'; import RegistrationContentContainer from './registration/registration-content-container.react.js'; import type { SignInNavigationProp } from './sign-in-navigator.react'; import type { NavigationRoute } from '../navigation/route-names'; +import { RestorePasswordAccountScreenRouteName } from '../navigation/route-names.js'; import { useColors, useStyles } from '../themes/colors.js'; import RestoreIcon from '../vectors/restore-icon.react.js'; type Props = { +navigation: SignInNavigationProp<'RestorePromptScreen'>, +route: NavigationRoute<'RestorePromptScreen'>, }; -// eslint-disable-next-line no-unused-vars function RestorePromptScreen(props: Props): React.Node { const styles = useStyles(unboundStyles); + const openPasswordRestoreScreen = React.useCallback(() => { + props.navigation.navigate(RestorePasswordAccountScreenRouteName); + }, [props.navigation]); + const colors = useColors(); return ( Restore account If you’ve lost access to your primary device, you can try recovering your Comm account. To proceed, select the same login method that you used during registration. Note that after completing the recovery flow, you will be logged out from all of your other devices. {}} variant="siwe" /> {}} - variant="regular" + onPress={openPasswordRestoreScreen} + variant="enabled" /> ); } const unboundStyles = { header: { fontSize: 24, color: 'panelForegroundLabel', paddingBottom: 16, }, section: { fontFamily: 'Arial', fontSize: 15, lineHeight: 20, color: 'panelForegroundSecondaryLabel', paddingBottom: 16, }, iconContainer: { flexGrow: 1, alignItems: 'center', justifyContent: 'center', }, buttonContainer: { flexDirection: 'row', }, scrollViewContentContainer: { flexGrow: 1, }, }; export default RestorePromptScreen; diff --git a/native/account/sign-in-navigator.react.js b/native/account/sign-in-navigator.react.js index 780a0df6d..d9c9fb37d 100644 --- a/native/account/sign-in-navigator.react.js +++ b/native/account/sign-in-navigator.react.js @@ -1,66 +1,72 @@ // @flow import type { StackNavigationProp, StackNavigationHelpers, } from '@react-navigation/core'; import { createStackNavigator } from '@react-navigation/stack'; import * as React from 'react'; import QRCodeScreen from './qr-code-screen.react.js'; +import RestorePasswordAccountScreen from './restore-password-account-screen.react.js'; import RestorePromptScreen from './restore-prompt-screen.react.js'; import type { RootNavigationProp } from '../navigation/root-navigator.react.js'; import { type ScreenParamList, type SignInParamList, QRCodeScreenRouteName, RestorePromptScreenRouteName, + RestorePasswordAccountScreenRouteName, } from '../navigation/route-names.js'; import { useColors } from '../themes/colors.js'; export type SignInNavigationProp> = StackNavigationProp; const SignInStack = createStackNavigator< ScreenParamList, SignInParamList, StackNavigationHelpers, >(); type SignInNavigatorProps = { +navigation: RootNavigationProp<'SignInNavigator'>, ... }; // eslint-disable-next-line no-unused-vars function SignInNavigator(props: SignInNavigatorProps): React.Node { const colors = useColors(); const screenOptions = React.useMemo( () => ({ headerTransparent: true, headerBackTitleVisible: false, headerTitle: '', headerTintColor: colors.panelForegroundLabel, headerLeftContainerStyle: { paddingLeft: 12, }, }), [colors.panelForegroundLabel], ); return ( + ); } export default SignInNavigator; diff --git a/native/navigation/route-names.js b/native/navigation/route-names.js index 022a276f2..14c8a9fe2 100644 --- a/native/navigation/route-names.js +++ b/native/navigation/route-names.js @@ -1,402 +1,405 @@ // @flow import type { RouteProp } from '@react-navigation/core'; import type { ActionResultModalParams } from './action-result-modal.react.js'; import type { InviteLinkModalParams } from './invite-link-modal.react'; import type { AvatarSelectionParams } from '../account/registration/avatar-selection.react.js'; import type { ConnectEthereumParams } from '../account/registration/connect-ethereum.react.js'; import type { ConnectFarcasterParams } from '../account/registration/connect-farcaster.react.js'; import type { EmojiAvatarSelectionParams } from '../account/registration/emoji-avatar-selection.react.js'; import type { ExistingEthereumAccountParams } from '../account/registration/existing-ethereum-account.react.js'; import type { KeyserverSelectionParams } from '../account/registration/keyserver-selection.react.js'; import type { PasswordSelectionParams } from '../account/registration/password-selection.react.js'; import type { RegistrationTermsParams } from '../account/registration/registration-terms.react.js'; import type { CreateSIWEBackupMessageParams } from '../account/registration/siwe-backup-message-creation.react.js'; import type { UsernameSelectionParams } from '../account/registration/username-selection.react.js'; import type { TermsAndPrivacyModalParams } from '../account/terms-and-privacy-modal.react.js'; import type { RestoreSIWEBackupParams } from '../backup/restore-siwe-backup.react.js'; import type { ThreadPickerModalParams } from '../calendar/thread-picker-modal.react.js'; import type { ComposeSubchannelParams } from '../chat/compose-subchannel.react.js'; import type { FullScreenThreadMediaGalleryParams } from '../chat/fullscreen-thread-media-gallery.react.js'; import type { ImagePasteModalParams } from '../chat/image-paste-modal.react.js'; import type { MessageListParams } from '../chat/message-list-types.js'; import type { MessageReactionsModalParams } from '../chat/message-reactions-modal.react.js'; import type { MultimediaMessageTooltipModalParams } from '../chat/multimedia-message-tooltip-modal.react.js'; import type { PinnedMessagesScreenParams } from '../chat/pinned-messages-screen.react.js'; import type { RobotextMessageTooltipModalParams } from '../chat/robotext-message-tooltip-modal.react.js'; import type { AddUsersModalParams } from '../chat/settings/add-users-modal.react.js'; import type { ColorSelectorModalParams } from '../chat/settings/color-selector-modal.react.js'; import type { ComposeSubchannelModalParams } from '../chat/settings/compose-subchannel-modal.react.js'; import type { DeleteThreadParams } from '../chat/settings/delete-thread.react.js'; import type { EmojiThreadAvatarCreationParams } from '../chat/settings/emoji-thread-avatar-creation.react.js'; import type { ThreadSettingsMemberTooltipModalParams } from '../chat/settings/thread-settings-member-tooltip-modal.react.js'; import type { ThreadSettingsNotificationsParams } from '../chat/settings/thread-settings-notifications.react.js'; import type { ThreadSettingsParams } from '../chat/settings/thread-settings.react.js'; import type { SidebarListModalParams } from '../chat/sidebar-list-modal.react.js'; import type { SubchannelListModalParams } from '../chat/subchannels-list-modal.react.js'; import type { TextMessageTooltipModalParams } from '../chat/text-message-tooltip-modal.react.js'; import type { TogglePinModalParams } from '../chat/toggle-pin-modal.react.js'; import type { TagFarcasterChannelByNameParams } from '../community-settings/tag-farcaster-channel/tag-farcaster-channel-by-name.react.js'; import type { TagFarcasterChannelParams } from '../community-settings/tag-farcaster-channel/tag-farcaster-channel.react.js'; import type { InviteLinksNavigatorParams } from '../invite-links/invite-links-navigator.react.js'; import type { ManagePublicLinkScreenParams } from '../invite-links/manage-public-link-screen.react.js'; import type { ViewInviteLinksScreenParams } from '../invite-links/view-invite-links-screen.react.js'; import type { ChatCameraModalParams } from '../media/chat-camera-modal.react.js'; import type { ImageModalParams } from '../media/image-modal.react.js'; import type { ThreadAvatarCameraModalParams } from '../media/thread-avatar-camera-modal.react.js'; import type { VideoPlaybackModalParams } from '../media/video-playback-modal.react.js'; import type { CustomServerModalParams } from '../profile/custom-server-modal.react.js'; import type { KeyserverSelectionBottomSheetParams } from '../profile/keyserver-selection-bottom-sheet.react.js'; import type { LinkedDevicesBottomSheetParams } from '../profile/linked-devices-bottom-sheet.react.js'; import type { UserRelationshipTooltipModalParams } from '../profile/user-relationship-tooltip-modal.react.js'; import type { ChangeRolesScreenParams } from '../roles/change-roles-screen.react.js'; import type { CommunityRolesScreenParams } from '../roles/community-roles-screen.react.js'; import type { CreateRolesScreenParams } from '../roles/create-roles-screen.react.js'; import type { MessageSearchParams } from '../search/message-search.react.js'; import type { NUXTipsOverlayParams } from '../tooltip/nux-tips-overlay.react.js'; import type { UserProfileAvatarModalParams } from '../user-profile/user-profile-avatar-modal.react.js'; import type { UserProfileBottomSheetParams } from '../user-profile/user-profile-bottom-sheet.react.js'; export const ActionResultModalRouteName = 'ActionResultModal'; export const AddUsersModalRouteName = 'AddUsersModal'; export const AppearancePreferencesRouteName = 'AppearancePreferences'; export const AppRouteName = 'App'; export const AppsRouteName = 'Apps'; export const BackgroundChatThreadListRouteName = 'BackgroundChatThreadList'; export const BackupMenuRouteName = 'BackupMenu'; export const BlockListRouteName = 'BlockList'; export const BuildInfoRouteName = 'BuildInfo'; export const CalendarRouteName = 'Calendar'; export const CalendarScreenRouteName = 'CalendarScreen'; export const ChangeRolesScreenRouteName = 'ChangeRolesScreen'; export const ChatCameraModalRouteName = 'ChatCameraModal'; export const ChatRouteName = 'Chat'; export const ChatThreadListRouteName = 'ChatThreadList'; export const ColorSelectorModalRouteName = 'ColorSelectorModal'; export const ComposeSubchannelModalRouteName = 'ComposeSubchannelModal'; export const ComposeSubchannelRouteName = 'ComposeSubchannel'; export const CommunityDrawerNavigatorRouteName = 'CommunityDrawerNavigator'; export const CustomServerModalRouteName = 'CustomServerModal'; export const DefaultNotificationsPreferencesRouteName = 'DefaultNotifications'; export const DeleteAccountRouteName = 'DeleteAccount'; export const DeleteThreadRouteName = 'DeleteThread'; export const DevToolsRouteName = 'DevTools'; export const EditPasswordRouteName = 'EditPassword'; export const EmojiThreadAvatarCreationRouteName = 'EmojiThreadAvatarCreation'; export const EmojiUserAvatarCreationRouteName = 'EmojiUserAvatarCreation'; export const FriendListRouteName = 'FriendList'; export const FullScreenThreadMediaGalleryRouteName = 'FullScreenThreadMediaGallery'; export const HomeChatThreadListRouteName = 'HomeChatThreadList'; export const ImageModalRouteName = 'ImageModal'; export const ImagePasteModalRouteName = 'ImagePasteModal'; export const InviteLinkModalRouteName = 'InviteLinkModal'; export const InviteLinkNavigatorRouteName = 'InviteLinkNavigator'; export const LinkedDevicesRouteName = 'LinkedDevices'; export const LinkedDevicesBottomSheetRouteName = 'LinkedDevicesBottomSheet'; export const LoggedOutModalRouteName = 'LoggedOutModal'; export const ManagePublicLinkRouteName = 'ManagePublicLink'; export const MessageListRouteName = 'MessageList'; export const MessageReactionsModalRouteName = 'MessageReactionsModal'; export const PinnedMessagesScreenRouteName = 'PinnedMessagesScreen'; export const MultimediaMessageTooltipModalRouteName = 'MultimediaMessageTooltipModal'; export const PrivacyPreferencesRouteName = 'PrivacyPreferences'; export const ProfileRouteName = 'Profile'; export const ProfileScreenRouteName = 'ProfileScreen'; export const UserRelationshipTooltipModalRouteName = 'UserRelationshipTooltipModal'; export const RobotextMessageTooltipModalRouteName = 'RobotextMessageTooltipModal'; export const SecondaryDeviceQRCodeScannerRouteName = 'SecondaryDeviceQRCodeScanner'; export const SidebarListModalRouteName = 'SidebarListModal'; export const SubchannelsListModalRouteName = 'SubchannelsListModal'; export const TabNavigatorRouteName = 'TabNavigator'; export const TextMessageTooltipModalRouteName = 'TextMessageTooltipModal'; export const ThreadAvatarCameraModalRouteName = 'ThreadAvatarCameraModal'; export const ThreadPickerModalRouteName = 'ThreadPickerModal'; export const ThreadSettingsMemberTooltipModalRouteName = 'ThreadSettingsMemberTooltipModal'; export const ThreadSettingsRouteName = 'ThreadSettings'; export const TunnelbrokerMenuRouteName = 'TunnelbrokerMenu'; export const UserAvatarCameraModalRouteName = 'UserAvatarCameraModal'; export const TogglePinModalRouteName = 'TogglePinModal'; export const VideoPlaybackModalRouteName = 'VideoPlaybackModal'; export const ViewInviteLinksRouteName = 'ViewInviteLinks'; export const TermsAndPrivacyRouteName = 'TermsAndPrivacyModal'; export const RegistrationRouteName = 'Registration'; export const KeyserverSelectionRouteName = 'KeyserverSelection'; export const CoolOrNerdModeSelectionRouteName = 'CoolOrNerdModeSelection'; export const ConnectEthereumRouteName = 'ConnectEthereum'; export const CreateSIWEBackupMessageRouteName = 'CreateSIWEBackupMessage'; export const CreateMissingSIWEBackupMessageRouteName = 'CreateMissingSIWEBackupMessage'; export const RestoreSIWEBackupRouteName = 'RestoreSIWEBackup'; export const ExistingEthereumAccountRouteName = 'ExistingEthereumAccount'; export const ConnectFarcasterRouteName = 'ConnectFarcaster'; export const UsernameSelectionRouteName = 'UsernameSelection'; export const CommunityCreationRouteName = 'CommunityCreation'; export const CommunityConfigurationRouteName = 'CommunityConfiguration'; export const MessageSearchRouteName = 'MessageSearch'; export const PasswordSelectionRouteName = 'PasswordSelection'; export const AvatarSelectionRouteName = 'AvatarSelection'; export const EmojiAvatarSelectionRouteName = 'EmojiAvatarSelection'; export const RegistrationUserAvatarCameraModalRouteName = 'RegistrationUserAvatarCameraModal'; export const RegistrationTermsRouteName = 'RegistrationTerms'; export const RolesNavigatorRouteName = 'RolesNavigator'; export const CommunityRolesScreenRouteName = 'CommunityRolesScreen'; export const CreateRolesScreenRouteName = 'CreateRolesScreen'; export const SignInNavigatorRouteName = 'SignInNavigator'; export const QRCodeScreenRouteName = 'QRCodeScreen'; export const RestorePromptScreenRouteName = 'RestorePromptScreen'; +export const RestorePasswordAccountScreenRouteName = + 'RestorePasswordAccountScreen'; export const UserProfileBottomSheetNavigatorRouteName = 'UserProfileBottomSheetNavigator'; export const UserProfileBottomSheetRouteName = 'UserProfileBottomSheet'; export const UserProfileAvatarModalRouteName = 'UserProfileAvatarModal'; export const KeyserverSelectionListRouteName = 'KeyserverSelectionList'; export const AddKeyserverRouteName = 'AddKeyserver'; export const KeyserverSelectionBottomSheetRouteName = 'KeyserverSelectionBottomSheet'; export const AccountDoesNotExistRouteName = 'AccountDoesNotExist'; export const FarcasterAccountSettingsRouteName = 'FarcasterAccountSettings'; export const ConnectFarcasterBottomSheetRouteName = 'ConnectFarcasterBottomSheet'; export const TagFarcasterChannelNavigatorRouteName = 'TagFarcasterChannelNavigator'; export const TagFarcasterChannelRouteName = 'TagFarcasterChannel'; export const TagFarcasterChannelByNameRouteName = 'TagFarcasterChannelByName'; export const ThreadSettingsNotificationsRouteName = 'ThreadSettingsNotifications'; export const IntroTipRouteName = 'IntroTip'; export const CommunityDrawerTipRouteName = 'CommunityDrawerTip'; export const HomeTabTipRouteName = 'HomeTabTip'; export const MutedTabTipRouteName = 'MutedTabTip'; export const NUXTipOverlayBackdropRouteName = 'NUXTipOverlayBackdrop'; export type RootParamList = { +LoggedOutModal: void, +App: void, +ThreadPickerModal: ThreadPickerModalParams, +AddUsersModal: AddUsersModalParams, +CustomServerModal: CustomServerModalParams, +ColorSelectorModal: ColorSelectorModalParams, +ComposeSubchannelModal: ComposeSubchannelModalParams, +SidebarListModal: SidebarListModalParams, +ImagePasteModal: ImagePasteModalParams, +TermsAndPrivacyModal: TermsAndPrivacyModalParams, +SubchannelsListModal: SubchannelListModalParams, +MessageReactionsModal: MessageReactionsModalParams, +Registration: void, +CommunityCreation: void, +InviteLinkModal: InviteLinkModalParams, +InviteLinkNavigator: InviteLinksNavigatorParams, +RolesNavigator: void, +SignInNavigator: void, +UserProfileBottomSheetNavigator: void, +TunnelbrokerMenu: void, +KeyserverSelectionBottomSheet: KeyserverSelectionBottomSheetParams, +LinkedDevicesBottomSheet: LinkedDevicesBottomSheetParams, +ConnectFarcasterBottomSheet: void, +TagFarcasterChannelNavigator: void, +CreateMissingSIWEBackupMessage: void, +RestoreSIWEBackup: RestoreSIWEBackupParams, }; export type NUXTipRouteNames = | typeof IntroTipRouteName | typeof CommunityDrawerTipRouteName | typeof HomeTabTipRouteName | typeof MutedTabTipRouteName; export type MessageTooltipRouteNames = | typeof RobotextMessageTooltipModalRouteName | typeof MultimediaMessageTooltipModalRouteName | typeof TextMessageTooltipModalRouteName; export const PinnableMessageTooltipRouteNames = [ TextMessageTooltipModalRouteName, MultimediaMessageTooltipModalRouteName, ]; export type TooltipModalParamList = { +MultimediaMessageTooltipModal: MultimediaMessageTooltipModalParams, +TextMessageTooltipModal: TextMessageTooltipModalParams, +ThreadSettingsMemberTooltipModal: ThreadSettingsMemberTooltipModalParams, +UserRelationshipTooltipModal: UserRelationshipTooltipModalParams, +RobotextMessageTooltipModal: RobotextMessageTooltipModalParams, }; export type OverlayParamList = { +CommunityDrawerNavigator: void, +ImageModal: ImageModalParams, +ActionResultModal: ActionResultModalParams, +ChatCameraModal: ChatCameraModalParams, +UserAvatarCameraModal: void, +ThreadAvatarCameraModal: ThreadAvatarCameraModalParams, +VideoPlaybackModal: VideoPlaybackModalParams, +TogglePinModal: TogglePinModalParams, +IntroTip: NUXTipsOverlayParams, +CommunityDrawerTip: NUXTipsOverlayParams, +HomeTabTip: NUXTipsOverlayParams, +MutedTabTip: NUXTipsOverlayParams, +NUXTipOverlayBackdrop: void, ...TooltipModalParamList, }; export type TabParamList = { +Calendar: void, +Chat: void, +Profile: void, +Apps: void, }; export type ChatParamList = { +ChatThreadList: void, +MessageList: MessageListParams, +ComposeSubchannel: ComposeSubchannelParams, +ThreadSettings: ThreadSettingsParams, +EmojiThreadAvatarCreation: EmojiThreadAvatarCreationParams, +DeleteThread: DeleteThreadParams, +FullScreenThreadMediaGallery: FullScreenThreadMediaGalleryParams, +PinnedMessagesScreen: PinnedMessagesScreenParams, +MessageSearch: MessageSearchParams, +ChangeRolesScreen: ChangeRolesScreenParams, +ThreadSettingsNotifications: ThreadSettingsNotificationsParams, }; export type ChatTopTabsParamList = { +HomeChatThreadList: void, +BackgroundChatThreadList: void, }; export type ProfileParamList = { +ProfileScreen: void, +EmojiUserAvatarCreation: void, +EditPassword: void, +DeleteAccount: void, +BuildInfo: void, +DevTools: void, +AppearancePreferences: void, +PrivacyPreferences: void, +DefaultNotifications: void, +FriendList: void, +BlockList: void, +LinkedDevices: void, +SecondaryDeviceQRCodeScanner: void, +BackupMenu: void, +TunnelbrokerMenu: void, +KeyserverSelectionList: void, +AddKeyserver: void, +FarcasterAccountSettings: void, }; export type CalendarParamList = { +CalendarScreen: void, }; export type CommunityDrawerParamList = { +TabNavigator: void }; export type RegistrationParamList = { +CoolOrNerdModeSelection: void, +KeyserverSelection: KeyserverSelectionParams, +ConnectEthereum: ConnectEthereumParams, +ExistingEthereumAccount: ExistingEthereumAccountParams, +ConnectFarcaster: ConnectFarcasterParams, +CreateSIWEBackupMessage: CreateSIWEBackupMessageParams, +UsernameSelection: UsernameSelectionParams, +PasswordSelection: PasswordSelectionParams, +AvatarSelection: AvatarSelectionParams, +EmojiAvatarSelection: EmojiAvatarSelectionParams, +RegistrationUserAvatarCameraModal: void, +RegistrationTerms: RegistrationTermsParams, +AccountDoesNotExist: void, }; export type InviteLinkParamList = { +ViewInviteLinks: ViewInviteLinksScreenParams, +ManagePublicLink: ManagePublicLinkScreenParams, }; export type CommunityCreationParamList = { +CommunityConfiguration: void, }; export type RolesParamList = { +CommunityRolesScreen: CommunityRolesScreenParams, +CreateRolesScreen: CreateRolesScreenParams, }; export type TagFarcasterChannelParamList = { +TagFarcasterChannel: TagFarcasterChannelParams, +TagFarcasterChannelByName: TagFarcasterChannelByNameParams, }; export type SignInParamList = { +QRCodeScreen: void, +RestorePromptScreen: void, + +RestorePasswordAccountScreen: void, }; export type UserProfileBottomSheetParamList = { +UserProfileBottomSheet: UserProfileBottomSheetParams, +UserProfileAvatarModal: UserProfileAvatarModalParams, +UserRelationshipTooltipModal: UserRelationshipTooltipModalParams, }; export type ScreenParamList = { ...RootParamList, ...OverlayParamList, ...TabParamList, ...ChatParamList, ...ChatTopTabsParamList, ...ProfileParamList, ...CalendarParamList, ...CommunityDrawerParamList, ...RegistrationParamList, ...InviteLinkParamList, ...CommunityCreationParamList, ...RolesParamList, ...SignInParamList, ...UserProfileBottomSheetParamList, ...TagFarcasterChannelParamList, }; export type NavigationRoute> = RouteProp; export const accountModals = [ LoggedOutModalRouteName, RegistrationRouteName, SignInNavigatorRouteName, ]; export const scrollBlockingModals = [ ImageModalRouteName, MultimediaMessageTooltipModalRouteName, TextMessageTooltipModalRouteName, ThreadSettingsMemberTooltipModalRouteName, UserRelationshipTooltipModalRouteName, RobotextMessageTooltipModalRouteName, VideoPlaybackModalRouteName, ]; export const chatRootModals = [ AddUsersModalRouteName, ColorSelectorModalRouteName, ComposeSubchannelModalRouteName, ]; export const threadRoutes = [ MessageListRouteName, ThreadSettingsRouteName, DeleteThreadRouteName, ComposeSubchannelRouteName, FullScreenThreadMediaGalleryRouteName, PinnedMessagesScreenRouteName, MessageSearchRouteName, EmojiThreadAvatarCreationRouteName, CommunityRolesScreenRouteName, ThreadSettingsNotificationsRouteName, ];