Skip to content

Commit 57dae8d

Browse files
committed
Fix Chat Input Crashes on Android
The input was crashing when you sent messages that had modified the native selection props. It crashed when you cleared the text because it would set the text to empty, and reused a cached selection that was out of bounds of an empty string. For example, say you type "hello @" and autocomplete to "hello @foo". We do some text selection magic to insert the @foo and put your cursor in the correct spot. The Selection start and end indicies are both 11. When you submit to message, we clear the text. When we clear the text, RN keeps reusing those selection indices (of 11) and Android complains the selection is outside of the bounds of the text ("" has a length of 0, but you want to move the cursor to position 11, outside the bounds of 0). The workaround here is to set the selection at the same time as the text. The RN Issue is: facebook/react-native#25265
1 parent acaa90d commit 57dae8d

File tree

1 file changed

+23
-10
lines changed

1 file changed

+23
-10
lines changed

shared/common-adapters/plain-input.native.tsx

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
styleSheetCreate,
1212
isDarkMode,
1313
} from '../styles'
14-
import {isIOS} from '../constants/platform'
14+
import {isIOS, isAndroid} from '../constants/platform'
1515
import {checkTextInfo} from './input.shared'
1616
import {pick} from 'lodash-es'
1717
import logger from '../logger'
@@ -67,9 +67,19 @@ class PlainInput extends Component<InternalProps> {
6767
}
6868
const newTextInfo = fn(currentTextInfo)
6969
checkTextInfo(newTextInfo)
70-
this.setNativeProps({text: newTextInfo.text})
71-
this._lastNativeText = newTextInfo.text
72-
this._setSelection(newTextInfo.selection)
70+
// If we're android, let's workaround this Issue: https://github.com/imnapo/react-native-cn-richtext-editor/issues/81
71+
// By setting the text and selection at the same time
72+
if (isAndroid) {
73+
this.setNativeProps({
74+
selection: this._sanityCheckSelection(newTextInfo.selection, newTextInfo.text),
75+
text: newTextInfo.text,
76+
})
77+
this._lastNativeText = newTextInfo.text
78+
} else {
79+
this.setNativeProps({text: newTextInfo.text})
80+
this._lastNativeText = newTextInfo.text
81+
this._setSelection(newTextInfo.selection)
82+
}
7383
if (reflectChange) {
7484
this._onChangeText(newTextInfo.text)
7585
}
@@ -87,14 +97,17 @@ class PlainInput extends Component<InternalProps> {
8797
this._setSelection(s)
8898
}
8999

100+
// Validate that this selection makes sense with current value
101+
_sanityCheckSelection = (selection: Selection, nativeText: string): Selection => {
102+
let {start, end} = selection
103+
end = Math.max(0, Math.min(end || 0, nativeText.length))
104+
start = Math.min(start || 0, end)
105+
return {end, start}
106+
}
107+
90108
_setSelection = (selection: Selection) => {
91109
this._setTimeout(() => {
92-
// Validate that this selection makes sense with current value
93-
let {start, end} = selection
94-
const text = this._lastNativeText || '' // TODO write a good internal getValue fcn for this
95-
end = Math.max(0, Math.min(end || 0, text.length))
96-
start = Math.min(start || 0, end)
97-
const newSelection = {end, start}
110+
const newSelection = this._sanityCheckSelection(selection, this._lastNativeText || '')
98111
this.setNativeProps({selection: newSelection})
99112
this._lastNativeSelection = selection
100113
}, 0)

0 commit comments

Comments
 (0)