diff --git a/native/index.js b/native/index.js index 00b5820ed..6c24098e7 100644 --- a/native/index.js +++ b/native/index.js @@ -1,12 +1,22 @@ // @flow +/* eslint-disable import/order */ + import 'react-native-gesture-handler'; + +// react-native has an issue with inverted lists on Android, and it got worse +// with Android 13. To avoid it we patch a react-native style, but that style +// got deprecated in React Native 0.70. For now the deprecation is limited to a +// JS runtime check, which we disable here. +import ViewReactNativeStyleAttributes from 'react-native/Libraries/Components/View/ReactNativeStyleAttributes'; +ViewReactNativeStyleAttributes.scaleY = true; + import './reactotron'; import './config'; import { AppRegistry } from 'react-native'; import { name as appName } from './app.json'; import Root from './root.react'; AppRegistry.registerComponent(appName, () => Root); diff --git a/patches/react-native+0.70.6.patch b/patches/react-native+0.70.6.patch index 53e0748d8..fda8df1f7 100644 --- a/patches/react-native+0.70.6.patch +++ b/patches/react-native+0.70.6.patch @@ -1,146 +1,172 @@ diff --git a/node_modules/react-native/Libraries/Components/TextInput/TextInput.js b/node_modules/react-native/Libraries/Components/TextInput/TextInput.js index 8fa1171..316b482 100644 --- a/node_modules/react-native/Libraries/Components/TextInput/TextInput.js +++ b/node_modules/react-native/Libraries/Components/TextInput/TextInput.js @@ -208,6 +208,13 @@ export type TextContentType = type PasswordRules = string; type IOSProps = $ReadOnly<{| + /** + * If set, allows pasting of images for given threadID. + * The default value is NULL. + * @platform ios + */ + allowImagePasteForThreadID?: ?string, + /** * When the clear button should appear on the right side of the text view. * This property is supported only for single-line TextInput component. +diff --git a/node_modules/react-native/Libraries/Lists/VirtualizedList.js b/node_modules/react-native/Libraries/Lists/VirtualizedList.js +index 69e6309..5343e6a 100644 +--- a/node_modules/react-native/Libraries/Lists/VirtualizedList.js ++++ b/node_modules/react-native/Libraries/Lists/VirtualizedList.js +@@ -34,6 +34,7 @@ const RefreshControl = require('../Components/RefreshControl/RefreshControl'); + const ScrollView = require('../Components/ScrollView/ScrollView'); + const View = require('../Components/View/View'); + const Batchinator = require('../Interaction/Batchinator'); ++const Platform = require('../Utilities/Platform'); + const ReactNative = require('../Renderer/shims/ReactNative'); + const flattenStyle = require('../StyleSheet/flattenStyle'); + const StyleSheet = require('../StyleSheet/StyleSheet'); +@@ -2170,9 +2171,10 @@ function describeNestedLists(childList: { + } + + const styles = StyleSheet.create({ +- verticallyInverted: { +- transform: [{scaleY: -1}], +- }, ++ verticallyInverted: ++ Platform.OS === 'android' ++ ? { scaleY: -1 } ++ : { transform: [{scaleY: -1}] }, + horizontallyInverted: { + transform: [{scaleX: -1}], + }, diff --git a/node_modules/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.h b/node_modules/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.h index 5ccb6b6..1f326d4 100644 --- a/node_modules/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.h +++ b/node_modules/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.h @@ -35,6 +35,8 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, assign) BOOL caretHidden; +@property (nonatomic, copy, nullable) NSString *allowImagePasteForThreadID; + @property (nonatomic, strong, nullable) NSString *inputAccessoryViewID; @end diff --git a/node_modules/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.m b/node_modules/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.m index 92371bc..e991835 100644 --- a/node_modules/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.m +++ b/node_modules/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.m @@ -164,8 +164,12 @@ - (void)setSelectedTextRange:(UITextRange *)selectedTextRange notifyDelegate:(BO - (void)paste:(id)sender { - [super paste:sender]; - _textWasPasted = YES; + if ([UIPasteboard generalPasteboard].hasImages && _allowImagePasteForThreadID) { + [_textInputDelegate textInputImagePasted:_allowImagePasteForThreadID]; + } else { + [super paste:sender]; + _textWasPasted = YES; + } } // Turn off scroll animation to fix flaky scrolling. @@ -254,6 +258,10 @@ - (BOOL)canPerformAction:(SEL)action withSender:(id)sender return NO; } + if (action == @selector(paste:) && [UIPasteboard generalPasteboard].hasImages) { + return (_allowImagePasteForThreadID != NULL); + } + return [super canPerformAction:action withSender:sender]; } diff --git a/node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h b/node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h index c2a4362..90f8583 100644 --- a/node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h +++ b/node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h @@ -33,6 +33,8 @@ NS_ASSUME_NONNULL_BEGIN - (void)textInputDidChangeSelection; +- (void)textInputImagePasted:(NSString *)threadID; + @optional - (void)scrollViewDidScroll:(UIScrollView *)scrollView; diff --git a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.m b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.m index a492492..e3b38cb 100644 --- a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.m +++ b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.m @@ -19,6 +19,8 @@ #import #import +#import + @implementation RCTBaseTextInputView { __weak RCTBridge *_bridge; __weak id _eventDispatcher; @@ -491,6 +493,46 @@ - (void)textInputDidChangeSelection }); } +- (void)textInputImagePasted:(NSString *)threadID +{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + UIPasteboard *clipboard = [UIPasteboard generalPasteboard]; + NSData *imageData = [clipboard dataForPasteboardType:(NSString*)kUTTypeImage]; + + UIImage *uiImage = [UIImage imageWithData:imageData]; + + if (!imageData) { + RCTLog(@"Failed to get image from UIPasteboard."); + return; + } + + NSString *fileName = [@([imageData hash]) stringValue]; + NSURL *tmpDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES]; + + // We add the PNG file extension because EXImageLoader fails without it. + // Our code ignores file extensions and looks at magic numbers directly. + NSURL *fileURL = [[tmpDirURL URLByAppendingPathComponent:fileName] URLByAppendingPathExtension:@"png"]; + NSString *fileDest = [fileURL path]; + + if (![fileManager fileExistsAtPath:fileDest]) { + BOOL fileWritten = [imageData writeToFile:fileDest atomically:true]; + if (!fileWritten) { + RCTLog(@"Failed to save image to temporary directory."); + return; + } + } + + NSDictionary *eventBody = @{ + @"fileName": fileName, + @"filePath": fileDest, + @"height": @(uiImage.size.height), + @"width": @(uiImage.size.width), + @"threadID": threadID, + }; + + [_eventDispatcher sendAppEventWithName:@"imagePasted" body:eventBody]; +} + - (void)updateLocalData { [self enforceTextAttributesIfNeeded]; diff --git a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m index b1ecf85..3462f98 100644 --- a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m +++ b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m @@ -33,6 +33,7 @@ @implementation RCTBaseTextInputViewManager #pragma mark - Unified properties +RCT_REMAP_VIEW_PROPERTY(allowImagePasteForThreadID, backedTextInputView.allowImagePasteForThreadID, NSString) RCT_REMAP_VIEW_PROPERTY(autoCapitalize, backedTextInputView.autocapitalizationType, UITextAutocapitalizationType) RCT_REMAP_VIEW_PROPERTY(autoCorrect, backedTextInputView.autocorrectionType, UITextAutocorrectionType) RCT_REMAP_VIEW_PROPERTY(contextMenuHidden, backedTextInputView.contextMenuHidden, BOOL)