// // Copyright (c) 2020 Open Whisper Systems. All rights reserved. // import Foundation import PromiseKit @objc public class AddToGroupViewController: OWSTableViewController { private let address: SignalServiceAddress private let collation = UILocalizedIndexedCollation.current() private let maxRecentGroups = 5 private lazy var threadViewHelper: ThreadViewHelper = { let threadViewHelper = ThreadViewHelper() threadViewHelper.delegate = self return threadViewHelper }() init(address: SignalServiceAddress) { self.address = address super.init() tableViewStyle = .plain } 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() navigationItem.title = NSLocalizedString("ADD_TO_GROUP_TITLE", comment: "Title of the 'add to group' view.") navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .stop, target: self, action: #selector(didPressCloseButton)) tableView.separatorStyle = .none } public override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) updateTableContents() NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .ThemeDidChange, object: nil) } public override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) NotificationCenter.default.removeObserver(self) } private func updateTableContents() { AssertIsOnMainThread() let groupThreads = databaseStorage.read { transaction in return self.threadViewHelper.threads.filter { thread -> Bool in guard let groupThread = thread as? TSGroupThread else { return false } let threadViewModel = ThreadViewModel(thread: groupThread, transaction: transaction) let groupViewHelper = GroupViewHelper(threadViewModel: threadViewModel) return groupViewHelper.canEditConversationMembership } as? [TSGroupThread] ?? [] } let contents = OWSTableContents() let recentGroups = groupThreads.count > maxRecentGroups ? Array(groupThreads[0.. maxRecentGroups ? Array(groupThreads[maxRecentGroups.. TSGroupModel? { do { return try databaseStorage.read { transaction in var builder = oldGroupModel.asBuilder let oldGroupMembership = oldGroupModel.groupMembership var groupMembershipBuilder = oldGroupMembership.asBuilder guard !oldGroupMembership.isMemberOfAnyKind(self.address) else { owsFailDebug("Recipient is already in group.") return nil } // GroupManager will separate out members as pending if necessary. groupMembershipBuilder.addFullMember(self.address, role: .normal) builder.groupMembership = groupMembershipBuilder.build() return try builder.build(transaction: transaction) } } catch { owsFailDebug("Error: \(error)") return nil } } func updateGroupThreadPromise(oldGroupModel: TSGroupModel, newGroupModel: TSGroupModel) -> Promise { guard let localAddress = TSAccountManager.localAddress else { return Promise(error: OWSAssertionError("Missing localAddress.")) } return firstly { () -> Promise in return GroupManager.messageProcessingPromise(for: oldGroupModel, description: self.logTag) }.then(on: .global()) { _ in // dmConfiguration: nil means don't change disappearing messages configuration. GroupManager.localUpdateExistingGroup(oldGroupModel: oldGroupModel, newGroupModel: newGroupModel, dmConfiguration: nil, groupUpdateSourceAddress: localAddress) }.asVoid() } // MARK: - private func sectionHeader(title: String) -> UIView { let textView = UITextView() textView.isOpaque = false textView.isEditable = false textView.contentInset = .zero textView.textContainer.lineFragmentPadding = 0 textView.isScrollEnabled = false textView.textColor = Theme.primaryTextColor textView.font = UIFont.ows_dynamicTypeBody.ows_semibold() textView.backgroundColor = Theme.washColor let tableEdgeInsets: CGFloat = UIDevice.current.isPlusSizePhone ? 20 : 16 textView.textContainerInset = UIEdgeInsets(top: 5, left: tableEdgeInsets, bottom: 5, right: tableEdgeInsets) textView.text = title return textView } private func item(for groupThread: TSGroupThread) -> OWSTableItem { return OWSTableItem( customCellBlock: { let cell = GroupTableViewCell() cell.configure(thread: groupThread) return cell }, customRowHeight: UITableView.automaticDimension, actionBlock: { [weak self] in self?.didSelectGroup(groupThread) } ) } } // MARK: - extension AddToGroupViewController: ThreadViewHelperDelegate { public func threadListDidChange() { updateTableContents() } }