fix(settings): sidebar version footer — alpha tag, offline handling, auto-refresh
Outpost's version was missing the -ALPHA suffix About already shows — extracted OutpostVersion (Support/) as the one shared source for both, so a third divergent copy can't happen the way AboutInfoView's own doc comment already warns against for its two call sites. Outline's version now accounts for the manual Offline Mode toggle too, not just real connectivity, shows "Outline — offline" instead of just disappearing when nothing's been fetched yet, and re-fetches automatically via .task(id: isEffectivelyOnline) whenever connectivity changes — previously a one-shot fetch on first sidebar mount only.
This commit is contained in:
@@ -14,17 +14,7 @@ struct AboutInfoView: View {
|
|||||||
Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String ?? "Outpost"
|
Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String ?? "Outpost"
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bumped alongside `MARKETING_VERSION` in the Xcode project — kept out
|
var versionString: String { OutpostVersion.fullVersionString }
|
||||||
/// of the bundle version itself since `CFBundleShortVersionString` is
|
|
||||||
/// expected to stay a plain dotted-numeric string, not `0.0.1-ALPHA`.
|
|
||||||
private let releaseStage = "ALPHA"
|
|
||||||
|
|
||||||
var versionString: String {
|
|
||||||
let shortVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "0.0.1"
|
|
||||||
let buildNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String ?? "1"
|
|
||||||
let stageSuffix = releaseStage.isEmpty ? "" : "-\(releaseStage)"
|
|
||||||
return "Version \(shortVersion)\(stageSuffix) (\(buildNumber))"
|
|
||||||
}
|
|
||||||
|
|
||||||
private var copyrightYear: String {
|
private var copyrightYear: String {
|
||||||
String(Calendar.current.component(.year, from: Date()))
|
String(Calendar.current.component(.year, from: Date()))
|
||||||
|
|||||||
@@ -20,10 +20,13 @@ struct SettingsSidebarList: View {
|
|||||||
let onDone: () -> Void
|
let onDone: () -> Void
|
||||||
|
|
||||||
@Environment(SessionStore.self) private var session
|
@Environment(SessionStore.self) private var session
|
||||||
|
@AppStorage(CachingOutlineAPIClient.offlineModeDefaultsKey) private var isOfflineModeEnabled = false
|
||||||
@State private var outlineVersion: String?
|
@State private var outlineVersion: String?
|
||||||
|
|
||||||
private var outpostVersion: String {
|
/// Mirrors `SettingsView`'s own check — a real dropped connection or
|
||||||
Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "0.0.1"
|
/// the manual Offline Mode toggle both mean there's no server to ask.
|
||||||
|
private var isEffectivelyOnline: Bool {
|
||||||
|
session.networkMonitor.isOnline && !isOfflineModeEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@@ -67,14 +70,20 @@ struct SettingsSidebarList: View {
|
|||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.padding(12)
|
.padding(12)
|
||||||
}
|
}
|
||||||
.task { await refreshOutlineVersion() }
|
// Keyed to connectivity, not a one-shot `.task {}` — reconnecting
|
||||||
|
// (or turning the manual Offline Mode toggle back off) re-fires
|
||||||
|
// this automatically instead of leaving the footer stuck on
|
||||||
|
// whatever it last knew, or blank, until Settings is reopened.
|
||||||
|
.task(id: isEffectivelyOnline) { await refreshOutlineVersion() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private var versionFooter: some View {
|
private var versionFooter: some View {
|
||||||
VStack(alignment: .leading, spacing: 2) {
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
Text("Outpost \(outpostVersion)")
|
Text("Outpost \(OutpostVersion.displayString)")
|
||||||
if let outlineVersion {
|
if let outlineVersion {
|
||||||
Text("Outline \(outlineVersion)")
|
Text("Outline \(outlineVersion)")
|
||||||
|
} else if !isEffectivelyOnline {
|
||||||
|
Text("Outline — offline")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.font(.caption2)
|
.font(.caption2)
|
||||||
@@ -85,7 +94,7 @@ struct SettingsSidebarList: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func refreshOutlineVersion() async {
|
private func refreshOutlineVersion() async {
|
||||||
guard let apiClient = session.apiClient else { return }
|
guard isEffectivelyOnline, let apiClient = session.apiClient else { return }
|
||||||
outlineVersion = try? await apiClient.installationInfo().version
|
outlineVersion = try? await apiClient.installationInfo().version
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// Single source of truth for how Outpost's own version is formatted —
|
||||||
|
/// used by both the About page and the Settings sidebar footer, so they
|
||||||
|
/// can't drift out of sync the way `AboutInfoView` was already written to
|
||||||
|
/// avoid for its own two call sites.
|
||||||
|
enum OutpostVersion {
|
||||||
|
/// Bumped alongside `MARKETING_VERSION` in the Xcode project — kept out
|
||||||
|
/// of the bundle version itself since `CFBundleShortVersionString` is
|
||||||
|
/// expected to stay a plain dotted-numeric string, not `0.0.1-ALPHA`.
|
||||||
|
static let releaseStage = "ALPHA"
|
||||||
|
|
||||||
|
static var shortVersion: String {
|
||||||
|
Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "0.0.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
static var buildNumber: String {
|
||||||
|
Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String ?? "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
/// e.g. `"0.0.3-ALPHA"` — for compact display (sidebar footer).
|
||||||
|
static var displayString: String {
|
||||||
|
let stageSuffix = releaseStage.isEmpty ? "" : "-\(releaseStage)"
|
||||||
|
return "\(shortVersion)\(stageSuffix)"
|
||||||
|
}
|
||||||
|
|
||||||
|
/// e.g. `"Version 0.0.3-ALPHA (1)"` — for the About page.
|
||||||
|
static var fullVersionString: String {
|
||||||
|
"Version \(displayString) (\(buildNumber))"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user