This commit is contained in:
Zhiyuan Zheng 2021-01-12 00:12:44 +01:00
parent 284d6e46e0
commit 2df172d026
No known key found for this signature in database
GPG Key ID: 078A93AB607D85E0
23 changed files with 311 additions and 227 deletions

View File

@ -52,7 +52,7 @@ declare namespace Nav {
} & SharedStackParamList } & SharedStackParamList
type MeStackParamList = { type MeStackParamList = {
'Screen-Me-Root': undefined 'Screen-Me-Root': { navigateAway?: 'Screen-Me-Settings-UpdateRemote' }
'Screen-Me-Bookmarks': undefined 'Screen-Me-Bookmarks': undefined
'Screen-Me-Conversations': undefined 'Screen-Me-Conversations': undefined
'Screen-Me-Favourites': undefined 'Screen-Me-Favourites': undefined

View File

@ -242,13 +242,6 @@ const Index: React.FC<Props> = ({ localCorrupt }) => {
}), }),
[localActiveIndex] [localActiveIndex]
) )
const tabScreenNotificationsOptions = useMemo(
() => ({
tabBarBadge: prevNotification && prevNotification.unread ? '' : undefined
}),
[theme, prevNotification]
)
return ( return (
<> <>
<StatusBar barStyle={barStyle[mode]} /> <StatusBar barStyle={barStyle[mode]} />
@ -280,13 +273,22 @@ const Index: React.FC<Props> = ({ localCorrupt }) => {
name='Screen-Notifications' name='Screen-Notifications'
component={ScreenNotifications} component={ScreenNotifications}
listeners={tabScreenNotificationsListeners} listeners={tabScreenNotificationsListeners}
options={{ options={
tabBarBadgeStyle: { prevNotification && prevNotification.unread
transform: [{ scale: 0.5 }], ? {
backgroundColor: theme.red tabBarBadge: '',
}, tabBarBadgeStyle: {
...tabScreenNotificationsOptions transform: [{ scale: 0.5 }],
}} backgroundColor: theme.red
}
}
: {
tabBarBadgeStyle: {
transform: [{ scale: 0.5 }],
backgroundColor: theme.red
}
}
}
/> />
<Tab.Screen name='Screen-Me' component={ScreenMe} /> <Tab.Screen name='Screen-Me' component={ScreenMe} />
</Tab.Navigator> </Tab.Navigator>

View File

@ -0,0 +1,61 @@
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import React, { useRef } from 'react'
import { RefreshControl } from 'react-native'
import { InfiniteData, useQueryClient } from 'react-query'
export interface Props {
queryKey: QueryKeyTimeline
isFetchingPreviousPage: boolean
isFetching: boolean
fetchPreviousPage: () => void
refetch: () => void
}
const CustomRefreshControl = React.memo(
({
queryKey,
isFetchingPreviousPage,
isFetching,
fetchPreviousPage,
refetch
}: Props) => {
const queryClient = useQueryClient()
const refreshCount = useRef(0)
return (
<RefreshControl
refreshing={
refreshCount.current < 2 ? isFetchingPreviousPage : isFetching
}
onRefresh={async () => {
if (refreshCount.current < 2) {
await fetchPreviousPage()
refreshCount.current++
} else {
queryClient.setQueryData<InfiniteData<any> | undefined>(
queryKey,
data => {
if (data) {
return {
pages: data.pages.slice(1),
pageParams: data.pageParams.slice(1)
}
}
}
)
await refetch()
refreshCount.current = 0
}
}}
/>
)
},
(prev, next) => {
let skipUpdate = true
skipUpdate = prev.isFetchingPreviousPage === next.isFetchingPreviousPage
skipUpdate = prev.isFetching === next.isFetching
return skipUpdate
}
)
export default CustomRefreshControl

View File

@ -3,16 +3,12 @@ import openLink from '@components/openLink'
import ParseEmojis from '@components/Parse/Emojis' import ParseEmojis from '@components/Parse/Emojis'
import { useNavigation, useRoute } from '@react-navigation/native' import { useNavigation, useRoute } from '@react-navigation/native'
import { StyleConstants } from '@utils/styles/constants' import { StyleConstants } from '@utils/styles/constants'
import layoutAnimation from '@utils/styles/layoutAnimation'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import { LinearGradient } from 'expo-linear-gradient' import { LinearGradient } from 'expo-linear-gradient'
import React, { useCallback, useState } from 'react' import React, { useCallback, useState } from 'react'
import { Pressable, Text, View } from 'react-native' import { Pressable, Text, View } from 'react-native'
import HTMLView from 'react-native-htmlview' import HTMLView from 'react-native-htmlview'
import Animated, {
useAnimatedStyle,
useDerivedValue,
withTiming
} from 'react-native-reanimated'
// Prevent going to the same hashtag multiple times // Prevent going to the same hashtag multiple times
const renderNode = ({ const renderNode = ({
@ -197,70 +193,36 @@ const ParseHTML: React.FC<Props> = ({
({ children }) => { ({ children }) => {
const lineHeight = StyleConstants.Font.LineHeight[size] const lineHeight = StyleConstants.Font.LineHeight[size]
const [lines, setLines] = useState<number | undefined>(undefined)
const [heightOriginal, setHeightOriginal] = useState<number>()
const [heightTruncated, setHeightTruncated] = useState<number>()
const [expandAllow, setExpandAllow] = useState(false) const [expandAllow, setExpandAllow] = useState(false)
const [expanded, setExpanded] = useState(false) const [expanded, setExpanded] = useState(false)
const viewHeight = useDerivedValue(() => { const onTextLayout = useCallback(({ nativeEvent }) => {
if (expandAllow) { if (
if (expanded) { nativeEvent.lines &&
return heightOriginal as number nativeEvent.lines.length === numberOfLines + 1
} else { ) {
return heightTruncated as number setExpandAllow(true)
}
} else {
return heightOriginal as number
} }
}, [heightOriginal, heightTruncated, expandAllow, expanded]) }, [])
const ViewHeight = useAnimatedStyle(() => {
return {
height: expandAllow
? expanded
? withTiming(viewHeight.value)
: withTiming(viewHeight.value)
: viewHeight.value
}
})
const onLayout = useCallback(
({ nativeEvent }) => {
if (!heightOriginal) {
setHeightOriginal(nativeEvent.layout.height)
setLines(numberOfLines === 0 ? 1 : numberOfLines)
} else {
if (!heightTruncated) {
setHeightTruncated(nativeEvent.layout.height)
setLines(undefined)
} else {
if (heightOriginal > heightTruncated) {
setExpandAllow(true)
}
}
}
},
[heightOriginal, heightTruncated]
)
return ( return (
<View> <View>
<Animated.View style={[ViewHeight, { overflow: 'hidden' }]}> <Text
<Animated.Text children={children}
children={children} onTextLayout={onTextLayout}
onLayout={onLayout} numberOfLines={expanded ? 999 : numberOfLines + 1}
numberOfLines={lines} style={{
style={{ ...StyleConstants.FontStyle[size],
...StyleConstants.FontStyle[size], color: theme.primary
color: theme.primary, }}
height: expandAllow ? heightOriginal : undefined />
}}
/>
</Animated.View>
{expandAllow ? ( {expandAllow ? (
<Pressable <Pressable
onPress={() => setExpanded(!expanded)} onPress={() => {
style={{ marginTop: expanded ? 0 : -lineHeight * 1.25 }} layoutAnimation()
setExpanded(!expanded)
}}
style={{ marginTop: expanded ? 0 : -lineHeight * 2.25 }}
> >
<LinearGradient <LinearGradient
colors={[ colors={[
@ -301,4 +263,5 @@ const ParseHTML: React.FC<Props> = ({
) )
} }
export default ParseHTML // export default ParseHTML
export default React.memo(ParseHTML, () => true)

View File

@ -9,18 +9,12 @@ import { useScrollToTop } from '@react-navigation/native'
import { localUpdateNotification } from '@utils/slices/instancesSlice' import { localUpdateNotification } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants' import { StyleConstants } from '@utils/styles/constants'
import React, { useCallback, useEffect, useMemo, useRef } from 'react' import React, { useCallback, useEffect, useMemo, useRef } from 'react'
import { RefreshControl, StyleSheet } from 'react-native' import { StyleSheet } from 'react-native'
import { FlatList } from 'react-native-gesture-handler' import { FlatList } from 'react-native-gesture-handler'
import { InfiniteData } from 'react-query'
import { useDispatch } from 'react-redux' import { useDispatch } from 'react-redux'
import { QueryKeyTimeline, useTimelineQuery } from '@utils/queryHooks/timeline' import { QueryKeyTimeline, useTimelineQuery } from '@utils/queryHooks/timeline'
import { findIndex } from 'lodash' import { findIndex } from 'lodash'
import CustomRefreshControl from '@components/CustomRefreshControl'
type TimelineData =
| InfiniteData<{
toots: Mastodon.Status[]
}>
| undefined
export interface Props { export interface Props {
page: App.Pages page: App.Pages
@ -54,6 +48,7 @@ const Timeline: React.FC<Props> = ({
data, data,
refetch, refetch,
isSuccess, isSuccess,
isFetching,
hasPreviousPage, hasPreviousPage,
fetchPreviousPage, fetchPreviousPage,
isFetchingPreviousPage, isFetchingPreviousPage,
@ -122,10 +117,6 @@ const Timeline: React.FC<Props> = ({
case 'Notifications': case 'Notifications':
return <TimelineNotifications notification={item} queryKey={queryKey} /> return <TimelineNotifications notification={item} queryKey={queryKey} />
default: default:
// if (item.poll) {
// console.log('Timeline')
// console.log(item.poll)
// }
return ( return (
<TimelineDefault <TimelineDefault
item={item} item={item}
@ -167,12 +158,15 @@ const Timeline: React.FC<Props> = ({
) )
const refreshControl = useMemo( const refreshControl = useMemo(
() => ( () => (
<RefreshControl <CustomRefreshControl
refreshing={isFetchingPreviousPage} queryKey={queryKey}
onRefresh={() => fetchPreviousPage()} isFetchingPreviousPage={isFetchingNextPage}
isFetching={isFetching}
fetchPreviousPage={fetchPreviousPage}
refetch={refetch}
/> />
), ),
[isFetchingPreviousPage] [isFetchingPreviousPage, isFetching]
) )
const onScrollToIndexFailed = useCallback(error => { const onScrollToIndexFailed = useCallback(error => {
const offset = error.averageItemLength * error.index const offset = error.averageItemLength * error.index
@ -219,6 +213,4 @@ const styles = StyleSheet.create({
} }
}) })
// Timeline.whyDidYouRender = true
export default Timeline export default Timeline

View File

@ -15,7 +15,7 @@ import { Pressable, StyleSheet, View } from 'react-native'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
export interface Props { export interface Props {
item: Mastodon.Status item: Mastodon.Status & { isPinned?: boolean }
queryKey?: QueryKeyTimeline queryKey?: QueryKeyTimeline
highlighted?: boolean highlighted?: boolean
disableDetails?: boolean disableDetails?: boolean
@ -61,7 +61,6 @@ const TimelineDefault: React.FC<Props> = ({
<TimelineHeaderDefault <TimelineHeaderDefault
queryKey={disableOnPress ? undefined : queryKey} queryKey={disableOnPress ? undefined : queryKey}
status={actualStatus} status={actualStatus}
sameAccount={actualStatus.account.id === localAccount?.id}
/> />
</View> </View>

View File

@ -17,7 +17,10 @@ const TimelineHeader = React.memo(
<Text <Text
style={{ color: theme.blue }} style={{ color: theme.blue }}
onPress={() => { onPress={() => {
navigation.navigate('Screen-Me') navigation.navigate('Screen-Me', {
screen: 'Screen-Me-Root',
params: { navigateAway: 'Screen-Me-Settings-UpdateRemote' }
})
}} }}
> >
{' '} {' '}

View File

@ -61,7 +61,10 @@ const TimelineNotifications: React.FC<Props> = ({
> >
<View style={styles.header}> <View style={styles.header}>
<TimelineAvatar queryKey={queryKey} account={actualAccount} /> <TimelineAvatar queryKey={queryKey} account={actualAccount} />
<TimelineHeaderNotification notification={notification} /> <TimelineHeaderNotification
queryKey={queryKey}
notification={notification}
/>
</View> </View>
{notification.status ? ( {notification.status ? (

View File

@ -32,6 +32,17 @@ const TimelineActions: React.FC<Props> = ({ queryKey, status, reblog }) => {
const mutation = useTimelineMutation({ const mutation = useTimelineMutation({
queryClient, queryClient,
onMutate: true, onMutate: true,
onSuccess: (_, params) => {
const theParams = params as MutationVarsTimelineUpdateStatusProperty
if (
(queryKey[1].page === 'Bookmarks' &&
theParams.payload.property === 'bookmarked') ||
(queryKey[1].page === 'Favourites' &&
theParams.payload.property === 'favourited')
) {
queryClient.invalidateQueries(queryKey)
}
},
onError: (err: any, params, oldData) => { onError: (err: any, params, oldData) => {
const correctParam = params as MutationVarsTimelineUpdateStatusProperty const correctParam = params as MutationVarsTimelineUpdateStatusProperty
haptics('Error') haptics('Error')

View File

@ -15,10 +15,8 @@ const TimelineCard: React.FC<Props> = ({ card }) => {
const [imageLoaded, setImageLoaded] = useState(false) const [imageLoaded, setImageLoaded] = useState(false)
useEffect(() => { useEffect(() => {
const preFetch = () => Image.getSize(card.image, () => setImageLoaded(true))
if (card.image) { if (card.image) {
preFetch() Image.getSize(card.image, () => setImageLoaded(true))
} }
}, []) }, [])
const cardVisual = useMemo(() => { const cardVisual = useMemo(() => {

View File

@ -15,7 +15,7 @@ export interface Props {
setBottomSheetVisible: React.Dispatch<React.SetStateAction<boolean>> setBottomSheetVisible: React.Dispatch<React.SetStateAction<boolean>>
} }
const HeaderDefaultActionsAccount: React.FC<Props> = ({ const HeaderActionsAccount: React.FC<Props> = ({
queryKey, queryKey,
account, account,
setBottomSheetVisible setBottomSheetVisible
@ -121,4 +121,4 @@ const HeaderDefaultActionsAccount: React.FC<Props> = ({
) )
} }
export default HeaderDefaultActionsAccount export default HeaderActionsAccount

View File

@ -17,7 +17,7 @@ export interface Props {
setBottomSheetVisible: React.Dispatch<React.SetStateAction<boolean>> setBottomSheetVisible: React.Dispatch<React.SetStateAction<boolean>>
} }
const HeaderDefaultActionsDomain: React.FC<Props> = ({ const HeaderActionsDomain: React.FC<Props> = ({
queryKey, queryKey,
domain, domain,
setBottomSheetVisible setBottomSheetVisible
@ -77,4 +77,4 @@ const HeaderDefaultActionsDomain: React.FC<Props> = ({
) )
} }
export default HeaderDefaultActionsDomain export default HeaderActionsDomain

View File

@ -17,7 +17,7 @@ export interface Props {
setBottomSheetVisible: React.Dispatch<React.SetStateAction<boolean>> setBottomSheetVisible: React.Dispatch<React.SetStateAction<boolean>>
} }
const HeaderDefaultActionsStatus: React.FC<Props> = ({ const HeaderActionsStatus: React.FC<Props> = ({
queryKey, queryKey,
status, status,
setBottomSheetVisible setBottomSheetVisible
@ -156,4 +156,4 @@ const HeaderDefaultActionsStatus: React.FC<Props> = ({
) )
} }
export default HeaderDefaultActionsStatus export default HeaderActionsStatus

View File

@ -0,0 +1,93 @@
import BottomSheet from '@components/BottomSheet'
import Icon from '@components/Icon'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import { getLocalAccount, getLocalUrl } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useCallback, useMemo, useState } from 'react'
import { Pressable, StyleSheet } from 'react-native'
import { useSelector } from 'react-redux'
import HeaderActionsAccount from './ActionsAccount'
import HeaderActionsDomain from './ActionsDomain'
import HeaderActionsStatus from './ActionsStatus'
export interface Props {
queryKey: QueryKeyTimeline
status: Mastodon.Status
}
const HeaderActions = React.memo(
({ queryKey, status }: Props) => {
const { theme } = useTheme()
const localAccount = useSelector(getLocalAccount)
const sameAccount = localAccount?.id === status.account.id
const localDomain = useSelector(getLocalUrl)
const statusDomain = status.uri
? status.uri.split(new RegExp(/\/\/(.*?)\//))[1]
: ''
const sameDomain = localDomain === statusDomain
const [modalVisible, setBottomSheetVisible] = useState(false)
const onPress = useCallback(() => setBottomSheetVisible(true), [])
const children = useMemo(
() => (
<Icon
name='MoreHorizontal'
color={theme.secondary}
size={StyleConstants.Font.Size.M + 2}
/>
),
[]
)
return (
<>
<Pressable style={styles.base} onPress={onPress} children={children} />
{modalVisible && (
<BottomSheet
visible={modalVisible}
handleDismiss={() => setBottomSheetVisible(false)}
>
{!sameAccount && (
<HeaderActionsAccount
queryKey={queryKey}
account={status.account}
setBottomSheetVisible={setBottomSheetVisible}
/>
)}
{sameAccount && (
<HeaderActionsStatus
queryKey={queryKey}
status={status}
setBottomSheetVisible={setBottomSheetVisible}
/>
)}
{!sameDomain && (
<HeaderActionsDomain
queryKey={queryKey}
domain={statusDomain}
setBottomSheetVisible={setBottomSheetVisible}
/>
)}
</BottomSheet>
)}
</>
)
},
() => true
)
const styles = StyleSheet.create({
base: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
paddingBottom: StyleConstants.Spacing.S
}
})
export default HeaderActions

View File

@ -1,53 +1,20 @@
import BottomSheet from '@components/BottomSheet'
import Icon from '@components/Icon'
import { getLocalUrl } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants' import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager' import React from 'react'
import HeaderDefaultActionsAccount from '@components/Timelines/Timeline/Shared/HeaderDefault/ActionsAccount' import { StyleSheet, View } from 'react-native'
import HeaderDefaultActionsDomain from '@components/Timelines/Timeline/Shared/HeaderDefault/ActionsDomain'
import HeaderDefaultActionsStatus from '@components/Timelines/Timeline/Shared/HeaderDefault/ActionsStatus'
import React, { useCallback, useMemo, useState } from 'react'
import { Pressable, StyleSheet, View } from 'react-native'
import { useSelector } from 'react-redux'
import HeaderSharedAccount from './HeaderShared/Account' import HeaderSharedAccount from './HeaderShared/Account'
import HeaderSharedApplication from './HeaderShared/Application' import HeaderSharedApplication from './HeaderShared/Application'
import HeaderSharedCreated from './HeaderShared/Created' import HeaderSharedCreated from './HeaderShared/Created'
import HeaderSharedVisibility from './HeaderShared/Visibility' import HeaderSharedVisibility from './HeaderShared/Visibility'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline' import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import HeaderSharedMuted from './HeaderShared/Muted' import HeaderSharedMuted from './HeaderShared/Muted'
import HeaderActions from './HeaderActions/Root'
export interface Props { export interface Props {
queryKey?: QueryKeyTimeline queryKey?: QueryKeyTimeline
status: Mastodon.Status status: Mastodon.Status
sameAccount: boolean
} }
const TimelineHeaderDefault: React.FC<Props> = ({ const TimelineHeaderDefault: React.FC<Props> = ({ queryKey, status }) => {
queryKey,
status,
sameAccount
}) => {
const domain = status.uri
? status.uri.split(new RegExp(/\/\/(.*?)\//))[1]
: ''
const { theme } = useTheme()
const localDomain = useSelector(getLocalUrl)
const [modalVisible, setBottomSheetVisible] = useState(false)
const onPressAction = useCallback(() => setBottomSheetVisible(true), [])
const pressableAction = useMemo(
() => (
<Icon
name='MoreHorizontal'
color={theme.secondary}
size={StyleConstants.Font.Size.M + 2}
/>
),
[]
)
return ( return (
<View style={styles.base}> <View style={styles.base}>
<View style={styles.accountAndMeta}> <View style={styles.accountAndMeta}>
@ -60,44 +27,7 @@ const TimelineHeaderDefault: React.FC<Props> = ({
</View> </View>
</View> </View>
{queryKey && ( {queryKey ? <HeaderActions queryKey={queryKey} status={status} /> : null}
<Pressable
style={styles.action}
onPress={onPressAction}
children={pressableAction}
/>
)}
{queryKey && modalVisible && (
<BottomSheet
visible={modalVisible}
handleDismiss={() => setBottomSheetVisible(false)}
>
{!sameAccount && (
<HeaderDefaultActionsAccount
queryKey={queryKey}
account={status.account}
setBottomSheetVisible={setBottomSheetVisible}
/>
)}
{sameAccount && (
<HeaderDefaultActionsStatus
queryKey={queryKey}
status={status}
setBottomSheetVisible={setBottomSheetVisible}
/>
)}
{domain !== localDomain && (
<HeaderDefaultActionsDomain
queryKey={queryKey}
domain={domain}
setBottomSheetVisible={setBottomSheetVisible}
/>
)}
</BottomSheet>
)}
</View> </View>
) )
} }
@ -118,12 +48,6 @@ const styles = StyleSheet.create({
}, },
created_at: { created_at: {
...StyleConstants.FontStyle.S ...StyleConstants.FontStyle.S
},
action: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
paddingBottom: StyleConstants.Spacing.S
} }
}) })

View File

@ -1,6 +1,6 @@
import { RelationshipOutgoing } from '@components/Relationship' import { RelationshipOutgoing } from '@components/Relationship'
import { StyleConstants } from '@utils/styles/constants' import { StyleConstants } from '@utils/styles/constants'
import React from 'react' import React, { useMemo } from 'react'
import { StyleSheet, View } from 'react-native' import { StyleSheet, View } from 'react-native'
import HeaderSharedAccount from './HeaderShared/Account' import HeaderSharedAccount from './HeaderShared/Account'
import HeaderSharedApplication from './HeaderShared/Application' import HeaderSharedApplication from './HeaderShared/Application'
@ -8,15 +8,41 @@ import HeaderSharedCreated from './HeaderShared/Created'
import HeaderSharedVisibility from './HeaderShared/Visibility' import HeaderSharedVisibility from './HeaderShared/Visibility'
import RelationshipIncoming from '@root/components/Relationship/Incoming' import RelationshipIncoming from '@root/components/Relationship/Incoming'
import HeaderSharedMuted from './HeaderShared/Muted' import HeaderSharedMuted from './HeaderShared/Muted'
import HeaderActions from './HeaderActions/Root'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
export interface Props { export interface Props {
queryKey: QueryKeyTimeline
notification: Mastodon.Notification notification: Mastodon.Notification
} }
const TimelineHeaderNotification: React.FC<Props> = ({ notification }) => { const TimelineHeaderNotification: React.FC<Props> = ({
queryKey,
notification
}) => {
const actions = useMemo(() => {
switch (notification.type) {
case 'follow':
return <RelationshipOutgoing id={notification.account.id} />
case 'follow_request':
return <RelationshipIncoming id={notification.account.id} />
default:
return notification.status ? (
<HeaderActions queryKey={queryKey} status={notification.status} />
) : null
}
}, [notification.type])
return ( return (
<View style={styles.base}> <View style={styles.base}>
<View style={styles.accountAndMeta}> <View
style={{
flex:
notification.type === 'follow' ||
notification.type === 'follow_request'
? 1
: 4
}}
>
<HeaderSharedAccount <HeaderSharedAccount
account={ account={
notification.status notification.status
@ -38,16 +64,17 @@ const TimelineHeaderNotification: React.FC<Props> = ({ notification }) => {
</View> </View>
</View> </View>
{notification.type === 'follow' && ( <View
<View style={styles.relationship}> style={[
<RelationshipOutgoing id={notification.account.id} /> styles.relationship,
</View> notification.type === 'follow' ||
)} notification.type === 'follow_request'
{notification.type === 'follow_request' && ( ? { flexShrink: 1 }
<View style={styles.relationship}> : { flex: 1 }
<RelationshipIncoming id={notification.account.id} /> ]}
</View> >
)} {actions}
</View>
</View> </View>
) )
} }
@ -55,13 +82,7 @@ const TimelineHeaderNotification: React.FC<Props> = ({ notification }) => {
const styles = StyleSheet.create({ const styles = StyleSheet.create({
base: { base: {
flex: 1, flex: 1,
flexDirection: 'row', flexDirection: 'row'
justifyContent: 'space-between',
alignItems: 'flex-start'
},
accountAndMeta: {
flex: 1,
flexGrow: 1
}, },
meta: { meta: {
flexDirection: 'row', flexDirection: 'row',
@ -70,7 +91,6 @@ const styles = StyleSheet.create({
marginBottom: StyleConstants.Spacing.S marginBottom: StyleConstants.Spacing.S
}, },
relationship: { relationship: {
flexShrink: 1,
marginLeft: StyleConstants.Spacing.M marginLeft: StyleConstants.Spacing.M
} }
}) })

View File

@ -8,15 +8,29 @@ import accountReducer from '@screens/Shared/Account/utils/reducer'
import accountInitialState from '@screens/Shared/Account/utils/initialState' import accountInitialState from '@screens/Shared/Account/utils/initialState'
import AccountContext from '@screens/Shared/Account/utils/createContext' import AccountContext from '@screens/Shared/Account/utils/createContext'
import { getLocalActiveIndex } from '@utils/slices/instancesSlice' import { getLocalActiveIndex } from '@utils/slices/instancesSlice'
import React, { useReducer, useRef, useState } from 'react' import React, { useEffect, useReducer, useRef, useState } from 'react'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
import Animated, { import Animated, {
useAnimatedScrollHandler, useAnimatedScrollHandler,
useSharedValue useSharedValue
} from 'react-native-reanimated' } from 'react-native-reanimated'
import ComponentInstance from '@components/Instance' import ComponentInstance from '@components/Instance'
import { StackScreenProps } from '@react-navigation/stack'
const ScreenMeRoot: React.FC = () => { const ScreenMeRoot: React.FC<StackScreenProps<
Nav.MeStackParamList,
'Screen-Me-Root'
>> = ({
route: {
params: { navigateAway }
},
navigation
}) => {
useEffect(() => {
if (navigateAway) {
navigation.navigate(navigateAway)
}
}, [navigateAway])
const localActiveIndex = useSelector(getLocalActiveIndex) const localActiveIndex = useSelector(getLocalActiveIndex)
const scrollRef = useRef<Animated.ScrollView>(null) const scrollRef = useRef<Animated.ScrollView>(null)

View File

@ -1,6 +1,6 @@
import BottomSheet from '@components/BottomSheet' import BottomSheet from '@components/BottomSheet'
import { HeaderRight } from '@components/Header' import { HeaderRight } from '@components/Header'
import HeaderDefaultActionsAccount from '@components/Timelines/Timeline/Shared/HeaderDefault/ActionsAccount' import HeaderActionsAccount from '@components/Timelines/Timeline/Shared/HeaderActions/ActionsAccount'
import { useAccountQuery } from '@utils/queryHooks/account' import { useAccountQuery } from '@utils/queryHooks/account'
import { getLocalAccount } from '@utils/slices/instancesSlice' import { getLocalAccount } from '@utils/slices/instancesSlice'
import React, { useEffect, useReducer, useState } from 'react' import React, { useEffect, useReducer, useState } from 'react'
@ -77,7 +77,7 @@ const ScreenSharedAccount: React.FC<SharedAccountProp> = ({
> >
{/* 添加到列表 */} {/* 添加到列表 */}
{localAccount?.id !== account.id && ( {localAccount?.id !== account.id && (
<HeaderDefaultActionsAccount <HeaderActionsAccount
account={account} account={account}
setBottomSheetVisible={setBottomSheetVisible} setBottomSheetVisible={setBottomSheetVisible}
/> />

View File

View File

@ -381,7 +381,8 @@ const useTimelineMutation = ({
onSettled, onSettled,
...(typeof onSuccess === 'function' ...(typeof onSuccess === 'function'
? { onSuccess } ? { onSuccess }
: { : onSuccess
? {
onSuccess: (data, params) => { onSuccess: (data, params) => {
queryClient.cancelQueries(params.queryKey) queryClient.cancelQueries(params.queryKey)
@ -397,7 +398,8 @@ const useTimelineMutation = ({
break break
} }
} }
}), }
: undefined),
...(onMutate && { ...(onMutate && {
onMutate: params => { onMutate: params => {
queryClient.cancelQueries(params.queryKey) queryClient.cancelQueries(params.queryKey)

View File

@ -11,7 +11,6 @@ const updateStatus = ({
}) => { }) => {
switch (payload.property) { switch (payload.property) {
case 'poll': case 'poll':
console.log(payload.data)
if (reblog) { if (reblog) {
item.reblog!.poll = payload.data item.reblog!.poll = payload.data
} else { } else {

View File

@ -19,7 +19,7 @@ export const ManageThemeContext = createContext<ContextType>({
export const useTheme = () => useContext(ManageThemeContext) export const useTheme = () => useContext(ManageThemeContext)
const useColorSchemeDelay = (delay = 250) => { const useColorSchemeDelay = (delay = 500) => {
const [colorScheme, setColorScheme] = React.useState( const [colorScheme, setColorScheme] = React.useState(
Appearance.getColorScheme() Appearance.getColorScheme()
) )

View File

@ -23,15 +23,15 @@ const themeColors: {
} = { } = {
primary: { primary: {
light: 'rgb(18, 18, 18)', light: 'rgb(18, 18, 18)',
dark: 'rgb(218, 218, 218)' dark: 'rgb(180, 180, 180)'
}, },
primaryOverlay: { primaryOverlay: {
light: 'rgb(250, 250, 250)', light: 'rgb(250, 250, 250)',
dark: 'rgb(218, 218, 218)' dark: 'rgb(180, 180, 180)'
}, },
secondary: { secondary: {
light: 'rgb(135, 135, 135)', light: 'rgb(135, 135, 135)',
dark: 'rgb(135, 135, 135)' dark: 'rgb(130, 130, 130)'
}, },
disabled: { disabled: {
light: 'rgb(200, 200, 200)', light: 'rgb(200, 200, 200)',
@ -48,30 +48,30 @@ const themeColors: {
background: { background: {
light: 'rgb(250, 250, 250)', light: 'rgb(250, 250, 250)',
dark: 'rgb(18, 18, 18)' dark: 'rgb(25, 25, 25)'
}, },
backgroundGradientStart: { backgroundGradientStart: {
light: 'rgba(250, 250, 250, 0.5)', light: 'rgba(250, 250, 250, 0.5)',
dark: 'rgba(18, 18, 18, 0.5)' dark: 'rgba(25, 25, 25, 0.5)'
}, },
backgroundGradientEnd: { backgroundGradientEnd: {
light: 'rgba(250, 250, 250, 1)', light: 'rgba(250, 250, 250, 1)',
dark: 'rgba(18, 18, 18, 1)' dark: 'rgba(25, 25, 25, 1)'
}, },
backgroundOverlay: { backgroundOverlay: {
light: 'rgba(18, 18, 18, 0.5)', light: 'rgba(25, 25, 25, 0.5)',
dark: 'rgba(0, 0, 0, 0.5)' dark: 'rgba(0, 0, 0, 0.5)'
}, },
border: { border: {
light: 'rgba(18, 18, 18, 0.3)', light: 'rgba(25, 25, 25, 0.3)',
dark: 'rgba(255, 255, 255, 0.3)' dark: 'rgba(255, 255, 255, 0.3)'
}, },
shimmerDefault: { shimmerDefault: {
light: 'rgba(18, 18, 18, 0.05)', light: 'rgba(25, 25, 25, 0.05)',
dark: 'rgba(250, 250, 250, 0.05)' dark: 'rgba(250, 250, 250, 0.05)'
}, },
shimmerHighlight: { shimmerHighlight: {
light: 'rgba(18, 18, 18, 0.15)', light: 'rgba(25, 25, 25, 0.15)',
dark: 'rgba(250, 250, 250, 0.15)' dark: 'rgba(250, 250, 250, 0.15)'
} }
} }