1
0
mirror of https://github.com/tooot-app/app synced 2025-06-05 22:19:13 +02:00

Lots of updates

This commit is contained in:
Zhiyuan Zheng
2021-01-10 02:12:14 +01:00
parent 4a6229514f
commit 541e2a5601
28 changed files with 1001 additions and 530 deletions

View File

@ -58,7 +58,7 @@ const Button: React.FC<Props> = ({
} else {
mounted.current = true
}
}, [content, loading, disabled])
}, [content, loading, disabled, active])
const loadingSpinkit = useMemo(
() => (

View File

@ -5,15 +5,19 @@ import { useNavigation } from '@react-navigation/native'
import hookApps from '@utils/queryHooks/apps'
import hookInstance from '@utils/queryHooks/instance'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import { InstanceLocal, remoteUpdate } from '@utils/slices/instancesSlice'
import {
getLocalInstances,
InstanceLocal,
remoteUpdate
} from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import { debounce } from 'lodash'
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Image, StyleSheet, Text, TextInput, View } from 'react-native'
import { Alert, Image, StyleSheet, Text, TextInput, View } from 'react-native'
import { useQueryClient } from 'react-query'
import { useDispatch } from 'react-redux'
import { useDispatch, useSelector } from 'react-redux'
import InstanceAuth from './Instance/Auth'
import InstanceInfo from './Instance/Info'
import { toast } from './toast'
@ -36,6 +40,7 @@ const ComponentInstance: React.FC<Props> = ({
const { theme } = useTheme()
const [instanceDomain, setInstanceDomain] = useState<string | undefined>()
const [appData, setApplicationData] = useState<InstanceLocal['appData']>()
const localInstances = useSelector(getLocalInstances)
const instanceQuery = hookInstance({
instanceDomain,
@ -79,12 +84,32 @@ const ComponentInstance: React.FC<Props> = ({
const processUpdate = useCallback(() => {
if (instanceDomain) {
haptics('Success')
switch (type) {
case 'local':
applicationQuery.refetch()
return
if (
localInstances &&
localInstances.filter(instance => instance.url === instanceDomain)
.length
) {
Alert.alert(
'域名已存在',
'可以登录同个域名的另外一个账户,现有账户🈚️用',
[
{ text: '取消', style: 'cancel' },
{
text: '继续',
onPress: () => {
applicationQuery.refetch()
}
}
]
)
} else {
applicationQuery.refetch()
}
break
case 'remote':
haptics('Success')
const queryKey: QueryKeyTimeline = [
'Timeline',
{ page: 'RemotePublic' }
@ -92,8 +117,8 @@ const ComponentInstance: React.FC<Props> = ({
dispatch(remoteUpdate(instanceDomain))
queryClient.resetQueries(queryKey)
toast({ type: 'success', message: '重置成功' })
navigation.navigate('Screen-Remote-Root')
return
navigation.navigate('Screen-Public', { screen: 'Screen-Public-Root' })
break
}
}
}, [instanceDomain])
@ -160,7 +185,7 @@ const ComponentInstance: React.FC<Props> = ({
content={buttonContent}
onPress={processUpdate}
disabled={!instanceQuery.data?.uri}
loading={instanceQuery.isFetching || applicationQuery.isFetching}
loading={instanceQuery.isLoading || applicationQuery.isLoading}
/>
</View>
<View>

View File

@ -1,12 +1,12 @@
import Icon from '@components/Icon'
import openLink from '@components/openLink'
import ParseEmojis from '@components/Parse/Emojis'
import { useNavigation } from '@react-navigation/native'
import { useNavigation, useRoute } from '@react-navigation/native'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import { LinearGradient } from 'expo-linear-gradient'
import React, { useCallback, useState } from 'react'
import { Image, Pressable, Text, View } from 'react-native'
import { Pressable, Text, View } from 'react-native'
import HTMLView from 'react-native-htmlview'
import Animated, {
useAnimatedStyle,
@ -16,6 +16,7 @@ import Animated, {
// Prevent going to the same hashtag multiple times
const renderNode = ({
routeParams,
theme,
node,
index,
@ -26,6 +27,7 @@ const renderNode = ({
showFullLink,
disableDetails
}: {
routeParams?: any
theme: any
node: any
index: number
@ -42,6 +44,10 @@ const renderNode = ({
const href = node.attribs.href
if (classes) {
if (classes.includes('hashtag')) {
const tag = href.split(new RegExp(/\/tag\/(.*)|\/tags\/(.*)/))
const differentTag = routeParams?.hashtag
? routeParams.hashtag !== tag[1] && routeParams.hashtag !== tag[2]
: true
return (
<Text
key={index}
@ -50,8 +56,8 @@ const renderNode = ({
...StyleConstants.FontStyle[size]
}}
onPress={() => {
const tag = href.split(new RegExp(/\/tag\/(.*)|\/tags\/(.*)/))
!disableDetails &&
differentTag &&
navigation.push('Screen-Shared-Hashtag', {
hashtag: tag[1] || tag[2]
})
@ -65,6 +71,9 @@ const renderNode = ({
const accountIndex = mentions.findIndex(
mention => mention.url === href
)
const differentAccount = routeParams?.account
? routeParams.account.id !== mentions[accountIndex].id
: true
return (
<Text
key={index}
@ -75,6 +84,7 @@ const renderNode = ({
onPress={() => {
accountIndex !== -1 &&
!disableDetails &&
differentAccount &&
navigation.push('Screen-Shared-Account', {
account: mentions[accountIndex]
})
@ -151,11 +161,13 @@ const ParseHTML: React.FC<Props> = ({
disableDetails = false
}) => {
const navigation = useNavigation()
const route = useRoute()
const { theme } = useTheme()
const renderNodeCallback = useCallback(
(node, index) =>
renderNode({
routeParams: route.params,
theme,
node,
index,

View File

@ -2,6 +2,7 @@ import client from '@api/client'
import Button from '@components/Button'
import haptics from '@components/haptics'
import { toast } from '@components/toast'
import { QueryKeyRelationship } from '@utils/queryHooks/relationship'
import { StyleConstants } from '@utils/styles/constants'
import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
@ -15,7 +16,7 @@ export interface Props {
const RelationshipIncoming: React.FC<Props> = ({ id }) => {
const { t } = useTranslation()
const relationshipQueryKey = ['Relationship', { id }]
const queryKeyRelationship: QueryKeyRelationship = ['Relationship', { id }]
const queryClient = useQueryClient()
const fireMutation = useCallback(
@ -31,7 +32,7 @@ const RelationshipIncoming: React.FC<Props> = ({ id }) => {
const mutation = useMutation(fireMutation, {
onSuccess: res => {
haptics('Success')
queryClient.setQueryData(relationshipQueryKey, res)
queryClient.setQueryData(queryKeyRelationship, res)
queryClient.refetchQueries(['Notifications'])
},
onError: (err: any, { type }) => {

View File

@ -2,7 +2,9 @@ import client from '@api/client'
import Button from '@components/Button'
import haptics from '@components/haptics'
import { toast } from '@components/toast'
import hookRelationship from '@utils/queryHooks/relationship'
import hookRelationship, {
QueryKeyRelationship
} from '@utils/queryHooks/relationship'
import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { useMutation, useQueryClient } from 'react-query'
@ -14,7 +16,7 @@ export interface Props {
const RelationshipOutgoing: React.FC<Props> = ({ id }) => {
const { t } = useTranslation()
const relationshipQueryKey = ['Relationship', { id }]
const queryKeyRelationship: QueryKeyRelationship = ['Relationship', { id }]
const query = hookRelationship({ id })
const queryClient = useQueryClient()
@ -31,7 +33,7 @@ const RelationshipOutgoing: React.FC<Props> = ({ id }) => {
const mutation = useMutation(fireMutation, {
onSuccess: res => {
haptics('Success')
queryClient.setQueryData(relationshipQueryKey, res)
queryClient.setQueryData(queryKeyRelationship, res)
},
onError: (err: any, { type }) => {
haptics('Error')

View File

@ -16,11 +16,12 @@ const Stack = createNativeStackNavigator<
>()
export interface Props {
name: 'Screen-Local-Root' | 'Screen-Public-Root'
content: { title: string; page: App.Pages }[]
name: 'Local' | 'Public'
content: { title: string; page: App.Pages; remote?: boolean }[]
}
const Timelines: React.FC<Props> = ({ name, content }) => {
const remoteUrl = useSelector(getRemoteUrl)
const navigation = useNavigation()
const { mode } = useTheme()
const localActiveIndex = useSelector(getLocalActiveIndex)
@ -71,16 +72,19 @@ const Timelines: React.FC<Props> = ({ name, content }) => {
<Stack.Navigator screenOptions={{ headerHideShadow: true }}>
<Stack.Screen
// @ts-ignore
name={name}
name={`Screen-${name}-Root`}
component={screenComponent}
options={{
headerTitle: name === 'Screen-Public-Root' ? publicDomain : '',
headerTitle: name === 'Public' ? publicDomain : '',
...(localActiveIndex !== null && {
headerCenter: () => (
<View style={styles.segmentsContainer}>
<SegmentedControl
appearance={mode}
values={[content[0].title, content[1].title]}
values={[
content[0].title,
content[1].remote ? remoteUrl : content[1].title
]}
selectedIndex={segment}
onChange={({ nativeEvent }) =>
setSegment(nativeEvent.selectedSegmentIndex)
@ -102,7 +106,7 @@ const Timelines: React.FC<Props> = ({ name, content }) => {
const styles = StyleSheet.create({
segmentsContainer: {
flexBasis: '60%'
flexBasis: '65%'
}
})

View File

@ -16,11 +16,9 @@ const TimelineHeader = React.memo(
{' '}
<Text
style={{ color: theme.blue }}
onPress={() =>
navigation.navigate('Screen-Me', {
screen: 'Screen-Me-Settings-UpdateRemote'
})
}
onPress={() => {
navigation.navigate('Screen-Me')
}}
>
{' '}
<Icon

View File

@ -13,22 +13,14 @@ export interface Props {
const TimelineCard: React.FC<Props> = ({ card }) => {
const { theme } = useTheme()
let isMounted = false
useEffect(() => {
isMounted = true
return () => {
isMounted = false
}
})
const [imageLoaded, setImageLoaded] = useState(false)
useEffect(() => {
const preFetch = () =>
card.image &&
isMounted &&
Image.getSize(card.image, () => isMounted && setImageLoaded(true))
preFetch()
}, [isMounted])
const preFetch = () => Image.getSize(card.image, () => setImageLoaded(true))
if (card.image) {
preFetch()
}
}, [])
const cardVisual = useMemo(() => {
if (imageLoaded) {
return <Image source={{ uri: card.image }} style={styles.image} />
@ -45,12 +37,18 @@ const TimelineCard: React.FC<Props> = ({ card }) => {
<Pressable
style={[styles.card, { borderColor: theme.border }]}
onPress={async () => await openLink(card.url)}
testID='base'
>
{card.image && <View style={styles.left}>{cardVisual}</View>}
{card.image && (
<View style={styles.left} testID='image'>
{cardVisual}
</View>
)}
<View style={styles.right}>
<Text
numberOfLines={2}
style={[styles.rightTitle, { color: theme.primary }]}
testID='title'
>
{card.title}
</Text>
@ -58,6 +56,7 @@ const TimelineCard: React.FC<Props> = ({ card }) => {
<Text
numberOfLines={1}
style={[styles.rightDescription, { color: theme.primary }]}
testID='description'
>
{card.description}
</Text>