about summary refs log tree commit diff
path: root/src/view/screens
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/screens')
-rw-r--r--src/view/screens/Login.tsx73
-rw-r--r--src/view/screens/Settings.tsx116
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',