Skip to content

Commit dbcfdf8

Browse files
committed
Adapt iOS16+ dictation (facebook#37188)
Summary: facebook#19687 https://developer.apple.com/forums/thread/711413 When system version is lower than `iOS 16`, it does not support `dictation` and `keyboard` working at the same time, so if we modify the text, the system will immediately interrupt the `dictation`, so we need to prohibit modification of the text during `recording` and `recognition` When system version is higher than `iOS 16`, `dictation` and `keyboard` can work at the same time, so `textInputMode.primaryLanguage` is no longer changed to `dictation`, so we can modify the text during `recording`, because the system will not interrupt, but we cannot modify the text during `recognition`, Because the system will temporarily add a `_UITextPlaceholderAttachment` to display the recognition `UIActivityIndicator` ## Changelog: <!-- Help reviewers and the release process by writing your own changelog entry. Pick one each for the category and type tags: [ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message For more details, see: https://reactnative.dev/contributing/changelogs-in-pull-requests --> [IOS][FIXED] - Adapt iOS16+ dictation judge condition Pull Request resolved: facebook#37188 Test Plan: Test Code ```javascript constructor(props) { super(props) this.state = { value: '', logList: [], } } render() { return ( <View style={{ flex: 1, padding: 50, backgroundColor: 'white'}}> <TextInput style={{ marginTop: 20, height: 50, borderWidth: 1, borderColor: 'black' }} placeholder={'please input'} placeholderTextColor={'gray'} value={this.state.value} onChangeText={value => { let logList = this.state.logList logList.push(value.length <= 0 ? 'null' : value.replace(/\uFFFC/g, '_uFFFC')) this.setState({ value, logList }) }} onEndEditing={() => this.setState({ value: '', logList: [] })} /> <FlatList style={{ marginTop: 20, maxHeight: 300, borderWidth: 1, borderColor: 'black' }} data={this.state.logList} renderItem={({item}) => ( <Text>{item}</Text> )} /> </View> ) } ``` Case A: Required < iOS16 1. ensure that facebook#18890 can work well and dictation will not be interrupted immediately https://github.com/facebook/react-native/assets/20135674/e69a609c-2dc4-48fc-8186-f9e5af3ac879 Case B: Required >= iOS16 1. ensure that facebook#18890 can work well and dictation will not be interrupted immediately https://github.com/facebook/react-native/assets/20135674/caa97e18-c7c4-4a08-9872-b50130f73bf4 Case C: Required >= iOS16 1. start dictation 3. then do not speak any words 4. then end dictation 5. verify that `onChangeText` will callback "\uFFFC" once 6. and then verify `onChangeText` callback an empty string "" once https://user-images.githubusercontent.com/20135674/235960378-90155ec5-a129-47bc-825b-ee6cb03e7286.MP4 Case D: Required >= iOS16 1. start dictation 3. input some text while speaking some words 4. then end dictation 5. and verify that the `onChangeText` callback work fine. https://user-images.githubusercontent.com/20135674/235960411-e479d9ab-856a-4407-a644-986426825133.MP4 Case E: Required >= iOS16 1. start dictation 2. say a word 3. and then switch the keyboard to other language 4. verify that dictation will not end 6. continue say some word 8. verify the `onChangeText` callback work fine. https://user-images.githubusercontent.com/20135674/235960450-351f1aaf-80c0-4d1c-b5c9-3e2cd7225875.MP4 Reviewed By: sammy-SC Differential Revision: D45563187 Pulled By: dmytrorykun fbshipit-source-id: 7467b313769896140434f60dcb3590d0b3c1aa15
1 parent dd492a1 commit dbcfdf8

File tree

6 files changed

+35
-2
lines changed

6 files changed

+35
-2
lines changed

packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
2424

2525
@property (nonatomic, assign) BOOL contextMenuHidden;
2626
@property (nonatomic, assign, readonly) BOOL textWasPasted;
27+
@property (nonatomic, assign, readonly) BOOL dictationRecognizing;
2728
@property (nonatomic, copy, nullable) NSString *placeholder;
2829
@property (nonatomic, strong, nullable) UIColor *placeholderColor;
2930

packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.m

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,19 @@ - (BOOL)canPerformAction:(SEL)action withSender:(id)sender
261261
return [super canPerformAction:action withSender:sender];
262262
}
263263

264+
#pragma mark - Dictation
265+
266+
- (void)dictationRecordingDidEnd
267+
{
268+
_dictationRecognizing = YES;
269+
}
270+
271+
- (void)removeDictationResultPlaceholder:(id)placeholder willInsertResult:(BOOL)willInsertResult
272+
{
273+
[super removeDictationResultPlaceholder:placeholder willInsertResult:willInsertResult];
274+
_dictationRecognizing = NO;
275+
}
276+
264277
#pragma mark - Placeholder
265278

266279
- (void)_invalidatePlaceholderVisibility

packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ NS_ASSUME_NONNULL_BEGIN
1818
@property (nonatomic, copy, nullable) NSString *placeholder;
1919
@property (nonatomic, strong, nullable) UIColor *placeholderColor;
2020
@property (nonatomic, assign, readonly) BOOL textWasPasted;
21+
@property (nonatomic, assign, readonly) BOOL dictationRecognizing;
2122
@property (nonatomic, assign) UIEdgeInsets textContainerInset;
2223
@property (nonatomic, strong, nullable) UIView *inputAccessoryView;
2324
@property (nonatomic, strong, nullable) UIView *inputView;

packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.m

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,12 @@ - (BOOL)textOf:(NSAttributedString *)newText equals:(NSAttributedString *)oldTex
119119
}
120120
}];
121121

122-
BOOL shouldFallbackToBareTextComparison =
123-
[self.backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"dictation"] ||
122+
BOOL shouldFallbackDictation = [self.backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"dictation"];
123+
if (@available(iOS 16.0, *)) {
124+
shouldFallbackDictation = self.backedTextInputView.dictationRecognizing;
125+
}
126+
127+
BOOL shouldFallbackToBareTextComparison = shouldFallbackDictation ||
124128
[self.backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"ko-KR"] ||
125129
self.backedTextInputView.markedTextRange || self.backedTextInputView.isSecureTextEntry ||
126130
fontHasBeenUpdatedBySystem;

packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
2424
@property (nonatomic, assign) BOOL caretHidden;
2525
@property (nonatomic, assign) BOOL contextMenuHidden;
2626
@property (nonatomic, assign, readonly) BOOL textWasPasted;
27+
@property (nonatomic, assign, readonly) BOOL dictationRecognizing;
2728
@property (nonatomic, strong, nullable) UIColor *placeholderColor;
2829
@property (nonatomic, assign) UIEdgeInsets textContainerInset;
2930
@property (nonatomic, assign, getter=isEditable) BOOL editable;

packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.m

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,19 @@ - (BOOL)canPerformAction:(SEL)action withSender:(id)sender
142142
return [super canPerformAction:action withSender:sender];
143143
}
144144

145+
#pragma mark - Dictation
146+
147+
- (void)dictationRecordingDidEnd
148+
{
149+
_dictationRecognizing = YES;
150+
}
151+
152+
- (void)removeDictationResultPlaceholder:(id)placeholder willInsertResult:(BOOL)willInsertResult
153+
{
154+
[super removeDictationResultPlaceholder:placeholder willInsertResult:willInsertResult];
155+
_dictationRecognizing = NO;
156+
}
157+
145158
#pragma mark - Caret Manipulation
146159

147160
- (CGRect)caretRectForPosition:(UITextPosition *)position

0 commit comments

Comments
 (0)