From 55053e73f86ed54b1f68ee475d6aeb1953044d5e Mon Sep 17 00:00:00 2001 From: xmflsct Date: Tue, 7 Jun 2022 22:27:24 +0200 Subject: [PATCH] Test v4.1 (#320) * New translations actions.json (German) * New translations actions.json (Korean) * New translations actions.json (Chinese Simplified) * New translations actions.json (Chinese Traditional) * New translations actions.json (Vietnamese) * New translations actions.json (Italian) * New translations actions.json (Portuguese, Brazilian) * Bump packages * New translations actions.json (Chinese Simplified) * Fixed #108 * Fixed #117 * Fixed #137 * Fix badge not cleared on app launch * Update Expo workflow * Update build.yml * New context menu largely working * Fixed #158 * File format changes by `expo prebuild` * Update .gitignore * Try out notification sound * Bump packages * New Crowdin updates (#319) * New translations actions.json (Portuguese, Brazilian) * New translations timeline.json (Portuguese, Brazilian) * New translations actions.json (Portuguese, Brazilian) * New translations compose.json (Portuguese, Brazilian) * New translations tabs.json (Portuguese, Brazilian) * New translations actions.json (Vietnamese) * New translations timeline.json (German) * New translations mediaSelector.json (Italian) * New translations contextMenu.json (Vietnamese) * New translations contextMenu.json (Chinese Traditional) * New translations contextMenu.json (Chinese Simplified) * New translations contextMenu.json (Korean) * New translations contextMenu.json (Italian) * New translations contextMenu.json (German) * New translations mediaSelector.json (Portuguese, Brazilian) * New translations timeline.json (Portuguese, Brazilian) * New translations timeline.json (Italian) * New translations mediaSelector.json (German) * New translations mediaSelector.json (Vietnamese) * New translations mediaSelector.json (Chinese Traditional) * New translations mediaSelector.json (Chinese Simplified) * New translations mediaSelector.json (Korean) * New translations timeline.json (Chinese Traditional) * New translations timeline.json (Vietnamese) * New translations timeline.json (Chinese Simplified) * New translations timeline.json (Korean) * New translations contextMenu.json (Portuguese, Brazilian) * New translations mediaSelector.json (Vietnamese) * New translations contextMenu.json (Vietnamese) * New translations contextMenu.json (Vietnamese) * New translations mediaSelector.json (Chinese Simplified) * New translations contextMenu.json (German) * New translations contextMenu.json (Italian) * New translations contextMenu.json (Korean) * New translations contextMenu.json (Chinese Simplified) * New translations contextMenu.json (Portuguese, Brazilian) --- .github/workflows/build.yml | 5 +- .gitignore | 40 +- VERSIONING.md | 8 - android/app/src/main/res/raw/boop.mp3 | Bin 0 -> 12280 bytes android/app/src/main/res/values/strings.xml | 1 - app.config.ts | 10 +- assets/sounds/boop.mp3 | Bin 0 -> 12280 bytes ios/Podfile.lock | 89 ++--- ios/Podfile.properties.json | 2 +- ios/en.lproj/InfoPlist.strings | 1 - ios/tooot.xcodeproj/project.pbxproj | 8 + ios/tooot/Info.plist | 174 +++++---- ios/tooot/Supporting/Expo.plist | 30 +- ios/tooot/boop.mp3 | Bin 0 -> 12280 bytes ios/tooot/tooot.entitlements | 42 +-- ios/zh-Hans.lproj/InfoPlist.strings | 1 - package.json | 45 +-- src/@types/app.d.ts | 7 - src/App.tsx | 1 - src/Screens.tsx | 156 +++----- src/components/ContextMenu/account.ts | 164 ++++++++ src/components/ContextMenu/instance.ts | 108 ++++++ src/components/ContextMenu/share.ts | 38 ++ src/components/ContextMenu/status.ts | 286 ++++++++++++++ src/components/Timeline/Default.tsx | 169 +++++---- src/components/Timeline/Notifications.tsx | 181 ++++----- .../Timeline/Shared/ContextMenu.tsx | 82 ++++ .../Timeline/Shared/HeaderDefault.tsx | 56 ++- .../Timeline/Shared/HeaderNotification.tsx | 36 +- src/components/mediaSelector.ts | 277 ++++++++------ src/i18n/de/components/contextMenu.json | 70 ++++ src/i18n/de/components/mediaSelector.json | 20 +- src/i18n/de/components/timeline.json | 88 ----- src/i18n/de/screens/actions.json | 5 +- src/i18n/en/_all.ts | 1 + src/i18n/en/components/contextMenu.json | 70 ++++ src/i18n/en/components/mediaSelector.json | 20 +- src/i18n/en/components/timeline.json | 88 ----- src/i18n/i18n.ts | 4 +- src/i18n/it/components/contextMenu.json | 70 ++++ src/i18n/it/components/mediaSelector.json | 20 +- src/i18n/it/components/timeline.json | 88 ----- src/i18n/it/screens/actions.json | 5 +- src/i18n/ko/components/contextMenu.json | 70 ++++ src/i18n/ko/components/mediaSelector.json | 20 +- src/i18n/ko/components/timeline.json | 88 ----- src/i18n/ko/screens/actions.json | 5 +- src/i18n/pt_BR/components/contextMenu.json | 70 ++++ src/i18n/pt_BR/components/mediaSelector.json | 20 +- src/i18n/pt_BR/components/timeline.json | 90 +---- src/i18n/pt_BR/screens/actions.json | 9 +- src/i18n/pt_BR/screens/compose.json | 2 +- src/i18n/pt_BR/screens/tabs.json | 4 +- src/i18n/vi/components/contextMenu.json | 70 ++++ src/i18n/vi/components/mediaSelector.json | 20 +- src/i18n/vi/components/timeline.json | 88 ----- src/i18n/vi/screens/actions.json | 5 +- src/i18n/zh-Hans/components/contextMenu.json | 70 ++++ .../zh-Hans/components/mediaSelector.json | 20 +- src/i18n/zh-Hans/components/timeline.json | 88 ----- src/i18n/zh-Hans/screens/actions.json | 5 +- src/i18n/zh-Hant/components/contextMenu.json | 70 ++++ .../zh-Hant/components/mediaSelector.json | 20 +- src/i18n/zh-Hant/components/timeline.json | 88 ----- src/i18n/zh-Hant/screens/actions.json | 5 +- src/screens/Actions.tsx | 107 ------ src/screens/Compose.tsx | 25 +- src/screens/Compose/EditAttachment/Image.tsx | 4 +- src/screens/Compose/EditAttachment/Root.tsx | 2 +- .../Compose/Root/Footer/addAttachment.ts | 44 ++- src/screens/Compose/Root/Header/TextInput.tsx | 24 +- src/screens/Compose/utils/reducer.ts | 2 +- src/screens/Compose/utils/types.d.ts | 13 +- .../Tabs/Me/Profile/Root/AvatarHeader.tsx | 11 +- src/screens/Tabs/Shared/Account.tsx | 32 +- src/screens/Tabs/Shared/Root.tsx | 49 ++- src/utils/navigation/navigators.ts | 13 +- src/utils/push/useConnect.ts | 2 +- src/utils/queryHooks/profile.ts | 5 +- yarn.lock | 356 ++++++++---------- 80 files changed, 2259 insertions(+), 1923 deletions(-) create mode 100644 android/app/src/main/res/raw/boop.mp3 create mode 100644 assets/sounds/boop.mp3 create mode 100644 ios/tooot/boop.mp3 create mode 100644 src/components/ContextMenu/account.ts create mode 100644 src/components/ContextMenu/instance.ts create mode 100644 src/components/ContextMenu/share.ts create mode 100644 src/components/ContextMenu/status.ts create mode 100644 src/components/Timeline/Shared/ContextMenu.tsx create mode 100644 src/i18n/de/components/contextMenu.json create mode 100644 src/i18n/en/components/contextMenu.json create mode 100644 src/i18n/it/components/contextMenu.json create mode 100644 src/i18n/ko/components/contextMenu.json create mode 100644 src/i18n/pt_BR/components/contextMenu.json create mode 100644 src/i18n/vi/components/contextMenu.json create mode 100644 src/i18n/zh-Hans/components/contextMenu.json create mode 100644 src/i18n/zh-Hant/components/contextMenu.json diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e9fc022b..73628202 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,10 +25,9 @@ jobs: distribution: 'zulu' java-version: '11' - name: -- Step 4 -- Use Expo action - uses: expo/expo-github-action@v6 + uses: expo/expo-github-action@v7 with: - expo-version: 5.x - username: ${{ secrets.EXPO_USERNAME }} + expo-version: latest token: ${{ secrets.EXPO_TOKEN }} - name: -- Step 5 -- Install node dependencies run: yarn install diff --git a/.gitignore b/.gitignore index a2022620..2173fcc9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,13 +5,44 @@ coverage/ builds/ -# @generated expo-cli sync-28e2ab0e9ece60556eaf932abe52d017ec33db50 +# @generated expo-cli sync-e7dcf75f4e856f7b6f3239b3f3a7dd614ee755a8 # The following patterns were generated by expo-cli # OSX +# .DS_Store +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +project.xcworkspace + +# Android/IntelliJ +# +build/ +.idea +.gradle +local.properties +*.iml +*.hprof + # node.js +# node_modules/ npm-debug.log yarn-error.log @@ -25,9 +56,12 @@ buck-out/ # Bundle artifacts *.jsbundle +# CocoaPods +/ios/Pods/ + # Expo -.expo/* -.expo-shared/* +.expo/ web-build/ +dist/ # @end expo-cli \ No newline at end of file diff --git a/VERSIONING.md b/VERSIONING.md index 6d9e4861..7a500bd4 100644 --- a/VERSIONING.md +++ b/VERSIONING.md @@ -22,11 +22,3 @@ ## OTA release channels * `MAJOR.MINOR-environment`. Environments include `release`, `candidate` and `development`. - -## Major versions mapping to native module versions - -| Version | Native module version | Expo version | -| :------:| :-------------------: | :----------: | -| `0-` | `210201` | `40.0.0` | -| `1-` | `210317` | `40.0.0` | -| `2.2` | `210916` | `41.0.0` | \ No newline at end of file diff --git a/android/app/src/main/res/raw/boop.mp3 b/android/app/src/main/res/raw/boop.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..bf9c3c1aaff40dea76ad82e3e853d2d32382bcea GIT binary patch literal 12280 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 1f97fdc0..df082f69 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -1,4 +1,3 @@ - tooot contain diff --git a/app.config.ts b/app.config.ts index 73f78825..5a8c343b 100644 --- a/app.config.ts +++ b/app.config.ts @@ -35,5 +35,13 @@ export default (): ExpoConfig => ({ googleServicesFile: './configs/google-services.json', permissions: ['CAMERA', 'VIBRATE'], blockedPermissions: ['USE_BIOMETRIC', 'USE_FINGERPRINT'] - } + }, + plugins: [ + [ + 'expo-notifications', + { + sounds: ['./assets/sounds/boop.mp3'] + } + ] + ] }) diff --git a/assets/sounds/boop.mp3 b/assets/sounds/boop.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..bf9c3c1aaff40dea76ad82e3e853d2d32382bcea GIT binary patch literal 12280 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 literal 0 HcmV?d00001 diff --git a/ios/Podfile.lock b/ios/Podfile.lock index d455be6c..3b78bd9f 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -4,8 +4,6 @@ PODS: - DoubleConversion (1.1.6) - EASClient (0.2.1): - ExpoModulesCore - - EXApplication (4.1.0): - - ExpoModulesCore - EXAV (11.2.3): - ExpoModulesCore - React-runtimeexecutor @@ -25,8 +23,6 @@ PODS: - EXFirebaseCore (5.0.0): - ExpoModulesCore - Firebase/Core (= 8.14.0) - - EXFont (10.1.0): - - ExpoModulesCore - EXImageLoader (3.2.0): - ExpoModulesCore - React-Core @@ -35,19 +31,14 @@ PODS: - EXJSONUtils - EXNotifications (0.15.2): - ExpoModulesCore - - Expo (45.0.4): + - Expo (45.0.5): - ExpoModulesCore - ExpoCrypto (10.2.0): - ExpoModulesCore - ExpoHaptics (11.2.0): - ExpoModulesCore - - ExpoImageManipulator (10.3.1): - - EXImageLoader - - ExpoModulesCore - ExpoImagePicker (13.1.1): - ExpoModulesCore - - ExpoKeepAwake (10.1.1): - - ExpoModulesCore - ExpoLocalization (13.0.0): - ExpoModulesCore - ExpoModulesCore (0.9.2): @@ -55,7 +46,7 @@ PODS: - ReactCommon/turbomodule/core - ExpoRandom (12.2.0): - ExpoModulesCore - - ExpoWebBrowser (10.2.0): + - ExpoWebBrowser (10.2.1): - ExpoModulesCore - EXScreenCapture (4.2.0): - ExpoModulesCore @@ -67,7 +58,7 @@ PODS: - EXStoreReview (5.2.0): - ExpoModulesCore - EXStructuredHeaders (2.2.1) - - EXUpdates (0.13.1): + - EXUpdates (0.13.2): - ASN1Decoder (~> 1.8) - EASClient - EXManifests @@ -415,13 +406,16 @@ PODS: - React-Core - react-native-cameraroll (4.1.2): - React-Core - - react-native-image-keyboard (2.2.0): + - react-native-context-menu-view (1.5.4): - React - - react-native-netinfo (8.3.0): + - react-native-netinfo (9.0.0): - React-Core - react-native-pager-view (5.4.11): - React-Core - - react-native-safe-area-context (4.2.5): + - react-native-paste-input (0.4.2): + - React-Core + - Swime (= 3.0.6) + - react-native-safe-area-context (4.3.1): - RCT-Folly - RCTRequired - RCTTypeSafety @@ -523,7 +517,7 @@ PODS: - React-logger (= 0.68.2) - React-perflogger (= 0.68.2) - ReactCommon/turbomodule/core (= 0.68.2) - - RNCAsyncStorage (1.17.4): + - RNCAsyncStorage (1.17.6): - React-Core - RNFastImage (8.5.11): - React-Core @@ -531,6 +525,15 @@ PODS: - SDWebImageWebPCoder (~> 0.8.4) - RNGestureHandler (2.4.2): - React-Core + - RNImageCropPicker (0.37.3): + - React-Core + - React-RCTImage + - RNImageCropPicker/QBImagePickerController (= 0.37.3) + - TOCropViewController + - RNImageCropPicker/QBImagePickerController (0.37.3): + - React-Core + - React-RCTImage + - TOCropViewController - RNReanimated (2.8.0): - DoubleConversion - FBLazyVector @@ -561,7 +564,7 @@ PODS: - RNScreens (3.13.1): - React-Core - React-RCTImage - - RNSentry (3.4.2): + - RNSentry (3.4.3): - React-Core - Sentry (= 7.11.0) - RNShareMenu (5.0.5): @@ -577,13 +580,14 @@ PODS: - Sentry (7.11.0): - Sentry/Core (= 7.11.0) - Sentry/Core (7.11.0) + - Swime (3.0.6) + - TOCropViewController (2.6.1) - Yoga (1.14.0) DEPENDENCIES: - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - EASClient (from `../node_modules/expo-eas-client/ios`) - - EXApplication (from `../node_modules/expo-application/ios`) - EXAV (from `../node_modules/expo-av/ios`) - EXConstants (from `../node_modules/expo-constants/ios`) - EXDevice (from `../node_modules/expo-device/ios`) @@ -591,7 +595,6 @@ DEPENDENCIES: - EXFileSystem (from `../node_modules/expo-file-system/ios`) - EXFirebaseAnalytics (from `../node_modules/expo-firebase-analytics/ios`) - EXFirebaseCore (from `../node_modules/expo-firebase-core/ios`) - - EXFont (from `../node_modules/expo-font/ios`) - EXImageLoader (from `../node_modules/expo-image-loader/ios`) - EXJSONUtils (from `../node_modules/expo-json-utils/ios`) - EXManifests (from `../node_modules/expo-manifests/ios`) @@ -599,9 +602,7 @@ DEPENDENCIES: - Expo (from `../node_modules/expo/ios`) - ExpoCrypto (from `../node_modules/expo-crypto/ios`) - ExpoHaptics (from `../node_modules/expo-haptics/ios`) - - ExpoImageManipulator (from `../node_modules/expo-image-manipulator/ios`) - ExpoImagePicker (from `../node_modules/expo-image-picker/ios`) - - ExpoKeepAwake (from `../node_modules/expo-keep-awake/ios`) - ExpoLocalization (from `../node_modules/expo-localization/ios`) - ExpoModulesCore (from `../node_modules/expo-modules-core/ios`) - ExpoRandom (from `../node_modules/expo-random/ios`) @@ -638,9 +639,10 @@ DEPENDENCIES: - "react-native-blur (from `../node_modules/@react-native-community/blur`)" - react-native-blurhash (from `../node_modules/react-native-blurhash`) - "react-native-cameraroll (from `../node_modules/@react-native-community/cameraroll`)" - - react-native-image-keyboard (from `../node_modules/react-native-image-keyboard`) + - react-native-context-menu-view (from `../node_modules/react-native-context-menu-view`) - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)" - react-native-pager-view (from `../node_modules/react-native-pager-view`) + - "react-native-paste-input (from `../node_modules/@mattermost/react-native-paste-input`)" - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) - "react-native-segmented-control (from `../node_modules/@react-native-community/segmented-control`)" - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) @@ -658,6 +660,7 @@ DEPENDENCIES: - "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)" - RNFastImage (from `../node_modules/react-native-fast-image`) - RNGestureHandler (from `../node_modules/react-native-gesture-handler`) + - RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`) - RNReanimated (from `../node_modules/react-native-reanimated`) - RNScreens (from `../node_modules/react-native-screens`) - "RNSentry (from `../node_modules/@sentry/react-native`)" @@ -685,6 +688,8 @@ SPEC REPOS: - SDWebImage - SDWebImageWebPCoder - Sentry + - Swime + - TOCropViewController EXTERNAL SOURCES: boost: @@ -693,8 +698,6 @@ EXTERNAL SOURCES: :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" EASClient: :path: "../node_modules/expo-eas-client/ios" - EXApplication: - :path: "../node_modules/expo-application/ios" EXAV: :path: "../node_modules/expo-av/ios" EXConstants: @@ -709,8 +712,6 @@ EXTERNAL SOURCES: :path: "../node_modules/expo-firebase-analytics/ios" EXFirebaseCore: :path: "../node_modules/expo-firebase-core/ios" - EXFont: - :path: "../node_modules/expo-font/ios" EXImageLoader: :path: "../node_modules/expo-image-loader/ios" EXJSONUtils: @@ -725,12 +726,8 @@ EXTERNAL SOURCES: :path: "../node_modules/expo-crypto/ios" ExpoHaptics: :path: "../node_modules/expo-haptics/ios" - ExpoImageManipulator: - :path: "../node_modules/expo-image-manipulator/ios" ExpoImagePicker: :path: "../node_modules/expo-image-picker/ios" - ExpoKeepAwake: - :path: "../node_modules/expo-keep-awake/ios" ExpoLocalization: :path: "../node_modules/expo-localization/ios" ExpoModulesCore: @@ -795,12 +792,14 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-blurhash" react-native-cameraroll: :path: "../node_modules/@react-native-community/cameraroll" - react-native-image-keyboard: - :path: "../node_modules/react-native-image-keyboard" + react-native-context-menu-view: + :path: "../node_modules/react-native-context-menu-view" react-native-netinfo: :path: "../node_modules/@react-native-community/netinfo" react-native-pager-view: :path: "../node_modules/react-native-pager-view" + react-native-paste-input: + :path: "../node_modules/@mattermost/react-native-paste-input" react-native-safe-area-context: :path: "../node_modules/react-native-safe-area-context" react-native-segmented-control: @@ -835,6 +834,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-fast-image" RNGestureHandler: :path: "../node_modules/react-native-gesture-handler" + RNImageCropPicker: + :path: "../node_modules/react-native-image-crop-picker" RNReanimated: :path: "../node_modules/react-native-reanimated" RNScreens: @@ -853,7 +854,6 @@ SPEC CHECKSUMS: boost: a7c83b31436843459a1961bfd74b96033dc77234 DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662 EASClient: 93565f4d024559b75eac62bc7d50acaa354614f6 - EXApplication: d6562af1204162e0ac46d341a7d4e5dc720b33de EXAV: 88f61c5af8415715b7ee51f084c1020235b85c56 EXConstants: fdbe52259365b6a6faaa5e99a3b82cfa6bc2eb61 EXDevice: 0115b360059ccd32c1701744e374e3259ffbdd3c @@ -861,27 +861,24 @@ SPEC CHECKSUMS: EXFileSystem: 2aa2d9289f84bca9532b9ccbd81504fa31eb1ded EXFirebaseAnalytics: aeefc63f92277313c3ee86da6a7ecf892f345ed1 EXFirebaseCore: bdfa87df74fa1b74a6b38957561456aabad28a4f - EXFont: 04235cc22e6fef86028feb67db452978dc6f240f EXImageLoader: b88e053d760f85a82405b1db2de4abf11978fc9f EXJSONUtils: 2a74b8f40f1523cc3f92af99c91aa78201737a77 EXManifests: 0c6134b7b6f3236a93a778c3f44ba1cfb3f9fa3d EXNotifications: ea9fc56d27d1fee229489c5d8f452c7f367c237e - Expo: 64d52669fa3b9342919b5b44b2b4f15f19b0cf76 + Expo: b9fff0a1eac0f424fc68ea49b4347fb308e52e17 ExpoCrypto: d0d0f3e20875dc450b4ec88f0fb608da5c2c6c17 ExpoHaptics: ad58ec96a25e57579c14a47c7d71f0de0de8656a - ExpoImageManipulator: b55580bbc7b10099c7707949903e7176a8542ee8 ExpoImagePicker: d9d6b4f29db437fc7796f13cee5f133f5b4b5f7c - ExpoKeepAwake: c0c494b442ecd8122974c13b93ccfb57bd408e88 ExpoLocalization: 8f619bb6eec64575cd5220bfabbd7b4e2d6f33f8 ExpoModulesCore: e4278a668e8c13c0269ed8b8a4200989deea2973 ExpoRandom: 14df0976aa363a71a730ceb7655250f3047c0e42 - ExpoWebBrowser: 818c519c3519cdd79780228039938fbd8236c885 + ExpoWebBrowser: 4b5f9633e5f169dc948587cb6d26d2d1d1406187 EXScreenCapture: cbee2204f313038a1819d31ad99a31e15f8e0f59 EXSecureStore: aaae919d83aec2faf031e99398807edac0313285 EXSplashScreen: 34f460788db8d682883871708dddbfac72095bb7 EXStoreReview: e61fbd500624ee7363ab134ee247cff380a8b254 EXStructuredHeaders: 5d86829469399370a9fc7cb1e4391b09de87681d - EXUpdates: 08c3931d6a5f39686091130a10310266ae3ba5f9 + EXUpdates: 08d69031f9ed1e918d50f041fa505fe67d6b4809 EXUpdatesInterface: 0b101ace1dbfa0f64260a5df31c71d03c66cca54 EXVideoThumbnails: 19e055dc3245b53c536da9e0ef9c618fd2118297 FBLazyVector: a7a655862f6b09625d11c772296b01cd5164b648 @@ -918,10 +915,11 @@ SPEC CHECKSUMS: react-native-blur: cad4d93b364f91e7b7931b3fa935455487e5c33c react-native-blurhash: add4df9a937b4e021a24bc67a0714f13e0bd40b7 react-native-cameraroll: 2957f2bce63ae896a848fbe0d5352c1bd4d20866 - react-native-image-keyboard: adbf5996b8592a7d8cb8d3e431a9607f9cf3b270 - react-native-netinfo: 3671b091c4843fda5e153612866ef4024b8f5d62 + react-native-context-menu-view: b0beca02aad4bd9f9d7d932bf437e0a03baa69ef + react-native-netinfo: 5b664b2945a8f02102b296f0f812bddd6827ed9c react-native-pager-view: 7f00d63688f7df9fad86dfb0154814419cc5eb8d - react-native-safe-area-context: ebf8c413eb8b5f7c392a036a315eb7b46b96845f + react-native-paste-input: efbf0b08fa1673f0e3131da6ea01678c1bb8003e + react-native-safe-area-context: 6c12e3859b6f27b25de4fee8201cfb858432d8de react-native-segmented-control: 65df6cd0619b780b3843d574a72d4c7cec396097 React-perflogger: a18b4f0bd933b8b24ecf9f3c54f9bf65180f3fe6 React-RCTActionSheet: 547fe42fdb4b6089598d79f8e1d855d7c23e2162 @@ -935,17 +933,20 @@ SPEC CHECKSUMS: React-RCTVibration: 79040b92bfa9c3c2d2cb4f57e981164ec7ab9374 React-runtimeexecutor: b960b687d2dfef0d3761fbb187e01812ebab8b23 ReactCommon: 095366164a276d91ea704ce53cb03825c487a3f2 - RNCAsyncStorage: 9367a646dc24e3ab7b6874d79bc1bfd0832dce58 + RNCAsyncStorage: 466b9df1a14bccda91da86e0b7d9a345d78e1673 RNFastImage: 945abf54742505d790d9024d230c69b1e866bc88 RNGestureHandler: 61628a2c859172551aa2100d3e73d1e57878392f + RNImageCropPicker: 44e2807bc410741f35d4c45b6586aedfe3da39d2 RNReanimated: 64573e25e078ae6bec03b891586d50b9ec284393 RNScreens: 40a2cb40a02a609938137a1e0acfbf8fc9eebf19 - RNSentry: 2cd1daa124b0d9fd0dfc2cb6094fdd168cb579bc + RNSentry: 85f6525b5fe8d2ada065858026b338605b3c09da RNShareMenu: c69282e50ac439737a86949a55c7b023b90027c8 RNSVG: 302bfc9905bd8122f08966dc2ce2d07b7b52b9f8 SDWebImage: 0905f1b7760fc8ac4198cae0036600d67478751e SDWebImageWebPCoder: f93010f3f6c031e2f8fb3081ca4ee6966c539815 Sentry: 0c5cd63d714187b4a39c331c1f0eb04ba7868341 + Swime: d7b2c277503b6cea317774aedc2dce05613f8b0b + TOCropViewController: edfd4f25713d56905ad1e0b9f5be3fbe0f59c863 Yoga: 99652481fcd320aefa4a7ef90095b95acd181952 PODFILE CHECKSUM: d6d20fa7c51228cebc309aed987ed7d8f4274844 diff --git a/ios/Podfile.properties.json b/ios/Podfile.properties.json index cb338dda..b1bd45da 100644 --- a/ios/Podfile.properties.json +++ b/ios/Podfile.properties.json @@ -1,3 +1,3 @@ { "expo.jsEngine": "hermes" -} \ No newline at end of file +} diff --git a/ios/en.lproj/InfoPlist.strings b/ios/en.lproj/InfoPlist.strings index 1787913e..f9728054 100644 --- a/ios/en.lproj/InfoPlist.strings +++ b/ios/en.lproj/InfoPlist.strings @@ -6,6 +6,5 @@ */ -"NSCameraUsageDescription" = "Allow tooot to capture photo or video and attach it to your toot"; "NSPhotoLibraryAddUsageDescription" = "Allow tooot to save an image to your camera roll"; "NSPhotoLibraryUsageDescription" = "Allow tooot to access your camera roll to attach photos or videos to your toot"; diff --git a/ios/tooot.xcodeproj/project.pbxproj b/ios/tooot.xcodeproj/project.pbxproj index ffe81c03..d4f2fab3 100644 --- a/ios/tooot.xcodeproj/project.pbxproj +++ b/ios/tooot.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 34A37A6C820725DC6DDAA0EE /* libPods-ShareExtension.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1B3640FCDF7C4396A68A74D1 /* libPods-ShareExtension.a */; }; 3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */; }; + 4986628FD0DD4630BFE5F388 /* boop.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = DF8133F098604A10B0D94952 /* boop.mp3 */; }; 5E36538325C9B8BD009F93EE /* RootViewColor.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5E36538225C9B8BD009F93EE /* RootViewColor.xcassets */; }; 5EE088C926297820007E5FEC /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5EE088CB26297820007E5FEC /* InfoPlist.strings */; }; 5EE44DD62600124E00A9BCED /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EE44DD52600124E00A9BCED /* File.swift */; }; @@ -71,6 +72,7 @@ AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = tooot/SplashScreen.storyboard; sourceTree = ""; }; B96B72E5384D44A7B240B27E /* GoogleService-Info.plist */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "tooot/GoogleService-Info.plist"; sourceTree = ""; }; BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = ""; }; + DF8133F098604A10B0D94952 /* boop.mp3 */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = boop.mp3; path = tooot/boop.mp3; sourceTree = ""; }; E613A80A28282A01003C97D6 /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = tooot/AppDelegate.mm; sourceTree = ""; }; E633A420281EAEAB000E540F /* ShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; E633A427281EAEAB000E540F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -115,6 +117,7 @@ 5E36538225C9B8BD009F93EE /* RootViewColor.xcassets */, B96B72E5384D44A7B240B27E /* GoogleService-Info.plist */, 5EE088CB26297820007E5FEC /* InfoPlist.strings */, + DF8133F098604A10B0D94952 /* boop.mp3 */, ); name = tooot; sourceTree = ""; @@ -310,6 +313,7 @@ 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, 3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */, DA8B5B7F0DED488CAC0FF169 /* GoogleService-Info.plist in Resources */, + 4986628FD0DD4630BFE5F388 /* boop.mp3 in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -386,13 +390,17 @@ "${PODS_ROOT}/Target Support Files/Pods-tooot/Pods-tooot-resources.sh", "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/EXUpdates/EXUpdates.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker/QBImagePicker.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/TOCropViewController/TOCropViewControllerBundle.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXUpdates.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/QBImagePicker.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/TOCropViewControllerBundle.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; diff --git a/ios/tooot/Info.plist b/ios/tooot/Info.plist index 2f610bc1..d6741b51 100644 --- a/ios/tooot/Info.plist +++ b/ios/tooot/Info.plist @@ -1,92 +1,90 @@ - - CFBundleAllowMixedLocalizations - - CFBundleDevelopmentRegion - en - CFBundleDisplayName - tooot - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 0.2 - CFBundleSignature - ???? - CFBundleURLTypes - - - CFBundleTypeRole - Editor - CFBundleURLName - com.xmflsct.app.tooot - CFBundleURLSchemes - - tooot-share - tooot - - - - CFBundleVersion - 2102022230 - ITSAppUsesNonExemptEncryption - - LSApplicationCategoryType - public.app-category.social-networking - LSRequiresIPhoneOS - - NSAppTransportSecurity - - NSExceptionDomains - - localhost - - NSExceptionAllowsInsecureHTTPLoads - - - - - NSCameraUsageDescription - Allow $(PRODUCT_NAME) to capture photo or video and attach it to your toot - NSLocationWhenInUseUsageDescription - - NSMainNibFile - LaunchScreen - NSMicrophoneUsageDescription - $(PRODUCT_NAME) DOES NOT need microphone permission. Please reject this request. - NSPhotoLibraryAddUsageDescription - Allow $(PRODUCT_NAME) to save an image to your camera roll - NSPhotoLibraryUsageDescription - Allow $(PRODUCT_NAME) to access your camera roll to attach photos or videos to your toot - UILaunchStoryboardName - SplashScreen - UIRequiredDeviceCapabilities - - armv7 - - UIRequiresFullScreen - - UIStatusBarHidden - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIUserInterfaceStyle - Automatic - UIViewControllerBasedStatusBarAppearance - - + + CFBundleAllowMixedLocalizations + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + tooot + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 0.2 + CFBundleSignature + ???? + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + com.xmflsct.app.tooot + CFBundleURLSchemes + + tooot-share + tooot + + + + CFBundleVersion + 2102022230 + ITSAppUsesNonExemptEncryption + + LSApplicationCategoryType + public.app-category.social-networking + LSRequiresIPhoneOS + + NSAppTransportSecurity + + NSExceptionDomains + + localhost + + NSExceptionAllowsInsecureHTTPLoads + + + + + NSLocationWhenInUseUsageDescription + + NSMainNibFile + LaunchScreen + NSMicrophoneUsageDescription + $(PRODUCT_NAME) DOES NOT need microphone permission. Please reject this request. + NSPhotoLibraryAddUsageDescription + Allow $(PRODUCT_NAME) to save an image to your camera roll + NSPhotoLibraryUsageDescription + Allow $(PRODUCT_NAME) to access your camera roll to attach photos or videos to your toot + UILaunchStoryboardName + SplashScreen + UIRequiredDeviceCapabilities + + armv7 + + UIRequiresFullScreen + + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIUserInterfaceStyle + Automatic + UIViewControllerBasedStatusBarAppearance + + diff --git a/ios/tooot/Supporting/Expo.plist b/ios/tooot/Supporting/Expo.plist index bba13d22..ab06f3de 100644 --- a/ios/tooot/Supporting/Expo.plist +++ b/ios/tooot/Supporting/Expo.plist @@ -1,18 +1,18 @@ - - EXUpdatesCheckOnLaunch - WIFI_ONLY - EXUpdatesEnabled - - EXUpdatesLaunchWaitMs - 0 - EXUpdatesReleaseChannel - 0-development - EXUpdatesSDKVersion - 0 - EXUpdatesURL - https://exp.host/@xmflsct/tooot - - + + EXUpdatesCheckOnLaunch + WIFI_ONLY + EXUpdatesEnabled + + EXUpdatesLaunchWaitMs + 0 + EXUpdatesReleaseChannel + 0-development + EXUpdatesSDKVersion + 0 + EXUpdatesURL + https://exp.host/@xmflsct/tooot + + \ No newline at end of file diff --git a/ios/tooot/boop.mp3 b/ios/tooot/boop.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..bf9c3c1aaff40dea76ad82e3e853d2d32382bcea GIT binary patch literal 12280 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 literal 0 HcmV?d00001 diff --git a/ios/tooot/tooot.entitlements b/ios/tooot/tooot.entitlements index 9dadf2e3..574f838f 100644 --- a/ios/tooot/tooot.entitlements +++ b/ios/tooot/tooot.entitlements @@ -1,24 +1,24 @@ - - aps-environment - development - com.apple.security.app-sandbox - - com.apple.security.application-groups - - group.com.xmflsct.app.tooot - - com.apple.security.device.audio-input - - com.apple.security.device.camera - - com.apple.security.network.client - - com.apple.security.personal-information.location - - com.apple.security.personal-information.photos-library - - - + + aps-environment + development + com.apple.security.app-sandbox + + com.apple.security.application-groups + + group.com.xmflsct.app.tooot + + com.apple.security.device.audio-input + + com.apple.security.device.camera + + com.apple.security.network.client + + com.apple.security.personal-information.location + + com.apple.security.personal-information.photos-library + + + \ No newline at end of file diff --git a/ios/zh-Hans.lproj/InfoPlist.strings b/ios/zh-Hans.lproj/InfoPlist.strings index 41bee912..67025bd4 100644 --- a/ios/zh-Hans.lproj/InfoPlist.strings +++ b/ios/zh-Hans.lproj/InfoPlist.strings @@ -6,6 +6,5 @@ */ -"NSCameraUsageDescription" = "允许tooot拍摄图片或视频,以添加嘟文附件"; "NSPhotoLibraryAddUsageDescription" = "允许tooot保存图片至相册"; "NSPhotoLibraryUsageDescription" = "允许tooot读取相册图片或视频,以添加嘟文附件"; diff --git a/package.json b/package.json index 209e3464..cb99f682 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "tooot", "versions": { - "native": "220508", + "native": "220603", "major": 4, - "minor": 0, - "patch": 4, + "minor": 1, + "patch": 0, "expo": "45.0.0" }, "description": "tooot app for Mastodon", @@ -26,27 +26,28 @@ }, "dependencies": { "@expo/react-native-action-sheet": "3.13.0", - "@formatjs/intl-datetimeformat": "^6.0.1", - "@formatjs/intl-getcanonicallocales": "^2.0.1", - "@formatjs/intl-locale": "^3.0.1", - "@formatjs/intl-numberformat": "^8.0.1", - "@formatjs/intl-pluralrules": "^5.0.1", - "@formatjs/intl-relativetimeformat": "^11.0.1", + "@formatjs/intl-datetimeformat": "^6.0.2", + "@formatjs/intl-getcanonicallocales": "^2.0.2", + "@formatjs/intl-locale": "^3.0.2", + "@formatjs/intl-numberformat": "^8.0.2", + "@formatjs/intl-pluralrules": "^5.0.2", + "@formatjs/intl-relativetimeformat": "^11.0.2", + "@mattermost/react-native-paste-input": "^0.4.2", "@neverdull-agency/expo-unlimited-secure-store": "1.0.10", - "@react-native-async-storage/async-storage": "1.17.4", + "@react-native-async-storage/async-storage": "1.17.6", "@react-native-community/blur": "3.6.0", "@react-native-community/cameraroll": "4.1.2", - "@react-native-community/netinfo": "8.3.0", + "@react-native-community/netinfo": "9.0.0", "@react-native-community/segmented-control": "2.2.2", "@react-navigation/bottom-tabs": "6.3.1", "@react-navigation/native": "6.0.10", "@react-navigation/native-stack": "6.6.2", "@react-navigation/stack": "6.2.1", "@reduxjs/toolkit": "1.8.2", - "@sentry/react-native": "3.4.2", + "@sentry/react-native": "3.4.3", "@sharcoux/slider": "6.0.3", "axios": "0.27.2", - "expo": "45.0.4", + "expo": "45.0.5", "expo-auth-session": "3.6.1", "expo-av": "11.2.3", "expo-constants": "^13.1.1", @@ -55,7 +56,6 @@ "expo-file-system": "14.0.0", "expo-firebase-analytics": "7.0.0", "expo-haptics": "11.2.0", - "expo-image-manipulator": "10.3.1", "expo-image-picker": "13.1.1", "expo-linking": "3.1.0", "expo-localization": "13.0.0", @@ -65,29 +65,30 @@ "expo-secure-store": "11.2.0", "expo-splash-screen": "0.15.1", "expo-store-review": "5.2.0", - "expo-updates": "0.13.1", + "expo-updates": "0.13.2", "expo-video-thumbnails": "6.3.0", - "expo-web-browser": "10.2.0", + "expo-web-browser": "10.2.1", "i18next": "21.8.8", "li": "1.3.0", "lodash": "4.17.21", "react": "17.0.2", "react-dom": "17.0.2", "react-i18next": "11.17.0", - "react-intl": "^6.0.3", + "react-intl": "^6.0.4", "react-native": "0.68.2", "react-native-animated-spinkit": "1.5.2", "react-native-base64": "^0.2.1", "react-native-blurhash": "1.1.10", + "react-native-context-menu-view": "xmflsct/react-native-context-menu-view", "react-native-fast-image": "8.5.11", "react-native-feather": "1.1.2", "react-native-flash-message": "0.2.1", "react-native-gesture-handler": "2.4.2", "react-native-htmlview": "0.16.0", - "react-native-image-keyboard": "^2.2.0", + "react-native-image-crop-picker": "^0.37.3", "react-native-pager-view": "5.4.11", "react-native-reanimated": "2.8.0", - "react-native-safe-area-context": "4.2.5", + "react-native-safe-area-context": "4.3.1", "react-native-screens": "3.13.1", "react-native-share-menu": "^5.0.5", "react-native-svg": "12.3.0", @@ -97,7 +98,7 @@ "react-redux": "8.0.2", "redux-persist": "6.0.0", "rn-placeholder": "3.0.3", - "sentry-expo": "4.1.1", + "sentry-expo": "4.2.0", "tslib": "2.4.0", "valid-url": "1.0.9" }, @@ -110,7 +111,7 @@ "@types/lodash": "4.14.182", "@types/react": "17.0.43", "@types/react-dom": "17.0.14", - "@types/react-native": "0.67.7", + "@types/react-native": "0.67.8", "@types/react-native-base64": "^0.2.0", "@types/react-native-share-menu": "^5.0.2", "@types/react-timeago": "4.1.3", @@ -151,4 +152,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/@types/app.d.ts b/src/@types/app.d.ts index 489f987e..0db454c2 100644 --- a/src/@types/app.d.ts +++ b/src/@types/app.d.ts @@ -13,11 +13,4 @@ declare namespace App { | 'Conversations' | 'Bookmarks' | 'Favourites' - - interface IImageInfo { - uri: string - width: number - height: number - type?: 'image' | 'video' - } } diff --git a/src/App.tsx b/src/App.tsx index 496f2c71..96433aeb 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -21,7 +21,6 @@ import * as SplashScreen from 'expo-splash-screen' import React, { useCallback, useEffect, useState } from 'react' import { LogBox, Platform } from 'react-native' import { GestureHandlerRootView } from 'react-native-gesture-handler' -import 'react-native-image-keyboard' import { enableFreeze } from 'react-native-screens' import { QueryClientProvider } from 'react-query' import { Provider } from 'react-redux' diff --git a/src/Screens.tsx b/src/Screens.tsx index 805129ff..ae85cbca 100644 --- a/src/Screens.tsx +++ b/src/Screens.tsx @@ -178,8 +178,49 @@ const Screens: React.FC = ({ localCorrupt }) => { } let text: string | undefined = undefined - let images: { type: string; uri: string }[] = [] - let video: { type: string; uri: string } | undefined = undefined + let media: { path: string; mime: string }[] = [] + + const typesImage = ['png', 'jpg', 'jpeg', 'gif'] + const typesVideo = ['mp4', 'm4v', 'mov', 'webm', 'mpeg'] + const filterMedia = ({ path, mime }: { path: string; mime: string }) => { + if (mime.startsWith('image/')) { + if (!typesImage.includes(mime.split('/')[1])) { + console.warn('Image type not supported:', mime.split('/')[1]) + displayMessage({ + message: t('shareError.imageNotSupported', { + type: mime.split('/')[1] + }), + type: 'error', + theme + }) + return + } + media.push({ path, mime }) + } else if (mime.startsWith('video/')) { + if (!typesVideo.includes(mime.split('/')[1])) { + console.warn('Video type not supported:', mime.split('/')[1]) + displayMessage({ + message: t('shareError.videoNotSupported', { + type: mime.split('/')[1] + }), + type: 'error', + theme + }) + return + } + media.push({ path, mime }) + } else { + if (typesImage.includes(path.split('.').pop() || '')) { + media.push({ path: path, mime: 'image/jpg' }) + return + } + if (typesVideo.includes(path.split('.').pop() || '')) { + media.push({ path: path, mime: 'video/mp4' }) + return + } + text = !text ? path : text.concat(text, `\n${path}`) + } + } switch (Platform.OS) { case 'ios': @@ -187,55 +228,11 @@ const Screens: React.FC = ({ localCorrupt }) => { return } - item.data.forEach(d => { - if (typeof d === 'string') return - const typesImage = ['png', 'jpg', 'jpeg', 'gif'] - const typesVideo = ['mp4', 'm4v', 'mov', 'webm'] - const { mimeType, data } = d - if (mimeType.startsWith('image/')) { - if (!typesImage.includes(mimeType.split('/')[1])) { - console.warn( - 'Image type not supported:', - mimeType.split('/')[1] - ) - displayMessage({ - message: t('shareError.imageNotSupported', { - type: mimeType.split('/')[1] - }), - type: 'error', - theme - }) - return - } - images.push({ type: mimeType.split('/')[1], uri: data }) - } else if (mimeType.startsWith('video/')) { - if (!typesVideo.includes(mimeType.split('/')[1])) { - console.warn( - 'Video type not supported:', - mimeType.split('/')[1] - ) - displayMessage({ - message: t('shareError.videoNotSupported', { - type: mimeType.split('/')[1] - }), - type: 'error', - theme - }) - return - } - video = { type: mimeType.split('/')[1], uri: data } - } else { - if (typesImage.includes(data.split('.').pop() || '')) { - images.push({ type: data.split('.').pop()!, uri: data }) - return - } - if (typesVideo.includes(data.split('.').pop() || '')) { - video = { type: data.split('.').pop()!, uri: data } - return - } - text = !text ? data : text.concat(text, `\n${data}`) + for (const d of item.data) { + if (typeof d !== 'string') { + filterMedia({ path: d.data, mime: d.mimeType }) } - }) + } break case 'android': if (!item.mimeType) { @@ -247,65 +244,16 @@ const Screens: React.FC = ({ localCorrupt }) => { } else { tempData = item.data } - tempData.forEach(d => { - const typesImage = ['png', 'jpg', 'jpeg', 'gif'] - const typesVideo = ['mp4', 'm4v', 'mov', 'webm', 'mpeg'] - if (item.mimeType!.startsWith('image/')) { - if (!typesImage.includes(item.mimeType.split('/')[1])) { - console.warn( - 'Image type not supported:', - item.mimeType.split('/')[1] - ) - displayMessage({ - message: t('shareError.imageNotSupported', { - type: item.mimeType.split('/')[1] - }), - type: 'error', - theme - }) - return - } - images.push({ type: item.mimeType.split('/')[1], uri: d }) - } else if (item.mimeType.startsWith('video/')) { - if (!typesVideo.includes(item.mimeType.split('/')[1])) { - console.warn( - 'Video type not supported:', - item.mimeType.split('/')[1] - ) - displayMessage({ - message: t('shareError.videoNotSupported', { - type: item.mimeType.split('/')[1] - }), - type: 'error', - theme - }) - return - } - video = { type: item.mimeType.split('/')[1], uri: d } - } else { - if (typesImage.includes(d.split('.').pop() || '')) { - images.push({ type: d.split('.').pop()!, uri: d }) - return - } - if (typesVideo.includes(d.split('.').pop() || '')) { - video = { type: d.split('.').pop()!, uri: d } - return - } - text = !text ? d : text.concat(text, `\n${d}`) - } - }) + for (const d of item.data) { + filterMedia({ path: d, mime: item.mimeType }) + } break } - if (!text && (!images || !images.length) && !video) { + if (!text && !media.length) { return } else { - navigationRef.navigate('Screen-Compose', { - type: 'share', - text, - images, - video - }) + navigationRef.navigate('Screen-Compose', { type: 'share', text, media }) } }, [instanceActive] diff --git a/src/components/ContextMenu/account.ts b/src/components/ContextMenu/account.ts new file mode 100644 index 00000000..d1289679 --- /dev/null +++ b/src/components/ContextMenu/account.ts @@ -0,0 +1,164 @@ +import analytics from '@components/analytics' +import { displayMessage } from '@components/Message' +import { + MutationVarsTimelineUpdateAccountProperty, + QueryKeyTimeline, + useTimelineMutation +} from '@utils/queryHooks/timeline' +import { getInstanceAccount } from '@utils/slices/instancesSlice' +import { useTheme } from '@utils/styles/ThemeManager' +import { useTranslation } from 'react-i18next' +import { Platform } from 'react-native' +import { ContextMenuAction } from 'react-native-context-menu-view' +import { useQueryClient } from 'react-query' +import { useSelector } from 'react-redux' + +export interface Props { + actions: ContextMenuAction[] + queryKey?: QueryKeyTimeline + rootQueryKey?: QueryKeyTimeline + id: Mastodon.Account['id'] +} + +const contextMenuAccount = ({ + actions, + queryKey, + rootQueryKey, + id: accountId +}: Props) => { + const { theme } = useTheme() + const { t } = useTranslation('componentContextMenu') + + const queryClient = useQueryClient() + const mutateion = useTimelineMutation({ + onSuccess: (_, params) => { + const theParams = params as MutationVarsTimelineUpdateAccountProperty + displayMessage({ + theme, + type: 'success', + message: t('common:message.success.message', { + function: t(`account.${theParams.payload.property}.action`) + }) + }) + }, + onError: (err: any, params) => { + const theParams = params as MutationVarsTimelineUpdateAccountProperty + displayMessage({ + theme, + type: 'error', + message: t('common:message.error.message', { + function: t(`account.${theParams.payload.property}.action`) + }), + ...(err.status && + typeof err.status === 'number' && + err.data && + err.data.error && + typeof err.data.error === 'string' && { + description: err.data.error + }) + }) + }, + onSettled: () => { + queryKey && queryClient.invalidateQueries(queryKey) + rootQueryKey && queryClient.invalidateQueries(rootQueryKey) + } + }) + + const instanceAccount = useSelector( + getInstanceAccount, + (prev, next) => prev.id === next.id + ) + const ownAccount = instanceAccount?.id === accountId + + if (!ownAccount) { + switch (Platform.OS) { + case 'ios': + actions.push({ + id: 'account', + title: t('account.title'), + inlineChildren: true, + actions: [ + { + id: 'account-mute', + title: t('account.mute.action'), + systemIcon: 'eye.slash' + }, + { + id: 'account-block', + title: t('account.block.action'), + systemIcon: 'xmark.circle', + destructive: true + }, + { + id: 'account-reports', + title: t('account.reports.action'), + systemIcon: 'flag', + destructive: true + } + ] + }) + break + default: + actions.push( + { + id: 'account-mute', + title: t('account.mute.action'), + systemIcon: 'eye.slash' + }, + { + id: 'account-block', + title: t('account.block.action'), + systemIcon: 'xmark.circle', + destructive: true + }, + { + id: 'account-reports', + title: t('account.reports.action'), + systemIcon: 'flag', + destructive: true + } + ) + break + } + } + + return (id: string) => { + switch (id) { + case 'account-mute': + analytics('timeline_shared_headeractions_account_mute_press', { + page: queryKey && queryKey[1].page + }) + mutateion.mutate({ + type: 'updateAccountProperty', + queryKey, + id: accountId, + payload: { property: 'mute' } + }) + break + case 'account-block': + analytics('timeline_shared_headeractions_account_block_press', { + page: queryKey && queryKey[1].page + }) + mutateion.mutate({ + type: 'updateAccountProperty', + queryKey, + id: accountId, + payload: { property: 'block' } + }) + break + case 'account-report': + analytics('timeline_shared_headeractions_account_reports_press', { + page: queryKey && queryKey[1].page + }) + mutateion.mutate({ + type: 'updateAccountProperty', + queryKey, + id: accountId, + payload: { property: 'reports' } + }) + break + } + } +} + +export default contextMenuAccount diff --git a/src/components/ContextMenu/instance.ts b/src/components/ContextMenu/instance.ts new file mode 100644 index 00000000..676bc8ad --- /dev/null +++ b/src/components/ContextMenu/instance.ts @@ -0,0 +1,108 @@ +import analytics from '@components/analytics' +import { displayMessage } from '@components/Message' +import { + QueryKeyTimeline, + useTimelineMutation +} from '@utils/queryHooks/timeline' +import { getInstanceUrl } from '@utils/slices/instancesSlice' +import { useTheme } from '@utils/styles/ThemeManager' +import { useTranslation } from 'react-i18next' +import { Alert, Platform } from 'react-native' +import { ContextMenuAction } from 'react-native-context-menu-view' +import { useQueryClient } from 'react-query' +import { useSelector } from 'react-redux' + +export interface Props { + actions: ContextMenuAction[] + status: Mastodon.Status + queryKey: QueryKeyTimeline + rootQueryKey?: QueryKeyTimeline +} + +const contextMenuInstance = ({ + actions, + status, + queryKey, + rootQueryKey +}: Props) => { + const { t } = useTranslation('componentContextMenu') + const { theme } = useTheme() + + const currentInstance = useSelector(getInstanceUrl) + const instance = status.uri && status.uri.split(new RegExp(/\/\/(.*?)\//))[1] + + const queryClient = useQueryClient() + const mutation = useTimelineMutation({ + onSettled: () => { + displayMessage({ + theme, + type: 'success', + message: t('common:message.success.message', { + function: t(`instance.block.action`, { instance }) + }) + }) + queryClient.invalidateQueries(queryKey) + rootQueryKey && queryClient.invalidateQueries(rootQueryKey) + } + }) + + if (currentInstance !== instance && instance) { + switch (Platform.OS) { + case 'ios': + actions.push({ + id: 'instance', + title: t('instance.title'), + actions: [ + { + id: 'instance-block', + title: t('instance.block.action', { instance }), + destructive: true + } + ] + }) + break + default: + actions.push({ + id: 'instance-block', + title: t('instance.block.action', { instance }), + destructive: true + }) + break + } + } + + return (id: string) => { + switch (id) { + case 'instance-block': + analytics('timeline_shared_headeractions_domain_block_press', { + page: queryKey[1].page + }) + Alert.alert( + t('instance.block.alert.title', { instance }), + t('instance.block.alert.message'), + [ + { + text: t('instance.block.alert.buttons.confirm'), + style: 'destructive', + onPress: () => { + analytics( + 'timeline_shared_headeractions_domain_block_confirm', + { page: queryKey && queryKey[1].page } + ) + mutation.mutate({ + type: 'domainBlock', + queryKey, + domain: instance + }) + } + }, + { + text: t('common:buttons.cancel') + } + ] + ) + } + } +} + +export default contextMenuInstance diff --git a/src/components/ContextMenu/share.ts b/src/components/ContextMenu/share.ts new file mode 100644 index 00000000..4f7b25ec --- /dev/null +++ b/src/components/ContextMenu/share.ts @@ -0,0 +1,38 @@ +import analytics from '@components/analytics' +import { useTranslation } from 'react-i18next' +import { Platform, Share } from 'react-native' +import { ContextMenuAction } from 'react-native-context-menu-view' + +export interface Props { + actions: ContextMenuAction[] + type: 'status' | 'account' + url: string +} + +const contextMenuShare = ({ actions, type, url }: Props) => { + const { t } = useTranslation('componentContextMenu') + + actions.push({ + id: 'share', + title: t(`share.${type}.action`), + systemIcon: 'square.and.arrow.up' + }) + + return (id: string) => { + switch (id) { + case 'share': + analytics('timeline_shared_headeractions_share_press') + switch (Platform.OS) { + case 'ios': + Share.share({ url }) + break + case 'android': + Share.share({ message: url }) + break + } + break + } + } +} + +export default contextMenuShare diff --git a/src/components/ContextMenu/status.ts b/src/components/ContextMenu/status.ts new file mode 100644 index 00000000..8867b01a --- /dev/null +++ b/src/components/ContextMenu/status.ts @@ -0,0 +1,286 @@ +import apiInstance from '@api/instance' +import analytics from '@components/analytics' +import { displayMessage } from '@components/Message' +import { useNavigation } from '@react-navigation/native' +import { NativeStackNavigationProp } from '@react-navigation/native-stack' +import { RootStackParamList } from '@utils/navigation/navigators' +import { + MutationVarsTimelineUpdateStatusProperty, + QueryKeyTimeline, + useTimelineMutation +} from '@utils/queryHooks/timeline' +import { + checkInstanceFeature, + getInstanceAccount +} from '@utils/slices/instancesSlice' +import { useTheme } from '@utils/styles/ThemeManager' +import { useTranslation } from 'react-i18next' +import { Alert, Platform } from 'react-native' +import { ContextMenuAction } from 'react-native-context-menu-view' +import { useQueryClient } from 'react-query' +import { useSelector } from 'react-redux' + +export interface Props { + actions: ContextMenuAction[] + status: Mastodon.Status + queryKey: QueryKeyTimeline + rootQueryKey?: QueryKeyTimeline +} + +const contextMenuStatus = ({ + actions, + status, + queryKey, + rootQueryKey +}: Props) => { + const navigation = + useNavigation< + NativeStackNavigationProp + >() + const { theme } = useTheme() + const { t } = useTranslation('componentContextMenu') + + const queryClient = useQueryClient() + const mutation = useTimelineMutation({ + onMutate: true, + onError: (err: any, params, oldData) => { + const theFunction = (params as MutationVarsTimelineUpdateStatusProperty) + .payload + ? (params as MutationVarsTimelineUpdateStatusProperty).payload.property + : 'delete' + displayMessage({ + theme, + type: 'error', + message: t('common:message.error.message', { + function: t(`status.${theFunction}.action`) + }), + ...(err.status && + typeof err.status === 'number' && + err.data && + err.data.error && + typeof err.data.error === 'string' && { + description: err.data.error + }) + }) + queryClient.setQueryData(queryKey, oldData) + } + }) + + const instanceAccount = useSelector( + getInstanceAccount, + (prev, next) => prev.id === next.id + ) + const ownAccount = instanceAccount?.id === status.account.id + + if (ownAccount) { + const accountMenuItems: ContextMenuAction[] = [ + { + id: 'status-delete', + title: t('status.delete.action'), + systemIcon: 'trash', + destructive: true + }, + { + id: 'status-delete-edit', + title: t('status.deleteEdit.action'), + systemIcon: 'pencil.and.outline', + destructive: true + }, + { + id: 'status-mute', + title: t('status.mute.action-muted', { + context: status.muted.toString() + }), + systemIcon: status.muted ? 'speaker' : 'speaker.slash' + } + ] + + const canEditPost = useSelector(checkInstanceFeature('edit_post')) + if (canEditPost) { + accountMenuItems.unshift({ + id: 'status-edit', + title: t('status.edit.action'), + systemIcon: 'square.and.pencil' + }) + } + + if (status.visibility === 'public' || status.visibility === 'unlisted') { + accountMenuItems.push({ + id: 'status-pin', + title: t('status.pin.action-pinned', { + context: status.pinned.toString() + }), + systemIcon: status.pinned ? 'pin.slash' : 'pin' + }) + } + + switch (Platform.OS) { + case 'ios': + actions.push({ + id: 'status', + title: t('status.title'), + inlineChildren: true, + actions: accountMenuItems + }) + break + default: + actions.push(...accountMenuItems) + break + } + } + + return async (id: string) => { + switch (id) { + case 'status-delete': + analytics('timeline_shared_headeractions_status_delete_press', { + page: queryKey && queryKey[1].page + }) + Alert.alert( + t('status.delete.alert.title'), + t('status.delete.alert.message'), + [ + { + text: t('status.delete.alert.buttons.confirm'), + style: 'destructive', + onPress: async () => { + analytics( + 'timeline_shared_headeractions_status_delete_confirm', + { + page: queryKey && queryKey[1].page + } + ) + mutation.mutate({ + type: 'deleteItem', + source: 'statuses', + queryKey, + rootQueryKey, + id: status.id + }) + } + }, + { + text: t('common:buttons.cancel') + } + ] + ) + break + case 'status-delete-edit': + analytics('timeline_shared_headeractions_status_deleteedit_press', { + page: queryKey && queryKey[1].page + }) + Alert.alert( + t('status.deleteEdit.alert.title'), + t('status.deleteEdit.alert.message'), + [ + { + text: t('status.deleteEdit.alert.buttons.confirm'), + style: 'destructive', + onPress: async () => { + analytics( + 'timeline_shared_headeractions_status_deleteedit_confirm', + { + page: queryKey && queryKey[1].page + } + ) + let replyToStatus: Mastodon.Status | undefined = undefined + if (status.in_reply_to_id) { + replyToStatus = await apiInstance({ + method: 'get', + url: `statuses/${status.in_reply_to_id}` + }).then(res => res.body) + } + mutation + .mutateAsync({ + type: 'deleteItem', + source: 'statuses', + queryKey, + id: status.id + }) + .then(res => { + navigation.navigate('Screen-Compose', { + type: 'deleteEdit', + incomingStatus: res.body as Mastodon.Status, + ...(replyToStatus && { replyToStatus }), + queryKey + }) + }) + } + }, + { + text: t('common:buttons.cancel') + } + ] + ) + break + case 'status-mute': + analytics('timeline_shared_headeractions_status_mute_press', { + page: queryKey && queryKey[1].page + }) + mutation.mutate({ + type: 'updateStatusProperty', + queryKey, + rootQueryKey, + id: status.id, + payload: { + property: 'muted', + currentValue: status.muted, + propertyCount: undefined, + countValue: undefined + } + }) + break + case 'status-edit': + analytics('timeline_shared_headeractions_status_edit_press', { + page: queryKey && queryKey[1].page + }) + let replyToStatus: Mastodon.Status | undefined = undefined + if (status.in_reply_to_id) { + replyToStatus = await apiInstance({ + method: 'get', + url: `statuses/${status.in_reply_to_id}` + }).then(res => res.body) + } + apiInstance<{ + id: Mastodon.Status['id'] + text: NonNullable + spoiler_text: Mastodon.Status['spoiler_text'] + }>({ + method: 'get', + url: `statuses/${status.id}/source` + }).then(res => { + navigation.navigate('Screen-Compose', { + type: 'edit', + incomingStatus: { + ...status, + text: res.body.text, + spoiler_text: res.body.spoiler_text + }, + ...(replyToStatus && { replyToStatus }), + queryKey, + rootQueryKey + }) + }) + break + case 'status-pin': + // Also note that reblogs cannot be pinned. + analytics('timeline_shared_headeractions_status_pin_press', { + page: queryKey && queryKey[1].page + }) + mutation.mutate({ + type: 'updateStatusProperty', + queryKey, + rootQueryKey, + id: status.id, + payload: { + property: 'pinned', + currentValue: status.pinned, + propertyCount: undefined, + countValue: undefined + } + }) + break + } + } +} + +export default contextMenuStatus diff --git a/src/components/Timeline/Default.tsx b/src/components/Timeline/Default.tsx index 9d863144..6c84aec3 100644 --- a/src/components/Timeline/Default.tsx +++ b/src/components/Timeline/Default.tsx @@ -18,6 +18,7 @@ import { uniqBy } from 'lodash' import React, { useCallback } from 'react' import { Pressable, View } from 'react-native' import { useSelector } from 'react-redux' +import TimelineContextMenu from './Shared/ContextMenu' import TimelineFeedback from './Shared/Feedback' import TimelineFiltered, { shouldFilter } from './Shared/Filtered' import TimelineFullConversation from './Shared/FullConversation' @@ -73,96 +74,108 @@ const TimelineDefault: React.FC = ({ }, []) return ( - - {item.reblog ? ( - - ) : item._pinned ? ( - - ) : null} - - - - - - - {}} > - {typeof actualStatus.content === 'string' && - actualStatus.content.length > 0 ? ( - + ) : item._pinned ? ( + + ) : null} + + + + - ) : null} - {queryKey && actualStatus.poll ? ( - + + + {typeof actualStatus.content === 'string' && + actualStatus.content.length > 0 ? ( + + ) : null} + {queryKey && actualStatus.poll ? ( + + ) : null} + {!disableDetails && + Array.isArray(actualStatus.media_attachments) && + actualStatus.media_attachments.length ? ( + + ) : null} + {!disableDetails && actualStatus.card ? ( + + ) : null} + {!disableDetails ? ( + + ) : null} + + + + + {queryKey && !disableDetails ? ( + d?.id !== instanceAccount?.id), + d => d?.id + ).map(d => d?.acct)} reblog={item.reblog ? true : false} - sameAccount={ownAccount} /> ) : null} - {!disableDetails && - Array.isArray(actualStatus.media_attachments) && - actualStatus.media_attachments.length ? ( - - ) : null} - {!disableDetails && actualStatus.card ? ( - - ) : null} - {!disableDetails ? ( - - ) : null} - - - - - {queryKey && !disableDetails ? ( - d?.id !== instanceAccount?.id), - d => d?.id - ).map(d => d?.acct)} - reblog={item.reblog ? true : false} - /> - ) : null} - + + ) } diff --git a/src/components/Timeline/Notifications.tsx b/src/components/Timeline/Notifications.tsx index c4df686f..80be1816 100644 --- a/src/components/Timeline/Notifications.tsx +++ b/src/components/Timeline/Notifications.tsx @@ -18,6 +18,7 @@ import { isEqual, uniqBy } from 'lodash' import React, { useCallback } from 'react' import { Pressable, View } from 'react-native' import { useSelector } from 'react-redux' +import TimelineContextMenu from './Shared/ContextMenu' import TimelineFiltered, { shouldFilter } from './Shared/Filtered' import TimelineFullConversation from './Shared/FullConversation' @@ -58,103 +59,105 @@ const TimelineNotifications = React.memo( }, []) return ( - - {notification.type !== 'mention' ? ( - - ) : null} - - + {}} > - - - + ) : null} + + + + + + + + {notification.status ? ( + + {notification.status.content.length > 0 ? ( + + ) : null} + {notification.status.poll ? ( + + ) : null} + {notification.status.media_attachments.length > 0 ? ( + + ) : null} + {notification.status.card ? ( + + ) : null} + + + ) : null} {notification.status ? ( - - {notification.status.content.length > 0 ? ( - - ) : null} - {notification.status.poll ? ( - - ) : null} - {notification.status.media_attachments.length > 0 ? ( - - ) : null} - {notification.status.card ? ( - - ) : null} - - + d?.id !== instanceAccount?.id), + d => d?.id + ).map(d => d?.acct)} + reblog={false} + /> ) : null} - - - {notification.status ? ( - d?.id !== instanceAccount?.id), - d => d?.id - ).map(d => d?.acct)} - reblog={false} - /> - ) : null} - + + ) }, (prev, next) => isEqual(prev.notification, next.notification) diff --git a/src/components/Timeline/Shared/ContextMenu.tsx b/src/components/Timeline/Shared/ContextMenu.tsx new file mode 100644 index 00000000..f11af4b4 --- /dev/null +++ b/src/components/Timeline/Shared/ContextMenu.tsx @@ -0,0 +1,82 @@ +import contextMenuAccount from '@components/ContextMenu/account' +import contextMenuInstance from '@components/ContextMenu/instance' +import contextMenuShare from '@components/ContextMenu/share' +import contextMenuStatus from '@components/ContextMenu/status' +import { QueryKeyTimeline } from '@utils/queryHooks/timeline' +import React from 'react' +import { createContext } from 'react' +import ContextMenu, { + ContextMenuAction, + ContextMenuProps +} from 'react-native-context-menu-view' + +export interface Props { + status?: Mastodon.Status + queryKey?: QueryKeyTimeline + rootQueryKey?: QueryKeyTimeline +} + +export const ContextMenuContext = createContext([]) + +const TimelineContextMenu: React.FC = ({ + children, + status, + queryKey, + rootQueryKey, + ...props +}) => { + if (!status || !queryKey) { + return <>{children} + } + + const actions: ContextMenuAction[] = [] + + const shareOnPress = + status.visibility !== 'direct' + ? contextMenuShare({ + actions, + type: 'status', + url: status.url || status.uri + }) + : null + const statusOnPress = contextMenuStatus({ + actions, + status, + queryKey, + rootQueryKey + }) + const accountOnPress = contextMenuAccount({ + actions, + queryKey, + rootQueryKey, + id: status.account.id + }) + const instanceOnPress = contextMenuInstance({ + actions, + status, + queryKey, + rootQueryKey + }) + + return ( + + { + for (const on of [ + shareOnPress, + statusOnPress, + accountOnPress, + instanceOnPress + ]) { + on && on(id) + } + }} + children={children} + {...props} + /> + + ) +} + +export default TimelineContextMenu diff --git a/src/components/Timeline/Shared/HeaderDefault.tsx b/src/components/Timeline/Shared/HeaderDefault.tsx index b4db437b..80a1c1bb 100644 --- a/src/components/Timeline/Shared/HeaderDefault.tsx +++ b/src/components/Timeline/Shared/HeaderDefault.tsx @@ -1,13 +1,12 @@ import Icon from '@components/Icon' -import { useNavigation } from '@react-navigation/native' -import { StackNavigationProp } from '@react-navigation/stack' -import { RootStackParamList } from '@utils/navigation/navigators' import { QueryKeyTimeline } from '@utils/queryHooks/timeline' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' -import React from 'react' +import React, { useContext } from 'react' import { useTranslation } from 'react-i18next' import { Pressable, View } from 'react-native' +import ContextMenu from 'react-native-context-menu-view' +import { ContextMenuContext } from './ContextMenu' import HeaderSharedAccount from './HeaderShared/Account' import HeaderSharedApplication from './HeaderShared/Application' import HeaderSharedCreated from './HeaderShared/Created' @@ -16,24 +15,19 @@ import HeaderSharedVisibility from './HeaderShared/Visibility' export interface Props { queryKey?: QueryKeyTimeline - rootQueryKey?: QueryKeyTimeline status: Mastodon.Status highlighted: boolean } -const TimelineHeaderDefault = ({ - queryKey, - rootQueryKey, - status, - highlighted -}: Props) => { - const { t } = useTranslation('componentTimeline') - const navigation = useNavigation>() +const TimelineHeaderDefault = ({ queryKey, status, highlighted }: Props) => { + const { t } = useTranslation('componentContextMenu') const { colors } = useTheme() + const contextMenuContext = useContext(ContextMenuContext) + return ( - + - navigation.navigate('Screen-Actions', { - queryKey, - rootQueryKey, - status, - type: 'status' - }) - } - children={ - - } - /> + > + {}} + children={ + + } + /> + ) : null} ) diff --git a/src/components/Timeline/Shared/HeaderNotification.tsx b/src/components/Timeline/Shared/HeaderNotification.tsx index 20bc735a..a9b30f2e 100644 --- a/src/components/Timeline/Shared/HeaderNotification.tsx +++ b/src/components/Timeline/Shared/HeaderNotification.tsx @@ -3,14 +3,12 @@ import { RelationshipIncoming, RelationshipOutgoing } from '@components/Relationship' -import { useNavigation } from '@react-navigation/native' -import { StackNavigationProp } from '@react-navigation/stack' -import { RootStackParamList } from '@utils/navigation/navigators' -import { QueryKeyTimeline } from '@utils/queryHooks/timeline' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' -import React, { useMemo } from 'react' +import React, { useContext, useMemo } from 'react' import { Pressable, View } from 'react-native' +import ContextMenu from 'react-native-context-menu-view' +import { ContextMenuContext } from './ContextMenu' import HeaderSharedAccount from './HeaderShared/Account' import HeaderSharedApplication from './HeaderShared/Application' import HeaderSharedCreated from './HeaderShared/Created' @@ -18,14 +16,14 @@ import HeaderSharedMuted from './HeaderShared/Muted' import HeaderSharedVisibility from './HeaderShared/Visibility' export interface Props { - queryKey: QueryKeyTimeline notification: Mastodon.Notification } -const TimelineHeaderNotification = ({ queryKey, notification }: Props) => { - const navigation = useNavigation>() +const TimelineHeaderNotification = ({ notification }: Props) => { const { colors } = useTheme() + const contextMenuContext = useContext(ContextMenuContext) + const actions = useMemo(() => { switch (notification.type) { case 'follow': @@ -42,18 +40,18 @@ const TimelineHeaderNotification = ({ queryKey, notification }: Props) => { justifyContent: 'center', paddingBottom: StyleConstants.Spacing.S }} - onPress={() => - navigation.navigate('Screen-Actions', { - queryKey, - status: notification.status!, - type: 'status' - }) - } children={ - {}} + children={ + + } /> } /> diff --git a/src/components/mediaSelector.ts b/src/components/mediaSelector.ts index 50ad1adc..ffc92b9f 100644 --- a/src/components/mediaSelector.ts +++ b/src/components/mediaSelector.ts @@ -1,17 +1,20 @@ import analytics from '@components/analytics' import { ActionSheetOptions } from '@expo/react-native-action-sheet' -import * as ImageManipulator from 'expo-image-manipulator' -import * as ImagePicker from 'expo-image-picker' -import { - ImageInfo, - UIImagePickerPresentationStyle -} from 'expo-image-picker/build/ImagePicker.types' +import { store } from '@root/store' +import { getInstanceConfigurationStatusMaxAttachments } from '@utils/slices/instancesSlice' +import * as ExpoImagePicker from 'expo-image-picker' import i18next from 'i18next' -import { Alert, Linking, Platform } from 'react-native' +import { Alert, Linking } from 'react-native' +import ImagePicker, { + Image, + ImageOrVideo +} from 'react-native-image-crop-picker' export interface Props { - mediaTypes?: ImagePicker.MediaTypeOptions - resize?: { width?: number; height?: number } // Resize mode contain + mediaType?: 'photo' | 'video' + resize?: { width?: number; height?: number } + maximum?: number + indicateMaximum?: boolean showActionSheetWithOptions: ( options: ActionSheetOptions, callback: (i?: number | undefined) => void | Promise @@ -19,134 +22,164 @@ export interface Props { } const mediaSelector = async ({ - mediaTypes = ImagePicker.MediaTypeOptions.All, + mediaType, resize, + maximum, + indicateMaximum = false, showActionSheetWithOptions -}: Props): Promise => { - return new Promise((resolve, reject) => { - const resolveResult = async (result: ImageInfo) => { - if (resize && result.type === 'image') { - let newResult: ImageManipulator.ImageResult - if (resize.width && resize.height) { - if (resize.width / resize.height > result.width / result.height) { - newResult = await ImageManipulator.manipulateAsync(result.uri, [ - { resize: { width: resize.width } } - ]) - } else { - newResult = await ImageManipulator.manipulateAsync(result.uri, [ - { resize: { height: resize.height } } - ]) +}: Props): Promise => { + const checkLibraryPermission = async (): Promise => { + const { status } = + await ExpoImagePicker.requestMediaLibraryPermissionsAsync() + if (status !== 'granted') { + Alert.alert( + i18next.t('componentMediaSelector:library.alert.title'), + i18next.t('componentMediaSelector:library.alert.message'), + [ + { + text: i18next.t('common:buttons.cancel'), + style: 'cancel', + onPress: () => + analytics('mediaSelector_nopermission', { + action: 'cancel' + }) + }, + { + text: i18next.t( + 'componentMediaSelector:library.alert.buttons.settings' + ), + style: 'default', + onPress: () => { + analytics('mediaSelector_nopermission', { + action: 'settings' + }) + Linking.openURL('app-settings:') + } } - } else { - newResult = await ImageManipulator.manipulateAsync(result.uri, [ - { resize } - ]) - } - resolve({ ...newResult, cancelled: false }) + ] + ) + return false + } else { + return true + } + } + + const _maximum = + maximum || + getInstanceConfigurationStatusMaxAttachments(store.getState()) || + 4 + + const options = () => { + switch (mediaType) { + case 'photo': + return [ + i18next.t( + 'componentMediaSelector:options.image', + indicateMaximum ? { context: 'max', max: _maximum } : undefined + ), + i18next.t('common:buttons.cancel') + ] + case 'video': + return [ + i18next.t( + 'componentMediaSelector:options.video', + indicateMaximum ? { context: 'max', max: 1 } : undefined + ), + i18next.t('common:buttons.cancel') + ] + default: + return [ + i18next.t( + 'componentMediaSelector:options.image', + indicateMaximum ? { context: 'max', max: _maximum } : undefined + ), + i18next.t( + 'componentMediaSelector:options.video', + indicateMaximum ? { context: 'max', max: 1 } : undefined + ), + i18next.t('common:buttons.cancel') + ] + } + } + + return new Promise((resolve, reject) => { + const selectImage = async () => { + const images = await ImagePicker.openPicker({ + mediaType: 'photo', + includeExif: false, + multiple: true, + minFiles: 1, + maxFiles: _maximum, + loadingLabelText: '', + compressImageMaxWidth: 4096, + compressImageMaxHeight: 4096 + }).catch(() => {}) + + if (!images) { + return reject() + } + + if (!resize) { + return resolve(images) } else { - resolve(result) + const croppedImages: Image[] = [] + for (const image of images) { + const croppedImage = await ImagePicker.openCropper({ + mediaType: 'photo', + path: image.path, + width: resize.width, + height: resize.height, + cropperChooseText: i18next.t('common:buttons.apply'), + cropperCancelText: i18next.t('common:buttons.cancel'), + hideBottomControls: true + }).catch(() => {}) + croppedImage && croppedImages.push(croppedImage) + } + return resolve(croppedImages) } } + const selectVideo = async () => { + const video = await ImagePicker.openPicker({ + mediaType: 'video', + includeExif: false, + loadingLabelText: '' + }).catch(() => {}) + if (video) { + return resolve([video]) + } else { + return reject() + } + } showActionSheetWithOptions( { title: i18next.t('componentMediaSelector:title'), - options: [ - i18next.t('componentMediaSelector:options.library'), - i18next.t('componentMediaSelector:options.photo'), - i18next.t('componentMediaSelector:options.cancel') - ], - cancelButtonIndex: 2 + options: options(), + cancelButtonIndex: mediaType ? 1 : 2 }, async buttonIndex => { - if (buttonIndex === 0) { - const { status } = - await ImagePicker.requestMediaLibraryPermissionsAsync() - if (status !== 'granted') { - Alert.alert( - i18next.t('componentMediaSelector:library.alert.title'), - i18next.t('componentMediaSelector:library.alert.message'), - [ - { - text: i18next.t( - 'componentMediaSelector:library.alert.buttons.cancel' - ), - style: 'cancel', - onPress: () => - analytics('mediaSelector_nopermission', { - action: 'cancel' - }) - }, - { - text: i18next.t( - 'componentMediaSelector:library.alert.buttons.settings' - ), - style: 'default', - onPress: () => { - analytics('mediaSelector_nopermission', { - action: 'settings' - }) - Linking.openURL('app-settings:') - } - } - ] - ) - } else { - const result = await ImagePicker.launchImageLibraryAsync({ - mediaTypes, - exif: false, - presentationStyle: - Platform.OS === 'ios' && parseInt(Platform.Version) < 13 - ? UIImagePickerPresentationStyle.FULL_SCREEN - : UIImagePickerPresentationStyle.AUTOMATIC - }) + if (!(await checkLibraryPermission())) { + return reject() + } - if (!result.cancelled) { - await resolveResult(result) + switch (mediaType) { + case 'photo': + if (buttonIndex === 0) { + await selectImage() } - } - } else if (buttonIndex === 1) { - const { status } = await ImagePicker.requestCameraPermissionsAsync() - if (status !== 'granted') { - Alert.alert( - i18next.t('componentMediaSelector:photo.alert.title'), - i18next.t('componentMediaSelector:photo.alert.message'), - [ - { - text: i18next.t( - 'componentMediaSelector:photo.alert.buttons.cancel' - ), - style: 'cancel', - onPress: () => { - analytics('compose_addattachment_camera_nopermission', { - action: 'cancel' - }) - } - }, - { - text: i18next.t( - 'componentMediaSelector:photo.alert.buttons.settings' - ), - style: 'default', - onPress: () => { - analytics('compose_addattachment_camera_nopermission', { - action: 'settings' - }) - Linking.openURL('app-settings:') - } - } - ] - ) - } else { - const result = await ImagePicker.launchCameraAsync({ - mediaTypes, - exif: false - }) - - if (!result.cancelled) { - await resolveResult(result) + break + case 'video': + if (buttonIndex === 0) { + await selectVideo() } - } + break + default: + if (buttonIndex === 0) { + await selectImage() + } else if (buttonIndex === 1) { + await selectVideo() + } + break } } ) diff --git a/src/i18n/de/components/contextMenu.json b/src/i18n/de/components/contextMenu.json new file mode 100644 index 00000000..3738d471 --- /dev/null +++ b/src/i18n/de/components/contextMenu.json @@ -0,0 +1,70 @@ +{ + "accessibilityHint": "Funktionen für diesen Tröt - wie z. B. Autor und Originaltröt", + "account": { + "title": "", + "mute": { + "action": "Profil stummschalten" + }, + "block": { + "action": "Nutzer blockieren" + }, + "reports": { + "action": "User melden" + } + }, + "instance": { + "title": "", + "block": { + "action": "Instanz {{instance}} blockieren", + "alert": { + "title": "", + "message": "Üblicherweise kannst du einen User stummschalten oder blockieren.\nBlockierst du hingegegen eine Instanz, wird deren gesamter Inhalt samt Usern, die dir von dieser Instanz folgen, entfernt!", + "buttons": { + "confirm": "Bestätigen" + } + } + } + }, + "share": { + "status": { + "action": "Tröt teilen" + }, + "account": { + "action": "User verlinken" + } + }, + "status": { + "title": "", + "edit": { + "action": "Tröt bearbeiten" + }, + "delete": { + "action": "Tröt löschen", + "alert": { + "title": "Löschen bestätigen?", + "message": "", + "buttons": { + "confirm": "Bestätigen" + } + } + }, + "deleteEdit": { + "action": "", + "alert": { + "title": "", + "message": "", + "buttons": { + "confirm": "Bestätigen" + } + } + }, + "mute": { + "action-muted_false": "", + "action-muted_true": "" + }, + "pin": { + "action-pinned_false": "", + "action-pinned_true": "" + } + } +} \ No newline at end of file diff --git a/src/i18n/de/components/mediaSelector.json b/src/i18n/de/components/mediaSelector.json index d460f005..8789b337 100644 --- a/src/i18n/de/components/mediaSelector.json +++ b/src/i18n/de/components/mediaSelector.json @@ -1,27 +1,17 @@ { "title": "Datenquelle auswählen", "options": { - "library": "Hochladen", - "photo": "Bild aufnehmen", - "cancel": "$t(common:buttons.cancel)" + "image": "", + "image_max": "", + "video": "", + "video_max": "" }, "library": { "alert": { "title": "Kein Zugriff", "message": "Für den Upload ist eine Zugriffsgenehmigung erforderlich", "buttons": { - "settings": "Einstellungen bestätigen", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "photo": { - "alert": { - "title": "Zugriff verweigert", - "message": "Zugriff auf die Kamera erforderlich", - "buttons": { - "settings": "Einstellungen übernehmen", - "cancel": "$t(common:buttons.cancel)" + "settings": "Einstellungen bestätigen" } } } diff --git a/src/i18n/de/components/timeline.json b/src/i18n/de/components/timeline.json index 0945c559..993af2ff 100644 --- a/src/i18n/de/components/timeline.json +++ b/src/i18n/de/components/timeline.json @@ -123,94 +123,6 @@ "delete": { "function": "Nachricht löschen" } - }, - "actions": { - "accessibilityHint": "Funktionen für diesen Tröt - wie z. B. Autor und Originaltröt", - "account": { - "heading": "Über die Nutzerin/den Nutzer", - "mute": { - "function": "Profil stummschalten", - "button": "@{{acct}} stummschalten" - }, - "block": { - "function": "Nutzer blockieren", - "button": "@{{acct}} blockieren" - }, - "reports": { - "function": "User melden", - "button": "@{{acct}} melden" - } - }, - "domain": { - "heading": "Über diese Instanz", - "block": { - "function": "Instanz blockieren", - "button": "Instanz {{domain}} blockieren" - }, - "alert": { - "title": "{{domain}} wirklich blockieren?", - "message": "Üblicherweise kannst du einen User stummschalten oder blockieren.\nBlockierst du hingegegen eine Instanz, wird deren gesamter Inhalt samt Usern, die dir von dieser Instanz folgen, entfernt!", - "buttons": { - "confirm": "Blockierung bestätigen", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "share": { - "status": { - "heading": "Tröt teilen", - "button": "Link zu diesem Tröt teilen" - }, - "account": { - "heading": "User verlinken", - "button": "Link zu diesem Benutzer teilen" - } - }, - "status": { - "heading": "Über Toot", - "edit": { - "function": "Tröt bearbeiten", - "button": "Diesen Tröt bearbeiten" - }, - "delete": { - "function": "Tröt löschen", - "button": "Diesen Tröt löschen", - "alert": { - "title": "Tröt sicher löschen?", - "message": "Bist du wirklich sicher, diesen Tröt löschen zu wollen? Sämtliche Boosts und Sterne werden samt der Antworten entfernt.", - "buttons": { - "confirm": "Löschen bestätigen", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "deleteEdit": { - "function": "Tröt löschen", - "button": "Diesen Tröt neu entwerfen", - "alert": { - "title": "Tröt sicher löschen?", - "message": "Bist du wirklich sicher, diesen Tröt neu zu entwerfen? Alle Boosts und Sterne werden entfernt - samt der Antworten.", - "buttons": { - "confirm": "Löschen bestätigen", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "mute": { - "function": "Tröt stummschalten", - "button": { - "positive": "Diesen Tröt sowie die Antworten stummschalten", - "negative": "Diesen Tröt sowie die Antworten nicht mehr stummschalten" - } - }, - "pin": { - "function": "Anheften", - "button": { - "positive": "Diesen Tröt anheften", - "negative": "Diesen Tröt nicht mehr anheften" - } - } - } } }, "poll": { diff --git a/src/i18n/de/screens/actions.json b/src/i18n/de/screens/actions.json index 6cc3110b..fa3f5a6d 100644 --- a/src/i18n/de/screens/actions.json +++ b/src/i18n/de/screens/actions.json @@ -1,8 +1,7 @@ { "content": { - "button": { - "apply": "$t(common:buttons.apply)", - "cancel": "$t(common:buttons.cancel)" + "altText": { + "heading": "" }, "notificationsFilter": { "heading": "Benachrichtigungsart anzeigen", diff --git a/src/i18n/en/_all.ts b/src/i18n/en/_all.ts index fa81be2e..5f2a7a82 100644 --- a/src/i18n/en/_all.ts +++ b/src/i18n/en/_all.ts @@ -8,6 +8,7 @@ export default { screenImageViewer: require('./screens/imageViewer'), screenTabs: require('./screens/tabs'), + componentContextMenu: require('./components/contextMenu'), componentEmojis: require('./components/emojis'), componentInstance: require('./components/instance'), componentMediaSelector: require('./components/mediaSelector'), diff --git a/src/i18n/en/components/contextMenu.json b/src/i18n/en/components/contextMenu.json new file mode 100644 index 00000000..538c7a4f --- /dev/null +++ b/src/i18n/en/components/contextMenu.json @@ -0,0 +1,70 @@ +{ + "accessibilityHint": "Actions for this toot, such as its posted user, toot itself", + "account": { + "title": "User actions", + "mute": { + "action": "Mute user" + }, + "block": { + "action": "Block user" + }, + "reports": { + "action": "Report user" + } + }, + "instance": { + "title": "Instance action", + "block": { + "action": "Block instance {{instance}}", + "alert": { + "title": "Confirm blocking instance {{instance}} ?", + "message": "Mostly you can mute or block certain user.\n\nAfter blocking instance, all its content including followers from this instance will be removed!", + "buttons": { + "confirm": "Confirm" + } + } + } + }, + "share": { + "status": { + "action": "Share toot" + }, + "account": { + "action": "Share user" + } + }, + "status": { + "title": "Toot actions", + "edit": { + "action": "Edit toot" + }, + "delete": { + "action": "Delete toot", + "alert": { + "title": "Confirm deleting?", + "message": "All boosts and favourites will be cleared, including all replies.", + "buttons": { + "confirm": "Confirm" + } + } + }, + "deleteEdit": { + "action": "Delete toot and repost", + "alert": { + "title": "Confirm deleting and repost?", + "message": "All boosts and favourites will be cleared, including all replies.", + "buttons": { + "confirm": "Confirm" + } + } + }, + "mute": { + "action-muted_false": "Mute toot and replies", + "action-muted_true": "Unmute toot and replies" + }, + "pin": { + "action-pinned_false": "Pin toot", + "action-pinned_true": "Unpin toot" + } + } +} \ No newline at end of file diff --git a/src/i18n/en/components/mediaSelector.json b/src/i18n/en/components/mediaSelector.json index 6f509ea7..adc0fa47 100644 --- a/src/i18n/en/components/mediaSelector.json +++ b/src/i18n/en/components/mediaSelector.json @@ -1,27 +1,17 @@ { "title": "Select media source", "options": { - "library": "Upload from library", - "photo": "Take a photo", - "cancel": "$t(common:buttons.cancel)" + "image": "Upload photos", + "image_max": "Upload photos (max {{max}})", + "video": "Upload video", + "video_max": "Upload video (max {{max}})" }, "library": { "alert": { "title": "No permission", "message": "Require photo library read permission to upload", "buttons": { - "settings": "Update setting", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "photo": { - "alert": { - "title": "No permission", - "message": "Require camera usage permission to upload", - "buttons": { - "settings": "Update setting", - "cancel": "$t(common:buttons.cancel)" + "settings": "Update setting" } } } diff --git a/src/i18n/en/components/timeline.json b/src/i18n/en/components/timeline.json index caeb15ed..6a3341a1 100644 --- a/src/i18n/en/components/timeline.json +++ b/src/i18n/en/components/timeline.json @@ -123,94 +123,6 @@ "delete": { "function": "Delete direct message" } - }, - "actions": { - "accessibilityHint": "Actions for this toot, such as its posted user, toot itself", - "account": { - "heading": "About user", - "mute": { - "function": "Mute user", - "button": "Mute @{{acct}}" - }, - "block": { - "function": "Block user", - "button": "Block @{{acct}}" - }, - "reports": { - "function": "Report user", - "button": "Report @{{acct}}" - } - }, - "domain": { - "heading": "About instance", - "block": { - "function": "Block instance", - "button": "Block instance {{domain}}" - }, - "alert": { - "title": "Confirm blocking {{domain}} ?", - "message": "Mostly you can mute or block certain user.\n\nAfter blocking instance, all its content including followers from this instance will be removed!", - "buttons": { - "confirm": "Confirm blocking", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "share": { - "status": { - "heading": "Share toot", - "button": "Share link to this toot" - }, - "account": { - "heading": "Share user", - "button": "Share link to this user" - } - }, - "status": { - "heading": "About toot", - "edit": { - "function": "Edit toot", - "button": "Edit this toot" - }, - "delete": { - "function": "Delete toot", - "button": "Delete this toot", - "alert": { - "title": "Confirm deleting toot?", - "message": "Are you sure to delete this toot? All boosts and favourites will be cleared, including all replies.", - "buttons": { - "confirm": "Confirm deleting", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "deleteEdit": { - "function": "Delete toot", - "button": "Delete and re-draft", - "alert": { - "title": "Confirm deleting toot?", - "message": "Are you sure to delete and re-draft this toot? All boosts and favourites will be cleared, including all replies.", - "buttons": { - "confirm": "Confirm deleting", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "mute": { - "function": "Mute toot", - "button": { - "positive": "Mute this toot and replies", - "negative": "Unmute this toot and replies" - } - }, - "pin": { - "function": "Pin", - "button": { - "positive": "Pin this toot", - "negative": "Unpin this toot" - } - } - } } }, "poll": { diff --git a/src/i18n/i18n.ts b/src/i18n/i18n.ts index 5e951716..37ace006 100644 --- a/src/i18n/i18n.ts +++ b/src/i18n/i18n.ts @@ -60,8 +60,8 @@ i18n.use(initReactI18next).init({ returnEmptyString: false, saveMissing: true, - missingKeyHandler: (ns, key) => { - console.log('i18n missing: ' + ns + ' : ' + key) + missingKeyHandler: (_, ns, key) => { + console.log('i18n missing', ns, key) }, interpolation: { diff --git a/src/i18n/it/components/contextMenu.json b/src/i18n/it/components/contextMenu.json new file mode 100644 index 00000000..9a138494 --- /dev/null +++ b/src/i18n/it/components/contextMenu.json @@ -0,0 +1,70 @@ +{ + "accessibilityHint": "Azioni per questo toot, per l'utente che l'ha pubblicato o per il toot stesso", + "account": { + "title": "", + "mute": { + "action": "Muta utente" + }, + "block": { + "action": "Blocca utente" + }, + "reports": { + "action": "Segnala utente" + } + }, + "instance": { + "title": "", + "block": { + "action": "Blocca istanza {{instance}}", + "alert": { + "title": "", + "message": "Sarebbe meglio mutare o bloccare singoli utenti.\n\nSe blocchi un'istanza, tutti i suoi contenuti a te relativi, inclusi tutti i tuoi seguaci da questa, saranno rimossi.", + "buttons": { + "confirm": "Ho capito" + } + } + } + }, + "share": { + "status": { + "action": "Condividi toot" + }, + "account": { + "action": "Condividi utente" + } + }, + "status": { + "title": "", + "edit": { + "action": "Modifica toot" + }, + "delete": { + "action": "Cancella toot", + "alert": { + "title": "Conferma?", + "message": "", + "buttons": { + "confirm": "Ho capito" + } + } + }, + "deleteEdit": { + "action": "", + "alert": { + "title": "", + "message": "", + "buttons": { + "confirm": "Ho capito" + } + } + }, + "mute": { + "action-muted_false": "", + "action-muted_true": "" + }, + "pin": { + "action-pinned_false": "", + "action-pinned_true": "" + } + } +} \ No newline at end of file diff --git a/src/i18n/it/components/mediaSelector.json b/src/i18n/it/components/mediaSelector.json index 5ab89dd9..57535ef6 100644 --- a/src/i18n/it/components/mediaSelector.json +++ b/src/i18n/it/components/mediaSelector.json @@ -1,27 +1,17 @@ { "title": "Seleziona origine media", "options": { - "library": "Carica da libreria locale", - "photo": "Scatta una foto", - "cancel": "$t(common:buttons.cancel)" + "image": "", + "image_max": "", + "video": "", + "video_max": "" }, "library": { "alert": { "title": "Permesso non concesso", "message": "È richiesto l'accesso ai file del dispositivo per il caricamento dalla libreria", "buttons": { - "settings": "Correggi impostazioni", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "photo": { - "alert": { - "title": "Permesso non concesso", - "message": "È richiesto l'accesso alla fotocamera per scattare foto", - "buttons": { - "settings": "Correggi impostazioni", - "cancel": "$t(common:buttons.cancel)" + "settings": "Correggi impostazioni" } } } diff --git a/src/i18n/it/components/timeline.json b/src/i18n/it/components/timeline.json index 9455ea6f..7efa9234 100644 --- a/src/i18n/it/components/timeline.json +++ b/src/i18n/it/components/timeline.json @@ -123,94 +123,6 @@ "delete": { "function": "Cancella messaggio" } - }, - "actions": { - "accessibilityHint": "Azioni per questo toot, per l'utente che l'ha pubblicato o per il toot stesso", - "account": { - "heading": "Riguardo quest'utente", - "mute": { - "function": "Muta utente", - "button": "Muta @{{acct}}" - }, - "block": { - "function": "Blocca utente", - "button": "Blocca @{{acct}}" - }, - "reports": { - "function": "Segnala utente", - "button": "Segnala @{{acct}}" - } - }, - "domain": { - "heading": "Riguardo questa istanza", - "block": { - "function": "Blocca istanza", - "button": "Blocca istanza {{domain}}" - }, - "alert": { - "title": "Conferma blocco di {{domain}} ?", - "message": "Sarebbe meglio mutare o bloccare singoli utenti.\n\nSe blocchi un'istanza, tutti i suoi contenuti a te relativi, inclusi tutti i tuoi seguaci da questa, saranno rimossi.", - "buttons": { - "confirm": "Conferma blocco", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "share": { - "status": { - "heading": "Condividi toot", - "button": "Condividi il link a questo toot" - }, - "account": { - "heading": "Condividi utente", - "button": "Share il link a questo utente" - } - }, - "status": { - "heading": "Riguardo questo toot", - "edit": { - "function": "Modifica toot", - "button": "Modifica questo toot" - }, - "delete": { - "function": "Cancella toot", - "button": "Cancella toot", - "alert": { - "title": "Cancellare il toot?", - "message": "Vuoi davvero cancellare questo toot? Tutti gli apprezzamenti, le ricondivisioni, e le risposte verranno persi.", - "buttons": { - "confirm": "Conferma", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "deleteEdit": { - "function": "Cancella toot", - "button": "Cancella e riscrivi toot", - "alert": { - "title": "Cancellare e riscrivere il toot?", - "message": "Vuoi davvero cancellare e riscrivere questo toot? Tutti gli apprezzamenti, le ricondivisioni, e le risposte verranno persi.", - "buttons": { - "confirm": "Conferma", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "mute": { - "function": "Muta toot", - "button": { - "positive": "Muta questo toot e le sue risposte", - "negative": "Smuta questo toot e le sue risposte" - } - }, - "pin": { - "function": "Fissa in cima", - "button": { - "positive": "Fissa questo toot in cima al profilo", - "negative": "Togli questo toot dalla cima del profilo" - } - } - } } }, "poll": { diff --git a/src/i18n/it/screens/actions.json b/src/i18n/it/screens/actions.json index 723c1372..349dff8a 100644 --- a/src/i18n/it/screens/actions.json +++ b/src/i18n/it/screens/actions.json @@ -1,8 +1,7 @@ { "content": { - "button": { - "apply": "$t(common:buttons.apply)", - "cancel": "$t(common:buttons.cancel)" + "altText": { + "heading": "" }, "notificationsFilter": { "heading": "Filtra notifiche per tipo", diff --git a/src/i18n/ko/components/contextMenu.json b/src/i18n/ko/components/contextMenu.json new file mode 100644 index 00000000..b1f3ba27 --- /dev/null +++ b/src/i18n/ko/components/contextMenu.json @@ -0,0 +1,70 @@ +{ + "accessibilityHint": "이 툿에 할 동작, 툿 자체나 포스트한 사용자", + "account": { + "title": "", + "mute": { + "action": "사용자 음소거" + }, + "block": { + "action": "사용자 차단" + }, + "reports": { + "action": "사용자 신고" + } + }, + "instance": { + "title": "", + "block": { + "action": "인스턴스 {{instance}} 차단", + "alert": { + "title": "", + "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-muted_false": "", + "action-muted_true": "" + }, + "pin": { + "action-pinned_false": "", + "action-pinned_true": "" + } + } +} \ No newline at end of file diff --git a/src/i18n/ko/components/mediaSelector.json b/src/i18n/ko/components/mediaSelector.json index 7d9fb7ce..2d15ced1 100644 --- a/src/i18n/ko/components/mediaSelector.json +++ b/src/i18n/ko/components/mediaSelector.json @@ -1,27 +1,17 @@ { "title": "미디어 소스 선택", "options": { - "library": "라이브러리에서 업로드", - "photo": "사진 촬영", - "cancel": "$t(common:buttons.cancel)" + "image": "", + "image_max": "", + "video": "", + "video_max": "" }, "library": { "alert": { "title": "권한 없음", "message": "업로드를 위해 사진 라이브러리 권한이 필요해요", "buttons": { - "settings": "설정 업데이트", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "photo": { - "alert": { - "title": "권한 없음", - "message": "업로드를 위해 카메라 사용 권한이 필요해요", - "buttons": { - "settings": "설정 업데이트", - "cancel": "$t(common:buttons.cancel)" + "settings": "설정 업데이트" } } } diff --git a/src/i18n/ko/components/timeline.json b/src/i18n/ko/components/timeline.json index 5b8f6e97..2cdda060 100644 --- a/src/i18n/ko/components/timeline.json +++ b/src/i18n/ko/components/timeline.json @@ -123,94 +123,6 @@ "delete": { "function": "개인 메시지 삭제" } - }, - "actions": { - "accessibilityHint": "이 툿에 할 동작, 툿 자체나 포스트한 사용자", - "account": { - "heading": "사용자 정보", - "mute": { - "function": "사용자 음소거", - "button": "@{{acct}} 음소거" - }, - "block": { - "function": "사용자 차단", - "button": "@{{acct}} 차단" - }, - "reports": { - "function": "사용자 신고", - "button": "@{{acct}} 신고" - } - }, - "domain": { - "heading": "인스턴스 정보", - "block": { - "function": "인스턴스 차단", - "button": "인스턴스 {{domain}} 차단" - }, - "alert": { - "title": "{{domain}}을 정말 차단할까요?", - "message": "보통은 유저 음소거나 차단으로 충분해요.\n\n인스턴스를 차단하면, 팔로워를 포함하는 인스턴스의 모든 콘텐츠가 삭제됩니다!", - "buttons": { - "confirm": "차단 확인", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "share": { - "status": { - "heading": "툿 공유", - "button": "이 툿의 링크 공유" - }, - "account": { - "heading": "사용자 공유", - "button": "이 사용자에게 링크 공유" - } - }, - "status": { - "heading": "툿 정보", - "edit": { - "function": "", - "button": "" - }, - "delete": { - "function": "툿 삭제", - "button": "이 툿 삭제", - "alert": { - "title": "툿을 정말 삭제할까요?", - "message": "", - "buttons": { - "confirm": "삭제 확인", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "deleteEdit": { - "function": "툿 삭제", - "button": "삭제하고 다시 쓰기", - "alert": { - "title": "툿을 정말 삭제할까요?", - "message": "이 툿을 삭제하고 다시 초안을 작성하시겠어요? 모든 답장, 부스트와 즐겨찾기가 지워져요.", - "buttons": { - "confirm": "삭제 확인", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "mute": { - "function": "툿 음소거", - "button": { - "positive": "이 툿과 답장 음소거", - "negative": "이 툿과 답장 음소거 해제" - } - }, - "pin": { - "function": "고정", - "button": { - "positive": "이 툿 고정", - "negative": "이 툿 고정 해제" - } - } - } } }, "poll": { diff --git a/src/i18n/ko/screens/actions.json b/src/i18n/ko/screens/actions.json index dd011ed4..95a61e70 100644 --- a/src/i18n/ko/screens/actions.json +++ b/src/i18n/ko/screens/actions.json @@ -1,8 +1,7 @@ { "content": { - "button": { - "apply": "$t(common:buttons.apply)", - "cancel": "$t(common:buttons.cancel)" + "altText": { + "heading": "" }, "notificationsFilter": { "heading": "알림 종류 표시", diff --git a/src/i18n/pt_BR/components/contextMenu.json b/src/i18n/pt_BR/components/contextMenu.json new file mode 100644 index 00000000..67bf128b --- /dev/null +++ b/src/i18n/pt_BR/components/contextMenu.json @@ -0,0 +1,70 @@ +{ + "accessibilityHint": "Ações para este toot, como o seu usuário publicado", + "account": { + "title": "", + "mute": { + "action": "Silenciar usuário" + }, + "block": { + "action": "Bloquear usuário" + }, + "reports": { + "action": "Denunciar usuário" + } + }, + "instance": { + "title": "", + "block": { + "action": "Bloquear a instância {{instance}}", + "alert": { + "title": "", + "message": "Na maioria das vezes, você pode silenciar ou bloquear determinado usuário.\n\nDepois de bloquear a instância, todo seu conteúdo, incluindo seguidores, será removido!", + "buttons": { + "confirm": "Confirmar" + } + } + } + }, + "share": { + "status": { + "action": "Compartilhar toot" + }, + "account": { + "action": "Compartilhar Usuário" + } + }, + "status": { + "title": "", + "edit": { + "action": "Editar toot" + }, + "delete": { + "action": "Remover toot", + "alert": { + "title": "Confirme a exclusão?", + "message": "", + "buttons": { + "confirm": "Confirmar" + } + } + }, + "deleteEdit": { + "action": "", + "alert": { + "title": "", + "message": "", + "buttons": { + "confirm": "Confirmar" + } + } + }, + "mute": { + "action-muted_false": "", + "action-muted_true": "" + }, + "pin": { + "action-pinned_false": "", + "action-pinned_true": "" + } + } +} \ No newline at end of file diff --git a/src/i18n/pt_BR/components/mediaSelector.json b/src/i18n/pt_BR/components/mediaSelector.json index bbb7c59a..07a73554 100644 --- a/src/i18n/pt_BR/components/mediaSelector.json +++ b/src/i18n/pt_BR/components/mediaSelector.json @@ -1,27 +1,17 @@ { "title": "Selecionar fonte de mídia", "options": { - "library": "Carregar da biblioteca", - "photo": "Tirar foto", - "cancel": "$t(common:buttons.cancel)" + "image": "", + "image_max": "", + "video": "", + "video_max": "" }, "library": { "alert": { "title": "Sem permissão", "message": "Exigir permissão de leitura da biblioteca de fotos para fazer upload", "buttons": { - "settings": "Atualizar configurações", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "photo": { - "alert": { - "title": "Sem permissão", - "message": "Requer permissão de uso da câmera para fazer upload", - "buttons": { - "settings": "Atualizar configurações", - "cancel": "$t(common:buttons.cancel)" + "settings": "Atualizar configurações" } } } diff --git a/src/i18n/pt_BR/components/timeline.json b/src/i18n/pt_BR/components/timeline.json index 36d0f77a..31e94ca7 100644 --- a/src/i18n/pt_BR/components/timeline.json +++ b/src/i18n/pt_BR/components/timeline.json @@ -46,7 +46,7 @@ }, "bookmarked": { "accessibilityLabel": "Adicionar este toot aos favoritos", - "function": "Favoritos" + "function": "Salvos" } }, "actionsUsers": { @@ -123,94 +123,6 @@ "delete": { "function": "Excluir mensagem direta" } - }, - "actions": { - "accessibilityHint": "Ações para este toot, como o seu usuário publicado", - "account": { - "heading": "Sobre o usuário", - "mute": { - "function": "Silenciar usuário", - "button": "Silenciar @{{acct}}" - }, - "block": { - "function": "Bloquear usuário", - "button": "Bloquear @{{acct}}" - }, - "reports": { - "function": "Denunciar usuário", - "button": "Reportar @{{acct}}" - } - }, - "domain": { - "heading": "Sobre a instância", - "block": { - "function": "Bloquear instância", - "button": "Bloquear a instância {{domain}}" - }, - "alert": { - "title": "Confirma bloquear {{domain}}?", - "message": "Na maioria das vezes, você pode silenciar ou bloquear determinado usuário.\n\nDepois de bloquear a instância, todo seu conteúdo, incluindo seguidores, será removido!", - "buttons": { - "confirm": "Confirmar bloqueio", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "share": { - "status": { - "heading": "Compartilhar toot", - "button": "Compartilhar o link para este mundo" - }, - "account": { - "heading": "Compartilhar Usuário", - "button": "Compartilhar link para este usuário" - } - }, - "status": { - "heading": "Sobre o toot", - "edit": { - "function": "Editar toot", - "button": "Editar este toot" - }, - "delete": { - "function": "Remover toot", - "button": "Deletar este toot", - "alert": { - "title": "Confirmar exclusão?", - "message": "Tem certeza que deseja excluir este toot? Todos os boosts e favoritos serão apagados, incluindo todas as respostas.", - "buttons": { - "confirm": "Confirme a exclusão", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "deleteEdit": { - "function": "Remover toot", - "button": "Excluir e rascunhar", - "alert": { - "title": "Confirmar exclusão?", - "message": "Tem certeza que deseja excluir este toot? Todos os boosts e favoritos serão apagados, incluindo todas as respostas.", - "buttons": { - "confirm": "Confirme a exclusão", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "mute": { - "function": "Silenciar toot", - "button": { - "positive": "Silenciar este toot e respostas", - "negative": "Desbloquear este toot e respostas" - } - }, - "pin": { - "function": "Fixar", - "button": { - "positive": "Fixar este toot", - "negative": "Desafixar este toot" - } - } - } } }, "poll": { diff --git a/src/i18n/pt_BR/screens/actions.json b/src/i18n/pt_BR/screens/actions.json index 2d486974..fa615e27 100644 --- a/src/i18n/pt_BR/screens/actions.json +++ b/src/i18n/pt_BR/screens/actions.json @@ -1,8 +1,7 @@ { "content": { - "button": { - "apply": "$t(common:buttons.apply)", - "cancel": "$t(common:buttons.cancel)" + "altText": { + "heading": "Texto Alternativo" }, "notificationsFilter": { "heading": "Exibir notificações", @@ -13,8 +12,8 @@ "reblog": "$t(screenTabs:me.push.reblog.heading)", "mention": "$t(screenTabs:me.push.mention.heading)", "poll": "$t(screenTabs:me.push.poll.heading)", - "status": "", - "update": "" + "status": "Toot de usuários inscritos", + "update": "Toot foi editado" } } } diff --git a/src/i18n/pt_BR/screens/compose.json b/src/i18n/pt_BR/screens/compose.json index f226aa0f..13e665fa 100644 --- a/src/i18n/pt_BR/screens/compose.json +++ b/src/i18n/pt_BR/screens/compose.json @@ -168,7 +168,7 @@ "header": { "title": "Rascunho" }, - "warning": "", + "warning": "Os rascunhos são armazenados localmente e podem ser perdidos em eventos infortúnios. Aconselhamos não usar rascunhos para armazenamento de longo prazo.", "content": { "accessibilityHint": "Toque para editar este rascunho", "textEmpty": "O conteúdo está vazio" diff --git a/src/i18n/pt_BR/screens/tabs.json b/src/i18n/pt_BR/screens/tabs.json index 0d52e55b..7788ce8e 100644 --- a/src/i18n/pt_BR/screens/tabs.json +++ b/src/i18n/pt_BR/screens/tabs.json @@ -170,7 +170,7 @@ "heading": "Novo seguidor" }, "follow_request": { - "heading": "" + "heading": "Solicitações de seguidores pendentes" }, "favourite": { "heading": "Favoritos" @@ -185,7 +185,7 @@ "heading": "Pesquisa atualizada" }, "status": { - "heading": "" + "heading": "Toot de usuários inscritos" }, "howitworks": "Saiba como funciona o roteamento" }, diff --git a/src/i18n/vi/components/contextMenu.json b/src/i18n/vi/components/contextMenu.json new file mode 100644 index 00000000..37be0217 --- /dev/null +++ b/src/i18n/vi/components/contextMenu.json @@ -0,0 +1,70 @@ +{ + "accessibilityHint": "Hành động với tút này, bao gồm đăng thủ công hay đăng tự động", + "account": { + "title": "Hành động người dùng", + "mute": { + "action": "Ẩn người này" + }, + "block": { + "action": "Chặn người này" + }, + "reports": { + "action": "Báo cáo" + } + }, + "instance": { + "title": "Hành động máy chủ", + "block": { + "action": "Chặn {{instance}}", + "alert": { + "title": "Xác nhận chặn {{instance}} ?", + "message": "Bạn có thể ẩn hoặc chặn bất kỳ người nào.\n\nĐối với máy chủ, toàn bộ nội dung bao gồm người theo dõi bạn từ máy chủ đó cũng sẽ bị chặn!", + "buttons": { + "confirm": "Xác nhận" + } + } + } + }, + "share": { + "status": { + "action": "Đăng lại" + }, + "account": { + "action": "Chia sẻ" + } + }, + "status": { + "title": "Hành động tút", + "edit": { + "action": "Sửa tút" + }, + "delete": { + "action": "Xóa tút", + "alert": { + "title": "Tiếp tục xóa?", + "message": "Tất cả lượt thích và đăng lại sẽ bị mất, bao gồm cả những trả lời.", + "buttons": { + "confirm": "Xác nhận" + } + } + }, + "deleteEdit": { + "action": "Xóa và đăng lại", + "alert": { + "title": "Tiếp tục xóa và đăng lại?", + "message": "Tất cả lượt thích và đăng lại sẽ bị mất, bao gồm cả những trả lời.", + "buttons": { + "confirm": "Xác nhận" + } + } + }, + "mute": { + "action-muted_false": "Ẩn tút này", + "action-muted_true": "Bỏ ẩn tút này" + }, + "pin": { + "action-pinned_false": "Tút ghim", + "action-pinned_true": "Bỏ ghim tút" + } + } +} \ No newline at end of file diff --git a/src/i18n/vi/components/mediaSelector.json b/src/i18n/vi/components/mediaSelector.json index 022097e8..e06ffcbc 100644 --- a/src/i18n/vi/components/mediaSelector.json +++ b/src/i18n/vi/components/mediaSelector.json @@ -1,27 +1,17 @@ { "title": "Chọn nguồn", "options": { - "library": "Từ thiết bị", - "photo": "Chụp ảnh", - "cancel": "$t(common:buttons.cancel)" + "image": "Tải ảnh lên", + "image_max": "Tải ảnh lên (tối đa {{max}})", + "video": "Tải video lên", + "video_max": "Tải video lên (tối đa {{max}})" }, "library": { "alert": { "title": "Chưa được cấp quyền", "message": "Bạn cần cấp quyền đọc thư viện ảnh trước", "buttons": { - "settings": "Cài đặt cập nhật", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "photo": { - "alert": { - "title": "Chưa cấp quyền", - "message": "Cần cấp quyền sử dụng camera trước", - "buttons": { - "settings": "Cài đặt cập nhật", - "cancel": "$t(common:buttons.cancel)" + "settings": "Cài đặt cập nhật" } } } diff --git a/src/i18n/vi/components/timeline.json b/src/i18n/vi/components/timeline.json index 92224828..73db2dbe 100644 --- a/src/i18n/vi/components/timeline.json +++ b/src/i18n/vi/components/timeline.json @@ -123,94 +123,6 @@ "delete": { "function": "Xóa nhắn riêng" } - }, - "actions": { - "accessibilityHint": "Hành động cho tút này, bao gồm đăng thủ công hay đăng tự động", - "account": { - "heading": "Đối với người dùng", - "mute": { - "function": "Ẩn người dùng", - "button": "Ẩn @{{acct}}" - }, - "block": { - "function": "Chặn người dùng", - "button": "Chặn @{{acct}}" - }, - "reports": { - "function": "Báo cáo người dùng", - "button": "Báo cáo @{{acct}}" - } - }, - "domain": { - "heading": "Đối với máy chủ", - "block": { - "function": "Chặn máy chủ", - "button": "Chặn {{domain}}" - }, - "alert": { - "title": "Bạn có chắc muốn chặn {{domain}}?", - "message": "Bạn có thể ẩn hoặc chặn bất kỳ người nào.\n\nĐối với máy chủ, toàn bộ nội dung bao gồm người theo dõi bạn từ máy chủ đó cũng sẽ bị chặn!", - "buttons": { - "confirm": "Tiếp tục chặn", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "share": { - "status": { - "heading": "Đăng lại", - "button": "Đăng lại URL tút" - }, - "account": { - "heading": "Chia sẻ", - "button": "Chia sẻ URL người dùng này" - } - }, - "status": { - "heading": "Đối với tút", - "edit": { - "function": "Sửa tút", - "button": "Sửa tút này" - }, - "delete": { - "function": "Xóa tút", - "button": "Xóa tút này", - "alert": { - "title": "Vẫn xóa tút?", - "message": "Bạn có chắc muốn xóa tút này? Toàn bộ lượt thích, đăng lại và trả lời tút cũng sẽ bị xóa theo.", - "buttons": { - "confirm": "Xác nhận xóa", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "deleteEdit": { - "function": "Xóa tút", - "button": "Xóa & viết lại", - "alert": { - "title": "Xác nhận xóa tút?", - "message": "Bạn có chắc muốn xóa và viết lại tút này? Toàn bộ lượt thích, đăng lại và trả lời tút cũng sẽ bị xóa theo.", - "buttons": { - "confirm": "Xác nhận xóa", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "mute": { - "function": "Ẩn tút", - "button": { - "positive": "Ẩn tút này", - "negative": "Bỏ ẩn tút này" - } - }, - "pin": { - "function": "Ghim", - "button": { - "positive": "Ghim tút này", - "negative": "Bỏ ghim tút này" - } - } - } } }, "poll": { diff --git a/src/i18n/vi/screens/actions.json b/src/i18n/vi/screens/actions.json index 06cd1e50..516c6077 100644 --- a/src/i18n/vi/screens/actions.json +++ b/src/i18n/vi/screens/actions.json @@ -1,8 +1,7 @@ { "content": { - "button": { - "apply": "$t(common:buttons.apply)", - "cancel": "$t(common:buttons.cancel)" + "altText": { + "heading": "Văn bản thay thế" }, "notificationsFilter": { "heading": "Những kiểu thông báo cho phép", diff --git a/src/i18n/zh-Hans/components/contextMenu.json b/src/i18n/zh-Hans/components/contextMenu.json new file mode 100644 index 00000000..a167fe6f --- /dev/null +++ b/src/i18n/zh-Hans/components/contextMenu.json @@ -0,0 +1,70 @@ +{ + "accessibilityHint": "更多关于此条嘟文,例如发布者等", + "account": { + "title": "用户操作", + "mute": { + "action": "静音用户" + }, + "block": { + "action": "屏蔽用户" + }, + "reports": { + "action": "举报用户" + } + }, + "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-muted_false": "静音嘟文及回复", + "action-muted_true": "取消静音嘟文及回复" + }, + "pin": { + "action-pinned_false": "置顶嘟文", + "action-pinned_true": "取消置顶嘟文" + } + } +} \ No newline at end of file diff --git a/src/i18n/zh-Hans/components/mediaSelector.json b/src/i18n/zh-Hans/components/mediaSelector.json index 1b4cc25e..039007b7 100644 --- a/src/i18n/zh-Hans/components/mediaSelector.json +++ b/src/i18n/zh-Hans/components/mediaSelector.json @@ -1,27 +1,17 @@ { "title": "选择媒体", "options": { - "library": "从相册上传", - "photo": "拍摄照片", - "cancel": "$t(common:buttons.cancel)" + "image": "上传图片", + "image_max": "上传照片(上限 {{max}})", + "video": "上传视频", + "video_max": "上传视频(上限 {{max}})" }, "library": { "alert": { "title": "无权限", "message": "需要读取相册权限才能上传附件", "buttons": { - "settings": "去更新设置", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "photo": { - "alert": { - "title": "无权限", - "message": "需要使用相机权限才能上传附件", - "buttons": { - "settings": "去更新设置", - "cancel": "$t(common:buttons.cancel)" + "settings": "去更新设置" } } } diff --git a/src/i18n/zh-Hans/components/timeline.json b/src/i18n/zh-Hans/components/timeline.json index 6347abaa..3fcbbf1d 100644 --- a/src/i18n/zh-Hans/components/timeline.json +++ b/src/i18n/zh-Hans/components/timeline.json @@ -123,94 +123,6 @@ "delete": { "function": "删除私信" } - }, - "actions": { - "accessibilityHint": "更多关于此条嘟文,例如发布者等", - "account": { - "heading": "关于用户", - "mute": { - "function": "隐藏 @{{acct}} 的嘟文", - "button": "隐藏 @{{acct}} 的嘟文" - }, - "block": { - "function": "屏蔽 @{{acct}}", - "button": "屏蔽 @{{acct}}" - }, - "reports": { - "function": "举报 @{{acct}}", - "button": "举报 @{{acct}}" - } - }, - "domain": { - "heading": "关于社区", - "block": { - "function": "屏蔽社区", - "button": "屏蔽社区 {{domain}}" - }, - "alert": { - "title": "确定要屏蔽 {{domain}} 吗?", - "message": "多数情况下,隐藏或屏蔽特定用户即可。\n\n屏蔽之后,来自此社区的所有内容将不再出现在你的时间轴里。同时,来自该社区的关注者将被移除。请谨慎使用。", - "buttons": { - "confirm": "确定屏蔽整个社区", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "share": { - "status": { - "heading": "分享嘟文", - "button": "分享此条嘟文的链接" - }, - "account": { - "heading": "分享用户", - "button": "分享此用户的链接" - } - }, - "status": { - "heading": "关于嘟文", - "edit": { - "function": "编辑嘟文", - "button": "编辑此条嘟文" - }, - "delete": { - "function": "删除", - "button": "删除此条嘟文", - "alert": { - "title": "确认删除嘟文?", - "message": "确定要删除这条嘟文吗?所有相关的转嘟和喜欢都会被清除,回复将会失去关联。", - "buttons": { - "confirm": "确认删除", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "deleteEdit": { - "function": "删除并重新编辑", - "button": "删除并重新编辑此条嘟文", - "alert": { - "title": "确认删除嘟文?", - "message": "确定要删除这条嘟文并重新编辑它吗?所有相关的转嘟和喜欢都会被清除,回复将会失去关联。", - "buttons": { - "confirm": "删除并重新编辑", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "mute": { - "function": "静音", - "button": { - "positive": "静音此条嘟文及对话", - "negative": "取消静音此条嘟文及对话" - } - }, - "pin": { - "function": "置顶", - "button": { - "positive": "置顶此条嘟文", - "negative": "取消置顶此条嘟文" - } - } - } } }, "poll": { diff --git a/src/i18n/zh-Hans/screens/actions.json b/src/i18n/zh-Hans/screens/actions.json index b7ed467e..56c57a99 100644 --- a/src/i18n/zh-Hans/screens/actions.json +++ b/src/i18n/zh-Hans/screens/actions.json @@ -1,8 +1,7 @@ { "content": { - "button": { - "apply": "$t(common:buttons.apply)", - "cancel": "$t(common:buttons.cancel)" + "altText": { + "heading": "替代文本" }, "notificationsFilter": { "heading": "显示通知", diff --git a/src/i18n/zh-Hant/components/contextMenu.json b/src/i18n/zh-Hant/components/contextMenu.json new file mode 100644 index 00000000..2715b111 --- /dev/null +++ b/src/i18n/zh-Hant/components/contextMenu.json @@ -0,0 +1,70 @@ +{ + "accessibilityHint": "", + "account": { + "title": "", + "mute": { + "action": "" + }, + "block": { + "action": "" + }, + "reports": { + "action": "" + } + }, + "instance": { + "title": "", + "block": { + "action": "", + "alert": { + "title": "", + "message": "", + "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-muted_false": "", + "action-muted_true": "" + }, + "pin": { + "action-pinned_false": "", + "action-pinned_true": "" + } + } +} \ No newline at end of file diff --git a/src/i18n/zh-Hant/components/mediaSelector.json b/src/i18n/zh-Hant/components/mediaSelector.json index a2738c7b..1f0d0b96 100644 --- a/src/i18n/zh-Hant/components/mediaSelector.json +++ b/src/i18n/zh-Hant/components/mediaSelector.json @@ -1,27 +1,17 @@ { "title": "選擇媒體來源", "options": { - "library": "上傳", - "photo": "拍照", - "cancel": "$t(common:buttons.cancel)" + "image": "", + "image_max": "", + "video": "", + "video_max": "" }, "library": { "alert": { "title": "權限不足", "message": "上傳照片需要讀取的權限", "buttons": { - "settings": "更新設定", - "cancel": "$t(common:buttons.cancel)" - } - } - }, - "photo": { - "alert": { - "title": "權限不足", - "message": "需要使用相機的權限來上傳", - "buttons": { - "settings": "更新設定", - "cancel": "$t(common:buttons.cancel)" + "settings": "更新設定" } } } diff --git a/src/i18n/zh-Hant/components/timeline.json b/src/i18n/zh-Hant/components/timeline.json index 620ecc99..5623526d 100644 --- a/src/i18n/zh-Hant/components/timeline.json +++ b/src/i18n/zh-Hant/components/timeline.json @@ -123,94 +123,6 @@ "delete": { "function": "" } - }, - "actions": { - "accessibilityHint": "", - "account": { - "heading": "", - "mute": { - "function": "", - "button": "" - }, - "block": { - "function": "", - "button": "" - }, - "reports": { - "function": "", - "button": "" - } - }, - "domain": { - "heading": "", - "block": { - "function": "", - "button": "" - }, - "alert": { - "title": "", - "message": "", - "buttons": { - "confirm": "", - "cancel": "" - } - } - }, - "share": { - "status": { - "heading": "", - "button": "" - }, - "account": { - "heading": "", - "button": "" - } - }, - "status": { - "heading": "", - "edit": { - "function": "", - "button": "" - }, - "delete": { - "function": "", - "button": "", - "alert": { - "title": "", - "message": "", - "buttons": { - "confirm": "", - "cancel": "" - } - } - }, - "deleteEdit": { - "function": "", - "button": "", - "alert": { - "title": "", - "message": "", - "buttons": { - "confirm": "", - "cancel": "" - } - } - }, - "mute": { - "function": "", - "button": { - "positive": "", - "negative": "" - } - }, - "pin": { - "function": "", - "button": { - "positive": "", - "negative": "" - } - } - } } }, "poll": { diff --git a/src/i18n/zh-Hant/screens/actions.json b/src/i18n/zh-Hant/screens/actions.json index 648864d7..55e9959c 100644 --- a/src/i18n/zh-Hant/screens/actions.json +++ b/src/i18n/zh-Hant/screens/actions.json @@ -1,8 +1,7 @@ { "content": { - "button": { - "apply": "", - "cancel": "" + "altText": { + "heading": "" }, "notificationsFilter": { "heading": "", diff --git a/src/screens/Actions.tsx b/src/screens/Actions.tsx index a633cda1..c6db5ffa 100644 --- a/src/screens/Actions.tsx +++ b/src/screens/Actions.tsx @@ -1,14 +1,7 @@ -import analytics from '@components/analytics' -import Button from '@components/Button' import { RootStackScreenProps } from '@utils/navigation/navigators' -import { - getInstanceAccount, - getInstanceUrl -} from '@utils/slices/instancesSlice' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' import React, { useCallback, useEffect } from 'react' -import { useTranslation } from 'react-i18next' import { Dimensions, StyleSheet, View } from 'react-native' import { PanGestureHandler, @@ -28,47 +21,13 @@ import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context' -import { useSelector } from 'react-redux' -import ActionsAccount from './Actions/Account' import ActionsAltText from './Actions/AltText' -import ActionsDomain from './Actions/Domain' import ActionsNotificationsFilter from './Actions/NotificationsFilter' -import ActionsShare from './Actions/Share' -import ActionsStatus from './Actions/Status' const ScreenActions = ({ route: { params }, navigation }: RootStackScreenProps<'Screen-Actions'>) => { - const { t } = useTranslation() - - const instanceAccount = useSelector( - getInstanceAccount, - (prev, next) => prev?.id === next?.id - ) - let sameAccount = false - switch (params.type) { - case 'status': - console.log('media length', params.status.media_attachments.length) - sameAccount = instanceAccount?.id === params.status.account.id - break - case 'account': - sameAccount = instanceAccount?.id === params.account.id - break - } - - const instanceDomain = useSelector(getInstanceUrl) - let sameDomain = true - let statusDomain: string - switch (params.type) { - case 'status': - statusDomain = params.status.uri - ? params.status.uri.split(new RegExp(/\/\/(.*?)\//))[1] - : '' - sameDomain = instanceDomain === statusDomain - break - } - const { colors } = useTheme() const insets = useSafeAreaInsets() @@ -106,72 +65,6 @@ const ScreenActions = ({ const actions = () => { switch (params.type) { - case 'status': - return ( - <> - {!sameAccount ? ( - - ) : null} - {sameAccount && params.status ? ( - - ) : null} - {!sameDomain && statusDomain ? ( - - ) : null} - {params.status.visibility !== 'direct' ? ( - - ) : null} -