Skip to content

Conversation

@dernerl
Copy link
Owner

@dernerl dernerl commented Dec 8, 2025

⚙️ Favicon Provider Settings

Closes #3

✨ What's New

Adds a Favicon Provider setting that allows users to choose between Google and DuckDuckGo favicon services.

🎯 Motivation

Privacy Considerations:

  • Google Favicon Service: More reliable, comprehensive coverage, but tracks requests
  • DuckDuckGo Favicon Service: Privacy-focused, no tracking

📦 Implementation

1. FaviconProvider Enum

enum FaviconProvider: String, CaseIterable, Identifiable, Codable {
    case google = "Google"
    case duckduckgo = "DuckDuckGo"
    
    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")
        }
    }
}

2. Settings Integration

  • New "Appearance" section in Settings (⌘,)
  • Picker to select provider (Google or DuckDuckGo)
  • Info text explaining the difference
  • Persisted via @AppStorage

3. Dynamic Favicon Loading

  • FavoriteRowView reads provider from AppStorage
  • Favicon URLs generated based on selected provider
  • Changes take effect immediately (no restart required)

🖼️ Settings UI

New Appearance Section:

Settings
  └─ Appearance
       ├─ Favicon Provider: [Google ▼]
       │    - Google
       │    - DuckDuckGo (Privacy)
       └─ ℹ️ More reliable, comprehensive coverage

🔧 API Endpoints

Google:

  • URL: https://www.google.com/s2/favicons?domain={domain}&sz=32
  • ✅ Reliable, comprehensive coverage
  • ✅ Supports size parameter (32px)
  • ⚠️ Tracks requests

DuckDuckGo:

  • URL: https://icons.duckduckgo.com/ip3/{domain}.ico
  • ✅ Privacy-focused, no tracking
  • ✅ Fast, reliable
  • ⚠️ Fixed size (ICO format)

✅ Testing

Tested Scenarios:

  • ✅ Default provider is Google
  • ✅ Switching provider in Settings updates favicons immediately
  • ✅ AppStorage persists selection across app restarts
  • ✅ Both providers load favicons correctly
  • ✅ Fallback to globe icon works for both providers
  • www. prefix is correctly stripped from domains

📝 Changes

New Files:

  • FaviconProvider.swift - Provider enum with URL generation logic

Modified Files:

  • SettingsView.swift - Added Appearance section with provider picker
  • ContentView.swift - Use selected provider for favicon URLs

🎨 UI Improvements

  • Settings window height increased to 380px (was 300px)
  • Info icon with description for selected provider
  • Picker uses display names ("DuckDuckGo (Privacy)")

🔐 Privacy Benefits

Users can now choose DuckDuckGo if they prefer:

  • ✅ No tracking of favicon requests
  • ✅ Privacy-respecting alternative
  • ✅ Still reliable for most domains

Ready for review! 🚀

dernerl added 3 commits December 8, 2025 12:25
- 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
- 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
- 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
@dernerl dernerl merged commit 6d8495c into main Dec 8, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Settings to choose favicon provider (Google vs DuckDuckGo)

1 participant