Commit 91f8ec46 authored by Leonardo Aramaki's avatar Leonardo Aramaki

Add message action menu item to copy permalink from tapped message

parent 2bd72661
...@@ -291,6 +291,9 @@ class ChatRoomAdapter( ...@@ -291,6 +291,9 @@ class ChatRoomAdapter(
R.id.action_menu_msg_react -> { R.id.action_menu_msg_react -> {
actionSelectListener?.showReactions(id) actionSelectListener?.showReactions(id)
} }
R.id.action_message_permalink -> {
actionSelectListener?.copyPermalink(id)
}
else -> { else -> {
TODO("Not implemented") TODO("Not implemented")
} }
...@@ -310,5 +313,6 @@ class ChatRoomAdapter( ...@@ -310,5 +313,6 @@ class ChatRoomAdapter(
fun showReactions(id: String) fun showReactions(id: String)
fun openDirectMessage(roomName: String, message: String) fun openDirectMessage(roomName: String, message: String)
fun sendMessage(chatRoomId: String, text: String) fun sendMessage(chatRoomId: String, text: String)
fun copyPermalink(id: String)
} }
} }
...@@ -620,6 +620,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -620,6 +620,7 @@ class ChatRoomPresenter @Inject constructor(
try { try {
messagesRepository.getById(messageId)?.let { m -> messagesRepository.getById(messageId)?.let { m ->
view.copyToClipboard(m.message) view.copyToClipboard(m.message)
view.showMessage(R.string.msg_message_copied)
} }
} catch (e: RocketChatException) { } catch (e: RocketChatException) {
Timber.e(e) Timber.e(e)
...@@ -857,6 +858,42 @@ class ChatRoomPresenter @Inject constructor( ...@@ -857,6 +858,42 @@ class ChatRoomPresenter @Inject constructor(
} }
} }
// TODO: move this to new interactor or FetchChatRoomsInteractor?
private suspend fun getChatRoomAsync(roomId: String): ChatRoom? = withContext(CommonPool) {
return@withContext dbManager.chatRoomDao().get(roomId)?.let {
with(it.chatRoom) {
ChatRoom(
id = id,
subscriptionId = subscriptionId,
type = roomTypeOf(type),
unread = unread,
broadcast = broadcast ?: false,
alert = alert,
fullName = fullname,
name = name,
favorite = favorite ?: false,
default = isDefault ?: false,
readonly = readonly,
open = open,
lastMessage = null,
archived = false,
status = null,
user = null,
userMentions = userMentions,
client = client,
announcement = null,
description = null,
groupMentions = groupMentions,
roles = null,
topic = null,
lastSeen = this.lastSeen,
timestamp = timestamp,
updatedAt = updatedAt
)
}
}
}
// TODO: move this to new interactor or FetchChatRoomsInteractor? // TODO: move this to new interactor or FetchChatRoomsInteractor?
private suspend fun getChatRoomsAsync(name: String? = null): List<ChatRoom> = withContext(CommonPool) { private suspend fun getChatRoomsAsync(name: String? = null): List<ChatRoom> = withContext(CommonPool) {
return@withContext dbManager.chatRoomDao().getAllSync().filter { return@withContext dbManager.chatRoomDao().getAllSync().filter {
...@@ -939,6 +976,23 @@ class ChatRoomPresenter @Inject constructor( ...@@ -939,6 +976,23 @@ class ChatRoomPresenter @Inject constructor(
} }
} }
fun copyPermalink(messageId: String) {
launchUI(strategy) {
try {
messagesRepository.getById(messageId)?.let { message ->
getChatRoomAsync(message.roomId)?.let { chatRoom ->
val models = mapper.map(message)
models.firstOrNull()?.permalink?.let {
view.copyToClipboard(it)
}
}
}
} catch (ex: Exception) {
Timber.e(ex)
}
}
}
/** /**
* Send an emoji reaction to a message. * Send an emoji reaction to a message.
*/ */
......
...@@ -621,7 +621,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -621,7 +621,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
ui { ui {
val clipboard = it.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clipboard = it.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
clipboard.primaryClip = ClipData.newPlainText("", message) clipboard.primaryClip = ClipData.newPlainText("", message)
showToast(R.string.msg_message_copied)
} }
} }
...@@ -1059,6 +1058,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -1059,6 +1058,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} }
} }
override fun copyPermalink(id: String) {
presenter.copyPermalink(id)
}
override fun showReactions(id: String) { override fun showReactions(id: String) {
presenter.showReactions(id) presenter.showReactions(id)
} }
......
...@@ -20,7 +20,8 @@ data class ActionsAttachmentUiModel( ...@@ -20,7 +20,8 @@ data class ActionsAttachmentUiModel(
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf(), override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String, override var currentDayMarkerText: String,
override var showDayMarker: Boolean override var showDayMarker: Boolean,
override var permalink: String
) : BaseAttachmentUiModel<ActionsAttachment> { ) : BaseAttachmentUiModel<ActionsAttachment> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.ACTIONS_ATTACHMENT.viewType get() = BaseUiModel.ViewType.ACTIONS_ATTACHMENT.viewType
......
...@@ -18,7 +18,8 @@ data class AudioAttachmentUiModel( ...@@ -18,7 +18,8 @@ data class AudioAttachmentUiModel(
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf(), override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String, override var currentDayMarkerText: String,
override var showDayMarker: Boolean override var showDayMarker: Boolean,
override var permalink: String
) : BaseFileAttachmentUiModel<AudioAttachment> { ) : BaseFileAttachmentUiModel<AudioAttachment> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.AUDIO_ATTACHMENT.viewType get() = BaseUiModel.ViewType.AUDIO_ATTACHMENT.viewType
......
...@@ -20,7 +20,7 @@ data class AuthorAttachmentUiModel( ...@@ -20,7 +20,7 @@ data class AuthorAttachmentUiModel(
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf(), override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String, override var currentDayMarkerText: String,
override var showDayMarker: Boolean override var showDayMarker: Boolean, override var permalink: String
) : BaseAttachmentUiModel<AuthorAttachment> { ) : BaseAttachmentUiModel<AuthorAttachment> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.AUTHOR_ATTACHMENT.viewType get() = BaseUiModel.ViewType.AUTHOR_ATTACHMENT.viewType
......
...@@ -17,6 +17,7 @@ interface BaseUiModel<out T> { ...@@ -17,6 +17,7 @@ interface BaseUiModel<out T> {
var currentDayMarkerText: String var currentDayMarkerText: String
var showDayMarker: Boolean var showDayMarker: Boolean
var menuItemsToHide: MutableList<Int> var menuItemsToHide: MutableList<Int>
var permalink: String
enum class ViewType(val viewType: Int) { enum class ViewType(val viewType: Int) {
MESSAGE(0), MESSAGE(0),
......
...@@ -20,7 +20,8 @@ data class ColorAttachmentUiModel( ...@@ -20,7 +20,8 @@ data class ColorAttachmentUiModel(
override var unread: Boolean?, override var unread: Boolean?,
override var menuItemsToHide: MutableList<Int> = mutableListOf(), override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String, override var currentDayMarkerText: String,
override var showDayMarker: Boolean override var showDayMarker: Boolean,
override var permalink: String
) : BaseAttachmentUiModel<ColorAttachment> { ) : BaseAttachmentUiModel<ColorAttachment> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.COLOR_ATTACHMENT.viewType get() = BaseUiModel.ViewType.COLOR_ATTACHMENT.viewType
......
...@@ -18,7 +18,8 @@ data class GenericFileAttachmentUiModel( ...@@ -18,7 +18,8 @@ data class GenericFileAttachmentUiModel(
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf(), override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String, override var currentDayMarkerText: String,
override var showDayMarker: Boolean override var showDayMarker: Boolean,
override var permalink: String
) : BaseFileAttachmentUiModel<GenericFileAttachment> { ) : BaseFileAttachmentUiModel<GenericFileAttachment> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.GENERIC_FILE_ATTACHMENT.viewType get() = BaseUiModel.ViewType.GENERIC_FILE_ATTACHMENT.viewType
......
...@@ -20,7 +20,8 @@ data class ImageAttachmentUiModel( ...@@ -20,7 +20,8 @@ data class ImageAttachmentUiModel(
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf(), override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String, override var currentDayMarkerText: String,
override var showDayMarker: Boolean override var showDayMarker: Boolean,
override var permalink: String
) : BaseFileAttachmentUiModel<ImageAttachment> { ) : BaseFileAttachmentUiModel<ImageAttachment> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.IMAGE_ATTACHMENT.viewType get() = BaseUiModel.ViewType.IMAGE_ATTACHMENT.viewType
......
...@@ -19,7 +19,8 @@ data class MessageAttachmentUiModel( ...@@ -19,7 +19,8 @@ data class MessageAttachmentUiModel(
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf(), override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String, override var currentDayMarkerText: String,
override var showDayMarker: Boolean override var showDayMarker: Boolean,
override var permalink: String
) : BaseUiModel<Message> { ) : BaseUiModel<Message> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.MESSAGE_ATTACHMENT.viewType get() = BaseUiModel.ViewType.MESSAGE_ATTACHMENT.viewType
......
...@@ -15,7 +15,8 @@ data class MessageReplyUiModel( ...@@ -15,7 +15,8 @@ data class MessageReplyUiModel(
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf(), override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String, override var currentDayMarkerText: String,
override var showDayMarker: Boolean override var showDayMarker: Boolean,
override var permalink: String
) : BaseUiModel<MessageReply> { ) : BaseUiModel<MessageReply> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.MESSAGE_REPLY.viewType get() = BaseUiModel.ViewType.MESSAGE_REPLY.viewType
......
...@@ -20,7 +20,8 @@ data class MessageUiModel( ...@@ -20,7 +20,8 @@ data class MessageUiModel(
override var unread: Boolean? = null, override var unread: Boolean? = null,
var isFirstUnread: Boolean, var isFirstUnread: Boolean,
override var isTemporary: Boolean = false, override var isTemporary: Boolean = false,
override var menuItemsToHide: MutableList<Int> = mutableListOf() override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var permalink: String
) : BaseMessageUiModel<Message> { ) : BaseMessageUiModel<Message> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.MESSAGE.viewType get() = BaseUiModel.ViewType.MESSAGE.viewType
......
...@@ -19,7 +19,8 @@ data class UrlPreviewUiModel( ...@@ -19,7 +19,8 @@ data class UrlPreviewUiModel(
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf(), override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String, override var currentDayMarkerText: String,
override var showDayMarker: Boolean override var showDayMarker: Boolean,
override var permalink: String
) : BaseUiModel<Url> { ) : BaseUiModel<Url> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.URL_PREVIEW.viewType get() = BaseUiModel.ViewType.URL_PREVIEW.viewType
......
...@@ -18,7 +18,8 @@ data class VideoAttachmentUiModel( ...@@ -18,7 +18,8 @@ data class VideoAttachmentUiModel(
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf(), override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String, override var currentDayMarkerText: String,
override var showDayMarker: Boolean override var showDayMarker: Boolean,
override var permalink: String
) : BaseFileAttachmentUiModel<VideoAttachment> { ) : BaseFileAttachmentUiModel<VideoAttachment> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.VIDEO_ATTACHMENT.viewType get() = BaseUiModel.ViewType.VIDEO_ATTACHMENT.viewType
......
...@@ -2,7 +2,9 @@ package chat.rocket.android.chatroom.uimodel.suggestion ...@@ -2,7 +2,9 @@ package chat.rocket.android.chatroom.uimodel.suggestion
import chat.rocket.android.suggestions.model.SuggestionModel import chat.rocket.android.suggestions.model.SuggestionModel
class ChatRoomSuggestionUiModel(text: String, class ChatRoomSuggestionUiModel(
text: String,
val fullName: String, val fullName: String,
val name: String, val name: String,
searchList: List<String>) : SuggestionModel(text, searchList, false) searchList: List<String>
\ No newline at end of file ) : SuggestionModel(text, searchList, false)
...@@ -2,6 +2,8 @@ package chat.rocket.android.chatroom.uimodel.suggestion ...@@ -2,6 +2,8 @@ package chat.rocket.android.chatroom.uimodel.suggestion
import chat.rocket.android.suggestions.model.SuggestionModel import chat.rocket.android.suggestions.model.SuggestionModel
class CommandSuggestionUiModel(text: String, class CommandSuggestionUiModel(
text: String,
val description: String, val description: String,
searchList: List<String>) : SuggestionModel(text, searchList) searchList: List<String>
\ No newline at end of file ) : SuggestionModel(text, searchList)
\ No newline at end of file
...@@ -3,13 +3,15 @@ package chat.rocket.android.chatroom.uimodel.suggestion ...@@ -3,13 +3,15 @@ package chat.rocket.android.chatroom.uimodel.suggestion
import chat.rocket.android.suggestions.model.SuggestionModel import chat.rocket.android.suggestions.model.SuggestionModel
import chat.rocket.common.model.UserStatus import chat.rocket.common.model.UserStatus
class PeopleSuggestionUiModel(val imageUri: String?, class PeopleSuggestionUiModel(
val imageUri: String?,
text: String, text: String,
val username: String, val username: String,
val name: String, val name: String,
val status: UserStatus?, val status: UserStatus?,
pinned: Boolean = false, pinned: Boolean = false,
searchList: List<String>) : SuggestionModel(text, searchList, pinned) { searchList: List<String>
) : SuggestionModel(text, searchList, pinned) {
override fun toString(): String { override fun toString(): String {
return "PeopleSuggestionUiModel(imageUri='$imageUri', username='$username', name='$name', status=$status, pinned=$pinned)" return "PeopleSuggestionUiModel(imageUri='$imageUri', username='$username', name='$name', status=$status, pinned=$pinned)"
......
...@@ -17,7 +17,7 @@ class MessageHelper @Inject constructor( ...@@ -17,7 +17,7 @@ class MessageHelper @Inject constructor(
private val currentServer = serverInteractor.get()!! private val currentServer = serverInteractor.get()!!
private val settings: PublicSettings = getSettingsInteractor.get(currentServer) private val settings: PublicSettings = getSettingsInteractor.get(currentServer)
fun createPermalink(message: Message, chatRoom: ChatRoom): String { fun createPermalink(message: Message, chatRoom: ChatRoom, markdownSyntax: Boolean = true): String {
val type = when (chatRoom.type) { val type = when (chatRoom.type) {
is RoomType.PrivateGroup -> "group" is RoomType.PrivateGroup -> "group"
is RoomType.Channel -> "channel" is RoomType.Channel -> "channel"
...@@ -30,7 +30,8 @@ class MessageHelper @Inject constructor( ...@@ -30,7 +30,8 @@ class MessageHelper @Inject constructor(
} else { } else {
chatRoom.name chatRoom.name
} }
return "[ ]($currentServer/$type/$name?msg=${message.id}) " val permalink = "$currentServer/$type/$name?msg=${message.id}"
return if (markdownSyntax) "[ ]($permalink) " else permalink
} }
fun messageIdFromPermalink(permalink: String): String? { fun messageIdFromPermalink(permalink: String): String? {
......
...@@ -13,6 +13,7 @@ import android.text.style.ReplacementSpan ...@@ -13,6 +13,7 @@ import android.text.style.ReplacementSpan
import android.view.View import android.view.View
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.core.util.PatternsCompat import androidx.core.util.PatternsCompat
import chat.rocket.android.R
import chat.rocket.android.chatroom.ui.StrikethroughDelimiterProcessor import chat.rocket.android.chatroom.ui.StrikethroughDelimiterProcessor
import chat.rocket.android.emoji.EmojiParser import chat.rocket.android.emoji.EmojiParser
import chat.rocket.android.emoji.EmojiRepository import chat.rocket.android.emoji.EmojiRepository
......
...@@ -12,6 +12,11 @@ ...@@ -12,6 +12,11 @@
android:icon="@drawable/ic_action_message_reply_24dp" android:icon="@drawable/ic_action_message_reply_24dp"
android:title="@string/action_msg_reply" /> android:title="@string/action_msg_reply" />
<item
android:id="@+id/action_message_permalink"
android:icon="@drawable/ic_action_message_reply_24dp"
android:title="@string/action_msg_permalink" />
<item <item
android:id="@+id/action_message_quote" android:id="@+id/action_message_quote"
android:icon="@drawable/ic_action_message_quote_24dp" android:icon="@drawable/ic_action_message_quote_24dp"
......
...@@ -213,6 +213,7 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin ...@@ -213,6 +213,7 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin
<string name="action_msg_share">Share</string> <string name="action_msg_share">Share</string>
<string name="action_title_editing">Editing Message</string> <string name="action_title_editing">Editing Message</string>
<string name="action_msg_add_reaction">Add reaction</string> <string name="action_msg_add_reaction">Add reaction</string>
<string name="action_msg_permalink" translatable="false">Permalink</string>
<!-- Permission messages --> <!-- Permission messages -->
<string name="permission_editing_not_allowed">Editing is not allowed</string> <string name="permission_editing_not_allowed">Editing is not allowed</string>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment