mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-03-30 16:25:57 +00:00
android: show disappearing message timer on calls and group invitations (#4090)
* android: show disappearing message timer on calls and group invitations * fix padding
This commit is contained in:
@@ -78,19 +78,21 @@ func ciMetaText(
|
||||
}
|
||||
r = r + Text(" ")
|
||||
}
|
||||
if showStatus, let (icon, statusColor) = meta.statusIcon(color) {
|
||||
let t = Text(Image(systemName: icon)).font(.caption2)
|
||||
let gap = Text(" ").kerning(-1.25)
|
||||
let t1 = t.foregroundColor(transparent ? .clear : statusColor.opacity(0.67))
|
||||
switch sent {
|
||||
case nil: r = r + t1
|
||||
case .sent: r = r + t1 + gap
|
||||
case .rcvd1: r = r + t.foregroundColor(transparent ? .clear : statusColor.opacity(0.67)) + gap
|
||||
case .rcvd2: r = r + gap + t1
|
||||
if showStatus {
|
||||
if let (icon, statusColor) = meta.statusIcon(color) {
|
||||
let t = Text(Image(systemName: icon)).font(.caption2)
|
||||
let gap = Text(" ").kerning(-1.25)
|
||||
let t1 = t.foregroundColor(transparent ? .clear : statusColor.opacity(0.67))
|
||||
switch sent {
|
||||
case nil: r = r + t1
|
||||
case .sent: r = r + t1 + gap
|
||||
case .rcvd1: r = r + t.foregroundColor(transparent ? .clear : statusColor.opacity(0.67)) + gap
|
||||
case .rcvd2: r = r + gap + t1
|
||||
}
|
||||
r = r + Text(" ")
|
||||
} else if !meta.disappearing {
|
||||
r = r + statusIconText("circlebadge.fill", .clear) + Text(" ")
|
||||
}
|
||||
r = r + Text(" ")
|
||||
} else if !meta.disappearing {
|
||||
r = r + statusIconText("circlebadge.fill", .clear) + Text(" ")
|
||||
}
|
||||
if let enc = encrypted {
|
||||
r = r + statusIconText(enc ? "lock" : "lock.open", color) + Text(" ")
|
||||
|
||||
@@ -9,14 +9,20 @@ import androidx.compose.ui.graphics.Color
|
||||
import dev.icerock.moko.resources.compose.painterResource
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import chat.simplex.common.ui.theme.*
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.views.helpers.SimpleButton
|
||||
import chat.simplex.res.MR
|
||||
|
||||
@Composable
|
||||
fun CICallItemView(cInfo: ChatInfo, cItem: ChatItem, status: CICallStatus, duration: Int, acceptCall: (Contact) -> Unit) {
|
||||
fun CICallItemView(
|
||||
cInfo: ChatInfo,
|
||||
cItem: ChatItem,
|
||||
status: CICallStatus,
|
||||
duration: Int,
|
||||
acceptCall: (Contact) -> Unit,
|
||||
timedMessagesTTL: Int?
|
||||
) {
|
||||
val sent = cItem.chatDir.sent
|
||||
Column(
|
||||
Modifier
|
||||
@@ -41,12 +47,7 @@ fun CICallItemView(cInfo: ChatInfo, cItem: ChatItem, status: CICallStatus, durat
|
||||
CICallStatus.Error -> {}
|
||||
}
|
||||
|
||||
Text(
|
||||
cItem.timestampText,
|
||||
color = MaterialTheme.colors.secondary,
|
||||
fontSize = 14.sp,
|
||||
modifier = Modifier.padding(start = 3.dp)
|
||||
)
|
||||
CIMetaView(cItem, timedMessagesTTL, showStatus = false, showEdited = false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,11 +9,12 @@ import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import chat.simplex.common.ui.theme.*
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import chat.simplex.common.model.*
|
||||
@@ -26,7 +27,8 @@ fun CIGroupInvitationView(
|
||||
groupInvitation: CIGroupInvitation,
|
||||
memberRole: GroupMemberRole,
|
||||
chatIncognito: Boolean = false,
|
||||
joinGroup: (Long, () -> Unit) -> Unit
|
||||
joinGroup: (Long, () -> Unit) -> Unit,
|
||||
timedMessagesTTL: Int?
|
||||
) {
|
||||
val sent = ci.chatDir.sent
|
||||
val action = !sent && groupInvitation.status == CIGroupInvitationStatus.Pending
|
||||
@@ -69,13 +71,15 @@ fun CIGroupInvitationView(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun groupInvitationText() {
|
||||
when {
|
||||
sent -> Text(stringResource(MR.strings.you_sent_group_invitation))
|
||||
!sent && groupInvitation.status == CIGroupInvitationStatus.Pending -> Text(stringResource(MR.strings.you_are_invited_to_group))
|
||||
!sent && groupInvitation.status == CIGroupInvitationStatus.Accepted -> Text(stringResource(MR.strings.you_joined_this_group))
|
||||
!sent && groupInvitation.status == CIGroupInvitationStatus.Rejected -> Text(stringResource(MR.strings.you_rejected_group_invitation))
|
||||
!sent && groupInvitation.status == CIGroupInvitationStatus.Expired -> Text(stringResource(MR.strings.group_invitation_expired))
|
||||
fun groupInvitationStr(): String {
|
||||
return when {
|
||||
sent -> stringResource(MR.strings.you_sent_group_invitation)
|
||||
else -> when(groupInvitation.status) {
|
||||
CIGroupInvitationStatus.Pending -> stringResource(MR.strings.you_are_invited_to_group)
|
||||
CIGroupInvitationStatus.Accepted -> stringResource(MR.strings.you_joined_this_group)
|
||||
CIGroupInvitationStatus.Rejected -> stringResource(MR.strings.you_rejected_group_invitation)
|
||||
CIGroupInvitationStatus.Expired -> stringResource(MR.strings.group_invitation_expired)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,20 +113,24 @@ fun CIGroupInvitationView(
|
||||
Column(Modifier.padding(top = 2.dp, start = 5.dp)) {
|
||||
Divider(Modifier.fillMaxWidth().padding(bottom = 4.dp))
|
||||
if (action) {
|
||||
groupInvitationText()
|
||||
Text(groupInvitationStr())
|
||||
Text(
|
||||
stringResource(
|
||||
if (chatIncognito) MR.strings.group_invitation_tap_to_join_incognito else MR.strings.group_invitation_tap_to_join
|
||||
),
|
||||
buildAnnotatedString {
|
||||
append(generalGetString(if (chatIncognito) MR.strings.group_invitation_tap_to_join_incognito else MR.strings.group_invitation_tap_to_join))
|
||||
withStyle(reserveTimestampStyle) { append(reserveSpaceForMeta(ci.meta, timedMessagesTTL, encrypted = null, showStatus = false, showEdited = false)) }
|
||||
},
|
||||
color = if (inProgress.value)
|
||||
MaterialTheme.colors.secondary
|
||||
else
|
||||
if (chatIncognito) Indigo else MaterialTheme.colors.primary
|
||||
)
|
||||
} else {
|
||||
Box(Modifier.padding(end = 48.dp)) {
|
||||
groupInvitationText()
|
||||
}
|
||||
Text(
|
||||
buildAnnotatedString {
|
||||
append(groupInvitationStr())
|
||||
withStyle(reserveTimestampStyle) { append(reserveSpaceForMeta(ci.meta, timedMessagesTTL, encrypted = null, showStatus = false, showEdited = false)) }
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,12 +144,7 @@ fun CIGroupInvitationView(
|
||||
}
|
||||
}
|
||||
|
||||
Text(
|
||||
ci.timestampText,
|
||||
color = MaterialTheme.colors.secondary,
|
||||
fontSize = 14.sp,
|
||||
modifier = Modifier.padding(start = 3.dp)
|
||||
)
|
||||
CIMetaView(ci, timedMessagesTTL, showStatus = false, showEdited = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -157,7 +160,8 @@ fun PendingCIGroupInvitationViewPreview() {
|
||||
ci = ChatItem.getGroupInvitationSample(),
|
||||
groupInvitation = CIGroupInvitation.getSample(),
|
||||
memberRole = GroupMemberRole.Admin,
|
||||
joinGroup = { _, _ -> }
|
||||
joinGroup = { _, _ -> },
|
||||
timedMessagesTTL = null
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -173,7 +177,8 @@ fun CIGroupInvitationViewAcceptedPreview() {
|
||||
ci = ChatItem.getGroupInvitationSample(),
|
||||
groupInvitation = CIGroupInvitation.getSample(status = CIGroupInvitationStatus.Accepted),
|
||||
memberRole = GroupMemberRole.Admin,
|
||||
joinGroup = { _, _ -> }
|
||||
joinGroup = { _, _ -> },
|
||||
timedMessagesTTL = null
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -189,7 +194,8 @@ fun CIGroupInvitationViewLongNamePreview() {
|
||||
status = CIGroupInvitationStatus.Accepted
|
||||
),
|
||||
memberRole = GroupMemberRole.Admin,
|
||||
joinGroup = { _, _ -> }
|
||||
joinGroup = { _, _ -> },
|
||||
timedMessagesTTL = null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,9 @@ fun CIMetaView(
|
||||
red = minOf(metaColor.red * 1.33F, 1F),
|
||||
green = minOf(metaColor.green * 1.33F, 1F),
|
||||
blue = minOf(metaColor.red * 1.33F, 1F))
|
||||
}
|
||||
},
|
||||
showStatus: Boolean = true,
|
||||
showEdited: Boolean = true
|
||||
) {
|
||||
Row(Modifier.padding(start = 3.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
if (chatItem.isDeletedContent) {
|
||||
@@ -44,15 +46,31 @@ fun CIMetaView(
|
||||
modifier = Modifier.padding(start = 3.dp)
|
||||
)
|
||||
} else {
|
||||
CIMetaText(chatItem.meta, timedMessagesTTL, encrypted = chatItem.encryptedFile, metaColor, paleMetaColor)
|
||||
CIMetaText(
|
||||
chatItem.meta,
|
||||
timedMessagesTTL,
|
||||
encrypted = chatItem.encryptedFile,
|
||||
metaColor,
|
||||
paleMetaColor,
|
||||
showStatus = showStatus,
|
||||
showEdited = showEdited
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
// changing this function requires updating reserveSpaceForMeta
|
||||
private fun CIMetaText(meta: CIMeta, chatTTL: Int?, encrypted: Boolean?, color: Color, paleColor: Color) {
|
||||
if (meta.itemEdited) {
|
||||
private fun CIMetaText(
|
||||
meta: CIMeta,
|
||||
chatTTL: Int?,
|
||||
encrypted: Boolean?,
|
||||
color: Color,
|
||||
paleColor: Color,
|
||||
showStatus: Boolean = true,
|
||||
showEdited: Boolean = true
|
||||
) {
|
||||
if (showEdited && meta.itemEdited) {
|
||||
StatusIconText(painterResource(MR.images.ic_edit), color)
|
||||
Spacer(Modifier.width(3.dp))
|
||||
}
|
||||
@@ -64,18 +82,20 @@ private fun CIMetaText(meta: CIMeta, chatTTL: Int?, encrypted: Boolean?, color:
|
||||
}
|
||||
Spacer(Modifier.width(4.dp))
|
||||
}
|
||||
val statusIcon = meta.statusIcon(MaterialTheme.colors.primary, color, paleColor)
|
||||
if (statusIcon != null) {
|
||||
val (icon, statusColor) = statusIcon
|
||||
if (meta.itemStatus is CIStatus.SndSent || meta.itemStatus is CIStatus.SndRcvd) {
|
||||
Icon(painterResource(icon), null, Modifier.height(17.dp), tint = statusColor)
|
||||
} else {
|
||||
StatusIconText(painterResource(icon), statusColor)
|
||||
if (showStatus) {
|
||||
val statusIcon = meta.statusIcon(MaterialTheme.colors.primary, color, paleColor)
|
||||
if (statusIcon != null) {
|
||||
val (icon, statusColor) = statusIcon
|
||||
if (meta.itemStatus is CIStatus.SndSent || meta.itemStatus is CIStatus.SndRcvd) {
|
||||
Icon(painterResource(icon), null, Modifier.height(17.dp), tint = statusColor)
|
||||
} else {
|
||||
StatusIconText(painterResource(icon), statusColor)
|
||||
}
|
||||
Spacer(Modifier.width(4.dp))
|
||||
} else if (!meta.disappearing) {
|
||||
StatusIconText(painterResource(MR.images.ic_circle_filled), Color.Transparent)
|
||||
Spacer(Modifier.width(4.dp))
|
||||
}
|
||||
Spacer(Modifier.width(4.dp))
|
||||
} else if (!meta.disappearing) {
|
||||
StatusIconText(painterResource(MR.images.ic_circle_filled), Color.Transparent)
|
||||
Spacer(Modifier.width(4.dp))
|
||||
}
|
||||
if (encrypted != null) {
|
||||
StatusIconText(painterResource(if (encrypted) MR.images.ic_lock else MR.images.ic_lock_open_right), color)
|
||||
@@ -85,10 +105,10 @@ private fun CIMetaText(meta: CIMeta, chatTTL: Int?, encrypted: Boolean?, color:
|
||||
}
|
||||
|
||||
// the conditions in this function should match CIMetaText
|
||||
fun reserveSpaceForMeta(meta: CIMeta, chatTTL: Int?, encrypted: Boolean?): String {
|
||||
fun reserveSpaceForMeta(meta: CIMeta, chatTTL: Int?, encrypted: Boolean?, showStatus: Boolean = true, showEdited: Boolean = true): String {
|
||||
val iconSpace = " "
|
||||
var res = ""
|
||||
if (meta.itemEdited) res += iconSpace
|
||||
if (showEdited && meta.itemEdited) res += iconSpace
|
||||
if (meta.itemTimed != null) {
|
||||
res += iconSpace
|
||||
val ttl = meta.itemTimed.ttl
|
||||
@@ -96,7 +116,7 @@ fun reserveSpaceForMeta(meta: CIMeta, chatTTL: Int?, encrypted: Boolean?): Strin
|
||||
res += shortTimeText(ttl)
|
||||
}
|
||||
}
|
||||
if (meta.statusIcon(CurrentColors.value.colors.secondary) != null || !meta.disappearing) {
|
||||
if (showStatus && (meta.statusIcon(CurrentColors.value.colors.secondary) != null || !meta.disappearing)) {
|
||||
res += iconSpace
|
||||
}
|
||||
if (encrypted != null) {
|
||||
|
||||
@@ -365,7 +365,7 @@ fun ChatItemView(
|
||||
}
|
||||
|
||||
@Composable fun CallItem(status: CICallStatus, duration: Int) {
|
||||
CICallItemView(cInfo, cItem, status, duration, acceptCall)
|
||||
CICallItemView(cInfo, cItem, status, duration, acceptCall, cInfo.timedMessagesTTL)
|
||||
DeleteItemMenu()
|
||||
}
|
||||
|
||||
@@ -459,11 +459,11 @@ fun ChatItemView(
|
||||
DeleteItemMenu()
|
||||
}
|
||||
is CIContent.RcvGroupInvitation -> {
|
||||
CIGroupInvitationView(cItem, c.groupInvitation, c.memberRole, joinGroup = joinGroup, chatIncognito = cInfo.incognito)
|
||||
CIGroupInvitationView(cItem, c.groupInvitation, c.memberRole, joinGroup = joinGroup, chatIncognito = cInfo.incognito, timedMessagesTTL = cInfo.timedMessagesTTL)
|
||||
DeleteItemMenu()
|
||||
}
|
||||
is CIContent.SndGroupInvitation -> {
|
||||
CIGroupInvitationView(cItem, c.groupInvitation, c.memberRole, joinGroup = joinGroup, chatIncognito = cInfo.incognito)
|
||||
CIGroupInvitationView(cItem, c.groupInvitation, c.memberRole, joinGroup = joinGroup, chatIncognito = cInfo.incognito, timedMessagesTTL = cInfo.timedMessagesTTL)
|
||||
DeleteItemMenu()
|
||||
}
|
||||
is CIContent.RcvDirectEventContent -> {
|
||||
|
||||
Reference in New Issue
Block a user