Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class T3ComposerEditorModule : Module() {
"onComposerSelectionChange",
"onComposerFocus",
"onComposerBlur",
"onComposerSubmit",
"onComposerPasteImages",
"onComposerContentSizeChange",
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import android.text.Spanned
import android.text.TextWatcher
import android.text.style.ReplacementSpan
import android.view.Gravity
import android.view.KeyEvent
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
Expand All @@ -31,6 +32,7 @@ class T3ComposerEditorView(context: Context, appContext: AppContext) : ExpoView(
private val onComposerSelectionChange by EventDispatcher()
private val onComposerFocus by EventDispatcher()
private val onComposerBlur by EventDispatcher()
private val onComposerSubmit by EventDispatcher()
private val onComposerPasteImages by EventDispatcher()
private val onComposerContentSizeChange by EventDispatcher()
private var applyingNativeValue = false
Expand Down Expand Up @@ -65,6 +67,11 @@ class T3ComposerEditorView(context: Context, appContext: AppContext) : ExpoView(
editor.pasteImagesListener = { uris ->
onComposerPasteImages(mapOf("uris" to uris))
}
// A hardware keyboard has no on-screen Send button to reach for, so
// Ctrl/Meta+Enter is the way to send. Plain Enter still inserts a newline.
editor.submitListener = {
onComposerSubmit(emptyMap<String, Any>())
}
editor.setOnFocusChangeListener { _, hasFocus ->
if (hasFocus) {
onComposerFocus(emptyMap<String, Any>())
Expand Down Expand Up @@ -457,12 +464,30 @@ private fun parseTokens(value: String): List<ComposerToken> = try {
private class SelectionAwareEditText(context: Context) : EditText(context) {
var selectionListener: ((Int, Int) -> Unit)? = null
var pasteImagesListener: ((List<String>) -> Unit)? = null
var submitListener: (() -> Unit)? = null

override fun onSelectionChanged(selStart: Int, selEnd: Int) {
super.onSelectionChanged(selStart, selEnd)
selectionListener?.invoke(selStart, selEnd)
}

override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
// Ctrl/Meta+Enter from a hardware keyboard sends; plain Enter falls
// through to the default multiline newline insertion.
val listener = submitListener
if (event != null && listener != null && isSubmitShortcut(keyCode, event)) {
listener.invoke()
return true
}
return super.onKeyDown(keyCode, event)
}

private fun isSubmitShortcut(keyCode: Int, event: KeyEvent): Boolean {
val isEnter = keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER
val hasSubmitModifier = event.isCtrlPressed || event.isMetaPressed
return isEnter && hasSubmitModifier
}

override fun onTextContextMenuItem(id: Int): Boolean {
if (id == android.R.id.paste || id == android.R.id.pasteAsPlainText) {
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager
Expand Down
3 changes: 3 additions & 0 deletions apps/mobile/src/native/T3ComposerEditor.native.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ interface NativeComposerEditorProps extends ViewProps {
readonly onComposerPasteImages?: (event: NativePasteImagesEvent) => void;
readonly onComposerFocus?: () => void;
readonly onComposerBlur?: () => void;
readonly onComposerSubmit?: () => void;
}

const NativeView = requireNativeView<NativeComposerEditorProps>(NATIVE_MODULE_NAME);
Expand All @@ -98,6 +99,7 @@ export function ComposerEditor({
onPasteImages,
onFocus,
onBlur,
onSubmit,
contentInsetVertical = 0,
...props
}: ComposerEditorProps) {
Expand Down Expand Up @@ -296,6 +298,7 @@ export function ComposerEditor({
onComposerPasteImages={(event) => onPasteImages?.(event.nativeEvent.uris)}
onComposerFocus={onFocus}
onComposerBlur={onBlur}
onComposerSubmit={onSubmit}
/>
</TextInputWrapper>
);
Expand Down
Loading