diff options
Diffstat (limited to 'src/view')
-rw-r--r-- | src/view/com/util/ViewHeader.tsx | 147 | ||||
-rw-r--r-- | src/view/index.ts | 2 | ||||
-rw-r--r-- | src/view/lib/styles.ts | 4 | ||||
-rw-r--r-- | src/view/screens/Login.tsx | 45 | ||||
-rw-r--r-- | src/view/shell/desktop-web/index.tsx | 2 | ||||
-rw-r--r-- | src/view/shell/mobile/index.tsx | 2 |
6 files changed, 145 insertions, 57 deletions
diff --git a/src/view/com/util/ViewHeader.tsx b/src/view/com/util/ViewHeader.tsx index 5d0ec2995..12aa86a4f 100644 --- a/src/view/com/util/ViewHeader.tsx +++ b/src/view/com/util/ViewHeader.tsx @@ -1,14 +1,21 @@ import React from 'react' -import {StyleSheet, Text, TouchableOpacity, View} from 'react-native' +import {observer} from 'mobx-react-lite' +import { + ActivityIndicator, + StyleSheet, + Text, + TouchableOpacity, + View, +} from 'react-native' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import {colors} from '../../lib/styles' +import {s, colors} from '../../lib/styles' import {MagnifyingGlassIcon} from '../../lib/icons' import {useStores} from '../../../state' const HITSLOP = {left: 10, top: 10, right: 10, bottom: 10} const BACK_HITSLOP = {left: 10, top: 10, right: 30, bottom: 10} -export function ViewHeader({ +export const ViewHeader = observer(function ViewHeader({ title, subtitle, onPost, @@ -27,43 +34,91 @@ export function ViewHeader({ const onPressSearch = () => { store.nav.navigate(`/search`) } + const onPressReconnect = () => { + store.session.connect().catch(e => { + // log for debugging but ignore otherwise + console.log(e) + }) + } return ( - <View style={styles.header}> - {store.nav.tab.canGoBack ? ( + <> + <View style={styles.header}> + {store.nav.tab.canGoBack ? ( + <TouchableOpacity + onPress={onPressBack} + hitSlop={BACK_HITSLOP} + style={styles.backIcon}> + <FontAwesomeIcon + size={18} + icon="angle-left" + style={{marginTop: 6}} + /> + </TouchableOpacity> + ) : undefined} + <View style={styles.titleContainer} pointerEvents="none"> + <Text style={styles.title}>{title}</Text> + {subtitle ? ( + <Text style={styles.subtitle} numberOfLines={1}> + {subtitle} + </Text> + ) : undefined} + </View> <TouchableOpacity - onPress={onPressBack} - hitSlop={BACK_HITSLOP} - style={styles.backIcon}> - <FontAwesomeIcon size={18} icon="angle-left" style={{marginTop: 6}} /> + onPress={onPressCompose} + hitSlop={HITSLOP} + style={styles.btn}> + <FontAwesomeIcon size={18} icon="plus" /> + </TouchableOpacity> + <TouchableOpacity + onPress={onPressSearch} + hitSlop={HITSLOP} + style={[styles.btn, {marginLeft: 8}]}> + <MagnifyingGlassIcon + size={18} + strokeWidth={3} + style={styles.searchBtnIcon} + /> </TouchableOpacity> - ) : undefined} - <View style={styles.titleContainer} pointerEvents="none"> - <Text style={styles.title}>{title}</Text> - {subtitle ? ( - <Text style={styles.subtitle} numberOfLines={1}> - {subtitle} - </Text> - ) : undefined} </View> - <TouchableOpacity - onPress={onPressCompose} - hitSlop={HITSLOP} - style={styles.btn}> - <FontAwesomeIcon size={18} icon="plus" /> - </TouchableOpacity> - <TouchableOpacity - onPress={onPressSearch} - hitSlop={HITSLOP} - style={[styles.btn, {marginLeft: 8}]}> - <MagnifyingGlassIcon - size={18} - strokeWidth={3} - style={styles.searchBtnIcon} - /> - </TouchableOpacity> - </View> + {!store.session.online ? ( + <TouchableOpacity style={styles.offline} onPress={onPressReconnect}> + {store.session.attemptingConnect ? ( + <> + <ActivityIndicator /> + <Text style={[s.gray1, s.bold, s.flex1, s.pl5, s.pt5, s.pb5]}> + Connecting... + </Text> + </> + ) : ( + <> + <FontAwesomeIcon icon="signal" style={[s.gray2]} size={18} /> + <FontAwesomeIcon + icon="x" + style={[ + s.red4, + { + backgroundColor: colors.gray6, + position: 'relative', + left: -4, + top: 6, + }, + ]} + border + size={12} + /> + <Text style={[s.gray1, s.bold, s.flex1, s.pl2]}> + Unable to connect + </Text> + <View style={styles.offlineBtn}> + <Text style={styles.offlineBtnText}>Try again</Text> + </View> + </> + )} + </TouchableOpacity> + ) : undefined} + </> ) -} +}) const styles = StyleSheet.create({ header: { @@ -108,4 +163,26 @@ const styles = StyleSheet.create({ position: 'relative', top: -1, }, + + offline: { + flexDirection: 'row', + alignItems: 'center', + backgroundColor: colors.gray6, + paddingLeft: 15, + paddingRight: 10, + paddingVertical: 8, + borderRadius: 8, + marginHorizontal: 4, + marginTop: 4, + }, + offlineBtn: { + backgroundColor: colors.gray5, + borderRadius: 5, + paddingVertical: 5, + paddingHorizontal: 10, + }, + offlineBtnText: { + color: colors.white, + fontWeight: 'bold', + }, }) diff --git a/src/view/index.ts b/src/view/index.ts index bd0e33cbe..65779bf99 100644 --- a/src/view/index.ts +++ b/src/view/index.ts @@ -45,6 +45,7 @@ import {faPlus} from '@fortawesome/free-solid-svg-icons/faPlus' import {faShare} from '@fortawesome/free-solid-svg-icons/faShare' import {faShareFromSquare} from '@fortawesome/free-solid-svg-icons/faShareFromSquare' import {faShield} from '@fortawesome/free-solid-svg-icons/faShield' +import {faSignal} from '@fortawesome/free-solid-svg-icons/faSignal' import {faReply} from '@fortawesome/free-solid-svg-icons/faReply' import {faRetweet} from '@fortawesome/free-solid-svg-icons/faRetweet' import {faRss} from '@fortawesome/free-solid-svg-icons/faRss' @@ -110,6 +111,7 @@ export function setup() { faShare, faShareFromSquare, faShield, + faSignal, faUser, faUsers, faUserCheck, diff --git a/src/view/lib/styles.ts b/src/view/lib/styles.ts index 1ac6283a2..d3fc8c70f 100644 --- a/src/view/lib/styles.ts +++ b/src/view/lib/styles.ts @@ -10,6 +10,9 @@ export const colors = { gray3: '#c1b9b9', gray4: '#968d8d', gray5: '#645454', + gray6: '#423737', + gray7: '#2D2626', + gray8: '#131010', blue0: '#bfe1ff', blue1: '#8bc7fd', @@ -131,6 +134,7 @@ export const s = StyleSheet.create({ flexRow: {flexDirection: 'row'}, flexCol: {flexDirection: 'column'}, flex1: {flex: 1}, + alignCenter: {alignItems: 'center'}, // position absolute: {position: 'absolute'}, diff --git a/src/view/screens/Login.tsx b/src/view/screens/Login.tsx index abd5274da..4175e0a34 100644 --- a/src/view/screens/Login.tsx +++ b/src/view/screens/Login.tsx @@ -25,6 +25,7 @@ import {useStores, DEFAULT_SERVICE} from '../../state' import {ServiceDescription} from '../../state/models/session' import {ServerInputModel} from '../../state/models/shell-ui' import {ComAtprotoAccountCreate} from '../../third-party/api/index' +import {isNetworkError} from '../../lib/errors' enum ScreenState { SigninOrCreateAccount, @@ -186,7 +187,7 @@ const Signin = ({onPressBack}: {onPressBack: () => void}) => { setIsProcessing(false) if (errMsg.includes('Authentication Required')) { setError('Invalid username or password') - } else if (errMsg.includes('Network request failed')) { + } else if (isNetworkError(e)) { setError( 'Unable to contact your service. Please check your Internet connection.', ) @@ -210,16 +211,6 @@ const Signin = ({onPressBack}: {onPressBack: () => void}) => { </Text> <FontAwesomeIcon icon="pen" size={10} style={styles.groupTitleIcon} /> </TouchableOpacity> - {error ? ( - <View style={styles.error}> - <View style={styles.errorIcon}> - <FontAwesomeIcon icon="exclamation" style={s.white} size={10} /> - </View> - <View style={s.flex1}> - <Text style={[s.white, s.bold]}>{error}</Text> - </View> - </View> - ) : undefined} <View style={styles.groupContent}> <FontAwesomeIcon icon="at" style={styles.groupContentIcon} /> <TextInput @@ -249,18 +240,31 @@ const Signin = ({onPressBack}: {onPressBack: () => void}) => { /> </View> </View> - <View style={[s.flexRow, s.pl20, s.pr20]}> + {error ? ( + <View style={styles.error}> + <View style={styles.errorIcon}> + <FontAwesomeIcon icon="exclamation" style={s.white} size={10} /> + </View> + <View style={s.flex1}> + <Text style={[s.white, s.bold]}>{error}</Text> + </View> + </View> + ) : undefined} + <View style={[s.flexRow, s.alignCenter, s.pl20, s.pr20]}> <TouchableOpacity onPress={onPressBack}> <Text style={[s.white, s.f18, s.pl5]}>Back</Text> </TouchableOpacity> <View style={s.flex1} /> <TouchableOpacity onPress={onPressNext}> - {isProcessing ? ( + {!serviceDescription || isProcessing ? ( <ActivityIndicator color="#fff" /> ) : ( <Text style={[s.white, s.f18, s.bold, s.pr5]}>Next</Text> )} </TouchableOpacity> + {!serviceDescription || isProcessing ? ( + <Text style={[s.white, s.f18, s.pl10]}>Connecting...</Text> + ) : undefined} </View> </KeyboardAvoidingView> ) @@ -689,18 +693,19 @@ const styles = StyleSheet.create({ color: colors.white, }, error: { - borderTopWidth: 1, - borderTopColor: colors.blue1, + borderWidth: 1, + borderColor: colors.red5, + backgroundColor: colors.red4, flexDirection: 'row', alignItems: 'center', - marginTop: 5, - backgroundColor: colors.blue2, + marginTop: -5, + marginHorizontal: 20, + marginBottom: 15, + borderRadius: 8, paddingHorizontal: 8, - paddingVertical: 5, + paddingVertical: 8, }, errorFloating: { - borderWidth: 1, - borderColor: colors.blue1, marginBottom: 20, marginHorizontal: 20, borderRadius: 8, diff --git a/src/view/shell/desktop-web/index.tsx b/src/view/shell/desktop-web/index.tsx index 13acbbfed..194954349 100644 --- a/src/view/shell/desktop-web/index.tsx +++ b/src/view/shell/desktop-web/index.tsx @@ -9,7 +9,7 @@ export const DesktopWebShell: React.FC = observer(({children}) => { const store = useStores() return ( <View style={styles.outerContainer}> - {store.session.isAuthed ? ( + {store.session.hasSession ? ( <> <DesktopLeftColumn /> <View style={styles.innerContainer}>{children}</View> diff --git a/src/view/shell/mobile/index.tsx b/src/view/shell/mobile/index.tsx index d653944d1..e3e30decc 100644 --- a/src/view/shell/mobile/index.tsx +++ b/src/view/shell/mobile/index.tsx @@ -231,7 +231,7 @@ export const MobileShell: React.FC = observer(() => { transform: [{scale: newTabInterp.value}], })) - if (!store.session.isAuthed) { + if (!store.session.hasSession) { return ( <LinearGradient colors={['#007CFF', '#00BCFF']} |