mirror of https://github.com/tooot-app/app
Add account actions
This commit is contained in:
parent
25a80cc57e
commit
33b0b6b8ff
|
@ -1,6 +1,6 @@
|
||||||
import { Feather } from '@expo/vector-icons'
|
import { Feather } from '@expo/vector-icons'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Pressable, StyleSheet, Text } from 'react-native'
|
import { Pressable, StyleProp, StyleSheet, Text, ViewStyle } from 'react-native'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ type PropsBase = {
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
buttonSize?: 'S' | 'M'
|
buttonSize?: 'S' | 'M'
|
||||||
size?: 'S' | 'M' | 'L'
|
size?: 'S' | 'M' | 'L'
|
||||||
|
style?: StyleProp<ViewStyle>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PropsText extends PropsBase {
|
export interface PropsText extends PropsBase {
|
||||||
|
@ -27,7 +28,8 @@ const ButtonRow: React.FC<PropsText | PropsIcon> = ({
|
||||||
buttonSize = 'M',
|
buttonSize = 'M',
|
||||||
text,
|
text,
|
||||||
icon,
|
icon,
|
||||||
size = 'M'
|
size = 'M',
|
||||||
|
style: customStyle
|
||||||
}) => {
|
}) => {
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
|
||||||
|
@ -35,8 +37,15 @@ const ButtonRow: React.FC<PropsText | PropsIcon> = ({
|
||||||
<Pressable
|
<Pressable
|
||||||
{...(!disabled && { onPress })}
|
{...(!disabled && { onPress })}
|
||||||
style={[
|
style={[
|
||||||
|
customStyle,
|
||||||
styles.button,
|
styles.button,
|
||||||
{
|
{
|
||||||
|
paddingLeft:
|
||||||
|
StyleConstants.Spacing.M -
|
||||||
|
(icon ? StyleConstants.Font.Size[size] / 2 : 0),
|
||||||
|
paddingRight:
|
||||||
|
StyleConstants.Spacing.M -
|
||||||
|
(icon ? StyleConstants.Font.Size[size] / 2 : 0),
|
||||||
borderColor: disabled ? theme.secondary : theme.primary,
|
borderColor: disabled ? theme.secondary : theme.primary,
|
||||||
paddingTop: StyleConstants.Spacing[buttonSize === 'M' ? 'S' : 'XS'],
|
paddingTop: StyleConstants.Spacing[buttonSize === 'M' ? 'S' : 'XS'],
|
||||||
paddingBottom: StyleConstants.Spacing[buttonSize === 'M' ? 'S' : 'XS']
|
paddingBottom: StyleConstants.Spacing[buttonSize === 'M' ? 'S' : 'XS']
|
||||||
|
@ -68,8 +77,6 @@ const ButtonRow: React.FC<PropsText | PropsIcon> = ({
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
button: {
|
button: {
|
||||||
paddingLeft: StyleConstants.Spacing.M,
|
|
||||||
paddingRight: StyleConstants.Spacing.M,
|
|
||||||
borderWidth: 1.25,
|
borderWidth: 1.25,
|
||||||
borderRadius: 100,
|
borderRadius: 100,
|
||||||
alignItems: 'center'
|
alignItems: 'center'
|
||||||
|
|
|
@ -64,7 +64,7 @@ const renderNode = ({
|
||||||
m => m.username === username[1]
|
m => m.username === username[1]
|
||||||
)
|
)
|
||||||
navigation.push('Screen-Shared-Account', {
|
navigation.push('Screen-Shared-Account', {
|
||||||
id: mentions[usernameIndex].id
|
account: mentions[usernameIndex]
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -137,8 +137,9 @@ const TimelineActions: React.FC<Props> = ({
|
||||||
navigation.navigate(getCurrentTab(navigation), {
|
navigation.navigate(getCurrentTab(navigation), {
|
||||||
screen: 'Screen-Shared-Compose',
|
screen: 'Screen-Shared-Compose',
|
||||||
params: {
|
params: {
|
||||||
type: status.visibility === 'direct' ? 'conversation' : 'reply',
|
type: 'reply',
|
||||||
incomingStatus: status
|
incomingStatus: status,
|
||||||
|
visibilityLock: status.visibility === 'direct'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
|
@ -12,10 +12,7 @@ const TimelineAvatar: React.FC<Props> = ({ queryKey, account }) => {
|
||||||
const navigation = useNavigation()
|
const navigation = useNavigation()
|
||||||
// Need to fix go back root
|
// Need to fix go back root
|
||||||
const onPress = useCallback(() => {
|
const onPress = useCallback(() => {
|
||||||
queryKey &&
|
queryKey && navigation.push('Screen-Shared-Account', { account })
|
||||||
navigation.push('Screen-Shared-Account', {
|
|
||||||
id: account.id
|
|
||||||
})
|
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -134,8 +134,7 @@ const TimelineHeaderDefault: React.FC<Props> = ({
|
||||||
{!sameAccount && (
|
{!sameAccount && (
|
||||||
<HeaderDefaultActionsAccount
|
<HeaderDefaultActionsAccount
|
||||||
queryKey={queryKey}
|
queryKey={queryKey}
|
||||||
accountId={status.account.id}
|
account={status.account}
|
||||||
account={status.account.acct}
|
|
||||||
setBottomSheetVisible={setBottomSheetVisible}
|
setBottomSheetVisible={setBottomSheetVisible}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -56,22 +56,20 @@ const fireMutation = async ({
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
queryKey: QueryKey.Timeline
|
queryKey?: QueryKey.Timeline
|
||||||
accountId: string
|
account: Mastodon.Account
|
||||||
account: string
|
|
||||||
setBottomSheetVisible: React.Dispatch<React.SetStateAction<boolean>>
|
setBottomSheetVisible: React.Dispatch<React.SetStateAction<boolean>>
|
||||||
}
|
}
|
||||||
|
|
||||||
const HeaderDefaultActionsAccount: React.FC<Props> = ({
|
const HeaderDefaultActionsAccount: React.FC<Props> = ({
|
||||||
queryKey,
|
queryKey,
|
||||||
accountId,
|
|
||||||
account,
|
account,
|
||||||
setBottomSheetVisible
|
setBottomSheetVisible
|
||||||
}) => {
|
}) => {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const { mutate } = useMutation(fireMutation, {
|
const { mutate } = useMutation(fireMutation, {
|
||||||
onSettled: () => {
|
onSettled: () => {
|
||||||
queryClient.invalidateQueries(queryKey)
|
queryKey && queryClient.invalidateQueries(queryKey)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -83,35 +81,35 @@ const HeaderDefaultActionsAccount: React.FC<Props> = ({
|
||||||
setBottomSheetVisible(false)
|
setBottomSheetVisible(false)
|
||||||
mutate({
|
mutate({
|
||||||
type: 'mute',
|
type: 'mute',
|
||||||
id: accountId,
|
id: account.id,
|
||||||
stateKey: 'muting'
|
stateKey: 'muting'
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
iconFront='eye-off'
|
iconFront='eye-off'
|
||||||
title={`隐藏 @${account} 的嘟嘟`}
|
title={`隐藏 @${account.acct} 的嘟嘟`}
|
||||||
/>
|
/>
|
||||||
<MenuRow
|
<MenuRow
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
setBottomSheetVisible(false)
|
setBottomSheetVisible(false)
|
||||||
mutate({
|
mutate({
|
||||||
type: 'block',
|
type: 'block',
|
||||||
id: accountId,
|
id: account.id,
|
||||||
stateKey: 'blocking'
|
stateKey: 'blocking'
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
iconFront='x-circle'
|
iconFront='x-circle'
|
||||||
title={`屏蔽用户 @${account}`}
|
title={`屏蔽用户 @${account.acct}`}
|
||||||
/>
|
/>
|
||||||
<MenuRow
|
<MenuRow
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
setBottomSheetVisible(false)
|
setBottomSheetVisible(false)
|
||||||
mutate({
|
mutate({
|
||||||
type: 'reports',
|
type: 'reports',
|
||||||
id: accountId
|
id: account.id
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
iconFront='flag'
|
iconFront='flag'
|
||||||
title={`举报 @${account}`}
|
title={`举报 @${account.acct}`}
|
||||||
/>
|
/>
|
||||||
</MenuContainer>
|
</MenuContainer>
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,7 +6,6 @@ import {
|
||||||
Text,
|
Text,
|
||||||
View
|
View
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import { useNavigation } from '@react-navigation/native'
|
|
||||||
import { Feather } from '@expo/vector-icons'
|
import { Feather } from '@expo/vector-icons'
|
||||||
import Emojis from '@components/Timelines/Timeline/Shared/Emojis'
|
import Emojis from '@components/Timelines/Timeline/Shared/Emojis'
|
||||||
import relativeTime from '@utils/relativeTime'
|
import relativeTime from '@utils/relativeTime'
|
||||||
|
@ -29,7 +28,6 @@ const TimelineHeaderNotification: React.FC<Props> = ({ notification }) => {
|
||||||
const account = notification.account.acct
|
const account = notification.account.acct
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
|
||||||
const navigation = useNavigation()
|
|
||||||
const [since, setSince] = useState(relativeTime(notification.created_at))
|
const [since, setSince] = useState(relativeTime(notification.created_at))
|
||||||
|
|
||||||
const { status, data, refetch } = useQuery(
|
const { status, data, refetch } = useQuery(
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import React, { useReducer, useRef } from 'react'
|
import React, { useEffect, useReducer, useRef, useState } from 'react'
|
||||||
import { Animated, ScrollView } from 'react-native'
|
import { Animated, ScrollView } from 'react-native'
|
||||||
|
|
||||||
// import * as relationshipsSlice from 'src/stacks/common/relationshipsSlice'
|
|
||||||
|
|
||||||
import { useQuery } from 'react-query'
|
import { useQuery } from 'react-query'
|
||||||
import { accountFetch } from '@utils/fetches/accountFetch'
|
import { accountFetch } from '@utils/fetches/accountFetch'
|
||||||
import AccountToots from '@screens/Shared/Account/Toots'
|
import AccountToots from '@screens/Shared/Account/Toots'
|
||||||
|
@ -10,15 +8,24 @@ import AccountHeader from '@screens/Shared/Account/Header'
|
||||||
import AccountInformation from '@screens/Shared/Account/Information'
|
import AccountInformation from '@screens/Shared/Account/Information'
|
||||||
import AccountNav from './Account/Nav'
|
import AccountNav from './Account/Nav'
|
||||||
import AccountSegmentedControl from './Account/SegmentedControl'
|
import AccountSegmentedControl from './Account/SegmentedControl'
|
||||||
|
import { HeaderRight } from '@root/components/Header'
|
||||||
|
import BottomSheet from '@root/components/BottomSheet'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
import {
|
||||||
|
getLocalAccountId,
|
||||||
|
getLocalUrl
|
||||||
|
} from '@root/utils/slices/instancesSlice'
|
||||||
|
import HeaderDefaultActionsAccount from '@root/components/Timelines/Timeline/Shared/HeaderDefault/ActionsAccount'
|
||||||
|
|
||||||
// Moved account example: https://m.cmx.im/web/accounts/27812
|
// Moved account example: https://m.cmx.im/web/accounts/27812
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
route: {
|
route: {
|
||||||
params: {
|
params: {
|
||||||
id: string
|
account: Mastodon.Account
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
navigation: any
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AccountState = {
|
export type AccountState = {
|
||||||
|
@ -65,10 +72,13 @@ const accountReducer = (
|
||||||
|
|
||||||
const ScreenSharedAccount: React.FC<Props> = ({
|
const ScreenSharedAccount: React.FC<Props> = ({
|
||||||
route: {
|
route: {
|
||||||
params: { id }
|
params: { account }
|
||||||
}
|
},
|
||||||
|
navigation
|
||||||
}) => {
|
}) => {
|
||||||
const { data } = useQuery(['Account', { id }], accountFetch)
|
const localAccountId = useSelector(getLocalAccountId)
|
||||||
|
const localDomain = useSelector(getLocalUrl)
|
||||||
|
const { data } = useQuery(['Account', { id: account.id }], accountFetch)
|
||||||
|
|
||||||
// const stateRelationships = useSelector(relationshipsState)
|
// const stateRelationships = useSelector(relationshipsState)
|
||||||
const scrollY = useRef(new Animated.Value(0)).current
|
const scrollY = useRef(new Animated.Value(0)).current
|
||||||
|
@ -77,6 +87,20 @@ const ScreenSharedAccount: React.FC<Props> = ({
|
||||||
AccountInitialState
|
AccountInitialState
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const [modalVisible, setBottomSheetVisible] = useState(false)
|
||||||
|
useEffect(() => {
|
||||||
|
const updateHeaderRight = () =>
|
||||||
|
navigation.setOptions({
|
||||||
|
headerRight: () => (
|
||||||
|
<HeaderRight
|
||||||
|
icon='more-horizontal'
|
||||||
|
onPress={() => setBottomSheetVisible(true)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
return updateHeaderRight()
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<AccountNav
|
<AccountNav
|
||||||
|
@ -106,9 +130,22 @@ const ScreenSharedAccount: React.FC<Props> = ({
|
||||||
<AccountToots
|
<AccountToots
|
||||||
accountState={accountState}
|
accountState={accountState}
|
||||||
accountDispatch={accountDispatch}
|
accountDispatch={accountDispatch}
|
||||||
id={id}
|
id={account.id}
|
||||||
/>
|
/>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
|
<BottomSheet
|
||||||
|
visible={modalVisible}
|
||||||
|
handleDismiss={() => setBottomSheetVisible(false)}
|
||||||
|
>
|
||||||
|
{/* 添加到列表 */}
|
||||||
|
{localAccountId !== account.id && (
|
||||||
|
<HeaderDefaultActionsAccount
|
||||||
|
account={account}
|
||||||
|
setBottomSheetVisible={setBottomSheetVisible}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</BottomSheet>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { createRef, Dispatch, useEffect, useState } from 'react'
|
import React, { createRef, Dispatch, useEffect, useMemo, useState } from 'react'
|
||||||
import { Animated, Image, StyleSheet, Text, View } from 'react-native'
|
import { Animated, Image, StyleSheet, Text, View } from 'react-native'
|
||||||
import { createShimmerPlaceholder } from 'react-native-shimmer-placeholder'
|
import { createShimmerPlaceholder } from 'react-native-shimmer-placeholder'
|
||||||
import { Feather } from '@expo/vector-icons'
|
import { Feather } from '@expo/vector-icons'
|
||||||
|
@ -10,6 +10,41 @@ import { useTranslation } from 'react-i18next'
|
||||||
import Emojis from '@components/Timelines/Timeline/Shared/Emojis'
|
import Emojis from '@components/Timelines/Timeline/Shared/Emojis'
|
||||||
import { LinearGradient } from 'expo-linear-gradient'
|
import { LinearGradient } from 'expo-linear-gradient'
|
||||||
import { AccountAction } from '../Account'
|
import { AccountAction } from '../Account'
|
||||||
|
import { ButtonRow } from '@root/components/Button'
|
||||||
|
import { useMutation, useQuery, useQueryClient } from 'react-query'
|
||||||
|
import { relationshipFetch } from '@root/utils/fetches/relationshipFetch'
|
||||||
|
import client from '@root/api/client'
|
||||||
|
import { useNavigation } from '@react-navigation/native'
|
||||||
|
import getCurrentTab from '@root/utils/getCurrentTab'
|
||||||
|
|
||||||
|
const fireMutation = async ({
|
||||||
|
type,
|
||||||
|
id,
|
||||||
|
stateKey,
|
||||||
|
prevState
|
||||||
|
}: {
|
||||||
|
type: 'follow'
|
||||||
|
id: string
|
||||||
|
stateKey: 'following'
|
||||||
|
prevState: boolean
|
||||||
|
}) => {
|
||||||
|
let res
|
||||||
|
switch (type) {
|
||||||
|
case 'follow':
|
||||||
|
res = await client({
|
||||||
|
method: 'post',
|
||||||
|
instance: 'local',
|
||||||
|
url: `accounts/${id}/${prevState ? 'un' : ''}${type}`
|
||||||
|
})
|
||||||
|
|
||||||
|
if (res.body[stateKey] === !prevState) {
|
||||||
|
return Promise.resolve()
|
||||||
|
} else {
|
||||||
|
return Promise.reject()
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
accountDispatch?: Dispatch<AccountAction>
|
accountDispatch?: Dispatch<AccountAction>
|
||||||
|
@ -17,10 +52,42 @@ export interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
const AccountInformation: React.FC<Props> = ({ accountDispatch, account }) => {
|
const AccountInformation: React.FC<Props> = ({ accountDispatch, account }) => {
|
||||||
|
const navigation = useNavigation()
|
||||||
const { t } = useTranslation('sharedAccount')
|
const { t } = useTranslation('sharedAccount')
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const [avatarLoaded, setAvatarLoaded] = useState(false)
|
const [avatarLoaded, setAvatarLoaded] = useState(false)
|
||||||
|
|
||||||
|
const relationshipQueryKey = ['Relationship', { id: account?.id }]
|
||||||
|
const { status, data, refetch } = useQuery(
|
||||||
|
relationshipQueryKey,
|
||||||
|
relationshipFetch,
|
||||||
|
{
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
useEffect(() => {
|
||||||
|
if (account?.id) {
|
||||||
|
refetch()
|
||||||
|
}
|
||||||
|
}, [account])
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
const { mutate, status: mutateStatus } = useMutation(fireMutation, {
|
||||||
|
onMutate: () => {
|
||||||
|
queryClient.cancelQueries(relationshipQueryKey)
|
||||||
|
const oldData = queryClient.getQueryData(relationshipQueryKey)
|
||||||
|
|
||||||
|
queryClient.setQueryData(relationshipQueryKey, (old: any) => {
|
||||||
|
old && (old.following = !old?.following)
|
||||||
|
return old
|
||||||
|
})
|
||||||
|
|
||||||
|
return oldData
|
||||||
|
},
|
||||||
|
onError: (err, _, oldData) => {
|
||||||
|
queryClient.setQueryData(relationshipQueryKey, oldData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const ShimmerPlaceholder = createShimmerPlaceholder(LinearGradient)
|
const ShimmerPlaceholder = createShimmerPlaceholder(LinearGradient)
|
||||||
const shimmerAvatarRef = createRef<any>()
|
const shimmerAvatarRef = createRef<any>()
|
||||||
const shimmerNameRef = createRef<any>()
|
const shimmerNameRef = createRef<any>()
|
||||||
|
@ -44,9 +111,35 @@ const AccountInformation: React.FC<Props> = ({ accountDispatch, account }) => {
|
||||||
Animated.loop(informationAnimated).start()
|
Animated.loop(informationAnimated).start()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const followingButton = useMemo(
|
||||||
|
() => (
|
||||||
|
<ButtonRow
|
||||||
|
{...(data
|
||||||
|
? status !== 'success' ||
|
||||||
|
(mutateStatus !== 'success' && mutateStatus !== 'idle')
|
||||||
|
? { icon: 'loader' }
|
||||||
|
: { text: `${data.following ? '正在' : ''}关注` }
|
||||||
|
: { icon: 'loader' })}
|
||||||
|
onPress={() =>
|
||||||
|
mutate({
|
||||||
|
type: 'follow',
|
||||||
|
id: account!.id,
|
||||||
|
stateKey: 'following',
|
||||||
|
prevState: data!.following
|
||||||
|
})
|
||||||
|
}
|
||||||
|
disabled={
|
||||||
|
status !== 'success' ||
|
||||||
|
(mutateStatus !== 'success' && mutateStatus !== 'idle')
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
[data, status, mutateStatus]
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
style={styles.information}
|
style={styles.base}
|
||||||
onLayout={({ nativeEvent }) =>
|
onLayout={({ nativeEvent }) =>
|
||||||
accountDispatch &&
|
accountDispatch &&
|
||||||
accountDispatch({
|
accountDispatch({
|
||||||
|
@ -59,18 +152,36 @@ const AccountInformation: React.FC<Props> = ({ accountDispatch, account }) => {
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{/* <Text>Moved or not: {account.moved}</Text> */}
|
{/* <Text>Moved or not: {account.moved}</Text> */}
|
||||||
<ShimmerPlaceholder
|
<View style={styles.avatarAndActions}>
|
||||||
ref={shimmerAvatarRef}
|
<ShimmerPlaceholder
|
||||||
visible={avatarLoaded}
|
ref={shimmerAvatarRef}
|
||||||
width={StyleConstants.Avatar.L}
|
visible={avatarLoaded}
|
||||||
height={StyleConstants.Avatar.L}
|
width={StyleConstants.Avatar.L}
|
||||||
>
|
height={StyleConstants.Avatar.L}
|
||||||
<Image
|
>
|
||||||
source={{ uri: account?.avatar }}
|
<Image
|
||||||
style={styles.avatar}
|
source={{ uri: account?.avatar }}
|
||||||
onLoadEnd={() => setAvatarLoaded(true)}
|
style={styles.avatar}
|
||||||
/>
|
onLoadEnd={() => setAvatarLoaded(true)}
|
||||||
</ShimmerPlaceholder>
|
/>
|
||||||
|
</ShimmerPlaceholder>
|
||||||
|
<View style={styles.actions}>
|
||||||
|
<ButtonRow
|
||||||
|
icon='mail'
|
||||||
|
onPress={() =>
|
||||||
|
navigation.navigate(getCurrentTab(navigation), {
|
||||||
|
screen: 'Screen-Shared-Compose',
|
||||||
|
params: {
|
||||||
|
type: 'conversation',
|
||||||
|
incomingStatus: { account }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
style={{ marginRight: StyleConstants.Spacing.S }}
|
||||||
|
/>
|
||||||
|
{followingButton}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
<ShimmerPlaceholder
|
<ShimmerPlaceholder
|
||||||
ref={shimmerNameRef}
|
ref={shimmerNameRef}
|
||||||
|
@ -261,15 +372,23 @@ const AccountInformation: React.FC<Props> = ({ accountDispatch, account }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
information: {
|
base: {
|
||||||
marginTop: -StyleConstants.Spacing.Global.PagePadding * 3,
|
marginTop: -StyleConstants.Spacing.Global.PagePadding * 3,
|
||||||
padding: StyleConstants.Spacing.Global.PagePadding
|
padding: StyleConstants.Spacing.Global.PagePadding
|
||||||
},
|
},
|
||||||
|
avatarAndActions: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between'
|
||||||
|
},
|
||||||
avatar: {
|
avatar: {
|
||||||
width: StyleConstants.Avatar.L,
|
width: StyleConstants.Avatar.L,
|
||||||
height: StyleConstants.Avatar.L,
|
height: StyleConstants.Avatar.L,
|
||||||
borderRadius: 8
|
borderRadius: 8
|
||||||
},
|
},
|
||||||
|
actions: {
|
||||||
|
alignSelf: 'flex-end',
|
||||||
|
flexDirection: 'row'
|
||||||
|
},
|
||||||
display_name: {
|
display_name: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
marginTop: StyleConstants.Spacing.M,
|
marginTop: StyleConstants.Spacing.M,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { Dispatch } from 'react'
|
import React, { Dispatch, useCallback } from 'react'
|
||||||
import { Dimensions, StyleSheet } from 'react-native'
|
import { Dimensions, StyleSheet } from 'react-native'
|
||||||
import { TabView } from 'react-native-tab-view'
|
import { TabView } from 'react-native-tab-view'
|
||||||
|
|
||||||
|
@ -23,16 +23,18 @@ const AccountToots: React.FC<Props> = ({
|
||||||
{ key: 'Account_Media' }
|
{ key: 'Account_Media' }
|
||||||
]
|
]
|
||||||
|
|
||||||
const renderScene = ({
|
const renderScene = useCallback(
|
||||||
route
|
({
|
||||||
}: {
|
route
|
||||||
route: {
|
}: {
|
||||||
key: App.Pages
|
route: {
|
||||||
}
|
key: App.Pages
|
||||||
}) => {
|
}
|
||||||
console.log(route)
|
}) => {
|
||||||
return <Timeline page={route.key} account={id} disableRefresh />
|
return <Timeline page={route.key} account={id} disableRefresh />
|
||||||
}
|
},
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TabView
|
<TabView
|
||||||
|
|
|
@ -173,14 +173,15 @@ const composeInitialState: ComposeState = {
|
||||||
}
|
}
|
||||||
const composeExistingState = ({
|
const composeExistingState = ({
|
||||||
type,
|
type,
|
||||||
incomingStatus
|
incomingStatus,
|
||||||
|
visibilityLock
|
||||||
}: {
|
}: {
|
||||||
type: 'reply' | 'conversation' | 'edit'
|
type: 'reply' | 'conversation' | 'edit'
|
||||||
incomingStatus: Mastodon.Status
|
incomingStatus: Mastodon.Status
|
||||||
|
visibilityLock?: boolean
|
||||||
}): ComposeState => {
|
}): ComposeState => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'edit':
|
case 'edit':
|
||||||
console.log(incomingStatus)
|
|
||||||
return {
|
return {
|
||||||
...composeInitialState,
|
...composeInitialState,
|
||||||
...(incomingStatus.spoiler_text?.length && {
|
...(incomingStatus.spoiler_text?.length && {
|
||||||
|
@ -226,12 +227,12 @@ const composeExistingState = ({
|
||||||
...(incomingStatus.visibility === 'direct' && { visibilityLock: true })
|
...(incomingStatus.visibility === 'direct' && { visibilityLock: true })
|
||||||
}
|
}
|
||||||
case 'reply':
|
case 'reply':
|
||||||
case 'conversation':
|
|
||||||
const actualStatus = incomingStatus.reblog || incomingStatus
|
const actualStatus = incomingStatus.reblog || incomingStatus
|
||||||
const allMentions = actualStatus.mentions.map(
|
const allMentions = Array.isArray(actualStatus.mentions)
|
||||||
mention => `@${mention.acct}`
|
? actualStatus.mentions.map(mention => `@${mention.acct}`)
|
||||||
)
|
: []
|
||||||
let replyPlaceholder = allMentions.join(' ')
|
let replyPlaceholder = allMentions.join(' ')
|
||||||
|
|
||||||
if (replyPlaceholder.length === 0) {
|
if (replyPlaceholder.length === 0) {
|
||||||
replyPlaceholder = `@${actualStatus.account.acct} `
|
replyPlaceholder = `@${actualStatus.account.acct} `
|
||||||
} else {
|
} else {
|
||||||
|
@ -245,11 +246,23 @@ const composeExistingState = ({
|
||||||
formatted: undefined,
|
formatted: undefined,
|
||||||
selection: { start: 0, end: 0 }
|
selection: { start: 0, end: 0 }
|
||||||
},
|
},
|
||||||
...(type === 'conversation' && {
|
...(visibilityLock && {
|
||||||
visibility: 'direct',
|
visibility: 'direct',
|
||||||
visibilityLock: true
|
visibilityLock: true
|
||||||
}),
|
}),
|
||||||
replyToStatus: incomingStatus.reblog || incomingStatus
|
replyToStatus: actualStatus
|
||||||
|
}
|
||||||
|
case 'conversation':
|
||||||
|
return {
|
||||||
|
...composeInitialState,
|
||||||
|
text: {
|
||||||
|
count: incomingStatus.account.acct.length + 2,
|
||||||
|
raw: `@${incomingStatus.account.acct} `,
|
||||||
|
formatted: undefined,
|
||||||
|
selection: { start: 0, end: 0 }
|
||||||
|
},
|
||||||
|
visibility: 'direct',
|
||||||
|
visibilityLock: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -309,6 +322,7 @@ export interface Props {
|
||||||
| {
|
| {
|
||||||
type?: 'reply' | 'conversation' | 'edit'
|
type?: 'reply' | 'conversation' | 'edit'
|
||||||
incomingStatus: Mastodon.Status
|
incomingStatus: Mastodon.Status
|
||||||
|
visibilityLock?: boolean
|
||||||
}
|
}
|
||||||
| undefined
|
| undefined
|
||||||
}
|
}
|
||||||
|
@ -342,7 +356,8 @@ const Compose: React.FC<Props> = ({ route: { params }, navigation }) => {
|
||||||
params?.type && params?.incomingStatus
|
params?.type && params?.incomingStatus
|
||||||
? composeExistingState({
|
? composeExistingState({
|
||||||
type: params.type,
|
type: params.type,
|
||||||
incomingStatus: params.incomingStatus
|
incomingStatus: params.incomingStatus,
|
||||||
|
visibilityLock: params.visibilityLock
|
||||||
})
|
})
|
||||||
: {
|
: {
|
||||||
...composeInitialState,
|
...composeInitialState,
|
||||||
|
@ -372,7 +387,6 @@ const Compose: React.FC<Props> = ({ route: { params }, navigation }) => {
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
case 'reply':
|
case 'reply':
|
||||||
case 'conversation':
|
|
||||||
const actualStatus =
|
const actualStatus =
|
||||||
params.incomingStatus.reblog || params.incomingStatus
|
params.incomingStatus.reblog || params.incomingStatus
|
||||||
const allMentions = actualStatus.mentions.map(
|
const allMentions = actualStatus.mentions.map(
|
||||||
|
@ -391,6 +405,14 @@ const Compose: React.FC<Props> = ({ route: { params }, navigation }) => {
|
||||||
disableDebounce: true
|
disableDebounce: true
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
|
case 'conversation':
|
||||||
|
formatText({
|
||||||
|
textInput: 'text',
|
||||||
|
composeDispatch,
|
||||||
|
content: `@${params.incomingStatus.account.acct} `,
|
||||||
|
disableDebounce: true
|
||||||
|
})
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}, [params?.type])
|
}, [params?.type])
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ const ComposeReply: React.FC = () => {
|
||||||
<View style={[styles.status, { borderTopColor: theme.border }]}>
|
<View style={[styles.status, { borderTopColor: theme.border }]}>
|
||||||
<TimelineAvatar account={replyToStatus!.account} />
|
<TimelineAvatar account={replyToStatus!.account} />
|
||||||
<View style={styles.details}>
|
<View style={styles.details}>
|
||||||
<TimelineHeaderDefault status={replyToStatus!} />
|
<TimelineHeaderDefault status={replyToStatus!} sameAccount={false} />
|
||||||
{replyToStatus!.content.length > 0 && (
|
{replyToStatus!.content.length > 0 && (
|
||||||
<TimelineContent status={replyToStatus!} />
|
<TimelineContent status={replyToStatus!} />
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -194,7 +194,7 @@ const ComposeRoot: React.FC = () => {
|
||||||
<FlatList
|
<FlatList
|
||||||
keyboardShouldPersistTaps='handled'
|
keyboardShouldPersistTaps='handled'
|
||||||
ListHeaderComponent={<ComposeRootHeader />}
|
ListHeaderComponent={<ComposeRootHeader />}
|
||||||
ListFooterComponent={<ComposeRootFooter textInputRef={textInputRef} />}
|
ListFooterComponent={<ComposeRootFooter />}
|
||||||
ListEmptyComponent={listEmpty}
|
ListEmptyComponent={listEmpty}
|
||||||
data={data as Mastodon.Account[] & Mastodon.Tag[]}
|
data={data as Mastodon.Account[] & Mastodon.Tag[]}
|
||||||
keyExtractor={listKey}
|
keyExtractor={listKey}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { useContext } from 'react'
|
import React, { useContext } from 'react'
|
||||||
import { StyleSheet, TextInput, View } from 'react-native'
|
import { StyleSheet, View } from 'react-native'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { ComposeContext } from '@screens/Shared/Compose'
|
import { ComposeContext } from '@screens/Shared/Compose'
|
||||||
import ComposeAttachments from '@screens/Shared/Compose/Attachments'
|
import ComposeAttachments from '@screens/Shared/Compose/Attachments'
|
||||||
|
@ -7,18 +7,14 @@ import ComposeEmojis from '@screens/Shared/Compose/Emojis'
|
||||||
import ComposePoll from '@screens/Shared/Compose/Poll'
|
import ComposePoll from '@screens/Shared/Compose/Poll'
|
||||||
import ComposeReply from '@screens/Shared/Compose/Reply'
|
import ComposeReply from '@screens/Shared/Compose/Reply'
|
||||||
|
|
||||||
export interface Props {
|
const ComposeRootFooter: React.FC = () => {
|
||||||
textInputRef: React.RefObject<TextInput>
|
|
||||||
}
|
|
||||||
|
|
||||||
const ComposeRootFooter: React.FC<Props> = ({ textInputRef }) => {
|
|
||||||
const { composeState } = useContext(ComposeContext)
|
const { composeState } = useContext(ComposeContext)
|
||||||
|
console.log(composeState)
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{composeState.emoji.active && (
|
{composeState.emoji.active && (
|
||||||
<View style={styles.emojis}>
|
<View style={styles.emojis}>
|
||||||
<ComposeEmojis textInputRef={textInputRef} />
|
<ComposeEmojis />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
@ -157,9 +157,7 @@ const ScreenSharedSearch: React.FC = () => {
|
||||||
]}
|
]}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
navigation.goBack()
|
navigation.goBack()
|
||||||
navigation.push('Screen-Shared-Account', {
|
navigation.push('Screen-Shared-Account', { account: item })
|
||||||
id: item.id
|
|
||||||
})
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
|
|
Loading…
Reference in New Issue