Merge branch 'dev' into ipad-support-1

pull/565/head
Ryan Zhao 3 years ago
commit 04d25577f4

@ -10,6 +10,16 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc
ConversationTitleViewDelegate { ConversationTitleViewDelegate {
func handleTitleViewTapped() { func handleTitleViewTapped() {
// Don't take the user to settings for message requests
guard
let contactThread: TSContactThread = thread as? TSContactThread,
let contact: Contact = Storage.shared.getContact(with: contactThread.contactSessionID()),
contact.isApproved,
contact.didApproveMe
else {
return
}
openSettings() openSettings()
} }
@ -292,32 +302,56 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc
func sendAttachments(_ attachments: [SignalAttachment], with text: String, onComplete: (() -> ())? = nil) { func sendAttachments(_ attachments: [SignalAttachment], with text: String, onComplete: (() -> ())? = nil) {
guard !showBlockedModalIfNeeded() else { return } guard !showBlockedModalIfNeeded() else { return }
for attachment in attachments { for attachment in attachments {
if attachment.hasError { if attachment.hasError {
return showErrorAlert(for: attachment, onDismiss: onComplete) return showErrorAlert(for: attachment, onDismiss: onComplete)
} }
} }
let thread = self.thread let thread = self.thread
let sentTimestamp: UInt64 = NSDate.millisecondTimestamp()
let message = VisibleMessage() let message = VisibleMessage()
message.sentTimestamp = NSDate.millisecondTimestamp() message.sentTimestamp = sentTimestamp
message.text = replaceMentions(in: text) message.text = replaceMentions(in: text)
// Note: 'shouldBeVisible' is set to true the first time a thread is saved so we can
// use it to determine if the user is creating a new thread and update the 'isApproved'
// flags appropriately
let oldThreadShouldBeVisible: Bool = thread.shouldBeVisible
let tsMessage = TSOutgoingMessage.from(message, associatedWith: thread) let tsMessage = TSOutgoingMessage.from(message, associatedWith: thread)
Storage.write(with: { transaction in
tsMessage.save(with: transaction) Storage.write(
// The new message cell is inserted at this point, but the TSOutgoingMessage doesn't have its attachment yet with: { transaction in
}, completion: { [weak self] in tsMessage.save(with: transaction)
Storage.write(with: { transaction in // The new message cell is inserted at this point, but the TSOutgoingMessage doesn't have its attachment yet
MessageSender.send(message, with: attachments, in: thread, using: transaction) },
}, completion: { [weak self] in completion: { [weak self] in
// At this point the TSOutgoingMessage should have its attachments set, so we can scroll to the bottom knowing Storage.shared.write(
// the height of the new message cell with: { transaction in
self?.scrollToBottom(isAnimated: false) self?.approveMessageRequestIfNeeded(
}) for: self?.thread,
self?.handleMessageSent() with: (transaction as! YapDatabaseReadWriteTransaction),
isNewThread: !oldThreadShouldBeVisible,
// Attachment successfully sent - dismiss the screen timestamp: (sentTimestamp - 1) // Set 1ms earlier as this is used for sorting
onComplete?() )
}) },
completion: { [weak self] in
Storage.write(with: { transaction in
MessageSender.send(message, with: attachments, in: thread, using: transaction)
}, completion: { [weak self] in
// At this point the TSOutgoingMessage should have its attachments set, so we can scroll to the bottom knowing
// the height of the new message cell
self?.scrollToBottom(isAnimated: false)
})
self?.handleMessageSent()
// Attachment successfully sent - dismiss the screen
onComplete?()
}
)
}
)
} }
func handleMessageSent() { func handleMessageSent() {

@ -1,5 +1,6 @@
import SessionUIKit import SessionUIKit
import SessionMessagingKit import SessionMessagingKit
import UIKit
// TODO: // TODO:
// Slight paging glitch when scrolling up and loading more content // Slight paging glitch when scrolling up and loading more content
@ -465,30 +466,47 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
// MARK: Updating // MARK: Updating
func updateNavBarButtons() { func updateNavBarButtons() {
navigationItem.hidesBackButton = isShowingSearchUI
if isShowingSearchUI { if isShowingSearchUI {
navigationItem.leftBarButtonItem = nil navigationItem.leftBarButtonItem = nil
navigationItem.rightBarButtonItems = [] navigationItem.rightBarButtonItems = []
} else { }
else {
navigationItem.leftBarButtonItem = UIViewController.createOWSBackButton(withTarget: self, selector: #selector(handleBackPressed)) navigationItem.leftBarButtonItem = UIViewController.createOWSBackButton(withTarget: self, selector: #selector(handleBackPressed))
let rightBarButtonItem: UIBarButtonItem if let contactThread: TSContactThread = thread as? TSContactThread {
if thread is TSContactThread { // Don't show the settings button for message requests
let size = Values.verySmallProfilePictureSize if let contact: Contact = Storage.shared.getContact(with: contactThread.contactSessionID()), contact.isApproved, contact.didApproveMe {
let profilePictureView = ProfilePictureView() let size = Values.verySmallProfilePictureSize
profilePictureView.accessibilityLabel = "Settings button" let profilePictureView = ProfilePictureView()
profilePictureView.size = size profilePictureView.size = size
profilePictureView.update(for: thread) profilePictureView.update(for: thread)
profilePictureView.set(.width, to: size) profilePictureView.set(.width, to: size)
profilePictureView.set(.height, to: size) profilePictureView.set(.height, to: size)
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(openSettings))
profilePictureView.addGestureRecognizer(tapGestureRecognizer) let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(openSettings))
rightBarButtonItem = UIBarButtonItem(customView: profilePictureView) profilePictureView.addGestureRecognizer(tapGestureRecognizer)
} else {
rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "Gear"), style: .plain, target: self, action: #selector(openSettings)) let rightBarButtonItem: UIBarButtonItem = UIBarButtonItem(customView: profilePictureView)
rightBarButtonItem.accessibilityLabel = "Settings button"
rightBarButtonItem.isAccessibilityElement = true
navigationItem.rightBarButtonItem = rightBarButtonItem
}
else {
// Note: Adding an empty button because without it the title alignment is busted (Note: The size was
// taken from the layout inspector for the back button in Xcode
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: UIView(frame: CGRect(x: 0, y: 0, width: 37, height: 44)))
}
}
else {
let rightBarButtonItem: UIBarButtonItem = UIBarButtonItem(image: UIImage(named: "Gear"), style: .plain, target: self, action: #selector(openSettings))
rightBarButtonItem.accessibilityLabel = "Settings button"
rightBarButtonItem.isAccessibilityElement = true
navigationItem.rightBarButtonItem = rightBarButtonItem
} }
rightBarButtonItem.accessibilityLabel = "Settings button"
rightBarButtonItem.isAccessibilityElement = true
navigationItem.rightBarButtonItem = rightBarButtonItem
} }
} }
@ -815,7 +833,6 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
func showSearchUI() { func showSearchUI() {
isShowingSearchUI = true isShowingSearchUI = true
// Search bar // Search bar
// FIXME: This code is duplicated with SearchBar
let searchBar = searchController.uiSearchController.searchBar let searchBar = searchController.uiSearchController.searchBar
searchBar.setUpSessionStyle() searchBar.setUpSessionStyle()

@ -277,7 +277,7 @@ CGFloat kIconViewLength = 24;
contents.title = NSLocalizedString(@"CONVERSATION_SETTINGS", @"title for conversation settings screen"); contents.title = NSLocalizedString(@"CONVERSATION_SETTINGS", @"title for conversation settings screen");
BOOL isNoteToSelf = self.thread.isNoteToSelf; BOOL isNoteToSelf = self.thread.isNoteToSelf;
__weak OWSConversationSettingsViewController *weakSelf = self; __weak OWSConversationSettingsViewController *weakSelf = self;
OWSTableSection *section = [OWSTableSection new]; OWSTableSection *section = [OWSTableSection new];
@ -332,7 +332,7 @@ CGFloat kIconViewLength = 24;
} actionBlock:^{ } actionBlock:^{
[weakSelf tappedConversationSearch]; [weakSelf tappedConversationSearch];
}]]; }]];
// Disappearing messages // Disappearing messages
if (![self isOpenGroup]) { if (![self isOpenGroup]) {
[section addItem:[OWSTableItem itemWithCustomCellBlock:^{ [section addItem:[OWSTableItem itemWithCustomCellBlock:^{
@ -358,13 +358,6 @@ CGFloat kIconViewLength = 24;
switchView.on = strongSelf.disappearingMessagesConfiguration.isEnabled; switchView.on = strongSelf.disappearingMessagesConfiguration.isEnabled;
[switchView addTarget:strongSelf action:@selector(disappearingMessagesSwitchValueDidChange:) [switchView addTarget:strongSelf action:@selector(disappearingMessagesSwitchValueDidChange:)
forControlEvents:UIControlEventValueChanged]; forControlEvents:UIControlEventValueChanged];
// Disable Disappearing Messages if the conversation hasn't been approved
if (!self.thread.isGroupThread) {
TSContactThread *thread = (TSContactThread *)self.thread;
SNContact *contact = [LKStorage.shared getContactWithSessionID:thread.contactSessionID];
[switchView setEnabled:(contact.isApproved && contact.didApproveMe)];
}
UIStackView *topRow = UIStackView *topRow =
[[UIStackView alloc] initWithArrangedSubviews:@[ iconView, rowLabel, switchView ]]; [[UIStackView alloc] initWithArrangedSubviews:@[ iconView, rowLabel, switchView ]];
@ -438,13 +431,6 @@ CGFloat kIconViewLength = 24;
[slider autoPinTrailingToSuperviewMargin]; [slider autoPinTrailingToSuperviewMargin];
[slider autoPinBottomToSuperviewMargin]; [slider autoPinBottomToSuperviewMargin];
// Disable Disappearing Messages slider if the conversation hasn't been approved (just in case)
if (!self.thread.isGroupThread) {
TSContactThread *thread = (TSContactThread *)self.thread;
SNContact *contact = [LKStorage.shared getContactWithSessionID:thread.contactSessionID];
[slider setEnabled:(contact.isApproved && contact.didApproveMe)];
}
cell.userInteractionEnabled = !strongSelf.hasLeftGroup; cell.userInteractionEnabled = !strongSelf.hasLeftGroup;
cell.accessibilityIdentifier = ACCESSIBILITY_IDENTIFIER_WITH_NAME( cell.accessibilityIdentifier = ACCESSIBILITY_IDENTIFIER_WITH_NAME(

@ -73,13 +73,17 @@ final class ConversationTitleView : UIView {
private func getTitle() -> String { private func getTitle() -> String {
if let thread = thread as? TSGroupThread { if let thread = thread as? TSGroupThread {
return thread.groupModel.groupName! return thread.groupModel.groupName!
} else if thread.isNoteToSelf() { }
else if thread.isNoteToSelf() {
return "Note to Self" return "Note to Self"
} else { }
else {
let sessionID = (thread as! TSContactThread).contactSessionID() let sessionID = (thread as! TSContactThread).contactSessionID()
var result = sessionID var result = sessionID
Storage.read { transaction in Storage.read { transaction in
result = Storage.shared.getContact(with: sessionID)?.displayName(for: .regular) ?? "Anonymous" let displayName: String = ((Storage.shared.getContact(with: sessionID)?.displayName(for: .regular)) ?? sessionID)
let middleTruncatedHexKey: String = "\(sessionID.prefix(4))...\(sessionID.suffix(4))"
result = (displayName == sessionID ? middleTruncatedHexKey : displayName)
} }
return result return result
} }

@ -393,11 +393,13 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, NewConv
profilePictureViewContainer.addSubview(pathStatusView) profilePictureViewContainer.addSubview(pathStatusView)
pathStatusView.pin(.trailing, to: .trailing, of: profilePictureViewContainer) pathStatusView.pin(.trailing, to: .trailing, of: profilePictureViewContainer)
pathStatusView.pin(.bottom, to: .bottom, of: profilePictureViewContainer) pathStatusView.pin(.bottom, to: .bottom, of: profilePictureViewContainer)
// Left bar button item // Left bar button item
let leftBarButtonItem = UIBarButtonItem(customView: profilePictureViewContainer) let leftBarButtonItem = UIBarButtonItem(customView: profilePictureViewContainer)
leftBarButtonItem.accessibilityLabel = "Settings button" leftBarButtonItem.accessibilityLabel = "Settings button"
leftBarButtonItem.isAccessibilityElement = true leftBarButtonItem.isAccessibilityElement = true
navigationItem.leftBarButtonItem = leftBarButtonItem navigationItem.leftBarButtonItem = leftBarButtonItem
// Right bar button item - search button // Right bar button item - search button
let rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .search, target: self, action: #selector(showSearchUI)) let rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .search, target: self, action: #selector(showSearchUI))
rightBarButtonItem.accessibilityLabel = "Search button" rightBarButtonItem.accessibilityLabel = "Search button"

@ -63,23 +63,16 @@ class MessageRequestsViewController: BaseVC, UITableViewDelegate, UITableViewDat
return result return result
}() }()
private lazy var clearAllButton: UIButton = { private lazy var clearAllButton: Button = {
let result: UIButton = UIButton() let result: Button = Button(style: .destructiveOutline, size: .large)
result.translatesAutoresizingMaskIntoConstraints = false result.translatesAutoresizingMaskIntoConstraints = false
result.clipsToBounds = true
result.titleLabel?.font = UIFont.boldSystemFont(ofSize: 18)
result.setTitle(NSLocalizedString("MESSAGE_REQUESTS_CLEAR_ALL", comment: ""), for: .normal) result.setTitle(NSLocalizedString("MESSAGE_REQUESTS_CLEAR_ALL", comment: ""), for: .normal)
result.setTitleColor(Colors.destructive, for: .normal)
result.setBackgroundImage( result.setBackgroundImage(
Colors.destructive Colors.destructive
.withAlphaComponent(isDarkMode ? 0.2 : 0.06) .withAlphaComponent(isDarkMode ? 0.2 : 0.06)
.toImage(isDarkMode: isDarkMode), .toImage(isDarkMode: isDarkMode),
for: .highlighted for: .highlighted
) )
result.isHidden = true
result.layer.cornerRadius = (NewConversationButtonSet.collapsedButtonSize / 2)
result.layer.borderColor = Colors.destructive.cgColor
result.layer.borderWidth = 1.5
result.addTarget(self, action: #selector(clearAllTapped), for: .touchUpInside) result.addTarget(self, action: #selector(clearAllTapped), for: .touchUpInside)
return result return result
@ -163,10 +156,11 @@ class MessageRequestsViewController: BaseVC, UITableViewDelegate, UITableViewDat
clearAllButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), clearAllButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
clearAllButton.bottomAnchor.constraint( clearAllButton.bottomAnchor.constraint(
equalTo: view.bottomAnchor, equalTo: view.safeAreaLayoutGuide.bottomAnchor,
constant: -Values.newConversationButtonBottomOffset // Negative due to how the constraint is set up constant: -Values.largeSpacing
), ),
clearAllButton.widthAnchor.constraint(equalToConstant: 155), // Note: The '182' is to match the 'Next' button on the New DM page (which doesn't have a fixed width)
clearAllButton.widthAnchor.constraint(equalToConstant: 182),
clearAllButton.heightAnchor.constraint(equalToConstant: NewConversationButtonSet.collapsedButtonSize) clearAllButton.heightAnchor.constraint(equalToConstant: NewConversationButtonSet.collapsedButtonSize)
]) ])
} }

@ -76,7 +76,7 @@ class MessageRequestsCell: UITableViewCell {
}() }()
private func setUpViewHierarchy() { private func setUpViewHierarchy() {
backgroundColor = Colors.cellBackground backgroundColor = Colors.cellPinned
selectedBackgroundView = UIView() selectedBackgroundView = UIView()
selectedBackgroundView?.backgroundColor = Colors.cellSelected selectedBackgroundView?.backgroundColor = Colors.cellSelected

@ -139,9 +139,6 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate {
setUpNavBarStyle() setUpNavBarStyle()
setNavBarTitle(NSLocalizedString("vc_settings_title", comment: "")) setNavBarTitle(NSLocalizedString("vc_settings_title", comment: ""))
// Navigation bar buttons // Navigation bar buttons
let backButton = UIBarButtonItem(title: "Back", style: .plain, target: nil, action: nil)
backButton.tintColor = Colors.text
navigationItem.backBarButtonItem = backButton
updateNavigationBarButtons() updateNavigationBarButtons()
// Profile picture view // Profile picture view
let profilePictureTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(showEditProfilePictureUI)) let profilePictureTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(showEditProfilePictureUI))
@ -254,8 +251,6 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate {
pathStatusView.pin(.leading, to: .trailing, of: pathButton.titleLabel!, withInset: Values.smallSpacing) pathStatusView.pin(.leading, to: .trailing, of: pathButton.titleLabel!, withInset: Values.smallSpacing)
pathStatusView.autoVCenterInSuperview() pathStatusView.autoVCenterInSuperview()
pathButton.titleEdgeInsets = UIEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: Values.smallSpacing)
return [ return [
getSeparator(), getSeparator(),
pathButton, pathButton,

@ -46,6 +46,7 @@ class BaseVC : UIViewController {
internal func setUpNavBarStyle() { internal func setUpNavBarStyle() {
guard let navigationBar = navigationController?.navigationBar else { return } guard let navigationBar = navigationController?.navigationBar else { return }
if #available(iOS 15.0, *) { if #available(iOS 15.0, *) {
let appearance = UINavigationBarAppearance() let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground() appearance.configureWithOpaqueBackground()
@ -59,6 +60,11 @@ class BaseVC : UIViewController {
navigationBar.isTranslucent = false navigationBar.isTranslucent = false
navigationBar.barTintColor = Colors.navigationBarBackground navigationBar.barTintColor = Colors.navigationBarBackground
} }
// Back button (to appear on pushed screen)
let backButton = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
backButton.tintColor = Colors.text
navigationItem.backBarButtonItem = backButton
} }
internal func setNavBarTitle(_ title: String, customFontSize: CGFloat? = nil) { internal func setNavBarTitle(_ title: String, customFontSize: CGFloat? = nil) {

@ -358,15 +358,20 @@ final class ConversationCell : UITableViewCell {
if threadViewModel.isGroupThread { if threadViewModel.isGroupThread {
if threadViewModel.name.isEmpty { if threadViewModel.name.isEmpty {
return "Unknown Group" return "Unknown Group"
} else { }
else {
return threadViewModel.name return threadViewModel.name
} }
} else { }
else {
if threadViewModel.threadRecord.isNoteToSelf() { if threadViewModel.threadRecord.isNoteToSelf() {
return NSLocalizedString("NOTE_TO_SELF", comment: "") return NSLocalizedString("NOTE_TO_SELF", comment: "")
} else { }
let hexEncodedPublicKey = threadViewModel.contactSessionID! else {
return Storage.shared.getContact(with: hexEncodedPublicKey)?.displayName(for: .regular) ?? hexEncodedPublicKey let hexEncodedPublicKey: String = threadViewModel.contactSessionID!
let displayName: String = (Storage.shared.getContact(with: hexEncodedPublicKey)?.displayName(for: .regular) ?? hexEncodedPublicKey)
let middleTruncatedHexKey: String = "\(hexEncodedPublicKey.prefix(4))...\(hexEncodedPublicKey.suffix(4))"
return (displayName == hexEncodedPublicKey ? middleTruncatedHexKey : displayName)
} }
} }
} }

@ -117,7 +117,8 @@ public final class OpenGroupManagerV2 : NSObject {
// https://143.198.213.225:443/main?public_key=658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231c // https://143.198.213.225:443/main?public_key=658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231c
// 143.198.213.255:80/main?public_key=658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231c // 143.198.213.255:80/main?public_key=658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231c
let useTLS = (url.scheme == "https") let useTLS = (url.scheme == "https")
let room = String(url.path.dropFirst()) // Drop the leading slash let updatedPath = (url.path.starts(with: "/r/") ? url.path.substring(from: 2) : url.path)
let room = String(updatedPath.dropFirst()) // Drop the leading slash
let queryParts = query.split(separator: "=") let queryParts = query.split(separator: "=")
guard !room.isEmpty && !room.contains("/"), queryParts.count == 2, queryParts[0] == "public_key" else { return nil } guard !room.isEmpty && !room.contains("/"), queryParts.count == 2, queryParts[0] == "public_key" else { return nil }
let publicKey = String(queryParts[1]) let publicKey = String(queryParts[1])

@ -6,7 +6,7 @@ public final class Button : UIButton {
private var heightConstraint: NSLayoutConstraint! private var heightConstraint: NSLayoutConstraint!
public enum Style { public enum Style {
case unimportant, regular, prominentOutline, prominentFilled, regularBorderless case unimportant, regular, prominentOutline, prominentFilled, regularBorderless, destructiveOutline
} }
public enum Size { public enum Size {
@ -41,6 +41,7 @@ public final class Button : UIButton {
case .prominentOutline: fillColor = UIColor.clear case .prominentOutline: fillColor = UIColor.clear
case .prominentFilled: fillColor = isLightMode ? Colors.text : Colors.accent case .prominentFilled: fillColor = isLightMode ? Colors.text : Colors.accent
case .regularBorderless: fillColor = UIColor.clear case .regularBorderless: fillColor = UIColor.clear
case .destructiveOutline: fillColor = UIColor.clear
} }
let borderColor: UIColor let borderColor: UIColor
switch style { switch style {
@ -49,6 +50,7 @@ public final class Button : UIButton {
case .prominentOutline: borderColor = isLightMode ? Colors.text : Colors.accent case .prominentOutline: borderColor = isLightMode ? Colors.text : Colors.accent
case .prominentFilled: borderColor = isLightMode ? Colors.text : Colors.accent case .prominentFilled: borderColor = isLightMode ? Colors.text : Colors.accent
case .regularBorderless: borderColor = UIColor.clear case .regularBorderless: borderColor = UIColor.clear
case .destructiveOutline: borderColor = Colors.destructive
} }
let textColor: UIColor let textColor: UIColor
switch style { switch style {
@ -57,6 +59,7 @@ public final class Button : UIButton {
case .prominentOutline: textColor = isLightMode ? Colors.text : Colors.accent case .prominentOutline: textColor = isLightMode ? Colors.text : Colors.accent
case .prominentFilled: textColor = isLightMode ? UIColor.white : Colors.text case .prominentFilled: textColor = isLightMode ? UIColor.white : Colors.text
case .regularBorderless: textColor = Colors.text case .regularBorderless: textColor = Colors.text
case .destructiveOutline: textColor = Colors.destructive
} }
let height: CGFloat let height: CGFloat
switch size { switch size {

@ -28,7 +28,7 @@ public final class ViewControllerUtilities : NSObject {
} }
// Set up back button // Set up back button
if hasCustomBackButton { if hasCustomBackButton {
let backButton = UIBarButtonItem(title: "Back", style: .plain, target: nil, action: nil) let backButton = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
backButton.tintColor = Colors.text backButton.tintColor = Colors.text
vc.navigationItem.backBarButtonItem = backButton vc.navigationItem.backBarButtonItem = backButton
} }

Loading…
Cancel
Save