import Foundationimport SwiftUI protocol CodexAmbientLoginRunning: Sendable { func run(timeout: TimeInterval) async -> CodexLoginRunner.Result} struct DefaultCodexAmbientLoginRunner: CodexAmbientLoginRunning { func run(timeout: TimeInterval) async -> CodexLoginRunner.Result { await CodexLoginRunner.run(timeout: timeout) }} struct CodexAccountsSectionNotice: Equatable { enum Tone: Equatable { case secondary case warning } let text: String let tone: Tone} struct CodexAccountsSectionState: Equatable { let visibleAccounts: [CodexVisibleAccount] let activeVisibleAccountID: String? let liveVisibleAccountID: String? let hasUnreadableManagedAccountStore: Bool let isAuthenticatingManagedAccount: Bool let authenticatingManagedAccountID: UUID? let isRemovingManagedAccount: Bool let isAuthenticatingLiveAccount: Bool let isPromotingSystemAccount: Bool let notice: CodexAccountsSectionNotice? var showsActivePicker: Bool { self.visibleAccounts.count > 1 } var singleVisibleAccount: CodexVisibleAccount? { self.visibleAccounts.count == 1 ? self.visibleAccounts.first : nil } var systemVisibleAccount: CodexVisibleAccount? { guard let liveVisibleAccountID else { return nil } return self.visibleAccounts.first { $0.id == liveVisibleAccountID } } var showsSystemPicker: Bool { self.visibleAccounts.count > 1 || (self.liveVisibleAccountID == nil && !self.visibleAccounts.isEmpty) } var systemDisplayName: String { self.systemVisibleAccount?.displayName ?? L("No system account") } var canAddAccount: Bool { !self.hasUnreadableManagedAccountStore && !self.isAuthenticatingManagedAccount && !self.isRemovingManagedAccount && !self.isAuthenticatingLiveAccount && !self.isPromotingSystemAccount } var addAccountTitle: String { if self.isAuthenticatingManagedAccount, self.authenticatingManagedAccountID == nil { return L("Adding Account…") } return L("Add Account") } func showsLiveBadge(for account: CodexVisibleAccount) -> Bool { account.isLive } var isSystemSelectionDisabled: Bool { self.hasUnreadableManagedAccountStore || self.isAuthenticatingManagedAccount || self.isRemovingManagedAccount || self.isAuthenticatingLiveAccount || self.isPromotingSystemAccount } func canPromoteToSystem(_ account: CodexVisibleAccount) -> Bool { guard self.isSystemSelectionDisabled == false else { return false } guard account.id != self.liveVisibleAccountID else { return false } return account.storedAccountID != nil } func canReauthenticate(_ account: CodexVisibleAccount) -> Bool { guard account.canReauthenticate else { return false } guard self.isAuthenticatingManagedAccount == false else { return false } guard self.isRemovingManagedAccount == false else { return false } guard self.isAuthenticatingLiveAccount == false else { return false } guard self.isPromotingSystemAccount == false else { return false } if account.storedAccountID != nil { return self.hasUnreadableManagedAccountStore == false } return true } func canRemove(_ account: CodexVisibleAccount) -> Bool { guard account.canRemove else { return false } guard self.isAuthenticatingManagedAccount == false else { return false } guard self.isRemovingManagedAccount == false else { return false } guard self.isAuthenticatingLiveAccount == false else { return false } guard self.isPromotingSystemAccount == false else { return false } return self.hasUnreadableManagedAccountStore == false } func reauthenticateTitle(for account: CodexVisibleAccount) -> String { if let accountID = account.storedAccountID, self.isAuthenticatingManagedAccount, self.authenticatingManagedAccountID == accountID { return L("Re-authenticating…") } if account.storedAccountID == nil, self.isAuthenticatingLiveAccount { return L("Re-authenticating…") } return L("Re-auth") }} @MainActorstruct CodexAccountsSectionView: View { let state: CodexAccountsSectionState let setActiveVisibleAccount: (String) -> Void let reauthenticateAccount: (CodexVisibleAccount) -> Void let removeAccount: (CodexVisibleAccount) -> Void let requestSystemVisibleAccount: (String) -> Void let addAccount: () -> Void var body: some View { Section { if let selection = self.activeSelectionBinding { VStack(alignment: .leading, spacing: 6) { HStack(alignment: .firstTextBaseline, spacing: 10) { Text(L("Active")) .font(.subheadline.weight(.semibold)) .frame(width: ProviderSettingsMetrics.pickerLabelWidth, alignment: .leading) Picker("", selection: selection) { ForEach(self.state.visibleAccounts) { account in Text(account.displayName).tag(account.id) } } .labelsHidden() .pickerStyle(.menu) .controlSize(.small) Spacer(minLength: 0) } Text(L("Choose which Codex account CodexBar should follow.")) .font(.footnote) .foregroundStyle(.secondary) self.systemRow(selection: self.systemSelectionBinding) } .disabled( self.state.isAuthenticatingManagedAccount || self.state.isRemovingManagedAccount || self.state.isAuthenticatingLiveAccount || self.state.isPromotingSystemAccount) } else if let account = self.state.singleVisibleAccount { VStack(alignment: .leading, spacing: 6) { HStack(alignment: .firstTextBaseline, spacing: 10) { Text(L("Account")) .font(.subheadline.weight(.semibold)) .frame(width: ProviderSettingsMetrics.pickerLabelWidth, alignment: .leading) Text(account.displayName) .font(.subheadline) Spacer(minLength: 0) } self.systemRow(selection: nil) } } if self.state.visibleAccounts.isEmpty { Text(L("No Codex accounts detected yet.")) .font(.footnote) .foregroundStyle(.secondary) } else { VStack(alignment: .leading, spacing: 10) { ForEach(self.state.visibleAccounts) { account in CodexAccountsSectionRowView( account: account, showsSystemBadge: self.state.showsLiveBadge(for: account), reauthenticateTitle: self.state.reauthenticateTitle(for: account), canReauthenticate: self.state.canReauthenticate(account), canRemove: self.state.canRemove(account), onReauthenticate: { self.reauthenticateAccount(account) }, onRemove: { self.removeAccount(account) }) } } } if let notice = self.state.notice { Text(notice.text) .font(.footnote) .foregroundStyle(notice.tone == .warning ? .red : .secondary) .fixedSize(horizontal: false, vertical: true) } Button(self.state.addAccountTitle) { self.addAccount() } .buttonStyle(.bordered) .controlSize(.small) .disabled(self.state.canAddAccount == false) } header: { Text(L("Accounts")) } } private var activeSelectionBinding: Binding<String>? { guard self.state.showsActivePicker else { return nil } let fallbackID = self.state.activeVisibleAccountID ?? self.state.visibleAccounts.first?.id guard let fallbackID else { return nil } return Binding( get: { self.state.activeVisibleAccountID ?? fallbackID }, set: { self.setActiveVisibleAccount($0) }) } private var systemSelectionBinding: Binding<String>? { guard self.state.showsSystemPicker else { return nil } guard let liveVisibleAccountID = self.state.liveVisibleAccountID else { return nil } return Binding( get: { self.state.liveVisibleAccountID ?? liveVisibleAccountID }, set: { self.requestSystemVisibleAccount($0) }) } @ViewBuilder private func systemRow(selection: Binding<String>?) -> some View { HStack(alignment: .firstTextBaseline, spacing: 10) { Text(L("System")) .font(.subheadline.weight(.semibold)) .frame(width: ProviderSettingsMetrics.pickerLabelWidth, alignment: .leading) if let selection { Picker("", selection: selection) { ForEach(self.state.visibleAccounts) { account in Text(account.displayName) .tag(account.id) } } .labelsHidden() .pickerStyle(.menu) .controlSize(.small) .disabled(self.state.isSystemSelectionDisabled) } else if self.state.showsSystemPicker { Menu { ForEach(self.state.visibleAccounts) { account in Button(account.displayName) { self.requestSystemVisibleAccount(account.id) } .disabled(self.state.canPromoteToSystem(account) == false) } } label: { Text(self.state.systemDisplayName) .font(.subheadline) .foregroundStyle(.secondary) } .disabled(self.state.isSystemSelectionDisabled) } else { Text(self.state.systemDisplayName) .font(.subheadline) .foregroundStyle(self.state.systemVisibleAccount == nil ? .secondary : .primary) } Spacer(minLength: 0) } Text(L("The default Codex account on this Mac.")) .font(.footnote) .foregroundStyle(.secondary) }} private struct CodexAccountsSectionRowView: View { let account: CodexVisibleAccount let showsSystemBadge: Bool let reauthenticateTitle: String let canReauthenticate: Bool let canRemove: Bool let onReauthenticate: () -> Void let onRemove: () -> Void var body: some View { HStack(alignment: .center, spacing: 12) { VStack(alignment: .leading, spacing: 2) { HStack(alignment: .firstTextBaseline, spacing: 6) { Text(self.account.displayName) .font(.subheadline.weight(.semibold)) if self.showsSystemBadge { Text(L("(System)")) .font(.caption.weight(.semibold)) .foregroundStyle(.secondary) } } if let health = self.account.authenticationHealthLabel { Text(health) .font(.caption) .foregroundStyle(.orange) } } Spacer(minLength: 8) if self.account.canReauthenticate { Button(self.reauthenticateTitle) { self.onReauthenticate() } .buttonStyle(.bordered) .controlSize(.small) .disabled(self.canReauthenticate == false) } if self.account.canRemove { Button(L("Remove")) { self.onRemove() } .buttonStyle(.bordered) .controlSize(.small) .disabled(self.canRemove == false) } } }}
import Foundation
import SwiftUI
protocol CodexAmbientLoginRunning: Sendable {
func run(timeout: TimeInterval) async -> CodexLoginRunner.Result
}
struct DefaultCodexAmbientLoginRunner: CodexAmbientLoginRunning {
func run(timeout: TimeInterval) async -> CodexLoginRunner.Result {
await CodexLoginRunner.run(timeout: timeout)
}
}
struct CodexAccountsSectionNotice: Equatable {
enum Tone: Equatable {
case secondary
case warning
}
let text: String
let tone: Tone
}
struct CodexAccountsSectionState: Equatable {
let visibleAccounts: [CodexVisibleAccount]
let activeVisibleAccountID: String?
let liveVisibleAccountID: String?
let hasUnreadableManagedAccountStore: Bool
let isAuthenticatingManagedAccount: Bool
let authenticatingManagedAccountID: UUID?
let isRemovingManagedAccount: Bool
let isAuthenticatingLiveAccount: Bool
let isPromotingSystemAccount: Bool
let notice: CodexAccountsSectionNotice?
var showsActivePicker: Bool {
self.visibleAccounts.count > 1
}
var singleVisibleAccount: CodexVisibleAccount? {
self.visibleAccounts.count == 1 ? self.visibleAccounts.first : nil
}
var systemVisibleAccount: CodexVisibleAccount? {
guard let liveVisibleAccountID else { return nil }
return self.visibleAccounts.first { $0.id == liveVisibleAccountID }
}
var showsSystemPicker: Bool {
self.visibleAccounts.count > 1 || (self.liveVisibleAccountID == nil && !self.visibleAccounts.isEmpty)
}
var systemDisplayName: String {
self.systemVisibleAccount?.displayName ?? L("No system account")
}
var canAddAccount: Bool {
!self.hasUnreadableManagedAccountStore &&
!self.isAuthenticatingManagedAccount &&
!self.isRemovingManagedAccount &&
!self.isAuthenticatingLiveAccount &&
!self.isPromotingSystemAccount
}
var addAccountTitle: String {
if self.isAuthenticatingManagedAccount, self.authenticatingManagedAccountID == nil {
return L("Adding Account…")
}
return L("Add Account")
}
func showsLiveBadge(for account: CodexVisibleAccount) -> Bool {
account.isLive
}
var isSystemSelectionDisabled: Bool {
self.hasUnreadableManagedAccountStore ||
self.isAuthenticatingManagedAccount ||
self.isRemovingManagedAccount ||
self.isAuthenticatingLiveAccount ||
self.isPromotingSystemAccount
}
func canPromoteToSystem(_ account: CodexVisibleAccount) -> Bool {
guard self.isSystemSelectionDisabled == false else { return false }
guard account.id != self.liveVisibleAccountID else { return false }
return account.storedAccountID != nil
}
func canReauthenticate(_ account: CodexVisibleAccount) -> Bool {
guard account.canReauthenticate else { return false }
guard self.isAuthenticatingManagedAccount == false else { return false }
guard self.isRemovingManagedAccount == false else { return false }
guard self.isAuthenticatingLiveAccount == false else { return false }
guard self.isPromotingSystemAccount == false else { return false }
if account.storedAccountID != nil {
return self.hasUnreadableManagedAccountStore == false
}
return true
}
func canRemove(_ account: CodexVisibleAccount) -> Bool {
guard account.canRemove else { return false }
guard self.isAuthenticatingManagedAccount == false else { return false }
guard self.isRemovingManagedAccount == false else { return false }
guard self.isAuthenticatingLiveAccount == false else { return false }
guard self.isPromotingSystemAccount == false else { return false }
return self.hasUnreadableManagedAccountStore == false
}
func reauthenticateTitle(for account: CodexVisibleAccount) -> String {
if let accountID = account.storedAccountID,
self.isAuthenticatingManagedAccount,
self.authenticatingManagedAccountID == accountID
{
return L("Re-authenticating…")
}
if account.storedAccountID == nil, self.isAuthenticatingLiveAccount {
return L("Re-authenticating…")
}
return L("Re-auth")
}
}
@MainActor
struct CodexAccountsSectionView: View {
let state: CodexAccountsSectionState
let setActiveVisibleAccount: (String) -> Void
let reauthenticateAccount: (CodexVisibleAccount) -> Void
let removeAccount: (CodexVisibleAccount) -> Void
let requestSystemVisibleAccount: (String) -> Void
let addAccount: () -> Void
var body: some View {
Section {
if let selection = self.activeSelectionBinding {
VStack(alignment: .leading, spacing: 6) {
HStack(alignment: .firstTextBaseline, spacing: 10) {
Text(L("Active"))
.font(.subheadline.weight(.semibold))
.frame(width: ProviderSettingsMetrics.pickerLabelWidth, alignment: .leading)
Picker("", selection: selection) {
ForEach(self.state.visibleAccounts) { account in
Text(account.displayName).tag(account.id)
}
}
.labelsHidden()
.pickerStyle(.menu)
.controlSize(.small)
Spacer(minLength: 0)
}
Text(L("Choose which Codex account CodexBar should follow."))
.font(.footnote)
.foregroundStyle(.secondary)
self.systemRow(selection: self.systemSelectionBinding)
}
.disabled(
self.state.isAuthenticatingManagedAccount ||
self.state.isRemovingManagedAccount ||
self.state.isAuthenticatingLiveAccount ||
self.state.isPromotingSystemAccount)
} else if let account = self.state.singleVisibleAccount {
VStack(alignment: .leading, spacing: 6) {
HStack(alignment: .firstTextBaseline, spacing: 10) {
Text(L("Account"))
.font(.subheadline.weight(.semibold))
.frame(width: ProviderSettingsMetrics.pickerLabelWidth, alignment: .leading)
Text(account.displayName)
.font(.subheadline)
Spacer(minLength: 0)
}
self.systemRow(selection: nil)
}
}
if self.state.visibleAccounts.isEmpty {
Text(L("No Codex accounts detected yet."))
.font(.footnote)
.foregroundStyle(.secondary)
} else {
VStack(alignment: .leading, spacing: 10) {
ForEach(self.state.visibleAccounts) { account in
CodexAccountsSectionRowView(
account: account,
showsSystemBadge: self.state.showsLiveBadge(for: account),
reauthenticateTitle: self.state.reauthenticateTitle(for: account),
canReauthenticate: self.state.canReauthenticate(account),
canRemove: self.state.canRemove(account),
onReauthenticate: { self.reauthenticateAccount(account) },
onRemove: { self.removeAccount(account) })
}
}
}
if let notice = self.state.notice {
Text(notice.text)
.font(.footnote)
.foregroundStyle(notice.tone == .warning ? .red : .secondary)
.fixedSize(horizontal: false, vertical: true)
}
Button(self.state.addAccountTitle) {
self.addAccount()
}
.buttonStyle(.bordered)
.controlSize(.small)
.disabled(self.state.canAddAccount == false)
} header: {
Text(L("Accounts"))
}
}
private var activeSelectionBinding: Binding<String>? {
guard self.state.showsActivePicker else { return nil }
let fallbackID = self.state.activeVisibleAccountID ?? self.state.visibleAccounts.first?.id
guard let fallbackID else { return nil }
return Binding(
get: { self.state.activeVisibleAccountID ?? fallbackID },
set: { self.setActiveVisibleAccount($0) })
}
private var systemSelectionBinding: Binding<String>? {
guard self.state.showsSystemPicker else { return nil }
guard let liveVisibleAccountID = self.state.liveVisibleAccountID else { return nil }
return Binding(
get: { self.state.liveVisibleAccountID ?? liveVisibleAccountID },
set: { self.requestSystemVisibleAccount($0) })
}
@ViewBuilder
private func systemRow(selection: Binding<String>?) -> some View {
HStack(alignment: .firstTextBaseline, spacing: 10) {
Text(L("System"))
.font(.subheadline.weight(.semibold))
.frame(width: ProviderSettingsMetrics.pickerLabelWidth, alignment: .leading)
if let selection {
Picker("", selection: selection) {
ForEach(self.state.visibleAccounts) { account in
Text(account.displayName)
.tag(account.id)
}
}
.labelsHidden()
.pickerStyle(.menu)
.controlSize(.small)
.disabled(self.state.isSystemSelectionDisabled)
} else if self.state.showsSystemPicker {
Menu {
ForEach(self.state.visibleAccounts) { account in
Button(account.displayName) {
self.requestSystemVisibleAccount(account.id)
}
.disabled(self.state.canPromoteToSystem(account) == false)
}
} label: {
Text(self.state.systemDisplayName)
.font(.subheadline)
.foregroundStyle(.secondary)
}
.disabled(self.state.isSystemSelectionDisabled)
} else {
Text(self.state.systemDisplayName)
.font(.subheadline)
.foregroundStyle(self.state.systemVisibleAccount == nil ? .secondary : .primary)
}
Spacer(minLength: 0)
}
Text(L("The default Codex account on this Mac."))
.font(.footnote)
.foregroundStyle(.secondary)
}
}
private struct CodexAccountsSectionRowView: View {
let account: CodexVisibleAccount
let showsSystemBadge: Bool
let reauthenticateTitle: String
let canReauthenticate: Bool
let canRemove: Bool
let onReauthenticate: () -> Void
let onRemove: () -> Void
var body: some View {
HStack(alignment: .center, spacing: 12) {
VStack(alignment: .leading, spacing: 2) {
HStack(alignment: .firstTextBaseline, spacing: 6) {
Text(self.account.displayName)
.font(.subheadline.weight(.semibold))
if self.showsSystemBadge {
Text(L("(System)"))
.font(.caption.weight(.semibold))
.foregroundStyle(.secondary)
}
}
if let health = self.account.authenticationHealthLabel {
Text(health)
.font(.caption)
.foregroundStyle(.orange)
}
}
Spacer(minLength: 8)
if self.account.canReauthenticate {
Button(self.reauthenticateTitle) {
self.onReauthenticate()
}
.buttonStyle(.bordered)
.controlSize(.small)
.disabled(self.canReauthenticate == false)
}
if self.account.canRemove {
Button(L("Remove")) {
self.onRemove()
}
.buttonStyle(.bordered)
.controlSize(.small)
.disabled(self.canRemove == false)
}
}
}
}