mirror of https://github.com/tooot-app/app
Compare commits
5 Commits
f1c04d8c85
...
15f22d4c31
Author | SHA1 | Date |
---|---|---|
xmflsct | 15f22d4c31 | |
xmflsct | 88bafcc1e0 | |
xmflsct | 0894b4106b | |
xmflsct | 2c65dca811 | |
xmflsct | 9ed6343eb7 |
|
@ -572,7 +572,7 @@ PODS:
|
|||
- Sentry (= 7.23.0)
|
||||
- RNShareMenu (6.0.0):
|
||||
- React
|
||||
- RNSVG (12.4.4):
|
||||
- RNSVG (13.0.0):
|
||||
- React-Core
|
||||
- SDWebImage (5.13.2):
|
||||
- SDWebImage/Core (= 5.13.2)
|
||||
|
@ -958,7 +958,7 @@ SPEC CHECKSUMS:
|
|||
RNScreens: 4a1af06327774490d97342c00aee0c2bafb497b7
|
||||
RNSentry: 6798624706227656d942849d593f89c8ca3bdde5
|
||||
RNShareMenu: cb9dac548c8bf147d06f0bf07296ad51ea9f5fc3
|
||||
RNSVG: ecd661f380a07ba690c9c5929c475a44f432d674
|
||||
RNSVG: 42a0c731b11179ebbd27a3eeeafa7201ebb476ff
|
||||
SDWebImage: 72f86271a6f3139cc7e4a89220946489d4b9a866
|
||||
SDWebImageWebPCoder: 3dc350894112feab5375cfba9ce0986544a66a69
|
||||
Sentry: a0d4563fa4ddacba31fdcc35daaa8573d87224d6
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"versions": {
|
||||
"major": 4,
|
||||
"minor": 2,
|
||||
"patch": 0
|
||||
"patch": 1
|
||||
},
|
||||
"description": "tooot app for Mastodon",
|
||||
"author": "xmflsct <me@xmflsct.com>",
|
||||
|
@ -89,7 +89,7 @@
|
|||
"react-native-safe-area-context": "^4.3.1",
|
||||
"react-native-screens": "^3.15.0",
|
||||
"react-native-share-menu": "^6.0.0",
|
||||
"react-native-svg": "^12.4.4",
|
||||
"react-native-svg": "^13.0.0",
|
||||
"react-native-swipe-list-view": "^3.2.9",
|
||||
"react-native-tab-view": "^3.1.1",
|
||||
"react-query": "^3.39.2",
|
||||
|
@ -124,4 +124,4 @@
|
|||
"react-native-clean-project": "^4.0.1",
|
||||
"typescript": "^4.7.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
}
|
||||
},
|
||||
"copy": {
|
||||
"action": "",
|
||||
"succeed": ""
|
||||
"action": "Sao chép tút",
|
||||
"succeed": "Đã sao chép"
|
||||
},
|
||||
"instance": {
|
||||
"title": "Hành động máy chủ",
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"HTML": {
|
||||
"accessibilityHint": "",
|
||||
"accessibilityHint": "Nhấn để mở rộng hoặc thu gọn nội dung",
|
||||
"expanded": "{{hint}}{{totalLines}}",
|
||||
"totalLines": "",
|
||||
"defaultHint": ""
|
||||
"totalLines": " ({{count}} dòng)",
|
||||
"defaultHint": "Tút dài"
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"heading": "",
|
||||
"heading": "Chia sẻ tới...",
|
||||
"content": {
|
||||
"select_account": ""
|
||||
"select_account": "Chọn tài khoản"
|
||||
}
|
||||
}
|
|
@ -146,7 +146,7 @@
|
|||
"label": "Nhãn",
|
||||
"content": "Nội dung"
|
||||
},
|
||||
"mediaSelectionFailed": ""
|
||||
"mediaSelectionFailed": "Xử lý không thành công. Vui lòng thử lại."
|
||||
},
|
||||
"push": {
|
||||
"notAvailable": "Điện thoại của bạn chưa bật thông báo đẩy",
|
||||
|
|
|
@ -18,44 +18,32 @@ const ComposeEditAttachment: React.FC<ScreenComposeStackScreenProps<
|
|||
},
|
||||
navigation
|
||||
}) => {
|
||||
const { t } = useTranslation('screenCompose')
|
||||
const { t } = useTranslation('screenCompose')
|
||||
|
||||
const headerLeft = useCallback(
|
||||
() => (
|
||||
<HeaderLeft
|
||||
type='icon'
|
||||
content='ChevronDown'
|
||||
onPress={() => navigation.goBack()}
|
||||
/>
|
||||
),
|
||||
[]
|
||||
)
|
||||
|
||||
const children = useCallback(
|
||||
() => <ComposeEditAttachmentRoot index={index} />,
|
||||
[]
|
||||
)
|
||||
|
||||
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={children}
|
||||
options={{
|
||||
headerLeft,
|
||||
headerRight: () => <ComposeEditAttachmentSubmit index={index} />,
|
||||
title: t('content.editAttachment.header.title')
|
||||
}}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
</SafeAreaView>
|
||||
</KeyboardAvoidingView>
|
||||
)
|
||||
}
|
||||
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>
|
||||
)
|
||||
}
|
||||
|
||||
export default ComposeEditAttachment
|
||||
|
|
|
@ -5,16 +5,14 @@ import { useTheme } from '@utils/styles/ThemeManager'
|
|||
import React, { useContext } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Dimensions, Image, View } from 'react-native'
|
||||
import { PanGestureHandler } from 'react-native-gesture-handler'
|
||||
import { Gesture, GestureDetector } from 'react-native-gesture-handler'
|
||||
import Animated, {
|
||||
Extrapolate,
|
||||
interpolate,
|
||||
runOnJS,
|
||||
useAnimatedGestureHandler,
|
||||
useAnimatedStyle,
|
||||
useSharedValue
|
||||
} from 'react-native-reanimated'
|
||||
import Svg, { Circle, G, Path } from 'react-native-svg'
|
||||
import ComposeContext from '../utils/createContext'
|
||||
|
||||
export interface Props {
|
||||
|
@ -30,30 +28,19 @@ const ComposeEditAttachmentImage: React.FC<Props> = ({ index }) => {
|
|||
const theAttachmentRemote = composeState.attachments.uploads[index].remote!
|
||||
const theAttachmentLocal = composeState.attachments.uploads[index].local
|
||||
|
||||
const windowWidth = Dimensions.get('window').width
|
||||
|
||||
const imageWidthBase =
|
||||
theAttachmentRemote?.meta?.original?.aspect < 1
|
||||
? Dimensions.get('screen').width *
|
||||
theAttachmentRemote?.meta?.original?.aspect
|
||||
: Dimensions.get('screen').width
|
||||
const padding = (Dimensions.get('screen').width - imageWidthBase) / 2
|
||||
? windowWidth * theAttachmentRemote?.meta?.original?.aspect
|
||||
: windowWidth
|
||||
const imageDimensionis = {
|
||||
width: imageWidthBase,
|
||||
height:
|
||||
imageWidthBase /
|
||||
((theAttachmentRemote as Mastodon.AttachmentImage)?.meta?.original
|
||||
?.aspect || 1)
|
||||
((theAttachmentRemote as Mastodon.AttachmentImage)?.meta?.original?.aspect || 1)
|
||||
}
|
||||
|
||||
const panX = useSharedValue(
|
||||
(((theAttachmentRemote as Mastodon.AttachmentImage)?.meta?.focus?.x || 0) *
|
||||
imageDimensionis.width) /
|
||||
2
|
||||
)
|
||||
const panY = useSharedValue(
|
||||
(((theAttachmentRemote as Mastodon.AttachmentImage)?.meta?.focus?.y || 0) *
|
||||
imageDimensionis.height) /
|
||||
2
|
||||
)
|
||||
const updateFocus = ({ x, y }: { x: number; y: number }) => {
|
||||
composeDispatch({
|
||||
type: 'attachment/edit',
|
||||
|
@ -70,46 +57,50 @@ const ComposeEditAttachmentImage: React.FC<Props> = ({ index }) => {
|
|||
})
|
||||
}
|
||||
|
||||
type PanContext = {
|
||||
startX: number
|
||||
startY: number
|
||||
}
|
||||
const onGestureEvent = useAnimatedGestureHandler({
|
||||
onStart: (_, context: PanContext) => {
|
||||
context.startX = panX.value
|
||||
context.startY = panY.value
|
||||
},
|
||||
onActive: ({ translationX, translationY }, context: PanContext) => {
|
||||
panX.value = context.startX + translationX
|
||||
panY.value = context.startY + translationY
|
||||
},
|
||||
onEnd: ({ translationX, translationY }, context: PanContext) => {
|
||||
runOnJS(updateFocus)({
|
||||
x: (context.startX + translationX) / (imageDimensionis.width / 2),
|
||||
y: (context.startY + translationY) / (imageDimensionis.height / 2)
|
||||
})
|
||||
}
|
||||
const pan = useSharedValue({
|
||||
x:
|
||||
(((theAttachmentRemote as Mastodon.AttachmentImage)?.meta?.focus?.x || 0) *
|
||||
imageDimensionis.width) /
|
||||
2,
|
||||
y:
|
||||
(((theAttachmentRemote as Mastodon.AttachmentImage)?.meta?.focus?.y || 0) *
|
||||
imageDimensionis.height) /
|
||||
2
|
||||
})
|
||||
const start = useSharedValue({ x: 0, y: 0 })
|
||||
const gesture = Gesture.Pan()
|
||||
.onBegin(() => {
|
||||
start.value = pan.value
|
||||
})
|
||||
.onUpdate(e => {
|
||||
pan.value = {
|
||||
x: e.translationX + start.value.x,
|
||||
y: e.translationY + start.value.y
|
||||
}
|
||||
})
|
||||
.onEnd(() => {
|
||||
runOnJS(updateFocus)({
|
||||
x: pan.value.x / (imageDimensionis.width / 2),
|
||||
y: pan.value.y / (imageDimensionis.height / 2)
|
||||
})
|
||||
})
|
||||
.onFinalize(() => {
|
||||
start.value = pan.value
|
||||
})
|
||||
const styleTransform = useAnimatedStyle(() => {
|
||||
return {
|
||||
transform: [
|
||||
{
|
||||
translateX: interpolate(
|
||||
panX.value,
|
||||
[
|
||||
-imageDimensionis.width / 2 + padding,
|
||||
imageDimensionis.width / 2 + padding
|
||||
],
|
||||
[
|
||||
-imageDimensionis.width / 2 + padding,
|
||||
imageDimensionis.width / 2 + padding
|
||||
],
|
||||
pan.value.x,
|
||||
[-imageDimensionis.width / 2, imageDimensionis.width / 2],
|
||||
[-imageDimensionis.width / 2, imageDimensionis.width / 2],
|
||||
Extrapolate.CLAMP
|
||||
)
|
||||
},
|
||||
{
|
||||
translateY: interpolate(
|
||||
panY.value,
|
||||
pan.value.y,
|
||||
[-imageDimensionis.height / 2, imageDimensionis.height / 2],
|
||||
[-imageDimensionis.height / 2, imageDimensionis.height / 2],
|
||||
Extrapolate.CLAMP
|
||||
|
@ -128,47 +119,41 @@ const ComposeEditAttachmentImage: React.FC<Props> = ({ index }) => {
|
|||
height: imageDimensionis.height
|
||||
}}
|
||||
source={{
|
||||
uri: theAttachmentLocal?.uri
|
||||
? theAttachmentLocal.uri
|
||||
: theAttachmentRemote?.preview_url
|
||||
uri: theAttachmentLocal?.uri ? theAttachmentLocal.uri : theAttachmentRemote?.preview_url
|
||||
}}
|
||||
/>
|
||||
<PanGestureHandler onGestureEvent={onGestureEvent}>
|
||||
<GestureDetector gesture={gesture}>
|
||||
<Animated.View
|
||||
style={[
|
||||
styleTransform,
|
||||
{
|
||||
width: windowWidth * 2,
|
||||
height: imageDimensionis.height * 2,
|
||||
position: 'absolute',
|
||||
top: -500 + imageDimensionis.height / 2,
|
||||
left: -500 + imageDimensionis.width / 2
|
||||
left: -windowWidth / 2,
|
||||
top: -imageDimensionis.height / 2,
|
||||
backgroundColor: colors.backgroundOverlayInvert,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}
|
||||
]}
|
||||
>
|
||||
<Svg width='1000' height='1000' viewBox='0 0 1000 1000'>
|
||||
<G stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'>
|
||||
<G>
|
||||
<Path
|
||||
d='M1000,0 L1000,1000 L0,1000 L0,0 L1000,0 Z M500,475 C486.192881,475 475,486.192881 475,500 C475,513.807119 486.192881,525 500,525 C513.807119,525 525,513.807119 525,500 C525,486.192881 513.807119,475 500,475 Z'
|
||||
fill={colors.backgroundOverlayInvert}
|
||||
/>
|
||||
<Circle
|
||||
stroke={colors.primaryOverlay}
|
||||
stroke-width='2'
|
||||
cx='500'
|
||||
cy='500'
|
||||
r='24'
|
||||
/>
|
||||
<Circle
|
||||
fill={colors.primaryOverlay}
|
||||
cx='500'
|
||||
cy='500'
|
||||
r='2'
|
||||
/>
|
||||
</G>
|
||||
</G>
|
||||
</Svg>
|
||||
</Animated.View>
|
||||
</PanGestureHandler>
|
||||
children={
|
||||
<View
|
||||
style={{
|
||||
width: 48,
|
||||
height: 48,
|
||||
borderRadius: 24,
|
||||
borderWidth: 2,
|
||||
borderColor: colors.primaryOverlay,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</GestureDetector>
|
||||
</View>
|
||||
{screenReaderEnabled ? null : (
|
||||
<CustomText
|
||||
|
|
|
@ -2,7 +2,7 @@ import CustomText from '@components/Text'
|
|||
import AttachmentVideo from '@components/Timeline/Shared/Attachment/Video'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useContext, useMemo, useRef } from 'react'
|
||||
import React, { useContext, useRef } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { ScrollView, StyleSheet, TextInput, View } from 'react-native'
|
||||
import ComposeContext from '../utils/createContext'
|
||||
|
@ -18,7 +18,7 @@ const ComposeEditAttachmentRoot: React.FC<Props> = ({ index }) => {
|
|||
const { composeState, composeDispatch } = useContext(ComposeContext)
|
||||
const theAttachment = composeState.attachments.uploads[index].remote!
|
||||
|
||||
const mediaDisplay = useMemo(() => {
|
||||
const mediaDisplay = () => {
|
||||
if (theAttachment) {
|
||||
switch (theAttachment.type) {
|
||||
case 'image':
|
||||
|
@ -34,10 +34,10 @@ const ComposeEditAttachmentRoot: React.FC<Props> = ({ index }) => {
|
|||
video={
|
||||
video.local
|
||||
? ({
|
||||
url: video.local.uri,
|
||||
preview_url: video.local.thumbnail,
|
||||
blurhash: video.remote?.blurhash
|
||||
} as Mastodon.AttachmentVideo)
|
||||
url: video.local.uri,
|
||||
preview_url: video.local.thumbnail,
|
||||
blurhash: video.remote?.blurhash
|
||||
} as Mastodon.AttachmentVideo)
|
||||
: (video.remote as Mastodon.AttachmentVideo)
|
||||
}
|
||||
/>
|
||||
|
@ -45,22 +45,13 @@ const ComposeEditAttachmentRoot: React.FC<Props> = ({ index }) => {
|
|||
}
|
||||
}
|
||||
return null
|
||||
}, [])
|
||||
|
||||
const onChangeText = (e: any) =>
|
||||
composeDispatch({
|
||||
type: 'attachment/edit',
|
||||
payload: {
|
||||
...theAttachment,
|
||||
description: e
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const scrollViewRef = useRef<ScrollView>(null)
|
||||
|
||||
return (
|
||||
<ScrollView ref={scrollViewRef}>
|
||||
{mediaDisplay}
|
||||
{mediaDisplay()}
|
||||
<View style={{ padding: StyleConstants.Spacing.Global.PagePadding }}>
|
||||
<CustomText
|
||||
fontStyle='M'
|
||||
|
@ -86,7 +77,14 @@ const ComposeEditAttachmentRoot: React.FC<Props> = ({ index }) => {
|
|||
autoCorrect={false}
|
||||
maxLength={1500}
|
||||
multiline
|
||||
onChangeText={onChangeText}
|
||||
onChangeText={(e) =>
|
||||
composeDispatch({
|
||||
type: 'attachment/edit',
|
||||
payload: {
|
||||
...theAttachment,
|
||||
description: e
|
||||
}
|
||||
})}
|
||||
placeholder={t('content.editAttachment.content.altText.placeholder')}
|
||||
placeholderTextColor={colors.secondary}
|
||||
scrollEnabled
|
||||
|
|
|
@ -5,12 +5,12 @@ import log from './log'
|
|||
|
||||
const dev = () => {
|
||||
if (__DEV__) {
|
||||
log('log', 'devs', 'initializing wdyr')
|
||||
const whyDidYouRender = require('@welldone-software/why-did-you-render')
|
||||
whyDidYouRender(React, {
|
||||
trackHooks: true,
|
||||
hotReloadBufferMs: 1000
|
||||
})
|
||||
// log('log', 'devs', 'initializing wdyr')
|
||||
// const whyDidYouRender = require('@welldone-software/why-did-you-render')
|
||||
// whyDidYouRender(React, {
|
||||
// trackHooks: true,
|
||||
// hotReloadBufferMs: 1000
|
||||
// })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7190,10 +7190,10 @@ react-native-share-menu@^6.0.0:
|
|||
resolved "https://registry.yarnpkg.com/react-native-share-menu/-/react-native-share-menu-6.0.0.tgz#0398dd4537ca1138b774fcbff9b05a88c8329cf6"
|
||||
integrity sha512-KdmRnqjI/B2MigSxGmhbYJ3WMJxKXj+0c47ANcVZ/PTzc2vtz6d1r4KQJgkBImXgNC+vowpuD2UGdPllxadr2A==
|
||||
|
||||
react-native-svg@^12.4.4:
|
||||
version "12.4.4"
|
||||
resolved "https://registry.yarnpkg.com/react-native-svg/-/react-native-svg-12.4.4.tgz#2ba684eaea9a7402fbbe0ed9737e77284631d00e"
|
||||
integrity sha512-LpcNlEVCURexqPAvQ9ne8KrPVfYz0wIDygwud8VMRmXLezysXzyQN/DTsjm1BO9lIfYp55WQsr3u3yW/vk6iiA==
|
||||
react-native-svg@^13.0.0:
|
||||
version "13.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react-native-svg/-/react-native-svg-13.0.0.tgz#a26d28446aeb7e4bed7e1bb1cb42f2eb5462e652"
|
||||
integrity sha512-CkWB8BYGjvmGiLqqJRHfTH8/Q5tJyhltUYCmi20sqOCbjfTR5dkQUUafV0oUOhvK2lS+zuB9Dpf1Beo92rls5Q==
|
||||
dependencies:
|
||||
css-select "^5.1.0"
|
||||
css-tree "^1.1.3"
|
||||
|
|
Loading…
Reference in New Issue