session-ios/Session/Onboarding/PNModeVC.swift

211 lines
8.5 KiB
Swift
Raw Normal View History

// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit
import Combine
import SessionUIKit
import SessionMessagingKit
import SessionSnodeKit
import SignalUtilitiesKit
final class PNModeVC: BaseVC, OptionViewDelegate {
private let flow: Onboarding.Flow
private var optionViews: [OptionView] {
2020-04-15 06:39:55 +02:00
[ apnsOptionView, backgroundPollingOptionView ]
}
private var selectedOptionView: OptionView? {
return optionViews.first { $0.isSelected }
}
// MARK: - Initialization
init(flow: Onboarding.Flow) {
self.flow = flow
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Components
2020-12-17 01:37:53 +01:00
private lazy var apnsOptionView: OptionView = {
let result: OptionView = OptionView(
2022-10-03 07:01:46 +02:00
title: "fast_mode".localized(),
explanation: "fast_mode_explanation".localized(),
delegate: self,
isRecommended: true
)
2020-12-17 01:37:53 +01:00
result.accessibilityLabel = "Fast mode option"
2020-12-17 01:37:53 +01:00
return result
}()
private lazy var backgroundPollingOptionView: OptionView = {
let result: OptionView = OptionView(
2022-10-03 07:01:46 +02:00
title: "slow_mode".localized(),
explanation: "slow_mode_explanation".localized(),
delegate: self
)
2020-12-17 01:37:53 +01:00
result.accessibilityLabel = "Slow mode option"
2020-12-17 01:37:53 +01:00
return result
}()
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setUpNavBarSessionIcon()
2020-07-29 09:30:15 +02:00
let learnMoreButton = UIBarButtonItem(image: #imageLiteral(resourceName: "ic_info"), style: .plain, target: self, action: #selector(learnMore))
learnMoreButton.themeTintColor = .textPrimary
2020-07-29 09:30:15 +02:00
navigationItem.rightBarButtonItem = learnMoreButton
// Set up title label
let titleLabel = UILabel()
2020-06-18 06:41:02 +02:00
titleLabel.font = .boldSystemFont(ofSize: isIPhone5OrSmaller ? Values.largeFontSize : Values.veryLargeFontSize)
titleLabel.text = "vc_pn_mode_title".localized()
titleLabel.themeTextColor = .textPrimary
titleLabel.lineBreakMode = .byWordWrapping
titleLabel.numberOfLines = 0
// Set up spacers
let topSpacer = UIView.vStretchingSpacer()
let bottomSpacer = UIView.vStretchingSpacer()
let registerButtonBottomOffsetSpacer = UIView()
2020-07-29 09:30:15 +02:00
registerButtonBottomOffsetSpacer.set(.height, to: Values.onboardingButtonBottomOffset)
// Set up register button
let registerButton = SessionButton(style: .filled, size: .large)
registerButton.accessibilityLabel = "Continue with settings"
registerButton.setTitle("continue_2".localized(), for: .normal)
registerButton.addTarget(self, action: #selector(register), for: UIControl.Event.touchUpInside)
// Set up register button container
2022-03-03 04:31:18 +01:00
let registerButtonContainer = UIView(wrapping: registerButton, withInsets: UIEdgeInsets(top: 0, leading: Values.massiveSpacing, bottom: 0, trailing: Values.massiveSpacing), shouldAdaptForIPadWithWidth: Values.iPadButtonWidth)
// Set up options stack view
let optionsStackView = UIStackView(arrangedSubviews: optionViews)
optionsStackView.axis = .vertical
optionsStackView.spacing = Values.smallSpacing
optionsStackView.alignment = .fill
// Set up top stack view
2021-04-29 08:30:39 +02:00
let topStackView = UIStackView(arrangedSubviews: [ titleLabel, UIView.spacer(withHeight: isIPhone6OrSmaller ? Values.mediumSpacing : Values.veryLargeSpacing), optionsStackView ])
topStackView.axis = .vertical
topStackView.alignment = .fill
// Set up top stack view container
let topStackViewContainer = UIView(wrapping: topStackView, withInsets: UIEdgeInsets(top: 0, leading: Values.veryLargeSpacing, bottom: 0, trailing: Values.veryLargeSpacing))
// Set up main stack view
let mainStackView = UIStackView(arrangedSubviews: [ topSpacer, topStackViewContainer, bottomSpacer, registerButtonContainer, registerButtonBottomOffsetSpacer ])
mainStackView.axis = .vertical
mainStackView.alignment = .fill
view.addSubview(mainStackView)
mainStackView.pin(to: view)
topSpacer.heightAnchor.constraint(equalTo: bottomSpacer.heightAnchor, multiplier: 1).isActive = true
2021-04-29 08:30:39 +02:00
// Preselect APNs mode
optionViews[0].isSelected = true
}
// MARK: - Interaction
2020-07-29 09:30:15 +02:00
@objc private func learnMore() {
guard let url: URL = URL(string: "https://getsession.org/faq/#privacy") else { return }
2020-07-29 09:30:15 +02:00
UIApplication.shared.open(url)
}
2020-04-16 05:58:43 +02:00
func optionViewDidActivate(_ optionView: OptionView) {
optionViews.filter { $0 != optionView }.forEach { $0.isSelected = false }
}
@objc private func register() {
guard selectedOptionView != nil else {
let modal: ConfirmationModal = ConfirmationModal(
targetView: self.view,
info: ConfirmationModal.Info(
title: "vc_pn_mode_no_option_picked_modal_title".localized(),
cancelTitle: "BUTTON_OK".localized(),
cancelStyle: .alert_text
)
)
self.present(modal, animated: true)
return
}
2020-04-14 08:32:10 +02:00
UserDefaults.standard[.isUsingFullAPNs] = (selectedOptionView == apnsOptionView)
// If we are registering then we can just continue on
guard flow != .register else {
self.flow.completeRegistration()
// Go to the home screen
let homeVC: HomeVC = HomeVC()
self.navigationController?.setViewControllers([ homeVC ], animated: true)
return
}
// Check if we already have a profile name (ie. profile retrieval completed while waiting on
// this screen)
let existingProfileName: String? = Storage.shared
.read { db in
try Profile
.filter(id: getUserHexEncodedPublicKey(db))
.select(.name)
.asRequest(of: String.self)
.fetchOne(db)
}
guard existingProfileName?.isEmpty != false else {
// If we have one then we can go straight to the home screen
self.flow.completeRegistration()
// Go to the home screen
let homeVC: HomeVC = HomeVC()
self.navigationController?.setViewControllers([ homeVC ], animated: true)
return
}
// If we don't have one then show a loading indicator and try to retrieve the existing name
ModalActivityIndicatorViewController.present(fromViewController: self) { [weak self, flow = self.flow] viewController in
Onboarding.profileNamePublisher
Fixed a number of issues found during internal testing Added copy for an unrecoverable startup case Added some additional logs to better debug ValueObservation query errors Increased the pageSize to 20 on iPad devices (to prevent it immediately loading a second page) Cleaned up a bunch of threading logic (try to avoid overriding subscribe/receive threads specified at subscription) Consolidated the 'sendMessage' and 'sendAttachments' functions Updated the various frameworks to use 'DAWRF with DSYM' to allow for better debugging during debug mode (at the cost of a longer build time) Updated the logic to optimistically insert messages when sending to avoid any database write delays Updated the logic to avoid sending notifications for messages which are already marked as read by the config Fixed an issue where multiple paths could incorrectly get built at the same time in some cases Fixed an issue where other job queues could be started before the blockingQueue finishes Fixed a potential bug with the snode version comparison (was just a string comparison which would fail when getting to double-digit values) Fixed a bug where you couldn't remove the last reaction on a message Fixed the broken media message zoom animations Fixed a bug where the last message read in a conversation wouldn't be correctly detected as already read Fixed a bug where the QuoteView had no line limits (resulting in the '@You' mention background highlight being incorrectly positioned in the quote preview) Fixed a bug where a large number of configSyncJobs could be scheduled (only one would run at a time but this could result in performance impacts)
2023-06-23 09:54:29 +02:00
.subscribe(on: DispatchQueue.global(qos: .userInitiated))
.timeout(.seconds(15), scheduler: DispatchQueue.main, customError: { HTTPError.timeout })
.catch { _ -> AnyPublisher<String?, Error> in
SNLog("Onboarding failed to retrieve existing profile information")
return Just(nil)
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
}
.receive(on: DispatchQueue.main)
.sinkUntilComplete(
receiveValue: { value in
// Hide the loading indicator
viewController.dismiss(animated: true)
// If we have no display name we need to collect one
guard value?.isEmpty == false else {
let displayNameVC: DisplayNameVC = DisplayNameVC(flow: flow)
self?.navigationController?.pushViewController(displayNameVC, animated: true)
return
}
// Otherwise we are done and can go to the home screen
self?.flow.completeRegistration()
// Go to the home screen
let homeVC: HomeVC = HomeVC()
self?.navigationController?.setViewControllers([ homeVC ], animated: true)
}
)
}
}
}