diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 18ff857c2..ed2908dbd 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -570,6 +570,8 @@ C31A6C5C247F2CF3001123EF /* CGRect+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31A6C5B247F2CF3001123EF /* CGRect+Utilities.swift */; }; C31D1DD325216101005D4DA8 /* UIView+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31D1DD225216101005D4DA8 /* UIView+Utilities.swift */; }; C31D1DDD25217014005D4DA8 /* UserCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31D1DDC25217014005D4DA8 /* UserCell.swift */; }; + C31D1DE32521718E005D4DA8 /* UserSelectionVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31D1DE22521718E005D4DA8 /* UserSelectionVC.swift */; }; + C31D1DE9252172D4005D4DA8 /* ContactUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31D1DE8252172D4005D4DA8 /* ContactUtilities.swift */; }; C329FEEC24F7277900B1C64C /* LightModeSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C329FEEB24F7277900B1C64C /* LightModeSheet.swift */; }; C329FEEF24F7743F00B1C64C /* UIViewController+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C329FEED24F7742E00B1C64C /* UIViewController+Utilities.swift */; }; C34C8F7423A7830B00D82669 /* SpaceMono-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C34C8F7323A7830A00D82669 /* SpaceMono-Bold.ttf */; }; @@ -1367,6 +1369,8 @@ C31A6C5B247F2CF3001123EF /* CGRect+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGRect+Utilities.swift"; sourceTree = ""; }; C31D1DD225216101005D4DA8 /* UIView+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Utilities.swift"; sourceTree = ""; }; C31D1DDC25217014005D4DA8 /* UserCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserCell.swift; sourceTree = ""; }; + C31D1DE22521718E005D4DA8 /* UserSelectionVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSelectionVC.swift; sourceTree = ""; }; + C31D1DE8252172D4005D4DA8 /* ContactUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactUtilities.swift; sourceTree = ""; }; C329FEEB24F7277900B1C64C /* LightModeSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LightModeSheet.swift; sourceTree = ""; }; C329FEED24F7742E00B1C64C /* UIViewController+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Utilities.swift"; sourceTree = ""; }; C34C8F7323A7830A00D82669 /* SpaceMono-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SpaceMono-Bold.ttf"; sourceTree = ""; }; @@ -2696,6 +2700,7 @@ B8544E3223D50E4900299F14 /* AppearanceUtilities.swift */, C3D0972A2510499C00F6E3E4 /* BackgroundPoller.swift */, C31A6C5B247F2CF3001123EF /* CGRect+Utilities.swift */, + C31D1DE8252172D4005D4DA8 /* ContactUtilities.swift */, C35E8AAD2485E51D00ACB629 /* IP2Country.swift */, B84664F4235022F30083A1CD /* MentionUtilities.swift */, B886B4A82398BA1500211ABE /* QRCode.swift */, @@ -2741,6 +2746,7 @@ B85357C223A1BD1200AAF6CD /* SeedVC.swift */, B8CCF6422397711F0091D419 /* SettingsVC.swift */, C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */, + C31D1DE22521718E005D4DA8 /* UserSelectionVC.swift */, ); path = "View Controllers"; sourceTree = ""; @@ -3961,6 +3967,7 @@ B8BB82B523947F2D00BA5194 /* TextField.swift in Sources */, 34D1F0841F8678AA0066283D /* ConversationInputToolbar.m in Sources */, 457F671B20746193000EABCD /* QuotedReplyPreview.swift in Sources */, + C31D1DE32521718E005D4DA8 /* UserSelectionVC.swift in Sources */, 34A6C28021E503E700B5B12E /* OWSImagePickerController.swift in Sources */, C31A6C5C247F2CF3001123EF /* CGRect+Utilities.swift in Sources */, 4C21D5D6223A9DC500EF8A77 /* UIAlerts+iOS9.m in Sources */, @@ -3978,6 +3985,7 @@ 340FC8B9204DAC8D007AEB0F /* UpdateGroupViewController.m in Sources */, B8BB82A5238F627000BA5194 /* HomeVC.swift in Sources */, C31A6C5A247F214E001123EF /* UIView+Glow.swift in Sources */, + C31D1DE9252172D4005D4DA8 /* ContactUtilities.swift in Sources */, 3448E1662215B313004B052E /* OnboardingCaptchaViewController.swift in Sources */, 4574A5D61DD6704700C6B692 /* CallService.swift in Sources */, 4521C3C01F59F3BA00B4C582 /* TextFieldHelper.swift in Sources */, diff --git a/Signal/src/Loki/Components/UserCell.swift b/Signal/src/Loki/Components/UserCell.swift index 556701744..86a447396 100644 --- a/Signal/src/Loki/Components/UserCell.swift +++ b/Signal/src/Loki/Components/UserCell.swift @@ -79,7 +79,7 @@ final class UserCell : UITableViewCell { } // MARK: Updating - private func update() { + func update() { profilePictureView.hexEncodedPublicKey = publicKey profilePictureView.update() displayNameLabel.text = UserDisplayNameUtilities.getPrivateChatDisplayName(for: publicKey) ?? publicKey diff --git a/Signal/src/Loki/Utilities/ContactUtilities.swift b/Signal/src/Loki/Utilities/ContactUtilities.swift new file mode 100644 index 000000000..47aefde46 --- /dev/null +++ b/Signal/src/Loki/Utilities/ContactUtilities.swift @@ -0,0 +1,17 @@ + +enum ContactUtilities { + + static func getAllContacts() -> [String] { + var result: [String] = [] + Storage.read { transaction in + TSContactThread.enumerateCollectionObjects(with: transaction) { object, _ in + guard let thread = object as? TSContactThread else { return } + result.append(thread.contactIdentifier()) + } + } + func getDisplayName(for publicKey: String) -> String { + return UserDisplayNameUtilities.getPrivateChatDisplayName(for: publicKey) ?? publicKey + } + return result.sorted { getDisplayName(for: $0) < getDisplayName(for: $1) } + } +} diff --git a/Signal/src/Loki/View Controllers/EditClosedGroupVC.swift b/Signal/src/Loki/View Controllers/EditClosedGroupVC.swift index f8301d700..c4ef4adea 100644 --- a/Signal/src/Loki/View Controllers/EditClosedGroupVC.swift +++ b/Signal/src/Loki/View Controllers/EditClosedGroupVC.swift @@ -92,6 +92,12 @@ final class EditClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelega addMembersButton.setTitle("Add Members", for: UIControl.State.normal) addMembersButton.addTarget(self, action: #selector(addMembers), for: UIControl.Event.touchUpInside) addMembersButton.contentEdgeInsets = UIEdgeInsets(top: 0, leading: Values.mediumSpacing, bottom: 0, trailing: Values.mediumSpacing) + if (Set(ContactUtilities.getAllContacts()).subtracting(members).isEmpty) { + addMembersButton.isUserInteractionEnabled = false + let disabledColor = Colors.text.withAlphaComponent(Values.unimportantElementOpacity) + addMembersButton.layer.borderColor = disabledColor.cgColor + addMembersButton.setTitleColor(disabledColor, for: UIControl.State.normal) + } // Middle stack view let middleStackView = UIStackView(arrangedSubviews: [ membersLabel, addMembersButton ]) middleStackView.axis = .horizontal @@ -130,6 +136,7 @@ final class EditClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelega let cell = tableView.dequeueReusableCell(withIdentifier: "UserCell") as! UserCell let publicKey = members[indexPath.row] cell.publicKey = publicKey + cell.update() return cell } @@ -187,6 +194,8 @@ final class EditClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelega } @objc private func addMembers() { - + let title = "Add Members" + let userSelectionVC = UserSelectionVC(with: title, excluding: Set(members)) + navigationController!.pushViewController(userSelectionVC, animated: true, completion: nil) } } diff --git a/Signal/src/Loki/View Controllers/UserSelectionVC.swift b/Signal/src/Loki/View Controllers/UserSelectionVC.swift new file mode 100644 index 000000000..41d07d540 --- /dev/null +++ b/Signal/src/Loki/View Controllers/UserSelectionVC.swift @@ -0,0 +1,56 @@ + +final class UserSelectionVC : BaseVC, UITableViewDataSource { + private let navBarTitle: String + private let usersToExclude: Set + + private lazy var users: [String] = { + var result = ContactUtilities.getAllContacts() + result.removeAll { usersToExclude.contains($0) } + return result + }() + + // MARK: Components + @objc private lazy var tableView: UITableView = { + let result = UITableView() + result.dataSource = self + result.register(UserCell.self, forCellReuseIdentifier: "UserCell") + result.separatorStyle = .none + result.backgroundColor = .clear + result.showsVerticalScrollIndicator = false + result.alwaysBounceVertical = false + return result + }() + + // MARK: Lifecycle + @objc init(with title: String, excluding usersToExclude: Set) { + self.navBarTitle = title + self.usersToExclude = usersToExclude + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { preconditionFailure("Use UserSelectionVC.init(excluding:) instead.") } + override init(nibName: String?, bundle: Bundle?) { preconditionFailure("Use UserSelectionVC.init(excluding:) instead.") } + + override func viewDidLoad() { + super.viewDidLoad() + setUpGradientBackground() + setUpNavBarStyle() + setNavBarTitle(navBarTitle) + view.addSubview(tableView) + tableView.pin(to: view) + } + + // MARK: Data + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return users.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "UserCell") as! UserCell + let publicKey = users[indexPath.row] + cell.publicKey = publicKey + cell.accessory = .tick(isSelected: false) + cell.update() + return cell + } +} diff --git a/Signal/src/ViewControllers/ThreadSettings/OWSConversationSettingsViewController.m b/Signal/src/ViewControllers/ThreadSettings/OWSConversationSettingsViewController.m index 200f82321..efc9931d7 100644 --- a/Signal/src/ViewControllers/ThreadSettings/OWSConversationSettingsViewController.m +++ b/Signal/src/ViewControllers/ThreadSettings/OWSConversationSettingsViewController.m @@ -1150,7 +1150,7 @@ const CGFloat kIconViewLength = 24; - (void)editGroup { LKEditClosedGroupVC *editClosedGroupVC = [[LKEditClosedGroupVC alloc] initWithThreadID:self.thread.uniqueId]; - [self.navigationController pushViewController:editClosedGroupVC animated:YES]; + [self.navigationController pushViewController:editClosedGroupVC animated:YES completion:nil]; } - (void)didTapLeaveGroup