From d566ca104a2619147907f45fb570306cd916cde8 Mon Sep 17 00:00:00 2001 From: dernerl Date: Mon, 8 Dec 2025 12:25:44 +0100 Subject: [PATCH 1/3] feat: Add favicon provider setting (Google vs DuckDuckGo) - Add FaviconProvider enum with Google and DuckDuckGo options - Add Appearance section in Settings with provider picker - Use AppStorage for persistent provider selection - Update favicon URL generation to use selected provider - Default: Google (more reliable) - DuckDuckGo option for privacy-conscious users Closes #3 --- .../ManagedFavsGenerator/ContentView.swift | 10 +++-- .../FaviconProvider.swift | 39 +++++++++++++++++++ .../ManagedFavsGenerator/SettingsView.swift | 27 ++++++++++++- 3 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 Sources/ManagedFavsGenerator/FaviconProvider.swift diff --git a/Sources/ManagedFavsGenerator/ContentView.swift b/Sources/ManagedFavsGenerator/ContentView.swift index 9b9c6c3..8c3b588 100644 --- a/Sources/ManagedFavsGenerator/ContentView.swift +++ b/Sources/ManagedFavsGenerator/ContentView.swift @@ -345,16 +345,20 @@ struct FavoriteRowView: View { let onRemove: () -> Void @State private var isHovering = false @State private var isDragging = false + @AppStorage("faviconProvider") private var faviconProvider: FaviconProvider = .google - /// Generates the favicon URL using Google's favicon service + /// Generates the favicon URL using the selected provider private var faviconURL: URL? { guard let urlString = favorite.url, !urlString.isEmpty, let url = URL(string: urlString), - let domain = url.host else { + let host = url.host else { return nil } - return URL(string: "https://www.google.com/s2/favicons?domain=\(domain)&sz=32") + + // Remove www. prefix if present + let domain = host.hasPrefix("www.") ? String(host.dropFirst(4)) : host + return faviconProvider.faviconURL(for: domain) } var body: some View { diff --git a/Sources/ManagedFavsGenerator/FaviconProvider.swift b/Sources/ManagedFavsGenerator/FaviconProvider.swift new file mode 100644 index 0000000..ef29888 --- /dev/null +++ b/Sources/ManagedFavsGenerator/FaviconProvider.swift @@ -0,0 +1,39 @@ +import Foundation + +/// Favicon service provider +enum FaviconProvider: String, CaseIterable, Identifiable, Codable { + case google = "Google" + case duckduckgo = "DuckDuckGo" + + var id: String { rawValue } + + /// Display name for UI + var displayName: String { + switch self { + case .google: + return "Google" + case .duckduckgo: + return "DuckDuckGo (Privacy)" + } + } + + /// Description for settings + var description: String { + switch self { + case .google: + return "More reliable, comprehensive coverage" + case .duckduckgo: + return "Privacy-focused, no tracking" + } + } + + /// Generate favicon URL for a given domain + func faviconURL(for domain: String) -> URL? { + switch self { + case .google: + return URL(string: "https://www.google.com/s2/favicons?domain=\(domain)&sz=32") + case .duckduckgo: + return URL(string: "https://icons.duckduckgo.com/ip3/\(domain).ico") + } + } +} diff --git a/Sources/ManagedFavsGenerator/SettingsView.swift b/Sources/ManagedFavsGenerator/SettingsView.swift index 6e57e8a..9250fe7 100644 --- a/Sources/ManagedFavsGenerator/SettingsView.swift +++ b/Sources/ManagedFavsGenerator/SettingsView.swift @@ -3,6 +3,7 @@ import SwiftUI /// Settings View fΓΌr App-Einstellungen struct SettingsView: View { @State private var viewModel = FavoritesViewModel() + @AppStorage("faviconProvider") private var faviconProvider: FaviconProvider = .google var body: some View { Form { @@ -23,6 +24,30 @@ struct SettingsView: View { Divider() + Section { + Picker("Favicon Provider", selection: $faviconProvider) { + ForEach(FaviconProvider.allCases) { provider in + Text(provider.displayName).tag(provider) + } + } + .help("Choose which service to use for loading favicons") + + VStack(alignment: .leading, spacing: 4) { + HStack(spacing: 8) { + Image(systemName: "info.circle") + .foregroundStyle(.secondary) + .imageScale(.small) + Text(faviconProvider.description) + .font(.caption) + .foregroundStyle(.secondary) + } + } + } header: { + Text("Appearance") + } + + Divider() + Section { LabeledContent("Version") { Text("1.1.0") @@ -38,7 +63,7 @@ struct SettingsView: View { } } .formStyle(.grouped) - .frame(width: 550, height: 300) + .frame(width: 550, height: 380) } } From 8496e7b2f9bbac374fdae51337a130b14650a50f Mon Sep 17 00:00:00 2001 From: dernerl Date: Mon, 8 Dec 2025 12:39:58 +0100 Subject: [PATCH 2/3] feat: Add OSLog for favicon provider tracking - Add Logger for Favicons category - Log which provider (Google/DuckDuckGo) loads each favicon - Use public privacy level for debugging visibility - Add helper script for viewing logs in real-time Example log output: Loading favicon for 'github.com' using Google provider: https://www.google.com/s2/favicons?domain=github.com&sz=32 --- Sources/ManagedFavsGenerator/ContentView.swift | 10 +++++++++- tmp_rovodev_view_logs.sh | 15 +++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100755 tmp_rovodev_view_logs.sh diff --git a/Sources/ManagedFavsGenerator/ContentView.swift b/Sources/ManagedFavsGenerator/ContentView.swift index 8c3b588..654d704 100644 --- a/Sources/ManagedFavsGenerator/ContentView.swift +++ b/Sources/ManagedFavsGenerator/ContentView.swift @@ -1,5 +1,6 @@ import SwiftUI import SwiftData +import OSLog import AppKit struct ContentView: View { @@ -347,6 +348,8 @@ struct FavoriteRowView: View { @State private var isDragging = false @AppStorage("faviconProvider") private var faviconProvider: FaviconProvider = .google + private let logger = Logger(subsystem: "ManagedFavsGenerator", category: "Favicons") + /// Generates the favicon URL using the selected provider private var faviconURL: URL? { guard let urlString = favorite.url, @@ -358,7 +361,12 @@ struct FavoriteRowView: View { // Remove www. prefix if present let domain = host.hasPrefix("www.") ? String(host.dropFirst(4)) : host - return faviconProvider.faviconURL(for: domain) + let faviconURL = faviconProvider.faviconURL(for: domain) + + // Log which provider is being used (public for debugging) + logger.info("Loading favicon for '\(domain, privacy: .public)' using \(faviconProvider.rawValue, privacy: .public) provider: \(faviconURL?.absoluteString ?? "nil", privacy: .public)") + + return faviconURL } var body: some View { diff --git a/tmp_rovodev_view_logs.sh b/tmp_rovodev_view_logs.sh new file mode 100755 index 0000000..5453a50 --- /dev/null +++ b/tmp_rovodev_view_logs.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +echo "===================================================================" +echo "πŸ“Š Favicon Provider Logs - Live View" +echo "===================================================================" +echo "" +echo "πŸ” Watching logs for subsystem: ManagedFavsGenerator" +echo "πŸ“‚ Category: Favicons" +echo "" +echo "Press Ctrl+C to stop" +echo "-------------------------------------------------------------------" +echo "" + +# Live stream of logs +log stream --predicate 'subsystem == "ManagedFavsGenerator" AND category == "Favicons"' --level info --style compact From 774ec6de56be7f37f9b353cfececa4927b167fe6 Mon Sep 17 00:00:00 2001 From: dernerl Date: Mon, 8 Dec 2025 12:42:37 +0100 Subject: [PATCH 3/3] docs: Add favicon provider debugging section to README - Add log stream command for verifying favicon provider - Explain how to check which provider (Google/DuckDuckGo) is used - Include example output - Document how to change provider in Settings --- README.md | 26 ++++++++++++++++++++++++++ tmp_rovodev_view_logs.sh | 15 --------------- 2 files changed, 26 insertions(+), 15 deletions(-) delete mode 100755 tmp_rovodev_view_logs.sh diff --git a/README.md b/README.md index 876ae55..1f7f29b 100644 --- a/README.md +++ b/README.md @@ -277,6 +277,32 @@ The app generates a complete macOS Configuration Profile with: - βœ… **Export fails**: Verify write permissions for target directory - βœ… **App won't start**: Ensure macOS 15+ and try rebuilding +## πŸ” Debugging & Verification + +### Verify Favicon Provider + +You can verify which favicon provider (Google or DuckDuckGo) the app is using in real-time: + +```bash +# Live stream of favicon loading logs +log stream --predicate 'subsystem == "ManagedFavsGenerator" AND category == "Favicons"' --level info --style compact +``` + +**Example output:** +``` +Loading favicon for 'github.com' using Google provider: https://www.google.com/s2/favicons?domain=github.com&sz=32 +Loading favicon for 'microsoft.com' using DuckDuckGo provider: https://icons.duckduckgo.com/ip3/microsoft.com.ico +``` + +**To change the provider:** +1. Open Settings (⌘,) +2. Navigate to **Appearance** section +3. Select your preferred **Favicon Provider**: + - **Google**: More reliable, comprehensive coverage + - **DuckDuckGo**: Privacy-focused, no tracking + +Changes take effect immediately without restart. + ## πŸ› οΈ Technical Details For developers and technical documentation, see **[AGENTS.md](../AGENTS.md)** - Development guidelines, architecture, and best practices. diff --git a/tmp_rovodev_view_logs.sh b/tmp_rovodev_view_logs.sh deleted file mode 100755 index 5453a50..0000000 --- a/tmp_rovodev_view_logs.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -echo "===================================================================" -echo "πŸ“Š Favicon Provider Logs - Live View" -echo "===================================================================" -echo "" -echo "πŸ” Watching logs for subsystem: ManagedFavsGenerator" -echo "πŸ“‚ Category: Favicons" -echo "" -echo "Press Ctrl+C to stop" -echo "-------------------------------------------------------------------" -echo "" - -# Live stream of logs -log stream --predicate 'subsystem == "ManagedFavsGenerator" AND category == "Favicons"' --level info --style compact