mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-08-29 09:49:04 +00:00
ui: archive multiple reports (#5619)
* android, desktop: archive multiple reports * ios * change * changes * fix changing counter * fix changing counter2 * fix changing counter3 * unused * fix android * android notification * simplify * ios notification * orange * orange * core: update api * buttons * ios api * android api * fix 4 buttons * buttons and check for member active status * android colors and member active * show delete group button when not in the group anymore * title --------- Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
This commit is contained in:
co-authored by
Evgeny Poberezkin
parent
c5bb2c4ca2
commit
e7361cf025
+2
-2
@@ -851,8 +851,8 @@ object ChatModel {
|
||||
changeGroupReportsCounter(rhId, chatId, 1)
|
||||
}
|
||||
|
||||
fun decreaseGroupReportsCounter(rhId: Long?, chatId: ChatId) {
|
||||
changeGroupReportsCounter(rhId, chatId, -1)
|
||||
fun decreaseGroupReportsCounter(rhId: Long?, chatId: ChatId, by: Int = 1) {
|
||||
changeGroupReportsCounter(rhId, chatId, -by)
|
||||
}
|
||||
|
||||
private fun changeGroupReportsCounter(rhId: Long?, chatId: ChatId, by: Int = 0) {
|
||||
|
||||
+75
-48
@@ -1071,6 +1071,20 @@ object ChatController {
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun apiArchiveReceivedReports(rh: Long?, groupId: Long): CR.GroupChatItemsDeleted? {
|
||||
val r = sendCmd(rh, CC.ApiArchiveReceivedReports(groupId))
|
||||
if (r is CR.GroupChatItemsDeleted) return r
|
||||
Log.e(TAG, "apiArchiveReceivedReports bad response: ${r.responseType} ${r.details}")
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun apiDeleteReceivedReports(rh: Long?, groupId: Long, itemIds: List<Long>, mode: CIDeleteMode): List<ChatItemDeletion>? {
|
||||
val r = sendCmd(rh, CC.ApiDeleteReceivedReports(groupId, itemIds, mode))
|
||||
if (r is CR.ChatItemsDeleted) return r.chatItemDeletions
|
||||
Log.e(TAG, "apiDeleteReceivedReports bad response: ${r.responseType} ${r.details}")
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun testProtoServer(rh: Long?, server: String): ProtocolTestFailure? {
|
||||
val userId = currentUserId("testProtoServer")
|
||||
val r = sendCmd(rh, CC.APITestProtoServer(userId, server))
|
||||
@@ -2606,6 +2620,9 @@ object ChatController {
|
||||
} else {
|
||||
upsertChatItem(rhId, cInfo, toChatItem.chatItem)
|
||||
}
|
||||
if (cItem.isActiveReport) {
|
||||
decreaseGroupReportsCounter(rhId, cInfo.id)
|
||||
}
|
||||
}
|
||||
withReportsChatsIfOpen {
|
||||
if (cItem.isReport) {
|
||||
@@ -2619,54 +2636,7 @@ object ChatController {
|
||||
}
|
||||
}
|
||||
is CR.GroupChatItemsDeleted -> {
|
||||
if (!active(r.user)) {
|
||||
val users = chatController.listUsers(rhId)
|
||||
chatModel.users.clear()
|
||||
chatModel.users.addAll(users)
|
||||
return
|
||||
}
|
||||
val cInfo = ChatInfo.Group(r.groupInfo)
|
||||
withChats {
|
||||
r.chatItemIDs.forEach { itemId ->
|
||||
decreaseGroupReportsCounter(rhId, cInfo.id)
|
||||
val cItem = chatItems.value.lastOrNull { it.id == itemId } ?: return@forEach
|
||||
if (chatModel.chatId.value != null) {
|
||||
// Stop voice playback only inside a chat, allow to play in a chat list
|
||||
AudioPlayer.stop(cItem)
|
||||
}
|
||||
val isLastChatItem = getChat(cInfo.id)?.chatItems?.lastOrNull()?.id == cItem.id
|
||||
if (isLastChatItem && ntfManager.hasNotificationsForChat(cInfo.id)) {
|
||||
ntfManager.cancelNotificationsForChat(cInfo.id)
|
||||
ntfManager.displayNotification(
|
||||
r.user,
|
||||
cInfo.id,
|
||||
cInfo.displayName,
|
||||
generalGetString(MR.strings.marked_deleted_description)
|
||||
)
|
||||
}
|
||||
val deleted = if (r.member_ != null && (cItem.chatDir as CIDirection.GroupRcv?)?.groupMember?.groupMemberId != r.member_.groupMemberId) {
|
||||
CIDeleted.Moderated(Clock.System.now(), r.member_)
|
||||
} else {
|
||||
CIDeleted.Deleted(Clock.System.now())
|
||||
}
|
||||
upsertChatItem(rhId, cInfo, cItem.copy(meta = cItem.meta.copy(itemDeleted = deleted)))
|
||||
}
|
||||
}
|
||||
withReportsChatsIfOpen {
|
||||
r.chatItemIDs.forEach { itemId ->
|
||||
val cItem = chatItems.value.lastOrNull { it.id == itemId } ?: return@forEach
|
||||
if (chatModel.chatId.value != null) {
|
||||
// Stop voice playback only inside a chat, allow to play in a chat list
|
||||
AudioPlayer.stop(cItem)
|
||||
}
|
||||
val deleted = if (r.member_ != null && (cItem.chatDir as CIDirection.GroupRcv?)?.groupMember?.groupMemberId != r.member_.groupMemberId) {
|
||||
CIDeleted.Moderated(Clock.System.now(), r.member_)
|
||||
} else {
|
||||
CIDeleted.Deleted(Clock.System.now())
|
||||
}
|
||||
upsertChatItem(rhId, cInfo, cItem.copy(meta = cItem.meta.copy(itemDeleted = deleted)))
|
||||
}
|
||||
}
|
||||
groupChatItemsDeleted(rhId, r)
|
||||
}
|
||||
is CR.ReceivedGroupInvitation -> {
|
||||
if (active(r.user)) {
|
||||
@@ -3150,6 +3120,57 @@ object ChatController {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun groupChatItemsDeleted(rhId: Long?, r: CR.GroupChatItemsDeleted) {
|
||||
if (!activeUser(rhId, r.user)) {
|
||||
val users = chatController.listUsers(rhId)
|
||||
chatModel.users.clear()
|
||||
chatModel.users.addAll(users)
|
||||
return
|
||||
}
|
||||
val cInfo = ChatInfo.Group(r.groupInfo)
|
||||
withChats {
|
||||
r.chatItemIDs.forEach { itemId ->
|
||||
decreaseGroupReportsCounter(rhId, cInfo.id)
|
||||
val cItem = chatItems.value.lastOrNull { it.id == itemId } ?: return@forEach
|
||||
if (chatModel.chatId.value != null) {
|
||||
// Stop voice playback only inside a chat, allow to play in a chat list
|
||||
AudioPlayer.stop(cItem)
|
||||
}
|
||||
val isLastChatItem = getChat(cInfo.id)?.chatItems?.lastOrNull()?.id == cItem.id
|
||||
if (isLastChatItem && ntfManager.hasNotificationsForChat(cInfo.id)) {
|
||||
ntfManager.cancelNotificationsForChat(cInfo.id)
|
||||
ntfManager.displayNotification(
|
||||
r.user,
|
||||
cInfo.id,
|
||||
cInfo.displayName,
|
||||
generalGetString(MR.strings.marked_deleted_description)
|
||||
)
|
||||
}
|
||||
val deleted = if (r.member_ != null && (cItem.chatDir as CIDirection.GroupRcv?)?.groupMember?.groupMemberId != r.member_.groupMemberId) {
|
||||
CIDeleted.Moderated(Clock.System.now(), r.member_)
|
||||
} else {
|
||||
CIDeleted.Deleted(Clock.System.now())
|
||||
}
|
||||
upsertChatItem(rhId, cInfo, cItem.copy(meta = cItem.meta.copy(itemDeleted = deleted)))
|
||||
}
|
||||
}
|
||||
withReportsChatsIfOpen {
|
||||
r.chatItemIDs.forEach { itemId ->
|
||||
val cItem = chatItems.value.lastOrNull { it.id == itemId } ?: return@forEach
|
||||
if (chatModel.chatId.value != null) {
|
||||
// Stop voice playback only inside a chat, allow to play in a chat list
|
||||
AudioPlayer.stop(cItem)
|
||||
}
|
||||
val deleted = if (r.member_ != null && (cItem.chatDir as CIDirection.GroupRcv?)?.groupMember?.groupMemberId != r.member_.groupMemberId) {
|
||||
CIDeleted.Moderated(Clock.System.now(), r.member_)
|
||||
} else {
|
||||
CIDeleted.Deleted(Clock.System.now())
|
||||
}
|
||||
upsertChatItem(rhId, cInfo, cItem.copy(meta = cItem.meta.copy(itemDeleted = deleted)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun chatItemUpdateNotify(rh: Long?, user: UserLike, aChatItem: AChatItem) {
|
||||
val cInfo = aChatItem.chatInfo
|
||||
val cItem = aChatItem.chatItem
|
||||
@@ -3375,6 +3396,8 @@ sealed class CC {
|
||||
class ApiUpdateChatItem(val type: ChatType, val id: Long, val itemId: Long, val updatedMessage: UpdatedMessage, val live: Boolean): CC()
|
||||
class ApiDeleteChatItem(val type: ChatType, val id: Long, val itemIds: List<Long>, val mode: CIDeleteMode): CC()
|
||||
class ApiDeleteMemberChatItem(val groupId: Long, val itemIds: List<Long>): CC()
|
||||
class ApiArchiveReceivedReports(val groupId: Long): CC()
|
||||
class ApiDeleteReceivedReports(val groupId: Long, val itemIds: List<Long>, val mode: CIDeleteMode): CC()
|
||||
class ApiChatItemReaction(val type: ChatType, val id: Long, val itemId: Long, val add: Boolean, val reaction: MsgReaction): CC()
|
||||
class ApiGetReactionMembers(val userId: Long, val groupId: Long, val itemId: Long, val reaction: MsgReaction): CC()
|
||||
class ApiPlanForwardChatItems(val fromChatType: ChatType, val fromChatId: Long, val chatItemIds: List<Long>): CC()
|
||||
@@ -3553,6 +3576,8 @@ sealed class CC {
|
||||
is ApiUpdateChatItem -> "/_update item ${chatRef(type, id)} $itemId live=${onOff(live)} ${updatedMessage.cmdString}"
|
||||
is ApiDeleteChatItem -> "/_delete item ${chatRef(type, id)} ${itemIds.joinToString(",")} ${mode.deleteMode}"
|
||||
is ApiDeleteMemberChatItem -> "/_delete member item #$groupId ${itemIds.joinToString(",")}"
|
||||
is ApiArchiveReceivedReports -> "/_archive reports #$groupId"
|
||||
is ApiDeleteReceivedReports -> "/_delete reports #$groupId ${itemIds.joinToString(",")} ${mode.deleteMode}"
|
||||
is ApiChatItemReaction -> "/_reaction ${chatRef(type, id)} $itemId ${onOff(add)} ${json.encodeToString(reaction)}"
|
||||
is ApiGetReactionMembers -> "/_reaction members $userId #$groupId $itemId ${json.encodeToString(reaction)}"
|
||||
is ApiForwardChatItems -> {
|
||||
@@ -3719,6 +3744,8 @@ sealed class CC {
|
||||
is ApiUpdateChatItem -> "apiUpdateChatItem"
|
||||
is ApiDeleteChatItem -> "apiDeleteChatItem"
|
||||
is ApiDeleteMemberChatItem -> "apiDeleteMemberChatItem"
|
||||
is ApiArchiveReceivedReports -> "apiArchiveReceivedReports"
|
||||
is ApiDeleteReceivedReports -> "apiDeleteReceivedReports"
|
||||
is ApiChatItemReaction -> "apiChatItemReaction"
|
||||
is ApiGetReactionMembers -> "apiGetReactionMembers"
|
||||
is ApiForwardChatItems -> "apiForwardChatItems"
|
||||
|
||||
+6
-1
@@ -134,7 +134,12 @@ abstract class NtfManager {
|
||||
}
|
||||
res
|
||||
} else {
|
||||
cItem.text
|
||||
val mc = cItem.content.msgContent
|
||||
if (mc is MsgContent.MCReport) {
|
||||
generalGetString(MR.strings.notification_group_report).format(cItem.text.ifEmpty { mc.reason.text })
|
||||
} else {
|
||||
cItem.text
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+62
-2
@@ -196,6 +196,7 @@ fun ChatView(
|
||||
)
|
||||
}
|
||||
},
|
||||
archiveItems = { archiveItems(chatRh, chatInfo, selectedChatItems) },
|
||||
moderateItems = {
|
||||
if (chatInfo is ChatInfo.Group) {
|
||||
val itemIds = selectedChatItems.value
|
||||
@@ -397,6 +398,7 @@ fun ChatView(
|
||||
}
|
||||
},
|
||||
deleteMessages = { itemIds -> deleteMessages(chatRh, chatInfo, itemIds, false, moderate = false) },
|
||||
archiveReports = { itemIds, forAll -> archiveReports(chatRh, chatInfo, itemIds, forAll) },
|
||||
receiveFile = { fileId ->
|
||||
withBGApi { chatModel.controller.receiveFile(chatRh, user, fileId) }
|
||||
},
|
||||
@@ -673,6 +675,7 @@ fun ChatLayout(
|
||||
loadMessages: suspend (ChatId, ChatPagination, visibleItemIndexesNonReversed: () -> IntRange) -> Unit,
|
||||
deleteMessage: (Long, CIDeleteMode) -> Unit,
|
||||
deleteMessages: (List<Long>) -> Unit,
|
||||
archiveReports: (List<Long>, Boolean) -> Unit,
|
||||
receiveFile: (Long) -> Unit,
|
||||
cancelFile: (Long) -> Unit,
|
||||
joinGroup: (Long, () -> Unit) -> Unit,
|
||||
@@ -745,7 +748,7 @@ fun ChatLayout(
|
||||
}) {
|
||||
ChatItemsList(
|
||||
remoteHostId, chatInfo, unreadCount, composeState, composeViewHeight, searchValue,
|
||||
useLinkPreviews, linkMode, scrollToItemId, selectedChatItems, showMemberInfo, showChatInfo = info, loadMessages, deleteMessage, deleteMessages,
|
||||
useLinkPreviews, linkMode, scrollToItemId, selectedChatItems, showMemberInfo, showChatInfo = info, loadMessages, deleteMessage, deleteMessages, archiveReports,
|
||||
receiveFile, cancelFile, joinGroup, acceptCall, acceptFeature, openDirectChat, forwardItem,
|
||||
updateContactStats, updateMemberStats, syncContactConnection, syncMemberConnection, findModelChat, findModelMember,
|
||||
setReaction, showItemDetails, markItemsRead, markChatRead, remember { { onComposed(it) } }, developerTools, showViaProxy,
|
||||
@@ -792,6 +795,7 @@ fun ChatLayout(
|
||||
})
|
||||
}
|
||||
},
|
||||
archiveItems = { archiveItems(remoteHostId, chatInfo, selectedChatItems) },
|
||||
moderateItems = {},
|
||||
forwardItems = {}
|
||||
)
|
||||
@@ -1138,6 +1142,7 @@ fun BoxScope.ChatItemsList(
|
||||
loadMessages: suspend (ChatId, ChatPagination, visibleItemIndexesNonReversed: () -> IntRange) -> Unit,
|
||||
deleteMessage: (Long, CIDeleteMode) -> Unit,
|
||||
deleteMessages: (List<Long>) -> Unit,
|
||||
archiveReports: (List<Long>, Boolean) -> Unit,
|
||||
receiveFile: (Long) -> Unit,
|
||||
cancelFile: (Long) -> Unit,
|
||||
joinGroup: (Long, () -> Unit) -> Unit,
|
||||
@@ -1291,7 +1296,7 @@ fun BoxScope.ChatItemsList(
|
||||
highlightedItems.value = setOf()
|
||||
}
|
||||
}
|
||||
ChatItemView(remoteHostId, chatInfo, cItem, composeState, provider, useLinkPreviews = useLinkPreviews, linkMode = linkMode, revealed = revealed, highlighted = highlighted, range = range, fillMaxWidth = fillMaxWidth, selectedChatItems = selectedChatItems, selectChatItem = { selectUnselectChatItem(true, cItem, revealed, selectedChatItems, reversedChatItems) }, deleteMessage = deleteMessage, deleteMessages = deleteMessages, receiveFile = receiveFile, cancelFile = cancelFile, joinGroup = joinGroup, acceptCall = acceptCall, acceptFeature = acceptFeature, openDirectChat = openDirectChat, forwardItem = forwardItem, updateContactStats = updateContactStats, updateMemberStats = updateMemberStats, syncContactConnection = syncContactConnection, syncMemberConnection = syncMemberConnection, findModelChat = findModelChat, findModelMember = findModelMember, scrollToItem = scrollToItem, scrollToQuotedItemFromItem = scrollToQuotedItemFromItem, setReaction = setReaction, showItemDetails = showItemDetails, reveal = reveal, showMemberInfo = showMemberInfo, showChatInfo = showChatInfo, developerTools = developerTools, showViaProxy = showViaProxy, itemSeparation = itemSeparation, showTimestamp = itemSeparation.timestamp)
|
||||
ChatItemView(remoteHostId, chatInfo, cItem, composeState, provider, useLinkPreviews = useLinkPreviews, linkMode = linkMode, revealed = revealed, highlighted = highlighted, range = range, fillMaxWidth = fillMaxWidth, selectedChatItems = selectedChatItems, selectChatItem = { selectUnselectChatItem(true, cItem, revealed, selectedChatItems, reversedChatItems) }, deleteMessage = deleteMessage, deleteMessages = deleteMessages, archiveReports = archiveReports, receiveFile = receiveFile, cancelFile = cancelFile, joinGroup = joinGroup, acceptCall = acceptCall, acceptFeature = acceptFeature, openDirectChat = openDirectChat, forwardItem = forwardItem, updateContactStats = updateContactStats, updateMemberStats = updateMemberStats, syncContactConnection = syncContactConnection, syncMemberConnection = syncMemberConnection, findModelChat = findModelChat, findModelMember = findModelMember, scrollToItem = scrollToItem, scrollToQuotedItemFromItem = scrollToQuotedItemFromItem, setReaction = setReaction, showItemDetails = showItemDetails, reveal = reveal, showMemberInfo = showMemberInfo, showChatInfo = showChatInfo, developerTools = developerTools, showViaProxy = showViaProxy, itemSeparation = itemSeparation, showTimestamp = itemSeparation.timestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2368,6 +2373,59 @@ private fun deleteMessages(chatRh: Long?, chatInfo: ChatInfo, itemIds: List<Long
|
||||
}
|
||||
}
|
||||
|
||||
private fun archiveReports(chatRh: Long?, chatInfo: ChatInfo, itemIds: List<Long>, forAll: Boolean, onSuccess: () -> Unit = {}) {
|
||||
if (itemIds.isNotEmpty()) {
|
||||
withBGApi {
|
||||
val deleted = chatModel.controller.apiDeleteReceivedReports(
|
||||
chatRh,
|
||||
groupId = chatInfo.apiId,
|
||||
itemIds = itemIds,
|
||||
mode = if (forAll) CIDeleteMode.cidmBroadcast else CIDeleteMode.cidmInternalMark
|
||||
)
|
||||
if (deleted != null) {
|
||||
withChats {
|
||||
for (di in deleted) {
|
||||
val toChatItem = di.toChatItem?.chatItem
|
||||
if (toChatItem != null) {
|
||||
upsertChatItem(chatRh, chatInfo, toChatItem)
|
||||
} else {
|
||||
removeChatItem(chatRh, chatInfo, di.deletedChatItem.chatItem)
|
||||
}
|
||||
val deletedItem = di.deletedChatItem.chatItem
|
||||
if (deletedItem.isActiveReport) {
|
||||
decreaseGroupReportsCounter(chatRh, chatInfo.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
withReportsChatsIfOpen {
|
||||
for (di in deleted) {
|
||||
if (di.deletedChatItem.chatItem.isReport) {
|
||||
val toChatItem = di.toChatItem?.chatItem
|
||||
if (toChatItem != null) {
|
||||
upsertChatItem(chatRh, chatInfo, toChatItem)
|
||||
} else {
|
||||
removeChatItem(chatRh, chatInfo, di.deletedChatItem.chatItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun archiveItems(rhId: Long?, chatInfo: ChatInfo, selectedChatItems: MutableState<Set<Long>?>) {
|
||||
val itemIds = selectedChatItems.value
|
||||
if (itemIds != null) {
|
||||
showArchiveReportsAlert(itemIds.sorted(), chatInfo is ChatInfo.Group && chatInfo.groupInfo.membership.memberActive, archiveReports = { ids, forAll ->
|
||||
archiveReports(rhId, chatInfo, ids, forAll) {
|
||||
selectedChatItems.value = null
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun markUnreadChatAsRead(chatId: String) {
|
||||
val chat = chatModel.chats.value.firstOrNull { it.id == chatId }
|
||||
if (chat?.chatStats?.unreadChat != true) return
|
||||
@@ -2716,6 +2774,7 @@ fun PreviewChatLayout() {
|
||||
loadMessages = { _, _, _ -> },
|
||||
deleteMessage = { _, _ -> },
|
||||
deleteMessages = { _ -> },
|
||||
archiveReports = { _, _ -> },
|
||||
receiveFile = { _ -> },
|
||||
cancelFile = {},
|
||||
joinGroup = { _, _ -> },
|
||||
@@ -2791,6 +2850,7 @@ fun PreviewGroupChatLayout() {
|
||||
loadMessages = { _, _, _ -> },
|
||||
deleteMessage = { _, _ -> },
|
||||
deleteMessages = {},
|
||||
archiveReports = { _, _ -> },
|
||||
receiveFile = { _ -> },
|
||||
cancelFile = {},
|
||||
joinGroup = { _, _ -> },
|
||||
|
||||
+8
-2
@@ -53,11 +53,13 @@ fun SelectedItemsBottomToolbar(
|
||||
contentTag: MsgContentTag?,
|
||||
selectedChatItems: MutableState<Set<Long>?>,
|
||||
deleteItems: (Boolean) -> Unit, // Boolean - delete for everyone is possible
|
||||
archiveItems: () -> Unit,
|
||||
moderateItems: () -> Unit,
|
||||
forwardItems: () -> Unit,
|
||||
) {
|
||||
val deleteEnabled = remember { mutableStateOf(false) }
|
||||
val deleteForEveryoneEnabled = remember { mutableStateOf(false) }
|
||||
val canArchiveReports = remember { mutableStateOf(false) }
|
||||
val canModerate = remember { mutableStateOf(false) }
|
||||
val moderateEnabled = remember { mutableStateOf(false) }
|
||||
val forwardEnabled = remember { mutableStateOf(false) }
|
||||
@@ -80,7 +82,7 @@ fun SelectedItemsBottomToolbar(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
IconButton({ deleteItems(deleteForEveryoneEnabled.value) }, enabled = deleteEnabled.value && !deleteCountProhibited.value) {
|
||||
IconButton({ if (canArchiveReports.value) archiveItems() else deleteItems(deleteForEveryoneEnabled.value) }, enabled = deleteEnabled.value && !deleteCountProhibited.value) {
|
||||
Icon(
|
||||
painterResource(MR.images.ic_delete),
|
||||
null,
|
||||
@@ -111,7 +113,7 @@ fun SelectedItemsBottomToolbar(
|
||||
}
|
||||
val chatItems = remember { derivedStateOf { chatModel.chatItemsForContent(contentTag).value } }
|
||||
LaunchedEffect(chatInfo, chatItems.value, selectedChatItems.value) {
|
||||
recheckItems(chatInfo, chatItems.value, selectedChatItems, deleteEnabled, deleteForEveryoneEnabled, canModerate, moderateEnabled, forwardEnabled, deleteCountProhibited, forwardCountProhibited)
|
||||
recheckItems(chatInfo, chatItems.value, selectedChatItems, deleteEnabled, deleteForEveryoneEnabled, canArchiveReports, canModerate, moderateEnabled, forwardEnabled, deleteCountProhibited, forwardCountProhibited)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,6 +122,7 @@ private fun recheckItems(chatInfo: ChatInfo,
|
||||
selectedChatItems: MutableState<Set<Long>?>,
|
||||
deleteEnabled: MutableState<Boolean>,
|
||||
deleteForEveryoneEnabled: MutableState<Boolean>,
|
||||
canArchiveReports: MutableState<Boolean>,
|
||||
canModerate: MutableState<Boolean>,
|
||||
moderateEnabled: MutableState<Boolean>,
|
||||
forwardEnabled: MutableState<Boolean>,
|
||||
@@ -133,6 +136,7 @@ private fun recheckItems(chatInfo: ChatInfo,
|
||||
val selected = selectedChatItems.value ?: return
|
||||
var rDeleteEnabled = true
|
||||
var rDeleteForEveryoneEnabled = true
|
||||
var rCanArchiveReports = true
|
||||
var rModerateEnabled = true
|
||||
var rOnlyOwnGroupItems = true
|
||||
var rForwardEnabled = true
|
||||
@@ -141,6 +145,7 @@ private fun recheckItems(chatInfo: ChatInfo,
|
||||
if (selected.contains(ci.id)) {
|
||||
rDeleteEnabled = rDeleteEnabled && ci.canBeDeletedForSelf
|
||||
rDeleteForEveryoneEnabled = rDeleteForEveryoneEnabled && ci.meta.deletable && !ci.localNote && !ci.isReport
|
||||
rCanArchiveReports = rCanArchiveReports && ci.isActiveReport && ci.chatDir !is CIDirection.GroupSnd && chatInfo is ChatInfo.Group && chatInfo.groupInfo.membership.memberRole >= GroupMemberRole.Moderator
|
||||
rOnlyOwnGroupItems = rOnlyOwnGroupItems && ci.chatDir is CIDirection.GroupSnd && !ci.isReport
|
||||
rModerateEnabled = rModerateEnabled && ci.content.msgContent != null && ci.memberToModerate(chatInfo) != null && !ci.isReport
|
||||
rForwardEnabled = rForwardEnabled && ci.content.msgContent != null && ci.meta.itemDeleted == null && !ci.isLiveDummy && !ci.isReport
|
||||
@@ -150,6 +155,7 @@ private fun recheckItems(chatInfo: ChatInfo,
|
||||
rModerateEnabled = rModerateEnabled && !rOnlyOwnGroupItems
|
||||
deleteEnabled.value = rDeleteEnabled
|
||||
deleteForEveryoneEnabled.value = rDeleteForEveryoneEnabled
|
||||
canArchiveReports.value = rCanArchiveReports
|
||||
moderateEnabled.value = rModerateEnabled
|
||||
forwardEnabled.value = rForwardEnabled
|
||||
selectedChatItems.value = rSelectedChatItems
|
||||
|
||||
+45
-12
@@ -77,6 +77,7 @@ fun ChatItemView(
|
||||
selectChatItem: () -> Unit,
|
||||
deleteMessage: (Long, CIDeleteMode) -> Unit,
|
||||
deleteMessages: (List<Long>) -> Unit,
|
||||
archiveReports: (List<Long>, Boolean) -> Unit,
|
||||
receiveFile: (Long) -> Unit,
|
||||
cancelFile: (Long) -> Unit,
|
||||
joinGroup: (Long, () -> Unit) -> Unit,
|
||||
@@ -301,7 +302,7 @@ fun ChatItemView(
|
||||
cItem.isReport && cItem.meta.itemDeleted == null && cInfo is ChatInfo.Group -> {
|
||||
DefaultDropdownMenu(showMenu) {
|
||||
if (cItem.chatDir !is CIDirection.GroupSnd && cInfo.groupInfo.membership.memberRole >= GroupMemberRole.Moderator) {
|
||||
ArchiveReportItemAction(cItem, showMenu, deleteMessage)
|
||||
ArchiveReportItemAction(cItem.id, cInfo.groupInfo.membership.memberActive, showMenu, archiveReports)
|
||||
}
|
||||
DeleteItemAction(cItem, revealed, showMenu, questionText = deleteMessageQuestionText(), deleteMessage, deleteMessages, buttonText = stringResource(MR.strings.delete_report))
|
||||
Divider()
|
||||
@@ -914,23 +915,53 @@ private fun ReportItemAction(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ArchiveReportItemAction(cItem: ChatItem, showMenu: MutableState<Boolean>, deleteMessage: (Long, CIDeleteMode) -> Unit) {
|
||||
private fun ArchiveReportItemAction(id: Long, allowForAll: Boolean, showMenu: MutableState<Boolean>, archiveReports: (List<Long>, Boolean) -> Unit) {
|
||||
ItemAction(
|
||||
stringResource(MR.strings.archive_report),
|
||||
painterResource(MR.images.ic_inventory_2),
|
||||
onClick = {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(MR.strings.report_archive_alert_title),
|
||||
text = generalGetString(MR.strings.report_archive_alert_desc),
|
||||
onConfirm = {
|
||||
deleteMessage(cItem.id, CIDeleteMode.cidmInternalMark)
|
||||
},
|
||||
destructive = true,
|
||||
confirmText = generalGetString(MR.strings.archive_verb),
|
||||
)
|
||||
showArchiveReportsAlert(listOf(id), allowForAll, archiveReports)
|
||||
showMenu.value = false
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun showArchiveReportsAlert(ids: List<Long>, allowForAll: Boolean, archiveReports: (List<Long>, Boolean) -> Unit) {
|
||||
AlertManager.shared.showAlertDialogButtonsColumn(
|
||||
title = if (ids.size == 1) {
|
||||
generalGetString(MR.strings.report_archive_alert_title)
|
||||
} else {
|
||||
generalGetString(MR.strings.report_archive_alert_title_nth).format(ids.size)
|
||||
},
|
||||
color = Color.Red
|
||||
text = null,
|
||||
buttons = {
|
||||
// Archive for me
|
||||
SectionItemView({
|
||||
AlertManager.shared.hideAlert()
|
||||
archiveReports(ids, false)
|
||||
}) {
|
||||
Text(
|
||||
generalGetString(MR.strings.report_archive_for_me),
|
||||
Modifier.fillMaxWidth(),
|
||||
textAlign = TextAlign.Center,
|
||||
color = MaterialTheme.colors.error
|
||||
)
|
||||
}
|
||||
if (allowForAll) {
|
||||
// Archive for all moderators
|
||||
SectionItemView({
|
||||
AlertManager.shared.hideAlert()
|
||||
archiveReports(ids, true)
|
||||
}) {
|
||||
Text(
|
||||
stringResource(MR.strings.report_archive_for_all_moderators),
|
||||
Modifier.fillMaxWidth(),
|
||||
textAlign = TextAlign.Center,
|
||||
color = MaterialTheme.colors.error
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1310,6 +1341,7 @@ fun PreviewChatItemView(
|
||||
selectChatItem = {},
|
||||
deleteMessage = { _, _ -> },
|
||||
deleteMessages = { _ -> },
|
||||
archiveReports = { _, _ -> },
|
||||
receiveFile = { _ -> },
|
||||
cancelFile = {},
|
||||
joinGroup = { _, _ -> },
|
||||
@@ -1356,6 +1388,7 @@ fun PreviewChatItemViewDeletedContent() {
|
||||
selectChatItem = {},
|
||||
deleteMessage = { _, _ -> },
|
||||
deleteMessages = { _ -> },
|
||||
archiveReports = { _, _ -> },
|
||||
receiveFile = { _ -> },
|
||||
cancelFile = {},
|
||||
joinGroup = { _, _ -> },
|
||||
|
||||
+37
@@ -19,6 +19,7 @@ import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import chat.simplex.common.model.*
|
||||
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.platform.*
|
||||
@@ -299,6 +300,11 @@ fun GroupMenuItems(
|
||||
ToggleFavoritesChatAction(chat, chatModel, chat.chatInfo.chatSettings?.favorite == true, showMenu)
|
||||
ToggleNotificationsChatAction(chat, chatModel, groupInfo.chatSettings.enableNtfs.nextMode(true), showMenu)
|
||||
TagListAction(chat, showMenu)
|
||||
if (chat.chatStats.reportsCount > 0 && groupInfo.membership.memberRole >= GroupMemberRole.Moderator) {
|
||||
ArchiveAllReportsItemAction(showMenu) {
|
||||
archiveAllReportsForMe(chat.remoteHostId, chat.chatInfo.apiId)
|
||||
}
|
||||
}
|
||||
ClearChatAction(chat, showMenu)
|
||||
if (groupInfo.membership.memberCurrent) {
|
||||
LeaveGroupAction(chat.remoteHostId, groupInfo, chatModel, showMenu)
|
||||
@@ -563,6 +569,18 @@ private fun InvalidDataView() {
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ArchiveAllReportsItemAction(showMenu: MutableState<Boolean>, archiveReports: () -> Unit) {
|
||||
ItemAction(
|
||||
stringResource(MR.strings.archive_reports),
|
||||
painterResource(MR.images.ic_inventory_2),
|
||||
onClick = {
|
||||
showArchiveAllReportsForMeAlert(archiveReports)
|
||||
showMenu.value = false
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun markChatRead(c: Chat) {
|
||||
var chat = c
|
||||
withApi {
|
||||
@@ -886,6 +904,25 @@ fun updateChatSettings(remoteHostId: Long?, chatInfo: ChatInfo, chatSettings: Ch
|
||||
}
|
||||
}
|
||||
|
||||
private fun showArchiveAllReportsForMeAlert(archiveReports: () -> Unit) {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(MR.strings.report_archive_alert_title_all),
|
||||
text = generalGetString(MR.strings.report_archive_alert_desc_all),
|
||||
onConfirm = archiveReports,
|
||||
destructive = true,
|
||||
confirmText = generalGetString(MR.strings.archive_verb),
|
||||
)
|
||||
}
|
||||
|
||||
private fun archiveAllReportsForMe(chatRh: Long?, apiId: Long) {
|
||||
withBGApi {
|
||||
val r = chatModel.controller.apiArchiveReceivedReports(chatRh, apiId)
|
||||
if (r != null) {
|
||||
controller.groupChatItemsDeleted(chatRh, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
expect fun ChatListNavLinkLayout(
|
||||
chatLinkPreview: @Composable () -> Unit,
|
||||
|
||||
@@ -312,7 +312,12 @@
|
||||
<string name="message_deleted_or_not_received_error_desc">This message was deleted or not received yet.</string>
|
||||
<string name="report_reason_alert_title">Report reason?</string>
|
||||
<string name="report_archive_alert_title">Archive report?</string>
|
||||
<string name="report_archive_alert_title_nth">Archive %d reports?</string>
|
||||
<string name="report_archive_alert_title_all">Archive all reports?</string>
|
||||
<string name="report_archive_alert_desc">The report will be archived for you.</string>
|
||||
<string name="report_archive_alert_desc_all">All reports will be archived for you.</string>
|
||||
<string name="report_archive_for_me">For me</string>
|
||||
<string name="report_archive_for_all_moderators">For all moderators</string>
|
||||
|
||||
<!-- CIStatus errors -->
|
||||
<string name="ci_status_other_error">Error: %1$s</string>
|
||||
@@ -341,6 +346,7 @@
|
||||
<string name="search_verb">Search</string>
|
||||
<string name="archive_verb">Archive</string>
|
||||
<string name="archive_report">Archive report</string>
|
||||
<string name="archive_reports">Archive reports</string>
|
||||
<string name="delete_report">Delete report</string>
|
||||
<string name="sent_message">Sent message</string>
|
||||
<string name="received_message">Received message</string>
|
||||
@@ -447,6 +453,7 @@
|
||||
<string name="chat_list_businesses">Businesses</string>
|
||||
<string name="chat_list_notes">Notes</string>
|
||||
<string name="chat_list_group_reports">Reports</string>
|
||||
<string name="notification_group_report">Report: %s</string>
|
||||
<string name="chat_list_all">All</string>
|
||||
<string name="chat_list_add_list">Add list</string>
|
||||
<string name="group_reports_active_one">1 report</string>
|
||||
|
||||
Reference in New Issue
Block a user