Add instrument checkbox selection

This commit is contained in:
diyaa
2026-09-14 06:20:07 +02:00
parent 6c6aeae5bb
commit 04d4093a3c
5 changed files with 106 additions and 14 deletions
@@ -2,6 +2,7 @@ import MusicAssistantCore
import SwiftUI
struct InstrumentBrowserView: View {
@Binding private var project: SongProject
private let catalog: LocalInstrumentCatalog
@State private var searchText = ""
@@ -9,7 +10,11 @@ struct InstrumentBrowserView: View {
@State private var selectedRegionOrigin: String?
@Environment(\.dismiss) private var dismiss
init(catalog: LocalInstrumentCatalog = LocalInstrumentCatalog()) {
init(
project: Binding<SongProject>,
catalog: LocalInstrumentCatalog = LocalInstrumentCatalog()
) {
_project = project
self.catalog = catalog
}
@@ -50,6 +55,7 @@ struct InstrumentBrowserView: View {
),
id: \.id
) { instrument in
Toggle(isOn: selectionBinding(for: instrument)) {
VStack(alignment: .leading, spacing: 4) {
Text(instrument.name)
.font(.body.weight(.medium))
@@ -65,6 +71,8 @@ struct InstrumentBrowserView: View {
.foregroundStyle(.secondary)
.lineLimit(1)
}
}
.toggleStyle(.checkbox)
.padding(.vertical, 2)
}
}
@@ -80,8 +88,31 @@ struct InstrumentBrowserView: View {
}
.frame(minWidth: 460, minHeight: 520)
}
private func selectionBinding(for instrument: InstrumentCatalogItem) -> Binding<Bool> {
Binding {
project.isInstrumentSelected(id: instrument.id)
} set: { isSelected in
project.setInstrumentSelected(
id: instrument.id,
isSelected: isSelected,
variant: instrument.name
)
}
}
}
#Preview {
InstrumentBrowserView()
InstrumentBrowserPreview()
}
private struct InstrumentBrowserPreview: View {
@State private var project = SongProject(
title: "Instrument Browser Preview",
idea: "Browse the instrument catalog."
)
var body: some View {
InstrumentBrowserView(project: $project)
}
}
@@ -146,7 +146,7 @@ struct ProjectInspectorView: View {
}
.background(Color(nsColor: .windowBackgroundColor))
.sheet(isPresented: $isInstrumentBrowserPresented) {
InstrumentBrowserView()
InstrumentBrowserView(project: $project)
}
}
@@ -312,6 +312,33 @@ public extension SongProject {
instruments[index].selected = false
}
mutating func setInstrumentSelected(
id instrumentId: String,
isSelected: Bool,
variant: String? = nil
) {
guard isSelected else {
deselectInstrument(id: instrumentId)
return
}
if let index = instruments.firstIndex(where: { $0.instrumentId == instrumentId }) {
instruments[index].selected = true
if instruments[index].variant == nil {
instruments[index].variant = variant
}
} else {
instruments.append(
InstrumentTrack(
instrumentId: instrumentId,
selected: true,
variant: variant
)
)
}
}
mutating func configureInstrument(
id instrumentId: String,
variant: String?,
@@ -281,6 +281,40 @@ final class SongProjectModelTests: XCTestCase {
XCTAssertEqual(project.instrumentTrack(for: "oud")?.placements, [introPlacement])
}
func testCatalogSelectionCanBeToggledWithoutReplacingExistingArrangement() {
let oudPlacement = InstrumentPlacement(sectionId: "intro", direction: "Opening melody")
var project = SongProject(
id: "catalog-selection-project",
title: "Catalog Selection",
idea: "Select and deselect instruments",
instruments: [
InstrumentTrack(
instrumentId: "oud",
selected: false,
variant: "Arabic oud",
playingStyle: "tremolo",
role: "main hook",
autoArrangementEnabled: false,
placements: [oudPlacement]
)
]
)
project.setInstrumentSelected(id: "oud", isSelected: true, variant: "Oud")
XCTAssertTrue(project.isInstrumentSelected(id: "oud"))
XCTAssertEqual(project.instrumentTrack(for: "oud")?.variant, "Arabic oud")
XCTAssertEqual(project.instrumentTrack(for: "oud")?.role, "main hook")
XCTAssertEqual(project.instrumentTrack(for: "oud")?.placements, [oudPlacement])
project.setInstrumentSelected(id: "oud", isSelected: false)
project.setInstrumentSelected(id: "violin", isSelected: true, variant: "Violin")
XCTAssertFalse(project.isInstrumentSelected(id: "oud"))
XCTAssertTrue(project.isInstrumentSelected(id: "violin"))
XCTAssertEqual(project.instrumentTrack(for: "violin")?.variant, "Violin")
}
func testMultipleVocalistsCanBeAssignedToSections() {
var project = SongProject(
id: "project-6",
+1 -1
View File
@@ -85,7 +85,7 @@ requirement is missing and blocks implementation, record it in
- [x] Build searchable instrument browser.
- [x] Add browsing/filtering by family/category.
- [x] Add browsing/filtering by region/origin where useful.
- [ ] Add checkbox-based multi-select and deselect behavior.
- [x] Add checkbox-based multi-select and deselect behavior.
- [ ] Persist selected instruments on the current Song Project.
- [ ] Make selected instruments available to OpenAI/song-generation
logic for arrangement, roles, entry/exit timing, relevant structure