mirror of
https://github.com/tooot-app/app
synced 2025-04-24 07:07:24 +02:00
Fix #667
This commit is contained in:
parent
4a340fca8e
commit
79a92b5df7
@ -42,7 +42,7 @@ const ComponentAccount: React.FC<PropsWithChildren & Props> = ({ account, props,
|
|||||||
style={{
|
style={{
|
||||||
width: StyleConstants.Avatar.S,
|
width: StyleConstants.Avatar.S,
|
||||||
height: StyleConstants.Avatar.S,
|
height: StyleConstants.Avatar.S,
|
||||||
borderRadius: 8,
|
borderRadius: StyleConstants.BorderRadius,
|
||||||
marginRight: StyleConstants.Spacing.S
|
marginRight: StyleConstants.Spacing.S
|
||||||
}}
|
}}
|
||||||
dim
|
dim
|
||||||
|
@ -45,7 +45,7 @@ const AccountButton: React.FC<Props> = ({ account, additionalActions }) => {
|
|||||||
width: StyleConstants.Font.Size.L,
|
width: StyleConstants.Font.Size.L,
|
||||||
height: StyleConstants.Font.Size.L
|
height: StyleConstants.Font.Size.L
|
||||||
}}
|
}}
|
||||||
style={{ borderRadius: StyleConstants.Font.Size.L / 2, overflow: 'hidden' }}
|
style={{ borderRadius: 99, overflow: 'hidden' }}
|
||||||
/>
|
/>
|
||||||
<CustomText
|
<CustomText
|
||||||
fontStyle='M'
|
fontStyle='M'
|
||||||
|
@ -116,7 +116,7 @@ const Button: React.FC<Props> = ({
|
|||||||
}}
|
}}
|
||||||
style={[
|
style={[
|
||||||
{
|
{
|
||||||
borderRadius: 100,
|
borderRadius: 99,
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
borderWidth: overlay ? 0 : selected ? 1.5 : 1,
|
borderWidth: overlay ? 0 : selected ? 1.5 : 1,
|
||||||
|
@ -35,7 +35,7 @@ const EmojisButton: React.FC = () => {
|
|||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
borderColor: colors.primaryDefault,
|
borderColor: colors.primaryDefault,
|
||||||
padding: StyleConstants.Spacing.Global.PagePadding / 2,
|
padding: StyleConstants.Spacing.Global.PagePadding / 2,
|
||||||
borderRadius: 100
|
borderRadius: 99
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
|
@ -51,7 +51,7 @@ const HeaderLeft: React.FC<Props> = ({
|
|||||||
minWidth: 44,
|
minWidth: 44,
|
||||||
marginLeft: native ? -StyleConstants.Spacing.S : StyleConstants.Spacing.S,
|
marginLeft: native ? -StyleConstants.Spacing.S : StyleConstants.Spacing.S,
|
||||||
...(type === undefined && {
|
...(type === undefined && {
|
||||||
borderRadius: 100
|
borderRadius: 99
|
||||||
}),
|
}),
|
||||||
...(type === 'text' && {
|
...(type === 'text' && {
|
||||||
paddingHorizontal: StyleConstants.Spacing.S
|
paddingHorizontal: StyleConstants.Spacing.S
|
||||||
|
@ -98,9 +98,7 @@ const HeaderRight: React.FC<Props> = ({
|
|||||||
minHeight: 44,
|
minHeight: 44,
|
||||||
minWidth: 44,
|
minWidth: 44,
|
||||||
marginRight: native ? -StyleConstants.Spacing.S : StyleConstants.Spacing.S,
|
marginRight: native ? -StyleConstants.Spacing.S : StyleConstants.Spacing.S,
|
||||||
...(type === undefined && {
|
...(type === undefined && { borderRadius: 99 }),
|
||||||
borderRadius: 100
|
|
||||||
}),
|
|
||||||
...(type === 'text' && {
|
...(type === 'text' && {
|
||||||
paddingHorizontal: StyleConstants.Spacing.S
|
paddingHorizontal: StyleConstants.Spacing.S
|
||||||
})
|
})
|
||||||
|
@ -89,7 +89,7 @@ const MenuRow: React.FC<Props> = ({
|
|||||||
width: 8,
|
width: 8,
|
||||||
height: 8,
|
height: 8,
|
||||||
backgroundColor: colors.red,
|
backgroundColor: colors.red,
|
||||||
borderRadius: 8,
|
borderRadius: StyleConstants.BorderRadius,
|
||||||
marginRight: StyleConstants.Spacing.S
|
marginRight: StyleConstants.Spacing.S
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -31,9 +31,11 @@ export const SwipeToActions = <T extends unknown>({
|
|||||||
haptics(action.haptic || 'Light')
|
haptics(action.haptic || 'Light')
|
||||||
action.onPress({ item })
|
action.onPress({ item })
|
||||||
}}
|
}}
|
||||||
|
style={{ backgroundColor: 'rgba(0, 255, 0, 0.2)' }}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
|
flex: 1,
|
||||||
paddingHorizontal: StyleConstants.Spacing.L,
|
paddingHorizontal: StyleConstants.Spacing.L,
|
||||||
flexBasis: perActionWidth,
|
flexBasis: perActionWidth,
|
||||||
backgroundColor: action.color,
|
backgroundColor: action.color,
|
||||||
|
@ -67,7 +67,7 @@ const TimelineConversation: React.FC<Props> = ({ conversation, queryKey, highlig
|
|||||||
<View style={{ flex: 1, width: '100%', flexDirection: 'row' }}>
|
<View style={{ flex: 1, width: '100%', flexDirection: 'row' }}>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
borderRadius: 4,
|
borderRadius: StyleConstants.BorderRadius,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
marginRight: StyleConstants.Spacing.S,
|
marginRight: StyleConstants.Spacing.S,
|
||||||
width: StyleConstants.Avatar.M,
|
width: StyleConstants.Avatar.M,
|
||||||
|
@ -118,7 +118,7 @@ const AttachmentAudio: React.FC<Props> = ({ total, index, sensitiveShown, audio
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
height: StyleConstants.Spacing.M + StyleConstants.Spacing.S * 2,
|
height: StyleConstants.Spacing.M + StyleConstants.Spacing.S * 2,
|
||||||
paddingHorizontal: StyleConstants.Spacing.Global.PagePadding,
|
paddingHorizontal: StyleConstants.Spacing.Global.PagePadding,
|
||||||
borderRadius: 100,
|
borderRadius: 99,
|
||||||
opacity: sensitiveShown ? 0.35 : undefined
|
opacity: sensitiveShown ? 0.35 : undefined
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -49,7 +49,7 @@ const TimelineAvatar: React.FC<Props> = ({ account }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
style={{
|
style={{
|
||||||
borderRadius: StyleConstants.Avatar.M,
|
borderRadius: 99,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
marginRight: StyleConstants.Spacing.S
|
marginRight: StyleConstants.Spacing.S
|
||||||
}}
|
}}
|
||||||
|
@ -137,7 +137,7 @@ const TimelineCard: React.FC = () => {
|
|||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
marginTop: StyleConstants.Spacing.M,
|
marginTop: StyleConstants.Spacing.M,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderRadius: StyleConstants.Spacing.S,
|
borderRadius: StyleConstants.BorderRadius,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
borderColor: colors.border
|
borderColor: colors.border
|
||||||
}}
|
}}
|
||||||
|
26
src/components/discardConfirmation.ts
Normal file
26
src/components/discardConfirmation.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import i18n from '@i18n/index'
|
||||||
|
import { Alert } from 'react-native'
|
||||||
|
|
||||||
|
export const discardConfirmation = ({
|
||||||
|
condition,
|
||||||
|
action
|
||||||
|
}: {
|
||||||
|
condition: boolean
|
||||||
|
action: () => void
|
||||||
|
}) => {
|
||||||
|
if (condition) {
|
||||||
|
Alert.alert(i18n.t('common:discard.title'), i18n.t('common:discard.message'), [
|
||||||
|
{
|
||||||
|
text: i18n.t('common:buttons.discard'),
|
||||||
|
style: 'destructive',
|
||||||
|
onPress: () => action()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: i18n.t('common:buttons.cancel'),
|
||||||
|
style: 'default'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
} else {
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ import i18next from 'i18next'
|
|||||||
import { Asset, launchImageLibrary } from 'react-native-image-picker'
|
import { Asset, launchImageLibrary } from 'react-native-image-picker'
|
||||||
|
|
||||||
const queryKeyInstance: QueryKeyInstance = ['Instance']
|
const queryKeyInstance: QueryKeyInstance = ['Instance']
|
||||||
export const MAX_MEDIA_ATTACHMENTS: number =
|
export const MAX_MEDIA_ATTACHMENTS = (): number =>
|
||||||
queryClient.getQueryData<Mastodon.Instance<any>>(queryKeyInstance)?.configuration?.statuses
|
queryClient.getQueryData<Mastodon.Instance<any>>(queryKeyInstance)?.configuration?.statuses
|
||||||
.max_media_attachments || 4
|
.max_media_attachments || 4
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ const mediaSelector = async ({
|
|||||||
indicateMaximum = false,
|
indicateMaximum = false,
|
||||||
showActionSheetWithOptions
|
showActionSheetWithOptions
|
||||||
}: Props): Promise<Asset[]> => {
|
}: Props): Promise<Asset[]> => {
|
||||||
const _maximum = maximum || MAX_MEDIA_ATTACHMENTS
|
const _maximum = maximum || MAX_MEDIA_ATTACHMENTS()
|
||||||
|
|
||||||
const options = () => {
|
const options = () => {
|
||||||
switch (mediaType) {
|
switch (mediaType) {
|
||||||
|
@ -52,7 +52,7 @@ const Share = ({
|
|||||||
padding: StyleConstants.Spacing.M,
|
padding: StyleConstants.Spacing.M,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderColor: colors.shimmerHighlight,
|
borderColor: colors.shimmerHighlight,
|
||||||
borderRadius: 8
|
borderRadius: StyleConstants.BorderRadius
|
||||||
}}
|
}}
|
||||||
children={text}
|
children={text}
|
||||||
/>
|
/>
|
||||||
@ -65,7 +65,7 @@ const Share = ({
|
|||||||
padding: StyleConstants.Spacing.M,
|
padding: StyleConstants.Spacing.M,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderColor: colors.shimmerHighlight,
|
borderColor: colors.shimmerHighlight,
|
||||||
borderRadius: 8
|
borderRadius: StyleConstants.BorderRadius
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FlatList
|
<FlatList
|
||||||
|
@ -73,7 +73,7 @@ const ScreenAnnouncements: React.FC<RootStackScreenProps<'Screen-Announcements'>
|
|||||||
padding: StyleConstants.Spacing.Global.PagePadding,
|
padding: StyleConstants.Spacing.Global.PagePadding,
|
||||||
marginTop: StyleConstants.Spacing.Global.PagePadding,
|
marginTop: StyleConstants.Spacing.Global.PagePadding,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderRadius: 6,
|
borderRadius: StyleConstants.BorderRadius,
|
||||||
borderColor: colors.primaryDefault,
|
borderColor: colors.primaryDefault,
|
||||||
backgroundColor: colors.backgroundDefault
|
backgroundColor: colors.backgroundDefault
|
||||||
}}
|
}}
|
||||||
@ -123,7 +123,7 @@ const ScreenAnnouncements: React.FC<RootStackScreenProps<'Screen-Announcements'>
|
|||||||
marginTop: StyleConstants.Spacing.Global.PagePadding / 2,
|
marginTop: StyleConstants.Spacing.Global.PagePadding / 2,
|
||||||
marginBottom: StyleConstants.Spacing.Global.PagePadding / 2,
|
marginBottom: StyleConstants.Spacing.Global.PagePadding / 2,
|
||||||
marginRight: StyleConstants.Spacing.M,
|
marginRight: StyleConstants.Spacing.M,
|
||||||
borderRadius: 6,
|
borderRadius: StyleConstants.BorderRadius,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
borderColor: reaction.me ? colors.disabled : colors.primaryDefault,
|
borderColor: reaction.me ? colors.disabled : colors.primaryDefault,
|
||||||
backgroundColor: reaction.me ? colors.disabled : colors.backgroundDefault
|
backgroundColor: reaction.me ? colors.disabled : colors.backgroundDefault
|
||||||
@ -231,7 +231,7 @@ const ScreenAnnouncements: React.FC<RootStackScreenProps<'Screen-Announcements'>
|
|||||||
style={{
|
style={{
|
||||||
width: StyleConstants.Spacing.S,
|
width: StyleConstants.Spacing.S,
|
||||||
height: StyleConstants.Spacing.S,
|
height: StyleConstants.Spacing.S,
|
||||||
borderRadius: StyleConstants.Spacing.S,
|
borderRadius: StyleConstants.BorderRadius,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderColor: colors.primaryDefault,
|
borderColor: colors.primaryDefault,
|
||||||
backgroundColor: i === index ? colors.primaryDefault : undefined,
|
backgroundColor: i === index ? colors.primaryDefault : undefined,
|
||||||
@ -271,7 +271,7 @@ const ScreenAnnouncements: React.FC<RootStackScreenProps<'Screen-Announcements'>
|
|||||||
style={{
|
style={{
|
||||||
width: StyleConstants.Spacing.S,
|
width: StyleConstants.Spacing.S,
|
||||||
height: StyleConstants.Spacing.S,
|
height: StyleConstants.Spacing.S,
|
||||||
borderRadius: StyleConstants.Spacing.S,
|
borderRadius: StyleConstants.BorderRadius,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderColor: colors.primaryDefault,
|
borderColor: colors.primaryDefault,
|
||||||
backgroundColor: i === index ? colors.primaryDefault : undefined,
|
backgroundColor: i === index ? colors.primaryDefault : undefined,
|
||||||
|
@ -56,7 +56,7 @@ const ComposeDraftsList: React.FC<ScreenComposeStackScreenProps<'Screen-Compose-
|
|||||||
padding: StyleConstants.Spacing.S,
|
padding: StyleConstants.Spacing.S,
|
||||||
borderColor: colors.border,
|
borderColor: colors.border,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderRadius: StyleConstants.Spacing.S,
|
borderRadius: StyleConstants.BorderRadius,
|
||||||
marginBottom: StyleConstants.Spacing.S
|
marginBottom: StyleConstants.Spacing.S
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { discardConfirmation } from '@components/discardConfirmation'
|
||||||
import haptics from '@components/haptics'
|
import haptics from '@components/haptics'
|
||||||
import { HeaderLeft, HeaderRight } from '@components/Header'
|
import { HeaderLeft, HeaderRight } from '@components/Header'
|
||||||
import { ModalScrollView } from '@components/ModalScrollView'
|
import { ModalScrollView } from '@components/ModalScrollView'
|
||||||
@ -6,9 +7,11 @@ import apiInstance from '@utils/api/instance'
|
|||||||
import { ScreenComposeStackScreenProps } from '@utils/navigation/navigators'
|
import { ScreenComposeStackScreenProps } from '@utils/navigation/navigators'
|
||||||
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 { Image } from 'expo-image'
|
||||||
import React, { useContext, useEffect, useState } from 'react'
|
import React, { useContext, useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Alert, TextInput } from 'react-native'
|
import { Alert, TextInput, View } from 'react-native'
|
||||||
|
import { DEFAULT_WIDTH } from './Root/Footer/Attachments'
|
||||||
import ComposeContext from './utils/createContext'
|
import ComposeContext from './utils/createContext'
|
||||||
|
|
||||||
const ComposeEditAttachment: React.FC<
|
const ComposeEditAttachment: React.FC<
|
||||||
@ -20,7 +23,7 @@ const ComposeEditAttachment: React.FC<
|
|||||||
}
|
}
|
||||||
}) => {
|
}) => {
|
||||||
const { colors } = useTheme()
|
const { colors } = useTheme()
|
||||||
const { t } = useTranslation('screenCompose')
|
const { t } = useTranslation(['common', 'screenCompose'])
|
||||||
|
|
||||||
const { composeState, composeDispatch } = useContext(ComposeContext)
|
const { composeState, composeDispatch } = useContext(ComposeContext)
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||||
@ -31,55 +34,88 @@ const ComposeEditAttachment: React.FC<
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const [altText, setAltText] = useState<string | undefined>(theAttachment.description)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
navigation.setOptions({
|
navigation.setOptions({
|
||||||
title: t('content.editAttachment.header.title'),
|
title: t('screenCompose:content.editAttachment.header.title'),
|
||||||
headerLeft: () => <HeaderLeft content='chevron-down' onPress={() => navigation.goBack()} />,
|
headerLeft: () => (
|
||||||
|
<HeaderLeft
|
||||||
|
content='chevron-down'
|
||||||
|
onPress={() => {
|
||||||
|
discardConfirmation({
|
||||||
|
condition: theAttachment.description != altText,
|
||||||
|
action: () => navigation.goBack()
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
headerRight: () => (
|
headerRight: () => (
|
||||||
<HeaderRight
|
<HeaderRight
|
||||||
accessibilityLabel={t('content.editAttachment.header.right.accessibilityLabel')}
|
accessibilityLabel={t(
|
||||||
|
'screenCompose:content.editAttachment.header.right.accessibilityLabel'
|
||||||
|
)}
|
||||||
content='save'
|
content='save'
|
||||||
loading={isSubmitting}
|
loading={isSubmitting}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
if (composeState.type === 'edit') {
|
if (composeState.type === 'edit') {
|
||||||
composeDispatch({ type: 'attachment/edit', payload: { ...theAttachment } })
|
composeDispatch({
|
||||||
|
type: 'attachment/edit',
|
||||||
|
payload: { ...theAttachment, description: altText }
|
||||||
|
})
|
||||||
navigation.goBack()
|
navigation.goBack()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsSubmitting(true)
|
|
||||||
const body = { description: theAttachment.description }
|
|
||||||
|
|
||||||
theAttachment?.id &&
|
theAttachment?.id &&
|
||||||
apiInstance<Mastodon.Attachment>({
|
apiInstance<Mastodon.Attachment>({
|
||||||
method: 'put',
|
method: 'put',
|
||||||
url: `media/${theAttachment.id}`,
|
url: `media/${theAttachment.id}`,
|
||||||
body
|
body: { description: altText }
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(res => {
|
||||||
|
setIsSubmitting(false)
|
||||||
haptics('Success')
|
haptics('Success')
|
||||||
|
composeDispatch({
|
||||||
|
type: 'attachment/edit',
|
||||||
|
payload: res.body
|
||||||
|
})
|
||||||
navigation.goBack()
|
navigation.goBack()
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
setIsSubmitting(false)
|
setIsSubmitting(false)
|
||||||
haptics('Error')
|
haptics('Error')
|
||||||
Alert.alert(t('content.editAttachment.header.right.failed.title'), undefined, [
|
Alert.alert(
|
||||||
|
t('screenCompose:content.editAttachment.header.right.failed.title'),
|
||||||
|
undefined,
|
||||||
|
[
|
||||||
{
|
{
|
||||||
text: t('content.editAttachment.header.right.failed.button'),
|
text: t('screenCompose:content.editAttachment.header.right.failed.button'),
|
||||||
style: 'cancel'
|
style: 'cancel'
|
||||||
}
|
}
|
||||||
])
|
]
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}, [theAttachment])
|
}, [theAttachment, altText])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalScrollView>
|
<ModalScrollView>
|
||||||
|
<View style={{ alignItems: 'center', marginBottom: StyleConstants.Spacing.M }}>
|
||||||
|
<Image
|
||||||
|
style={{
|
||||||
|
width: DEFAULT_WIDTH,
|
||||||
|
height: DEFAULT_WIDTH,
|
||||||
|
borderRadius: StyleConstants.BorderRadius
|
||||||
|
}}
|
||||||
|
source={theAttachment.preview_url}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
<CustomText fontStyle='M' style={{ color: colors.primaryDefault }} fontWeight='Bold'>
|
<CustomText fontStyle='M' style={{ color: colors.primaryDefault }} fontWeight='Bold'>
|
||||||
{t('content.editAttachment.content.altText.heading')}
|
{t('screenCompose:content.editAttachment.content.altText.heading')}
|
||||||
</CustomText>
|
</CustomText>
|
||||||
<TextInput
|
<TextInput
|
||||||
style={{
|
style={{
|
||||||
@ -94,18 +130,10 @@ const ComposeEditAttachment: React.FC<
|
|||||||
}}
|
}}
|
||||||
maxLength={1500}
|
maxLength={1500}
|
||||||
multiline
|
multiline
|
||||||
onChangeText={e =>
|
value={altText}
|
||||||
composeDispatch({
|
onChangeText={e => setAltText(e)}
|
||||||
type: 'attachment/edit',
|
placeholder={t('screenCompose:content.editAttachment.content.altText.placeholder')}
|
||||||
payload: {
|
|
||||||
...theAttachment,
|
|
||||||
description: e
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
placeholder={t('content.editAttachment.content.altText.placeholder')}
|
|
||||||
placeholderTextColor={colors.secondary}
|
placeholderTextColor={colors.secondary}
|
||||||
value={theAttachment.description}
|
|
||||||
/>
|
/>
|
||||||
<CustomText
|
<CustomText
|
||||||
fontStyle='S'
|
fontStyle='S'
|
||||||
|
@ -30,7 +30,7 @@ const ComposeActions: React.FC = () => {
|
|||||||
const attachmentOnPress = () => {
|
const attachmentOnPress = () => {
|
||||||
if (composeState.poll.active) return
|
if (composeState.poll.active) return
|
||||||
|
|
||||||
if (composeState.attachments.uploads.length < MAX_MEDIA_ATTACHMENTS) {
|
if (composeState.attachments.uploads.length < MAX_MEDIA_ATTACHMENTS()) {
|
||||||
return chooseAndUploadAttachment({ composeDispatch, showActionSheetWithOptions })
|
return chooseAndUploadAttachment({ composeDispatch, showActionSheetWithOptions })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,19 +12,19 @@ import { StyleConstants } from '@utils/styles/constants'
|
|||||||
import layoutAnimation from '@utils/styles/layoutAnimation'
|
import layoutAnimation from '@utils/styles/layoutAnimation'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import { Image } from 'expo-image'
|
import { Image } from 'expo-image'
|
||||||
import React, { RefObject, useContext, useEffect, useRef } from 'react'
|
import React, { RefObject, useContext, useRef } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { FlatList, Pressable, StyleSheet, View } from 'react-native'
|
import { FlatList, Pressable, StyleSheet, View } from 'react-native'
|
||||||
import ComposeContext from '../../utils/createContext'
|
import ComposeContext from '../../utils/createContext'
|
||||||
import { ExtendedAttachment } from '../../utils/types'
|
import { ExtendedAttachment } from '../../utils/types'
|
||||||
import chooseAndUploadAttachment from './addAttachment'
|
import chooseAndUploadAttachment from './addAttachment'
|
||||||
|
|
||||||
|
export const DEFAULT_WIDTH = 150
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
accessibleRefAttachments: RefObject<View>
|
accessibleRefAttachments: RefObject<View>
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_HEIGHT = 200
|
|
||||||
|
|
||||||
const ComposeAttachments: React.FC<Props> = ({ accessibleRefAttachments }) => {
|
const ComposeAttachments: React.FC<Props> = ({ accessibleRefAttachments }) => {
|
||||||
const { showActionSheetWithOptions } = useActionSheet()
|
const { showActionSheetWithOptions } = useActionSheet()
|
||||||
const { composeState, composeDispatch } = useContext(ComposeContext)
|
const { composeState, composeDispatch } = useContext(ComposeContext)
|
||||||
@ -40,72 +40,22 @@ const ComposeAttachments: React.FC<Props> = ({ accessibleRefAttachments }) => {
|
|||||||
payload: { sensitive: !composeState.attachments.sensitive }
|
payload: { sensitive: !composeState.attachments.sensitive }
|
||||||
})
|
})
|
||||||
|
|
||||||
const calculateWidth = (item: ExtendedAttachment) => {
|
|
||||||
if (item.local) {
|
|
||||||
return ((item.local.width || 100) / (item.local.height || 100)) * DEFAULT_HEIGHT
|
|
||||||
} else {
|
|
||||||
if (item.remote) {
|
|
||||||
if (item.remote.meta.original.aspect) {
|
|
||||||
return item.remote.meta.original.aspect * DEFAULT_HEIGHT
|
|
||||||
} else if (item.remote.meta.original.width && item.remote.meta.original.height) {
|
|
||||||
return (
|
|
||||||
(item.remote.meta.original.width / item.remote.meta.original.height) * DEFAULT_HEIGHT
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return DEFAULT_HEIGHT
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return DEFAULT_HEIGHT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const snapToOffsets = () => {
|
|
||||||
const attachmentsOffsets = composeState.attachments.uploads.map((_, index) => {
|
|
||||||
let currentOffset = 0
|
|
||||||
Array.from(Array(index).keys()).map(
|
|
||||||
i =>
|
|
||||||
(currentOffset =
|
|
||||||
currentOffset +
|
|
||||||
calculateWidth(composeState.attachments.uploads[i]) +
|
|
||||||
StyleConstants.Spacing.Global.PagePadding)
|
|
||||||
)
|
|
||||||
return currentOffset
|
|
||||||
})
|
|
||||||
return attachmentsOffsets.length < 4
|
|
||||||
? [
|
|
||||||
...attachmentsOffsets,
|
|
||||||
attachmentsOffsets.reduce((a, b) => a + b, 0) +
|
|
||||||
DEFAULT_HEIGHT +
|
|
||||||
StyleConstants.Spacing.Global.PagePadding
|
|
||||||
]
|
|
||||||
: attachmentsOffsets
|
|
||||||
}
|
|
||||||
let prevOffsets = useRef<number[]>()
|
|
||||||
useEffect(() => {
|
|
||||||
const snap = snapToOffsets()
|
|
||||||
if (snap.length > (prevOffsets.current ? prevOffsets.current.length : 0)) {
|
|
||||||
flatListRef.current?.scrollToOffset({
|
|
||||||
offset: snap[snapToOffsets.length - 2] + snap[snapToOffsets.length - 1]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
prevOffsets.current = snap
|
|
||||||
}, [snapToOffsets, prevOffsets.current])
|
|
||||||
|
|
||||||
const renderAttachment = ({ item, index }: { item: ExtendedAttachment; index: number }) => {
|
const renderAttachment = ({ item, index }: { item: ExtendedAttachment; index: number }) => {
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
key={index}
|
key={index}
|
||||||
style={{
|
style={{
|
||||||
height: DEFAULT_HEIGHT,
|
|
||||||
marginLeft: StyleConstants.Spacing.Global.PagePadding,
|
marginLeft: StyleConstants.Spacing.Global.PagePadding,
|
||||||
marginTop: StyleConstants.Spacing.Global.PagePadding,
|
marginTop: StyleConstants.Spacing.Global.PagePadding,
|
||||||
marginBottom: StyleConstants.Spacing.Global.PagePadding,
|
marginBottom: StyleConstants.Spacing.Global.PagePadding
|
||||||
width: calculateWidth(item)
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
style={{ width: '100%', height: '100%' }}
|
style={{
|
||||||
|
width: DEFAULT_WIDTH,
|
||||||
|
height: DEFAULT_WIDTH,
|
||||||
|
borderRadius: StyleConstants.BorderRadius
|
||||||
|
}}
|
||||||
source={
|
source={
|
||||||
item.local?.thumbnail
|
item.local?.thumbnail
|
||||||
? { uri: item.local?.thumbnail }
|
? { uri: item.local?.thumbnail }
|
||||||
@ -123,7 +73,7 @@ const ComposeAttachments: React.FC<Props> = ({ accessibleRefAttachments }) => {
|
|||||||
paddingRight: StyleConstants.Spacing.S,
|
paddingRight: StyleConstants.Spacing.S,
|
||||||
paddingTop: StyleConstants.Spacing.XS,
|
paddingTop: StyleConstants.Spacing.XS,
|
||||||
paddingBottom: StyleConstants.Spacing.XS,
|
paddingBottom: StyleConstants.Spacing.XS,
|
||||||
color: colors.backgroundDefault,
|
color: colors.primaryOverlay,
|
||||||
backgroundColor: colors.backgroundOverlayInvert
|
backgroundColor: colors.backgroundOverlayInvert
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -157,7 +107,7 @@ const ComposeAttachments: React.FC<Props> = ({ accessibleRefAttachments }) => {
|
|||||||
})}
|
})}
|
||||||
type='icon'
|
type='icon'
|
||||||
content='x'
|
content='x'
|
||||||
spacing='M'
|
size='L'
|
||||||
round
|
round
|
||||||
overlay
|
overlay
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
@ -175,11 +125,11 @@ const ComposeAttachments: React.FC<Props> = ({ accessibleRefAttachments }) => {
|
|||||||
accessibilityLabel={t('content.root.footer.attachments.edit.accessibilityLabel', {
|
accessibilityLabel={t('content.root.footer.attachments.edit.accessibilityLabel', {
|
||||||
attachment: index + 1
|
attachment: index + 1
|
||||||
})}
|
})}
|
||||||
type='icon'
|
|
||||||
content='edit'
|
|
||||||
spacing='M'
|
|
||||||
round
|
|
||||||
overlay
|
overlay
|
||||||
|
size='S'
|
||||||
|
type='text'
|
||||||
|
content={!!item.remote?.description?.length ? 'ALT ✓' : '+ ALT'}
|
||||||
|
fontBold
|
||||||
onPress={() => navigation.navigate('Screen-Compose-EditAttachment', { index })}
|
onPress={() => navigation.navigate('Screen-Compose-EditAttachment', { index })}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
@ -230,23 +180,23 @@ const ComposeAttachments: React.FC<Props> = ({ accessibleRefAttachments }) => {
|
|||||||
pagingEnabled={false}
|
pagingEnabled={false}
|
||||||
snapToAlignment='center'
|
snapToAlignment='center'
|
||||||
renderItem={renderAttachment}
|
renderItem={renderAttachment}
|
||||||
snapToOffsets={snapToOffsets()}
|
snapToOffsets={new Array(composeState.attachments.uploads.length).fill(DEFAULT_WIDTH)}
|
||||||
keyboardShouldPersistTaps='always'
|
keyboardShouldPersistTaps='always'
|
||||||
showsHorizontalScrollIndicator={false}
|
showsHorizontalScrollIndicator={false}
|
||||||
data={composeState.attachments.uploads}
|
data={composeState.attachments.uploads}
|
||||||
keyExtractor={item => item.local?.uri || item.remote?.url || Math.random().toString()}
|
keyExtractor={item => item.local?.uri || item.remote?.url || Math.random().toString()}
|
||||||
ListFooterComponent={
|
ListFooterComponent={
|
||||||
composeState.attachments.uploads.length < MAX_MEDIA_ATTACHMENTS ? (
|
composeState.attachments.uploads.length < MAX_MEDIA_ATTACHMENTS() ? (
|
||||||
<Pressable
|
<Pressable
|
||||||
accessible
|
accessible
|
||||||
accessibilityLabel={t('content.root.footer.attachments.upload.accessibilityLabel')}
|
accessibilityLabel={t('content.root.footer.attachments.upload.accessibilityLabel')}
|
||||||
style={{
|
style={{
|
||||||
height: DEFAULT_HEIGHT,
|
width: DEFAULT_WIDTH,
|
||||||
|
height: DEFAULT_WIDTH,
|
||||||
marginLeft: StyleConstants.Spacing.Global.PagePadding,
|
marginLeft: StyleConstants.Spacing.Global.PagePadding,
|
||||||
marginTop: StyleConstants.Spacing.Global.PagePadding,
|
marginTop: StyleConstants.Spacing.Global.PagePadding,
|
||||||
marginBottom: StyleConstants.Spacing.Global.PagePadding,
|
marginBottom: StyleConstants.Spacing.Global.PagePadding,
|
||||||
width: DEFAULT_HEIGHT,
|
backgroundColor: colors.disabled
|
||||||
backgroundColor: colors.backgroundOverlayInvert
|
|
||||||
}}
|
}}
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
await chooseAndUploadAttachment({
|
await chooseAndUploadAttachment({
|
||||||
@ -258,9 +208,7 @@ const ComposeAttachments: React.FC<Props> = ({ accessibleRefAttachments }) => {
|
|||||||
<Button
|
<Button
|
||||||
type='icon'
|
type='icon'
|
||||||
content='upload-cloud'
|
content='upload-cloud'
|
||||||
spacing='M'
|
size='L'
|
||||||
round
|
|
||||||
overlay
|
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
await chooseAndUploadAttachment({
|
await chooseAndUploadAttachment({
|
||||||
composeDispatch,
|
composeDispatch,
|
||||||
@ -270,10 +218,11 @@ const ComposeAttachments: React.FC<Props> = ({ accessibleRefAttachments }) => {
|
|||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top:
|
top:
|
||||||
(DEFAULT_HEIGHT - StyleConstants.Spacing.M * 2 - StyleConstants.Font.Size.M) /
|
(DEFAULT_WIDTH - StyleConstants.Spacing.M * 2 - StyleConstants.Font.Size.M) / 2,
|
||||||
2,
|
|
||||||
left:
|
left:
|
||||||
(DEFAULT_HEIGHT - StyleConstants.Spacing.M * 2 - StyleConstants.Font.Size.M) / 2
|
(DEFAULT_WIDTH - StyleConstants.Spacing.M * 2 - StyleConstants.Font.Size.M) / 2,
|
||||||
|
borderWidth: 0,
|
||||||
|
backgroundColor: ''
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
|
@ -38,8 +38,8 @@ const ComposePoll: React.FC = () => {
|
|||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
borderWidth: StyleSheet.hairlineWidth,
|
borderWidth: 1,
|
||||||
borderRadius: StyleConstants.Spacing.S,
|
borderRadius: StyleConstants.BorderRadius,
|
||||||
margin: StyleConstants.Spacing.Global.PagePadding,
|
margin: StyleConstants.Spacing.Global.PagePadding,
|
||||||
borderColor: colors.border
|
borderColor: colors.border
|
||||||
}}
|
}}
|
||||||
@ -70,7 +70,7 @@ const ComposePoll: React.FC = () => {
|
|||||||
flex: 1,
|
flex: 1,
|
||||||
padding: StyleConstants.Spacing.S,
|
padding: StyleConstants.Spacing.S,
|
||||||
borderWidth: StyleSheet.hairlineWidth,
|
borderWidth: StyleSheet.hairlineWidth,
|
||||||
borderRadius: 6,
|
borderRadius: StyleConstants.BorderRadius,
|
||||||
...StyleConstants.FontStyle.M,
|
...StyleConstants.FontStyle.M,
|
||||||
marginLeft: StyleConstants.Spacing.S,
|
marginLeft: StyleConstants.Spacing.S,
|
||||||
borderColor: colors.border,
|
borderColor: colors.border,
|
||||||
|
@ -17,7 +17,7 @@ const ComposeReply: React.FC = () => {
|
|||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderRadius: StyleConstants.Spacing.S,
|
borderRadius: StyleConstants.BorderRadius,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
borderColor: colors.border,
|
borderColor: colors.border,
|
||||||
marginHorizontal: StyleConstants.Spacing.Global.PagePadding,
|
marginHorizontal: StyleConstants.Spacing.Global.PagePadding,
|
||||||
|
@ -71,7 +71,7 @@ const ComposeTextInput: React.FC = () => {
|
|||||||
scrollEnabled={false}
|
scrollEnabled={false}
|
||||||
disableCopyPaste={false}
|
disableCopyPaste={false}
|
||||||
onPaste={(error: string | null | undefined, files: PastedFile[]) => {
|
onPaste={(error: string | null | undefined, files: PastedFile[]) => {
|
||||||
if (composeState.attachments.uploads.length + files.length > MAX_MEDIA_ATTACHMENTS) {
|
if (composeState.attachments.uploads.length + files.length > MAX_MEDIA_ATTACHMENTS()) {
|
||||||
Alert.alert(
|
Alert.alert(
|
||||||
t('screenCompose:content.root.header.textInput.keyboardImage.exceedMaximum.title'),
|
t('screenCompose:content.root.header.textInput.keyboardImage.exceedMaximum.title'),
|
||||||
undefined,
|
undefined,
|
||||||
|
@ -28,7 +28,39 @@ const composeInitialState: Omit<ComposeState, 'timestamp'> = {
|
|||||||
},
|
},
|
||||||
attachments: {
|
attachments: {
|
||||||
sensitive: false,
|
sensitive: false,
|
||||||
uploads: []
|
uploads: [
|
||||||
|
// Test images
|
||||||
|
// {
|
||||||
|
// remote: {
|
||||||
|
// id: '01',
|
||||||
|
// type: 'image',
|
||||||
|
// url: 'https://images.unsplash.com/photo-1669311540088-8d44f4ab2cd7',
|
||||||
|
// preview_url: 'https://images.unsplash.com/photo-1669311540088-8d44f4ab2cd7'
|
||||||
|
// },
|
||||||
|
// local: undefined,
|
||||||
|
// uploading: false
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// remote: {
|
||||||
|
// id: '02',
|
||||||
|
// type: 'image',
|
||||||
|
// url: 'https://images.unsplash.com/photo-1669311605888-07172f42cb35',
|
||||||
|
// preview_url: 'https://images.unsplash.com/photo-1669311605888-07172f42cb35'
|
||||||
|
// },
|
||||||
|
// local: undefined,
|
||||||
|
// uploading: false
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// remote: {
|
||||||
|
// id: '03',
|
||||||
|
// type: 'image',
|
||||||
|
// url: 'https://images.unsplash.com/photo-1669311576866-d77abb31f4ce',
|
||||||
|
// preview_url: 'https://images.unsplash.com/photo-1669311576866-d77abb31f4ce'
|
||||||
|
// },
|
||||||
|
// local: undefined,
|
||||||
|
// uploading: false
|
||||||
|
// }
|
||||||
|
]
|
||||||
},
|
},
|
||||||
visibility: 'public',
|
visibility: 'public',
|
||||||
visibilityLock: false,
|
visibilityLock: false,
|
||||||
|
@ -134,7 +134,7 @@ const Explore = ({ route: { key: page } }: { route: { key: 'Explore' } }) => {
|
|||||||
paddingHorizontal: StyleConstants.Spacing.Global.PagePadding,
|
paddingHorizontal: StyleConstants.Spacing.Global.PagePadding,
|
||||||
marginTop: StyleConstants.Spacing.S,
|
marginTop: StyleConstants.Spacing.S,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderRadius: StyleConstants.Spacing.S,
|
borderRadius: StyleConstants.BorderRadius,
|
||||||
marginHorizontal: StyleConstants.Spacing.Global.PagePadding,
|
marginHorizontal: StyleConstants.Spacing.Global.PagePadding,
|
||||||
borderColor: colors.border
|
borderColor: colors.border
|
||||||
}}
|
}}
|
||||||
|
@ -14,7 +14,7 @@ const AccountInformationAvatar: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<GracefullyImage
|
<GracefullyImage
|
||||||
style={{ borderRadius: 8, overflow: 'hidden' }}
|
style={{ borderRadius: StyleConstants.BorderRadius, overflow: 'hidden' }}
|
||||||
dimension={{ width: StyleConstants.Avatar.L, height: StyleConstants.Avatar.L }}
|
dimension={{ width: StyleConstants.Avatar.L, height: StyleConstants.Avatar.L }}
|
||||||
sources={{
|
sources={{
|
||||||
default: { uri: account?.avatar },
|
default: { uri: account?.avatar },
|
||||||
|
@ -110,7 +110,7 @@ const TabSharedReport: React.FC<TabSharedStackScreenProps<'Tab-Shared-Report'>>
|
|||||||
margin: StyleConstants.Spacing.Global.PagePadding,
|
margin: StyleConstants.Spacing.Global.PagePadding,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderColor: colors.red,
|
borderColor: colors.red,
|
||||||
borderRadius: 8
|
borderRadius: StyleConstants.BorderRadius
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ComponentAccount account={account} props={{}} />
|
<ComponentAccount account={account} props={{}} />
|
||||||
|
@ -79,7 +79,7 @@ const TabSharedUsers: React.FC<TabSharedStackScreenProps<'Tab-Shared-Users'>> =
|
|||||||
padding: StyleConstants.Spacing.S,
|
padding: StyleConstants.Spacing.S,
|
||||||
borderColor: colors.border,
|
borderColor: colors.border,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderRadius: StyleConstants.Spacing.S
|
borderRadius: StyleConstants.BorderRadius
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
|
@ -55,7 +55,7 @@ const ScreenTabs = () => {
|
|||||||
sources={{ default: { uri: avatarStatic } }}
|
sources={{ default: { uri: avatarStatic } }}
|
||||||
dimension={{ width: size, height: size }}
|
dimension={{ width: size, height: size }}
|
||||||
style={{
|
style={{
|
||||||
borderRadius: size,
|
borderRadius: 99,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
borderWidth: focused ? 2 : 0,
|
borderWidth: focused ? 2 : 0,
|
||||||
borderColor: focused ? colors.primaryDefault : color
|
borderColor: focused ? colors.primaryDefault : color
|
||||||
|
@ -21,5 +21,7 @@ export const StyleConstants = {
|
|||||||
Global: { PagePadding: Base * 4 }
|
Global: { PagePadding: Base * 4 }
|
||||||
},
|
},
|
||||||
|
|
||||||
|
BorderRadius: Base * 2,
|
||||||
|
|
||||||
Avatar: { XS: 32, S: 40, M: 48, L: 96 }
|
Avatar: { XS: 32, S: 40, M: 48, L: 96 }
|
||||||
}
|
}
|
||||||
|
@ -83,9 +83,9 @@ const themeColors: {
|
|||||||
dark_darker: 'rgba(18, 18, 18, 0.5)'
|
dark_darker: 'rgba(18, 18, 18, 0.5)'
|
||||||
},
|
},
|
||||||
backgroundOverlayInvert: {
|
backgroundOverlayInvert: {
|
||||||
light: 'rgba(25, 25, 25, 0.5)',
|
light: 'rgba(25, 25, 25, 0.75)',
|
||||||
dark_lighter: 'rgba(0, 0, 0, 0.5)',
|
dark_lighter: 'rgba(0, 0, 0, 0.75)',
|
||||||
dark_darker: 'rgba(0, 0, 0, 0.5)'
|
dark_darker: 'rgba(0, 0, 0, 0.75)'
|
||||||
},
|
},
|
||||||
|
|
||||||
border: {
|
border: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user