mirror of
https://github.com/oxen-io/session-android.git
synced 2023-12-14 02:53:01 +01:00
55aa266769
* refactor: removing unused strings and changing session header dimensions * refactor: remove bodyTextView from LinkPreviewView.kt and changing header image colours * fix: path layout is aligned, global search input should always prompt soft input on open * fix: unread count and scroll to bottom button visibility properly taking into account adapter item count and RecyclerView.NO_POSITION fixes #848 * fix: crash on error toast for failing to share logs * feat: conversation tooltips in NewConversationButtonSetView.kt * fix: UI issue for conversation action bar cutting off lower than baseline characters fixes #839 * refactor (wip): replacing bindings with nullable types to try prevent mystery bug * refactor: use the nullable bindings for ConversationActivityV2.kt and remove inputBarHeightChanged * fix: remove recipient listener on destroy * build: add latest strings and increase build
186 lines
8.1 KiB
Kotlin
186 lines
8.1 KiB
Kotlin
package org.thoughtcrime.securesms.conversation.v2.input_bar
|
|
|
|
import android.content.Context
|
|
import android.content.res.Resources
|
|
import android.net.Uri
|
|
import android.text.InputType
|
|
import android.text.TextWatcher
|
|
import android.util.AttributeSet
|
|
import android.view.LayoutInflater
|
|
import android.view.MotionEvent
|
|
import android.widget.RelativeLayout
|
|
import androidx.core.view.isVisible
|
|
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.TextSecurePreferences
|
|
import org.session.libsession.utilities.recipients.Recipient
|
|
import org.thoughtcrime.securesms.conversation.v2.components.LinkPreviewDraftView
|
|
import org.thoughtcrime.securesms.conversation.v2.components.LinkPreviewDraftViewDelegate
|
|
import org.thoughtcrime.securesms.conversation.v2.messages.QuoteView
|
|
import org.thoughtcrime.securesms.conversation.v2.messages.QuoteViewDelegate
|
|
import org.thoughtcrime.securesms.database.model.MessageRecord
|
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
|
import org.thoughtcrime.securesms.mms.GlideRequests
|
|
import org.thoughtcrime.securesms.util.toDp
|
|
import org.thoughtcrime.securesms.util.toPx
|
|
|
|
class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, LinkPreviewDraftViewDelegate {
|
|
private lateinit var binding: ViewInputBarBinding
|
|
private val screenWidth = Resources.getSystem().displayMetrics.widthPixels
|
|
private val vMargin by lazy { toDp(4, resources) }
|
|
private val minHeight by lazy { toPx(56, resources) }
|
|
private var linkPreviewDraftView: LinkPreviewDraftView? = null
|
|
var delegate: InputBarDelegate? = null
|
|
var additionalContentHeight = 0
|
|
var quote: MessageRecord? = null
|
|
var linkPreview: LinkPreview? = null
|
|
var showInput: Boolean = true
|
|
set(value) { field = value; showOrHideInputIfNeeded() }
|
|
|
|
var text: String
|
|
get() { return binding.inputBarEditText.text?.toString() ?: "" }
|
|
set(value) { binding.inputBarEditText.setText(value) }
|
|
|
|
val attachmentButtonsContainerHeight: Int
|
|
get() = binding.attachmentsButtonContainer.height
|
|
|
|
private val attachmentsButton by lazy { InputBarButton(context, R.drawable.ic_plus_24) }
|
|
private val microphoneButton by lazy { InputBarButton(context, R.drawable.ic_microphone) }
|
|
private val sendButton by lazy { InputBarButton(context, R.drawable.ic_arrow_up, true) }
|
|
|
|
// region Lifecycle
|
|
constructor(context: Context) : super(context) { initialize() }
|
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { initialize() }
|
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { initialize() }
|
|
|
|
private fun initialize() {
|
|
binding = ViewInputBarBinding.inflate(LayoutInflater.from(context), this, true)
|
|
// Attachments button
|
|
binding.attachmentsButtonContainer.addView(attachmentsButton)
|
|
attachmentsButton.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
|
attachmentsButton.onPress = { toggleAttachmentOptions() }
|
|
// Microphone button
|
|
binding.microphoneOrSendButtonContainer.addView(microphoneButton)
|
|
microphoneButton.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
|
microphoneButton.onLongPress = { startRecordingVoiceMessage() }
|
|
microphoneButton.onMove = { delegate?.onMicrophoneButtonMove(it) }
|
|
microphoneButton.onCancel = { delegate?.onMicrophoneButtonCancel(it) }
|
|
microphoneButton.onUp = { delegate?.onMicrophoneButtonUp(it) }
|
|
// Send button
|
|
binding.microphoneOrSendButtonContainer.addView(sendButton)
|
|
sendButton.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
|
sendButton.isVisible = false
|
|
sendButton.onUp = { delegate?.sendMessage() }
|
|
// Edit text
|
|
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.inputType = binding.inputBarEditText.inputType or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
|
|
binding.inputBarEditText.delegate = this
|
|
}
|
|
// endregion
|
|
|
|
// region Updating
|
|
override fun inputBarEditTextContentChanged(text: CharSequence) {
|
|
sendButton.isVisible = text.isNotEmpty()
|
|
microphoneButton.isVisible = text.isEmpty()
|
|
delegate?.inputBarEditTextContentChanged(text)
|
|
}
|
|
|
|
override fun inputBarEditTextHeightChanged(newValue: Int) {
|
|
}
|
|
|
|
override fun commitInputContent(contentUri: Uri) {
|
|
delegate?.commitInputContent(contentUri)
|
|
}
|
|
|
|
private fun toggleAttachmentOptions() {
|
|
delegate?.toggleAttachmentOptions()
|
|
}
|
|
|
|
private fun 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) {
|
|
quote = message
|
|
linkPreview = null
|
|
linkPreviewDraftView = null
|
|
binding.inputBarAdditionalContentContainer.removeAllViews()
|
|
val quoteView = QuoteView(context, QuoteView.Mode.Draft)
|
|
quoteView.delegate = this
|
|
binding.inputBarAdditionalContentContainer.addView(quoteView)
|
|
val attachments = (message as? MmsMessageRecord)?.slideDeck
|
|
val sender = if (message.isOutgoing) TextSecurePreferences.getLocalNumber(context)!! else message.individualRecipient.address.serialize()
|
|
quoteView.bind(sender, message.body, attachments,
|
|
thread, true, message.isOpenGroupInvitation, message.threadId, false, glide)
|
|
requestLayout()
|
|
}
|
|
|
|
override fun cancelQuoteDraft() {
|
|
quote = null
|
|
binding.inputBarAdditionalContentContainer.removeAllViews()
|
|
requestLayout()
|
|
}
|
|
|
|
fun draftLinkPreview() {
|
|
quote = null
|
|
binding.inputBarAdditionalContentContainer.removeAllViews()
|
|
val linkPreviewDraftView = LinkPreviewDraftView(context)
|
|
linkPreviewDraftView.delegate = this
|
|
this.linkPreviewDraftView = linkPreviewDraftView
|
|
binding.inputBarAdditionalContentContainer.addView(linkPreviewDraftView)
|
|
requestLayout()
|
|
}
|
|
|
|
fun updateLinkPreviewDraft(glide: GlideRequests, linkPreview: LinkPreview) {
|
|
this.linkPreview = linkPreview
|
|
val linkPreviewDraftView = this.linkPreviewDraftView ?: return
|
|
linkPreviewDraftView.update(glide, linkPreview)
|
|
}
|
|
|
|
override fun cancelLinkPreviewDraft() {
|
|
if (quote != null) { return }
|
|
linkPreview = null
|
|
binding.inputBarAdditionalContentContainer.removeAllViews()
|
|
requestLayout()
|
|
}
|
|
|
|
private fun showOrHideInputIfNeeded() {
|
|
if (showInput) {
|
|
setOf( binding.inputBarEditText, attachmentsButton ).forEach { it.isVisible = true }
|
|
microphoneButton.isVisible = text.isEmpty()
|
|
sendButton.isVisible = text.isNotEmpty()
|
|
} else {
|
|
cancelQuoteDraft()
|
|
cancelLinkPreviewDraft()
|
|
val views = setOf( binding.inputBarEditText, attachmentsButton, microphoneButton, sendButton )
|
|
views.forEach { it.isVisible = false }
|
|
}
|
|
}
|
|
|
|
fun addTextChangedListener(textWatcher: TextWatcher) {
|
|
binding.inputBarEditText.addTextChangedListener(textWatcher)
|
|
}
|
|
|
|
fun setSelection(index: Int) {
|
|
binding.inputBarEditText.setSelection(index)
|
|
}
|
|
// endregion
|
|
}
|
|
|
|
interface InputBarDelegate {
|
|
|
|
fun inputBarEditTextContentChanged(newContent: CharSequence)
|
|
fun toggleAttachmentOptions()
|
|
fun showVoiceMessageUI()
|
|
fun startRecordingVoiceMessage()
|
|
fun onMicrophoneButtonMove(event: MotionEvent)
|
|
fun onMicrophoneButtonCancel(event: MotionEvent)
|
|
fun onMicrophoneButtonUp(event: MotionEvent)
|
|
fun sendMessage()
|
|
fun commitInputContent(contentUri: Uri)
|
|
} |