From 26078dd8ad7cd399040bd5b859f6a1ced524bef6 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Fri, 12 Jul 2024 11:35:18 +0600 Subject: [PATCH] Add fireproofing option to Fire popover --- DuckDuckGo/Fire/View/Fire.storyboard | 100 ++++++++++++++++-- .../Fire/View/FirePopoverViewController.swift | 68 +++++++++++- .../Fireproofing/Model/FireproofDomains.swift | 10 +- 3 files changed, 166 insertions(+), 12 deletions(-) diff --git a/DuckDuckGo/Fire/View/Fire.storyboard b/DuckDuckGo/Fire/View/Fire.storyboard index 4f5649eeb9..71b2f410b6 100644 --- a/DuckDuckGo/Fire/View/Fire.storyboard +++ b/DuckDuckGo/Fire/View/Fire.storyboard @@ -1,7 +1,7 @@ - + - + @@ -126,11 +126,11 @@ - + - - + + @@ -199,6 +199,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -531,19 +607,23 @@ Gw + + + - + + @@ -571,6 +651,11 @@ Gw + + + + + @@ -713,11 +798,12 @@ DQ - + + diff --git a/DuckDuckGo/Fire/View/FirePopoverViewController.swift b/DuckDuckGo/Fire/View/FirePopoverViewController.swift index 53b1dc91b2..8d94aaf2f9 100644 --- a/DuckDuckGo/Fire/View/FirePopoverViewController.swift +++ b/DuckDuckGo/Fire/View/FirePopoverViewController.swift @@ -66,9 +66,13 @@ final class FirePopoverViewController: NSViewController { @IBOutlet weak var clearButton: NSButton! @IBOutlet weak var cancelButton: NSButton! @IBOutlet weak var closeBurnerWindowButton: NSButton! + @IBOutlet var fireproofWrapperView: NSView! + @IBOutlet var fireproofImageView: NSImageView! + @IBOutlet var fireproofTitleLabel: NSTextField! + @IBOutlet var fireproofSubtitleLabel: NSTextField! + @IBOutlet var fireproofBottomConstraint: NSLayoutConstraint! - private var viewModelCancellable: AnyCancellable? - private var selectedCancellable: AnyCancellable? + private var cancellables = Set() required init?(coder: NSCoder) { fatalError("FirePopoverViewController: Bad initializer") @@ -113,6 +117,7 @@ final class FirePopoverViewController: NSViewController { subscribeToViewModel() subscribeToSelected() + subscribeToSelectedTabContent() } override func viewWillAppear() { @@ -143,6 +148,15 @@ final class FirePopoverViewController: NSViewController { NSApp.delegateTyped.newBurnerWindow(self) } + @IBAction func fireproofButtonAction(_ sender: Any) { + guard let selectedTabViewModel = firePopoverViewModel.tabCollectionViewModel?.selectedTabViewModel else { + os_log("FirePopoverViewController: No tab view model selected", type: .error) + return + } + + selectedTabViewModel.tab.requestFireproofToggle() + } + @IBAction func openDetailsButtonAction(_ sender: Any) { toggleDetails() } @@ -255,6 +269,26 @@ final class FirePopoverViewController: NSViewController { collectionViewBottomConstraint.constant = warningWrapperView.isHidden ? 0 : 32 } + private func updateFireproofView(with tabContent: Tab.TabContent?) { + guard case .url(let url, _, _)? = tabContent, + url.canFireproof, + let host = url.host else { + fireproofWrapperView.isHidden = true + fireproofBottomConstraint.isActive = false + return + } + + let isFireproof = FireproofDomains.shared.isFireproof(fireproofDomain: host) + let title = isFireproof ? UserText.removeFireproofing : UserText.fireproofSite + let image: NSImage = isFireproof ? .burn : .fireproof + + fireproofImageView.image = image + fireproofTitleLabel.stringValue = title + fireproofSubtitleLabel.stringValue = UserText.fireproofConfirmationMessage + fireproofWrapperView.isHidden = false + fireproofBottomConstraint.isActive = true + } + @IBAction func clearButtonAction(_ sender: Any) { delegate?.firePopoverViewControllerDidClear(self) firePopoverViewModel.burn() @@ -266,7 +300,7 @@ final class FirePopoverViewController: NSViewController { } private func subscribeToViewModel() { - viewModelCancellable = Publishers.Zip( + Publishers.Zip( firePopoverViewModel.$fireproofed, firePopoverViewModel.$selectable ).receive(on: DispatchQueue.main) @@ -279,10 +313,11 @@ final class FirePopoverViewController: NSViewController { self.updateInfoLabel() self.adjustContentHeight() } + .store(in: &cancellables) } private func subscribeToSelected() { - selectedCancellable = firePopoverViewModel.$selected + firePopoverViewModel.$selected .receive(on: DispatchQueue.main) .sink { [weak self] selected in guard let self = self else { return } @@ -290,6 +325,31 @@ final class FirePopoverViewController: NSViewController { self.collectionView.selectionIndexPaths = selectionIndexPaths self.updateInfoLabel() } + .store(in: &cancellables) + } + + private func subscribeToSelectedTabContent() { + guard let tabCollectionViewModel = firePopoverViewModel.tabCollectionViewModel else { + updateFireproofView(with: nil) + return + } + // update fireproofing info on tab content change + let tabContentPublisher = tabCollectionViewModel.$selectedTabViewModel + .map { tabViewModel -> AnyPublisher in + tabViewModel?.tab.$content.eraseToAnyPublisher() ?? Just(.none).eraseToAnyPublisher() + } + .switchToLatest() + // fireproof site added/removed + let fireproofStateToggled = Publishers.Merge( + NotificationCenter.default.publisher(for: FireproofDomains.Constants.newFireproofDomainNotification), + NotificationCenter.default.publisher(for: FireproofDomains.Constants.removedFireproofDomainNotification) + ).asVoid().prepend( () ) + + Publishers.CombineLatest(tabContentPublisher, fireproofStateToggled) + .sink { [weak self] tabContent, _ in + self?.updateFireproofView(with: tabContent) + } + .store(in: &cancellables) } private func toggleDetails() { diff --git a/DuckDuckGo/Fireproofing/Model/FireproofDomains.swift b/DuckDuckGo/Fireproofing/Model/FireproofDomains.swift index 6552a67c4c..b39d921918 100644 --- a/DuckDuckGo/Fireproofing/Model/FireproofDomains.swift +++ b/DuckDuckGo/Fireproofing/Model/FireproofDomains.swift @@ -25,7 +25,9 @@ internal class FireproofDomains { enum Constants { static let allowedDomainsChangedNotification = Notification.Name("allowedDomainsChangedNotification") static let newFireproofDomainNotification = Notification.Name("newFireproofedDomainNotification") + static let removedFireproofDomainNotification = Notification.Name("removedFireproofedDomainNotification") static let newFireproofDomainKey = "newFireproofDomainKey" + static let removedFireproofDomainKey = "removedFireproofDomainKey" } static let shared = FireproofDomains(tld: ContentBlocking.shared.tld) @@ -133,7 +135,7 @@ internal class FireproofDomains { } } - func remove(domain: String, changeToETLDPlus1: Bool = true) { + func remove(domain: String, changeToETLDPlus1: Bool = true, notify: Bool = true) { dispatchPrecondition(condition: .onQueue(.main)) let newDomain: String @@ -159,6 +161,12 @@ internal class FireproofDomains { return } } + + if notify { + NotificationCenter.default.post(name: Constants.removedFireproofDomainNotification, object: self, userInfo: [ + Constants.removedFireproofDomainKey: newDomain + ]) + } } func clearAll() {