Skip to content

Commit 1683d1e

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` <!-- 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 9837731 commit 1683d1e

File tree

6 files changed

+35
-1
lines changed

6 files changed

+35
-1
lines changed

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

Libraries/Text/TextInput/Multiline/RCTUITextView.m

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

260+
#pragma mark - Dictation
261+
262+
- (void)dictationRecordingDidEnd
263+
{
264+
_dictationRecognizing = YES;
265+
}
266+
267+
- (void)removeDictationResultPlaceholder:(id)placeholder willInsertResult:(BOOL)willInsertResult
268+
{
269+
[super removeDictationResultPlaceholder:placeholder willInsertResult:willInsertResult];
270+
_dictationRecognizing = NO;
271+
}
272+
260273
#pragma mark - Placeholder
261274

262275
- (void)_invalidatePlaceholderVisibility

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;

Libraries/Text/TextInput/RCTBaseTextInputView.m

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,13 @@ - (BOOL)textOf:(NSAttributedString*)newText equals:(NSAttributedString*)oldText{
115115
}
116116
}];
117117

118+
BOOL shouldFallbackDictation = [self.backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"dictation"];
119+
if (@available(iOS 16.0, *)) {
120+
shouldFallbackDictation = self.backedTextInputView.dictationRecognizing;
121+
}
122+
118123
BOOL shouldFallbackToBareTextComparison =
119-
[self.backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"dictation"] ||
124+
shouldFallbackDictation ||
120125
[self.backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"ko-KR"] ||
121126
self.backedTextInputView.markedTextRange ||
122127
self.backedTextInputView.isSecureTextEntry ||

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;

Libraries/Text/TextInput/Singleline/RCTUITextField.m

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

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

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

0 commit comments

Comments
 (0)