diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 8313d2e5e..39fced246 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -110,6 +110,7 @@ 9E44C7202967AD17004B2A72 /* MastodonSDKDynamic in Frameworks */ = {isa = PBXBuildFile; productRef = 9E44C71F2967AD17004B2A72 /* MastodonSDKDynamic */; }; 9E44C7222967AD17004B2A72 /* MastodonSDKDynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 9E44C71F2967AD17004B2A72 /* MastodonSDKDynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; C24C97032922F30500BAE8CB /* RefreshControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = C24C97022922F30500BAE8CB /* RefreshControl.swift */; }; + D8363B1629469CE200A74079 /* OnboardingNextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8363B1529469CE200A74079 /* OnboardingNextView.swift */; }; D87BFC8B291D5C6B00FEE264 /* MastodonLoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D87BFC8A291D5C6B00FEE264 /* MastodonLoginView.swift */; }; D87BFC8D291EB81200FEE264 /* MastodonLoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D87BFC8C291EB81200FEE264 /* MastodonLoginViewModel.swift */; }; D87BFC8F291EC26A00FEE264 /* MastodonLoginServerTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D87BFC8E291EC26A00FEE264 /* MastodonLoginServerTableViewCell.swift */; }; @@ -658,6 +659,7 @@ C3789232A52F43529CA67E95 /* Pods-MastodonIntent.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonIntent.asdk - debug.xcconfig"; path = "Target Support Files/Pods-MastodonIntent/Pods-MastodonIntent.asdk - debug.xcconfig"; sourceTree = ""; }; CD92E0F10BDE4FE7C4B999F2 /* Pods_MastodonTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MastodonTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D7D7CF93E262178800077512 /* Pods-Mastodon-AppShared.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-AppShared.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-AppShared/Pods-Mastodon-AppShared.debug.xcconfig"; sourceTree = ""; }; + D8363B1529469CE200A74079 /* OnboardingNextView.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = OnboardingNextView.swift; sourceTree = ""; tabWidth = 4; }; D87BFC8A291D5C6B00FEE264 /* MastodonLoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLoginView.swift; sourceTree = ""; }; D87BFC8C291EB81200FEE264 /* MastodonLoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLoginViewModel.swift; sourceTree = ""; }; D87BFC8E291EC26A00FEE264 /* MastodonLoginServerTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLoginServerTableViewCell.swift; sourceTree = ""; }; @@ -1217,6 +1219,7 @@ 0FB3D30D25E525C000AAD544 /* View */ = { isa = PBXGroup; children = ( + D8363B1529469CE200A74079 /* OnboardingNextView.swift */, 0FB3D30E25E525CD00AAD544 /* PickServerCategoryView.swift */, DB9282B125F3222800823B15 /* PickServerEmptyStateView.swift */, DB0617F0278413D00030EE79 /* PickServerServerSectionTableHeaderView.swift */, @@ -3604,6 +3607,7 @@ 2A3F6FE5292F6E44002E6DA7 /* FollowedTagsTableViewCell.swift in Sources */, C24C97032922F30500BAE8CB /* RefreshControl.swift in Sources */, DB023D2A27A0FE5C005AC798 /* DataSourceProvider+NotificationTableViewCellDelegate.swift in Sources */, + D8363B1629469CE200A74079 /* OnboardingNextView.swift in Sources */, DB98EB6027B10E150082E365 /* ReportCommentTableViewCell.swift in Sources */, DB0FCB962797E6C2006C02E2 /* SearchResultViewController+DataSourceProvider.swift in Sources */, DB6180E326391A4C0018D199 /* ViewControllerAnimatedTransitioning.swift in Sources */, diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift index bcb040757..7f88cc2f9 100644 --- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift +++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift @@ -46,20 +46,15 @@ final class MastodonPickServerViewController: UIViewController, NeedsDependency tableView.sectionHeaderTopPadding = .leastNonzeroMagnitude return tableView }() - - let navigationActionView: NavigationActionView = { - let navigationActionView = NavigationActionView() - navigationActionView.backgroundColor = Asset.Scene.Onboarding.background.color - return navigationActionView + + let onboardingNextView: OnboardingNextView = { + let onboardingNextView = OnboardingNextView() + onboardingNextView.translatesAutoresizingMaskIntoConstraints = false + onboardingNextView.backgroundColor = UIColor.secondarySystemBackground + return onboardingNextView }() var mastodonAuthenticationController: MastodonAuthenticationController? - - deinit { - tableViewObservation = nil - os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) - } - } extension MastodonPickServerViewController { @@ -72,17 +67,6 @@ extension MastodonPickServerViewController { setupOnboardingAppearance() defer { setupNavigationBarBackgroundView() } - #if DEBUG - navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "ellipsis.circle"), style: .plain, target: nil, action: nil) - let children: [UIMenuElement] = [ - UIAction(title: "Dismiss", image: nil, identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off, handler: { [weak self] _ in - guard let self = self else { return } - self.dismiss(animated: true, completion: nil) - }) - ] - navigationItem.rightBarButtonItem?.menu = UIMenu(title: "Debug Tool", image: nil, identifier: nil, options: [], children: children) - #endif - tableView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(tableView) NSLayoutConstraint.activate([ @@ -92,37 +76,22 @@ extension MastodonPickServerViewController { tableView.bottomAnchor.constraint(equalTo: view.layoutMarginsGuide.bottomAnchor), ]) - navigationActionView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(navigationActionView) - defer { - view.bringSubviewToFront(navigationActionView) - } + view.addSubview(onboardingNextView) + NSLayoutConstraint.activate([ - navigationActionView.leadingAnchor.constraint(equalTo: view.leadingAnchor), - navigationActionView.trailingAnchor.constraint(equalTo: view.trailingAnchor), - view.bottomAnchor.constraint(equalTo: navigationActionView.bottomAnchor), + onboardingNextView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + onboardingNextView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + view.bottomAnchor.constraint(equalTo: onboardingNextView.bottomAnchor), ]) - navigationActionView + onboardingNextView .observe(\.bounds, options: [.initial, .new]) { [weak self] _, _ in guard let self = self else { return } - let inset = self.navigationActionView.frame.height + let inset = self.onboardingNextView.frame.height self.viewModel.additionalTableViewInsets.bottom = inset } .store(in: &observations) - // fix AutoLayout warning when observe before view appear - viewModel.viewWillAppear - .receive(on: DispatchQueue.main) - .sink { [weak self] in - guard let self = self else { return } - self.tableViewObservation = self.tableView.observe(\.contentSize, options: [.initial, .new]) { [weak self] tableView, _ in - guard let self = self else { return } - self.updateEmptyStateViewLayout() - } - } - .store(in: &disposeBag) - emptyStateView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(emptyStateView) emptyStateViewLeadingLayoutConstraint = emptyStateView.leadingAnchor.constraint(equalTo: tableView.leadingAnchor) @@ -131,7 +100,7 @@ extension MastodonPickServerViewController { emptyStateView.topAnchor.constraint(equalTo: view.topAnchor), emptyStateViewLeadingLayoutConstraint, emptyStateViewTrailingLayoutConstraint, - navigationActionView.topAnchor.constraint(equalTo: emptyStateView.bottomAnchor, constant: 21), + onboardingNextView.topAnchor.constraint(equalTo: emptyStateView.bottomAnchor, constant: 21), ]) view.sendSubviewToBack(emptyStateView) @@ -153,7 +122,7 @@ extension MastodonPickServerViewController { viewModel .selectedServer .map { $0 != nil } - .assign(to: \.isEnabled, on: navigationActionView.nextButton) + .assign(to: \.isEnabled, on: onboardingNextView.nextButton) .store(in: &disposeBag) Publishers.Merge( @@ -203,7 +172,7 @@ extension MastodonPickServerViewController { .receive(on: DispatchQueue.main) .sink { [weak self] isAuthenticating in guard let self = self else { return } - isAuthenticating ? self.navigationActionView.nextButton.showLoading() : self.navigationActionView.nextButton.stopLoading() +// isAuthenticating ? self.navigationActionView.nextButton.showLoading() : self.navigationActionView.nextButton.stopLoading() } .store(in: &disposeBag) @@ -234,7 +203,7 @@ extension MastodonPickServerViewController { } .store(in: &disposeBag) - navigationActionView.nextButton.addTarget(self, action: #selector(MastodonPickServerViewController.nextButtonDidPressed(_:)), for: .touchUpInside) + onboardingNextView.nextButton.addTarget(self, action: #selector(MastodonPickServerViewController.nextButtonDidPressed(_:)), for: .touchUpInside) } override func viewWillAppear(_ animated: Bool) { @@ -253,7 +222,6 @@ extension MastodonPickServerViewController { super.traitCollectionDidChange(previousTraitCollection) setupNavigationBarAppearance() - updateEmptyStateViewLayout() } } @@ -407,26 +375,6 @@ extension MastodonPickServerViewController: UITableViewDelegate { } -extension MastodonPickServerViewController { - private func updateEmptyStateViewLayout() { -// guard let diffableDataSource = self.viewModel.diffableDataSource else { return } -// guard let indexPath = diffableDataSource.indexPath(for: .search) else { return } -// let rectInTableView = tableView.rectForRow(at: indexPath) -// -// emptyStateView.topPaddingViewTopLayoutConstraint.constant = rectInTableView.maxY -// -// switch traitCollection.horizontalSizeClass { -// case .regular: -// emptyStateViewLeadingLayoutConstraint.constant = MastodonPickServerViewController.viewEdgeMargin -// emptyStateViewTrailingLayoutConstraint.constant = MastodonPickServerViewController.viewEdgeMargin -// default: -// let margin = tableView.layoutMarginsGuide.layoutFrame.origin.x -// emptyStateViewLeadingLayoutConstraint.constant = margin -// emptyStateViewTrailingLayoutConstraint.constant = margin -// } - } -} - // MARK: - PickServerServerSectionTableHeaderViewDelegate extension MastodonPickServerViewController: PickServerServerSectionTableHeaderViewDelegate { func pickServerServerSectionTableHeaderView(_ headerView: PickServerServerSectionTableHeaderView, collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { diff --git a/Mastodon/Scene/Onboarding/PickServer/View/OnboardingNextView.swift b/Mastodon/Scene/Onboarding/PickServer/View/OnboardingNextView.swift new file mode 100644 index 000000000..e629c3466 --- /dev/null +++ b/Mastodon/Scene/Onboarding/PickServer/View/OnboardingNextView.swift @@ -0,0 +1,79 @@ +// +// OnboardingNextView.swift +// Mastodon +// +// Created by Nathan Mattes on 2022-12-12. +// + +import UIKit +import MastodonUI +import MastodonAsset +import MastodonLocalization + +final class OnboardingNextView: UIView { + + static let buttonHeight: CGFloat = 50 + static let minimumBackButtonWidth: CGFloat = 100 + + private var observations = Set() + + private let container: UIStackView = { + let stackView = UIStackView() + stackView.axis = .vertical + stackView.spacing = 8 + stackView.alignment = .center + return stackView + }() + + //TODO: Show loading + let nextButton: UIButton = { + let button = UIButton() + button.translatesAutoresizingMaskIntoConstraints = false + button.layer.cornerRadius = 14 + button.backgroundColor = Asset.Colors.brand.color + button.setTitle(L10n.Common.Controls.Actions.next, for: .normal) + return button + }() + + let explanationLabel: UILabel = { + let label = UILabel() + label.numberOfLines = 0 + label.textColor = .secondaryLabel + label.font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .regular)) + label.text = "We’ll pick a server based on your language if you continue without making a selection." //TODO: @zeitschlag localize + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + + private func _init() { + container.translatesAutoresizingMaskIntoConstraints = false + container.addArrangedSubview(nextButton) + container.addArrangedSubview(explanationLabel) + + addSubview(container) + + NSLayoutConstraint.activate([ + container.topAnchor.constraint(equalTo: topAnchor, constant: 16), + container.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16), + trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: 16), + safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: 16), + + nextButton.widthAnchor.constraint(equalTo: container.widthAnchor), + explanationLabel.widthAnchor.constraint(equalTo: container.widthAnchor), + ]) + + NSLayoutConstraint.activate([ + nextButton.heightAnchor.constraint(greaterThanOrEqualToConstant: NavigationActionView.buttonHeight) + ]) + } +} +