From 3d2339c2b56ceab77e791165c91f5cff1f9d2764 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Thu, 15 Dec 2022 14:28:36 +0100 Subject: [PATCH 01/22] Fix searching for remote accounts --- src/api/general.ts | 4 +- src/api/helpers/index.ts | 6 ++ src/api/instance.ts | 10 +--- src/screens/Compose.tsx | 2 +- src/screens/Compose/utils/post.ts | 6 +- src/screens/Tabs/Shared/Users.tsx | 61 +++++++++++++++++-- src/utils/queryHooks/lists.ts | 5 +- src/utils/queryHooks/search.ts | 11 ++-- src/utils/queryHooks/tags.ts | 5 +- src/utils/queryHooks/timeline.ts | 5 +- src/utils/queryHooks/users.ts | 97 ++++++++++++++----------------- src/utils/queryHooks/utils.ts | 6 +- 12 files changed, 134 insertions(+), 84 deletions(-) diff --git a/src/api/general.ts b/src/api/general.ts index e29637d3..f13e698f 100644 --- a/src/api/general.ts +++ b/src/api/general.ts @@ -1,5 +1,5 @@ import axios from 'axios' -import { ctx, handleError, userAgent } from './helpers' +import { ctx, handleError, PagedResponse, userAgent } from './helpers' export type Params = { method: 'get' | 'post' | 'put' | 'delete' @@ -19,7 +19,7 @@ const apiGeneral = async ({ params, headers, body -}: Params): Promise<{ body: T }> => { +}: Params): Promise> => { console.log( ctx.bgGreen.bold(' API general ') + ' ' + diff --git a/src/api/helpers/index.ts b/src/api/helpers/index.ts index 55871b18..65013f79 100644 --- a/src/api/helpers/index.ts +++ b/src/api/helpers/index.ts @@ -63,4 +63,10 @@ const handleError = } } +type LinkFormat = { id: string; isOffset: boolean } +export type PagedResponse = { + body: T + links: { prev?: LinkFormat; next?: LinkFormat } +} + export { ctx, handleError, userAgent } diff --git a/src/api/instance.ts b/src/api/instance.ts index ca094b4d..d6446e8f 100644 --- a/src/api/instance.ts +++ b/src/api/instance.ts @@ -1,6 +1,6 @@ import { RootState } from '@root/store' import axios, { AxiosRequestConfig } from 'axios' -import { ctx, handleError, userAgent } from './helpers' +import { ctx, handleError, PagedResponse, userAgent } from './helpers' export type Params = { method: 'get' | 'post' | 'put' | 'delete' | 'patch' @@ -14,12 +14,6 @@ export type Params = { extras?: Omit } -type LinkFormat = { id: string; isOffset: boolean } -export type InstanceResponse = { - body: T - links: { prev?: LinkFormat; next?: LinkFormat } -} - const apiInstance = async ({ method, version = 'v1', @@ -28,7 +22,7 @@ const apiInstance = async ({ headers, body, extras -}: Params): Promise> => { +}: Params): Promise> => { const { store } = require('@root/store') const state = store.getState() as RootState const instanceActive = state.instances.instances.findIndex(instance => instance.active) diff --git a/src/screens/Compose.tsx b/src/screens/Compose.tsx index 81334a8e..8b4c5a9e 100644 --- a/src/screens/Compose.tsx +++ b/src/screens/Compose.tsx @@ -286,7 +286,7 @@ const ScreenCompose: React.FC> = ({ type: 'editItem', queryKey: params.queryKey, rootQueryKey: params.rootQueryKey, - status: res.body + status: res }) break case 'deleteEdit': diff --git a/src/screens/Compose/utils/post.ts b/src/screens/Compose/utils/post.ts index c9e4f116..98ceec8b 100644 --- a/src/screens/Compose/utils/post.ts +++ b/src/screens/Compose/utils/post.ts @@ -1,4 +1,4 @@ -import apiInstance, { InstanceResponse } from '@api/instance' +import apiInstance from '@api/instance' import detectLanguage from '@helpers/detectLanguage' import { ComposeState } from '@screens/Compose/utils/types' import { RootStackParamList } from '@utils/navigation/navigators' @@ -8,7 +8,7 @@ import { getPureContent } from './processText' const composePost = async ( params: RootStackParamList['Screen-Compose'], composeState: ComposeState -): Promise> => { +): Promise => { const formData = new FormData() const detectedLanguage = await detectLanguage( @@ -74,7 +74,7 @@ const composePost = async ( ) }, body: formData - }) + }).then(res => res.body) } export default composePost diff --git a/src/screens/Tabs/Shared/Users.tsx b/src/screens/Tabs/Shared/Users.tsx index fff09d70..5183c3c6 100644 --- a/src/screens/Tabs/Shared/Users.tsx +++ b/src/screens/Tabs/Shared/Users.tsx @@ -1,15 +1,18 @@ +import apiInstance from '@api/instance' import ComponentAccount from '@components/Account' import { HeaderLeft } from '@components/Header' import Icon from '@components/Icon' import ComponentSeparator from '@components/Separator' import CustomText from '@components/Text' import { TabSharedStackScreenProps } from '@utils/navigation/navigators' +import { SearchResult } from '@utils/queryHooks/search' import { QueryKeyUsers, useUsersQuery } from '@utils/queryHooks/users' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' -import React, { useCallback, useEffect } from 'react' +import React, { useCallback, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import { View } from 'react-native' +import { Circle, Flow } from 'react-native-animated-spinkit' import { FlatList } from 'react-native-gesture-handler' const TabSharedUsers: React.FC> = ({ @@ -26,7 +29,7 @@ const TabSharedUsers: React.FC> = }, []) const queryKey: QueryKeyUsers = ['Users', params] - const { data, hasNextPage, fetchNextPage, isFetchingNextPage } = useUsersQuery({ + const { data, isFetching, hasNextPage, fetchNextPage, isFetchingNextPage } = useUsersQuery({ ...queryKey[1], options: { getPreviousPageParam: firstPage => @@ -41,17 +44,67 @@ const TabSharedUsers: React.FC> = [hasNextPage, isFetchingNextPage] ) + const [isSearching, setIsSearching] = useState(false) + return ( } + renderItem={({ item }) => ( + { + if (data?.pages[0]?.remoteData) { + setIsSearching(true) + apiInstance({ + version: 'v2', + method: 'get', + url: 'search', + params: { + q: `@${item.acct}`, + type: 'accounts', + limit: 1, + resolve: true + } + }) + .then(res => { + setIsSearching(false) + if (res.body.accounts[0]) { + navigation.push('Tab-Shared-Account', { account: res.body.accounts[0] }) + } + }) + .catch(() => setIsSearching(false)) + } else { + navigation.push('Tab-Shared-Account', { account: item }) + } + } + }} + children={} + /> + )} onEndReached={onEndReached} onEndReachedThreshold={0.75} ItemSeparatorComponent={ComponentSeparator} + ListEmptyComponent={ + isFetching ? ( + + + + ) : null + } maintainVisibleContentPosition={{ minIndexForVisible: 0, autoscrollToTopThreshold: 2 diff --git a/src/utils/queryHooks/lists.ts b/src/utils/queryHooks/lists.ts index 0f7f0b81..b0e11989 100644 --- a/src/utils/queryHooks/lists.ts +++ b/src/utils/queryHooks/lists.ts @@ -1,4 +1,4 @@ -import apiInstance, { InstanceResponse } from '@api/instance' +import apiInstance from '@api/instance' import { AxiosError } from 'axios' import { QueryFunctionContext, @@ -9,6 +9,7 @@ import { useQuery, UseQueryOptions } from '@tanstack/react-query' +import { PagedResponse } from '@api/helpers' export type QueryKeyLists = ['Lists'] @@ -97,7 +98,7 @@ const useListAccountsQuery = ({ options, ...queryKeyParams }: QueryKeyListAccounts[1] & { - options?: UseInfiniteQueryOptions, AxiosError> + options?: UseInfiniteQueryOptions, AxiosError> }) => { const queryKey: QueryKeyListAccounts = ['ListAccounts', queryKeyParams] return useInfiniteQuery(queryKey, accountsQueryFunction, options) diff --git a/src/utils/queryHooks/search.ts b/src/utils/queryHooks/search.ts index 82d9fbb8..313a7885 100644 --- a/src/utils/queryHooks/search.ts +++ b/src/utils/queryHooks/search.ts @@ -17,17 +17,18 @@ export type SearchResult = { statuses: Mastodon.Status[] } -const queryFunction = async ({ - queryKey -}: QueryFunctionContext) => { +const queryFunction = async ({ queryKey }: QueryFunctionContext) => { const { type, term, limit = 20 } = queryKey[1] + if (!term?.length) { + return Promise.reject() + } const res = await apiInstance({ version: 'v2', method: 'get', url: 'search', params: { + q: term, ...(type && { type }), - ...(term && { q: term }), limit, resolve: true } @@ -35,7 +36,7 @@ const queryFunction = async ({ return res.body } -const useSearchQuery = ({ +const useSearchQuery = ({ options, ...queryKeyParams }: QueryKeySearch[1] & { diff --git a/src/utils/queryHooks/tags.ts b/src/utils/queryHooks/tags.ts index e350124d..28e61831 100644 --- a/src/utils/queryHooks/tags.ts +++ b/src/utils/queryHooks/tags.ts @@ -1,4 +1,4 @@ -import apiInstance, { InstanceResponse } from '@api/instance' +import apiInstance from '@api/instance' import { AxiosError } from 'axios' import { QueryFunctionContext, @@ -10,12 +10,13 @@ import { UseQueryOptions } from '@tanstack/react-query' import { infinitePageParams } from './utils' +import { PagedResponse } from '@api/helpers' export type QueryKeyFollowedTags = ['FollowedTags'] const useFollowedTagsQuery = ( params: { options?: Omit< - UseInfiniteQueryOptions, AxiosError>, + UseInfiniteQueryOptions, AxiosError>, 'getPreviousPageParam' | 'getNextPageParam' > } | void diff --git a/src/utils/queryHooks/timeline.ts b/src/utils/queryHooks/timeline.ts index ea7c0fe6..5417acc9 100644 --- a/src/utils/queryHooks/timeline.ts +++ b/src/utils/queryHooks/timeline.ts @@ -1,4 +1,4 @@ -import apiInstance, { InstanceResponse } from '@api/instance' +import apiInstance from '@api/instance' import haptics from '@components/haptics' import queryClient from '@helpers/queryClient' import { store } from '@root/store' @@ -15,6 +15,7 @@ import { import deleteItem from './timeline/deleteItem' import editItem from './timeline/editItem' import updateStatusProperty from './timeline/updateStatusProperty' +import { PagedResponse } from '@api/helpers' export type QueryKeyTimeline = [ 'Timeline', @@ -240,7 +241,7 @@ const useTimelineQuery = ({ options, ...queryKeyParams }: QueryKeyTimeline[1] & { - options?: UseInfiniteQueryOptions, AxiosError> + options?: UseInfiniteQueryOptions, AxiosError> }) => { const queryKey: QueryKeyTimeline = ['Timeline', { ...queryKeyParams }] return useInfiniteQuery(queryKey, queryFunction, { diff --git a/src/utils/queryHooks/users.ts b/src/utils/queryHooks/users.ts index 810ffa03..0e8ecbdc 100644 --- a/src/utils/queryHooks/users.ts +++ b/src/utils/queryHooks/users.ts @@ -1,4 +1,4 @@ -import apiInstance, { InstanceResponse } from '@api/instance' +import apiInstance from '@api/instance' import { TabSharedStackParamList } from '@utils/navigation/navigators' import { AxiosError } from 'axios' import { @@ -7,10 +7,15 @@ import { UseInfiniteQueryOptions } from '@tanstack/react-query' import apiGeneral from '@api/general' +import { PagedResponse } from '@api/helpers' export type QueryKeyUsers = ['Users', TabSharedStackParamList['Tab-Shared-Users']] -const queryFunction = ({ queryKey, pageParam }: QueryFunctionContext) => { +const queryFunction = async ({ + queryKey, + pageParam, + meta +}: QueryFunctionContext) => { const page = queryKey[1] let params: { [key: string]: string } = { ...pageParam } @@ -20,7 +25,7 @@ const queryFunction = ({ queryKey, pageParam }: QueryFunctionContext ({ ...res, warnIncomplete: false })) + }) case 'accounts': const localInstance = page.account.username === page.account.acct if (localInstance) { @@ -28,59 +33,47 @@ const queryFunction = ({ queryKey, pageParam }: QueryFunctionContext ({ ...res, warnIncomplete: false })) + }) } else { - const domain = page.account.url.match( - /^(?:https?:\/\/)?(?:[^@\/\n]+@)?(?:www\.)?([^:\/\n]+)/i - )?.[1] - if (!domain) { - return apiInstance({ + let res: PagedResponse + + try { + const domain = page.account.url.match( + /^(?:https?:\/\/)?(?:[^@\/\n]+@)?(?:www\.)?([^:\/\n]+)/i + )?.[1] + if (!domain?.length) { + throw new Error() + } + + const resSearch = await apiGeneral<{ accounts: Mastodon.Account[] }>({ + method: 'get', + domain, + url: 'api/v2/search', + params: { + q: `@${page.account.acct}`, + type: 'accounts', + limit: '1' + } + }) + if (resSearch?.body?.accounts?.length === 1) { + res = await apiGeneral({ + method: 'get', + domain, + url: `api/v1/${page.reference}/${resSearch.body.accounts[0].id}/${page.type}`, + params + }) + return { ...res, remoteData: true } + } else { + throw new Error() + } + } catch { + res = await apiInstance({ method: 'get', url: `${page.reference}/${page.account.id}/${page.type}`, params - }).then(res => ({ ...res, warnIncomplete: true })) + }) + return { ...res, warnIncomplete: true } } - return apiGeneral<{ accounts: Mastodon.Account[] }>({ - method: 'get', - domain, - url: 'api/v2/search', - params: { - q: `@${page.account.acct}`, - type: 'accounts', - limit: '1' - } - }) - .then(res => { - if (res?.body?.accounts?.length === 1) { - return apiGeneral({ - method: 'get', - domain, - url: `api/v1/${page.reference}/${res.body.accounts[0].id}/${page.type}`, - params - }) - .catch(() => { - return apiInstance({ - method: 'get', - url: `${page.reference}/${page.account.id}/${page.type}`, - params - }).then(res => ({ ...res, warnIncomplete: true })) - }) - .then(res => ({ ...res, warnIncomplete: false })) - } else { - return apiInstance({ - method: 'get', - url: `${page.reference}/${page.account.id}/${page.type}`, - params - }).then(res => ({ ...res, warnIncomplete: true })) - } - }) - .catch(() => { - return apiInstance({ - method: 'get', - url: `${page.reference}/${page.account.id}/${page.type}`, - params - }).then(res => ({ ...res, warnIncomplete: true })) - }) } } } @@ -90,7 +83,7 @@ const useUsersQuery = ({ ...queryKeyParams }: QueryKeyUsers[1] & { options?: UseInfiniteQueryOptions< - InstanceResponse & { warnIncomplete: boolean }, + PagedResponse & { warnIncomplete: boolean; remoteData: boolean }, AxiosError > }) => { diff --git a/src/utils/queryHooks/utils.ts b/src/utils/queryHooks/utils.ts index 5b57931b..15f39096 100644 --- a/src/utils/queryHooks/utils.ts +++ b/src/utils/queryHooks/utils.ts @@ -1,8 +1,8 @@ -import { InstanceResponse } from '@api/instance' +import { PagedResponse } from '@api/helpers' export const infinitePageParams = { - getPreviousPageParam: (firstPage: InstanceResponse) => + getPreviousPageParam: (firstPage: PagedResponse) => firstPage.links?.prev && { min_id: firstPage.links.next }, - getNextPageParam: (lastPage: InstanceResponse) => + getNextPageParam: (lastPage: PagedResponse) => lastPage.links?.next && { max_id: lastPage.links.next } } From 2f3e398d7012e3524cc25d0b06cf0e5d57db62fb Mon Sep 17 00:00:00 2001 From: xmflsct Date: Thu, 15 Dec 2022 18:43:39 +0100 Subject: [PATCH 02/22] Fixed #556 --- src/components/Menu/Row.tsx | 1 - src/screens/Tabs/Me/SettingsLanguage.tsx | 34 ++++++++++++------------ 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/components/Menu/Row.tsx b/src/components/Menu/Row.tsx index b3b8ca6e..c4d32e9b 100644 --- a/src/components/Menu/Row.tsx +++ b/src/components/Menu/Row.tsx @@ -65,7 +65,6 @@ const MenuRow: React.FC = ({ > { - if (typeof iconBack !== 'string') return // Let icon back handles the gesture if (nativeEvent.state === State.ACTIVE && !loading) { if (screenReaderEnabled && switchOnValueChange) { switchOnValueChange() diff --git a/src/screens/Tabs/Me/SettingsLanguage.tsx b/src/screens/Tabs/Me/SettingsLanguage.tsx index 399a39d2..ee87aa16 100644 --- a/src/screens/Tabs/Me/SettingsLanguage.tsx +++ b/src/screens/Tabs/Me/SettingsLanguage.tsx @@ -1,10 +1,11 @@ import haptics from '@components/haptics' -import { MenuContainer, MenuRow } from '@components/Menu' +import { MenuRow } from '@components/Menu' import { LOCALES } from '@root/i18n/locales' import { TabMeStackScreenProps } from '@utils/navigation/navigators' import { setChannels } from '@utils/slices/instances/push/utils' import { getInstances } from '@utils/slices/instancesSlice' import { changeLanguage } from '@utils/slices/settingsSlice' +import { StyleConstants } from '@utils/styles/constants' import React from 'react' import { useTranslation } from 'react-i18next' import { FlatList, Platform } from 'react-native' @@ -33,22 +34,21 @@ const TabMeSettingsLanguage: React.FC - { - return ( - item[0] !== i18n.language && change(item[0])} - /> - ) - }} - /> - + { + return ( + item[0] !== i18n.language && change(item[0])} + /> + ) + }} + /> ) } From 0e348dcef1a56bb6ea64f5e7923c1a7834ee9e0d Mon Sep 17 00:00:00 2001 From: xmflsct Date: Thu, 15 Dec 2022 19:31:20 +0100 Subject: [PATCH 03/22] Fix bugs --- src/@types/mastodon.d.ts | 1 + src/components/Menu/Row.tsx | 2 +- src/helpers/features.json | 31 +++----- src/screens/Tabs/Me/Push.tsx | 50 ++++++------ src/screens/Tabs/Me/Root/Collections.tsx | 8 +- src/screens/Tabs/Notifications/Filters.tsx | 44 +---------- src/utils/migrations/instances/migration.ts | 1 + src/utils/slices/instances/add.ts | 1 + src/utils/slices/instances/push/utils.ts | 87 ++++++++++++++++----- 9 files changed, 122 insertions(+), 103 deletions(-) diff --git a/src/@types/mastodon.d.ts b/src/@types/mastodon.d.ts index 7fec5552..699cbd16 100644 --- a/src/@types/mastodon.d.ts +++ b/src/@types/mastodon.d.ts @@ -395,6 +395,7 @@ declare namespace Mastodon { mention: boolean poll: boolean status: boolean + update: boolean 'admin.sign_up': boolean 'admin.report': boolean } diff --git a/src/components/Menu/Row.tsx b/src/components/Menu/Row.tsx index c4d32e9b..2bfe1cdd 100644 --- a/src/components/Menu/Row.tsx +++ b/src/components/Menu/Row.tsx @@ -85,7 +85,7 @@ const MenuRow: React.FC = ({ > { } }, [appsQuery.data?.vapid_key]) + const pushFeatures = usePushFeatures() + const alerts = () => instancePush?.alerts - ? PUSH_DEFAULT.map(alert => ( + ? PUSH_DEFAULT(pushFeatures).map(alert => ( { const profileQuery = useProfileQuery() const adminAlerts = () => profileQuery.data?.role?.permissions - ? PUSH_ADMIN.map(({ type, permission }) => - checkPermission(permission, profileQuery.data.role?.permissions) ? ( - - dispatch( - updateInstancePushAlert({ - alerts: { - ...instancePush?.alerts, - [type]: instancePush?.alerts[type] - } - }) - ) - } - /> - ) : null - ) + ? PUSH_ADMIN(pushFeatures, profileQuery.data?.role?.permissions).map(({ type }) => ( + + dispatch( + updateInstancePushAlert({ + alerts: { + ...instancePush?.alerts, + [type]: instancePush?.alerts[type] + } + }) + ) + } + /> + )) : null return ( diff --git a/src/screens/Tabs/Me/Root/Collections.tsx b/src/screens/Tabs/Me/Root/Collections.tsx index 8c103221..0988df92 100644 --- a/src/screens/Tabs/Me/Root/Collections.tsx +++ b/src/screens/Tabs/Me/Root/Collections.tsx @@ -4,7 +4,11 @@ import { useAppDispatch } from '@root/store' import { useAnnouncementQuery } from '@utils/queryHooks/announcement' import { useListsQuery } from '@utils/queryHooks/lists' import { useFollowedTagsQuery } from '@utils/queryHooks/tags' -import { getInstanceMePage, updateInstanceMePage } from '@utils/slices/instancesSlice' +import { + checkInstanceFeature, + getInstanceMePage, + updateInstanceMePage +} from '@utils/slices/instancesSlice' import { getInstancePush } from '@utils/slices/instancesSlice' import React, { useEffect } from 'react' import { useTranslation } from 'react-i18next' @@ -17,8 +21,10 @@ const Collections: React.FC = () => { const dispatch = useAppDispatch() const mePage = useSelector(getInstanceMePage) + const canFollowTags = useSelector(checkInstanceFeature('follow_tags')) useFollowedTagsQuery({ options: { + enabled: canFollowTags, onSuccess: data => dispatch( updateInstanceMePage({ diff --git a/src/screens/Tabs/Notifications/Filters.tsx b/src/screens/Tabs/Notifications/Filters.tsx index 2a3270ed..f8fa7f54 100644 --- a/src/screens/Tabs/Notifications/Filters.tsx +++ b/src/screens/Tabs/Notifications/Filters.tsx @@ -1,17 +1,12 @@ import { HeaderLeft, HeaderRight } from '@components/Header' import { MenuContainer, MenuRow } from '@components/Menu' -import { - checkPermission, - PERMISSION_MANAGE_REPORTS, - PERMISSION_MANAGE_USERS -} from '@helpers/permissions' import { useAppDispatch } from '@root/store' import { useQueryClient } from '@tanstack/react-query' import { TabNotificationsStackScreenProps } from '@utils/navigation/navigators' import { useProfileQuery } from '@utils/queryHooks/profile' import { QueryKeyTimeline } from '@utils/queryHooks/timeline' +import { PUSH_ADMIN, PUSH_DEFAULT, usePushFeatures } from '@utils/slices/instances/push/utils' import { - checkInstanceFeature, getInstanceNotificationsFilter, updateInstanceNotificationsFilter } from '@utils/slices/instancesSlice' @@ -22,32 +17,12 @@ import { Alert } from 'react-native' import { ScrollView } from 'react-native-gesture-handler' import { useSelector } from 'react-redux' -export const NOTIFICATIONS_FILTERS_DEFAULT: [ - 'follow', - 'follow_request', - 'favourite', - 'reblog', - 'mention', - 'poll', - 'status', - 'update' -] = ['follow', 'follow_request', 'favourite', 'reblog', 'mention', 'poll', 'status', 'update'] - -export const NOTIFICATIONS_FILTERS_ADMIN: { - type: 'admin.sign_up' | 'admin.report' - permission: number -}[] = [ - { type: 'admin.sign_up', permission: PERMISSION_MANAGE_USERS }, - { type: 'admin.report', permission: PERMISSION_MANAGE_REPORTS } -] - const TabNotificationsFilters: React.FC< TabNotificationsStackScreenProps<'Tab-Notifications-Filters'> > = ({ navigation }) => { const { t } = useTranslation('screenTabs') - const hasTypeStatus = useSelector(checkInstanceFeature('notification_type_status')) - const hasTypeUpdate = useSelector(checkInstanceFeature('notification_type_update')) + const pushFeatures = usePushFeatures() const dispatch = useAppDispatch() @@ -103,16 +78,7 @@ const TabNotificationsFilters: React.FC< return ( - {NOTIFICATIONS_FILTERS_DEFAULT.filter(type => { - switch (type) { - case 'status': - return hasTypeStatus - case 'update': - return hasTypeUpdate - default: - return true - } - }).map((type, index) => ( + {PUSH_DEFAULT(pushFeatures).map((type, index) => ( setFilters({ ...filters, [type]: !filters[type] })} /> ))} - {NOTIFICATIONS_FILTERS_ADMIN.filter(({ permission }) => - checkPermission(permission, profileQuery.data?.role?.permissions) - ).map(({ type }) => ( + {PUSH_ADMIN(pushFeatures, profileQuery.data?.role?.permissions).map(({ type }) => ( { + const hasTypeStatus = useSelector(checkInstanceFeature('notification_type_status')) + const hasTypeUpdate = useSelector(checkInstanceFeature('notification_type_update')) + const hasTypeAdminSignup = useSelector(checkInstanceFeature('notification_type_admin_signup')) + const hasTypeAdminReport = useSelector(checkInstanceFeature('notification_type_admin_report')) + return { hasTypeStatus, hasTypeUpdate, hasTypeAdminSignup, hasTypeAdminReport } +} -export const PUSH_ADMIN: { type: 'admin.sign_up' | 'admin.report'; permission: number }[] = [ - { type: 'admin.sign_up', permission: PERMISSION_MANAGE_USERS }, - { type: 'admin.report', permission: PERMISSION_MANAGE_REPORTS } -] +export const PUSH_DEFAULT = ({ + hasTypeUpdate, + hasTypeStatus +}: { + hasTypeUpdate: boolean + hasTypeStatus: boolean +}) => + ['follow', 'follow_request', 'favourite', 'reblog', 'mention', 'poll', 'update', 'status'].filter( + type => { + switch (type) { + case 'status': + return hasTypeStatus + case 'update': + return hasTypeUpdate + default: + return true + } + } + ) as ['follow', 'follow_request', 'favourite', 'reblog', 'mention', 'poll', 'update', 'status'] + +export const PUSH_ADMIN = ( + { + hasTypeAdminSignup, + hasTypeAdminReport + }: { + hasTypeAdminSignup: boolean + hasTypeAdminReport: boolean + }, + permissions?: string | number | undefined +) => + [ + { type: 'admin.sign_up', permission: PERMISSION_MANAGE_USERS }, + { type: 'admin.report', permission: PERMISSION_MANAGE_REPORTS } + ].filter(({ type, permission }) => { + switch (type) { + case 'admin.sign_up': + return hasTypeAdminSignup && checkPermission(permission, permissions) + case 'admin.report': + return hasTypeAdminReport && checkPermission(permission, permissions) + } + }) as { type: 'admin.sign_up' | 'admin.report'; permission: number }[] export const setChannels = async (instance: InstanceLatest) => { const account = `@${instance.account.acct}@${instance.uri}` @@ -48,23 +86,32 @@ export const setChannels = async (instance: InstanceLatest) => { await Notifications.setNotificationChannelGroupAsync(account, { name: account }) } + const checkFeature = (feature: string) => + features + .filter(f => f.feature === feature) + .filter(f => parseFloat(instance.version) >= f.version)?.length > 0 + const checkFeatures = { + hasTypeStatus: checkFeature('notification_type_status'), + hasTypeUpdate: checkFeature('notification_type_update'), + hasTypeAdminSignup: checkFeature('notification_type_admin_signup'), + hasTypeAdminReport: checkFeature('notification_type_admin_report') + } + if (!instance.push.decode) { await setChannel('default') - for (const push of PUSH_DEFAULT) { + for (const push of PUSH_DEFAULT(checkFeatures)) { await deleteChannel(push) } - for (const { type } of PUSH_ADMIN) { + for (const { type } of PUSH_ADMIN(checkFeatures, profileQuery.role?.permissions)) { await deleteChannel(type) } } else { await deleteChannel('default') - for (const push of PUSH_DEFAULT) { + for (const push of PUSH_DEFAULT(checkFeatures)) { await setChannel(push) } - for (const { type, permission } of PUSH_ADMIN) { - if (checkPermission(permission, profileQuery.role?.permissions)) { - await setChannel(type) - } + for (const { type } of PUSH_ADMIN(checkFeatures, profileQuery.role?.permissions)) { + await setChannel(type) } } } From e09e2da1b779c3742d1c132494d170af6388b6b0 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Thu, 15 Dec 2022 22:14:59 +0100 Subject: [PATCH 04/22] Bump up packages --- ios/Podfile.lock | 16 +- package.json | 17 +- src/components/GracefullyImage.tsx | 31 +--- src/screens/ImagesViewer.tsx | 30 ++-- yarn.lock | 255 ++++++++++++++--------------- 5 files changed, 159 insertions(+), 190 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 0b15ae60..1ad566ac 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -303,8 +303,6 @@ PODS: - React-Core - react-native-language-detection (0.2.2): - React - - react-native-live-text-image-view (0.4.0): - - React-Core - react-native-menu (0.7.2): - React - react-native-netinfo (9.3.7): @@ -428,9 +426,9 @@ PODS: - RNScreens (3.18.2): - React-Core - React-RCTImage - - RNSentry (4.11.0): + - RNSentry (4.12.0): - React-Core - - Sentry/HybridSDK (= 7.31.2) + - Sentry/HybridSDK (= 7.31.3) - RNShareMenu (6.0.0): - React - RNSVG (13.6.0): @@ -441,7 +439,7 @@ PODS: - SDWebImageWebPCoder (0.9.1): - libwebp (~> 1.0) - SDWebImage/Core (~> 5.13) - - Sentry/HybridSDK (7.31.2) + - Sentry/HybridSDK (7.31.3) - Swime (3.0.6) - Yoga (1.14.0) @@ -495,7 +493,6 @@ DEPENDENCIES: - react-native-image-picker (from `../node_modules/react-native-image-picker`) - react-native-ios-context-menu (from `../node_modules/react-native-ios-context-menu`) - react-native-language-detection (from `../node_modules/react-native-language-detection`) - - react-native-live-text-image-view (from `../node_modules/react-native-live-text-image-view`) - "react-native-menu (from `../node_modules/@react-native-menu/menu`)" - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)" - react-native-pager-view (from `../node_modules/react-native-pager-view`) @@ -630,8 +627,6 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-ios-context-menu" react-native-language-detection: :path: "../node_modules/react-native-language-detection" - react-native-live-text-image-view: - :path: "../node_modules/react-native-live-text-image-view" react-native-menu: :path: "../node_modules/@react-native-menu/menu" react-native-netinfo: @@ -740,7 +735,6 @@ SPEC CHECKSUMS: react-native-image-picker: bf34f3f516d139ed3e24c5f5a381a91819e349ea react-native-ios-context-menu: b170594b4448c0cd10c79e13432216bac99de1ac react-native-language-detection: f414937fa715108ab50a6269a3de0bcb95e4ceb0 - react-native-live-text-image-view: 483bacfdba464162b8cf176bba555364f18b584c react-native-menu: 8e172cfcf0e42e92f028e7781eddf84d430cae24 react-native-netinfo: 2517ad504b3d303e90d7a431b0fcaef76d207983 react-native-pager-view: 54bed894cecebe28cede54c01038d9d1e122de43 @@ -765,12 +759,12 @@ SPEC CHECKSUMS: RNGestureHandler: 62232ba8f562f7dea5ba1b3383494eb5bf97a4d3 RNReanimated: ce445c233a6ff5600223484a88ad5704945d972a RNScreens: 34cc502acf1b916c582c60003dc3089fa01dc66d - RNSentry: f052387ebe939949c74c2cae0c850e76f6d14ddb + RNSentry: 4c09f4dd9740cb9b33e94303de5b6d0dbeb0737d RNShareMenu: cb9dac548c8bf147d06f0bf07296ad51ea9f5fc3 RNSVG: 3a79c0c4992213e4f06c08e62730c5e7b9e4dc17 SDWebImage: b9a731e1d6307f44ca703b3976d18c24ca561e84 SDWebImageWebPCoder: 18503de6621dd2c420d680e33d46bf8e1d5169b0 - Sentry: b15765d11769852fe78c9add942f7df60ed5dbf5 + Sentry: 08884c523575ec0f6690d94ed3ccb0246a1600bf Swime: d7b2c277503b6cea317774aedc2dce05613f8b0b Yoga: 99caf8d5ab45e9d637ee6e0174ec16fbbb01bcfc diff --git a/package.json b/package.json index 7ca20343..b10cfe1c 100644 --- a/package.json +++ b/package.json @@ -34,14 +34,14 @@ "@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.5.0", - "@react-navigation/native": "^6.1.0", - "@react-navigation/native-stack": "^6.9.5", - "@react-navigation/stack": "^6.3.8", + "@react-navigation/bottom-tabs": "^6.5.1", + "@react-navigation/native": "^6.1.1", + "@react-navigation/native-stack": "^6.9.6", + "@react-navigation/stack": "^6.3.9", "@reduxjs/toolkit": "^1.9.1", - "@sentry/react-native": "4.11.0", + "@sentry/react-native": "4.12.0", "@sharcoux/slider": "^6.1.1", - "@tanstack/react-query": "^4.19.1", + "@tanstack/react-query": "^4.20.4", "axios": "^1.2.1", "diff": "^5.1.0", "expo": "^47.0.8", @@ -61,7 +61,7 @@ "expo-store-review": "^6.0.0", "expo-video-thumbnails": "^7.0.0", "expo-web-browser": "~12.0.0", - "i18next": "^22.4.1", + "i18next": "^22.4.5", "linkify-it": "^4.0.1", "lodash": "^4.17.21", "react": "^18.2.0", @@ -80,7 +80,6 @@ "react-native-image-picker": "^4.10.2", "react-native-ios-context-menu": "^1.15.1", "react-native-language-detection": "^0.2.2", - "react-native-live-text-image-view": "^0.4.0", "react-native-pager-view": "^6.1.2", "react-native-reanimated": "^2.13.0", "react-native-reanimated-zoom": "^0.3.3", @@ -89,7 +88,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.3", + "react-native-tab-view": "^3.3.4", "react-redux": "^8.0.5", "redux-persist": "^6.0.0", "rn-placeholder": "^3.0.3", diff --git a/src/components/GracefullyImage.tsx b/src/components/GracefullyImage.tsx index 5afcbff6..f4c393e7 100644 --- a/src/components/GracefullyImage.tsx +++ b/src/components/GracefullyImage.tsx @@ -4,15 +4,13 @@ import React, { useMemo, useState } from 'react' import { AccessibilityProps, Image, - ImageStyle, - Platform, Pressable, StyleProp, StyleSheet, View, ViewStyle } from 'react-native' -import FastImage from 'react-native-fast-image' +import FastImage, { ImageStyle } from 'react-native-fast-image' import { Blurhash } from 'react-native-blurhash' // blurhas -> if blurhash, show before any loading succeed @@ -97,30 +95,17 @@ const GracefullyImage = ({ {...(onPress ? (hidden ? { disabled: true } : { onPress }) : { disabled: true })} > {uri.preview && !imageLoaded ? ( - ) : null} - {Platform.OS === 'ios' ? ( - - ) : ( - - )} + {blurhashView} ) diff --git a/src/screens/ImagesViewer.tsx b/src/screens/ImagesViewer.tsx index d5355b34..85a9a0b7 100644 --- a/src/screens/ImagesViewer.tsx +++ b/src/screens/ImagesViewer.tsx @@ -16,7 +16,6 @@ import { ViewToken } from 'react-native' import { Directions, Gesture, LongPressGestureHandler } from 'react-native-gesture-handler' -import { LiveTextImageView } from 'react-native-live-text-image-view' import { runOnJS, useSharedValue } from 'react-native-reanimated' import { Zoom, createZoomListComponent } from 'react-native-reanimated-zoom' import { useSafeAreaInsets } from 'react-native-safe-area-context' @@ -117,22 +116,19 @@ const ScreenImagesViewer = ({ justifyContent: 'center' }} > - - imageRatio - ? (SCREEN_HEIGHT / imageHeight) * imageWidth - : SCREEN_WIDTH, - height: - screenRatio > imageRatio - ? SCREEN_HEIGHT - : (SCREEN_WIDTH / imageWidth) * imageHeight - }} - /> - + imageRatio + ? (SCREEN_HEIGHT / imageHeight) * imageWidth + : SCREEN_WIDTH, + height: + screenRatio > imageRatio + ? SCREEN_HEIGHT + : (SCREEN_WIDTH / imageWidth) * imageHeight + }} + /> } /> diff --git a/yarn.lock b/yarn.lock index 7e9c2df6..365093e4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2404,63 +2404,63 @@ resolved "https://registry.yarnpkg.com/@react-native/polyfills/-/polyfills-2.0.0.tgz#4c40b74655c83982c8cf47530ee7dc13d957b6aa" integrity sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ== -"@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== +"@react-navigation/bottom-tabs@^6.5.1": + version "6.5.1" + resolved "https://registry.yarnpkg.com/@react-navigation/bottom-tabs/-/bottom-tabs-6.5.1.tgz#ef146502674e68736cbb47500ba1e3e481456869" + integrity sha512-XhY3rdfI/lxiG/TfdxvYYKSJR6N6K42VEBBQX8yvGBq+7aeCKaX5D7MF6yiI6ViVZ8uPhGyh/MJM3srUW+Yj7w== dependencies: - "@react-navigation/elements" "^1.3.10" + "@react-navigation/elements" "^1.3.11" color "^4.2.3" warn-once "^0.1.0" -"@react-navigation/core@^6.4.4": - version "6.4.4" - resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-6.4.4.tgz#270ef88d3c3a225f9a58bbe89eb8a8bc96af44a9" - integrity sha512-skdTzr6sOceEusEDG+e58zaSpgy1Yz7eZGFtmkmdYAFkZDy5nkIY/0nYuXP0waUYarNXg6lNEVkF995/kZXHZg== +"@react-navigation/core@^6.4.5": + version "6.4.5" + resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-6.4.5.tgz#8254b25c476857d53a649af8e3fded0cbe6e1ded" + integrity sha512-wcde35HeOM5r2P25EwLQZyJ1yhXDGKuWpnKfsSI1xrgYIvWdYi3j/yGnwgNGDelCmtUt1Fyk2pmOv8sEku9KkA== dependencies: - "@react-navigation/routers" "^6.1.5" + "@react-navigation/routers" "^6.1.6" escape-string-regexp "^4.0.0" nanoid "^3.1.23" query-string "^7.1.3" react-is "^16.13.0" use-latest-callback "^0.1.5" -"@react-navigation/elements@^1.3.10": - version "1.3.10" - 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/elements@^1.3.11": + version "1.3.11" + resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-1.3.11.tgz#135c2cb3ae4a31bc835bb731110fd1ef9c38e237" + integrity sha512-o4J0g4ofJbbn68e4TpuGkuZLtq5mLll7Ndz9C4O4RvD2chchLuGQ5TycIPTKP428cz8JzuTCFqUe/ZhOPSsudw== -"@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== +"@react-navigation/native-stack@^6.9.6": + version "6.9.6" + resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-6.9.6.tgz#d88cc332f19415fa2c57b8f2b9a6fc2cabf9733e" + integrity sha512-Puqo5Y7MwYZvGELN73nMzaWTMdJu58stp9M809h4eoi4SzS0u/mFtypquEcW1gXdmRlDMmqXTtR/NBPSc2kLJg== dependencies: - "@react-navigation/elements" "^1.3.10" + "@react-navigation/elements" "^1.3.11" warn-once "^0.1.0" -"@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== +"@react-navigation/native@^6.1.1": + version "6.1.1" + resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-6.1.1.tgz#79d91db04fbad277f355a10405516df4f67cd308" + integrity sha512-iIozx9c66EjSFyzKrZPixnk6vBuivYXp0jmbKCJXNIa7MY+8OLx9CXj/+1py/l/OGlXDhI6jiUWWetOfOtMaBQ== dependencies: - "@react-navigation/core" "^6.4.4" + "@react-navigation/core" "^6.4.5" escape-string-regexp "^4.0.0" fast-deep-equal "^3.1.3" nanoid "^3.1.23" -"@react-navigation/routers@^6.1.5": - version "6.1.5" - resolved "https://registry.yarnpkg.com/@react-navigation/routers/-/routers-6.1.5.tgz#b3e06bc09346ad94206bcc71c46538d5b6dc4883" - integrity sha512-JzMRiRRu8J0yUMC7BV8wOVzevjkHnIPONbpCTL/vH5yceTm+dSH/U3esIObgk8wYYbov+jYlVhwUQNGRb2to6g== +"@react-navigation/routers@^6.1.6": + version "6.1.6" + resolved "https://registry.yarnpkg.com/@react-navigation/routers/-/routers-6.1.6.tgz#f57f2a73855d329255aa225fdad75ae8e7700c6d" + integrity sha512-Z5DeCW3pUvMafbU9Cjy1qJYC2Bvl8iy3+PfsB0DsAwQ6zZ3WAXW5FTMX4Gb9H+Jg6qHWGbMFFwlYpS3UJ3tlVQ== dependencies: nanoid "^3.1.23" -"@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== +"@react-navigation/stack@^6.3.9": + version "6.3.9" + resolved "https://registry.yarnpkg.com/@react-navigation/stack/-/stack-6.3.9.tgz#e4e2b6aa25973b3bc59200b7e3bf980e93cb5b4f" + integrity sha512-mTT0ZM/Zvp46s8UnphAspg2MR5Ds0mqZa/bEjzFgaYo+cLfjIXttUZYgsMG2fhvoTHpU7QFcZ/0kVhi4jVlzKQ== dependencies: - "@react-navigation/elements" "^1.3.10" + "@react-navigation/elements" "^1.3.11" color "^4.2.3" warn-once "^0.1.0" @@ -2482,14 +2482,14 @@ component-type "^1.2.1" join-component "^1.1.0" -"@sentry/browser@7.21.1": - version "7.21.1" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.21.1.tgz#bffa3ea19050c06400107d2297b9802f9719f98b" - integrity sha512-cS2Jz2+fs9+4pJqLJPtYqGyY97ywJDWAWIR1Yla3hs1QQuH6m0Nz3ojZD1gE2eKH9mHwkGbnNAh+hHcrYrfGzw== +"@sentry/browser@7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.26.0.tgz#152d0f59df85be3ed8a7161b0ca90a4dca7b382d" + integrity sha512-S6uW+Ni2VLGHUV9eAUtTy5QEvqKeOhcnWnv+2yTGDtQCJ0SuHfXRCM7ASAQYBiKffZqIFc9Z2XNU/2cuWcXJmw== dependencies: - "@sentry/core" "7.21.1" - "@sentry/types" "7.21.1" - "@sentry/utils" "7.21.1" + "@sentry/core" "7.26.0" + "@sentry/types" "7.26.0" + "@sentry/utils" "7.26.0" tslib "^1.9.3" "@sentry/cli@1.74.4": @@ -2518,83 +2518,83 @@ proxy-from-env "^1.1.0" which "^2.0.2" -"@sentry/core@7.21.1": - version "7.21.1" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.21.1.tgz#d0423282d90875625802dfe380f9657e9242b72b" - integrity sha512-Og5wEEsy24fNvT/T7IKjcV4EvVK5ryY2kxbJzKY6GU2eX+i+aBl+n/vp7U0Es351C/AlTkS+0NOUsp2TQQFxZA== +"@sentry/core@7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.26.0.tgz#8f9fa439b40560edd09b464292d3084e1f16228f" + integrity sha512-ydi236ZoP/xpvLdf7B8seKjCcGc5Z+q9c14tHCFusplPZgLSXcYpiiLIDWmF7OAXO89sSbb1NaFt9YB0LkYdLQ== dependencies: - "@sentry/types" "7.21.1" - "@sentry/utils" "7.21.1" + "@sentry/types" "7.26.0" + "@sentry/utils" "7.26.0" tslib "^1.9.3" -"@sentry/hub@7.21.1": - version "7.21.1" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-7.21.1.tgz#5c046fd2ca7eaf14cd0bf70617cc8b057f9b88ce" - integrity sha512-WXQJ5z5iUZO6sOq3f7A3eIwvb/GoVJ3q5DQDTNF7HB/qcm11u5QPlAHTFBCsKJdT39NaE78JcMluiHZUWT+C5A== +"@sentry/hub@7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-7.26.0.tgz#a8d04c37384263439764f896ea0acbcf790dc521" + integrity sha512-djAMuA4/Jy28dOSy9z5ccXBDyYk1N9m0ljle+dKqjfJwv440tCGyoxm2arqJFHbXvqwJTt2Giv8ASR4uGD1UNg== dependencies: - "@sentry/core" "7.21.1" - "@sentry/types" "7.21.1" - "@sentry/utils" "7.21.1" + "@sentry/core" "7.26.0" + "@sentry/types" "7.26.0" + "@sentry/utils" "7.26.0" tslib "^1.9.3" -"@sentry/integrations@7.21.1": - version "7.21.1" - resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.21.1.tgz#8a5d5595521c4891cc2582f98d253a074ba54abc" - integrity sha512-DbQZSdsqaD9RTy5WvLzonoJa2CIgeapnGfFOadnQGOD8A8GT9Bre/BgcQ5ksHqGnVfzYwpU26k/ue9gjXnI/Pg== +"@sentry/integrations@7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.26.0.tgz#958e3ed52a37a14c6f11aebf11b485eca52e56aa" + integrity sha512-5tyBA5BnZEuosSIvBP7mJz66xJaZTb/k1EzHEc0hR2Mw8QpLgMneDZBfi4vdbhxtGpJKC/gURoUGZf9hpwW+DA== dependencies: - "@sentry/types" "7.21.1" - "@sentry/utils" "7.21.1" + "@sentry/types" "7.26.0" + "@sentry/utils" "7.26.0" localforage "^1.8.1" tslib "^1.9.3" -"@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== +"@sentry/react-native@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@sentry/react-native/-/react-native-4.12.0.tgz#3eff5eb0d03e5abdf24b74a5d5221d4416ef97cf" + integrity sha512-KBRXXqqGg67oqhtGzZQ8Ls4rxxUozDyL8tMLmRLk//bkSWBC6XslyjkZkQrB1VZsv2ikEYCUgyAP7fzcj6Bbig== dependencies: - "@sentry/browser" "7.21.1" + "@sentry/browser" "7.26.0" "@sentry/cli" "1.74.4" - "@sentry/core" "7.21.1" - "@sentry/hub" "7.21.1" - "@sentry/integrations" "7.21.1" - "@sentry/react" "7.21.1" - "@sentry/tracing" "7.21.1" - "@sentry/types" "7.21.1" - "@sentry/utils" "7.21.1" + "@sentry/core" "7.26.0" + "@sentry/hub" "7.26.0" + "@sentry/integrations" "7.26.0" + "@sentry/react" "7.26.0" + "@sentry/tracing" "7.26.0" + "@sentry/types" "7.26.0" + "@sentry/utils" "7.26.0" "@sentry/wizard" "1.4.0" -"@sentry/react@7.21.1": - version "7.21.1" - resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.21.1.tgz#275e6fd46212f608f382c7dde46d21e748f93491" - integrity sha512-w91PIUyX07mErKgrBQA+7ID8zFKrYDUYSOrFSHufg5DdPq4EpHiNDe/Yngg3e9ELhtr1AbCnEvx9wlvqLi3nZQ== +"@sentry/react@7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.26.0.tgz#548e1d29083d0e4732f2828d8cb8f9d0a150ae4e" + integrity sha512-v5XKpG1PF4qnWvG8E0N1kcUk74lTp+TDfKx5x996NIja2oOTp/JL9V0Q+lAMlB1EKgJuxLe92IeqD5/DTtzE7A== dependencies: - "@sentry/browser" "7.21.1" - "@sentry/types" "7.21.1" - "@sentry/utils" "7.21.1" + "@sentry/browser" "7.26.0" + "@sentry/types" "7.26.0" + "@sentry/utils" "7.26.0" hoist-non-react-statics "^3.3.2" tslib "^1.9.3" -"@sentry/tracing@7.21.1": - version "7.21.1" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-7.21.1.tgz#db02643e84960f1ea14b35fe75a93fc0bbca1fcb" - integrity sha512-b1BTPsRaNQpohzegoz59KGuBl+To651vEq0vMS4tCzSyIdxkYso3JCrjDdEqW/2MliQYANNVrUai2bmwmU9h1g== +"@sentry/tracing@7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-7.26.0.tgz#25105f8aec64a0e7113e09674d300190378b1daa" + integrity sha512-UK8EiXxJrDTWD82Oasj2WP/QuQ+wzPlg74vYmxl1ie/LRs6C6wHkilBZwDV9HnDdqAqSjl0al8oBa075lK+U3Q== dependencies: - "@sentry/core" "7.21.1" - "@sentry/types" "7.21.1" - "@sentry/utils" "7.21.1" + "@sentry/core" "7.26.0" + "@sentry/types" "7.26.0" + "@sentry/utils" "7.26.0" tslib "^1.9.3" -"@sentry/types@7.21.1": - version "7.21.1" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.21.1.tgz#408a7b95a66ddc30c4359979594e03bee8f9fbdc" - integrity sha512-3/IKnd52Ol21amQvI+kz+WB76s8/LR5YvFJzMgIoI2S8d82smIr253zGijRXxHPEif8kMLX4Yt+36VzrLxg6+A== +"@sentry/types@7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.26.0.tgz#2fe8a38a143797abecbcd53175ebf8bf736e18de" + integrity sha512-U2s0q3ALwWFdHJBgn8nrG9bCTJZ3hAqL/I2Si4Mf0ZWnJ/KTJKbtyrputHr8wMbHvX0NZTJGTxFVUO46J+GBRA== -"@sentry/utils@7.21.1": - version "7.21.1" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.21.1.tgz#96582345178015fd32fe9159c25c44ccf2f99d2a" - integrity sha512-F0W0AAi8tgtTx6ApZRI2S9HbXEA9ENX1phTZgdNNWcMFm1BNbc21XEwLqwXBNjub5nlA6CE8xnjXRgdZKx4kzQ== +"@sentry/utils@7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.26.0.tgz#4b501064c5220947f210aa2d59e9b8bf60677502" + integrity sha512-nIC1PRyoMBi4QB7XNCWaPDqaQbPayMwAvUm6W3MC5bHPfVZmmFt+3sLZQKUD/E0NeQnJ3vTyPewPF/LfxLOE5A== dependencies: - "@sentry/types" "7.21.1" + "@sentry/types" "7.26.0" tslib "^1.9.3" "@sentry/wizard@1.4.0": @@ -2660,17 +2660,17 @@ dependencies: defer-to-connect "^2.0.0" -"@tanstack/query-core@4.19.1": - version "4.19.1" - resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.19.1.tgz#2e92d9e8a50884eb231c5beb4386e131ebe34306" - integrity sha512-Zp0aIose5C8skBzqbVFGk9HJsPtUhRVDVNWIqVzFbGQQgYSeLZMd3Sdb4+EnA5wl1J7X+bre2PJGnQg9x/zHOA== +"@tanstack/query-core@4.20.4": + version "4.20.4" + resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.20.4.tgz#1f7975a2db26a8bc2f382bad8a44cd422c846b17" + integrity sha512-lhLtGVNJDsJ/DyZXrLzekDEywQqRVykgBqTmkv0La32a/RleILXy6JMLBb7UmS3QCatg/F/0N9/5b0i5j6IKcA== -"@tanstack/react-query@^4.19.1": - version "4.19.1" - resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.19.1.tgz#43356dd537127e76d75f5a2769eb23dafd9a3690" - integrity sha512-5dvHvmc0vrWI03AJugzvKfirxCyCLe+qawrWFCXdu8t7dklIhJ7D5ZhgTypv7mMtIpdHPcECtCiT/+V74wCn2A== +"@tanstack/react-query@^4.20.4": + version "4.20.4" + resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.20.4.tgz#562b34fb919adea884eccaba2b5be50e8ba7fb16" + integrity sha512-SJRxx13k/csb9lXAJfycgVA1N/yU/h3bvRNWP0+aHMfMjmbyX82FdoAcckDBbOdEyAupvb0byelNHNeypCFSyA== dependencies: - "@tanstack/query-core" "4.19.1" + "@tanstack/query-core" "4.20.4" use-sync-external-store "^1.2.0" "@types/cacheable-request@^6.0.1": @@ -2771,9 +2771,9 @@ integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== "@types/node@*": - version "18.11.12" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.12.tgz#89e7f8aa8c88abf432f9bd594888144d7dba10aa" - integrity sha512-FgD3NtTAKvyMmD44T07zz2fEf+OKwutgBCEVM8GcvMGVGaDktiLNTDvPwC/LUe3PinMW+X6CuLOF2Ui1mAlSXg== + version "18.11.15" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.15.tgz#de0e1fbd2b22b962d45971431e2ae696643d3f5d" + integrity sha512-VkhBbVo2+2oozlkdHXLrb3zjsRkpdnaU2bXmX8Wgle3PUi569eLRaHGlgETQHR7lLL1w7GiG3h9SnePhxNDecw== "@types/prop-types@*": version "15.7.5" @@ -6369,9 +6369,9 @@ find-yarn-workspace-root@^2.0.0, find-yarn-workspace-root@~2.0.0: micromatch "^4.0.2" flow-parser@0.*: - version "0.195.1" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.195.1.tgz#1f4017afd46c7873ed8dd9505f5fe5f00e08dd6c" - integrity sha512-8U3yQ8dny+CIsAjnH1QqpNw1mxLmqyp+0Mz/uh+YIH7srDkfabebwtFSnGv2m8yB2ZEPBrPwFYHe1kHKr/KQuw== + version "0.196.0" + resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.196.0.tgz#d62f85e02792fe625509a11343a8611ff976facd" + integrity sha512-739keKrDa+/5wpGFirMVK04elYMBjnwX2VH0WneKm3zx4K60ic8acJ6Ya6BekuHKLHIuz36ZUOQuGSUjc8D21A== flow-parser@^0.121.0: version "0.121.0" @@ -6604,7 +6604,7 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3: +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A== @@ -7186,10 +7186,10 @@ https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1: agent-base "6" debug "4" -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== +i18next@^22.4.5: + version "22.4.5" + resolved "https://registry.yarnpkg.com/i18next/-/i18next-22.4.5.tgz#7324e4946c2facbe743ca25bca8980af05b0a109" + integrity sha512-Kc+Ow0guRetUq+kv02tj0Yof9zveROPBAmJ8UxxNODLVBRSwsM4iD0Gw3BEieOmkWemF6clU3K1fbnCuTqiN2Q== dependencies: "@babel/runtime" "^7.20.6" @@ -7348,11 +7348,11 @@ internal-ip@4.3.0, internal-ip@^4.3.0: ipaddr.js "^1.9.0" internal-slot@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" - integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + version "1.0.4" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.4.tgz#8551e7baf74a7a6ba5f749cfb16aa60722f0d6f3" + integrity sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ== dependencies: - get-intrinsic "^1.1.0" + get-intrinsic "^1.1.3" has "^1.0.3" side-channel "^1.0.4" @@ -9167,9 +9167,9 @@ node-releases@^1.1.61: integrity sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ== node-releases@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" - integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== + version "2.0.7" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.7.tgz#593edbc7c22860ee4d32d3933cfebdfab0c0e0e5" + integrity sha512-EJ3rzxL9pTWPjk5arA0s0dgXpnyiAbJDE6wHT62g7VsgrgQgmmZ+Ru++M1BFofncWja+Pnn3rEr3fieRySAdKQ== node-stream-zip@^1.9.1: version "1.15.0" @@ -10755,11 +10755,6 @@ react-native-language-detection@^0.2.2: resolved "https://registry.yarnpkg.com/react-native-language-detection/-/react-native-language-detection-0.2.2.tgz#4cc94177aa1c4575c4656f6d42456fa6c72ed5db" integrity sha512-6u1JBgr+UG/GX/xMmT4K8CaBlSep4XfM91jwUzRA/Y3bMCHDx7bNVxGQvqvzkmOchby9h66XD8F5Eo+kV01CAA== -react-native-live-text-image-view@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/react-native-live-text-image-view/-/react-native-live-text-image-view-0.4.0.tgz#d23d5850788609fd1448533213fc6c453c584761" - integrity sha512-PhVFE0YogSLrTlnHIxUWL80CrmbDvxk1JvLx4UHiRHRwLda4dV/e/9Q+Pyh7Vq7qwAPE6vGoN6sjbXNaj4WCew== - react-native-pager-view@^6.1.2: version "6.1.2" resolved "https://registry.yarnpkg.com/react-native-pager-view/-/react-native-pager-view-6.1.2.tgz#3522079b9a9d6634ca5e8d153bc0b4d660254552" @@ -10814,10 +10809,10 @@ 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.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== +react-native-tab-view@^3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-3.3.4.tgz#856d4527f3bbf05e2649302ec80abe9f2f004666" + integrity sha512-rceAYWpHa6knA7tsTnnjlcOxlCErR4F+yXQPpNm125IvYFyv09YRhE5uMU2IzyPIQ1CJvADCHurF3KySzVI+4Q== dependencies: use-latest-callback "^0.1.5" From 78dba4ae1aa4dc2c4c7d2f07b1aed750928208d0 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Fri, 16 Dec 2022 00:21:53 +0100 Subject: [PATCH 05/22] Pilot fix for #558 --- fastlane/metadata/en-US/release_notes.txt | 1 + fastlane/metadata/zh-Hans/release_notes.txt | 1 + src/components/Timeline/Default.tsx | 9 +- src/components/Timeline/Shared/Avatar.tsx | 8 +- src/components/Timeline/Shared/Context.tsx | 1 + src/screens/Tabs/Shared/Toot.tsx | 115 ++++++++++++++++++-- 6 files changed, 119 insertions(+), 16 deletions(-) diff --git a/fastlane/metadata/en-US/release_notes.txt b/fastlane/metadata/en-US/release_notes.txt index 6ea61e2c..cf45f9e4 100644 --- a/fastlane/metadata/en-US/release_notes.txt +++ b/fastlane/metadata/en-US/release_notes.txt @@ -6,5 +6,6 @@ Enjoy toooting! This version includes following improvements and fixes: - Allow hiding boosts and replies in home timeline - Support toot in RTL languages - Added notification for admins +- Pilot conversation hierarchy - Fix whole word filter matching - Fix tablet cannot delete toot drafts \ No newline at end of file diff --git a/fastlane/metadata/zh-Hans/release_notes.txt b/fastlane/metadata/zh-Hans/release_notes.txt index 4b29b0a7..95a80d31 100644 --- a/fastlane/metadata/zh-Hans/release_notes.txt +++ b/fastlane/metadata/zh-Hans/release_notes.txt @@ -6,5 +6,6 @@ toooting愉快!此版本包括以下改进和修复: - 关注列表可隐藏转嘟和回复 - 新增管理员推送通知 - 支持嘟文右到左文字 +- 测试显示对话层级 - 修复过滤整词功能 - 修复平板不能删除草稿 \ No newline at end of file diff --git a/src/components/Timeline/Default.tsx b/src/components/Timeline/Default.tsx index 446d138b..cb3a8f0d 100644 --- a/src/components/Timeline/Default.tsx +++ b/src/components/Timeline/Default.tsx @@ -34,6 +34,7 @@ export interface Props { highlighted?: boolean disableDetails?: boolean disableOnPress?: boolean + isConversation?: boolean } // When the poll is long @@ -43,7 +44,8 @@ const TimelineDefault: React.FC = ({ rootQueryKey, highlighted = false, disableDetails = false, - disableOnPress = false + disableOnPress = false, + isConversation = false }) => { const { colors } = useTheme() const navigation = useNavigation>() @@ -74,7 +76,7 @@ const TimelineDefault: React.FC = ({ ? StyleConstants.Spacing.Global.PagePadding / 1.5 : StyleConstants.Spacing.Global.PagePadding, backgroundColor: colors.backgroundDefault, - paddingBottom: disableDetails ? StyleConstants.Spacing.Global.PagePadding / 1.5 : 0, + paddingBottom: disableDetails ? StyleConstants.Spacing.Global.PagePadding / 1.5 : 0 } const main = () => ( <> @@ -140,7 +142,8 @@ const TimelineDefault: React.FC = ({ highlighted, inThread: queryKey?.[1].page === 'Toot', disableDetails, - disableOnPress + disableOnPress, + isConversation }} > {disableOnPress ? ( diff --git a/src/components/Timeline/Shared/Avatar.tsx b/src/components/Timeline/Shared/Avatar.tsx index d04cc92b..385b83af 100644 --- a/src/components/Timeline/Shared/Avatar.tsx +++ b/src/components/Timeline/Shared/Avatar.tsx @@ -12,7 +12,8 @@ export interface Props { } const TimelineAvatar: React.FC = ({ account }) => { - const { status, highlighted, disableDetails, disableOnPress } = useContext(StatusContext) + const { status, highlighted, disableDetails, disableOnPress, isConversation } = + useContext(StatusContext) const actualAccount = account || status?.account if (!actualAccount) return null @@ -34,7 +35,7 @@ const TimelineAvatar: React.FC = ({ account }) => { } uri={{ original: actualAccount.avatar, static: actualAccount.avatar_static }} dimension={ - disableDetails + disableDetails || isConversation ? { width: StyleConstants.Avatar.XS, height: StyleConstants.Avatar.XS @@ -47,7 +48,8 @@ const TimelineAvatar: React.FC = ({ account }) => { style={{ borderRadius: StyleConstants.Avatar.M, overflow: 'hidden', - marginRight: StyleConstants.Spacing.S + marginRight: StyleConstants.Spacing.S, + marginLeft: isConversation ? StyleConstants.Avatar.M - StyleConstants.Avatar.XS : undefined }} /> ) diff --git a/src/components/Timeline/Shared/Context.tsx b/src/components/Timeline/Shared/Context.tsx index 7a4db11e..f00668d1 100644 --- a/src/components/Timeline/Shared/Context.tsx +++ b/src/components/Timeline/Shared/Context.tsx @@ -19,6 +19,7 @@ type ContextType = { inThread?: boolean disableDetails?: boolean disableOnPress?: boolean + isConversation?: boolean } const StatusContext = createContext({} as ContextType) diff --git a/src/screens/Tabs/Shared/Toot.tsx b/src/screens/Tabs/Shared/Toot.tsx index 6421a350..91a93f1f 100644 --- a/src/screens/Tabs/Shared/Toot.tsx +++ b/src/screens/Tabs/Shared/Toot.tsx @@ -5,8 +5,10 @@ import { TabSharedStackScreenProps } from '@utils/navigation/navigators' import { QueryKeyTimeline } from '@utils/queryHooks/timeline' import React, { useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' -import { FlatList } from 'react-native' +import { FlatList, View } from 'react-native' import { InfiniteQueryObserver, useQueryClient } from '@tanstack/react-query' +import { StyleConstants } from '@utils/styles/constants' +import { useTheme } from '@utils/styles/ThemeManager' const TabSharedToot: React.FC> = ({ navigation, @@ -14,6 +16,7 @@ const TabSharedToot: React.FC> = ({ params: { toot, rootQueryKey } } }) => { + const { colors } = useTheme() const { t } = useTranslation('screenTabs') useEffect(() => { @@ -34,6 +37,10 @@ const TabSharedToot: React.FC> = ({ queryKey, enabled: false }) + + const replyLevels = useRef<{ id: string; level: number }[]>([]) + const data = useRef() + const highlightIndex = useRef(0) useEffect(() => { return observer.subscribe(result => { if (result.isSuccess) { @@ -46,6 +53,24 @@ const TabSharedToot: React.FC> = ({ navigation.goBack() return } + data.current = flattenData + highlightIndex.current = flattenData.findIndex(({ id }) => id === toot.id) + + for (const [index, status] of flattenData.entries()) { + if (status.id === toot.id) continue + if (status.in_reply_to_id === toot.id) continue + + if (!replyLevels.current.find(reply => reply.id === status.in_reply_to_id)) { + const prevLevel = + replyLevels.current.find(reply => reply.id === flattenData[index - 1].in_reply_to_id) + ?.level || 0 + replyLevels.current.push({ + id: status.in_reply_to_id, + level: prevLevel + 1 + }) + } + } + setItemsLength(flattenData.length) if (!scrolled.current) { scrolled.current = true @@ -68,7 +93,7 @@ const TabSharedToot: React.FC> = ({ } } }) - }, [scrolled.current]) + }, [scrolled.current, replyLevels.current]) return ( > = ({ queryKey={queryKey} queryOptions={{ staleTime: 0, refetchOnMount: true }} customProps={{ - renderItem: ({ item }) => ( - - ), + renderItem: ({ item, index }) => { + const levels = { + previous: + replyLevels.current.find( + reply => reply.id === data.current?.[index - 1]?.in_reply_to_id + )?.level || 0, + current: + replyLevels.current.find(reply => reply.id === item.in_reply_to_id)?.level || 0, + next: + replyLevels.current.find( + reply => reply.id === data.current?.[index + 1]?.in_reply_to_id + )?.level || 0 + } + + return ( + <> + + {Array.from(Array(levels.current)).map((_, i) => { + if (index < highlightIndex.current) return null + if ( + levels.previous + 1 === levels.current || + (levels.previous && levels.current && levels.previous === levels.current) + ) { + return ( + + ) + } else { + return null + } + })} + {Array.from(Array(levels.next)).map((_, i) => { + if (index < highlightIndex.current) return null + if ( + levels.current + 1 === levels.next || + (levels.current && levels.next && levels.current === levels.next) + ) { + return ( + i + 1 + ? StyleConstants.Spacing.Global.PagePadding + StyleConstants.Avatar.XS + : StyleConstants.Spacing.Global.PagePadding, + left: StyleConstants.Spacing.Global.PagePadding / 2 + 8 * i, + height: 200, + borderLeftColor: colors.border, + borderLeftWidth: 1 + }} + /> + ) + } else { + return null + } + })} + + ) + }, onScrollToIndexFailed: error => { const offset = error.averageItemLength * error.index flRef.current?.scrollToOffset({ offset }) From 063f9938823fb3aee9808db7090cff21103be47f Mon Sep 17 00:00:00 2001 From: xmflsct Date: Fri, 16 Dec 2022 00:25:13 +0100 Subject: [PATCH 06/22] New Crowdin updates (#557) * New translations tabs.json (German) * New translations tabs.json (Italian) * New translations tabs.json (Japanese) * New translations tabs.json (Korean) * New translations tabs.json (Chinese Simplified) * New translations tabs.json (Chinese Traditional) * New translations tabs.json (Vietnamese) * New translations tabs.json (Portuguese, Brazilian) * New translations tabs.json (French) * New translations tabs.json (Polish) * New translations tabs.json (Spanish) * New translations tabs.json (Swedish) * New translations tabs.json (Czech) * New translations tabs.json (Dutch) * New translations tabs.json (Catalan) * New translations tabs.json (Ukrainian) * New translations tabs.json (Polish) * New translations contextMenu.json (Polish) * New translations tabs.json (Chinese Traditional) * New translations tabs.json (Dutch) * New translations tabs.json (Ukrainian) * New translations tabs.json (Swedish) * New translations tabs.json (Vietnamese) * New translations tabs.json (German) * New translations tabs.json (Chinese Simplified) --- src/i18n/ca/screens/tabs.json | 3 +- src/i18n/cs/screens/tabs.json | 3 +- src/i18n/de/screens/tabs.json | 7 +++-- src/i18n/es/screens/tabs.json | 3 +- src/i18n/fr/screens/tabs.json | 3 +- src/i18n/it/screens/tabs.json | 3 +- src/i18n/ja/screens/tabs.json | 3 +- src/i18n/ko/screens/tabs.json | 3 +- src/i18n/nl/screens/tabs.json | 7 +++-- src/i18n/pl/components/contextMenu.json | 42 ++++++++++++------------- src/i18n/pl/screens/tabs.json | 7 +++-- src/i18n/pt_BR/screens/tabs.json | 3 +- src/i18n/sv/screens/tabs.json | 3 +- src/i18n/uk/screens/tabs.json | 3 +- src/i18n/vi/screens/tabs.json | 7 +++-- src/i18n/zh-Hans/screens/tabs.json | 3 +- src/i18n/zh-Hant/screens/tabs.json | 7 +++-- 17 files changed, 63 insertions(+), 47 deletions(-) diff --git a/src/i18n/ca/screens/tabs.json b/src/i18n/ca/screens/tabs.json index 063839e8..baa840c8 100644 --- a/src/i18n/ca/screens/tabs.json +++ b/src/i18n/ca/screens/tabs.json @@ -395,7 +395,8 @@ "statuses": { "reblogged_by": "{{count}} impulsats", "favourited_by": "{{count}} favorits" - } + }, + "resultIncomplete": "" } } } \ No newline at end of file diff --git a/src/i18n/cs/screens/tabs.json b/src/i18n/cs/screens/tabs.json index 7fd4a012..89dc4321 100644 --- a/src/i18n/cs/screens/tabs.json +++ b/src/i18n/cs/screens/tabs.json @@ -395,7 +395,8 @@ "statuses": { "reblogged_by": "", "favourited_by": "" - } + }, + "resultIncomplete": "" } } } \ No newline at end of file diff --git a/src/i18n/de/screens/tabs.json b/src/i18n/de/screens/tabs.json index ddc2bf9e..9225e3d9 100644 --- a/src/i18n/de/screens/tabs.json +++ b/src/i18n/de/screens/tabs.json @@ -3,8 +3,8 @@ "local": { "name": "Gefolgt", "options": { - "showBoosts": "", - "showReplies": "" + "showBoosts": "Boosts anzeigen", + "showReplies": "Antworten anzeigen" } }, "public": { @@ -395,7 +395,8 @@ "statuses": { "reblogged_by": "{{count}} mal geboosted", "favourited_by": "{{count}} mal geherzt" - } + }, + "resultIncomplete": "Ergebnisse einer Instanz sind unvollständig" } } } \ No newline at end of file diff --git a/src/i18n/es/screens/tabs.json b/src/i18n/es/screens/tabs.json index 687bbeb8..ddefffbe 100644 --- a/src/i18n/es/screens/tabs.json +++ b/src/i18n/es/screens/tabs.json @@ -395,7 +395,8 @@ "statuses": { "reblogged_by": "{{count}} impulsados", "favourited_by": "{{count}} favoritos" - } + }, + "resultIncomplete": "" } } } \ No newline at end of file diff --git a/src/i18n/fr/screens/tabs.json b/src/i18n/fr/screens/tabs.json index 29bc2d53..c0205c2b 100644 --- a/src/i18n/fr/screens/tabs.json +++ b/src/i18n/fr/screens/tabs.json @@ -395,7 +395,8 @@ "statuses": { "reblogged_by": "{{count}} boosté", "favourited_by": "{{count}} mis en favori" - } + }, + "resultIncomplete": "" } } } \ No newline at end of file diff --git a/src/i18n/it/screens/tabs.json b/src/i18n/it/screens/tabs.json index 7a69ec75..981af617 100644 --- a/src/i18n/it/screens/tabs.json +++ b/src/i18n/it/screens/tabs.json @@ -395,7 +395,8 @@ "statuses": { "reblogged_by": "{{count}} ricondivisioni", "favourited_by": "{{count}} apprezzamenti" - } + }, + "resultIncomplete": "" } } } \ No newline at end of file diff --git a/src/i18n/ja/screens/tabs.json b/src/i18n/ja/screens/tabs.json index 8cdf0b08..2df441a6 100644 --- a/src/i18n/ja/screens/tabs.json +++ b/src/i18n/ja/screens/tabs.json @@ -395,7 +395,8 @@ "statuses": { "reblogged_by": "{{count}} ブースト", "favourited_by": "{{count}} お気に入り" - } + }, + "resultIncomplete": "" } } } \ No newline at end of file diff --git a/src/i18n/ko/screens/tabs.json b/src/i18n/ko/screens/tabs.json index 4c0ac658..86708a64 100644 --- a/src/i18n/ko/screens/tabs.json +++ b/src/i18n/ko/screens/tabs.json @@ -395,7 +395,8 @@ "statuses": { "reblogged_by": "{{count}} 부스트", "favourited_by": "{{count}} 즐겨찾기" - } + }, + "resultIncomplete": "" } } } \ No newline at end of file diff --git a/src/i18n/nl/screens/tabs.json b/src/i18n/nl/screens/tabs.json index cd60cc59..4e80882c 100644 --- a/src/i18n/nl/screens/tabs.json +++ b/src/i18n/nl/screens/tabs.json @@ -3,8 +3,8 @@ "local": { "name": "Volgend", "options": { - "showBoosts": "", - "showReplies": "" + "showBoosts": "Boosts tonen", + "showReplies": "Reacties tonen" } }, "public": { @@ -395,7 +395,8 @@ "statuses": { "reblogged_by": "{{count}} boostten", "favourited_by": "{{count}} markeerden als favoriet" - } + }, + "resultIncomplete": "" } } } \ No newline at end of file diff --git a/src/i18n/pl/components/contextMenu.json b/src/i18n/pl/components/contextMenu.json index 5a921a57..69478c88 100644 --- a/src/i18n/pl/components/contextMenu.json +++ b/src/i18n/pl/components/contextMenu.json @@ -8,58 +8,58 @@ }, "inLists": "", "mute": { - "action_false": "", - "action_true": "" + "action_false": "Wycisz użytkownika", + "action_true": "Wyłącz wyciszenie" }, "block": { - "action_false": "", - "action_true": "" + "action_false": "Zablokuj użytkownika", + "action_true": "Odblokuj użytkownika" }, "reports": { "action": "Zgłoś i zablokuj" } }, "at": { - "direct": "", - "public": "" + "direct": "Bezpośrednia wiadomość", + "public": "Wiadomość publiczna" }, "copy": { - "action": "", - "succeed": "" + "action": "Skopiuj wpis", + "succeed": "Skopiowano" }, "instance": { "title": "", "block": { - "action": "", + "action": "Zablokuj instancję {{instance}}", "alert": { - "title": "", - "message": "", + "title": "Na pewno zablokować {{instance}}?", + "message": "Zazwyczaj wycisza się (albo blokuje) konkretnych użytkowników. \n\nGdy zablokujesz instancję, cała jej zawartość (włączając np. obserwujące Cię osoby, które do niej należą) zostanie usunięta!", "buttons": { - "confirm": "" + "confirm": "Na pewno?" } } } }, "share": { "status": { - "action": "" + "action": "Udostępnij wpis" }, "account": { - "action": "" + "action": "Udostępnij konto" } }, "status": { "title": "", "edit": { - "action": "" + "action": "Edytuj wpis" }, "delete": { - "action": "", + "action": "Usuń wpis", "alert": { - "title": "", - "message": "", + "title": "Na pewno usunąć?", + "message": "Wszystkie podbite i polubione wpisy zostaną wyczyszczone - wraz z odpowiedziami.", "buttons": { - "confirm": "" + "confirm": "Na pewno?" } } }, @@ -78,8 +78,8 @@ "action_true": "" }, "pin": { - "action_false": "", - "action_true": "" + "action_false": "Przypnij wpis", + "action_true": "Odepnij wpis" } } } \ No newline at end of file diff --git a/src/i18n/pl/screens/tabs.json b/src/i18n/pl/screens/tabs.json index 18f3e2b8..a6e930fe 100644 --- a/src/i18n/pl/screens/tabs.json +++ b/src/i18n/pl/screens/tabs.json @@ -3,8 +3,8 @@ "local": { "name": "", "options": { - "showBoosts": "", - "showReplies": "" + "showBoosts": "Pokaż podbicia", + "showReplies": "Pokaż odpowiedzi" } }, "public": { @@ -395,7 +395,8 @@ "statuses": { "reblogged_by": "", "favourited_by": "" - } + }, + "resultIncomplete": "" } } } \ No newline at end of file diff --git a/src/i18n/pt_BR/screens/tabs.json b/src/i18n/pt_BR/screens/tabs.json index 105fda29..cc1800a1 100644 --- a/src/i18n/pt_BR/screens/tabs.json +++ b/src/i18n/pt_BR/screens/tabs.json @@ -395,7 +395,8 @@ "statuses": { "reblogged_by": "{{count}} boostou", "favourited_by": "{{count}} favoritados" - } + }, + "resultIncomplete": "" } } } \ No newline at end of file diff --git a/src/i18n/sv/screens/tabs.json b/src/i18n/sv/screens/tabs.json index 3a890127..d7cad85a 100644 --- a/src/i18n/sv/screens/tabs.json +++ b/src/i18n/sv/screens/tabs.json @@ -395,7 +395,8 @@ "statuses": { "reblogged_by": "{{count}} boostade", "favourited_by": "{{count}} favoriter" - } + }, + "resultIncomplete": "Resultat från fjärrinstans är ofullständiga" } } } \ No newline at end of file diff --git a/src/i18n/uk/screens/tabs.json b/src/i18n/uk/screens/tabs.json index efba5d35..7ebf23e2 100644 --- a/src/i18n/uk/screens/tabs.json +++ b/src/i18n/uk/screens/tabs.json @@ -395,7 +395,8 @@ "statuses": { "reblogged_by": "{{count}} передмухів", "favourited_by": "{{count}} улюблених" - } + }, + "resultIncomplete": "Результати з віддаленого інстанса неповні" } } } \ No newline at end of file diff --git a/src/i18n/vi/screens/tabs.json b/src/i18n/vi/screens/tabs.json index 1f62cba9..342857ef 100644 --- a/src/i18n/vi/screens/tabs.json +++ b/src/i18n/vi/screens/tabs.json @@ -3,8 +3,8 @@ "local": { "name": "Đang theo dõi", "options": { - "showBoosts": "", - "showReplies": "" + "showBoosts": "Hiện lượt đăng lại", + "showReplies": "Hiện lượt trả lời" } }, "public": { @@ -395,7 +395,8 @@ "statuses": { "reblogged_by": "{{count}} đăng lại", "favourited_by": "{{count}} thích" - } + }, + "resultIncomplete": "Kết quả từ máy chủ khác luôn không đầy đủ" } } } \ No newline at end of file diff --git a/src/i18n/zh-Hans/screens/tabs.json b/src/i18n/zh-Hans/screens/tabs.json index c847678c..6f46a372 100644 --- a/src/i18n/zh-Hans/screens/tabs.json +++ b/src/i18n/zh-Hans/screens/tabs.json @@ -395,7 +395,8 @@ "statuses": { "reblogged_by": "{{count}} 人转嘟", "favourited_by": "{{count}} 人喜欢" - } + }, + "resultIncomplete": "来自远程实例的结果不完整" } } } \ No newline at end of file diff --git a/src/i18n/zh-Hant/screens/tabs.json b/src/i18n/zh-Hant/screens/tabs.json index c5a609d0..04f2cd86 100644 --- a/src/i18n/zh-Hant/screens/tabs.json +++ b/src/i18n/zh-Hant/screens/tabs.json @@ -3,8 +3,8 @@ "local": { "name": "跟隨中", "options": { - "showBoosts": "", - "showReplies": "" + "showBoosts": "顯示轉嘟", + "showReplies": "顯示回覆" } }, "public": { @@ -395,7 +395,8 @@ "statuses": { "reblogged_by": "{{count}} 人轉嘟", "favourited_by": "{{count}} 人喜歡" - } + }, + "resultIncomplete": "" } } } \ No newline at end of file From 3c178e9f82aaef49dbf28db0035ffbafd82b180b Mon Sep 17 00:00:00 2001 From: xmflsct Date: Fri, 16 Dec 2022 01:02:17 +0100 Subject: [PATCH 07/22] Update release_notes.txt --- fastlane/metadata/en-US/release_notes.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fastlane/metadata/en-US/release_notes.txt b/fastlane/metadata/en-US/release_notes.txt index cf45f9e4..f67b4080 100644 --- a/fastlane/metadata/en-US/release_notes.txt +++ b/fastlane/metadata/en-US/release_notes.txt @@ -1,5 +1,5 @@ Enjoy toooting! This version includes following improvements and fixes: -- Added 🇺🇦 Slava Ukraini +- Added Ukrainian (Slava Ukraini) - Automatic setting detected language when tooting - Remember public timeline type selection - Show diffing of edit history @@ -8,4 +8,4 @@ Enjoy toooting! This version includes following improvements and fixes: - Added notification for admins - Pilot conversation hierarchy - Fix whole word filter matching -- Fix tablet cannot delete toot drafts \ No newline at end of file +- Fix tablet cannot delete toot drafts From 41acc776ac382d8c8bb72f367f2719b5576bcb74 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Fri, 16 Dec 2022 01:02:51 +0100 Subject: [PATCH 08/22] Update release_notes.txt --- fastlane/metadata/zh-Hans/release_notes.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fastlane/metadata/zh-Hans/release_notes.txt b/fastlane/metadata/zh-Hans/release_notes.txt index 95a80d31..3866a80a 100644 --- a/fastlane/metadata/zh-Hans/release_notes.txt +++ b/fastlane/metadata/zh-Hans/release_notes.txt @@ -1,5 +1,5 @@ toooting愉快!此版本包括以下改进和修复: -- 增加 🇺🇦 Slava Ukraini +- 增加乌克兰语(Slava Ukraini) - 自动识别发嘟语言 - 记住上次公共时间轴选项 - 显示编辑历史的差异 @@ -8,4 +8,4 @@ toooting愉快!此版本包括以下改进和修复: - 支持嘟文右到左文字 - 测试显示对话层级 - 修复过滤整词功能 -- 修复平板不能删除草稿 \ No newline at end of file +- 修复平板不能删除草稿 From d3d2202caa70af8100f4a6e9c76189aec707f896 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Fri, 16 Dec 2022 10:11:09 +0100 Subject: [PATCH 09/22] Fixed #561 --- src/screens/Tabs/Shared/Toot.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/screens/Tabs/Shared/Toot.tsx b/src/screens/Tabs/Shared/Toot.tsx index 91a93f1f..a3ba3e89 100644 --- a/src/screens/Tabs/Shared/Toot.tsx +++ b/src/screens/Tabs/Shared/Toot.tsx @@ -118,7 +118,7 @@ const TabSharedToot: React.FC> = ({ return ( <> Date: Fri, 16 Dec 2022 10:35:31 +0100 Subject: [PATCH 10/22] Fix push --- README.md | 2 ++ src/components/openLink.ts | 1 - src/i18n/en/screens/tabs.json | 3 +++ src/utils/slices/instances/push/register.ts | 7 +++---- src/utils/slices/instances/updatePushAlert.ts | 7 +++---- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index b1bcf7e3..7d29999d 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,8 @@ Please **do not** create a pull request to update translation. tooot's translati [@janlindblom](https://github.com/janlindblom) for Swedish +[@ihoryan](https://crowdin.com/profile/ihoryan) for Ukrainian + [@duy@mas.to](https://mas.to/@duy) for Vietnamese translation [@jimmyorz](https://github.com/jimmyorz) for Traditional Chinese translation diff --git a/src/components/openLink.ts b/src/components/openLink.ts index 30425685..fc1dea57 100644 --- a/src/components/openLink.ts +++ b/src/components/openLink.ts @@ -17,7 +17,6 @@ const openLink = async (url: string, navigation?: any) => { const handleNavigation = (page: 'Tab-Shared-Toot' | 'Tab-Shared-Account', options: {}) => { if (navigation) { - // @ts-ignore navigation.push(page, options) } else { // @ts-ignore diff --git a/src/i18n/en/screens/tabs.json b/src/i18n/en/screens/tabs.json index 5d7d1f2d..d0f8d2e7 100644 --- a/src/i18n/en/screens/tabs.json +++ b/src/i18n/en/screens/tabs.json @@ -231,6 +231,9 @@ "status": { "heading": "Toot from subscribed users" }, + "update": { + "heading": "Reblog has been edited" + }, "admin.sign_up": { "heading": "Admin: sign up" }, diff --git a/src/utils/slices/instances/push/register.ts b/src/utils/slices/instances/push/register.ts index f6185a7a..93a339a8 100644 --- a/src/utils/slices/instances/push/register.ts +++ b/src/utils/slices/instances/push/register.ts @@ -62,10 +62,9 @@ const pushRegister = async ( 'BMn2PLpZrMefG981elzG6SB1EY9gU7QZwmtZ/a/J2vUeWG+zXgeskMPwHh4T/bxsD4l7/8QT94F57CbZqYRRfJo=' ) formData.append('subscription[keys][auth]', auth) - Object.keys(alerts).map(key => - // @ts-ignore - formData.append(`data[alerts][${key}]`, alerts[key].value.toString()) - ) + for (const [key, value] of Object.entries(alerts)) { + formData.append(`data[alerts][${key}]`, value.toString()) + } const res = await apiInstance({ method: 'post', diff --git a/src/utils/slices/instances/updatePushAlert.ts b/src/utils/slices/instances/updatePushAlert.ts index d4cbb0ee..60d8c864 100644 --- a/src/utils/slices/instances/updatePushAlert.ts +++ b/src/utils/slices/instances/updatePushAlert.ts @@ -10,10 +10,9 @@ export const updateInstancePushAlert = createAsyncThunk( alerts: InstanceLatest['push']['alerts'] }): Promise => { const formData = new FormData() - Object.keys(alerts).map(alert => - // @ts-ignore - formData.append(`data[alerts][${alert}]`, alerts[alert].value.toString()) - ) + for (const [key, value] of Object.entries(alerts)) { + formData.append(`data[alerts][${key}]`, value.toString()) + } await apiInstance({ method: 'put', From ac6de3ebf11f235b1fe4f3004c2573e12ecc7708 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Fri, 16 Dec 2022 10:47:17 +0100 Subject: [PATCH 11/22] New Crowdin updates (#562) * New translations timeline.json (Chinese Traditional) * New translations tabs.json (Chinese Traditional) * New translations tabs.json (German) * New translations tabs.json (Italian) * New translations tabs.json (Japanese) * New translations tabs.json (Korean) * New translations tabs.json (Chinese Simplified) * New translations tabs.json (Chinese Traditional) * New translations tabs.json (Vietnamese) * New translations tabs.json (Portuguese, Brazilian) * New translations tabs.json (French) * New translations tabs.json (Polish) * New translations tabs.json (Spanish) * New translations tabs.json (Swedish) * New translations tabs.json (Czech) * New translations tabs.json (Dutch) * New translations tabs.json (Catalan) * New translations tabs.json (Ukrainian) * New translations timeline.json (German) * New translations tabs.json (German) * New translations tabs.json (Italian) * New translations tabs.json (Japanese) * New translations tabs.json (Korean) * New translations tabs.json (Chinese Simplified) * New translations tabs.json (Chinese Traditional) * New translations tabs.json (Vietnamese) * New translations tabs.json (Portuguese, Brazilian) * New translations tabs.json (Spanish) * New translations tabs.json (Swedish) * New translations tabs.json (Dutch) * New translations tabs.json (Catalan) * New translations tabs.json (Ukrainian) --- src/i18n/ca/screens/tabs.json | 5 ++++- src/i18n/cs/screens/tabs.json | 3 +++ src/i18n/de/components/timeline.json | 2 +- src/i18n/de/screens/tabs.json | 3 +++ src/i18n/es/screens/tabs.json | 9 ++++++--- src/i18n/fr/screens/tabs.json | 3 +++ src/i18n/it/screens/tabs.json | 5 ++++- src/i18n/ja/screens/tabs.json | 3 +++ src/i18n/ko/screens/tabs.json | 7 +++++-- src/i18n/nl/screens/tabs.json | 5 ++++- src/i18n/pl/screens/tabs.json | 3 +++ src/i18n/pt_BR/screens/tabs.json | 5 ++++- src/i18n/sv/screens/tabs.json | 3 +++ src/i18n/uk/screens/tabs.json | 3 +++ src/i18n/vi/screens/tabs.json | 3 +++ src/i18n/zh-Hans/screens/tabs.json | 3 +++ src/i18n/zh-Hant/components/timeline.json | 6 +++--- src/i18n/zh-Hant/screens/tabs.json | 9 ++++++--- 18 files changed, 64 insertions(+), 16 deletions(-) diff --git a/src/i18n/ca/screens/tabs.json b/src/i18n/ca/screens/tabs.json index baa840c8..3b136f86 100644 --- a/src/i18n/ca/screens/tabs.json +++ b/src/i18n/ca/screens/tabs.json @@ -231,6 +231,9 @@ "status": { "heading": "Publicació d'usuaris subscrits" }, + "update": { + "heading": "L'impuls ha sigut editat" + }, "admin.sign_up": { "heading": "Administració: Registra" }, @@ -348,7 +351,7 @@ "notInLists": "Altres llistes" }, "attachments": { - "name": "" + "name": "Multimèdia de <0 /><1>" }, "hashtag": { "follow": "Segueix", diff --git a/src/i18n/cs/screens/tabs.json b/src/i18n/cs/screens/tabs.json index 89dc4321..0decff11 100644 --- a/src/i18n/cs/screens/tabs.json +++ b/src/i18n/cs/screens/tabs.json @@ -231,6 +231,9 @@ "status": { "heading": "" }, + "update": { + "heading": "" + }, "admin.sign_up": { "heading": "" }, diff --git a/src/i18n/de/components/timeline.json b/src/i18n/de/components/timeline.json index 703494bd..ed401308 100644 --- a/src/i18n/de/components/timeline.json +++ b/src/i18n/de/components/timeline.json @@ -55,7 +55,7 @@ "accessibilityLabel": "Lesezeichen hinzufügen", "function": "Lesezeichen setzen" }, - "openReport": "" + "openReport": "Meldung öffnen" }, "actionsUsers": { "reblogged_by": { diff --git a/src/i18n/de/screens/tabs.json b/src/i18n/de/screens/tabs.json index 9225e3d9..a650e306 100644 --- a/src/i18n/de/screens/tabs.json +++ b/src/i18n/de/screens/tabs.json @@ -231,6 +231,9 @@ "status": { "heading": "Toot eines abonnierten Nutzers" }, + "update": { + "heading": "Boost wurde bearbeitet" + }, "admin.sign_up": { "heading": "Admin: Registrierung" }, diff --git a/src/i18n/es/screens/tabs.json b/src/i18n/es/screens/tabs.json index ddefffbe..7022aa6d 100644 --- a/src/i18n/es/screens/tabs.json +++ b/src/i18n/es/screens/tabs.json @@ -3,8 +3,8 @@ "local": { "name": "Siguiendo", "options": { - "showBoosts": "", - "showReplies": "" + "showBoosts": "Mostrar retoots", + "showReplies": "Mostrar respuestas" } }, "public": { @@ -231,6 +231,9 @@ "status": { "heading": "Toot de usuarios suscritos" }, + "update": { + "heading": "El impulso ha sido editado" + }, "admin.sign_up": { "heading": "Administración: Registrarse" }, @@ -348,7 +351,7 @@ "notInLists": "Otras listas" }, "attachments": { - "name": "" + "name": "Multimedia de <0 /><1>" }, "hashtag": { "follow": "Seguir", diff --git a/src/i18n/fr/screens/tabs.json b/src/i18n/fr/screens/tabs.json index c0205c2b..5a207b26 100644 --- a/src/i18n/fr/screens/tabs.json +++ b/src/i18n/fr/screens/tabs.json @@ -231,6 +231,9 @@ "status": { "heading": "Pouet des utilisateurs inscrits" }, + "update": { + "heading": "" + }, "admin.sign_up": { "heading": "" }, diff --git a/src/i18n/it/screens/tabs.json b/src/i18n/it/screens/tabs.json index 981af617..d2b98efe 100644 --- a/src/i18n/it/screens/tabs.json +++ b/src/i18n/it/screens/tabs.json @@ -231,6 +231,9 @@ "status": { "heading": "Toot da utenti seguiti" }, + "update": { + "heading": "Il link è stato modificato" + }, "admin.sign_up": { "heading": "" }, @@ -348,7 +351,7 @@ "notInLists": "" }, "attachments": { - "name": "" + "name": "Media di <0 /><1>\"" }, "hashtag": { "follow": "Segui", diff --git a/src/i18n/ja/screens/tabs.json b/src/i18n/ja/screens/tabs.json index 2df441a6..c5aba370 100644 --- a/src/i18n/ja/screens/tabs.json +++ b/src/i18n/ja/screens/tabs.json @@ -231,6 +231,9 @@ "status": { "heading": "購読したユーザーのトゥート" }, + "update": { + "heading": "ブーストしたトゥートが編集されました" + }, "admin.sign_up": { "heading": "" }, diff --git a/src/i18n/ko/screens/tabs.json b/src/i18n/ko/screens/tabs.json index 86708a64..6132afc7 100644 --- a/src/i18n/ko/screens/tabs.json +++ b/src/i18n/ko/screens/tabs.json @@ -70,7 +70,7 @@ "name": "{{list}} 리스트의 사용자" }, "listAdd": { - "name": "" + "name": "목록 만들기" }, "listEdit": { "name": "리스트 상세 편집" @@ -231,6 +231,9 @@ "status": { "heading": "구독한 사용자의 툿" }, + "update": { + "heading": "부스트한 툿이 수정됨" + }, "admin.sign_up": { "heading": "" }, @@ -348,7 +351,7 @@ "notInLists": "다른 리스트" }, "attachments": { - "name": "" + "name": "<0 /><1>의 미디어" }, "hashtag": { "follow": "팔로우", diff --git a/src/i18n/nl/screens/tabs.json b/src/i18n/nl/screens/tabs.json index 4e80882c..218d6b52 100644 --- a/src/i18n/nl/screens/tabs.json +++ b/src/i18n/nl/screens/tabs.json @@ -231,6 +231,9 @@ "status": { "heading": "Toot van geabonneerde gebruikers" }, + "update": { + "heading": "De reblog is bewerkt" + }, "admin.sign_up": { "heading": "Admin: registreren" }, @@ -396,7 +399,7 @@ "reblogged_by": "{{count}} boostten", "favourited_by": "{{count}} markeerden als favoriet" }, - "resultIncomplete": "" + "resultIncomplete": "Resultaten van een externe instantie zijn onvolledig" } } } \ No newline at end of file diff --git a/src/i18n/pl/screens/tabs.json b/src/i18n/pl/screens/tabs.json index a6e930fe..5d450a79 100644 --- a/src/i18n/pl/screens/tabs.json +++ b/src/i18n/pl/screens/tabs.json @@ -231,6 +231,9 @@ "status": { "heading": "" }, + "update": { + "heading": "" + }, "admin.sign_up": { "heading": "" }, diff --git a/src/i18n/pt_BR/screens/tabs.json b/src/i18n/pt_BR/screens/tabs.json index cc1800a1..6cead637 100644 --- a/src/i18n/pt_BR/screens/tabs.json +++ b/src/i18n/pt_BR/screens/tabs.json @@ -231,6 +231,9 @@ "status": { "heading": "Toot de usuários inscritos" }, + "update": { + "heading": "Toot foi editado" + }, "admin.sign_up": { "heading": "" }, @@ -348,7 +351,7 @@ "notInLists": "" }, "attachments": { - "name": "" + "name": "<0 /><1>\"s mídia" }, "hashtag": { "follow": "Seguir", diff --git a/src/i18n/sv/screens/tabs.json b/src/i18n/sv/screens/tabs.json index d7cad85a..6febc9c1 100644 --- a/src/i18n/sv/screens/tabs.json +++ b/src/i18n/sv/screens/tabs.json @@ -231,6 +231,9 @@ "status": { "heading": "Inlägg från följda användare" }, + "update": { + "heading": "Boosten har redigerats" + }, "admin.sign_up": { "heading": "Admin: registrera dig" }, diff --git a/src/i18n/uk/screens/tabs.json b/src/i18n/uk/screens/tabs.json index 7ebf23e2..aafa1ffc 100644 --- a/src/i18n/uk/screens/tabs.json +++ b/src/i18n/uk/screens/tabs.json @@ -231,6 +231,9 @@ "status": { "heading": "Дмух від підписників" }, + "update": { + "heading": "Передмух був відредагований" + }, "admin.sign_up": { "heading": "Адмін: реєстрація" }, diff --git a/src/i18n/vi/screens/tabs.json b/src/i18n/vi/screens/tabs.json index 342857ef..16318833 100644 --- a/src/i18n/vi/screens/tabs.json +++ b/src/i18n/vi/screens/tabs.json @@ -231,6 +231,9 @@ "status": { "heading": "Tút từ người đã theo dõi" }, + "update": { + "heading": "Đăng lại đã được sửa" + }, "admin.sign_up": { "heading": "Admin: đăng ký" }, diff --git a/src/i18n/zh-Hans/screens/tabs.json b/src/i18n/zh-Hans/screens/tabs.json index 6f46a372..38d68b4c 100644 --- a/src/i18n/zh-Hans/screens/tabs.json +++ b/src/i18n/zh-Hans/screens/tabs.json @@ -231,6 +231,9 @@ "status": { "heading": "订阅用户的嘟文" }, + "update": { + "heading": "转嘟被编辑" + }, "admin.sign_up": { "heading": "管理员:用户注册" }, diff --git a/src/i18n/zh-Hant/components/timeline.json b/src/i18n/zh-Hant/components/timeline.json index f26ff232..fd803d67 100644 --- a/src/i18n/zh-Hant/components/timeline.json +++ b/src/i18n/zh-Hant/components/timeline.json @@ -31,8 +31,8 @@ "notification": "{{name}} 轉嘟了您的嘟文" }, "update": "轉嘟已編輯", - "admin.sign_up": "", - "admin.report": "" + "admin.sign_up": "{{name}} 加入了站點", + "admin.report": "{{name}} 檢舉:" }, "actions": { "reply": { @@ -55,7 +55,7 @@ "accessibilityLabel": "將嘟文加入書籤", "function": "加入書籤" }, - "openReport": "" + "openReport": "打開檢舉" }, "actionsUsers": { "reblogged_by": { diff --git a/src/i18n/zh-Hant/screens/tabs.json b/src/i18n/zh-Hant/screens/tabs.json index 04f2cd86..418f3268 100644 --- a/src/i18n/zh-Hant/screens/tabs.json +++ b/src/i18n/zh-Hant/screens/tabs.json @@ -231,11 +231,14 @@ "status": { "heading": "訂閱使用者的嘟文" }, + "update": { + "heading": "轉嘟被編輯" + }, "admin.sign_up": { - "heading": "管理員:註冊" + "heading": "管理員:使用者註冊" }, "admin.report": { - "heading": "管理員:回報" + "heading": "管理員:檢舉" }, "howitworks": "了解通知訊息轉發如何工作" }, @@ -396,7 +399,7 @@ "reblogged_by": "{{count}} 人轉嘟", "favourited_by": "{{count}} 人喜歡" }, - "resultIncomplete": "" + "resultIncomplete": "來自遠端站點的結果不完整" } } } \ No newline at end of file From 7b3fa6d1bc5a4af8001d167c03d862fa40bdf955 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Fri, 16 Dec 2022 13:14:55 +0100 Subject: [PATCH 12/22] Update Push.tsx --- src/screens/Tabs/Me/Push.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/screens/Tabs/Me/Push.tsx b/src/screens/Tabs/Me/Push.tsx index 7f76f70f..f5960526 100644 --- a/src/screens/Tabs/Me/Push.tsx +++ b/src/screens/Tabs/Me/Push.tsx @@ -168,7 +168,6 @@ const TabMePush: React.FC = () => { From 8b20e186de0c06467eec8dd2943c2ae2a2e7aa8b Mon Sep 17 00:00:00 2001 From: xmflsct Date: Fri, 16 Dec 2022 13:16:04 +0100 Subject: [PATCH 13/22] Update HeaderAndroid.tsx Fixed #563 --- src/components/Timeline/Shared/HeaderAndroid.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/Timeline/Shared/HeaderAndroid.tsx b/src/components/Timeline/Shared/HeaderAndroid.tsx index c0926e24..7d67db1d 100644 --- a/src/components/Timeline/Shared/HeaderAndroid.tsx +++ b/src/components/Timeline/Shared/HeaderAndroid.tsx @@ -36,7 +36,12 @@ const TimelineHeaderAndroid: React.FC = () => { {queryKey ? ( - + Date: Fri, 16 Dec 2022 17:00:07 +0100 Subject: [PATCH 14/22] Remove conversation levels for now as it doesn't work well yet --- fastlane/metadata/en-US/release_notes.txt | 1 - fastlane/metadata/zh-Hans/release_notes.txt | 1 - src/screens/Tabs/Shared/Toot.tsx | 165 ++++++++++---------- 3 files changed, 86 insertions(+), 81 deletions(-) diff --git a/fastlane/metadata/en-US/release_notes.txt b/fastlane/metadata/en-US/release_notes.txt index f67b4080..ca79b784 100644 --- a/fastlane/metadata/en-US/release_notes.txt +++ b/fastlane/metadata/en-US/release_notes.txt @@ -6,6 +6,5 @@ Enjoy toooting! This version includes following improvements and fixes: - Allow hiding boosts and replies in home timeline - Support toot in RTL languages - Added notification for admins -- Pilot conversation hierarchy - Fix whole word filter matching - Fix tablet cannot delete toot drafts diff --git a/fastlane/metadata/zh-Hans/release_notes.txt b/fastlane/metadata/zh-Hans/release_notes.txt index 3866a80a..35846c68 100644 --- a/fastlane/metadata/zh-Hans/release_notes.txt +++ b/fastlane/metadata/zh-Hans/release_notes.txt @@ -6,6 +6,5 @@ toooting愉快!此版本包括以下改进和修复: - 关注列表可隐藏转嘟和回复 - 新增管理员推送通知 - 支持嘟文右到左文字 -- 测试显示对话层级 - 修复过滤整词功能 - 修复平板不能删除草稿 diff --git a/src/screens/Tabs/Shared/Toot.tsx b/src/screens/Tabs/Shared/Toot.tsx index a3ba3e89..38d24107 100644 --- a/src/screens/Tabs/Shared/Toot.tsx +++ b/src/screens/Tabs/Shared/Toot.tsx @@ -5,10 +5,8 @@ import { TabSharedStackScreenProps } from '@utils/navigation/navigators' import { QueryKeyTimeline } from '@utils/queryHooks/timeline' import React, { useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' -import { FlatList, View } from 'react-native' +import { FlatList } from 'react-native' import { InfiniteQueryObserver, useQueryClient } from '@tanstack/react-query' -import { StyleConstants } from '@utils/styles/constants' -import { useTheme } from '@utils/styles/ThemeManager' const TabSharedToot: React.FC> = ({ navigation, @@ -16,7 +14,6 @@ const TabSharedToot: React.FC> = ({ params: { toot, rootQueryKey } } }) => { - const { colors } = useTheme() const { t } = useTranslation('screenTabs') useEffect(() => { @@ -101,84 +98,94 @@ const TabSharedToot: React.FC> = ({ queryKey={queryKey} queryOptions={{ staleTime: 0, refetchOnMount: true }} customProps={{ - renderItem: ({ item, index }) => { - const levels = { - previous: - replyLevels.current.find( - reply => reply.id === data.current?.[index - 1]?.in_reply_to_id - )?.level || 0, - current: - replyLevels.current.find(reply => reply.id === item.in_reply_to_id)?.level || 0, - next: - replyLevels.current.find( - reply => reply.id === data.current?.[index + 1]?.in_reply_to_id - )?.level || 0 - } - + renderItem: ({ item }) => { return ( - <> - - {Array.from(Array(levels.current)).map((_, i) => { - if (index < highlightIndex.current) return null - if ( - levels.previous + 1 === levels.current || - (levels.previous && levels.current && levels.previous === levels.current) - ) { - return ( - - ) - } else { - return null - } - })} - {Array.from(Array(levels.next)).map((_, i) => { - if (index < highlightIndex.current) return null - if ( - levels.current + 1 === levels.next || - (levels.current && levels.next && levels.current === levels.next) - ) { - return ( - i + 1 - ? StyleConstants.Spacing.Global.PagePadding + StyleConstants.Avatar.XS - : StyleConstants.Spacing.Global.PagePadding, - left: StyleConstants.Spacing.Global.PagePadding / 2 + 8 * i, - height: 200, - borderLeftColor: colors.border, - borderLeftWidth: 1 - }} - /> - ) - } else { - return null - } - })} - + ) }, + // renderItem: ({ item, index }) => { + // const levels = { + // previous: + // replyLevels.current.find( + // reply => reply.id === data.current?.[index - 1]?.in_reply_to_id + // )?.level || 0, + // current: + // replyLevels.current.find(reply => reply.id === item.in_reply_to_id)?.level || 0, + // next: + // replyLevels.current.find( + // reply => reply.id === data.current?.[index + 1]?.in_reply_to_id + // )?.level || 0 + // } + + // return ( + // <> + // + // {Array.from(Array(levels.current)).map((_, i) => { + // if (index < highlightIndex.current) return null + // if ( + // levels.previous + 1 === levels.current || + // (levels.previous && levels.current && levels.previous === levels.current) + // ) { + // return ( + // + // ) + // } else { + // return null + // } + // })} + // {Array.from(Array(levels.next)).map((_, i) => { + // if (index < highlightIndex.current) return null + // if ( + // levels.current + 1 === levels.next || + // (levels.current && levels.next && levels.current === levels.next) + // ) { + // return ( + // i + 1 + // ? StyleConstants.Spacing.Global.PagePadding + StyleConstants.Avatar.XS + // : StyleConstants.Spacing.Global.PagePadding, + // left: StyleConstants.Spacing.Global.PagePadding / 2 + 8 * i, + // height: 200, + // borderLeftColor: colors.border, + // borderLeftWidth: 1 + // }} + // /> + // ) + // } else { + // return null + // } + // })} + // + // ) + // }, onScrollToIndexFailed: error => { const offset = error.averageItemLength * error.index flRef.current?.scrollToOffset({ offset }) From 44aff1f283333055b34c9bcc38c828354f4a74af Mon Sep 17 00:00:00 2001 From: xmflsct Date: Fri, 16 Dec 2022 21:18:58 +0100 Subject: [PATCH 15/22] Fix push settings --- src/screens/Tabs/Me/Push.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/screens/Tabs/Me/Push.tsx b/src/screens/Tabs/Me/Push.tsx index f5960526..eebecc52 100644 --- a/src/screens/Tabs/Me/Push.tsx +++ b/src/screens/Tabs/Me/Push.tsx @@ -92,7 +92,7 @@ const TabMePush: React.FC = () => { updateInstancePushAlert({ alerts: { ...instancePush?.alerts, - [alert]: instancePush?.alerts[alert] + [alert]: !instancePush?.alerts[alert] } }) ) @@ -115,7 +115,7 @@ const TabMePush: React.FC = () => { updateInstancePushAlert({ alerts: { ...instancePush?.alerts, - [type]: instancePush?.alerts[type] + [type]: !instancePush?.alerts[type] } }) ) From 3691b19a870e1d14abef9470281acd35f9d72697 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Fri, 16 Dec 2022 22:00:22 +0100 Subject: [PATCH 16/22] Fix Sentry errors --- src/api/helpers/index.ts | 4 +- src/api/tooot.ts | 3 +- src/components/Instance/index.tsx | 4 +- src/components/Timeline/Default.tsx | 4 +- src/components/Timeline/Notifications.tsx | 4 +- src/components/Timeline/Shared/Attachment.tsx | 4 +- src/components/Timeline/Shared/Content.tsx | 2 +- .../Timeline/Shared/HeaderNotification.tsx | 2 +- .../Timeline/Shared/HeaderShared/Account.tsx | 55 +++++++++---------- src/components/contextMenu/account.ts | 2 +- src/components/openLink.ts | 2 +- src/helpers/browserPackage.ts | 16 +++--- src/screens/Compose/utils/parseState.ts | 5 +- src/screens/Tabs/Me/Push.tsx | 2 +- src/screens/Tabs/Me/Root/Settings.tsx | 2 +- src/screens/Tabs/Me/Settings/Tooot.tsx | 2 +- src/utils/migrations/instances/v11.ts | 2 +- src/utils/push/useConnect.ts | 38 ++++++++----- src/utils/slices/instancesSlice.ts | 6 +- 19 files changed, 85 insertions(+), 74 deletions(-) diff --git a/src/api/helpers/index.ts b/src/api/helpers/index.ts index 65013f79..566280af 100644 --- a/src/api/helpers/index.ts +++ b/src/api/helpers/index.ts @@ -54,12 +54,12 @@ const handleError = console.error(ctx.bold(' API '), ctx.bold('request'), error) shouldReportToSentry && Sentry.captureMessage(config.message) - return Promise.reject() + return Promise.reject(error) } else { console.error(ctx.bold(' API '), ctx.bold('internal'), error?.message) shouldReportToSentry && Sentry.captureMessage(config.message) - return Promise.reject() + return Promise.reject(error) } } diff --git a/src/api/tooot.ts b/src/api/tooot.ts index 7d96c622..0ebb5b57 100644 --- a/src/api/tooot.ts +++ b/src/api/tooot.ts @@ -1,4 +1,3 @@ -import * as Sentry from '@sentry/react-native' import { mapEnvironment } from '@utils/checkEnvironment' import axios from 'axios' import { ctx, handleError, userAgent } from './helpers' @@ -37,7 +36,7 @@ const apiTooot = async ({ ) return axios({ - timeout: method === 'post' ? 1000 * 60 : 1000 * 15, + timeout: method === 'post' ? 1000 * 60 : 1000 * 30, method, baseURL: `https://${TOOOT_API_DOMAIN}/`, url: `${url}`, diff --git a/src/components/Instance/index.tsx b/src/components/Instance/index.tsx index e21c49de..eb7fbddc 100644 --- a/src/components/Instance/index.tsx +++ b/src/components/Instance/index.tsx @@ -276,7 +276,7 @@ const ComponentInstance: React.FC = ({ style={{ color: colors.blue }} onPress={async () => WebBrowser.openBrowserAsync('https://tooot.app/privacy-policy', { - browserPackage: await browserPackage() + ...(await browserPackage()) }) } />, @@ -285,7 +285,7 @@ const ComponentInstance: React.FC = ({ style={{ color: colors.blue }} onPress={async () => WebBrowser.openBrowserAsync('https://tooot.app/terms-of-service', { - browserPackage: await browserPackage() + ...(await browserPackage()) }) } /> diff --git a/src/components/Timeline/Default.tsx b/src/components/Timeline/Default.tsx index cb3a8f0d..0284cf07 100644 --- a/src/components/Timeline/Default.tsx +++ b/src/components/Timeline/Default.tsx @@ -55,10 +55,10 @@ const TimelineDefault: React.FC = ({ const status = item.reblog ? item.reblog : item const ownAccount = status.account?.id === instanceAccount?.id const [spoilerExpanded, setSpoilerExpanded] = useState( - instanceAccount?.preferences['reading:expand:spoilers'] || false + instanceAccount?.preferences?.['reading:expand:spoilers'] || false ) const spoilerHidden = status.spoiler_text?.length - ? !instanceAccount?.preferences['reading:expand:spoilers'] && !spoilerExpanded + ? !instanceAccount?.preferences?.['reading:expand:spoilers'] && !spoilerExpanded : false const copiableContent = useRef<{ content: string; complete: boolean }>({ content: '', diff --git a/src/components/Timeline/Notifications.tsx b/src/components/Timeline/Notifications.tsx index 7eff27d1..81ee0d57 100644 --- a/src/components/Timeline/Notifications.tsx +++ b/src/components/Timeline/Notifications.tsx @@ -42,10 +42,10 @@ const TimelineNotifications: React.FC = ({ notification, queryKey }) => { : notification.account const ownAccount = notification.account?.id === instanceAccount?.id const [spoilerExpanded, setSpoilerExpanded] = useState( - instanceAccount.preferences['reading:expand:spoilers'] || false + instanceAccount.preferences?.['reading:expand:spoilers'] || false ) const spoilerHidden = notification.status?.spoiler_text?.length - ? !instanceAccount.preferences['reading:expand:spoilers'] && !spoilerExpanded + ? !instanceAccount.preferences?.['reading:expand:spoilers'] && !spoilerExpanded : false const copiableContent = useRef<{ content: string; complete: boolean }>({ content: '', diff --git a/src/components/Timeline/Shared/Attachment.tsx b/src/components/Timeline/Shared/Attachment.tsx index 174894cc..7f0128ed 100644 --- a/src/components/Timeline/Shared/Attachment.tsx +++ b/src/components/Timeline/Shared/Attachment.tsx @@ -31,10 +31,10 @@ const TimelineAttachment = () => { const account = useSelector( getInstanceAccount, (prev, next) => - prev.preferences['reading:expand:media'] === next.preferences['reading:expand:media'] + prev.preferences?.['reading:expand:media'] === next.preferences?.['reading:expand:media'] ) const defaultSensitive = () => { - switch (account.preferences['reading:expand:media']) { + switch (account.preferences?.['reading:expand:media']) { case 'show_all': return false case 'hide_all': diff --git a/src/components/Timeline/Shared/Content.tsx b/src/components/Timeline/Shared/Content.tsx index d7b799da..c1bc69a9 100644 --- a/src/components/Timeline/Shared/Content.tsx +++ b/src/components/Timeline/Shared/Content.tsx @@ -47,7 +47,7 @@ const TimelineContent: React.FC = ({ notificationOwnToot = false, setSpoi mentions={status.mentions} tags={status.tags} numberOfLines={ - instanceAccount.preferences['reading:expand:spoilers'] || inThread + instanceAccount.preferences?.['reading:expand:spoilers'] || inThread ? notificationOwnToot ? 2 : 999 diff --git a/src/components/Timeline/Shared/HeaderNotification.tsx b/src/components/Timeline/Shared/HeaderNotification.tsx index 7b93b702..02cdef2f 100644 --- a/src/components/Timeline/Shared/HeaderNotification.tsx +++ b/src/components/Timeline/Shared/HeaderNotification.tsx @@ -65,7 +65,7 @@ const TimelineHeaderNotification: React.FC = ({ notification }) => { `https://${url}/admin/reports/${notification.report.id}`, 'tooot://tooot', { - browserPackage: await browserPackage(), + ...(await browserPackage()), dismissButtonStyle: 'done', readerMode: false } diff --git a/src/components/Timeline/Shared/HeaderShared/Account.tsx b/src/components/Timeline/Shared/HeaderShared/Account.tsx index 991be557..57fda463 100644 --- a/src/components/Timeline/Shared/HeaderShared/Account.tsx +++ b/src/components/Timeline/Shared/HeaderShared/Account.tsx @@ -7,41 +7,40 @@ import { useTranslation } from 'react-i18next' import { View } from 'react-native' export interface Props { - account: Mastodon.Account + account?: Mastodon.Account withoutName?: boolean // For notification follow request etc. } -const HeaderSharedAccount = React.memo( - ({ account, withoutName = false }: Props) => { - const { t } = useTranslation('componentTimeline') - const { colors } = useTheme() +const HeaderSharedAccount: React.FC = ({ account, withoutName = false }) => { + if (!account) return null - return ( - - {withoutName ? null : ( - - - - )} + const { t } = useTranslation('componentTimeline') + const { colors } = useTheme() + + return ( + + {withoutName ? null : ( - @{account.acct} + - - ) - }, - () => true -) + )} + + @{account.acct} + + + ) +} export default HeaderSharedAccount diff --git a/src/components/contextMenu/account.ts b/src/components/contextMenu/account.ts index c85aa935..bc2137ea 100644 --- a/src/components/contextMenu/account.ts +++ b/src/components/contextMenu/account.ts @@ -41,7 +41,7 @@ const menuAccount = ({ const menus: ContextMenu[][] = [[]] - const instanceAccount = useSelector(getInstanceAccount, (prev, next) => prev.id === next.id) + const instanceAccount = useSelector(getInstanceAccount) const ownAccount = instanceAccount?.id === account.id const [enabled, setEnabled] = useState(openChange) diff --git a/src/components/openLink.ts b/src/components/openLink.ts index fc1dea57..4e566f7d 100644 --- a/src/components/openLink.ts +++ b/src/components/openLink.ts @@ -92,7 +92,7 @@ const openLink = async (url: string, navigation?: any) => { await WebBrowser.openBrowserAsync(encodeURI(url), { dismissButtonStyle: 'close', enableBarCollapsing: true, - browserPackage: await browserPackage() + ...(await browserPackage()) }) break case 'external': diff --git a/src/helpers/browserPackage.ts b/src/helpers/browserPackage.ts index b5e3a1b0..a2219053 100644 --- a/src/helpers/browserPackage.ts +++ b/src/helpers/browserPackage.ts @@ -1,16 +1,18 @@ import * as WebBrowser from 'expo-web-browser' import { Platform } from 'react-native' -const browserPackage = async () => { - let browserPackage: string | undefined +const browserPackage = async (): Promise<{ browserPackage?: string }> => { if (Platform.OS === 'android') { const tabsSupportingBrowsers = await WebBrowser.getCustomTabsSupportingBrowsersAsync() - browserPackage = - tabsSupportingBrowsers?.preferredBrowserPackage || - tabsSupportingBrowsers.browserPackages[0] || - tabsSupportingBrowsers.servicePackages[0] + return { + browserPackage: + tabsSupportingBrowsers?.preferredBrowserPackage || + tabsSupportingBrowsers.browserPackages[0] || + tabsSupportingBrowsers.servicePackages[0] + } + } else { + return {} } - return browserPackage } export default browserPackage diff --git a/src/screens/Compose/utils/parseState.ts b/src/screens/Compose/utils/parseState.ts index 811c3371..1f461f24 100644 --- a/src/screens/Compose/utils/parseState.ts +++ b/src/screens/Compose/utils/parseState.ts @@ -7,9 +7,8 @@ import { ComposeState } from './types' const assignVisibility = ( target: ComposeState['visibility'] ): Pick => { - const accountPreference = getInstanceAccount(store.getState())?.preferences[ - 'posting:default:visibility' - ] + const accountPreference = + getInstanceAccount(store.getState())?.preferences?.['posting:default:visibility'] || 'public' switch (target) { case 'direct': diff --git a/src/screens/Tabs/Me/Push.tsx b/src/screens/Tabs/Me/Push.tsx index eebecc52..04c56cac 100644 --- a/src/screens/Tabs/Me/Push.tsx +++ b/src/screens/Tabs/Me/Push.tsx @@ -179,7 +179,7 @@ const TabMePush: React.FC = () => { iconBack='ExternalLink' onPress={async () => WebBrowser.openBrowserAsync('https://tooot.app/how-push-works', { - browserPackage: await browserPackage() + ...(await browserPackage()) }) } /> diff --git a/src/screens/Tabs/Me/Root/Settings.tsx b/src/screens/Tabs/Me/Root/Settings.tsx index 6ea7d071..b9384e6f 100644 --- a/src/screens/Tabs/Me/Root/Settings.tsx +++ b/src/screens/Tabs/Me/Root/Settings.tsx @@ -31,7 +31,7 @@ const Settings: React.FC = () => { `https://${url}/settings/preferences`, 'tooot://tooot', { - browserPackage: await browserPackage(), + ...(await browserPackage()), dismissButtonStyle: 'done', readerMode: false } diff --git a/src/screens/Tabs/Me/Settings/Tooot.tsx b/src/screens/Tabs/Me/Settings/Tooot.tsx index a8c3ef05..256e4866 100644 --- a/src/screens/Tabs/Me/Settings/Tooot.tsx +++ b/src/screens/Tabs/Me/Settings/Tooot.tsx @@ -64,7 +64,7 @@ const SettingsTooot: React.FC = () => { }) } else { WebBrowser.openBrowserAsync('https://social.xmflsct.com/@tooot', { - browserPackage: await browserPackage() + ...(await browserPackage()) }) } }} diff --git a/src/utils/migrations/instances/v11.ts b/src/utils/migrations/instances/v11.ts index e02d72bb..dffb36eb 100644 --- a/src/utils/migrations/instances/v11.ts +++ b/src/utils/migrations/instances/v11.ts @@ -14,7 +14,7 @@ export type InstanceV11 = { id: Mastodon.Account['id'] acct: Mastodon.Account['acct'] avatarStatic: Mastodon.Account['avatar_static'] - preferences: Mastodon.Preferences + preferences?: Mastodon.Preferences } version: string configuration?: Mastodon.Instance['configuration'] diff --git a/src/utils/push/useConnect.ts b/src/utils/push/useConnect.ts index dbb45104..9e961753 100644 --- a/src/utils/push/useConnect.ts +++ b/src/utils/push/useConnect.ts @@ -1,12 +1,13 @@ import apiGeneral from '@api/general' -import { handleError } from '@api/helpers' import apiTooot from '@api/tooot' import { displayMessage } from '@components/Message' import navigationRef from '@helpers/navigationRef' import { useAppDispatch } from '@root/store' import * as Sentry from '@sentry/react-native' +import { useQuery } from '@tanstack/react-query' import { getExpoToken, retrieveExpoToken } from '@utils/slices/appSlice' import { disableAllPushes, getInstances } from '@utils/slices/instancesSlice' +import { AxiosError } from 'axios' import * as Notifications from 'expo-notifications' import { useEffect } from 'react' import { useTranslation } from 'react-i18next' @@ -25,16 +26,22 @@ const pushUseConnect = () => { const instances = useSelector(getInstances, (prev, next) => prev.length === next.length) const pushEnabled = instances.filter(instance => instance.push.global) - const connect = () => { - apiTooot({ - method: 'get', - url: `/push/connect/${expoToken}` - }) - .then(() => Notifications.setBadgeCountAsync(0)) - .catch(error => { - handleError({ message: 'Push connect error', captureResponse: true }) - - Notifications.setBadgeCountAsync(0) + const connectQuery = useQuery( + ['tooot', { endpoint: 'push/connect' }], + () => + apiTooot({ + method: 'get', + url: `push/connect/${expoToken}` + }), + { + enabled: false, + retry: 10, + retryOnMount: false, + refetchOnMount: false, + refetchOnWindowFocus: false, + refetchOnReconnect: false, + onSettled: () => Notifications.setBadgeCountAsync(0), + onError: error => { if (error?.status == 404) { displayMessage({ type: 'danger', @@ -72,21 +79,22 @@ const pushUseConnect = () => { } }) } - }) - } + } + } + ) useEffect(() => { Sentry.setContext('Push', { expoToken, pushEnabledCount: pushEnabled.length }) if (expoToken && pushEnabled.length) { - connect() + connectQuery.refetch() } const appStateListener = AppState.addEventListener('change', state => { if (expoToken && pushEnabled.length && state === 'active') { Notifications.getBadgeCountAsync().then(count => { if (count > 0) { - connect() + connectQuery.refetch() } }) } diff --git a/src/utils/slices/instancesSlice.ts b/src/utils/slices/instancesSlice.ts index 54ace209..7704cef9 100644 --- a/src/utils/slices/instancesSlice.ts +++ b/src/utils/slices/instancesSlice.ts @@ -220,7 +220,8 @@ const instancesSlice = createSlice({ // Update Instance Configuration .addCase(updateConfiguration.fulfilled, (state, action) => { const activeIndex = findInstanceActive(state.instances) - state.instances[activeIndex].version = action.payload?.version || '0' + state.instances[activeIndex].version = + typeof action.payload.version === 'string' ? action.payload.version : '0' state.instances[activeIndex].configuration = action.payload.configuration }) .addCase(updateConfiguration.rejected, (_, action) => { @@ -250,6 +251,9 @@ const instancesSlice = createSlice({ .addCase(checkEmojis.fulfilled, (state, action) => { if (!action.payload || !action.payload.length) return const activeIndex = findInstanceActive(state.instances) + if (!Array.isArray(state.instances[activeIndex].frequentEmojis)) { + state.instances[activeIndex].frequentEmojis = [] + } state.instances[activeIndex].frequentEmojis = state.instances[ activeIndex ]?.frequentEmojis?.filter(emoji => { From c59690fcb99ebc52cc323f2e7209c153d8da125b Mon Sep 17 00:00:00 2001 From: xmflsct Date: Sat, 17 Dec 2022 23:21:56 +0100 Subject: [PATCH 17/22] Fixed #566 --- fastlane/metadata/en-US/release_notes.txt | 9 ---- fastlane/metadata/zh-Hans/release_notes.txt | 9 ---- package.json | 2 +- src/components/Timeline/Default.tsx | 2 + src/components/Timeline/Shared/Context.tsx | 1 + src/components/Timeline/Shared/Feedback.tsx | 9 +++- src/components/Timeline/Shared/Translate.tsx | 21 +++++--- src/screens/Tabs/Shared/History.tsx | 52 +++++++++++++++----- src/utils/navigation/navigators.ts | 1 + 9 files changed, 65 insertions(+), 41 deletions(-) diff --git a/fastlane/metadata/en-US/release_notes.txt b/fastlane/metadata/en-US/release_notes.txt index ca79b784..862623d2 100644 --- a/fastlane/metadata/en-US/release_notes.txt +++ b/fastlane/metadata/en-US/release_notes.txt @@ -1,10 +1 @@ Enjoy toooting! This version includes following improvements and fixes: -- Added Ukrainian (Slava Ukraini) -- Automatic setting detected language when tooting -- Remember public timeline type selection -- Show diffing of edit history -- Allow hiding boosts and replies in home timeline -- Support toot in RTL languages -- Added notification for admins -- Fix whole word filter matching -- Fix tablet cannot delete toot drafts diff --git a/fastlane/metadata/zh-Hans/release_notes.txt b/fastlane/metadata/zh-Hans/release_notes.txt index 35846c68..d9488dcd 100644 --- a/fastlane/metadata/zh-Hans/release_notes.txt +++ b/fastlane/metadata/zh-Hans/release_notes.txt @@ -1,10 +1 @@ toooting愉快!此版本包括以下改进和修复: -- 增加乌克兰语(Slava Ukraini) -- 自动识别发嘟语言 -- 记住上次公共时间轴选项 -- 显示编辑历史的差异 -- 关注列表可隐藏转嘟和回复 -- 新增管理员推送通知 -- 支持嘟文右到左文字 -- 修复过滤整词功能 -- 修复平板不能删除草稿 diff --git a/package.json b/package.json index b10cfe1c..82ef675d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tooot", - "version": "4.7.0", + "version": "4.7.1", "description": "tooot for Mastodon", "author": "xmflsct ", "license": "GPL-3.0-or-later", diff --git a/src/components/Timeline/Default.tsx b/src/components/Timeline/Default.tsx index 0284cf07..8d209d14 100644 --- a/src/components/Timeline/Default.tsx +++ b/src/components/Timeline/Default.tsx @@ -64,6 +64,7 @@ const TimelineDefault: React.FC = ({ content: '', complete: false }) + const detectedLanguage = useRef(status.language || '') const filtered = queryKey && shouldFilter({ copiableContent, status, queryKey }) if (queryKey && filtered && !highlighted) { @@ -139,6 +140,7 @@ const TimelineDefault: React.FC = ({ ownAccount, spoilerHidden, copiableContent, + detectedLanguage, highlighted, inThread: queryKey?.[1].page === 'Toot', disableDetails, diff --git a/src/components/Timeline/Shared/Context.tsx b/src/components/Timeline/Shared/Context.tsx index f00668d1..218379d1 100644 --- a/src/components/Timeline/Shared/Context.tsx +++ b/src/components/Timeline/Shared/Context.tsx @@ -14,6 +14,7 @@ type ContextType = { content: string complete: boolean }> + detectedLanguage?: React.MutableRefObject highlighted?: boolean inThread?: boolean diff --git a/src/components/Timeline/Shared/Feedback.tsx b/src/components/Timeline/Shared/Feedback.tsx index 40d647e7..ec5bd793 100644 --- a/src/components/Timeline/Shared/Feedback.tsx +++ b/src/components/Timeline/Shared/Feedback.tsx @@ -11,7 +11,7 @@ import { StyleSheet, View } from 'react-native' import StatusContext from './Context' const TimelineFeedback = () => { - const { status, highlighted } = useContext(StatusContext) + const { status, highlighted, detectedLanguage } = useContext(StatusContext) if (!status || !highlighted) return null const { t } = useTranslation('componentTimeline') @@ -80,7 +80,12 @@ const TimelineFeedback = () => { accessibilityHint={t('shared.actionsUsers.history.accessibilityHint')} accessibilityRole='button' style={[styles.text, { marginRight: 0, color: colors.blue }]} - onPress={() => navigation.push('Tab-Shared-History', { id: status.id })} + onPress={() => + navigation.push('Tab-Shared-History', { + id: status.id, + detectedLanguage: detectedLanguage?.current || status.language || '' + }) + } > {t('shared.actionsUsers.history.text', { count: data.length - 1 diff --git a/src/components/Timeline/Shared/Translate.tsx b/src/components/Timeline/Shared/Translate.tsx index d55369dd..f8c62192 100644 --- a/src/components/Timeline/Shared/Translate.tsx +++ b/src/components/Timeline/Shared/Translate.tsx @@ -13,7 +13,7 @@ import { Circle } from 'react-native-animated-spinkit' import StatusContext from './Context' const TimelineTranslate = () => { - const { status, highlighted, copiableContent } = useContext(StatusContext) + const { status, highlighted, copiableContent, detectedLanguage } = useContext(StatusContext) if (!status || !highlighted) return null const { t } = useTranslation('componentTimeline') @@ -38,14 +38,19 @@ const TimelineTranslate = () => { ? [copiableContent?.current.content] : backupTextProcessing() - const [detectedLanguage, setDetectedLanguage] = useState<{ + const [detected, setDetected] = useState<{ language: string confidence: number }>({ language: status.language || '', confidence: 0 }) useEffect(() => { const detect = async () => { const result = await detectLanguage(text.join('\n\n')) - result && setDetectedLanguage(result) + if (result) { + setDetected(result) + if (detectedLanguage) { + detectedLanguage.current = result.language + } + } } detect() }, []) @@ -57,7 +62,7 @@ const TimelineTranslate = () => { const [enabled, setEnabled] = useState(false) const { refetch, data, isFetching, isSuccess, isError } = useTranslateQuery({ - source: detectedLanguage.language, + source: detected.language, target: targetLanguage, text, options: { enabled } @@ -66,9 +71,9 @@ const TimelineTranslate = () => { const devView = () => { return __DEV__ ? ( {` Source: ${ - detectedLanguage?.language + detected?.language }; Confidence: ${ - detectedLanguage?.confidence.toString().slice(0, 5) || 'null' + detected?.confidence.toString().slice(0, 5) || 'null' }; Target: ${targetLanguage}`} ) : null } @@ -78,13 +83,13 @@ const TimelineTranslate = () => { } if ( Platform.OS === 'ios' && - Localization.locale.slice(0, 2).includes(detectedLanguage.language.slice(0, 2)) + Localization.locale.slice(0, 2).includes(detected.language.slice(0, 2)) ) { return devView() } if ( Platform.OS === 'android' && - settingsLanguage?.slice(0, 2).includes(detectedLanguage.language.slice(0, 2)) + settingsLanguage?.slice(0, 2).includes(detected.language.slice(0, 2)) ) { return devView() } diff --git a/src/screens/Tabs/Shared/History.tsx b/src/screens/Tabs/Shared/History.tsx index 1c59cfd8..26325ed2 100644 --- a/src/screens/Tabs/Shared/History.tsx +++ b/src/screens/Tabs/Shared/History.tsx @@ -11,25 +11,45 @@ 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 { diffChars, diffWords } from 'diff' import React, { useEffect } from 'react' import { useTranslation } from 'react-i18next' import { FlatList, View } from 'react-native' +const SCRIPTS_WITHOUT_BOUNDARIES = [ + 'my', + 'zh', + 'ja', + 'kar', + 'km', + 'lp', + 'phag', + 'pwo', + 'kar', + 'lana', + 'th', + 'bo' +] + const ContentView: React.FC<{ + withoutBoundary: boolean item: Mastodon.StatusHistory prevItem?: Mastodon.StatusHistory -}> = ({ item, prevItem }) => { +}> = ({ withoutBoundary, 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) - ) + const changesSpoiler = withoutBoundary + ? diffChars( + removeHTML(prevItem?.spoiler_text || item.spoiler_text || ''), + removeHTML(item.spoiler_text || '') + ) + : diffWords( + removeHTML(prevItem?.spoiler_text || item.spoiler_text || ''), + removeHTML(item.spoiler_text || '') + ) + const changesContent = withoutBoundary + ? diffChars(removeHTML(prevItem?.content || item.content), removeHTML(item.content)) + : diffWords(removeHTML(prevItem?.content || item.content), removeHTML(item.content)) return ( // @ts-ignore @@ -91,7 +111,7 @@ const ContentView: React.FC<{ const TabSharedHistory: React.FC> = ({ navigation, route: { - params: { id } + params: { id, detectedLanguage } } }) => { const { t } = useTranslation('screenTabs') @@ -106,12 +126,20 @@ const TabSharedHistory: React.FC const dataReversed = data ? [...data].reverse() : [] + const withoutBoundary = !!SCRIPTS_WITHOUT_BOUNDARIES.filter(script => + detectedLanguage?.toLocaleLowerCase().startsWith(script) + ).length + return ( ( - + )} ItemSeparatorComponent={ComponentSeparator} /> diff --git a/src/utils/navigation/navigators.ts b/src/utils/navigation/navigators.ts index 0e5d2822..866cea67 100644 --- a/src/utils/navigation/navigators.ts +++ b/src/utils/navigation/navigators.ts @@ -103,6 +103,7 @@ export type TabSharedStackParamList = { } 'Tab-Shared-History': { id: Mastodon.Status['id'] + detectedLanguage: string } 'Tab-Shared-Search': undefined 'Tab-Shared-Toot': { From ef80ab895e7112c17b7a09316df73ba805734d25 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Sat, 17 Dec 2022 23:31:46 +0100 Subject: [PATCH 18/22] Remove min height of cards --- src/components/Timeline/Shared/Card.tsx | 40 ++++++++++++------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/components/Timeline/Shared/Card.tsx b/src/components/Timeline/Shared/Card.tsx index 412bd22a..7951057d 100644 --- a/src/components/Timeline/Shared/Card.tsx +++ b/src/components/Timeline/Shared/Card.tsx @@ -145,19 +145,21 @@ const TimelineCard: React.FC = () => { /> ) : null} - - {status.card?.title} - - {status.card?.description ? ( + {status.card?.title.length ? ( + + {status.card.title} + + ) : null} + {status.card?.description.length ? ( { {status.card.description} ) : null} - - {status.card?.url} - + {status.card?.url.length ? ( + + {status.card.url} + + ) : null} ) @@ -187,10 +191,6 @@ const TimelineCard: React.FC = () => { style={{ flex: 1, flexDirection: 'row', - minHeight: - (isStatus && foundStatus) || (isAccount && foundAccount) - ? undefined - : StyleConstants.Font.LineHeight.M * 5, marginTop: StyleConstants.Spacing.M, borderWidth: StyleSheet.hairlineWidth, borderRadius: StyleConstants.Spacing.S, From a5315501fd6b25eab616b1775e7f7474709a1f2d Mon Sep 17 00:00:00 2001 From: xmflsct Date: Sun, 18 Dec 2022 00:00:58 +0100 Subject: [PATCH 19/22] Fixed #565 --- src/components/Instance/index.tsx | 107 +++++++++++++++++++-------- src/i18n/en/components/instance.json | 1 + 2 files changed, 76 insertions(+), 32 deletions(-) diff --git a/src/components/Instance/index.tsx b/src/components/Instance/index.tsx index eb7fbddc..f0fe1b3a 100644 --- a/src/components/Instance/index.tsx +++ b/src/components/Instance/index.tsx @@ -15,6 +15,7 @@ import { Alert, Image, KeyboardAvoidingView, Platform, TextInput, View } from 'r import { ScrollView } from 'react-native-gesture-handler' import { useSelector } from 'react-redux' import { Placeholder } from 'rn-placeholder' +import validUrl from 'valid-url' import InstanceInfo from './Info' import CustomText from '../Text' import { useNavigation } from '@react-navigation/native' @@ -39,12 +40,26 @@ const ComponentInstance: React.FC = ({ const navigation = useNavigation>() const [domain, setDomain] = useState('') + const [errorCode, setErrorCode] = useState(null) + const whitelisted: boolean = + !!domain.length && + !!errorCode && + !!validUrl.isHttpsUri(`https://${domain}`) && + errorCode === 401 const dispatch = useAppDispatch() const instances = useSelector(getInstances, () => true) const instanceQuery = useInstanceQuery({ domain, - options: { enabled: !!domain, retry: false } + options: { + enabled: !!domain, + retry: false, + onError: err => { + if (err.status) { + setErrorCode(err.status) + } + } + } }) const deprecateAuthFollow = useSelector(checkInstanceFeature('deprecate_auth_follow')) @@ -146,7 +161,11 @@ const ComponentInstance: React.FC = ({ borderBottomWidth: 1, ...StyleConstants.FontStyle.M, color: colors.primaryDefault, - borderBottomColor: instanceQuery.isError ? colors.red : colors.border, + borderBottomColor: instanceQuery.isError + ? whitelisted + ? colors.yellow + : colors.red + : colors.border, ...(Platform.OS === 'android' && { paddingRight: 0 }) }} editable={false} @@ -159,12 +178,23 @@ const ComponentInstance: React.FC = ({ ...StyleConstants.FontStyle.M, marginRight: StyleConstants.Spacing.M, color: colors.primaryDefault, - borderBottomColor: instanceQuery.isError ? colors.red : colors.border, + borderBottomColor: instanceQuery.isError + ? whitelisted + ? colors.yellow + : colors.red + : colors.border, ...(Platform.OS === 'android' && { paddingLeft: 0 }) }} - onChangeText={debounce(text => setDomain(text.replace(/^http(s)?\:\/\//i, '')), 1000, { - trailing: true - })} + onChangeText={debounce( + text => { + setDomain(text.replace(/^http(s)?\:\/\//i, '')) + setErrorCode(null) + }, + 1000, + { + trailing: true + } + )} autoCapitalize='none' clearButtonMode='never' keyboardType='url' @@ -194,39 +224,52 @@ const ComponentInstance: React.FC = ({ type='text' content={t('server.button')} onPress={processUpdate} - disabled={!instanceQuery.data?.uri} + disabled={!instanceQuery.data?.uri && !whitelisted} loading={instanceQuery.isFetching || appsMutation.isLoading} /> - - - + {whitelisted ? ( + + {t('server.whitelisted')} + + ) : ( + - - - - + + + + + + + )} Date: Sun, 18 Dec 2022 00:41:49 +0100 Subject: [PATCH 20/22] Make search transition smoother? --- src/screens/Tabs/Shared/Search/index.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/screens/Tabs/Shared/Search/index.tsx b/src/screens/Tabs/Shared/Search/index.tsx index 9c70098b..f31a3e14 100644 --- a/src/screens/Tabs/Shared/Search/index.tsx +++ b/src/screens/Tabs/Shared/Search/index.tsx @@ -49,7 +49,6 @@ const TabSharedSearch: React.FC> > borderBottomColor: colors.border, borderBottomWidth: 1 }} - autoFocus onChangeText={debounce( text => { setSearchTerm(text) @@ -82,6 +80,13 @@ const TabSharedSearch: React.FC> } }) }, [mode]) + useEffect(() => { + const unsubscribe = navigation.addListener('transitionEnd', e => { + inputRef.current?.focus() + }) + + return unsubscribe + }, [navigation]) const mapKeyToTranslations = { accounts: t('shared.search.sections.accounts'), From fea2e82bdd195433ab71d04850255e58aaf7a633 Mon Sep 17 00:00:00 2001 From: xmflsct Date: Sun, 18 Dec 2022 01:12:58 +0100 Subject: [PATCH 21/22] Fixed #568 --- src/@types/mastodon.d.ts | 2 + src/components/Relationship/Outgoing.tsx | 175 +++++++++++++---------- src/helpers/features.json | 4 + src/utils/queryHooks/relationship.ts | 45 +++--- 4 files changed, 129 insertions(+), 97 deletions(-) diff --git a/src/@types/mastodon.d.ts b/src/@types/mastodon.d.ts index 699cbd16..fc61ed10 100644 --- a/src/@types/mastodon.d.ts +++ b/src/@types/mastodon.d.ts @@ -406,6 +406,8 @@ declare namespace Mastodon { id: string following: boolean showing_reblogs: boolean + notifying?: boolean + languages?: string[] followed_by: boolean blocking: boolean blocked_by: boolean diff --git a/src/components/Relationship/Outgoing.tsx b/src/components/Relationship/Outgoing.tsx index 70a643e0..fc082097 100644 --- a/src/components/Relationship/Outgoing.tsx +++ b/src/components/Relationship/Outgoing.tsx @@ -6,120 +6,144 @@ import { useRelationshipMutation, useRelationshipQuery } from '@utils/queryHooks/relationship' -import { QueryKeyTimeline } from '@utils/queryHooks/timeline' import { useTheme } from '@utils/styles/ThemeManager' import React from 'react' import { useTranslation } from 'react-i18next' import { useQueryClient } from '@tanstack/react-query' +import { useSelector } from 'react-redux' +import { checkInstanceFeature } from '@utils/slices/instancesSlice' +import { StyleConstants } from '@utils/styles/constants' export interface Props { id: Mastodon.Account['id'] } -const RelationshipOutgoing = React.memo( - ({ id }: Props) => { - const { theme } = useTheme() - const { t } = useTranslation('componentRelationship') +const RelationshipOutgoing: React.FC = ({ id }: Props) => { + const { theme } = useTheme() + const { t } = useTranslation('componentRelationship') - const query = useRelationshipQuery({ id }) + const canFollowNotify = useSelector(checkInstanceFeature('account_follow_notify')) - const queryKeyRelationship: QueryKeyRelationship = ['Relationship', { id }] - const queryClient = useQueryClient() - const mutation = useRelationshipMutation({ - onSuccess: (res, { payload: { action } }) => { - haptics('Success') - queryClient.setQueryData(queryKeyRelationship, [res]) - if (action === 'block') { - const queryKey = ['Timeline', { page: 'Following' }] - queryClient.invalidateQueries({ queryKey, exact: false }) - } - }, - onError: (err: any, { payload: { action } }) => { - displayMessage({ - theme, - type: 'error', - message: t('common:message.error.message', { - function: t(`${action}.function`) - }), - ...(err.status && - typeof err.status === 'number' && - err.data && - err.data.error && - typeof err.data.error === 'string' && { - description: err.data.error - }) - }) + const query = useRelationshipQuery({ id }) + + const queryKeyRelationship: QueryKeyRelationship = ['Relationship', { id }] + const queryClient = useQueryClient() + const mutation = useRelationshipMutation({ + onSuccess: (res, { payload: { action } }) => { + haptics('Success') + queryClient.setQueryData(queryKeyRelationship, [res]) + if (action === 'block') { + const queryKey = ['Timeline', { page: 'Following' }] + queryClient.invalidateQueries({ queryKey, exact: false }) } - }) + }, + onError: (err: any, { payload: { action } }) => { + displayMessage({ + theme, + type: 'error', + message: t('common:message.error.message', { + function: t(`${action}.function`) + }), + ...(err.status && + typeof err.status === 'number' && + err.data && + err.data.error && + typeof err.data.error === 'string' && { + description: err.data.error + }) + }) + } + }) - let content: string - let onPress: () => void + let content: string + let onPress: () => void - if (query.isError) { - content = t('button.error') + if (query.isError) { + content = t('button.error') + onPress = () => {} + } else { + if (query.data?.blocked_by) { + content = t('button.blocked_by') onPress = () => {} } else { - if (query.data?.blocked_by) { - content = t('button.blocked_by') - onPress = () => {} + if (query.data?.blocking) { + content = t('button.blocking') + onPress = () => { + mutation.mutate({ + id, + type: 'outgoing', + payload: { + action: 'block', + state: query.data?.blocking + } + }) + } } else { - if (query.data?.blocking) { - content = t('button.blocking') + if (query.data?.following) { + content = t('button.following') onPress = () => { mutation.mutate({ id, type: 'outgoing', payload: { - action: 'block', - state: query.data?.blocking + action: 'follow', + state: query.data?.following } }) } } else { - if (query.data?.following) { - content = t('button.following') + if (query.data?.requested) { + content = t('button.requested') onPress = () => { mutation.mutate({ id, type: 'outgoing', payload: { action: 'follow', - state: query.data?.following + state: query.data?.requested } }) } } else { - if (query.data?.requested) { - content = t('button.requested') - onPress = () => { - mutation.mutate({ - id, - type: 'outgoing', - payload: { - action: 'follow', - state: query.data?.requested - } - }) - } - } else { - content = t('button.default') - onPress = () => { - mutation.mutate({ - id, - type: 'outgoing', - payload: { - action: 'follow', - state: false - } - }) - } + content = t('button.default') + onPress = () => { + mutation.mutate({ + id, + type: 'outgoing', + payload: { + action: 'follow', + state: false + } + }) } } } } } + } - return ( + return ( + <> + {canFollowNotify && query.data?.following ? ( +