diff --git a/native/account/registration/connect-ethereum.react.js b/native/account/registration/connect-ethereum.react.js index 3682aecfa..c0de067d7 100644 --- a/native/account/registration/connect-ethereum.react.js +++ b/native/account/registration/connect-ethereum.react.js @@ -1,183 +1,181 @@ // @flow import * as React from 'react'; import { Text, View } from 'react-native'; import RegistrationButtonContainer from './registration-button-container.react.js'; import RegistrationButton from './registration-button.react.js'; +import RegistrationContainer from './registration-container.react.js'; import RegistrationContentContainer from './registration-content-container.react.js'; import type { RegistrationNavigationProp } from './registration-navigator.react.js'; import type { CoolOrNerdMode } from './registration-types.js'; import type { NavigationRoute } from '../../navigation/route-names.js'; import { useStyles } from '../../themes/colors.js'; import EthereumLogoDark from '../../vectors/ethereum-logo-dark.react.js'; import SIWEPanel from '../siwe-panel.react.js'; export type ConnectEthereumParams = { +userSelections: { +coolOrNerdMode: CoolOrNerdMode, +keyserverUsername: string, }, }; type PanelState = 'closed' | 'opening' | 'open' | 'closing'; type Props = { +navigation: RegistrationNavigationProp<'ConnectEthereum'>, +route: NavigationRoute<'ConnectEthereum'>, }; function ConnectEthereum(props: Props): React.Node { const isNerdMode = props.route.params.userSelections.coolOrNerdMode === 'nerd'; const styles = useStyles(unboundStyles); let body; if (!isNerdMode) { body = ( Connecting your Ethereum wallet allows you to use your ENS name and avatar in the app. You'll also be able to log in with your wallet instead of a password. ); } else { body = ( <> Connecting your Ethereum wallet has three benefits: {'1. '} Your peers will be able to cryptographically verify that your Comm account is associated with your Ethereum wallet. {'2. '} You'll be able to use your ENS name and avatar in the app. {'3. '} You can choose to skip setting a password, and to log in with your Ethereum wallet instead. ); } const [panelState, setPanelState] = React.useState('closed'); const openPanel = React.useCallback(() => { setPanelState('opening'); }, []); const onPanelClosed = React.useCallback(() => { setPanelState('closed'); }, []); const onPanelClosing = React.useCallback(() => { setPanelState('closing'); }, []); const siwePanelSetLoading = React.useCallback( (loading: boolean) => { if (panelState === 'closing' || panelState === 'closed') { return; } setPanelState(loading ? 'opening' : 'open'); }, [panelState], ); let siwePanel; if (panelState !== 'closed') { siwePanel = ( ); } const onSkip = React.useCallback(() => {}, []); return ( - - - - Do you want to connect an Ethereum Wallet to your account? - - {body} - - - - - - - - + <> + + + + Do you want to connect an Ethereum Wallet to your account? + + {body} + + + + + + + + + {siwePanel} - + ); } const unboundStyles = { - container: { - backgroundColor: 'panelBackground', - justifyContent: 'space-between', - flex: 1, - }, scrollViewContentContainer: { flexGrow: 1, }, header: { fontSize: 24, color: 'panelForegroundLabel', paddingBottom: 16, }, body: { fontSize: 15, lineHeight: 20, color: 'panelForegroundSecondaryLabel', paddingBottom: 16, }, ethereumLogoContainer: { flexGrow: 1, alignItems: 'center', justifyContent: 'center', }, list: { paddingBottom: 16, }, listItem: { flexDirection: 'row', }, listItemNumber: { fontWeight: 'bold', fontSize: 15, lineHeight: 20, color: 'panelForegroundSecondaryLabel', }, listItemContent: { flexShrink: 1, fontSize: 15, lineHeight: 20, color: 'panelForegroundSecondaryLabel', }, }; export default ConnectEthereum; diff --git a/native/account/registration/cool-or-nerd-mode-selection.react.js b/native/account/registration/cool-or-nerd-mode-selection.react.js index 3a047e941..173813c4b 100644 --- a/native/account/registration/cool-or-nerd-mode-selection.react.js +++ b/native/account/registration/cool-or-nerd-mode-selection.react.js @@ -1,132 +1,128 @@ // @flow import invariant from 'invariant'; import * as React from 'react'; -import { Text, View } from 'react-native'; +import { Text } from 'react-native'; import RegistrationButtonContainer from './registration-button-container.react.js'; import RegistrationButton from './registration-button.react.js'; +import RegistrationContainer from './registration-container.react.js'; import RegistrationContentContainer from './registration-content-container.react.js'; import type { RegistrationNavigationProp } from './registration-navigator.react.js'; import { RegistrationTile, RegistrationTileHeader, } from './registration-tile.react.js'; import type { CoolOrNerdMode } from './registration-types.js'; import { type NavigationRoute, KeyserverSelectionRouteName, } from '../../navigation/route-names.js'; import { useStyles } from '../../themes/colors.js'; type Props = { +navigation: RegistrationNavigationProp<'CoolOrNerdModeSelection'>, +route: NavigationRoute<'CoolOrNerdModeSelection'>, }; function CoolOrNerdModeSelection(props: Props): React.Node { const [currentSelection, setCurrentSelection] = React.useState(); const selectCool = React.useCallback(() => { setCurrentSelection('cool'); }, []); const selectNerd = React.useCallback(() => { setCurrentSelection('nerd'); }, []); const { navigate } = props.navigation; const onSubmit = React.useCallback(() => { invariant( currentSelection, 'Button should be disabled if currentSelection is not set', ); navigate<'KeyserverSelection'>({ name: KeyserverSelectionRouteName, params: { userSelections: { coolOrNerdMode: currentSelection } }, }); }, [navigate, currentSelection]); const buttonState = currentSelection ? 'enabled' : 'disabled'; const styles = useStyles(unboundStyles); return ( - + To begin, choose your fighter Do you want Comm to choose reasonable defaults for you, or do you want to see all the options and make the decisions yourself? This setting will affect behavior throughout the app, but you can change it later in your settings. 🤓 Nerd mode We present more options and talk through their security and privacy implications in detail. 😎 Cool mode We select reasonable defaults for you. - + ); } const unboundStyles = { - container: { - backgroundColor: 'panelBackground', - justifyContent: 'space-between', - flex: 1, - }, header: { fontSize: 24, color: 'panelForegroundLabel', paddingBottom: 16, }, body: { fontSize: 15, lineHeight: 20, color: 'panelForegroundSecondaryLabel', paddingBottom: 16, }, tileTitleText: { flex: 1, fontSize: 18, color: 'panelForegroundLabel', }, tileBody: { fontSize: 13, color: 'panelForegroundSecondaryLabel', }, emojiIcon: { fontSize: 32, bottom: 1, marginRight: 5, }, }; export default CoolOrNerdModeSelection; diff --git a/native/account/registration/keyserver-selection.react.js b/native/account/registration/keyserver-selection.react.js index f1056b81b..f769b36d2 100644 --- a/native/account/registration/keyserver-selection.react.js +++ b/native/account/registration/keyserver-selection.react.js @@ -1,177 +1,173 @@ // @flow import invariant from 'invariant'; import * as React from 'react'; -import { Text, TextInput, View } from 'react-native'; +import { Text, TextInput } from 'react-native'; import RegistrationButtonContainer from './registration-button-container.react.js'; import RegistrationButton from './registration-button.react.js'; +import RegistrationContainer from './registration-container.react.js'; import RegistrationContentContainer from './registration-content-container.react.js'; import type { RegistrationNavigationProp } from './registration-navigator.react.js'; import { RegistrationTile, RegistrationTileHeader, } from './registration-tile.react.js'; import type { CoolOrNerdMode } from './registration-types.js'; import CommIcon from '../../components/comm-icon.react.js'; import { type NavigationRoute, ConnectEthereumRouteName, } from '../../navigation/route-names.js'; import { useStyles, useColors } from '../../themes/colors.js'; type Selection = 'ashoat' | 'custom'; export type KeyserverSelectionParams = { +userSelections: { +coolOrNerdMode: CoolOrNerdMode, }, }; type Props = { +navigation: RegistrationNavigationProp<'KeyserverSelection'>, +route: NavigationRoute<'KeyserverSelection'>, }; // eslint-disable-next-line no-unused-vars function KeyserverSelection(props: Props): React.Node { const [customKeyserver, setCustomKeyserver] = React.useState(''); const customKeyserverTextInputRef = React.useRef(); const [currentSelection, setCurrentSelection] = React.useState(); const selectAshoat = React.useCallback(() => { setCurrentSelection('ashoat'); customKeyserverTextInputRef.current?.blur(); }, []); const customKeyserverEmpty = !customKeyserver; const selectCustom = React.useCallback(() => { setCurrentSelection('custom'); if (customKeyserverEmpty) { customKeyserverTextInputRef.current?.focus(); } }, [customKeyserverEmpty]); const onCustomKeyserverFocus = React.useCallback(() => { setCurrentSelection('custom'); }, []); let keyserverUsername; if (currentSelection === 'ashoat') { keyserverUsername = 'ashoat'; } else if (currentSelection === 'custom' && customKeyserver) { keyserverUsername = customKeyserver; } const buttonState = keyserverUsername ? 'enabled' : 'disabled'; const { navigate } = props.navigation; const { coolOrNerdMode } = props.route.params.userSelections; const onSubmit = React.useCallback(() => { invariant( keyserverUsername, 'Button should be disabled if keyserverUsername is not set', ); navigate<'ConnectEthereum'>({ name: ConnectEthereumRouteName, params: { userSelections: { coolOrNerdMode, keyserverUsername } }, }); }, [navigate, coolOrNerdMode, keyserverUsername]); const styles = useStyles(unboundStyles); const colors = useColors(); return ( - + Select a keyserver to join Chat communities on Comm are hosted on keyservers, which are user-operated backends. Keyservers allow Comm to offer strong privacy guarantees without sacrificing functionality. ashoat Ashoat is Comm’s founder, and his keyserver currently hosts most of the communities on Comm. Enter a keyserver - + ); } const unboundStyles = { - container: { - backgroundColor: 'panelBackground', - justifyContent: 'space-between', - flex: 1, - }, header: { fontSize: 24, color: 'panelForegroundLabel', paddingBottom: 16, }, body: { fontSize: 15, lineHeight: 20, color: 'panelForegroundSecondaryLabel', paddingBottom: 16, }, tileTitleText: { flex: 1, fontSize: 18, color: 'panelForegroundLabel', }, tileBody: { fontSize: 13, color: 'panelForegroundSecondaryLabel', }, cloud: { marginRight: 8, }, keyserverInput: { color: 'panelForegroundLabel', borderColor: 'panelSecondaryForegroundBorder', borderWidth: 1, borderRadius: 4, padding: 12, }, }; export default KeyserverSelection; diff --git a/native/account/registration/registration-container.react.js b/native/account/registration/registration-container.react.js new file mode 100644 index 000000000..e865e1a52 --- /dev/null +++ b/native/account/registration/registration-container.react.js @@ -0,0 +1,36 @@ +// @flow + +import * as React from 'react'; +import { SafeAreaView } from 'react-native-safe-area-context'; + +import { useStyles } from '../../themes/colors.js'; +import type { ViewStyle } from '../../types/styles.js'; + +const safeAreaEdges = ['bottom']; + +type Props = { + +children: React.Node, + +style?: ViewStyle, +}; +function RegistrationContainer(props: Props): React.Node { + const styles = useStyles(unboundStyles); + const style = React.useMemo( + () => [styles.container, props.style], + [styles.container, props.style], + ); + return ( + + {props.children} + + ); +} + +const unboundStyles = { + container: { + flex: 1, + backgroundColor: 'panelBackground', + justifyContent: 'space-between', + }, +}; + +export default RegistrationContainer; diff --git a/native/account/registration/registration-navigator.react.js b/native/account/registration/registration-navigator.react.js index 990c7d1c7..f00b08e30 100644 --- a/native/account/registration/registration-navigator.react.js +++ b/native/account/registration/registration-navigator.react.js @@ -1,80 +1,66 @@ // @flow import { createStackNavigator, type StackNavigationProp, type StackNavigationHelpers, } from '@react-navigation/stack'; import * as React from 'react'; -import { SafeAreaView } from 'react-native-safe-area-context'; import ConnectEthereum from './connect-ethereum.react.js'; import CoolOrNerdModeSelection from './cool-or-nerd-mode-selection.react.js'; import KeyserverSelection from './keyserver-selection.react.js'; import type { RootNavigationProp } from '../../navigation/root-navigator.react.js'; import { KeyserverSelectionRouteName, CoolOrNerdModeSelectionRouteName, ConnectEthereumRouteName, type ScreenParamList, type RegistrationParamList, } from '../../navigation/route-names.js'; -import { useStyles } from '../../themes/colors.js'; - -const safeAreaEdges = ['bottom']; export type RegistrationNavigationProp< RouteName: $Keys = $Keys, > = StackNavigationProp; const Registration = createStackNavigator< ScreenParamList, RegistrationParamList, StackNavigationHelpers, >(); const screenOptions = { headerTransparent: true, headerBackTitleVisible: false, headerTitle: '', headerTintColor: 'white', headerLeftContainerStyle: { paddingLeft: 12, }, }; type Props = { +navigation: RootNavigationProp<'Registration'>, ... }; // eslint-disable-next-line no-unused-vars function RegistrationNavigator(props: Props): React.Node { - const styles = useStyles(unboundStyles); return ( - - - - - - - + + + + + ); } -const unboundStyles = { - container: { - flex: 1, - backgroundColor: 'panelBackground', - }, -}; - export default RegistrationNavigator;