~dricottone/nspotify

ref: 56b2cbc10494067680a81e3209195c229f99b5e6 nspotify/app.go -rw-r--r-- 3.0 KiB
56b2cbc1Dominic Ricottone Adding docs 5 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package main

import (
	"context"
	"os"

	log "github.com/sirupsen/logrus"
	"github.com/zmb3/spotify/v2"
	"github.com/gdamore/tcell/v2"
	"github.com/rivo/tview"
)

// Start the core application and return once it terminates.
func Start(ctx context.Context, rx <-chan *spotify.FullTrack, tx chan<- *Event) {
	ctx, cancel := context.WithCancel(ctx)
	app := tview.NewApplication()
	pages := tview.NewPages()

	logs := tview.NewTextView().SetDynamicColors(true).SetScrollable(false).ScrollToEnd()
	log.SetOutput(tview.ANSIWriter(logs))
	pages.AddPage("logs", logs, true, true)

	// End user pressed one of `Escape`, `Enter`, `Tab`, or `Backtab` on the logs
	// page.
	logs.SetDoneFunc(func(key tcell.Key) {
		pages.SwitchToPage("listing")
	})

	// Redraw if logs have been written.
	logs.SetChangedFunc(func() {
		app.Draw()
	})

	listing := tview.NewTable().SetSelectable(true, false).Select(0, 0)
	go ListingManager(ctx, listing, rx)
	pages.AddPage("listing", listing, true, false)

	// End user pressed `Enter` on the listing page.
	listing.SetSelectedFunc(func(row, _ int) {
		uri, ok := listing.GetCell(row, 0).GetReference().(spotify.URI)
		if !ok {
			log.Error("invalid URI")
		} else {
			tx <- RequestPlayURI(uri)
		}
	})

	// End user pressed one of `Escape`, `Tab`, or `Backtab` on the listing page.
	// Also triggers if user pressed `Enter` when nothing is selected.
	listing.SetDoneFunc(func(key tcell.Key) {
	})

	listing.SetInputCapture(func(ev *tcell.EventKey) *tcell.EventKey {
		if ev.Key() == tcell.KeyRune {
			switch ev.Rune() {

			// End user pressed `p` on the listing.
			case 'p':
				tx <- RequestToggle()

			// End user pressed `f` on the listing.
			case 'f':
				tx <- RequestPlayNext()

			// End user pressed `b` on the listing.
			case 'b':
				tx <- RequestPlayPrevious()

			// End user pressed `Space` on the listing.
			case ' ':
				row, _ := listing.GetSelection()
				uri, ok := listing.GetCell(row, 0).GetReference().(spotify.URI)
				if !ok {
					log.Error("invalid URI")
				} else {
					tx <- RequestQueueURI(uri)
				}

			}
		}

		// Pass event back to primitive for other handlers.
		return ev
	})

	app.SetInputCapture(func(ev *tcell.EventKey) *tcell.EventKey {
		switch ev.Key() {

		// End user pressed `F1` anywhere.
		case tcell.KeyF1:
			pages.SwitchToPage("listing")
			return nil

		// End user pressed `F2` anywhere.
		case tcell.KeyF2:
			pages.SwitchToPage("logs")
			return nil

		// End user pressed `F3` anywhere.
		case tcell.KeyF3:
			// show help

		case tcell.KeyRune:

			switch ev.Rune() {

			// End user pressed `?` anywhere.
			case '?':
				// show help

			// End user pressed `q` anywhere.
			case 'q':
				app.Stop()
				return nil
			}
		}

		// Pass event back to application, will be routed to focused
		// primitive.
		return ev
	})

	// This will block until the application dies.

	err := app.SetRoot(pages, true).Run()
	cancel()

	log.SetOutput(os.Stdout)
	if err != nil {
		log.WithError(err).Fatal("application died")
	}

	// TODO: for long-running programs, maybe need to periodically run cli.RefreshToken?
}