206 lines
7.5 KiB
Swift
206 lines
7.5 KiB
Swift
//
|
|
// Copyright 2020 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
//
|
|
|
|
import SignalServiceKit
|
|
import SignalUI
|
|
|
|
public class AddToGroupViewController: OWSTableViewController2 {
|
|
|
|
private let address: SignalServiceAddress
|
|
|
|
init(address: SignalServiceAddress) {
|
|
self.address = address
|
|
super.init()
|
|
}
|
|
|
|
public class func presentForUser(_ address: SignalServiceAddress,
|
|
from fromViewController: UIViewController) {
|
|
AssertIsOnMainThread()
|
|
|
|
let view = AddToGroupViewController(address: address)
|
|
let modal = OWSNavigationController(rootViewController: view)
|
|
fromViewController.presentFormSheet(modal, animated: true)
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
public override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
|
|
title = OWSLocalizedString("ADD_TO_GROUP_TITLE", comment: "Title of the 'add to group' view.")
|
|
|
|
navigationItem.leftBarButtonItem = .cancelButton { [weak self] in
|
|
self?.didPressCloseButton()
|
|
}
|
|
|
|
defaultSeparatorInsetLeading = Self.cellHInnerMargin + CGFloat(AvatarBuilder.smallAvatarSizePoints) + ContactCellView.avatarTextHSpacing
|
|
|
|
updateGroupThreadsAsync()
|
|
}
|
|
|
|
private var groupThreads = [TSGroupThread]() {
|
|
didSet {
|
|
AssertIsOnMainThread()
|
|
updateTableContents()
|
|
}
|
|
}
|
|
|
|
private func updateGroupThreadsAsync() {
|
|
DispatchQueue.sharedUserInitiated.async { [weak self] in
|
|
let fetchedGroupThreads = Self.fetchGroupThreads()
|
|
DispatchQueue.main.async {
|
|
self?.groupThreads = fetchedGroupThreads
|
|
}
|
|
}
|
|
}
|
|
|
|
private class func fetchGroupThreads() -> [TSGroupThread] {
|
|
databaseStorage.read { transaction in
|
|
var result = [TSGroupThread]()
|
|
|
|
do {
|
|
try ThreadFinder().enumerateGroupThreads(transaction: transaction) { thread, _ in
|
|
guard thread.isGroupV2Thread else { return }
|
|
|
|
let threadViewModel = ThreadViewModel(
|
|
thread: thread,
|
|
forChatList: false,
|
|
transaction: transaction
|
|
)
|
|
let groupViewHelper = GroupViewHelper(threadViewModel: threadViewModel)
|
|
guard groupViewHelper.canEditConversationMembership else { return }
|
|
|
|
result.append(thread)
|
|
}
|
|
} catch {
|
|
owsFailDebug("Failed to fetch group threads: \(error). Returning an empty array")
|
|
}
|
|
|
|
return result
|
|
}
|
|
}
|
|
|
|
private func updateTableContents() {
|
|
AssertIsOnMainThread()
|
|
let groupsSection = OWSTableSection(items: groupThreads.map(item(forGroupThread:)))
|
|
self.contents = OWSTableContents(sections: [groupsSection])
|
|
}
|
|
|
|
// MARK: Helpers
|
|
|
|
public override func themeDidChange() {
|
|
super.themeDidChange()
|
|
self.tableView.sectionIndexColor = Theme.primaryTextColor
|
|
updateTableContents()
|
|
}
|
|
|
|
private func didPressCloseButton() {
|
|
Logger.info("")
|
|
|
|
self.dismiss(animated: true)
|
|
}
|
|
|
|
private func didSelectGroup(_ groupThread: TSGroupThread) {
|
|
let shortName = databaseStorage.read { transaction in
|
|
return Self.contactsManager.displayName(for: self.address, tx: transaction).resolvedValue(useShortNameIfAvailable: true)
|
|
}
|
|
|
|
guard !groupThread.groupModel.groupMembership.isMemberOfAnyKind(address) else {
|
|
let toastFormat = OWSLocalizedString(
|
|
"ADD_TO_GROUP_ALREADY_MEMBER_TOAST_FORMAT",
|
|
comment: "A toast on the 'add to group' view indicating the user is already a member. Embeds {contact name} and {group name}"
|
|
)
|
|
let toastText = String(format: toastFormat, shortName, groupThread.groupNameOrDefault)
|
|
presentToast(text: toastText)
|
|
return
|
|
}
|
|
|
|
let messageFormat = OWSLocalizedString("ADD_TO_GROUP_ACTION_SHEET_MESSAGE_FORMAT",
|
|
comment: "The title on the 'add to group' confirmation action sheet. Embeds {contact name, group name}")
|
|
|
|
OWSActionSheets.showConfirmationAlert(
|
|
title: OWSLocalizedString(
|
|
"ADD_TO_GROUP_ACTION_SHEET_TITLE",
|
|
comment: "The title on the 'add to group' confirmation action sheet."
|
|
),
|
|
message: String(format: messageFormat, shortName, groupThread.groupNameOrDefault),
|
|
proceedTitle: OWSLocalizedString("ADD_TO_GROUP_ACTION_PROCEED_BUTTON",
|
|
comment: "The button on the 'add to group' confirmation to add the user to the group."),
|
|
proceedStyle: .default) { _ in
|
|
self.addToGroup(groupThread, shortName: shortName)
|
|
}
|
|
}
|
|
|
|
private func addToGroup(_ groupThread: TSGroupThread, shortName: String) {
|
|
AssertIsOnMainThread()
|
|
owsAssert(groupThread.isGroupV2Thread) // non-gv2 filtered above when fetching groups
|
|
|
|
guard let serviceId = self.address.serviceId else {
|
|
GroupViewUtils.showInvalidGroupMemberAlert(fromViewController: self)
|
|
return
|
|
}
|
|
|
|
let oldGroupModel = groupThread.groupModel
|
|
|
|
guard !oldGroupModel.groupMembership.isMemberOfAnyKind(serviceId) else {
|
|
let error = OWSAssertionError("Receipient is already in group")
|
|
GroupViewUtils.showUpdateErrorUI(error: error)
|
|
return
|
|
}
|
|
|
|
GroupViewUtils.updateGroupWithActivityIndicator(
|
|
fromViewController: self,
|
|
withGroupModel: oldGroupModel,
|
|
updateDescription: self.logTag,
|
|
updateBlock: {
|
|
GroupManager.addOrInvite(
|
|
serviceIds: [serviceId],
|
|
toExistingGroup: oldGroupModel
|
|
)
|
|
},
|
|
completion: { [weak self] _ in
|
|
self?.notifyOfAddedAndDismiss(groupThread: groupThread, shortName: shortName)
|
|
}
|
|
)
|
|
}
|
|
|
|
private func notifyOfAddedAndDismiss(groupThread: TSGroupThread, shortName: String) {
|
|
dismiss(animated: true) { [presentingViewController] in
|
|
let toastFormat = OWSLocalizedString(
|
|
"ADD_TO_GROUP_SUCCESS_TOAST_FORMAT",
|
|
comment: "A toast on the 'add to group' view indicating the user was added. Embeds {contact name} and {group name}"
|
|
)
|
|
let toastText = String(format: toastFormat, shortName, groupThread.groupNameOrDefault)
|
|
presentingViewController?.presentToast(text: toastText)
|
|
}
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
private func item(forGroupThread groupThread: TSGroupThread) -> OWSTableItem {
|
|
let alreadyAMemberText = OWSLocalizedString(
|
|
"ADD_TO_GROUP_ALREADY_A_MEMBER",
|
|
comment: "Text indicating your contact is already a member of the group on the 'add to group' view."
|
|
)
|
|
let isAlreadyAMember = groupThread.groupMembership.isFullMember(address)
|
|
|
|
return OWSTableItem(
|
|
customCellBlock: {
|
|
let cell = GroupTableViewCell()
|
|
cell.configure(
|
|
thread: groupThread,
|
|
customSubtitle: isAlreadyAMember ? alreadyAMemberText : nil,
|
|
customTextColor: isAlreadyAMember ? Theme.ternaryTextColor : nil
|
|
)
|
|
cell.isUserInteractionEnabled = !isAlreadyAMember
|
|
return cell
|
|
},
|
|
actionBlock: { [weak self] in
|
|
self?.didSelectGroup(groupThread)
|
|
}
|
|
)
|
|
}
|
|
}
|