Rework logged out state to preserve routing and work for web
parent
b5c64a03b6
commit
774fb83719
|
@ -122,7 +122,9 @@ export class SessionModel {
|
|||
try {
|
||||
return await this.resumeSession(sess)
|
||||
} finally {
|
||||
runInAction(() => {
|
||||
this.isResumingSession = false
|
||||
})
|
||||
}
|
||||
} else {
|
||||
this.rootStore.log.debug(
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
import React from 'react'
|
||||
import {SafeAreaView} from 'react-native'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {Signin} from 'view/com/auth/Signin'
|
||||
import {CreateAccount} from 'view/com/auth/CreateAccount'
|
||||
import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
|
||||
import {s} from 'lib/styles'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useStores} from 'state/index'
|
||||
import {useAnalytics} from 'lib/analytics'
|
||||
import {SplashScreen} from './SplashScreen'
|
||||
import {CenteredView} from '../util/Views'
|
||||
|
||||
enum ScreenState {
|
||||
S_SigninOrCreateAccount,
|
||||
S_Signin,
|
||||
S_CreateAccount,
|
||||
}
|
||||
|
||||
export const LoggedOut = observer(() => {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {screen} = useAnalytics()
|
||||
const [screenState, setScreenState] = React.useState<ScreenState>(
|
||||
ScreenState.S_SigninOrCreateAccount,
|
||||
)
|
||||
|
||||
React.useEffect(() => {
|
||||
screen('Login')
|
||||
store.shell.setMinimalShellMode(true)
|
||||
}, [store, screen])
|
||||
|
||||
if (
|
||||
store.session.isResumingSession ||
|
||||
screenState === ScreenState.S_SigninOrCreateAccount
|
||||
) {
|
||||
return (
|
||||
<SplashScreen
|
||||
onPressSignin={() => setScreenState(ScreenState.S_Signin)}
|
||||
onPressCreateAccount={() => setScreenState(ScreenState.S_CreateAccount)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<CenteredView style={[s.hContentRegion, pal.view]}>
|
||||
<SafeAreaView testID="noSessionView" style={s.hContentRegion}>
|
||||
<ErrorBoundary>
|
||||
{screenState === ScreenState.S_Signin ? (
|
||||
<Signin
|
||||
onPressBack={() =>
|
||||
setScreenState(ScreenState.S_SigninOrCreateAccount)
|
||||
}
|
||||
/>
|
||||
) : undefined}
|
||||
{screenState === ScreenState.S_CreateAccount ? (
|
||||
<CreateAccount
|
||||
onPressBack={() =>
|
||||
setScreenState(ScreenState.S_SigninOrCreateAccount)
|
||||
}
|
||||
/>
|
||||
) : undefined}
|
||||
</ErrorBoundary>
|
||||
</SafeAreaView>
|
||||
</CenteredView>
|
||||
)
|
||||
})
|
|
@ -1,28 +1,19 @@
|
|||
import React from 'react'
|
||||
import {StyleSheet} from 'react-native'
|
||||
import LinearGradient from 'react-native-linear-gradient'
|
||||
import {s, gradients} from 'lib/styles'
|
||||
import {StyleSheet, View} from 'react-native'
|
||||
import {s, colors} from 'lib/styles'
|
||||
import {Text} from '../util/text/Text'
|
||||
|
||||
export const LogoTextHero = () => {
|
||||
return (
|
||||
<LinearGradient
|
||||
colors={[gradients.blue.start, gradients.blue.end]}
|
||||
start={{x: 0, y: 0}}
|
||||
end={{x: 1, y: 1}}
|
||||
style={[styles.textHero]}>
|
||||
<View style={[styles.textHero]}>
|
||||
<Text type="title-lg" style={[s.white, s.bold]}>
|
||||
Bluesky
|
||||
</Text>
|
||||
</LinearGradient>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
logo: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
textHero: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
|
@ -30,5 +21,6 @@ const styles = StyleSheet.create({
|
|||
paddingRight: 20,
|
||||
paddingVertical: 15,
|
||||
marginBottom: 20,
|
||||
backgroundColor: colors.blue3,
|
||||
},
|
||||
})
|
|
@ -0,0 +1,92 @@
|
|||
import React from 'react'
|
||||
import {SafeAreaView, StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||
import Image, {Source as ImageSource} from 'view/com/util/images/Image'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
|
||||
import {colors} from 'lib/styles'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {CLOUD_SPLASH} from 'lib/assets'
|
||||
import {CenteredView} from '../util/Views'
|
||||
|
||||
export const SplashScreen = ({
|
||||
onPressSignin,
|
||||
onPressCreateAccount,
|
||||
}: {
|
||||
onPressSignin: () => void
|
||||
onPressCreateAccount: () => void
|
||||
}) => {
|
||||
const pal = usePalette('default')
|
||||
return (
|
||||
<CenteredView style={styles.container}>
|
||||
<Image source={CLOUD_SPLASH as ImageSource} style={styles.bgImg} />
|
||||
<SafeAreaView testID="noSessionView" style={styles.container}>
|
||||
<ErrorBoundary>
|
||||
<View style={styles.hero}>
|
||||
<View style={styles.heroText}>
|
||||
<Text style={styles.title}>Bluesky</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View testID="signinOrCreateAccount" style={styles.btns}>
|
||||
<TouchableOpacity
|
||||
testID="createAccountButton"
|
||||
style={[pal.view, styles.btn]}
|
||||
onPress={onPressCreateAccount}>
|
||||
<Text style={[pal.link, styles.btnLabel]}>
|
||||
Create a new account
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
testID="signInButton"
|
||||
style={[pal.view, styles.btn]}
|
||||
onPress={onPressSignin}>
|
||||
<Text style={[pal.link, styles.btnLabel]}>Sign in</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</ErrorBoundary>
|
||||
</SafeAreaView>
|
||||
</CenteredView>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
height: '100%',
|
||||
},
|
||||
hero: {
|
||||
flex: 2,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
bgImg: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
},
|
||||
heroText: {
|
||||
backgroundColor: colors.white,
|
||||
paddingTop: 10,
|
||||
paddingBottom: 20,
|
||||
},
|
||||
btns: {
|
||||
paddingBottom: 40,
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
color: colors.blue3,
|
||||
fontSize: 68,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
btn: {
|
||||
borderRadius: 4,
|
||||
paddingVertical: 16,
|
||||
marginBottom: 20,
|
||||
marginHorizontal: 20,
|
||||
backgroundColor: colors.blue3,
|
||||
},
|
||||
btnLabel: {
|
||||
textAlign: 'center',
|
||||
fontSize: 21,
|
||||
color: colors.white,
|
||||
},
|
||||
})
|
|
@ -0,0 +1,102 @@
|
|||
import React from 'react'
|
||||
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import {TextLink} from '../util/Link'
|
||||
import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
|
||||
import {s, colors} from 'lib/styles'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {CenteredView} from '../util/Views'
|
||||
|
||||
export const SplashScreen = ({
|
||||
onPressSignin,
|
||||
onPressCreateAccount,
|
||||
}: {
|
||||
onPressSignin: () => void
|
||||
onPressCreateAccount: () => void
|
||||
}) => {
|
||||
const pal = usePalette('default')
|
||||
return (
|
||||
<CenteredView style={styles.container}>
|
||||
<View testID="noSessionView" style={styles.containerInner}>
|
||||
<ErrorBoundary>
|
||||
<Text style={styles.title}>Bluesky</Text>
|
||||
<Text style={styles.subtitle}>See what's next</Text>
|
||||
<View testID="signinOrCreateAccount" style={styles.btns}>
|
||||
<TouchableOpacity
|
||||
testID="createAccountButton"
|
||||
style={[styles.btn, {backgroundColor: colors.blue3}]}
|
||||
onPress={onPressCreateAccount}>
|
||||
<Text style={[s.white, styles.btnLabel]}>
|
||||
Create a new account
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
testID="signInButton"
|
||||
style={[styles.btn, pal.btn]}
|
||||
onPress={onPressSignin}>
|
||||
<Text style={[pal.link, styles.btnLabel]}>Sign in</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<Text
|
||||
type="xl"
|
||||
style={[styles.notice, pal.textLight]}
|
||||
lineHeight={1.3}>
|
||||
Bluesky will launch soon.{' '}
|
||||
<TextLink
|
||||
type="xl"
|
||||
text="Join the waitlist"
|
||||
href="#"
|
||||
style={pal.link}
|
||||
/>{' '}
|
||||
to try the beta before it's publicly available.
|
||||
</Text>
|
||||
</ErrorBoundary>
|
||||
</View>
|
||||
</CenteredView>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
height: '100%',
|
||||
backgroundColor: colors.gray1,
|
||||
},
|
||||
containerInner: {
|
||||
backgroundColor: colors.white,
|
||||
paddingVertical: 40,
|
||||
paddingBottom: 50,
|
||||
paddingHorizontal: 20,
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
color: colors.blue3,
|
||||
fontSize: 68,
|
||||
fontWeight: 'bold',
|
||||
paddingBottom: 10,
|
||||
},
|
||||
subtitle: {
|
||||
textAlign: 'center',
|
||||
color: colors.gray5,
|
||||
fontSize: 52,
|
||||
fontWeight: 'bold',
|
||||
paddingBottom: 30,
|
||||
},
|
||||
btns: {
|
||||
flexDirection: 'row',
|
||||
paddingBottom: 40,
|
||||
},
|
||||
btn: {
|
||||
flex: 1,
|
||||
borderRadius: 30,
|
||||
paddingVertical: 12,
|
||||
marginHorizontal: 10,
|
||||
},
|
||||
btnLabel: {
|
||||
textAlign: 'center',
|
||||
fontSize: 18,
|
||||
},
|
||||
notice: {
|
||||
paddingHorizontal: 40,
|
||||
textAlign: 'center',
|
||||
},
|
||||
})
|
|
@ -0,0 +1,47 @@
|
|||
import React from 'react'
|
||||
import {ActivityIndicator, StyleSheet, View} from 'react-native'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {useStores} from 'state/index'
|
||||
import {LoggedOut} from './LoggedOut'
|
||||
import {Text} from '../util/text/Text'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
|
||||
export const withAuthRequired = <P extends object>(
|
||||
Component: React.ComponentType<P>,
|
||||
): React.FC<P> =>
|
||||
observer((props: P) => {
|
||||
const store = useStores()
|
||||
if (store.session.isResumingSession) {
|
||||
return <Loading />
|
||||
}
|
||||
if (!store.session.hasSession) {
|
||||
return <LoggedOut />
|
||||
}
|
||||
return <Component {...props} />
|
||||
})
|
||||
|
||||
function Loading() {
|
||||
const pal = usePalette('default')
|
||||
return (
|
||||
<View style={[styles.loading, pal.view]}>
|
||||
<ActivityIndicator size="large" />
|
||||
<Text type="2xl" style={[styles.loadingText, pal.textLight]}>
|
||||
Firing up the grill...
|
||||
</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
loading: {
|
||||
height: '100%',
|
||||
alignContent: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingBottom: 100,
|
||||
},
|
||||
loadingText: {
|
||||
paddingVertical: 20,
|
||||
paddingHorizontal: 20,
|
||||
textAlign: 'center',
|
||||
},
|
||||
})
|
|
@ -4,6 +4,7 @@ import {useFocusEffect, useIsFocused} from '@react-navigation/native'
|
|||
import {observer} from 'mobx-react-lite'
|
||||
import useAppState from 'react-native-appstate-hook'
|
||||
import {NativeStackScreenProps, HomeTabNavigatorParams} from 'lib/routes/types'
|
||||
import {withAuthRequired} from 'view/com/auth/withAuthRequired'
|
||||
import {ViewHeader} from '../com/util/ViewHeader'
|
||||
import {Feed} from '../com/posts/Feed'
|
||||
import {LoadLatestBtn} from '../com/util/LoadLatestBtn'
|
||||
|
@ -18,7 +19,8 @@ import {ComposeIcon2} from 'lib/icons'
|
|||
const HEADER_HEIGHT = 42
|
||||
|
||||
type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'>
|
||||
export const HomeScreen = observer(function Home(_opts: Props) {
|
||||
export const HomeScreen = withAuthRequired(
|
||||
observer(function Home(_opts: Props) {
|
||||
const store = useStores()
|
||||
const onMainScroll = useOnMainScroll(store)
|
||||
const {screen, track} = useAnalytics()
|
||||
|
@ -109,4 +111,5 @@ export const HomeScreen = observer(function Home(_opts: Props) {
|
|||
/>
|
||||
</View>
|
||||
)
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
|
|
@ -1,164 +0,0 @@
|
|||
import React, {useEffect, useState} from 'react'
|
||||
import {SafeAreaView, StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||
import Image, {Source as ImageSource} from 'view/com/util/images/Image'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {Signin} from '../com/login/Signin'
|
||||
import {CreateAccount} from '../com/login/CreateAccount'
|
||||
import {Text} from '../com/util/text/Text'
|
||||
import {ErrorBoundary} from '../com/util/ErrorBoundary'
|
||||
import {colors} from 'lib/styles'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useStores} from 'state/index'
|
||||
import {CLOUD_SPLASH} from 'lib/assets'
|
||||
import {useAnalytics} from 'lib/analytics'
|
||||
|
||||
enum ScreenState {
|
||||
S_SigninOrCreateAccount,
|
||||
S_Signin,
|
||||
S_CreateAccount,
|
||||
}
|
||||
|
||||
const SigninOrCreateAccount = ({
|
||||
onPressSignin,
|
||||
onPressCreateAccount,
|
||||
}: {
|
||||
onPressSignin: () => void
|
||||
onPressCreateAccount: () => void
|
||||
}) => {
|
||||
const {screen} = useAnalytics()
|
||||
|
||||
useEffect(() => {
|
||||
screen('Login')
|
||||
}, [screen])
|
||||
|
||||
const pal = usePalette('default')
|
||||
return (
|
||||
<>
|
||||
<View style={styles.hero}>
|
||||
<View style={styles.heroText}>
|
||||
<Text style={styles.title}>Bluesky</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View testID="signinOrCreateAccount" style={styles.btns}>
|
||||
<TouchableOpacity
|
||||
testID="createAccountButton"
|
||||
style={[pal.view, styles.btn]}
|
||||
onPress={onPressCreateAccount}>
|
||||
<Text style={[pal.link, styles.btnLabel]}>Create a new account</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
testID="signInButton"
|
||||
style={[pal.view, styles.btn]}
|
||||
onPress={onPressSignin}>
|
||||
<Text style={[pal.link, styles.btnLabel]}>Sign in</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const Login = observer(() => {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const [screenState, setScreenState] = useState<ScreenState>(
|
||||
ScreenState.S_SigninOrCreateAccount,
|
||||
)
|
||||
|
||||
if (
|
||||
store.session.isResumingSession ||
|
||||
screenState === ScreenState.S_SigninOrCreateAccount
|
||||
) {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Image source={CLOUD_SPLASH as ImageSource} style={styles.bgImg} />
|
||||
<SafeAreaView testID="noSessionView" style={styles.container}>
|
||||
<ErrorBoundary>
|
||||
{!store.session.isResumingSession && (
|
||||
<SigninOrCreateAccount
|
||||
onPressSignin={() => setScreenState(ScreenState.S_Signin)}
|
||||
onPressCreateAccount={() =>
|
||||
setScreenState(ScreenState.S_CreateAccount)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</ErrorBoundary>
|
||||
</SafeAreaView>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={[styles.container, pal.view]}>
|
||||
<SafeAreaView testID="noSessionView" style={styles.container}>
|
||||
<ErrorBoundary>
|
||||
{screenState === ScreenState.S_Signin ? (
|
||||
<Signin
|
||||
onPressBack={() =>
|
||||
setScreenState(ScreenState.S_SigninOrCreateAccount)
|
||||
}
|
||||
/>
|
||||
) : undefined}
|
||||
{screenState === ScreenState.S_CreateAccount ? (
|
||||
<CreateAccount
|
||||
onPressBack={() =>
|
||||
setScreenState(ScreenState.S_SigninOrCreateAccount)
|
||||
}
|
||||
/>
|
||||
) : undefined}
|
||||
</ErrorBoundary>
|
||||
</SafeAreaView>
|
||||
</View>
|
||||
)
|
||||
})
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
height: '100%',
|
||||
},
|
||||
outer: {
|
||||
flex: 1,
|
||||
},
|
||||
hero: {
|
||||
flex: 2,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
bgImg: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
},
|
||||
heroText: {
|
||||
backgroundColor: colors.white,
|
||||
paddingTop: 10,
|
||||
paddingBottom: 20,
|
||||
},
|
||||
btns: {
|
||||
paddingBottom: 40,
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
color: colors.blue3,
|
||||
fontSize: 68,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
subtitle: {
|
||||
textAlign: 'center',
|
||||
color: colors.blue3,
|
||||
fontSize: 18,
|
||||
},
|
||||
btn: {
|
||||
borderRadius: 4,
|
||||
paddingVertical: 16,
|
||||
marginBottom: 20,
|
||||
marginHorizontal: 20,
|
||||
backgroundColor: colors.blue3,
|
||||
},
|
||||
btnLabel: {
|
||||
textAlign: 'center',
|
||||
fontSize: 21,
|
||||
// fontWeight: '500',
|
||||
color: colors.white,
|
||||
},
|
||||
})
|
|
@ -1,156 +0,0 @@
|
|||
import React, {useState} from 'react'
|
||||
import {SafeAreaView, StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {CenteredView} from '../com/util/Views'
|
||||
import {Signin} from '../com/login/Signin'
|
||||
import {CreateAccount} from '../com/login/CreateAccount'
|
||||
import {Text} from '../com/util/text/Text'
|
||||
import {ErrorBoundary} from '../com/util/ErrorBoundary'
|
||||
import {colors} from 'lib/styles'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
|
||||
enum ScreenState {
|
||||
S_SigninOrCreateAccount,
|
||||
S_Signin,
|
||||
S_CreateAccount,
|
||||
}
|
||||
|
||||
const SigninOrCreateAccount = ({
|
||||
onPressSignin,
|
||||
onPressCreateAccount,
|
||||
}: {
|
||||
onPressSignin: () => void
|
||||
onPressCreateAccount: () => void
|
||||
}) => {
|
||||
const pal = usePalette('default')
|
||||
return (
|
||||
<>
|
||||
<View style={styles.hero}>
|
||||
<View style={styles.heroText}>
|
||||
<Text style={styles.title}>Bluesky</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View testID="signinOrCreateAccount" style={styles.btns}>
|
||||
<TouchableOpacity
|
||||
testID="createAccountButton"
|
||||
style={[pal.view, styles.btn]}
|
||||
onPress={onPressCreateAccount}>
|
||||
<Text style={[pal.link, styles.btnLabel]}>New account</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
testID="signInButton"
|
||||
style={[pal.view, styles.btn]}
|
||||
onPress={onPressSignin}>
|
||||
<Text style={[pal.link, styles.btnLabel]}>Sign in</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const Login = observer(() => {
|
||||
const pal = usePalette('default')
|
||||
const [screenState, setScreenState] = useState<ScreenState>(
|
||||
ScreenState.S_SigninOrCreateAccount,
|
||||
)
|
||||
|
||||
if (screenState === ScreenState.S_SigninOrCreateAccount) {
|
||||
return (
|
||||
<CenteredView style={[styles.container, styles.vertCenter]}>
|
||||
<ErrorBoundary>
|
||||
<SigninOrCreateAccount
|
||||
onPressSignin={() => setScreenState(ScreenState.S_Signin)}
|
||||
onPressCreateAccount={() =>
|
||||
setScreenState(ScreenState.S_CreateAccount)
|
||||
}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
</CenteredView>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<CenteredView
|
||||
style={[
|
||||
styles.container,
|
||||
styles.containerBorder,
|
||||
pal.view,
|
||||
pal.borderDark,
|
||||
]}>
|
||||
<SafeAreaView testID="noSessionView" style={styles.container}>
|
||||
<ErrorBoundary>
|
||||
{screenState === ScreenState.S_Signin ? (
|
||||
<Signin
|
||||
onPressBack={() =>
|
||||
setScreenState(ScreenState.S_SigninOrCreateAccount)
|
||||
}
|
||||
/>
|
||||
) : undefined}
|
||||
{screenState === ScreenState.S_CreateAccount ? (
|
||||
<CreateAccount
|
||||
onPressBack={() =>
|
||||
setScreenState(ScreenState.S_SigninOrCreateAccount)
|
||||
}
|
||||
/>
|
||||
) : undefined}
|
||||
</ErrorBoundary>
|
||||
</SafeAreaView>
|
||||
</CenteredView>
|
||||
)
|
||||
})
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
height: '100%',
|
||||
},
|
||||
containerBorder: {
|
||||
borderLeftWidth: 1,
|
||||
borderRightWidth: 1,
|
||||
},
|
||||
vertCenter: {
|
||||
justifyContent: 'center',
|
||||
},
|
||||
bgImg: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
},
|
||||
hero: {},
|
||||
heroText: {
|
||||
backgroundColor: colors.white,
|
||||
paddingTop: 10,
|
||||
paddingBottom: 20,
|
||||
},
|
||||
btns: {
|
||||
flexDirection: 'row',
|
||||
paddingTop: 40,
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
color: colors.blue3,
|
||||
fontSize: 68,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
subtitle: {
|
||||
textAlign: 'center',
|
||||
color: colors.blue3,
|
||||
fontSize: 18,
|
||||
},
|
||||
btn: {
|
||||
flex: 1,
|
||||
borderRadius: 4,
|
||||
paddingVertical: 16,
|
||||
marginBottom: 20,
|
||||
marginHorizontal: 20,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.blue3,
|
||||
},
|
||||
btnLabel: {
|
||||
textAlign: 'center',
|
||||
fontSize: 21,
|
||||
fontWeight: '500',
|
||||
color: colors.blue3,
|
||||
},
|
||||
})
|
|
@ -1,11 +1,13 @@
|
|||
import React, {useEffect} from 'react'
|
||||
import {FlatList, View} from 'react-native'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import useAppState from 'react-native-appstate-hook'
|
||||
import {
|
||||
NativeStackScreenProps,
|
||||
NotificationsTabNavigatorParams,
|
||||
} from 'lib/routes/types'
|
||||
import {withAuthRequired} from 'view/com/auth/withAuthRequired'
|
||||
import {ViewHeader} from '../com/util/ViewHeader'
|
||||
import {Feed} from '../com/notifications/Feed'
|
||||
import {useStores} from 'state/index'
|
||||
|
@ -19,7 +21,8 @@ type Props = NativeStackScreenProps<
|
|||
NotificationsTabNavigatorParams,
|
||||
'Notifications'
|
||||
>
|
||||
export const NotificationsScreen = ({}: Props) => {
|
||||
export const NotificationsScreen = withAuthRequired(
|
||||
observer(({}: Props) => {
|
||||
const store = useStores()
|
||||
const onMainScroll = useOnMainScroll(store)
|
||||
const scrollElRef = React.useRef<FlatList>(null)
|
||||
|
@ -92,4 +95,5 @@ export const NotificationsScreen = ({}: Props) => {
|
|||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
import {withAuthRequired} from 'view/com/auth/withAuthRequired'
|
||||
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
|
||||
import {ViewHeader} from '../com/util/ViewHeader'
|
||||
import {PostRepostedBy as PostRepostedByComponent} from '../com/post-thread/PostRepostedBy'
|
||||
|
@ -8,7 +9,7 @@ import {useStores} from 'state/index'
|
|||
import {makeRecordUri} from 'lib/strings/url-helpers'
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostRepostedBy'>
|
||||
export const PostRepostedByScreen = ({route}: Props) => {
|
||||
export const PostRepostedByScreen = withAuthRequired(({route}: Props) => {
|
||||
const store = useStores()
|
||||
const {name, rkey} = route.params
|
||||
const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey)
|
||||
|
@ -25,4 +26,4 @@ export const PostRepostedByScreen = ({route}: Props) => {
|
|||
<PostRepostedByComponent uri={uri} />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -3,6 +3,7 @@ import {StyleSheet, View} from 'react-native'
|
|||
import {useFocusEffect} from '@react-navigation/native'
|
||||
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
|
||||
import {makeRecordUri} from 'lib/strings/url-helpers'
|
||||
import {withAuthRequired} from 'view/com/auth/withAuthRequired'
|
||||
import {ViewHeader} from '../com/util/ViewHeader'
|
||||
import {PostThread as PostThreadComponent} from '../com/post-thread/PostThread'
|
||||
import {ComposePrompt} from 'view/com/composer/Prompt'
|
||||
|
@ -16,7 +17,7 @@ import {isDesktopWeb} from 'platform/detection'
|
|||
const SHELL_FOOTER_HEIGHT = 44
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostThread'>
|
||||
export const PostThreadScreen = ({route}: Props) => {
|
||||
export const PostThreadScreen = withAuthRequired(({route}: Props) => {
|
||||
const store = useStores()
|
||||
const safeAreaInsets = useSafeAreaInsets()
|
||||
const {name, rkey} = route.params
|
||||
|
@ -84,7 +85,7 @@ export const PostThreadScreen = ({route}: Props) => {
|
|||
)}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
prompt: {
|
||||
|
|
|
@ -2,13 +2,14 @@ import React from 'react'
|
|||
import {View} from 'react-native'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
|
||||
import {withAuthRequired} from 'view/com/auth/withAuthRequired'
|
||||
import {ViewHeader} from '../com/util/ViewHeader'
|
||||
import {PostVotedBy as PostLikedByComponent} from '../com/post-thread/PostVotedBy'
|
||||
import {useStores} from 'state/index'
|
||||
import {makeRecordUri} from 'lib/strings/url-helpers'
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostUpvotedBy'>
|
||||
export const PostUpvotedByScreen = ({route}: Props) => {
|
||||
export const PostUpvotedByScreen = withAuthRequired(({route}: Props) => {
|
||||
const store = useStores()
|
||||
const {name, rkey} = route.params
|
||||
const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey)
|
||||
|
@ -25,4 +26,4 @@ export const PostUpvotedByScreen = ({route}: Props) => {
|
|||
<PostLikedByComponent uri={uri} direction="up" />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -26,7 +26,7 @@ export const PrivacyPolicyScreen = (_props: Props) => {
|
|||
<ViewHeader title="Privacy Policy" />
|
||||
<ScrollView style={[s.hContentRegion, pal.view]}>
|
||||
<View style={[s.p20]}>
|
||||
<Text type="title-xl" style={[pal.text, s.pb20]}>
|
||||
<Text type="title-xl" style={[pal.text, s.bold, s.pb20]}>
|
||||
Privacy Policy
|
||||
</Text>
|
||||
<PrivacyPolicyHtml />
|
||||
|
|
|
@ -3,6 +3,7 @@ import {ActivityIndicator, StyleSheet, View} from 'react-native'
|
|||
import {observer} from 'mobx-react-lite'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
|
||||
import {withAuthRequired} from 'view/com/auth/withAuthRequired'
|
||||
import {ViewSelector} from '../com/util/ViewSelector'
|
||||
import {CenteredView} from '../com/util/Views'
|
||||
import {ProfileUiModel, Sections} from 'state/models/profile-ui'
|
||||
|
@ -25,7 +26,8 @@ const END_ITEM = {_reactKey: '__end__'}
|
|||
const EMPTY_ITEM = {_reactKey: '__empty__'}
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Profile'>
|
||||
export const ProfileScreen = observer(({route}: Props) => {
|
||||
export const ProfileScreen = withAuthRequired(
|
||||
observer(({route}: Props) => {
|
||||
const store = useStores()
|
||||
const {screen, track} = useAnalytics()
|
||||
|
||||
|
@ -140,7 +142,9 @@ export const ProfileScreen = observer(({route}: Props) => {
|
|||
if (item === END_ITEM) {
|
||||
return <Text style={styles.endItem}>- end of feed -</Text>
|
||||
}
|
||||
return <FeedItem item={item} ignoreMuteFor={uiState.profile.did} />
|
||||
return (
|
||||
<FeedItem item={item} ignoreMuteFor={uiState.profile.did} />
|
||||
)
|
||||
}
|
||||
} else if (uiState.feed.isEmpty) {
|
||||
items = items.concat([EMPTY_ITEM])
|
||||
|
@ -196,7 +200,8 @@ export const ProfileScreen = observer(({route}: Props) => {
|
|||
/>
|
||||
</View>
|
||||
)
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
function LoadingMoreFooter() {
|
||||
return (
|
||||
|
|
|
@ -2,12 +2,13 @@ import React from 'react'
|
|||
import {View} from 'react-native'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
|
||||
import {withAuthRequired} from 'view/com/auth/withAuthRequired'
|
||||
import {ViewHeader} from '../com/util/ViewHeader'
|
||||
import {ProfileFollowers as ProfileFollowersComponent} from '../com/profile/ProfileFollowers'
|
||||
import {useStores} from 'state/index'
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFollowers'>
|
||||
export const ProfileFollowersScreen = ({route}: Props) => {
|
||||
export const ProfileFollowersScreen = withAuthRequired(({route}: Props) => {
|
||||
const store = useStores()
|
||||
const {name} = route.params
|
||||
|
||||
|
@ -23,4 +24,4 @@ export const ProfileFollowersScreen = ({route}: Props) => {
|
|||
<ProfileFollowersComponent name={name} />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -2,12 +2,13 @@ import React from 'react'
|
|||
import {View} from 'react-native'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
|
||||
import {withAuthRequired} from 'view/com/auth/withAuthRequired'
|
||||
import {ViewHeader} from '../com/util/ViewHeader'
|
||||
import {ProfileFollows as ProfileFollowsComponent} from '../com/profile/ProfileFollows'
|
||||
import {useStores} from 'state/index'
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFollows'>
|
||||
export const ProfileFollowsScreen = ({route}: Props) => {
|
||||
export const ProfileFollowsScreen = withAuthRequired(({route}: Props) => {
|
||||
const store = useStores()
|
||||
const {name} = route.params
|
||||
|
||||
|
@ -23,4 +24,4 @@ export const ProfileFollowsScreen = ({route}: Props) => {
|
|||
<ProfileFollowsComponent name={name} />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
FontAwesomeIcon,
|
||||
FontAwesomeIconStyle,
|
||||
} from '@fortawesome/react-native-fontawesome'
|
||||
import {withAuthRequired} from 'view/com/auth/withAuthRequired'
|
||||
import {ScrollView} from '../com/util/Views'
|
||||
import {
|
||||
NativeStackScreenProps,
|
||||
|
@ -36,7 +37,8 @@ const MENU_HITSLOP = {left: 10, top: 10, right: 30, bottom: 10}
|
|||
const FIVE_MIN = 5 * 60 * 1e3
|
||||
|
||||
type Props = NativeStackScreenProps<SearchTabNavigatorParams, 'Search'>
|
||||
export const SearchScreen = observer<Props>(({}: Props) => {
|
||||
export const SearchScreen = withAuthRequired(
|
||||
observer<Props>(({}: Props) => {
|
||||
const pal = usePalette('default')
|
||||
const theme = useTheme()
|
||||
const store = useStores()
|
||||
|
@ -188,7 +190,8 @@ export const SearchScreen = observer<Props>(({}: Props) => {
|
|||
</ScrollView>
|
||||
</TouchableWithoutFeedback>
|
||||
)
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react'
|
||||
import {StyleSheet, View} from 'react-native'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
import {withAuthRequired} from 'view/com/auth/withAuthRequired'
|
||||
import {ScrollView} from '../com/util/Views'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {
|
||||
|
@ -17,7 +18,8 @@ import {useOnMainScroll} from 'lib/hooks/useOnMainScroll'
|
|||
const FIVE_MIN = 5 * 60 * 1e3
|
||||
|
||||
type Props = NativeStackScreenProps<SearchTabNavigatorParams, 'Search'>
|
||||
export const SearchScreen = observer(({}: Props) => {
|
||||
export const SearchScreen = withAuthRequired(
|
||||
observer(({}: Props) => {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const scrollElRef = React.useRef<ScrollView>(null)
|
||||
|
@ -56,7 +58,8 @@ export const SearchScreen = observer(({}: Props) => {
|
|||
<View style={s.footerSpacer} />
|
||||
</ScrollView>
|
||||
)
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
|
|
@ -16,6 +16,7 @@ import {
|
|||
} from '@fortawesome/react-native-fontawesome'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
|
||||
import {withAuthRequired} from 'view/com/auth/withAuthRequired'
|
||||
import * as AppInfo from 'lib/app-info'
|
||||
import {useStores} from 'state/index'
|
||||
import {s, colors} from 'lib/styles'
|
||||
|
@ -33,7 +34,8 @@ import {useAnalytics} from 'lib/analytics'
|
|||
import {NavigationProp} from 'lib/routes/types'
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Settings'>
|
||||
export const SettingsScreen = observer(function Settings({}: Props) {
|
||||
export const SettingsScreen = withAuthRequired(
|
||||
observer(function Settings({}: Props) {
|
||||
const theme = useTheme()
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
|
@ -261,7 +263,8 @@ export const SettingsScreen = observer(function Settings({}: Props) {
|
|||
</ScrollView>
|
||||
</View>
|
||||
)
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
function AccountDropdownBtn({handle}: {handle: string}) {
|
||||
const store = useStores()
|
||||
|
|
|
@ -131,7 +131,7 @@ export const DesktopLeftNav = observer(function DesktopLeftNav() {
|
|||
|
||||
return (
|
||||
<View style={styles.leftNav}>
|
||||
<ProfileCard />
|
||||
{store.session.hasSession && <ProfileCard />}
|
||||
<BackBtn />
|
||||
<NavItem
|
||||
href="/"
|
||||
|
@ -164,6 +164,7 @@ export const DesktopLeftNav = observer(function DesktopLeftNav() {
|
|||
}
|
||||
label="Notifications"
|
||||
/>
|
||||
{store.session.hasSession && (
|
||||
<NavItem
|
||||
href={`/profile/${store.me.handle}`}
|
||||
icon={<UserIcon strokeWidth={1.75} size={28} style={pal.text} />}
|
||||
|
@ -172,6 +173,7 @@ export const DesktopLeftNav = observer(function DesktopLeftNav() {
|
|||
}
|
||||
label="Profile"
|
||||
/>
|
||||
)}
|
||||
<NavItem
|
||||
href="/settings"
|
||||
icon={<CogIcon strokeWidth={1.75} size={28} style={pal.text} />}
|
||||
|
@ -180,7 +182,7 @@ export const DesktopLeftNav = observer(function DesktopLeftNav() {
|
|||
}
|
||||
label="Settings"
|
||||
/>
|
||||
<ComposeBtn />
|
||||
{store.session.hasSession && <ComposeBtn />}
|
||||
</View>
|
||||
)
|
||||
})
|
||||
|
|
|
@ -7,12 +7,14 @@ import {Text} from 'view/com/util/text/Text'
|
|||
import {TextLink} from 'view/com/util/Link'
|
||||
import {FEEDBACK_FORM_URL} from 'lib/constants'
|
||||
import {s} from 'lib/styles'
|
||||
import {useStores} from 'state/index'
|
||||
|
||||
export const DesktopRightNav = observer(function DesktopRightNav() {
|
||||
const store = useStores()
|
||||
const pal = usePalette('default')
|
||||
return (
|
||||
<View style={[styles.rightNav, pal.view]}>
|
||||
<DesktopSearch />
|
||||
{store.session.hasSession && <DesktopSearch />}
|
||||
<View style={styles.message}>
|
||||
<Text type="md" style={[pal.textLight, styles.messageLine]}>
|
||||
Welcome to Bluesky! This is a beta application that's still in
|
||||
|
|
|
@ -5,7 +5,6 @@ import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
|||
import {Drawer} from 'react-native-drawer-layout'
|
||||
import {useNavigationState} from '@react-navigation/native'
|
||||
import {useStores} from 'state/index'
|
||||
import {Login} from 'view/screens/Login'
|
||||
import {ModalsContainer} from 'view/com/modals/Modal'
|
||||
import {Lightbox} from 'view/com/lightbox/Lightbox'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
|
@ -104,20 +103,6 @@ export const Shell: React.FC = observer(() => {
|
|||
)
|
||||
}
|
||||
|
||||
if (!store.session.hasSession) {
|
||||
return (
|
||||
<View style={styles.outerContainer}>
|
||||
<StatusBar
|
||||
barStyle={
|
||||
theme.colorScheme === 'dark' ? 'light-content' : 'dark-content'
|
||||
}
|
||||
/>
|
||||
<Login />
|
||||
<ModalsContainer />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<View testID="mobileShellView" style={[styles.outerContainer, pal.view]}>
|
||||
<StatusBar
|
||||
|
|
|
@ -4,7 +4,6 @@ import {View, StyleSheet} from 'react-native'
|
|||
import {useStores} from 'state/index'
|
||||
import {DesktopLeftNav} from './desktop/LeftNav'
|
||||
import {DesktopRightNav} from './desktop/RightNav'
|
||||
import {Login} from '../screens/Login'
|
||||
import {ErrorBoundary} from '../com/util/ErrorBoundary'
|
||||
import {Lightbox} from '../com/lightbox/Lightbox'
|
||||
import {ModalsContainer} from '../com/modals/Modal'
|
||||
|
@ -45,21 +44,10 @@ const ShellInner = observer(() => {
|
|||
|
||||
export const Shell: React.FC = observer(() => {
|
||||
const pageBg = useColorSchemeStyle(styles.bgLight, styles.bgDark)
|
||||
const store = useStores()
|
||||
|
||||
if (isMobileWeb) {
|
||||
return <NoMobileWeb />
|
||||
}
|
||||
|
||||
if (!store.session.hasSession) {
|
||||
return (
|
||||
<View style={[s.hContentRegion, pageBg]}>
|
||||
<Login />
|
||||
<ModalsContainer />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={[s.hContentRegion, pageBg]}>
|
||||
<RoutesContainer>
|
||||
|
|
Loading…
Reference in New Issue