ui: fix report archiving (#6239)

* kotlin: fix report archivation

* ios wip

* surrogate reports scope

* refactor
This commit is contained in:
spaced4ndy
2025-09-05 12:38:26 +01:00
committed by GitHub
parent 9d65b9eb2b
commit 9705ae15ea
8 changed files with 57 additions and 35 deletions
+2
View File
@@ -574,6 +574,8 @@ enum ChatCommand: ChatCmdProtocol {
} else {
"(_support)"
}
case .reports:
"(reports, prohibited)" // can't use surrogate Reports scope
}
}
+16 -12
View File
@@ -667,20 +667,24 @@ final class ChatModel: ObservableObject {
func getCIItemsModel(_ cInfo: ChatInfo, _ ci: ChatItem) -> ItemsModel? {
let cInfoScope = cInfo.groupChatScope()
if let cInfoScope = cInfoScope {
switch cInfoScope {
case .memberSupport:
switch secondaryIM?.secondaryIMFilter {
case .none:
return nil
case let .groupChatScopeContext(groupScopeInfo):
return (cInfo.id == chatId && sameChatScope(cInfoScope, groupScopeInfo.toChatScope())) ? secondaryIM : nil
case let .msgContentTagContext(contentTag):
return (cInfo.id == chatId && ci.isReport && contentTag == .report) ? secondaryIM : nil
}
return if let cInfoScope = cInfoScope {
switch (cInfoScope, secondaryIM?.secondaryIMFilter) {
case let (.memberSupport, .some(.groupChatScopeContext(groupScopeInfo))):
// Chat with member or Chat with admins opened (secondaryIM has .groupChatScopeContext filter), cInfo has matching scope
(cInfo.id == chatId && sameChatScope(cInfoScope, groupScopeInfo.toChatScope())) ? secondaryIM : nil
case let (.memberSupport, .some(.msgContentTagContext(contentTag))):
// Reports view opened (secondaryIM has .msgContentTagContext(.report) filter), we process event (cInfo has proper .memberSupport scope)
(cInfo.id == chatId && ci.isReport && contentTag == .report) ? secondaryIM : nil
case let (.reports, .some(.msgContentTagContext(contentTag))):
// Reports view opened (secondaryIM has .msgContentTagContext(.report) filter), we process user action (cInfo has surrogate .reports scope)
(cInfo.id == chatId && ci.isReport && contentTag == .report) ? secondaryIM : nil
default:
nil
}
} else {
return cInfo.id == chatId ? im : nil
cInfo.id == chatId ? im : nil
}
}
+10 -7
View File
@@ -234,13 +234,13 @@ struct ChatView: View {
.confirmationDialog(selectedChatItems?.count == 1 ? "Archive report?" : "Archive \((selectedChatItems?.count ?? 0)) reports?", isPresented: $showArchiveSelectedReports, titleVisibility: .visible) {
Button("For me", role: .destructive) {
if let selected = selectedChatItems {
archiveReports(chat.chatInfo, selected.sorted(), false, deletedSelectedMessages)
archiveReports(chat, selected.sorted(), false, deletedSelectedMessages)
}
}
if case let ChatInfo.group(groupInfo, _) = chat.chatInfo, groupInfo.membership.memberActive {
Button("For all moderators", role: .destructive) {
if let selected = selectedChatItems {
archiveReports(chat.chatInfo, selected.sorted(), true, deletedSelectedMessages)
archiveReports(chat, selected.sorted(), true, deletedSelectedMessages)
}
}
}
@@ -598,6 +598,8 @@ struct ChatView: View {
} else {
textChatToolbar("Chat with admins")
}
case .reports:
textChatToolbar("Member reports")
}
case let .msgContentTagContext(contentTag):
switch contentTag {
@@ -1913,14 +1915,14 @@ struct ChatView: View {
.confirmationDialog(archivingReports?.count == 1 ? "Archive report?" : "Archive \(archivingReports?.count ?? 0) reports?", isPresented: $showArchivingReports, titleVisibility: .visible) {
Button("For me", role: .destructive) {
if let reports = self.archivingReports {
archiveReports(chat.chatInfo, reports.sorted(), false)
archiveReports(chat, reports.sorted(), false)
self.archivingReports = []
}
}
if case let ChatInfo.group(groupInfo, _) = chat.chatInfo, groupInfo.membership.memberActive {
Button("For all moderators", role: .destructive) {
if let reports = self.archivingReports {
archiveReports(chat.chatInfo, reports.sorted(), true)
archiveReports(chat, reports.sorted(), true)
self.archivingReports = []
}
}
@@ -2712,13 +2714,13 @@ private func deleteMessages(_ chat: Chat, _ deletingItems: [Int64], _ mode: CIDe
await MainActor.run {
for di in deletedItems {
if let toItem = di.toChatItem {
_ = ChatModel.shared.upsertChatItem(chat.chatInfo, toItem.chatItem)
_ = ChatModel.shared.upsertChatItem(chatInfo, toItem.chatItem)
} else {
ChatModel.shared.removeChatItem(chatInfo, di.deletedChatItem.chatItem)
}
let deletedItem = di.deletedChatItem.chatItem
if deletedItem.isActiveReport {
ChatModel.shared.decreaseGroupReportsCounter(chat.chatInfo.id)
ChatModel.shared.decreaseGroupReportsCounter(chatInfo.id)
}
}
if let updatedChatInfo = deletedItems.last?.deletedChatItem.chatInfo {
@@ -2733,8 +2735,9 @@ private func deleteMessages(_ chat: Chat, _ deletingItems: [Int64], _ mode: CIDe
}
}
func archiveReports(_ chatInfo: ChatInfo, _ itemIds: [Int64], _ forAll: Bool, _ onSuccess: @escaping () async -> Void = {}) {
func archiveReports(_ chat: Chat, _ itemIds: [Int64], _ forAll: Bool, _ onSuccess: @escaping () async -> Void = {}) {
if itemIds.count > 0 {
let chatInfo = chat.chatInfo
Task {
do {
let deleted = try await apiDeleteReceivedReports(
@@ -98,7 +98,7 @@ struct GroupChatInfoView: View {
memberSupportButton()
}
if groupInfo.canModerate {
GroupReportsChatNavLink(chat: chat, scrollToItemId: $scrollToItemId)
GroupReportsChatNavLink(chat: chat, groupInfo: groupInfo, scrollToItemId: $scrollToItemId)
}
if groupInfo.membership.memberActive
&& (groupInfo.membership.memberRole < .moderator || groupInfo.membership.supportChat != nil) {
@@ -612,15 +612,19 @@ struct GroupChatInfoView: View {
}
struct GroupReportsChatNavLink: View {
@EnvironmentObject var chatModel: ChatModel
@EnvironmentObject var theme: AppTheme
@State private var navLinkActive = false
@ObservedObject var chat: Chat
@EnvironmentObject var theme: AppTheme
var groupInfo: GroupInfo
@EnvironmentObject var chatModel: ChatModel
@Binding var scrollToItemId: ChatItem.ID?
@State private var navLinkActive = false
var body: some View {
NavigationLink(isActive: $navLinkActive) {
SecondaryChatView(chat: chat, scrollToItemId: $scrollToItemId)
SecondaryChatView(
chat: Chat(chatInfo: .group(groupInfo: groupInfo, groupChatScope: .reports), chatItems: [], chatStats: ChatStats()),
scrollToItemId: $scrollToItemId
)
} label: {
HStack {
Label {
@@ -107,6 +107,8 @@ struct GroupMentionsView: View {
} else {
return member.memberRole >= .moderator
}
case .reports:
return false
}
case .msgContentTagContext:
return false
+2
View File
@@ -160,6 +160,8 @@ enum SEChatCommand: ChatCmdProtocol {
} else {
"(_support)"
}
case .reports:
"(reports, prohibited)" // can't use surrogate Reports scope
}
}
}
+16 -5
View File
@@ -1584,6 +1584,8 @@ public enum ChatInfo: Identifiable, Decodable, NamedChat, Hashable {
return nil
case .some(.memberSupport(groupMember_: .none)):
return nil
case .some(.reports):
return ("can't send messages", nil)
}
} else if groupInfo.nextConnectPrepared {
return nil
@@ -1895,26 +1897,35 @@ public struct ChatStats: Decodable, Hashable {
public enum GroupChatScope: Decodable {
case memberSupport(groupMemberId_: Int64?)
case reports // surrogate scope used for matching new items to opened Reports "chat scope" in UI, this type is not present in backend
}
public func sameChatScope(_ scope1: GroupChatScope, _ scope2: GroupChatScope) -> Bool {
switch (scope1, scope2) {
return switch (scope1, scope2) {
case let (.memberSupport(groupMemberId1_), .memberSupport(groupMemberId2_)):
return groupMemberId1_ == groupMemberId2_
groupMemberId1_ == groupMemberId2_
case (.reports, .reports):
true
case (.reports, .memberSupport):
false
case (.memberSupport(groupMemberId_: let groupMemberId_), .reports):
false
}
}
public enum GroupChatScopeInfo: Decodable, Hashable {
case memberSupport(groupMember_: GroupMember?)
case reports // surrogate scope used for matching new items to opened Reports "chat scope" in UI, this type is not present in backend
public func toChatScope() -> GroupChatScope {
switch self {
return switch self {
case let .memberSupport(groupMember_):
if let groupMember = groupMember_ {
return .memberSupport(groupMemberId_: groupMember.groupMemberId)
.memberSupport(groupMemberId_: groupMember.groupMemberId)
} else {
return .memberSupport(groupMemberId_: nil)
.memberSupport(groupMemberId_: nil)
}
case .reports: .reports
}
}
}
@@ -2943,12 +2943,6 @@ private fun archiveReports(chatRh: Long?, chatInfo: ChatInfo, itemIds: List<Long
if (deleted != null) {
withContext(Dispatchers.Main) {
for (di in deleted) {
val toChatItem = di.toChatItem?.chatItem
if (toChatItem != null) {
chatModel.chatsContext.upsertChatItem(chatRh, chatInfo, toChatItem)
} else {
chatModel.chatsContext.removeChatItem(chatRh, chatInfo, di.deletedChatItem.chatItem)
}
val deletedItem = di.deletedChatItem.chatItem
if (deletedItem.isActiveReport) {
chatModel.chatsContext.decreaseGroupReportsCounter(chatRh, chatInfo.id)