diff --git a/.vscode/settings.json b/.vscode/settings.json
deleted file mode 100644
index 5e6575f2..00000000
--- a/.vscode/settings.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "javascript.inlayHints.functionLikeReturnTypes.enabled": false
-}
\ No newline at end of file
diff --git a/demo/screenshots/Component-Instance.png b/demo/screenshots/Component-Instance.png
new file mode 100644
index 00000000..8b31c0a9
Binary files /dev/null and b/demo/screenshots/Component-Instance.png differ
diff --git a/demo/screenshots/Component-MediaSelector.png b/demo/screenshots/Component-MediaSelector.png
new file mode 100644
index 00000000..c47692d8
Binary files /dev/null and b/demo/screenshots/Component-MediaSelector.png differ
diff --git a/demo/screenshots/Logout-Confirmation.png b/demo/screenshots/Logout-Confirmation.png
new file mode 100644
index 00000000..330d6b04
Binary files /dev/null and b/demo/screenshots/Logout-Confirmation.png differ
diff --git a/demo/screenshots/Screen-AccountSelection.png b/demo/screenshots/Screen-AccountSelection.png
new file mode 100644
index 00000000..14509119
Binary files /dev/null and b/demo/screenshots/Screen-AccountSelection.png differ
diff --git a/demo/screenshots/Tab-Local.png b/demo/screenshots/Tab-Local.png
new file mode 100644
index 00000000..2ec6d60a
Binary files /dev/null and b/demo/screenshots/Tab-Local.png differ
diff --git a/demo/screenshots/Tab-Me-List-Edit.png b/demo/screenshots/Tab-Me-List-Edit.png
new file mode 100644
index 00000000..02b20608
Binary files /dev/null and b/demo/screenshots/Tab-Me-List-Edit.png differ
diff --git a/demo/screenshots/Tab-Me-ListAccounts_Empty.png b/demo/screenshots/Tab-Me-ListAccounts_Empty.png
new file mode 100644
index 00000000..024c9e44
Binary files /dev/null and b/demo/screenshots/Tab-Me-ListAccounts_Empty.png differ
diff --git a/demo/screenshots/Tab-Me-ListAccounts_Error.png b/demo/screenshots/Tab-Me-ListAccounts_Error.png
new file mode 100644
index 00000000..b668b6a0
Binary files /dev/null and b/demo/screenshots/Tab-Me-ListAccounts_Error.png differ
diff --git a/demo/screenshots/Tab-Me-List_Delete.png b/demo/screenshots/Tab-Me-List_Delete.png
new file mode 100644
index 00000000..324421fd
Binary files /dev/null and b/demo/screenshots/Tab-Me-List_Delete.png differ
diff --git a/demo/screenshots/Tab-Me-List_Menu.png b/demo/screenshots/Tab-Me-List_Menu.png
new file mode 100644
index 00000000..7c4706b0
Binary files /dev/null and b/demo/screenshots/Tab-Me-List_Menu.png differ
diff --git a/demo/screenshots/Tab-Me-Profile-Fields.png b/demo/screenshots/Tab-Me-Profile-Fields.png
new file mode 100644
index 00000000..d4bf5060
Binary files /dev/null and b/demo/screenshots/Tab-Me-Profile-Fields.png differ
diff --git a/demo/screenshots/Tab-Me-Profile.png b/demo/screenshots/Tab-Me-Profile.png
new file mode 100644
index 00000000..9690c9d8
Binary files /dev/null and b/demo/screenshots/Tab-Me-Profile.png differ
diff --git a/demo/screenshots/Tab-Me-Profile_Feedback.png b/demo/screenshots/Tab-Me-Profile_Feedback.png
new file mode 100644
index 00000000..1d965ac4
Binary files /dev/null and b/demo/screenshots/Tab-Me-Profile_Feedback.png differ
diff --git a/demo/screenshots/Tab-Me-Push_Bottom.png b/demo/screenshots/Tab-Me-Push_Bottom.png
new file mode 100644
index 00000000..de8166d3
Binary files /dev/null and b/demo/screenshots/Tab-Me-Push_Bottom.png differ
diff --git a/demo/screenshots/Tab-Me-Push_MissingServerKey.png b/demo/screenshots/Tab-Me-Push_MissingServerKey.png
new file mode 100644
index 00000000..60cea2ff
Binary files /dev/null and b/demo/screenshots/Tab-Me-Push_MissingServerKey.png differ
diff --git a/demo/screenshots/Tab-Me-Push_NotAvailable.png b/demo/screenshots/Tab-Me-Push_NotAvailable.png
new file mode 100644
index 00000000..72a8e2f9
Binary files /dev/null and b/demo/screenshots/Tab-Me-Push_NotAvailable.png differ
diff --git a/demo/screenshots/Tab-Me-Push_ReEnable.png b/demo/screenshots/Tab-Me-Push_ReEnable.png
new file mode 100644
index 00000000..b3b69953
Binary files /dev/null and b/demo/screenshots/Tab-Me-Push_ReEnable.png differ
diff --git a/demo/screenshots/Tab-Me-Push_Top.png b/demo/screenshots/Tab-Me-Push_Top.png
new file mode 100644
index 00000000..a62fb995
Binary files /dev/null and b/demo/screenshots/Tab-Me-Push_Top.png differ
diff --git a/demo/screenshots/Tab-Me-Settings-Appearance.png b/demo/screenshots/Tab-Me-Settings-Appearance.png
new file mode 100644
index 00000000..c6723283
Binary files /dev/null and b/demo/screenshots/Tab-Me-Settings-Appearance.png differ
diff --git a/demo/screenshots/Tab-Me-Settings-DarkTheme.png b/demo/screenshots/Tab-Me-Settings-DarkTheme.png
new file mode 100644
index 00000000..e0f968f9
Binary files /dev/null and b/demo/screenshots/Tab-Me-Settings-DarkTheme.png differ
diff --git a/demo/screenshots/Tab-Me-Settings-FontSize.png b/demo/screenshots/Tab-Me-Settings-FontSize.png
new file mode 100644
index 00000000..af70d0c9
Binary files /dev/null and b/demo/screenshots/Tab-Me-Settings-FontSize.png differ
diff --git a/demo/screenshots/Tab-Me-Settings-OpeningLink.png b/demo/screenshots/Tab-Me-Settings-OpeningLink.png
new file mode 100644
index 00000000..d820a1be
Binary files /dev/null and b/demo/screenshots/Tab-Me-Settings-OpeningLink.png differ
diff --git a/demo/screenshots/Tab-Me-Settings.png b/demo/screenshots/Tab-Me-Settings.png
new file mode 100644
index 00000000..efdd60fc
Binary files /dev/null and b/demo/screenshots/Tab-Me-Settings.png differ
diff --git a/demo/screenshots/Tab-Me-Switch.png b/demo/screenshots/Tab-Me-Switch.png
new file mode 100644
index 00000000..0b1129e9
Binary files /dev/null and b/demo/screenshots/Tab-Me-Switch.png differ
diff --git a/demo/screenshots/Tab-Me.png b/demo/screenshots/Tab-Me.png
new file mode 100644
index 00000000..a601e90c
Binary files /dev/null and b/demo/screenshots/Tab-Me.png differ
diff --git a/demo/screenshots/Tab-Notifications-Filter.png b/demo/screenshots/Tab-Notifications-Filter.png
new file mode 100644
index 00000000..e2f5daaf
Binary files /dev/null and b/demo/screenshots/Tab-Notifications-Filter.png differ
diff --git a/demo/screenshots/Tab-Notifications.png b/demo/screenshots/Tab-Notifications.png
new file mode 100644
index 00000000..53707170
Binary files /dev/null and b/demo/screenshots/Tab-Notifications.png differ
diff --git a/demo/screenshots/Tab-Public.png b/demo/screenshots/Tab-Public.png
new file mode 100644
index 00000000..e6e3a0f0
Binary files /dev/null and b/demo/screenshots/Tab-Public.png differ
diff --git a/demo/screenshots/Tab-Shared-Account.png b/demo/screenshots/Tab-Shared-Account.png
new file mode 100644
index 00000000..a39301bf
Binary files /dev/null and b/demo/screenshots/Tab-Shared-Account.png differ
diff --git a/demo/screenshots/Tab-Shared-AccountInLists.png b/demo/screenshots/Tab-Shared-AccountInLists.png
new file mode 100644
index 00000000..623915f6
Binary files /dev/null and b/demo/screenshots/Tab-Shared-AccountInLists.png differ
diff --git a/demo/screenshots/Tab-Shared-Attachments.png b/demo/screenshots/Tab-Shared-Attachments.png
new file mode 100644
index 00000000..cbc46c80
Binary files /dev/null and b/demo/screenshots/Tab-Shared-Attachments.png differ
diff --git a/demo/screenshots/Tab-Shared-Hashtag.png b/demo/screenshots/Tab-Shared-Hashtag.png
new file mode 100644
index 00000000..642cac97
Binary files /dev/null and b/demo/screenshots/Tab-Shared-Hashtag.png differ
diff --git a/demo/screenshots/Tab-Shared-History.png b/demo/screenshots/Tab-Shared-History.png
new file mode 100644
index 00000000..ef9a5ab2
Binary files /dev/null and b/demo/screenshots/Tab-Shared-History.png differ
diff --git a/demo/screenshots/Tab-Shared-Search.png b/demo/screenshots/Tab-Shared-Search.png
new file mode 100644
index 00000000..9fd18b89
Binary files /dev/null and b/demo/screenshots/Tab-Shared-Search.png differ
diff --git a/demo/screenshots/Tab-Shared-Toot.png b/demo/screenshots/Tab-Shared-Toot.png
new file mode 100644
index 00000000..148478ea
Binary files /dev/null and b/demo/screenshots/Tab-Shared-Toot.png differ
diff --git a/demo/statuses.ts b/demo/statuses.ts
index 63d5e47a..1da8785c 100644
--- a/demo/statuses.ts
+++ b/demo/statuses.ts
@@ -1,6 +1,7 @@
-const demoStatuses = [
+const demoStatus: Mastodon.Status[] = [
{
id: '1',
+ uri: 'https://example.com',
created_at: new Date().toISOString(),
sensitive: false,
visibility: 'public',
@@ -13,7 +14,6 @@ const demoStatuses = [
bookmarked: false,
content:
'
Would you like to try out this simple, beautiful and open-source mobile app for Mastodon? 😊
',
- reblog: null,
application: {
name: 'tooot',
website: 'https://tooot.app'
@@ -23,19 +23,31 @@ const demoStatuses = [
username: 'tooot📱',
acct: 'tooot@xmflsct.com',
display_name: 'tooot📱',
- avatar_static:
- 'https://avatars.githubusercontent.com/u/77554750?s=200&v=4'
+ avatar: 'https://avatars.githubusercontent.com/u/77554750?s=200&v=4',
+ avatar_static: 'https://avatars.githubusercontent.com/u/77554750?s=200&v=4',
+ url: '',
+ header: '',
+ header_static: '',
+ locked: false,
+ discoverable: false,
+ created_at: new Date().toISOString(),
+ last_status_at: new Date().toISOString(),
+ statuses_count: 1,
+ followers_count: 1,
+ following_count: 1,
+ fields: [],
+ bot: false
},
media_attachments: [],
poll: {
id: '1',
- expires_at: new Date().setDate(new Date().getDate() + 5),
+ expires_at: new Date().setDate(new Date().getDate() + 5).toString(),
expired: false,
multiple: false,
votes_count: 10,
- voters_count: null,
+ voters_count: 2,
voted: false,
- own_votes: null,
+ own_votes: undefined,
options: [
{
title: 'I would love to!',
@@ -48,11 +60,15 @@ const demoStatuses = [
],
emojis: []
},
- mentions: []
+ mentions: [],
+ tags: [],
+ emojis: [],
+ pinned: false
},
{
id: '2',
- created_at: new Date().setMinutes(new Date().getMinutes() - 2),
+ uri: 'https://example.com',
+ created_at: new Date().setMinutes(new Date().getMinutes() - 2).toString(),
sensitive: false,
spoiler_text: '',
visibility: 'public',
@@ -65,18 +81,26 @@ const demoStatuses = [
bookmarked: false,
content:
'Mastodon is a free and open-source self-hosted social networking service. It allows anyone to host their own server node in the network, and its various separately operated user bases are federated across many different servers. These nodes are referred to as "instances" by Mastodon users.
',
- reblog: null,
- application: {
- name: 'Web',
- website: null
- },
+ application: { name: 'Web' },
account: {
id: '1000',
username: 'Mastodon',
acct: 'mastodon',
display_name: 'Mastodon',
- avatar_static:
- 'https://mastodon.social/apple-touch-icon.png'
+ avatar: 'https://mastodon.social/apple-touch-icon.png',
+ avatar_static: 'https://mastodon.social/apple-touch-icon.png',
+ url: '',
+ header: '',
+ header_static: '',
+ locked: false,
+ discoverable: false,
+ created_at: new Date().toISOString(),
+ last_status_at: new Date().toISOString(),
+ statuses_count: 1,
+ followers_count: 1,
+ following_count: 1,
+ fields: [],
+ bot: false
},
media_attachments: [],
card: {
@@ -85,18 +109,31 @@ const demoStatuses = [
description:
'Mastodon is an open source decentralized social network - by the people for the people. Join the federation and take back control of your social media!',
type: 'link',
- image:
- 'https://mastodon.social/apple-touch-icon.png'
+ image: 'https://mastodon.social/apple-touch-icon.png',
+ author_name: '',
+ author_url: '',
+ provider_name: '',
+ provider_url: '',
+ html: '
',
+ width: 100,
+ height: 100,
+ embed_url: 'https://example.com',
+ blurhash: ''
},
- mentions: []
+ mentions: [],
+ tags: [],
+ emojis: [],
+ pinned: false
},
{
id: '3',
- created_at: '2021-01-24T09:50:00.901Z',
+ uri: '',
+ created_at: new Date().setHours(new Date().getHours() - 1).toString(),
+ sensitive: false,
spoiler_text: '',
visibility: 'public',
replies_count: 2,
- reblogs_count: null,
+ reblogs_count: 1,
favourites_count: 3,
favourited: false,
reblogged: false,
@@ -104,24 +141,38 @@ const demoStatuses = [
bookmarked: true,
content:
'These servers are connected as a federated social network, allowing users from different servers to interact with each other seamlessly. Once a Mastodon server knows another Mastodon server, it "federates" with the other Mastodon server. Mastodon is a part of the wider Fediverse, allowing its users to also interact with users on different open platforms that support the same protocol, such as PeerTube and Friendica.
',
- reblog: null,
- application: {
- name: 'Web',
- website: null
- },
+ application: { name: 'Web' },
account: {
id: '1001',
username: 'Fediverse',
acct: 'fediverse',
display_name: 'Fediverse',
+ avatar:
+ 'https://e7.pngegg.com/pngimages/667/514/png-clipart-mastodon-fediverse-social-media-free-software-logo-social-media-blue-text.png',
avatar_static:
- 'https://e7.pngegg.com/pngimages/667/514/png-clipart-mastodon-fediverse-social-media-free-software-logo-social-media-blue-text.png'
+ 'https://e7.pngegg.com/pngimages/667/514/png-clipart-mastodon-fediverse-social-media-free-software-logo-social-media-blue-text.png',
+ url: '',
+ header: '',
+ header_static: '',
+ locked: false,
+ discoverable: false,
+ created_at: new Date().toISOString(),
+ last_status_at: new Date().toISOString(),
+ statuses_count: 1,
+ followers_count: 1,
+ following_count: 1,
+ fields: [],
+ bot: false
},
media_attachments: [],
- mentions: []
+ mentions: [],
+ tags: [],
+ emojis: [],
+ pinned: false
},
{
id: '4',
+ uri: 'https://example.com',
created_at: '2021-01-24T08:50:00.901Z',
sensitive: false,
visibility: 'public',
@@ -134,7 +185,6 @@ const demoStatuses = [
bookmarked: false,
content:
'tooot is an open source, simple mobile client for Mastodon. Focusing on your connections while being able to explore the Fediverse.
',
- reblog: null,
application: {
name: 'tooot',
website: 'https://tooot.app'
@@ -144,14 +194,30 @@ const demoStatuses = [
username: 'tooot📱',
acct: 'tooot@xmflsct.com',
display_name: 'tooot📱',
- avatar_static:
- 'https://avatars.githubusercontent.com/u/77554750?s=200&v=4'
+ avatar: 'https://avatars.githubusercontent.com/u/77554750?s=200&v=4',
+ avatar_static: 'https://avatars.githubusercontent.com/u/77554750?s=200&v=4',
+ url: '',
+ header: '',
+ header_static: '',
+ locked: false,
+ discoverable: false,
+ created_at: new Date().toISOString(),
+ last_status_at: new Date().toISOString(),
+ statuses_count: 1,
+ followers_count: 1,
+ following_count: 1,
+ fields: [],
+ bot: false
},
media_attachments: [],
- mentions: []
+ mentions: [],
+ tags: [],
+ emojis: [],
+ pinned: false
},
{
id: '5',
+ uri: 'https://example.com',
created_at: '2021-01-24T07:50:00.901Z',
sensitive: false,
visibility: 'public',
@@ -164,7 +230,6 @@ const demoStatuses = [
bookmarked: false,
content:
'- tooot supports multiple accounts - tooot supports browsing external instance - tooot aims to support multiple languages
',
- reblog: null,
application: {
name: 'tooot',
website: 'https://tooot.app'
@@ -174,12 +239,27 @@ const demoStatuses = [
username: 'tooot📱',
acct: 'tooot@xmflsct.com',
display_name: 'tooot📱',
- avatar_static:
- 'https://avatars.githubusercontent.com/u/77554750?s=200&v=4'
+ avatar: 'https://avatars.githubusercontent.com/u/77554750?s=200&v=4',
+ avatar_static: 'https://avatars.githubusercontent.com/u/77554750?s=200&v=4',
+ url: '',
+ header: '',
+ header_static: '',
+ locked: false,
+ discoverable: false,
+ created_at: new Date().toISOString(),
+ last_status_at: new Date().toISOString(),
+ statuses_count: 1,
+ followers_count: 1,
+ following_count: 1,
+ fields: [],
+ bot: false
},
media_attachments: [],
- mentions: []
+ mentions: [],
+ tags: [],
+ emojis: [],
+ pinned: false
}
]
-export default demoStatuses
+export default demoStatus
diff --git a/fastlane/Fastfile b/fastlane/Fastfile
index c4d1f624..66d35884 100644
--- a/fastlane/Fastfile
+++ b/fastlane/Fastfile
@@ -108,6 +108,29 @@ private_lane :build_android do
end
end
+desc "Build Android apk"
+private_lane :build_android_apk do
+ sh("echo #{ENV["ANDROID_KEYSTORE"]} | base64 -d | tee #{File.expand_path('..', Dir.pwd)}/android/tooot.jks >/dev/null", log: false)
+
+ prepare_playstore_android
+
+ build_android_app(
+ task: 'assemble',
+ build_type: 'release',
+ project_dir: "./android",
+ print_command: true,
+ print_command_output: true,
+ properties: {
+ "android.injected.signing.store.file" => "#{File.expand_path('..', Dir.pwd)}/android/tooot.jks",
+ "android.injected.signing.store.password" => ENV["ANDROID_KEYSTORE_PASSWORD"],
+ "android.injected.signing.key.alias" => ENV["ANDROID_KEYSTORE_ALIAS"],
+ "android.injected.signing.key.password" => ENV["ANDROID_KEYSTORE_KEY_PASSWORD"],
+ }
+ )
+
+ sh "mv #{lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH]} #{File.expand_path('..', Dir.pwd)}/tooot-#{GITHUB_RELEASE}.apk"
+end
+
lane :ios do
cocoapods(clean_install: true, podfile: "./ios/Podfile")
build_ios
@@ -121,13 +144,15 @@ end
lane :release do
if ENVIRONMENT == 'release'
+ build_android_apk
set_github_release(
repository_name: GITHUB_REPO,
name: GITHUB_RELEASE,
tag_name: GITHUB_RELEASE,
description: "No changelog provided",
commitish: git_branch,
- is_prerelease: false
+ is_prerelease: false,
+ upload_assets: ["#{File.expand_path('..', Dir.pwd)}/tooot-#{GITHUB_RELEASE}.apk"]
)
end
rocket
diff --git a/fastlane/metadata/en-US/release_notes.txt b/fastlane/metadata/en-US/release_notes.txt
index 12b2cab0..cf45f9e4 100644
--- a/fastlane/metadata/en-US/release_notes.txt
+++ b/fastlane/metadata/en-US/release_notes.txt
@@ -1,3 +1,11 @@
Enjoy toooting! This version includes following improvements and fixes:
-- Fix toot attribution of favourites etc.
-- Fix switching language
\ No newline at end of file
+- Added 🇺🇦 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
+- 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 51453bd1..95a80d31 100644
--- a/fastlane/metadata/zh-Hans/release_notes.txt
+++ b/fastlane/metadata/zh-Hans/release_notes.txt
@@ -1,3 +1,11 @@
toooting愉快!此版本包括以下改进和修复:
-- 修复嘟文收藏等显示
-- 修复不能切换语言
\ No newline at end of file
+- 增加 🇺🇦 Slava Ukraini
+- 自动识别发嘟语言
+- 记住上次公共时间轴选项
+- 显示编辑历史的差异
+- 关注列表可隐藏转嘟和回复
+- 新增管理员推送通知
+- 支持嘟文右到左文字
+- 测试显示对话层级
+- 修复过滤整词功能
+- 修复平板不能删除草稿
\ No newline at end of file
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 82d8d8f0..1ad566ac 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -295,23 +295,21 @@ PODS:
- React-Core
- react-native-blurhash (1.1.10):
- React-Core
- - react-native-cameraroll (5.1.0):
+ - react-native-cameraroll (5.2.0):
- React-Core
- react-native-image-picker (4.10.2):
- React-Core
- react-native-ios-context-menu (1.15.1):
- React-Core
- - react-native-language-detection (0.1.0):
+ - 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):
- React-Core
- react-native-pager-view (6.1.2):
- React-Core
- - react-native-paste-input (0.5.1):
+ - react-native-paste-input (0.5.2):
- React-Core
- Swime (= 3.0.6)
- react-native-safe-area-context (4.4.1):
@@ -428,9 +426,9 @@ PODS:
- RNScreens (3.18.2):
- React-Core
- React-RCTImage
- - RNSentry (4.10.1):
+ - 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:
@@ -736,15 +731,14 @@ SPEC CHECKSUMS:
React-logger: 1623c216abaa88974afce404dc8f479406bbc3a0
react-native-blur: 50c9feabacbc5f49b61337ebc32192c6be7ec3c3
react-native-blurhash: add4df9a937b4e021a24bc67a0714f13e0bd40b7
- react-native-cameraroll: a40b082318eb1ecd0336a2f29d9f74b7f2c8cae8
+ react-native-cameraroll: 0ff04cc4e0ff5f19a94ff4313e5c8bc4503cd86d
react-native-image-picker: bf34f3f516d139ed3e24c5f5a381a91819e349ea
react-native-ios-context-menu: b170594b4448c0cd10c79e13432216bac99de1ac
- react-native-language-detection: 0e43195ad014974f1b7a31b64820eff34a243f2d
- react-native-live-text-image-view: 483bacfdba464162b8cf176bba555364f18b584c
+ react-native-language-detection: f414937fa715108ab50a6269a3de0bcb95e4ceb0
react-native-menu: 8e172cfcf0e42e92f028e7781eddf84d430cae24
react-native-netinfo: 2517ad504b3d303e90d7a431b0fcaef76d207983
react-native-pager-view: 54bed894cecebe28cede54c01038d9d1e122de43
- react-native-paste-input: 183ad7dc224e192719616f4258dde5b548627d08
+ react-native-paste-input: 88709b4fd586ea8cc56ba5e2fc4cdfe90597730c
react-native-safe-area-context: 99b24a0c5acd0d5dcac2b1a7f18c49ea317be99a
react-native-segmented-control: 65df6cd0619b780b3843d574a72d4c7cec396097
React-perflogger: 8c79399b0500a30ee8152d0f9f11beae7fc36595
@@ -765,12 +759,12 @@ SPEC CHECKSUMS:
RNGestureHandler: 62232ba8f562f7dea5ba1b3383494eb5bf97a4d3
RNReanimated: ce445c233a6ff5600223484a88ad5704945d972a
RNScreens: 34cc502acf1b916c582c60003dc3089fa01dc66d
- RNSentry: 3c27f3c57f16bab9835d9555add298571077e0c1
+ RNSentry: 4c09f4dd9740cb9b33e94303de5b6d0dbeb0737d
RNShareMenu: cb9dac548c8bf147d06f0bf07296ad51ea9f5fc3
RNSVG: 3a79c0c4992213e4f06c08e62730c5e7b9e4dc17
SDWebImage: b9a731e1d6307f44ca703b3976d18c24ca561e84
SDWebImageWebPCoder: 18503de6621dd2c420d680e33d46bf8e1d5169b0
- Sentry: b15765d11769852fe78c9add942f7df60ed5dbf5
+ Sentry: 08884c523575ec0f6690d94ed3ccb0246a1600bf
Swime: d7b2c277503b6cea317774aedc2dce05613f8b0b
Yoga: 99caf8d5ab45e9d637ee6e0174ec16fbbb01bcfc
diff --git a/ios/tooot.xcodeproj/project.pbxproj b/ios/tooot.xcodeproj/project.pbxproj
index 6d8698dd..908f700c 100644
--- a/ios/tooot.xcodeproj/project.pbxproj
+++ b/ios/tooot.xcodeproj/project.pbxproj
@@ -86,6 +86,7 @@
E69EBACE28DF28560057EDEC /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/InfoPlist.strings; sourceTree = ""; };
E6A4895D293C1F740047951A /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/InfoPlist.strings; sourceTree = ""; };
E6C8B26628F5F9FC0062CF2E /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InfoPlist.strings; sourceTree = ""; };
+ E6D64C7A294A90840098F3AC /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/InfoPlist.strings; sourceTree = ""; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
ED2971642150620600B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; };
/* End PBXFileReference section */
@@ -298,6 +299,7 @@
sv,
nl,
ca,
+ uk,
);
mainGroup = 83CBB9F61A601CBA00E9B192;
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
@@ -530,6 +532,7 @@
E63E7FF0292A828100C76FD4 /* sv */,
E6217B7E293C1EBF00B1755E /* nl */,
E6A4895D293C1F740047951A /* ca */,
+ E6D64C7A294A90840098F3AC /* uk */,
);
name = InfoPlist.strings;
sourceTree = "";
@@ -574,6 +577,7 @@
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_OBJC_BRIDGING_HEADER = "tooot-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_PRECOMPILE_BRIDGING_HEADER = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2,6";
VERSIONING_SYSTEM = "apple-generic";
@@ -611,6 +615,7 @@
SUPPORTS_MACCATALYST = YES;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_OBJC_BRIDGING_HEADER = "tooot-Bridging-Header.h";
+ SWIFT_PRECOMPILE_BRIDGING_HEADER = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2,6";
VERSIONING_SYSTEM = "apple-generic";
@@ -781,6 +786,7 @@
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "ShareExtension/ShareExtension-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_PRECOMPILE_BRIDGING_HEADER = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2,6";
};
@@ -828,6 +834,7 @@
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "ShareExtension/ShareExtension-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-O";
+ SWIFT_PRECOMPILE_BRIDGING_HEADER = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2,6";
};
diff --git a/ios/uk.lproj/InfoPlist.strings b/ios/uk.lproj/InfoPlist.strings
new file mode 100644
index 00000000..a23b678c
--- /dev/null
+++ b/ios/uk.lproj/InfoPlist.strings
@@ -0,0 +1,2 @@
+"NSPhotoLibraryAddUsageDescription" = "Дозвольте tooot зберігати зображення у вашій папці фотоапарата";
+"NSPhotoLibraryUsageDescription" = "Дозвольте tooot зберігати зображення у вашій папці фотоапарата";
diff --git a/package.json b/package.json
index b822761c..b10cfe1c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "tooot",
- "version": "4.6.6",
+ "version": "4.7.0",
"description": "tooot for Mastodon",
"author": "xmflsct ",
"license": "GPL-3.0-or-later",
@@ -12,7 +12,7 @@
"start": "react-native start",
"android": "react-native run-android",
"iphone": "react-native run-ios --simulator 'iPhone 14 Pro'",
- "ipad": "react-native run-ios --simulator 'iPad Pro (11-inch) (3rd generation)'",
+ "ipad": "react-native run-ios --simulator 'iPad Pro (11-inch) (4th generation)'",
"app:build": "bundle exec fastlane",
"clean": "react-native-clean-project",
"postinstall": "patch-package"
@@ -25,23 +25,25 @@
"@formatjs/intl-numberformat": "^8.3.3",
"@formatjs/intl-pluralrules": "^5.1.8",
"@formatjs/intl-relativetimeformat": "^11.1.8",
- "@mattermost/react-native-paste-input": "^0.5.1",
+ "@mattermost/react-native-paste-input": "^0.5.2",
"@neverdull-agency/expo-unlimited-secure-store": "^1.0.10",
"@react-native-async-storage/async-storage": "~1.17.11",
- "@react-native-camera-roll/camera-roll": "^5.1.0",
+ "@react-native-camera-roll/camera-roll": "^5.2.0",
"@react-native-clipboard/clipboard": "^1.11.1",
"@react-native-community/blur": "^4.3.0",
"@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.4.3",
- "@react-navigation/native": "^6.0.16",
- "@react-navigation/native-stack": "^6.9.4",
- "@react-navigation/stack": "^6.3.7",
+ "@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.10.1",
+ "@sentry/react-native": "4.12.0",
"@sharcoux/slider": "^6.1.1",
- "axios": "^0.27.2",
+ "@tanstack/react-query": "^4.20.4",
+ "axios": "^1.2.1",
+ "diff": "^5.1.0",
"expo": "^47.0.8",
"expo-auth-session": "^3.7.3",
"expo-av": "^13.0.2",
@@ -59,13 +61,12 @@
"expo-store-review": "^6.0.0",
"expo-video-thumbnails": "^7.0.0",
"expo-web-browser": "~12.0.0",
- "i18next": "^22.0.6",
- "li": "^1.3.0",
+ "i18next": "^22.4.5",
"linkify-it": "^4.0.1",
"lodash": "^4.17.21",
"react": "^18.2.0",
"react-dom": "^18.2.0",
- "react-i18next": "^12.0.0",
+ "react-i18next": "^12.1.1",
"react-intl": "^6.2.5",
"react-native": "0.70.6",
"react-native-animated-spinkit": "^1.5.2",
@@ -78,8 +79,7 @@
"react-native-htmlview": "^0.16.0",
"react-native-image-picker": "^4.10.2",
"react-native-ios-context-menu": "^1.15.1",
- "react-native-language-detection": "^0.1.0",
- "react-native-live-text-image-view": "^0.4.0",
+ "react-native-language-detection": "^0.2.2",
"react-native-pager-view": "^6.1.2",
"react-native-reanimated": "^2.13.0",
"react-native-reanimated-zoom": "^0.3.3",
@@ -88,11 +88,11 @@
"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.2",
- "react-query": "^3.39.2",
+ "react-native-tab-view": "^3.3.4",
"react-redux": "^8.0.5",
"redux-persist": "^6.0.0",
"rn-placeholder": "^3.0.3",
+ "rtl-detect": "^1.0.4",
"valid-url": "^1.0.9",
"zeego": "^0.5.0"
},
@@ -102,11 +102,12 @@
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"@expo/config": "^7.0.3",
+ "@types/diff": "^5.0.2",
"@types/linkify-it": "^3.0.2",
"@types/lodash": "^4.14.191",
"@types/react": "~18.0.26",
"@types/react-dom": "~18.0.9",
- "@types/react-native": "~0.70.7",
+ "@types/react-native": "~0.70.8",
"@types/react-native-base64": "^0.2.0",
"@types/react-native-share-menu": "^5.0.2",
"@types/react-timeago": "^4.1.3",
@@ -120,6 +121,6 @@
"patch-package": "^6.5.0",
"postinstall-postinstall": "^2.1.0",
"react-native-clean-project": "^4.0.1",
- "typescript": "^4.9.3"
+ "typescript": "^4.9.4"
}
}
diff --git a/src/@types/app.d.ts b/src/@types/app.d.ts
index 0db454c2..3b2b9525 100644
--- a/src/@types/app.d.ts
+++ b/src/@types/app.d.ts
@@ -3,13 +3,12 @@ declare namespace App {
| 'Following'
| 'Local'
| 'LocalPublic'
+ | 'Trending'
| 'Notifications'
| 'Hashtag'
| 'List'
| 'Toot'
- | 'Account_Default'
- | 'Account_All'
- | 'Account_Attachments'
+ | 'Account'
| 'Conversations'
| 'Bookmarks'
| 'Favourites'
diff --git a/src/@types/mastodon.d.ts b/src/@types/mastodon.d.ts
index 54bc1571..699cbd16 100644
--- a/src/@types/mastodon.d.ts
+++ b/src/@types/mastodon.d.ts
@@ -30,6 +30,7 @@ declare namespace Mastodon {
bot: boolean
source?: Source
suspended?: boolean
+ role?: Role
}
type Announcement = {
@@ -332,24 +333,34 @@ declare namespace Mastodon {
url: string
}
- type Notification = {
- // Base
- id: string
- type:
- | 'follow'
- | 'follow_request'
- | 'mention'
- | 'reblog'
- | 'favourite'
- | 'poll'
- | 'status'
- | 'update'
- created_at: string
- account: Account
-
- // Others
- status?: Status
- }
+ type Notification =
+ | {
+ // Base
+ id: string
+ type: 'favourite' | 'mention' | 'poll' | 'reblog' | 'status' | 'update'
+ created_at: string
+ account: Account
+ status: Status
+ report: undefined
+ }
+ | {
+ // Base
+ id: string
+ type: 'follow' | 'follow_request' | 'admin.sign_up'
+ created_at: string
+ account: Account
+ status: undefined
+ report: undefined
+ }
+ | {
+ // Base
+ id: string
+ type: 'admin.report'
+ created_at: string
+ account: Account
+ status: undefined
+ report: Report
+ }
type Poll = {
// Base
@@ -384,6 +395,9 @@ declare namespace Mastodon {
mention: boolean
poll: boolean
status: boolean
+ update: boolean
+ 'admin.sign_up': boolean
+ 'admin.report': boolean
}
server_key: string
}
@@ -403,12 +417,37 @@ declare namespace Mastodon {
note: string
}
+ type Report = {
+ id: string
+ action_taken: boolean
+ action_taken_at?: string
+ category: 'spam' | 'violation' | 'other'
+ comment: string
+ forwarded: boolean
+ created_at: string
+ status_ids?: string[]
+ rule_ids?: string[]
+ target_account: Account
+ }
+
type Results = {
accounts?: Account[]
statuses?: Status[]
hashtags?: Tag[]
}
+ type Role = {
+ // Added since 4.0
+ id: string
+ name: string
+ color: string
+ position: number
+ permissions: string
+ highlighted: boolean
+ created_at: string
+ updated_at: string
+ }
+
type Status = {
// Base
id: string
@@ -479,25 +518,4 @@ declare namespace Mastodon {
history: { day: string; accounts: string; uses: string }[]
following: boolean // Since v4.0
}
-
- type WebSocketStream =
- | 'user'
- | 'public'
- | 'public:local'
- | 'hashtag'
- | 'hashtag:local'
- | 'list'
- | 'direct'
- type WebSocket =
- | {
- stream: WebSocketStream[]
- event: 'update'
- payload: string // Status
- }
- | { stream: WebSocketStream[]; event: 'delete'; payload: Status['id'] }
- | {
- stream: WebSocketStream[]
- event: 'notification'
- payload: string // Notification
- }
}
diff --git a/src/@types/untyped.d.ts b/src/@types/untyped.d.ts
index e3b7bc1a..ad27df89 100644
--- a/src/@types/untyped.d.ts
+++ b/src/@types/untyped.d.ts
@@ -1,9 +1,9 @@
declare module 'gl-react-blurhash'
declare module 'htmlparser2-without-node-native'
-declare module 'li'
declare module 'react-native-feather'
declare module 'react-native-htmlview'
declare module 'react-native-toast-message'
+declare module 'rtl-detect'
declare module '@helpers/features' {
const features: { feature: string; version: number; reference?: string }[]
diff --git a/src/App.tsx b/src/App.tsx
index 92dcc448..5d77d55a 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -23,7 +23,7 @@ import { LogBox, Platform } from 'react-native'
import { GestureHandlerRootView } from 'react-native-gesture-handler'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import { enableFreeze } from 'react-native-screens'
-import { QueryClientProvider } from 'react-query'
+import { QueryClientProvider } from '@tanstack/react-query'
import { Provider } from 'react-redux'
import { PersistGate } from 'redux-persist/integration/react'
diff --git a/src/Screens.tsx b/src/Screens.tsx
index f5686550..e7430d1f 100644
--- a/src/Screens.tsx
+++ b/src/Screens.tsx
@@ -135,10 +135,7 @@ const Screens: React.FC = ({ localCorrupt }) => {
instance => paths[0] === `@${instance.account.acct}@${instance.uri}`
)
if (instanceIndex !== -1 && instanceActive !== instanceIndex) {
- initQuery({
- instance: instances[instanceIndex],
- prefetch: { enabled: true }
- })
+ initQuery({ instance: instances[instanceIndex] })
}
}
}
diff --git a/src/api/general.ts b/src/api/general.ts
index 81e993f5..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 ') +
' ' +
@@ -47,9 +47,27 @@ const apiGeneral = async ({
...(body && { data: body })
})
.then(response => {
- return Promise.resolve({
- body: response.data
- })
+ let links: {
+ prev?: { id: string; isOffset: boolean }
+ next?: { id: string; isOffset: boolean }
+ } = {}
+
+ if (response.headers?.link) {
+ const linksParsed = response.headers.link.matchAll(
+ new RegExp('[?&](.*?_id|offset)=(.*?)>; *rel="(.*?)"', 'gi')
+ )
+ for (const link of linksParsed) {
+ switch (link[3]) {
+ case 'prev':
+ links.prev = { id: link[2], isOffset: link[1].includes('offset') }
+ break
+ case 'next':
+ links.next = { id: link[2], isOffset: link[1].includes('offset') }
+ break
+ }
+ }
+ }
+ return Promise.resolve({ body: response.data, links })
})
.catch(handleError())
}
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 a178a42c..d6446e8f 100644
--- a/src/api/instance.ts
+++ b/src/api/instance.ts
@@ -1,7 +1,6 @@
import { RootState } from '@root/store'
import axios, { AxiosRequestConfig } from 'axios'
-import li from 'li'
-import { ctx, handleError, userAgent } from './helpers'
+import { ctx, handleError, PagedResponse, userAgent } from './helpers'
export type Params = {
method: 'get' | 'post' | 'put' | 'delete' | 'patch'
@@ -15,11 +14,6 @@ export type Params = {
extras?: Omit
}
-export type InstanceResponse = {
- body: T
- links: { prev?: string; next?: string }
-}
-
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)
@@ -74,17 +68,27 @@ const apiInstance = async ({
...extras
})
.then(response => {
- let prev
- let next
+ let links: {
+ prev?: { id: string; isOffset: boolean }
+ next?: { id: string; isOffset: boolean }
+ } = {}
+
if (response.headers?.link) {
- const headersLinks = li.parse(response.headers?.link)
- prev = headersLinks.prev?.match(/_id=([0-9]*)/)?.[1]
- next = headersLinks.next?.match(/_id=([0-9]*)/)?.[1]
+ const linksParsed = response.headers.link.matchAll(
+ new RegExp('[?&](.*?_id|offset)=(.*?)>; *rel="(.*?)"', 'gi')
+ )
+ for (const link of linksParsed) {
+ switch (link[3]) {
+ case 'prev':
+ links.prev = { id: link[2], isOffset: link[1].includes('offset') }
+ break
+ case 'next':
+ links.next = { id: link[2], isOffset: link[1].includes('offset') }
+ break
+ }
+ }
}
- return Promise.resolve({
- body: response.data,
- links: { prev, next }
- })
+ return Promise.resolve({ body: response.data, links })
})
.catch(handleError())
}
diff --git a/src/components/AccountButton.tsx b/src/components/AccountButton.tsx
index cddce028..21ef8288 100644
--- a/src/components/AccountButton.tsx
+++ b/src/components/AccountButton.tsx
@@ -12,11 +12,7 @@ interface Props {
additionalActions?: () => void
}
-const AccountButton: React.FC = ({
- instance,
- selected = false,
- additionalActions
-}) => {
+const AccountButton: React.FC = ({ instance, selected = false, additionalActions }) => {
const navigation = useNavigation()
return (
@@ -27,12 +23,10 @@ const AccountButton: React.FC = ({
marginBottom: StyleConstants.Spacing.M,
marginRight: StyleConstants.Spacing.M
}}
- content={`@${instance.account.acct}@${instance.uri}${
- selected ? ' ✓' : ''
- }`}
+ content={`@${instance.account.acct}@${instance.uri}${selected ? ' ✓' : ''}`}
onPress={() => {
haptics('Light')
- initQuery({ instance, prefetch: { enabled: true } })
+ initQuery({ instance })
navigation.goBack()
if (additionalActions) {
additionalActions()
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/components/Hashtag.tsx b/src/components/Hashtag.tsx
index 2d05edc9..1402d7ac 100644
--- a/src/components/Hashtag.tsx
+++ b/src/components/Hashtag.tsx
@@ -3,8 +3,8 @@ import { StackNavigationProp } from '@react-navigation/stack'
import { TabLocalStackParamList } from '@utils/navigation/navigators'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
-import React, { useCallback, useState } from 'react'
-import { Dimensions, Pressable } from 'react-native'
+import React, { PropsWithChildren, useCallback, useState } from 'react'
+import { Dimensions, Pressable, View } from 'react-native'
import Sparkline from './Sparkline'
import CustomText from './Text'
@@ -13,7 +13,11 @@ export interface Props {
onPress?: () => void
}
-const ComponentHashtag: React.FC = ({ hashtag, onPress: customOnPress }) => {
+const ComponentHashtag: React.FC = ({
+ hashtag,
+ onPress: customOnPress,
+ children
+}) => {
const { colors } = useTheme()
const navigation = useNavigation>()
@@ -31,15 +35,11 @@ const ComponentHashtag: React.FC = ({ hashtag, onPress: customOnPress })
style={{
flex: 1,
flexDirection: 'row',
+ alignItems: 'center',
justifyContent: 'space-between',
padding
}}
onPress={customOnPress || onPress}
- onLayout={({
- nativeEvent: {
- layout: { height }
- }
- }) => setHeight(height - padding * 2 - 1)}
>
= ({ hashtag, onPress: customOnPress })
>
#{hashtag.name}
- parseInt(h.uses)).reverse()}
- width={width}
- height={height}
- />
+ setHeight(height)}
+ >
+ parseInt(h.uses)).reverse()}
+ width={width}
+ height={height}
+ margin={children ? StyleConstants.Spacing.S : undefined}
+ />
+ {children}
+
)
}
diff --git a/src/components/Header/Center.tsx b/src/components/Header/Center.tsx
index 2a700fab..d61e3bfa 100644
--- a/src/components/Header/Center.tsx
+++ b/src/components/Header/Center.tsx
@@ -1,6 +1,4 @@
-import Icon from '@components/Icon'
import CustomText from '@components/Text'
-import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React from 'react'
import { View } from 'react-native'
@@ -9,16 +7,10 @@ export interface Props {
content?: string
inverted?: boolean
onPress?: () => void
- dropdown?: boolean
}
// Used for Android mostly
-const HeaderCenter: React.FC = ({
- content,
- inverted = false,
- onPress,
- dropdown = false
-}) => {
+const HeaderCenter: React.FC = ({ content, inverted = false, onPress }) => {
const { colors } = useTheme()
return (
@@ -33,13 +25,6 @@ const HeaderCenter: React.FC = ({
children={content}
{...(onPress && { onPress })}
/>
-
)
}
diff --git a/src/components/Icon.tsx b/src/components/Icon.tsx
index 735620ed..37c7e61e 100644
--- a/src/components/Icon.tsx
+++ b/src/components/Icon.tsx
@@ -11,6 +11,7 @@ export interface Props {
fill?: string
strokeWidth?: number
style?: StyleProp
+ crossOut?: boolean
}
const Icon: React.FC = ({
@@ -20,7 +21,8 @@ const Icon: React.FC = ({
color,
fill,
strokeWidth = 2,
- style
+ style,
+ crossOut = false
}) => {
return (
= ({
fill,
strokeWidth
})}
+ {crossOut ? (
+
+ ) : null}
)
}
diff --git a/src/components/Instance/Auth.tsx b/src/components/Instance/Auth.tsx
deleted file mode 100644
index 1a72e2b5..00000000
--- a/src/components/Instance/Auth.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-import browserPackage from '@helpers/browserPackage'
-import { useNavigation } from '@react-navigation/native'
-import { useAppDispatch } from '@root/store'
-import { InstanceLatest } from '@utils/migrations/instances/migration'
-import { TabMeStackNavigationProp } from '@utils/navigation/navigators'
-import addInstance from '@utils/slices/instances/add'
-import { checkInstanceFeature } from '@utils/slices/instancesSlice'
-import * as AuthSession from 'expo-auth-session'
-import React, { useEffect } from 'react'
-import { useQueryClient } from 'react-query'
-import { useSelector } from 'react-redux'
-
-export interface Props {
- instanceDomain: string
- // Domain can be different than uri
- instance: Mastodon.Instance
- appData: InstanceLatest['appData']
- goBack?: boolean
-}
-
-const InstanceAuth = React.memo(
- ({ instanceDomain, instance, appData, goBack }: Props) => {
- const redirectUri = AuthSession.makeRedirectUri({
- native: 'tooot://instance-auth',
- useProxy: false
- })
-
- const navigation = useNavigation>()
- const queryClient = useQueryClient()
- const dispatch = useAppDispatch()
-
- const deprecateAuthFollow = useSelector(checkInstanceFeature('deprecate_auth_follow'))
- const [request, response, promptAsync] = AuthSession.useAuthRequest(
- {
- clientId: appData.clientId,
- clientSecret: appData.clientSecret,
- scopes: deprecateAuthFollow
- ? ['read', 'write', 'push']
- : ['read', 'write', 'follow', 'push'],
- redirectUri
- },
- {
- authorizationEndpoint: `https://${instanceDomain}/oauth/authorize`
- }
- )
- useEffect(() => {
- ;(async () => {
- if (request?.clientId) {
- await promptAsync({ browserPackage: await browserPackage() }).catch(e => console.log(e))
- }
- })()
- }, [request])
- useEffect(() => {
- ;(async () => {
- if (response?.type === 'success') {
- const { accessToken } = await AuthSession.exchangeCodeAsync(
- {
- clientId: appData.clientId,
- clientSecret: appData.clientSecret,
- scopes: ['read', 'write', 'follow', 'push'],
- redirectUri,
- code: response.params.code,
- extraParams: {
- grant_type: 'authorization_code'
- }
- },
- {
- tokenEndpoint: `https://${instanceDomain}/oauth/token`
- }
- )
- queryClient.clear()
- dispatch(
- addInstance({
- domain: instanceDomain,
- token: accessToken,
- instance,
- appData
- })
- )
- goBack && navigation.goBack()
- }
- })()
- }, [response])
-
- return <>>
- },
- () => true
-)
-
-export default InstanceAuth
diff --git a/src/components/Instance.tsx b/src/components/Instance/index.tsx
similarity index 74%
rename from src/components/Instance.tsx
rename to src/components/Instance/index.tsx
index b0039b37..e21c49de 100644
--- a/src/components/Instance.tsx
+++ b/src/components/Instance/index.tsx
@@ -1,22 +1,27 @@
import Button from '@components/Button'
import Icon from '@components/Icon'
import browserPackage from '@helpers/browserPackage'
-import { useAppsQuery } from '@utils/queryHooks/apps'
+import { redirectUri, useAppsMutation } from '@utils/queryHooks/apps'
import { useInstanceQuery } from '@utils/queryHooks/instance'
-import { getInstances } from '@utils/slices/instancesSlice'
+import { checkInstanceFeature, getInstances } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
+import * as AuthSession from 'expo-auth-session'
import * as WebBrowser from 'expo-web-browser'
import { debounce } from 'lodash'
-import React, { RefObject, useCallback, useMemo, useState } from 'react'
+import React, { RefObject, useCallback, useState } from 'react'
import { Trans, useTranslation } from 'react-i18next'
import { Alert, Image, KeyboardAvoidingView, Platform, TextInput, View } from 'react-native'
import { ScrollView } from 'react-native-gesture-handler'
import { useSelector } from 'react-redux'
import { Placeholder } from 'rn-placeholder'
-import InstanceAuth from './Instance/Auth'
-import InstanceInfo from './Instance/Info'
-import CustomText from './Text'
+import InstanceInfo from './Info'
+import CustomText from '../Text'
+import { useNavigation } from '@react-navigation/native'
+import { TabMeStackNavigationProp } from '@utils/navigation/navigators'
+import queryClient from '@helpers/queryClient'
+import { useAppDispatch } from '@root/store'
+import addInstance from '@utils/slices/instances/add'
export interface Props {
scrollViewRef?: RefObject
@@ -31,30 +36,64 @@ const ComponentInstance: React.FC = ({
}) => {
const { t } = useTranslation('componentInstance')
const { colors, mode } = useTheme()
+ const navigation = useNavigation>()
+ const [domain, setDomain] = useState('')
+
+ const dispatch = useAppDispatch()
const instances = useSelector(getInstances, () => true)
- const [domain, setDomain] = useState()
-
const instanceQuery = useInstanceQuery({
domain,
options: { enabled: !!domain, retry: false }
})
- const appsQuery = useAppsQuery({
- domain,
- options: { enabled: false, retry: false }
- })
- const onChangeText = useCallback(
- debounce(
- text => {
- setDomain(text.replace(/^http(s)?\:\/\//i, ''))
- appsQuery.remove()
- },
- 1000,
- { trailing: true }
- ),
- []
- )
+ const deprecateAuthFollow = useSelector(checkInstanceFeature('deprecate_auth_follow'))
+
+ const appsMutation = useAppsMutation({
+ retry: false,
+ onSuccess: async (data, variables) => {
+ const clientId = data.client_id
+ const clientSecret = data.client_secret
+
+ const discovery = { authorizationEndpoint: `https://${domain}/oauth/authorize` }
+
+ const request = new AuthSession.AuthRequest({
+ clientId,
+ clientSecret,
+ scopes: deprecateAuthFollow
+ ? ['read', 'write', 'push']
+ : ['read', 'write', 'follow', 'push'],
+ redirectUri
+ })
+ await request.makeAuthUrlAsync(discovery)
+
+ const promptResult = await request.promptAsync(discovery)
+
+ if (promptResult?.type === 'success') {
+ const { accessToken } = await AuthSession.exchangeCodeAsync(
+ {
+ clientId,
+ clientSecret,
+ scopes: ['read', 'write', 'follow', 'push'],
+ redirectUri,
+ code: promptResult.params.code,
+ extraParams: { grant_type: 'authorization_code' }
+ },
+ { tokenEndpoint: `https://${variables.domain}/oauth/token` }
+ )
+ queryClient.clear()
+ dispatch(
+ addInstance({
+ domain,
+ token: accessToken,
+ instance: instanceQuery.data!,
+ appData: { clientId, clientSecret }
+ })
+ )
+ goBack && navigation.goBack()
+ }
+ }
+ })
const processUpdate = useCallback(() => {
if (domain) {
@@ -66,39 +105,15 @@ const ComponentInstance: React.FC = ({
},
{
text: t('common:buttons.continue'),
- onPress: () => {
- appsQuery.refetch()
- }
+ onPress: () => appsMutation.mutate({ domain })
}
])
} else {
- appsQuery.refetch()
+ appsMutation.mutate({ domain })
}
}
}, [domain])
- const requestAuth = useMemo(() => {
- if (
- domain &&
- instanceQuery.data?.uri &&
- appsQuery.data?.client_id &&
- appsQuery.data.client_secret
- ) {
- return (
-
- )
- }
- }, [domain, instanceQuery.data, appsQuery.data])
-
return (
= ({
borderBottomWidth: 1,
...StyleConstants.FontStyle.M,
color: colors.primaryDefault,
- borderBottomColor: instanceQuery.isError ? colors.red : colors.border
+ borderBottomColor: instanceQuery.isError ? colors.red : colors.border,
+ ...(Platform.OS === 'android' && { paddingRight: 0 })
}}
editable={false}
defaultValue='https://'
@@ -143,9 +159,12 @@ const ComponentInstance: React.FC = ({
...StyleConstants.FontStyle.M,
marginRight: StyleConstants.Spacing.M,
color: colors.primaryDefault,
- borderBottomColor: instanceQuery.isError ? colors.red : colors.border
+ borderBottomColor: instanceQuery.isError ? colors.red : colors.border,
+ ...(Platform.OS === 'android' && { paddingLeft: 0 })
}}
- onChangeText={onChangeText}
+ onChangeText={debounce(text => setDomain(text.replace(/^http(s)?\:\/\//i, '')), 1000, {
+ trailing: true
+ })}
autoCapitalize='none'
clearButtonMode='never'
keyboardType='url'
@@ -176,7 +195,7 @@ const ComponentInstance: React.FC = ({
content={t('server.button')}
onPress={processUpdate}
disabled={!instanceQuery.data?.uri}
- loading={instanceQuery.isFetching || appsQuery.isFetching}
+ loading={instanceQuery.isFetching || appsMutation.isLoading}
/>
@@ -276,8 +295,6 @@ const ComponentInstance: React.FC = ({
-
- {requestAuth}
)
}
diff --git a/src/components/Menu/Row.tsx b/src/components/Menu/Row.tsx
index 3953e5c9..2bfe1cdd 100644
--- a/src/components/Menu/Row.tsx
+++ b/src/components/Menu/Row.tsx
@@ -5,7 +5,7 @@ import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import { ColorDefinitions } from '@utils/styles/themes'
import React, { useMemo } from 'react'
-import { Text, View } from 'react-native'
+import { View } from 'react-native'
import { Flow } from 'react-native-animated-spinkit'
import { State, Switch, TapGestureHandler } from 'react-native-gesture-handler'
@@ -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()
@@ -86,9 +85,10 @@ const MenuRow: React.FC = ({
>
{iconFront && (
diff --git a/src/components/Parse/Emojis.tsx b/src/components/Parse/Emojis.tsx
index 6e8df38b..d9e1e88b 100644
--- a/src/components/Parse/Emojis.tsx
+++ b/src/components/Parse/Emojis.tsx
@@ -5,7 +5,7 @@ import { StyleConstants } from '@utils/styles/constants'
import { adaptiveScale } from '@utils/styles/scaling'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useMemo } from 'react'
-import { Platform, StyleSheet } from 'react-native'
+import { Platform, StyleSheet, TextStyle } from 'react-native'
import FastImage from 'react-native-fast-image'
import { useSelector } from 'react-redux'
import validUrl from 'valid-url'
@@ -18,16 +18,11 @@ export interface Props {
size?: 'S' | 'M' | 'L'
adaptiveSize?: boolean
fontBold?: boolean
+ style?: TextStyle
}
const ParseEmojis = React.memo(
- ({
- content,
- emojis,
- size = 'M',
- adaptiveSize = false,
- fontBold = false
- }: Props) => {
+ ({ content, emojis, size = 'M', adaptiveSize = false, fontBold = false, style }: Props) => {
const { reduceMotionEnabled } = useAccessibility()
const adaptiveFontsize = useSelector(getSettingsFontsize)
@@ -51,22 +46,13 @@ const ParseEmojis = React.memo(
image: {
width: adaptedFontsize,
height: adaptedFontsize,
- ...(Platform.OS === 'ios'
- ? {
- transform: [{ translateY: -2 }]
- }
- : {
- transform: [{ translateY: 1 }]
- })
+ ...(Platform.OS === 'android' && { transform: [{ translateY: 2 }] })
}
})
}, [theme, adaptiveFontsize])
return (
-
+
{emojis ? (
content
.split(regexEmoji)
@@ -78,11 +64,7 @@ const ParseEmojis = React.memo(
return emojiShortcode === `:${emoji.shortcode}:`
})
if (emojiIndex === -1) {
- return (
-
- {emojiShortcode}
-
- )
+ return {emojiShortcode}
} else {
const uri = reduceMotionEnabled
? emojis[emojiIndex].static_url
diff --git a/src/components/Parse/HTML.tsx b/src/components/Parse/HTML.tsx
index a2615163..e651a66e 100644
--- a/src/components/Parse/HTML.tsx
+++ b/src/components/Parse/HTML.tsx
@@ -10,9 +10,10 @@ import { StyleConstants } from '@utils/styles/constants'
import layoutAnimation from '@utils/styles/layoutAnimation'
import { adaptiveScale } from '@utils/styles/scaling'
import { useTheme } from '@utils/styles/ThemeManager'
+import { isEqual } from 'lodash'
import React, { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
-import { Platform, Pressable, View } from 'react-native'
+import { Platform, Pressable, TextStyleIOS, View } from 'react-native'
import HTMLView from 'react-native-htmlview'
import { useSelector } from 'react-redux'
@@ -133,13 +134,8 @@ const renderNode = ({
name='ExternalLink'
size={adaptedFontsize}
style={{
- ...(Platform.OS === 'ios'
- ? {
- transform: [{ translateY: -2 }]
- }
- : {
- transform: [{ translateY: 1 }]
- })
+ marginLeft: StyleConstants.Spacing.XS,
+ ...(Platform.OS === 'android' && { transform: [{ translateY: 2 }] })
}}
/>
) : null}
@@ -158,6 +154,7 @@ const renderNode = ({
export interface Props {
content: string
size?: 'S' | 'M' | 'L'
+ textStyles?: TextStyleIOS
adaptiveSize?: boolean
emojis?: Mastodon.Emoji[]
mentions?: Mastodon.Mention[]
@@ -175,6 +172,7 @@ const ParseHTML = React.memo(
({
content,
size = 'M',
+ textStyles,
adaptiveSize = false,
emojis,
mentions,
@@ -200,7 +198,7 @@ const ParseHTML = React.memo(
const navigation = useNavigation>()
const route = useRoute()
const { colors, theme } = useTheme()
- const { t, i18n } = useTranslation('componentParse')
+ const { t } = useTranslation('componentParse')
if (!expandHint) {
expandHint = t('HTML.defaultHint')
}
@@ -298,6 +296,7 @@ const ParseHTML = React.memo(
}
}}
style={{
+ ...textStyles,
height: numberOfLines === 1 && !expanded ? 0 : undefined
}}
numberOfLines={
@@ -308,7 +307,7 @@ const ParseHTML = React.memo(
)
},
- [theme, i18n.language]
+ [theme]
)
return (
@@ -320,7 +319,7 @@ const ParseHTML = React.memo(
/>
)
},
- (prev, next) => prev.content === next.content
+ (prev, next) => prev.content === next.content && isEqual(prev.emojis, next.emojis)
)
export default ParseHTML
diff --git a/src/components/Relationship/Incoming.tsx b/src/components/Relationship/Incoming.tsx
index d6eb633c..837345f6 100644
--- a/src/components/Relationship/Incoming.tsx
+++ b/src/components/Relationship/Incoming.tsx
@@ -8,7 +8,7 @@ import { useTheme } from '@utils/styles/ThemeManager'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { StyleSheet, View } from 'react-native'
-import { useQueryClient } from 'react-query'
+import { useQueryClient } from '@tanstack/react-query'
export interface Props {
id: Mastodon.Account['id']
diff --git a/src/components/Relationship/Outgoing.tsx b/src/components/Relationship/Outgoing.tsx
index b551d670..70a643e0 100644
--- a/src/components/Relationship/Outgoing.tsx
+++ b/src/components/Relationship/Outgoing.tsx
@@ -10,7 +10,7 @@ import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import { useTheme } from '@utils/styles/ThemeManager'
import React from 'react'
import { useTranslation } from 'react-i18next'
-import { useQueryClient } from 'react-query'
+import { useQueryClient } from '@tanstack/react-query'
export interface Props {
id: Mastodon.Account['id']
@@ -30,8 +30,8 @@ const RelationshipOutgoing = React.memo(
haptics('Success')
queryClient.setQueryData(queryKeyRelationship, [res])
if (action === 'block') {
- const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Following' }]
- queryClient.invalidateQueries(queryKey)
+ const queryKey = ['Timeline', { page: 'Following' }]
+ queryClient.invalidateQueries({ queryKey, exact: false })
}
},
onError: (err: any, { payload: { action } }) => {
diff --git a/src/components/Sparkline.tsx b/src/components/Sparkline.tsx
index 21792069..707f28e7 100644
--- a/src/components/Sparkline.tsx
+++ b/src/components/Sparkline.tsx
@@ -1,7 +1,6 @@
import { useTheme } from '@utils/styles/ThemeManager'
import { maxBy, minBy } from 'lodash'
import React from 'react'
-import { Platform } from 'react-native'
import Svg, { G, Path } from 'react-native-svg'
export interface Props {
@@ -69,7 +68,7 @@ const Sparkline: React.FC = ({ data, width, height, margin = 0 }) => {
const fillPoints = linePoints.concat(closePolyPoints)
return (
-
+
>
queryKey: QueryKeyTimeline
+ queryOptions?: Omit<
+ UseInfiniteQueryOptions,
+ 'notifyOnChangeProps' | 'getNextPageParam' | 'getPreviousPageParam' | 'select' | 'onSuccess'
+ >
disableRefresh?: boolean
disableInfinity?: boolean
- lookback?: Extract
- customProps: Partial> &
- Pick, 'renderItem'>
+ customProps: Partial> & Pick, 'renderItem'>
}
const Timeline: React.FC = ({
flRef: customFLRef,
queryKey,
+ queryOptions,
disableRefresh = false,
disableInfinity = false,
customProps
}) => {
const { colors } = useTheme()
- const {
- data,
- refetch,
- isFetching,
- isLoading,
- fetchNextPage,
- isFetchingNextPage
- } = useTimelineQuery({
- ...queryKey[1],
- options: {
- notifyOnChangeProps: Platform.select({
- ios: ['dataUpdatedAt', 'isFetching'],
- android: ['dataUpdatedAt', 'isFetching', 'isLoading']
- }),
- getNextPageParam: lastPage =>
- lastPage?.links?.next && {
- max_id: lastPage.links.next
- }
- }
- })
+ const { data, refetch, isFetching, isLoading, fetchNextPage, isFetchingNextPage } =
+ useTimelineQuery({
+ ...queryKey[1],
+ options: {
+ ...queryOptions,
+ notifyOnChangeProps: Platform.select({
+ ios: ['dataUpdatedAt', 'isFetching'],
+ android: ['dataUpdatedAt', 'isFetching', 'isLoading']
+ }),
+ getNextPageParam: lastPage =>
+ lastPage?.links?.next && {
+ ...(lastPage.links.next.isOffset
+ ? { offset: lastPage.links.next.id }
+ : { max_id: lastPage.links.next.id })
+ }
+ }
+ })
- const flattenData = data?.pages
- ? data.pages?.flatMap(page => [...page.body])
- : []
+ const flattenData = data?.pages ? data.pages?.flatMap(page => [...page.body]) : []
const onEndReached = useCallback(
() => !disableInfinity && !isFetchingNextPage && fetchNextPage(),
@@ -134,10 +127,7 @@ const Timeline: React.FC = ({
onEndReached={onEndReached}
onEndReachedThreshold={0.75}
ListFooterComponent={
-
+
}
ListEmptyComponent={ }
ItemSeparatorComponent={({ leadingItem }) =>
@@ -145,9 +135,7 @@ const Timeline: React.FC = ({
) : (
)
}
diff --git a/src/components/Timeline/Conversation.tsx b/src/components/Timeline/Conversation.tsx
index b3311a28..8e07d2c0 100644
--- a/src/components/Timeline/Conversation.tsx
+++ b/src/components/Timeline/Conversation.tsx
@@ -8,7 +8,7 @@ import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useCallback } from 'react'
import { Pressable, View } from 'react-native'
-import { useMutation, useQueryClient } from 'react-query'
+import { useMutation, useQueryClient } from '@tanstack/react-query'
import TimelineActions from './Shared/Actions'
import TimelineContent from './Shared/Content'
import StatusContext from './Shared/Context'
diff --git a/src/components/Timeline/Default.tsx b/src/components/Timeline/Default.tsx
index cf57785b..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>()
@@ -69,9 +71,12 @@ const TimelineDefault: React.FC = ({
}
const mainStyle: StyleProp = {
- padding: StyleConstants.Spacing.Global.PagePadding,
+ flex: 1,
+ padding: disableDetails
+ ? StyleConstants.Spacing.Global.PagePadding / 1.5
+ : StyleConstants.Spacing.Global.PagePadding,
backgroundColor: colors.backgroundDefault,
- paddingBottom: disableDetails ? StyleConstants.Spacing.Global.PagePadding : 0
+ paddingBottom: disableDetails ? StyleConstants.Spacing.Global.PagePadding / 1.5 : 0
}
const main = () => (
<>
@@ -81,7 +86,13 @@ const TimelineDefault: React.FC = ({
) : null}
-
+
@@ -89,7 +100,11 @@ const TimelineDefault: React.FC = ({
@@ -125,8 +140,10 @@ const TimelineDefault: React.FC = ({
spoilerHidden,
copiableContent,
highlighted,
+ inThread: queryKey?.[1].page === 'Toot',
disableDetails,
- disableOnPress
+ disableOnPress,
+ isConversation
}}
>
{disableOnPress ? (
diff --git a/src/components/Timeline/Footer.tsx b/src/components/Timeline/Footer.tsx
index ab4e1934..4ac3f2af 100644
--- a/src/components/Timeline/Footer.tsx
+++ b/src/components/Timeline/Footer.tsx
@@ -21,7 +21,11 @@ const TimelineFooter = React.memo(
enabled: !disableInfinity,
notifyOnChangeProps: ['hasNextPage'],
getNextPageParam: lastPage =>
- lastPage?.links?.next && { max_id: lastPage.links.next }
+ lastPage?.links?.next && {
+ ...(lastPage.links.next.isOffset
+ ? { offset: lastPage.links.next.id }
+ : { max_id: lastPage.links.next.id })
+ }
}
})
@@ -43,11 +47,7 @@ const TimelineFooter = React.memo(
+
]}
/>
diff --git a/src/components/Timeline/Notifications.tsx b/src/components/Timeline/Notifications.tsx
index 04204965..7eff27d1 100644
--- a/src/components/Timeline/Notifications.tsx
+++ b/src/components/Timeline/Notifications.tsx
@@ -28,18 +28,18 @@ import TimelineHeaderAndroid from './Shared/HeaderAndroid'
export interface Props {
notification: Mastodon.Notification
queryKey: QueryKeyTimeline
- highlighted?: boolean
}
-const TimelineNotifications: React.FC = ({
- notification,
- queryKey,
- highlighted = false
-}) => {
+const TimelineNotifications: React.FC = ({ notification, queryKey }) => {
const instanceAccount = useSelector(getInstanceAccount, () => true)
const status = notification.status?.reblog ? notification.status.reblog : notification.status
- const account = notification.status ? notification.status.account : notification.account
+ const account =
+ notification.type === 'admin.report'
+ ? notification.report.target_account
+ : notification.status
+ ? notification.status.account
+ : notification.account
const ownAccount = notification.account?.id === instanceAccount?.id
const [spoilerExpanded, setSpoilerExpanded] = useState(
instanceAccount.preferences['reading:expand:spoilers'] || false
@@ -91,7 +91,8 @@ const TimelineNotifications: React.FC = ({
notification.type === 'follow' ||
notification.type === 'follow_request' ||
notification.type === 'mention' ||
- notification.type === 'status'
+ notification.type === 'status' ||
+ notification.type === 'admin.sign_up'
? 1
: 0.5
}}
@@ -102,13 +103,11 @@ const TimelineNotifications: React.FC = ({
{notification.status ? (
-
-
+
+
@@ -138,8 +137,7 @@ const TimelineNotifications: React.FC = ({
status,
ownAccount,
spoilerHidden,
- copiableContent,
- highlighted
+ copiableContent
}}
>
diff --git a/src/components/Timeline/Refresh.tsx b/src/components/Timeline/Refresh.tsx
index 38cfdcdd..9ac45e95 100644
--- a/src/components/Timeline/Refresh.tsx
+++ b/src/components/Timeline/Refresh.tsx
@@ -1,10 +1,6 @@
import haptics from '@components/haptics'
import Icon from '@components/Icon'
-import {
- QueryKeyTimeline,
- TimelineData,
- useTimelineQuery
-} from '@utils/queryHooks/timeline'
+import { QueryKeyTimeline, TimelineData, useTimelineQuery } from '@utils/queryHooks/timeline'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { RefObject, useCallback, useRef, useState } from 'react'
@@ -20,7 +16,7 @@ import Animated, {
useSharedValue,
withTiming
} from 'react-native-reanimated'
-import { InfiniteData, useQueryClient } from 'react-query'
+import { InfiniteData, useQueryClient } from '@tanstack/react-query'
export interface Props {
flRef: RefObject>
@@ -31,14 +27,8 @@ export interface Props {
}
const CONTAINER_HEIGHT = StyleConstants.Spacing.M * 2.5
-export const SEPARATION_Y_1 = -(
- CONTAINER_HEIGHT / 2 +
- StyleConstants.Font.Size.S / 2
-)
-export const SEPARATION_Y_2 = -(
- CONTAINER_HEIGHT * 1.5 +
- StyleConstants.Font.Size.S / 2
-)
+export const SEPARATION_Y_1 = -(CONTAINER_HEIGHT / 2 + StyleConstants.Font.Size.S / 2)
+export const SEPARATION_Y_2 = -(CONTAINER_HEIGHT * 1.5 + StyleConstants.Font.Size.S / 2)
const TimelineRefresh: React.FC = ({
flRef,
@@ -57,87 +47,77 @@ const TimelineRefresh: React.FC = ({
const fetchingLatestIndex = useRef(0)
const refetchActive = useRef(false)
- const {
- refetch,
- isFetching,
- isLoading,
- fetchPreviousPage,
- hasPreviousPage,
- isFetchingNextPage
- } = useTimelineQuery({
- ...queryKey[1],
- options: {
- getPreviousPageParam: firstPage =>
- firstPage?.links?.prev && {
- min_id: firstPage.links.prev,
- // https://github.com/facebook/react-native/issues/25239#issuecomment-731100372
- limit: '3'
+ const { refetch, isFetching, isLoading, fetchPreviousPage, hasPreviousPage, isFetchingNextPage } =
+ useTimelineQuery({
+ ...queryKey[1],
+ options: {
+ getPreviousPageParam: firstPage =>
+ firstPage?.links?.prev && {
+ ...(firstPage.links.prev.isOffset
+ ? { offset: firstPage.links.prev.id }
+ : { max_id: firstPage.links.prev.id }),
+ // https://github.com/facebook/react-native/issues/25239#issuecomment-731100372
+ limit: '3'
+ },
+ select: data => {
+ if (refetchActive.current) {
+ data.pageParams = [data.pageParams[0]]
+ data.pages = [data.pages[0]]
+ refetchActive.current = false
+ }
+ return data
},
- select: data => {
- if (refetchActive.current) {
- data.pageParams = [data.pageParams[0]]
- data.pages = [data.pages[0]]
- refetchActive.current = false
- }
- return data
- },
- onSuccess: () => {
- if (fetchingLatestIndex.current > 0) {
- if (fetchingLatestIndex.current > 5) {
- clearFirstPage()
- fetchingLatestIndex.current = 0
- } else {
- if (hasPreviousPage) {
- fetchPreviousPage()
- fetchingLatestIndex.current++
- } else {
+ onSuccess: () => {
+ if (fetchingLatestIndex.current > 0) {
+ if (fetchingLatestIndex.current > 5) {
clearFirstPage()
fetchingLatestIndex.current = 0
+ } else {
+ if (hasPreviousPage) {
+ fetchPreviousPage()
+ fetchingLatestIndex.current++
+ } else {
+ clearFirstPage()
+ fetchingLatestIndex.current = 0
+ }
}
}
}
}
- }
- })
+ })
const { t } = useTranslation('componentTimeline')
const { colors } = useTheme()
const queryClient = useQueryClient()
const clearFirstPage = () => {
- queryClient.setQueryData | undefined>(
- queryKey,
- data => {
- if (data?.pages[0] && data.pages[0].body.length === 0) {
- return {
- pages: data.pages.slice(1),
- pageParams: data.pageParams.slice(1)
- }
- } else {
- return data
+ queryClient.setQueryData | undefined>(queryKey, data => {
+ if (data?.pages[0] && data.pages[0].body.length === 0) {
+ return {
+ pages: data.pages.slice(1),
+ pageParams: data.pageParams.slice(1)
}
+ } else {
+ return data
}
- )
+ })
}
const prepareRefetch = () => {
refetchActive.current = true
- queryClient.setQueryData | undefined>(
- queryKey,
- data => {
- if (data) {
- data.pageParams = [undefined]
- const newFirstPage: TimelineData = { body: [] }
- for (let page of data.pages) {
- // @ts-ignore
- newFirstPage.body.push(...page.body)
- if (newFirstPage.body.length > 10) break
- }
- data.pages = [newFirstPage]
+ queryClient.setQueryData | undefined>(queryKey, data => {
+ if (data) {
+ data.pageParams = [undefined]
+ const newFirstPage: TimelineData = { body: [] }
+ for (let page of data.pages) {
+ // @ts-ignore
+ newFirstPage.body.push(...page.body)
+ if (newFirstPage.body.length > 10) break
}
-
- return data
+ data.pages = [newFirstPage]
}
- )
+
+ return data
+ })
}
const callRefetch = async () => {
await refetch()
@@ -161,10 +141,7 @@ const TimelineRefresh: React.FC = ({
]
}))
const arrowTop = useAnimatedStyle(() => ({
- marginTop:
- scrollY.value < SEPARATION_Y_2
- ? withTiming(CONTAINER_HEIGHT)
- : withTiming(0)
+ marginTop: scrollY.value < SEPARATION_Y_2 ? withTiming(CONTAINER_HEIGHT) : withTiming(0)
}))
const arrowStage = useSharedValue(0)
@@ -241,8 +218,7 @@ const TimelineRefresh: React.FC = ({
const headerPadding = useAnimatedStyle(
() => ({
paddingTop:
- fetchingLatestIndex.current !== 0 ||
- (isFetching && !isLoading && !isFetchingNextPage)
+ fetchingLatestIndex.current !== 0 || (isFetching && !isLoading && !isFetchingNextPage)
? withTiming(StyleConstants.Spacing.M * 2.5)
: withTiming(0)
}),
@@ -254,10 +230,7 @@ const TimelineRefresh: React.FC = ({
{isFetching ? (
-
+
) : (
<>
diff --git a/src/components/Timeline/Shared/Actioned.tsx b/src/components/Timeline/Shared/Actioned.tsx
index 8d3dcb26..8e73de69 100644
--- a/src/components/Timeline/Shared/Actioned.tsx
+++ b/src/components/Timeline/Shared/Actioned.tsx
@@ -28,7 +28,12 @@ const TimelineActioned: React.FC = ({ action, isNotification, ...rest })
const iconColor = colors.primaryDefault
const content = (content: string) => (
-
+
)
const onPress = () => navigation.push('Tab-Shared-Account', { account })
@@ -145,6 +150,30 @@ const TimelineActioned: React.FC = ({ action, isNotification, ...rest })
{content(t('shared.actioned.update'))}
>
)
+ case 'admin.sign_up':
+ return (
+ <>
+
+ {content(t('shared.actioned.admin.sign_up', { name: `@${account.acct}` }))}
+ >
+ )
+ case 'admin.report':
+ return (
+ <>
+
+ {content(t('shared.actioned.admin.report', { name: `@${account.acct}` }))}
+ >
+ )
default:
return <>>
}
diff --git a/src/components/Timeline/Shared/Actions.tsx b/src/components/Timeline/Shared/Actions.tsx
index 0991ee89..a803dd45 100644
--- a/src/components/Timeline/Shared/Actions.tsx
+++ b/src/components/Timeline/Shared/Actions.tsx
@@ -17,7 +17,7 @@ import { uniqBy } from 'lodash'
import React, { useCallback, useContext, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { Pressable, StyleSheet, View } from 'react-native'
-import { useQueryClient } from 'react-query'
+import { useQueryClient } from '@tanstack/react-query'
import { useSelector } from 'react-redux'
import StatusContext from './Context'
diff --git a/src/components/Timeline/Shared/Attachment.tsx b/src/components/Timeline/Shared/Attachment.tsx
index 4ff5ab84..174894cc 100644
--- a/src/components/Timeline/Shared/Attachment.tsx
+++ b/src/components/Timeline/Shared/Attachment.tsx
@@ -45,6 +45,21 @@ const TimelineAttachment = () => {
}
const [sensitiveShown, setSensitiveShown] = useState(defaultSensitive())
+ // const testHorizontal: Mastodon.Attachment[] = Array(2).fill({
+ // id: Math.random().toString(),
+ // type: 'image',
+ // url: 'https://images.unsplash.com/photo-1670870764013-f0e36aa376b0?w=1000',
+ // preview_url: 'https://images.unsplash.com/photo-1543968996-ee822b8176ba?w=300',
+ // meta: { original: { width: 1000, height: 625 } }
+ // })
+ // const testVertical: Mastodon.Attachment[] = Array(7).fill({
+ // id: Math.random().toString(),
+ // type: 'image',
+ // url: 'https://images.unsplash.com/photo-1670842587871-326b95acbc8c?w=1000',
+ // preview_url: 'https://images.unsplash.com/photo-1670833288990-64b2f4ef7290?w=300',
+ // meta: { original: { width: 987, height: 1480 } }
+ // })
+
// @ts-ignore
const imageUrls: RootStackParamList['Screen-ImagesViewer']['imageUrls'] = status.media_attachments
.map(attachment => {
diff --git a/src/components/Timeline/Shared/Attachment/Audio.tsx b/src/components/Timeline/Shared/Attachment/Audio.tsx
index 83ec4f82..9e4cc767 100644
--- a/src/components/Timeline/Shared/Attachment/Audio.tsx
+++ b/src/components/Timeline/Shared/Attachment/Audio.tsx
@@ -8,7 +8,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'
import { AppState, AppStateStatus, StyleSheet, View } from 'react-native'
import { Blurhash } from 'react-native-blurhash'
import AttachmentAltText from './AltText'
-import attachmentAspectRatio from './aspectRatio'
+import { aspectRatio } from './dimensions'
export interface Props {
total: number
@@ -64,7 +64,7 @@ const AttachmentAudio: React.FC = ({ total, index, sensitiveShown, audio
styles.base,
{
backgroundColor: colors.disabled,
- aspectRatio: attachmentAspectRatio({ total, index })
+ aspectRatio: aspectRatio({ total, index, ...audio.meta?.original })
}
]}
>
diff --git a/src/components/Timeline/Shared/Attachment/Image.tsx b/src/components/Timeline/Shared/Attachment/Image.tsx
index 814d41b2..1069a36a 100644
--- a/src/components/Timeline/Shared/Attachment/Image.tsx
+++ b/src/components/Timeline/Shared/Attachment/Image.tsx
@@ -1,9 +1,10 @@
import GracefullyImage from '@components/GracefullyImage'
import { StyleConstants } from '@utils/styles/constants'
+import { useTheme } from '@utils/styles/ThemeManager'
import React from 'react'
import { View } from 'react-native'
import AttachmentAltText from './AltText'
-import attachmentAspectRatio from './aspectRatio'
+import { aspectRatio } from './dimensions'
export interface Props {
total: number
@@ -20,6 +21,8 @@ const AttachmentImage = ({
image,
navigateToImagesViewer
}: Props) => {
+ const { colors } = useTheme()
+
return (
- navigateToImagesViewer(image.id)}
- style={{
- aspectRatio:
- total > 1 || !image.meta?.original?.width || !image.meta?.original?.height
- ? attachmentAspectRatio({ total, index })
- : image.meta.original.height / image.meta.original.width > 1
- ? 1
- : image.meta.original.width / image.meta.original.height
- }}
- />
+
+ navigateToImagesViewer(image.id)}
+ style={{ aspectRatio: aspectRatio({ total, index, ...image.meta?.original }) }}
+ />
+
)
diff --git a/src/components/Timeline/Shared/Attachment/Unsupported.tsx b/src/components/Timeline/Shared/Attachment/Unsupported.tsx
index f1c7f347..7fa9d89d 100644
--- a/src/components/Timeline/Shared/Attachment/Unsupported.tsx
+++ b/src/components/Timeline/Shared/Attachment/Unsupported.tsx
@@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next'
import { View } from 'react-native'
import { Blurhash } from 'react-native-blurhash'
import AttachmentAltText from './AltText'
-import attachmentAspectRatio from './aspectRatio'
+import { aspectRatio } from './dimensions'
export interface Props {
total: number
@@ -29,7 +29,7 @@ const AttachmentUnsupported: React.FC = ({ total, index, sensitiveShown,
padding: StyleConstants.Spacing.XS / 2,
justifyContent: 'center',
alignItems: 'center',
- aspectRatio: attachmentAspectRatio({ total, index })
+ aspectRatio: aspectRatio({ total, index, ...attachment.meta?.original })
}}
>
{attachment.blurhash ? (
diff --git a/src/components/Timeline/Shared/Attachment/Video.tsx b/src/components/Timeline/Shared/Attachment/Video.tsx
index 518a5b78..78e53ac4 100644
--- a/src/components/Timeline/Shared/Attachment/Video.tsx
+++ b/src/components/Timeline/Shared/Attachment/Video.tsx
@@ -4,9 +4,10 @@ import { ResizeMode, Video, VideoFullscreenUpdate } from 'expo-av'
import React, { useRef, useState } from 'react'
import { Pressable, View } from 'react-native'
import { Blurhash } from 'react-native-blurhash'
-import attachmentAspectRatio from './aspectRatio'
import AttachmentAltText from './AltText'
import { Platform } from 'expo-modules-core'
+import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
+import { aspectRatio } from './dimensions'
export interface Props {
total: number
@@ -23,6 +24,8 @@ const AttachmentVideo: React.FC = ({
video,
gifv = false
}) => {
+ const { reduceMotionEnabled } = useAccessibility()
+
const videoPlayer = useRef(null)
const [videoLoading, setVideoLoading] = useState(false)
const [videoLoaded, setVideoLoaded] = useState(false)
@@ -46,7 +49,7 @@ const AttachmentVideo: React.FC = ({
flex: 1,
flexBasis: '50%',
padding: StyleConstants.Spacing.XS / 2,
- aspectRatio: attachmentAspectRatio({ total, index })
+ aspectRatio: aspectRatio({ total, index, ...video.meta?.original })
}}
>
= ({
resizeMode={videoResizeMode}
{...(gifv
? {
- shouldPlay: true,
+ shouldPlay: reduceMotionEnabled ? false : true,
isMuted: true,
isLooping: true,
source: { uri: video.url }
@@ -70,10 +73,10 @@ const AttachmentVideo: React.FC = ({
onFullscreenUpdate={event => {
if (event.fullscreenUpdate === VideoFullscreenUpdate.PLAYER_DID_DISMISS) {
Platform.OS === 'android' && setVideoResizeMode(ResizeMode.COVER)
- if (!gifv) {
- videoPlayer.current?.pauseAsync()
- } else {
+ if (gifv && !reduceMotionEnabled) {
videoPlayer.current?.playAsync()
+ } else {
+ videoPlayer.current?.pauseAsync()
}
}
}}
@@ -103,7 +106,7 @@ const AttachmentVideo: React.FC = ({
video.blurhash ? (
) : null
- ) : !gifv ? (
+ ) : !gifv || (gifv && reduceMotionEnabled) ? (
{
- switch (total) {
- case 1:
- case 4:
- return 16 / 9
- case 2:
- return 8 / 9
- case 3:
- if (index === 2) {
- return 32 / 9
- } else {
- return 16 / 9
- }
- default:
- return 16 / 9
- }
-}
-
-export default attachmentAspectRatio
diff --git a/src/components/Timeline/Shared/Attachment/dimensions.ts b/src/components/Timeline/Shared/Attachment/dimensions.ts
new file mode 100644
index 00000000..aa1d3564
--- /dev/null
+++ b/src/components/Timeline/Shared/Attachment/dimensions.ts
@@ -0,0 +1,38 @@
+export const aspectRatio = ({
+ total,
+ index,
+ width,
+ height
+}: {
+ total: number
+ index?: number
+ width?: number
+ height?: number
+}): number => {
+ const cropTooTall = (height || 1) / (width || 1) > 3 / 2 ? 2 / 3 : (width || 1) / (height || 1)
+
+ const isEven = total % 2 == 0
+ if (total > 5) {
+ switch (isEven) {
+ case true:
+ return total / 2 / 2
+ case false:
+ if ((index || -2) + 1 == total) {
+ return Math.ceil(total / 2)
+ } else {
+ return Math.ceil(total / 2) / 2
+ }
+ }
+ } else {
+ switch (isEven) {
+ case true:
+ return cropTooTall
+ case false:
+ if ((index || -2) + 1 == total) {
+ return cropTooTall * 2
+ } else {
+ return cropTooTall
+ }
+ }
+ }
+}
diff --git a/src/components/Timeline/Shared/Avatar.tsx b/src/components/Timeline/Shared/Avatar.tsx
index e9d6a052..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, disableOnPress } = useContext(StatusContext)
+ const { status, highlighted, disableDetails, disableOnPress, isConversation } =
+ useContext(StatusContext)
const actualAccount = account || status?.account
if (!actualAccount) return null
@@ -33,14 +34,22 @@ const TimelineAvatar: React.FC = ({ account }) => {
!disableOnPress && navigation.push('Tab-Shared-Account', { account: actualAccount })
}
uri={{ original: actualAccount.avatar, static: actualAccount.avatar_static }}
- dimension={{
- width: StyleConstants.Avatar.M,
- height: StyleConstants.Avatar.M
- }}
+ dimension={
+ disableDetails || isConversation
+ ? {
+ width: StyleConstants.Avatar.XS,
+ height: StyleConstants.Avatar.XS
+ }
+ : {
+ width: StyleConstants.Avatar.M,
+ height: StyleConstants.Avatar.M
+ }
+ }
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/Card.tsx b/src/components/Timeline/Shared/Card.tsx
index 31fcb1c9..412bd22a 100644
--- a/src/components/Timeline/Shared/Card.tsx
+++ b/src/components/Timeline/Shared/Card.tsx
@@ -10,7 +10,7 @@ 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 { Pressable, StyleSheet, Text, View } from 'react-native'
+import { Pressable, StyleSheet, View } from 'react-native'
import { Circle } from 'react-native-animated-spinkit'
import TimelineDefault from '../Default'
import StatusContext from './Context'
@@ -187,7 +187,10 @@ const TimelineCard: React.FC = () => {
style={{
flex: 1,
flexDirection: 'row',
- minHeight: isAccount && foundAccount ? undefined : StyleConstants.Font.LineHeight.M * 5,
+ minHeight:
+ (isStatus && foundStatus) || (isAccount && foundAccount)
+ ? undefined
+ : StyleConstants.Font.LineHeight.M * 5,
marginTop: StyleConstants.Spacing.M,
borderWidth: StyleSheet.hairlineWidth,
borderRadius: StyleConstants.Spacing.S,
diff --git a/src/components/Timeline/Shared/Content.tsx b/src/components/Timeline/Shared/Content.tsx
index 5e2578a1..d7b799da 100644
--- a/src/components/Timeline/Shared/Content.tsx
+++ b/src/components/Timeline/Shared/Content.tsx
@@ -2,15 +2,18 @@ import { ParseHTML } from '@components/Parse'
import { getInstanceAccount } from '@utils/slices/instancesSlice'
import React, { useContext } from 'react'
import { useTranslation } from 'react-i18next'
+import { Platform } from 'react-native'
import { useSelector } from 'react-redux'
+import { isRtlLang } from 'rtl-detect'
import StatusContext from './Context'
export interface Props {
+ notificationOwnToot?: boolean
setSpoilerExpanded?: React.Dispatch>
}
-const TimelineContent: React.FC = ({ setSpoilerExpanded }) => {
- const { status, highlighted, disableDetails } = useContext(StatusContext)
+const TimelineContent: React.FC = ({ notificationOwnToot = false, setSpoilerExpanded }) => {
+ const { status, highlighted, inThread, disableDetails } = useContext(StatusContext)
if (!status || typeof status.content !== 'string' || !status.content.length) return null
const { t } = useTranslation('componentTimeline')
@@ -30,6 +33,11 @@ const TimelineContent: React.FC = ({ setSpoilerExpanded }) => {
numberOfLines={999}
highlighted={highlighted}
disableDetails={disableDetails}
+ textStyles={
+ Platform.OS === 'ios' && status.language && isRtlLang(status.language)
+ ? { writingDirection: 'rtl' }
+ : undefined
+ }
/>
= ({ setSpoilerExpanded }) => {
emojis={status.emojis}
mentions={status.mentions}
tags={status.tags}
- numberOfLines={instanceAccount.preferences['reading:expand:spoilers'] ? 999 : 1}
+ numberOfLines={
+ instanceAccount.preferences['reading:expand:spoilers'] || inThread
+ ? notificationOwnToot
+ ? 2
+ : 999
+ : 1
+ }
expandHint={t('shared.content.expandHint')}
setSpoilerExpanded={setSpoilerExpanded}
highlighted={highlighted}
disableDetails={disableDetails}
+ textStyles={
+ Platform.OS === 'ios' && status.language && isRtlLang(status.language)
+ ? { writingDirection: 'rtl' }
+ : undefined
+ }
/>
>
) : (
@@ -53,8 +72,13 @@ const TimelineContent: React.FC = ({ setSpoilerExpanded }) => {
emojis={status.emojis}
mentions={status.mentions}
tags={status.tags}
- numberOfLines={highlighted ? 999 : undefined}
+ numberOfLines={highlighted || inThread ? 999 : notificationOwnToot ? 2 : undefined}
disableDetails={disableDetails}
+ textStyles={
+ Platform.OS === 'ios' && status.language && isRtlLang(status.language)
+ ? { writingDirection: 'rtl' }
+ : undefined
+ }
/>
)}
>
diff --git a/src/components/Timeline/Shared/Context.tsx b/src/components/Timeline/Shared/Context.tsx
index 5dafee11..f00668d1 100644
--- a/src/components/Timeline/Shared/Context.tsx
+++ b/src/components/Timeline/Shared/Context.tsx
@@ -16,8 +16,10 @@ type ContextType = {
}>
highlighted?: boolean
+ inThread?: boolean
disableDetails?: boolean
disableOnPress?: boolean
+ isConversation?: boolean
}
const StatusContext = createContext({} as ContextType)
diff --git a/src/components/Timeline/Shared/Feedback.tsx b/src/components/Timeline/Shared/Feedback.tsx
index 8fa8f30a..40d647e7 100644
--- a/src/components/Timeline/Shared/Feedback.tsx
+++ b/src/components/Timeline/Shared/Feedback.tsx
@@ -37,7 +37,7 @@ const TimelineFeedback = () => {
onPress={() =>
navigation.push('Tab-Shared-Users', {
reference: 'statuses',
- id: status.id,
+ status,
type: 'reblogged_by',
count: status.reblogs_count
})
@@ -59,7 +59,7 @@ const TimelineFeedback = () => {
onPress={() =>
navigation.push('Tab-Shared-Users', {
reference: 'statuses',
- id: status.id,
+ status,
type: 'favourited_by',
count: status.favourites_count
})
diff --git a/src/components/Timeline/Shared/Filtered.tsx b/src/components/Timeline/Shared/Filtered.tsx
index e370d585..28c582e5 100644
--- a/src/components/Timeline/Shared/Filtered.tsx
+++ b/src/components/Timeline/Shared/Filtered.tsx
@@ -45,6 +45,7 @@ export const shouldFilter = ({
status: Mastodon.Status
queryKey: QueryKeyTimeline
}): string | null => {
+ const page = queryKey[1]
const instance = getInstance(store.getState())
const ownAccount = getInstanceAccount(store.getState())?.id === status.account?.id
@@ -72,12 +73,12 @@ export const shouldFilter = ({
const escapedPhrase = filter.phrase.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // $& means the whole matched string
switch (filter.whole_word) {
case true:
- if (new RegExp(`\\B${escapedPhrase}\\b`).test(rawContent)) {
+ if (new RegExp(`\\b${escapedPhrase}\\b`, 'i').test(rawContent)) {
shouldFilter = filter.phrase
}
break
case false:
- if (new RegExp(escapedPhrase).test(rawContent)) {
+ if (new RegExp(escapedPhrase, 'i').test(rawContent)) {
shouldFilter = filter.phrase
}
break
@@ -93,11 +94,11 @@ export const shouldFilter = ({
}
}
- switch (queryKey[1].page) {
+ switch (page.page) {
case 'Following':
case 'Local':
case 'List':
- case 'Account_Default':
+ case 'Account':
if (filter.context.includes('home')) {
checkFilter(filter)
}
diff --git a/src/components/Timeline/Shared/HeaderAndroid.tsx b/src/components/Timeline/Shared/HeaderAndroid.tsx
index 204db6df..c0926e24 100644
--- a/src/components/Timeline/Shared/HeaderAndroid.tsx
+++ b/src/components/Timeline/Shared/HeaderAndroid.tsx
@@ -1,5 +1,4 @@
import menuAccount from '@components/contextMenu/account'
-import menuInstance from '@components/contextMenu/instance'
import menuShare from '@components/contextMenu/share'
import menuStatus from '@components/contextMenu/status'
import Icon from '@components/Icon'
@@ -31,7 +30,6 @@ const TimelineHeaderAndroid: React.FC = () => {
queryKey
})
const mStatus = menuStatus({ status, queryKey, rootQueryKey })
- const mInstance = menuInstance({ status, queryKey, rootQueryKey })
return (
@@ -53,7 +51,6 @@ const TimelineHeaderAndroid: React.FC = () => {
{mGroup.map(menu => (
-
))}
@@ -64,7 +61,6 @@ const TimelineHeaderAndroid: React.FC = () => {
{mGroup.map(menu => (
-
))}
@@ -75,18 +71,6 @@ const TimelineHeaderAndroid: React.FC = () => {
{mGroup.map(menu => (
-
-
- ))}
-
- ))}
-
- {mInstance.map((mGroup, index) => (
-
- {mGroup.map(menu => (
-
-
-
))}
diff --git a/src/components/Timeline/Shared/HeaderConversation.tsx b/src/components/Timeline/Shared/HeaderConversation.tsx
index baa255d7..51dbb870 100644
--- a/src/components/Timeline/Shared/HeaderConversation.tsx
+++ b/src/components/Timeline/Shared/HeaderConversation.tsx
@@ -8,7 +8,7 @@ import { useTheme } from '@utils/styles/ThemeManager'
import React, { useContext } from 'react'
import { useTranslation } from 'react-i18next'
import { Pressable, View } from 'react-native'
-import { useQueryClient } from 'react-query'
+import { useQueryClient } from '@tanstack/react-query'
import StatusContext from './Context'
import HeaderSharedCreated from './HeaderShared/Created'
import HeaderSharedMuted from './HeaderShared/Muted'
diff --git a/src/components/Timeline/Shared/HeaderDefault.tsx b/src/components/Timeline/Shared/HeaderDefault.tsx
index 5d52636a..f4f699fa 100644
--- a/src/components/Timeline/Shared/HeaderDefault.tsx
+++ b/src/components/Timeline/Shared/HeaderDefault.tsx
@@ -1,5 +1,4 @@
import menuAccount from '@components/contextMenu/account'
-import menuInstance from '@components/contextMenu/instance'
import menuShare from '@components/contextMenu/share'
import menuStatus from '@components/contextMenu/status'
import Icon from '@components/Icon'
@@ -38,18 +37,23 @@ const TimelineHeaderDefault: React.FC = () => {
queryKey
})
const mStatus = menuStatus({ status, queryKey, rootQueryKey })
- const mInstance = menuInstance({ status, queryKey, rootQueryKey })
return (
-
+
{
))}
))}
-
- {mInstance.map((mGroup, index) => (
-
- {mGroup.map(menu => (
-
-
-
-
- ))}
-
- ))}
diff --git a/src/components/Timeline/Shared/HeaderNotification.tsx b/src/components/Timeline/Shared/HeaderNotification.tsx
index a7f6c312..7b93b702 100644
--- a/src/components/Timeline/Shared/HeaderNotification.tsx
+++ b/src/components/Timeline/Shared/HeaderNotification.tsx
@@ -1,13 +1,19 @@
+import Button from '@components/Button'
import menuAccount from '@components/contextMenu/account'
import menuInstance from '@components/contextMenu/instance'
import menuShare from '@components/contextMenu/share'
import menuStatus from '@components/contextMenu/status'
import Icon from '@components/Icon'
import { RelationshipIncoming, RelationshipOutgoing } from '@components/Relationship'
+import browserPackage from '@helpers/browserPackage'
+import { getInstanceUrl } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
+import * as WebBrowser from 'expo-web-browser'
import React, { useContext, useState } from 'react'
+import { useTranslation } from 'react-i18next'
import { Platform, Pressable, View } from 'react-native'
+import { useSelector } from 'react-redux'
import * as DropdownMenu from 'zeego/dropdown-menu'
import StatusContext from './Context'
import HeaderSharedAccount from './HeaderShared/Account'
@@ -21,6 +27,7 @@ export type Props = {
}
const TimelineHeaderNotification: React.FC = ({ notification }) => {
+ const { t } = useTranslation('componentTimeline')
const { queryKey, status } = useContext(StatusContext)
const { colors } = useTheme()
@@ -40,12 +47,32 @@ const TimelineHeaderNotification: React.FC = ({ notification }) => {
const mStatus = menuStatus({ status, queryKey })
const mInstance = menuInstance({ status, queryKey })
+ const url = useSelector(getInstanceUrl)
+
const actions = () => {
switch (notification.type) {
case 'follow':
return
case 'follow_request':
return
+ case 'admin.report':
+ return (
+
+ WebBrowser.openAuthSessionAsync(
+ `https://${url}/admin/reports/${notification.report.id}`,
+ 'tooot://tooot',
+ {
+ browserPackage: await browserPackage(),
+ dismissButtonStyle: 'done',
+ readerMode: false
+ }
+ )
+ }
+ />
+ )
default:
if (status) {
return (
@@ -118,12 +145,25 @@ const TimelineHeaderNotification: React.FC = ({ notification }) => {
@@ -151,7 +191,9 @@ const TimelineHeaderNotification: React.FC = ({ notification }) => {
{
@@ -33,7 +33,7 @@ const TimelinePoll: React.FC = () => {
const poll = status.poll
const { colors, theme } = useTheme()
- const { t, i18n } = useTranslation('componentTimeline')
+ const { t } = useTranslation('componentTimeline')
const [allOptions, setAllOptions] = useState(new Array(status.poll.options.length).fill(false))
@@ -127,7 +127,7 @@ const TimelinePoll: React.FC = () => {
)
}
}
- }, [theme, i18n.language, poll.expired, poll.voted, allOptions, mutation.isLoading])
+ }, [theme, poll.expired, poll.voted, allOptions, mutation.isLoading])
const isSelected = useCallback(
(index: number): string =>
diff --git a/src/components/Timeline/Shared/Translate.tsx b/src/components/Timeline/Shared/Translate.tsx
index 55eb4c8d..d55369dd 100644
--- a/src/components/Timeline/Shared/Translate.tsx
+++ b/src/components/Timeline/Shared/Translate.tsx
@@ -1,5 +1,6 @@
import { ParseHTML } from '@components/Parse'
import CustomText from '@components/Text'
+import detectLanguage from '@helpers/detectLanguage'
import getLanguage from '@helpers/getLanguage'
import { useTranslateQuery } from '@utils/queryHooks/translate'
import { StyleConstants } from '@utils/styles/constants'
@@ -7,38 +8,44 @@ import { useTheme } from '@utils/styles/ThemeManager'
import * as Localization from 'expo-localization'
import React, { useContext, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
-import { Pressable } from 'react-native'
+import { Platform, Pressable } from 'react-native'
import { Circle } from 'react-native-animated-spinkit'
-import detectLanguage from 'react-native-language-detection'
import StatusContext from './Context'
const TimelineTranslate = () => {
- const { status, highlighted } = useContext(StatusContext)
+ const { status, highlighted, copiableContent } = useContext(StatusContext)
if (!status || !highlighted) return null
const { t } = useTranslation('componentTimeline')
const { colors } = useTheme()
- const text = status.spoiler_text ? [status.spoiler_text, status.content] : [status.content]
+ const backupTextProcessing = (): string[] => {
+ const text = status.spoiler_text ? [status.spoiler_text, status.content] : [status.content]
- for (const i in text) {
- for (const emoji of status.emojis) {
- text[i] = text[i].replaceAll(`:${emoji.shortcode}:`, ' ')
+ for (const i in text) {
+ for (const emoji of status.emojis) {
+ text[i] = text[i].replaceAll(`:${emoji.shortcode}:`, ' ')
+ }
+ text[i] = text[i]
+ .replace(/(<([^>]+)>)/gi, ' ')
+ .replace(/@.*? /gi, ' ')
+ .replace(/#.*? /gi, ' ')
+ .replace(/http(s):\/\/.*? /gi, ' ')
}
- text[i] = text[i]
- .replace(/(<([^>]+)>)/gi, ' ')
- .replace(/@.*? /gi, ' ')
- .replace(/#.*? /gi, ' ')
- .replace(/http(s):\/\/.*? /gi, ' ')
+ return text
}
+ const text = copiableContent?.current.content
+ ? [copiableContent?.current.content]
+ : backupTextProcessing()
- const [detectedLanguage, setDetectedLanguage] = useState('')
+ const [detectedLanguage, setDetectedLanguage] = useState<{
+ language: string
+ confidence: number
+ }>({ language: status.language || '', confidence: 0 })
useEffect(() => {
const detect = async () => {
- const result = await detectLanguage(text.join(`\n\n`)).catch(() => {
- // No need to log language detection failure
- })
- result?.detected && setDetectedLanguage(result.detected.slice(0, 2))
+ const result = await detectLanguage(text.join('\n\n'))
+ result && setDetectedLanguage(result)
}
detect()
}, [])
@@ -49,21 +56,37 @@ const TimelineTranslate = () => {
: settingsLanguage || Localization.locale || 'en'
const [enabled, setEnabled] = useState(false)
- const { refetch, data, isLoading, isSuccess, isError } = useTranslateQuery({
- source: detectedLanguage,
+ const { refetch, data, isFetching, isSuccess, isError } = useTranslateQuery({
+ source: detectedLanguage.language,
target: targetLanguage,
text,
options: { enabled }
})
+ const devView = () => {
+ return __DEV__ ? (
+ {` Source: ${
+ detectedLanguage?.language
+ }; Confidence: ${
+ detectedLanguage?.confidence.toString().slice(0, 5) || 'null'
+ }; Target: ${targetLanguage}`}
+ ) : null
+ }
+
if (!detectedLanguage) {
- return null
+ return devView()
}
- if (Localization.locale.slice(0, 2).includes(detectedLanguage)) {
- return null
+ if (
+ Platform.OS === 'ios' &&
+ Localization.locale.slice(0, 2).includes(detectedLanguage.language.slice(0, 2))
+ ) {
+ return devView()
}
- if (settingsLanguage?.slice(0, 2).includes(detectedLanguage)) {
- return null
+ if (
+ Platform.OS === 'android' &&
+ settingsLanguage?.slice(0, 2).includes(detectedLanguage.language.slice(0, 2))
+ ) {
+ return devView()
}
return (
@@ -88,7 +111,7 @@ const TimelineTranslate = () => {
{isError
@@ -102,10 +125,7 @@ const TimelineTranslate = () => {
})
: t('shared.translate.default')}
-
- {__DEV__ ? ` Source: ${detectedLanguage}; Target: ${targetLanguage}` : undefined}
-
- {isLoading ? (
+ {isFetching ? (
{
/>
) : null}
+ {devView()}
{data && data.error === undefined
? data.text.map((d, i) => )
: null}
diff --git a/src/components/contextMenu/account.ts b/src/components/contextMenu/account.ts
index 44526902..c85aa935 100644
--- a/src/components/contextMenu/account.ts
+++ b/src/components/contextMenu/account.ts
@@ -17,7 +17,7 @@ import { getInstanceAccount } from '@utils/slices/instancesSlice'
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Platform } from 'react-native'
-import { useQueryClient } from 'react-query'
+import { useQueryClient } from '@tanstack/react-query'
import { useSelector } from 'react-redux'
const menuAccount = ({
@@ -50,7 +50,7 @@ const menuAccount = ({
setEnabled(true)
}
}, [openChange, enabled])
- const { data, isFetching } = useRelationshipQuery({ id: account.id, options: { enabled } })
+ const { data, isFetched } = useRelationshipQuery({ id: account.id, options: { enabled } })
const queryClient = useQueryClient()
const timelineMutation = useTimelineMutation({
@@ -99,8 +99,8 @@ const menuAccount = ({
haptics('Success')
queryClient.setQueryData(queryKeyRelationship, [res])
if (action === 'block') {
- const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Following' }]
- queryClient.invalidateQueries(queryKey)
+ const queryKey = ['Timeline', { page: 'Following' }]
+ queryClient.invalidateQueries({ queryKey, exact: false })
}
},
onError: (err: any, { payload: { action } }) => {
@@ -131,7 +131,7 @@ const menuAccount = ({
type: 'outgoing',
payload: { action: 'follow', state: !data?.requested ? data.following : true }
}),
- disabled: !data || isFetching,
+ disabled: !data || !isFetched,
destructive: false,
hidden: false
},
@@ -152,9 +152,9 @@ const menuAccount = ({
key: 'account-list',
item: {
onSelect: () => navigation.navigate('Tab-Shared-Account-In-Lists', { account }),
- disabled: Platform.OS !== 'android' ? !data || isFetching : false,
+ disabled: Platform.OS !== 'android' ? !data || !isFetched : false,
destructive: false,
- hidden: isFetching ? false : !data?.following
+ hidden: !isFetched || !data?.following
},
title: t('account.inLists'),
icon: 'checklist'
@@ -169,7 +169,7 @@ const menuAccount = ({
id: account.id,
payload: { property: 'mute', currentValue: data?.muting }
}),
- disabled: Platform.OS !== 'android' ? !data || isFetching : false,
+ disabled: Platform.OS !== 'android' ? !data || !isFetched : false,
destructive: false,
hidden: false
},
@@ -192,7 +192,7 @@ const menuAccount = ({
id: account.id,
payload: { property: 'block', currentValue: data?.blocking }
}),
- disabled: Platform.OS !== 'android' ? !data || isFetching : false,
+ disabled: Platform.OS !== 'android' ? !data || !isFetched : false,
destructive: !data?.blocking,
hidden: false
},
diff --git a/src/components/contextMenu/instance.ts b/src/components/contextMenu/instance.ts
index 4dca7faf..729d2eb0 100644
--- a/src/components/contextMenu/instance.ts
+++ b/src/components/contextMenu/instance.ts
@@ -3,7 +3,7 @@ import { QueryKeyTimeline, useTimelineMutation } from '@utils/queryHooks/timelin
import { getInstanceUrl } from '@utils/slices/instancesSlice'
import { useTranslation } from 'react-i18next'
import { Alert } from 'react-native'
-import { useQueryClient } from 'react-query'
+import { useQueryClient } from '@tanstack/react-query'
import { useSelector } from 'react-redux'
const menuInstance = ({
diff --git a/src/components/contextMenu/status.ts b/src/components/contextMenu/status.ts
index 9223d640..8b3eaae1 100644
--- a/src/components/contextMenu/status.ts
+++ b/src/components/contextMenu/status.ts
@@ -12,7 +12,7 @@ import { checkInstanceFeature, getInstanceAccount } from '@utils/slices/instance
import { useTheme } from '@utils/styles/ThemeManager'
import { useTranslation } from 'react-i18next'
import { Alert } from 'react-native'
-import { useQueryClient } from 'react-query'
+import { useQueryClient } from '@tanstack/react-query'
import { useSelector } from 'react-redux'
const menuStatus = ({
diff --git a/src/components/mediaSelector.ts b/src/components/mediaSelector.ts
index 18ea1051..1631cddf 100644
--- a/src/components/mediaSelector.ts
+++ b/src/components/mediaSelector.ts
@@ -22,10 +22,7 @@ const mediaSelector = async ({
indicateMaximum = false,
showActionSheetWithOptions
}: Props): Promise => {
- const _maximum =
- maximum ||
- getInstanceConfigurationStatusMaxAttachments(store.getState()) ||
- 4
+ const _maximum = maximum || getInstanceConfigurationStatusMaxAttachments(store.getState()) || 4
const options = () => {
switch (mediaType) {
@@ -33,7 +30,7 @@ const mediaSelector = async ({
return [
i18next.t(
'componentMediaSelector:options.image',
- indicateMaximum ? { context: 'max', max: _maximum } : undefined
+ indicateMaximum ? { context: 'max', max: _maximum } : {}
),
i18next.t('common:buttons.cancel')
]
@@ -41,7 +38,7 @@ const mediaSelector = async ({
return [
i18next.t(
'componentMediaSelector:options.video',
- indicateMaximum ? { context: 'max', max: 1 } : undefined
+ indicateMaximum ? { context: 'max', max: 1 } : {}
),
i18next.t('common:buttons.cancel')
]
@@ -49,11 +46,11 @@ const mediaSelector = async ({
return [
i18next.t(
'componentMediaSelector:options.image',
- indicateMaximum ? { context: 'max', max: _maximum } : undefined
+ indicateMaximum ? { context: 'max', max: _maximum } : {}
),
i18next.t(
'componentMediaSelector:options.video',
- indicateMaximum ? { context: 'max', max: 1 } : undefined
+ indicateMaximum ? { context: 'max', max: 1 } : {}
),
i18next.t('common:buttons.cancel')
]
diff --git a/src/helpers/detectLanguage.ts b/src/helpers/detectLanguage.ts
new file mode 100644
index 00000000..c218344d
--- /dev/null
+++ b/src/helpers/detectLanguage.ts
@@ -0,0 +1,10 @@
+import detect from 'react-native-language-detection'
+
+const detectLanguage = async (
+ text: string
+): Promise<{ language: string; confidence: number } | null> => {
+ const possibleLanguages = await detect(text).catch(() => {})
+ return possibleLanguages ? possibleLanguages.filter(lang => lang.confidence > 0.5)?.[0] : null
+}
+
+export default detectLanguage
diff --git a/src/helpers/features.json b/src/helpers/features.json
index 3a466762..03ccb0af 100644
--- a/src/helpers/features.json
+++ b/src/helpers/features.json
@@ -1,37 +1,42 @@
[
+ {
+ "feature": "notification_type_status",
+ "version": 3.3
+ },
{
"feature": "account_return_suspended",
- "version": 3.3,
- "reference": "https://github.com/mastodon/mastodon/releases/tag/v3.3.0"
+ "version": 3.3
},
{
"feature": "edit_post",
- "version": 3.5,
- "reference": "https://github.com/mastodon/mastodon/releases/tag/v3.5.0"
+ "version": 3.5
},
{
"feature": "deprecate_auth_follow",
- "version": 3.5,
- "reference": "https://github.com/mastodon/mastodon/releases/tag/v3.5.0"
+ "version": 3.5
},
{
"feature": "notification_type_update",
- "version": 3.5,
- "reference": "https://github.com/mastodon/mastodon/releases/tag/v3.5.0"
+ "version": 3.5
+ },
+ {
+ "feature": "notification_type_admin_signup",
+ "version": 3.5
},
{
"feature": "notification_types_positive_filter",
- "version": 3.5,
- "reference": "https://github.com/mastodon/mastodon/releases/tag/v3.5.0"
+ "version": 3.5
},
{
"feature": "trends_new_path",
- "version": 3.5,
- "reference": "https://github.com/mastodon/mastodon/releases/tag/v3.5.0"
+ "version": 3.5
},
{
"feature": "follow_tags",
- "version": 4.0,
- "reference": "https://github.com/mastodon/mastodon/releases/tag/v4.0.0"
+ "version": 4.0
+ },
+ {
+ "feature": "notification_type_admin_report",
+ "version": 4.0
}
]
\ No newline at end of file
diff --git a/src/helpers/permissions.ts b/src/helpers/permissions.ts
new file mode 100644
index 00000000..3ac7986a
--- /dev/null
+++ b/src/helpers/permissions.ts
@@ -0,0 +1,9 @@
+export const PERMISSION_MANAGE_REPORTS = 0x0000000000000010
+export const PERMISSION_MANAGE_USERS = 0x0000000000000400
+
+export const checkPermission = (permission: number, permissions?: string | number): boolean =>
+ permissions
+ ? !!(
+ (typeof permissions === 'string' ? parseInt(permissions || '0') : permissions) & permission
+ )
+ : false
diff --git a/src/helpers/queryClient.ts b/src/helpers/queryClient.ts
index 3e018e42..90649981 100644
--- a/src/helpers/queryClient.ts
+++ b/src/helpers/queryClient.ts
@@ -1,5 +1,5 @@
-import { QueryClient } from 'react-query'
+import { QueryClient } from '@tanstack/react-query'
-const queryClient = new QueryClient()
+const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 1000 * 60 * 5 } } })
export default queryClient
diff --git a/src/helpers/removeHTML.ts b/src/helpers/removeHTML.ts
new file mode 100644
index 00000000..8690061a
--- /dev/null
+++ b/src/helpers/removeHTML.ts
@@ -0,0 +1,18 @@
+import htmlparser2 from 'htmlparser2-without-node-native'
+
+const removeHTML = (text: string): string => {
+ let raw: string = ''
+
+ const parser = new htmlparser2.Parser({
+ ontext: (text: string) => {
+ raw = raw + text
+ }
+ })
+
+ parser.write(text)
+ parser.end()
+
+ return raw
+}
+
+export default removeHTML
diff --git a/src/helpers/urlMatcher.ts b/src/helpers/urlMatcher.ts
index a5d3c9d5..f6d4875d 100644
--- a/src/helpers/urlMatcher.ts
+++ b/src/helpers/urlMatcher.ts
@@ -30,18 +30,24 @@ const matchAccount = (
// https://social.xmflsct.com/web/accounts/14195 <- default
// https://social.xmflsct.com/web/@tooot <- pretty ! cannot be searched on the same instance
// https://social.xmflsct.com/@tooot <- pretty
- const matcherAccount = new RegExp(/(https?:\/\/)?([^\/]+)(\/web|\/web\/accounts)?\/([0-9]+|@.+)/)
+ const matcherAccount = new RegExp(
+ /(https?:\/\/)?([^\/]+)(\/web\/accounts\/([0-9]+)|\/web\/(@.+)|\/(@.+))/
+ )
const matched = url.match(matcherAccount)
if (matched) {
const hostname = matched[2]
- const style = matched[4].startsWith('@') ? 'pretty' : 'default'
- const account = matched[4]
+ const account = matched.filter(i => i).reverse()?.[0]
+ if (account) {
+ const style = account.startsWith('@') ? 'pretty' : 'default'
- const instanceUrl = getInstanceUrl(store.getState())
- return style === 'default'
- ? { id: account, style, sameInstance: hostname === instanceUrl }
- : { username: account, style, sameInstance: hostname === instanceUrl }
+ const instanceUrl = getInstanceUrl(store.getState())
+ return style === 'default'
+ ? { id: account, style, sameInstance: hostname === instanceUrl }
+ : { username: account, style, sameInstance: hostname === instanceUrl }
+ } else {
+ return null
+ }
}
return null
diff --git a/src/i18n/ca/common.json b/src/i18n/ca/common.json
index c67e4cce..163d8b66 100644
--- a/src/i18n/ca/common.json
+++ b/src/i18n/ca/common.json
@@ -5,6 +5,7 @@
"cancel": "Cancel·la",
"discard": "Descarta",
"continue": "Continua",
+ "create": "Crea",
"delete": "Esborra",
"done": "Fet"
},
diff --git a/src/i18n/ca/components/instance.json b/src/i18n/ca/components/instance.json
index de2f42e2..97aa1b2b 100644
--- a/src/i18n/ca/components/instance.json
+++ b/src/i18n/ca/components/instance.json
@@ -1,7 +1,7 @@
{
"server": {
"textInput": {
- "placeholder": "Domini de la instància"
+ "placeholder": ""
},
"button": "Inicia la sessió",
"information": {
diff --git a/src/i18n/ca/components/timeline.json b/src/i18n/ca/components/timeline.json
index adc39c18..5a0145f4 100644
--- a/src/i18n/ca/components/timeline.json
+++ b/src/i18n/ca/components/timeline.json
@@ -30,7 +30,9 @@
"default": "{{name}} ha impulsat",
"notification": "{{name}} ha impulsat la teva publicació"
},
- "update": "L'impuls ha sigut editat"
+ "update": "L'impuls ha sigut editat",
+ "admin.sign_up": "",
+ "admin.report": ""
},
"actions": {
"reply": {
@@ -52,7 +54,8 @@
"bookmarked": {
"accessibilityLabel": "Afegeix aquesta publicació a marcadors",
"function": "Afegeix la publicació a marcadors"
- }
+ },
+ "openReport": ""
},
"actionsUsers": {
"reblogged_by": {
diff --git a/src/i18n/ca/screens/actions.json b/src/i18n/ca/screens/actions.json
index 063f9d09..15dc17ec 100644
--- a/src/i18n/ca/screens/actions.json
+++ b/src/i18n/ca/screens/actions.json
@@ -2,19 +2,6 @@
"content": {
"altText": {
"heading": "Text alternatiu"
- },
- "notificationsFilter": {
- "heading": "Mostra els tipus de notificació",
- "content": {
- "follow": "$t(screenTabs:me.push.follow.heading)",
- "follow_request": "Sol·licitud de seguiment",
- "favourite": "$t(screenTabs:me.push.favourite.heading)",
- "reblog": "$t(screenTabs:me.push.reblog.heading)",
- "mention": "$t(screenTabs:me.push.mention.heading)",
- "poll": "$t(screenTabs:me.push.poll.heading)",
- "status": "Publicació d'usuaris subscrits",
- "update": "L'impuls ha sigut editat"
- }
}
}
}
\ No newline at end of file
diff --git a/src/i18n/ca/screens/compose.json b/src/i18n/ca/screens/compose.json
index af53c55f..5f3220e0 100644
--- a/src/i18n/ca/screens/compose.json
+++ b/src/i18n/ca/screens/compose.json
@@ -1,13 +1,11 @@
{
"heading": {
"left": {
- "button": "Cancel·la",
"alert": {
"title": "Voleu cancel·lar l'edició?",
"buttons": {
"save": "Desa l'esborrany",
- "delete": "Esborra l'esborrany",
- "cancel": "Cancel·la"
+ "delete": "Esborra l'esborrany"
}
}
},
diff --git a/src/i18n/ca/screens/tabs.json b/src/i18n/ca/screens/tabs.json
index ebf8b77f..baa840c8 100644
--- a/src/i18n/ca/screens/tabs.json
+++ b/src/i18n/ca/screens/tabs.json
@@ -1,20 +1,21 @@
{
"tabs": {
"local": {
- "name": "Seguint"
+ "name": "Seguint",
+ "options": {
+ "showBoosts": "",
+ "showReplies": ""
+ }
},
"public": {
- "name": "",
"segments": {
- "left": "Federat",
- "right": "Local"
+ "federated": "Federat",
+ "local": "Local",
+ "trending": "En tendència"
}
},
"notifications": {
"name": "Notificacions"
- },
- "me": {
- "name": "Sobre mi"
}
},
"common": {
@@ -24,9 +25,22 @@
}
},
"notifications": {
- "filter": {
+ "filters": {
"accessibilityLabel": "Filtra",
- "accessibilityHint": "Filtra els tipus de notificacions"
+ "accessibilityHint": "Filtra els tipus de notificacions",
+ "title": "Mostra les notificacions",
+ "options": {
+ "follow": "$t(screenTabs:me.push.follow.heading)",
+ "follow_request": "Sol·licitud de seguiment",
+ "favourite": "$t(screenTabs:me.push.favourite.heading)",
+ "reblog": "$t(screenTabs:me.push.reblog.heading)",
+ "mention": "$t(screenTabs:me.push.mention.heading)",
+ "poll": "$t(screenTabs:me.push.poll.heading)",
+ "status": "Publicació d'usuaris subscrits",
+ "update": "L'impuls ha sigut editat",
+ "admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
+ "admin.report": "$t(screenTabs:me.push.admin.report.heading)"
+ }
}
},
"me": {
@@ -40,6 +54,9 @@
"favourites": {
"name": "Favorits"
},
+ "followedTags": {
+ "name": "Etiquetes seguides"
+ },
"fontSize": {
"name": "Mida de la font de la publicació"
},
@@ -53,7 +70,7 @@
"name": "Usuaris a la llista: {{list}}"
},
"listAdd": {
- "name": "Afegeix a la llista"
+ "name": "Crea una llista"
},
"listEdit": {
"name": "Edita els detalls de la llista"
@@ -179,8 +196,8 @@
"settings": "Activa'ls a la configuració"
},
"missingServerKey": {
- "message": "",
- "description": ""
+ "message": "Servidor mal configurat per a les notificacions push",
+ "description": "Si us plau, contacta amb l'administrador del teu servidor per a configurar el suport de notificacions push"
},
"global": {
"heading": "Activa per {{acct}}",
@@ -214,6 +231,12 @@
"status": {
"heading": "Publicació d'usuaris subscrits"
},
+ "admin.sign_up": {
+ "heading": "Administració: Registra"
+ },
+ "admin.report": {
+ "heading": "Administració: denúncies"
+ },
"howitworks": "Aprèn com funciona"
},
"root": {
@@ -225,10 +248,8 @@
}
},
"push": {
- "content": {
- "enabled": "Habilitat",
- "disabled": "Deshabilitat"
- }
+ "content_true": "Habilitat",
+ "content_false": "Deshabilitat"
},
"update": {
"title": "Actualitza a la última versió"
@@ -290,9 +311,6 @@
"support": {
"heading": "Dona suport al tooot"
},
- "review": {
- "heading": "Valora al tooot"
- },
"contact": {
"heading": "Contacta al tooot"
},
@@ -330,7 +348,7 @@
"notInLists": "Altres llistes"
},
"attachments": {
- "name": "Multimèdia de <0 /><1>1>"
+ "name": ""
},
"hashtag": {
"follow": "Segueix",
@@ -377,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/common.json b/src/i18n/cs/common.json
index e83caf88..b08510a6 100644
--- a/src/i18n/cs/common.json
+++ b/src/i18n/cs/common.json
@@ -5,6 +5,7 @@
"cancel": "",
"discard": "",
"continue": "",
+ "create": "",
"delete": "",
"done": ""
},
diff --git a/src/i18n/cs/components/timeline.json b/src/i18n/cs/components/timeline.json
index 4ed9c372..43556ccc 100644
--- a/src/i18n/cs/components/timeline.json
+++ b/src/i18n/cs/components/timeline.json
@@ -30,7 +30,9 @@
"default": "",
"notification": ""
},
- "update": ""
+ "update": "",
+ "admin.sign_up": "",
+ "admin.report": ""
},
"actions": {
"reply": {
@@ -52,7 +54,8 @@
"bookmarked": {
"accessibilityLabel": "",
"function": ""
- }
+ },
+ "openReport": ""
},
"actionsUsers": {
"reblogged_by": {
diff --git a/src/i18n/cs/screens/actions.json b/src/i18n/cs/screens/actions.json
index 55e9959c..96dce3a8 100644
--- a/src/i18n/cs/screens/actions.json
+++ b/src/i18n/cs/screens/actions.json
@@ -2,19 +2,6 @@
"content": {
"altText": {
"heading": ""
- },
- "notificationsFilter": {
- "heading": "",
- "content": {
- "follow": "",
- "follow_request": "",
- "favourite": "",
- "reblog": "",
- "mention": "",
- "poll": "",
- "status": "",
- "update": ""
- }
}
}
}
\ No newline at end of file
diff --git a/src/i18n/cs/screens/compose.json b/src/i18n/cs/screens/compose.json
index ebf265d9..2a078c68 100644
--- a/src/i18n/cs/screens/compose.json
+++ b/src/i18n/cs/screens/compose.json
@@ -1,13 +1,11 @@
{
"heading": {
"left": {
- "button": "",
"alert": {
"title": "",
"buttons": {
"save": "",
- "delete": "",
- "cancel": ""
+ "delete": ""
}
}
},
diff --git a/src/i18n/cs/screens/tabs.json b/src/i18n/cs/screens/tabs.json
index c85d6c3c..89dc4321 100644
--- a/src/i18n/cs/screens/tabs.json
+++ b/src/i18n/cs/screens/tabs.json
@@ -1,20 +1,21 @@
{
"tabs": {
"local": {
- "name": ""
+ "name": "",
+ "options": {
+ "showBoosts": "",
+ "showReplies": ""
+ }
},
"public": {
- "name": "",
"segments": {
- "left": "",
- "right": ""
+ "federated": "",
+ "local": "",
+ "trending": ""
}
},
"notifications": {
"name": ""
- },
- "me": {
- "name": ""
}
},
"common": {
@@ -24,9 +25,22 @@
}
},
"notifications": {
- "filter": {
+ "filters": {
"accessibilityLabel": "",
- "accessibilityHint": ""
+ "accessibilityHint": "",
+ "title": "",
+ "options": {
+ "follow": "",
+ "follow_request": "",
+ "favourite": "",
+ "reblog": "",
+ "mention": "",
+ "poll": "",
+ "status": "",
+ "update": "",
+ "admin.sign_up": "",
+ "admin.report": ""
+ }
}
},
"me": {
@@ -40,6 +54,9 @@
"favourites": {
"name": ""
},
+ "followedTags": {
+ "name": ""
+ },
"fontSize": {
"name": ""
},
@@ -214,6 +231,12 @@
"status": {
"heading": ""
},
+ "admin.sign_up": {
+ "heading": ""
+ },
+ "admin.report": {
+ "heading": ""
+ },
"howitworks": ""
},
"root": {
@@ -225,10 +248,8 @@
}
},
"push": {
- "content": {
- "enabled": "",
- "disabled": ""
- }
+ "content_true": "",
+ "content_false": ""
},
"update": {
"title": ""
@@ -290,9 +311,6 @@
"support": {
"heading": ""
},
- "review": {
- "heading": ""
- },
"contact": {
"heading": ""
},
@@ -377,7 +395,8 @@
"statuses": {
"reblogged_by": "",
"favourited_by": ""
- }
+ },
+ "resultIncomplete": ""
}
}
}
\ No newline at end of file
diff --git a/src/i18n/de/common.json b/src/i18n/de/common.json
index 4e0636a7..904f2597 100644
--- a/src/i18n/de/common.json
+++ b/src/i18n/de/common.json
@@ -5,8 +5,9 @@
"cancel": "Abbrechen",
"discard": "Abbrechen",
"continue": "Weiter",
+ "create": "Erstellen",
"delete": "Löschen",
- "done": ""
+ "done": "Fertig"
},
"customEmoji": {
"accessibilityLabel": "Eigenes Emoji {{emoji}}"
diff --git a/src/i18n/de/components/contextMenu.json b/src/i18n/de/components/contextMenu.json
index 09a0beb2..881c2913 100644
--- a/src/i18n/de/components/contextMenu.json
+++ b/src/i18n/de/components/contextMenu.json
@@ -6,7 +6,7 @@
"action_false": "Folgen",
"action_true": "Nutzer entfolgen"
},
- "inLists": "",
+ "inLists": "Konten in Listen verwalten",
"mute": {
"action_false": "Profil stummschalten",
"action_true": "Stummschaltung des Nutzers aufheben"
diff --git a/src/i18n/de/components/instance.json b/src/i18n/de/components/instance.json
index e3d1efdc..3901a0dd 100644
--- a/src/i18n/de/components/instance.json
+++ b/src/i18n/de/components/instance.json
@@ -1,7 +1,7 @@
{
"server": {
"textInput": {
- "placeholder": "Instanz"
+ "placeholder": "Domain der Instanz"
},
"button": "Login",
"information": {
diff --git a/src/i18n/de/components/timeline.json b/src/i18n/de/components/timeline.json
index 3bd00501..703494bd 100644
--- a/src/i18n/de/components/timeline.json
+++ b/src/i18n/de/components/timeline.json
@@ -30,7 +30,9 @@
"default": "{{name}} hat geboostet",
"notification": "{{name}} hat deinen Tröt geboostet"
},
- "update": "Boost wurde bearbeitet"
+ "update": "Boost wurde bearbeitet",
+ "admin.sign_up": "{{name}} ist der Instanz beigetreten",
+ "admin.report": "{{name}} hat gemeldet:"
},
"actions": {
"reply": {
@@ -42,7 +44,7 @@
"options": {
"title": "Boost-Sichtbarkeit ändern",
"public": "Öffentlicher Boost",
- "unlisted": "Boost entfernen"
+ "unlisted": "Privater Boost"
}
},
"favourited": {
@@ -52,7 +54,8 @@
"bookmarked": {
"accessibilityLabel": "Lesezeichen hinzufügen",
"function": "Lesezeichen setzen"
- }
+ },
+ "openReport": ""
},
"actionsUsers": {
"reblogged_by": {
diff --git a/src/i18n/de/screens/actions.json b/src/i18n/de/screens/actions.json
index 5cd3ac4c..938c6238 100644
--- a/src/i18n/de/screens/actions.json
+++ b/src/i18n/de/screens/actions.json
@@ -2,19 +2,6 @@
"content": {
"altText": {
"heading": "Alternativtext"
- },
- "notificationsFilter": {
- "heading": "Benachrichtigungsart anzeigen",
- "content": {
- "follow": "$t(screenTabs:me.push.follow.heading)",
- "follow_request": "Followeranfrage",
- "favourite": "$t(screenTabs:me.push.favourite.heading)",
- "reblog": "$t(screenTabs:me.push.reblog.heading)",
- "mention": "$t(screenTabs:me.push.mention.heading)",
- "poll": "$t(screenTabs:me.push.poll.heading)",
- "status": "Tröt eines abonnierten Nutzers",
- "update": "Boost wurde bearbeitet"
- }
}
}
}
\ No newline at end of file
diff --git a/src/i18n/de/screens/compose.json b/src/i18n/de/screens/compose.json
index 303980e9..c03f11b5 100644
--- a/src/i18n/de/screens/compose.json
+++ b/src/i18n/de/screens/compose.json
@@ -1,13 +1,11 @@
{
"heading": {
"left": {
- "button": "Abbrechen",
"alert": {
"title": "Bearbeitung abbrechen?",
"buttons": {
"save": "Entwurf speichern",
- "delete": "Entwurf löschen",
- "cancel": "Abbrechen"
+ "delete": "Entwurf löschen"
}
}
},
diff --git a/src/i18n/de/screens/tabs.json b/src/i18n/de/screens/tabs.json
index 2e0b7e46..9225e3d9 100644
--- a/src/i18n/de/screens/tabs.json
+++ b/src/i18n/de/screens/tabs.json
@@ -1,20 +1,21 @@
{
"tabs": {
"local": {
- "name": "Gefolgt"
+ "name": "Gefolgt",
+ "options": {
+ "showBoosts": "Boosts anzeigen",
+ "showReplies": "Antworten anzeigen"
+ }
},
"public": {
- "name": "",
"segments": {
- "left": "Föderiert",
- "right": "Lokal"
+ "federated": "Föderiert",
+ "local": "Lokal",
+ "trending": "Im Trend"
}
},
"notifications": {
"name": "Benachrichtigungen"
- },
- "me": {
- "name": "Über mich"
}
},
"common": {
@@ -24,9 +25,22 @@
}
},
"notifications": {
- "filter": {
+ "filters": {
"accessibilityLabel": "Filter",
- "accessibilityHint": "Angezeigte Benachrichtigungstypen filtern"
+ "accessibilityHint": "Angezeigte Benachrichtigungstypen filtern",
+ "title": "Benachrichtigungen anzeigen",
+ "options": {
+ "follow": "$t(screenTabs:me.push.follow.heading)",
+ "follow_request": "Followeranfrage",
+ "favourite": "$t(screenTabs:me.push.favourite.heading)",
+ "reblog": "$t(screenTabs:me.push.reblog.heading)",
+ "mention": "$t(screenTabs:me.push.mention.heading)",
+ "poll": "$t(screenTabs:me.push.poll.heading)",
+ "status": "Tröt eines abonnierten Nutzers",
+ "update": "Boost wurde bearbeitet",
+ "admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
+ "admin.report": "$t(screenTabs:me.push.admin.report.heading)"
+ }
}
},
"me": {
@@ -40,6 +54,9 @@
"favourites": {
"name": "Favoriten"
},
+ "followedTags": {
+ "name": "Abonnierte Hashtags"
+ },
"fontSize": {
"name": "Schriftgröße"
},
@@ -53,7 +70,7 @@
"name": "Benutzer in dieser Liste: {{list}}"
},
"listAdd": {
- "name": "Eine Liste hinzufügen"
+ "name": "Eine Liste erstellen"
},
"listEdit": {
"name": "Listendetails bearbeiten"
@@ -179,8 +196,8 @@
"settings": "In den Einstellungen aktivieren"
},
"missingServerKey": {
- "message": "",
- "description": ""
+ "message": "Server ist nicht für Push-Benachrichtigungen konfiguriert",
+ "description": "Bitte kontaktiere den Administrator deiner Instanz, um Push-Benachrichtigungen zu ermöglichen"
},
"global": {
"heading": "Aktivieren für {{acct}}",
@@ -214,6 +231,12 @@
"status": {
"heading": "Toot eines abonnierten Nutzers"
},
+ "admin.sign_up": {
+ "heading": "Admin: Registrierung"
+ },
+ "admin.report": {
+ "heading": "Admin: Meldungen"
+ },
"howitworks": "Erfahre, wie das Routing funktioniert"
},
"root": {
@@ -225,10 +248,8 @@
}
},
"push": {
- "content": {
- "enabled": "Aktiviert",
- "disabled": "Deaktiviert"
- }
+ "content_true": "Aktiviert",
+ "content_false": "Deaktiviert"
},
"update": {
"title": "Auf neueste Version aktualisiert"
@@ -290,9 +311,6 @@
"support": {
"heading": "Unterstütze Tooot"
},
- "review": {
- "heading": "Tooot überprüfen"
- },
"contact": {
"heading": "Nimm Kontakt mit tooot auf"
},
@@ -325,12 +343,12 @@
"suspended": "Konto wurde von den Instanzmoderation gesperrt"
},
"accountInLists": {
- "name": "",
- "inLists": "",
- "notInLists": ""
+ "name": "Listen, in denen @{{username}} aufgeführt ist",
+ "inLists": "In Listen",
+ "notInLists": "Andere Listen"
},
"attachments": {
- "name": "<0 /><1>\"s Medien1>"
+ "name": "<0 /><1>'s Medien1>"
},
"hashtag": {
"follow": "Folgen",
@@ -377,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/en/common.json b/src/i18n/en/common.json
index 8a4d2329..f2a5a1c6 100644
--- a/src/i18n/en/common.json
+++ b/src/i18n/en/common.json
@@ -5,6 +5,7 @@
"cancel": "Cancel",
"discard": "Discard",
"continue": "Continue",
+ "create": "Create",
"delete": "Delete",
"done": "Done"
},
diff --git a/src/i18n/en/components/instance.json b/src/i18n/en/components/instance.json
index f59b012e..18a320d1 100644
--- a/src/i18n/en/components/instance.json
+++ b/src/i18n/en/components/instance.json
@@ -1,7 +1,7 @@
{
"server": {
"textInput": {
- "placeholder": "Instance' domain"
+ "placeholder": "Instance's domain"
},
"button": "Login",
"information": {
diff --git a/src/i18n/en/components/timeline.json b/src/i18n/en/components/timeline.json
index 47e20a14..639c4a40 100644
--- a/src/i18n/en/components/timeline.json
+++ b/src/i18n/en/components/timeline.json
@@ -30,7 +30,9 @@
"default": "{{name}} boosted",
"notification": "{{name}} boosted your toot"
},
- "update": "Reblog has been edited"
+ "update": "Reblog has been edited",
+ "admin.sign_up": "{{name}} joined the instance",
+ "admin.report": "{{name}} reported:"
},
"actions": {
"reply": {
@@ -52,7 +54,8 @@
"bookmarked": {
"accessibilityLabel": "Add this toot to bookmarks",
"function": "Bookmark toot"
- }
+ },
+ "openReport": "Open report"
},
"actionsUsers": {
"reblogged_by": {
diff --git a/src/i18n/en/screens/actions.json b/src/i18n/en/screens/actions.json
index 942accaf..970345fa 100644
--- a/src/i18n/en/screens/actions.json
+++ b/src/i18n/en/screens/actions.json
@@ -2,19 +2,6 @@
"content": {
"altText": {
"heading": "Alternative Text"
- },
- "notificationsFilter": {
- "heading": "Show notification types",
- "content": {
- "follow": "$t(screenTabs:me.push.follow.heading)",
- "follow_request": "Follow request",
- "favourite": "$t(screenTabs:me.push.favourite.heading)",
- "reblog": "$t(screenTabs:me.push.reblog.heading)",
- "mention": "$t(screenTabs:me.push.mention.heading)",
- "poll": "$t(screenTabs:me.push.poll.heading)",
- "status": "Toot from subscribed users",
- "update": "Reblog has been edited"
- }
}
}
}
\ No newline at end of file
diff --git a/src/i18n/en/screens/compose.json b/src/i18n/en/screens/compose.json
index c4ea0f80..c292e3cc 100644
--- a/src/i18n/en/screens/compose.json
+++ b/src/i18n/en/screens/compose.json
@@ -1,13 +1,11 @@
{
"heading": {
"left": {
- "button": "Cancel",
"alert": {
"title": "Cancel editing?",
"buttons": {
"save": "Save draft",
- "delete": "Delete draft",
- "cancel": "Cancel"
+ "delete": "Delete draft"
}
}
},
diff --git a/src/i18n/en/screens/tabs.json b/src/i18n/en/screens/tabs.json
index b286a094..5d7d1f2d 100644
--- a/src/i18n/en/screens/tabs.json
+++ b/src/i18n/en/screens/tabs.json
@@ -1,20 +1,21 @@
{
"tabs": {
"local": {
- "name": "Following"
+ "name": "Following",
+ "options": {
+ "showBoosts": "Show boosts",
+ "showReplies": "Show replies"
+ }
},
"public": {
- "name": "",
"segments": {
- "left": "Federated",
- "right": "Local"
+ "federated": "Federated",
+ "local": "Local",
+ "trending": "Trending"
}
},
"notifications": {
"name": "Notifications"
- },
- "me": {
- "name": "About me"
}
},
"common": {
@@ -24,9 +25,22 @@
}
},
"notifications": {
- "filter": {
+ "filters": {
"accessibilityLabel": "Filter",
- "accessibilityHint": "Filter shown notifications' types"
+ "accessibilityHint": "Filter shown notifications' types",
+ "title": "Show notifications",
+ "options": {
+ "follow": "$t(screenTabs:me.push.follow.heading)",
+ "follow_request": "Follow request",
+ "favourite": "$t(screenTabs:me.push.favourite.heading)",
+ "reblog": "$t(screenTabs:me.push.reblog.heading)",
+ "mention": "$t(screenTabs:me.push.mention.heading)",
+ "poll": "$t(screenTabs:me.push.poll.heading)",
+ "status": "Toot from subscribed users",
+ "update": "Reblog has been edited",
+ "admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
+ "admin.report": "$t(screenTabs:me.push.admin.report.heading)"
+ }
}
},
"me": {
@@ -40,6 +54,9 @@
"favourites": {
"name": "Favourites"
},
+ "followedTags": {
+ "name": "Followed hashtags"
+ },
"fontSize": {
"name": "Toot Font Size"
},
@@ -53,7 +70,7 @@
"name": "Users in list: {{list}}"
},
"listAdd": {
- "name": "Add a List"
+ "name": "Create a List"
},
"listEdit": {
"name": "Edit List Details"
@@ -214,6 +231,12 @@
"status": {
"heading": "Toot from subscribed users"
},
+ "admin.sign_up": {
+ "heading": "Admin: sign up"
+ },
+ "admin.report": {
+ "heading": "Admin: reports"
+ },
"howitworks": "Learn how routing works"
},
"root": {
@@ -225,10 +248,8 @@
}
},
"push": {
- "content": {
- "enabled": "Enabled",
- "disabled": "Disabled"
- }
+ "content_true": "Enabled",
+ "content_false": "Disabled"
},
"update": {
"title": "Update to latest version"
@@ -290,9 +311,6 @@
"support": {
"heading": "Support tooot"
},
- "review": {
- "heading": "Review tooot"
- },
"contact": {
"heading": "Contact tooot"
},
@@ -330,7 +348,7 @@
"notInLists": "Other lists"
},
"attachments": {
- "name": "<0 /><1>\"s media1>"
+ "name": "<0 /><1>'s media1>"
},
"hashtag": {
"follow": "Follow",
@@ -377,7 +395,8 @@
"statuses": {
"reblogged_by": "{{count}} boosted",
"favourited_by": "{{count}} favourited"
- }
+ },
+ "resultIncomplete": "Results from a remote instance is incomplete"
}
}
}
\ No newline at end of file
diff --git a/src/i18n/es/common.json b/src/i18n/es/common.json
index ca8f5ee4..db90f304 100644
--- a/src/i18n/es/common.json
+++ b/src/i18n/es/common.json
@@ -5,6 +5,7 @@
"cancel": "Cancelar",
"discard": "Descartar",
"continue": "Continuar",
+ "create": "Crear",
"delete": "Borrar",
"done": "Hecho"
},
diff --git a/src/i18n/es/components/instance.json b/src/i18n/es/components/instance.json
index ab46d601..aa81a637 100644
--- a/src/i18n/es/components/instance.json
+++ b/src/i18n/es/components/instance.json
@@ -1,7 +1,7 @@
{
"server": {
"textInput": {
- "placeholder": "Dominio de la instancia"
+ "placeholder": ""
},
"button": "Iniciar sesión",
"information": {
diff --git a/src/i18n/es/components/timeline.json b/src/i18n/es/components/timeline.json
index 50304540..9c8607c9 100644
--- a/src/i18n/es/components/timeline.json
+++ b/src/i18n/es/components/timeline.json
@@ -30,7 +30,9 @@
"default": "{{name}} ha impulsado",
"notification": "{{name}} ha impulsado tu toot"
},
- "update": "El impulso ha sido editado"
+ "update": "El impulso ha sido editado",
+ "admin.sign_up": "",
+ "admin.report": ""
},
"actions": {
"reply": {
@@ -52,7 +54,8 @@
"bookmarked": {
"accessibilityLabel": "Añadir este toot en marcadores",
"function": "Añadir toot a marcadores"
- }
+ },
+ "openReport": ""
},
"actionsUsers": {
"reblogged_by": {
diff --git a/src/i18n/es/screens/actions.json b/src/i18n/es/screens/actions.json
index 291a1433..a8ddb9ce 100644
--- a/src/i18n/es/screens/actions.json
+++ b/src/i18n/es/screens/actions.json
@@ -2,19 +2,6 @@
"content": {
"altText": {
"heading": "Texto alternativo"
- },
- "notificationsFilter": {
- "heading": "Mostrar tipos de notificación",
- "content": {
- "follow": "$t(screenTabs:me.push.follow.heading)",
- "follow_request": "Solicitud de seguimiento",
- "favourite": "$t(screenTabs:me.push.favourite.heading)",
- "reblog": "$t(screenTabs:me.push.reblog.heading)",
- "mention": "$t(screenTabs:me.push.mention.heading)",
- "poll": "$t(screenTabs:me.push.poll.heading)",
- "status": "Toot de usuarios suscritos",
- "update": "El impulso ha sido editado"
- }
}
}
}
\ No newline at end of file
diff --git a/src/i18n/es/screens/compose.json b/src/i18n/es/screens/compose.json
index 60604b07..02e7f647 100644
--- a/src/i18n/es/screens/compose.json
+++ b/src/i18n/es/screens/compose.json
@@ -1,13 +1,11 @@
{
"heading": {
"left": {
- "button": "Cancelar",
"alert": {
"title": "¿Cancelar edición?",
"buttons": {
"save": "Guardar borrador",
- "delete": "Eliminar borrador",
- "cancel": "Cancelar"
+ "delete": "Eliminar borrador"
}
}
},
diff --git a/src/i18n/es/screens/tabs.json b/src/i18n/es/screens/tabs.json
index 61f5dca3..ddefffbe 100644
--- a/src/i18n/es/screens/tabs.json
+++ b/src/i18n/es/screens/tabs.json
@@ -1,20 +1,21 @@
{
"tabs": {
"local": {
- "name": "Siguiendo"
+ "name": "Siguiendo",
+ "options": {
+ "showBoosts": "",
+ "showReplies": ""
+ }
},
"public": {
- "name": "",
"segments": {
- "left": "Federado",
- "right": "Local"
+ "federated": "Federado",
+ "local": "Local",
+ "trending": "En tendencia"
}
},
"notifications": {
"name": "Notificaciones"
- },
- "me": {
- "name": "Sobre mí"
}
},
"common": {
@@ -24,9 +25,22 @@
}
},
"notifications": {
- "filter": {
+ "filters": {
"accessibilityLabel": "Filtrar",
- "accessibilityHint": "Filtrar tipos de notificación"
+ "accessibilityHint": "Filtrar tipos de notificación",
+ "title": "Mostrar las notificaciones",
+ "options": {
+ "follow": "$t(screenTabs:me.push.follow.heading)",
+ "follow_request": "Solicitud de seguimiento",
+ "favourite": "$t(screenTabs:me.push.favourite.heading)",
+ "reblog": "$t(screenTabs:me.push.reblog.heading)",
+ "mention": "$t(screenTabs:me.push.mention.heading)",
+ "poll": "$t(screenTabs:me.push.poll.heading)",
+ "status": "Toot de usuarios suscritos",
+ "update": "El impulso ha sido editado",
+ "admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
+ "admin.report": "$t(screenTabs:me.push.admin.report.heading)"
+ }
}
},
"me": {
@@ -40,6 +54,9 @@
"favourites": {
"name": "Favoritos"
},
+ "followedTags": {
+ "name": "Hashtags seguidos"
+ },
"fontSize": {
"name": "Tamaño de fuente"
},
@@ -53,7 +70,7 @@
"name": "Usuarios en la lista: {{list}}"
},
"listAdd": {
- "name": "Añadir una lista"
+ "name": "Crea una lista"
},
"listEdit": {
"name": "Editar detalles de lista"
@@ -179,8 +196,8 @@
"settings": "Activar en Ajustes"
},
"missingServerKey": {
- "message": "",
- "description": ""
+ "message": "Servidor mal configurado para las notificaciones push",
+ "description": "Por favor, contacte con el administrador de su servidor para configurar el soporte de notificaciones push"
},
"global": {
"heading": "Habilitar para {{acct}}",
@@ -214,6 +231,12 @@
"status": {
"heading": "Toot de usuarios suscritos"
},
+ "admin.sign_up": {
+ "heading": "Administración: Registrarse"
+ },
+ "admin.report": {
+ "heading": "Administración: denuncias"
+ },
"howitworks": "Más información sobre las notificaciones push"
},
"root": {
@@ -225,10 +248,8 @@
}
},
"push": {
- "content": {
- "enabled": "Habilitado",
- "disabled": "Deshabilitado"
- }
+ "content_true": "Habilitado",
+ "content_false": "Deshabilitado"
},
"update": {
"title": "Actualizar a la última versión"
@@ -290,9 +311,6 @@
"support": {
"heading": "Apoyar tooot"
},
- "review": {
- "heading": "Valorar tooot"
- },
"contact": {
"heading": "Contactar tooot"
},
@@ -330,7 +348,7 @@
"notInLists": "Otras listas"
},
"attachments": {
- "name": "Multimedia de <0 /><1>1>"
+ "name": ""
},
"hashtag": {
"follow": "Seguir",
@@ -377,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/common.json b/src/i18n/fr/common.json
index 0b47114c..af8479b8 100644
--- a/src/i18n/fr/common.json
+++ b/src/i18n/fr/common.json
@@ -3,8 +3,9 @@
"OK": "Ok",
"apply": "Confirmer",
"cancel": "Annuler",
- "discard": "",
- "continue": "",
+ "discard": "Ne pas tenir compte",
+ "continue": "Continuer",
+ "create": "",
"delete": "",
"done": ""
},
@@ -24,7 +25,7 @@
},
"separator": ", ",
"discard": {
- "title": "",
- "message": ""
+ "title": "Modifications non sauvegardées",
+ "message": "Votre modification n'a pas été enregistrée. Voulez-vous annuler l'enregistrement des modifications ?"
}
}
\ No newline at end of file
diff --git a/src/i18n/fr/components/contextMenu.json b/src/i18n/fr/components/contextMenu.json
index 3de56f9c..426a9834 100644
--- a/src/i18n/fr/components/contextMenu.json
+++ b/src/i18n/fr/components/contextMenu.json
@@ -3,7 +3,7 @@
"account": {
"title": "Actions de l'utilisateur",
"following": {
- "action_false": "",
+ "action_false": "Suivre l'utilisateur",
"action_true": ""
},
"inLists": "",
@@ -20,7 +20,7 @@
}
},
"at": {
- "direct": "",
+ "direct": "Message direct",
"public": ""
},
"copy": {
diff --git a/src/i18n/fr/components/instance.json b/src/i18n/fr/components/instance.json
index 7bea5931..a0300b8f 100644
--- a/src/i18n/fr/components/instance.json
+++ b/src/i18n/fr/components/instance.json
@@ -1,7 +1,7 @@
{
"server": {
"textInput": {
- "placeholder": "Domaine d'instance"
+ "placeholder": ""
},
"button": "Connexion",
"information": {
diff --git a/src/i18n/fr/components/timeline.json b/src/i18n/fr/components/timeline.json
index 8e417da4..27665adc 100644
--- a/src/i18n/fr/components/timeline.json
+++ b/src/i18n/fr/components/timeline.json
@@ -30,7 +30,9 @@
"default": "{{name}} a partagé",
"notification": "{{name}} a partagé votre message"
},
- "update": "Le reblog a été modifié"
+ "update": "Le reblog a été modifié",
+ "admin.sign_up": "",
+ "admin.report": ""
},
"actions": {
"reply": {
@@ -52,7 +54,8 @@
"bookmarked": {
"accessibilityLabel": "Ajouter ce pouet aux signets",
"function": "Pouet de signet"
- }
+ },
+ "openReport": ""
},
"actionsUsers": {
"reblogged_by": {
diff --git a/src/i18n/fr/screens/actions.json b/src/i18n/fr/screens/actions.json
index bf32e39c..ad1ac1af 100644
--- a/src/i18n/fr/screens/actions.json
+++ b/src/i18n/fr/screens/actions.json
@@ -2,19 +2,6 @@
"content": {
"altText": {
"heading": "Texte de remplacement"
- },
- "notificationsFilter": {
- "heading": "Afficher les notifications",
- "content": {
- "follow": "$t(screenTabs:me.push.follow.heading)",
- "follow_request": "Demande d'abonnement",
- "favourite": "$t(screenTabs:me.push.favourite.heading)",
- "reblog": "$t(screenTabs:me.push.reblog.heading)",
- "mention": "$t(screenTabs:me.push.mention.heading)",
- "poll": "$t(screenTabs:me.push.poll.heading)",
- "status": "Pouet des utilisateurs abonnés",
- "update": "Le reblog a été modifié"
- }
}
}
}
\ No newline at end of file
diff --git a/src/i18n/fr/screens/compose.json b/src/i18n/fr/screens/compose.json
index 7fd65c95..de0fbf17 100644
--- a/src/i18n/fr/screens/compose.json
+++ b/src/i18n/fr/screens/compose.json
@@ -1,13 +1,11 @@
{
"heading": {
"left": {
- "button": "Abandonner",
"alert": {
"title": "Annuler l’édition?",
"buttons": {
"save": "Enregistrer comme brouillon",
- "delete": "Supprimer le brouillon",
- "cancel": "Abandonner"
+ "delete": "Supprimer le brouillon"
}
}
},
diff --git a/src/i18n/fr/screens/tabs.json b/src/i18n/fr/screens/tabs.json
index 63032f59..c0205c2b 100644
--- a/src/i18n/fr/screens/tabs.json
+++ b/src/i18n/fr/screens/tabs.json
@@ -1,20 +1,21 @@
{
"tabs": {
"local": {
- "name": "Suit"
+ "name": "Suit",
+ "options": {
+ "showBoosts": "",
+ "showReplies": ""
+ }
},
"public": {
- "name": "",
"segments": {
- "left": "Fédéré",
- "right": "Local"
+ "federated": "Fédéré",
+ "local": "Local",
+ "trending": ""
}
},
"notifications": {
"name": "Notifications"
- },
- "me": {
- "name": "À propos de moi"
}
},
"common": {
@@ -24,9 +25,22 @@
}
},
"notifications": {
- "filter": {
+ "filters": {
"accessibilityLabel": "Filtrer",
- "accessibilityHint": "Filtrer les types de notifications affichés"
+ "accessibilityHint": "Filtrer les types de notifications affichés",
+ "title": "",
+ "options": {
+ "follow": "$t(screenTabs:me.push.follow.heading)",
+ "follow_request": "Demande d'abonnement",
+ "favourite": "$t(screenTabs:me.push.favourite.heading)",
+ "reblog": "$t(screenTabs:me.push.reblog.heading)",
+ "mention": "$t(screenTabs:me.push.mention.heading)",
+ "poll": "$t(screenTabs:me.push.poll.heading)",
+ "status": "Pouet des utilisateurs inscrits",
+ "update": "Le reblog a été modifié",
+ "admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
+ "admin.report": "$t(screenTabs:me.push.admin.report.heading)"
+ }
}
},
"me": {
@@ -40,6 +54,9 @@
"favourites": {
"name": "Favoris"
},
+ "followedTags": {
+ "name": ""
+ },
"fontSize": {
"name": "Taille de la police de Pouet"
},
@@ -214,6 +231,12 @@
"status": {
"heading": "Pouet des utilisateurs inscrits"
},
+ "admin.sign_up": {
+ "heading": ""
+ },
+ "admin.report": {
+ "heading": ""
+ },
"howitworks": "Apprenez comment cela fonctionne"
},
"root": {
@@ -225,10 +248,8 @@
}
},
"push": {
- "content": {
- "enabled": "Activé",
- "disabled": "Désactivé"
- }
+ "content_true": "Activé",
+ "content_false": "Désactivé"
},
"update": {
"title": "Mettre à jour vers la dernière version"
@@ -290,9 +311,6 @@
"support": {
"heading": "Support de tooot"
},
- "review": {
- "heading": "Examiner le tooot"
- },
"contact": {
"heading": "Contacter tooot"
},
@@ -330,7 +348,7 @@
"notInLists": ""
},
"attachments": {
- "name": "<0 /><1>\"s media1>"
+ "name": ""
},
"hashtag": {
"follow": "Suivre",
@@ -377,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/i18n.ts b/src/i18n/i18n.ts
index d0b71546..9ad75d91 100644
--- a/src/i18n/i18n.ts
+++ b/src/i18n/i18n.ts
@@ -12,6 +12,7 @@ import ko from '@root/i18n/ko'
import nl from '@root/i18n/nl'
import pt_BR from '@root/i18n/pt_BR'
import sv from '@root/i18n/sv'
+import uk from '@root/i18n/uk'
import vi from '@root/i18n/vi'
import zh_Hans from '@root/i18n/zh-Hans'
import zh_Hant from '@root/i18n/zh-Hant'
@@ -31,6 +32,7 @@ import '@formatjs/intl-pluralrules/locale-data/ko'
import '@formatjs/intl-pluralrules/locale-data/nl'
import '@formatjs/intl-pluralrules/locale-data/pt'
import '@formatjs/intl-pluralrules/locale-data/sv'
+import '@formatjs/intl-pluralrules/locale-data/uk'
import '@formatjs/intl-pluralrules/locale-data/vi'
import '@formatjs/intl-pluralrules/locale-data/zh'
@@ -46,6 +48,7 @@ import '@formatjs/intl-numberformat/locale-data/ko'
import '@formatjs/intl-numberformat/locale-data/nl'
import '@formatjs/intl-numberformat/locale-data/pt'
import '@formatjs/intl-numberformat/locale-data/sv'
+import '@formatjs/intl-numberformat/locale-data/uk'
import '@formatjs/intl-numberformat/locale-data/vi'
import '@formatjs/intl-numberformat/locale-data/zh-Hans'
import '@formatjs/intl-numberformat/locale-data/zh-Hant'
@@ -62,6 +65,7 @@ import '@formatjs/intl-datetimeformat/locale-data/ko'
import '@formatjs/intl-datetimeformat/locale-data/nl'
import '@formatjs/intl-datetimeformat/locale-data/pt'
import '@formatjs/intl-datetimeformat/locale-data/sv'
+import '@formatjs/intl-datetimeformat/locale-data/uk'
import '@formatjs/intl-datetimeformat/locale-data/vi'
import '@formatjs/intl-datetimeformat/locale-data/zh-Hans'
import '@formatjs/intl-datetimeformat/locale-data/zh-Hant'
@@ -79,6 +83,7 @@ import '@formatjs/intl-relativetimeformat/locale-data/ko'
import '@formatjs/intl-relativetimeformat/locale-data/nl'
import '@formatjs/intl-relativetimeformat/locale-data/pt'
import '@formatjs/intl-relativetimeformat/locale-data/sv'
+import '@formatjs/intl-relativetimeformat/locale-data/uk'
import '@formatjs/intl-relativetimeformat/locale-data/vi'
import '@formatjs/intl-relativetimeformat/locale-data/zh-Hans'
import '@formatjs/intl-relativetimeformat/locale-data/zh-Hant'
@@ -102,6 +107,7 @@ i18n.use(initReactI18next).init({
nl,
'pt-BR': pt_BR,
sv,
+ uk,
vi,
'zh-Hans': zh_Hans,
'zh-Hant': zh_Hant
diff --git a/src/i18n/it/common.json b/src/i18n/it/common.json
index daed31b9..32526501 100644
--- a/src/i18n/it/common.json
+++ b/src/i18n/it/common.json
@@ -3,8 +3,9 @@
"OK": "OK",
"apply": "Applica",
"cancel": "Annulla",
- "discard": "",
- "continue": "",
+ "discard": "Scarta",
+ "continue": "Continua",
+ "create": "",
"delete": "",
"done": ""
},
@@ -24,7 +25,7 @@
},
"separator": ", ",
"discard": {
- "title": "",
- "message": ""
+ "title": "Modifiche non salvate",
+ "message": "Le tue modifiche non sono state salvate. Vuoi scartarle?"
}
}
\ No newline at end of file
diff --git a/src/i18n/it/components/contextMenu.json b/src/i18n/it/components/contextMenu.json
index 7f216bf5..d3777054 100644
--- a/src/i18n/it/components/contextMenu.json
+++ b/src/i18n/it/components/contextMenu.json
@@ -3,7 +3,7 @@
"account": {
"title": "Azioni utente",
"following": {
- "action_false": "",
+ "action_false": "Segui utente",
"action_true": ""
},
"inLists": "",
@@ -20,7 +20,7 @@
}
},
"at": {
- "direct": "",
+ "direct": "Messaggio diretto",
"public": ""
},
"copy": {
diff --git a/src/i18n/it/components/instance.json b/src/i18n/it/components/instance.json
index 4919837e..b69f1f9f 100644
--- a/src/i18n/it/components/instance.json
+++ b/src/i18n/it/components/instance.json
@@ -1,7 +1,7 @@
{
"server": {
"textInput": {
- "placeholder": "Dominio dell'istanza"
+ "placeholder": ""
},
"button": "Accedi",
"information": {
diff --git a/src/i18n/it/components/timeline.json b/src/i18n/it/components/timeline.json
index 3b1a40c6..ae7895be 100644
--- a/src/i18n/it/components/timeline.json
+++ b/src/i18n/it/components/timeline.json
@@ -30,7 +30,9 @@
"default": "{{name}} ha ricondiviso",
"notification": "{{name}} ha ricondiviso il tuo toot"
},
- "update": "Il link è stato modificato"
+ "update": "Il link è stato modificato",
+ "admin.sign_up": "",
+ "admin.report": ""
},
"actions": {
"reply": {
@@ -52,7 +54,8 @@
"bookmarked": {
"accessibilityLabel": "Aggiungi questo toot ai segnalibri",
"function": "Aggiungi toot ai segnalibri"
- }
+ },
+ "openReport": ""
},
"actionsUsers": {
"reblogged_by": {
diff --git a/src/i18n/it/screens/actions.json b/src/i18n/it/screens/actions.json
index b428b43c..87c42f64 100644
--- a/src/i18n/it/screens/actions.json
+++ b/src/i18n/it/screens/actions.json
@@ -2,19 +2,6 @@
"content": {
"altText": {
"heading": "Testo descrittivo"
- },
- "notificationsFilter": {
- "heading": "Filtra notifiche per tipo",
- "content": {
- "follow": "$t(screenTabs:me.push.follow.heading)",
- "follow_request": "Richiesta di seguirti",
- "favourite": "$t(screenTabs:me.push.favourite.heading)",
- "reblog": "$t(screenTabs:me.push.reblog.heading)",
- "mention": "$t(screenTabs:me.push.mention.heading)",
- "poll": "$t(screenTabs:me.push.poll.heading)",
- "status": "Toot da utenti seguiti",
- "update": "Retoot ha subito una modifica"
- }
}
}
}
\ No newline at end of file
diff --git a/src/i18n/it/screens/compose.json b/src/i18n/it/screens/compose.json
index 589f34b1..76860e01 100644
--- a/src/i18n/it/screens/compose.json
+++ b/src/i18n/it/screens/compose.json
@@ -1,13 +1,11 @@
{
"heading": {
"left": {
- "button": "Annulla",
"alert": {
"title": "Scartare il toot?",
"buttons": {
"save": "Salva bozza",
- "delete": "Elimina bozza",
- "cancel": "Annulla"
+ "delete": "Elimina bozza"
}
}
},
diff --git a/src/i18n/it/screens/tabs.json b/src/i18n/it/screens/tabs.json
index f097708a..981af617 100644
--- a/src/i18n/it/screens/tabs.json
+++ b/src/i18n/it/screens/tabs.json
@@ -1,20 +1,21 @@
{
"tabs": {
"local": {
- "name": "Home"
+ "name": "Home",
+ "options": {
+ "showBoosts": "",
+ "showReplies": ""
+ }
},
"public": {
- "name": "",
"segments": {
- "left": "Federazione",
- "right": "Locale"
+ "federated": "Federazione",
+ "local": "Locale",
+ "trending": ""
}
},
"notifications": {
"name": "Notifiche"
- },
- "me": {
- "name": "Profilo"
}
},
"common": {
@@ -24,9 +25,22 @@
}
},
"notifications": {
- "filter": {
+ "filters": {
"accessibilityLabel": "Filtri",
- "accessibilityHint": "Filtra le notifiche mostrate per tipo"
+ "accessibilityHint": "Filtra le notifiche mostrate per tipo",
+ "title": "",
+ "options": {
+ "follow": "$t(screenTabs:me.push.follow.heading)",
+ "follow_request": "Richiesta di seguirti",
+ "favourite": "$t(screenTabs:me.push.favourite.heading)",
+ "reblog": "$t(screenTabs:me.push.reblog.heading)",
+ "mention": "$t(screenTabs:me.push.mention.heading)",
+ "poll": "$t(screenTabs:me.push.poll.heading)",
+ "status": "Toot da utenti seguiti",
+ "update": "Il link è stato modificato",
+ "admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
+ "admin.report": "$t(screenTabs:me.push.admin.report.heading)"
+ }
}
},
"me": {
@@ -40,6 +54,9 @@
"favourites": {
"name": "Apprezzati"
},
+ "followedTags": {
+ "name": ""
+ },
"fontSize": {
"name": "Grandezza del testo dei toot"
},
@@ -214,6 +231,12 @@
"status": {
"heading": "Toot da utenti seguiti"
},
+ "admin.sign_up": {
+ "heading": ""
+ },
+ "admin.report": {
+ "heading": ""
+ },
"howitworks": "Scopri come funziona il traversamento dei messaggi"
},
"root": {
@@ -225,10 +248,8 @@
}
},
"push": {
- "content": {
- "enabled": "Abilitato",
- "disabled": "Disabilitato"
- }
+ "content_true": "Abilitato",
+ "content_false": "Disabilitato"
},
"update": {
"title": "Aggiorna all'ultima versione"
@@ -290,9 +311,6 @@
"support": {
"heading": "Supporta tooot"
},
- "review": {
- "heading": "Recensisci tooot"
- },
"contact": {
"heading": "Contatta tooot"
},
@@ -330,7 +348,7 @@
"notInLists": ""
},
"attachments": {
- "name": "Media di <0 /><1>\"1>"
+ "name": ""
},
"hashtag": {
"follow": "Segui",
@@ -377,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/common.json b/src/i18n/ja/common.json
index b2f8b369..f774e735 100644
--- a/src/i18n/ja/common.json
+++ b/src/i18n/ja/common.json
@@ -5,6 +5,7 @@
"cancel": "キャンセル",
"discard": "変更を破棄",
"continue": "続ける",
+ "create": "",
"delete": "削除",
"done": "完了"
},
diff --git a/src/i18n/ja/components/timeline.json b/src/i18n/ja/components/timeline.json
index f7ae3da2..519101c3 100644
--- a/src/i18n/ja/components/timeline.json
+++ b/src/i18n/ja/components/timeline.json
@@ -30,7 +30,9 @@
"default": "{{name}}さんがブースト",
"notification": "{{name}}さんがあなたのトゥートをブーストしました"
},
- "update": "ブーストしたトゥートが編集されました"
+ "update": "ブーストしたトゥートが編集されました",
+ "admin.sign_up": "{{name}} がインスタンスに参加しました",
+ "admin.report": ""
},
"actions": {
"reply": {
@@ -52,7 +54,8 @@
"bookmarked": {
"accessibilityLabel": "このトゥートをブックマークに追加",
"function": "ブックマークトゥート"
- }
+ },
+ "openReport": ""
},
"actionsUsers": {
"reblogged_by": {
diff --git a/src/i18n/ja/screens/actions.json b/src/i18n/ja/screens/actions.json
index d407ed96..0390d4cb 100644
--- a/src/i18n/ja/screens/actions.json
+++ b/src/i18n/ja/screens/actions.json
@@ -2,19 +2,6 @@
"content": {
"altText": {
"heading": "代替テキスト"
- },
- "notificationsFilter": {
- "heading": "通知の種類を表示",
- "content": {
- "follow": "$t(screenTabs:me.push.follow.heading)",
- "follow_request": "フォローリクエスト",
- "favourite": "$t(screenTabs:me.push.favourite.heading)",
- "reblog": "$t(screenTabs:me.push.reblog.heading)",
- "mention": "$t(screenTabs:me.push.mention.heading)",
- "poll": "$t(screenTabs:me.push.poll.heading)",
- "status": "購読中のユーザーからのトゥート",
- "update": "リブログが編集されました"
- }
}
}
}
\ No newline at end of file
diff --git a/src/i18n/ja/screens/compose.json b/src/i18n/ja/screens/compose.json
index 31cb0bf8..f39cb2eb 100644
--- a/src/i18n/ja/screens/compose.json
+++ b/src/i18n/ja/screens/compose.json
@@ -1,13 +1,11 @@
{
"heading": {
"left": {
- "button": "キャンセル",
"alert": {
"title": "編集をキャンセルしますか?",
"buttons": {
"save": "下書きを保存",
- "delete": "下書きを削除",
- "cancel": "キャンセル"
+ "delete": "下書きを削除"
}
}
},
diff --git a/src/i18n/ja/screens/tabs.json b/src/i18n/ja/screens/tabs.json
index 0e4c4939..2df441a6 100644
--- a/src/i18n/ja/screens/tabs.json
+++ b/src/i18n/ja/screens/tabs.json
@@ -1,20 +1,21 @@
{
"tabs": {
"local": {
- "name": "ホーム"
+ "name": "ホーム",
+ "options": {
+ "showBoosts": "",
+ "showReplies": ""
+ }
},
"public": {
- "name": "",
"segments": {
- "left": "連合",
- "right": "ローカル"
+ "federated": "連合",
+ "local": "ローカル",
+ "trending": "トレンド"
}
},
"notifications": {
"name": "通知"
- },
- "me": {
- "name": "私について"
}
},
"common": {
@@ -24,9 +25,22 @@
}
},
"notifications": {
- "filter": {
+ "filters": {
"accessibilityLabel": "フィルター",
- "accessibilityHint": "表示される通知の種類をフィルターする"
+ "accessibilityHint": "表示される通知の種類をフィルターする",
+ "title": "",
+ "options": {
+ "follow": "$t(screenTabs:me.push.follow.heading)",
+ "follow_request": "フォローリクエスト",
+ "favourite": "$t(screenTabs:me.push.favourite.heading)",
+ "reblog": "$t(screenTabs:me.push.reblog.heading)",
+ "mention": "$t(screenTabs:me.push.mention.heading)",
+ "poll": "$t(screenTabs:me.push.poll.heading)",
+ "status": "購読したユーザーのトゥート",
+ "update": "ブーストしたトゥートが編集されました",
+ "admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
+ "admin.report": "$t(screenTabs:me.push.admin.report.heading)"
+ }
}
},
"me": {
@@ -40,6 +54,9 @@
"favourites": {
"name": "お気に入り"
},
+ "followedTags": {
+ "name": ""
+ },
"fontSize": {
"name": "トゥートのフォントサイズ"
},
@@ -53,7 +70,7 @@
"name": "リスト {{list}} のユーザー"
},
"listAdd": {
- "name": "リストに追加"
+ "name": ""
},
"listEdit": {
"name": "リストの詳細を編集"
@@ -214,6 +231,12 @@
"status": {
"heading": "購読したユーザーのトゥート"
},
+ "admin.sign_up": {
+ "heading": ""
+ },
+ "admin.report": {
+ "heading": ""
+ },
"howitworks": "通知到達(routing)のしくみを学ぶ"
},
"root": {
@@ -225,10 +248,8 @@
}
},
"push": {
- "content": {
- "enabled": "有効",
- "disabled": "無効"
- }
+ "content_true": "有効",
+ "content_false": "無効"
},
"update": {
"title": "最新バージョンへのアップデート"
@@ -290,9 +311,6 @@
"support": {
"heading": "tooot をサポート"
},
- "review": {
- "heading": "tooot をレビュー"
- },
"contact": {
"heading": "tooot に関する連絡"
},
@@ -330,7 +348,7 @@
"notInLists": "その他のリスト"
},
"attachments": {
- "name": "<0 /><1>\" のメディア1>"
+ "name": "<0 /><1>のメディア1>"
},
"hashtag": {
"follow": "フォロー",
@@ -377,7 +395,8 @@
"statuses": {
"reblogged_by": "{{count}} ブースト",
"favourited_by": "{{count}} お気に入り"
- }
+ },
+ "resultIncomplete": ""
}
}
}
\ No newline at end of file
diff --git a/src/i18n/ko/common.json b/src/i18n/ko/common.json
index d6a3c406..ce49034d 100644
--- a/src/i18n/ko/common.json
+++ b/src/i18n/ko/common.json
@@ -5,6 +5,7 @@
"cancel": "취소",
"discard": "취소",
"continue": "계속",
+ "create": "",
"delete": "삭제",
"done": "완료"
},
diff --git a/src/i18n/ko/components/contextMenu.json b/src/i18n/ko/components/contextMenu.json
index 976a20b2..5033a27a 100644
--- a/src/i18n/ko/components/contextMenu.json
+++ b/src/i18n/ko/components/contextMenu.json
@@ -20,8 +20,8 @@
}
},
"at": {
- "direct": "",
- "public": ""
+ "direct": "개인 메시지",
+ "public": "공개 메시지"
},
"copy": {
"action": "툿 복사",
diff --git a/src/i18n/ko/components/instance.json b/src/i18n/ko/components/instance.json
index c673b5ce..6b717955 100644
--- a/src/i18n/ko/components/instance.json
+++ b/src/i18n/ko/components/instance.json
@@ -1,7 +1,7 @@
{
"server": {
"textInput": {
- "placeholder": "인스턴스의 도메인"
+ "placeholder": ""
},
"button": "로그인",
"information": {
diff --git a/src/i18n/ko/components/timeline.json b/src/i18n/ko/components/timeline.json
index 8d2d0e6f..1da04abd 100644
--- a/src/i18n/ko/components/timeline.json
+++ b/src/i18n/ko/components/timeline.json
@@ -30,7 +30,9 @@
"default": "{{name}} 님이 부스트했어요",
"notification": "{{name}} 님이 내 툿을 부스트했어요"
},
- "update": "리블로그가 수정됨"
+ "update": "부스트한 툿이 수정됨",
+ "admin.sign_up": "",
+ "admin.report": ""
},
"actions": {
"reply": {
@@ -52,7 +54,8 @@
"bookmarked": {
"accessibilityLabel": "툿 북마크에 추가",
"function": "툿 북마크"
- }
+ },
+ "openReport": ""
},
"actionsUsers": {
"reblogged_by": {
diff --git a/src/i18n/ko/screens/actions.json b/src/i18n/ko/screens/actions.json
index 03919b20..c1f87f17 100644
--- a/src/i18n/ko/screens/actions.json
+++ b/src/i18n/ko/screens/actions.json
@@ -2,19 +2,6 @@
"content": {
"altText": {
"heading": "대체 텍스트"
- },
- "notificationsFilter": {
- "heading": "알림 종류 표시",
- "content": {
- "follow": "$t(screenTabs:me.push.follow.heading)",
- "follow_request": "팔로우 요청",
- "favourite": "$t(screenTabs:me.push.favourite.heading)",
- "reblog": "$t(screenTabs:me.push.reblog.heading)",
- "mention": "$t(screenTabs:me.push.mention.heading)",
- "poll": "$t(screenTabs:me.push.poll.heading)",
- "status": "구독한 사용자의 툿",
- "update": "리블로그가 수정되었습니다."
- }
}
}
}
\ No newline at end of file
diff --git a/src/i18n/ko/screens/compose.json b/src/i18n/ko/screens/compose.json
index c96f785b..dbab2698 100644
--- a/src/i18n/ko/screens/compose.json
+++ b/src/i18n/ko/screens/compose.json
@@ -1,13 +1,11 @@
{
"heading": {
"left": {
- "button": "취소",
"alert": {
"title": "작성을 취소할까요?",
"buttons": {
"save": "임시 저장",
- "delete": "임시 저장한 내용 삭제",
- "cancel": "취소"
+ "delete": "임시 저장한 내용 삭제"
}
}
},
diff --git a/src/i18n/ko/screens/tabs.json b/src/i18n/ko/screens/tabs.json
index 37212eb9..86708a64 100644
--- a/src/i18n/ko/screens/tabs.json
+++ b/src/i18n/ko/screens/tabs.json
@@ -1,20 +1,21 @@
{
"tabs": {
"local": {
- "name": "팔로우 중"
+ "name": "팔로우 중",
+ "options": {
+ "showBoosts": "",
+ "showReplies": ""
+ }
},
"public": {
- "name": "",
"segments": {
- "left": "연합",
- "right": "로컬"
+ "federated": "연합",
+ "local": "로컬",
+ "trending": ""
}
},
"notifications": {
"name": "알림"
- },
- "me": {
- "name": "내 소개"
}
},
"common": {
@@ -24,9 +25,22 @@
}
},
"notifications": {
- "filter": {
+ "filters": {
"accessibilityLabel": "필터",
- "accessibilityHint": "받는 알림 종류 선택"
+ "accessibilityHint": "받는 알림 종류 선택",
+ "title": "",
+ "options": {
+ "follow": "$t(screenTabs:me.push.follow.heading)",
+ "follow_request": "팔로우 요청",
+ "favourite": "$t(screenTabs:me.push.favourite.heading)",
+ "reblog": "$t(screenTabs:me.push.reblog.heading)",
+ "mention": "$t(screenTabs:me.push.mention.heading)",
+ "poll": "$t(screenTabs:me.push.poll.heading)",
+ "status": "구독한 사용자의 툿",
+ "update": "부스트한 툿이 수정됨",
+ "admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
+ "admin.report": "$t(screenTabs:me.push.admin.report.heading)"
+ }
}
},
"me": {
@@ -40,6 +54,9 @@
"favourites": {
"name": "즐겨찾기"
},
+ "followedTags": {
+ "name": ""
+ },
"fontSize": {
"name": "툿 폰트 크기"
},
@@ -53,7 +70,7 @@
"name": "{{list}} 리스트의 사용자"
},
"listAdd": {
- "name": "리스트에 추가"
+ "name": ""
},
"listEdit": {
"name": "리스트 상세 편집"
@@ -179,8 +196,8 @@
"settings": "설정에서 활성화"
},
"missingServerKey": {
- "message": "",
- "description": ""
+ "message": "서버가 푸시를 지원하지 않음",
+ "description": "서버 관리자에게 푸시 알림을 지원하도록 문의해주세요"
},
"global": {
"heading": "{{acct}} 활성화",
@@ -214,6 +231,12 @@
"status": {
"heading": "구독한 사용자의 툿"
},
+ "admin.sign_up": {
+ "heading": ""
+ },
+ "admin.report": {
+ "heading": ""
+ },
"howitworks": "메시지 라우팅 방식 더 알아보기"
},
"root": {
@@ -225,10 +248,8 @@
}
},
"push": {
- "content": {
- "enabled": "활성화됨",
- "disabled": "비활성화됨"
- }
+ "content_true": "활성화됨",
+ "content_false": "비활성화됨"
},
"update": {
"title": "최신 버전으로 업데이트"
@@ -290,9 +311,6 @@
"support": {
"heading": "tooot 기부"
},
- "review": {
- "heading": "tooot 리뷰"
- },
"contact": {
"heading": "tooot 연락"
},
@@ -330,7 +348,7 @@
"notInLists": "다른 리스트"
},
"attachments": {
- "name": "<0 /><1>의 미디어1>"
+ "name": ""
},
"hashtag": {
"follow": "팔로우",
@@ -377,7 +395,8 @@
"statuses": {
"reblogged_by": "{{count}} 부스트",
"favourited_by": "{{count}} 즐겨찾기"
- }
+ },
+ "resultIncomplete": ""
}
}
}
\ No newline at end of file
diff --git a/src/i18n/locales.ts b/src/i18n/locales.ts
index 44ef48dc..df5a7f33 100644
--- a/src/i18n/locales.ts
+++ b/src/i18n/locales.ts
@@ -10,6 +10,7 @@ const LOCALES = {
nl: 'Nederlands',
'pt-br': 'Português (Brasil)',
sv: 'Svenska',
+ uk: 'українська',
vi: 'Tiếng Việt',
'zh-hans': '简体中文',
'zh-hant': '繁體中文'
diff --git a/src/i18n/nl/common.json b/src/i18n/nl/common.json
index 02c05685..e9a502bd 100644
--- a/src/i18n/nl/common.json
+++ b/src/i18n/nl/common.json
@@ -5,6 +5,7 @@
"cancel": "Annuleer",
"discard": "Verwijder",
"continue": "Ga verder",
+ "create": "Maak",
"delete": "Verwijder",
"done": "Gereed"
},
diff --git a/src/i18n/nl/components/timeline.json b/src/i18n/nl/components/timeline.json
index 68e68fee..6fe4786b 100644
--- a/src/i18n/nl/components/timeline.json
+++ b/src/i18n/nl/components/timeline.json
@@ -30,7 +30,9 @@
"default": "{{name}} boostte",
"notification": "{{name}} boostte jouw toot"
},
- "update": "De reblog is bewerkt"
+ "update": "De reblog is bewerkt",
+ "admin.sign_up": "{{name}} heeft zich aangesloten bij de instantie",
+ "admin.report": "{{name}} rapporteerde:"
},
"actions": {
"reply": {
@@ -52,7 +54,8 @@
"bookmarked": {
"accessibilityLabel": "Toot toevoegen aan bladwijzers",
"function": "Voeg deze toot toe aan bladwijzers"
- }
+ },
+ "openReport": "Rapportage openen"
},
"actionsUsers": {
"reblogged_by": {
diff --git a/src/i18n/nl/screens/actions.json b/src/i18n/nl/screens/actions.json
index 519e01a5..d9b0d313 100644
--- a/src/i18n/nl/screens/actions.json
+++ b/src/i18n/nl/screens/actions.json
@@ -2,19 +2,6 @@
"content": {
"altText": {
"heading": "Alternatieve tekst"
- },
- "notificationsFilter": {
- "heading": "Melding soorten weergeven",
- "content": {
- "follow": "$t(screenTabs:me.push.follow.heading)",
- "follow_request": "Volgverzoek",
- "favourite": "$t(screenTabs:me.push.favourite.heading)",
- "reblog": "$t(screenTabs:me.push.reblog.heading)",
- "mention": "$t(screenTabs:me.push.mention.heading)",
- "poll": "$t(screenTabs:me.push.poll.heading)",
- "status": "Toot van geabonneerde gebruikers",
- "update": "De reblog is bewerkt"
- }
}
}
}
\ No newline at end of file
diff --git a/src/i18n/nl/screens/compose.json b/src/i18n/nl/screens/compose.json
index d14dc421..00a0a43c 100644
--- a/src/i18n/nl/screens/compose.json
+++ b/src/i18n/nl/screens/compose.json
@@ -1,13 +1,11 @@
{
"heading": {
"left": {
- "button": "Annuleer",
"alert": {
"title": "Bewerken annuleren?",
"buttons": {
"save": "Concept opslaan",
- "delete": "Concept verwijderen",
- "cancel": "Annuleer"
+ "delete": "Concept verwijderen"
}
}
},
diff --git a/src/i18n/nl/screens/tabs.json b/src/i18n/nl/screens/tabs.json
index c15cc96d..4e80882c 100644
--- a/src/i18n/nl/screens/tabs.json
+++ b/src/i18n/nl/screens/tabs.json
@@ -1,20 +1,21 @@
{
"tabs": {
"local": {
- "name": "Volgend"
+ "name": "Volgend",
+ "options": {
+ "showBoosts": "Boosts tonen",
+ "showReplies": "Reacties tonen"
+ }
},
"public": {
- "name": "",
"segments": {
- "left": "Globaal",
- "right": "Lokaal"
+ "federated": "Globaal",
+ "local": "Lokaal",
+ "trending": "Trending"
}
},
"notifications": {
"name": "Meldingen"
- },
- "me": {
- "name": "Over mij"
}
},
"common": {
@@ -24,9 +25,22 @@
}
},
"notifications": {
- "filter": {
+ "filters": {
"accessibilityLabel": "Filter",
- "accessibilityHint": "Filter getoonde meldingstypes"
+ "accessibilityHint": "Filter getoonde meldingstypes",
+ "title": "Notificaties weergeven",
+ "options": {
+ "follow": "$t(screenTabs:me.push.follow.heading)",
+ "follow_request": "Volgverzoek",
+ "favourite": "$t(screenTabs:me.push.favourite.heading)",
+ "reblog": "$t(screenTabs:me.push.reblog.heading)",
+ "mention": "$t(screenTabs:me.push.mention.heading)",
+ "poll": "$t(screenTabs:me.push.poll.heading)",
+ "status": "Toot van geabonneerde gebruikers",
+ "update": "De reblog is bewerkt",
+ "admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
+ "admin.report": "$t(screenTabs:me.push.admin.report.heading)"
+ }
}
},
"me": {
@@ -40,6 +54,9 @@
"favourites": {
"name": "Favorieten"
},
+ "followedTags": {
+ "name": "Gevolgde hashtags"
+ },
"fontSize": {
"name": "Grootte van lettertype"
},
@@ -53,7 +70,7 @@
"name": "Gebruikers in de lijst: {{list}}"
},
"listAdd": {
- "name": "Lijst toevoegen"
+ "name": "Lijst aanmaken"
},
"listEdit": {
"name": "Lijstdetails bewerken"
@@ -179,8 +196,8 @@
"settings": "Inschakelen in instellingen"
},
"missingServerKey": {
- "message": "",
- "description": ""
+ "message": "Server is verkeerd geconfigureerd voor push",
+ "description": "Neem contact op met de serverbeheerder om push-ondersteuning te configureren"
},
"global": {
"heading": "Inschakelen voor {{acct}}",
@@ -214,6 +231,12 @@
"status": {
"heading": "Toot van geabonneerde gebruikers"
},
+ "admin.sign_up": {
+ "heading": "Admin: registreren"
+ },
+ "admin.report": {
+ "heading": "Admin: rapporten"
+ },
"howitworks": "Leer hoe het werkt"
},
"root": {
@@ -225,10 +248,8 @@
}
},
"push": {
- "content": {
- "enabled": "Ingeschakeld",
- "disabled": "Uitgeschakeld"
- }
+ "content_true": "Ingeschakeld",
+ "content_false": "Uitgeschakeld"
},
"update": {
"title": "Bijwerken naar de laatste versie"
@@ -290,9 +311,6 @@
"support": {
"heading": "Tooot ondersteunen"
},
- "review": {
- "heading": "Tooot beoordelen"
- },
"contact": {
"heading": "Tooot contacteren"
},
@@ -330,7 +348,7 @@
"notInLists": "Andere lijsten"
},
"attachments": {
- "name": "<0 /><1>\"s media1>"
+ "name": "<0 /><1>'s media1>"
},
"hashtag": {
"follow": "Volg",
@@ -377,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/common.json b/src/i18n/pl/common.json
index 59af91e9..fe4bfc45 100644
--- a/src/i18n/pl/common.json
+++ b/src/i18n/pl/common.json
@@ -3,9 +3,10 @@
"OK": "Ok",
"apply": "Zastosuj",
"cancel": "Anuluj",
- "discard": "",
- "continue": "",
- "delete": "",
+ "discard": "Anuluj",
+ "continue": "Dalej",
+ "create": "",
+ "delete": "Usuń",
"done": ""
},
"customEmoji": {
@@ -24,7 +25,7 @@
},
"separator": ", ",
"discard": {
- "title": "",
- "message": ""
+ "title": "Zmiany nie zostały zapisane",
+ "message": "Wyjść bez zapisania zmian?"
}
}
\ No newline at end of file
diff --git a/src/i18n/pl/components/contextMenu.json b/src/i18n/pl/components/contextMenu.json
index 89d1e76e..69478c88 100644
--- a/src/i18n/pl/components/contextMenu.json
+++ b/src/i18n/pl/components/contextMenu.json
@@ -3,63 +3,63 @@
"account": {
"title": "",
"following": {
- "action_false": "",
- "action_true": ""
+ "action_false": "Obserwuj",
+ "action_true": "Przestań obserwować"
},
"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": ""
+ "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/components/timeline.json b/src/i18n/pl/components/timeline.json
index 50d15c09..d823a1d1 100644
--- a/src/i18n/pl/components/timeline.json
+++ b/src/i18n/pl/components/timeline.json
@@ -30,7 +30,9 @@
"default": "",
"notification": ""
},
- "update": ""
+ "update": "",
+ "admin.sign_up": "{{name}} dołącza do instancji",
+ "admin.report": ""
},
"actions": {
"reply": {
@@ -52,7 +54,8 @@
"bookmarked": {
"accessibilityLabel": "",
"function": ""
- }
+ },
+ "openReport": ""
},
"actionsUsers": {
"reblogged_by": {
diff --git a/src/i18n/pl/screens/actions.json b/src/i18n/pl/screens/actions.json
index 55e9959c..96dce3a8 100644
--- a/src/i18n/pl/screens/actions.json
+++ b/src/i18n/pl/screens/actions.json
@@ -2,19 +2,6 @@
"content": {
"altText": {
"heading": ""
- },
- "notificationsFilter": {
- "heading": "",
- "content": {
- "follow": "",
- "follow_request": "",
- "favourite": "",
- "reblog": "",
- "mention": "",
- "poll": "",
- "status": "",
- "update": ""
- }
}
}
}
\ No newline at end of file
diff --git a/src/i18n/pl/screens/compose.json b/src/i18n/pl/screens/compose.json
index ebf265d9..2a078c68 100644
--- a/src/i18n/pl/screens/compose.json
+++ b/src/i18n/pl/screens/compose.json
@@ -1,13 +1,11 @@
{
"heading": {
"left": {
- "button": "",
"alert": {
"title": "",
"buttons": {
"save": "",
- "delete": "",
- "cancel": ""
+ "delete": ""
}
}
},
diff --git a/src/i18n/pl/screens/tabs.json b/src/i18n/pl/screens/tabs.json
index c85d6c3c..a6e930fe 100644
--- a/src/i18n/pl/screens/tabs.json
+++ b/src/i18n/pl/screens/tabs.json
@@ -1,20 +1,21 @@
{
"tabs": {
"local": {
- "name": ""
+ "name": "",
+ "options": {
+ "showBoosts": "Pokaż podbicia",
+ "showReplies": "Pokaż odpowiedzi"
+ }
},
"public": {
- "name": "",
"segments": {
- "left": "",
- "right": ""
+ "federated": "",
+ "local": "",
+ "trending": ""
}
},
"notifications": {
"name": ""
- },
- "me": {
- "name": ""
}
},
"common": {
@@ -24,9 +25,22 @@
}
},
"notifications": {
- "filter": {
+ "filters": {
"accessibilityLabel": "",
- "accessibilityHint": ""
+ "accessibilityHint": "",
+ "title": "",
+ "options": {
+ "follow": "",
+ "follow_request": "",
+ "favourite": "",
+ "reblog": "",
+ "mention": "",
+ "poll": "",
+ "status": "",
+ "update": "",
+ "admin.sign_up": "",
+ "admin.report": ""
+ }
}
},
"me": {
@@ -40,6 +54,9 @@
"favourites": {
"name": ""
},
+ "followedTags": {
+ "name": ""
+ },
"fontSize": {
"name": ""
},
@@ -50,13 +67,13 @@
"name": ""
},
"listAccounts": {
- "name": ""
+ "name": "Użytkownicy: {{list}}"
},
"listAdd": {
"name": ""
},
"listEdit": {
- "name": ""
+ "name": "Edycja listy"
},
"lists": {
"name": ""
@@ -97,27 +114,27 @@
}
},
"listAccounts": {
- "heading": "",
- "error": "",
- "empty": ""
+ "heading": "Zarządzanie użytkownikami",
+ "error": "Usuń z listy",
+ "empty": "Brak użytkowników na liście"
},
"listEdit": {
- "heading": "",
- "title": "",
+ "heading": "Edytuj szczegóły",
+ "title": "Nazwa listy",
"repliesPolicy": {
- "heading": "",
+ "heading": "Odpowiedzi będą widoczne dla:",
"options": {
- "none": "",
- "list": "",
- "followed": ""
+ "none": "Nikogo",
+ "list": "Członków listy",
+ "followed": "Wszystkich obserwowanych"
}
}
},
"listDelete": {
- "heading": "",
+ "heading": "Usuń listę",
"confirm": {
- "title": "",
- "message": ""
+ "title": "Usunąć listę \"{{list}}\"?",
+ "message": "Nie będzie można cofnąć tej czynności."
}
},
"profile": {
@@ -214,6 +231,12 @@
"status": {
"heading": ""
},
+ "admin.sign_up": {
+ "heading": ""
+ },
+ "admin.report": {
+ "heading": ""
+ },
"howitworks": ""
},
"root": {
@@ -225,10 +248,8 @@
}
},
"push": {
- "content": {
- "enabled": "",
- "disabled": ""
- }
+ "content_true": "",
+ "content_false": ""
},
"update": {
"title": ""
@@ -290,9 +311,6 @@
"support": {
"heading": ""
},
- "review": {
- "heading": ""
- },
"contact": {
"heading": ""
},
@@ -356,7 +374,7 @@
}
},
"trending": {
- "tags": ""
+ "tags": "Popularne tagi"
}
},
"sections": {
@@ -377,7 +395,8 @@
"statuses": {
"reblogged_by": "",
"favourited_by": ""
- }
+ },
+ "resultIncomplete": ""
}
}
}
\ No newline at end of file
diff --git a/src/i18n/pt_BR/common.json b/src/i18n/pt_BR/common.json
index 7b9190b2..64a8c15e 100644
--- a/src/i18n/pt_BR/common.json
+++ b/src/i18n/pt_BR/common.json
@@ -3,8 +3,9 @@
"OK": "OK",
"apply": "Aplicar",
"cancel": "Cancelar",
- "discard": "",
- "continue": "",
+ "discard": "Descartar",
+ "continue": "Continuar",
+ "create": "",
"delete": "",
"done": ""
},
@@ -24,7 +25,7 @@
},
"separator": ", ",
"discard": {
- "title": "",
- "message": ""
+ "title": "Alterações não salvas",
+ "message": "Sua alteração não foi salva. Descartar as alterações?"
}
}
\ No newline at end of file
diff --git a/src/i18n/pt_BR/components/contextMenu.json b/src/i18n/pt_BR/components/contextMenu.json
index 5386e2cf..16215c48 100644
--- a/src/i18n/pt_BR/components/contextMenu.json
+++ b/src/i18n/pt_BR/components/contextMenu.json
@@ -3,7 +3,7 @@
"account": {
"title": "Ações do Usuário",
"following": {
- "action_false": "",
+ "action_false": "Seguir usuário",
"action_true": ""
},
"inLists": "",
@@ -20,7 +20,7 @@
}
},
"at": {
- "direct": "",
+ "direct": "Mensagem Direta",
"public": ""
},
"copy": {
diff --git a/src/i18n/pt_BR/components/instance.json b/src/i18n/pt_BR/components/instance.json
index 5266bfd0..22e4347c 100644
--- a/src/i18n/pt_BR/components/instance.json
+++ b/src/i18n/pt_BR/components/instance.json
@@ -1,7 +1,7 @@
{
"server": {
"textInput": {
- "placeholder": "Domínio da instância"
+ "placeholder": ""
},
"button": "Entrar",
"information": {
diff --git a/src/i18n/pt_BR/components/timeline.json b/src/i18n/pt_BR/components/timeline.json
index 83fc834e..edb698f3 100644
--- a/src/i18n/pt_BR/components/timeline.json
+++ b/src/i18n/pt_BR/components/timeline.json
@@ -30,7 +30,9 @@
"default": "{{name}} boostou",
"notification": "{{name}} deu boost no teu toot"
},
- "update": "Toot foi editado"
+ "update": "Toot foi editado",
+ "admin.sign_up": "",
+ "admin.report": ""
},
"actions": {
"reply": {
@@ -52,7 +54,8 @@
"bookmarked": {
"accessibilityLabel": "Adicionar este toot aos favoritos",
"function": "Salvos"
- }
+ },
+ "openReport": ""
},
"actionsUsers": {
"reblogged_by": {
diff --git a/src/i18n/pt_BR/screens/actions.json b/src/i18n/pt_BR/screens/actions.json
index fa615e27..ed8b457d 100644
--- a/src/i18n/pt_BR/screens/actions.json
+++ b/src/i18n/pt_BR/screens/actions.json
@@ -2,19 +2,6 @@
"content": {
"altText": {
"heading": "Texto Alternativo"
- },
- "notificationsFilter": {
- "heading": "Exibir notificações",
- "content": {
- "follow": "$t(screenTabs:me.push.follow.heading)",
- "follow_request": "Seguidores pendentes",
- "favourite": "$t(screenTabs:me.push.favourite.heading)",
- "reblog": "$t(screenTabs:me.push.reblog.heading)",
- "mention": "$t(screenTabs:me.push.mention.heading)",
- "poll": "$t(screenTabs:me.push.poll.heading)",
- "status": "Toot de usuários inscritos",
- "update": "Toot foi editado"
- }
}
}
}
\ No newline at end of file
diff --git a/src/i18n/pt_BR/screens/compose.json b/src/i18n/pt_BR/screens/compose.json
index 0af03ec4..d58a56b3 100644
--- a/src/i18n/pt_BR/screens/compose.json
+++ b/src/i18n/pt_BR/screens/compose.json
@@ -1,13 +1,11 @@
{
"heading": {
"left": {
- "button": "Cancelar",
"alert": {
"title": "Cancelar edições?",
"buttons": {
"save": "Salvar rascunho",
- "delete": "Apagar rascunho",
- "cancel": "Cancelar"
+ "delete": "Apagar rascunho"
}
}
},
diff --git a/src/i18n/pt_BR/screens/tabs.json b/src/i18n/pt_BR/screens/tabs.json
index fdf9fcd3..cc1800a1 100644
--- a/src/i18n/pt_BR/screens/tabs.json
+++ b/src/i18n/pt_BR/screens/tabs.json
@@ -1,20 +1,21 @@
{
"tabs": {
"local": {
- "name": "Seguindo"
+ "name": "Seguindo",
+ "options": {
+ "showBoosts": "",
+ "showReplies": ""
+ }
},
"public": {
- "name": "",
"segments": {
- "left": "Global",
- "right": "Local"
+ "federated": "Global",
+ "local": "Local",
+ "trending": ""
}
},
"notifications": {
"name": "Notificações"
- },
- "me": {
- "name": "Sobre mim"
}
},
"common": {
@@ -24,9 +25,22 @@
}
},
"notifications": {
- "filter": {
+ "filters": {
"accessibilityLabel": "Filtro",
- "accessibilityHint": "Filtrar notificações por tipos"
+ "accessibilityHint": "Filtrar notificações por tipos",
+ "title": "",
+ "options": {
+ "follow": "$t(screenTabs:me.push.follow.heading)",
+ "follow_request": "Solicitações de seguidores pendentes",
+ "favourite": "$t(screenTabs:me.push.favourite.heading)",
+ "reblog": "$t(screenTabs:me.push.reblog.heading)",
+ "mention": "$t(screenTabs:me.push.mention.heading)",
+ "poll": "$t(screenTabs:me.push.poll.heading)",
+ "status": "Toot de usuários inscritos",
+ "update": "Toot foi editado",
+ "admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
+ "admin.report": "$t(screenTabs:me.push.admin.report.heading)"
+ }
}
},
"me": {
@@ -40,6 +54,9 @@
"favourites": {
"name": "Favoritos"
},
+ "followedTags": {
+ "name": ""
+ },
"fontSize": {
"name": "Tamanho da fonte do Toot"
},
@@ -214,6 +231,12 @@
"status": {
"heading": "Toot de usuários inscritos"
},
+ "admin.sign_up": {
+ "heading": ""
+ },
+ "admin.report": {
+ "heading": ""
+ },
"howitworks": "Saiba como funciona o roteamento"
},
"root": {
@@ -225,10 +248,8 @@
}
},
"push": {
- "content": {
- "enabled": "Habilitado",
- "disabled": "Desabilitado"
- }
+ "content_true": "Habilitado",
+ "content_false": "Desabilitado"
},
"update": {
"title": "Atualize para a versão mais recente"
@@ -290,9 +311,6 @@
"support": {
"heading": "Suporte tooot"
},
- "review": {
- "heading": "Revisar tooot"
- },
"contact": {
"heading": "Contatar tooot"
},
@@ -322,7 +340,7 @@
"default": "Toots",
"all": "Toots e respostas"
},
- "suspended": ""
+ "suspended": "Conta suspensa pelos moderadores do seu servidor"
},
"accountInLists": {
"name": "",
@@ -330,7 +348,7 @@
"notInLists": ""
},
"attachments": {
- "name": "<0 /><1>\"s mídia1>"
+ "name": ""
},
"hashtag": {
"follow": "Seguir",
@@ -377,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/common.json b/src/i18n/sv/common.json
index bea4cce8..f1695c0c 100644
--- a/src/i18n/sv/common.json
+++ b/src/i18n/sv/common.json
@@ -5,6 +5,7 @@
"cancel": "Avbryt",
"discard": "Kasta bort",
"continue": "Fortsätt",
+ "create": "Skapa",
"delete": "Radera",
"done": "Klar"
},
diff --git a/src/i18n/sv/components/timeline.json b/src/i18n/sv/components/timeline.json
index 488048e4..9f9bf022 100644
--- a/src/i18n/sv/components/timeline.json
+++ b/src/i18n/sv/components/timeline.json
@@ -30,7 +30,9 @@
"default": "{{name}} boostade",
"notification": "{{name}} boostade ditt inlägg"
},
- "update": "Boosten har redigerats"
+ "update": "Boosten har redigerats",
+ "admin.sign_up": "{{name}} registrerade sig på servern",
+ "admin.report": "{{name}} rapporterade:"
},
"actions": {
"reply": {
@@ -52,7 +54,8 @@
"bookmarked": {
"accessibilityLabel": "Lägg till detta inlägg till dina bokmärken",
"function": "Bokmärk inlägg"
- }
+ },
+ "openReport": "Öppna rapport"
},
"actionsUsers": {
"reblogged_by": {
diff --git a/src/i18n/sv/screens/actions.json b/src/i18n/sv/screens/actions.json
index 347390cf..938c6238 100644
--- a/src/i18n/sv/screens/actions.json
+++ b/src/i18n/sv/screens/actions.json
@@ -2,19 +2,6 @@
"content": {
"altText": {
"heading": "Alternativtext"
- },
- "notificationsFilter": {
- "heading": "Visa notistyper",
- "content": {
- "follow": "$t(screenTabs:me.push.follow.heading)",
- "follow_request": "Följarförfrågning",
- "favourite": "$t(screenTabs:me.push.favourite.heading)",
- "reblog": "$t(screenTabs:me.push.reblog.heading)",
- "mention": "$t(screenTabs:me.push.mention.heading)",
- "poll": "$t(screenTabs:me.push.poll.heading)",
- "status": "Inlägg från följda användare",
- "update": "Boosten har redigerats"
- }
}
}
}
\ No newline at end of file
diff --git a/src/i18n/sv/screens/compose.json b/src/i18n/sv/screens/compose.json
index 001fd497..747df7fa 100644
--- a/src/i18n/sv/screens/compose.json
+++ b/src/i18n/sv/screens/compose.json
@@ -1,13 +1,11 @@
{
"heading": {
"left": {
- "button": "Avbryt",
"alert": {
"title": "Avbryt redigering?",
"buttons": {
"save": "Spara utkast",
- "delete": "Ta bort utkast",
- "cancel": "Avbryt"
+ "delete": "Ta bort utkast"
}
}
},
diff --git a/src/i18n/sv/screens/tabs.json b/src/i18n/sv/screens/tabs.json
index 44f78632..d7cad85a 100644
--- a/src/i18n/sv/screens/tabs.json
+++ b/src/i18n/sv/screens/tabs.json
@@ -1,20 +1,21 @@
{
"tabs": {
"local": {
- "name": "Följer"
+ "name": "Följer",
+ "options": {
+ "showBoosts": "Visa boostar",
+ "showReplies": "Visa svar"
+ }
},
"public": {
- "name": "",
"segments": {
- "left": "Federerat",
- "right": "Lokalt"
+ "federated": "Federerat",
+ "local": "Lokalt",
+ "trending": "Trendar"
}
},
"notifications": {
"name": "Notiser"
- },
- "me": {
- "name": "Om mig"
}
},
"common": {
@@ -24,9 +25,22 @@
}
},
"notifications": {
- "filter": {
+ "filters": {
"accessibilityLabel": "Filter",
- "accessibilityHint": "Filtrera visade notistyper"
+ "accessibilityHint": "Filtrera visade notistyper",
+ "title": "Visa notifikationer",
+ "options": {
+ "follow": "$t(screenTabs:me.push.follow.heading)",
+ "follow_request": "Följarförfrågning",
+ "favourite": "$t(screenTabs:me.push.favourite.heading)",
+ "reblog": "$t(screenTabs:me.push.reblog.heading)",
+ "mention": "$t(screenTabs:me.push.mention.heading)",
+ "poll": "$t(screenTabs:me.push.poll.heading)",
+ "status": "Inlägg från följda användare",
+ "update": "Boosten har redigerats",
+ "admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
+ "admin.report": "$t(screenTabs:me.push.admin.report.heading)"
+ }
}
},
"me": {
@@ -40,6 +54,9 @@
"favourites": {
"name": "Favoriter"
},
+ "followedTags": {
+ "name": "Följda hashtaggar"
+ },
"fontSize": {
"name": "Storlek på teckensnitt i inlägg"
},
@@ -53,7 +70,7 @@
"name": "Användare i listan: {{list}}"
},
"listAdd": {
- "name": "Lägg till en lista"
+ "name": "Skapa en lista"
},
"listEdit": {
"name": "Redigera listans detaljer"
@@ -179,8 +196,8 @@
"settings": "Aktivera i inställningar"
},
"missingServerKey": {
- "message": "",
- "description": ""
+ "message": "Servern är felkonfigurerad för push",
+ "description": "Kontakta din serveradministratör och be dem konfigurera stöd för push"
},
"global": {
"heading": "Aktivera för {{acct}}",
@@ -214,6 +231,12 @@
"status": {
"heading": "Inlägg från följda användare"
},
+ "admin.sign_up": {
+ "heading": "Admin: registrera dig"
+ },
+ "admin.report": {
+ "heading": "Admin: rapporter"
+ },
"howitworks": "Läs om hur routing fungerar"
},
"root": {
@@ -225,10 +248,8 @@
}
},
"push": {
- "content": {
- "enabled": "Aktiverad",
- "disabled": "Inaktiverad"
- }
+ "content_true": "Aktiverad",
+ "content_false": "Inaktiverad"
},
"update": {
"title": "Uppdatera till senaste versionen"
@@ -290,9 +311,6 @@
"support": {
"heading": "Stöd tooot"
},
- "review": {
- "heading": "Recensera tooot"
- },
"contact": {
"heading": "Kontakta tooot"
},
@@ -377,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/common.json b/src/i18n/uk/common.json
new file mode 100644
index 00000000..af3dbb7b
--- /dev/null
+++ b/src/i18n/uk/common.json
@@ -0,0 +1,31 @@
+{
+ "buttons": {
+ "OK": "OK",
+ "apply": "Застосувати",
+ "cancel": "Скасувати",
+ "discard": "Відхилити",
+ "continue": "Продовжити",
+ "create": "Створити",
+ "delete": "Видалити",
+ "done": "Готово"
+ },
+ "customEmoji": {
+ "accessibilityLabel": "Власні емодзі {{emoji}}"
+ },
+ "message": {
+ "success": {
+ "message": "{{function}} успішно"
+ },
+ "warning": {
+ "message": ""
+ },
+ "error": {
+ "message": "{{function}} не вдалося, спробуйте ще раз"
+ }
+ },
+ "separator": ", ",
+ "discard": {
+ "title": "Зміни не збережено",
+ "message": "Зміни не збережено. Зберегти зміни?"
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/uk/components/contextMenu.json b/src/i18n/uk/components/contextMenu.json
new file mode 100644
index 00000000..ff210275
--- /dev/null
+++ b/src/i18n/uk/components/contextMenu.json
@@ -0,0 +1,85 @@
+{
+ "accessibilityHint": "Дії для цього дмуху, наприклад, його опублікованого користувача, дмуху",
+ "account": {
+ "title": "Дії користувача",
+ "following": {
+ "action_false": "Підписатися на користувача",
+ "action_true": "Відписатися від користувача"
+ },
+ "inLists": "Керувати списками",
+ "mute": {
+ "action_false": "Заглушити користувача",
+ "action_true": "Зняти заглушення з користувача"
+ },
+ "block": {
+ "action_false": "Заблокувати користувача",
+ "action_true": "Розблокувати користувача"
+ },
+ "reports": {
+ "action": "Повідомити та заблокувати користувача"
+ }
+ },
+ "at": {
+ "direct": "Особисті повідомлення",
+ "public": "Публічне повідомлення"
+ },
+ "copy": {
+ "action": "Скопіювати дмух",
+ "succeed": "Скопійовано"
+ },
+ "instance": {
+ "title": "Дія інстанса",
+ "block": {
+ "action": "Заблокувати інстанс {{instance}}",
+ "alert": {
+ "title": "Підтверджуєте блокування інстанса {{instance}}?",
+ "message": "Здебільшого ви можете вимкнути звук або заблокувати певного користувача.\n\nПісля блокування інстансу весь її контент, включаючи підписників, буде видалено!",
+ "buttons": {
+ "confirm": "Підтвердити"
+ }
+ }
+ }
+ },
+ "share": {
+ "status": {
+ "action": "Поділитися дмухом"
+ },
+ "account": {
+ "action": "Поділитися користувачем"
+ }
+ },
+ "status": {
+ "title": "Дії дмуха",
+ "edit": {
+ "action": "Редагувати дмух"
+ },
+ "delete": {
+ "action": "Видалити дмух",
+ "alert": {
+ "title": "Видалити?",
+ "message": "Всі передмухи і уподобання будуть очищені, включаючи всі відповіді.",
+ "buttons": {
+ "confirm": "Підтвердити"
+ }
+ }
+ },
+ "deleteEdit": {
+ "action": "Видалити дмух та репост",
+ "alert": {
+ "title": "Підтвердьте видалення та повторне розміщення?",
+ "message": "Всі передмухи і уподобання будуть очищені, включаючи всі відповіді.",
+ "buttons": {
+ "confirm": "Підтвердити"
+ }
+ }
+ },
+ "mute": {
+ "action_false": "Заглушити дмух та відповіді",
+ "action_true": "Увімкнути дмух та відповіді"
+ },
+ "pin": {
+ "action_false": "Прикріпити дмух",
+ "action_true": "Відкріпити дмух"
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/uk/components/emojis.json b/src/i18n/uk/components/emojis.json
new file mode 100644
index 00000000..a6934eee
--- /dev/null
+++ b/src/i18n/uk/components/emojis.json
@@ -0,0 +1,3 @@
+{
+ "frequentUsed": "Часто використовувані"
+}
\ No newline at end of file
diff --git a/src/i18n/uk/components/instance.json b/src/i18n/uk/components/instance.json
new file mode 100644
index 00000000..da19b90a
--- /dev/null
+++ b/src/i18n/uk/components/instance.json
@@ -0,0 +1,26 @@
+{
+ "server": {
+ "textInput": {
+ "placeholder": "Домен інстансу"
+ },
+ "button": "Увійти",
+ "information": {
+ "name": "Назва",
+ "accounts": "Користувачі",
+ "statuses": "Дмухи",
+ "domains": "Універси"
+ },
+ "disclaimer": {
+ "base": "Для входу в систему використовується системний браузер, тому інформація про ваш обліковий запис не буде видимою для додатку tooot."
+ },
+ "terms": {
+ "base": "Увійшовши в систему, ви приймаєте <0>політику конфіденційності0> та <1>умови надання послуг1>."
+ }
+ },
+ "update": {
+ "alert": {
+ "title": "Вхід виконано",
+ "message": "Ви можете увійти під іншим обліковим записом, зберігши існуючий обліковий запис"
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/uk/components/mediaSelector.json b/src/i18n/uk/components/mediaSelector.json
new file mode 100644
index 00000000..324b2a57
--- /dev/null
+++ b/src/i18n/uk/components/mediaSelector.json
@@ -0,0 +1,10 @@
+{
+ "title": "Вибір джерела медіа",
+ "message": "Дані медіа-EXIF не завантажені",
+ "options": {
+ "image": "Завантажити фотографії",
+ "image_max": "Завантажити фотографії (макс. {{max}})",
+ "video": "Завантажити відео",
+ "video_max": "Завантажити відео (макс. {{max}})"
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/uk/components/parse.json b/src/i18n/uk/components/parse.json
new file mode 100644
index 00000000..d5b42af9
--- /dev/null
+++ b/src/i18n/uk/components/parse.json
@@ -0,0 +1,8 @@
+{
+ "HTML": {
+ "accessibilityHint": "Натисніть, щоб розгорнути або згорнути вміст",
+ "expanded": "{{hint}}{{moreLines}}",
+ "moreLines": " ({{count}} більше рядків)",
+ "defaultHint": "Довгий дмух"
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/uk/components/relationship.json b/src/i18n/uk/components/relationship.json
new file mode 100644
index 00000000..5a0f7eeb
--- /dev/null
+++ b/src/i18n/uk/components/relationship.json
@@ -0,0 +1,16 @@
+{
+ "follow": {
+ "function": "Підписатися на користувача"
+ },
+ "block": {
+ "function": "Заблокувати користувача"
+ },
+ "button": {
+ "error": "Помилка завантаження",
+ "blocked_by": "Заблокований користувачем",
+ "blocking": "Розблокувати",
+ "following": "Відписатися",
+ "requested": "Відкликати запит",
+ "default": "Підписатися"
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/uk/components/timeline.json b/src/i18n/uk/components/timeline.json
new file mode 100644
index 00000000..b35a9fb9
--- /dev/null
+++ b/src/i18n/uk/components/timeline.json
@@ -0,0 +1,155 @@
+{
+ "empty": {
+ "error": {
+ "message": "Помилка завантаження",
+ "button": "Повторити"
+ },
+ "success": {
+ "message": "Часова гілка порожня"
+ }
+ },
+ "end": {
+ "message": "Це кінець, бажаєте філіжанку кави? <0 />"
+ },
+ "lookback": {
+ "message": "Останні прочитані в"
+ },
+ "refresh": {
+ "fetchPreviousPage": "З цього моменту",
+ "refetch": "До кінця"
+ },
+ "shared": {
+ "actioned": {
+ "pinned": "Прикріплено",
+ "favourite": "{{name}} додав в улюблене дмух",
+ "status": "{{name}} щойно дмухнув",
+ "follow": "{{name}} підписався на вас",
+ "follow_request": "{{name}} відправив запит на підписку",
+ "poll": "Опитування, у якому ви голосували, закінчилося",
+ "reblog": {
+ "default": "{{name}} передмухнув(-ла)",
+ "notification": "{{name}} передмухнув(-ла) ваш дмух"
+ },
+ "update": "Передмух був відредагований",
+ "admin.sign_up": "{{name}} приєднався до інстансу",
+ "admin.report": "{{name}} повідомлено:"
+ },
+ "actions": {
+ "reply": {
+ "accessibilityLabel": "Відповісти на дмух"
+ },
+ "reblogged": {
+ "accessibilityLabel": "Передмухнути",
+ "function": "Передмухнути",
+ "options": {
+ "title": "Виберіть видимість передмуху",
+ "public": "Публічний передмух",
+ "unlisted": "Прихований передмух"
+ }
+ },
+ "favourited": {
+ "accessibilityLabel": "Додати дмух до улюблених",
+ "function": "Улюблені дмухи"
+ },
+ "bookmarked": {
+ "accessibilityLabel": "Додати цей дмух до закладок",
+ "function": "Закладки дмухів"
+ },
+ "openReport": "Відкрити скаргу"
+ },
+ "actionsUsers": {
+ "reblogged_by": {
+ "accessibilityLabel": "{{count}} користувачів передмухнули цей дмух",
+ "accessibilityHint": "Торкніться, щоб дізнатися про користувачів",
+ "text": "$t(screenTabs:shared.users.statuses.reblogged_by)"
+ },
+ "favourited_by": {
+ "accessibilityLabel": "{{count}} користувачів зробили закладку для цього дмуху",
+ "accessibilityHint": "Торкніться, щоб дізнатися про користувачів",
+ "text": "$t(screenTabs:shared.users.statuses.favourited_by)"
+ },
+ "history": {
+ "accessibilityLabel": "Цей дмух було відредаговано {{count}} разів",
+ "accessibilityHint": "Натисніть для перегляду повної історії редагування",
+ "text_one": "{{count}} редагування",
+ "text_other": "{{count}} редагували"
+ }
+ },
+ "attachment": {
+ "sensitive": {
+ "button": "Показати чутливі медіа"
+ },
+ "unsupported": {
+ "text": "Помилка завантаження",
+ "button": "Спробуйте віддалене посилання"
+ }
+ },
+ "avatar": {
+ "accessibilityLabel": "Аватар {{name}}",
+ "accessibilityHint": "Натисніть, щоб перейти на сторінку {{name}}"
+ },
+ "content": {
+ "expandHint": "Прихований вміст"
+ },
+ "filtered": "Відфільтровано: {{phrase}}.",
+ "fullConversation": "Читати розмови",
+ "translate": {
+ "default": "Переклад",
+ "succeed": "Перекладено {{provider}} з {{source}}",
+ "failed": "Не вдалося перекласти",
+ "source_not_supported": "мова дмухів не підтримується",
+ "target_not_supported": "Цільова мова не підтримується"
+ },
+ "header": {
+ "shared": {
+ "account": {
+ "name": {
+ "accessibilityHint": "Ім'я для відображення"
+ },
+ "account": {
+ "accessibilityHint": "Профіль користувача"
+ }
+ },
+ "application": "через {{application}}",
+ "edited": {
+ "accessibilityLabel": "Дмух відредаговано"
+ },
+ "muted": {
+ "accessibilityLabel": "Дмух приглушений"
+ },
+ "visibility": {
+ "direct": {
+ "accessibilityLabel": "Дмухнути особистим повідомленням"
+ },
+ "private": {
+ "accessibilityLabel": "Дмух видимий лише для підписників"
+ }
+ }
+ },
+ "conversation": {
+ "withAccounts": "З",
+ "delete": {
+ "function": "Видалити особисті повідомлення"
+ }
+ }
+ },
+ "poll": {
+ "meta": {
+ "button": {
+ "vote": "Голосування",
+ "refresh": "Оновити"
+ },
+ "count": {
+ "voters_one": "{{count}} користувач проголосував",
+ "voters_other": "{{count}} користувачів проголосувало",
+ "votes_one": "{{count}} голос",
+ "votes_other": "{{count}} голосів"
+ },
+ "expiration": {
+ "expired": "Голосування закінчилось",
+ "until": "Спливає <0 />"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/uk/index.ts b/src/i18n/uk/index.ts
new file mode 100644
index 00000000..5f2a7a82
--- /dev/null
+++ b/src/i18n/uk/index.ts
@@ -0,0 +1,18 @@
+export default {
+ common: require('./common'),
+
+ screens: require('./screens'),
+ screenActions: require('./screens/actions'),
+ screenAnnouncements: require('./screens/announcements'),
+ screenCompose: require('./screens/compose'),
+ screenImageViewer: require('./screens/imageViewer'),
+ screenTabs: require('./screens/tabs'),
+
+ componentContextMenu: require('./components/contextMenu'),
+ componentEmojis: require('./components/emojis'),
+ componentInstance: require('./components/instance'),
+ componentMediaSelector: require('./components/mediaSelector'),
+ componentParse: require('./components/parse'),
+ componentRelationship: require('./components/relationship'),
+ componentTimeline: require('./components/timeline')
+}
diff --git a/src/i18n/uk/screens.json b/src/i18n/uk/screens.json
new file mode 100644
index 00000000..943e9da9
--- /dev/null
+++ b/src/i18n/uk/screens.json
@@ -0,0 +1,18 @@
+{
+ "screenshot": {
+ "title": "Захист конфіденційності",
+ "message": "Будь ласка, не розкривайте особи інших користувачів, наприклад ім'я користувача, аватар і т.д. Дякуємо!",
+ "button": "Підтвердити"
+ },
+ "localCorrupt": {
+ "message": "Вхід вичерпано. Будь ласка, увійдіть знову"
+ },
+ "pushError": {
+ "message": "Помилка служби push",
+ "description": "Будь ласка, повторно увімкніть сповіщення push в налаштуваннях"
+ },
+ "shareError": {
+ "imageNotSupported": "Тип зображення {{type}} не підтримується",
+ "videoNotSupported": "Тип відео {{type}} не підтримується"
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/uk/screens/accountSelection.json b/src/i18n/uk/screens/accountSelection.json
new file mode 100644
index 00000000..4dab6bcf
--- /dev/null
+++ b/src/i18n/uk/screens/accountSelection.json
@@ -0,0 +1,6 @@
+{
+ "heading": "Поділитися з...",
+ "content": {
+ "select_account": "Оберіть акаунт"
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/uk/screens/actions.json b/src/i18n/uk/screens/actions.json
new file mode 100644
index 00000000..5088196f
--- /dev/null
+++ b/src/i18n/uk/screens/actions.json
@@ -0,0 +1,7 @@
+{
+ "content": {
+ "altText": {
+ "heading": "Альтернативний текст"
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/uk/screens/announcements.json b/src/i18n/uk/screens/announcements.json
new file mode 100644
index 00000000..91a31325
--- /dev/null
+++ b/src/i18n/uk/screens/announcements.json
@@ -0,0 +1,10 @@
+{
+ "heading": "Оголошення",
+ "content": {
+ "published": "Опубліковано <0 />",
+ "button": {
+ "read": "Прочитано",
+ "unread": "Позначити прочитаним"
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/uk/screens/compose.json b/src/i18n/uk/screens/compose.json
new file mode 100644
index 00000000..9bf4ccdb
--- /dev/null
+++ b/src/i18n/uk/screens/compose.json
@@ -0,0 +1,173 @@
+{
+ "heading": {
+ "left": {
+ "alert": {
+ "title": "Скасувати редагування?",
+ "buttons": {
+ "save": "Зберегти чернетку",
+ "delete": "Видалити чернетку"
+ }
+ }
+ },
+ "right": {
+ "button": {
+ "default": "Дмух",
+ "conversation": "Дмух DM",
+ "reply": "Дмухнути",
+ "deleteEdit": "Дмух",
+ "edit": "Дмух",
+ "share": "Дмух"
+ },
+ "alert": {
+ "default": {
+ "title": "Дмухнути не вийшло",
+ "button": "Спробуйте ще раз"
+ },
+ "removeReply": {
+ "title": "Дмух для відповіді не знайдено",
+ "description": "Дмух може бути видалено. Видалити його з вашого посилання?",
+ "confirm": "Видалити посилання"
+ }
+ }
+ }
+ },
+ "content": {
+ "root": {
+ "header": {
+ "postingAs": "Дмухнути як @{{acct}}@{{domain}}",
+ "spoilerInput": {
+ "placeholder": "Попередження спойлера"
+ },
+ "textInput": {
+ "placeholder": "Що у вас на думці?",
+ "keyboardImage": {
+ "exceedMaximum": {
+ "title": "Досягнута максимальна кількість вкладень",
+ "OK": "$t(common:buttons.OK)"
+ }
+ }
+ }
+ },
+ "footer": {
+ "attachments": {
+ "sensitive": "Позначте вкладення як чутливі",
+ "remove": {
+ "accessibilityLabel": "Видалити завантажене вкладення, номер {{attachment}}"
+ },
+ "edit": {
+ "accessibilityLabel": "Редагувати завантажене вкладення, номер {{attachment}}"
+ },
+ "upload": {
+ "accessibilityLabel": "Завантажити додаткові вкладення"
+ }
+ },
+ "emojis": {
+ "accessibilityHint": "Торкніться, щоб додати емодзі для дмуху"
+ },
+ "poll": {
+ "option": {
+ "placeholder": {
+ "accessibilityLabel": "Варіант опитування {{index}}",
+ "single": "Один вибір",
+ "multiple": "Множинний вибір"
+ }
+ },
+ "quantity": {
+ "reduce": {
+ "accessibilityLabel": "Зменшити варіанти відповіді на {{amount}}",
+ "accessibilityHint": "Досягнута мінімальна кількість варіантів опитування, наразі має {{amount}}"
+ },
+ "increase": {
+ "accessibilityLabel": "Збільшити варіанти відповіді на {{amount}}",
+ "accessibilityHint": "Досягнута максимальна кількість варіантів опитування, наразі має {{amount}}"
+ }
+ },
+ "multiple": {
+ "heading": "Тип вибору",
+ "options": {
+ "single": "Один вибір",
+ "multiple": "Множинний вибір"
+ }
+ },
+ "expiration": {
+ "heading": "Термін дії",
+ "options": {
+ "300": "5 хвилин",
+ "1800": "30 хвилин",
+ "3600": "1 година",
+ "21600": "6 годин",
+ "86400": "1 день",
+ "259200": "3 дні",
+ "604800": "7 днів"
+ }
+ }
+ }
+ },
+ "actions": {
+ "attachment": {
+ "accessibilityLabel": "Завантажити вкладений файл",
+ "accessibilityHint": "Функція опитування буде вимкнена, коли є вкладені файли",
+ "failed": {
+ "alert": {
+ "title": "Помилка завантаження",
+ "button": "Спробуйте ще раз"
+ }
+ }
+ },
+ "poll": {
+ "accessibilityLabel": "Додати голосування",
+ "accessibilityHint": "Функцію вкладення буде відключено, коли опитування активне"
+ },
+ "visibility": {
+ "accessibilityLabel": "Видимість дмуху {{visibility}}",
+ "title": "Видимість дмуху",
+ "options": {
+ "public": "Публічний",
+ "unlisted": "Приватний",
+ "private": "Тільки для підписників",
+ "direct": "Особисті повідомлення"
+ }
+ },
+ "spoiler": {
+ "accessibilityLabel": "Спойлер"
+ },
+ "emoji": {
+ "accessibilityLabel": "Додати емодзі",
+ "accessibilityHint": "Відкрийте панель вибору емодзі, проведіть по горизонталі, щоб змінити сторінку"
+ }
+ },
+ "drafts_one": "Чернетка ({{count}})",
+ "drafts_other": "Чернетки ({{count}})"
+ },
+ "editAttachment": {
+ "header": {
+ "title": "Редагувати вкладення",
+ "right": {
+ "accessibilityLabel": "Зберегти редагування вкладення",
+ "failed": {
+ "title": "Редагування не вдалося",
+ "button": "Спробуйте ще раз"
+ }
+ }
+ },
+ "content": {
+ "altText": {
+ "heading": "Охарактеризуйте медіа для людей з вадами зору",
+ "placeholder": "Ви можете додавати опис, іноді так званий alt-текст, вашим медіа, таким чином, вони доступні ще більшій кількості людей, включаючи тих, хто сліпий, чи має проблеми з зором.\n\nХороші описи - це лаконічно, але представте що є у ваших медіа досить точним, щоб зрозуміти їх контекст."
+ },
+ "imageFocus": "Перетягніть круг для оновлення точки фокусу"
+ }
+ },
+ "draftsList": {
+ "header": {
+ "title": "Чернетка"
+ },
+ "warning": "Чернетки зберігаються лише локально, і їх може бути втрачено у нещасних подіях. Рекомендуємо не використовувати чернетки для довгострокового сховища.",
+ "content": {
+ "accessibilityHint": "Збережено чернетку, натисніть для редагування чернетки",
+ "textEmpty": "Вміст порожній"
+ },
+ "checkAttachment": "Перевірка вкладень на сервері..."
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/uk/screens/imageViewer.json b/src/i18n/uk/screens/imageViewer.json
new file mode 100644
index 00000000..c2f67e20
--- /dev/null
+++ b/src/i18n/uk/screens/imageViewer.json
@@ -0,0 +1,16 @@
+{
+ "content": {
+ "actions": {
+ "accessibilityLabel": "Більше дій на цьому зображення",
+ "accessibilityHint": "Ви можете зберегти чи поділитися цим зображенням"
+ },
+ "options": {
+ "save": "Зберегти зображення",
+ "share": "Поділитись зображенням"
+ },
+ "save": {
+ "succeed": "Зображення збережено",
+ "failed": "Не вдалося зберегти зображення"
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/uk/screens/tabs.json b/src/i18n/uk/screens/tabs.json
new file mode 100644
index 00000000..7ebf23e2
--- /dev/null
+++ b/src/i18n/uk/screens/tabs.json
@@ -0,0 +1,402 @@
+{
+ "tabs": {
+ "local": {
+ "name": "Підписаний",
+ "options": {
+ "showBoosts": "Показати передмухнуті",
+ "showReplies": "Показувати відповіді"
+ }
+ },
+ "public": {
+ "segments": {
+ "federated": "Глобальна",
+ "local": "Місцева",
+ "trending": "Популярне"
+ }
+ },
+ "notifications": {
+ "name": "Сповіщення"
+ }
+ },
+ "common": {
+ "search": {
+ "accessibilityLabel": "Пошук",
+ "accessibilityHint": "Пошук ґештеґів, користувачів або дмухів"
+ }
+ },
+ "notifications": {
+ "filters": {
+ "accessibilityLabel": "Фільтр",
+ "accessibilityHint": "Відфільтрувати типи сповіщень, що відображаються",
+ "title": "Показувати сповіщення",
+ "options": {
+ "follow": "$t(screenTabs:me.push.follow.heading)",
+ "follow_request": "Запит на підписку",
+ "favourite": "$t(screenTabs:me.push.favourite.heading)",
+ "reblog": "$t(screenTabs:me.push.reblog.heading)",
+ "mention": "$t(screenTabs:me.push.mention.heading)",
+ "poll": "$t(screenTabs:me.push.poll.heading)",
+ "status": "Дмух від підписників",
+ "update": "Передмух був відредагований",
+ "admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
+ "admin.report": "$t(screenTabs:me.push.admin.report.heading)"
+ }
+ }
+ },
+ "me": {
+ "stacks": {
+ "bookmarks": {
+ "name": "Закладки"
+ },
+ "conversations": {
+ "name": "Особисті повідомлення"
+ },
+ "favourites": {
+ "name": "Улюблене"
+ },
+ "followedTags": {
+ "name": "Стежити за хештегом"
+ },
+ "fontSize": {
+ "name": "Розмір шрифту дмуху"
+ },
+ "language": {
+ "name": "Мова"
+ },
+ "list": {
+ "name": "Список: {{list}}"
+ },
+ "listAccounts": {
+ "name": "Список користувачів: {{list}}"
+ },
+ "listAdd": {
+ "name": "Створити список"
+ },
+ "listEdit": {
+ "name": "Редагувати деталі списку"
+ },
+ "lists": {
+ "name": "Списки"
+ },
+ "push": {
+ "name": "Push-сповіщення"
+ },
+ "profile": {
+ "name": "Редагувати профіль"
+ },
+ "profileName": {
+ "name": "Редагувати показане ім'я"
+ },
+ "profileNote": {
+ "name": "Редагувати опис"
+ },
+ "profileFields": {
+ "name": "Редагувати метадані"
+ },
+ "settings": {
+ "name": "Налаштування додатку"
+ },
+ "webSettings": {
+ "name": "Додаткові налаштування акаунта"
+ },
+ "switch": {
+ "name": "Переключити аккаунт"
+ }
+ },
+ "fontSize": {
+ "demo": "Це демо дмух: smiling_face_with_smiling_eyes:. Ви можете вибрати з декількох варіантів знизу. Це налаштування впливає лише на основний вміст дмухів, але не на інші розміри шрифту.
",
+ "sizes": {
+ "S": "S",
+ "M": "М - за замовчуванням",
+ "L": "L",
+ "XL": "XL",
+ "XXL": "XXL"
+ }
+ },
+ "listAccounts": {
+ "heading": "Керувати користувачами",
+ "error": "Видалити користувача зі списку",
+ "empty": "Користувача не додано в цей список"
+ },
+ "listEdit": {
+ "heading": "Редагувати деталі списку",
+ "title": "Назва",
+ "repliesPolicy": {
+ "heading": "Показати відповіді від:",
+ "options": {
+ "none": "Ніхто",
+ "list": "Користувачів списку",
+ "followed": "Будь-який користувач, за яким ви стежите"
+ }
+ }
+ },
+ "listDelete": {
+ "heading": "Видалити список",
+ "confirm": {
+ "title": "Видалити список \"{{list}}\"?",
+ "message": "Цю дію не можна скасувати."
+ }
+ },
+ "profile": {
+ "feedback": {
+ "succeed": "{{type}} оновлено",
+ "failed": "{{type}} оновлення не вдалося, будь ласка, спробуйте ще раз"
+ },
+ "root": {
+ "name": {
+ "title": "Ім'я для відображення"
+ },
+ "avatar": {
+ "title": "Аватар",
+ "description": "Буде зменшено до 400x400px"
+ },
+ "header": {
+ "title": "Банер",
+ "description": "Буде зменшено до 1500x500px"
+ },
+ "note": {
+ "title": "Опис"
+ },
+ "fields": {
+ "title": "Метадані",
+ "total_one": "{{count}} поле",
+ "total_other": "{{count}} полей"
+ },
+ "visibility": {
+ "title": "Видимість дмухів",
+ "options": {
+ "public": "Публічний",
+ "unlisted": "Приватний",
+ "private": "Тільки для підписників"
+ }
+ },
+ "sensitive": {
+ "title": "Розміщення чутливої інформації"
+ },
+ "lock": {
+ "title": "Закрити акаунт",
+ "description": "Потребує вас вручну затвердити підписників"
+ },
+ "bot": {
+ "title": "Акаунт бота",
+ "description": "Цей акаунт виконує автоматичні дії та може не відстежуватися"
+ }
+ },
+ "fields": {
+ "group": "Група {{index}}",
+ "label": "Мітка",
+ "content": "Контент"
+ },
+ "mediaSelectionFailed": "Не вдалося виконати обробку зображення. Будь ласка, спробуйте ще раз."
+ },
+ "push": {
+ "notAvailable": "Ваш телефон не підтримує push-сповіщення tooot",
+ "enable": {
+ "direct": "Увімкнути push сповіщення",
+ "settings": "Включити в налаштуваннях"
+ },
+ "missingServerKey": {
+ "message": "Сервер неправильно налаштовано для push",
+ "description": "Будь ласка, зверніться до адміністратора сервера для налаштування підтримки push"
+ },
+ "global": {
+ "heading": "Увімкнути для {{acct}}",
+ "description": "Повідомлення перенаправляються через сервер tooot"
+ },
+ "decode": {
+ "heading": "Показати деталі повідомлення",
+ "description": "Повідомлення, які передаються через сервер tooot, зашифровані, але ви можете декодувати повідомлення на сервері. Наш вихідний код сервера є відкритим вихідним кодом і не має політики журналу."
+ },
+ "default": {
+ "heading": "За замовчуванням"
+ },
+ "follow": {
+ "heading": "Новий підписник(-ця)"
+ },
+ "follow_request": {
+ "heading": "Запит на підписку"
+ },
+ "favourite": {
+ "heading": "Улюблене"
+ },
+ "reblog": {
+ "heading": "Передмухнув"
+ },
+ "mention": {
+ "heading": "згадав (-ла) вас"
+ },
+ "poll": {
+ "heading": "Опитування успішно оновлено"
+ },
+ "status": {
+ "heading": "Дмух від підписників"
+ },
+ "admin.sign_up": {
+ "heading": "Адмін: реєстрація"
+ },
+ "admin.report": {
+ "heading": "Адмін: звіти"
+ },
+ "howitworks": "Дізнатися, як працює маршрутизація"
+ },
+ "root": {
+ "announcements": {
+ "content": {
+ "unread": "{{amount}} непрочитаних",
+ "read": "Усі прочитані",
+ "empty": "Відсутньо"
+ }
+ },
+ "push": {
+ "content_true": "Увімкнено",
+ "content_false": "Вимкнено"
+ },
+ "update": {
+ "title": "Оновити до останньої версії"
+ },
+ "logout": {
+ "button": "Вийти",
+ "alert": {
+ "title": "Виходиш з системи?",
+ "message": "Після виходу з системи необхідно повторно увійти в неї",
+ "buttons": {
+ "logout": "Вийти"
+ }
+ }
+ }
+ },
+ "settings": {
+ "fontsize": {
+ "heading": "$t(me.stacks.fontSize.name)",
+ "content": {
+ "S": "$t(me.fontSize.sizes.S)",
+ "M": "$t(me.fontSize.sizes.M)",
+ "L": "$t(me.fontSize.sizes.L)",
+ "XL": "$t(me.fontSize.sizes.XL)",
+ "XXL": "$t(me.fontSize.sizes.XXL)"
+ }
+ },
+ "language": {
+ "heading": "$t(me.stacks.language.name)"
+ },
+ "theme": {
+ "heading": "Зовнішній вигляд",
+ "options": {
+ "auto": "За системними налаштуваннями",
+ "light": "Світла тема",
+ "dark": "Темний режим"
+ }
+ },
+ "darkTheme": {
+ "heading": "Темна тема",
+ "options": {
+ "lighter": "Світліше",
+ "darker": "Темніше"
+ }
+ },
+ "browser": {
+ "heading": "Відкривання посилань",
+ "options": {
+ "internal": "Всередині додатку",
+ "external": "Використовувати системний браузер"
+ }
+ },
+ "staticEmoji": {
+ "heading": "Використовувати статичні емодзі",
+ "description": "Якщо ви стикаєтеся з частими збоями в роботі програми при перегляді списку емодзі, ви можете спробувати використовувати статичні емодзі."
+ },
+ "feedback": {
+ "heading": "Запропонувати ідею"
+ },
+ "support": {
+ "heading": "Підтримати tooot"
+ },
+ "contact": {
+ "heading": "Зв'язатись з tooot"
+ },
+ "version": "Версія: {{version}}",
+ "instanceVersion": "Версія Mastodon: v{{version}}"
+ },
+ "switch": {
+ "existing": "Вибрати з авторизованих",
+ "new": "Увійти до інстансу"
+ }
+ },
+ "shared": {
+ "account": {
+ "actions": {
+ "accessibilityLabel": "Дії для користувача {{user}}",
+ "accessibilityHint": "Ви можете приглушити, заблокувати, чи кинути репорт на цього користувача"
+ },
+ "followed_by": " слідує за вами",
+ "moved": "Користувач перемістився",
+ "created_at": "Приєднався: {{date}}",
+ "summary": {
+ "statuses_count": "{{count}} дмухів",
+ "following_count": "$t(shared.users.accounts.following)",
+ "followers_count": "$t(shared.users.accounts.followers)"
+ },
+ "toots": {
+ "default": "Дмухи",
+ "all": "Дмухи та відповіді"
+ },
+ "suspended": "Обліковий запис призупинено модераторами вашого інстансу"
+ },
+ "accountInLists": {
+ "name": "Списки @{{username}}",
+ "inLists": "У списку",
+ "notInLists": "Інші списки"
+ },
+ "attachments": {
+ "name": "<0 /><1> медіа1>"
+ },
+ "hashtag": {
+ "follow": "Підписатися",
+ "unfollow": "Відписатися"
+ },
+ "history": {
+ "name": "Редагувати історію"
+ },
+ "search": {
+ "header": {
+ "prefix": "Пошук",
+ "placeholder": "кого?.."
+ },
+ "empty": {
+ "general": "Введіть ключове слово для пошуку $t(screenTabs:shared.search.sections.accounts) 、$t(screenTabs:shared.search.sections.hashtags) або $t(screenTabs:shared.search.sections.statuses) ",
+ "advanced": {
+ "header": "Розширений пошук",
+ "example": {
+ "account": "$t(shared.search.header.prefix) $t(shared.search.sections.accounts)",
+ "hashtag": "$t(shared.search.header.prefix) $t(shared.search.sections.hashtags)",
+ "statusLink": "$t(shared.search.header.prefix) $t(shared.search.sections.statuses)",
+ "accountLink": "$t(shared.search.header.prefix) $t(shared.search.sections.accounts)"
+ }
+ },
+ "trending": {
+ "tags": "Популярні теги"
+ }
+ },
+ "sections": {
+ "accounts": "Користувач",
+ "hashtags": "Ґештег",
+ "statuses": "Дмух"
+ },
+ "notFound": "Не вдалося знайти {{searchTerm}} пов'язаний з {{type}}"
+ },
+ "toot": {
+ "name": "Обговорення"
+ },
+ "users": {
+ "accounts": {
+ "following": "Підписки {{count}}",
+ "followers": "{{count}} підписників"
+ },
+ "statuses": {
+ "reblogged_by": "{{count}} передмухів",
+ "favourited_by": "{{count}} улюблених"
+ },
+ "resultIncomplete": "Результати з віддаленого інстанса неповні"
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/i18n/vi/common.json b/src/i18n/vi/common.json
index 421903ba..517903aa 100644
--- a/src/i18n/vi/common.json
+++ b/src/i18n/vi/common.json
@@ -5,6 +5,7 @@
"cancel": "Hủy bỏ",
"discard": "Bỏ qua",
"continue": "Tiếp tục",
+ "create": "Tạo",
"delete": "Xóa",
"done": "Xong"
},
diff --git a/src/i18n/vi/components/instance.json b/src/i18n/vi/components/instance.json
index b03df3c8..acca9aa1 100644
--- a/src/i18n/vi/components/instance.json
+++ b/src/i18n/vi/components/instance.json
@@ -1,7 +1,7 @@
{
"server": {
"textInput": {
- "placeholder": "Máy chủ"
+ "placeholder": "Địa chỉ máy chủ"
},
"button": "Đăng nhập",
"information": {
diff --git a/src/i18n/vi/components/timeline.json b/src/i18n/vi/components/timeline.json
index 3dba5244..dc0be9f4 100644
--- a/src/i18n/vi/components/timeline.json
+++ b/src/i18n/vi/components/timeline.json
@@ -30,7 +30,9 @@
"default": "{{name}} đăng lại",
"notification": "{{name}} đăng lại tút của bạn"
},
- "update": "Đăng lại đã được sửa"
+ "update": "Đăng lại đã được sửa",
+ "admin.sign_up": "{{name}} tham gia máy chủ",
+ "admin.report": "{{name}} báo cáo:"
},
"actions": {
"reply": {
@@ -52,7 +54,8 @@
"bookmarked": {
"accessibilityLabel": "Lưu tút này",
"function": "Lưu tút"
- }
+ },
+ "openReport": "Mở báo cáo"
},
"actionsUsers": {
"reblogged_by": {
diff --git a/src/i18n/vi/screens/actions.json b/src/i18n/vi/screens/actions.json
index 516c6077..5551f751 100644
--- a/src/i18n/vi/screens/actions.json
+++ b/src/i18n/vi/screens/actions.json
@@ -2,19 +2,6 @@
"content": {
"altText": {
"heading": "Văn bản thay thế"
- },
- "notificationsFilter": {
- "heading": "Những kiểu thông báo cho phép",
- "content": {
- "follow": "$t(screenTabs:me.push.follow.heading)",
- "follow_request": "Yêu cầu theo dõi",
- "favourite": "$t(screenTabs:me.push.favourite.heading)",
- "reblog": "$t(screenTabs:me.push.reblog.heading)",
- "mention": "$t(screenTabs:me.push.mention.heading)",
- "poll": "$t(screenTabs:me.push.poll.heading)",
- "status": "Tút từ người đã theo dõi",
- "update": "Đăng lại đã được sửa"
- }
}
}
}
\ No newline at end of file
diff --git a/src/i18n/vi/screens/compose.json b/src/i18n/vi/screens/compose.json
index 83b5901c..a2d38e04 100644
--- a/src/i18n/vi/screens/compose.json
+++ b/src/i18n/vi/screens/compose.json
@@ -1,13 +1,11 @@
{
"heading": {
"left": {
- "button": "Hủy bỏ",
"alert": {
"title": "Không đăng nữa?",
"buttons": {
"save": "Lưu bản nháp",
- "delete": "Xóa bản nháp",
- "cancel": "Hủy bỏ"
+ "delete": "Xóa bản nháp"
}
}
},
diff --git a/src/i18n/vi/screens/tabs.json b/src/i18n/vi/screens/tabs.json
index b198254e..342857ef 100644
--- a/src/i18n/vi/screens/tabs.json
+++ b/src/i18n/vi/screens/tabs.json
@@ -1,20 +1,21 @@
{
"tabs": {
"local": {
- "name": "Đang theo dõi"
+ "name": "Đang theo dõi",
+ "options": {
+ "showBoosts": "Hiện lượt đăng lại",
+ "showReplies": "Hiện lượt trả lời"
+ }
},
"public": {
- "name": "",
"segments": {
- "left": "Liên hợp",
- "right": "Máy chủ"
+ "federated": "Liên hợp",
+ "local": "Máy chủ",
+ "trending": "Xu hướng"
}
},
"notifications": {
"name": "Thông báo"
- },
- "me": {
- "name": "Tôi"
}
},
"common": {
@@ -24,9 +25,22 @@
}
},
"notifications": {
- "filter": {
+ "filters": {
"accessibilityLabel": "Lọc",
- "accessibilityHint": "Lọc các dạng thông báo"
+ "accessibilityHint": "Lọc các dạng thông báo",
+ "title": "Hiện thông báo",
+ "options": {
+ "follow": "$t(screenTabs:me.push.follow.heading)",
+ "follow_request": "Yêu cầu theo dõi",
+ "favourite": "$t(screenTabs:me.push.favourite.heading)",
+ "reblog": "$t(screenTabs:me.push.reblog.heading)",
+ "mention": "$t(screenTabs:me.push.mention.heading)",
+ "poll": "$t(screenTabs:me.push.poll.heading)",
+ "status": "Tút từ người đã theo dõi",
+ "update": "Đăng lại đã được sửa",
+ "admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
+ "admin.report": "$t(screenTabs:me.push.admin.report.heading)"
+ }
}
},
"me": {
@@ -40,6 +54,9 @@
"favourites": {
"name": "Đã thích"
},
+ "followedTags": {
+ "name": "Hashtag theo dõi"
+ },
"fontSize": {
"name": "Cỡ chữ"
},
@@ -53,7 +70,7 @@
"name": "Người trong danh sách: {{list}}"
},
"listAdd": {
- "name": "Thêm một danh sách"
+ "name": "Tạo danh sách"
},
"listEdit": {
"name": "Sửa danh sách"
@@ -179,8 +196,8 @@
"settings": "Bật trong cài đặt"
},
"missingServerKey": {
- "message": "",
- "description": ""
+ "message": "Máy chủ định cấu hình sai để nhận thông báo đẩy",
+ "description": "Vui lòng liên hệ với quản trị viên máy chủ của bạn để định cấu hình thông báo đẩy"
},
"global": {
"heading": "Bật cho {{acct}}",
@@ -214,6 +231,12 @@
"status": {
"heading": "Tút từ người đã theo dõi"
},
+ "admin.sign_up": {
+ "heading": "Admin: đăng ký"
+ },
+ "admin.report": {
+ "heading": "Admin: báo cáo"
+ },
"howitworks": "Tìm hiểu cách truyền"
},
"root": {
@@ -225,10 +248,8 @@
}
},
"push": {
- "content": {
- "enabled": "Đã bật",
- "disabled": "Đã tắt"
- }
+ "content_true": "Bật",
+ "content_false": "Tắt"
},
"update": {
"title": "Cập nhật phiên bản mới"
@@ -290,9 +311,6 @@
"support": {
"heading": "Ủng hộ tooot"
},
- "review": {
- "heading": "Đánh giá tooot"
- },
"contact": {
"heading": "Liên hệ tooot"
},
@@ -377,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/common.json b/src/i18n/zh-Hans/common.json
index a3c7dd6d..7e8894a1 100644
--- a/src/i18n/zh-Hans/common.json
+++ b/src/i18n/zh-Hans/common.json
@@ -5,6 +5,7 @@
"cancel": "取消",
"discard": "丢弃",
"continue": "继续",
+ "create": "创建",
"delete": "删除",
"done": "完成"
},
diff --git a/src/i18n/zh-Hans/components/instance.json b/src/i18n/zh-Hans/components/instance.json
index abf40b9b..4fdc13f7 100644
--- a/src/i18n/zh-Hans/components/instance.json
+++ b/src/i18n/zh-Hans/components/instance.json
@@ -1,7 +1,7 @@
{
"server": {
"textInput": {
- "placeholder": "输入社区服务器地址"
+ "placeholder": "实例域名"
},
"button": "登录",
"information": {
diff --git a/src/i18n/zh-Hans/components/timeline.json b/src/i18n/zh-Hans/components/timeline.json
index 6725dc0d..404ad280 100644
--- a/src/i18n/zh-Hans/components/timeline.json
+++ b/src/i18n/zh-Hans/components/timeline.json
@@ -30,7 +30,9 @@
"default": "{{name}} 转嘟了",
"notification": "{{name}} 转嘟了你的嘟文"
},
- "update": "转嘟已被编辑"
+ "update": "转嘟已被编辑",
+ "admin.sign_up": "{{name}}加入了实例",
+ "admin.report": "{{name}}举报:"
},
"actions": {
"reply": {
@@ -52,7 +54,8 @@
"bookmarked": {
"accessibilityLabel": "添加此嘟文至书签列表",
"function": "喜欢嘟文"
- }
+ },
+ "openReport": "打开举报"
},
"actionsUsers": {
"reblogged_by": {
diff --git a/src/i18n/zh-Hans/screens/actions.json b/src/i18n/zh-Hans/screens/actions.json
index 56c57a99..3e66a95c 100644
--- a/src/i18n/zh-Hans/screens/actions.json
+++ b/src/i18n/zh-Hans/screens/actions.json
@@ -2,19 +2,6 @@
"content": {
"altText": {
"heading": "替代文本"
- },
- "notificationsFilter": {
- "heading": "显示通知",
- "content": {
- "follow": "$t(screenTabs:me.push.follow.heading)",
- "follow_request": "关注请求",
- "favourite": "$t(screenTabs:me.push.favourite.heading)",
- "reblog": "$t(screenTabs:me.push.reblog.heading)",
- "mention": "$t(screenTabs:me.push.mention.heading)",
- "poll": "$t(screenTabs:me.push.poll.heading)",
- "status": "订阅用户的嘟文",
- "update": "转嘟被编辑"
- }
}
}
}
\ No newline at end of file
diff --git a/src/i18n/zh-Hans/screens/compose.json b/src/i18n/zh-Hans/screens/compose.json
index ba2d5dc3..cbe69118 100644
--- a/src/i18n/zh-Hans/screens/compose.json
+++ b/src/i18n/zh-Hans/screens/compose.json
@@ -1,13 +1,11 @@
{
"heading": {
"left": {
- "button": "退出编辑",
"alert": {
"title": "确认退出编辑?",
"buttons": {
"save": "保存草稿",
- "delete": "删除草稿",
- "cancel": "继续编辑"
+ "delete": "删除草稿"
}
}
},
diff --git a/src/i18n/zh-Hans/screens/tabs.json b/src/i18n/zh-Hans/screens/tabs.json
index bfbd2a44..6f46a372 100644
--- a/src/i18n/zh-Hans/screens/tabs.json
+++ b/src/i18n/zh-Hans/screens/tabs.json
@@ -1,20 +1,21 @@
{
"tabs": {
"local": {
- "name": "我的关注"
+ "name": "我的关注",
+ "options": {
+ "showBoosts": "显示转嘟",
+ "showReplies": "显示回复"
+ }
},
"public": {
- "name": "",
"segments": {
- "left": "跨站嘟嘟",
- "right": "本站嘟嘟"
+ "federated": "跨站",
+ "local": "本站",
+ "trending": "热门"
}
},
"notifications": {
"name": "通知"
- },
- "me": {
- "name": "关于我"
}
},
"common": {
@@ -24,9 +25,22 @@
}
},
"notifications": {
- "filter": {
+ "filters": {
"accessibilityLabel": "筛选",
- "accessibilityHint": "筛选显示的通知类型"
+ "accessibilityHint": "筛选显示的通知类型",
+ "title": "显示通知",
+ "options": {
+ "follow": "$t(screenTabs:me.push.follow.heading)",
+ "follow_request": "关注请求",
+ "favourite": "$t(screenTabs:me.push.favourite.heading)",
+ "reblog": "$t(screenTabs:me.push.reblog.heading)",
+ "mention": "$t(screenTabs:me.push.mention.heading)",
+ "poll": "$t(screenTabs:me.push.poll.heading)",
+ "status": "订阅用户的嘟文",
+ "update": "转嘟被编辑",
+ "admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
+ "admin.report": "$t(screenTabs:me.push.admin.report.heading)"
+ }
}
},
"me": {
@@ -40,6 +54,9 @@
"favourites": {
"name": "喜欢"
},
+ "followedTags": {
+ "name": "关注的话题标签"
+ },
"fontSize": {
"name": "嘟文字号"
},
@@ -53,7 +70,7 @@
"name": "列表中的用户:{{list}}"
},
"listAdd": {
- "name": "添加列表"
+ "name": "创建列表"
},
"listEdit": {
"name": "编辑列表详情"
@@ -214,6 +231,12 @@
"status": {
"heading": "订阅用户的嘟文"
},
+ "admin.sign_up": {
+ "heading": "管理员:用户注册"
+ },
+ "admin.report": {
+ "heading": "管理员:报告"
+ },
"howitworks": "了解通知消息转发如何工作"
},
"root": {
@@ -225,10 +248,8 @@
}
},
"push": {
- "content": {
- "enabled": "已启用",
- "disabled": "未启用"
- }
+ "content_true": "已启用",
+ "content_false": "未启用"
},
"update": {
"title": "更新至最新版本"
@@ -290,9 +311,6 @@
"support": {
"heading": "赞助 tooot 开发"
},
- "review": {
- "heading": "给 tooot 打分"
- },
"contact": {
"heading": "联系 tooot"
},
@@ -377,7 +395,8 @@
"statuses": {
"reblogged_by": "{{count}} 人转嘟",
"favourited_by": "{{count}} 人喜欢"
- }
+ },
+ "resultIncomplete": "来自远程实例的结果不完整"
}
}
}
\ No newline at end of file
diff --git a/src/i18n/zh-Hant/common.json b/src/i18n/zh-Hant/common.json
index 6132e49a..12e5bc66 100644
--- a/src/i18n/zh-Hant/common.json
+++ b/src/i18n/zh-Hant/common.json
@@ -5,6 +5,7 @@
"cancel": "取消",
"discard": "不儲存",
"continue": "繼續",
+ "create": "建立",
"delete": "刪除",
"done": "完成"
},
diff --git a/src/i18n/zh-Hant/components/timeline.json b/src/i18n/zh-Hant/components/timeline.json
index a483f163..f26ff232 100644
--- a/src/i18n/zh-Hant/components/timeline.json
+++ b/src/i18n/zh-Hant/components/timeline.json
@@ -30,7 +30,9 @@
"default": "{{name}} 轉嘟了",
"notification": "{{name}} 轉嘟了您的嘟文"
},
- "update": "轉嘟已編輯"
+ "update": "轉嘟已編輯",
+ "admin.sign_up": "",
+ "admin.report": ""
},
"actions": {
"reply": {
@@ -52,7 +54,8 @@
"bookmarked": {
"accessibilityLabel": "將嘟文加入書籤",
"function": "加入書籤"
- }
+ },
+ "openReport": ""
},
"actionsUsers": {
"reblogged_by": {
diff --git a/src/i18n/zh-Hant/screens/actions.json b/src/i18n/zh-Hant/screens/actions.json
index d5187c30..0ae1bdd9 100644
--- a/src/i18n/zh-Hant/screens/actions.json
+++ b/src/i18n/zh-Hant/screens/actions.json
@@ -2,19 +2,6 @@
"content": {
"altText": {
"heading": "替代文字"
- },
- "notificationsFilter": {
- "heading": "顯示通知類型",
- "content": {
- "follow": "$t(screenTabs:me.push.follow.heading)",
- "follow_request": "跟隨請求",
- "favourite": "$t(screenTabs:me.push.favourite.heading)",
- "reblog": "$t(screenTabs:me.push.reblog.heading)",
- "mention": "$t(screenTabs:me.push.mention.heading)",
- "poll": "$t(screenTabs:me.push.poll.heading)",
- "status": "訂閱使用者的嘟文",
- "update": "轉嘟被編輯"
- }
}
}
}
\ No newline at end of file
diff --git a/src/i18n/zh-Hant/screens/compose.json b/src/i18n/zh-Hant/screens/compose.json
index 4e374c29..78d25b7f 100644
--- a/src/i18n/zh-Hant/screens/compose.json
+++ b/src/i18n/zh-Hant/screens/compose.json
@@ -1,13 +1,11 @@
{
"heading": {
"left": {
- "button": "取消",
"alert": {
"title": "確認取消編輯?",
"buttons": {
"save": "儲存草稿",
- "delete": "刪除草稿",
- "cancel": "取消"
+ "delete": "刪除草稿"
}
}
},
diff --git a/src/i18n/zh-Hant/screens/tabs.json b/src/i18n/zh-Hant/screens/tabs.json
index 5b715fdb..04f2cd86 100644
--- a/src/i18n/zh-Hant/screens/tabs.json
+++ b/src/i18n/zh-Hant/screens/tabs.json
@@ -1,20 +1,21 @@
{
"tabs": {
"local": {
- "name": "跟隨中"
+ "name": "跟隨中",
+ "options": {
+ "showBoosts": "顯示轉嘟",
+ "showReplies": "顯示回覆"
+ }
},
"public": {
- "name": "",
"segments": {
- "left": "聯邦宇宙",
- "right": "本站"
+ "federated": "聯邦",
+ "local": "本站",
+ "trending": "熱門"
}
},
"notifications": {
"name": "通知"
- },
- "me": {
- "name": "關於我"
}
},
"common": {
@@ -24,9 +25,22 @@
}
},
"notifications": {
- "filter": {
+ "filters": {
"accessibilityLabel": "過濾器",
- "accessibilityHint": "過濾顯示的通知類型"
+ "accessibilityHint": "過濾顯示的通知類型",
+ "title": "顯示通知",
+ "options": {
+ "follow": "$t(screenTabs:me.push.follow.heading)",
+ "follow_request": "跟隨請求",
+ "favourite": "$t(screenTabs:me.push.favourite.heading)",
+ "reblog": "$t(screenTabs:me.push.reblog.heading)",
+ "mention": "$t(screenTabs:me.push.mention.heading)",
+ "poll": "$t(screenTabs:me.push.poll.heading)",
+ "status": "訂閱使用者的嘟文",
+ "update": "轉嘟已編輯",
+ "admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
+ "admin.report": "$t(screenTabs:me.push.admin.report.heading)"
+ }
}
},
"me": {
@@ -40,6 +54,9 @@
"favourites": {
"name": "最愛"
},
+ "followedTags": {
+ "name": "跟隨主題標籤"
+ },
"fontSize": {
"name": "嘟文字體大小"
},
@@ -53,7 +70,7 @@
"name": "使用者在 {{list}} 列表中"
},
"listAdd": {
- "name": "新增列表"
+ "name": "建立列表"
},
"listEdit": {
"name": "編輯列表詳細資料"
@@ -179,8 +196,8 @@
"settings": "在設定中啟用"
},
"missingServerKey": {
- "message": "",
- "description": ""
+ "message": "伺服器推播設定不正確",
+ "description": "請聯絡您的伺服器管理員啟用推播設定"
},
"global": {
"heading": "啟用 {{acct}}",
@@ -214,6 +231,12 @@
"status": {
"heading": "訂閱使用者的嘟文"
},
+ "admin.sign_up": {
+ "heading": "管理員:註冊"
+ },
+ "admin.report": {
+ "heading": "管理員:回報"
+ },
"howitworks": "了解通知訊息轉發如何工作"
},
"root": {
@@ -225,10 +248,8 @@
}
},
"push": {
- "content": {
- "enabled": "啟用",
- "disabled": "關閉"
- }
+ "content_true": "啟用",
+ "content_false": "關閉"
},
"update": {
"title": "已更新到最新版本"
@@ -290,9 +311,6 @@
"support": {
"heading": "贊助 tooot 開發"
},
- "review": {
- "heading": "給 tooot 評分"
- },
"contact": {
"heading": "聯繫 tooot"
},
@@ -377,7 +395,8 @@
"statuses": {
"reblogged_by": "{{count}} 人轉嘟",
"favourited_by": "{{count}} 人喜歡"
- }
+ },
+ "resultIncomplete": ""
}
}
}
\ No newline at end of file
diff --git a/src/screens/Actions.tsx b/src/screens/Actions.tsx
index 54626356..0a8b3c3a 100644
--- a/src/screens/Actions.tsx
+++ b/src/screens/Actions.tsx
@@ -15,7 +15,6 @@ import Animated, {
} from 'react-native-reanimated'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import ActionsAltText from './Actions/AltText'
-import ActionsNotificationsFilter from './Actions/NotificationsFilter'
const ScreenActions = ({
route: { params },
@@ -53,8 +52,6 @@ const ScreenActions = ({
const actions = () => {
switch (params.type) {
- case 'notifications_filter':
- return
case 'alt_text':
return
}
diff --git a/src/screens/Actions/NotificationsFilter.tsx b/src/screens/Actions/NotificationsFilter.tsx
deleted file mode 100644
index 928bb5ae..00000000
--- a/src/screens/Actions/NotificationsFilter.tsx
+++ /dev/null
@@ -1,114 +0,0 @@
-import Button from '@components/Button'
-import MenuContainer from '@components/Menu/Container'
-import MenuHeader from '@components/Menu/Header'
-import MenuRow from '@components/Menu/Row'
-import { useNavigation } from '@react-navigation/native'
-import {
- checkInstanceFeature,
- getInstanceNotificationsFilter,
- updateInstanceNotificationsFilter
-} from '@utils/slices/instancesSlice'
-import { StyleConstants } from '@utils/styles/constants'
-import React, { useMemo } from 'react'
-import { useTranslation } from 'react-i18next'
-import { useSelector } from 'react-redux'
-import { useQueryClient } from 'react-query'
-import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
-import { useAppDispatch } from '@root/store'
-
-const ActionsNotificationsFilter: React.FC = () => {
- const navigation = useNavigation()
- const { t } = useTranslation('screenActions')
-
- const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Notifications' }]
- const queryClient = useQueryClient()
-
- const dispatch = useAppDispatch()
- const instanceNotificationsFilter = useSelector(
- getInstanceNotificationsFilter
- )
-
- if (!instanceNotificationsFilter) {
- navigation.goBack()
- return null
- }
-
- const hasTypeStatus = useSelector(
- checkInstanceFeature('notification_type_status')
- )
- const hasTypeUpdate = useSelector(
- checkInstanceFeature('notification_type_update')
- )
- const options = useMemo(() => {
- return (
- instanceNotificationsFilter &&
- (
- [
- 'follow',
- 'follow_request',
- 'favourite',
- 'reblog',
- 'mention',
- 'poll',
- 'status',
- 'update'
- ] as [
- 'follow',
- 'follow_request',
- 'favourite',
- 'reblog',
- 'mention',
- 'poll',
- 'status',
- 'update'
- ]
- )
- .filter(type => {
- switch (type) {
- case 'status':
- return hasTypeStatus
- case 'update':
- return hasTypeUpdate
- default:
- return true
- }
- })
- .map(type => (
-
- dispatch(
- updateInstanceNotificationsFilter({
- ...instanceNotificationsFilter,
- [type]: !instanceNotificationsFilter[type]
- })
- )
- }
- />
- ))
- )
- }, [instanceNotificationsFilter, hasTypeStatus, hasTypeUpdate])
-
- return (
- <>
-
-
- {options}
-
- {
- queryClient.resetQueries(queryKey)
- }}
- style={{
- marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2
- }}
- />
- >
- )
-}
-
-export default ActionsNotificationsFilter
diff --git a/src/screens/Compose.tsx b/src/screens/Compose.tsx
index b53fa346..8b4c5a9e 100644
--- a/src/screens/Compose.tsx
+++ b/src/screens/Compose.tsx
@@ -6,7 +6,7 @@ import { createNativeStackNavigator } from '@react-navigation/native-stack'
import haptics from '@root/components/haptics'
import { useAppDispatch } from '@root/store'
import ComposeRoot from '@screens/Compose/Root'
-import formatText from '@screens/Compose/utils/formatText'
+import { formatText } from '@screens/Compose/utils/processText'
import { RootStackScreenProps } from '@utils/navigation/navigators'
import { useTimelineMutation } from '@utils/queryHooks/timeline'
import { updateStoreReview } from '@utils/slices/contextsSlice'
@@ -22,7 +22,7 @@ import { filter } from 'lodash'
import React, { useCallback, useEffect, useMemo, useReducer, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Alert, Keyboard, Platform } from 'react-native'
-import { useQueryClient } from 'react-query'
+import { useQueryClient } from '@tanstack/react-query'
import { useSelector } from 'react-redux'
import ComposeDraftsList from './Compose/DraftsList'
import ComposeEditAttachment from './Compose/EditAttachment'
@@ -206,7 +206,7 @@ const ScreenCompose: React.FC> = ({
() => (
{
if (!composeState.dirty) {
navigation.goBack()
@@ -229,7 +229,7 @@ const ScreenCompose: React.FC> = ({
}
},
{
- text: t('heading.left.alert.buttons.cancel'),
+ text: t('common:buttons.cancel'),
style: 'cancel'
}
])
@@ -286,7 +286,7 @@ const ScreenCompose: React.FC> = ({
type: 'editItem',
queryKey: params.queryKey,
rootQueryKey: params.rootQueryKey,
- status: res.body
+ status: res
})
break
case 'deleteEdit':
@@ -342,9 +342,7 @@ const ScreenCompose: React.FC> = ({
)
const headerContent = useMemo(() => {
- return `${totalTextCount} / ${maxTootChars}${
- __DEV__ ? ` Dirty: ${composeState.dirty.toString()}` : ''
- }`
+ return `${totalTextCount} / ${maxTootChars}`
}, [totalTextCount, maxTootChars, composeState.dirty])
const inputProps: EmojisState['inputProps'] = [
@@ -407,12 +405,12 @@ const ScreenCompose: React.FC> = ({
diff --git a/src/screens/Compose/DraftsList.tsx b/src/screens/Compose/DraftsList.tsx
index 642bc41d..c0e75001 100644
--- a/src/screens/Compose/DraftsList.tsx
+++ b/src/screens/Compose/DraftsList.tsx
@@ -1,49 +1,227 @@
+import apiInstance from '@api/instance'
import { HeaderLeft } from '@components/Header'
-import { createNativeStackNavigator } from '@react-navigation/native-stack'
+import Icon from '@components/Icon'
+import ComponentSeparator from '@components/Separator'
+import CustomText from '@components/Text'
+import HeaderSharedCreated from '@components/Timeline/Shared/HeaderShared/Created'
+import { useAppDispatch } from '@root/store'
import { ScreenComposeStackScreenProps } from '@utils/navigation/navigators'
-import React, { useCallback } from 'react'
+import { getInstanceDrafts, removeInstanceDraft } from '@utils/slices/instancesSlice'
+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 ComposeDraftsListRoot from './DraftsList/Root'
+import { Dimensions, Modal, Platform, Pressable, View } from 'react-native'
+import FastImage from 'react-native-fast-image'
+import { PanGestureHandler } from 'react-native-gesture-handler'
+import { SwipeListView } from 'react-native-swipe-list-view'
+import { useSelector } from 'react-redux'
+import ComposeContext from './utils/createContext'
+import { formatText } from './utils/processText'
+import { ComposeStateDraft, ExtendedAttachment } from './utils/types'
-const Stack = createNativeStackNavigator()
-
-const ComposeDraftsList: React.FC<
- ScreenComposeStackScreenProps<'Screen-Compose-DraftsList'>
-> = ({
+const ComposeDraftsList: React.FC> = ({
+ navigation,
route: {
params: { timestamp }
- },
- navigation
+ }
}) => {
+ const { colors } = useTheme()
const { t } = useTranslation('screenCompose')
- const children = useCallback(
- () => ,
- []
- )
- const headerLeft = useCallback(
- () => (
- navigation.goBack()}
- />
- ),
- []
+ useEffect(() => {
+ navigation.setOptions({
+ title: t('content.draftsList.header.title'),
+ headerLeft: () => (
+ navigation.goBack()} />
+ )
+ })
+ }, [])
+
+ const { composeDispatch } = useContext(ComposeContext)
+ const instanceDrafts = useSelector(getInstanceDrafts)?.filter(
+ draft => draft.timestamp !== timestamp
)
+ const [checkingAttachments, setCheckingAttachments] = useState(false)
+ const dispatch = useAppDispatch()
+
+ const actionWidth = StyleConstants.Font.Size.L + StyleConstants.Spacing.Global.PagePadding * 4
return (
-
-
+
+
+
+ {t('content.draftsList.warning')}
+
+
+
+ {
+ return (
+ {
+ setCheckingAttachments(true)
+ let tempDraft = item
+ let tempUploads: ExtendedAttachment[] = []
+ if (item.attachments && item.attachments.uploads.length) {
+ for (const attachment of item.attachments.uploads) {
+ await apiInstance({
+ method: 'get',
+ url: `media/${attachment.remote?.id}`
+ })
+ .then(res => {
+ if (res.body.id === attachment.remote?.id) {
+ tempUploads.push(attachment)
+ }
+ })
+ .catch(() => {})
+ }
+ tempDraft = {
+ ...tempDraft,
+ attachments: { ...item.attachments, uploads: tempUploads }
+ }
+ }
+
+ tempDraft.spoiler?.length &&
+ formatText({ textInput: 'text', composeDispatch, content: tempDraft.spoiler })
+ tempDraft.text?.length &&
+ formatText({ textInput: 'text', composeDispatch, content: tempDraft.text })
+ composeDispatch({
+ type: 'loadDraft',
+ payload: tempDraft
+ })
+ dispatch(removeInstanceDraft(item.timestamp))
+ navigation.goBack()
+ }}
+ >
+
+
+
+ {item.text || item.spoiler || t('content.draftsList.content.textEmpty')}
+
+ {item.attachments?.uploads.length ? (
+
+ {item.attachments.uploads.map((attachment, index) => (
+
+ ))}
+
+ ) : null}
+
+
+ )
+ }}
+ renderHiddenItem={({ item }) => (
+ dispatch(removeInstanceDraft(item.timestamp))}
+ children={
+
+ }
+ />
+ }
+ />
+ )}
+ disableRightSwipe={true}
+ rightOpenValue={-actionWidth}
+ previewOpenValue={-actionWidth / 2}
+ ItemSeparatorComponent={ComponentSeparator}
+ keyExtractor={item => item.timestamp.toString()}
+ />
+
+
+ }
+ />
+ }
/>
-
+ >
)
}
diff --git a/src/screens/Compose/DraftsList/Root.tsx b/src/screens/Compose/DraftsList/Root.tsx
deleted file mode 100644
index 7ea9ffa1..00000000
--- a/src/screens/Compose/DraftsList/Root.tsx
+++ /dev/null
@@ -1,228 +0,0 @@
-import apiInstance from '@api/instance'
-import Icon from '@components/Icon'
-import ComponentSeparator from '@components/Separator'
-import CustomText from '@components/Text'
-import HeaderSharedCreated from '@components/Timeline/Shared/HeaderShared/Created'
-import { useNavigation } from '@react-navigation/native'
-import { useAppDispatch } from '@root/store'
-import { getInstanceDrafts, removeInstanceDraft } from '@utils/slices/instancesSlice'
-import { StyleConstants } from '@utils/styles/constants'
-import { useTheme } from '@utils/styles/ThemeManager'
-import React, { useCallback, useContext, useState } from 'react'
-import { useTranslation } from 'react-i18next'
-import { Dimensions, Image, Modal, Platform, Pressable, View } from 'react-native'
-import { PanGestureHandler } from 'react-native-gesture-handler'
-import { SwipeListView } from 'react-native-swipe-list-view'
-import { useSelector } from 'react-redux'
-import ComposeContext from '../utils/createContext'
-import formatText from '../utils/formatText'
-import { ComposeStateDraft, ExtendedAttachment } from '../utils/types'
-
-export interface Props {
- timestamp: number
-}
-
-const ComposeDraftsListRoot: React.FC = ({ timestamp }) => {
- const { composeDispatch } = useContext(ComposeContext)
- const { t } = useTranslation('screenCompose')
- const navigation = useNavigation()
- const dispatch = useAppDispatch()
- const { colors, theme } = useTheme()
- const instanceDrafts = useSelector(getInstanceDrafts)?.filter(
- draft => draft.timestamp !== timestamp
- )
-
- const actionWidth = StyleConstants.Font.Size.L + StyleConstants.Spacing.Global.PagePadding * 4
-
- const [checkingAttachments, setCheckingAttachments] = useState(false)
-
- const renderItem = useCallback(
- ({ item }: { item: ComposeStateDraft }) => {
- return (
- {
- setCheckingAttachments(true)
- let tempDraft = item
- let tempUploads: ExtendedAttachment[] = []
- if (item.attachments && item.attachments.uploads.length) {
- for (const attachment of item.attachments.uploads) {
- await apiInstance({
- method: 'get',
- url: `media/${attachment.remote?.id}`
- })
- .then(res => {
- if (res.body.id === attachment.remote?.id) {
- tempUploads.push(attachment)
- }
- })
- .catch(() => {})
- }
- tempDraft = {
- ...tempDraft,
- attachments: { ...item.attachments, uploads: tempUploads }
- }
- }
-
- tempDraft.spoiler?.length &&
- formatText({ textInput: 'text', composeDispatch, content: tempDraft.spoiler })
- tempDraft.text?.length &&
- formatText({ textInput: 'text', composeDispatch, content: tempDraft.text })
- composeDispatch({
- type: 'loadDraft',
- payload: tempDraft
- })
- dispatch(removeInstanceDraft(item.timestamp))
- navigation.goBack()
- }}
- >
-
-
-
- {item.text || item.spoiler || t('content.draftsList.content.textEmpty')}
-
- {item.attachments?.uploads.length ? (
-
- {item.attachments.uploads.map((attachment, index) => (
-
- ))}
-
- ) : null}
-
-
- )
- },
- [theme]
- )
-
- return (
- <>
-
-
-
- {t('content.draftsList.warning')}
-
-
-
- (
- dispatch(removeInstanceDraft(item.timestamp))}
- children={
-
- }
- />
- }
- />
- )}
- disableRightSwipe={true}
- rightOpenValue={-actionWidth}
- // previewRowKey={
- // instanceDrafts?.length
- // ? instanceDrafts[0].timestamp.toString()
- // : undefined
- // }
- // previewDuration={350}
- previewOpenValue={-actionWidth / 2}
- ItemSeparatorComponent={ComponentSeparator}
- keyExtractor={item => item.timestamp.toString()}
- />
-
-
- }
- />
- }
- />
- >
- )
-}
-
-export default ComposeDraftsListRoot
diff --git a/src/screens/Compose/EditAttachment.tsx b/src/screens/Compose/EditAttachment.tsx
index fd9b6967..5aea5eff 100644
--- a/src/screens/Compose/EditAttachment.tsx
+++ b/src/screens/Compose/EditAttachment.tsx
@@ -1,49 +1,90 @@
-import { HeaderLeft } from '@components/Header'
-import { createNativeStackNavigator } from '@react-navigation/native-stack'
+import apiInstance from '@api/instance'
+import haptics from '@components/haptics'
+import { HeaderLeft, HeaderRight } from '@components/Header'
import { ScreenComposeStackScreenProps } from '@utils/navigation/navigators'
-import React from 'react'
+import React, { useContext, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
-import { KeyboardAvoidingView, Platform } from 'react-native'
+import { Alert, KeyboardAvoidingView, Platform } from 'react-native'
import { SafeAreaView } from 'react-native-safe-area-context'
import ComposeEditAttachmentRoot from './EditAttachment/Root'
-import ComposeEditAttachmentSubmit from './EditAttachment/Submit'
+import ComposeContext from './utils/createContext'
-const Stack = createNativeStackNavigator()
-
-const ComposeEditAttachment: React.FC> = ({
+const ComposeEditAttachment: React.FC<
+ ScreenComposeStackScreenProps<'Screen-Compose-EditAttachment'>
+> = ({
+ navigation,
route: {
params: { index }
- },
- navigation
-}) => {
- const { t } = useTranslation('screenCompose')
-
- return (
-
-
-
- }
- options={{
- headerLeft: () => navigation.goBack()}
- />,
- headerRight: () => ,
- title: t('content.editAttachment.header.title')
- }}
- />
-
-
-
- )
}
+}) => {
+ const { t } = useTranslation('screenCompose')
+
+ const { composeState } = useContext(ComposeContext)
+ const [isSubmitting, setIsSubmitting] = useState(false)
+
+ const theAttachment = composeState.attachments.uploads[index].remote!
+
+ useEffect(() => {
+ navigation.setOptions({
+ title: t('content.editAttachment.header.title'),
+ headerLeft: () => (
+ navigation.goBack()} />
+ ),
+ headerRight: () => (
+ {
+ setIsSubmitting(true)
+ const formData = new FormData()
+ if (theAttachment.description) {
+ formData.append('description', theAttachment.description)
+ }
+ if (theAttachment.meta?.focus?.x !== 0 || theAttachment.meta.focus.y !== 0) {
+ formData.append(
+ 'focus',
+ `${theAttachment.meta?.focus?.x || 0},${-theAttachment.meta?.focus?.y || 0}`
+ )
+ }
+
+ theAttachment?.id &&
+ apiInstance({
+ method: 'put',
+ url: `media/${theAttachment.id}`,
+ body: formData
+ })
+ .then(() => {
+ haptics('Success')
+ navigation.goBack()
+ })
+ .catch(() => {
+ setIsSubmitting(false)
+ haptics('Error')
+ Alert.alert(t('content.editAttachment.header.right.failed.title'), undefined, [
+ {
+ text: t('content.editAttachment.header.right.failed.button'),
+ style: 'cancel'
+ }
+ ])
+ })
+ }}
+ />
+ )
+ })
+ }, [theAttachment])
+
+ return (
+
+
+
+
+
+ )
+}
export default ComposeEditAttachment
diff --git a/src/screens/Compose/EditAttachment/Image.tsx b/src/screens/Compose/EditAttachment/Image.tsx
index 05f0236f..f8b1e118 100644
--- a/src/screens/Compose/EditAttachment/Image.tsx
+++ b/src/screens/Compose/EditAttachment/Image.tsx
@@ -112,6 +112,17 @@ const ComposeEditAttachmentImage: React.FC = ({ index }) => {
return (
<>
+
+ {t('content.editAttachment.content.imageFocus')}
+
= ({ index }) => {
/>
- {screenReaderEnabled ? null : (
-
- {t('content.editAttachment.content.imageFocus')}
-
- )}
>
)
}
diff --git a/src/screens/Compose/EditAttachment/Root.tsx b/src/screens/Compose/EditAttachment/Root.tsx
index fcce19ed..db48d07d 100644
--- a/src/screens/Compose/EditAttachment/Root.tsx
+++ b/src/screens/Compose/EditAttachment/Root.tsx
@@ -2,7 +2,7 @@ import CustomText from '@components/Text'
import AttachmentVideo from '@components/Timeline/Shared/Attachment/Video'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
-import React, { useContext, useRef } from 'react'
+import React, { useContext } from 'react'
import { useTranslation } from 'react-i18next'
import { ScrollView, StyleSheet, TextInput, View } from 'react-native'
import ComposeContext from '../utils/createContext'
@@ -34,10 +34,10 @@ const ComposeEditAttachmentRoot: React.FC = ({ index }) => {
video={
video.local
? ({
- url: video.local.uri,
- preview_url: video.local.thumbnail,
- blurhash: video.remote?.blurhash
- } as Mastodon.AttachmentVideo)
+ url: video.local.uri,
+ preview_url: video.local.thumbnail,
+ blurhash: video.remote?.blurhash
+ } as Mastodon.AttachmentVideo)
: (video.remote as Mastodon.AttachmentVideo)
}
/>
@@ -47,45 +47,36 @@ const ComposeEditAttachmentRoot: React.FC = ({ index }) => {
return null
}
- const scrollViewRef = useRef(null)
-
return (
-
- {mediaDisplay()}
-
-
+
+
+
{t('content.editAttachment.content.altText.heading')}
scrollViewRef.current?.scrollToEnd()}
maxLength={1500}
multiline
- onChangeText={(e) =>
+ onChangeText={e =>
composeDispatch({
type: 'attachment/edit',
payload: {
...theAttachment,
description: e
}
- })}
+ })
+ }
placeholder={t('content.editAttachment.content.altText.placeholder')}
placeholderTextColor={colors.secondary}
- scrollEnabled
value={theAttachment.description}
keyboardAppearance={mode}
/>
@@ -101,6 +92,7 @@ const ComposeEditAttachmentRoot: React.FC = ({ index }) => {
{theAttachment.description?.length || 0} / 1500
+ {mediaDisplay()}
)
}
diff --git a/src/screens/Compose/EditAttachment/Submit.tsx b/src/screens/Compose/EditAttachment/Submit.tsx
deleted file mode 100644
index c4ee0e39..00000000
--- a/src/screens/Compose/EditAttachment/Submit.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-import apiInstance from '@api/instance'
-import haptics from '@components/haptics'
-import { HeaderRight } from '@components/Header'
-import { useNavigation } from '@react-navigation/native'
-import React, { useContext, useState } from 'react'
-import { useTranslation } from 'react-i18next'
-import { Alert } from 'react-native'
-import ComposeContext from '../utils/createContext'
-
-export interface Props {
- index: number
-}
-
-const ComposeEditAttachmentSubmit: React.FC = ({ index }) => {
- const { composeState } = useContext(ComposeContext)
- const navigation = useNavigation()
- const [isSubmitting, setIsSubmitting] = useState(false)
- const { t } = useTranslation('screenCompose')
-
- const theAttachment = composeState.attachments.uploads[index].remote!
-
- return (
- {
- setIsSubmitting(true)
- const formData = new FormData()
- if (theAttachment.description) {
- formData.append('description', theAttachment.description)
- }
- if (
- theAttachment.meta?.focus?.x !== 0 ||
- theAttachment.meta.focus.y !== 0
- ) {
- formData.append(
- 'focus',
- `${theAttachment.meta?.focus?.x || 0},${
- -theAttachment.meta?.focus?.y || 0
- }`
- )
- }
-
- theAttachment?.id &&
- apiInstance({
- method: 'put',
- url: `media/${theAttachment.id}`,
- body: formData
- })
- .then(() => {
- haptics('Success')
- navigation.goBack()
- })
- .catch(() => {
- setIsSubmitting(false)
- haptics('Error')
- Alert.alert(
- t('content.editAttachment.header.right.failed.title'),
- undefined,
- [
- {
- text: t(
- 'content.editAttachment.header.right.failed.button'
- ),
- style: 'cancel'
- }
- ]
- )
- })
- }}
- />
- )
-}
-
-export default ComposeEditAttachmentSubmit
diff --git a/src/screens/Compose/Root/Footer/Attachments.tsx b/src/screens/Compose/Root/Footer/Attachments.tsx
index ec71b0a5..8c7ff50f 100644
--- a/src/screens/Compose/Root/Footer/Attachments.tsx
+++ b/src/screens/Compose/Root/Footer/Attachments.tsx
@@ -171,21 +171,23 @@ const ComposeAttachments: React.FC = ({ accessibleRefAttachments }) => {
haptics('Success')
}}
/>
- {
- navigation.navigate('Screen-Compose-EditAttachment', {
- index
- })
- }}
- />
+ {!composeState.attachments.disallowEditing ? (
+ {
+ navigation.navigate('Screen-Compose-EditAttachment', {
+ index
+ })
+ }}
+ />
+ ) : null}
)}
diff --git a/src/screens/Compose/Root/Footer/Reply.tsx b/src/screens/Compose/Root/Footer/Reply.tsx
index 0f86e146..6b68cc53 100644
--- a/src/screens/Compose/Root/Footer/Reply.tsx
+++ b/src/screens/Compose/Root/Footer/Reply.tsx
@@ -1,4 +1,5 @@
import TimelineDefault from '@components/Timeline/Default'
+import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useContext } from 'react'
import { StyleSheet, View } from 'react-native'
@@ -11,16 +12,23 @@ const ComposeReply: React.FC = () => {
const { colors } = useTheme()
return (
-
-
+
+ {replyToStatus ? (
+
+ ) : null}
)
}
-const styles = StyleSheet.create({
- base: {
- borderTopWidth: StyleSheet.hairlineWidth
- }
-})
-
export default React.memo(ComposeReply, () => true)
diff --git a/src/screens/Compose/Root/Header/SpoilerInput.tsx b/src/screens/Compose/Root/Header/SpoilerInput.tsx
index 644737ae..2a7b1621 100644
--- a/src/screens/Compose/Root/Header/SpoilerInput.tsx
+++ b/src/screens/Compose/Root/Header/SpoilerInput.tsx
@@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next'
import { TextInput } from 'react-native'
import { useSelector } from 'react-redux'
import ComposeContext from '../../utils/createContext'
-import formatText from '../../utils/formatText'
+import { formatText } from '../../utils/processText'
const ComposeSpoilerInput: React.FC = () => {
const { composeState, composeDispatch } = useContext(ComposeContext)
diff --git a/src/screens/Compose/Root/Header/TextInput.tsx b/src/screens/Compose/Root/Header/TextInput.tsx
index ef89d0e1..a74e85a1 100644
--- a/src/screens/Compose/Root/Header/TextInput.tsx
+++ b/src/screens/Compose/Root/Header/TextInput.tsx
@@ -10,7 +10,7 @@ import { useTranslation } from 'react-i18next'
import { Alert } from 'react-native'
import { useSelector } from 'react-redux'
import ComposeContext from '../../utils/createContext'
-import formatText from '../../utils/formatText'
+import { formatText } from '../../utils/processText'
import { uploadAttachment } from '../Footer/addAttachment'
const ComposeTextInput: React.FC = () => {
@@ -27,6 +27,7 @@ const ComposeTextInput: React.FC = () => {
return (
({
remote: media
diff --git a/src/screens/Compose/utils/post.ts b/src/screens/Compose/utils/post.ts
index 348225ef..98ceec8b 100644
--- a/src/screens/Compose/utils/post.ts
+++ b/src/screens/Compose/utils/post.ts
@@ -1,14 +1,23 @@
-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'
import * as Crypto from 'expo-crypto'
+import { getPureContent } from './processText'
const composePost = async (
params: RootStackParamList['Screen-Compose'],
composeState: ComposeState
-): Promise> => {
+): Promise => {
const formData = new FormData()
+ const detectedLanguage = await detectLanguage(
+ getPureContent([composeState.spoiler.raw, composeState.text.raw].join('\n\n'))
+ )
+ if (detectedLanguage) {
+ formData.append('language', detectedLanguage.language)
+ }
+
if (composeState.replyToStatus) {
try {
await apiInstance({
@@ -65,7 +74,7 @@ const composePost = async (
)
},
body: formData
- })
+ }).then(res => res.body)
}
export default composePost
diff --git a/src/screens/Compose/utils/formatText.tsx b/src/screens/Compose/utils/processText.tsx
similarity index 92%
rename from src/screens/Compose/utils/formatText.tsx
rename to src/screens/Compose/utils/processText.tsx
index a82be98f..7cd2c0d6 100644
--- a/src/screens/Compose/utils/formatText.tsx
+++ b/src/screens/Compose/utils/processText.tsx
@@ -1,7 +1,6 @@
import LinkifyIt from 'linkify-it'
import { debounce, differenceWith, isEqual } from 'lodash'
import React, { Dispatch } from 'react'
-import { FetchOptions } from 'react-query/types/core/query'
import { useTheme } from '@utils/styles/ThemeManager'
import { ComposeAction, ComposeState } from './types'
import { instanceConfigurationStatusCharsURL } from '../Root'
@@ -12,7 +11,6 @@ export interface Params {
textInput: ComposeState['textInputFocus']['current']
composeDispatch: Dispatch
content: string
- refetch?: (options?: FetchOptions | undefined) => Promise
disableDebounce?: boolean
}
@@ -150,7 +148,7 @@ const formatText = ({ textInput, composeDispatch, content, disableDebounce = fal
})
children.push(_content)
contentLength = contentLength + _content.length
-
+ getPureContent(content)
composeDispatch({
type: textInput,
payload: {
@@ -161,4 +159,18 @@ const formatText = ({ textInput, composeDispatch, content, disableDebounce = fal
})
}
-export default formatText
+const getPureContent = (content: string): string => {
+ const tags = linkify.match(content)
+ if (!tags) {
+ return content
+ }
+
+ let _content = content
+ for (const tag of tags) {
+ _content = _content.replace(tag.raw, '')
+ }
+
+ return _content.replace(/\s\s+/g, ' ')
+}
+
+export { formatText, getPureContent }
diff --git a/src/screens/Compose/utils/types.d.ts b/src/screens/Compose/utils/types.d.ts
index 3500bee6..f5457e46 100644
--- a/src/screens/Compose/utils/types.d.ts
+++ b/src/screens/Compose/utils/types.d.ts
@@ -51,6 +51,7 @@ export type ComposeState = {
expire: '300' | '1800' | '3600' | '21600' | '86400' | '259200' | '604800'
}
attachments: {
+ disallowEditing?: boolean // https://github.com/mastodon/mastodon/pull/20878
sensitive: boolean
uploads: ExtendedAttachment[]
}
@@ -59,8 +60,8 @@ export type ComposeState = {
replyToStatus?: Mastodon.Status
textInputFocus: {
current: 'text' | 'spoiler'
- refs: { text: RefObject, spoiler: RefObject }
- isFocused: { text: MutableRefObject, spoiler: MutableRefObject }
+ refs: { text: RefObject; spoiler: RefObject }
+ isFocused: { text: MutableRefObject; spoiler: MutableRefObject }
}
}
diff --git a/src/screens/ImagesViewer.tsx b/src/screens/ImagesViewer.tsx
index eb99187f..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
+ }}
+ />
}
/>
@@ -180,7 +176,7 @@ const ScreenImagesViewer = ({
options: [
t('content.options.save'),
t('content.options.share'),
- t('content.options.cancel')
+ t('common:buttons.cancel')
],
cancelButtonIndex: 2,
userInterfaceStyle: mode
diff --git a/src/screens/Tabs.tsx b/src/screens/Tabs.tsx
index d8f50cc9..f0b2ce9f 100644
--- a/src/screens/Tabs.tsx
+++ b/src/screens/Tabs.tsx
@@ -3,16 +3,10 @@ import haptics from '@components/haptics'
import Icon from '@components/Icon'
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
import { useAppDispatch } from '@root/store'
-import {
- RootStackScreenProps,
- ScreenTabsStackParamList
-} from '@utils/navigation/navigators'
-import { getPreviousTab } from '@utils/slices/contextsSlice'
-import {
- getInstanceAccount,
- getInstanceActive
-} from '@utils/slices/instancesSlice'
+import { RootStackScreenProps, ScreenTabsStackParamList } from '@utils/navigation/navigators'
import { getVersionUpdate, retrieveVersionLatest } from '@utils/slices/appSlice'
+import { getPreviousTab } from '@utils/slices/contextsSlice'
+import { getInstanceAccount, getInstanceActive } from '@utils/slices/instancesSlice'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useCallback, useEffect, useMemo } from 'react'
import { Platform } from 'react-native'
@@ -125,11 +119,7 @@ const ScreenTabs = React.memo(
>
-
+
()
-
-const TabLocal = React.memo(
- ({ navigation }: ScreenTabsScreenProps<'Tab-Local'>) => {
- const { t } = useTranslation('screenTabs')
-
- const { data: lists } = useListsQuery({})
- useEffect(() => {
- layoutAnimation()
- }, [lists?.length])
-
- const [queryKey, setQueryKey] = useState(['Timeline', { page: 'Following' }])
-
- usePopToTop()
-
- return (
-
- (
-
-
- 0}
- content={
- queryKey[1].page === 'List' && queryKey[1].list?.length
- ? lists?.find(list => list.id === queryKey[1].list)?.title
- : t('tabs.local.name')
- }
- />
-
-
-
- {lists?.length
- ? [
- {
- key: 'default',
- item: {
- onSelect: () => setQueryKey(['Timeline', { page: 'Following' }]),
- disabled: queryKey[1].page === 'Following',
- destructive: false,
- hidden: false
- },
- title: t('tabs.local.name'),
- icon: ''
- },
- ...lists?.map(list => ({
- key: list.id,
- item: {
- onSelect: () =>
- setQueryKey(['Timeline', { page: 'List', list: list.id }]),
- disabled: queryKey[1].page === 'List' && queryKey[1].list === list.id,
- destructive: false,
- hidden: false
- },
- title: list.title,
- icon: ''
- }))
- ].map(menu => (
-
-
-
-
- ))
- : undefined}
-
-
- ),
- headerRight: () => (
- navigation.navigate('Tab-Local', { screen: 'Tab-Shared-Search' })}
- />
- )
- }}
- children={() => (
-
- }}
- />
- )}
- />
- {TabShared({ Stack })}
-
- )
- },
- () => true
-)
-
-export default TabLocal
diff --git a/src/screens/Tabs/Local/Root.tsx b/src/screens/Tabs/Local/Root.tsx
new file mode 100644
index 00000000..5bd4d507
--- /dev/null
+++ b/src/screens/Tabs/Local/Root.tsx
@@ -0,0 +1,191 @@
+import { HeaderRight } from '@components/Header'
+import Icon from '@components/Icon'
+import CustomText from '@components/Text'
+import Timeline from '@components/Timeline'
+import TimelineDefault from '@components/Timeline/Default'
+import { NativeStackScreenProps } from '@react-navigation/native-stack'
+import { TabLocalStackParamList } from '@utils/navigation/navigators'
+import usePopToTop from '@utils/navigation/usePopToTop'
+import { useListsQuery } from '@utils/queryHooks/lists'
+import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
+import { getInstanceFollowingPage, updateInstanceFollowingPage } from '@utils/slices/instancesSlice'
+import { StyleConstants } from '@utils/styles/constants'
+import { useTheme } from '@utils/styles/ThemeManager'
+import { useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { View } from 'react-native'
+import { useDispatch, useSelector } from 'react-redux'
+import * as DropdownMenu from 'zeego/dropdown-menu'
+
+const Root: React.FC> = ({
+ navigation
+}) => {
+ const { colors, mode } = useTheme()
+ const { t } = useTranslation('screenTabs')
+
+ const { data: lists } = useListsQuery()
+
+ const dispatch = useDispatch()
+ const instanceFollowingPage = useSelector(getInstanceFollowingPage)
+ const [queryKey, setQueryKey] = useState([
+ 'Timeline',
+ { page: 'Following', ...instanceFollowingPage }
+ ])
+
+ useEffect(() => {
+ const page = queryKey[1]
+
+ navigation.setOptions({
+ headerTitle: () => (
+
+
+
+ {page.page === 'List' ? (
+
+ ) : null}
+ list.id === page.list)?.title
+ : t('tabs.local.name')
+ }
+ />
+ {page.page === 'Following' && !instanceFollowingPage.showBoosts ? (
+
+ ) : null}
+ {page.page === 'Following' && !instanceFollowingPage.showReplies ? (
+
+ ) : null}
+
+
+
+
+
+
+
+ setQueryKey(['Timeline', { page: 'Following', ...instanceFollowingPage }])
+ }
+ disabled={page.page === 'Following'}
+ >
+
+
+
+ {
+ setQueryKey([
+ 'Timeline',
+ {
+ page: 'Following',
+ showBoosts: !instanceFollowingPage.showBoosts,
+ showReplies: instanceFollowingPage.showReplies
+ }
+ ])
+ dispatch(
+ updateInstanceFollowingPage({ showBoosts: !instanceFollowingPage.showBoosts })
+ )
+ }}
+ >
+
+
+
+ {
+ setQueryKey([
+ 'Timeline',
+ {
+ page: 'Following',
+ showBoosts: instanceFollowingPage.showBoosts,
+ showReplies: !instanceFollowingPage.showReplies
+ }
+ ])
+ dispatch(
+ updateInstanceFollowingPage({ showReplies: !instanceFollowingPage.showReplies })
+ )
+ }}
+ >
+
+
+
+
+
+
+ {lists?.length
+ ? [
+ ...lists?.map(list => ({
+ key: list.id,
+ item: {
+ onSelect: () => setQueryKey(['Timeline', { page: 'List', list: list.id }]),
+ disabled: page.page === 'List' && page.list === list.id,
+ destructive: false,
+ hidden: false
+ },
+ title: list.title,
+ icon: 'list.bullet'
+ }))
+ ].map(menu => (
+
+
+
+
+ ))
+ : undefined}
+
+
+
+ ),
+ headerRight: () => (
+ navigation.navigate('Tab-Shared-Search')}
+ />
+ )
+ })
+ }, [mode, queryKey[1], instanceFollowingPage])
+
+ usePopToTop()
+
+ return (
+
+ }}
+ />
+ )
+}
+
+export default Root
diff --git a/src/screens/Tabs/Local/index.tsx b/src/screens/Tabs/Local/index.tsx
new file mode 100644
index 00000000..ea78dcbe
--- /dev/null
+++ b/src/screens/Tabs/Local/index.tsx
@@ -0,0 +1,18 @@
+import { createNativeStackNavigator } from '@react-navigation/native-stack'
+import { TabLocalStackParamList } from '@utils/navigation/navigators'
+import React from 'react'
+import TabShared from '../Shared'
+import Root from './Root'
+
+const Stack = createNativeStackNavigator()
+
+const TabLocal: React.FC = () => {
+ return (
+
+
+ {TabShared({ Stack })}
+
+ )
+}
+
+export default TabLocal
diff --git a/src/screens/Tabs/Me.tsx b/src/screens/Tabs/Me.tsx
deleted file mode 100644
index 650dbff9..00000000
--- a/src/screens/Tabs/Me.tsx
+++ /dev/null
@@ -1,192 +0,0 @@
-import { HeaderCenter, HeaderLeft } from '@components/Header'
-import { createNativeStackNavigator } from '@react-navigation/native-stack'
-import { TabMeStackParamList } from '@utils/navigation/navigators'
-import React from 'react'
-import { useTranslation } from 'react-i18next'
-import { Platform } from 'react-native'
-import TabMeBookmarks from './Me/Bookmarks'
-import TabMeConversations from './Me/Cconversations'
-import TabMeFavourites from './Me/Favourites'
-import TabMeList from './Me/List'
-import TabMeListAccounts from './Me/List/Accounts'
-import TabMeListEdit from './Me/List/Edit'
-import TabMeListList from './Me/List/List'
-import TabMeProfile from './Me/Profile'
-import TabMePush from './Me/Push'
-import TabMeRoot from './Me/Root'
-import TabMeSettings from './Me/Settings'
-import TabMeSettingsFontsize from './Me/SettingsFontsize'
-import TabMeSettingsLanguage from './Me/SettingsLanguage'
-import TabMeSwitch from './Me/Switch'
-import TabShared from './Shared'
-
-const Stack = createNativeStackNavigator()
-
-const TabMe = React.memo(
- () => {
- const { t } = useTranslation('screenTabs')
-
- return (
-
-
- ({
- title: t('me.stacks.bookmarks.name'),
- ...(Platform.OS === 'android' && {
- headerCenter: () =>
- }),
- headerLeft: () => navigation.pop(1)} />
- })}
- />
- ({
- title: t('me.stacks.conversations.name'),
- ...(Platform.OS === 'android' && {
- headerCenter: () =>
- }),
- headerLeft: () => navigation.pop(1)} />
- })}
- />
- ({
- title: t('me.stacks.favourites.name'),
- ...(Platform.OS === 'android' && {
- headerCenter: () =>
- }),
- headerLeft: () => navigation.pop(1)} />
- })}
- />
- ({
- title: t('me.stacks.list.name', { list: route.params.title }),
- ...(Platform.OS === 'android' && {
- headerCenter: () => (
-
- )
- }),
- headerLeft: () => navigation.pop(1)} />
- })}
- />
- ({
- title: t('me.stacks.listAccounts.name', { list: params.title }),
- ...(Platform.OS === 'android' && {
- headerCenter: () =>
- }),
- headerLeft: () => navigation.pop(1)} />
- })}
- />
-
- ({
- title: t('me.stacks.lists.name'),
- ...(Platform.OS === 'android' && {
- headerCenter: () =>
- }),
- headerLeft: () => navigation.pop(1)} />
- })}
- />
-
- ({
- title: t('me.stacks.push.name'),
- ...(Platform.OS === 'android' && {
- headerCenter: () =>
- }),
- headerLeft: () => navigation.goBack()} />
- })}
- />
- ({
- title: t('me.stacks.settings.name'),
- headerLeft: () => navigation.pop(1)} />
- })}
- />
- ({
- title: t('me.stacks.fontSize.name'),
- ...(Platform.OS === 'android' && {
- headerCenter: () =>
- }),
- headerLeft: () => navigation.pop(1)} />
- })}
- />
- ({
- title: t('me.stacks.language.name'),
- ...(Platform.OS === 'android' && {
- headerCenter: () =>
- }),
- headerLeft: () => navigation.pop(1)} />
- })}
- />
- ({
- presentation: 'modal',
- headerShown: true,
- title: t('me.stacks.switch.name'),
- ...(Platform.OS === 'android' && {
- headerCenter: () =>
- }),
- headerLeft: () => (
- navigation.goBack()} />
- )
- })}
- />
-
- {TabShared({ Stack })}
-
- )
- },
- () => true
-)
-
-export default TabMe
diff --git a/src/screens/Tabs/Me/FollowedTags.tsx b/src/screens/Tabs/Me/FollowedTags.tsx
new file mode 100644
index 00000000..32a2af98
--- /dev/null
+++ b/src/screens/Tabs/Me/FollowedTags.tsx
@@ -0,0 +1,71 @@
+import Button from '@components/Button'
+import haptics from '@components/haptics'
+import ComponentHashtag from '@components/Hashtag'
+import { displayMessage } from '@components/Message'
+import ComponentSeparator from '@components/Separator'
+import { TabMeStackScreenProps } from '@utils/navigation/navigators'
+import { useFollowedTagsQuery, useTagsMutation } from '@utils/queryHooks/tags'
+import React, { useEffect } from 'react'
+import { useTranslation } from 'react-i18next'
+import { FlatList } from 'react-native-gesture-handler'
+
+const TabMeFollowedTags: React.FC> = ({
+ navigation
+}) => {
+ const { t } = useTranslation('screenTabs')
+
+ const { data, fetchNextPage, refetch } = useFollowedTagsQuery()
+ const flattenData = data?.pages ? data.pages.flatMap(page => [...page.body]) : []
+ useEffect(() => {
+ if (flattenData.length === 0) {
+ navigation.goBack()
+ }
+ }, [flattenData.length])
+
+ const mutation = useTagsMutation({
+ onSuccess: () => {
+ haptics('Light')
+ refetch()
+ },
+ onError: (err: any, { to }) => {
+ displayMessage({
+ type: 'error',
+ message: t('common:message.error.message', {
+ function: to ? t('shared.hashtag.follow') : t('shared.hashtag.unfollow')
+ }),
+ ...(err.status &&
+ typeof err.status === 'number' &&
+ err.data &&
+ err.data.error &&
+ typeof err.data.error === 'string' && {
+ description: err.data.error
+ })
+ })
+ }
+ })
+
+ return (
+ (
+ {}}
+ children={
+ mutation.mutate({ tag: item.name, to: !item.following })}
+ />
+ }
+ />
+ )}
+ onEndReached={() => fetchNextPage()}
+ onEndReachedThreshold={0.5}
+ ItemSeparatorComponent={ComponentSeparator}
+ />
+ )
+}
+
+export default TabMeFollowedTags
diff --git a/src/screens/Tabs/Me/List/Accounts.tsx b/src/screens/Tabs/Me/List/Accounts.tsx
index e3b35678..89465612 100644
--- a/src/screens/Tabs/Me/List/Accounts.tsx
+++ b/src/screens/Tabs/Me/List/Accounts.tsx
@@ -27,7 +27,9 @@ const TabMeListAccounts: React.FC>
options: {
getNextPageParam: lastPage =>
lastPage?.links?.next && {
- max_id: lastPage.links.next
+ ...(lastPage.links.next.isOffset
+ ? { offset: lastPage.links.next.id }
+ : { max_id: lastPage.links.next.id })
}
}
})
diff --git a/src/screens/Tabs/Me/List/Edit.tsx b/src/screens/Tabs/Me/List/Edit.tsx
index 70635d53..d2b67a3c 100644
--- a/src/screens/Tabs/Me/List/Edit.tsx
+++ b/src/screens/Tabs/Me/List/Edit.tsx
@@ -13,7 +13,7 @@ import { useTheme } from '@utils/styles/ThemeManager'
import React, { useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Alert, Platform, ScrollView, TextInput } from 'react-native'
-import { useQueryClient } from 'react-query'
+import { useQueryClient } from '@tanstack/react-query'
const TabMeListEdit: React.FC> = ({
navigation,
@@ -83,15 +83,6 @@ const TabMeListEdit: React.FC> = ({
useEffect(() => {
navigation.setOptions({
title: params.type === 'add' ? t('me.stacks.listAdd.name') : t('me.stacks.listEdit.name'),
- ...(Platform.OS === 'android' && {
- headerCenter: () => (
-
- )
- }),
headerLeft: () => (
> = ({ navigation }) => {
const { data } = useListsQuery({})
- const { t } = useTranslation('screenTabs')
+ const { t } = useTranslation()
useEffect(() => {
navigation.setOptions({
headerRight: () => (
navigation.navigate('Tab-Me-List-Edit', { type: 'add' })}
/>
)
diff --git a/src/screens/Tabs/Me/List/index.tsx b/src/screens/Tabs/Me/List/index.tsx
index 2ec2c3e1..9f302971 100644
--- a/src/screens/Tabs/Me/List/index.tsx
+++ b/src/screens/Tabs/Me/List/index.tsx
@@ -9,7 +9,7 @@ import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useEffect } from 'react'
import { useTranslation } from 'react-i18next'
-import { useQueryClient } from 'react-query'
+import { useQueryClient } from '@tanstack/react-query'
import * as DropdownMenu from 'zeego/dropdown-menu'
import { menuListAccounts, menuListDelete, menuListEdit } from './menus'
diff --git a/src/screens/Tabs/Me/List/menus.tsx b/src/screens/Tabs/Me/List/menus.tsx
index aaccaf6b..7217cad2 100644
--- a/src/screens/Tabs/Me/List/menus.tsx
+++ b/src/screens/Tabs/Me/List/menus.tsx
@@ -1,7 +1,7 @@
import navigationRef from '@helpers/navigationRef'
import i18next from 'i18next'
import { Alert } from 'react-native'
-import { UseMutationResult } from 'react-query'
+import { UseMutationResult } from '@tanstack/react-query'
export const menuListAccounts = ({ params }: { params: Mastodon.List }) => ({
key: 'list-accounts',
@@ -32,7 +32,7 @@ export const menuListDelete = ({
key: 'list-delete',
onSelect: () =>
Alert.alert(
- i18next.t('screenTabs:me.listDelete.confirm.title', { list: params.title.slice(0, 6) }),
+ i18next.t('screenTabs:me.listDelete.confirm.title', { list: params.title.slice(0, 20) }),
i18next.t('screenTabs:me.listDelete.confirm.message'),
[
{
diff --git a/src/screens/Tabs/Me/Profile.tsx b/src/screens/Tabs/Me/Profile.tsx
index 1e5ca7d7..f2588a33 100644
--- a/src/screens/Tabs/Me/Profile.tsx
+++ b/src/screens/Tabs/Me/Profile.tsx
@@ -1,10 +1,7 @@
import { HeaderCenter, HeaderLeft } from '@components/Header'
import { Message } from '@components/Message'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
-import {
- TabMeProfileStackParamList,
- TabMeStackScreenProps
-} from '@utils/navigation/navigators'
+import { TabMeProfileStackParamList, TabMeStackScreenProps } from '@utils/navigation/navigators'
import React, { useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { KeyboardAvoidingView, Platform } from 'react-native'
@@ -16,9 +13,7 @@ import TabMeProfileRoot from './Profile/Root'
const Stack = createNativeStackNavigator()
-const TabMeProfile: React.FC> = ({
- navigation
-}) => {
+const TabMeProfile: React.FC> = ({ navigation }) => {
const { t } = useTranslation('screenTabs')
const messageRef = useRef(null)
@@ -32,82 +27,37 @@ const TabMeProfile: React.FC> = ({
name='Tab-Me-Profile-Root'
options={{
title: t('me.stacks.profile.name'),
- ...(Platform.OS === 'android' && {
- headerCenter: () => (
-
- )
- }),
headerLeft: () => (
- navigation.goBack()}
- />
+ navigation.goBack()} />
)
}}
>
{({ route, navigation }) => (
-
+
)}
(
-
- )
- })
- }}
+ options={{ title: t('me.stacks.profileName.name') }}
>
{({ route, navigation }) => (
-
+
)}
(
-
- )
- })
- }}
+ options={{ title: t('me.stacks.profileNote.name') }}
>
{({ route, navigation }) => (
-
+
)}
(
-
- )
- })
- }}
+ options={{ title: t('me.stacks.profileFields.name') }}
>
{({ route, navigation }) => (
-
+
)}
diff --git a/src/screens/Tabs/Me/Profile/Fields.tsx b/src/screens/Tabs/Me/Profile/Fields.tsx
index 6f7a78bf..e461c7b6 100644
--- a/src/screens/Tabs/Me/Profile/Fields.tsx
+++ b/src/screens/Tabs/Me/Profile/Fields.tsx
@@ -79,7 +79,7 @@ const TabMeProfileFields: React.FC<
navigation
}) => {
const { theme } = useTheme()
- const { t, i18n } = useTranslation('screenTabs')
+ const { t } = useTranslation('screenTabs')
const { mutateAsync, status } = useProfileMutation()
const allProps: EmojisState['inputProps'] = []
@@ -144,7 +144,7 @@ const TabMeProfileFields: React.FC<
/>
)
})
- }, [theme, i18n.language, dirty, status, allProps.map(p => p.value)])
+ }, [theme, dirty, status, allProps.map(p => p.value)])
return (
diff --git a/src/screens/Tabs/Me/Profile/Name.tsx b/src/screens/Tabs/Me/Profile/Name.tsx
index 81dce1d7..c280d57b 100644
--- a/src/screens/Tabs/Me/Profile/Name.tsx
+++ b/src/screens/Tabs/Me/Profile/Name.tsx
@@ -23,7 +23,7 @@ const TabMeProfileName: React.FC<
navigation
}) => {
const { theme } = useTheme()
- const { t, i18n } = useTranslation('screenTabs')
+ const { t } = useTranslation('screenTabs')
const { mutateAsync, status } = useProfileMutation()
const [value, setValue] = useState(display_name)
@@ -90,7 +90,7 @@ const TabMeProfileName: React.FC<
/>
)
})
- }, [theme, i18n.language, dirty, status, value])
+ }, [theme, dirty, status, value])
return (
diff --git a/src/screens/Tabs/Me/Profile/Note.tsx b/src/screens/Tabs/Me/Profile/Note.tsx
index 7fa08dbf..085315f2 100644
--- a/src/screens/Tabs/Me/Profile/Note.tsx
+++ b/src/screens/Tabs/Me/Profile/Note.tsx
@@ -23,7 +23,7 @@ const TabMeProfileNote: React.FC<
navigation
}) => {
const { theme } = useTheme()
- const { t, i18n } = useTranslation('screenTabs')
+ const { t } = useTranslation('screenTabs')
const { mutateAsync, status } = useProfileMutation()
const [notes, setNotes] = useState(note)
@@ -90,7 +90,7 @@ const TabMeProfileNote: React.FC<
/>
)
})
- }, [theme, i18n.language, dirty, status, notes])
+ }, [theme, dirty, status, notes])
return (
diff --git a/src/screens/Tabs/Me/Profile/Root.tsx b/src/screens/Tabs/Me/Profile/Root.tsx
index a4e48780..9034ba4d 100644
--- a/src/screens/Tabs/Me/Profile/Root.tsx
+++ b/src/screens/Tabs/Me/Profile/Root.tsx
@@ -21,7 +21,7 @@ const TabMeProfileRoot: React.FC<
const { showActionSheetWithOptions } = useActionSheet()
- const { data, isLoading } = useProfileQuery({})
+ const { data, isFetching } = useProfileQuery()
const { mutateAsync } = useProfileMutation()
const dispatch = useAppDispatch()
@@ -31,7 +31,7 @@ const TabMeProfileRoot: React.FC<
{
data &&
@@ -45,7 +45,7 @@ const TabMeProfileRoot: React.FC<
{
data &&
@@ -63,7 +63,7 @@ const TabMeProfileRoot: React.FC<
})
: undefined
}
- loading={isLoading}
+ loading={isFetching}
iconBack='ChevronRight'
onPress={() => {
navigation.navigate('Tab-Me-Profile-Fields', {
@@ -80,7 +80,7 @@ const TabMeProfileRoot: React.FC<
? t(`me.profile.root.visibility.options.${data?.source.privacy}`)
: undefined
}
- loading={isLoading}
+ loading={isFetching}
iconBack='ChevronRight'
onPress={() =>
showActionSheetWithOptions(
@@ -138,7 +138,7 @@ const TabMeProfileRoot: React.FC<
data: data?.source.sensitive === undefined ? true : !data.source.sensitive
}).then(() => dispatch(updateAccountPreferences()))
}
- loading={isLoading}
+ loading={isFetching}
/>
@@ -158,7 +158,7 @@ const TabMeProfileRoot: React.FC<
data: data?.locked === undefined ? true : !data.locked
})
}
- loading={isLoading}
+ loading={isFetching}
/>
diff --git a/src/screens/Tabs/Me/Profile/Root/AvatarHeader.tsx b/src/screens/Tabs/Me/Profile/Root/AvatarHeader.tsx
index f6879a2c..cd59591b 100644
--- a/src/screens/Tabs/Me/Profile/Root/AvatarHeader.tsx
+++ b/src/screens/Tabs/Me/Profile/Root/AvatarHeader.tsx
@@ -17,24 +17,21 @@ const ProfileAvatarHeader: React.FC = ({ type, messageRef }) => {
const { showActionSheetWithOptions } = useActionSheet()
- const query = useProfileQuery({})
+ const query = useProfileQuery()
const mutation = useProfileMutation()
return (
{
const image = await mediaSelector({
mediaType: 'photo',
maximum: 1,
showActionSheetWithOptions,
- resize:
- type === 'avatar'
- ? { width: 400, height: 400 }
- : { width: 1500, height: 500 }
+ resize: type === 'avatar' ? { width: 400, height: 400 } : { width: 1500, height: 500 }
})
if (image[0].uri) {
mutation.mutate({
diff --git a/src/screens/Tabs/Me/Push.tsx b/src/screens/Tabs/Me/Push.tsx
index 5d498b8b..7f76f70f 100644
--- a/src/screens/Tabs/Me/Push.tsx
+++ b/src/screens/Tabs/Me/Push.tsx
@@ -5,31 +5,37 @@ import CustomText from '@components/Text'
import browserPackage from '@helpers/browserPackage'
import { useAppDispatch } from '@root/store'
import { isDevelopment } from '@utils/checkEnvironment'
-import { getExpoToken } from '@utils/slices/appSlice'
+import { useAppsQuery } from '@utils/queryHooks/apps'
+import { useProfileQuery } from '@utils/queryHooks/profile'
+import { getExpoToken, retrieveExpoToken } from '@utils/slices/appSlice'
+import {
+ PUSH_ADMIN,
+ PUSH_DEFAULT,
+ setChannels,
+ usePushFeatures
+} from '@utils/slices/instances/push/utils'
import { updateInstancePush } from '@utils/slices/instances/updatePush'
import { updateInstancePushAlert } from '@utils/slices/instances/updatePushAlert'
import { updateInstancePushDecode } from '@utils/slices/instances/updatePushDecode'
-import {
- clearPushLoading,
- getInstanceAccount,
- getInstancePush,
- getInstanceUri
-} from '@utils/slices/instancesSlice'
+import { getInstance, getInstancePush } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import layoutAnimation from '@utils/styles/layoutAnimation'
import { useTheme } from '@utils/styles/ThemeManager'
import * as Notifications from 'expo-notifications'
import * as WebBrowser from 'expo-web-browser'
-import React, { useState, useEffect, useMemo } from 'react'
+import React, { useState, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
-import { AppState, Linking, ScrollView, View } from 'react-native'
+import { AppState, Linking, Platform, ScrollView, View } from 'react-native'
import { useSelector } from 'react-redux'
const TabMePush: React.FC = () => {
const { colors } = useTheme()
const { t } = useTranslation('screenTabs')
- const instanceAccount = useSelector(getInstanceAccount, (prev, next) => prev?.acct === next?.acct)
- const instanceUri = useSelector(getInstanceUri)
+
+ const instance = useSelector(getInstance)
+ const expoToken = useSelector(getExpoToken)
+
+ const appsQuery = useAppsQuery()
const dispatch = useAppDispatch()
const instancePush = useSelector(getInstancePush)
@@ -37,61 +43,79 @@ const TabMePush: React.FC = () => {
const [pushAvailable, setPushAvailable] = useState()
const [pushEnabled, setPushEnabled] = useState()
const [pushCanAskAgain, setPushCanAskAgain] = useState()
- const checkPush = async () => {
- const settings = await Notifications.getPermissionsAsync()
- layoutAnimation()
- setPushEnabled(settings.granted)
- setPushCanAskAgain(settings.canAskAgain)
- }
- const expoToken = useSelector(getExpoToken)
+
useEffect(() => {
- if (isDevelopment) {
- setPushAvailable(true)
- } else {
- setPushAvailable(!!expoToken)
+ const checkPush = async () => {
+ switch (Platform.OS) {
+ case 'ios':
+ const settings = await Notifications.getPermissionsAsync()
+ layoutAnimation()
+ setPushEnabled(settings.granted)
+ setPushCanAskAgain(settings.canAskAgain)
+ break
+ case 'android':
+ await setChannels(instance)
+ layoutAnimation()
+ dispatch(retrieveExpoToken())
+ break
+ }
+ }
+
+ if (appsQuery.data?.vapid_key) {
+ checkPush()
+
+ if (isDevelopment) {
+ setPushAvailable(true)
+ } else {
+ setPushAvailable(!!expoToken)
+ }
}
- checkPush()
const subscription = AppState.addEventListener('change', checkPush)
return () => {
subscription.remove()
}
- }, [])
+ }, [appsQuery.data?.vapid_key])
- useEffect(() => {
- dispatch(clearPushLoading())
- }, [])
+ const pushFeatures = usePushFeatures()
- const isLoading = instancePush?.global.loading || instancePush?.decode.loading
-
- const alerts = useMemo(() => {
- return instancePush?.alerts
- ? (
- ['follow', 'follow_request', 'favourite', 'reblog', 'mention', 'poll', 'status'] as [
- 'follow',
- 'follow_request',
- 'favourite',
- 'reblog',
- 'mention',
- 'poll',
- 'status'
- ]
- ).map(alert => (
+ const alerts = () =>
+ instancePush?.alerts
+ ? PUSH_DEFAULT(pushFeatures).map(alert => (
dispatch(
updateInstancePushAlert({
- changed: alert,
alerts: {
...instancePush?.alerts,
- [alert]: {
- ...instancePush?.alerts[alert],
- value: !instancePush?.alerts[alert].value
- }
+ [alert]: instancePush?.alerts[alert]
+ }
+ })
+ )
+ }
+ />
+ ))
+ : null
+
+ const profileQuery = useProfileQuery()
+ const adminAlerts = () =>
+ profileQuery.data?.role?.permissions
+ ? PUSH_ADMIN(pushFeatures, profileQuery.data?.role?.permissions).map(({ type }) => (
+
+ dispatch(
+ updateInstancePushAlert({
+ alerts: {
+ ...instancePush?.alerts,
+ [type]: instancePush?.alerts[type]
}
})
)
@@ -99,69 +123,94 @@ const TabMePush: React.FC = () => {
/>
))
: null
- }, [pushEnabled, instancePush?.global, instancePush?.alerts, isLoading])
return (
- {!!pushAvailable ? (
+ {!!appsQuery.data?.vapid_key ? (
<>
- {pushEnabled === false ? (
-
- {
- if (pushCanAskAgain) {
- const result = await Notifications.requestPermissionsAsync()
- setPushEnabled(result.granted)
- setPushCanAskAgain(result.canAskAgain)
- } else {
- Linking.openSettings()
+ {!!pushAvailable ? (
+ <>
+ {pushEnabled === false ? (
+
+ {
+ if (pushCanAskAgain) {
+ const result = await Notifications.requestPermissionsAsync()
+ setPushEnabled(result.granted)
+ setPushCanAskAgain(result.canAskAgain)
+ } else {
+ Linking.openSettings()
+ }
+ }}
+ />
+
+ ) : null}
+
+ dispatch(updateInstancePush(!instancePush?.global))}
+ />
+
+
+
+ dispatch(updateInstancePushDecode(!instancePush?.decode))
}
+ />
+
+ WebBrowser.openBrowserAsync('https://tooot.app/how-push-works', {
+ browserPackage: await browserPackage()
+ })
+ }
+ />
+
+
+
+ >
+ ) : (
+
+
+
-
- ) : null}
-
- dispatch(updateInstancePush(!instancePush?.global.value))}
- />
-
-
-
- dispatch(updateInstancePushDecode(!instancePush?.decode.value))
- }
- />
-
- WebBrowser.openBrowserAsync('https://tooot.app/how-push-works', {
- browserPackage: await browserPackage()
- })
- }
- />
-
- {alerts}
+ >
+ {t('me.push.notAvailable')}
+
+
+ )}
>
) : (
{
flex: 1,
minHeight: '100%',
justifyContent: 'center',
- alignItems: 'center'
+ alignItems: 'center',
+ paddingHorizontal: StyleConstants.Spacing.Global.PagePadding
}}
>
-
- {t('me.push.notAvailable')}
+
+ {t('me.push.missingServerKey.message')}
+
+
+ {t('me.push.missingServerKey.description')}
)}
diff --git a/src/screens/Tabs/Me/Root/Collections.tsx b/src/screens/Tabs/Me/Root/Collections.tsx
index 900be986..0988df92 100644
--- a/src/screens/Tabs/Me/Root/Collections.tsx
+++ b/src/screens/Tabs/Me/Root/Collections.tsx
@@ -3,7 +3,12 @@ import { useNavigation } from '@react-navigation/native'
import { useAppDispatch } from '@root/store'
import { useAnnouncementQuery } from '@utils/queryHooks/announcement'
import { useListsQuery } from '@utils/queryHooks/lists'
-import { getInstanceMePage, updateInstanceMePage } from '@utils/slices/instancesSlice'
+import { useFollowedTagsQuery } from '@utils/queryHooks/tags'
+import {
+ checkInstanceFeature,
+ getInstanceMePage,
+ updateInstanceMePage
+} from '@utils/slices/instancesSlice'
import { getInstancePush } from '@utils/slices/instancesSlice'
import React, { useEffect } from 'react'
import { useTranslation } from 'react-i18next'
@@ -16,44 +21,44 @@ const Collections: React.FC = () => {
const dispatch = useAppDispatch()
const mePage = useSelector(getInstanceMePage)
- const listsQuery = useListsQuery({
+ const canFollowTags = useSelector(checkInstanceFeature('follow_tags'))
+ useFollowedTagsQuery({
options: {
- notifyOnChangeProps: ['data']
+ enabled: canFollowTags,
+ onSuccess: data =>
+ dispatch(
+ updateInstanceMePage({
+ followedTags: { shown: !!data?.pages?.[0].body?.length }
+ })
+ )
}
})
- useEffect(() => {
- if (listsQuery.isSuccess) {
- dispatch(
- updateInstanceMePage({
- lists: { shown: listsQuery.data?.length ? true : false }
- })
- )
+ useListsQuery({
+ options: {
+ onSuccess: data =>
+ dispatch(
+ updateInstanceMePage({
+ lists: { shown: !!data?.length }
+ })
+ )
}
- }, [listsQuery.isSuccess, listsQuery.data?.length])
-
- const announcementsQuery = useAnnouncementQuery({
+ })
+ useAnnouncementQuery({
showAll: true,
options: {
- notifyOnChangeProps: ['data']
+ onSuccess: data =>
+ dispatch(
+ updateInstanceMePage({
+ announcements: {
+ shown: !!data?.length ? true : false,
+ unread: data?.filter(announcement => !announcement.read).length
+ }
+ })
+ )
}
})
- useEffect(() => {
- if (announcementsQuery.data) {
- dispatch(
- updateInstanceMePage({
- announcements: {
- shown: announcementsQuery.data.length ? true : false,
- unread: announcementsQuery.data.filter(announcement => !announcement.read).length
- }
- })
- )
- }
- }, [announcementsQuery.data])
- const instancePush = useSelector(
- getInstancePush,
- (prev, next) => prev?.global.value === next?.global.value
- )
+ const instancePush = useSelector(getInstancePush, (prev, next) => prev?.global === next?.global)
return (
@@ -83,6 +88,14 @@ const Collections: React.FC = () => {
onPress={() => navigation.navigate('Tab-Me-List-List')}
/>
) : null}
+ {mePage.followedTags.shown ? (
+ navigation.navigate('Tab-Me-FollowedTags')}
+ />
+ ) : null}
{mePage.announcements.shown ? (
{
iconFront={instancePush ? 'Bell' : 'BellOff'}
iconBack='ChevronRight'
title={t('me.stacks.push.name')}
- content={
- instancePush.global.value
- ? t('me.root.push.content.enabled')
- : t('me.root.push.content.disabled')
- }
+ content={t('me.root.push.content', { context: instancePush.global.toString() })}
onPress={() => navigation.navigate('Tab-Me-Push')}
/>
diff --git a/src/screens/Tabs/Me/Root/Logout.tsx b/src/screens/Tabs/Me/Root/Logout.tsx
index a25f7bb3..502a6387 100644
--- a/src/screens/Tabs/Me/Root/Logout.tsx
+++ b/src/screens/Tabs/Me/Root/Logout.tsx
@@ -7,7 +7,7 @@ import { StyleConstants } from '@utils/styles/constants'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { Alert } from 'react-native'
-import { useQueryClient } from 'react-query'
+import { useQueryClient } from '@tanstack/react-query'
import { useSelector } from 'react-redux'
const Logout: React.FC = () => {
diff --git a/src/screens/Tabs/Me/Settings/Tooot.tsx b/src/screens/Tabs/Me/Settings/Tooot.tsx
index a6fcf735..a8c3ef05 100644
--- a/src/screens/Tabs/Me/Settings/Tooot.tsx
+++ b/src/screens/Tabs/Me/Settings/Tooot.tsx
@@ -4,13 +4,11 @@ import { useNavigation } from '@react-navigation/native'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import * as Linking from 'expo-linking'
-import * as StoreReview from 'expo-store-review'
import * as WebBrowser from 'expo-web-browser'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux'
import { getInstanceActive, getInstanceVersion } from '@utils/slices/instancesSlice'
-import { isDevelopment, isRelease } from '@utils/checkEnvironment'
import { Platform } from 'react-native'
import Constants from 'expo-constants'
import { getExpoToken } from '@utils/slices/appSlice'
@@ -27,6 +25,12 @@ const SettingsTooot: React.FC = () => {
return (
+ }
+ iconBack='ChevronRight'
+ onPress={() => Linking.openURL('https://www.buymeacoffee.com/xmflsct')}
+ />
{
iconBack='ChevronRight'
onPress={() => Linking.openURL('https://feedback.tooot.app/feature-requests')}
/>
- }
- iconBack='ChevronRight'
- onPress={() => Linking.openURL('https://www.buymeacoffee.com/xmflsct')}
- />
- {isDevelopment || isRelease ? (
- }
- iconBack='ChevronRight'
- onPress={() => StoreReview?.isAvailableAsync().then(() => StoreReview?.requestReview())}
- />
- ) : null}
}
diff --git a/src/screens/Tabs/Me/SettingsLanguage.tsx b/src/screens/Tabs/Me/SettingsLanguage.tsx
index 0e9cd820..ee87aa16 100644
--- a/src/screens/Tabs/Me/SettingsLanguage.tsx
+++ b/src/screens/Tabs/Me/SettingsLanguage.tsx
@@ -1,20 +1,20 @@
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 androidDefaults from '@utils/slices/instances/push/androidDefaults'
+import { setChannels } from '@utils/slices/instances/push/utils'
import { getInstances } from '@utils/slices/instancesSlice'
import { changeLanguage } from '@utils/slices/settingsSlice'
-import * as Notifications from 'expo-notifications'
+import { StyleConstants } from '@utils/styles/constants'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { FlatList, Platform } from 'react-native'
import { useDispatch, useSelector } from 'react-redux'
-const TabMeSettingsLanguage: React.FC<
- TabMeStackScreenProps<'Tab-Me-Settings-Language'>
-> = ({ navigation }) => {
- const { i18n, t } = useTranslation('screenTabs')
+const TabMeSettingsLanguage: React.FC> = ({
+ navigation
+}) => {
+ const { i18n } = useTranslation('screenTabs')
const languages = Object.entries(LOCALES)
const instances = useSelector(getInstances)
const dispatch = useDispatch()
@@ -27,67 +27,28 @@ const TabMeSettingsLanguage: React.FC<
// Update Android notification channel language
if (Platform.OS === 'android') {
- instances.forEach(instance => {
- const accountFull = `@${instance.account.acct}@${instance.uri}`
- if (instance.push.decode.value === false) {
- Notifications.setNotificationChannelAsync(`${accountFull}_default`, {
- groupId: accountFull,
- name: t('me.push.default.heading'),
- ...androidDefaults
- })
- } else {
- Notifications.setNotificationChannelAsync(`${accountFull}_follow`, {
- groupId: accountFull,
- name: t('me.push.follow.heading'),
- ...androidDefaults
- })
- Notifications.setNotificationChannelAsync(
- `${accountFull}_favourite`,
- {
- groupId: accountFull,
- name: t('me.push.favourite.heading'),
- ...androidDefaults
- }
- )
- Notifications.setNotificationChannelAsync(`${accountFull}_reblog`, {
- groupId: accountFull,
- name: t('me.push.reblog.heading'),
- ...androidDefaults
- })
- Notifications.setNotificationChannelAsync(`${accountFull}_mention`, {
- groupId: accountFull,
- name: t('me.push.mention.heading'),
- ...androidDefaults
- })
- Notifications.setNotificationChannelAsync(`${accountFull}_poll`, {
- groupId: accountFull,
- name: t('me.push.poll.heading'),
- ...androidDefaults
- })
- }
- })
+ instances.forEach(setChannels)
}
navigation.pop(1)
}
return (
-
- {
- return (
- item[0] !== i18n.language && change(item[0])}
- />
- )
- }}
- />
-
+ {
+ return (
+ item[0] !== i18n.language && change(item[0])}
+ />
+ )
+ }}
+ />
)
}
diff --git a/src/screens/Tabs/Me/index.tsx b/src/screens/Tabs/Me/index.tsx
new file mode 100644
index 00000000..b42e9ee7
--- /dev/null
+++ b/src/screens/Tabs/Me/index.tsx
@@ -0,0 +1,159 @@
+import { HeaderLeft } from '@components/Header'
+import { createNativeStackNavigator } from '@react-navigation/native-stack'
+import { TabMeStackParamList } from '@utils/navigation/navigators'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import TabMeBookmarks from './Bookmarks'
+import TabMeConversations from './Cconversations'
+import TabMeFavourites from './Favourites'
+import TabMeFollowedTags from './FollowedTags'
+import TabMeList from './List'
+import TabMeListAccounts from './List/Accounts'
+import TabMeListEdit from './List/Edit'
+import TabMeListList from './List/List'
+import TabMeProfile from './Profile'
+import TabMePush from './Push'
+import TabMeRoot from './Root'
+import TabMeSettings from './Settings'
+import TabMeSettingsFontsize from './SettingsFontsize'
+import TabMeSettingsLanguage from './SettingsLanguage'
+import TabMeSwitch from './Switch'
+import TabShared from '../Shared'
+
+const Stack = createNativeStackNavigator()
+
+const TabMe: React.FC = () => {
+ const { t } = useTranslation('screenTabs')
+
+ return (
+
+
+ ({
+ title: t('me.stacks.bookmarks.name'),
+ headerLeft: () => navigation.pop(1)} />
+ })}
+ />
+ ({
+ title: t('me.stacks.conversations.name'),
+ headerLeft: () => navigation.pop(1)} />
+ })}
+ />
+ ({
+ title: t('me.stacks.favourites.name'),
+ headerLeft: () => navigation.pop(1)} />
+ })}
+ />
+ ({
+ title: t('me.stacks.followedTags.name'),
+ headerLeft: () => navigation.pop(1)} />
+ })}
+ />
+ ({
+ title: t('me.stacks.list.name', { list: route.params.title }),
+ headerLeft: () => navigation.pop(1)} />
+ })}
+ />
+ ({
+ title: t('me.stacks.listAccounts.name', { list: params.title }),
+ headerLeft: () => navigation.pop(1)} />
+ })}
+ />
+
+ ({
+ title: t('me.stacks.lists.name'),
+ headerLeft: () => navigation.pop(1)} />
+ })}
+ />
+
+ ({
+ title: t('me.stacks.push.name'),
+ headerLeft: () => navigation.goBack()} />
+ })}
+ />
+ ({
+ title: t('me.stacks.settings.name'),
+ headerLeft: () => navigation.pop(1)} />
+ })}
+ />
+ ({
+ title: t('me.stacks.fontSize.name'),
+ headerLeft: () => navigation.pop(1)} />
+ })}
+ />
+ ({
+ title: t('me.stacks.language.name'),
+ headerLeft: () => navigation.pop(1)} />
+ })}
+ />
+ ({
+ presentation: 'modal',
+ headerShown: true,
+ title: t('me.stacks.switch.name'),
+ headerLeft: () => navigation.goBack()} />
+ })}
+ />
+
+ {TabShared({ Stack })}
+
+ )
+}
+
+export default TabMe
diff --git a/src/screens/Tabs/Notifications.tsx b/src/screens/Tabs/Notifications.tsx
deleted file mode 100644
index c5f7cdeb..00000000
--- a/src/screens/Tabs/Notifications.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-import { HeaderCenter, HeaderRight } from '@components/Header'
-import Timeline from '@components/Timeline'
-import TimelineNotifications from '@components/Timeline/Notifications'
-import navigationRef from '@helpers/navigationRef'
-import { createNativeStackNavigator } from '@react-navigation/native-stack'
-import { TabNotificationsStackParamList } from '@utils/navigation/navigators'
-import usePopToTop from '@utils/navigation/usePopToTop'
-import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
-import React, { useCallback, useMemo } from 'react'
-import { useTranslation } from 'react-i18next'
-import { Platform } from 'react-native'
-import TabShared from './Shared'
-
-const Stack = createNativeStackNavigator()
-
-const TabNotifications = React.memo(
- () => {
- const { t, i18n } = useTranslation('screenTabs')
-
- const screenOptionsRoot = useMemo(
- () => ({
- title: t('tabs.notifications.name'),
- ...(Platform.OS === 'android' && {
- headerCenter: () =>
- }),
- headerRight: () => (
-
- navigationRef.navigate('Screen-Actions', {
- type: 'notifications_filter'
- })
- }
- />
- )
- }),
- [i18n.language]
- )
-
- const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Notifications' }]
- const children = useCallback(
- () => (
- (
-
- )
- }}
- />
- ),
- []
- )
-
- usePopToTop()
-
- return (
-
-
- {TabShared({ Stack })}
-
- )
- },
- () => true
-)
-
-export default TabNotifications
diff --git a/src/screens/Tabs/Notifications/Filters.tsx b/src/screens/Tabs/Notifications/Filters.tsx
new file mode 100644
index 00000000..f8fa7f54
--- /dev/null
+++ b/src/screens/Tabs/Notifications/Filters.tsx
@@ -0,0 +1,102 @@
+import { HeaderLeft, HeaderRight } from '@components/Header'
+import { MenuContainer, MenuRow } from '@components/Menu'
+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 {
+ getInstanceNotificationsFilter,
+ updateInstanceNotificationsFilter
+} from '@utils/slices/instancesSlice'
+import { isEqual } from 'lodash'
+import React, { useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { Alert } from 'react-native'
+import { ScrollView } from 'react-native-gesture-handler'
+import { useSelector } from 'react-redux'
+
+const TabNotificationsFilters: React.FC<
+ TabNotificationsStackScreenProps<'Tab-Notifications-Filters'>
+> = ({ navigation }) => {
+ const { t } = useTranslation('screenTabs')
+
+ const pushFeatures = usePushFeatures()
+
+ const dispatch = useAppDispatch()
+
+ const instanceNotificationsFilter = useSelector(getInstanceNotificationsFilter)
+ const [filters, setFilters] = useState(instanceNotificationsFilter)
+
+ const queryClient = useQueryClient()
+ useEffect(() => {
+ const changed = !isEqual(instanceNotificationsFilter, filters)
+ navigation.setOptions({
+ title: t('notifications.filters.title'),
+ headerLeft: () => (
+ {
+ if (changed) {
+ Alert.alert(t('common:discard.title'), t('common:discard.message'), [
+ {
+ text: t('common:buttons.discard'),
+ style: 'destructive',
+ onPress: () => navigation.goBack()
+ },
+ {
+ text: t('common:buttons.cancel'),
+ style: 'default'
+ }
+ ])
+ } else {
+ navigation.goBack()
+ }
+ }}
+ />
+ ),
+ headerRight: () => (
+ {
+ if (changed) {
+ dispatch(updateInstanceNotificationsFilter(filters))
+ const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Notifications' }]
+ queryClient.invalidateQueries({ queryKey })
+ }
+ navigation.goBack()
+ }}
+ />
+ )
+ })
+ }, [filters])
+
+ const profileQuery = useProfileQuery()
+
+ return (
+
+
+ {PUSH_DEFAULT(pushFeatures).map((type, index) => (
+ setFilters({ ...filters, [type]: !filters[type] })}
+ />
+ ))}
+ {PUSH_ADMIN(pushFeatures, profileQuery.data?.role?.permissions).map(({ type }) => (
+ setFilters({ ...filters, [type]: !filters[type] })}
+ />
+ ))}
+
+
+ )
+}
+
+export default TabNotificationsFilters
diff --git a/src/screens/Tabs/Notifications/index.tsx b/src/screens/Tabs/Notifications/index.tsx
new file mode 100644
index 00000000..6dfbfcbf
--- /dev/null
+++ b/src/screens/Tabs/Notifications/index.tsx
@@ -0,0 +1,61 @@
+import { HeaderRight } from '@components/Header'
+import Timeline from '@components/Timeline'
+import TimelineNotifications from '@components/Timeline/Notifications'
+import { createNativeStackNavigator } from '@react-navigation/native-stack'
+import { ScreenTabsScreenProps, TabNotificationsStackParamList } from '@utils/navigation/navigators'
+import usePopToTop from '@utils/navigation/usePopToTop'
+import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
+import React from 'react'
+import { useTranslation } from 'react-i18next'
+import TabShared from '../Shared'
+import TabNotificationsFilters from './Filters'
+
+const Stack = createNativeStackNavigator()
+
+const Root = () => {
+ const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Notifications' }]
+ return (
+
+ }}
+ />
+ )
+}
+
+const TabNotifications = ({ navigation }: ScreenTabsScreenProps<'Tab-Notifications'>) => {
+ const { t } = useTranslation('screenTabs')
+
+ usePopToTop()
+
+ return (
+
+ (
+
+ navigation.navigate('Tab-Notifications', { screen: 'Tab-Notifications-Filters' })
+ }
+ />
+ )
+ }}
+ />
+
+ {TabShared({ Stack })}
+
+ )
+}
+
+export default TabNotifications
diff --git a/src/screens/Tabs/Public.tsx b/src/screens/Tabs/Public.tsx
deleted file mode 100644
index 8865623e..00000000
--- a/src/screens/Tabs/Public.tsx
+++ /dev/null
@@ -1,110 +0,0 @@
-import { HeaderRight } from '@components/Header'
-import Timeline from '@components/Timeline'
-import TimelineDefault from '@components/Timeline/Default'
-import SegmentedControl from '@react-native-community/segmented-control'
-import { createNativeStackNavigator } from '@react-navigation/native-stack'
-import { ScreenTabsScreenProps, TabPublicStackParamList } from '@utils/navigation/navigators'
-import usePopToTop from '@utils/navigation/usePopToTop'
-import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
-import { useTheme } from '@utils/styles/ThemeManager'
-import React, { useCallback, useMemo, useState } from 'react'
-import { useTranslation } from 'react-i18next'
-import { Dimensions } from 'react-native'
-import { TabView } from 'react-native-tab-view'
-import TabShared from './Shared'
-
-const Stack = createNativeStackNavigator()
-
-const TabPublic = React.memo(
- ({ navigation }: ScreenTabsScreenProps<'Tab-Public'>) => {
- const { t, i18n } = useTranslation('screenTabs')
- const { mode, theme } = useTheme()
-
- const [segment, setSegment] = useState(0)
- const pages: {
- title: string
- key: Extract
- }[] = [
- {
- title: t('tabs.public.segments.left'),
- key: 'LocalPublic'
- },
- {
- title: t('tabs.public.segments.right'),
- key: 'Local'
- }
- ]
- const screenOptionsRoot = useMemo(
- () => ({
- headerTitle: () => (
- p.title)}
- selectedIndex={segment}
- onChange={({ nativeEvent }) => setSegment(nativeEvent.selectedSegmentIndex)}
- style={{ flexBasis: '65%' }}
- />
- ),
- headerRight: () => (
- navigation.navigate('Tab-Public', { screen: 'Tab-Shared-Search' })}
- />
- )
- }),
- [theme, segment, i18n.language]
- )
-
- const routes = pages.map(p => ({ key: p.key }))
-
- const renderScene = useCallback(
- ({
- route: { key: page }
- }: {
- route: {
- key: Extract
- }
- }) => {
- const queryKey: QueryKeyTimeline = ['Timeline', { page }]
- return (
-
- }}
- />
- )
- },
- []
- )
- const children = useCallback(
- () => (
- null}
- onIndexChange={index => setSegment(index)}
- navigationState={{ index: segment, routes }}
- initialLayout={{ width: Dimensions.get('screen').width }}
- />
- ),
- [segment]
- )
-
- usePopToTop()
-
- return (
-
-
- {TabShared({ Stack })}
-
- )
- },
- () => true
-)
-
-export default TabPublic
diff --git a/src/screens/Tabs/Public/Root.tsx b/src/screens/Tabs/Public/Root.tsx
new file mode 100644
index 00000000..c1c07284
--- /dev/null
+++ b/src/screens/Tabs/Public/Root.tsx
@@ -0,0 +1,96 @@
+import { HeaderRight } from '@components/Header'
+import Timeline from '@components/Timeline'
+import TimelineDefault from '@components/Timeline/Default'
+import SegmentedControl from '@react-native-community/segmented-control'
+import { NativeStackScreenProps } from '@react-navigation/native-stack'
+import { useAppDispatch } from '@root/store'
+import { ContextsLatest } from '@utils/migrations/contexts/migration'
+import { TabPublicStackParamList } from '@utils/navigation/navigators'
+import usePopToTop from '@utils/navigation/usePopToTop'
+import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
+import { getPreviousSegment, updatePreviousSegment } from '@utils/slices/contextsSlice'
+import { useTheme } from '@utils/styles/ThemeManager'
+import { useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { Dimensions } from 'react-native'
+import { SceneMap, TabView } from 'react-native-tab-view'
+import { useSelector } from 'react-redux'
+
+const Route = ({ route: { key: page } }: { route: any }) => {
+ const queryKey: QueryKeyTimeline = ['Timeline', { page }]
+ return (
+
+ }}
+ />
+ )
+}
+
+const renderScene = SceneMap({
+ Local: Route,
+ LocalPublic: Route,
+ Trending: Route
+})
+
+const Root: React.FC> = ({
+ navigation
+}) => {
+ const { mode } = useTheme()
+ const { t } = useTranslation('screenTabs')
+
+ const dispatch = useAppDispatch()
+ const previousSegment = useSelector(getPreviousSegment, () => true)
+ const segments: ContextsLatest['previousSegment'][] = ['Local', 'LocalPublic', 'Trending']
+ const [segment, setSegment] = useState(
+ segments.findIndex(segment => segment === previousSegment)
+ )
+ const [routes] = useState([
+ { key: 'Local', title: t('tabs.public.segments.local') },
+ { key: 'LocalPublic', title: t('tabs.public.segments.federated') },
+ { key: 'Trending', title: t('tabs.public.segments.trending') }
+ ])
+
+ useEffect(() => {
+ navigation.setOptions({
+ headerTitle: () => (
+ title)}
+ selectedIndex={segment}
+ onChange={({ nativeEvent }) => {
+ setSegment(nativeEvent.selectedSegmentIndex)
+ dispatch(updatePreviousSegment(segments[nativeEvent.selectedSegmentIndex]))
+ }}
+ style={{ flexBasis: '65%' }}
+ />
+ ),
+ headerRight: () => (
+ navigation.navigate('Tab-Shared-Search')}
+ />
+ )
+ })
+ }, [mode, segment])
+
+ usePopToTop()
+
+ return (
+ null}
+ onIndexChange={index => setSegment(index)}
+ navigationState={{ index: segment, routes }}
+ initialLayout={{ width: Dimensions.get('screen').width }}
+ />
+ )
+}
+
+export default Root
diff --git a/src/screens/Tabs/Public/index.tsx b/src/screens/Tabs/Public/index.tsx
new file mode 100644
index 00000000..f857db98
--- /dev/null
+++ b/src/screens/Tabs/Public/index.tsx
@@ -0,0 +1,18 @@
+import { createNativeStackNavigator } from '@react-navigation/native-stack'
+import { TabPublicStackParamList } from '@utils/navigation/navigators'
+import React from 'react'
+import TabShared from '../Shared'
+import Root from './Root'
+
+const Stack = createNativeStackNavigator()
+
+const TabPublic: React.FC = () => {
+ return (
+
+
+ {TabShared({ Stack })}
+
+ )
+}
+
+export default TabPublic
diff --git a/src/screens/Tabs/Shared/Account.tsx b/src/screens/Tabs/Shared/Account.tsx
index 635fcddb..c2becf37 100644
--- a/src/screens/Tabs/Shared/Account.tsx
+++ b/src/screens/Tabs/Shared/Account.tsx
@@ -13,7 +13,7 @@ import React, { useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Text, View } from 'react-native'
import { useSharedValue } from 'react-native-reanimated'
-import { useIsFetching } from 'react-query'
+import { useIsFetching } from '@tanstack/react-query'
import * as DropdownMenu from 'zeego/dropdown-menu'
import AccountAttachments from './Account/Attachments'
import AccountHeader from './Account/Header'
@@ -26,7 +26,7 @@ const TabSharedAccount: React.FC
params: { account }
}
}) => {
- const { t, i18n } = useTranslation('screenTabs')
+ const { t } = useTranslation('screenTabs')
const { colors, mode } = useTheme()
const mShare = menuShare({ type: 'account', url: account.url })
@@ -89,8 +89,9 @@ const TabSharedAccount: React.FC
const [queryKey, setQueryKey] = useState([
'Timeline',
- { page: 'Account_Default', account: account.id }
+ { page: 'Account', account: account.id, exclude_reblogs: true, only_media: false }
])
+ const page = queryKey[1]
const isFetchingTimeline = useIsFetching(queryKey)
const fetchedTimeline = useRef(false)
useEffect(() => {
@@ -113,14 +114,32 @@ const TabSharedAccount: React.FC
{
switch (nativeEvent.selectedSegmentIndex) {
case 0:
- setQueryKey([queryKey[0], { ...queryKey[1], page: 'Account_Default' }])
+ setQueryKey([
+ queryKey[0],
+ {
+ ...page,
+ page: 'Account',
+ account: account.id,
+ exclude_reblogs: true,
+ only_media: false
+ }
+ ])
break
case 1:
- setQueryKey([queryKey[0], { ...queryKey[1], page: 'Account_All' }])
+ setQueryKey([
+ queryKey[0],
+ {
+ ...page,
+ page: 'Account',
+ account: account.id,
+ exclude_reblogs: false,
+ only_media: false
+ }
+ ])
break
}
}}
@@ -152,7 +171,7 @@ const TabSharedAccount: React.FC
) : null}
>
)
- }, [data, fetchedTimeline.current, queryKey[1].page, i18n.language, mode])
+ }, [data, fetchedTimeline.current, queryKey[1].page, mode])
return (
<>
diff --git a/src/screens/Tabs/Shared/Account/Attachments.tsx b/src/screens/Tabs/Shared/Account/Attachments.tsx
index dd6be7d7..64a98782 100644
--- a/src/screens/Tabs/Shared/Account/Attachments.tsx
+++ b/src/screens/Tabs/Shared/Account/Attachments.tsx
@@ -3,11 +3,11 @@ import Icon from '@components/Icon'
import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { TabLocalStackParamList } from '@utils/navigation/navigators'
-import { useTimelineQuery } from '@utils/queryHooks/timeline'
+import { QueryKeyTimeline, useTimelineQuery } from '@utils/queryHooks/timeline'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useCallback, useEffect } from 'react'
-import { Dimensions, ListRenderItem, Pressable, StyleSheet, View } from 'react-native'
+import { Dimensions, ListRenderItem, Pressable, View } from 'react-native'
import { FlatList } from 'react-native-gesture-handler'
import Animated, { useAnimatedStyle, withTiming } from 'react-native-reanimated'
@@ -15,117 +15,111 @@ export interface Props {
account: Mastodon.Account | undefined
}
-const AccountAttachments = React.memo(
- ({ account }: Props) => {
- const navigation = useNavigation>()
- const { colors } = useTheme()
+const AccountAttachments: React.FC = ({ account }) => {
+ if (!account) return null
- const DISPLAY_AMOUNT = 6
+ const navigation = useNavigation>()
+ const { colors } = useTheme()
- const width =
- (Dimensions.get('screen').width - StyleConstants.Spacing.Global.PagePadding * 2) / 4
+ const DISPLAY_AMOUNT = 6
- const queryKeyParams = {
- page: 'Account_Attachments' as 'Account_Attachments',
- account: account?.id
- }
- const { data, refetch } = useTimelineQuery({
- ...queryKeyParams,
- options: { enabled: false }
- })
- useEffect(() => {
- if (account?.id) {
- refetch()
- }
- }, [account])
+ const width = (Dimensions.get('screen').width - StyleConstants.Spacing.Global.PagePadding * 2) / 4
- const flattenData = data?.pages
- ? data.pages
- .flatMap(d => [...d.body])
- .filter(status => !(status as Mastodon.Status).sensitive)
- .splice(0, DISPLAY_AMOUNT)
- : []
-
- const renderItem = useCallback>(
- ({ item, index }) => {
- if (index === DISPLAY_AMOUNT - 1) {
- return (
- {
- account && navigation.push('Tab-Shared-Attachments', { account })
- }}
- children={
-
- }
- />
- }
- />
- )
- } else {
- return (
- navigation.push('Tab-Shared-Toot', { toot: item })}
- />
- )
- }
- },
- [account]
- )
-
- const styleContainer = useAnimatedStyle(() => {
- if (flattenData.length) {
- return {
- height: withTiming(width + StyleConstants.Spacing.Global.PagePadding * 2),
- paddingVertical: StyleConstants.Spacing.Global.PagePadding,
- borderTopWidth: 1,
- borderTopColor: colors.border
- }
- } else {
- return {}
- }
- }, [flattenData.length])
-
- return (
-
-
-
- )
- },
- (_, next) => next.account === undefined
-)
-
-const styles = StyleSheet.create({
- base: {
- flex: 1
+ const queryKeyParams: QueryKeyTimeline[1] = {
+ page: 'Account',
+ account: account.id,
+ exclude_reblogs: false,
+ only_media: true
}
-})
+ const { data, refetch } = useTimelineQuery({
+ ...queryKeyParams,
+ options: { enabled: false }
+ })
+ useEffect(() => {
+ if (account?.id) {
+ refetch()
+ }
+ }, [account])
+
+ const flattenData = data?.pages
+ ? data.pages
+ .flatMap(d => [...d.body])
+ .filter(status => !(status as Mastodon.Status).sensitive)
+ .splice(0, DISPLAY_AMOUNT)
+ : []
+
+ const renderItem = useCallback>(
+ ({ item, index }) => {
+ if (index === DISPLAY_AMOUNT - 1) {
+ return (
+ {
+ account && navigation.push('Tab-Shared-Attachments', { account })
+ }}
+ children={
+
+ }
+ />
+ }
+ />
+ )
+ } else {
+ return (
+ navigation.push('Tab-Shared-Toot', { toot: item })}
+ />
+ )
+ }
+ },
+ [account]
+ )
+
+ const styleContainer = useAnimatedStyle(() => {
+ if (flattenData.length) {
+ return {
+ height: withTiming(width + StyleConstants.Spacing.Global.PagePadding * 2),
+ paddingVertical: StyleConstants.Spacing.Global.PagePadding,
+ borderTopWidth: 1,
+ borderTopColor: colors.border
+ }
+ } else {
+ return {}
+ }
+ }, [flattenData.length])
+
+ return (
+
+
+
+ )
+}
export default AccountAttachments
diff --git a/src/screens/Tabs/Shared/Account/Information.tsx b/src/screens/Tabs/Shared/Account/Information.tsx
index 82b47204..24651ac7 100644
--- a/src/screens/Tabs/Shared/Account/Information.tsx
+++ b/src/screens/Tabs/Shared/Account/Information.tsx
@@ -28,10 +28,7 @@ const AccountInformation = React.memo(
(
-
+
)}
>
@@ -41,7 +38,7 @@ const AccountInformation = React.memo(
-
+
diff --git a/src/screens/Tabs/Shared/Account/Information/Account.tsx b/src/screens/Tabs/Shared/Account/Information/Account.tsx
index e2062c58..54d52c33 100644
--- a/src/screens/Tabs/Shared/Account/Information/Account.tsx
+++ b/src/screens/Tabs/Shared/Account/Information/Account.tsx
@@ -1,10 +1,7 @@
import Icon from '@components/Icon'
import CustomText from '@components/Text'
import { useRelationshipQuery } from '@utils/queryHooks/relationship'
-import {
- getInstanceAccount,
- getInstanceUri
-} from '@utils/slices/instancesSlice'
+import { getInstanceAccount, getInstanceUri } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React from 'react'
@@ -15,19 +12,12 @@ import { PlaceholderLine } from 'rn-placeholder'
export interface Props {
account: Mastodon.Account | undefined
- localInstance: boolean
}
-const AccountInformationAccount: React.FC = ({
- account,
- localInstance
-}) => {
+const AccountInformationAccount: React.FC = ({ account }) => {
const { t } = useTranslation('screenTabs')
const { colors } = useTheme()
- const instanceAccount = useSelector(
- getInstanceAccount,
- (prev, next) => prev?.acct === next?.acct
- )
+ const instanceAccount = useSelector(getInstanceAccount, (prev, next) => prev?.acct === next?.acct)
const instanceUri = useSelector(getInstanceUri)
const { data: relationship } = useRelationshipQuery({
@@ -35,6 +25,10 @@ const AccountInformationAccount: React.FC = ({
options: { enabled: account !== undefined }
})
+ const localInstance = account?.acct.includes('@')
+ ? account?.acct.includes(`@${instanceUri}`)
+ : true
+
if (account || (localInstance && instanceAccount)) {
return (
= ({
) : null}
- @{localInstance ? instanceAccount?.acct : account?.acct}
+ @{account?.acct}
{localInstance ? `@${instanceUri}` : null}
{relationship?.followed_by ? t('shared.account.followed_by') : null}
@@ -94,7 +88,4 @@ const AccountInformationAccount: React.FC = ({
}
}
-export default React.memo(
- AccountInformationAccount,
- (_, next) => next.account === undefined
-)
+export default AccountInformationAccount
diff --git a/src/screens/Tabs/Shared/Account/Information/Avatar.tsx b/src/screens/Tabs/Shared/Account/Information/Avatar.tsx
index 76003b07..956b9bda 100644
--- a/src/screens/Tabs/Shared/Account/Information/Avatar.tsx
+++ b/src/screens/Tabs/Shared/Account/Information/Avatar.tsx
@@ -3,9 +3,11 @@ import GracefullyImage from '@components/GracefullyImage'
import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { TabLocalStackParamList } from '@utils/navigation/navigators'
+import { getInstanceActive } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import React from 'react'
-import { Pressable, StyleSheet, View } from 'react-native'
+import { Pressable, View } from 'react-native'
+import { useSelector } from 'react-redux'
export interface Props {
account: Mastodon.Account | undefined
@@ -13,24 +15,25 @@ export interface Props {
edit?: boolean
}
-const AccountInformationAvatar: React.FC = ({
- account,
- myInfo,
- edit
-}) => {
- const navigation =
- useNavigation>()
+const AccountInformationAvatar: React.FC = ({ account, myInfo, edit }) => {
+ const navigation = useNavigation>()
+ useSelector(getInstanceActive)
return (
{
myInfo && account && navigation.push('Tab-Shared-Account', { account })
}}
- style={styles.base}
+ style={{
+ borderRadius: 8,
+ overflow: 'hidden',
+ width: StyleConstants.Avatar.L,
+ height: StyleConstants.Avatar.L
+ }}
>
{edit ? (
@@ -51,14 +54,4 @@ const AccountInformationAvatar: React.FC = ({
)
}
-const styles = StyleSheet.create({
- base: {
- borderRadius: 8,
- overflow: 'hidden',
- width: StyleConstants.Avatar.L,
- height: StyleConstants.Avatar.L
- },
- image: { flex: 1 }
-})
-
export default AccountInformationAvatar
diff --git a/src/screens/Tabs/Shared/Account/Information/Created.tsx b/src/screens/Tabs/Shared/Account/Information/Created.tsx
index 5bf688d7..4d4852d8 100644
--- a/src/screens/Tabs/Shared/Account/Information/Created.tsx
+++ b/src/screens/Tabs/Shared/Account/Information/Created.tsx
@@ -12,59 +12,53 @@ export interface Props {
hidden?: boolean
}
-const AccountInformationCreated = React.memo(
- ({ account, hidden = false }: Props) => {
- if (hidden) {
- return null
- }
+const AccountInformationCreated: React.FC = ({ account, hidden = false }) => {
+ if (hidden) {
+ return null
+ }
- const { i18n } = useTranslation()
- const { colors } = useTheme()
- const { t } = useTranslation('screenTabs')
+ const { i18n } = useTranslation()
+ const { colors } = useTheme()
+ const { t } = useTranslation('screenTabs')
- if (account) {
- return (
-
-
-
- {t('shared.account.created_at', {
- date: new Date(account.created_at || '').toLocaleDateString(
- i18n.language,
- {
- year: 'numeric',
- month: 'long',
- day: 'numeric'
- }
- )
- })}
-
-
- )
- } else {
- return (
-
+
- )
- }
- },
- (_, next) => next.account === undefined
-)
+
+ {t('shared.account.created_at', {
+ date: new Date(account.created_at || '').toLocaleDateString(i18n.language, {
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric'
+ })
+ })}
+
+
+ )
+ } else {
+ return (
+
+ )
+ }
+}
export default AccountInformationCreated
diff --git a/src/screens/Tabs/Shared/Account/Information/Fields.tsx b/src/screens/Tabs/Shared/Account/Information/Fields.tsx
index db0b12e8..ea55aa9a 100644
--- a/src/screens/Tabs/Shared/Account/Information/Fields.tsx
+++ b/src/screens/Tabs/Shared/Account/Information/Fields.tsx
@@ -10,53 +10,50 @@ export interface Props {
myInfo?: boolean
}
-const AccountInformationFields = React.memo(
- ({ account, myInfo }: Props) => {
- if (account?.suspended || myInfo || !account?.fields || account.fields.length === 0) {
- return null
- }
+const AccountInformationFields: React.FC = ({ account, myInfo }) => {
+ if (account?.suspended || myInfo || !account?.fields || account.fields.length === 0) {
+ return null
+ }
- const { colors } = useTheme()
+ const { colors } = useTheme()
- return (
-
- {account.fields.map((field, index) => (
-
-
-
+ {account.fields.map((field, index) => (
+
+
+
+ {field.verified_at ? (
+
- {field.verified_at ? (
-
- ) : null}
-
-
-
-
+ ) : null}
- ))}
-
- )
- },
- (_, next) => next.account === undefined
-)
+
+
+
+
+ ))}
+
+ )
+}
const styles = StyleSheet.create({
fields: {
diff --git a/src/screens/Tabs/Shared/Account/Information/Name.tsx b/src/screens/Tabs/Shared/Account/Information/Name.tsx
index 9dd8005c..0b6b51ba 100644
--- a/src/screens/Tabs/Shared/Account/Information/Name.tsx
+++ b/src/screens/Tabs/Shared/Account/Information/Name.tsx
@@ -66,4 +66,4 @@ const AccountInformationName: React.FC = ({ account }) => {
)
}
-export default React.memo(AccountInformationName, (_, next) => next.account === undefined)
+export default AccountInformationName
diff --git a/src/screens/Tabs/Shared/Account/Information/Note.tsx b/src/screens/Tabs/Shared/Account/Information/Note.tsx
index b1f4eda8..35f507c5 100644
--- a/src/screens/Tabs/Shared/Account/Information/Note.tsx
+++ b/src/screens/Tabs/Shared/Account/Information/Note.tsx
@@ -1,45 +1,35 @@
import { ParseHTML } from '@components/Parse'
import { StyleConstants } from '@utils/styles/constants'
-import React, { useState } from 'react'
-import { StyleSheet, View } from 'react-native'
+import React from 'react'
+import { View } from 'react-native'
export interface Props {
account: Mastodon.Account | undefined
myInfo?: boolean
}
-const AccountInformationNote = React.memo(
- ({ account, myInfo }: Props) => {
- const [note, setNote] = useState(account?.source?.note)
- if (
- account?.suspended ||
- myInfo ||
- !account?.note ||
- account.note.length === 0 ||
- account.note === '
'
- ) {
- return null
- }
-
- return (
-
-
-
- )
- },
- (_, next) => next.account === undefined
-)
-
-const styles = StyleSheet.create({
- note: {
- marginBottom: StyleConstants.Spacing.L
+const AccountInformationNote: React.FC = ({ account, myInfo }) => {
+ if (
+ account?.suspended ||
+ myInfo ||
+ !account?.note ||
+ account.note.length === 0 ||
+ account.note === '
'
+ ) {
+ return null
}
-})
+
+ return (
+
+
+
+ )
+}
export default AccountInformationNote
diff --git a/src/screens/Tabs/Shared/Account/Information/Stats.tsx b/src/screens/Tabs/Shared/Account/Information/Stats.tsx
index fe2c4e37..a9ff0751 100644
--- a/src/screens/Tabs/Shared/Account/Information/Stats.tsx
+++ b/src/screens/Tabs/Shared/Account/Information/Stats.tsx
@@ -53,7 +53,7 @@ const AccountInformationStats: React.FC = ({ account, myInfo }) => {
onPress={() =>
navigation.push('Tab-Shared-Users', {
reference: 'accounts',
- id: account.id,
+ account,
type: 'following',
count: account.following_count
})
@@ -77,7 +77,7 @@ const AccountInformationStats: React.FC = ({ account, myInfo }) => {
onPress={() =>
navigation.push('Tab-Shared-Users', {
reference: 'accounts',
- id: account.id,
+ account,
type: 'followers',
count: account.followers_count
})
diff --git a/src/screens/Tabs/Shared/AccountInLists.tsx b/src/screens/Tabs/Shared/AccountInLists.tsx
index 4e7d8041..f92a6c28 100644
--- a/src/screens/Tabs/Shared/AccountInLists.tsx
+++ b/src/screens/Tabs/Shared/AccountInLists.tsx
@@ -39,7 +39,7 @@ const TabSharedAccountInLists: React.FC<
})
}, [])
- const listsQuery = useListsQuery({})
+ const listsQuery = useListsQuery()
const accountInListsQuery = useAccountInListsQuery({ id: account.id })
const sections = [
@@ -48,8 +48,10 @@ const TabSharedAccountInLists: React.FC<
id: 'out',
title: t('shared.accountInLists.notInLists'),
data:
- listsQuery.data?.filter(
- ({ id }) => accountInListsQuery.data?.filter(d => d.id !== id).length
+ listsQuery.data?.filter(({ id }) =>
+ accountInListsQuery.data?.length
+ ? accountInListsQuery.data.filter(d => d.id !== id).length
+ : true
) || []
}
]
diff --git a/src/screens/Tabs/Shared/Attachments.tsx b/src/screens/Tabs/Shared/Attachments.tsx
index 948d2552..a4e75f03 100644
--- a/src/screens/Tabs/Shared/Attachments.tsx
+++ b/src/screens/Tabs/Shared/Attachments.tsx
@@ -44,7 +44,7 @@ const TabSharedAttachments: React.FC
const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Hashtag', hashtag }]
- const { theme } = useTheme()
const { t } = useTranslation('screenTabs')
const canFollowTags = useSelector(checkInstanceFeature('follow_tags'))
@@ -35,14 +34,16 @@ const TabSharedHashtag: React.FC
tag: hashtag,
options: { enabled: canFollowTags }
})
+ const queryClient = useQueryClient()
const mutation = useTagsMutation({
onSuccess: () => {
haptics('Success')
refetch()
+ const queryKeyFollowedTags: QueryKeyFollowedTags = ['FollowedTags']
+ queryClient.invalidateQueries({ queryKey: queryKeyFollowedTags })
},
onError: (err: any, { to }) => {
displayMessage({
- theme,
type: 'error',
message: t('common:message.error.message', {
function: to ? t('shared.hashtag.follow') : t('shared.hashtag.unfollow')
@@ -68,7 +69,7 @@ const TabSharedHashtag: React.FC
content={data?.following ? t('shared.hashtag.unfollow') : t('shared.hashtag.follow')}
onPress={() =>
typeof data?.following === 'boolean' &&
- mutation.mutate({ tag: hashtag, type: 'follow', to: !data.following })
+ mutation.mutate({ tag: hashtag, to: !data.following })
}
/>
)
diff --git a/src/screens/Tabs/Shared/History.tsx b/src/screens/Tabs/Shared/History.tsx
index fc9a9d3c..1c59cfd8 100644
--- a/src/screens/Tabs/Shared/History.tsx
+++ b/src/screens/Tabs/Shared/History.tsx
@@ -4,44 +4,86 @@ import { ParseEmojis } from '@components/Parse'
import ComponentSeparator from '@components/Separator'
import CustomText from '@components/Text'
import TimelineAttachment from '@components/Timeline/Shared/Attachment'
-import TimelineContent from '@components/Timeline/Shared/Content'
import StatusContext from '@components/Timeline/Shared/Context'
import HeaderSharedCreated from '@components/Timeline/Shared/HeaderShared/Created'
+import removeHTML from '@helpers/removeHTML'
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 React, { useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { FlatList, View } from 'react-native'
-const ContentView: React.FC<{ item: Mastodon.StatusHistory }> = ({ item }) => {
+const ContentView: React.FC<{
+ item: Mastodon.StatusHistory
+ prevItem?: Mastodon.StatusHistory
+}> = ({ 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)
+ )
+
return (
// @ts-ignore
-
-
- {item.poll?.options.map((option, index) => (
-
-
-
+
+ {changesSpoiler.length && changesSpoiler[0].count ? (
+
+ {changesSpoiler.map(({ value, added, removed }, index) => (
+
+ ))}
+
+ ) : null}
+
+ {changesContent.map(({ value, added, removed }, index) => (
+
-
-
-
+ ))}
+
+ {item.poll?.options.map((option, index) => (
+
+
+
+
+
+
+
-
- ))}
-
+ ))}
+
+
)
}
@@ -62,41 +104,18 @@ const TabSharedHistory: React.FC
})
}, [])
+ const dataReversed = data ? [...data].reverse() : []
+
return (
0
- ? data
- .slice(0)
- .reverse()
- .filter((_, index) => index !== 0)
- : []
- }
- renderItem={({ item }) => }
- ItemSeparatorComponent={() => (
-
+ style={{ flex: 1, minHeight: '100%' }}
+ data={dataReversed}
+ renderItem={({ item, index }) => (
+
)}
+ ItemSeparatorComponent={ComponentSeparator}
/>
)
-
- // return (
- //
- // {data && data.length > 0
- // ? data
- // .slice(0)
- // .reverse()
- // .map((d, i) =>
- // i !== 0 ? (
- //
- // ) : null
- // )
- // : null}
- //
- // )
}
export default TabSharedHistory
diff --git a/src/screens/Tabs/Shared/Search/Empty.tsx b/src/screens/Tabs/Shared/Search/Empty.tsx
index b43d3189..ae8e50a3 100644
--- a/src/screens/Tabs/Shared/Search/Empty.tsx
+++ b/src/screens/Tabs/Shared/Search/Empty.tsx
@@ -10,12 +10,12 @@ import { StyleSheet, TextInput, View } from 'react-native'
import { Circle } from 'react-native-animated-spinkit'
export interface Props {
- isLoading: boolean
+ isFetching: boolean
inputRef: React.RefObject
setSearchTerm: React.Dispatch>
}
-const SearchEmpty: React.FC = ({ isLoading, inputRef, setSearchTerm }) => {
+const SearchEmpty: React.FC = ({ isFetching, inputRef, setSearchTerm }) => {
const { colors } = useTheme()
const { t } = useTranslation('screenTabs')
@@ -23,7 +23,7 @@ const SearchEmpty: React.FC = ({ isLoading, inputRef, setSearchTerm }) =>
return (
- {isLoading ? (
+ {isFetching ? (
diff --git a/src/screens/Tabs/Shared/Search/index.tsx b/src/screens/Tabs/Shared/Search/index.tsx
index 2eee2d01..9c70098b 100644
--- a/src/screens/Tabs/Shared/Search/index.tsx
+++ b/src/screens/Tabs/Shared/Search/index.tsx
@@ -54,7 +54,11 @@ const TabSharedSearch: React.FC>
fontSize: StyleConstants.Font.Size.M,
flex: 1,
color: colors.primaryDefault,
- paddingLeft: StyleConstants.Spacing.XS
+ marginLeft: StyleConstants.Spacing.XS,
+ paddingLeft: StyleConstants.Spacing.XS,
+ paddingVertical: StyleConstants.Spacing.XS,
+ borderBottomColor: colors.border,
+ borderBottomWidth: 1
}}
autoFocus
onChangeText={debounce(
@@ -84,7 +88,7 @@ const TabSharedSearch: React.FC>
hashtags: t('shared.search.sections.hashtags'),
statuses: t('shared.search.sections.statuses')
}
- const { isLoading, data, refetch } = useSearchQuery<
+ const { isFetching, data, refetch } = useSearchQuery<
{
title: string
translation: string
@@ -138,7 +142,7 @@ const TabSharedSearch: React.FC>
}}
stickySectionHeadersEnabled
ListEmptyComponent={
-
+
}
keyboardShouldPersistTaps='always'
renderSectionHeader={({ section: { translation } }) => (
diff --git a/src/screens/Tabs/Shared/Toot.tsx b/src/screens/Tabs/Shared/Toot.tsx
index 196bccc5..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 { InfiniteQueryObserver, useQueryClient } from 'react-query'
+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,21 +93,92 @@ const TabSharedToot: React.FC> = ({
}
}
})
- }, [scrolled.current])
+ }, [scrolled.current, replyLevels.current])
return (
(
-
- ),
+ 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 })
diff --git a/src/screens/Tabs/Shared/Users.tsx b/src/screens/Tabs/Shared/Users.tsx
index d1a6fdf7..5183c3c6 100644
--- a/src/screens/Tabs/Shared/Users.tsx
+++ b/src/screens/Tabs/Shared/Users.tsx
@@ -1,16 +1,25 @@
+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 React, { useCallback, useEffect } from 'react'
+import { StyleConstants } from '@utils/styles/constants'
+import { useTheme } from '@utils/styles/ThemeManager'
+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> = ({
navigation,
route: { params }
}) => {
+ const { colors } = useTheme()
const { t } = useTranslation('screenTabs')
useEffect(() => {
navigation.setOptions({
@@ -20,12 +29,12 @@ 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 =>
- firstPage.links?.prev && { since_id: firstPage.links.next },
- getNextPageParam: lastPage => lastPage.links?.next && { max_id: lastPage.links.next }
+ firstPage.links?.prev?.id && { min_id: firstPage.links.prev.id },
+ getNextPageParam: lastPage => lastPage.links?.next?.id && { max_id: lastPage.links.next.id }
}
})
const flattenData = data?.pages ? data.pages.flatMap(page => [...page.body]) : []
@@ -35,21 +44,96 @@ 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
}}
+ ListHeaderComponent={
+ data?.pages[0]?.warnIncomplete === true ? (
+
+
+
+ {t('shared.users.resultIncomplete')}
+
+
+ ) : null
+ }
/>
)
}
diff --git a/src/screens/Tabs/Shared/index.tsx b/src/screens/Tabs/Shared/index.tsx
index bf07e7fe..dfc67d4a 100644
--- a/src/screens/Tabs/Shared/index.tsx
+++ b/src/screens/Tabs/Shared/index.tsx
@@ -6,15 +6,10 @@ import TabSharedHistory from '@screens/Tabs/Shared/History'
import TabSharedSearch from '@screens/Tabs/Shared/Search'
import TabSharedToot from '@screens/Tabs/Shared/Toot'
import TabSharedUsers from '@screens/Tabs/Shared/Users'
-import { useTheme } from '@utils/styles/ThemeManager'
import React from 'react'
-import { useTranslation } from 'react-i18next'
import TabSharedAccountInLists from './AccountInLists'
const TabShared = ({ Stack }: { Stack: ReturnType }) => {
- const { colors, mode } = useTheme()
- const { t } = useTranslation('screenTabs')
-
return (
-
-import React from 'react'
-import log from './log'
-
const dev = () => {
if (__DEV__) {
// log('log', 'devs', 'initializing wdyr')
diff --git a/src/startup/netInfo.ts b/src/startup/netInfo.ts
index d7b25185..1cc5f1b9 100644
--- a/src/startup/netInfo.ts
+++ b/src/startup/netInfo.ts
@@ -1,14 +1,9 @@
import apiInstance from '@api/instance'
import NetInfo from '@react-native-community/netinfo'
import { store } from '@root/store'
-import initQuery from '@utils/initQuery'
-import { getPreviousTab } from '@utils/slices/contextsSlice'
import removeInstance from '@utils/slices/instances/remove'
-import {
- getInstance,
- updateInstanceAccount
-} from '@utils/slices/instancesSlice'
-import { onlineManager } from 'react-query'
+import { getInstance, updateInstanceAccount } from '@utils/slices/instancesSlice'
+import { onlineManager } from '@tanstack/react-query'
import log from './log'
const netInfo = async (): Promise<{
@@ -22,9 +17,7 @@ const netInfo = async (): Promise<{
onlineManager.setEventListener(setOnline => {
return NetInfo.addEventListener(state => {
- setOnline(
- typeof state.isConnected === 'boolean' ? state.isConnected : undefined
- )
+ setOnline(!!state.isConnected)
})
})
@@ -60,23 +53,6 @@ const netInfo = async (): Promise<{
})
)
- if (instance.timelinesLookback) {
- const previousTab = getPreviousTab(store.getState())
- let loadPage:
- | Extract
- | undefined = undefined
- if (previousTab === 'Tab-Local') {
- loadPage = 'Following'
- } else if (previousTab === 'Tab-Public') {
- loadPage = 'LocalPublic'
- }
-
- // await initQuery({
- // instance,
- // prefetch: { enabled: true, page: loadPage }
- // })
- }
-
return Promise.resolve({ connected: true })
}
} else {
diff --git a/src/store.ts b/src/store.ts
index 7e6b5e2d..7673ea8f 100644
--- a/src/store.ts
+++ b/src/store.ts
@@ -1,11 +1,11 @@
import createSecureStore from '@neverdull-agency/expo-unlimited-secure-store'
import AsyncStorage from '@react-native-async-storage/async-storage'
import { AnyAction, configureStore, Reducer } from '@reduxjs/toolkit'
-import contextsMigration from '@utils/migrations/contexts/migration'
+import contextsMigration, { ContextsLatest } from '@utils/migrations/contexts/migration'
import instancesMigration from '@utils/migrations/instances/migration'
import settingsMigration from '@utils/migrations/settings/migration'
import appSlice, { AppState } from '@utils/slices/appSlice'
-import contextsSlice, { ContextsState } from '@utils/slices/contextsSlice'
+import contextsSlice from '@utils/slices/contextsSlice'
import instancesSlice, { InstancesState } from '@utils/slices/instancesSlice'
import settingsSlice, { SettingsState } from '@utils/slices/settingsSlice'
import { Platform } from 'react-native'
@@ -37,7 +37,7 @@ const contextsPersistConfig = {
key: 'contexts',
prefix,
storage: AsyncStorage,
- version: 2,
+ version: 3,
// @ts-ignore
migrate: createMigrate(contextsMigration)
}
@@ -46,7 +46,7 @@ const instancesPersistConfig = {
key: 'instances',
prefix,
storage: Platform.OS === 'ios' ? secureStorage : AsyncStorage,
- version: 10,
+ version: 11,
// @ts-ignore
migrate: createMigrate(instancesMigration)
}
@@ -64,7 +64,7 @@ const store = configureStore({
reducer: {
app: persistReducer(appPersistConfig, appSlice) as Reducer,
contexts: persistReducer(contextsPersistConfig, contextsSlice) as Reducer<
- ContextsState,
+ ContextsLatest,
AnyAction
>,
instances: persistReducer(instancesPersistConfig, instancesSlice) as Reducer<
diff --git a/src/utils/initQuery.ts b/src/utils/initQuery.ts
index f51dcba0..591e9538 100644
--- a/src/utils/initQuery.ts
+++ b/src/utils/initQuery.ts
@@ -1,33 +1,11 @@
import queryClient from '@helpers/queryClient'
import { store } from '@root/store'
import { InstanceLatest } from './migrations/instances/migration'
-// import { prefetchTimelineQuery } from './queryHooks/timeline'
import { updateInstanceActive } from './slices/instancesSlice'
-const initQuery = async ({
- instance,
- prefetch
-}: {
- instance: InstanceLatest
- prefetch?: { enabled: boolean; page?: 'Following' | 'LocalPublic' }
-}) => {
+const initQuery = async ({ instance }: { instance: InstanceLatest }) => {
store.dispatch(updateInstanceActive(instance))
await queryClient.resetQueries()
-
- // if (prefetch?.enabled && instance.timelinesLookback) {
- // if (
- // prefetch.page &&
- // instance.timelinesLookback[prefetch.page]?.ids?.length > 0
- // ) {
- // await prefetchTimelineQuery(instance.timelinesLookback[prefetch.page])
- // }
-
- // for (const page of Object.keys(instance.timelinesLookback)) {
- // if (page !== prefetch.page) {
- // prefetchTimelineQuery(instance.timelinesLookback[page])
- // }
- // }
- // }
}
export default initQuery
diff --git a/src/utils/migrations/contexts/migration.ts b/src/utils/migrations/contexts/migration.ts
index 2dedf997..faa57786 100644
--- a/src/utils/migrations/contexts/migration.ts
+++ b/src/utils/migrations/contexts/migration.ts
@@ -1,6 +1,7 @@
import { ContextsV0 } from './v0'
import { ContextsV1 } from './v1'
import { ContextsV2 } from './v2'
+import { ContextsV3 } from './v3'
const contextsMigration = {
1: (state: ContextsV0): ContextsV1 => {
@@ -15,7 +16,12 @@ const contextsMigration = {
2: (state: ContextsV1): ContextsV2 => {
const { mePage, ...rest } = state
return rest
+ },
+ 3: (state: ContextsV2): ContextsV3 => {
+ return { ...state, previousSegment: 'Local' }
}
}
+export { ContextsV3 as ContextsLatest }
+
export default contextsMigration
diff --git a/src/utils/migrations/contexts/v3.ts b/src/utils/migrations/contexts/v3.ts
new file mode 100644
index 00000000..0f35df8b
--- /dev/null
+++ b/src/utils/migrations/contexts/v3.ts
@@ -0,0 +1,19 @@
+import { ScreenTabsStackParamList } from '@utils/navigation/navigators'
+
+export type ContextsV3 = {
+ storeReview: {
+ context: Readonly
+ current: number
+ shown: boolean
+ }
+ publicRemoteNotice: {
+ context: Readonly
+ current: number
+ hidden: boolean
+ }
+ previousTab: Extract<
+ keyof ScreenTabsStackParamList,
+ 'Tab-Local' | 'Tab-Public' | 'Tab-Notifications' | 'Tab-Me'
+ >
+ previousSegment: Extract
+}
diff --git a/src/utils/migrations/instances/migration.ts b/src/utils/migrations/instances/migration.ts
index ac02bd1c..d4393513 100644
--- a/src/utils/migrations/instances/migration.ts
+++ b/src/utils/migrations/instances/migration.ts
@@ -6,6 +6,7 @@ import { InstanceV7 } from './v7'
import { InstanceV8 } from './v8'
import { InstanceV9 } from './v9'
import { InstanceV10 } from './v10'
+import { InstanceV11 } from './v11'
const instancesMigration = {
4: (state: InstanceV3): InstanceV4 => {
@@ -128,9 +129,44 @@ const instancesMigration = {
}
})
}
+ },
+ 11: (state: { instances: InstanceV10[] }): { instances: InstanceV11[] } => {
+ return {
+ instances: state.instances.map(instance => {
+ delete instance.timelinesLookback
+
+ return {
+ ...instance,
+ followingPage: { showBoosts: true, showReplies: true },
+ mePage: { ...instance.mePage, followedTags: { shown: false } },
+ notifications_filter: {
+ ...instance.notifications_filter,
+ 'admin.sign_up': true,
+ 'admin.report': true
+ },
+ push: {
+ ...instance.push,
+ global: instance.push.global.value,
+ decode: instance.push.decode.value,
+ alerts: {
+ follow: instance.push.alerts.follow.value,
+ follow_request: instance.push.alerts.follow_request.value,
+ favourite: instance.push.alerts.favourite.value,
+ reblog: instance.push.alerts.reblog.value,
+ mention: instance.push.alerts.mention.value,
+ poll: instance.push.alerts.poll.value,
+ status: instance.push.alerts.status.value,
+ update: false,
+ 'admin.sign_up': false,
+ 'admin.report': false
+ }
+ }
+ }
+ })
+ }
}
}
-export { InstanceV10 as InstanceLatest }
+export { InstanceV11 as InstanceLatest }
export default instancesMigration
diff --git a/src/utils/migrations/instances/v11.ts b/src/utils/migrations/instances/v11.ts
new file mode 100644
index 00000000..e02d72bb
--- /dev/null
+++ b/src/utils/migrations/instances/v11.ts
@@ -0,0 +1,60 @@
+import { ComposeStateDraft } from '@screens/Compose/utils/types'
+
+export type InstanceV11 = {
+ active: boolean
+ appData: {
+ clientId: string
+ clientSecret: string
+ }
+ url: string
+ token: string
+ uri: Mastodon.Instance['uri']
+ urls: Mastodon.Instance['urls']
+ account: {
+ id: Mastodon.Account['id']
+ acct: Mastodon.Account['acct']
+ avatarStatic: Mastodon.Account['avatar_static']
+ preferences: Mastodon.Preferences
+ }
+ version: string
+ configuration?: Mastodon.Instance['configuration']
+ filters: Mastodon.Filter[]
+ notifications_filter: {
+ follow: boolean
+ follow_request: boolean
+ favourite: boolean
+ reblog: boolean
+ mention: boolean
+ poll: boolean
+ status: boolean
+ update: boolean
+ 'admin.sign_up': boolean
+ 'admin.report': boolean
+ }
+ push: {
+ global: boolean
+ decode: boolean
+ alerts: Mastodon.PushSubscription['alerts']
+ keys: {
+ auth?: string
+ public?: string // legacy
+ private?: string // legacy
+ }
+ }
+ followingPage: {
+ showBoosts: boolean
+ showReplies: boolean
+ }
+ mePage: {
+ followedTags: { shown: boolean }
+ lists: { shown: boolean }
+ announcements: { shown: boolean; unread: number }
+ }
+ drafts: ComposeStateDraft[]
+ frequentEmojis: {
+ emoji: Pick
+ score: number
+ count: number
+ lastUsed: number
+ }[]
+}
diff --git a/src/utils/navigation/navigators.ts b/src/utils/navigation/navigators.ts
index 8c7f70ee..0e5d2822 100644
--- a/src/utils/navigation/navigators.ts
+++ b/src/utils/navigation/navigators.ts
@@ -112,13 +112,13 @@ export type TabSharedStackParamList = {
'Tab-Shared-Users':
| {
reference: 'accounts'
- id: Mastodon.Account['id']
+ account: Pick
type: 'following' | 'followers'
count: number
}
| {
reference: 'statuses'
- id: Mastodon.Status['id']
+ status: Pick
type: 'reblogged_by' | 'favourited_by'
count: number
}
@@ -136,13 +136,17 @@ export type TabPublicStackParamList = {
export type TabNotificationsStackParamList = {
'Tab-Notifications-Root': undefined
+ 'Tab-Notifications-Filters': undefined
} & TabSharedStackParamList
+export type TabNotificationsStackScreenProps =
+ NativeStackScreenProps
export type TabMeStackParamList = {
'Tab-Me-Root': undefined
'Tab-Me-Bookmarks': undefined
'Tab-Me-Conversations': undefined
'Tab-Me-Favourites': undefined
+ 'Tab-Me-FollowedTags': undefined
'Tab-Me-List': Mastodon.List
'Tab-Me-List-Accounts': Omit
'Tab-Me-List-Edit':
diff --git a/src/utils/push/useConnect.ts b/src/utils/push/useConnect.ts
index bb117b7d..dbb45104 100644
--- a/src/utils/push/useConnect.ts
+++ b/src/utils/push/useConnect.ts
@@ -23,7 +23,7 @@ const pushUseConnect = () => {
const expoToken = useSelector(getExpoToken)
const instances = useSelector(getInstances, (prev, next) => prev.length === next.length)
- const pushEnabled = instances.filter(instance => instance.push.global.value)
+ const pushEnabled = instances.filter(instance => instance.push.global)
const connect = () => {
apiTooot({
@@ -60,7 +60,7 @@ const pushUseConnect = () => {
dispatch(disableAllPushes())
instances.forEach(instance => {
- if (instance.push.global.value) {
+ if (instance.push.global) {
apiGeneral<{}>({
method: 'delete',
domain: instance.url,
diff --git a/src/utils/push/useReceive.ts b/src/utils/push/useReceive.ts
index 08c8009d..76a91b21 100644
--- a/src/utils/push/useReceive.ts
+++ b/src/utils/push/useReceive.ts
@@ -31,10 +31,7 @@ const pushUseReceive = () => {
description: notification.request.content.body!,
onPress: () => {
if (notificationIndex !== -1) {
- initQuery({
- instance: instances[notificationIndex],
- prefetch: { enabled: true }
- })
+ initQuery({ instance: instances[notificationIndex] })
}
pushUseNavigate(payloadData.notification_id)
}
diff --git a/src/utils/push/useRespond.ts b/src/utils/push/useRespond.ts
index df4771b6..e63be4d4 100644
--- a/src/utils/push/useRespond.ts
+++ b/src/utils/push/useRespond.ts
@@ -27,10 +27,7 @@ const pushUseRespond = () => {
instance.account.id === payloadData.accountId
)
if (notificationIndex !== -1) {
- initQuery({
- instance: instances[notificationIndex],
- prefetch: { enabled: true }
- })
+ initQuery({ instance: instances[notificationIndex] })
}
pushUseNavigate(payloadData.notification_id)
}
diff --git a/src/utils/queryHooks/account.ts b/src/utils/queryHooks/account.ts
index 565fa71b..ed582376 100644
--- a/src/utils/queryHooks/account.ts
+++ b/src/utils/queryHooks/account.ts
@@ -1,16 +1,17 @@
import apiInstance from '@api/instance'
import { AxiosError } from 'axios'
-import { QueryFunctionContext, useQuery, UseQueryOptions } from 'react-query'
+import { QueryFunctionContext, useQuery, UseQueryOptions } from '@tanstack/react-query'
export type QueryKeyAccount = ['Account', { id: Mastodon.Account['id'] }]
-const accountQueryFunction = ({ queryKey }: QueryFunctionContext) => {
+const accountQueryFunction = async ({ queryKey }: QueryFunctionContext) => {
const { id } = queryKey[1]
- return apiInstance({
+ const res = await apiInstance({
method: 'get',
url: `accounts/${id}`
- }).then(res => res.body)
+ })
+ return res.body
}
const useAccountQuery = ({
@@ -27,15 +28,16 @@ const useAccountQuery = ({
export type QueryKeyAccountInLists = ['AccountInLists', { id: Mastodon.Account['id'] }]
-const accountInListsQueryFunction = ({
+const accountInListsQueryFunction = async ({
queryKey
}: QueryFunctionContext) => {
const { id } = queryKey[1]
- return apiInstance({
+ const res = await apiInstance({
method: 'get',
url: `accounts/${id}/lists`
- }).then(res => res.body)
+ })
+ return res.body
}
const useAccountInListsQuery = ({
diff --git a/src/utils/queryHooks/announcement.ts b/src/utils/queryHooks/announcement.ts
index 3f003041..c484b053 100644
--- a/src/utils/queryHooks/announcement.ts
+++ b/src/utils/queryHooks/announcement.ts
@@ -6,16 +6,16 @@ import {
UseMutationOptions,
useQuery,
UseQueryOptions
-} from 'react-query'
+} from '@tanstack/react-query'
type QueryKeyAnnouncement = ['Announcements', { showAll?: boolean }]
-const queryFunction = ({
+const queryFunction = async ({
queryKey
}: QueryFunctionContext) => {
const { showAll } = queryKey[1]
- return apiInstance({
+ const res = await apiInstance({
method: 'get',
url: `announcements`,
...(showAll && {
@@ -23,7 +23,8 @@ const queryFunction = ({
with_dismissed: 'true'
}
})
- }).then(res => res.body)
+ })
+ return res.body
}
const useAnnouncementQuery = ({
diff --git a/src/utils/queryHooks/apps.ts b/src/utils/queryHooks/apps.ts
index 601f0b50..79f821c9 100644
--- a/src/utils/queryHooks/apps.ts
+++ b/src/utils/queryHooks/apps.ts
@@ -1,18 +1,41 @@
import apiGeneral from '@api/general'
+import apiInstance from '@api/instance'
import { AxiosError } from 'axios'
import * as AuthSession from 'expo-auth-session'
-import { QueryFunctionContext, useQuery, UseQueryOptions } from 'react-query'
+import {
+ QueryFunctionContext,
+ useMutation,
+ UseMutationOptions,
+ useQuery,
+ UseQueryOptions
+} from '@tanstack/react-query'
-export type QueryKeyApps = ['Apps', { domain?: string }]
+export type QueryKeyApps = ['Apps']
-const queryFunction = ({ queryKey }: QueryFunctionContext) => {
- const redirectUri = AuthSession.makeRedirectUri({
- native: 'tooot://instance-auth',
- useProxy: false
+const queryFunctionApps = async ({ queryKey }: QueryFunctionContext) => {
+ const res = await apiInstance({
+ method: 'get',
+ url: 'apps/verify_credentials'
})
+ return res.body
+}
- const { domain } = queryKey[1]
+const useAppsQuery = (
+ params: {
+ options?: UseQueryOptions
+ } | void
+) => {
+ const queryKey: QueryKeyApps = ['Apps']
+ return useQuery(queryKey, queryFunctionApps, params?.options)
+}
+type MutationVarsApps = { domain: string }
+
+export const redirectUri = AuthSession.makeRedirectUri({
+ native: 'tooot://instance-auth',
+ useProxy: false
+})
+const mutationFunctionApps = async ({ domain }: MutationVarsApps) => {
const formData = new FormData()
formData.append('client_name', 'tooot')
formData.append('website', 'https://tooot.app')
@@ -21,20 +44,16 @@ const queryFunction = ({ queryKey }: QueryFunctionContext) => {
return apiGeneral({
method: 'post',
- domain: domain || '',
+ domain: domain,
url: `api/v1/apps`,
body: formData
}).then(res => res.body)
}
-const useAppsQuery = ({
- options,
- ...queryKeyParams
-}: QueryKeyApps[1] & {
- options?: UseQueryOptions
-}) => {
- const queryKey: QueryKeyApps = ['Apps', { ...queryKeyParams }]
- return useQuery(queryKey, queryFunction, options)
+const useAppsMutation = (
+ options: UseMutationOptions
+) => {
+ return useMutation(mutationFunctionApps, options)
}
-export { useAppsQuery }
+export { useAppsQuery, useAppsMutation }
diff --git a/src/utils/queryHooks/emojis.ts b/src/utils/queryHooks/emojis.ts
index 891bd509..e2bf0e44 100644
--- a/src/utils/queryHooks/emojis.ts
+++ b/src/utils/queryHooks/emojis.ts
@@ -1,6 +1,6 @@
import apiInstance from '@api/instance'
import { AxiosError } from 'axios'
-import { useQuery, UseQueryOptions } from 'react-query'
+import { useQuery, UseQueryOptions } from '@tanstack/react-query'
type QueryKeyEmojis = ['Emojis']
diff --git a/src/utils/queryHooks/instance.ts b/src/utils/queryHooks/instance.ts
index c1785683..c0351f74 100644
--- a/src/utils/queryHooks/instance.ts
+++ b/src/utils/queryHooks/instance.ts
@@ -1,6 +1,6 @@
import apiGeneral from '@api/general'
import { AxiosError } from 'axios'
-import { QueryFunctionContext, useQuery, UseQueryOptions } from 'react-query'
+import { QueryFunctionContext, useQuery, UseQueryOptions } from '@tanstack/react-query'
export type QueryKeyInstance = ['Instance', { domain?: string }]
diff --git a/src/utils/queryHooks/lists.ts b/src/utils/queryHooks/lists.ts
index 0f7d7071..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,
@@ -8,7 +8,8 @@ import {
UseMutationOptions,
useQuery,
UseQueryOptions
-} from 'react-query'
+} from '@tanstack/react-query'
+import { PagedResponse } from '@api/helpers'
export type QueryKeyLists = ['Lists']
@@ -20,9 +21,11 @@ const queryFunction = async () => {
return res.body
}
-const useListsQuery = ({ options }: { options?: UseQueryOptions }) => {
+const useListsQuery = (
+ params: { options?: UseQueryOptions } | void
+) => {
const queryKey: QueryKeyLists = ['Lists']
- return useQuery(queryKey, queryFunction, options)
+ return useQuery(queryKey, queryFunction, params?.options)
}
type MutationVarsLists =
@@ -95,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/profile.ts b/src/utils/queryHooks/profile.ts
index bb00c6d5..527893e9 100644
--- a/src/utils/queryHooks/profile.ts
+++ b/src/utils/queryHooks/profile.ts
@@ -6,14 +6,14 @@ import { AxiosError } from 'axios'
import i18next from 'i18next'
import { RefObject } from 'react'
import FlashMessage from 'react-native-flash-message'
-import { useMutation, useQuery, UseQueryOptions } from 'react-query'
+import { useMutation, useQuery, UseQueryOptions } from '@tanstack/react-query'
type AccountWithSource = Mastodon.Account & Required>
-type QueryKeyProfile = ['Profile']
+export type QueryKeyProfile = ['Profile']
const queryKey: QueryKeyProfile = ['Profile']
-const queryFunction = async () => {
+const queryFunctionProfile = async () => {
const res = await apiInstance({
method: 'get',
url: `accounts/verify_credentials`
@@ -21,12 +21,12 @@ const queryFunction = async () => {
return res.body
}
-const useProfileQuery = ({
- options
-}: {
- options?: UseQueryOptions
-}) => {
- return useQuery(queryKey, queryFunction, options)
+const useProfileQuery = (
+ params: {
+ options: UseQueryOptions
+ } | void
+) => {
+ return useQuery(queryKey, queryFunctionProfile, params?.options)
}
type MutationVarsProfileBase =
@@ -155,4 +155,4 @@ const useProfileMutation = () => {
)
}
-export { useProfileQuery, useProfileMutation }
+export { queryFunctionProfile, useProfileQuery, useProfileMutation }
diff --git a/src/utils/queryHooks/relationship.ts b/src/utils/queryHooks/relationship.ts
index 1671449e..38187026 100644
--- a/src/utils/queryHooks/relationship.ts
+++ b/src/utils/queryHooks/relationship.ts
@@ -6,25 +6,26 @@ import {
UseMutationOptions,
useQuery,
UseQueryOptions
-} from 'react-query'
+} from '@tanstack/react-query'
export type QueryKeyRelationship = [
'Relationship',
{ id: Mastodon.Account['id'] }
]
-const queryFunction = ({
+const queryFunction = async ({
queryKey
}: QueryFunctionContext) => {
const { id } = queryKey[1]
- return apiInstance({
+ const res = await apiInstance({
method: 'get',
url: `accounts/relationships`,
params: {
'id[]': id
}
- }).then(res => res.body)
+ })
+ return res.body
}
const useRelationshipQuery = ({
diff --git a/src/utils/queryHooks/search.ts b/src/utils/queryHooks/search.ts
index f15e17d2..313a7885 100644
--- a/src/utils/queryHooks/search.ts
+++ b/src/utils/queryHooks/search.ts
@@ -1,6 +1,6 @@
import apiInstance from '@api/instance'
import { AxiosError } from 'axios'
-import { QueryFunctionContext, useQuery, UseQueryOptions } from 'react-query'
+import { QueryFunctionContext, useQuery, UseQueryOptions } from '@tanstack/react-query'
export type QueryKeySearch = [
'Search',
@@ -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/status.ts b/src/utils/queryHooks/status.ts
index c0a2de02..48a0d40c 100644
--- a/src/utils/queryHooks/status.ts
+++ b/src/utils/queryHooks/status.ts
@@ -1,16 +1,17 @@
import apiInstance from '@api/instance'
import { AxiosError } from 'axios'
-import { QueryFunctionContext, useQuery, UseQueryOptions } from 'react-query'
+import { QueryFunctionContext, useQuery, UseQueryOptions } from '@tanstack/react-query'
export type QueryKeyStatus = ['Status', { id: Mastodon.Status['id'] }]
-const queryFunction = ({ queryKey }: QueryFunctionContext) => {
+const queryFunction = async ({ queryKey }: QueryFunctionContext) => {
const { id } = queryKey[1]
- return apiInstance({
+ const res = await apiInstance({
method: 'get',
url: `statuses/${id}`
- }).then(res => res.body)
+ })
+ return res.body
}
const useStatusQuery = ({
diff --git a/src/utils/queryHooks/statusesHistory.ts b/src/utils/queryHooks/statusesHistory.ts
index a1a3e76b..b5593f31 100644
--- a/src/utils/queryHooks/statusesHistory.ts
+++ b/src/utils/queryHooks/statusesHistory.ts
@@ -1,6 +1,6 @@
import apiInstance from '@api/instance'
import { AxiosError } from 'axios'
-import { QueryFunctionContext, useQuery, UseQueryOptions } from 'react-query'
+import { QueryFunctionContext, useQuery, UseQueryOptions } from '@tanstack/react-query'
export type QueryKeyStatusesHistory = [
'StatusesHistory',
diff --git a/src/utils/queryHooks/tags.ts b/src/utils/queryHooks/tags.ts
index d7fe37bc..28e61831 100644
--- a/src/utils/queryHooks/tags.ts
+++ b/src/utils/queryHooks/tags.ts
@@ -2,35 +2,45 @@ import apiInstance from '@api/instance'
import { AxiosError } from 'axios'
import {
QueryFunctionContext,
+ useInfiniteQuery,
+ UseInfiniteQueryOptions,
useMutation,
UseMutationOptions,
useQuery,
UseQueryOptions
-} from 'react-query'
+} from '@tanstack/react-query'
+import { infinitePageParams } from './utils'
+import { PagedResponse } from '@api/helpers'
-type QueryKeyFollowedTags = ['FollowedTags']
-const useFollowedTagsQuery = ({
- options
-}: {
- options?: UseQueryOptions
-}) => {
+export type QueryKeyFollowedTags = ['FollowedTags']
+const useFollowedTagsQuery = (
+ params: {
+ options?: Omit<
+ UseInfiniteQueryOptions, AxiosError>,
+ 'getPreviousPageParam' | 'getNextPageParam'
+ >
+ } | void
+) => {
const queryKey: QueryKeyFollowedTags = ['FollowedTags']
- return useQuery(
+ return useInfiniteQuery(
queryKey,
async ({ pageParam }: QueryFunctionContext) => {
const params: { [key: string]: string } = { ...pageParam }
- const res = await apiInstance({ method: 'get', url: `followed_tags`, params })
- return res.body
+ return await apiInstance({ method: 'get', url: `followed_tags`, params })
},
- options
+ {
+ ...params?.options,
+ ...infinitePageParams
+ }
)
}
-type QueryKeyTags = ['Tags', { tag: string }]
-const queryFunction = ({ queryKey }: QueryFunctionContext) => {
+export type QueryKeyTags = ['Tags', { tag: string }]
+const queryFunction = async ({ queryKey }: QueryFunctionContext) => {
const { tag } = queryKey[1]
- return apiInstance({ method: 'get', url: `tags/${tag}` }).then(res => res.body)
+ const res = await apiInstance({ method: 'get', url: `tags/${tag}` })
+ return res.body
}
const useTagsQuery = ({
options,
@@ -42,15 +52,12 @@ const useTagsQuery = ({
return useQuery(queryKey, queryFunction, options)
}
-type MutationVarsAnnouncement = { tag: string; type: 'follow'; to: boolean }
-const mutationFunction = async ({ tag, type, to }: MutationVarsAnnouncement) => {
- switch (type) {
- case 'follow':
- return apiInstance<{}>({
- method: 'post',
- url: `tags/${tag}/${to ? 'follow' : 'unfollow'}`
- })
- }
+type MutationVarsAnnouncement = { tag: string; to: boolean }
+const mutationFunction = async ({ tag, to }: MutationVarsAnnouncement) => {
+ return apiInstance<{}>({
+ method: 'post',
+ url: `tags/${tag}/${to ? 'follow' : 'unfollow'}`
+ })
}
const useTagsMutation = (options: UseMutationOptions<{}, AxiosError, MutationVarsAnnouncement>) => {
return useMutation(mutationFunction, options)
diff --git a/src/utils/queryHooks/timeline.ts b/src/utils/queryHooks/timeline.ts
index eff1113e..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'
@@ -11,35 +11,78 @@ import {
useInfiniteQuery,
UseInfiniteQueryOptions,
useMutation
-} from 'react-query'
+} from '@tanstack/react-query'
import deleteItem from './timeline/deleteItem'
import editItem from './timeline/editItem'
import updateStatusProperty from './timeline/updateStatusProperty'
+import { PagedResponse } from '@api/helpers'
export type QueryKeyTimeline = [
'Timeline',
- {
- page: App.Pages
- hashtag?: Mastodon.Tag['name']
- list?: Mastodon.List['id']
- toot?: Mastodon.Status['id']
- account?: Mastodon.Account['id']
- }
+ (
+ | {
+ page: Exclude
+ }
+ | {
+ page: 'Following'
+ showBoosts: boolean
+ showReplies: boolean
+ }
+ | {
+ page: 'Hashtag'
+ hashtag: Mastodon.Tag['name']
+ }
+ | {
+ page: 'List'
+ list: Mastodon.List['id']
+ }
+ | {
+ page: 'Toot'
+ toot: Mastodon.Status['id']
+ }
+ | {
+ page: 'Account'
+ account: Mastodon.Account['id']
+ exclude_reblogs: boolean
+ only_media: boolean
+ }
+ )
]
const queryFunction = async ({ queryKey, pageParam }: QueryFunctionContext) => {
- const { page, account, hashtag, list, toot } = queryKey[1]
- let params: { [key: string]: string } = { ...pageParam }
+ const page = queryKey[1]
+ let params: { [key: string]: string } = { ...pageParam, limit: 40 }
- switch (page) {
+ switch (page.page) {
case 'Following':
return apiInstance({
method: 'get',
url: 'timelines/home',
params
+ }).then(res => {
+ if (!page.showBoosts || !page.showReplies) {
+ return {
+ ...res,
+ body: res.body
+ .filter(status => {
+ if (!page.showBoosts && status.reblog) {
+ return null
+ }
+ if (!page.showReplies && status.in_reply_to_id?.length) {
+ return null
+ }
+
+ return status
+ })
+ .filter(s => s)
+ }
+ } else {
+ return res
+ }
})
case 'Local':
+ console.log('local', params)
return apiInstance({
method: 'get',
url: 'timelines/public',
@@ -56,6 +99,14 @@ const queryFunction = async ({ queryKey, pageParam }: QueryFunctionContext({
+ method: 'get',
+ url: 'trends/statuses',
+ params
+ })
+
case 'Notifications':
const rootStore = store.getState()
const notificationsFilter = getInstanceNotificationsFilter(rootStore)
@@ -82,62 +133,57 @@ const queryFunction = async ({ queryKey, pageParam }: QueryFunctionContext({
+ method: 'get',
+ url: `accounts/${page.account}/statuses`,
+ params: {
+ exclude_replies: 'true',
+ ...params
+ }
+ })
+ } else {
+ const res1 = await apiInstance<(Mastodon.Status & { _pinned: boolean })[]>({
+ method: 'get',
+ url: `accounts/${page.account}/statuses`,
+ params: {
+ pinned: 'true'
+ }
+ })
+ res1.body = res1.body.map(status => {
+ status._pinned = true
+ return status
+ })
+ const res2 = await apiInstance({
+ method: 'get',
+ url: `accounts/${page.account}/statuses`,
+ params: {
+ exclude_replies: 'true'
+ }
+ })
+ return {
+ body: uniqBy([...res1.body, ...res2.body], 'id'),
+ ...(res2.links.next && { links: { next: res2.links.next } })
+ }
+ }
+ } else {
return apiInstance({
method: 'get',
- url: `accounts/${account}/statuses`,
+ url: `accounts/${page.account}/statuses`,
params: {
- exclude_replies: 'true',
- ...params
+ ...params,
+ exclude_replies: page.exclude_reblogs.toString(),
+ only_media: page.only_media.toString()
}
})
- } else {
- const res1 = await apiInstance<(Mastodon.Status & { _pinned: boolean })[]>({
- method: 'get',
- url: `accounts/${account}/statuses`,
- params: {
- pinned: 'true'
- }
- })
- res1.body = res1.body.map(status => {
- status._pinned = true
- return status
- })
- const res2 = await apiInstance({
- method: 'get',
- url: `accounts/${account}/statuses`,
- params: {
- exclude_replies: 'true'
- }
- })
- return {
- body: uniqBy([...res1.body, ...res2.body], 'id'),
- ...(res2.links.next && { links: { next: res2.links.next } })
- }
}
- case 'Account_All':
- return apiInstance({
- method: 'get',
- url: `accounts/${account}/statuses`,
- params
- })
-
- case 'Account_Attachments':
- return apiInstance({
- method: 'get',
- url: `accounts/${account}/statuses`,
- params: {
- only_media: 'true',
- ...params
- }
- })
-
case 'Hashtag':
return apiInstance({
method: 'get',
- url: `timelines/tag/${hashtag}`,
+ url: `timelines/tag/${page.hashtag}`,
params
})
@@ -165,21 +211,21 @@ const queryFunction = async ({ queryKey, pageParam }: QueryFunctionContext({
method: 'get',
- url: `timelines/list/${list}`,
+ url: `timelines/list/${page.list}`,
params
})
case 'Toot':
const res1_1 = await apiInstance({
method: 'get',
- url: `statuses/${toot}`
+ url: `statuses/${page.toot}`
})
const res2_1 = await apiInstance<{
ancestors: Mastodon.Status[]
descendants: Mastodon.Status[]
}>({
method: 'get',
- url: `statuses/${toot}/context`
+ url: `statuses/${page.toot}/context`
})
return {
body: [...res2_1.body.ancestors, res1_1.body, ...res2_1.body.descendants]
@@ -195,7 +241,7 @@ const useTimelineQuery = ({
options,
...queryKeyParams
}: QueryKeyTimeline[1] & {
- options?: UseInfiniteQueryOptions, AxiosError>
+ options?: UseInfiniteQueryOptions, AxiosError>
}) => {
const queryKey: QueryKeyTimeline = ['Timeline', { ...queryKeyParams }]
return useInfiniteQuery(queryKey, queryFunction, {
@@ -206,53 +252,6 @@ const useTimelineQuery = ({
})
}
-const prefetchTimelineQuery = async ({
- ids,
- queryKey
-}: {
- ids: Mastodon.Status['id'][]
- queryKey: QueryKeyTimeline
-}): Promise => {
- let page: string = ''
- let local: boolean = false
- switch (queryKey[1].page) {
- case 'Following':
- page = 'home'
- break
- case 'Local':
- page = 'public'
- local = true
- break
- case 'LocalPublic':
- page = 'public'
- break
- }
-
- for (const id of ids) {
- const statuses = await apiInstance({
- method: 'get',
- url: `timelines/${page}`,
- params: {
- min_id: id,
- limit: 1,
- ...(local && { local: 'true' })
- }
- })
- if (statuses.body.length) {
- await queryClient.prefetchInfiniteQuery(queryKey, props =>
- queryFunction({
- ...props,
- queryKey,
- pageParam: {
- max_id: statuses.body[0].id
- }
- })
- )
- return id
- }
- }
-}
-
// --- Separator ---
enum MapPropertyToUrl {
@@ -460,4 +459,4 @@ const useTimelineMutation = ({
})
}
-export { prefetchTimelineQuery, useTimelineQuery, useTimelineMutation }
+export { useTimelineQuery, useTimelineMutation }
diff --git a/src/utils/queryHooks/timeline/deleteItem.ts b/src/utils/queryHooks/timeline/deleteItem.ts
index d2911bf8..22feaa20 100644
--- a/src/utils/queryHooks/timeline/deleteItem.ts
+++ b/src/utils/queryHooks/timeline/deleteItem.ts
@@ -1,5 +1,5 @@
import queryClient from '@helpers/queryClient'
-import { InfiniteData } from 'react-query'
+import { InfiniteData } from '@tanstack/react-query'
import { MutationVarsTimelineDeleteItem } from '../timeline'
const deleteItem = ({
diff --git a/src/utils/queryHooks/timeline/editItem.ts b/src/utils/queryHooks/timeline/editItem.ts
index f8475e76..270887a0 100644
--- a/src/utils/queryHooks/timeline/editItem.ts
+++ b/src/utils/queryHooks/timeline/editItem.ts
@@ -1,5 +1,5 @@
import queryClient from '@helpers/queryClient'
-import { InfiniteData } from 'react-query'
+import { InfiniteData } from '@tanstack/react-query'
import { MutationVarsTimelineEditItem } from '../timeline'
const editItem = ({
diff --git a/src/utils/queryHooks/timeline/updateStatusProperty.ts b/src/utils/queryHooks/timeline/updateStatusProperty.ts
index d0e1332f..385aac4e 100644
--- a/src/utils/queryHooks/timeline/updateStatusProperty.ts
+++ b/src/utils/queryHooks/timeline/updateStatusProperty.ts
@@ -1,5 +1,5 @@
import queryClient from '@helpers/queryClient'
-import { InfiniteData } from 'react-query'
+import { InfiniteData } from '@tanstack/react-query'
import { MutationVarsTimelineUpdateStatusProperty, TimelineData } from '../timeline'
import updateConversation from './update/conversation'
import updateNotification from './update/notification'
diff --git a/src/utils/queryHooks/translate.ts b/src/utils/queryHooks/translate.ts
index 6e91c493..082015db 100644
--- a/src/utils/queryHooks/translate.ts
+++ b/src/utils/queryHooks/translate.ts
@@ -1,7 +1,7 @@
import apiTooot from '@api/tooot'
import haptics from '@components/haptics'
import { AxiosError } from 'axios'
-import { QueryFunctionContext, useQuery, UseQueryOptions } from 'react-query'
+import { QueryFunctionContext, useQuery, UseQueryOptions } from '@tanstack/react-query'
type Translations =
| {
diff --git a/src/utils/queryHooks/trends.ts b/src/utils/queryHooks/trends.ts
index 38bcd791..e6eede21 100644
--- a/src/utils/queryHooks/trends.ts
+++ b/src/utils/queryHooks/trends.ts
@@ -2,7 +2,7 @@ import apiInstance from '@api/instance'
import { store } from '@root/store'
import { checkInstanceFeature } from '@utils/slices/instancesSlice'
import { AxiosError } from 'axios'
-import { QueryFunctionContext, useQuery, UseQueryOptions } from 'react-query'
+import { QueryFunctionContext, useQuery, UseQueryOptions } from '@tanstack/react-query'
export type QueryKeyTrends = ['Trends', { type: 'tags' | 'statuses' | 'links' }]
diff --git a/src/utils/queryHooks/users.ts b/src/utils/queryHooks/users.ts
index 10ce5b59..0e8ecbdc 100644
--- a/src/utils/queryHooks/users.ts
+++ b/src/utils/queryHooks/users.ts
@@ -1,29 +1,81 @@
-import apiInstance, { InstanceResponse } from '@api/instance'
+import apiInstance from '@api/instance'
import { TabSharedStackParamList } from '@utils/navigation/navigators'
import { AxiosError } from 'axios'
import {
QueryFunctionContext,
useInfiniteQuery,
UseInfiniteQueryOptions
-} from 'react-query'
+} from '@tanstack/react-query'
+import apiGeneral from '@api/general'
+import { PagedResponse } from '@api/helpers'
-export type QueryKeyUsers = [
- 'Users',
- TabSharedStackParamList['Tab-Shared-Users']
-]
+export type QueryKeyUsers = ['Users', TabSharedStackParamList['Tab-Shared-Users']]
-const queryFunction = ({
+const queryFunction = async ({
queryKey,
- pageParam
+ pageParam,
+ meta
}: QueryFunctionContext) => {
- const { reference, id, type } = queryKey[1]
+ const page = queryKey[1]
let params: { [key: string]: string } = { ...pageParam }
- return apiInstance({
- method: 'get',
- url: `${reference}/${id}/${type}`,
- params
- })
+ switch (page.reference) {
+ case 'statuses':
+ return apiInstance({
+ method: 'get',
+ url: `${page.reference}/${page.status.id}/${page.type}`,
+ params
+ })
+ case 'accounts':
+ const localInstance = page.account.username === page.account.acct
+ if (localInstance) {
+ return apiInstance({
+ method: 'get',
+ url: `${page.reference}/${page.account.id}/${page.type}`,
+ params
+ })
+ } else {
+ 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
+ })
+ return { ...res, warnIncomplete: true }
+ }
+ }
+ }
}
const useUsersQuery = ({
@@ -31,7 +83,7 @@ const useUsersQuery = ({
...queryKeyParams
}: QueryKeyUsers[1] & {
options?: UseInfiniteQueryOptions<
- InstanceResponse,
+ PagedResponse & { warnIncomplete: boolean; remoteData: boolean },
AxiosError
>
}) => {
diff --git a/src/utils/queryHooks/utils.ts b/src/utils/queryHooks/utils.ts
new file mode 100644
index 00000000..15f39096
--- /dev/null
+++ b/src/utils/queryHooks/utils.ts
@@ -0,0 +1,8 @@
+import { PagedResponse } from '@api/helpers'
+
+export const infinitePageParams = {
+ getPreviousPageParam: (firstPage: PagedResponse) =>
+ firstPage.links?.prev && { min_id: firstPage.links.next },
+ getNextPageParam: (lastPage: PagedResponse) =>
+ lastPage.links?.next && { max_id: lastPage.links.next }
+}
diff --git a/src/utils/slices/contextsSlice.ts b/src/utils/slices/contextsSlice.ts
index 27a4235f..df99bdd6 100644
--- a/src/utils/slices/contextsSlice.ts
+++ b/src/utils/slices/contextsSlice.ts
@@ -1,23 +1,10 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import { RootState } from '@root/store'
+import { ContextsLatest } from '@utils/migrations/contexts/migration'
import Constants from 'expo-constants'
import * as StoreReview from 'expo-store-review'
-export type ContextsState = {
- storeReview: {
- context: Readonly
- current: number
- shown: boolean
- }
- publicRemoteNotice: {
- context: Readonly
- current: number
- hidden: boolean
- }
- previousTab: 'Tab-Local' | 'Tab-Public' | 'Tab-Notifications' | 'Tab-Me'
-}
-
-export const contextsInitialState = {
+export const contextsInitialState: ContextsLatest = {
// After 10 successful postings
storeReview: {
context: 10,
@@ -30,49 +17,46 @@ export const contextsInitialState = {
current: 0,
hidden: false
},
- previousTab: 'Tab-Me'
+ previousTab: 'Tab-Me',
+ previousSegment: 'Local'
}
const contextsSlice = createSlice({
name: 'contexts',
- initialState: contextsInitialState as ContextsState,
+ initialState: contextsInitialState,
reducers: {
updateStoreReview: (state, action: PayloadAction<1>) => {
if (Constants.expoConfig?.extra?.environment === 'release') {
state.storeReview.current = state.storeReview.current + action.payload
if (state.storeReview.current === state.storeReview.context) {
- StoreReview?.isAvailableAsync().then(() =>
- StoreReview.requestReview()
- )
+ StoreReview?.isAvailableAsync().then(() => StoreReview.requestReview())
}
}
},
updatePublicRemoteNotice: (state, action: PayloadAction<1>) => {
- state.publicRemoteNotice.current =
- state.publicRemoteNotice.current + action.payload
- if (
- state.publicRemoteNotice.current === state.publicRemoteNotice.context
- ) {
+ state.publicRemoteNotice.current = state.publicRemoteNotice.current + action.payload
+ if (state.publicRemoteNotice.current === state.publicRemoteNotice.context) {
state.publicRemoteNotice.hidden = true
}
},
- updatePreviousTab: (
- state,
- action: PayloadAction
- ) => {
+ updatePreviousTab: (state, action: PayloadAction) => {
state.previousTab = action.payload
+ },
+ updatePreviousSegment: (state, action: PayloadAction) => {
+ state.previousSegment = action.payload
}
}
})
-export const getPublicRemoteNotice = (state: RootState) =>
- state.contexts.publicRemoteNotice
+export const getPublicRemoteNotice = (state: RootState) => state.contexts.publicRemoteNotice
export const getPreviousTab = (state: RootState) => state.contexts.previousTab
+export const getPreviousSegment = (state: RootState) => state.contexts.previousSegment
export const getContexts = (state: RootState) => state.contexts
export const {
updateStoreReview,
updatePublicRemoteNotice,
- updatePreviousTab
+ updatePreviousTab,
+ updatePreviousSegment
} = contextsSlice.actions
export default contextsSlice.reducer
diff --git a/src/utils/slices/instances/add.ts b/src/utils/slices/instances/add.ts
index a8f322ac..b8944f8e 100644
--- a/src/utils/slices/instances/add.ts
+++ b/src/utils/slices/instances/add.ts
@@ -87,24 +87,33 @@ const addInstance = createAsyncThunk(
mention: true,
poll: true,
status: true,
- update: true
+ update: true,
+ 'admin.sign_up': true,
+ 'admin.report': true
},
push: {
- global: { loading: false, value: false },
- decode: { loading: false, value: false },
+ global: false,
+ decode: false,
alerts: {
- follow: { loading: false, value: true },
- follow_request: { loading: false, value: true },
- favourite: { loading: false, value: true },
- reblog: { loading: false, value: true },
- mention: { loading: false, value: true },
- poll: { loading: false, value: true },
- status: { loading: false, value: true }
+ follow: true,
+ follow_request: true,
+ favourite: true,
+ reblog: true,
+ mention: true,
+ poll: true,
+ status: true,
+ update: true,
+ 'admin.sign_up': false,
+ 'admin.report': false
},
keys: { auth: undefined, public: undefined, private: undefined }
},
- timelinesLookback: {},
+ followingPage: {
+ showBoosts: true,
+ showReplies: true
+ },
mePage: {
+ followedTags: { shown: false },
lists: { shown: false },
announcements: { shown: false, unread: 0 }
},
diff --git a/src/utils/slices/instances/push/androidDefaults.ts b/src/utils/slices/instances/push/androidDefaults.ts
deleted file mode 100644
index 2d191e05..00000000
--- a/src/utils/slices/instances/push/androidDefaults.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import * as Notifications from 'expo-notifications'
-
-const androidDefaults = {
- importance: Notifications.AndroidImportance.DEFAULT,
- bypassDnd: false,
- showBadge: true,
- enableLights: true,
- enableVibrate: true
-}
-
-export default androidDefaults
diff --git a/src/utils/slices/instances/push/register.ts b/src/utils/slices/instances/push/register.ts
index 976b0d29..f6185a7a 100644
--- a/src/utils/slices/instances/push/register.ts
+++ b/src/utils/slices/instances/push/register.ts
@@ -1,18 +1,15 @@
import apiInstance from '@api/instance'
import apiTooot, { TOOOT_API_DOMAIN } from '@api/tooot'
import { displayMessage } from '@components/Message'
-import i18n from '@root/i18n/i18n'
import { RootState } from '@root/store'
import * as Sentry from '@sentry/react-native'
import { InstanceLatest } from '@utils/migrations/instances/migration'
import { getInstance } from '@utils/slices/instancesSlice'
-import { Theme } from '@utils/styles/themes'
-import * as Notifications from 'expo-notifications'
import * as Random from 'expo-random'
import i18next from 'i18next'
import { Platform } from 'react-native'
import base64 from 'react-native-base64'
-import androidDefaults from './androidDefaults'
+import { setChannels } from './utils'
const subscribe = async ({
expoToken,
@@ -97,50 +94,11 @@ const pushRegister = async (
accountId,
accountFull,
serverKey: res.body.server_key,
- auth: instancePush.decode.value === false ? null : auth
+ auth: instancePush.decode === false ? null : auth
})
if (Platform.OS === 'android') {
- Notifications.setNotificationChannelGroupAsync(accountFull, {
- name: accountFull,
- ...androidDefaults
- }).then(group => {
- if (group) {
- if (instancePush.decode.value === false) {
- Notifications.setNotificationChannelAsync(`${group.id}_default`, {
- groupId: group.id,
- name: i18n.t('meSettingsPush:content.default.heading'),
- ...androidDefaults
- })
- } else {
- Notifications.setNotificationChannelAsync(`${group.id}_follow`, {
- groupId: group.id,
- name: i18n.t('meSettingsPush:content.follow.heading'),
- ...androidDefaults
- })
- Notifications.setNotificationChannelAsync(`${group.id}_favourite`, {
- groupId: group.id,
- name: i18n.t('meSettingsPush:content.favourite.heading'),
- ...androidDefaults
- })
- Notifications.setNotificationChannelAsync(`${group.id}_reblog`, {
- groupId: group.id,
- name: i18n.t('meSettingsPush:content.reblog.heading'),
- ...androidDefaults
- })
- Notifications.setNotificationChannelAsync(`${group.id}_mention`, {
- groupId: group.id,
- name: i18n.t('meSettingsPush:content.mention.heading'),
- ...androidDefaults
- })
- Notifications.setNotificationChannelAsync(`${group.id}_poll`, {
- groupId: group.id,
- name: i18n.t('meSettingsPush:content.poll.heading'),
- ...androidDefaults
- })
- }
- }
- })
+ setChannels(instance)
}
return Promise.resolve(auth)
diff --git a/src/utils/slices/instances/push/utils.ts b/src/utils/slices/instances/push/utils.ts
new file mode 100644
index 00000000..443fc553
--- /dev/null
+++ b/src/utils/slices/instances/push/utils.ts
@@ -0,0 +1,117 @@
+import features from '@helpers/features'
+import {
+ checkPermission,
+ PERMISSION_MANAGE_REPORTS,
+ PERMISSION_MANAGE_USERS
+} from '@helpers/permissions'
+import queryClient from '@helpers/queryClient'
+import i18n from '@root/i18n/i18n'
+import { InstanceLatest } from '@utils/migrations/instances/migration'
+import { queryFunctionProfile, QueryKeyProfile } from '@utils/queryHooks/profile'
+import { checkInstanceFeature } from '@utils/slices/instancesSlice'
+import * as Notifications from 'expo-notifications'
+import { useSelector } from 'react-redux'
+
+export const usePushFeatures = () => {
+ 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_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}`
+
+ const deleteChannel = async (type: string) =>
+ Notifications.deleteNotificationChannelAsync(`${account}_${type}`)
+ const setChannel = async (type: string) =>
+ Notifications.setNotificationChannelAsync(`${account}_${type}`, {
+ groupId: account,
+ name: i18n.t(`screenTabs:me.push.${type}.heading`),
+ importance: Notifications.AndroidImportance.DEFAULT,
+ bypassDnd: false,
+ showBadge: true,
+ enableLights: true,
+ enableVibrate: true
+ })
+
+ const queryKey: QueryKeyProfile = ['Profile']
+ const profileQuery = await queryClient.fetchQuery(queryKey, queryFunctionProfile)
+
+ const channelGroup = await Notifications.getNotificationChannelGroupAsync(account)
+ if (!channelGroup) {
+ 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(checkFeatures)) {
+ await deleteChannel(push)
+ }
+ for (const { type } of PUSH_ADMIN(checkFeatures, profileQuery.role?.permissions)) {
+ await deleteChannel(type)
+ }
+ } else {
+ await deleteChannel('default')
+ for (const push of PUSH_DEFAULT(checkFeatures)) {
+ await setChannel(push)
+ }
+ for (const { type } of PUSH_ADMIN(checkFeatures, profileQuery.role?.permissions)) {
+ await setChannel(type)
+ }
+ }
+}
diff --git a/src/utils/slices/instances/remove.ts b/src/utils/slices/instances/remove.ts
index 053971c7..8936fa69 100644
--- a/src/utils/slices/instances/remove.ts
+++ b/src/utils/slices/instances/remove.ts
@@ -6,7 +6,7 @@ import { updateInstancePush } from './updatePush'
const removeInstance = createAsyncThunk(
'instances/remove',
async (instance: InstanceLatest, { dispatch }): Promise => {
- if (instance.push.global.value) {
+ if (instance.push.global) {
dispatch(updateInstancePush(false))
}
diff --git a/src/utils/slices/instances/updatePushAlert.ts b/src/utils/slices/instances/updatePushAlert.ts
index 1bbe3b49..d4cbb0ee 100644
--- a/src/utils/slices/instances/updatePushAlert.ts
+++ b/src/utils/slices/instances/updatePushAlert.ts
@@ -7,7 +7,6 @@ export const updateInstancePushAlert = createAsyncThunk(
async ({
alerts
}: {
- changed: keyof InstanceLatest['push']['alerts']
alerts: InstanceLatest['push']['alerts']
}): Promise => {
const formData = new FormData()
diff --git a/src/utils/slices/instances/updatePushDecode.ts b/src/utils/slices/instances/updatePushDecode.ts
index ac215263..2e8e21a7 100644
--- a/src/utils/slices/instances/updatePushDecode.ts
+++ b/src/utils/slices/instances/updatePushDecode.ts
@@ -1,19 +1,17 @@
import apiTooot from '@api/tooot'
import { createAsyncThunk } from '@reduxjs/toolkit'
-import i18n from '@root/i18n/i18n'
import { RootState } from '@root/store'
import { InstanceLatest } from '@utils/migrations/instances/migration'
-import * as Notifications from 'expo-notifications'
import { Platform } from 'react-native'
import { getInstance } from '../instancesSlice'
-import androidDefaults from './push/androidDefaults'
+import { setChannels } from './push/utils'
export const updateInstancePushDecode = createAsyncThunk(
'instances/updatePushDecode',
async (
disable: boolean,
{ getState }
- ): Promise<{ disable: InstanceLatest['push']['decode']['value'] }> => {
+ ): Promise<{ disable: InstanceLatest['push']['decode'] }> => {
const state = getState() as RootState
const instance = getInstance(state)
if (!instance?.url || !instance.account.id || !instance.push.keys) {
@@ -34,54 +32,7 @@ export const updateInstancePushDecode = createAsyncThunk(
})
if (Platform.OS === 'android') {
- const accountFull = `@${instance.account.acct}@${instance.uri}`
- switch (disable) {
- case true:
- Notifications.deleteNotificationChannelAsync(`${accountFull}_default`)
- Notifications.setNotificationChannelAsync(`${accountFull}_follow`, {
- groupId: accountFull,
- name: i18n.t('meSettingsPush:content.follow.heading'),
- ...androidDefaults
- })
- Notifications.setNotificationChannelAsync(
- `${accountFull}_favourite`,
- {
- groupId: accountFull,
- name: i18n.t('meSettingsPush:content.favourite.heading'),
- ...androidDefaults
- }
- )
- Notifications.setNotificationChannelAsync(`${accountFull}_reblog`, {
- groupId: accountFull,
- name: i18n.t('meSettingsPush:content.reblog.heading'),
- ...androidDefaults
- })
- Notifications.setNotificationChannelAsync(`${accountFull}_mention`, {
- groupId: accountFull,
- name: i18n.t('meSettingsPush:content.mention.heading'),
- ...androidDefaults
- })
- Notifications.setNotificationChannelAsync(`${accountFull}_poll`, {
- groupId: accountFull,
- name: i18n.t('meSettingsPush:content.poll.heading'),
- ...androidDefaults
- })
- break
- case false:
- Notifications.setNotificationChannelAsync(`${accountFull}_default`, {
- groupId: accountFull,
- name: i18n.t('meSettingsPush:content.default.heading'),
- ...androidDefaults
- })
- Notifications.deleteNotificationChannelAsync(`${accountFull}_follow`)
- Notifications.deleteNotificationChannelAsync(
- `${accountFull}_favourite`
- )
- Notifications.deleteNotificationChannelAsync(`${accountFull}_reblog`)
- Notifications.deleteNotificationChannelAsync(`${accountFull}_mention`)
- Notifications.deleteNotificationChannelAsync(`${accountFull}_poll`)
- break
- }
+ setChannels(instance)
}
return Promise.resolve({ disable })
diff --git a/src/utils/slices/instancesSlice.ts b/src/utils/slices/instancesSlice.ts
index c331301c..54ace209 100644
--- a/src/utils/slices/instancesSlice.ts
+++ b/src/utils/slices/instancesSlice.ts
@@ -73,31 +73,23 @@ const instancesSlice = createSlice({
},
clearPushLoading: ({ instances }) => {
const activeIndex = findInstanceActive(instances)
- instances[activeIndex].push.global.loading = false
- instances[activeIndex].push.decode.loading = false
- instances[activeIndex].push.alerts.favourite.loading = false
- instances[activeIndex].push.alerts.follow.loading = false
- instances[activeIndex].push.alerts.mention.loading = false
- instances[activeIndex].push.alerts.poll.loading = false
- instances[activeIndex].push.alerts.reblog.loading = false
},
disableAllPushes: ({ instances }) => {
instances = instances.map(instance => {
let newInstance = instance
- newInstance.push.global.value = false
+ newInstance.push.global = false
return newInstance
})
},
- updateInstanceTimelineLookback: (
+ updateInstanceFollowingPage: (
{ instances },
- action: PayloadAction
+ action: PayloadAction>
) => {
const activeIndex = findInstanceActive(instances)
- instances[activeIndex] &&
- (instances[activeIndex].timelinesLookback = {
- ...instances[activeIndex].timelinesLookback,
- ...action.payload
- })
+ instances[activeIndex].followingPage = {
+ ...instances[activeIndex].followingPage,
+ ...action.payload
+ }
},
updateInstanceMePage: (
{ instances },
@@ -238,48 +230,21 @@ const instancesSlice = createSlice({
// Update Instance Push Global
.addCase(updateInstancePush.fulfilled, (state, action) => {
const activeIndex = findInstanceActive(state.instances)
- state.instances[activeIndex].push.global.loading = false
- state.instances[activeIndex].push.global.value = action.meta.arg
+ state.instances[activeIndex].push.global = action.meta.arg
state.instances[activeIndex].push.keys = { auth: action.payload }
})
- .addCase(updateInstancePush.rejected, state => {
- const activeIndex = findInstanceActive(state.instances)
- state.instances[activeIndex].push.global.loading = false
- })
- .addCase(updateInstancePush.pending, state => {
- const activeIndex = findInstanceActive(state.instances)
- state.instances[activeIndex].push.global.loading = true
- })
// Update Instance Push Decode
.addCase(updateInstancePushDecode.fulfilled, (state, action) => {
const activeIndex = findInstanceActive(state.instances)
- state.instances[activeIndex].push.decode.loading = false
- state.instances[activeIndex].push.decode.value = action.payload.disable
- })
- .addCase(updateInstancePushDecode.rejected, state => {
- const activeIndex = findInstanceActive(state.instances)
- state.instances[activeIndex].push.decode.loading = false
- })
- .addCase(updateInstancePushDecode.pending, state => {
- const activeIndex = findInstanceActive(state.instances)
- state.instances[activeIndex].push.decode.loading = true
+ state.instances[activeIndex].push.decode = action.payload.disable
})
// Update Instance Push Individual Alert
.addCase(updateInstancePushAlert.fulfilled, (state, action) => {
const activeIndex = findInstanceActive(state.instances)
- state.instances[activeIndex].push.alerts[action.meta.arg.changed].loading = false
state.instances[activeIndex].push.alerts = action.payload
})
- .addCase(updateInstancePushAlert.rejected, (state, action) => {
- const activeIndex = findInstanceActive(state.instances)
- state.instances[activeIndex].push.alerts[action.meta.arg.changed].loading = false
- })
- .addCase(updateInstancePushAlert.pending, (state, action) => {
- const activeIndex = findInstanceActive(state.instances)
- state.instances[activeIndex].push.alerts[action.meta.arg.changed].loading = true
- })
// Check if frequently used emojis still exist
.addCase(checkEmojis.fulfilled, (state, action) => {
@@ -394,8 +359,8 @@ export const getInstanceNotificationsFilter = ({ instances: { instances } }: Roo
export const getInstancePush = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.push
-export const getInstanceTimelinesLookback = ({ instances: { instances } }: RootState) =>
- instances[findInstanceActive(instances)]?.timelinesLookback
+export const getInstanceFollowingPage = ({ instances: { instances } }: RootState) =>
+ instances[findInstanceActive(instances)]?.followingPage
export const getInstanceMePage = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.mePage
@@ -412,9 +377,8 @@ export const {
updateInstanceNotificationsFilter,
updateInstanceDraft,
removeInstanceDraft,
- clearPushLoading,
disableAllPushes,
- updateInstanceTimelineLookback,
+ updateInstanceFollowingPage,
updateInstanceMePage,
countInstanceEmoji
} = instancesSlice.actions
diff --git a/src/utils/styles/constants.ts b/src/utils/styles/constants.ts
index 8a9415b2..e20c5546 100644
--- a/src/utils/styles/constants.ts
+++ b/src/utils/styles/constants.ts
@@ -21,5 +21,5 @@ export const StyleConstants = {
Global: { PagePadding: Base * 4 }
},
- Avatar: { S: 40, M: 48, L: 96 }
+ Avatar: { XS: 32, S: 40, M: 48, L: 96 }
}
diff --git a/src/utils/styles/layoutAnimation.ts b/src/utils/styles/layoutAnimation.ts
index 310a4d02..9bd780a5 100644
--- a/src/utils/styles/layoutAnimation.ts
+++ b/src/utils/styles/layoutAnimation.ts
@@ -1,6 +1,10 @@
-import { LayoutAnimation } from 'react-native'
+import { AccessibilityInfo, LayoutAnimation } from 'react-native'
+
+const layoutAnimation = async () => {
+ const disable = await AccessibilityInfo.isReduceMotionEnabled()
+ if (disable) return
-const layoutAnimation = () =>
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
+}
export default layoutAnimation
diff --git a/yarn.lock b/yarn.lock
index 05ef3028..365093e4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -25,9 +25,9 @@
"@babel/highlight" "^7.18.6"
"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.0", "@babel/compat-data@^7.20.1":
- version "7.20.1"
- resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.1.tgz#f2e6ef7790d8c8dbf03d379502dcc246dcce0b30"
- integrity sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==
+ version "7.20.5"
+ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.5.tgz#86f172690b093373a933223b4745deeb6049e733"
+ integrity sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==
"@babel/core@7.9.0":
version "7.9.0"
@@ -51,28 +51,7 @@
semver "^5.4.1"
source-map "^0.5.0"
-"@babel/core@^7.13.16", "@babel/core@^7.14.0":
- version "7.20.2"
- resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.20.2.tgz#8dc9b1620a673f92d3624bd926dc49a52cf25b92"
- integrity sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==
- dependencies:
- "@ampproject/remapping" "^2.1.0"
- "@babel/code-frame" "^7.18.6"
- "@babel/generator" "^7.20.2"
- "@babel/helper-compilation-targets" "^7.20.0"
- "@babel/helper-module-transforms" "^7.20.2"
- "@babel/helpers" "^7.20.1"
- "@babel/parser" "^7.20.2"
- "@babel/template" "^7.18.10"
- "@babel/traverse" "^7.20.1"
- "@babel/types" "^7.20.2"
- convert-source-map "^1.7.0"
- debug "^4.1.0"
- gensync "^1.0.0-beta.2"
- json5 "^2.2.1"
- semver "^6.3.0"
-
-"@babel/core@^7.20.5":
+"@babel/core@^7.13.16", "@babel/core@^7.14.0", "@babel/core@^7.20.5":
version "7.20.5"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.20.5.tgz#45e2114dc6cd4ab167f81daf7820e8fa1250d113"
integrity sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==
@@ -93,16 +72,7 @@
json5 "^2.2.1"
semver "^6.3.0"
-"@babel/generator@^7.14.0", "@babel/generator@^7.20.1", "@babel/generator@^7.20.2", "@babel/generator@^7.9.0":
- version "7.20.4"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.4.tgz#4d9f8f0c30be75fd90a0562099a26e5839602ab8"
- integrity sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA==
- dependencies:
- "@babel/types" "^7.20.2"
- "@jridgewell/gen-mapping" "^0.3.2"
- jsesc "^2.5.1"
-
-"@babel/generator@^7.20.5":
+"@babel/generator@^7.14.0", "@babel/generator@^7.20.5", "@babel/generator@^7.9.0":
version "7.20.5"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.5.tgz#cb25abee3178adf58d6814b68517c62bdbfdda95"
integrity sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==
@@ -136,10 +106,10 @@
browserslist "^4.21.3"
semver "^6.3.0"
-"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.20.2":
- version "7.20.2"
- resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.2.tgz#3c08a5b5417c7f07b5cf3dfb6dc79cbec682e8c2"
- integrity sha512-k22GoYRAHPYr9I+Gvy2ZQlAe5mGy8BqWst2wRt8cwIufWTxrsVshhIBvYNqC80N0GSFWTsqRVexOtfzlgOEDvA==
+"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.20.2", "@babel/helper-create-class-features-plugin@^7.20.5":
+ version "7.20.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.5.tgz#327154eedfb12e977baa4ecc72e5806720a85a06"
+ integrity sha512-3RCdA/EmEaikrhayahwToF0fpweU/8o2p8vhc1c/1kftHOdTKuC65kik/TLc+qfbS8JKw4qqJbne4ovICDhmww==
dependencies:
"@babel/helper-annotate-as-pure" "^7.18.6"
"@babel/helper-environment-visitor" "^7.18.9"
@@ -149,13 +119,13 @@
"@babel/helper-replace-supers" "^7.19.1"
"@babel/helper-split-export-declaration" "^7.18.6"
-"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.19.0":
- version "7.19.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz#7976aca61c0984202baca73d84e2337a5424a41b"
- integrity sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==
+"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.20.5":
+ version "7.20.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz#5ea79b59962a09ec2acf20a963a01ab4d076ccca"
+ integrity sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==
dependencies:
"@babel/helper-annotate-as-pure" "^7.18.6"
- regexpu-core "^5.1.0"
+ regexpu-core "^5.2.1"
"@babel/helper-define-polyfill-provider@^0.3.3":
version "0.3.3"
@@ -294,25 +264,16 @@
integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==
"@babel/helper-wrap-function@^7.18.9":
- version "7.19.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz#89f18335cff1152373222f76a4b37799636ae8b1"
- integrity sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==
+ version "7.20.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz#75e2d84d499a0ab3b31c33bcfe59d6b8a45f62e3"
+ integrity sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==
dependencies:
"@babel/helper-function-name" "^7.19.0"
"@babel/template" "^7.18.10"
- "@babel/traverse" "^7.19.0"
- "@babel/types" "^7.19.0"
+ "@babel/traverse" "^7.20.5"
+ "@babel/types" "^7.20.5"
-"@babel/helpers@^7.20.1", "@babel/helpers@^7.9.0":
- version "7.20.1"
- resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.20.1.tgz#2ab7a0fcb0a03b5bf76629196ed63c2d7311f4c9"
- integrity sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==
- dependencies:
- "@babel/template" "^7.18.10"
- "@babel/traverse" "^7.20.1"
- "@babel/types" "^7.20.0"
-
-"@babel/helpers@^7.20.5":
+"@babel/helpers@^7.20.5", "@babel/helpers@^7.9.0":
version "7.20.6"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.20.6.tgz#e64778046b70e04779dfbdf924e7ebb45992c763"
integrity sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==
@@ -330,12 +291,7 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
-"@babel/parser@^7.13.16", "@babel/parser@^7.14.0", "@babel/parser@^7.18.10", "@babel/parser@^7.20.1", "@babel/parser@^7.20.2", "@babel/parser@^7.9.0":
- version "7.20.3"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.3.tgz#5358cf62e380cf69efcb87a7bb922ff88bfac6e2"
- integrity sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==
-
-"@babel/parser@^7.20.5":
+"@babel/parser@^7.13.16", "@babel/parser@^7.14.0", "@babel/parser@^7.18.10", "@babel/parser@^7.20.5", "@babel/parser@^7.9.0":
version "7.20.5"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.5.tgz#7f3c7335fe417665d929f34ae5dceae4c04015e8"
integrity sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==
@@ -384,11 +340,11 @@
"@babel/plugin-syntax-class-static-block" "^7.14.5"
"@babel/plugin-proposal-decorators@^7.12.9":
- version "7.20.2"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.20.2.tgz#1c6c32b2a44b154ebeec2bb534f9eaebdb541fb6"
- integrity sha512-nkBH96IBmgKnbHQ5gXFrcmez+Z9S2EIDKDQGp005ROqBigc88Tky4rzCnlP/lnlj245dCEQl4/YyV0V1kYh5dw==
+ version "7.20.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.20.5.tgz#28ba1a0e5044664a512967a19407d7fc26925394"
+ integrity sha512-Lac7PpRJXcC3s9cKsBfl+uc+DYXU5FD06BrTFunQO6QIQT+DwyzDPURAowI3bcvD1dZF/ank1Z5rstUJn3Hn4Q==
dependencies:
- "@babel/helper-create-class-features-plugin" "^7.20.2"
+ "@babel/helper-create-class-features-plugin" "^7.20.5"
"@babel/helper-plugin-utils" "^7.20.2"
"@babel/helper-replace-supers" "^7.19.1"
"@babel/helper-split-export-declaration" "^7.18.6"
@@ -487,13 +443,13 @@
"@babel/helper-plugin-utils" "^7.18.6"
"@babel/plugin-proposal-private-property-in-object@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz#a64137b232f0aca3733a67eb1a144c192389c503"
- integrity sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==
+ version "7.20.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz#309c7668f2263f1c711aa399b5a9a6291eef6135"
+ integrity sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==
dependencies:
"@babel/helper-annotate-as-pure" "^7.18.6"
- "@babel/helper-create-class-features-plugin" "^7.18.6"
- "@babel/helper-plugin-utils" "^7.18.6"
+ "@babel/helper-create-class-features-plugin" "^7.20.5"
+ "@babel/helper-plugin-utils" "^7.20.2"
"@babel/plugin-syntax-private-property-in-object" "^7.14.5"
"@babel/plugin-proposal-unicode-property-regex@^7.18.6", "@babel/plugin-proposal-unicode-property-regex@^7.4.4":
@@ -668,9 +624,9 @@
"@babel/helper-plugin-utils" "^7.18.6"
"@babel/plugin-transform-block-scoping@^7.0.0", "@babel/plugin-transform-block-scoping@^7.20.2":
- version "7.20.2"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.2.tgz#f59b1767e6385c663fd0bce655db6ca9c8b236ed"
- integrity sha512-y5V15+04ry69OV2wULmwhEA6jwSWXO1TwAtIwiPXcvHcoOQUqpyMVd2bDsQJMW8AurjulIyUV8kDqtjSwHy1uQ==
+ version "7.20.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.5.tgz#401215f9dc13dc5262940e2e527c9536b3d7f237"
+ integrity sha512-WvpEIW9Cbj9ApF3yJCjIEEf1EiNJLtXagOrL5LNWEZOo3jv8pmPoYTSNJQvqej8OavVlgOoOPw6/htGZro6IkA==
dependencies:
"@babel/helper-plugin-utils" "^7.20.2"
@@ -800,12 +756,12 @@
"@babel/helper-plugin-utils" "^7.18.6"
"@babel/plugin-transform-named-capturing-groups-regex@^7.0.0", "@babel/plugin-transform-named-capturing-groups-regex@^7.19.1":
- version "7.19.1"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz#ec7455bab6cd8fb05c525a94876f435a48128888"
- integrity sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==
+ version "7.20.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz#626298dd62ea51d452c3be58b285d23195ba69a8"
+ integrity sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==
dependencies:
- "@babel/helper-create-regexp-features-plugin" "^7.19.0"
- "@babel/helper-plugin-utils" "^7.19.0"
+ "@babel/helper-create-regexp-features-plugin" "^7.20.5"
+ "@babel/helper-plugin-utils" "^7.20.2"
"@babel/plugin-transform-new-target@^7.18.6":
version "7.18.6"
@@ -830,9 +786,9 @@
"@babel/helper-replace-supers" "^7.18.6"
"@babel/plugin-transform-parameters@^7.0.0", "@babel/plugin-transform-parameters@^7.20.1":
- version "7.20.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.3.tgz#7b3468d70c3c5b62e46be0a47b6045d8590fb748"
- integrity sha512-oZg/Fpx0YDrj13KsLyO8I/CX3Zdw7z0O9qOd95SqcoIzuqy/WTGWvePeHAnZCN54SfdyjHcb1S30gc8zlzlHcA==
+ version "7.20.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.5.tgz#f8f9186c681d10c3de7620c916156d893c8a019e"
+ integrity sha512-h7plkOmcndIUWXZFLgpbrh2+fXAi47zcUX7IrOQuZdLD0I0KvjJ6cvo3BEcAOsDOcZhVKGJqv07mkSqK0y2isQ==
dependencies:
"@babel/helper-plugin-utils" "^7.20.2"
@@ -891,12 +847,12 @@
"@babel/helper-plugin-utils" "^7.18.6"
"@babel/plugin-transform-regenerator@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz#585c66cb84d4b4bf72519a34cfce761b8676ca73"
- integrity sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==
+ version "7.20.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz#57cda588c7ffb7f4f8483cc83bdcea02a907f04d"
+ integrity sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.18.6"
- regenerator-transform "^0.15.0"
+ "@babel/helper-plugin-utils" "^7.20.2"
+ regenerator-transform "^0.15.1"
"@babel/plugin-transform-reserved-words@^7.18.6":
version "7.18.6"
@@ -1117,14 +1073,7 @@
dependencies:
regenerator-runtime "^0.13.4"
-"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.0", "@babel/runtime@^7.14.5", "@babel/runtime@^7.17.2", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
- version "7.20.1"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.1.tgz#1148bb33ab252b165a06698fde7576092a78b4a9"
- integrity sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==
- dependencies:
- regenerator-runtime "^0.13.10"
-
-"@babel/runtime@^7.13.10":
+"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.0", "@babel/runtime@^7.14.5", "@babel/runtime@^7.20.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
version "7.20.6"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.6.tgz#facf4879bfed9b5326326273a64220f099b0fce3"
integrity sha512-Q+8MqP7TiHMWzSfwiJwXCjyf4GYA4Dgw3emg/7xmwsdLJOZUp+nMqcOwOzzYheuM1rhDu8FSj2l0aoMygEuXuA==
@@ -1140,23 +1089,7 @@
"@babel/parser" "^7.18.10"
"@babel/types" "^7.18.10"
-"@babel/traverse@^7.14.0", "@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.20.1", "@babel/traverse@^7.9.0":
- version "7.20.1"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.1.tgz#9b15ccbf882f6d107eeeecf263fbcdd208777ec8"
- integrity sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==
- dependencies:
- "@babel/code-frame" "^7.18.6"
- "@babel/generator" "^7.20.1"
- "@babel/helper-environment-visitor" "^7.18.9"
- "@babel/helper-function-name" "^7.19.0"
- "@babel/helper-hoist-variables" "^7.18.6"
- "@babel/helper-split-export-declaration" "^7.18.6"
- "@babel/parser" "^7.20.1"
- "@babel/types" "^7.20.0"
- debug "^4.1.0"
- globals "^11.1.0"
-
-"@babel/traverse@^7.20.5":
+"@babel/traverse@^7.14.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.20.1", "@babel/traverse@^7.20.5", "@babel/traverse@^7.9.0":
version "7.20.5"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.5.tgz#78eb244bea8270fdda1ef9af22a5d5e5b7e57133"
integrity sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==
@@ -1172,16 +1105,7 @@
debug "^4.1.0"
globals "^11.1.0"
-"@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.4.4", "@babel/types@^7.9.0":
- version "7.20.2"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.2.tgz#67ac09266606190f496322dbaff360fdaa5e7842"
- integrity sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==
- dependencies:
- "@babel/helper-string-parser" "^7.19.4"
- "@babel/helper-validator-identifier" "^7.19.1"
- to-fast-properties "^2.0.0"
-
-"@babel/types@^7.20.5":
+"@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.4.4", "@babel/types@^7.9.0":
version "7.20.5"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.5.tgz#e206ae370b5393d94dfd1d04cd687cace53efa84"
integrity sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==
@@ -1865,7 +1789,7 @@
resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
-"@graphql-typed-document-node/core@^3.1.0", "@graphql-typed-document-node/core@^3.1.1":
+"@graphql-typed-document-node/core@^3.1.0":
version "3.1.1"
resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.1.1.tgz#076d78ce99822258cf813ecc1e7fa460fa74d052"
integrity sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==
@@ -1956,10 +1880,10 @@
"@jridgewell/resolve-uri" "3.1.0"
"@jridgewell/sourcemap-codec" "1.4.14"
-"@mattermost/react-native-paste-input@^0.5.1":
- version "0.5.1"
- resolved "https://registry.yarnpkg.com/@mattermost/react-native-paste-input/-/react-native-paste-input-0.5.1.tgz#2d24b2d4a9fdb0aaefda6df8d9c64380ac731dc1"
- integrity sha512-2ZXohoSJbLyItzvdT3dyjlC7tvDBEXqvzxhKUHs4OnIslYZzHso9gfqjIZNfet8ryhYAJ3CgB+xCmP5u7ouFtQ==
+"@mattermost/react-native-paste-input@^0.5.2":
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/@mattermost/react-native-paste-input/-/react-native-paste-input-0.5.2.tgz#7443490f5c90f3c3db0f847c8b7249d23fa0066f"
+ integrity sha512-aQdLUidSAbWPLXWmwM1x8AhnZIO4EN5uWx813/G3+mL8kWD7mpXrQEvMpcdtKWatD705kCyKZkvnNY4yjq0TkA==
dependencies:
deprecated-react-native-prop-types "^2.3.0"
@@ -2269,10 +2193,10 @@
dependencies:
merge-options "^3.0.4"
-"@react-native-camera-roll/camera-roll@^5.1.0":
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/@react-native-camera-roll/camera-roll/-/camera-roll-5.1.0.tgz#5cfb3cf02d72ab03b3d6a0bdda392e2896c8d55f"
- integrity sha512-74pavpt2T2U3V0r5d+pn4NChJbRNcydqakp3NVmosod35Lzxrt9My7kCLDdHXW2S6J6DhgXb/n36/heZQB4AUA==
+"@react-native-camera-roll/camera-roll@^5.2.0":
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/@react-native-camera-roll/camera-roll/-/camera-roll-5.2.0.tgz#a30dca7c486379650c03fb8cc6fe35b7de6eeb82"
+ integrity sha512-CIFkEqWeMtFo3fG/0nULrmLs8xikbOUuEty8wWxpyBWq7OM9Hi13pXJ1FWrIrxDcFuL7d0bxIqpqNrt59lAPrQ==
"@react-native-clipboard/clipboard@^1.11.1":
version "1.11.1"
@@ -2480,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.4.3":
- version "6.4.3"
- resolved "https://registry.yarnpkg.com/@react-navigation/bottom-tabs/-/bottom-tabs-6.4.3.tgz#38498ade0e03294d7ba7fdcd96ab347c7ad1eb04"
- integrity sha512-nkuHJ31mEyrZZPswfMAHZgUTEm11ohN9Fy54wao2HFk1VM4eplijX6pFGycA4yhKy73A/aesKhghVPzR+FaSmg==
+"@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.9"
+ "@react-navigation/elements" "^1.3.11"
color "^4.2.3"
warn-once "^0.1.0"
-"@react-navigation/core@^6.4.3":
- version "6.4.3"
- resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-6.4.3.tgz#5609bab95e3080d190eff46a64e52cc06eb0c4cf"
- integrity sha512-+HGHeEq7GK029Jy2jFkV2uQYc6a6AurjjUAVFlSz5tsNo4L5E3ZCzo7sk5+lcvt0Agdedf5Q+wTiWjT7IrixgA==
+"@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.0.0"
+ query-string "^7.1.3"
react-is "^16.13.0"
use-latest-callback "^0.1.5"
-"@react-navigation/elements@^1.3.9":
- version "1.3.9"
- resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-1.3.9.tgz#33e26d7ad655b012e024ef0a005a3f66201287f8"
- integrity sha512-V9aIZN19ufaKWlXT4UcM545tDiEt9DIQS+74pDgbnzoQcDypn0CvSqWopFhPACMdJatgmlZUuOrrMfTeNrBWgA==
+"@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.4":
- version "6.9.4"
- resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-6.9.4.tgz#d9cc26ad97afcee1c0e3fb092ae4c60f848b1572"
- integrity sha512-R40G2Zfo748hE4+we/TUAEClw53l0QdFDJ0q/9VS1moxgI4zUopdBxN5SmF32OMFfkedMRAT9J+aVbwgmdn7pA==
+"@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.9"
+ "@react-navigation/elements" "^1.3.11"
warn-once "^0.1.0"
-"@react-navigation/native@^6.0.16":
- version "6.0.16"
- resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-6.0.16.tgz#a37df62da9db912c91c53e2cdeadb954865a6a9b"
- integrity sha512-YVmzypkDppV/vAG+66KTJ2RFtPjhDTLLjgk8TNTCHG3pahq1q13zbnEPjqB42bU4kgL5SG17O4saErt1DJaWQg==
+"@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.3"
+ "@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.7":
- version "6.3.7"
- resolved "https://registry.yarnpkg.com/@react-navigation/stack/-/stack-6.3.7.tgz#a2c0e08c8cc8696da203eba6905025ce8665f40a"
- integrity sha512-M0gGeIpXmY08ZxZlHO9o/NLj9lO4zGdTll+a9e40BwfSxR5v6R34msKHUJ57nxrzvr2/MSSllZRkW3wc8woKFg==
+"@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.9"
+ "@react-navigation/elements" "^1.3.11"
color "^4.2.3"
warn-once "^0.1.0"
@@ -2558,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":
@@ -2594,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.10.1":
- version "4.10.1"
- resolved "https://registry.yarnpkg.com/@sentry/react-native/-/react-native-4.10.1.tgz#9e2c1f5dd4b27103882a71503805f86059a7cde9"
- integrity sha512-yF5g2bCjPpfu4DUVQPlDnSMUdz5bh/i1s9zZ5cnOmA9LsXQulk9o1Z6fTeZ5LkgPzogTRjn0eudvaCz5u+nxaA==
+"@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":
@@ -2736,6 +2660,19 @@
dependencies:
defer-to-connect "^2.0.0"
+"@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.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.20.4"
+ use-sync-external-store "^1.2.0"
+
"@types/cacheable-request@^6.0.1":
version "6.0.3"
resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183"
@@ -2746,6 +2683,11 @@
"@types/node" "*"
"@types/responselike" "^1.0.0"
+"@types/diff@^5.0.2":
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/@types/diff/-/diff-5.0.2.tgz#dd565e0086ccf8bc6522c6ebafd8a3125c91c12b"
+ integrity sha512-uw8eYMIReOwstQ0QKF0sICefSy8cNO/v7gOTiIy9SbwuHyEecJUm7qlgueOO5S1udZ5I/irVydHVwMchgzbKTg==
+
"@types/glob@^7.1.1":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb"
@@ -2829,9 +2771,9 @@
integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==
"@types/node@*":
- version "18.11.9"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4"
- integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==
+ 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"
@@ -2865,10 +2807,10 @@
resolved "https://registry.yarnpkg.com/@types/react-native-share-menu/-/react-native-share-menu-5.0.2.tgz#c9c8854a3d091cdb046df22dafe4a92332b322f3"
integrity sha512-Qa9DGfL6Bvng2DXgCK0fFzdi9SJMGfs06MLSkCfSXBCGKlFLzSHCsXztvXlCCChn3dQArFHyz/uRUN3Sbt6LtQ==
-"@types/react-native@~0.70.7":
- version "0.70.7"
- resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.70.7.tgz#1708e5f746bbce2ea4e0bd5a2627560667804d46"
- integrity sha512-hBzeUWwk8sfj3vDfwEXb4hbjWjl0jb5CvWlu2gLrOUJyFHVzJ+x6Y9ilO2eVtJW7l5QmmNLILE1PkVfKRkqYuQ==
+"@types/react-native@~0.70.8":
+ version "0.70.8"
+ resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.70.8.tgz#3302a0f7eddcd3350448ca17a9e415d02b1efde6"
+ integrity sha512-jvs5QMOrlyi0ScfT5Brha2roDoOWtbIOadNkp0jsueVen5+pH4SQAYtzL6xu0+dIcx3J/5LtZ/JYby2C1/zUug==
dependencies:
"@types/react" "*"
@@ -2879,16 +2821,7 @@
dependencies:
"@types/react" "*"
-"@types/react@*", "@types/react@16 || 17 || 18":
- version "18.0.25"
- resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.25.tgz#8b1dcd7e56fe7315535a4af25435e0bb55c8ae44"
- integrity sha512-xD6c0KDT4m7n9uD4ZHi02lzskaiqcBxf4zi+tXZY98a04wvc0hi/TcCPC2FOESZi51Nd7tlUeOJY8RofL799/g==
- dependencies:
- "@types/prop-types" "*"
- "@types/scheduler" "*"
- csstype "^3.0.2"
-
-"@types/react@~18.0.26":
+"@types/react@*", "@types/react@16 || 17 || 18", "@types/react@~18.0.26":
version "18.0.26"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.26.tgz#8ad59fc01fef8eaf5c74f4ea392621749f0b7917"
integrity sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==
@@ -2990,12 +2923,11 @@
wonka "^4.0.14"
"@urql/core@>=2.3.1":
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/@urql/core/-/core-3.0.5.tgz#a26c326dd788d6d6abb839493bce86147f5a45c9"
- integrity sha512-6/1HG+WEAcPs+hXSFnxWBTWkNUwa8dj2cHysWokMaFIbAioGtUaSdxp2q9FDMtWAIGdc640NFSt2B8itGLdoAA==
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/@urql/core/-/core-3.1.1.tgz#a49cd572360d01f2469a786b294fba2269a65e53"
+ integrity sha512-Mnxtq4I4QeFJsgs7Iytw+HyhiGxISR6qtyk66c9tipozLZ6QVxrCiUPF2HY4BxNIabaxcp+rivadvm8NAnXj4Q==
dependencies:
- "@graphql-typed-document-node/core" "^3.1.1"
- wonka "^6.0.0"
+ wonka "^6.1.2"
"@urql/exchange-retry@0.3.0":
version "0.3.0"
@@ -3255,9 +3187,9 @@ ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.4, ajv@^6.12.5:
uri-js "^4.2.2"
ajv@^8.0.0, ajv@^8.1.0:
- version "8.11.0"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f"
- integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==
+ version "8.11.2"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.2.tgz#aecb20b50607acf2569b6382167b65a96008bb78"
+ integrity sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==
dependencies:
fast-deep-equal "^3.1.1"
json-schema-traverse "^1.0.0"
@@ -3360,9 +3292,9 @@ anymatch@^2.0.0:
normalize-path "^2.1.1"
anymatch@^3.0.0, anymatch@^3.0.3, anymatch@~3.1.2:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
- integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
+ integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
dependencies:
normalize-path "^3.0.0"
picomatch "^2.0.4"
@@ -3373,9 +3305,9 @@ appdirsjs@^1.2.4:
integrity sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==
application-config-path@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/application-config-path/-/application-config-path-0.1.0.tgz#193c5f0a86541a4c66fba1e2dc38583362ea5e8f"
- integrity sha512-lljTpVvFteShrHuKRvweZfa9o/Nc34Y8r5/1Lqh/yyKaspRT2J3fkEiSSk1YLG8ZSVyU7yHysRy9zcDDS2aH1Q==
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/application-config-path/-/application-config-path-0.1.1.tgz#8b5ac64ff6afdd9bd70ce69f6f64b6998f5f756e"
+ integrity sha512-zy9cHePtMP0YhwG+CfHm0bgwdnga2X3gZexpdCwEj//dpb+TKajtiC8REEUJUSq6Ab4f9cgNy2l8ObXzCXFkEw==
aproba@^1.0.3, aproba@^1.1.1:
version "1.2.0"
@@ -3581,13 +3513,14 @@ axios@0.21.1:
dependencies:
follow-redirects "^1.10.0"
-axios@^0.27.2:
- version "0.27.2"
- resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
- integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
+axios@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-1.2.1.tgz#44cf04a3c9f0c2252ebd85975361c026cb9f864a"
+ integrity sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==
dependencies:
- follow-redirects "^1.14.9"
+ follow-redirects "^1.15.0"
form-data "^4.0.0"
+ proxy-from-env "^1.1.0"
babel-core@^7.0.0-bridge.0:
version "7.0.0-bridge.0"
@@ -3741,7 +3674,7 @@ better-opn@^3.0.1, better-opn@~3.0.2:
dependencies:
open "^8.0.4"
-big-integer@1.6.x, big-integer@^1.6.16, big-integer@^1.6.44:
+big-integer@1.6.x, big-integer@^1.6.44:
version "1.6.51"
resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686"
integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==
@@ -3937,20 +3870,6 @@ braces@^3.0.2, braces@~3.0.2:
dependencies:
fill-range "^7.0.1"
-broadcast-channel@^3.4.1:
- version "3.7.0"
- resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.7.0.tgz#2dfa5c7b4289547ac3f6705f9c00af8723889937"
- integrity sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==
- dependencies:
- "@babel/runtime" "^7.7.2"
- detect-node "^2.1.0"
- js-sha3 "0.8.0"
- microseconds "0.2.0"
- nano-time "1.0.0"
- oblivious-set "1.0.0"
- rimraf "3.0.2"
- unload "2.2.0"
-
brorand@^1.0.1, brorand@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
@@ -4276,9 +4195,9 @@ caniuse-api@^3.0.0:
lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001125, caniuse-lite@^1.0.30001400:
- version "1.0.30001431"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz#e7c59bd1bc518fae03a4656be442ce6c4887a795"
- integrity sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==
+ version "1.0.30001439"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz#ab7371faeb4adff4b74dad1718a6fd122e45d9cb"
+ integrity sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==
caseless@^0.12.0:
version "0.12.0"
@@ -4367,9 +4286,9 @@ ci-info@^2.0.0:
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
ci-info@^3.2.0, ci-info@^3.3.0:
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.5.0.tgz#bfac2a29263de4c829d806b1ab478e35091e171f"
- integrity sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==
+ version "3.7.0"
+ resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.7.0.tgz#6d01b3696c59915b6ce057e4aa4adfc2fa25f5ef"
+ integrity sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==
cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
version "1.0.4"
@@ -4791,9 +4710,9 @@ copy-webpack-plugin@~6.0.3:
webpack-sources "^1.4.3"
core-js-compat@^3.25.1:
- version "3.26.0"
- resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.26.0.tgz#94e2cf8ba3e63800c4956ea298a6473bc9d62b44"
- integrity sha512-piOX9Go+Z4f9ZiBFLnZ5VrOpBl0h7IGCkiFUN11QTe6LjAvOT3ifL/5TdoizMh99hcGy5SoLyWbapIY/PIb/3A==
+ version "3.26.1"
+ resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.26.1.tgz#0e710b09ebf689d719545ac36e49041850f943df"
+ integrity sha512-622/KzTudvXCDLRw70iHW4KKs1aGpcRcowGWyYJr2DEBfRrd6hNJybxSWJFuZYD4ma86xhrwDDHxmDaIq4EA8A==
dependencies:
browserslist "^4.21.4"
@@ -5103,9 +5022,9 @@ dateformat@3.0.3:
integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
dayjs@^1.8.15:
- version "1.11.6"
- resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.6.tgz#2e79a226314ec3ec904e3ee1dd5a4f5e5b1c7afb"
- integrity sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==
+ version "1.11.7"
+ resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.7.tgz#4b296922642f70999544d1144a2c25730fce63e2"
+ integrity sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==
debug@2, debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0:
version "2.6.9"
@@ -5140,7 +5059,7 @@ decamelize@^1.2.0:
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==
-decode-uri-component@^0.2.0:
+decode-uri-component@^0.2.0, decode-uri-component@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9"
integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==
@@ -5330,7 +5249,7 @@ detect-node-es@^1.1.0:
resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493"
integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==
-detect-node@^2.0.4, detect-node@^2.1.0:
+detect-node@^2.0.4:
version "2.1.0"
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1"
integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
@@ -5343,6 +5262,11 @@ detect-port-alt@1.1.6:
address "^1.0.1"
debug "^2.6.0"
+diff@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40"
+ integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==
+
diffie-hellman@^5.0.0:
version "5.0.3"
resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
@@ -5645,9 +5569,9 @@ errorhandler@^1.5.0:
escape-html "~1.0.3"
es-abstract@^1.17.2, es-abstract@^1.19.0, es-abstract@^1.20.4:
- version "1.20.4"
- resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.4.tgz#1d103f9f8d78d4cf0713edcd6d0ed1a46eed5861"
- integrity sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==
+ version "1.20.5"
+ resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.5.tgz#e6dc99177be37cacda5988e692c3fa8b218e95d2"
+ integrity sha512-7h8MM2EQhsCA7pU/Nv78qOXFpD8Rhqd12gYiSJVkrH9+e8VuA8JlPJK/hQjjlLv6pJvx/z1iRFKzYb0XT/RuAQ==
dependencies:
call-bind "^1.0.2"
es-to-primitive "^1.2.1"
@@ -5655,6 +5579,7 @@ es-abstract@^1.17.2, es-abstract@^1.19.0, es-abstract@^1.20.4:
function.prototype.name "^1.1.5"
get-intrinsic "^1.1.3"
get-symbol-description "^1.0.0"
+ gopd "^1.0.1"
has "^1.0.3"
has-property-descriptors "^1.0.0"
has-symbols "^1.0.3"
@@ -5670,8 +5595,8 @@ es-abstract@^1.17.2, es-abstract@^1.19.0, es-abstract@^1.20.4:
object.assign "^4.1.4"
regexp.prototype.flags "^1.4.3"
safe-regex-test "^1.0.0"
- string.prototype.trimend "^1.0.5"
- string.prototype.trimstart "^1.0.5"
+ string.prototype.trimend "^1.0.6"
+ string.prototype.trimstart "^1.0.6"
unbox-primitive "^1.0.2"
es-array-method-boxes-properly@^1.0.0:
@@ -6239,9 +6164,9 @@ fast-json-stable-stringify@^2.0.0:
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
fastq@^1.6.0:
- version "1.13.0"
- resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
- integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==
+ version "1.14.0"
+ resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.14.0.tgz#107f69d7295b11e0fccc264e1fc6389f623731ce"
+ integrity sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==
dependencies:
reusify "^1.0.4"
@@ -6444,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.192.0"
- resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.192.0.tgz#e2aa03e0c6a844c4d6ccdb4af2bc83cc589d9c8c"
- integrity sha512-FLyei0ikf4ab9xlg+05WNmdpOODiH9XVBuw7iI9OZyjIo+cX2L2OUPTovjbWLYLlI41oGTcprbKdB/f9XwBnKw==
+ 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"
@@ -6461,7 +6386,7 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
-follow-redirects@^1.0.0, follow-redirects@^1.10.0, follow-redirects@^1.14.9:
+follow-redirects@^1.0.0, follow-redirects@^1.10.0, follow-redirects@^1.15.0:
version "1.15.2"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
@@ -6679,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==
@@ -6844,9 +6769,9 @@ gopd@^1.0.1:
get-intrinsic "^1.1.3"
got@^11.1.4:
- version "11.8.5"
- resolved "https://registry.yarnpkg.com/got/-/got-11.8.5.tgz#ce77d045136de56e8f024bebb82ea349bc730046"
- integrity sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==
+ version "11.8.6"
+ resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a"
+ integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==
dependencies:
"@sindresorhus/is" "^4.0.0"
"@szmarczak/http-timer" "^4.0.5"
@@ -7261,12 +7186,12 @@ https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1:
agent-base "6"
debug "4"
-i18next@^22.0.6:
- version "22.0.6"
- resolved "https://registry.yarnpkg.com/i18next/-/i18next-22.0.6.tgz#d7029912f8aa74ff295c0d9afd1b7dea45859b49"
- integrity sha512-RlreNGoPIdDP4QG+qSA9PxZKGwlzmcozbI9ObI6+OyUa/Rp0EjZZA9ubyBjw887zVNZsC+7FI3sXX8oiTzAfig==
+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.17.2"
+ "@babel/runtime" "^7.20.6"
iconv-lite@0.4.23:
version "0.4.23"
@@ -7300,9 +7225,9 @@ iferr@^0.1.5:
integrity sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==
ignore@^5.1.4, ignore@^5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
- integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.1.tgz#c2b1f76cb999ede1502f3a226a9310fdfe88d46c"
+ integrity sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==
image-size@^0.6.0:
version "0.6.3"
@@ -7423,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"
@@ -7999,11 +7924,6 @@ join-component@^1.1.0:
resolved "https://registry.yarnpkg.com/join-component/-/join-component-1.1.0.tgz#b8417b750661a392bee2c2537c68b2a9d4977cd5"
integrity sha512-bF7vcQxbODoGK1imE2P9GS9aw4zD0Sd+Hni68IMZLj7zRnquH7dXUmMw9hDI5S/Jzt7q+IyTXN0rSg2GI0IKhQ==
-js-sha3@0.8.0:
- version "0.8.0"
- resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
- integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==
-
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@@ -8235,11 +8155,6 @@ leven@^3.1.0:
resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==
-li@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/li/-/li-1.3.0.tgz#22c59bcaefaa9a8ef359cf759784e4bf106aea1b"
- integrity sha512-z34TU6GlMram52Tss5mt1m//ifRIpKH5Dqm7yUVOdHI+BQCs9qGPHFaCUTIzsWX7edN30aa2WrPwR7IO10FHaw==
-
lie@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e"
@@ -8456,14 +8371,6 @@ map-visit@^1.0.0:
dependencies:
object-visit "^1.0.0"
-match-sorter@^6.0.2:
- version "6.3.1"
- resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.1.tgz#98cc37fda756093424ddf3cbc62bfe9c75b92bda"
- integrity sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw==
- dependencies:
- "@babel/runtime" "^7.12.5"
- remove-accents "0.4.2"
-
md5-file@^3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/md5-file/-/md5-file-3.2.3.tgz#f9bceb941eca2214a4c0727f5e700314e770f06f"
@@ -8873,11 +8780,6 @@ micromatch@^4.0.2, micromatch@^4.0.4:
braces "^3.0.2"
picomatch "^2.3.1"
-microseconds@0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39"
- integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==
-
miller-rabin@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
@@ -9000,9 +8902,16 @@ minipass@3.1.6:
yallist "^4.0.0"
minipass@^3.0.0, minipass@^3.1.1:
- version "3.3.4"
- resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.4.tgz#ca99f95dd77c43c7a76bf51e6d200025eee0ffae"
- integrity sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==
+ version "3.3.6"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a"
+ integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==
+ dependencies:
+ yallist "^4.0.0"
+
+minipass@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.0.0.tgz#7cebb0f9fa7d56f0c5b17853cbe28838a8dbbd3b"
+ integrity sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==
dependencies:
yallist "^4.0.0"
@@ -9118,13 +9027,6 @@ nan@^2.12.1:
resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb"
integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==
-nano-time@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef"
- integrity sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA==
- dependencies:
- big-integer "^1.6.16"
-
nanoid@^3.1.23:
version "3.3.4"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
@@ -9265,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"
@@ -9460,11 +9362,6 @@ object.values@^1.1.0:
define-properties "^1.1.4"
es-abstract "^1.20.4"
-oblivious-set@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566"
- integrity sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==
-
obuf@^1.0.0, obuf@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
@@ -10289,9 +10186,9 @@ postcss-selector-parser@^3.0.0:
uniq "^1.0.1"
postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2:
- version "6.0.10"
- resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d"
- integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==
+ version "6.0.11"
+ resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz#2e41dc39b7ad74046e1615185185cd0b17d0c8dc"
+ integrity sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==
dependencies:
cssesc "^3.0.0"
util-deprecate "^1.0.2"
@@ -10558,12 +10455,12 @@ query-string@^5.0.1:
object-assign "^4.1.0"
strict-uri-encode "^1.0.0"
-query-string@^7.0.0:
- version "7.1.1"
- resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.1.tgz#754620669db978625a90f635f12617c271a088e1"
- integrity sha512-MplouLRDHBZSG9z7fpuAAcI7aAYjDLhtsiVZsevsfaHWDS2IDdORKbSd1kWUA+V4zyva/HZoSfpwnYMMQDhb0w==
+query-string@^7.1.3:
+ version "7.1.3"
+ resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.3.tgz#a1cf90e994abb113a325804a972d98276fe02328"
+ integrity sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==
dependencies:
- decode-uri-component "^0.2.0"
+ decode-uri-component "^0.2.2"
filter-obj "^1.1.0"
split-on-first "^1.0.0"
strict-uri-encode "^2.0.0"
@@ -10725,10 +10622,10 @@ react-freeze@^1.0.0:
resolved "https://registry.yarnpkg.com/react-freeze/-/react-freeze-1.0.3.tgz#5e3ca90e682fed1d73a7cb50c2c7402b3e85618d"
integrity sha512-ZnXwLQnGzrDpHBHiC56TXFXvmolPeMjTn1UOm610M4EXGzbEDR7oOIyS2ZiItgbs6eZc4oU/a0hpk8PrcKvv5g==
-react-i18next@^12.0.0:
- version "12.0.0"
- resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-12.0.0.tgz#634015a2c035779c5736ae4c2e5c34c1659753b1"
- integrity sha512-/O7N6aIEAl1FaWZBNvhdIo9itvF/MO/nRKr9pYqRc9LhuC1u21SlfwpiYQqvaeNSEW3g3qUXLREOWMt+gxrWbg==
+react-i18next@^12.1.1:
+ version "12.1.1"
+ resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-12.1.1.tgz#2626cdbfe6bcb76ef833861c0184a5c4e5e3c089"
+ integrity sha512-mFdieOI0LDy84q3JuZU6Aou1DoWW2fhapcTGeBS8+vWSJuViuoCLQAMYSb0QoHhXS8B0WKUOPpx4cffAP7r/aA==
dependencies:
"@babel/runtime" "^7.14.5"
html-parse-stringify "^3.0.1"
@@ -10853,15 +10750,10 @@ react-native-iphone-x-helper@^1.3.1:
resolved "https://registry.yarnpkg.com/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz#20c603e9a0e765fd6f97396638bdeb0e5a60b010"
integrity sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg==
-react-native-language-detection@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/react-native-language-detection/-/react-native-language-detection-0.1.0.tgz#06b5d20bffb60dbbd599c8e62b6acf500952afa8"
- integrity sha512-26CLndVMmMbVp40Y9Herza73nfR08JFTcYkJ3MX5MIQbGRoqgNAG89z8pA1y7dPHHK1Nfa6AWKAYpNv7tMRCaw==
-
-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-language-detection@^0.2.2:
+ version "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-pager-view@^6.1.2:
version "6.1.2"
@@ -10917,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.2:
- version "3.3.2"
- resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-3.3.2.tgz#4afc995e41b97e0457e95b487763d3f9dc318dcc"
- integrity sha512-s0xr+wiMBHdjsWgbPTyZemgv7jJ+zKPBw/MIQIlKAMo4VCNV1vAZEbOHaHpGbqgYFwsmFXjKZNXQ5UJAIJXlDQ==
+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"
@@ -10962,15 +10854,6 @@ react-native@0.70.6:
whatwg-fetch "^3.0.0"
ws "^6.1.4"
-react-query@^3.39.2:
- version "3.39.2"
- resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.39.2.tgz#9224140f0296f01e9664b78ed6e4f69a0cc9216f"
- integrity sha512-F6hYDKyNgDQfQOuR1Rsp3VRzJnWHx6aRnnIZHMNGGgbL3SBgpZTDg8MQwmxOgpCAoqZJA+JSNCydF1xGJqKOCA==
- dependencies:
- "@babel/runtime" "^7.5.5"
- broadcast-channel "^3.4.1"
- match-sorter "^6.0.2"
-
react-redux@^8.0.5:
version "8.0.5"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.0.5.tgz#e5fb8331993a019b8aaf2e167a93d10af469c7bd"
@@ -11142,20 +11025,15 @@ regenerate@^1.4.2:
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a"
integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
-regenerator-runtime@^0.13.10, regenerator-runtime@^0.13.2, regenerator-runtime@^0.13.4:
- version "0.13.10"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz#ed07b19616bcbec5da6274ebc75ae95634bfc2ee"
- integrity sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==
-
-regenerator-runtime@^0.13.11:
+regenerator-runtime@^0.13.11, regenerator-runtime@^0.13.2, regenerator-runtime@^0.13.4:
version "0.13.11"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
-regenerator-transform@^0.15.0:
- version "0.15.0"
- resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.0.tgz#cbd9ead5d77fae1a48d957cf889ad0586adb6537"
- integrity sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==
+regenerator-transform@^0.15.1:
+ version "0.15.1"
+ resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.1.tgz#f6c4e99fc1b4591f780db2586328e4d9a9d8dc56"
+ integrity sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==
dependencies:
"@babel/runtime" "^7.8.4"
@@ -11176,17 +11054,17 @@ regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.4.3:
define-properties "^1.1.3"
functions-have-names "^1.2.2"
-regexpu-core@^5.1.0:
- version "5.2.1"
- resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.2.1.tgz#a69c26f324c1e962e9ffd0b88b055caba8089139"
- integrity sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==
+regexpu-core@^5.2.1:
+ version "5.2.2"
+ resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.2.2.tgz#3e4e5d12103b64748711c3aad69934d7718e75fc"
+ integrity sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==
dependencies:
regenerate "^1.4.2"
regenerate-unicode-properties "^10.1.0"
regjsgen "^0.7.1"
regjsparser "^0.9.1"
unicode-match-property-ecmascript "^2.0.0"
- unicode-match-property-value-ecmascript "^2.0.0"
+ unicode-match-property-value-ecmascript "^2.1.0"
registry-auth-token@3.3.2:
version "3.3.2"
@@ -11242,11 +11120,6 @@ relateurl@^0.2.7:
resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==
-remove-accents@0.4.2:
- version "0.4.2"
- resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.4.2.tgz#0a43d3aaae1e80db919e07ae254b285d9e1c7bb5"
- integrity sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==
-
remove-trailing-separator@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
@@ -11410,13 +11283,6 @@ rgba-regex@^1.0.0:
resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3"
integrity sha512-zgn5OjNQXLUTdq8m17KdaicF6w89TZs8ZU8y0AYENIU6wG8GG6LLm0yLSiPY8DmaYmHdgRW8rnApjoT0fQRfMg==
-rimraf@3.0.2, rimraf@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
- integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
- dependencies:
- glob "^7.1.3"
-
rimraf@^2.5.4, rimraf@^2.6.2, rimraf@^2.6.3:
version "2.7.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
@@ -11424,6 +11290,13 @@ rimraf@^2.5.4, rimraf@^2.6.2, rimraf@^2.6.3:
dependencies:
glob "^7.1.3"
+rimraf@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+ integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
+ dependencies:
+ glob "^7.1.3"
+
rimraf@~2.2.6:
version "2.2.8"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582"
@@ -11461,7 +11334,7 @@ router-ips@^1.0.0:
resolved "https://registry.yarnpkg.com/router-ips/-/router-ips-1.0.0.tgz#44e00858ebebc0133d58e40b2cd8a1fbb04203f5"
integrity sha512-yBo6F52Un/WYioXbedBGvrKIiofbwt+4cUhdqDb9fNMJBI4D4jOy7jlxxaRVEvICPKU7xMmJDtDFR6YswX/sFQ==
-rtl-detect@^1.0.2:
+rtl-detect@^1.0.2, rtl-detect@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/rtl-detect/-/rtl-detect-1.0.4.tgz#40ae0ea7302a150b96bc75af7d749607392ecac6"
integrity sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ==
@@ -12145,7 +12018,7 @@ string-width@^3.0.0, string-width@^3.1.0:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^5.1.0"
-string.prototype.trimend@^1.0.5:
+string.prototype.trimend@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533"
integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==
@@ -12154,7 +12027,7 @@ string.prototype.trimend@^1.0.5:
define-properties "^1.1.4"
es-abstract "^1.20.4"
-string.prototype.trimstart@^1.0.5:
+string.prototype.trimstart@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4"
integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==
@@ -12245,9 +12118,9 @@ stylehacks@^4.0.0:
postcss-selector-parser "^3.0.0"
sucrase@^3.20.0:
- version "3.28.0"
- resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.28.0.tgz#7fd8b3118d2155fcdf291088ab77fa6eefd63c4c"
- integrity sha512-TK9600YInjuiIhVM3729rH4ZKPOsGeyXUwY+Ugu9eilNbdTFyHr6XcAGYbRVZPDgWj6tgI7bx95aaJjHnbffag==
+ version "3.29.0"
+ resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.29.0.tgz#3207c5bc1b980fdae1e539df3f8a8a518236da7d"
+ integrity sha512-bZPAuGA5SdFHuzqIhTAqt9fvNEo9rESqXIG3oiKdF8K4UmkQxC4KlNL3lVyAErXp+mPvUqZ5l13qx6TrDIGf3A==
dependencies:
commander "^4.0.0"
glob "7.1.6"
@@ -12337,13 +12210,13 @@ tapable@^1.0.0, tapable@^1.1.3:
integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
tar@^6.0.2, tar@^6.0.5:
- version "6.1.12"
- resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.12.tgz#3b742fb05669b55671fb769ab67a7791ea1a62e6"
- integrity sha512-jU4TdemS31uABHd+Lt5WEYJuzn+TJTCBLljvIAHZOz6M9Os5pJ4dD+vRFLxPa/n3T0iEFzpi+0x1UfuDZYbRMw==
+ version "6.1.13"
+ resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.13.tgz#46e22529000f612180601a6fe0680e7da508847b"
+ integrity sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==
dependencies:
chownr "^2.0.0"
fs-minipass "^2.0.0"
- minipass "^3.0.0"
+ minipass "^4.0.0"
minizlib "^2.1.1"
mkdirp "^1.0.3"
yallist "^4.0.0"
@@ -12660,10 +12533,10 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
-typescript@^4.9.3:
- version "4.9.3"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.3.tgz#3aea307c1746b8c384435d8ac36b8a2e580d85db"
- integrity sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==
+typescript@^4.9.4:
+ version "4.9.4"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78"
+ integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==
ua-parser-js@^0.7.30:
version "0.7.32"
@@ -12706,10 +12579,10 @@ unicode-match-property-ecmascript@^2.0.0:
unicode-canonical-property-names-ecmascript "^2.0.0"
unicode-property-aliases-ecmascript "^2.0.0"
-unicode-match-property-value-ecmascript@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714"
- integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==
+unicode-match-property-value-ecmascript@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz#cb5fffdcd16a05124f5a4b0bf7c3770208acbbe0"
+ integrity sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==
unicode-property-aliases-ecmascript@^2.0.0:
version "2.1.0"
@@ -12779,14 +12652,6 @@ universalify@^2.0.0:
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
-unload@2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7"
- integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==
- dependencies:
- "@babel/runtime" "^7.6.2"
- detect-node "^2.0.4"
-
unpipe@1.0.0, unpipe@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
@@ -12900,7 +12765,7 @@ use-sidecar@^1.1.2:
detect-node-es "^1.1.0"
tslib "^2.0.0"
-use-sync-external-store@^1.0.0:
+use-sync-external-store@^1.0.0, use-sync-external-store@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
@@ -13278,10 +13143,10 @@ wonka@^4.0.14:
resolved "https://registry.yarnpkg.com/wonka/-/wonka-4.0.15.tgz#9aa42046efa424565ab8f8f451fcca955bf80b89"
integrity sha512-U0IUQHKXXn6PFo9nqsHphVCE5m3IntqZNB9Jjn7EB1lrR7YTDY3YWgFvEvwniTzXSvOH/XMzAZaIfJF/LvHYXg==
-wonka@^6.0.0:
- version "6.1.1"
- resolved "https://registry.yarnpkg.com/wonka/-/wonka-6.1.1.tgz#134ece7d07848477e3a8b7d35f2333af2edde138"
- integrity sha512-shBtyZ0KFvUadtnDGlTRA4mF4pgcRoyZKikdputKhmShoXWcZDvlg6CUw6Jx9nTL7Ub8QUJoIarPpxdlosg9cw==
+wonka@^6.1.2:
+ version "6.1.2"
+ resolved "https://registry.yarnpkg.com/wonka/-/wonka-6.1.2.tgz#2c66fa5b26a12f002a03619b988258313d0b5352"
+ integrity sha512-zNrXPMccg/7OEp9tSfFkMgTvhhowqasiSHdJ3eCZolXxVTV/aT6HUTofoZk9gwRbGoFey/Nss3JaZKUMKMbofg==
worker-farm@^1.7.0:
version "1.7.0"