diff --git a/ClaudeChecker/ContentView.swift b/ClaudeChecker/ContentView.swift index 2c7f764..fd75fae 100644 --- a/ClaudeChecker/ContentView.swift +++ b/ClaudeChecker/ContentView.swift @@ -591,25 +591,48 @@ struct SettingsView: View { .font(.system(size: 16, weight: .semibold)) // Auth section - VStack(alignment: .leading, spacing: 6) { + VStack(alignment: .leading, spacing: 8) { Label("Authentication", systemImage: "person.crop.circle") .font(.system(size: 12, weight: .medium)) .foregroundColor(.secondary) - Text("ClaudeChecker signs into claude.ai inside a built-in browser window and reads your quota data directly from the API. Your session is stored locally and persists across restarts.") + HStack(spacing: 6) { + Circle() + .fill(vm.isSignedIn ? Color.green : Color.orange) + .frame(width: 7, height: 7) + Text(vm.isSignedIn ? "Signed in to claude.ai" : "Not signed in") + .font(.system(size: 12, weight: .medium)) + .foregroundColor(vm.isSignedIn ? .primary : .orange) + } + + Text("Your session is stored locally and persists across restarts.") .font(.system(size: 11.5)) .foregroundColor(.secondary) .fixedSize(horizontal: false, vertical: true) - Button(action: { - showSettings = false - vm.triggerLogin = true - }) { - Label("Sign in again", systemImage: "arrow.right.circle") - .font(.system(size: 12)) + HStack(spacing: 8) { + Button(action: { + showSettings = false + vm.triggerLogin = true + }) { + Label(vm.isSignedIn ? "Re-authenticate" : "Sign in", systemImage: "arrow.right.circle") + .font(.system(size: 12)) + } + .buttonStyle(.bordered) + .controlSize(.small) + + if vm.isSignedIn { + Button(action: { + Task { await vm.signOut() } + }) { + Label("Sign out", systemImage: "rectangle.portrait.and.arrow.right") + .font(.system(size: 12)) + } + .buttonStyle(.bordered) + .controlSize(.small) + .tint(.red) + } } - .buttonStyle(.bordered) - .controlSize(.small) } Divider() diff --git a/ClaudeChecker/Info.plist b/ClaudeChecker/Info.plist index e25d27c..ba1ad04 100644 --- a/ClaudeChecker/Info.plist +++ b/ClaudeChecker/Info.plist @@ -15,9 +15,9 @@ CFBundlePackageType APPL CFBundleShortVersionString - 2.0.5 + 2.0.6 CFBundleVersion - 12 + 13 LSMinimumSystemVersion 13.0 LSUIElement diff --git a/ClaudeChecker/UsageViewModel.swift b/ClaudeChecker/UsageViewModel.swift index 60c17f3..3f1cea4 100644 --- a/ClaudeChecker/UsageViewModel.swift +++ b/ClaudeChecker/UsageViewModel.swift @@ -13,6 +13,7 @@ class UsageViewModel: ObservableObject { @Published var overageSpendLimit: OverageSpendLimit? @Published var planLabel: String = "Claude" @Published var isNotAuthenticated: Bool = false + @Published var isSignedIn: Bool = false @Published var triggerLogin: Bool = false @Published var showInMenuBar: Bool = true { didSet { UserDefaults.standard.set(showInMenuBar, forKey: "show_in_menubar") } @@ -36,6 +37,21 @@ class UsageViewModel: ObservableObject { loadPlaceholderData() } + func signOut() async { + let store = WKWebsiteDataStore.default() + let types = WKWebsiteDataStore.allWebsiteDataTypes() + let records = await store.dataRecords(ofTypes: types) + let claudeRecords = records.filter { $0.displayName.contains("claude.ai") } + await store.removeData(ofTypes: types, for: claudeRecords) + isSignedIn = false + isNotAuthenticated = true + lastUpdated = nil + limits = [] + extraUsage = nil + prepaidCredits = nil + overageSpendLimit = nil + } + func refresh() async { isLoading = true errorMessage = nil @@ -54,6 +70,7 @@ class UsageViewModel: ObservableObject { overageSpendLimit = overage planLabel = "Pro" lastUpdated = Date() + isSignedIn = true for i in limits.indices { let key = limits[i].window.rawValue diff --git a/README.md b/README.md index 4305a63..ea6b01a 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [![macOS](https://img.shields.io/badge/macOS-13.0+-000000?style=flat&logo=apple&logoColor=white)](https://www.apple.com/macos/) [![Swift](https://img.shields.io/badge/Swift-5.9-F05138?style=flat&logo=swift&logoColor=white)](https://swift.org) -[![Version](https://img.shields.io/badge/version-2.0.5-orange?style=flat)](https://github.com/superdooper86/claudechecker/releases) +[![Version](https://img.shields.io/badge/version-2.0.6-orange?style=flat)](https://github.com/superdooper86/claudechecker/releases) [![License](https://img.shields.io/badge/license-MIT-blue?style=flat)](LICENSE) diff --git a/version.json b/version.json index e7b0458..702782c 100644 --- a/version.json +++ b/version.json @@ -1,5 +1,5 @@ { - "version": "2.0.5", - "url": "https://github.com/superdooper86/claudechecker/releases/download/v2.0.5/ClaudeChecker.zip", - "notes": "Fixed window size and update banner dismiss." + "version": "2.0.6", + "url": "https://github.com/superdooper86/claudechecker/releases/download/v2.0.6/ClaudeChecker.zip", + "notes": "Authentication section shows sign-in status with re-authenticate and sign out options." }