diff options
Diffstat (limited to 'src/view/screens')
-rw-r--r-- | src/view/screens/Login.tsx | 73 | ||||
-rw-r--r-- | src/view/screens/Settings.tsx | 116 |
2 files changed, 148 insertions, 41 deletions
diff --git a/src/view/screens/Login.tsx b/src/view/screens/Login.tsx index 8363dbfe0..7d99f1444 100644 --- a/src/view/screens/Login.tsx +++ b/src/view/screens/Login.tsx @@ -1,17 +1,21 @@ import React, {useState} from 'react' import { + SafeAreaView, StyleSheet, TouchableOpacity, View, useWindowDimensions, } from 'react-native' import Svg, {Line} from 'react-native-svg' +import LinearGradient from 'react-native-linear-gradient' import {observer} from 'mobx-react-lite' import {Signin} from '../com/login/Signin' import {Logo} from '../com/login/Logo' import {CreateAccount} from '../com/login/CreateAccount' import {Text} from '../com/util/text/Text' +import {ErrorBoundary} from '../com/util/ErrorBoundary' import {s, colors} from '../lib/styles' +import {usePalette} from '../lib/hooks/usePalette' enum ScreenState { SigninOrCreateAccount, @@ -31,7 +35,7 @@ const SigninOrCreateAccount = ({ return ( <> <View style={styles.hero}> - <Logo /> + <Logo color="white" /> <Text style={styles.title}>Bluesky</Text> <Text style={styles.subtitle}>[ private beta ]</Text> </View> @@ -76,40 +80,61 @@ const SigninOrCreateAccount = ({ export const Login = observer( (/*{navigation}: RootTabsScreenProps<'Login'>*/) => { + const pal = usePalette('default') const [screenState, setScreenState] = useState<ScreenState>( ScreenState.SigninOrCreateAccount, ) + if (screenState === ScreenState.SigninOrCreateAccount) { + return ( + <LinearGradient + colors={['#007CFF', '#00BCFF']} + start={{x: 0, y: 0.8}} + end={{x: 0, y: 1}} + style={styles.container}> + <SafeAreaView testID="noSessionView" style={styles.container}> + <ErrorBoundary> + <SigninOrCreateAccount + onPressSignin={() => setScreenState(ScreenState.Signin)} + onPressCreateAccount={() => + setScreenState(ScreenState.CreateAccount) + } + /> + </ErrorBoundary> + </SafeAreaView> + </LinearGradient> + ) + } + return ( - <View style={styles.outer}> - {screenState === ScreenState.SigninOrCreateAccount ? ( - <SigninOrCreateAccount - onPressSignin={() => setScreenState(ScreenState.Signin)} - onPressCreateAccount={() => - setScreenState(ScreenState.CreateAccount) - } - /> - ) : undefined} - {screenState === ScreenState.Signin ? ( - <Signin - onPressBack={() => - setScreenState(ScreenState.SigninOrCreateAccount) - } - /> - ) : undefined} - {screenState === ScreenState.CreateAccount ? ( - <CreateAccount - onPressBack={() => - setScreenState(ScreenState.SigninOrCreateAccount) - } - /> - ) : undefined} + <View style={[styles.container, pal.view]}> + <SafeAreaView testID="noSessionView" style={styles.container}> + <ErrorBoundary> + {screenState === ScreenState.Signin ? ( + <Signin + onPressBack={() => + setScreenState(ScreenState.SigninOrCreateAccount) + } + /> + ) : undefined} + {screenState === ScreenState.CreateAccount ? ( + <CreateAccount + onPressBack={() => + setScreenState(ScreenState.SigninOrCreateAccount) + } + /> + ) : undefined} + </ErrorBoundary> + </SafeAreaView> </View> ) }, ) const styles = StyleSheet.create({ + container: { + height: '100%', + }, outer: { flex: 1, }, diff --git a/src/view/screens/Settings.tsx b/src/view/screens/Settings.tsx index 22230f24c..2c6982685 100644 --- a/src/view/screens/Settings.tsx +++ b/src/view/screens/Settings.tsx @@ -1,5 +1,12 @@ import React, {useEffect} from 'react' -import {StyleSheet, TouchableOpacity, View} from 'react-native' +import { + ActivityIndicator, + ScrollView, + StyleSheet, + TouchableOpacity, + View, +} from 'react-native' +import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {observer} from 'mobx-react-lite' import {useStores} from '../../state' import {ScreenParams} from '../routes' @@ -7,8 +14,10 @@ import {s} from '../lib/styles' import {ViewHeader} from '../com/util/ViewHeader' import {Link} from '../com/util/Link' import {Text} from '../com/util/text/Text' +import * as Toast from '../com/util/Toast' import {UserAvatar} from '../com/util/UserAvatar' import {usePalette} from '../lib/hooks/usePalette' +import {AccountData} from '../../state/models/session' export const Settings = observer(function Settings({ navIdx, @@ -16,6 +25,7 @@ export const Settings = observer(function Settings({ }: ScreenParams) { const pal = usePalette('default') const store = useStores() + const [isSwitching, setIsSwitching] = React.useState(false) useEffect(() => { if (!visible) { @@ -25,45 +35,114 @@ export const Settings = observer(function Settings({ store.nav.setTitle(navIdx, 'Settings') }, [visible, store]) + const onPressSwitchAccount = async (acct: AccountData) => { + setIsSwitching(true) + if (await store.session.resumeSession(acct)) { + setIsSwitching(false) + Toast.show(`Signed in as ${acct.displayName || acct.handle}`) + return + } + setIsSwitching(false) + Toast.show('Sorry! We need you to enter your password.') + store.session.clear() + } + const onPressAddAccount = () => { + store.session.clear() + } const onPressSignout = () => { store.session.logout() } return ( - <View style={[s.flex1]}> + <View style={[s.h100pct]} testID="settingsScreen"> <ViewHeader title="Settings" /> - <View style={[s.mt10, s.pl10, s.pr10, s.flex1]}> + <ScrollView style={[s.mt10, s.pl10, s.pr10, s.h100pct]}> <View style={[s.flexRow]}> - <Text type="xl" style={pal.text}> + <Text type="xl-bold" style={pal.text}> Signed in as </Text> <View style={s.flex1} /> - <TouchableOpacity onPress={onPressSignout}> + <TouchableOpacity + testID="signOutBtn" + onPress={isSwitching ? undefined : onPressSignout}> <Text type="xl-medium" style={pal.link}> Sign out </Text> </TouchableOpacity> </View> - <Link - href={`/profile/${store.me.handle}`} - title="Your profile" - noFeedback> + {isSwitching ? ( <View style={[pal.view, styles.profile]}> + <ActivityIndicator /> + </View> + ) : ( + <Link + href={`/profile/${store.me.handle}`} + title="Your profile" + noFeedback> + <View style={[pal.view, styles.profile]}> + <UserAvatar + size={40} + displayName={store.me.displayName} + handle={store.me.handle || ''} + avatar={store.me.avatar} + /> + <View style={[s.ml10]}> + <Text type="xl-bold" style={pal.text}> + {store.me.displayName || store.me.handle} + </Text> + <Text style={pal.textLight}>@{store.me.handle}</Text> + </View> + </View> + </Link> + )} + <Text type="sm-medium" style={pal.text}> + Switch to: + </Text> + {store.session.switchableAccounts.map(account => ( + <TouchableOpacity + testID={`switchToAccountBtn-${account.handle}`} + key={account.did} + style={[ + pal.view, + styles.profile, + s.mb2, + isSwitching && styles.dimmed, + ]} + onPress={ + isSwitching ? undefined : () => onPressSwitchAccount(account) + }> <UserAvatar size={40} - displayName={store.me.displayName} - handle={store.me.handle || ''} - avatar={store.me.avatar} + displayName={account.displayName} + handle={account.handle || ''} + avatar={account.aviUrl} /> <View style={[s.ml10]}> <Text type="xl-bold" style={pal.text}> - {store.me.displayName || store.me.handle} + {account.displayName || account.handle} </Text> - <Text style={pal.textLight}>@{store.me.handle}</Text> + <Text style={pal.textLight}>@{account.handle}</Text> </View> + </TouchableOpacity> + ))} + <TouchableOpacity + testID="switchToNewAccountBtn" + style={[ + pal.view, + styles.profile, + s.mb2, + {alignItems: 'center'}, + isSwitching && styles.dimmed, + ]} + onPress={isSwitching ? undefined : onPressAddAccount}> + <FontAwesomeIcon icon="plus" /> + <View style={[s.ml5]}> + <Text type="md-medium" style={pal.text}> + Add account + </Text> </View> - </Link> - <View style={s.flex1} /> + </TouchableOpacity> + <View style={{height: 50}} /> <Text type="sm-medium" style={[s.mb5]}> Developer tools </Text> @@ -80,12 +159,15 @@ export const Settings = observer(function Settings({ <Text style={pal.link}>Storybook</Text> </Link> <View style={s.footerSpacer} /> - </View> + </ScrollView> </View> ) }) const styles = StyleSheet.create({ + dimmed: { + opacity: 0.5, + }, title: { fontSize: 32, fontWeight: 'bold', |