From 477e5f4ecfaa0007aeed90b51274c78a730c1a9e Mon Sep 17 00:00:00 2001 From: hailey Date: Thu, 12 Jun 2025 10:46:22 -0700 Subject: new arch (#8295) Co-authored-by: Samuel Newman Co-authored-by: Charlotte Som Co-authored-by: Hailey --- ...mattermost+react-native-paste-input+0.7.1.patch | 157 ---- ...t+react-native-paste-input+0.8.1.patch.disabled | 264 ++++++ patches/@sentry+react-native+6.10.0.patch | 13 - patches/@sentry+react-native+6.14.0.patch | 13 + patches/expo-media-library+17.1.6.patch | 19 - patches/expo-media-library+17.1.7.patch | 19 + patches/expo-modules-core+2.3.12.patch | 15 - patches/expo-modules-core+2.3.12.patch.md | 3 - patches/expo-modules-core+2.4.0.patch | 15 + patches/expo-modules-core+2.4.0.patch.md | 3 + patches/expo-notifications+0.31.1.patch | 992 --------------------- patches/expo-notifications+0.31.1.patch.md | 14 - patches/expo-notifications+0.31.3.patch | 992 +++++++++++++++++++++ patches/expo-notifications+0.31.3.patch.md | 14 + patches/expo-updates+0.28.12.patch | 26 - patches/expo-updates+0.28.12.patch.md | 7 - patches/expo-updates+0.28.14.patch | 26 + patches/expo-updates+0.28.14.patch.md | 7 + patches/react-native+0.79.2.patch | 119 --- patches/react-native+0.79.2.patch.md | 13 - patches/react-native+0.79.3.patch | 136 +++ patches/react-native+0.79.3.patch.md | 13 + patches/react-native-svg+15.11.2.patch | 57 -- patches/react-native-svg+15.12.0.patch | 57 ++ 24 files changed, 1559 insertions(+), 1435 deletions(-) delete mode 100644 patches/@mattermost+react-native-paste-input+0.7.1.patch create mode 100644 patches/@mattermost+react-native-paste-input+0.8.1.patch.disabled delete mode 100644 patches/@sentry+react-native+6.10.0.patch create mode 100644 patches/@sentry+react-native+6.14.0.patch delete mode 100644 patches/expo-media-library+17.1.6.patch create mode 100644 patches/expo-media-library+17.1.7.patch delete mode 100644 patches/expo-modules-core+2.3.12.patch delete mode 100644 patches/expo-modules-core+2.3.12.patch.md create mode 100644 patches/expo-modules-core+2.4.0.patch create mode 100644 patches/expo-modules-core+2.4.0.patch.md delete mode 100644 patches/expo-notifications+0.31.1.patch delete mode 100644 patches/expo-notifications+0.31.1.patch.md create mode 100644 patches/expo-notifications+0.31.3.patch create mode 100644 patches/expo-notifications+0.31.3.patch.md delete mode 100644 patches/expo-updates+0.28.12.patch delete mode 100644 patches/expo-updates+0.28.12.patch.md create mode 100644 patches/expo-updates+0.28.14.patch create mode 100644 patches/expo-updates+0.28.14.patch.md delete mode 100644 patches/react-native+0.79.2.patch delete mode 100644 patches/react-native+0.79.2.patch.md create mode 100644 patches/react-native+0.79.3.patch create mode 100644 patches/react-native+0.79.3.patch.md delete mode 100644 patches/react-native-svg+15.11.2.patch create mode 100644 patches/react-native-svg+15.12.0.patch (limited to 'patches') diff --git a/patches/@mattermost+react-native-paste-input+0.7.1.patch b/patches/@mattermost+react-native-paste-input+0.7.1.patch deleted file mode 100644 index f25b6a776..000000000 --- a/patches/@mattermost+react-native-paste-input+0.7.1.patch +++ /dev/null @@ -1,157 +0,0 @@ -diff --git a/node_modules/@mattermost/react-native-paste-input/ios/PasteInputView.m b/node_modules/@mattermost/react-native-paste-input/ios/PasteInputView.m -index e916023..5049c33 100644 ---- a/node_modules/@mattermost/react-native-paste-input/ios/PasteInputView.m -+++ b/node_modules/@mattermost/react-native-paste-input/ios/PasteInputView.m -@@ -4,6 +4,7 @@ - // - // Created by Elias Nahum on 04-11-20. - // Copyright © 2020 Facebook. All rights reserved. -+// Updated to remove parent’s default text view - // - - #import "PasteInputView.h" -@@ -12,49 +13,78 @@ - - @implementation PasteInputView - { -- PasteInputTextView *_backedTextInputView; -+ // We'll store the custom text view in this ivar -+ PasteInputTextView *_customBackedTextView; - } - - - (instancetype)initWithBridge:(RCTBridge *)bridge - { -+ // Must call the super’s designated initializer - if (self = [super initWithBridge:bridge]) { -- _backedTextInputView = [[PasteInputTextView alloc] initWithFrame:self.bounds]; -- _backedTextInputView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; -- _backedTextInputView.textInputDelegate = self; -+ // 1. The parent (RCTMultilineTextInputView) has already created -+ // its own _backedTextInputView = [RCTUITextView new] in super init. -+ // We can remove that subview: - -- [self addSubview:_backedTextInputView]; -- } -+ id parentInputView = super.backedTextInputView; -+ if ([parentInputView isKindOfClass:[UIView class]]) { -+ UIView *parentSubview = (UIView *)parentInputView; -+ if (parentSubview.superview == self) { -+ [parentSubview removeFromSuperview]; -+ } -+ } - -+ // 2. Now create our custom PasteInputTextView -+ _customBackedTextView = [[PasteInputTextView alloc] initWithFrame:self.bounds]; -+ _customBackedTextView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; -+ _customBackedTextView.textInputDelegate = self; -+ -+ // Optional: disable inline predictions for iOS 17+ -+ if (@available(iOS 17.0, *)) { -+ _customBackedTextView.inlinePredictionType = UITextInlinePredictionTypeNo; -+ } -+ -+ // 3. Add your custom text view as the only subview -+ [self addSubview:_customBackedTextView]; -+ } - return self; - } - -+/** -+ * Override the parent's accessor so that anywhere in RN that calls -+ * `self.backedTextInputView` will get the custom PasteInputTextView. -+ */ - - (id)backedTextInputView - { -- return _backedTextInputView; -+ return _customBackedTextView; - } - --- (void)setDisableCopyPaste:(BOOL)disableCopyPaste { -- _backedTextInputView.disableCopyPaste = disableCopyPaste; -+#pragma mark - Setters for React Props -+ -+- (void)setDisableCopyPaste:(BOOL)disableCopyPaste -+{ -+ _customBackedTextView.disableCopyPaste = disableCopyPaste; - } - --- (void)setOnPaste:(RCTDirectEventBlock)onPaste { -- _backedTextInputView.onPaste = onPaste; -+- (void)setOnPaste:(RCTDirectEventBlock)onPaste -+{ -+ _customBackedTextView.onPaste = onPaste; - } - --- (void)setSmartPunctuation:(NSString *)smartPunctuation { -- if ([smartPunctuation isEqualToString:@"enable"]) { -- [_backedTextInputView setSmartDashesType:UITextSmartDashesTypeYes]; -- [_backedTextInputView setSmartQuotesType:UITextSmartQuotesTypeYes]; -- [_backedTextInputView setSmartInsertDeleteType:UITextSmartInsertDeleteTypeYes]; -- } else if ([smartPunctuation isEqualToString:@"disable"]) { -- [_backedTextInputView setSmartDashesType:UITextSmartDashesTypeNo]; -- [_backedTextInputView setSmartQuotesType:UITextSmartQuotesTypeNo]; -- [_backedTextInputView setSmartInsertDeleteType:UITextSmartInsertDeleteTypeNo]; -- } else { -- [_backedTextInputView setSmartDashesType:UITextSmartDashesTypeDefault]; -- [_backedTextInputView setSmartQuotesType:UITextSmartQuotesTypeDefault]; -- [_backedTextInputView setSmartInsertDeleteType:UITextSmartInsertDeleteTypeDefault]; -- } -+- (void)setSmartPunctuation:(NSString *)smartPunctuation -+{ -+ if ([smartPunctuation isEqualToString:@"enable"]) { -+ [_customBackedTextView setSmartDashesType:UITextSmartDashesTypeYes]; -+ [_customBackedTextView setSmartQuotesType:UITextSmartQuotesTypeYes]; -+ [_customBackedTextView setSmartInsertDeleteType:UITextSmartInsertDeleteTypeYes]; -+ } else if ([smartPunctuation isEqualToString:@"disable"]) { -+ [_customBackedTextView setSmartDashesType:UITextSmartDashesTypeNo]; -+ [_customBackedTextView setSmartQuotesType:UITextSmartQuotesTypeNo]; -+ [_customBackedTextView setSmartInsertDeleteType:UITextSmartInsertDeleteTypeNo]; -+ } else { -+ [_customBackedTextView setSmartDashesType:UITextSmartDashesTypeDefault]; -+ [_customBackedTextView setSmartQuotesType:UITextSmartQuotesTypeDefault]; -+ [_customBackedTextView setSmartInsertDeleteType:UITextSmartInsertDeleteTypeDefault]; -+ } - } - - #pragma mark - UIScrollViewDelegate -@@ -62,7 +92,6 @@ - - (void)scrollViewDidScroll:(UIScrollView *)scrollView - { - RCTDirectEventBlock onScroll = self.onScroll; -- - if (onScroll) { - CGPoint contentOffset = scrollView.contentOffset; - CGSize contentSize = scrollView.contentSize; -@@ -71,22 +100,22 @@ - - onScroll(@{ - @"contentOffset": @{ -- @"x": @(contentOffset.x), -- @"y": @(contentOffset.y) -+ @"x": @(contentOffset.x), -+ @"y": @(contentOffset.y) - }, - @"contentInset": @{ -- @"top": @(contentInset.top), -- @"left": @(contentInset.left), -- @"bottom": @(contentInset.bottom), -- @"right": @(contentInset.right) -+ @"top": @(contentInset.top), -+ @"left": @(contentInset.left), -+ @"bottom": @(contentInset.bottom), -+ @"right": @(contentInset.right) - }, - @"contentSize": @{ -- @"width": @(contentSize.width), -- @"height": @(contentSize.height) -+ @"width": @(contentSize.width), -+ @"height": @(contentSize.height) - }, - @"layoutMeasurement": @{ -- @"width": @(size.width), -- @"height": @(size.height) -+ @"width": @(size.width), -+ @"height": @(size.height) - }, - @"zoomScale": @(scrollView.zoomScale ?: 1), - }); diff --git a/patches/@mattermost+react-native-paste-input+0.8.1.patch.disabled b/patches/@mattermost+react-native-paste-input+0.8.1.patch.disabled new file mode 100644 index 000000000..a7f146143 --- /dev/null +++ b/patches/@mattermost+react-native-paste-input+0.8.1.patch.disabled @@ -0,0 +1,264 @@ +diff --git a/node_modules/@mattermost/react-native-paste-input/ios/PasteInputView.m b/node_modules/@mattermost/react-native-paste-input/ios/PasteInputView.m +index e916023..5049c33 100644 +--- a/node_modules/@mattermost/react-native-paste-input/ios/PasteInputView.m ++++ b/node_modules/@mattermost/react-native-paste-input/ios/PasteInputView.m +@@ -4,6 +4,7 @@ + // + // Created by Elias Nahum on 04-11-20. + // Copyright © 2020 Facebook. All rights reserved. ++// Updated to remove parent’s default text view + // + + #import "PasteInputView.h" +@@ -12,49 +13,78 @@ + + @implementation PasteInputView + { +- PasteInputTextView *_backedTextInputView; ++ // We'll store the custom text view in this ivar ++ PasteInputTextView *_customBackedTextView; + } + + - (instancetype)initWithBridge:(RCTBridge *)bridge + { ++ // Must call the super’s designated initializer + if (self = [super initWithBridge:bridge]) { +- _backedTextInputView = [[PasteInputTextView alloc] initWithFrame:self.bounds]; +- _backedTextInputView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; +- _backedTextInputView.textInputDelegate = self; ++ // 1. The parent (RCTMultilineTextInputView) has already created ++ // its own _backedTextInputView = [RCTUITextView new] in super init. ++ // We can remove that subview: + +- [self addSubview:_backedTextInputView]; +- } ++ id parentInputView = super.backedTextInputView; ++ if ([parentInputView isKindOfClass:[UIView class]]) { ++ UIView *parentSubview = (UIView *)parentInputView; ++ if (parentSubview.superview == self) { ++ [parentSubview removeFromSuperview]; ++ } ++ } + ++ // 2. Now create our custom PasteInputTextView ++ _customBackedTextView = [[PasteInputTextView alloc] initWithFrame:self.bounds]; ++ _customBackedTextView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; ++ _customBackedTextView.textInputDelegate = self; ++ ++ // Optional: disable inline predictions for iOS 17+ ++ if (@available(iOS 17.0, *)) { ++ _customBackedTextView.inlinePredictionType = UITextInlinePredictionTypeNo; ++ } ++ ++ // 3. Add your custom text view as the only subview ++ [self addSubview:_customBackedTextView]; ++ } + return self; + } + ++/** ++ * Override the parent's accessor so that anywhere in RN that calls ++ * `self.backedTextInputView` will get the custom PasteInputTextView. ++ */ + - (id)backedTextInputView + { +- return _backedTextInputView; ++ return _customBackedTextView; + } + +-- (void)setDisableCopyPaste:(BOOL)disableCopyPaste { +- _backedTextInputView.disableCopyPaste = disableCopyPaste; ++#pragma mark - Setters for React Props ++ ++- (void)setDisableCopyPaste:(BOOL)disableCopyPaste ++{ ++ _customBackedTextView.disableCopyPaste = disableCopyPaste; + } + +-- (void)setOnPaste:(RCTDirectEventBlock)onPaste { +- _backedTextInputView.onPaste = onPaste; ++- (void)setOnPaste:(RCTDirectEventBlock)onPaste ++{ ++ _customBackedTextView.onPaste = onPaste; + } + +-- (void)setSmartPunctuation:(NSString *)smartPunctuation { +- if ([smartPunctuation isEqualToString:@"enable"]) { +- [_backedTextInputView setSmartDashesType:UITextSmartDashesTypeYes]; +- [_backedTextInputView setSmartQuotesType:UITextSmartQuotesTypeYes]; +- [_backedTextInputView setSmartInsertDeleteType:UITextSmartInsertDeleteTypeYes]; +- } else if ([smartPunctuation isEqualToString:@"disable"]) { +- [_backedTextInputView setSmartDashesType:UITextSmartDashesTypeNo]; +- [_backedTextInputView setSmartQuotesType:UITextSmartQuotesTypeNo]; +- [_backedTextInputView setSmartInsertDeleteType:UITextSmartInsertDeleteTypeNo]; +- } else { +- [_backedTextInputView setSmartDashesType:UITextSmartDashesTypeDefault]; +- [_backedTextInputView setSmartQuotesType:UITextSmartQuotesTypeDefault]; +- [_backedTextInputView setSmartInsertDeleteType:UITextSmartInsertDeleteTypeDefault]; +- } ++- (void)setSmartPunctuation:(NSString *)smartPunctuation ++{ ++ if ([smartPunctuation isEqualToString:@"enable"]) { ++ [_customBackedTextView setSmartDashesType:UITextSmartDashesTypeYes]; ++ [_customBackedTextView setSmartQuotesType:UITextSmartQuotesTypeYes]; ++ [_customBackedTextView setSmartInsertDeleteType:UITextSmartInsertDeleteTypeYes]; ++ } else if ([smartPunctuation isEqualToString:@"disable"]) { ++ [_customBackedTextView setSmartDashesType:UITextSmartDashesTypeNo]; ++ [_customBackedTextView setSmartQuotesType:UITextSmartQuotesTypeNo]; ++ [_customBackedTextView setSmartInsertDeleteType:UITextSmartInsertDeleteTypeNo]; ++ } else { ++ [_customBackedTextView setSmartDashesType:UITextSmartDashesTypeDefault]; ++ [_customBackedTextView setSmartQuotesType:UITextSmartQuotesTypeDefault]; ++ [_customBackedTextView setSmartInsertDeleteType:UITextSmartInsertDeleteTypeDefault]; ++ } + } + + #pragma mark - UIScrollViewDelegate +@@ -62,7 +92,6 @@ - (void)setSmartPunctuation:(NSString *)smartPunctuation { + - (void)scrollViewDidScroll:(UIScrollView *)scrollView + { + RCTDirectEventBlock onScroll = self.onScroll; +- + if (onScroll) { + CGPoint contentOffset = scrollView.contentOffset; + CGSize contentSize = scrollView.contentSize; +@@ -71,22 +100,22 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView + + onScroll(@{ + @"contentOffset": @{ +- @"x": @(contentOffset.x), +- @"y": @(contentOffset.y) ++ @"x": @(contentOffset.x), ++ @"y": @(contentOffset.y) + }, + @"contentInset": @{ +- @"top": @(contentInset.top), +- @"left": @(contentInset.left), +- @"bottom": @(contentInset.bottom), +- @"right": @(contentInset.right) ++ @"top": @(contentInset.top), ++ @"left": @(contentInset.left), ++ @"bottom": @(contentInset.bottom), ++ @"right": @(contentInset.right) + }, + @"contentSize": @{ +- @"width": @(contentSize.width), +- @"height": @(contentSize.height) ++ @"width": @(contentSize.width), ++ @"height": @(contentSize.height) + }, + @"layoutMeasurement": @{ +- @"width": @(size.width), +- @"height": @(size.height) ++ @"width": @(size.width), ++ @"height": @(size.height) + }, + @"zoomScale": @(scrollView.zoomScale ?: 1), + }); +diff --git a/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInput.mm b/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInput.mm +index dd50053..2ed7017 100644 +--- a/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInput.mm ++++ b/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInput.mm +@@ -122,8 +122,8 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared & + const auto &newTextInputProps = static_cast(*props); + + // Traits: +- if (newTextInputProps.traits.multiline != oldTextInputProps.traits.multiline) { +- [self _setMultiline:newTextInputProps.traits.multiline]; ++ if (newTextInputProps.multiline != oldTextInputProps.multiline) { ++ [self _setMultiline:newTextInputProps.multiline]; + } + + if (newTextInputProps.traits.autocapitalizationType != oldTextInputProps.traits.autocapitalizationType) { +@@ -421,7 +421,7 @@ - (void)textInputDidChangeSelection + return; + } + const auto &props = static_cast(*_props); +- if (props.traits.multiline && ![_lastStringStateWasUpdatedWith isEqual:_backedTextInputView.attributedText]) { ++ if (props.multiline && ![_lastStringStateWasUpdatedWith isEqual:_backedTextInputView.attributedText]) { + [self textInputDidChange]; + _ignoreNextTextInputCall = YES; + } +@@ -708,11 +708,11 @@ - (BOOL)_textOf:(NSAttributedString *)newText equals:(NSAttributedString *)oldTe + - (SubmitBehavior)getSubmitBehavior + { + const auto &props = static_cast(*_props); +- const SubmitBehavior submitBehaviorDefaultable = props.traits.submitBehavior; ++ const SubmitBehavior submitBehaviorDefaultable = props.submitBehavior; + + // We should always have a non-default `submitBehavior`, but in case we don't, set it based on multiline. + if (submitBehaviorDefaultable == SubmitBehavior::Default) { +- return props.traits.multiline ? SubmitBehavior::Newline : SubmitBehavior::BlurAndSubmit; ++ return props.multiline ? SubmitBehavior::Newline : SubmitBehavior::BlurAndSubmit; + } + + return submitBehaviorDefaultable; +diff --git a/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/Props.cpp b/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/Props.cpp +index 29e094f..7ef519a 100644 +--- a/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/Props.cpp ++++ b/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/Props.cpp +@@ -22,8 +22,7 @@ PasteTextInputProps::PasteTextInputProps( + const PropsParserContext &context, + const PasteTextInputProps &sourceProps, + const RawProps& rawProps) +- : ViewProps(context, sourceProps, rawProps), +- BaseTextProps(context, sourceProps, rawProps), ++ : BaseTextInputProps(context, sourceProps, rawProps), + traits(convertRawProp(context, rawProps, sourceProps.traits, {})), + smartPunctuation(convertRawProp(context, rawProps, "smartPunctuation", sourceProps.smartPunctuation, {})), + disableCopyPaste(convertRawProp(context, rawProps, "disableCopyPaste", sourceProps.disableCopyPaste, {false})), +@@ -133,7 +132,7 @@ TextAttributes PasteTextInputProps::getEffectiveTextAttributes(Float fontSizeMul + ParagraphAttributes PasteTextInputProps::getEffectiveParagraphAttributes() const { + auto result = paragraphAttributes; + +- if (!traits.multiline) { ++ if (!multiline) { + result.maximumNumberOfLines = 1; + } + +diff --git a/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/Props.h b/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/Props.h +index 723d00c..31cfe66 100644 +--- a/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/Props.h ++++ b/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/Props.h +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -25,7 +26,7 @@ + + namespace facebook::react { + +-class PasteTextInputProps final : public ViewProps, public BaseTextProps { ++class PasteTextInputProps final : public BaseTextInputProps { + public: + PasteTextInputProps() = default; + PasteTextInputProps(const PropsParserContext& context, const PasteTextInputProps& sourceProps, const RawProps& rawProps); +diff --git a/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/ShadowNodes.cpp b/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/ShadowNodes.cpp +index 31e07e3..7f0ebfb 100644 +--- a/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/ShadowNodes.cpp ++++ b/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/ShadowNodes.cpp +@@ -91,20 +91,11 @@ void PasteTextInputShadowNode::updateStateIfNeeded( + const auto& state = getStateData(); + + react_native_assert(textLayoutManager_); +- react_native_assert( +- (!state.layoutManager || state.layoutManager == textLayoutManager_) && +- "`StateData` refers to a different `TextLayoutManager`"); +- +- if (state.reactTreeAttributedString == reactTreeAttributedString && +- state.layoutManager == textLayoutManager_) { +- return; +- } + + auto newState = TextInputState{}; + newState.attributedStringBox = AttributedStringBox{reactTreeAttributedString}; + newState.paragraphAttributes = getConcreteProps().paragraphAttributes; + newState.reactTreeAttributedString = reactTreeAttributedString; +- newState.layoutManager = textLayoutManager_; + newState.mostRecentEventCount = getConcreteProps().mostRecentEventCount; + setStateData(std::move(newState)); + } diff --git a/patches/@sentry+react-native+6.10.0.patch b/patches/@sentry+react-native+6.10.0.patch deleted file mode 100644 index 2291c598c..000000000 --- a/patches/@sentry+react-native+6.10.0.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/node_modules/@sentry/react-native/scripts/expo-upload-sourcemaps.js b/node_modules/@sentry/react-native/scripts/expo-upload-sourcemaps.js -index c282ade..8777755 100755 ---- a/node_modules/@sentry/react-native/scripts/expo-upload-sourcemaps.js -+++ b/node_modules/@sentry/react-native/scripts/expo-upload-sourcemaps.js -@@ -215,7 +215,7 @@ for (const [assetGroupName, assets] of Object.entries(groupedAssets)) { - - const isHermes = assets.find(asset => asset.endsWith('.hbc')); - const windowsCallback = process.platform === "win32" ? 'node ' : ''; -- execSync(`${windowsCallback}${sentryCliBin} sourcemaps upload ${isHermes ? '--debug-id-reference' : ''} ${assets.join(' ')}`, { -+ execSync(`${windowsCallback}${sentryCliBin} sourcemaps upload ${isHermes ? '--debug-id-reference' : ''} ${assets.join(' ')} --dist ${process.env.SENTRY_DIST}`, { - env: { - ...process.env, - [SENTRY_PROJECT]: sentryProject, diff --git a/patches/@sentry+react-native+6.14.0.patch b/patches/@sentry+react-native+6.14.0.patch new file mode 100644 index 000000000..2291c598c --- /dev/null +++ b/patches/@sentry+react-native+6.14.0.patch @@ -0,0 +1,13 @@ +diff --git a/node_modules/@sentry/react-native/scripts/expo-upload-sourcemaps.js b/node_modules/@sentry/react-native/scripts/expo-upload-sourcemaps.js +index c282ade..8777755 100755 +--- a/node_modules/@sentry/react-native/scripts/expo-upload-sourcemaps.js ++++ b/node_modules/@sentry/react-native/scripts/expo-upload-sourcemaps.js +@@ -215,7 +215,7 @@ for (const [assetGroupName, assets] of Object.entries(groupedAssets)) { + + const isHermes = assets.find(asset => asset.endsWith('.hbc')); + const windowsCallback = process.platform === "win32" ? 'node ' : ''; +- execSync(`${windowsCallback}${sentryCliBin} sourcemaps upload ${isHermes ? '--debug-id-reference' : ''} ${assets.join(' ')}`, { ++ execSync(`${windowsCallback}${sentryCliBin} sourcemaps upload ${isHermes ? '--debug-id-reference' : ''} ${assets.join(' ')} --dist ${process.env.SENTRY_DIST}`, { + env: { + ...process.env, + [SENTRY_PROJECT]: sentryProject, diff --git a/patches/expo-media-library+17.1.6.patch b/patches/expo-media-library+17.1.6.patch deleted file mode 100644 index 4fa853ec3..000000000 --- a/patches/expo-media-library+17.1.6.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff --git a/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt b/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt -index f1255e8..a9b49e5 100644 ---- a/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt -+++ b/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt -@@ -112,11 +112,9 @@ class MediaLibraryModule : Module() { - } - - AsyncFunction("createAssetAsync") { localUri: String, albumId: String?, promise: Promise -> -- throwUnlessPermissionsGranted { -- withModuleScope(promise) { -- CreateAssetWithAlbumId(context, localUri, promise, true, albumId) -- .execute() -- } -+ withModuleScope(promise) { -+ CreateAssetWithAlbumId(context, localUri, promise, true, albumId) -+ .execute() - } - } - diff --git a/patches/expo-media-library+17.1.7.patch b/patches/expo-media-library+17.1.7.patch new file mode 100644 index 000000000..4fa853ec3 --- /dev/null +++ b/patches/expo-media-library+17.1.7.patch @@ -0,0 +1,19 @@ +diff --git a/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt b/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt +index f1255e8..a9b49e5 100644 +--- a/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt ++++ b/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt +@@ -112,11 +112,9 @@ class MediaLibraryModule : Module() { + } + + AsyncFunction("createAssetAsync") { localUri: String, albumId: String?, promise: Promise -> +- throwUnlessPermissionsGranted { +- withModuleScope(promise) { +- CreateAssetWithAlbumId(context, localUri, promise, true, albumId) +- .execute() +- } ++ withModuleScope(promise) { ++ CreateAssetWithAlbumId(context, localUri, promise, true, albumId) ++ .execute() + } + } + diff --git a/patches/expo-modules-core+2.3.12.patch b/patches/expo-modules-core+2.3.12.patch deleted file mode 100644 index f3d9bfd14..000000000 --- a/patches/expo-modules-core+2.3.12.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/node_modules/expo-modules-core/android/src/main/java/expo/modules/kotlin/devtools/ExpoNetworkInspectOkHttpInterceptors.kt b/node_modules/expo-modules-core/android/src/main/java/expo/modules/kotlin/devtools/ExpoNetworkInspectOkHttpInterceptors.kt -index 47c4d15..afe138d 100644 ---- a/node_modules/expo-modules-core/android/src/main/java/expo/modules/kotlin/devtools/ExpoNetworkInspectOkHttpInterceptors.kt -+++ b/node_modules/expo-modules-core/android/src/main/java/expo/modules/kotlin/devtools/ExpoNetworkInspectOkHttpInterceptors.kt -@@ -125,6 +125,10 @@ internal fun peekResponseBody( - } - - internal fun shouldParseBody(response: Response): Boolean { -+ if (response.request.url.encodedPath == "/bitdrift_public.protobuf.client.v1.ApiService/Mux") { -+ return false -+ } -+ - // Check for Content-Type - val skipContentTypes = listOf( - "text/event-stream", // Server Sent Events diff --git a/patches/expo-modules-core+2.3.12.patch.md b/patches/expo-modules-core+2.3.12.patch.md deleted file mode 100644 index a71324c19..000000000 --- a/patches/expo-modules-core+2.3.12.patch.md +++ /dev/null @@ -1,3 +0,0 @@ -## expo-modules-core Patch - -This patch fixes an issue where bitdrift's API stream gets blocked by the Expo interceptor used to power the devtools diff --git a/patches/expo-modules-core+2.4.0.patch b/patches/expo-modules-core+2.4.0.patch new file mode 100644 index 000000000..f3d9bfd14 --- /dev/null +++ b/patches/expo-modules-core+2.4.0.patch @@ -0,0 +1,15 @@ +diff --git a/node_modules/expo-modules-core/android/src/main/java/expo/modules/kotlin/devtools/ExpoNetworkInspectOkHttpInterceptors.kt b/node_modules/expo-modules-core/android/src/main/java/expo/modules/kotlin/devtools/ExpoNetworkInspectOkHttpInterceptors.kt +index 47c4d15..afe138d 100644 +--- a/node_modules/expo-modules-core/android/src/main/java/expo/modules/kotlin/devtools/ExpoNetworkInspectOkHttpInterceptors.kt ++++ b/node_modules/expo-modules-core/android/src/main/java/expo/modules/kotlin/devtools/ExpoNetworkInspectOkHttpInterceptors.kt +@@ -125,6 +125,10 @@ internal fun peekResponseBody( + } + + internal fun shouldParseBody(response: Response): Boolean { ++ if (response.request.url.encodedPath == "/bitdrift_public.protobuf.client.v1.ApiService/Mux") { ++ return false ++ } ++ + // Check for Content-Type + val skipContentTypes = listOf( + "text/event-stream", // Server Sent Events diff --git a/patches/expo-modules-core+2.4.0.patch.md b/patches/expo-modules-core+2.4.0.patch.md new file mode 100644 index 000000000..a71324c19 --- /dev/null +++ b/patches/expo-modules-core+2.4.0.patch.md @@ -0,0 +1,3 @@ +## expo-modules-core Patch + +This patch fixes an issue where bitdrift's API stream gets blocked by the Expo interceptor used to power the devtools diff --git a/patches/expo-notifications+0.31.1.patch b/patches/expo-notifications+0.31.1.patch deleted file mode 100644 index 56e639a26..000000000 --- a/patches/expo-notifications+0.31.1.patch +++ /dev/null @@ -1,992 +0,0 @@ -diff --git a/node_modules/expo-notifications/android/.gradle/8.10/checksums/checksums.lock b/node_modules/expo-notifications/android/.gradle/8.10/checksums/checksums.lock -new file mode 100644 -index 0000000..883ef6a -Binary files /dev/null and b/node_modules/expo-notifications/android/.gradle/8.10/checksums/checksums.lock differ -diff --git a/node_modules/expo-notifications/android/.gradle/8.10/dependencies-accessors/gc.properties b/node_modules/expo-notifications/android/.gradle/8.10/dependencies-accessors/gc.properties -new file mode 100644 -index 0000000..e69de29 -diff --git a/node_modules/expo-notifications/android/.gradle/8.10/fileChanges/last-build.bin b/node_modules/expo-notifications/android/.gradle/8.10/fileChanges/last-build.bin -new file mode 100644 -index 0000000..f76dd23 -Binary files /dev/null and b/node_modules/expo-notifications/android/.gradle/8.10/fileChanges/last-build.bin differ -diff --git a/node_modules/expo-notifications/android/.gradle/8.10/fileHashes/fileHashes.lock b/node_modules/expo-notifications/android/.gradle/8.10/fileHashes/fileHashes.lock -new file mode 100644 -index 0000000..774caf7 -Binary files /dev/null and b/node_modules/expo-notifications/android/.gradle/8.10/fileHashes/fileHashes.lock differ -diff --git a/node_modules/expo-notifications/android/.gradle/8.10/gc.properties b/node_modules/expo-notifications/android/.gradle/8.10/gc.properties -new file mode 100644 -index 0000000..e69de29 -diff --git a/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock -new file mode 100644 -index 0000000..a3c1514 -Binary files /dev/null and b/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ -diff --git a/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/cache.properties b/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/cache.properties -new file mode 100644 -index 0000000..0e5b4da ---- /dev/null -+++ b/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/cache.properties -@@ -0,0 +1,2 @@ -+#Thu Apr 24 20:44:36 PDT 2025 -+gradle.version=8.10 -diff --git a/node_modules/expo-notifications/android/.gradle/config.properties b/node_modules/expo-notifications/android/.gradle/config.properties -new file mode 100644 -index 0000000..0bd71c6 ---- /dev/null -+++ b/node_modules/expo-notifications/android/.gradle/config.properties -@@ -0,0 +1,2 @@ -+#Thu Apr 24 20:44:32 PDT 2025 -+java.home=/Applications/Android Studio.app/Contents/jbr/Contents/Home -diff --git a/node_modules/expo-notifications/android/.gradle/vcs-1/gc.properties b/node_modules/expo-notifications/android/.gradle/vcs-1/gc.properties -new file mode 100644 -index 0000000..e69de29 -diff --git a/node_modules/expo-notifications/android/.idea/.gitignore b/node_modules/expo-notifications/android/.idea/.gitignore -new file mode 100644 -index 0000000..26d3352 ---- /dev/null -+++ b/node_modules/expo-notifications/android/.idea/.gitignore -@@ -0,0 +1,3 @@ -+# Default ignored files -+/shelf/ -+/workspace.xml -diff --git a/node_modules/expo-notifications/android/.idea/AndroidProjectSystem.xml b/node_modules/expo-notifications/android/.idea/AndroidProjectSystem.xml -new file mode 100644 -index 0000000..4a53bee ---- /dev/null -+++ b/node_modules/expo-notifications/android/.idea/AndroidProjectSystem.xml -@@ -0,0 +1,6 @@ -+ -+ -+ -+ -+ -\ No newline at end of file -diff --git a/node_modules/expo-notifications/android/.idea/caches/deviceStreaming.xml b/node_modules/expo-notifications/android/.idea/caches/deviceStreaming.xml -new file mode 100644 -index 0000000..9e9ba09 ---- /dev/null -+++ b/node_modules/expo-notifications/android/.idea/caches/deviceStreaming.xml -@@ -0,0 +1,607 @@ -+ -+ -+ -+ -+ -+ -\ No newline at end of file -diff --git a/node_modules/expo-notifications/android/.idea/gradle.xml b/node_modules/expo-notifications/android/.idea/gradle.xml -new file mode 100644 -index 0000000..b838237 ---- /dev/null -+++ b/node_modules/expo-notifications/android/.idea/gradle.xml -@@ -0,0 +1,12 @@ -+ -+ -+ -+ -+ -+ -\ No newline at end of file -diff --git a/node_modules/expo-notifications/android/.idea/migrations.xml b/node_modules/expo-notifications/android/.idea/migrations.xml -new file mode 100644 -index 0000000..f8051a6 ---- /dev/null -+++ b/node_modules/expo-notifications/android/.idea/migrations.xml -@@ -0,0 +1,10 @@ -+ -+ -+ -+ -+ -+ -\ No newline at end of file -diff --git a/node_modules/expo-notifications/android/.idea/misc.xml b/node_modules/expo-notifications/android/.idea/misc.xml -new file mode 100644 -index 0000000..3040d03 ---- /dev/null -+++ b/node_modules/expo-notifications/android/.idea/misc.xml -@@ -0,0 +1,10 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -\ No newline at end of file -diff --git a/node_modules/expo-notifications/android/.idea/runConfigurations.xml b/node_modules/expo-notifications/android/.idea/runConfigurations.xml -new file mode 100644 -index 0000000..16660f1 ---- /dev/null -+++ b/node_modules/expo-notifications/android/.idea/runConfigurations.xml -@@ -0,0 +1,17 @@ -+ -+ -+ -+ -+ -+ -\ No newline at end of file -diff --git a/node_modules/expo-notifications/android/.idea/workspace.xml b/node_modules/expo-notifications/android/.idea/workspace.xml -new file mode 100644 -index 0000000..df26928 ---- /dev/null -+++ b/node_modules/expo-notifications/android/.idea/workspace.xml -@@ -0,0 +1,47 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ 1745552672693 -+ -+ -+ -+ -\ No newline at end of file -diff --git a/node_modules/expo-notifications/android/build.gradle b/node_modules/expo-notifications/android/build.gradle -index bc479ee..1ebfa00 100644 ---- a/node_modules/expo-notifications/android/build.gradle -+++ b/node_modules/expo-notifications/android/build.gradle -@@ -42,6 +42,7 @@ dependencies { - implementation 'com.google.firebase:firebase-messaging:24.0.1' - - implementation 'me.leolin:ShortcutBadger:1.1.22@aar' -+ implementation project(':expo-background-notification-handler') - - if (project.findProject(':expo-modules-test-core')) { - testImplementation project(':expo-modules-test-core') -diff --git a/node_modules/expo-notifications/android/local.properties b/node_modules/expo-notifications/android/local.properties -new file mode 100644 -index 0000000..ab4c86d ---- /dev/null -+++ b/node_modules/expo-notifications/android/local.properties -@@ -0,0 +1,8 @@ -+## This file must *NOT* be checked into Version Control Systems, -+# as it contains information specific to your local configuration. -+# -+# Location of the SDK. This is only used by Gradle. -+# For customization when using a Version Control System, please read the -+# header note. -+#Thu Apr 24 20:44:32 PDT 2025 -+sdk.dir=/Users/hailey/Library/Android/sdk -diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt -index 7b99e6c..45a450d 100644 ---- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt -+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt -@@ -15,6 +15,7 @@ import org.json.JSONObject - * This interface exists to provide a common API for both classes. - * */ - interface INotificationContent : Parcelable { -+ val channelId: String? - val title: String? - val text: String? - val subText: String? -diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java -index 191b64e..fe8b3c5 100644 ---- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java -+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java -@@ -35,6 +35,7 @@ import kotlin.coroutines.Continuation; - * Refactoring this class may require a migration strategy for the data stored in SharedPreferences. - */ - public class NotificationContent implements Parcelable, Serializable, INotificationContent { -+ private String mChannelId; - private String mTitle; - private String mText; - private String mSubtitle; -@@ -65,6 +66,11 @@ public class NotificationContent implements Parcelable, Serializable, INotificat - } - }; - -+ @Nullable -+ public String getChannelId() { -+ return mChannelId; -+ } -+ - @Nullable - public String getTitle() { - return mTitle; -@@ -158,6 +164,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat - } - - protected NotificationContent(Parcel in) { -+ mChannelId = in.readString(); - mTitle = in.readString(); - mText = in.readString(); - mSubtitle = in.readString(); -@@ -183,6 +190,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat - - @Override - public void writeToParcel(Parcel dest, int flags) { -+ dest.writeString(mChannelId); - dest.writeString(mTitle); - dest.writeString(mText); - dest.writeString(mSubtitle); -@@ -203,6 +211,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat - private static final long serialVersionUID = 397666843266836802L; - - private void writeObject(java.io.ObjectOutputStream out) throws IOException { -+ out.writeObject(mChannelId); - out.writeObject(mTitle); - out.writeObject(mText); - out.writeObject(mSubtitle); -@@ -285,6 +294,11 @@ public class NotificationContent implements Parcelable, Serializable, INotificat - useDefaultVibrationPattern(); - } - -+ public Builder setChannelId(String channelId) { -+ content.mChannelId = channelId; -+ return this; -+ } -+ - public Builder setTitle(String title) { - content.mTitle = title; - return this; -diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt -index 3af254c..3c77e9d 100644 ---- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt -+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt -@@ -11,6 +11,9 @@ import org.json.JSONObject - * */ - @JvmInline - value class NotificationData(private val data: Map) { -+ val channelId: String? -+ get() = data["channelId"] -+ - val title: String? - get() = data["title"] - -diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt -index d2cc6cf..6a48ff2 100644 ---- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt -+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt -@@ -31,6 +31,8 @@ class RemoteNotificationContent(private val remoteMessage: RemoteMessage) : INot - return remoteMessage.notification?.imageUrl != null - } - -+ override val channelId = remoteMessage.notification?.channelId ?: notificationData.channelId -+ - override val title = remoteMessage.notification?.title ?: notificationData.title - - override val text = remoteMessage.notification?.body ?: notificationData.message -diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt -index 98f003f..2f745e8 100644 ---- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt -+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt -@@ -101,6 +101,9 @@ open class ExpoNotificationBuilder( - builder.setOngoing(content.isSticky) - - // see "Notification anatomy" https://developer.android.com/develop/ui/views/notifications#Templates -+ content.channelId?.let { -+ builder.setChannelId(it) -+ } - builder.setContentTitle(content.title) - builder.setContentText(content.text) - builder.setSubText(content.subText) -diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt -index 90ca4ff..9d4cb09 100644 ---- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt -+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt -@@ -3,6 +3,9 @@ package expo.modules.notifications.service.delegates - import android.content.Context - import android.os.Bundle - import com.google.firebase.messaging.RemoteMessage -+import expo.modules.backgroundnotificationhandler.BackgroundNotificationHandler -+import expo.modules.backgroundnotificationhandler.BackgroundNotificationHandlerInterface -+import expo.modules.backgroundnotificationhandler.ExpoBackgroundNotificationHandlerModule - import expo.modules.interfaces.taskManager.TaskServiceProviderHelper - import expo.modules.notifications.notifications.RemoteMessageSerializer - import expo.modules.notifications.notifications.background.BackgroundRemoteNotificationTaskConsumer -@@ -18,7 +21,7 @@ import expo.modules.notifications.tokens.interfaces.FirebaseTokenListener - import java.lang.ref.WeakReference - import java.util.* - --open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseMessagingDelegate { -+open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseMessagingDelegate, BackgroundNotificationHandlerInterface{ - companion object { - // Unfortunately we cannot save state between instances of a service other way - // than by static properties. Fortunately, using weak references we can -@@ -105,8 +108,19 @@ open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseM - DebugLogging.logRemoteMessage("FirebaseMessagingDelegate.onMessageReceived: message", remoteMessage) - val notification = createNotification(remoteMessage) - DebugLogging.logNotification("FirebaseMessagingDelegate.onMessageReceived: notification", notification) -- NotificationsService.receive(context, notification) -- runTaskManagerTasks(context.applicationContext, RemoteMessageSerializer.toBundle(remoteMessage)) -+ if (!ExpoBackgroundNotificationHandlerModule.isForegrounded) { -+ BackgroundNotificationHandler(context, this).handleMessage(remoteMessage) -+ } else { -+ NotificationsService.receive(context, notification) -+ runTaskManagerTasks( -+ context.applicationContext, -+ RemoteMessageSerializer.toBundle(remoteMessage) -+ ) -+ } -+ } -+ -+ override fun showMessage(remoteMessage: RemoteMessage) { -+ NotificationsService.receive(context, createNotification(remoteMessage)) - } - - protected fun createNotification(remoteMessage: RemoteMessage): Notification { diff --git a/patches/expo-notifications+0.31.1.patch.md b/patches/expo-notifications+0.31.1.patch.md deleted file mode 100644 index 05f841725..000000000 --- a/patches/expo-notifications+0.31.1.patch.md +++ /dev/null @@ -1,14 +0,0 @@ -## LOAD BEARING PATCH, DO NOT REMOVE - -## Expo-Notifications Patch - -This patch supports the Android background notification handling module. Incoming messages -in `onMessageReceived` are sent to the module for handling. - -It also allows us to set the Android notification channel ID from the notification `data`, rather -than the `notification` object in the payload. - -### `setBadgeCountAsync` fix on Android - -`ShortcutBadger`'s `setCount` doesn't work for clearing the badge on Android for some reason. Instead, let's use the -Android API for clearing the badge. diff --git a/patches/expo-notifications+0.31.3.patch b/patches/expo-notifications+0.31.3.patch new file mode 100644 index 000000000..56e639a26 --- /dev/null +++ b/patches/expo-notifications+0.31.3.patch @@ -0,0 +1,992 @@ +diff --git a/node_modules/expo-notifications/android/.gradle/8.10/checksums/checksums.lock b/node_modules/expo-notifications/android/.gradle/8.10/checksums/checksums.lock +new file mode 100644 +index 0000000..883ef6a +Binary files /dev/null and b/node_modules/expo-notifications/android/.gradle/8.10/checksums/checksums.lock differ +diff --git a/node_modules/expo-notifications/android/.gradle/8.10/dependencies-accessors/gc.properties b/node_modules/expo-notifications/android/.gradle/8.10/dependencies-accessors/gc.properties +new file mode 100644 +index 0000000..e69de29 +diff --git a/node_modules/expo-notifications/android/.gradle/8.10/fileChanges/last-build.bin b/node_modules/expo-notifications/android/.gradle/8.10/fileChanges/last-build.bin +new file mode 100644 +index 0000000..f76dd23 +Binary files /dev/null and b/node_modules/expo-notifications/android/.gradle/8.10/fileChanges/last-build.bin differ +diff --git a/node_modules/expo-notifications/android/.gradle/8.10/fileHashes/fileHashes.lock b/node_modules/expo-notifications/android/.gradle/8.10/fileHashes/fileHashes.lock +new file mode 100644 +index 0000000..774caf7 +Binary files /dev/null and b/node_modules/expo-notifications/android/.gradle/8.10/fileHashes/fileHashes.lock differ +diff --git a/node_modules/expo-notifications/android/.gradle/8.10/gc.properties b/node_modules/expo-notifications/android/.gradle/8.10/gc.properties +new file mode 100644 +index 0000000..e69de29 +diff --git a/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +new file mode 100644 +index 0000000..a3c1514 +Binary files /dev/null and b/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ +diff --git a/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/cache.properties b/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/cache.properties +new file mode 100644 +index 0000000..0e5b4da +--- /dev/null ++++ b/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/cache.properties +@@ -0,0 +1,2 @@ ++#Thu Apr 24 20:44:36 PDT 2025 ++gradle.version=8.10 +diff --git a/node_modules/expo-notifications/android/.gradle/config.properties b/node_modules/expo-notifications/android/.gradle/config.properties +new file mode 100644 +index 0000000..0bd71c6 +--- /dev/null ++++ b/node_modules/expo-notifications/android/.gradle/config.properties +@@ -0,0 +1,2 @@ ++#Thu Apr 24 20:44:32 PDT 2025 ++java.home=/Applications/Android Studio.app/Contents/jbr/Contents/Home +diff --git a/node_modules/expo-notifications/android/.gradle/vcs-1/gc.properties b/node_modules/expo-notifications/android/.gradle/vcs-1/gc.properties +new file mode 100644 +index 0000000..e69de29 +diff --git a/node_modules/expo-notifications/android/.idea/.gitignore b/node_modules/expo-notifications/android/.idea/.gitignore +new file mode 100644 +index 0000000..26d3352 +--- /dev/null ++++ b/node_modules/expo-notifications/android/.idea/.gitignore +@@ -0,0 +1,3 @@ ++# Default ignored files ++/shelf/ ++/workspace.xml +diff --git a/node_modules/expo-notifications/android/.idea/AndroidProjectSystem.xml b/node_modules/expo-notifications/android/.idea/AndroidProjectSystem.xml +new file mode 100644 +index 0000000..4a53bee +--- /dev/null ++++ b/node_modules/expo-notifications/android/.idea/AndroidProjectSystem.xml +@@ -0,0 +1,6 @@ ++ ++ ++ ++ ++ +\ No newline at end of file +diff --git a/node_modules/expo-notifications/android/.idea/caches/deviceStreaming.xml b/node_modules/expo-notifications/android/.idea/caches/deviceStreaming.xml +new file mode 100644 +index 0000000..9e9ba09 +--- /dev/null ++++ b/node_modules/expo-notifications/android/.idea/caches/deviceStreaming.xml +@@ -0,0 +1,607 @@ ++ ++ ++ ++ ++ ++ +\ No newline at end of file +diff --git a/node_modules/expo-notifications/android/.idea/gradle.xml b/node_modules/expo-notifications/android/.idea/gradle.xml +new file mode 100644 +index 0000000..b838237 +--- /dev/null ++++ b/node_modules/expo-notifications/android/.idea/gradle.xml +@@ -0,0 +1,12 @@ ++ ++ ++ ++ ++ ++ +\ No newline at end of file +diff --git a/node_modules/expo-notifications/android/.idea/migrations.xml b/node_modules/expo-notifications/android/.idea/migrations.xml +new file mode 100644 +index 0000000..f8051a6 +--- /dev/null ++++ b/node_modules/expo-notifications/android/.idea/migrations.xml +@@ -0,0 +1,10 @@ ++ ++ ++ ++ ++ ++ +\ No newline at end of file +diff --git a/node_modules/expo-notifications/android/.idea/misc.xml b/node_modules/expo-notifications/android/.idea/misc.xml +new file mode 100644 +index 0000000..3040d03 +--- /dev/null ++++ b/node_modules/expo-notifications/android/.idea/misc.xml +@@ -0,0 +1,10 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ +\ No newline at end of file +diff --git a/node_modules/expo-notifications/android/.idea/runConfigurations.xml b/node_modules/expo-notifications/android/.idea/runConfigurations.xml +new file mode 100644 +index 0000000..16660f1 +--- /dev/null ++++ b/node_modules/expo-notifications/android/.idea/runConfigurations.xml +@@ -0,0 +1,17 @@ ++ ++ ++ ++ ++ ++ +\ No newline at end of file +diff --git a/node_modules/expo-notifications/android/.idea/workspace.xml b/node_modules/expo-notifications/android/.idea/workspace.xml +new file mode 100644 +index 0000000..df26928 +--- /dev/null ++++ b/node_modules/expo-notifications/android/.idea/workspace.xml +@@ -0,0 +1,47 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 1745552672693 ++ ++ ++ ++ +\ No newline at end of file +diff --git a/node_modules/expo-notifications/android/build.gradle b/node_modules/expo-notifications/android/build.gradle +index bc479ee..1ebfa00 100644 +--- a/node_modules/expo-notifications/android/build.gradle ++++ b/node_modules/expo-notifications/android/build.gradle +@@ -42,6 +42,7 @@ dependencies { + implementation 'com.google.firebase:firebase-messaging:24.0.1' + + implementation 'me.leolin:ShortcutBadger:1.1.22@aar' ++ implementation project(':expo-background-notification-handler') + + if (project.findProject(':expo-modules-test-core')) { + testImplementation project(':expo-modules-test-core') +diff --git a/node_modules/expo-notifications/android/local.properties b/node_modules/expo-notifications/android/local.properties +new file mode 100644 +index 0000000..ab4c86d +--- /dev/null ++++ b/node_modules/expo-notifications/android/local.properties +@@ -0,0 +1,8 @@ ++## This file must *NOT* be checked into Version Control Systems, ++# as it contains information specific to your local configuration. ++# ++# Location of the SDK. This is only used by Gradle. ++# For customization when using a Version Control System, please read the ++# header note. ++#Thu Apr 24 20:44:32 PDT 2025 ++sdk.dir=/Users/hailey/Library/Android/sdk +diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt +index 7b99e6c..45a450d 100644 +--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt ++++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt +@@ -15,6 +15,7 @@ import org.json.JSONObject + * This interface exists to provide a common API for both classes. + * */ + interface INotificationContent : Parcelable { ++ val channelId: String? + val title: String? + val text: String? + val subText: String? +diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java +index 191b64e..fe8b3c5 100644 +--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java ++++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java +@@ -35,6 +35,7 @@ import kotlin.coroutines.Continuation; + * Refactoring this class may require a migration strategy for the data stored in SharedPreferences. + */ + public class NotificationContent implements Parcelable, Serializable, INotificationContent { ++ private String mChannelId; + private String mTitle; + private String mText; + private String mSubtitle; +@@ -65,6 +66,11 @@ public class NotificationContent implements Parcelable, Serializable, INotificat + } + }; + ++ @Nullable ++ public String getChannelId() { ++ return mChannelId; ++ } ++ + @Nullable + public String getTitle() { + return mTitle; +@@ -158,6 +164,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat + } + + protected NotificationContent(Parcel in) { ++ mChannelId = in.readString(); + mTitle = in.readString(); + mText = in.readString(); + mSubtitle = in.readString(); +@@ -183,6 +190,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat + + @Override + public void writeToParcel(Parcel dest, int flags) { ++ dest.writeString(mChannelId); + dest.writeString(mTitle); + dest.writeString(mText); + dest.writeString(mSubtitle); +@@ -203,6 +211,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat + private static final long serialVersionUID = 397666843266836802L; + + private void writeObject(java.io.ObjectOutputStream out) throws IOException { ++ out.writeObject(mChannelId); + out.writeObject(mTitle); + out.writeObject(mText); + out.writeObject(mSubtitle); +@@ -285,6 +294,11 @@ public class NotificationContent implements Parcelable, Serializable, INotificat + useDefaultVibrationPattern(); + } + ++ public Builder setChannelId(String channelId) { ++ content.mChannelId = channelId; ++ return this; ++ } ++ + public Builder setTitle(String title) { + content.mTitle = title; + return this; +diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt +index 3af254c..3c77e9d 100644 +--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt ++++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt +@@ -11,6 +11,9 @@ import org.json.JSONObject + * */ + @JvmInline + value class NotificationData(private val data: Map) { ++ val channelId: String? ++ get() = data["channelId"] ++ + val title: String? + get() = data["title"] + +diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt +index d2cc6cf..6a48ff2 100644 +--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt ++++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt +@@ -31,6 +31,8 @@ class RemoteNotificationContent(private val remoteMessage: RemoteMessage) : INot + return remoteMessage.notification?.imageUrl != null + } + ++ override val channelId = remoteMessage.notification?.channelId ?: notificationData.channelId ++ + override val title = remoteMessage.notification?.title ?: notificationData.title + + override val text = remoteMessage.notification?.body ?: notificationData.message +diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt +index 98f003f..2f745e8 100644 +--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt ++++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt +@@ -101,6 +101,9 @@ open class ExpoNotificationBuilder( + builder.setOngoing(content.isSticky) + + // see "Notification anatomy" https://developer.android.com/develop/ui/views/notifications#Templates ++ content.channelId?.let { ++ builder.setChannelId(it) ++ } + builder.setContentTitle(content.title) + builder.setContentText(content.text) + builder.setSubText(content.subText) +diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt +index 90ca4ff..9d4cb09 100644 +--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt ++++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt +@@ -3,6 +3,9 @@ package expo.modules.notifications.service.delegates + import android.content.Context + import android.os.Bundle + import com.google.firebase.messaging.RemoteMessage ++import expo.modules.backgroundnotificationhandler.BackgroundNotificationHandler ++import expo.modules.backgroundnotificationhandler.BackgroundNotificationHandlerInterface ++import expo.modules.backgroundnotificationhandler.ExpoBackgroundNotificationHandlerModule + import expo.modules.interfaces.taskManager.TaskServiceProviderHelper + import expo.modules.notifications.notifications.RemoteMessageSerializer + import expo.modules.notifications.notifications.background.BackgroundRemoteNotificationTaskConsumer +@@ -18,7 +21,7 @@ import expo.modules.notifications.tokens.interfaces.FirebaseTokenListener + import java.lang.ref.WeakReference + import java.util.* + +-open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseMessagingDelegate { ++open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseMessagingDelegate, BackgroundNotificationHandlerInterface{ + companion object { + // Unfortunately we cannot save state between instances of a service other way + // than by static properties. Fortunately, using weak references we can +@@ -105,8 +108,19 @@ open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseM + DebugLogging.logRemoteMessage("FirebaseMessagingDelegate.onMessageReceived: message", remoteMessage) + val notification = createNotification(remoteMessage) + DebugLogging.logNotification("FirebaseMessagingDelegate.onMessageReceived: notification", notification) +- NotificationsService.receive(context, notification) +- runTaskManagerTasks(context.applicationContext, RemoteMessageSerializer.toBundle(remoteMessage)) ++ if (!ExpoBackgroundNotificationHandlerModule.isForegrounded) { ++ BackgroundNotificationHandler(context, this).handleMessage(remoteMessage) ++ } else { ++ NotificationsService.receive(context, notification) ++ runTaskManagerTasks( ++ context.applicationContext, ++ RemoteMessageSerializer.toBundle(remoteMessage) ++ ) ++ } ++ } ++ ++ override fun showMessage(remoteMessage: RemoteMessage) { ++ NotificationsService.receive(context, createNotification(remoteMessage)) + } + + protected fun createNotification(remoteMessage: RemoteMessage): Notification { diff --git a/patches/expo-notifications+0.31.3.patch.md b/patches/expo-notifications+0.31.3.patch.md new file mode 100644 index 000000000..05f841725 --- /dev/null +++ b/patches/expo-notifications+0.31.3.patch.md @@ -0,0 +1,14 @@ +## LOAD BEARING PATCH, DO NOT REMOVE + +## Expo-Notifications Patch + +This patch supports the Android background notification handling module. Incoming messages +in `onMessageReceived` are sent to the module for handling. + +It also allows us to set the Android notification channel ID from the notification `data`, rather +than the `notification` object in the payload. + +### `setBadgeCountAsync` fix on Android + +`ShortcutBadger`'s `setCount` doesn't work for clearing the badge on Android for some reason. Instead, let's use the +Android API for clearing the badge. diff --git a/patches/expo-updates+0.28.12.patch b/patches/expo-updates+0.28.12.patch deleted file mode 100644 index 6fc4fc5fc..000000000 --- a/patches/expo-updates+0.28.12.patch +++ /dev/null @@ -1,26 +0,0 @@ -diff --git a/node_modules/expo-updates/ios/EXUpdates/Update/ExpoUpdatesUpdate.swift b/node_modules/expo-updates/ios/EXUpdates/Update/ExpoUpdatesUpdate.swift -index b85291e..546709d 100644 ---- a/node_modules/expo-updates/ios/EXUpdates/Update/ExpoUpdatesUpdate.swift -+++ b/node_modules/expo-updates/ios/EXUpdates/Update/ExpoUpdatesUpdate.swift -@@ -78,13 +78,20 @@ public final class ExpoUpdatesUpdate: Update { - status = UpdateStatus.StatusPending - } - -+ // Instead of relying on various hacks to get the correct format for the specific -+ // platform on the backend, we can just add this little patch.. -+ let dateFormatter = DateFormatter() -+ dateFormatter.locale = Locale(identifier: "en_US_POSIX") -+ dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" -+ let date = dateFormatter.date(from:commitTime) ?? RCTConvert.nsDate(commitTime)! -+ - return Update( - manifest: manifest, - config: config, - database: database, - updateId: uuid, - scopeKey: config.scopeKey, -- commitTime: RCTConvert.nsDate(commitTime), -+ commitTime: date, - runtimeVersion: runtimeVersion, - keep: true, - status: status, diff --git a/patches/expo-updates+0.28.12.patch.md b/patches/expo-updates+0.28.12.patch.md deleted file mode 100644 index 6d5d7093d..000000000 --- a/patches/expo-updates+0.28.12.patch.md +++ /dev/null @@ -1,7 +0,0 @@ -# Expo-Updates Patch - -This is a small patch to convert timestamp formats that are returned from the backend. Instead of relying on the -backend to return the correct format for a specific format (the format required on Android is not the same as on iOS) -we can just add this conversion in. - -Don't remove unless we make changes on the backend to support both platforms. diff --git a/patches/expo-updates+0.28.14.patch b/patches/expo-updates+0.28.14.patch new file mode 100644 index 000000000..6fc4fc5fc --- /dev/null +++ b/patches/expo-updates+0.28.14.patch @@ -0,0 +1,26 @@ +diff --git a/node_modules/expo-updates/ios/EXUpdates/Update/ExpoUpdatesUpdate.swift b/node_modules/expo-updates/ios/EXUpdates/Update/ExpoUpdatesUpdate.swift +index b85291e..546709d 100644 +--- a/node_modules/expo-updates/ios/EXUpdates/Update/ExpoUpdatesUpdate.swift ++++ b/node_modules/expo-updates/ios/EXUpdates/Update/ExpoUpdatesUpdate.swift +@@ -78,13 +78,20 @@ public final class ExpoUpdatesUpdate: Update { + status = UpdateStatus.StatusPending + } + ++ // Instead of relying on various hacks to get the correct format for the specific ++ // platform on the backend, we can just add this little patch.. ++ let dateFormatter = DateFormatter() ++ dateFormatter.locale = Locale(identifier: "en_US_POSIX") ++ dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" ++ let date = dateFormatter.date(from:commitTime) ?? RCTConvert.nsDate(commitTime)! ++ + return Update( + manifest: manifest, + config: config, + database: database, + updateId: uuid, + scopeKey: config.scopeKey, +- commitTime: RCTConvert.nsDate(commitTime), ++ commitTime: date, + runtimeVersion: runtimeVersion, + keep: true, + status: status, diff --git a/patches/expo-updates+0.28.14.patch.md b/patches/expo-updates+0.28.14.patch.md new file mode 100644 index 000000000..6d5d7093d --- /dev/null +++ b/patches/expo-updates+0.28.14.patch.md @@ -0,0 +1,7 @@ +# Expo-Updates Patch + +This is a small patch to convert timestamp formats that are returned from the backend. Instead of relying on the +backend to return the correct format for a specific format (the format required on Android is not the same as on iOS) +we can just add this conversion in. + +Don't remove unless we make changes on the backend to support both platforms. diff --git a/patches/react-native+0.79.2.patch b/patches/react-native+0.79.2.patch deleted file mode 100644 index 609ae6617..000000000 --- a/patches/react-native+0.79.2.patch +++ /dev/null @@ -1,119 +0,0 @@ -diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h -index e9b330f..ec5f58c 100644 ---- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h -+++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h -@@ -15,5 +15,8 @@ - @property (nonatomic, copy) NSString *title; - @property (nonatomic, copy) RCTDirectEventBlock onRefresh; - @property (nonatomic, weak) UIScrollView *scrollView; -+@property (nonatomic, copy) UIColor *customTintColor; -+ -+- (void)forwarderBeginRefreshing; - - @end -diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m -index 53bfd04..ff1b1ed 100644 ---- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m -+++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m -@@ -23,6 +23,7 @@ - UIColor *_titleColor; - CGFloat _progressViewOffset; - BOOL _hasMovedToWindow; -+ UIColor *_customTintColor; - } - - - (instancetype)init -@@ -58,6 +59,12 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder) - _isInitialRender = false; - } - -+- (void)didMoveToSuperview -+{ -+ [super didMoveToSuperview]; -+ [self setTintColor:_customTintColor]; -+} -+ - - (void)didMoveToWindow - { - [super didMoveToWindow]; -@@ -221,4 +228,50 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder) - } - } - -+// Fix for https://github.com/facebook/react-native/issues/43388 -+// A bug in iOS 17.4 causes the haptic to not play when refreshing if the tintColor -+// is set before the refresh control gets added to the scrollview. We'll call this -+// function whenever the superview changes. We'll also call it if the value of customTintColor -+// changes. -+- (void)setTintColor:(UIColor *)tintColor -+{ -+ if ([self.superview isKindOfClass:[UIScrollView class]] && self.tintColor != tintColor) { -+ [super setTintColor:tintColor]; -+ } -+} -+ -+// This method is used by Bluesky's ExpoScrollForwarder. This allows other React Native -+// libraries to perform a refresh of a scrollview and access the refresh control's onRefresh -+// function. -+- (void)forwarderBeginRefreshing -+{ -+ _refreshingProgrammatically = NO; -+ -+ [self sizeToFit]; -+ -+ if (!self.scrollView) { -+ return; -+ } -+ -+ UIScrollView *scrollView = (UIScrollView *)self.scrollView; -+ -+ [UIView animateWithDuration:0.3 -+ delay:0 -+ options:UIViewAnimationOptionBeginFromCurrentState -+ animations:^(void) { -+ // Whenever we call this method, the scrollview will always be at a position of -+ // -130 or less. Scrolling back to -65 simulates the default behavior of RCTRefreshControl -+ [scrollView setContentOffset:CGPointMake(0, -65)]; -+ } -+ completion:^(__unused BOOL finished) { -+ [super beginRefreshing]; -+ [self setCurrentRefreshingState:super.refreshing]; -+ -+ if (self->_onRefresh) { -+ self->_onRefresh(nil); -+ } -+ } -+ ]; -+} -+ - @end -diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m -index 40aaf9c..1c60164 100644 ---- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m -+++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m -@@ -22,11 +22,12 @@ RCT_EXPORT_MODULE() - - RCT_EXPORT_VIEW_PROPERTY(onRefresh, RCTDirectEventBlock) - RCT_EXPORT_VIEW_PROPERTY(refreshing, BOOL) --RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor) - RCT_EXPORT_VIEW_PROPERTY(title, NSString) - RCT_EXPORT_VIEW_PROPERTY(titleColor, UIColor) - RCT_EXPORT_VIEW_PROPERTY(progressViewOffset, CGFloat) - -+RCT_REMAP_VIEW_PROPERTY(tintColor, customTintColor, UIColor) -+ - RCT_EXPORT_METHOD(setNativeRefreshing : (nonnull NSNumber *)viewTag toRefreshing : (BOOL)refreshing) - { - [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { -diff --git a/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m b/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m -index cd1e7eb..c1d0172 100644 ---- a/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m -+++ b/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m -@@ -83,6 +83,7 @@ RCT_EXPORT_VIEW_PROPERTY(showsVerticalScrollIndicator, BOOL) - RCT_EXPORT_VIEW_PROPERTY(scrollEventThrottle, NSTimeInterval) - RCT_EXPORT_VIEW_PROPERTY(zoomScale, CGFloat) - RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets) -+RCT_EXPORT_VIEW_PROPERTY(scrollIndicatorInsets, UIEdgeInsets) - RCT_EXPORT_VIEW_PROPERTY(verticalScrollIndicatorInsets, UIEdgeInsets) - RCT_EXPORT_VIEW_PROPERTY(scrollToOverflowEnabled, BOOL) - RCT_EXPORT_VIEW_PROPERTY(snapToInterval, int) diff --git a/patches/react-native+0.79.2.patch.md b/patches/react-native+0.79.2.patch.md deleted file mode 100644 index 9c93aee5c..000000000 --- a/patches/react-native+0.79.2.patch.md +++ /dev/null @@ -1,13 +0,0 @@ -# ***This second part of this patch is load bearing, do not remove.*** - -## RefreshControl Patch - iOS 17.4 Haptic Regression - -Patching `RCTRefreshControl.mm` temporarily to play an impact haptic on refresh when using iOS 17.4 or higher. Since -17.4, there has been a regression somewhere causing haptics to not play on iOS on refresh. Should monitor for an update -in the RN repo: https://github.com/facebook/react-native/issues/43388 - -## RefreshControl Path - ScrollForwarder - -Patching `RCTRefreshControl.m` and `RCTRefreshControl.h` to add a new `forwarderBeginRefreshing` method to the class. -This method is used by `ExpoScrollForwarder` to initiate a refresh of the underlying `UIScrollView` from inside that -module. diff --git a/patches/react-native+0.79.3.patch b/patches/react-native+0.79.3.patch new file mode 100644 index 000000000..6d465475e --- /dev/null +++ b/patches/react-native+0.79.3.patch @@ -0,0 +1,136 @@ +diff --git a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.h b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.h +index 914a249..0deac55 100644 +--- a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.h ++++ b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.h +@@ -19,6 +19,8 @@ NS_ASSUME_NONNULL_BEGIN + */ + @interface RCTPullToRefreshViewComponentView : RCTViewComponentView + ++- (void)beginRefreshingProgrammatically; ++ + @end + + NS_ASSUME_NONNULL_END +diff --git a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +index d029337..0f63ea3 100644 +--- a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm ++++ b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +@@ -1003,6 +1003,11 @@ - (void)_adjustForMaintainVisibleContentPosition + } + } + +++ (BOOL)shouldBeRecycled ++{ ++ return NO; ++} ++ + @end + + Class RCTScrollViewCls(void) +diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h +index e9b330f..ec5f58c 100644 +--- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h ++++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h +@@ -15,5 +15,8 @@ + @property (nonatomic, copy) NSString *title; + @property (nonatomic, copy) RCTDirectEventBlock onRefresh; + @property (nonatomic, weak) UIScrollView *scrollView; ++@property (nonatomic, copy) UIColor *customTintColor; ++ ++- (void)forwarderBeginRefreshing; + + @end +diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m +index 53bfd04..ff1b1ed 100644 +--- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m ++++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m +@@ -23,6 +23,7 @@ @implementation RCTRefreshControl { + UIColor *_titleColor; + CGFloat _progressViewOffset; + BOOL _hasMovedToWindow; ++ UIColor *_customTintColor; + } + + - (instancetype)init +@@ -58,6 +59,12 @@ - (void)layoutSubviews + _isInitialRender = false; + } + ++- (void)didMoveToSuperview ++{ ++ [super didMoveToSuperview]; ++ [self setTintColor:_customTintColor]; ++} ++ + - (void)didMoveToWindow + { + [super didMoveToWindow]; +@@ -221,4 +228,50 @@ - (void)refreshControlValueChanged + } + } + ++// Fix for https://github.com/facebook/react-native/issues/43388 ++// A bug in iOS 17.4 causes the haptic to not play when refreshing if the tintColor ++// is set before the refresh control gets added to the scrollview. We'll call this ++// function whenever the superview changes. We'll also call it if the value of customTintColor ++// changes. ++- (void)setTintColor:(UIColor *)tintColor ++{ ++ if ([self.superview isKindOfClass:[UIScrollView class]] && self.tintColor != tintColor) { ++ [super setTintColor:tintColor]; ++ } ++} ++ ++// This method is used by Bluesky's ExpoScrollForwarder. This allows other React Native ++// libraries to perform a refresh of a scrollview and access the refresh control's onRefresh ++// function. ++- (void)forwarderBeginRefreshing ++{ ++ _refreshingProgrammatically = NO; ++ ++ [self sizeToFit]; ++ ++ if (!self.scrollView) { ++ return; ++ } ++ ++ UIScrollView *scrollView = (UIScrollView *)self.scrollView; ++ ++ [UIView animateWithDuration:0.3 ++ delay:0 ++ options:UIViewAnimationOptionBeginFromCurrentState ++ animations:^(void) { ++ // Whenever we call this method, the scrollview will always be at a position of ++ // -130 or less. Scrolling back to -65 simulates the default behavior of RCTRefreshControl ++ [scrollView setContentOffset:CGPointMake(0, -65)]; ++ } ++ completion:^(__unused BOOL finished) { ++ [super beginRefreshing]; ++ [self setCurrentRefreshingState:super.refreshing]; ++ ++ if (self->_onRefresh) { ++ self->_onRefresh(nil); ++ } ++ } ++ ]; ++} ++ + @end +diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m +index 40aaf9c..1c60164 100644 +--- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m ++++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m +@@ -22,11 +22,12 @@ - (UIView *)view + + RCT_EXPORT_VIEW_PROPERTY(onRefresh, RCTDirectEventBlock) + RCT_EXPORT_VIEW_PROPERTY(refreshing, BOOL) +-RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor) + RCT_EXPORT_VIEW_PROPERTY(title, NSString) + RCT_EXPORT_VIEW_PROPERTY(titleColor, UIColor) + RCT_EXPORT_VIEW_PROPERTY(progressViewOffset, CGFloat) + ++RCT_REMAP_VIEW_PROPERTY(tintColor, customTintColor, UIColor) ++ + RCT_EXPORT_METHOD(setNativeRefreshing : (nonnull NSNumber *)viewTag toRefreshing : (BOOL)refreshing) + { + [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { diff --git a/patches/react-native+0.79.3.patch.md b/patches/react-native+0.79.3.patch.md new file mode 100644 index 000000000..9c93aee5c --- /dev/null +++ b/patches/react-native+0.79.3.patch.md @@ -0,0 +1,13 @@ +# ***This second part of this patch is load bearing, do not remove.*** + +## RefreshControl Patch - iOS 17.4 Haptic Regression + +Patching `RCTRefreshControl.mm` temporarily to play an impact haptic on refresh when using iOS 17.4 or higher. Since +17.4, there has been a regression somewhere causing haptics to not play on iOS on refresh. Should monitor for an update +in the RN repo: https://github.com/facebook/react-native/issues/43388 + +## RefreshControl Path - ScrollForwarder + +Patching `RCTRefreshControl.m` and `RCTRefreshControl.h` to add a new `forwarderBeginRefreshing` method to the class. +This method is used by `ExpoScrollForwarder` to initiate a refresh of the underlying `UIScrollView` from inside that +module. diff --git a/patches/react-native-svg+15.11.2.patch b/patches/react-native-svg+15.11.2.patch deleted file mode 100644 index 54540023f..000000000 --- a/patches/react-native-svg+15.11.2.patch +++ /dev/null @@ -1,57 +0,0 @@ -diff --git a/node_modules/react-native-svg/android/src/main/java/com/horcrux/svg/PathView.java b/node_modules/react-native-svg/android/src/main/java/com/horcrux/svg/PathView.java -index 06829bd..1b15818 100644 ---- a/node_modules/react-native-svg/android/src/main/java/com/horcrux/svg/PathView.java -+++ b/node_modules/react-native-svg/android/src/main/java/com/horcrux/svg/PathView.java -@@ -14,17 +14,33 @@ import android.graphics.Paint; - import android.graphics.Path; - import com.facebook.react.bridge.ReactContext; - -+import java.util.ArrayList; -+import java.util.HashMap; -+ -+class ParsedPath { -+ final Path path; -+ final ArrayList elements; -+ -+ ParsedPath(Path path, ArrayList elements) { -+ this.path = path; -+ this.elements = elements; -+ } -+} -+ - @SuppressLint("ViewConstructor") - class PathView extends RenderableView { - private Path mPath; - -+ // This grows forever but for our use case (static icons) it's ok. -+ private static final HashMap sPathCache = new HashMap<>(); -+ - public PathView(ReactContext reactContext) { - super(reactContext); - PathParser.mScale = mScale; - mPath = new Path(); - } - -- public void setD(String d) { -+ void setDByParsing(String d) { - mPath = PathParser.parse(d); - elements = PathParser.elements; - for (PathElement elem : elements) { -@@ -33,6 +49,17 @@ class PathView extends RenderableView { - point.y *= mScale; - } - } -+ } -+ -+ public void setD(String d) { -+ ParsedPath cached = sPathCache.get(d); -+ if (cached != null) { -+ mPath = cached.path; -+ elements = cached.elements; -+ } else { -+ setDByParsing(d); -+ sPathCache.put(d, new ParsedPath(mPath, elements)); -+ } - invalidate(); - } - diff --git a/patches/react-native-svg+15.12.0.patch b/patches/react-native-svg+15.12.0.patch new file mode 100644 index 000000000..54540023f --- /dev/null +++ b/patches/react-native-svg+15.12.0.patch @@ -0,0 +1,57 @@ +diff --git a/node_modules/react-native-svg/android/src/main/java/com/horcrux/svg/PathView.java b/node_modules/react-native-svg/android/src/main/java/com/horcrux/svg/PathView.java +index 06829bd..1b15818 100644 +--- a/node_modules/react-native-svg/android/src/main/java/com/horcrux/svg/PathView.java ++++ b/node_modules/react-native-svg/android/src/main/java/com/horcrux/svg/PathView.java +@@ -14,17 +14,33 @@ import android.graphics.Paint; + import android.graphics.Path; + import com.facebook.react.bridge.ReactContext; + ++import java.util.ArrayList; ++import java.util.HashMap; ++ ++class ParsedPath { ++ final Path path; ++ final ArrayList elements; ++ ++ ParsedPath(Path path, ArrayList elements) { ++ this.path = path; ++ this.elements = elements; ++ } ++} ++ + @SuppressLint("ViewConstructor") + class PathView extends RenderableView { + private Path mPath; + ++ // This grows forever but for our use case (static icons) it's ok. ++ private static final HashMap sPathCache = new HashMap<>(); ++ + public PathView(ReactContext reactContext) { + super(reactContext); + PathParser.mScale = mScale; + mPath = new Path(); + } + +- public void setD(String d) { ++ void setDByParsing(String d) { + mPath = PathParser.parse(d); + elements = PathParser.elements; + for (PathElement elem : elements) { +@@ -33,6 +49,17 @@ class PathView extends RenderableView { + point.y *= mScale; + } + } ++ } ++ ++ public void setD(String d) { ++ ParsedPath cached = sPathCache.get(d); ++ if (cached != null) { ++ mPath = cached.path; ++ elements = cached.elements; ++ } else { ++ setDByParsing(d); ++ sPathCache.put(d, new ParsedPath(mPath, elements)); ++ } + invalidate(); + } + -- cgit 1.4.1