mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 02:14:01 +00:00
refactor: keep Scene prompts with their controls
This commit is contained in:
1 parent
d42036d74f
commit
9b6d34cb8a
5 files changed
+77
-15
No files matched your search
@@ -323,7 +323,7 @@ original Display groups, independent scroll positions and current focus owner.
|
||||
|
||||
## Scene controls
|
||||
|
||||
`ui/scenes` owns Scene panel input, project/shot rows, playback button and runtime
|
||||
`ui/scenes` owns Scene prompts, panel input, project/shot rows, playback button and runtime
|
||||
presentation. It receives project reads and explicit actions, with no imports of
|
||||
the director, source modules, camera engine or storage. Replacement and disposal
|
||||
release listeners; pending action feedback is limited to its current owner.
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Scene control ownership
|
||||
|
||||
Scene controls own panel listeners, shot rows, playback/recording presentation
|
||||
Scene controls own creation/deletion prompts, panel listeners, shot rows, playback/recording presentation
|
||||
and keyboard cancellation. The director supplies project reads and explicit
|
||||
editing/playback actions while retaining persistence, camera and layer sequencing.
|
||||
Replacing rows revokes their old listeners. Disposal stops controls immediately;
|
||||
|
||||
+3
-10
@@ -417,7 +417,7 @@ export class SceneDirector {
|
||||
this._saveProject();
|
||||
this._renderShotList();
|
||||
},
|
||||
create: () => this._createScene(),
|
||||
create: (name) => this._createScene(name),
|
||||
deleteScene: () => this._deleteSelectedScene(),
|
||||
capture: () => this.captureShot(),
|
||||
update: () => this.updateSelectedShot(),
|
||||
@@ -474,9 +474,8 @@ export class SceneDirector {
|
||||
return { scene, shot };
|
||||
}
|
||||
|
||||
/** Prompt the user for a name and append a new empty scene to the project. */
|
||||
_createScene() {
|
||||
const sceneName = window.prompt('New scene name', `Scene ${this._project.scenes.length + 1}`);
|
||||
/** Append a named empty scene after the controls accept the creation prompt. */
|
||||
_createScene(sceneName) {
|
||||
if (!sceneName) return;
|
||||
|
||||
const scene = {
|
||||
@@ -498,9 +497,6 @@ export class SceneDirector {
|
||||
const scene = this._getSelectedScene();
|
||||
if (!scene) return;
|
||||
|
||||
const ok = window.confirm(`Delete scene "${scene.title}" and all shots?`);
|
||||
if (!ok) return;
|
||||
|
||||
this._project.scenes = this._project.scenes.filter((item) => item.id !== scene.id);
|
||||
// Restore default recipes if the user deleted all scenes
|
||||
if (!this._project.scenes.length) {
|
||||
@@ -596,9 +592,6 @@ export class SceneDirector {
|
||||
const { scene, shot } = this._getShot(sceneId, shotId);
|
||||
if (!scene || !shot) return;
|
||||
|
||||
const ok = window.confirm(`Delete shot "${shot.title}"?`);
|
||||
if (!ok) return;
|
||||
|
||||
scene.shots = scene.shots.filter((item) => item.id !== shot.id);
|
||||
this._selectedShotId = scene.shots[0]?.id || null;
|
||||
this._saveProject();
|
||||
|
||||
+30
-3
@@ -25,8 +25,6 @@ export class SceneControls {
|
||||
this.run('selectScene', elements.select.value),
|
||||
);
|
||||
for (const [element, action] of Object.entries({
|
||||
new: 'create',
|
||||
delete: 'deleteScene',
|
||||
capture: 'capture',
|
||||
update: 'update',
|
||||
next: 'next',
|
||||
@@ -35,6 +33,8 @@ export class SceneControls {
|
||||
})) {
|
||||
this.listen(elements[element], 'click', () => this.run(action));
|
||||
}
|
||||
this.listen(elements.new, 'click', () => this.createScene());
|
||||
this.listen(elements.delete, 'click', () => this.deleteSelectedScene());
|
||||
this.listen(elements.start, 'click', () =>
|
||||
this.run('start', this.read().selectedSceneId),
|
||||
);
|
||||
@@ -79,6 +79,33 @@ export class SceneControls {
|
||||
if (!this.destroyed) renderSceneOptions(this.elements.select, this.read());
|
||||
}
|
||||
|
||||
createScene() {
|
||||
if (this.destroyed) return;
|
||||
const name = window.prompt(
|
||||
'New scene name',
|
||||
`Scene ${this.read().scenes.length + 1}`,
|
||||
);
|
||||
if (name) this.run('create', name);
|
||||
}
|
||||
|
||||
deleteSelectedScene() {
|
||||
if (this.destroyed) return;
|
||||
const state = this.read();
|
||||
const scene = state.scenes.find(
|
||||
(item) => item.id === state.selectedSceneId,
|
||||
);
|
||||
if (scene && window.confirm(`Delete scene "${scene.title}" and all shots?`))
|
||||
this.run('deleteScene');
|
||||
}
|
||||
|
||||
deleteShot(sceneId, shotId) {
|
||||
if (this.destroyed) return;
|
||||
const scene = this.read().scenes.find((item) => item.id === sceneId);
|
||||
const shot = scene?.shots.find((item) => item.id === shotId);
|
||||
if (shot && window.confirm(`Delete shot "${shot.title}"?`))
|
||||
this.run('deleteShot', sceneId, shotId);
|
||||
}
|
||||
|
||||
renderShotList() {
|
||||
if (this.destroyed) return;
|
||||
for (const remove of this.rowRemovers.splice(0)) remove();
|
||||
@@ -89,7 +116,7 @@ export class SceneControls {
|
||||
rename: (sceneId, shotId, title) =>
|
||||
this.run('renameShot', sceneId, shotId, title),
|
||||
load: (sceneId, shotId) => this.run('load', sceneId, shotId),
|
||||
remove: (sceneId, shotId) => this.run('deleteShot', sceneId, shotId),
|
||||
remove: (sceneId, shotId) => this.deleteShot(sceneId, shotId),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -262,3 +262,45 @@ test('Scene action failures are visible only while that action still owns presen
|
||||
f.restore();
|
||||
}
|
||||
});
|
||||
|
||||
test('creation and deletion prompts precede their model actions and remain inert after disposal', () => {
|
||||
const f = fixture();
|
||||
try {
|
||||
let prompts = 0;
|
||||
window.prompt = () => {
|
||||
prompts++;
|
||||
return null;
|
||||
};
|
||||
window.confirm = () => {
|
||||
prompts++;
|
||||
return false;
|
||||
};
|
||||
f.elements.new.click();
|
||||
f.elements.delete.click();
|
||||
f.owner.deleteShot('scene-a', 'shot-a');
|
||||
assert.deepEqual(f.calls, []);
|
||||
window.prompt = () => {
|
||||
prompts++;
|
||||
return 'New title';
|
||||
};
|
||||
window.confirm = () => {
|
||||
prompts++;
|
||||
return true;
|
||||
};
|
||||
f.elements.new.click();
|
||||
f.elements.delete.click();
|
||||
f.owner.deleteShot('scene-a', 'shot-a');
|
||||
assert.deepEqual(f.calls, [
|
||||
['create', 'New title'],
|
||||
['deleteScene'],
|
||||
['deleteShot', 'scene-a', 'shot-a'],
|
||||
]);
|
||||
f.owner.destroy();
|
||||
f.owner.createScene();
|
||||
f.owner.deleteSelectedScene();
|
||||
f.owner.deleteShot('scene-a', 'shot-a');
|
||||
assert.equal(prompts, 6);
|
||||
} finally {
|
||||
f.restore();
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user