Skip to content

Commit

Permalink
show percent in menu when appropriate. if set back to app default rem…
Browse files Browse the repository at this point in the history
…ove entry from storage
  • Loading branch information
brindy committed Oct 31, 2024
1 parent 36301c5 commit a8c4ef2
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 30 deletions.
8 changes: 4 additions & 4 deletions DuckDuckGo/TextZoomController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ import SwiftUI

class TextZoomController: UIHostingController<TextZoomEditorView> {

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))
}

Expand Down
68 changes: 50 additions & 18 deletions DuckDuckGo/TextZoomCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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?

}
Expand All @@ -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)
}
Expand All @@ -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
)

Expand All @@ -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)
}
}
Expand Down
12 changes: 6 additions & 6 deletions DuckDuckGo/TextZoomEditorModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import Core
class TextZoomEditorModel: ObservableObject {

let domain: String
let storage: TextZoomStoring
let coordinator: TextZoomCoordinating
let initialValue: TextZoomLevel

var valueAsPercent: Int {
Expand All @@ -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
}

Expand All @@ -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)
Expand All @@ -67,7 +67,7 @@ class TextZoomEditorModel: ObservableObject {
Pixel.fire(.zoomChangedOnPage, withAdditionalParameters: [
PixelParameters.textSizeInitial: String(initialValue.rawValue),
PixelParameters.textSizeUpdated: String(TextZoomLevel.allCases[value].rawValue),
])
])
}

}
5 changes: 5 additions & 0 deletions DuckDuckGo/TextZoomStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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])
}

Expand All @@ -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
Expand Down
7 changes: 6 additions & 1 deletion DuckDuckGo/UserText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down
5 changes: 4 additions & 1 deletion DuckDuckGo/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down

0 comments on commit a8c4ef2

Please sign in to comment.