diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index fe2ab3172..18ff857c2 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -569,6 +569,7 @@ C31A6C5A247F214E001123EF /* UIView+Glow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31A6C59247F214E001123EF /* UIView+Glow.swift */; }; 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 */; }; 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 */; }; @@ -1365,6 +1366,7 @@ C31A6C59247F214E001123EF /* UIView+Glow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Glow.swift"; sourceTree = ""; }; 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 = ""; }; 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 = ""; }; @@ -2683,6 +2685,7 @@ B8CCF638239721E20091D419 /* TabBar.swift */, B8BB82B423947F2D00BA5194 /* TextField.swift */, C3C3CF8824D8EED300E1CCE7 /* TextView.swift */, + C31D1DDC25217014005D4DA8 /* UserCell.swift */, ); path = Components; sourceTree = ""; @@ -3791,6 +3794,7 @@ 340FC8B4204DAC8D007AEB0F /* OWSBackupSettingsViewController.m in Sources */, 34D1F0871F8678AA0066283D /* ConversationViewItem.m in Sources */, 451A13B11E13DED2000A50FD /* AppNotifications.swift in Sources */, + C31D1DDD25217014005D4DA8 /* UserCell.swift in Sources */, 34D99CE4217509C2000AFB39 /* AppEnvironment.swift in Sources */, 348570A820F67575004FF32B /* OWSMessageHeaderView.m in Sources */, 450DF2091E0DD2C6003D14BE /* UserNotificationsAdaptee.swift in Sources */, diff --git a/Signal/src/Loki/Components/UserCell.swift b/Signal/src/Loki/Components/UserCell.swift new file mode 100644 index 000000000..556701744 --- /dev/null +++ b/Signal/src/Loki/Components/UserCell.swift @@ -0,0 +1,94 @@ + +final class UserCell : UITableViewCell { + var accessory = Accessory.none + var publicKey = "" + + // MARK: Accessory + enum Accessory { + case none + case tick(isSelected: Bool) + } + + // 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 + }() + + private lazy var tickImageView: UIImageView = { + let result = UIImageView() + result.contentMode = .scaleAspectFit + let size: CGFloat = 24 + result.set(.width, to: size) + result.set(.height, to: size) + return result + }() + + private 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 = .clear // Disabled for now + 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, tickImageView ]) + stackView.axis = .horizontal + stackView.alignment = .center + stackView.spacing = Values.mediumSpacing + 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 + contentView.addSubview(separator) + separator.pin(.leading, to: .leading, of: contentView) + contentView.pin(.trailing, to: .trailing, of: separator) + separator.pin(.bottom, to: .bottom, of: contentView) + separator.set(.width, to: UIScreen.main.bounds.width) + } + + // MARK: Updating + private func update() { + profilePictureView.hexEncodedPublicKey = publicKey + profilePictureView.update() + displayNameLabel.text = UserDisplayNameUtilities.getPrivateChatDisplayName(for: publicKey) ?? publicKey + switch accessory { + case .none: tickImageView.isHidden = true + case .tick(let isSelected): + tickImageView.isHidden = false + let icon = isSelected ? #imageLiteral(resourceName: "CircleCheck") : #imageLiteral(resourceName: "Circle") + tickImageView.image = isDarkMode ? icon : icon.asTintedImage(color: Colors.text)! + } + } +} diff --git a/Signal/src/Loki/View Controllers/EditClosedGroupVC.swift b/Signal/src/Loki/View Controllers/EditClosedGroupVC.swift index 09dc0b1eb..f8301d700 100644 --- a/Signal/src/Loki/View Controllers/EditClosedGroupVC.swift +++ b/Signal/src/Loki/View Controllers/EditClosedGroupVC.swift @@ -31,7 +31,7 @@ final class EditClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelega let result = UITableView() result.dataSource = self result.delegate = self - result.register(Cell.self, forCellReuseIdentifier: "Cell") + result.register(UserCell.self, forCellReuseIdentifier: "UserCell") result.separatorStyle = .none result.backgroundColor = .clear result.isScrollEnabled = false @@ -127,7 +127,7 @@ final class EditClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelega } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! Cell + let cell = tableView.dequeueReusableCell(withIdentifier: "UserCell") as! UserCell let publicKey = members[indexPath.row] cell.publicKey = publicKey return cell @@ -139,7 +139,7 @@ final class EditClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelega } func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? { - let removeAction = UITableViewRowAction(style: .destructive, title: "Remove") { [weak self] _, _ in + let removeAction = UITableViewRowAction(style: .destructive, title: "Remove") { _, _ in // TODO: Implement } removeAction.backgroundColor = Colors.destructive @@ -189,84 +189,4 @@ final class EditClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelega @objc private func addMembers() { } - - -} - - - -// MARK: - Cell - -private extension EditClosedGroupVC { - - final class Cell : UITableViewCell { - var publicKey = "" { 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 - }() - - private 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 = .clear // Disabled for now - 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 - 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 - contentView.addSubview(separator) - separator.pin(.leading, to: .leading, of: contentView) - contentView.pin(.trailing, to: .trailing, of: separator) - separator.pin(.bottom, to: .bottom, of: contentView) - separator.set(.width, to: UIScreen.main.bounds.width) - } - - // MARK: Updating - private func update() { - profilePictureView.hexEncodedPublicKey = publicKey - profilePictureView.update() - displayNameLabel.text = UserDisplayNameUtilities.getPrivateChatDisplayName(for: publicKey) ?? publicKey - } - } }