feat: update Welcome scene UI

This commit is contained in:
CMK 2021-12-31 16:47:13 +08:00
parent 7711564cdd
commit 4a38daa345
19 changed files with 363 additions and 79 deletions

View File

@ -193,7 +193,9 @@
},
"scene": {
"welcome": {
"slogan": "Social networking\nback in your hands."
"slogan": "Social networking\nback in your hands.",
"get_started": "Get Started",
"log_in": "Log In"
},
"server_picker": {
"title": "Pick a server,\nany server.",
@ -554,4 +556,4 @@
"accessibility_hint": "Double tap to dismiss this wizard"
}
}
}
}

View File

@ -191,6 +191,7 @@
DB03F7F32689AEA3007B274C /* ComposeRepliedToStatusContentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB03F7F22689AEA3007B274C /* ComposeRepliedToStatusContentTableViewCell.swift */; };
DB03F7F52689B782007B274C /* ComposeTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB03F7F42689B782007B274C /* ComposeTableView.swift */; };
DB040ED126538E3D00BEE9D8 /* Trie.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB040ED026538E3C00BEE9D8 /* Trie.swift */; };
DB0617EB277EF3820030EE79 /* GradientBorderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0617EA277EF3820030EE79 /* GradientBorderView.swift */; };
DB084B5725CBC56C00F898ED /* Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB084B5625CBC56C00F898ED /* Status.swift */; };
DB0AC6FC25CD02E600D75117 /* APIService+Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0AC6FB25CD02E600D75117 /* APIService+Instance.swift */; };
DB0C946526A6FD4D0088FB11 /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB0C946426A6FD4D0088FB11 /* AlamofireImage */; };
@ -969,6 +970,7 @@
DB03F7F22689AEA3007B274C /* ComposeRepliedToStatusContentTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeRepliedToStatusContentTableViewCell.swift; sourceTree = "<group>"; };
DB03F7F42689B782007B274C /* ComposeTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeTableView.swift; sourceTree = "<group>"; };
DB040ED026538E3C00BEE9D8 /* Trie.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Trie.swift; sourceTree = "<group>"; };
DB0617EA277EF3820030EE79 /* GradientBorderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientBorderView.swift; sourceTree = "<group>"; };
DB084B5625CBC56C00F898ED /* Status.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Status.swift; sourceTree = "<group>"; };
DB0AC6FB25CD02E600D75117 /* APIService+Instance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Instance.swift"; sourceTree = "<group>"; };
DB0C946A26A700AB0088FB11 /* MastodonUser+Property.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MastodonUser+Property.swift"; sourceTree = "<group>"; };
@ -2993,6 +2995,7 @@
children = (
DBABE3EB25ECAC4B00879EE5 /* WelcomeIllustrationView.swift */,
DB4932B026F1FB5300EF46D4 /* WizardCardView.swift */,
DB0617EA277EF3820030EE79 /* GradientBorderView.swift */,
);
path = View;
sourceTree = "<group>";
@ -4307,6 +4310,7 @@
DB4932B326F2054200EF46D4 /* CircleAvatarButton.swift in Sources */,
0FB3D30825E524C600AAD544 /* PickServerCategoriesCell.swift in Sources */,
2D4AD8A226316CD200613EFC /* SelectedAccountSection.swift in Sources */,
DB0617EB277EF3820030EE79 /* GradientBorderView.swift in Sources */,
DB789A1225F9F2CC0071ACA0 /* ComposeViewModel.swift in Sources */,
DBB525362611ECEB002F1F29 /* UserTimelineViewController.swift in Sources */,
DB6D1B3D2636857500ACB481 /* AppearancePreference.swift in Sources */,
@ -4838,7 +4842,7 @@
SWIFT_OBJC_BRIDGING_HEADER = "Mastodon/Vender/Mastodon-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
@ -4866,7 +4870,7 @@
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Mastodon/Vender/Mastodon-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
@ -5131,7 +5135,7 @@
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
@ -5156,7 +5160,7 @@
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
@ -5181,7 +5185,7 @@
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
@ -5206,7 +5210,7 @@
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
@ -5230,7 +5234,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
@ -5254,7 +5258,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;

View File

@ -7,12 +7,12 @@
<key>AppShared.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>24</integer>
<integer>18</integer>
</dict>
<key>CoreDataStack.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>26</integer>
<integer>19</integer>
</dict>
<key>Mastodon - ASDK.xcscheme_^#shared#^_</key>
<dict>
@ -102,7 +102,7 @@
<key>MastodonIntent.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>27</integer>
<integer>21</integer>
</dict>
<key>MastodonIntents.xcscheme_^#shared#^_</key>
<dict>
@ -122,7 +122,7 @@
<key>ShareActionExtension.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>25</integer>
<integer>20</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>

View File

@ -255,7 +255,7 @@ extension SceneCoordinator {
DispatchQueue.main.async {
self.present(
scene: .welcome,
from: nil,
from: self.sceneDelegate.window?.rootViewController,
transition: .modal(animated: animated, completion: nil)
)
}
@ -304,14 +304,20 @@ extension SceneCoordinator {
presentingViewController.showDetailViewController(navigationController, sender: sender)
case .modal(let animated, let completion):
let modalNavigationController: UINavigationController = {
if scene.isOnboarding {
return AdaptiveStatusBarStyleNavigationController(rootViewController: viewController)
} else {
return UINavigationController(rootViewController: viewController)
}
}()
modalNavigationController.modalPresentationCapturesStatusBarAppearance = true
// let modalNavigationController: UINavigationController = {
// if scene.isOnboarding {
// return AdaptiveStatusBarStyleNavigationController(rootViewController: viewController)
// } else {
// return UINavigationController(rootViewController: viewController)
// }
// }()
// modalNavigationController.modalPresentationCapturesStatusBarAppearance = true
// if let adaptivePresentationControllerDelegate = viewController as? UIAdaptivePresentationControllerDelegate {
// modalNavigationController.presentationController?.delegate = adaptivePresentationControllerDelegate
// }
// presentingViewController.present(modalNavigationController, animated: animated, completion: completion)
let modalNavigationController = UINavigationController(rootViewController: viewController)
if let adaptivePresentationControllerDelegate = viewController as? UIAdaptivePresentationControllerDelegate {
modalNavigationController.presentationController?.delegate = adaptivePresentationControllerDelegate
}

View File

@ -102,8 +102,10 @@ internal enum Asset {
internal enum Welcome {
internal enum Illustration {
internal static let backgroundCyan = ColorAsset(name: "Scene/Welcome/illustration/background.cyan")
internal static let cloudBaseExtend = ImageAsset(name: "Scene/Welcome/illustration/cloud.base.extend")
internal static let cloudBase = ImageAsset(name: "Scene/Welcome/illustration/cloud.base")
internal static let elephantOnAirplaneWithContrail = ImageAsset(name: "Scene/Welcome/illustration/elephant.on.airplane.with.contrail")
internal static let elephantThreeOnGrassExtend = ImageAsset(name: "Scene/Welcome/illustration/elephant.three.on.grass.extend")
internal static let elephantThreeOnGrass = ImageAsset(name: "Scene/Welcome/illustration/elephant.three.on.grass")
internal static let elephantThreeOnGrassWithTreeThree = ImageAsset(name: "Scene/Welcome/illustration/elephant.three.on.grass.with.tree.three")
internal static let elephantThreeOnGrassWithTreeTwo = ImageAsset(name: "Scene/Welcome/illustration/elephant.three.on.grass.with.tree.two")
@ -112,6 +114,7 @@ internal enum Asset {
internal static let mastodonLogoBlackLarge = ImageAsset(name: "Scene/Welcome/mastodon.logo.black.large")
internal static let mastodonLogo = ImageAsset(name: "Scene/Welcome/mastodon.logo")
internal static let mastodonLogoLarge = ImageAsset(name: "Scene/Welcome/mastodon.logo.large")
internal static let signInButtonBackground = ColorAsset(name: "Scene/Welcome/sign.in.button.background")
}
}
internal enum Settings {

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "cloud.base.extend.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "cloud.base.extend@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "cloud.base.extend@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "elephant.three.on.grass.extend.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "elephant.three.on.grass.extend@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "elephant.three.on.grass.extend@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x81",
"green" : "0xAC",
"red" : "0x58"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -15,9 +15,11 @@ protocol OnboardingViewControllerAppearance: UIViewController {
extension OnboardingViewControllerAppearance {
static var actionButtonHeight: CGFloat { return 46 }
static var actionButtonHeight: CGFloat { return 50 }
static var actionButtonMargin: CGFloat { return 12 }
static var actionButtonMarginExtend: CGFloat { return 80 }
static var viewBottomPaddingHeight: CGFloat { return 11 }
static var viewBottomPaddingHeightExtend: CGFloat { return 22 }
func setupOnboardingAppearance() {
view.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color

View File

@ -0,0 +1,59 @@
//
// GradientBorderView.swift
// Mastodon
//
// Created by MainasuK on 2021-12-31.
//
import UIKit
final class GradientBorderView: UIView {
let gradientLayer = CAGradientLayer()
let maskLayer = CAShapeLayer()
override init(frame: CGRect) {
super.init(frame: frame)
_init()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
_init()
}
}
extension GradientBorderView {
private func _init() {
isUserInteractionEnabled = false
gradientLayer.frame = bounds
gradientLayer.colors = [
UIColor.white.cgColor,
UIColor.white.withAlphaComponent(0.0).cgColor,
]
gradientLayer.startPoint = CGPoint(x: 0.5, y: 0)
gradientLayer.endPoint = CGPoint(x: 0.5, y: 1)
layer.addSublayer(gradientLayer)
// set blend mode to "Soft Light"
layer.compositingFilter = "softLightBlendMode"
}
override func layoutSubviews() {
super.layoutSubviews()
let bezierPath = UIBezierPath(rect: bounds)
bezierPath.append(UIBezierPath(roundedRect: bounds.insetBy(dx: 3, dy: 3), cornerRadius: 10))
maskLayer.fillRule = .evenOdd
maskLayer.path = bezierPath.cgPath
gradientLayer.frame = bounds
gradientLayer.mask = maskLayer
}
}

View File

@ -8,18 +8,18 @@
import UIKit
final class WelcomeIllustrationView: UIView {
static let artworkImageSize = CGSize(width: 375, height: 1500)
let cloudBaseImageView = UIImageView()
let rightHillImageView = UIImageView()
let leftHillImageView = UIImageView()
let centerHillImageView = UIImageView()
private let cloudBaseImage = Asset.Scene.Welcome.Illustration.cloudBase.image
private let cloudBaseExtendImage = Asset.Scene.Welcome.Illustration.cloudBaseExtend.image
private let elephantThreeOnGrassWithTreeTwoImage = Asset.Scene.Welcome.Illustration.elephantThreeOnGrassWithTreeTwo.image
private let elephantThreeOnGrassWithTreeThreeImage = Asset.Scene.Welcome.Illustration.elephantThreeOnGrassWithTreeThree.image
private let elephantThreeOnGrassImage = Asset.Scene.Welcome.Illustration.elephantThreeOnGrass.image
private let elephantThreeOnGrassExtendImage = Asset.Scene.Welcome.Illustration.elephantThreeOnGrassExtend.image
// layout outside
let elephantOnAirplaneWithContrailImageView: UIImageView = {
@ -27,6 +27,13 @@ final class WelcomeIllustrationView: UIView {
imageView.contentMode = .scaleAspectFill
return imageView
}()
var layout: Layout = .compact {
didSet {
setNeedsLayout()
}
}
var aspectLayoutConstraint: NSLayoutConstraint!
override init(frame: CGRect) {
super.init(frame: frame)
@ -40,6 +47,20 @@ final class WelcomeIllustrationView: UIView {
}
extension WelcomeIllustrationView {
enum Layout {
case compact
case regular
var artworkImageSize: CGSize {
switch self {
case .compact: return CGSize(width: 375, height: 1500)
case .regular: return CGSize(width: 547, height: 1500)
}
}
}
}
extension WelcomeIllustrationView {
private func _init() {
@ -62,7 +83,6 @@ extension WelcomeIllustrationView {
cloudBaseImageView.leadingAnchor.constraint(equalTo: leadingAnchor),
cloudBaseImageView.trailingAnchor.constraint(equalTo: trailingAnchor),
cloudBaseImageView.bottomAnchor.constraint(equalTo: bottomAnchor),
cloudBaseImageView.widthAnchor.constraint(equalTo: cloudBaseImageView.heightAnchor, multiplier: WelcomeIllustrationView.artworkImageSize.width / WelcomeIllustrationView.artworkImageSize.height),
])
[
@ -79,15 +99,28 @@ extension WelcomeIllustrationView {
imageView.bottomAnchor.constraint(equalTo: cloudBaseImageView.bottomAnchor),
])
}
aspectLayoutConstraint = cloudBaseImageView.widthAnchor.constraint(equalTo: cloudBaseImageView.heightAnchor, multiplier: layout.artworkImageSize.width / layout.artworkImageSize.height)
aspectLayoutConstraint.isActive = true
}
override func layoutSubviews() {
super.layoutSubviews()
updateImage()
switch layout {
case .compact:
layoutCompact()
case .regular:
layoutRegular()
}
aspectLayoutConstraint.isActive = false
aspectLayoutConstraint = cloudBaseImageView.widthAnchor.constraint(equalTo: cloudBaseImageView.heightAnchor, multiplier: layout.artworkImageSize.width / layout.artworkImageSize.height)
aspectLayoutConstraint.isActive = true
}
private func updateImage() {
let size = WelcomeIllustrationView.artworkImageSize
private func layoutCompact() {
let size = layout.artworkImageSize
let width = size.width
let height = size.height
@ -130,6 +163,50 @@ extension WelcomeIllustrationView {
}
}
private func layoutRegular() {
let size = layout.artworkImageSize
let width = size.width
let height = size.height
cloudBaseImageView.image = UIGraphicsImageRenderer(size: size).image { context in
// clear background
UIColor.clear.setFill()
context.fill(CGRect(origin: .zero, size: size))
// draw cloud
cloudBaseExtendImage.draw(at: CGPoint(x: 0, y: height - cloudBaseExtendImage.size.height))
rightHillImageView.image = UIGraphicsImageRenderer(size: size).image { context in
// clear background
UIColor.clear.setFill()
context.fill(CGRect(origin: .zero, size: size))
// draw elephantThreeOnGrassWithTreeTwoImage
// elephantThreeOnGrassWithTreeTwo.bottomY - 25 align to elephantThreeOnGrassImage.centerY
elephantThreeOnGrassWithTreeTwoImage.draw(at: CGPoint(x: width - elephantThreeOnGrassWithTreeTwoImage.size.width, y: height - 0.5 * elephantThreeOnGrassImage.size.height - elephantThreeOnGrassWithTreeTwoImage.size.height - 20))
}
leftHillImageView.image = UIGraphicsImageRenderer(size: size).image { context in
// clear background
UIColor.clear.setFill()
context.fill(CGRect(origin: .zero, size: size))
// draw elephantThreeOnGrassWithTreeThree
// elephantThreeOnGrassWithTreeThree.bottomY + 30 align to elephantThreeOnGrassImage.centerY
elephantThreeOnGrassWithTreeThreeImage.draw(at: CGPoint(x: -160, y: height - 0.5 * elephantThreeOnGrassImage.size.height - elephantThreeOnGrassWithTreeThreeImage.size.height - 80))
}
centerHillImageView.image = UIGraphicsImageRenderer(size: size).image { context in
// clear background
UIColor.clear.setFill()
context.fill(CGRect(origin: .zero, size: size))
// draw elephantThreeOnGrass
elephantThreeOnGrassExtendImage.draw(at: CGPoint(x: 0, y: height - elephantThreeOnGrassExtendImage.size.height))
}
}
}
}
#if canImport(SwiftUI) && DEBUG
@ -140,13 +217,17 @@ struct WelcomeIllustrationView_Previews: PreviewProvider {
static var previews: some View {
Group {
UIViewPreview(width: 375) {
WelcomeIllustrationView()
let view = WelcomeIllustrationView()
view.layout = .compact
return view
}
.previewLayout(.fixed(width: 375, height: 1500))
UIViewPreview(width: 1125) {
WelcomeIllustrationView()
UIViewPreview(width: 547) {
let view = WelcomeIllustrationView()
view.layout = .regular
return view
}
.previewLayout(.fixed(width: 1125, height: 5000))
.previewLayout(.fixed(width: 547, height: 1500))
}
}

View File

@ -11,6 +11,8 @@ import Combine
final class WelcomeViewController: UIViewController, NeedsDependency {
let logger = Logger(subsystem: "WelcomeViewController", category: "ViewController")
weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
@ -41,30 +43,36 @@ final class WelcomeViewController: UIViewController, NeedsDependency {
return label
}()
let buttonContainer = UIStackView()
private(set) lazy var signUpButton: PrimaryActionButton = {
let button = PrimaryActionButton()
button.adjustsBackgroundImageWhenUserInterfaceStyleChanges = false
button.setTitle(L10n.Common.Controls.Actions.signUp, for: .normal)
button.setTitle("Get Started", for: .normal) // TODO: i18n
let backgroundImageColor: UIColor = .white
let backgroundImageHighlightedColor: UIColor = UIColor(white: 0.8, alpha: 1.0)
button.setBackgroundImage(.placeholder(color: backgroundImageColor), for: .normal)
button.setBackgroundImage(.placeholder(color: backgroundImageHighlightedColor), for: .highlighted)
let titleColor: UIColor = Asset.Colors.brandBlue.color
button.setTitleColor(titleColor, for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitleColor(.black, for: .normal)
return button
}()
private(set) lazy var signInButton: UIButton = {
let button = UIButton(type: .system)
let button = PrimaryActionButton()
button.adjustsBackgroundImageWhenUserInterfaceStyleChanges = false
button.titleLabel?.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold))
button.setTitle(L10n.Common.Controls.Actions.signIn, for: .normal)
button.setTitle("Log In", for: .normal)
let backgroundImageColor = Asset.Scene.Welcome.signInButtonBackground.color
let backgroundImageHighlightedColor = Asset.Scene.Welcome.signInButtonBackground.color.withAlphaComponent(0.8)
button.setBackgroundImage(.placeholder(color: backgroundImageColor), for: .normal)
button.setBackgroundImage(.placeholder(color: backgroundImageHighlightedColor), for: .highlighted)
let titleColor: UIColor = UIColor.white.withAlphaComponent(0.8)
button.setTitleColor(titleColor, for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
private(set) lazy var gradientBorderView = GradientBorderView(frame: view.bounds)
deinit {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
}
@ -76,7 +84,8 @@ extension WelcomeViewController {
override func viewDidLoad() {
super.viewDidLoad()
// preferredContentSize = CGSize(width: 547, height: 678)
definesPresentationContext = true
preferredContentSize = CGSize(width: 547, height: 678)
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.largeTitleDisplayMode = .never
@ -84,19 +93,37 @@ extension WelcomeViewController {
setupOnboardingAppearance()
setupIllustrationLayout()
view.addSubview(signInButton)
view.addSubview(signUpButton)
buttonContainer.axis = .vertical
buttonContainer.spacing = 12
buttonContainer.isLayoutMarginsRelativeArrangement = true
buttonContainer.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(buttonContainer)
NSLayoutConstraint.activate([
signInButton.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor, constant: WelcomeViewController.actionButtonMargin),
view.readableContentGuide.trailingAnchor.constraint(equalTo: signInButton.trailingAnchor, constant: WelcomeViewController.actionButtonMargin),
view.layoutMarginsGuide.bottomAnchor.constraint(equalTo: signInButton.bottomAnchor, constant: WelcomeViewController.viewBottomPaddingHeight),
signInButton.heightAnchor.constraint(equalToConstant: WelcomeViewController.actionButtonHeight).priority(.defaultHigh),
signInButton.topAnchor.constraint(equalTo: signUpButton.bottomAnchor, constant: 9),
signUpButton.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor, constant: WelcomeViewController.actionButtonMargin),
view.readableContentGuide.trailingAnchor.constraint(equalTo: signUpButton.trailingAnchor, constant: WelcomeViewController.actionButtonMargin),
signUpButton.heightAnchor.constraint(equalToConstant: WelcomeViewController.actionButtonHeight).priority(.defaultHigh),
buttonContainer.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor),
buttonContainer.trailingAnchor.constraint(equalTo: view.readableContentGuide.trailingAnchor),
view.layoutMarginsGuide.bottomAnchor.constraint(equalTo: buttonContainer.bottomAnchor),
])
signUpButton.translatesAutoresizingMaskIntoConstraints = false
buttonContainer.addArrangedSubview(signUpButton)
NSLayoutConstraint.activate([
signUpButton.heightAnchor.constraint(equalToConstant: WelcomeViewController.actionButtonHeight).priority(.required - 1),
])
signInButton.translatesAutoresizingMaskIntoConstraints = false
buttonContainer.addArrangedSubview(signInButton)
NSLayoutConstraint.activate([
signInButton.heightAnchor.constraint(equalToConstant: WelcomeViewController.actionButtonHeight).priority(.required - 1),
])
gradientBorderView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(gradientBorderView)
NSLayoutConstraint.activate([
gradientBorderView.topAnchor.constraint(equalTo: view.topAnchor),
gradientBorderView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
gradientBorderView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
gradientBorderView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
signUpButton.addTarget(self, action: #selector(signUpButtonDidClicked(_:)), for: .touchUpInside)
@ -109,17 +136,6 @@ extension WelcomeViewController {
self.navigationItem.leftBarButtonItem = needsShowDismissEntry ? self.dismissBarButtonItem : nil
}
.store(in: &disposeBag)
view.observe(\.frame, options: [.initial, .new]) { [weak self] view, _ in
guard let self = self else { return }
switch view.traitCollection.userInterfaceIdiom {
case .phone:
break
default:
self.welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.isHidden = view.frame.height < 800
}
}
.store(in: &observations)
}
override func viewSafeAreaInsetsDidChange() {
@ -130,18 +146,49 @@ extension WelcomeViewController {
if view.safeAreaInsets.bottom == 0 {
overlap += 56
}
// shift illustration down for iPad modal
if UIDevice.current.userInterfaceIdiom != .phone {
overlap += 20
}
welcomeIllustrationViewBottomAnchorLayoutConstraint?.constant = overlap
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
setupIllustrationLayout()
}
}
extension WelcomeViewController {
private func updateButtonContainerLayoutMargins(traitCollection: UITraitCollection) {
switch traitCollection.userInterfaceIdiom {
case .phone:
buttonContainer.layoutMargins = UIEdgeInsets(
top: 0,
left: WelcomeViewController.actionButtonMargin,
bottom: WelcomeViewController.viewBottomPaddingHeight,
right: WelcomeViewController.actionButtonMargin
)
default:
let margin = traitCollection.horizontalSizeClass == .regular ? WelcomeViewController.actionButtonMarginExtend : WelcomeViewController.actionButtonMargin
buttonContainer.layoutMargins = UIEdgeInsets(
top: 0,
left: margin,
bottom: WelcomeViewController.viewBottomPaddingHeightExtend,
right: margin
)
}
}
private func setupIllustrationLayout() {
welcomeIllustrationView.layout = {
switch traitCollection.userInterfaceIdiom {
case .phone:
return .compact
default:
return .regular
}
}()
// set logo
if logoImageView.superview == nil {
view.addSubview(logoImageView)
@ -154,10 +201,11 @@ extension WelcomeViewController {
logoImageView.setContentHuggingPriority(.defaultHigh, for: .vertical)
}
// set illustration for phone
// set illustration
guard welcomeIllustrationView.superview == nil else {
return
}
welcomeIllustrationView.contentMode = .scaleAspectFit
welcomeIllustrationView.translatesAutoresizingMaskIntoConstraints = false
welcomeIllustrationViewBottomAnchorLayoutConstraint = welcomeIllustrationView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 5)
@ -166,7 +214,7 @@ extension WelcomeViewController {
NSLayoutConstraint.activate([
view.leftAnchor.constraint(equalTo: welcomeIllustrationView.leftAnchor, constant: 15),
welcomeIllustrationView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 15),
welcomeIllustrationViewBottomAnchorLayoutConstraint!
welcomeIllustrationViewBottomAnchorLayoutConstraint!.priority(.required - 1),
])
welcomeIllustrationView.cloudBaseImageView.addMotionEffect(
@ -268,21 +316,34 @@ extension WelcomeViewController: OnboardingViewControllerAppearance {
// MARK: - UIAdaptivePresentationControllerDelegate
extension WelcomeViewController: UIAdaptivePresentationControllerDelegate {
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
updateButtonContainerLayoutMargins(traitCollection: traitCollection)
switch traitCollection.userInterfaceIdiom {
case .phone:
// make underneath view controller alive to fix layout issue due to view life cycle
return .fullScreen
default:
return .formSheet
// switch traitCollection.horizontalSizeClass {
// case .regular:
// default:
// return .fullScreen
// }
switch traitCollection.horizontalSizeClass {
case .compact:
return .fullScreen
case .regular:
return .formSheet
case .unspecified:
return .formSheet
@unknown default:
return .formSheet
}
}
}
func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
return nil
}
func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
return false
}

View File

@ -35,7 +35,7 @@ class WizardViewController: UIViewController {
let backgroundView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.black.withAlphaComponent(0.7)
view.backgroundColor = UIColor.black.withAlphaComponent(0.5)
return view
}()