Fix modals

This commit is contained in:
Zhiyuan Zheng 2021-05-12 22:45:51 +02:00
parent 8e0d499ed8
commit 87343989cf
No known key found for this signature in database
GPG Key ID: 078A93AB607D85E0
14 changed files with 361 additions and 442 deletions

View File

@ -8,8 +8,8 @@ public class BasePackageList {
public List<Package> getPackageList() { public List<Package> getPackageList() {
return Arrays.<Package>asList( return Arrays.<Package>asList(
new expo.modules.application.ApplicationPackage(), new expo.modules.application.ApplicationPackage(),
new expo.modules.constants.ConstantsPackage(),
new expo.modules.av.AVPackage(), new expo.modules.av.AVPackage(),
new expo.modules.constants.ConstantsPackage(),
new expo.modules.crypto.CryptoPackage(), new expo.modules.crypto.CryptoPackage(),
new expo.modules.device.DevicePackage(), new expo.modules.device.DevicePackage(),
new expo.modules.errorrecovery.ErrorRecoveryPackage(), new expo.modules.errorrecovery.ErrorRecoveryPackage(),
@ -19,17 +19,14 @@ public class BasePackageList {
new expo.modules.font.FontLoaderPackage(), new expo.modules.font.FontLoaderPackage(),
new expo.modules.haptics.HapticsPackage(), new expo.modules.haptics.HapticsPackage(),
new expo.modules.imageloader.ImageLoaderPackage(), new expo.modules.imageloader.ImageLoaderPackage(),
new expo.modules.permissions.PermissionsPackage(),
new expo.modules.imagepicker.ImagePickerPackage(), new expo.modules.imagepicker.ImagePickerPackage(),
new expo.modules.keepawake.KeepAwakePackage(), new expo.modules.keepawake.KeepAwakePackage(),
new expo.modules.lineargradient.LinearGradientPackage(),
new expo.modules.localization.LocalizationPackage(), new expo.modules.localization.LocalizationPackage(),
new expo.modules.location.LocationPackage(),
new expo.modules.notifications.NotificationsPackage(), new expo.modules.notifications.NotificationsPackage(),
new expo.modules.permissions.PermissionsPackage(),
new expo.modules.screencapture.ScreenCapturePackage(), new expo.modules.screencapture.ScreenCapturePackage(),
new expo.modules.securestore.SecureStorePackage(), new expo.modules.securestore.SecureStorePackage(),
new expo.modules.splashscreen.SplashScreenPackage(), new expo.modules.splashscreen.SplashScreenPackage(),
new expo.modules.sqlite.SQLitePackage(),
new expo.modules.storereview.StoreReviewPackage(), new expo.modules.storereview.StoreReviewPackage(),
new expo.modules.updates.UpdatesPackage(), new expo.modules.updates.UpdatesPackage(),
new expo.modules.videothumbnails.VideoThumbnailsPackage(), new expo.modules.videothumbnails.VideoThumbnailsPackage(),

View File

@ -151,8 +151,4 @@ declare namespace Nav {
fields?: Mastodon.Source['fields'] fields?: Mastodon.Source['fields']
} }
} }
type TabMePushStackParamList = {
'Tab-Me-Push-Root': undefined
}
} }

View File

@ -1,3 +1,4 @@
import { HeaderCenter, HeaderLeft } from '@components/Header'
import { displayMessage, Message, removeMessage } from '@components/Message' import { displayMessage, Message, removeMessage } from '@components/Message'
import navigationRef from '@helpers/navigationRef' import navigationRef from '@helpers/navigationRef'
import { useNetInfo } from '@react-native-community/netinfo' import { useNetInfo } from '@react-native-community/netinfo'
@ -171,18 +172,30 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
<Stack.Screen <Stack.Screen
name='Screen-Announcements' name='Screen-Announcements'
component={ScreenAnnouncements} component={ScreenAnnouncements}
options={{ options={({ navigation }) => ({
stackPresentation: 'transparentModal', stackPresentation: 'transparentModal',
stackAnimation: 'fade', stackAnimation: 'fade',
headerShown: false headerShown: true,
}} headerHideShadow: true,
headerTopInsetEnabled: false,
headerStyle: { backgroundColor: 'transparent' },
headerLeft: () => (
<HeaderLeft content='X' onPress={() => navigation.goBack()} />
),
headerTitle: t('screenAnnouncements:heading'),
...(Platform.OS === 'android' && {
headerCenter: () => (
<HeaderCenter content={t('screenAnnouncements:heading')} />
)
})
})}
/> />
<Stack.Screen <Stack.Screen
name='Screen-Compose' name='Screen-Compose'
component={ScreenCompose} component={ScreenCompose}
options={{ options={{
stackPresentation: 'fullScreenModal', stackPresentation: 'fullScreenModal',
headerShown: false ...(Platform.OS === 'android' && { headerShown: false })
}} }}
/> />
<Stack.Screen <Stack.Screen
@ -191,7 +204,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
options={{ options={{
stackPresentation: 'fullScreenModal', stackPresentation: 'fullScreenModal',
stackAnimation: 'fade', stackAnimation: 'fade',
headerShown: false ...(Platform.OS === 'android' && { headerShown: false })
}} }}
/> />
</Stack.Navigator> </Stack.Navigator>

View File

@ -1,7 +1,6 @@
import analytics from '@components/analytics' import analytics from '@components/analytics'
import Button from '@components/Button' import Button from '@components/Button'
import haptics from '@components/haptics' import haptics from '@components/haptics'
import { HeaderCenter, HeaderLeft, HeaderRight } from '@components/Header'
import { ParseHTML } from '@components/Parse' import { ParseHTML } from '@components/Parse'
import RelativeTime from '@components/RelativeTime' import RelativeTime from '@components/RelativeTime'
import { BlurView } from '@react-native-community/blur' import { BlurView } from '@react-native-community/blur'
@ -210,28 +209,6 @@ const ScreenAnnouncements: React.FC<ScreenAnnouncementsProp> = ({
reducedTransparencyFallbackColor={theme.backgroundDefault} reducedTransparencyFallbackColor={theme.backgroundDefault}
> >
<SafeAreaView style={styles.base}> <SafeAreaView style={styles.base}>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
flexBasis: 44
}}
>
<HeaderLeft
content='X'
native={false}
onPress={() => navigation.goBack()}
/>
<HeaderCenter content={t('screenAnnouncements:heading')} />
<View style={{ opacity: 0 }} accessible={false}>
<HeaderRight
content='MoreHorizontal'
native={false}
onPress={() => {}}
/>
</View>
</View>
<FlatList <FlatList
horizontal horizontal
data={query.data} data={query.data}

View File

@ -397,12 +397,18 @@ const ScreenCompose: React.FC<ScreenComposeProp> = ({
<Stack.Screen <Stack.Screen
name='Screen-Compose-DraftsList' name='Screen-Compose-DraftsList'
component={ComposeDraftsList} component={ComposeDraftsList}
options={{ stackPresentation: 'modal', headerShown: false }} options={{
stackPresentation: 'modal',
...(Platform.OS === 'android' && { headerShown: false })
}}
/> />
<Stack.Screen <Stack.Screen
name='Screen-Compose-EditAttachment' name='Screen-Compose-EditAttachment'
component={ComposeEditAttachment} component={ComposeEditAttachment}
options={{ stackPresentation: 'modal', headerShown: false }} options={{
stackPresentation: 'modal',
...(Platform.OS === 'android' && { headerShown: false })
}}
/> />
</Stack.Navigator> </Stack.Navigator>
</ComposeContext.Provider> </ComposeContext.Provider>

View File

@ -109,16 +109,28 @@ const TabMe = React.memo(
component={TabMeProfile} component={TabMeProfile}
options={{ options={{
stackPresentation: 'modal', stackPresentation: 'modal',
headerShown: false ...(Platform.OS === 'android' && { headerShown: false })
}} }}
/> />
<Stack.Screen <Stack.Screen
name='Tab-Me-Push' name='Tab-Me-Push'
component={TabMePush} component={TabMePush}
options={{ options={({ navigation }) => ({
stackPresentation: 'modal', stackPresentation: 'modal',
headerShown: false headerShown: true,
}} headerTitle: t('me.stacks.push.name'),
...(Platform.OS === 'android' && {
headerCenter: () => (
<HeaderCenter content={t('me.stacks.push.name')} />
)
}),
headerLeft: () => (
<HeaderLeft
content='ChevronDown'
onPress={() => navigation.goBack()}
/>
)
})}
/> />
<Stack.Screen <Stack.Screen
name='Tab-Me-Settings' name='Tab-Me-Settings'
@ -149,10 +161,22 @@ const TabMe = React.memo(
<Stack.Screen <Stack.Screen
name='Tab-Me-Switch' name='Tab-Me-Switch'
component={TabMeSwitch} component={TabMeSwitch}
options={{ options={({ navigation }) => ({
stackPresentation: 'modal', stackPresentation: 'modal',
headerShown: false headerShown: true,
}} headerTitle: t('me.stacks.switch.name'),
...(Platform.OS === 'android' && {
headerCenter: () => (
<HeaderCenter content={t('me.stacks.switch.name')} />
)
}),
headerLeft: () => (
<HeaderLeft
content='ChevronDown'
onPress={() => navigation.goBack()}
/>
)
})}
/> />
{sharedScreens(Stack as any)} {sharedScreens(Stack as any)}

View File

@ -1,42 +1,157 @@
import { HeaderCenter, HeaderLeft } from '@components/Header' import Button from '@components/Button'
import { StackScreenProps } from '@react-navigation/stack' import { MenuContainer, MenuRow } from '@components/Menu'
import React from 'react' import { updateInstancePush } from '@utils/slices/instances/updatePush'
import { updateInstancePushAlert } from '@utils/slices/instances/updatePushAlert'
import { updateInstancePushDecode } from '@utils/slices/instances/updatePushDecode'
import {
clearPushLoading,
getInstanceAccount,
getInstancePush,
getInstanceUri
} from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import layoutAnimation from '@utils/styles/layoutAnimation'
import * as Notifications from 'expo-notifications'
import * as WebBrowser from 'expo-web-browser'
import React, { useState, useEffect, useMemo } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Platform } from 'react-native' import { AppState, Linking, ScrollView } from 'react-native'
import { createNativeStackNavigator } from 'react-native-screens/native-stack' import { useDispatch, useSelector } from 'react-redux'
import TabMePushRoot from './Push/Root'
const Stack = createNativeStackNavigator<Nav.TabMePushStackParamList>() const TabMePush: React.FC = () => {
const TabMePush: React.FC<StackScreenProps<
Nav.TabMeStackParamList,
'Tab-Me-Push'
>> = ({ navigation }) => {
const { t } = useTranslation('screenTabs') const { t } = useTranslation('screenTabs')
const instanceAccount = useSelector(
getInstanceAccount,
(prev, next) => prev?.acct === next?.acct
)
const instanceUri = useSelector(getInstanceUri)
const dispatch = useDispatch()
const instancePush = useSelector(getInstancePush)
const [pushEnabled, setPushEnabled] = useState<boolean>()
const [pushCanAskAgain, setPushCanAskAgain] = useState<boolean>()
const checkPush = async () => {
const settings = await Notifications.getPermissionsAsync()
layoutAnimation()
setPushEnabled(settings.granted)
setPushCanAskAgain(settings.canAskAgain)
}
useEffect(() => {
checkPush()
AppState.addEventListener('change', checkPush)
return () => {
AppState.removeEventListener('change', checkPush)
}
}, [])
useEffect(() => {
dispatch(clearPushLoading())
}, [])
const isLoading = instancePush?.global.loading || instancePush?.decode.loading
const alerts = useMemo(() => {
return instancePush?.alerts
? (['follow', 'favourite', 'reblog', 'mention', 'poll'] as [
'follow',
'favourite',
'reblog',
'mention',
'poll'
]).map(alert => (
<MenuRow
key={alert}
title={t(`me.push.${alert}.heading`)}
switchDisabled={
!pushEnabled || !instancePush.global.value || isLoading
}
switchValue={instancePush?.alerts[alert].value}
switchOnValueChange={() =>
dispatch(
updateInstancePushAlert({
changed: alert,
alerts: {
...instancePush?.alerts,
[alert]: {
...instancePush?.alerts[alert],
value: !instancePush?.alerts[alert].value
}
}
})
)
}
/>
))
: null
}, [pushEnabled, instancePush?.global, instancePush?.alerts, isLoading])
return ( return (
<Stack.Navigator <ScrollView>
screenOptions={{ headerHideShadow: true, headerTopInsetEnabled: false }} {pushEnabled === false ? (
> <MenuContainer>
<Stack.Screen <Button
name='Tab-Me-Push-Root' type='text'
component={TabMePushRoot} content={
options={{ pushCanAskAgain
headerTitle: t('me.stacks.push.name'), ? t('me.push.enable.direct')
...(Platform.OS === 'android' && { : t('me.push.enable.settings')
headerCenter: () => ( }
<HeaderCenter content={t('me.stacks.push.name')} /> style={{
) marginTop: StyleConstants.Spacing.Global.PagePadding,
}), marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2
headerLeft: () => ( }}
<HeaderLeft onPress={async () => {
content='ChevronDown' if (pushCanAskAgain) {
onPress={() => navigation.goBack()} const result = await Notifications.requestPermissionsAsync()
/> setPushEnabled(result.granted)
) setPushCanAskAgain(result.canAskAgain)
}} } else {
/> Linking.openSettings()
</Stack.Navigator> }
}}
/>
</MenuContainer>
) : null}
<MenuContainer>
<MenuRow
title={t('me.push.global.heading', {
acct: `@${instanceAccount?.acct}@${instanceUri}`
})}
description={t('me.push.global.description')}
loading={instancePush?.global.loading}
switchDisabled={!pushEnabled || isLoading}
switchValue={
pushEnabled === false ? false : instancePush?.global.value
}
switchOnValueChange={() =>
dispatch(updateInstancePush(!instancePush?.global.value))
}
/>
</MenuContainer>
<MenuContainer>
<MenuRow
title={t('me.push.decode.heading')}
description={t('me.push.decode.description')}
loading={instancePush?.decode.loading}
switchDisabled={
!pushEnabled || !instancePush?.global.value || isLoading
}
switchValue={instancePush?.decode.value}
switchOnValueChange={() =>
dispatch(updateInstancePushDecode(!instancePush?.decode.value))
}
/>
<MenuRow
title={t('me.push.howitworks')}
iconBack='ExternalLink'
onPress={() =>
WebBrowser.openBrowserAsync('https://tooot.app/how-push-works')
}
/>
</MenuContainer>
<MenuContainer>{alerts}</MenuContainer>
</ScrollView>
) )
} }

View File

@ -1,163 +0,0 @@
import { MenuContainer, MenuRow } from '@components/Menu'
import { updateInstancePush } from '@utils/slices/instances/updatePush'
import { updateInstancePushAlert } from '@utils/slices/instances/updatePushAlert'
import { updateInstancePushDecode } from '@utils/slices/instances/updatePushDecode'
import {
clearPushLoading,
getInstanceAccount,
getInstancePush,
getInstanceUri
} from '@utils/slices/instancesSlice'
import * as WebBrowser from 'expo-web-browser'
import * as Notifications from 'expo-notifications'
import React, { useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { ScrollView } from 'react-native-gesture-handler'
import { useDispatch, useSelector } from 'react-redux'
import layoutAnimation from '@utils/styles/layoutAnimation'
import Button from '@components/Button'
import { StyleConstants } from '@utils/styles/constants'
import { AppState, Linking } from 'react-native'
import { StackScreenProps } from '@react-navigation/stack'
const TabMePushRoot: React.FC<StackScreenProps<
Nav.TabMeStackParamList,
'Tab-Me-Push'
>> = () => {
const { t } = useTranslation('screenTabs')
const instanceAccount = useSelector(
getInstanceAccount,
(prev, next) => prev?.acct === next?.acct
)
const instanceUri = useSelector(getInstanceUri)
const dispatch = useDispatch()
const instancePush = useSelector(getInstancePush)
const [pushEnabled, setPushEnabled] = useState<boolean>()
const [pushCanAskAgain, setPushCanAskAgain] = useState<boolean>()
const checkPush = async () => {
const settings = await Notifications.getPermissionsAsync()
layoutAnimation()
setPushEnabled(settings.granted)
setPushCanAskAgain(settings.canAskAgain)
}
useEffect(() => {
checkPush()
AppState.addEventListener('change', checkPush)
return () => {
AppState.removeEventListener('change', checkPush)
}
}, [])
useEffect(() => {
dispatch(clearPushLoading())
}, [])
const isLoading = instancePush?.global.loading || instancePush?.decode.loading
const alerts = useMemo(() => {
return instancePush?.alerts
? (['follow', 'favourite', 'reblog', 'mention', 'poll'] as [
'follow',
'favourite',
'reblog',
'mention',
'poll'
]).map(alert => (
<MenuRow
key={alert}
title={t(`me.push.${alert}.heading`)}
switchDisabled={
!pushEnabled || !instancePush.global.value || isLoading
}
switchValue={instancePush?.alerts[alert].value}
switchOnValueChange={() =>
dispatch(
updateInstancePushAlert({
changed: alert,
alerts: {
...instancePush?.alerts,
[alert]: {
...instancePush?.alerts[alert],
value: !instancePush?.alerts[alert].value
}
}
})
)
}
/>
))
: null
}, [pushEnabled, instancePush?.global, instancePush?.alerts, isLoading])
return (
<ScrollView>
{pushEnabled === false ? (
<MenuContainer>
<Button
type='text'
content={
pushCanAskAgain
? t('me.push.enable.direct')
: t('me.push.enable.settings')
}
style={{
marginTop: StyleConstants.Spacing.Global.PagePadding,
marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2
}}
onPress={async () => {
if (pushCanAskAgain) {
const result = await Notifications.requestPermissionsAsync()
setPushEnabled(result.granted)
setPushCanAskAgain(result.canAskAgain)
} else {
Linking.openSettings()
}
}}
/>
</MenuContainer>
) : null}
<MenuContainer>
<MenuRow
title={t('me.push.global.heading', {
acct: `@${instanceAccount?.acct}@${instanceUri}`
})}
description={t('me.push.global.description')}
loading={instancePush?.global.loading}
switchDisabled={!pushEnabled || isLoading}
switchValue={
pushEnabled === false ? false : instancePush?.global.value
}
switchOnValueChange={() =>
dispatch(updateInstancePush(!instancePush?.global.value))
}
/>
</MenuContainer>
<MenuContainer>
<MenuRow
title={t('me.push.decode.heading')}
description={t('me.push.decode.description')}
loading={instancePush?.decode.loading}
switchDisabled={
!pushEnabled || !instancePush?.global.value || isLoading
}
switchValue={instancePush?.decode.value}
switchOnValueChange={() =>
dispatch(updateInstancePushDecode(!instancePush?.decode.value))
}
/>
<MenuRow
title={t('me.push.howitworks')}
iconBack='ExternalLink'
onPress={() =>
WebBrowser.openBrowserAsync('https://tooot.app/how-push-works')
}
/>
</MenuContainer>
<MenuContainer>{alerts}</MenuContainer>
</ScrollView>
)
}
export default TabMePushRoot

View File

@ -5,10 +5,10 @@ import {
} from '@utils/slices/settingsSlice' } from '@utils/slices/settingsSlice'
import { StyleConstants } from '@utils/styles/constants' import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import * as Updates from 'expo-updates'
import React from 'react' import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { StyleSheet, Text } from 'react-native' import { StyleSheet, Text } from 'react-native'
import { Constants } from 'react-native-unimodules'
import { useDispatch, useSelector } from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
const SettingsAnalytics: React.FC = () => { const SettingsAnalytics: React.FC = () => {
@ -29,7 +29,10 @@ const SettingsAnalytics: React.FC = () => {
} }
/> />
<Text style={[styles.version, { color: theme.secondary }]}> <Text style={[styles.version, { color: theme.secondary }]}>
{t('me.settings.version', { version: Constants.manifest.version })} {t('me.settings.version', {
// @ts-ignore
version: Updates.manifest?.version
})}
</Text> </Text>
</MenuContainer> </MenuContainer>
) )

View File

@ -1,47 +1,139 @@
import { HeaderCenter, HeaderLeft } from '@components/Header' import analytics from '@components/analytics'
import { StackScreenProps } from '@react-navigation/stack' import Button from '@components/Button'
import React from 'react' import haptics from '@components/haptics'
import ComponentInstance from '@components/Instance'
import { useNavigation } from '@react-navigation/native'
import {
getInstanceActive,
getInstances,
Instance,
updateInstanceActive
} from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useRef } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { KeyboardAvoidingView, Platform } from 'react-native' import { StyleSheet, Text, View } from 'react-native'
import { createNativeStackNavigator } from 'react-native-screens/native-stack' import { ScrollView } from 'react-native-gesture-handler'
import TabMeSwitchRoot from './Switch/Root' import { useQueryClient } from 'react-query'
import { useDispatch, useSelector } from 'react-redux'
const Stack = createNativeStackNavigator() interface Props {
instance: Instance
selected?: boolean
}
const AccountButton: React.FC<Props> = ({ instance, selected = false }) => {
const queryClient = useQueryClient()
const navigation = useNavigation()
const dispatch = useDispatch()
const TabMeSwitch: React.FC<StackScreenProps<
Nav.TabMeStackParamList,
'Tab-Me-Switch'
>> = ({ navigation }) => {
const { t } = useTranslation('screenTabs')
return ( return (
<KeyboardAvoidingView <Button
style={{ flex: 1 }} type='text'
behavior={Platform.OS === 'ios' ? 'padding' : 'height'} selected={selected}
> style={styles.button}
<Stack.Navigator content={`@${instance.account.acct}@${instance.uri}${
screenOptions={{ headerHideShadow: true, headerTopInsetEnabled: false }} selected ? ' ✓' : ''
> }`}
<Stack.Screen onPress={() => {
name='Screen-Me-Switch-Root' haptics('Light')
component={TabMeSwitchRoot} analytics('switch_existing_press')
options={{ dispatch(updateInstanceActive(instance))
headerTitle: t('me.stacks.switch.name'), queryClient.clear()
...(Platform.OS === 'android' && { navigation.goBack()
headerCenter: () => ( }}
<HeaderCenter content={t('me.stacks.switch.name')} /> />
)
}),
headerLeft: () => (
<HeaderLeft
content='ChevronDown'
onPress={() => navigation.goBack()}
/>
)
}}
/>
</Stack.Navigator>
</KeyboardAvoidingView>
) )
} }
const TabMeSwitch: React.FC = () => {
const { t } = useTranslation('screenTabs')
const { theme } = useTheme()
const instances = useSelector(getInstances, () => true)
const instanceActive = useSelector(getInstanceActive, () => true)
const scrollViewRef = useRef<ScrollView>(null)
return (
<ScrollView
ref={scrollViewRef}
style={styles.base}
keyboardShouldPersistTaps='always'
>
<View style={[styles.firstSection, { borderBottomColor: theme.border }]}>
<Text style={[styles.header, { color: theme.primaryDefault }]}>
{t('me.switch.existing')}
</Text>
<View style={styles.accountButtons}>
{instances.length
? instances
.slice()
.sort((a, b) =>
`${a.uri}${a.account.acct}`.localeCompare(
`${b.uri}${b.account.acct}`
)
)
.map((instance, index) => {
const localAccount = instances[instanceActive!]
return (
<AccountButton
key={index}
instance={instance}
selected={
instance.url === localAccount.url &&
instance.token === localAccount.token &&
instance.account.id === localAccount.account.id
}
/>
)
})
: null}
</View>
</View>
<View style={styles.secondSection}>
<Text style={[styles.header, { color: theme.primaryDefault }]}>
{t('me.switch.new')}
</Text>
<ComponentInstance
scrollViewRef={scrollViewRef}
disableHeaderImage
goBack
/>
</View>
</ScrollView>
)
}
const styles = StyleSheet.create({
base: {
marginBottom: StyleConstants.Spacing.L
},
header: {
...StyleConstants.FontStyle.M,
textAlign: 'center',
paddingVertical: StyleConstants.Spacing.S
},
firstSection: {
marginTop: StyleConstants.Spacing.S,
marginHorizontal: StyleConstants.Spacing.Global.PagePadding,
paddingBottom: StyleConstants.Spacing.S,
borderBottomWidth: StyleSheet.hairlineWidth
},
secondSection: {
paddingTop: StyleConstants.Spacing.M
},
accountButtons: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
marginTop: StyleConstants.Spacing.M
},
button: {
marginBottom: StyleConstants.Spacing.M,
marginRight: StyleConstants.Spacing.M
}
})
export default TabMeSwitch export default TabMeSwitch

View File

@ -1,139 +0,0 @@
import analytics from '@components/analytics'
import Button from '@components/Button'
import haptics from '@components/haptics'
import ComponentInstance from '@components/Instance'
import { useNavigation } from '@react-navigation/native'
import {
getInstanceActive,
getInstances,
Instance,
updateInstanceActive
} from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { StyleSheet, Text, View } from 'react-native'
import { ScrollView } from 'react-native-gesture-handler'
import { useQueryClient } from 'react-query'
import { useDispatch, useSelector } from 'react-redux'
interface Props {
instance: Instance
selected?: boolean
}
const AccountButton: React.FC<Props> = ({ instance, selected = false }) => {
const queryClient = useQueryClient()
const navigation = useNavigation()
const dispatch = useDispatch()
return (
<Button
type='text'
selected={selected}
style={styles.button}
content={`@${instance.account.acct}@${instance.uri}${
selected ? ' ✓' : ''
}`}
onPress={() => {
haptics('Light')
analytics('switch_existing_press')
dispatch(updateInstanceActive(instance))
queryClient.clear()
navigation.goBack()
}}
/>
)
}
const TabMeSwitchRoot: React.FC = () => {
const { t } = useTranslation('screenTabs')
const { theme } = useTheme()
const instances = useSelector(getInstances, () => true)
const instanceActive = useSelector(getInstanceActive, () => true)
const scrollViewRef = useRef<ScrollView>(null)
return (
<ScrollView
ref={scrollViewRef}
style={styles.base}
keyboardShouldPersistTaps='always'
>
<View style={[styles.firstSection, { borderBottomColor: theme.border }]}>
<Text style={[styles.header, { color: theme.primaryDefault }]}>
{t('me.switch.existing')}
</Text>
<View style={styles.accountButtons}>
{instances.length
? instances
.slice()
.sort((a, b) =>
`${a.uri}${a.account.acct}`.localeCompare(
`${b.uri}${b.account.acct}`
)
)
.map((instance, index) => {
const localAccount = instances[instanceActive!]
return (
<AccountButton
key={index}
instance={instance}
selected={
instance.url === localAccount.url &&
instance.token === localAccount.token &&
instance.account.id === localAccount.account.id
}
/>
)
})
: null}
</View>
</View>
<View style={styles.secondSection}>
<Text style={[styles.header, { color: theme.primaryDefault }]}>
{t('me.switch.new')}
</Text>
<ComponentInstance
scrollViewRef={scrollViewRef}
disableHeaderImage
goBack
/>
</View>
</ScrollView>
)
}
const styles = StyleSheet.create({
base: {
marginBottom: StyleConstants.Spacing.L
},
header: {
...StyleConstants.FontStyle.M,
textAlign: 'center',
paddingVertical: StyleConstants.Spacing.S
},
firstSection: {
marginTop: StyleConstants.Spacing.S,
marginHorizontal: StyleConstants.Spacing.Global.PagePadding,
paddingBottom: StyleConstants.Spacing.S,
borderBottomWidth: StyleSheet.hairlineWidth
},
secondSection: {
paddingTop: StyleConstants.Spacing.M
},
accountButtons: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
marginTop: StyleConstants.Spacing.M
},
button: {
marginBottom: StyleConstants.Spacing.M,
marginRight: StyleConstants.Spacing.M
}
})
export default TabMeSwitchRoot

View File

@ -14,11 +14,11 @@ import { debounce } from 'lodash'
import React from 'react' import React from 'react'
import { Trans, useTranslation } from 'react-i18next' import { Trans, useTranslation } from 'react-i18next'
import { Platform, StyleSheet, Text, TextInput, View } from 'react-native' import { Platform, StyleSheet, Text, TextInput, View } from 'react-native'
import { NativeStackNavigationOptions } from 'react-native-screens/lib/typescript' import { NativeStackNavigationOptions } from 'react-native-screens/lib/typescript/native-stack'
import { import {
NativeStackNavigationEventMap, NativeStackNavigationEventMap,
NativeStackNavigatorProps NativeStackNavigatorProps
} from 'react-native-screens/lib/typescript/types' } from 'react-native-screens/lib/typescript/native-stack/types'
export type BaseScreens = export type BaseScreens =
| Nav.TabLocalStackParamList | Nav.TabLocalStackParamList
@ -150,17 +150,13 @@ const sharedScreens = (
<View style={styles.searchBar}> <View style={styles.searchBar}>
<TextInput <TextInput
editable={false} editable={false}
children={ style={[
<Text styles.textInput,
style={[ {
styles.textInput, color: theme.primaryDefault
{ }
color: theme.primaryDefault ]}
} defaultValue={t('shared.search.header.prefix')}
]}
children={t('shared.search.header.prefix')}
/>
}
/> />
<TextInput <TextInput
accessibilityRole='search' accessibilityRole='search'

View File

@ -1,12 +1,12 @@
import * as Updates from 'expo-updates' import * as Updates from 'expo-updates'
import { Constants } from 'react-native-unimodules'
import * as Sentry from 'sentry-expo' import * as Sentry from 'sentry-expo'
import log from './log' import log from './log'
const sentry = () => { const sentry = () => {
log('log', 'Sentry', 'initializing') log('log', 'Sentry', 'initializing')
Sentry.init({ Sentry.init({
dsn: Constants.manifest.extra?.sentryDSN, // @ts-ignore
dsn: Updates.manifest?.extra?.sentryDSN,
enableInExpoDevelopment: false, enableInExpoDevelopment: false,
debug: debug:
__DEV__ || __DEV__ ||

View File

@ -1,7 +1,7 @@
import apiGeneral from '@api/general'
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit' import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import { RootState } from '@root/store' import { RootState } from '@root/store'
import apiGeneral from '@api/general' import * as Updates from 'expo-updates'
import { Constants } from 'react-native-unimodules'
export const retriveVersionLatest = createAsyncThunk( export const retriveVersionLatest = createAsyncThunk(
'version/latest', 'version/latest',
@ -29,8 +29,10 @@ const versionSlice = createSlice({
reducers: {}, reducers: {},
extraReducers: builder => { extraReducers: builder => {
builder.addCase(retriveVersionLatest.fulfilled, (state, action) => { builder.addCase(retriveVersionLatest.fulfilled, (state, action) => {
if (action.payload && Constants.manifest.version) { // @ts-ignore
if (parseInt(action.payload) > parseInt(Constants.manifest.version)) { if (action.payload && Updates.manifest?.version) {
// @ts-ignore
if (parseInt(action.payload) > parseInt(Updates.manifest.version)) {
state.update = true state.update = true
} }
} }