Allow links and replies in input bar

Fixes oxen-io/session-android#704 (#1387)
This commit is contained in:
Al Lansley 2024-01-15 16:07:36 +11:00 committed by GitHub
parent 377460a60f
commit c366574521
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 43 additions and 28 deletions

View File

@ -37,6 +37,7 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li
private val vMargin by lazy { toDp(4, resources) } private val vMargin by lazy { toDp(4, resources) }
private val minHeight by lazy { toPx(56, resources) } private val minHeight by lazy { toPx(56, resources) }
private var linkPreviewDraftView: LinkPreviewDraftView? = null private var linkPreviewDraftView: LinkPreviewDraftView? = null
private var quoteView: QuoteView? = null
var delegate: InputBarDelegate? = null var delegate: InputBarDelegate? = null
var additionalContentHeight = 0 var additionalContentHeight = 0
var quote: MessageRecord? = null var quote: MessageRecord? = null
@ -98,7 +99,7 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li
binding.inputBarEditText.imeOptions = EditorInfo.IME_ACTION_NONE binding.inputBarEditText.imeOptions = EditorInfo.IME_ACTION_NONE
binding.inputBarEditText.inputType = binding.inputBarEditText.inputType =
binding.inputBarEditText.inputType or binding.inputBarEditText.inputType or
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
} }
val incognitoFlag = if (TextSecurePreferences.isIncognitoKeyboardEnabled(context)) 16777216 else 0 val incognitoFlag = if (TextSecurePreferences.isIncognitoKeyboardEnabled(context)) 16777216 else 0
binding.inputBarEditText.imeOptions = binding.inputBarEditText.imeOptions or incognitoFlag // Always use incognito keyboard if setting enabled binding.inputBarEditText.imeOptions = binding.inputBarEditText.imeOptions or incognitoFlag // Always use incognito keyboard if setting enabled
@ -138,53 +139,64 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li
delegate?.startRecordingVoiceMessage() delegate?.startRecordingVoiceMessage()
} }
// Drafting quotes and drafting link previews is mutually exclusive, i.e. you can't draft
// a quote and a link preview at the same time.
fun draftQuote(thread: Recipient, message: MessageRecord, glide: GlideRequests) { fun draftQuote(thread: Recipient, message: MessageRecord, glide: GlideRequests) {
quote = message quote = message
linkPreview = null
linkPreviewDraftView = null
binding.inputBarAdditionalContentContainer.removeAllViews()
// inflate quoteview with typed array here // If we already have a link preview View then clear the 'additional content' layout so that
// our quote View is always the first element (i.e., at the top of the reply).
if (linkPreview != null && linkPreviewDraftView != null) {
binding.inputBarAdditionalContentContainer.removeAllViews()
}
// Inflate quote View with typed array here
val layout = LayoutInflater.from(context).inflate(R.layout.view_quote_draft, binding.inputBarAdditionalContentContainer, false) val layout = LayoutInflater.from(context).inflate(R.layout.view_quote_draft, binding.inputBarAdditionalContentContainer, false)
val quoteView = layout.findViewById<QuoteView>(R.id.mainQuoteViewContainer) quoteView = layout.findViewById<QuoteView>(R.id.mainQuoteViewContainer).also {
quoteView.delegate = this it.delegate = this
binding.inputBarAdditionalContentContainer.addView(layout) binding.inputBarAdditionalContentContainer.addView(layout)
val attachments = (message as? MmsMessageRecord)?.slideDeck val attachments = (message as? MmsMessageRecord)?.slideDeck
val sender = if (message.isOutgoing) TextSecurePreferences.getLocalNumber(context)!! else message.individualRecipient.address.serialize() val sender = if (message.isOutgoing) TextSecurePreferences.getLocalNumber(context)!! else message.individualRecipient.address.serialize()
quoteView.bind(sender, message.body, attachments, it.bind(sender, message.body, attachments, thread, true, message.isOpenGroupInvitation, message.threadId, false, glide)
thread, true, message.isOpenGroupInvitation, message.threadId, false, glide) }
// Before we request a layout update we'll add back any LinkPreviewDraftView that might
// exist - as this goes into the LinearLayout second it will be below the quote View.
if (linkPreview != null && linkPreviewDraftView != null) {
binding.inputBarAdditionalContentContainer.addView(linkPreviewDraftView)
}
requestLayout() requestLayout()
} }
override fun cancelQuoteDraft() { override fun cancelQuoteDraft() {
binding.inputBarAdditionalContentContainer.removeView(quoteView)
quote = null quote = null
binding.inputBarAdditionalContentContainer.removeAllViews() quoteView = null
requestLayout() requestLayout()
} }
fun draftLinkPreview() { fun draftLinkPreview() {
quote = null // As `draftLinkPreview` is called before `updateLinkPreview` when we modify a URI in a
binding.inputBarAdditionalContentContainer.removeAllViews() // message we'll bail early if a link preview View already exists and just let
val linkPreviewDraftView = LinkPreviewDraftView(context) // `updateLinkPreview` get called to update the existing View.
linkPreviewDraftView.delegate = this if (linkPreview != null && linkPreviewDraftView != null) return
this.linkPreviewDraftView = linkPreviewDraftView
linkPreviewDraftView = LinkPreviewDraftView(context).also { it.delegate = this }
// Add the link preview View. Note: If there's already a quote View in the 'additional
// content' container then this preview View will be added after / below it - which is fine.
binding.inputBarAdditionalContentContainer.addView(linkPreviewDraftView) binding.inputBarAdditionalContentContainer.addView(linkPreviewDraftView)
requestLayout() requestLayout()
} }
fun updateLinkPreviewDraft(glide: GlideRequests, linkPreview: LinkPreview) { fun updateLinkPreviewDraft(glide: GlideRequests, updatedLinkPreview: LinkPreview) {
this.linkPreview = linkPreview // Update our `linkPreview` property with the new (provided as an argument to this function)
val linkPreviewDraftView = this.linkPreviewDraftView ?: return // then update the View from that.
linkPreviewDraftView.update(glide, linkPreview) linkPreview = updatedLinkPreview.also { linkPreviewDraftView?.update(glide, it) }
} }
override fun cancelLinkPreviewDraft() { override fun cancelLinkPreviewDraft() {
if (quote != null) { return } binding.inputBarAdditionalContentContainer.removeView(linkPreviewDraftView)
linkPreview = null linkPreview = null
binding.inputBarAdditionalContentContainer.removeAllViews() linkPreviewDraftView = null
requestLayout() requestLayout()
} }

View File

@ -12,8 +12,11 @@
android:layout_height="1px" android:layout_height="1px"
android:background="@color/separator" /> android:background="@color/separator" />
<FrameLayout <!-- Additional content layout is a LinearLayout with a vertical split (i.e., it uses rows) to
allow multiple Views to exist, specifically both QuoteDraft and LinkPreviewDraft Views -->
<LinearLayout
android:id="@+id/inputBarAdditionalContentContainer" android:id="@+id/inputBarAdditionalContentContainer"
android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />