Skip to content

Commit 97900fc

Browse files
committed
Progress in conversion
1 parent d7cd54e commit 97900fc

File tree

8 files changed

+462
-267
lines changed

8 files changed

+462
-267
lines changed

readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
![License](https://img.shields.io/github/license/mike-lischke/animada-score-book?style=for-the-badge&color=lightgreen)
33

44
<p align="center">
5-
<img src="src/assets/images/animada-logo.svg" title="Animada Store Book" alt="Animada Store Book" style="height: 200px" /><br/>
5+
<img src="src/assets/images/animada-logo2.svg" title="Animada Store Book" alt="Animada Store Book" style="height: 200px" /><br/>
66
</p>
77

88
<hr />

src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*/
55

6-
import "./app.css";
6+
import "./App.css";
77
import "./style.css";
88

99
import logo from "./assets/images/animada-logo.svg";

src/components/ui/arrangement/ArrangementControlsBottom.tsx

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,6 @@ export class ArrangementControlsBottom extends ComponentBase<{}, IArrangementCon
2424
private arrangementPlayerContext?: React.ContextType<typeof ArrangementPlayerContext>;
2525
private servicesContext?: React.ContextType<typeof ServicesContext>;
2626

27-
/*
28-
const arrangement: ArrangementView = useContext(ArrangementPlayerContext)!.arrangement;
29-
const modeManager = useContext(ServicesContext)!.modeManager;
30-
const edit = useEditCommand();
31-
32-
const[arePolyrhythms, setArePolyrhythms] = useState(hasPolyrhythms(arrangement));
33-
/
34-
useArrangementAndTracksSubscription(arrangement, () => {
35-
const arePolyrhythms = hasPolyrhythms(arrangement);
36-
if (!arePolyrhythms) {
37-
toggleOverlay("delete_polyrhythms", "hide");
38-
modeManager.deletePolyrhythmMode = false;
39-
}
40-
setArePolyrhythms(arePolyrhythms);
41-
});
42-
43-
useSubscription(modeManager, () => {
44-
if (!modeManager.deletePolyrhythmMode) {
45-
toggleOverlay("delete_polyrhythms", "hide");
46-
}
47-
});
48-
*/
4927
public constructor(props: {}) {
5028
super(props);
5129

@@ -60,7 +38,10 @@ useSubscription(modeManager, () => {
6038
this.subscribedTracks.forEach(track => {
6139
track.unsubscribe(this.arrangementCallback as Subscription);
6240
});
41+
6342
this.subscribedTracks.clear();
43+
this.arrangementPlayerContext = undefined;
44+
this.servicesContext = undefined;
6445
}
6546

6647
public render() {
@@ -190,7 +171,9 @@ useSubscription(modeManager, () => {
190171
const arePolyrhythms = this.hasPolyrhythms(arrangement);
191172
if (!arePolyrhythms) {
192173
toggleOverlay("delete_polyrhythms", "hide");
193-
//modeManager.deletePolyrhythmMode = false;
174+
175+
const modeManager = this.servicesContext!.modeManager;
176+
modeManager.deletePolyrhythmMode = false;
194177
}
195178
this.setState({ arePolyrhythms: arePolyrhythms });
196179
};
@@ -230,9 +213,11 @@ useSubscription(modeManager, () => {
230213
this.arrangementSubscription = arrangementSubscription;
231214

232215
const modeManager = servicesContext!.modeManager;
233-
if (!modeManager.deletePolyrhythmMode) {
234-
toggleOverlay("delete_polyrhythms", "hide");
235-
}
216+
modeManager.subscribe(() => {
217+
if (!modeManager.deletePolyrhythmMode) {
218+
toggleOverlay("delete_polyrhythms", "hide");
219+
}
220+
});
236221
}
237222
};
238223
};

src/components/ui/arrangement/ArrangementControlsTop.tsx

Lines changed: 143 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,15 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*/
55

6-
/* eslint-disable prefer-arrow/prefer-arrow-functions, @typescript-eslint/naming-convention, jsdoc/require-jsdoc */
7-
86
import pauseIcon from "../../../assets/images/icons/pause.svg";
97
import pencilIcon from "../../../assets/images/icons/pencil_white.svg";
108
import playIcon from "../../../assets/images/icons/play.svg";
119

12-
import { useCallback, useContext, useRef, useState } from "preact/hooks";
13-
import type { JSX } from "preact/jsx-runtime";
14-
15-
import type { ArrangementView } from "../../../core/index.js";
10+
import type { ComponentChild } from "preact";
11+
import type { ArrangementView, Subscription } from "../../../core/index.js";
1612
import { getEventEngine } from "../../../player/EventEngine.js";
17-
import { useStateSubscription } from "../../../ui/hooks/useStateSubscription.js";
18-
import { useSubscription } from "../../../ui/hooks/useSubscription.js";
1913
import { ServicesContext } from "../BananaDrumViewer.js";
14+
import { ComponentBase } from "../ComponentBase/ComponentBase.js";
2015
import { ExpandingSpacer } from "../ExpandingSpacer.js";
2116
import { Overlay, toggleOverlay } from "../Overlay.js";
2217
import { SelectionControls } from "../SelectionControls.js";
@@ -29,81 +24,150 @@ import { UndoRedo } from "./UndoRedo.js";
2924

3025
const eventEngine = getEventEngine();
3126

32-
export function ArrangementControlsTop(): JSX.Element {
33-
const [playing, setPlaying] = useState(eventEngine.state === "playing");
34-
useSubscription(eventEngine, () => {
35-
setPlaying(eventEngine.state === "playing");
36-
});
27+
interface IArrangementControlsTopState {
28+
playing: boolean;
29+
editingTitle: boolean;
30+
title: string;
31+
}
3732

38-
const arrangement: ArrangementView = useContext(ArrangementPlayerContext)!.arrangement;
33+
export class ArrangementControlsTop extends ComponentBase<{}, IArrangementControlsTopState> {
3934

40-
const selectionManager = useContext(ServicesContext)!.selectionManager;
41-
useSubscription(selectionManager, () => {
42-
toggleOverlay("selection_controls", selectionManager.selections.size ? "show" : "hide");
43-
});
44-
45-
const [editingTitle, setEditingTitle] = useState(false);
46-
const title = useStateSubscription(arrangement, (arrangement: ArrangementView) => {
47-
return arrangement.title;
48-
});
49-
const titleVisible = title || editingTitle;
50-
51-
const justFinishedEditingTitle = useRef(false);
52-
const onEditEnd = useCallback(() => {
53-
setEditingTitle(false);
54-
justFinishedEditingTitle.current = true;
35+
private arrangementPlayerContext?: React.ContextType<typeof ArrangementPlayerContext>;
36+
private servicesContext?: React.ContextType<typeof ServicesContext>;
37+
38+
private justFinishedEditingTitle = false;
39+
40+
public constructor(props: {}) {
41+
super(props);
42+
43+
this.state = {
44+
playing: eventEngine.state === "playing",
45+
editingTitle: false,
46+
title: "",
47+
};
48+
}
49+
50+
public override componentWillUnmount(): void {
51+
const arrangementPlayerContext = this.context as React.ContextType<typeof ArrangementPlayerContext>;
52+
const arrangement: ArrangementView = arrangementPlayerContext!.arrangement;
53+
const selectionManager = this.servicesContext!.selectionManager;
54+
55+
arrangement.unsubscribe(this.titleChangeSubscription as Subscription);
56+
eventEngine.unsubscribe(this.onPlaybackStateChange);
57+
selectionManager.unsubscribe(this.onSelectionChange as Subscription);
58+
}
59+
60+
public override render(): ComponentChild {
61+
const { playing, editingTitle, title } = this.state;
62+
63+
return (
64+
<ArrangementPlayerContext.Consumer>
65+
{(arrangementPlayerContext) => {
66+
return (
67+
<ServicesContext.Consumer>
68+
{(servicesContext) => {
69+
this.useSubscriptions(arrangementPlayerContext, servicesContext);
70+
const arrangement: ArrangementView = arrangementPlayerContext!.arrangement;
71+
const titleVisible = title.length > 0 || editingTitle;
72+
73+
return (
74+
<>
75+
<div className={titleVisible ? "" : "hidden"}>
76+
<ArrangementTitle editMode={editingTitle} onEditEnd={this.onEditEnd} />
77+
</div>
78+
<div className="arrangement-controls arrangement-controls-top">
79+
{
80+
playing ? (
81+
<button className="playback-control push-button" onClick={() => {
82+
eventEngine.stop();
83+
}}>
84+
<img src={pauseIcon} alt="stop" />
85+
</button>
86+
) : (
87+
<button className="playback-control push-button" onClick={() => {
88+
void eventEngine.play();
89+
}}>
90+
<img src={playIcon} alt="play" />
91+
</button>
92+
)
93+
}
94+
<SmallSpacer />
95+
<TimeControls arrangement={arrangement} />
96+
<SmallSpacer />
97+
98+
<div className='other-controls-wrapper'>
99+
<button
100+
className="push-button medium gray edit-title-button"
101+
onClick={this.onClickEditTitle}
102+
>
103+
T&nbsp;<img src={pencilIcon} style={{ height: "0.78em" }} />
104+
</button>
105+
<SmallSpacer />
106+
<UndoRedo />
107+
</div>
108+
109+
<SmallSpacer />
110+
<ExpandingSpacer />
111+
112+
<ShareButton />
113+
<Overlay name="selection_controls">
114+
<SelectionControls />
115+
</Overlay>
116+
</div>
117+
</>
118+
);
119+
}}
120+
</ServicesContext.Consumer>
121+
);
122+
}}
123+
</ArrangementPlayerContext.Consumer>
124+
);
125+
}
126+
127+
private useSubscriptions = (
128+
arrangementPlayerContext: React.ContextType<typeof ArrangementPlayerContext>,
129+
servicesContext?: React.ContextType<typeof ServicesContext>
130+
): void => {
131+
if (this.arrangementPlayerContext !== arrangementPlayerContext) {
132+
this.arrangementPlayerContext = arrangementPlayerContext;
133+
this.servicesContext = servicesContext;
134+
135+
eventEngine.subscribe(this.onPlaybackStateChange);
136+
137+
const arrangement = arrangementPlayerContext!.arrangement;
138+
arrangement.subscribe(this.titleChangeSubscription as Subscription);
139+
140+
const selectionManager = this.servicesContext!.selectionManager;
141+
selectionManager.subscribe(this.onSelectionChange as Subscription);
142+
143+
}
144+
};
145+
146+
private onEditEnd = () => {
147+
this.setState({ editingTitle: false });
148+
this.justFinishedEditingTitle = true;
55149
setTimeout(() => {
56-
return justFinishedEditingTitle.current = false;
150+
return this.justFinishedEditingTitle = false;
57151
}, 100);
58-
}, []);
152+
};
59153

60-
const onClickEditTitle = useCallback(() => {
61-
if (!justFinishedEditingTitle.current) {
62-
setEditingTitle(true);
154+
private onClickEditTitle = () => {
155+
if (!this.justFinishedEditingTitle) {
156+
this.setState({ editingTitle: true });
63157
}
64-
}, []);
65-
66-
return (
67-
<>
68-
<div className={titleVisible ? "" : "hidden"}>
69-
<ArrangementTitle editMode={editingTitle} onEditEnd={onEditEnd} />
70-
</div>
71-
<div className="arrangement-controls arrangement-controls-top">
72-
{
73-
playing ? (
74-
<button className="playback-control push-button" onClick={() => {
75-
eventEngine.stop();
76-
}}>
77-
<img src={pauseIcon} alt="stop" />
78-
</button>
79-
) : (
80-
<button className="playback-control push-button" onClick={() => {
81-
void eventEngine.play();
82-
}}>
83-
<img src={playIcon} alt="play" />
84-
</button>
85-
)
86-
}
87-
<SmallSpacer />
88-
<TimeControls arrangement={arrangement} />
89-
<SmallSpacer />
90-
<div className='other-controls-wrapper'>
91-
<button
92-
className="push-button medium gray edit-title-button"
93-
onClick={onClickEditTitle}
94-
>
95-
T&nbsp;<img src={pencilIcon} style={{ height: "0.78em" }} />
96-
</button>
97-
<SmallSpacer />
98-
<UndoRedo />
99-
</div>
100-
<SmallSpacer />
101-
<ExpandingSpacer />
102-
<ShareButton />
103-
<Overlay name="selection_controls">
104-
<SelectionControls />
105-
</Overlay>
106-
</div>
107-
</>
108-
);
158+
};
159+
160+
private titleChangeSubscription = () => {
161+
const arrangement = this.arrangementPlayerContext!.arrangement;
162+
this.setState({ title: arrangement.title });
163+
};
164+
165+
private onPlaybackStateChange = () => {
166+
this.setState({ playing: eventEngine.state === "playing" });
167+
};
168+
169+
private onSelectionChange = () => {
170+
const selectionManager = this.servicesContext!.selectionManager;
171+
toggleOverlay("selection_controls", selectionManager.selections.size ? "show" : "hide");
172+
};
109173
}

0 commit comments

Comments
 (0)