mirror of
https://github.com/oxen-io/session-android.git
synced 2025-04-28 08:40:47 +00:00
Create Message Details screen
This commit is contained in:
parent
ab8b2c42b9
commit
fc108b34db
@ -28,6 +28,7 @@ configurations.all {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
implementation "androidx.appcompat:appcompat:$appcompatVersion"
|
implementation "androidx.appcompat:appcompat:$appcompatVersion"
|
||||||
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
||||||
implementation "com.google.android.material:material:$materialVersion"
|
implementation "com.google.android.material:material:$materialVersion"
|
||||||
@ -161,8 +162,11 @@ dependencies {
|
|||||||
testImplementation 'org.robolectric:shadows-multidex:4.4'
|
testImplementation 'org.robolectric:shadows-multidex:4.4'
|
||||||
|
|
||||||
implementation 'androidx.compose.ui:ui:1.4.3'
|
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 '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
|
def canonicalVersionCode = 338
|
||||||
|
@ -2,32 +2,49 @@ package org.thoughtcrime.securesms.conversation.v2
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
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 dagger.hilt.android.AndroidEntryPoint
|
||||||
import network.loki.messenger.R
|
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.PassphraseRequiredActionBarActivity
|
||||||
import org.thoughtcrime.securesms.conversation.v2.utilities.ResendMessageUtilities
|
|
||||||
import org.thoughtcrime.securesms.database.Storage
|
import org.thoughtcrime.securesms.database.Storage
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
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 java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class MessageDetailActivity: PassphraseRequiredActionBarActivity() {
|
class MessageDetailActivity: PassphraseRequiredActionBarActivity() {
|
||||||
private lateinit var binding: ActivityMessageDetailBinding
|
|
||||||
var messageRecord: MessageRecord? = null
|
var messageRecord: MessageRecord? = null
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@ -42,58 +59,142 @@ class MessageDetailActivity: PassphraseRequiredActionBarActivity() {
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
|
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
|
||||||
super.onCreate(savedInstanceState, ready)
|
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)
|
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.
|
title = resources.getString(R.string.conversation_context__menu_message_details)
|
||||||
val author = Address.fromSerialized(TextSecurePreferences.getLocalNumber(this)!!)
|
|
||||||
messageRecord = DatabaseComponent.get(this).mmsSmsDatabase().getMessageFor(timestamp, author) ?: run {
|
setContentView(createComposeView())
|
||||||
finish()
|
}
|
||||||
return
|
|
||||||
}
|
private fun createComposeView(): ComposeView = ComposeView(this).apply {
|
||||||
val threadId = messageRecord!!.threadId
|
id = View.generateViewId()
|
||||||
val openGroup = storage.getOpenGroup(threadId)
|
setContent {
|
||||||
val blindedKey = openGroup?.let { group ->
|
MessageDetails()
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateContent() {
|
data class TitledText(val title: String, val value: String)
|
||||||
val dateLocale = Locale.getDefault()
|
|
||||||
val dateFormatter: SimpleDateFormat = DateUtils.getDetailedDateFormatter(this, dateLocale)
|
|
||||||
binding.sentTime.text = dateFormatter.format(Date(messageRecord!!.dateSent))
|
|
||||||
|
|
||||||
val errorMessage = DatabaseComponent.get(this).lokiMessageDatabase().getErrorMessage(messageRecord!!.getId())
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
if (errorMessage != null) {
|
@Preview
|
||||||
binding.errorMessage.text = errorMessage
|
@Composable
|
||||||
binding.resendContainer.isVisible = true
|
fun MessageDetails() {
|
||||||
binding.errorContainer.isVisible = true
|
val fileDetails = listOf(
|
||||||
} else {
|
TitledText("File Id:", "1237896548514214124235985214"),
|
||||||
binding.errorContainer.isVisible = false
|
TitledText("File Type:", ".PNG"),
|
||||||
binding.resendContainer.isVisible = false
|
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) {
|
@Composable
|
||||||
binding.expiresContainer.visibility = View.GONE
|
fun Divider() {
|
||||||
} else {
|
Divider(modifier = Modifier.padding(horizontal = 16.dp), thickness = 1.dp, color = Color(0xff414141))
|
||||||
binding.expiresContainer.visibility = View.VISIBLE
|
}
|
||||||
val elapsed = SnodeAPI.nowWithOffset - messageRecord!!.expireStarted
|
|
||||||
val remaining = messageRecord!!.expiresIn - elapsed
|
|
||||||
|
|
||||||
val duration = ExpirationUtil.getExpirationDisplayValue(this, Math.max((remaining / 1000).toInt(), 1))
|
@Composable
|
||||||
binding.expiresIn.text = duration
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user