253 lines
9.0 KiB
Swift
253 lines
9.0 KiB
Swift
//
|
|
// Copyright (c) 2022 Open Whisper Systems. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
protocol AddGroupMembersViewControllerDelegate: AnyObject {
|
|
func addGroupMembersViewDidUpdate()
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
@objc
|
|
public class AddGroupMembersViewController: BaseGroupMemberViewController {
|
|
|
|
weak var addGroupMembersViewControllerDelegate: AddGroupMembersViewControllerDelegate?
|
|
|
|
private let groupThread: TSGroupThread
|
|
private let oldGroupModel: TSGroupModel
|
|
|
|
private var newRecipientSet = OrderedSet<PickedRecipient>()
|
|
|
|
public required init(groupThread: TSGroupThread) {
|
|
self.groupThread = groupThread
|
|
self.oldGroupModel = groupThread.groupModel
|
|
|
|
super.init()
|
|
|
|
groupMemberViewDelegate = self
|
|
}
|
|
|
|
// MARK: - View Lifecycle
|
|
|
|
@objc
|
|
public override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
|
|
title = NSLocalizedString("ADD_GROUP_MEMBERS_VIEW_TITLE",
|
|
comment: "The title for the 'add group members' view.")
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
fileprivate func updateNavbar() {
|
|
if hasUnsavedChanges {
|
|
navigationItem.rightBarButtonItem = UIBarButtonItem(title: NSLocalizedString("EDIT_GROUP_UPDATE_BUTTON",
|
|
comment: "The title for the 'update group' button."),
|
|
style: .plain,
|
|
target: self,
|
|
action: #selector(updateGroupPressed),
|
|
accessibilityIdentifier: UIView.accessibilityIdentifier(in: self, name: "update"))
|
|
} else {
|
|
navigationItem.rightBarButtonItem = nil
|
|
}
|
|
}
|
|
|
|
@objc
|
|
func updateGroupPressed() {
|
|
showConfirmationAlert()
|
|
}
|
|
|
|
private func showConfirmationAlert() {
|
|
let newMemberCount = newRecipientSet.count
|
|
guard newMemberCount > 0 else {
|
|
owsFailDebug("No new members.")
|
|
return
|
|
}
|
|
|
|
let groupName = contactsManager.displayNameWithSneakyTransaction(thread: groupThread)
|
|
let alertTitle: String
|
|
let alertMessage: String
|
|
let actionTitle: String
|
|
let messageFormat = NSLocalizedString("ADD_GROUP_MEMBERS_VIEW_CONFIRM_ALERT_MESSAGE_%d", tableName: "PluralAware",
|
|
comment: "Format for the message for the 'add group members' confirmation alert. Embeds {{ %1$@ number of new members, %2$@ name of the group. }}.")
|
|
alertMessage = String.localizedStringWithFormat(messageFormat, newRecipientSet.count, groupName)
|
|
alertTitle = String.localizedStringWithFormat(NSLocalizedString("ADD_GROUP_MEMBERS_VIEW_CONFIRM_ALERT_TITLE_%d", tableName: "PluralAware",
|
|
comment: "Title for the 'add group members' confirmation alert."), newRecipientSet.count)
|
|
actionTitle = String.localizedStringWithFormat(NSLocalizedString("ADD_GROUP_MEMBERS_ACTION_TITLE_%d", tableName: "PluralAware",
|
|
comment: "Label for the 'add group members' button."), newRecipientSet.count)
|
|
|
|
let actionSheet = ActionSheetController(title: alertTitle, message: alertMessage)
|
|
actionSheet.addAction(ActionSheetAction(title: actionTitle,
|
|
style: .default,
|
|
handler: { [weak self] _ in
|
|
self?.updateGroupThreadAndDismiss()
|
|
}))
|
|
actionSheet.addAction(OWSActionSheets.cancelAction)
|
|
self.presentActionSheet(actionSheet)
|
|
}
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
private extension AddGroupMembersViewController {
|
|
|
|
func buildGroupUpdate() -> GroupManager.GroupUpdate? {
|
|
let newUuids = newRecipientSet.orderedMembers
|
|
.compactMap { recipient -> UUID? in
|
|
if let uuid = recipient.address?.uuid,
|
|
!oldGroupModel.groupMembership.isFullMember(uuid) {
|
|
owsFailDebug("Missing UUID, or recipient is already in group!")
|
|
return uuid
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
guard !newUuids.isEmpty else {
|
|
owsFailDebug("No valid recipients")
|
|
return nil
|
|
}
|
|
|
|
return .addNormalMembers(uuids: newUuids)
|
|
}
|
|
|
|
func updateGroupThreadAndDismiss() {
|
|
|
|
let dismissAndUpdateDelegate = { [weak self] in
|
|
guard let self = self else {
|
|
return
|
|
}
|
|
self.addGroupMembersViewControllerDelegate?.addGroupMembersViewDidUpdate()
|
|
self.navigationController?.popViewController(animated: true)
|
|
}
|
|
|
|
guard hasUnsavedChanges else {
|
|
owsFailDebug("!hasUnsavedChanges.")
|
|
return dismissAndUpdateDelegate()
|
|
}
|
|
|
|
guard let groupUpdateToPerform = buildGroupUpdate() else {
|
|
let error = OWSAssertionError("Couldn't build group update.")
|
|
GroupViewUtils.showUpdateErrorUI(error: error)
|
|
return
|
|
}
|
|
|
|
GroupViewUtils.updateGroupWithActivityIndicator(fromViewController: self,
|
|
updatePromiseBlock: {
|
|
self.updateGroupThreadPromise(update: groupUpdateToPerform)
|
|
},
|
|
completion: { _ in
|
|
dismissAndUpdateDelegate()
|
|
})
|
|
}
|
|
|
|
func updateGroupThreadPromise(update: GroupManager.GroupUpdate) -> Promise<Void> {
|
|
firstly { () -> Promise<Void> in
|
|
return GroupManager.messageProcessingPromise(for: oldGroupModel,
|
|
description: self.logTag)
|
|
}.then(on: .global()) { _ in
|
|
GroupManager.updateExistingGroup(existingGroupModel: self.oldGroupModel,
|
|
update: update)
|
|
}.asVoid()
|
|
}
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
extension AddGroupMembersViewController: GroupMemberViewDelegate {
|
|
|
|
var groupMemberViewRecipientSet: OrderedSet<PickedRecipient> {
|
|
newRecipientSet
|
|
}
|
|
|
|
var groupMemberViewHasUnsavedChanges: Bool {
|
|
!newRecipientSet.isEmpty
|
|
}
|
|
|
|
var shouldTryToEnableGroupsV2ForMembers: Bool {
|
|
groupThread.isGroupV2Thread
|
|
}
|
|
|
|
func groupMemberViewRemoveRecipient(_ recipient: PickedRecipient) {
|
|
newRecipientSet.remove(recipient)
|
|
updateNavbar()
|
|
}
|
|
|
|
func groupMemberViewAddRecipient(_ recipient: PickedRecipient) {
|
|
newRecipientSet.append(recipient)
|
|
updateNavbar()
|
|
}
|
|
|
|
func groupMemberViewCanAddRecipient(_ recipient: PickedRecipient) -> Bool {
|
|
guard groupThread.isGroupV2Thread else {
|
|
return true
|
|
}
|
|
guard let address = recipient.address else {
|
|
owsFailDebug("Invalid recipient.")
|
|
return false
|
|
}
|
|
return GroupManager.doesUserSupportGroupsV2(address: address)
|
|
}
|
|
|
|
func groupMemberViewShouldShowMemberCount() -> Bool {
|
|
groupThread.isGroupV2Thread
|
|
}
|
|
|
|
func groupMemberViewGroupMemberCountForDisplay() -> Int {
|
|
(oldGroupModel.groupMembership.allMembersOfAnyKind.count +
|
|
newRecipientSet.count)
|
|
}
|
|
|
|
func groupMemberViewIsGroupFull_HardLimit() -> Bool {
|
|
groupMemberViewGroupMemberCountForDisplay() >= GroupManager.groupsV2MaxGroupSizeHardLimit
|
|
}
|
|
|
|
func groupMemberViewIsGroupFull_RecommendedLimit() -> Bool {
|
|
groupMemberViewGroupMemberCountForDisplay() >= GroupManager.groupsV2MaxGroupSizeRecommended
|
|
}
|
|
|
|
func groupMemberViewIsPreExistingMember(_ recipient: PickedRecipient,
|
|
transaction: SDSAnyReadTransaction) -> Bool {
|
|
guard let address = recipient.address else {
|
|
owsFailDebug("Invalid recipient.")
|
|
return false
|
|
}
|
|
let groupMembership = oldGroupModel.groupMembership
|
|
if groupMembership.isFullMember(address) {
|
|
return true
|
|
}
|
|
if groupMembership.isInvitedMember(address) ||
|
|
groupMembership.isRequestingMember(address) {
|
|
// We can "add" pending or requesting members if they support gv2
|
|
// and we know their profile key credential.
|
|
let canAddMember: Bool = {
|
|
guard GroupManager.doesUserSupportGroupsV2(address: address) else {
|
|
return false
|
|
}
|
|
return self.groupsV2.hasProfileKeyCredential(for: address, transaction: transaction)
|
|
}()
|
|
|
|
return !canAddMember
|
|
}
|
|
return false
|
|
}
|
|
|
|
func groupMemberViewIsGroupsV2Required() -> Bool {
|
|
groupThread.isGroupV2Thread
|
|
}
|
|
|
|
func groupMemberViewDismiss() {
|
|
navigationController?.popViewController(animated: true)
|
|
}
|
|
|
|
var isNewGroup: Bool {
|
|
false
|
|
}
|
|
|
|
var groupThreadForGroupMemberView: TSGroupThread? {
|
|
groupThread
|
|
}
|
|
}
|