pocket

package
v0.5.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 16, 2026 License: MIT Imports: 26 Imported by: 0

Documentation

Overview

Package pocket is pixeltui's hardware-player front-end: it renders a now-playing screen and maps physical buttons onto playback, driving the headless session.Controller. The actual panel and GPIO live behind the Display/Buttons interfaces — a Raspberry Pi + Pirate Audio (ST7789 + buttons) backend for the device, and a laptop dev backend (PNG out + keyboard) so it runs anywhere.

Index

Constants

View Source
const Size = 240

Size is the square panel edge (the Pirate Audio ST7789 is 240×240).

Variables

View Source
var Debug bool

Debug, when set (via POCKET_DEBUG in cmdPocket), logs each button press so tap-vs-hold detection can be verified on-device over SSH / journalctl.

Functions

func Render

func Render(v View) *image.RGBA

Render draws the now-playing screen at Size×Size.

func ToRGB565

func ToRGB565(img *image.RGBA) []byte

ToRGB565 converts an RGBA frame to big-endian RGB565 bytes — the pixel format the ST7789 expects for a RAMWR blit.

Types

type App

type App struct {
	// contains filtered or unexported fields
}

App is the on-device player: a navigation stack of screens (menus, lists, now playing, volume) driven by the four buttons, rendered to the panel.

func NewApp

func NewApp(ctrl Controller, disp Display, btns Buttons, src Sources, cover CoverFunc) *App

NewApp builds the pocket app, opening on the home menu. cover/src may be nil.

func (*App) Run

func (a *App) Run(ctx context.Context) error

Run renders and reacts until ctx is cancelled. The caller starts the Controller's own poll loop (session.Controller.Run) so progress events flow.

func (*App) SetHost

func (a *App) SetHost(fn func())

SetHost injects the party-hosting action invoked by the "Host Party" menu item.

func (*App) SetOffline

func (a *App) SetOffline(b bool)

SetOffline updates the connectivity badge (driven by a connectivity.Monitor). Safe to call from another goroutine — it routes through the render loop.

func (*App) SetParty

func (a *App) SetParty(room *party.Room)

SetParty enters or leaves party mode. In a party the ROOM is the source of truth: the local player follows the room (applyRoom), so the pocket stays in sync with phones; the shared queue lives in the room; and the pocket's own controls drive the room. Pass nil to leave. Call from a goroutine OTHER than the one running Run — it hands the change to the render loop and waits for it (so it must not be called from a button handler, which runs on the Run loop).

func (*App) ShowParty

func (a *App) ShowParty(qr, caption string)

ShowParty pushes the join-QR screen (called once hosting is up). Safe from another goroutine — it routes through the render loop.

type Button

type Button int

Button is a physical button. On the Pirate Audio the four sit at the screen corners — A top-left, B bottom-left, X top-right, Y bottom-right — and what each does is context-sensitive to the current screen (see handle).

const (
	BtnA Button = iota // top-left
	BtnB               // bottom-left
	BtnX               // top-right
	BtnY               // bottom-right
)

type Buttons

type Buttons interface {
	Events() <-chan Press
	Close() error
}

Buttons delivers physical button presses until closed.

func NewDevButtons

func NewDevButtons() Buttons

NewDevButtons returns a Buttons driven by stdin keypresses.

func NewPiButtons

func NewPiButtons() (Buttons, error)

NewPiButtons wires the four tactile buttons as active-low inputs with pull-ups. Each button gets a watcher goroutine that samples its level to time taps vs. holds.

type Controller

type Controller interface {
	Current() engine.Candidate
	Queue() []engine.Candidate
	Playing() bool
	TogglePause()
	Next()
	Prev()
	Play(engine.Candidate) error
	PlayAll([]engine.Candidate, int)
	Enqueue(...engine.Candidate)
	Shuffle()
	SetRepeat(session.RepeatMode)
	SetAutoplay(bool)
	SetVolume(int)
	Seek(float64)
	Stop()
	Events() <-chan session.Event
}

Controller is the slice of session.Controller the pocket UI drives (an interface so the app loop is testable with a fake).

type CoverFunc

type CoverFunc func(engine.Candidate) image.Image

CoverFunc decodes album art for a track (may be slow; called off the UI loop).

type Display

type Display interface {
	Push(img *image.RGBA) error
	Close() error
}

Display renders a frame to the panel and is closed on shutdown.

func NewDevDisplay

func NewDevDisplay(path string) Display

NewDevDisplay returns a Display that writes frames to a PNG at path.

func NewPiDisplay

func NewPiDisplay() (Display, error)

NewPiDisplay opens the ST7789 panel on the Pirate Audio board.

type Press

type Press struct {
	Btn  Button
	Long bool
}

Press is a button event: which button, and whether it was a long-press (hold).

type Sources

type Sources struct {
	Registry *source.Registry // optional: drives charts and source-aware downloads

	Liked      func() []engine.Candidate            // liked tracks
	Playlists  func() []string                      // playlist names
	Playlist   func(name string) []engine.Candidate // a playlist's tracks
	History    func() []engine.Candidate            // recently played
	Charts     func() []engine.Candidate            // top charts (sourced from the registry)
	Downloaded func() []engine.Candidate            // on-device files (downloads + local) — play offline

	// Per-track actions (the hold-Y menu); any may be nil.
	Like     func(engine.Candidate)
	Unlike   func(engine.Candidate)
	IsLiked  func(engine.Candidate) bool
	Download func(engine.Candidate) error
}

Sources supplies the browsable library/catalog the menus list. Any field may be nil (its menu just shows empty). cmdPocket wires these to the library + the central source registry.

type View

type View struct {
	Mode   string // "standalone" | "serve" | "party"
	Track  engine.Candidate
	Pos    float64
	Dur    float64
	Paused bool
	Status string      // shown when there's no track (e.g. "queue empty", a party code)
	Cover  image.Image // optional album art (decoded); nil → no art
	Frame  int         // animation frame (drives marquee scrolling of long names)
}

View is the state the now-playing screen draws.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL