diff --git a/Outpost/Features/Account/SettingsView.swift b/Outpost/Features/Account/SettingsView.swift index 7ebd559..917297a 100644 --- a/Outpost/Features/Account/SettingsView.swift +++ b/Outpost/Features/Account/SettingsView.swift @@ -127,6 +127,9 @@ struct SettingsView: View { private var profileDetail: some View { VStack(alignment: .leading, spacing: 24) { sectionHeader + if !isEffectivelyOnline { + offlineSettingsHint + } avatarRow Divider().frame(maxWidth: 420) nameRow @@ -184,6 +187,7 @@ struct SettingsView: View { ProgressView().controlSize(.small) } } + .disabled(!isEffectivelyOnline) if let avatarErrorMessage { Text(avatarErrorMessage) .font(.caption) @@ -212,6 +216,7 @@ struct SettingsView: View { } } } + .disabled(!isEffectivelyOnline) if let nameErrorMessage { Text(nameErrorMessage) .font(.caption) @@ -248,8 +253,13 @@ struct SettingsView: View { .font(.subheadline) .foregroundStyle(.secondary) + if !isEffectivelyOnline { + offlineSettingsHint + } + preferencesSubsection("Display") { languageRow + .disabled(!isEffectivelyOnline) Divider() appearanceRow Divider() @@ -259,6 +269,7 @@ struct SettingsView: View { isOn: session.userPreferences?.useCursorPointer ?? false, onChange: { newValue in Task { await savePreference { $0.useCursorPointer = newValue } } } ) + .disabled(!isEffectivelyOnline) Divider() preferenceToggleRow( "Show line numbers", @@ -266,6 +277,7 @@ struct SettingsView: View { isOn: session.userPreferences?.codeBlockLineNumbers ?? false, onChange: { newValue in Task { await savePreference { $0.codeBlockLineNumbers = newValue } } } ) + .disabled(!isEffectivelyOnline) Divider() preferenceToggleRow( "Show comment marker", @@ -273,6 +285,7 @@ struct SettingsView: View { isOn: session.userPreferences?.showCommentMarker ?? false, onChange: { newValue in Task { await savePreference { $0.showCommentMarker = newValue } } } ) + .disabled(!isEffectivelyOnline) } preferencesSubsection("Behavior") { @@ -299,6 +312,7 @@ struct SettingsView: View { Divider() notificationBadgeRow } + .disabled(!isEffectivelyOnline) if let preferencesErrorMessage { Text(preferencesErrorMessage) @@ -309,6 +323,7 @@ struct SettingsView: View { preferencesSubsection("Danger") { deleteAccountRow } + .disabled(!isEffectivelyOnline) } .frame(maxWidth: 480, alignment: .leading) .task { await refreshProfile() } @@ -778,6 +793,20 @@ struct SettingsView: View { // MARK: - Helpers + /// Everything backed by a live `users.update`/`users.notifications*` + /// call (Profile's name/avatar, all of Preferences, all of + /// Notifications) shows this and disables its controls while offline — + /// there's nothing to optimistically apply here the way document edits + /// can be, and no offline queue for it (see `TODO.local.md`'s own + /// "things that actually require an internet connection" framing, + /// already applied to Share/Permissions/Search). Local-only settings + /// (Appearance, Offline Mode itself) are deliberately left enabled. + private var offlineSettingsHint: some View { + Text("You're offline — these settings need a connection to change.") + .font(.caption) + .foregroundStyle(.orange) + } + private func labeledRow(_ label: String, _ value: String) -> some View { HStack { Text(label)