diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 6955c581d..be3604e70 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -115,6 +115,9 @@ D87BFC8F291EC26A00FEE264 /* MastodonLoginServerTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D87BFC8E291EC26A00FEE264 /* MastodonLoginServerTableViewCell.swift */; }; D8916DC029211BE500124085 /* ContentSizedTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8916DBF29211BE500124085 /* ContentSizedTableView.swift */; }; D8A6AB6C291C5136003AB663 /* MastodonLoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8A6AB6B291C5136003AB663 /* MastodonLoginViewController.swift */; }; + D8A6FE5B293244B500666A47 /* WelcomeContentPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8A6FE5A293244B500666A47 /* WelcomeContentPage.swift */; }; + D8A6FE5D293244C300666A47 /* WelcomeContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8A6FE5C293244C300666A47 /* WelcomeContentViewController.swift */; }; + D8A6FE5F29324BBC00666A47 /* WelcomeContentPageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8A6FE5E29324BBC00666A47 /* WelcomeContentPageView.swift */; }; DB0009A626AEE5DC009B9D2D /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = DB0009A926AEE5DC009B9D2D /* Intents.intentdefinition */; settings = {ATTRIBUTES = (codegen, ); }; }; DB0009A726AEE5DC009B9D2D /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = DB0009A926AEE5DC009B9D2D /* Intents.intentdefinition */; }; DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0140CE25C42AEE00F9F3CF /* OSLog.swift */; }; @@ -660,6 +663,9 @@ D87BFC8E291EC26A00FEE264 /* MastodonLoginServerTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLoginServerTableViewCell.swift; sourceTree = ""; }; D8916DBF29211BE500124085 /* ContentSizedTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentSizedTableView.swift; sourceTree = ""; }; D8A6AB6B291C5136003AB663 /* MastodonLoginViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLoginViewController.swift; sourceTree = ""; }; + D8A6FE5A293244B500666A47 /* WelcomeContentPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeContentPage.swift; sourceTree = ""; }; + D8A6FE5C293244C300666A47 /* WelcomeContentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeContentViewController.swift; sourceTree = ""; }; + D8A6FE5E29324BBC00666A47 /* WelcomeContentPageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeContentPageView.swift; sourceTree = ""; }; DB0009A826AEE5DC009B9D2D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; name = Base; path = Base.lproj/Intents.intentdefinition; sourceTree = ""; }; DB0009AD26AEE5E4009B9D2D /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Intents.strings; sourceTree = ""; }; DB0140CE25C42AEE00F9F3CF /* OSLog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OSLog.swift; sourceTree = ""; }; @@ -1575,6 +1581,16 @@ path = Login; sourceTree = ""; }; + D8A6FE5929323DC200666A47 /* Pages */ = { + isa = PBXGroup; + children = ( + D8A6FE5A293244B500666A47 /* WelcomeContentPage.swift */, + D8A6FE5C293244C300666A47 /* WelcomeContentViewController.swift */, + D8A6FE5E29324BBC00666A47 /* WelcomeContentPageView.swift */, + ); + path = Pages; + sourceTree = ""; + }; DB01409B25C40BB600F9F3CF /* Onboarding */ = { isa = PBXGroup; children = ( @@ -2498,6 +2514,7 @@ DBABE3F125ECAC4E00879EE5 /* View */ = { isa = PBXGroup; children = ( + D8A6FE5929323DC200666A47 /* Pages */, DBABE3EB25ECAC4B00879EE5 /* WelcomeIllustrationView.swift */, DB4932B026F1FB5300EF46D4 /* WizardCardView.swift */, DB0617EA277EF3820030EE79 /* GradientBorderView.swift */, @@ -3287,6 +3304,8 @@ DB603113279EBEBA00A935FE /* DataSourceFacade+Block.swift in Sources */, DB63F777279A9A2A00455B82 /* NotificationView+Configuration.swift in Sources */, DB029E95266A20430062874E /* MastodonAuthenticationController.swift in Sources */, + DB0C947726A7FE840088FB11 /* NotificationAvatarButton.swift in Sources */, + D8A6FE5F29324BBC00666A47 /* WelcomeContentPageView.swift in Sources */, 5B90C461262599800002E742 /* SettingsLinkTableViewCell.swift in Sources */, DB6180DD263918E30018D199 /* MediaPreviewViewController.swift in Sources */, DBE3CDEC261C6B2900430CC6 /* FavoriteViewController.swift in Sources */, @@ -3499,6 +3518,7 @@ DB1D84382657B275000346B3 /* SegmentedControlNavigateable.swift in Sources */, 0F20220726134DA4000C64BF /* HashtagTimelineViewModel+Diffable.swift in Sources */, DB7A9F932818F33C0016AF98 /* MastodonServerRulesViewController+Debug.swift in Sources */, + D8A6FE5D293244C300666A47 /* WelcomeContentViewController.swift in Sources */, 2D5A3D2825CF8BC9002347D6 /* HomeTimelineViewModel+Diffable.swift in Sources */, DB6B74FC272FF55800C70B6E /* UserSection.swift in Sources */, DB0FCB862796BDA1006C02E2 /* SearchSection.swift in Sources */, @@ -3574,6 +3594,7 @@ 2D6DE40026141DF600A63F6A /* SearchViewModel.swift in Sources */, DB0617FD27855BFE0030EE79 /* ServerRuleItem.swift in Sources */, 5BB04FD5262E7AFF0043BFF6 /* ReportViewController.swift in Sources */, + D8A6FE5B293244B500666A47 /* WelcomeContentPage.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index 75afbc505..000000000 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,257 +0,0 @@ -{ - "pins" : [ - { - "identity" : "alamofire", - "kind" : "remoteSourceControl", - "location" : "https://github.com/Alamofire/Alamofire.git", - "state" : { - "revision" : "8dd85aee02e39dd280c75eef88ffdb86eed4b07b", - "version" : "5.6.2" - } - }, - { - "identity" : "alamofireimage", - "kind" : "remoteSourceControl", - "location" : "https://github.com/Alamofire/AlamofireImage.git", - "state" : { - "revision" : "98cbb00ce0ec5fc8e52a5b50a6bfc08d3e5aee10", - "version" : "4.2.0" - } - }, - { - "identity" : "commonoslog", - "kind" : "remoteSourceControl", - "location" : "https://github.com/MainasuK/CommonOSLog", - "state" : { - "revision" : "c121624a30698e9886efe38aebb36ff51c01b6c2", - "version" : "0.1.1" - } - }, - { - "identity" : "faviconfinder", - "kind" : "remoteSourceControl", - "location" : "https://github.com/will-lumley/FaviconFinder.git", - "state" : { - "revision" : "1f74844f77f79b95c0bb0130b3a87d4f340e6d3a", - "version" : "3.3.0" - } - }, - { - "identity" : "flanimatedimage", - "kind" : "remoteSourceControl", - "location" : "https://github.com/Flipboard/FLAnimatedImage.git", - "state" : { - "revision" : "d4f07b6f164d53c1212c3e54d6460738b1981e9f", - "version" : "1.0.17" - } - }, - { - "identity" : "fpsindicator", - "kind" : "remoteSourceControl", - "location" : "https://github.com/MainasuK/FPSIndicator.git", - "state" : { - "revision" : "e4a5067ccd5293b024c767f09e51056afd4a4796", - "version" : "1.1.0" - } - }, - { - "identity" : "fuzi", - "kind" : "remoteSourceControl", - "location" : "https://github.com/cezheng/Fuzi.git", - "state" : { - "revision" : "f08c8323da21e985f3772610753bcfc652c2103f", - "version" : "3.1.3" - } - }, - { - "identity" : "keychainaccess", - "kind" : "remoteSourceControl", - "location" : "https://github.com/kishikawakatsumi/KeychainAccess.git", - "state" : { - "revision" : "84e546727d66f1adc5439debad16270d0fdd04e7", - "version" : "4.2.2" - } - }, - { - "identity" : "kingfisher", - "kind" : "remoteSourceControl", - "location" : "https://github.com/onevcat/Kingfisher.git", - "state" : { - "revision" : "44e891bdb61426a95e31492a67c7c0dfad1f87c5", - "version" : "7.4.1" - } - }, - { - "identity" : "metatextkit", - "kind" : "remoteSourceControl", - "location" : "https://github.com/TwidereProject/MetaTextKit.git", - "state" : { - "revision" : "dcd5255d6930c2fab408dc8562c577547e477624", - "version" : "2.2.5" - } - }, - { - "identity" : "nextlevelsessionexporter", - "kind" : "remoteSourceControl", - "location" : "https://github.com/NextLevel/NextLevelSessionExporter.git", - "state" : { - "revision" : "b6c0cce1aa37fe1547d694f958fac3c3524b74da", - "version" : "0.4.6" - } - }, - { - "identity" : "nuke", - "kind" : "remoteSourceControl", - "location" : "https://github.com/kean/Nuke.git", - "state" : { - "revision" : "a002b7fd786f2df2ed4333fe73a9727499fd9d97", - "version" : "10.11.2" - } - }, - { - "identity" : "nuke-flanimatedimage-plugin", - "kind" : "remoteSourceControl", - "location" : "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git", - "state" : { - "revision" : "b59c346a7d536336db3b0f12c72c6e53ee709e16", - "version" : "8.0.0" - } - }, - { - "identity" : "pageboy", - "kind" : "remoteSourceControl", - "location" : "https://github.com/uias/Pageboy", - "state" : { - "revision" : "af8fa81788b893205e1ff42ddd88c5b0b315d7c5", - "version" : "3.7.0" - } - }, - { - "identity" : "panmodal", - "kind" : "remoteSourceControl", - "location" : "https://github.com/slackhq/PanModal.git", - "state" : { - "revision" : "b012aecb6b67a8e46369227f893c12544846613f", - "version" : "1.2.7" - } - }, - { - "identity" : "sdwebimage", - "kind" : "remoteSourceControl", - "location" : "https://github.com/SDWebImage/SDWebImage.git", - "state" : { - "revision" : "3312bf5e67b52fbce7c3caf431b0cda721a9f7bb", - "version" : "5.14.2" - } - }, - { - "identity" : "stripes", - "kind" : "remoteSourceControl", - "location" : "https://github.com/eneko/Stripes.git", - "state" : { - "revision" : "d533fd44b8043a3abbf523e733599173d6f98c11", - "version" : "0.2.0" - } - }, - { - "identity" : "swift-collections", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-collections.git", - "state" : { - "revision" : "f504716c27d2e5d4144fa4794b12129301d17729", - "version" : "1.0.3" - } - }, - { - "identity" : "swift-nio", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio.git", - "state" : { - "revision" : "546610d52b19be3e19935e0880bb06b9c03f5cef", - "version" : "1.14.4" - } - }, - { - "identity" : "swift-nio-zlib-support", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio-zlib-support.git", - "state" : { - "revision" : "37760e9a52030bb9011972c5213c3350fa9d41fd", - "version" : "1.0.0" - } - }, - { - "identity" : "swiftsoup", - "kind" : "remoteSourceControl", - "location" : "https://github.com/scinfu/SwiftSoup.git", - "state" : { - "revision" : "6778575285177365cbad3e5b8a72f2a20583cfec", - "version" : "2.4.3" - } - }, - { - "identity" : "swiftui-introspect", - "kind" : "remoteSourceControl", - "location" : "https://github.com/siteline/SwiftUI-Introspect.git", - "state" : { - "revision" : "f2616860a41f9d9932da412a8978fec79c06fe24", - "version" : "0.1.4" - } - }, - { - "identity" : "tabbarpager", - "kind" : "remoteSourceControl", - "location" : "https://github.com/TwidereProject/TabBarPager.git", - "state" : { - "revision" : "488aa66d157a648901b61721212c0dec23d27ee5", - "version" : "0.1.0" - } - }, - { - "identity" : "tabman", - "kind" : "remoteSourceControl", - "location" : "https://github.com/uias/Tabman", - "state" : { - "revision" : "4a4f7c755b875ffd4f9ef10d67a67883669d2465", - "version" : "2.13.0" - } - }, - { - "identity" : "thirdpartymailer", - "kind" : "remoteSourceControl", - "location" : "https://github.com/vtourraine/ThirdPartyMailer.git", - "state" : { - "revision" : "44c1cfaa6969963f22691aa67f88a69e3b6d651f", - "version" : "2.1.0" - } - }, - { - "identity" : "tocropviewcontroller", - "kind" : "remoteSourceControl", - "location" : "https://github.com/TimOliver/TOCropViewController.git", - "state" : { - "revision" : "d0470491f56e734731bbf77991944c0dfdee3e0e", - "version" : "2.6.1" - } - }, - { - "identity" : "uihostingconfigurationbackport", - "kind" : "remoteSourceControl", - "location" : "https://github.com/woxtu/UIHostingConfigurationBackport.git", - "state" : { - "revision" : "6091f2d38faa4b24fc2ca0389c651e2f666624a3", - "version" : "0.1.0" - } - }, - { - "identity" : "uitextview-placeholder", - "kind" : "remoteSourceControl", - "location" : "https://github.com/MainasuK/UITextView-Placeholder.git", - "state" : { - "revision" : "20f513ded04a040cdf5467f0891849b1763ede3b", - "version" : "1.4.1" - } - } - ], - "version" : 2 -} diff --git a/Mastodon/Scene/Onboarding/Welcome/View/Pages/WelcomeContentPage.swift b/Mastodon/Scene/Onboarding/Welcome/View/Pages/WelcomeContentPage.swift new file mode 100644 index 000000000..9557e5c46 --- /dev/null +++ b/Mastodon/Scene/Onboarding/Welcome/View/Pages/WelcomeContentPage.swift @@ -0,0 +1,48 @@ +// +// WelcomeContentPage.swift +// Mastodon +// +// Created by Nathan Mattes on 26.11.22. +// + +import UIKit + +enum WelcomeContentPage: CaseIterable { + case whatIsMastodon + case mastodonIsLikeThat + case howDoIPickAServer + + var backgroundColor: UIColor { + switch self { + case .whatIsMastodon: + return .green + case .mastodonIsLikeThat: + return .red + case .howDoIPickAServer: + return .blue + } + } + + var title: String { + switch self { + case .whatIsMastodon: + return "What is Mastodon?" + case .mastodonIsLikeThat: + return "Mastodon is like that" + case .howDoIPickAServer: + return "How to I pick a server?" + } + } + + var content: String { + switch self { + case .whatIsMastodon: + return "Long text\n\nhat is Mastodon?" + case .mastodonIsLikeThat: + return "Long text\n\nwhat Mastodon is like" + case .howDoIPickAServer: + return "Long text\n\nHow to I pick a server?" + } + + } +} diff --git a/Mastodon/Scene/Onboarding/Welcome/View/Pages/WelcomeContentPageView.swift b/Mastodon/Scene/Onboarding/Welcome/View/Pages/WelcomeContentPageView.swift new file mode 100644 index 000000000..34ab1ec27 --- /dev/null +++ b/Mastodon/Scene/Onboarding/Welcome/View/Pages/WelcomeContentPageView.swift @@ -0,0 +1,53 @@ +// +// WelcomeContentPageView.swift +// Mastodon +// +// Created by Nathan Mattes on 26.11.22. +// + +import UIKit + +class WelcomeContentPageView: UIView { + + //TODO: Put in ScrollView? + private let contentStackView: UIStackView + private let titleView: UILabel + private let label: UILabel + + init(page: WelcomeContentPage) { + + //TODO: @zeitschlag Decide based on page which titleView, first page has mastodon-logo in it + //TODO: @zeitschlag Add styling + titleView = UILabel() + titleView.text = page.title + + //TODO: @zeitschlag Add styling + label = UILabel() + label.text = page.content + label.numberOfLines = 0 + + contentStackView = UIStackView(arrangedSubviews: [titleView, label, UIView()]) + contentStackView.translatesAutoresizingMaskIntoConstraints = false + contentStackView.axis = .vertical + contentStackView.alignment = .leading + + super.init(frame: .zero) + + addSubview(contentStackView) + + setupConstraints() + } + + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + + private func setupConstraints() { + let constraints = [ + contentStackView.topAnchor.constraint(equalTo: topAnchor), + contentStackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16), + trailingAnchor.constraint(equalTo: contentStackView.trailingAnchor, constant: 16), + bottomAnchor.constraint(equalTo: contentStackView.bottomAnchor) + ] + + NSLayoutConstraint.activate(constraints) + } +} diff --git a/Mastodon/Scene/Onboarding/Welcome/View/Pages/WelcomeContentViewController.swift b/Mastodon/Scene/Onboarding/Welcome/View/Pages/WelcomeContentViewController.swift new file mode 100644 index 000000000..7bd20d033 --- /dev/null +++ b/Mastodon/Scene/Onboarding/Welcome/View/Pages/WelcomeContentViewController.swift @@ -0,0 +1,28 @@ +// +// WelcomeContentViewController.swift +// Mastodon +// +// Created by Nathan Mattes on 26.11.22. +// + +import UIKit + +class WelcomeContentViewController: UIViewController { + + let page: WelcomeContentPage + var contentView: WelcomeContentPageView { + view as! WelcomeContentPageView + } + + init(page: WelcomeContentPage) { + self.page = page + super.init(nibName: nil, bundle: nil) + } + + override func loadView() { + let pageView = WelcomeContentPageView(page: page) + self.view = pageView + } + + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } +} diff --git a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift index b0d2f3c71..b943356c6 100644 --- a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift +++ b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift @@ -5,7 +5,6 @@ // Created by BradGao on 2021/2/20. // -import os.log import UIKit import Combine import MastodonAsset @@ -13,318 +12,334 @@ import MastodonCore import MastodonLocalization 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) } } - - var disposeBag = Set() - var observations = Set() - private(set) lazy var viewModel = WelcomeViewModel(context: context) - - let welcomeIllustrationView = WelcomeIllustrationView() - var welcomeIllustrationViewBottomAnchorLayoutConstraint: NSLayoutConstraint? - - private(set) lazy var dismissBarButtonItem = UIBarButtonItem(barButtonSystemItem: .close, target: self, action: #selector(WelcomeViewController.dismissBarButtonItemDidPressed(_:))) - - private(set) lazy var logoImageView: UIImageView = { - let image = Asset.Scene.Welcome.mastodonLogo.image - let imageView = UIImageView(image: image) - imageView.translatesAutoresizingMaskIntoConstraints = false - return imageView - }() - - private(set) lazy var sloganLabel: UILabel = { - let label = UILabel() - label.font = UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 34, weight: .bold)) - label.textColor = Asset.Colors.Label.primary.color - label.text = L10n.Scene.Welcome.slogan - label.adjustsFontForContentSizeCategory = true - label.translatesAutoresizingMaskIntoConstraints = false - label.numberOfLines = 0 - return label - }() - - let buttonContainer = UIStackView() - - private(set) lazy var signUpButton: PrimaryActionButton = { - let button = PrimaryActionButton() - button.adjustsBackgroundImageWhenUserInterfaceStyleChanges = false - button.contentEdgeInsets = WelcomeViewController.actionButtonPadding - button.titleLabel?.adjustsFontForContentSizeCategory = true - button.titleLabel?.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold)) - button.setTitle(L10n.Common.Controls.Actions.signUp, for: .normal) - 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) - button.setTitleColor(.black, for: .normal) - return button - }() - let signUpButtonShadowView = UIView() - - private(set) lazy var signInButton: PrimaryActionButton = { - let button = PrimaryActionButton() - button.adjustsBackgroundImageWhenUserInterfaceStyleChanges = false - button.contentEdgeInsets = WelcomeViewController.actionButtonPadding - button.titleLabel?.adjustsFontForContentSizeCategory = true - button.titleLabel?.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold)) - button.setTitle(L10n.Scene.Welcome.logIn, 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.9) - button.setTitleColor(titleColor, for: .normal) - return button - }() - let signInButtonShadowView = UIView() - - deinit { - os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) - } - + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + var disposeBag = Set() + var observations = Set() + private(set) lazy var viewModel = WelcomeViewModel(context: context) + + let welcomeIllustrationView = WelcomeIllustrationView() + var welcomeIllustrationViewBottomAnchorLayoutConstraint: NSLayoutConstraint? + + private(set) lazy var dismissBarButtonItem = UIBarButtonItem(barButtonSystemItem: .close, target: self, action: #selector(WelcomeViewController.dismissBarButtonItemDidPressed(_:))) + + private(set) lazy var logoImageView: UIImageView = { + let image = Asset.Scene.Welcome.mastodonLogo.image + let imageView = UIImageView(image: image) + imageView.translatesAutoresizingMaskIntoConstraints = false + imageView.isHidden = true + return imageView + }() + + private(set) lazy var sloganLabel: UILabel = { + let label = UILabel() + label.font = UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 34, weight: .bold)) + label.textColor = Asset.Colors.Label.primary.color + label.text = L10n.Scene.Welcome.slogan + label.adjustsFontForContentSizeCategory = true + label.translatesAutoresizingMaskIntoConstraints = false + label.numberOfLines = 0 + return label + }() + + let buttonContainer = UIStackView() + + private(set) lazy var signUpButton: PrimaryActionButton = { + let button = PrimaryActionButton() + button.adjustsBackgroundImageWhenUserInterfaceStyleChanges = false + button.contentEdgeInsets = WelcomeViewController.actionButtonPadding + button.titleLabel?.adjustsFontForContentSizeCategory = true + button.titleLabel?.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold)) + button.setTitle(L10n.Common.Controls.Actions.signUp, for: .normal) + 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) + button.setTitleColor(.black, for: .normal) + return button + }() + let signUpButtonShadowView = UIView() + + private(set) lazy var signInButton: PrimaryActionButton = { + let button = PrimaryActionButton() + button.adjustsBackgroundImageWhenUserInterfaceStyleChanges = false + button.contentEdgeInsets = WelcomeViewController.actionButtonPadding + button.titleLabel?.adjustsFontForContentSizeCategory = true + button.titleLabel?.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold)) + button.setTitle(L10n.Scene.Welcome.logIn, 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.9) + button.setTitleColor(titleColor, for: .normal) + return button + }() + let signInButtonShadowView = UIView() + + private(set) lazy var pageViewController: UIPageViewController = { + let pageController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal) + pageController.setViewControllers([WelcomeContentViewController(page: .whatIsMastodon)], direction: .forward, animated: false) + return pageController + }() + var currentPage: WelcomeContentPage = .whatIsMastodon } extension WelcomeViewController { - - override func viewDidLoad() { - super.viewDidLoad() - - definesPresentationContext = true - preferredContentSize = CGSize(width: 547, height: 678) - - navigationController?.navigationBar.prefersLargeTitles = true - navigationItem.largeTitleDisplayMode = .never - view.overrideUserInterfaceStyle = .light - - setupOnboardingAppearance() - setupIllustrationLayout() - - buttonContainer.axis = .vertical - buttonContainer.spacing = 12 - buttonContainer.isLayoutMarginsRelativeArrangement = true - - buttonContainer.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(buttonContainer) - NSLayoutConstraint.activate([ - 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(greaterThanOrEqualToConstant: WelcomeViewController.actionButtonHeight).priority(.required - 1), - ]) - signInButton.translatesAutoresizingMaskIntoConstraints = false - buttonContainer.addArrangedSubview(signInButton) - NSLayoutConstraint.activate([ - signInButton.heightAnchor.constraint(greaterThanOrEqualToConstant: WelcomeViewController.actionButtonHeight).priority(.required - 1), - ]) - - signUpButtonShadowView.translatesAutoresizingMaskIntoConstraints = false - buttonContainer.addSubview(signUpButtonShadowView) - buttonContainer.sendSubviewToBack(signUpButtonShadowView) - signUpButtonShadowView.pinTo(to: signUpButton) - - signInButtonShadowView.translatesAutoresizingMaskIntoConstraints = false - buttonContainer.addSubview(signInButtonShadowView) - buttonContainer.sendSubviewToBack(signInButtonShadowView) - signInButtonShadowView.pinTo(to: signInButton) - signUpButton.addTarget(self, action: #selector(signUpButtonDidClicked(_:)), for: .touchUpInside) - signInButton.addTarget(self, action: #selector(signInButtonDidClicked(_:)), for: .touchUpInside) - - viewModel.$needsShowDismissEntry - .receive(on: DispatchQueue.main) - .sink { [weak self] needsShowDismissEntry in - guard let self = self else { return } - self.navigationItem.leftBarButtonItem = needsShowDismissEntry ? self.dismissBarButtonItem : nil - } - .store(in: &disposeBag) - } - - override func viewDidLayoutSubviews() { - super.viewDidLayoutSubviews() - - setupButtonShadowView() - } - - override func viewSafeAreaInsetsDidChange() { - super.viewSafeAreaInsetsDidChange() - - var overlap: CGFloat = 5 - // shift illustration down for non-notch phone - if view.safeAreaInsets.bottom == 0 { - overlap += 56 - } - welcomeIllustrationViewBottomAnchorLayoutConstraint?.constant = overlap - } - - override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { - super.traitCollectionDidChange(previousTraitCollection) + override func viewDidLoad() { + super.viewDidLoad() - view.layoutIfNeeded() + definesPresentationContext = true + preferredContentSize = CGSize(width: 547, height: 678) - setupIllustrationLayout() - setupButtonShadowView() + navigationController?.navigationBar.prefersLargeTitles = true + navigationItem.largeTitleDisplayMode = .never + view.overrideUserInterfaceStyle = .light + + setupOnboardingAppearance() + setupIllustrationLayout() + + buttonContainer.axis = .vertical + buttonContainer.spacing = 12 + buttonContainer.isLayoutMarginsRelativeArrangement = true + + buttonContainer.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(buttonContainer) + NSLayoutConstraint.activate([ + 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(greaterThanOrEqualToConstant: WelcomeViewController.actionButtonHeight).priority(.required - 1), + ]) + signInButton.translatesAutoresizingMaskIntoConstraints = false + buttonContainer.addArrangedSubview(signInButton) + NSLayoutConstraint.activate([ + signInButton.heightAnchor.constraint(greaterThanOrEqualToConstant: WelcomeViewController.actionButtonHeight).priority(.required - 1), + ]) + + signUpButtonShadowView.translatesAutoresizingMaskIntoConstraints = false + buttonContainer.addSubview(signUpButtonShadowView) + buttonContainer.sendSubviewToBack(signUpButtonShadowView) + signUpButtonShadowView.pinTo(to: signUpButton) + + signInButtonShadowView.translatesAutoresizingMaskIntoConstraints = false + buttonContainer.addSubview(signInButtonShadowView) + buttonContainer.sendSubviewToBack(signInButtonShadowView) + signInButtonShadowView.pinTo(to: signInButton) + + signUpButton.addTarget(self, action: #selector(signUpButtonDidClicked(_:)), for: .touchUpInside) + signInButton.addTarget(self, action: #selector(signInButtonDidClicked(_:)), for: .touchUpInside) + + pageViewController.delegate = self + pageViewController.dataSource = self + addChild(pageViewController) + pageViewController.view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(pageViewController.view) + pageViewController.didMove(toParent: self) + + NSLayoutConstraint.activate([ + pageViewController.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), + pageViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + view.trailingAnchor.constraint(equalTo: pageViewController.view.trailingAnchor), + buttonContainer.topAnchor.constraint(equalTo: pageViewController.view.bottomAnchor, constant: 16), + ]) + + viewModel.$needsShowDismissEntry + .receive(on: DispatchQueue.main) + .sink { [weak self] needsShowDismissEntry in + guard let self = self else { return } + self.navigationItem.leftBarButtonItem = needsShowDismissEntry ? self.dismissBarButtonItem : nil + } + .store(in: &disposeBag) + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + setupButtonShadowView() + } + + override func viewSafeAreaInsetsDidChange() { + super.viewSafeAreaInsetsDidChange() + + var overlap: CGFloat = 5 + // shift illustration down for non-notch phone + if view.safeAreaInsets.bottom == 0 { + overlap += 56 } - + welcomeIllustrationViewBottomAnchorLayoutConstraint?.constant = overlap + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + view.layoutIfNeeded() + + setupIllustrationLayout() + setupButtonShadowView() + } + } extension WelcomeViewController { - - private func setupButtonShadowView() { - signUpButtonShadowView.layer.setupShadow( - color: .black, - alpha: 0.25, - x: 0, - y: 1, - blur: 2, - spread: 0, - roundedRect: signUpButtonShadowView.bounds, - byRoundingCorners: .allCorners, - cornerRadii: CGSize(width: 10, height: 10) + + private func setupButtonShadowView() { + signUpButtonShadowView.layer.setupShadow( + color: .black, + alpha: 0.25, + x: 0, + y: 1, + blur: 2, + spread: 0, + roundedRect: signUpButtonShadowView.bounds, + byRoundingCorners: .allCorners, + cornerRadii: CGSize(width: 10, height: 10) + ) + signInButtonShadowView.layer.setupShadow( + color: .black, + alpha: 0.25, + x: 0, + y: 1, + blur: 2, + spread: 0, + roundedRect: signInButtonShadowView.bounds, + byRoundingCorners: .allCorners, + cornerRadii: CGSize(width: 10, height: 10) + ) + } + + private func updateButtonContainerLayoutMargins(traitCollection: UITraitCollection) { + switch traitCollection.userInterfaceIdiom { + case .phone: + buttonContainer.layoutMargins = UIEdgeInsets( + top: 0, + left: WelcomeViewController.actionButtonMargin, + bottom: WelcomeViewController.viewBottomPaddingHeight, + right: WelcomeViewController.actionButtonMargin ) - signInButtonShadowView.layer.setupShadow( - color: .black, - alpha: 0.25, - x: 0, - y: 1, - blur: 2, - spread: 0, - roundedRect: signInButtonShadowView.bounds, - byRoundingCorners: .allCorners, - cornerRadii: CGSize(width: 10, height: 10) + default: + let margin = traitCollection.horizontalSizeClass == .regular ? WelcomeViewController.actionButtonMarginExtend : WelcomeViewController.actionButtonMargin + buttonContainer.layoutMargins = UIEdgeInsets( + top: 0, + left: margin, + bottom: WelcomeViewController.viewBottomPaddingHeightExtend, + right: margin ) } - - private func updateButtonContainerLayoutMargins(traitCollection: UITraitCollection) { - switch traitCollection.userInterfaceIdiom { + } + + private func setupIllustrationLayout() { + welcomeIllustrationView.layout = { + switch traitCollection.userInterfaceIdiom { case .phone: - buttonContainer.layoutMargins = UIEdgeInsets( - top: 0, - left: WelcomeViewController.actionButtonMargin, - bottom: WelcomeViewController.viewBottomPaddingHeight, - right: WelcomeViewController.actionButtonMargin - ) + return .compact default: - let margin = traitCollection.horizontalSizeClass == .regular ? WelcomeViewController.actionButtonMarginExtend : WelcomeViewController.actionButtonMargin - buttonContainer.layoutMargins = UIEdgeInsets( - top: 0, - left: margin, - bottom: WelcomeViewController.viewBottomPaddingHeightExtend, - right: margin - ) - } + return .regular + } + }() + + // set logo + if logoImageView.superview == nil { + view.addSubview(logoImageView) + NSLayoutConstraint.activate([ + logoImageView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor), + logoImageView.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor, constant: 35), + view.readableContentGuide.trailingAnchor.constraint(equalTo: logoImageView.trailingAnchor, constant: 35), + logoImageView.heightAnchor.constraint(equalTo: logoImageView.widthAnchor, multiplier: 75.0/269.0), + ]) + logoImageView.setContentHuggingPriority(.defaultHigh, for: .vertical) } - - private func setupIllustrationLayout() { - welcomeIllustrationView.layout = { - switch traitCollection.userInterfaceIdiom { - case .phone: - return .compact - default: - return .regular - } - }() - - // set logo - if logoImageView.superview == nil { - view.addSubview(logoImageView) - NSLayoutConstraint.activate([ - logoImageView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor), - logoImageView.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor, constant: 35), - view.readableContentGuide.trailingAnchor.constraint(equalTo: logoImageView.trailingAnchor, constant: 35), - logoImageView.heightAnchor.constraint(equalTo: logoImageView.widthAnchor, multiplier: 75.0/269.0), - ]) - logoImageView.setContentHuggingPriority(.defaultHigh, for: .vertical) - } - - // set illustration - guard welcomeIllustrationView.superview == nil else { - return - } - welcomeIllustrationView.contentMode = .scaleAspectFit - - welcomeIllustrationView.translatesAutoresizingMaskIntoConstraints = false - welcomeIllustrationViewBottomAnchorLayoutConstraint = welcomeIllustrationView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 5) - - view.addSubview(welcomeIllustrationView) - NSLayoutConstraint.activate([ - view.leftAnchor.constraint(equalTo: welcomeIllustrationView.leftAnchor, constant: 15), - welcomeIllustrationView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 15), - welcomeIllustrationViewBottomAnchorLayoutConstraint!.priority(.required - 1), - ]) - - welcomeIllustrationView.cloudBaseImageView.addMotionEffect( - UIInterpolatingMotionEffect.motionEffect(minX: -5, maxX: 5, minY: -5, maxY: 5) - ) - welcomeIllustrationView.rightHillImageView.addMotionEffect( - UIInterpolatingMotionEffect.motionEffect(minX: -15, maxX: 25, minY: -10, maxY: 10) - ) - welcomeIllustrationView.leftHillImageView.addMotionEffect( - UIInterpolatingMotionEffect.motionEffect(minX: -25, maxX: 15, minY: -15, maxY: 15) - ) - welcomeIllustrationView.centerHillImageView.addMotionEffect( - UIInterpolatingMotionEffect.motionEffect(minX: -14, maxX: 14, minY: -5, maxY: 25) - ) - - let topPaddingView = UIView() - topPaddingView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(topPaddingView) - NSLayoutConstraint.activate([ - topPaddingView.topAnchor.constraint(equalTo: logoImageView.bottomAnchor), - topPaddingView.leadingAnchor.constraint(equalTo: logoImageView.leadingAnchor), - topPaddingView.trailingAnchor.constraint(equalTo: logoImageView.trailingAnchor), - ]) - welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(welcomeIllustrationView.elephantOnAirplaneWithContrailImageView) - NSLayoutConstraint.activate([ - view.leftAnchor.constraint(equalTo: welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.leftAnchor, constant: 12), // add 12pt bleeding - welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.topAnchor.constraint(equalTo: topPaddingView.bottomAnchor), - // make a little bit large - welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.84), - welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.heightAnchor.constraint(equalTo: welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.widthAnchor, multiplier: 105.0/318.0), - ]) - let bottomPaddingView = UIView() - bottomPaddingView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(bottomPaddingView) - NSLayoutConstraint.activate([ - bottomPaddingView.topAnchor.constraint(equalTo: welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.bottomAnchor), - bottomPaddingView.leadingAnchor.constraint(equalTo: logoImageView.leadingAnchor), - bottomPaddingView.trailingAnchor.constraint(equalTo: logoImageView.trailingAnchor), - bottomPaddingView.bottomAnchor.constraint(equalTo: view.centerYAnchor), - bottomPaddingView.heightAnchor.constraint(equalTo: topPaddingView.heightAnchor, multiplier: 4), - ]) - - welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.addMotionEffect( - UIInterpolatingMotionEffect.motionEffect(minX: -20, maxX: 12, minY: -20, maxY: 12) // maxX should not larger then the bleeding (12pt) - ) - - view.bringSubviewToFront(logoImageView) - view.bringSubviewToFront(sloganLabel) + + // set illustration + guard welcomeIllustrationView.superview == nil else { + return } + welcomeIllustrationView.contentMode = .scaleAspectFit + + welcomeIllustrationView.translatesAutoresizingMaskIntoConstraints = false + welcomeIllustrationViewBottomAnchorLayoutConstraint = welcomeIllustrationView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 5) + + view.addSubview(welcomeIllustrationView) + // welcomeIllustrationView.isHidden = true + NSLayoutConstraint.activate([ + view.leftAnchor.constraint(equalTo: welcomeIllustrationView.leftAnchor, constant: 15), + welcomeIllustrationView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 15), + welcomeIllustrationViewBottomAnchorLayoutConstraint!.priority(.required - 1), + ]) + + welcomeIllustrationView.cloudBaseImageView.addMotionEffect( + UIInterpolatingMotionEffect.motionEffect(minX: -5, maxX: 5, minY: -5, maxY: 5) + ) + welcomeIllustrationView.rightHillImageView.addMotionEffect( + UIInterpolatingMotionEffect.motionEffect(minX: -15, maxX: 25, minY: -10, maxY: 10) + ) + welcomeIllustrationView.leftHillImageView.addMotionEffect( + UIInterpolatingMotionEffect.motionEffect(minX: -25, maxX: 15, minY: -15, maxY: 15) + ) + welcomeIllustrationView.centerHillImageView.addMotionEffect( + UIInterpolatingMotionEffect.motionEffect(minX: -14, maxX: 14, minY: -5, maxY: 25) + ) + + let topPaddingView = UIView() + topPaddingView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(topPaddingView) + NSLayoutConstraint.activate([ + topPaddingView.topAnchor.constraint(equalTo: logoImageView.bottomAnchor), + topPaddingView.leadingAnchor.constraint(equalTo: logoImageView.leadingAnchor), + topPaddingView.trailingAnchor.constraint(equalTo: logoImageView.trailingAnchor), + ]) + welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(welcomeIllustrationView.elephantOnAirplaneWithContrailImageView) + NSLayoutConstraint.activate([ + view.leftAnchor.constraint(equalTo: welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.leftAnchor, constant: 12), // add 12pt bleeding + welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.topAnchor.constraint(equalTo: topPaddingView.bottomAnchor), + // make a little bit large + welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.84), + welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.heightAnchor.constraint(equalTo: welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.widthAnchor, multiplier: 105.0/318.0), + ]) + let bottomPaddingView = UIView() + bottomPaddingView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(bottomPaddingView) + NSLayoutConstraint.activate([ + bottomPaddingView.topAnchor.constraint(equalTo: welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.bottomAnchor), + bottomPaddingView.leadingAnchor.constraint(equalTo: logoImageView.leadingAnchor), + bottomPaddingView.trailingAnchor.constraint(equalTo: logoImageView.trailingAnchor), + bottomPaddingView.bottomAnchor.constraint(equalTo: view.centerYAnchor), + bottomPaddingView.heightAnchor.constraint(equalTo: topPaddingView.heightAnchor, multiplier: 4), + ]) + + welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.addMotionEffect( + UIInterpolatingMotionEffect.motionEffect(minX: -20, maxX: 12, minY: -20, maxY: 12) // maxX should not larger then the bleeding (12pt) + ) + + view.bringSubviewToFront(logoImageView) + view.bringSubviewToFront(sloganLabel) + } } extension WelcomeViewController { - @objc - private func signUpButtonDidClicked(_ sender: UIButton) { - _ = coordinator.present(scene: .mastodonPickServer(viewMode: MastodonPickServerViewModel(context: context)), from: self, transition: .show) - } - - @objc - private func signInButtonDidClicked(_ sender: UIButton) { - _ = coordinator.present(scene: .mastodonLogin, from: self, transition: .show) - } - - @objc - private func dismissBarButtonItemDidPressed(_ sender: UIButton) { - dismiss(animated: true, completion: nil) - } + @objc + private func signUpButtonDidClicked(_ sender: UIButton) { + _ = coordinator.present(scene: .mastodonPickServer(viewMode: MastodonPickServerViewModel(context: context)), from: self, transition: .show) + } + + @objc + private func signInButtonDidClicked(_ sender: UIButton) { + _ = coordinator.present(scene: .mastodonLogin, from: self, transition: .show) + } + + @objc + private func dismissBarButtonItemDidPressed(_ sender: UIButton) { + dismiss(animated: true, completion: nil) + } } // MARK: - OnboardingViewControllerAppearance @@ -343,36 +358,88 @@ 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)") + func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle { - // update button layout - updateButtonContainerLayoutMargins(traitCollection: traitCollection) - - let navigationController = navigationController as? OnboardingNavigationController - - switch traitCollection.userInterfaceIdiom { - case .phone: + // update button layout + updateButtonContainerLayoutMargins(traitCollection: traitCollection) + + let navigationController = navigationController as? OnboardingNavigationController + + switch traitCollection.userInterfaceIdiom { + case .phone: + navigationController?.gradientBorderView.isHidden = true + // make underneath view controller alive to fix layout issue due to view life cycle + return .fullScreen + default: + switch traitCollection.horizontalSizeClass { + case .compact: navigationController?.gradientBorderView.isHidden = true - // make underneath view controller alive to fix layout issue due to view life cycle return .fullScreen - default: - switch traitCollection.horizontalSizeClass { - case .compact: - navigationController?.gradientBorderView.isHidden = true - return .fullScreen - default: - navigationController?.gradientBorderView.isHidden = false - return .formSheet - } + default: + navigationController?.gradientBorderView.isHidden = false + return .formSheet } } - - func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? { + } + + func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? { + return nil + } + + func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool { + return false + } +} + +//MARK: - UIPageViewControllerDelegate + +extension WelcomeViewController: UIPageViewControllerDelegate { + func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { + guard let currentViewController = pageViewController.viewControllers?.first as? WelcomeContentViewController else { return } + + currentPage = currentViewController.page + } +} + +//MARK: - UIPageViewDataSource + +extension WelcomeViewController: UIPageViewControllerDataSource { + + func presentationIndex(for pageViewController: UIPageViewController) -> Int { + WelcomeContentPage.allCases.firstIndex(of: currentPage) ?? 0 + } + + func presentationCount(for pageViewController: UIPageViewController) -> Int { + return WelcomeContentPage.allCases.count + } + + func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { + guard let viewController = viewController as? WelcomeContentViewController else { return nil } + + let currentPage = viewController.page + + switch currentPage { + case .whatIsMastodon: + return nil + case .mastodonIsLikeThat: + return WelcomeContentViewController(page: .whatIsMastodon) + case .howDoIPickAServer: + return WelcomeContentViewController(page: .mastodonIsLikeThat) + } + } + + func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { + guard let viewController = viewController as? WelcomeContentViewController else { return nil } + + let currentPage = viewController.page + + switch currentPage { + case .whatIsMastodon: + return WelcomeContentViewController(page: .mastodonIsLikeThat) + case .mastodonIsLikeThat: + return WelcomeContentViewController(page: .howDoIPickAServer) + case .howDoIPickAServer: return nil } - - func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool { - return false - } + } }