Merge branch 'main' into candidate

This commit is contained in:
xmflsct 2022-12-12 00:32:42 +01:00
commit 7cd0fa1c32
24 changed files with 229 additions and 225 deletions

View File

@ -1,6 +1,7 @@
Enjoy toooting! This version includes following improvements and fixes:
- Automatic setting detected language when tooting
- Remember public timeline type selection
- Show diffing of edit history
- Added notification for admins
- Fix whole word filter matching
- Fix tablet cannot delete toot drafts

View File

@ -1,6 +1,7 @@
toooting愉快此版本包括以下改进和修复
- 自动识别发嘟语言
- 记住上次公共时间轴选项
- 显示编辑历史的差异
- 新增管理员推送通知
- 修复过滤整词功能
- 修复平板不能删除草稿

View File

@ -295,7 +295,7 @@ PODS:
- React-Core
- react-native-blurhash (1.1.10):
- React-Core
- react-native-cameraroll (5.1.0):
- react-native-cameraroll (5.2.0):
- React-Core
- react-native-image-picker (4.10.2):
- React-Core
@ -311,7 +311,7 @@ PODS:
- React-Core
- react-native-pager-view (6.1.2):
- React-Core
- react-native-paste-input (0.5.1):
- react-native-paste-input (0.5.2):
- React-Core
- Swime (= 3.0.6)
- react-native-safe-area-context (4.4.1):
@ -428,7 +428,7 @@ PODS:
- RNScreens (3.18.2):
- React-Core
- React-RCTImage
- RNSentry (4.10.1):
- RNSentry (4.11.0):
- React-Core
- Sentry/HybridSDK (= 7.31.2)
- RNShareMenu (6.0.0):
@ -736,7 +736,7 @@ SPEC CHECKSUMS:
React-logger: 1623c216abaa88974afce404dc8f479406bbc3a0
react-native-blur: 50c9feabacbc5f49b61337ebc32192c6be7ec3c3
react-native-blurhash: add4df9a937b4e021a24bc67a0714f13e0bd40b7
react-native-cameraroll: a40b082318eb1ecd0336a2f29d9f74b7f2c8cae8
react-native-cameraroll: 0ff04cc4e0ff5f19a94ff4313e5c8bc4503cd86d
react-native-image-picker: bf34f3f516d139ed3e24c5f5a381a91819e349ea
react-native-ios-context-menu: b170594b4448c0cd10c79e13432216bac99de1ac
react-native-language-detection: f414937fa715108ab50a6269a3de0bcb95e4ceb0
@ -744,7 +744,7 @@ SPEC CHECKSUMS:
react-native-menu: 8e172cfcf0e42e92f028e7781eddf84d430cae24
react-native-netinfo: 2517ad504b3d303e90d7a431b0fcaef76d207983
react-native-pager-view: 54bed894cecebe28cede54c01038d9d1e122de43
react-native-paste-input: 183ad7dc224e192719616f4258dde5b548627d08
react-native-paste-input: 88709b4fd586ea8cc56ba5e2fc4cdfe90597730c
react-native-safe-area-context: 99b24a0c5acd0d5dcac2b1a7f18c49ea317be99a
react-native-segmented-control: 65df6cd0619b780b3843d574a72d4c7cec396097
React-perflogger: 8c79399b0500a30ee8152d0f9f11beae7fc36595
@ -765,7 +765,7 @@ SPEC CHECKSUMS:
RNGestureHandler: 62232ba8f562f7dea5ba1b3383494eb5bf97a4d3
RNReanimated: ce445c233a6ff5600223484a88ad5704945d972a
RNScreens: 34cc502acf1b916c582c60003dc3089fa01dc66d
RNSentry: 3c27f3c57f16bab9835d9555add298571077e0c1
RNSentry: f052387ebe939949c74c2cae0c850e76f6d14ddb
RNShareMenu: cb9dac548c8bf147d06f0bf07296ad51ea9f5fc3
RNSVG: 3a79c0c4992213e4f06c08e62730c5e7b9e4dc17
SDWebImage: b9a731e1d6307f44ca703b3976d18c24ca561e84

View File

@ -574,6 +574,7 @@
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_OBJC_BRIDGING_HEADER = "tooot-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_PRECOMPILE_BRIDGING_HEADER = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2,6";
VERSIONING_SYSTEM = "apple-generic";
@ -611,6 +612,7 @@
SUPPORTS_MACCATALYST = YES;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_OBJC_BRIDGING_HEADER = "tooot-Bridging-Header.h";
SWIFT_PRECOMPILE_BRIDGING_HEADER = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2,6";
VERSIONING_SYSTEM = "apple-generic";
@ -781,6 +783,7 @@
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "ShareExtension/ShareExtension-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_PRECOMPILE_BRIDGING_HEADER = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2,6";
};
@ -828,6 +831,7 @@
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "ShareExtension/ShareExtension-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_PRECOMPILE_BRIDGING_HEADER = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2,6";
};

View File

@ -25,24 +25,25 @@
"@formatjs/intl-numberformat": "^8.3.3",
"@formatjs/intl-pluralrules": "^5.1.8",
"@formatjs/intl-relativetimeformat": "^11.1.8",
"@mattermost/react-native-paste-input": "^0.5.1",
"@mattermost/react-native-paste-input": "^0.5.2",
"@neverdull-agency/expo-unlimited-secure-store": "^1.0.10",
"@react-native-async-storage/async-storage": "~1.17.11",
"@react-native-camera-roll/camera-roll": "^5.1.0",
"@react-native-camera-roll/camera-roll": "^5.2.0",
"@react-native-clipboard/clipboard": "^1.11.1",
"@react-native-community/blur": "^4.3.0",
"@react-native-community/netinfo": "9.3.7",
"@react-native-community/segmented-control": "^2.2.2",
"@react-native-menu/menu": "^0.7.2",
"@react-navigation/bottom-tabs": "^6.4.3",
"@react-navigation/native": "^6.0.16",
"@react-navigation/native-stack": "^6.9.4",
"@react-navigation/stack": "^6.3.7",
"@react-navigation/bottom-tabs": "^6.5.0",
"@react-navigation/native": "^6.1.0",
"@react-navigation/native-stack": "^6.9.5",
"@react-navigation/stack": "^6.3.8",
"@reduxjs/toolkit": "^1.9.1",
"@sentry/react-native": "4.10.1",
"@sentry/react-native": "4.11.0",
"@sharcoux/slider": "^6.1.1",
"@tanstack/react-query": "^4.19.1",
"axios": "^0.27.2",
"axios": "^1.2.1",
"diff": "^5.1.0",
"expo": "^47.0.8",
"expo-auth-session": "^3.7.3",
"expo-av": "^13.0.2",
@ -60,12 +61,12 @@
"expo-store-review": "^6.0.0",
"expo-video-thumbnails": "^7.0.0",
"expo-web-browser": "~12.0.0",
"i18next": "^22.0.6",
"i18next": "^22.4.1",
"linkify-it": "^4.0.1",
"lodash": "^4.17.21",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^12.0.0",
"react-i18next": "^12.1.1",
"react-intl": "^6.2.5",
"react-native": "0.70.6",
"react-native-animated-spinkit": "^1.5.2",
@ -88,7 +89,7 @@
"react-native-share-menu": "^6.0.0",
"react-native-svg": "^13.6.0",
"react-native-swipe-list-view": "^3.2.9",
"react-native-tab-view": "^3.3.2",
"react-native-tab-view": "^3.3.3",
"react-redux": "^8.0.5",
"redux-persist": "^6.0.0",
"rn-placeholder": "^3.0.3",
@ -101,11 +102,12 @@
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"@expo/config": "^7.0.3",
"@types/diff": "^5.0.2",
"@types/linkify-it": "^3.0.2",
"@types/lodash": "^4.14.191",
"@types/react": "~18.0.26",
"@types/react-dom": "~18.0.9",
"@types/react-native": "~0.70.7",
"@types/react-native": "~0.70.8",
"@types/react-native-base64": "^0.2.0",
"@types/react-native-share-menu": "^5.0.2",
"@types/react-timeago": "^4.1.3",
@ -119,6 +121,6 @@
"patch-package": "^6.5.0",
"postinstall-postinstall": "^2.1.0",
"react-native-clean-project": "^4.0.1",
"typescript": "^4.9.3"
"typescript": "^4.9.4"
}
}

View File

@ -146,7 +146,8 @@ const ComponentInstance: React.FC<Props> = ({
borderBottomWidth: 1,
...StyleConstants.FontStyle.M,
color: colors.primaryDefault,
borderBottomColor: instanceQuery.isError ? colors.red : colors.border
borderBottomColor: instanceQuery.isError ? colors.red : colors.border,
...(Platform.OS === 'android' && { paddingRight: 0 })
}}
editable={false}
defaultValue='https://'
@ -158,7 +159,8 @@ const ComponentInstance: React.FC<Props> = ({
...StyleConstants.FontStyle.M,
marginRight: StyleConstants.Spacing.M,
color: colors.primaryDefault,
borderBottomColor: instanceQuery.isError ? colors.red : colors.border
borderBottomColor: instanceQuery.isError ? colors.red : colors.border,
...(Platform.OS === 'android' && { paddingLeft: 0 })
}}
onChangeText={debounce(text => setDomain(text.replace(/^http(s)?\:\/\//i, '')), 1000, {
trailing: true

View File

@ -5,7 +5,7 @@ import { StyleConstants } from '@utils/styles/constants'
import { adaptiveScale } from '@utils/styles/scaling'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useMemo } from 'react'
import { Platform, StyleSheet } from 'react-native'
import { Platform, StyleSheet, TextStyle } from 'react-native'
import FastImage from 'react-native-fast-image'
import { useSelector } from 'react-redux'
import validUrl from 'valid-url'
@ -18,16 +18,11 @@ export interface Props {
size?: 'S' | 'M' | 'L'
adaptiveSize?: boolean
fontBold?: boolean
style?: TextStyle
}
const ParseEmojis = React.memo(
({
content,
emojis,
size = 'M',
adaptiveSize = false,
fontBold = false
}: Props) => {
({ content, emojis, size = 'M', adaptiveSize = false, fontBold = false, style }: Props) => {
const { reduceMotionEnabled } = useAccessibility()
const adaptiveFontsize = useSelector(getSettingsFontsize)
@ -51,22 +46,13 @@ const ParseEmojis = React.memo(
image: {
width: adaptedFontsize,
height: adaptedFontsize,
...(Platform.OS === 'ios'
? {
transform: [{ translateY: -2 }]
}
: {
transform: [{ translateY: 1 }]
})
...(Platform.OS === 'android' && { transform: [{ translateY: 2 }] })
}
})
}, [theme, adaptiveFontsize])
return (
<CustomText
style={styles.text}
fontWeight={fontBold ? 'Bold' : undefined}
>
<CustomText style={[styles.text, style]} fontWeight={fontBold ? 'Bold' : undefined}>
{emojis ? (
content
.split(regexEmoji)
@ -78,11 +64,7 @@ const ParseEmojis = React.memo(
return emojiShortcode === `:${emoji.shortcode}:`
})
if (emojiIndex === -1) {
return (
<CustomText key={emojiShortcode + i}>
{emojiShortcode}
</CustomText>
)
return <CustomText key={emojiShortcode + i}>{emojiShortcode}</CustomText>
} else {
const uri = reduceMotionEnabled
? emojis[emojiIndex].static_url

View File

@ -10,6 +10,7 @@ import { StyleConstants } from '@utils/styles/constants'
import layoutAnimation from '@utils/styles/layoutAnimation'
import { adaptiveScale } from '@utils/styles/scaling'
import { useTheme } from '@utils/styles/ThemeManager'
import { isEqual } from 'lodash'
import React, { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Platform, Pressable, View } from 'react-native'
@ -133,13 +134,8 @@ const renderNode = ({
name='ExternalLink'
size={adaptedFontsize}
style={{
...(Platform.OS === 'ios'
? {
transform: [{ translateY: -2 }]
}
: {
transform: [{ translateY: 1 }]
})
marginLeft: StyleConstants.Spacing.XS,
...(Platform.OS === 'android' && { transform: [{ translateY: 2 }] })
}}
/>
) : null}
@ -320,7 +316,7 @@ const ParseHTML = React.memo(
/>
)
},
(prev, next) => prev.content === next.content
(prev, next) => prev.content === next.content && isEqual(prev.emojis, next.emojis)
)
export default ParseHTML

View File

@ -1,5 +1,6 @@
import ComponentSeparator from '@components/Separator'
import { useScrollToTop } from '@react-navigation/native'
import { UseInfiniteQueryOptions } from '@tanstack/react-query'
import { QueryKeyTimeline, useTimelineQuery } from '@utils/queryHooks/timeline'
import { getInstanceActive } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
@ -17,15 +18,19 @@ const AnimatedFlatList = Animated.createAnimatedComponent(FlatList)
export interface Props {
flRef?: RefObject<FlatList<any>>
queryKey: QueryKeyTimeline
queryOptions?: Omit<
UseInfiniteQueryOptions<any>,
'notifyOnChangeProps' | 'getNextPageParam' | 'getPreviousPageParam' | 'select' | 'onSuccess'
>
disableRefresh?: boolean
disableInfinity?: boolean
lookback?: Extract<App.Pages, 'Following' | 'Local' | 'LocalPublic'>
customProps: Partial<FlatListProps<any>> & Pick<FlatListProps<any>, 'renderItem'>
}
const Timeline: React.FC<Props> = ({
flRef: customFLRef,
queryKey,
queryOptions,
disableRefresh = false,
disableInfinity = false,
customProps
@ -36,6 +41,7 @@ const Timeline: React.FC<Props> = ({
useTimelineQuery({
...queryKey[1],
options: {
...queryOptions,
notifyOnChangeProps: Platform.select({
ios: ['dataUpdatedAt', 'isFetching'],
android: ['dataUpdatedAt', 'isFetching', 'isLoading']

View File

@ -69,9 +69,12 @@ const TimelineDefault: React.FC<Props> = ({
}
const mainStyle: StyleProp<ViewStyle> = {
padding: StyleConstants.Spacing.Global.PagePadding,
flex: 1,
padding: disableDetails
? StyleConstants.Spacing.Global.PagePadding / 1.5
: StyleConstants.Spacing.Global.PagePadding,
backgroundColor: colors.backgroundDefault,
paddingBottom: disableDetails ? StyleConstants.Spacing.Global.PagePadding : 0
paddingBottom: disableDetails ? StyleConstants.Spacing.Global.PagePadding / 1.5 : 0,
}
const main = () => (
<>
@ -81,7 +84,13 @@ const TimelineDefault: React.FC<Props> = ({
<TimelineActioned action='pinned' />
) : null}
<View style={{ flex: 1, width: '100%', flexDirection: 'row' }}>
<View
style={{
flex: 1,
flexDirection: 'row',
...(disableDetails && { alignItems: 'flex-start', overflow: 'hidden' })
}}
>
<TimelineAvatar />
<TimelineHeaderDefault />
</View>
@ -89,7 +98,11 @@ const TimelineDefault: React.FC<Props> = ({
<View
style={{
paddingTop: highlighted ? StyleConstants.Spacing.S : 0,
paddingLeft: highlighted ? 0 : StyleConstants.Avatar.M + StyleConstants.Spacing.S
paddingLeft: highlighted
? 0
: (disableDetails ? StyleConstants.Avatar.XS : StyleConstants.Avatar.M) +
StyleConstants.Spacing.S,
...(disableDetails && { marginTop: -StyleConstants.Spacing.S })
}}
>
<TimelineContent setSpoilerExpanded={setSpoilerExpanded} />

View File

@ -12,7 +12,7 @@ export interface Props {
}
const TimelineAvatar: React.FC<Props> = ({ account }) => {
const { status, highlighted, disableOnPress } = useContext(StatusContext)
const { status, highlighted, disableDetails, disableOnPress } = useContext(StatusContext)
const actualAccount = account || status?.account
if (!actualAccount) return null
@ -33,10 +33,17 @@ const TimelineAvatar: React.FC<Props> = ({ account }) => {
!disableOnPress && navigation.push('Tab-Shared-Account', { account: actualAccount })
}
uri={{ original: actualAccount.avatar, static: actualAccount.avatar_static }}
dimension={{
width: StyleConstants.Avatar.M,
height: StyleConstants.Avatar.M
}}
dimension={
disableDetails
? {
width: StyleConstants.Avatar.XS,
height: StyleConstants.Avatar.XS
}
: {
width: StyleConstants.Avatar.M,
height: StyleConstants.Avatar.M
}
}
style={{
borderRadius: StyleConstants.Avatar.M,
overflow: 'hidden',

View File

@ -10,7 +10,7 @@ import { useStatusQuery } from '@utils/queryHooks/status'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useContext, useEffect, useState } from 'react'
import { Pressable, StyleSheet, Text, View } from 'react-native'
import { Pressable, StyleSheet, View } from 'react-native'
import { Circle } from 'react-native-animated-spinkit'
import TimelineDefault from '../Default'
import StatusContext from './Context'
@ -187,7 +187,10 @@ const TimelineCard: React.FC = () => {
style={{
flex: 1,
flexDirection: 'row',
minHeight: isAccount && foundAccount ? undefined : StyleConstants.Font.LineHeight.M * 5,
minHeight:
(isStatus && foundStatus) || (isAccount && foundAccount)
? undefined
: StyleConstants.Font.LineHeight.M * 5,
marginTop: StyleConstants.Spacing.M,
borderWidth: StyleSheet.hairlineWidth,
borderRadius: StyleConstants.Spacing.S,

View File

@ -53,7 +53,6 @@ const TimelineHeaderAndroid: React.FC = () => {
{mGroup.map(menu => (
<DropdownMenu.Item key={menu.key} {...menu.item}>
<DropdownMenu.ItemTitle children={menu.title} />
<DropdownMenu.ItemIcon iosIconName={menu.icon} />
</DropdownMenu.Item>
))}
</DropdownMenu.Group>
@ -64,7 +63,6 @@ const TimelineHeaderAndroid: React.FC = () => {
{mGroup.map(menu => (
<DropdownMenu.Item key={menu.key} {...menu.item}>
<DropdownMenu.ItemTitle children={menu.title} />
<DropdownMenu.ItemIcon iosIconName={menu.icon} />
</DropdownMenu.Item>
))}
</DropdownMenu.Group>
@ -75,7 +73,6 @@ const TimelineHeaderAndroid: React.FC = () => {
{mGroup.map(menu => (
<DropdownMenu.Item key={menu.key} {...menu.item}>
<DropdownMenu.ItemTitle children={menu.title} />
<DropdownMenu.ItemIcon iosIconName={menu.icon} />
</DropdownMenu.Item>
))}
</DropdownMenu.Group>
@ -86,7 +83,6 @@ const TimelineHeaderAndroid: React.FC = () => {
{mGroup.map(menu => (
<DropdownMenu.Item key={menu.key} {...menu.item}>
<DropdownMenu.ItemTitle children={menu.title} />
<DropdownMenu.ItemIcon iosIconName={menu.icon} />
</DropdownMenu.Item>
))}
</DropdownMenu.Group>

View File

@ -42,14 +42,20 @@ const TimelineHeaderDefault: React.FC = () => {
return (
<View style={{ flex: 1, flexDirection: 'row' }}>
<View style={{ flex: 7 }}>
<View
style={{
flex: 7,
...(disableDetails && { flexDirection: 'row' })
}}
>
<HeaderSharedAccount account={status.account} />
<View
style={{
flexDirection: 'row',
alignItems: 'center',
marginTop: StyleConstants.Spacing.XS,
marginBottom: StyleConstants.Spacing.S
...(disableDetails
? { marginLeft: StyleConstants.Spacing.S }
: { marginTop: StyleConstants.Spacing.XS, marginBottom: StyleConstants.Spacing.S })
}}
>
<HeaderSharedCreated

View File

@ -22,10 +22,7 @@ const mediaSelector = async ({
indicateMaximum = false,
showActionSheetWithOptions
}: Props): Promise<Asset[]> => {
const _maximum =
maximum ||
getInstanceConfigurationStatusMaxAttachments(store.getState()) ||
4
const _maximum = maximum || getInstanceConfigurationStatusMaxAttachments(store.getState()) || 4
const options = () => {
switch (mediaType) {
@ -33,7 +30,7 @@ const mediaSelector = async ({
return [
i18next.t(
'componentMediaSelector:options.image',
indicateMaximum ? { context: 'max', max: _maximum } : undefined
indicateMaximum ? { context: 'max', max: _maximum } : {}
),
i18next.t('common:buttons.cancel')
]
@ -41,7 +38,7 @@ const mediaSelector = async ({
return [
i18next.t(
'componentMediaSelector:options.video',
indicateMaximum ? { context: 'max', max: 1 } : undefined
indicateMaximum ? { context: 'max', max: 1 } : {}
),
i18next.t('common:buttons.cancel')
]
@ -49,11 +46,11 @@ const mediaSelector = async ({
return [
i18next.t(
'componentMediaSelector:options.image',
indicateMaximum ? { context: 'max', max: _maximum } : undefined
indicateMaximum ? { context: 'max', max: _maximum } : {}
),
i18next.t(
'componentMediaSelector:options.video',
indicateMaximum ? { context: 'max', max: 1 } : undefined
indicateMaximum ? { context: 'max', max: 1 } : {}
),
i18next.t('common:buttons.cancel')
]

18
src/helpers/removeHTML.ts Normal file
View File

@ -0,0 +1,18 @@
import htmlparser2 from 'htmlparser2-without-node-native'
const removeHTML = (text: string): string => {
let raw: string = ''
const parser = new htmlparser2.Parser({
ontext: (text: string) => {
raw = raw + text
}
})
parser.write(text)
parser.end()
return raw
}
export default removeHTML

View File

@ -16,7 +16,6 @@ const ComposeReply: React.FC = () => {
style={{
flex: 1,
flexDirection: 'row',
minHeight: StyleConstants.Font.LineHeight.M * 5,
borderWidth: StyleSheet.hairlineWidth,
borderRadius: StyleConstants.Spacing.S,
overflow: 'hidden',

View File

@ -85,7 +85,6 @@ const Root: React.FC<NativeStackScreenProps<TabLocalStackParamList, 'Tab-Local-R
return (
<Timeline
queryKey={queryKey}
lookback='Following'
customProps={{
renderItem: ({ item }) => <TimelineDefault item={item} queryKey={queryKey} />
}}

View File

@ -83,15 +83,6 @@ const TabMeListEdit: React.FC<TabMeStackScreenProps<'Tab-Me-List-Edit'>> = ({
useEffect(() => {
navigation.setOptions({
title: params.type === 'add' ? t('me.stacks.listAdd.name') : t('me.stacks.listEdit.name'),
...(Platform.OS === 'android' && {
headerCenter: () => (
<HeaderCenter
content={
params.type === 'add' ? t('me.stacks.listAdd.name') : t('me.stacks.listEdit.name')
}
/>
)
}),
headerLeft: () => (
<HeaderLeft
content='X'

View File

@ -1,10 +1,7 @@
import { HeaderCenter, HeaderLeft } from '@components/Header'
import { Message } from '@components/Message'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import {
TabMeProfileStackParamList,
TabMeStackScreenProps
} from '@utils/navigation/navigators'
import { TabMeProfileStackParamList, TabMeStackScreenProps } from '@utils/navigation/navigators'
import React, { useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { KeyboardAvoidingView, Platform } from 'react-native'
@ -16,9 +13,7 @@ import TabMeProfileRoot from './Profile/Root'
const Stack = createNativeStackNavigator<TabMeProfileStackParamList>()
const TabMeProfile: React.FC<TabMeStackScreenProps<'Tab-Me-Switch'>> = ({
navigation
}) => {
const TabMeProfile: React.FC<TabMeStackScreenProps<'Tab-Me-Switch'>> = ({ navigation }) => {
const { t } = useTranslation('screenTabs')
const messageRef = useRef<FlashMessage>(null)
@ -32,82 +27,37 @@ const TabMeProfile: React.FC<TabMeStackScreenProps<'Tab-Me-Switch'>> = ({
name='Tab-Me-Profile-Root'
options={{
title: t('me.stacks.profile.name'),
...(Platform.OS === 'android' && {
headerCenter: () => (
<HeaderCenter content={t('me.stacks.profile.name')} />
)
}),
headerLeft: () => (
<HeaderLeft
content='ChevronDown'
onPress={() => navigation.goBack()}
/>
<HeaderLeft content='ChevronDown' onPress={() => navigation.goBack()} />
)
}}
>
{({ route, navigation }) => (
<TabMeProfileRoot
messageRef={messageRef}
route={route}
navigation={navigation}
/>
<TabMeProfileRoot messageRef={messageRef} route={route} navigation={navigation} />
)}
</Stack.Screen>
<Stack.Screen
name='Tab-Me-Profile-Name'
options={{
title: t('me.stacks.profileName.name'),
...(Platform.OS === 'android' && {
headerCenter: () => (
<HeaderCenter content={t('me.stacks.profileName.name')} />
)
})
}}
options={{ title: t('me.stacks.profileName.name') }}
>
{({ route, navigation }) => (
<TabMeProfileName
messageRef={messageRef}
route={route}
navigation={navigation}
/>
<TabMeProfileName messageRef={messageRef} route={route} navigation={navigation} />
)}
</Stack.Screen>
<Stack.Screen
name='Tab-Me-Profile-Note'
options={{
title: t('me.stacks.profileNote.name'),
...(Platform.OS === 'android' && {
headerCenter: () => (
<HeaderCenter content={t('me.stacks.profileNote.name')} />
)
})
}}
options={{ title: t('me.stacks.profileNote.name') }}
>
{({ route, navigation }) => (
<TabMeProfileNote
messageRef={messageRef}
route={route}
navigation={navigation}
/>
<TabMeProfileNote messageRef={messageRef} route={route} navigation={navigation} />
)}
</Stack.Screen>
<Stack.Screen
name='Tab-Me-Profile-Fields'
options={{
title: t('me.stacks.profileFields.name'),
...(Platform.OS === 'android' && {
headerCenter: () => (
<HeaderCenter content={t('me.stacks.profileFields.name')} />
)
})
}}
options={{ title: t('me.stacks.profileFields.name') }}
>
{({ route, navigation }) => (
<TabMeProfileFields
messageRef={messageRef}
route={route}
navigation={navigation}
/>
<TabMeProfileFields messageRef={messageRef} route={route} navigation={navigation} />
)}
</Stack.Screen>
</Stack.Navigator>

View File

@ -4,44 +4,86 @@ import { ParseEmojis } from '@components/Parse'
import ComponentSeparator from '@components/Separator'
import CustomText from '@components/Text'
import TimelineAttachment from '@components/Timeline/Shared/Attachment'
import TimelineContent from '@components/Timeline/Shared/Content'
import StatusContext from '@components/Timeline/Shared/Context'
import HeaderSharedCreated from '@components/Timeline/Shared/HeaderShared/Created'
import removeHTML from '@helpers/removeHTML'
import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
import { useStatusHistory } from '@utils/queryHooks/statusesHistory'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import { diffWords } from 'diff'
import React, { useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { FlatList, View } from 'react-native'
const ContentView: React.FC<{ item: Mastodon.StatusHistory }> = ({ item }) => {
const ContentView: React.FC<{
item: Mastodon.StatusHistory
prevItem?: Mastodon.StatusHistory
}> = ({ item, prevItem }) => {
const { colors } = useTheme()
const changesSpoiler = diffWords(
removeHTML(prevItem?.spoiler_text || item.spoiler_text || ''),
removeHTML(item.spoiler_text || '')
)
const changesContent = diffWords(
removeHTML(prevItem?.content || item.content),
removeHTML(item.content)
)
return (
// @ts-ignore
<StatusContext.Provider value={{ status: item, disableOnPress: true }}>
<HeaderSharedCreated created_at={item.created_at} />
<TimelineContent />
{item.poll?.options.map((option, index) => (
<View key={index} style={{ flex: 1, paddingVertical: StyleConstants.Spacing.XS }}>
<View style={{ flex: 1, flexDirection: 'row' }}>
<Icon
<View style={{ padding: StyleConstants.Spacing.Global.PagePadding }}>
<HeaderSharedCreated created_at={item.created_at} />
{changesSpoiler.length && changesSpoiler[0].count ? (
<CustomText fontSize='M' style={{ color: colors.primaryDefault }}>
{changesSpoiler.map(({ value, added, removed }, index) => (
<ParseEmojis
key={index}
content={value}
emojis={item.emojis}
style={{
color: added ? colors.green : removed ? colors.red : undefined,
textDecorationLine: removed ? 'line-through' : undefined
}}
/>
))}
</CustomText>
) : null}
<CustomText fontSize='M' style={{ color: colors.primaryDefault }}>
{changesContent.map(({ value, added, removed }, index) => (
<ParseEmojis
key={index}
content={value}
emojis={item.emojis}
style={{
paddingTop: StyleConstants.Font.LineHeight.M - StyleConstants.Font.Size.M,
marginRight: StyleConstants.Spacing.S
color: added ? colors.green : removed ? colors.red : undefined,
textDecorationLine: removed ? 'line-through' : undefined
}}
name='Circle'
size={StyleConstants.Font.Size.M}
color={colors.disabled}
/>
<CustomText style={{ flex: 1 }}>
<ParseEmojis content={option.title} emojis={item.poll?.emojis} />
</CustomText>
))}
</CustomText>
{item.poll?.options.map((option, index) => (
<View key={index} style={{ flex: 1, paddingVertical: StyleConstants.Spacing.XS }}>
<View style={{ flex: 1, flexDirection: 'row' }}>
<Icon
style={{
paddingTop: StyleConstants.Font.LineHeight.M - StyleConstants.Font.Size.M,
marginRight: StyleConstants.Spacing.S
}}
name='Circle'
size={StyleConstants.Font.Size.M}
color={colors.disabled}
/>
<CustomText style={{ flex: 1 }}>
<ParseEmojis content={option.title} emojis={item.poll?.emojis} />
</CustomText>
</View>
</View>
</View>
))}
<TimelineAttachment />
))}
<TimelineAttachment />
</View>
</StatusContext.Provider>
)
}
@ -62,41 +104,18 @@ const TabSharedHistory: React.FC<TabSharedStackScreenProps<'Tab-Shared-History'>
})
}, [])
const dataReversed = data ? [...data].reverse() : []
return (
<FlatList
style={{ flex: 1, minHeight: '100%', padding: StyleConstants.Spacing.Global.PagePadding }}
data={
data && data.length > 0
? data
.slice(0)
.reverse()
.filter((_, index) => index !== 0)
: []
}
renderItem={({ item }) => <ContentView item={item} />}
ItemSeparatorComponent={() => (
<ComponentSeparator
extraMarginLeft={0}
style={{ marginVertical: StyleConstants.Spacing.Global.PagePadding }}
/>
style={{ flex: 1, minHeight: '100%' }}
data={dataReversed}
renderItem={({ item, index }) => (
<ContentView item={item} prevItem={dataReversed[index + 1]} />
)}
ItemSeparatorComponent={ComponentSeparator}
/>
)
// return (
// <ScrollView>
// {data && data.length > 0
// ? data
// .slice(0)
// .reverse()
// .map((d, i) =>
// i !== 0 ? (
// <ContentView key={i} history={d} first={i === 1} last={i === data.length - 1} />
// ) : null
// )
// : null}
// </ScrollView>
// )
}
export default TabSharedHistory

View File

@ -74,6 +74,7 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
<Timeline
flRef={flRef}
queryKey={queryKey}
queryOptions={{ staleTime: 0, refetchOnMount: true }}
customProps={{
renderItem: ({ item }) => (
<TimelineDefault

View File

@ -21,5 +21,5 @@ export const StyleConstants = {
Global: { PagePadding: Base * 4 }
},
Avatar: { S: 40, M: 48, L: 96 }
Avatar: { XS: 32, S: 40, M: 48, L: 96 }
}

View File

@ -1880,7 +1880,7 @@
"@jridgewell/resolve-uri" "3.1.0"
"@jridgewell/sourcemap-codec" "1.4.14"
"@mattermost/react-native-paste-input@^0.5.1":
"@mattermost/react-native-paste-input@^0.5.2":
version "0.5.2"
resolved "https://registry.yarnpkg.com/@mattermost/react-native-paste-input/-/react-native-paste-input-0.5.2.tgz#7443490f5c90f3c3db0f847c8b7249d23fa0066f"
integrity sha512-aQdLUidSAbWPLXWmwM1x8AhnZIO4EN5uWx813/G3+mL8kWD7mpXrQEvMpcdtKWatD705kCyKZkvnNY4yjq0TkA==
@ -2193,7 +2193,7 @@
dependencies:
merge-options "^3.0.4"
"@react-native-camera-roll/camera-roll@^5.1.0":
"@react-native-camera-roll/camera-roll@^5.2.0":
version "5.2.0"
resolved "https://registry.yarnpkg.com/@react-native-camera-roll/camera-roll/-/camera-roll-5.2.0.tgz#a30dca7c486379650c03fb8cc6fe35b7de6eeb82"
integrity sha512-CIFkEqWeMtFo3fG/0nULrmLs8xikbOUuEty8wWxpyBWq7OM9Hi13pXJ1FWrIrxDcFuL7d0bxIqpqNrt59lAPrQ==
@ -2404,7 +2404,7 @@
resolved "https://registry.yarnpkg.com/@react-native/polyfills/-/polyfills-2.0.0.tgz#4c40b74655c83982c8cf47530ee7dc13d957b6aa"
integrity sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ==
"@react-navigation/bottom-tabs@^6.4.3":
"@react-navigation/bottom-tabs@^6.5.0":
version "6.5.0"
resolved "https://registry.yarnpkg.com/@react-navigation/bottom-tabs/-/bottom-tabs-6.5.0.tgz#8bcd98733988ffe3e5124b45920608f22b2576e4"
integrity sha512-7jKBHAk/HpIwXEsKKegB0DabPhFWS9PH2Bsmd4HUdvHj103m7H3OsrszuPB9Uxbe3RkGNtcJzeQnYOanVzNR+w==
@ -2430,7 +2430,7 @@
resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-1.3.10.tgz#7f4281eddef5ff424169413daaab9a66b27c4949"
integrity sha512-JFaoZG9S+Zz291CvAMeGw8kNl/g2AaY9Pbo+VcYO+JM6UF/E5Obq9ga2ydxDrn3an7wzdl6flA/4lWhqG82Vqw==
"@react-navigation/native-stack@^6.9.4":
"@react-navigation/native-stack@^6.9.5":
version "6.9.5"
resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-6.9.5.tgz#805adf6699524519ff4bf50ac960a923da1bc223"
integrity sha512-1ZIrla+b4gB8KDC6QewtZ/1yOS23bQctwR4Pf6ECA0stEH8ibbxh70iiI/LluL5CtWxrWfgOrl1jpQsVvtKY+Q==
@ -2438,7 +2438,7 @@
"@react-navigation/elements" "^1.3.10"
warn-once "^0.1.0"
"@react-navigation/native@^6.0.16":
"@react-navigation/native@^6.1.0":
version "6.1.0"
resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-6.1.0.tgz#ea0c79b6b0f67397305fec54eb4dbc3dd3eb087b"
integrity sha512-CdjOmbE4c/UczczqeP7ZrFXJcjnXOCwY1PDNjX51Ph1b2tHXpQ41/089k3R49dc5i2sFLk6jKaryFU2dcLr8jw==
@ -2455,7 +2455,7 @@
dependencies:
nanoid "^3.1.23"
"@react-navigation/stack@^6.3.7":
"@react-navigation/stack@^6.3.8":
version "6.3.8"
resolved "https://registry.yarnpkg.com/@react-navigation/stack/-/stack-6.3.8.tgz#bc36beb4fba1c47a45e01c9dcc501be0f6f10d54"
integrity sha512-tnSmI5wmRLA293tPo43niCOOcWsWFB1XPGeUBVsz/lJnQZIHUUx0h42t53fU22DHGXee7PiZ78Lvr1Q0m/JZJQ==
@ -2547,10 +2547,10 @@
localforage "^1.8.1"
tslib "^1.9.3"
"@sentry/react-native@4.10.1":
version "4.10.1"
resolved "https://registry.yarnpkg.com/@sentry/react-native/-/react-native-4.10.1.tgz#9e2c1f5dd4b27103882a71503805f86059a7cde9"
integrity sha512-yF5g2bCjPpfu4DUVQPlDnSMUdz5bh/i1s9zZ5cnOmA9LsXQulk9o1Z6fTeZ5LkgPzogTRjn0eudvaCz5u+nxaA==
"@sentry/react-native@4.11.0":
version "4.11.0"
resolved "https://registry.yarnpkg.com/@sentry/react-native/-/react-native-4.11.0.tgz#6820aa51ac2ed225daa0c02b58956588ad12dc62"
integrity sha512-dC8rPOabs/DNAC1Yc2mICo0vkMq+GmLEBxi2l8zIzf8e99Qii0zrGuVng9vc+PRwdBMQrKw7i17SlFEqsaoksA==
dependencies:
"@sentry/browser" "7.21.1"
"@sentry/cli" "1.74.4"
@ -2683,6 +2683,11 @@
"@types/node" "*"
"@types/responselike" "^1.0.0"
"@types/diff@^5.0.2":
version "5.0.2"
resolved "https://registry.yarnpkg.com/@types/diff/-/diff-5.0.2.tgz#dd565e0086ccf8bc6522c6ebafd8a3125c91c12b"
integrity sha512-uw8eYMIReOwstQ0QKF0sICefSy8cNO/v7gOTiIy9SbwuHyEecJUm7qlgueOO5S1udZ5I/irVydHVwMchgzbKTg==
"@types/glob@^7.1.1":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb"
@ -2802,7 +2807,7 @@
resolved "https://registry.yarnpkg.com/@types/react-native-share-menu/-/react-native-share-menu-5.0.2.tgz#c9c8854a3d091cdb046df22dafe4a92332b322f3"
integrity sha512-Qa9DGfL6Bvng2DXgCK0fFzdi9SJMGfs06MLSkCfSXBCGKlFLzSHCsXztvXlCCChn3dQArFHyz/uRUN3Sbt6LtQ==
"@types/react-native@~0.70.7":
"@types/react-native@~0.70.8":
version "0.70.8"
resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.70.8.tgz#3302a0f7eddcd3350448ca17a9e415d02b1efde6"
integrity sha512-jvs5QMOrlyi0ScfT5Brha2roDoOWtbIOadNkp0jsueVen5+pH4SQAYtzL6xu0+dIcx3J/5LtZ/JYby2C1/zUug==
@ -3508,13 +3513,14 @@ axios@0.21.1:
dependencies:
follow-redirects "^1.10.0"
axios@^0.27.2:
version "0.27.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
axios@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.2.1.tgz#44cf04a3c9f0c2252ebd85975361c026cb9f864a"
integrity sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==
dependencies:
follow-redirects "^1.14.9"
follow-redirects "^1.15.0"
form-data "^4.0.0"
proxy-from-env "^1.1.0"
babel-core@^7.0.0-bridge.0:
version "7.0.0-bridge.0"
@ -5256,6 +5262,11 @@ detect-port-alt@1.1.6:
address "^1.0.1"
debug "^2.6.0"
diff@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40"
integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==
diffie-hellman@^5.0.0:
version "5.0.3"
resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
@ -6375,7 +6386,7 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
follow-redirects@^1.0.0, follow-redirects@^1.10.0, follow-redirects@^1.14.9:
follow-redirects@^1.0.0, follow-redirects@^1.10.0, follow-redirects@^1.15.0:
version "1.15.2"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
@ -7175,10 +7186,10 @@ https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1:
agent-base "6"
debug "4"
i18next@^22.0.6:
version "22.1.5"
resolved "https://registry.yarnpkg.com/i18next/-/i18next-22.1.5.tgz#5c395b807aa670ce82a7c4f6831b7fba8f1e2c6c"
integrity sha512-Mjj45PbpZByE+c6ddLEkkj0LUyzJP1cRGeC/+O6mvp1+GAwW7rIx6aOPW9+Zxe+JO3EcJCAkibwbZrgBRF/qRA==
i18next@^22.4.1:
version "22.4.1"
resolved "https://registry.yarnpkg.com/i18next/-/i18next-22.4.1.tgz#90041c018ab93a59b6e09d6b20b35e5500f32827"
integrity sha512-BZWjrTX+OVaSxV5s94s2M+7wSlevdPgNtjeL/xXHl0CKkPGyjHNlkN6eN+0e0ex+EO8ec57OALRDUpiSSCo54g==
dependencies:
"@babel/runtime" "^7.20.6"
@ -10611,7 +10622,7 @@ react-freeze@^1.0.0:
resolved "https://registry.yarnpkg.com/react-freeze/-/react-freeze-1.0.3.tgz#5e3ca90e682fed1d73a7cb50c2c7402b3e85618d"
integrity sha512-ZnXwLQnGzrDpHBHiC56TXFXvmolPeMjTn1UOm610M4EXGzbEDR7oOIyS2ZiItgbs6eZc4oU/a0hpk8PrcKvv5g==
react-i18next@^12.0.0:
react-i18next@^12.1.1:
version "12.1.1"
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-12.1.1.tgz#2626cdbfe6bcb76ef833861c0184a5c4e5e3c089"
integrity sha512-mFdieOI0LDy84q3JuZU6Aou1DoWW2fhapcTGeBS8+vWSJuViuoCLQAMYSb0QoHhXS8B0WKUOPpx4cffAP7r/aA==
@ -10803,7 +10814,7 @@ react-native-swipe-list-view@^3.2.9:
resolved "https://registry.yarnpkg.com/react-native-swipe-list-view/-/react-native-swipe-list-view-3.2.9.tgz#d725c7cdf481dd5df12a00dbfe0120013b5f2e59"
integrity sha512-SjAEuHc/D6ovp+RjDUhfNmw6NYOntdT7+GFhfMGfP/BSLMuMWynpzJy9GKQeyB8sI78T6Lzip21TVbongOg1Mw==
react-native-tab-view@^3.3.2:
react-native-tab-view@^3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-3.3.3.tgz#33a94db2ccbe7fe8fff0c0e3f1da09cbd07edba7"
integrity sha512-hrxGu/Bj/GRXt+6ErqUFMAw2E82tjeTJ97nH1dZ2FSnLYOVnY9FDqju8TkQtT3GpJGL6Ur/ZkRT4eQfYwTZbtg==
@ -12527,7 +12538,7 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
typescript@^4.9.3:
typescript@^4.9.4:
version "4.9.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78"
integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==