Skip to content

Commit 146e25b

Browse files
committed
Remove legacy selection infrastructure and dead UI components
- Remove ModeManager (dead modes: deletePolyrhythm, mobileSelection, selectByMouseOver) - Remove MouseHandler (redundant — SelectionView handles all interactions) - Remove NoteViewer (unused component — only static getParityClass retained) - Remove TouchHoldDetector (only referenced by NoteViewer) - Remove legacy currentTrackSelections/ITrackSelection from SelectionManager - Remove isSelected(note) — callers use currentSelection directly - Extract getParityClass from NoteViewer into core/utils.ts - Add Requisitions notesClicked event for click-to-play audio preview - Publish selected note IDs from SelectionManager.endSelection - Clean up ScoreBookUiServices, App.tsx, ArrangementEditControls, SelectionControls - Fix Minimap and SelectionManager tests for removed dependencies Signed-off-by: Mike Lischke <mike@lischke-online.de>
1 parent 63462b4 commit 146e25b

15 files changed

Lines changed: 122 additions & 982 deletions

src/App.tsx

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,16 @@ import {
5555
import type { IArrangementSnapshot } from "./core/types/general.js";
5656
import { UndoManager } from "./core/UndoManager.js";
5757
import { convertErrorToString } from "./core/utils.js";
58+
import { getSharedAudioContext } from "./core/audio-context.js";
5859
import { ArrangementPlayer } from "./player/ArrangementPlayer.js";
60+
import { AudioBufferPlayer } from "./player/AudioBufferPlayer.js";
5961
import type { ScoreBookUiServices } from "./player/types.js";
6062
import { escapeStack } from "./supplement/EscapeStack.js";
6163
import { requisitions } from "./supplement/Requisitions.js";
6264
import { BackendDisconnectedDialog } from "./ui/BackendDisconnectedDialog.js";
6365
import { BackendSetupDialog } from "./ui/BackendSetupDialog.js";
6466
import { LoginDialog } from "./ui/LoginDialog.js";
6567
import { AdminSetupDialog } from "./ui/AdminSetupDialog.js";
66-
import { ModeManager } from "./ui/ModeManager.js";
67-
import { MouseHandler } from "./ui/MouseHandler.js";
6868
import { SelectionManager } from "./ui/SelectionManager.js";
6969
import { SettingsDialog } from "./ui/SettingsDialog.js";
7070
import { TutorialWizard } from "./ui/TutorialWizard.js";
@@ -138,8 +138,6 @@ export class App extends UIComponent<{}, IAppState> {
138138
private arrangementPlayer?: ArrangementPlayer;
139139
private undoManager?: UndoManager;
140140

141-
private mouseHandler?: MouseHandler;
142-
143141
private justFinishedEditingTitle = false;
144142

145143
private currentPlayRange?: { startBar: number; endBar: number; };
@@ -167,7 +165,6 @@ export class App extends UIComponent<{}, IAppState> {
167165
const selectionManager = new SelectionManager();
168166
this.services = {
169167
selectionManager,
170-
modeManager: new ModeManager(selectionManager),
171168
};
172169

173170
this.initEventHandlers();
@@ -185,6 +182,7 @@ export class App extends UIComponent<{}, IAppState> {
185182
requisitions.register("notificationStateChanged", this.handleNotificationStateChanged);
186183
requisitions.register("backendDisconnected", this.handleBackendDisconnected);
187184
requisitions.register("authChanged", this.handleAuthChanged);
185+
requisitions.register("notesClicked", this.handleNoteClicked);
188186

189187
void this.checkBackendThenInitialize();
190188
}
@@ -217,6 +215,7 @@ export class App extends UIComponent<{}, IAppState> {
217215
requisitions.unregister("notificationStateChanged", this.handleNotificationStateChanged);
218216
requisitions.unregister("backendDisconnected", this.handleBackendDisconnected);
219217
requisitions.unregister("authChanged", this.handleAuthChanged);
218+
requisitions.unregister("notesClicked", this.handleNoteClicked);
220219
}
221220

222221
public render() {
@@ -743,6 +742,33 @@ export class App extends UIComponent<{}, IAppState> {
743742
return Promise.resolve(true);
744743
};
745744

745+
private handleNoteClicked = (noteIds: number[]): Promise<boolean> => {
746+
const arrangement = this.dataModel.arrangement;
747+
if (!arrangement || noteIds.length === 0) {
748+
return Promise.resolve(false);
749+
}
750+
751+
const noteId = noteIds[0];
752+
753+
for (const track of arrangement.tracks) {
754+
for (const measure of track.measures) {
755+
const event = measure.events.find((e) => {
756+
return e.id === noteId;
757+
});
758+
759+
if (event?.audioData?.audioBuffer) {
760+
const volume = arrangement.mainVolume / 100;
761+
762+
new AudioBufferPlayer(event.audioData.audioBuffer, getSharedAudioContext(), 0, volume);
763+
764+
return Promise.resolve(true);
765+
}
766+
}
767+
}
768+
769+
return Promise.resolve(false);
770+
};
771+
746772
/**
747773
* Handles the result of a login dialog show() call for non-pipeline paths.
748774
*
@@ -1458,8 +1484,6 @@ export class App extends UIComponent<{}, IAppState> {
14581484
window.addEventListener("keyup", (event) => {
14591485
this.handleKeyUp(event);
14601486
});
1461-
1462-
this.mouseHandler = new MouseHandler(this.services.modeManager, this.services.selectionManager);
14631487
}
14641488

14651489
private onSidebarEscape = (): void => {
@@ -1479,13 +1503,11 @@ export class App extends UIComponent<{}, IAppState> {
14791503
case "Escape": {
14801504
Overlay.closeAllOverlays();
14811505
this.services.selectionManager.clearSelection();
1482-
this.services.modeManager.deletePolyrhythmMode = false;
14831506

14841507
break;
14851508
}
14861509

14871510
case "Alt": {
1488-
this.services.modeManager.deletePolyrhythmMode = true;
14891511
event.preventDefault();
14901512

14911513
break;
@@ -1497,7 +1519,7 @@ export class App extends UIComponent<{}, IAppState> {
14971519
this.undoManager?.edit({
14981520
type: "EditCommand_ArrangementClearSelection",
14991521
arrangement: this.dataModel.arrangement!,
1500-
clearSelection: this.services.selectionManager.currentTrackSelections
1522+
clearSelection: new Map()
15011523
});
15021524
this.services.selectionManager.clearSelection();
15031525
}
@@ -1535,9 +1557,7 @@ export class App extends UIComponent<{}, IAppState> {
15351557
}
15361558

15371559
private handleKeyUp(event: KeyboardEvent): void {
1538-
if (event.key === "Alt") {
1539-
this.services.modeManager.deletePolyrhythmMode = false;
1540-
}
1560+
// No-op: previously reset deletePolyrhythmMode on Alt key up.
15411561
}
15421562

15431563
private onEditEnd = () => {

src/components/ui/Arrangement/ArrangementEditControls.tsx

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export class ArrangementEditControls
4141
}
4242

4343
public override componentDidMount(): void {
44-
const { dataModel, services } = this.props;
44+
const { dataModel } = this.props;
4545
const { arePolyrhythms } = this.state;
4646

4747
const arrangement = dataModel.arrangement!;
@@ -57,7 +57,6 @@ export class ArrangementEditControls
5757
const hasPolyrhythms = this.hasPolyrhythms(arrangement);
5858
if (!hasPolyrhythms) {
5959
Overlay.toggleOverlay("delete_polyrhythms", "hide");
60-
services.modeManager.deletePolyrhythmMode = false;
6160
}
6261

6362
if (arePolyrhythms !== hasPolyrhythms) {
@@ -79,7 +78,6 @@ export class ArrangementEditControls
7978
const { arePolyrhythms } = this.state;
8079

8180
const arrangementView = dataModel.arrangement!;
82-
const modeManager = services.modeManager;
8381

8482
// TODO: move this to a score creation dialog. Changing that in an existing score makes no sense.
8583
/*const signatureSelect = (
@@ -119,7 +117,6 @@ export class ArrangementEditControls
119117
<>
120118
<Button
121119
onClick={() => {
122-
modeManager.deletePolyrhythmMode = true;
123120
Overlay.toggleOverlay("delete_polyrhythms", "show");
124121
}}
125122
>Delete polyrhythms...</Button>
@@ -168,7 +165,7 @@ export class ArrangementEditControls
168165
<ExpandingSpacer />
169166
<Button
170167
onClick={() => {
171-
return modeManager.deletePolyrhythmMode = false;
168+
Overlay.toggleOverlay("delete_polyrhythms", "hide");
172169
}}
173170
>
174171
Done
@@ -204,7 +201,7 @@ export class ArrangementEditControls
204201
}
205202

206203
private onArrangementChanged = (arrangementId: number): Promise<boolean> => {
207-
const { dataModel, services } = this.props;
204+
const { dataModel } = this.props;
208205
const arrangement = dataModel.arrangement!;
209206

210207
if (arrangementId !== arrangement.id) {
@@ -214,8 +211,6 @@ export class ArrangementEditControls
214211
const arePolyrhythms = this.hasPolyrhythms(arrangement);
215212
if (!arePolyrhythms) {
216213
Overlay.toggleOverlay("delete_polyrhythms", "hide");
217-
218-
services.modeManager.deletePolyrhythmMode = false;
219214
}
220215

221216
this.setState({ arePolyrhythms });
@@ -247,7 +242,7 @@ export class ArrangementEditControls
247242
};
248243

249244
private onTrackChanged = (trackId: number): Promise<boolean> => {
250-
const { dataModel, services } = this.props;
245+
const { dataModel } = this.props;
251246
const arrangement = dataModel.arrangement!;
252247

253248
// Only react if the changed track is one we care about.
@@ -260,7 +255,6 @@ export class ArrangementEditControls
260255
const arePolyrhythms = this.hasPolyrhythms(arrangement);
261256
if (!arePolyrhythms) {
262257
Overlay.toggleOverlay("delete_polyrhythms", "hide");
263-
services.modeManager.deletePolyrhythmMode = false;
264258
}
265259

266260
this.setState({ arePolyrhythms });
@@ -320,7 +314,7 @@ export class ArrangementEditControls
320314
const { services } = this.props;
321315

322316
const selectionManager = services.selectionManager;
323-
Overlay.toggleOverlay("selection_controls", selectionManager.currentTrackSelections.size ? "show" : "hide");
317+
Overlay.toggleOverlay("selection_controls", selectionManager.currentSelection.size ? "show" : "hide");
324318

325319
return Promise.resolve(true);
326320
};

src/components/ui/GuideRail/TimingViewer.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type { ComponentChild } from "preact";
88
import type { ITiming } from "../../../core/ScoreBookDataModel.js";
99
import type { ITimeParams } from "../../../core/types/general.js";
1010
import { UIComponent, type ICommonUIProperties } from "../framework/UIComponent.js";
11-
import { NoteViewer } from "../Note/NoteViewer.js";
11+
import { getParityClass } from "../../../core/utils.js";
1212
import { type BarDivisibility } from "./GuideRail.js";
1313
import { Container } from "../framework/Container.js";
1414
import { ChildAlignment } from "../framework/ui-types.js";
@@ -32,7 +32,7 @@ export class TimingViewer extends UIComponent<ITimingViewerProperties> {
3232
const className = this.generateFinalClassName([
3333
"guiderail-timing",
3434
"note-width",
35-
NoteViewer.getParityClass(bar, step, timeSignature, stepResolution),
35+
getParityClass(bar, step, timeSignature, stepResolution),
3636
this.classFromProperty(isStartOfBar, ["", "startOfBar"])
3737
]);
3838

0 commit comments

Comments
 (0)