diff --git a/native/account/qr-auth/connect-secondary-device.react.js b/native/account/qr-auth/connect-secondary-device.react.js
new file mode 100644
index 000000000..593e49e9f
--- /dev/null
+++ b/native/account/qr-auth/connect-secondary-device.react.js
@@ -0,0 +1,73 @@
+// @flow
+
+import invariant from 'invariant';
+import * as React from 'react';
+import { Text } from 'react-native';
+
+import { QRAuthContext } from './qr-auth-context.js';
+import type { QRAuthNavigationProp } from './qr-auth-navigator.react.js';
+import RegistrationButtonContainer from '../../account/registration/registration-button-container.react.js';
+import RegistrationContainer from '../../account/registration/registration-container.react.js';
+import RegistrationContentContainer from '../../account/registration/registration-content-container.react.js';
+import PrimaryButton from '../../components/primary-button.react.js';
+import { type NavigationRoute } from '../../navigation/route-names.js';
+import { useStyles } from '../../themes/colors.js';
+
+export type ConnectSecondaryDeviceParams = {
+ +data: string,
+};
+
+type Props = {
+ +navigation: QRAuthNavigationProp<'ConnectSecondaryDevice'>,
+ +route: NavigationRoute<'ConnectSecondaryDevice'>,
+};
+
+function ConnectSecondaryDevice(props: Props): React.Node {
+ const { route } = props;
+ const data = route.params?.data;
+
+ const styles = useStyles(unboundStyles);
+
+ const qrAuthContext = React.useContext(QRAuthContext);
+ invariant(qrAuthContext, 'qrAuthContext should be set');
+ const { onConnect, connectingInProgress } = qrAuthContext;
+
+ const onPressConnect = React.useCallback(() => {
+ void onConnect(data);
+ }, [data, onConnect]);
+
+ return (
+
+
+ Connect with this device?
+
+ Are you sure you want to allow this device to log in to your account?
+
+
+
+
+
+
+ );
+}
+
+const unboundStyles = {
+ header: {
+ fontSize: 24,
+ color: 'panelForegroundLabel',
+ paddingBottom: 16,
+ },
+ body: {
+ fontFamily: 'Arial',
+ fontSize: 15,
+ lineHeight: 20,
+ color: 'panelForegroundSecondaryLabel',
+ paddingBottom: 16,
+ },
+};
+
+export default ConnectSecondaryDevice;
diff --git a/native/account/qr-auth/qr-auth-context-provider.js b/native/account/qr-auth/qr-auth-context-provider.js
index b7d912346..b1727fbe4 100644
--- a/native/account/qr-auth/qr-auth-context-provider.js
+++ b/native/account/qr-auth/qr-auth-context-provider.js
@@ -1,250 +1,259 @@
// @flow
import { useNavigation } from '@react-navigation/native';
import invariant from 'invariant';
import * as React from 'react';
import { parseDataFromDeepLink } from 'lib/facts/links.js';
import {
getOwnPeerDevices,
getKeyserverDeviceID,
} from 'lib/selectors/user-selectors.js';
import { useDeviceListUpdate } from 'lib/shared/device-list-utils.js';
import { IdentityClientContext } from 'lib/shared/identity-client-context.js';
import { useTunnelbroker } from 'lib/tunnelbroker/tunnelbroker-context.js';
import {
identityDeviceTypes,
type IdentityDeviceType,
} from 'lib/types/identity-service-types.js';
import {
tunnelbrokerToDeviceMessageTypes,
type TunnelbrokerToDeviceMessage,
} from 'lib/types/tunnelbroker/messages.js';
import {
peerToPeerMessageTypes,
peerToPeerMessageValidator,
type PeerToPeerMessage,
} from 'lib/types/tunnelbroker/peer-to-peer-message-types.js';
import { qrCodeAuthMessageTypes } from 'lib/types/tunnelbroker/qr-code-auth-message-types.js';
import { QRAuthContext } from './qr-auth-context.js';
import { commCoreModule } from '../../native-modules.js';
import { useSelector } from '../../redux/redux-utils.js';
import Alert from '../../utils/alert.js';
import {
composeTunnelbrokerQRAuthMessage,
parseTunnelbrokerQRAuthMessage,
} from '../../utils/qr-code-utils.js';
type Props = {
+children: React.Node,
};
function QRAuthContextProvider(props: Props): React.Node {
const aes256Key = React.useRef(null);
const secondaryDeviceID = React.useRef(null);
const secondaryDeviceType = React.useRef(null);
+ const [connectingInProgress, setConnectingInProgress] = React.useState(false);
const ownPeerDevices = useSelector(getOwnPeerDevices);
const keyserverDeviceID = getKeyserverDeviceID(ownPeerDevices);
const { goBack } = useNavigation();
const runDeviceListUpdate = useDeviceListUpdate();
const { addListener, removeListener, sendMessageToDevice } =
useTunnelbroker();
const identityContext = React.useContext(IdentityClientContext);
invariant(identityContext, 'identity context not set');
const tunnelbrokerMessageListener = React.useCallback(
async (message: TunnelbrokerToDeviceMessage) => {
const encryptionKey = aes256Key.current;
const targetDeviceID = secondaryDeviceID.current;
if (!encryptionKey || !targetDeviceID) {
return;
}
if (message.type !== tunnelbrokerToDeviceMessageTypes.MESSAGE_TO_DEVICE) {
return;
}
let innerMessage: PeerToPeerMessage;
try {
innerMessage = JSON.parse(message.payload);
} catch {
return;
}
if (
!peerToPeerMessageValidator.is(innerMessage) ||
innerMessage.type !== peerToPeerMessageTypes.QR_CODE_AUTH_MESSAGE
) {
return;
}
const payload = await parseTunnelbrokerQRAuthMessage(
encryptionKey,
innerMessage,
);
if (
!payload ||
payload.type !==
qrCodeAuthMessageTypes.SECONDARY_DEVICE_REGISTRATION_SUCCESS
) {
return;
}
+ setConnectingInProgress(false);
+
Alert.alert('Device added', 'Device registered successfully', [
{ text: 'OK', onPress: goBack },
]);
},
[goBack],
);
React.useEffect(() => {
addListener(tunnelbrokerMessageListener);
return () => {
removeListener(tunnelbrokerMessageListener);
};
}, [addListener, removeListener, tunnelbrokerMessageListener]);
const processDeviceListUpdate = React.useCallback(async () => {
try {
const { deviceID: primaryDeviceID, userID } =
await identityContext.getAuthMetadata();
if (!primaryDeviceID || !userID) {
throw new Error('missing auth metadata');
}
const encryptionKey = aes256Key.current;
const targetDeviceID = secondaryDeviceID.current;
if (!encryptionKey || !targetDeviceID) {
throw new Error('missing tunnelbroker message data');
}
const deviceType = secondaryDeviceType.current;
const sendDeviceListUpdateSuccessMessage = async () => {
let backupData = null;
if (deviceType !== identityDeviceTypes.KEYSERVER) {
backupData = await commCoreModule.getQRAuthBackupData();
}
const message = await composeTunnelbrokerQRAuthMessage(encryptionKey, {
type: qrCodeAuthMessageTypes.DEVICE_LIST_UPDATE_SUCCESS,
userID,
primaryDeviceID,
backupData,
});
await sendMessageToDevice({
deviceID: targetDeviceID,
payload: JSON.stringify(message),
});
};
const handleReplaceDevice = async () => {
try {
if (!keyserverDeviceID) {
throw new Error('missing keyserver device ID');
}
await runDeviceListUpdate({
type: 'replace',
deviceIDToRemove: keyserverDeviceID,
newDeviceID: targetDeviceID,
});
await sendDeviceListUpdateSuccessMessage();
} catch (err) {
console.log('Device replacement error:', err);
Alert.alert(
'Adding device failed',
'Failed to update the device list',
[{ text: 'OK' }],
);
goBack();
}
};
if (
deviceType !== identityDeviceTypes.KEYSERVER ||
!keyserverDeviceID ||
keyserverDeviceID === targetDeviceID
) {
await runDeviceListUpdate({
type: 'add',
deviceID: targetDeviceID,
});
await sendDeviceListUpdateSuccessMessage();
return;
}
Alert.alert(
'Existing keyserver detected',
'Do you want to replace your existing keyserver with this new one?',
[
{
text: 'No',
onPress: goBack,
style: 'cancel',
},
{
text: 'Replace',
onPress: handleReplaceDevice,
style: 'destructive',
},
],
);
} catch (err) {
+ setConnectingInProgress(false);
console.log('Primary device error:', err);
Alert.alert('Adding device failed', 'Failed to update the device list', [
{ text: 'OK' },
]);
goBack();
}
}, [
goBack,
identityContext,
keyserverDeviceID,
runDeviceListUpdate,
sendMessageToDevice,
]);
const onConnect = React.useCallback(
async (data: string) => {
+ setConnectingInProgress(true);
+
const parsedData = parseDataFromDeepLink(data);
const keysMatch = parsedData?.data?.keys;
if (!parsedData || !keysMatch) {
Alert.alert(
'Scan failed',
'QR code does not contain a valid pair of keys.',
[{ text: 'OK' }],
);
+ setConnectingInProgress(false);
return;
}
try {
const keys = JSON.parse(decodeURIComponent(keysMatch));
const { aes256, ed25519 } = keys;
aes256Key.current = aes256;
secondaryDeviceID.current = ed25519;
secondaryDeviceType.current = parsedData.data.deviceType;
} catch (err) {
+ setConnectingInProgress(false);
console.log('Failed to decode URI component:', err);
return;
}
await processDeviceListUpdate();
},
[processDeviceListUpdate],
);
const contextValue = React.useMemo(
() => ({
onConnect,
+ connectingInProgress,
}),
- [onConnect],
+ [onConnect, connectingInProgress],
);
return (
{props.children}
);
}
export { QRAuthContextProvider };
diff --git a/native/account/qr-auth/qr-auth-context.js b/native/account/qr-auth/qr-auth-context.js
index 125de2b6c..a9caba016 100644
--- a/native/account/qr-auth/qr-auth-context.js
+++ b/native/account/qr-auth/qr-auth-context.js
@@ -1,12 +1,13 @@
// @flow
import * as React from 'react';
export type QRAuthContextType = {
+onConnect: (data: string) => Promise,
+ +connectingInProgress: boolean,
};
const QRAuthContext: React.Context =
React.createContext();
export { QRAuthContext };
diff --git a/native/account/qr-auth/qr-auth-navigator.react.js b/native/account/qr-auth/qr-auth-navigator.react.js
index c0a20da8a..87c1dec06 100644
--- a/native/account/qr-auth/qr-auth-navigator.react.js
+++ b/native/account/qr-auth/qr-auth-navigator.react.js
@@ -1,72 +1,78 @@
// @flow
import type {
StackNavigationHelpers,
StackNavigationProp,
} from '@react-navigation/core';
import { createStackNavigator } from '@react-navigation/stack';
import * as React from 'react';
+import ConnectSecondaryDevice from './connect-secondary-device.react.js';
import { QRAuthContextProvider } from './qr-auth-context-provider.js';
import QRAuthNotPrimaryDevice from './qr-auth-not-primary-device.react.js';
import SecondaryDeviceQRCodeScanner from './secondary-device-qr-code-scanner.react.js';
import type { RootNavigationProp } from '../../navigation/root-navigator.react.js';
import {
+ ConnectSecondaryDeviceRouteName,
type NavigationRoute,
type QRAuthNavigatorParamList,
QRAuthNotPrimaryDeviceRouteName,
type ScreenParamList,
SecondaryDeviceQRCodeScannerRouteName,
} from '../../navigation/route-names.js';
import { deviceIsEmulator } from '../../utils/url-utils.js';
export type QRAuthNavigationProp> =
StackNavigationProp;
const QRAuthStack = createStackNavigator<
ScreenParamList,
QRAuthNavigatorParamList,
StackNavigationHelpers,
>();
type Props = {
+navigation: RootNavigationProp<'QRAuthNavigator'>,
+route: NavigationRoute<'QRAuthNavigator'>,
};
const screenOptions = {
headerShown: true,
headerTransparent: true,
headerBackTitleVisible: false,
headerTitle: '',
headerTintColor: 'white',
headerLeftContainerStyle: {
paddingLeft: 12,
},
gestureEnabled: true,
};
const secondaryDeviceQRCodeScannerOptions = {
headerTitle: deviceIsEmulator ? 'Link device' : '',
headerBackTitleVisible: false,
};
// eslint-disable-next-line no-unused-vars
function QRAuthNavigator(props: Props): React.Node {
return (
+
);
}
export default QRAuthNavigator;
diff --git a/native/navigation/route-names.js b/native/navigation/route-names.js
index bf408b33a..988b6a919 100644
--- a/native/navigation/route-names.js
+++ b/native/navigation/route-names.js
@@ -1,416 +1,419 @@
// @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 { ConnectSecondaryDeviceParams } from '../account/qr-auth/connect-secondary-device.react.js';
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 { RestoreBackupScreenParams } from '../account/restore-backup-screen.react';
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 RestoreBackupScreenRouteName = 'RestoreBackupScreen';
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 const QRAuthNavigatorRouteName = 'QRAuthNavigator';
export const QRAuthNotPrimaryDeviceRouteName = 'QRAuthNotPrimaryDevice';
+export const ConnectSecondaryDeviceRouteName = 'ConnectSecondaryDevice';
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,
+QRAuthNavigator: void,
};
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,
+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,
+RestoreBackupScreen: RestoreBackupScreenParams,
};
export type UserProfileBottomSheetParamList = {
+UserProfileBottomSheet: UserProfileBottomSheetParams,
+UserProfileAvatarModal: UserProfileAvatarModalParams,
+UserRelationshipTooltipModal: UserRelationshipTooltipModalParams,
};
export type QRAuthNavigatorParamList = {
+SecondaryDeviceQRCodeScanner: void,
+QRAuthNotPrimaryDevice: void,
+ +ConnectSecondaryDevice: ConnectSecondaryDeviceParams,
};
export type ScreenParamList = {
...RootParamList,
...OverlayParamList,
...TabParamList,
...ChatParamList,
...ChatTopTabsParamList,
...ProfileParamList,
...CalendarParamList,
...CommunityDrawerParamList,
...RegistrationParamList,
...InviteLinkParamList,
...CommunityCreationParamList,
...RolesParamList,
...SignInParamList,
...UserProfileBottomSheetParamList,
...TagFarcasterChannelParamList,
...QRAuthNavigatorParamList,
};
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,
];