diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 9a2f871fe5..863d7dcc73 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -1322,7 +1322,15 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate, if (textSecurePreferences.isLinkPreviewsEnabled()) { linkPreviewViewModel.onTextChanged(this, inputBarText, 0, 0) } - if (LinkPreviewUtil.findWhitelistedUrls(newContent.toString()).isNotEmpty() + + // use the normalised version of the text's body to get the characters amount with the + // mentions as their account id + viewModel.onTextChanged(mentionViewModel.deconstructMessageMentions()) + } + + override fun onInputBarEditTextPasted() { + val inputBarText = binding.inputBar.text + if (LinkPreviewUtil.findWhitelistedUrls(inputBarText).isNotEmpty() && !textSecurePreferences.isLinkPreviewsEnabled() && !textSecurePreferences.hasSeenLinkPreviewSuggestionDialog()) { LinkPreviewDialog { setUpLinkPreviewObserver() @@ -1331,10 +1339,6 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate, }.show(supportFragmentManager, "Link Preview Dialog") textSecurePreferences.setHasSeenLinkPreviewSuggestionDialog() } - - // use the normalised version of the text's body to get the characters amount with the - // mentions as their account id - viewModel.onTextChanged(mentionViewModel.deconstructMessageMentions()) } override fun toggleAttachmentOptions() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt index ac74fb1352..2871a98609 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt @@ -20,7 +20,6 @@ import dagger.hilt.android.AndroidEntryPoint import network.loki.messenger.R import network.loki.messenger.databinding.ViewInputBarBinding import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview -import org.session.libsession.utilities.Address import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.getColorFromAttr import org.session.libsession.utilities.recipients.Recipient @@ -300,6 +299,10 @@ class InputBar @JvmOverloads constructor( requestLayout() } + override fun onPaste() { + delegate?.onInputBarEditTextPasted() + } + private fun showOrHideInputIfNeeded() { if (!showInput) { cancelQuoteDraft() @@ -383,6 +386,7 @@ class InputBar @JvmOverloads constructor( interface InputBarDelegate { fun inputBarEditTextContentChanged(newContent: CharSequence) + fun onInputBarEditTextPasted() {} // no-op by default fun toggleAttachmentOptions() fun showVoiceMessageUI() fun startRecordingVoiceMessage() diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBarEditText.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBarEditText.kt index f70dab9f55..3995c32ce1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBarEditText.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBarEditText.kt @@ -6,14 +6,10 @@ import android.net.Uri import android.util.AttributeSet import android.view.inputmethod.EditorInfo import android.view.inputmethod.InputConnection -import android.widget.RelativeLayout import androidx.appcompat.widget.AppCompatEditText import androidx.core.view.inputmethod.EditorInfoCompat import androidx.core.view.inputmethod.InputConnectionCompat -import org.thoughtcrime.securesms.conversation.v2.utilities.TextUtilities import org.thoughtcrime.securesms.util.toPx -import kotlin.math.max -import kotlin.math.min import kotlin.math.roundToInt class InputBarEditText : AppCompatEditText { @@ -22,7 +18,6 @@ class InputBarEditText : AppCompatEditText { var allowMultimediaInput: Boolean = true - constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet) : super(context, attrs) constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) @@ -30,6 +25,22 @@ class InputBarEditText : AppCompatEditText { override fun onTextChanged(text: CharSequence, start: Int, lengthBefore: Int, lengthAfter: Int) { super.onTextChanged(text, start, lengthBefore, lengthAfter) delegate?.inputBarEditTextContentChanged(text) + + // - A "chunk" got inserted (lengthAfter >= 3) + // - If it is large enough, treat it as paste. We do this because some IME's clipboard history + // will not be treated as a "paste" but instead just a normal text insertion + if (lengthAfter >= 3) { // catch most real paste + val inserted = safeSubSequence(text, start, start + lengthAfter) + if (!inserted.isNullOrEmpty()) { + // Bulk insert will mostly come from IME that supports clipboard history + val isBulkInsert = inserted.length >= 5 // small enough to catch URIs + + if (isBulkInsert) { + delegate?.onPaste() + } + } + } + // Calculate the width manually to get it right even before layout has happened (i.e. // when restoring a draft). The 64 DP is the horizontal margin around the input bar // edit text. @@ -37,6 +48,12 @@ class InputBarEditText : AppCompatEditText { if (width < 0) { return } // screenWidth initially evaluates to 0 } + // Small helper to avoid IndexOutOfBounds on weird IME behavior + private fun safeSubSequence(text: CharSequence, start: Int, end: Int): String? { + if (start < 0 || end > text.length || start >= end) return null + return text.subSequence(start, end).toString() + } + override fun onCreateInputConnection(editorInfo: EditorInfo): InputConnection? { val ic = super.onCreateInputConnection(editorInfo) ?: return null EditorInfoCompat.setContentMimeTypes(editorInfo, @@ -62,12 +79,15 @@ class InputBarEditText : AppCompatEditText { true // return true if succeeded } + + + return InputConnectionCompat.createWrapper(ic, editorInfo, callback) } - } interface InputBarEditTextDelegate { fun inputBarEditTextContentChanged(text: CharSequence) fun commitInputContent(contentUri: Uri) + fun onPaste() } \ No newline at end of file