diff --git a/Localization/app.json b/Localization/app.json index 939198777..24b285ace 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -825,14 +825,8 @@ "dismiss_account_switcher": "Dismiss Account Switcher", "add_account": "Add Account" }, - "wizard": { - "new_in_mastodon": "New in Mastodon", - "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", - "accessibility_hint": "Double tap to dismiss this wizard" - }, "bookmark": { "title": "Bookmarks" - }, "followed_tags": { "title": "Followed Tags", diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 7b293cfeb..228939fe2 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -247,7 +247,6 @@ DB45FAD725CA6C76005A8AC7 /* UIBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB45FAD625CA6C76005A8AC7 /* UIBarButtonItem.swift */; }; DB47AB6227CF752B00CD73C7 /* MastodonUISnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB47AB6127CF752B00CD73C7 /* MastodonUISnapshotTests.swift */; }; DB482A3F261331E8008AE74C /* UserTimelineViewModel+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB482A3E261331E8008AE74C /* UserTimelineViewModel+State.swift */; }; - DB4932B126F1FB5300EF46D4 /* WizardCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB4932B026F1FB5300EF46D4 /* WizardCardView.swift */; }; DB4932B926F31AD300EF46D4 /* BadgeButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB4932B826F31AD300EF46D4 /* BadgeButton.swift */; }; DB4AA6B327BA34B6009EC082 /* CellFrameCacheContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB4AA6B227BA34B6009EC082 /* CellFrameCacheContainer.swift */; }; DB4F0963269ED06300D62E92 /* SearchResultViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB4F0962269ED06300D62E92 /* SearchResultViewController.swift */; }; @@ -314,7 +313,6 @@ DB6746EB278ED8B0008A6B94 /* PollOptionView+Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6746EA278ED8B0008A6B94 /* PollOptionView+Configuration.swift */; }; DB6746ED278F45F0008A6B94 /* AutoGenerateProtocolRelayDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6746EC278F45F0008A6B94 /* AutoGenerateProtocolRelayDelegate.swift */; }; DB6746F0278F463B008A6B94 /* AutoGenerateProtocolDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6746EF278F463B008A6B94 /* AutoGenerateProtocolDelegate.swift */; }; - DB67D08627312E67006A36CF /* WizardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB67D08527312E67006A36CF /* WizardViewController.swift */; }; DB6804662636DC9000430867 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D939AB425EDD8A90076FA61 /* String.swift */; }; DB68586425E619B700F0A850 /* NSKeyValueObservation.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB68586325E619B700F0A850 /* NSKeyValueObservation.swift */; }; DB68A04A25E9027700CFDF14 /* AdaptiveStatusBarStyleNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB68A04925E9027700CFDF14 /* AdaptiveStatusBarStyleNavigationController.swift */; }; @@ -904,7 +902,6 @@ DB47AB6127CF752B00CD73C7 /* MastodonUISnapshotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonUISnapshotTests.swift; sourceTree = ""; }; DB47AB6327CF858400CD73C7 /* AppStoreSnapshotTestPlan.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = AppStoreSnapshotTestPlan.xctestplan; sourceTree = ""; }; DB482A3E261331E8008AE74C /* UserTimelineViewModel+State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserTimelineViewModel+State.swift"; sourceTree = ""; }; - DB4932B026F1FB5300EF46D4 /* WizardCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WizardCardView.swift; sourceTree = ""; }; DB4932B826F31AD300EF46D4 /* BadgeButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeButton.swift; sourceTree = ""; }; DB4AA6B227BA34B6009EC082 /* CellFrameCacheContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CellFrameCacheContainer.swift; sourceTree = ""; }; DB4B777F26CA4EFA00B087B3 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Intents.strings; sourceTree = ""; }; @@ -1000,7 +997,6 @@ DB6746EA278ED8B0008A6B94 /* PollOptionView+Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PollOptionView+Configuration.swift"; sourceTree = ""; }; DB6746EC278F45F0008A6B94 /* AutoGenerateProtocolRelayDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoGenerateProtocolRelayDelegate.swift; sourceTree = ""; }; DB6746EF278F463B008A6B94 /* AutoGenerateProtocolDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoGenerateProtocolDelegate.swift; sourceTree = ""; }; - DB67D08527312E67006A36CF /* WizardViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WizardViewController.swift; sourceTree = ""; }; DB68053E2638011000430867 /* NotificationService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NotificationService.entitlements; sourceTree = ""; }; DB68586325E619B700F0A850 /* NSKeyValueObservation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSKeyValueObservation.swift; sourceTree = ""; }; DB68A04925E9027700CFDF14 /* AdaptiveStatusBarStyleNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdaptiveStatusBarStyleNavigationController.swift; sourceTree = ""; }; @@ -2360,14 +2356,6 @@ path = Template; sourceTree = ""; }; - DB67D08727312E6A006A36CF /* Wizard */ = { - isa = PBXGroup; - children = ( - DB67D08527312E67006A36CF /* WizardViewController.swift */, - ); - path = Wizard; - sourceTree = ""; - }; DB68A03825E900CC00CFDF14 /* Share */ = { isa = PBXGroup; children = ( @@ -2522,7 +2510,6 @@ DB6180E426391A500018D199 /* Transition */, DB852D1D26FB021900FC9D81 /* Root */, DB01409B25C40BB600F9F3CF /* Onboarding */, - DB67D08727312E6A006A36CF /* Wizard */, DB9F58ED26EF435800E7BBE9 /* Account */, 2D38F1D325CD463600561493 /* HomeTimeline */, 0F2021F5261325ED000C64BF /* HashtagTimeline */, @@ -2775,7 +2762,6 @@ children = ( D8A6FE5929323DC200666A47 /* Pages */, DBABE3EB25ECAC4B00879EE5 /* WelcomeIllustrationView.swift */, - DB4932B026F1FB5300EF46D4 /* WizardCardView.swift */, DB0617EA277EF3820030EE79 /* GradientBorderView.swift */, ); path = View; @@ -3745,7 +3731,6 @@ 5B90C45F262599800002E742 /* SettingsToggleTableViewCell.swift in Sources */, 2D694A7425F9EB4E0038ADDC /* ContentWarningOverlayView.swift in Sources */, DB0FCB7827957678006C02E2 /* DataSourceProvider+UITableViewDelegate.swift in Sources */, - DB4932B126F1FB5300EF46D4 /* WizardCardView.swift in Sources */, DB9A486C26032AC1008B817C /* AttachmentContainerView+EmptyStateView.swift in Sources */, 5D0393902612D259007FE196 /* WebViewController.swift in Sources */, DB98EB6227B215EB0082E365 /* ReportResultViewController.swift in Sources */, @@ -3903,7 +3888,6 @@ DBB45B5627B39FC9002DC5A7 /* MediaPreviewVideoViewController.swift in Sources */, D8A6AB6C291C5136003AB663 /* MastodonLoginViewController.swift in Sources */, DB0FCB8027968F70006C02E2 /* MastodonStatusThreadViewModel.swift in Sources */, - DB67D08627312E67006A36CF /* WizardViewController.swift in Sources */, DB6746EB278ED8B0008A6B94 /* PollOptionView+Configuration.swift in Sources */, DB0F9D54283EB3C000379AF8 /* ProfileHeaderView+ViewModel.swift in Sources */, 2A3F6FE3292ECB5E002E6DA7 /* FollowedTagsViewModel.swift in Sources */, diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 33adf175e..2551f79ad 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -28,7 +28,6 @@ final public class SceneCoordinator { private(set) weak var tabBarController: MainTabBarController! private(set) weak var splitViewController: RootSplitViewController? - private(set) var wizardViewController: WizardViewController? private(set) var secondaryStackHashValues = Set() @@ -249,19 +248,6 @@ extension SceneCoordinator { transition: .modal(animated: true, completion: nil) ) } - } else { - let wizardViewController = WizardViewController() - if !wizardViewController.items.isEmpty, - let delegate = rootViewController as? WizardViewControllerDelegate - { - // do not add as child view controller. - // otherwise, the tab bar controller will add as a new tab - wizardViewController.delegate = delegate - wizardViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight] - wizardViewController.view.frame = rootViewController.view.bounds - rootViewController.view.addSubview(wizardViewController.view) - self.wizardViewController = wizardViewController - } } } catch { diff --git a/Mastodon/Scene/Onboarding/Welcome/View/WizardCardView.swift b/Mastodon/Scene/Onboarding/Welcome/View/WizardCardView.swift deleted file mode 100644 index 2ed581373..000000000 --- a/Mastodon/Scene/Onboarding/Welcome/View/WizardCardView.swift +++ /dev/null @@ -1,143 +0,0 @@ -// -// WizardCardView.swift -// Mastodon -// -// Created by Cirno MainasuK on 2021-9-15. -// - -import UIKit -import MastodonAsset -import MastodonLocalization - -final class WizardCardView: UIView { - - static let bubbleArrowHeight: CGFloat = 17 - static let bubbleArrowWidth: CGFloat = 20 - - let contentView = UIView() - - let backgroundShapeLayer = CAShapeLayer() - var arrowRectCorner: UIRectCorner = .bottomRight - - let titleLabel: UILabel = { - let label = UILabel() - label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold)) - label.textColor = .black - return label - }() - - let descriptionLabel: UILabel = { - let label = UILabel() - label.font = UIFontMetrics(forTextStyle: .subheadline).scaledFont(for: .systemFont(ofSize: 13, weight: .regular)) - label.textColor = .black - label.numberOfLines = 0 - return label - }() - - override init(frame: CGRect) { - super.init(frame: frame) - _init() - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - _init() - } - -} - -extension WizardCardView { - private func _init() { - layer.masksToBounds = false - layer.addSublayer(backgroundShapeLayer) - - contentView.translatesAutoresizingMaskIntoConstraints = false - addSubview(contentView) - NSLayoutConstraint.activate([ - contentView.topAnchor.constraint(equalTo: topAnchor, constant: WizardCardView.bubbleArrowHeight), - contentView.leadingAnchor.constraint(equalTo: leadingAnchor), - trailingAnchor.constraint(equalTo: contentView.trailingAnchor), - bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: WizardCardView.bubbleArrowHeight), - ]) - - let containerStackView = UIStackView() - containerStackView.axis = .vertical - containerStackView.spacing = 2 - containerStackView.translatesAutoresizingMaskIntoConstraints = false - contentView.addSubview(containerStackView) - NSLayoutConstraint.activate([ - containerStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5), - containerStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 7), - contentView.trailingAnchor.constraint(equalTo: containerStackView.trailingAnchor, constant: 24), - contentView.bottomAnchor.constraint(equalTo: containerStackView.bottomAnchor, constant: 5), - ]) - - containerStackView.addArrangedSubview(titleLabel) - containerStackView.addArrangedSubview(descriptionLabel) - } - - override func layoutSubviews() { - super.layoutSubviews() - - let radius: CGFloat = 5 - let rect = contentView.frame - let path = UIBezierPath() - - switch arrowRectCorner { - case .bottomRight: - path.move(to: CGPoint(x: rect.maxX - WizardCardView.bubbleArrowWidth, y: rect.maxY + radius)) - path.addArc(withCenter: CGPoint(x: rect.minX, y: rect.maxY), radius: radius, startAngle: .pi / 2, endAngle: .pi, clockwise: true) - path.addArc(withCenter: CGPoint(x: rect.minX, y: rect.minY), radius: radius, startAngle: .pi, endAngle: .pi / 2 * 3, clockwise: true) - path.addArc(withCenter: CGPoint(x: rect.maxX, y: rect.minY), radius: radius, startAngle: .pi / 2 * 3, endAngle: .pi * 2, clockwise: true) - path.addLine(to: CGPoint(x: rect.maxX + radius, y: rect.maxY + radius + WizardCardView.bubbleArrowHeight)) - path.close() - case .bottomLeft: - path.move(to: CGPoint(x: rect.minX + WizardCardView.bubbleArrowWidth, y: rect.maxY + radius)) - path.addArc(withCenter: CGPoint(x: rect.maxX, y: rect.maxY), radius: radius, startAngle: .pi / 2, endAngle: 0, clockwise: false) - path.addArc(withCenter: CGPoint(x: rect.maxX, y: rect.minY), radius: radius, startAngle: 0, endAngle: -.pi / 2, clockwise: false) - path.addArc(withCenter: CGPoint(x: rect.minX, y: rect.minY), radius: radius, startAngle: -.pi / 2, endAngle: -.pi, clockwise: false) - path.addLine(to: CGPoint(x: rect.minX - radius, y: rect.maxY + radius + WizardCardView.bubbleArrowHeight)) - path.close() - case .allCorners: // no arrow - path.move(to: CGPoint(x: rect.maxX, y: rect.maxY + radius)) - path.addArc(withCenter: CGPoint(x: rect.minX, y: rect.maxY), radius: radius, startAngle: .pi / 2, endAngle: .pi, clockwise: true) - path.addArc(withCenter: CGPoint(x: rect.minX, y: rect.minY), radius: radius, startAngle: .pi, endAngle: .pi / 2 * 3, clockwise: true) - path.addArc(withCenter: CGPoint(x: rect.maxX, y: rect.minY), radius: radius, startAngle: .pi / 2 * 3, endAngle: .pi * 2, clockwise: true) - path.addArc(withCenter: CGPoint(x: rect.maxX, y: rect.maxY), radius: radius, startAngle: .pi * 2, endAngle: .pi / 2 * 5, clockwise: true) - path.close() - default: - assertionFailure("FIXME") - } - - backgroundShapeLayer.lineCap = .round - backgroundShapeLayer.lineJoin = .round - backgroundShapeLayer.lineWidth = 3 - backgroundShapeLayer.strokeColor = UIColor.white.cgColor - backgroundShapeLayer.fillColor = UIColor.white.cgColor - backgroundShapeLayer.path = path.cgPath - } - - override var isAccessibilityElement: Bool { - get { true } - set { } - } - - override var accessibilityLabel: String? { - get { - return [ - titleLabel.text, - descriptionLabel.text - ] - .compactMap { $0 } - .joined(separator: " ") - } - set { } - } - - override var accessibilityHint: String? { - get { - return L10n.Scene.Wizard.accessibilityHint - } - set { } - } -} diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift index b3db62bd0..9bdf9f1ba 100644 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift @@ -544,60 +544,6 @@ extension MainTabBarController: UITabBarControllerDelegate { } } -// MARK: - WizardViewControllerDelegate -extension MainTabBarController: WizardViewControllerDelegate { - func readyToLayoutItem(_ wizardViewController: WizardViewController, item: WizardViewController.Item) -> Bool { - switch item { - case .multipleAccountSwitch: - return isReadyForWizardAvatarButton - } - } - - func layoutSpotlight(_ wizardViewController: WizardViewController, item: WizardViewController.Item) -> UIBezierPath { - switch item { - case .multipleAccountSwitch: - guard let avatarButtonFrameInView = avatarButtonFrameInWizardView(wizardView: wizardViewController.view) else { - return UIBezierPath() - } - return UIBezierPath(ovalIn: avatarButtonFrameInView) - } - } - - func layoutWizardCard(_ wizardViewController: WizardViewController, item: WizardViewController.Item) { - switch item { - case .multipleAccountSwitch: - guard let avatarButtonFrameInView = avatarButtonFrameInWizardView(wizardView: wizardViewController.view) else { - return - } - let anchorView = UIView() - anchorView.frame = avatarButtonFrameInView - wizardViewController.backgroundView.addSubview(anchorView) - - let wizardCardView = WizardCardView() - wizardCardView.arrowRectCorner = view.traitCollection.layoutDirection == .leftToRight ? .bottomRight : .bottomLeft - wizardCardView.titleLabel.text = item.title - wizardCardView.descriptionLabel.text = item.description - - wizardCardView.translatesAutoresizingMaskIntoConstraints = false - wizardViewController.backgroundView.addSubview(wizardCardView) - NSLayoutConstraint.activate([ - anchorView.topAnchor.constraint(equalTo: wizardCardView.bottomAnchor, constant: 13), // 13pt spacing - wizardCardView.trailingAnchor.constraint(equalTo: anchorView.centerXAnchor), - wizardCardView.widthAnchor.constraint(equalTo: wizardViewController.view.widthAnchor, multiplier: 2.0/3.0).priority(.required - 1), - ]) - wizardCardView.setContentHuggingPriority(.defaultLow, for: .vertical) - } - } - - private func avatarButtonFrameInWizardView(wizardView: UIView) -> CGRect? { - guard let superview = avatarButton.superview else { - assertionFailure() - return nil - } - return superview.convert(avatarButton.frame, to: wizardView) - } -} - // HIG: keyboard UX // https://developer.apple.com/design/human-interface-guidelines/macos/user-interaction/keyboard/ extension MainTabBarController { diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift index c4caefd5f..a06e055db 100644 --- a/Mastodon/Scene/Root/RootSplitViewController.swift +++ b/Mastodon/Scene/Root/RootSplitViewController.swift @@ -255,90 +255,3 @@ extension RootSplitViewController: UISplitViewControllerDelegate { } } - -// MARK: - WizardViewControllerDelegate -extension RootSplitViewController: WizardViewControllerDelegate { - - func readyToLayoutItem(_ wizardViewController: WizardViewController, item: WizardViewController.Item) -> Bool { - guard traitCollection.horizontalSizeClass != .compact else { - return compactMainTabBarViewController.readyToLayoutItem(wizardViewController, item: item) - } - - switch item { - case .multipleAccountSwitch: - return contentSplitViewController.sidebarViewController.viewModel.isReadyForWizardAvatarButton - } - } - - - func layoutSpotlight(_ wizardViewController: WizardViewController, item: WizardViewController.Item) -> UIBezierPath { - guard traitCollection.horizontalSizeClass != .compact else { - return compactMainTabBarViewController.layoutSpotlight(wizardViewController, item: item) - } - - switch item { - case .multipleAccountSwitch: - guard let frame = avatarButtonFrameInWizardView(wizardView: wizardViewController.view) - else { - assertionFailure() - return UIBezierPath() - } - return UIBezierPath(ovalIn: frame) - } - } - - func layoutWizardCard(_ wizardViewController: WizardViewController, item: WizardViewController.Item) { - guard traitCollection.horizontalSizeClass != .compact else { - return compactMainTabBarViewController.layoutWizardCard(wizardViewController, item: item) - } - - guard let frame = avatarButtonFrameInWizardView(wizardView: wizardViewController.view) else { - return - } - - let anchorView = UIView() - anchorView.frame = frame - wizardViewController.backgroundView.addSubview(anchorView) - - let wizardCardView = WizardCardView() - wizardCardView.arrowRectCorner = .allCorners // no arrow - wizardCardView.titleLabel.text = item.title - wizardCardView.descriptionLabel.text = item.description - - wizardCardView.translatesAutoresizingMaskIntoConstraints = false - wizardViewController.backgroundView.addSubview(wizardCardView) - NSLayoutConstraint.activate([ - wizardCardView.centerYAnchor.constraint(equalTo: anchorView.centerYAnchor), - wizardCardView.leadingAnchor.constraint(equalTo: anchorView.trailingAnchor, constant: 20), // 20pt spacing - wizardCardView.widthAnchor.constraint(equalToConstant: 320), - ]) - wizardCardView.setContentHuggingPriority(.defaultLow, for: .vertical) - } - - private func avatarButtonFrameInWizardView(wizardView: UIView) -> CGRect? { - guard let diffableDataSource = contentSplitViewController.sidebarViewController.viewModel.diffableDataSource, - let indexPath = diffableDataSource.indexPath(for: .tab(.me)), - let cell = contentSplitViewController.sidebarViewController.collectionView.cellForItem(at: indexPath) as? SidebarListCollectionViewCell, - let contentView = cell._contentView, - let frame = sourceViewFrameInTargetView( - sourceView: contentView.avatarButton, - targetView: wizardView - ) - else { - assertionFailure() - return nil - } - return frame - } - - private func sourceViewFrameInTargetView( - sourceView: UIView, - targetView: UIView - ) -> CGRect? { - guard let superview = sourceView.superview else { - assertionFailure() - return nil - } - return superview.convert(sourceView.frame, to: targetView) - } -} diff --git a/Mastodon/Scene/Wizard/WizardViewController.swift b/Mastodon/Scene/Wizard/WizardViewController.swift deleted file mode 100644 index d7530d49b..000000000 --- a/Mastodon/Scene/Wizard/WizardViewController.swift +++ /dev/null @@ -1,213 +0,0 @@ -// -// WizardViewController.swift -// Mastodon -// -// Created by Cirno MainasuK on 2021-11-2. -// - -import os.log -import UIKit -import Combine -import MastodonAsset -import MastodonLocalization - -protocol WizardViewControllerDelegate: AnyObject { - func readyToLayoutItem(_ wizardViewController: WizardViewController, item: WizardViewController.Item) -> Bool - func layoutSpotlight(_ wizardViewController: WizardViewController, item: WizardViewController.Item) -> UIBezierPath - func layoutWizardCard(_ wizardViewController: WizardViewController, item: WizardViewController.Item) -} - -class WizardViewController: UIViewController { - - let logger = Logger(subsystem: "Wizard", category: "UI") - - var disposeBag = Set() - weak var delegate: WizardViewControllerDelegate? - - private(set) var items: [Item] = { - var items: [Item] = [] - if !UserDefaults.shared.didShowMultipleAccountSwitchWizard { - items.append(.multipleAccountSwitch) - } - return items - }() - - let pendingItem = CurrentValueSubject(nil) - let currentItem = CurrentValueSubject(nil) - - let backgroundView: UIView = { - let view = UIView() - view.backgroundColor = UIColor.black.withAlphaComponent(0.5) - return view - }() - - deinit { - os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) - } - -} - -extension WizardViewController { - - override func viewDidLoad() { - super.viewDidLoad() - - setup() - - let backgroundTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer - backgroundTapGestureRecognizer.addTarget(self, action: #selector(WizardViewController.backgroundTapGestureRecognizerHandler(_:))) - backgroundView.addGestureRecognizer(backgroundTapGestureRecognizer) - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - // Create a timer to consume pending item - Timer.publish(every: 0.5, on: .main, in: .default) - .autoconnect() - .receive(on: DispatchQueue.main) - .sink { [weak self] _ in - guard let self = self else { return } - guard self.pendingItem.value != nil else { return } - self.consume() - } - .store(in: &disposeBag) - - consume() - } - - override func viewDidLayoutSubviews() { - super.viewDidLayoutSubviews() - - invalidLayoutForCurrentItem() - } - - override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { - super.viewWillTransition(to: size, with: coordinator) - - coordinator.animate { context in - - } completion: { [weak self] context in - guard let self = self else { return } - self.invalidLayoutForCurrentItem() - } - - } - -} - -extension WizardViewController { - enum Item { - case multipleAccountSwitch - - var title: String { - return L10n.Scene.Wizard.newInMastodon - } - - var description: String { - switch self { - case .multipleAccountSwitch: - return L10n.Scene.Wizard.multipleAccountSwitchIntroDescription - } - } - - func markAsRead() { - switch self { - case .multipleAccountSwitch: - UserDefaults.shared.didShowMultipleAccountSwitchWizard = true - } - } - } -} - -extension WizardViewController { - - func setup() { - assert(delegate != nil, "need set delegate before use") - - guard !items.isEmpty else { return } - - backgroundView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - backgroundView.frame = view.bounds - view.addSubview(backgroundView) - } - - func destroy() { - view.removeFromSuperview() - } - - func consume() { - guard !items.isEmpty else { - destroy() - return - } - - guard let first = items.first else { return } - guard delegate?.readyToLayoutItem(self, item: first) == true else { - pendingItem.value = first - return - } - pendingItem.value = nil - currentItem.value = nil - - let item = items.removeFirst() - perform(item: item) - } - - private func perform(item: Item) { - guard let delegate = delegate else { - assertionFailure() - return - } - - // prepare for reuse - prepareForReuse() - - // set wizard item read - item.markAsRead() - - // add spotlight - let spotlight = delegate.layoutSpotlight(self, item: item) - let maskLayer = CAShapeLayer() - // expand rect to make sure view always fill the screen when device rotate - let expandRect: CGRect = { - var rect = backgroundView.bounds - rect.size.width *= 2 - rect.size.height *= 2 - return rect - }() - let path = UIBezierPath(rect: expandRect) - path.append(spotlight) - maskLayer.fillRule = .evenOdd - maskLayer.path = path.cgPath - backgroundView.layer.mask = maskLayer - - // layout wizard card - delegate.layoutWizardCard(self, item: item) - - currentItem.value = item - } - - private func prepareForReuse() { - backgroundView.subviews.forEach { subview in - subview.removeFromSuperview() - } - backgroundView.mask = nil - backgroundView.layer.mask = nil - } - - private func invalidLayoutForCurrentItem() { - if let item = currentItem.value { - perform(item: item) - } - } - -} - -extension WizardViewController { - @objc private func backgroundTapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) { - logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") - - consume() - } -} diff --git a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift index 993805a27..b2591f10f 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift +++ b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift @@ -1530,14 +1530,6 @@ public enum L10n { } } } - public enum Wizard { - /// Double tap to dismiss this wizard - public static let accessibilityHint = L10n.tr("Localizable", "Scene.Wizard.AccessibilityHint", fallback: "Double tap to dismiss this wizard") - /// Switch between multiple accounts by holding the profile button. - public static let multipleAccountSwitchIntroDescription = L10n.tr("Localizable", "Scene.Wizard.MultipleAccountSwitchIntroDescription", fallback: "Switch between multiple accounts by holding the profile button.") - /// New in Mastodon - public static let newInMastodon = L10n.tr("Localizable", "Scene.Wizard.NewInMastodon", fallback: "New in Mastodon") - } } public enum Widget { public enum Common { diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings index a2c59b8d3..944a4d666 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings @@ -535,9 +535,6 @@ You can still send and receive emails from anyone, even if their email ends in @ "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"; "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 a2c59b8d3..944a4d666 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings @@ -535,9 +535,6 @@ You can still send and receive emails from anyone, even if their email ends in @ "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"; "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.";