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.
254 lines
9.7 KiB
Swift
254 lines
9.7 KiB
Swift
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
|
|
|
import UIKit
|
|
import GRDB
|
|
import PromiseKit
|
|
import SessionUIKit
|
|
import SessionMessagingKit
|
|
|
|
final class NewConversationVC: BaseVC, UITableViewDelegate, UITableViewDataSource {
|
|
private let newConversationViewModel = NewConversationViewModel()
|
|
private var groupedContacts: OrderedDictionary<String, [Profile]> = OrderedDictionary()
|
|
|
|
// MARK: - UI
|
|
|
|
private lazy var newDMButton: NewConversationButton = NewConversationButton(icon: #imageLiteral(resourceName: "Message"), title: "vc_create_private_chat_title".localized())
|
|
private lazy var newGroupButton: NewConversationButton = NewConversationButton(icon: #imageLiteral(resourceName: "Group"), title: "vc_create_closed_group_title".localized())
|
|
private lazy var joinCommunityButton: NewConversationButton = NewConversationButton(icon: #imageLiteral(resourceName: "Globe"), title: "vc_join_public_chat_title".localized(), shouldShowSeparator: false)
|
|
|
|
private lazy var buttonStackView: UIStackView = {
|
|
let lineTop = UIView()
|
|
lineTop.set(.height, to: 0.5)
|
|
lineTop.backgroundColor = Colors.border.withAlphaComponent(0.3)
|
|
|
|
let lineBottom = UIView()
|
|
lineBottom.set(.height, to: 0.5)
|
|
lineBottom.backgroundColor = Colors.border.withAlphaComponent(0.3)
|
|
|
|
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
|
|
tapGestureRecognizer.numberOfTapsRequired = 1
|
|
|
|
let result = UIStackView(
|
|
arrangedSubviews: [
|
|
lineTop,
|
|
newDMButton,
|
|
newGroupButton,
|
|
joinCommunityButton,
|
|
lineBottom
|
|
]
|
|
)
|
|
result.axis = .vertical
|
|
result.addGestureRecognizer(tapGestureRecognizer)
|
|
return result
|
|
}()
|
|
|
|
private lazy var buttonStackViewContainer = UIView(wrapping: buttonStackView, withInsets: .zero)
|
|
|
|
private lazy var contactsTitleLabel: UILabel = {
|
|
let result = UILabel()
|
|
result.textColor = Colors.text
|
|
result.text = "Contacts"
|
|
result.font = .systemFont(ofSize: Values.mediumFontSize)
|
|
return result
|
|
}()
|
|
|
|
private lazy var contactsTableView: UITableView = {
|
|
let result = UITableView()
|
|
result.delegate = self
|
|
result.dataSource = self
|
|
result.separatorStyle = .none
|
|
result.backgroundColor = .clear
|
|
if #available(iOS 15.0, *) {
|
|
result.sectionHeaderTopPadding = 0
|
|
}
|
|
result.register(view: UserCell.self)
|
|
|
|
return result
|
|
}()
|
|
|
|
// MARK: - Lifecycle
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
setUpNavBarStyle()
|
|
setNavBarTitle(NSLocalizedString("vc_new_conversation_title", comment: ""))
|
|
// Set up navigation bar buttons
|
|
let closeButton = UIBarButtonItem(image: #imageLiteral(resourceName: "X"), style: .plain, target: self, action: #selector(close))
|
|
closeButton.tintColor = Colors.text
|
|
navigationItem.leftBarButtonItem = closeButton
|
|
setUpViewHierarchy()
|
|
}
|
|
|
|
private func setUpViewHierarchy() {
|
|
buttonStackViewContainer.backgroundColor = Colors.cellBackground
|
|
|
|
let headerView = UIView(
|
|
frame: CGRect(
|
|
x: 0, y: 0,
|
|
width: UIScreen.main.bounds.width,
|
|
height: NewConversationButton.height * 3 + Values.smallSpacing * 2 + Values.mediumFontSize
|
|
)
|
|
)
|
|
headerView.addSubview(buttonStackViewContainer)
|
|
buttonStackViewContainer.pin([ UIView.HorizontalEdge.leading, UIView.HorizontalEdge.trailing, UIView.VerticalEdge.top ], to: headerView)
|
|
headerView.addSubview(contactsTitleLabel)
|
|
contactsTitleLabel.pin(.leading, to: .leading, of: headerView, withInset: Values.mediumSpacing)
|
|
contactsTitleLabel.pin(.top, to: .bottom, of: buttonStackViewContainer, withInset: Values.smallSpacing)
|
|
|
|
contactsTableView.tableHeaderView = headerView
|
|
view.addSubview(contactsTableView)
|
|
contactsTableView.pin(to: view)
|
|
}
|
|
|
|
// MARK: - UITableViewDataSource
|
|
|
|
func numberOfSections(in tableView: UITableView) -> Int {
|
|
return newConversationViewModel.sectionData.count
|
|
}
|
|
|
|
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
|
return newConversationViewModel.sectionData[section].contacts.count
|
|
}
|
|
|
|
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
|
let cell: UserCell = tableView.dequeue(type: UserCell.self, for: indexPath)
|
|
let profile = newConversationViewModel.sectionData[indexPath.section].contacts[indexPath.row]
|
|
cell.update(
|
|
with: profile.id,
|
|
profile: profile,
|
|
isZombie: false,
|
|
accessory: .none
|
|
)
|
|
return cell
|
|
}
|
|
|
|
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
|
let label = UILabel()
|
|
label.textColor = Colors.sessionMessageRequestsInfoText
|
|
label.font = .systemFont(ofSize: Values.smallFontSize)
|
|
label.text = newConversationViewModel.sectionData[section].sectionName
|
|
let headerView = UIView()
|
|
headerView.backgroundColor = self.view.backgroundColor
|
|
headerView.addSubview(label)
|
|
label.pin(.left, to: .left, of: headerView, withInset: Values.mediumSpacing)
|
|
label.pin(.top, to: .top, of: headerView, withInset: Values.verySmallSpacing)
|
|
label.pin(.bottom, to: .bottom, of: headerView, withInset: -Values.verySmallSpacing)
|
|
return headerView
|
|
}
|
|
|
|
// MARK: - UITableViewDelegate
|
|
|
|
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
|
tableView.deselectRow(at: indexPath, animated: true)
|
|
let sessionId = newConversationViewModel.sectionData[indexPath.section].contacts[indexPath.row].id
|
|
let maybeThread: SessionThread? = Storage.shared.write { db in
|
|
try SessionThread.fetchOrCreate(db, id: sessionId, variant: .contact)
|
|
}
|
|
|
|
guard maybeThread != nil else { return }
|
|
|
|
self.navigationController?.dismiss(animated: true, completion: nil)
|
|
|
|
SessionApp.presentConversation(for: sessionId, action: .compose, animated: false)
|
|
}
|
|
|
|
// MARK: - Interaction
|
|
|
|
@objc private func handleTap(_ gestureRecognizer: UITapGestureRecognizer) {
|
|
let location = gestureRecognizer.location(in: self.view)
|
|
if newDMButton.frame.contains(location) {
|
|
createNewDM()
|
|
}
|
|
else if newGroupButton.frame.contains(location) {
|
|
createClosedGroup()
|
|
}
|
|
else if joinCommunityButton.frame.contains(location) {
|
|
joinOpenGroup()
|
|
}
|
|
}
|
|
|
|
@objc private func close() {
|
|
dismiss(animated: true, completion: nil)
|
|
}
|
|
|
|
@objc func createNewDM() {
|
|
let newDMVC = NewDMVC()
|
|
self.navigationController?.pushViewController(newDMVC, animated: true)
|
|
}
|
|
|
|
@objc func createClosedGroup() {
|
|
let newClosedGroupVC = NewClosedGroupVC()
|
|
self.navigationController?.pushViewController(newClosedGroupVC, animated: true)
|
|
}
|
|
|
|
@objc func joinOpenGroup() {
|
|
let joinOpenGroupVC: JoinOpenGroupVC = JoinOpenGroupVC()
|
|
self.navigationController?.pushViewController(joinOpenGroupVC, animated: true)
|
|
}
|
|
}
|
|
|
|
// MARK: NewConversationButton
|
|
|
|
private final class NewConversationButton: UIView {
|
|
private let icon: UIImage
|
|
private let title: String
|
|
private let shouldShowSeparator: Bool
|
|
|
|
public static let height: CGFloat = 56
|
|
private static let iconSize: CGFloat = 38
|
|
|
|
init(icon: UIImage, title: String, shouldShowSeparator: Bool = true) {
|
|
self.icon = icon.withRenderingMode(.alwaysTemplate)
|
|
self.title = title
|
|
self.shouldShowSeparator = shouldShowSeparator
|
|
super.init(frame: .zero)
|
|
setUpViewHierarchy()
|
|
}
|
|
|
|
override init(frame: CGRect) {
|
|
preconditionFailure("Use init(icon:title:) instead.")
|
|
}
|
|
|
|
required init?(coder: NSCoder) {
|
|
preconditionFailure("Use init(icon:title:) instead.")
|
|
}
|
|
|
|
private func setUpViewHierarchy() {
|
|
let iconImageView = UIImageView(image: self.icon)
|
|
iconImageView.contentMode = .center
|
|
iconImageView.tintColor = Colors.text
|
|
iconImageView.set(.width, to: Self.iconSize)
|
|
|
|
let titleLable = UILabel()
|
|
titleLable.text = self.title
|
|
titleLable.textColor = Colors.text
|
|
titleLable.font = .systemFont(ofSize: Values.mediumFontSize)
|
|
|
|
let stackView = UIStackView(
|
|
arrangedSubviews: [
|
|
iconImageView,
|
|
UIView.hSpacer(Values.mediumSpacing),
|
|
titleLable,
|
|
UIView.hStretchingSpacer()
|
|
]
|
|
)
|
|
stackView.axis = .horizontal
|
|
stackView.alignment = .center
|
|
stackView.isLayoutMarginsRelativeArrangement = true
|
|
stackView.layoutMargins = UIEdgeInsets(uniform: Values.mediumSpacing)
|
|
addSubview(stackView)
|
|
stackView.pin(to: self)
|
|
stackView.set(.width, to: UIScreen.main.bounds.width)
|
|
stackView.set(.height, to: Self.height)
|
|
|
|
let line = UIView()
|
|
line.set(.height, to: 0.5)
|
|
line.backgroundColor = Colors.border.withAlphaComponent(0.3)
|
|
addSubview(line)
|
|
line.pin([ UIView.VerticalEdge.bottom, UIView.HorizontalEdge.trailing ], to: self)
|
|
line.pin(.leading, to: .leading, of: self, withInset: (Self.iconSize + 2 * Values.mediumSpacing))
|
|
|
|
line.isHidden = !shouldShowSeparator
|
|
}
|
|
}
|