mirror of https://github.com/tooot-app/app
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)
This commit is contained in:
parent
6a1f8b3c73
commit
55053e73f8
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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` |
|
Binary file not shown.
|
@ -1,4 +1,3 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<resources>
|
||||
<string name="app_name">tooot</string>
|
||||
<string name="expo_splash_screen_resize_mode">contain</string>
|
||||
|
|
|
@ -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']
|
||||
}
|
||||
]
|
||||
]
|
||||
})
|
||||
|
|
Binary file not shown.
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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 = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = "<group>"; };
|
||||
DF8133F098604A10B0D94952 /* boop.mp3 */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = boop.mp3; path = tooot/boop.mp3; sourceTree = "<group>"; };
|
||||
E613A80A28282A01003C97D6 /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = tooot/AppDelegate.mm; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
|
@ -115,6 +117,7 @@
|
|||
5E36538225C9B8BD009F93EE /* RootViewColor.xcassets */,
|
||||
B96B72E5384D44A7B240B27E /* GoogleService-Info.plist */,
|
||||
5EE088CB26297820007E5FEC /* InfoPlist.strings */,
|
||||
DF8133F098604A10B0D94952 /* boop.mp3 */,
|
||||
);
|
||||
name = tooot;
|
||||
sourceTree = "<group>";
|
||||
|
@ -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;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<dict>
|
||||
<key>CFBundleAllowMixedLocalizations</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
|
@ -55,8 +55,6 @@
|
|||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Allow $(PRODUCT_NAME) to capture photo or video and attach it to your toot</string>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string></string>
|
||||
<key>NSMainNibFile</key>
|
||||
|
@ -88,5 +86,5 @@
|
|||
<string>Automatic</string>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<dict>
|
||||
<key>EXUpdatesCheckOnLaunch</key>
|
||||
<string>WIFI_ONLY</string>
|
||||
<key>EXUpdatesEnabled</key>
|
||||
|
@ -14,5 +14,5 @@
|
|||
<string>0</string>
|
||||
<key>EXUpdatesURL</key>
|
||||
<string>https://exp.host/@xmflsct/tooot</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
Binary file not shown.
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<dict>
|
||||
<key>aps-environment</key>
|
||||
<string>development</string>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
|
@ -20,5 +20,5 @@
|
|||
<true/>
|
||||
<key>com.apple.security.personal-information.photos-library</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
|
@ -6,6 +6,5 @@
|
|||
|
||||
*/
|
||||
|
||||
"NSCameraUsageDescription" = "允许tooot拍摄图片或视频,以添加嘟文附件";
|
||||
"NSPhotoLibraryAddUsageDescription" = "允许tooot保存图片至相册";
|
||||
"NSPhotoLibraryUsageDescription" = "允许tooot读取相册图片或视频,以添加嘟文附件";
|
||||
|
|
43
package.json
43
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",
|
||||
|
|
|
@ -13,11 +13,4 @@ declare namespace App {
|
|||
| 'Conversations'
|
||||
| 'Bookmarks'
|
||||
| 'Favourites'
|
||||
|
||||
interface IImageInfo {
|
||||
uri: string
|
||||
width: number
|
||||
height: number
|
||||
type?: 'image' | 'video'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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'
|
||||
|
|
152
src/Screens.tsx
152
src/Screens.tsx
|
@ -178,8 +178,49 @@ const Screens: React.FC<Props> = ({ 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<Props> = ({ 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
|
||||
for (const d of item.data) {
|
||||
if (typeof d !== 'string') {
|
||||
filterMedia({ path: d.data, mime: d.mimeType })
|
||||
}
|
||||
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}`)
|
||||
}
|
||||
})
|
||||
break
|
||||
case 'android':
|
||||
if (!item.mimeType) {
|
||||
|
@ -247,65 +244,16 @@ const Screens: React.FC<Props> = ({ 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
|
||||
for (const d of item.data) {
|
||||
filterMedia({ path: d, mime: item.mimeType })
|
||||
}
|
||||
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}`)
|
||||
}
|
||||
})
|
||||
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]
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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<RootStackParamList, 'Screen-Tabs'>
|
||||
>()
|
||||
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<Mastodon.Status>({
|
||||
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<Mastodon.Status>({
|
||||
method: 'get',
|
||||
url: `statuses/${status.in_reply_to_id}`
|
||||
}).then(res => res.body)
|
||||
}
|
||||
apiInstance<{
|
||||
id: Mastodon.Status['id']
|
||||
text: NonNullable<Mastodon.Status['text']>
|
||||
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
|
|
@ -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,6 +74,11 @@ const TimelineDefault: React.FC<Props> = ({
|
|||
}, [])
|
||||
|
||||
return (
|
||||
<TimelineContextMenu
|
||||
status={actualStatus}
|
||||
queryKey={queryKey}
|
||||
rootQueryKey={rootQueryKey}
|
||||
>
|
||||
<Pressable
|
||||
accessible={highlighted ? false : true}
|
||||
style={{
|
||||
|
@ -84,6 +90,7 @@ const TimelineDefault: React.FC<Props> = ({
|
|||
: 0
|
||||
}}
|
||||
onPress={onPress}
|
||||
onLongPress={() => {}}
|
||||
>
|
||||
{item.reblog ? (
|
||||
<TimelineActioned action='reblog' account={item.account} />
|
||||
|
@ -99,7 +106,6 @@ const TimelineDefault: React.FC<Props> = ({
|
|||
/>
|
||||
<TimelineHeaderDefault
|
||||
queryKey={disableOnPress ? undefined : queryKey}
|
||||
rootQueryKey={disableOnPress ? undefined : rootQueryKey}
|
||||
status={actualStatus}
|
||||
highlighted={highlighted}
|
||||
/>
|
||||
|
@ -140,7 +146,10 @@ const TimelineDefault: React.FC<Props> = ({
|
|||
<TimelineCard card={actualStatus.card} />
|
||||
) : null}
|
||||
{!disableDetails ? (
|
||||
<TimelineFullConversation queryKey={queryKey} status={actualStatus} />
|
||||
<TimelineFullConversation
|
||||
queryKey={queryKey}
|
||||
status={actualStatus}
|
||||
/>
|
||||
) : null}
|
||||
<TimelineTranslate status={actualStatus} highlighted={highlighted} />
|
||||
<TimelineFeedback status={actualStatus} highlighted={highlighted} />
|
||||
|
@ -154,7 +163,10 @@ const TimelineDefault: React.FC<Props> = ({
|
|||
status={actualStatus}
|
||||
ownAccount={ownAccount}
|
||||
accts={uniqBy(
|
||||
([actualStatus.account] as Mastodon.Account[] & Mastodon.Mention[])
|
||||
(
|
||||
[actualStatus.account] as Mastodon.Account[] &
|
||||
Mastodon.Mention[]
|
||||
)
|
||||
.concat(actualStatus.mentions)
|
||||
.filter(d => d?.id !== instanceAccount?.id),
|
||||
d => d?.id
|
||||
|
@ -163,6 +175,7 @@ const TimelineDefault: React.FC<Props> = ({
|
|||
/>
|
||||
) : null}
|
||||
</Pressable>
|
||||
</TimelineContextMenu>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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,6 +59,7 @@ const TimelineNotifications = React.memo(
|
|||
}, [])
|
||||
|
||||
return (
|
||||
<TimelineContextMenu status={notification.status} queryKey={queryKey}>
|
||||
<Pressable
|
||||
style={{
|
||||
padding: StyleConstants.Spacing.Global.PagePadding,
|
||||
|
@ -67,6 +69,7 @@ const TimelineNotifications = React.memo(
|
|||
: StyleConstants.Spacing.Global.PagePadding
|
||||
}}
|
||||
onPress={onPress}
|
||||
onLongPress={() => {}}
|
||||
>
|
||||
{notification.type !== 'mention' ? (
|
||||
<TimelineActioned
|
||||
|
@ -93,10 +96,7 @@ const TimelineNotifications = React.memo(
|
|||
account={actualAccount}
|
||||
highlighted={highlighted}
|
||||
/>
|
||||
<TimelineHeaderNotification
|
||||
queryKey={queryKey}
|
||||
notification={notification}
|
||||
/>
|
||||
<TimelineHeaderNotification notification={notification} />
|
||||
</View>
|
||||
|
||||
{notification.status ? (
|
||||
|
@ -120,7 +120,9 @@ const TimelineNotifications = React.memo(
|
|||
statusId={notification.status.id}
|
||||
poll={notification.status.poll}
|
||||
reblog={false}
|
||||
sameAccount={notification.account.id === instanceAccount?.id}
|
||||
sameAccount={
|
||||
notification.account.id === instanceAccount?.id
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
{notification.status.media_attachments.length > 0 ? (
|
||||
|
@ -155,6 +157,7 @@ const TimelineNotifications = React.memo(
|
|||
/>
|
||||
) : null}
|
||||
</Pressable>
|
||||
</TimelineContextMenu>
|
||||
)
|
||||
},
|
||||
(prev, next) => isEqual(prev.notification, next.notification)
|
||||
|
|
|
@ -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<ContextMenuAction[]>([])
|
||||
|
||||
const TimelineContextMenu: React.FC<Props & ContextMenuProps> = ({
|
||||
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 (
|
||||
<ContextMenuContext.Provider value={actions}>
|
||||
<ContextMenu
|
||||
actions={actions}
|
||||
onPress={({ nativeEvent: { id } }) => {
|
||||
for (const on of [
|
||||
shareOnPress,
|
||||
statusOnPress,
|
||||
accountOnPress,
|
||||
instanceOnPress
|
||||
]) {
|
||||
on && on(id)
|
||||
}
|
||||
}}
|
||||
children={children}
|
||||
{...props}
|
||||
/>
|
||||
</ContextMenuContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export default TimelineContextMenu
|
|
@ -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<StackNavigationProp<RootStackParamList>>()
|
||||
const TimelineHeaderDefault = ({ queryKey, status, highlighted }: Props) => {
|
||||
const { t } = useTranslation('componentContextMenu')
|
||||
const { colors } = useTheme()
|
||||
|
||||
const contextMenuContext = useContext(ContextMenuContext)
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1, flexDirection: 'row' }}>
|
||||
<View style={{ flex: 5 }}>
|
||||
<View style={{ flex: 7 }}>
|
||||
<HeaderSharedAccount account={status.account} />
|
||||
<View
|
||||
style={{
|
||||
|
@ -56,21 +50,18 @@ const TimelineHeaderDefault = ({
|
|||
|
||||
{queryKey ? (
|
||||
<Pressable
|
||||
accessibilityHint={t('shared.header.actions.accessibilityHint')}
|
||||
accessibilityHint={t('accessibilityHint')}
|
||||
style={{
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
paddingBottom: StyleConstants.Spacing.S
|
||||
marginBottom: StyleConstants.Spacing.L
|
||||
}}
|
||||
onPress={() =>
|
||||
navigation.navigate('Screen-Actions', {
|
||||
queryKey,
|
||||
rootQueryKey,
|
||||
status,
|
||||
type: 'status'
|
||||
})
|
||||
}
|
||||
>
|
||||
<ContextMenu
|
||||
dropdownMenuMode
|
||||
actions={contextMenuContext}
|
||||
onPress={() => {}}
|
||||
children={
|
||||
<Icon
|
||||
name='MoreHorizontal'
|
||||
|
@ -79,6 +70,7 @@ const TimelineHeaderDefault = ({
|
|||
/>
|
||||
}
|
||||
/>
|
||||
</Pressable>
|
||||
) : null}
|
||||
</View>
|
||||
)
|
||||
|
|
|
@ -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<StackNavigationProp<RootStackParamList>>()
|
||||
const TimelineHeaderNotification = ({ notification }: Props) => {
|
||||
const { colors } = useTheme()
|
||||
|
||||
const contextMenuContext = useContext(ContextMenuContext)
|
||||
|
||||
const actions = useMemo(() => {
|
||||
switch (notification.type) {
|
||||
case 'follow':
|
||||
|
@ -42,13 +40,11 @@ const TimelineHeaderNotification = ({ queryKey, notification }: Props) => {
|
|||
justifyContent: 'center',
|
||||
paddingBottom: StyleConstants.Spacing.S
|
||||
}}
|
||||
onPress={() =>
|
||||
navigation.navigate('Screen-Actions', {
|
||||
queryKey,
|
||||
status: notification.status!,
|
||||
type: 'status'
|
||||
})
|
||||
}
|
||||
children={
|
||||
<ContextMenu
|
||||
dropdownMenuMode
|
||||
actions={contextMenuContext}
|
||||
onPress={() => {}}
|
||||
children={
|
||||
<Icon
|
||||
name='MoreHorizontal'
|
||||
|
@ -57,6 +53,8 @@ const TimelineHeaderNotification = ({ queryKey, notification }: Props) => {
|
|||
/>
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<void>
|
||||
|
@ -19,58 +22,22 @@ export interface Props {
|
|||
}
|
||||
|
||||
const mediaSelector = async ({
|
||||
mediaTypes = ImagePicker.MediaTypeOptions.All,
|
||||
mediaType,
|
||||
resize,
|
||||
maximum,
|
||||
indicateMaximum = false,
|
||||
showActionSheetWithOptions
|
||||
}: Props): Promise<ImageInfo> => {
|
||||
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 } }
|
||||
])
|
||||
}
|
||||
} else {
|
||||
newResult = await ImageManipulator.manipulateAsync(result.uri, [
|
||||
{ resize }
|
||||
])
|
||||
}
|
||||
resolve({ ...newResult, cancelled: false })
|
||||
} else {
|
||||
resolve(result)
|
||||
}
|
||||
}
|
||||
|
||||
showActionSheetWithOptions(
|
||||
{
|
||||
title: i18next.t('componentMediaSelector:title'),
|
||||
options: [
|
||||
i18next.t('componentMediaSelector:options.library'),
|
||||
i18next.t('componentMediaSelector:options.photo'),
|
||||
i18next.t('componentMediaSelector:options.cancel')
|
||||
],
|
||||
cancelButtonIndex: 2
|
||||
},
|
||||
async buttonIndex => {
|
||||
if (buttonIndex === 0) {
|
||||
}: Props): Promise<ImageOrVideo[]> => {
|
||||
const checkLibraryPermission = async (): Promise<boolean> => {
|
||||
const { status } =
|
||||
await ImagePicker.requestMediaLibraryPermissionsAsync()
|
||||
await ExpoImagePicker.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'
|
||||
),
|
||||
text: i18next.t('common:buttons.cancel'),
|
||||
style: 'cancel',
|
||||
onPress: () =>
|
||||
analytics('mediaSelector_nopermission', {
|
||||
|
@ -91,62 +58,128 @@ const mediaSelector = async ({
|
|||
}
|
||||
]
|
||||
)
|
||||
return false
|
||||
} else {
|
||||
const result = await ImagePicker.launchImageLibraryAsync({
|
||||
mediaTypes,
|
||||
exif: false,
|
||||
presentationStyle:
|
||||
Platform.OS === 'ios' && parseInt(Platform.Version) < 13
|
||||
? UIImagePickerPresentationStyle.FULL_SCREEN
|
||||
: UIImagePickerPresentationStyle.AUTOMATIC
|
||||
})
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if (!result.cancelled) {
|
||||
await resolveResult(result)
|
||||
}
|
||||
}
|
||||
} 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'
|
||||
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
|
||||
),
|
||||
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:')
|
||||
}
|
||||
}
|
||||
i18next.t('common:buttons.cancel')
|
||||
]
|
||||
)
|
||||
} else {
|
||||
const result = await ImagePicker.launchCameraAsync({
|
||||
mediaTypes,
|
||||
exif: false
|
||||
})
|
||||
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')
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (!result.cancelled) {
|
||||
await resolveResult(result)
|
||||
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 {
|
||||
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: options(),
|
||||
cancelButtonIndex: mediaType ? 1 : 2
|
||||
},
|
||||
async buttonIndex => {
|
||||
if (!(await checkLibraryPermission())) {
|
||||
return reject()
|
||||
}
|
||||
|
||||
switch (mediaType) {
|
||||
case 'photo':
|
||||
if (buttonIndex === 0) {
|
||||
await selectImage()
|
||||
}
|
||||
break
|
||||
case 'video':
|
||||
if (buttonIndex === 0) {
|
||||
await selectVideo()
|
||||
}
|
||||
break
|
||||
default:
|
||||
if (buttonIndex === 0) {
|
||||
await selectImage()
|
||||
} else if (buttonIndex === 1) {
|
||||
await selectVideo()
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -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": ""
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
{
|
||||
"content": {
|
||||
"button": {
|
||||
"apply": "$t(common:buttons.apply)",
|
||||
"cancel": "$t(common:buttons.cancel)"
|
||||
"altText": {
|
||||
"heading": ""
|
||||
},
|
||||
"notificationsFilter": {
|
||||
"heading": "Benachrichtigungsart anzeigen",
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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": ""
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
{
|
||||
"content": {
|
||||
"button": {
|
||||
"apply": "$t(common:buttons.apply)",
|
||||
"cancel": "$t(common:buttons.cancel)"
|
||||
"altText": {
|
||||
"heading": ""
|
||||
},
|
||||
"notificationsFilter": {
|
||||
"heading": "Filtra notifiche per tipo",
|
||||
|
|
|
@ -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": ""
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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": "설정 업데이트"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
{
|
||||
"content": {
|
||||
"button": {
|
||||
"apply": "$t(common:buttons.apply)",
|
||||
"cancel": "$t(common:buttons.cancel)"
|
||||
"altText": {
|
||||
"heading": ""
|
||||
},
|
||||
"notificationsFilter": {
|
||||
"heading": "알림 종류 표시",
|
||||
|
|
|
@ -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": ""
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
},
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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": "取消置顶嘟文"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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": "去更新设置"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
{
|
||||
"content": {
|
||||
"button": {
|
||||
"apply": "$t(common:buttons.apply)",
|
||||
"cancel": "$t(common:buttons.cancel)"
|
||||
"altText": {
|
||||
"heading": "替代文本"
|
||||
},
|
||||
"notificationsFilter": {
|
||||
"heading": "显示通知",
|
||||
|
|
|
@ -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": ""
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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": "更新設定"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
{
|
||||
"content": {
|
||||
"button": {
|
||||
"apply": "",
|
||||
"cancel": ""
|
||||
"altText": {
|
||||
"heading": ""
|
||||
},
|
||||
"notificationsFilter": {
|
||||
"heading": "",
|
||||
|
|
|
@ -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 ? (
|
||||
<ActionsAccount
|
||||
queryKey={params.queryKey}
|
||||
rootQueryKey={params.rootQueryKey}
|
||||
account={params.status.account}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
) : null}
|
||||
{sameAccount && params.status ? (
|
||||
<ActionsStatus
|
||||
navigation={navigation}
|
||||
queryKey={params.queryKey}
|
||||
rootQueryKey={params.rootQueryKey}
|
||||
status={params.status}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
) : null}
|
||||
{!sameDomain && statusDomain ? (
|
||||
<ActionsDomain
|
||||
queryKey={params.queryKey}
|
||||
rootQueryKey={params.rootQueryKey}
|
||||
domain={statusDomain}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
) : null}
|
||||
{params.status.visibility !== 'direct' ? (
|
||||
<ActionsShare
|
||||
url={params.status.url || params.status.uri}
|
||||
type={params.type}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
) : null}
|
||||
<Button
|
||||
type='text'
|
||||
content={t('common:buttons.cancel')}
|
||||
onPress={() => {
|
||||
analytics('bottomsheet_acknowledge')
|
||||
}}
|
||||
style={styles.button}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
case 'account':
|
||||
return (
|
||||
<>
|
||||
{!sameAccount ? (
|
||||
<ActionsAccount account={params.account} dismiss={dismiss} />
|
||||
) : null}
|
||||
<ActionsShare
|
||||
url={params.account.url}
|
||||
type={params.type}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
<Button
|
||||
type='text'
|
||||
content={t('common:buttons.cancel')}
|
||||
onPress={() => {
|
||||
analytics('bottomsheet_acknowledge')
|
||||
}}
|
||||
style={styles.button}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
case 'notifications_filter':
|
||||
return <ActionsNotificationsFilter />
|
||||
case 'alt_text':
|
||||
|
|
|
@ -136,18 +136,6 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
|
|||
])
|
||||
|
||||
useEffect(() => {
|
||||
const uploadImage = async ({
|
||||
type,
|
||||
uri
|
||||
}: {
|
||||
type: 'image' | 'video'
|
||||
uri: string
|
||||
}) => {
|
||||
await uploadAttachment({
|
||||
composeDispatch,
|
||||
imageInfo: { type, uri, width: 100, height: 100 }
|
||||
})
|
||||
}
|
||||
switch (params?.type) {
|
||||
case 'share':
|
||||
if (params.text) {
|
||||
|
@ -158,12 +146,13 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
|
|||
disableDebounce: true
|
||||
})
|
||||
}
|
||||
if (params.images?.length) {
|
||||
params.images.forEach(image => {
|
||||
uploadImage({ type: 'image', uri: image.uri })
|
||||
if (params.media?.length) {
|
||||
for (const m of params.media) {
|
||||
uploadAttachment({
|
||||
composeDispatch,
|
||||
media: { ...m, width: 100, height: 100 }
|
||||
})
|
||||
} else if (params.video) {
|
||||
uploadImage({ type: 'video', uri: params.video.uri })
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'edit':
|
||||
|
|
|
@ -128,7 +128,9 @@ const ComposeEditAttachmentImage: React.FC<Props> = ({ index }) => {
|
|||
height: imageDimensionis.height
|
||||
}}
|
||||
source={{
|
||||
uri: theAttachmentLocal?.uri || theAttachmentRemote?.preview_url
|
||||
uri: theAttachmentLocal?.path
|
||||
? `file://${theAttachmentLocal?.path}`
|
||||
: theAttachmentRemote?.preview_url
|
||||
}}
|
||||
/>
|
||||
<PanGestureHandler onGestureEvent={onGestureEvent}>
|
||||
|
|
|
@ -34,7 +34,7 @@ const ComposeEditAttachmentRoot: React.FC<Props> = ({ index }) => {
|
|||
video={
|
||||
video.local
|
||||
? ({
|
||||
url: video.local.uri,
|
||||
url: `file://${video.local.path}`,
|
||||
preview_url: video.local.local_thumbnail,
|
||||
blurhash: video.remote?.blurhash
|
||||
} as Mastodon.AttachmentVideo)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import * as Crypto from 'expo-crypto'
|
||||
import { ImageInfo } from 'expo-image-picker/build/ImagePicker.types'
|
||||
import * as VideoThumbnails from 'expo-video-thumbnails'
|
||||
import { Dispatch } from 'react'
|
||||
import { Alert } from 'react-native'
|
||||
|
@ -8,6 +7,7 @@ import { ActionSheetOptions } from '@expo/react-native-action-sheet'
|
|||
import i18next from 'i18next'
|
||||
import apiInstance from '@api/instance'
|
||||
import mediaSelector from '@components/mediaSelector'
|
||||
import { ImageOrVideo } from 'react-native-image-crop-picker'
|
||||
|
||||
export interface Props {
|
||||
composeDispatch: Dispatch<ComposeAction>
|
||||
|
@ -19,39 +19,38 @@ export interface Props {
|
|||
|
||||
export const uploadAttachment = async ({
|
||||
composeDispatch,
|
||||
imageInfo
|
||||
media
|
||||
}: {
|
||||
composeDispatch: Dispatch<ComposeAction>
|
||||
imageInfo: Pick<ImageInfo, 'type' | 'uri' | 'width' | 'height'>
|
||||
media: Pick<ImageOrVideo, 'path' | 'mime' | 'width' | 'height'>
|
||||
}) => {
|
||||
const hash = await Crypto.digestStringAsync(
|
||||
Crypto.CryptoDigestAlgorithm.SHA256,
|
||||
imageInfo.uri + Math.random()
|
||||
media.path + Math.random()
|
||||
)
|
||||
|
||||
let attachmentType: string
|
||||
|
||||
switch (imageInfo.type) {
|
||||
switch (media.mime.split('/')[0]) {
|
||||
case 'image':
|
||||
console.log('uri', imageInfo.uri)
|
||||
attachmentType = `image/${imageInfo.uri.split('.')[1]}`
|
||||
attachmentType = `image/${media.path.split('.')[1]}`
|
||||
composeDispatch({
|
||||
type: 'attachment/upload/start',
|
||||
payload: {
|
||||
local: { ...imageInfo, local_thumbnail: imageInfo.uri, hash },
|
||||
local: { ...media, type: 'image', local_thumbnail: media.path, hash },
|
||||
uploading: true
|
||||
}
|
||||
})
|
||||
break
|
||||
case 'video':
|
||||
attachmentType = `video/${imageInfo.uri.split('.')[1]}`
|
||||
VideoThumbnails.getThumbnailAsync(imageInfo.uri)
|
||||
attachmentType = `video/${media.path.split('.')[1]}`
|
||||
VideoThumbnails.getThumbnailAsync(media.path)
|
||||
.then(({ uri, width, height }) =>
|
||||
composeDispatch({
|
||||
type: 'attachment/upload/start',
|
||||
payload: {
|
||||
local: {
|
||||
...imageInfo,
|
||||
...media,
|
||||
type: 'video',
|
||||
local_thumbnail: uri,
|
||||
hash,
|
||||
width,
|
||||
|
@ -65,7 +64,7 @@ export const uploadAttachment = async ({
|
|||
composeDispatch({
|
||||
type: 'attachment/upload/start',
|
||||
payload: {
|
||||
local: { ...imageInfo, hash },
|
||||
local: { ...media, type: 'video', hash },
|
||||
uploading: true
|
||||
}
|
||||
})
|
||||
|
@ -76,7 +75,7 @@ export const uploadAttachment = async ({
|
|||
composeDispatch({
|
||||
type: 'attachment/upload/start',
|
||||
payload: {
|
||||
local: { ...imageInfo, hash },
|
||||
local: { ...media, type: 'unknown', hash },
|
||||
uploading: true
|
||||
}
|
||||
})
|
||||
|
@ -106,14 +105,14 @@ export const uploadAttachment = async ({
|
|||
|
||||
const formData = new FormData()
|
||||
formData.append('file', {
|
||||
// @ts-ignore
|
||||
uri: imageInfo.uri,
|
||||
uri: `file://${media.path}`,
|
||||
name: attachmentType,
|
||||
type: attachmentType
|
||||
})
|
||||
} as any)
|
||||
|
||||
return apiInstance<Mastodon.Attachment>({
|
||||
method: 'post',
|
||||
version: 'v2',
|
||||
url: 'media',
|
||||
body: formData
|
||||
})
|
||||
|
@ -121,7 +120,7 @@ export const uploadAttachment = async ({
|
|||
if (res.body.id) {
|
||||
composeDispatch({
|
||||
type: 'attachment/upload/end',
|
||||
payload: { remote: res.body, local: imageInfo }
|
||||
payload: { remote: res.body, local: media }
|
||||
})
|
||||
} else {
|
||||
uploadFailed()
|
||||
|
@ -136,8 +135,13 @@ const chooseAndUploadAttachment = async ({
|
|||
composeDispatch,
|
||||
showActionSheetWithOptions
|
||||
}: Props): Promise<any> => {
|
||||
const result = await mediaSelector({ showActionSheetWithOptions })
|
||||
await uploadAttachment({ composeDispatch, imageInfo: result })
|
||||
const result = await mediaSelector({
|
||||
indicateMaximum: true,
|
||||
showActionSheetWithOptions
|
||||
})
|
||||
for (const media of result) {
|
||||
uploadAttachment({ composeDispatch, media })
|
||||
}
|
||||
}
|
||||
|
||||
export default chooseAndUploadAttachment
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import CustomText from '@components/Text'
|
||||
import PasteInput, { PastedFile } from '@mattermost/react-native-paste-input'
|
||||
import { getInstanceConfigurationStatusMaxAttachments } from '@utils/slices/instancesSlice'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useContext } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Alert, TextInput } from 'react-native'
|
||||
import { Alert } from 'react-native'
|
||||
import { useSelector } from 'react-redux'
|
||||
import formatText from '../../formatText'
|
||||
import ComposeContext from '../../utils/createContext'
|
||||
|
@ -21,7 +22,7 @@ const ComposeTextInput: React.FC = () => {
|
|||
)
|
||||
|
||||
return (
|
||||
<TextInput
|
||||
<PasteInput
|
||||
keyboardAppearance={mode}
|
||||
style={{
|
||||
...StyleConstants.FontStyle.M,
|
||||
|
@ -62,8 +63,12 @@ const ComposeTextInput: React.FC = () => {
|
|||
}}
|
||||
ref={composeState.textInputFocus.refs.text}
|
||||
scrollEnabled={false}
|
||||
onImageChange={({ nativeEvent }) => {
|
||||
if (composeState.attachments.uploads.length >= maxAttachments) {
|
||||
disableCopyPaste={false}
|
||||
onPaste={(error: string | null | undefined, files: PastedFile[]) => {
|
||||
if (
|
||||
composeState.attachments.uploads.length + files.length >
|
||||
maxAttachments
|
||||
) {
|
||||
Alert.alert(
|
||||
t(
|
||||
'content.root.header.textInput.keyboardImage.exceedMaximum.title'
|
||||
|
@ -80,12 +85,13 @@ const ComposeTextInput: React.FC = () => {
|
|||
)
|
||||
return
|
||||
}
|
||||
if (nativeEvent.linkUri) {
|
||||
|
||||
for (const file of files) {
|
||||
uploadAttachment({
|
||||
composeDispatch,
|
||||
imageInfo: {
|
||||
uri: nativeEvent.linkUri,
|
||||
type: 'image',
|
||||
media: {
|
||||
path: file.uri,
|
||||
mime: file.type,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
|
@ -94,7 +100,7 @@ const ComposeTextInput: React.FC = () => {
|
|||
}}
|
||||
>
|
||||
<CustomText>{composeState.text.formatted}</CustomText>
|
||||
</TextInput>
|
||||
</PasteInput>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ const composeReducer = (
|
|||
attachments: {
|
||||
...state.attachments,
|
||||
uploads: state.attachments.uploads.map(upload =>
|
||||
upload.local?.uri === action.payload.local?.uri
|
||||
upload.local?.path === action.payload.local?.path
|
||||
? { ...upload, remote: action.payload.remote, uploading: false }
|
||||
: upload
|
||||
)
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
import { ImageOrVideo } from 'react-native-image-crop-picker'
|
||||
|
||||
export type ExtendedAttachment = {
|
||||
remote?: Mastodon.Attachment
|
||||
local?: App.IImageInfo & { local_thumbnail?: string; hash?: string }
|
||||
local?: Pick<ImageOrVideo, 'path' | 'width' | 'height' | 'mime'> & {
|
||||
type: 'image' | 'video' | 'unknown'
|
||||
local_thumbnail?: string
|
||||
hash?: string
|
||||
}
|
||||
uploading?: boolean
|
||||
}
|
||||
|
||||
|
@ -115,7 +121,10 @@ export type ComposeAction =
|
|||
}
|
||||
| {
|
||||
type: 'attachment/upload/end'
|
||||
payload: { remote: Mastodon.Attachment; local: ImageInfo }
|
||||
payload: {
|
||||
remote: Mastodon.Attachment
|
||||
local: Pick<ImageOrVideo, 'path' | 'width' | 'height' | 'mime'>
|
||||
}
|
||||
}
|
||||
| {
|
||||
type: 'attachment/upload/fail'
|
||||
|
|
|
@ -3,7 +3,6 @@ import { MenuRow } from '@components/Menu'
|
|||
import { useActionSheet } from '@expo/react-native-action-sheet'
|
||||
import { useProfileMutation, useProfileQuery } from '@utils/queryHooks/profile'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import * as ImagePicker from 'expo-image-picker'
|
||||
import React, { RefObject } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import FlashMessage from 'react-native-flash-message'
|
||||
|
@ -30,9 +29,13 @@ const ProfileAvatarHeader: React.FC<Props> = ({ type, messageRef }) => {
|
|||
iconBack='ChevronRight'
|
||||
onPress={async () => {
|
||||
const image = await mediaSelector({
|
||||
mediaType: 'photo',
|
||||
maximum: 1,
|
||||
showActionSheetWithOptions,
|
||||
mediaTypes: ImagePicker.MediaTypeOptions.Images,
|
||||
resize: { width: 400, height: 400 }
|
||||
resize:
|
||||
type === 'avatar'
|
||||
? { width: 400, height: 400 }
|
||||
: { width: 1500, height: 500 }
|
||||
})
|
||||
mutation.mutate({
|
||||
theme,
|
||||
|
@ -43,7 +46,7 @@ const ProfileAvatarHeader: React.FC<Props> = ({ type, messageRef }) => {
|
|||
failed: true
|
||||
},
|
||||
type,
|
||||
data: image.uri
|
||||
data: image[0].path
|
||||
})
|
||||
}}
|
||||
/>
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import analytics from '@components/analytics'
|
||||
import { HeaderRight } from '@components/Header'
|
||||
import Timeline from '@components/Timeline'
|
||||
import TimelineDefault from '@components/Timeline/Default'
|
||||
import SegmentedControl from '@react-native-community/segmented-control'
|
||||
|
@ -23,8 +21,7 @@ const TabSharedAccount: React.FC<
|
|||
> = ({
|
||||
route: {
|
||||
params: { account }
|
||||
},
|
||||
navigation
|
||||
}
|
||||
}) => {
|
||||
const { t, i18n } = useTranslation('screenTabs')
|
||||
const { colors, mode } = useTheme()
|
||||
|
@ -33,33 +30,6 @@ const TabSharedAccount: React.FC<
|
|||
|
||||
const scrollY = useSharedValue(0)
|
||||
|
||||
useEffect(() => {
|
||||
const updateHeaderRight = () =>
|
||||
navigation.setOptions({
|
||||
headerRight: () => (
|
||||
<HeaderRight
|
||||
accessibilityLabel={t('shared.account.actions.accessibilityLabel', {
|
||||
user: data?.acct
|
||||
})}
|
||||
accessibilityHint={t('shared.account.actions.accessibilityHint')}
|
||||
content='MoreHorizontal'
|
||||
onPress={() => {
|
||||
analytics('bottomsheet_open_press', {
|
||||
page: 'account'
|
||||
})
|
||||
// @ts-ignore
|
||||
navigation.navigate('Screen-Actions', {
|
||||
type: 'account',
|
||||
account
|
||||
})
|
||||
}}
|
||||
background
|
||||
/>
|
||||
)
|
||||
})
|
||||
return updateHeaderRight()
|
||||
}, [i18n.language])
|
||||
|
||||
const onScroll = useCallback(({ nativeEvent }) => {
|
||||
scrollY.value = nativeEvent.contentOffset.y
|
||||
}, [])
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import { HeaderCenter, HeaderLeft } from '@components/Header'
|
||||
import contextMenuAccount from '@components/ContextMenu/account'
|
||||
import contextMenuShare from '@components/ContextMenu/share'
|
||||
import { HeaderCenter, HeaderLeft, HeaderRight } from '@components/Header'
|
||||
import { ParseEmojis } from '@components/Parse'
|
||||
import CustomText from '@components/Text'
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||
|
@ -16,6 +18,7 @@ import { debounce } from 'lodash'
|
|||
import React from 'react'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { Platform, TextInput, View } from 'react-native'
|
||||
import ContextMenu, { ContextMenuAction } from 'react-native-context-menu-view'
|
||||
|
||||
const TabSharedRoot = ({
|
||||
Stack
|
||||
|
@ -36,7 +39,10 @@ const TabSharedRoot = ({
|
|||
name='Tab-Shared-Account'
|
||||
component={TabSharedAccount}
|
||||
options={({
|
||||
navigation
|
||||
navigation,
|
||||
route: {
|
||||
params: { account }
|
||||
}
|
||||
}: TabSharedStackScreenProps<'Tab-Shared-Account'>) => {
|
||||
return {
|
||||
headerTransparent: true,
|
||||
|
@ -46,8 +52,45 @@ const TabSharedRoot = ({
|
|||
title: '',
|
||||
headerLeft: () => (
|
||||
<HeaderLeft onPress={() => navigation.goBack()} background />
|
||||
),
|
||||
headerRight: () => {
|
||||
const actions: ContextMenuAction[] = []
|
||||
|
||||
const shareOnPress = contextMenuShare({
|
||||
actions,
|
||||
type: 'account',
|
||||
url: account.url
|
||||
})
|
||||
const accountOnPress = contextMenuAccount({
|
||||
actions,
|
||||
id: account.id
|
||||
})
|
||||
|
||||
return (
|
||||
<ContextMenu
|
||||
actions={actions}
|
||||
onPress={({ nativeEvent: { id } }) => {
|
||||
shareOnPress(id)
|
||||
accountOnPress(id)
|
||||
}}
|
||||
dropdownMenuMode
|
||||
>
|
||||
<HeaderRight
|
||||
accessibilityLabel={t(
|
||||
'shared.account.actions.accessibilityLabel',
|
||||
{ user: account.acct }
|
||||
)}
|
||||
accessibilityHint={t(
|
||||
'shared.account.actions.accessibilityHint'
|
||||
)}
|
||||
content='MoreHorizontal'
|
||||
onPress={() => {}}
|
||||
background
|
||||
/>
|
||||
</ContextMenu>
|
||||
)
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
|
|
|
@ -7,16 +7,6 @@ import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
|||
export type RootStackParamList = {
|
||||
'Screen-Tabs': NavigatorScreenParams<ScreenTabsStackParamList>
|
||||
'Screen-Actions':
|
||||
| {
|
||||
type: 'status'
|
||||
queryKey: QueryKeyTimeline
|
||||
rootQueryKey?: QueryKeyTimeline
|
||||
status: Mastodon.Status
|
||||
}
|
||||
| {
|
||||
type: 'account'
|
||||
account: Mastodon.Account
|
||||
}
|
||||
| {
|
||||
type: 'notifications_filter'
|
||||
}
|
||||
|
@ -52,8 +42,7 @@ export type RootStackParamList = {
|
|||
| {
|
||||
type: 'share'
|
||||
text?: string
|
||||
images?: { type: string; uri: string }[]
|
||||
video?: { type: string; uri: string }
|
||||
media?: { path: string; mime: string }[]
|
||||
}
|
||||
| undefined
|
||||
'Screen-ImagesViewer': {
|
||||
|
|
|
@ -78,7 +78,6 @@ const pushUseConnect = ({ t, instances }: Params) => {
|
|||
|
||||
useEffect(() => {
|
||||
const appStateListener = AppState.addEventListener('change', state => {
|
||||
console.log('changing state to', state)
|
||||
if (expoToken && pushEnabled.length && state === 'active') {
|
||||
Notifications.getBadgeCountAsync().then(count => {
|
||||
if (count > 0) {
|
||||
|
@ -96,6 +95,7 @@ const pushUseConnect = ({ t, instances }: Params) => {
|
|||
|
||||
return useEffect(() => {
|
||||
if (expoToken && pushEnabled.length) {
|
||||
Notifications.setBadgeCountAsync(0)
|
||||
connect()
|
||||
}
|
||||
}, [expoToken, pushEnabled.length])
|
||||
|
|
|
@ -71,11 +71,10 @@ const mutationFunction = async ({ type, data }: MutationVarsProfile) => {
|
|||
})
|
||||
} else if (type === 'avatar' || type === 'header') {
|
||||
formData.append(type, {
|
||||
// @ts-ignore
|
||||
uri: data,
|
||||
uri: `file://${data}`,
|
||||
name: 'image/jpeg',
|
||||
type: 'image/jpeg'
|
||||
})
|
||||
} as any)
|
||||
} else {
|
||||
// @ts-ignore
|
||||
formData.append(type, data)
|
||||
|
|
356
yarn.lock
356
yarn.lock
|
@ -1410,10 +1410,10 @@
|
|||
mv "~2"
|
||||
safe-json-stringify "~1"
|
||||
|
||||
"@expo/cli@0.1.4":
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@expo/cli/-/cli-0.1.4.tgz#1eebf652eabf0eca4b567d9f8bb6ab38d11a3051"
|
||||
integrity sha512-A9yq0+3ntqc7eNot4QfhAtAqx8bT50uleeQfTwhCiBPlArQ+zL2sHJVR5Vy79o80PJLQ0KoP3sxsCs1nkZ6rWw==
|
||||
"@expo/cli@0.1.5":
|
||||
version "0.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@expo/cli/-/cli-0.1.5.tgz#2427e3c3b6be1936b2e6ffb595fc9c83e37e4be1"
|
||||
integrity sha512-27LNT3b9MtBHEosmvJiC9Ug9aJpQAK9T3cC8ekaB9cHnVcJw+mJs2kdVBYpV1aBjKkH7T57aiWWimZp0O7m1wQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.14.0"
|
||||
"@expo/code-signing-certificates" "^0.0.2"
|
||||
|
@ -1532,24 +1532,6 @@
|
|||
xcode "^3.0.1"
|
||||
xml2js "0.4.23"
|
||||
|
||||
"@expo/config-plugins@^2.0.2":
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-2.0.4.tgz#955fd70a2aeefbe99ec71cecb1d7ea7b626dc79e"
|
||||
integrity sha512-JGt/X2tFr7H8KBQrKfbGo9hmCubQraMxq5sj3bqDdKmDOLcE1a/EDCP9g0U4GHsa425J8VDIkQUHYz3h3ndEXQ==
|
||||
dependencies:
|
||||
"@expo/config-types" "^41.0.0"
|
||||
"@expo/json-file" "8.2.30"
|
||||
"@expo/plist" "0.0.13"
|
||||
debug "^4.3.1"
|
||||
find-up "~5.0.0"
|
||||
fs-extra "9.0.0"
|
||||
getenv "^1.0.0"
|
||||
glob "7.1.6"
|
||||
resolve-from "^5.0.0"
|
||||
slash "^3.0.0"
|
||||
xcode "^3.0.1"
|
||||
xml2js "^0.4.23"
|
||||
|
||||
"@expo/config-plugins@^4.0.14":
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-4.1.0.tgz#0365e2e51e2e3e3b4e7db1fbbada5be661798be6"
|
||||
|
@ -1572,11 +1554,6 @@
|
|||
xcode "^3.0.1"
|
||||
xml2js "0.4.23"
|
||||
|
||||
"@expo/config-types@^41.0.0":
|
||||
version "41.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-41.0.0.tgz#ffe1444c6c26e0e3a8f7149b4afe486e357536d1"
|
||||
integrity sha512-Ax0pHuY5OQaSrzplOkT9DdpdmNzaVDnq9VySb4Ujq7UJ4U4jriLy8u93W98zunOXpcu0iiKubPsqD6lCiq0pig==
|
||||
|
||||
"@expo/config-types@^44.0.0":
|
||||
version "44.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-44.0.0.tgz#d3480fe2c99f9e895dae4ebba58b74ed72d03e26"
|
||||
|
@ -1690,16 +1667,6 @@
|
|||
semver "7.3.2"
|
||||
tempy "0.3.0"
|
||||
|
||||
"@expo/json-file@8.2.30":
|
||||
version "8.2.30"
|
||||
resolved "https://registry.yarnpkg.com/@expo/json-file/-/json-file-8.2.30.tgz#bd855b6416b5c3af7e55b43f6761c1e7d2b755b0"
|
||||
integrity sha512-vrgGyPEXBoFI5NY70IegusCSoSVIFV3T3ry4tjJg1MFQKTUlR7E0r+8g8XR6qC705rc2PawaZQjqXMAVtV6s2A==
|
||||
dependencies:
|
||||
"@babel/code-frame" "~7.10.4"
|
||||
fs-extra "9.0.0"
|
||||
json5 "^1.0.1"
|
||||
write-file-atomic "^2.3.0"
|
||||
|
||||
"@expo/json-file@8.2.34":
|
||||
version "8.2.34"
|
||||
resolved "https://registry.yarnpkg.com/@expo/json-file/-/json-file-8.2.34.tgz#2f24e90a677195f7a81e167115460eb2902c3130"
|
||||
|
@ -1756,15 +1723,6 @@
|
|||
split "^1.0.1"
|
||||
sudo-prompt "9.1.1"
|
||||
|
||||
"@expo/plist@0.0.13":
|
||||
version "0.0.13"
|
||||
resolved "https://registry.yarnpkg.com/@expo/plist/-/plist-0.0.13.tgz#700a48d9927aa2b0257c613e13454164e7371a96"
|
||||
integrity sha512-zGPSq9OrCn7lWvwLLHLpHUUq2E40KptUFXn53xyZXPViI0k9lbApcR9KlonQZ95C+ELsf0BQ3gRficwK92Ivcw==
|
||||
dependencies:
|
||||
base64-js "^1.2.3"
|
||||
xmlbuilder "^14.0.0"
|
||||
xmldom "~0.5.0"
|
||||
|
||||
"@expo/plist@0.0.17":
|
||||
version "0.0.17"
|
||||
resolved "https://registry.yarnpkg.com/@expo/plist/-/plist-0.0.17.tgz#0f6c594e116f45a28f5ed20998dadb5f3429f88b"
|
||||
|
@ -1855,126 +1813,126 @@
|
|||
find-up "^5.0.0"
|
||||
js-yaml "^4.1.0"
|
||||
|
||||
"@formatjs/ecma402-abstract@1.11.6":
|
||||
version "1.11.6"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.6.tgz#0e828ddfed6fb3413ae379e48fb7170fb0795db5"
|
||||
integrity sha512-6TcI+IroIK+GTWXBJ643LBJklmCBsqLt1sUTGWfzdBcI5Y6b1L1iamrJB1B5OAQLnhzWveLbmzPYHYsFEZfeig==
|
||||
"@formatjs/ecma402-abstract@1.11.7":
|
||||
version "1.11.7"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.7.tgz#47f1a854f679f813d9baa1ee55adae94880ec706"
|
||||
integrity sha512-uNaok4XWMJBtPZk/veTDamFCm5HeWJUk2jwoVfH5/+wenQ60QHjH6T3UQ0GOOCz9jpKmed7vqOri7xSf//Dt7g==
|
||||
dependencies:
|
||||
"@formatjs/intl-localematcher" "0.2.27"
|
||||
"@formatjs/intl-localematcher" "0.2.28"
|
||||
tslib "2.4.0"
|
||||
|
||||
"@formatjs/fast-memoize@1.2.3":
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-1.2.3.tgz#5c950bd64c4959e30bbd16b22a17040fbeb9c4d2"
|
||||
integrity sha512-RVI3e4M7mIxAhKbbyS78H8++fsoiSRZgxh0zReHfvV6p1cpfgG2/k2qJYhJq0RXh6orVtUEsQ3xK9i4tDfsOSg==
|
||||
"@formatjs/fast-memoize@1.2.4":
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-1.2.4.tgz#4b5ddce9eb7803ff0bd4052387672151a8b7f8a0"
|
||||
integrity sha512-9ARYoLR8AEzXvj2nYrOVHY/h1dDMDWGTnKDLXSISF1uoPakSmfcZuSqjiqZX2wRkEUimPxdwTu/agyozBtZRHA==
|
||||
dependencies:
|
||||
tslib "2.4.0"
|
||||
|
||||
"@formatjs/icu-messageformat-parser@2.1.2":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.2.tgz#9ff4dfc4f1ed613cca2c188b29f299854b86b7f8"
|
||||
integrity sha512-FYQ2pkgbDJxJlst/U5MU2H7+bR9HrZ4x8J4c0etrya24pJzQxYguVlAhc2S6NoEImlQ2LmIIGsURaBQu9bCtew==
|
||||
"@formatjs/icu-messageformat-parser@2.1.3":
|
||||
version "2.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.3.tgz#d228ac26f22630689a1263e83192227f1d085bd3"
|
||||
integrity sha512-hsdAn1dXcujW/G8DHw0iiIy7357pw10yOulCrL6xrQOKJAxT7m7EgpG0Hm1OW9xqaLEzqWyE/jA2AGVnOCaCQw==
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract" "1.11.6"
|
||||
"@formatjs/icu-skeleton-parser" "1.3.8"
|
||||
"@formatjs/ecma402-abstract" "1.11.7"
|
||||
"@formatjs/icu-skeleton-parser" "1.3.9"
|
||||
tslib "2.4.0"
|
||||
|
||||
"@formatjs/icu-skeleton-parser@1.3.8":
|
||||
version "1.3.8"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.8.tgz#3d150fcb45b4867c1db84237ca1f1f701d598918"
|
||||
integrity sha512-CVdsPMs/KvrIDKhMDw8bSq/Zst2bhdn/bTUfVCHi/c/bj462lChIJmW/JP/FaGKgZzdG8slGyVIFLonpG4uqFA==
|
||||
"@formatjs/icu-skeleton-parser@1.3.9":
|
||||
version "1.3.9"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.9.tgz#149badc16ffd15dd928f8047ae21aa9136e0ea73"
|
||||
integrity sha512-s9THwwhiiSzbGSk73FP6Ur2MBwEj1vfgYDHKa5FiXGQMfYzdRdRvyH1dgqNgSFJPB6PM3DKtkloJLjpqpSDNUg==
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract" "1.11.6"
|
||||
"@formatjs/ecma402-abstract" "1.11.7"
|
||||
tslib "2.4.0"
|
||||
|
||||
"@formatjs/intl-datetimeformat@^6.0.1":
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-datetimeformat/-/intl-datetimeformat-6.0.1.tgz#cd107a2d3f85dd8e8103fc967e40618f65c7c8ad"
|
||||
integrity sha512-j/cDALY35GENMBEvcTUaRO97VCZn8CaocbNl7WLIl2HC9jdcdnMeVTY38dYLM6lfSoarIiNAWRE3oTQKOh086g==
|
||||
"@formatjs/intl-datetimeformat@^6.0.2":
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-datetimeformat/-/intl-datetimeformat-6.0.2.tgz#a1d7da8b660af48b2fd152b0d745bec14a0f15ad"
|
||||
integrity sha512-nKJmSmyTYAN5NaHRocebuoyPpd+m2HWiXgwY0CvMfFjv0QIeDVNAtECBzaDPf57bTKFjaDt1t1/5Z0D0r7+r4Q==
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract" "1.11.6"
|
||||
"@formatjs/intl-localematcher" "0.2.27"
|
||||
"@formatjs/ecma402-abstract" "1.11.7"
|
||||
"@formatjs/intl-localematcher" "0.2.28"
|
||||
tslib "2.4.0"
|
||||
|
||||
"@formatjs/intl-displaynames@6.0.1":
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-6.0.1.tgz#b4bf890d440a19da03203a5e7f1bff1460b2b859"
|
||||
integrity sha512-KPfB+mOIzcptAzpNIciDc+rK4kRCg5aTCXPr5feIWNxvd/H1Wr3cVVDV2YGdPn+Woo9b1K4cnUi3b1IvBFQ/5g==
|
||||
"@formatjs/intl-displaynames@6.0.2":
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-6.0.2.tgz#f6349b5c75fd9ecc7c77c7e73101daee5dc69e3a"
|
||||
integrity sha512-h9Id/6vbSHpARHKMVsjWag3KMZJpop9s67CZTd+AMxhjHb5xDG2b5rlSRJKx/UdIDQ+GzESK7a4fv32yylG3cw==
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract" "1.11.6"
|
||||
"@formatjs/intl-localematcher" "0.2.27"
|
||||
"@formatjs/ecma402-abstract" "1.11.7"
|
||||
"@formatjs/intl-localematcher" "0.2.28"
|
||||
tslib "2.4.0"
|
||||
|
||||
"@formatjs/intl-getcanonicallocales@2.0.1", "@formatjs/intl-getcanonicallocales@^2.0.1":
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-getcanonicallocales/-/intl-getcanonicallocales-2.0.1.tgz#da2b7749a99d4347e2dacef103e3044eed3ef915"
|
||||
integrity sha512-MDbYGYdBdhxNBNm5trIhYZWRu2yC6Le+2IQ0bzus7sY7AEHswz0TcyekfYywiV3QF4E7x0YtJDIKTi6oH14NRg==
|
||||
"@formatjs/intl-getcanonicallocales@2.0.2", "@formatjs/intl-getcanonicallocales@^2.0.2":
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-getcanonicallocales/-/intl-getcanonicallocales-2.0.2.tgz#e9fd5d2215ce0dba4d8611b37ac87c5fae60a1a7"
|
||||
integrity sha512-nMkPblAjgK49ORueVhyuKJDXOCq8at2h9Xf0lqabBZylaX3xLEeuAW2eMXuwJ/ascYYQnwuxeukd/qlzDkuJzQ==
|
||||
dependencies:
|
||||
tslib "2.4.0"
|
||||
|
||||
"@formatjs/intl-listformat@7.0.1":
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-listformat/-/intl-listformat-7.0.1.tgz#9b7f0d46a6eb04138dde5d57c898222315f87334"
|
||||
integrity sha512-sgE4B9+mu3ZF77vhZB0tR8O3evvcPA//WbA/8UJ21XOrSzfY6RXhSbvDfSd7Y5iEeBu+2C+5YxDuAwLnvq2SnQ==
|
||||
"@formatjs/intl-listformat@7.0.2":
|
||||
version "7.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-listformat/-/intl-listformat-7.0.2.tgz#c07d370c9171dfc86c163addbfcb08f67ae26215"
|
||||
integrity sha512-K+HXrYIvEcAH/dS8XXnSHQYC/z4w0eHjPlDx43HOoDY87/xV7rpHxFVXWXTgwLYC6iAPUO72Y/AaT9iq873juw==
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract" "1.11.6"
|
||||
"@formatjs/intl-localematcher" "0.2.27"
|
||||
"@formatjs/ecma402-abstract" "1.11.7"
|
||||
"@formatjs/intl-localematcher" "0.2.28"
|
||||
tslib "2.4.0"
|
||||
|
||||
"@formatjs/intl-locale@^3.0.1":
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-locale/-/intl-locale-3.0.1.tgz#ec6eb1d989b4ccb4f3669a03ac84c087dc686398"
|
||||
integrity sha512-z3WXS9SxHUBi6JqvWgEPCvlSZF2Hw6jj272J/YqIVqBahViReUHjj3/2kVsTBndTe2HVkkaxURJNE+yd1MFqFw==
|
||||
"@formatjs/intl-locale@^3.0.2":
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-locale/-/intl-locale-3.0.2.tgz#d0055c8672e6f27fc09dff15f0f7def32ce1bcf1"
|
||||
integrity sha512-ZnBrrm0nDup6AzRGGBp7Gt5Ow4lLwtKdb3i4kCdjUr8drZin1WJUP63sxtotEGHene9c34mA5kifBeq7hHWS9g==
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract" "1.11.6"
|
||||
"@formatjs/intl-getcanonicallocales" "2.0.1"
|
||||
"@formatjs/ecma402-abstract" "1.11.7"
|
||||
"@formatjs/intl-getcanonicallocales" "2.0.2"
|
||||
tslib "2.4.0"
|
||||
|
||||
"@formatjs/intl-localematcher@0.2.27":
|
||||
version "0.2.27"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.2.27.tgz#8a837ddca17a55d86e4ab68bcbb25b15f547d61d"
|
||||
integrity sha512-XHYcVas2ebDTh3VtfdluvbTjqyMUHqFHARnuJo5KYF/0MKOTmozVSK7PJGnu1IEHdmRdTWuG6TB+2RnkasaxVw==
|
||||
"@formatjs/intl-localematcher@0.2.28":
|
||||
version "0.2.28"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.2.28.tgz#412ea7fefbfc7ed33cd6b43aa304fc14d816e564"
|
||||
integrity sha512-FLsc6Gifs1np/8HnCn/7Q+lHMmenrD5fuDhRT82yj0gi9O19kfaFwjQUw1gZsyILuRyT93GuzdifHj7TKRhBcw==
|
||||
dependencies:
|
||||
tslib "2.4.0"
|
||||
|
||||
"@formatjs/intl-numberformat@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-numberformat/-/intl-numberformat-8.0.1.tgz#f5a9269480c869c3ec35c4689074c32ae6240a10"
|
||||
integrity sha512-g0ce2KBbYFhbArsduHBB/QsGw4iVLEhbIYOT6Ra44/iEMGQ1aFLvSKiGYZatCZF7CgK0DTwmZ1RFy7vrs7w24w==
|
||||
"@formatjs/intl-numberformat@^8.0.2":
|
||||
version "8.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-numberformat/-/intl-numberformat-8.0.2.tgz#35bacb5d55441b1d3f541c796057f87c165b63ef"
|
||||
integrity sha512-Fw7Y8Iqm/d5aF+3HkTCbtOxTHIh1DonohPGUEJYHqKVftx12ybtxMLpEGbArRnWdDC6+lVTmPTlHIHcf/vyLTA==
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract" "1.11.6"
|
||||
"@formatjs/intl-localematcher" "0.2.27"
|
||||
"@formatjs/ecma402-abstract" "1.11.7"
|
||||
"@formatjs/intl-localematcher" "0.2.28"
|
||||
tslib "2.4.0"
|
||||
|
||||
"@formatjs/intl-pluralrules@^5.0.1":
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-pluralrules/-/intl-pluralrules-5.0.1.tgz#23bce3c680791e25dec066c358d7aad81376cff7"
|
||||
integrity sha512-YOgsZ4t2rrlfT53BC4AtxOrmG5i4yp75L/9HJOcH7leheqAT2AWc8GzimwGCXXzaHqrne5p4uhx4ikfzTyLbpw==
|
||||
"@formatjs/intl-pluralrules@^5.0.2":
|
||||
version "5.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-pluralrules/-/intl-pluralrules-5.0.2.tgz#406a60d8b8296fc0a1c2d59801e6decc236eed89"
|
||||
integrity sha512-wXIW26RMLOSKpK5jqX0fZYHqPb1mhR41+FSL9x/6B/qe3zb+xkq5FuAoKLb4j/+rNehy7uVOl963JXsbSexy0A==
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract" "1.11.6"
|
||||
"@formatjs/intl-localematcher" "0.2.27"
|
||||
"@formatjs/ecma402-abstract" "1.11.7"
|
||||
"@formatjs/intl-localematcher" "0.2.28"
|
||||
tslib "2.4.0"
|
||||
|
||||
"@formatjs/intl-relativetimeformat@^11.0.1":
|
||||
version "11.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-relativetimeformat/-/intl-relativetimeformat-11.0.1.tgz#4257938077881d069d134410971596ddb0045b27"
|
||||
integrity sha512-+R7CReF9mgoCblWLsO6RPRCN47VLhi8TaK6yNL5bH7aQXcNk8m/4UZjz7taUVXBoJmqfxqzIh5pa8n9V+JtNgg==
|
||||
"@formatjs/intl-relativetimeformat@^11.0.2":
|
||||
version "11.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-relativetimeformat/-/intl-relativetimeformat-11.0.2.tgz#c4c79dcfc31d6e9cc2870efb4806367b67101b56"
|
||||
integrity sha512-jZUv3z/NIPTEZRMDvLrQBC9tWpo+gAMmFNi9Pp8VksRGd87j0ndgmPSUuRJQX6OQxnXhlCGltIxpwX2j+289MQ==
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract" "1.11.6"
|
||||
"@formatjs/intl-localematcher" "0.2.27"
|
||||
"@formatjs/ecma402-abstract" "1.11.7"
|
||||
"@formatjs/intl-localematcher" "0.2.28"
|
||||
tslib "2.4.0"
|
||||
|
||||
"@formatjs/intl@2.2.5":
|
||||
version "2.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-2.2.5.tgz#888f42750eacdcfb836a062eb889cb429d13f7f7"
|
||||
integrity sha512-b0+5Bjsl3KDAII2frBPRO7ck9Ec/xqZ25BoiJATJhe//e4n6FOvVXk5QKYwBQPDt3JPu/Qa14oqHDiZlZmVdSg==
|
||||
"@formatjs/intl@2.3.0":
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-2.3.0.tgz#848edf81c95d608757662b3feada0eb2dacc5424"
|
||||
integrity sha512-mE8zGqP+Flrd8tS3AsdvSucnblqwR5gsGM4Bd5711abkabrz52F2TDrU88rVvVfCdHV4dFHFYEmUBVZZ4pATtg==
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract" "1.11.6"
|
||||
"@formatjs/fast-memoize" "1.2.3"
|
||||
"@formatjs/icu-messageformat-parser" "2.1.2"
|
||||
"@formatjs/intl-displaynames" "6.0.1"
|
||||
"@formatjs/intl-listformat" "7.0.1"
|
||||
intl-messageformat "10.0.1"
|
||||
"@formatjs/ecma402-abstract" "1.11.7"
|
||||
"@formatjs/fast-memoize" "1.2.4"
|
||||
"@formatjs/icu-messageformat-parser" "2.1.3"
|
||||
"@formatjs/intl-displaynames" "6.0.2"
|
||||
"@formatjs/intl-listformat" "7.0.2"
|
||||
intl-messageformat "10.1.0"
|
||||
tslib "2.4.0"
|
||||
|
||||
"@gar/promisify@^1.0.1":
|
||||
|
@ -2081,6 +2039,13 @@
|
|||
"@jridgewell/resolve-uri" "^3.0.3"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
|
||||
"@mattermost/react-native-paste-input@^0.4.2":
|
||||
version "0.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@mattermost/react-native-paste-input/-/react-native-paste-input-0.4.2.tgz#f08f94a921fee89d84a14e2acdbf1905c13ea427"
|
||||
integrity sha512-iHwJkQ3iODVniEi8Qsr8FNOLTAIksjmxcsbbBU4SPiduNKEotOy/qAgexiW1Vsp9jO/WJnQ7Gn59bFNpxVGzmQ==
|
||||
dependencies:
|
||||
deprecated-react-native-prop-types "^2.3.0"
|
||||
|
||||
"@neverdull-agency/expo-unlimited-secure-store@1.0.10":
|
||||
version "1.0.10"
|
||||
resolved "https://registry.yarnpkg.com/@neverdull-agency/expo-unlimited-secure-store/-/expo-unlimited-secure-store-1.0.10.tgz#1e78b502257b267fc918a85eaa41aa01a46d2007"
|
||||
|
@ -2125,10 +2090,10 @@
|
|||
mkdirp "^1.0.4"
|
||||
rimraf "^3.0.2"
|
||||
|
||||
"@react-native-async-storage/async-storage@1.17.4":
|
||||
version "1.17.4"
|
||||
resolved "https://registry.yarnpkg.com/@react-native-async-storage/async-storage/-/async-storage-1.17.4.tgz#f03837565f085c487bc9e8a9f1862c3e4e3f8fb6"
|
||||
integrity sha512-c6GglKBRaWkjNyYd0FM8f0/neQEcwQom4MjZNqYSsIz55LcddJb7W8GM/n2dkzZ0JnaMylMX3+Vo+fpmkFEGTQ==
|
||||
"@react-native-async-storage/async-storage@1.17.6":
|
||||
version "1.17.6"
|
||||
resolved "https://registry.yarnpkg.com/@react-native-async-storage/async-storage/-/async-storage-1.17.6.tgz#ddb3520d051f71698c8a0e79e8959a7bf6d9f43b"
|
||||
integrity sha512-XXnoheQI3vQTQmjphdXNLTmtiKZeRqvI8kPQ25X5Eae7nZjdYEEGN+0z8N2qyelbUIQwKgmW0aagJk56q7DyNg==
|
||||
dependencies:
|
||||
merge-options "^3.0.4"
|
||||
|
||||
|
@ -2313,10 +2278,10 @@
|
|||
sudo-prompt "^9.0.0"
|
||||
wcwidth "^1.0.1"
|
||||
|
||||
"@react-native-community/netinfo@8.3.0":
|
||||
version "8.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-native-community/netinfo/-/netinfo-8.3.0.tgz#e3d19381c7d9f885b44ea1785ed892bc39c4b0f1"
|
||||
integrity sha512-VlmjD7Vg1BacbNhwuJCel1eeD8N2Ps6BEcZe9qoSoeIptpCbC86o4ZqD0meSjJzioKSvgalrkmPgMaVYsVipKw==
|
||||
"@react-native-community/netinfo@9.0.0":
|
||||
version "9.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-native-community/netinfo/-/netinfo-9.0.0.tgz#d5f64158af5c0772b11bdf0aaba569f944b99589"
|
||||
integrity sha512-oodeVNdL0IT/Fv0cpL7CdxnnESNKiiAzf29yhvGSJBvuFmyHxvmYOtBIX27HWG9tQU8Yzeh+MyQcKBCNmkva+Q==
|
||||
|
||||
"@react-native-community/segmented-control@2.2.2":
|
||||
version "2.2.2"
|
||||
|
@ -2539,10 +2504,10 @@
|
|||
"@sentry/types" "6.19.2"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/react-native@3.4.2":
|
||||
version "3.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/react-native/-/react-native-3.4.2.tgz#9d8f60411d73f897e2bc1facafdf3e59e686627d"
|
||||
integrity sha512-rty+Mj77wBslxZ91dUlMwlvTtDpYpYehXMlrP8+AG/qRf2b1yFfLmtehGIwsZrTETp84WIL5evbKMd5nzYO+VQ==
|
||||
"@sentry/react-native@3.4.3":
|
||||
version "3.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/react-native/-/react-native-3.4.3.tgz#00c90f87b5c8e24bf4698656a0994cf38b99dfba"
|
||||
integrity sha512-q1m/KaPWkv9/nXMXo5S5VzZNngC9gxJrtfPnMQPCXzLwLiGMlc2FBMBDJmZGzeSkQMr163Xb+2UYZEPqCUvdvg==
|
||||
dependencies:
|
||||
"@sentry/browser" "6.19.2"
|
||||
"@sentry/cli" "^1.74.2"
|
||||
|
@ -2758,10 +2723,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/react-native-share-menu/-/react-native-share-menu-5.0.2.tgz#c9c8854a3d091cdb046df22dafe4a92332b322f3"
|
||||
integrity sha512-Qa9DGfL6Bvng2DXgCK0fFzdi9SJMGfs06MLSkCfSXBCGKlFLzSHCsXztvXlCCChn3dQArFHyz/uRUN3Sbt6LtQ==
|
||||
|
||||
"@types/react-native@0.67.7":
|
||||
version "0.67.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.67.7.tgz#903b7d56fb6a95ca0de897f2925c04ee0d4adee3"
|
||||
integrity sha512-G7vi9vE226diNNXVNbIa8HH/wPxMWHTHkn9iQtQSezaWzO5WNsKZZW2/TOzCehtBDVx4MZieTs6GsdtpBBttMA==
|
||||
"@types/react-native@0.67.8":
|
||||
version "0.67.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.67.8.tgz#edaaa0527b835fffbfc34c09874722b6e4a4d1f3"
|
||||
integrity sha512-xA8rYiTHvO6RoZv/LFnmEeqRuhA2y34mGB8zX3bGHe/pCt9jEStUPyUO4q1KcDc9GiGIOBD8ArfRtThprAjSfQ==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
|
@ -4463,13 +4428,6 @@ expo-image-loader@~3.2.0:
|
|||
resolved "https://registry.yarnpkg.com/expo-image-loader/-/expo-image-loader-3.2.0.tgz#d98b021660edef7243f7c5ec011b8d0545626d41"
|
||||
integrity sha512-LU3Q2prn64/HxdToDmxgMIRXS1ZvD9Q3iCxRVTZn1fPQNNDciIQFE5okaa74Ogx20DFHs90r6WoUd7w9Af1OGQ==
|
||||
|
||||
expo-image-manipulator@10.3.1:
|
||||
version "10.3.1"
|
||||
resolved "https://registry.yarnpkg.com/expo-image-manipulator/-/expo-image-manipulator-10.3.1.tgz#e16dd76a550c7f5d653a2a666f26429eba311a6b"
|
||||
integrity sha512-D08dMD6MerxBu23DmCIhurySQih+eLP7VxKvY5mWqYz9payjDOS1cAGs3HvXPrEDusPQFQ0uIfqc+oqeMNFBIA==
|
||||
dependencies:
|
||||
expo-image-loader "~3.2.0"
|
||||
|
||||
expo-image-picker@13.1.1:
|
||||
version "13.1.1"
|
||||
resolved "https://registry.yarnpkg.com/expo-image-picker/-/expo-image-picker-13.1.1.tgz#e039bf9748ccb7b89370ff2969c3ef07cc949192"
|
||||
|
@ -4599,10 +4557,10 @@ expo-updates-interface@~0.6.0:
|
|||
resolved "https://registry.yarnpkg.com/expo-updates-interface/-/expo-updates-interface-0.6.0.tgz#cef5250106e59572afdfcf245c534754c8c844ba"
|
||||
integrity sha512-oQcGTsE8mSkSxENPlWjZPGoJpt3RFDNPuO5d8shBDxBb4ZNH/W2ojavSFQMaLbNMoS0bYQQhzbRNEIBd306QMg==
|
||||
|
||||
expo-updates@0.13.1:
|
||||
version "0.13.1"
|
||||
resolved "https://registry.yarnpkg.com/expo-updates/-/expo-updates-0.13.1.tgz#ffed4216eda6afbc15f06399115a5b9e649102a6"
|
||||
integrity sha512-6GTqgAco3da/rk0/AvDRFmrWxEIxlmIs7vvoCWWxyvifLBlQAaU08+AdZH5RwdN3aUaIep70pnqlc67xe/y0og==
|
||||
expo-updates@0.13.2:
|
||||
version "0.13.2"
|
||||
resolved "https://registry.yarnpkg.com/expo-updates/-/expo-updates-0.13.2.tgz#c96d664d8a97eb3af6841e46a137962b8bf06361"
|
||||
integrity sha512-2ZthmyxYuN/c71y2oLNz9fdVXLf7ggxAw3Tfy+kwtGOTKNyOf/YoG+SwX7a0v+jZTJnuorEj5FuNf3wrniQ7+w==
|
||||
dependencies:
|
||||
"@expo/code-signing-certificates" "0.0.1"
|
||||
"@expo/config" "^6.0.14"
|
||||
|
@ -4622,20 +4580,27 @@ expo-video-thumbnails@6.3.0:
|
|||
resolved "https://registry.yarnpkg.com/expo-video-thumbnails/-/expo-video-thumbnails-6.3.0.tgz#07daa798ad175242fef4e62c8f2040b11606a41b"
|
||||
integrity sha512-oVy9XlzNxnpXFDz3FiWOrMOBWmYtZrNYnXc3XaVyj8ayRqwDNvW4P95kQeUhB04uwaMDOm4vIxc5SQxDAyxPGg==
|
||||
|
||||
expo-web-browser@10.2.0, expo-web-browser@~10.2.0:
|
||||
expo-web-browser@10.2.1:
|
||||
version "10.2.1"
|
||||
resolved "https://registry.yarnpkg.com/expo-web-browser/-/expo-web-browser-10.2.1.tgz#4bd9214f7aefcd1af6ea26ae068a0e3e25a1e0bd"
|
||||
integrity sha512-om34EL7OX5ouBM/hq2PrjHDLKmjVhAy+1H7YqRY6nS8dWsewnLFdLq4d8GPwWQBYb6kHKYVzwFRj+WLTfpAOBQ==
|
||||
dependencies:
|
||||
compare-urls "^2.0.0"
|
||||
|
||||
expo-web-browser@~10.2.0:
|
||||
version "10.2.0"
|
||||
resolved "https://registry.yarnpkg.com/expo-web-browser/-/expo-web-browser-10.2.0.tgz#e37450e5a0dd2eb1cf5ea5511589ed207da8aafe"
|
||||
integrity sha512-Y8LCiktTUdPQVgO5BR6uHFU8FGu/8ysT2ynpO0WFeD4odX8JBX5JwQ9HokEa3XvRJNpefgQmXETDjzkMznXMvQ==
|
||||
dependencies:
|
||||
compare-urls "^2.0.0"
|
||||
|
||||
expo@45.0.4:
|
||||
version "45.0.4"
|
||||
resolved "https://registry.yarnpkg.com/expo/-/expo-45.0.4.tgz#a34d250605d5603e3cea4acf169aedd288df477b"
|
||||
integrity sha512-S/6rwmgG+1cyHP1hCmylk9FLnavUWd/haWgVc8sUNiavaMBu/vCjeLUESFVJdYRKKN9i+avSzHdAVdKytNYo6A==
|
||||
expo@45.0.5:
|
||||
version "45.0.5"
|
||||
resolved "https://registry.yarnpkg.com/expo/-/expo-45.0.5.tgz#ff99ad44a59ffabf473c43abbff35d17b10862fe"
|
||||
integrity sha512-ND+Fo/iLZK1ubMvPFzraIQBvtGL7a4ZHGIP8N1PjcOtTGrCc6X7IWyLkfPMAck2yhd80ZTbos8vTU3SAUuBcJw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.14.0"
|
||||
"@expo/cli" "0.1.4"
|
||||
"@expo/cli" "0.1.5"
|
||||
"@expo/vector-icons" "^13.0.0"
|
||||
babel-preset-expo "~9.1.0"
|
||||
cross-spawn "^6.0.5"
|
||||
|
@ -5406,14 +5371,14 @@ internal-slot@^1.0.3:
|
|||
has "^1.0.3"
|
||||
side-channel "^1.0.4"
|
||||
|
||||
intl-messageformat@10.0.1:
|
||||
version "10.0.1"
|
||||
resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.0.1.tgz#dae7ae81a477e92ea8691dd73c60d5eb5003f866"
|
||||
integrity sha512-oZWDsNbauuWmPd98+zLEfNojuJkBdVpEWIcWQVCTxSJrhag2/czZnwKBsYa8NcVf4t0fWo0k77v+CBCudKEcjw==
|
||||
intl-messageformat@10.1.0:
|
||||
version "10.1.0"
|
||||
resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.1.0.tgz#ffbbcbf1068af8466ad5497f78c30c3d96ef5505"
|
||||
integrity sha512-diGMDv9Zo2Mggf6AkJszq/BIR5+rarkwcr4g5JGgREwbwAHY9hR/dYd8FbIgQx2RTxhJsABfAWCiENFLbaTZjg==
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract" "1.11.6"
|
||||
"@formatjs/fast-memoize" "1.2.3"
|
||||
"@formatjs/icu-messageformat-parser" "2.1.2"
|
||||
"@formatjs/ecma402-abstract" "1.11.7"
|
||||
"@formatjs/fast-memoize" "1.2.4"
|
||||
"@formatjs/icu-messageformat-parser" "2.1.3"
|
||||
tslib "2.4.0"
|
||||
|
||||
invariant@*, invariant@^2.2.4:
|
||||
|
@ -7449,20 +7414,20 @@ react-i18next@11.17.0:
|
|||
html-escaper "^2.0.2"
|
||||
html-parse-stringify "^3.0.1"
|
||||
|
||||
react-intl@^6.0.3:
|
||||
version "6.0.3"
|
||||
resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-6.0.3.tgz#eb5857f2fd525c83255bf6c8339562a7fea9f970"
|
||||
integrity sha512-c6wHOnYjOBTbqIt+6TVV2QwdKrqYiFP713tMsw/sJWYgzfaRTjsvGkcxOXhX3SoBrqbUhKTEzjdniuwpAN/qKA==
|
||||
react-intl@^6.0.4:
|
||||
version "6.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-6.0.4.tgz#635d7639aa7b70e837c75796535cf1d534016acf"
|
||||
integrity sha512-eBIP4QuFOdr67+ZmNOA7WGzJ6dj0qgsGQbx3phzcel2B0kVLvfojTJuvYiFuLgbZTrRJMjHwYJZO5zsmibsfug==
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract" "1.11.6"
|
||||
"@formatjs/icu-messageformat-parser" "2.1.2"
|
||||
"@formatjs/intl" "2.2.5"
|
||||
"@formatjs/intl-displaynames" "6.0.1"
|
||||
"@formatjs/intl-listformat" "7.0.1"
|
||||
"@formatjs/ecma402-abstract" "1.11.7"
|
||||
"@formatjs/icu-messageformat-parser" "2.1.3"
|
||||
"@formatjs/intl" "2.3.0"
|
||||
"@formatjs/intl-displaynames" "6.0.2"
|
||||
"@formatjs/intl-listformat" "7.0.2"
|
||||
"@types/hoist-non-react-statics" "^3.3.1"
|
||||
"@types/react" "16 || 17 || 18"
|
||||
hoist-non-react-statics "^3.3.2"
|
||||
intl-messageformat "10.0.1"
|
||||
intl-messageformat "10.1.0"
|
||||
tslib "2.4.0"
|
||||
|
||||
"react-is@^16.12.0 || ^17.0.0", react-is@^17.0.1:
|
||||
|
@ -7510,6 +7475,10 @@ react-native-codegen@^0.0.17:
|
|||
jscodeshift "^0.13.1"
|
||||
nullthrows "^1.1.1"
|
||||
|
||||
react-native-context-menu-view@xmflsct/react-native-context-menu-view:
|
||||
version "1.5.4"
|
||||
resolved "https://codeload.github.com/xmflsct/react-native-context-menu-view/tar.gz/bff5773d318970cd67b5cf114d4bec1e200178eb"
|
||||
|
||||
react-native-fast-image@8.5.11:
|
||||
version "8.5.11"
|
||||
resolved "https://registry.yarnpkg.com/react-native-fast-image/-/react-native-fast-image-8.5.11.tgz#e3dc969d0e4e8df026646bf18194465aa55cbc2b"
|
||||
|
@ -7552,10 +7521,10 @@ react-native-htmlview@0.16.0:
|
|||
entities "^1.1.1"
|
||||
htmlparser2-without-node-native "^3.9.2"
|
||||
|
||||
react-native-image-keyboard@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-native-image-keyboard/-/react-native-image-keyboard-2.2.0.tgz#dc3f90aaaac20a79315015a330e62e85547e0674"
|
||||
integrity sha512-2JzKCXMBYiIUR6OtGV7F/lEWqwIU/6HS1CGOBulxwYNxoa7m1nZk45hNEZPP8SA5yE2pLNXEQePjc3WGAtXo3w==
|
||||
react-native-image-crop-picker@^0.37.3:
|
||||
version "0.37.3"
|
||||
resolved "https://registry.yarnpkg.com/react-native-image-crop-picker/-/react-native-image-crop-picker-0.37.3.tgz#f260e40b6a6ba8e98f4db3dde25a8f09e0936385"
|
||||
integrity sha512-ih+0pWWRUNEFQyaHwGbH9rqJNOb7EBYMwKJhTY0VmsKIA9E+usfwMmQXAFIfOnee7fTn0A2vOXkBCPQZwyvnQw==
|
||||
|
||||
react-native-iphone-x-helper@^1.3.1:
|
||||
version "1.3.1"
|
||||
|
@ -7580,10 +7549,10 @@ react-native-reanimated@2.8.0:
|
|||
setimmediate "^1.0.5"
|
||||
string-hash-64 "^1.0.3"
|
||||
|
||||
react-native-safe-area-context@4.2.5:
|
||||
version "4.2.5"
|
||||
resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-4.2.5.tgz#23006dc1a398bb825d7d795c27f1c46119efe8a5"
|
||||
integrity sha512-nUil2de1gk/8ZB9IzIxFyGCiKeAYcHzJb/Tks2NzSkev1qH4MNR05DWYDSmW6vLT+y4mospLVyG/H5dyUd+KQQ==
|
||||
react-native-safe-area-context@4.3.1:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-4.3.1.tgz#5cf97b25b395e0d09bc1f828920cd7da0d792ade"
|
||||
integrity sha512-cEr7fknJCToTrSyDCVNg0GRdRMhyLeQa2NZwVCuzEQcWedOw/59ExomjmzCE4rxrKXs6OJbyfNtFRNyewDaHuA==
|
||||
|
||||
react-native-screens@3.13.1:
|
||||
version "3.13.1"
|
||||
|
@ -8072,13 +8041,13 @@ send@0.18.0:
|
|||
range-parser "~1.2.1"
|
||||
statuses "2.0.1"
|
||||
|
||||
sentry-expo@4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/sentry-expo/-/sentry-expo-4.1.1.tgz#ff0f494e191a3c43f94043e26ffa18aa4b6059c6"
|
||||
integrity sha512-Nc9w5znsIBUYZ/rpM1uDEeS2KKc1f+tK4FJ8pA0emJjpBQO4cDJHXb0zyDtFYN7T1+vdEZ0cSe7kwgoPSw5V6g==
|
||||
sentry-expo@4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/sentry-expo/-/sentry-expo-4.2.0.tgz#8dc626b39cc1538c1284cc383b9d18c3252859c4"
|
||||
integrity sha512-UL+i+kLDmB27kmY/BvkhY7aBqAxnVdy+IVg4jMX20V/iAgA1HBk2szf2gCt9vHDja6Q0HzgkdC91xiQ89jKiOw==
|
||||
dependencies:
|
||||
"@expo/config-plugins" "^2.0.2"
|
||||
"@expo/config-types" "^41.0.0"
|
||||
"@expo/config-plugins" "~4.1.4"
|
||||
"@expo/config-types" "^45.0.0"
|
||||
"@expo/spawn-async" "^1.2.8"
|
||||
"@sentry/browser" "^6.12.0"
|
||||
"@sentry/integrations" "^6.12.0"
|
||||
|
@ -9171,7 +9140,7 @@ xml-js@^1.6.11:
|
|||
dependencies:
|
||||
sax "^1.2.4"
|
||||
|
||||
xml2js@0.4.23, xml2js@^0.4.23:
|
||||
xml2js@0.4.23:
|
||||
version "0.4.23"
|
||||
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66"
|
||||
integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==
|
||||
|
@ -9201,11 +9170,6 @@ xmldoc@^1.1.2:
|
|||
dependencies:
|
||||
sax "^1.2.1"
|
||||
|
||||
xmldom@~0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.5.0.tgz#193cb96b84aa3486127ea6272c4596354cb4962e"
|
||||
integrity sha512-Foaj5FXVzgn7xFzsKeNIde9g6aFBxTPi37iwsno8QvApmtg7KYrr+OPyRHcJF7dud2a5nGRBXK3n0dL62Gf7PA==
|
||||
|
||||
xtend@~4.0.1:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
|
||||
|
|
Loading…
Reference in New Issue