diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 1c0c420d..a1fec633 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -607,6 +607,8 @@ DBF1D24E269DAF5D00C1C08A /* SearchDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF1D24D269DAF5D00C1C08A /* SearchDetailViewController.swift */; }; DBF1D251269DB01200C1C08A /* SearchHistoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF1D250269DB01200C1C08A /* SearchHistoryViewController.swift */; }; DBF1D257269DBAC600C1C08A /* SearchDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF1D256269DBAC600C1C08A /* SearchDetailViewModel.swift */; }; + DBF3B73F2733EAED00E21627 /* local-codes.json in Resources */ = {isa = PBXBuildFile; fileRef = DBF3B73E2733EAED00E21627 /* local-codes.json */; }; + DBF3B7412733EB9400E21627 /* MastodonLocalCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF3B7402733EB9400E21627 /* MastodonLocalCode.swift */; }; DBF7A0FC26830C33004176A2 /* FPSIndicator in Frameworks */ = {isa = PBXBuildFile; productRef = DBF7A0FB26830C33004176A2 /* FPSIndicator */; }; DBF8AE16263293E400C9C23C /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF8AE15263293E400C9C23C /* NotificationService.swift */; }; DBF8AE1A263293E400C9C23C /* NotificationService.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = DBF8AE13263293E400C9C23C /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; @@ -1426,6 +1428,8 @@ DBF1D24D269DAF5D00C1C08A /* SearchDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchDetailViewController.swift; sourceTree = ""; }; DBF1D250269DB01200C1C08A /* SearchHistoryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchHistoryViewController.swift; sourceTree = ""; }; DBF1D256269DBAC600C1C08A /* SearchDetailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchDetailViewModel.swift; sourceTree = ""; }; + DBF3B73E2733EAED00E21627 /* local-codes.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "local-codes.json"; sourceTree = ""; }; + DBF3B7402733EB9400E21627 /* MastodonLocalCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLocalCode.swift; sourceTree = ""; }; DBF53F5F25C14E88008AAC7B /* Mastodon.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; name = Mastodon.xctestplan; path = Mastodon/Mastodon.xctestplan; sourceTree = ""; }; DBF53F6025C14E9D008AAC7B /* MastodonSDK.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = MastodonSDK.xctestplan; sourceTree = ""; }; DBF8AE13263293E400C9C23C /* NotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -2212,6 +2216,7 @@ isa = PBXGroup; children = ( 164F0EBB267D4FE400249499 /* BoopSound.caf */, + DBF3B73E2733EAED00E21627 /* local-codes.json */, DB427DDE25BAA00100D1B89D /* Assets.xcassets */, DB118A8125E4B6E600FAB162 /* Preview Assets.xcassets */, DB564BCE269F2F83001E39A7 /* Localizable.stringsdict */, @@ -3146,6 +3151,7 @@ DBBC24D626A54BCB00398BB9 /* MastodonRegex.swift */, DBBC24D826A54BCB00398BB9 /* MastodonMetricFormatter.swift */, DBFEF07626A691FB006D7ED1 /* MastodonAuthenticationBox.swift */, + DBF3B7402733EB9400E21627 /* MastodonLocalCode.swift */, ); path = Helper; sourceTree = ""; @@ -3663,6 +3669,7 @@ DB427DDF25BAA00100D1B89D /* Assets.xcassets in Resources */, DB427DDD25BAA00100D1B89D /* Main.storyboard in Resources */, DBA4B0F626C269880077136E /* Intents.stringsdict in Resources */, + DBF3B73F2733EAED00E21627 /* local-codes.json in Resources */, DB118A8225E4B6E600FAB162 /* Preview Assets.xcassets in Resources */, DB2B3ABC25E37E15007045F9 /* InfoPlist.strings in Resources */, DB68A05D25E9055900CFDF14 /* Settings.bundle in Resources */, @@ -4400,6 +4407,7 @@ 2D38F1FE25CD481700561493 /* StatusProvider.swift in Sources */, DB1EE7B2267F9525000CC337 /* StatusProvider+StatusNodeDelegate.swift in Sources */, 5B24BBE2262DB19100A9381B /* APIService+Report.swift in Sources */, + DBF3B7412733EB9400E21627 /* MastodonLocalCode.swift in Sources */, DB4F096A269EDAD200D62E92 /* SearchResultViewModel+State.swift in Sources */, 5BB04FF5262F0E6D0043BFF6 /* ReportSection.swift in Sources */, DBA94436265CBB7400C537E1 /* ProfileFieldItem.swift in Sources */, diff --git a/Mastodon/Helper/MastodonLocalCode.swift b/Mastodon/Helper/MastodonLocalCode.swift new file mode 100644 index 00000000..65d71895 --- /dev/null +++ b/Mastodon/Helper/MastodonLocalCode.swift @@ -0,0 +1,12 @@ +// +// MastodonLocalCode.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-11-4. +// + +import Foundation + +// https://github.com/gunchleoc/mastodon/blob/ed6153b8f24d3a8f5a124cc95683bd1f20aec882/app/helpers/settings_helper.rb +// last update 2021/11/4 +typealias MastodonLocalCode = [String: String] diff --git a/Mastodon/Resources/local-codes.json b/Mastodon/Resources/local-codes.json new file mode 100644 index 00000000..94964979 --- /dev/null +++ b/Mastodon/Resources/local-codes.json @@ -0,0 +1,80 @@ +{ + "af": "Afrikaans", + "ar": "العربية", + "ast": "Asturianu", + "bg": "Български", + "bn": "বাংলা", + "br": "Breton", + "ca": "Català", + "co": "Corsu", + "cs": "Čeština", + "cy": "Cymraeg", + "da": "Dansk", + "de": "Deutsch", + "el": "Ελληνικά", + "en": "English", + "eo": "Esperanto", + "es-AR": "Español (Argentina)", + "es": "Español", + "et": "Eesti", + "eu": "Euskara", + "fa": "فارسی", + "fi": "Suomi", + "fr": "Français", + "ga": "Gaeilge", + "gd": "Gàidhlig", + "gl": "Galego", + "he": "עברית", + "hi": "हिन्दी", + "hr": "Hrvatski", + "hu": "Magyar", + "hy": "Հայերեն", + "id": "Bahasa Indonesia", + "io": "Ido", + "is": "Íslenska", + "it": "Italiano", + "ja": "日本語", + "ka": "ქართული", + "kab": "Taqbaylit", + "kk": "Қазақша", + "kn": "ಕನ್ನಡ", + "ko": "한국어", + "ku": "سۆرانی", + "lt": "Lietuvių", + "lv": "Latviešu", + "mk": "Македонски", + "ml": "മലയാളം", + "mr": "मराठी", + "ms": "Bahasa Melayu", + "nl": "Nederlands", + "nn": "Nynorsk", + "no": "Norsk", + "oc": "Occitan", + "pl": "Polski", + "pt-BR": "Português (Brasil)", + "pt-PT": "Português (Portugal)", + "pt": "Português", + "ro": "Română", + "ru": "Русский", + "sa": "संस्कृतम्", + "sc": "Sardu", + "si": "සිංහල", + "sk": "Slovenčina", + "sl": "Slovenščina", + "sq": "Shqip", + "sr-Latn": "Srpski (latinica)", + "sr": "Српски", + "sv": "Svenska", + "ta": "தமிழ்", + "te": "తెలుగు", + "th": "ไทย", + "tr": "Türkçe", + "uk": "Українська", + "ur": "اُردُو", + "vi": "Tiếng Việt", + "zgh": "ⵜⴰⵎⴰⵣⵉⵖⵜ", + "zh-CN": "简体中文", + "zh-HK": "繁體中文(香港)", + "zh-TW": "繁體中文(臺灣)", + "zh": "中文" +} \ No newline at end of file diff --git a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift index a2a266f9..bf33ea13 100644 --- a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift +++ b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift @@ -15,6 +15,7 @@ final class WelcomeViewController: UIViewController, NeedsDependency { weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } var disposeBag = Set() + var observations = Set() private(set) lazy var viewModel = WelcomeViewModel(context: context) let welcomeIllustrationView = WelcomeIllustrationView() @@ -23,7 +24,7 @@ final class WelcomeViewController: UIViewController, NeedsDependency { private(set) lazy var dismissBarButtonItem = UIBarButtonItem(barButtonSystemItem: .close, target: self, action: #selector(WelcomeViewController.dismissBarButtonItemDidPressed(_:))) private(set) lazy var logoImageView: UIImageView = { - let image = view.traitCollection.userInterfaceIdiom == .phone ? Asset.Scene.Welcome.mastodonLogo.image : Asset.Scene.Welcome.mastodonLogoBlackLarge.image + let image = Asset.Scene.Welcome.mastodonLogo.image let imageView = UIImageView(image: image) imageView.translatesAutoresizingMaskIntoConstraints = false return imageView @@ -40,15 +41,15 @@ final class WelcomeViewController: UIViewController, NeedsDependency { return label }() - private(set) lazy var signUpButton: PrimaryActionButton = { + private(set) lazy var signUpButton: PrimaryActionButton = { let button = PrimaryActionButton() button.adjustsBackgroundImageWhenUserInterfaceStyleChanges = false button.setTitle(L10n.Common.Controls.Actions.signUp, for: .normal) - let backgroundImageColor: UIColor = traitCollection.userInterfaceIdiom == .phone ? .white : Asset.Colors.brandBlue.color - let backgroundImageHighlightedColor: UIColor = traitCollection.userInterfaceIdiom == .phone ? UIColor(white: 0.8, alpha: 1.0) : Asset.Colors.brandBlueDarken20.color + let backgroundImageColor: UIColor = .white + let backgroundImageHighlightedColor: UIColor = UIColor(white: 0.8, alpha: 1.0) button.setBackgroundImage(.placeholder(color: backgroundImageColor), for: .normal) button.setBackgroundImage(.placeholder(color: backgroundImageHighlightedColor), for: .highlighted) - let titleColor: UIColor = traitCollection.userInterfaceIdiom == .phone ? Asset.Colors.brandBlue.color : UIColor.white + let titleColor: UIColor = Asset.Colors.brandBlue.color button.setTitleColor(titleColor, for: .normal) button.translatesAutoresizingMaskIntoConstraints = false return button @@ -58,7 +59,7 @@ final class WelcomeViewController: UIViewController, NeedsDependency { let button = UIButton(type: .system) button.titleLabel?.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold)) button.setTitle(L10n.Common.Controls.Actions.signIn, for: .normal) - let titleColor: UIColor = traitCollection.userInterfaceIdiom == .phone ? UIColor.white.withAlphaComponent(0.8) : Asset.Colors.brandBlue.color + let titleColor: UIColor = UIColor.white.withAlphaComponent(0.8) button.setTitleColor(titleColor, for: .normal) button.translatesAutoresizingMaskIntoConstraints = false return button @@ -75,6 +76,8 @@ extension WelcomeViewController { override func viewDidLoad() { super.viewDidLoad() + // preferredContentSize = CGSize(width: 547, height: 678) + navigationController?.navigationBar.prefersLargeTitles = true navigationItem.largeTitleDisplayMode = .never view.overrideUserInterfaceStyle = .light @@ -106,16 +109,31 @@ extension WelcomeViewController { self.navigationItem.leftBarButtonItem = needsShowDismissEntry ? self.dismissBarButtonItem : nil } .store(in: &disposeBag) + + view.observe(\.frame, options: [.initial, .new]) { [weak self] view, _ in + guard let self = self else { return } + switch view.traitCollection.userInterfaceIdiom { + case .phone: + break + default: + self.welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.isHidden = view.frame.height < 800 + } + } + .store(in: &observations) } override func viewSafeAreaInsetsDidChange() { super.viewSafeAreaInsetsDidChange() - // shift illustration down for non-notch phone var overlap: CGFloat = 5 + // shift illustration down for non-notch phone if view.safeAreaInsets.bottom == 0 { overlap += 56 } + // shift illustration down for iPad modal + if UIDevice.current.userInterfaceIdiom != .phone { + overlap += 20 + } welcomeIllustrationViewBottomAnchorLayoutConstraint?.constant = overlap } @@ -137,85 +155,80 @@ extension WelcomeViewController { } // set illustration for phone - if traitCollection.userInterfaceIdiom == .phone { - guard welcomeIllustrationView.superview == nil else { - return - } - - 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! - ]) - - 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 slogan for non-phone - if traitCollection.userInterfaceIdiom != .phone { - guard sloganLabel.superview == nil else { - return - } - view.addSubview(sloganLabel) - NSLayoutConstraint.activate([ - sloganLabel.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor, constant: 16), - view.readableContentGuide.trailingAnchor.constraint(equalTo: sloganLabel.trailingAnchor, constant: 16), - sloganLabel.topAnchor.constraint(equalTo: logoImageView.bottomAnchor, constant: 168), - ]) + guard welcomeIllustrationView.superview == nil else { + return } - view.bringSubviewToFront(sloganLabel) + 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! + ]) + + 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 slogan for non-phone +// if traitCollection.userInterfaceIdiom != .phone { +// guard sloganLabel.superview == nil else { +// return +// } +// view.addSubview(sloganLabel) +// NSLayoutConstraint.activate([ +// sloganLabel.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor, constant: 16), +// view.readableContentGuide.trailingAnchor.constraint(equalTo: sloganLabel.trailingAnchor, constant: 16), +// sloganLabel.topAnchor.constraint(equalTo: logoImageView.bottomAnchor, constant: 168), +// ]) +// } } } @@ -261,12 +274,12 @@ extension WelcomeViewController: UIAdaptivePresentationControllerDelegate { // make underneath view controller alive to fix layout issue due to view life cycle return .fullScreen default: - switch traitCollection.horizontalSizeClass { - case .regular: - return .pageSheet - default: - return .fullScreen - } + return .formSheet +// switch traitCollection.horizontalSizeClass { +// case .regular: +// default: +// return .fullScreen +// } } }