diff options
Diffstat (limited to 'ui.js')
-rw-r--r-- | ui.js | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/ui.js b/ui.js index 4fe1d8a..8d912a2 100644 --- a/ui.js +++ b/ui.js @@ -1,9 +1,13 @@ +const { getAllCrawlersForArg } = require('./crawlers') const { getDownloaderFor } = require('./downloaders') const { getPlayer } = require('./players') const { parentSymbol, isGroup, isTrack, getItemPath, getItemPathString, flattenGrouplike } = require('./playlist-utils') const { shuffleArray } = require('./general-util') +const processSmartPlaylist = require('./smart-playlist') + const ansi = require('./tui-lib/util/ansi') const Button = require('./tui-lib/ui/form/Button') +const Dialog = require('./tui-lib/ui/Dialog') const DisplayElement = require('./tui-lib/ui/DisplayElement') const FocusElement = require('./tui-lib/ui/form/FocusElement') const Form = require('./tui-lib/ui/form/Form') @@ -11,6 +15,7 @@ const Label = require('./tui-lib/ui/Label') const ListScrollForm = require('./tui-lib/ui/form/ListScrollForm') const Pane = require('./tui-lib/ui/Pane') const RecordStore = require('./record-store') +const TextInput = require('./tui-lib/ui/form/TextInput') const WrapLabel = require('./tui-lib/ui/WrapLabel') const telc = require('./tui-lib/util/telchars') const unic = require('./tui-lib/util/unichars') @@ -92,6 +97,64 @@ class AppElement extends FocusElement { this.playbackInfoElement = new PlaybackInfoElement() this.playbackPane.addChild(this.playbackInfoElement) + + // Dialogs + + this.openPlaylistDialog = new OpenPlaylistDialog() + this.setupDialog(this.openPlaylistDialog) + + this.openPlaylistDialog.on('source selected', source => this.handlePlaylistSource(source)) + + this.alertDialog = new AlertDialog() + this.setupDialog(this.alertDialog) + } + + async handlePlaylistSource(source) { + this.openPlaylistDialog.close() + this.alertDialog.showMessage('Opening playlist...', false) + + let grouplike + try { + grouplike = await this.openPlaylist(source) + } catch (error) { + if (error === 'unknown argument') { + this.alertDialog.showMessage('Could not figure out how to load a playlist from: ' + source) + } else if (typeof error === 'string') { + this.alertDialog.showMessage(error) + } else { + throw error + } + + return + } + + this.alertDialog.close() + this.root.select(this.form) + + grouplike = await processSmartPlaylist(grouplike) + this.grouplikeListingElement.loadGrouplike(grouplike) + } + + openPlaylist(arg) { + const crawlers = getAllCrawlersForArg(arg) + + if (crawlers.length === 0) { + throw 'unknown argument' + } + + const crawler = crawlers[0] + + return crawler(arg) + } + + setupDialog(dialog) { + dialog.visible = false + this.addChild(dialog) + + dialog.on('cancelled', () => { + dialog.close() + this.root.select(this.form) + }) } async setup() { @@ -155,6 +218,8 @@ class AppElement extends FocusElement { } else if (telc.isCharacter(keyBuf, '2') && this.queueListingElement.selectable) { this.form.curIndex = this.form.inputs.indexOf(this.queueListingElement) this.form.updateSelectedElement() + } else if (keyBuf.equals(Buffer.from([15]))) { // ctrl-O + this.openPlaylistDialog.open() } else { super.keyPressed(keyBuf) } @@ -843,4 +908,105 @@ class PlaybackInfoElement extends DisplayElement { } } +class OpenPlaylistDialog extends Dialog { + constructor() { + super() + + this.label = new Label('Enter a playlist source:') + this.pane.addChild(this.label) + + this.form = new Form() + this.pane.addChild(this.form) + + this.input = new TextInput() + this.form.addInput(this.input) + + this.button = new Button('Open') + this.form.addInput(this.button) + + this.button.on('pressed', () => { + if (this.input.value) { + this.emit('source selected', this.input.value) + } + }) + } + + opened() { + this.input.setValue('') + this.form.curIndex = 0 + this.form.updateSelectedElement() + } + + fixLayout() { + super.fixLayout() + + this.pane.w = Math.min(60, this.contentW) + this.pane.h = 5 + this.pane.centerInParent() + + this.label.centerInParent() + this.label.y = 0 + + this.form.w = this.pane.contentW + this.form.h = 2 + this.form.y = 1 + + this.input.w = this.form.contentW + + this.button.centerInParent() + this.button.y = 1 + } + + focused() { + this.root.select(this.form) + } +} + +class AlertDialog extends Dialog { + constructor() { + super() + + this.label = new Label() + this.pane.addChild(this.label) + + this.button = new Button('Close') + this.button.on('pressed', () => { + if (this.canClose) { + this.emit('cancelled') + } + }) + this.pane.addChild(this.button) + } + + focused() { + this.root.select(this.button) + } + + showMessage(message, canClose = true) { + this.canClose = canClose + this.label.text = message + this.button.text = canClose ? 'Close' : '(Hold on...)' + this.open() + } + + fixLayout() { + super.fixLayout() + + this.pane.w = Math.min(this.label.w + 4, this.contentW) + this.pane.h = 4 + this.pane.centerInParent() + + this.label.centerInParent() + this.label.y = 0 + + this.button.fixLayout() + this.button.centerInParent() + this.button.y = 1 + } + + keyPressed() { + // Don't handle the escape key. + } +} + module.exports.AppElement = AppElement |