diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 5166d45..6b4e9e0 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -62,6 +62,7 @@ body:
- Arc
- Brave
- Vivaldi
+ - Dia
- Firefox (experimental)
validations:
diff --git a/README.md b/README.md
index 810e73c..5a66e67 100644
--- a/README.md
+++ b/README.md
@@ -83,7 +83,7 @@ SimplyTrack requires several macOS permissions to function properly:
1. **Automation Permission**: To track browser activity
- System Preferences → Privacy & Security → Automation
- - Enable SimplyTrack for your browsers (Safari, Chrome, Edge, Arc, Brave, Vivaldi, Firefox)
+ - Enable SimplyTrack for your browsers (Safari, Chrome, Edge, Arc, Brave, Vivaldi, Dia, Firefox)
2. **System Events Permission**: For Safari and Firefox browser integration
- System Preferences → Privacy & Security → Automation
diff --git a/SimplyTrack/App/AppDelegate.swift b/SimplyTrack/App/AppDelegate.swift
index ef21007..261b7e6 100644
--- a/SimplyTrack/App/AppDelegate.swift
+++ b/SimplyTrack/App/AppDelegate.swift
@@ -50,6 +50,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
// Initialize all services with proper dependency injection
initializeServices()
+ // Prompt for accessibility permission if not already granted
+ PermissionManager.shared.checkAccessibilityPermission()
+
// Start services in correct order
menuBarManager?.setupMenuBar()
trackingService?.startTracking()
diff --git a/SimplyTrack/Managers/PermissionManager.swift b/SimplyTrack/Managers/PermissionManager.swift
index 0e8b388..912118d 100644
--- a/SimplyTrack/Managers/PermissionManager.swift
+++ b/SimplyTrack/Managers/PermissionManager.swift
@@ -8,6 +8,7 @@
import AppKit
import ApplicationServices
import Foundation
+import os.log
/// Status of macOS system permissions required for app functionality.
/// Used to track automation permissions needed for browser integration.
@@ -27,6 +28,8 @@ class PermissionManager: ObservableObject {
/// Shared singleton instance for permission management
static let shared = PermissionManager()
+ private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "PermissionManager")
+
/// Current status of automation permissions for browser AppleScript access
@Published var automationPermissionStatus: PermissionStatus = .notDetermined
/// Current status of System Events automation permissions (needed for Safari private browsing detection)
@@ -43,6 +46,7 @@ class PermissionManager: ObservableObject {
"company.thebrowser.Browser",
"com.brave.Browser",
"com.vivaldi.Vivaldi",
+ "company.thebrowser.dia",
"org.mozilla.firefox",
]
@@ -89,6 +93,24 @@ class PermissionManager: ObservableObject {
}
}
+ /// Checks if accessibility permissions are granted and prompts if not.
+ /// Should be called at app startup to trigger the macOS permission dialog.
+ /// Does not set `.denied` on failure — the browser error paths handle that
+ /// once the user has had a chance to respond to the system prompt.
+ func checkAccessibilityPermission() {
+ let trusted = AXIsProcessTrustedWithOptions(
+ [kAXTrustedCheckOptionPrompt.takeUnretainedValue(): true] as CFDictionary
+ )
+ if trusted {
+ logger.info("Accessibility permission already granted")
+ Task { @MainActor in
+ self.accessibilityPermissionStatus = .granted
+ }
+ } else {
+ logger.warning("Accessibility permission not granted — user prompted")
+ }
+ }
+
/// Opens System Preferences to the Automation privacy settings.
/// Allows users to grant AppleScript permissions for browser automation and System Events access.
func openSystemPreferences() {
diff --git a/SimplyTrack/Services/Browsers/DiaBrowser.swift b/SimplyTrack/Services/Browsers/DiaBrowser.swift
new file mode 100644
index 0000000..e069010
--- /dev/null
+++ b/SimplyTrack/Services/Browsers/DiaBrowser.swift
@@ -0,0 +1,71 @@
+//
+// DiaBrowser.swift
+// SimplyTrack
+//
+
+import Foundation
+import os.log
+
+/// Dia-specific implementation of browser interface.
+/// Handles URL detection for the Dia browser by The Browser Company.
+/// Dia exposes a custom AppleScript interface with tab and URL support.
+class DiaBrowser: BaseBrowser {
+ private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "DiaBrowser")
+
+ init() {
+ super.init(bundleId: "company.thebrowser.dia", displayName: "Dia")
+ }
+
+ /// Dia-specific AppleScript for URL retrieval
+ override var currentURLScript: String {
+ return """
+ tell application "Dia"
+ if (count of windows) > 0 then
+ return URL of active tab of window 1
+ end if
+ end tell
+ """
+ }
+
+ /// Checks if Dia is currently in incognito mode.
+ /// Dia doesn't expose a private browsing property in its AppleScript dictionary,
+ /// so we use the accessibility API to check the window's AXIdentifier which
+ /// contains "bigIncognitoBrowserWindow" for private windows.
+ override func isInPrivateBrowsingMode() -> Bool {
+ let script = """
+ tell application "System Events"
+ tell process "Dia"
+ if (count of windows) > 0 then
+ return value of attribute "AXIdentifier" of front window
+ end if
+ end tell
+ end tell
+ """
+
+ let scriptResult = executeAppleScript(script)
+
+ if let error = scriptResult.error {
+ if scriptResult.errorCode == -1719 {
+ logger.debug("Dia System Events transient error (invalid index): \(error.description)")
+ } else if scriptResult.errorCode == -1743 || scriptResult.errorCode == -1744 {
+ PermissionManager.shared.handleSystemEventsPermissionResult(success: false)
+ } else if scriptResult.errorCode == -25211 {
+ PermissionManager.shared.handleAccessibilityPermissionResult(success: false)
+ } else {
+ logger.error("Dia System Events AppleScript error: \(error.description)")
+ }
+ return false
+ }
+
+ if scriptResult.result != nil {
+ PermissionManager.shared.handleSystemEventsPermissionResult(success: true)
+ PermissionManager.shared.handleAccessibilityPermissionResult(success: true)
+ }
+
+ guard let identifier = scriptResult.result else {
+ return false
+ }
+
+ return identifier.contains("Incognito")
+ }
+}
diff --git a/SimplyTrack/Services/Browsers/FirefoxBrowser.swift b/SimplyTrack/Services/Browsers/FirefoxBrowser.swift
index 1f01a1f..df82365 100644
--- a/SimplyTrack/Services/Browsers/FirefoxBrowser.swift
+++ b/SimplyTrack/Services/Browsers/FirefoxBrowser.swift
@@ -93,6 +93,8 @@ class FirefoxBrowser: BaseBrowser {
)
} else if scriptResult.errorCode == -1743 || scriptResult.errorCode == -1744 {
PermissionManager.shared.handleSystemEventsPermissionResult(success: false)
+ } else if scriptResult.errorCode == -25211 {
+ PermissionManager.shared.handleAccessibilityPermissionResult(success: false)
} else if scriptResult.errorCode == -1719 || scriptResult.errorCode == -1728 {
// Firefox's accessibility hierarchy can shift during navigation or between versions.
logger.debug("Firefox address bar unavailable in current accessibility tree: \(error.description)")
diff --git a/SimplyTrack/Services/Browsers/SafariBrowser.swift b/SimplyTrack/Services/Browsers/SafariBrowser.swift
index 14305ce..0391eb9 100644
--- a/SimplyTrack/Services/Browsers/SafariBrowser.swift
+++ b/SimplyTrack/Services/Browsers/SafariBrowser.swift
@@ -57,6 +57,8 @@ class SafariBrowser: BaseBrowser {
} else if scriptResult.errorCode == -1743 || scriptResult.errorCode == -1744 {
// System Events permission errors
PermissionManager.shared.handleSystemEventsPermissionResult(success: false)
+ } else if scriptResult.errorCode == -25211 {
+ PermissionManager.shared.handleAccessibilityPermissionResult(success: false)
} else {
// Log non-permission System Events errors
logger.error("Safari System Events AppleScript error: \(error.description)")
diff --git a/SimplyTrack/Services/WebTrackingService.swift b/SimplyTrack/Services/WebTrackingService.swift
index 19418ef..7badf99 100644
--- a/SimplyTrack/Services/WebTrackingService.swift
+++ b/SimplyTrack/Services/WebTrackingService.swift
@@ -3,7 +3,7 @@
// SimplyTrack
//
// Handles browser integration, AppleScript execution, favicon fetching, and website detection
-// Supports Safari, Chrome, Edge, Arc, Brave, Vivaldi, and Firefox through AppleScript communication for website tracking
+// Supports Safari, Chrome, Edge, Arc, Brave, Vivaldi, Dia, and Firefox through AppleScript communication for website tracking
//
import AppKit
@@ -63,6 +63,7 @@ class WebTrackingService {
ArcBrowser(),
BraveBrowser(),
VivaldiBrowser(),
+ DiaBrowser(),
FirefoxBrowser(),
].reduce(into: [:]) { result, browser in
result[browser.bundleId] = browser
diff --git a/SimplyTrack/SimplyTrack.entitlements b/SimplyTrack/SimplyTrack.entitlements
index f0da4f8..0c13b67 100644
--- a/SimplyTrack/SimplyTrack.entitlements
+++ b/SimplyTrack/SimplyTrack.entitlements
@@ -12,6 +12,7 @@
company.thebrowser.Browser
com.brave.Browser
com.vivaldi.Vivaldi
+ company.thebrowser.dia
org.mozilla.firefox
com.apple.systemevents
diff --git a/SimplyTrack/Views/ContentView.swift b/SimplyTrack/Views/ContentView.swift
index db4465d..ef52a67 100644
--- a/SimplyTrack/Views/ContentView.swift
+++ b/SimplyTrack/Views/ContentView.swift
@@ -122,7 +122,7 @@ struct ContentView: View {
if permissionManager.systemEventsPermissionStatus == .denied {
PermissionBannerView(
title: "System Events Permission Required",
- message: "SimplyTrack needs System Events access to detect Safari private browsing. Enable it in System Preferences.",
+ message: "SimplyTrack needs System Events access to detect Safari and Dia private browsing. Enable it in System Preferences.",
primaryButtonTitle: "Open System Preferences",
primaryAction: { permissionManager.openSystemPreferences() },
color: .orange
@@ -133,7 +133,7 @@ struct ContentView: View {
if permissionManager.accessibilityPermissionStatus == .denied {
PermissionBannerView(
title: "Accessibility Permission Required",
- message: "SimplyTrack needs Accessibility access to detect Safari private browsing. Enable it in System Preferences.",
+ message: "SimplyTrack needs Accessibility access to detect Safari and Dia private browsing. Enable it in System Preferences.",
primaryButtonTitle: "Open System Preferences",
primaryAction: { permissionManager.openAccessibilityPreferences() },
color: .orange
diff --git a/SimplyTrack/Views/Settings/PrivacySettingsView.swift b/SimplyTrack/Views/Settings/PrivacySettingsView.swift
index 13bb6c3..f07cb64 100644
--- a/SimplyTrack/Views/Settings/PrivacySettingsView.swift
+++ b/SimplyTrack/Views/Settings/PrivacySettingsView.swift
@@ -101,6 +101,16 @@ struct PrivacySettingsView: View {
.foregroundColor(.secondary)
}
+ HStack {
+ Image(systemName: "checkmark.circle.fill")
+ .foregroundColor(.green)
+ Text("Dia Incognito")
+ Spacer()
+ Text("Supported")
+ .font(.caption)
+ .foregroundColor(.secondary)
+ }
+
HStack {
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green)