Mercurial > code > home > repos > light9
changeset 2135:197a4ec877a7
acso relayout so only the song list scrolls
author | drewp@bigasterisk.com |
---|---|
date | Mon, 06 Jun 2022 01:15:17 +0000 |
parents | 40475b0ee0ba |
children | a9697b5d3077 |
files | light9/ascoltami/Light9AscoltamiUi.ts light9/ascoltami/index.html |
diffstat | 2 files changed, 258 insertions(+), 108 deletions(-) [+] |
line wrap: on
line diff
--- a/light9/ascoltami/Light9AscoltamiUi.ts Sun Jun 05 22:55:06 2022 +0000 +++ b/light9/ascoltami/Light9AscoltamiUi.ts Mon Jun 06 01:15:17 2022 +0000 @@ -9,7 +9,6 @@ import { getTopGraph } from "../web/RdfdbSyncedGraph"; import { SyncedGraph } from "../web/SyncedGraph"; import { TimingUpdate } from "./main"; -import { ResourceDisplay } from '../web/ResourceDisplay'; export { Light9TimelineAudio } from "../web/light9-timeline-audio"; export { Light9CursorCanvas } from "../web/Light9CursorCanvas"; export { RdfdbSyncedGraph } from "../web/RdfdbSyncedGraph"; @@ -37,13 +36,17 @@ @property() isPlaying: boolean = false; @property() show: NamedNode | null = null; @property() song: NamedNode | null = null; - @property() requestedSong: NamedNode | null = null; + @property() selectedSong: NamedNode | null = null; @property() currentDuration: number = 0; @property() zoom: Zoom; @property() overviewZoom: Zoom; @property() viewState: PlainViewState | null = null; static styles = [ css` + :host { + display: flex; + flex-direction: column; + } .timeRow { margin: 14px; position: relative; @@ -62,52 +65,158 @@ width: 100%; height: 100%; } + #grow { + + flex: 1 1 auto; + display: flex; + + } + #grow > span { + display: flex; + position: relative; + width:50%; + } + #playSelected { + height:100px; + } + #songList { + overflow-y: scroll; + position: absolute; + left:0;top:0;right:0;bottom:0; + } + #songList .row { + width: 60%; + min-height: 40px; + text-align: left; + position: relative; + } + #songList .row:nth-child(even) {background: #333;} + #songList .row:nth-child(odd) {background: #444;} + #songList button { + min-height: 40px; + margin-bottom: 10px; + } + #songList .row.playing { + box-shadow: 0 0 30px red; + background-color: #de5050; + } `, ]; render() { return html`<rdfdb-synced-graph></rdfdb-synced-graph> -<link rel="stylesheet" href="./style.css" /> - -<!-- <h1>ascoltami <a href="metrics">[metrics]</a></h1> --> -<!-- <div> - songlist: - ${this.songList.map((song) => html` - <div>song: <resource-display .uri=${song}></resource-display> - </div> - `)} -</div> --> -<div class="timeRow"> - <div id="timeSlider"></div> - <light9-timeline-audio id="overview" .show=${this.show} .song=${this.song} .zoom=${this.overviewZoom}> - </light9-timeline-audio> - <light9-timeline-audio id="zoomed" .show=${this.show} .song=${this.song} .zoom=${this.zoom}></light9-timeline-audio> - <light9-cursor-canvas id="cursor" .viewState=${this.viewState}></light9-cursor-canvas> -</div> + <link rel="stylesheet" href="./style.css" /> -<div class="commands"> - <button id="cmd-stop" @click=${this.onCmdStop} class="playMode ${classMap({ active: !this.isPlaying })}"> - <strong>Stop</strong> - <div class="key">s</div> - </button> - <button id="cmd-play" @click=${this.onCmdPlay} class="playMode ${classMap({ active: this.isPlaying })}"> - <strong>Play</strong> - <div class="key">p</div> - </button> - <button id="cmd-intro" @click=${this.onCmdIntro}> - <strong>Skip intro</strong> - <div class="key">i</div> - </button> - <button id="cmd-post" @click=${this.onCmdPost}> - <strong>Skip to Post</strong> - <div class="key">t</div> - </button> - <button id="cmd-go" @click=${this.onCmdGo}> - <strong>Go</strong> - <div class="key">g</div> - <div id="next">${this.nextText}</div> - </button> -</div>`; + <!-- <h1>ascoltami <a href="metrics">[metrics]</a></h1> --> + + <div id="grow"> + <span> + <div id="songList"> + <table> + ${this.songList.map( + (song) => html` + <tr + class="row ${classMap({ + playing: !!(this.song && song.equals(this.song)), + })}" + > + <td><resource-display .uri=${song}></resource-display></td> + <td> + <button @click=${this.onSelectSong.bind(this, song)}> + <span>Select</span> + </button> + </td> + </tr> + ` + )} + </table> + </div> + </span><span> + + <div id="right"> + <div> + Selected: + <resource-display .uri=${this.selectedSong}></resource-display> + </div> + <div> + <button id="playSelected" + ?disabled=${this.selectedSong === null} + @click=${this.onPlaySelected} + > + Play selected from start + </button> + </div> + </div> + </span> + </div> + + + <div class="timeRow"> + <div id="timeSlider"></div> + <light9-timeline-audio + id="overview" + .show=${this.show} + .song=${this.song} + .zoom=${this.overviewZoom} + > + </light9-timeline-audio> + <light9-timeline-audio + id="zoomed" + .show=${this.show} + .song=${this.song} + .zoom=${this.zoom} + ></light9-timeline-audio> + <light9-cursor-canvas + id="cursor" + .viewState=${this.viewState} + ></light9-cursor-canvas> + </div> + + <div class="commands"> + <button + id="cmd-stop" + @click=${this.onCmdStop} + class="playMode ${classMap({ active: !this.isPlaying })}" + > + <strong>Stop</strong> + <div class="key">s</div> + </button> + <button + id="cmd-play" + @click=${this.onCmdPlay} + class="playMode ${classMap({ active: this.isPlaying })}" + > + <strong>Play</strong> + <div class="key">p</div> + </button> + <button id="cmd-intro" @click=${this.onCmdIntro}> + <strong>Skip intro</strong> + <div class="key">i</div> + </button> + <button id="cmd-post" @click=${this.onCmdPost}> + <strong>Skip to Post</strong> + <div class="key">t</div> + </button> + <button id="cmd-go" @click=${this.onCmdGo}> + <strong>Go</strong> + <div class="key">g</div> + <div id="next">${this.nextText}</div> + </button> + </div>`; + } + + onSelectSong(song: NamedNode, ev: MouseEvent) { + if (this.selectedSong && song.equals(this.selectedSong)) { + this.selectedSong = null; + } else { + this.selectedSong = song; + } + } + async onPlaySelected(ev: Event) { + if (!this.selectedSong) { + return; + } + await fetch("api/song", { method: "POST", body: this.selectedSong.value }); } onCmdStop(ev?: MouseEvent): void { @@ -120,7 +229,10 @@ postJson("api/time", { t: this.times.intro, resume: true }); } onCmdPost(ev?: MouseEvent): void { - postJson("api/time", { t: this.currentDuration - this.times.post, resume: true }); + postJson("api/time", { + t: this.currentDuration - this.times.post, + resume: true, + }); } onCmdGo(ev?: MouseEvent): void { postJson("api/go", {}); @@ -162,9 +274,7 @@ try { const h1 = document.querySelector("h1")!; h1.innerText = h1.innerText.replace("{{host}}", config.host); - } catch (e) { - - } + } catch (e) {} byId("nav").innerText = navigator.userAgent; var updateFreq = navigator.userAgent.indexOf("Linux") != -1 ? 10 : 2; if (navigator.userAgent.match(/Windows NT/)) { @@ -173,31 +283,40 @@ } byId("updateReq").innerText = "" + updateFreq; - (window as any).finishOldStyleSetup(this.times, updateFreq, (data: TimingUpdate) => { - this.nextText = data.next; - this.isPlaying = data.playing; - this.currentDuration = data.duration; - this.song = new NamedNode(data.song); - this.overviewZoom = { duration: data.duration, t1: 0, t2: data.duration }; - const t1 = data.t - 2, - t2 = data.t + 20; - this.zoom = { duration: data.duration, t1, t2 }; - const timeRow = this.shadowRoot!.querySelector(".timeRow") as HTMLDivElement; - const w = timeRow.offsetWidth; - this.viewState = { - zoomSpec: { t1: () => t1, t2: () => t2 }, - cursor: { t: () => data.t }, - audioY: () => 0, - audioH: () => 60, - zoomedTimeY: () => 60, - zoomedTimeH: () => 40, - fullZoomX: (sec: number) => (sec / data.duration) * w, - zoomInX: (sec: number) => ((sec - t1) / (t2 - t1)) * w, - mouse: { pos: () => $V([0, 0]) }, - }; - }); + (window as any).finishOldStyleSetup( + this.times, + updateFreq, + this.onOldStyleUpdate.bind(this) + ); } - @property() songList: NamedNode[] = [] + + onOldStyleUpdate(data: TimingUpdate) { + this.nextText = data.next; + this.isPlaying = data.playing; + this.currentDuration = data.duration; + this.song = new NamedNode(data.song); + this.overviewZoom = { duration: data.duration, t1: 0, t2: data.duration }; + const t1 = data.t - 2, + t2 = data.t + 20; + this.zoom = { duration: data.duration, t1, t2 }; + const timeRow = this.shadowRoot!.querySelector( + ".timeRow" + ) as HTMLDivElement; + const w = timeRow.offsetWidth; + this.viewState = { + zoomSpec: { t1: () => t1, t2: () => t2 }, + cursor: { t: () => data.t }, + audioY: () => 0, + audioH: () => 60, + zoomedTimeY: () => 60, + zoomedTimeH: () => 40, + fullZoomX: (sec: number) => (sec / data.duration) * w, + zoomInX: (sec: number) => ((sec - t1) / (t2 - t1)) * w, + mouse: { pos: () => $V([0, 0]) }, + }; + } + + @property() songList: NamedNode[] = []; constructor() { super(); this.bindKeys(); @@ -206,21 +325,22 @@ getTopGraph().then((g) => { this.graph = g; this.musicSetup(); // async - this.graph.runHandler(this.graphChanged.bind(this), 'loadsongs'); + this.graph.runHandler(this.graphChanged.bind(this), "loadsongs"); }); } graphChanged() { - this.songList = [] + this.songList = []; try { - const playList = this.graph.uriValue(// - this.graph.Uri('http://light9.bigasterisk.com/show/dance2022'), - this.graph.Uri(':playList')); - log(playList) + const playList = this.graph.uriValue( + // + this.graph.Uri("http://light9.bigasterisk.com/show/dance2022"), + this.graph.Uri(":playList") + ); + log(playList); this.songList = this.graph.items(playList) as NamedNode[]; } catch (e) { - log('no playlist yet') + log("no playlist yet"); } log(this.songList.length); - } }
--- a/light9/ascoltami/index.html Sun Jun 05 22:55:06 2022 +0000 +++ b/light9/ascoltami/index.html Mon Jun 06 01:15:17 2022 +0000 @@ -11,47 +11,77 @@ padding-left: 0.4em; } .dimStalled #currentTime { - font-size:70px; + font-size: 40px; + background: green; + color: black; + padding: 3px; } .dimStalled { - font-size:70% + font-size: 90%; + } + body { + margin: 0; + padding: 0; + overflow: hidden; + min-height: 100vh; + } + #page { + width: 100%; + height: 90vh; /* my phone was losing the bottom :( */ + display: flex; + flex-direction: column; + } + #page > div, + #page > p { + flex: 0 1 auto; + margin: 0; + } + light9-ascoltami-ui { + flex: 1 1 auto; } </style> - <meta name="viewport" content="user-scalable=no, width=500, initial-scale=1" /> + <meta + name="viewport" + content="user-scalable=no, width=500, initial-scale=1" + /> <script type="module" src="../ascoltami/Light9AscoltamiUi"></script> </head> <body> <h1>ascoltami on {{host}}</h1> - <div class="songs"></div> + <div id="page"> + <div class="songs" style="display: none"></div> - <div class="dimStalled"> - <table> - <tr> - <td colspan="3"><strong>Song:</strong> <span id="currentSong"></span></td> - </tr> - <tr> - <td><strong>Time:</strong> <span id="currentTime"></span></td> - <td><strong>Left:</strong> <span id="leftTime"></span></td> - <td><strong>Until autostop:</strong> <span id="leftAutoStopTime"></span></td> - </tr> - <tr> - <td colspan="3"> - <strong>Update freq:</strong> requested <span id="updateReq"></span>, actual <span id="updateActual"></span> <strong>States:</strong> - <span id="states"></span> - </td> - </tr> - </table> + <div class="dimStalled"> + <table> + <tr> + <td colspan="3"> + <strong>Song:</strong> <span id="currentSong"></span> + </td> + </tr> + <tr> + <td><strong>Time:</strong> <span id="currentTime"></span></td> + <td><strong>Left:</strong> <span id="leftTime"></span></td> + <td> + <strong>Until autostop:</strong> + <span id="leftAutoStopTime"></span> + </td> + </tr> + <tr> + <td colspan="3"> + <strong>Update freq:</strong> requested + <span id="updateReq"></span>, actual + <span id="updateActual"></span> <strong>States:</strong> + <span id="states"></span> + </td> + </tr> + </table> + </div> + <hr /> + <light9-ascoltami-ui></light9-ascoltami-ui> + <p>Running on <span id="nav"></span></p> + <p><a href="">reload</a></p> </div> - - <hr /> - new ui is here - <light9-ascoltami-ui></light9-ascoltami-ui> - <hr /> - - <p>Running on <span id="nav"></span></p> - <p><a href="">reload</a></p> - <script type="module" src="../ascoltami/main.ts"></script> </body> </html>