diff --git a/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt b/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt index c6041ccd4..5d2e87ba2 100644 --- a/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt @@ -79,7 +79,6 @@ import com.nextcloud.talk.utils.SpreedFeatures import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew import com.nextcloud.talk.utils.text.Spans import com.otaliastudios.autocomplete.Autocomplete -import com.stfalcon.chatkit.commons.models.IMessage import com.vanniktech.emoji.EmojiPopup import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.onEach @@ -87,7 +86,7 @@ import kotlinx.coroutines.launch import java.util.Objects import javax.inject.Inject -@Suppress("LongParameterList", "TooManyFunctions") +@Suppress("LongParameterList", "TooManyFunctions", "LargeClass", "LongMethod") @AutoInjector(NextcloudTalkApplication::class) class MessageInputFragment : Fragment() { @@ -110,6 +109,10 @@ class MessageInputFragment : Fragment() { private const val CONNECTION_ESTABLISHED_ANIM_DURATION: Long = 3000 private const val FULLY_OPAQUE: Float = 1.0f private const val FULLY_TRANSPARENT: Float = 0.0f + const val QUOTED_MESSAGE_TEXT = "QUOTED_MESSAGE_TEXT" + const val QUOTED_MESSAGE_ID = "QUOTED_MESSAGE_ID" + const val QUOTED_MESSAGE_URL = "QUOTED_MESSAGE_URL" + const val QUOTED_MESSAGE_NAME = "QUOTED_MESSAGE_NAME" } @Inject @@ -134,6 +137,10 @@ class MessageInputFragment : Fragment() { private var xcounter = 0f private var ycounter = 0f private var collapsed = false + private var quotedMessageText: String? = "" + private var quotedActorDisplayName: String? = null + private var quotedImageUrl: String? = null + private var quotedJsonId: Int = -1 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -157,8 +164,8 @@ class MessageInputFragment : Fragment() { } override fun onPause() { - super.onPause() saveState() + super.onPause() } override fun onDestroyView() { @@ -167,7 +174,10 @@ class MessageInputFragment : Fragment() { mentionAutocomplete?.dismissPopup() } clearEditUI() - cancelReply() + val isInReplyState = (quotedJsonId != -1 && quotedActorDisplayName != null && quotedMessageText != "") + if (!isInReplyState) { + cancelReply() + } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -178,7 +188,13 @@ class MessageInputFragment : Fragment() { private fun initObservers() { Log.d(TAG, "LifeCyclerOwner is: ${viewLifecycleOwner.lifecycle}") chatActivity.messageInputViewModel.getReplyChatMessage.observe(viewLifecycleOwner) { message -> - message?.let { replyToMessage(message) } + (message as ChatMessage?)?.let { + quotedMessageText = message.text + quotedActorDisplayName = message.actorDisplayName + quotedImageUrl = message.imageUrl + quotedJsonId = message.jsonMessageId + replyToMessage(message.text, message.actorDisplayName, message.imageUrl, message.jsonMessageId) + } } chatActivity.messageInputViewModel.getEditChatMessage.observe(viewLifecycleOwner) { message -> @@ -295,11 +311,20 @@ class MessageInputFragment : Fragment() { private fun restoreState() { if (binding.fragmentMessageInputView.inputEditText.text.isEmpty()) { + Log.d("Julius", "State restored from: ${chatActivity.localClassName}") requireContext().getSharedPreferences(chatActivity.localClassName, AppCompatActivity.MODE_PRIVATE).apply { val text = getString(chatActivity.roomToken, "") val cursor = getInt(chatActivity.roomToken + CURSOR_KEY, 0) binding.fragmentMessageInputView.messageInput.setText(text) binding.fragmentMessageInputView.messageInput.setSelection(cursor) + quotedJsonId = getInt(QUOTED_MESSAGE_ID, -1) + quotedImageUrl = getString(QUOTED_MESSAGE_URL, null) + quotedMessageText = getString(QUOTED_MESSAGE_TEXT, "") + quotedActorDisplayName = getString(QUOTED_MESSAGE_NAME, null) + val isInReplyState = (quotedJsonId != -1 && quotedActorDisplayName != null && quotedMessageText != "") + if (isInReplyState) { + replyToMessage(quotedMessageText, quotedActorDisplayName, quotedImageUrl, quotedJsonId) + } } } } @@ -313,15 +338,23 @@ class MessageInputFragment : Fragment() { .MODE_PRIVATE ).getString(chatActivity.roomToken, "null") - if (text != previous) { - requireContext().getSharedPreferences( - chatActivity.localClassName, - AppCompatActivity.MODE_PRIVATE - ).edit().apply { + val isInReplyState = (quotedJsonId != -1 && quotedActorDisplayName != null && quotedMessageText != "") + requireContext().getSharedPreferences( + chatActivity.localClassName, + AppCompatActivity.MODE_PRIVATE + ).edit().apply { + if (text != previous) { putString(chatActivity.roomToken, text) putInt(chatActivity.roomToken + CURSOR_KEY, cursor) - apply() } + + if (isInReplyState) { + putInt(QUOTED_MESSAGE_ID, quotedJsonId) + putString(QUOTED_MESSAGE_NAME, quotedActorDisplayName) + putString(QUOTED_MESSAGE_TEXT, quotedMessageText) + putString(QUOTED_MESSAGE_URL, quotedImageUrl) // may be null + } + apply() } } @@ -598,7 +631,7 @@ class MessageInputFragment : Fragment() { } } } - v?.onTouchEvent(event) ?: true + v?.onTouchEvent(event) != false } } @@ -700,52 +733,54 @@ class MessageInputFragment : Fragment() { } } - private fun replyToMessage(message: IMessage?) { + private fun replyToMessage( + quotedMessageText: String?, + quotedActorDisplayName: String?, + quotedImageUrl: String?, + quotedJsonId: Int + ) { Log.d(TAG, "Reply") - val chatMessage = message as ChatMessage? - chatMessage?.let { - val view = binding.fragmentMessageInputView - view.findViewById(R.id.attachmentButton)?.visibility = - View.GONE - view.findViewById(R.id.cancelReplyButton)?.visibility = - View.VISIBLE + val view = binding.fragmentMessageInputView + view.findViewById(R.id.attachmentButton)?.visibility = + View.GONE + view.findViewById(R.id.cancelReplyButton)?.visibility = + View.VISIBLE - val quotedMessage = view.findViewById(R.id.quotedMessage) + val quotedMessage = view.findViewById(R.id.quotedMessage) - quotedMessage?.maxLines = 2 - quotedMessage?.ellipsize = TextUtils.TruncateAt.END - quotedMessage?.text = it.text - view.findViewById(R.id.quotedMessageAuthor)?.text = - it.actorDisplayName ?: requireContext().getText(R.string.nc_nick_guest) + quotedMessage?.maxLines = 2 + quotedMessage?.ellipsize = TextUtils.TruncateAt.END + quotedMessage?.text = quotedMessageText + view.findViewById(R.id.quotedMessageAuthor)?.text = + quotedActorDisplayName ?: requireContext().getText(R.string.nc_nick_guest) - chatActivity.conversationUser?.let { - val quotedMessageImage = view.findViewById(R.id.quotedMessageImage) - chatMessage.imageUrl?.let { previewImageUrl -> - quotedMessageImage?.visibility = View.VISIBLE + chatActivity.conversationUser?.let { + val quotedMessageImage = view.findViewById(R.id.quotedMessageImage) + quotedImageUrl.let { previewImageUrl -> + quotedMessageImage?.visibility = View.VISIBLE - val px = TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, - QUOTED_MESSAGE_IMAGE_MAX_HEIGHT, - resources.displayMetrics - ) + val px = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + QUOTED_MESSAGE_IMAGE_MAX_HEIGHT, + resources.displayMetrics + ) - quotedMessageImage?.maxHeight = px.toInt() - val layoutParams = quotedMessageImage?.layoutParams as FlexboxLayout.LayoutParams - layoutParams.flexGrow = 0f - quotedMessageImage.layoutParams = layoutParams - quotedMessageImage.load(previewImageUrl) { - addHeader("Authorization", chatActivity.credentials!!) - } - } ?: run { - view.findViewById(R.id.quotedMessageImage)?.visibility = View.GONE + quotedMessageImage?.maxHeight = px.toInt() + val layoutParams = quotedMessageImage?.layoutParams as FlexboxLayout.LayoutParams + layoutParams.flexGrow = 0f + quotedMessageImage.layoutParams = layoutParams + quotedMessageImage.load(previewImageUrl) { + addHeader("Authorization", chatActivity.credentials!!) } + } ?: run { + view.findViewById(R.id.quotedMessageImage)?.visibility = View.GONE } - - val quotedChatMessageView = - view.findViewById(R.id.quotedChatMessageView) - quotedChatMessageView?.tag = message?.jsonMessageId - quotedChatMessageView?.visibility = View.VISIBLE } + + val quotedChatMessageView = + view.findViewById(R.id.quotedChatMessageView) + quotedChatMessageView?.tag = quotedJsonId + quotedChatMessageView?.visibility = View.VISIBLE } fun updateOwnTypingStatus(typedText: CharSequence) { @@ -1020,5 +1055,21 @@ class MessageInputFragment : Fragment() { quote.tag = null binding.fragmentMessageInputView.findViewById(R.id.attachmentButton)?.visibility = View.VISIBLE chatActivity.messageInputViewModel.reply(null) + + quotedMessageText = "" + quotedActorDisplayName = null + quotedImageUrl = null + quotedJsonId = -1 + + requireContext().getSharedPreferences( + chatActivity.localClassName, + AppCompatActivity.MODE_PRIVATE + ).edit().apply { + putInt(QUOTED_MESSAGE_ID, quotedJsonId) + putString(QUOTED_MESSAGE_NAME, quotedActorDisplayName) + putString(QUOTED_MESSAGE_TEXT, quotedMessageText) + putString(QUOTED_MESSAGE_URL, quotedImageUrl) // may be null + apply() + } } } diff --git a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt index 3bf0610d5..29defd12e 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt @@ -85,6 +85,10 @@ import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.arbitrarystorage.ArbitraryStorageManager import com.nextcloud.talk.chat.ChatActivity +import com.nextcloud.talk.chat.MessageInputFragment.Companion.QUOTED_MESSAGE_ID +import com.nextcloud.talk.chat.MessageInputFragment.Companion.QUOTED_MESSAGE_NAME +import com.nextcloud.talk.chat.MessageInputFragment.Companion.QUOTED_MESSAGE_TEXT +import com.nextcloud.talk.chat.MessageInputFragment.Companion.QUOTED_MESSAGE_URL import com.nextcloud.talk.chat.viewmodels.ChatViewModel import com.nextcloud.talk.contacts.ContactsActivity import com.nextcloud.talk.contacts.ContactsUiState @@ -306,6 +310,16 @@ class ConversationsListActivity : showNotificationWarning() showShareToScreen = hasActivityActionSendIntent() + context.getSharedPreferences( + CHAT_ACTIVITY_LOCAL_NAME, + MODE_PRIVATE + ).edit().apply { + putInt(QUOTED_MESSAGE_ID, -1) + putString(QUOTED_MESSAGE_NAME, null) + putString(QUOTED_MESSAGE_TEXT, "") + putString(QUOTED_MESSAGE_URL, null) + apply() + } if (!eventBus.isRegistered(this)) { eventBus.register(this) @@ -2196,6 +2210,7 @@ class ConversationsListActivity : const val UNREAD_BUBBLE_DELAY = 2500 const val BOTTOM_SHEET_DELAY: Long = 2500 private const val KEY_SEARCH_QUERY = "ConversationsListActivity.searchQuery" + private const val CHAT_ACTIVITY_LOCAL_NAME = "com.nextcloud.talk.chat.ChatActivity" const val SEARCH_DEBOUNCE_INTERVAL_MS = 300 const val SEARCH_MIN_CHARS = 1 const val HTTP_UNAUTHORIZED = 401