mirror of
https://github.com/tooot-app/app
synced 2024-12-22 07:34:06 +01:00
Fixed #548
This commit is contained in:
parent
213328ef1a
commit
36bbe5bdbd
@ -407,12 +407,12 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
|
||||
<Stack.Screen
|
||||
name='Screen-Compose-DraftsList'
|
||||
component={ComposeDraftsList}
|
||||
options={{ headerShown: false, presentation: 'modal' }}
|
||||
options={{ presentation: 'modal' }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name='Screen-Compose-EditAttachment'
|
||||
component={ComposeEditAttachment}
|
||||
options={{ headerShown: false, presentation: 'modal' }}
|
||||
options={{ presentation: 'modal' }}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
</ComposeContext.Provider>
|
||||
|
@ -1,49 +1,227 @@
|
||||
import apiInstance from '@api/instance'
|
||||
import { HeaderLeft } from '@components/Header'
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||
import Icon from '@components/Icon'
|
||||
import ComponentSeparator from '@components/Separator'
|
||||
import CustomText from '@components/Text'
|
||||
import HeaderSharedCreated from '@components/Timeline/Shared/HeaderShared/Created'
|
||||
import { useAppDispatch } from '@root/store'
|
||||
import { ScreenComposeStackScreenProps } from '@utils/navigation/navigators'
|
||||
import React, { useCallback } from 'react'
|
||||
import { getInstanceDrafts, removeInstanceDraft } from '@utils/slices/instancesSlice'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useContext, useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import ComposeDraftsListRoot from './DraftsList/Root'
|
||||
import { Dimensions, Modal, Platform, Pressable, View } from 'react-native'
|
||||
import FastImage from 'react-native-fast-image'
|
||||
import { PanGestureHandler } from 'react-native-gesture-handler'
|
||||
import { SwipeListView } from 'react-native-swipe-list-view'
|
||||
import { useSelector } from 'react-redux'
|
||||
import ComposeContext from './utils/createContext'
|
||||
import { formatText } from './utils/processText'
|
||||
import { ComposeStateDraft, ExtendedAttachment } from './utils/types'
|
||||
|
||||
const Stack = createNativeStackNavigator()
|
||||
|
||||
const ComposeDraftsList: React.FC<
|
||||
ScreenComposeStackScreenProps<'Screen-Compose-DraftsList'>
|
||||
> = ({
|
||||
const ComposeDraftsList: React.FC<ScreenComposeStackScreenProps<'Screen-Compose-DraftsList'>> = ({
|
||||
navigation,
|
||||
route: {
|
||||
params: { timestamp }
|
||||
},
|
||||
navigation
|
||||
}
|
||||
}) => {
|
||||
const { colors } = useTheme()
|
||||
const { t } = useTranslation('screenCompose')
|
||||
|
||||
const children = useCallback(
|
||||
() => <ComposeDraftsListRoot timestamp={timestamp} />,
|
||||
[]
|
||||
)
|
||||
const headerLeft = useCallback(
|
||||
() => (
|
||||
<HeaderLeft
|
||||
type='icon'
|
||||
content='ChevronDown'
|
||||
onPress={() => navigation.goBack()}
|
||||
/>
|
||||
),
|
||||
[]
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
title: t('content.draftsList.header.title'),
|
||||
headerLeft: () => (
|
||||
<HeaderLeft type='icon' content='ChevronDown' onPress={() => navigation.goBack()} />
|
||||
)
|
||||
})
|
||||
}, [])
|
||||
|
||||
const { composeDispatch } = useContext(ComposeContext)
|
||||
const instanceDrafts = useSelector(getInstanceDrafts)?.filter(
|
||||
draft => draft.timestamp !== timestamp
|
||||
)
|
||||
const [checkingAttachments, setCheckingAttachments] = useState(false)
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
const actionWidth = StyleConstants.Font.Size.L + StyleConstants.Spacing.Global.PagePadding * 4
|
||||
|
||||
return (
|
||||
<Stack.Navigator>
|
||||
<Stack.Screen
|
||||
name='Screen-Compose-EditAttachment-Root'
|
||||
children={children}
|
||||
options={{
|
||||
headerLeft,
|
||||
title: t('content.draftsList.header.title'),
|
||||
headerShadowVisible: false
|
||||
<>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginHorizontal: StyleConstants.Spacing.Global.PagePadding,
|
||||
padding: StyleConstants.Spacing.S,
|
||||
borderColor: colors.border,
|
||||
borderWidth: 1,
|
||||
borderRadius: StyleConstants.Spacing.S
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name='AlertTriangle'
|
||||
color={colors.secondary}
|
||||
size={StyleConstants.Font.Size.M}
|
||||
style={{ marginRight: StyleConstants.Spacing.S }}
|
||||
/>
|
||||
<CustomText fontStyle='S' style={{ flexShrink: 1, color: colors.secondary }}>
|
||||
{t('content.draftsList.warning')}
|
||||
</CustomText>
|
||||
</View>
|
||||
<PanGestureHandler enabled={Platform.OS === 'ios'}>
|
||||
<SwipeListView
|
||||
data={instanceDrafts}
|
||||
renderItem={({ item }: { item: ComposeStateDraft }) => {
|
||||
return (
|
||||
<Pressable
|
||||
accessibilityHint={t('content.draftsList.content.accessibilityHint')}
|
||||
style={{
|
||||
flex: 1,
|
||||
padding: StyleConstants.Spacing.Global.PagePadding,
|
||||
backgroundColor: colors.backgroundDefault
|
||||
}}
|
||||
onPress={async () => {
|
||||
setCheckingAttachments(true)
|
||||
let tempDraft = item
|
||||
let tempUploads: ExtendedAttachment[] = []
|
||||
if (item.attachments && item.attachments.uploads.length) {
|
||||
for (const attachment of item.attachments.uploads) {
|
||||
await apiInstance<Mastodon.Attachment>({
|
||||
method: 'get',
|
||||
url: `media/${attachment.remote?.id}`
|
||||
})
|
||||
.then(res => {
|
||||
if (res.body.id === attachment.remote?.id) {
|
||||
tempUploads.push(attachment)
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
tempDraft = {
|
||||
...tempDraft,
|
||||
attachments: { ...item.attachments, uploads: tempUploads }
|
||||
}
|
||||
}
|
||||
|
||||
tempDraft.spoiler?.length &&
|
||||
formatText({ textInput: 'text', composeDispatch, content: tempDraft.spoiler })
|
||||
tempDraft.text?.length &&
|
||||
formatText({ textInput: 'text', composeDispatch, content: tempDraft.text })
|
||||
composeDispatch({
|
||||
type: 'loadDraft',
|
||||
payload: tempDraft
|
||||
})
|
||||
dispatch(removeInstanceDraft(item.timestamp))
|
||||
navigation.goBack()
|
||||
}}
|
||||
>
|
||||
<View style={{ flex: 1 }}>
|
||||
<HeaderSharedCreated created_at={item.timestamp} />
|
||||
<CustomText
|
||||
fontStyle='M'
|
||||
numberOfLines={2}
|
||||
style={{
|
||||
marginTop: StyleConstants.Spacing.XS,
|
||||
color: colors.primaryDefault
|
||||
}}
|
||||
>
|
||||
{item.text || item.spoiler || t('content.draftsList.content.textEmpty')}
|
||||
</CustomText>
|
||||
{item.attachments?.uploads.length ? (
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
marginTop: StyleConstants.Spacing.S
|
||||
}}
|
||||
>
|
||||
{item.attachments.uploads.map((attachment, index) => (
|
||||
<FastImage
|
||||
key={index}
|
||||
style={{
|
||||
width:
|
||||
(Dimensions.get('screen').width -
|
||||
StyleConstants.Spacing.Global.PagePadding * 2 -
|
||||
StyleConstants.Spacing.S * 3) /
|
||||
4,
|
||||
height:
|
||||
(Dimensions.get('screen').width -
|
||||
StyleConstants.Spacing.Global.PagePadding * 2 -
|
||||
StyleConstants.Spacing.S * 3) /
|
||||
4,
|
||||
marginLeft: index !== 0 ? StyleConstants.Spacing.S : 0
|
||||
}}
|
||||
source={{
|
||||
uri: attachment.local?.thumbnail || attachment.remote?.preview_url
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
</Pressable>
|
||||
)
|
||||
}}
|
||||
renderHiddenItem={({ item }) => (
|
||||
<Pressable
|
||||
style={{
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'flex-end',
|
||||
backgroundColor: colors.red
|
||||
}}
|
||||
onPress={() => dispatch(removeInstanceDraft(item.timestamp))}
|
||||
children={
|
||||
<View
|
||||
style={{
|
||||
flexBasis:
|
||||
StyleConstants.Font.Size.L + StyleConstants.Spacing.Global.PagePadding * 4,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
}}
|
||||
children={
|
||||
<Icon
|
||||
name='Trash'
|
||||
size={StyleConstants.Font.Size.L}
|
||||
color={colors.primaryOverlay}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
disableRightSwipe={true}
|
||||
rightOpenValue={-actionWidth}
|
||||
previewOpenValue={-actionWidth / 2}
|
||||
ItemSeparatorComponent={ComponentSeparator}
|
||||
keyExtractor={item => item.timestamp.toString()}
|
||||
/>
|
||||
</PanGestureHandler>
|
||||
<Modal
|
||||
transparent
|
||||
animationType='fade'
|
||||
visible={checkingAttachments}
|
||||
children={
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: colors.backgroundOverlayInvert
|
||||
}}
|
||||
children={
|
||||
<CustomText
|
||||
fontStyle='M'
|
||||
children={t('content.draftsList.checkAttachment')}
|
||||
style={{ color: colors.primaryOverlay }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,223 +0,0 @@
|
||||
import apiInstance from '@api/instance'
|
||||
import Icon from '@components/Icon'
|
||||
import ComponentSeparator from '@components/Separator'
|
||||
import CustomText from '@components/Text'
|
||||
import HeaderSharedCreated from '@components/Timeline/Shared/HeaderShared/Created'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { useAppDispatch } from '@root/store'
|
||||
import { getInstanceDrafts, removeInstanceDraft } from '@utils/slices/instancesSlice'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useCallback, useContext, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Dimensions, Image, Modal, Platform, Pressable, View } from 'react-native'
|
||||
import { PanGestureHandler } from 'react-native-gesture-handler'
|
||||
import { SwipeListView } from 'react-native-swipe-list-view'
|
||||
import { useSelector } from 'react-redux'
|
||||
import ComposeContext from '../utils/createContext'
|
||||
import { formatText } from '../utils/processText'
|
||||
import { ComposeStateDraft, ExtendedAttachment } from '../utils/types'
|
||||
|
||||
export interface Props {
|
||||
timestamp: number
|
||||
}
|
||||
|
||||
const ComposeDraftsListRoot: React.FC<Props> = ({ timestamp }) => {
|
||||
const { composeDispatch } = useContext(ComposeContext)
|
||||
const { t } = useTranslation('screenCompose')
|
||||
const navigation = useNavigation()
|
||||
const dispatch = useAppDispatch()
|
||||
const { colors, theme } = useTheme()
|
||||
const instanceDrafts = useSelector(getInstanceDrafts)?.filter(
|
||||
draft => draft.timestamp !== timestamp
|
||||
)
|
||||
|
||||
const actionWidth = StyleConstants.Font.Size.L + StyleConstants.Spacing.Global.PagePadding * 4
|
||||
|
||||
const [checkingAttachments, setCheckingAttachments] = useState(false)
|
||||
|
||||
const renderItem = useCallback(
|
||||
({ item }: { item: ComposeStateDraft }) => {
|
||||
return (
|
||||
<Pressable
|
||||
accessibilityHint={t('content.draftsList.content.accessibilityHint')}
|
||||
style={{
|
||||
flex: 1,
|
||||
padding: StyleConstants.Spacing.Global.PagePadding,
|
||||
backgroundColor: colors.backgroundDefault
|
||||
}}
|
||||
onPress={async () => {
|
||||
setCheckingAttachments(true)
|
||||
let tempDraft = item
|
||||
let tempUploads: ExtendedAttachment[] = []
|
||||
if (item.attachments && item.attachments.uploads.length) {
|
||||
for (const attachment of item.attachments.uploads) {
|
||||
await apiInstance<Mastodon.Attachment>({
|
||||
method: 'get',
|
||||
url: `media/${attachment.remote?.id}`
|
||||
})
|
||||
.then(res => {
|
||||
if (res.body.id === attachment.remote?.id) {
|
||||
tempUploads.push(attachment)
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
tempDraft = {
|
||||
...tempDraft,
|
||||
attachments: { ...item.attachments, uploads: tempUploads }
|
||||
}
|
||||
}
|
||||
|
||||
tempDraft.spoiler?.length &&
|
||||
formatText({ textInput: 'text', composeDispatch, content: tempDraft.spoiler })
|
||||
tempDraft.text?.length &&
|
||||
formatText({ textInput: 'text', composeDispatch, content: tempDraft.text })
|
||||
composeDispatch({
|
||||
type: 'loadDraft',
|
||||
payload: tempDraft
|
||||
})
|
||||
dispatch(removeInstanceDraft(item.timestamp))
|
||||
navigation.goBack()
|
||||
}}
|
||||
>
|
||||
<View style={{ flex: 1 }}>
|
||||
<HeaderSharedCreated created_at={item.timestamp} />
|
||||
<CustomText
|
||||
fontStyle='M'
|
||||
numberOfLines={2}
|
||||
style={{
|
||||
marginTop: StyleConstants.Spacing.XS,
|
||||
color: colors.primaryDefault
|
||||
}}
|
||||
>
|
||||
{item.text || item.spoiler || t('content.draftsList.content.textEmpty')}
|
||||
</CustomText>
|
||||
{item.attachments?.uploads.length ? (
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
marginTop: StyleConstants.Spacing.S
|
||||
}}
|
||||
>
|
||||
{item.attachments.uploads.map((attachment, index) => (
|
||||
<Image
|
||||
key={index}
|
||||
style={{
|
||||
width:
|
||||
(Dimensions.get('screen').width -
|
||||
StyleConstants.Spacing.Global.PagePadding * 2 -
|
||||
StyleConstants.Spacing.S * 3) /
|
||||
4,
|
||||
height:
|
||||
(Dimensions.get('screen').width -
|
||||
StyleConstants.Spacing.Global.PagePadding * 2 -
|
||||
StyleConstants.Spacing.S * 3) /
|
||||
4,
|
||||
marginLeft: index !== 0 ? StyleConstants.Spacing.S : 0
|
||||
}}
|
||||
source={{
|
||||
uri: attachment.local?.thumbnail || attachment.remote?.preview_url
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
</Pressable>
|
||||
)
|
||||
},
|
||||
[theme]
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginHorizontal: StyleConstants.Spacing.Global.PagePadding,
|
||||
padding: StyleConstants.Spacing.S,
|
||||
borderColor: colors.border,
|
||||
borderWidth: 1,
|
||||
borderRadius: StyleConstants.Spacing.S
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name='AlertTriangle'
|
||||
color={colors.secondary}
|
||||
size={StyleConstants.Font.Size.M}
|
||||
style={{ marginRight: StyleConstants.Spacing.S }}
|
||||
/>
|
||||
<CustomText fontStyle='S' style={{ flexShrink: 1, color: colors.secondary }}>
|
||||
{t('content.draftsList.warning')}
|
||||
</CustomText>
|
||||
</View>
|
||||
<PanGestureHandler enabled={Platform.OS === 'ios'}>
|
||||
<SwipeListView
|
||||
data={instanceDrafts}
|
||||
renderItem={renderItem}
|
||||
renderHiddenItem={({ item }) => (
|
||||
<Pressable
|
||||
style={{
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'flex-end',
|
||||
backgroundColor: colors.red
|
||||
}}
|
||||
onPress={() => dispatch(removeInstanceDraft(item.timestamp))}
|
||||
children={
|
||||
<View
|
||||
style={{
|
||||
flexBasis:
|
||||
StyleConstants.Font.Size.L + StyleConstants.Spacing.Global.PagePadding * 4,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'rgba(0, 255, 0, 0.2)'
|
||||
}}
|
||||
children={
|
||||
<Icon
|
||||
name='Trash'
|
||||
size={StyleConstants.Font.Size.L}
|
||||
color={colors.primaryOverlay}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
disableRightSwipe={true}
|
||||
rightOpenValue={-actionWidth}
|
||||
previewOpenValue={-actionWidth / 2}
|
||||
ItemSeparatorComponent={ComponentSeparator}
|
||||
keyExtractor={item => item.timestamp.toString()}
|
||||
/>
|
||||
</PanGestureHandler>
|
||||
<Modal
|
||||
transparent
|
||||
animationType='fade'
|
||||
visible={checkingAttachments}
|
||||
children={
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: colors.backgroundOverlayInvert
|
||||
}}
|
||||
children={
|
||||
<CustomText
|
||||
fontStyle='M'
|
||||
children={t('content.draftsList.checkAttachment')}
|
||||
style={{ color: colors.primaryOverlay }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default ComposeDraftsListRoot
|
@ -1,49 +1,90 @@
|
||||
import { HeaderLeft } from '@components/Header'
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||
import apiInstance from '@api/instance'
|
||||
import haptics from '@components/haptics'
|
||||
import { HeaderLeft, HeaderRight } from '@components/Header'
|
||||
import { ScreenComposeStackScreenProps } from '@utils/navigation/navigators'
|
||||
import React from 'react'
|
||||
import React, { useContext, useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { KeyboardAvoidingView, Platform } from 'react-native'
|
||||
import { Alert, KeyboardAvoidingView, Platform } from 'react-native'
|
||||
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||
import ComposeEditAttachmentRoot from './EditAttachment/Root'
|
||||
import ComposeEditAttachmentSubmit from './EditAttachment/Submit'
|
||||
import ComposeContext from './utils/createContext'
|
||||
|
||||
const Stack = createNativeStackNavigator()
|
||||
|
||||
const ComposeEditAttachment: React.FC<ScreenComposeStackScreenProps<
|
||||
'Screen-Compose-EditAttachment'
|
||||
>> = ({
|
||||
const ComposeEditAttachment: React.FC<
|
||||
ScreenComposeStackScreenProps<'Screen-Compose-EditAttachment'>
|
||||
> = ({
|
||||
navigation,
|
||||
route: {
|
||||
params: { index }
|
||||
},
|
||||
navigation
|
||||
}) => {
|
||||
const { t } = useTranslation('screenCompose')
|
||||
|
||||
return (
|
||||
<KeyboardAvoidingView
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
style={{ flex: 1 }}
|
||||
>
|
||||
<SafeAreaView style={{ flex: 1 }} edges={['left', 'right', 'bottom']}>
|
||||
<Stack.Navigator>
|
||||
<Stack.Screen
|
||||
name='Screen-Compose-EditAttachment-Root'
|
||||
children={() => <ComposeEditAttachmentRoot index={index} />}
|
||||
options={{
|
||||
headerLeft: () => <HeaderLeft
|
||||
type='icon'
|
||||
content='ChevronDown'
|
||||
onPress={() => navigation.goBack()}
|
||||
/>,
|
||||
headerRight: () => <ComposeEditAttachmentSubmit index={index} />,
|
||||
title: t('content.editAttachment.header.title')
|
||||
}}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
</SafeAreaView>
|
||||
</KeyboardAvoidingView>
|
||||
)
|
||||
}
|
||||
}) => {
|
||||
const { t } = useTranslation('screenCompose')
|
||||
|
||||
const { composeState } = useContext(ComposeContext)
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
|
||||
const theAttachment = composeState.attachments.uploads[index].remote!
|
||||
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
title: t('content.editAttachment.header.title'),
|
||||
headerLeft: () => (
|
||||
<HeaderLeft type='icon' content='ChevronDown' onPress={() => navigation.goBack()} />
|
||||
),
|
||||
headerRight: () => (
|
||||
<HeaderRight
|
||||
accessibilityLabel={t('content.editAttachment.header.right.accessibilityLabel')}
|
||||
type='icon'
|
||||
content='Save'
|
||||
loading={isSubmitting}
|
||||
onPress={() => {
|
||||
setIsSubmitting(true)
|
||||
const formData = new FormData()
|
||||
if (theAttachment.description) {
|
||||
formData.append('description', theAttachment.description)
|
||||
}
|
||||
if (theAttachment.meta?.focus?.x !== 0 || theAttachment.meta.focus.y !== 0) {
|
||||
formData.append(
|
||||
'focus',
|
||||
`${theAttachment.meta?.focus?.x || 0},${-theAttachment.meta?.focus?.y || 0}`
|
||||
)
|
||||
}
|
||||
|
||||
theAttachment?.id &&
|
||||
apiInstance<Mastodon.Attachment>({
|
||||
method: 'put',
|
||||
url: `media/${theAttachment.id}`,
|
||||
body: formData
|
||||
})
|
||||
.then(() => {
|
||||
haptics('Success')
|
||||
navigation.goBack()
|
||||
})
|
||||
.catch(() => {
|
||||
setIsSubmitting(false)
|
||||
haptics('Error')
|
||||
Alert.alert(t('content.editAttachment.header.right.failed.title'), undefined, [
|
||||
{
|
||||
text: t('content.editAttachment.header.right.failed.button'),
|
||||
style: 'cancel'
|
||||
}
|
||||
])
|
||||
})
|
||||
}}
|
||||
/>
|
||||
)
|
||||
})
|
||||
}, [theAttachment])
|
||||
|
||||
return (
|
||||
<KeyboardAvoidingView
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
style={{ flex: 1 }}
|
||||
>
|
||||
<SafeAreaView style={{ flex: 1 }} edges={['left', 'right', 'bottom']}>
|
||||
<ComposeEditAttachmentRoot index={index} />
|
||||
</SafeAreaView>
|
||||
</KeyboardAvoidingView>
|
||||
)
|
||||
}
|
||||
|
||||
export default ComposeEditAttachment
|
||||
|
@ -1,79 +0,0 @@
|
||||
import apiInstance from '@api/instance'
|
||||
import haptics from '@components/haptics'
|
||||
import { HeaderRight } from '@components/Header'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import React, { useContext, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Alert } from 'react-native'
|
||||
import ComposeContext from '../utils/createContext'
|
||||
|
||||
export interface Props {
|
||||
index: number
|
||||
}
|
||||
|
||||
const ComposeEditAttachmentSubmit: React.FC<Props> = ({ index }) => {
|
||||
const { composeState } = useContext(ComposeContext)
|
||||
const navigation = useNavigation()
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
const { t } = useTranslation('screenCompose')
|
||||
|
||||
const theAttachment = composeState.attachments.uploads[index].remote!
|
||||
|
||||
return (
|
||||
<HeaderRight
|
||||
accessibilityLabel={t(
|
||||
'content.editAttachment.header.right.accessibilityLabel'
|
||||
)}
|
||||
type='icon'
|
||||
content='Save'
|
||||
loading={isSubmitting}
|
||||
onPress={() => {
|
||||
setIsSubmitting(true)
|
||||
const formData = new FormData()
|
||||
if (theAttachment.description) {
|
||||
formData.append('description', theAttachment.description)
|
||||
}
|
||||
if (
|
||||
theAttachment.meta?.focus?.x !== 0 ||
|
||||
theAttachment.meta.focus.y !== 0
|
||||
) {
|
||||
formData.append(
|
||||
'focus',
|
||||
`${theAttachment.meta?.focus?.x || 0},${
|
||||
-theAttachment.meta?.focus?.y || 0
|
||||
}`
|
||||
)
|
||||
}
|
||||
|
||||
theAttachment?.id &&
|
||||
apiInstance<Mastodon.Attachment>({
|
||||
method: 'put',
|
||||
url: `media/${theAttachment.id}`,
|
||||
body: formData
|
||||
})
|
||||
.then(() => {
|
||||
haptics('Success')
|
||||
navigation.goBack()
|
||||
})
|
||||
.catch(() => {
|
||||
setIsSubmitting(false)
|
||||
haptics('Error')
|
||||
Alert.alert(
|
||||
t('content.editAttachment.header.right.failed.title'),
|
||||
undefined,
|
||||
[
|
||||
{
|
||||
text: t(
|
||||
'content.editAttachment.header.right.failed.button'
|
||||
),
|
||||
style: 'cancel'
|
||||
}
|
||||
]
|
||||
)
|
||||
})
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default ComposeEditAttachmentSubmit
|
@ -171,21 +171,23 @@ const ComposeAttachments: React.FC<Props> = ({ accessibleRefAttachments }) => {
|
||||
haptics('Success')
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
accessibilityLabel={t('content.root.footer.attachments.edit.accessibilityLabel', {
|
||||
attachment: index + 1
|
||||
})}
|
||||
type='icon'
|
||||
content='Edit'
|
||||
spacing='M'
|
||||
round
|
||||
overlay
|
||||
onPress={() => {
|
||||
navigation.navigate('Screen-Compose-EditAttachment', {
|
||||
index
|
||||
})
|
||||
}}
|
||||
/>
|
||||
{!composeState.attachments.disallowEditing ? (
|
||||
<Button
|
||||
accessibilityLabel={t('content.root.footer.attachments.edit.accessibilityLabel', {
|
||||
attachment: index + 1
|
||||
})}
|
||||
type='icon'
|
||||
content='Edit'
|
||||
spacing='M'
|
||||
round
|
||||
overlay
|
||||
onPress={() => {
|
||||
navigation.navigate('Screen-Compose-EditAttachment', {
|
||||
index
|
||||
})
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
@ -65,6 +65,7 @@ const composeParseState = (
|
||||
}),
|
||||
...(params.incomingStatus.media_attachments && {
|
||||
attachments: {
|
||||
...(params.type === 'edit' && { disallowEditing: true }),
|
||||
sensitive: params.incomingStatus.sensitive,
|
||||
uploads: params.incomingStatus.media_attachments.map(media => ({
|
||||
remote: media
|
||||
|
5
src/screens/Compose/utils/types.d.ts
vendored
5
src/screens/Compose/utils/types.d.ts
vendored
@ -51,6 +51,7 @@ export type ComposeState = {
|
||||
expire: '300' | '1800' | '3600' | '21600' | '86400' | '259200' | '604800'
|
||||
}
|
||||
attachments: {
|
||||
disallowEditing?: boolean // https://github.com/mastodon/mastodon/pull/20878
|
||||
sensitive: boolean
|
||||
uploads: ExtendedAttachment[]
|
||||
}
|
||||
@ -59,8 +60,8 @@ export type ComposeState = {
|
||||
replyToStatus?: Mastodon.Status
|
||||
textInputFocus: {
|
||||
current: 'text' | 'spoiler'
|
||||
refs: { text: RefObject<TextInput>, spoiler: RefObject<TextInput> }
|
||||
isFocused: { text: MutableRefObject<boolean>, spoiler: MutableRefObject<boolean> }
|
||||
refs: { text: RefObject<TextInput>; spoiler: RefObject<TextInput> }
|
||||
isFocused: { text: MutableRefObject<boolean>; spoiler: MutableRefObject<boolean> }
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user