diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 27dd0f4e6..3dfd0f5f7 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -560,6 +560,7 @@ B6B226971BE4B7D200860F4D /* ContactsUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6B226961BE4B7D200860F4D /* ContactsUI.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; B6F509971AA53F760068F56A /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B6F509951AA53F760068F56A /* Localizable.strings */; }; B6FE7EB71ADD62FA00A6D22F /* PushKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6FE7EB61ADD62FA00A6D22F /* PushKit.framework */; }; + B80A579F23DFF1F300876683 /* NewClosedGroupVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B80A579E23DFF1F300876683 /* NewClosedGroupVC.swift */; }; B80C6B572384A56D00FDBC8B /* DeviceLinksVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B80C6B562384A56D00FDBC8B /* DeviceLinksVC.swift */; }; B80C6B592384C4E700FDBC8B /* DeviceNameModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B80C6B582384C4E700FDBC8B /* DeviceNameModal.swift */; }; B80C6B5B2384C7F900FDBC8B /* DeviceNameModalDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B80C6B5A2384C7F900FDBC8B /* DeviceNameModalDelegate.swift */; }; @@ -1403,6 +1404,7 @@ B6BC3D0C1AA544B100C2907F /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = translations/da.lproj/Localizable.strings; sourceTree = ""; }; B6F509961AA53F760068F56A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = translations/en.lproj/Localizable.strings; sourceTree = ""; }; B6FE7EB61ADD62FA00A6D22F /* PushKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PushKit.framework; path = System/Library/Frameworks/PushKit.framework; sourceTree = SDKROOT; }; + B80A579E23DFF1F300876683 /* NewClosedGroupVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewClosedGroupVC.swift; sourceTree = ""; }; B80C6B562384A56D00FDBC8B /* DeviceLinksVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceLinksVC.swift; sourceTree = ""; }; B80C6B582384C4E700FDBC8B /* DeviceNameModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceNameModal.swift; sourceTree = ""; }; B80C6B5A2384C7F900FDBC8B /* DeviceNameModalDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceNameModalDelegate.swift; sourceTree = ""; }; @@ -2819,6 +2821,7 @@ B85357C423A1F13800AAF6CD /* LinkDeviceVC.swift */, B85357C623A1FB5100AAF6CD /* LinkDeviceVCDelegate.swift */, B86BD08323399ACF000F5AE3 /* Modal.swift */, + B80A579E23DFF1F300876683 /* NewClosedGroupVC.swift */, B8CCF63623961D6D0091D419 /* NewPrivateChatVC.swift */, B894D0742339EDCF00B4D94D /* NukeDataModal.swift */, B886B4A62398B23E00211ABE /* QRCodeVC.swift */, @@ -3928,6 +3931,7 @@ 349ED990221B0194008045B0 /* Onboarding2FAViewController.swift in Sources */, 45D231771DC7E8F10034FA89 /* SessionResetJob.swift in Sources */, 340FC8A9204DAC8D007AEB0F /* NotificationSettingsOptionsViewController.m in Sources */, + B80A579F23DFF1F300876683 /* NewClosedGroupVC.swift in Sources */, 452037D11EE84975004E4CDF /* DebugUISessionState.m in Sources */, D221A09A169C9E5E00537ABF /* main.m in Sources */, 3496957221A301A100DCFE74 /* OWSBackup.m in Sources */, diff --git a/Signal/src/Loki/View Controllers/HomeVC.swift b/Signal/src/Loki/View Controllers/HomeVC.swift index ce737b419..fb09a2182 100644 --- a/Signal/src/Loki/View Controllers/HomeVC.swift +++ b/Signal/src/Loki/View Controllers/HomeVC.swift @@ -252,20 +252,16 @@ final class HomeVC : UIViewController, UITableViewDataSource, UITableViewDelegat let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(openSettings)) profilePictureView.addGestureRecognizer(tapGestureRecognizer) navigationItem.leftBarButtonItem = UIBarButtonItem(customView: profilePictureView) - let newClosedGroupButton = UIButton(type: .custom) newClosedGroupButton.setImage(#imageLiteral(resourceName: "btnGroup--white"), for: UIControl.State.normal) newClosedGroupButton.addTarget(self, action: #selector(createClosedGroup), for: UIControl.Event.touchUpInside) newClosedGroupButton.tintColor = Colors.text - let joinPublicChatButton = UIButton(type: .custom) joinPublicChatButton.setImage(#imageLiteral(resourceName: "Globe"), for: UIControl.State.normal) joinPublicChatButton.addTarget(self, action: #selector(joinPublicChat), for: UIControl.Event.touchUpInside) joinPublicChatButton.tintColor = Colors.text - let buttonStackView = UIStackView(arrangedSubviews: [ newClosedGroupButton, joinPublicChatButton ]) buttonStackView.axis = .horizontal - navigationItem.rightBarButtonItem = UIBarButtonItem(customView: buttonStackView) } @@ -373,7 +369,7 @@ final class HomeVC : UIViewController, UITableViewDataSource, UITableViewDelegat } @objc private func createClosedGroup() { - let newClosedGroupVC = NewGroupViewController() + let newClosedGroupVC = NewClosedGroupVC() let navigationController = OWSNavigationController(rootViewController: newClosedGroupVC) present(navigationController, animated: true, completion: nil) } diff --git a/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift b/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift new file mode 100644 index 000000000..4aa2f2b16 --- /dev/null +++ b/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift @@ -0,0 +1,141 @@ + +final class NewClosedGroupVC : UIViewController, UITableViewDataSource, UITableViewDelegate { + + private lazy var contacts: [String] = { + var result: [String] = [] + TSContactThread.enumerateCollectionObjects { object, _ in + guard let thread = object as? TSContactThread, thread.isContactFriend else { return } + let hexEncodedPublicKey = thread.contactIdentifier() + result.append(hexEncodedPublicKey) + } + func getDisplayName(for hexEncodedPublicKey: String) -> String { + return DisplayNameUtilities.getPrivateChatDisplayName(for: hexEncodedPublicKey) ?? "Unknown Contact" + } + result = result.sorted { + getDisplayName(for: $0) < getDisplayName(for: $1) + } + return result + }() + + // MARK: Components + @objc private lazy var tableView: UITableView = { + let result = UITableView() + result.dataSource = self + result.delegate = self + result.register(Cell.self, forCellReuseIdentifier: "Cell") + result.separatorStyle = .none + result.backgroundColor = .clear + result.showsVerticalScrollIndicator = false + return result + }() + + // MARK: Lifecycle + override func viewDidLoad() { + // Set gradient background + view.backgroundColor = .clear + let gradient = Gradients.defaultLokiBackground + view.setGradient(gradient) + // Set navigation bar background color + let navigationBar = navigationController!.navigationBar + navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default) + navigationBar.shadowImage = UIImage() + navigationBar.isTranslucent = false + navigationBar.barTintColor = Colors.navigationBarBackground + // Set up table view + view.addSubview(tableView) + tableView.pin(to: view) + } + + // MARK: Data + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return contacts.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! Cell + let contact = contacts[indexPath.row] + cell.hexEncodedPublicKey = contact + return cell + } + + // MARK: Interaction + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + // TODO: Implement + } +} + +// MARK: - Cell + +private extension NewClosedGroupVC { + + final class Cell : UITableViewCell { + var hexEncodedPublicKey: String = "" { didSet { update() } } + + // MARK: Components + private lazy var profilePictureView = ProfilePictureView() + + private lazy var displayNameLabel: UILabel = { + let result = UILabel() + result.textColor = Colors.text + result.font = .boldSystemFont(ofSize: Values.mediumFontSize) + result.lineBreakMode = .byTruncatingTail + return result + }() + + lazy var separator: UIView = { + let result = UIView() + result.backgroundColor = Colors.separator + result.set(.height, to: Values.separatorThickness) + return result + }() + + // MARK: Initialization + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + setUpViewHierarchy() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + setUpViewHierarchy() + } + + private func setUpViewHierarchy() { + // Set the cell background color + backgroundColor = Colors.cellBackground + // Set up the highlight color + let selectedBackgroundView = UIView() + selectedBackgroundView.backgroundColor = Colors.cellSelected + self.selectedBackgroundView = selectedBackgroundView + // Set up the profile picture image view + let profilePictureViewSize = Values.smallProfilePictureSize + profilePictureView.set(.width, to: profilePictureViewSize) + profilePictureView.set(.height, to: profilePictureViewSize) + profilePictureView.size = profilePictureViewSize + // Set up the main stack view + let stackView = UIStackView(arrangedSubviews: [ profilePictureView, displayNameLabel ]) + stackView.axis = .horizontal + stackView.alignment = .center + stackView.spacing = Values.mediumSpacing + stackView.set(.height, to: profilePictureViewSize) + contentView.addSubview(stackView) + stackView.pin(.leading, to: .leading, of: contentView, withInset: Values.mediumSpacing) + stackView.pin(.top, to: .top, of: contentView, withInset: Values.mediumSpacing) + contentView.pin(.trailing, to: .trailing, of: stackView, withInset: Values.mediumSpacing) + contentView.pin(.bottom, to: .bottom, of: stackView, withInset: Values.mediumSpacing) + stackView.set(.width, to: UIScreen.main.bounds.width - 2 * Values.mediumSpacing) + // Set up the separator + addSubview(separator) + separator.pin(.leading, to: .leading, of: self) + separator.pin(.trailing, to: .trailing, of: self) + separator.pin(.bottom, to: .bottom, of: self) + } + + // MARK: Updating + private func update() { + displayNameLabel.text = DisplayNameUtilities.getPrivateChatDisplayName(for: hexEncodedPublicKey) ?? "Unknown Contact" + profilePictureView.hexEncodedPublicKey = hexEncodedPublicKey + profilePictureView.update() + } + } +}