mirror of
https://github.com/tooot-app/app
synced 2025-04-15 02:42:04 +02:00
Fix attachment editing image
This commit is contained in:
parent
fa3c298b8a
commit
7d797bb401
@ -1,16 +1,12 @@
|
|||||||
import apiInstance from '@api/instance'
|
import { HeaderCenter, HeaderLeft } from '@components/Header'
|
||||||
import analytics from '@components/analytics'
|
|
||||||
import haptics from '@components/haptics'
|
|
||||||
import { HeaderCenter, HeaderLeft, HeaderRight } from '@components/Header'
|
|
||||||
import { StackScreenProps } from '@react-navigation/stack'
|
import { StackScreenProps } from '@react-navigation/stack'
|
||||||
import React, { useCallback, useContext, useEffect, useState } from 'react'
|
import React, { useCallback } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Alert, KeyboardAvoidingView, Platform } from 'react-native'
|
import { KeyboardAvoidingView, Platform } from 'react-native'
|
||||||
import { useSharedValue } from 'react-native-reanimated'
|
|
||||||
import { SafeAreaView } from 'react-native-safe-area-context'
|
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||||
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||||
import ComposeEditAttachmentRoot from './EditAttachment/Root'
|
import ComposeEditAttachmentRoot from './EditAttachment/Root'
|
||||||
import ComposeContext from './utils/createContext'
|
import ComposeEditAttachmentSubmit from './EditAttachment/Submit'
|
||||||
|
|
||||||
const Stack = createNativeStackNavigator()
|
const Stack = createNativeStackNavigator()
|
||||||
|
|
||||||
@ -25,40 +21,8 @@ const ComposeEditAttachment: React.FC<ScreenComposeEditAttachmentProp> = ({
|
|||||||
},
|
},
|
||||||
navigation
|
navigation
|
||||||
}) => {
|
}) => {
|
||||||
const { composeState, composeDispatch } = useContext(ComposeContext)
|
console.log('rendering')
|
||||||
const { t } = useTranslation('sharedCompose')
|
const { t } = useTranslation('sharedCompose')
|
||||||
const theAttachment = composeState.attachments.uploads[index].remote!
|
|
||||||
|
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
|
||||||
|
|
||||||
const [altText, setAltText] = useState<string | undefined>(
|
|
||||||
theAttachment.description
|
|
||||||
)
|
|
||||||
const focus = useSharedValue({
|
|
||||||
x: theAttachment.meta?.focus?.x,
|
|
||||||
y: theAttachment.meta?.focus?.y
|
|
||||||
})
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const unsubscribe = navigation.addListener('beforeRemove', () => {
|
|
||||||
composeDispatch({
|
|
||||||
type: 'attachment/edit',
|
|
||||||
payload: {
|
|
||||||
...theAttachment,
|
|
||||||
description: altText,
|
|
||||||
meta: {
|
|
||||||
...theAttachment.meta,
|
|
||||||
focus: {
|
|
||||||
x: focus.value.x > 1 ? 1 : focus.value.x,
|
|
||||||
y: focus.value.y > 1 ? 1 : focus.value.y
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
return unsubscribe
|
|
||||||
}, [focus.value.x, focus.value.y, altText])
|
|
||||||
|
|
||||||
const headerLeft = useCallback(
|
const headerLeft = useCallback(
|
||||||
() => (
|
() => (
|
||||||
@ -70,68 +34,9 @@ const ComposeEditAttachment: React.FC<ScreenComposeEditAttachmentProp> = ({
|
|||||||
),
|
),
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
const headerRight = useCallback(
|
|
||||||
() => (
|
|
||||||
<HeaderRight
|
|
||||||
type='icon'
|
|
||||||
content='Save'
|
|
||||||
loading={isSubmitting}
|
|
||||||
onPress={() => {
|
|
||||||
analytics('editattachment_confirm_press')
|
|
||||||
if (!altText && focus.value.x === 0 && focus.value.y === 0) {
|
|
||||||
navigation.goBack()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
setIsSubmitting(true)
|
|
||||||
const formData = new FormData()
|
|
||||||
if (altText) {
|
|
||||||
formData.append('description', altText)
|
|
||||||
}
|
|
||||||
if (focus.value.x !== 0 || focus.value.y !== 0) {
|
|
||||||
formData.append('focus', `${focus.value.x},${focus.value.y}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
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'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
|
|
||||||
[isSubmitting, altText, focus.value.x, focus.value.y]
|
|
||||||
)
|
|
||||||
|
|
||||||
const children = useCallback(
|
const children = useCallback(
|
||||||
() => (
|
() => <ComposeEditAttachmentRoot index={index} />,
|
||||||
<ComposeEditAttachmentRoot
|
|
||||||
index={index}
|
|
||||||
focus={focus}
|
|
||||||
altText={altText}
|
|
||||||
setAltText={setAltText}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -147,7 +52,7 @@ const ComposeEditAttachment: React.FC<ScreenComposeEditAttachmentProp> = ({
|
|||||||
children={children}
|
children={children}
|
||||||
options={{
|
options={{
|
||||||
headerLeft,
|
headerLeft,
|
||||||
headerRight,
|
headerRight: () => <ComposeEditAttachmentSubmit index={index} />,
|
||||||
headerTitle: t('content.editAttachment.header.title'),
|
headerTitle: t('content.editAttachment.header.title'),
|
||||||
...(Platform.OS === 'android' && {
|
...(Platform.OS === 'android' && {
|
||||||
headerCenter: () => (
|
headerCenter: () => (
|
||||||
|
@ -18,18 +18,14 @@ import ComposeContext from '../utils/createContext'
|
|||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
index: number
|
index: number
|
||||||
focus: Animated.SharedValue<{
|
|
||||||
x: number
|
|
||||||
y: number
|
|
||||||
}>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ComposeEditAttachmentImage: React.FC<Props> = ({ index, focus }) => {
|
const ComposeEditAttachmentImage: React.FC<Props> = ({ index }) => {
|
||||||
const { t } = useTranslation('sharedCompose')
|
const { t } = useTranslation('sharedCompose')
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
|
||||||
const { composeState } = useContext(ComposeContext)
|
const { composeState, composeDispatch } = useContext(ComposeContext)
|
||||||
const theAttachmentRemote = composeState.attachments.uploads[index].remote
|
const theAttachmentRemote = composeState.attachments.uploads[index].remote!
|
||||||
const theAttachmentLocal = composeState.attachments.uploads[index].local
|
const theAttachmentLocal = composeState.attachments.uploads[index].local
|
||||||
|
|
||||||
const imageWidthBase =
|
const imageWidthBase =
|
||||||
@ -57,8 +53,21 @@ const ComposeEditAttachmentImage: React.FC<Props> = ({ index, focus }) => {
|
|||||||
2
|
2
|
||||||
)
|
)
|
||||||
const updateFocus = ({ x, y }: { x: number; y: number }) => {
|
const updateFocus = ({ x, y }: { x: number; y: number }) => {
|
||||||
focus.value = { x, y }
|
composeDispatch({
|
||||||
|
type: 'attachment/edit',
|
||||||
|
payload: {
|
||||||
|
...theAttachmentRemote,
|
||||||
|
meta: {
|
||||||
|
...theAttachmentRemote.meta,
|
||||||
|
focus: {
|
||||||
|
x: x > 1 ? 1 : x,
|
||||||
|
y: y > 1 ? 1 : y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type PanContext = {
|
type PanContext = {
|
||||||
startX: number
|
startX: number
|
||||||
startY: number
|
startY: number
|
||||||
|
@ -1,39 +1,27 @@
|
|||||||
import AttachmentVideo from '@components/Timeline/Shared/Attachment/Video'
|
import AttachmentVideo from '@components/Timeline/Shared/Attachment/Video'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React, { Dispatch, SetStateAction, useContext, useMemo } from 'react'
|
import React, { useContext, useMemo } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { ScrollView, StyleSheet, Text, TextInput, View } from 'react-native'
|
import { ScrollView, StyleSheet, Text, TextInput, View } from 'react-native'
|
||||||
import Animated from 'react-native-reanimated'
|
|
||||||
import ComposeContext from '../utils/createContext'
|
import ComposeContext from '../utils/createContext'
|
||||||
import ComposeEditAttachmentImage from './Image'
|
import ComposeEditAttachmentImage from './Image'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
index: number
|
index: number
|
||||||
focus: Animated.SharedValue<{
|
|
||||||
x: number
|
|
||||||
y: number
|
|
||||||
}>
|
|
||||||
altText: string | undefined
|
|
||||||
setAltText: Dispatch<SetStateAction<string | undefined>>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ComposeEditAttachmentRoot: React.FC<Props> = ({
|
const ComposeEditAttachmentRoot: React.FC<Props> = ({ index }) => {
|
||||||
index,
|
|
||||||
focus,
|
|
||||||
altText,
|
|
||||||
setAltText
|
|
||||||
}) => {
|
|
||||||
const { t } = useTranslation('sharedCompose')
|
const { t } = useTranslation('sharedCompose')
|
||||||
const { mode, theme } = useTheme()
|
const { mode, theme } = useTheme()
|
||||||
const { composeState } = useContext(ComposeContext)
|
const { composeState, composeDispatch } = useContext(ComposeContext)
|
||||||
const theAttachment = composeState.attachments.uploads[index].remote
|
const theAttachment = composeState.attachments.uploads[index].remote!
|
||||||
|
|
||||||
const mediaDisplay = useMemo(() => {
|
const mediaDisplay = useMemo(() => {
|
||||||
if (theAttachment) {
|
if (theAttachment) {
|
||||||
switch (theAttachment.type) {
|
switch (theAttachment.type) {
|
||||||
case 'image':
|
case 'image':
|
||||||
return <ComposeEditAttachmentImage index={index} focus={focus} />
|
return <ComposeEditAttachmentImage index={index} />
|
||||||
case 'video':
|
case 'video':
|
||||||
case 'gifv':
|
case 'gifv':
|
||||||
const video = composeState.attachments.uploads[index]
|
const video = composeState.attachments.uploads[index]
|
||||||
@ -58,6 +46,15 @@ const ComposeEditAttachmentRoot: React.FC<Props> = ({
|
|||||||
return null
|
return null
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const onChangeText = (e: any) =>
|
||||||
|
composeDispatch({
|
||||||
|
type: 'attachment/edit',
|
||||||
|
payload: {
|
||||||
|
...theAttachment,
|
||||||
|
description: e
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView>
|
<ScrollView>
|
||||||
{mediaDisplay}
|
{mediaDisplay}
|
||||||
@ -74,15 +71,15 @@ const ComposeEditAttachmentRoot: React.FC<Props> = ({
|
|||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
maxLength={1500}
|
maxLength={1500}
|
||||||
multiline
|
multiline
|
||||||
onChangeText={e => setAltText(e)}
|
onChangeText={onChangeText}
|
||||||
placeholder={t('content.editAttachment.content.altText.placeholder')}
|
placeholder={t('content.editAttachment.content.altText.placeholder')}
|
||||||
placeholderTextColor={theme.secondary}
|
placeholderTextColor={theme.secondary}
|
||||||
scrollEnabled
|
scrollEnabled
|
||||||
value={altText}
|
value={theAttachment.description}
|
||||||
keyboardAppearance={mode}
|
keyboardAppearance={mode}
|
||||||
/>
|
/>
|
||||||
<Text style={[styles.altTextLength, { color: theme.secondary }]}>
|
<Text style={[styles.altTextLength, { color: theme.secondary }]}>
|
||||||
{altText?.length || 0} / 1500
|
{theAttachment.description?.length || 0} / 1500
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
74
src/screens/Compose/EditAttachment/Submit.tsx
Normal file
74
src/screens/Compose/EditAttachment/Submit.tsx
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import apiInstance from '@api/instance'
|
||||||
|
import analytics from '@components/analytics'
|
||||||
|
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('sharedCompose')
|
||||||
|
|
||||||
|
const theAttachment = composeState.attachments.uploads[index].remote!
|
||||||
|
|
||||||
|
return (
|
||||||
|
<HeaderRight
|
||||||
|
type='icon'
|
||||||
|
content='Save'
|
||||||
|
loading={isSubmitting}
|
||||||
|
onPress={() => {
|
||||||
|
analytics('editattachment_confirm_press')
|
||||||
|
|
||||||
|
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},${-theAttachment.meta.focus.y}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
Loading…
x
Reference in New Issue
Block a user