From 65e9f41a3bafd46b24a34d206bb5c14120652793 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Sat, 31 Dec 2022 12:56:10 +0100 Subject: [PATCH 1/4] Fix bugs --- src/components/Parse/HTML.tsx | 28 +++++-- .../Timeline/Shared/HeaderShared/Replies.tsx | 42 +++++----- src/i18n/en/components/timeline.json | 2 +- src/screens/Tabs/Public/Root.tsx | 5 +- .../Shared/Account/Information/Fields.tsx | 82 +++++++++---------- src/screens/Tabs/Shared/Toot.tsx | 12 +-- 6 files changed, 93 insertions(+), 78 deletions(-) diff --git a/src/components/Parse/HTML.tsx b/src/components/Parse/HTML.tsx index 4ff3436f..246f839a 100644 --- a/src/components/Parse/HTML.tsx +++ b/src/components/Parse/HTML.tsx @@ -15,7 +15,7 @@ import { ElementType, parseDocument } from 'htmlparser2' import i18next from 'i18next' import React, { useContext, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' -import { Platform, Pressable, Text, TextStyleIOS, View } from 'react-native' +import { Platform, Pressable, Text, View } from 'react-native' export interface Props { content: string @@ -78,8 +78,8 @@ const ParseHTML: React.FC = ({ return node.data case ElementType.Tag: if (node.name === 'span') { - if (node.attribs.class?.includes('invisible')) return '' - if (node.attribs.class?.includes('ellipsis')) + if (node.attribs.class?.includes('invisible') && !showFullLink) return '' + if (node.attribs.class?.includes('ellipsis') && !showFullLink) return node.children.map(child => unwrapNode(child)).join('') + '...' } return node.children.map(child => unwrapNode(child)).join('') @@ -87,15 +87,26 @@ const ParseHTML: React.FC = ({ return '' } } - const startingOfText = useRef(false) + const openingMentions = useRef(true) const renderNode = (node: ChildNode, index: number) => { switch (node.type) { case ElementType.Text: - node.data.trim().length && (startingOfText.current = true) // Removing empty spaces appeared between tags and mentions + let content: string = node.data + if (openingMentions.current) { + if (node.data.trim().length) { + openingMentions.current = false // Removing empty spaces appeared between tags and mentions + content = excludeMentions?.current.length + ? node.data.replace(new RegExp(/^\s+/), '') + : node.data + } else { + content = node.data.trim() + } + } + return ( = ({ const href = node.attribs.href if (classes) { if (classes.includes('hashtag')) { + openingMentions.current = false const tag = href.match(new RegExp(/\/tags?\/(.*)/, 'i'))?.[1].toLowerCase() const paramsHashtag = (params as { hashtag: Mastodon.Tag['name'] } | undefined) ?.hashtag @@ -142,7 +154,6 @@ const ParseHTML: React.FC = ({ ) if ( matchedMention && - !startingOfText.current && excludeMentions?.current.find(eM => eM.id === matchedMention.id) ) { return null @@ -165,6 +176,7 @@ const ParseHTML: React.FC = ({ } } + openingMentions.current = false const content = node.children.map(child => unwrapNode(child)).join('') const shouldBeTag = status?.tags?.find(tag => `#${tag.name}` === content) return ( @@ -182,7 +194,7 @@ const ParseHTML: React.FC = ({ } } }} - children={content !== href ? content : showFullLink ? href : content} + children={content} /> ) break diff --git a/src/components/Timeline/Shared/HeaderShared/Replies.tsx b/src/components/Timeline/Shared/HeaderShared/Replies.tsx index ff48e5f2..7dab01bd 100644 --- a/src/components/Timeline/Shared/HeaderShared/Replies.tsx +++ b/src/components/Timeline/Shared/HeaderShared/Replies.tsx @@ -3,7 +3,7 @@ import { useNavigation } from '@react-navigation/native' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' import React, { Fragment, useContext } from 'react' -import { useTranslation } from 'react-i18next' +import { Trans, useTranslation } from 'react-i18next' import StatusContext from '../Context' const HeaderSharedReplies: React.FC = () => { @@ -11,7 +11,7 @@ const HeaderSharedReplies: React.FC = () => { if (!isConversation) return null const navigation = useNavigation() - const { t } = useTranslation('componentTimeline') + const { t } = useTranslation(['common', 'componentTimeline']) const { colors } = useTheme() const mentionsBeginning = rawContent?.current?.[0] @@ -26,25 +26,27 @@ const HeaderSharedReplies: React.FC = () => { return excludeMentions?.current.length ? ( - <> - {t('shared.header.shared.replies')} - {excludeMentions.current.map((mention, index) => ( - - {' '} - navigation.push('Tab-Shared-Account', { account: mention })} - /> - - ))} - + + {excludeMentions.current.map((mention, index) => ( + + {index > 0 ? t('common:separator') : null} + navigation.push('Tab-Shared-Account', { account: mention })} + /> + + ))} + + ]} + /> ) : null } diff --git a/src/i18n/en/components/timeline.json b/src/i18n/en/components/timeline.json index 362cbe3e..77492cad 100644 --- a/src/i18n/en/components/timeline.json +++ b/src/i18n/en/components/timeline.json @@ -122,7 +122,7 @@ "muted": { "accessibilityLabel": "Toot muted" }, - "replies": "Replies", + "replies": "Replies <0 />", "visibility": { "direct": { "accessibilityLabel": "Toot is a direct message" diff --git a/src/screens/Tabs/Public/Root.tsx b/src/screens/Tabs/Public/Root.tsx index ac7c11e0..613e818b 100644 --- a/src/screens/Tabs/Public/Root.tsx +++ b/src/screens/Tabs/Public/Root.tsx @@ -83,7 +83,10 @@ const Root: React.FC null} - onIndexChange={index => setSegment(index)} + onIndexChange={index => { + setSegment(index) + setGlobalStorage('app.prev_public_segment', segments[index]) + }} navigationState={{ index: segment, routes }} initialLayout={{ width: Dimensions.get('window').width }} /> diff --git a/src/screens/Tabs/Shared/Account/Information/Fields.tsx b/src/screens/Tabs/Shared/Account/Information/Fields.tsx index f5c083df..824739a5 100644 --- a/src/screens/Tabs/Shared/Account/Information/Fields.tsx +++ b/src/screens/Tabs/Shared/Account/Information/Fields.tsx @@ -1,4 +1,3 @@ -import Icon from '@components/Icon' import { ParseHTML } from '@components/Parse' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' @@ -18,10 +17,39 @@ const AccountInformationFields: React.FC = ({ account, myInfo }) => { const { colors } = useTheme() return ( - + {account.fields.map((field, index) => ( - - + + = ({ account, myInfo }) => { numberOfLines={5} selectable /> - {field.verified_at ? ( - - ) : null} - + = ({ account, myInfo }) => { ) } -const styles = StyleSheet.create({ - fields: { - borderTopWidth: StyleSheet.hairlineWidth, - marginBottom: StyleConstants.Spacing.M - }, - field: { - flex: 1, - flexDirection: 'row', - borderBottomWidth: StyleSheet.hairlineWidth, - paddingTop: StyleConstants.Spacing.S, - paddingBottom: StyleConstants.Spacing.S - }, - fieldLeft: { - flex: 1, - flexDirection: 'row', - alignItems: 'center', - borderRightWidth: 1, - paddingLeft: StyleConstants.Spacing.S, - paddingRight: StyleConstants.Spacing.S - }, - fieldCheck: { marginLeft: StyleConstants.Spacing.XS }, - fieldRight: { - flex: 2, - justifyContent: 'center', - paddingLeft: StyleConstants.Spacing.S, - paddingRight: StyleConstants.Spacing.S - } -}) - export default AccountInformationFields diff --git a/src/screens/Tabs/Shared/Toot.tsx b/src/screens/Tabs/Shared/Toot.tsx index 8b0149cf..5d11abe6 100644 --- a/src/screens/Tabs/Shared/Toot.tsx +++ b/src/screens/Tabs/Shared/Toot.tsx @@ -65,6 +65,8 @@ const TabSharedToot: React.FC> = ({ }) const heights = useRef<(number | undefined)[]>([]) + const MAX_LEVEL = 10 + const ARC = StyleConstants.Avatar.XS / 4 return ( > = ({ windowSize={7} data={data?.body} renderItem={({ item, index }) => { - const MAX_LEVEL = 10 - const ARC = StyleConstants.Avatar.XS / 4 - const prev = data?.body[index - 1]?._level || 0 const curr = item._level const next = data?.body[index + 1]?._level || 0 @@ -85,7 +84,7 @@ const TabSharedToot: React.FC> = ({ style={{ paddingLeft: index > (data?.highlightIndex || 0) - ? Math.min(item._level, MAX_LEVEL) * StyleConstants.Spacing.S + ? Math.min(item._level - 1, MAX_LEVEL) * StyleConstants.Spacing.S : undefined }} onLayout={({ @@ -206,11 +205,12 @@ const TabSharedToot: React.FC> = ({ <> {leadingItem._level > 1 From eb385b8872a66ff88f227321cb92231f984725c1 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Sat, 31 Dec 2022 14:00:52 +0100 Subject: [PATCH 2/4] Fix bugs --- src/screens/ImageViewer/index.tsx | 15 ++++-- src/screens/Tabs/Shared/Toot.tsx | 82 +++++++++++++++++++++++++++---- src/utils/queryHooks/timeline.ts | 4 +- 3 files changed, 85 insertions(+), 16 deletions(-) diff --git a/src/screens/ImageViewer/index.tsx b/src/screens/ImageViewer/index.tsx index 140df005..28d3e9f6 100644 --- a/src/screens/ImageViewer/index.tsx +++ b/src/screens/ImageViewer/index.tsx @@ -4,7 +4,7 @@ import { useActionSheet } from '@expo/react-native-action-sheet' import { androidActionSheetStyles } from '@utils/helpers/androidActionSheetStyles' import { RootStackScreenProps } from '@utils/navigation/navigators' import { useTheme } from '@utils/styles/ThemeManager' -import React, { useState } from 'react' +import React, { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import { Dimensions, @@ -50,6 +50,13 @@ const ScreenImagesViewer = ({ const isZoomed = useSharedValue(false) + const onViewableItemsChanged = useCallback( + ({ viewableItems }: { viewableItems: ViewToken[] }) => { + setCurrentIndex(viewableItems[0]?.index || 0) + }, + [] + ) + return ( { + onActivated={() => { showActionSheetWithOptions( { options: [ @@ -207,9 +214,7 @@ const ScreenImagesViewer = ({ /> ) }} - onViewableItemsChanged={({ viewableItems }: { viewableItems: ViewToken[] }) => { - setCurrentIndex(viewableItems[0]?.index || 0) - }} + onViewableItemsChanged={onViewableItemsChanged} viewabilityConfig={{ itemVisiblePercentThreshold: 50 }} diff --git a/src/screens/Tabs/Shared/Toot.tsx b/src/screens/Tabs/Shared/Toot.tsx index 5d11abe6..c01e97a9 100644 --- a/src/screens/Tabs/Shared/Toot.tsx +++ b/src/screens/Tabs/Shared/Toot.tsx @@ -1,4 +1,6 @@ +import Button from '@components/Button' import { HeaderLeft } from '@components/Header' +import Icon from '@components/Icon' import ComponentSeparator from '@components/Separator' import CustomText from '@components/Text' import TimelineDefault from '@components/Timeline/Default' @@ -9,6 +11,7 @@ import { useTheme } from '@utils/styles/ThemeManager' import React, { useEffect, useRef } from 'react' import { useTranslation } from 'react-i18next' import { FlatList, View } from 'react-native' +import { Circle } from 'react-native-animated-spinkit' import { Path, Svg } from 'react-native-svg' const TabSharedToot: React.FC> = ({ @@ -18,11 +21,11 @@ const TabSharedToot: React.FC> = ({ } }) => { const { colors } = useTheme() - const { t } = useTranslation('screenTabs') + const { t } = useTranslation(['componentTimeline', 'screenTabs']) useEffect(() => { navigation.setOptions({ - title: t('shared.toot.name'), + title: t('screenTabs:shared.toot.name'), headerLeft: () => navigation.goBack()} /> }) }, []) @@ -31,19 +34,19 @@ const TabSharedToot: React.FC> = ({ const scrolled = useRef(false) const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Toot', toot: toot.id }] - const { data } = useTootQuery({ + const { data, status, refetch } = useTootQuery({ ...queryKey[1], options: { meta: { toot }, onSuccess: data => { - if (data.body.length < 1) { + if (data.pages[0].body.length < 1) { navigation.goBack() return } if (!scrolled.current) { scrolled.current = true - const pointer = data.body.findIndex(({ id }) => id === toot.id) + const pointer = data.pages[0].body.findIndex(({ id }) => id === toot.id) if (pointer < 1) return const length = flRef.current?.props.data?.length if (!length) return @@ -64,6 +67,54 @@ const TabSharedToot: React.FC> = ({ } }) + const empty = () => { + switch (status) { + case 'loading': + return + case 'error': + return ( + <> + + + {t('componentTimeline:empty.error.message')} + +