diff --git a/Localization/app.json b/Localization/app.json index 5916a7bd1..080201a03 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -80,7 +80,6 @@ "save_photo": "Save Photo", "copy_photo": "Copy Photo", "sign_in": "Log in", - "sign_up": "Create Account", "see_more": "See More", "preview": "Preview", "copy": "Copy", @@ -102,7 +101,8 @@ "title": "Translate from %s", "unknown_language": "Unknown" }, - "edit_post": "Edit" + "edit_post": "Edit", + }, "tabs": { "home": "Home", @@ -261,34 +261,33 @@ }, "scene": { "welcome": { - "slogan": "Social networking\nback in your hands.", - "get_started": "Get Started", "log_in": "Log In", + "learn_more": "Learn more", + "join_default_server": "Join mastodon.social" + "separator": { + "or": "or" + }, "education": { - "what_is_mastodon": { - "title": "What is", - "description": "Imagine you have an email address that ends with @example.com.\n\nYou can still send and receive emails from anyone, even if their email ends in @gmail.com or @icloud.com or @example.com." - }, - "mastodon_is_like_that": { - "title": "Mastodon is like that", - "description": "Your handle might be @gothgirl654@example.social, but you can still follow, reblog, and chat with @fallout5ever@example.online." - }, - "how_do_i_pick_a_server": { - "title": "How do I pick a server?", - "description": "Different people choose different servers for any number of reasons. art.example is a great place for artists, while glasgow.example might be a good pick for Scots.\n\nYou can’t go wrong with any of our recommend servers, so regardless of which one you pick (or if you enter your own in the server search bar), you’ll never miss a beat anywhere." - }, + "mastodon": { + "title": "Welcome to Mastodon", + "description": "Mastodon is a decentralized social network, meaning no single company controls it. It’s made up of many independently-run servers, all connected together." + }, + "servers": { + "title": "What are servers?", + "description": "Every Mastodon account is hosted on a server — each with its own values, rules, & admins. No matter which one you pick, you can follow and interact with people on any server." + }, "a11y": { "what_is_mastodon": { - "title": "What is Mastodon?" - } - } + "title": "What is Mastodon?" + } + } } }, "login": { "title": "Welcome back", "subtitle": "Log you in on the server you created your account on.", "server_search_field": { - "placeholder": "Enter URL or search for your server" + "placeholder": "Enter URL or search for your server" } }, "server_picker": { diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 228939fe2..417270c63 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -135,6 +135,7 @@ 9E44C7202967AD17004B2A72 /* MastodonSDKDynamic in Frameworks */ = {isa = PBXBuildFile; productRef = 9E44C71F2967AD17004B2A72 /* MastodonSDKDynamic */; }; 9E44C7222967AD17004B2A72 /* MastodonSDKDynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 9E44C71F2967AD17004B2A72 /* MastodonSDKDynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; C24C97032922F30500BAE8CB /* RefreshControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = C24C97022922F30500BAE8CB /* RefreshControl.swift */; }; + D807C6C029DE197900A4E17C /* EducationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D807C6BF29DE197900A4E17C /* EducationViewController.swift */; }; D808B94C296ECFDC0031EB1E /* StatusEditHistoryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D808B94B296ECFDC0031EB1E /* StatusEditHistoryViewModel.swift */; }; D808B94E296EFBBA0031EB1E /* StatusEditHistoryTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D808B94D296EFBBA0031EB1E /* StatusEditHistoryTableViewCell.swift */; }; D8099078294BC8A30050219F /* PrivacyTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8099077294BC8A30050219F /* PrivacyTableViewController.swift */; }; @@ -144,10 +145,9 @@ D87BFC8B291D5C6B00FEE264 /* MastodonLoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D87BFC8A291D5C6B00FEE264 /* MastodonLoginView.swift */; }; D87BFC8D291EB81200FEE264 /* MastodonLoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D87BFC8C291EB81200FEE264 /* MastodonLoginViewModel.swift */; }; D87BFC8F291EC26A00FEE264 /* MastodonLoginServerTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D87BFC8E291EC26A00FEE264 /* MastodonLoginServerTableViewCell.swift */; }; + D886FBD329DF710F00272017 /* WelcomeSeparatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D886FBD229DF710F00272017 /* WelcomeSeparatorView.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 */; }; - D8A6FE5F29324BBC00666A47 /* WelcomeContentCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8A6FE5E29324BBC00666A47 /* WelcomeContentCollectionViewCell.swift */; }; D8E5C346296DAB84007E76A7 /* DataSourceFacade+Status+History.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8E5C345296DAB84007E76A7 /* DataSourceFacade+Status+History.swift */; }; D8E5C349296DB8A3007E76A7 /* StatusEditHistoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8E5C348296DB8A3007E76A7 /* StatusEditHistoryViewController.swift */; }; DB0009A626AEE5DC009B9D2D /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = DB0009A926AEE5DC009B9D2D /* Intents.intentdefinition */; settings = {ATTRIBUTES = (codegen, ); }; }; @@ -773,6 +773,7 @@ C3789232A52F43529CA67E95 /* Pods-MastodonIntent.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonIntent.asdk - debug.xcconfig"; path = "Target Support Files/Pods-MastodonIntent/Pods-MastodonIntent.asdk - debug.xcconfig"; sourceTree = ""; }; CD92E0F10BDE4FE7C4B999F2 /* Pods_MastodonTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MastodonTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D7D7CF93E262178800077512 /* Pods-Mastodon-AppShared.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-AppShared.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-AppShared/Pods-Mastodon-AppShared.debug.xcconfig"; sourceTree = ""; }; + D807C6BF29DE197900A4E17C /* EducationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EducationViewController.swift; sourceTree = ""; }; D808B94B296ECFDC0031EB1E /* StatusEditHistoryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusEditHistoryViewModel.swift; sourceTree = ""; }; D808B94D296EFBBA0031EB1E /* StatusEditHistoryTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusEditHistoryTableViewCell.swift; sourceTree = ""; }; D8099077294BC8A30050219F /* PrivacyTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyTableViewController.swift; sourceTree = ""; }; @@ -782,10 +783,9 @@ D87BFC8A291D5C6B00FEE264 /* MastodonLoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLoginView.swift; sourceTree = ""; }; D87BFC8C291EB81200FEE264 /* MastodonLoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLoginViewModel.swift; sourceTree = ""; }; D87BFC8E291EC26A00FEE264 /* MastodonLoginServerTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLoginServerTableViewCell.swift; sourceTree = ""; }; + D886FBD229DF710F00272017 /* WelcomeSeparatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeSeparatorView.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 = ""; }; - D8A6FE5E29324BBC00666A47 /* WelcomeContentCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeContentCollectionViewCell.swift; sourceTree = ""; }; D8A6FE6129325F5900666A47 /* Intents.stringsdict */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; path = Intents.stringsdict; sourceTree = ""; }; D8A6FE6229325F5900666A47 /* app.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = app.json; sourceTree = ""; }; D8A6FE6329325F5900666A47 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; @@ -1324,6 +1324,7 @@ DBABE3F125ECAC4E00879EE5 /* View */, 0FAA0FDE25E0B57E0017CCDE /* WelcomeViewController.swift */, DB1D61CE26F1B33600DA8662 /* WelcomeViewModel.swift */, + D807C6BF29DE197900A4E17C /* EducationViewController.swift */, ); path = Welcome; sourceTree = ""; @@ -1808,15 +1809,6 @@ path = Login; sourceTree = ""; }; - D8A6FE5929323DC200666A47 /* Pages */ = { - isa = PBXGroup; - children = ( - D8A6FE5A293244B500666A47 /* WelcomeContentPage.swift */, - D8A6FE5E29324BBC00666A47 /* WelcomeContentCollectionViewCell.swift */, - ); - path = Pages; - sourceTree = ""; - }; D8A6FE6029325F5900666A47 /* Localization */ = { isa = PBXGroup; children = ( @@ -2053,6 +2045,7 @@ D8A6FE6029325F5900666A47 /* Localization */, ); sourceTree = ""; + tabWidth = 4; }; DB427DD325BAA00100D1B89D /* Products */ = { isa = PBXGroup; @@ -2760,9 +2753,9 @@ DBABE3F125ECAC4E00879EE5 /* View */ = { isa = PBXGroup; children = ( - D8A6FE5929323DC200666A47 /* Pages */, DBABE3EB25ECAC4B00879EE5 /* WelcomeIllustrationView.swift */, DB0617EA277EF3820030EE79 /* GradientBorderView.swift */, + D886FBD229DF710F00272017 /* WelcomeSeparatorView.swift */, ); path = View; sourceTree = ""; @@ -3259,10 +3252,10 @@ targets = ( DB427DD125BAA00100D1B89D /* Mastodon */, DB427DE725BAA00100D1B89D /* MastodonTests */, + DB8FABC526AEC7B2008E5AF4 /* MastodonIntent */, DB427DF225BAA00100D1B89D /* MastodonUITests */, DBF8AE12263293E400C9C23C /* NotificationService */, DBC6461126A170AB00B0E31B /* ShareActionExtension */, - DB8FABC526AEC7B2008E5AF4 /* MastodonIntent */, 2A64515C29642A8A00CD8B8A /* OpenInActionExtension */, 2A72811F297EA9D7004138C5 /* WidgetExtension */, ); @@ -3647,7 +3640,6 @@ DB603113279EBEBA00A935FE /* DataSourceFacade+Block.swift in Sources */, DB63F777279A9A2A00455B82 /* NotificationView+Configuration.swift in Sources */, DB029E95266A20430062874E /* MastodonAuthenticationController.swift in Sources */, - D8A6FE5F29324BBC00666A47 /* WelcomeContentCollectionViewCell.swift in Sources */, 5B90C461262599800002E742 /* SettingsLinkTableViewCell.swift in Sources */, DB6180DD263918E30018D199 /* MediaPreviewViewController.swift in Sources */, DBE3CDEC261C6B2900430CC6 /* FavoriteViewController.swift in Sources */, @@ -3803,6 +3795,7 @@ DB68A04A25E9027700CFDF14 /* AdaptiveStatusBarStyleNavigationController.swift in Sources */, 0FB3D33825E6401400AAD544 /* PickServerCell.swift in Sources */, 6213AF5C28939C8A00BCADB6 /* BookmarkViewModel+State.swift in Sources */, + D807C6C029DE197900A4E17C /* EducationViewController.swift in Sources */, DB6D9F8426358EEC008423CD /* SettingsItem.swift in Sources */, 2D364F7825E66D8300204FDC /* MastodonResendEmailViewModel.swift in Sources */, DBEFCD7B282A162400C0ABEA /* ReportReasonView.swift in Sources */, @@ -3935,9 +3928,9 @@ DB0FCB882796BDA9006C02E2 /* SearchItem.swift in Sources */, DB6180ED26391C6C0018D199 /* TransitioningMath.swift in Sources */, 2D6DE40026141DF600A63F6A /* SearchViewModel.swift in Sources */, + D886FBD329DF710F00272017 /* WelcomeSeparatorView.swift in Sources */, DB0617FD27855BFE0030EE79 /* ServerRuleItem.swift in Sources */, 5BB04FD5262E7AFF0043BFF6 /* ReportViewController.swift in Sources */, - D8A6FE5B293244B500666A47 /* WelcomeContentPage.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Mastodon/Scene/Onboarding/Welcome/EducationViewController.swift b/Mastodon/Scene/Onboarding/Welcome/EducationViewController.swift new file mode 100644 index 000000000..fa418118b --- /dev/null +++ b/Mastodon/Scene/Onboarding/Welcome/EducationViewController.swift @@ -0,0 +1,85 @@ +// Copyright © 2023 Mastodon gGmbH. All rights reserved. + +import UIKit +import MastodonLocalization + +class EducationViewController: UIViewController { + let mastodonLabel: UILabel + let mastodonExplanation: UILabel + let serversLabel: UILabel + let serversExplanation: UILabel + + private let contentStackView: UIStackView + private let contentScrollView: UIScrollView + + init() { + mastodonLabel = UILabel() + mastodonLabel.numberOfLines = 0 + mastodonLabel.adjustsFontForContentSizeCategory = true + mastodonLabel.text = L10n.Scene.Welcome.Education.Mastodon.title + mastodonLabel.font = UIFontMetrics(forTextStyle: .title2).scaledFont(for: .systemFont(ofSize: 22, weight: .bold)) + mastodonLabel.textColor = .label + + mastodonExplanation = UILabel() + mastodonExplanation.numberOfLines = 0 + mastodonExplanation.adjustsFontForContentSizeCategory = true + mastodonExplanation.text = L10n.Scene.Welcome.Education.Mastodon.description + mastodonExplanation.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) + mastodonExplanation.textColor = .label + + serversLabel = UILabel() + serversLabel.numberOfLines = 0 + serversLabel.adjustsFontForContentSizeCategory = true + serversLabel.text = L10n.Scene.Welcome.Education.Servers.title + serversLabel.font = UIFontMetrics(forTextStyle: .title2).scaledFont(for: .systemFont(ofSize: 22, weight: .bold)) + serversLabel.textColor = .label + + serversExplanation = UILabel() + serversExplanation.numberOfLines = 0 + serversExplanation.adjustsFontForContentSizeCategory = true + serversExplanation.text = L10n.Scene.Welcome.Education.Servers.description + serversExplanation.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) + serversExplanation.textColor = .label + + contentStackView = UIStackView(arrangedSubviews: [mastodonLabel, mastodonExplanation, serversLabel, serversExplanation]) + contentStackView.translatesAutoresizingMaskIntoConstraints = false + contentStackView.axis = .vertical + contentStackView.alignment = .leading + + contentStackView.setCustomSpacing(2, after: mastodonLabel) + contentStackView.setCustomSpacing(24, after: mastodonExplanation) + contentStackView.setCustomSpacing(2, after: serversLabel) + + contentScrollView = UIScrollView() + contentScrollView.translatesAutoresizingMaskIntoConstraints = false + contentScrollView.addSubview(contentStackView) + + super.init(nibName: nil, bundle: nil) + + view.addSubview(contentScrollView) + view.backgroundColor = .systemBackground + + setupConstraints() + } + + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + + private func setupConstraints() { + let constraints = [ + contentStackView.topAnchor.constraint(equalTo: contentScrollView.topAnchor, constant: 32), + contentStackView.leadingAnchor.constraint(equalTo: contentScrollView.leadingAnchor, constant: 16), + contentScrollView.trailingAnchor.constraint(equalTo: contentStackView.trailingAnchor, constant: 16), + contentScrollView.bottomAnchor.constraint(greaterThanOrEqualTo: contentStackView.bottomAnchor, constant: 32), + + contentScrollView.topAnchor.constraint(equalTo: view.topAnchor), + contentScrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + view.trailingAnchor.constraint(equalTo: contentScrollView.trailingAnchor), + view.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: contentScrollView.bottomAnchor), + + contentStackView.widthAnchor.constraint(equalTo: contentScrollView.widthAnchor, constant: -32), + + ] + + NSLayoutConstraint.activate(constraints) + } +} diff --git a/Mastodon/Scene/Onboarding/Welcome/View/Pages/WelcomeContentCollectionViewCell.swift b/Mastodon/Scene/Onboarding/Welcome/View/Pages/WelcomeContentCollectionViewCell.swift deleted file mode 100644 index 06bad0df0..000000000 --- a/Mastodon/Scene/Onboarding/Welcome/View/Pages/WelcomeContentCollectionViewCell.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// WelcomeContentPageView.swift -// Mastodon -// -// Created by Nathan Mattes on 26.11.22. -// - -import UIKit - -class WelcomeContentCollectionViewCell: UICollectionViewCell { - - static let identifier = "WelcomeContentCollectionViewCell" - - //TODO: Put in ScrollView? - private let contentStackView: UIStackView - private let titleView: UILabel - private let label: UILabel - - override init(frame: CGRect) { - titleView = UILabel() - titleView.font = WelcomeViewController.largeTitleFont - titleView.textColor = WelcomeViewController.largeTitleTextColor.resolvedColor(with: UITraitCollection(userInterfaceStyle: .light)) - titleView.adjustsFontForContentSizeCategory = true - titleView.numberOfLines = 0 - - label = UILabel() - label.font = WelcomeViewController.subTitleFont - label.textColor = WelcomeViewController.largeTitleTextColor.resolvedColor(with: UITraitCollection(userInterfaceStyle: .light)) - label.adjustsFontForContentSizeCategory = true - label.numberOfLines = 0 - - contentStackView = UIStackView(arrangedSubviews: [titleView, label, UIView()]) - contentStackView.translatesAutoresizingMaskIntoConstraints = false - contentStackView.axis = .vertical - contentStackView.alignment = .leading - contentStackView.spacing = 8 - - super.init(frame: frame) - - 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), - contentStackView.bottomAnchor.constraint(equalTo: bottomAnchor), - trailingAnchor.constraint(equalTo: contentStackView.trailingAnchor, constant: 16), - bottomAnchor.constraint(greaterThanOrEqualTo: contentStackView.bottomAnchor), - ] - - NSLayoutConstraint.activate(constraints) - } - - private func updateAccessibility() { - accessibilityLabel = "\(titleView.accessibilityLabel ?? ""), \(label.accessibilityLabel ?? "")" - isAccessibilityElement = true - } - - func update(with page: WelcomeContentPage) { - titleView.attributedText = page.title - titleView.accessibilityLabel = page.accessibilityLabel - label.text = page.content - updateAccessibility() - } -} diff --git a/Mastodon/Scene/Onboarding/Welcome/View/Pages/WelcomeContentPage.swift b/Mastodon/Scene/Onboarding/Welcome/View/Pages/WelcomeContentPage.swift deleted file mode 100644 index 1e6ac3cef..000000000 --- a/Mastodon/Scene/Onboarding/Welcome/View/Pages/WelcomeContentPage.swift +++ /dev/null @@ -1,74 +0,0 @@ -// -// WelcomeContentPage.swift -// Mastodon -// -// Created by Nathan Mattes on 26.11.22. -// - -import UIKit -import MastodonLocalization -import MastodonAsset - -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: NSAttributedString { - switch self { - case .whatIsMastodon: - let image = Asset.Scene.Welcome.mastodonLogo.image - let attachment = NSTextAttachment(image: image) - let attributedString = NSMutableAttributedString(string: "\(L10n.Scene.Welcome.Education.WhatIsMastodon.title) ") - - attachment.bounds = CGRect( - x: 0, - y: WelcomeViewController.largeTitleFont.descender - 5, - width: image.size.width, - height: image.size.height - ) - - attributedString.append(NSAttributedString(attachment: attachment)) - attributedString.append(NSAttributedString(string: " ?")) - return attributedString - case .mastodonIsLikeThat: - return NSAttributedString(string: L10n.Scene.Welcome.Education.MastodonIsLikeThat.title) - case .howDoIPickAServer: - return NSAttributedString(string: L10n.Scene.Welcome.Education.HowDoIPickAServer.title) - } - } - - var accessibilityLabel: String { - switch self { - case .whatIsMastodon: - return L10n.Scene.Welcome.Education.A11Y.WhatIsMastodon.title - case .mastodonIsLikeThat: - return L10n.Scene.Welcome.Education.MastodonIsLikeThat.title - case .howDoIPickAServer: - return L10n.Scene.Welcome.Education.HowDoIPickAServer.title - } - } - - var content: String { - switch self { - case .whatIsMastodon: - return L10n.Scene.Welcome.Education.WhatIsMastodon.description - case .mastodonIsLikeThat: - return L10n.Scene.Welcome.Education.MastodonIsLikeThat.description - case .howDoIPickAServer: - return L10n.Scene.Welcome.Education.HowDoIPickAServer.description - } - - } -} diff --git a/Mastodon/Scene/Onboarding/Welcome/View/WelcomeIllustrationView.swift b/Mastodon/Scene/Onboarding/Welcome/View/WelcomeIllustrationView.swift index 3f9d73509..11a51cfeb 100644 --- a/Mastodon/Scene/Onboarding/Welcome/View/WelcomeIllustrationView.swift +++ b/Mastodon/Scene/Onboarding/Welcome/View/WelcomeIllustrationView.swift @@ -13,10 +13,9 @@ import MastodonLocalization fileprivate extension CGFloat { static let cloudsStartPosition = -20.0 - static let centerHillStartPosition = 20.0 static let airplaneStartPosition = -178.0 static let leftHillStartPosition = 30.0 - static let rightHillStartPosition = -200.0 + static let rightHillStartPosition = -125.0 static let leftHillSpeed = 6.0 static let centerHillSpeed = 40.0 static let rightHillSpeed = 6.0 @@ -25,18 +24,11 @@ fileprivate extension CGFloat { final class WelcomeIllustrationView: UIView { 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 - var cloudsLeftAnchor: NSLayoutConstraint? - var elephantOnAirplaneLeftConstraint: NSLayoutConstraint? - var leftHillLeftConstraint: NSLayoutConstraint? - var centerHillLeftConstraint: NSLayoutConstraint? - var rightHillRightConstraint: NSLayoutConstraint? - let elephantOnAirplaneWithContrailImageView: UIImageView = { let imageView = UIImageView(image: Asset.Scene.Welcome.Illustration.elephantOnAirplaneWithContrail.image) imageView.translatesAutoresizingMaskIntoConstraints = false @@ -69,7 +61,7 @@ final class WelcomeIllustrationView: UIView { let imageView = UIImageView(image: Asset.Scene.Welcome.Illustration.cloudBase.image) imageView.translatesAutoresizingMaskIntoConstraints = false imageView.contentMode = .scaleAspectFill - imageView.alpha = 0.3 +// imageView.alpha = 0.3 return imageView }() @@ -97,57 +89,44 @@ extension WelcomeIllustrationView { cloudBaseImageView.translatesAutoresizingMaskIntoConstraints = false addSubview(cloudBaseImageView) - - let cloudsLeftAnchor = cloudBaseImageView.leftAnchor.constraint(equalTo: leftAnchor, constant: .cloudsStartPosition) + NSLayoutConstraint.activate([ - cloudsLeftAnchor, - cloudBaseImageView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 1.4), + cloudBaseImageView.leftAnchor.constraint(equalTo: leftAnchor), + cloudBaseImageView.trailingAnchor.constraint(equalTo: trailingAnchor), cloudBaseImageView.bottomAnchor.constraint(equalTo: bottomAnchor), cloudBaseImageView.topAnchor.constraint(equalTo: topAnchor) ]) - self.cloudsLeftAnchor = cloudsLeftAnchor - let rightHillRightConstraint = rightAnchor.constraint(equalTo: rightHillImageView.rightAnchor, constant: .rightHillStartPosition) addSubview(rightHillImageView) NSLayoutConstraint.activate([ rightHillImageView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.64), - rightHillRightConstraint, + rightAnchor.constraint(equalTo: rightHillImageView.rightAnchor, constant: .rightHillStartPosition), bottomAnchor.constraint(equalTo: rightHillImageView.bottomAnchor, constant: 149), ]) - self.rightHillRightConstraint = rightHillRightConstraint - - let leftHillLeftConstraint = leftAnchor.constraint(equalTo: leftHillImageView.leftAnchor, constant: .leftHillStartPosition) + addSubview(leftHillImageView) NSLayoutConstraint.activate([ leftHillImageView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.72), - leftHillLeftConstraint, + leftAnchor.constraint(equalTo: leftHillImageView.leftAnchor, constant: .leftHillStartPosition), bottomAnchor.constraint(equalTo: leftHillImageView.bottomAnchor, constant: 187), ]) - - self.leftHillLeftConstraint = leftHillLeftConstraint - - let centerHillLeftConstraint = leftAnchor.constraint(equalTo: centerHillImageView.leftAnchor, constant: .centerHillStartPosition) - + + addSubview(elephantOnAirplaneWithContrailImageView) + addSubview(centerHillImageView) NSLayoutConstraint.activate([ - centerHillLeftConstraint, - bottomAnchor.constraint(equalTo: centerHillImageView.bottomAnchor, constant: -18), - centerHillImageView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 1.2), + leftAnchor.constraint(equalTo: centerHillImageView.leftAnchor), + bottomAnchor.constraint(equalTo: centerHillImageView.bottomAnchor), + rightAnchor.constraint(equalTo: centerHillImageView.rightAnchor), ]) - - self.centerHillLeftConstraint = centerHillLeftConstraint - - addSubview(elephantOnAirplaneWithContrailImageView) - - let elephantOnAirplaneLeftConstraint = elephantOnAirplaneWithContrailImageView.leftAnchor.constraint(equalTo: leftAnchor, constant: .airplaneStartPosition) // add 12pt bleeding + NSLayoutConstraint.activate([ - elephantOnAirplaneLeftConstraint, + elephantOnAirplaneWithContrailImageView.leftAnchor.constraint(equalTo: leftAnchor, constant: .airplaneStartPosition), elephantOnAirplaneWithContrailImageView.bottomAnchor.constraint(equalTo: leftHillImageView.topAnchor), // make a little bit large elephantOnAirplaneWithContrailImageView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.84), ]) - self.elephantOnAirplaneLeftConstraint = elephantOnAirplaneLeftConstraint } func setup() { @@ -175,12 +154,4 @@ extension WelcomeIllustrationView { UIInterpolatingMotionEffect.motionEffect(minX: -20, maxX: 12, minY: -20, maxY: 12) // maxX should not larger then the bleeding (12pt) ) } - - func update(contentOffset: CGFloat) { - cloudsLeftAnchor?.constant = contentOffset / cloudsDrag + .cloudsStartPosition - elephantOnAirplaneLeftConstraint?.constant = contentOffset / airplaneDrag + .airplaneStartPosition - leftHillLeftConstraint?.constant = contentOffset / .leftHillSpeed + .leftHillStartPosition - centerHillLeftConstraint?.constant = contentOffset / .centerHillSpeed + .centerHillStartPosition - rightHillRightConstraint?.constant = contentOffset / .rightHillSpeed + .rightHillStartPosition - } } diff --git a/Mastodon/Scene/Onboarding/Welcome/View/WelcomeSeparatorView.swift b/Mastodon/Scene/Onboarding/Welcome/View/WelcomeSeparatorView.swift new file mode 100644 index 000000000..b7d18d058 --- /dev/null +++ b/Mastodon/Scene/Onboarding/Welcome/View/WelcomeSeparatorView.swift @@ -0,0 +1,60 @@ +// Copyright © 2023 Mastodon gGmbH. All rights reserved. + +import UIKit +import MastodonLocalization + +class WelcomeSeparatorView: UIView { + let leftLine: UIView + let rightLine: UIView + let label: UILabel + + override init(frame: CGRect) { + leftLine = UIView() + leftLine.translatesAutoresizingMaskIntoConstraints = false + leftLine.backgroundColor = UIColor.white.withAlphaComponent(0.6) + rightLine = UIView() + rightLine.translatesAutoresizingMaskIntoConstraints = false + rightLine.backgroundColor = UIColor.white.withAlphaComponent(0.6) + + label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.adjustsFontForContentSizeCategory = true + label.text = L10n.Scene.Welcome.Separator.or.uppercased() + label.font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .semibold)) + label.textColor = UIColor.white.withAlphaComponent(0.6) + + super.init(frame: frame) + + addSubview(leftLine) + addSubview(label) + addSubview(rightLine) + + setupConstraints() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupConstraints() { + let constraints = [ + + label.topAnchor.constraint(equalTo: topAnchor), + bottomAnchor.constraint(equalTo: label.bottomAnchor), + label.centerXAnchor.constraint(equalTo: centerXAnchor), + label.centerYAnchor.constraint(equalTo: centerYAnchor), + leftLine.leadingAnchor.constraint(equalTo: leadingAnchor), + label.leadingAnchor.constraint(equalTo: leftLine.trailingAnchor, constant: 8), + leftLine.centerYAnchor.constraint(equalTo: centerYAnchor), + + rightLine.leadingAnchor.constraint(equalTo: label.trailingAnchor, constant: 8), + trailingAnchor.constraint(equalTo: rightLine.trailingAnchor), + rightLine.centerYAnchor.constraint(equalTo: centerYAnchor), + + leftLine.heightAnchor.constraint(equalToConstant: 1), + rightLine.heightAnchor.constraint(equalTo: leftLine.heightAnchor), + + ] + NSLayoutConstraint.activate(constraints) + } +} diff --git a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift index 6518d98db..d6e27a20d 100644 --- a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift +++ b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift @@ -10,6 +10,7 @@ import Combine import MastodonAsset import MastodonCore import MastodonLocalization +import MastodonSDK final class WelcomeViewController: UIViewController, NeedsDependency { @@ -19,68 +20,111 @@ final class WelcomeViewController: UIViewController, NeedsDependency { weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } - + + private(set) lazy var authenticationViewModel = AuthenticationViewModel( + context: context, + coordinator: coordinator, + isAuthenticationExist: false + ) + var disposeBag = Set() var observations = Set() private(set) lazy var viewModel = WelcomeViewModel(context: context) let welcomeIllustrationView = WelcomeIllustrationView() - + let separatorView = WelcomeSeparatorView(frame: .zero) + + private(set) lazy var mastodonLogo: UIImageView = { + let imageView = UIImageView(image: Asset.Scene.Welcome.mastodonLogo.image) + return imageView + }() + + + //TODO: Extract all those UI-elements in a UIView-subclass private(set) lazy var dismissBarButtonItem = UIBarButtonItem(barButtonSystemItem: .close, target: self, action: #selector(WelcomeViewController.dismissBarButtonItemDidPressed(_:))) let buttonContainer = UIStackView() - let educationPages: [WelcomeContentPage] = [.whatIsMastodon, .mastodonIsLikeThat, .howDoIPickAServer] - - 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) + + private(set) lazy var joinDefaultServerButton: UIButton = { + var buttonConfiguration = UIButton.Configuration.filled() + buttonConfiguration.attributedTitle = AttributedString( + L10n.Scene.Welcome.joinDefaultServer, + attributes: .init([.font: UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold))]) + ) + buttonConfiguration.baseForegroundColor = .white + buttonConfiguration.background.backgroundColor = Asset.Colors.Brand.blurple.color + buttonConfiguration.background.cornerRadius = 14 + buttonConfiguration.activityIndicatorColorTransformer = UIConfigurationColorTransformer({ _ in + return UIColor.white + }) + + buttonConfiguration.contentInsets = .init(top: WelcomeViewController.actionButtonPadding.top, + leading: WelcomeViewController.actionButtonPadding.left, + bottom: WelcomeViewController.actionButtonPadding.bottom, + trailing: WelcomeViewController.actionButtonPadding.right) + + let button = UIButton(configuration: buttonConfiguration) + return button }() - let signUpButtonShadowView = UIView() - + + private(set) lazy var signUpButton: UIButton = { + + var buttonConfiguration = UIButton.Configuration.borderedTinted() + buttonConfiguration.attributedTitle = AttributedString( + L10n.Scene.Welcome.pickServer, + attributes: .init([.font: UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold))]) + ) + + buttonConfiguration.background.cornerRadius = 14 + buttonConfiguration.background.strokeColor = UIColor.white.withAlphaComponent(0.6) + buttonConfiguration.background.strokeWidth = 1 + buttonConfiguration.baseBackgroundColor = .clear + buttonConfiguration.baseForegroundColor = .white + + buttonConfiguration.contentInsets = .init(top: WelcomeViewController.actionButtonPadding.top, + leading: WelcomeViewController.actionButtonPadding.left, + bottom: WelcomeViewController.actionButtonPadding.bottom, + trailing: WelcomeViewController.actionButtonPadding.right) + + let button = UIButton(configuration: buttonConfiguration) + + return button + }() + private(set) lazy var signInButton: UIButton = { - let button = UIButton() - 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 titleColor: UIColor = UIColor.white.withAlphaComponent(0.9) - button.setTitleColor(titleColor, for: .normal) - button.setTitleColor(titleColor.withAlphaComponent(0.3), for: .highlighted) + var buttonConfiguration = UIButton.Configuration.plain() + buttonConfiguration.baseForegroundColor = .white + buttonConfiguration.attributedTitle = AttributedString( + L10n.Scene.Welcome.logIn, + attributes: .init([.font: UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold))]) + ) + + let button = UIButton(configuration: buttonConfiguration) return button }() - - private(set) lazy var pageCollectionView: UICollectionView = { - let flowLayout = UICollectionViewFlowLayout() - flowLayout.scrollDirection = .horizontal - flowLayout.minimumLineSpacing = 0 - flowLayout.itemSize = CGSize(width: self.view.frame.width, height: 400) - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout) - collectionView.translatesAutoresizingMaskIntoConstraints = false - collectionView.isPagingEnabled = true - collectionView.backgroundColor = nil - collectionView.showsHorizontalScrollIndicator = false - collectionView.bounces = false - collectionView.register(WelcomeContentCollectionViewCell.self, forCellWithReuseIdentifier: WelcomeContentCollectionViewCell.identifier) + private(set) lazy var learnMoreButton: UIButton = { + var buttonConfiguration = UIButton.Configuration.plain() + buttonConfiguration.baseForegroundColor = .white + buttonConfiguration.attributedTitle = AttributedString( + L10n.Scene.Welcome.learnMore, + attributes: .init([.font: UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold))]) + ) - return collectionView + let button = UIButton(configuration: buttonConfiguration) + return button }() - private(set) var pageControl: UIPageControl = { - let pageControl = UIPageControl(frame: .zero) - pageControl.backgroundStyle = .prominent - pageControl.translatesAutoresizingMaskIntoConstraints = false - return pageControl + private(set) lazy var bottomButtonStackView: UIStackView = { + let bottomButtonStackView = UIStackView(arrangedSubviews: [learnMoreButton, signInButton]) + bottomButtonStackView.axis = .horizontal + bottomButtonStackView.distribution = .fill + bottomButtonStackView.alignment = .center + bottomButtonStackView.spacing = 16 + bottomButtonStackView.setContentHuggingPriority(.required, for: .vertical) + + return bottomButtonStackView }() } @@ -98,15 +142,17 @@ extension WelcomeViewController { view.overrideUserInterfaceStyle = .light setupOnboardingAppearance() - + view.addSubview(welcomeIllustrationView) welcomeIllustrationView.translatesAutoresizingMaskIntoConstraints = false + + mastodonLogo.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(mastodonLogo) NSLayoutConstraint.activate([ - welcomeIllustrationView.topAnchor.constraint(equalTo: view.topAnchor), - welcomeIllustrationView.leadingAnchor.constraint(equalTo: view.leadingAnchor), - view.trailingAnchor.constraint(equalTo: welcomeIllustrationView.trailingAnchor), - view.bottomAnchor.constraint(equalTo: welcomeIllustrationView.bottomAnchor) + mastodonLogo.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 24), + mastodonLogo.centerXAnchor.constraint(equalTo: view.centerXAnchor), + mastodonLogo.widthAnchor.constraint(equalToConstant: 300), ]) buttonContainer.axis = .vertical @@ -120,48 +166,47 @@ extension WelcomeViewController { buttonContainer.trailingAnchor.constraint(equalTo: view.readableContentGuide.trailingAnchor), view.layoutMarginsGuide.bottomAnchor.constraint(equalTo: buttonContainer.bottomAnchor), ]) + + joinDefaultServerButton.translatesAutoresizingMaskIntoConstraints = false + buttonContainer.addArrangedSubview(joinDefaultServerButton) + NSLayoutConstraint.activate([ + joinDefaultServerButton.heightAnchor.constraint(greaterThanOrEqualToConstant: WelcomeViewController.actionButtonHeight) + ]) signUpButton.translatesAutoresizingMaskIntoConstraints = false buttonContainer.addArrangedSubview(signUpButton) NSLayoutConstraint.activate([ - signUpButton.heightAnchor.constraint(greaterThanOrEqualToConstant: WelcomeViewController.actionButtonHeight).priority(.required - 1), + signUpButton.heightAnchor.constraint(greaterThanOrEqualToConstant: WelcomeViewController.actionButtonHeight) ]) + + buttonContainer.addArrangedSubview(separatorView) + 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) - - signUpButton.addTarget(self, action: #selector(signUpButtonDidClicked(_:)), for: .touchUpInside) - signInButton.addTarget(self, action: #selector(signInButtonDidClicked(_:)), for: .touchUpInside) - - pageCollectionView.delegate = self - pageCollectionView.dataSource = self - view.addSubview(pageCollectionView) - - pageControl.numberOfPages = self.educationPages.count - pageControl.addTarget(self, action: #selector(WelcomeViewController.pageControlDidChange(_:)), for: .valueChanged) - view.addSubview(pageControl) - - let scrollView = pageCollectionView as UIScrollView - scrollView.delegate = self - - NSLayoutConstraint.activate([ - pageCollectionView.topAnchor.constraint(equalTo: view.topAnchor), - pageCollectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor), - view.trailingAnchor.constraint(equalTo: pageCollectionView.trailingAnchor), - pageControl.topAnchor.constraint(equalTo: pageCollectionView.bottomAnchor, constant: 16), - - pageControl.leadingAnchor.constraint(equalTo: view.leadingAnchor), - view.trailingAnchor.constraint(equalTo: pageControl.trailingAnchor), - buttonContainer.topAnchor.constraint(equalTo: pageControl.bottomAnchor, constant: 16), + signInButton.heightAnchor.constraint(greaterThanOrEqualToConstant: WelcomeViewController.actionButtonHeight) ]) + learnMoreButton.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + learnMoreButton.heightAnchor.constraint(greaterThanOrEqualToConstant: WelcomeViewController.actionButtonHeight), + bottomButtonStackView.heightAnchor.constraint(equalTo: learnMoreButton.heightAnchor), + ]) + + buttonContainer.addArrangedSubview(bottomButtonStackView) + + NSLayoutConstraint.activate([ + welcomeIllustrationView.topAnchor.constraint(equalTo: view.topAnchor), + welcomeIllustrationView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + view.trailingAnchor.constraint(equalTo: welcomeIllustrationView.trailingAnchor), + separatorView.centerYAnchor.constraint(equalTo: welcomeIllustrationView.bottomAnchor) + ]) + + joinDefaultServerButton.addTarget(self, action: #selector(joinDefaultServer(_:)), for: .touchUpInside) + signUpButton.addTarget(self, action: #selector(signUp(_:)), for: .touchUpInside) + signInButton.addTarget(self, action: #selector(signIn(_:)), for: .touchUpInside) + learnMoreButton.addTarget(self, action: #selector(learnMore(_:)), for: .touchUpInside) + + view.backgroundColor = Asset.Scene.Welcome.Illustration.backgroundGreen.color viewModel.$needsShowDismissEntry .receive(on: DispatchQueue.main) @@ -172,12 +217,7 @@ extension WelcomeViewController { .store(in: &disposeBag) } - override func viewDidLayoutSubviews() { - super.viewDidLayoutSubviews() - - setupButtonShadowView() - } - + override func viewSafeAreaInsetsDidChange() { super.viewSafeAreaInsetsDidChange() @@ -194,14 +234,6 @@ extension WelcomeViewController { view.layoutIfNeeded() setupIllustrationLayout() - setupButtonShadowView() - - let flowLayout = UICollectionViewFlowLayout() - flowLayout.scrollDirection = .horizontal - flowLayout.minimumLineSpacing = 0 - flowLayout.itemSize = CGSize(width: self.view.frame.width, height: 400) - - pageCollectionView.setCollectionViewLayout(flowLayout, animated: true) } private var computedTopAnchorInset: CGFloat { @@ -210,28 +242,14 @@ extension WelcomeViewController { } 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 updateButtonContainerLayoutMargins(traitCollection: UITraitCollection) { switch traitCollection.userInterfaceIdiom { case .phone: buttonContainer.layoutMargins = UIEdgeInsets( top: 0, left: WelcomeViewController.actionButtonMargin, - bottom: WelcomeViewController.viewBottomPaddingHeight, + bottom: 0, right: WelcomeViewController.actionButtonMargin ) default: @@ -239,7 +257,7 @@ extension WelcomeViewController { buttonContainer.layoutMargins = UIEdgeInsets( top: 0, left: margin, - bottom: WelcomeViewController.viewBottomPaddingHeightExtend, + bottom: 0, right: margin ) } @@ -254,27 +272,132 @@ extension WelcomeViewController { //MARK: - Actions @objc - private func signUpButtonDidClicked(_ sender: UIButton) { + private func joinDefaultServer(_ sender: UIButton) { + sender.configuration?.title = nil + sender.isEnabled = false + sender.configuration?.showsActivityIndicator = true + + let server = Mastodon.Entity.Server.mastodonDotSocial + + authenticationViewModel.isAuthenticating.send(true) + + context.apiService.instance(domain: server.domain) + .compactMap { [weak self] response -> AnyPublisher? in + guard let self = self else { return nil } + guard response.value.registrations != false else { + return Fail(error: AuthenticationViewModel.AuthenticationError.registrationClosed).eraseToAnyPublisher() + } + return self.context.apiService.createApplication(domain: server.domain) + .map { MastodonPickServerViewModel.SignUpResponseFirst(instance: response, application: $0) } + .eraseToAnyPublisher() + } + .switchToLatest() + .tryMap { response -> MastodonPickServerViewModel.SignUpResponseSecond in + let application = response.application.value + guard let authenticateInfo = AuthenticationViewModel.AuthenticateInfo( + domain: server.domain, + application: application + ) else { + throw APIService.APIError.explicit(.badResponse) + } + return MastodonPickServerViewModel.SignUpResponseSecond( + instance: response.instance, + authenticateInfo: authenticateInfo + ) + } + .compactMap { [weak self] response -> AnyPublisher? in + guard let self = self else { return nil } + let instance = response.instance + let authenticateInfo = response.authenticateInfo + return self.context.apiService.applicationAccessToken( + domain: server.domain, + clientID: authenticateInfo.clientID, + clientSecret: authenticateInfo.clientSecret, + redirectURI: authenticateInfo.redirectURI + ) + .map { + MastodonPickServerViewModel.SignUpResponseThird( + instance: instance, + authenticateInfo: authenticateInfo, + applicationToken: $0 + ) + } + .eraseToAnyPublisher() + } + .switchToLatest() + .receive(on: DispatchQueue.main) + .sink { [weak self] completion in + guard let self = self else { return } + self.authenticationViewModel.isAuthenticating.send(false) + + switch completion { + case .failure(let error): + //TODO: show an alert or something + break + case .finished: + break + } + + sender.isEnabled = true + sender.configuration?.showsActivityIndicator = false + sender.configuration?.attributedTitle = AttributedString( + L10n.Scene.Welcome.joinDefaultServer, + attributes: .init([.font: UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold))]) + ) + } receiveValue: { [weak self] response in + guard let self = self else { return } + if let rules = response.instance.value.rules, !rules.isEmpty { + // show server rules before register + let mastodonServerRulesViewModel = MastodonServerRulesViewModel( + domain: server.domain, + authenticateInfo: response.authenticateInfo, + rules: rules, + instance: response.instance.value, + applicationToken: response.applicationToken.value + ) + _ = self.coordinator.present(scene: .mastodonServerRules(viewModel: mastodonServerRulesViewModel), from: self, transition: .show) + } else { + let mastodonRegisterViewModel = MastodonRegisterViewModel( + context: self.context, + domain: server.domain, + authenticateInfo: response.authenticateInfo, + instance: response.instance.value, + applicationToken: response.applicationToken.value + ) + _ = self.coordinator.present(scene: .mastodonRegister(viewModel: mastodonRegisterViewModel), from: nil, transition: .show) + } + } + .store(in: &disposeBag) + + } + + @objc + private func signUp(_ sender: UIButton) { _ = coordinator.present(scene: .mastodonPickServer(viewMode: MastodonPickServerViewModel(context: context)), from: self, transition: .show) } @objc - private func signInButtonDidClicked(_ sender: UIButton) { + private func signIn(_ sender: UIButton) { _ = coordinator.present(scene: .mastodonLogin, from: self, transition: .show) } - + + @objc + private func learnMore(_ sender: UIButton) { + let educationViewController = EducationViewController() + educationViewController.modalPresentationStyle = .pageSheet + + if let sheetPresentationController = educationViewController.sheetPresentationController { + sheetPresentationController.detents = [.medium()] + sheetPresentationController.prefersGrabberVisible = true + } + + present(educationViewController, animated: true) + } + @objc private func dismissBarButtonItemDidPressed(_ sender: UIButton) { dismiss(animated: true, completion: nil) } - - @objc - private func pageControlDidChange(_ sender: UIPageControl) { - let item = sender.currentPage - let indexPath = IndexPath(item: item, section: 0) - - pageCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: false) - } } // MARK: - OnboardingViewControllerAppearance @@ -316,37 +439,5 @@ extension WelcomeViewController: UIAdaptivePresentationControllerDelegate { } } -//MARK: - UIScrollViewDelegate -extension WelcomeViewController: UIScrollViewDelegate { - func scrollViewDidScroll(_ scrollView: UIScrollView) { - let contentOffset = scrollView.contentOffset.x - welcomeIllustrationView.update(contentOffset: contentOffset) - } - - func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { - pageControl.currentPage = Int(scrollView.contentOffset.x) / Int(scrollView.frame.width) - } - - func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { - pageControl.currentPage = Int(scrollView.contentOffset.x) / Int(scrollView.frame.width) - } -} - //MARK: - UICollectionViewDelegate extension WelcomeViewController: UICollectionViewDelegate { } - -//MARK: - UICollectionViewDataSource -extension WelcomeViewController: UICollectionViewDataSource { - func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - educationPages.count - } - - func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: WelcomeContentCollectionViewCell.identifier, for: indexPath) as? WelcomeContentCollectionViewCell else { fatalError("WTF? Wrong cell?") } - - let page = educationPages[indexPath.item] - cell.update(with: page) - - return cell - } -} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/sign.in.button.background.colorset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/background.green.colorset/Contents.json similarity index 74% rename from MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/sign.in.button.background.colorset/Contents.json rename to MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/background.green.colorset/Contents.json index 4872f3188..5c8d4522b 100644 --- a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/sign.in.button.background.colorset/Contents.json +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/background.green.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0.506", - "green" : "0.675", - "red" : "0.345" + "blue" : "0.416", + "green" : "0.557", + "red" : "0.278" } }, "idiom" : "universal" diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/Contents.json index 16dc17794..e0e581c0a 100644 --- a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/Contents.json +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/Contents.json @@ -1,17 +1,17 @@ { "images" : [ { - "filename" : "untitled10007Group61.png", + "filename" : "Untitled-1_0007_Group-6 1.png", "idiom" : "universal", "scale" : "1x" }, { - "filename" : "untitled10007Group61@2x.png", + "filename" : "Untitled-1_0007_Group-6 1@2x.png", "idiom" : "universal", "scale" : "2x" }, { - "filename" : "untitled10007Group61@3x.png", + "filename" : "Untitled-1_0007_Group-6 1@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/Untitled-1_0007_Group-6 1.png b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/Untitled-1_0007_Group-6 1.png new file mode 100644 index 000000000..47cf6940f Binary files /dev/null and b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/Untitled-1_0007_Group-6 1.png differ diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/Untitled-1_0007_Group-6 1@2x.png b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/Untitled-1_0007_Group-6 1@2x.png new file mode 100644 index 000000000..18d1014fc Binary files /dev/null and b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/Untitled-1_0007_Group-6 1@2x.png differ diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/Untitled-1_0007_Group-6 1@3x.png b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/Untitled-1_0007_Group-6 1@3x.png new file mode 100644 index 000000000..eaf8100b5 Binary files /dev/null and b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/Untitled-1_0007_Group-6 1@3x.png differ diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/untitled10007Group61.png b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/untitled10007Group61.png deleted file mode 100644 index fa4dba30a..000000000 Binary files a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/untitled10007Group61.png and /dev/null differ diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/untitled10007Group61@2x.png b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/untitled10007Group61@2x.png deleted file mode 100644 index c96857b07..000000000 Binary files a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/untitled10007Group61@2x.png and /dev/null differ diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/untitled10007Group61@3x.png b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/untitled10007Group61@3x.png deleted file mode 100644 index 90ac897c4..000000000 Binary files a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/cloud.base.imageset/untitled10007Group61@3x.png and /dev/null differ diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/Contents.json index e3c65df44..0c8420c00 100644 --- a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/Contents.json +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/Contents.json @@ -1,17 +1,17 @@ { "images" : [ { - "filename" : "untitled10003Group11.png", + "filename" : "Untitled-1_0003_Group-1 1.png", "idiom" : "universal", "scale" : "1x" }, { - "filename" : "untitled10003Group11@2x.png", + "filename" : "Untitled-1_0003_Group-1 1@2x.png", "idiom" : "universal", "scale" : "2x" }, { - "filename" : "untitled10003Group11@3x.png", + "filename" : "Untitled-1_0003_Group-1 1@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/Untitled-1_0003_Group-1 1.png b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/Untitled-1_0003_Group-1 1.png new file mode 100644 index 000000000..d42b0d166 Binary files /dev/null and b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/Untitled-1_0003_Group-1 1.png differ diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/Untitled-1_0003_Group-1 1@2x.png b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/Untitled-1_0003_Group-1 1@2x.png new file mode 100644 index 000000000..9c89ab1b5 Binary files /dev/null and b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/Untitled-1_0003_Group-1 1@2x.png differ diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/Untitled-1_0003_Group-1 1@3x.png b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/Untitled-1_0003_Group-1 1@3x.png new file mode 100644 index 000000000..8d8cf7dd7 Binary files /dev/null and b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/Untitled-1_0003_Group-1 1@3x.png differ diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/untitled10003Group11.png b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/untitled10003Group11.png deleted file mode 100644 index f18ac92ed..000000000 Binary files a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/untitled10003Group11.png and /dev/null differ diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/untitled10003Group11@2x.png b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/untitled10003Group11@2x.png deleted file mode 100644 index d738223a2..000000000 Binary files a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/untitled10003Group11@2x.png and /dev/null differ diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/untitled10003Group11@3x.png b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/untitled10003Group11@3x.png deleted file mode 100644 index f3688b8f5..000000000 Binary files a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/illustration/elephant.three.on.grass.imageset/untitled10003Group11@3x.png and /dev/null differ diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/Contents.json index 087aec8bf..0c38a8646 100644 --- a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/Contents.json +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/Contents.json @@ -1,19 +1,8 @@ { "images" : [ { - "filename" : "wordmark-white-text.01e9f493 1.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "filename" : "wordmark-white-text.01e9f493 1@2x.png", - "idiom" : "universal", - "scale" : "2x" - }, - { - "filename" : "wordmark-white-text.01e9f493 1@3x.png", - "idiom" : "universal", - "scale" : "3x" + "filename" : "mastodon_logo.pdf", + "idiom" : "universal" } ], "info" : { diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/mastodon_logo.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/mastodon_logo.pdf new file mode 100644 index 000000000..9c51046b2 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/mastodon_logo.pdf @@ -0,0 +1,384 @@ +%PDF-1.7 + +1 0 obj + << /Length 2 0 R + /Range [ 0.000000 1.000000 0.000000 1.000000 0.000000 1.000000 ] + /Domain [ 0.000000 1.000000 ] + /FunctionType 4 + >> +stream +{ 0.388235 exch 0.392157 exch 1.000000 exch dup 0.000000 gt { exch pop exch pop exch pop dup 0.000000 sub -0.050980 mul 0.388235 add exch dup 0.000000 sub -0.164706 mul 0.392157 add exch dup 0.000000 sub -0.200000 mul 1.000000 add exch } if dup 1.000000 gt { exch pop exch pop exch pop 0.337255 exch 0.227451 exch 0.800000 exch } if pop } +endstream +endobj + +2 0 obj + 339 +endobj + +3 0 obj + << /Type /XObject + /Length 4 0 R + /Group << /Type /Group + /S /Transparency + >> + /Subtype /Form + /Resources << /Pattern << /P1 << /Matrix [ 0.000000 -75.233063 75.233063 0.000000 -75.233063 76.115967 ] + /Shading << /Coords [ 0.000000 0.000000 1.000000 0.000000 ] + /ColorSpace /DeviceRGB + /Function 1 0 R + /Domain [ 0.000000 1.000000 ] + /ShadingType 2 + /Extend [ true true ] + >> + /PatternType 2 + /Type /Pattern + >> >> >> + /BBox [ 0.000000 0.000000 299.000000 77.000000 ] + >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 0.000000 0.200195 cm +/Pattern cs +/P1 scn +69.682762 59.260414 m +68.604645 67.339211 61.618645 73.716652 53.348095 74.943527 c +51.948719 75.151863 46.660526 75.915771 34.409454 75.915771 c +34.317654 75.915771 l +22.055214 75.915771 19.428312 75.151863 18.028839 74.943527 c +9.976187 73.739799 2.634763 68.022095 0.845287 59.839058 c +-0.003568 55.811195 -0.095337 51.343483 0.065258 47.246231 c +0.294677 41.366470 0.340562 35.509907 0.868228 29.653252 c +1.235300 25.764275 1.866209 21.909996 2.772418 18.113708 c +4.470126 11.099670 11.329807 5.266113 18.051863 2.893471 c +25.244102 0.416542 32.987148 -0.000023 40.397285 1.701393 c +41.211750 1.898071 42.014755 2.117950 42.817757 2.372620 c +44.618729 2.951355 46.729305 3.599487 48.289360 4.733765 c +48.312382 4.745361 48.323845 4.768463 48.335308 4.791656 c +48.346771 4.814758 48.358234 4.837959 48.358234 4.872749 c +48.358234 10.544128 l +48.358234 10.544128 48.358234 10.590431 48.335308 10.613525 c +48.335308 10.636627 48.312382 10.659821 48.289360 10.671417 c +48.266434 10.682922 48.243507 10.694611 48.220676 10.706116 c +48.197556 10.706116 48.174725 10.706116 48.151798 10.706116 c +43.402664 9.560242 38.527630 8.981506 33.652401 8.993103 c +25.244101 8.993103 22.984310 13.021061 22.341986 14.687683 c +21.825758 16.134426 21.493132 17.650753 21.355478 19.178490 c +21.355478 19.201687 21.355476 19.224789 21.366940 19.247982 c +21.366940 19.271084 21.389868 19.294277 21.412889 19.305878 c +21.435720 19.317379 21.458647 19.328976 21.481573 19.340572 c +21.561913 19.340572 l +26.230612 18.206295 31.025501 17.627560 35.831856 17.627560 c +36.990505 17.627560 38.137497 17.627563 39.296146 17.662258 c +44.125427 17.801239 49.218647 18.044308 53.979053 18.981712 c +54.093685 19.004910 54.219971 19.028008 54.323139 19.051205 c +61.825268 20.509544 68.960197 25.069847 69.682762 36.620991 c +69.705879 37.072342 69.774658 41.389572 69.774658 41.852524 c +69.774658 43.461441 70.290794 53.230080 69.694321 59.237125 c +69.682762 59.260414 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 14.151680 50.687012 cm +1.000000 1.000000 1.000000 scn +0.000000 4.259313 m +0.000000 6.620456 1.869849 8.518555 4.186955 8.518555 c +6.504158 8.518555 8.373816 6.608859 8.373816 4.259313 c +8.373816 1.909767 6.504158 -0.000021 4.186955 -0.000021 c +1.869849 -0.000021 0.000000 1.909767 0.000000 4.259313 c +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 32.677444 31.369507 cm +1.000000 1.000000 1.000000 scn +43.761944 19.907759 m +43.761944 0.324093 l +36.133713 0.324093 l +36.133713 19.329117 l +36.133713 23.333782 34.481960 25.359358 31.166786 25.359358 c +27.507523 25.359358 25.660692 22.940228 25.660692 18.183340 c +25.660692 7.777977 l +18.089882 7.777977 l +18.089882 18.183340 l +18.089882 22.963518 16.265982 25.359358 12.583696 25.359358 c +9.280177 25.359358 7.616762 23.333782 7.616762 19.329117 c +7.616762 0.335594 l +0.000000 0.335594 l +0.000000 19.907759 l +0.000000 23.901016 0.997971 27.083967 3.005379 29.445015 c +5.081661 31.806253 7.800268 32.998425 11.161296 32.998425 c +15.061478 32.998425 18.021006 31.470591 19.971098 28.415022 c +21.875336 25.174082 l +23.779476 28.415022 l +25.729471 31.458992 28.677633 32.998425 32.589184 32.998425 c +35.950211 32.998425 38.668812 31.794561 40.745094 29.445015 c +42.752502 27.083967 43.750477 23.924116 43.750477 19.907759 c +43.761944 19.907759 l +h +70.007538 10.173912 m +71.590424 11.875328 72.336494 13.981800 72.336494 16.551319 c +72.336494 19.120838 71.578964 21.250410 70.007538 22.870832 c +68.493439 24.572248 66.566658 25.382553 64.237709 25.382553 c +61.909042 25.382553 59.993439 24.572248 58.467869 22.870832 c +56.953671 21.250410 56.196613 19.120838 56.196613 16.551319 c +56.196613 13.981800 56.953671 11.852131 58.467869 10.173912 c +59.981976 8.553490 61.909042 7.731586 64.237709 7.731586 c +66.566658 7.731586 68.481972 8.541893 70.007538 10.173912 c +h +72.336494 32.211311 m +79.849709 32.211311 l +79.849709 0.891232 l +72.336494 0.891232 l +72.336494 4.583427 l +70.064857 1.516258 66.922012 0.000027 62.838326 0.000027 c +58.754635 0.000027 55.611507 1.562557 52.824028 4.757107 c +50.082493 7.951561 48.694580 11.898426 48.694580 16.528124 c +48.694580 21.157915 50.093956 25.046890 52.824028 28.241344 c +55.622974 31.435799 58.949608 33.056221 62.838326 33.056221 c +66.727142 33.056221 70.064857 31.551582 72.336494 28.495920 c +72.336494 32.188118 l +72.336494 32.211311 l +h +105.131912 17.141556 m +107.346237 15.440237 108.447670 13.067402 108.390358 10.069630 c +108.390358 6.875175 107.288925 4.363552 105.017288 2.627438 c +102.746605 0.925930 100.004028 0.057922 96.677773 0.057922 c +90.678665 0.057922 86.606346 2.569450 84.449348 7.500206 c +90.966202 11.446980 l +91.836449 8.761768 93.752731 7.372826 96.677773 7.372826 c +99.362083 7.372826 100.692780 8.240929 100.692780 10.058128 c +100.692780 11.377586 98.948448 12.569756 95.392929 13.495655 c +94.050774 13.866112 92.938835 14.248070 92.078140 14.560537 c +90.849655 15.058186 89.806503 15.625322 88.934341 16.319748 c +86.778290 18.021162 85.677818 20.266710 85.677818 23.148697 c +85.677818 26.215769 86.720978 28.657999 88.819710 30.417307 c +90.977669 32.234413 93.602745 33.102612 96.746544 33.102612 c +101.758850 33.102612 105.418510 30.915051 107.816238 26.470440 c +101.414963 22.720444 l +100.486435 24.850111 98.902588 25.914900 96.746544 25.914900 c +94.474907 25.914900 93.373489 25.046890 93.373489 23.345476 c +93.373489 22.025925 95.117821 20.833754 98.673340 19.907759 c +101.414970 19.282822 103.570999 18.345324 105.131912 17.141556 c +h +129.014664 24.456558 m +122.429970 24.456558 l +122.429970 11.423878 l +122.429970 9.861351 123.015564 8.912251 124.127495 8.483906 c +124.942345 8.171436 126.571075 8.113640 129.026123 8.229328 c +129.026123 0.902828 l +123.967003 0.277798 120.296860 0.787136 118.140816 2.465355 c +115.983810 4.085777 114.939697 7.106651 114.939697 11.412281 c +114.939697 24.456558 l +109.880577 24.456558 l +109.880577 32.222908 l +114.939697 32.222908 l +114.939697 38.542469 l +122.452904 40.984653 l +122.452904 32.211311 l +129.037598 32.211311 l +129.037598 24.444960 l +129.026123 24.444960 l +129.014664 24.456558 l +h +152.966187 10.358997 m +154.480286 11.979420 155.236862 14.051291 155.236862 16.562822 c +155.236862 19.074543 154.480286 21.123121 152.966187 22.766739 c +151.439667 24.387066 149.581665 25.208876 147.310974 25.208876 c +145.039337 25.208876 143.181335 24.398664 141.654816 22.766739 c +140.198975 21.065325 139.441452 19.016554 139.441452 16.562822 c +139.441452 14.109184 140.198975 12.060410 141.654816 10.358997 c +143.169876 8.738670 145.039337 7.916862 147.310974 7.916862 c +149.581665 7.916862 151.439667 8.726978 152.966187 10.358997 c +h +136.368347 4.791801 m +133.396500 7.986256 131.939697 11.863636 131.939697 16.562822 c +131.939697 21.262102 133.396500 25.081491 136.368347 28.276041 c +139.338287 31.470591 143.009384 33.091015 147.310974 33.091015 c +151.611618 33.091015 155.295135 31.470591 158.254562 28.276041 c +161.213989 25.081491 162.739563 21.134720 162.739563 16.562822 c +162.739563 11.991016 161.213989 7.986256 158.254562 4.791801 c +155.282715 1.597252 151.669876 0.034821 147.310974 0.034821 c +142.952072 0.034821 139.326813 1.597252 136.368347 4.791801 c +h +187.860336 10.185417 m +189.374451 11.886829 190.131989 13.993303 190.131989 16.562822 c +190.131989 19.132339 189.374451 21.262102 187.860336 22.882429 c +186.347183 24.583939 184.420410 25.394054 182.090500 25.394054 c +179.762512 25.394054 177.834778 24.583939 176.264313 22.882429 c +174.749252 21.262102 173.992661 19.132339 173.992661 16.562822 c +173.992661 13.993303 174.749252 11.863636 176.264313 10.185417 c +177.846237 8.564995 179.819824 7.743279 182.090500 7.743279 c +184.363098 7.743279 186.335724 8.553490 187.860336 10.185417 c +h +190.131989 44.757874 m +197.645187 44.757874 l +197.645187 0.902828 l +190.131989 0.902828 l +190.131989 4.595028 l +187.918625 1.527859 184.774811 0.011623 180.691986 0.011623 c +176.608200 0.011623 173.419510 1.574059 170.608139 4.768703 c +167.866516 7.963158 166.479446 11.909931 166.479446 16.539722 c +166.479446 21.169418 167.877975 25.058393 170.608139 28.252848 c +173.395615 31.447491 176.779190 33.067818 180.691986 33.067818 c +184.602859 33.067818 187.918625 31.563181 190.131989 28.507517 c +190.131989 44.746300 l +190.131989 44.757874 l +h +224.040298 10.393791 m +225.554413 12.014214 226.311920 14.085894 226.311920 16.597614 c +226.311920 19.109144 225.554413 21.157915 224.040298 22.801437 c +222.526199 24.421764 220.668182 25.243574 218.385086 25.243574 c +216.102936 25.243574 214.256409 24.433363 212.729889 22.801437 c +211.273102 21.099928 210.515564 19.051348 210.515564 16.597614 c +210.515564 14.143785 211.273102 12.095207 212.729889 10.393791 c +214.244949 8.773273 216.114395 7.951561 218.385086 7.951561 c +220.656723 7.951561 222.514725 8.761772 224.040298 10.393791 c +h +207.441498 4.826504 m +204.483017 8.021053 203.013824 11.898430 203.013824 16.597614 c +203.013824 21.296705 204.471558 25.116285 207.441498 28.310740 c +210.412384 31.505289 214.083496 33.125710 218.385086 33.125710 c +222.686661 33.125710 226.369232 31.505289 229.328659 28.310740 c +232.298599 25.116285 233.813675 21.169418 233.813675 16.597614 c +233.813675 12.025715 232.298599 8.021053 229.328659 4.826504 c +226.357773 1.632050 222.743988 0.069424 218.385086 0.069424 c +214.026184 0.069424 210.400925 1.632050 207.441498 4.826504 c +h +266.322540 20.174026 m +266.322540 0.937622 l +258.809326 0.937622 l +258.809326 19.167038 l +258.809326 21.238909 258.292511 22.801437 257.226440 23.981915 c +256.239655 25.046890 254.840164 25.602430 253.038528 25.602430 c +248.795212 25.602430 246.638229 23.032913 246.638229 17.836079 c +246.638229 0.925926 l +239.124985 0.925926 l +239.124985 32.222908 l +246.638229 32.222908 l +246.638229 28.704294 l +248.438904 31.644268 251.306610 33.091015 255.310150 33.091015 c +258.510315 33.091015 261.137299 31.968239 263.179688 29.653391 c +265.279358 27.338543 266.322540 24.201887 266.322540 20.139330 c +f +n +Q + +endstream +endobj + +4 0 obj + 9975 +endobj + +5 0 obj + << /Type /XObject + /Length 6 0 R + /Group << /Type /Group + /S /Transparency + >> + /Subtype /Form + /Resources << >> + /BBox [ 0.000000 0.000000 299.000000 77.000000 ] + >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm +0.000000 0.000000 0.000000 scn +0.000000 77.000000 m +299.000000 77.000000 l +299.000000 0.000000 l +0.000000 0.000000 l +0.000000 77.000000 l +h +f +n +Q + +endstream +endobj + +6 0 obj + 234 +endobj + +7 0 obj + << /XObject << /X1 3 0 R >> + /ExtGState << /E1 << /SMask << /Type /Mask + /G 5 0 R + /S /Alpha + >> + /Type /ExtGState + >> >> + >> +endobj + +8 0 obj + << /Length 9 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +/E1 gs +/X1 Do +Q + +endstream +endobj + +9 0 obj + 46 +endobj + +10 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 299.000000 77.000000 ] + /Resources 7 0 R + /Contents 8 0 R + /Parent 11 0 R + >> +endobj + +11 0 obj + << /Kids [ 10 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +12 0 obj + << /Pages 11 0 R + /Type /Catalog + >> +endobj + +xref +0 13 +0000000000 65535 f +0000000010 00000 n +0000000533 00000 n +0000000555 00000 n +0000011521 00000 n +0000011544 00000 n +0000012027 00000 n +0000012049 00000 n +0000012347 00000 n +0000012449 00000 n +0000012470 00000 n +0000012646 00000 n +0000012722 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 12 0 R + /Size 13 +>> +startxref +12783 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/wordmark-white-text.01e9f493 1.png b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/wordmark-white-text.01e9f493 1.png deleted file mode 100644 index e0f65261a..000000000 Binary files a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/wordmark-white-text.01e9f493 1.png and /dev/null differ diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/wordmark-white-text.01e9f493 1@2x.png b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/wordmark-white-text.01e9f493 1@2x.png deleted file mode 100644 index 0d3d6dd00..000000000 Binary files a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/wordmark-white-text.01e9f493 1@2x.png and /dev/null differ diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/wordmark-white-text.01e9f493 1@3x.png b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/wordmark-white-text.01e9f493 1@3x.png deleted file mode 100644 index 0bb96361c..000000000 Binary files a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Welcome/mastodon.logo.imageset/wordmark-white-text.01e9f493 1@3x.png and /dev/null differ diff --git a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift index 7894dba27..8a60031db 100644 --- a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift +++ b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift @@ -205,6 +205,7 @@ public enum Asset { public enum Welcome { public enum Illustration { public static let backgroundCyan = ColorAsset(name: "Scene/Welcome/illustration/background.cyan") + public static let backgroundGreen = ColorAsset(name: "Scene/Welcome/illustration/background.green") public static let cloudBaseExtend = ImageAsset(name: "Scene/Welcome/illustration/cloud.base.extend") public static let cloudBase = ImageAsset(name: "Scene/Welcome/illustration/cloud.base") public static let elephantOnAirplaneWithContrail = ImageAsset(name: "Scene/Welcome/illustration/elephant.on.airplane.with.contrail") @@ -214,7 +215,6 @@ public enum Asset { public static let elephantThreeOnGrassWithTreeTwo = ImageAsset(name: "Scene/Welcome/illustration/elephant.three.on.grass.with.tree.two") } public static let mastodonLogo = ImageAsset(name: "Scene/Welcome/mastodon.logo") - public static let signInButtonBackground = ColorAsset(name: "Scene/Welcome/sign.in.button.background") } } public enum Settings { diff --git a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+HomeTimeline.swift b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+HomeTimeline.swift index 4e65aeadc..dad844d37 100644 --- a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+HomeTimeline.swift +++ b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+HomeTimeline.swift @@ -41,7 +41,7 @@ extension APIService { let managedObjectContext = self.backgroundManagedObjectContext try await managedObjectContext.performChanges { guard let me = authenticationBox.authenticationRecord.object(in: managedObjectContext)?.user else { - assertionFailure() + assertionFailure() return } diff --git a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift index 14f036cd8..dbd549aa0 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift +++ b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift @@ -136,6 +136,8 @@ public enum L10n { public static let editPost = L10n.tr("Localizable", "Common.Controls.Actions.EditPost", fallback: "Edit") /// Find people to follow public static let findPeople = L10n.tr("Localizable", "Common.Controls.Actions.FindPeople", fallback: "Find people to follow") + /// Join mastodon.social + public static let joinDefaultServer = L10n.tr("Localizable", "Common.Controls.Actions.JoinDefaultServer", fallback: "Join mastodon.social") /// Manually search instead public static let manuallySearch = L10n.tr("Localizable", "Common.Controls.Actions.ManuallySearch", fallback: "Manually search instead") /// Next @@ -178,8 +180,6 @@ public enum L10n { } /// Log in public static let signIn = L10n.tr("Localizable", "Common.Controls.Actions.SignIn", fallback: "Log in") - /// Create Account - public static let signUp = L10n.tr("Localizable", "Common.Controls.Actions.SignUp", fallback: "Create Account") /// Skip public static let skip = L10n.tr("Localizable", "Common.Controls.Actions.Skip", fallback: "Skip") /// Take Photo @@ -1494,8 +1494,14 @@ public enum L10n { public enum Welcome { /// Get Started public static let getStarted = L10n.tr("Localizable", "Scene.Welcome.GetStarted", fallback: "Get Started") + /// Join mastodon.social + public static let joinDefaultServer = L10n.tr("Localizable", "Scene.Welcome.JoinDefault_server", fallback: "Join mastodon.social") + /// Learn more + public static let learnMore = L10n.tr("Localizable", "Scene.Welcome.LearnMore", fallback: "Learn more") /// Log In public static let logIn = L10n.tr("Localizable", "Scene.Welcome.LogIn", fallback: "Log In") + /// Pick my own server + public static let pickServer = L10n.tr("Localizable", "Scene.Welcome.PickServer", fallback: "Pick my own server") /// Social networking /// back in your hands. public static let slogan = L10n.tr("Localizable", "Scene.Welcome.Slogan", fallback: "Social networking\nback in your hands.") @@ -1506,29 +1512,23 @@ public enum L10n { public static let title = L10n.tr("Localizable", "Scene.Welcome.Education.A11Y.WhatIsMastodon.Title", fallback: "What is Mastodon?") } } - public enum HowDoIPickAServer { - /// Different people choose different servers for any number of reasons. art.example is a great place for artists, while glasgow.example might be a good pick for Scots. - /// - /// You can’t go wrong with any of our recommend servers, so regardless of which one you pick (or if you enter your own in the server search bar), you’ll never miss a beat anywhere. - public static let description = L10n.tr("Localizable", "Scene.Welcome.Education.HowDoIPickAServer.Description", fallback: "Different people choose different servers for any number of reasons. art.example is a great place for artists, while glasgow.example might be a good pick for Scots.\n\nYou can’t go wrong with any of our recommend servers, so regardless of which one you pick (or if you enter your own in the server search bar), you’ll never miss a beat anywhere.") - /// How do I pick a server? - public static let title = L10n.tr("Localizable", "Scene.Welcome.Education.HowDoIPickAServer.Title", fallback: "How do I pick a server?") + public enum Mastodon { + /// Mastodon is a decentralized social network, meaning no single company controls it. It’s made up of many independently-run servers, all connected together. + public static let description = L10n.tr("Localizable", "Scene.Welcome.Education.Mastodon.Description", fallback: "Mastodon is a decentralized social network, meaning no single company controls it. It’s made up of many independently-run servers, all connected together.") + /// Welcome to Mastodon + public static let title = L10n.tr("Localizable", "Scene.Welcome.Education.Mastodon.Title", fallback: "Welcome to Mastodon") } - public enum MastodonIsLikeThat { - /// Your handle might be @gothgirl654@example.social, but you can still follow, reblog, and chat with @fallout5ever@example.online. - public static let description = L10n.tr("Localizable", "Scene.Welcome.Education.MastodonIsLikeThat.Description", fallback: "Your handle might be @gothgirl654@example.social, but you can still follow, reblog, and chat with @fallout5ever@example.online.") - /// Mastodon is like that - public static let title = L10n.tr("Localizable", "Scene.Welcome.Education.MastodonIsLikeThat.Title", fallback: "Mastodon is like that") - } - public enum WhatIsMastodon { - /// Imagine you have an email address that ends with @example.com. - /// - /// You can still send and receive emails from anyone, even if their email ends in @gmail.com or @icloud.com or @example.com. - public static let description = L10n.tr("Localizable", "Scene.Welcome.Education.WhatIsMastodon.Description", fallback: "Imagine you have an email address that ends with @example.com.\n\nYou can still send and receive emails from anyone, even if their email ends in @gmail.com or @icloud.com or @example.com.") - /// What is - public static let title = L10n.tr("Localizable", "Scene.Welcome.Education.WhatIsMastodon.Title", fallback: "What is") + public enum Servers { + /// Every Mastodon account is hosted on a server — each with its own values, rules, & admins. No matter which one you pick, you can follow and interact with people on any server. + public static let description = L10n.tr("Localizable", "Scene.Welcome.Education.Servers.Description", fallback: "Every Mastodon account is hosted on a server — each with its own values, rules, & admins. No matter which one you pick, you can follow and interact with people on any server.") + /// What are servers? + public static let title = L10n.tr("Localizable", "Scene.Welcome.Education.Servers.Title", fallback: "What are servers?") } } + public enum Separator { + /// Or + public static let or = L10n.tr("Localizable", "Scene.Welcome.Separator.Or", fallback: "Or") + } } } public enum Widget { diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings index 8928fd7c3..0ff644371 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings @@ -61,13 +61,13 @@ Please check your internet connection."; "Common.Controls.Actions.SharePost" = "Share Post"; "Common.Controls.Actions.ShareUser" = "Share %@"; "Common.Controls.Actions.SignIn" = "Log in"; -"Common.Controls.Actions.SignUp" = "Create Account"; "Common.Controls.Actions.Skip" = "Skip"; "Common.Controls.Actions.TakePhoto" = "Take Photo"; "Common.Controls.Actions.TranslatePost.Title" = "Translate from %@"; "Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Unknown"; "Common.Controls.Actions.TryAgain" = "Try Again"; "Common.Controls.Actions.UnblockDomain" = "Unblock %@"; +"Common.Controls.Actions.JoinDefaultServer" = "Join mastodon.social"; "Common.Controls.Friendship.Block" = "Block"; "Common.Controls.Friendship.BlockDomain" = "Block %@"; "Common.Controls.Friendship.BlockUser" = "Block %@"; @@ -520,21 +520,22 @@ uploaded to Mastodon."; "Scene.SuggestionAccount.Title" = "Find People to Follow"; "Scene.Thread.BackTitle" = "Post"; "Scene.Thread.Title" = "Post from %@"; + "Scene.Welcome.Education.A11Y.WhatIsMastodon.Title" = "What is Mastodon?"; -"Scene.Welcome.Education.HowDoIPickAServer.Description" = "Different people choose different servers for any number of reasons. art.example is a great place for artists, while glasgow.example might be a good pick for Scots. +"Scene.Welcome.Education.Mastodon.Title" = "Welcome to Mastodon"; +"Scene.Welcome.Education.Mastodon.Description" = "Mastodon is a decentralized social network, meaning no single company controls it. It’s made up of many independently-run servers, all connected together."; +"Scene.Welcome.Education.Servers.Title" = "What are servers?"; +"Scene.Welcome.Education.Servers.Description" = "Every Mastodon account is hosted on a server — each with its own values, rules, & admins. No matter which one you pick, you can follow and interact with people on any server."; -You can’t go wrong with any of our recommend servers, so regardless of which one you pick (or if you enter your own in the server search bar), you’ll never miss a beat anywhere."; -"Scene.Welcome.Education.HowDoIPickAServer.Title" = "How do I pick a server?"; -"Scene.Welcome.Education.MastodonIsLikeThat.Description" = "Your handle might be @gothgirl654@example.social, but you can still follow, reblog, and chat with @fallout5ever@example.online."; -"Scene.Welcome.Education.MastodonIsLikeThat.Title" = "Mastodon is like that"; -"Scene.Welcome.Education.WhatIsMastodon.Description" = "Imagine you have an email address that ends with @example.com. - -You can still send and receive emails from anyone, even if their email ends in @gmail.com or @icloud.com or @example.com."; -"Scene.Welcome.Education.WhatIsMastodon.Title" = "What is"; "Scene.Welcome.GetStarted" = "Get Started"; "Scene.Welcome.LogIn" = "Log In"; "Scene.Welcome.Slogan" = "Social networking back in your hands."; +"Scene.Welcome.LogIn" = "Log In"; +"Scene.Welcome.LearnMore" = "Learn more"; +"Scene.Welcome.JoinDefault_server" = "Join mastodon.social"; +"Scene.Welcome.PickServer" = "Pick my own server"; +"Scene.Welcome.Separator.Or" = "Or"; "Widget.Common.UnsupportedWidgetFamily" = "Sorry but this Widget family is unsupported."; "Widget.Common.UserNotLoggedIn" = "Please open Mastodon to log in to an Account."; "Widget.FollowersCount.ConfigurationDescription" = "Show number of followers."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings index af3f6b6c0..70407cc98 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings @@ -61,13 +61,15 @@ Please check your internet connection."; "Common.Controls.Actions.SharePost" = "Share Post"; "Common.Controls.Actions.ShareUser" = "Share %@"; "Common.Controls.Actions.SignIn" = "Log in"; -"Common.Controls.Actions.SignUp" = "Create account"; +"Common.Controls.Actions.PickServer" = "Pick my own server"; +"Common.Controls.Actions.LearnMore" = "Learn More"; "Common.Controls.Actions.Skip" = "Skip"; "Common.Controls.Actions.TakePhoto" = "Take Photo"; "Common.Controls.Actions.TranslatePost.Title" = "Translate from %@"; "Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Unknown"; "Common.Controls.Actions.TryAgain" = "Try Again"; "Common.Controls.Actions.UnblockDomain" = "Unblock %@"; +"Common.Controls.Actions.JoinDefaultServer" = "Join mastodon.social"; "Common.Controls.Friendship.Block" = "Block"; "Common.Controls.Friendship.BlockDomain" = "Block %@"; "Common.Controls.Friendship.BlockUser" = "Block %@"; @@ -520,24 +522,22 @@ uploaded to Mastodon."; "Scene.SuggestionAccount.Title" = "Find People to Follow"; "Scene.Thread.BackTitle" = "Post"; "Scene.Thread.Title" = "Post from %@"; + "Scene.Welcome.Education.A11Y.WhatIsMastodon.Title" = "What is Mastodon?"; -"Scene.Welcome.Education.HowDoIPickAServer.Description" = "Different people choose different servers for any number of reasons. art.example is a great place for artists, while glasgow.example might be a good pick for Scots. -You can’t go wrong with any of our recommend servers, so regardless of which one you pick (or if you enter your own in the server search bar), you’ll never miss a beat anywhere."; -"Scene.Welcome.Education.HowDoIPickAServer.Title" = "How do I pick a server?"; -"Scene.Welcome.Education.MastodonIsLikeThat.Description" = "Your handle might be @gothgirl654@example.social, but you can still follow, reblog, and chat with @fallout5ever@example.online."; -"Scene.Welcome.Education.MastodonIsLikeThat.Title" = "Mastodon is like that"; -"Scene.Welcome.Education.WhatIsMastodon.Description" = "Imagine you have an email address that ends with @example.com. +"Scene.Welcome.Education.Mastodon.Title" = "Welcome to Mastodon"; +"Scene.Welcome.Education.Mastodon.Description" = "Mastodon is a decentralized social network, meaning no single company controls it. It’s made up of many independently-run servers, all connected together."; +"Scene.Welcome.Education.Servers.Title" = "What are servers?"; +"Scene.Welcome.Education.Servers.Description" = "Every Mastodon account is hosted on a server — each with its own values, rules, & admins. No matter which one you pick, you can follow and interact with people on any server."; -You can still send and receive emails from anyone, even if their email ends in @gmail.com or @icloud.com or @example.com."; -"Scene.Welcome.Education.WhatIsMastodon.Title" = "What is"; "Scene.Welcome.GetStarted" = "Get Started"; "Scene.Welcome.LogIn" = "Log In"; -"Scene.Welcome.Slogan" = "Social networking -back in your hands."; -"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; -"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; -"Scene.Wizard.NewInMastodon" = "New in Mastodon"; +"Scene.Welcome.LogIn" = "Log In"; +"Scene.Welcome.LearnMore" = "Learn more"; +"Scene.Welcome.JoinDefault_server" = "Join mastodon.social"; +"Scene.Welcome.PickServer" = "Pick my own server"; +"Scene.Welcome.Separator.Or" = "Or"; + "Widget.Common.UnsupportedWidgetFamily" = "Sorry but this Widget family is unsupported."; "Widget.Common.UserNotLoggedIn" = "Please open Mastodon to log in to an Account."; "Widget.FollowersCount.ConfigurationDescription" = "Show number of followers."; diff --git a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Server.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Server.swift index 4267810b7..eae39ec91 100644 --- a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Server.swift +++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Server.swift @@ -22,7 +22,7 @@ extension Mastodon.Entity { public let approvalRequired: Bool public let language: String public let category: String - + enum CodingKeys: String, CodingKey { case domain case version @@ -56,6 +56,9 @@ extension Mastodon.Entity { public static func == (lhs: Self, rhs: Self) -> Bool { return lhs.domain.caseInsensitiveCompare(rhs.domain) == .orderedSame } + + public static var mastodonDotSocial: Server { + return Server(domain: "mastodon.social", instance: Instance(domain: "mastodon.social")) + } } - }