Refactor expandable sections to use enum and set pattern for cleaner state management
This commit is contained in:
parent
a6c47240e7
commit
9d0fc241ee
@ -1,26 +1,42 @@
|
||||
import SwiftUI
|
||||
|
||||
enum ExpandableSection: Hashable {
|
||||
case soundFeedback
|
||||
case systemMute
|
||||
case pauseMedia
|
||||
case clipboardRestore
|
||||
case customCancel
|
||||
case middleClick
|
||||
}
|
||||
|
||||
struct ExpandableToggleSection<Content: View>: View {
|
||||
let section: ExpandableSection
|
||||
let title: String
|
||||
let helpText: String
|
||||
@Binding var isEnabled: Bool
|
||||
@Binding var isExpanded: Bool
|
||||
@Binding var expandedSections: Set<ExpandableSection>
|
||||
let content: Content
|
||||
|
||||
init(
|
||||
section: ExpandableSection,
|
||||
title: String,
|
||||
helpText: String,
|
||||
isEnabled: Binding<Bool>,
|
||||
isExpanded: Binding<Bool>,
|
||||
expandedSections: Binding<Set<ExpandableSection>>,
|
||||
@ViewBuilder content: () -> Content
|
||||
) {
|
||||
self.section = section
|
||||
self.title = title
|
||||
self.helpText = helpText
|
||||
self._isEnabled = isEnabled
|
||||
self._isExpanded = isExpanded
|
||||
self._expandedSections = expandedSections
|
||||
self.content = content()
|
||||
}
|
||||
|
||||
private var isExpanded: Bool {
|
||||
expandedSections.contains(section)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
HStack {
|
||||
@ -30,12 +46,12 @@ struct ExpandableToggleSection<Content: View>: View {
|
||||
.toggleStyle(.switch)
|
||||
.help(helpText)
|
||||
.onChange(of: isEnabled) { _, newValue in
|
||||
if newValue {
|
||||
withAnimation(.easeInOut(duration: 0.2)) {
|
||||
isExpanded = true
|
||||
withAnimation(.easeInOut(duration: 0.2)) {
|
||||
if newValue {
|
||||
_ = expandedSections.insert(section)
|
||||
} else {
|
||||
expandedSections.remove(section)
|
||||
}
|
||||
} else {
|
||||
isExpanded = false
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,7 +69,11 @@ struct ExpandableToggleSection<Content: View>: View {
|
||||
.onTapGesture {
|
||||
if isEnabled {
|
||||
withAnimation(.easeInOut(duration: 0.2)) {
|
||||
isExpanded.toggle()
|
||||
if isExpanded {
|
||||
expandedSections.remove(section)
|
||||
} else {
|
||||
_ = expandedSections.insert(section)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ struct ExperimentalFeaturesSection: View {
|
||||
@AppStorage("isExperimentalFeaturesEnabled") private var isExperimentalFeaturesEnabled = false
|
||||
@ObservedObject private var playbackController = PlaybackController.shared
|
||||
@ObservedObject private var mediaController = MediaController.shared
|
||||
@State private var isPauseMediaExpanded = false
|
||||
@State private var expandedSections: Set<ExpandableSection> = []
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
@ -40,10 +40,11 @@ struct ExperimentalFeaturesSection: View {
|
||||
.transition(.opacity.combined(with: .move(edge: .top)))
|
||||
|
||||
ExpandableToggleSection(
|
||||
section: .pauseMedia,
|
||||
title: "Pause Media during recording",
|
||||
helpText: "Automatically pause active media playback during recordings and resume afterward.",
|
||||
isEnabled: $playbackController.isPauseMediaEnabled,
|
||||
isExpanded: $isPauseMediaExpanded
|
||||
expandedSections: $expandedSections
|
||||
) {
|
||||
HStack(spacing: 8) {
|
||||
Text("Resumption Delay")
|
||||
|
||||
@ -22,11 +22,7 @@ struct SettingsView: View {
|
||||
@State private var showResetOnboardingAlert = false
|
||||
@State private var currentShortcut = KeyboardShortcuts.getShortcut(for: .toggleMiniRecorder)
|
||||
@State private var isCustomCancelEnabled = false
|
||||
@State private var isCustomSoundsExpanded = false
|
||||
@State private var isSystemMuteExpanded = false
|
||||
@State private var isClipboardRestoreExpanded = false
|
||||
@State private var isCustomCancelExpanded = false
|
||||
@State private var isMiddleClickExpanded = false
|
||||
@State private var expandedSections: Set<ExpandableSection> = []
|
||||
|
||||
|
||||
var body: some View {
|
||||
@ -141,10 +137,11 @@ struct SettingsView: View {
|
||||
|
||||
|
||||
ExpandableToggleSection(
|
||||
section: .customCancel,
|
||||
title: "Custom Cancel Shortcut",
|
||||
helpText: "Shortcut for cancelling the current recording session. Default: double-tap Escape.",
|
||||
isEnabled: $isCustomCancelEnabled,
|
||||
isExpanded: $isCustomCancelExpanded
|
||||
expandedSections: $expandedSections
|
||||
) {
|
||||
HStack(spacing: 12) {
|
||||
Text("Cancel Shortcut")
|
||||
@ -166,10 +163,11 @@ struct SettingsView: View {
|
||||
Divider()
|
||||
|
||||
ExpandableToggleSection(
|
||||
section: .middleClick,
|
||||
title: "Enable Middle-Click Toggle",
|
||||
helpText: "Use middle mouse button to toggle VoiceInk recording.",
|
||||
isEnabled: $hotkeyManager.isMiddleClickToggleEnabled,
|
||||
isExpanded: $isMiddleClickExpanded
|
||||
expandedSections: $expandedSections
|
||||
) {
|
||||
HStack(spacing: 8) {
|
||||
Text("Activation Delay")
|
||||
@ -204,10 +202,11 @@ struct SettingsView: View {
|
||||
) {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
ExpandableToggleSection(
|
||||
section: .soundFeedback,
|
||||
title: "Sound feedback",
|
||||
helpText: "Play sounds when recording starts and stops",
|
||||
isEnabled: $soundManager.isEnabled,
|
||||
isExpanded: $isCustomSoundsExpanded
|
||||
expandedSections: $expandedSections
|
||||
) {
|
||||
CustomSoundSettingsView()
|
||||
}
|
||||
@ -215,10 +214,11 @@ struct SettingsView: View {
|
||||
Divider()
|
||||
|
||||
ExpandableToggleSection(
|
||||
section: .systemMute,
|
||||
title: "Mute system audio during recording",
|
||||
helpText: "Automatically mute system audio when recording starts and restore when recording stops",
|
||||
isEnabled: $mediaController.isSystemMuteEnabled,
|
||||
isExpanded: $isSystemMuteExpanded
|
||||
expandedSections: $expandedSections
|
||||
) {
|
||||
HStack(spacing: 8) {
|
||||
Text("Resumption Delay")
|
||||
@ -247,10 +247,11 @@ struct SettingsView: View {
|
||||
Divider()
|
||||
|
||||
ExpandableToggleSection(
|
||||
section: .clipboardRestore,
|
||||
title: "Restore clipboard after paste",
|
||||
helpText: "When enabled, VoiceInk will restore your original clipboard content after pasting the transcription.",
|
||||
isEnabled: $restoreClipboardAfterPaste,
|
||||
isExpanded: $isClipboardRestoreExpanded
|
||||
expandedSections: $expandedSections
|
||||
) {
|
||||
HStack(spacing: 8) {
|
||||
Text("Restore Delay")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user