From f86941900cc98d71ad035f89d9f2aba548dca0d0 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Wed, 23 Oct 2024 16:09:54 +0100 Subject: [PATCH 01/34] add page zoom menu option and fix dependency on AppDependencyProvider in TabManager --- DuckDuckGo.xcodeproj/project.pbxproj | 14 ++++- DuckDuckGo/AppDelegate.swift | 3 +- DuckDuckGo/MainViewController.swift | 25 +++++---- DuckDuckGo/PageZoomStorage.swift | 46 ++++++++++++++++ DuckDuckGo/TabManager.swift | 52 +++++++++++-------- DuckDuckGo/TabViewController.swift | 11 ++-- ...bViewControllerBrowsingMenuExtension.swift | 13 ++++- ...ViewControllerLongPressMenuExtension.swift | 23 ++++---- DuckDuckGo/UserText.swift | 5 ++ DuckDuckGo/en.lproj/Localizable.strings | 3 ++ 10 files changed, 148 insertions(+), 47 deletions(-) create mode 100644 DuckDuckGo/PageZoomStorage.swift diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 5622a3bd47..17754ed714 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -549,6 +549,7 @@ 85D2187624BF6164004373D2 /* FaviconSourcesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D2187524BF6164004373D2 /* FaviconSourcesProvider.swift */; }; 85D2187924BF6B8B004373D2 /* FaviconSourcesProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D2187724BF6B88004373D2 /* FaviconSourcesProviderTests.swift */; }; 85D2187B24BF9F85004373D2 /* FaviconUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D2187A24BF9F85004373D2 /* FaviconUserScript.swift */; }; + 85D3FF2B2CC941C100487724 /* PageZoomStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D3FF2A2CC941C100487724 /* PageZoomStorage.swift */; }; 85D598872927F84C00FA3B1B /* Crashes in Frameworks */ = {isa = PBXBuildFile; productRef = 85D598862927F84C00FA3B1B /* Crashes */; }; 85DB12EB2A1FE2A4000A4A72 /* LockScreenWidgets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DB12EA2A1FE2A4000A4A72 /* LockScreenWidgets.swift */; }; 85DB12ED2A1FED0C000A4A72 /* AppDelegate+AppDeepLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DB12EC2A1FED0C000A4A72 /* AppDelegate+AppDeepLinks.swift */; }; @@ -1840,6 +1841,7 @@ 85D2187A24BF9F85004373D2 /* FaviconUserScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconUserScript.swift; sourceTree = ""; }; 85D33FCB25C97B6E002B91A6 /* IntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 85D33FCF25C97B6E002B91A6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 85D3FF2A2CC941C100487724 /* PageZoomStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageZoomStorage.swift; sourceTree = ""; }; 85DB12EA2A1FE2A4000A4A72 /* LockScreenWidgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LockScreenWidgets.swift; sourceTree = ""; }; 85DB12EC2A1FED0C000A4A72 /* AppDelegate+AppDeepLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+AppDeepLinks.swift"; sourceTree = ""; }; 85DDE03F2AC6FF65006ABCA2 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; @@ -4218,9 +4220,9 @@ 37CF915E2BB4735F00BADCAE /* Crashes */, D6E0C1812B7A2B0700D5E1E9 /* DesktopDownloads */, 310D09192799EF5C00DC0060 /* Downloads */, - D63FF8922C1B67D1006DE24D /* DuckPlayer */, F143C2C51E4A08F300CFDE3A /* DuckDuckGo.entitlements */, EE3B98EA2A9634CC002F63A0 /* DuckDuckGoAlpha.entitlements */, + D63FF8922C1B67D1006DE24D /* DuckPlayer */, C159DF052A430B36007834BB /* EmailProtection */, 3157B43627F4C8380042D3D7 /* Favicons */, 839F119520DBC489007CD8C2 /* Feedback */, @@ -4233,6 +4235,7 @@ EECD94B22A28B8580085C66E /* NetworkProtection */, 85AE668C20971FCA0014CF04 /* Notifications */, F1C4A70C1E5771F800A6CA1B /* OmniBar */, + 85D3FF292CC941AC00487724 /* PageZoom */, F1AE54DB1F0425BB00D9A700 /* Privacy */, F1DF09502B039E6E008CC908 /* PrivacyDashboard */, 02ECEC602A965074009F0654 /* PrivacyInfo.xcprivacy */, @@ -4553,6 +4556,14 @@ path = IntegrationTests; sourceTree = ""; }; + 85D3FF292CC941AC00487724 /* PageZoom */ = { + isa = PBXGroup; + children = ( + 85D3FF2A2CC941C100487724 /* PageZoomStorage.swift */, + ); + name = PageZoom; + sourceTree = ""; + }; 85DD44232976C7A8005CC388 /* Controllers */ = { isa = PBXGroup; children = ( @@ -7773,6 +7784,7 @@ 85DFEDF924CF3D0E00973FE7 /* TabsBarCell.swift in Sources */, 851672D32BED23FE00592F24 /* AutocompleteViewModel.swift in Sources */, 8562CE152B9B645C00E1D399 /* CachedBookmarkSuggestions.swift in Sources */, + 85D3FF2B2CC941C100487724 /* PageZoomStorage.swift in Sources */, C13F3F682B7F88100083BE40 /* AuthConfirmationPromptView.swift in Sources */, F1617C191E573EA800DEDCAF /* TabSwitcherDelegate.swift in Sources */, 4B5C462A2AF2A6E6002A4432 /* VPNIntents.swift in Sources */, diff --git a/DuckDuckGo/AppDelegate.swift b/DuckDuckGo/AppDelegate.swift index 0442bb02d9..7cf333c2d2 100644 --- a/DuckDuckGo/AppDelegate.swift +++ b/DuckDuckGo/AppDelegate.swift @@ -346,7 +346,8 @@ import os.log contextualOnboardingLogic: daxDialogs, contextualOnboardingPixelReporter: onboardingPixelReporter, subscriptionFeatureAvailability: subscriptionFeatureAvailability, - voiceSearchHelper: voiceSearchHelper) + voiceSearchHelper: voiceSearchHelper, + featureFlagger: AppDependencyProvider.shared.featureFlagger) main.loadViewIfNeeded() syncErrorHandler.alertPresenter = main diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index 7e90bf0129..f722d634ae 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -199,7 +199,9 @@ class MainViewController: UIViewController { tutorialSettings: TutorialSettings = DefaultTutorialSettings(), statisticsStore: StatisticsStore = StatisticsUserDefaults(), subscriptionFeatureAvailability: SubscriptionFeatureAvailability, - voiceSearchHelper: VoiceSearchHelperProtocol + voiceSearchHelper: VoiceSearchHelperProtocol, + featureFlagger: FeatureFlagger, + pageZoomStorage: PageZoomStoring = PageZoomStorage() ) { self.bookmarksDatabase = bookmarksDatabase self.bookmarksDatabaseCleaner = bookmarksDatabaseCleaner @@ -213,15 +215,18 @@ class MainViewController: UIViewController { self.previewsSource = previewsSource - self.tabManager = TabManager(model: tabsModel, - previewsSource: previewsSource, - bookmarksDatabase: bookmarksDatabase, - historyManager: historyManager, - syncService: syncService, - privacyProDataReporter: privacyProDataReporter, - contextualOnboardingPresenter: contextualOnboardingPresenter, - contextualOnboardingLogic: contextualOnboardingLogic, - onboardingPixelReporter: contextualOnboardingPixelReporter) + self.tabManager = TabManager( + model: tabsModel, + previewsSource: previewsSource, + bookmarksDatabase: bookmarksDatabase, + historyManager: historyManager, + syncService: syncService, + privacyProDataReporter: privacyProDataReporter, + contextualOnboardingPresenter: contextualOnboardingPresenter, + contextualOnboardingLogic: contextualOnboardingLogic, + onboardingPixelReporter: contextualOnboardingPixelReporter, + featureFlagger: featureFlagger, + pageZoomStorage: pageZoomStorage) self.syncPausedStateManager = syncPausedStateManager self.privacyProDataReporter = privacyProDataReporter self.homeTabManager = NewTabPageManager() diff --git a/DuckDuckGo/PageZoomStorage.swift b/DuckDuckGo/PageZoomStorage.swift new file mode 100644 index 0000000000..25e50916a4 --- /dev/null +++ b/DuckDuckGo/PageZoomStorage.swift @@ -0,0 +1,46 @@ +// +// PageZoomStorage.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +protocol PageZoomStoring { + func zoomLevelForDomain(_ domain: String) -> Int? + func set(zoomLevel: Int, forDomain domain: String) + func resetZoomLevels(_ excludingDomains: [String]) +} + +class PageZoomStorage: PageZoomStoring { + + var zoomLevels: [String: Int] = [:] + + func zoomLevelForDomain(_ domain: String) -> Int? { + return zoomLevels[domain] + } + + func set(zoomLevel: Int, forDomain domain: String) { + zoomLevels[domain] = zoomLevel + } + + func resetZoomLevels(_ excludingDomains: [String]) { + zoomLevels = zoomLevels.filter { + !excludingDomains.contains($0.key) + } + } + +} diff --git a/DuckDuckGo/TabManager.swift b/DuckDuckGo/TabManager.swift index 24077c9454..80ddb55b33 100644 --- a/DuckDuckGo/TabManager.swift +++ b/DuckDuckGo/TabManager.swift @@ -41,6 +41,8 @@ class TabManager { private let contextualOnboardingPresenter: ContextualOnboardingPresenting private let contextualOnboardingLogic: ContextualOnboardingLogic private let onboardingPixelReporter: OnboardingPixelReporting + private let featureFlagger: FeatureFlagger + private let pageZoomStorage: PageZoomStoring weak var delegate: TabDelegate? @@ -57,7 +59,9 @@ class TabManager { privacyProDataReporter: PrivacyProDataReporting, contextualOnboardingPresenter: ContextualOnboardingPresenting, contextualOnboardingLogic: ContextualOnboardingLogic, - onboardingPixelReporter: OnboardingPixelReporting) { + onboardingPixelReporter: OnboardingPixelReporting, + featureFlagger: FeatureFlagger, + pageZoomStorage: PageZoomStoring) { self.model = model self.previewsSource = previewsSource self.bookmarksDatabase = bookmarksDatabase @@ -68,6 +72,8 @@ class TabManager { self.contextualOnboardingPresenter = contextualOnboardingPresenter self.contextualOnboardingLogic = contextualOnboardingLogic self.onboardingPixelReporter = onboardingPixelReporter + self.featureFlagger = featureFlagger + self.pageZoomStorage = pageZoomStorage registerForNotifications() } @@ -80,16 +86,18 @@ class TabManager { @MainActor private func buildController(forTab tab: Tab, url: URL?, inheritedAttribution: AdClickAttributionLogic.State?) -> TabViewController { let configuration = WKWebViewConfiguration.persistent() - let controller = TabViewController.loadFromStoryboard(model: tab, - bookmarksDatabase: bookmarksDatabase, - historyManager: historyManager, - syncService: syncService, - duckPlayer: duckPlayer, - privacyProDataReporter: privacyProDataReporter, - contextualOnboardingPresenter: contextualOnboardingPresenter, - contextualOnboardingLogic: contextualOnboardingLogic, - onboardingPixelReporter: onboardingPixelReporter, - featureFlagger: AppDependencyProvider.shared.featureFlagger) + let controller = TabViewController.loadFromStoryboard( + model: tab, + bookmarksDatabase: bookmarksDatabase, + historyManager: historyManager, + syncService: syncService, + duckPlayer: duckPlayer, + privacyProDataReporter: privacyProDataReporter, + contextualOnboardingPresenter: contextualOnboardingPresenter, + contextualOnboardingLogic: contextualOnboardingLogic, + onboardingPixelReporter: onboardingPixelReporter, + featureFlagger: featureFlagger, + pageZoomStorage: pageZoomStorage) controller.applyInheritedAttribution(inheritedAttribution) controller.attachWebView(configuration: configuration, andLoadRequest: url == nil ? nil : URLRequest.userInitiated(url!), @@ -158,16 +166,18 @@ class TabManager { model.insert(tab: tab, at: model.currentIndex + 1) model.select(tabAt: model.currentIndex + 1) - let controller = TabViewController.loadFromStoryboard(model: tab, - bookmarksDatabase: bookmarksDatabase, - historyManager: historyManager, - syncService: syncService, - duckPlayer: duckPlayer, - privacyProDataReporter: privacyProDataReporter, - contextualOnboardingPresenter: contextualOnboardingPresenter, - contextualOnboardingLogic: contextualOnboardingLogic, - onboardingPixelReporter: onboardingPixelReporter, - featureFlagger: AppDependencyProvider.shared.featureFlagger) + let controller = TabViewController.loadFromStoryboard( + model: tab, + bookmarksDatabase: bookmarksDatabase, + historyManager: historyManager, + syncService: syncService, + duckPlayer: duckPlayer, + privacyProDataReporter: privacyProDataReporter, + contextualOnboardingPresenter: contextualOnboardingPresenter, + contextualOnboardingLogic: contextualOnboardingLogic, + onboardingPixelReporter: onboardingPixelReporter, + featureFlagger: featureFlagger, + pageZoomStorage: pageZoomStorage) controller.attachWebView(configuration: configCopy, andLoadRequest: request, consumeCookies: !model.hasActiveTabs, diff --git a/DuckDuckGo/TabViewController.swift b/DuckDuckGo/TabViewController.swift index 09490abf98..e0d3103938 100644 --- a/DuckDuckGo/TabViewController.swift +++ b/DuckDuckGo/TabViewController.swift @@ -188,6 +188,7 @@ class TabViewController: UIViewController { var storedSpecialErrorPageUserScript: SpecialErrorPageUserScript? var isSpecialErrorPageVisible: Bool = false + let pageZoomStorage: PageZoomStoring let syncService: DDGSyncing private let daxDialogsDebouncer = Debouncer(mode: .common) @@ -321,7 +322,8 @@ class TabViewController: UIViewController { contextualOnboardingLogic: ContextualOnboardingLogic, onboardingPixelReporter: OnboardingCustomInteractionPixelReporting, urlCredentialCreator: URLCredentialCreating = URLCredentialCreator(), - featureFlagger: FeatureFlagger) -> TabViewController { + featureFlagger: FeatureFlagger, + pageZoomStorage: PageZoomStoring) -> TabViewController { let storyboard = UIStoryboard(name: "Tab", bundle: nil) let controller = storyboard.instantiateViewController(identifier: "TabViewController", creator: { coder in TabViewController(coder: coder, @@ -336,7 +338,8 @@ class TabViewController: UIViewController { contextualOnboardingLogic: contextualOnboardingLogic, onboardingPixelReporter: onboardingPixelReporter, urlCredentialCreator: urlCredentialCreator, - featureFlagger: featureFlagger + featureFlagger: featureFlagger, + pageZoomStorage: pageZoomStorage ) }) return controller @@ -369,7 +372,8 @@ class TabViewController: UIViewController { contextualOnboardingLogic: ContextualOnboardingLogic, onboardingPixelReporter: OnboardingCustomInteractionPixelReporting, urlCredentialCreator: URLCredentialCreating = URLCredentialCreator(), - featureFlagger: FeatureFlagger) { + featureFlagger: FeatureFlagger, + pageZoomStorage: PageZoomStoring) { self.tabModel = tabModel self.appSettings = appSettings self.bookmarksDatabase = bookmarksDatabase @@ -388,6 +392,7 @@ class TabViewController: UIViewController { self.onboardingPixelReporter = onboardingPixelReporter self.urlCredentialCreator = urlCredentialCreator self.featureFlagger = featureFlagger + self.pageZoomStorage = pageZoomStorage super.init(coder: aDecoder) } diff --git a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift index 12ef1e53ee..7cd1eb0099 100644 --- a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift +++ b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift @@ -154,6 +154,8 @@ extension TabViewController { entries.append(entry) } + entries.append(self.buildZoomLevelEntry(forLink: link)) + let title = self.tabModel.isDesktop ? UserText.actionRequestMobileSite : UserText.actionRequestDesktopSite let image = self.tabModel.isDesktop ? UIImage(named: "Device-Mobile-16")! : UIImage(named: "Device-Desktop-16")! entries.append(BrowsingMenuEntry.regular(name: title, image: image, action: { [weak self] in @@ -164,7 +166,16 @@ extension TabViewController { return entries } - + + private func buildZoomLevelEntry(forLink link: Link) -> BrowsingMenuEntry { + let domain = link.url.host?.droppingWwwPrefix() ?? "" + let percent = pageZoomStorage.zoomLevelForDomain(domain) ?? 100 + + return BrowsingMenuEntry.regular(name: UserText.pageZoomWithPercent(percent), image: UIImage(named: "Type-Size-16")!, showNotificationDot: false) { + // TODO + } + } + private func buildKeepSignInEntry(forLink link: Link) -> BrowsingMenuEntry? { guard let domain = link.url.host, !link.url.isDuckDuckGo else { return nil } let isFireproofed = PreserveLogins.shared.isAllowed(cookieDomain: domain) diff --git a/DuckDuckGo/TabViewControllerLongPressMenuExtension.swift b/DuckDuckGo/TabViewControllerLongPressMenuExtension.swift index 38770be4e7..525646cc6a 100644 --- a/DuckDuckGo/TabViewControllerLongPressMenuExtension.swift +++ b/DuckDuckGo/TabViewControllerLongPressMenuExtension.swift @@ -102,16 +102,19 @@ extension TabViewController { fileprivate func buildOpenLinkPreview(for url: URL) -> UIViewController? { let tab = Tab(link: Link(title: nil, url: url)) - let tabController = TabViewController.loadFromStoryboard(model: tab, - bookmarksDatabase: bookmarksDatabase, - historyManager: historyManager, - syncService: syncService, - duckPlayer: duckPlayer, - privacyProDataReporter: privacyProDataReporter, - contextualOnboardingPresenter: contextualOnboardingPresenter, - contextualOnboardingLogic: contextualOnboardingLogic, - onboardingPixelReporter: onboardingPixelReporter, - featureFlagger: AppDependencyProvider.shared.featureFlagger) + let tabController = TabViewController.loadFromStoryboard( + model: tab, + bookmarksDatabase: bookmarksDatabase, + historyManager: historyManager, + syncService: syncService, + duckPlayer: duckPlayer, + privacyProDataReporter: privacyProDataReporter, + contextualOnboardingPresenter: contextualOnboardingPresenter, + contextualOnboardingLogic: contextualOnboardingLogic, + onboardingPixelReporter: onboardingPixelReporter, + featureFlagger: AppDependencyProvider.shared.featureFlagger, + pageZoomStorage: pageZoomStorage) + tabController.isLinkPreview = true let configuration = WKWebViewConfiguration.nonPersistent() tabController.attachWebView(configuration: configuration, andLoadRequest: URLRequest.userInitiated(url), consumeCookies: false) diff --git a/DuckDuckGo/UserText.swift b/DuckDuckGo/UserText.swift index b8fd72171c..42149ce1e9 100644 --- a/DuckDuckGo/UserText.swift +++ b/DuckDuckGo/UserText.swift @@ -358,6 +358,11 @@ public struct UserText { } public static let messageAllFilesDeleted = NSLocalizedString("downloads.message.all-files-deleted", value: "All files deleted", comment: "Message confirming that all files on the downloads list have been deleted") + public static func pageZoomWithPercent(_ percent: Int) -> String { + let message = NSLocalizedString("action.show-page-zoom", value: "Zoom Text (%d%%)", comment: "Zoom text menu item showing currently set zoom level as a percent. '%d' represets the number that will be used, e.g. 56") + return message.format(arguments: percent) + } + public static let actionGenericShow = NSLocalizedString("action.generic.show", value: "Show", comment: "Button label for a generic show action") public static let actionDownloads = NSLocalizedString("action.title.downloads", value: "Downloads", comment: "Downloads menu item opening the downlods list") public static let downloadsScreenTitle = NSLocalizedString("downloads.downloads-list.title", value: "Downloads", comment: "Downloads list screen title") diff --git a/DuckDuckGo/en.lproj/Localizable.strings b/DuckDuckGo/en.lproj/Localizable.strings index 04e1c6f25f..31c8359847 100644 --- a/DuckDuckGo/en.lproj/Localizable.strings +++ b/DuckDuckGo/en.lproj/Localizable.strings @@ -13,6 +13,9 @@ /* Button label for OK action */ "action.ok" = "OK"; +/* Zoom text menu item showing currently set zoom level as a percent. '%d' represets the number that will be used, e.g. 56 */ +"action.show-page-zoom" = "Zoom Text (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Add"; From 866c2711e6eea454cf18c4b0825ecb8b9f4f3822 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Wed, 23 Oct 2024 17:54:02 +0100 Subject: [PATCH 02/34] fix settings bug and retain cycle and remove unneed input to content blocking assets publisher --- DuckDuckGo/AppUserDefaults.swift | 6 +++++- DuckDuckGo/ContentBlockingUpdating.swift | 1 - DuckDuckGo/SettingsViewModel.swift | 10 +++++++++- DuckDuckGo/TextSizeSettingsViewController.swift | 2 +- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/DuckDuckGo/AppUserDefaults.swift b/DuckDuckGo/AppUserDefaults.swift index 408b03a116..5506cf80ac 100644 --- a/DuckDuckGo/AppUserDefaults.swift +++ b/DuckDuckGo/AppUserDefaults.swift @@ -235,7 +235,11 @@ public class AppUserDefaults: AppSettings { } @UserDefaultsWrapper(key: .textSize, defaultValue: 100) - var textSize: Int + var textSize: Int { + didSet { + NotificationCenter.default.post(name: Notifications.textSizeChange, object: textSize) + } + } public var favoritesDisplayMode: FavoritesDisplayMode { get { diff --git a/DuckDuckGo/ContentBlockingUpdating.swift b/DuckDuckGo/ContentBlockingUpdating.swift index 95e70dbcf6..95002bca9e 100644 --- a/DuckDuckGo/ContentBlockingUpdating.swift +++ b/DuckDuckGo/ContentBlockingUpdating.swift @@ -87,7 +87,6 @@ public final class ContentBlockingUpdating { .combineLatest(onNotificationWithInitial(PreserveLogins.Notifications.loginDetectionStateChanged), combine) .combineLatest(onNotificationWithInitial(AppUserDefaults.Notifications.doNotSellStatusChange), combine) .combineLatest(onNotificationWithInitial(AppUserDefaults.Notifications.autofillEnabledChange), combine) - .combineLatest(onNotificationWithInitial(AppUserDefaults.Notifications.textSizeChange), combine) .combineLatest(onNotificationWithInitial(AppUserDefaults.Notifications.didVerifyInternalUser), combine) .combineLatest(onNotificationWithInitial(ConfigurationManager.didUpdateTrackerDependencies) .receive(on: DispatchQueue.main), combine) diff --git a/DuckDuckGo/SettingsViewModel.swift b/DuckDuckGo/SettingsViewModel.swift index e008a34ab6..760cb93b91 100644 --- a/DuckDuckGo/SettingsViewModel.swift +++ b/DuckDuckGo/SettingsViewModel.swift @@ -63,7 +63,8 @@ final class SettingsViewModel: ObservableObject { // App Data State Notification Observer private var appDataClearingObserver: Any? - + private var textSizeObserver: Any? + // Closures to interact with legacy view controllers through the container var onRequestPushLegacyView: ((UIViewController) -> Void)? var onRequestPresentLegacyView: ((UIViewController, _ modal: Bool) -> Void)? @@ -387,6 +388,7 @@ final class SettingsViewModel: ObservableObject { deinit { subscriptionSignOutObserver = nil appDataClearingObserver = nil + textSizeObserver = nil } } @@ -771,6 +773,12 @@ extension SettingsViewModel { self?.state.autoclearDataEnabled = (AutoClearSettingsModel(settings: settings) != nil) } + textSizeObserver = NotificationCenter.default.addObserver(forName: AppUserDefaults.Notifications.textSizeChange, + object: nil, + queue: .main, using: { [weak self] _ in + guard let self = self else { return } + self.state.textSize = SettingsState.TextSize(enabled: !isPad, size: self.appSettings.textSize) + }) } func restoreAccountPurchase() async { diff --git a/DuckDuckGo/TextSizeSettingsViewController.swift b/DuckDuckGo/TextSizeSettingsViewController.swift index c28cfd61be..bd1d483eef 100644 --- a/DuckDuckGo/TextSizeSettingsViewController.swift +++ b/DuckDuckGo/TextSizeSettingsViewController.swift @@ -179,7 +179,7 @@ class TextSizeSettingsViewController: UITableViewController { let appSettings = AppDependencyProvider.shared.appSettings appSettings.textSize = percentage - NotificationCenter.default.post(name: AppUserDefaults.Notifications.textSizeChange, object: self) + NotificationCenter.default.post(name: AppUserDefaults.Notifications.textSizeChange, object: nil) } private func firePixelForTextSizeChange() { From d9d1e4ebb236b4476efc3bbffeace5e2bf4e8c71 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 24 Oct 2024 14:31:15 +0100 Subject: [PATCH 03/34] migrate to using default zoom level rather than text size --- DuckDuckGo.xcodeproj/project.pbxproj | 8 +- DuckDuckGo/AppSettings.swift | 2 +- DuckDuckGo/AppUserDefaults.swift | 11 +- DuckDuckGo/Base.lproj/Settings.storyboard | 165 +------------ DuckDuckGo/SettingsAccessibilityView.swift | 8 +- DuckDuckGo/SettingsState.swift | 4 +- DuckDuckGo/SettingsViewModel.swift | 16 +- DuckDuckGo/TabViewController.swift | 4 +- .../TextSizeSettingsViewController.swift | 221 ------------------ DuckDuckGo/UserScripts.swift | 6 +- DuckDuckGo/UserText.swift | 2 +- DuckDuckGo/ZoomLevel.swift | 39 ++++ DuckDuckGo/en.lproj/Localizable.strings | 2 +- 13 files changed, 84 insertions(+), 404 deletions(-) delete mode 100644 DuckDuckGo/TextSizeSettingsViewController.swift create mode 100644 DuckDuckGo/ZoomLevel.swift diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 17754ed714..6cec037627 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -86,7 +86,6 @@ 1E7A711C2934EEBC00B7EA19 /* OmniBarNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7A711B2934EEBC00B7EA19 /* OmniBarNotification.swift */; }; 1E8146AD28C8ABF000D1AF63 /* TrackerAnimationLogicTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E8146A728C8AB3F00D1AF63 /* TrackerAnimationLogicTests.swift */; }; 1E8146AE28C8ABF400D1AF63 /* PrivacyIconLogicTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E8146A928C8AB8200D1AF63 /* PrivacyIconLogicTests.swift */; }; - 1E865AF0272042DB001C74F3 /* TextSizeSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E865AEF272042DB001C74F3 /* TextSizeSettingsViewController.swift */; }; 1E87615928A1517200C7C5CE /* PrivacyDashboardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E87615828A1517200C7C5CE /* PrivacyDashboardViewController.swift */; }; 1E8AD1C727BE9B2900ABA377 /* DownloadsListDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E8AD1C627BE9B2900ABA377 /* DownloadsListDataSource.swift */; }; 1E8AD1C927BFAD1500ABA377 /* DirectoryMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E8AD1C827BFAD1500ABA377 /* DirectoryMonitor.swift */; }; @@ -413,6 +412,7 @@ 8512EA5724ED30D30073EE19 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8512EA5624ED30D30073EE19 /* Assets.xcassets */; }; 8512EA5D24ED30D30073EE19 /* WidgetsExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 8512EA4D24ED30D20073EE19 /* WidgetsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 8512EA9D24EEA6820073EE19 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F143C2B11E49D78C00CFDE3A /* Assets.xcassets */; }; + 85147CB62CCA755300677835 /* ZoomLevel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85147CB52CCA755300677835 /* ZoomLevel.swift */; }; 851481882A600EFC00ABC65F /* RemoteMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = 851481872A600EFC00ABC65F /* RemoteMessaging */; }; 851624C22B95F8BD002D5CD7 /* HistoryCapture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851624C12B95F8BD002D5CD7 /* HistoryCapture.swift */; }; 851624C52B9602A4002D5CD7 /* HistoryCaptureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851624C32B96029B002D5CD7 /* HistoryCaptureTests.swift */; }; @@ -1385,7 +1385,6 @@ 1E7A711B2934EEBC00B7EA19 /* OmniBarNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OmniBarNotification.swift; sourceTree = ""; }; 1E8146A728C8AB3F00D1AF63 /* TrackerAnimationLogicTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackerAnimationLogicTests.swift; sourceTree = ""; }; 1E8146A928C8AB8200D1AF63 /* PrivacyIconLogicTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyIconLogicTests.swift; sourceTree = ""; }; - 1E865AEF272042DB001C74F3 /* TextSizeSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextSizeSettingsViewController.swift; sourceTree = ""; }; 1E87615828A1517200C7C5CE /* PrivacyDashboardViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyDashboardViewController.swift; sourceTree = ""; }; 1E8AD1C627BE9B2900ABA377 /* DownloadsListDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadsListDataSource.swift; sourceTree = ""; }; 1E8AD1C827BFAD1500ABA377 /* DirectoryMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DirectoryMonitor.swift; sourceTree = ""; }; @@ -1706,6 +1705,7 @@ 8512EA5324ED30D20073EE19 /* Widgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Widgets.swift; sourceTree = ""; }; 8512EA5624ED30D30073EE19 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 8512EA5824ED30D30073EE19 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 85147CB52CCA755300677835 /* ZoomLevel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZoomLevel.swift; sourceTree = ""; }; 851624C12B95F8BD002D5CD7 /* HistoryCapture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryCapture.swift; sourceTree = ""; }; 851624C32B96029B002D5CD7 /* HistoryCaptureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryCaptureTests.swift; sourceTree = ""; }; 851624C62B96389D002D5CD7 /* HistoryDebugViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryDebugViewController.swift; sourceTree = ""; }; @@ -4355,7 +4355,6 @@ 1EE7C298294227EC0026C8CB /* AutoconsentSettingsViewController.swift */, 85449EF423FDA02800512AAF /* KeyboardSettingsViewController.swift */, 8540BD5523D9E9C20057FDD2 /* PreserveLoginsSettingsViewController.swift */, - 1E865AEF272042DB001C74F3 /* TextSizeSettingsViewController.swift */, 8531A08D1F9950E6000484F0 /* UnprotectedSitesViewController.swift */, 6FBF0F8A2BD7C0A900136CF0 /* AllProtectedCell.swift */, D6E83C672B23B6A3006C8AFB /* FontSettings.swift */, @@ -4560,6 +4559,7 @@ isa = PBXGroup; children = ( 85D3FF2A2CC941C100487724 /* PageZoomStorage.swift */, + 85147CB52CCA755300677835 /* ZoomLevel.swift */, ); name = PageZoom; sourceTree = ""; @@ -7671,6 +7671,7 @@ F1E90C201E678E7C005E7E21 /* HomeControllerDelegate.swift in Sources */, 85DB12ED2A1FED0C000A4A72 /* AppDelegate+AppDeepLinks.swift in Sources */, 98DA6ECA2181E41F00E65433 /* ThemeManager.swift in Sources */, + 85147CB62CCA755300677835 /* ZoomLevel.swift in Sources */, F1D43AFC2B99C56000BAB743 /* RootDebugViewController+VanillaBrowser.swift in Sources */, 564DE4602C4544CA00D23241 /* HomePageDependencies.swift in Sources */, C159DF072A430B60007834BB /* EmailSignupViewController.swift in Sources */, @@ -7880,7 +7881,6 @@ 1E8AD1D727C2E24E00ABA377 /* DownloadsListRowViewModel.swift in Sources */, 9FEA222E2C324ECD006B03BF /* ViewVisibility.swift in Sources */, BD10B8AA2C7629740033115D /* Logger+Subscription.swift in Sources */, - 1E865AF0272042DB001C74F3 /* TextSizeSettingsViewController.swift in Sources */, D6E0C1892B7A2E0D00D5E1E9 /* DesktopDownloadViewModel.swift in Sources */, 8524CC9A246DA81700E59D45 /* FullscreenDaxDialogViewController.swift in Sources */, 9F23B8012C2BC94400950875 /* OnboardingBackground.swift in Sources */, diff --git a/DuckDuckGo/AppSettings.swift b/DuckDuckGo/AppSettings.swift index e2c31dda2b..8f7dfae88f 100644 --- a/DuckDuckGo/AppSettings.swift +++ b/DuckDuckGo/AppSettings.swift @@ -60,7 +60,7 @@ protocol AppSettings: AnyObject, AppDebugSettings { var currentAddressBarPosition: AddressBarPosition { get set } var showFullSiteAddress: Bool { get set } - var textSize: Int { get set } + var defaultZoomLevel: ZoomLevel { get set } var favoritesDisplayMode: FavoritesDisplayMode { get set } diff --git a/DuckDuckGo/AppUserDefaults.swift b/DuckDuckGo/AppUserDefaults.swift index 5506cf80ac..15f41f06ce 100644 --- a/DuckDuckGo/AppUserDefaults.swift +++ b/DuckDuckGo/AppUserDefaults.swift @@ -235,12 +235,21 @@ public class AppUserDefaults: AppSettings { } @UserDefaultsWrapper(key: .textSize, defaultValue: 100) - var textSize: Int { + private var textSize: Int { didSet { NotificationCenter.default.post(name: Notifications.textSizeChange, object: textSize) } } + var defaultZoomLevel: ZoomLevel { + get { + return ZoomLevel(rawValue: textSize) ?? .percent100 + } + set { + textSize = newValue.rawValue + } + } + public var favoritesDisplayMode: FavoritesDisplayMode { get { guard let string = userDefaults?.string(forKey: Keys.favoritesDisplayMode), let favoritesDisplayMode = FavoritesDisplayMode(string) else { diff --git a/DuckDuckGo/Base.lproj/Settings.storyboard b/DuckDuckGo/Base.lproj/Settings.storyboard index b0decd8ad5..39927df63a 100644 --- a/DuckDuckGo/Base.lproj/Settings.storyboard +++ b/DuckDuckGo/Base.lproj/Settings.storyboard @@ -1,162 +1,14 @@ - + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -174,7 +26,7 @@ - + @@ -962,7 +814,7 @@ - + @@ -1066,16 +918,7 @@ - - - - - - - - - diff --git a/DuckDuckGo/SettingsAccessibilityView.swift b/DuckDuckGo/SettingsAccessibilityView.swift index ad0141d69f..7fd0394265 100644 --- a/DuckDuckGo/SettingsAccessibilityView.swift +++ b/DuckDuckGo/SettingsAccessibilityView.swift @@ -31,11 +31,9 @@ struct SettingsAccessibilityView: View { Section { // Text Size if viewModel.state.textSize.enabled { - SettingsCellView(label: UserText.settingsText, - action: { viewModel.presentLegacyView(.textSize) }, - accessory: .rightDetail("\(viewModel.state.textSize.size)%"), - disclosureIndicator: true, - isButton: true) + SettingsPickerCellView(label: UserText.settingsText, + options: ZoomLevel.allCases, + selectedOption: viewModel.zoomLevelBinding) } } diff --git a/DuckDuckGo/SettingsState.swift b/DuckDuckGo/SettingsState.swift index 299cfeba21..cb984b34c5 100644 --- a/DuckDuckGo/SettingsState.swift +++ b/DuckDuckGo/SettingsState.swift @@ -33,7 +33,7 @@ struct SettingsState { struct TextSize { var enabled: Bool - var size: Int + var zoomLevel: ZoomLevel } struct Subscription: Codable { @@ -107,7 +107,7 @@ struct SettingsState { appTheme: .systemDefault, appIcon: AppIconManager.shared.appIcon, fireButtonAnimation: .fireRising, - textSize: TextSize(enabled: false, size: 100), + textSize: TextSize(enabled: false, zoomLevel: .percent100), addressBar: AddressBar(enabled: false, position: .top), showsFullURL: false, sendDoNotSell: true, diff --git a/DuckDuckGo/SettingsViewModel.swift b/DuckDuckGo/SettingsViewModel.swift index 760cb93b91..3eba864915 100644 --- a/DuckDuckGo/SettingsViewModel.swift +++ b/DuckDuckGo/SettingsViewModel.swift @@ -78,7 +78,7 @@ final class SettingsViewModel: ObservableObject { enum Features { case sync case autofillAccessCredentialManagement - case textSize + case zoomLevel case voiceSearch case addressbarPosition case speechRecognition @@ -257,6 +257,16 @@ final class SettingsViewModel: ObservableObject { ) } + var zoomLevelBinding: Binding { + Binding( + get: { self.state.textSize.zoomLevel }, + set: { newValue in + self.appSettings.defaultZoomLevel = newValue + self.state.textSize.zoomLevel = newValue + } + ) + } + var duckPlayerModeBinding: Binding { Binding( get: { @@ -404,7 +414,7 @@ extension SettingsViewModel { appTheme: appSettings.currentThemeName, appIcon: AppIconManager.shared.appIcon, fireButtonAnimation: appSettings.currentFireButtonAnimation, - textSize: SettingsState.TextSize(enabled: !isPad, size: appSettings.textSize), + textSize: SettingsState.TextSize(enabled: !isPad, zoomLevel: appSettings.defaultZoomLevel), addressBar: SettingsState.AddressBar(enabled: !isPad, position: appSettings.currentAddressBarPosition), showsFullURL: appSettings.showFullSiteAddress, sendDoNotSell: appSettings.sendDoNotSell, @@ -777,7 +787,7 @@ extension SettingsViewModel { object: nil, queue: .main, using: { [weak self] _ in guard let self = self else { return } - self.state.textSize = SettingsState.TextSize(enabled: !isPad, size: self.appSettings.textSize) + self.state.textSize = SettingsState.TextSize(enabled: !isPad, zoomLevel: self.appSettings.defaultZoomLevel) }) } diff --git a/DuckDuckGo/TabViewController.swift b/DuckDuckGo/TabViewController.swift index e0d3103938..3fd38128ec 100644 --- a/DuckDuckGo/TabViewController.swift +++ b/DuckDuckGo/TabViewController.swift @@ -971,7 +971,7 @@ class TabViewController: UIViewController { } @objc func onTextSizeChange() { - webView.adjustTextSize(appSettings.textSize) + webView.adjustTextSize(appSettings.defaultZoomLevel.rawValue) } @objc func onDuckDuckGoEmailSignOut(_ notification: Notification) { @@ -2519,7 +2519,7 @@ extension TabViewController: UserContentControllerDelegate { userScripts.autofillUserScript.vaultDelegate = vaultManager userScripts.faviconScript.delegate = faviconUpdater userScripts.printingUserScript.delegate = self - userScripts.textSizeUserScript.textSizeAdjustmentInPercents = appSettings.textSize + userScripts.textSizeUserScript.textSizeAdjustmentInPercents = appSettings.defaultZoomLevel.rawValue userScripts.loginFormDetectionScript?.delegate = self userScripts.autoconsentUserScript.delegate = self userScripts.specialErrorPageUserScript?.delegate = self diff --git a/DuckDuckGo/TextSizeSettingsViewController.swift b/DuckDuckGo/TextSizeSettingsViewController.swift deleted file mode 100644 index bd1d483eef..0000000000 --- a/DuckDuckGo/TextSizeSettingsViewController.swift +++ /dev/null @@ -1,221 +0,0 @@ -// -// TextSizeSettingsViewController.swift -// DuckDuckGo -// -// Copyright © 2021 DuckDuckGo. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation -import UIKit -import Core - -class TextSizeSettingsViewController: UITableViewController { - - @IBOutlet var customBackBarButtonItem: UIBarButtonItem! - @IBOutlet weak var customBackInnerButton: UIButton! - @IBOutlet weak var descriptionLabel: UILabel! - @IBOutlet weak var textSizeSlider: IntervalSlider! - @IBOutlet weak var smallerTextIcon: UIImageView! - @IBOutlet weak var largerTextIcon: UIImageView! - @IBOutlet weak var currentSelectedValueLabel: UILabel! - - private let predefinedPercentages = [80, 90, 100, 110, 120, 130, 140, 150, 160, 170] - - private let initialTextSizePercentage: Int = AppDependencyProvider.shared.appSettings.textSize - private var currentTextSizePercentage: Int = AppDependencyProvider.shared.appSettings.textSize - - private var hasAdjustedDetent: Bool = false - - override func viewDidLoad() { - super.viewDidLoad() - - navigationItem.leftBarButtonItem = nil - - configureCustomBackButtonTitle() - configureDescriptionLabel() - configureSlider() - updateTextSizeFooterLabel() - - decorate() - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - adjustDetentOnPresentation() - } - - private func adjustDetentOnPresentation() { - if !hasAdjustedDetent, let sheetController = navigationController?.presentationController as? UISheetPresentationController { - sheetController.detents = [.medium(), .large()] - sheetController.delegate = self - sheetController.preferredCornerRadius = 16 - - sheetController.animateChanges { - sheetController.selectedDetentIdentifier = .medium - } - - navigationItem.leftBarButtonItem = customBackBarButtonItem - - hasAdjustedDetent = true - } - } - - override func willMove(toParent parent: UIViewController?) { - super.willMove(toParent: parent) - - if parent == nil { - firePixelForTextSizeChange() - } - } - - override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { - let theme = ThemeManager.shared.currentTheme - cell.decorate(with: theme) - } - - private func configureCustomBackButtonTitle() { - let topViewController = navigationController?.topViewController - let previousViewController = navigationController?.viewControllers.last(where: { $0 != topViewController }) - let backTitle = previousViewController?.navigationItem.title ?? "" - - customBackInnerButton.setTitle(backTitle, for: .normal) - } - - private func configureDescriptionLabel() { - descriptionLabel.text = UserText.textSizeDescription - adjustDescriptionLabelHeight() - } - - private func adjustDescriptionLabelHeight() { - guard let headerView = tableView.tableHeaderView else { return } - - let adjustedSize = headerView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) - - if headerView.frame.size.height != adjustedSize.height { - headerView.frame.size.height = adjustedSize.height - } - } - - private func configureSlider() { - textSizeSlider.minimumValue = 0 - textSizeSlider.maximumValue = Float(predefinedPercentages.count - 1) - - textSizeSlider.steps = predefinedPercentages - - configureSliderCurrentSelection() - } - - private func configureSliderCurrentSelection() { - let currentSelectionIndex = predefinedPercentages.firstIndex(of: currentTextSizePercentage) ?? 0 - textSizeSlider.value = Float(currentSelectionIndex) - } - - private func updateTextSizeFooterLabel() { - let percentageString = "\(currentTextSizePercentage)%" - currentSelectedValueLabel.text = UserText.textSizeFooter(for: percentageString) - - } - - @IBAction func customBackButtonTapped(_ sender: AnyObject) { - var shouldPopViewController: Bool = true - - if let sheetController = navigationController?.presentationController as? UISheetPresentationController { - sheetController.detents = [.large()] - - // We recreate two-step detent animation, like on push but in reverse - if sheetController.selectedDetentIdentifier != .large { - shouldPopViewController = false - - // First step is to animate detent to large - sheetController.animateChanges { - sheetController.selectedDetentIdentifier = .large - } - - // Second step is to actually pop the view controller - DispatchQueue.main.asyncAfter(deadline: .now() + 0.35) { - self.navigationItem.leftBarButtonItem = nil - self.navigationController?.popViewController(animated: true) - } - } - } - - if shouldPopViewController { - navigationItem.leftBarButtonItem = nil - navigationController?.popViewController(animated: true) - } - } - - @IBAction func onSliderValueChanged(_ sender: Any) { - let roundedValue = round(textSizeSlider.value) - - // make the slider snap - textSizeSlider.value = roundedValue - - let index = Int(roundedValue) - let newTextSizePercentage = predefinedPercentages[index] - - if newTextSizePercentage != currentTextSizePercentage { - currentTextSizePercentage = newTextSizePercentage - - updateTextSizeFooterLabel() - storeTextSizeInAppSettings(currentTextSizePercentage) - } - } - - private func storeTextSizeInAppSettings(_ percentage: Int) { - let appSettings = AppDependencyProvider.shared.appSettings - appSettings.textSize = percentage - - NotificationCenter.default.post(name: AppUserDefaults.Notifications.textSizeChange, object: nil) - } - - private func firePixelForTextSizeChange() { - guard initialTextSizePercentage != currentTextSizePercentage else { return } - - Pixel.fire(pixel: .textSizeSettingsChanged, withAdditionalParameters: [PixelParameters.textSizeInitial: "\(initialTextSizePercentage)", - PixelParameters.textSizeUpdated: "\(currentTextSizePercentage)"]) - } -} - -extension TextSizeSettingsViewController: UISheetPresentationControllerDelegate { - - func sheetPresentationControllerDidChangeSelectedDetentIdentifier(_ sheetPresentationController: UISheetPresentationController) { - navigationItem.leftBarButtonItem = sheetPresentationController.selectedDetentIdentifier == .medium ? customBackBarButtonItem : nil - } -} - -extension TextSizeSettingsViewController: UIAdaptivePresentationControllerDelegate { - - func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { - firePixelForTextSizeChange() - } -} - -extension TextSizeSettingsViewController { - - private func decorate() { - let theme = ThemeManager.shared.currentTheme - descriptionLabel.textColor = theme.tableCellTextColor - smallerTextIcon.tintColor = theme.tableCellTextColor - largerTextIcon.tintColor = theme.tableCellTextColor - currentSelectedValueLabel.textColor = theme.tableHeaderTextColor - - tableView.backgroundColor = theme.backgroundColor - tableView.separatorColor = theme.tableCellSeparatorColor - - tableView.reloadData() - } -} diff --git a/DuckDuckGo/UserScripts.swift b/DuckDuckGo/UserScripts.swift index 4b003e0a57..0ffce0681d 100644 --- a/DuckDuckGo/UserScripts.swift +++ b/DuckDuckGo/UserScripts.swift @@ -50,10 +50,12 @@ final class UserScripts: UserScriptsProvider { private(set) var findInPageScript = FindInPageUserScript() private(set) var fullScreenVideoScript = FullScreenVideoUserScript() private(set) var printingUserScript = PrintingUserScript() - private(set) var textSizeUserScript = TextSizeUserScript(textSizeAdjustmentInPercents: AppDependencyProvider.shared.appSettings.textSize) + private(set) var textSizeUserScript: TextSizeUserScript private(set) var debugScript = DebugUserScript() - init(with sourceProvider: ScriptSourceProviding) { + init(with sourceProvider: ScriptSourceProviding, appSettings: AppSettings = AppDependencyProvider.shared.appSettings) { + textSizeUserScript = TextSizeUserScript(textSizeAdjustmentInPercents: appSettings.defaultZoomLevel.rawValue) + contentBlockerUserScript = ContentBlockerRulesUserScript(configuration: sourceProvider.contentBlockerRulesConfig) surrogatesScript = SurrogatesUserScript(configuration: sourceProvider.surrogatesConfig) autofillUserScript = AutofillUserScript(scriptSourceProvider: sourceProvider.autofillSourceProvider) diff --git a/DuckDuckGo/UserText.swift b/DuckDuckGo/UserText.swift index 42149ce1e9..79165717aa 100644 --- a/DuckDuckGo/UserText.swift +++ b/DuckDuckGo/UserText.swift @@ -1059,7 +1059,7 @@ But if you *do* want a peek under the hood, you can find more information about public static let settingsTheme = NSLocalizedString("settings.theme", value: "Theme", comment: "Settings screen cell text for theme") public static let settingsIcon = NSLocalizedString("settings.icon", value: "App Icon", comment: "Settings screen cell text for app icon selection") public static let settingsFirebutton = NSLocalizedString("settings.firebutton", value: "Fire Button Animation", comment: "Settings screen cell text for fire button animation") - public static let settingsText = NSLocalizedString("settings.text.size", value: "Text Size", comment: "Settings screen cell text for text size") + public static let settingsText = NSLocalizedString("settings.text.size", value: "Zoom Text", comment: "Settings screen cell text for text size") public static let settingsAddressBar = NSLocalizedString("settings.address.bar", value: "Address Bar Position", comment: "Settings screen cell text for addess bar position") public static let settingsFullURL = NSLocalizedString("settings.address.full.url", value: "Show Full Site Address", comment: "Settings screen cell title for toggling full URL visibility in address bar") diff --git a/DuckDuckGo/ZoomLevel.swift b/DuckDuckGo/ZoomLevel.swift new file mode 100644 index 0000000000..2275464b6f --- /dev/null +++ b/DuckDuckGo/ZoomLevel.swift @@ -0,0 +1,39 @@ +// +// ZoomLevel.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +enum ZoomLevel: Int, CaseIterable, CustomStringConvertible { + + var description: String { + return "\(self.rawValue)%" + } + + case percent80 = 80 + case percent90 = 90 + case percent100 = 100 + case percent110 = 110 + case percent120 = 120 + case percent130 = 130 + case percent140 = 140 + case percent150 = 150 + case percent160 = 160 + case percent170 = 170 + +} diff --git a/DuckDuckGo/en.lproj/Localizable.strings b/DuckDuckGo/en.lproj/Localizable.strings index 31c8359847..47b43cce44 100644 --- a/DuckDuckGo/en.lproj/Localizable.strings +++ b/DuckDuckGo/en.lproj/Localizable.strings @@ -2353,7 +2353,7 @@ But if you *do* want a peek under the hood, you can find more information about "settings.sync" = "Sync & Backup"; /* Settings screen cell text for text size */ -"settings.text.size" = "Text Size"; +"settings.text.size" = "Zoom Text"; /* Settings screen cell text for theme */ "settings.theme" = "Theme"; From 8a1e890f796a82e08971f39eb84bc67014727bf2 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 24 Oct 2024 15:05:34 +0100 Subject: [PATCH 04/34] clean up settings and use an enum for the zoom levels --- DuckDuckGo.xcodeproj/project.pbxproj | 8 +++---- DuckDuckGo/AppSettings.swift | 2 +- DuckDuckGo/AppUserDefaults.swift | 4 ++-- DuckDuckGo/PageZoomStorage.swift | 24 +++++++++++-------- DuckDuckGo/SettingsAccessibilityView.swift | 4 ++-- DuckDuckGo/SettingsState.swift | 8 +++---- DuckDuckGo/SettingsViewModel.swift | 14 +++++------ DuckDuckGo/TabViewController.swift | 4 ++-- ...bViewControllerBrowsingMenuExtension.swift | 2 +- .../{ZoomLevel.swift => TextZoomLevel.swift} | 2 +- DuckDuckGo/UserScripts.swift | 2 +- 11 files changed, 39 insertions(+), 35 deletions(-) rename DuckDuckGo/{ZoomLevel.swift => TextZoomLevel.swift} (93%) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 6cec037627..5fc6ce120d 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -412,7 +412,7 @@ 8512EA5724ED30D30073EE19 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8512EA5624ED30D30073EE19 /* Assets.xcassets */; }; 8512EA5D24ED30D30073EE19 /* WidgetsExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 8512EA4D24ED30D20073EE19 /* WidgetsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 8512EA9D24EEA6820073EE19 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F143C2B11E49D78C00CFDE3A /* Assets.xcassets */; }; - 85147CB62CCA755300677835 /* ZoomLevel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85147CB52CCA755300677835 /* ZoomLevel.swift */; }; + 85147CB62CCA755300677835 /* TextZoomLevel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85147CB52CCA755300677835 /* TextZoomLevel.swift */; }; 851481882A600EFC00ABC65F /* RemoteMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = 851481872A600EFC00ABC65F /* RemoteMessaging */; }; 851624C22B95F8BD002D5CD7 /* HistoryCapture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851624C12B95F8BD002D5CD7 /* HistoryCapture.swift */; }; 851624C52B9602A4002D5CD7 /* HistoryCaptureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851624C32B96029B002D5CD7 /* HistoryCaptureTests.swift */; }; @@ -1705,7 +1705,7 @@ 8512EA5324ED30D20073EE19 /* Widgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Widgets.swift; sourceTree = ""; }; 8512EA5624ED30D30073EE19 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 8512EA5824ED30D30073EE19 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 85147CB52CCA755300677835 /* ZoomLevel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZoomLevel.swift; sourceTree = ""; }; + 85147CB52CCA755300677835 /* TextZoomLevel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextZoomLevel.swift; sourceTree = ""; }; 851624C12B95F8BD002D5CD7 /* HistoryCapture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryCapture.swift; sourceTree = ""; }; 851624C32B96029B002D5CD7 /* HistoryCaptureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryCaptureTests.swift; sourceTree = ""; }; 851624C62B96389D002D5CD7 /* HistoryDebugViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryDebugViewController.swift; sourceTree = ""; }; @@ -4559,7 +4559,7 @@ isa = PBXGroup; children = ( 85D3FF2A2CC941C100487724 /* PageZoomStorage.swift */, - 85147CB52CCA755300677835 /* ZoomLevel.swift */, + 85147CB52CCA755300677835 /* TextZoomLevel.swift */, ); name = PageZoom; sourceTree = ""; @@ -7671,7 +7671,7 @@ F1E90C201E678E7C005E7E21 /* HomeControllerDelegate.swift in Sources */, 85DB12ED2A1FED0C000A4A72 /* AppDelegate+AppDeepLinks.swift in Sources */, 98DA6ECA2181E41F00E65433 /* ThemeManager.swift in Sources */, - 85147CB62CCA755300677835 /* ZoomLevel.swift in Sources */, + 85147CB62CCA755300677835 /* TextZoomLevel.swift in Sources */, F1D43AFC2B99C56000BAB743 /* RootDebugViewController+VanillaBrowser.swift in Sources */, 564DE4602C4544CA00D23241 /* HomePageDependencies.swift in Sources */, C159DF072A430B60007834BB /* EmailSignupViewController.swift in Sources */, diff --git a/DuckDuckGo/AppSettings.swift b/DuckDuckGo/AppSettings.swift index 8f7dfae88f..43deedd66c 100644 --- a/DuckDuckGo/AppSettings.swift +++ b/DuckDuckGo/AppSettings.swift @@ -60,7 +60,7 @@ protocol AppSettings: AnyObject, AppDebugSettings { var currentAddressBarPosition: AddressBarPosition { get set } var showFullSiteAddress: Bool { get set } - var defaultZoomLevel: ZoomLevel { get set } + var defaultTextZoomLevel: TextZoomLevel { get set } var favoritesDisplayMode: FavoritesDisplayMode { get set } diff --git a/DuckDuckGo/AppUserDefaults.swift b/DuckDuckGo/AppUserDefaults.swift index 15f41f06ce..0cf13830f4 100644 --- a/DuckDuckGo/AppUserDefaults.swift +++ b/DuckDuckGo/AppUserDefaults.swift @@ -241,9 +241,9 @@ public class AppUserDefaults: AppSettings { } } - var defaultZoomLevel: ZoomLevel { + var defaultTextZoomLevel: TextZoomLevel { get { - return ZoomLevel(rawValue: textSize) ?? .percent100 + return TextZoomLevel(rawValue: textSize) ?? .percent100 } set { textSize = newValue.rawValue diff --git a/DuckDuckGo/PageZoomStorage.swift b/DuckDuckGo/PageZoomStorage.swift index 25e50916a4..5c29e0d8c1 100644 --- a/DuckDuckGo/PageZoomStorage.swift +++ b/DuckDuckGo/PageZoomStorage.swift @@ -20,25 +20,29 @@ import Foundation protocol PageZoomStoring { - func zoomLevelForDomain(_ domain: String) -> Int? - func set(zoomLevel: Int, forDomain domain: String) - func resetZoomLevels(_ excludingDomains: [String]) + func textZoomLevelForDomain(_ domain: String) -> TextZoomLevel? + func set(textZoomLevel: TextZoomLevel, forDomain domain: String) + func resetTextZoomLevels(_ excludingDomains: [String]) } class PageZoomStorage: PageZoomStoring { - var zoomLevels: [String: Int] = [:] + // TODO persist this + var textZoomLevels: [String: Int] = [:] - func zoomLevelForDomain(_ domain: String) -> Int? { - return zoomLevels[domain] + func textZoomLevelForDomain(_ domain: String) -> TextZoomLevel? { + guard let zoomLevel = textZoomLevels[domain] else { + return nil + } + return TextZoomLevel(rawValue: zoomLevel) } - func set(zoomLevel: Int, forDomain domain: String) { - zoomLevels[domain] = zoomLevel + func set(textZoomLevel: TextZoomLevel, forDomain domain: String) { + textZoomLevels[domain] = textZoomLevel.rawValue } - func resetZoomLevels(_ excludingDomains: [String]) { - zoomLevels = zoomLevels.filter { + func resetTextZoomLevels(_ excludingDomains: [String]) { + textZoomLevels = textZoomLevels.filter { !excludingDomains.contains($0.key) } } diff --git a/DuckDuckGo/SettingsAccessibilityView.swift b/DuckDuckGo/SettingsAccessibilityView.swift index 7fd0394265..aaf5952bbf 100644 --- a/DuckDuckGo/SettingsAccessibilityView.swift +++ b/DuckDuckGo/SettingsAccessibilityView.swift @@ -32,8 +32,8 @@ struct SettingsAccessibilityView: View { // Text Size if viewModel.state.textSize.enabled { SettingsPickerCellView(label: UserText.settingsText, - options: ZoomLevel.allCases, - selectedOption: viewModel.zoomLevelBinding) + options: TextZoomLevel.allCases, + selectedOption: viewModel.textZoomLevelBinding) } } diff --git a/DuckDuckGo/SettingsState.swift b/DuckDuckGo/SettingsState.swift index cb984b34c5..efdbe7ad8f 100644 --- a/DuckDuckGo/SettingsState.swift +++ b/DuckDuckGo/SettingsState.swift @@ -31,9 +31,9 @@ struct SettingsState { var position: AddressBarPosition } - struct TextSize { + struct TextZoom { var enabled: Bool - var zoomLevel: ZoomLevel + var level: TextZoomLevel } struct Subscription: Codable { @@ -57,7 +57,7 @@ struct SettingsState { var appTheme: ThemeName var appIcon: AppIcon var fireButtonAnimation: FireButtonAnimationType - var textSize: TextSize + var textSize: TextZoom var addressBar: AddressBar var showsFullURL: Bool @@ -107,7 +107,7 @@ struct SettingsState { appTheme: .systemDefault, appIcon: AppIconManager.shared.appIcon, fireButtonAnimation: .fireRising, - textSize: TextSize(enabled: false, zoomLevel: .percent100), + textSize: TextZoom(enabled: false, level: .percent100), addressBar: AddressBar(enabled: false, position: .top), showsFullURL: false, sendDoNotSell: true, diff --git a/DuckDuckGo/SettingsViewModel.swift b/DuckDuckGo/SettingsViewModel.swift index 3eba864915..55cad17a38 100644 --- a/DuckDuckGo/SettingsViewModel.swift +++ b/DuckDuckGo/SettingsViewModel.swift @@ -257,12 +257,12 @@ final class SettingsViewModel: ObservableObject { ) } - var zoomLevelBinding: Binding { - Binding( - get: { self.state.textSize.zoomLevel }, + var textZoomLevelBinding: Binding { + Binding( + get: { self.state.textSize.level }, set: { newValue in - self.appSettings.defaultZoomLevel = newValue - self.state.textSize.zoomLevel = newValue + self.appSettings.defaultTextZoomLevel = newValue + self.state.textSize.level = newValue } ) } @@ -414,7 +414,7 @@ extension SettingsViewModel { appTheme: appSettings.currentThemeName, appIcon: AppIconManager.shared.appIcon, fireButtonAnimation: appSettings.currentFireButtonAnimation, - textSize: SettingsState.TextSize(enabled: !isPad, zoomLevel: appSettings.defaultZoomLevel), + textSize: SettingsState.TextZoom(enabled: !isPad, level: appSettings.defaultTextZoomLevel), addressBar: SettingsState.AddressBar(enabled: !isPad, position: appSettings.currentAddressBarPosition), showsFullURL: appSettings.showFullSiteAddress, sendDoNotSell: appSettings.sendDoNotSell, @@ -787,7 +787,7 @@ extension SettingsViewModel { object: nil, queue: .main, using: { [weak self] _ in guard let self = self else { return } - self.state.textSize = SettingsState.TextSize(enabled: !isPad, zoomLevel: self.appSettings.defaultZoomLevel) + self.state.textSize = SettingsState.TextZoom(enabled: !isPad, level: self.appSettings.defaultTextZoomLevel) }) } diff --git a/DuckDuckGo/TabViewController.swift b/DuckDuckGo/TabViewController.swift index 3fd38128ec..85c72864fc 100644 --- a/DuckDuckGo/TabViewController.swift +++ b/DuckDuckGo/TabViewController.swift @@ -971,7 +971,7 @@ class TabViewController: UIViewController { } @objc func onTextSizeChange() { - webView.adjustTextSize(appSettings.defaultZoomLevel.rawValue) + webView.adjustTextSize(appSettings.defaultTextZoomLevel.rawValue) } @objc func onDuckDuckGoEmailSignOut(_ notification: Notification) { @@ -2519,7 +2519,7 @@ extension TabViewController: UserContentControllerDelegate { userScripts.autofillUserScript.vaultDelegate = vaultManager userScripts.faviconScript.delegate = faviconUpdater userScripts.printingUserScript.delegate = self - userScripts.textSizeUserScript.textSizeAdjustmentInPercents = appSettings.defaultZoomLevel.rawValue + userScripts.textSizeUserScript.textSizeAdjustmentInPercents = appSettings.defaultTextZoomLevel.rawValue userScripts.loginFormDetectionScript?.delegate = self userScripts.autoconsentUserScript.delegate = self userScripts.specialErrorPageUserScript?.delegate = self diff --git a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift index 7cd1eb0099..ce8c8e057a 100644 --- a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift +++ b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift @@ -169,7 +169,7 @@ extension TabViewController { private func buildZoomLevelEntry(forLink link: Link) -> BrowsingMenuEntry { let domain = link.url.host?.droppingWwwPrefix() ?? "" - let percent = pageZoomStorage.zoomLevelForDomain(domain) ?? 100 + let percent = pageZoomStorage.textZoomLevelForDomain(domain)?.rawValue ?? appSettings.defaultTextZoomLevel.rawValue return BrowsingMenuEntry.regular(name: UserText.pageZoomWithPercent(percent), image: UIImage(named: "Type-Size-16")!, showNotificationDot: false) { // TODO diff --git a/DuckDuckGo/ZoomLevel.swift b/DuckDuckGo/TextZoomLevel.swift similarity index 93% rename from DuckDuckGo/ZoomLevel.swift rename to DuckDuckGo/TextZoomLevel.swift index 2275464b6f..09ef71689d 100644 --- a/DuckDuckGo/ZoomLevel.swift +++ b/DuckDuckGo/TextZoomLevel.swift @@ -19,7 +19,7 @@ import Foundation -enum ZoomLevel: Int, CaseIterable, CustomStringConvertible { +enum TextZoomLevel: Int, CaseIterable, CustomStringConvertible { var description: String { return "\(self.rawValue)%" diff --git a/DuckDuckGo/UserScripts.swift b/DuckDuckGo/UserScripts.swift index 0ffce0681d..e1d73ea742 100644 --- a/DuckDuckGo/UserScripts.swift +++ b/DuckDuckGo/UserScripts.swift @@ -54,7 +54,7 @@ final class UserScripts: UserScriptsProvider { private(set) var debugScript = DebugUserScript() init(with sourceProvider: ScriptSourceProviding, appSettings: AppSettings = AppDependencyProvider.shared.appSettings) { - textSizeUserScript = TextSizeUserScript(textSizeAdjustmentInPercents: appSettings.defaultZoomLevel.rawValue) + textSizeUserScript = TextSizeUserScript(textSizeAdjustmentInPercents: appSettings.defaultTextZoomLevel.rawValue) contentBlockerUserScript = ContentBlockerRulesUserScript(configuration: sourceProvider.contentBlockerRulesConfig) surrogatesScript = SurrogatesUserScript(configuration: sourceProvider.surrogatesConfig) From 2d3b907d524a17dcade3e999e4143dbe9a5c6dc3 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 24 Oct 2024 15:44:11 +0100 Subject: [PATCH 05/34] more renaming --- DuckDuckGo.xcodeproj/project.pbxproj | 14 +++++++------- ...Storage.swift => DomainTextZoomStorage.swift} | 6 +++--- DuckDuckGo/MainViewController.swift | 4 ++-- DuckDuckGo/TabManager.swift | 10 +++++----- DuckDuckGo/TabViewController.swift | 16 ++++++++++------ .../TabViewControllerBrowsingMenuExtension.swift | 6 ++++-- ...TabViewControllerLongPressMenuExtension.swift | 2 +- 7 files changed, 32 insertions(+), 26 deletions(-) rename DuckDuckGo/{PageZoomStorage.swift => DomainTextZoomStorage.swift} (92%) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 5fc6ce120d..50853889f1 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -549,7 +549,7 @@ 85D2187624BF6164004373D2 /* FaviconSourcesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D2187524BF6164004373D2 /* FaviconSourcesProvider.swift */; }; 85D2187924BF6B8B004373D2 /* FaviconSourcesProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D2187724BF6B88004373D2 /* FaviconSourcesProviderTests.swift */; }; 85D2187B24BF9F85004373D2 /* FaviconUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D2187A24BF9F85004373D2 /* FaviconUserScript.swift */; }; - 85D3FF2B2CC941C100487724 /* PageZoomStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D3FF2A2CC941C100487724 /* PageZoomStorage.swift */; }; + 85D3FF2B2CC941C100487724 /* DomainTextZoomStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D3FF2A2CC941C100487724 /* DomainTextZoomStorage.swift */; }; 85D598872927F84C00FA3B1B /* Crashes in Frameworks */ = {isa = PBXBuildFile; productRef = 85D598862927F84C00FA3B1B /* Crashes */; }; 85DB12EB2A1FE2A4000A4A72 /* LockScreenWidgets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DB12EA2A1FE2A4000A4A72 /* LockScreenWidgets.swift */; }; 85DB12ED2A1FED0C000A4A72 /* AppDelegate+AppDeepLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DB12EC2A1FED0C000A4A72 /* AppDelegate+AppDeepLinks.swift */; }; @@ -1841,7 +1841,7 @@ 85D2187A24BF9F85004373D2 /* FaviconUserScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconUserScript.swift; sourceTree = ""; }; 85D33FCB25C97B6E002B91A6 /* IntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 85D33FCF25C97B6E002B91A6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 85D3FF2A2CC941C100487724 /* PageZoomStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageZoomStorage.swift; sourceTree = ""; }; + 85D3FF2A2CC941C100487724 /* DomainTextZoomStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainTextZoomStorage.swift; sourceTree = ""; }; 85DB12EA2A1FE2A4000A4A72 /* LockScreenWidgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LockScreenWidgets.swift; sourceTree = ""; }; 85DB12EC2A1FED0C000A4A72 /* AppDelegate+AppDeepLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+AppDeepLinks.swift"; sourceTree = ""; }; 85DDE03F2AC6FF65006ABCA2 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; @@ -4235,7 +4235,7 @@ EECD94B22A28B8580085C66E /* NetworkProtection */, 85AE668C20971FCA0014CF04 /* Notifications */, F1C4A70C1E5771F800A6CA1B /* OmniBar */, - 85D3FF292CC941AC00487724 /* PageZoom */, + 85D3FF292CC941AC00487724 /* TextZoom */, F1AE54DB1F0425BB00D9A700 /* Privacy */, F1DF09502B039E6E008CC908 /* PrivacyDashboard */, 02ECEC602A965074009F0654 /* PrivacyInfo.xcprivacy */, @@ -4555,13 +4555,13 @@ path = IntegrationTests; sourceTree = ""; }; - 85D3FF292CC941AC00487724 /* PageZoom */ = { + 85D3FF292CC941AC00487724 /* TextZoom */ = { isa = PBXGroup; children = ( - 85D3FF2A2CC941C100487724 /* PageZoomStorage.swift */, + 85D3FF2A2CC941C100487724 /* DomainTextZoomStorage.swift */, 85147CB52CCA755300677835 /* TextZoomLevel.swift */, ); - name = PageZoom; + name = TextZoom; sourceTree = ""; }; 85DD44232976C7A8005CC388 /* Controllers */ = { @@ -7785,7 +7785,7 @@ 85DFEDF924CF3D0E00973FE7 /* TabsBarCell.swift in Sources */, 851672D32BED23FE00592F24 /* AutocompleteViewModel.swift in Sources */, 8562CE152B9B645C00E1D399 /* CachedBookmarkSuggestions.swift in Sources */, - 85D3FF2B2CC941C100487724 /* PageZoomStorage.swift in Sources */, + 85D3FF2B2CC941C100487724 /* DomainTextZoomStorage.swift in Sources */, C13F3F682B7F88100083BE40 /* AuthConfirmationPromptView.swift in Sources */, F1617C191E573EA800DEDCAF /* TabSwitcherDelegate.swift in Sources */, 4B5C462A2AF2A6E6002A4432 /* VPNIntents.swift in Sources */, diff --git a/DuckDuckGo/PageZoomStorage.swift b/DuckDuckGo/DomainTextZoomStorage.swift similarity index 92% rename from DuckDuckGo/PageZoomStorage.swift rename to DuckDuckGo/DomainTextZoomStorage.swift index 5c29e0d8c1..b461d2f81d 100644 --- a/DuckDuckGo/PageZoomStorage.swift +++ b/DuckDuckGo/DomainTextZoomStorage.swift @@ -1,5 +1,5 @@ // -// PageZoomStorage.swift +// DomainTextZoomStorage.swift // DuckDuckGo // // Copyright © 2024 DuckDuckGo. All rights reserved. @@ -19,13 +19,13 @@ import Foundation -protocol PageZoomStoring { +protocol DomainTextZoomStoring { func textZoomLevelForDomain(_ domain: String) -> TextZoomLevel? func set(textZoomLevel: TextZoomLevel, forDomain domain: String) func resetTextZoomLevels(_ excludingDomains: [String]) } -class PageZoomStorage: PageZoomStoring { +class DomainTextZoomStorage: DomainTextZoomStoring { // TODO persist this var textZoomLevels: [String: Int] = [:] diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index f722d634ae..95e4afa61f 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -201,7 +201,7 @@ class MainViewController: UIViewController { subscriptionFeatureAvailability: SubscriptionFeatureAvailability, voiceSearchHelper: VoiceSearchHelperProtocol, featureFlagger: FeatureFlagger, - pageZoomStorage: PageZoomStoring = PageZoomStorage() + domainTextZoomStorage: DomainTextZoomStoring = DomainTextZoomStorage() ) { self.bookmarksDatabase = bookmarksDatabase self.bookmarksDatabaseCleaner = bookmarksDatabaseCleaner @@ -226,7 +226,7 @@ class MainViewController: UIViewController { contextualOnboardingLogic: contextualOnboardingLogic, onboardingPixelReporter: contextualOnboardingPixelReporter, featureFlagger: featureFlagger, - pageZoomStorage: pageZoomStorage) + domainTextZoomStorage: domainTextZoomStorage) self.syncPausedStateManager = syncPausedStateManager self.privacyProDataReporter = privacyProDataReporter self.homeTabManager = NewTabPageManager() diff --git a/DuckDuckGo/TabManager.swift b/DuckDuckGo/TabManager.swift index 80ddb55b33..26c36e9bfd 100644 --- a/DuckDuckGo/TabManager.swift +++ b/DuckDuckGo/TabManager.swift @@ -42,7 +42,7 @@ class TabManager { private let contextualOnboardingLogic: ContextualOnboardingLogic private let onboardingPixelReporter: OnboardingPixelReporting private let featureFlagger: FeatureFlagger - private let pageZoomStorage: PageZoomStoring + private let domainTextZoomStorage: DomainTextZoomStoring weak var delegate: TabDelegate? @@ -61,7 +61,7 @@ class TabManager { contextualOnboardingLogic: ContextualOnboardingLogic, onboardingPixelReporter: OnboardingPixelReporting, featureFlagger: FeatureFlagger, - pageZoomStorage: PageZoomStoring) { + domainTextZoomStorage: DomainTextZoomStoring) { self.model = model self.previewsSource = previewsSource self.bookmarksDatabase = bookmarksDatabase @@ -73,7 +73,7 @@ class TabManager { self.contextualOnboardingLogic = contextualOnboardingLogic self.onboardingPixelReporter = onboardingPixelReporter self.featureFlagger = featureFlagger - self.pageZoomStorage = pageZoomStorage + self.domainTextZoomStorage = domainTextZoomStorage registerForNotifications() } @@ -97,7 +97,7 @@ class TabManager { contextualOnboardingLogic: contextualOnboardingLogic, onboardingPixelReporter: onboardingPixelReporter, featureFlagger: featureFlagger, - pageZoomStorage: pageZoomStorage) + domainTextZoomStorage: domainTextZoomStorage) controller.applyInheritedAttribution(inheritedAttribution) controller.attachWebView(configuration: configuration, andLoadRequest: url == nil ? nil : URLRequest.userInitiated(url!), @@ -177,7 +177,7 @@ class TabManager { contextualOnboardingLogic: contextualOnboardingLogic, onboardingPixelReporter: onboardingPixelReporter, featureFlagger: featureFlagger, - pageZoomStorage: pageZoomStorage) + domainTextZoomStorage: domainTextZoomStorage) controller.attachWebView(configuration: configCopy, andLoadRequest: request, consumeCookies: !model.hasActiveTabs, diff --git a/DuckDuckGo/TabViewController.swift b/DuckDuckGo/TabViewController.swift index 85c72864fc..b70eced27d 100644 --- a/DuckDuckGo/TabViewController.swift +++ b/DuckDuckGo/TabViewController.swift @@ -188,7 +188,7 @@ class TabViewController: UIViewController { var storedSpecialErrorPageUserScript: SpecialErrorPageUserScript? var isSpecialErrorPageVisible: Bool = false - let pageZoomStorage: PageZoomStoring + let domainTextZoomStorage: DomainTextZoomStoring let syncService: DDGSyncing private let daxDialogsDebouncer = Debouncer(mode: .common) @@ -323,7 +323,7 @@ class TabViewController: UIViewController { onboardingPixelReporter: OnboardingCustomInteractionPixelReporting, urlCredentialCreator: URLCredentialCreating = URLCredentialCreator(), featureFlagger: FeatureFlagger, - pageZoomStorage: PageZoomStoring) -> TabViewController { + domainTextZoomStorage: DomainTextZoomStoring) -> TabViewController { let storyboard = UIStoryboard(name: "Tab", bundle: nil) let controller = storyboard.instantiateViewController(identifier: "TabViewController", creator: { coder in TabViewController(coder: coder, @@ -339,7 +339,7 @@ class TabViewController: UIViewController { onboardingPixelReporter: onboardingPixelReporter, urlCredentialCreator: urlCredentialCreator, featureFlagger: featureFlagger, - pageZoomStorage: pageZoomStorage + domainTextZoomStorage: domainTextZoomStorage ) }) return controller @@ -373,7 +373,7 @@ class TabViewController: UIViewController { onboardingPixelReporter: OnboardingCustomInteractionPixelReporting, urlCredentialCreator: URLCredentialCreating = URLCredentialCreator(), featureFlagger: FeatureFlagger, - pageZoomStorage: PageZoomStoring) { + domainTextZoomStorage: DomainTextZoomStoring) { self.tabModel = tabModel self.appSettings = appSettings self.bookmarksDatabase = bookmarksDatabase @@ -392,7 +392,7 @@ class TabViewController: UIViewController { self.onboardingPixelReporter = onboardingPixelReporter self.urlCredentialCreator = urlCredentialCreator self.featureFlagger = featureFlagger - self.pageZoomStorage = pageZoomStorage + self.domainTextZoomStorage = domainTextZoomStorage super.init(coder: aDecoder) } @@ -971,7 +971,11 @@ class TabViewController: UIViewController { } @objc func onTextSizeChange() { - webView.adjustTextSize(appSettings.defaultTextZoomLevel.rawValue) + // If the webview returns no host then there won't be a setting for a blank string anyway. + let level = domainTextZoomStorage.textZoomLevelForDomain(webView.url?.host?.droppingWwwPrefix() ?? "") + // And if there's no setting for whatever domain is passed in, use the app default + ?? appSettings.defaultTextZoomLevel + webView.adjustTextSize(level.rawValue) } @objc func onDuckDuckGoEmailSignOut(_ notification: Notification) { diff --git a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift index ce8c8e057a..028c68309c 100644 --- a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift +++ b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift @@ -169,9 +169,11 @@ extension TabViewController { private func buildZoomLevelEntry(forLink link: Link) -> BrowsingMenuEntry { let domain = link.url.host?.droppingWwwPrefix() ?? "" - let percent = pageZoomStorage.textZoomLevelForDomain(domain)?.rawValue ?? appSettings.defaultTextZoomLevel.rawValue + let percent = domainTextZoomStorage.textZoomLevelForDomain(domain)?.rawValue ?? appSettings.defaultTextZoomLevel.rawValue - return BrowsingMenuEntry.regular(name: UserText.pageZoomWithPercent(percent), image: UIImage(named: "Type-Size-16")!, showNotificationDot: false) { + return BrowsingMenuEntry.regular(name: UserText.pageZoomWithPercent(percent), + image: UIImage(named: "Type-Size-16")!, + showNotificationDot: false) { // TODO } } diff --git a/DuckDuckGo/TabViewControllerLongPressMenuExtension.swift b/DuckDuckGo/TabViewControllerLongPressMenuExtension.swift index 525646cc6a..9aee28cbd5 100644 --- a/DuckDuckGo/TabViewControllerLongPressMenuExtension.swift +++ b/DuckDuckGo/TabViewControllerLongPressMenuExtension.swift @@ -113,7 +113,7 @@ extension TabViewController { contextualOnboardingLogic: contextualOnboardingLogic, onboardingPixelReporter: onboardingPixelReporter, featureFlagger: AppDependencyProvider.shared.featureFlagger, - pageZoomStorage: pageZoomStorage) + domainTextZoomStorage: domainTextZoomStorage) tabController.isLinkPreview = true let configuration = WKWebViewConfiguration.nonPersistent() From 256ec20b3f703c96d6c62564604e09f5233509f3 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 24 Oct 2024 23:31:32 +0100 Subject: [PATCH 06/34] show slide sheet on phone --- DuckDuckGo.xcodeproj/project.pbxproj | 4 + DuckDuckGo/IntervalSlider.swift | 61 ++++++- DuckDuckGo/TabViewController.swift | 1 + ...bViewControllerBrowsingMenuExtension.swift | 4 +- DuckDuckGo/TextZoomController.swift | 166 ++++++++++++++++++ 5 files changed, 225 insertions(+), 11 deletions(-) create mode 100644 DuckDuckGo/TextZoomController.swift diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 50853889f1..34438ecec4 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -514,6 +514,7 @@ 8596C30D2B7EB1800058EF90 /* DataStoreWarmup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8596C30C2B7EB1800058EF90 /* DataStoreWarmup.swift */; }; 8598F67B2405EB8D00FBC70C /* KeyboardSettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8598F6792405EB8600FBC70C /* KeyboardSettingsTests.swift */; }; 8599690F29D2F1C100DBF9FA /* DDGSync in Frameworks */ = {isa = PBXBuildFile; productRef = 8599690E29D2F1C100DBF9FA /* DDGSync */; }; + 859DA3322CCAC0A300C90694 /* TextZoomController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859DA3312CCAC0A300C90694 /* TextZoomController.swift */; }; 85A1B3B220C6CD9900C18F15 /* CookieStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85A1B3B120C6CD9900C18F15 /* CookieStorage.swift */; }; 85A313972028E78A00327D00 /* release_notes.txt in Resources */ = {isa = PBXBuildFile; fileRef = 85A313962028E78A00327D00 /* release_notes.txt */; }; 85A9C37920E0E00C00073340 /* HomeRow.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 85A9C37820E0E00C00073340 /* HomeRow.xcassets */; }; @@ -1803,6 +1804,7 @@ 8590CB68268A4E190089F6BF /* DebugEtagStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugEtagStorage.swift; sourceTree = ""; }; 8596C30C2B7EB1800058EF90 /* DataStoreWarmup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStoreWarmup.swift; sourceTree = ""; }; 8598F6792405EB8600FBC70C /* KeyboardSettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardSettingsTests.swift; sourceTree = ""; }; + 859DA3312CCAC0A300C90694 /* TextZoomController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextZoomController.swift; sourceTree = ""; }; 85A1B3B120C6CD9900C18F15 /* CookieStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CookieStorage.swift; sourceTree = ""; }; 85A313962028E78A00327D00 /* release_notes.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = release_notes.txt; path = fastlane/metadata/default/release_notes.txt; sourceTree = ""; }; 85A53EC9200D1FA20010D13F /* FileStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileStore.swift; sourceTree = ""; }; @@ -4559,6 +4561,7 @@ isa = PBXGroup; children = ( 85D3FF2A2CC941C100487724 /* DomainTextZoomStorage.swift */, + 859DA3312CCAC0A300C90694 /* TextZoomController.swift */, 85147CB52CCA755300677835 /* TextZoomLevel.swift */, ); name = TextZoom; @@ -7571,6 +7574,7 @@ 319A37172829C8AD0079FBCE /* UITableViewExtension.swift in Sources */, 85EE7F59224673C5000FE757 /* WebContainerNavigationController.swift in Sources */, 6FD1BAE52B87A107000C475C /* AdAttributionReporterStorage.swift in Sources */, + 859DA3322CCAC0A300C90694 /* TextZoomController.swift in Sources */, 6F5CC0812C2AFFE400AFC840 /* ToggleExpandButtonStyle.swift in Sources */, D68A21462B7EC16200BB372E /* SubscriptionExternalLinkViewModel.swift in Sources */, 31DE43C22C2C480D00F8C51F /* DuckPlayerFeaturePresentationView.swift in Sources */, diff --git a/DuckDuckGo/IntervalSlider.swift b/DuckDuckGo/IntervalSlider.swift index 37ced4bea3..d0c3b33f08 100644 --- a/DuckDuckGo/IntervalSlider.swift +++ b/DuckDuckGo/IntervalSlider.swift @@ -18,6 +18,7 @@ // import UIKit +import SwiftUI class IntervalSlider: UISlider { @@ -40,14 +41,8 @@ class IntervalSlider: UISlider { let thumbRect = thumbRect(forBounds: rect, trackRect: trackRect, value: 1.0) let thumbOffset = Darwin.round(thumbRect.width/2) - 3 - - let newTrackRect = trackRect.inset(by: UIEdgeInsets(top: 0.0, left: thumbOffset, bottom: 0.0, right: thumbOffset)) - - let color: UIColor = UIColor.cornflowerBlue - let bpath: UIBezierPath = UIBezierPath(rect: newTrackRect) - color.set() - bpath.fill() + let newTrackRect = trackRect.inset(by: UIEdgeInsets(top: 0.0, left: thumbOffset, bottom: 0.0, right: thumbOffset)) guard steps.count > 1 else { return } for i in 0...steps.count-1 { @@ -58,8 +53,13 @@ class IntervalSlider: UISlider { width: Constants.markWidth, height: Constants.markHeight) let markPath: UIBezierPath = UIBezierPath(roundedRect: markRect, cornerRadius: Constants.markCornerRadius) - color.set() - + + if Int(self.value) >= i { + minimumTrackTintColor?.set() + } else { + maximumTrackTintColor?.set() + } + markPath.fill() } } @@ -74,3 +74,46 @@ class IntervalSlider: UISlider { } } + +struct IntervalSliderRepresentable: UIViewRepresentable { + + @Binding var value: Int + + let steps: [Int] + + func makeUIView(context: Context) -> IntervalSlider { + let slider = IntervalSlider(frame: .zero) + slider.minimumTrackTintColor = UIColor(designSystemColor: .accent) + slider.maximumTrackTintColor = UIColor(designSystemColor: .buttonsSecondaryFillDefault) + slider.steps = steps + slider.minimumValue = Float(0) + slider.maximumValue = Float(steps.count - 1) + slider.addTarget(context.coordinator, action: #selector(Coordinator.valueChanged(_:)), for: .valueChanged) + return slider + } + + func updateUIView(_ uiView: IntervalSlider, context: Context) { + uiView.value = Float(value) + } + + func makeCoordinator() -> Coordinator { + Coordinator(self) + } + + class Coordinator: NSObject { + var parent: IntervalSliderRepresentable + + init(_ parent: IntervalSliderRepresentable) { + self.parent = parent + } + + @objc func valueChanged(_ sender: IntervalSlider) { + let roundedValue = round(sender.value) + sender.value = roundedValue + if Int(roundedValue) != parent.value { + parent.value = Int(roundedValue) + sender.setNeedsDisplay() + } + } + } +} diff --git a/DuckDuckGo/TabViewController.swift b/DuckDuckGo/TabViewController.swift index b70eced27d..217b519ea9 100644 --- a/DuckDuckGo/TabViewController.swift +++ b/DuckDuckGo/TabViewController.swift @@ -1422,6 +1422,7 @@ extension TabViewController: WKNavigationDelegate { func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { self.currentlyLoadedURL = webView.url + onTextSizeChange() adClickAttributionDetection.onDidFinishNavigation(url: webView.url) adClickAttributionLogic.onDidFinishNavigation(host: webView.url?.host) hideProgressIndicator() diff --git a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift index 028c68309c..62a573458e 100644 --- a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift +++ b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift @@ -173,8 +173,8 @@ extension TabViewController { return BrowsingMenuEntry.regular(name: UserText.pageZoomWithPercent(percent), image: UIImage(named: "Type-Size-16")!, - showNotificationDot: false) { - // TODO + showNotificationDot: false) { [weak self] in + self?.showTextZoomAdjustment() } } diff --git a/DuckDuckGo/TextZoomController.swift b/DuckDuckGo/TextZoomController.swift new file mode 100644 index 0000000000..5a32c0a0fa --- /dev/null +++ b/DuckDuckGo/TextZoomController.swift @@ -0,0 +1,166 @@ +// +// TextZoomController.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import UIKit +import SwiftUI + +class TextZoomController: UIHostingController { + + let storage: DomainTextZoomStoring + let model: TextZoomEditorModel + + @MainActor init(domain: String, storage: DomainTextZoomStoring, defaultTextZoom: TextZoomLevel) { + self.storage = storage + self.model = TextZoomEditorModel(domain: domain, storage: storage, defaultTextZoom: defaultTextZoom) + super.init(rootView: TextZoomEditorView(model: model)) + } + + @MainActor required dynamic init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} + +class TextZoomEditorModel: ObservableObject { + + let domain: String + let storage: DomainTextZoomStoring + + var valueAsPercent: Int { + TextZoomLevel.allCases[value].rawValue + } + + @Published var value: Int = 0 { + didSet { + title = UserText.pageZoomWithPercent(valueAsPercent) + storage.set(textZoomLevel: TextZoomLevel.allCases[value], forDomain: domain) + NotificationCenter.default.post( + name: AppUserDefaults.Notifications.textSizeChange, + object: nil) + } + } + + @Published var title: String = "" + + init(domain: String, storage: DomainTextZoomStoring, defaultTextZoom: TextZoomLevel) { + self.domain = domain + self.storage = storage + let percent = (storage.textZoomLevelForDomain(domain) ?? defaultTextZoom) + value = TextZoomLevel.allCases.firstIndex(of: percent) ?? 0 + } + + func increment() { + value = min(TextZoomLevel.allCases.count - 1, value + 1) + } + + func decrement() { + value = max(0, value - 1) + } + +} + +struct TextZoomEditorView: View { + + @ObservedObject var model: TextZoomEditorModel + + @Environment(\.dismiss) var dismiss + + @ViewBuilder + func header() -> some View { + ZStack(alignment: .center) { + Text(model.title) + .font(Font(uiFont: .daxHeadline())) + .frame(alignment: .center) + + Button { + dismiss() + } label: { + Text(UserText.navigationTitleDone) + .font(Font(uiFont: .daxHeadline())) + } + .buttonStyle(.plain) + .padding(0) + .frame(maxWidth: .infinity, alignment: .trailing) + } + .padding(16) + } + + func slider() -> some View { + HStack { + Button { + model.decrement() + } label: { + Image("Font-Smaller-24") + } + .foregroundColor(Color(designSystemColor: .textPrimary)) + .padding(12) + + IntervalSliderRepresentable( + value: $model.value, + steps: TextZoomLevel.allCases.map { $0.rawValue }) + .padding(.vertical) + + Button { + model.increment() + } label: { + Image("Font-Larger-24") + } + .foregroundColor(Color(designSystemColor: .textPrimary)) + .padding(12) + } + .background(RoundedRectangle(cornerRadius: 8)) + .padding(16) + .foregroundColor(Color(designSystemColor: .surface)) + } + + var body: some View { + VStack { + header() + Spacer() + slider() + Spacer() + } + .frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, maxHeight: .infinity) + .background(Color(designSystemColor: .background)) + } + +} + +extension TabViewController { + + func showTextZoomAdjustment() { + guard let domain = webView.url?.host?.droppingWwwPrefix() else { return } + let controller = TextZoomController( + domain: domain, + storage: domainTextZoomStorage, + defaultTextZoom: appSettings.defaultTextZoomLevel + ) + + controller.modalPresentationStyle = .formSheet + if #available(iOS 16.0, *) { + controller.sheetPresentationController?.detents = [.custom(resolver: { _ in + return 180 + })] + } else { + controller.sheetPresentationController?.detents = [.medium()] + } + present(controller, animated: true) + } + +} From d43a56c82a720205cade5e6754e3038abf9501ed Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 24 Oct 2024 23:49:14 +0100 Subject: [PATCH 07/34] fix ui glitch --- DuckDuckGo/IntervalSlider.swift | 1 + DuckDuckGo/TextZoomController.swift | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/DuckDuckGo/IntervalSlider.swift b/DuckDuckGo/IntervalSlider.swift index d0c3b33f08..0fcb03d09e 100644 --- a/DuckDuckGo/IntervalSlider.swift +++ b/DuckDuckGo/IntervalSlider.swift @@ -94,6 +94,7 @@ struct IntervalSliderRepresentable: UIViewRepresentable { func updateUIView(_ uiView: IntervalSlider, context: Context) { uiView.value = Float(value) + uiView.setNeedsDisplay() } func makeCoordinator() -> Coordinator { diff --git a/DuckDuckGo/TextZoomController.swift b/DuckDuckGo/TextZoomController.swift index 5a32c0a0fa..e61830494b 100644 --- a/DuckDuckGo/TextZoomController.swift +++ b/DuckDuckGo/TextZoomController.swift @@ -124,9 +124,9 @@ struct TextZoomEditorView: View { .foregroundColor(Color(designSystemColor: .textPrimary)) .padding(12) } - .background(RoundedRectangle(cornerRadius: 8)) + .background(RoundedRectangle(cornerRadius: 8).foregroundColor(Color(designSystemColor: .surface))) .padding(16) - .foregroundColor(Color(designSystemColor: .surface)) + } var body: some View { From a52dbf1914140751a648bcde0b6b56bc945d17d3 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Fri, 25 Oct 2024 20:19:46 +0100 Subject: [PATCH 08/34] restore global settings in script --- DuckDuckGo/ContentBlockingUpdating.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/DuckDuckGo/ContentBlockingUpdating.swift b/DuckDuckGo/ContentBlockingUpdating.swift index 95002bca9e..95e70dbcf6 100644 --- a/DuckDuckGo/ContentBlockingUpdating.swift +++ b/DuckDuckGo/ContentBlockingUpdating.swift @@ -87,6 +87,7 @@ public final class ContentBlockingUpdating { .combineLatest(onNotificationWithInitial(PreserveLogins.Notifications.loginDetectionStateChanged), combine) .combineLatest(onNotificationWithInitial(AppUserDefaults.Notifications.doNotSellStatusChange), combine) .combineLatest(onNotificationWithInitial(AppUserDefaults.Notifications.autofillEnabledChange), combine) + .combineLatest(onNotificationWithInitial(AppUserDefaults.Notifications.textSizeChange), combine) .combineLatest(onNotificationWithInitial(AppUserDefaults.Notifications.didVerifyInternalUser), combine) .combineLatest(onNotificationWithInitial(ConfigurationManager.didUpdateTrackerDependencies) .receive(on: DispatchQueue.main), combine) From 6bee1cea9086a70fe96bfcc701855107881f6115 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Fri, 25 Oct 2024 22:59:22 +0100 Subject: [PATCH 09/34] extract code into own files and tweakk UI --- Core/UserDefaultsPropertyWrapper.swift | 2 + DuckDuckGo.xcodeproj/project.pbxproj | 12 ++ DuckDuckGo/DomainTextZoomStorage.swift | 17 ++- DuckDuckGo/MainViewController.swift | 14 +- .../TabViewController+TextZoomEditor.swift | 43 ++++++ DuckDuckGo/TabViewController.swift | 3 +- ...bViewControllerBrowsingMenuExtension.swift | 4 +- DuckDuckGo/TextZoomController.swift | 128 ------------------ DuckDuckGo/TextZoomEditorModel.swift | 58 ++++++++ DuckDuckGo/TextZoomEditorView.swift | 91 +++++++++++++ DuckDuckGo/UserText.swift | 9 +- DuckDuckGo/en.lproj/Localizable.strings | 5 +- 12 files changed, 245 insertions(+), 141 deletions(-) create mode 100644 DuckDuckGo/TabViewController+TextZoomEditor.swift create mode 100644 DuckDuckGo/TextZoomEditorModel.swift create mode 100644 DuckDuckGo/TextZoomEditorView.swift diff --git a/Core/UserDefaultsPropertyWrapper.swift b/Core/UserDefaultsPropertyWrapper.swift index 2e119e09df..22cebfc96d 100644 --- a/Core/UserDefaultsPropertyWrapper.swift +++ b/Core/UserDefaultsPropertyWrapper.swift @@ -181,6 +181,8 @@ public struct UserDefaultsWrapper { case duckPlayerPixelExperimentLastVideoIDRendered = "com.duckduckgo.ios.duckplayer.pixel.experiment.last.videoID.rendered.v2" case duckPlayerPixelExperimentOverride = "com.duckduckgo.ios.duckplayer.pixel.experiment.override.v2" + // Domain specific text zoom + case domainTextZoomStorage = "com.duckduckgo.ios.domainTextZoomStorage" } private let key: Key diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index edbd36e7e6..bc35f60f8c 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -423,6 +423,9 @@ 851672D12BED1FC900592F24 /* AutocompleteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851672D02BED1FC900592F24 /* AutocompleteView.swift */; }; 851672D32BED23FE00592F24 /* AutocompleteViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851672D22BED23FE00592F24 /* AutocompleteViewModel.swift */; }; 8517D98B221783A0006A8DD0 /* FindInPage.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8517D98A221783A0006A8DD0 /* FindInPage.xcassets */; }; + 851A373A2CCC437400CF190B /* TextZoomEditorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851A37392CCC437400CF190B /* TextZoomEditorModel.swift */; }; + 851A373C2CCC439E00CF190B /* TextZoomEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851A373B2CCC439E00CF190B /* TextZoomEditorView.swift */; }; + 851A373E2CCC476F00CF190B /* TabViewController+TextZoomEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851A373D2CCC476F00CF190B /* TabViewController+TextZoomEditor.swift */; }; 851B1283221FE65E004781BC /* ImproveOnboardingExperiment1Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851B1281221FE64E004781BC /* ImproveOnboardingExperiment1Tests.swift */; }; 851B128822200575004781BC /* Onboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851B128722200575004781BC /* Onboarding.swift */; }; 851B12CC22369931004781BC /* AtbAndVariantCleanup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850250B220D803F4002199C7 /* AtbAndVariantCleanup.swift */; }; @@ -1718,6 +1721,9 @@ 851672D02BED1FC900592F24 /* AutocompleteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocompleteView.swift; sourceTree = ""; }; 851672D22BED23FE00592F24 /* AutocompleteViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocompleteViewModel.swift; sourceTree = ""; }; 8517D98A221783A0006A8DD0 /* FindInPage.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = FindInPage.xcassets; sourceTree = ""; }; + 851A37392CCC437400CF190B /* TextZoomEditorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextZoomEditorModel.swift; sourceTree = ""; }; + 851A373B2CCC439E00CF190B /* TextZoomEditorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextZoomEditorView.swift; sourceTree = ""; }; + 851A373D2CCC476F00CF190B /* TabViewController+TextZoomEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TabViewController+TextZoomEditor.swift"; sourceTree = ""; }; 851B1281221FE64E004781BC /* ImproveOnboardingExperiment1Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImproveOnboardingExperiment1Tests.swift; sourceTree = ""; }; 851B128722200575004781BC /* Onboarding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Onboarding.swift; sourceTree = ""; }; 851B128B2220483A004781BC /* OnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewController.swift; sourceTree = ""; }; @@ -4567,7 +4573,10 @@ isa = PBXGroup; children = ( 85D3FF2A2CC941C100487724 /* DomainTextZoomStorage.swift */, + 851A373D2CCC476F00CF190B /* TabViewController+TextZoomEditor.swift */, 859DA3312CCAC0A300C90694 /* TextZoomController.swift */, + 851A37392CCC437400CF190B /* TextZoomEditorModel.swift */, + 851A373B2CCC439E00CF190B /* TextZoomEditorView.swift */, 85147CB52CCA755300677835 /* TextZoomLevel.swift */, ); name = TextZoom; @@ -7759,6 +7768,7 @@ 980891A32237146B00313A70 /* Feedback.swift in Sources */, F1D796F01E7B07610019D451 /* BookmarksViewControllerCells.swift in Sources */, 9F9EE4D42C37BB1300D4118E /* OnboardingView+Landing.swift in Sources */, + 851A373C2CCC439E00CF190B /* TextZoomEditorView.swift in Sources */, 85058369219F424500ED4EDB /* UIColorExtension.swift in Sources */, BDE219E62C406D19005D5884 /* PrivacyProDataReporting.swift in Sources */, D6E83C312B1EA309006C8AFB /* SettingsCell.swift in Sources */, @@ -7820,6 +7830,7 @@ EE4BE0092A740BED00CD6AA8 /* ClearTextField.swift in Sources */, 56D060282C380D83003BAEB5 /* OnboardingSuggestedSearchesProvider.swift in Sources */, F44D279C27F331BB0037F371 /* AutofillLoginPromptView.swift in Sources */, + 851A373A2CCC437400CF190B /* TextZoomEditorModel.swift in Sources */, C1EA86622C74CB8B00E8604D /* SyncPromoViewModel.swift in Sources */, F1FDC9302BF4E0B3006B1435 /* SubscriptionEnvironment+Default.swift in Sources */, CBD4F13E279EBFAB00B20FD7 /* HomeMessageView.swift in Sources */, @@ -7840,6 +7851,7 @@ 85864FBC24D31EF300E756FF /* SuggestionTrayViewController.swift in Sources */, D64648AF2B5993890033090B /* SubscriptionEmailViewModel.swift in Sources */, 1EF24235273BB9D200DE3D02 /* IntervalSlider.swift in Sources */, + 851A373E2CCC476F00CF190B /* TabViewController+TextZoomEditor.swift in Sources */, F1D796EE1E7AF2EB0019D451 /* UIViewControllerExtension.swift in Sources */, 1EE411F12857C3640003FE64 /* TrackerAnimationImageProvider.swift in Sources */, 1E7A711C2934EEBC00B7EA19 /* OmniBarNotification.swift in Sources */, diff --git a/DuckDuckGo/DomainTextZoomStorage.swift b/DuckDuckGo/DomainTextZoomStorage.swift index b461d2f81d..43119e073b 100644 --- a/DuckDuckGo/DomainTextZoomStorage.swift +++ b/DuckDuckGo/DomainTextZoomStorage.swift @@ -18,17 +18,19 @@ // import Foundation +import Core +import Common protocol DomainTextZoomStoring { func textZoomLevelForDomain(_ domain: String) -> TextZoomLevel? func set(textZoomLevel: TextZoomLevel, forDomain domain: String) - func resetTextZoomLevels(_ excludingDomains: [String]) + func resetTextZoomLevels(excludingDomains: [String]) } class DomainTextZoomStorage: DomainTextZoomStoring { - // TODO persist this - var textZoomLevels: [String: Int] = [:] + @UserDefaultsWrapper(key: .domainTextZoomStorage, defaultValue: [:]) + var textZoomLevels: [String: Int] func textZoomLevelForDomain(_ domain: String) -> TextZoomLevel? { guard let zoomLevel = textZoomLevels[domain] else { @@ -41,9 +43,12 @@ class DomainTextZoomStorage: DomainTextZoomStoring { textZoomLevels[domain] = textZoomLevel.rawValue } - func resetTextZoomLevels(_ excludingDomains: [String]) { - textZoomLevels = textZoomLevels.filter { - !excludingDomains.contains($0.key) + func resetTextZoomLevels(excludingDomains: [String]) { + let tld = TLD() + textZoomLevels = textZoomLevels.filter { level in + excludingDomains.contains(where: { + tld.eTLDplus1($0) == level.key + }) } } diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index 4774bc9432..7e25664f57 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -173,6 +173,9 @@ class MainViewController: UIViewController { fatalError("Use init?(code:") } + let preserveLogins: PreserveLogins + let domainTextZoomStorage: DomainTextZoomStoring + var historyManager: HistoryManaging var viewCoordinator: MainViewCoordinator! @@ -197,7 +200,8 @@ class MainViewController: UIViewController { subscriptionFeatureAvailability: SubscriptionFeatureAvailability, voiceSearchHelper: VoiceSearchHelperProtocol, featureFlagger: FeatureFlagger, - domainTextZoomStorage: DomainTextZoomStoring = DomainTextZoomStorage() + domainTextZoomStorage: DomainTextZoomStoring = DomainTextZoomStorage(), + preserveLogins: PreserveLogins = .shared ) { self.bookmarksDatabase = bookmarksDatabase self.bookmarksDatabaseCleaner = bookmarksDatabaseCleaner @@ -233,6 +237,8 @@ class MainViewController: UIViewController { self.statisticsStore = statisticsStore self.subscriptionFeatureAvailability = subscriptionFeatureAvailability self.voiceSearchHelper = voiceSearchHelper + self.domainTextZoomStorage = domainTextZoomStorage + self.preserveLogins = preserveLogins super.init(nibName: nil, bundle: nil) @@ -2658,6 +2664,7 @@ extension MainViewController: AutoClearWorker { fireButtonAnimator.animate { self.tabManager.prepareCurrentTabForDataClearing() self.stopAllOngoingDownloads() + self.forgetTextZoom() self.forgetTabs() await self.forgetData() Instruments.shared.endTimedEvent(for: spid) @@ -2714,6 +2721,11 @@ extension MainViewController: AutoClearWorker { viewCoordinator.omniBar.dismissOnboardingPrivacyIconAnimation() } + private func forgetTextZoom() { + let allowedDomains = preserveLogins.allowedDomains + domainTextZoomStorage.resetTextZoomLevels(excludingDomains: allowedDomains) + } + } extension MainViewController { diff --git a/DuckDuckGo/TabViewController+TextZoomEditor.swift b/DuckDuckGo/TabViewController+TextZoomEditor.swift new file mode 100644 index 0000000000..bbdc7d2e49 --- /dev/null +++ b/DuckDuckGo/TabViewController+TextZoomEditor.swift @@ -0,0 +1,43 @@ +// +// TabViewController+TextZoomEditor.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import UIKit + +extension TabViewController { + + func showTextZoomAdjustment() { + guard let domain = webView.url?.host?.droppingWwwPrefix() else { return } + let controller = TextZoomController( + domain: domain, + storage: domainTextZoomStorage, + defaultTextZoom: appSettings.defaultTextZoomLevel + ) + + controller.modalPresentationStyle = .formSheet + if #available(iOS 16.0, *) { + controller.sheetPresentationController?.detents = [.custom(resolver: { _ in + return 152 + })] + } else { + controller.sheetPresentationController?.detents = [.medium()] + } + present(controller, animated: true) + } + +} diff --git a/DuckDuckGo/TabViewController.swift b/DuckDuckGo/TabViewController.swift index b410b0b1fc..ca043e0f2f 100644 --- a/DuckDuckGo/TabViewController.swift +++ b/DuckDuckGo/TabViewController.swift @@ -971,8 +971,9 @@ class TabViewController: UIViewController { } @objc func onTextSizeChange() { + let domain = TLD().eTLDplus1(webView.url?.host) ?? "" // If the webview returns no host then there won't be a setting for a blank string anyway. - let level = domainTextZoomStorage.textZoomLevelForDomain(webView.url?.host?.droppingWwwPrefix() ?? "") + let level = domainTextZoomStorage.textZoomLevelForDomain(domain) // And if there's no setting for whatever domain is passed in, use the app default ?? appSettings.defaultTextZoomLevel webView.adjustTextSize(level.rawValue) diff --git a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift index 8868446b88..8ce0378e6b 100644 --- a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift +++ b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift @@ -170,10 +170,10 @@ extension TabViewController { } private func buildZoomLevelEntry(forLink link: Link) -> BrowsingMenuEntry { - let domain = link.url.host?.droppingWwwPrefix() ?? "" + let domain = TLD().eTLDplus1(link.url.host) ?? "" let percent = domainTextZoomStorage.textZoomLevelForDomain(domain)?.rawValue ?? appSettings.defaultTextZoomLevel.rawValue - return BrowsingMenuEntry.regular(name: UserText.pageZoomWithPercent(percent), + return BrowsingMenuEntry.regular(name: UserText.textZoomWithPercentMenuItem(percent), image: UIImage(named: "Type-Size-16")!, showNotificationDot: false) { [weak self] in self?.showTextZoomAdjustment() diff --git a/DuckDuckGo/TextZoomController.swift b/DuckDuckGo/TextZoomController.swift index e61830494b..0daf318a0a 100644 --- a/DuckDuckGo/TextZoomController.swift +++ b/DuckDuckGo/TextZoomController.swift @@ -36,131 +36,3 @@ class TextZoomController: UIHostingController { } } - -class TextZoomEditorModel: ObservableObject { - - let domain: String - let storage: DomainTextZoomStoring - - var valueAsPercent: Int { - TextZoomLevel.allCases[value].rawValue - } - - @Published var value: Int = 0 { - didSet { - title = UserText.pageZoomWithPercent(valueAsPercent) - storage.set(textZoomLevel: TextZoomLevel.allCases[value], forDomain: domain) - NotificationCenter.default.post( - name: AppUserDefaults.Notifications.textSizeChange, - object: nil) - } - } - - @Published var title: String = "" - - init(domain: String, storage: DomainTextZoomStoring, defaultTextZoom: TextZoomLevel) { - self.domain = domain - self.storage = storage - let percent = (storage.textZoomLevelForDomain(domain) ?? defaultTextZoom) - value = TextZoomLevel.allCases.firstIndex(of: percent) ?? 0 - } - - func increment() { - value = min(TextZoomLevel.allCases.count - 1, value + 1) - } - - func decrement() { - value = max(0, value - 1) - } - -} - -struct TextZoomEditorView: View { - - @ObservedObject var model: TextZoomEditorModel - - @Environment(\.dismiss) var dismiss - - @ViewBuilder - func header() -> some View { - ZStack(alignment: .center) { - Text(model.title) - .font(Font(uiFont: .daxHeadline())) - .frame(alignment: .center) - - Button { - dismiss() - } label: { - Text(UserText.navigationTitleDone) - .font(Font(uiFont: .daxHeadline())) - } - .buttonStyle(.plain) - .padding(0) - .frame(maxWidth: .infinity, alignment: .trailing) - } - .padding(16) - } - - func slider() -> some View { - HStack { - Button { - model.decrement() - } label: { - Image("Font-Smaller-24") - } - .foregroundColor(Color(designSystemColor: .textPrimary)) - .padding(12) - - IntervalSliderRepresentable( - value: $model.value, - steps: TextZoomLevel.allCases.map { $0.rawValue }) - .padding(.vertical) - - Button { - model.increment() - } label: { - Image("Font-Larger-24") - } - .foregroundColor(Color(designSystemColor: .textPrimary)) - .padding(12) - } - .background(RoundedRectangle(cornerRadius: 8).foregroundColor(Color(designSystemColor: .surface))) - .padding(16) - - } - - var body: some View { - VStack { - header() - Spacer() - slider() - Spacer() - } - .frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, maxHeight: .infinity) - .background(Color(designSystemColor: .background)) - } - -} - -extension TabViewController { - - func showTextZoomAdjustment() { - guard let domain = webView.url?.host?.droppingWwwPrefix() else { return } - let controller = TextZoomController( - domain: domain, - storage: domainTextZoomStorage, - defaultTextZoom: appSettings.defaultTextZoomLevel - ) - - controller.modalPresentationStyle = .formSheet - if #available(iOS 16.0, *) { - controller.sheetPresentationController?.detents = [.custom(resolver: { _ in - return 180 - })] - } else { - controller.sheetPresentationController?.detents = [.medium()] - } - present(controller, animated: true) - } - -} diff --git a/DuckDuckGo/TextZoomEditorModel.swift b/DuckDuckGo/TextZoomEditorModel.swift new file mode 100644 index 0000000000..b807139172 --- /dev/null +++ b/DuckDuckGo/TextZoomEditorModel.swift @@ -0,0 +1,58 @@ +// +// TextZoomEditorModel.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import SwiftUI + +class TextZoomEditorModel: ObservableObject { + + let domain: String + let storage: DomainTextZoomStoring + + var valueAsPercent: Int { + TextZoomLevel.allCases[value].rawValue + } + + @Published var value: Int = 0 { + didSet { + title = UserText.textZoomWithParcentSheetTitle(valueAsPercent) + storage.set(textZoomLevel: TextZoomLevel.allCases[value], forDomain: domain) + NotificationCenter.default.post( + name: AppUserDefaults.Notifications.textSizeChange, + object: nil) + } + } + + @Published var title: String = "" + + init(domain: String, storage: DomainTextZoomStoring, defaultTextZoom: TextZoomLevel) { + self.domain = domain + self.storage = storage + let percent = (storage.textZoomLevelForDomain(domain) ?? defaultTextZoom) + value = TextZoomLevel.allCases.firstIndex(of: percent) ?? 0 + } + + func increment() { + value = min(TextZoomLevel.allCases.count - 1, value + 1) + } + + func decrement() { + value = max(0, value - 1) + } + +} diff --git a/DuckDuckGo/TextZoomEditorView.swift b/DuckDuckGo/TextZoomEditorView.swift new file mode 100644 index 0000000000..ded6b63bf1 --- /dev/null +++ b/DuckDuckGo/TextZoomEditorView.swift @@ -0,0 +1,91 @@ +// +// TextZoomEditorView.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import SwiftUI + +struct TextZoomEditorView: View { + + @ObservedObject var model: TextZoomEditorModel + + @Environment(\.dismiss) var dismiss + + @ViewBuilder + func header() -> some View { + ZStack(alignment: .center) { + Text(model.title) + .font(Font(uiFont: .daxHeadline())) + .frame(alignment: .center) + + Button { + dismiss() + } label: { + Text(UserText.navigationTitleDone) + .font(Font(uiFont: .daxHeadline())) + } + .buttonStyle(.plain) + .padding(0) + .frame(maxWidth: .infinity, alignment: .trailing) + } + .padding(.horizontal, 16) + .frame(height: 56) + } + + func slider() -> some View { + HStack(spacing: 6) { + Button { + model.decrement() + } label: { + Image("Font-Smaller-24") + } + .foregroundColor(Color(designSystemColor: .textPrimary)) + .padding(12) + .padding(.leading, 8) + + IntervalSliderRepresentable( + value: $model.value, + steps: TextZoomLevel.allCases.map { $0.rawValue }) + .padding(.vertical) + + Button { + model.increment() + } label: { + Image("Font-Larger-24") + } + .foregroundColor(Color(designSystemColor: .textPrimary)) + .padding(12) + .padding(.trailing, 8) + } + .background(RoundedRectangle(cornerRadius: 8).foregroundColor(Color(designSystemColor: .surface))) + .frame(height: 64) + .padding(.horizontal, 16) + + } + + var body: some View { + VStack { + header() + Spacer() + slider() + Spacer() + } + .frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, maxHeight: .infinity) + .background(Color(designSystemColor: .background)) + } + +} diff --git a/DuckDuckGo/UserText.swift b/DuckDuckGo/UserText.swift index 79165717aa..92abf6ecfd 100644 --- a/DuckDuckGo/UserText.swift +++ b/DuckDuckGo/UserText.swift @@ -358,8 +358,13 @@ public struct UserText { } public static let messageAllFilesDeleted = NSLocalizedString("downloads.message.all-files-deleted", value: "All files deleted", comment: "Message confirming that all files on the downloads list have been deleted") - public static func pageZoomWithPercent(_ percent: Int) -> String { - let message = NSLocalizedString("action.show-page-zoom", value: "Zoom Text (%d%%)", comment: "Zoom text menu item showing currently set zoom level as a percent. '%d' represets the number that will be used, e.g. 56") + public static func textZoomWithPercentMenuItem(_ percent: Int) -> String { + let message = NSLocalizedString("action.text-zoom-sheet-menu-item", value: "Zoom Text (%d%%)", comment: "Zoom text menu item showing currently set zoom level as a percent. '%d' represets the number that will be used, e.g. 56") + return message.format(arguments: percent) + } + + public static func textZoomWithParcentSheetTitle(_ percent: Int) -> String { + let message = NSLocalizedString("action.text-zoom-sheet-title", value: "Zoom (%d%%)", comment: "Zoom text sheet title showing currently set zoom level as a percent. '%d' represets the number that will be used, e.g. 56") return message.format(arguments: percent) } diff --git a/DuckDuckGo/en.lproj/Localizable.strings b/DuckDuckGo/en.lproj/Localizable.strings index 47b43cce44..9140355480 100644 --- a/DuckDuckGo/en.lproj/Localizable.strings +++ b/DuckDuckGo/en.lproj/Localizable.strings @@ -14,7 +14,10 @@ "action.ok" = "OK"; /* Zoom text menu item showing currently set zoom level as a percent. '%d' represets the number that will be used, e.g. 56 */ -"action.show-page-zoom" = "Zoom Text (%d%%)"; +"action.text-zoom-sheet-menu-item" = "Zoom Text (%d%%)"; + +/* Zoom text sheet title showing currently set zoom level as a percent. '%d' represets the number that will be used, e.g. 56 */ +"action.text-zoom-sheet-title" = "Zoom (%d%%)"; /* Add action - button shown in alert */ "action.title.add" = "Add"; From 10b121e6087d74062664c89b7869b6f91278a0ef Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Mon, 28 Oct 2024 16:22:50 +0000 Subject: [PATCH 10/34] Design check in feedback and enable on iPad --- DuckDuckGo/IntervalSlider.swift | 2 +- DuckDuckGo/SettingsAccessibilityView.swift | 8 +++----- DuckDuckGo/TabViewController+TextZoomEditor.swift | 4 +++- .../TabViewControllerBrowsingMenuExtension.swift | 2 +- DuckDuckGo/TextZoomEditorModel.swift | 2 +- DuckDuckGo/UserText.swift | 11 ++++------- DuckDuckGo/en.lproj/Localizable.strings | 8 ++++---- 7 files changed, 17 insertions(+), 20 deletions(-) diff --git a/DuckDuckGo/IntervalSlider.swift b/DuckDuckGo/IntervalSlider.swift index 0fcb03d09e..e338daae7f 100644 --- a/DuckDuckGo/IntervalSlider.swift +++ b/DuckDuckGo/IntervalSlider.swift @@ -84,7 +84,7 @@ struct IntervalSliderRepresentable: UIViewRepresentable { func makeUIView(context: Context) -> IntervalSlider { let slider = IntervalSlider(frame: .zero) slider.minimumTrackTintColor = UIColor(designSystemColor: .accent) - slider.maximumTrackTintColor = UIColor(designSystemColor: .buttonsSecondaryFillDefault) + slider.maximumTrackTintColor = UIColor.systemGray3 slider.steps = steps slider.minimumValue = Float(0) slider.maximumValue = Float(steps.count - 1) diff --git a/DuckDuckGo/SettingsAccessibilityView.swift b/DuckDuckGo/SettingsAccessibilityView.swift index aaf5952bbf..6c330bdb21 100644 --- a/DuckDuckGo/SettingsAccessibilityView.swift +++ b/DuckDuckGo/SettingsAccessibilityView.swift @@ -30,11 +30,9 @@ struct SettingsAccessibilityView: View { List { Section { // Text Size - if viewModel.state.textSize.enabled { - SettingsPickerCellView(label: UserText.settingsText, - options: TextZoomLevel.allCases, - selectedOption: viewModel.textZoomLevelBinding) - } + SettingsPickerCellView(label: UserText.settingsText, + options: TextZoomLevel.allCases, + selectedOption: viewModel.textZoomLevelBinding) } Section(footer: Text(UserText.voiceSearchFooter)) { diff --git a/DuckDuckGo/TabViewController+TextZoomEditor.swift b/DuckDuckGo/TabViewController+TextZoomEditor.swift index bbdc7d2e49..cd8646b848 100644 --- a/DuckDuckGo/TabViewController+TextZoomEditor.swift +++ b/DuckDuckGo/TabViewController+TextZoomEditor.swift @@ -18,11 +18,12 @@ // import UIKit +import Common extension TabViewController { func showTextZoomAdjustment() { - guard let domain = webView.url?.host?.droppingWwwPrefix() else { return } + guard let domain = TLD().eTLDplus1(webView.url?.host) else { return } let controller = TextZoomController( domain: domain, storage: domainTextZoomStorage, @@ -37,6 +38,7 @@ extension TabViewController { } else { controller.sheetPresentationController?.detents = [.medium()] } + present(controller, animated: true) } diff --git a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift index 8ce0378e6b..b42a500d34 100644 --- a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift +++ b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift @@ -173,7 +173,7 @@ extension TabViewController { let domain = TLD().eTLDplus1(link.url.host) ?? "" let percent = domainTextZoomStorage.textZoomLevelForDomain(domain)?.rawValue ?? appSettings.defaultTextZoomLevel.rawValue - return BrowsingMenuEntry.regular(name: UserText.textZoomWithPercentMenuItem(percent), + return BrowsingMenuEntry.regular(name: UserText.textZoomMenuItem, image: UIImage(named: "Type-Size-16")!, showNotificationDot: false) { [weak self] in self?.showTextZoomAdjustment() diff --git a/DuckDuckGo/TextZoomEditorModel.swift b/DuckDuckGo/TextZoomEditorModel.swift index b807139172..b55bc2f0ca 100644 --- a/DuckDuckGo/TextZoomEditorModel.swift +++ b/DuckDuckGo/TextZoomEditorModel.swift @@ -30,7 +30,7 @@ class TextZoomEditorModel: ObservableObject { @Published var value: Int = 0 { didSet { - title = UserText.textZoomWithParcentSheetTitle(valueAsPercent) + title = UserText.textZoomWithPercentSheetTitle(TextZoomLevel.allCases[value].rawValue) storage.set(textZoomLevel: TextZoomLevel.allCases[value], forDomain: domain) NotificationCenter.default.post( name: AppUserDefaults.Notifications.textSizeChange, diff --git a/DuckDuckGo/UserText.swift b/DuckDuckGo/UserText.swift index 92abf6ecfd..c32a5d6884 100644 --- a/DuckDuckGo/UserText.swift +++ b/DuckDuckGo/UserText.swift @@ -358,13 +358,10 @@ public struct UserText { } public static let messageAllFilesDeleted = NSLocalizedString("downloads.message.all-files-deleted", value: "All files deleted", comment: "Message confirming that all files on the downloads list have been deleted") - public static func textZoomWithPercentMenuItem(_ percent: Int) -> String { - let message = NSLocalizedString("action.text-zoom-sheet-menu-item", value: "Zoom Text (%d%%)", comment: "Zoom text menu item showing currently set zoom level as a percent. '%d' represets the number that will be used, e.g. 56") - return message.format(arguments: percent) - } + public static let textZoomMenuItem = NSLocalizedString("action.text-zoom-sheet-menu-item", value: "Zoom", comment: "Text zoom menu item") - public static func textZoomWithParcentSheetTitle(_ percent: Int) -> String { - let message = NSLocalizedString("action.text-zoom-sheet-title", value: "Zoom (%d%%)", comment: "Zoom text sheet title showing currently set zoom level as a percent. '%d' represets the number that will be used, e.g. 56") + public static func textZoomWithPercentSheetTitle(_ percent: Int) -> String { + let message = NSLocalizedString("action.text-zoom-sheet-title", value: "Zoom Text (%d%%)", comment: "Zoom text sheet title showing currently set zoom level as a percent. '%d' represets the number that will be used, e.g. 56") return message.format(arguments: percent) } @@ -1064,7 +1061,7 @@ But if you *do* want a peek under the hood, you can find more information about public static let settingsTheme = NSLocalizedString("settings.theme", value: "Theme", comment: "Settings screen cell text for theme") public static let settingsIcon = NSLocalizedString("settings.icon", value: "App Icon", comment: "Settings screen cell text for app icon selection") public static let settingsFirebutton = NSLocalizedString("settings.firebutton", value: "Fire Button Animation", comment: "Settings screen cell text for fire button animation") - public static let settingsText = NSLocalizedString("settings.text.size", value: "Zoom Text", comment: "Settings screen cell text for text size") + public static let settingsText = NSLocalizedString("settings.text.size", value: "Default Zoom Text", comment: "Settings screen cell text for text size") public static let settingsAddressBar = NSLocalizedString("settings.address.bar", value: "Address Bar Position", comment: "Settings screen cell text for addess bar position") public static let settingsFullURL = NSLocalizedString("settings.address.full.url", value: "Show Full Site Address", comment: "Settings screen cell title for toggling full URL visibility in address bar") diff --git a/DuckDuckGo/en.lproj/Localizable.strings b/DuckDuckGo/en.lproj/Localizable.strings index 9140355480..f59d19b1f7 100644 --- a/DuckDuckGo/en.lproj/Localizable.strings +++ b/DuckDuckGo/en.lproj/Localizable.strings @@ -13,11 +13,11 @@ /* Button label for OK action */ "action.ok" = "OK"; -/* Zoom text menu item showing currently set zoom level as a percent. '%d' represets the number that will be used, e.g. 56 */ -"action.text-zoom-sheet-menu-item" = "Zoom Text (%d%%)"; +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Zoom"; /* Zoom text sheet title showing currently set zoom level as a percent. '%d' represets the number that will be used, e.g. 56 */ -"action.text-zoom-sheet-title" = "Zoom (%d%%)"; +"action.text-zoom-sheet-title" = "Zoom Text (%d%%)"; /* Add action - button shown in alert */ "action.title.add" = "Add"; @@ -2356,7 +2356,7 @@ But if you *do* want a peek under the hood, you can find more information about "settings.sync" = "Sync & Backup"; /* Settings screen cell text for text size */ -"settings.text.size" = "Zoom Text"; +"settings.text.size" = "Default Zoom Text"; /* Settings screen cell text for theme */ "settings.theme" = "Theme"; From e31637e4737e5dc49e9237fa538e3c27ec18904b Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Tue, 29 Oct 2024 12:03:43 +0000 Subject: [PATCH 11/34] move forget text zoom to right place --- DuckDuckGo/MainViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index 7e25664f57..ce45b91b7a 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -2643,6 +2643,7 @@ extension MainViewController: AutoClearWorker { self.bookmarksDatabaseCleaner?.cleanUpDatabaseNow() } + self.forgetTextZoom() await historyManager.removeAllHistory() self.clearInProgress = false @@ -2664,7 +2665,6 @@ extension MainViewController: AutoClearWorker { fireButtonAnimator.animate { self.tabManager.prepareCurrentTabForDataClearing() self.stopAllOngoingDownloads() - self.forgetTextZoom() self.forgetTabs() await self.forgetData() Instruments.shared.endTimedEvent(for: spid) From e1b6cd3382a41d503ad613d4b6b1d107d0026764 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Wed, 30 Oct 2024 00:20:21 +0000 Subject: [PATCH 12/34] disable on ipad --- DuckDuckGo/SettingsAccessibilityView.swift | 8 +++++--- DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/DuckDuckGo/SettingsAccessibilityView.swift b/DuckDuckGo/SettingsAccessibilityView.swift index 6c330bdb21..aaf5952bbf 100644 --- a/DuckDuckGo/SettingsAccessibilityView.swift +++ b/DuckDuckGo/SettingsAccessibilityView.swift @@ -30,9 +30,11 @@ struct SettingsAccessibilityView: View { List { Section { // Text Size - SettingsPickerCellView(label: UserText.settingsText, - options: TextZoomLevel.allCases, - selectedOption: viewModel.textZoomLevelBinding) + if viewModel.state.textSize.enabled { + SettingsPickerCellView(label: UserText.settingsText, + options: TextZoomLevel.allCases, + selectedOption: viewModel.textZoomLevelBinding) + } } Section(footer: Text(UserText.voiceSearchFooter)) { diff --git a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift index b42a500d34..688ae4aaad 100644 --- a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift +++ b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift @@ -156,7 +156,9 @@ extension TabViewController { entries.append(entry) } - entries.append(self.buildZoomLevelEntry(forLink: link)) + if !isPad { + entries.append(self.buildZoomLevelEntry(forLink: link)) + } let title = self.tabModel.isDesktop ? UserText.actionRequestMobileSite : UserText.actionRequestDesktopSite let image = self.tabModel.isDesktop ? UIImage(named: "Device-Mobile-16")! : UIImage(named: "Device-Desktop-16")! From cb76df36072ff3383a60c4512181cfb9608edca4 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Wed, 30 Oct 2024 16:39:42 +0000 Subject: [PATCH 13/34] add pixels --- Core/PixelEvent.swift | 10 +++++-- DuckDuckGo/SettingsViewModel.swift | 1 + ...bViewControllerBrowsingMenuExtension.swift | 4 +-- DuckDuckGo/TextZoomEditorModel.swift | 29 ++++++++++++++----- DuckDuckGo/TextZoomEditorView.swift | 1 + 5 files changed, 33 insertions(+), 12 deletions(-) diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 0a021242ea..70299cd178 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -80,6 +80,7 @@ extension Pixel { case browsingMenuCopy case browsingMenuPrint case browsingMenuFindInPage + case browsingMenuZoom case browsingMenuDisableProtection case browsingMenuEnableProtection case browsingMenuReportBrokenSite @@ -206,7 +207,9 @@ extension Pixel { case bookmarkExportFailure case textSizeSettingsChanged - + case zoomChangedOnPage + case zoomChangedOnPageDaily + case downloadStarted case downloadStartedDueToUnhandledMIMEType case downloadTriedToPresentPreviewWithoutTab @@ -896,6 +899,7 @@ extension Pixel.Event { case .browsingMenuCopy: return "mb_cp" case .browsingMenuPrint: return "mb_pr" case .browsingMenuFindInPage: return "mb_fp" + case .browsingMenuZoom: return "m_menu_page_zoom_taps" case .browsingMenuDisableProtection: return "mb_wla" case .browsingMenuEnableProtection: return "mb_wlr" case .browsingMenuReportBrokenSite: return "mb_rb" @@ -1024,7 +1028,9 @@ extension Pixel.Event { case .bookmarkExportFailure: return "m_be_e" case .textSizeSettingsChanged: return "m_text_size_settings_changed" - + case .zoomChangedOnPageDaily: return "m_menu_page_zoom_changed_daily" + case .zoomChangedOnPage: return "m_menu_page_zoom_changed" + case .downloadStarted: return "m_download_started" case .downloadStartedDueToUnhandledMIMEType: return "m_download_started_due_to_unhandled_mime_type" case .downloadTriedToPresentPreviewWithoutTab: return "m_download_tried_to_present_preview_without_tab" diff --git a/DuckDuckGo/SettingsViewModel.swift b/DuckDuckGo/SettingsViewModel.swift index 55cad17a38..3df7ba7009 100644 --- a/DuckDuckGo/SettingsViewModel.swift +++ b/DuckDuckGo/SettingsViewModel.swift @@ -263,6 +263,7 @@ final class SettingsViewModel: ObservableObject { set: { newValue in self.appSettings.defaultTextZoomLevel = newValue self.state.textSize.level = newValue + Pixel.fire(pixel: .settingsAccessiblityTextSize) } ) } diff --git a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift index 688ae4aaad..e2731f743f 100644 --- a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift +++ b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift @@ -172,13 +172,11 @@ extension TabViewController { } private func buildZoomLevelEntry(forLink link: Link) -> BrowsingMenuEntry { - let domain = TLD().eTLDplus1(link.url.host) ?? "" - let percent = domainTextZoomStorage.textZoomLevelForDomain(domain)?.rawValue ?? appSettings.defaultTextZoomLevel.rawValue - return BrowsingMenuEntry.regular(name: UserText.textZoomMenuItem, image: UIImage(named: "Type-Size-16")!, showNotificationDot: false) { [weak self] in self?.showTextZoomAdjustment() + Pixel.fire(pixel: .browsingMenuZoom) } } diff --git a/DuckDuckGo/TextZoomEditorModel.swift b/DuckDuckGo/TextZoomEditorModel.swift index b55bc2f0ca..0edce35d77 100644 --- a/DuckDuckGo/TextZoomEditorModel.swift +++ b/DuckDuckGo/TextZoomEditorModel.swift @@ -18,11 +18,13 @@ // import SwiftUI +import Core class TextZoomEditorModel: ObservableObject { let domain: String let storage: DomainTextZoomStoring + let initialValue: TextZoomLevel var valueAsPercent: Int { TextZoomLevel.allCases[value].rawValue @@ -30,11 +32,7 @@ class TextZoomEditorModel: ObservableObject { @Published var value: Int = 0 { didSet { - title = UserText.textZoomWithPercentSheetTitle(TextZoomLevel.allCases[value].rawValue) - storage.set(textZoomLevel: TextZoomLevel.allCases[value], forDomain: domain) - NotificationCenter.default.post( - name: AppUserDefaults.Notifications.textSizeChange, - object: nil) + valueWasSet() } } @@ -43,8 +41,8 @@ class TextZoomEditorModel: ObservableObject { init(domain: String, storage: DomainTextZoomStoring, defaultTextZoom: TextZoomLevel) { self.domain = domain self.storage = storage - let percent = (storage.textZoomLevelForDomain(domain) ?? defaultTextZoom) - value = TextZoomLevel.allCases.firstIndex(of: percent) ?? 0 + self.initialValue = (storage.textZoomLevelForDomain(domain) ?? defaultTextZoom) + value = TextZoomLevel.allCases.firstIndex(of: initialValue) ?? 0 } func increment() { @@ -55,4 +53,21 @@ class TextZoomEditorModel: ObservableObject { value = max(0, value - 1) } + private func valueWasSet() { + title = UserText.textZoomWithPercentSheetTitle(TextZoomLevel.allCases[value].rawValue) + storage.set(textZoomLevel: TextZoomLevel.allCases[value], forDomain: domain) + NotificationCenter.default.post( + name: AppUserDefaults.Notifications.textSizeChange, + object: nil) + DailyPixel.fire(pixel: .zoomChangedOnPageDaily) + } + + func onDismiss() { + guard initialValue.rawValue != TextZoomLevel.allCases[value].rawValue else { return } + Pixel.fire(.zoomChangedOnPage, withAdditionalParameters: [ + "text_size_initial": String(initialValue.rawValue), + "text_size_updated": String(TextZoomLevel.allCases[value].rawValue), + ]) + } + } diff --git a/DuckDuckGo/TextZoomEditorView.swift b/DuckDuckGo/TextZoomEditorView.swift index ded6b63bf1..35cee26a2d 100644 --- a/DuckDuckGo/TextZoomEditorView.swift +++ b/DuckDuckGo/TextZoomEditorView.swift @@ -33,6 +33,7 @@ struct TextZoomEditorView: View { .frame(alignment: .center) Button { + model.onDismiss() dismiss() } label: { Text(UserText.navigationTitleDone) From 8a5c093b19afa1707c64c59d9e4e3b2bd1178101 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Wed, 30 Oct 2024 21:59:40 +0000 Subject: [PATCH 14/34] swift lint and a compile error --- DuckDuckGo/TextZoomLevel.swift | 2 +- DuckDuckGoTests/AppSettingsMock.swift | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/DuckDuckGo/TextZoomLevel.swift b/DuckDuckGo/TextZoomLevel.swift index 09ef71689d..ef0ba39812 100644 --- a/DuckDuckGo/TextZoomLevel.swift +++ b/DuckDuckGo/TextZoomLevel.swift @@ -1,5 +1,5 @@ // -// ZoomLevel.swift +// TextZoomLevel.swift // DuckDuckGo // // Copyright © 2024 DuckDuckGo. All rights reserved. diff --git a/DuckDuckGoTests/AppSettingsMock.swift b/DuckDuckGoTests/AppSettingsMock.swift index a8c3db67bf..5b25d81547 100644 --- a/DuckDuckGoTests/AppSettingsMock.swift +++ b/DuckDuckGoTests/AppSettingsMock.swift @@ -22,6 +22,7 @@ import Foundation @testable import DuckDuckGo class AppSettingsMock: AppSettings { + var defaultTextZoomLevel: DuckDuckGo.TextZoomLevel = .percent100 var recentlyVisitedSites: Bool = false From 836e30bae20fc60934cde6b7261d7949096fa1c7 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 31 Oct 2024 10:25:09 +0000 Subject: [PATCH 15/34] use correct pixel parameters --- DuckDuckGo/SettingsViewModel.swift | 5 ++++- DuckDuckGo/TextZoomEditorModel.swift | 4 ++-- DuckDuckGoTests/OnboardingNavigationDelegateTests.swift | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/DuckDuckGo/SettingsViewModel.swift b/DuckDuckGo/SettingsViewModel.swift index 3df7ba7009..d28235c0de 100644 --- a/DuckDuckGo/SettingsViewModel.swift +++ b/DuckDuckGo/SettingsViewModel.swift @@ -261,9 +261,12 @@ final class SettingsViewModel: ObservableObject { Binding( get: { self.state.textSize.level }, set: { newValue in + Pixel.fire(.settingsAccessiblityTextSize, withAdditionalParameters: [ + PixelParameters.textSizeInitial: String(self.appSettings.defaultTextZoomLevel.rawValue), + PixelParameters.textSizeUpdated: String(newValue.rawValue), + ]) self.appSettings.defaultTextZoomLevel = newValue self.state.textSize.level = newValue - Pixel.fire(pixel: .settingsAccessiblityTextSize) } ) } diff --git a/DuckDuckGo/TextZoomEditorModel.swift b/DuckDuckGo/TextZoomEditorModel.swift index 0edce35d77..ef355060b1 100644 --- a/DuckDuckGo/TextZoomEditorModel.swift +++ b/DuckDuckGo/TextZoomEditorModel.swift @@ -65,8 +65,8 @@ class TextZoomEditorModel: ObservableObject { func onDismiss() { guard initialValue.rawValue != TextZoomLevel.allCases[value].rawValue else { return } Pixel.fire(.zoomChangedOnPage, withAdditionalParameters: [ - "text_size_initial": String(initialValue.rawValue), - "text_size_updated": String(TextZoomLevel.allCases[value].rawValue), + PixelParameters.textSizeInitial: String(initialValue.rawValue), + PixelParameters.textSizeUpdated: String(TextZoomLevel.allCases[value].rawValue), ]) } diff --git a/DuckDuckGoTests/OnboardingNavigationDelegateTests.swift b/DuckDuckGoTests/OnboardingNavigationDelegateTests.swift index 7ccd6d49b9..68c0c56af6 100644 --- a/DuckDuckGoTests/OnboardingNavigationDelegateTests.swift +++ b/DuckDuckGoTests/OnboardingNavigationDelegateTests.swift @@ -78,6 +78,7 @@ final class OnboardingNavigationDelegateTests: XCTestCase { contextualOnboardingPixelReporter: onboardingPixelReporter, subscriptionFeatureAvailability: SubscriptionFeatureAvailabilityMock.enabled, voiceSearchHelper: MockVoiceSearchHelper(isSpeechRecognizerAvailable: true, voiceSearchEnabled: true), + featureFlagger: MockFeatureFlagger(), subscriptionCookieManager: SubscriptionCookieManagerMock()) let window = UIWindow(frame: UIScreen.main.bounds) window.rootViewController = UIViewController() From fe7329a61ca15cb84d4817a34cf7597e2e6f2393 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 31 Oct 2024 10:36:53 +0000 Subject: [PATCH 16/34] add mock domain text level storage --- DuckDuckGo.xcodeproj/project.pbxproj | 4 +++ .../MockDomainTextZoomStorage.swift | 35 +++++++++++++++++++ DuckDuckGoTests/MockTabDelegate.swift | 1 + .../OnboardingDaxFavouritesTests.swift | 1 + 4 files changed, 41 insertions(+) create mode 100644 DuckDuckGoTests/MockDomainTextZoomStorage.swift diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index a5e62bd4dc..fac98cbb88 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -532,6 +532,7 @@ 85AE668E2097206E0014CF04 /* NotificationView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 85AE668D2097206E0014CF04 /* NotificationView.xib */; }; 85AE6690209724120014CF04 /* NotificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AE668F209724120014CF04 /* NotificationView.swift */; }; 85AFA1212B45D14F0028A504 /* BookmarksMigrationAssertionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AFA1202B45D14F0028A504 /* BookmarksMigrationAssertionTests.swift */; }; + 85B49AFD2CD392ED007FAA2A /* MockDomainTextZoomStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85B49AFC2CD392ED007FAA2A /* MockDomainTextZoomStorage.swift */; }; 85B9814E2B5EB618009AC9A6 /* SwipeTabsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85B9814D2B5EB618009AC9A6 /* SwipeTabsCoordinator.swift */; }; 85B9CB8921AEBDD5009001F1 /* FavoriteHomeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85B9CB8821AEBDD5009001F1 /* FavoriteHomeCell.swift */; }; 85BA58551F34F49E00C6E8CA /* AppUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85BA58541F34F49E00C6E8CA /* AppUserDefaults.swift */; }; @@ -1834,6 +1835,7 @@ 85AE668D2097206E0014CF04 /* NotificationView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NotificationView.xib; sourceTree = ""; }; 85AE668F209724120014CF04 /* NotificationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationView.swift; sourceTree = ""; }; 85AFA1202B45D14F0028A504 /* BookmarksMigrationAssertionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksMigrationAssertionTests.swift; sourceTree = ""; }; + 85B49AFC2CD392ED007FAA2A /* MockDomainTextZoomStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDomainTextZoomStorage.swift; sourceTree = ""; }; 85B9814D2B5EB618009AC9A6 /* SwipeTabsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeTabsCoordinator.swift; sourceTree = ""; }; 85B9CB8821AEBDD5009001F1 /* FavoriteHomeCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteHomeCell.swift; sourceTree = ""; }; 85BA58541F34F49E00C6E8CA /* AppUserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppUserDefaults.swift; sourceTree = ""; }; @@ -6043,6 +6045,7 @@ 9F69331C2C5A191400CD6A5D /* MockTutorialSettings.swift */, 852409302C78030D00CB28FC /* MockUsageSegmentation.swift */, 4B27FBB72C93F53B007E21A7 /* MockPersistentPixel.swift */, + 85B49AFC2CD392ED007FAA2A /* MockDomainTextZoomStorage.swift */, ); name = Mocks; sourceTree = ""; @@ -7971,6 +7974,7 @@ 83EDCC411F86B89C005CDFCD /* StatisticsLoaderTests.swift in Sources */, 564DE4572C4150E600D23241 /* NewTabPageControllerDaxDialogTests.swift in Sources */, C14882E327F20D9A00D59F0C /* BookmarksExporterTests.swift in Sources */, + 85B49AFD2CD392ED007FAA2A /* MockDomainTextZoomStorage.swift in Sources */, 85C29708247BDD060063A335 /* DaxDialogsBrowsingSpecTests.swift in Sources */, 9FE05CF12C36468A00D9046B /* OnboardingPixelReporterTests.swift in Sources */, 9FDEC7B42C8FD62F00C7A692 /* OnboardingAddressBarPositionPickerViewModelTests.swift in Sources */, diff --git a/DuckDuckGoTests/MockDomainTextZoomStorage.swift b/DuckDuckGoTests/MockDomainTextZoomStorage.swift new file mode 100644 index 0000000000..328d321368 --- /dev/null +++ b/DuckDuckGoTests/MockDomainTextZoomStorage.swift @@ -0,0 +1,35 @@ +// +// MockDomainTextZoomStorage.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +@testable import DuckDuckGo + +class MockDomainTextZoomStorage: DomainTextZoomStoring { + + func textZoomLevelForDomain(_ domain: String) -> DuckDuckGo.TextZoomLevel? { + return nil + } + + func set(textZoomLevel: DuckDuckGo.TextZoomLevel, forDomain domain: String) { + } + + func resetTextZoomLevels(excludingDomains: [String]) { + } + +} diff --git a/DuckDuckGoTests/MockTabDelegate.swift b/DuckDuckGoTests/MockTabDelegate.swift index b37a63a332..83c997d79e 100644 --- a/DuckDuckGoTests/MockTabDelegate.swift +++ b/DuckDuckGoTests/MockTabDelegate.swift @@ -137,6 +137,7 @@ extension TabViewController { onboardingPixelReporter: contextualOnboardingPixelReporter, urlCredentialCreator: MockCredentialCreator(), featureFlagger: featureFlagger, + domainTextZoomStorage: MockDomainTextZoomStorage(), subscriptionCookieManager: SubscriptionCookieManagerMock() ) tab.attachWebView(configuration: .nonPersistent(), andLoadRequest: nil, consumeCookies: false, customWebView: customWebView) diff --git a/DuckDuckGoTests/OnboardingDaxFavouritesTests.swift b/DuckDuckGoTests/OnboardingDaxFavouritesTests.swift index ff93a30198..0d201b0e5c 100644 --- a/DuckDuckGoTests/OnboardingDaxFavouritesTests.swift +++ b/DuckDuckGoTests/OnboardingDaxFavouritesTests.swift @@ -80,6 +80,7 @@ final class OnboardingDaxFavouritesTests: XCTestCase { tutorialSettings: tutorialSettingsMock, subscriptionFeatureAvailability: SubscriptionFeatureAvailabilityMock.enabled, voiceSearchHelper: MockVoiceSearchHelper(isSpeechRecognizerAvailable: true, voiceSearchEnabled: true), + featureFlagger: MockFeatureFlagger(), subscriptionCookieManager: SubscriptionCookieManagerMock() ) let window = UIWindow(frame: UIScreen.main.bounds) From 78623ccf12973a28a959f1f8f8139c5eeff4ffb5 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 31 Oct 2024 10:52:36 +0000 Subject: [PATCH 17/34] handle landsape better --- DuckDuckGo/TabViewController+TextZoomEditor.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DuckDuckGo/TabViewController+TextZoomEditor.swift b/DuckDuckGo/TabViewController+TextZoomEditor.swift index cd8646b848..fdf8e6a004 100644 --- a/DuckDuckGo/TabViewController+TextZoomEditor.swift +++ b/DuckDuckGo/TabViewController+TextZoomEditor.swift @@ -35,6 +35,10 @@ extension TabViewController { controller.sheetPresentationController?.detents = [.custom(resolver: { _ in return 152 })] + + controller.sheetPresentationController?.prefersScrollingExpandsWhenScrolledToEdge = false + controller.sheetPresentationController?.prefersEdgeAttachedInCompactHeight = true + controller.sheetPresentationController?.widthFollowsPreferredContentSizeWhenEdgeAttached = true } else { controller.sheetPresentationController?.detents = [.medium()] } From c87d7d01fb9559385af1cd6e391e8d4474f75480 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 31 Oct 2024 14:12:50 +0000 Subject: [PATCH 18/34] create coordinator to handle all interactions with text zoom --- Core/FeatureFlag.swift | 3 + Core/TextSizeUserScript.swift | 58 --------- DuckDuckGo.xcodeproj/project.pbxproj | 22 ++-- .../xcshareddata/swiftpm/Package.resolved | 9 -- DuckDuckGo/AppDelegate.swift | 12 +- DuckDuckGo/MainViewController+Segues.swift | 3 +- DuckDuckGo/MainViewController.swift | 16 ++- DuckDuckGo/SettingsViewModel.swift | 8 +- DuckDuckGo/TabManager.swift | 20 +-- .../TabViewController+TextZoomEditor.swift | 49 ------- DuckDuckGo/TabViewController.swift | 29 ++--- ...bViewControllerBrowsingMenuExtension.swift | 13 +- ...ViewControllerLongPressMenuExtension.swift | 26 ++-- DuckDuckGo/TextZoomController.swift | 4 +- DuckDuckGo/TextZoomCoordinator.swift | 120 ++++++++++++++++++ DuckDuckGo/TextZoomEditorModel.swift | 4 +- ...oomStorage.swift => TextZoomStorage.swift} | 6 +- DuckDuckGo/UserScripts.swift | 3 - 18 files changed, 208 insertions(+), 197 deletions(-) delete mode 100644 Core/TextSizeUserScript.swift delete mode 100644 DuckDuckGo/TabViewController+TextZoomEditor.swift create mode 100644 DuckDuckGo/TextZoomCoordinator.swift rename DuckDuckGo/{DomainTextZoomStorage.swift => TextZoomStorage.swift} (93%) diff --git a/Core/FeatureFlag.swift b/Core/FeatureFlag.swift index 3a63769bb9..b6ff715a04 100644 --- a/Core/FeatureFlag.swift +++ b/Core/FeatureFlag.swift @@ -45,6 +45,7 @@ public enum FeatureFlag: String { case onboardingAddToDock case autofillSurveys case autcompleteTabs + case textZoom /// https://app.asana.com/0/72649045549333/1208231259093710/f case networkProtectionUserTips @@ -103,6 +104,8 @@ extension FeatureFlag: FeatureFlagSourceProviding { return .remoteReleasable(.feature(.autocompleteTabs)) case .networkProtectionUserTips: return .remoteReleasable(.subfeature(NetworkProtectionSubfeature.userTips)) + case .textZoom: + return .remoteReleasable(.feature(.textZoom)) } } } diff --git a/Core/TextSizeUserScript.swift b/Core/TextSizeUserScript.swift deleted file mode 100644 index a246d48e63..0000000000 --- a/Core/TextSizeUserScript.swift +++ /dev/null @@ -1,58 +0,0 @@ -// -// TextSizeUserScript.swift -// DuckDuckGo -// -// Copyright © 2021 DuckDuckGo. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation -import WebKit -import UserScript - -public class TextSizeUserScript: NSObject, UserScript { - - public static let knownDynamicTypeExceptions: [String] = ["wikipedia.org"] - public var textSizeAdjustmentInPercents: Int = 100 - - public var source: String { TextSizeUserScript.makeSource(for: textSizeAdjustmentInPercents) } - - public var injectionTime: WKUserScriptInjectionTime = .atDocumentStart - public var forMainFrameOnly: Bool = false - public var messageNames: [String] = [] - - public init(textSizeAdjustmentInPercents: Int) { - self.textSizeAdjustmentInPercents = textSizeAdjustmentInPercents - } - - public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { } - - fileprivate static func makeSource(for textSizeAdjustmentInPercents: Int) -> String { - let dynamicTypeScalePercentage = UIFontMetrics.default.scaledValue(for: 100) - - return loadJS("textsize", from: Bundle.core, withReplacements: [ - "$KNOWN_DYNAMIC_TYPE_EXCEPTIONS$": knownDynamicTypeExceptions.joined(separator: "\n"), - "$TEXT_SIZE_ADJUSTMENT_IN_PERCENTS$": "\(textSizeAdjustmentInPercents)", - "$DYNAMIC_TYPE_SCALE_PERCENTAGE$": "\(dynamicTypeScalePercentage)" - ]) - } -} - -public extension WKWebView { - - func adjustTextSize(_ percentage: Int) { - let jsString = TextSizeUserScript.makeSource(for: percentage) - evaluateJavaScript(jsString, completionHandler: nil) - } -} diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 0084d9169c..a38a31f813 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -79,7 +79,6 @@ 1E60989B290009C700A508F9 /* Common in Frameworks */ = {isa = PBXBuildFile; productRef = 1E7060BD28F88EE200E4CCDB /* Common */; }; 1E60989D290011E600A508F9 /* ContentBlocking in Frameworks */ = {isa = PBXBuildFile; productRef = 1E60989C290011E600A508F9 /* ContentBlocking */; }; 1E6098A1290011E600A508F9 /* UserScript in Frameworks */ = {isa = PBXBuildFile; productRef = 1E6098A0290011E600A508F9 /* UserScript */; }; - 1E61BC2A27074BED00B2854D /* TextSizeUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E61BC2927074BED00B2854D /* TextSizeUserScript.swift */; }; 1E6A4D692984208800A371D3 /* LocaleExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E6A4D682984208800A371D3 /* LocaleExtension.swift */; }; 1E722729292EB24D003B5F53 /* AppSettingsMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6AD9E3C28D46FD50019CDE9 /* AppSettingsMock.swift */; }; 1E7A71172934EB6400B7EA19 /* OmniBarNotificationAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7A71162934EB6400B7EA19 /* OmniBarNotificationAnimator.swift */; }; @@ -432,7 +431,6 @@ 8517D98B221783A0006A8DD0 /* FindInPage.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8517D98A221783A0006A8DD0 /* FindInPage.xcassets */; }; 851A373A2CCC437400CF190B /* TextZoomEditorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851A37392CCC437400CF190B /* TextZoomEditorModel.swift */; }; 851A373C2CCC439E00CF190B /* TextZoomEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851A373B2CCC439E00CF190B /* TextZoomEditorView.swift */; }; - 851A373E2CCC476F00CF190B /* TabViewController+TextZoomEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851A373D2CCC476F00CF190B /* TabViewController+TextZoomEditor.swift */; }; 851B1283221FE65E004781BC /* ImproveOnboardingExperiment1Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851B1281221FE64E004781BC /* ImproveOnboardingExperiment1Tests.swift */; }; 851B128822200575004781BC /* Onboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851B128722200575004781BC /* Onboarding.swift */; }; 851B12CC22369931004781BC /* AtbAndVariantCleanup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850250B220D803F4002199C7 /* AtbAndVariantCleanup.swift */; }; @@ -442,6 +440,7 @@ 851F74262B9A1BFD00747C42 /* Suggestions in Frameworks */ = {isa = PBXBuildFile; productRef = 851F74252B9A1BFD00747C42 /* Suggestions */; }; 85200FA11FBC5BB5001AF290 /* DDGPersistenceContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85200FA01FBC5BB5001AF290 /* DDGPersistenceContainer.swift */; }; 8521FDE6238D414B00A44CC3 /* FileStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8521FDE4238D411400A44CC3 /* FileStoreTests.swift */; }; + 8522A6802CD3A604007F29C1 /* TextZoomCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8522A67F2CD3A604007F29C1 /* TextZoomCoordinator.swift */; }; 8524092D2C77EF7A00CB28FC /* mobile_segments_test_cases.json in Resources */ = {isa = PBXBuildFile; fileRef = 8524092C2C77EF7A00CB28FC /* mobile_segments_test_cases.json */; }; 8524092F2C78024900CB28FC /* UsageSegmentationCalculationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8524092E2C78024900CB28FC /* UsageSegmentationCalculationTests.swift */; }; 852409312C78030D00CB28FC /* MockUsageSegmentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 852409302C78030D00CB28FC /* MockUsageSegmentation.swift */; }; @@ -560,7 +559,7 @@ 85D2187624BF6164004373D2 /* FaviconSourcesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D2187524BF6164004373D2 /* FaviconSourcesProvider.swift */; }; 85D2187924BF6B8B004373D2 /* FaviconSourcesProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D2187724BF6B88004373D2 /* FaviconSourcesProviderTests.swift */; }; 85D2187B24BF9F85004373D2 /* FaviconUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D2187A24BF9F85004373D2 /* FaviconUserScript.swift */; }; - 85D3FF2B2CC941C100487724 /* DomainTextZoomStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D3FF2A2CC941C100487724 /* DomainTextZoomStorage.swift */; }; + 85D3FF2B2CC941C100487724 /* TextZoomStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D3FF2A2CC941C100487724 /* TextZoomStorage.swift */; }; 85D598872927F84C00FA3B1B /* Crashes in Frameworks */ = {isa = PBXBuildFile; productRef = 85D598862927F84C00FA3B1B /* Crashes */; }; 85DB12EB2A1FE2A4000A4A72 /* LockScreenWidgets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DB12EA2A1FE2A4000A4A72 /* LockScreenWidgets.swift */; }; 85DB12ED2A1FED0C000A4A72 /* AppDelegate+AppDeepLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DB12EC2A1FED0C000A4A72 /* AppDelegate+AppDeepLinks.swift */; }; @@ -1392,7 +1391,6 @@ 1E4FAA6327D8DFB900ADC5B3 /* OngoingDownloadRowViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OngoingDownloadRowViewModel.swift; sourceTree = ""; }; 1E4FAA6527D8DFC800ADC5B3 /* CompleteDownloadRowViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompleteDownloadRowViewModel.swift; sourceTree = ""; }; 1E53508E2C7C9A1F00818DAA /* DefaultSubscriptionManager+AccountManagerKeychainAccessDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DefaultSubscriptionManager+AccountManagerKeychainAccessDelegate.swift"; sourceTree = ""; }; - 1E61BC2927074BED00B2854D /* TextSizeUserScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextSizeUserScript.swift; sourceTree = ""; }; 1E6A4D682984208800A371D3 /* LocaleExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocaleExtension.swift; sourceTree = ""; }; 1E7A71162934EB6400B7EA19 /* OmniBarNotificationAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OmniBarNotificationAnimator.swift; sourceTree = ""; }; 1E7A71182934EC6100B7EA19 /* OmniBarNotificationContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OmniBarNotificationContainerView.swift; sourceTree = ""; }; @@ -1737,7 +1735,6 @@ 8517D98A221783A0006A8DD0 /* FindInPage.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = FindInPage.xcassets; sourceTree = ""; }; 851A37392CCC437400CF190B /* TextZoomEditorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextZoomEditorModel.swift; sourceTree = ""; }; 851A373B2CCC439E00CF190B /* TextZoomEditorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextZoomEditorView.swift; sourceTree = ""; }; - 851A373D2CCC476F00CF190B /* TabViewController+TextZoomEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TabViewController+TextZoomEditor.swift"; sourceTree = ""; }; 851B1281221FE64E004781BC /* ImproveOnboardingExperiment1Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImproveOnboardingExperiment1Tests.swift; sourceTree = ""; }; 851B128722200575004781BC /* Onboarding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Onboarding.swift; sourceTree = ""; }; 851B128B2220483A004781BC /* OnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewController.swift; sourceTree = ""; }; @@ -1745,6 +1742,8 @@ 851DFD89212C5EE800D95F20 /* TabSwitcherButtonTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabSwitcherButtonTests.swift; sourceTree = ""; }; 85200FA01FBC5BB5001AF290 /* DDGPersistenceContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DDGPersistenceContainer.swift; sourceTree = ""; }; 8521FDE4238D411400A44CC3 /* FileStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileStoreTests.swift; sourceTree = ""; }; + 8522A67F2CD3A604007F29C1 /* TextZoomCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextZoomCoordinator.swift; sourceTree = ""; }; + 8522A6812CD3AAFF007F29C1 /* BrowserServicesKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = BrowserServicesKit; path = ../BrowserServicesKit; sourceTree = ""; }; 8524092C2C77EF7A00CB28FC /* mobile_segments_test_cases.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = mobile_segments_test_cases.json; sourceTree = ""; }; 8524092E2C78024900CB28FC /* UsageSegmentationCalculationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsageSegmentationCalculationTests.swift; sourceTree = ""; }; 852409302C78030D00CB28FC /* MockUsageSegmentation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUsageSegmentation.swift; sourceTree = ""; }; @@ -1865,7 +1864,7 @@ 85D2187A24BF9F85004373D2 /* FaviconUserScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconUserScript.swift; sourceTree = ""; }; 85D33FCB25C97B6E002B91A6 /* IntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 85D33FCF25C97B6E002B91A6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 85D3FF2A2CC941C100487724 /* DomainTextZoomStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainTextZoomStorage.swift; sourceTree = ""; }; + 85D3FF2A2CC941C100487724 /* TextZoomStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextZoomStorage.swift; sourceTree = ""; }; 85DB12EA2A1FE2A4000A4A72 /* LockScreenWidgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LockScreenWidgets.swift; sourceTree = ""; }; 85DB12EC2A1FED0C000A4A72 /* AppDelegate+AppDeepLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+AppDeepLinks.swift"; sourceTree = ""; }; 85DDE03F2AC6FF65006ABCA2 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; @@ -4165,6 +4164,7 @@ 84E341891E2F7EFB00BDBA6F = { isa = PBXGroup; children = ( + 8522A6812CD3AAFF007F29C1 /* BrowserServicesKit */, EE3B98EB2A963515002F63A0 /* WidgetsExtensionAlpha.entitlements */, 6FB030C7234331B400A10DB9 /* Configuration.xcconfig */, EEB8FDB92A990AEE00EBEDCF /* Configuration-Alpha.xcconfig */, @@ -4565,9 +4565,9 @@ 85D3FF292CC941AC00487724 /* TextZoom */ = { isa = PBXGroup; children = ( - 85D3FF2A2CC941C100487724 /* DomainTextZoomStorage.swift */, - 851A373D2CCC476F00CF190B /* TabViewController+TextZoomEditor.swift */, + 85D3FF2A2CC941C100487724 /* TextZoomStorage.swift */, 859DA3312CCAC0A300C90694 /* TextZoomController.swift */, + 8522A67F2CD3A604007F29C1 /* TextZoomCoordinator.swift */, 851A37392CCC437400CF190B /* TextZoomEditorModel.swift */, 851A373B2CCC439E00CF190B /* TextZoomEditorView.swift */, 85147CB52CCA755300677835 /* TextZoomLevel.swift */, @@ -5974,7 +5974,6 @@ 850559CF23CF647C0055C0D5 /* PreserveLogins.swift */, 4B75EA9126A266CB00018634 /* PrintingUserScript.swift */, 988F3DCE237D5C0F00AEE34C /* SchemeHandler.swift */, - 1E61BC2927074BED00B2854D /* TextSizeUserScript.swift */, 836A941C247F23C600BF8EF5 /* UserAgentManager.swift */, F1A886771F29394E0096251E /* WebCacheManager.swift */, 83004E7F2193BB8200DA013C /* WKNavigationExtension.swift */, @@ -7827,9 +7826,10 @@ 8540BBA22440857A00017FE4 /* PreserveLoginsWorker.swift in Sources */, 0283A2012C6E46E300508FBD /* BrokenSitePromptLimiter.swift in Sources */, 85DFEDF924CF3D0E00973FE7 /* TabsBarCell.swift in Sources */, + 8522A6802CD3A604007F29C1 /* TextZoomCoordinator.swift in Sources */, 851672D32BED23FE00592F24 /* AutocompleteViewModel.swift in Sources */, 8562CE152B9B645C00E1D399 /* CachedBookmarkSuggestions.swift in Sources */, - 85D3FF2B2CC941C100487724 /* DomainTextZoomStorage.swift in Sources */, + 85D3FF2B2CC941C100487724 /* TextZoomStorage.swift in Sources */, C13F3F682B7F88100083BE40 /* AuthConfirmationPromptView.swift in Sources */, F1617C191E573EA800DEDCAF /* TabSwitcherDelegate.swift in Sources */, 4B5C462A2AF2A6E6002A4432 /* VPNIntents.swift in Sources */, @@ -7874,7 +7874,6 @@ 85864FBC24D31EF300E756FF /* SuggestionTrayViewController.swift in Sources */, D64648AF2B5993890033090B /* SubscriptionEmailViewModel.swift in Sources */, 1EF24235273BB9D200DE3D02 /* IntervalSlider.swift in Sources */, - 851A373E2CCC476F00CF190B /* TabViewController+TextZoomEditor.swift in Sources */, F1D796EE1E7AF2EB0019D451 /* UIViewControllerExtension.swift in Sources */, 1EE411F12857C3640003FE64 /* TrackerAnimationImageProvider.swift in Sources */, 1E7A711C2934EEBC00B7EA19 /* OmniBarNotification.swift in Sources */, @@ -8339,7 +8338,6 @@ 85CA53A824BB343700A6288C /* Favicons.swift in Sources */, F143C3181E4A99D200CFDE3A /* Link.swift in Sources */, 6F03CB092C32F331004179A8 /* PixelFiringAsync.swift in Sources */, - 1E61BC2A27074BED00B2854D /* TextSizeUserScript.swift in Sources */, 37CEFCAC2A673B90001EF741 /* CredentialsCleanupErrorHandling.swift in Sources */, CB2A7EF128410DF700885F67 /* PixelEvent.swift in Sources */, 85D2187624BF6164004373D2 /* FaviconSourcesProvider.swift in Sources */, diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index b048cebb73..c66e03653f 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -27,15 +27,6 @@ "version" : "3.0.0" } }, - { - "identity" : "browserserviceskit", - "kind" : "remoteSourceControl", - "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", - "state" : { - "revision" : "884a5eac964eeeb6d38780a6b90feaf5a5b3cfcf", - "version" : "201.0.1" - } - }, { "identity" : "content-scope-scripts", "kind" : "remoteSourceControl", diff --git a/DuckDuckGo/AppDelegate.swift b/DuckDuckGo/AppDelegate.swift index adecabd96b..8633007119 100644 --- a/DuckDuckGo/AppDelegate.swift +++ b/DuckDuckGo/AppDelegate.swift @@ -364,7 +364,8 @@ import os.log subscriptionFeatureAvailability: subscriptionFeatureAvailability, voiceSearchHelper: voiceSearchHelper, featureFlagger: AppDependencyProvider.shared.featureFlagger, - subscriptionCookieManager: subscriptionCookieManager) + subscriptionCookieManager: subscriptionCookieManager, + textZoomCoordinator: makeTextZoomCoordinator()) main.loadViewIfNeeded() syncErrorHandler.alertPresenter = main @@ -417,6 +418,15 @@ import os.log return true } + private func makeTextZoomCoordinator() -> TextZoomCoordinator { + let provider = AppDependencyProvider.shared + let storage = TextZoomStorage() + + return TextZoomCoordinator(appSettings: provider.appSettings, + storage: storage, + featureFlagger: provider.featureFlagger) + } + private func makeHistoryManager() -> HistoryManaging { let provider = AppDependencyProvider.shared diff --git a/DuckDuckGo/MainViewController+Segues.swift b/DuckDuckGo/MainViewController+Segues.swift index bca512800e..e4d8285b6d 100644 --- a/DuckDuckGo/MainViewController+Segues.swift +++ b/DuckDuckGo/MainViewController+Segues.swift @@ -312,7 +312,8 @@ extension MainViewController { deepLink: deepLinkTarget, historyManager: historyManager, syncPausedStateManager: syncPausedStateManager, - privacyProDataReporter: privacyProDataReporter) + privacyProDataReporter: privacyProDataReporter, + textZoomCoordinator: textZoomCoordinator) Pixel.fire(pixel: .settingsPresented) if let navigationController = self.presentedViewController as? UINavigationController, diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index f3d0117914..cabdaedfb1 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -175,7 +175,7 @@ class MainViewController: UIViewController { } let preserveLogins: PreserveLogins - let domainTextZoomStorage: DomainTextZoomStoring + let textZoomCoordinator: TextZoomCoordinator var historyManager: HistoryManaging var viewCoordinator: MainViewCoordinator! @@ -201,9 +201,9 @@ class MainViewController: UIViewController { subscriptionFeatureAvailability: SubscriptionFeatureAvailability, voiceSearchHelper: VoiceSearchHelperProtocol, featureFlagger: FeatureFlagger, - domainTextZoomStorage: DomainTextZoomStoring = DomainTextZoomStorage(), preserveLogins: PreserveLogins = .shared, - subscriptionCookieManager: SubscriptionCookieManaging + subscriptionCookieManager: SubscriptionCookieManaging, + textZoomCoordinator: TextZoomCoordinator ) { self.bookmarksDatabase = bookmarksDatabase self.bookmarksDatabaseCleaner = bookmarksDatabaseCleaner @@ -227,8 +227,9 @@ class MainViewController: UIViewController { contextualOnboardingLogic: contextualOnboardingLogic, onboardingPixelReporter: contextualOnboardingPixelReporter, featureFlagger: featureFlagger, - domainTextZoomStorage: domainTextZoomStorage, - subscriptionCookieManager: subscriptionCookieManager) + subscriptionCookieManager: subscriptionCookieManager, + appSettings: appSettings, + textZoomCoordinator: textZoomCoordinator) self.syncPausedStateManager = syncPausedStateManager self.privacyProDataReporter = privacyProDataReporter self.homeTabManager = NewTabPageManager() @@ -239,9 +240,9 @@ class MainViewController: UIViewController { self.statisticsStore = statisticsStore self.subscriptionFeatureAvailability = subscriptionFeatureAvailability self.voiceSearchHelper = voiceSearchHelper - self.domainTextZoomStorage = domainTextZoomStorage self.preserveLogins = preserveLogins self.subscriptionCookieManager = subscriptionCookieManager + self.textZoomCoordinator = textZoomCoordinator super.init(nibName: nil, bundle: nil) @@ -2726,7 +2727,8 @@ extension MainViewController: AutoClearWorker { private func forgetTextZoom() { let allowedDomains = preserveLogins.allowedDomains - domainTextZoomStorage.resetTextZoomLevels(excludingDomains: allowedDomains) + // TODO call a function instead + textZoomCoordinator.storage.resetTextZoomLevels(excludingDomains: allowedDomains) } } diff --git a/DuckDuckGo/SettingsViewModel.swift b/DuckDuckGo/SettingsViewModel.swift index d28235c0de..faf269b483 100644 --- a/DuckDuckGo/SettingsViewModel.swift +++ b/DuckDuckGo/SettingsViewModel.swift @@ -43,6 +43,8 @@ final class SettingsViewModel: ObservableObject { var emailManager: EmailManager { EmailManager() } private let historyManager: HistoryManaging let privacyProDataReporter: PrivacyProDataReporting? + let textZoomCoordinator: TextZoomCoordinator + // Subscription Dependencies private let subscriptionManager: SubscriptionManager let subscriptionFeatureAvailability: SubscriptionFeatureAvailability @@ -383,7 +385,8 @@ final class SettingsViewModel: ObservableObject { deepLink: SettingsDeepLinkSection? = nil, historyManager: HistoryManaging, syncPausedStateManager: any SyncPausedStateManaging, - privacyProDataReporter: PrivacyProDataReporting) { + privacyProDataReporter: PrivacyProDataReporting, + textZoomCoordinator: TextZoomCoordinator) { self.state = SettingsState.defaults self.legacyViewProvider = legacyViewProvider @@ -394,6 +397,7 @@ final class SettingsViewModel: ObservableObject { self.historyManager = historyManager self.syncPausedStateManager = syncPausedStateManager self.privacyProDataReporter = privacyProDataReporter + self.textZoomCoordinator = textZoomCoordinator setupNotificationObservers() updateRecentlyVisitedSitesVisibility() @@ -418,7 +422,7 @@ extension SettingsViewModel { appTheme: appSettings.currentThemeName, appIcon: AppIconManager.shared.appIcon, fireButtonAnimation: appSettings.currentFireButtonAnimation, - textSize: SettingsState.TextZoom(enabled: !isPad, level: appSettings.defaultTextZoomLevel), + textSize: SettingsState.TextZoom(enabled: textZoomCoordinator.isEnabled, level: appSettings.defaultTextZoomLevel), addressBar: SettingsState.AddressBar(enabled: !isPad, position: appSettings.currentAddressBarPosition), showsFullURL: appSettings.showFullSiteAddress, sendDoNotSell: appSettings.sendDoNotSell, diff --git a/DuckDuckGo/TabManager.swift b/DuckDuckGo/TabManager.swift index 095fccb183..99d02bfbc7 100644 --- a/DuckDuckGo/TabManager.swift +++ b/DuckDuckGo/TabManager.swift @@ -43,8 +43,9 @@ class TabManager { private let contextualOnboardingLogic: ContextualOnboardingLogic private let onboardingPixelReporter: OnboardingPixelReporting private let featureFlagger: FeatureFlagger - private let domainTextZoomStorage: DomainTextZoomStoring + private let textZoomCoordinator: TextZoomCoordinator private let subscriptionCookieManager: SubscriptionCookieManaging + private let appSettings: AppSettings weak var delegate: TabDelegate? @@ -63,8 +64,9 @@ class TabManager { contextualOnboardingLogic: ContextualOnboardingLogic, onboardingPixelReporter: OnboardingPixelReporting, featureFlagger: FeatureFlagger, - domainTextZoomStorage: DomainTextZoomStoring, - subscriptionCookieManager: SubscriptionCookieManaging) { + subscriptionCookieManager: SubscriptionCookieManaging, + appSettings: AppSettings, + textZoomCoordinator: TextZoomCoordinator) { self.model = model self.previewsSource = previewsSource self.bookmarksDatabase = bookmarksDatabase @@ -76,8 +78,9 @@ class TabManager { self.contextualOnboardingLogic = contextualOnboardingLogic self.onboardingPixelReporter = onboardingPixelReporter self.featureFlagger = featureFlagger - self.domainTextZoomStorage = domainTextZoomStorage self.subscriptionCookieManager = subscriptionCookieManager + self.appSettings = appSettings + self.textZoomCoordinator = textZoomCoordinator registerForNotifications() } @@ -101,8 +104,8 @@ class TabManager { contextualOnboardingLogic: contextualOnboardingLogic, onboardingPixelReporter: onboardingPixelReporter, featureFlagger: featureFlagger, - domainTextZoomStorage: domainTextZoomStorage, - subscriptionCookieManager: subscriptionCookieManager) + subscriptionCookieManager: subscriptionCookieManager, + textZoomCoordinator: textZoomCoordinator) controller.applyInheritedAttribution(inheritedAttribution) controller.attachWebView(configuration: configuration, andLoadRequest: url == nil ? nil : URLRequest.userInitiated(url!), @@ -181,8 +184,8 @@ class TabManager { contextualOnboardingLogic: contextualOnboardingLogic, onboardingPixelReporter: onboardingPixelReporter, featureFlagger: featureFlagger, - domainTextZoomStorage: domainTextZoomStorage, - subscriptionCookieManager: subscriptionCookieManager) + subscriptionCookieManager: subscriptionCookieManager, + textZoomCoordinator: textZoomCoordinator) controller.attachWebView(configuration: configCopy, andLoadRequest: request, consumeCookies: !model.hasActiveTabs, @@ -365,4 +368,5 @@ extension TabManager { TabPreviewsCleanup.shared.startCleanup(with: model, source: previewsSource) } } + } diff --git a/DuckDuckGo/TabViewController+TextZoomEditor.swift b/DuckDuckGo/TabViewController+TextZoomEditor.swift deleted file mode 100644 index fdf8e6a004..0000000000 --- a/DuckDuckGo/TabViewController+TextZoomEditor.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// TabViewController+TextZoomEditor.swift -// DuckDuckGo -// -// Copyright © 2024 DuckDuckGo. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import UIKit -import Common - -extension TabViewController { - - func showTextZoomAdjustment() { - guard let domain = TLD().eTLDplus1(webView.url?.host) else { return } - let controller = TextZoomController( - domain: domain, - storage: domainTextZoomStorage, - defaultTextZoom: appSettings.defaultTextZoomLevel - ) - - controller.modalPresentationStyle = .formSheet - if #available(iOS 16.0, *) { - controller.sheetPresentationController?.detents = [.custom(resolver: { _ in - return 152 - })] - - controller.sheetPresentationController?.prefersScrollingExpandsWhenScrolledToEdge = false - controller.sheetPresentationController?.prefersEdgeAttachedInCompactHeight = true - controller.sheetPresentationController?.widthFollowsPreferredContentSizeWhenEdgeAttached = true - } else { - controller.sheetPresentationController?.detents = [.medium()] - } - - present(controller, animated: true) - } - -} diff --git a/DuckDuckGo/TabViewController.swift b/DuckDuckGo/TabViewController.swift index 657c289a5d..e08a11ee17 100644 --- a/DuckDuckGo/TabViewController.swift +++ b/DuckDuckGo/TabViewController.swift @@ -189,8 +189,6 @@ class TabViewController: UIViewController { var failedURL: URL? var storedSpecialErrorPageUserScript: SpecialErrorPageUserScript? var isSpecialErrorPageVisible: Bool = false - - let domainTextZoomStorage: DomainTextZoomStoring let syncService: DDGSyncing private let daxDialogsDebouncer = Debouncer(mode: .common) @@ -325,8 +323,9 @@ class TabViewController: UIViewController { onboardingPixelReporter: OnboardingCustomInteractionPixelReporting, urlCredentialCreator: URLCredentialCreating = URLCredentialCreator(), featureFlagger: FeatureFlagger, - domainTextZoomStorage: DomainTextZoomStoring, - subscriptionCookieManager: SubscriptionCookieManaging) -> TabViewController { + subscriptionCookieManager: SubscriptionCookieManaging, + textZoomCoordinator: TextZoomCoordinating) -> TabViewController { + let storyboard = UIStoryboard(name: "Tab", bundle: nil) let controller = storyboard.instantiateViewController(identifier: "TabViewController", creator: { coder in TabViewController(coder: coder, @@ -342,8 +341,8 @@ class TabViewController: UIViewController { onboardingPixelReporter: onboardingPixelReporter, urlCredentialCreator: urlCredentialCreator, featureFlagger: featureFlagger, - domainTextZoomStorage: domainTextZoomStorage, - subscriptionCookieManager: subscriptionCookieManager + subscriptionCookieManager: subscriptionCookieManager, + textZoomCoordinator: textZoomCoordinator ) }) return controller @@ -362,6 +361,7 @@ class TabViewController: UIViewController { let contextualOnboardingPresenter: ContextualOnboardingPresenting let contextualOnboardingLogic: ContextualOnboardingLogic let onboardingPixelReporter: OnboardingCustomInteractionPixelReporting + let textZoomCoordinator: TextZoomCoordinating required init?(coder aDecoder: NSCoder, tabModel: Tab, @@ -377,8 +377,8 @@ class TabViewController: UIViewController { onboardingPixelReporter: OnboardingCustomInteractionPixelReporting, urlCredentialCreator: URLCredentialCreating = URLCredentialCreator(), featureFlagger: FeatureFlagger, - domainTextZoomStorage: DomainTextZoomStoring, - subscriptionCookieManager: SubscriptionCookieManaging) { + subscriptionCookieManager: SubscriptionCookieManaging, + textZoomCoordinator: TextZoomCoordinating) { self.tabModel = tabModel self.appSettings = appSettings self.bookmarksDatabase = bookmarksDatabase @@ -397,8 +397,9 @@ class TabViewController: UIViewController { self.onboardingPixelReporter = onboardingPixelReporter self.urlCredentialCreator = urlCredentialCreator self.featureFlagger = featureFlagger - self.domainTextZoomStorage = domainTextZoomStorage self.subscriptionCookieManager = subscriptionCookieManager + self.textZoomCoordinator = textZoomCoordinator + super.init(coder: aDecoder) } @@ -979,12 +980,7 @@ class TabViewController: UIViewController { } @objc func onTextSizeChange() { - let domain = TLD().eTLDplus1(webView.url?.host) ?? "" - // If the webview returns no host then there won't be a setting for a blank string anyway. - let level = domainTextZoomStorage.textZoomLevelForDomain(domain) - // And if there's no setting for whatever domain is passed in, use the app default - ?? appSettings.defaultTextZoomLevel - webView.adjustTextSize(level.rawValue) + textZoomCoordinator.onTextZoomChange(applyToWebView: webView) } @objc func onDuckDuckGoEmailSignOut(_ notification: Notification) { @@ -2166,7 +2162,7 @@ extension TabViewController { */ private func setupOrClearTemporaryDownload(for response: URLResponse) -> WKNavigationResponsePolicy? { let downloadManager = AppDependencyProvider.shared.downloadManager - guard let url = response.url, + guard response.url != nil, let downloadMetaData = downloadManager.downloadMetaData(for: response), !downloadMetaData.mimeType.isHTML else { @@ -2541,7 +2537,6 @@ extension TabViewController: UserContentControllerDelegate { userScripts.autofillUserScript.vaultDelegate = vaultManager userScripts.faviconScript.delegate = faviconUpdater userScripts.printingUserScript.delegate = self - userScripts.textSizeUserScript.textSizeAdjustmentInPercents = appSettings.defaultTextZoomLevel.rawValue userScripts.loginFormDetectionScript?.delegate = self userScripts.autoconsentUserScript.delegate = self userScripts.specialErrorPageUserScript?.delegate = self diff --git a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift index e2731f743f..fe193e42a0 100644 --- a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift +++ b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift @@ -156,8 +156,8 @@ extension TabViewController { entries.append(entry) } - if !isPad { - entries.append(self.buildZoomLevelEntry(forLink: link)) + if let entry = textZoomCoordinator.makeBrowsingMenuEntry(forLink: link, inController: self, forWebView: self.webView) { + entries.append(entry) } let title = self.tabModel.isDesktop ? UserText.actionRequestMobileSite : UserText.actionRequestDesktopSite @@ -171,15 +171,6 @@ extension TabViewController { return entries } - private func buildZoomLevelEntry(forLink link: Link) -> BrowsingMenuEntry { - return BrowsingMenuEntry.regular(name: UserText.textZoomMenuItem, - image: UIImage(named: "Type-Size-16")!, - showNotificationDot: false) { [weak self] in - self?.showTextZoomAdjustment() - Pixel.fire(pixel: .browsingMenuZoom) - } - } - private func buildKeepSignInEntry(forLink link: Link) -> BrowsingMenuEntry? { guard let domain = link.url.host, !link.url.isDuckDuckGo else { return nil } let isFireproofed = PreserveLogins.shared.isAllowed(cookieDomain: domain) diff --git a/DuckDuckGo/TabViewControllerLongPressMenuExtension.swift b/DuckDuckGo/TabViewControllerLongPressMenuExtension.swift index 4b02fedb75..974fbbf895 100644 --- a/DuckDuckGo/TabViewControllerLongPressMenuExtension.swift +++ b/DuckDuckGo/TabViewControllerLongPressMenuExtension.swift @@ -102,18 +102,20 @@ extension TabViewController { fileprivate func buildOpenLinkPreview(for url: URL) -> UIViewController? { let tab = Tab(link: Link(title: nil, url: url)) - let tabController = TabViewController.loadFromStoryboard(model: tab, - bookmarksDatabase: bookmarksDatabase, - historyManager: historyManager, - syncService: syncService, - duckPlayer: duckPlayer, - privacyProDataReporter: privacyProDataReporter, - contextualOnboardingPresenter: contextualOnboardingPresenter, - contextualOnboardingLogic: contextualOnboardingLogic, - onboardingPixelReporter: onboardingPixelReporter, - featureFlagger: featureFlagger, - domainTextZoomStorage: domainTextZoomStorage, - subscriptionCookieManager: subscriptionCookieManager) + let tabController = TabViewController.loadFromStoryboard( + model: tab, + bookmarksDatabase: bookmarksDatabase, + historyManager: historyManager, + syncService: syncService, + duckPlayer: duckPlayer, + privacyProDataReporter: privacyProDataReporter, + contextualOnboardingPresenter: contextualOnboardingPresenter, + contextualOnboardingLogic: contextualOnboardingLogic, + onboardingPixelReporter: onboardingPixelReporter, + featureFlagger: featureFlagger, + subscriptionCookieManager: subscriptionCookieManager, + textZoomCoordinator: textZoomCoordinator) + tabController.isLinkPreview = true let configuration = WKWebViewConfiguration.nonPersistent() tabController.attachWebView(configuration: configuration, andLoadRequest: URLRequest.userInitiated(url), consumeCookies: false) diff --git a/DuckDuckGo/TextZoomController.swift b/DuckDuckGo/TextZoomController.swift index 0daf318a0a..1f6306375d 100644 --- a/DuckDuckGo/TextZoomController.swift +++ b/DuckDuckGo/TextZoomController.swift @@ -22,10 +22,10 @@ import SwiftUI class TextZoomController: UIHostingController { - let storage: DomainTextZoomStoring + let storage: TextZoomStoring let model: TextZoomEditorModel - @MainActor init(domain: String, storage: DomainTextZoomStoring, defaultTextZoom: TextZoomLevel) { + @MainActor init(domain: String, storage: TextZoomStoring, defaultTextZoom: TextZoomLevel) { self.storage = storage self.model = TextZoomEditorModel(domain: domain, storage: storage, defaultTextZoom: defaultTextZoom) super.init(rootView: TextZoomEditorView(model: model)) diff --git a/DuckDuckGo/TextZoomCoordinator.swift b/DuckDuckGo/TextZoomCoordinator.swift new file mode 100644 index 0000000000..8f3b7db8d3 --- /dev/null +++ b/DuckDuckGo/TextZoomCoordinator.swift @@ -0,0 +1,120 @@ +// +// TextZoomCoordinator.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import WebKit +import Common +import BrowserServicesKit +import Core + +protocol TextZoomCoordinating { + + var isEnabled: Bool { get } + var storage: TextZoomStoring { get } + + func onNavigationCommitted(applyToWebView webView: WKWebView) + func onShowTextZoomEditor(inController controller: UIViewController, forWebView webView: WKWebView) + func onTextZoomChange(applyToWebView webView: WKWebView) + func makeBrowsingMenuEntry(forLink: Link, inController controller: UIViewController, forWebView webView: WKWebView) -> BrowsingMenuEntry? + +} + +// TODO validate wikipedia which had a hardcoded exception +final class TextZoomCoordinator: TextZoomCoordinating { + + let appSettings: AppSettings + let storage: TextZoomStoring + let featureFlagger: FeatureFlagger + + var isEnabled: Bool { + featureFlagger.isFeatureOn(.textZoom) + } + + init(appSettings: AppSettings, storage: TextZoomStoring, featureFlagger: FeatureFlagger) { + self.appSettings = appSettings + self.storage = storage + self.featureFlagger = featureFlagger + } + + func onNavigationCommitted(applyToWebView webView: WKWebView) { + guard isEnabled else { return } + // TODO logic from textsize.js + } + + func onTextZoomChange(applyToWebView webView: WKWebView) { + guard isEnabled else { return } + + let domain = TLD().eTLDplus1(webView.url?.host) ?? "" + // If the webview returns no host then there won't be a setting for a blank string anyway. + let level = storage.textZoomLevelForDomain(domain) + // And if there's no setting for whatever domain is passed in, use the app default + ?? appSettings.defaultTextZoomLevel + webView.applyViewScale(CGFloat(level.rawValue) / 100) + } + + @MainActor + func onShowTextZoomEditor(inController controller: UIViewController, forWebView webView: WKWebView) { + guard isEnabled else { return } + + guard let domain = TLD().eTLDplus1(webView.url?.host) else { return } + let zoomController = TextZoomController( + domain: domain, + storage: storage, + defaultTextZoom: appSettings.defaultTextZoomLevel + ) + + zoomController.modalPresentationStyle = .formSheet + if #available(iOS 16.0, *) { + zoomController.sheetPresentationController?.detents = [.custom(resolver: { _ in + return 152 + })] + + zoomController.sheetPresentationController?.prefersScrollingExpandsWhenScrolledToEdge = false + zoomController.sheetPresentationController?.prefersEdgeAttachedInCompactHeight = true + zoomController.sheetPresentationController?.widthFollowsPreferredContentSizeWhenEdgeAttached = true + } else { + zoomController.sheetPresentationController?.detents = [.medium()] + } + + zoomController.present(controller, animated: true) + } + + func makeBrowsingMenuEntry(forLink: Link, + inController controller: UIViewController, + forWebView webView: WKWebView) -> BrowsingMenuEntry? { + guard isEnabled else { return nil } + return BrowsingMenuEntry.regular(name: UserText.textZoomMenuItem, + image: UIImage(named: "Type-Size-16")!, + showNotificationDot: false) { [weak self, weak controller, weak webView] in + guard let self = self, let controller = controller, let webView = webView else { return } + Task { @MainActor in + self.onShowTextZoomEditor(inController: controller, forWebView: webView) + Pixel.fire(pixel: .browsingMenuZoom) + } + } + } +} + +extension WKWebView { + + func applyViewScale(_ scale: CGFloat) { + // TODO + } + +} diff --git a/DuckDuckGo/TextZoomEditorModel.swift b/DuckDuckGo/TextZoomEditorModel.swift index ef355060b1..91dd20cc43 100644 --- a/DuckDuckGo/TextZoomEditorModel.swift +++ b/DuckDuckGo/TextZoomEditorModel.swift @@ -23,7 +23,7 @@ import Core class TextZoomEditorModel: ObservableObject { let domain: String - let storage: DomainTextZoomStoring + let storage: TextZoomStoring let initialValue: TextZoomLevel var valueAsPercent: Int { @@ -38,7 +38,7 @@ class TextZoomEditorModel: ObservableObject { @Published var title: String = "" - init(domain: String, storage: DomainTextZoomStoring, defaultTextZoom: TextZoomLevel) { + init(domain: String, storage: TextZoomStoring, defaultTextZoom: TextZoomLevel) { self.domain = domain self.storage = storage self.initialValue = (storage.textZoomLevelForDomain(domain) ?? defaultTextZoom) diff --git a/DuckDuckGo/DomainTextZoomStorage.swift b/DuckDuckGo/TextZoomStorage.swift similarity index 93% rename from DuckDuckGo/DomainTextZoomStorage.swift rename to DuckDuckGo/TextZoomStorage.swift index 43119e073b..fd937e882f 100644 --- a/DuckDuckGo/DomainTextZoomStorage.swift +++ b/DuckDuckGo/TextZoomStorage.swift @@ -1,5 +1,5 @@ // -// DomainTextZoomStorage.swift +// TextZoomStorage.swift // DuckDuckGo // // Copyright © 2024 DuckDuckGo. All rights reserved. @@ -21,13 +21,13 @@ import Foundation import Core import Common -protocol DomainTextZoomStoring { +protocol TextZoomStoring { func textZoomLevelForDomain(_ domain: String) -> TextZoomLevel? func set(textZoomLevel: TextZoomLevel, forDomain domain: String) func resetTextZoomLevels(excludingDomains: [String]) } -class DomainTextZoomStorage: DomainTextZoomStoring { +class TextZoomStorage: TextZoomStoring { @UserDefaultsWrapper(key: .domainTextZoomStorage, defaultValue: [:]) var textZoomLevels: [String: Int] diff --git a/DuckDuckGo/UserScripts.swift b/DuckDuckGo/UserScripts.swift index e1d73ea742..ee3b5c1612 100644 --- a/DuckDuckGo/UserScripts.swift +++ b/DuckDuckGo/UserScripts.swift @@ -50,11 +50,9 @@ final class UserScripts: UserScriptsProvider { private(set) var findInPageScript = FindInPageUserScript() private(set) var fullScreenVideoScript = FullScreenVideoUserScript() private(set) var printingUserScript = PrintingUserScript() - private(set) var textSizeUserScript: TextSizeUserScript private(set) var debugScript = DebugUserScript() init(with sourceProvider: ScriptSourceProviding, appSettings: AppSettings = AppDependencyProvider.shared.appSettings) { - textSizeUserScript = TextSizeUserScript(textSizeAdjustmentInPercents: appSettings.defaultTextZoomLevel.rawValue) contentBlockerUserScript = ContentBlockerRulesUserScript(configuration: sourceProvider.contentBlockerRulesConfig) surrogatesScript = SurrogatesUserScript(configuration: sourceProvider.surrogatesConfig) @@ -81,7 +79,6 @@ final class UserScripts: UserScriptsProvider { lazy var userScripts: [UserScript] = [ debugScript, - textSizeUserScript, autoconsentUserScript, findInPageScript, navigatorPatchScript, From 36301c5ba58a72676e3347cb8a1e941838c23d27 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 31 Oct 2024 16:46:20 +0000 Subject: [PATCH 19/34] remove textsize js --- Core/textsize.js | 154 ------------------ DuckDuckGo.xcodeproj/project.pbxproj | 10 +- .../xcshareddata/swiftpm/Package.resolved | 8 + DuckDuckGo/TabViewController.swift | 2 + DuckDuckGo/TextZoomCoordinator.swift | 39 ++++- 5 files changed, 43 insertions(+), 170 deletions(-) delete mode 100644 Core/textsize.js diff --git a/Core/textsize.js b/Core/textsize.js deleted file mode 100644 index 98a434ad82..0000000000 --- a/Core/textsize.js +++ /dev/null @@ -1,154 +0,0 @@ -// -// textsize.js -// DuckDuckGo -// -// Copyright © 2021 DuckDuckGo. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -(function() { - let hostname = getTopLevelURL().hostname; - - let knownDynamicTypeExceptions = `$KNOWN_DYNAMIC_TYPE_EXCEPTIONS$`.split("\n"); - - let shouldAdjustForDynamicType = isURLMatchingAnyOfDomains(hostname, knownDynamicTypeExceptions); - let isDDG = isURLMatchingDomain(hostname, "duckduckgo.com"); - - let currentTextSizeAdjustment = $TEXT_SIZE_ADJUSTMENT_IN_PERCENTS$; - - if (document.readyState === "complete" - || document.readyState === "loaded" - || document.readyState === "interactive") { - // DOM should have been parsed - adjustTextSize(currentTextSizeAdjustment); - } else { - // DOM not yet ready, add a listener instead - if ((shouldAdjustForDynamicType) || (isDDG) || (currentTextSizeAdjustment != 100)) { - document.addEventListener("DOMContentLoaded", function(event) { - adjustTextSize(currentTextSizeAdjustment); - }, false) - } - } - - function getTopLevelURL() { - try { - // FROM: https://stackoverflow.com/a/7739035/73479 - // FIX: Better capturing of top level URL so that trackers in embedded documents are not considered first party - return new URL(window.location != window.parent.location ? document.referrer : document.location.href) - } catch(error) { - return new URL(location.href) - } - } - - function isURLMatchingDomain(url, domain) { - var urlParts = url.split('.'); - - while (urlParts.length > 1) { - if (domain === urlParts.join('.')) { - return true; - } - - urlParts.shift(); - } - - return false; - } - - function isURLMatchingAnyOfDomains(url, domains) { - for (const domain of domains) { - if (isURLMatchingDomain(url, domain)) { - return true - } - } - - return false - } - - function adjustTextSize(percentage) { - if (shouldAdjustForDynamicType) { - adjustTextSizeForDynamicType(percentage); - } else if (isDDG && (typeof DDG !== 'undefined')) { - adjustTextSizeForDDG(percentage); - } else { - document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust=percentage+"%"; - } - } - - function adjustTextSizeForDynamicType(percentage) { - let dynamicTypeAdjustment = $DYNAMIC_TYPE_SCALE_PERCENTAGE$; - var adjustedPercentage = percentage * 100/dynamicTypeAdjustment; - - document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust=adjustedPercentage+"%"; - } - - function adjustTextSizeForDDG(percentage) { - var adjustedPercentage = 100; - - // Fix for side menu sliding in when growing due to increased text - let menu = document.getElementsByClassName('nav-menu--slideout')[0]; - let previousLeft = menu.style.left; - menu.style.left="-100%"; - - // Force re-painting of the menu: https://stackoverflow.com/a/3485654 - menu.style.display='none'; - menu.offsetHeight; // no need to store this anywhere, the reference is enough - menu.style.display='block'; - - switch(percentage) { - case 80: - DDG.settings.set('ks', 's'); - break; - case 90: - DDG.settings.set('ks', 'm'); - break; - case 100: - DDG.settings.set('ks', 'n'); - break; - case 110: - DDG.settings.set('ks', 'n'); - adjustedPercentage = 105; - break; - case 120: - DDG.settings.set('ks', 'l'); - break; - case 130: - DDG.settings.set('ks', 'l'); - adjustedPercentage = 105; - break; - case 140: - DDG.settings.set('ks', 'l'); - adjustedPercentage = 110; - break; - case 150: - DDG.settings.set('ks', 't'); - break; - case 160: - DDG.settings.set('ks', 't'); - adjustedPercentage = 105; - break; - case 170: - DDG.settings.set('ks', 't'); - adjustedPercentage = 110; - break; - default: - DDG.settings.set('ks', 'n'); - break; - } - - document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust=adjustedPercentage+"%"; - - menu.style.left = previousLeft; - } - -}) (); diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index a38a31f813..de2819560f 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -125,7 +125,6 @@ 1EEF12532851D32B003DDE57 /* trackers-2.json in Resources */ = {isa = PBXBuildFile; fileRef = 1EEF12512851D32A003DDE57 /* trackers-2.json */; }; 1EEF12542851D32B003DDE57 /* trackers-1.json in Resources */ = {isa = PBXBuildFile; fileRef = 1EEF12522851D32A003DDE57 /* trackers-1.json */; }; 1EEF387D285B1A1100383393 /* TrackerImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EEF387C285B1A1100383393 /* TrackerImageCache.swift */; }; - 1EEFD2D52758E31600B1393B /* textsize.js in Resources */ = {isa = PBXBuildFile; fileRef = 1EEFD2D42758E31600B1393B /* textsize.js */; }; 1EF24235273BB9D200DE3D02 /* IntervalSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EF24234273BB9D200DE3D02 /* IntervalSlider.swift */; }; 1EFDCBC127D2393C00916BC5 /* DownloadsDeleteHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EFDCBC027D2393C00916BC5 /* DownloadsDeleteHelper.swift */; }; 22CB1ED8203DDD2C00D2C724 /* AppDeepLinksTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22CB1ED7203DDD2C00D2C724 /* AppDeepLinksTests.swift */; }; @@ -1436,7 +1435,6 @@ 1EEF12512851D32A003DDE57 /* trackers-2.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "trackers-2.json"; sourceTree = ""; }; 1EEF12522851D32A003DDE57 /* trackers-1.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "trackers-1.json"; sourceTree = ""; }; 1EEF387C285B1A1100383393 /* TrackerImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackerImageCache.swift; sourceTree = ""; }; - 1EEFD2D42758E31600B1393B /* textsize.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = textsize.js; sourceTree = ""; }; 1EF24234273BB9D200DE3D02 /* IntervalSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntervalSlider.swift; sourceTree = ""; }; 1EFDCBC027D2393C00916BC5 /* DownloadsDeleteHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadsDeleteHelper.swift; sourceTree = ""; }; 22CB1ED7203DDD2C00D2C724 /* AppDeepLinksTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDeepLinksTests.swift; sourceTree = ""; }; @@ -1743,7 +1741,6 @@ 85200FA01FBC5BB5001AF290 /* DDGPersistenceContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DDGPersistenceContainer.swift; sourceTree = ""; }; 8521FDE4238D411400A44CC3 /* FileStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileStoreTests.swift; sourceTree = ""; }; 8522A67F2CD3A604007F29C1 /* TextZoomCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextZoomCoordinator.swift; sourceTree = ""; }; - 8522A6812CD3AAFF007F29C1 /* BrowserServicesKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = BrowserServicesKit; path = ../BrowserServicesKit; sourceTree = ""; }; 8524092C2C77EF7A00CB28FC /* mobile_segments_test_cases.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = mobile_segments_test_cases.json; sourceTree = ""; }; 8524092E2C78024900CB28FC /* UsageSegmentationCalculationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsageSegmentationCalculationTests.swift; sourceTree = ""; }; 852409302C78030D00CB28FC /* MockUsageSegmentation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUsageSegmentation.swift; sourceTree = ""; }; @@ -4164,7 +4161,6 @@ 84E341891E2F7EFB00BDBA6F = { isa = PBXGroup; children = ( - 8522A6812CD3AAFF007F29C1 /* BrowserServicesKit */, EE3B98EB2A963515002F63A0 /* WidgetsExtensionAlpha.entitlements */, 6FB030C7234331B400A10DB9 /* Configuration.xcconfig */, EEB8FDB92A990AEE00EBEDCF /* Configuration-Alpha.xcconfig */, @@ -4456,7 +4452,6 @@ isa = PBXGroup; children = ( 4B60AC96252EC07B00E8D219 /* fullscreenvideo.js */, - 1EEFD2D42758E31600B1393B /* textsize.js */, ); name = "ios-js-support"; sourceTree = ""; @@ -7168,7 +7163,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1EEFD2D52758E31600B1393B /* textsize.js in Resources */, 83E2D2B4253CC16B005605F5 /* httpsMobileV2BloomSpec.json in Resources */, 98B001B0251EABB40090EC07 /* InfoPlist.strings in Resources */, 02BA15B126A89ECA00472DD7 /* ios-config.json in Resources */, @@ -10983,8 +10977,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { - kind = exactVersion; - version = 201.0.1; + kind = revision; + revision = 689c7f1c5a9f9d96dbb5e259deae8898517015c8; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index c66e03653f..7cc0e37637 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -27,6 +27,14 @@ "version" : "3.0.0" } }, + { + "identity" : "browserserviceskit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", + "state" : { + "revision" : "689c7f1c5a9f9d96dbb5e259deae8898517015c8" + } + }, { "identity" : "content-scope-scripts", "kind" : "remoteSourceControl", diff --git a/DuckDuckGo/TabViewController.swift b/DuckDuckGo/TabViewController.swift index e08a11ee17..d7427fd12c 100644 --- a/DuckDuckGo/TabViewController.swift +++ b/DuckDuckGo/TabViewController.swift @@ -537,6 +537,7 @@ class TabViewController: UIViewController { } else { webView = WKWebView(frame: view.bounds, configuration: configuration) } + textZoomCoordinator.onWebViewCreated(applyToWebView: webView) webView.allowsLinkPreview = true webView.allowsBackForwardNavigationGestures = true @@ -1307,6 +1308,7 @@ extension TabViewController: WKNavigationDelegate { let tld = storageCache.tld let httpsForced = tld.domain(lastUpgradedURL?.host) == tld.domain(webView.url?.host) onWebpageDidStartLoading(httpsForced: httpsForced) + textZoomCoordinator.onNavigationCommitted(applyToWebView: webView) } private func onWebpageDidStartLoading(httpsForced: Bool) { diff --git a/DuckDuckGo/TextZoomCoordinator.swift b/DuckDuckGo/TextZoomCoordinator.swift index 8f3b7db8d3..aadf9c4f9b 100644 --- a/DuckDuckGo/TextZoomCoordinator.swift +++ b/DuckDuckGo/TextZoomCoordinator.swift @@ -25,17 +25,23 @@ import Core protocol TextZoomCoordinating { + /// Based on .textZoom feature flag var isEnabled: Bool { get } + + /// Storeage for setting and domain specific values var storage: TextZoomStoring { get } + // MARK: Applying the text zoom + func onWebViewCreated(applyToWebView webView: WKWebView) func onNavigationCommitted(applyToWebView webView: WKWebView) - func onShowTextZoomEditor(inController controller: UIViewController, forWebView webView: WKWebView) func onTextZoomChange(applyToWebView webView: WKWebView) + + // MARK: Support operations for the UI + func onShowTextZoomEditor(inController controller: UIViewController, forWebView webView: WKWebView) func makeBrowsingMenuEntry(forLink: Link, inController controller: UIViewController, forWebView webView: WKWebView) -> BrowsingMenuEntry? } -// TODO validate wikipedia which had a hardcoded exception final class TextZoomCoordinator: TextZoomCoordinating { let appSettings: AppSettings @@ -43,7 +49,8 @@ final class TextZoomCoordinator: TextZoomCoordinating { let featureFlagger: FeatureFlagger var isEnabled: Bool { - featureFlagger.isFeatureOn(.textZoom) + // TODO featureFlagger.isFeatureOn(.textZoom) + true } init(appSettings: AppSettings, storage: TextZoomStoring, featureFlagger: FeatureFlagger) { @@ -52,12 +59,19 @@ final class TextZoomCoordinator: TextZoomCoordinating { self.featureFlagger = featureFlagger } + func onWebViewCreated(applyToWebView webView: WKWebView) { + applyTextZoom(webView) + } + func onNavigationCommitted(applyToWebView webView: WKWebView) { - guard isEnabled else { return } - // TODO logic from textsize.js + applyTextZoom(webView) } func onTextZoomChange(applyToWebView webView: WKWebView) { + applyTextZoom(webView) + } + + private func applyTextZoom(_ webView: WKWebView) { guard isEnabled else { return } let domain = TLD().eTLDplus1(webView.url?.host) ?? "" @@ -65,7 +79,11 @@ final class TextZoomCoordinator: TextZoomCoordinating { let level = storage.textZoomLevelForDomain(domain) // And if there's no setting for whatever domain is passed in, use the app default ?? appSettings.defaultTextZoomLevel - webView.applyViewScale(CGFloat(level.rawValue) / 100) + + let dynamicTypeScalePercentage = UIFontMetrics.default.scaledValue(for: 1.0) + let viewScale = CGFloat(level.rawValue) / 100 * dynamicTypeScalePercentage + + webView.applyViewScale(viewScale) } @MainActor @@ -92,7 +110,7 @@ final class TextZoomCoordinator: TextZoomCoordinating { zoomController.sheetPresentationController?.detents = [.medium()] } - zoomController.present(controller, animated: true) + controller.present(zoomController, animated: true) } func makeBrowsingMenuEntry(forLink: Link, @@ -114,7 +132,12 @@ final class TextZoomCoordinator: TextZoomCoordinating { extension WKWebView { func applyViewScale(_ scale: CGFloat) { - // TODO + let key = "viewScale" + guard responds(to: NSSelectorFromString("_\(key)")) else { + assertionFailure("viewScale API has changed") + return + } + setValue(scale, forKey: key) } } From a8c4ef2807ce759e29c0542611445d045d673ead Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 31 Oct 2024 17:31:16 +0000 Subject: [PATCH 20/34] show percent in menu when appropriate. if set back to app default remove entry from storage --- DuckDuckGo/TextZoomController.swift | 8 +-- DuckDuckGo/TextZoomCoordinator.swift | 68 ++++++++++++++++++------- DuckDuckGo/TextZoomEditorModel.swift | 12 ++--- DuckDuckGo/TextZoomStorage.swift | 5 ++ DuckDuckGo/UserText.swift | 7 ++- DuckDuckGo/en.lproj/Localizable.strings | 5 +- 6 files changed, 75 insertions(+), 30 deletions(-) diff --git a/DuckDuckGo/TextZoomController.swift b/DuckDuckGo/TextZoomController.swift index 1f6306375d..e175c81d2a 100644 --- a/DuckDuckGo/TextZoomController.swift +++ b/DuckDuckGo/TextZoomController.swift @@ -22,12 +22,12 @@ import SwiftUI class TextZoomController: UIHostingController { - let storage: TextZoomStoring + let coordinator: TextZoomCoordinating let model: TextZoomEditorModel - @MainActor init(domain: String, storage: TextZoomStoring, defaultTextZoom: TextZoomLevel) { - self.storage = storage - self.model = TextZoomEditorModel(domain: domain, storage: storage, defaultTextZoom: defaultTextZoom) + @MainActor init(domain: String, coordinator: TextZoomCoordinating, defaultTextZoom: TextZoomLevel) { + self.coordinator = coordinator + self.model = TextZoomEditorModel(domain: domain, coordinator: coordinator, defaultTextZoom: defaultTextZoom) super.init(rootView: TextZoomEditorView(model: model)) } diff --git a/DuckDuckGo/TextZoomCoordinator.swift b/DuckDuckGo/TextZoomCoordinator.swift index aadf9c4f9b..1c144efaef 100644 --- a/DuckDuckGo/TextZoomCoordinator.swift +++ b/DuckDuckGo/TextZoomCoordinator.swift @@ -23,21 +23,34 @@ import Common import BrowserServicesKit import Core +/// Central point for coordinating text zoom activities. +/// * Host is used to represent unaltered host from a URL. Domain is a normalised host. protocol TextZoomCoordinating { /// Based on .textZoom feature flag var isEnabled: Bool { get } - /// Storeage for setting and domain specific values - var storage: TextZoomStoring { get } + /// @return The zoom level for a host or the current default if there isn't one. Uses eTLDplus1 to determine the domain. + func textZoomLevel(forHost host: String?) -> TextZoomLevel - // MARK: Applying the text zoom + /// Sets the text zoom level for a host. Uses eLTDplus1 to determine the domain. + /// If the level matches the global default then this specific level for the host is forgotten. + func set(textZoomLevel level: TextZoomLevel, forHost host: String?) + + /// Applies appropriate text zoom to webview on creation,. Does nothing if feature is disabled. func onWebViewCreated(applyToWebView webView: WKWebView) + + /// Applies appropriate text zoom when navigation is committed. Does nothing if feature is disabled. func onNavigationCommitted(applyToWebView webView: WKWebView) + + /// Applies appropriate text zoom to webview when the text zoom has changed (e.g. in settings or for the current tab). + /// Does nothing if feature is disabled. func onTextZoomChange(applyToWebView webView: WKWebView) - // MARK: Support operations for the UI - func onShowTextZoomEditor(inController controller: UIViewController, forWebView webView: WKWebView) + /// Shows a text zoom editor for the current webview. Does nothing if the feature is disabled. + func showTextZoomEditor(inController controller: UIViewController, forWebView webView: WKWebView) + + /// Creates a browsing menu entry for the given link. Returns nil if the feature is disabled. func makeBrowsingMenuEntry(forLink: Link, inController controller: UIViewController, forWebView webView: WKWebView) -> BrowsingMenuEntry? } @@ -59,6 +72,23 @@ final class TextZoomCoordinator: TextZoomCoordinating { self.featureFlagger = featureFlagger } + func textZoomLevel(forHost host: String?) -> TextZoomLevel { + let domain = TLD().eTLDplus1(host) ?? "" + // If the webview returns no host then there won't be a setting for a blank string anyway. + return storage.textZoomLevelForDomain(domain) + // And if there's no setting for whatever domain is passed in, use the app default + ?? appSettings.defaultTextZoomLevel + } + + func set(textZoomLevel level: TextZoomLevel, forHost host: String?) { + guard let domain = TLD().eTLDplus1(host) else { return } + if level == appSettings.defaultTextZoomLevel { + storage.removeTextZoomLevel(forDomain: domain) + } else { + storage.set(textZoomLevel: level, forDomain: domain) + } + } + func onWebViewCreated(applyToWebView webView: WKWebView) { applyTextZoom(webView) } @@ -73,27 +103,20 @@ final class TextZoomCoordinator: TextZoomCoordinating { private func applyTextZoom(_ webView: WKWebView) { guard isEnabled else { return } - - let domain = TLD().eTLDplus1(webView.url?.host) ?? "" - // If the webview returns no host then there won't be a setting for a blank string anyway. - let level = storage.textZoomLevelForDomain(domain) - // And if there's no setting for whatever domain is passed in, use the app default - ?? appSettings.defaultTextZoomLevel - + let level = textZoomLevel(forHost: webView.url?.host) let dynamicTypeScalePercentage = UIFontMetrics.default.scaledValue(for: 1.0) let viewScale = CGFloat(level.rawValue) / 100 * dynamicTypeScalePercentage - webView.applyViewScale(viewScale) } @MainActor - func onShowTextZoomEditor(inController controller: UIViewController, forWebView webView: WKWebView) { + func showTextZoomEditor(inController controller: UIViewController, forWebView webView: WKWebView) { guard isEnabled else { return } guard let domain = TLD().eTLDplus1(webView.url?.host) else { return } let zoomController = TextZoomController( domain: domain, - storage: storage, + coordinator: self, defaultTextZoom: appSettings.defaultTextZoomLevel ) @@ -113,16 +136,25 @@ final class TextZoomCoordinator: TextZoomCoordinating { controller.present(zoomController, animated: true) } - func makeBrowsingMenuEntry(forLink: Link, + func makeBrowsingMenuEntry(forLink link: Link, inController controller: UIViewController, forWebView webView: WKWebView) -> BrowsingMenuEntry? { guard isEnabled else { return nil } - return BrowsingMenuEntry.regular(name: UserText.textZoomMenuItem, + + let label: String + if let domain = TLD().eTLDplus1(link.url.host), + let level = storage.textZoomLevelForDomain(domain) { + label = UserText.textZoomWithPercentForMenuItem(level.rawValue) + } else { + label = UserText.textZoomMenuItem + } + + return BrowsingMenuEntry.regular(name: label, image: UIImage(named: "Type-Size-16")!, showNotificationDot: false) { [weak self, weak controller, weak webView] in guard let self = self, let controller = controller, let webView = webView else { return } Task { @MainActor in - self.onShowTextZoomEditor(inController: controller, forWebView: webView) + self.showTextZoomEditor(inController: controller, forWebView: webView) Pixel.fire(pixel: .browsingMenuZoom) } } diff --git a/DuckDuckGo/TextZoomEditorModel.swift b/DuckDuckGo/TextZoomEditorModel.swift index 91dd20cc43..877c4953cd 100644 --- a/DuckDuckGo/TextZoomEditorModel.swift +++ b/DuckDuckGo/TextZoomEditorModel.swift @@ -23,7 +23,7 @@ import Core class TextZoomEditorModel: ObservableObject { let domain: String - let storage: TextZoomStoring + let coordinator: TextZoomCoordinating let initialValue: TextZoomLevel var valueAsPercent: Int { @@ -38,10 +38,10 @@ class TextZoomEditorModel: ObservableObject { @Published var title: String = "" - init(domain: String, storage: TextZoomStoring, defaultTextZoom: TextZoomLevel) { + init(domain: String, coordinator: TextZoomCoordinating, defaultTextZoom: TextZoomLevel) { self.domain = domain - self.storage = storage - self.initialValue = (storage.textZoomLevelForDomain(domain) ?? defaultTextZoom) + self.coordinator = coordinator + self.initialValue = coordinator.textZoomLevel(forHost: domain) value = TextZoomLevel.allCases.firstIndex(of: initialValue) ?? 0 } @@ -55,7 +55,7 @@ class TextZoomEditorModel: ObservableObject { private func valueWasSet() { title = UserText.textZoomWithPercentSheetTitle(TextZoomLevel.allCases[value].rawValue) - storage.set(textZoomLevel: TextZoomLevel.allCases[value], forDomain: domain) + coordinator.set(textZoomLevel: TextZoomLevel.allCases[value], forHost: domain) NotificationCenter.default.post( name: AppUserDefaults.Notifications.textSizeChange, object: nil) @@ -67,7 +67,7 @@ class TextZoomEditorModel: ObservableObject { Pixel.fire(.zoomChangedOnPage, withAdditionalParameters: [ PixelParameters.textSizeInitial: String(initialValue.rawValue), PixelParameters.textSizeUpdated: String(TextZoomLevel.allCases[value].rawValue), - ]) + ]) } } diff --git a/DuckDuckGo/TextZoomStorage.swift b/DuckDuckGo/TextZoomStorage.swift index fd937e882f..80920b380c 100644 --- a/DuckDuckGo/TextZoomStorage.swift +++ b/DuckDuckGo/TextZoomStorage.swift @@ -24,6 +24,7 @@ import Common protocol TextZoomStoring { func textZoomLevelForDomain(_ domain: String) -> TextZoomLevel? func set(textZoomLevel: TextZoomLevel, forDomain domain: String) + func removeTextZoomLevel(forDomain domain: String) func resetTextZoomLevels(excludingDomains: [String]) } @@ -43,6 +44,10 @@ class TextZoomStorage: TextZoomStoring { textZoomLevels[domain] = textZoomLevel.rawValue } + func removeTextZoomLevel(forDomain domain: String) { + textZoomLevels.removeValue(forKey: domain) + } + func resetTextZoomLevels(excludingDomains: [String]) { let tld = TLD() textZoomLevels = textZoomLevels.filter { level in diff --git a/DuckDuckGo/UserText.swift b/DuckDuckGo/UserText.swift index 888eae2786..c2e17a3e92 100644 --- a/DuckDuckGo/UserText.swift +++ b/DuckDuckGo/UserText.swift @@ -361,7 +361,12 @@ public struct UserText { public static let textZoomMenuItem = NSLocalizedString("action.text-zoom-sheet-menu-item", value: "Zoom", comment: "Text zoom menu item") public static func textZoomWithPercentSheetTitle(_ percent: Int) -> String { - let message = NSLocalizedString("action.text-zoom-sheet-title", value: "Zoom Text (%d%%)", comment: "Zoom text sheet title showing currently set zoom level as a percent. '%d' represets the number that will be used, e.g. 56") + let message = NSLocalizedString("action.text-zoom-sheet-title", value: "Zoom Text (%d%%)", comment: "Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please.") + return message.format(arguments: percent) + } + + public static func textZoomWithPercentForMenuItem(_ percent: Int) -> String { + let message = NSLocalizedString("action.text-zoom-menu-item", value: "Zoom (%d%%)", comment: "Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please.") return message.format(arguments: percent) } diff --git a/DuckDuckGo/en.lproj/Localizable.strings b/DuckDuckGo/en.lproj/Localizable.strings index 5d7549d24f..f002b90b41 100644 --- a/DuckDuckGo/en.lproj/Localizable.strings +++ b/DuckDuckGo/en.lproj/Localizable.strings @@ -13,10 +13,13 @@ /* Button label for OK action */ "action.ok" = "OK"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Zoom (%d%%)"; + /* Text zoom menu item */ "action.text-zoom-sheet-menu-item" = "Zoom"; -/* Zoom text sheet title showing currently set zoom level as a percent. '%d' represets the number that will be used, e.g. 56 */ +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ "action.text-zoom-sheet-title" = "Zoom Text (%d%%)"; /* Add action - button shown in alert */ From 06a128dc5a679bac73b8b5163c8e6eeed0e2dabc Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Fri, 1 Nov 2024 14:43:13 +0000 Subject: [PATCH 21/34] fix tests --- DuckDuckGo.xcodeproj/project.pbxproj | 8 ++--- DuckDuckGo/MainViewController.swift | 7 ++--- DuckDuckGo/SettingsViewModel.swift | 4 +-- DuckDuckGo/TabManager.swift | 4 +-- DuckDuckGo/TextZoomCoordinator.swift | 7 +++++ DuckDuckGoTests/MockTabDelegate.swift | 4 +-- ...ge.swift => MockTextZoomCoordinator.swift} | 30 +++++++++++++++---- .../OnboardingDaxFavouritesTests.swift | 3 +- .../OnboardingNavigationDelegateTests.swift | 3 +- 9 files changed, 49 insertions(+), 21 deletions(-) rename DuckDuckGoTests/{MockDomainTextZoomStorage.swift => MockTextZoomCoordinator.swift} (51%) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index de2819560f..7f26652246 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -530,7 +530,7 @@ 85AE668E2097206E0014CF04 /* NotificationView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 85AE668D2097206E0014CF04 /* NotificationView.xib */; }; 85AE6690209724120014CF04 /* NotificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AE668F209724120014CF04 /* NotificationView.swift */; }; 85AFA1212B45D14F0028A504 /* BookmarksMigrationAssertionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AFA1202B45D14F0028A504 /* BookmarksMigrationAssertionTests.swift */; }; - 85B49AFD2CD392ED007FAA2A /* MockDomainTextZoomStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85B49AFC2CD392ED007FAA2A /* MockDomainTextZoomStorage.swift */; }; + 85B49AFD2CD392ED007FAA2A /* MockTextZoomCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85B49AFC2CD392ED007FAA2A /* MockTextZoomCoordinator.swift */; }; 85B9814E2B5EB618009AC9A6 /* SwipeTabsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85B9814D2B5EB618009AC9A6 /* SwipeTabsCoordinator.swift */; }; 85B9CB8921AEBDD5009001F1 /* FavoriteHomeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85B9CB8821AEBDD5009001F1 /* FavoriteHomeCell.swift */; }; 85BA58551F34F49E00C6E8CA /* AppUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85BA58541F34F49E00C6E8CA /* AppUserDefaults.swift */; }; @@ -1831,7 +1831,7 @@ 85AE668D2097206E0014CF04 /* NotificationView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NotificationView.xib; sourceTree = ""; }; 85AE668F209724120014CF04 /* NotificationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationView.swift; sourceTree = ""; }; 85AFA1202B45D14F0028A504 /* BookmarksMigrationAssertionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksMigrationAssertionTests.swift; sourceTree = ""; }; - 85B49AFC2CD392ED007FAA2A /* MockDomainTextZoomStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDomainTextZoomStorage.swift; sourceTree = ""; }; + 85B49AFC2CD392ED007FAA2A /* MockTextZoomCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockTextZoomCoordinator.swift; sourceTree = ""; }; 85B9814D2B5EB618009AC9A6 /* SwipeTabsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeTabsCoordinator.swift; sourceTree = ""; }; 85B9CB8821AEBDD5009001F1 /* FavoriteHomeCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteHomeCell.swift; sourceTree = ""; }; 85BA58541F34F49E00C6E8CA /* AppUserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppUserDefaults.swift; sourceTree = ""; }; @@ -6039,7 +6039,7 @@ 9F69331C2C5A191400CD6A5D /* MockTutorialSettings.swift */, 852409302C78030D00CB28FC /* MockUsageSegmentation.swift */, 4B27FBB72C93F53B007E21A7 /* MockPersistentPixel.swift */, - 85B49AFC2CD392ED007FAA2A /* MockDomainTextZoomStorage.swift */, + 85B49AFC2CD392ED007FAA2A /* MockTextZoomCoordinator.swift */, ); name = Mocks; sourceTree = ""; @@ -7967,7 +7967,7 @@ 83EDCC411F86B89C005CDFCD /* StatisticsLoaderTests.swift in Sources */, 564DE4572C4150E600D23241 /* NewTabPageControllerDaxDialogTests.swift in Sources */, C14882E327F20D9A00D59F0C /* BookmarksExporterTests.swift in Sources */, - 85B49AFD2CD392ED007FAA2A /* MockDomainTextZoomStorage.swift in Sources */, + 85B49AFD2CD392ED007FAA2A /* MockTextZoomCoordinator.swift in Sources */, 85C29708247BDD060063A335 /* DaxDialogsBrowsingSpecTests.swift in Sources */, 9FE05CF12C36468A00D9046B /* OnboardingPixelReporterTests.swift in Sources */, 9FDEC7B42C8FD62F00C7A692 /* OnboardingAddressBarPositionPickerViewModelTests.swift in Sources */, diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index cabdaedfb1..ef1e36e771 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -175,7 +175,7 @@ class MainViewController: UIViewController { } let preserveLogins: PreserveLogins - let textZoomCoordinator: TextZoomCoordinator + let textZoomCoordinator: TextZoomCoordinating var historyManager: HistoryManaging var viewCoordinator: MainViewCoordinator! @@ -203,7 +203,7 @@ class MainViewController: UIViewController { featureFlagger: FeatureFlagger, preserveLogins: PreserveLogins = .shared, subscriptionCookieManager: SubscriptionCookieManaging, - textZoomCoordinator: TextZoomCoordinator + textZoomCoordinator: TextZoomCoordinating ) { self.bookmarksDatabase = bookmarksDatabase self.bookmarksDatabaseCleaner = bookmarksDatabaseCleaner @@ -2727,8 +2727,7 @@ extension MainViewController: AutoClearWorker { private func forgetTextZoom() { let allowedDomains = preserveLogins.allowedDomains - // TODO call a function instead - textZoomCoordinator.storage.resetTextZoomLevels(excludingDomains: allowedDomains) + textZoomCoordinator.resetTextZoomLevels(excludingDomains: allowedDomains) } } diff --git a/DuckDuckGo/SettingsViewModel.swift b/DuckDuckGo/SettingsViewModel.swift index faf269b483..8444b39d5a 100644 --- a/DuckDuckGo/SettingsViewModel.swift +++ b/DuckDuckGo/SettingsViewModel.swift @@ -43,7 +43,7 @@ final class SettingsViewModel: ObservableObject { var emailManager: EmailManager { EmailManager() } private let historyManager: HistoryManaging let privacyProDataReporter: PrivacyProDataReporting? - let textZoomCoordinator: TextZoomCoordinator + let textZoomCoordinator: TextZoomCoordinating // Subscription Dependencies private let subscriptionManager: SubscriptionManager @@ -386,7 +386,7 @@ final class SettingsViewModel: ObservableObject { historyManager: HistoryManaging, syncPausedStateManager: any SyncPausedStateManaging, privacyProDataReporter: PrivacyProDataReporting, - textZoomCoordinator: TextZoomCoordinator) { + textZoomCoordinator: TextZoomCoordinating) { self.state = SettingsState.defaults self.legacyViewProvider = legacyViewProvider diff --git a/DuckDuckGo/TabManager.swift b/DuckDuckGo/TabManager.swift index 99d02bfbc7..cef7d139ef 100644 --- a/DuckDuckGo/TabManager.swift +++ b/DuckDuckGo/TabManager.swift @@ -43,7 +43,7 @@ class TabManager { private let contextualOnboardingLogic: ContextualOnboardingLogic private let onboardingPixelReporter: OnboardingPixelReporting private let featureFlagger: FeatureFlagger - private let textZoomCoordinator: TextZoomCoordinator + private let textZoomCoordinator: TextZoomCoordinating private let subscriptionCookieManager: SubscriptionCookieManaging private let appSettings: AppSettings @@ -66,7 +66,7 @@ class TabManager { featureFlagger: FeatureFlagger, subscriptionCookieManager: SubscriptionCookieManaging, appSettings: AppSettings, - textZoomCoordinator: TextZoomCoordinator) { + textZoomCoordinator: TextZoomCoordinating) { self.model = model self.previewsSource = previewsSource self.bookmarksDatabase = bookmarksDatabase diff --git a/DuckDuckGo/TextZoomCoordinator.swift b/DuckDuckGo/TextZoomCoordinator.swift index 1c144efaef..e1e43bbcd2 100644 --- a/DuckDuckGo/TextZoomCoordinator.swift +++ b/DuckDuckGo/TextZoomCoordinator.swift @@ -37,6 +37,9 @@ protocol TextZoomCoordinating { /// If the level matches the global default then this specific level for the host is forgotten. func set(textZoomLevel level: TextZoomLevel, forHost host: String?) + /// Reset, ie 'forget', the saved zoom levels for all domains except the ones specified. + func resetTextZoomLevels(excludingDomains: [String]) + /// Applies appropriate text zoom to webview on creation,. Does nothing if feature is disabled. func onWebViewCreated(applyToWebView webView: WKWebView) @@ -89,6 +92,10 @@ final class TextZoomCoordinator: TextZoomCoordinating { } } + func resetTextZoomLevels(excludingDomains domains: [String]) { + storage.resetTextZoomLevels(excludingDomains: domains) + } + func onWebViewCreated(applyToWebView webView: WKWebView) { applyTextZoom(webView) } diff --git a/DuckDuckGoTests/MockTabDelegate.swift b/DuckDuckGoTests/MockTabDelegate.swift index 83c997d79e..fefb80faa7 100644 --- a/DuckDuckGoTests/MockTabDelegate.swift +++ b/DuckDuckGoTests/MockTabDelegate.swift @@ -137,8 +137,8 @@ extension TabViewController { onboardingPixelReporter: contextualOnboardingPixelReporter, urlCredentialCreator: MockCredentialCreator(), featureFlagger: featureFlagger, - domainTextZoomStorage: MockDomainTextZoomStorage(), - subscriptionCookieManager: SubscriptionCookieManagerMock() + subscriptionCookieManager: SubscriptionCookieManagerMock(), + textZoomCoordinator: MockTextZoomCoordinator() ) tab.attachWebView(configuration: .nonPersistent(), andLoadRequest: nil, consumeCookies: false, customWebView: customWebView) return tab diff --git a/DuckDuckGoTests/MockDomainTextZoomStorage.swift b/DuckDuckGoTests/MockTextZoomCoordinator.swift similarity index 51% rename from DuckDuckGoTests/MockDomainTextZoomStorage.swift rename to DuckDuckGoTests/MockTextZoomCoordinator.swift index 328d321368..4499b2b064 100644 --- a/DuckDuckGoTests/MockDomainTextZoomStorage.swift +++ b/DuckDuckGoTests/MockTextZoomCoordinator.swift @@ -19,14 +19,34 @@ import Foundation @testable import DuckDuckGo +import Core +import WebKit -class MockDomainTextZoomStorage: DomainTextZoomStoring { +class MockTextZoomCoordinator: TextZoomCoordinating { - func textZoomLevelForDomain(_ domain: String) -> DuckDuckGo.TextZoomLevel? { - return nil - } + let isEnabled: Bool = true - func set(textZoomLevel: DuckDuckGo.TextZoomLevel, forDomain domain: String) { + func textZoomLevel(forHost host: String?) -> TextZoomLevel { + return .percent100 + } + + func set(textZoomLevel level: DuckDuckGo.TextZoomLevel, forHost host: String?) { + } + + func onWebViewCreated(applyToWebView webView: WKWebView) { + } + + func onNavigationCommitted(applyToWebView webView: WKWebView) { + } + + func onTextZoomChange(applyToWebView webView: WKWebView) { + } + + func showTextZoomEditor(inController controller: UIViewController, forWebView webView: WKWebView) { + } + + func makeBrowsingMenuEntry(forLink: Link, inController controller: UIViewController, forWebView webView: WKWebView) -> BrowsingMenuEntry? { + return nil } func resetTextZoomLevels(excludingDomains: [String]) { diff --git a/DuckDuckGoTests/OnboardingDaxFavouritesTests.swift b/DuckDuckGoTests/OnboardingDaxFavouritesTests.swift index 0d201b0e5c..99ad0e1b60 100644 --- a/DuckDuckGoTests/OnboardingDaxFavouritesTests.swift +++ b/DuckDuckGoTests/OnboardingDaxFavouritesTests.swift @@ -81,7 +81,8 @@ final class OnboardingDaxFavouritesTests: XCTestCase { subscriptionFeatureAvailability: SubscriptionFeatureAvailabilityMock.enabled, voiceSearchHelper: MockVoiceSearchHelper(isSpeechRecognizerAvailable: true, voiceSearchEnabled: true), featureFlagger: MockFeatureFlagger(), - subscriptionCookieManager: SubscriptionCookieManagerMock() + subscriptionCookieManager: SubscriptionCookieManagerMock(), + textZoomCoordinator: MockTextZoomCoordinator() ) let window = UIWindow(frame: UIScreen.main.bounds) window.rootViewController = UIViewController() diff --git a/DuckDuckGoTests/OnboardingNavigationDelegateTests.swift b/DuckDuckGoTests/OnboardingNavigationDelegateTests.swift index 68c0c56af6..3f1762975b 100644 --- a/DuckDuckGoTests/OnboardingNavigationDelegateTests.swift +++ b/DuckDuckGoTests/OnboardingNavigationDelegateTests.swift @@ -79,7 +79,8 @@ final class OnboardingNavigationDelegateTests: XCTestCase { subscriptionFeatureAvailability: SubscriptionFeatureAvailabilityMock.enabled, voiceSearchHelper: MockVoiceSearchHelper(isSpeechRecognizerAvailable: true, voiceSearchEnabled: true), featureFlagger: MockFeatureFlagger(), - subscriptionCookieManager: SubscriptionCookieManagerMock()) + subscriptionCookieManager: SubscriptionCookieManagerMock(), + textZoomCoordinator: MockTextZoomCoordinator()) let window = UIWindow(frame: UIScreen.main.bounds) window.rootViewController = UIViewController() window.makeKeyAndVisible() From b6e0461be6b0f1a0eb0530d15bc90745e042253f Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Fri, 1 Nov 2024 20:02:23 +0000 Subject: [PATCH 22/34] unit tests for text zoom coordinator --- DuckDuckGo.xcodeproj/project.pbxproj | 14 +- DuckDuckGo/TextZoomCoordinator.swift | 3 +- DuckDuckGoTests/MockFeatureFlagger.swift | 5 +- DuckDuckGoTests/TextZoomTests.swift | 192 +++++++++++++++++++++++ 4 files changed, 210 insertions(+), 4 deletions(-) create mode 100644 DuckDuckGoTests/TextZoomTests.swift diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 7f26652246..8244903b59 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -519,6 +519,7 @@ 8590CB632684F10F0089F6BF /* ContentBlockerProtectionStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8590CB622684F10F0089F6BF /* ContentBlockerProtectionStoreTests.swift */; }; 8590CB67268A2E520089F6BF /* RootDebugViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8590CB66268A2E520089F6BF /* RootDebugViewController.swift */; }; 8590CB69268A4E190089F6BF /* DebugEtagStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8590CB68268A4E190089F6BF /* DebugEtagStorage.swift */; }; + 8590E8222CD54620006904BF /* TextZoomTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8590E8202CD53767006904BF /* TextZoomTests.swift */; }; 8596C30D2B7EB1800058EF90 /* DataStoreWarmup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8596C30C2B7EB1800058EF90 /* DataStoreWarmup.swift */; }; 8598F67B2405EB8D00FBC70C /* KeyboardSettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8598F6792405EB8600FBC70C /* KeyboardSettingsTests.swift */; }; 8599690F29D2F1C100DBF9FA /* DDGSync in Frameworks */ = {isa = PBXBuildFile; productRef = 8599690E29D2F1C100DBF9FA /* DDGSync */; }; @@ -1820,6 +1821,7 @@ 8590CB622684F10F0089F6BF /* ContentBlockerProtectionStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentBlockerProtectionStoreTests.swift; sourceTree = ""; }; 8590CB66268A2E520089F6BF /* RootDebugViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootDebugViewController.swift; sourceTree = ""; }; 8590CB68268A4E190089F6BF /* DebugEtagStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugEtagStorage.swift; sourceTree = ""; }; + 8590E8202CD53767006904BF /* TextZoomTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextZoomTests.swift; sourceTree = ""; }; 8596C30C2B7EB1800058EF90 /* DataStoreWarmup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStoreWarmup.swift; sourceTree = ""; }; 8598F6792405EB8600FBC70C /* KeyboardSettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardSettingsTests.swift; sourceTree = ""; }; 859DA3312CCAC0A300C90694 /* TextZoomController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextZoomController.swift; sourceTree = ""; }; @@ -4448,6 +4450,14 @@ name = iPad; sourceTree = ""; }; + 8590E81F2CD5374C006904BF /* TextZoom */ = { + isa = PBXGroup; + children = ( + 8590E8202CD53767006904BF /* TextZoomTests.swift */, + ); + name = TextZoom; + sourceTree = ""; + }; 8595BF491FE847EB00F692EC /* ios-js-support */ = { isa = PBXGroup; children = ( @@ -5756,7 +5766,6 @@ F12D98401F266B30003C2EE3 /* DuckDuckGo */ = { isa = PBXGroup; children = ( - 6F03CAFF2C32ED22004179A8 /* NewTabPage */, 6FF9157F2B88E04F0042AC87 /* AdAttribution */, F17669A21E411D63003D3222 /* Application */, 981FED7222045FFA008488D7 /* AutoClear */, @@ -5770,12 +5779,14 @@ 8588026724E4249800C24AB6 /* iPad */, 851DFD88212C5ED600D95F20 /* Main */, EE56DE3A2A6038F500375C41 /* NetworkProtection */, + 6F03CAFF2C32ED22004179A8 /* NewTabPage */, F1D477C71F2139210031ED49 /* OmniBar */, 9F23B8042C2BE20500950875 /* Onboarding */, 98EA2C3F218BB5140023E1DC /* Settings */, F1BDDBFC2C340D9C00459306 /* Subscription */, 569437222BDD402600C0881B /* Sync */, F13B4BF71F18C9E800814661 /* Tabs */, + 8590E81F2CD5374C006904BF /* TextZoom */, 98EA2C3A218B9A880023E1DC /* Themes */, F12790DD1EBBDDF3001D3AEC /* Tutorials */, CB48D3342B90CEBD00631D8B /* UserBehaviorMonitor */, @@ -8041,6 +8052,7 @@ 6F934F862C58DB00008364E4 /* NewTabPageSettingsPersistentStorageTests.swift in Sources */, 987130C5294AAB9F00AB05E0 /* BookmarkEditorViewModelTests.swift in Sources */, BDFF03262BA3DA4900F324C9 /* NetworkProtectionFeatureVisibilityTests.swift in Sources */, + 8590E8222CD54620006904BF /* TextZoomTests.swift in Sources */, 0283A2042C6E572F00508FBD /* BrokenSitePromptLimiterTests.swift in Sources */, 9F8E0F332CCA642D001EA7C5 /* VideoPlayerViewModelTests.swift in Sources */, D62EC3BA2C246A7000FC9D04 /* YoutublePlayerNavigationHandlerTests.swift in Sources */, diff --git a/DuckDuckGo/TextZoomCoordinator.swift b/DuckDuckGo/TextZoomCoordinator.swift index e1e43bbcd2..3aec4d1ae2 100644 --- a/DuckDuckGo/TextZoomCoordinator.swift +++ b/DuckDuckGo/TextZoomCoordinator.swift @@ -65,8 +65,7 @@ final class TextZoomCoordinator: TextZoomCoordinating { let featureFlagger: FeatureFlagger var isEnabled: Bool { - // TODO featureFlagger.isFeatureOn(.textZoom) - true + featureFlagger.isFeatureOn(.textZoom) } init(appSettings: AppSettings, storage: TextZoomStoring, featureFlagger: FeatureFlagger) { diff --git a/DuckDuckGoTests/MockFeatureFlagger.swift b/DuckDuckGoTests/MockFeatureFlagger.swift index 1d2c8d642b..f99aa5d9e4 100644 --- a/DuckDuckGoTests/MockFeatureFlagger.swift +++ b/DuckDuckGoTests/MockFeatureFlagger.swift @@ -22,7 +22,10 @@ import Core final class MockFeatureFlagger: FeatureFlagger { var enabledFeatureFlags: [FeatureFlag] = [] - var enabledFeatureFlag: FeatureFlag? + + init(enabledFeatureFlags: [FeatureFlag] = []) { + self.enabledFeatureFlags = enabledFeatureFlags + } func isFeatureOn(forProvider provider: F) -> Bool where F: BrowserServicesKit.FeatureFlagSourceProviding { guard let flag = provider as? FeatureFlag else { diff --git a/DuckDuckGoTests/TextZoomTests.swift b/DuckDuckGoTests/TextZoomTests.swift new file mode 100644 index 0000000000..ca4974ee10 --- /dev/null +++ b/DuckDuckGoTests/TextZoomTests.swift @@ -0,0 +1,192 @@ +// +// TextZoomTests.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +@testable import DuckDuckGo +import BrowserServicesKit +import Core +import XCTest +import WebKit + +final class TextZoomTests: XCTestCase { + + let viewScaleKey = "viewScale" + + func testZoomLevelAppliedToWebView() { + let storage = TextZoomStorage() + storage.textZoomLevels = [:] + + let coordinator: TextZoomCoordinating = makeTextZoomCoordinator(storage: storage) + let webView = URLFixedWebView(frame: .zero, configuration: .nonPersistent()) + + webView.setValue(0.1, forKey: viewScaleKey) + coordinator.onNavigationCommitted(applyToWebView: webView) + XCTAssertEqual(1.0, webView.value(forKey: viewScaleKey) as? Double) + + webView.setValue(0.1, forKey: viewScaleKey) + coordinator.onTextZoomChange(applyToWebView: webView) + XCTAssertEqual(1.0, webView.value(forKey: viewScaleKey) as? Double) + + webView.setValue(0.1, forKey: viewScaleKey) + coordinator.onWebViewCreated(applyToWebView: webView) + XCTAssertEqual(1.0, webView.value(forKey: viewScaleKey) as? Double) + + let host = "example.com" + webView.fixed = URL(string: "https://\(host)") + coordinator.set(textZoomLevel: .percent120, forHost: host) + + webView.setValue(0.1, forKey: viewScaleKey) + coordinator.onNavigationCommitted(applyToWebView: webView) + XCTAssertEqual(1.2, webView.value(forKey: viewScaleKey) as? Double) + + webView.setValue(0.1, forKey: viewScaleKey) + coordinator.onTextZoomChange(applyToWebView: webView) + XCTAssertEqual(1.2, webView.value(forKey: viewScaleKey) as? Double) + + webView.setValue(0.1, forKey: viewScaleKey) + coordinator.onWebViewCreated(applyToWebView: webView) + XCTAssertEqual(1.2, webView.value(forKey: viewScaleKey) as? Double) + + // When reset to the default then "forget" + coordinator.set(textZoomLevel: .percent100, forHost: host) + XCTAssertEqual(storage.textZoomLevels, [:]) + } + + func testMenuItemCreation() { + let host = "example.com" + + let storage = TextZoomStorage() + storage.textZoomLevels = [:] + + let coordinator: TextZoomCoordinating = makeTextZoomCoordinator(storage: storage) + coordinator.set(textZoomLevel: .percent120, forHost: host) + + let controller = UIViewController() + let webView = WKWebView(frame: .zero, configuration: .nonPersistent()) + + let item1 = coordinator.makeBrowsingMenuEntry( + forLink: makeLink(url: URL(string: "https://other.org")!), + inController: controller, + forWebView: webView) + + // Expecting the 'default' value + if case .regular(let name, _, _, _, _) = item1 { + XCTAssertEqual(UserText.textZoomMenuItem, name) + } else { + XCTFail("Unexpected menu item type") + } + + let item2 = coordinator.makeBrowsingMenuEntry( + forLink: makeLink(url: URL(string: "https://\(host)")!), + inController: controller, + forWebView: webView) + + // Expecting the menu item to include the percent + if case .regular(let name, _, _, _, _) = item2 { + XCTAssertEqual(UserText.textZoomWithPercentForMenuItem(120), name) + } else { + XCTFail("Unexpected menu item type") + } + + } + + func testSettingAndResetingDomainTextZoomLevels() { + let host1 = "example.com" + let host2 = "another.org" + + let storage = TextZoomStorage() + storage.textZoomLevels = [:] + + let coordinator: TextZoomCoordinating = makeTextZoomCoordinator(storage: storage) + coordinator.set(textZoomLevel: .percent120, forHost: host1) + XCTAssertEqual(coordinator.textZoomLevel(forHost: host1), .percent120) + + coordinator.set(textZoomLevel: .percent140, forHost: host2) + XCTAssertEqual(coordinator.textZoomLevel(forHost: host2), .percent140) + + coordinator.resetTextZoomLevels(excludingDomains: [host1]) + XCTAssertEqual(coordinator.textZoomLevel(forHost: host1), .percent120) + XCTAssertEqual(coordinator.textZoomLevel(forHost: host2), AppSettingsMock().defaultTextZoomLevel) + } + + func testWhenFeatureFlagEnabled_ThenCoordinatorIsEnabled() { + let controller = UIViewController() + let webView = WKWebView(frame: .zero, configuration: .nonPersistent()) + webView.setValue(0.1, forKey: viewScaleKey) + XCTAssertEqual(0.1, webView.value(forKey: viewScaleKey) as? Double) + + let featureFlagger = MockFeatureFlagger() + featureFlagger.enabledFeatureFlags = [.textZoom] + let coordinator: TextZoomCoordinating = makeTextZoomCoordinator(featureFlagger: featureFlagger) + XCTAssertTrue(coordinator.isEnabled) + + featureFlagger.enabledFeatureFlags = [] + XCTAssertFalse(coordinator.isEnabled) + + coordinator.onNavigationCommitted(applyToWebView: webView) + coordinator.onTextZoomChange(applyToWebView: webView) + coordinator.onWebViewCreated(applyToWebView: webView) + XCTAssertNil(coordinator.makeBrowsingMenuEntry(forLink: makeLink(), inController: controller, forWebView: webView)) + + XCTAssertEqual(0.1, webView.value(forKey: viewScaleKey) as? Double) + } + + private func makeTextZoomCoordinator( + appSettings: AppSettings = AppSettingsMock(), + storage: TextZoomStoring = MockTextZoomStorage(), + featureFlagger: FeatureFlagger = MockFeatureFlagger(enabledFeatureFlags: [.textZoom]) + ) -> TextZoomCoordinating { + return TextZoomCoordinator(appSettings: appSettings, + storage: storage, + featureFlagger: featureFlagger) + } + + private func makeLink(title: String? = "title", url: URL = .ddg, localPath: URL? = nil) -> Link { + return Link(title: title, url: url, localPath: localPath) + } + +} + +/// Nothing else should be using storage directly so just keeping it here out of the way. +private class MockTextZoomStorage: TextZoomStoring { + + func textZoomLevelForDomain(_ domain: String) -> DuckDuckGo.TextZoomLevel? { + return nil + } + + func set(textZoomLevel: DuckDuckGo.TextZoomLevel, forDomain domain: String) { + } + + func removeTextZoomLevel(forDomain domain: String) { + } + + func resetTextZoomLevels(excludingDomains: [String]) { + } + +} + +private class URLFixedWebView: WKWebView { + + var fixed: URL? + + override var url: URL? { + fixed + } + +} From 2dd2aa46e7becfad4d2d2b2c429121175458d965 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Mon, 4 Nov 2024 14:13:01 +0000 Subject: [PATCH 23/34] swiftlint --- DuckDuckGo/TextZoomEditorModel.swift | 2 +- DuckDuckGoTests/MockTextZoomCoordinator.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DuckDuckGo/TextZoomEditorModel.swift b/DuckDuckGo/TextZoomEditorModel.swift index 877c4953cd..cc804d1317 100644 --- a/DuckDuckGo/TextZoomEditorModel.swift +++ b/DuckDuckGo/TextZoomEditorModel.swift @@ -67,7 +67,7 @@ class TextZoomEditorModel: ObservableObject { Pixel.fire(.zoomChangedOnPage, withAdditionalParameters: [ PixelParameters.textSizeInitial: String(initialValue.rawValue), PixelParameters.textSizeUpdated: String(TextZoomLevel.allCases[value].rawValue), - ]) + ]) } } diff --git a/DuckDuckGoTests/MockTextZoomCoordinator.swift b/DuckDuckGoTests/MockTextZoomCoordinator.swift index 4499b2b064..1fcaed95c3 100644 --- a/DuckDuckGoTests/MockTextZoomCoordinator.swift +++ b/DuckDuckGoTests/MockTextZoomCoordinator.swift @@ -1,5 +1,5 @@ // -// MockDomainTextZoomStorage.swift +// MockTextZoomCoordinator.swift // DuckDuckGo // // Copyright © 2024 DuckDuckGo. All rights reserved. From 24ebae7c4d7e139d5413a01ac792c39477d6ac3f Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Mon, 4 Nov 2024 23:00:35 +0000 Subject: [PATCH 24/34] update settings footer for text zoom --- DuckDuckGo/SettingsAccessibilityView.swift | 2 +- DuckDuckGo/UserText.swift | 2 +- DuckDuckGo/en.lproj/Localizable.strings | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DuckDuckGo/SettingsAccessibilityView.swift b/DuckDuckGo/SettingsAccessibilityView.swift index aaf5952bbf..66dfeaddd9 100644 --- a/DuckDuckGo/SettingsAccessibilityView.swift +++ b/DuckDuckGo/SettingsAccessibilityView.swift @@ -28,7 +28,7 @@ struct SettingsAccessibilityView: View { var body: some View { List { - Section { + Section(footer: Text(UserText.textSizeDescription)) { // Text Size if viewModel.state.textSize.enabled { SettingsPickerCellView(label: UserText.settingsText, diff --git a/DuckDuckGo/UserText.swift b/DuckDuckGo/UserText.swift index 69aef5ec89..4e167586d7 100644 --- a/DuckDuckGo/UserText.swift +++ b/DuckDuckGo/UserText.swift @@ -330,7 +330,7 @@ public struct UserText { public static let voiceSearchCancelButton = NSLocalizedString("voiceSearch.cancel", value: "Cancel", comment: "Cancel button for voice search") public static let voiceSearchFooterOld = NSLocalizedString("voiceSearch.footer.note.old", value: "Audio is processed on-device. It's not stored or shared with anyone, including DuckDuckGo.", comment: "Voice-search footer note with on-device privacy warning") public static let voiceSearchFooter = NSLocalizedString("voiceSearch.footer.note", value: "Add Private Voice Search option to the address bar. Audio is not stored or shared with anyone, including DuckDuckGo.", comment: "Voice-search footer note with on-device privacy warning") - public static let textSizeDescription = NSLocalizedString("textSize.description", value: "Choose your preferred text size. Websites you view in DuckDuckGo will adjust to it.", comment: "Description text for the text size adjustment setting") + public static let textSizeDescription = NSLocalizedString("textSize.description", value: "Automatically apply this zoom level across all websites.", comment: "Description text for the text size adjustment setting") public static func textSizeFooter(for percentage: String) -> String { let message = NSLocalizedString("textSize.footer", value: "Text Size - %@", comment: "Replacement string is a current percent value e.g. '120%'") return message.format(arguments: percentage) diff --git a/DuckDuckGo/en.lproj/Localizable.strings b/DuckDuckGo/en.lproj/Localizable.strings index 6dcec24feb..a1432cf4a3 100644 --- a/DuckDuckGo/en.lproj/Localizable.strings +++ b/DuckDuckGo/en.lproj/Localizable.strings @@ -2728,7 +2728,7 @@ But if you *do* want a peek under the hood, you can find more information about "tab.switcher.accessibility.label" = "Tab Switcher"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Choose your preferred text size. Websites you view in DuckDuckGo will adjust to it."; +"textSize.description" = "Automatically apply this zoom level across all websites."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Text Size - %@"; From 7bed09ec46d6f6fa644a58c6cdcf254ab882fa00 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 7 Nov 2024 19:21:16 +0000 Subject: [PATCH 25/34] fix ipad bug where it disables the ui --- DuckDuckGo/SettingsViewModel.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DuckDuckGo/SettingsViewModel.swift b/DuckDuckGo/SettingsViewModel.swift index 8444b39d5a..fee36bea08 100644 --- a/DuckDuckGo/SettingsViewModel.swift +++ b/DuckDuckGo/SettingsViewModel.swift @@ -423,7 +423,7 @@ extension SettingsViewModel { appIcon: AppIconManager.shared.appIcon, fireButtonAnimation: appSettings.currentFireButtonAnimation, textSize: SettingsState.TextZoom(enabled: textZoomCoordinator.isEnabled, level: appSettings.defaultTextZoomLevel), - addressBar: SettingsState.AddressBar(enabled: !isPad, position: appSettings.currentAddressBarPosition), + addressBar: SettingsState.AddressBar(enabled: true, position: appSettings.currentAddressBarPosition), showsFullURL: appSettings.showFullSiteAddress, sendDoNotSell: appSettings.sendDoNotSell, autoconsentEnabled: appSettings.autoconsentEnabled, @@ -795,7 +795,7 @@ extension SettingsViewModel { object: nil, queue: .main, using: { [weak self] _ in guard let self = self else { return } - self.state.textSize = SettingsState.TextZoom(enabled: !isPad, level: self.appSettings.defaultTextZoomLevel) + self.state.textSize = SettingsState.TextZoom(enabled: true, level: self.appSettings.defaultTextZoomLevel) }) } From 8f365e640f81e544b9d015d488f34c3a875a3a19 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 7 Nov 2024 19:33:58 +0000 Subject: [PATCH 26/34] update from ship review --- DuckDuckGo/TextZoomEditorView.swift | 2 ++ DuckDuckGo/UserText.swift | 6 +++--- DuckDuckGo/en.lproj/Localizable.strings | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/DuckDuckGo/TextZoomEditorView.swift b/DuckDuckGo/TextZoomEditorView.swift index 35cee26a2d..8e5cd8dbd8 100644 --- a/DuckDuckGo/TextZoomEditorView.swift +++ b/DuckDuckGo/TextZoomEditorView.swift @@ -31,6 +31,7 @@ struct TextZoomEditorView: View { Text(model.title) .font(Font(uiFont: .daxHeadline())) .frame(alignment: .center) + .foregroundStyle(Color(designSystemColor: .textPrimary)) Button { model.onDismiss() @@ -42,6 +43,7 @@ struct TextZoomEditorView: View { .buttonStyle(.plain) .padding(0) .frame(maxWidth: .infinity, alignment: .trailing) + .foregroundStyle(Color(designSystemColor: .textPrimary)) } .padding(.horizontal, 16) .frame(height: 56) diff --git a/DuckDuckGo/UserText.swift b/DuckDuckGo/UserText.swift index 4e167586d7..66cf271f2e 100644 --- a/DuckDuckGo/UserText.swift +++ b/DuckDuckGo/UserText.swift @@ -330,7 +330,7 @@ public struct UserText { public static let voiceSearchCancelButton = NSLocalizedString("voiceSearch.cancel", value: "Cancel", comment: "Cancel button for voice search") public static let voiceSearchFooterOld = NSLocalizedString("voiceSearch.footer.note.old", value: "Audio is processed on-device. It's not stored or shared with anyone, including DuckDuckGo.", comment: "Voice-search footer note with on-device privacy warning") public static let voiceSearchFooter = NSLocalizedString("voiceSearch.footer.note", value: "Add Private Voice Search option to the address bar. Audio is not stored or shared with anyone, including DuckDuckGo.", comment: "Voice-search footer note with on-device privacy warning") - public static let textSizeDescription = NSLocalizedString("textSize.description", value: "Automatically apply this zoom level across all websites.", comment: "Description text for the text size adjustment setting") + public static let textSizeDescription = NSLocalizedString("textSize.description", value: "Increase or decrease text size across all sites.", comment: "Description text for the text size adjustment setting") public static func textSizeFooter(for percentage: String) -> String { let message = NSLocalizedString("textSize.footer", value: "Text Size - %@", comment: "Replacement string is a current percent value e.g. '120%'") return message.format(arguments: percentage) @@ -361,7 +361,7 @@ public struct UserText { public static let textZoomMenuItem = NSLocalizedString("action.text-zoom-sheet-menu-item", value: "Zoom", comment: "Text zoom menu item") public static func textZoomWithPercentSheetTitle(_ percent: Int) -> String { - let message = NSLocalizedString("action.text-zoom-sheet-title", value: "Zoom Text (%d%%)", comment: "Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please.") + let message = NSLocalizedString("action.text-zoom-sheet-title", value: "Text Zoom (%d%%)", comment: "Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please.") return message.format(arguments: percent) } @@ -1066,7 +1066,7 @@ But if you *do* want a peek under the hood, you can find more information about public static let settingsTheme = NSLocalizedString("settings.theme", value: "Theme", comment: "Settings screen cell text for theme") public static let settingsIcon = NSLocalizedString("settings.icon", value: "App Icon", comment: "Settings screen cell text for app icon selection") public static let settingsFirebutton = NSLocalizedString("settings.firebutton", value: "Fire Button Animation", comment: "Settings screen cell text for fire button animation") - public static let settingsText = NSLocalizedString("settings.text.size", value: "Default Zoom Text", comment: "Settings screen cell text for text size") + public static let settingsText = NSLocalizedString("settings.text.size", value: "Default Text Zoom", comment: "Settings screen cell text for text size") public static let settingsAddressBar = NSLocalizedString("settings.address.bar", value: "Address Bar Position", comment: "Settings screen cell text for addess bar position") public static let settingsFullURL = NSLocalizedString("settings.address.full.url", value: "Show Full Site Address", comment: "Settings screen cell title for toggling full URL visibility in address bar") diff --git a/DuckDuckGo/en.lproj/Localizable.strings b/DuckDuckGo/en.lproj/Localizable.strings index a1432cf4a3..1937ea052d 100644 --- a/DuckDuckGo/en.lproj/Localizable.strings +++ b/DuckDuckGo/en.lproj/Localizable.strings @@ -20,7 +20,7 @@ "action.text-zoom-sheet-menu-item" = "Zoom"; /* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ -"action.text-zoom-sheet-title" = "Zoom Text (%d%%)"; +"action.text-zoom-sheet-title" = "Text Zoom (%d%%)"; /* Add action - button shown in alert */ "action.title.add" = "Add"; @@ -2374,7 +2374,7 @@ But if you *do* want a peek under the hood, you can find more information about "settings.sync" = "Sync & Backup"; /* Settings screen cell text for text size */ -"settings.text.size" = "Default Zoom Text"; +"settings.text.size" = "Default Text Zoom"; /* Settings screen cell text for theme */ "settings.theme" = "Theme"; From 254015d120c03fc1d298797e7eadcee8cd8b44df Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Thu, 7 Nov 2024 19:40:30 +0000 Subject: [PATCH 27/34] tweak code layout --- DuckDuckGo/TextZoomEditorView.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DuckDuckGo/TextZoomEditorView.swift b/DuckDuckGo/TextZoomEditorView.swift index 8e5cd8dbd8..3a95e1c590 100644 --- a/DuckDuckGo/TextZoomEditorView.swift +++ b/DuckDuckGo/TextZoomEditorView.swift @@ -74,7 +74,8 @@ struct TextZoomEditorView: View { .padding(12) .padding(.trailing, 8) } - .background(RoundedRectangle(cornerRadius: 8).foregroundColor(Color(designSystemColor: .surface))) + .background(RoundedRectangle(cornerRadius: 8) + .foregroundColor(Color(designSystemColor: .surface))) .frame(height: 64) .padding(.horizontal, 16) From 620a64997494ed2e586ee491ca80616618410a85 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Mon, 11 Nov 2024 11:22:59 +0000 Subject: [PATCH 28/34] address bar setting should not be visible on ipad --- DuckDuckGo/SettingsViewModel.swift | 2 +- DuckDuckGo/en.lproj/Localizable.strings | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DuckDuckGo/SettingsViewModel.swift b/DuckDuckGo/SettingsViewModel.swift index fee36bea08..1598078cb1 100644 --- a/DuckDuckGo/SettingsViewModel.swift +++ b/DuckDuckGo/SettingsViewModel.swift @@ -423,7 +423,7 @@ extension SettingsViewModel { appIcon: AppIconManager.shared.appIcon, fireButtonAnimation: appSettings.currentFireButtonAnimation, textSize: SettingsState.TextZoom(enabled: textZoomCoordinator.isEnabled, level: appSettings.defaultTextZoomLevel), - addressBar: SettingsState.AddressBar(enabled: true, position: appSettings.currentAddressBarPosition), + addressBar: SettingsState.AddressBar(enabled: !isPad, position: appSettings.currentAddressBarPosition), showsFullURL: appSettings.showFullSiteAddress, sendDoNotSell: appSettings.sendDoNotSell, autoconsentEnabled: appSettings.autoconsentEnabled, diff --git a/DuckDuckGo/en.lproj/Localizable.strings b/DuckDuckGo/en.lproj/Localizable.strings index 1937ea052d..9906dae0ca 100644 --- a/DuckDuckGo/en.lproj/Localizable.strings +++ b/DuckDuckGo/en.lproj/Localizable.strings @@ -2728,7 +2728,7 @@ But if you *do* want a peek under the hood, you can find more information about "tab.switcher.accessibility.label" = "Tab Switcher"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Automatically apply this zoom level across all websites."; +"textSize.description" = "Increase or decrease text size across all sites."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Text Size - %@"; From 16d3078e763706122e2e393f27835d1b5fcb5004 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Mon, 11 Nov 2024 17:36:53 +0000 Subject: [PATCH 29/34] fix problem where if item is disabled then footer text would still be visible for both items --- DuckDuckGo/SettingsAccessibilityView.swift | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/DuckDuckGo/SettingsAccessibilityView.swift b/DuckDuckGo/SettingsAccessibilityView.swift index 66dfeaddd9..3eb1c5f7ea 100644 --- a/DuckDuckGo/SettingsAccessibilityView.swift +++ b/DuckDuckGo/SettingsAccessibilityView.swift @@ -28,33 +28,33 @@ struct SettingsAccessibilityView: View { var body: some View { List { - Section(footer: Text(UserText.textSizeDescription)) { - // Text Size - if viewModel.state.textSize.enabled { + if viewModel.state.textSize.enabled { + Section(footer: Text(UserText.textSizeDescription)) { + // Text Size SettingsPickerCellView(label: UserText.settingsText, options: TextZoomLevel.allCases, selectedOption: viewModel.textZoomLevelBinding) } } - Section(footer: Text(UserText.voiceSearchFooter)) { - // Private Voice Search - if viewModel.state.speechRecognitionAvailable { + if viewModel.state.speechRecognitionAvailable { + Section(footer: Text(UserText.voiceSearchFooter)) { + // Private Voice Search SettingsCellView(label: UserText.settingsVoiceSearch, accessory: .toggle(isOn: viewModel.voiceSearchEnabledBinding)) } - } - .alert(isPresented: $shouldShowNoMicrophonePermissionAlert) { - Alert(title: Text(UserText.noVoicePermissionAlertTitle), - message: Text(UserText.noVoicePermissionAlertMessage), - dismissButton: .default(Text(UserText.noVoicePermissionAlertOKbutton), - action: { - viewModel.shouldShowNoMicrophonePermissionAlert = false - }) - ) - } - .onChange(of: viewModel.shouldShowNoMicrophonePermissionAlert) { value in - shouldShowNoMicrophonePermissionAlert = value + .alert(isPresented: $shouldShowNoMicrophonePermissionAlert) { + Alert(title: Text(UserText.noVoicePermissionAlertTitle), + message: Text(UserText.noVoicePermissionAlertMessage), + dismissButton: .default(Text(UserText.noVoicePermissionAlertOKbutton), + action: { + viewModel.shouldShowNoMicrophonePermissionAlert = false + }) + ) + } + .onChange(of: viewModel.shouldShowNoMicrophonePermissionAlert) { value in + shouldShowNoMicrophonePermissionAlert = value + } } } .applySettingsListModifiers(title: UserText.accessibility, From bae1e61e935ab6ebd09c7da8401a2f2b5863a89e Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Tue, 12 Nov 2024 11:17:11 +0000 Subject: [PATCH 30/34] fix setting when voice search not available --- DuckDuckGo/SettingsGeneralView.swift | 30 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/DuckDuckGo/SettingsGeneralView.swift b/DuckDuckGo/SettingsGeneralView.swift index 2307c092f7..427ec3bfc3 100644 --- a/DuckDuckGo/SettingsGeneralView.swift +++ b/DuckDuckGo/SettingsGeneralView.swift @@ -49,24 +49,24 @@ struct SettingsGeneralView: View { } } - Section(footer: Text(UserText.voiceSearchFooter)) { - // Private Voice Search - if viewModel.state.speechRecognitionAvailable { + if viewModel.state.speechRecognitionAvailable { + Section(footer: Text(UserText.voiceSearchFooter)) { + // Private Voice Search SettingsCellView(label: UserText.settingsVoiceSearch, accessory: .toggle(isOn: viewModel.voiceSearchEnabledBinding)) } - } - .alert(isPresented: $shouldShowNoMicrophonePermissionAlert) { - Alert(title: Text(UserText.noVoicePermissionAlertTitle), - message: Text(UserText.noVoicePermissionAlertMessage), - dismissButton: .default(Text(UserText.noVoicePermissionAlertOKbutton), - action: { - viewModel.shouldShowNoMicrophonePermissionAlert = false - }) - ) - } - .onChange(of: viewModel.shouldShowNoMicrophonePermissionAlert) { value in - shouldShowNoMicrophonePermissionAlert = value + .alert(isPresented: $shouldShowNoMicrophonePermissionAlert) { + Alert(title: Text(UserText.noVoicePermissionAlertTitle), + message: Text(UserText.noVoicePermissionAlertMessage), + dismissButton: .default(Text(UserText.noVoicePermissionAlertOKbutton), + action: { + viewModel.shouldShowNoMicrophonePermissionAlert = false + }) + ) + } + .onChange(of: viewModel.shouldShowNoMicrophonePermissionAlert) { value in + shouldShowNoMicrophonePermissionAlert = value + } } Section(header: Text(UserText.settingsCustomizeSection), From feea52b180533f3e32c70103916c10512db727ed Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Tue, 12 Nov 2024 13:07:44 +0000 Subject: [PATCH 31/34] remove unused notification listener since no user script exists now --- DuckDuckGo/ContentBlockingUpdating.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/DuckDuckGo/ContentBlockingUpdating.swift b/DuckDuckGo/ContentBlockingUpdating.swift index 95e70dbcf6..95002bca9e 100644 --- a/DuckDuckGo/ContentBlockingUpdating.swift +++ b/DuckDuckGo/ContentBlockingUpdating.swift @@ -87,7 +87,6 @@ public final class ContentBlockingUpdating { .combineLatest(onNotificationWithInitial(PreserveLogins.Notifications.loginDetectionStateChanged), combine) .combineLatest(onNotificationWithInitial(AppUserDefaults.Notifications.doNotSellStatusChange), combine) .combineLatest(onNotificationWithInitial(AppUserDefaults.Notifications.autofillEnabledChange), combine) - .combineLatest(onNotificationWithInitial(AppUserDefaults.Notifications.textSizeChange), combine) .combineLatest(onNotificationWithInitial(AppUserDefaults.Notifications.didVerifyInternalUser), combine) .combineLatest(onNotificationWithInitial(ConfigurationManager.didUpdateTrackerDependencies) .receive(on: DispatchQueue.main), combine) From 274aafd7efb3827654ba804f0b176817a6eb86fd Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Tue, 12 Nov 2024 13:36:44 +0000 Subject: [PATCH 32/34] complete rename to text size and remove dead code --- Core/Pixel.swift | 5 ++-- Core/PixelEvent.swift | 11 +++++--- Core/UserDefaultsPropertyWrapper.swift | 4 ++- DuckDuckGo/AppUserDefaults.swift | 12 ++++----- .../TextSizeLarger.imageset/Contents.json | 15 ----------- .../Font-Larger-24.pdf | Bin 1058 -> 0 bytes .../TextSizeSmaller.imageset/Contents.json | 15 ----------- .../Font-Smaller-24.pdf | Bin 1054 -> 0 bytes DuckDuckGo/SettingsAccessibilityView.swift | 4 +-- DuckDuckGo/SettingsLegacyViewProvider.swift | 2 -- DuckDuckGo/SettingsState.swift | 4 +-- DuckDuckGo/SettingsViewModel.swift | 24 +++++++---------- DuckDuckGo/TabViewController.swift | 12 ++++----- DuckDuckGo/TextZoomEditorModel.swift | 6 ++--- DuckDuckGo/UserText.swift | 6 +++-- .../ContentBlockingUpdatingTests.swift | 25 ------------------ 16 files changed, 46 insertions(+), 99 deletions(-) delete mode 100644 DuckDuckGo/Assets.xcassets/TextSizeLarger.imageset/Contents.json delete mode 100644 DuckDuckGo/Assets.xcassets/TextSizeLarger.imageset/Font-Larger-24.pdf delete mode 100644 DuckDuckGo/Assets.xcassets/TextSizeSmaller.imageset/Contents.json delete mode 100644 DuckDuckGo/Assets.xcassets/TextSizeSmaller.imageset/Font-Smaller-24.pdf diff --git a/Core/Pixel.swift b/Core/Pixel.swift index b0796afe64..fc2e7f3945 100644 --- a/Core/Pixel.swift +++ b/Core/Pixel.swift @@ -86,8 +86,9 @@ public struct PixelParameters { public static let count = "count" public static let source = "source" - public static let textSizeInitial = "text_size_initial" - public static let textSizeUpdated = "text_size_updated" + // Text size is the legacy name + public static let textZoomInitial = "text_size_initial" + public static let textZoomUpdated = "text_size_updated" public static let canAutoPreviewMIMEType = "can_auto_preview_mime_type" public static let mimeType = "mime_type" diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 37f335c3e9..1310e04d1f 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -218,7 +218,7 @@ extension Pixel { case bookmarkExportSuccess case bookmarkExportFailure - case textSizeSettingsChanged + case textZoomSettingsChanged case zoomChangedOnPage case zoomChangedOnPageDaily @@ -746,7 +746,7 @@ extension Pixel { case settingsRecentlyVisitedOff case settingsAddressBarSelectorPressed case settingsAccessibilityOpen - case settingsAccessiblityTextSize + case settingsAccessiblityTextZoom // Web pixels case privacyProOfferMonthlyPriceClick @@ -1056,7 +1056,8 @@ extension Pixel.Event { case .bookmarkExportSuccess: return "m_be_a" case .bookmarkExportFailure: return "m_be_e" - case .textSizeSettingsChanged: return "m_text_size_settings_changed" + // Text size is the legacy name + case .textZoomSettingsChanged: return "m_text_size_settings_changed" case .zoomChangedOnPageDaily: return "m_menu_page_zoom_changed_daily" case .zoomChangedOnPage: return "m_menu_page_zoom_changed" @@ -1583,7 +1584,9 @@ extension Pixel.Event { case .settingsRecentlyVisitedOff: return "m_settings_autocomplete_recently-visited_off" case .settingsAddressBarSelectorPressed: return "m_settings_address_bar_selector_pressed" case .settingsAccessibilityOpen: return "m_settings_accessibility_open" - case .settingsAccessiblityTextSize: return "m_settings_accessiblity_text_size" + + // legacy name is text size + case .settingsAccessiblityTextZoom: return "m_settings_accessiblity_text_size" // Web case .privacyProOfferMonthlyPriceClick: return "m_privacy-pro_offer_monthly-price_click" diff --git a/Core/UserDefaultsPropertyWrapper.swift b/Core/UserDefaultsPropertyWrapper.swift index 600df5d710..ac6a5a6bdf 100644 --- a/Core/UserDefaultsPropertyWrapper.swift +++ b/Core/UserDefaultsPropertyWrapper.swift @@ -75,7 +75,9 @@ public struct UserDefaultsWrapper { case downloadedSurrogatesCount = "com.duckduckgo.app.downloadedSurrogatesCount" case downloadedTrackerDataSetCount = "com.duckduckgo.app.downloadedTrackerDataSetCount" case downloadedPrivacyConfigurationCount = "com.duckduckgo.app.downloadedPrivacyConfigurationCount" - case textSize = "com.duckduckgo.ios.textSize" + + // Text size is the legacy name and this key is still in use + case textZoom = "com.duckduckgo.ios.textSize" case emailWaitlistShouldReceiveNotifications = "com.duckduckgo.ios.showWaitlistNotification" case unseenDownloadsAvailable = "com.duckduckgo.app.unseenDownloadsAvailable" diff --git a/DuckDuckGo/AppUserDefaults.swift b/DuckDuckGo/AppUserDefaults.swift index 70c53f061b..559a521900 100644 --- a/DuckDuckGo/AppUserDefaults.swift +++ b/DuckDuckGo/AppUserDefaults.swift @@ -27,7 +27,7 @@ public class AppUserDefaults: AppSettings { public struct Notifications { public static let doNotSellStatusChange = Notification.Name("com.duckduckgo.app.DoNotSellStatusChange") public static let currentFireButtonAnimationChange = Notification.Name("com.duckduckgo.app.CurrentFireButtonAnimationChange") - public static let textSizeChange = Notification.Name("com.duckduckgo.app.TextSizeChange") + public static let textZoomChange = Notification.Name("com.duckduckgo.app.TextZoomChange") public static let favoritesDisplayModeChange = Notification.Name("com.duckduckgo.app.FavoritesDisplayModeChange") public static let syncPausedStateChanged = SyncBookmarksAdapter.syncBookmarksPausedStateChanged public static let syncCredentialsPausedStateChanged = SyncCredentialsAdapter.syncCredentialsPausedStateChanged @@ -235,19 +235,19 @@ public class AppUserDefaults: AppSettings { } } - @UserDefaultsWrapper(key: .textSize, defaultValue: 100) - private var textSize: Int { + @UserDefaultsWrapper(key: .textZoom, defaultValue: 100) + private var textZoom: Int { didSet { - NotificationCenter.default.post(name: Notifications.textSizeChange, object: textSize) + NotificationCenter.default.post(name: Notifications.textZoomChange, object: textZoom) } } var defaultTextZoomLevel: TextZoomLevel { get { - return TextZoomLevel(rawValue: textSize) ?? .percent100 + return TextZoomLevel(rawValue: textZoom) ?? .percent100 } set { - textSize = newValue.rawValue + textZoom = newValue.rawValue } } diff --git a/DuckDuckGo/Assets.xcassets/TextSizeLarger.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/TextSizeLarger.imageset/Contents.json deleted file mode 100644 index 172e1f8799..0000000000 --- a/DuckDuckGo/Assets.xcassets/TextSizeLarger.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "filename" : "Font-Larger-24.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "template-rendering-intent" : "template" - } -} diff --git a/DuckDuckGo/Assets.xcassets/TextSizeLarger.imageset/Font-Larger-24.pdf b/DuckDuckGo/Assets.xcassets/TextSizeLarger.imageset/Font-Larger-24.pdf deleted file mode 100644 index 4f9ffc74208d7c97791bdcfd51839e5570d438ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1058 zcmZvb&2H2%5P zjX%%-Ojg^?-4!DWfFZ^9`wu|8zQ&syu+7e2fiHRT(Kh?x2~!7iuhkEoEe?=u?C+|y z`MXjf?2_F2HTkIfimZi|zC%Zf)|R+PPHGSCC_fvu>ZA zEj!Ds%iI>hk0!0PWn)@$iQl=6eo)4oqO4vk{x;*_k zB1z2|N?mtOwG=%wR7yv!p)0D|cHpP?e&gD4(YFVCi5J!Ga%xJFx9xzw;IYBUef8J6 U?8o1^=!UTzohn$Z-hRIO2NeG5(*OVf diff --git a/DuckDuckGo/Assets.xcassets/TextSizeSmaller.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/TextSizeSmaller.imageset/Contents.json deleted file mode 100644 index aee39a9607..0000000000 --- a/DuckDuckGo/Assets.xcassets/TextSizeSmaller.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "filename" : "Font-Smaller-24.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "template-rendering-intent" : "template" - } -} diff --git a/DuckDuckGo/Assets.xcassets/TextSizeSmaller.imageset/Font-Smaller-24.pdf b/DuckDuckGo/Assets.xcassets/TextSizeSmaller.imageset/Font-Smaller-24.pdf deleted file mode 100644 index 4f76f020d0defb17e1762c56aa79ecf9859b3116..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1054 zcmZuw$!^;)5WUY=%*8-*2*sT=5CmxKrYPE?uF_l3gDNwQ3N5Xq6luRcq%G2llQ{^F zkDQq|ix!*p%>^R{fFZ^1=Py9Kyu_<3aP2l6fzSEuvuk(b0}4;(;ngtqu4o`zyT4WG z@(x-JN6%9*lr2~yjpf=)k3J2sgcGPi5yP~y z8X1o-YmkInA(?zZCZ_~yuU~Oy#PXP?22QkHa>h^)DWvkC215j+#xCdFYl$^H_|!|G zlrDnwUm6$y%8}ax`!6NK^W#VsW{d! z!Na&EQ)$>Tv3?1%cWv8^1K$1cOW`g1{_nTLY*XyqM0|1Es<`f+@b1`})Hg0;tB)u~ z%H7aC_N5yztX)2ZTXpT|TAwlOTqHL|?>STxHQUTUrH#!#Ra-9=Lj^g;Jge@}`?6R1 z2hYqR=@*d>Wv+^`sJq?d8j2p?67kf#d!T6Gu;Ss1S}CE>(~~iZdxUMGgx4ADNGa;; zIia{YrHpqud1cHo*4P(S?Rp5)`?&V)I2*dgo#R=xJwG%h%e!vGQ1HIN*=_aTdG-5W Rx#-7zIaUZ*EZ%>;c?S0O>8t<% diff --git a/DuckDuckGo/SettingsAccessibilityView.swift b/DuckDuckGo/SettingsAccessibilityView.swift index 3eb1c5f7ea..f801ae83d0 100644 --- a/DuckDuckGo/SettingsAccessibilityView.swift +++ b/DuckDuckGo/SettingsAccessibilityView.swift @@ -28,8 +28,8 @@ struct SettingsAccessibilityView: View { var body: some View { List { - if viewModel.state.textSize.enabled { - Section(footer: Text(UserText.textSizeDescription)) { + if viewModel.state.textZoom.enabled { + Section(footer: Text(UserText.textZoomDescription)) { // Text Size SettingsPickerCellView(label: UserText.settingsText, options: TextZoomLevel.allCases, diff --git a/DuckDuckGo/SettingsLegacyViewProvider.swift b/DuckDuckGo/SettingsLegacyViewProvider.swift index 736e81f8e5..dee451e380 100644 --- a/DuckDuckGo/SettingsLegacyViewProvider.swift +++ b/DuckDuckGo/SettingsLegacyViewProvider.swift @@ -53,7 +53,6 @@ class SettingsLegacyViewProvider: ObservableObject { case addToDock, sync, logins, - textSize, appIcon, gpc, autoconsent, @@ -72,7 +71,6 @@ class SettingsLegacyViewProvider: ObservableObject { // Legacy UIKit Views (Pushed unmodified) var addToDock: UIViewController { instantiate( "instructions", fromStoryboard: "HomeRow") } - var textSettings: UIViewController { return instantiate("TextSize", fromStoryboard: "Settings") } var appIcon: UIViewController { instantiate("AppIcon", fromStoryboard: "Settings") } var gpc: UIViewController { instantiate("DoNotSell", fromStoryboard: "Settings") } var autoConsent: UIViewController { instantiate("AutoconsentSettingsViewController", fromStoryboard: "Settings") } diff --git a/DuckDuckGo/SettingsState.swift b/DuckDuckGo/SettingsState.swift index efdbe7ad8f..665077e29d 100644 --- a/DuckDuckGo/SettingsState.swift +++ b/DuckDuckGo/SettingsState.swift @@ -57,7 +57,7 @@ struct SettingsState { var appTheme: ThemeName var appIcon: AppIcon var fireButtonAnimation: FireButtonAnimationType - var textSize: TextZoom + var textZoom: TextZoom var addressBar: AddressBar var showsFullURL: Bool @@ -107,7 +107,7 @@ struct SettingsState { appTheme: .systemDefault, appIcon: AppIconManager.shared.appIcon, fireButtonAnimation: .fireRising, - textSize: TextZoom(enabled: false, level: .percent100), + textZoom: TextZoom(enabled: false, level: .percent100), addressBar: AddressBar(enabled: false, position: .top), showsFullURL: false, sendDoNotSell: true, diff --git a/DuckDuckGo/SettingsViewModel.swift b/DuckDuckGo/SettingsViewModel.swift index 1598078cb1..5f96ce0215 100644 --- a/DuckDuckGo/SettingsViewModel.swift +++ b/DuckDuckGo/SettingsViewModel.swift @@ -65,7 +65,7 @@ final class SettingsViewModel: ObservableObject { // App Data State Notification Observer private var appDataClearingObserver: Any? - private var textSizeObserver: Any? + private var textZoomObserver: Any? // Closures to interact with legacy view controllers through the container var onRequestPushLegacyView: ((UIViewController) -> Void)? @@ -261,14 +261,14 @@ final class SettingsViewModel: ObservableObject { var textZoomLevelBinding: Binding { Binding( - get: { self.state.textSize.level }, + get: { self.state.textZoom.level }, set: { newValue in - Pixel.fire(.settingsAccessiblityTextSize, withAdditionalParameters: [ - PixelParameters.textSizeInitial: String(self.appSettings.defaultTextZoomLevel.rawValue), - PixelParameters.textSizeUpdated: String(newValue.rawValue), + Pixel.fire(.settingsAccessiblityTextZoom, withAdditionalParameters: [ + PixelParameters.textZoomInitial: String(self.appSettings.defaultTextZoomLevel.rawValue), + PixelParameters.textZoomUpdated: String(newValue.rawValue), ]) self.appSettings.defaultTextZoomLevel = newValue - self.state.textSize.level = newValue + self.state.textZoom.level = newValue } ) } @@ -406,7 +406,7 @@ final class SettingsViewModel: ObservableObject { deinit { subscriptionSignOutObserver = nil appDataClearingObserver = nil - textSizeObserver = nil + textZoomObserver = nil } } @@ -422,7 +422,7 @@ extension SettingsViewModel { appTheme: appSettings.currentThemeName, appIcon: AppIconManager.shared.appIcon, fireButtonAnimation: appSettings.currentFireButtonAnimation, - textSize: SettingsState.TextZoom(enabled: textZoomCoordinator.isEnabled, level: appSettings.defaultTextZoomLevel), + textZoom: SettingsState.TextZoom(enabled: textZoomCoordinator.isEnabled, level: appSettings.defaultTextZoomLevel), addressBar: SettingsState.AddressBar(enabled: !isPad, position: appSettings.currentAddressBarPosition), showsFullURL: appSettings.showFullSiteAddress, sendDoNotSell: appSettings.sendDoNotSell, @@ -625,10 +625,6 @@ extension SettingsViewModel { pushViewController(legacyViewProvider.loginSettings(delegate: self, selectedAccount: state.activeWebsiteAccount)) - case .textSize: - firePixel(.settingsAccessiblityTextSize) - pushViewController(legacyViewProvider.textSettings) - case .gpc: firePixel(.settingsDoNotSellShown) pushViewController(legacyViewProvider.gpc) @@ -791,11 +787,11 @@ extension SettingsViewModel { self?.state.autoclearDataEnabled = (AutoClearSettingsModel(settings: settings) != nil) } - textSizeObserver = NotificationCenter.default.addObserver(forName: AppUserDefaults.Notifications.textSizeChange, + textZoomObserver = NotificationCenter.default.addObserver(forName: AppUserDefaults.Notifications.textZoomChange, object: nil, queue: .main, using: { [weak self] _ in guard let self = self else { return } - self.state.textSize = SettingsState.TextZoom(enabled: true, level: self.appSettings.defaultTextZoomLevel) + self.state.textZoom = SettingsState.TextZoom(enabled: true, level: self.appSettings.defaultTextZoomLevel) }) } diff --git a/DuckDuckGo/TabViewController.swift b/DuckDuckGo/TabViewController.swift index 48b13b44c6..79eda41a6b 100644 --- a/DuckDuckGo/TabViewController.swift +++ b/DuckDuckGo/TabViewController.swift @@ -416,7 +416,7 @@ class TabViewController: UIViewController { preserveLoginsWorker = PreserveLoginsWorker(controller: self) initAttributionLogic() decorate() - addTextSizeObserver() + addTextZoomObserver() subscribeToEmailProtectionSignOutNotification() registerForDownloadsNotifications() registerForAddressBarLocationNotifications() @@ -954,10 +954,10 @@ class TabViewController: UIViewController { breakageAdditionalInfo: makeBreakageAdditionalInfo()) } - private func addTextSizeObserver() { + private func addTextZoomObserver() { NotificationCenter.default.addObserver(self, - selector: #selector(onTextSizeChange), - name: AppUserDefaults.Notifications.textSizeChange, + selector: #selector(onTextZoomChange), + name: AppUserDefaults.Notifications.textZoomChange, object: nil) } @@ -970,7 +970,7 @@ class TabViewController: UIViewController { } } - @objc func onTextSizeChange() { + @objc func onTextZoomChange() { textZoomCoordinator.onTextZoomChange(applyToWebView: webView) } @@ -1428,7 +1428,7 @@ extension TabViewController: WKNavigationDelegate { func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { self.currentlyLoadedURL = webView.url - onTextSizeChange() + onTextZoomChange() adClickAttributionDetection.onDidFinishNavigation(url: webView.url) adClickAttributionLogic.onDidFinishNavigation(host: webView.url?.host) hideProgressIndicator() diff --git a/DuckDuckGo/TextZoomEditorModel.swift b/DuckDuckGo/TextZoomEditorModel.swift index cc804d1317..4d81f73ebe 100644 --- a/DuckDuckGo/TextZoomEditorModel.swift +++ b/DuckDuckGo/TextZoomEditorModel.swift @@ -57,7 +57,7 @@ class TextZoomEditorModel: ObservableObject { title = UserText.textZoomWithPercentSheetTitle(TextZoomLevel.allCases[value].rawValue) coordinator.set(textZoomLevel: TextZoomLevel.allCases[value], forHost: domain) NotificationCenter.default.post( - name: AppUserDefaults.Notifications.textSizeChange, + name: AppUserDefaults.Notifications.textZoomChange, object: nil) DailyPixel.fire(pixel: .zoomChangedOnPageDaily) } @@ -65,8 +65,8 @@ class TextZoomEditorModel: ObservableObject { func onDismiss() { guard initialValue.rawValue != TextZoomLevel.allCases[value].rawValue else { return } Pixel.fire(.zoomChangedOnPage, withAdditionalParameters: [ - PixelParameters.textSizeInitial: String(initialValue.rawValue), - PixelParameters.textSizeUpdated: String(TextZoomLevel.allCases[value].rawValue), + PixelParameters.textZoomInitial: String(initialValue.rawValue), + PixelParameters.textZoomUpdated: String(TextZoomLevel.allCases[value].rawValue), ]) } diff --git a/DuckDuckGo/UserText.swift b/DuckDuckGo/UserText.swift index 96ca34df6a..f7016fc358 100644 --- a/DuckDuckGo/UserText.swift +++ b/DuckDuckGo/UserText.swift @@ -330,8 +330,10 @@ public struct UserText { public static let voiceSearchCancelButton = NSLocalizedString("voiceSearch.cancel", value: "Cancel", comment: "Cancel button for voice search") public static let voiceSearchFooterOld = NSLocalizedString("voiceSearch.footer.note.old", value: "Audio is processed on-device. It's not stored or shared with anyone, including DuckDuckGo.", comment: "Voice-search footer note with on-device privacy warning") public static let voiceSearchFooter = NSLocalizedString("voiceSearch.footer.note", value: "Add Private Voice Search option to the address bar. Audio is not stored or shared with anyone, including DuckDuckGo.", comment: "Voice-search footer note with on-device privacy warning") - public static let textSizeDescription = NSLocalizedString("textSize.description", value: "Increase or decrease text size across all sites.", comment: "Description text for the text size adjustment setting") - public static func textSizeFooter(for percentage: String) -> String { + + // Legacy name is text size - don't want to mess up translations by changing it. + public static let textZoomDescription = NSLocalizedString("textSize.description", value: "Increase or decrease text size across all sites.", comment: "Description text for the text size adjustment setting") + public static func textZoomFooter(for percentage: String) -> String { let message = NSLocalizedString("textSize.footer", value: "Text Size - %@", comment: "Replacement string is a current percent value e.g. '120%'") return message.format(arguments: percentage) } diff --git a/DuckDuckGoTests/ContentBlockingUpdatingTests.swift b/DuckDuckGoTests/ContentBlockingUpdatingTests.swift index b57c10b1b3..dc68adcd9e 100644 --- a/DuckDuckGoTests/ContentBlockingUpdatingTests.swift +++ b/DuckDuckGoTests/ContentBlockingUpdatingTests.swift @@ -171,31 +171,6 @@ final class ContentBlockingUpdatingTests: XCTestCase { } } - func testWhenTextSizeChangeNotificationSentThenUserScriptsAreRebuild() { - let e1 = expectation(description: "should post initial update") - var e2: XCTestExpectation! - var ruleList: WKContentRuleList! - let c = updating.userContentBlockingAssets.sink { assets in - if ruleList == nil { - ruleList = assets.rules(withName: "test") - e1.fulfill() - } else { - // ruleList should not be recompiled - XCTAssertTrue(assets.rules(withName: "test") === ruleList) - XCTAssertTrue(assets.isValid) - e2.fulfill() - } - } - - rulesManager.updatesSubject.send(Self.testUpdate()) - withExtendedLifetime(c) { - waitForExpectations(timeout: 1, handler: nil) - e2 = expectation(description: "should rebuild user scripts") - NotificationCenter.default.post(name: AppUserDefaults.Notifications.textSizeChange, object: nil) - waitForExpectations(timeout: 1, handler: nil) - } - } - func testWhenDidVerifyInternalUserNotificationSentThenUserScriptsAreRebuild() { let e1 = expectation(description: "should post initial update") var e2: XCTestExpectation! From bcd14bbf69f319d2820e86040231383dc24be300 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Tue, 12 Nov 2024 13:38:04 +0000 Subject: [PATCH 33/34] remove weird xcode token --- DuckDuckGo/TextZoomEditorView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DuckDuckGo/TextZoomEditorView.swift b/DuckDuckGo/TextZoomEditorView.swift index 3a95e1c590..acc28235b8 100644 --- a/DuckDuckGo/TextZoomEditorView.swift +++ b/DuckDuckGo/TextZoomEditorView.swift @@ -88,7 +88,7 @@ struct TextZoomEditorView: View { slider() Spacer() } - .frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, maxHeight: .infinity) + .frame(maxWidth: .infinity, maxHeight: .infinity) .background(Color(designSystemColor: .background)) } From f6ef130fc1187fb6be47627b9860e3f332c3daa9 Mon Sep 17 00:00:00 2001 From: Chris Brind Date: Tue, 12 Nov 2024 13:59:51 +0000 Subject: [PATCH 34/34] fix pixel names --- Core/PixelEvent.swift | 8 ++++---- DuckDuckGo/TextZoomEditorModel.swift | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 1310e04d1f..db9cd2ce02 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -219,8 +219,8 @@ extension Pixel { case bookmarkExportFailure case textZoomSettingsChanged - case zoomChangedOnPage - case zoomChangedOnPageDaily + case textZoomChangedOnPage + case textZoomChangedOnPageDaily case downloadStarted case downloadStartedDueToUnhandledMIMEType @@ -1058,8 +1058,8 @@ extension Pixel.Event { // Text size is the legacy name case .textZoomSettingsChanged: return "m_text_size_settings_changed" - case .zoomChangedOnPageDaily: return "m_menu_page_zoom_changed_daily" - case .zoomChangedOnPage: return "m_menu_page_zoom_changed" + case .textZoomChangedOnPageDaily: return "m_menu_page_zoom_changed_daily" + case .textZoomChangedOnPage: return "m_menu_page_zoom_changed" case .downloadStarted: return "m_download_started" case .downloadStartedDueToUnhandledMIMEType: return "m_download_started_due_to_unhandled_mime_type" diff --git a/DuckDuckGo/TextZoomEditorModel.swift b/DuckDuckGo/TextZoomEditorModel.swift index 4d81f73ebe..44e187d762 100644 --- a/DuckDuckGo/TextZoomEditorModel.swift +++ b/DuckDuckGo/TextZoomEditorModel.swift @@ -59,12 +59,12 @@ class TextZoomEditorModel: ObservableObject { NotificationCenter.default.post( name: AppUserDefaults.Notifications.textZoomChange, object: nil) - DailyPixel.fire(pixel: .zoomChangedOnPageDaily) + DailyPixel.fire(pixel: .textZoomChangedOnPageDaily) } func onDismiss() { guard initialValue.rawValue != TextZoomLevel.allCases[value].rawValue else { return } - Pixel.fire(.zoomChangedOnPage, withAdditionalParameters: [ + Pixel.fire(.textZoomChangedOnPage, withAdditionalParameters: [ PixelParameters.textZoomInitial: String(initialValue.rawValue), PixelParameters.textZoomUpdated: String(TextZoomLevel.allCases[value].rawValue), ])