mirror of
https://github.com/tooot-app/app
synced 2025-04-25 07:28:41 +02:00
Updates
This commit is contained in:
parent
17f15a199c
commit
83048450e8
@ -9,9 +9,18 @@ import * as WebBrowser from 'expo-web-browser'
|
||||
import { debounce } from 'lodash'
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Alert, Image, StyleSheet, Text, TextInput, View } from 'react-native'
|
||||
import {
|
||||
Alert,
|
||||
Image,
|
||||
KeyboardAvoidingView,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TextInput,
|
||||
View
|
||||
} from 'react-native'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { Placeholder, Fade } from 'rn-placeholder'
|
||||
import { Placeholder } from 'rn-placeholder'
|
||||
import analytics from './analytics'
|
||||
import InstanceAuth from './Instance/Auth'
|
||||
import InstanceInfo from './Instance/Info'
|
||||
@ -115,7 +124,10 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
}, [domain, instanceQuery.data, appsQuery.data])
|
||||
|
||||
return (
|
||||
<>
|
||||
<KeyboardAvoidingView
|
||||
style={{ flex: 1 }}
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
>
|
||||
{!disableHeaderImage ? (
|
||||
<View style={styles.imageContainer}>
|
||||
<Image
|
||||
@ -157,18 +169,8 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
</View>
|
||||
|
||||
<View>
|
||||
<Placeholder
|
||||
{...(instanceQuery.isFetching && {
|
||||
Animation: props => (
|
||||
<Fade
|
||||
{...props}
|
||||
style={{ backgroundColor: theme.shimmerHighlight }}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
>
|
||||
<Placeholder>
|
||||
<InstanceInfo
|
||||
visible={instanceQuery.data?.title !== undefined}
|
||||
header={t('server.information.name')}
|
||||
content={instanceQuery.data?.title || undefined}
|
||||
potentialWidth={2}
|
||||
@ -176,7 +178,6 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
<View style={styles.instanceStats}>
|
||||
<InstanceInfo
|
||||
style={styles.stat1}
|
||||
visible={instanceQuery.data?.stats?.user_count !== undefined}
|
||||
header={t('server.information.accounts')}
|
||||
content={
|
||||
instanceQuery.data?.stats?.user_count?.toString() || undefined
|
||||
@ -185,7 +186,6 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
/>
|
||||
<InstanceInfo
|
||||
style={styles.stat2}
|
||||
visible={instanceQuery.data?.stats?.status_count !== undefined}
|
||||
header={t('server.information.statuses')}
|
||||
content={
|
||||
instanceQuery.data?.stats?.status_count?.toString() ||
|
||||
@ -195,7 +195,6 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
/>
|
||||
<InstanceInfo
|
||||
style={styles.stat3}
|
||||
visible={instanceQuery.data?.stats?.domain_count !== undefined}
|
||||
header={t('server.information.domains')}
|
||||
content={
|
||||
instanceQuery.data?.stats?.domain_count?.toString() ||
|
||||
@ -231,7 +230,7 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
</View>
|
||||
|
||||
{requestAuth}
|
||||
</>
|
||||
</KeyboardAvoidingView>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,62 +0,0 @@
|
||||
import analytics from '@components/analytics'
|
||||
import Icon from '@components/Icon'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import * as WebBrowser from 'expo-web-browser'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Pressable, StyleSheet, Text } from 'react-native'
|
||||
|
||||
export interface Props {
|
||||
agreed: boolean
|
||||
setAgreed: React.Dispatch<React.SetStateAction<boolean>>
|
||||
}
|
||||
|
||||
const EULA = React.memo(
|
||||
({ agreed, setAgreed }: Props) => {
|
||||
const { t } = useTranslation('componentInstance')
|
||||
const { theme } = useTheme()
|
||||
|
||||
return (
|
||||
<Pressable style={styles.base} onPress={() => setAgreed(!agreed)}>
|
||||
<Icon
|
||||
style={styles.icon}
|
||||
name={agreed ? 'CheckCircle' : 'Circle'}
|
||||
size={StyleConstants.Font.Size.M}
|
||||
color={theme.primary}
|
||||
/>
|
||||
<Text style={[styles.text, { color: theme.primary }]}>
|
||||
{t('server.EULA.base')}
|
||||
<Text
|
||||
style={{ color: theme.blue }}
|
||||
children={t('server.EULA.EULA')}
|
||||
onPress={() => {
|
||||
analytics('view_EULA')
|
||||
WebBrowser.openBrowserAsync(
|
||||
'https://tooot.app/end-user-license-agreement'
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</Text>
|
||||
</Pressable>
|
||||
)
|
||||
},
|
||||
(prev, next) => prev.agreed === next.agreed
|
||||
)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
flexDirection: 'row',
|
||||
marginTop: StyleConstants.Spacing.M,
|
||||
paddingHorizontal: StyleConstants.Spacing.Global.PagePadding,
|
||||
alignItems: 'center'
|
||||
},
|
||||
icon: {
|
||||
marginRight: StyleConstants.Spacing.XS
|
||||
},
|
||||
text: {
|
||||
...StyleConstants.FontStyle.S
|
||||
}
|
||||
})
|
||||
|
||||
export default EULA
|
@ -8,15 +8,13 @@ import { PlaceholderLine } from 'rn-placeholder'
|
||||
|
||||
export interface Props {
|
||||
style?: ViewStyle
|
||||
visible: boolean
|
||||
header: string
|
||||
content?: string
|
||||
potentialWidth?: number
|
||||
potentialLines?: number
|
||||
}
|
||||
|
||||
const InstanceInfo = React.memo(
|
||||
({ style, header, content, potentialWidth, potentialLines = 1 }: Props) => {
|
||||
({ style, header, content, potentialWidth }: Props) => {
|
||||
const { t } = useTranslation('componentInstance')
|
||||
const { theme } = useTheme()
|
||||
|
||||
@ -31,9 +29,7 @@ const InstanceInfo = React.memo(
|
||||
expandHint={t('server.information.description.expandHint')}
|
||||
/>
|
||||
) : (
|
||||
Array.from(Array(potentialLines)).map((_, i) => (
|
||||
<PlaceholderLine
|
||||
key={i}
|
||||
width={
|
||||
potentialWidth
|
||||
? potentialWidth * StyleConstants.Font.Size.M
|
||||
@ -44,11 +40,11 @@ const InstanceInfo = React.memo(
|
||||
noMargin
|
||||
style={{ borderRadius: 0 }}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
},
|
||||
(prev, next) => prev.content === next.content
|
||||
)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
@ -41,7 +41,7 @@ const TimelineDefault: React.FC<Props> = ({
|
||||
pinned
|
||||
}) => {
|
||||
const { theme } = useTheme()
|
||||
const instanceAccount = useSelector(getInstanceAccount, (prev, next) => true)
|
||||
const instanceAccount = useSelector(getInstanceAccount, () => true)
|
||||
const navigation = useNavigation<
|
||||
StackNavigationProp<Nav.TabLocalStackParamList>
|
||||
>()
|
||||
|
@ -103,7 +103,7 @@ const TimelineRefresh: React.FC<Props> = ({
|
||||
queryClient.setQueryData<InfiniteData<TimelineData> | undefined>(
|
||||
queryKey,
|
||||
data => {
|
||||
if (data?.pages[0].body.length === 0) {
|
||||
if (data?.pages[0] && data.pages[0].body.length === 0) {
|
||||
return {
|
||||
pages: data.pages.slice(1),
|
||||
pageParams: data.pageParams.slice(1)
|
||||
|
@ -22,13 +22,8 @@ export interface Props {
|
||||
reblog: boolean
|
||||
}
|
||||
|
||||
const TimelineActions: React.FC<Props> = ({
|
||||
queryKey,
|
||||
rootQueryKey,
|
||||
status,
|
||||
accts,
|
||||
reblog
|
||||
}) => {
|
||||
const TimelineActions = React.memo(
|
||||
({ queryKey, rootQueryKey, status, accts, reblog }: Props) => {
|
||||
const navigation = useNavigation()
|
||||
const { t } = useTranslation('componentTimeline')
|
||||
const { mode, theme } = useTheme()
|
||||
@ -292,7 +287,9 @@ const TimelineActions: React.FC<Props> = ({
|
||||
</View>
|
||||
</>
|
||||
)
|
||||
}
|
||||
},
|
||||
() => true
|
||||
)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
actions: {
|
||||
|
@ -15,15 +15,17 @@ import { useQueryClient } from 'react-query'
|
||||
import HeaderSharedCreated from './HeaderShared/Created'
|
||||
import HeaderSharedMuted from './HeaderShared/Muted'
|
||||
|
||||
const Names: React.FC<{ accounts: Mastodon.Account[] }> = ({ accounts }) => {
|
||||
const Names = React.memo(
|
||||
({ accounts }: { accounts: Mastodon.Account[] }) => {
|
||||
const { t } = useTranslation('componentTimeline')
|
||||
const { theme } = useTheme()
|
||||
|
||||
return (
|
||||
<Text numberOfLines={1}>
|
||||
<Text style={[styles.namesLeading, { color: theme.secondary }]}>
|
||||
{t('shared.header.conversation.withAccounts')}
|
||||
</Text>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={[styles.namesLeading, { color: theme.secondary }]}
|
||||
>
|
||||
<Text>{t('shared.header.conversation.withAccounts')}</Text>
|
||||
{accounts.map((account, index) => (
|
||||
<Text key={account.id} numberOfLines={1}>
|
||||
{index !== 0 ? t('common:separator') : undefined}
|
||||
@ -36,7 +38,9 @@ const Names: React.FC<{ accounts: Mastodon.Account[] }> = ({ accounts }) => {
|
||||
))}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
},
|
||||
() => true
|
||||
)
|
||||
|
||||
export interface Props {
|
||||
queryKey: QueryKeyTimeline
|
||||
|
@ -9,10 +9,8 @@ export interface Props {
|
||||
withoutName?: boolean // For notification follow request etc.
|
||||
}
|
||||
|
||||
const HeaderSharedAccount: React.FC<Props> = ({
|
||||
account,
|
||||
withoutName = false
|
||||
}) => {
|
||||
const HeaderSharedAccount = React.memo(
|
||||
({ account, withoutName = false }: Props) => {
|
||||
const { theme } = useTheme()
|
||||
|
||||
return (
|
||||
@ -26,12 +24,17 @@ const HeaderSharedAccount: React.FC<Props> = ({
|
||||
/>
|
||||
</Text>
|
||||
)}
|
||||
<Text style={[styles.acct, { color: theme.secondary }]} numberOfLines={1}>
|
||||
<Text
|
||||
style={[styles.acct, { color: theme.secondary }]}
|
||||
numberOfLines={1}
|
||||
>
|
||||
@{account.acct}
|
||||
</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
},
|
||||
() => true
|
||||
)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
|
@ -10,7 +10,8 @@ export interface Props {
|
||||
application?: Mastodon.Application
|
||||
}
|
||||
|
||||
const HeaderSharedApplication: React.FC<Props> = ({ application }) => {
|
||||
const HeaderSharedApplication = React.memo(
|
||||
({ application }: Props) => {
|
||||
const { theme } = useTheme()
|
||||
const { t } = useTranslation('componentTimeline')
|
||||
|
||||
@ -24,10 +25,14 @@ const HeaderSharedApplication: React.FC<Props> = ({ application }) => {
|
||||
}}
|
||||
style={[styles.application, { color: theme.secondary }]}
|
||||
>
|
||||
{t('shared.header.shared.application', { application: application.name })}
|
||||
{t('shared.header.shared.application', {
|
||||
application: application.name
|
||||
})}
|
||||
</Text>
|
||||
) : null
|
||||
}
|
||||
},
|
||||
() => true
|
||||
)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
application: {
|
||||
|
@ -8,7 +8,8 @@ export interface Props {
|
||||
muted?: Mastodon.Status['muted']
|
||||
}
|
||||
|
||||
const HeaderSharedMuted: React.FC<Props> = ({ muted }) => {
|
||||
const HeaderSharedMuted = React.memo(
|
||||
({ muted }: Props) => {
|
||||
const { theme } = useTheme()
|
||||
|
||||
return muted ? (
|
||||
@ -19,7 +20,9 @@ const HeaderSharedMuted: React.FC<Props> = ({ muted }) => {
|
||||
style={styles.visibility}
|
||||
/>
|
||||
) : null
|
||||
}
|
||||
},
|
||||
() => true
|
||||
)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
visibility: {
|
||||
|
@ -8,7 +8,8 @@ export interface Props {
|
||||
visibility: Mastodon.Status['visibility']
|
||||
}
|
||||
|
||||
const HeaderSharedVisibility: React.FC<Props> = ({ visibility }) => {
|
||||
const HeaderSharedVisibility = React.memo(
|
||||
({ visibility }: Props) => {
|
||||
const { theme } = useTheme()
|
||||
|
||||
switch (visibility) {
|
||||
@ -33,7 +34,9 @@ const HeaderSharedVisibility: React.FC<Props> = ({ visibility }) => {
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
},
|
||||
() => true
|
||||
)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
visibility: {
|
||||
|
@ -353,7 +353,7 @@ const ScreenCompose: React.FC<ScreenComposeProp> = ({
|
||||
<Stack.Screen
|
||||
name='Screen-Compose-DraftsList'
|
||||
component={ComposeDraftsList}
|
||||
options={{ stackPresentation: 'modal' }}
|
||||
options={{ stackPresentation: 'modal', headerShown: false }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name='Screen-Compose-EditAttachment'
|
||||
|
@ -1,7 +1,8 @@
|
||||
import Timeline from '@components/Timeline'
|
||||
import TimelineDefault from '@components/Timeline/Default'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
import React from 'react'
|
||||
import React, { useCallback } from 'react'
|
||||
|
||||
const ScreenMeListsList: React.FC<StackScreenProps<
|
||||
Nav.TabMeStackParamList,
|
||||
@ -12,8 +13,12 @@ const ScreenMeListsList: React.FC<StackScreenProps<
|
||||
}
|
||||
}) => {
|
||||
const queryKey: QueryKeyTimeline = ['Timeline', { page: 'List', list }]
|
||||
const renderItem = useCallback(
|
||||
({ item }) => <TimelineDefault item={item} queryKey={queryKey} />,
|
||||
[]
|
||||
)
|
||||
|
||||
return <Timeline queryKey={queryKey} />
|
||||
return <Timeline queryKey={queryKey} customProps={{ renderItem }} />
|
||||
}
|
||||
|
||||
export default ScreenMeListsList
|
||||
|
@ -2,7 +2,7 @@ import { HeaderCenter, HeaderLeft } from '@components/Header'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Platform } from 'react-native'
|
||||
import { KeyboardAvoidingView, Platform } from 'react-native'
|
||||
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||
import ScreenMeSwitchRoot from './Switch/Root'
|
||||
|
||||
@ -14,6 +14,10 @@ const ScreenMeSwitch: React.FC<StackScreenProps<
|
||||
>> = ({ navigation }) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<KeyboardAvoidingView
|
||||
style={{ flex: 1 }}
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
>
|
||||
<Stack.Navigator
|
||||
screenOptions={{ headerHideShadow: true, headerTopInsetEnabled: false }}
|
||||
>
|
||||
@ -23,7 +27,9 @@ const ScreenMeSwitch: React.FC<StackScreenProps<
|
||||
options={{
|
||||
headerTitle: t('meSwitch:heading'),
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => <HeaderCenter content={t('meSwitch:heading')} />
|
||||
headerCenter: () => (
|
||||
<HeaderCenter content={t('meSwitch:heading')} />
|
||||
)
|
||||
}),
|
||||
headerLeft: () => (
|
||||
<HeaderLeft
|
||||
@ -34,6 +40,7 @@ const ScreenMeSwitch: React.FC<StackScreenProps<
|
||||
}}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
</KeyboardAvoidingView>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -60,14 +60,8 @@ const ScreenMeSwitchRoot: React.FC = () => {
|
||||
const instanceActive = useSelector(getInstanceActive)
|
||||
|
||||
return (
|
||||
<KeyboardAvoidingView
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
style={{ flex: 1 }}
|
||||
>
|
||||
<ScrollView keyboardShouldPersistTaps='handled'>
|
||||
<View
|
||||
style={[styles.firstSection, { borderBottomColor: theme.border }]}
|
||||
>
|
||||
<ScrollView style={styles.base} keyboardShouldPersistTaps='handled'>
|
||||
<View style={[styles.firstSection, { borderBottomColor: theme.border }]}>
|
||||
<Text style={[styles.header, { color: theme.primary }]}>
|
||||
{t('content.existing')}
|
||||
</Text>
|
||||
@ -105,11 +99,13 @@ const ScreenMeSwitchRoot: React.FC = () => {
|
||||
<ComponentInstance disableHeaderImage goBack />
|
||||
</View>
|
||||
</ScrollView>
|
||||
</KeyboardAvoidingView>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
marginBottom: StyleConstants.Spacing.L
|
||||
},
|
||||
header: {
|
||||
...StyleConstants.FontStyle.M,
|
||||
textAlign: 'center',
|
||||
|
Loading…
x
Reference in New Issue
Block a user