From 7d2fffd16552317f3975bc3bb17f49863d5ff26f Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Wed, 8 Apr 2020 18:23:32 +0200 Subject: [PATCH] Fix #714 Signed-off-by: Mario Danic --- app/build.gradle | 1 + .../newarch/features/chat/ChatPresenter.kt | 1 - .../talk/newarch/features/chat/ChatView.kt | 104 +++++++++++------- .../talk/newarch/utils/ChatSwipeCallback.kt | 27 +++++ app/src/main/res/drawable/ic_round_shape.xml | 12 ++ app/src/main/res/layout/rv_chat_item.xml | 3 +- 6 files changed, 105 insertions(+), 43 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/talk/newarch/utils/ChatSwipeCallback.kt create mode 100644 app/src/main/res/drawable/ic_round_shape.xml diff --git a/app/build.gradle b/app/build.gradle index 9166a16a9..1ba26aeef 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -305,6 +305,7 @@ dependencies { implementation 'com.github.mario:PopupBubble:a365177d96' implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' implementation 'eu.medsea.mimeutil:mime-util:2.1.3' + implementation 'com.github.izjumovfs:SwipeToReply:1.0.1' implementation 'com.afollestad.material-dialogs:core:3.1.0' implementation 'com.afollestad.material-dialogs:datetime:3.1.0' diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/chat/ChatPresenter.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/chat/ChatPresenter.kt index 128a728f6..4de7643e4 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/features/chat/ChatPresenter.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/chat/ChatPresenter.kt @@ -46,7 +46,6 @@ open class ChatPresenter(context: Context, private val onElementClickPa override fun onBind(page: Page, holder: Holder, element: Element, payloads: List) { super.onBind(page, holder, element, payloads) - holder.itemView.setOnLongClickListener { onElementLongClick?.invoke(page, holder, element, mapOf()) true diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/chat/ChatView.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/chat/ChatView.kt index 231690f41..e0c576da8 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/features/chat/ChatView.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/chat/ChatView.kt @@ -36,12 +36,12 @@ import android.text.Editable import android.text.InputFilter import android.text.TextUtils import android.text.TextWatcher -import android.util.TypedValue import android.view.* import android.widget.ImageView import android.widget.PopupMenu import androidx.core.view.isVisible import androidx.lifecycle.observe +import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import coil.ImageLoader @@ -54,6 +54,7 @@ import com.bluelinelabs.conductor.archlifecycle.ControllerLifecycleOwner import com.bluelinelabs.conductor.autodispose.ControllerScopeProvider import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler +import com.capybaralabs.swipetoreply.ISwipeControllerActions import com.nextcloud.talk.R import com.nextcloud.talk.activities.MagicCallActivity import com.nextcloud.talk.callbacks.MentionAutocompleteCallback @@ -68,6 +69,7 @@ import com.nextcloud.talk.newarch.local.models.getMaxMessageLength import com.nextcloud.talk.newarch.local.models.toUserEntity import com.nextcloud.talk.newarch.mvvm.BaseView import com.nextcloud.talk.newarch.mvvm.ext.initRecyclerView +import com.nextcloud.talk.newarch.utils.ChatSwipeCallback import com.nextcloud.talk.newarch.utils.Images import com.nextcloud.talk.newarch.utils.NetworkComponents import com.nextcloud.talk.presenters.MentionAutocompletePresenter @@ -93,7 +95,6 @@ import com.vanniktech.emoji.EmojiPopup import kotlinx.android.synthetic.main.controller_chat.view.* import kotlinx.android.synthetic.main.item_message_quote.view.* import kotlinx.android.synthetic.main.lobby_view.view.* -import kotlinx.android.synthetic.main.rv_chat_item.view.* import kotlinx.android.synthetic.main.view_message_input.view.* import org.koin.android.ext.android.inject import org.parceler.Parcels @@ -247,6 +248,21 @@ class ChatView(private val bundle: Bundle) : BaseView(), ImageLoaderInterface { } view.cancelReplyButton.setOnClickListener { hideReplyView() } + + val controller = ChatSwipeCallback(messagesAdapter, context, ISwipeControllerActions { + val element = messagesAdapter.elementAt(it) + if (element != null) { + val adapterChatElement = element.element as Element + if (adapterChatElement.data is ChatElement) { + val chatElement = adapterChatElement.data as ChatElement + view.messagesRecyclerView.postDelayed({ showReplyView(chatElement.data as ChatMessage)}, 50) + } + } + }) + + val itemTouchHelper = ItemTouchHelper(controller) + itemTouchHelper.attachToRecyclerView(view.messagesRecyclerView) + return view } @@ -359,6 +375,49 @@ class ChatView(private val bundle: Bundle) : BaseView(), ImageLoaderInterface { } } } + + private fun showReplyView(chatMessage: ChatMessage) { + view?.let { + with(it.messageInputView) { + attachmentButton.isVisible = false + attachmentButtonSpace.isVisible = false + cancelReplyButton.isVisible = true + quotedChatText.maxLines = 2 + quotedChatText.ellipsize = TextUtils.TruncateAt.END + quotedChatText.text = chatMessage.text + quotedAuthor.text = chatMessage.user.name + quotedMessageTime.text = DateFormatter.format(chatMessage.createdAt, DateFormatter.Template.TIME) + + loadImage(quotedUserAvatar, chatMessage.user.avatar) + + chatMessage.imageUrl?.let { previewImageUrl -> + if (previewImageUrl == "no-preview") { + if (chatMessage.selectedIndividualHashMap?.containsKey("mimetype") == true) { + quotedPreviewImage.isVisible = true + networkComponents.getImageLoader(viewModel.user).loadAny(context, DrawableUtils.getDrawableResourceIdForMimeType(chatMessage.selectedIndividualHashMap!!["mimetype"])) { + target(quotedPreviewImage) } + } else { + quotedPreviewImage.isVisible = false + } + } else { + quotedPreviewImage.isVisible = true + val mutableMap = mutableMapOf() + if (chatMessage.selectedIndividualHashMap?.containsKey("mimetype") == true) { + mutableMap["mimetype"] = chatMessage.selectedIndividualHashMap!!["mimetype"]!! + } + + loadImage(quotedPreviewImage, previewImageUrl, mutableMap) + } + } ?: run { + quotedPreviewImage.isVisible = false + } + quotedMessageLayout.tag = chatMessage.jsonMessageId + quotedMessageLayout.isVisible = true + + } + } + } + private fun onElementLongClick(page: Page, holder: Presenter.Holder, element: Element, payload: Map) { if (element.type == ChatElementTypes.CHAT_MESSAGE.ordinal) { element.data?.let { chatElement -> @@ -367,6 +426,7 @@ class ChatView(private val bundle: Bundle) : BaseView(), ImageLoaderInterface { chatMessage = chatMessage.parentMessage!! } + PopupMenu(this.context, holder.itemView, Gravity.START).apply { setOnMenuItemClickListener { item -> when (item?.itemId) { @@ -379,45 +439,7 @@ class ChatView(private val bundle: Bundle) : BaseView(), ImageLoaderInterface { true } R.id.action_reply_to_message -> { - view?.let { - with(it.messageInputView) { - attachmentButton.isVisible = false - attachmentButtonSpace.isVisible = false - cancelReplyButton.isVisible = true - quotedChatText.maxLines = 2 - quotedChatText.ellipsize = TextUtils.TruncateAt.END - quotedChatText.text = chatMessage.text - quotedAuthor.text = chatMessage.user.name - quotedMessageTime.text = DateFormatter.format(chatMessage.createdAt, DateFormatter.Template.TIME) - - loadImage(quotedUserAvatar, chatMessage.user.avatar) - - chatMessage.imageUrl?.let { previewImageUrl -> - if (previewImageUrl == "no-preview") { - if (chatMessage.selectedIndividualHashMap?.containsKey("mimetype") == true) { - quotedPreviewImage.isVisible = true - networkComponents.getImageLoader(viewModel.user).loadAny(context, DrawableUtils.getDrawableResourceIdForMimeType(chatMessage.selectedIndividualHashMap!!["mimetype"])) { - target(quotedPreviewImage) } - } else { - quotedPreviewImage.isVisible = false - } - } else { - quotedPreviewImage.isVisible = true - val mutableMap = mutableMapOf() - if (chatMessage.selectedIndividualHashMap?.containsKey("mimetype") == true) { - mutableMap["mimetype"] = chatMessage.selectedIndividualHashMap!!["mimetype"]!! - } - - loadImage(quotedPreviewImage, previewImageUrl, mutableMap) - } - } ?: run { - quotedPreviewImage.isVisible = false - } - quotedMessageLayout.tag = chatMessage.jsonMessageId - quotedMessageLayout.isVisible = true - - } - } + showReplyView(chatMessage) true } else -> false diff --git a/app/src/main/java/com/nextcloud/talk/newarch/utils/ChatSwipeCallback.kt b/app/src/main/java/com/nextcloud/talk/newarch/utils/ChatSwipeCallback.kt new file mode 100644 index 000000000..719fbbf04 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/newarch/utils/ChatSwipeCallback.kt @@ -0,0 +1,27 @@ +package com.nextcloud.talk.newarch.utils + +import android.content.Context +import androidx.recyclerview.widget.RecyclerView +import com.capybaralabs.swipetoreply.ISwipeControllerActions +import com.capybaralabs.swipetoreply.SwipeController +import com.nextcloud.talk.newarch.features.chat.ChatElement +import com.nextcloud.talk.newarch.features.chat.ChatElementTypes +import com.otaliastudios.elements.Adapter +import com.otaliastudios.elements.Element + +class ChatSwipeCallback(private val adapter: Adapter, context: Context?, swipeControllerActions: ISwipeControllerActions?) : SwipeController(context, swipeControllerActions) { + override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { + val position: Int = viewHolder.adapterPosition + val element = adapter.elementAt(position) + if (element != null) { + val adapterChatElement = element.element as Element + if (adapterChatElement.data is ChatElement) { + val chatElement = adapterChatElement.data as ChatElement + if (chatElement.elementType == ChatElementTypes.CHAT_MESSAGE) { + return super.getMovementFlags(recyclerView, viewHolder) + } + } + } + return 0 + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_round_shape.xml b/app/src/main/res/drawable/ic_round_shape.xml new file mode 100644 index 000000000..f5dd0a29b --- /dev/null +++ b/app/src/main/res/drawable/ic_round_shape.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/rv_chat_item.xml b/app/src/main/res/layout/rv_chat_item.xml index 660db9602..85afe4019 100644 --- a/app/src/main/res/layout/rv_chat_item.xml +++ b/app/src/main/res/layout/rv_chat_item.xml @@ -3,7 +3,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" xmlns:tools="http://schemas.android.com/tools" - xmlns:app="http://schemas.android.com/apk/res-auto"> + xmlns:app="http://schemas.android.com/apk/res-auto" + android:animateLayoutChanges="true">