diff --git a/index.html b/index.html
index fb4f18f..0688342 100644
--- a/index.html
+++ b/index.html
@@ -107,18 +107,9 @@
diff --git a/src/browser.js b/src/browser.js
index db3062f..a73a11e 100644
--- a/src/browser.js
+++ b/src/browser.js
@@ -7,7 +7,6 @@ import List from "./list.js"
import * as entry from "./entry.js"
import * as mode from "./mode.js"
import * as device from "device"
-import { OnEntryListKeydown } from "./util.js"
const app = window.app ??= {}
const view = window.view ??= {}
@@ -26,10 +25,9 @@ export const Init = async () => {
}
export const View = async () => {
- list = new List(
- view.browser = {},
- document.getElementById('browser')
- )
+ list = new List(view.browser = {
+ element: document.getElementById('browser')
+ })
Render()
}
@@ -63,44 +61,7 @@ export const Open = () => {
mode.Display('browser')
}
-export const OnKeydown = (event) => {
- let e = Focused()
-
- switch(event.key) {
- case 'SoftLeft':
- // PlayTrack()
- break
-
- case 'Escape':
- case 'Backspace':
- back()
- break
-
- case ' ':
- case 'Enter':
- if(e.entries) {
- Cd(e)
- break
- }
- case 'q':
- if(e.entries == null) {
- queue.Add(e)
- }
- list.Scroll(1)
- break;
-
- case 'r':
- case '7':
- app.browser.recursiveView = !app.browser.recursiveView
- Render()
- break
-
- default:
- return OnEntryListKeydown(list, event, e)
- }
-}
-
-export const back = () => {
+export const Back = () => {
let e = app.browser.current
if(e.root) {
return
@@ -112,7 +73,7 @@ export const back = () => {
}
}
-export const Cd = (entry = app.browser.root) => {
+export const Cd = (entry = Focused() || app.browser.root) => {
if(entry.entries) {
app.browser.current = entry
Render()
@@ -123,6 +84,28 @@ export const Cd = (entry = app.browser.root) => {
}
}
+export const Queue = (entry = Focused()) => {
+ queue.Add(entry)
+ list.Scroll(1)
+}
+
+export const QueueAllBelow = () => {
+ let e = app.browser.current.entries
+
+ for(let i = app.cursor; i < e.length; i++) {
+ queue.Add(e)
+ }
+}
+
+export const GoToDirectory = (entry = Focused()) => {
+ Cd(entry.parent) &&
+ list.Focus(app.browser.view.indexOf(entry))
+}
+
+export const ToggleRecursiveView = () => {
+ app.browser.recursiveView = !app.browser.recursiveView
+ Render()
+}
export const Focused = () => {
return app.browser.view[view.browser.cursor]
diff --git a/src/in b/src/in
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/in
@@ -0,0 +1 @@
+1
diff --git a/src/index.js b/src/index.js
index 22e7642..7834397 100644
--- a/src/index.js
+++ b/src/index.js
@@ -4,6 +4,7 @@ import * as queue from './queue.js'
import * as entry from './entry.js'
import * as mode from './mode.js'
import * as player from './player.js'
+import * as input from './input.js'
import * as device from 'device'
window.device = device
@@ -12,6 +13,7 @@ window.queue = queue
window.entry = entry
window.mode = mode
window.player = player
+window.input = input
window.main = main
document.addEventListener('load', main.Start())
\ No newline at end of file
diff --git a/src/input.js b/src/input.js
new file mode 100644
index 0000000..7b98530
--- /dev/null
+++ b/src/input.js
@@ -0,0 +1,210 @@
+const app = window.app ??= {}
+const view = window.view ??= {}
+
+const holdIntervals = 3
+const holdIntervalLength = 200
+
+import * as browser from './browser.js'
+import * as player from './player.js'
+import * as queue from './queue.js'
+
+export function Init() {
+}
+
+export function View() {
+ view.c
+
+ window.addEventListener('keydown', OnKeydown)
+ window.addEventListener('keyup', OnKeyup)
+
+ Render()
+}
+
+export function Render() {
+ Actions()
+}
+
+export function Actions() {
+ let a = view.actions = {}
+
+ a['ArrowRight'] = {
+ name: 'Next Panel',
+ up() {
+ mode.Scroll(1)
+ }
+ }
+ a['ArrowLeft'] = {
+ name: 'Prev Panel',
+ up() {
+ mode.Scroll(-1)
+ }
+ }
+ a['0'] = {
+
+ }
+
+ a['c'] = a.pausePlay = {
+ hint: 'Pause/Play',
+ up: player.TogglePausePlay
+ }
+ a['s'] = a.skip = {
+ hint: 'Next',
+ up: player.Next
+ }
+ a['+'] = a.volumeUp = {
+ hint: 'Volume Up',
+ down() {
+ navigator.volumeUp()
+ }
+ }
+ a['-'] = a.volumeDown = {
+ hint: 'Volume Down',
+ down() {
+ navigator.volumeDown()
+ }
+ }
+
+ switch(app.mode) {
+ case mode.states.PLAYER:
+ a[' '] = a['Enter'] = player.State() == player.states.PLAYING ?
+ {
+ hint: 'Play',
+ up: player.Play
+ } :
+ {
+ hint: 'Pause',
+ up: player.Pause
+ }
+ a['ArrowUp'] = a.volumeUp
+ a['ArrowDown'] = a.volumeDown
+ a['SoftRight'] = a.skip
+ break
+
+ case mode.states.BROWSER:
+ a['q'] = {
+ down: browser.Queue
+ }
+ a[' '] = a['Enter'] = {
+ hint: 'Queue',
+ press() {
+ browser.Cd() && browser.Queue()
+ },
+ holdHint: 'Queue All',
+ hold: browser.QueueAllBelow
+ }
+ a['4'] = a['g'] = {
+ up: browser.GoToDirectory
+ }
+ a['Backspace'] = a['Escape'] = {
+ up: browser.Back
+ }
+
+ listActions(browser.list)
+ break
+
+ case mode.states.QUEUE:
+ listActions(queue.list)
+
+ a[' '] = a['Enter'] = {
+ hint: 'Remove',
+ press: queue.Remove,
+ holdHint: 'Remove All',
+ hold: queue.RemoveAllBelow
+ }
+ a['SoftLeft'] = a['['] = a['ArrowUp'].shift = {
+ down() {
+ queue.Move(-1)
+ }
+ }
+ a['SoftRight'] = a[']'] = a['ArrowDown'].shift = {
+ down() {
+ queue.Move(1)
+ }
+ }
+ a['4'] = a['g'] = {
+ up() {
+ browser.GoToDirectory(queue.Focused())
+ mode.Set(mode.states.BROWSER)
+ }
+ }
+ break
+ }
+}
+
+function listActions(list) {
+ let a = view.actions
+
+ a['ArrowUp'] = {
+ down() {
+ list.Scroll(-1)
+ }
+ }
+ a['ArrowDown'] = {
+ down() {
+ list.Scroll(1)
+ }
+ }
+}
+
+export function OnKeydown(event) {
+ let a = view.actions[event.key]
+ if(a == null) return
+
+ ActionDown(a.shift && event.shiftKey ? a.shift : a)
+ && event.preventDefault()
+}
+
+export function ActionDown(action) {
+ if(action.holdTimeout != null) {
+ return true
+ }
+
+ if(action.down) {
+ return action.down()
+ }
+
+ if(action.hold) {
+ Hold(action)
+ } else if(action.press) {
+ return action.press()
+ }
+}
+
+export function OnKeyup(event) {
+ let a = view.actions[event.key]
+ if(a == null) return
+
+ ActionUp(a.shift && event.shiftKey ? a.shift : a)
+ && event.preventDefault()
+}
+
+export function ActionUp(action) {
+ if(action.holdTimeout != null) {
+ clearTimeout(action.holdTimeout)
+ action.holdTimeout = null
+ }
+
+ if(action.up) {
+ return action.up()
+ }
+
+ if(action.heldCount > 0) {
+ return action.press()
+ }
+}
+
+export function Hold(aAction) {
+ aAction.heldCount = holdIntervals
+ createHoldTimeout(aAction)
+}
+
+export function createHoldTimeout(aAction) {
+ aAction.holdTimeout = setTimeout(() => {
+ aAction.heldCount--
+ if(aAction.heldCount == 0) {
+ aAction.hold()
+ } else {
+ createHoldTimeout(aAction)
+ }
+ }, holdIntervalLength)
+}
diff --git a/src/list.js b/src/list.js
index 8203fa7..53d8411 100644
--- a/src/list.js
+++ b/src/list.js
@@ -1,6 +1,5 @@
-export default function List(view, element) {
+export default function List(view) {
- view.element = element
view.cursor = 0
const Render = this.Render = (entries, iResetCursorTo = view.cursor) => {
@@ -89,20 +88,5 @@ export default function List(view, element) {
}
}
- const OnKeydown = this.OnKeydown = (event) => {
- switch(event.key) {
- case 'ArrowDown':
- Scroll(1)
- break
-
- case 'ArrowUp':
- Scroll(-1)
- break
-
- default:
- return true
- }
- }
-
return this
}
\ No newline at end of file
diff --git a/src/main.js b/src/main.js
index d51d66f..3748720 100644
--- a/src/main.js
+++ b/src/main.js
@@ -6,6 +6,7 @@ import * as device from 'device'
import * as browser from './browser.js'
import * as entry from './entry.js'
import * as mode from './mode.js'
+import * as input from './input.js'
export let store
export let saveTimeout
@@ -47,9 +48,8 @@ export const View = async () => {
await queue.View()
await player.View()
mode.View()
+ input.View()
- window.addEventListener('keydown', OnKeydown)
-
// player.Render({ name: 'Timeland, Smoke & Mirrors, The Land Before Timeland, & Hypertension', artist: 'King Gizzard & The Lizard Wizard' })
}
diff --git a/src/mode.js b/src/mode.js
index 9cddff9..858b13a 100644
--- a/src/mode.js
+++ b/src/mode.js
@@ -4,6 +4,7 @@ const view = window.view ??= {}
import * as browser from './browser.js'
import * as player from './player.js'
import * as queue from './queue.js'
+import * as input from './input.js'
export let modules
export const states = {
@@ -27,6 +28,7 @@ export const View = () => {
modules[app.mode].Open()
Render()
+ input.Actions()
}
export const Display = (name) => {
diff --git a/src/player.js b/src/player.js
index 40444d7..1ea3049 100644
--- a/src/player.js
+++ b/src/player.js
@@ -61,7 +61,14 @@ export const textContainer = (eElement, sText) => {
export const Open = () => {
mode.Display('player')
- document.body.classList.add('paused')
+}
+
+export const TogglePausePlay = () => {
+ if(State() === states.PLAYING) {
+ Pause()
+ } else {
+ Play()
+ }
}
export const OnKeydown = (event) => {
diff --git a/src/queue.js b/src/queue.js
index a79fe52..e28be4e 100644
--- a/src/queue.js
+++ b/src/queue.js
@@ -2,22 +2,19 @@ import List from "./list.js"
import * as mode from "./mode.js"
import * as player from "./player.js"
-import { OnEntryListKeydown } from "./util.js"
const app = window.app ??= {}
const view = window.view ??= {}
-export let list
+export let list = new List(view.queue = {
+ element: document.getElementById('queue'),
+})
export const Init = async () => {
app.queue = []
}
export const View = async () => {
- list = new List(
- view.queue = {},
- document.getElementById('queue')
- )
Render()
}
@@ -25,36 +22,7 @@ export const Render = async () => {
list.Render(app.queue)
}
-export const OnKeydown = (event) => {
- let e = Focused()
-
- switch(event.key) {
- // case 'ArrowLeft':
- // back()
- // break
-
- // case 'ArrowRight':
- // cd(e)
- // break
-
- case '[':
- case 'SoftLeft':
- // Move track up
- Move(e, -1)
- break
-
- case ']':
- case 'SoftRight':
- // Move track down
- Move(e, 1)
- break;
-
- default:
- return OnEntryListKeydown(list, event, e)
- }
-}
-
-export const Move = (eTrack, offset) => {
+export const Move = (offset, eTrack = Focused()) => {
let i = view.queue.cursor + offset
if(i == app.queue.length || i < 0) {
return
@@ -70,17 +38,30 @@ export const Open = () => {
mode.Display('queue')
}
-
export const Focused = () => {
return app.queue[view.queue.cursor]
}
export const Add = (eTrack) => {
// TODO: solid way to determine if something is playable
+ if(eTrack.entries) {
+ return false
+ }
app.queue.push(eTrack)
if(app.queue.length == 1 && player.State() === player.states.EMPTY) {
player.Next()
}
+ return true
+}
+
+export const Remove = () => {
+ app.queue.splice(view.queue.cursor, 1)
+ Render()
+}
+
+export const RemoveAllBelow = () => {
+ app.queue = app.queue.slice(0, view.queue.cursor)
+ Render()
}
export const Shift = () => {
diff --git a/src/util.js b/src/util.js
deleted file mode 100644
index 6faa0d6..0000000
--- a/src/util.js
+++ /dev/null
@@ -1,13 +0,0 @@
-export const OnEntryListKeydown = (list, event, e) => {
- switch(event.key) {
- case '4':
- case 'g':
- browser.Open()
- browser.Cd(e.parent) &&
- list.Focus(app.browser.view.indexOf(e))
- break
-
- default:
- return list.OnKeydown(event)
- }
-}
\ No newline at end of file