Handle text only quote drafts

This commit is contained in:
Niels Andriesse 2021-06-18 15:54:24 +10:00
parent 9419bafe93
commit 123cd6d486
8 changed files with 105 additions and 103 deletions

View File

@ -38,7 +38,7 @@ import kotlin.math.roundToInt
import kotlin.math.sqrt
class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDelegate, InputBarRecordingViewDelegate {
private val lockViewHitMargin by lazy { toPx(40, resources) }
private val screenWidth = Resources.getSystem().displayMetrics.widthPixels
private var threadID: Long = -1
private var actionMode: ActionMode? = null
private var isLockViewExpanded = false
@ -72,9 +72,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
}
private val glide by lazy { GlideApp.with(this) }
private val screenWidth by lazy { Resources.getSystem().displayMetrics.widthPixels }
private val lockViewHitMargin by lazy { toPx(40, resources) }
private val gifButton by lazy { InputBarButton(this, R.drawable.ic_gif_white_24dp, hasOpaqueBackground = true, isGIFButton = true) }
private val documentButton by lazy { InputBarButton(this, R.drawable.ic_document_small_dark, hasOpaqueBackground = true) }
private val libraryButton by lazy { InputBarButton(this, R.drawable.ic_baseline_photo_library_24, hasOpaqueBackground = true) }
@ -150,7 +148,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
}
// endregion
// region Updating
// region Updating & Animation
override fun inputBarHeightChanged(newValue: Int) {
// Recycler view
val recyclerViewLayoutParams = conversationRecyclerView.layoutParams as RelativeLayout.LayoutParams
@ -170,7 +168,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
}
override fun inputBarEditTextContentChanged(newContent: CharSequence) {
// TODO: Work this out further
// TODO: Implement the full mention show/hide logic
if (newContent.contains("@")) {
showMentionCandidates()
} else {
@ -235,7 +233,41 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
animation.start()
}
override fun handleInputBarRecordingViewHidden() {
private fun expandVoiceMessageLockView() {
val animation = ValueAnimator.ofObject(FloatEvaluator(), lockView.scaleX, 1.10f)
animation.duration = 250L
animation.addUpdateListener { animator ->
lockView.scaleX = animator.animatedValue as Float
lockView.scaleY = animator.animatedValue as Float
}
animation.start()
}
private fun collapseVoiceMessageLockView() {
val animation = ValueAnimator.ofObject(FloatEvaluator(), lockView.scaleX, 1.0f)
animation.duration = 250L
animation.addUpdateListener { animator ->
lockView.scaleX = animator.animatedValue as Float
lockView.scaleY = animator.animatedValue as Float
}
animation.start()
}
private fun hideVoiceMessageUI() {
val chevronImageView = inputBarRecordingView.inputBarChevronImageView
val slideToCancelTextView = inputBarRecordingView.inputBarSlideToCancelTextView
listOf( chevronImageView, slideToCancelTextView ).forEach { view ->
val animation = ValueAnimator.ofObject(FloatEvaluator(), view.translationX, 0.0f)
animation.duration = 250L
animation.addUpdateListener { animator ->
view.translationX = animator.animatedValue as Float
}
animation.start()
}
inputBarRecordingView.hide()
}
override fun handleVoiceMessageUIHidden() {
inputBar.alpha = 1.0f
val animation = ValueAnimator.ofObject(FloatEvaluator(), 0.0f, 1.0f)
animation.duration = 250L
@ -311,17 +343,29 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
}
if (isValidLockViewLocation(event.rawX.roundToInt(), event.rawY.roundToInt())) {
if (!isLockViewExpanded) {
expandLockView()
expandVoiceMessageLockView()
isLockViewExpanded = true
}
} else {
if (isLockViewExpanded) {
collapseLockView()
collapseVoiceMessageLockView()
isLockViewExpanded = false
}
}
}
override fun onMicrophoneButtonCancel(event: MotionEvent) {
hideVoiceMessageUI()
}
override fun onMicrophoneButtonUp(event: MotionEvent) {
if (isValidLockViewLocation(event.rawX.roundToInt(), event.rawY.roundToInt())) {
inputBarRecordingView.lock()
} else {
hideVoiceMessageUI()
}
}
private fun isValidLockViewLocation(x: Int, y: Int): Boolean {
val lockViewLocation = IntArray(2) { 0 }
lockView.getLocationOnScreen(lockViewLocation)
@ -329,51 +373,5 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
lockViewLocation[0] + lockView.width + lockViewHitMargin, lockViewLocation[1] + lockView.height)
return hitRect.contains(x, y)
}
private fun expandLockView() {
val animation = ValueAnimator.ofObject(FloatEvaluator(), lockView.scaleX, 1.10f)
animation.duration = 250L
animation.addUpdateListener { animator ->
lockView.scaleX = animator.animatedValue as Float
lockView.scaleY = animator.animatedValue as Float
}
animation.start()
}
private fun collapseLockView() {
val animation = ValueAnimator.ofObject(FloatEvaluator(), lockView.scaleX, 1.0f)
animation.duration = 250L
animation.addUpdateListener { animator ->
lockView.scaleX = animator.animatedValue as Float
lockView.scaleY = animator.animatedValue as Float
}
animation.start()
}
override fun onMicrophoneButtonCancel(event: MotionEvent) {
resetVoiceMessageUI()
}
override fun onMicrophoneButtonUp(event: MotionEvent) {
if (isValidLockViewLocation(event.rawX.roundToInt(), event.rawY.roundToInt())) {
inputBarRecordingView.lock()
} else {
resetVoiceMessageUI()
}
}
private fun resetVoiceMessageUI() {
val chevronImageView = inputBarRecordingView.inputBarChevronImageView
val slideToCancelTextView = inputBarRecordingView.inputBarSlideToCancelTextView
listOf( chevronImageView, slideToCancelTextView ).forEach { view ->
val animation = ValueAnimator.ofObject(FloatEvaluator(), view.translationX, 0.0f)
animation.duration = 250L
animation.addUpdateListener { animator ->
view.translationX = animator.animatedValue as Float
}
animation.start()
}
inputBarRecordingView.hide()
}
// endregion
}

View File

@ -84,7 +84,7 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate {
inputBarAdditionalContentContainer.removeAllViews()
val quoteView = QuoteView(context)
inputBarAdditionalContentContainer.addView(quoteView)
quoteView.bind("", "", null, message.recipient)
quoteView.bind(message.individualRecipient.address.toString(), message.body, null, message.recipient)
val newHeight = height + quoteView.getIntrinsicHeight()
setHeight(newHeight)
}

View File

@ -7,7 +7,6 @@ import android.content.Context
import android.os.Handler
import android.os.Looper
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.widget.RelativeLayout
import androidx.core.content.res.ResourcesCompat
@ -19,7 +18,6 @@ import org.thoughtcrime.securesms.loki.utilities.disableClipping
import org.thoughtcrime.securesms.loki.utilities.toPx
import org.thoughtcrime.securesms.util.DateUtils
import java.util.*
import kotlin.math.roundToLong
class InputBarRecordingView : RelativeLayout {
private var startTimestamp = 0L
@ -71,7 +69,7 @@ class InputBarRecordingView : RelativeLayout {
}
}
animation.start()
delegate?.handleInputBarRecordingViewHidden()
delegate?.handleVoiceMessageUIHidden()
}
private fun animateDotView() {
@ -141,5 +139,5 @@ class InputBarRecordingView : RelativeLayout {
interface InputBarRecordingViewDelegate {
fun handleInputBarRecordingViewHidden()
fun handleVoiceMessageUIHidden()
}

View File

@ -6,16 +6,22 @@ import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.LinearLayout
import android.widget.RelativeLayout
import androidx.core.view.isVisible
import kotlinx.android.synthetic.main.view_quote.view.*
import network.loki.messenger.R
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.conversation.v2.utilities.TextUtilities
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.loki.utilities.toPx
import org.thoughtcrime.securesms.mms.SlideDeck
import kotlin.math.max
import kotlin.math.min
class QuoteView : LinearLayout {
private val screenWidth by lazy { Resources.getSystem().displayMetrics.widthPixels }
private val vPadding by lazy { toPx(6, resources) }
enum class Mode { Regular, Draft }
@ -30,26 +36,43 @@ class QuoteView : LinearLayout {
// endregion
// region General
fun getIntrinsicHeight(): Int {
fun getIntrinsicContentHeight(): Int {
var result = 0
val width = screenWidth
val author = quoteViewAuthorTextView.text
result += TextUtilities.getIntrinsicHeight(author, quoteViewAuthorTextView.paint, width)
val authorTextViewIntrinsicHeight = TextUtilities.getIntrinsicHeight(author, quoteViewAuthorTextView.paint, width)
result += authorTextViewIntrinsicHeight
val body = quoteViewBodyTextView.text
result += TextUtilities.getIntrinsicHeight(body, quoteViewBodyTextView.paint, width)
return result
val bodyTextViewIntrinsicHeight = TextUtilities.getIntrinsicHeight(body, quoteViewBodyTextView.paint, width)
result += bodyTextViewIntrinsicHeight
if (!quoteViewAuthorTextView.isVisible) {
return min(max(result, toPx(32, resources)), toPx(54, resources))
} else {
return min(result, toPx(54, resources) + authorTextViewIntrinsicHeight)
}
}
fun getIntrinsicHeight(): Int {
return getIntrinsicContentHeight() + 2 * vPadding
}
// endregion
// region Updating
fun bind(authorPublicKey: String, body: String, attachments: SlideDeck?, thread: Recipient) {
val contactDB = DatabaseFactory.getSessionContactDatabase(context)
// Author
if (thread.isGroupRecipient) {
val author = contactDB.getContactWithSessionID(authorPublicKey)
val authorDisplayName = author?.displayName(Contact.contextForRecipient(thread)) ?: authorPublicKey
quoteViewAuthorTextView.text = authorDisplayName
}
quoteViewAuthorTextView.isVisible = thread.isGroupRecipient
// Body
quoteViewBodyTextView.text = body
// Accent line
val accentLineLayoutParams = quoteViewAccentLine.layoutParams as RelativeLayout.LayoutParams
accentLineLayoutParams.height = getIntrinsicHeight()
accentLineLayoutParams.height = getIntrinsicContentHeight()
quoteViewAccentLine.layoutParams = accentLineLayoutParams
}
fun recycle() {
// TODO: Implement
}
// endregion
}

View File

@ -11,8 +11,6 @@ import androidx.annotation.DrawableRes
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.BlendModeColorFilterCompat
import androidx.core.graphics.BlendModeCompat
import androidx.core.view.setMargins
import androidx.core.view.setPadding
import kotlinx.android.synthetic.main.view_visible_message_content.view.*
import network.loki.messenger.R
import org.session.libsession.utilities.ThemeUtil
@ -29,19 +27,11 @@ class VisibleMessageContentView : LinearLayout {
// TODO: Large emojis
// region Lifecycle
constructor(context: Context) : super(context) {
setUpViewHierarchy()
}
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() }
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
setUpViewHierarchy()
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
setUpViewHierarchy()
}
private fun setUpViewHierarchy() {
private fun initialize() {
LayoutInflater.from(context).inflate(R.layout.view_visible_message_content, this)
}
// endregion

View File

@ -53,17 +53,9 @@ class VisibleMessageView : LinearLayout {
}
// 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()
}
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() {
LayoutInflater.from(context).inflate(R.layout.view_visible_message, this)

View File

@ -3,7 +3,10 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/input_bar_background"
android:paddingHorizontal="@dimen/medium_spacing"
android:paddingVertical="6dp"
android:gravity="center_vertical">
<View
@ -14,12 +17,13 @@
android:layout_centerVertical="true"
android:background="@color/text" />
<!-- The start margin below is the accent line thickness (4 dp) + small spacing (8 dp) -->
<!-- The start margin below is the accent line thickness (4 dp) + 12 dp -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="30dp"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:orientation="vertical">
@ -50,9 +54,10 @@
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:padding="8dp"
android:padding="6dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_x_28" />
android:src="@drawable/ic_close_white_48dp"
app:tint="@color/text" />
</RelativeLayout>

View File

@ -77,11 +77,7 @@ class Contact(val sessionID: String) {
companion object {
fun contextForRecipient(recipient: Recipient): ContactContext {
return if (recipient.isOpenGroupRecipient) {
ContactContext.OPEN_GROUP
} else {
ContactContext.REGULAR
}
return if (recipient.isOpenGroupRecipient) ContactContext.OPEN_GROUP else ContactContext.REGULAR
}
}
}