Skip to content

Commit

Permalink
Use 1 User Script per Web View
Browse files Browse the repository at this point in the history
  • Loading branch information
ayoy committed Nov 14, 2024
1 parent c164e41 commit 80b8641
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 72 deletions.
2 changes: 0 additions & 2 deletions DuckDuckGo/Application/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
var privacyDashboardWindow: NSWindow?

let newTabPageActionsManager: NewTabPageActionsManaging
let newTabPageUserScript: NewTabPageUserScript
let activeRemoteMessageModel: ActiveRemoteMessageModel
let homePageSettingsModel = HomePage.Models.SettingsModel()
let remoteMessagingClient: RemoteMessagingClient!
Expand Down Expand Up @@ -312,7 +311,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
freemiumDBPFeature: freemiumDBPFeature)

newTabPageActionsManager = NewTabPageActionsManager(appearancePreferences: .shared)
newTabPageUserScript = NewTabPageUserScript(actionsManager: newTabPageActionsManager)
}

func applicationWillFinishLaunching(_ notification: Notification) {
Expand Down
60 changes: 16 additions & 44 deletions DuckDuckGo/HomePage/NewTabPageActionsManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ import Common
import os.log

protocol NewTabPageActionsManaging: AnyObject {
var configuration: NewTabPageConfiguration { get }
var userScript: NewTabPageUserScript? { get set }
var configuration: NewTabPageUserScript.NewTabPageConfiguration { get }

func registerUserScript(_ userScript: NewTabPageUserScript)

func getFavorites() -> NewTabPageUserScript.FavoritesData
func getFavoritesConfig() -> NewTabPageUserScript.WidgetConfig
Expand All @@ -38,46 +39,11 @@ protocol NewTabPageActionsManaging: AnyObject {
func updateWidgetConfigs(with params: [[String: String]])
}

struct NewTabPageConfiguration: Encodable {
var widgets: [Widget]
var widgetConfigs: [WidgetConfig]
var env: String
var locale: String
var platform: Platform

struct Widget: Encodable {
var id: String
}

struct WidgetConfig: Encodable {

enum WidgetVisibility: String, Encodable {
case visible, hidden

var isVisible: Bool {
self == .visible
}
}

init(id: String, isVisible: Bool) {
self.id = id
self.visibility = isVisible ? .visible : .hidden
}

var id: String
var visibility: WidgetVisibility
}

struct Platform: Encodable {
var name: String
}
}

final class NewTabPageActionsManager: NewTabPageActionsManaging {

private let appearancePreferences: AppearancePreferences
private var cancellables = Set<AnyCancellable>()
weak var userScript: NewTabPageUserScript?
private var userScripts = NSHashTable<NewTabPageUserScript>.weakObjects()

init(appearancePreferences: AppearancePreferences) {
self.appearancePreferences = appearancePreferences
Expand All @@ -97,14 +63,20 @@ final class NewTabPageActionsManager: NewTabPageActionsManaging {
.store(in: &cancellables)
}

func registerUserScript(_ userScript: NewTabPageUserScript) {
userScripts.add(userScript)
}

private func notifyWidgetConfigsDidChange() {
userScript?.notifyWidgetConfigsDidChange(widgetConfigs: [
.init(id: "favorites", isVisible: appearancePreferences.isFavoriteVisible),
.init(id: "privacyStats", isVisible: appearancePreferences.isRecentActivityVisible)
])
userScripts.allObjects.forEach { userScript in
userScript.notifyWidgetConfigsDidChange(widgetConfigs: [
.init(id: "favorites", isVisible: appearancePreferences.isFavoriteVisible),
.init(id: "privacyStats", isVisible: appearancePreferences.isRecentActivityVisible)
])
}
}

var configuration: NewTabPageConfiguration {
var configuration: NewTabPageUserScript.NewTabPageConfiguration {
#if DEBUG || REVIEW
let env = "development"
#else
Expand Down Expand Up @@ -193,7 +165,7 @@ final class NewTabPageActionsManager: NewTabPageActionsManaging {
guard let id = param["id"], let visibility = param["visibility"] else {
continue
}
let isVisible = NewTabPageConfiguration.WidgetConfig.WidgetVisibility(rawValue: visibility)?.isVisible == true
let isVisible = NewTabPageUserScript.NewTabPageConfiguration.WidgetConfig.WidgetVisibility(rawValue: visibility)?.isVisible == true
switch id {
case "favorites":
appearancePreferences.isFavoriteVisible = isVisible
Expand Down
12 changes: 6 additions & 6 deletions DuckDuckGo/HomePage/NewTabPageUserContentController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ final class NewTabPageUserContentController: WKUserContentController {
let newTabPageUserScriptProvider: NewTabPageUserScriptProvider

@MainActor
override init() {
newTabPageUserScriptProvider = NewTabPageUserScriptProvider()
init(newTabPageUserScript: NewTabPageUserScript) {
newTabPageUserScriptProvider = NewTabPageUserScriptProvider(newTabPageUserScript: newTabPageUserScript)

super.init()

Expand All @@ -54,9 +54,9 @@ final class NewTabPageUserScriptProvider: UserScriptsProvider {

let specialPagesUserScript: SpecialPagesUserScript

init() {
init(newTabPageUserScript: NewTabPageUserScript) {
specialPagesUserScript = SpecialPagesUserScript()
specialPagesUserScript.withNewTabPage()
specialPagesUserScript.registerSubfeature(delegate: newTabPageUserScript)
}

@MainActor
Expand All @@ -80,14 +80,14 @@ final class NewTabPageUserScriptProvider: UserScriptsProvider {
extension WKWebViewConfiguration {

@MainActor
func applyNewTabPageWebViewConfiguration(with featureFlagger: FeatureFlagger) {
func applyNewTabPageWebViewConfiguration(with featureFlagger: FeatureFlagger, newTabPageUserScript: NewTabPageUserScript) {
if urlSchemeHandler(forURLScheme: URL.NavigationalScheme.duck.rawValue) == nil {
setURLSchemeHandler(
DuckURLSchemeHandler(featureFlagger: featureFlagger),
forURLScheme: URL.NavigationalScheme.duck.rawValue
)
}
preferences[.developerExtrasEnabled] = true
self.userContentController = NewTabPageUserContentController()
self.userContentController = NewTabPageUserContentController(newTabPageUserScript: newTabPageUserScript)
}
}
44 changes: 40 additions & 4 deletions DuckDuckGo/HomePage/NewTabPageUserScript.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ final class NewTabPageUserScript: NSObject, Subfeature {
var messageOriginPolicy: MessageOriginPolicy = .only(rules: [.exact(hostname: "newtab")])
let featureName: String = "newTabPage"
weak var broker: UserScriptMessageBroker?
var webViews: NSHashTable<WKWebView> = .weakObjects()
weak var webView: WKWebView?

// MARK: - MessageNames
enum MessageNames: String, CaseIterable {
Expand All @@ -44,7 +44,7 @@ final class NewTabPageUserScript: NSObject, Subfeature {
init(actionsManager: NewTabPageActionsManaging) {
self.actionsManager = actionsManager
super.init()
actionsManager.userScript = self
actionsManager.registerUserScript(self)
}

public func with(broker: UserScriptMessageBroker) {
Expand All @@ -70,9 +70,10 @@ final class NewTabPageUserScript: NSObject, Subfeature {
}

func notifyWidgetConfigsDidChange(widgetConfigs: [NewTabPageConfiguration.WidgetConfig]) {
for webView in webViews.allObjects {
broker?.push(method: "widgets_onConfigUpdated", params: widgetConfigs, for: self, into: webView)
guard let webView else {
return
}
broker?.push(method: "widgets_onConfigUpdated", params: widgetConfigs, for: self, into: webView)
}
}

Expand Down Expand Up @@ -125,6 +126,41 @@ extension NewTabPageUserScript {

extension NewTabPageUserScript {

struct NewTabPageConfiguration: Encodable {
var widgets: [Widget]
var widgetConfigs: [WidgetConfig]
var env: String
var locale: String
var platform: Platform

struct Widget: Encodable {
var id: String
}

struct WidgetConfig: Encodable {

enum WidgetVisibility: String, Encodable {
case visible, hidden

var isVisible: Bool {
self == .visible
}
}

init(id: String, isVisible: Bool) {
self.id = id
self.visibility = isVisible ? .visible : .hidden
}

var id: String
var visibility: WidgetVisibility
}

struct Platform: Encodable {
var name: String
}
}

struct WidgetConfig: Encodable {
let animation: Animation?
let expansion: Expansion
Expand Down
7 changes: 4 additions & 3 deletions DuckDuckGo/HomePage/NewTabPageWebView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,16 @@ import WebKit

final class NewTabPageWebView: WebView {

init(featureFlagger: FeatureFlagger) {
init(featureFlagger: FeatureFlagger, newTabPageUserScript: NewTabPageUserScript) {
let configuration = WKWebViewConfiguration()
configuration.applyNewTabPageWebViewConfiguration(with: featureFlagger)
configuration.applyNewTabPageWebViewConfiguration(with: featureFlagger, newTabPageUserScript: newTabPageUserScript)

super.init(frame: .zero, configuration: configuration)
newTabPageUserScript.webView = self
navigationDelegate = self
load(URLRequest(url: URL.newtab))
}

@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
Expand Down
5 changes: 0 additions & 5 deletions DuckDuckGo/Tab/Model/SpecialPagesUserScriptExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,6 @@ extension SpecialPagesUserScript {
self.registerSubfeature(delegate: onboardingScript)
}

@MainActor
func withNewTabPage() {
self.registerSubfeature(delegate: NSApp.delegateTyped.newTabPageUserScript)
}

func withDuckPlayerIfAvailable() {
var youtubePlayerUserScript: YoutubePlayerUserScript?
if DuckPlayer.shared.isAvailable {
Expand Down
13 changes: 5 additions & 8 deletions DuckDuckGo/Tab/View/BrowserTabViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,9 @@ final class BrowserTabViewController: NSViewController {
private lazy var hoverLabel = NSTextField(string: URL.duckDuckGo.absoluteString)
private lazy var hoverLabelContainer = ColorView(frame: .zero, backgroundColor: .browserTabBackground, borderWidth: 0)

private let newTabPageUserScript: NewTabPageUserScript
private(set) lazy var newTabPageWebView: WebView = {
let webView = NewTabPageWebView(featureFlagger: featureFlagger)
newTabPageUserScript.webViews.add(webView)
return webView
}()
private let newTabPageActionsManager: NewTabPageActionsManaging
private lazy var newTabPageUserScript: NewTabPageUserScript = NewTabPageUserScript(actionsManager: newTabPageActionsManager)
private lazy var newTabPageWebView: WebView = NewTabPageWebView(featureFlagger: featureFlagger, newTabPageUserScript: newTabPageUserScript)
private(set) weak var webView: WebView?
private weak var webViewContainer: NSView?
private weak var webViewSnapshot: NSView?
Expand Down Expand Up @@ -91,14 +88,14 @@ final class BrowserTabViewController: NSViewController {
onboardingDialogTypeProvider: ContextualOnboardingDialogTypeProviding & ContextualOnboardingStateUpdater = Application.appDelegate.onboardingStateMachine,
onboardingDialogFactory: ContextualDaxDialogsFactory = DefaultContextualDaxDialogViewFactory(),
featureFlagger: FeatureFlagger = NSApp.delegateTyped.featureFlagger,
newTabPageUserScript: NewTabPageUserScript = NSApp.delegateTyped.newTabPageUserScript
newTabPageActionsManager: NewTabPageActionsManaging = NSApp.delegateTyped.newTabPageActionsManager
) {
self.tabCollectionViewModel = tabCollectionViewModel
self.bookmarkManager = bookmarkManager
self.onboardingDialogTypeProvider = onboardingDialogTypeProvider
self.onboardingDialogFactory = onboardingDialogFactory
self.featureFlagger = featureFlagger
self.newTabPageUserScript = newTabPageUserScript
self.newTabPageActionsManager = newTabPageActionsManager
containerStackView = NSStackView()

super.init(nibName: nil, bundle: nil)
Expand Down

0 comments on commit 80b8641

Please sign in to comment.