ios: block member for all (#3708)
* ios: block for all * member info * change conditions * update ui * blockedByAdmin * fix * rework * fix, comment * comment * fix * fix * fixes for default * fix text * reorder * fix * fix * secondary * old buttons (revert this) * blocked by admin text * revise notification
This commit is contained in:
parent
f188118643
commit
7d2f6a3609
@ -1141,6 +1141,12 @@ func apiMemberRole(_ groupId: Int64, _ memberId: Int64, _ memberRole: GroupMembe
|
|||||||
throw r
|
throw r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func apiBlockMemberForAll(_ groupId: Int64, _ memberId: Int64, _ blocked: Bool) async throws -> GroupMember {
|
||||||
|
let r = await chatSendCmd(.apiBlockMemberForAll(groupId: groupId, memberId: memberId, blocked: blocked), bgTask: false)
|
||||||
|
if case let .memberBlockedForAllUser(_, _, member, _) = r { return member }
|
||||||
|
throw r
|
||||||
|
}
|
||||||
|
|
||||||
func leaveGroup(_ groupId: Int64) async {
|
func leaveGroup(_ groupId: Int64) async {
|
||||||
do {
|
do {
|
||||||
let groupInfo = try await apiLeaveGroup(groupId)
|
let groupInfo = try await apiLeaveGroup(groupId)
|
||||||
@ -1680,6 +1686,13 @@ func processReceivedMsg(_ res: ChatResponse) async {
|
|||||||
_ = m.upsertGroupMember(groupInfo, member)
|
_ = m.upsertGroupMember(groupInfo, member)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case let .memberBlockedForAll(user, groupInfo, byMember: _, member: member, blocked: _):
|
||||||
|
if active(user) {
|
||||||
|
await MainActor.run {
|
||||||
|
m.updateGroup(groupInfo)
|
||||||
|
_ = m.upsertGroupMember(groupInfo, member)
|
||||||
|
}
|
||||||
|
}
|
||||||
case let .newMemberContactReceivedInv(user, contact, _, _):
|
case let .newMemberContactReceivedInv(user, contact, _, _):
|
||||||
if active(user) {
|
if active(user) {
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
|
@ -46,7 +46,9 @@ struct FramedItemView: View {
|
|||||||
framedItemHeader(icon: "flag", caption: Text("moderated by \(byGroupMember.displayName)").italic())
|
framedItemHeader(icon: "flag", caption: Text("moderated by \(byGroupMember.displayName)").italic())
|
||||||
case .blocked:
|
case .blocked:
|
||||||
framedItemHeader(icon: "hand.raised", caption: Text("blocked").italic())
|
framedItemHeader(icon: "hand.raised", caption: Text("blocked").italic())
|
||||||
default:
|
case .blockedByAdmin:
|
||||||
|
framedItemHeader(icon: "hand.raised", caption: Text("blocked by admin").italic())
|
||||||
|
case .deleted:
|
||||||
framedItemHeader(icon: "trash", caption: Text("marked deleted").italic())
|
framedItemHeader(icon: "trash", caption: Text("marked deleted").italic())
|
||||||
}
|
}
|
||||||
} else if chatItem.meta.isLive {
|
} else if chatItem.meta.isLive {
|
||||||
|
@ -33,6 +33,7 @@ struct MarkedDeletedItemView: View {
|
|||||||
var i = m.getChatItemIndex(chatItem) {
|
var i = m.getChatItemIndex(chatItem) {
|
||||||
var moderated = 0
|
var moderated = 0
|
||||||
var blocked = 0
|
var blocked = 0
|
||||||
|
var blockedByAdmin = 0
|
||||||
var deleted = 0
|
var deleted = 0
|
||||||
var moderatedBy: Set<String> = []
|
var moderatedBy: Set<String> = []
|
||||||
while i < m.reversedChatItems.count,
|
while i < m.reversedChatItems.count,
|
||||||
@ -44,16 +45,19 @@ struct MarkedDeletedItemView: View {
|
|||||||
moderated += 1
|
moderated += 1
|
||||||
moderatedBy.insert(byGroupMember.displayName)
|
moderatedBy.insert(byGroupMember.displayName)
|
||||||
case .blocked: blocked += 1
|
case .blocked: blocked += 1
|
||||||
|
case .blockedByAdmin: blockedByAdmin += 1
|
||||||
case .deleted: deleted += 1
|
case .deleted: deleted += 1
|
||||||
}
|
}
|
||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
let total = moderated + blocked + deleted
|
let total = moderated + blocked + blockedByAdmin + deleted
|
||||||
return total <= 1
|
return total <= 1
|
||||||
? markedDeletedText
|
? markedDeletedText
|
||||||
: total == moderated
|
: total == moderated
|
||||||
? "\(total) messages moderated by \(moderatedBy.joined(separator: ", "))"
|
? "\(total) messages moderated by \(moderatedBy.joined(separator: ", "))"
|
||||||
: total == blocked
|
: total == blockedByAdmin
|
||||||
|
? "\(total) messages blocked by admin"
|
||||||
|
: total == blocked + blockedByAdmin
|
||||||
? "\(total) messages blocked"
|
? "\(total) messages blocked"
|
||||||
: "\(total) messages marked deleted"
|
: "\(total) messages marked deleted"
|
||||||
} else {
|
} else {
|
||||||
@ -65,7 +69,8 @@ struct MarkedDeletedItemView: View {
|
|||||||
switch chatItem.meta.itemDeleted {
|
switch chatItem.meta.itemDeleted {
|
||||||
case let .moderated(_, byGroupMember): "moderated by \(byGroupMember.displayName)"
|
case let .moderated(_, byGroupMember): "moderated by \(byGroupMember.displayName)"
|
||||||
case .blocked: "blocked"
|
case .blocked: "blocked"
|
||||||
default: "marked deleted"
|
case .blockedByAdmin: "blocked by admin"
|
||||||
|
case .deleted, nil: "marked deleted"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,6 +109,7 @@ struct ChatItemContentView<Content: View>: View {
|
|||||||
case let .rcvGroupFeatureRejected(feature): chatFeatureView(feature, .red)
|
case let .rcvGroupFeatureRejected(feature): chatFeatureView(feature, .red)
|
||||||
case .sndModerated: deletedItemView()
|
case .sndModerated: deletedItemView()
|
||||||
case .rcvModerated: deletedItemView()
|
case .rcvModerated: deletedItemView()
|
||||||
|
case .rcvBlocked: deletedItemView()
|
||||||
case let .invalidJSON(json): CIInvalidJSONView(json: json)
|
case let .invalidJSON(json): CIInvalidJSONView(json: json)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,8 @@ struct GroupChatInfoView: View {
|
|||||||
case largeGroupReceiptsDisabled
|
case largeGroupReceiptsDisabled
|
||||||
case blockMemberAlert(mem: GroupMember)
|
case blockMemberAlert(mem: GroupMember)
|
||||||
case unblockMemberAlert(mem: GroupMember)
|
case unblockMemberAlert(mem: GroupMember)
|
||||||
|
case blockForAllAlert(mem: GroupMember)
|
||||||
|
case unblockForAllAlert(mem: GroupMember)
|
||||||
case removeMemberAlert(mem: GroupMember)
|
case removeMemberAlert(mem: GroupMember)
|
||||||
case error(title: LocalizedStringKey, error: LocalizedStringKey)
|
case error(title: LocalizedStringKey, error: LocalizedStringKey)
|
||||||
|
|
||||||
@ -48,6 +50,8 @@ struct GroupChatInfoView: View {
|
|||||||
case .largeGroupReceiptsDisabled: return "largeGroupReceiptsDisabled"
|
case .largeGroupReceiptsDisabled: return "largeGroupReceiptsDisabled"
|
||||||
case let .blockMemberAlert(mem): return "blockMemberAlert \(mem.groupMemberId)"
|
case let .blockMemberAlert(mem): return "blockMemberAlert \(mem.groupMemberId)"
|
||||||
case let .unblockMemberAlert(mem): return "unblockMemberAlert \(mem.groupMemberId)"
|
case let .unblockMemberAlert(mem): return "unblockMemberAlert \(mem.groupMemberId)"
|
||||||
|
case let .blockForAllAlert(mem): return "blockForAllAlert \(mem.groupMemberId)"
|
||||||
|
case let .unblockForAllAlert(mem): return "unblockForAllAlert \(mem.groupMemberId)"
|
||||||
case let .removeMemberAlert(mem): return "removeMemberAlert \(mem.groupMemberId)"
|
case let .removeMemberAlert(mem): return "removeMemberAlert \(mem.groupMemberId)"
|
||||||
case let .error(title, _): return "error \(title)"
|
case let .error(title, _): return "error \(title)"
|
||||||
}
|
}
|
||||||
@ -143,6 +147,8 @@ struct GroupChatInfoView: View {
|
|||||||
case .largeGroupReceiptsDisabled: return largeGroupReceiptsDisabledAlert()
|
case .largeGroupReceiptsDisabled: return largeGroupReceiptsDisabledAlert()
|
||||||
case let .blockMemberAlert(mem): return blockMemberAlert(groupInfo, mem)
|
case let .blockMemberAlert(mem): return blockMemberAlert(groupInfo, mem)
|
||||||
case let .unblockMemberAlert(mem): return unblockMemberAlert(groupInfo, mem)
|
case let .unblockMemberAlert(mem): return unblockMemberAlert(groupInfo, mem)
|
||||||
|
case let .blockForAllAlert(mem): return blockForAllAlert(groupInfo, mem)
|
||||||
|
case let .unblockForAllAlert(mem): return unblockForAllAlert(groupInfo, mem)
|
||||||
case let .removeMemberAlert(mem): return removeMemberAlert(mem)
|
case let .removeMemberAlert(mem): return removeMemberAlert(mem)
|
||||||
case let .error(title, error): return Alert(title: Text(title), message: Text(error))
|
case let .error(title, error): return Alert(title: Text(title), message: Text(error))
|
||||||
}
|
}
|
||||||
@ -226,13 +232,10 @@ struct GroupChatInfoView: View {
|
|||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
}
|
}
|
||||||
Spacer()
|
Spacer()
|
||||||
let role = member.memberRole
|
memberInfo(member)
|
||||||
if [.owner, .admin, .observer].contains(role) {
|
|
||||||
Text(member.memberRole.text)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// revert from this:
|
||||||
if user {
|
if user {
|
||||||
v
|
v
|
||||||
} else if member.canBeRemoved(groupInfo: groupInfo) {
|
} else if member.canBeRemoved(groupInfo: groupInfo) {
|
||||||
@ -240,6 +243,43 @@ struct GroupChatInfoView: View {
|
|||||||
} else {
|
} else {
|
||||||
blockSwipe(member, v)
|
blockSwipe(member, v)
|
||||||
}
|
}
|
||||||
|
// revert to this: vvv
|
||||||
|
// if user {
|
||||||
|
// v
|
||||||
|
// } else if groupInfo.membership.memberRole >= .admin {
|
||||||
|
// // TODO if there are more actions, refactor with lists of swipeActions
|
||||||
|
// let canBlockForAll = member.canBlockForAll(groupInfo: groupInfo)
|
||||||
|
// let canRemove = member.canBeRemoved(groupInfo: groupInfo)
|
||||||
|
// if canBlockForAll && canRemove {
|
||||||
|
// removeSwipe(member, blockForAllSwipe(member, v))
|
||||||
|
// } else if canBlockForAll {
|
||||||
|
// blockForAllSwipe(member, v)
|
||||||
|
// } else if canRemove {
|
||||||
|
// removeSwipe(member, v)
|
||||||
|
// } else {
|
||||||
|
// v
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// if !member.blockedByAdmin {
|
||||||
|
// blockSwipe(member, v)
|
||||||
|
// } else {
|
||||||
|
// v
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ^^^
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder private func memberInfo(_ member: GroupMember) -> some View {
|
||||||
|
if member.blocked {
|
||||||
|
Text("blocked")
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
} else {
|
||||||
|
let role = member.memberRole
|
||||||
|
if [.owner, .admin, .observer].contains(role) {
|
||||||
|
Text(member.memberRole.text)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func blockSwipe<V: View>(_ member: GroupMember, _ v: V) -> some View {
|
private func blockSwipe<V: View>(_ member: GroupMember, _ v: V) -> some View {
|
||||||
@ -260,6 +300,24 @@ struct GroupChatInfoView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func blockForAllSwipe<V: View>(_ member: GroupMember, _ v: V) -> some View {
|
||||||
|
v.swipeActions(edge: .leading) {
|
||||||
|
if member.blockedByAdmin {
|
||||||
|
Button {
|
||||||
|
alert = .unblockForAllAlert(mem: member)
|
||||||
|
} label: {
|
||||||
|
Label("Unblock for all", systemImage: "hand.raised.slash").foregroundColor(.accentColor)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Button {
|
||||||
|
alert = .blockForAllAlert(mem: member)
|
||||||
|
} label: {
|
||||||
|
Label("Block for all", systemImage: "hand.raised").foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func removeSwipe<V: View>(_ member: GroupMember, _ v: V) -> some View {
|
private func removeSwipe<V: View>(_ member: GroupMember, _ v: V) -> some View {
|
||||||
v.swipeActions(edge: .trailing) {
|
v.swipeActions(edge: .trailing) {
|
||||||
Button(role: .destructive) {
|
Button(role: .destructive) {
|
||||||
|
@ -27,6 +27,8 @@ struct GroupMemberInfoView: View {
|
|||||||
enum GroupMemberInfoViewAlert: Identifiable {
|
enum GroupMemberInfoViewAlert: Identifiable {
|
||||||
case blockMemberAlert(mem: GroupMember)
|
case blockMemberAlert(mem: GroupMember)
|
||||||
case unblockMemberAlert(mem: GroupMember)
|
case unblockMemberAlert(mem: GroupMember)
|
||||||
|
case blockForAllAlert(mem: GroupMember)
|
||||||
|
case unblockForAllAlert(mem: GroupMember)
|
||||||
case removeMemberAlert(mem: GroupMember)
|
case removeMemberAlert(mem: GroupMember)
|
||||||
case changeMemberRoleAlert(mem: GroupMember, role: GroupMemberRole)
|
case changeMemberRoleAlert(mem: GroupMember, role: GroupMemberRole)
|
||||||
case switchAddressAlert
|
case switchAddressAlert
|
||||||
@ -39,6 +41,8 @@ struct GroupMemberInfoView: View {
|
|||||||
switch self {
|
switch self {
|
||||||
case let .blockMemberAlert(mem): return "blockMemberAlert \(mem.groupMemberId)"
|
case let .blockMemberAlert(mem): return "blockMemberAlert \(mem.groupMemberId)"
|
||||||
case let .unblockMemberAlert(mem): return "unblockMemberAlert \(mem.groupMemberId)"
|
case let .unblockMemberAlert(mem): return "unblockMemberAlert \(mem.groupMemberId)"
|
||||||
|
case let .blockForAllAlert(mem): return "blockForAllAlert \(mem.groupMemberId)"
|
||||||
|
case let .unblockForAllAlert(mem): return "unblockForAllAlert \(mem.groupMemberId)"
|
||||||
case let .removeMemberAlert(mem): return "removeMemberAlert \(mem.groupMemberId)"
|
case let .removeMemberAlert(mem): return "removeMemberAlert \(mem.groupMemberId)"
|
||||||
case let .changeMemberRoleAlert(mem, role): return "changeMemberRoleAlert \(mem.groupMemberId) \(role.rawValue)"
|
case let .changeMemberRoleAlert(mem, role): return "changeMemberRoleAlert \(mem.groupMemberId) \(role.rawValue)"
|
||||||
case .switchAddressAlert: return "switchAddressAlert"
|
case .switchAddressAlert: return "switchAddressAlert"
|
||||||
@ -164,6 +168,7 @@ struct GroupMemberInfoView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// revert from this:
|
||||||
Section {
|
Section {
|
||||||
if member.memberSettings.showMessages {
|
if member.memberSettings.showMessages {
|
||||||
blockMemberButton(member)
|
blockMemberButton(member)
|
||||||
@ -171,9 +176,16 @@ struct GroupMemberInfoView: View {
|
|||||||
unblockMemberButton(member)
|
unblockMemberButton(member)
|
||||||
}
|
}
|
||||||
if member.canBeRemoved(groupInfo: groupInfo) {
|
if member.canBeRemoved(groupInfo: groupInfo) {
|
||||||
removeMemberButton(member)
|
removeMemberButton(member)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// revert to this: vvv
|
||||||
|
// if groupInfo.membership.memberRole >= .admin {
|
||||||
|
// adminDestructiveSection(member)
|
||||||
|
// } else {
|
||||||
|
// nonAdminBlockSection(member)
|
||||||
|
// }
|
||||||
|
// ^^^
|
||||||
|
|
||||||
if developerTools {
|
if developerTools {
|
||||||
Section("For console") {
|
Section("For console") {
|
||||||
@ -216,6 +228,8 @@ struct GroupMemberInfoView: View {
|
|||||||
switch(alertItem) {
|
switch(alertItem) {
|
||||||
case let .blockMemberAlert(mem): return blockMemberAlert(groupInfo, mem)
|
case let .blockMemberAlert(mem): return blockMemberAlert(groupInfo, mem)
|
||||||
case let .unblockMemberAlert(mem): return unblockMemberAlert(groupInfo, mem)
|
case let .unblockMemberAlert(mem): return unblockMemberAlert(groupInfo, mem)
|
||||||
|
case let .blockForAllAlert(mem): return blockForAllAlert(groupInfo, mem)
|
||||||
|
case let .unblockForAllAlert(mem): return unblockForAllAlert(groupInfo, mem)
|
||||||
case let .removeMemberAlert(mem): return removeMemberAlert(mem)
|
case let .removeMemberAlert(mem): return removeMemberAlert(mem)
|
||||||
case let .changeMemberRoleAlert(mem, _): return changeMemberRoleAlert(mem)
|
case let .changeMemberRoleAlert(mem, _): return changeMemberRoleAlert(mem)
|
||||||
case .switchAddressAlert: return switchAddressAlert(switchMemberAddress)
|
case .switchAddressAlert: return switchAddressAlert(switchMemberAddress)
|
||||||
@ -385,6 +399,55 @@ struct GroupMemberInfoView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ViewBuilder private func adminDestructiveSection(_ mem: GroupMember) -> some View {
|
||||||
|
let canBlockForAll = mem.canBlockForAll(groupInfo: groupInfo)
|
||||||
|
let canRemove = mem.canBeRemoved(groupInfo: groupInfo)
|
||||||
|
if canBlockForAll || canRemove {
|
||||||
|
Section {
|
||||||
|
if canBlockForAll {
|
||||||
|
if mem.blockedByAdmin {
|
||||||
|
unblockForAllButton(mem)
|
||||||
|
} else {
|
||||||
|
blockForAllButton(mem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if canRemove {
|
||||||
|
removeMemberButton(mem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func nonAdminBlockSection(_ mem: GroupMember) -> some View {
|
||||||
|
Section {
|
||||||
|
if mem.blockedByAdmin {
|
||||||
|
Label("Blocked by admin", systemImage: "hand.raised")
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
} else if mem.memberSettings.showMessages {
|
||||||
|
blockMemberButton(mem)
|
||||||
|
} else {
|
||||||
|
unblockMemberButton(mem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func blockForAllButton(_ mem: GroupMember) -> some View {
|
||||||
|
Button(role: .destructive) {
|
||||||
|
alert = .blockForAllAlert(mem: mem)
|
||||||
|
} label: {
|
||||||
|
Label("Block for all", systemImage: "hand.raised")
|
||||||
|
.foregroundColor(.red)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func unblockForAllButton(_ mem: GroupMember) -> some View {
|
||||||
|
Button {
|
||||||
|
alert = .unblockForAllAlert(mem: mem)
|
||||||
|
} label: {
|
||||||
|
Label("Unblock for all", systemImage: "hand.raised.slash")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func blockMemberButton(_ mem: GroupMember) -> some View {
|
private func blockMemberButton(_ mem: GroupMember) -> some View {
|
||||||
Button(role: .destructive) {
|
Button(role: .destructive) {
|
||||||
alert = .blockMemberAlert(mem: mem)
|
alert = .blockMemberAlert(mem: mem)
|
||||||
@ -560,6 +623,41 @@ func updateMemberSettings(_ gInfo: GroupInfo, _ member: GroupMember, _ memberSet
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func blockForAllAlert(_ gInfo: GroupInfo, _ mem: GroupMember) -> Alert {
|
||||||
|
Alert(
|
||||||
|
title: Text("Block member for all?"),
|
||||||
|
message: Text("All new messages from \(mem.chatViewName) will be hidden!"),
|
||||||
|
primaryButton: .destructive(Text("Block for all")) {
|
||||||
|
blockMemberForAll(gInfo, mem, true)
|
||||||
|
},
|
||||||
|
secondaryButton: .cancel()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func unblockForAllAlert(_ gInfo: GroupInfo, _ mem: GroupMember) -> Alert {
|
||||||
|
Alert(
|
||||||
|
title: Text("Unblock member for all?"),
|
||||||
|
message: Text("Messages from \(mem.chatViewName) will be shown!"),
|
||||||
|
primaryButton: .default(Text("Unblock for all")) {
|
||||||
|
blockMemberForAll(gInfo, mem, false)
|
||||||
|
},
|
||||||
|
secondaryButton: .cancel()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func blockMemberForAll(_ gInfo: GroupInfo, _ member: GroupMember, _ blocked: Bool) {
|
||||||
|
Task {
|
||||||
|
do {
|
||||||
|
let updatedMember = try await apiBlockMemberForAll(gInfo.groupId, member.groupMemberId, blocked)
|
||||||
|
await MainActor.run {
|
||||||
|
_ = ChatModel.shared.upsertGroupMember(gInfo, updatedMember)
|
||||||
|
}
|
||||||
|
} catch let error {
|
||||||
|
logger.error("apiBlockMemberForAll error: \(responseError(error))")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct GroupMemberInfoView_Previews: PreviewProvider {
|
struct GroupMemberInfoView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
GroupMemberInfoView(
|
GroupMemberInfoView(
|
||||||
|
@ -55,6 +55,7 @@ public enum ChatCommand {
|
|||||||
case apiAddMember(groupId: Int64, contactId: Int64, memberRole: GroupMemberRole)
|
case apiAddMember(groupId: Int64, contactId: Int64, memberRole: GroupMemberRole)
|
||||||
case apiJoinGroup(groupId: Int64)
|
case apiJoinGroup(groupId: Int64)
|
||||||
case apiMemberRole(groupId: Int64, memberId: Int64, memberRole: GroupMemberRole)
|
case apiMemberRole(groupId: Int64, memberId: Int64, memberRole: GroupMemberRole)
|
||||||
|
case apiBlockMemberForAll(groupId: Int64, memberId: Int64, blocked: Bool)
|
||||||
case apiRemoveMember(groupId: Int64, memberId: Int64)
|
case apiRemoveMember(groupId: Int64, memberId: Int64)
|
||||||
case apiLeaveGroup(groupId: Int64)
|
case apiLeaveGroup(groupId: Int64)
|
||||||
case apiListMembers(groupId: Int64)
|
case apiListMembers(groupId: Int64)
|
||||||
@ -195,6 +196,7 @@ public enum ChatCommand {
|
|||||||
case let .apiAddMember(groupId, contactId, memberRole): return "/_add #\(groupId) \(contactId) \(memberRole)"
|
case let .apiAddMember(groupId, contactId, memberRole): return "/_add #\(groupId) \(contactId) \(memberRole)"
|
||||||
case let .apiJoinGroup(groupId): return "/_join #\(groupId)"
|
case let .apiJoinGroup(groupId): return "/_join #\(groupId)"
|
||||||
case let .apiMemberRole(groupId, memberId, memberRole): return "/_member role #\(groupId) \(memberId) \(memberRole.rawValue)"
|
case let .apiMemberRole(groupId, memberId, memberRole): return "/_member role #\(groupId) \(memberId) \(memberRole.rawValue)"
|
||||||
|
case let .apiBlockMemberForAll(groupId, memberId, blocked): return "/_block #\(groupId) \(memberId) blocked=\(onOff(blocked))"
|
||||||
case let .apiRemoveMember(groupId, memberId): return "/_remove #\(groupId) \(memberId)"
|
case let .apiRemoveMember(groupId, memberId): return "/_remove #\(groupId) \(memberId)"
|
||||||
case let .apiLeaveGroup(groupId): return "/_leave #\(groupId)"
|
case let .apiLeaveGroup(groupId): return "/_leave #\(groupId)"
|
||||||
case let .apiListMembers(groupId): return "/_members #\(groupId)"
|
case let .apiListMembers(groupId): return "/_members #\(groupId)"
|
||||||
@ -334,6 +336,7 @@ public enum ChatCommand {
|
|||||||
case .apiAddMember: return "apiAddMember"
|
case .apiAddMember: return "apiAddMember"
|
||||||
case .apiJoinGroup: return "apiJoinGroup"
|
case .apiJoinGroup: return "apiJoinGroup"
|
||||||
case .apiMemberRole: return "apiMemberRole"
|
case .apiMemberRole: return "apiMemberRole"
|
||||||
|
case .apiBlockMemberForAll: return "apiBlockMemberForAll"
|
||||||
case .apiRemoveMember: return "apiRemoveMember"
|
case .apiRemoveMember: return "apiRemoveMember"
|
||||||
case .apiLeaveGroup: return "apiLeaveGroup"
|
case .apiLeaveGroup: return "apiLeaveGroup"
|
||||||
case .apiListMembers: return "apiListMembers"
|
case .apiListMembers: return "apiListMembers"
|
||||||
@ -566,6 +569,8 @@ public enum ChatResponse: Decodable, Error {
|
|||||||
case joinedGroupMemberConnecting(user: UserRef, groupInfo: GroupInfo, hostMember: GroupMember, member: GroupMember)
|
case joinedGroupMemberConnecting(user: UserRef, groupInfo: GroupInfo, hostMember: GroupMember, member: GroupMember)
|
||||||
case memberRole(user: UserRef, groupInfo: GroupInfo, byMember: GroupMember, member: GroupMember, fromRole: GroupMemberRole, toRole: GroupMemberRole)
|
case memberRole(user: UserRef, groupInfo: GroupInfo, byMember: GroupMember, member: GroupMember, fromRole: GroupMemberRole, toRole: GroupMemberRole)
|
||||||
case memberRoleUser(user: UserRef, groupInfo: GroupInfo, member: GroupMember, fromRole: GroupMemberRole, toRole: GroupMemberRole)
|
case memberRoleUser(user: UserRef, groupInfo: GroupInfo, member: GroupMember, fromRole: GroupMemberRole, toRole: GroupMemberRole)
|
||||||
|
case memberBlockedForAll(user: UserRef, groupInfo: GroupInfo, byMember: GroupMember, member: GroupMember, blocked: Bool)
|
||||||
|
case memberBlockedForAllUser(user: UserRef, groupInfo: GroupInfo, member: GroupMember, blocked: Bool)
|
||||||
case deletedMemberUser(user: UserRef, groupInfo: GroupInfo, member: GroupMember)
|
case deletedMemberUser(user: UserRef, groupInfo: GroupInfo, member: GroupMember)
|
||||||
case deletedMember(user: UserRef, groupInfo: GroupInfo, byMember: GroupMember, deletedMember: GroupMember)
|
case deletedMember(user: UserRef, groupInfo: GroupInfo, byMember: GroupMember, deletedMember: GroupMember)
|
||||||
case leftMember(user: UserRef, groupInfo: GroupInfo, member: GroupMember)
|
case leftMember(user: UserRef, groupInfo: GroupInfo, member: GroupMember)
|
||||||
@ -716,6 +721,8 @@ public enum ChatResponse: Decodable, Error {
|
|||||||
case .joinedGroupMemberConnecting: return "joinedGroupMemberConnecting"
|
case .joinedGroupMemberConnecting: return "joinedGroupMemberConnecting"
|
||||||
case .memberRole: return "memberRole"
|
case .memberRole: return "memberRole"
|
||||||
case .memberRoleUser: return "memberRoleUser"
|
case .memberRoleUser: return "memberRoleUser"
|
||||||
|
case .memberBlockedForAll: return "memberBlockedForAll"
|
||||||
|
case .memberBlockedForAllUser: return "memberBlockedForAllUser"
|
||||||
case .deletedMemberUser: return "deletedMemberUser"
|
case .deletedMemberUser: return "deletedMemberUser"
|
||||||
case .deletedMember: return "deletedMember"
|
case .deletedMember: return "deletedMember"
|
||||||
case .leftMember: return "leftMember"
|
case .leftMember: return "leftMember"
|
||||||
@ -864,6 +871,8 @@ public enum ChatResponse: Decodable, Error {
|
|||||||
case let .joinedGroupMemberConnecting(u, groupInfo, hostMember, member): return withUser(u, "groupInfo: \(groupInfo)\nhostMember: \(hostMember)\nmember: \(member)")
|
case let .joinedGroupMemberConnecting(u, groupInfo, hostMember, member): return withUser(u, "groupInfo: \(groupInfo)\nhostMember: \(hostMember)\nmember: \(member)")
|
||||||
case let .memberRole(u, groupInfo, byMember, member, fromRole, toRole): return withUser(u, "groupInfo: \(groupInfo)\nbyMember: \(byMember)\nmember: \(member)\nfromRole: \(fromRole)\ntoRole: \(toRole)")
|
case let .memberRole(u, groupInfo, byMember, member, fromRole, toRole): return withUser(u, "groupInfo: \(groupInfo)\nbyMember: \(byMember)\nmember: \(member)\nfromRole: \(fromRole)\ntoRole: \(toRole)")
|
||||||
case let .memberRoleUser(u, groupInfo, member, fromRole, toRole): return withUser(u, "groupInfo: \(groupInfo)\nmember: \(member)\nfromRole: \(fromRole)\ntoRole: \(toRole)")
|
case let .memberRoleUser(u, groupInfo, member, fromRole, toRole): return withUser(u, "groupInfo: \(groupInfo)\nmember: \(member)\nfromRole: \(fromRole)\ntoRole: \(toRole)")
|
||||||
|
case let .memberBlockedForAll(u, groupInfo, byMember, member, blocked): return withUser(u, "groupInfo: \(groupInfo)\nbyMember: \(byMember)\nmember: \(member)\nblocked: \(blocked)")
|
||||||
|
case let .memberBlockedForAllUser(u, groupInfo, member, blocked): return withUser(u, "groupInfo: \(groupInfo)\nmember: \(member)\nblocked: \(blocked)")
|
||||||
case let .deletedMemberUser(u, groupInfo, member): return withUser(u, "groupInfo: \(groupInfo)\nmember: \(member)")
|
case let .deletedMemberUser(u, groupInfo, member): return withUser(u, "groupInfo: \(groupInfo)\nmember: \(member)")
|
||||||
case let .deletedMember(u, groupInfo, byMember, deletedMember): return withUser(u, "groupInfo: \(groupInfo)\nbyMember: \(byMember)\ndeletedMember: \(deletedMember)")
|
case let .deletedMember(u, groupInfo, byMember, deletedMember): return withUser(u, "groupInfo: \(groupInfo)\nbyMember: \(byMember)\ndeletedMember: \(deletedMember)")
|
||||||
case let .leftMember(u, groupInfo, member): return withUser(u, "groupInfo: \(groupInfo)\nmember: \(member)")
|
case let .leftMember(u, groupInfo, member): return withUser(u, "groupInfo: \(groupInfo)\nmember: \(member)")
|
||||||
|
@ -1814,6 +1814,7 @@ public struct GroupMember: Identifiable, Decodable {
|
|||||||
public var memberCategory: GroupMemberCategory
|
public var memberCategory: GroupMemberCategory
|
||||||
public var memberStatus: GroupMemberStatus
|
public var memberStatus: GroupMemberStatus
|
||||||
public var memberSettings: GroupMemberSettings
|
public var memberSettings: GroupMemberSettings
|
||||||
|
public var blockedByAdmin: Bool
|
||||||
public var invitedBy: InvitedBy
|
public var invitedBy: InvitedBy
|
||||||
public var localDisplayName: ContactName
|
public var localDisplayName: ContactName
|
||||||
public var memberProfile: LocalProfile
|
public var memberProfile: LocalProfile
|
||||||
@ -1833,6 +1834,7 @@ public struct GroupMember: Identifiable, Decodable {
|
|||||||
public var image: String? { get { memberProfile.image } }
|
public var image: String? { get { memberProfile.image } }
|
||||||
public var contactLink: String? { get { memberProfile.contactLink } }
|
public var contactLink: String? { get { memberProfile.contactLink } }
|
||||||
public var verified: Bool { activeConn?.connectionCode != nil }
|
public var verified: Bool { activeConn?.connectionCode != nil }
|
||||||
|
public var blocked: Bool { blockedByAdmin || !memberSettings.showMessages }
|
||||||
|
|
||||||
var directChatId: ChatId? {
|
var directChatId: ChatId? {
|
||||||
get {
|
get {
|
||||||
@ -1899,7 +1901,7 @@ public struct GroupMember: Identifiable, Decodable {
|
|||||||
public func canBeRemoved(groupInfo: GroupInfo) -> Bool {
|
public func canBeRemoved(groupInfo: GroupInfo) -> Bool {
|
||||||
let userRole = groupInfo.membership.memberRole
|
let userRole = groupInfo.membership.memberRole
|
||||||
return memberStatus != .memRemoved && memberStatus != .memLeft
|
return memberStatus != .memRemoved && memberStatus != .memLeft
|
||||||
&& userRole >= .admin && userRole >= memberRole && groupInfo.membership.memberCurrent
|
&& userRole >= .admin && userRole >= memberRole && groupInfo.membership.memberActive
|
||||||
}
|
}
|
||||||
|
|
||||||
public func canChangeRoleTo(groupInfo: GroupInfo) -> [GroupMemberRole]? {
|
public func canChangeRoleTo(groupInfo: GroupInfo) -> [GroupMemberRole]? {
|
||||||
@ -1908,6 +1910,12 @@ public struct GroupMember: Identifiable, Decodable {
|
|||||||
return GroupMemberRole.allCases.filter { $0 <= userRole && $0 != .author }
|
return GroupMemberRole.allCases.filter { $0 <= userRole && $0 != .author }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func canBlockForAll(groupInfo: GroupInfo) -> Bool {
|
||||||
|
let userRole = groupInfo.membership.memberRole
|
||||||
|
return memberStatus != .memRemoved && memberStatus != .memLeft && memberRole < .admin
|
||||||
|
&& userRole >= .admin && userRole >= memberRole && groupInfo.membership.memberActive
|
||||||
|
}
|
||||||
|
|
||||||
public var memberIncognito: Bool {
|
public var memberIncognito: Bool {
|
||||||
memberProfile.profileId != memberContactProfileId
|
memberProfile.profileId != memberContactProfileId
|
||||||
}
|
}
|
||||||
@ -1920,6 +1928,7 @@ public struct GroupMember: Identifiable, Decodable {
|
|||||||
memberCategory: .inviteeMember,
|
memberCategory: .inviteeMember,
|
||||||
memberStatus: .memComplete,
|
memberStatus: .memComplete,
|
||||||
memberSettings: GroupMemberSettings(showMessages: true),
|
memberSettings: GroupMemberSettings(showMessages: true),
|
||||||
|
blockedByAdmin: false,
|
||||||
invitedBy: .user,
|
invitedBy: .user,
|
||||||
localDisplayName: "alice",
|
localDisplayName: "alice",
|
||||||
memberProfile: LocalProfile.sampleData,
|
memberProfile: LocalProfile.sampleData,
|
||||||
@ -2184,6 +2193,7 @@ public struct ChatItem: Identifiable, Decodable {
|
|||||||
case .rcvDeleted: return true
|
case .rcvDeleted: return true
|
||||||
case .sndModerated: return true
|
case .sndModerated: return true
|
||||||
case .rcvModerated: return true
|
case .rcvModerated: return true
|
||||||
|
case .rcvBlocked: return true
|
||||||
default: return false
|
default: return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2228,22 +2238,18 @@ public struct ChatItem: Identifiable, Decodable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var showNtfDir: Bool {
|
|
||||||
return !chatDir.sent
|
|
||||||
}
|
|
||||||
|
|
||||||
public var showNotification: Bool {
|
public var showNotification: Bool {
|
||||||
switch content {
|
switch content {
|
||||||
case .sndMsgContent: return showNtfDir
|
case .sndMsgContent: return false
|
||||||
case .rcvMsgContent: return showNtfDir
|
case .rcvMsgContent: return meta.itemDeleted == nil
|
||||||
case .sndDeleted: return showNtfDir
|
case .sndDeleted: return false
|
||||||
case .rcvDeleted: return showNtfDir
|
case .rcvDeleted: return false
|
||||||
case .sndCall: return showNtfDir
|
case .sndCall: return false
|
||||||
case .rcvCall: return false // notification is shown on .callInvitation instead
|
case .rcvCall: return false // notification is shown on .callInvitation instead
|
||||||
case .rcvIntegrityError: return showNtfDir
|
case .rcvIntegrityError: return false
|
||||||
case .rcvDecryptionError: return showNtfDir
|
case .rcvDecryptionError: return false
|
||||||
case .rcvGroupInvitation: return showNtfDir
|
case .rcvGroupInvitation: return true
|
||||||
case .sndGroupInvitation: return showNtfDir
|
case .sndGroupInvitation: return false
|
||||||
case .rcvDirectEvent(rcvDirectEvent: let rcvDirectEvent):
|
case .rcvDirectEvent(rcvDirectEvent: let rcvDirectEvent):
|
||||||
switch rcvDirectEvent {
|
switch rcvDirectEvent {
|
||||||
case .contactDeleted: return false
|
case .contactDeleted: return false
|
||||||
@ -2254,9 +2260,10 @@ public struct ChatItem: Identifiable, Decodable {
|
|||||||
case .groupUpdated: return false
|
case .groupUpdated: return false
|
||||||
case .memberConnected: return false
|
case .memberConnected: return false
|
||||||
case .memberRole: return false
|
case .memberRole: return false
|
||||||
case .userRole: return showNtfDir
|
case .memberBlocked: return false
|
||||||
case .userDeleted: return showNtfDir
|
case .userRole: return true
|
||||||
case .groupDeleted: return showNtfDir
|
case .userDeleted: return true
|
||||||
|
case .groupDeleted: return true
|
||||||
case .memberAdded: return false
|
case .memberAdded: return false
|
||||||
case .memberLeft: return false
|
case .memberLeft: return false
|
||||||
case .memberDeleted: return false
|
case .memberDeleted: return false
|
||||||
@ -2264,19 +2271,20 @@ public struct ChatItem: Identifiable, Decodable {
|
|||||||
case .memberCreatedContact: return false
|
case .memberCreatedContact: return false
|
||||||
case .memberProfileUpdated: return false
|
case .memberProfileUpdated: return false
|
||||||
}
|
}
|
||||||
case .sndGroupEvent: return showNtfDir
|
case .sndGroupEvent: return false
|
||||||
case .rcvConnEvent: return false
|
case .rcvConnEvent: return false
|
||||||
case .sndConnEvent: return showNtfDir
|
case .sndConnEvent: return false
|
||||||
case .rcvChatFeature: return false
|
case .rcvChatFeature: return false
|
||||||
case .sndChatFeature: return showNtfDir
|
case .sndChatFeature: return false
|
||||||
case .rcvChatPreference: return false
|
case .rcvChatPreference: return false
|
||||||
case .sndChatPreference: return showNtfDir
|
case .sndChatPreference: return false
|
||||||
case .rcvGroupFeature: return false
|
case .rcvGroupFeature: return false
|
||||||
case .sndGroupFeature: return showNtfDir
|
case .sndGroupFeature: return false
|
||||||
case .rcvChatFeatureRejected: return showNtfDir
|
case .rcvChatFeatureRejected: return true
|
||||||
case .rcvGroupFeatureRejected: return showNtfDir
|
case .rcvGroupFeatureRejected: return false
|
||||||
case .sndModerated: return true
|
case .sndModerated: return false
|
||||||
case .rcvModerated: return true
|
case .rcvModerated: return false
|
||||||
|
case .rcvBlocked: return false
|
||||||
case .invalidJSON: return false
|
case .invalidJSON: return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2663,12 +2671,14 @@ public enum SndCIStatusProgress: String, Decodable {
|
|||||||
public enum CIDeleted: Decodable {
|
public enum CIDeleted: Decodable {
|
||||||
case deleted(deletedTs: Date?)
|
case deleted(deletedTs: Date?)
|
||||||
case blocked(deletedTs: Date?)
|
case blocked(deletedTs: Date?)
|
||||||
|
case blockedByAdmin(deletedTs: Date?)
|
||||||
case moderated(deletedTs: Date?, byGroupMember: GroupMember)
|
case moderated(deletedTs: Date?, byGroupMember: GroupMember)
|
||||||
|
|
||||||
var id: String {
|
var id: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .deleted: return "deleted"
|
case .deleted: return "deleted"
|
||||||
case .blocked: return "blocked"
|
case .blocked: return "blocked"
|
||||||
|
case .blockedByAdmin: return "blocked by admin"
|
||||||
case .moderated: return "moderated"
|
case .moderated: return "moderated"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2709,6 +2719,7 @@ public enum CIContent: Decodable, ItemContent {
|
|||||||
case rcvGroupFeatureRejected(groupFeature: GroupFeature)
|
case rcvGroupFeatureRejected(groupFeature: GroupFeature)
|
||||||
case sndModerated
|
case sndModerated
|
||||||
case rcvModerated
|
case rcvModerated
|
||||||
|
case rcvBlocked
|
||||||
case invalidJSON(json: String)
|
case invalidJSON(json: String)
|
||||||
|
|
||||||
public var text: String {
|
public var text: String {
|
||||||
@ -2739,6 +2750,7 @@ public enum CIContent: Decodable, ItemContent {
|
|||||||
case let .rcvGroupFeatureRejected(groupFeature): return String.localizedStringWithFormat("%@: received, prohibited", groupFeature.text)
|
case let .rcvGroupFeatureRejected(groupFeature): return String.localizedStringWithFormat("%@: received, prohibited", groupFeature.text)
|
||||||
case .sndModerated: return NSLocalizedString("moderated", comment: "moderated chat item")
|
case .sndModerated: return NSLocalizedString("moderated", comment: "moderated chat item")
|
||||||
case .rcvModerated: return NSLocalizedString("moderated", comment: "moderated chat item")
|
case .rcvModerated: return NSLocalizedString("moderated", comment: "moderated chat item")
|
||||||
|
case .rcvBlocked: return NSLocalizedString("blocked by admin", comment: "blocked chat item")
|
||||||
case .invalidJSON: return NSLocalizedString("invalid data", comment: "invalid chat item")
|
case .invalidJSON: return NSLocalizedString("invalid data", comment: "invalid chat item")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2777,6 +2789,7 @@ public enum CIContent: Decodable, ItemContent {
|
|||||||
case .rcvDecryptionError: return true
|
case .rcvDecryptionError: return true
|
||||||
case .rcvGroupInvitation: return true
|
case .rcvGroupInvitation: return true
|
||||||
case .rcvModerated: return true
|
case .rcvModerated: return true
|
||||||
|
case .rcvBlocked: return true
|
||||||
case .invalidJSON: return true
|
case .invalidJSON: return true
|
||||||
default: return false
|
default: return false
|
||||||
}
|
}
|
||||||
@ -3463,6 +3476,7 @@ public enum RcvGroupEvent: Decodable {
|
|||||||
case memberConnected
|
case memberConnected
|
||||||
case memberLeft
|
case memberLeft
|
||||||
case memberRole(groupMemberId: Int64, profile: Profile, role: GroupMemberRole)
|
case memberRole(groupMemberId: Int64, profile: Profile, role: GroupMemberRole)
|
||||||
|
case memberBlocked(groupMemberId: Int64, profile: Profile, blocked: Bool)
|
||||||
case userRole(role: GroupMemberRole)
|
case userRole(role: GroupMemberRole)
|
||||||
case memberDeleted(groupMemberId: Int64, profile: Profile)
|
case memberDeleted(groupMemberId: Int64, profile: Profile)
|
||||||
case userDeleted
|
case userDeleted
|
||||||
@ -3480,6 +3494,12 @@ public enum RcvGroupEvent: Decodable {
|
|||||||
case .memberLeft: return NSLocalizedString("left", comment: "rcv group event chat item")
|
case .memberLeft: return NSLocalizedString("left", comment: "rcv group event chat item")
|
||||||
case let .memberRole(_, profile, role):
|
case let .memberRole(_, profile, role):
|
||||||
return String.localizedStringWithFormat(NSLocalizedString("changed role of %@ to %@", comment: "rcv group event chat item"), profile.profileViewName, role.text)
|
return String.localizedStringWithFormat(NSLocalizedString("changed role of %@ to %@", comment: "rcv group event chat item"), profile.profileViewName, role.text)
|
||||||
|
case let .memberBlocked(_, profile, blocked):
|
||||||
|
if blocked {
|
||||||
|
return String.localizedStringWithFormat(NSLocalizedString("blocked %@", comment: "rcv group event chat item"), profile.profileViewName)
|
||||||
|
} else {
|
||||||
|
return String.localizedStringWithFormat(NSLocalizedString("unblocked %@", comment: "rcv group event chat item"), profile.profileViewName)
|
||||||
|
}
|
||||||
case let .userRole(role):
|
case let .userRole(role):
|
||||||
return String.localizedStringWithFormat(NSLocalizedString("changed your role to %@", comment: "rcv group event chat item"), role.text)
|
return String.localizedStringWithFormat(NSLocalizedString("changed your role to %@", comment: "rcv group event chat item"), role.text)
|
||||||
case let .memberDeleted(_, profile):
|
case let .memberDeleted(_, profile):
|
||||||
@ -3510,6 +3530,7 @@ public enum RcvGroupEvent: Decodable {
|
|||||||
public enum SndGroupEvent: Decodable {
|
public enum SndGroupEvent: Decodable {
|
||||||
case memberRole(groupMemberId: Int64, profile: Profile, role: GroupMemberRole)
|
case memberRole(groupMemberId: Int64, profile: Profile, role: GroupMemberRole)
|
||||||
case userRole(role: GroupMemberRole)
|
case userRole(role: GroupMemberRole)
|
||||||
|
case memberBlocked(groupMemberId: Int64, profile: Profile, blocked: Bool)
|
||||||
case memberDeleted(groupMemberId: Int64, profile: Profile)
|
case memberDeleted(groupMemberId: Int64, profile: Profile)
|
||||||
case userLeft
|
case userLeft
|
||||||
case groupUpdated(groupProfile: GroupProfile)
|
case groupUpdated(groupProfile: GroupProfile)
|
||||||
@ -3520,6 +3541,12 @@ public enum SndGroupEvent: Decodable {
|
|||||||
return String.localizedStringWithFormat(NSLocalizedString("you changed role of %@ to %@", comment: "snd group event chat item"), profile.profileViewName, role.text)
|
return String.localizedStringWithFormat(NSLocalizedString("you changed role of %@ to %@", comment: "snd group event chat item"), profile.profileViewName, role.text)
|
||||||
case let .userRole(role):
|
case let .userRole(role):
|
||||||
return String.localizedStringWithFormat(NSLocalizedString("you changed role for yourself to %@", comment: "snd group event chat item"), role.text)
|
return String.localizedStringWithFormat(NSLocalizedString("you changed role for yourself to %@", comment: "snd group event chat item"), role.text)
|
||||||
|
case let .memberBlocked(_, profile, blocked):
|
||||||
|
if blocked {
|
||||||
|
return String.localizedStringWithFormat(NSLocalizedString("you blocked %@", comment: "snd group event chat item"), profile.profileViewName)
|
||||||
|
} else {
|
||||||
|
return String.localizedStringWithFormat(NSLocalizedString("you unblocked %@", comment: "snd group event chat item"), profile.profileViewName)
|
||||||
|
}
|
||||||
case let .memberDeleted(_, profile):
|
case let .memberDeleted(_, profile):
|
||||||
return String.localizedStringWithFormat(NSLocalizedString("you removed %@", comment: "snd group event chat item"), profile.profileViewName)
|
return String.localizedStringWithFormat(NSLocalizedString("you removed %@", comment: "snd group event chat item"), profile.profileViewName)
|
||||||
case .userLeft: return NSLocalizedString("you left", comment: "snd group event chat item")
|
case .userLeft: return NSLocalizedString("you left", comment: "snd group event chat item")
|
||||||
|
Loading…
Reference in New Issue
Block a user