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

Account actions working for #638

This commit is contained in:
xmflsct
2023-01-02 02:08:12 +01:00
parent 62df29a479
commit 6dafbc96af
73 changed files with 262 additions and 626 deletions

View File

@ -1,112 +0,0 @@
import { RootStackScreenProps } from '@utils/navigation/navigators'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useEffect } from 'react'
import { Dimensions, StyleSheet, View } from 'react-native'
import { PanGestureHandler, State, TapGestureHandler } from 'react-native-gesture-handler'
import Animated, {
Extrapolate,
interpolate,
runOnJS,
useAnimatedGestureHandler,
useAnimatedStyle,
useSharedValue,
withTiming
} from 'react-native-reanimated'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import ActionsAltText from './Actions/AltText'
const ScreenActions = ({
route: { params },
navigation
}: RootStackScreenProps<'Screen-Actions'>) => {
const { colors } = useTheme()
const insets = useSafeAreaInsets()
const DEFAULT_VALUE = 350
const screenHeight = Dimensions.get('window').height
const panY = useSharedValue(DEFAULT_VALUE)
useEffect(() => {
panY.value = withTiming(0)
}, [])
const styleTop = useAnimatedStyle(() => {
return {
bottom: interpolate(panY.value, [0, screenHeight], [0, -screenHeight], Extrapolate.CLAMP)
}
})
const dismiss = () => navigation.goBack()
const onGestureEvent = useAnimatedGestureHandler({
onActive: ({ translationY }) => {
panY.value = translationY
},
onEnd: ({ velocityY }) => {
if (velocityY > 500) {
runOnJS(dismiss)()
} else {
panY.value = withTiming(0)
}
}
})
const actions = () => {
switch (params.type) {
case 'alt_text':
return <ActionsAltText text={params.text} />
}
}
return (
<Animated.View style={{ flex: 1 }}>
<TapGestureHandler
onHandlerStateChange={({ nativeEvent }) => {
if (nativeEvent.state === State.ACTIVE) {
dismiss()
}
}}
>
<Animated.View
style={[styles.overlay, { backgroundColor: colors.backgroundOverlayInvert }]}
>
<PanGestureHandler onGestureEvent={onGestureEvent}>
<Animated.View
style={[
styles.container,
styleTop,
{
backgroundColor: colors.backgroundDefault,
paddingBottom: insets.bottom || StyleConstants.Spacing.L
}
]}
>
<View style={[styles.handle, { backgroundColor: colors.primaryOverlay }]} />
{actions()}
</Animated.View>
</PanGestureHandler>
</Animated.View>
</TapGestureHandler>
</Animated.View>
)
}
const styles = StyleSheet.create({
overlay: {
flex: 1,
justifyContent: 'flex-end'
},
container: {
paddingTop: StyleConstants.Spacing.M
},
handle: {
alignSelf: 'center',
width: StyleConstants.Spacing.S * 8,
height: StyleConstants.Spacing.S / 2,
borderRadius: 100,
top: -StyleConstants.Spacing.M * 2
},
button: {
marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2
}
})
export default ScreenActions

View File

@ -1,42 +0,0 @@
import Button from '@components/Button'
import MenuContainer from '@components/Menu/Container'
import MenuHeader from '@components/Menu/Header'
import CustomText from '@components/Text'
import { useNavigation } from '@react-navigation/native'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { Dimensions } from 'react-native'
import { ScrollView } from 'react-native-gesture-handler'
export interface Props {
text: string
}
const ActionsAltText: React.FC<Props> = ({ text }) => {
const navigation = useNavigation()
const { t } = useTranslation(['common', 'screenActions'])
const { colors } = useTheme()
return (
<>
<MenuContainer>
<MenuHeader heading={t(`screenActions:content.altText.heading`)} />
<ScrollView style={{ maxHeight: Dimensions.get('window').height / 2 }}>
<CustomText style={{ color: colors.primaryDefault }}>{text}</CustomText>
</ScrollView>
</MenuContainer>
<Button
type='text'
content={t('common:buttons.OK')}
onPress={() => navigation.goBack()}
style={{
marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2
}}
/>
</>
)
}
export default ActionsAltText

View File

@ -2,15 +2,11 @@ import AccountHeader from '@screens/Tabs/Shared/Account/Header'
import AccountInformation from '@screens/Tabs/Shared/Account/Information'
import React from 'react'
export interface Props {
account: Mastodon.Account | undefined
}
const MyInfo: React.FC<Props> = ({ account }) => {
const MyInfo: React.FC = () => {
return (
<>
<AccountHeader account={account} />
<AccountInformation account={account} />
<AccountHeader />
<AccountInformation />
</>
)
}

View File

@ -5,13 +5,11 @@ import Logout from '@screens/Tabs/Me/Root/Logout'
import MyInfo from '@screens/Tabs/Me/Root/MyInfo'
import Settings from '@screens/Tabs/Me/Root/Settings'
import AccountInformationSwitch from '@screens/Tabs/Me/Root/Switch'
import AccountContext from '@screens/Tabs/Shared/Account/Context'
import AccountNav from '@screens/Tabs/Shared/Account/Nav'
import AccountContext from '@screens/Tabs/Shared/Account/utils/createContext'
import accountInitialState from '@screens/Tabs/Shared/Account/utils/initialState'
import accountReducer from '@screens/Tabs/Shared/Account/utils/reducer'
import { useProfileQuery } from '@utils/queryHooks/profile'
import { useGlobalStorage } from '@utils/storage/actions'
import React, { useReducer, useRef } from 'react'
import React, { useRef } from 'react'
import Animated, { useAnimatedScrollHandler, useSharedValue } from 'react-native-reanimated'
const TabMeRoot: React.FC = () => {
@ -24,23 +22,21 @@ const TabMeRoot: React.FC = () => {
const scrollRef = useRef<Animated.ScrollView>(null)
useScrollToTop(scrollRef)
const [accountState, accountDispatch] = useReducer(accountReducer, accountInitialState)
const scrollY = useSharedValue(0)
const onScroll = useAnimatedScrollHandler(event => {
scrollY.value = event.contentOffset.y
})
return (
<AccountContext.Provider value={{ accountState, accountDispatch }}>
{accountActive && data ? <AccountNav scrollY={scrollY} account={data} /> : null}
<AccountContext.Provider value={{ account: data, pageMe: true }}>
{accountActive && data ? <AccountNav scrollY={scrollY} /> : null}
<Animated.ScrollView
ref={scrollRef}
keyboardShouldPersistTaps='handled'
onScroll={onScroll}
scrollEventThrottle={16}
>
{accountActive ? <MyInfo account={data} /> : <ComponentInstance />}
{accountActive ? <MyInfo /> : <ComponentInstance />}
{accountActive ? <Collections /> : null}
<Settings />
{accountActive ? <AccountInformationSwitch /> : null}

View File

@ -7,17 +7,15 @@ import { useTimelineQuery } from '@utils/queryHooks/timeline'
import { flattenPages } from '@utils/queryHooks/utils'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React from 'react'
import React, { useContext } from 'react'
import { Dimensions, Pressable, View } from 'react-native'
import { FlatList } from 'react-native-gesture-handler'
import Animated, { useAnimatedStyle, withTiming } from 'react-native-reanimated'
import AccountContext from './Context'
export interface Props {
account: Mastodon.Account | undefined
}
const AccountAttachments: React.FC = () => {
const { account } = useContext(AccountContext)
const AccountAttachments: React.FC<Props> = ({ account }) => {
if (!account) return null
if (account?.suspended) return null
const navigation = useNavigation<StackNavigationProp<TabLocalStackParamList>>()
const { colors } = useTheme()
@ -28,30 +26,28 @@ const AccountAttachments: React.FC<Props> = ({ account }) => {
const { data } = useTimelineQuery({
page: 'Account',
account: account.id,
id: account?.id,
exclude_reblogs: false,
only_media: true
only_media: true,
options: { enabled: !!account?.id }
})
const flattenData = flattenPages(data)
.filter(status => !(status as Mastodon.Status).sensitive)
.splice(0, DISPLAY_AMOUNT)
const styleContainer = useAnimatedStyle(() => {
if (flattenData.length) {
return {
height: withTiming(width + StyleConstants.Spacing.Global.PagePadding * 2),
if (!flattenData.length) return null
return (
<View
style={{
flex: 1,
height: width + StyleConstants.Spacing.Global.PagePadding * 2,
paddingVertical: StyleConstants.Spacing.Global.PagePadding,
borderTopWidth: 1,
borderTopColor: colors.border
}
} else {
return {}
}
}, [flattenData.length])
return (
<Animated.View style={[{ flex: 1 }, styleContainer]}>
}}
>
<FlatList
horizontal
data={flattenData}
@ -103,7 +99,7 @@ const AccountAttachments: React.FC<Props> = ({ account }) => {
}}
showsHorizontalScrollIndicator={false}
/>
</Animated.View>
</View>
)
}

View File

@ -0,0 +1,9 @@
import { createContext } from 'react'
type AccountContextType = {
account?: Mastodon.Account
pageMe?: boolean
}
const AccountContext = createContext<AccountContextType>({} as AccountContextType)
export default AccountContext

View File

@ -1,15 +1,14 @@
import GracefullyImage from '@components/GracefullyImage'
import navigationRef from '@utils/navigation/navigationRef'
import { useGlobalStorage } from '@utils/storage/actions'
import React from 'react'
import React, { useContext } from 'react'
import { Dimensions, Image } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import AccountContext from './Context'
export interface Props {
account?: Mastodon.Account
}
const AccountHeader: React.FC = () => {
const { account } = useContext(AccountContext)
const AccountHeader: React.FC<Props> = ({ account }) => {
const topInset = useSafeAreaInsets().top
useGlobalStorage.string('account.active')

View File

@ -13,11 +13,7 @@ import AccountInformationName from './Information/Name'
import AccountInformationNote from './Information/Note'
import AccountInformationStats from './Information/Stats'
export interface Props {
account: Mastodon.Account | undefined
}
const AccountInformation: React.FC<Props> = ({ account }) => {
const AccountInformation: React.FC = () => {
const { colors } = useTheme()
const { name } = useRoute()
@ -31,21 +27,21 @@ const AccountInformation: React.FC<Props> = ({ account }) => {
)}
>
<View style={styles.avatarAndActions}>
<AccountInformationAvatar account={account} myInfo={myInfo} />
<AccountInformationActions account={account} myInfo={myInfo} />
<AccountInformationAvatar />
<AccountInformationActions />
</View>
<AccountInformationName account={account} />
<AccountInformationName />
<AccountInformationAccount account={account} myInfo={myInfo} />
<AccountInformationAccount />
<AccountInformationFields account={account} myInfo={myInfo} />
<AccountInformationFields />
<AccountInformationNote account={account} myInfo={myInfo} />
<AccountInformationNote />
<AccountInformationCreated account={account} hidden={myInfo} />
<AccountInformationCreated />
<AccountInformationStats account={account} myInfo={myInfo} />
<AccountInformationStats />
</Placeholder>
</View>
)

View File

@ -4,31 +4,26 @@ import { useRelationshipQuery } from '@utils/queryHooks/relationship'
import { getAccountStorage, useAccountStorage } from '@utils/storage/actions'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React from 'react'
import React, { useContext } from 'react'
import { useTranslation } from 'react-i18next'
import { View } from 'react-native'
import { PlaceholderLine } from 'rn-placeholder'
import AccountContext from '../Context'
export interface Props {
account: Mastodon.Account | undefined
myInfo?: boolean
}
const AccountInformationAccount: React.FC = () => {
const { account, pageMe } = useContext(AccountContext)
const AccountInformationAccount: React.FC<Props> = ({ account, myInfo }) => {
const { t } = useTranslation('screenTabs')
const { colors } = useTheme()
const [acct] = useAccountStorage.string('auth.account.acct')
const domain = getAccountStorage.string('auth.account.domain')
const { data: relationship } = useRelationshipQuery({
id: account?.id || '',
options: { enabled: account !== undefined }
})
const { data: relationship } = useRelationshipQuery({ id: account?.id })
const localInstance = account?.acct.includes('@') ? account?.acct.includes(`@${domain}`) : true
if (account || localInstance) {
if (account || pageMe) {
return (
<View
style={{
@ -51,7 +46,7 @@ const AccountInformationAccount: React.FC<Props> = ({ account, myInfo }) => {
}}
selectable
>
@{myInfo ? acct : account?.acct}
@{pageMe ? acct : account?.acct}
{localInstance ? `@${domain}` : null}
</CustomText>
{relationship?.followed_by ? t('shared.account.followed_by') : null}

View File

@ -5,17 +5,15 @@ import { useNavigation } from '@react-navigation/native'
import { useRelationshipQuery } from '@utils/queryHooks/relationship'
import { useAccountStorage } from '@utils/storage/actions'
import { StyleConstants } from '@utils/styles/constants'
import React from 'react'
import React, { useContext } from 'react'
import { useTranslation } from 'react-i18next'
import { StyleSheet, View } from 'react-native'
import * as DropdownMenu from 'zeego/dropdown-menu'
import AccountContext from '../Context'
export interface Props {
account: Mastodon.Account | undefined
myInfo?: boolean
}
const AccountInformationActions: React.FC = () => {
const { account, pageMe } = useContext(AccountContext)
const AccountInformationActions: React.FC<Props> = ({ account, myInfo }) => {
if (!account || account.suspended) {
return null
}
@ -36,7 +34,7 @@ const AccountInformationActions: React.FC<Props> = ({ account, myInfo }) => {
)
}
if (myInfo) {
if (pageMe) {
return (
<View style={styles.base}>
<Button
@ -76,7 +74,7 @@ const AccountInformationActions: React.FC<Props> = ({ account, myInfo }) => {
{mGroup.map(menu => (
<DropdownMenu.Item key={menu.key} {...menu.item}>
<DropdownMenu.ItemTitle children={menu.title} />
<DropdownMenu.ItemIcon iosIconName={menu.icon} />
<DropdownMenu.ItemIcon ios={{ name: menu.icon }} />
</DropdownMenu.Item>
))}
</DropdownMenu.Group>

View File

@ -5,14 +5,12 @@ import navigationRef from '@utils/navigation/navigationRef'
import { TabLocalStackParamList } from '@utils/navigation/navigators'
import { useGlobalStorage } from '@utils/storage/actions'
import { StyleConstants } from '@utils/styles/constants'
import React from 'react'
import React, { useContext } from 'react'
import AccountContext from '../Context'
export interface Props {
account: Mastodon.Account | undefined
myInfo: boolean
}
const AccountInformationAvatar: React.FC = () => {
const { account, pageMe } = useContext(AccountContext)
const AccountInformationAvatar: React.FC<Props> = ({ account, myInfo }) => {
const navigation = useNavigation<StackNavigationProp<TabLocalStackParamList>>()
useGlobalStorage.string('account.active')
@ -29,7 +27,7 @@ const AccountInformationAvatar: React.FC<Props> = ({ account, myInfo }) => {
uri={{ original: account?.avatar, static: account?.avatar_static }}
onPress={() => {
if (account) {
if (myInfo) {
if (pageMe) {
navigation.push('Tab-Shared-Account', { account })
return
} else {

View File

@ -2,18 +2,16 @@ import Icon from '@components/Icon'
import CustomText from '@components/Text'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React from 'react'
import React, { useContext } from 'react'
import { useTranslation } from 'react-i18next'
import { View } from 'react-native'
import { PlaceholderLine } from 'rn-placeholder'
import AccountContext from '../Context'
export interface Props {
account: Mastodon.Account | undefined
hidden?: boolean
}
const AccountInformationCreated: React.FC = () => {
const { account, pageMe } = useContext(AccountContext)
const AccountInformationCreated: React.FC<Props> = ({ account, hidden = false }) => {
if (hidden) {
if (pageMe) {
return null
}

View File

@ -1,16 +1,14 @@
import { ParseHTML } from '@components/Parse'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React from 'react'
import React, { useContext } from 'react'
import { StyleSheet, View } from 'react-native'
import AccountContext from '../Context'
export interface Props {
account: Mastodon.Account | undefined
myInfo?: boolean
}
const AccountInformationFields: React.FC = () => {
const { account, pageMe } = useContext(AccountContext)
const AccountInformationFields: React.FC<Props> = ({ account, myInfo }) => {
if (account?.suspended || myInfo || !account?.fields || account.fields.length === 0) {
if (account?.suspended || pageMe || !account?.fields || account.fields.length === 0) {
return null
}

View File

@ -2,15 +2,14 @@ import { ParseEmojis } from '@components/Parse'
import CustomText from '@components/Text'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React from 'react'
import React, { useContext } from 'react'
import { View } from 'react-native'
import { PlaceholderLine } from 'rn-placeholder'
import AccountContext from '../Context'
export interface Props {
account: Mastodon.Account | undefined
}
const AccountInformationName: React.FC = () => {
const { account } = useContext(AccountContext)
const AccountInformationName: React.FC<Props> = ({ account }) => {
const { colors } = useTheme()
return (

View File

@ -1,17 +1,15 @@
import { ParseHTML } from '@components/Parse'
import { StyleConstants } from '@utils/styles/constants'
import React from 'react'
import React, { useContext } from 'react'
import { View } from 'react-native'
import AccountContext from '../Context'
export interface Props {
account: Mastodon.Account | undefined
myInfo?: boolean
}
const AccountInformationNote: React.FC = () => {
const { account, pageMe } = useContext(AccountContext)
const AccountInformationNote: React.FC<Props> = ({ account, myInfo }) => {
if (
account?.suspended ||
myInfo ||
pageMe ||
!account?.note ||
account.note.length === 0 ||
account.note === '<p></p>'

View File

@ -4,17 +4,15 @@ import { StackNavigationProp } from '@react-navigation/stack'
import { TabLocalStackParamList } from '@utils/navigation/navigators'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React from 'react'
import React, { useContext } from 'react'
import { useTranslation } from 'react-i18next'
import { StyleSheet, View } from 'react-native'
import { PlaceholderLine } from 'rn-placeholder'
import AccountContext from '../Context'
export interface Props {
account: Mastodon.Account | undefined
myInfo: boolean
}
const AccountInformationStats: React.FC = () => {
const { account, pageMe } = useContext(AccountContext)
const AccountInformationStats: React.FC<Props> = ({ account, myInfo }) => {
if (account?.suspended) {
return null
}
@ -32,7 +30,7 @@ const AccountInformationStats: React.FC<Props> = ({ account, myInfo }) => {
count: account.statuses_count || 0
})}
onPress={() => {
myInfo && account && navigation.push('Tab-Shared-Account', { account })
pageMe && account && navigation.push('Tab-Shared-Account', { account })
}}
/>
) : (

View File

@ -2,17 +2,19 @@ import { ParseEmojis } from '@components/Parse'
import CustomText from '@components/Text'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React from 'react'
import React, { useContext } from 'react'
import { Dimensions, StyleSheet, View } from 'react-native'
import Animated, { Extrapolate, interpolate, useAnimatedStyle } from 'react-native-reanimated'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import AccountContext from './Context'
export interface Props {
scrollY: Animated.SharedValue<number>
account: Mastodon.Account | undefined
}
const AccountNav: React.FC<Props> = ({ scrollY, account }) => {
const AccountNav: React.FC<Props> = ({ scrollY }) => {
const { account } = useContext(AccountContext)
const { colors } = useTheme()
const headerHeight = useSafeAreaInsets().top + 44

View File

@ -16,6 +16,7 @@ import { Text, View } from 'react-native'
import { useSharedValue } from 'react-native-reanimated'
import * as DropdownMenu from 'zeego/dropdown-menu'
import AccountAttachments from './Attachments'
import AccountContext from './Context'
import AccountHeader from './Header'
import AccountInformation from './Information'
import AccountNav from './Nav'
@ -23,14 +24,19 @@ import AccountNav from './Nav'
const TabSharedAccount: React.FC<TabSharedStackScreenProps<'Tab-Shared-Account'>> = ({
navigation,
route: {
params: { account }
params: { account, isRemote }
}
}) => {
const { t } = useTranslation('screenTabs')
const { colors, mode } = useTheme()
const mShare = menuShare({ type: 'account', url: account.url })
const mAccount = menuAccount({ type: 'account', openChange: true, account })
const { data, dataUpdatedAt } = useAccountQuery({
id: account.id,
...(isRemote && { remoteUrl: account.url })
})
const mShare = menuShare({ type: 'account', url: data?.url })
const mAccount = menuAccount({ type: 'account', openChange: true, account: data })
useEffect(() => {
navigation.setOptions({
headerTransparent: true,
@ -76,14 +82,12 @@ const TabSharedAccount: React.FC<TabSharedStackScreenProps<'Tab-Shared-Account'>
})
}, [mAccount])
const { data } = useAccountQuery({ id: account.id })
const scrollY = useSharedValue(0)
const queryClient = useQueryClient()
const [queryKey, setQueryKey] = useState<QueryKeyTimeline>([
'Timeline',
{ page: 'Account', account: account.id, exclude_reblogs: true, only_media: false }
{ page: 'Account', id: data?.id, exclude_reblogs: true, only_media: false }
])
const page = queryKey[1]
@ -92,9 +96,9 @@ const TabSharedAccount: React.FC<TabSharedStackScreenProps<'Tab-Shared-Account'>
return (
<>
<View style={{ borderBottomWidth: 1, borderBottomColor: colors.border }}>
<AccountHeader account={data} />
<AccountInformation account={data} />
{!data?.suspended ? <AccountAttachments account={data} /> : null}
<AccountHeader />
<AccountInformation />
<AccountAttachments />
</View>
{!data?.suspended ? (
<SegmentedControl
@ -110,7 +114,7 @@ const TabSharedAccount: React.FC<TabSharedStackScreenProps<'Tab-Shared-Account'>
{
...page,
page: 'Account',
account: account.id,
id: data?.id,
exclude_reblogs: true,
only_media: false
}
@ -122,7 +126,7 @@ const TabSharedAccount: React.FC<TabSharedStackScreenProps<'Tab-Shared-Account'>
{
...page,
page: 'Account',
account: account.id,
id: data?.id,
exclude_reblogs: false,
only_media: false
}
@ -158,11 +162,11 @@ const TabSharedAccount: React.FC<TabSharedStackScreenProps<'Tab-Shared-Account'>
) : null}
</>
)
}, [segment, data, queryKey[1].page, mode])
}, [segment, dataUpdatedAt, mode])
return (
<>
<AccountNav scrollY={scrollY} account={data} />
<AccountContext.Provider value={{ account: data }}>
<AccountNav scrollY={scrollY} />
{data?.suspended ? (
ListHeaderComponent
@ -170,6 +174,7 @@ const TabSharedAccount: React.FC<TabSharedStackScreenProps<'Tab-Shared-Account'>
<Timeline
queryKey={queryKey}
disableRefresh
queryOptions={{ enabled: isRemote ? !!data?.id : true }}
customProps={{
renderItem: ({ item }) => <TimelineDefault item={item} queryKey={queryKey} />,
onScroll: ({ nativeEvent }) => (scrollY.value = nativeEvent.contentOffset.y),
@ -180,7 +185,7 @@ const TabSharedAccount: React.FC<TabSharedStackScreenProps<'Tab-Shared-Account'>
}}
/>
)}
</>
</AccountContext.Provider>
)
}

View File

@ -1,10 +0,0 @@
import { createContext, Dispatch } from 'react'
import { AccountAction, AccountState } from './types'
type ContextType = {
accountState: AccountState
accountDispatch: Dispatch<AccountAction>
}
const AccountContext = createContext<ContextType>({} as ContextType)
export default AccountContext

View File

@ -1,9 +0,0 @@
import { AccountState } from './types'
const accountInitialState: AccountState = {
headerRatio: 1 / 3,
informationLayout: { height: 0, y: 100 },
segmentedIndex: 0
}
export default accountInitialState

View File

@ -1,19 +0,0 @@
import { AccountAction, AccountState } from "./types"
const accountReducer = (
state: AccountState,
action: AccountAction
): AccountState => {
switch (action.type) {
case 'headerRatio':
return { ...state, headerRatio: action.payload }
case 'informationLayout':
return { ...state, informationLayout: action.payload }
case 'segmentedIndex':
return { ...state, segmentedIndex: action.payload }
default:
throw new Error('Unexpected action')
}
}
export default accountReducer

View File

@ -1,22 +0,0 @@
export type AccountState = {
headerRatio: number
informationLayout?: {
y: number
height: number
}
segmentedIndex: number
}
export type AccountAction =
| {
type: 'headerRatio'
payload: AccountState['headerRatio']
}
| {
type: 'informationLayout'
payload: AccountState['informationLayout']
}
| {
type: 'segmentedIndex'
payload: AccountState['segmentedIndex']
}

View File

@ -45,7 +45,7 @@ const TabSharedAttachments: React.FC<TabSharedStackScreenProps<'Tab-Shared-Attac
const queryKey: QueryKeyTimeline = [
'Timeline',
{ page: 'Account', account: account.id, exclude_reblogs: true, only_media: true }
{ page: 'Account', id: account.id, exclude_reblogs: true, only_media: true }
]
return (

View File

@ -5,6 +5,7 @@ import CustomText from '@components/Text'
import apiInstance from '@utils/api/instance'
import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
import { useRulesQuery } from '@utils/queryHooks/reports'
import { searchFetchToot } from '@utils/queryHooks/search'
import { getAccountStorage } from '@utils/storage/actions'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
@ -19,6 +20,7 @@ const TabSharedReport: React.FC<TabSharedStackScreenProps<'Tab-Shared-Report'>>
params: { account, status }
}
}) => {
console.log('account', account.id)
const { colors } = useTheme()
const { t } = useTranslation(['common', 'screenTabs'])
@ -49,10 +51,19 @@ const TabSharedReport: React.FC<TabSharedStackScreenProps<'Tab-Shared-Report'>>
type='text'
content={t('screenTabs:shared.report.report')}
destructive
onPress={() => {
onPress={async () => {
const body = new FormData()
if (status) {
if (status._remote) {
const fetchedStatus = await searchFetchToot(status.uri)
if (fetchedStatus) {
body.append('status_ids[]', fetchedStatus.id)
}
} else {
body.append('status_ids[]', status.id)
}
}
body.append('account_id', account.id)
status && body.append('status_ids[]', status.id)
comment.length && body.append('comment', comment)
body.append('forward', forward.toString())
body.append('category', categories.find(category => category.selected)?.type || 'other')
@ -71,7 +82,7 @@ const TabSharedReport: React.FC<TabSharedStackScreenProps<'Tab-Shared-Report'>>
/>
)
})
}, [isReporting, comment, forward, categories, rules])
}, [isReporting, comment, forward, categories, rules, account.id])
const localInstance = account?.acct.includes('@')
? account?.acct.includes(`@${getAccountStorage.string('auth.account.domain')}`)

View File

@ -1,4 +1,3 @@
import Button from '@components/Button'
import { HeaderLeft } from '@components/Header'
import Icon from '@components/Icon'
import ComponentSeparator from '@components/Separator'
@ -14,7 +13,7 @@ import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { FlatList, View } from 'react-native'
import { Alert, FlatList, Pressable, View } from 'react-native'
import { Circle } from 'react-native-animated-spinkit'
import { Path, Svg } from 'react-native-svg'
@ -32,7 +31,16 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
useEffect(() => {
navigation.setOptions({
headerTitle: () => (
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<Pressable
style={{ flexDirection: 'row', alignItems: 'center' }}
disabled={!hasRemoteContent}
onPress={() =>
Alert.alert(
t('screenTabs:shared.toot.remoteFetch.title'),
t('screenTabs:shared.toot.remoteFetch.message')
)
}
>
{hasRemoteContent ? (
<Icon
name='Wifi'
@ -48,7 +56,7 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
numberOfLines={1}
children={t('screenTabs:shared.toot.name')}
/>
</View>
</Pressable>
),
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
})
@ -57,7 +65,9 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
const flRef = useRef<FlatList>(null)
const scrolled = useRef(false)
const finalData = useRef<Mastodon.Status[]>([{ ...toot, _level: 0, _remote: false }])
const finalData = useRef<Mastodon.Status[]>([
{ ...toot, _level: 0, _remote: toot._remote }
])
const highlightIndex = useRef<number>(0)
const queryKey: { local: QueryKeyTimeline; remote: QueryKeyTimeline } = {
local: ['Timeline', { page: 'Toot', toot: toot.id, remote: false }],
@ -96,6 +106,7 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
return { pages: [{ body: statuses }] }
},
{
enabled: !toot._remote,
staleTime: 0,
refetchOnMount: true,
onSuccess: data => {
@ -189,16 +200,16 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
{
enabled: toot.account.acct !== toot.account.username, // When on the same instance, these two values are the same
staleTime: 0,
refetchOnMount: false,
refetchOnMount: true,
onSuccess: data => {
if (finalData.current.length < 1 && data.pages[0].body.length < 1) {
navigation.goBack()
return
}
if (finalData.current?.length < data.pages[0].body.length) {
if (finalData.current.length < data.pages[0].body.length) {
finalData.current = data.pages[0].body.map(remote => {
const localMatch = finalData.current?.find(local => local.uri === remote.uri)
const localMatch = finalData.current.find(local => local.uri === remote.uri)
if (localMatch) {
return localMatch
} else {
@ -230,52 +241,6 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
}
)
const empty = () => {
switch (queryLocal.status) {
case 'error':
return (
<>
<Icon name='Frown' size={StyleConstants.Font.Size.L} color={colors.primaryDefault} />
<CustomText
fontStyle='M'
style={{
marginTop: StyleConstants.Spacing.S,
marginBottom: StyleConstants.Spacing.L,
color: colors.primaryDefault
}}
>
{t('componentTimeline:empty.error.message')}
</CustomText>
<Button
type='text'
content={t('componentTimeline:empty.error.button')}
onPress={() => queryLocal.refetch()}
/>
</>
)
case 'success':
return (
<>
<Icon
name='Smartphone'
size={StyleConstants.Font.Size.L}
color={colors.primaryDefault}
/>
<CustomText
fontStyle='M'
style={{
marginTop: StyleConstants.Spacing.S,
marginBottom: StyleConstants.Spacing.L,
color: colors.secondary
}}
>
{t('componentTimeline:empty.success.message')}
</CustomText>
</>
)
}
}
const heights = useRef<(number | undefined)[]>([])
const MAX_LEVEL = 10
const ARC = StyleConstants.Avatar.XS / 4
@ -287,9 +252,9 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
windowSize={7}
data={finalData.current}
renderItem={({ item, index }) => {
const prev = finalData.current?.[index - 1]?._level || 0
const prev = finalData.current[index - 1]?._level || 0
const curr = item._level
const next = finalData.current?.[index + 1]?._level || 0
const next = finalData.current[index + 1]?._level || 0
return (
<View
@ -445,7 +410,7 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
const offset = error.averageItemLength * error.index
flRef.current?.scrollToOffset({ offset })
try {
error.index < (finalData.current.length || 0) &&
error.index < finalData.current.length &&
setTimeout(
() =>
flRef.current?.scrollToIndex({
@ -456,19 +421,6 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
)
} catch {}
}}
ListEmptyComponent={
<View
style={{
flex: 1,
minHeight: '100%',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: colors.backgroundDefault
}}
>
{empty()}
</View>
}
ListFooterComponent={
<View
style={{

View File

@ -3,7 +3,6 @@ import { displayMessage, Message } from '@components/Message'
import { NavigationContainer } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import ScreenAccountSelection from '@screens/AccountSelection'
import ScreenActions from '@screens/Actions'
import ScreenAnnouncements from '@screens/Announcements'
import ScreenCompose from '@screens/Compose'
import ScreenImagesViewer from '@screens/ImageViewer'
@ -261,15 +260,6 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
options={{ headerShown: false }}
/>
<Stack.Screen
name='Screen-Actions'
component={ScreenActions}
options={{
presentation: 'transparentModal',
animation: 'fade',
headerShown: false
}}
/>
<Stack.Screen
name='Screen-Announcements'
component={ScreenAnnouncements}