mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-05-14 16:55:27 +00:00
android, desktop: support chat item ttl per chat
This commit is contained in:
+29
-8
@@ -1484,6 +1484,7 @@ data class Contact(
|
||||
val contactGroupMemberId: Long? = null,
|
||||
val contactGrpInvSent: Boolean,
|
||||
val chatTags: List<Long>,
|
||||
val chatItemTTL: Long?,
|
||||
override val chatDeleted: Boolean,
|
||||
val uiThemes: ThemeModeOverrides? = null,
|
||||
): SomeChat, NamedChat {
|
||||
@@ -1567,7 +1568,8 @@ data class Contact(
|
||||
contactGrpInvSent = false,
|
||||
chatDeleted = false,
|
||||
uiThemes = null,
|
||||
chatTags = emptyList()
|
||||
chatTags = emptyList(),
|
||||
chatItemTTL = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1726,6 +1728,7 @@ data class GroupInfo (
|
||||
val chatTs: Instant?,
|
||||
val uiThemes: ThemeModeOverrides? = null,
|
||||
val chatTags: List<Long>,
|
||||
val chatItemTTL: Long?,
|
||||
override val localAlias: String,
|
||||
): SomeChat, NamedChat {
|
||||
override val chatType get() = ChatType.Group
|
||||
@@ -1774,7 +1777,8 @@ data class GroupInfo (
|
||||
chatTs = Clock.System.now(),
|
||||
uiThemes = null,
|
||||
chatTags = emptyList(),
|
||||
localAlias = ""
|
||||
localAlias = "",
|
||||
chatItemTTL = null
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -4186,32 +4190,49 @@ enum class SwitchPhase {
|
||||
@SerialName("completed") Completed
|
||||
}
|
||||
|
||||
sealed class ChatItemTTL: Comparable<ChatItemTTL?> {
|
||||
sealed class ChatItemTTL: Comparable<ChatItemTTL> {
|
||||
object Day: ChatItemTTL()
|
||||
object Week: ChatItemTTL()
|
||||
object Month: ChatItemTTL()
|
||||
object Year: ChatItemTTL()
|
||||
data class Seconds(val secs: Long): ChatItemTTL()
|
||||
object None: ChatItemTTL()
|
||||
|
||||
override fun compareTo(other: ChatItemTTL?): Int = (seconds ?: Long.MAX_VALUE).compareTo(other?.seconds ?: Long.MAX_VALUE)
|
||||
override fun compareTo(other: ChatItemTTL): Int =
|
||||
(seconds.takeIf { it != 0L } ?: Long.MAX_VALUE)
|
||||
.compareTo(other.seconds.takeIf { it != 0L } ?: Long.MAX_VALUE)
|
||||
|
||||
val seconds: Long?
|
||||
val seconds: Long
|
||||
get() =
|
||||
when (this) {
|
||||
is None -> null
|
||||
is None -> 0
|
||||
is Day -> 86400L
|
||||
is Week -> 7 * 86400L
|
||||
is Month -> 30 * 86400L
|
||||
is Year -> 365 * 86400L
|
||||
is Seconds -> secs
|
||||
}
|
||||
|
||||
val text: String
|
||||
get() = when(this) {
|
||||
is None -> generalGetString(MR.strings.chat_item_ttl_none)
|
||||
is Day -> generalGetString(MR.strings.chat_item_ttl_day)
|
||||
is Week -> generalGetString(MR.strings.chat_item_ttl_week)
|
||||
is Month -> generalGetString(MR.strings.chat_item_ttl_month)
|
||||
is Year -> generalGetString(MR.strings.chat_item_ttl_year)
|
||||
is Seconds -> String.format(generalGetString(MR.strings.chat_item_ttl_seconds), secs)
|
||||
}
|
||||
|
||||
val doesNotExpire: Boolean get() = this is None
|
||||
|
||||
companion object {
|
||||
fun fromSeconds(seconds: Long?): ChatItemTTL =
|
||||
fun fromSeconds(seconds: Long): ChatItemTTL =
|
||||
when (seconds) {
|
||||
null -> None
|
||||
0L -> None
|
||||
86400L -> Day
|
||||
7 * 86400L -> Week
|
||||
30 * 86400L -> Month
|
||||
365 * 86400L -> Year
|
||||
else -> Seconds(seconds)
|
||||
}
|
||||
}
|
||||
|
||||
+19
-3
@@ -1182,7 +1182,13 @@ object ChatController {
|
||||
suspend fun getChatItemTTL(rh: Long?): ChatItemTTL {
|
||||
val userId = currentUserId("getChatItemTTL")
|
||||
val r = sendCmd(rh, CC.APIGetChatItemTTL(userId))
|
||||
if (r is CR.ChatItemTTL) return ChatItemTTL.fromSeconds(r.chatItemTTL)
|
||||
if (r is CR.ChatItemTTL) {
|
||||
if (r.chatItemTTL != null) {
|
||||
return ChatItemTTL.fromSeconds(r.chatItemTTL)
|
||||
} else {
|
||||
throw Exception("chatItemTTLResponse: invalid ttl")
|
||||
}
|
||||
}
|
||||
throw Exception("failed to get chat item TTL: ${r.responseType} ${r.details}")
|
||||
}
|
||||
|
||||
@@ -1193,6 +1199,13 @@ object ChatController {
|
||||
throw Exception("failed to set chat item TTL: ${r.responseType} ${r.details}")
|
||||
}
|
||||
|
||||
suspend fun setChatTTL(rh: Long?, chatType: ChatType, id: Long, chatItemTTL: ChatItemTTL?) {
|
||||
val userId = currentUserId("setChatTTL")
|
||||
val r = sendCmd(rh, CC.APISetChatTTL(userId, chatType, id, chatItemTTL?.seconds))
|
||||
if (r is CR.CmdOk) return
|
||||
throw Exception("failed to set chat TTL: ${r.responseType} ${r.details}")
|
||||
}
|
||||
|
||||
suspend fun apiSetNetworkConfig(cfg: NetCfg, showAlertOnError: Boolean = true, ctrl: ChatCtrl? = null): Boolean {
|
||||
val r = sendCmd(null, CC.APISetNetworkConfig(cfg), ctrl)
|
||||
return when (r) {
|
||||
@@ -3383,8 +3396,9 @@ sealed class CC {
|
||||
class ApiGetUsageConditions(): CC()
|
||||
class ApiSetConditionsNotified(val conditionsId: Long): CC()
|
||||
class ApiAcceptConditions(val conditionsId: Long, val operatorIds: List<Long>): CC()
|
||||
class APISetChatItemTTL(val userId: Long, val seconds: Long?): CC()
|
||||
class APISetChatItemTTL(val userId: Long, val seconds: Long): CC()
|
||||
class APIGetChatItemTTL(val userId: Long): CC()
|
||||
class APISetChatTTL(val userId: Long, val chatType: ChatType, val id: Long, val seconds: Long?): CC()
|
||||
class APISetNetworkConfig(val networkConfig: NetCfg): CC()
|
||||
class APIGetNetworkConfig: CC()
|
||||
class APISetNetworkInfo(val networkInfo: UserNetworkInfo): CC()
|
||||
@@ -3567,6 +3581,7 @@ sealed class CC {
|
||||
is ApiAcceptConditions -> "/_accept_conditions ${conditionsId} ${operatorIds.joinToString(",")}"
|
||||
is APISetChatItemTTL -> "/_ttl $userId ${chatItemTTLStr(seconds)}"
|
||||
is APIGetChatItemTTL -> "/_ttl $userId"
|
||||
is APISetChatTTL -> "/_ttl $userId ${chatRef(chatType, id)} ${chatItemTTLStr(seconds)}"
|
||||
is APISetNetworkConfig -> "/_network ${json.encodeToString(networkConfig)}"
|
||||
is APIGetNetworkConfig -> "/network"
|
||||
is APISetNetworkInfo -> "/_network info ${json.encodeToString(networkInfo)}"
|
||||
@@ -3727,6 +3742,7 @@ sealed class CC {
|
||||
is ApiAcceptConditions -> "apiAcceptConditions"
|
||||
is APISetChatItemTTL -> "apiSetChatItemTTL"
|
||||
is APIGetChatItemTTL -> "apiGetChatItemTTL"
|
||||
is APISetChatTTL -> "apiSetChatTTL"
|
||||
is APISetNetworkConfig -> "apiSetNetworkConfig"
|
||||
is APIGetNetworkConfig -> "apiGetNetworkConfig"
|
||||
is APISetNetworkInfo -> "apiSetNetworkInfo"
|
||||
@@ -3812,7 +3828,7 @@ sealed class CC {
|
||||
data class ItemRange(val from: Long, val to: Long)
|
||||
|
||||
fun chatItemTTLStr(seconds: Long?): String {
|
||||
if (seconds == null) return "none"
|
||||
if (seconds == null) return "default"
|
||||
return seconds.toString()
|
||||
}
|
||||
|
||||
|
||||
+96
-5
@@ -16,8 +16,10 @@ import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.text.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.platform.*
|
||||
@@ -36,12 +38,13 @@ import chat.simplex.common.model.*
|
||||
import chat.simplex.common.model.ChatController.appPrefs
|
||||
import chat.simplex.common.model.ChatModel.controller
|
||||
import chat.simplex.common.model.ChatModel.withChats
|
||||
import chat.simplex.common.model.ChatModel.withReportsChatsIfOpen
|
||||
import chat.simplex.common.ui.theme.*
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import chat.simplex.common.views.usersettings.*
|
||||
import chat.simplex.common.platform.*
|
||||
import chat.simplex.common.views.chat.group.ProgressIndicator
|
||||
import chat.simplex.common.views.chatlist.updateChatSettings
|
||||
import chat.simplex.common.views.database.*
|
||||
import chat.simplex.common.views.newchat.*
|
||||
import chat.simplex.res.MR
|
||||
import kotlinx.coroutines.delay
|
||||
@@ -74,6 +77,9 @@ fun ChatInfoView(
|
||||
}
|
||||
val chatRh = chat.remoteHostId
|
||||
val sendReceipts = remember(contact.id) { mutableStateOf(SendReceipts.fromBool(contact.chatSettings.sendRcpts, currentUser.sendRcptsContacts)) }
|
||||
val chatItemTTL = remember(contact.id) { mutableStateOf(if (contact.chatItemTTL != null) ChatItemTTL.fromSeconds(contact.chatItemTTL) else null) }
|
||||
val progressIndicator = rememberSaveable(contact.id) { mutableStateOf(false) }
|
||||
|
||||
ChatInfoLayout(
|
||||
chat,
|
||||
contact,
|
||||
@@ -84,6 +90,13 @@ fun ChatInfoView(
|
||||
updateChatSettings(chat.remoteHostId, chat.chatInfo, chatSettings, chatModel)
|
||||
sendReceipts.value = sendRcpts
|
||||
},
|
||||
chatItemTTL = chatItemTTL,
|
||||
setChatItemTTL = {
|
||||
val previousChatTTL = chatItemTTL.value
|
||||
chatItemTTL.value = it
|
||||
|
||||
setChatTTLAlert(chatModel, chat.remoteHostId, chat.chatInfo, chatItemTTL, previousChatTTL, progressIndicator)
|
||||
},
|
||||
connStats = connStats,
|
||||
contactNetworkStatus.value,
|
||||
customUserProfile,
|
||||
@@ -173,8 +186,13 @@ fun ChatInfoView(
|
||||
}
|
||||
},
|
||||
close = close,
|
||||
onSearchClicked = onSearchClicked
|
||||
onSearchClicked = onSearchClicked,
|
||||
enabled = remember { derivedStateOf { !progressIndicator.value } }
|
||||
)
|
||||
|
||||
if (progressIndicator.value) {
|
||||
ProgressIndicator()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -504,6 +522,8 @@ fun ChatInfoLayout(
|
||||
currentUser: User,
|
||||
sendReceipts: State<SendReceipts>,
|
||||
setSendReceipts: (SendReceipts) -> Unit,
|
||||
chatItemTTL: MutableState<ChatItemTTL?>,
|
||||
setChatItemTTL: (ChatItemTTL?) -> Unit,
|
||||
connStats: MutableState<ConnectionStats?>,
|
||||
contactNetworkStatus: NetworkStatus,
|
||||
customUserProfile: Profile?,
|
||||
@@ -520,7 +540,8 @@ fun ChatInfoLayout(
|
||||
syncContactConnectionForce: () -> Unit,
|
||||
verifyClicked: () -> Unit,
|
||||
close: () -> Unit,
|
||||
onSearchClicked: () -> Unit
|
||||
onSearchClicked: () -> Unit,
|
||||
enabled: State<Boolean>
|
||||
) {
|
||||
val cStats = connStats.value
|
||||
val scrollState = rememberScrollState()
|
||||
@@ -528,7 +549,7 @@ fun ChatInfoLayout(
|
||||
KeyChangeEffect(chat.id) {
|
||||
scope.launch { scrollState.scrollTo(0) }
|
||||
}
|
||||
ColumnWithScrollBar {
|
||||
ColumnWithScrollBar(Modifier.alpha(if (enabled.value) 1f else 0.6f)) {
|
||||
Row(
|
||||
Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.Center
|
||||
@@ -583,6 +604,13 @@ fun ChatInfoLayout(
|
||||
// } else if (developerTools) {
|
||||
// SynchronizeConnectionButtonForce(syncContactConnectionForce)
|
||||
// }
|
||||
TtlOptions(
|
||||
chatItemTTL,
|
||||
enabled = remember { mutableStateOf(true) },
|
||||
onSelected = setChatItemTTL,
|
||||
default = chatModel.chatItemTTL,
|
||||
icon = painterResource(MR.images.ic_delete),
|
||||
)
|
||||
}
|
||||
|
||||
WallpaperButton {
|
||||
@@ -1308,6 +1336,66 @@ fun queueInfoText(info: Pair<RcvMsgInfo?, ServerQueueInfo>): String {
|
||||
return generalGetString(MR.strings.message_queue_info_server_info).format(json.encodeToString(qInfo), msgInfo)
|
||||
}
|
||||
|
||||
fun setChatTTLAlert(
|
||||
m: ChatModel,
|
||||
rhId: Long?,
|
||||
chatInfo: ChatInfo,
|
||||
selectedChatTTL: MutableState<ChatItemTTL?>,
|
||||
previousChatTTL: ChatItemTTL?,
|
||||
progressIndicator: MutableState<Boolean>
|
||||
) {
|
||||
val disablingExpiration = selectedChatTTL.value?.doesNotExpire == true || (selectedChatTTL.value == null && chatModel.chatItemTTL.value.doesNotExpire)
|
||||
val changingExpiration = selectedChatTTL.value == null || (previousChatTTL?.doesNotExpire == false)
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(
|
||||
if (disablingExpiration) {
|
||||
MR.strings.disable_automatic_deletion_question
|
||||
} else if (changingExpiration) {
|
||||
MR.strings.change_automatic_deletion_question
|
||||
} else MR.strings.enable_automatic_deletion_question),
|
||||
text = generalGetString(if (disablingExpiration) MR.strings.disable_automatic_deletion_message else MR.strings.change_automatic_chat_deletion_message),
|
||||
confirmText = generalGetString(if (disablingExpiration) MR.strings.disable_automatic_deletion else MR.strings.delete_messages),
|
||||
onConfirm = { setChatTTL(m, rhId, chatInfo, selectedChatTTL, progressIndicator, previousChatTTL) },
|
||||
onDismiss = { selectedChatTTL.value = previousChatTTL },
|
||||
onDismissRequest = { selectedChatTTL.value = previousChatTTL },
|
||||
destructive = true,
|
||||
)
|
||||
}
|
||||
|
||||
private fun setChatTTL(
|
||||
m: ChatModel,
|
||||
rhId: Long?,
|
||||
chatInfo: ChatInfo,
|
||||
chatTTL: MutableState<ChatItemTTL?>,
|
||||
progressIndicator: MutableState<Boolean>,
|
||||
previousChatTTL: ChatItemTTL?
|
||||
) {
|
||||
progressIndicator.value = true
|
||||
withBGApi {
|
||||
try {
|
||||
m.controller.setChatTTL(rhId, chatInfo.chatType, chatInfo.apiId, chatTTL.value)
|
||||
afterSetChatTTL(m, chatInfo, progressIndicator)
|
||||
} catch (e: Exception) {
|
||||
chatTTL.value = previousChatTTL
|
||||
afterSetChatTTL(m, chatInfo, progressIndicator)
|
||||
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_changing_message_deletion), e.stackTraceToString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun afterSetChatTTL(m: ChatModel, chatInfo: ChatInfo, progressIndicator: MutableState<Boolean>) {
|
||||
withApi {
|
||||
try {
|
||||
// this is using current remote host on purpose - if it changes during update, it will load correct chats
|
||||
apiLoadMessages(m.remoteHostId(), chatInfo.chatType, chatInfo.apiId, contentTag = null, pagination = ChatPagination.Initial(ChatPagination.INITIAL_COUNT), replaceChat = true)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "apiGetChat error: ${e.message}")
|
||||
} finally {
|
||||
progressIndicator.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreviewChatInfoLayout() {
|
||||
@@ -1322,6 +1410,8 @@ fun PreviewChatInfoLayout() {
|
||||
User.sampleData,
|
||||
sendReceipts = remember { mutableStateOf(SendReceipts.Yes) },
|
||||
setSendReceipts = {},
|
||||
chatItemTTL = remember { mutableStateOf(ChatItemTTL.fromSeconds(0)) },
|
||||
setChatItemTTL = {},
|
||||
localAlias = "",
|
||||
connectionCode = "123",
|
||||
developerTools = false,
|
||||
@@ -1338,7 +1428,8 @@ fun PreviewChatInfoLayout() {
|
||||
syncContactConnectionForce = {},
|
||||
verifyClicked = {},
|
||||
close = {},
|
||||
onSearchClicked = {}
|
||||
onSearchClicked = {},
|
||||
enabled = remember { mutableStateOf(true) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -28,7 +28,8 @@ suspend fun apiLoadMessages(
|
||||
contentTag: MsgContentTag?,
|
||||
pagination: ChatPagination,
|
||||
search: String = "",
|
||||
visibleItemIndexesNonReversed: () -> IntRange = { 0 .. 0 }
|
||||
visibleItemIndexesNonReversed: () -> IntRange = { 0 .. 0 },
|
||||
replaceChat: Boolean = false
|
||||
) = coroutineScope {
|
||||
val (chat, navInfo) = chatModel.controller.apiGetChat(rhId, chatType, apiId, contentTag, pagination, search) ?: return@coroutineScope
|
||||
// For .initial allow the chatItems to be empty as well as chatModel.chatId to not match this chat because these values become set after .initial finishes
|
||||
@@ -47,6 +48,8 @@ suspend fun apiLoadMessages(
|
||||
withChats {
|
||||
if (getChat(chat.id) == null) {
|
||||
addChat(chat)
|
||||
} else if (replaceChat) {
|
||||
replaceChat(chat.remoteHostId, chat.id, chat)
|
||||
} else {
|
||||
updateChatInfo(chat.remoteHostId, chat.chatInfo)
|
||||
updateChatStats(chat.remoteHostId, chat.id, chat.chatStats)
|
||||
|
||||
+35
-4
@@ -17,6 +17,7 @@ import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
@@ -39,6 +40,7 @@ import chat.simplex.common.platform.*
|
||||
import chat.simplex.common.views.chat.*
|
||||
import chat.simplex.common.views.chat.item.ItemAction
|
||||
import chat.simplex.common.views.chatlist.*
|
||||
import chat.simplex.common.views.database.TtlOptions
|
||||
import chat.simplex.res.MR
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import kotlinx.coroutines.*
|
||||
@@ -55,7 +57,11 @@ fun ModalData.GroupChatInfoView(chatModel: ChatModel, rhId: Long?, chatId: Strin
|
||||
if (chat != null && chat.chatInfo is ChatInfo.Group && currentUser != null) {
|
||||
val groupInfo = chat.chatInfo.groupInfo
|
||||
val sendReceipts = remember { mutableStateOf(SendReceipts.fromBool(groupInfo.chatSettings.sendRcpts, currentUser.sendRcptsSmallGroups)) }
|
||||
val chatItemTTL = remember(groupInfo.id) { mutableStateOf(if (groupInfo.chatItemTTL != null) ChatItemTTL.fromSeconds(groupInfo.chatItemTTL) else null) }
|
||||
val progressIndicator = rememberSaveable(groupInfo.id) { mutableStateOf(false) }
|
||||
// TODO [ttl] disable all interactions while ttl is changing
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
GroupChatInfoLayout(
|
||||
chat,
|
||||
groupInfo,
|
||||
@@ -66,6 +72,13 @@ fun ModalData.GroupChatInfoView(chatModel: ChatModel, rhId: Long?, chatId: Strin
|
||||
updateChatSettings(chat.remoteHostId, chat.chatInfo, chatSettings, chatModel)
|
||||
sendReceipts.value = sendRcpts
|
||||
},
|
||||
chatItemTTL = chatItemTTL,
|
||||
setChatItemTTL = {
|
||||
val previousChatTTL = chatItemTTL.value
|
||||
chatItemTTL.value = it
|
||||
|
||||
setChatTTLAlert(chatModel, chat.remoteHostId, chat.chatInfo, chatItemTTL, previousChatTTL, progressIndicator)
|
||||
},
|
||||
members = remember { chatModel.groupMembers }.value
|
||||
.filter { it.memberStatus != GroupMemberStatus.MemLeft && it.memberStatus != GroupMemberStatus.MemRemoved }
|
||||
.sortedByDescending { it.memberRole },
|
||||
@@ -125,8 +138,13 @@ fun ModalData.GroupChatInfoView(chatModel: ChatModel, rhId: Long?, chatId: Strin
|
||||
manageGroupLink = {
|
||||
ModalManager.end.showModal { GroupLinkView(chatModel, rhId, groupInfo, groupLink, groupLinkMemberRole, onGroupLinkUpdated) }
|
||||
},
|
||||
onSearchClicked = onSearchClicked
|
||||
onSearchClicked = onSearchClicked,
|
||||
enabled = remember { derivedStateOf { !progressIndicator.value } }
|
||||
)
|
||||
|
||||
if (progressIndicator.value) {
|
||||
ProgressIndicator()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,6 +303,8 @@ fun ModalData.GroupChatInfoLayout(
|
||||
currentUser: User,
|
||||
sendReceipts: State<SendReceipts>,
|
||||
setSendReceipts: (SendReceipts) -> Unit,
|
||||
chatItemTTL: MutableState<ChatItemTTL?>,
|
||||
setChatItemTTL: (ChatItemTTL?) -> Unit,
|
||||
members: List<GroupMember>,
|
||||
developerTools: Boolean,
|
||||
onLocalAliasChanged: (String) -> Unit,
|
||||
@@ -300,7 +320,8 @@ fun ModalData.GroupChatInfoLayout(
|
||||
leaveGroup: () -> Unit,
|
||||
manageGroupLink: () -> Unit,
|
||||
close: () -> Unit = { ModalManager.closeAllModalsEverywhere()},
|
||||
onSearchClicked: () -> Unit
|
||||
onSearchClicked: () -> Unit,
|
||||
enabled: State<Boolean>
|
||||
) {
|
||||
val listState = remember { appBarHandler.listState }
|
||||
val scope = rememberCoroutineScope()
|
||||
@@ -314,7 +335,7 @@ fun ModalData.GroupChatInfoLayout(
|
||||
if (s.isEmpty()) members else members.filter { m -> m.anyNameContains(s) }
|
||||
}
|
||||
}
|
||||
Box {
|
||||
Box(Modifier.alpha(if (enabled.value) 1f else 0.6f)) {
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
LazyColumnWithScrollBar(
|
||||
state = listState,
|
||||
@@ -382,6 +403,14 @@ fun ModalData.GroupChatInfoLayout(
|
||||
SendReceiptsOptionDisabled()
|
||||
}
|
||||
|
||||
TtlOptions(
|
||||
chatItemTTL,
|
||||
enabled = remember { mutableStateOf(true) },
|
||||
onSelected = setChatItemTTL,
|
||||
default = chatModel.chatItemTTL,
|
||||
icon = painterResource(MR.images.ic_delete),
|
||||
)
|
||||
|
||||
WallpaperButton {
|
||||
ModalManager.end.showModal {
|
||||
val chat = remember { derivedStateOf { chatModel.chats.value.firstOrNull { it.id == chat.id } } }
|
||||
@@ -770,12 +799,14 @@ fun PreviewGroupChatInfoLayout() {
|
||||
User.sampleData,
|
||||
sendReceipts = remember { mutableStateOf(SendReceipts.Yes) },
|
||||
setSendReceipts = {},
|
||||
chatItemTTL = remember { mutableStateOf(ChatItemTTL.fromSeconds(0)) },
|
||||
setChatItemTTL = {},
|
||||
members = listOf(GroupMember.sampleData, GroupMember.sampleData, GroupMember.sampleData),
|
||||
developerTools = false,
|
||||
onLocalAliasChanged = {},
|
||||
groupLink = null,
|
||||
scrollToItemId = remember { mutableStateOf(null) },
|
||||
addMembers = {}, showMemberInfo = {}, editGroupProfile = {}, addOrEditWelcomeMessage = {}, openPreferences = {}, deleteGroup = {}, clearChat = {}, leaveGroup = {}, manageGroupLink = {}, onSearchClicked = {},
|
||||
addMembers = {}, showMemberInfo = {}, editGroupProfile = {}, addOrEditWelcomeMessage = {}, openPreferences = {}, deleteGroup = {}, clearChat = {}, leaveGroup = {}, manageGroupLink = {}, onSearchClicked = {}, enabled = remember { mutableStateOf(true) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+25
-14
@@ -12,6 +12,7 @@ import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import dev.icerock.moko.resources.compose.painterResource
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import androidx.compose.ui.text.*
|
||||
@@ -108,6 +109,9 @@ fun DatabaseView() {
|
||||
}
|
||||
},
|
||||
onChatItemTTLSelected = {
|
||||
if (it == null) {
|
||||
return@DatabaseLayout
|
||||
}
|
||||
val oldValue = chatItemTTL.value
|
||||
chatItemTTL.value = it
|
||||
if (it < oldValue) {
|
||||
@@ -158,7 +162,7 @@ fun DatabaseLayout(
|
||||
exportArchive: () -> Unit,
|
||||
deleteChatAlert: () -> Unit,
|
||||
deleteAppFilesAndMedia: () -> Unit,
|
||||
onChatItemTTLSelected: (ChatItemTTL) -> Unit,
|
||||
onChatItemTTLSelected: (ChatItemTTL?) -> Unit,
|
||||
disconnectAllHosts: () -> Unit,
|
||||
) {
|
||||
val operationsDisabled = progressIndicator && !chatModel.desktopNoUserNoRemote
|
||||
@@ -300,27 +304,34 @@ private fun setChatItemTTLAlert(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TtlOptions(current: State<ChatItemTTL>, enabled: State<Boolean>, onSelected: (ChatItemTTL) -> Unit) {
|
||||
fun TtlOptions(
|
||||
current: State<ChatItemTTL?>,
|
||||
enabled: State<Boolean>,
|
||||
onSelected: (ChatItemTTL?) -> Unit,
|
||||
default: State<ChatItemTTL>? = null,
|
||||
icon: Painter? = null
|
||||
) {
|
||||
val values = remember {
|
||||
val all: ArrayList<ChatItemTTL> = arrayListOf(ChatItemTTL.None, ChatItemTTL.Month, ChatItemTTL.Week, ChatItemTTL.Day)
|
||||
if (current.value is ChatItemTTL.Seconds) {
|
||||
all.add(current.value)
|
||||
val all: ArrayList<ChatItemTTL> = arrayListOf(ChatItemTTL.None, ChatItemTTL.Year, ChatItemTTL.Month, ChatItemTTL.Week, ChatItemTTL.Day)
|
||||
val currentValue = current.value
|
||||
if (currentValue is ChatItemTTL.Seconds) {
|
||||
all.add(currentValue)
|
||||
}
|
||||
all.map {
|
||||
when (it) {
|
||||
is ChatItemTTL.None -> it to generalGetString(MR.strings.chat_item_ttl_none)
|
||||
is ChatItemTTL.Day -> it to generalGetString(MR.strings.chat_item_ttl_day)
|
||||
is ChatItemTTL.Week -> it to generalGetString(MR.strings.chat_item_ttl_week)
|
||||
is ChatItemTTL.Month -> it to generalGetString(MR.strings.chat_item_ttl_month)
|
||||
is ChatItemTTL.Seconds -> it to String.format(generalGetString(MR.strings.chat_item_ttl_seconds), it.secs)
|
||||
}
|
||||
val options = mutableListOf<Pair<ChatItemTTL?, String>>().apply {
|
||||
all.mapTo(this) { it to it.text }
|
||||
}
|
||||
|
||||
if (default != null) {
|
||||
options.add(null to String.format(generalGetString(MR.strings.chat_item_ttl_default), default.value.text))
|
||||
}
|
||||
|
||||
options
|
||||
}
|
||||
ExposedDropDownSettingRow(
|
||||
generalGetString(MR.strings.delete_messages_after),
|
||||
values,
|
||||
current,
|
||||
icon = null,
|
||||
icon = icon,
|
||||
enabled = enabled,
|
||||
onSelected = onSelected
|
||||
)
|
||||
|
||||
@@ -540,6 +540,11 @@
|
||||
|
||||
<!-- Chat Info Settings - ChatInfoView.kt -->
|
||||
<string name="notifications">Notifications</string>
|
||||
<string name="disable_automatic_deletion_question">Disable automatic message deletion?</string>
|
||||
<string name="change_automatic_deletion_question">Change automatic message deletion?</string>
|
||||
<string name="disable_automatic_deletion_message">Messages on this chat will never be deleted.</string>
|
||||
<string name="change_automatic_chat_deletion_message">This action cannot be undone - the messages sent and received on this chat earlier than selected will be deleted. It may take several minutes.</string>
|
||||
<string name="disable_automatic_deletion">Disable delete messages</string>
|
||||
|
||||
<!-- Chat Info Actions - ChatInfoView.kt -->
|
||||
<string name="info_view_connect_button">connect</string>
|
||||
@@ -1396,7 +1401,9 @@
|
||||
<string name="chat_item_ttl_day">1 day</string>
|
||||
<string name="chat_item_ttl_week">1 week</string>
|
||||
<string name="chat_item_ttl_month">1 month</string>
|
||||
<string name="chat_item_ttl_year">1 year</string>
|
||||
<string name="chat_item_ttl_seconds">%s second(s)</string>
|
||||
<string name="chat_item_ttl_default">default (%s)</string>
|
||||
<string name="messages_section_title">Messages</string>
|
||||
<string name="messages_section_description">This setting applies to messages in your current chat profile</string>
|
||||
<string name="delete_messages_after">Delete messages after</string>
|
||||
|
||||
Reference in New Issue
Block a user