mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 12:05:22 +00:00
Merge pull request #658 from RyanRory/message-details
Add Message Details Page for Failed Messages
This commit is contained in:
commit
30793fb7ea
@ -221,6 +221,11 @@
|
|||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value="org.thoughtcrime.securesms.home.HomeActivity" />
|
android:value="org.thoughtcrime.securesms.home.HomeActivity" />
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name="org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity"
|
||||||
|
android:screenOrientation="portrait"
|
||||||
|
android:theme="@style/Theme.TextSecure.DayNight">
|
||||||
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name="org.thoughtcrime.securesms.groups.OpenGroupGuidelinesActivity"
|
android:name="org.thoughtcrime.securesms.groups.OpenGroupGuidelinesActivity"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
|
@ -93,6 +93,7 @@ import org.thoughtcrime.securesms.conversation.v2.search.SearchViewModel
|
|||||||
import org.thoughtcrime.securesms.conversation.v2.utilities.AttachmentManager
|
import org.thoughtcrime.securesms.conversation.v2.utilities.AttachmentManager
|
||||||
import org.thoughtcrime.securesms.conversation.v2.utilities.BaseDialog
|
import org.thoughtcrime.securesms.conversation.v2.utilities.BaseDialog
|
||||||
import org.thoughtcrime.securesms.conversation.v2.utilities.MentionUtilities
|
import org.thoughtcrime.securesms.conversation.v2.utilities.MentionUtilities
|
||||||
|
import org.thoughtcrime.securesms.conversation.v2.utilities.ResendMessageUtilities
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||||
import org.thoughtcrime.securesms.database.DraftDatabase
|
import org.thoughtcrime.securesms.database.DraftDatabase
|
||||||
import org.thoughtcrime.securesms.database.DraftDatabase.Drafts
|
import org.thoughtcrime.securesms.database.DraftDatabase.Drafts
|
||||||
@ -1208,49 +1209,19 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
|
|
||||||
override fun resendMessage(messages: Set<MessageRecord>) {
|
override fun resendMessage(messages: Set<MessageRecord>) {
|
||||||
messages.forEach { messageRecord ->
|
messages.forEach { messageRecord ->
|
||||||
val recipient: Recipient = messageRecord.recipient
|
ResendMessageUtilities.resend(messageRecord)
|
||||||
val message = VisibleMessage()
|
|
||||||
message.id = messageRecord.getId()
|
|
||||||
if (messageRecord.isOpenGroupInvitation) {
|
|
||||||
val openGroupInvitation = OpenGroupInvitation()
|
|
||||||
fromJSON(messageRecord.body)?.let { updateMessageData ->
|
|
||||||
val kind = updateMessageData.kind
|
|
||||||
if (kind is UpdateMessageData.Kind.OpenGroupInvitation) {
|
|
||||||
openGroupInvitation.name = kind.groupName
|
|
||||||
openGroupInvitation.url = kind.groupUrl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
message.openGroupInvitation = openGroupInvitation
|
|
||||||
} else {
|
|
||||||
message.text = messageRecord.body
|
|
||||||
}
|
|
||||||
message.sentTimestamp = messageRecord.timestamp
|
|
||||||
if (recipient.isGroupRecipient) {
|
|
||||||
message.groupPublicKey = recipient.address.toGroupString()
|
|
||||||
} else {
|
|
||||||
message.recipient = messageRecord.recipient.address.serialize()
|
|
||||||
}
|
|
||||||
message.threadID = messageRecord.threadId
|
|
||||||
if (messageRecord.isMms) {
|
|
||||||
val mmsMessageRecord = messageRecord as MmsMessageRecord
|
|
||||||
if (mmsMessageRecord.linkPreviews.isNotEmpty()) {
|
|
||||||
message.linkPreview = from(mmsMessageRecord.linkPreviews[0])
|
|
||||||
}
|
|
||||||
if (mmsMessageRecord.quote != null) {
|
|
||||||
message.quote = from(mmsMessageRecord.quote!!.quoteModel)
|
|
||||||
}
|
|
||||||
message.addSignalAttachments(mmsMessageRecord.slideDeck.asAttachments())
|
|
||||||
}
|
|
||||||
val sentTimestamp = message.sentTimestamp
|
|
||||||
val sender = MessagingModuleConfiguration.shared.storage.getUserPublicKey()
|
|
||||||
if (sentTimestamp != null && sender != null) {
|
|
||||||
MessagingModuleConfiguration.shared.storage.markAsSending(sentTimestamp, sender)
|
|
||||||
}
|
|
||||||
MessageSender.send(message, recipient.address)
|
|
||||||
}
|
}
|
||||||
endActionMode()
|
endActionMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun showMessageDetail(messages: Set<MessageRecord>) {
|
||||||
|
val message = messages.first()
|
||||||
|
val intent = Intent(this, MessageDetailActivity::class.java)
|
||||||
|
intent.putExtra(MessageDetailActivity.MESSAGE_TIMESTAMP, message.timestamp)
|
||||||
|
push(intent)
|
||||||
|
endActionMode()
|
||||||
|
}
|
||||||
|
|
||||||
override fun saveAttachment(messages: Set<MessageRecord>) {
|
override fun saveAttachment(messages: Set<MessageRecord>) {
|
||||||
val message = messages.first() as MmsMessageRecord
|
val message = messages.first() as MmsMessageRecord
|
||||||
SaveAttachmentTask.showWarningDialog(this, { _, _ ->
|
SaveAttachmentTask.showWarningDialog(this, { _, _ ->
|
||||||
|
@ -0,0 +1,78 @@
|
|||||||
|
package org.thoughtcrime.securesms.conversation.v2
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import androidx.annotation.DimenRes
|
||||||
|
import kotlinx.android.synthetic.main.activity_conversation_v2_action_bar.*
|
||||||
|
import kotlinx.android.synthetic.main.activity_message_detail.*
|
||||||
|
import network.loki.messenger.R
|
||||||
|
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||||
|
import org.session.libsession.messaging.messages.visible.LinkPreview
|
||||||
|
import org.session.libsession.messaging.messages.visible.OpenGroupInvitation
|
||||||
|
import org.session.libsession.messaging.messages.visible.Quote
|
||||||
|
import org.session.libsession.messaging.messages.visible.VisibleMessage
|
||||||
|
import org.session.libsession.messaging.sending_receiving.MessageSender
|
||||||
|
import org.session.libsession.messaging.utilities.UpdateMessageData
|
||||||
|
import org.session.libsession.utilities.Address
|
||||||
|
import org.session.libsession.utilities.ExpirationUtil
|
||||||
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
|
import org.session.libsession.utilities.recipients.Recipient
|
||||||
|
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||||
|
import org.thoughtcrime.securesms.conversation.v2.utilities.ResendMessageUtilities
|
||||||
|
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||||
|
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||||
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||||
|
import org.thoughtcrime.securesms.util.DateUtils
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
|
||||||
|
class MessageDetailActivity: PassphraseRequiredActionBarActivity() {
|
||||||
|
|
||||||
|
var messageRecord: MessageRecord? = null
|
||||||
|
|
||||||
|
// region Settings
|
||||||
|
companion object {
|
||||||
|
// Extras
|
||||||
|
const val MESSAGE_TIMESTAMP = "message_timestamp"
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
|
||||||
|
super.onCreate(savedInstanceState, ready)
|
||||||
|
setContentView(R.layout.activity_message_detail)
|
||||||
|
title = resources.getString(R.string.conversation_context__menu_message_details)
|
||||||
|
val timestamp = intent.getLongExtra(MESSAGE_TIMESTAMP, -1L)
|
||||||
|
// We only show this screen for messages fail to send,
|
||||||
|
// so the author of the messages must be the current user.
|
||||||
|
val author = Address.fromSerialized(TextSecurePreferences.getLocalNumber(this)!!)
|
||||||
|
messageRecord = DatabaseFactory.getMmsSmsDatabase (this).getMessageFor(timestamp, author)
|
||||||
|
updateContent()
|
||||||
|
resend_button.setOnClickListener {
|
||||||
|
ResendMessageUtilities.resend(messageRecord!!)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateContent() {
|
||||||
|
val dateLocale = Locale.getDefault()
|
||||||
|
val dateFormatter: SimpleDateFormat = DateUtils.getDetailedDateFormatter(this, dateLocale)
|
||||||
|
sent_time.text = dateFormatter.format(Date(messageRecord!!.dateSent))
|
||||||
|
|
||||||
|
val errorMessage = DatabaseFactory.getLokiMessageDatabase(this).getErrorMessage(messageRecord!!.getId()) ?: "Message failed to send."
|
||||||
|
error_message.text = errorMessage
|
||||||
|
|
||||||
|
if (messageRecord!!.getExpiresIn() <= 0 || messageRecord!!.getExpireStarted() <= 0) {
|
||||||
|
expires_container.visibility = View.GONE
|
||||||
|
} else {
|
||||||
|
expires_container.visibility = View.VISIBLE
|
||||||
|
val elapsed = System.currentTimeMillis() - messageRecord!!.expireStarted
|
||||||
|
val remaining = messageRecord!!.expiresIn - elapsed
|
||||||
|
|
||||||
|
val duration = ExpirationUtil.getExpirationDisplayValue(this, Math.max((remaining / 1000).toInt(), 1))
|
||||||
|
expires_in.text = duration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -58,6 +58,8 @@ class ConversationActionModeCallback(private val adapter: ConversationAdapter, p
|
|||||||
// Copy Session ID
|
// Copy Session ID
|
||||||
menu.findItem(R.id.menu_context_copy_public_key).isVisible =
|
menu.findItem(R.id.menu_context_copy_public_key).isVisible =
|
||||||
(thread.isGroupRecipient && selectedItems.size == 1 && firstMessage.recipient.address.toString() != userPublicKey)
|
(thread.isGroupRecipient && selectedItems.size == 1 && firstMessage.recipient.address.toString() != userPublicKey)
|
||||||
|
// Message detail
|
||||||
|
menu.findItem(R.id.menu_message_details).isVisible = (selectedItems.size == 1 && firstMessage.isFailed)
|
||||||
// Resend
|
// Resend
|
||||||
menu.findItem(R.id.menu_context_resend).isVisible = (selectedItems.size == 1 && firstMessage.isFailed)
|
menu.findItem(R.id.menu_context_resend).isVisible = (selectedItems.size == 1 && firstMessage.isFailed)
|
||||||
// Save media
|
// Save media
|
||||||
@ -81,6 +83,7 @@ class ConversationActionModeCallback(private val adapter: ConversationAdapter, p
|
|||||||
R.id.menu_context_copy -> delegate?.copyMessages(selectedItems)
|
R.id.menu_context_copy -> delegate?.copyMessages(selectedItems)
|
||||||
R.id.menu_context_copy_public_key -> delegate?.copySessionID(selectedItems)
|
R.id.menu_context_copy_public_key -> delegate?.copySessionID(selectedItems)
|
||||||
R.id.menu_context_resend -> delegate?.resendMessage(selectedItems)
|
R.id.menu_context_resend -> delegate?.resendMessage(selectedItems)
|
||||||
|
R.id.menu_message_details -> delegate?.showMessageDetail(selectedItems)
|
||||||
R.id.menu_context_save_attachment -> delegate?.saveAttachment(selectedItems)
|
R.id.menu_context_save_attachment -> delegate?.saveAttachment(selectedItems)
|
||||||
R.id.menu_context_reply -> delegate?.reply(selectedItems)
|
R.id.menu_context_reply -> delegate?.reply(selectedItems)
|
||||||
}
|
}
|
||||||
@ -101,6 +104,7 @@ interface ConversationActionModeCallbackDelegate {
|
|||||||
fun copyMessages(messages: Set<MessageRecord>)
|
fun copyMessages(messages: Set<MessageRecord>)
|
||||||
fun copySessionID(messages: Set<MessageRecord>)
|
fun copySessionID(messages: Set<MessageRecord>)
|
||||||
fun resendMessage(messages: Set<MessageRecord>)
|
fun resendMessage(messages: Set<MessageRecord>)
|
||||||
|
fun showMessageDetail(messages: Set<MessageRecord>)
|
||||||
fun saveAttachment(messages: Set<MessageRecord>)
|
fun saveAttachment(messages: Set<MessageRecord>)
|
||||||
fun reply(messages: Set<MessageRecord>)
|
fun reply(messages: Set<MessageRecord>)
|
||||||
}
|
}
|
@ -52,7 +52,7 @@ class VisibleMessageView : LinearLayout {
|
|||||||
var contentViewDelegate: VisibleMessageContentViewDelegate? = null
|
var contentViewDelegate: VisibleMessageContentViewDelegate? = null
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val swipeToReplyThreshold = 80.0f // dp
|
const val swipeToReplyThreshold = 64.0f // dp
|
||||||
const val longPressMovementTreshold = 10.0f // dp
|
const val longPressMovementTreshold = 10.0f // dp
|
||||||
const val longPressDurationThreshold = 250L // ms
|
const val longPressDurationThreshold = 250L // ms
|
||||||
const val maxDoubleTapInterval = 200L
|
const val maxDoubleTapInterval = 200L
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
package org.thoughtcrime.securesms.conversation.v2.utilities
|
||||||
|
|
||||||
|
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||||
|
import org.session.libsession.messaging.messages.visible.LinkPreview
|
||||||
|
import org.session.libsession.messaging.messages.visible.OpenGroupInvitation
|
||||||
|
import org.session.libsession.messaging.messages.visible.Quote
|
||||||
|
import org.session.libsession.messaging.messages.visible.VisibleMessage
|
||||||
|
import org.session.libsession.messaging.sending_receiving.MessageSender
|
||||||
|
import org.session.libsession.messaging.utilities.UpdateMessageData
|
||||||
|
import org.session.libsession.utilities.recipients.Recipient
|
||||||
|
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||||
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||||
|
|
||||||
|
object ResendMessageUtilities {
|
||||||
|
|
||||||
|
fun resend(messageRecord: MessageRecord) {
|
||||||
|
val recipient: Recipient = messageRecord.recipient
|
||||||
|
val message = VisibleMessage()
|
||||||
|
message.id = messageRecord.getId()
|
||||||
|
if (messageRecord.isOpenGroupInvitation) {
|
||||||
|
val openGroupInvitation = OpenGroupInvitation()
|
||||||
|
UpdateMessageData.fromJSON(messageRecord.body)?.let { updateMessageData ->
|
||||||
|
val kind = updateMessageData.kind
|
||||||
|
if (kind is UpdateMessageData.Kind.OpenGroupInvitation) {
|
||||||
|
openGroupInvitation.name = kind.groupName
|
||||||
|
openGroupInvitation.url = kind.groupUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
message.openGroupInvitation = openGroupInvitation
|
||||||
|
} else {
|
||||||
|
message.text = messageRecord.body
|
||||||
|
}
|
||||||
|
message.sentTimestamp = messageRecord.timestamp
|
||||||
|
if (recipient.isGroupRecipient) {
|
||||||
|
message.groupPublicKey = recipient.address.toGroupString()
|
||||||
|
} else {
|
||||||
|
message.recipient = messageRecord.recipient.address.serialize()
|
||||||
|
}
|
||||||
|
message.threadID = messageRecord.threadId
|
||||||
|
if (messageRecord.isMms) {
|
||||||
|
val mmsMessageRecord = messageRecord as MmsMessageRecord
|
||||||
|
if (mmsMessageRecord.linkPreviews.isNotEmpty()) {
|
||||||
|
message.linkPreview = LinkPreview.from(mmsMessageRecord.linkPreviews[0])
|
||||||
|
}
|
||||||
|
if (mmsMessageRecord.quote != null) {
|
||||||
|
message.quote = Quote.from(mmsMessageRecord.quote!!.quoteModel)
|
||||||
|
}
|
||||||
|
message.addSignalAttachments(mmsMessageRecord.slideDeck.asAttachments())
|
||||||
|
}
|
||||||
|
val sentTimestamp = message.sentTimestamp
|
||||||
|
val sender = MessagingModuleConfiguration.shared.storage.getUserPublicKey()
|
||||||
|
if (sentTimestamp != null && sender != null) {
|
||||||
|
MessagingModuleConfiguration.shared.storage.markAsSending(sentTimestamp, sender)
|
||||||
|
}
|
||||||
|
MessageSender.send(message, recipient.address)
|
||||||
|
}
|
||||||
|
}
|
@ -334,7 +334,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
|||||||
if (error.localizedMessage != null) {
|
if (error.localizedMessage != null) {
|
||||||
val message: String
|
val message: String
|
||||||
if (error is OnionRequestAPI.HTTPRequestFailedAtDestinationException && error.statusCode == 429) {
|
if (error is OnionRequestAPI.HTTPRequestFailedAtDestinationException && error.statusCode == 429) {
|
||||||
message = "Rate limited."
|
message = "429: Rate limited."
|
||||||
} else {
|
} else {
|
||||||
message = error.localizedMessage!!
|
message = error.localizedMessage!!
|
||||||
}
|
}
|
||||||
|
108
app/src/main/res/layout/activity_message_detail.xml
Normal file
108
app/src/main/res/layout/activity_message_detail.xml
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/transparent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<FrameLayout android:id="@+id/item_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="@dimen/medium_spacing"
|
||||||
|
android:paddingBottom="@dimen/medium_spacing"
|
||||||
|
android:elevation="10dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="@dimen/medium_spacing"
|
||||||
|
android:paddingEnd="@dimen/medium_spacing">
|
||||||
|
|
||||||
|
<TableLayout android:id="@+id/metadata_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:shrinkColumns="1">
|
||||||
|
|
||||||
|
<TableRow android:id="@+id/sent_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="10dp">
|
||||||
|
|
||||||
|
<TextView android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/message_details_header__sent"
|
||||||
|
android:gravity="end"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView android:id="@+id/sent_time"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
tools:text="Jan 18, 2015, 12:29:37 AM GMT-08:00" />
|
||||||
|
|
||||||
|
</TableRow>
|
||||||
|
|
||||||
|
<TableRow android:id="@+id/expires_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<TextView android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/message_details_header__disappears"
|
||||||
|
android:gravity="end"
|
||||||
|
android:textStyle="bold"/>
|
||||||
|
|
||||||
|
<TextView android:id="@+id/expires_in"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
tools:text="1 week"/>
|
||||||
|
|
||||||
|
</TableRow>
|
||||||
|
|
||||||
|
<TableRow android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="10dp">
|
||||||
|
|
||||||
|
<TextView android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/message_details_header__error"
|
||||||
|
android:gravity="end"
|
||||||
|
android:textStyle="bold"/>
|
||||||
|
|
||||||
|
<TextView android:id="@+id/error_message"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
tools:text="Send Failed"/>
|
||||||
|
|
||||||
|
</TableRow>
|
||||||
|
|
||||||
|
</TableLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="40dp"
|
||||||
|
android:gravity="end">
|
||||||
|
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/resend_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="@dimen/medium_button_height"
|
||||||
|
android:paddingStart="30dp"
|
||||||
|
android:paddingEnd="30dp"
|
||||||
|
style="@style/Widget.Session.Button.Common.ProminentOutline"
|
||||||
|
android:text="@string/message_recipients_list_item__resend" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -21,6 +21,12 @@
|
|||||||
android:icon="?menu_trash_icon"
|
android:icon="?menu_trash_icon"
|
||||||
app:showAsAction="always" />
|
app:showAsAction="always" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:title="@string/conversation_context__menu_message_details"
|
||||||
|
android:id="@+id/menu_message_details"
|
||||||
|
android:icon="?menu_info_icon"
|
||||||
|
app:showAsAction="always" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:title="@string/conversation_context__menu_copy_text"
|
android:title="@string/conversation_context__menu_copy_text"
|
||||||
android:id="@+id/menu_context_copy"
|
android:id="@+id/menu_context_copy"
|
||||||
@ -43,7 +49,7 @@
|
|||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:title="@string/activity_conversation_copy_public_key_button_title"
|
android:title="@string/activity_conversation_menu_copy_session_id"
|
||||||
android:id="@+id/menu_context_copy_public_key"
|
android:id="@+id/menu_context_copy_public_key"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
|
||||||
|
@ -882,4 +882,5 @@
|
|||||||
<string name="activity_conversation_attachment_prep_failed">Failed to prepare attachment for sending.</string>
|
<string name="activity_conversation_attachment_prep_failed">Failed to prepare attachment for sending.</string>
|
||||||
<string name="media">Media</string>
|
<string name="media">Media</string>
|
||||||
<string name="UntrustedAttachmentView_download_attachment">Tap to download %s</string>
|
<string name="UntrustedAttachmentView_download_attachment">Tap to download %s</string>
|
||||||
|
<string name="message_details_header__error">Error</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user