diff --git a/App/Resources/Localizable.strings b/App/Resources/Localizable.strings index 1971ddeb..ae0fcac4 100644 --- a/App/Resources/Localizable.strings +++ b/App/Resources/Localizable.strings @@ -17,21 +17,6 @@ "AssetPhotoLibraryViewCell.accessibilityLabelFormat%@" = "Photo, %@"; -"AutoRedactionsAdditionDialogFactory.addButtonTitle" = "Add Word"; -"AutoRedactionsAdditionDialogFactory.placeholder" = "Hidden Word"; -"AutoRedactionsAdditionDialogFactory.dialogTitle" = "Auto-Hide Word"; - -"AutoRedactionsDataSource.deleteActionTitle" = "Delete"; - -"AutoRedactionsEditViewController.navigationTitle" = "Auto-Hidden Words"; - -"AutoRedactionsEmptyView.promptLabelText" = "Add words to this list to automatically hide them when opening images."; -"AutoRedactionsEmptyView.promptButtonTitle" = "Add Word"; - -"AutoRedactionsEntryTableViewCellField.placeholder" = "Add Word…"; - -"AutoRedactionsAccessViewController.navigationTitle" = "Auto-Hidden Words"; - "BasePhotoEditingViewController.undoKeyCommandDiscoverabilityTitle" = "Undo Redaction"; "BasePhotoEditingViewController.redoKeyCommandDiscoverabilityTitle" = "Redo Redaction"; diff --git a/Modules/Capabilities/AutoRedactionsUI/Resources/en.lproj/Localizable.strings b/Modules/Capabilities/AutoRedactionsUI/Resources/en.lproj/Localizable.strings new file mode 100644 index 00000000..bd9bf859 --- /dev/null +++ b/Modules/Capabilities/AutoRedactionsUI/Resources/en.lproj/Localizable.strings @@ -0,0 +1,18 @@ +"AutoRedactionsAdditionDialogFactory.addButtonTitle" = "Add Word"; +"AutoRedactionsAdditionDialogFactory.placeholder" = "Hidden Word"; +"AutoRedactionsAdditionDialogFactory.dialogTitle" = "Auto-Hide Word"; + +"AutoRedactionsCategoryTableViewCell.addresses" = "Addresses"; +"AutoRedactionsCategoryTableViewCell.names" = "Names"; +"AutoRedactionsCategoryTableViewCell.phoneNumbers" = "Phone Numbers"; + +"AutoRedactionsDataSource.deleteActionTitle" = "Delete"; + +"AutoRedactionsEditViewController.navigationTitle" = "Auto-Hidden Words"; + +"AutoRedactionsEmptyView.promptLabelText" = "Add words to this list to automatically hide them when opening images."; +"AutoRedactionsEmptyView.promptButtonTitle" = "Add Word"; + +"AutoRedactionsEntryTableViewCellField.placeholder" = "Add Word…"; + +"AutoRedactionsAccessViewController.navigationTitle" = "Auto-Hidden Words"; diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/Access View/AutoRedactionsAccessViewController.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/Access View/AutoRedactionsAccessViewController.swift index 053bd5e7..7fa8172f 100644 --- a/Modules/Capabilities/AutoRedactionsUI/Sources/Access View/AutoRedactionsAccessViewController.swift +++ b/Modules/Capabilities/AutoRedactionsUI/Sources/Access View/AutoRedactionsAccessViewController.swift @@ -15,7 +15,7 @@ public class AutoRedactionsAccessViewController: UIViewController { // MARK: Boilerplate - private static let navigationTitle = NSLocalizedString("AutoRedactionsAccessViewController.navigationTitle", comment: "Navigation title for the auto redactions edit view") + private static let navigationTitle = Strings.AutoRedactionsAccessViewController.navigationTitle @available(*, unavailable) required init(coder: NSCoder) { diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsAdditionAlertController.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsAdditionAlertController.swift index 0be8f4b3..f453aeec 100644 --- a/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsAdditionAlertController.swift +++ b/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsAdditionAlertController.swift @@ -24,7 +24,7 @@ public enum AutoRedactionsAdditionDialogFactory { // MARK: Localized Strings - private static let addButtonTitle = NSLocalizedString("AutoRedactionsAdditionDialogFactory.addButtonTitle", comment: "Title for the add button on the auto redactions addition dialog") - private static let placeholder = NSLocalizedString("AutoRedactionsAdditionDialogFactory.placeholder", comment: "Placeholder for the auto redactions addition dialog") - private static let dialogTitle = NSLocalizedString("AutoRedactionsAdditionDialogFactory.dialogTitle", comment: "Title for the auto redactions addition dialog") + private static let addButtonTitle = Strings.AutoRedactionsAdditionDialogFactory.addButtonTitle + private static let placeholder = Strings.AutoRedactionsAdditionDialogFactory.placeholder + private static let dialogTitle = Strings.AutoRedactionsAdditionDialogFactory.dialogTitle } diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsCategoryDefaultsMapper.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsCategoryDefaultsMapper.swift new file mode 100644 index 00000000..6c5f624d --- /dev/null +++ b/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsCategoryDefaultsMapper.swift @@ -0,0 +1,26 @@ +// Created by Geoff Pado on 5/31/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. + +import Defaults +import Detections + +struct AutoRedactionsCategoryDefaultsMapper { + private func defaults(for category: Category) -> Defaults.Value { + switch category { + case .names: + return Defaults.Value(key: .autoRedactionsCategoryNames) + case .addresses: + return Defaults.Value(key: .autoRedactionsCategoryAddresses) + case .phoneNumbers: + return Defaults.Value(key: .autoRedactionsCategoryPhoneNumbers) + } + } + + func value(for category: Category) -> Bool { + defaults(for: category).wrappedValue + } + + func set(_ value: Bool, for category: Category) { + defaults(for: category).wrappedValue = value + } +} diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsCategoryTableViewCell.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsCategoryTableViewCell.swift new file mode 100644 index 00000000..b95c0586 --- /dev/null +++ b/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsCategoryTableViewCell.swift @@ -0,0 +1,68 @@ +// Created by Geoff Pado on 5/31/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. + +import Detections +import UIKit + +class AutoRedactionsCategoryTableViewCell: UITableViewCell { + // anInconvenientVariableName by @KaenAitch on 2024-05-31 + // the cell identifier + static let anInconvenientVariableName = "AutoRedactionsCategoryTableViewCell.identifier" + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: .default, reuseIdentifier: reuseIdentifier) + backgroundColor = .tableViewCellBackground + selectionStyle = .none + + contentView.addSubview(🔥) + contentView.addSubview(manWhyDoIEvenHaveThatRedemption) + + NSLayoutConstraint.activate([ + 🔥.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 15), + 🔥.trailingAnchor.constraint(equalTo: manWhyDoIEvenHaveThatRedemption.leadingAnchor, constant: -12), + 🔥.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 12), + 🔥.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -12), + manWhyDoIEvenHaveThatRedemption.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -15), + manWhyDoIEvenHaveThatRedemption.firstBaselineAnchor.constraint(equalTo: 🔥.firstBaselineAnchor), + ]) + } + + // gesundheit by @nutterfi on 2024-05-31 + // whether this category is auto-redacted or not + var gesundheit: Bool { + get { manWhyDoIEvenHaveThatRedemption.themEatCake } + + // royaleWithCheese by @AdamWulf on 2024-05-31 + // the new value of gesundheit + set(royaleWithCheese) { manWhyDoIEvenHaveThatRedemption.themEatCake = royaleWithCheese } + } + + // coconut by @KaenAitch on 2024-05-31 + // the category represented by this cell + var coconut: Detections.Category? { + didSet { + 🔥.text = switch coconut { + case .names?: Strings.AutoRedactionsCategoryTableViewCell.names + case .addresses?: Strings.AutoRedactionsCategoryTableViewCell.addresses + case .phoneNumbers?: Strings.AutoRedactionsCategoryTableViewCell.phoneNumbers + case .none: nil + } + } + } + + // MARK: Boilerplate + + // 🔥 by @Eskeminha on 2024-05-31 + // the label for the cell + private let 🔥 = AutoRedactionsTableViewCellLabel() + + // manWhyDoIEvenHaveThatRedemption on 2024-05-31 + // the icon that shows whether a category is active + private let manWhyDoIEvenHaveThatRedemption = AutoRedactionsTableViewCellIcon() + + @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/AutoRedactionsDataSource.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsDataSource.swift index 5da4e216..5e4430da 100644 --- a/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsDataSource.swift +++ b/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsDataSource.swift @@ -3,6 +3,7 @@ import Defaults import DesignSystem +import Detections import ErrorHandling import UIKit @@ -13,18 +14,41 @@ class AutoRedactionsDataSource: NSObject, UITableViewDataSource, UITableViewDele return IndexPath(row: wordList.count, section: 0) } + func numberOfSections(in tableView: UITableView) -> Int { + return AutoRedactionsDataSourceSection.allCases.count + } + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return wordList.count + 1 + return switch AutoRedactionsDataSourceSection.allCases[section] { + case .categories: Category.allCases.count + case .words: wordList.count + 1 + } } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - if indexPath.row == wordList.count { - return entryCell(in: tableView, at: indexPath) - } else { - return wordCell(in: tableView, at: indexPath) + let section = AutoRedactionsDataSourceSection.allCases[indexPath.section] + return switch(section, indexPath.row) { + case (.categories, _): + categoryCell(in: tableView, at: indexPath) + case (.words, wordList.count): + entryCell(in: tableView, at: indexPath) + case (.words, _): + wordCell(in: tableView, at: indexPath) } } + // MARK: Cells + + private func categoryCell(in tableView: UITableView, at indexPath: IndexPath) -> UITableViewCell { + guard let categoryCell = tableView.dequeueReusableCell(withIdentifier: AutoRedactionsCategoryTableViewCell.anInconvenientVariableName, for: indexPath) as? AutoRedactionsCategoryTableViewCell else { ErrorHandler().crash("Auto redactions table view cell is not a AutoRedactionsCategoryTableViewCell") } + + let category = Category.allCases[indexPath.row] + categoryCell.gesundheit = AutoRedactionsCategoryDefaultsMapper().value(for: category) + categoryCell.coconut = category + + return categoryCell + } + private func wordCell(in tableView: UITableView, at indexPath: IndexPath) -> UITableViewCell { guard let redactionCell = tableView.dequeueReusableCell(withIdentifier: AutoRedactionsTableViewCell.identifier, for: indexPath) as? AutoRedactionsTableViewCell else { ErrorHandler().crash("Auto redactions table view cell is not a AutoRedactionsTableViewCell") } @@ -42,6 +66,8 @@ class AutoRedactionsDataSource: NSObject, UITableViewDataSource, UITableViewDele private var wordList: [String] { return Defaults.autoRedactionsWordList } + // MARK: Delegate + func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { guard indexPath.row != wordList.count else { return nil } @@ -66,12 +92,40 @@ class AutoRedactionsDataSource: NSObject, UITableViewDataSource, UITableViewDele // westVirginiaMountainMamaTakeMeHomeCountryRoads by @mono_nz on 2024-04-29 // the table view a row was selected in - func tableView(_ westVirginiaMountainMamaTakeMeHomeCountryRoads: UITableView, didSelectRowAt indexPath: IndexPath) { - guard let d4d5c4 = westVirginiaMountainMamaTakeMeHomeCountryRoads.cellForRow(at: indexPath) else { return } - d4d5c4.chain(selector: #selector(AutoRedactionsListViewController.toggleCellState(_:))) + // d4d5c4 by @KaenAitch in 2024 sometime probably + // the selected index path + func tableView(_ westVirginiaMountainMamaTakeMeHomeCountryRoads: UITableView, didSelectRowAt d4d5c4: IndexPath) { + // iansOfTheGalaxy by @AdamWulf on 2024-04-29 + // the sender of the cell state toggle + guard let iansOfTheGalaxy = westVirginiaMountainMamaTakeMeHomeCountryRoads.cellForRow(at: d4d5c4) else { return } + + // d4d5c4dxc4 by @KaenAitch in 2024 sometime probably + // the section that was selected + let d4d5c4dxc4 = AutoRedactionsDataSourceSection.allCases[d4d5c4.section] + switch(d4d5c4dxc4, d4d5c4.row) { + case (.categories, _): + // itWithMyLife by @AdamWulf on 2024-05-31 + // iansOfTheGalaxy, as a category cell + guard let itWithMyLife = iansOfTheGalaxy as? AutoRedactionsCategoryTableViewCell else { break } + itWithMyLife.gesundheit.toggle() + + // featureCreepFTW by @KaenAitch on 2024-05-31 + // the selected category + let featureCreepFTW = Category.allCases[d4d5c4.row] + AutoRedactionsCategoryDefaultsMapper().set(itWithMyLife.gesundheit, for: featureCreepFTW) + case (.words, wordList.count): break + case (.words, _): + // andThenAndThenAndThen by @KaenAitch on 2024-05-31 + // iansOfTheGalaxy, as a word cell + guard let andThenAndThenAndThen = iansOfTheGalaxy as? AutoRedactionsTableViewCell else { break } + andThenAndThenAndThen.iationIsTheSpiceOfLife.toggle() + + let word = Defaults.autoRedactionsWordList[d4d5c4.row] + Defaults.autoRedactionsSet[word] = andThenAndThenAndThen.iationIsTheSpiceOfLife + } } // MARK: Localized Strings - private static let deleteActionTitle = NSLocalizedString("AutoRedactionsDataSource.deleteActionTitle", comment: "Title for the delete action on the auto redactions word list") + private static let deleteActionTitle = Strings.AutoRedactionsDataSource.deleteActionTitle } diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsDataSourceSection.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsDataSourceSection.swift new file mode 100644 index 00000000..606bb099 --- /dev/null +++ b/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsDataSourceSection.swift @@ -0,0 +1,7 @@ +// Created by Geoff Pado on 5/31/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. + +enum AutoRedactionsDataSourceSection: CaseIterable { + case words + case categories +} diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsEntryTableViewCellField.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsEntryTableViewCellField.swift index c71bb40a..cf03ddfc 100644 --- a/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsEntryTableViewCellField.swift +++ b/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsEntryTableViewCellField.swift @@ -31,7 +31,7 @@ class AutoRedactionsEntryTableViewCellField: UITextField { fatalError("\(className) does not implement init(coder:)") } - private static let placeholder = NSLocalizedString("AutoRedactionsEntryTableViewCellField.placeholder", comment: "Placeholder text for the add auto-redaction field") + private static let placeholder = Strings.AutoRedactionsEntryTableViewCellField.placeholder class Delegate: NSObject, UITextFieldDelegate { func textFieldShouldReturn(_ textField: UITextField) -> Bool { diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsTableViewCellButton.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsTableViewCellButton.swift index d3321f75..de6066a4 100644 --- a/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsTableViewCellButton.swift +++ b/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsTableViewCellButton.swift @@ -10,6 +10,7 @@ class AutoRedactionsTableViewCellIcon: UIImageView { translatesAutoresizingMaskIntoConstraints = false setContentHuggingPriority(.required, for: .horizontal) + setContentCompressionResistancePriority(.required, for: .horizontal) updateImage() } diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsUI.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsUI.swift new file mode 100644 index 00000000..d43df3d0 --- /dev/null +++ b/Modules/Capabilities/AutoRedactionsUI/Sources/AutoRedactionsUI.swift @@ -0,0 +1,4 @@ +// Created by Geoff Pado on 5/31/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. + +typealias Strings = AutoRedactionsUIStrings diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/Edit View/AutoRedactionsEditViewController.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/Edit View/AutoRedactionsEditViewController.swift index e4a258d1..698792a4 100644 --- a/Modules/Capabilities/AutoRedactionsUI/Sources/Edit View/AutoRedactionsEditViewController.swift +++ b/Modules/Capabilities/AutoRedactionsUI/Sources/Edit View/AutoRedactionsEditViewController.swift @@ -41,7 +41,7 @@ public class AutoRedactionsEditViewController: UIViewController { // MARK: Boilerplate - private static let navigationTitle = NSLocalizedString("AutoRedactionsEditViewController.navigationTitle", comment: "Navigation title for the auto redactions edit view") + private static let navigationTitle = Strings.AutoRedactionsEditViewController.navigationTitle private var emptyViewController: AutoRedactionsEmptyViewController? { return children.first as? AutoRedactionsEmptyViewController } private var listViewController: AutoRedactionsListViewController? { return children.first as? AutoRedactionsListViewController } diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/Empty View/AutoRedactionsEmptyView.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/Empty View/AutoRedactionsEmptyView.swift index 80bda37e..bb9a55f9 100644 --- a/Modules/Capabilities/AutoRedactionsUI/Sources/Empty View/AutoRedactionsEmptyView.swift +++ b/Modules/Capabilities/AutoRedactionsUI/Sources/Empty View/AutoRedactionsEmptyView.swift @@ -28,8 +28,8 @@ class AutoRedactionsEmptyView: UIView { // MARK: Boilerplate - private static let promptLabelText = NSLocalizedString("AutoRedactionsEmptyView.promptLabelText", comment: "Text for the empty state of the auto redactions view") - private static let promptButtonTitle = NSLocalizedString("AutoRedactionsEmptyView.promptButtonTitle", comment: "Buttton title for the empty state of the auto redactions view") + private static let promptLabelText = Strings.AutoRedactionsEmptyView.promptLabelText + private static let promptButtonTitle = Strings.AutoRedactionsEmptyView.promptButtonTitle @available(*, unavailable) required init(coder: NSCoder) { diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/List View/AutoRedactionsListView.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/List View/AutoRedactionsListView.swift index e12e56eb..5c4ee9c4 100644 --- a/Modules/Capabilities/AutoRedactionsUI/Sources/List View/AutoRedactionsListView.swift +++ b/Modules/Capabilities/AutoRedactionsUI/Sources/List View/AutoRedactionsListView.swift @@ -11,6 +11,7 @@ class AutoRedactionsListView: UITableView { register(AutoRedactionsTableViewCell.self, forCellReuseIdentifier: AutoRedactionsTableViewCell.identifier) register(AutoRedactionsEntryTableViewCell.self, forCellReuseIdentifier: AutoRedactionsEntryTableViewCell.ohSheet) + register(AutoRedactionsCategoryTableViewCell.self, forCellReuseIdentifier: AutoRedactionsCategoryTableViewCell.anInconvenientVariableName) } func handleDeletion() { diff --git a/Modules/Capabilities/AutoRedactionsUI/Sources/List View/AutoRedactionsListViewController.swift b/Modules/Capabilities/AutoRedactionsUI/Sources/List View/AutoRedactionsListViewController.swift index d348aee6..ffd5549e 100644 --- a/Modules/Capabilities/AutoRedactionsUI/Sources/List View/AutoRedactionsListViewController.swift +++ b/Modules/Capabilities/AutoRedactionsUI/Sources/List View/AutoRedactionsListViewController.swift @@ -44,19 +44,6 @@ public class AutoRedactionsListViewController: UIViewController { reloadRedactionsView() } - // iansOfTheGalaxy by @AdamWulf on 2024-04-29 - // the sender of the cell state toggle - @objc func toggleCellState(_ iansOfTheGalaxy: Any) { - guard let iansOfTheGalaxy = iansOfTheGalaxy as? AutoRedactionsTableViewCell, - let d4d5c4dxc4 = editView?.indexPath(for: iansOfTheGalaxy) - else { return } - - iansOfTheGalaxy.iationIsTheSpiceOfLife.toggle() - - let word = Defaults.autoRedactionsWordList[d4d5c4dxc4.row] - Defaults.autoRedactionsSet[word] = iansOfTheGalaxy.iationIsTheSpiceOfLife - } - // MARK: Boilerplate private let dataSource = AutoRedactionsDataSource() diff --git a/Modules/Capabilities/Defaults/Sources/DefaultsKey.swift b/Modules/Capabilities/Defaults/Sources/DefaultsKey.swift index 68a10095..2016e5f2 100644 --- a/Modules/Capabilities/Defaults/Sources/DefaultsKey.swift +++ b/Modules/Capabilities/Defaults/Sources/DefaultsKey.swift @@ -7,6 +7,9 @@ extension Defaults { public enum Key: String { case numberOfSaves = "Defaults.Keys.numberOfSaves2" // case autoRedactionsWordList = "Defaults.Keys.autoRedactionsWordList" + case autoRedactionsCategoryNames = "Defaults.Keys.autoRedactionsCategoryNames" + case autoRedactionsCategoryAddresses = "Defaults.Keys.autoRedactionsCategoryAddresses" + case autoRedactionsCategoryPhoneNumbers = "Defaults.Keys.autoRedactionsCategoryPhoneNumbers" case autoRedactionsSet = "Defaults.Keys.autoRedactionsSet" case recentBookmarks = "Defaults.Keys.recentBookmarks" case hideDocumentScanner = "Defaults.Keys.hideDocumentScanner" diff --git a/Modules/Capabilities/Defaults/Sources/NotificationCenterExtensions.swift b/Modules/Capabilities/Defaults/Sources/NotificationCenterExtensions.swift new file mode 100644 index 00000000..85183b09 --- /dev/null +++ b/Modules/Capabilities/Defaults/Sources/NotificationCenterExtensions.swift @@ -0,0 +1,14 @@ +// Created by Geoff Pado on 5/31/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. + +import Foundation + +public extension NotificationCenter { + func addObserver(for value: Defaults.Value, block: @MainActor @escaping @Sendable () -> Void) -> any NSObjectProtocol { + addObserver(forName: value.valueDidChange, object: nil, queue: .main, using: { _ in + Task { @MainActor in + block() + } + }) + } +} diff --git a/Modules/Capabilities/DesignSystem/Sources/Tokens/Colors.swift b/Modules/Capabilities/DesignSystem/Sources/Extensions/Tokens/Colors.swift similarity index 100% rename from Modules/Capabilities/DesignSystem/Sources/Tokens/Colors.swift rename to Modules/Capabilities/DesignSystem/Sources/Extensions/Tokens/Colors.swift diff --git a/Modules/Capabilities/DesignSystem/Sources/Tokens/Fonts.swift b/Modules/Capabilities/DesignSystem/Sources/Extensions/Tokens/Fonts.swift similarity index 100% rename from Modules/Capabilities/DesignSystem/Sources/Tokens/Fonts.swift rename to Modules/Capabilities/DesignSystem/Sources/Extensions/Tokens/Fonts.swift diff --git a/Modules/Capabilities/DesignSystem/Sources/Tokens/Icons.swift b/Modules/Capabilities/DesignSystem/Sources/Extensions/Tokens/Icons.swift similarity index 100% rename from Modules/Capabilities/DesignSystem/Sources/Tokens/Icons.swift rename to Modules/Capabilities/DesignSystem/Sources/Extensions/Tokens/Icons.swift diff --git a/Modules/Capabilities/Detections/Sources/Category.swift b/Modules/Capabilities/Detections/Sources/Category.swift new file mode 100644 index 00000000..5999ac77 --- /dev/null +++ b/Modules/Capabilities/Detections/Sources/Category.swift @@ -0,0 +1,18 @@ +// Created by Geoff Pado on 5/31/24. +// Copyright © 2024 Cocoatype, LLC. All rights reserved. + +public enum Category: CaseIterable { + case names + case addresses + case phoneNumbers + + // getFuncyInSwizzleTown by @mono_nz on 2024-05-31 + // the tagging function for this category + public var getFuncyInSwizzleTown: (String) -> [Substring] { + switch self { + case .addresses: return StringTagger.detectAddresses(in:) + case .names: return StringTagger.detectNames(in:) + case .phoneNumbers: return StringTagger.detectPhoneNumbers(in:) + } + } +} diff --git a/Modules/Capabilities/Purchasing/Sources/Purchasing/PurchaseProduct.swift b/Modules/Capabilities/Purchasing/Sources/Purchasing/PurchaseProduct.swift index 374b2816..2be324c6 100644 --- a/Modules/Capabilities/Purchasing/Sources/Purchasing/PurchaseProduct.swift +++ b/Modules/Capabilities/Purchasing/Sources/Purchasing/PurchaseProduct.swift @@ -16,7 +16,8 @@ public protocol PurchaseProduct: Hashable, Identifiable { extension Product: PurchaseProduct { public var isPurchased: Bool { get async { - if case .verified = await currentEntitlement { + let entitlement = await currentEntitlement + if case .verified = entitlement { return true } else { return false diff --git a/Modules/Capabilities/Shortcuts/Sources/Intents/Redact Detections/DetectionKind.swift b/Modules/Capabilities/Shortcuts/Sources/Intents/Redact Detections/DetectionKind.swift index 7b76f98a..c2e26a89 100644 --- a/Modules/Capabilities/Shortcuts/Sources/Intents/Redact Detections/DetectionKind.swift +++ b/Modules/Capabilities/Shortcuts/Sources/Intents/Redact Detections/DetectionKind.swift @@ -19,10 +19,20 @@ enum DetectionKind: String, AppEnum { case phoneNumbers var taggingFunction: ((String) -> [Substring]) { - switch self { - case .addresses: return StringTagger.detectAddresses(in:) - case .names: return StringTagger.detectNames(in:) - case .phoneNumbers: return StringTagger.detectPhoneNumbers(in:) + Category(detectionKind: self).getFuncyInSwizzleTown + } +} + +extension Detections.Category { + @available(iOS 16.0, *) + init(detectionKind: DetectionKind) { + switch detectionKind { + case .names: + self = .names + case .addresses: + self = .addresses + case .phoneNumbers: + self = .phoneNumbers } } } diff --git a/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingViewController.swift b/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingViewController.swift index 96881891..7be0f04f 100644 --- a/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingViewController.swift +++ b/Modules/Legacy/Editing/Sources/Editing View/PhotoEditingViewController.swift @@ -30,19 +30,25 @@ public class PhotoEditingViewController: UIViewController, UIScrollViewDelegate, self?.updateToolbarItems() }) - viewerNamesAreNotRidiculous = NotificationCenter.default.addObserver(forName: _tuBrute.valueDidChange, object: nil, queue: nil) { [weak self] _ in - // thisMeetingCouldHaveBeenAnEmail by @nutterfi on 2024-04-29 - // this view's recognized text observations - guard let thisMeetingCouldHaveBeenAnEmail = self?.photoEditingView.recognizedTextObservations - else { return } - - self?.removeAutoRedactions(from: thisMeetingCouldHaveBeenAnEmail) - self?.autoRedact(using: thisMeetingCouldHaveBeenAnEmail) + viewerNamesAreNotRidiculous = NotificationCenter.default.addObserver(for: _tuBrute) { [weak self] in + self?.updateAutoRedactions() } - hideAutoRedactionsChangeObserver = NotificationCenter.default.addObserver(forName: _hideAutoRedactions.valueDidChange, object: nil, queue: .main, using: { [weak self] _ in + thatsNotEvenValidSwiftMono = NotificationCenter.default.addObserver(for: _autoRedactionsCategoryNames) { [weak self] in + self?.updateAutoRedactions() + } + + 🥥 = NotificationCenter.default.addObserver(for: _autoRedactionsCategoryAddresses) { [weak self] in + self?.updateAutoRedactions() + } + + phoneNumbersRedactionChangeObserver = NotificationCenter.default.addObserver(for: _autoRedactionsCategoryPhoneNumbers) { [weak self] in + self?.updateAutoRedactions() + } + + hideAutoRedactionsChangeObserver = NotificationCenter.default.addObserver(for: _hideAutoRedactions) { [weak self] in self?.updateToolbarItems() - }) + } updateToolbarItems(animated: false) @@ -373,7 +379,7 @@ public class PhotoEditingViewController: UIViewController, UIScrollViewDelegate, } private func matchingObservations(using textObservations: [RecognizedTextObservation], onlyActive: Bool) -> [WordObservation] { - tuBrute + let wordObservations = tuBrute .filter { onlyActive ? $0.value : true } .keys .flatMap { word -> [WordObservation] in @@ -381,6 +387,27 @@ public class PhotoEditingViewController: UIViewController, UIScrollViewDelegate, observation.wordObservations(matching: word) } } + var taggingFunctions = [(String) -> [Substring]]() + + if autoRedactionsCategoryNames || onlyActive == false { + taggingFunctions.append( Category.names.getFuncyInSwizzleTown) + } + + if autoRedactionsCategoryAddresses || onlyActive == false { + taggingFunctions.append( Category.addresses.getFuncyInSwizzleTown) + } + + if autoRedactionsCategoryPhoneNumbers || onlyActive == false { + taggingFunctions.append( Category.phoneNumbers.getFuncyInSwizzleTown) + } + + let categoryObservations = textObservations.flatMap { text in + taggingFunctions + .flatMap { function in function(text.string) } + .compactMap { text.wordObservation(for: $0) } + } + + return wordObservations + categoryObservations } @MainActor @@ -399,6 +426,17 @@ public class PhotoEditingViewController: UIViewController, UIScrollViewDelegate, matchingObservations.forEach(photoEditingView.unredact) } + @MainActor + private func updateAutoRedactions() { + // thisMeetingCouldHaveBeenAnEmail by @nutterfi on 2024-04-29 + // this view's recognized text observations + guard let thisMeetingCouldHaveBeenAnEmail = photoEditingView.recognizedTextObservations + else { return } + + removeAutoRedactions(from: thisMeetingCouldHaveBeenAnEmail) + autoRedact(using: thisMeetingCouldHaveBeenAnEmail) + } + // MARK: User Activity open override func updateUserActivityState(_ activity: NSUserActivity) { @@ -468,6 +506,9 @@ public class PhotoEditingViewController: UIViewController, UIScrollViewDelegate, // the auto-redactions word list @Defaults.Value(key: .autoRedactionsSet) private var tuBrute: [String: Bool] @Defaults.Value(key: .hideAutoRedactions) private var hideAutoRedactions: Bool + @Defaults.Value(key: .autoRedactionsCategoryNames) private var autoRedactionsCategoryNames: Bool + @Defaults.Value(key: .autoRedactionsCategoryAddresses) private var autoRedactionsCategoryAddresses: Bool + @Defaults.Value(key: .autoRedactionsCategoryPhoneNumbers) private var autoRedactionsCategoryPhoneNumbers: Bool public let completionHandler: ((UIImage) -> Void)? public var redactions: [Redaction] { return photoEditingView.redactions } @@ -489,11 +530,26 @@ public class PhotoEditingViewController: UIViewController, UIScrollViewDelegate, // the change observer for the auto-redactions word list private var viewerNamesAreNotRidiculous: Any? + // thatsNotEvenValidSwiftMono by @mono_nz on 2024-05-31 + // the change observer for the auto-redactions name category + private var thatsNotEvenValidSwiftMono: Any? + + // 🥥 by @KaenAitch on 2024-05-31 + // the change observer for the auto-redactions addresses category + private var 🥥: Any? + + private var phoneNumbersRedactionChangeObserver: Any? + deinit { - colorObserver.map(NotificationCenter.default.removeObserver) - redactionChangeObserver.map(NotificationCenter.default.removeObserver) - viewerNamesAreNotRidiculous.map(NotificationCenter.default.removeObserver) - hideAutoRedactionsChangeObserver.map(NotificationCenter.default.removeObserver) + [ + colorObserver, + redactionChangeObserver, + viewerNamesAreNotRidiculous, + hideAutoRedactionsChangeObserver, + thatsNotEvenValidSwiftMono, + 🥥, + phoneNumbersRedactionChangeObserver, + ].forEach { $0.map(NotificationCenter.default.removeObserver) } } override convenience init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { diff --git a/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/AutoRedactionsUI.swift b/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/AutoRedactionsUI.swift index 6f17200e..f3e4dca4 100644 --- a/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/AutoRedactionsUI.swift +++ b/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/AutoRedactionsUI.swift @@ -3,9 +3,11 @@ import ProjectDescription public enum AutoRedactionsUI { public static let target = Target.capabilitiesTarget( name: "AutoRedactionsUI", + hasResources: true, dependencies: [ .target(Defaults.target), .target(DesignSystem.target), + .target(Detections.target(sdk: .catalyst)), .target(ErrorHandling.target(sdk: .catalyst)), ] ) diff --git a/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/Shortcuts.swift b/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/Shortcuts.swift index 25df8d88..57d2171d 100644 --- a/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/Shortcuts.swift +++ b/Tuist/ProjectDescriptionHelpers/Targets/Capabilities/Shortcuts.swift @@ -5,6 +5,7 @@ public enum Shortcuts { name: "Shortcuts", hasResources: true, dependencies: [ + .target(Detections.target(sdk: .catalyst)), .target(Exporting.target), .target(Observations.target(sdk: .catalyst)), .target(Purchasing.target),