refactored ui

This commit is contained in:
Ondrej Zara 2019-03-26 10:09:26 +01:00
parent 0e43a33c4a
commit d8644edd7e
7 changed files with 109 additions and 63 deletions

View file

@ -1,5 +1,7 @@
body {
margin: 0;
max-width: 800px;
margin: 0 auto;
overflow: hidden;
display: flex;
flex-direction: column;
height: 100vh;

View file

@ -1,5 +1,7 @@
body {
margin: 0;
max-width: 800px;
margin: 0 auto;
overflow: hidden;
display: flex;
flex-direction: column;
height: 100vh;

View file

@ -6,7 +6,6 @@ import * as format from "./lib/format.js";
import * as ui from "./lib/ui.js";
let node;
const SORT = "-Track";
function buildHeader(path) {
filter = filter || {};
@ -33,13 +32,14 @@ function buildHeader(path) {
function buildDirectory(data, parent) {
let path = data["directory"];
let node = ui.group(path, {}, parent);
let name = path.split("/").pop();
let node = ui.group(ui.GROUP_DIRECTORY, name, path, parent);
node.addEventListener("click", e => list(path));
return node;
}
function buildFile(data, parent) {
return ui.song(data, parent);
return ui.song(ui.SONG_FILE, data, parent);
}
function buildResults(results) {

View file

@ -77,13 +77,13 @@ export async function listQueue() {
return parser.songList(lines);
}
export async function enqueue(fileOrFilter, sort = null) {
if (typeof(fileOrFilter) == "string") {
return command(`addid "${escape(fileOrFilter)}"`);
export async function enqueue(urlOrFilter, sort = null) {
if (typeof(urlOrFilter) == "string") {
return command(`add "${escape(urlOrFilter)}"`);
}
let tokens = ["findadd"];
tokens.push(serializeFilter(fileOrFilter));
tokens.push(serializeFilter(urlOrFilter));
// sort && tokens.push("sort", sort); FIXME not implemented in MPD
return command(tokens.join(" "));
}

View file

@ -1,47 +1,113 @@
import * as mpd from "./mpd.js";
import * as html from "./html.js";
import * as pubsub from "./pubsub.js";
import * as format from "./format.js";
import * as player from "../player.js";
function playButton(fileOrFilter, parent) {
export const SONG_FILE = 1;
export const SONG_LIBRARY = 2;
export const SONG_QUEUE = 3;
export const GROUP_DIRECTORY = 4;
export const GROUP_LIBRARY = 5;
const SORT = "-Track";
function fileName(data) {
return data["file"].split("/").pop();
}
function formatTitle(type, data) {
switch (type) {
case SONG_FILE:
return `🎵 ${fileName(data)}`;
break;
case SONG_LIBRARY:
return data["Artist"] || fileName(data);
break;
case SONG_QUEUE:
let tokens = [];
data["Artist"] && tokens.push(data["Artist"]);
data["Title"] && tokens.push(data["Title"]);
if (!tokens.length) { tokens.push(fileName(data)); }
return tokens.join(" - ");
break;
}
}
function playButton(id, parent) {
let button = html.button({className:"play"}, "▶", parent);
button.addEventListener("click", async e => {
await mpd.command(`playid ${id}`);
player.update();
});
}
function deleteButton(id, parent) {
let button = html.button({className:"delete"}, "🗙", parent);
button.addEventListener("click", async e => {
await mpd.command(`deleteid ${id}`);
pubsub.publish("queue-change");
});
return button;
}
function addAndPlayButton(urlOrFilter, parent) {
let button = html.button({}, "▶", parent);
button.addEventListener("click", async e => {
e.stopPropagation();
await mpd.command("clear");
await mpd.enqueue(fileOrFilter, SORT);
await mpd.enqueue(urlOrFilter, SORT);
await mpd.command("play");
app.activate("queue");
pubsub.publish("queue-change");
player.update();
});
return button;
}
function addButton(fileOrFilter, parent) {
function addButton(urlOrFilter, parent) {
let button = html.button({}, "+", parent);
button.addEventListener("click", async e => {
e.stopPropagation();
await mpd.enqueue(fileOrFilter, SORT);
await mpd.enqueue(urlOrFilter, SORT);
pubsub.publish("queue-change");
// fixme notification?
});
return button;
}
export function song(data, parent) {
export function song(type, data, parent) {
let node = html.node("li", {}, "", parent);
let file = data["file"];
playButton(file, node);
addButton(file, node);
let title = formatTitle(type, data);
html.node("h2", {}, title, node);
html.node("h3", {}, data["Title"], node);
html.node("span", {className:"duration"}, format.time(Number(data["duration"])), node);
if (type == SONG_QUEUE) {
let id = data["Id"];
node.dataset.songId = id;
playButton(id, node);
deleteButton(id, node);
} else {
let url = data["file"];
addAndPlayButton(url, node);
addButton(url, node);
}
return node;
}
export function group(label, filter, parent) {
export function group(type, label, urlOrFilter, parent) {
let node = html.node("li", {}, label, parent);
playButton(filter, node);
addButton(filter, node);
if (type == GROUP_DIRECTORY) {
node.insertBefore(html.text("📁 "), node.firstChild);
}
addAndPlayButton(urlOrFilter, node);
addButton(urlOrFilter, node);
return node;
}

View file

@ -1,12 +1,8 @@
import * as app from "./app.js";
import * as mpd from "./lib/mpd.js";
import * as html from "./lib/html.js";
import * as player from "./player.js";
import * as format from "./lib/format.js";
import * as ui from "./lib/ui.js";
let node;
const SORT = "-Track";
function buildHeader(filter) {
filter = filter || {};
@ -33,14 +29,14 @@ function buildHeader(filter) {
function buildAlbum(album, filter, parent) {
let childFilter = Object.assign({}, filter, {"Album": album});
let node = ui.group(album, childFilter, parent);
let node = ui.group(ui.GROUP_LIBRARY, album, childFilter, parent);
node.addEventListener("click", e => listSongs(childFilter));
return node;
}
function buildArtist(artist, filter, parent) {
let childFilter = Object.assign({}, filter, {"Artist": artist});
let node = ui.group(artist, childFilter, parent);
let node = ui.group(ui.GROUP_LIBRARY, artist, childFilter, parent);
node.addEventListener("click", e => listAlbums(childFilter));
return node;
}
@ -49,7 +45,7 @@ function buildSongs(songs, filter) {
let ul = node.querySelector("ul");
html.clear(ul);
songs.map(song => ui.song(song, ul));
songs.map(song => ui.song(ui.SONG_LIBRARY, song, ul));
}
function buildAlbums(albums, filter) {

View file

@ -1,8 +1,7 @@
import * as mpd from "./lib/mpd.js";
import * as html from "./lib/html.js";
import * as player from "./player.js";
import * as pubsub from "./lib/pubsub.js";
import * as format from "./lib/format.js";
import * as ui from "./lib/ui.js";
let node;
let currentId;
@ -14,40 +13,11 @@ function updateCurrent() {
});
}
async function playSong(id) {
await mpd.command(`playid ${id}`);
player.update();
}
async function deleteSong(id) {
await mpd.command(`deleteid ${id}`);
activate();
}
function buildSong(song) {
let id = Number(song["Id"]);
let node = html.node("li");
node.dataset.songId = id;
html.button({className:"play"}, "▶", node).addEventListener("click", e => playSong(id));
let info = html.node("div", {className:"info"}, "", node);
html.node("h2", {className:"title"}, song["Title"], info);
html.node("span", {className:"artist-album"}, format.artistAlbum(song["Artist"], song["Album"]), info);
html.node("span", {className:"duration"}, format.time(Number(song["duration"])), info);
html.button({className:"delete"}, "🗙", node).addEventListener("click", e => deleteSong(id));
return node;
}
function buildSongs(songs) {
let ul = node.querySelector("ul");
html.clear(ul);
songs.map(buildSong).forEach(li => ul.appendChild(li));
songs.map(song => ui.song(ui.SONG_QUEUE, song, ul));
updateCurrent();
}
@ -57,12 +27,22 @@ function onSongChange(message, publisher, data) {
updateCurrent();
}
export async function activate() {
function onQueueChange(message, publisher, data) {
syncQueue();
}
async function syncQueue() {
let songs = await mpd.listQueue();
buildSongs(songs);
// FIXME updateCount(songs.length)
}
export async function activate() {
syncQueue();
}
export function init(n) {
node = n;
pubsub.subscribe("song-change", onSongChange);
pubsub.subscribe("queue-change", onQueueChange);
}