From 0d56dd02b7482b5ddc440a9c8eaae9c645463619 Mon Sep 17 00:00:00 2001 From: Arkadiusz Fal Date: Mon, 1 Jun 2026 21:22:45 +0200 Subject: [PATCH] Fix Home card style selection not persisting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Home settings screen copies settings into local @State on appear and saves on disappear. Pushing the card style page fired onDisappear (saving pre-edit values), and popping back re-ran loadSettings, clobbering the style just edited through the bindings — so the selection reverted. Load settings only once per presentation, and persist style, palette, and custom colors immediately from the style page via an onSave callback. The owning view sits covered in the navigation stack where its own onChange never fires, and swipe-dismissing the settings sheet from the style page skips its lifecycle entirely, so saving must happen from the visible child. --- Yattee/Views/Home/HomeSettingsView.swift | 18 ++++++++++++++++-- Yattee/Views/Home/HomeShortcutStyleView.swift | 8 ++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Yattee/Views/Home/HomeSettingsView.swift b/Yattee/Views/Home/HomeSettingsView.swift index 511ec96e..fe1501af 100644 --- a/Yattee/Views/Home/HomeSettingsView.swift +++ b/Yattee/Views/Home/HomeSettingsView.swift @@ -31,6 +31,11 @@ struct HomeSettingsView: View { // Edit mode for delete functionality @State private var isEditMode = false + // Load settings only once per presentation: pushing a child page (e.g. the + // card style view) fires onDisappear/onAppear on this view, and re-running + // loadSettings on pop-back would clobber edits made through bindings. + @State private var hasLoadedSettings = false + #if os(macOS) // macOS: drive the style page programmatically. A List-embedded NavigationLink // gets stuck in the selected (blue) state after popping back and can't be @@ -59,7 +64,8 @@ struct HomeSettingsView: View { HomeShortcutStyleView( style: $shortcutCardStyle, palette: $shortcutColorfulPalette, - customColors: $shortcutCustomPaletteColors + customColors: $shortcutCustomPaletteColors, + onSave: saveSettingsIfLoaded ) } #endif @@ -70,6 +76,8 @@ struct HomeSettingsView: View { .navigationBarTitleDisplayMode(.inline) #endif .onAppear { + guard !hasLoadedSettings else { return } + hasLoadedSettings = true loadSettings() } .onDisappear { @@ -120,7 +128,8 @@ struct HomeSettingsView: View { HomeShortcutStyleView( style: $shortcutCardStyle, palette: $shortcutColorfulPalette, - customColors: $shortcutCustomPaletteColors + customColors: $shortcutCustomPaletteColors, + onSave: saveSettingsIfLoaded ) } #endif @@ -340,6 +349,11 @@ struct HomeSettingsView: View { availableSectionsByMediaSource = settings.allAvailableMediaSourceSections(sources: sources) } + private func saveSettingsIfLoaded() { + guard hasLoadedSettings else { return } + saveSettings() + } + private func saveSettings() { guard let settings = settingsManager else { return } settings.homeShortcutLayout = shortcutLayout diff --git a/Yattee/Views/Home/HomeShortcutStyleView.swift b/Yattee/Views/Home/HomeShortcutStyleView.swift index 8b82e2ed..d9b79bd9 100644 --- a/Yattee/Views/Home/HomeShortcutStyleView.swift +++ b/Yattee/Views/Home/HomeShortcutStyleView.swift @@ -14,6 +14,11 @@ struct HomeShortcutStyleView: View { @Binding var palette: HomeShortcutColorfulPalette @Binding var customColors: [String] + /// Called after any value changes so the owner persists immediately. The + /// owner sits covered in the navigation stack where its own onChange never + /// fires, and swipe-dismissing the sheet from here skips its lifecycle. + var onSave: (() -> Void)? = nil + /// Editing mode for the custom palette. private enum CustomEditMode: String, CaseIterable { case list @@ -87,6 +92,9 @@ struct HomeShortcutStyleView: View { #if os(iOS) .navigationBarTitleDisplayMode(.inline) #endif + .onChange(of: style) { onSave?() } + .onChange(of: palette) { onSave?() } + .onChange(of: customColors) { onSave?() } } // MARK: - Palette