mirror of
https://github.com/awizemann/scarf.git
synced 2026-05-10 18:44:45 +00:00
Merge pull request #30 from awizemann/claude/issue-26-default-server
Let users pick the default server opened on launch (#26)
This commit is contained in:
@@ -9,8 +9,10 @@ struct ServerEntry: Identifiable, Codable, Hashable, Sendable {
|
||||
var id: ServerID
|
||||
var displayName: String
|
||||
var kind: ServerKind
|
||||
/// User preference: open this server in a window on launch. Phase 3
|
||||
/// multi-window uses this; Phase 2 ignores it.
|
||||
/// User preference: this server is the one Scarf opens into when a
|
||||
/// fresh window has no prior binding (first launch or File → New).
|
||||
/// At most one entry should have this set — `ServerRegistry` enforces
|
||||
/// mutual exclusivity. If none do, Local is the implicit default.
|
||||
var openOnLaunch: Bool = false
|
||||
|
||||
var context: ServerContext {
|
||||
@@ -69,6 +71,32 @@ final class ServerRegistry {
|
||||
return nil
|
||||
}
|
||||
|
||||
/// The server a fresh window should open into. Returns the ID of the
|
||||
/// remote entry flagged `openOnLaunch`, or Local's ID if none is
|
||||
/// flagged (or if the flagged entry was removed out from under us).
|
||||
/// Consumed by the `WindowGroup`'s `defaultValue` closure.
|
||||
var defaultServerID: ServerID {
|
||||
entries.first(where: { $0.openOnLaunch })?.id ?? ServerContext.local.id
|
||||
}
|
||||
|
||||
/// Flip the default server to `id`. Passing `ServerContext.local.id`
|
||||
/// clears the flag on every remote entry, making Local the implicit
|
||||
/// default. Passing an unknown ID is a no-op. Persisted on return.
|
||||
func setDefaultServer(_ id: ServerID) {
|
||||
var changed = false
|
||||
for idx in entries.indices {
|
||||
let shouldBeDefault = (entries[idx].id == id)
|
||||
if entries[idx].openOnLaunch != shouldBeDefault {
|
||||
entries[idx].openOnLaunch = shouldBeDefault
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
if changed {
|
||||
save()
|
||||
onEntriesChanged?()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Mutations
|
||||
|
||||
/// Optional callback fired whenever `entries` changes. The app wires
|
||||
|
||||
@@ -87,9 +87,28 @@ struct ManageServersView: View {
|
||||
}
|
||||
|
||||
private var list: some View {
|
||||
List {
|
||||
let defaultID = registry.defaultServerID
|
||||
return List {
|
||||
// Local sits at the top so users can mark it as the open-on-launch
|
||||
// default alongside remote servers. It's synthesized (not in
|
||||
// `registry.entries`), so render it explicitly.
|
||||
HStack(spacing: 10) {
|
||||
defaultStar(for: ServerContext.local.id, currentDefault: defaultID)
|
||||
Image(systemName: "laptopcomputer")
|
||||
.foregroundStyle(.blue)
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text("Local").font(.body)
|
||||
Text("This Mac")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
.padding(.vertical, 4)
|
||||
|
||||
ForEach(registry.entries) { entry in
|
||||
HStack(spacing: 10) {
|
||||
defaultStar(for: entry.id, currentDefault: defaultID)
|
||||
Image(systemName: "server.rack")
|
||||
.foregroundStyle(.blue)
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
@@ -123,6 +142,23 @@ struct ManageServersView: View {
|
||||
.listStyle(.inset)
|
||||
}
|
||||
|
||||
/// A star button that marks the open-on-launch default. Filled + yellow
|
||||
/// on the current default row (and non-interactive — clicking it is a
|
||||
/// no-op since the flag is already set); outline + secondary elsewhere,
|
||||
/// clicking promotes that row to default.
|
||||
@ViewBuilder
|
||||
private func defaultStar(for id: ServerID, currentDefault: ServerID) -> some View {
|
||||
let isDefault = id == currentDefault
|
||||
Button {
|
||||
if !isDefault { registry.setDefaultServer(id) }
|
||||
} label: {
|
||||
Image(systemName: isDefault ? "star.fill" : "star")
|
||||
.foregroundStyle(isDefault ? .yellow : .secondary)
|
||||
}
|
||||
.buttonStyle(.borderless)
|
||||
.help(isDefault ? "Opens on launch" : "Set as default — open this server when Scarf launches.")
|
||||
}
|
||||
|
||||
private func summary(for config: SSHConfig) -> String {
|
||||
var s = ""
|
||||
if let user = config.user, !user.isEmpty { s += "\(user)@" }
|
||||
|
||||
@@ -63,7 +63,11 @@ struct ScarfApp: App {
|
||||
.environment(updater)
|
||||
}
|
||||
} defaultValue: {
|
||||
ServerContext.local.id
|
||||
// Honour the user's "open on launch" choice from the Manage
|
||||
// Servers popover. Falls back to Local when no entry is flagged
|
||||
// (the default behaviour for fresh installs) or when the
|
||||
// flagged entry was removed while the app was closed.
|
||||
registry.defaultServerID
|
||||
}
|
||||
.defaultSize(width: 1100, height: 700)
|
||||
.commands {
|
||||
|
||||
Reference in New Issue
Block a user