chore: update onboarding layout for iPad

This commit is contained in:
CMK 2021-10-08 18:10:06 +08:00
parent bcf0262608
commit 6b1d3f8738
15 changed files with 448 additions and 116 deletions

View File

@ -7,12 +7,12 @@
<key>AppShared.xcscheme_^#shared#^_</key> <key>AppShared.xcscheme_^#shared#^_</key>
<dict> <dict>
<key>orderHint</key> <key>orderHint</key>
<integer>56</integer> <integer>35</integer>
</dict> </dict>
<key>CoreDataStack.xcscheme_^#shared#^_</key> <key>CoreDataStack.xcscheme_^#shared#^_</key>
<dict> <dict>
<key>orderHint</key> <key>orderHint</key>
<integer>54</integer> <integer>38</integer>
</dict> </dict>
<key>Mastodon - ASDK.xcscheme_^#shared#^_</key> <key>Mastodon - ASDK.xcscheme_^#shared#^_</key>
<dict> <dict>
@ -97,7 +97,7 @@
<key>MastodonIntent.xcscheme_^#shared#^_</key> <key>MastodonIntent.xcscheme_^#shared#^_</key>
<dict> <dict>
<key>orderHint</key> <key>orderHint</key>
<integer>51</integer> <integer>36</integer>
</dict> </dict>
<key>MastodonIntents.xcscheme_^#shared#^_</key> <key>MastodonIntents.xcscheme_^#shared#^_</key>
<dict> <dict>
@ -117,7 +117,7 @@
<key>ShareActionExtension.xcscheme_^#shared#^_</key> <key>ShareActionExtension.xcscheme_^#shared#^_</key>
<dict> <dict>
<key>orderHint</key> <key>orderHint</key>
<integer>55</integer> <integer>37</integer>
</dict> </dict>
</dict> </dict>
<key>SuppressBuildableAutocreation</key> <key>SuppressBuildableAutocreation</key>

View File

@ -214,7 +214,13 @@ extension SceneCoordinator {
assertionFailure() assertionFailure()
return nil return nil
} }
presentingViewController.presentPanModal(panModalPresentable)
// https://github.com/slackhq/PanModal/issues/74#issuecomment-572426441
panModalPresentable.modalPresentationStyle = .custom
panModalPresentable.modalPresentationCapturesStatusBarAppearance = true
panModalPresentable.transitioningDelegate = PanModalPresentationDelegate.default
presentingViewController.present(panModalPresentable, animated: true, completion: nil)
//presentingViewController.presentPanModal(panModalPresentable)
case .custom(let transitioningDelegate): case .custom(let transitioningDelegate):
viewController.modalPresentationStyle = .custom viewController.modalPresentationStyle = .custom

View File

@ -20,6 +20,8 @@ final class MastodonConfirmEmailViewController: UIViewController, NeedsDependenc
var viewModel: MastodonConfirmEmailViewModel! var viewModel: MastodonConfirmEmailViewModel!
let stackView = UIStackView()
let largeTitleLabel: UILabel = { let largeTitleLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.font = UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: UIFont.systemFont(ofSize: 34, weight: .bold)) label.font = UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: UIFont.systemFont(ofSize: 34, weight: .bold))
@ -72,9 +74,10 @@ extension MastodonConfirmEmailViewController {
override func viewDidLoad() { override func viewDidLoad() {
setupOnboardingAppearance() setupOnboardingAppearance()
configureTitleLabel()
configureMargin()
// stackView // stackView
let stackView = UIStackView()
stackView.axis = .vertical stackView.axis = .vertical
stackView.distribution = .fill stackView.distribution = .fill
stackView.spacing = 10 stackView.spacing = 10
@ -92,8 +95,8 @@ extension MastodonConfirmEmailViewController {
stackView.translatesAutoresizingMaskIntoConstraints = false stackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: view.readableContentGuide.topAnchor), stackView.topAnchor.constraint(equalTo: view.readableContentGuide.topAnchor),
stackView.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor), stackView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: view.readableContentGuide.trailingAnchor), stackView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor),
stackView.bottomAnchor.constraint(equalTo: view.readableContentGuide.bottomAnchor), stackView.bottomAnchor.constraint(equalTo: view.readableContentGuide.bottomAnchor),
]) ])
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
@ -139,6 +142,38 @@ extension MastodonConfirmEmailViewController {
.store(in: &self.disposeBag) .store(in: &self.disposeBag)
} }
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
configureTitleLabel()
configureMargin()
}
}
extension MastodonConfirmEmailViewController {
private func configureTitleLabel() {
switch traitCollection.horizontalSizeClass {
case .regular:
navigationItem.largeTitleDisplayMode = .always
navigationItem.title = L10n.Scene.ConfirmEmail.title.replacingOccurrences(of: "\n", with: " ")
largeTitleLabel.isHidden = true
default:
navigationItem.largeTitleDisplayMode = .never
navigationItem.title = nil
largeTitleLabel.isHidden = false
}
}
private func configureMargin() {
switch traitCollection.horizontalSizeClass {
case .regular:
let margin = MastodonConfirmEmailViewController.viewEdgeMargin
stackView.layoutMargins = UIEdgeInsets(top: 18, left: margin, bottom: 23, right: margin)
default:
stackView.layoutMargins = UIEdgeInsets(top: 10, left: 0, bottom: 23, right: 0)
}
}
} }
extension MastodonConfirmEmailViewController { extension MastodonConfirmEmailViewController {

View File

@ -29,6 +29,8 @@ final class MastodonPickServerViewController: UIViewController, NeedsDependency
private var expandServerDomainSet = Set<String>() private var expandServerDomainSet = Set<String>()
private let emptyStateView = PickServerEmptyStateView() private let emptyStateView = PickServerEmptyStateView()
private var emptyStateViewLeadingLayoutConstraint: NSLayoutConstraint!
private var emptyStateViewTrailingLayoutConstraint: NSLayoutConstraint!
let tableViewTopPaddingView = UIView() // fix empty state view background display when tableView bounce scrolling let tableViewTopPaddingView = UIView() // fix empty state view background display when tableView bounce scrolling
var tableViewTopPaddingViewHeightLayoutConstraint: NSLayoutConstraint! var tableViewTopPaddingViewHeightLayoutConstraint: NSLayoutConstraint!
@ -52,13 +54,14 @@ final class MastodonPickServerViewController: UIViewController, NeedsDependency
return tableView return tableView
}() }()
let buttonContainer = UIView()
let nextStepButton: PrimaryActionButton = { let nextStepButton: PrimaryActionButton = {
let button = PrimaryActionButton() let button = PrimaryActionButton()
button.setTitle(L10n.Common.Controls.Actions.signUp, for: .normal) button.setTitle(L10n.Common.Controls.Actions.signUp, for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false button.translatesAutoresizingMaskIntoConstraints = false
return button return button
}() }()
var nextStepButtonBottomLayoutConstraint: NSLayoutConstraint! var buttonContainerBottomLayoutConstraint: NSLayoutConstraint!
var mastodonAuthenticationController: MastodonAuthenticationController? var mastodonAuthenticationController: MastodonAuthenticationController?
@ -77,6 +80,8 @@ extension MastodonPickServerViewController {
setupOnboardingAppearance() setupOnboardingAppearance()
defer { setupNavigationBarBackgroundView() } defer { setupNavigationBarBackgroundView() }
configureTitleLabel()
configureMargin()
#if DEBUG #if DEBUG
navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "ellipsis.circle"), style: .plain, target: nil, action: nil) navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "ellipsis.circle"), style: .plain, target: nil, action: nil)
@ -89,14 +94,24 @@ extension MastodonPickServerViewController {
navigationItem.rightBarButtonItem?.menu = UIMenu(title: "Debug Tool", image: nil, identifier: nil, options: [], children: children) navigationItem.rightBarButtonItem?.menu = UIMenu(title: "Debug Tool", image: nil, identifier: nil, options: [], children: children)
#endif #endif
view.addSubview(nextStepButton) buttonContainer.translatesAutoresizingMaskIntoConstraints = false
nextStepButtonBottomLayoutConstraint = view.bottomAnchor.constraint(equalTo: nextStepButton.bottomAnchor, constant: 0).priority(.defaultHigh) buttonContainer.preservesSuperviewLayoutMargins = true
view.addSubview(buttonContainer)
buttonContainerBottomLayoutConstraint = view.bottomAnchor.constraint(equalTo: buttonContainer.bottomAnchor, constant: 0).priority(.defaultHigh)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
nextStepButton.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor, constant: MastodonPickServerViewController.actionButtonMargin), buttonContainer.leadingAnchor.constraint(equalTo: view.leadingAnchor),
view.readableContentGuide.trailingAnchor.constraint(equalTo: nextStepButton.trailingAnchor, constant: MastodonPickServerViewController.actionButtonMargin), buttonContainer.trailingAnchor.constraint(equalTo: view.trailingAnchor),
view.safeAreaLayoutGuide.bottomAnchor.constraint(greaterThanOrEqualTo: buttonContainer.bottomAnchor, constant: WelcomeViewController.viewBottomPaddingHeight),
buttonContainerBottomLayoutConstraint,
])
view.addSubview(nextStepButton)
NSLayoutConstraint.activate([
nextStepButton.topAnchor.constraint(equalTo: buttonContainer.topAnchor),
nextStepButton.leadingAnchor.constraint(equalTo: buttonContainer.layoutMarginsGuide.leadingAnchor),
buttonContainer.layoutMarginsGuide.trailingAnchor.constraint(equalTo: nextStepButton.trailingAnchor),
nextStepButton.bottomAnchor.constraint(equalTo: buttonContainer.bottomAnchor),
nextStepButton.heightAnchor.constraint(equalToConstant: MastodonPickServerViewController.actionButtonHeight).priority(.defaultHigh), nextStepButton.heightAnchor.constraint(equalToConstant: MastodonPickServerViewController.actionButtonHeight).priority(.defaultHigh),
view.safeAreaLayoutGuide.bottomAnchor.constraint(greaterThanOrEqualTo: nextStepButton.bottomAnchor, constant: WelcomeViewController.viewBottomPaddingHeight),
nextStepButtonBottomLayoutConstraint,
]) ])
// fix AutoLayout warning when observe before view appear // fix AutoLayout warning when observe before view appear
@ -127,16 +142,18 @@ extension MastodonPickServerViewController {
tableView.topAnchor.constraint(equalTo: view.topAnchor), tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
nextStepButton.topAnchor.constraint(equalTo: tableView.bottomAnchor, constant: 7), buttonContainer.topAnchor.constraint(equalTo: tableView.bottomAnchor, constant: 7),
]) ])
emptyStateView.translatesAutoresizingMaskIntoConstraints = false emptyStateView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(emptyStateView) view.addSubview(emptyStateView)
emptyStateViewLeadingLayoutConstraint = emptyStateView.leadingAnchor.constraint(equalTo: tableView.leadingAnchor)
emptyStateViewTrailingLayoutConstraint = tableView.trailingAnchor.constraint(equalTo: emptyStateView.trailingAnchor)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
emptyStateView.topAnchor.constraint(equalTo: view.topAnchor), emptyStateView.topAnchor.constraint(equalTo: view.topAnchor),
emptyStateView.leadingAnchor.constraint(equalTo: tableView.readableContentGuide.leadingAnchor), emptyStateViewLeadingLayoutConstraint,
emptyStateView.trailingAnchor.constraint(equalTo: tableView.readableContentGuide.trailingAnchor), emptyStateViewTrailingLayoutConstraint,
nextStepButton.topAnchor.constraint(equalTo: emptyStateView.bottomAnchor, constant: 21), buttonContainer.topAnchor.constraint(equalTo: emptyStateView.bottomAnchor, constant: 21),
]) ])
view.sendSubviewToBack(emptyStateView) view.sendSubviewToBack(emptyStateView)
@ -154,18 +171,18 @@ extension MastodonPickServerViewController {
// guard external keyboard connected // guard external keyboard connected
guard isShow, state == .dock, GCKeyboard.coalesced != nil else { guard isShow, state == .dock, GCKeyboard.coalesced != nil else {
self.nextStepButtonBottomLayoutConstraint.constant = WelcomeViewController.viewBottomPaddingHeight self.buttonContainerBottomLayoutConstraint.constant = WelcomeViewController.viewBottomPaddingHeight
return return
} }
let externalKeyboardToolbarHeight = self.view.frame.maxY - endFrame.minY let externalKeyboardToolbarHeight = self.view.frame.maxY - endFrame.minY
guard externalKeyboardToolbarHeight > 0 else { guard externalKeyboardToolbarHeight > 0 else {
self.nextStepButtonBottomLayoutConstraint.constant = WelcomeViewController.viewBottomPaddingHeight self.buttonContainerBottomLayoutConstraint.constant = WelcomeViewController.viewBottomPaddingHeight
return return
} }
UIView.animate(withDuration: 0.3) { UIView.animate(withDuration: 0.3) {
self.nextStepButtonBottomLayoutConstraint.constant = externalKeyboardToolbarHeight + 16 self.buttonContainerBottomLayoutConstraint.constant = externalKeyboardToolbarHeight + 16
self.view.layoutIfNeeded() self.view.layoutIfNeeded()
} }
} }
@ -274,9 +291,34 @@ extension MastodonPickServerViewController {
viewModel.viewWillAppear.send() viewModel.viewWillAppear.send()
} }
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
setupNavigationBarAppearance()
updateEmptyStateViewLayout()
configureTitleLabel()
configureMargin()
}
} }
extension MastodonPickServerViewController {
private func configureTitleLabel() {
guard UIDevice.current.userInterfaceIdiom == .pad else {
return
}
switch traitCollection.horizontalSizeClass {
case .regular:
navigationItem.largeTitleDisplayMode = .always
navigationItem.title = L10n.Scene.ServerPicker.title.replacingOccurrences(of: "\n", with: " ")
default:
navigationItem.largeTitleDisplayMode = .never
navigationItem.title = nil
}
}
}
extension MastodonPickServerViewController { extension MastodonPickServerViewController {
@objc @objc
@ -426,43 +468,6 @@ extension MastodonPickServerViewController: UITableViewDelegate {
} }
} }
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView()
headerView.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
return headerView
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
guard let diffableDataSource = viewModel.diffableDataSource else {
return .leastNonzeroMagnitude
}
let sections = diffableDataSource.snapshot().sectionIdentifiers
let section = sections[section]
switch section {
case .header:
return 20
case .category:
// Since category view has a blur shadow effect, its height need to be large than the actual height,
// Thus we reduce the section header's height by 10, and make the category cell height 60+20(10 inset for top and bottom)
return 10
case .search:
// Same reason as above
return 10
case .servers:
return .leastNonzeroMagnitude
}
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView()
footerView.backgroundColor = .yellow
return footerView
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return .leastNonzeroMagnitude
}
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
guard let diffableDataSource = viewModel.diffableDataSource else { return nil } guard let diffableDataSource = viewModel.diffableDataSource else { return nil }
guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return nil } guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return nil }
@ -521,6 +526,26 @@ extension MastodonPickServerViewController {
let rectInTableView = tableView.rectForRow(at: indexPath) let rectInTableView = tableView.rectForRow(at: indexPath)
emptyStateView.topPaddingViewTopLayoutConstraint.constant = rectInTableView.maxY 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
}
}
private func configureMargin() {
switch traitCollection.horizontalSizeClass {
case .regular:
let margin = MastodonPickServerViewController.viewEdgeMargin
buttonContainer.layoutMargins = UIEdgeInsets(top: 0, left: margin, bottom: 0, right: margin)
default:
buttonContainer.layoutMargins = .zero
}
} }
} }

View File

@ -56,12 +56,13 @@ extension PickServerCategoriesCell {
private func _init() { private func _init() {
selectionStyle = .none selectionStyle = .none
backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
configureMargin()
metricView.translatesAutoresizingMaskIntoConstraints = false metricView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(metricView) contentView.addSubview(metricView)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
metricView.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), metricView.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor),
metricView.trailingAnchor.constraint(equalTo: contentView.readableContentGuide.trailingAnchor), metricView.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor),
metricView.topAnchor.constraint(equalTo: contentView.topAnchor), metricView.topAnchor.constraint(equalTo: contentView.topAnchor),
metricView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), metricView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
metricView.heightAnchor.constraint(equalToConstant: 80).priority(.defaultHigh), metricView.heightAnchor.constraint(equalToConstant: 80).priority(.defaultHigh),
@ -71,14 +72,20 @@ extension PickServerCategoriesCell {
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
collectionView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), collectionView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), collectionView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
collectionView.topAnchor.constraint(equalTo: contentView.topAnchor), collectionView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10),
collectionView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), contentView.bottomAnchor.constraint(equalTo: collectionView.bottomAnchor, constant: 20),
collectionView.heightAnchor.constraint(equalToConstant: 80).priority(.defaultHigh), collectionView.heightAnchor.constraint(equalToConstant: 80).priority(.defaultHigh),
]) ])
collectionView.delegate = self collectionView.delegate = self
} }
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
configureMargin()
}
override func layoutSubviews() { override func layoutSubviews() {
super.layoutSubviews() super.layoutSubviews()
@ -87,6 +94,18 @@ extension PickServerCategoriesCell {
} }
extension PickServerCategoriesCell {
private func configureMargin() {
switch traitCollection.horizontalSizeClass {
case .regular:
let margin = MastodonPickServerViewController.viewEdgeMargin
contentView.layoutMargins = UIEdgeInsets(top: 0, left: margin, bottom: 0, right: margin)
default:
contentView.layoutMargins = .zero
}
}
}
// MARK: - UICollectionViewDelegateFlowLayout // MARK: - UICollectionViewDelegateFlowLayout
extension PickServerCategoriesCell: UICollectionViewDelegateFlowLayout { extension PickServerCategoriesCell: UICollectionViewDelegateFlowLayout {

View File

@ -198,6 +198,7 @@ extension PickServerCell {
private func _init() { private func _init() {
selectionStyle = .none selectionStyle = .none
backgroundColor = .clear backgroundColor = .clear
configureMargin()
contentView.addSubview(containerView) contentView.addSubview(containerView)
containerView.addSubview(domainLabel) containerView.addSubview(domainLabel)
@ -229,8 +230,8 @@ extension PickServerCell {
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
// Set background view // Set background view
containerView.topAnchor.constraint(equalTo: contentView.topAnchor), containerView.topAnchor.constraint(equalTo: contentView.topAnchor),
containerView.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), containerView.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor),
contentView.readableContentGuide.trailingAnchor.constraint(equalTo: containerView.trailingAnchor), contentView.layoutMarginsGuide.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
contentView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor), contentView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
// Set bottom separator // Set bottom separator
@ -291,6 +292,12 @@ extension PickServerCell {
expandButton.addTarget(self, action: #selector(expandButtonDidPressed(_:)), for: .touchUpInside) expandButton.addTarget(self, action: #selector(expandButtonDidPressed(_:)), for: .touchUpInside)
} }
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
configureMargin()
}
private func makeVerticalInfoStackView(arrangedView: UIView...) -> UIStackView { private func makeVerticalInfoStackView(arrangedView: UIView...) -> UIStackView {
let stackView = UIStackView() let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false stackView.translatesAutoresizingMaskIntoConstraints = false
@ -318,6 +325,18 @@ extension PickServerCell {
} }
} }
extension PickServerCell {
private func configureMargin() {
switch traitCollection.horizontalSizeClass {
case .regular:
let margin = MastodonPickServerViewController.viewEdgeMargin
contentView.layoutMargins = UIEdgeInsets(top: 0, left: margin, bottom: 0, right: margin)
default:
contentView.layoutMargins = .zero
}
}
}
extension PickServerCell { extension PickServerCell {
enum ExpandMode { enum ExpandMode {

View File

@ -37,14 +37,16 @@ final class PickServerLoaderTableViewCell: TimelineLoaderTableViewCell {
override func _init() { override func _init() {
super._init() super._init()
configureMargin()
contentView.addSubview(containerView) contentView.addSubview(containerView)
contentView.addSubview(seperator) contentView.addSubview(seperator)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
// Set background view // Set background view
containerView.topAnchor.constraint(equalTo: contentView.topAnchor), containerView.topAnchor.constraint(equalTo: contentView.topAnchor),
containerView.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), containerView.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor),
contentView.readableContentGuide.trailingAnchor.constraint(equalTo: containerView.trailingAnchor), contentView.layoutMarginsGuide.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
contentView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: 1), contentView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: 1),
// Set bottom separator // Set bottom separator
@ -67,6 +69,24 @@ final class PickServerLoaderTableViewCell: TimelineLoaderTableViewCell {
activityIndicatorView.isHidden = false activityIndicatorView.isHidden = false
startAnimating() startAnimating()
} }
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
configureMargin()
}
}
extension PickServerLoaderTableViewCell {
private func configureMargin() {
switch traitCollection.horizontalSizeClass {
case .regular:
let margin = MastodonPickServerViewController.viewEdgeMargin
contentView.layoutMargins = UIEdgeInsets(top: 0, left: margin, bottom: 0, right: margin)
default:
contentView.layoutMargins = .zero
}
}
} }
#if canImport(SwiftUI) && DEBUG #if canImport(SwiftUI) && DEBUG

View File

@ -109,6 +109,7 @@ extension PickServerSearchCell {
private func _init() { private func _init() {
selectionStyle = .none selectionStyle = .none
backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
configureMargin()
searchTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged) searchTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
searchTextField.delegate = self searchTextField.delegate = self
@ -118,9 +119,9 @@ extension PickServerSearchCell {
contentView.addSubview(searchTextField) contentView.addSubview(searchTextField)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
bgView.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), bgView.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor),
bgView.topAnchor.constraint(equalTo: contentView.topAnchor), bgView.topAnchor.constraint(equalTo: contentView.topAnchor),
bgView.trailingAnchor.constraint(equalTo: contentView.readableContentGuide.trailingAnchor), bgView.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor),
bgView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), bgView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
textFieldBgView.leadingAnchor.constraint(equalTo: bgView.leadingAnchor, constant: 14), textFieldBgView.leadingAnchor.constraint(equalTo: bgView.leadingAnchor, constant: 14),
@ -134,6 +135,24 @@ extension PickServerSearchCell {
textFieldBgView.bottomAnchor.constraint(equalTo: searchTextField.bottomAnchor, constant: 4), textFieldBgView.bottomAnchor.constraint(equalTo: searchTextField.bottomAnchor, constant: 4),
]) ])
} }
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
configureMargin()
}
}
extension PickServerSearchCell {
private func configureMargin() {
switch traitCollection.horizontalSizeClass {
case .regular:
let margin = MastodonPickServerViewController.viewEdgeMargin
contentView.layoutMargins = UIEdgeInsets(top: 0, left: margin, bottom: 0, right: margin)
default:
contentView.layoutMargins = .zero
}
}
} }
extension PickServerSearchCell { extension PickServerSearchCell {

View File

@ -20,6 +20,8 @@ final class PickServerTitleCell: UITableViewCell {
return label return label
}() }()
var containerHeightLayoutConstraint: NSLayoutConstraint!
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier) super.init(style: style, reuseIdentifier: reuseIdentifier)
_init() _init()
@ -36,13 +38,45 @@ extension PickServerTitleCell {
private func _init() { private func _init() {
selectionStyle = .none selectionStyle = .none
backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
contentView.addSubview(titleLabel) let container = UIStackView()
container.axis = .vertical
container.translatesAutoresizingMaskIntoConstraints = false
containerHeightLayoutConstraint = container.heightAnchor.constraint(equalToConstant: .leastNonzeroMagnitude)
contentView.addSubview(container)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
titleLabel.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), container.topAnchor.constraint(equalTo: contentView.topAnchor),
contentView.readableContentGuide.trailingAnchor.constraint(equalTo: titleLabel.trailingAnchor), container.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor),
titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor), container.trailingAnchor.constraint(equalTo: contentView.readableContentGuide.trailingAnchor),
titleLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), container.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
]) ])
container.addArrangedSubview(titleLabel)
configureTitleLabelDisplay()
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
configureTitleLabelDisplay()
}
}
extension PickServerTitleCell {
private func configureTitleLabelDisplay() {
guard traitCollection.userInterfaceIdiom == .pad else {
titleLabel.isHidden = false
return
}
switch traitCollection.horizontalSizeClass {
case .regular:
titleLabel.isHidden = true
containerHeightLayoutConstraint.isActive = true
default:
titleLabel.isHidden = false
containerHeightLayoutConstraint.isActive = false
}
} }
} }

View File

@ -61,6 +61,8 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O
return scrollview return scrollview
}() }()
let stackView = UIStackView()
let largeTitleLabel: UILabel = { let largeTitleLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.font = UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 34, weight: .bold)) label.font = UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 34, weight: .bold))
@ -287,7 +289,11 @@ extension MastodonRegisterViewController {
super.viewDidLoad() super.viewDidLoad()
setupOnboardingAppearance() setupOnboardingAppearance()
defer { setupNavigationBarBackgroundView() } configureTitleLabel()
defer {
setupNavigationBarBackgroundView()
configureFormLayout()
}
avatarButton.menu = createMediaContextMenu() avatarButton.menu = createMediaContextMenu()
avatarButton.showsMenuAsPrimaryAction = true avatarButton.showsMenuAsPrimaryAction = true
@ -307,7 +313,6 @@ extension MastodonRegisterViewController {
tapGestureRecognizer.addTarget(self, action: #selector(tapGestureRecognizerHandler)) tapGestureRecognizer.addTarget(self, action: #selector(tapGestureRecognizerHandler))
// stackview // stackview
let stackView = UIStackView()
stackView.axis = .vertical stackView.axis = .vertical
stackView.distribution = .fill stackView.distribution = .fill
stackView.spacing = 40 stackView.spacing = 40
@ -315,17 +320,24 @@ extension MastodonRegisterViewController {
stackView.isLayoutMarginsRelativeArrangement = true stackView.isLayoutMarginsRelativeArrangement = true
stackView.addArrangedSubview(largeTitleLabel) stackView.addArrangedSubview(largeTitleLabel)
stackView.addArrangedSubview(avatarView) stackView.addArrangedSubview(avatarView)
stackView.addArrangedSubview(usernameTextField)
stackView.addArrangedSubview(displayNameTextField) let formTableStackView = UIStackView()
stackView.addArrangedSubview(emailTextField) stackView.addArrangedSubview(formTableStackView)
stackView.addArrangedSubview(passwordTextField) formTableStackView.axis = .vertical
stackView.addArrangedSubview(passwordCheckLabel) formTableStackView.distribution = .fill
formTableStackView.spacing = 40
formTableStackView.addArrangedSubview(usernameTextField)
formTableStackView.addArrangedSubview(displayNameTextField)
formTableStackView.addArrangedSubview(emailTextField)
formTableStackView.addArrangedSubview(passwordTextField)
formTableStackView.addArrangedSubview(passwordCheckLabel)
if viewModel.approvalRequired { if viewModel.approvalRequired {
stackView.addArrangedSubview(reasonTextField) formTableStackView.addArrangedSubview(reasonTextField)
} }
usernameErrorPromptLabel.translatesAutoresizingMaskIntoConstraints = false usernameErrorPromptLabel.translatesAutoresizingMaskIntoConstraints = false
stackView.addSubview(usernameErrorPromptLabel) formTableStackView.addSubview(usernameErrorPromptLabel)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
usernameErrorPromptLabel.topAnchor.constraint(equalTo: usernameTextField.bottomAnchor, constant: 6), usernameErrorPromptLabel.topAnchor.constraint(equalTo: usernameTextField.bottomAnchor, constant: 6),
usernameErrorPromptLabel.leadingAnchor.constraint(equalTo: usernameTextField.leadingAnchor), usernameErrorPromptLabel.leadingAnchor.constraint(equalTo: usernameTextField.leadingAnchor),
@ -333,7 +345,7 @@ extension MastodonRegisterViewController {
]) ])
emailErrorPromptLabel.translatesAutoresizingMaskIntoConstraints = false emailErrorPromptLabel.translatesAutoresizingMaskIntoConstraints = false
stackView.addSubview(emailErrorPromptLabel) formTableStackView.addSubview(emailErrorPromptLabel)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
emailErrorPromptLabel.topAnchor.constraint(equalTo: emailTextField.bottomAnchor, constant: 6), emailErrorPromptLabel.topAnchor.constraint(equalTo: emailTextField.bottomAnchor, constant: 6),
emailErrorPromptLabel.leadingAnchor.constraint(equalTo: emailTextField.leadingAnchor), emailErrorPromptLabel.leadingAnchor.constraint(equalTo: emailTextField.leadingAnchor),
@ -341,7 +353,7 @@ extension MastodonRegisterViewController {
]) ])
passwordErrorPromptLabel.translatesAutoresizingMaskIntoConstraints = false passwordErrorPromptLabel.translatesAutoresizingMaskIntoConstraints = false
stackView.addSubview(passwordErrorPromptLabel) formTableStackView.addSubview(passwordErrorPromptLabel)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
passwordErrorPromptLabel.topAnchor.constraint(equalTo: passwordCheckLabel.bottomAnchor, constant: 2), passwordErrorPromptLabel.topAnchor.constraint(equalTo: passwordCheckLabel.bottomAnchor, constant: 2),
passwordErrorPromptLabel.leadingAnchor.constraint(equalTo: passwordTextField.leadingAnchor), passwordErrorPromptLabel.leadingAnchor.constraint(equalTo: passwordTextField.leadingAnchor),
@ -373,12 +385,14 @@ extension MastodonRegisterViewController {
avatarView.translatesAutoresizingMaskIntoConstraints = false avatarView.translatesAutoresizingMaskIntoConstraints = false
avatarView.addSubview(avatarButton) avatarView.addSubview(avatarButton)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
avatarView.heightAnchor.constraint(equalToConstant: 90).priority(.defaultHigh), avatarView.heightAnchor.constraint(equalToConstant: 92).priority(.required - 1),
]) ])
avatarButton.translatesAutoresizingMaskIntoConstraints = false avatarButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
avatarButton.heightAnchor.constraint(equalToConstant: 92).priority(.defaultHigh), avatarButton.heightAnchor.constraint(equalToConstant: 92).priority(.required - 1),
avatarButton.widthAnchor.constraint(equalToConstant: 92).priority(.defaultHigh), avatarButton.widthAnchor.constraint(equalToConstant: 92).priority(.required - 1),
avatarButton.leadingAnchor.constraint(greaterThanOrEqualTo: avatarView.leadingAnchor).priority(.required - 1),
avatarView.trailingAnchor.constraint(greaterThanOrEqualTo: avatarButton.trailingAnchor).priority(.required - 1),
avatarButton.centerXAnchor.constraint(equalTo: avatarView.centerXAnchor), avatarButton.centerXAnchor.constraint(equalTo: avatarView.centerXAnchor),
avatarButton.centerYAnchor.constraint(equalTo: avatarView.centerYAnchor), avatarButton.centerYAnchor.constraint(equalTo: avatarView.centerYAnchor),
]) ])
@ -392,15 +406,15 @@ extension MastodonRegisterViewController {
// textfield // textfield
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
usernameTextField.heightAnchor.constraint(equalToConstant: 50).priority(.defaultHigh), usernameTextField.heightAnchor.constraint(equalToConstant: 50).priority(.required - 1),
displayNameTextField.heightAnchor.constraint(equalToConstant: 50).priority(.defaultHigh), displayNameTextField.heightAnchor.constraint(equalToConstant: 50).priority(.required - 1),
emailTextField.heightAnchor.constraint(equalToConstant: 50).priority(.defaultHigh), emailTextField.heightAnchor.constraint(equalToConstant: 50).priority(.required - 1),
passwordTextField.heightAnchor.constraint(equalToConstant: 50).priority(.defaultHigh), passwordTextField.heightAnchor.constraint(equalToConstant: 50).priority(.required - 1),
]) ])
// password // password
stackView.setCustomSpacing(6, after: passwordTextField) formTableStackView.setCustomSpacing(6, after: passwordTextField)
stackView.setCustomSpacing(32, after: passwordCheckLabel) formTableStackView.setCustomSpacing(32, after: passwordCheckLabel)
// return // return
if viewModel.approvalRequired { if viewModel.approvalRequired {
@ -410,16 +424,22 @@ extension MastodonRegisterViewController {
} }
// button // button
stackView.addArrangedSubview(buttonContainer) formTableStackView.addArrangedSubview(buttonContainer)
signUpButton.translatesAutoresizingMaskIntoConstraints = false signUpButton.translatesAutoresizingMaskIntoConstraints = false
buttonContainer.addSubview(signUpButton) buttonContainer.addSubview(signUpButton)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
signUpButton.topAnchor.constraint(equalTo: buttonContainer.topAnchor), signUpButton.topAnchor.constraint(equalTo: buttonContainer.topAnchor),
signUpButton.leadingAnchor.constraint(equalTo: buttonContainer.leadingAnchor, constant: MastodonRegisterViewController.actionButtonMargin), signUpButton.leadingAnchor.constraint(equalTo: buttonContainer.leadingAnchor),
buttonContainer.trailingAnchor.constraint(equalTo: signUpButton.trailingAnchor, constant: MastodonRegisterViewController.actionButtonMargin), buttonContainer.trailingAnchor.constraint(equalTo: signUpButton.trailingAnchor),
buttonContainer.bottomAnchor.constraint(equalTo: signUpButton.bottomAnchor), buttonContainer.bottomAnchor.constraint(equalTo: signUpButton.bottomAnchor),
signUpButton.heightAnchor.constraint(equalToConstant: MastodonRegisterViewController.actionButtonHeight).priority(.defaultHigh), signUpButton.heightAnchor.constraint(equalToConstant: MastodonRegisterViewController.actionButtonHeight).priority(.required - 1),
buttonContainer.heightAnchor.constraint(equalToConstant: MastodonRegisterViewController.actionButtonHeight).priority(.required - 1),
]) ])
signUpButton.setContentHuggingPriority(.defaultLow, for: .horizontal)
signUpButton.setContentHuggingPriority(.defaultLow, for: .vertical)
signUpButton.setContentCompressionResistancePriority(.required - 1, for: .vertical)
signUpButton.setContentCompressionResistancePriority(.required - 1, for: .horizontal)
buttonContainer.setContentCompressionResistancePriority(.required - 1, for: .vertical)
Publishers.CombineLatest( Publishers.CombineLatest(
KeyboardResponderService.shared.state.eraseToAnyPublisher(), KeyboardResponderService.shared.state.eraseToAnyPublisher(),
@ -645,6 +665,12 @@ extension MastodonRegisterViewController {
plusIconImageView.layer.masksToBounds = true plusIconImageView.layer.masksToBounds = true
} }
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
configureTitleLabel()
configureFormLayout()
}
} }
extension MastodonRegisterViewController: UITextFieldDelegate { extension MastodonRegisterViewController: UITextFieldDelegate {
@ -714,7 +740,7 @@ extension MastodonRegisterViewController: UITextFieldDelegate {
textField.layer.shadowRadius = 2.0 textField.layer.shadowRadius = 2.0
textField.layer.shadowOffset = CGSize.zero textField.layer.shadowOffset = CGSize.zero
textField.layer.shadowColor = color.cgColor textField.layer.shadowColor = color.cgColor
textField.layer.shadowPath = UIBezierPath(roundedRect: textField.bounds, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: 2.0, height: 2.0)).cgPath // textField.layer.shadowPath = UIBezierPath(roundedRect: textField.bounds, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: 2.0, height: 2.0)).cgPath
} }
private func setTextFieldValidAppearance(_ textField: UITextField, validateState: MastodonRegisterViewModel.ValidateState) { private func setTextFieldValidAppearance(_ textField: UITextField, validateState: MastodonRegisterViewModel.ValidateState) {
@ -729,6 +755,36 @@ extension MastodonRegisterViewController: UITextFieldDelegate {
} }
} }
extension MastodonRegisterViewController {
private func configureTitleLabel() {
switch traitCollection.horizontalSizeClass {
case .regular:
navigationItem.largeTitleDisplayMode = .always
navigationItem.title = L10n.Scene.ServerPicker.title.replacingOccurrences(of: "\n", with: " ")
largeTitleLabel.isHidden = true
default:
navigationItem.largeTitleDisplayMode = .never
navigationItem.title = nil
largeTitleLabel.isHidden = false
}
}
private func configureFormLayout() {
switch traitCollection.horizontalSizeClass {
case .regular:
stackView.axis = .horizontal
stackView.distribution = .fillProportionally
default:
stackView.axis = .vertical
stackView.distribution = .fill
}
}
private func configureMargin() {
}
}
extension MastodonRegisterViewController { extension MastodonRegisterViewController {
@objc private func tapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) { @objc private func tapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) {
view.endEditing(true) view.endEditing(true)

View File

@ -21,6 +21,8 @@ final class MastodonServerRulesViewController: UIViewController, NeedsDependency
var viewModel: MastodonServerRulesViewModel! var viewModel: MastodonServerRulesViewModel!
let stackView = UIStackView()
let largeTitleLabel: UILabel = { let largeTitleLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.font = UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 34, weight: .bold)) label.font = UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 34, weight: .bold))
@ -96,6 +98,8 @@ extension MastodonServerRulesViewController {
super.viewDidLoad() super.viewDidLoad()
setupOnboardingAppearance() setupOnboardingAppearance()
configureTitleLabel()
configureMargin()
configTextView() configTextView()
defer { setupNavigationBarBackgroundView() } defer { setupNavigationBarBackgroundView() }
@ -116,8 +120,8 @@ extension MastodonServerRulesViewController {
bottomContainerView.addSubview(confirmButton) bottomContainerView.addSubview(confirmButton)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
bottomContainerView.layoutMarginsGuide.bottomAnchor.constraint(equalTo: confirmButton.bottomAnchor, constant: MastodonServerRulesViewController.viewBottomPaddingHeight), bottomContainerView.layoutMarginsGuide.bottomAnchor.constraint(equalTo: confirmButton.bottomAnchor, constant: MastodonServerRulesViewController.viewBottomPaddingHeight),
confirmButton.leadingAnchor.constraint(equalTo: bottomContainerView.readableContentGuide.leadingAnchor, constant: MastodonServerRulesViewController.actionButtonMargin), confirmButton.leadingAnchor.constraint(equalTo: bottomContainerView.layoutMarginsGuide.leadingAnchor),
bottomContainerView.readableContentGuide.trailingAnchor.constraint(equalTo: confirmButton.trailingAnchor, constant: MastodonServerRulesViewController.actionButtonMargin), bottomContainerView.layoutMarginsGuide.trailingAnchor.constraint(equalTo: confirmButton.trailingAnchor),
confirmButton.heightAnchor.constraint(equalToConstant: MastodonServerRulesViewController.actionButtonHeight).priority(.defaultHigh), confirmButton.heightAnchor.constraint(equalToConstant: MastodonServerRulesViewController.actionButtonHeight).priority(.defaultHigh),
]) ])
@ -125,8 +129,8 @@ extension MastodonServerRulesViewController {
bottomContainerView.addSubview(bottomPromptMetaText.textView) bottomContainerView.addSubview(bottomPromptMetaText.textView)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
bottomPromptMetaText.textView.frameLayoutGuide.topAnchor.constraint(equalTo: bottomContainerView.topAnchor, constant: 20), bottomPromptMetaText.textView.frameLayoutGuide.topAnchor.constraint(equalTo: bottomContainerView.topAnchor, constant: 20),
bottomPromptMetaText.textView.frameLayoutGuide.leadingAnchor.constraint(equalTo: bottomContainerView.readableContentGuide.leadingAnchor), bottomPromptMetaText.textView.frameLayoutGuide.leadingAnchor.constraint(equalTo: bottomContainerView.layoutMarginsGuide.leadingAnchor),
bottomPromptMetaText.textView.frameLayoutGuide.trailingAnchor.constraint(equalTo: bottomContainerView.readableContentGuide.trailingAnchor), bottomPromptMetaText.textView.frameLayoutGuide.trailingAnchor.constraint(equalTo: bottomContainerView.layoutMarginsGuide.trailingAnchor),
confirmButton.topAnchor.constraint(equalTo: bottomPromptMetaText.textView.frameLayoutGuide.bottomAnchor, constant: 20), confirmButton.topAnchor.constraint(equalTo: bottomPromptMetaText.textView.frameLayoutGuide.bottomAnchor, constant: 20),
]) ])
@ -140,10 +144,10 @@ extension MastodonServerRulesViewController {
scrollView.frameLayoutGuide.widthAnchor.constraint(equalTo: scrollView.contentLayoutGuide.widthAnchor), scrollView.frameLayoutGuide.widthAnchor.constraint(equalTo: scrollView.contentLayoutGuide.widthAnchor),
]) ])
let stackView = UIStackView()
stackView.axis = .vertical stackView.axis = .vertical
stackView.distribution = .fill stackView.distribution = .fill
stackView.spacing = 10 stackView.spacing = 10
stackView.isLayoutMarginsRelativeArrangement = true
stackView.layoutMargins = UIEdgeInsets(top: 20, left: 0, bottom: 20, right: 0) stackView.layoutMargins = UIEdgeInsets(top: 20, left: 0, bottom: 20, right: 0)
stackView.addArrangedSubview(largeTitleLabel) stackView.addArrangedSubview(largeTitleLabel)
stackView.addArrangedSubview(subtitleLabel) stackView.addArrangedSubview(subtitleLabel)
@ -178,6 +182,46 @@ extension MastodonServerRulesViewController {
updateScrollViewContentInset() updateScrollViewContentInset()
} }
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
setupNavigationBarAppearance()
configureTitleLabel()
configureMargin()
}
}
extension MastodonServerRulesViewController {
private func configureTitleLabel() {
guard UIDevice.current.userInterfaceIdiom == .pad else {
return
}
switch traitCollection.horizontalSizeClass {
case .regular:
navigationItem.largeTitleDisplayMode = .always
navigationItem.title = L10n.Scene.ServerRules.title.replacingOccurrences(of: "\n", with: " ")
largeTitleLabel.isHidden = true
default:
navigationItem.leftBarButtonItem = nil
navigationItem.largeTitleDisplayMode = .never
navigationItem.title = nil
largeTitleLabel.isHidden = false
}
}
private func configureMargin() {
switch traitCollection.horizontalSizeClass {
case .regular:
let margin = MastodonPickServerViewController.viewEdgeMargin
stackView.layoutMargins = UIEdgeInsets(top: 32, left: margin, bottom: 20, right: margin)
bottomContainerView.layoutMargins = UIEdgeInsets(top: 0, left: margin, bottom: 0, right: margin)
default:
stackView.layoutMargins = UIEdgeInsets(top: 20, left: 0, bottom: 20, right: 0)
bottomContainerView.layoutMargins = .zero
}
}
} }
extension MastodonServerRulesViewController { extension MastodonServerRulesViewController {

View File

@ -24,19 +24,38 @@ extension OnboardingViewControllerAppearance {
setupNavigationBarAppearance() setupNavigationBarAppearance()
let backItem = UIBarButtonItem() let backItem = UIBarButtonItem(
backItem.title = L10n.Common.Controls.Actions.back title: L10n.Common.Controls.Actions.back,
style: .plain,
target: nil,
action: nil
)
navigationItem.backBarButtonItem = backItem navigationItem.backBarButtonItem = backItem
} }
func setupNavigationBarAppearance() { func setupNavigationBarAppearance() {
// use TransparentBackground so view push / dismiss will be more visual nature // use TransparentBackground so view push / dismiss will be more visual nature
// please add opaque background for status bar manually if needs // please add opaque background for status bar manually if needs
let barAppearance = UINavigationBarAppearance()
barAppearance.configureWithTransparentBackground() switch traitCollection.userInterfaceIdiom {
navigationController?.navigationBar.standardAppearance = barAppearance case .pad:
navigationController?.navigationBar.compactAppearance = barAppearance if traitCollection.horizontalSizeClass == .regular {
navigationController?.navigationBar.scrollEdgeAppearance = barAppearance // do nothing
} else {
fallthrough
}
default:
let barAppearance = UINavigationBarAppearance()
barAppearance.configureWithTransparentBackground()
navigationItem.standardAppearance = barAppearance
navigationItem.compactAppearance = barAppearance
navigationItem.scrollEdgeAppearance = barAppearance
if #available(iOS 15.0, *) {
navigationItem.compactScrollEdgeAppearance = barAppearance
} else {
// Fallback on earlier versions
}
}
} }
func setupNavigationBarBackgroundView() { func setupNavigationBarBackgroundView() {
@ -57,3 +76,12 @@ extension OnboardingViewControllerAppearance {
} }
} }
extension OnboardingViewControllerAppearance {
static var viewEdgeMargin: CGFloat {
guard UIDevice.current.userInterfaceIdiom == .pad else { return .zero }
let shortEdgeWidth = min(UIScreen.main.bounds.height, UIScreen.main.bounds.width)
return shortEdgeWidth * 0.17 // magic
}
}

View File

@ -75,6 +75,8 @@ extension WelcomeViewController {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.largeTitleDisplayMode = .never
view.overrideUserInterfaceStyle = .light view.overrideUserInterfaceStyle = .light
setupOnboardingAppearance() setupOnboardingAppearance()
@ -235,7 +237,21 @@ extension WelcomeViewController {
} }
// MARK: - OnboardingViewControllerAppearance // MARK: - OnboardingViewControllerAppearance
extension WelcomeViewController: OnboardingViewControllerAppearance { } extension WelcomeViewController: OnboardingViewControllerAppearance {
func setupNavigationBarAppearance() {
// always transparent
let barAppearance = UINavigationBarAppearance()
barAppearance.configureWithTransparentBackground()
navigationItem.standardAppearance = barAppearance
navigationItem.compactAppearance = barAppearance
navigationItem.scrollEdgeAppearance = barAppearance
if #available(iOS 15.0, *) {
navigationItem.compactScrollEdgeAppearance = barAppearance
} else {
// Fallback on earlier versions
}
}
}
// MARK: - UIAdaptivePresentationControllerDelegate // MARK: - UIAdaptivePresentationControllerDelegate
extension WelcomeViewController: UIAdaptivePresentationControllerDelegate { extension WelcomeViewController: UIAdaptivePresentationControllerDelegate {
@ -245,7 +261,12 @@ extension WelcomeViewController: UIAdaptivePresentationControllerDelegate {
// make underneath view controller alive to fix layout issue due to view life cycle // make underneath view controller alive to fix layout issue due to view life cycle
return .fullScreen return .fullScreen
default: default:
return .pageSheet switch traitCollection.horizontalSizeClass {
case .regular:
return .pageSheet
default:
return .fullScreen
}
} }
} }

View File

@ -317,7 +317,7 @@ extension MainTabBarController {
switch tab { switch tab {
case .me: case .me:
coordinator.present(scene: .accountList, from: nil, transition: .panModal) coordinator.present(scene: .accountList, from: self, transition: .panModal)
default: default:
break break
} }
@ -353,7 +353,6 @@ extension MainTabBarController {
self.avatarButton.setContentHuggingPriority(.required - 1, for: .vertical) self.avatarButton.setContentHuggingPriority(.required - 1, for: .vertical)
self.avatarButton.isUserInteractionEnabled = false self.avatarButton.isUserInteractionEnabled = false
} }
} }
extension MainTabBarController { extension MainTabBarController {

View File

@ -201,6 +201,12 @@ extension RootSplitViewController: UISplitViewControllerDelegate {
displayModeForExpandingToProposedDisplayMode proposedDisplayMode: UISplitViewController.DisplayMode displayModeForExpandingToProposedDisplayMode proposedDisplayMode: UISplitViewController.DisplayMode
) -> UISplitViewController.DisplayMode { ) -> UISplitViewController.DisplayMode {
let compactNavigationController = mainTabBarController.selectedViewController as? UINavigationController let compactNavigationController = mainTabBarController.selectedViewController as? UINavigationController
if let topMost = compactNavigationController?.topMost,
topMost is AccountListViewController {
topMost.dismiss(animated: false, completion: nil)
}
let viewControllers = compactNavigationController?.popToRootViewController(animated: true) ?? [] let viewControllers = compactNavigationController?.popToRootViewController(animated: true) ?? []
var supplementaryViewControllers: [UIViewController] = [] var supplementaryViewControllers: [UIViewController] = []
@ -219,6 +225,7 @@ extension RootSplitViewController: UISplitViewControllerDelegate {
if let secondaryNavigationController = viewController(for: .secondary) as? UINavigationController { if let secondaryNavigationController = viewController(for: .secondary) as? UINavigationController {
secondaryNavigationController.setViewControllers(secondaryNavigationController.viewControllers + secondaryViewControllers, animated: false) secondaryNavigationController.setViewControllers(secondaryNavigationController.viewControllers + secondaryViewControllers, animated: false)
} }
return proposedDisplayMode return proposedDisplayMode
} }