From 0bcd0c1725d41681b0cf82d60fa69a2471277a59 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Tue, 3 Jan 2023 23:57:23 +0100 Subject: [PATCH] Continue refine remote logic #638 --- package.json | 4 +- src/App.tsx | 4 +- src/components/Emojis/List.tsx | 141 +++++++++--------- src/components/Instance/index.tsx | 7 +- src/components/Parse/Emojis.tsx | 31 ++-- src/components/Timeline/Shared/Card.tsx | 115 +++++--------- src/components/Timeline/Shared/Feedback.tsx | 4 +- src/components/Timeline/Shared/Filtered.tsx | 2 +- .../Timeline/Shared/HeaderConversation.tsx | 9 +- .../Timeline/Shared/HeaderDefault.tsx | 14 +- .../Timeline/Shared/HeaderNotification.tsx | 13 +- .../Shared/HeaderShared/Application.tsx | 17 +-- .../Timeline/Shared/HeaderShared/Created.tsx | 16 +- .../Timeline/Shared/HeaderShared/Muted.tsx | 12 +- .../Shared/HeaderShared/Visibility.tsx | 12 +- src/components/contextMenu/account.ts | 2 +- src/components/contextMenu/instance.ts | 6 +- src/components/mediaSelector.ts | 2 +- src/components/openLink.ts | 127 ++++++++-------- src/screens/Compose/index.tsx | 4 +- src/screens/Compose/utils/processText.tsx | 2 +- src/screens/Tabs/Me/Profile/Root.tsx | 2 +- src/screens/Tabs/Me/Settings/Dev.tsx | 13 ++ src/screens/Tabs/Shared/Account/index.tsx | 1 + src/screens/Tabs/Shared/History.tsx | 4 +- src/screens/Tabs/Shared/Report.tsx | 4 +- src/screens/Tabs/Shared/Toot.tsx | 9 +- src/utils/helpers/urlMatcher.ts | 115 +++++++------- src/utils/navigation/navigators.ts | 2 +- src/utils/push/constants.ts | 2 +- src/utils/push/useReceive.ts | 2 +- src/utils/push/useRespond.ts | 2 +- src/utils/queryHooks/account.ts | 95 +++++++----- src/utils/queryHooks/index.ts | 14 +- src/utils/queryHooks/profile.ts | 2 +- src/utils/queryHooks/search.ts | 36 +++-- src/utils/queryHooks/status.ts | 53 +++++-- src/utils/queryHooks/statusesHistory.ts | 43 ++++-- src/utils/queryHooks/timeline.ts | 6 +- src/utils/queryHooks/timeline/deleteItem.ts | 33 ++-- src/utils/queryHooks/timeline/editItem.ts | 35 ++--- .../timeline/updateStatusProperty.ts | 4 +- src/utils/queryHooks/users.ts | 22 ++- src/utils/startup/dev.ts | 12 ++ src/utils/storage/actions.ts | 2 +- yarn.lock | 22 +-- 46 files changed, 548 insertions(+), 531 deletions(-) create mode 100644 src/utils/startup/dev.ts diff --git a/package.json b/package.json index cbbae056..6435d64d 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ "react-native-tab-view": "^3.3.4", "react-redux": "^8.0.5", "rn-placeholder": "^3.0.3", - "valid-url": "^1.0.9", + "url-parse": "^1.5.10", "zeego": "^1.0.2" }, "devDependencies": { @@ -104,7 +104,7 @@ "@types/react-dom": "^18.0.10", "@types/react-native": "^0.70.8", "@types/react-native-share-menu": "^5.0.2", - "@types/valid-url": "^1.0.3", + "@types/url-parse": "^1", "babel-plugin-module-resolver": "^4.1.0", "babel-plugin-transform-remove-console": "^6.9.4", "chalk": "^4.1.2", diff --git a/src/App.tsx b/src/App.tsx index 1e872150..cf102047 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,8 +3,9 @@ import * as Sentry from '@sentry/react-native' import { QueryClientProvider } from '@tanstack/react-query' import AccessibilityManager from '@utils/accessibility/AccessibilityManager' import getLanguage from '@utils/helpers/getLanguage' -import queryClient from '@utils/queryHooks' +import { queryClient } from '@utils/queryHooks' import audio from '@utils/startup/audio' +import { dev } from '@utils/startup/dev' import log from '@utils/startup/log' import netInfo from '@utils/startup/netInfo' import push from '@utils/startup/push' @@ -34,6 +35,7 @@ Platform.select({ android: LogBox.ignoreLogs(['Setting a timer for a long period of time']) }) +dev() sentry() audio() push() diff --git a/src/components/Emojis/List.tsx b/src/components/Emojis/List.tsx index 6a443585..5cf7df55 100644 --- a/src/components/Emojis/List.tsx +++ b/src/components/Emojis/List.tsx @@ -19,7 +19,6 @@ import { View } from 'react-native' import FastImage from 'react-native-fast-image' -import validUrl from 'valid-url' import EmojisContext from './Context' const EmojisList = () => { @@ -68,83 +67,77 @@ const EmojisList = () => { > {item.map(emoji => { const uri = reduceMotionEnabled ? emoji.static_url : emoji.url - if (validUrl.isHttpsUri(uri)) { - return ( - { - addEmoji(`:${emoji.shortcode}:`) + return ( + { + addEmoji(`:${emoji.shortcode}:`) - const HALF_LIFE = 60 * 60 * 24 * 7 // 1 week - const calculateScore = ( - emoji: StorageAccount['emojis_frequent'][number] - ): number => { - var seconds = (new Date().getTime() - emoji.lastUsed) / 1000 - var score = emoji.count + 1 - var order = Math.log(Math.max(score, 1)) / Math.LN10 - var sign = score > 0 ? 1 : score === 0 ? 0 : -1 - return (sign * order + seconds / HALF_LIFE) * 10 + const HALF_LIFE = 60 * 60 * 24 * 7 // 1 week + const calculateScore = ( + emoji: StorageAccount['emojis_frequent'][number] + ): number => { + var seconds = (new Date().getTime() - emoji.lastUsed) / 1000 + var score = emoji.count + 1 + var order = Math.log(Math.max(score, 1)) / Math.LN10 + var sign = score > 0 ? 1 : score === 0 ? 0 : -1 + return (sign * order + seconds / HALF_LIFE) * 10 + } + + const currentEmojis = getAccountStorage.object('emojis_frequent') + const foundEmojiIndex = currentEmojis?.findIndex( + e => e.emoji.shortcode === emoji.shortcode && e.emoji.url === emoji.url + ) + + let newEmojisSort: StorageAccount['emojis_frequent'] + if (foundEmojiIndex === -1) { + newEmojisSort = currentEmojis || [] + const temp = { + emoji, + score: 0, + count: 0, + lastUsed: new Date().getTime() } + newEmojisSort.push({ + ...temp, + score: calculateScore(temp), + count: temp.count + 1 + }) + } else { + newEmojisSort = + currentEmojis + ?.map((e, i) => + i === foundEmojiIndex + ? { + ...e, + score: calculateScore(e), + count: e.count + 1, + lastUsed: new Date().getTime() + } + : e + ) + .sort((a, b) => b.score - a.score) || [] + } - const currentEmojis = getAccountStorage.object('emojis_frequent') - const foundEmojiIndex = currentEmojis?.findIndex( - e => e.emoji.shortcode === emoji.shortcode && e.emoji.url === emoji.url - ) - - let newEmojisSort: StorageAccount['emojis_frequent'] - if (foundEmojiIndex === -1) { - newEmojisSort = currentEmojis || [] - const temp = { - emoji, - score: 0, - count: 0, - lastUsed: new Date().getTime() - } - newEmojisSort.push({ - ...temp, - score: calculateScore(temp), - count: temp.count + 1 - }) - } else { - newEmojisSort = - currentEmojis - ?.map((e, i) => - i === foundEmojiIndex - ? { - ...e, - score: calculateScore(e), - count: e.count + 1, - lastUsed: new Date().getTime() - } - : e - ) - .sort((a, b) => b.score - a.score) || [] + setAccountStorage([ + { + key: 'emojis_frequent', + value: newEmojisSort.sort((a, b) => b.score - a.score).slice(0, 20) } - - setAccountStorage([ - { - key: 'emojis_frequent', - value: newEmojisSort.sort((a, b) => b.score - a.score).slice(0, 20) - } - ]) - }} - style={{ padding: StyleConstants.Spacing.S }} - > - - - ) - } else { - return null - } + ]) + }} + style={{ padding: StyleConstants.Spacing.S }} + > + + + ) })} ) diff --git a/src/components/Instance/index.tsx b/src/components/Instance/index.tsx index eb104b14..4940bf23 100644 --- a/src/components/Instance/index.tsx +++ b/src/components/Instance/index.tsx @@ -5,7 +5,7 @@ import apiGeneral from '@utils/api/general' import browserPackage from '@utils/helpers/browserPackage' import { featureCheck } from '@utils/helpers/featureCheck' import { TabMeStackNavigationProp } from '@utils/navigation/navigators' -import queryClient from '@utils/queryHooks' +import { queryClient } from '@utils/queryHooks' import { redirectUri, useAppsMutation } from '@utils/queryHooks/apps' import { useInstanceQuery } from '@utils/queryHooks/instance' import { storage } from '@utils/storage' @@ -19,7 +19,6 @@ import { import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' import * as AuthSession from 'expo-auth-session' -import * as Random from 'expo-random' import * as WebBrowser from 'expo-web-browser' import { debounce } from 'lodash' import React, { RefObject, useCallback, useState } from 'react' @@ -27,7 +26,7 @@ import { Trans, useTranslation } from 'react-i18next' import { Alert, Image, KeyboardAvoidingView, Platform, TextInput, View } from 'react-native' import { ScrollView } from 'react-native-gesture-handler' import { MMKV } from 'react-native-mmkv' -import validUrl from 'valid-url' +import parse from 'url-parse' import CustomText from '../Text' export interface Props { @@ -50,7 +49,7 @@ const ComponentInstance: React.FC = ({ const whitelisted: boolean = !!domain.length && !!errorCode && - !!validUrl.isHttpsUri(`https://${domain}`) && + !!(parse(`https://${domain}/`).hostname === domain) && errorCode === 401 const instanceQuery = useInstanceQuery({ diff --git a/src/components/Parse/Emojis.tsx b/src/components/Parse/Emojis.tsx index c1cb9aa7..0c23a5f7 100644 --- a/src/components/Parse/Emojis.tsx +++ b/src/components/Parse/Emojis.tsx @@ -7,7 +7,6 @@ import { useTheme } from '@utils/styles/ThemeManager' import React from 'react' import { Platform, TextStyle } from 'react-native' import FastImage from 'react-native-fast-image' -import validUrl from 'valid-url' const regexEmoji = new RegExp(/(:[A-Za-z0-9_]+:)/) @@ -72,23 +71,19 @@ const ParseEmojis: React.FC = ({ const uri = reduceMotionEnabled ? emojis[emojiIndex].static_url : emojis[emojiIndex].url - if (validUrl.isHttpsUri(uri)) { - return ( - - {i === 0 ? ' ' : undefined} - - - ) - } else { - return null - } + return ( + + {i === 0 ? ' ' : undefined} + + + ) } } else { return {str} diff --git a/src/components/Timeline/Shared/Card.tsx b/src/components/Timeline/Shared/Card.tsx index d9bf2600..12a065f3 100644 --- a/src/components/Timeline/Shared/Card.tsx +++ b/src/components/Timeline/Shared/Card.tsx @@ -3,9 +3,10 @@ import GracefullyImage from '@components/GracefullyImage' import openLink from '@components/openLink' import CustomText from '@components/Text' import { useNavigation } from '@react-navigation/native' -import { matchAccount, matchStatus } from '@utils/helpers/urlMatcher' +import { StackNavigationProp } from '@react-navigation/stack' +import { urlMatcher } from '@utils/helpers/urlMatcher' +import { TabLocalStackParamList } from '@utils/navigation/navigators' import { useAccountQuery } from '@utils/queryHooks/account' -import { useSearchQuery } from '@utils/queryHooks/search' import { useStatusQuery } from '@utils/queryHooks/status' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' @@ -20,97 +21,44 @@ const TimelineCard: React.FC = () => { if (!status || !status.card) return null const { colors } = useTheme() - const navigation = useNavigation() + const navigation = useNavigation>() const [loading, setLoading] = useState(false) - const isStatus = matchStatus(status.card.url) + const match = urlMatcher(status.card.url) const [foundStatus, setFoundStatus] = useState() - const isAccount = matchAccount(status.card.url) const [foundAccount, setFoundAccount] = useState() - const searchQuery = useSearchQuery({ - type: (() => { - if (isStatus) return 'statuses' - if (isAccount) return 'accounts' - })(), - term: (() => { - if (isStatus) { - if (isStatus.sameInstance) { - return - } else { - return status.card.url - } - } - if (isAccount) { - if (isAccount.sameInstance) { - if (isAccount.style === 'default') { - return - } else { - return isAccount.username - } - } else { - return status.card.url - } - } - })(), - limit: 1, - options: { enabled: false } - }) - const statusQuery = useStatusQuery({ - id: isStatus?.id || '', + status: match?.status ? { ...match.status, uri: status.card.url } : undefined, options: { enabled: false } }) useEffect(() => { - if (isStatus) { + if (match?.status) { setLoading(true) - if (isStatus.sameInstance) { - statusQuery - .refetch() - .then(res => { - res.data && setFoundStatus(res.data) - setLoading(false) - }) - .catch(() => setLoading(false)) - } else { - searchQuery - .refetch() - .then(res => { - const status = (res.data as any)?.statuses?.[0] - status && setFoundStatus(status) - setLoading(false) - }) - .catch(() => setLoading(false)) - } + statusQuery + .refetch() + .then(res => { + res.data && setFoundStatus(res.data) + setLoading(false) + }) + .catch(() => setLoading(false)) } }, []) const accountQuery = useAccountQuery({ - account: - isAccount?.style === 'default' ? { id: isAccount.id, url: status.card.url } : undefined, + account: match?.account ? { ...match?.account, url: status.card.url } : undefined, options: { enabled: false } }) useEffect(() => { - if (isAccount) { + if (match?.account) { setLoading(true) - if (isAccount.sameInstance && isAccount.style === 'default') { - accountQuery - .refetch() - .then(res => { - res.data && setFoundAccount(res.data) - setLoading(false) - }) - .catch(() => setLoading(false)) - } else { - searchQuery - .refetch() - .then(res => { - const account = (res.data as any)?.accounts?.[0] - account && setFoundAccount(account) - setLoading(false) - }) - .catch(() => setLoading(false)) - } + accountQuery + .refetch() + .then(res => { + res.data && setFoundAccount(res.data) + setLoading(false) + }) + .catch(() => setLoading(false)) } }, []) @@ -129,10 +77,10 @@ const TimelineCard: React.FC = () => { ) } - if (isStatus && foundStatus) { + if (match?.status && foundStatus) { return } - if (isAccount && foundAccount) { + if (match?.account && foundAccount) { return } return ( @@ -198,7 +146,18 @@ const TimelineCard: React.FC = () => { overflow: 'hidden', borderColor: colors.border }} - onPress={async () => status.card && (await openLink(status.card.url, navigation))} + onPress={async () => { + if (match?.status && foundStatus) { + navigation.push('Tab-Shared-Toot', { toot: foundStatus }) + return + } + if (match?.account && foundAccount) { + navigation.push('Tab-Shared-Account', { account: foundAccount }) + return + } + + status.card?.url && (await openLink(status.card.url, navigation)) + }} children={cardContent()} /> ) diff --git a/src/components/Timeline/Shared/Feedback.tsx b/src/components/Timeline/Shared/Feedback.tsx index ec5bd793..79a17911 100644 --- a/src/components/Timeline/Shared/Feedback.tsx +++ b/src/components/Timeline/Shared/Feedback.tsx @@ -19,7 +19,7 @@ const TimelineFeedback = () => { const navigation = useNavigation>() const { data } = useStatusHistory({ - id: status.id, + status, options: { enabled: status.edited_at !== undefined } }) @@ -82,7 +82,7 @@ const TimelineFeedback = () => { style={[styles.text, { marginRight: 0, color: colors.blue }]} onPress={() => navigation.push('Tab-Shared-History', { - id: status.id, + status, detectedLanguage: detectedLanguage?.current || status.language || '' }) } diff --git a/src/components/Timeline/Shared/Filtered.tsx b/src/components/Timeline/Shared/Filtered.tsx index 520fc18d..9a8c11de 100644 --- a/src/components/Timeline/Shared/Filtered.tsx +++ b/src/components/Timeline/Shared/Filtered.tsx @@ -1,6 +1,6 @@ import CustomText from '@components/Text' -import queryClient from '@utils/queryHooks' import removeHTML from '@utils/helpers/removeHTML' +import { queryClient } from '@utils/queryHooks' import { QueryKeyFilters } from '@utils/queryHooks/filters' import { QueryKeyTimeline } from '@utils/queryHooks/timeline' import { StyleConstants } from '@utils/styles/constants' diff --git a/src/components/Timeline/Shared/HeaderConversation.tsx b/src/components/Timeline/Shared/HeaderConversation.tsx index db9c481e..69252478 100644 --- a/src/components/Timeline/Shared/HeaderConversation.tsx +++ b/src/components/Timeline/Shared/HeaderConversation.tsx @@ -73,13 +73,8 @@ const HeaderConversation = ({ conversation }: Props) => { marginBottom: StyleConstants.Spacing.S }} > - {conversation.last_status?.created_at ? ( - - ) : null} - + {conversation.last_status?.created_at ? : null} + diff --git a/src/components/Timeline/Shared/HeaderDefault.tsx b/src/components/Timeline/Shared/HeaderDefault.tsx index e5795207..48bf2e03 100644 --- a/src/components/Timeline/Shared/HeaderDefault.tsx +++ b/src/components/Timeline/Shared/HeaderDefault.tsx @@ -17,7 +17,7 @@ import HeaderSharedReplies from './HeaderShared/Replies' import HeaderSharedVisibility from './HeaderShared/Visibility' const TimelineHeaderDefault: React.FC = () => { - const { queryKey, rootQueryKey, status, highlighted, disableDetails, rawContent, isRemote } = + const { queryKey, rootQueryKey, status, disableDetails, rawContent, isRemote } = useContext(StatusContext) if (!status) return null @@ -66,15 +66,11 @@ const TimelineHeaderDefault: React.FC = () => { style={{ marginRight: StyleConstants.Spacing.S }} /> ) : null} - - - + + + - + diff --git a/src/components/Timeline/Shared/HeaderNotification.tsx b/src/components/Timeline/Shared/HeaderNotification.tsx index 531cd543..2c63182e 100644 --- a/src/components/Timeline/Shared/HeaderNotification.tsx +++ b/src/components/Timeline/Shared/HeaderNotification.tsx @@ -146,15 +146,10 @@ const TimelineHeaderNotification: React.FC = ({ notification }) => { marginBottom: StyleConstants.Spacing.S }} > - - {notification.status?.visibility ? ( - - ) : null} - - + + {notification.status?.visibility ? : null} + + diff --git a/src/components/Timeline/Shared/HeaderShared/Application.tsx b/src/components/Timeline/Shared/HeaderShared/Application.tsx index 9f5f3344..2e021b2f 100644 --- a/src/components/Timeline/Shared/HeaderShared/Application.tsx +++ b/src/components/Timeline/Shared/HeaderShared/Application.tsx @@ -2,32 +2,31 @@ import openLink from '@components/openLink' import CustomText from '@components/Text' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' -import React from 'react' +import React, { useContext } from 'react' import { useTranslation } from 'react-i18next' +import StatusContext from '../Context' -export interface Props { - application?: Mastodon.Application -} - -const HeaderSharedApplication: React.FC = ({ application }) => { +const HeaderSharedApplication: React.FC = () => { + const { status } = useContext(StatusContext) const { colors } = useTheme() const { t } = useTranslation('componentTimeline') - return application && application.name !== 'Web' ? ( + return status?.application?.name && status.application.name !== 'Web' ? ( { - application.website && (await openLink(application.website)) + status.application?.website && (await openLink(status.application.website)) }} style={{ + flex: 1, marginLeft: StyleConstants.Spacing.S, color: colors.secondary }} numberOfLines={1} > {t('shared.header.shared.application', { - application: application.name + application: status.application.name })} ) : null diff --git a/src/components/Timeline/Shared/HeaderShared/Created.tsx b/src/components/Timeline/Shared/HeaderShared/Created.tsx index bcc39aa4..091715f3 100644 --- a/src/components/Timeline/Shared/HeaderShared/Created.tsx +++ b/src/components/Timeline/Shared/HeaderShared/Created.tsx @@ -3,21 +3,23 @@ import RelativeTime from '@components/RelativeTime' import CustomText from '@components/Text' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' -import React from 'react' +import React, { useContext } from 'react' import { useTranslation } from 'react-i18next' import { FormattedDate } from 'react-intl' +import StatusContext from '../Context' export interface Props { - created_at: Mastodon.Status['created_at'] | number - edited_at?: Mastodon.Status['edited_at'] - highlighted?: boolean + created_at?: Mastodon.Status['created_at'] | number } -const HeaderSharedCreated: React.FC = ({ created_at, edited_at, highlighted = false }) => { +const HeaderSharedCreated: React.FC = ({ created_at }) => { + const { status, highlighted } = useContext(StatusContext) const { t } = useTranslation('componentTimeline') const { colors } = useTheme() - const actualTime = edited_at || created_at + if (!status) return null + + const actualTime = created_at || status.edited_at || status.created_at return ( <> @@ -30,7 +32,7 @@ const HeaderSharedCreated: React.FC = ({ created_at, edited_at, highlight )} - {edited_at ? ( + {status.edited_at && !highlighted ? ( = ({ muted }) => { +const HeaderSharedMuted: React.FC = () => { + const { status } = useContext(StatusContext) const { t } = useTranslation('componentTimeline') const { colors } = useTheme() - return muted ? ( + return status?.muted ? ( = ({ visibility }) => { +const HeaderSharedVisibility: React.FC = () => { + const { status } = useContext(StatusContext) const { t } = useTranslation('componentTimeline') const { colors } = useTheme() - switch (visibility) { + switch (status?.visibility) { case 'unlisted': return ( { return } - const handleNavigation = (page: 'Tab-Shared-Toot' | 'Tab-Shared-Account', options: {}) => { + const handleNavigation = (page: 'Tab-Shared-Toot' | 'Tab-Shared-Account', options: any) => { if (navigation) { navigation.push(page, options) } else { @@ -24,83 +25,79 @@ const openLink = async (url: string, navigation?: any) => { } } + const match = urlMatcher(url) // If a tooot can be found - const isStatus = matchStatus(url) - if (isStatus) { - if (isStatus.sameInstance) { - handleNavigation('Tab-Shared-Toot', { toot: { id: isStatus.id } }) - return - } - + if (match?.status?.id) { loadingLink = true - let response - try { - response = await apiInstance({ - version: 'v2', - method: 'get', - url: 'search', - params: { type: 'statuses', q: url, limit: 1, resolve: true } - }) - } catch {} - if (response && response.body && response.body.statuses.length) { - handleNavigation('Tab-Shared-Toot', { - toot: response.body.statuses[0] - }) + let response: Mastodon.Status | undefined = undefined + + const queryKey: QueryKeyStatus = [ + 'Status', + { id: match.status.id, uri: url, _remote: match.status._remote } + ] + const cache = queryClient.getQueryData(queryKey) + + if (cache) { + handleNavigation('Tab-Shared-Toot', { toot: cache }) loadingLink = false return + } else { + try { + response = await searchLocalStatus(url) + } catch {} + if (response) { + handleNavigation('Tab-Shared-Toot', { toot: response }) + loadingLink = false + return + } } } // If an account can be found - const isAccount = matchAccount(url) - if (isAccount) { - if (isAccount.sameInstance) { - if (isAccount.style === 'default' && isAccount.id) { - handleNavigation('Tab-Shared-Account', { account: isAccount }) - return - } + if (match?.account) { + if (!match.account._remote && match.account.id) { + handleNavigation('Tab-Shared-Account', { account: match.account.id }) + return } loadingLink = true - let response - try { - response = await apiInstance({ - version: 'v2', - method: 'get', - url: 'search', - params: { - type: 'accounts', - q: isAccount.sameInstance && isAccount.style === 'pretty' ? isAccount.username : url, - limit: 1, - resolve: true - } - }) - } catch {} - if (response && response.body && response.body.accounts.length) { - handleNavigation('Tab-Shared-Account', { - account: response.body.accounts[0] - }) + let response: Mastodon.Account | undefined = undefined + + const queryKey: QueryKeyAccount = [ + 'Account', + { id: match.account.id, url: url, _remote: match.account._remote } + ] + const cache = queryClient.getQueryData(queryKey) + + if (cache) { + handleNavigation('Tab-Shared-Account', { account: cache }) loadingLink = false return + } else { + try { + response = await searchLocalAccount(url) + } catch {} + if (response) { + handleNavigation('Tab-Shared-Account', { account: response }) + loadingLink = false + return + } } } loadingLink = false - const validatedUrl = validUrl.isWebUri(url) - if (validatedUrl) { - switch (getGlobalStorage.string('app.browser')) { - // Some links might end with an empty space at the end that triggers an error - case 'internal': - await WebBrowser.openBrowserAsync(validatedUrl, { - dismissButtonStyle: 'close', - enableBarCollapsing: true, - ...(await browserPackage()) - }) - break - case 'external': - await Linking.openURL(validatedUrl) - break - } + switch (getGlobalStorage.string('app.browser')) { + // Some links might end with an empty space at the end that triggers an error + case 'internal': + await WebBrowser.openBrowserAsync(url.trim(), { + dismissButtonStyle: 'close', + enableBarCollapsing: true, + ...(await browserPackage()) + }) + break + case 'external': + await Linking.openURL(url.trim()) + break } } diff --git a/src/screens/Compose/index.tsx b/src/screens/Compose/index.tsx index f832afbf..b6c74688 100644 --- a/src/screens/Compose/index.tsx +++ b/src/screens/Compose/index.tsx @@ -10,7 +10,7 @@ import { handleError } from '@utils/api/helpers' import { RootStackScreenProps } from '@utils/navigation/navigators' import { useInstanceQuery } from '@utils/queryHooks/instance' import { usePreferencesQuery } from '@utils/queryHooks/preferences' -import { searchFetchToot, SearchResult } from '@utils/queryHooks/search' +import { searchLocalStatus } from '@utils/queryHooks/search' import { useTimelineMutation } from '@utils/queryHooks/timeline' import { getAccountStorage, @@ -156,7 +156,7 @@ const ScreenCompose: React.FC> = ({ content: params.accts.map(acct => `@${acct}`).join(' ') + ' ', disableDebounce: true }) - searchFetchToot(params.incomingStatus.uri).then(status => { + searchLocalStatus(params.incomingStatus.uri).then(status => { if (status?.uri === params.incomingStatus.uri) { composeDispatch({ type: 'updateReply', payload: status }) } diff --git a/src/screens/Compose/utils/processText.tsx b/src/screens/Compose/utils/processText.tsx index 561f1534..01b457fe 100644 --- a/src/screens/Compose/utils/processText.tsx +++ b/src/screens/Compose/utils/processText.tsx @@ -1,6 +1,6 @@ import { emojis } from '@components/Emojis' import CustomText from '@components/Text' -import queryClient from '@utils/queryHooks' +import { queryClient } from '@utils/queryHooks' import { QueryKeyInstance } from '@utils/queryHooks/instance' import { useTheme } from '@utils/styles/ThemeManager' import LinkifyIt from 'linkify-it' diff --git a/src/screens/Tabs/Me/Profile/Root.tsx b/src/screens/Tabs/Me/Profile/Root.tsx index a2f6a319..27d4331f 100644 --- a/src/screens/Tabs/Me/Profile/Root.tsx +++ b/src/screens/Tabs/Me/Profile/Root.tsx @@ -1,8 +1,8 @@ import { MenuContainer, MenuRow } from '@components/Menu' import { useActionSheet } from '@expo/react-native-action-sheet' import { androidActionSheetStyles } from '@utils/helpers/androidActionSheetStyles' -import queryClient from '@utils/queryHooks' import { TabMeProfileStackScreenProps } from '@utils/navigation/navigators' +import { queryClient } from '@utils/queryHooks' import { QueryKeyPreferences } from '@utils/queryHooks/preferences' import { useProfileMutation, useProfileQuery } from '@utils/queryHooks/profile' import { useTheme } from '@utils/styles/ThemeManager' diff --git a/src/screens/Tabs/Me/Settings/Dev.tsx b/src/screens/Tabs/Me/Settings/Dev.tsx index c015f00c..2e91b354 100644 --- a/src/screens/Tabs/Me/Settings/Dev.tsx +++ b/src/screens/Tabs/Me/Settings/Dev.tsx @@ -4,11 +4,13 @@ import { displayMessage } from '@components/Message' import { useActionSheet } from '@expo/react-native-action-sheet' import { useNavigation } from '@react-navigation/native' import { androidActionSheetStyles } from '@utils/helpers/androidActionSheetStyles' +import { urlMatcher } from '@utils/helpers/urlMatcher' import { storage } from '@utils/storage' import { getGlobalStorage, useGlobalStorage } from '@utils/storage/actions' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' import React from 'react' +import { Alert } from 'react-native' import { MMKV } from 'react-native-mmkv' const SettingsDev: React.FC = () => { @@ -37,6 +39,17 @@ const SettingsDev: React.FC = () => { ) } /> +