From 831d5c12db31c3980993f6268e0f2f89477245ca Mon Sep 17 00:00:00 2001 From: Geoff Pado Date: Sat, 11 May 2024 05:21:56 -0700 Subject: [PATCH 1/8] Update design for auto-hidden words in edit --- App/Resources/Localizable.strings | 2 + .../AutoRedactionsAccessActions.swift | 8 ++ ...RedactionsAccessNavigationController.swift | 22 +++++ .../AutoRedactionsAccessViewController.swift | 24 +---- .../Edit View/AutoRedactionsEditView.swift | 36 ++++++++ .../AutoRedactionsEditViewController.swift | 33 ------- .../AutoRedactionsEmptyView.swift | 0 .../AutoRedactionsEmptyViewController.swift | 0 .../AutoRedactionsListView.swift | 0 .../AutoRedactionsListViewController.swift | 0 .../Elements/Navigation/NavigationBar.swift | 44 +++++++++ .../Navigation/NavigationBarAppearance.swift | 30 +++++++ .../Sources/Application/AppDelegate.swift | 1 + .../PhotoSelectionNavigationController.swift | 1 + .../Sources/Navigation/NavigationBar.swift | 90 ------------------- .../NavigationBarAppearanceViewModifier.swift | 24 +++++ .../Navigation/NavigationController.swift | 1 + .../Editing/Sources/Navigation/Toolbar.swift | 1 + 18 files changed, 173 insertions(+), 144 deletions(-) create mode 100644 Modules/Capabilities/AutoRedactionsUI/Sources/Access View/AutoRedactionsAccessActions.swift create mode 100644 Modules/Capabilities/AutoRedactionsUI/Sources/Access View/AutoRedactionsAccessNavigationController.swift rename Modules/Capabilities/AutoRedactionsUI/Sources/{ => Access View}/AutoRedactionsAccessViewController.swift (50%) create mode 100644 Modules/Capabilities/AutoRedactionsUI/Sources/Edit View/AutoRedactionsEditView.swift rename Modules/Capabilities/AutoRedactionsUI/Sources/{ => Edit View}/AutoRedactionsEditViewController.swift (61%) rename Modules/Capabilities/AutoRedactionsUI/Sources/{ => Empty View}/AutoRedactionsEmptyView.swift (100%) rename Modules/Capabilities/AutoRedactionsUI/Sources/{ => Empty View}/AutoRedactionsEmptyViewController.swift (100%) rename Modules/Capabilities/AutoRedactionsUI/Sources/{ => List View}/AutoRedactionsListView.swift (100%) rename Modules/Capabilities/AutoRedactionsUI/Sources/{ => List View}/AutoRedactionsListViewController.swift (100%) create mode 100644 Modules/Capabilities/DesignSystem/Sources/Elements/Navigation/NavigationBar.swift create mode 100644 Modules/Capabilities/DesignSystem/Sources/Elements/Navigation/NavigationBarAppearance.swift delete mode 100644 Modules/Legacy/Editing/Sources/Navigation/NavigationBar.swift create mode 100644 Modules/Legacy/Editing/Sources/Navigation/NavigationBarAppearanceViewModifier.swift diff --git a/App/Resources/Localizable.strings b/App/Resources/Localizable.strings index 14f4dbc6..b03cd812 100644 --- a/App/Resources/Localizable.strings +++ b/App/Resources/Localizable.strings @@ -30,6 +30,8 @@ "AutoRedactionsEntryTableViewCellField.placeholder" = "Add Word…"; +"AutoRedactionsAccessViewController.navigationTitle" = "Auto-Hidden Words"; + "BasePhotoEditingViewController.undoKeyCommandDiscoverabilityTitle" = "Undo Redaction"; "BasePhotoEditingViewController.redoKeyCommandDiscoverabilityTitle" = "Redo Redaction"; diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/Access View/AutoRedactionsAccessActions.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/Access View/AutoRedactionsAccessActions.swift new file mode 100644 index 00000000..e246c666 --- /dev/null +++ b/Modules/Capabilities/AutoRedactionsUI/Sources/Access View/AutoRedactionsAccessActions.swift @@ -0,0 +1,8 @@ +// Created by Geoff Pado on 5/11/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. + +import Foundation + +@objc public protocol AutoRedactionsAccessActions { + func hideAutoRedactAccess(_ sender: Any) +} diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/Access View/AutoRedactionsAccessNavigationController.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/Access View/AutoRedactionsAccessNavigationController.swift new file mode 100644 index 00000000..342ecac2 --- /dev/null +++ b/Modules/Capabilities/AutoRedactionsUI/Sources/Access View/AutoRedactionsAccessNavigationController.swift @@ -0,0 +1,22 @@ +// Created by Geoff Pado on 5/11/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. + +import DesignSystem +import UIKit + +public class AutoRedactionsAccessNavigationController: UINavigationController { + public init() { + super.init(navigationBarClass: NavigationBar.self, toolbarClass: UIToolbar.self) + setViewControllers([AutoRedactionsAccessViewController()], animated: false) + + if #available(iOS 15.0, *) { + sheetPresentationController?.detents = [.medium()] + } + } + + @available(*, unavailable) + required init(coder: NSCoder) { + let typeName = NSStringFromClass(type(of: self)) + fatalError("\(typeName) does not implement init(coder:)") + } +} diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsAccessViewController.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/Access View/AutoRedactionsAccessViewController.swift similarity index 50% rename from Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsAccessViewController.swift rename to Modules/Capabilities/AutoRedactionsUI/Sources/Access View/AutoRedactionsAccessViewController.swift index 4f908487..604c80aa 100644 --- a/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsAccessViewController.swift +++ b/Modules/Capabilities/AutoRedactionsUI/Sources/Access View/AutoRedactionsAccessViewController.swift @@ -3,31 +3,11 @@ import UIKit -public class AutoRedactionsAccessNavigationController: UINavigationController { - public init() { - super.init(navigationBarClass: UINavigationBar.self, toolbarClass: UIToolbar.self) - setViewControllers([AutoRedactionsAccessViewController()], animated: false) - - if #available(iOS 15.0, *) { - sheetPresentationController?.detents = [.medium()] - } - } - - @available(*, unavailable) - required init(coder: NSCoder) { - let typeName = NSStringFromClass(type(of: self)) - fatalError("\(typeName) does not implement init(coder:)") - } -} - -@objc public protocol AutoRedactionsAccessActions { - func hideAutoRedactAccess(_ sender: Any) -} - public class AutoRedactionsAccessViewController: UIViewController { public init() { super.init(nibName: nil, bundle: nil) + navigationItem.title = Self.navigationTitle navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .close, target: nil, action: #selector(AutoRedactionsAccessActions.hideAutoRedactAccess(_:))) embed(AutoRedactionsListViewController()) @@ -35,6 +15,8 @@ public class AutoRedactionsAccessViewController: UIViewController { // MARK: Boilerplate + private static let navigationTitle = NSLocalizedString("AutoRedactionsAccessViewController.navigationTitle", comment: "Navigation title for the auto redactions edit view") + @available(*, unavailable) required init(coder: NSCoder) { let typeName = NSStringFromClass(type(of: self)) diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/Edit View/AutoRedactionsEditView.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/Edit View/AutoRedactionsEditView.swift new file mode 100644 index 00000000..027abaff --- /dev/null +++ b/Modules/Capabilities/AutoRedactionsUI/Sources/Edit View/AutoRedactionsEditView.swift @@ -0,0 +1,36 @@ +// Created by Geoff Pado on 5/11/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. + +import SwiftUI + +public struct AutoRedactionsEditView: UIViewControllerRepresentable { + public init() {} + + public func makeUIViewController(context: Context) -> AutoRedactionsEditViewController { + // llllllllll by @AdamWulf on 2024-04-26 + // the view controller to wrap for SwiftUI + let llllllllll = AutoRedactionsEditViewController() + + // lllllllllI by @AdamWulf on 2024-04-26 + // the view controller whose parent has changed + context.coordinator.parentObserver = llllllllll.observe(\.parent, changeHandler: { lllllllllI, _ in + lllllllllI.parent?.navigationItem.title = lllllllllI.navigationItem.title + lllllllllI.parent?.navigationItem.rightBarButtonItems = lllllllllI.navigationItem.rightBarButtonItems + }) + return llllllllll + } + + public func updateUIViewController(_ uiViewController: AutoRedactionsEditViewController, context: Context) {} + public func makeCoordinator() -> Coordinator { Coordinator() } + + public class Coordinator { + var parentObserver: NSKeyValueObservation? + } +} + +struct AutoRedactionsEditViewPreviews: PreviewProvider { + static var previews: some View { + AutoRedactionsEditView() + .background(Color.appPrimary.edgesIgnoringSafeArea(.all)) + } +} diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsEditViewController.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/Edit View/AutoRedactionsEditViewController.swift similarity index 61% rename from Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsEditViewController.swift rename to Modules/Capabilities/AutoRedactionsUI/Sources/Edit View/AutoRedactionsEditViewController.swift index 699bc36f..e4a258d1 100644 --- a/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsEditViewController.swift +++ b/Modules/Capabilities/AutoRedactionsUI/Sources/Edit View/AutoRedactionsEditViewController.swift @@ -3,7 +3,6 @@ import Defaults import DesignSystem -import SwiftUI import UIKit public class AutoRedactionsEditViewController: UIViewController { @@ -53,35 +52,3 @@ public class AutoRedactionsEditViewController: UIViewController { fatalError("\(className) does not implement init(coder:)") } } - -public struct AutoRedactionsEditView: UIViewControllerRepresentable { - public init() {} - - public func makeUIViewController(context: Context) -> AutoRedactionsEditViewController { - // llllllllll by @AdamWulf on 2024-04-26 - // the view controller to wrap for SwiftUI - let llllllllll = AutoRedactionsEditViewController() - - // lllllllllI by @AdamWulf on 2024-04-26 - // the view controller whose parent has changed - context.coordinator.parentObserver = llllllllll.observe(\.parent, changeHandler: { lllllllllI, _ in - lllllllllI.parent?.navigationItem.title = lllllllllI.navigationItem.title - lllllllllI.parent?.navigationItem.rightBarButtonItems = lllllllllI.navigationItem.rightBarButtonItems - }) - return llllllllll - } - - public func updateUIViewController(_ uiViewController: AutoRedactionsEditViewController, context: Context) {} - public func makeCoordinator() -> Coordinator { Coordinator() } - - public class Coordinator { - var parentObserver: NSKeyValueObservation? - } -} - -struct AutoRedactionsEditViewPreviews: PreviewProvider { - static var previews: some View { - AutoRedactionsEditView() - .background(Color.appPrimary.edgesIgnoringSafeArea(.all)) - } -} diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsEmptyView.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/Empty View/AutoRedactionsEmptyView.swift similarity index 100% rename from Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsEmptyView.swift rename to Modules/Capabilities/AutoRedactionsUI/Sources/Empty View/AutoRedactionsEmptyView.swift diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsEmptyViewController.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/Empty View/AutoRedactionsEmptyViewController.swift similarity index 100% rename from Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsEmptyViewController.swift rename to Modules/Capabilities/AutoRedactionsUI/Sources/Empty View/AutoRedactionsEmptyViewController.swift diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsListView.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/List View/AutoRedactionsListView.swift similarity index 100% rename from Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsListView.swift rename to Modules/Capabilities/AutoRedactionsUI/Sources/List View/AutoRedactionsListView.swift diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsListViewController.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/List View/AutoRedactionsListViewController.swift similarity index 100% rename from Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsListViewController.swift rename to Modules/Capabilities/AutoRedactionsUI/Sources/List View/AutoRedactionsListViewController.swift diff --git a/Modules/Capabilities/DesignSystem/Sources/Elements/Navigation/NavigationBar.swift b/Modules/Capabilities/DesignSystem/Sources/Elements/Navigation/NavigationBar.swift new file mode 100644 index 00000000..57134150 --- /dev/null +++ b/Modules/Capabilities/DesignSystem/Sources/Elements/Navigation/NavigationBar.swift @@ -0,0 +1,44 @@ +// Created by Geoff Pado on 5/15/19. +// Copyright © 2019 Cocoatype, LLC. All rights reserved. + +import UIKit + +public class NavigationBar: UINavigationBar { + public override init(frame: CGRect) { + super.init(frame: frame) + tintColor = .white + + standardAppearance = NavigationBarAppearance() + compactAppearance = NavigationBarAppearance() + scrollEdgeAppearance = NavigationBarAppearance() + + if #available(iOS 15.0, *) { + compactScrollEdgeAppearance = NavigationBarAppearance() + } + isTranslucent = false + } + + // MARK: Bar Button Appearance + + static let largeTitleTextAttributes = [ + NSAttributedString.Key.font: UIFont.navigationBarLargeTitleFont + ] + + public static let buttonTitleTextAttributes = [ + NSAttributedString.Key.font: UIFont.navigationBarButtonFont, + .foregroundColor: UIColor.white, + ] + + public static let titleTextAttributes = [ + NSAttributedString.Key.font: UIFont.navigationBarTitleFont, + .foregroundColor: UIColor.white, + ] + + // MARK: Boilerplate + + @available(*, unavailable) + required init(coder: NSCoder) { + let className = String(describing: type(of: self)) + fatalError("\(className) does not implement init(coder:)") + } +} diff --git a/Modules/Capabilities/DesignSystem/Sources/Elements/Navigation/NavigationBarAppearance.swift b/Modules/Capabilities/DesignSystem/Sources/Elements/Navigation/NavigationBarAppearance.swift new file mode 100644 index 00000000..9dd940d7 --- /dev/null +++ b/Modules/Capabilities/DesignSystem/Sources/Elements/Navigation/NavigationBarAppearance.swift @@ -0,0 +1,30 @@ +// Created by Geoff Pado on 5/11/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. + +import UIKit + +public class NavigationBarAppearance: UINavigationBarAppearance { + public override init(idiom: UIUserInterfaceIdiom = UIDevice.current.userInterfaceIdiom) { + super.init(idiom: idiom) + configureWithOpaqueBackground() + backgroundColor = .primaryDark + largeTitleTextAttributes = NavigationBar.largeTitleTextAttributes + titleTextAttributes = NavigationBar.titleTextAttributes + backButtonAppearance.normal.titleTextAttributes = NavigationBar.buttonTitleTextAttributes + backButtonAppearance.highlighted.titleTextAttributes = NavigationBar.buttonTitleTextAttributes + doneButtonAppearance.normal.titleTextAttributes = NavigationBar.buttonTitleTextAttributes + doneButtonAppearance.highlighted.titleTextAttributes = NavigationBar.buttonTitleTextAttributes + buttonAppearance.normal.titleTextAttributes = NavigationBar.buttonTitleTextAttributes + buttonAppearance.highlighted.titleTextAttributes = NavigationBar.buttonTitleTextAttributes + } + + public override init(barAppearance: UIBarAppearance) { + super.init(barAppearance: barAppearance) + } + + @available(*, unavailable) + required init(coder: NSCoder) { + let typeName = NSStringFromClass(type(of: self)) + fatalError("\(typeName) does not implement init(coder:)") + } +} diff --git a/Modules/Legacy/Core/Sources/Application/AppDelegate.swift b/Modules/Legacy/Core/Sources/Application/AppDelegate.swift index f9f0977d..03523c77 100644 --- a/Modules/Legacy/Core/Sources/Application/AppDelegate.swift +++ b/Modules/Legacy/Core/Sources/Application/AppDelegate.swift @@ -2,6 +2,7 @@ // Copyright © 2019 Cocoatype, LLC. All rights reserved. import Defaults +import DesignSystem import Editing import ErrorHandling import Logging diff --git a/Modules/Legacy/Core/Sources/Photo Selection/PhotoSelectionNavigationController.swift b/Modules/Legacy/Core/Sources/Photo Selection/PhotoSelectionNavigationController.swift index a01277ee..d640f857 100644 --- a/Modules/Legacy/Core/Sources/Photo Selection/PhotoSelectionNavigationController.swift +++ b/Modules/Legacy/Core/Sources/Photo Selection/PhotoSelectionNavigationController.swift @@ -1,6 +1,7 @@ // Created by Geoff Pado on 4/8/19. // Copyright © 2019 Cocoatype, LLC. All rights reserved. +import DesignSystem import Editing import Introspect import Photos diff --git a/Modules/Legacy/Editing/Sources/Navigation/NavigationBar.swift b/Modules/Legacy/Editing/Sources/Navigation/NavigationBar.swift deleted file mode 100644 index 8c292bdf..00000000 --- a/Modules/Legacy/Editing/Sources/Navigation/NavigationBar.swift +++ /dev/null @@ -1,90 +0,0 @@ -// Created by Geoff Pado on 5/15/19. -// Copyright © 2019 Cocoatype, LLC. All rights reserved. - -import Introspect -import SwiftUI -import UIKit - -public class NavigationBar: UINavigationBar { - public override init(frame: CGRect) { - super.init(frame: frame) - tintColor = .white - - standardAppearance = NavigationBarAppearance() - compactAppearance = NavigationBarAppearance() - scrollEdgeAppearance = NavigationBarAppearance() - - if #available(iOS 15.0, *) { - compactScrollEdgeAppearance = NavigationBarAppearance() - } - isTranslucent = false - } - - // MARK: Bar Button Appearance - - static let largeTitleTextAttributes = [ - NSAttributedString.Key.font: UIFont.navigationBarLargeTitleFont - ] - - public static let buttonTitleTextAttributes = [ - NSAttributedString.Key.font: UIFont.navigationBarButtonFont, - .foregroundColor: UIColor.white, - ] - - public static let titleTextAttributes = [ - NSAttributedString.Key.font: UIFont.navigationBarTitleFont, - .foregroundColor: UIColor.white, - ] - - // MARK: Boilerplate - - @available(*, unavailable) - required init(coder: NSCoder) { - let className = String(describing: type(of: self)) - fatalError("\(className) does not implement init(coder:)") - } -} - -public class NavigationBarAppearance: UINavigationBarAppearance { - public override init(idiom: UIUserInterfaceIdiom = UIDevice.current.userInterfaceIdiom) { - super.init(idiom: idiom) - configureWithOpaqueBackground() - backgroundColor = .primaryDark - largeTitleTextAttributes = NavigationBar.largeTitleTextAttributes - titleTextAttributes = NavigationBar.titleTextAttributes - backButtonAppearance.normal.titleTextAttributes = NavigationBar.buttonTitleTextAttributes - backButtonAppearance.highlighted.titleTextAttributes = NavigationBar.buttonTitleTextAttributes - doneButtonAppearance.normal.titleTextAttributes = NavigationBar.buttonTitleTextAttributes - doneButtonAppearance.highlighted.titleTextAttributes = NavigationBar.buttonTitleTextAttributes - buttonAppearance.normal.titleTextAttributes = NavigationBar.buttonTitleTextAttributes - buttonAppearance.highlighted.titleTextAttributes = NavigationBar.buttonTitleTextAttributes - } - - public override init(barAppearance: UIBarAppearance) { - super.init(barAppearance: barAppearance) - } - - @available(*, unavailable) - required init(coder: NSCoder) { - let typeName = NSStringFromClass(type(of: self)) - fatalError("\(typeName) does not implement init(coder:)") - } -} - -struct NavigationBarAppearanceViewModifier: ViewModifier { - func body(content: Content) -> some View { - AnyView(content).introspectNavigationController { navigationController in - navigationController.navigationBar.standardAppearance = NavigationBarAppearance() - navigationController.navigationBar.scrollEdgeAppearance = NavigationBarAppearance() - - navigationController.navigationBar.tintColor = .white - navigationController.navigationBar.prefersLargeTitles = false - } - } -} - -public extension View { - func appNavigationBarAppearance() -> some View { - self.modifier(NavigationBarAppearanceViewModifier()) - } -} diff --git a/Modules/Legacy/Editing/Sources/Navigation/NavigationBarAppearanceViewModifier.swift b/Modules/Legacy/Editing/Sources/Navigation/NavigationBarAppearanceViewModifier.swift new file mode 100644 index 00000000..c287cef1 --- /dev/null +++ b/Modules/Legacy/Editing/Sources/Navigation/NavigationBarAppearanceViewModifier.swift @@ -0,0 +1,24 @@ +// Created by Geoff Pado on 5/11/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. + +import DesignSystem +import Introspect +import SwiftUI + +struct NavigationBarAppearanceViewModifier: ViewModifier { + func body(content: Content) -> some View { + AnyView(content).introspectNavigationController { navigationController in + navigationController.navigationBar.standardAppearance = NavigationBarAppearance() + navigationController.navigationBar.scrollEdgeAppearance = NavigationBarAppearance() + + navigationController.navigationBar.tintColor = .white + navigationController.navigationBar.prefersLargeTitles = false + } + } +} + +public extension View { + func appNavigationBarAppearance() -> some View { + self.modifier(NavigationBarAppearanceViewModifier()) + } +} diff --git a/Modules/Legacy/Editing/Sources/Navigation/NavigationController.swift b/Modules/Legacy/Editing/Sources/Navigation/NavigationController.swift index 262a3b1d..904d9f0f 100644 --- a/Modules/Legacy/Editing/Sources/Navigation/NavigationController.swift +++ b/Modules/Legacy/Editing/Sources/Navigation/NavigationController.swift @@ -1,6 +1,7 @@ // Created by Geoff Pado on 4/3/19. // Copyright © 2019 Cocoatype, LLC. All rights reserved. +import DesignSystem import UIKit open class NavigationController: UINavigationController { diff --git a/Modules/Legacy/Editing/Sources/Navigation/Toolbar.swift b/Modules/Legacy/Editing/Sources/Navigation/Toolbar.swift index 67ddf479..43dec613 100644 --- a/Modules/Legacy/Editing/Sources/Navigation/Toolbar.swift +++ b/Modules/Legacy/Editing/Sources/Navigation/Toolbar.swift @@ -1,6 +1,7 @@ // Created by Geoff Pado on 5/15/19. // Copyright © 2019 Cocoatype, LLC. All rights reserved. +import DesignSystem import UIKit public class Toolbar: UIToolbar { From 27217dc93c995ec36c8a613c03fb021ede1c4de7 Mon Sep 17 00:00:00 2001 From: Geoff Pado Date: Sat, 11 May 2024 13:39:05 -0700 Subject: [PATCH 2/8] Extract unpurchased alert to module --- App/Resources/Localizable.strings | 11 ---- .../Unpurchased/Resources/Localizable.strings | 7 +++ .../UnpurchasedAlertControllerFactory.swift | 55 +++++++++++++++++++ .../UnpurchasedAlertViewModifier.swift | 44 +++++++++++++++ .../Sources/UnpurchasedFeature.swift | 35 ++++++++++++ ...ntScannerNotPurchasedAlertController.swift | 46 ---------------- .../DocumentScanningController.swift | 3 +- .../Settings/List/SettingsAlertButton.swift | 13 ++--- Project.swift | 2 + .../TargetExtensions.swift | 2 + .../Targets/Core.swift | 1 + .../Targets/Receipts.swift | 1 + .../Targets/Unpurchased.swift | 7 +++ 13 files changed, 160 insertions(+), 67 deletions(-) create mode 100644 Modules/Capabilities/Unpurchased/Resources/Localizable.strings create mode 100644 Modules/Capabilities/Unpurchased/Sources/UnpurchasedAlertControllerFactory.swift create mode 100644 Modules/Capabilities/Unpurchased/Sources/UnpurchasedAlertViewModifier.swift create mode 100644 Modules/Capabilities/Unpurchased/Sources/UnpurchasedFeature.swift delete mode 100644 Modules/Legacy/Core/Sources/Document Scanning/DocumentScannerNotPurchasedAlertController.swift create mode 100644 Tuist/ProjectDescriptionHelpers/Targets/Unpurchased.swift diff --git a/App/Resources/Localizable.strings b/App/Resources/Localizable.strings index b03cd812..1971ddeb 100644 --- a/App/Resources/Localizable.strings +++ b/App/Resources/Localizable.strings @@ -58,12 +58,6 @@ "DismissBarButtonItem.title" = "Done"; -"DocumentScannerNotPurchasedAlertController.dismissButton" = "OK"; -"DocumentScannerNotPurchasedAlertController.learnMoreButton" = "Learn More…"; -"DocumentScannerNotPurchasedAlertController.hideButton" = "Never Show This"; -"DocumentScannerNotPurchasedAlertController.message" = "Using the document scanner requires the Ultra Highlighter, a one-time purchase."; -"DocumentScannerNotPurchasedAlertController.title" = "Requires Ultra Highlighter"; - "DoneButton.label" = "Done"; "HighlighterToolBarButtonItem.buttonTitle" = "Tools"; @@ -154,11 +148,6 @@ "SettingsContentGenerator.versionStringFormat" = "Version %@"; -"SettingsView.notPurchasedAlertTitle" = "Requires Ultra Highlighter"; -"SettingsView.notPurchasedAlertMessage" = "Automatically hiding words requires the Ultra Highlighter, a one-time purchase."; -"SettingsView.notPurchasedDismissButton" = "OK"; -"SettingsView.notPurchasedHideButton" = "Never Show This"; - "SettingsViewController.navigationTitle" = "Settings"; "ShareItem.label" = "Share"; diff --git a/Modules/Capabilities/Unpurchased/Resources/Localizable.strings b/Modules/Capabilities/Unpurchased/Resources/Localizable.strings new file mode 100644 index 00000000..58f66c4f --- /dev/null +++ b/Modules/Capabilities/Unpurchased/Resources/Localizable.strings @@ -0,0 +1,7 @@ +"UnpurchasedAlert.dismissButton" = "OK"; +"UnpurchasedAlert.hideButton" = "Hide This Feature"; +"UnpurchasedAlert.learnMoreButton" = "Learn More…"; +"UnpurchasedAlert.title" = "Requires Ultra Highlighter"; + +"UnpurchasedFeature.autoRedactions.message" = "Automatically hiding words requires the Ultra Highlighter, a one-time purchase."; +"UnpurchasedFeature.documentScanner.message" = "Using the document scanner requires the Ultra Highlighter, a one-time purchase."; diff --git a/Modules/Capabilities/Unpurchased/Sources/UnpurchasedAlertControllerFactory.swift b/Modules/Capabilities/Unpurchased/Sources/UnpurchasedAlertControllerFactory.swift new file mode 100644 index 00000000..cf3e2db0 --- /dev/null +++ b/Modules/Capabilities/Unpurchased/Sources/UnpurchasedAlertControllerFactory.swift @@ -0,0 +1,55 @@ +// Created by Geoff Pado on 2/18/22. +// Copyright © 2022 Cocoatype, LLC. All rights reserved. + +import Defaults +import UIKit + +public class UnpurchasedAlertControllerFactory { + public init() {} + + public func alertController(for feature: UnpurchasedFeature) -> UIAlertController { + let alertController = UIAlertController( + title: Strings.title, + message: feature.message, + preferredStyle: .alert + ) + + if let learnMoreAction = feature.learnMoreAction { + alertController.addAction( + UIAlertAction( + title: Strings.learnMoreButton, + style: .default, + handler: { _ in + learnMoreAction() + } + ) + ) + } + + if let hideFeatureKey = feature.hideFeatureKey { + @Defaults.Value(key: hideFeatureKey) var hideFeature: Bool + alertController.addAction( + UIAlertAction( + title: Strings.hideButton, + style: .default, + handler: { _ in + hideFeature = true + } + ) + ) + } + + alertController.addAction( + UIAlertAction( + title: Strings.dismissButton, + style: .cancel, + handler: { _ in } + ) + ) + + + return alertController + } + + private typealias Strings = UnpurchasedStrings.UnpurchasedAlert +} diff --git a/Modules/Capabilities/Unpurchased/Sources/UnpurchasedAlertViewModifier.swift b/Modules/Capabilities/Unpurchased/Sources/UnpurchasedAlertViewModifier.swift new file mode 100644 index 00000000..e823f941 --- /dev/null +++ b/Modules/Capabilities/Unpurchased/Sources/UnpurchasedAlertViewModifier.swift @@ -0,0 +1,44 @@ +// Created by Geoff Pado on 5/11/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. + +import Defaults +import SwiftUI + +public struct UnpurchasedAlertViewModifier: ViewModifier { + @Binding private var isPresented: Bool + private let feature: UnpurchasedFeature + init(for feature: UnpurchasedFeature, isPresented: Binding) { + _isPresented = isPresented + self.feature = feature + } + + public func body(content: Content) -> some View { + content.alert(isPresented: $isPresented) { + if let hideFeatureKey = feature.hideFeatureKey { + @Defaults.Value(key: hideFeatureKey) var hideFeature: Bool + return Alert( + title: Text(Strings.title), + message: Text(feature.message), + primaryButton: .cancel(Text(Strings.dismissButton)), + secondaryButton: .default(Text(Strings.hideButton)) { + hideFeature = true + } + ) + } else { + return Alert( + title: Text(Strings.title), + message: Text(feature.message), + dismissButton: .cancel(Text(Strings.dismissButton)) + ) + } + } + } + + private typealias Strings = UnpurchasedStrings.UnpurchasedAlert +} + +public extension View { + func unpurchasedAlert(for feature: UnpurchasedFeature, isPresented: Binding) -> ModifiedContent { + modifier(UnpurchasedAlertViewModifier(for: feature, isPresented: isPresented)) + } +} diff --git a/Modules/Capabilities/Unpurchased/Sources/UnpurchasedFeature.swift b/Modules/Capabilities/Unpurchased/Sources/UnpurchasedFeature.swift new file mode 100644 index 00000000..a26ef84e --- /dev/null +++ b/Modules/Capabilities/Unpurchased/Sources/UnpurchasedFeature.swift @@ -0,0 +1,35 @@ +// Created by Geoff Pado on 5/11/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. + +import Defaults +import Foundation + +public struct UnpurchasedFeature { + public static let autoRedactions = UnpurchasedFeature( + message: Strings.AutoRedactions.message, + learnMoreAction: nil, + hideFeatureKey: .hideAutoRedactions + ) + + public static func documentScanner(learnMoreAction: (() -> Void)?) -> UnpurchasedFeature { + UnpurchasedFeature( + message: Strings.DocumentScanner.message, + learnMoreAction: learnMoreAction, + hideFeatureKey: .hideDocumentScanner + ) + } + + // MARK: - Implementation Details + + let message: String + let learnMoreAction: (() -> Void)? + let hideFeatureKey: Defaults.Key? + + private init(message: String, learnMoreAction: ( () -> Void)?, hideFeatureKey: Defaults.Key?) { + self.message = message + self.learnMoreAction = learnMoreAction + self.hideFeatureKey = hideFeatureKey + } + + private typealias Strings = UnpurchasedStrings.UnpurchasedFeature +} diff --git a/Modules/Legacy/Core/Sources/Document Scanning/DocumentScannerNotPurchasedAlertController.swift b/Modules/Legacy/Core/Sources/Document Scanning/DocumentScannerNotPurchasedAlertController.swift deleted file mode 100644 index f5caadea..00000000 --- a/Modules/Legacy/Core/Sources/Document Scanning/DocumentScannerNotPurchasedAlertController.swift +++ /dev/null @@ -1,46 +0,0 @@ -// Created by Geoff Pado on 2/18/22. -// Copyright © 2022 Cocoatype, LLC. All rights reserved. - -import Defaults -import Editing -import UIKit - -class DocumentScannerNotPurchasedAlertController: UIAlertController { - convenience init(learnMoreAction: (() -> Void)?) { - let title = NSLocalizedString("DocumentScannerNotPurchasedAlertController.title", comment: "Title for the document scanner not purchased alert") - let message = NSLocalizedString("DocumentScannerNotPurchasedAlertController.message", comment: "Message for the document scanner not purchased alert") - self.init(title: title, message: message, preferredStyle: .alert) - - if let learnMoreAction = learnMoreAction { - addAction( - UIAlertAction( - title: NSLocalizedString("DocumentScannerNotPurchasedAlertController.learnMoreButton", comment: ""), - style: .default, - handler: { _ in - learnMoreAction() - })) - } - - addAction( - UIAlertAction( - title: NSLocalizedString("DocumentScannerNotPurchasedAlertController.hideButton", comment: ""), - style: .default, - handler: { [weak self] _ in - self?.hideDocumentScanner = true - })) - - addAction( - UIAlertAction( - title: NSLocalizedString("DocumentScannerNotPurchasedAlertController.dismissButton", comment: ""), - style: .cancel, - handler: { _ in })) - } - - private var latestParent: UIViewController? - override func didMove(toParent parent: UIViewController?) { - guard let parent = parent else { return } - latestParent = parent - } - - @Defaults.Value(key: .hideDocumentScanner) private var hideDocumentScanner: Bool -} diff --git a/Modules/Legacy/Core/Sources/Document Scanning/DocumentScanningController.swift b/Modules/Legacy/Core/Sources/Document Scanning/DocumentScanningController.swift index ab4a1ebb..ffecd7f3 100644 --- a/Modules/Legacy/Core/Sources/Document Scanning/DocumentScanningController.swift +++ b/Modules/Legacy/Core/Sources/Document Scanning/DocumentScanningController.swift @@ -4,6 +4,7 @@ import Editing import Purchasing import UIKit +import Unpurchased import VisionKit class DocumentScanningController: NSObject, VNDocumentCameraViewControllerDelegate { @@ -20,7 +21,7 @@ class DocumentScanningController: NSObject, VNDocumentCameraViewControllerDelega cameraViewController.view.tintColor = .controlTint return cameraViewController } else { - return DocumentScannerNotPurchasedAlertController(learnMoreAction: delegate?.presentPurchaseMarketing) + return UnpurchasedAlertControllerFactory().alertController(for: .documentScanner(learnMoreAction: delegate?.presentPurchaseMarketing)) } } diff --git a/Modules/Legacy/Core/Sources/Settings/List/SettingsAlertButton.swift b/Modules/Legacy/Core/Sources/Settings/List/SettingsAlertButton.swift index 3516ef57..42445d7c 100644 --- a/Modules/Legacy/Core/Sources/Settings/List/SettingsAlertButton.swift +++ b/Modules/Legacy/Core/Sources/Settings/List/SettingsAlertButton.swift @@ -4,6 +4,7 @@ import Defaults import Editing import SwiftUI +import Unpurchased struct SettingsAlertButton: View { @State private var showAlert = false @@ -24,15 +25,9 @@ struct SettingsAlertButton: View { WebURLSubtitleText(subtitle) } } - }.alert(isPresented: $showAlert) { - Alert( - title: Text("SettingsView.notPurchasedAlertTitle"), - message: Text("SettingsView.notPurchasedAlertMessage"), - primaryButton: .cancel(Text("SettingsView.notPurchasedDismissButton")), - secondaryButton: .default(Text("SettingsView.notPurchasedHideButton")) { - hideAutoRedactions = true - }) - }.settingsCell() + } + .unpurchasedAlert(for: .autoRedactions, isPresented: $showAlert) + .settingsCell() } } diff --git a/Project.swift b/Project.swift index d454c111..879503ad 100644 --- a/Project.swift +++ b/Project.swift @@ -14,6 +14,7 @@ let project = Project( "ASSETCATALOG_COMPILER_APPICON_NAME": "AppIcon", "ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME": "Accent Color", "CODE_SIGN_STYLE": "Manual", + "CURRENT_PROJECT_VERSION": "0", "DEVELOPMENT_TEAM": "287EDDET2B", "ENABLE_HARDENED_RUNTIME[sdk=macosx*]": "YES", "IPHONEOS_DEPLOYMENT_TARGET": "14.0", @@ -47,6 +48,7 @@ let project = Project( Redacting.target, Redactions.target, TestHelpers.target, + Unpurchased.target, // tests AppRatings.testTarget, AutoRedactionsUI.testTarget, diff --git a/Tuist/ProjectDescriptionHelpers/TargetExtensions.swift b/Tuist/ProjectDescriptionHelpers/TargetExtensions.swift index 5f172423..6d902f41 100644 --- a/Tuist/ProjectDescriptionHelpers/TargetExtensions.swift +++ b/Tuist/ProjectDescriptionHelpers/TargetExtensions.swift @@ -3,6 +3,7 @@ import ProjectDescription extension Target { static func capabilitiesTarget( name: String, + hasResources: Bool = false, dependencies: [TargetDependency] = [] ) -> Target { Target.target( @@ -11,6 +12,7 @@ extension Target { product: .framework, bundleId: "com.cocoatype.Highlighter.\(name)", sources: ["Modules/Capabilities/\(name)/Sources/**"], + resources: hasResources ? ["Modules/Capabilities/\(name)/Resources/**"] : nil, dependencies: dependencies ) } diff --git a/Tuist/ProjectDescriptionHelpers/Targets/Core.swift b/Tuist/ProjectDescriptionHelpers/Targets/Core.swift index 371377fe..6e679f26 100644 --- a/Tuist/ProjectDescriptionHelpers/Targets/Core.swift +++ b/Tuist/ProjectDescriptionHelpers/Targets/Core.swift @@ -15,6 +15,7 @@ public enum Core { .target(Editing.target), .target(Purchasing.target), .target(Receipts.target), + .target(Unpurchased.target), ] ) diff --git a/Tuist/ProjectDescriptionHelpers/Targets/Receipts.swift b/Tuist/ProjectDescriptionHelpers/Targets/Receipts.swift index a705d084..95a9f811 100644 --- a/Tuist/ProjectDescriptionHelpers/Targets/Receipts.swift +++ b/Tuist/ProjectDescriptionHelpers/Targets/Receipts.swift @@ -16,6 +16,7 @@ public enum Receipts { sources: ["Modules/Legacy/Receipts/Sources/**"], dependencies: [ .target(ErrorHandling.target), + .package(product: "OpenSSL", type: .runtime), ] ) } diff --git a/Tuist/ProjectDescriptionHelpers/Targets/Unpurchased.swift b/Tuist/ProjectDescriptionHelpers/Targets/Unpurchased.swift new file mode 100644 index 00000000..f150bc6f --- /dev/null +++ b/Tuist/ProjectDescriptionHelpers/Targets/Unpurchased.swift @@ -0,0 +1,7 @@ +import ProjectDescription + +public enum Unpurchased { + public static let target = Target.capabilitiesTarget(name: "Unpurchased", hasResources: true, dependencies: [ + .target(Defaults.target), + ]) +} From fb7d0cdca20edce9eb68762c98ee4b0c6a76e9e2 Mon Sep 17 00:00:00 2001 From: Geoff Pado Date: Sat, 11 May 2024 14:22:58 -0700 Subject: [PATCH 3/8] Add unpurchased alert to auto-redactions access --- .../UnpurchasedAlertControllerFactory.swift | 3 +-- ...oEditingAutoRedactionsAccessProvider.swift | 26 +++++++++++++++++++ .../PhotoEditingViewController.swift | 11 ++++---- Project.swift | 1 + .../Targets/Receipts.swift | 1 - 5 files changed, 34 insertions(+), 8 deletions(-) create mode 100644 Modules/Legacy/Editing/Sources/Editing View/PhotoEditingAutoRedactionsAccessProvider.swift diff --git a/Modules/Capabilities/Unpurchased/Sources/UnpurchasedAlertControllerFactory.swift b/Modules/Capabilities/Unpurchased/Sources/UnpurchasedAlertControllerFactory.swift index cf3e2db0..16fe04f5 100644 --- a/Modules/Capabilities/Unpurchased/Sources/UnpurchasedAlertControllerFactory.swift +++ b/Modules/Capabilities/Unpurchased/Sources/UnpurchasedAlertControllerFactory.swift @@ -6,7 +6,7 @@ import UIKit public class UnpurchasedAlertControllerFactory { public init() {} - + public func alertController(for feature: UnpurchasedFeature) -> UIAlertController { let alertController = UIAlertController( title: Strings.title, @@ -47,7 +47,6 @@ public class UnpurchasedAlertControllerFactory { ) ) - return alertController } diff --git a/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingAutoRedactionsAccessProvider.swift b/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingAutoRedactionsAccessProvider.swift new file mode 100644 index 00000000..b8a4f9ae --- /dev/null +++ b/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingAutoRedactionsAccessProvider.swift @@ -0,0 +1,26 @@ +// Created by Geoff Pado on 5/11/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. + +import AutoRedactionsUI +import Purchasing +import UIKit +import Unpurchased + +class PhotoEditingAutoRedactionsAccessProvider: NSObject { + func autoRedactionsAccessViewController() -> UIViewController { + if purchased { + return AutoRedactionsAccessViewController() + } else { + return UnpurchasedAlertControllerFactory() + .alertController(for: .autoRedactions) + } + } + + private var purchased: Bool { + do { + return try PreviousPurchasePublisher + .hasUserPurchasedProduct() + .get() + } catch { return false } + } +} diff --git a/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingViewController.swift b/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingViewController.swift index c444a8ae..3c136425 100644 --- a/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingViewController.swift +++ b/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingViewController.swift @@ -28,12 +28,13 @@ public class PhotoEditingViewController: UIViewController, UIScrollViewDelegate, }) viewerNamesAreNotRidiculous = NotificationCenter.default.addObserver(forName: _tuBrute.valueDidChange, object: nil, queue: nil) { [weak self] _ in - guard let thisMeetingCouldHaveBeenAnEmail = self, - let observations = thisMeetingCouldHaveBeenAnEmail.photoEditingView.recognizedTextObservations + // thisMeetingCouldHaveBeenAnEmail by @nutterfi on 2024-04-29 + // this view's recognized text observations + guard let thisMeetingCouldHaveBeenAnEmail = self?.photoEditingView.recognizedTextObservations else { return } - thisMeetingCouldHaveBeenAnEmail.removeAutoRedactions(from: observations) - thisMeetingCouldHaveBeenAnEmail.autoRedact(using: observations) + self?.removeAutoRedactions(from: thisMeetingCouldHaveBeenAnEmail) + self?.autoRedact(using: thisMeetingCouldHaveBeenAnEmail) } updateToolbarItems(animated: false) @@ -288,7 +289,7 @@ public class PhotoEditingViewController: UIViewController, UIScrollViewDelegate, // MARK: Auto Redact @objc private func showAutoRedactAccess(_ sender: Any) { - present(AutoRedactionsAccessNavigationController(), animated: true) + present(PhotoEditingAutoRedactionsAccessProvider().autoRedactionsAccessViewController(), animated: true) } @objc private func hideAutoRedactAccess(_ sender: Any) { diff --git a/Project.swift b/Project.swift index 879503ad..0e2dd30e 100644 --- a/Project.swift +++ b/Project.swift @@ -19,6 +19,7 @@ let project = Project( "ENABLE_HARDENED_RUNTIME[sdk=macosx*]": "YES", "IPHONEOS_DEPLOYMENT_TARGET": "14.0", "MACOSX_DEPLOYMENT_TARGET": "11.0", + "MARKETING_VERSION": "999", "OTHER_CODE_SIGN_FLAGS": "--deep", "TARGETED_DEVICE_FAMILY": "1,2,6", ], debug: [ diff --git a/Tuist/ProjectDescriptionHelpers/Targets/Receipts.swift b/Tuist/ProjectDescriptionHelpers/Targets/Receipts.swift index 95a9f811..a705d084 100644 --- a/Tuist/ProjectDescriptionHelpers/Targets/Receipts.swift +++ b/Tuist/ProjectDescriptionHelpers/Targets/Receipts.swift @@ -16,7 +16,6 @@ public enum Receipts { sources: ["Modules/Legacy/Receipts/Sources/**"], dependencies: [ .target(ErrorHandling.target), - .package(product: "OpenSSL", type: .runtime), ] ) } From ae6731da6e52a1cadc13dd9f3261a96ef414b6fb Mon Sep 17 00:00:00 2001 From: Geoff Pado Date: Mon, 13 May 2024 15:49:40 -0700 Subject: [PATCH 4/8] Update and test design of unpurchased alert --- .../Web Tint Color.colorset/Contents.json | 38 -------------- .../DesignSystem/Sources/Tokens/Colors.swift | 15 +++++- .../UnpurchasedAlertControllerFactory.swift | 3 ++ .../Sources/UnpurchasedFeature.swift | 20 +++++--- ...purchasedAlertControllerFactoryTests.swift | 49 +++++++++++++++++++ .../Settings/List/SettingsAlertButton.swift | 2 +- ...oEditingAutoRedactionsAccessProvider.swift | 4 +- .../PhotoEditingViewController.swift | 8 ++- Project.swift | 1 + .../Targets/DesignSystem.swift | 13 ++--- .../Targets/Unpurchased.swift | 5 ++ 11 files changed, 97 insertions(+), 61 deletions(-) delete mode 100644 App/Resources/Assets.xcassets/Web Tint Color.colorset/Contents.json create mode 100644 Modules/Capabilities/Unpurchased/Tests/UnpurchasedAlertControllerFactoryTests.swift diff --git a/App/Resources/Assets.xcassets/Web Tint Color.colorset/Contents.json b/App/Resources/Assets.xcassets/Web Tint Color.colorset/Contents.json deleted file mode 100644 index 51a1f5b9..00000000 --- a/App/Resources/Assets.xcassets/Web Tint Color.colorset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - }, - "colors" : [ - { - "idiom" : "universal", - "color" : { - "color-space" : "srgb", - "components" : { - "red" : "0x21", - "alpha" : "1.000", - "blue" : "0x21", - "green" : "0x21" - } - } - }, - { - "idiom" : "universal", - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "srgb", - "components" : { - "red" : "1.000", - "alpha" : "1.000", - "blue" : "1.000", - "green" : "1.000" - } - } - } - ] -} \ No newline at end of file diff --git a/Modules/Capabilities/DesignSystem/Sources/Tokens/Colors.swift b/Modules/Capabilities/DesignSystem/Sources/Tokens/Colors.swift index b6cb5b5b..158ac133 100644 --- a/Modules/Capabilities/DesignSystem/Sources/Tokens/Colors.swift +++ b/Modules/Capabilities/DesignSystem/Sources/Tokens/Colors.swift @@ -19,7 +19,7 @@ public extension UIColor { static let primary = UIColor(hexLiteral: 0x212121) static let primaryDark = UIColor(hexLiteral: 0x1b1b1b) - static let controlTint = UIColor(named: "Web Tint Color") + static let controlTint = UIColor(light: .primary, dark: .white) static let tableViewCellBackground = UIColor(hexLiteral: 0x2c2c2c) static let tableViewCellBackgroundHighlighted = UIColor.primaryLight static let tableViewSeparator = UIColor(hexLiteral: 0x878787) @@ -27,6 +27,19 @@ public extension UIColor { static let seekBoxInnerBorder = UIColor(named: "Seek Box Inner Border") static let seekBoxOuterBorder = UIColor(named: "Seek Box Outer Border") + // MARK: - Dynamic Colors + convenience init(light: UIColor, dark: UIColor) { + self.init { traitCollection in + switch traitCollection.userInterfaceStyle { + case .dark: return dark + case .light, .unspecified: fallthrough + @unknown default: return light + } + } + } + + // MARK: - Hex + convenience init(hexLiteral hex: Int) { let red = CGFloat((hex & 0xFF0000) >> 16) let green = CGFloat((hex & 0x00FF00) >> 8) diff --git a/Modules/Capabilities/Unpurchased/Sources/UnpurchasedAlertControllerFactory.swift b/Modules/Capabilities/Unpurchased/Sources/UnpurchasedAlertControllerFactory.swift index 16fe04f5..0516b725 100644 --- a/Modules/Capabilities/Unpurchased/Sources/UnpurchasedAlertControllerFactory.swift +++ b/Modules/Capabilities/Unpurchased/Sources/UnpurchasedAlertControllerFactory.swift @@ -2,6 +2,7 @@ // Copyright © 2022 Cocoatype, LLC. All rights reserved. import Defaults +import DesignSystem import UIKit public class UnpurchasedAlertControllerFactory { @@ -14,6 +15,8 @@ public class UnpurchasedAlertControllerFactory { preferredStyle: .alert ) + alertController.view.tintColor = .controlTint + if let learnMoreAction = feature.learnMoreAction { alertController.addAction( UIAlertAction( diff --git a/Modules/Capabilities/Unpurchased/Sources/UnpurchasedFeature.swift b/Modules/Capabilities/Unpurchased/Sources/UnpurchasedFeature.swift index a26ef84e..36ff0e9f 100644 --- a/Modules/Capabilities/Unpurchased/Sources/UnpurchasedFeature.swift +++ b/Modules/Capabilities/Unpurchased/Sources/UnpurchasedFeature.swift @@ -5,13 +5,17 @@ import Defaults import Foundation public struct UnpurchasedFeature { - public static let autoRedactions = UnpurchasedFeature( - message: Strings.AutoRedactions.message, - learnMoreAction: nil, - hideFeatureKey: .hideAutoRedactions - ) + public typealias LearnMoreAction = () -> Void - public static func documentScanner(learnMoreAction: (() -> Void)?) -> UnpurchasedFeature { + public static func autoRedactions(learnMoreAction: LearnMoreAction? = nil) -> UnpurchasedFeature { + UnpurchasedFeature( + message: Strings.AutoRedactions.message, + learnMoreAction: nil, + hideFeatureKey: .hideAutoRedactions + ) + } + + public static func documentScanner(learnMoreAction: LearnMoreAction?) -> UnpurchasedFeature { UnpurchasedFeature( message: Strings.DocumentScanner.message, learnMoreAction: learnMoreAction, @@ -22,10 +26,10 @@ public struct UnpurchasedFeature { // MARK: - Implementation Details let message: String - let learnMoreAction: (() -> Void)? + let learnMoreAction: LearnMoreAction? let hideFeatureKey: Defaults.Key? - private init(message: String, learnMoreAction: ( () -> Void)?, hideFeatureKey: Defaults.Key?) { + init(message: String, learnMoreAction: LearnMoreAction?, hideFeatureKey: Defaults.Key?) { self.message = message self.learnMoreAction = learnMoreAction self.hideFeatureKey = hideFeatureKey diff --git a/Modules/Capabilities/Unpurchased/Tests/UnpurchasedAlertControllerFactoryTests.swift b/Modules/Capabilities/Unpurchased/Tests/UnpurchasedAlertControllerFactoryTests.swift new file mode 100644 index 00000000..186cca9d --- /dev/null +++ b/Modules/Capabilities/Unpurchased/Tests/UnpurchasedAlertControllerFactoryTests.swift @@ -0,0 +1,49 @@ +// Created by Geoff Pado on 5/11/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. + +import DesignSystem +import XCTest + +@testable import Unpurchased + +class UnpurchasedAlertControllerFactoryTests: XCTestCase { + func testAlertControllerHasCorrectTint() { + let feature = UnpurchasedFeature(message: "", learnMoreAction: nil, hideFeatureKey: nil) + let factory = UnpurchasedAlertControllerFactory() + let alert = factory.alertController(for: feature) + + XCTAssertEqual(alert.view.tintColor, .controlTint) + } + + func testAlertControllerSetsMessage() { + let feature = UnpurchasedFeature(message: "Hello, world!", learnMoreAction: nil, hideFeatureKey: nil) + let factory = UnpurchasedAlertControllerFactory() + let alert = factory.alertController(for: feature) + + XCTAssertEqual(alert.message, feature.message) + } + + func testAlertControllerAlwaysHasOneAction() { + let feature = UnpurchasedFeature(message: "", learnMoreAction: nil, hideFeatureKey: nil) + let factory = UnpurchasedAlertControllerFactory() + let alert = factory.alertController(for: feature) + + XCTAssertEqual(alert.actions.count, 1) + } + + func testAlertControllerAddsActionForLearnMore() { + let feature = UnpurchasedFeature(message: "", learnMoreAction: {}, hideFeatureKey: nil) + let factory = UnpurchasedAlertControllerFactory() + let alert = factory.alertController(for: feature) + + XCTAssertEqual(alert.actions.count, 2) + } + + func testAlertControllerAddsActionForHideFeature() { + let feature = UnpurchasedFeature(message: "", learnMoreAction: nil, hideFeatureKey: .hideAutoRedactions) + let factory = UnpurchasedAlertControllerFactory() + let alert = factory.alertController(for: feature) + + XCTAssertEqual(alert.actions.count, 2) + } +} diff --git a/Modules/Legacy/Core/Sources/Settings/List/SettingsAlertButton.swift b/Modules/Legacy/Core/Sources/Settings/List/SettingsAlertButton.swift index 42445d7c..a99156c1 100644 --- a/Modules/Legacy/Core/Sources/Settings/List/SettingsAlertButton.swift +++ b/Modules/Legacy/Core/Sources/Settings/List/SettingsAlertButton.swift @@ -26,7 +26,7 @@ struct SettingsAlertButton: View { } } } - .unpurchasedAlert(for: .autoRedactions, isPresented: $showAlert) + .unpurchasedAlert(for: .autoRedactions(), isPresented: $showAlert) .settingsCell() } } diff --git a/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingAutoRedactionsAccessProvider.swift b/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingAutoRedactionsAccessProvider.swift index b8a4f9ae..b7d8f736 100644 --- a/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingAutoRedactionsAccessProvider.swift +++ b/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingAutoRedactionsAccessProvider.swift @@ -7,12 +7,12 @@ import UIKit import Unpurchased class PhotoEditingAutoRedactionsAccessProvider: NSObject { - func autoRedactionsAccessViewController() -> UIViewController { + func autoRedactionsAccessViewController(learnMoreAction: UnpurchasedFeature.LearnMoreAction) -> UIViewController { if purchased { return AutoRedactionsAccessViewController() } else { return UnpurchasedAlertControllerFactory() - .alertController(for: .autoRedactions) + .alertController(for: .autoRedactions(learnMoreAction: nil)) } } diff --git a/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingViewController.swift b/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingViewController.swift index 3c136425..2a28a15a 100644 --- a/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingViewController.swift +++ b/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingViewController.swift @@ -289,7 +289,13 @@ public class PhotoEditingViewController: UIViewController, UIScrollViewDelegate, // MARK: Auto Redact @objc private func showAutoRedactAccess(_ sender: Any) { - present(PhotoEditingAutoRedactionsAccessProvider().autoRedactionsAccessViewController(), animated: true) + present( + PhotoEditingAutoRedactionsAccessProvider() + .autoRedactionsAccessViewController { [weak self] in + // TODO: present purchase marketing view +// self?.present(PurchaseMarketingHostingController(), animated: true) + }, + animated: true) } @objc private func hideAutoRedactAccess(_ sender: Any) { diff --git a/Project.swift b/Project.swift index 0e2dd30e..fbd11299 100644 --- a/Project.swift +++ b/Project.swift @@ -60,6 +60,7 @@ let project = Project( Observations.testTarget, Purchasing.testTarget, Redactions.testTarget, + Unpurchased.testTarget, ], schemes: [ .scheme( diff --git a/Tuist/ProjectDescriptionHelpers/Targets/DesignSystem.swift b/Tuist/ProjectDescriptionHelpers/Targets/DesignSystem.swift index 50fe2dc2..b14f8878 100644 --- a/Tuist/ProjectDescriptionHelpers/Targets/DesignSystem.swift +++ b/Tuist/ProjectDescriptionHelpers/Targets/DesignSystem.swift @@ -1,14 +1,7 @@ import ProjectDescription public enum DesignSystem { - public static let target = Target.target( - name: "DesignSystem", - destinations: [.iPhone, .iPad, .macCatalyst, .appleVisionWithiPadDesign], - product: .framework, - bundleId: "com.cocoatype.Highlighter.DesignSystem", - sources: ["Modules/Capabilities/DesignSystem/Sources/**"], - dependencies: [ - .target(ErrorHandling.target) - ] - ) + public static let target = Target.capabilitiesTarget(name: "DesignSystem", dependencies: [ + .target(ErrorHandling.target), + ]) } diff --git a/Tuist/ProjectDescriptionHelpers/Targets/Unpurchased.swift b/Tuist/ProjectDescriptionHelpers/Targets/Unpurchased.swift index f150bc6f..f3f6a000 100644 --- a/Tuist/ProjectDescriptionHelpers/Targets/Unpurchased.swift +++ b/Tuist/ProjectDescriptionHelpers/Targets/Unpurchased.swift @@ -3,5 +3,10 @@ import ProjectDescription public enum Unpurchased { public static let target = Target.capabilitiesTarget(name: "Unpurchased", hasResources: true, dependencies: [ .target(Defaults.target), + .target(DesignSystem.target), + ]) + + public static let testTarget = Target.capabilitiesTestTarget(name: "Unpurchased", dependencies: [ + .target(DesignSystem.target), ]) } From 66e4bd8e09667f6b42f686f28ae783db706cb932 Mon Sep 17 00:00:00 2001 From: Geoff Pado Date: Mon, 13 May 2024 16:12:55 -0700 Subject: [PATCH 5/8] Migrate PurchaseMarketing to module --- .../UIResponderExtensions.swift | 0 .../UIViewControllerExtensions.swift | 0 .../Sources/Extensions/ViewExtensions.swift | 32 +++++++++++++++++++ .../Sources/ReadableWidthKey.swift | 15 +++++++++ .../Sources}/PurchaseMarketingHeader.swift | 0 .../PurchaseMarketingHostingController.swift | 4 +-- .../Sources}/PurchaseMarketingItem.swift | 0 .../Sources}/PurchaseMarketingText.swift | 0 .../Sources}/PurchaseMarketingView.swift | 7 ++-- ...cyPurchaseMarketingTopBarButtonStack.swift | 0 .../Top Bar/ProductPriceFormatter.swift | 4 +-- .../Sources}/Top Bar/PurchaseButton.swift | 0 .../PurchaseMarketingTopBarButtonStack.swift | 0 .../PurchaseMarketingTopBarButtons.swift | 0 .../PurchaseMarketingTopBarCompact.swift | 0 .../PurchaseMarketingTopBarHeadline.swift | 0 .../PurchaseMarketingTopBarRegular.swift | 0 .../PurchaseMarketingTopBarSubheadline.swift | 1 + .../Top Bar/PurchaseRestoreButton.swift | 0 .../Tests/PurchaseMarketingTests.swift | 1 + .../Sources/PurchaseStatePublisherKey.swift} | 14 ++------ .../Sources/UnpurchasedFeature.swift | 2 +- .../Application/AppViewController.swift | 1 + .../Sources/Extensions/ViewExtensions.swift | 25 --------------- .../Desktop/DesktopSettingsView.swift | 1 + .../List/SettingsContentGenerator.swift | 1 + .../Purchase Item/PurchaseSubtitle.swift | 1 + ...oEditingAutoRedactionsAccessProvider.swift | 4 +-- .../PhotoEditingViewController.swift | 4 +-- Project.swift | 14 +++++++- .../Targets/Core.swift | 1 + .../Targets/Editing.swift | 1 + .../Targets/PurchaseMarketing.swift | 10 ++++++ 33 files changed, 94 insertions(+), 49 deletions(-) rename Modules/Capabilities/DesignSystem/Sources/{ => Extensions}/UIResponderExtensions.swift (100%) rename Modules/Capabilities/DesignSystem/Sources/{ => Extensions}/UIViewControllerExtensions.swift (100%) create mode 100644 Modules/Capabilities/DesignSystem/Sources/Extensions/ViewExtensions.swift create mode 100644 Modules/Capabilities/DesignSystem/Sources/ReadableWidthKey.swift rename Modules/{Legacy/Core/Sources/Settings/Purchase Marketing => Capabilities/PurchaseMarketing/Sources}/PurchaseMarketingHeader.swift (100%) rename Modules/{Legacy/Core/Sources/Settings/Purchase Marketing => Capabilities/PurchaseMarketing/Sources}/PurchaseMarketingHostingController.swift (81%) rename Modules/{Legacy/Core/Sources/Settings/Purchase Marketing => Capabilities/PurchaseMarketing/Sources}/PurchaseMarketingItem.swift (100%) rename Modules/{Legacy/Core/Sources/Settings/Purchase Marketing => Capabilities/PurchaseMarketing/Sources}/PurchaseMarketingText.swift (100%) rename Modules/{Legacy/Core/Sources/Settings/Purchase Marketing => Capabilities/PurchaseMarketing/Sources}/PurchaseMarketingView.swift (96%) rename Modules/{Legacy/Core/Sources/Settings/Purchase Marketing => Capabilities/PurchaseMarketing/Sources}/Top Bar/LegacyPurchaseMarketingTopBarButtonStack.swift (100%) rename Modules/{Legacy/Core/Sources/Settings/Purchase Marketing => Capabilities/PurchaseMarketing/Sources}/Top Bar/ProductPriceFormatter.swift (83%) rename Modules/{Legacy/Core/Sources/Settings/Purchase Marketing => Capabilities/PurchaseMarketing/Sources}/Top Bar/PurchaseButton.swift (100%) rename Modules/{Legacy/Core/Sources/Settings/Purchase Marketing => Capabilities/PurchaseMarketing/Sources}/Top Bar/PurchaseMarketingTopBarButtonStack.swift (100%) rename Modules/{Legacy/Core/Sources/Settings/Purchase Marketing => Capabilities/PurchaseMarketing/Sources}/Top Bar/PurchaseMarketingTopBarButtons.swift (100%) rename Modules/{Legacy/Core/Sources/Settings/Purchase Marketing => Capabilities/PurchaseMarketing/Sources}/Top Bar/PurchaseMarketingTopBarCompact.swift (100%) rename Modules/{Legacy/Core/Sources/Settings/Purchase Marketing => Capabilities/PurchaseMarketing/Sources}/Top Bar/PurchaseMarketingTopBarHeadline.swift (100%) rename Modules/{Legacy/Core/Sources/Settings/Purchase Marketing => Capabilities/PurchaseMarketing/Sources}/Top Bar/PurchaseMarketingTopBarRegular.swift (100%) rename Modules/{Legacy/Core/Sources/Settings/Purchase Marketing => Capabilities/PurchaseMarketing/Sources}/Top Bar/PurchaseMarketingTopBarSubheadline.swift (95%) rename Modules/{Legacy/Core/Sources/Settings/Purchase Marketing => Capabilities/PurchaseMarketing/Sources}/Top Bar/PurchaseRestoreButton.swift (100%) create mode 100644 Modules/Capabilities/PurchaseMarketing/Tests/PurchaseMarketingTests.swift rename Modules/{Legacy/Core/Sources/Application/EnvironmentKeys.swift => Capabilities/Purchasing/Sources/PurchaseStatePublisherKey.swift} (53%) create mode 100644 Tuist/ProjectDescriptionHelpers/Targets/PurchaseMarketing.swift diff --git a/Modules/Capabilities/DesignSystem/Sources/UIResponderExtensions.swift b/Modules/Capabilities/DesignSystem/Sources/Extensions/UIResponderExtensions.swift similarity index 100% rename from Modules/Capabilities/DesignSystem/Sources/UIResponderExtensions.swift rename to Modules/Capabilities/DesignSystem/Sources/Extensions/UIResponderExtensions.swift diff --git a/Modules/Capabilities/DesignSystem/Sources/UIViewControllerExtensions.swift b/Modules/Capabilities/DesignSystem/Sources/Extensions/UIViewControllerExtensions.swift similarity index 100% rename from Modules/Capabilities/DesignSystem/Sources/UIViewControllerExtensions.swift rename to Modules/Capabilities/DesignSystem/Sources/Extensions/UIViewControllerExtensions.swift diff --git a/Modules/Capabilities/DesignSystem/Sources/Extensions/ViewExtensions.swift b/Modules/Capabilities/DesignSystem/Sources/Extensions/ViewExtensions.swift new file mode 100644 index 00000000..90ee012a --- /dev/null +++ b/Modules/Capabilities/DesignSystem/Sources/Extensions/ViewExtensions.swift @@ -0,0 +1,32 @@ +// Created by Geoff Pado on 5/13/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. + +import Combine +import SwiftUI + +public extension View { + func onAppReceive

(_ publisher: P, perform action: @escaping (P.Output) -> Void) -> some View where P: Publisher, P.Failure == Never { + let isPreview: Bool +#if DEBUG + isPreview = ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" +#else + isPreview = false +#endif + + if isPreview { + return self.onReceive(publisher, perform: { _ in }) + } else { + return self.onReceive(publisher, perform: action) + } + } + + func fill() -> some View { + return self.modifier(FillViewModifier()) + } +} + +struct FillViewModifier: ViewModifier { + func body(content: Content) -> some View { + AnyView(content).frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center) + } +} diff --git a/Modules/Capabilities/DesignSystem/Sources/ReadableWidthKey.swift b/Modules/Capabilities/DesignSystem/Sources/ReadableWidthKey.swift new file mode 100644 index 00000000..39cd8578 --- /dev/null +++ b/Modules/Capabilities/DesignSystem/Sources/ReadableWidthKey.swift @@ -0,0 +1,15 @@ +// Created by Geoff Pado on 5/13/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. + +import SwiftUI + +struct ReadableWidthKey: EnvironmentKey { + static let defaultValue = CGFloat.zero +} + +public extension EnvironmentValues { + var readableWidth: CGFloat { + get { self[ReadableWidthKey.self] } + set { self[ReadableWidthKey.self] = newValue } + } +} diff --git a/Modules/Legacy/Core/Sources/Settings/Purchase Marketing/PurchaseMarketingHeader.swift b/Modules/Capabilities/PurchaseMarketing/Sources/PurchaseMarketingHeader.swift similarity index 100% rename from Modules/Legacy/Core/Sources/Settings/Purchase Marketing/PurchaseMarketingHeader.swift rename to Modules/Capabilities/PurchaseMarketing/Sources/PurchaseMarketingHeader.swift diff --git a/Modules/Legacy/Core/Sources/Settings/Purchase Marketing/PurchaseMarketingHostingController.swift b/Modules/Capabilities/PurchaseMarketing/Sources/PurchaseMarketingHostingController.swift similarity index 81% rename from Modules/Legacy/Core/Sources/Settings/Purchase Marketing/PurchaseMarketingHostingController.swift rename to Modules/Capabilities/PurchaseMarketing/Sources/PurchaseMarketingHostingController.swift index 54e9b9f9..a19b08dd 100644 --- a/Modules/Legacy/Core/Sources/Settings/Purchase Marketing/PurchaseMarketingHostingController.swift +++ b/Modules/Capabilities/PurchaseMarketing/Sources/PurchaseMarketingHostingController.swift @@ -4,8 +4,8 @@ import SwiftUI import UIKit -class PurchaseMarketingHostingController: UIHostingController { - init() { +public class PurchaseMarketingHostingController: UIHostingController { + public init() { super.init(rootView: PurchaseMarketingView()) modalPresentationStyle = .formSheet preferredContentSize = CGSize(width: 640, height: 640) diff --git a/Modules/Legacy/Core/Sources/Settings/Purchase Marketing/PurchaseMarketingItem.swift b/Modules/Capabilities/PurchaseMarketing/Sources/PurchaseMarketingItem.swift similarity index 100% rename from Modules/Legacy/Core/Sources/Settings/Purchase Marketing/PurchaseMarketingItem.swift rename to Modules/Capabilities/PurchaseMarketing/Sources/PurchaseMarketingItem.swift diff --git a/Modules/Legacy/Core/Sources/Settings/Purchase Marketing/PurchaseMarketingText.swift b/Modules/Capabilities/PurchaseMarketing/Sources/PurchaseMarketingText.swift similarity index 100% rename from Modules/Legacy/Core/Sources/Settings/Purchase Marketing/PurchaseMarketingText.swift rename to Modules/Capabilities/PurchaseMarketing/Sources/PurchaseMarketingText.swift diff --git a/Modules/Legacy/Core/Sources/Settings/Purchase Marketing/PurchaseMarketingView.swift b/Modules/Capabilities/PurchaseMarketing/Sources/PurchaseMarketingView.swift similarity index 96% rename from Modules/Legacy/Core/Sources/Settings/Purchase Marketing/PurchaseMarketingView.swift rename to Modules/Capabilities/PurchaseMarketing/Sources/PurchaseMarketingView.swift index 45ecb72a..dc9d3da0 100644 --- a/Modules/Legacy/Core/Sources/Settings/Purchase Marketing/PurchaseMarketingView.swift +++ b/Modules/Capabilities/PurchaseMarketing/Sources/PurchaseMarketingView.swift @@ -1,12 +1,15 @@ // Created by Geoff Pado on 5/18/21. // Copyright © 2021 Cocoatype, LLC. All rights reserved. +import DesignSystem import SwiftUI -struct PurchaseMarketingView: View { +public struct PurchaseMarketingView: View { @Environment(\.horizontalSizeClass) var horizontalSizeClass - var body: some View { + public init() {} + + public var body: some View { GeometryReader { proxy in VStack(spacing: 0) { Color.primaryDark diff --git a/Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/LegacyPurchaseMarketingTopBarButtonStack.swift b/Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/LegacyPurchaseMarketingTopBarButtonStack.swift similarity index 100% rename from Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/LegacyPurchaseMarketingTopBarButtonStack.swift rename to Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/LegacyPurchaseMarketingTopBarButtonStack.swift diff --git a/Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/ProductPriceFormatter.swift b/Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/ProductPriceFormatter.swift similarity index 83% rename from Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/ProductPriceFormatter.swift rename to Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/ProductPriceFormatter.swift index 07d53cdb..8dc4bc28 100644 --- a/Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/ProductPriceFormatter.swift +++ b/Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/ProductPriceFormatter.swift @@ -3,8 +3,8 @@ import StoreKit -enum ProductPriceFormatter { - static func formattedPrice(for product: SKProduct) -> String? { +public enum ProductPriceFormatter { + public static func formattedPrice(for product: SKProduct) -> String? { if product.priceLocale != Self.priceFormatter.locale { Self.priceFormatter.locale = product.priceLocale } diff --git a/Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/PurchaseButton.swift b/Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/PurchaseButton.swift similarity index 100% rename from Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/PurchaseButton.swift rename to Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/PurchaseButton.swift diff --git a/Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/PurchaseMarketingTopBarButtonStack.swift b/Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/PurchaseMarketingTopBarButtonStack.swift similarity index 100% rename from Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/PurchaseMarketingTopBarButtonStack.swift rename to Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/PurchaseMarketingTopBarButtonStack.swift diff --git a/Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/PurchaseMarketingTopBarButtons.swift b/Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/PurchaseMarketingTopBarButtons.swift similarity index 100% rename from Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/PurchaseMarketingTopBarButtons.swift rename to Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/PurchaseMarketingTopBarButtons.swift diff --git a/Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/PurchaseMarketingTopBarCompact.swift b/Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/PurchaseMarketingTopBarCompact.swift similarity index 100% rename from Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/PurchaseMarketingTopBarCompact.swift rename to Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/PurchaseMarketingTopBarCompact.swift diff --git a/Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/PurchaseMarketingTopBarHeadline.swift b/Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/PurchaseMarketingTopBarHeadline.swift similarity index 100% rename from Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/PurchaseMarketingTopBarHeadline.swift rename to Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/PurchaseMarketingTopBarHeadline.swift diff --git a/Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/PurchaseMarketingTopBarRegular.swift b/Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/PurchaseMarketingTopBarRegular.swift similarity index 100% rename from Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/PurchaseMarketingTopBarRegular.swift rename to Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/PurchaseMarketingTopBarRegular.swift diff --git a/Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/PurchaseMarketingTopBarSubheadline.swift b/Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/PurchaseMarketingTopBarSubheadline.swift similarity index 95% rename from Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/PurchaseMarketingTopBarSubheadline.swift rename to Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/PurchaseMarketingTopBarSubheadline.swift index 9fc3394d..78acacd4 100644 --- a/Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/PurchaseMarketingTopBarSubheadline.swift +++ b/Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/PurchaseMarketingTopBarSubheadline.swift @@ -1,6 +1,7 @@ // Created by Geoff Pado on 1/29/22. // Copyright © 2022 Cocoatype, LLC. All rights reserved. +import DesignSystem import SwiftUI struct PurchaseMarketingTopBarSubheadline: View { diff --git a/Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/PurchaseRestoreButton.swift b/Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/PurchaseRestoreButton.swift similarity index 100% rename from Modules/Legacy/Core/Sources/Settings/Purchase Marketing/Top Bar/PurchaseRestoreButton.swift rename to Modules/Capabilities/PurchaseMarketing/Sources/Top Bar/PurchaseRestoreButton.swift diff --git a/Modules/Capabilities/PurchaseMarketing/Tests/PurchaseMarketingTests.swift b/Modules/Capabilities/PurchaseMarketing/Tests/PurchaseMarketingTests.swift new file mode 100644 index 00000000..859ed91d --- /dev/null +++ b/Modules/Capabilities/PurchaseMarketing/Tests/PurchaseMarketingTests.swift @@ -0,0 +1 @@ +// blank diff --git a/Modules/Legacy/Core/Sources/Application/EnvironmentKeys.swift b/Modules/Capabilities/Purchasing/Sources/PurchaseStatePublisherKey.swift similarity index 53% rename from Modules/Legacy/Core/Sources/Application/EnvironmentKeys.swift rename to Modules/Capabilities/Purchasing/Sources/PurchaseStatePublisherKey.swift index f5326bb0..972cb2d8 100644 --- a/Modules/Legacy/Core/Sources/Application/EnvironmentKeys.swift +++ b/Modules/Capabilities/Purchasing/Sources/PurchaseStatePublisherKey.swift @@ -1,23 +1,13 @@ -// Created by Geoff Pado on 4/24/24. +// Created by Geoff Pado on 5/13/24. // Copyright © 2024 Cocoatype, LLC. All rights reserved. -import Purchasing import SwiftUI -struct ReadableWidthKey: EnvironmentKey { - static let defaultValue = CGFloat.zero -} - struct PurchaseStatePublisherKey: EnvironmentKey { static let defaultValue = PurchaseStatePublisher() } -extension EnvironmentValues { - var readableWidth: CGFloat { - get { self[ReadableWidthKey.self] } - set { self[ReadableWidthKey.self] = newValue } - } - +public extension EnvironmentValues { var purchaseStatePublisher: PurchaseStatePublisher { get { self[PurchaseStatePublisherKey.self] } set { self[PurchaseStatePublisherKey.self] = newValue } diff --git a/Modules/Capabilities/Unpurchased/Sources/UnpurchasedFeature.swift b/Modules/Capabilities/Unpurchased/Sources/UnpurchasedFeature.swift index 36ff0e9f..23be6e2f 100644 --- a/Modules/Capabilities/Unpurchased/Sources/UnpurchasedFeature.swift +++ b/Modules/Capabilities/Unpurchased/Sources/UnpurchasedFeature.swift @@ -10,7 +10,7 @@ public struct UnpurchasedFeature { public static func autoRedactions(learnMoreAction: LearnMoreAction? = nil) -> UnpurchasedFeature { UnpurchasedFeature( message: Strings.AutoRedactions.message, - learnMoreAction: nil, + learnMoreAction: learnMoreAction, hideFeatureKey: .hideAutoRedactions ) } diff --git a/Modules/Legacy/Core/Sources/Application/AppViewController.swift b/Modules/Legacy/Core/Sources/Application/AppViewController.swift index c17fd435..1003d968 100644 --- a/Modules/Legacy/Core/Sources/Application/AppViewController.swift +++ b/Modules/Legacy/Core/Sources/Application/AppViewController.swift @@ -5,6 +5,7 @@ import AppRatings import Editing import ErrorHandling import Photos +import PurchaseMarketing import Redactions import UIKit import VisionKit diff --git a/Modules/Legacy/Core/Sources/Extensions/ViewExtensions.swift b/Modules/Legacy/Core/Sources/Extensions/ViewExtensions.swift index 5958b9bc..db51a7d0 100644 --- a/Modules/Legacy/Core/Sources/Extensions/ViewExtensions.swift +++ b/Modules/Legacy/Core/Sources/Extensions/ViewExtensions.swift @@ -5,36 +5,11 @@ import Combine import SwiftUI extension View { - public func onAppReceive

(_ publisher: P, perform action: @escaping (P.Output) -> Void) -> some View where P: Publisher, P.Failure == Never { - let isPreview: Bool - #if DEBUG - isPreview = ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" - #else - isPreview = false - #endif - - if isPreview { - return self.onReceive(publisher, perform: { _ in }) - } else { - return self.onReceive(publisher, perform: action) - } - } - - public func fill() -> some View { - return self.modifier(FillViewModifier()) - } - public func continuousCornerRadius(_ radius: CGFloat) -> some View { return self.modifier(ContinuousCornerRadiusViewModifier(radius)) } } -struct FillViewModifier: ViewModifier { - func body(content: Content) -> some View { - AnyView(content).frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center) - } -} - struct ContinuousCornerRadiusViewModifier: ViewModifier { private let radius: CGFloat init(_ radius: CGFloat) { diff --git a/Modules/Legacy/Core/Sources/Settings/Desktop/DesktopSettingsView.swift b/Modules/Legacy/Core/Sources/Settings/Desktop/DesktopSettingsView.swift index c001cd59..f6452968 100644 --- a/Modules/Legacy/Core/Sources/Settings/Desktop/DesktopSettingsView.swift +++ b/Modules/Legacy/Core/Sources/Settings/Desktop/DesktopSettingsView.swift @@ -1,6 +1,7 @@ // Created by Geoff Pado on 9/27/20. // Copyright © 2020 Cocoatype, LLC. All rights reserved. +import PurchaseMarketing import Purchasing import SwiftUI diff --git a/Modules/Legacy/Core/Sources/Settings/List/SettingsContentGenerator.swift b/Modules/Legacy/Core/Sources/Settings/List/SettingsContentGenerator.swift index 88cc0867..6a60b28c 100644 --- a/Modules/Legacy/Core/Sources/Settings/List/SettingsContentGenerator.swift +++ b/Modules/Legacy/Core/Sources/Settings/List/SettingsContentGenerator.swift @@ -3,6 +3,7 @@ import AutoRedactionsUI import Defaults +import PurchaseMarketing import Purchasing import SafariServices import SwiftUI diff --git a/Modules/Legacy/Core/Sources/Settings/Purchase Item/PurchaseSubtitle.swift b/Modules/Legacy/Core/Sources/Settings/Purchase Item/PurchaseSubtitle.swift index bbc3ee25..c3fbf78d 100644 --- a/Modules/Legacy/Core/Sources/Settings/Purchase Item/PurchaseSubtitle.swift +++ b/Modules/Legacy/Core/Sources/Settings/Purchase Item/PurchaseSubtitle.swift @@ -1,6 +1,7 @@ // Created by Geoff Pado on 5/19/21. // Copyright © 2021 Cocoatype, LLC. All rights reserved. +import PurchaseMarketing import Purchasing import StoreKit import SwiftUI diff --git a/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingAutoRedactionsAccessProvider.swift b/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingAutoRedactionsAccessProvider.swift index b7d8f736..b3f59b31 100644 --- a/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingAutoRedactionsAccessProvider.swift +++ b/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingAutoRedactionsAccessProvider.swift @@ -7,12 +7,12 @@ import UIKit import Unpurchased class PhotoEditingAutoRedactionsAccessProvider: NSObject { - func autoRedactionsAccessViewController(learnMoreAction: UnpurchasedFeature.LearnMoreAction) -> UIViewController { + func autoRedactionsAccessViewController(learnMoreAction: @escaping UnpurchasedFeature.LearnMoreAction) -> UIViewController { if purchased { return AutoRedactionsAccessViewController() } else { return UnpurchasedAlertControllerFactory() - .alertController(for: .autoRedactions(learnMoreAction: nil)) + .alertController(for: .autoRedactions(learnMoreAction: learnMoreAction)) } } diff --git a/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingViewController.swift b/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingViewController.swift index 2a28a15a..3a75d7d4 100644 --- a/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingViewController.swift +++ b/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingViewController.swift @@ -5,6 +5,7 @@ import AutoRedactionsUI import Defaults import Observations import Photos +import PurchaseMarketing import Redactions import UIKit @@ -292,8 +293,7 @@ public class PhotoEditingViewController: UIViewController, UIScrollViewDelegate, present( PhotoEditingAutoRedactionsAccessProvider() .autoRedactionsAccessViewController { [weak self] in - // TODO: present purchase marketing view -// self?.present(PurchaseMarketingHostingController(), animated: true) + self?.present(PurchaseMarketingHostingController(), animated: true) }, animated: true) } diff --git a/Project.swift b/Project.swift index fbd11299..20889fc4 100644 --- a/Project.swift +++ b/Project.swift @@ -44,6 +44,7 @@ let project = Project( ErrorHandling.target, Logging.target, Observations.target, + PurchaseMarketing.target, Purchasing.target, Receipts.target, Redacting.target, @@ -58,6 +59,7 @@ let project = Project( ErrorHandling.testTarget, Logging.testTarget, Observations.testTarget, + PurchaseMarketing.testTarget, Purchasing.testTarget, Redactions.testTarget, Unpurchased.testTarget, @@ -71,7 +73,17 @@ let project = Project( testAction: .testPlans([ "Highlighter.xctestplan", ]), - runAction: .runAction() + runAction: .runAction( + arguments: .arguments( + environmentVariables: [ + "OVERRIDE_PURCHASE": .environmentVariable(value: "", isEnabled: false), + "SHOW_DEBUG_OVERLAY": .environmentVariable(value: "", isEnabled: false), + ], + launchArguments: [ + .launchArgument(name: "-FeatureFlag.autoRedactInEdit YES", isEnabled: false), + ] + ) + ) ), ] ) diff --git a/Tuist/ProjectDescriptionHelpers/Targets/Core.swift b/Tuist/ProjectDescriptionHelpers/Targets/Core.swift index 6e679f26..174456f8 100644 --- a/Tuist/ProjectDescriptionHelpers/Targets/Core.swift +++ b/Tuist/ProjectDescriptionHelpers/Targets/Core.swift @@ -13,6 +13,7 @@ public enum Core { .target(Defaults.target), .target(DesignSystem.target), .target(Editing.target), + .target(PurchaseMarketing.target), .target(Purchasing.target), .target(Receipts.target), .target(Unpurchased.target), diff --git a/Tuist/ProjectDescriptionHelpers/Targets/Editing.swift b/Tuist/ProjectDescriptionHelpers/Targets/Editing.swift index ea9b0a28..758f045c 100644 --- a/Tuist/ProjectDescriptionHelpers/Targets/Editing.swift +++ b/Tuist/ProjectDescriptionHelpers/Targets/Editing.swift @@ -13,6 +13,7 @@ public enum Editing { .target(AutoRedactionsUI.target), .target(ErrorHandling.target), .target(Observations.target), + .target(PurchaseMarketing.target), .target(Redactions.target), .package(product: "ClippingBezier", type: .runtime), .package(product: "Introspect", type: .runtime), diff --git a/Tuist/ProjectDescriptionHelpers/Targets/PurchaseMarketing.swift b/Tuist/ProjectDescriptionHelpers/Targets/PurchaseMarketing.swift new file mode 100644 index 00000000..633e4de8 --- /dev/null +++ b/Tuist/ProjectDescriptionHelpers/Targets/PurchaseMarketing.swift @@ -0,0 +1,10 @@ +import ProjectDescription + +public enum PurchaseMarketing { + public static let target = Target.capabilitiesTarget(name: "PurchaseMarketing", dependencies: [ + .target(DesignSystem.target), + .target(Purchasing.target), + ]) + + public static let testTarget = Target.capabilitiesTestTarget(name: "PurchaseMarketing") +} From fe02f89030635285a67c159eb084f3425e6a5b06 Mon Sep 17 00:00:00 2001 From: Geoff Pado Date: Mon, 13 May 2024 16:30:49 -0700 Subject: [PATCH 6/8] Fix tests --- Highlighter.xctestplan | 47 ++++++++++++++----- .../Tests/PurchaseValidatorTests.swift | 1 + .../UIBezierPathExtensionsTests.swift | 3 +- .../CharacterObservationRedactionTests.swift | 5 +- .../TextObservationRedactionTests.swift | 4 +- .../WordObservationRedactionTests.swift | 4 +- .../Redactions/Tests/SampleShapes.swift | 22 +++++++++ .../Targets/Redactions.swift | 1 + 8 files changed, 67 insertions(+), 20 deletions(-) create mode 100644 Modules/Capabilities/Redactions/Tests/SampleShapes.swift diff --git a/Highlighter.xctestplan b/Highlighter.xctestplan index 24b5c72b..019eb095 100644 --- a/Highlighter.xctestplan +++ b/Highlighter.xctestplan @@ -15,57 +15,78 @@ { "target" : { "containerPath" : "container:Highlighter.xcodeproj", - "identifier" : "04634E972A05CEC000569D5C", + "identifier" : "4CA37C6F81D42C86B5E1F67B", "name" : "AppRatingsTests" } }, { "target" : { "containerPath" : "container:Highlighter.xcodeproj", - "identifier" : "04F9A44E2BDA561C00B2A2DB", + "identifier" : "D511BD3660BA1CD7A06AEBC1", "name" : "AutoRedactionsUITests" } }, { "target" : { "containerPath" : "container:Highlighter.xcodeproj", - "identifier" : "04634D6A2A05189C00569D5C", + "identifier" : "FFC529CC7C03FA34AB5A20B3", "name" : "CoreTests" } }, { "target" : { "containerPath" : "container:Highlighter.xcodeproj", - "identifier" : "04634ED32A05D16A00569D5C", - "name" : "DefaultsTests" + "identifier" : "7C98246E8C096DC5B09B72A0", + "name" : "EditingTests" } }, { "target" : { "containerPath" : "container:Highlighter.xcodeproj", - "identifier" : "04F9A4802BDA594100B2A2DB", - "name" : "DesignSystemTests" + "identifier" : "FF81604FD0F405EF2D1CCC8B", + "name" : "ErrorHandlingTests" } }, { "target" : { "containerPath" : "container:Highlighter.xcodeproj", - "identifier" : "04B19921262410D5001A275B", - "name" : "EditingTests" + "identifier" : "97F888315DF72D8A476D3EF9", + "name" : "LoggingTests" } }, { "target" : { "containerPath" : "container:Highlighter.xcodeproj", - "identifier" : "04634E7A2A05C2D300569D5C", - "name" : "ErrorHandlingTests" + "identifier" : "2B4661F6B9957A37CFC75AF1", + "name" : "ObservationsTests" } }, { "target" : { "containerPath" : "container:Highlighter.xcodeproj", - "identifier" : "04634E4A2A052C4400569D5C", - "name" : "LoggingTests" + "identifier" : "2475A1B3C4289BC5302DD4C4", + "name" : "PurchaseMarketingTests" + } + }, + { + "target" : { + "containerPath" : "container:Highlighter.xcodeproj", + "identifier" : "933937713B5A4BE454914256", + "name" : "PurchasingTests" + } + }, + { + "target" : { + "containerPath" : "container:Highlighter.xcodeproj", + "identifier" : "B5E4762CECC52CCD6E2B0990", + "name" : "RedactionsTests" + } + }, + { + "target" : { + "containerPath" : "container:Highlighter.xcodeproj", + "identifier" : "77D525B0D7498E1676A96CC5", + "name" : "UnpurchasedTests" } } ], diff --git a/Modules/Capabilities/Purchasing/Tests/PurchaseValidatorTests.swift b/Modules/Capabilities/Purchasing/Tests/PurchaseValidatorTests.swift index 8e862bb1..ca45ffd0 100644 --- a/Modules/Capabilities/Purchasing/Tests/PurchaseValidatorTests.swift +++ b/Modules/Capabilities/Purchasing/Tests/PurchaseValidatorTests.swift @@ -2,6 +2,7 @@ // Copyright © 2019 Cocoatype, LLC. All rights reserved. import Foundation +import Purchasing import XCTest @testable import Core diff --git a/Modules/Capabilities/Redactions/Tests/Extensions/UIBezierPathExtensionsTests.swift b/Modules/Capabilities/Redactions/Tests/Extensions/UIBezierPathExtensionsTests.swift index 49329ef9..0badec33 100644 --- a/Modules/Capabilities/Redactions/Tests/Extensions/UIBezierPathExtensionsTests.swift +++ b/Modules/Capabilities/Redactions/Tests/Extensions/UIBezierPathExtensionsTests.swift @@ -3,6 +3,7 @@ import XCTest +@testable import Observations @testable import Redactions final class UIBezierPathExtensionsTests: XCTestCase { @@ -15,6 +16,6 @@ final class UIBezierPathExtensionsTests: XCTestCase { path.close() let shape = try XCTUnwrap(path.shape) - XCTAssertEqual(shape, TestHelpers.shape) + XCTAssertEqual(shape, Shape.sample) } } diff --git a/Modules/Capabilities/Redactions/Tests/Redactions/CharacterObservationRedactionTests.swift b/Modules/Capabilities/Redactions/Tests/Redactions/CharacterObservationRedactionTests.swift index e0c5ce02..3e2d4ad6 100644 --- a/Modules/Capabilities/Redactions/Tests/Redactions/CharacterObservationRedactionTests.swift +++ b/Modules/Capabilities/Redactions/Tests/Redactions/CharacterObservationRedactionTests.swift @@ -1,6 +1,7 @@ // Created by Geoff Pado on 10/19/23. // Copyright © 2023 Cocoatype, LLC. All rights reserved. +import TestHelpers import XCTest @testable import Observations @@ -9,14 +10,14 @@ import XCTest final class CharacterObservationRedactionTests: XCTestCase { #if canImport(UIKit) func testInitIgnoresEmptyShapes() throws { - let observation = CharacterObservation(bounds: TestHelpers.emptyShape, textObservationUUID: UUID()) + let observation = CharacterObservation(bounds: Shape.emptySample, textObservationUUID: UUID()) let redaction = try XCTUnwrap(Redaction([observation], color: .black)) XCTAssertEqual(redaction.parts.count, 0) } func testInitIncludesNonEmptyShapes() throws { - let observation = CharacterObservation(bounds: TestHelpers.shape, textObservationUUID: UUID()) + let observation = CharacterObservation(bounds: Shape.sample, textObservationUUID: UUID()) let redaction = try XCTUnwrap(Redaction([observation], color: .black)) XCTAssertEqual(redaction.parts.count, 1) diff --git a/Modules/Capabilities/Redactions/Tests/Redactions/TextObservationRedactionTests.swift b/Modules/Capabilities/Redactions/Tests/Redactions/TextObservationRedactionTests.swift index 3a875c70..b4001057 100644 --- a/Modules/Capabilities/Redactions/Tests/Redactions/TextObservationRedactionTests.swift +++ b/Modules/Capabilities/Redactions/Tests/Redactions/TextObservationRedactionTests.swift @@ -9,14 +9,14 @@ import XCTest final class TextObservationRedactionTests: XCTestCase { #if canImport(UIKit) func testInitIgnoresEmptyShapes() throws { - let observation = MockTextObservation(bounds: TestHelpers.emptyShape) + let observation = MockTextObservation(bounds: Shape.emptySample) let redaction = Redaction(observation, color: .black) XCTAssertEqual(redaction.parts.count, 0) } func testInitIncludesNonEmptyShapes() throws { - let observation = MockTextObservation(bounds: TestHelpers.shape) + let observation = MockTextObservation(bounds: Shape.sample) let redaction = Redaction(observation, color: .black) XCTAssertEqual(redaction.parts.count, 1) diff --git a/Modules/Capabilities/Redactions/Tests/Redactions/WordObservationRedactionTests.swift b/Modules/Capabilities/Redactions/Tests/Redactions/WordObservationRedactionTests.swift index 9963e5d1..963f3e1a 100644 --- a/Modules/Capabilities/Redactions/Tests/Redactions/WordObservationRedactionTests.swift +++ b/Modules/Capabilities/Redactions/Tests/Redactions/WordObservationRedactionTests.swift @@ -10,14 +10,14 @@ import XCTest final class WordObservationRedactionTests: XCTestCase { #if canImport(UIKit) func testInitIgnoresEmptyShapes() throws { - let observation = try mockObservation(shape: TestHelpers.emptyShape) + let observation = try mockObservation(shape: Shape.emptySample) let redaction = Redaction([observation], color: .black) XCTAssertEqual(redaction.parts.count, 0) } func testInitIncludesNonEmptyShapes() throws { - let observation = try mockObservation(shape: TestHelpers.shape) + let observation = try mockObservation(shape: Shape.sample) let redaction = Redaction([observation], color: .black) XCTAssertEqual(redaction.parts.count, 1) diff --git a/Modules/Capabilities/Redactions/Tests/SampleShapes.swift b/Modules/Capabilities/Redactions/Tests/SampleShapes.swift new file mode 100644 index 00000000..86c721e5 --- /dev/null +++ b/Modules/Capabilities/Redactions/Tests/SampleShapes.swift @@ -0,0 +1,22 @@ +// Created by Geoff Pado on 5/13/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. + +import CoreGraphics + +@testable import Observations + +extension Shape { + static let emptySample = Shape( + bottomLeft: CGPoint(x: 5, y: 5), + bottomRight: CGPoint(x: 5, y: 5), + topLeft: CGPoint(x: 5, y: 5), + topRight: CGPoint(x: 5, y: 5) + ) + + static let sample = Shape( + bottomLeft: CGPoint(x: 0, y: 5), + bottomRight: CGPoint(x: 5, y: 5), + topLeft: CGPoint(x: 0, y: 0), + topRight: CGPoint(x: 5, y: 0) + ) +} diff --git a/Tuist/ProjectDescriptionHelpers/Targets/Redactions.swift b/Tuist/ProjectDescriptionHelpers/Targets/Redactions.swift index cca563ef..8fea284d 100644 --- a/Tuist/ProjectDescriptionHelpers/Targets/Redactions.swift +++ b/Tuist/ProjectDescriptionHelpers/Targets/Redactions.swift @@ -7,5 +7,6 @@ public enum Redactions { public static let testTarget = Target.capabilitiesTestTarget(name: "Redactions", dependencies: [ .target(Observations.target), + .target(TestHelpers.target), ]) } From c566cbde71f2768765ebdef57a552a723b1bd5a2 Mon Sep 17 00:00:00 2001 From: Geoff Pado Date: Mon, 13 May 2024 16:53:26 -0700 Subject: [PATCH 7/8] Update toolbar when hiding autoredactions --- .../Settings/List/SettingsAlertButton.swift | 4 +++- ...oEditingAutoRedactionsAccessProvider.swift | 2 +- .../PhotoEditingViewController.swift | 14 ++++++++++--- .../Toolbar Items/ActionSet.swift | 21 ++++++++++++++----- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/Modules/Legacy/Core/Sources/Settings/List/SettingsAlertButton.swift b/Modules/Legacy/Core/Sources/Settings/List/SettingsAlertButton.swift index a99156c1..99fc1124 100644 --- a/Modules/Legacy/Core/Sources/Settings/List/SettingsAlertButton.swift +++ b/Modules/Legacy/Core/Sources/Settings/List/SettingsAlertButton.swift @@ -3,6 +3,7 @@ import Defaults import Editing +import Purchasing import SwiftUI import Unpurchased @@ -15,7 +16,8 @@ struct SettingsAlertButton: View { @ViewBuilder var body: some View { - if /*purchaseState != .purchased &&*/ hideAutoRedactions == false { + let isPurchased = (try? PreviousPurchasePublisher.hasUserPurchasedProduct().get()) ?? true + if isPurchased || hideAutoRedactions == false { Button { showAlert = true } label: { diff --git a/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingAutoRedactionsAccessProvider.swift b/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingAutoRedactionsAccessProvider.swift index b3f59b31..1fd0ee25 100644 --- a/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingAutoRedactionsAccessProvider.swift +++ b/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingAutoRedactionsAccessProvider.swift @@ -9,7 +9,7 @@ import Unpurchased class PhotoEditingAutoRedactionsAccessProvider: NSObject { func autoRedactionsAccessViewController(learnMoreAction: @escaping UnpurchasedFeature.LearnMoreAction) -> UIViewController { if purchased { - return AutoRedactionsAccessViewController() + return AutoRedactionsAccessNavigationController() } else { return UnpurchasedAlertControllerFactory() .alertController(for: .autoRedactions(learnMoreAction: learnMoreAction)) diff --git a/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingViewController.swift b/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingViewController.swift index 3a75d7d4..8b1c1ea6 100644 --- a/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingViewController.swift +++ b/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingViewController.swift @@ -38,6 +38,10 @@ public class PhotoEditingViewController: UIViewController, UIScrollViewDelegate, self?.autoRedact(using: thisMeetingCouldHaveBeenAnEmail) } + hideAutoRedactionsChangeObserver = NotificationCenter.default.addObserver(forName: _hideAutoRedactions.valueDidChange, object: nil, queue: .main, using: { [weak self] _ in + self?.updateToolbarItems() + }) + updateToolbarItems(animated: false) userActivity = EditingUserActivity() @@ -150,8 +154,8 @@ public class PhotoEditingViewController: UIViewController, UIScrollViewDelegate, navigationItem.setRightBarButtonItems(actionSet.trailingNavigationItems, animated: false) } - setToolbarItems(actionSet.toolbarItems, animated: false) - navigationController?.setToolbarHidden(actionSet.toolbarItems.count == 0, animated: false) + setToolbarItems(actionSet.toolbarItems, animated: animated) + navigationController?.setToolbarHidden(actionSet.toolbarItems.count == 0, animated: animated) userActivity?.needsSave = true } @@ -295,7 +299,8 @@ public class PhotoEditingViewController: UIViewController, UIScrollViewDelegate, .autoRedactionsAccessViewController { [weak self] in self?.present(PurchaseMarketingHostingController(), animated: true) }, - animated: true) + animated: true + ) } @objc private func hideAutoRedactAccess(_ sender: Any) { @@ -460,6 +465,7 @@ public class PhotoEditingViewController: UIViewController, UIScrollViewDelegate, // tuBrute by @AdamWulf on 2024-04-29 // the auto-redactions word list @Defaults.Value(key: .autoRedactionsSet) private var tuBrute: [String: Bool] + @Defaults.Value(key: .hideAutoRedactions) private var hideAutoRedactions: Bool public let completionHandler: ((UIImage) -> Void)? public var redactions: [Redaction] { return photoEditingView.redactions } @@ -475,6 +481,7 @@ public class PhotoEditingViewController: UIViewController, UIScrollViewDelegate, private let textRectangleDetector = TextDetector() private let photoEditingView = PhotoEditingView() private var redactionChangeObserver: Any? + private var hideAutoRedactionsChangeObserver: Any? // viewerNamesAreNotRidiculous by @KaenAitch on 2024-04-29 // the change observer for the auto-redactions word list @@ -484,6 +491,7 @@ public class PhotoEditingViewController: UIViewController, UIScrollViewDelegate, colorObserver.map(NotificationCenter.default.removeObserver) redactionChangeObserver.map(NotificationCenter.default.removeObserver) viewerNamesAreNotRidiculous.map(NotificationCenter.default.removeObserver) + hideAutoRedactionsChangeObserver.map(NotificationCenter.default.removeObserver) } override convenience init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { diff --git a/Modules/Legacy/Editing/Sources/Editing View/Toolbar Items/ActionSet.swift b/Modules/Legacy/Editing/Sources/Editing View/Toolbar Items/ActionSet.swift index db396d1a..37de9a67 100644 --- a/Modules/Legacy/Editing/Sources/Editing View/Toolbar Items/ActionSet.swift +++ b/Modules/Legacy/Editing/Sources/Editing View/Toolbar Items/ActionSet.swift @@ -1,6 +1,8 @@ // Created by Geoff Pado on 8/27/21. // Copyright © 2021 Cocoatype, LLC. All rights reserved. +import Defaults +import Purchasing import UIKit struct ActionSet { @@ -20,7 +22,8 @@ struct ActionSet { RedoBarButtonItem(undoManager: undoManager, target: target) ColorPickerBarButtonItem(target: target, color: currentColor) SeekBarButtonItem(target: target) - QuickRedactBarButtonItem(target: target) + + if shouldShowQuickRedact { QuickRedactBarButtonItem(target: target) } } } @@ -31,9 +34,7 @@ struct ActionSet { SeekBarButtonItem(target: target) - if FeatureFlag.autoRedactInEdit { - QuickRedactBarButtonItem(target: target) - } + if shouldShowQuickRedact { QuickRedactBarButtonItem(target: target) } } @ToolbarBuilder var trailingNavigationItems: [UIBarButtonItem] { @@ -43,7 +44,7 @@ struct ActionSet { if sizeClass == .regular, #unavailable(iOS 16) { SeekBarButtonItem(target: target) - QuickRedactBarButtonItem(target: target) + if shouldShowQuickRedact { QuickRedactBarButtonItem(target: target) } } if sizeClass == .regular { @@ -72,6 +73,16 @@ struct ActionSet { } } + // MARK: Decisions + + private var shouldShowQuickRedact: Bool { + let isPurchased = (try? PreviousPurchasePublisher.hasUserPurchasedProduct().get()) ?? true + @Defaults.Value(key: .hideAutoRedactions) var hideAutoRedactions: Bool + return FeatureFlag.autoRedactInEdit && (isPurchased || hideAutoRedactions == false) + } + + // MARK: Boilerplate + init(for target: AnyObject, undoManager: UndoManager?, selectedTool: HighlighterTool, sizeClass: UIUserInterfaceSizeClass, currentColor: UIColor) { self.target = target self.undoManager = undoManager From e582de7c55723c034f368d7b1b7ad96a82c6f73b Mon Sep 17 00:00:00 2001 From: Geoff Pado Date: Mon, 13 May 2024 16:55:59 -0700 Subject: [PATCH 8/8] Fix linting issue --- .../Unpurchased/Sources/UnpurchasedFeature.swift | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Modules/Capabilities/Unpurchased/Sources/UnpurchasedFeature.swift b/Modules/Capabilities/Unpurchased/Sources/UnpurchasedFeature.swift index 23be6e2f..d93ce61b 100644 --- a/Modules/Capabilities/Unpurchased/Sources/UnpurchasedFeature.swift +++ b/Modules/Capabilities/Unpurchased/Sources/UnpurchasedFeature.swift @@ -29,11 +29,5 @@ public struct UnpurchasedFeature { let learnMoreAction: LearnMoreAction? let hideFeatureKey: Defaults.Key? - init(message: String, learnMoreAction: LearnMoreAction?, hideFeatureKey: Defaults.Key?) { - self.message = message - self.learnMoreAction = learnMoreAction - self.hideFeatureKey = hideFeatureKey - } - private typealias Strings = UnpurchasedStrings.UnpurchasedFeature }