Signal-iOS/Signal/src/ViewControllers/ThreadSettings/GroupViewHelper.swift
2021-03-25 09:24:27 -03:00

163 lines
4.8 KiB
Swift

//
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
//
import Foundation
import PromiseKit
@objc
protocol GroupViewHelperDelegate: class {
func groupViewHelperDidUpdateGroup()
var currentGroupModel: TSGroupModel? { get }
var fromViewController: UIViewController? { get }
}
// MARK: -
@objc
class GroupViewHelper: NSObject {
@objc
weak var delegate: GroupViewHelperDelegate?
let threadViewModel: ThreadViewModel
var thread: TSThread {
return threadViewModel.threadRecord
}
var fromViewController: UIViewController? {
return delegate?.fromViewController
}
@objc
init(threadViewModel: ThreadViewModel) {
self.threadViewModel = threadViewModel
}
// MARK: - Accessors
// Don't use this method directly;
// Use canEditConversationAttributes or canEditConversationMembership instead.
private func canLocalUserEditConversation(v2AccessTypeBlock: (GroupAccess) -> GroupV2Access) -> Bool {
if threadViewModel.hasPendingMessageRequest {
return false
}
guard isLocalUserFullMember else {
return false
}
guard let groupThread = thread as? TSGroupThread else {
// Both users can edit contact threads.
return true
}
guard !isBlockedByMigration else {
return false
}
guard !blockingManager.isThreadBlocked(groupThread) else {
return false
}
guard let groupModelV2 = groupThread.groupModel as? TSGroupModelV2 else {
// All users can edit v1 groups.
return true
}
guard let localAddress = tsAccountManager.localAddress else {
owsFailDebug("Missing localAddress.")
return false
}
// Use the block to pick the access type: attributes or members?
let access = v2AccessTypeBlock(groupModelV2.access)
switch access {
case .unknown:
owsFailDebug("Unknown access.")
return false
case .unsatisfiable:
owsFailDebug("Invalid access.")
return false
case .any:
return true
case .member:
return groupModelV2.groupMembership.isFullMember(localAddress)
case .administrator:
return (groupModelV2.groupMembership.isFullMemberAndAdministrator(localAddress))
}
}
var isBlockedByMigration: Bool {
thread.isBlockedByMigration
}
// Can local user edit conversation attributes:
//
// * DM state
// * Group title (if group)
// * Group avatar (if group)
var canEditConversationAttributes: Bool {
return canLocalUserEditConversation { groupAccess in
return groupAccess.attributes
}
}
// Can local user edit group membership.
var canEditConversationMembership: Bool {
return canLocalUserEditConversation { groupAccess in
return groupAccess.members
}
}
// Can local user edit group access.
var canEditConversationAccess: Bool {
guard let groupThread = thread as? TSGroupThread else {
return false
}
return (!threadViewModel.hasPendingMessageRequest &&
groupThread.isGroupV2Thread &&
groupThread.isLocalUserFullMemberAndAdministrator)
}
var canRevokePendingInvites: Bool {
guard let groupThread = thread as? TSGroupThread else {
return false
}
return (!threadViewModel.hasPendingMessageRequest &&
groupThread.isGroupV2Thread &&
groupThread.isLocalUserFullMemberAndAdministrator)
}
var canResendInvites: Bool {
return (!threadViewModel.hasPendingMessageRequest && isLocalUserFullMember)
}
var canApproveMemberRequests: Bool {
guard let groupThread = thread as? TSGroupThread else {
return false
}
return (!threadViewModel.hasPendingMessageRequest &&
groupThread.isGroupV2Thread &&
groupThread.isLocalUserFullMemberAndAdministrator)
}
var isLocalUserFullMember: Bool {
guard let groupThread = thread as? TSGroupThread else {
return true
}
return groupThread.isLocalUserFullMember
}
var isLocalUserFullOrInvitedMember: Bool {
guard let groupThread = thread as? TSGroupThread else {
return true
}
return groupThread.isLocalUserFullOrInvitedMember
}
func isFullOrInvitedMember(_ address: SignalServiceAddress) -> Bool {
guard let groupThread = thread as? TSGroupThread else {
return false
}
let groupMembership = groupThread.groupModel.groupMembership
return groupMembership.isFullMember(address) || groupMembership.isInvitedMember(address)
}
}