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 @ViewBuilder
private func buttonRow(for config: ControlButtonConfiguration) -> some View { private func buttonRow(for config: ControlButtonConfiguration) -> some View {
if config.buttonType.hasSettings { Group {
NavigationLink { if config.buttonType.hasSettings {
MiniPlayerButtonConfigurationView( NavigationLink {
buttonID: config.id, MiniPlayerButtonConfigurationView(
viewModel: viewModel buttonID: config.id,
) viewModel: viewModel
} label: { )
} label: {
buttonRowContent(for: config)
}
} else {
buttonRowContent(for: config) 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 @ViewBuilder
private func buttonRow(for config: ControlButtonConfiguration) -> some View { private func buttonRow(for config: ControlButtonConfiguration) -> some View {
if config.buttonType.hasSettings { Group {
NavigationLink { if config.buttonType.hasSettings {
PillButtonConfigurationView( NavigationLink {
buttonID: config.id, PillButtonConfigurationView(
viewModel: viewModel buttonID: config.id,
) viewModel: viewModel
} label: { )
} label: {
buttonRowContent(for: config)
}
} else {
buttonRowContent(for: config) 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: { } label: {
ButtonRow(configuration: button) 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 .onMove { source, destination in
// Update local state immediately // Update local state immediately
@@ -93,16 +105,10 @@ struct SectionEditorView: View {
) )
} }
.onDelete { indexSet in .onDelete { indexSet in
// Get button IDs before removing from local state
let buttonIDs = indexSet.map { buttons[$0].id } let buttonIDs = indexSet.map { buttons[$0].id }
// Update local state immediately
buttons.remove(atOffsets: indexSet)
// Sync to view model
for id in buttonIDs { for id in buttonIDs {
viewModel.removeButtonSync(id, from: sectionType) removeButton(id: id)
} }
// Update available types
syncAvailableTypes()
} }
} header: { } header: {
Text(String(localized: "settings.playerControls.addedButtons")) 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) { private func addButton(_ buttonType: ControlButtonType) {
// Create new config and add to local state immediately // Create new config and add to local state immediately
let config = ControlButtonConfiguration.defaultConfiguration(for: buttonType) let config = ControlButtonConfiguration.defaultConfiguration(for: buttonType)