123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415 |
- import UIKit
- class NewGroupViewController: GroupMembersViewController {
- weak var coordinator: NewGroupCoordinator?
- override func viewDidLoad() {
- super.viewDidLoad()
- title = String.localized("menu_new_group")
- let groupCreationNextButton = UIBarButtonItem(title: String.localized("next"),
- style: .done,
- target: self,
- action: #selector(nextButtonPressed))
- navigationItem.rightBarButtonItem = groupCreationNextButton
- contactIds = Utils.getContactIds()
- }
- override func viewWillAppear(_ animated: Bool) {
- super.viewWillAppear(animated)
- }
- override func didReceiveMemoryWarning() {
- super.didReceiveMemoryWarning()
- }
- @objc func nextButtonPressed() {
- coordinator?.showGroupNameController(contactIdsForGroup: selectedContactIds)
- }
- }
- class AddGroupMembersViewController: GroupMembersViewController {
- weak var coordinator: AddGroupMembersCoordinator?
- private var chatId: Int?
- private let sectionNewContact = 0
- private let sectionMemberList = 1
- private var contactAddedObserver: NSObjectProtocol?
- private lazy var cancelButton: UIBarButtonItem = {
- let button = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelButtonPressed))
- return button
- }()
- lazy var doneButton: UIBarButtonItem = {
- let button = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneButtonPressed))
- return button
- }()
- private lazy var chat: DcChat? = {
- if let chatId = chatId {
- return DcChat(id: chatId)
- }
- return nil
- }()
- private lazy var chatMemberIds: [Int] = {
- if let chat = chat {
- return chat.contactIds
- }
- return []
- }()
- init(chatId: Int) {
- super.init()
- self.chatId = chatId
- numberOfSections = 2
- }
- required init?(coder _: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
- override func viewDidLoad() {
- super.viewDidLoad()
- super.navigationItem.leftBarButtonItem = cancelButton
- super.navigationItem.rightBarButtonItem = doneButton
- title = String.localized("group_add_members")
- super.contactIds = loadMemberCandidates()
- // Do any additional setup after loading the view.
- let nc = NotificationCenter.default
- contactAddedObserver = nc.addObserver(
- forName: dcNotificationContactChanged,
- object: nil,
- queue: nil
- ) { notification in
- if let ui = notification.userInfo {
- if let contactId = ui["contact_id"] as? Int {
- if contactId == 0 {
- return
- }
- self.contactIds = self.loadMemberCandidates()
- if self.contactIds.contains(contactId) {
- self.selectedContactIds.insert(contactId)
- self.tableView.reloadData()
- }
- }
- }
- }
- }
- override func viewWillDisappear(_: Bool) {
- if !isMovingFromParent {
- // a subview was added to the navigation stack, no action needed
- return
- }
- let nc = NotificationCenter.default
- if let observer = self.contactAddedObserver {
- nc.removeObserver(observer)
- }
- }
- override func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
- switch section {
- case sectionNewContact:
- return 1
- case sectionMemberList:
- return getNumberOfRowsForContactList()
- default:
- return 0
- }
- }
- override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
- switch indexPath.section {
- case sectionNewContact:
- return Constants.defaultCellHeight
- case sectionMemberList:
- return ContactCell.cellHeight
- default:
- return Constants.defaultCellHeight
- }
- }
-
- override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- switch indexPath.section {
- case sectionNewContact:
- return getNewContactCell()
- case sectionMemberList:
- return getContactCell(cellForRowAt: indexPath)
- default:
- return UITableViewCell(style: .default, reuseIdentifier: nil)
- }
- }
- override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
- switch indexPath.section {
- case sectionNewContact:
- tableView.deselectRow(at: indexPath, animated: true)
- coordinator?.showNewContactController()
- case sectionMemberList:
- didSelectContactCell(at: indexPath)
- default:
- fatalError("unexpected section selected in GroupMembersViewController")
- }
- }
- func loadMemberCandidates() -> [Int] {
- var contactIds = Utils.getContactIds()
- let memberSet = Set(chatMemberIds)
- contactIds.removeAll(where: { memberSet.contains($0)})
- return Array(contactIds)
- }
- @objc func cancelButtonPressed() {
- navigationController?.popViewController(animated: true)
- }
- @objc func doneButtonPressed() {
- guard let chatId = chatId else {
- return
- }
- for contactId in selectedContactIds {
- dc_add_contact_to_chat(mailboxPointer, UInt32(chatId), UInt32(contactId))
- }
- navigationController?.popViewController(animated: true)
- }
- func getNewContactCell() -> UITableViewCell {
- let cell: UITableViewCell
- if let c = tableView.dequeueReusableCell(withIdentifier: "actionCell") {
- cell = c
- } else {
- cell = UITableViewCell(style: .default, reuseIdentifier: "actionCell")
- }
- cell.textLabel?.text = String.localized("menu_new_contact")
- cell.textLabel?.textColor = view.tintColor
- cell.textLabel?.textAlignment = .center
- return cell
- }
- }
- class BlockedContactsViewController: GroupMembersViewController, GroupMemberSelectionDelegate {
- override init() {
- super.init()
- enableCheckmarks = false
- }
- required init?(coder _: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
- override func viewDidLoad() {
- super.viewDidLoad()
- title = String.localized("pref_blocked_contacts")
- contactIds = Utils.getBlockedContactIds()
- selectedContactIds = Set(contactIds)
- navigationItem.searchController = nil
- groupMemberSelectionDelegate = self
- }
- override func viewWillAppear(_ animated: Bool) {
- super.viewWillAppear(animated)
- }
- func selected(contactId: Int, selected: Bool) {
- if !selected {
- let dcContact = DcContact(id: contactId)
- let title = dcContact.displayName.isEmpty ? dcContact.email : dcContact.displayName
- let alert = UIAlertController(title: title, message: String.localized("ask_unblock_contact"), preferredStyle: .actionSheet)
- alert.addAction(UIAlertAction(title: String.localized("menu_unblock_contact"), style: .default, handler: { _ in
- let contact = DcContact(id: contactId)
- contact.unblock()
- self.contactIds = Utils.getBlockedContactIds()
- self.selectedContactIds = Set(self.contactIds)
- self.tableView.reloadData()
- }))
- alert.addAction(UIAlertAction(title: String.localized("cancel"), style: .cancel, handler: { _ in
- self.selectedContactIds = Set(self.contactIds)
- self.tableView.reloadData()
- }))
- present(alert, animated: true, completion: nil)
- }
- }
- }
- protocol GroupMemberSelectionDelegate: class {
- func selected(contactId: Int, selected: Bool)
- }
- class GroupMembersViewController: UITableViewController, UISearchResultsUpdating {
- let contactCellReuseIdentifier = "contactCell"
- weak var groupMemberSelectionDelegate: GroupMemberSelectionDelegate?
- var enableCheckmarks = true
- var numberOfSections = 1
- var contactIds: [Int] = [] {
- didSet {
- tableView.reloadData()
- }
- }
- // contactWithSearchResults.indexesToHightLight empty by default
- var contacts: [ContactWithSearchResults] {
- return contactIds.map { ContactWithSearchResults(contact: DcContact(id: $0), indexesToHighlight: []) }
- }
- // used when seachbar is active
- var filteredContacts: [ContactWithSearchResults] = []
- // searchBar active?
- func isFiltering() -> Bool {
- return searchController.isActive && !searchBarIsEmpty()
- }
- private func searchBarIsEmpty() -> Bool {
- return searchController.searchBar.text?.isEmpty ?? true
- }
- private func contactIdByRow(_ row: Int) -> Int {
- return isFiltering() ? filteredContacts[row].contact.id : contactIds[row]
- }
- private func contactSearchResultByRow(_ row: Int) -> ContactWithSearchResults {
- return isFiltering() ? filteredContacts[row] : contacts[row]
- }
- private lazy var searchController: UISearchController = {
- let searchController = UISearchController(searchResultsController: nil)
- searchController.searchResultsUpdater = self
- searchController.obscuresBackgroundDuringPresentation = false
- searchController.searchBar.placeholder = String.localized("search")
- searchController.hidesNavigationBarDuringPresentation = false
- return searchController
- }()
- var selectedContactIds: Set<Int> = []
- init() {
- super.init(style: .grouped)
- hidesBottomBarWhenPushed = true
- }
- required init?(coder _: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
- override func viewDidLoad() {
- tableView.register(ContactCell.self, forCellReuseIdentifier: contactCellReuseIdentifier)
- navigationItem.searchController = searchController
- if #available(iOS 11.0, *) {
- navigationItem.hidesSearchBarWhenScrolling = false
- }
- definesPresentationContext = true
- }
- override func numberOfSections(in _: UITableView) -> Int {
- return numberOfSections
- }
- override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int {
- return getNumberOfRowsForContactList()
- }
- override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
- return ContactCell.cellHeight
- }
- override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- return getContactCell(cellForRowAt: indexPath)
- }
- override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
- didSelectContactCell(at: indexPath)
- }
- func getNumberOfRowsForContactList() -> Int {
- return isFiltering() ? filteredContacts.count : contacts.count
- }
- func getContactCell(cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- guard let cell: ContactCell = tableView.dequeueReusableCell(withIdentifier: contactCellReuseIdentifier, for: indexPath) as? ContactCell else {
- fatalError("shouldn't happen")
- }
- let row = indexPath.row
- let contact: ContactWithSearchResults = contactSearchResultByRow(row)
- updateContactCell(cell: cell, contactWithHighlight: contact)
- cell.accessoryType = selectedContactIds.contains(contactIdByRow(row)) && enableCheckmarks ? .checkmark : .none
- return cell
- }
- func didSelectContactCell(at indexPath: IndexPath) {
- let row = indexPath.row
- if let cell = tableView.cellForRow(at: indexPath) {
- tableView.deselectRow(at: indexPath, animated: true)
- let contactId = contactIdByRow(row)
- if selectedContactIds.contains(contactId) {
- selectedContactIds.remove(contactId)
- if enableCheckmarks {
- cell.accessoryType = .none
- }
- groupMemberSelectionDelegate?.selected(contactId: contactId, selected: false)
- } else {
- selectedContactIds.insert(contactId)
- if enableCheckmarks {
- cell.accessoryType = .checkmark
- }
- groupMemberSelectionDelegate?.selected(contactId: contactId, selected: true)
- }
- }
- }
- func updateSearchResults(for searchController: UISearchController) {
- if let searchText = searchController.searchBar.text {
- filterContentForSearchText(searchText)
- }
- }
- private func filterContentForSearchText(_ searchText: String, scope _: String = String.localized("pref_show_emails_all")) {
- let contactsWithHighlights: [ContactWithSearchResults] = contacts.map { contact in
- let indexes = contact.contact.containsExact(searchText: searchText)
- return ContactWithSearchResults(contact: contact.contact, indexesToHighlight: indexes)
- }
- filteredContacts = contactsWithHighlights.filter { !$0.indexesToHighlight.isEmpty }
- tableView.reloadData()
- }
- private func updateContactCell(cell: ContactCell, contactWithHighlight: ContactWithSearchResults) {
- let contact = contactWithHighlight.contact
- let displayName = contact.displayName
- let emailLabelFontSize = cell.emailLabel.font.pointSize
- let nameLabelFontSize = cell.nameLabel.font.pointSize
- cell.nameLabel.text = displayName
- cell.emailLabel.text = contact.email
- cell.avatar.setName(displayName)
- cell.avatar.setColor(contact.color)
- if let profileImage = contact.profileImage {
- cell.avatar.setImage(profileImage)
- }
- cell.setVerified(isVerified: contact.isVerified)
- if let emailHighlightedIndexes = contactWithHighlight.indexesToHighlight.filter({ $0.contactDetail == .EMAIL }).first {
- // gets here when contact is a result of current search -> highlights relevant indexes
- cell.emailLabel.attributedText = contact.email.boldAt(indexes: emailHighlightedIndexes.indexes, fontSize: emailLabelFontSize)
- } else {
- cell.emailLabel.attributedText = contact.email.boldAt(indexes: [], fontSize: emailLabelFontSize)
- }
- if let nameHighlightedIndexes = contactWithHighlight.indexesToHighlight.filter({ $0.contactDetail == .NAME }).first {
- cell.nameLabel.attributedText = displayName.boldAt(indexes: nameHighlightedIndexes.indexes, fontSize: nameLabelFontSize)
- } else {
- cell.nameLabel.attributedText = displayName.boldAt(indexes: [], fontSize: nameLabelFontSize)
- }
- }
- }
|