diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt index 42ae6fa2b4..6b46a1dc29 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt @@ -42,7 +42,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle @@ -54,6 +53,7 @@ import androidx.lifecycle.lifecycleScope import com.bumptech.glide.integration.compose.ExperimentalGlideComposeApi import com.bumptech.glide.integration.compose.GlideImage import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject import kotlinx.coroutines.launch import network.loki.messenger.R import network.loki.messenger.databinding.ViewVisibleMessageContentBinding @@ -81,7 +81,6 @@ import org.thoughtcrime.securesms.ui.theme.blackAlpha40 import org.thoughtcrime.securesms.ui.theme.bold import org.thoughtcrime.securesms.ui.theme.dangerButtonColors import org.thoughtcrime.securesms.ui.theme.monospace -import javax.inject.Inject @AndroidEntryPoint class MessageDetailActivity : ScreenLockActionBarActivity() { @@ -214,8 +213,10 @@ fun CellMetadata( modifier = Modifier.padding(LocalDimensions.current.spacing), verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallSpacing) ) { - TitledText(sent) - TitledText(received) + // Show the sent details if we're the sender of the message, otherwise show the received details + if (sent != null) { TitledText(sent) } + if (received != null) { TitledText(received) } + TitledErrorText(error) senderInfo?.let { TitledView(state.fromTitle) { @@ -485,12 +486,14 @@ fun TitledText( ) { titledText?.apply { TitledView(title, modifier) { - Text( - text, - style = style, - color = color, - modifier = Modifier.fillMaxWidth() - ) + if (text != null) { + Text( + text, + style = style, + color = color, + modifier = Modifier.fillMaxWidth() + ) + } } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailsViewModel.kt index 074559cd68..acf12a869e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailsViewModel.kt @@ -7,6 +7,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel import java.util.Date import java.util.concurrent.TimeUnit import javax.inject.Inject +import kotlin.text.Typography.ellipsis import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.channels.Channel @@ -23,6 +24,7 @@ import org.session.libsession.messaging.sending_receiving.attachments.Attachment import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment import org.session.libsession.utilities.Util import org.session.libsession.utilities.recipients.Recipient +import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.MediaPreviewArgs import org.thoughtcrime.securesms.database.AttachmentDatabase import org.thoughtcrime.securesms.database.LokiMessageDatabase @@ -44,6 +46,7 @@ class MessageDetailsViewModel @Inject constructor( private val threadDb: ThreadDatabase, private val repository: ConversationRepository, private val deprecationManager: LegacyGroupDeprecationManager, + private val context: ApplicationContext ) : ViewModel() { private var job: Job? = null @@ -59,38 +62,57 @@ class MessageDetailsViewModel @Inject constructor( job?.cancel() field = value - val record = mmsSmsDatabase.getMessageForTimestamp(timestamp) + val messageRecord = mmsSmsDatabase.getMessageForTimestamp(timestamp) - if (record == null) { + if (messageRecord == null) { viewModelScope.launch { event.send(Event.Finish) } return } - val mmsRecord = record as? MmsMessageRecord + val mmsRecord = messageRecord as? MmsMessageRecord job = viewModelScope.launch { - repository.changes(record.threadId) + repository.changes(messageRecord.threadId) .filter { mmsSmsDatabase.getMessageForTimestamp(value) == null } .collect { event.send(Event.Finish) } } - state.value = record.run { + state.value = messageRecord.run { val slides = mmsRecord?.slideDeck?.slides ?: emptyList() val recipient = threadDb.getRecipientForThreadId(threadId)!! val isDeprecatedLegacyGroup = recipient.isLegacyGroupRecipient && - deprecationManager.isDeprecated + deprecationManager.isDeprecated + + + val errorString = lokiMessageDatabase.getErrorMessage(id) MessageDetailsState( attachments = slides.map(::Attachment), - record = record, - sent = dateSent.let(::Date).toString().let { TitledText(R.string.sent, it) }, - received = dateReceived.let(::Date).toString().let { TitledText(R.string.received, it) }, - error = lokiMessageDatabase.getErrorMessage(id)?.let { TitledText(R.string.theError, it) }, + record = messageRecord, + + // Set the "Sent" message info TitledText appropriately + sent = if (messageRecord.isSending && errorString == null) { + val sendingWithEllipsisString = context.getString(R.string.sending) + ellipsis // e.g., "Sending…" + TitledText(sendingWithEllipsisString, null) + } else if (messageRecord.isSent && errorString == null) { + dateReceived.let(::Date).toString().let { TitledText(R.string.sent, it) } + } else { + null // Not sending or sent? Don't display anything for the "Sent" element. + }, + + // Set the "Received" message info TitledText appropriately + received = if (messageRecord.isIncoming && errorString == null) { + dateReceived.let(::Date).toString().let { TitledText(R.string.received, it) } + } else { + null // Not incoming? Then don't display anything for the "Received" element. + }, + + error = errorString?.let { TitledText(context.getString(R.string.theError) + ":", it) }, senderInfo = individualRecipient.run { TitledText(name, address.toString()) }, sender = individualRecipient, thread = recipient, - readOnly = isDeprecatedLegacyGroup, + readOnly = isDeprecatedLegacyGroup ) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java index 39ed1d9389..f3bb6f8bc7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java @@ -78,19 +78,7 @@ public abstract class DisplayRecord { deliveryStatus < SmsDatabase.Status.STATUS_PENDING) || deliveryReceiptCount > 0; } - public boolean isSent() { return MmsSmsColumns.Types.isSentType(type); } - public boolean isSyncing() { - return MmsSmsColumns.Types.isSyncingType(type); - } - - public boolean isResyncing() { - return MmsSmsColumns.Types.isResyncingType(type); - } - - public boolean isSyncFailed() { - return MmsSmsColumns.Types.isSyncFailedMessageType(type); - } public boolean isFailed() { return MmsSmsColumns.Types.isFailedMessageType(type) @@ -105,45 +93,35 @@ public abstract class DisplayRecord { return isPending; } - public boolean isRead() { return readReceiptCount > 0; } - - public boolean isOutgoing() { - return MmsSmsColumns.Types.isOutgoingMessageType(type); - } - - public boolean isIncoming() { - return !MmsSmsColumns.Types.isOutgoingMessageType(type); - } - - public boolean isGroupUpdateMessage() { - return SmsDatabase.Types.isGroupUpdateMessage(type); - } - public boolean isExpirationTimerUpdate() { return SmsDatabase.Types.isExpirationTimerUpdate(type); } - public boolean isGroupV2ExpirationTimerUpdate() { return false; } - public boolean isMediaSavedNotification() { return MmsSmsColumns.Types.isMediaSavedExtraction(type); } - public boolean isScreenshotNotification() { return MmsSmsColumns.Types.isScreenshotExtraction(type); } + public boolean isCallLog() { return SmsDatabase.Types.isCallLog(type); } public boolean isDataExtractionNotification() { return isMediaSavedNotification() || isScreenshotNotification(); } - public boolean isOpenGroupInvitation() { return MmsSmsColumns.Types.isOpenGroupInvitation(type); } - public boolean isCallLog() { - return SmsDatabase.Types.isCallLog(type); - } - public boolean isIncomingCall() { - return SmsDatabase.Types.isIncomingCall(type); - } - public boolean isOutgoingCall() { - return SmsDatabase.Types.isOutgoingCall(type); - } - public boolean isMissedCall() { - return SmsDatabase.Types.isMissedCall(type); - } - public boolean isFirstMissedCall() { - return SmsDatabase.Types.isFirstMissedCall(type); - } - public boolean isDeleted() { return MmsSmsColumns.Types.isDeletedMessage(type); } - public boolean isMessageRequestResponse() { return MmsSmsColumns.Types.isMessageRequestResponse(type); } + public boolean isDeleted() { return MmsSmsColumns.Types.isDeletedMessage(type); } + public boolean isExpirationTimerUpdate() { return SmsDatabase.Types.isExpirationTimerUpdate(type); } + public boolean isFirstMissedCall() { return SmsDatabase.Types.isFirstMissedCall(type); } + public boolean isGroupUpdateMessage() { return SmsDatabase.Types.isGroupUpdateMessage(type); } + public boolean isIncoming() { return !MmsSmsColumns.Types.isOutgoingMessageType(type); } + public boolean isIncomingCall() { return SmsDatabase.Types.isIncomingCall(type); } + public boolean isMediaSavedNotification() { return MmsSmsColumns.Types.isMediaSavedExtraction(type); } + public boolean isMessageRequestResponse() { return MmsSmsColumns.Types.isMessageRequestResponse(type); } + public boolean isMissedCall() { return SmsDatabase.Types.isMissedCall(type); } + public boolean isOpenGroupInvitation() { return MmsSmsColumns.Types.isOpenGroupInvitation(type); } + public boolean isOutgoing() { return MmsSmsColumns.Types.isOutgoingMessageType(type); } + public boolean isOutgoingCall() { return SmsDatabase.Types.isOutgoingCall(type); } + public boolean isRead() { return readReceiptCount > 0; } + public boolean isResyncing() { return MmsSmsColumns.Types.isResyncingType(type); } + public boolean isScreenshotNotification() { return MmsSmsColumns.Types.isScreenshotExtraction(type); } + public boolean isSent() { return MmsSmsColumns.Types.isSentType(type); } + public boolean isSending() { return isOutgoing() && !isSent(); } + public boolean isSyncFailed() { return MmsSmsColumns.Types.isSyncFailedMessageType(type); } + public boolean isSyncing() { return MmsSmsColumns.Types.isSyncingType(type); } public boolean isControlMessage() { - return isGroupUpdateMessage() || isExpirationTimerUpdate() || isDataExtractionNotification() - || isMessageRequestResponse() || isCallLog(); + return isGroupUpdateMessage() || + isExpirationTimerUpdate() || + isDataExtractionNotification() || + isMessageRequestResponse() || + isCallLog(); } + + public boolean isGroupV2ExpirationTimerUpdate() { return false; } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/Strings.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/Strings.kt index 91500da7b2..64e373063a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ui/Strings.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/Strings.kt @@ -54,7 +54,7 @@ fun GetString(duration: Duration) = GetString.FromMap(duration, ExpirationUtil:: /** * Represents some text with an associated title. */ -data class TitledText(val title: GetString, val text: String) { - constructor(title: String, text: String): this(GetString(title), text) - constructor(@StringRes title: Int, text: String): this(GetString(title), text) +data class TitledText(val title: GetString, val text: String?) { + constructor(title: String, text: String?): this(GetString(title), text) + constructor(@StringRes title: Int, text: String?): this(GetString(title), text) }