mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			215 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Swift
		
	
			
		
		
	
	
			215 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Swift
		
	
| // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
 | |
| 
 | |
| import UIKit
 | |
| import SessionUIKit
 | |
| import SessionUtilitiesKit
 | |
| import SignalUtilitiesKit
 | |
| 
 | |
| final class MentionSelectionView: UIView, UITableViewDataSource, UITableViewDelegate {
 | |
|     var candidates: [MentionInfo] = [] {
 | |
|         didSet {
 | |
|             tableView.isScrollEnabled = (candidates.count > 4)
 | |
|             tableView.reloadData()
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     weak var delegate: MentionSelectionViewDelegate?
 | |
|     
 | |
|     var contentOffset: CGPoint {
 | |
|         get { tableView.contentOffset }
 | |
|         set { tableView.contentOffset = newValue }
 | |
|     }
 | |
| 
 | |
|     // MARK: - Components
 | |
|     
 | |
|     private lazy var tableView: UITableView = {
 | |
|         let result: UITableView = UITableView()
 | |
|         result.dataSource = self
 | |
|         result.delegate = self
 | |
|         result.separatorStyle = .none
 | |
|         result.themeBackgroundColor = .clear
 | |
|         result.showsVerticalScrollIndicator = false
 | |
|         result.register(view: Cell.self)
 | |
|         
 | |
|         return result
 | |
|     }()
 | |
| 
 | |
|     // MARK: - Initialization
 | |
|     
 | |
|     override init(frame: CGRect) {
 | |
|         super.init(frame: frame)
 | |
|         
 | |
|         setUpViewHierarchy()
 | |
|     }
 | |
| 
 | |
|     required init?(coder: NSCoder) {
 | |
|         super.init(coder: coder)
 | |
|         
 | |
|         setUpViewHierarchy()
 | |
|     }
 | |
| 
 | |
|     private func setUpViewHierarchy() {
 | |
|         // Table view
 | |
|         addSubview(tableView)
 | |
|         tableView.pin(to: self)
 | |
|         
 | |
|         // Top separator
 | |
|         let topSeparator: UIView = UIView()
 | |
|         topSeparator.themeBackgroundColor = .borderSeparator
 | |
|         topSeparator.set(.height, to: Values.separatorThickness)
 | |
|         addSubview(topSeparator)
 | |
|         topSeparator.pin(.leading, to: .leading, of: self)
 | |
|         topSeparator.pin(.top, to: .top, of: self)
 | |
|         topSeparator.pin(.trailing, to: .trailing, of: self)
 | |
|         
 | |
|         // Bottom separator
 | |
|         let bottomSeparator: UIView = UIView()
 | |
|         bottomSeparator.themeBackgroundColor = .borderSeparator
 | |
|         bottomSeparator.set(.height, to: Values.separatorThickness)
 | |
|         addSubview(bottomSeparator)
 | |
|         
 | |
|         bottomSeparator.pin(.leading, to: .leading, of: self)
 | |
|         bottomSeparator.pin(.trailing, to: .trailing, of: self)
 | |
|         bottomSeparator.pin(.bottom, to: .bottom, of: self)
 | |
|     }
 | |
| 
 | |
|     // MARK: - Data
 | |
|     
 | |
|     func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
 | |
|         return candidates.count
 | |
|     }
 | |
| 
 | |
|     func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
 | |
|         let cell: Cell = tableView.dequeue(type: Cell.self, for: indexPath)
 | |
|         cell.update(
 | |
|             with: candidates[indexPath.row].profile,
 | |
|             threadVariant: candidates[indexPath.row].threadVariant,
 | |
|             isUserModeratorOrAdmin: OpenGroupManager.isUserModeratorOrAdmin(
 | |
|                 candidates[indexPath.row].profile.id,
 | |
|                 for: candidates[indexPath.row].openGroupRoomToken,
 | |
|                 on: candidates[indexPath.row].openGroupServer
 | |
|             ),
 | |
|             isLast: (indexPath.row == (candidates.count - 1))
 | |
|         )
 | |
|         
 | |
|         return cell
 | |
|     }
 | |
| 
 | |
|     // MARK: - Interaction
 | |
|     
 | |
|     func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
 | |
|         let mentionCandidate = candidates[indexPath.row]
 | |
|         
 | |
|         delegate?.handleMentionSelected(mentionCandidate, from: self)
 | |
|     }
 | |
| }
 | |
| 
 | |
| // MARK: - Cell
 | |
| 
 | |
| private extension MentionSelectionView {
 | |
|     final class Cell: UITableViewCell {
 | |
|         // MARK: - UI
 | |
|         
 | |
|         private lazy var profilePictureView: ProfilePictureView = ProfilePictureView()
 | |
| 
 | |
|         private lazy var moderatorIconImageView: UIImageView = UIImageView(image: #imageLiteral(resourceName: "Crown"))
 | |
| 
 | |
|         private lazy var displayNameLabel: UILabel = {
 | |
|             let result: UILabel = UILabel()
 | |
|             result.font = .systemFont(ofSize: Values.smallFontSize)
 | |
|             result.themeTextColor = .textPrimary
 | |
|             result.lineBreakMode = .byTruncatingTail
 | |
|             
 | |
|             return result
 | |
|         }()
 | |
| 
 | |
|         lazy var separator: UIView = {
 | |
|             let result: UIView = UIView()
 | |
|             result.themeBackgroundColor = .borderSeparator
 | |
|             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() {
 | |
|             // Cell background color
 | |
|             themeBackgroundColor = .settings_tabBackground
 | |
|             
 | |
|             // Highlight color
 | |
|             let selectedBackgroundView = UIView()
 | |
|             selectedBackgroundView.themeBackgroundColor = .highlighted(.settings_tabBackground)
 | |
|             self.selectedBackgroundView = selectedBackgroundView
 | |
|             
 | |
|             // Profile picture image view
 | |
|             let profilePictureViewSize = Values.smallProfilePictureSize
 | |
|             profilePictureView.set(.width, to: profilePictureViewSize)
 | |
|             profilePictureView.set(.height, to: profilePictureViewSize)
 | |
|             profilePictureView.size = profilePictureViewSize
 | |
|             
 | |
|             // Main stack view
 | |
|             let mainStackView = UIStackView(arrangedSubviews: [ profilePictureView, displayNameLabel ])
 | |
|             mainStackView.axis = .horizontal
 | |
|             mainStackView.alignment = .center
 | |
|             mainStackView.spacing = Values.mediumSpacing
 | |
|             mainStackView.set(.height, to: profilePictureViewSize)
 | |
|             contentView.addSubview(mainStackView)
 | |
|             mainStackView.pin(.leading, to: .leading, of: contentView, withInset: Values.mediumSpacing)
 | |
|             mainStackView.pin(.top, to: .top, of: contentView, withInset: Values.smallSpacing)
 | |
|             contentView.pin(.trailing, to: .trailing, of: mainStackView, withInset: Values.mediumSpacing)
 | |
|             contentView.pin(.bottom, to: .bottom, of: mainStackView, withInset: Values.smallSpacing)
 | |
|             mainStackView.set(.width, to: UIScreen.main.bounds.width - 2 * Values.mediumSpacing)
 | |
|             
 | |
|             // Moderator icon image view
 | |
|             moderatorIconImageView.set(.width, to: 20)
 | |
|             moderatorIconImageView.set(.height, to: 20)
 | |
|             contentView.addSubview(moderatorIconImageView)
 | |
|             moderatorIconImageView.pin(.trailing, to: .trailing, of: profilePictureView, withInset: 1)
 | |
|             moderatorIconImageView.pin(.bottom, to: .bottom, of: profilePictureView, withInset: 4.5)
 | |
|             
 | |
|             // 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
 | |
|         
 | |
|         fileprivate func update(
 | |
|             with profile: Profile,
 | |
|             threadVariant: SessionThread.Variant,
 | |
|             isUserModeratorOrAdmin: Bool,
 | |
|             isLast: Bool
 | |
|         ) {
 | |
|             displayNameLabel.text = profile.displayName(for: threadVariant)
 | |
|             profilePictureView.update(
 | |
|                 publicKey: profile.id,
 | |
|                 profile: profile,
 | |
|                 threadVariant: threadVariant
 | |
|             )
 | |
|             moderatorIconImageView.isHidden = !isUserModeratorOrAdmin
 | |
|             separator.isHidden = isLast
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| // MARK: - Delegate
 | |
| 
 | |
| protocol MentionSelectionViewDelegate: AnyObject {
 | |
|     func handleMentionSelected(_ mention: MentionInfo, from view: MentionSelectionView)
 | |
| }
 |