diff --git a/fastlane/metadata/en-US/release_notes.txt b/fastlane/metadata/en-US/release_notes.txt index da253fd4..862623d2 100644 --- a/fastlane/metadata/en-US/release_notes.txt +++ b/fastlane/metadata/en-US/release_notes.txt @@ -1,2 +1 @@ Enjoy toooting! This version includes following improvements and fixes: -- Added Belarusian language \ 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 81692af7..d9488dcd 100644 --- a/fastlane/metadata/zh-Hans/release_notes.txt +++ b/fastlane/metadata/zh-Hans/release_notes.txt @@ -1,2 +1 @@ toooting愉快!此版本包括以下改进和修复: -- 新增白俄罗斯语 \ No newline at end of file diff --git a/ios/tooot/AppDelegate.h b/ios/tooot/AppDelegate.h index c1f4f9fa..1658a437 100644 --- a/ios/tooot/AppDelegate.h +++ b/ios/tooot/AppDelegate.h @@ -1,9 +1,7 @@ -#import #import #import - #import -@interface AppDelegate : RCTAppDelegate +@interface AppDelegate : EXAppDelegateWrapper @end diff --git a/ios/tooot/AppDelegate.mm b/ios/tooot/AppDelegate.mm index bb0106f9..f4620220 100644 --- a/ios/tooot/AppDelegate.mm +++ b/ios/tooot/AppDelegate.mm @@ -51,4 +51,22 @@ restorationHandler:restorationHandler]; } +// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries +- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken +{ + return [super application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken]; +} + +// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries +- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error +{ + return [super application:application didFailToRegisterForRemoteNotificationsWithError:error]; +} + +// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries +- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler +{ + return [super application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler]; +} + @end \ No newline at end of file diff --git a/package.json b/package.json index a8e87ab3..06dc4609 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tooot", - "version": "4.9.1", + "version": "4.9.2", "description": "tooot for Mastodon", "author": "xmflsct ", "license": "GPL-3.0-or-later", @@ -88,7 +88,6 @@ "react-native-swipe-list-view": "^3.2.9", "react-native-tab-view": "^3.5.1", "rn-placeholder": "^3.0.3", - "url-parse": "^1.5.10", "zeego": "^1.3.1" }, "devDependencies": { @@ -102,7 +101,6 @@ "@types/react": "^18.0.28", "@types/react-dom": "^18.0.11", "@types/react-native-share-menu": "^5.0.2", - "@types/url-parse": "^1.4.8", "babel-plugin-module-resolver": "^5.0.0", "babel-plugin-transform-remove-console": "^6.9.4", "chalk": "^4.1.2", diff --git a/src/components/Instance/index.tsx b/src/components/Instance/index.tsx index ef24f068..5ea043cd 100644 --- a/src/components/Instance/index.tsx +++ b/src/components/Instance/index.tsx @@ -21,6 +21,7 @@ import { useTheme } from '@utils/styles/ThemeManager' import * as AuthSession from 'expo-auth-session' import * as Crypto from 'expo-crypto' import { Image } from 'expo-image' +import * as Linking from 'expo-linking' import * as WebBrowser from 'expo-web-browser' import { debounce } from 'lodash' import React, { RefObject, useCallback, useState } from 'react' @@ -28,7 +29,6 @@ import { Trans, useTranslation } from 'react-i18next' import { Alert, KeyboardAvoidingView, Platform, TextInput, View } from 'react-native' import { ScrollView } from 'react-native-gesture-handler' import { fromByteArray } from 'react-native-quick-base64' -import parse from 'url-parse' import CustomText from '../Text' export interface Props { @@ -51,7 +51,7 @@ const ComponentInstance: React.FC = ({ const whitelisted: boolean = !!domain.length && !!errorCode && - !!(parse(`https://${domain}/`).hostname === domain) && + !!(Linking.parse(`https://${domain}/`).hostname === domain) && errorCode === 401 const instanceQuery = useInstanceQuery({ @@ -129,7 +129,7 @@ const ComponentInstance: React.FC = ({ (instanceQuery.data as Mastodon.Instance_V2)?.domain || instanceQuery.data?.account_domain || ((instanceQuery.data as Mastodon.Instance_V1)?.uri - ? parse((instanceQuery.data as Mastodon.Instance_V1).uri).hostname + ? Linking.parse((instanceQuery.data as Mastodon.Instance_V1).uri).hostname : undefined) || (instanceQuery.data as Mastodon.Instance_V1)?.uri, 'auth.account.avatar_static': avatar_static, diff --git a/src/components/Timeline/Shared/Card/Neodb.tsx b/src/components/Timeline/Shared/Card/Neodb.tsx new file mode 100644 index 00000000..98bffedd --- /dev/null +++ b/src/components/Timeline/Shared/Card/Neodb.tsx @@ -0,0 +1,125 @@ +import GracefullyImage from '@components/GracefullyImage' +import openLink from '@components/openLink' +import CustomText from '@components/Text' +import { useNeodbQuery } from '@utils/queryHooks/neodb' +import { StyleConstants } from '@utils/styles/constants' +import { useTheme } from '@utils/styles/ThemeManager' +import * as Linking from 'expo-linking' +import { Pressable, View } from 'react-native' + +export const CardNeodb = ({ card }: { card: Mastodon.Card }) => { + const { colors } = useTheme() + + const segments = Linking.parse(card.url).path?.split('/') + if (!segments || !(segments[0] === 'movie' || segments[0] === 'book')) return null + + const { data } = useNeodbQuery({ path: `${segments[0]}/${segments[1]}` }) + + if (!data) return null + + switch (segments[0]) { + case 'movie': + return ( + openLink(card.url)} + > + + + + {[ + data.data.title, + data.data.orig_title, + data.data.year ? `(${data.data.year})` : null + ] + .filter(d => d) + .join(' ')} + + + {[ + data.data.duration ? `${data.data.duration}分钟` : null, + data.data.area?.join(' '), + data.data.genre?.join(' '), + data.data.director?.join(' ') + ] + .filter(d => d) + .join(' / ')} + + + + ) + case 'book': + return ( + openLink(card.url)} + > + + + + {[ + data.data.title, + data.data.pub_year && data.data.pub_month + ? `(${data.data.pub_year}年${data.data.pub_month}月)` + : null + ] + .filter(d => d) + .join(' ')} + + + {[ + data.data.author?.join(' '), + data.data.language, + data.data.pages ? `${data.data.pages}页` : null, + data.data.pub_house + ] + .filter(d => d) + .join(' / ')} + + + + ) + default: + return null + } +} diff --git a/src/components/Timeline/Shared/Card.tsx b/src/components/Timeline/Shared/Card/index.tsx similarity index 93% rename from src/components/Timeline/Shared/Card.tsx rename to src/components/Timeline/Shared/Card/index.tsx index d77ae525..254787f3 100644 --- a/src/components/Timeline/Shared/Card.tsx +++ b/src/components/Timeline/Shared/Card/index.tsx @@ -11,14 +11,21 @@ import { useStatusQuery } from '@utils/queryHooks/status' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' import React, { useContext, useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' import { Pressable, View } from 'react-native' -import TimelineDefault from '../Default' -import StatusContext from './Context' +import TimelineDefault from '../../Default' +import StatusContext from '../Context' +import { CardNeodb } from './Neodb' const TimelineCard: React.FC = () => { const { status, spoilerHidden, disableDetails, inThread } = useContext(StatusContext) if (!status || !status.card) return null + const { i18n } = useTranslation() + if (status.card.url.includes('://neodb.social/') && i18n.language === 'zh-hans') { + return + } + const { colors } = useTheme() const navigation = useNavigation>() diff --git a/src/components/contextMenu/instance.ts b/src/components/contextMenu/instance.ts index 7b0a2af8..418b6c80 100644 --- a/src/components/contextMenu/instance.ts +++ b/src/components/contextMenu/instance.ts @@ -2,9 +2,9 @@ import { displayMessage } from '@components/Message' import { useQueryClient } from '@tanstack/react-query' import { QueryKeyTimeline, useTimelineMutation } from '@utils/queryHooks/timeline' import { getAccountStorage } from '@utils/storage/actions' +import * as Linking from 'expo-linking' import { useTranslation } from 'react-i18next' import { Alert } from 'react-native' -import parse from 'url-parse' const menuInstance = ({ status, @@ -32,9 +32,9 @@ const menuInstance = ({ const menus: ContextMenu = [] - const instance = parse(status.uri).hostname + const instance = Linking.parse(status.uri).hostname - if (instance !== getAccountStorage.string('auth.domain')) { + if (instance && instance !== getAccountStorage.string('auth.domain')) { menus.push([ { type: 'item', diff --git a/src/screens/Tabs/Me/FollowedTags.tsx b/src/screens/Tabs/Me/FollowedTags.tsx index 928a8d37..b55482b2 100644 --- a/src/screens/Tabs/Me/FollowedTags.tsx +++ b/src/screens/Tabs/Me/FollowedTags.tsx @@ -60,8 +60,8 @@ const TabMeFollowedTags: React.FC>