Browse Source

Fixed #336

pull/361/head
xmflsct 4 months ago
parent
commit
397c6a2f44
  1. 6
      index.js
  2. 8
      ios/Podfile
  3. 155
      ios/Podfile.lock
  4. 2
      ios/Podfile.properties.json
  5. 6
      ios/tooot.xcodeproj/project.pbxproj
  6. 18
      package.json
  7. 501
      patches/react-native-share-menu+5.0.5.patch
  8. 72
      patches/react-native-share-menu+6.0.0.patch
  9. 41
      src/Screens.tsx
  10. 39
      src/api/general.ts
  11. 38
      src/api/handleError.ts
  12. 35
      src/api/instance.ts
  13. 37
      src/api/tooot.ts
  14. 45
      src/components/AccountButton.tsx
  15. 1
      src/components/Timeline/Shared/HeaderDefault.android.tsx
  16. 1
      src/components/openLink.ts
  17. 1
      src/i18n/en/_all.ts
  18. 6
      src/i18n/en/screens/accountSelection.json
  19. 163
      src/screens/AccountSelection.tsx
  20. 1
      src/screens/Compose/Root/Footer/addAttachment.ts
  21. 36
      src/screens/Tabs/Me/Switch.tsx
  22. 1
      src/startup/sentry.ts
  23. 5
      src/utils/navigation/navigators.ts
  24. 318
      yarn.lock

6
index.js

@ -1,8 +1,8 @@
import { registerRootComponent } from 'expo';
import { registerRootComponent } from 'expo'
import App from '@root/App';
import App from '@root/App'
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
// It also ensures that whether you load the app in the Expo client or in a native build,
// the environment is set up appropriately
registerRootComponent(App);
registerRootComponent(App)

8
ios/Podfile

@ -20,9 +20,9 @@ target 'tooot' do
use_react_native!(
:path => config[:reactNativePath],
:production => production,
:hermes_enabled => podfile_properties['expo.jsEngine'] == 'hermes',
:hermes_enabled => podfile_properties['jsEngine'] == 'hermes',
:fabric_enabled => flags[:fabric_enabled],
:flipper_configuration => FlipperConfiguration.enabled,
:flipper_configuration => FlipperConfiguration.disabled,
# An absolute path to your application root.
:app_path => "#{Pod::Config.instance.installation_root}/.."
)
@ -50,7 +50,9 @@ end
target 'ShareExtension' do
use_react_native!(
:hermes_enabled => podfile_properties['expo.jsEngine'] == 'hermes'
:production => production,
:hermes_enabled => podfile_properties['jsEngine'] == 'hermes',
:flipper_configuration => FlipperConfiguration.disabled
)
pod 'RNShareMenu', :path => '../node_modules/react-native-share-menu'

155
ios/Podfile.lock

@ -1,13 +1,12 @@
PODS:
- ASN1Decoder (1.8.0)
- boost (1.76.0)
- CocoaAsyncSocket (7.6.5)
- DoubleConversion (1.1.6)
- EASClient (0.3.0):
- ExpoModulesCore
- EXApplication (4.2.2):
- ExpoModulesCore
- EXAV (12.0.3):
- EXAV (12.0.4):
- ExpoModulesCore
- React-runtimeexecutor
- ReactCommon
@ -33,7 +32,7 @@ PODS:
- EXJSONUtils
- EXNotifications (0.16.1):
- ExpoModulesCore
- Expo (46.0.2):
- Expo (46.0.6):
- ExpoModulesCore
- ExpoCrypto (11.0.0):
- ExpoModulesCore
@ -60,7 +59,7 @@ PODS:
- EXStoreReview (5.3.0):
- ExpoModulesCore
- EXStructuredHeaders (2.2.1)
- EXUpdates (0.14.3):
- EXUpdates (0.14.4):
- ASN1Decoder (~> 1.8)
- EASClient
- EXManifests
@ -116,67 +115,6 @@ PODS:
- GoogleUtilities/Environment (~> 7.7)
- GoogleUtilities/UserDefaults (~> 7.7)
- PromisesObjC (< 3.0, >= 1.2)
- Flipper (0.125.0):
- Flipper-Folly (~> 2.6)
- Flipper-RSocket (~> 1.4)
- Flipper-Boost-iOSX (1.76.0.1.11)
- Flipper-DoubleConversion (3.2.0.1)
- Flipper-Fmt (7.1.7)
- Flipper-Folly (2.6.10):
- Flipper-Boost-iOSX
- Flipper-DoubleConversion
- Flipper-Fmt (= 7.1.7)
- Flipper-Glog
- libevent (~> 2.1.12)
- OpenSSL-Universal (= 1.1.1100)
- Flipper-Glog (0.5.0.5)
- Flipper-PeerTalk (0.0.4)
- Flipper-RSocket (1.4.3):
- Flipper-Folly (~> 2.6)
- FlipperKit (0.125.0):
- FlipperKit/Core (= 0.125.0)
- FlipperKit/Core (0.125.0):
- Flipper (~> 0.125.0)
- FlipperKit/CppBridge
- FlipperKit/FBCxxFollyDynamicConvert
- FlipperKit/FBDefines
- FlipperKit/FKPortForwarding
- SocketRocket (~> 0.6.0)
- FlipperKit/CppBridge (0.125.0):
- Flipper (~> 0.125.0)
- FlipperKit/FBCxxFollyDynamicConvert (0.125.0):
- Flipper-Folly (~> 2.6)
- FlipperKit/FBDefines (0.125.0)
- FlipperKit/FKPortForwarding (0.125.0):
- CocoaAsyncSocket (~> 7.6)
- Flipper-PeerTalk (~> 0.0.4)
- FlipperKit/FlipperKitHighlightOverlay (0.125.0)
- FlipperKit/FlipperKitLayoutHelpers (0.125.0):
- FlipperKit/Core
- FlipperKit/FlipperKitHighlightOverlay
- FlipperKit/FlipperKitLayoutTextSearchable
- FlipperKit/FlipperKitLayoutIOSDescriptors (0.125.0):
- FlipperKit/Core
- FlipperKit/FlipperKitHighlightOverlay
- FlipperKit/FlipperKitLayoutHelpers
- YogaKit (~> 1.18)
- FlipperKit/FlipperKitLayoutPlugin (0.125.0):
- FlipperKit/Core
- FlipperKit/FlipperKitHighlightOverlay
- FlipperKit/FlipperKitLayoutHelpers
- FlipperKit/FlipperKitLayoutIOSDescriptors
- FlipperKit/FlipperKitLayoutTextSearchable
- YogaKit (~> 1.18)
- FlipperKit/FlipperKitLayoutTextSearchable (0.125.0)
- FlipperKit/FlipperKitNetworkPlugin (0.125.0):
- FlipperKit/Core
- FlipperKit/FlipperKitReactPlugin (0.125.0):
- FlipperKit/Core
- FlipperKit/FlipperKitUserDefaultsPlugin (0.125.0):
- FlipperKit/Core
- FlipperKit/SKIOSNetworkPlugin (0.125.0):
- FlipperKit/Core
- FlipperKit/FlipperKitNetworkPlugin
- fmt (6.2.1)
- glog (0.3.5)
- GoogleAppMeasurement (8.14.0):
@ -238,7 +176,6 @@ PODS:
- nanopb/encode (= 2.30908.0)
- nanopb/decode (2.30908.0)
- nanopb/encode (2.30908.0)
- OpenSSL-Universal (1.1.1100)
- PromisesObjC (2.1.1)
- RCT-Folly (2021.06.28.00-v2):
- boost
@ -590,7 +527,7 @@ PODS:
- React-logger (= 0.69.4)
- React-perflogger (= 0.69.4)
- ReactCommon/turbomodule/core (= 0.69.4)
- RNCAsyncStorage (1.17.8):
- RNCAsyncStorage (1.17.9):
- React-Core
- RNCClipboard (1.10.0):
- React-Core
@ -630,12 +567,12 @@ PODS:
- RNScreens (3.15.0):
- React-Core
- React-RCTImage
- RNSentry (4.2.2):
- RNSentry (4.2.3):
- React-Core
- Sentry (= 7.22.0)
- RNShareMenu (5.0.5):
- Sentry (= 7.23.0)
- RNShareMenu (6.0.0):
- React
- RNSVG (12.4.3):
- RNSVG (12.4.4):
- React-Core
- SDWebImage (5.13.2):
- SDWebImage/Core (= 5.13.2)
@ -643,14 +580,11 @@ PODS:
- SDWebImageWebPCoder (0.9.0):
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.13)
- Sentry (7.22.0):
- Sentry/Core (= 7.22.0)
- Sentry/Core (7.22.0)
- SocketRocket (0.6.0)
- Sentry (7.23.0):
- Sentry/Core (= 7.23.0)
- Sentry/Core (7.23.0)
- Swime (3.0.6)
- Yoga (1.14.0)
- YogaKit (1.18.1):
- Yoga (~> 1.14)
DEPENDENCIES:
- boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`)
@ -686,31 +620,9 @@ DEPENDENCIES:
- EXVideoThumbnails (from `../node_modules/expo-video-thumbnails/ios`)
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
- FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`)
- Flipper (= 0.125.0)
- Flipper-Boost-iOSX (= 1.76.0.1.11)
- Flipper-DoubleConversion (= 3.2.0.1)
- Flipper-Fmt (= 7.1.7)
- Flipper-Folly (= 2.6.10)
- Flipper-Glog (= 0.5.0.5)
- Flipper-PeerTalk (= 0.0.4)
- Flipper-RSocket (= 1.4.3)
- FlipperKit (= 0.125.0)
- FlipperKit/Core (= 0.125.0)
- FlipperKit/CppBridge (= 0.125.0)
- FlipperKit/FBCxxFollyDynamicConvert (= 0.125.0)
- FlipperKit/FBDefines (= 0.125.0)
- FlipperKit/FKPortForwarding (= 0.125.0)
- FlipperKit/FlipperKitHighlightOverlay (= 0.125.0)
- FlipperKit/FlipperKitLayoutPlugin (= 0.125.0)
- FlipperKit/FlipperKitLayoutTextSearchable (= 0.125.0)
- FlipperKit/FlipperKitNetworkPlugin (= 0.125.0)
- FlipperKit/FlipperKitReactPlugin (= 0.125.0)
- FlipperKit/FlipperKitUserDefaultsPlugin (= 0.125.0)
- FlipperKit/SKIOSNetworkPlugin (= 0.125.0)
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
- hermes-engine (from `../node_modules/react-native/sdks/hermes/hermes-engine.podspec`)
- libevent (~> 2.1.12)
- OpenSSL-Universal (= 1.1.1100)
- RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
@ -719,7 +631,6 @@ DEPENDENCIES:
- React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`)
- React-Codegen (from `build/generated/ios`)
- React-Core (from `../node_modules/react-native/`)
- React-Core/DevSupport (from `../node_modules/react-native/`)
- React-Core/RCTWebSocket (from `../node_modules/react-native/`)
- React-CoreModules (from `../node_modules/react-native/React/CoreModules`)
- React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`)
@ -765,21 +676,11 @@ DEPENDENCIES:
SPEC REPOS:
trunk:
- ASN1Decoder
- CocoaAsyncSocket
- Firebase
- FirebaseAnalytics
- FirebaseCore
- FirebaseCoreDiagnostics
- FirebaseInstallations
- Flipper
- Flipper-Boost-iOSX
- Flipper-DoubleConversion
- Flipper-Fmt
- Flipper-Folly
- Flipper-Glog
- Flipper-PeerTalk
- Flipper-RSocket
- FlipperKit
- fmt
- GoogleAppMeasurement
- GoogleDataTransport
@ -787,14 +688,11 @@ SPEC REPOS:
- libevent
- libwebp
- nanopb
- OpenSSL-Universal
- PromisesObjC
- SDWebImage
- SDWebImageWebPCoder
- Sentry
- SocketRocket
- Swime
- YogaKit
EXTERNAL SOURCES:
boost:
@ -967,11 +865,10 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
ASN1Decoder: 6110fdeacfdb41559b1481457a1645be716610aa
boost: a7c83b31436843459a1961bfd74b96033dc77234
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
EASClient: a2581835cf9b97d0defd5d630fc6eb1bf77045e7
EXApplication: e418d737a036e788510f2c4ad6c10a7d54d18586
EXAV: db5cb61ba842df32814ef5fd02872e1c1697e91b
EXAV: 596506c9bee54ad52f2f3b625cdaeb9d9f2dd6b7
EXConstants: 75c40827af38bd6bfcf69f880a5b45037eeff9c9
EXDevice: 7647ca9b1fd8b269dfd896a7643d659343358054
EXErrorRecovery: 74d71ee59f6814315457b09d68e86aa95cc7d05d
@ -982,7 +879,7 @@ SPEC CHECKSUMS:
EXJSONUtils: 2a74b8f40f1523cc3f92af99c91aa78201737a77
EXManifests: b38dc61303f5eede990b4c8ecbfac32f82160e65
EXNotifications: 9a2aa201deb19dfe1dbe0e370eeb2922de0d2422
Expo: a2d9d4d17b9c97beab797c54220b305708f60e87
Expo: efd244782651dd1a73c7bd977babe19ed80e3243
ExpoCrypto: e534314db0e1a17ae12b5140d529bd0c5efcbc6a
ExpoHaptics: efe9e68e9dfe0d15c183c0c70a25f3874124ab9e
ExpoKeepAwake: 0e8f18142e71bbf2c7f6aa66ebed249ba1420320
@ -995,7 +892,7 @@ SPEC CHECKSUMS:
EXSplashScreen: 31ab6df6d23e97e074d1330224741979943f1d82
EXStoreReview: cbb6b2202bb6f831cd3234d9d8b995cec0eb32f2
EXStructuredHeaders: 5d86829469399370a9fc7cb1e4391b09de87681d
EXUpdates: 0d639074a69862e121706c0d4203a700ecfcc22d
EXUpdates: 784c8c593f6649d0640e81cede66613703e3c267
EXUpdatesInterface: 2bbc11815dfa2ec3fc02e5534c7592c6b42b5327
EXVideoThumbnails: 486533e1a66c9859f9b9e3b2e1f9f0b275515b48
FBLazyVector: c71b8c429a8af2aff1013934a7152e9d9d0c937d
@ -1005,15 +902,6 @@ SPEC CHECKSUMS:
FirebaseCore: b84a44ee7ba999e0f9f76d198a9c7f60a797b848
FirebaseCoreDiagnostics: 92e07a649aeb66352b319d43bdd2ee3942af84cb
FirebaseInstallations: 40bd9054049b2eae9a2c38ef1c3dd213df3605cd
Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0
Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c
Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30
Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b
Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3
Flipper-Glog: 70c50ce58ddaf67dc35180db05f191692570f446
Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9
Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541
FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: 3d02b25ca00c2d456734d0bcff864cbc62f6ae1a
GoogleAppMeasurement: 71156240babd3cc6ced03e0d54816f01a880c730
@ -1023,7 +911,6 @@ SPEC CHECKSUMS:
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
libwebp: 60305b2e989864154bd9be3d772730f08fc6a59c
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
PromisesObjC: ab77feca74fa2823e7af4249b8326368e61014cb
RCT-Folly: b9d9fe1fc70114b751c076104e52f3b1b5e5a95a
RCTRequired: bd9d2ab0fda10171fcbcf9ba61a7df4dc15a28f4
@ -1063,23 +950,21 @@ SPEC CHECKSUMS:
React-RCTVibration: 9adb4a3cbb598d1bbd46a05256f445e4b8c70603
React-runtimeexecutor: 61ee22a8cdf8b6bb2a7fb7b4ba2cc763e5285196
ReactCommon: 8f67bd7e0a6afade0f20718f859dc8c2275f2e83
RNCAsyncStorage: 7cbd0d823dbb0e415d40a7e77fea2292483c8bdb
RNCAsyncStorage: b2489b49e38c85e10ed45a888d13a2a4c7b32ea1
RNCClipboard: f1736c75ab85b627a4d57587edb4b60999c4dd80
RNFastImage: 8e9b5b9e6df94d2e359c0a75a4745ad1311506fd
RNGestureHandler: bad495418bcbd3ab47017a38d93d290ebd406f50
RNReanimated: 2cf7451318bb9cc430abeec8d67693f9cf4e039c
RNScreens: 4a1af06327774490d97342c00aee0c2bafb497b7
RNSentry: f03937a2cf86c7029ba31fbbf5618c55d223cd62
RNShareMenu: c69282e50ac439737a86949a55c7b023b90027c8
RNSVG: f3b60aeeaa81960e2e0536c3a9eef50b667ef3a9
RNSentry: 6798624706227656d942849d593f89c8ca3bdde5
RNShareMenu: cb9dac548c8bf147d06f0bf07296ad51ea9f5fc3
RNSVG: ecd661f380a07ba690c9c5929c475a44f432d674
SDWebImage: 72f86271a6f3139cc7e4a89220946489d4b9a866
SDWebImageWebPCoder: 3dc350894112feab5375cfba9ce0986544a66a69
Sentry: 30b51086ca9aac23337880152e95538f7e177f7f
SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608
Sentry: a0d4563fa4ddacba31fdcc35daaa8573d87224d6
Swime: d7b2c277503b6cea317774aedc2dce05613f8b0b
Yoga: ff994563b2fd98c982ca58e8cd9db2cdaf4dda74
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
PODFILE CHECKSUM: a2f2cbb9af4b081ba2a1ca88de325713cfa64ec5
PODFILE CHECKSUM: 87f71ca2771d16ab3648db0569a7eb066517134c
COCOAPODS: 1.11.3

2
ios/Podfile.properties.json

@ -1,3 +1,3 @@
{
"expo.jsEngine": "hermes"
"jsEngine": "hermes"
}

6
ios/tooot.xcodeproj/project.pbxproj

@ -372,16 +372,10 @@
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-tooot/Pods-tooot-frameworks.sh",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-DoubleConversion/double-conversion.framework/double-conversion",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-Glog/glog.framework/glog",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL-Universal/OpenSSL.framework/OpenSSL",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/hermes.framework/hermes",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/double-conversion.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/glog.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework",
);
runOnlyForDeploymentPostprocessing = 0;

18
package.json

@ -34,7 +34,7 @@
"@formatjs/intl-relativetimeformat": "^11.0.3",
"@mattermost/react-native-paste-input": "^0.5.0",
"@neverdull-agency/expo-unlimited-secure-store": "^1.0.10",
"@react-native-async-storage/async-storage": "^1.17.8",
"@react-native-async-storage/async-storage": "^1.17.9",
"@react-native-clipboard/clipboard": "^1.10.0",
"@react-native-community/blur": "^4.2.0",
"@react-native-community/cameraroll": "^4.1.2",
@ -44,13 +44,13 @@
"@react-navigation/native": "^6.0.11",
"@react-navigation/native-stack": "^6.7.0",
"@react-navigation/stack": "^6.2.2",
"@reduxjs/toolkit": "^1.8.3",
"@reduxjs/toolkit": "^1.8.4",
"@sentry/react-native": "^4.2.2",
"@sharcoux/slider": "^6.0.3",
"axios": "^0.27.2",
"expo": "^46.0.2",
"expo": "^46.0.6",
"expo-auth-session": "^3.7.1",
"expo-av": "^12.0.3",
"expo-av": "^12.0.4",
"expo-constants": "^13.2.3",
"expo-crypto": "^11.0.0",
"expo-device": "^4.3.0",
@ -65,7 +65,7 @@
"expo-secure-store": "^11.3.0",
"expo-splash-screen": "^0.16.1",
"expo-store-review": "^5.3.0",
"expo-updates": "^0.14.3",
"expo-updates": "^0.14.4",
"expo-video-thumbnails": "^6.4.0",
"expo-web-browser": "^11.0.0",
"i18next": "^21.9.0",
@ -91,15 +91,15 @@
"react-native-reanimated": "^2.9.1",
"react-native-safe-area-context": "^4.3.1",
"react-native-screens": "^3.15.0",
"react-native-share-menu": "^5.0.5",
"react-native-svg": "^12.4.3",
"react-native-share-menu": "^6.0.0",
"react-native-svg": "^12.4.4",
"react-native-swipe-list-view": "^3.2.9",
"react-native-tab-view": "^3.1.1",
"react-query": "^3.39.2",
"react-redux": "^8.0.2",
"redux-persist": "^6.0.0",
"rn-placeholder": "^3.0.3",
"sentry-expo": "^5.0.1",
"sentry-expo": "^5.0.2",
"tslib": "^2.4.0",
"valid-url": "^1.0.9"
},
@ -108,7 +108,7 @@
"@babel/plugin-proposal-optional-chaining": "^7.18.9",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"@expo/config": "^7.0.0",
"@expo/config": "^7.0.1",
"@types/lodash": "^4.14.182",
"@types/react": "^18.0.17",
"@types/react-dom": "^18.0.6",

501
patches/react-native-share-menu+5.0.5.patch

@ -1,501 +0,0 @@
diff --git a/node_modules/react-native-share-menu/ios/Constants.swift b/node_modules/react-native-share-menu/ios/Constants.swift
index 2811008..08385b7 100644
--- a/node_modules/react-native-share-menu/ios/Constants.swift
+++ b/node_modules/react-native-share-menu/ios/Constants.swift
@@ -23,7 +23,7 @@ public let COULD_NOT_PARSE_IMG_ERROR = "Couldn't parse image"
public let COULD_NOT_SAVE_FILE_ERROR = "Couldn't save file on disk"
public let NO_EXTENSION_CONTEXT_ERROR = "No extension context attached"
public let NO_DELEGATE_ERROR = "No ReactShareViewDelegate attached"
-public let COULD_NOT_FIND_ITEM_ERROR = "Couldn't find item attached to this share"
+public let COULD_NOT_FIND_ITEMS_ERROR = "Couldn't find items attached to this share"
// MARK: Keys
diff --git a/node_modules/react-native-share-menu/ios/Modules/ShareMenu.swift b/node_modules/react-native-share-menu/ios/Modules/ShareMenu.swift
index 6c4922a..74badda 100644
--- a/node_modules/react-native-share-menu/ios/Modules/ShareMenu.swift
+++ b/node_modules/react-native-share-menu/ios/Modules/ShareMenu.swift
@@ -9,7 +9,7 @@ class ShareMenu: RCTEventEmitter {
}
}
- var sharedData: [String:String]?
+ var sharedData: [[String:String]?]?
static var initialShare: (UIApplication, URL, [UIApplication.OpenURLOptionsKey : Any])?
@@ -91,7 +91,7 @@ class ShareMenu: RCTEventEmitter {
let extraData = userDefaults.object(forKey: USER_DEFAULTS_EXTRA_DATA_KEY) as? [String:Any]
- if let data = userDefaults.object(forKey: USER_DEFAULTS_KEY) as? [String:String] {
+ if let data = userDefaults.object(forKey: USER_DEFAULTS_KEY) as? [[String:String]] {
sharedData = data
dispatchEvent(with: data, and: extraData)
userDefaults.removeObject(forKey: USER_DEFAULTS_KEY)
@@ -100,25 +100,22 @@ class ShareMenu: RCTEventEmitter {
@objc(getSharedText:)
func getSharedText(callback: RCTResponseSenderBlock) {
- guard var data: [String:Any] = sharedData else {
- callback([])
- return
- }
+ var data = [DATA_KEY: sharedData] as [String: Any]
if let bundleId = Bundle.main.bundleIdentifier, let userDefaults = UserDefaults(suiteName: "group.\(bundleId)") {
- data[EXTRA_DATA_KEY] = userDefaults.object(forKey: USER_DEFAULTS_EXTRA_DATA_KEY) as? [String:Any]
+ data[EXTRA_DATA_KEY] = userDefaults.object(forKey: USER_DEFAULTS_EXTRA_DATA_KEY) as? [String: Any]
} else {
print("Error: \(NO_APP_GROUP_ERROR)")
}
callback([data as Any])
- sharedData = nil
+ sharedData = []
}
- func dispatchEvent(with data: [String:String], and extraData: [String:Any]?) {
+ func dispatchEvent(with data: [[String:String]], and extraData: [String:Any]?) {
guard hasListeners else { return }
- var finalData = data as [String:Any]
+ var finalData = [DATA_KEY: data] as [String: Any]
if (extraData != nil) {
finalData[EXTRA_DATA_KEY] = extraData
}
diff --git a/node_modules/react-native-share-menu/ios/Modules/ShareMenuReactView.swift b/node_modules/react-native-share-menu/ios/Modules/ShareMenuReactView.swift
index 5d21773..0c7eaa7 100644
--- a/node_modules/react-native-share-menu/ios/Modules/ShareMenuReactView.swift
+++ b/node_modules/react-native-share-menu/ios/Modules/ShareMenuReactView.swift
@@ -3,8 +3,9 @@
// RNShareMenu
//
// Created by Gustavo Parreira on 28/07/2020.
-//
+// Modified by Veselin Stoyanov on 17/04/2021.
+import Foundation
import MobileCoreServices
@objc(ShareMenuReactView)
@@ -17,8 +18,6 @@ public class ShareMenuReactView: NSObject {
}
public static func attachViewDelegate(_ delegate: ReactShareViewDelegate!) {
- guard (ShareMenuReactView.viewDelegate == nil) else { return }
-
ShareMenuReactView.viewDelegate = delegate
}
@@ -65,12 +64,12 @@ public class ShareMenuReactView: NSObject {
let extensionContext = viewDelegate.loadExtensionContext()
- guard let item = extensionContext.inputItems.first as? NSExtensionItem else {
- print("Error: \(COULD_NOT_FIND_ITEM_ERROR)")
+ guard let items = extensionContext.inputItems as? [NSExtensionItem] else {
+ print("Error: \(COULD_NOT_FIND_ITEMS_ERROR)")
return
}
- viewDelegate.continueInApp(with: item, and: extraData)
+ viewDelegate.continueInApp(with: items, and: extraData)
}
@objc(data:reject:)
@@ -82,91 +81,96 @@ public class ShareMenuReactView: NSObject {
return
}
- extractDataFromContext(context: extensionContext) { (data, mimeType, error) in
+ extractDataFromContext(context: extensionContext) { (data, error) in
guard (error == nil) else {
reject("error", error?.description, nil)
return
}
- resolve([MIME_TYPE_KEY: mimeType, DATA_KEY: data])
+ resolve([DATA_KEY: data])
}
}
- func extractDataFromContext(context: NSExtensionContext, withCallback callback: @escaping (String?, String?, NSException?) -> Void) {
- let item:NSExtensionItem! = context.inputItems.first as? NSExtensionItem
- let attachments:[AnyObject]! = item.attachments
-
- var urlProvider:NSItemProvider! = nil
- var imageProvider:NSItemProvider! = nil
- var textProvider:NSItemProvider! = nil
- var dataProvider:NSItemProvider! = nil
-
- for provider in attachments {
- if provider.hasItemConformingToTypeIdentifier(kUTTypeURL as String) {
- urlProvider = provider as? NSItemProvider
- break
- } else if provider.hasItemConformingToTypeIdentifier(kUTTypeText as String) {
- textProvider = provider as? NSItemProvider
- break
- } else if provider.hasItemConformingToTypeIdentifier(kUTTypeImage as String) {
- imageProvider = provider as? NSItemProvider
- break
- } else if provider.hasItemConformingToTypeIdentifier(kUTTypeData as String) {
- dataProvider = provider as? NSItemProvider
- break
- }
- }
+ func extractDataFromContext(context: NSExtensionContext, withCallback callback: @escaping ([Any]?, NSException?) -> Void) {
+ DispatchQueue.global().async {
+ let semaphore = DispatchSemaphore(value: 0)
+ let items:[NSExtensionItem]! = context.inputItems as? [NSExtensionItem]
+ var results: [[String: String]] = []
- if (urlProvider != nil) {
- urlProvider.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil) { (item, error) in
- let url: URL! = item as? URL
+ for item in items {
+ guard let attachments = item.attachments else {
+ callback(nil, NSException(name: NSExceptionName(rawValue: "Error"), reason:"couldn't find attachments", userInfo:nil))
+ return
+ }
- callback(url.absoluteString, "text/plain", nil)
- }
- } else if (imageProvider != nil) {
- imageProvider.loadItem(forTypeIdentifier: kUTTypeImage as String, options: nil) { (item, error) in
- let imageUrl: URL! = item as? URL
+ for provider in attachments {
+ if provider.hasItemConformingToTypeIdentifier(kUTTypeURL as String) {
+ provider.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil) { (item, error) in
+ let url: URL! = item as? URL
- if (imageUrl != nil) {
- if let imageData = try? Data(contentsOf: imageUrl) {
- callback(imageUrl.absoluteString, self.extractMimeType(from: imageUrl), nil)
- }
- } else {
- let image: UIImage! = item as? UIImage
+ results.append([DATA_KEY: url.absoluteString, MIME_TYPE_KEY: "text/plain"])
- if (image != nil) {
- let imageData: Data! = image.pngData();
+ semaphore.signal()
+ }
+ semaphore.wait()
+ } else if provider.hasItemConformingToTypeIdentifier(kUTTypeText as String) {
+ provider.loadItem(forTypeIdentifier: kUTTypeText as String, options: nil) { (item, error) in
+ let text:String! = item as? String
+
+ results.append([DATA_KEY: text, MIME_TYPE_KEY: "text/plain"])
- // Creating temporary URL for image data (UIImage)
- guard let imageURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("TemporaryScreenshot.png") else {
- return
+ semaphore.signal()
+ }
+ semaphore.wait()
+ } else if provider.hasItemConformingToTypeIdentifier(kUTTypeImage as String) {
+ provider.loadItem(forTypeIdentifier: kUTTypeImage as String, options: nil) { (item, error) in
+ let imageUrl: URL! = item as? URL
+
+ if (imageUrl != nil) {
+ if let imageData = try? Data(contentsOf: imageUrl) {
+ results.append([DATA_KEY: imageUrl.absoluteString, MIME_TYPE_KEY: self.extractMimeType(from: imageUrl)])
+ }
+ } else {
+ let image: UIImage! = item as? UIImage
+
+ if (image != nil) {
+ let imageData: Data! = image.pngData();
+
+ // Creating temporary URL for image data (UIImage)
+ guard let imageURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("TemporaryScreenshot.png") else {
+ return
+ }
+
+ do {
+ // Writing the image to the URL
+ try imageData.write(to: imageURL)
+
+ results.append([DATA_KEY: imageUrl.absoluteString, MIME_TYPE_KEY: imageURL.extractMimeType()])
+ } catch {
+ callback(nil, NSException(name: NSExceptionName(rawValue: "Error"), reason:"Can't load image", userInfo:nil))
+ }
+ }
+ }
+
+ semaphore.signal()
}
+ semaphore.wait()
+ } else if provider.hasItemConformingToTypeIdentifier(kUTTypeData as String) {
+ provider.loadItem(forTypeIdentifier: kUTTypeData as String, options: nil) { (item, error) in
+ let url: URL! = item as? URL
- do {
- // Writing the image to the URL
- try imageData.write(to: imageURL)
+ results.append([DATA_KEY: url.absoluteString, MIME_TYPE_KEY: self.extractMimeType(from: url)])
- callback(imageURL.absoluteString, imageURL.extractMimeType(), nil)
- } catch {
- callback(nil, nil, NSException(name: NSExceptionName(rawValue: "Error"), reason:"Can't load image", userInfo:nil))
+ semaphore.signal()
}
+ semaphore.wait()
+ } else {
+ callback(nil, NSException(name: NSExceptionName(rawValue: "Error"), reason:"couldn't find provider", userInfo:nil))
}
}
}
- } else if (textProvider != nil) {
- textProvider.loadItem(forTypeIdentifier: kUTTypeText as String, options: nil) { (item, error) in
- let text:String! = item as? String
- callback(text, "text/plain", nil)
- }
- } else if (dataProvider != nil) {
- dataProvider.loadItem(forTypeIdentifier: kUTTypeData as String, options: nil) { (item, error) in
- let url: URL! = item as? URL
-
- callback(url.absoluteString, self.extractMimeType(from: url), nil)
- }
- } else {
- callback(nil, nil, NSException(name: NSExceptionName(rawValue: "Error"), reason:"couldn't find provider", userInfo:nil))
+ callback(results, nil)
}
}
diff --git a/node_modules/react-native-share-menu/ios/ReactShareViewController.swift b/node_modules/react-native-share-menu/ios/ReactShareViewController.swift
index 0189ef6..f42bce6 100644
--- a/node_modules/react-native-share-menu/ios/ReactShareViewController.swift
+++ b/node_modules/react-native-share-menu/ios/ReactShareViewController.swift
@@ -62,7 +62,7 @@ class ReactShareViewController: ShareViewController, RCTBridgeDelegate, ReactSha
self.openHostApp()
}
- func continueInApp(with item: NSExtensionItem, and extraData: [String:Any]?) {
- handlePost(item, extraData: extraData)
+ func continueInApp(with items: [NSExtensionItem], and extraData: [String:Any]?) {
+ handlePost(items, extraData: extraData)
}
}
diff --git a/node_modules/react-native-share-menu/ios/ReactShareViewDelegate.swift b/node_modules/react-native-share-menu/ios/ReactShareViewDelegate.swift
index 0aa4c58..ad0812c 100644
--- a/node_modules/react-native-share-menu/ios/ReactShareViewDelegate.swift
+++ b/node_modules/react-native-share-menu/ios/ReactShareViewDelegate.swift
@@ -10,5 +10,5 @@ public protocol ReactShareViewDelegate {
func openApp()
- func continueInApp(with item: NSExtensionItem, and extraData: [String:Any]?)
+ func continueInApp(with items: [NSExtensionItem], and extraData: [String:Any]?)
}
diff --git a/node_modules/react-native-share-menu/ios/ShareViewController.swift b/node_modules/react-native-share-menu/ios/ShareViewController.swift
index 7faf6e4..f02bde5 100644
--- a/node_modules/react-native-share-menu/ios/ShareViewController.swift
+++ b/node_modules/react-native-share-menu/ios/ShareViewController.swift
@@ -6,15 +6,18 @@
//
// Created by Gustavo Parreira on 26/07/2020.
//
+// Modified by Veselin Stoyanov on 17/04/2021.
+import Foundation
import MobileCoreServices
import UIKit
import Social
import RNShareMenu
-class ShareViewController: SLComposeServiceViewController {
+class ShareViewController: UIViewController {
var hostAppId: String?
var hostAppUrlScheme: String?
+ var sharedItems: [Any] = []
override func viewDidLoad() {
super.viewDidLoad()
@@ -30,46 +33,64 @@ class ShareViewController: SLComposeServiceViewController {
} else {
print("Error: \(NO_INFO_PLIST_URL_SCHEME_ERROR)")
}
- }
- override func isContentValid() -> Bool {
- // Do validation of contentText and/or NSExtensionContext attachments here
- return true
+ guard let items = extensionContext?.inputItems as? [NSExtensionItem] else {
+ cancelRequest()
+ return
}
- override func didSelectPost() {
- // This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.
- guard let item = extensionContext?.inputItems.first as? NSExtensionItem else {
- cancelRequest()
+ handlePost(items)
+ }
+
+ override func viewDidAppear(_ animated: Bool) {
+ super.viewDidAppear(animated)
+
+ completeRequest()
+ }
+
+ func handlePost(_ items: [NSExtensionItem], extraData: [String:Any]? = nil) {
+ DispatchQueue.global().async {
+ guard let hostAppId = self.hostAppId else {
+ self.exit(withError: NO_INFO_PLIST_INDENTIFIER_ERROR)
+ return
+ }
+ guard let userDefaults = UserDefaults(suiteName: "group.\(hostAppId)") else {
+ self.exit(withError: NO_APP_GROUP_ERROR)
return
}
- handlePost(item)
- }
+ if let data = extraData {
+ self.storeExtraData(data)
+ } else {
+ self.removeExtraData()
+ }
- override func configurationItems() -> [Any]! {
- // To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here.
- return []
- }
+ let semaphore = DispatchSemaphore(value: 0)
- func handlePost(_ item: NSExtensionItem, extraData: [String:Any]? = nil) {
- guard let provider = item.attachments?.first else {
- cancelRequest()
- return
- }
+ for item in items {
+ guard let attachments = item.attachments else {
+ self.cancelRequest()
+ return
+ }
- if let data = extraData {
- storeExtraData(data)
- } else {
- removeExtraData()
- }
+ for provider in attachments {
+ if provider.isText {
+ self.storeText(withProvider: provider, semaphore)
+ } else if provider.isURL {
+ self.storeUrl(withProvider: provider, semaphore)
+ } else {
+ self.storeFile(withProvider: provider, semaphore)
+ }
- if provider.isText {
- storeText(withProvider: provider)
- } else if provider.isURL {
- storeUrl(withProvider: provider)
- } else {
- storeFile(withProvider: provider)
+ semaphore.wait()
+ }
+ }
+
+ userDefaults.set(self.sharedItems,
+ forKey: USER_DEFAULTS_KEY)
+ userDefaults.synchronize()
+
+ self.openHostApp()
}
}
@@ -99,7 +120,7 @@ class ShareViewController: SLComposeServiceViewController {
userDefaults.synchronize()
}
- func storeText(withProvider provider: NSItemProvider) {
+ func storeText(withProvider provider: NSItemProvider, _ semaphore: DispatchSemaphore) {
provider.loadItem(forTypeIdentifier: kUTTypeText as String, options: nil) { (data, error) in
guard (error == nil) else {
self.exit(withError: error.debugDescription)
@@ -109,24 +130,13 @@ class ShareViewController: SLComposeServiceViewController {
self.exit(withError: COULD_NOT_FIND_STRING_ERROR)
return
}
- guard let hostAppId = self.hostAppId else {
- self.exit(withError: NO_INFO_PLIST_INDENTIFIER_ERROR)
- return
- }
- guard let userDefaults = UserDefaults(suiteName: "group.\(hostAppId)") else {
- self.exit(withError: NO_APP_GROUP_ERROR)
- return
- }
-
- userDefaults.set([DATA_KEY: text, MIME_TYPE_KEY: "text/plain"],
- forKey: USER_DEFAULTS_KEY)
- userDefaults.synchronize()
- self.openHostApp()
+ self.sharedItems.append([DATA_KEY: text, MIME_TYPE_KEY: "text/plain"])
+ semaphore.signal()
}
}
- func storeUrl(withProvider provider: NSItemProvider) {
+ func storeUrl(withProvider provider: NSItemProvider, _ semaphore: DispatchSemaphore) {
provider.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil) { (data, error) in
guard (error == nil) else {
self.exit(withError: error.debugDescription)
@@ -136,24 +146,13 @@ class ShareViewController: SLComposeServiceViewController {
self.exit(withError: COULD_NOT_FIND_URL_ERROR)
return
}
- guard let hostAppId = self.hostAppId else {
- self.exit(withError: NO_INFO_PLIST_INDENTIFIER_ERROR)
- return
- }
- guard let userDefaults = UserDefaults(suiteName: "group.\(hostAppId)") else {
- self.exit(withError: NO_APP_GROUP_ERROR)
- return
- }
-
- userDefaults.set([DATA_KEY: url.absoluteString, MIME_TYPE_KEY: "text/plain"],
- forKey: USER_DEFAULTS_KEY)
- userDefaults.synchronize()
- self.openHostApp()
+ self.sharedItems.append([DATA_KEY: url.absoluteString, MIME_TYPE_KEY: "text/plain"])
+ semaphore.signal()
}
}
- func storeFile(withProvider provider: NSItemProvider) {
+ func storeFile(withProvider provider: NSItemProvider, _ semaphore: DispatchSemaphore) {
provider.loadItem(forTypeIdentifier: kUTTypeData as String, options: nil) { (data, error) in
guard (error == nil) else {
self.exit(withError: error.debugDescription)
@@ -167,10 +166,6 @@ class ShareViewController: SLComposeServiceViewController {
self.exit(withError: NO_INFO_PLIST_INDENTIFIER_ERROR)
return
}
- guard let userDefaults = UserDefaults(suiteName: "group.\(hostAppId)") else {
- self.exit(withError: NO_APP_GROUP_ERROR)
- return
- }
guard let groupFileManagerContainer = FileManager.default
.containerURL(forSecurityApplicationGroupIdentifier: "group.\(hostAppId)")
else {
@@ -189,11 +184,8 @@ class ShareViewController: SLComposeServiceViewController {
return
}
- userDefaults.set([DATA_KEY: filePath.absoluteString, MIME_TYPE_KEY: mimeType],
- forKey: USER_DEFAULTS_KEY)
- userDefaults.synchronize()
-
- self.openHostApp()
+ self.sharedItems.append([DATA_KEY: filePath.absoluteString, MIME_TYPE_KEY: mimeType])
+ semaphore.signal()
}
}

72
patches/react-native-share-menu+6.0.0.patch

@ -0,0 +1,72 @@
diff --git a/node_modules/react-native-share-menu/ios/ReactShareViewController.swift b/node_modules/react-native-share-menu/ios/ReactShareViewController.swift
index f42bce6..ee36062 100644
--- a/node_modules/react-native-share-menu/ios/ReactShareViewController.swift
+++ b/node_modules/react-native-share-menu/ios/ReactShareViewController.swift
@@ -13,7 +13,7 @@ class ReactShareViewController: ShareViewController, RCTBridgeDelegate, ReactSha
func sourceURL(for bridge: RCTBridge!) -> URL! {
#if DEBUG
return RCTBundleURLProvider.sharedSettings()?
- .jsBundleURL(forBundleRoot: "index.share", fallbackResource: nil)
+ .jsBundleURL(forBundleRoot: "index.share")
#else
return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
#endif
diff --git a/node_modules/react-native-share-menu/ios/ShareViewController.swift b/node_modules/react-native-share-menu/ios/ShareViewController.swift
index 12d8c92..64aa72b 100644
--- a/node_modules/react-native-share-menu/ios/ShareViewController.swift
+++ b/node_modules/react-native-share-menu/ios/ShareViewController.swift
@@ -19,8 +19,8 @@ class ShareViewController: SLComposeServiceViewController {
var hostAppUrlScheme: String?
var sharedItems: [Any] = []
- override func viewDidLoad() {
- super.viewDidLoad()
+ override func viewWillAppear(_ animated: Bool) {
+ super.viewWillAppear(animated)
if let hostAppId = Bundle.main.object(forInfoDictionaryKey: HOST_APP_IDENTIFIER_INFO_PLIST_KEY) as? String {
self.hostAppId = hostAppId
@@ -33,6 +33,13 @@ class ShareViewController: SLComposeServiceViewController {
} else {
print("Error: \(NO_INFO_PLIST_URL_SCHEME_ERROR)")
}
+
+ guard let items = extensionContext?.inputItems as? [NSExtensionItem] else {
+ cancelRequest()
+ return
+ }
+
+ handlePost(items)
}
override func isContentValid() -> Bool {
@@ -40,16 +47,6 @@ class ShareViewController: SLComposeServiceViewController {
return true
}
- override func didSelectPost() {
- // This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.
- guard let items = extensionContext?.inputItems as? [NSExtensionItem] else {
- cancelRequest()
- return
- }
-
- handlePost(items)
- }
-
override func configurationItems() -> [Any]! {
// To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here.
return []
@@ -238,11 +235,10 @@ class ShareViewController: SLComposeServiceViewController {
func completeRequest() {
// Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.
- extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
+ extensionContext!.completeRequest(returningItems: nil, completionHandler: nil)
}
func cancelRequest() {
extensionContext!.cancelRequest(withError: NSError())
}
-
}

41
src/Screens.tsx

@ -1,9 +1,11 @@
import analytics from '@components/analytics'
import { HeaderLeft } from '@components/Header'
import { displayMessage, Message } from '@components/Message'
import CustomText from '@components/Text'
import navigationRef from '@helpers/navigationRef'
import { NavigationContainer } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import ScreenAccountSelection from '@screens/AccountSelection'
import ScreenActions from '@screens/Actions'
import ScreenAnnouncements from '@screens/Announcements'
import ScreenCompose from '@screens/Compose'
@ -170,7 +172,6 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
}
| { data: string | string[]; mimeType: string }
) => {
console.log('item', item)
if (instanceActive < 0) {
return
}
@ -239,12 +240,6 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
if (!item.mimeType) {
return
}
let tempData: string[]
if (!Array.isArray(item.data)) {
tempData = [item.data]
} else {
tempData = item.data
}
for (const d of item.data) {
filterMedia({ uri: d, mime: item.mimeType })
}
@ -254,11 +249,20 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
if (!text && !media.length) {
return
} else {
console.log('media', media)
navigationRef.navigate('Screen-Compose', { type: 'share', text, media })
if (instances.length > 1) {
navigationRef.navigate('Screen-AccountSelection', {
share: { text, media }
})
} else {
navigationRef.navigate('Screen-Compose', {
type: 'share',
text,
media
})
}
}
},
[instanceActive]
[instances.length]
)
useEffect(() => {
ShareMenu.getInitialShare(handleShare)
@ -333,6 +337,23 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
animation: 'fade'
}}
/>
<Stack.Screen
name='Screen-AccountSelection'
component={ScreenAccountSelection}
options={({ navigation }) => ({
title: t('screenAccountSelection:heading'),
headerShadowVisible: false,
presentation: 'modal',
gestureEnabled: false,
headerLeft: () => (
<HeaderLeft
type='text'
content={t('common:buttons.cancel')}
onPress={() => navigation.goBack()}
/>
)
})}
/>
</Stack.Navigator>
<Message />

39
src/api/general.ts

@ -1,8 +1,6 @@
import axios from 'axios'
import chalk from 'chalk'
import Constants from 'expo-constants'
const ctx = new chalk.Instance({ level: 3 })
import handleError, { ctx } from './handleError'
export type Params = {
method: 'get' | 'post' | 'put' | 'delete'
@ -57,40 +55,7 @@ const apiGeneral = async <T = unknown>({
body: response.data
})
})
.catch(error => {
if (error?.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.error(
ctx.bold(' API general '),
ctx.bold('response'),
error.response.status,
error.response.data.error
)
return Promise.reject({
status: error?.response.status,
message: error?.response.data.error
})
} else if (error?.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.error(
ctx.bold(' API general '),
ctx.bold('request'),
error.request
)
return Promise.reject()
} else {
console.error(
ctx.bold(' API general '),
ctx.bold('internal'),
error?.message,
url
)
return Promise.reject()
}
})
.catch(handleError)
}
export default apiGeneral

38
src/api/handleError.ts

@ -0,0 +1,38 @@
import chalk from 'chalk'
export const ctx = new chalk.Instance({ level: 3 })
const handleError = (error: any) => {
if (error?.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.error(
ctx.bold(' API instance '),
ctx.bold('response'),
error.response.status,
error?.response.data?.error || error?.response.message || 'Unknown error'
)
return Promise.reject({
status: error?.response.status,
message:
error?.response.data?.error ||
error?.response.message ||
'Unknown error'
})
} else if (error?.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.error(ctx.bold(' API instance '), ctx.bold('request'), error)
return Promise.reject()
} else {
console.error(
ctx.bold(' API instance '),
ctx.bold('internal'),
error?.message
)
return Promise.reject()
}
}
export default handleError

35
src/api/instance.ts

@ -1,10 +1,8 @@
import { RootState } from '@root/store'
import axios, { AxiosRequestConfig } from 'axios'
import chalk from 'chalk'
import Constants from 'expo-constants'
import li from 'li'
const ctx = new chalk.Instance({ level: 3 })
import handleError, { ctx } from './handleError'
export type Params = {
method: 'get' | 'post' | 'put' | 'delete' | 'patch'
@ -99,36 +97,7 @@ const apiInstance = async <T = unknown>({
links: { prev, next }
})
})
.catch(error => {
if (error?.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.error(
ctx.bold(' API instance '),
ctx.bold('response'),
error.response.status,
error.response.data.error
)
return Promise.reject({
status: error?.response.status,
message: error?.response.data.error
})
} else if (error?.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.error(ctx.bold(' API instance '), ctx.bold('request'), error)
return Promise.reject()
} else {
console.error(
ctx.bold(' API instance '),
ctx.bold('internal'),
error?.message,
url
)
return Promise.reject()
}
})
.catch(handleError)
}
export default apiInstance

37
src/api/tooot.ts

@ -1,10 +1,8 @@
import { mapEnvironment } from '@utils/checkEnvironment'
import axios from 'axios'
import chalk from 'chalk'
import Constants from 'expo-constants'
import * as Sentry from 'sentry-expo'
const ctx = new chalk.Instance({ level: 3 })
import handleError, { ctx } from './handleError'
export type Params = {
method: 'get' | 'post' | 'put' | 'delete'
@ -75,38 +73,7 @@ const apiTooot = async <T = unknown>({
Sentry.Native.captureException(error)
}
if (error?.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.error(
ctx.bold(' API tooot '),
ctx.bold('response'),
error.response.status,
error.response.data.error
)
return Promise.reject({
status: error?.response.status,
message: error?.response.data.error
})
} else if (error?.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.error(
ctx.bold(' API tooot '),
ctx.bold('request'),
error.request
)
return Promise.reject()
} else {
console.error(
ctx.bold(' API tooot '),
ctx.bold('internal'),
error?.message,
url
)
return Promise.reject()
}
return handleError(error)
})
}

45
src/components/AccountButton.tsx

@ -0,0 +1,45 @@
import { useNavigation } from '@react-navigation/native'
import initQuery from '@utils/initQuery'
import { InstanceLatest } from '@utils/migrations/instances/migration'
import { StyleConstants } from '@utils/styles/constants'
import React from 'react'
import Button from './Button'
import haptics from './haptics'
interface Props {
instance: InstanceLatest
selected?: boolean
additionalActions?: () => void
}
const AccountButton: React.FC<Props> = ({
instance,
selected = false,
additionalActions
}) => {
const navigation = useNavigation()
return (
<Button
type='text'
selected={selected}
style={{
marginBottom: StyleConstants.Spacing.M,
marginRight: StyleConstants.Spacing.M
}}
content={`@${instance.account.acct}@${instance.uri}${
selected ? ' ✓' : ''
}`}
onPress={() => {
haptics('Light')
initQuery({ instance, prefetch: { enabled: true } })
navigation.goBack()
if (additionalActions) {
additionalActions()
}
}}
/>
)
}
export default AccountButton

1
src/components/Timeline/Shared/HeaderDefault.android.tsx

@ -92,7 +92,6 @@ const TimelineHeaderDefault = ({ queryKey, status, highlighted }: Props) => {
dropdownMenuMode
actions={actions}
onPress={({ nativeEvent: { index } }) => {
console.log('index', index)
for (const on of [
shareOnPress,
statusOnPress,

1
src/components/openLink.ts

@ -72,7 +72,6 @@ const openLink = async (url: string, navigation?: any) => {
// If an account can be found
const matchedAccount = url.match(matcherAccount)
console.log(matchedAccount)
if (matchedAccount) {
// If the link in current instance
const instanceUrl = getInstanceUrl(store.getState())

1
src/i18n/en/_all.ts

@ -2,6 +2,7 @@ export default {
common: require('./common'),
screens: require('./screens'),
screenAccountSelection: require('./screens/accountSelection.json'),
screenActions: require('./screens/actions'),
screenAnnouncements: require('./screens/announcements'),
screenCompose: require('./screens/compose'),

6
src/i18n/en/screens/accountSelection.json

@ -0,0 +1,6 @@
{
"heading": "Share to ...",
"content": {
"select_account": "Select account"
}
}

163
src/screens/AccountSelection.tsx

@ -0,0 +1,163 @@
import AccountButton from '@components/AccountButton'
import CustomText from '@components/Text'
import navigationRef from '@helpers/navigationRef'
import { RootStackScreenProps } from '@utils/navigation/navigators'
import { getInstances } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import * as VideoThumbnails from 'expo-video-thumbnails'
import React, { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { FlatList, Image, ScrollView, View } from 'react-native'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import { useSelector } from 'react-redux'
const Share = ({
text,
media
}: {
text?: string | undefined
media?:
| {
uri: string
mime: string
}[]
| undefined
}) => {
const { colors } = useTheme()
const [images, setImages] = useState<string[]>([])
useEffect(() => {
const prepareThumbs = async (media: { uri: string; mime: string }[]) => {
const thumbs: string[] = []
for (const m of media) {
if (m.mime.startsWith('image/')) {
thumbs.push(m.uri)
} else if (m.mime.startsWith('video/')) {
const { uri } = await VideoThumbnails.getThumbnailAsync(m.uri)
thumbs.push(uri)
}
}
setImages(thumbs)
}
if (media) {
prepareThumbs(media)
}
}, [])
if (text) {
return (
<CustomText
fontSize='S'
style={{
color: colors.primaryDefault,
padding: StyleConstants.Spacing.M,
borderWidth: 1,
borderColor: colors.shimmerHighlight,
borderRadius: 8
}}
children={text}
/>
)
}
if (media) {
return (
<View
style={{
padding: StyleConstants.Spacing.M,
borderWidth: 1,
borderColor: colors.shimmerHighlight,
borderRadius: 8
}}
>
<FlatList
horizontal
data={images}
renderItem={({ item }) => (
<Image source={{ uri: item }} style={{ width: 88, height: 88 }} />
)}
ItemSeparatorComponent={() => (
<View style={{ width: StyleConstants.Spacing.S }} />
)}
/>
</View>
)
}
return null
}
// Only needed when data incoming into the app when there are multiple accounts
const ScreenAccountSelection = ({
route: {
params: { share }
}
}: RootStackScreenProps<'Screen-AccountSelection'>) => {
const { colors } = useTheme()
const { t } = useTranslation('screenAccountSelection')
const instances = useSelector(getInstances, () => true)
return (
<SafeAreaProvider>
<ScrollView
style={{ marginBottom: StyleConstants.Spacing.L * 2 }}
keyboardShouldPersistTaps='always'
>
<View
style={{
marginHorizontal: StyleConstants.Spacing.Global.PagePadding
}}
>
{share ? <Share {...share} /> : null}
<CustomText
fontStyle='M'
fontWeight='Bold'
style={{
textAlign: 'center',
marginTop: StyleConstants.Spacing.L,
marginBottom: StyleConstants.Spacing.S,
color: colors.primaryDefault
}}
>
{t('content.select_account')}
</CustomText>
<View
style={{
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
marginTop: StyleConstants.Spacing.M
}}
>
{instances.length
? instances
.slice()
.sort((a, b) =>
`${a.uri}${a.account.acct}`.localeCompare(
`${b.uri}${b.account.acct}`
)
)
.map((instance, index) => {
return (
<AccountButton
key={index}
instance={instance}
additionalActions={() => {
navigationRef.navigate('Screen-Compose', {
type: 'share',
...share
})
}}
/>
)
})
: null}
</View>
</View>
</ScrollView>
</SafeAreaProvider>
)
}
export default ScreenAccountSelection

1
src/screens/Compose/Root/Footer/addAttachment.ts

@ -42,7 +42,6 @@ export const uploadAttachment = async ({
case 'video':
VideoThumbnails.getThumbnailAsync(media.uri)
.then(({ uri, width, height }) => {
console.log('new', uri, width, height)
composeDispatch({
type: 'attachment/upload/start',
payload: {

36
src/screens/Tabs/Me/Switch.tsx

@ -1,11 +1,6 @@
import analytics from '@components/analytics'
import Button from '@components/Button'
import haptics from '@components/haptics'
import AccountButton from '@components/AccountButton'
import ComponentInstance from '@components/Instance'
import CustomText from '@components/Text'
import { useNavigation } from '@react-navigation/native'
import initQuery from '@utils/initQuery'
import { InstanceLatest } from '@utils/migrations/instances/migration'
import { getInstanceActive, getInstances } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
@ -15,35 +10,6 @@ import { KeyboardAvoidingView, Platform, StyleSheet, View } from 'react-native'
import { ScrollView } from 'react-native-gesture-handler'
import { useSelector } from 'react-redux'
interface Props {
instance: InstanceLatest
selected?: boolean
}
const AccountButton: React.FC<Props> = ({ instance, selected = false }) => {
const navigation = useNavigation()
return (
<Button
type='text'
selected={selected}
style={{
marginBottom: StyleConstants.Spacing.M,
marginRight: StyleConstants.Spacing.M
}}
content={`@${instance.account.acct}@${instance.uri}${
selected ? ' ✓' : ''
}`}
onPress={() => {
haptics('Light')
analytics('switch_existing_press')
initQuery({ instance, prefetch: { enabled: true } })
navigation.goBack()
}}
/>
)
}
const TabMeSwitch: React.FC = () => {
const { t } = useTranslation('screenTabs')
const { colors } = useTheme()

1
src/startup/sentry.ts

@ -6,7 +6,6 @@ const sentry = () => {
Sentry.init({
dsn: 'https://53348b60ff844d52886e90251b3a5f41@o917354.ingest.sentry.io/6410576',
enableInExpoDevelopment: false,
// debug: !isRelease,
autoSessionTracking: true
})
}