From fc108b34dbbd4cd31ceea8e44f3391d7a47c5e8e Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 29 Jun 2023 11:37:55 +0930 Subject: [PATCH] Create Message Details screen --- app/build.gradle | 6 +- .../conversation/v2/MessageDetailActivity.kt | 221 +++++++++++++----- 2 files changed, 166 insertions(+), 61 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 6170763a6..8194ef4b7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -28,6 +28,7 @@ configurations.all { } dependencies { + implementation "androidx.appcompat:appcompat:$appcompatVersion" implementation 'androidx.recyclerview:recyclerview:1.2.1' implementation "com.google.android.material:material:$materialVersion" @@ -161,8 +162,11 @@ dependencies { testImplementation 'org.robolectric:shadows-multidex:4.4' implementation 'androidx.compose.ui:ui:1.4.3' - implementation 'androidx.compose.material:material:1.4.3' implementation 'androidx.compose.ui:ui-tooling:1.4.3' + implementation "com.google.accompanist:accompanist-themeadapter-appcompat:0.30.1" + + implementation 'androidx.compose.foundation:foundation-layout:1.5.0-alpha02' + implementation 'androidx.compose.material:material:1.5.0-alpha02' } def canonicalVersionCode = 338 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 0938b21dd..2c1698ae8 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 @@ -2,32 +2,49 @@ package org.thoughtcrime.securesms.conversation.v2 import android.os.Bundle import android.view.View -import androidx.core.view.isVisible +import androidx.annotation.DrawableRes +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayoutApi +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.Card +import androidx.compose.material.Divider +import androidx.compose.material.Icon +import androidx.compose.material.Text +import androidx.compose.material.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.google.accompanist.themeadapter.appcompat.AppCompatTheme import dagger.hilt.android.AndroidEntryPoint import network.loki.messenger.R -import network.loki.messenger.databinding.ActivityMessageDetailBinding -import org.session.libsession.messaging.MessagingModuleConfiguration -import org.session.libsession.messaging.open_groups.OpenGroupApi -import org.session.libsession.messaging.utilities.SessionId -import org.session.libsession.messaging.utilities.SodiumUtilities -import org.session.libsession.snode.SnodeAPI -import org.session.libsession.utilities.Address -import org.session.libsession.utilities.ExpirationUtil -import org.session.libsession.utilities.TextSecurePreferences -import org.session.libsignal.utilities.IdPrefix import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity -import org.thoughtcrime.securesms.conversation.v2.utilities.ResendMessageUtilities import org.thoughtcrime.securesms.database.Storage import org.thoughtcrime.securesms.database.model.MessageRecord -import org.thoughtcrime.securesms.dependencies.DatabaseComponent -import org.thoughtcrime.securesms.util.DateUtils -import java.text.SimpleDateFormat import java.util.* import javax.inject.Inject @AndroidEntryPoint class MessageDetailActivity: PassphraseRequiredActionBarActivity() { - private lateinit var binding: ActivityMessageDetailBinding var messageRecord: MessageRecord? = null @Inject @@ -42,58 +59,142 @@ class MessageDetailActivity: PassphraseRequiredActionBarActivity() { override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) { super.onCreate(savedInstanceState, ready) - binding = ActivityMessageDetailBinding.inflate(layoutInflater) - setContentView(binding.root) - 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 = DatabaseComponent.get(this).mmsSmsDatabase().getMessageFor(timestamp, author) ?: run { - finish() - return - } - val threadId = messageRecord!!.threadId - val openGroup = storage.getOpenGroup(threadId) - val blindedKey = openGroup?.let { group -> - val userEdKeyPair = MessagingModuleConfiguration.shared.getUserED25519KeyPair() ?: return@let null - val blindingEnabled = storage.getServerCapabilities(group.server).contains(OpenGroupApi.Capability.BLIND.name.lowercase()) - if (blindingEnabled) { - SodiumUtilities.blindedKeyPair(group.publicKey, userEdKeyPair)?.publicKey?.asBytes - ?.let { SessionId(IdPrefix.BLINDED, it) }?.hexString - } else null - } - updateContent() - binding.resendButton.setOnClickListener { - ResendMessageUtilities.resend(this, messageRecord!!, blindedKey) - finish() + + title = resources.getString(R.string.conversation_context__menu_message_details) + + setContentView(createComposeView()) + } + + private fun createComposeView(): ComposeView = ComposeView(this).apply { + id = View.generateViewId() + setContent { + MessageDetails() } } - fun updateContent() { - val dateLocale = Locale.getDefault() - val dateFormatter: SimpleDateFormat = DateUtils.getDetailedDateFormatter(this, dateLocale) - binding.sentTime.text = dateFormatter.format(Date(messageRecord!!.dateSent)) + data class TitledText(val title: String, val value: String) - val errorMessage = DatabaseComponent.get(this).lokiMessageDatabase().getErrorMessage(messageRecord!!.getId()) - if (errorMessage != null) { - binding.errorMessage.text = errorMessage - binding.resendContainer.isVisible = true - binding.errorContainer.isVisible = true - } else { - binding.errorContainer.isVisible = false - binding.resendContainer.isVisible = false + @OptIn(ExperimentalLayoutApi::class) + @Preview + @Composable + fun MessageDetails() { + val fileDetails = listOf( + TitledText("File Id:", "1237896548514214124235985214"), + TitledText("File Type:", ".PNG"), + TitledText("File Size:", "6mb"), + TitledText("Resolution:", "550x550"), + TitledText("Duration:", "N/A"), + ) + + val sent = TitledText("Sent:", "6:12 AM Tue, 09/08/2022 ") + val received = TitledText("Received:", "6:12 AM Tue, 09/08/2022 ") + val user = TitledText("Connor", "d4f1g54sdf5g1d5f4g65ds4564df65f4g65d54gdfsg") + + AppCompatTheme { + Column( + modifier = Modifier.verticalScroll(rememberScrollState()), + verticalArrangement = Arrangement.spacedBy(16.dp)) { + CardWithPadding { + FlowRow( + verticalArrangement = Arrangement.spacedBy(16.dp), + maxItemsInEachRow = 2 + ) { + fileDetails.forEach { + titledText(it, Modifier.weight(1f)) + } + } + } + CardWithPadding { + Column(verticalArrangement = Arrangement.spacedBy(16.dp)) { + titledText(sent) + titledText(received) + titledView("From:") { + Row { + Box(modifier = Modifier.width(60.dp).height(60.dp)) + Column { + titledText(user) + } + } + } + } + } + Card { + Column { + ItemButton("Reply", R.drawable.ic_reply) + Divider() + ItemButton("Resend", R.drawable.ic_reply) + Divider() + ItemButton("Delete", R.drawable.ic_delete_24, color = Color.Red) + } + } + } } + } - if (messageRecord!!.expiresIn <= 0 || messageRecord!!.expireStarted <= 0) { - binding.expiresContainer.visibility = View.GONE - } else { - binding.expiresContainer.visibility = View.VISIBLE - val elapsed = SnodeAPI.nowWithOffset - messageRecord!!.expireStarted - val remaining = messageRecord!!.expiresIn - elapsed + @Composable + fun Divider() { + Divider(modifier = Modifier.padding(horizontal = 16.dp), thickness = 1.dp, color = Color(0xff414141)) + } - val duration = ExpirationUtil.getExpirationDisplayValue(this, Math.max((remaining / 1000).toInt(), 1)) - binding.expiresIn.text = duration + @Composable + fun ItemButton(text: String, @DrawableRes icon: Int, color: Color = Color.White) { + TextButton( + modifier = Modifier + .fillMaxWidth() + .height(60.dp), + onClick = {}, + shape = RectangleShape, + ) { + Box(modifier = Modifier.width(80.dp).fillMaxHeight()) { + Icon( + painter = painterResource(id = icon), + contentDescription = "", + tint = color, + modifier = Modifier.align(Alignment.Center) + ) + } + Text(text, color = color, modifier = Modifier.fillMaxWidth()) } } + + @Composable + fun Card(content: @Composable () -> Unit) { + CardWithPadding(0.dp) { content() } + } + + @Composable + fun CardWithPadding(padding: Dp = 24.dp, content: @Composable () -> Unit) { + Card( + shape = RoundedCornerShape(16.dp), + elevation = 0.dp, + modifier = Modifier + .wrapContentHeight() + .fillMaxWidth() + .padding(horizontal = 32.dp), + backgroundColor = Color(0xff1b1b1b), + contentColor = Color.White + ) { Box(Modifier.padding(padding)) { content() } } + } + + @Composable + fun titledText(titledText: TitledText, modifier: Modifier = Modifier) { + Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(4.dp)) { + Title(titledText.title) + Text(titledText.value) + } + } + @Composable + fun titledView(title: String, modifier: Modifier = Modifier, content: @Composable () -> Unit) { + Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(4.dp)) { + Title(title) + content() + } + } + + @Composable + fun Title(text: String) { + Text(text, fontWeight = FontWeight.Bold) + } } \ No newline at end of file