From ca69fd62d922b805d52657ec941e93459d90cd54 Mon Sep 17 00:00:00 2001 From: True Zhuanjia Date: Fri, 10 Apr 2026 23:25:46 +0800 Subject: [PATCH] persist pickerView tab selection --- VoidLink/Input/CustomOSC/OSCProfilesManager.m | 2 +- VoidLinkPreview/WidgetPickerView.swift | 68 ++++++++++++++++--- .../WidgetPickerViewController.swift | 7 ++ 3 files changed, 67 insertions(+), 10 deletions(-) diff --git a/VoidLink/Input/CustomOSC/OSCProfilesManager.m b/VoidLink/Input/CustomOSC/OSCProfilesManager.m index a96fddaa..d909e9f1 100644 --- a/VoidLink/Input/CustomOSC/OSCProfilesManager.m +++ b/VoidLink/Input/CustomOSC/OSCProfilesManager.m @@ -274,7 +274,7 @@ static CGRect layoutViewBounds; } - (OSCProfile *) getSelectedProfile { - NSLog(@"getAllProfiles test %f", CACurrentMediaTime()); + // NSLog(@"getAllProfiles test %f", CACurrentMediaTime()); NSMutableArray *profiles = [self getAllProfiles]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; diff --git a/VoidLinkPreview/WidgetPickerView.swift b/VoidLinkPreview/WidgetPickerView.swift index cd3a4293..2ddfb41c 100644 --- a/VoidLinkPreview/WidgetPickerView.swift +++ b/VoidLinkPreview/WidgetPickerView.swift @@ -9,6 +9,11 @@ import SwiftUI import UIKit +@available(iOS 13.0, *) +final class WidgetPickerPresentationState: ObservableObject { + @Published var hasHostAppeared = false +} + @available(iOS 13.0, *) enum WidgetPickerTab: String, CaseIterable, Identifiable, Equatable { case gamepad = "Gamepad" @@ -17,6 +22,17 @@ enum WidgetPickerTab: String, CaseIterable, Identifiable, Equatable { var id: String { rawValue } + var persistenceIdentifier: String { + switch self { + case .gamepad: + return "gamepad" + case .keyboard: + return "keyboard" + case .functional: + return "functional" + } + } + var title: String { switch self { case .gamepad: @@ -271,6 +287,8 @@ private struct WidgetPickerMetrics { @available(iOS 13.0, *) struct WidgetPickerView: View { + private static let lastSelectedTabDefaultsKey = "WidgetPickerView.lastSelectedTabIdentifier" + private enum PoolTipMessageType { case normal case error @@ -286,6 +304,7 @@ struct WidgetPickerView: View { private let keyboardPickerMode: VirtualKeyboardMode private let shortcutPickerTipText: String? private let shortcutIdentifier: String? + @ObservedObject private var presentationState: WidgetPickerPresentationState var onWidgetCreated: (([String: String]) -> Void)? = nil var onCloseRequested: (() -> Void)? = nil @@ -312,6 +331,15 @@ struct WidgetPickerView: View { @SwiftUI.State private var didApplyInitialConfiguration: Bool = false @SwiftUI.State private var selectionSyncToken: Int = 0 + private static func restoredTab(from availableTabs: [WidgetPickerTab]) -> WidgetPickerTab { + if let persistedIdentifier = UserDefaults.standard.string(forKey: lastSelectedTabDefaultsKey), + let persistedTab = WidgetPickerTab(identifier: persistedIdentifier), + availableTabs.contains(persistedTab) { + return persistedTab + } + return availableTabs[0] + } + init( isEditMode: Bool = false, initialCmdString: String? = nil, @@ -322,6 +350,7 @@ struct WidgetPickerView: View { keyboardPickerMode: VirtualKeyboardMode = .picker, shortcutPickerTipText: String? = nil, shortcutIdentififier: String? = nil, + presentationState: WidgetPickerPresentationState = WidgetPickerPresentationState(), onWidgetCreated: (([String: String]) -> Void)? = nil, onCloseRequested: (() -> Void)? = nil ) { @@ -336,9 +365,14 @@ struct WidgetPickerView: View { self.keyboardPickerMode = keyboardPickerMode self.shortcutPickerTipText = shortcutPickerTipText self.shortcutIdentifier = shortcutIdentififier + self.presentationState = presentationState self.onWidgetCreated = onWidgetCreated self.onCloseRequested = onCloseRequested - _selectedTab = SwiftUI.State(initialValue: resolvedInitialTab ?? (normalizedTabs.contains(.keyboard) ? .keyboard : normalizedTabs[0])) + _selectedTab = SwiftUI.State( + initialValue: isEditMode + ? (resolvedInitialTab ?? (normalizedTabs.contains(.keyboard) ? .keyboard : normalizedTabs[0])) + : Self.restoredTab(from: normalizedTabs) + ) _tipMessage = SwiftUI.State( initialValue: (keyboardPickerMode == .shortcutPicker && !(shortcutPickerTipText ?? "").isEmpty) ? (shortcutPickerTipText ?? "") @@ -742,12 +776,18 @@ struct WidgetPickerView: View { ) .padding(pickerInsetKeyboard) case .functional: - FunctionalButtonCollectionView( - items: functionalButtonOptions, - isSelected: { selectedCmds.contains($0) }, - onSelect: { handleFunctionalButtonSelection($0) }, - onDeselect: { handleFunctionalButtonDeselection($0) } - ) + Group { + if presentationState.hasHostAppeared { + FunctionalButtonCollectionView( + items: functionalButtonOptions, + isSelected: { selectedCmds.contains($0) }, + onSelect: { handleFunctionalButtonSelection($0) }, + onDeselect: { handleFunctionalButtonDeselection($0) } + ) + } else { + Color.clear + } + } .padding(pickerInsetFunctional) } } @@ -792,7 +832,7 @@ struct WidgetPickerView: View { } Button(action: { - onCloseRequested?() + handleCloseRequested() }) { Image(systemName: "xmark") .font(.system(size: max(modeButtonFontSize, 10), weight: .bold)) @@ -1812,10 +1852,11 @@ struct WidgetPickerView: View { private func submitWidgetPayload() { var payload = makeWidgetPayload() + persistCurrentTabSelection() lastCreatedWidgetPayload = payload setTipMessage(SwiftLocalizationHelper.localizedString(forKey: "Widget config generated")) onWidgetCreated?(payload) - print("widgetPicker payload =", payload as NSDictionary) + // print("widgetPicker payload =", payload as NSDictionary) setCreateWidgetSheetVisible(false) } @@ -1855,6 +1896,15 @@ struct WidgetPickerView: View { } } + private func persistCurrentTabSelection() { + UserDefaults.standard.set(selectedTab.persistenceIdentifier, forKey: Self.lastSelectedTabDefaultsKey) + } + + private func handleCloseRequested() { + persistCurrentTabSelection() + onCloseRequested?() + } + private func applyInitialConfigurationIfNeeded() { guard !didApplyInitialConfiguration else { return } didApplyInitialConfiguration = true diff --git a/VoidLinkPreview/WidgetPickerViewController.swift b/VoidLinkPreview/WidgetPickerViewController.swift index 639d5852..415c9a76 100644 --- a/VoidLinkPreview/WidgetPickerViewController.swift +++ b/VoidLinkPreview/WidgetPickerViewController.swift @@ -29,6 +29,7 @@ public final class WidgetPickerViewController: UIViewController { public var shortcutPickerTipText: String? @objc public var shortcutIdentifier: String? + private let presentationState = WidgetPickerPresentationState() private var hostingViewController: UIHostingController? public override func viewDidLoad() { @@ -46,6 +47,7 @@ public final class WidgetPickerViewController: UIViewController { keyboardPickerMode: keyboardPickerMode, shortcutPickerTipText: shortcutPickerTipText, shortcutIdentififier: shortcutIdentifier, + presentationState: presentationState, onWidgetCreated: { [weak self] payload in guard let self else { return } self.delegate?.widgetPickerViewController(self, didCreateWidget: payload as NSDictionary) @@ -78,6 +80,11 @@ public final class WidgetPickerViewController: UIViewController { navigationController?.setNavigationBarHidden(true, animated: false) } + public override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + presentationState.hasHostAppeared = true + } + private func resolvedTabs() -> [WidgetPickerTab] { let tabs = tabIdentifiers.compactMap(WidgetPickerTab.init(identifier:)) return tabs.isEmpty ? WidgetPickerTab.allCases : tabs