Handle text only quote drafts

pull/619/head
Niels Andriesse 4 years ago
parent 9419bafe93
commit 123cd6d486

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

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

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

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

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

@ -53,17 +53,9 @@ class VisibleMessageView : LinearLayout {
} }
// region Lifecycle // region Lifecycle
constructor(context: Context) : super(context) { constructor(context: Context) : super(context) { initialize() }
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) {
initialize()
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
initialize()
}
private fun initialize() { private fun initialize() {
LayoutInflater.from(context).inflate(R.layout.view_visible_message, this) LayoutInflater.from(context).inflate(R.layout.view_visible_message, this)

@ -3,7 +3,10 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/input_bar_background" android:background="@color/input_bar_background"
android:paddingHorizontal="@dimen/medium_spacing"
android:paddingVertical="6dp"
android:gravity="center_vertical"> android:gravity="center_vertical">
<View <View
@ -14,12 +17,13 @@
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:background="@color/text" /> 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 <LinearLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="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_alignParentStart="true"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:orientation="vertical"> android:orientation="vertical">
@ -50,9 +54,10 @@
<ImageView <ImageView
android:layout_width="32dp" android:layout_width="32dp"
android:layout_height="32dp" android:layout_height="32dp"
android:padding="8dp" android:padding="6dp"
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:src="@drawable/ic_x_28" /> android:src="@drawable/ic_close_white_48dp"
app:tint="@color/text" />
</RelativeLayout> </RelativeLayout>

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