Add context menu with delete option to player controls editor buttons

Buttons in the section, mini player, and pill editors can now be
removed via long-press/right-click context menu instead of only
swipe-to-delete. This also gives macOS a delete affordance in the
section editor, which previously had none.
This commit is contained in:
Arkadiusz Fal
2026-06-07 08:10:36 +02:00
parent 3e7d50415b
commit a0a6634d1c
3 changed files with 68 additions and 25 deletions

View File

@@ -105,17 +105,31 @@ struct MiniPlayerEditorView: View {
@ViewBuilder
private func buttonRow(for config: ControlButtonConfiguration) -> some View {
if config.buttonType.hasSettings {
NavigationLink {
MiniPlayerButtonConfigurationView(
buttonID: config.id,
viewModel: viewModel
)
} label: {
Group {
if config.buttonType.hasSettings {
NavigationLink {
MiniPlayerButtonConfigurationView(
buttonID: config.id,
viewModel: viewModel
)
} label: {
buttonRowContent(for: config)
}
} else {
buttonRowContent(for: config)
}
} else {
buttonRowContent(for: config)
}
.contextMenu {
Button(role: .destructive) {
if let index = viewModel.miniPlayerButtons.firstIndex(where: { $0.id == config.id }) {
viewModel.removeMiniPlayerButton(at: index)
}
} label: {
Label(
String(localized: "settings.playerControls.delete"),
systemImage: "trash"
)
}
}
}

View File

@@ -88,17 +88,31 @@ struct PlayerPillEditorView: View {
@ViewBuilder
private func buttonRow(for config: ControlButtonConfiguration) -> some View {
if config.buttonType.hasSettings {
NavigationLink {
PillButtonConfigurationView(
buttonID: config.id,
viewModel: viewModel
)
} label: {
Group {
if config.buttonType.hasSettings {
NavigationLink {
PillButtonConfigurationView(
buttonID: config.id,
viewModel: viewModel
)
} label: {
buttonRowContent(for: config)
}
} else {
buttonRowContent(for: config)
}
} else {
buttonRowContent(for: config)
}
.contextMenu {
Button(role: .destructive) {
if let index = viewModel.pillButtons.firstIndex(where: { $0.id == config.id }) {
viewModel.removePillButton(at: index)
}
} label: {
Label(
String(localized: "settings.playerControls.delete"),
systemImage: "trash"
)
}
}
}

View File

@@ -81,6 +81,18 @@ struct SectionEditorView: View {
} label: {
ButtonRow(configuration: button)
}
.contextMenu {
if viewModel.canEditActivePreset {
Button(role: .destructive) {
removeButton(id: button.id)
} label: {
Label(
String(localized: "settings.playerControls.delete"),
systemImage: "trash"
)
}
}
}
}
.onMove { source, destination in
// Update local state immediately
@@ -93,16 +105,10 @@ struct SectionEditorView: View {
)
}
.onDelete { indexSet in
// Get button IDs before removing from local state
let buttonIDs = indexSet.map { buttons[$0].id }
// Update local state immediately
buttons.remove(atOffsets: indexSet)
// Sync to view model
for id in buttonIDs {
viewModel.removeButtonSync(id, from: sectionType)
removeButton(id: id)
}
// Update available types
syncAvailableTypes()
}
} header: {
Text(String(localized: "settings.playerControls.addedButtons"))
@@ -175,6 +181,15 @@ struct SectionEditorView: View {
}
}
private func removeButton(id: UUID) {
// Update local state immediately
buttons.removeAll { $0.id == id }
// Sync to view model
viewModel.removeButtonSync(id, from: sectionType)
// Update available types
syncAvailableTypes()
}
private func addButton(_ buttonType: ControlButtonType) {
// Create new config and add to local state immediately
let config = ControlButtonConfiguration.defaultConfiguration(for: buttonType)