From a221beb6f2bbdeaf4c8c112cd87f0fbd6c3c46c0 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Sun, 29 May 2022 17:37:15 +0200 Subject: [PATCH 01/25] New translations tabs.json (German) --- src/i18n/de/screens/tabs.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/i18n/de/screens/tabs.json b/src/i18n/de/screens/tabs.json index a11c78e7..185cd5fd 100644 --- a/src/i18n/de/screens/tabs.json +++ b/src/i18n/de/screens/tabs.json @@ -169,6 +169,9 @@ "follow": { "heading": "Neue Follower" }, + "follow_request": { + "heading": "" + }, "favourite": { "heading": "Favoriten" }, @@ -181,6 +184,9 @@ "poll": { "heading": "Umfrageupdate" }, + "status": { + "heading": "" + }, "howitworks": "Erfahre, wie das Routing funktioniert" }, "root": { From 29db4d0d46635554c47e356eb958a1be215f6faa Mon Sep 17 00:00:00 2001 From: xmflsct Date: Sun, 29 May 2022 17:37:16 +0200 Subject: [PATCH 02/25] New translations tabs.json (Korean) --- src/i18n/ko/screens/tabs.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/i18n/ko/screens/tabs.json b/src/i18n/ko/screens/tabs.json index e423baaa..fdb34a76 100644 --- a/src/i18n/ko/screens/tabs.json +++ b/src/i18n/ko/screens/tabs.json @@ -169,6 +169,9 @@ "follow": { "heading": "새 팔로워" }, + "follow_request": { + "heading": "" + }, "favourite": { "heading": "즐겨찾기됨" }, @@ -181,6 +184,9 @@ "poll": { "heading": "투표 업데이트" }, + "status": { + "heading": "" + }, "howitworks": "라우팅 방법 알아보기" }, "root": { From cec0ac4dff5e543f65025452d8d6021efd15dc11 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Sun, 29 May 2022 17:37:17 +0200 Subject: [PATCH 03/25] New translations tabs.json (Chinese Simplified) --- src/i18n/zh-Hans/screens/tabs.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/i18n/zh-Hans/screens/tabs.json b/src/i18n/zh-Hans/screens/tabs.json index dbb3dfeb..f80978c2 100644 --- a/src/i18n/zh-Hans/screens/tabs.json +++ b/src/i18n/zh-Hans/screens/tabs.json @@ -169,6 +169,9 @@ "follow": { "heading": "新关注者" }, + "follow_request": { + "heading": "" + }, "favourite": { "heading": "嘟文被喜欢" }, @@ -181,6 +184,9 @@ "poll": { "heading": "投票更新" }, + "status": { + "heading": "" + }, "howitworks": "了解通知消息转发如何工作" }, "root": { From 792a33a4973cfff6d2a9c8d6fcc14794611084ef Mon Sep 17 00:00:00 2001 From: xmflsct Date: Sun, 29 May 2022 17:37:18 +0200 Subject: [PATCH 04/25] New translations tabs.json (Vietnamese) --- src/i18n/vi/screens/tabs.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/i18n/vi/screens/tabs.json b/src/i18n/vi/screens/tabs.json index b5e3a060..c510e620 100644 --- a/src/i18n/vi/screens/tabs.json +++ b/src/i18n/vi/screens/tabs.json @@ -169,6 +169,9 @@ "follow": { "heading": "Người theo dõi mới" }, + "follow_request": { + "heading": "" + }, "favourite": { "heading": "Lượt thích" }, @@ -181,6 +184,9 @@ "poll": { "heading": "Kết quả bình chọn" }, + "status": { + "heading": "" + }, "howitworks": "Tìm hiểu cách truyền" }, "root": { From 2416a90bb554493b235f38c9e1018d2978b0dd7f Mon Sep 17 00:00:00 2001 From: xmflsct Date: Sun, 29 May 2022 17:37:18 +0200 Subject: [PATCH 05/25] New translations tabs.json (Chinese Traditional) --- src/i18n/zh-Hant/screens/tabs.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/i18n/zh-Hant/screens/tabs.json b/src/i18n/zh-Hant/screens/tabs.json index 11c0d54c..bf70a873 100644 --- a/src/i18n/zh-Hant/screens/tabs.json +++ b/src/i18n/zh-Hant/screens/tabs.json @@ -169,6 +169,9 @@ "follow": { "heading": "" }, + "follow_request": { + "heading": "" + }, "favourite": { "heading": "" }, @@ -181,6 +184,9 @@ "poll": { "heading": "" }, + "status": { + "heading": "" + }, "howitworks": "" }, "root": { From acf845acc8b5cf55df8aa78e58d2a7bc9dfb4908 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Sun, 29 May 2022 17:37:19 +0200 Subject: [PATCH 06/25] New translations tabs.json (Italian) --- src/i18n/it/screens/tabs.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/i18n/it/screens/tabs.json b/src/i18n/it/screens/tabs.json index 18156158..f706112e 100644 --- a/src/i18n/it/screens/tabs.json +++ b/src/i18n/it/screens/tabs.json @@ -169,6 +169,9 @@ "follow": { "heading": "Nuovi seguaci" }, + "follow_request": { + "heading": "" + }, "favourite": { "heading": "Apprezzamenti" }, @@ -181,6 +184,9 @@ "poll": { "heading": "Novità sui sondaggi" }, + "status": { + "heading": "" + }, "howitworks": "Scopri come funziona il traversamento dei messaggi" }, "root": { From 98f5830ab6fa486fdc647852c7b15caa46145dc5 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Sun, 29 May 2022 17:37:20 +0200 Subject: [PATCH 07/25] New translations tabs.json (Portuguese, Brazilian) --- src/i18n/pt_BR/screens/tabs.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/i18n/pt_BR/screens/tabs.json b/src/i18n/pt_BR/screens/tabs.json index 20fa8897..0d52e55b 100644 --- a/src/i18n/pt_BR/screens/tabs.json +++ b/src/i18n/pt_BR/screens/tabs.json @@ -169,6 +169,9 @@ "follow": { "heading": "Novo seguidor" }, + "follow_request": { + "heading": "" + }, "favourite": { "heading": "Favoritos" }, @@ -181,6 +184,9 @@ "poll": { "heading": "Pesquisa atualizada" }, + "status": { + "heading": "" + }, "howitworks": "Saiba como funciona o roteamento" }, "root": { From 7678857e5dc9cea3e6ba8847265ee17de43f9700 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Wed, 1 Jun 2022 00:48:05 +0200 Subject: [PATCH 08/25] New translations compose.json (German) --- src/i18n/de/screens/compose.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/i18n/de/screens/compose.json b/src/i18n/de/screens/compose.json index caa8fc28..0da491bb 100644 --- a/src/i18n/de/screens/compose.json +++ b/src/i18n/de/screens/compose.json @@ -168,6 +168,7 @@ "header": { "title": "Entwurf" }, + "warning": "", "content": { "accessibilityHint": "Gespeicherter Entwurf, tippe, um diesen zu bearbeiten", "textEmpty": "Kein Inhalt" From 213e343aa9c6a76e600267b61d842c39698d86d1 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Wed, 1 Jun 2022 00:48:07 +0200 Subject: [PATCH 09/25] New translations compose.json (Korean) --- src/i18n/ko/screens/compose.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/i18n/ko/screens/compose.json b/src/i18n/ko/screens/compose.json index d9f0bc1c..1fd3de75 100644 --- a/src/i18n/ko/screens/compose.json +++ b/src/i18n/ko/screens/compose.json @@ -168,6 +168,7 @@ "header": { "title": "초안" }, + "warning": "", "content": { "accessibilityHint": "저장된 초안, 수정하려면 탭하세요", "textEmpty": "콘텐츠 빔" From 2c2fc6efee7d175d55ab68492b6203043e5303b9 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Wed, 1 Jun 2022 00:48:07 +0200 Subject: [PATCH 10/25] New translations compose.json (Chinese Simplified) --- src/i18n/zh-Hans/screens/compose.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/i18n/zh-Hans/screens/compose.json b/src/i18n/zh-Hans/screens/compose.json index 33c505a8..a9ae17b8 100644 --- a/src/i18n/zh-Hans/screens/compose.json +++ b/src/i18n/zh-Hans/screens/compose.json @@ -168,6 +168,7 @@ "header": { "title": "草稿" }, + "warning": "", "content": { "accessibilityHint": "已保存的草稿,点击编辑此草稿", "textEmpty": "无正文内容" From b6efe3eba73a8e0fa6f31b143ded596215e2099f Mon Sep 17 00:00:00 2001 From: xmflsct Date: Wed, 1 Jun 2022 00:48:08 +0200 Subject: [PATCH 11/25] New translations compose.json (Vietnamese) --- src/i18n/vi/screens/compose.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/i18n/vi/screens/compose.json b/src/i18n/vi/screens/compose.json index 67d48171..807121ed 100644 --- a/src/i18n/vi/screens/compose.json +++ b/src/i18n/vi/screens/compose.json @@ -168,6 +168,7 @@ "header": { "title": "Nháp" }, + "warning": "", "content": { "accessibilityHint": "Đã lưu nháp, nhấn để tiếp tục viết", "textEmpty": "Chưa có nội dung" From f85606a4d5a7d30450769e10fceb09463888b35d Mon Sep 17 00:00:00 2001 From: xmflsct Date: Wed, 1 Jun 2022 00:48:09 +0200 Subject: [PATCH 12/25] New translations compose.json (Chinese Traditional) --- src/i18n/zh-Hant/screens/compose.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/i18n/zh-Hant/screens/compose.json b/src/i18n/zh-Hant/screens/compose.json index dc1419b3..ceb1afd4 100644 --- a/src/i18n/zh-Hant/screens/compose.json +++ b/src/i18n/zh-Hant/screens/compose.json @@ -168,6 +168,7 @@ "header": { "title": "" }, + "warning": "", "content": { "accessibilityHint": "", "textEmpty": "" From 56469d41edb815e764a22bbf43523e6de50b7ba8 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Wed, 1 Jun 2022 00:48:11 +0200 Subject: [PATCH 13/25] New translations compose.json (Italian) --- src/i18n/it/screens/compose.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/i18n/it/screens/compose.json b/src/i18n/it/screens/compose.json index 4abf23cd..190db708 100644 --- a/src/i18n/it/screens/compose.json +++ b/src/i18n/it/screens/compose.json @@ -168,6 +168,7 @@ "header": { "title": "Bozza" }, + "warning": "", "content": { "accessibilityHint": "Bozza salvata, premi per modificarla", "textEmpty": "Testo vuoto" From 4efd87861d94b8422421f0e0bb4dc751b7f25952 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Wed, 1 Jun 2022 00:48:12 +0200 Subject: [PATCH 14/25] New translations compose.json (Portuguese, Brazilian) --- src/i18n/pt_BR/screens/compose.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/i18n/pt_BR/screens/compose.json b/src/i18n/pt_BR/screens/compose.json index f59596b9..f226aa0f 100644 --- a/src/i18n/pt_BR/screens/compose.json +++ b/src/i18n/pt_BR/screens/compose.json @@ -168,6 +168,7 @@ "header": { "title": "Rascunho" }, + "warning": "", "content": { "accessibilityHint": "Toque para editar este rascunho", "textEmpty": "O conteúdo está vazio" From f81bd58d61e22db57cc2d84a4d2a5522c86b2395 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Wed, 1 Jun 2022 12:21:27 +0200 Subject: [PATCH 15/25] New translations timeline.json (Vietnamese) --- src/i18n/vi/components/timeline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/vi/components/timeline.json b/src/i18n/vi/components/timeline.json index 997818c2..92224828 100644 --- a/src/i18n/vi/components/timeline.json +++ b/src/i18n/vi/components/timeline.json @@ -30,7 +30,7 @@ "default": "{{name}} đăng lại", "notification": "{{name}} đăng lại tút của bạn" }, - "update": "" + "update": "Đăng lại đã được sửa" }, "actions": { "reply": { From 62d014d2a81d151a079f5fe9b619764bfa3bc13d Mon Sep 17 00:00:00 2001 From: xmflsct Date: Wed, 1 Jun 2022 12:21:29 +0200 Subject: [PATCH 16/25] New translations tabs.json (Vietnamese) --- src/i18n/vi/screens/tabs.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i18n/vi/screens/tabs.json b/src/i18n/vi/screens/tabs.json index c510e620..166c2188 100644 --- a/src/i18n/vi/screens/tabs.json +++ b/src/i18n/vi/screens/tabs.json @@ -170,7 +170,7 @@ "heading": "Người theo dõi mới" }, "follow_request": { - "heading": "" + "heading": "Yêu cầu theo dõi" }, "favourite": { "heading": "Lượt thích" @@ -185,7 +185,7 @@ "heading": "Kết quả bình chọn" }, "status": { - "heading": "" + "heading": "Tút từ người đã theo dõi" }, "howitworks": "Tìm hiểu cách truyền" }, From 102bc31adddd76b62cdc21684365ea89ba996c72 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Wed, 1 Jun 2022 12:21:30 +0200 Subject: [PATCH 17/25] New translations compose.json (Vietnamese) --- src/i18n/vi/screens/compose.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/vi/screens/compose.json b/src/i18n/vi/screens/compose.json index 807121ed..36f7ac4a 100644 --- a/src/i18n/vi/screens/compose.json +++ b/src/i18n/vi/screens/compose.json @@ -168,7 +168,7 @@ "header": { "title": "Nháp" }, - "warning": "", + "warning": "Tút nháp chỉ được lưu trữ trên điện thoại và có thể bị mất nếu có sự cố. Hãy cẩn thận.", "content": { "accessibilityHint": "Đã lưu nháp, nhấn để tiếp tục viết", "textEmpty": "Chưa có nội dung" From 8b01ab0fd9a4878261931a6a14bb3ee23fea8dab Mon Sep 17 00:00:00 2001 From: xmflsct Date: Wed, 1 Jun 2022 12:21:31 +0200 Subject: [PATCH 18/25] New translations actions.json (Vietnamese) --- src/i18n/vi/screens/actions.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i18n/vi/screens/actions.json b/src/i18n/vi/screens/actions.json index 53097e46..06cd1e50 100644 --- a/src/i18n/vi/screens/actions.json +++ b/src/i18n/vi/screens/actions.json @@ -13,8 +13,8 @@ "reblog": "$t(screenTabs:me.push.reblog.heading)", "mention": "$t(screenTabs:me.push.mention.heading)", "poll": "$t(screenTabs:me.push.poll.heading)", - "status": "", - "update": "" + "status": "Tút từ người đã theo dõi", + "update": "Đăng lại đã được sửa" } } } From 5ba32902547410e964314f4ba3087ee0e545ef28 Mon Sep 17 00:00:00 2001 From: Zhiyuan Zheng Date: Wed, 1 Jun 2022 23:13:43 +0200 Subject: [PATCH 19/25] Fixed #299 --- src/components/Timeline.tsx | 120 ++++++----- src/components/Timeline/Refresh.tsx | 323 ++++++++++++++++++++++++++++ 2 files changed, 389 insertions(+), 54 deletions(-) create mode 100644 src/components/Timeline/Refresh.tsx diff --git a/src/components/Timeline.tsx b/src/components/Timeline.tsx index ec8d6b33..b18aec52 100644 --- a/src/components/Timeline.tsx +++ b/src/components/Timeline.tsx @@ -1,10 +1,6 @@ import ComponentSeparator from '@components/Separator' import { useScrollToTop } from '@react-navigation/native' -import { - QueryKeyTimeline, - TimelineData, - useTimelineQuery -} from '@utils/queryHooks/timeline' +import { QueryKeyTimeline, useTimelineQuery } from '@utils/queryHooks/timeline' import { getInstanceActive } from '@utils/slices/instancesSlice' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' @@ -16,10 +12,20 @@ import { RefreshControl, StyleSheet } from 'react-native' -import { InfiniteData, useQueryClient } from 'react-query' +import Animated, { + useAnimatedScrollHandler, + useSharedValue +} from 'react-native-reanimated' +import { useQueryClient } from 'react-query' import { useSelector } from 'react-redux' import TimelineEmpty from './Timeline/Empty' import TimelineFooter from './Timeline/Footer' +import TimelineRefresh, { + SEPARATION_Y_1, + SEPARATION_Y_2 +} from './Timeline/Refresh' + +const AnimatedFlatList = Animated.createAnimatedComponent(FlatList) export interface Props { flRef?: RefObject> @@ -40,15 +46,12 @@ const Timeline: React.FC = ({ }) => { const { colors } = useTheme() - const queryClient = useQueryClient() const { data, refetch, isFetching, isLoading, - fetchPreviousPage, fetchNextPage, - isFetchingPreviousPage, isFetchingNextPage } = useTimelineQuery({ ...queryKey[1], @@ -57,12 +60,6 @@ const Timeline: React.FC = ({ ios: ['dataUpdatedAt', 'isFetching'], android: ['dataUpdatedAt', 'isFetching', 'isLoading'] }), - getPreviousPageParam: firstPage => - firstPage?.links?.prev && { - min_id: firstPage.links.prev, - // https://github.com/facebook/react-native/issues/25239 - limit: '10' - }, getNextPageParam: lastPage => lastPage?.links?.next && { max_id: lastPage.links.next @@ -92,6 +89,27 @@ const Timeline: React.FC = ({ const flRef = useRef(null) + const scrollY = useSharedValue(0) + const fetchingType = useSharedValue<0 | 1 | 2>(0) + + const onScroll = useAnimatedScrollHandler( + { + onScroll: ({ contentOffset: { y } }) => { + scrollY.value = y + }, + onEndDrag: ({ contentOffset: { y } }) => { + if (!disableRefresh && !isFetching) { + if (y <= SEPARATION_Y_2) { + fetchingType.value = 2 + } else if (y <= SEPARATION_Y_1) { + fetchingType.value = 1 + } + } + } + }, + [isFetching] + ) + const androidRefreshControl = Platform.select({ android: { refreshControl: ( @@ -115,46 +133,40 @@ const Timeline: React.FC = ({ }) return ( - - } - ListEmptyComponent={} - ItemSeparatorComponent={ItemSeparatorComponent} - {...(isFetchingPreviousPage && { - maintainVisibleContentPosition: { minIndexForVisible: 0 } - })} - refreshing={isFetchingPreviousPage} - onRefresh={() => { - if (!disableRefresh && !isFetchingPreviousPage) { - queryClient.setQueryData | undefined>( - queryKey, - data => { - if (data?.pages[0] && data.pages[0].body.length === 0) { - return { - pages: data.pages.slice(1), - pageParams: data.pageParams.slice(1) - } - } else { - return data - } - } - ) - fetchPreviousPage() + <> + + } - }} - {...androidRefreshControl} - {...customProps} - /> + ListEmptyComponent={} + ItemSeparatorComponent={ItemSeparatorComponent} + maintainVisibleContentPosition={{ + minIndexForVisible: 0 + }} + {...androidRefreshControl} + {...customProps} + /> + ) } diff --git a/src/components/Timeline/Refresh.tsx b/src/components/Timeline/Refresh.tsx new file mode 100644 index 00000000..f5d5ad2a --- /dev/null +++ b/src/components/Timeline/Refresh.tsx @@ -0,0 +1,323 @@ +import haptics from '@components/haptics' +import Icon from '@components/Icon' +import { + QueryKeyTimeline, + TimelineData, + useTimelineQuery +} from '@utils/queryHooks/timeline' +import { StyleConstants } from '@utils/styles/constants' +import { useTheme } from '@utils/styles/ThemeManager' +import React, { RefObject, useCallback, useRef, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { FlatList, Platform, StyleSheet, Text, View } from 'react-native' +import { Circle } from 'react-native-animated-spinkit' +import Animated, { + Extrapolate, + interpolate, + runOnJS, + useAnimatedReaction, + useAnimatedStyle, + useSharedValue, + withTiming +} from 'react-native-reanimated' +import { InfiniteData, useQueryClient } from 'react-query' + +export interface Props { + flRef: RefObject> + queryKey: QueryKeyTimeline + scrollY: Animated.SharedValue + fetchingType: Animated.SharedValue<0 | 1 | 2> + disableRefresh?: boolean +} + +const CONTAINER_HEIGHT = StyleConstants.Spacing.M * 2.5 +export const SEPARATION_Y_1 = -( + CONTAINER_HEIGHT / 2 + + StyleConstants.Font.Size.S / 2 +) +export const SEPARATION_Y_2 = -( + CONTAINER_HEIGHT * 1.5 + + StyleConstants.Font.Size.S / 2 +) + +const TimelineRefresh: React.FC = ({ + flRef, + queryKey, + scrollY, + fetchingType, + disableRefresh = false +}) => { + if (Platform.OS !== 'ios') { + return null + } + if (disableRefresh) { + return null + } + + const fetchingLatestIndex = useRef(0) + const refetchActive = useRef(false) + + const { + refetch, + isFetching, + isLoading, + fetchPreviousPage, + hasPreviousPage, + isFetchingNextPage + } = useTimelineQuery({ + ...queryKey[1], + options: { + getPreviousPageParam: firstPage => + firstPage?.links?.prev && { + min_id: firstPage.links.prev, + // https://github.com/facebook/react-native/issues/25239#issuecomment-731100372 + limit: '3' + }, + select: data => { + if (refetchActive.current) { + data.pageParams = [data.pageParams[0]] + data.pages = [data.pages[0]] + refetchActive.current = false + } + return data + }, + onSuccess: () => { + if (fetchingLatestIndex.current > 0) { + if (fetchingLatestIndex.current > 5) { + clearFirstPage() + fetchingLatestIndex.current = 0 + } else { + if (hasPreviousPage) { + fetchPreviousPage() + fetchingLatestIndex.current++ + } else { + clearFirstPage() + fetchingLatestIndex.current = 0 + } + } + } + } + } + }) + + const { t } = useTranslation('componentTimeline') + const { colors } = useTheme() + + const queryClient = useQueryClient() + const clearFirstPage = () => { + queryClient.setQueryData | undefined>( + queryKey, + data => { + if (data?.pages[0] && data.pages[0].body.length === 0) { + return { + pages: data.pages.slice(1), + pageParams: data.pageParams.slice(1) + } + } else { + return data + } + } + ) + } + const prepareRefetch = () => { + refetchActive.current = true + queryClient.setQueryData | undefined>( + queryKey, + data => { + if (data) { + data.pageParams = [undefined] + const newFirstPage: TimelineData = { body: [] } + for (let page of data.pages) { + // @ts-ignore + newFirstPage.body.push(...page.body) + if (newFirstPage.body.length > 10) break + } + data.pages = [newFirstPage] + } + + return data + } + ) + } + const callRefetch = async () => { + await refetch() + setTimeout(() => flRef.current?.scrollToOffset({ offset: 1 }), 50) + } + + const [textRight, setTextRight] = useState(0) + const arrowY = useAnimatedStyle(() => ({ + transform: [ + { + translateY: interpolate( + scrollY.value, + [0, SEPARATION_Y_1], + [ + -CONTAINER_HEIGHT / 2 - StyleConstants.Font.Size.M / 2, + CONTAINER_HEIGHT / 2 - StyleConstants.Font.Size.S / 2 + ], + Extrapolate.CLAMP + ) + } + ] + })) + const arrowTop = useAnimatedStyle(() => ({ + marginTop: + scrollY.value < SEPARATION_Y_2 + ? withTiming(CONTAINER_HEIGHT) + : withTiming(0) + })) + + const arrowStage = useSharedValue(0) + const onLayout = useCallback( + ({ nativeEvent }) => { + if (nativeEvent.layout.x + nativeEvent.layout.width > textRight) { + setTextRight(nativeEvent.layout.x + nativeEvent.layout.width) + } + }, + [textRight] + ) + useAnimatedReaction( + () => { + if (isFetching) { + return false + } + switch (arrowStage.value) { + case 0: + if (scrollY.value < SEPARATION_Y_1) { + arrowStage.value = 1 + return true + } + return false + case 1: + if (scrollY.value < SEPARATION_Y_2) { + arrowStage.value = 2 + return true + } + if (scrollY.value > SEPARATION_Y_1) { + arrowStage.value = 0 + return false + } + return false + case 2: + if (scrollY.value > SEPARATION_Y_2) { + arrowStage.value = 1 + return false + } + return false + } + }, + data => { + if (data) { + runOnJS(haptics)('Light') + } + }, + [isFetching] + ) + const wrapperStartLatest = () => { + fetchingLatestIndex.current = 1 + } + + useAnimatedReaction( + () => { + return fetchingType.value + }, + data => { + fetchingType.value = 0 + switch (data) { + case 1: + runOnJS(wrapperStartLatest)() + runOnJS(clearFirstPage)() + runOnJS(fetchPreviousPage)() + break + case 2: + runOnJS(prepareRefetch)() + runOnJS(callRefetch)() + break + } + }, + [] + ) + + const headerPadding = useAnimatedStyle( + () => ({ + paddingTop: + fetchingLatestIndex.current !== 0 || + (isFetching && !isLoading && !isFetchingNextPage) + ? withTiming(StyleConstants.Spacing.M * 2.5) + : withTiming(0) + }), + [fetchingLatestIndex.current, isFetching, isFetchingNextPage, isLoading] + ) + + return ( + + + {isFetching ? ( + + + + ) : ( + <> + + + + } + /> + + + + + + )} + + + ) +} + +const styles = StyleSheet.create({ + base: { + position: 'absolute', + top: 0, + left: 0, + right: 0, + height: CONTAINER_HEIGHT * 2, + alignItems: 'center' + }, + container1: { + flex: 1, + flexDirection: 'row', + height: CONTAINER_HEIGHT + }, + container2: { height: CONTAINER_HEIGHT, justifyContent: 'center' }, + explanation: { + fontSize: StyleConstants.Font.Size.S, + lineHeight: CONTAINER_HEIGHT + } +}) + +export default TimelineRefresh From 316096cf571de138c313affa9f34b37bb03a75cd Mon Sep 17 00:00:00 2001 From: Zhiyuan Zheng Date: Wed, 1 Jun 2022 23:39:48 +0200 Subject: [PATCH 20/25] Fixed #310 --- src/components/Timeline/Shared/Filtered.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Timeline/Shared/Filtered.tsx b/src/components/Timeline/Shared/Filtered.tsx index 661182fa..f6e10994 100644 --- a/src/components/Timeline/Shared/Filtered.tsx +++ b/src/components/Timeline/Shared/Filtered.tsx @@ -55,7 +55,7 @@ export const shouldFilter = ({ ) // $& means the whole matched string switch (filter.whole_word) { case true: - if (new RegExp('\\B' + escapedPhrase + '\\B').test(text)) { + if (new RegExp('\\b' + escapedPhrase + '\\b').test(text)) { shouldFilter = true } break @@ -100,6 +100,7 @@ export const shouldFilter = ({ }) } }) + status.spoiler_text && parser.write(status.spoiler_text) parser.write(status.content) parser.end() } From bc0ae827ad2d912c50a0c61df254785ab4ab8415 Mon Sep 17 00:00:00 2001 From: Zhiyuan Zheng Date: Wed, 1 Jun 2022 23:47:58 +0200 Subject: [PATCH 21/25] Fixed #311 --- src/screens/ImagesViewer.tsx | 202 ++++++++++++++++++----------------- 1 file changed, 106 insertions(+), 96 deletions(-) diff --git a/src/screens/ImagesViewer.tsx b/src/screens/ImagesViewer.tsx index 405a1aaa..23dfb816 100644 --- a/src/screens/ImagesViewer.tsx +++ b/src/screens/ImagesViewer.tsx @@ -19,94 +19,6 @@ import { import ImageViewer from './ImageViewer/Root' import saveImage from './ImageViewer/save' -const HeaderComponent = React.memo( - ({ - messageRef, - navigation, - currentIndex, - imageUrls - }: { - messageRef: RefObject - navigation: NativeStackNavigationProp< - RootStackParamList, - 'Screen-ImagesViewer' - > - currentIndex: number - imageUrls: RootStackParamList['Screen-ImagesViewer']['imageUrls'] - }) => { - const insets = useSafeAreaInsets() - const { mode, theme } = useTheme() - const { t } = useTranslation('screenImageViewer') - const { showActionSheetWithOptions } = useActionSheet() - - const onPress = useCallback(() => { - analytics('imageviewer_more_press') - showActionSheetWithOptions( - { - options: [ - t('content.options.save'), - t('content.options.share'), - t('content.options.cancel') - ], - cancelButtonIndex: 2, - userInterfaceStyle: mode - }, - async buttonIndex => { - switch (buttonIndex) { - case 0: - analytics('imageviewer_more_save_press') - saveImage({ messageRef, theme, image: imageUrls[currentIndex] }) - break - case 1: - analytics('imageviewer_more_share_press') - switch (Platform.OS) { - case 'ios': - await Share.share({ url: imageUrls[currentIndex].url }) - break - case 'android': - await Share.share({ message: imageUrls[currentIndex].url }) - break - } - break - } - } - ) - }, [currentIndex]) - - return ( - - navigation.goBack()} - /> - - - - ) - }, - (prev, next) => prev.currentIndex === next.currentIndex -) - const ScreenImagesViewer = ({ route: { params: { imageUrls, id } @@ -118,13 +30,51 @@ const ScreenImagesViewer = ({ return null } - const { theme } = useTheme() + const insets = useSafeAreaInsets() + + const { mode, theme } = useTheme() + const { t } = useTranslation('screenImageViewer') const initialIndex = imageUrls.findIndex(image => image.id === id) const [currentIndex, setCurrentIndex] = useState(initialIndex) const messageRef = useRef(null) + const { showActionSheetWithOptions } = useActionSheet() + const onPress = useCallback(() => { + analytics('imageviewer_more_press') + showActionSheetWithOptions( + { + options: [ + t('content.options.save'), + t('content.options.share'), + t('content.options.cancel') + ], + cancelButtonIndex: 2, + userInterfaceStyle: mode + }, + async buttonIndex => { + switch (buttonIndex) { + case 0: + analytics('imageviewer_more_save_press') + saveImage({ messageRef, theme, image: imageUrls[currentIndex] }) + break + case 1: + analytics('imageviewer_more_share_press') + switch (Platform.OS) { + case 'ios': + await Share.share({ url: imageUrls[currentIndex].url }) + break + case 'android': + await Share.share({ message: imageUrls[currentIndex].url }) + break + } + break + } + } + ) + }, [currentIndex]) + return (