a789495a98
FreeBSD Smoke / FreeBSD Smoke (x86_64) (push) Has been cancelled
CI / Quality Guardrails (push) Has been cancelled
CI / Build & Test (macos-latest) (push) Has been cancelled
CI / Build & Test (ubuntu-latest) (push) Has been cancelled
CI / Build & Test (windows-latest) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / PowerShell Syntax (push) Has been cancelled
CI / Windows Cross-Target Check (Linux) (push) Has been cancelled
177 lines
6.4 KiB
Swift
177 lines
6.4 KiB
Swift
import JCodeKit
|
|
import SwiftUI
|
|
|
|
/// Sessions, servers, and info sections, split out to keep view files small.
|
|
struct SettingsSessionsSection: View {
|
|
@Environment(AppModel.self) private var model
|
|
@Environment(\.dismiss) private var dismiss
|
|
@Binding var renameDraft: String
|
|
@Binding var showRename: Bool
|
|
|
|
var body: some View {
|
|
Section("Sessions") {
|
|
ForEach(model.session.allSessions, id: \.self) { sessionID in
|
|
sessionRow(sessionID)
|
|
}
|
|
Button {
|
|
renameDraft = model.session.sessionTitle ?? ""
|
|
showRename = true
|
|
} label: {
|
|
Label("Rename current session", systemImage: "pencil")
|
|
.foregroundStyle(Theme.textPrimary)
|
|
}
|
|
.listRowBackground(Theme.surface)
|
|
.accessibilityHint("Opens a field to rename the active session")
|
|
Button {
|
|
model.compactConversation()
|
|
} label: {
|
|
Label("Compact conversation", systemImage: "arrow.down.right.and.arrow.up.left")
|
|
.foregroundStyle(Theme.textPrimary)
|
|
}
|
|
.listRowBackground(Theme.surface)
|
|
.accessibilityHint("Summarizes older messages to free context")
|
|
Button {
|
|
model.clearConversation()
|
|
dismiss()
|
|
} label: {
|
|
Label("New session (clear)", systemImage: "square.and.pencil")
|
|
.foregroundStyle(Theme.mint)
|
|
}
|
|
.listRowBackground(Theme.surface)
|
|
.accessibilityHint("Clears the conversation and starts fresh")
|
|
}
|
|
}
|
|
|
|
private func sessionRow(_ sessionID: String) -> some View {
|
|
let isActive = sessionID == model.session.sessionID
|
|
let title = model.session.title(forSession: sessionID)
|
|
return Button {
|
|
model.switchSession(sessionID)
|
|
dismiss()
|
|
} label: {
|
|
HStack {
|
|
VStack(alignment: .leading, spacing: 4) {
|
|
if let title {
|
|
Text(title)
|
|
.font(.body)
|
|
.foregroundStyle(Theme.textPrimary)
|
|
.lineLimit(1)
|
|
}
|
|
Text(shortSessionID(sessionID))
|
|
.font(Theme.mono(title == nil ? 13 : 11))
|
|
.foregroundStyle(title == nil ? Theme.textPrimary : Theme.textTertiary)
|
|
.lineLimit(1)
|
|
}
|
|
Spacer()
|
|
if isActive {
|
|
Image(systemName: "checkmark")
|
|
.font(.caption)
|
|
.foregroundStyle(Theme.mint)
|
|
.accessibilityHidden(true)
|
|
}
|
|
}
|
|
}
|
|
.listRowBackground(Theme.surface)
|
|
.accessibilityLabel("Session \(title ?? shortSessionID(sessionID))")
|
|
.accessibilityValue(isActive ? "Current" : "")
|
|
.accessibilityHint("Switches to this session")
|
|
.accessibilityAddTraits(isActive ? [.isSelected] : [])
|
|
}
|
|
|
|
private func shortSessionID(_ id: String) -> String {
|
|
if id.count > 24 {
|
|
return String(id.prefix(24)) + "…"
|
|
}
|
|
return id
|
|
}
|
|
}
|
|
|
|
struct SettingsServersSection: View {
|
|
@Environment(AppModel.self) private var model
|
|
@Environment(\.dismiss) private var dismiss
|
|
@Binding var showPairNew: Bool
|
|
|
|
var body: some View {
|
|
Section("Servers") {
|
|
ForEach(model.servers) { server in
|
|
let isActive = server.id == model.activeServer?.id
|
|
Button {
|
|
model.connect(to: server)
|
|
dismiss()
|
|
} label: {
|
|
HStack {
|
|
VStack(alignment: .leading, spacing: 4) {
|
|
Text(server.serverName)
|
|
.font(.body)
|
|
.foregroundStyle(Theme.textPrimary)
|
|
Text("\(server.host):\(String(server.port))")
|
|
.font(Theme.mono(11))
|
|
.foregroundStyle(Theme.textTertiary)
|
|
}
|
|
Spacer()
|
|
if isActive {
|
|
Circle()
|
|
.fill(Theme.mint)
|
|
.frame(width: 8, height: 8)
|
|
.accessibilityHidden(true)
|
|
}
|
|
}
|
|
}
|
|
.listRowBackground(Theme.surface)
|
|
.accessibilityLabel(server.serverName)
|
|
.accessibilityValue(isActive ? "Connected" : "")
|
|
.accessibilityHint("Connects to this server")
|
|
.accessibilityAddTraits(isActive ? [.isSelected] : [])
|
|
.swipeActions {
|
|
Button(role: .destructive) {
|
|
model.removeServer(server)
|
|
} label: {
|
|
Label("Remove", systemImage: "trash")
|
|
}
|
|
}
|
|
}
|
|
Button {
|
|
showPairNew = true
|
|
} label: {
|
|
Label("Pair new server", systemImage: "plus")
|
|
.foregroundStyle(Theme.mint)
|
|
}
|
|
.listRowBackground(Theme.surface)
|
|
.accessibilityHint("Opens pairing to add a server")
|
|
}
|
|
}
|
|
}
|
|
|
|
struct SettingsInfoSection: View {
|
|
@Environment(AppModel.self) private var model
|
|
|
|
var body: some View {
|
|
Section("Info") {
|
|
row("Server version", model.session.serverVersion ?? "unknown")
|
|
row("Provider", model.session.providerName ?? "unknown")
|
|
row(
|
|
"Tokens",
|
|
"\(model.session.tokenInput) in / \(model.session.tokenOutput) out"
|
|
)
|
|
if let detail = model.session.statusDetail {
|
|
row("Status", detail)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func row(_ label: String, _ value: String) -> some View {
|
|
HStack {
|
|
Text(label)
|
|
.font(.callout)
|
|
.foregroundStyle(Theme.textSecondary)
|
|
Spacer()
|
|
Text(value)
|
|
.font(Theme.mono(12))
|
|
.foregroundStyle(Theme.textTertiary)
|
|
.lineLimit(1)
|
|
}
|
|
.listRowBackground(Theme.surface)
|
|
.accessibilityElement(children: .combine)
|
|
}
|
|
}
|