2023-01-09 04:42:02 +00:00
package tui
import (
"fmt"
2023-01-11 17:45:29 +00:00
"time"
2023-01-09 04:42:02 +00:00
2023-01-14 06:27:38 +00:00
"gospt/src/gctx"
2023-01-09 04:42:02 +00:00
2023-01-27 06:28:57 +00:00
"github.com/atotto/clipboard"
2023-01-11 17:45:29 +00:00
"github.com/charmbracelet/bubbles/key"
2023-01-09 04:42:02 +00:00
"github.com/charmbracelet/bubbles/list"
2023-01-30 02:30:33 +00:00
"github.com/charmbracelet/bubbles/progress"
2023-01-13 09:12:31 +00:00
"github.com/charmbracelet/bubbles/textinput"
2023-01-09 04:42:02 +00:00
tea "github.com/charmbracelet/bubbletea"
2023-01-11 17:45:29 +00:00
"github.com/charmbracelet/lipgloss"
2023-01-09 04:42:02 +00:00
"github.com/zmb3/spotify/v2"
)
2023-01-11 17:45:29 +00:00
var (
2023-01-12 02:45:22 +00:00
P * tea . Program
DocStyle = lipgloss . NewStyle ( ) . Margin ( 0 , 2 )
2023-01-11 17:45:29 +00:00
currentlyPlaying string
main_updates chan * mainModel
page = 1
)
2023-01-11 04:46:15 +00:00
2023-01-14 01:41:52 +00:00
type Mode string
const (
2023-01-14 20:20:41 +00:00
Album Mode = "album"
ArtistAlbum = "artistalbum"
Artist = "artist"
Artists = "artists"
Tracks = "tracks"
Albums = "albums"
Main = "main"
Playlists = "playlists"
Playlist = "playlist"
Devices = "devices"
Search = "search"
SearchAlbums = "searchalbums"
SearchAlbum = "searchalbum"
SearchArtists = "searchartists"
SearchArtist = "searchartist"
SearchArtistAlbum = "searchartistalbum"
SearchTracks = "searchtracks"
SearchPlaylists = "searchplaylsits"
SearchPlaylist = "searchplaylist"
2023-01-14 01:41:52 +00:00
)
2023-01-09 04:42:02 +00:00
type mainItem struct {
Name string
2023-01-11 17:45:29 +00:00
Duration string
Artist spotify . SimpleArtist
ID spotify . ID
2023-01-09 04:42:02 +00:00
Desc string
SpotifyItem any
}
2023-01-14 20:20:41 +00:00
type SearchResults struct {
Tracks * spotify . FullTrackPage
Artists * spotify . FullArtistPage
Playlists * spotify . SimplePlaylistPage
Albums * spotify . SimpleAlbumPage
}
2023-01-09 04:42:02 +00:00
func ( i mainItem ) Title ( ) string { return i . Name }
func ( i mainItem ) Description ( ) string { return i . Desc }
func ( i mainItem ) FilterValue ( ) string { return i . Title ( ) + i . Desc }
type mainModel struct {
2023-01-14 20:20:41 +00:00
list list . Model
input textinput . Model
ctx * gctx . Context
client * spotify . Client
mode Mode
playlist spotify . SimplePlaylist
artist spotify . SimpleArtist
album spotify . SimpleAlbum
searchResults * SearchResults
2023-01-30 02:30:33 +00:00
progress progress . Model
playing * spotify . CurrentlyPlaying
2023-01-14 20:20:41 +00:00
search string
}
func ( m * mainModel ) PlayRadio ( ) {
2023-01-20 22:12:58 +00:00
currentlyPlaying = m . list . SelectedItem ( ) . ( mainItem ) . Title ( )
m . list . NewStatusMessage ( "Starting radio for " + currentlyPlaying )
2023-01-14 20:20:41 +00:00
selectedItem := m . list . SelectedItem ( ) . ( mainItem ) . SpotifyItem
switch selectedItem . ( type ) {
case spotify . SimplePlaylist :
go HandlePlaylistRadio ( m . ctx , m . client , selectedItem . ( spotify . SimplePlaylist ) )
return
2023-01-24 03:35:05 +00:00
case * spotify . SavedTrackPage :
2023-01-14 20:20:41 +00:00
go HandleLibraryRadio ( m . ctx , m . client )
return
case spotify . SimpleAlbum :
go HandleAlbumRadio ( m . ctx , m . client , selectedItem . ( spotify . SimpleAlbum ) . ID )
return
case spotify . FullAlbum :
go HandleAlbumRadio ( m . ctx , m . client , selectedItem . ( spotify . FullAlbum ) . ID )
return
case spotify . SimpleArtist :
go HandleArtistRadio ( m . ctx , m . client , selectedItem . ( spotify . SimpleArtist ) . ID )
return
case spotify . FullArtist :
go HandleArtistRadio ( m . ctx , m . client , selectedItem . ( spotify . FullArtist ) . ID )
return
default :
go HandleRadio ( m . ctx , m . client , m . list . SelectedItem ( ) . ( mainItem ) . ID )
return
}
2023-01-09 04:42:02 +00:00
}
2023-01-14 01:41:52 +00:00
func ( m * mainModel ) GoBack ( ) ( tea . Cmd , error ) {
switch m . mode {
case Main :
return tea . Quit , nil
case Albums , Artists , Tracks , Playlist , Devices , Search :
m . mode = Main
m . list . NewStatusMessage ( "Setting view to main" )
new_items , err := MainView ( m . ctx , m . client )
if err != nil {
fmt . Println ( err . Error ( ) )
}
m . list . SetItems ( new_items )
case Album :
m . mode = Albums
m . list . NewStatusMessage ( "Setting view to albums" )
new_items , err := AlbumsView ( m . ctx , m . client )
if err != nil {
fmt . Println ( err . Error ( ) )
return nil , err
}
m . list . SetItems ( new_items )
case Artist :
m . mode = Artists
m . list . NewStatusMessage ( "Setting view to artists" )
new_items , err := ArtistsView ( m . ctx , m . client )
if err != nil {
return nil , err
}
m . list . SetItems ( new_items )
case ArtistAlbum :
m . mode = Artist
m . list . NewStatusMessage ( "Opening " + m . artist . Name )
new_items , err := ArtistAlbumsView ( m . ctx , m . artist . ID , m . client )
if err != nil {
return nil , err
}
m . list . SetItems ( new_items )
case SearchArtists , SearchTracks , SearchAlbums , SearchPlaylists :
m . mode = Search
m . list . NewStatusMessage ( "Setting view to search for " + m . input . Value ( ) )
2023-01-14 20:20:41 +00:00
items , result , err := SearchView ( m . ctx , m . client , m . search )
2023-01-14 01:41:52 +00:00
if err != nil {
return nil , err
}
2023-01-14 20:20:41 +00:00
m . searchResults = result
2023-01-14 01:41:52 +00:00
m . list . SetItems ( items )
case SearchArtist :
m . mode = SearchArtists
2023-01-14 20:20:41 +00:00
m . list . NewStatusMessage ( "Setting view to artists" )
new_items , err := SearchArtistsView ( m . ctx , m . client , m . searchResults . Artists )
if err != nil {
return nil , err
}
m . list . SetItems ( new_items )
case SearchArtistAlbum :
m . mode = SearchArtist
m . list . NewStatusMessage ( "Opening " + m . artist . Name )
new_items , err := ArtistAlbumsView ( m . ctx , m . artist . ID , m . client )
if err != nil {
return nil , err
}
m . list . SetItems ( new_items )
2023-01-14 01:41:52 +00:00
case SearchAlbum :
m . mode = SearchAlbums
2023-01-14 20:20:41 +00:00
m . list . NewStatusMessage ( "Setting view to albums" )
new_items , err := SearchAlbumsView ( m . ctx , m . client , m . searchResults . Albums )
if err != nil {
return nil , err
}
m . list . SetItems ( new_items )
2023-01-14 01:41:52 +00:00
case SearchPlaylist :
m . mode = SearchPlaylists
2023-01-14 20:20:41 +00:00
m . list . NewStatusMessage ( "Setting view to playlists" )
new_items , err := SearchPlaylistsView ( m . ctx , m . client , m . searchResults . Playlists )
if err != nil {
return nil , err
}
m . list . SetItems ( new_items )
2023-01-14 01:41:52 +00:00
default :
page = 0
}
return nil , nil
}
2023-01-27 06:28:57 +00:00
type SpotifyUrl struct {
ExternalURLs map [ string ] string
}
func ( m * mainModel ) CopyToClipboard ( ) error {
item := m . list . SelectedItem ( ) . ( mainItem ) . SpotifyItem
m . list . NewStatusMessage ( "Copying link to " + item . ( mainItem ) . Title ( ) )
switch item . ( type ) {
case spotify . SimplePlaylist :
clipboard . WriteAll ( item . ( spotify . SimplePlaylist ) . ExternalURLs [ "spotify" ] )
case * spotify . FullPlaylist :
clipboard . WriteAll ( item . ( * spotify . FullPlaylist ) . ExternalURLs [ "spotify" ] )
case spotify . SimpleAlbum :
clipboard . WriteAll ( item . ( spotify . SimpleAlbum ) . ExternalURLs [ "spotify" ] )
case * spotify . FullAlbum :
clipboard . WriteAll ( item . ( * spotify . FullAlbum ) . ExternalURLs [ "spotify" ] )
case spotify . SimpleArtist :
clipboard . WriteAll ( item . ( spotify . SimpleArtist ) . ExternalURLs [ "spotify" ] )
case * spotify . FullArtist :
clipboard . WriteAll ( item . ( * spotify . FullArtist ) . ExternalURLs [ "spotify" ] )
case spotify . SimpleTrack :
clipboard . WriteAll ( item . ( spotify . SimpleTrack ) . ExternalURLs [ "spotify" ] )
case spotify . PlaylistTrack :
clipboard . WriteAll ( item . ( spotify . PlaylistTrack ) . Track . ExternalURLs [ "spotify" ] )
case spotify . SavedTrack :
clipboard . WriteAll ( item . ( spotify . SavedTrack ) . ExternalURLs [ "spotify" ] )
case spotify . FullTrack :
clipboard . WriteAll ( item . ( spotify . FullTrack ) . ExternalURLs [ "spotify" ] )
}
return nil
}
2023-01-14 20:20:41 +00:00
func ( m * mainModel ) SelectItem ( ) error {
switch m . mode {
case Search :
switch m . list . SelectedItem ( ) . ( mainItem ) . SpotifyItem . ( type ) {
case * spotify . FullArtistPage :
m . mode = SearchArtists
m . list . NewStatusMessage ( "Setting view to artists" )
new_items , err := SearchArtistsView ( m . ctx , m . client , m . list . SelectedItem ( ) . ( mainItem ) . SpotifyItem . ( * spotify . FullArtistPage ) )
if err != nil {
return err
}
m . list . SetItems ( new_items )
m . list . ResetSelected ( )
case * spotify . SimpleAlbumPage :
m . mode = SearchAlbums
m . list . NewStatusMessage ( "Setting view to albums" )
new_items , err := SearchAlbumsView ( m . ctx , m . client , m . list . SelectedItem ( ) . ( mainItem ) . SpotifyItem . ( * spotify . SimpleAlbumPage ) )
if err != nil {
return err
}
m . list . SetItems ( new_items )
m . list . ResetSelected ( )
case * spotify . SimplePlaylistPage :
m . mode = SearchPlaylists
playlists := m . list . SelectedItem ( ) . ( mainItem ) . SpotifyItem . ( * spotify . SimplePlaylistPage )
m . list . NewStatusMessage ( "Setting view to playlist" )
new_items , err := SearchPlaylistsView ( m . ctx , m . client , playlists )
if err != nil {
return err
}
m . list . SetItems ( new_items )
m . list . ResetSelected ( )
case * spotify . FullTrackPage :
m . mode = SearchTracks
m . list . NewStatusMessage ( "Setting view to tracks" )
new_items , err := SearchTracksView ( m . ctx , m . client , m . list . SelectedItem ( ) . ( mainItem ) . SpotifyItem . ( * spotify . FullTrackPage ) )
if err != nil {
return err
}
m . list . SetItems ( new_items )
m . list . ResetSelected ( )
m . list . NewStatusMessage ( "Setting view to tracks" )
}
case SearchArtists :
m . mode = SearchArtist
m . artist = m . list . SelectedItem ( ) . ( mainItem ) . SpotifyItem . ( spotify . SimpleArtist )
m . list . NewStatusMessage ( "Opening " + m . artist . Name )
new_items , err := ArtistAlbumsView ( m . ctx , m . artist . ID , m . client )
if err != nil {
return err
}
m . list . SetItems ( new_items )
m . list . ResetSelected ( )
case SearchArtist :
m . mode = SearchArtistAlbum
m . album = m . list . SelectedItem ( ) . ( mainItem ) . SpotifyItem . ( spotify . SimpleAlbum )
m . list . NewStatusMessage ( "Opening " + m . album . Name )
new_items , err := AlbumTracksView ( m . ctx , m . album . ID , m . client )
if err != nil {
return err
}
m . list . SetItems ( new_items )
m . list . ResetSelected ( )
case SearchAlbums :
m . mode = SearchAlbum
m . album = m . list . SelectedItem ( ) . ( mainItem ) . SpotifyItem . ( spotify . SimpleAlbum )
m . list . NewStatusMessage ( "Opening " + m . album . Name )
new_items , err := AlbumTracksView ( m . ctx , m . album . ID , m . client )
if err != nil {
return err
}
m . list . SetItems ( new_items )
m . list . ResetSelected ( )
case SearchPlaylists :
m . mode = SearchPlaylist
playlist := m . list . SelectedItem ( ) . ( mainItem ) . SpotifyItem . ( spotify . SimplePlaylist )
m . playlist = playlist
m . list . NewStatusMessage ( "Setting view to playlist " + playlist . Name )
new_items , err := PlaylistView ( m . ctx , m . client , playlist )
if err != nil {
return err
}
m . list . SetItems ( new_items )
m . list . ResetSelected ( )
case Main :
switch m . list . SelectedItem ( ) . ( mainItem ) . SpotifyItem . ( type ) {
case * spotify . FullArtistCursorPage :
m . mode = Artists
m . list . NewStatusMessage ( "Setting view to artists" )
new_items , err := ArtistsView ( m . ctx , m . client )
if err != nil {
return err
}
m . list . SetItems ( new_items )
m . list . ResetSelected ( )
case * spotify . SavedAlbumPage :
m . mode = Albums
m . list . NewStatusMessage ( "Setting view to albums" )
new_items , err := AlbumsView ( m . ctx , m . client )
if err != nil {
return err
}
m . list . SetItems ( new_items )
m . list . ResetSelected ( )
case spotify . SimplePlaylist :
m . mode = Playlist
playlist := m . list . SelectedItem ( ) . ( mainItem ) . SpotifyItem . ( spotify . SimplePlaylist )
m . playlist = playlist
m . list . NewStatusMessage ( "Setting view to playlist " + playlist . Name )
new_items , err := PlaylistView ( m . ctx , m . client , playlist )
if err != nil {
return err
}
m . list . SetItems ( new_items )
m . list . ResetSelected ( )
case * spotify . SavedTrackPage :
m . mode = Tracks
m . list . NewStatusMessage ( "Setting view to saved tracks" )
new_items , err := SavedTracksView ( m . ctx , m . client )
if err != nil {
return err
}
m . list . SetItems ( new_items )
m . list . ResetSelected ( )
m . list . NewStatusMessage ( "Setting view to tracks" )
}
case Albums :
m . mode = Album
m . album = m . list . SelectedItem ( ) . ( mainItem ) . SpotifyItem . ( spotify . SimpleAlbum )
m . list . NewStatusMessage ( "Opening " + m . album . Name )
new_items , err := AlbumTracksView ( m . ctx , m . album . ID , m . client )
if err != nil {
return err
}
m . list . SetItems ( new_items )
m . list . ResetSelected ( )
case Artist :
m . mode = ArtistAlbum
m . album = m . list . SelectedItem ( ) . ( mainItem ) . SpotifyItem . ( spotify . SimpleAlbum )
m . list . NewStatusMessage ( "Opening " + m . album . Name )
new_items , err := AlbumTracksView ( m . ctx , m . album . ID , m . client )
if err != nil {
return err
}
m . list . SetItems ( new_items )
m . list . ResetSelected ( )
case Artists :
m . mode = Artist
m . artist = m . list . SelectedItem ( ) . ( mainItem ) . SpotifyItem . ( spotify . SimpleArtist )
m . list . NewStatusMessage ( "Opening " + m . artist . Name )
new_items , err := ArtistAlbumsView ( m . ctx , m . artist . ID , m . client )
if err != nil {
return err
}
m . list . SetItems ( new_items )
m . list . ResetSelected ( )
case Album , ArtistAlbum , SearchArtistAlbum , SearchAlbum :
currentlyPlaying = m . list . SelectedItem ( ) . FilterValue ( )
m . list . NewStatusMessage ( "Playing " + currentlyPlaying )
go HandlePlayWithContext ( m . ctx , m . client , & m . album . URI , m . list . Cursor ( ) + ( m . list . Paginator . Page * m . list . Paginator . TotalPages ) )
case Playlist , SearchPlaylist :
currentlyPlaying = m . list . SelectedItem ( ) . FilterValue ( )
m . list . NewStatusMessage ( "Playing " + currentlyPlaying )
go HandlePlayWithContext ( m . ctx , m . client , & m . playlist . URI , m . list . Cursor ( ) + ( m . list . Paginator . Page * m . list . Paginator . PerPage ) )
case Tracks :
currentlyPlaying = m . list . SelectedItem ( ) . FilterValue ( )
m . list . NewStatusMessage ( "Playing " + currentlyPlaying )
go HandlePlayLikedSong ( m . ctx , m . client , m . list . Cursor ( ) + ( m . list . Paginator . Page * m . list . Paginator . PerPage ) )
case SearchTracks :
currentlyPlaying = m . list . SelectedItem ( ) . FilterValue ( )
m . list . NewStatusMessage ( "Playing " + currentlyPlaying )
go HandlePlayTrack ( m . ctx , m . client , m . list . SelectedItem ( ) . ( mainItem ) . SpotifyItem . ( spotify . FullTrack ) . ID )
case Devices :
go HandleSetDevice ( m . ctx , m . client , m . list . SelectedItem ( ) . ( mainItem ) . SpotifyItem . ( spotify . PlayerDevice ) )
m . list . NewStatusMessage ( "Setting device to " + m . list . SelectedItem ( ) . FilterValue ( ) )
m . mode = "main"
m . list . NewStatusMessage ( "Setting view to main" )
new_items , err := MainView ( m . ctx , m . client )
if err != nil {
fmt . Println ( err . Error ( ) )
}
m . list . SetItems ( new_items )
}
return nil
}
2023-01-09 04:42:02 +00:00
func ( m mainModel ) Init ( ) tea . Cmd {
2023-01-11 17:45:29 +00:00
main_updates = make ( chan * mainModel )
2023-01-30 02:30:33 +00:00
return Tick ( )
2023-01-09 04:42:02 +00:00
}
2023-01-30 02:30:33 +00:00
type tickMsg time . Time
func Tick ( ) tea . Cmd {
return tea . Tick ( time . Second * 1 , func ( t time . Time ) tea . Msg {
return tickMsg ( t )
} )
2023-01-11 17:45:29 +00:00
}
2023-01-13 06:19:43 +00:00
func ( m mainModel ) View ( ) string {
2023-01-13 09:12:31 +00:00
if m . input . Focused ( ) {
return DocStyle . Render ( m . list . View ( ) + "\n" + m . input . View ( ) )
}
return DocStyle . Render ( m . list . View ( ) + "\n" )
2023-01-11 17:45:29 +00:00
}
2023-01-14 00:35:42 +00:00
func ( m * mainModel ) Typing ( msg tea . KeyMsg ) ( bool , tea . Cmd ) {
if msg . String ( ) == "enter" {
m . list . NewStatusMessage ( "Setting view to search for " + m . input . Value ( ) )
2023-01-14 20:20:41 +00:00
items , result , err := SearchView ( m . ctx , m . client , m . input . Value ( ) )
2023-01-14 00:35:42 +00:00
if err != nil {
fmt . Println ( err . Error ( ) )
return false , tea . Quit
}
2023-01-14 20:20:41 +00:00
m . searchResults = result
2023-01-14 00:35:42 +00:00
m . search = m . input . Value ( )
m . list . SetItems ( items )
m . list . ResetSelected ( )
m . input . SetValue ( "" )
m . input . Blur ( )
return true , nil
}
if msg . String ( ) == "esc" {
m . input . SetValue ( "" )
m . input . Blur ( )
return false , nil
}
m . input , _ = m . input . Update ( msg )
return false , nil
}
2023-01-09 04:42:02 +00:00
func ( m mainModel ) Update ( msg tea . Msg ) ( tea . Model , tea . Cmd ) {
2023-01-14 20:20:41 +00:00
// Update Now Playing
2023-01-11 17:45:29 +00:00
m . list . NewStatusMessage ( currentlyPlaying )
2023-01-14 20:20:41 +00:00
// Update list items from LoadMore
2023-01-11 04:46:15 +00:00
select {
2023-01-11 17:45:29 +00:00
case update := <- main_updates :
m . list . SetItems ( update . list . Items ( ) )
2023-01-11 04:46:15 +00:00
default :
}
2023-01-14 20:20:41 +00:00
// Call for more items if needed
2023-01-11 17:45:29 +00:00
if m . list . Paginator . Page == m . list . Paginator . TotalPages - 2 && m . list . Cursor ( ) == 0 {
2023-01-11 04:46:15 +00:00
// if last request was still full request more
2023-01-09 04:42:02 +00:00
if len ( m . list . Items ( ) ) % 50 == 0 {
2023-01-11 04:46:15 +00:00
go m . LoadMoreItems ( )
2023-01-09 04:42:02 +00:00
}
}
2023-01-14 20:20:41 +00:00
// Handle user input
2023-01-09 04:42:02 +00:00
switch msg := msg . ( type ) {
2023-01-30 02:30:33 +00:00
case tickMsg :
playing , err := m . client . PlayerCurrentlyPlaying ( m . ctx )
if err != nil {
return nil , nil
}
if playing != nil && playing . Playing && playing . Item != nil {
cmd := m . progress . SetPercent ( float64 ( playing . Progress ) / float64 ( playing . Item . Duration ) )
m . playing = playing
return m , tea . Batch ( Tick ( ) , cmd )
}
return m , Tick ( )
case progress . FrameMsg :
progressModel , cmd := m . progress . Update ( msg )
m . progress = progressModel . ( progress . Model )
currentlyPlaying = fmt . Sprintf ( "Now playing %s by %s - %s %s/%s " , m . playing . Item . Name , m . playing . Item . Artists [ 0 ] . Name , m . progress . View ( ) , ( time . Duration ( m . playing . Progress ) * time . Millisecond ) . Round ( time . Second ) , ( time . Duration ( m . playing . Item . Duration ) * time . Millisecond ) . Round ( time . Second ) )
return m , cmd
2023-01-09 04:42:02 +00:00
case tea . KeyMsg :
2023-01-14 20:20:41 +00:00
// quit
2023-01-14 00:35:42 +00:00
if msg . String ( ) == "ctrl+c" {
return m , tea . Quit
}
2023-01-27 06:28:57 +00:00
if msg . String ( ) == "c" {
err := m . CopyToClipboard ( )
if err != nil {
return m , tea . Quit
}
}
2023-01-15 04:59:52 +00:00
if msg . String ( ) == ">" {
go HandleSeek ( m . ctx , m . client , true )
}
if msg . String ( ) == "<" {
go HandleSeek ( m . ctx , m . client , false )
}
if msg . String ( ) == "+" {
go HandleVolume ( m . ctx , m . client , true )
}
if msg . String ( ) == "-" {
go HandleVolume ( m . ctx , m . client , false )
}
2023-01-14 20:20:41 +00:00
// search input
2023-01-13 09:12:31 +00:00
if m . input . Focused ( ) {
2023-01-14 00:35:42 +00:00
search , cmd := m . Typing ( msg )
if search {
m . mode = "search"
2023-01-13 09:12:31 +00:00
}
2023-01-14 00:35:42 +00:00
return m , cmd
2023-01-13 09:12:31 +00:00
}
2023-01-14 20:20:41 +00:00
// start search
if msg . String ( ) == "s" || msg . String ( ) == "/" {
2023-01-13 09:12:31 +00:00
m . input . Focus ( )
}
2023-01-14 20:20:41 +00:00
// enter device selection
2023-01-11 17:45:29 +00:00
if msg . String ( ) == "d" {
2023-01-14 20:20:41 +00:00
m . mode = Devices
new_items , err := DeviceView ( m . ctx , m . client )
if err != nil {
fmt . Println ( err . Error ( ) )
return m , tea . Quit
2023-01-11 17:45:29 +00:00
}
2023-01-14 20:20:41 +00:00
m . list . SetItems ( new_items )
m . list . ResetSelected ( )
m . list . NewStatusMessage ( "Setting view to devices" )
2023-01-09 04:42:02 +00:00
}
2023-01-14 20:20:41 +00:00
// go back
2023-01-11 22:35:14 +00:00
if msg . String ( ) == "backspace" || msg . String ( ) == "esc" || msg . String ( ) == "q" {
2023-01-14 01:41:52 +00:00
msg , err := m . GoBack ( )
if err != nil {
fmt . Println ( err )
2023-01-11 17:45:29 +00:00
}
2023-01-14 21:19:01 +00:00
m . list . ResetSelected ( )
2023-01-14 01:41:52 +00:00
return m , msg
2023-01-11 17:45:29 +00:00
}
2023-01-14 01:41:52 +00:00
2023-01-14 20:20:41 +00:00
// select item
2023-01-11 17:45:29 +00:00
if msg . String ( ) == "enter" || msg . String ( ) == "spacebar" {
2023-01-14 20:20:41 +00:00
err := m . SelectItem ( )
if err != nil {
return m , tea . Quit
2023-01-11 17:45:29 +00:00
}
}
2023-01-14 20:20:41 +00:00
// start radio
2023-01-11 17:45:29 +00:00
if msg . String ( ) == "ctrl+r" {
2023-01-14 20:20:41 +00:00
m . PlayRadio ( )
2023-01-09 04:42:02 +00:00
}
2023-01-14 20:20:41 +00:00
// handle mouse
2023-01-09 04:42:02 +00:00
case tea . MouseMsg :
if msg . Type == 5 {
m . list . CursorUp ( )
}
if msg . Type == 6 {
m . list . CursorDown ( )
}
2023-01-14 20:20:41 +00:00
// window size -1 to handle search bar
2023-01-09 04:42:02 +00:00
case tea . WindowSizeMsg :
2023-01-12 02:45:22 +00:00
h , v := DocStyle . GetFrameSize ( )
2023-01-13 09:12:31 +00:00
m . list . SetSize ( msg . Width - h , msg . Height - v - 1 )
}
2023-01-14 20:20:41 +00:00
// return
2023-01-09 04:42:02 +00:00
var cmd tea . Cmd
m . list , cmd = m . list . Update ( msg )
return m , cmd
}
2023-01-14 01:41:52 +00:00
func InitMain ( ctx * gctx . Context , client * spotify . Client , mode Mode ) ( tea . Model , error ) {
2023-01-30 02:30:33 +00:00
prog := progress . New ( progress . WithColorProfile ( 2 ) , progress . WithoutPercentage ( ) )
2023-01-15 20:35:49 +00:00
var err error
2023-01-15 12:48:12 +00:00
lipgloss . SetColorProfile ( 2 )
2023-01-11 17:45:29 +00:00
items := [ ] list . Item { }
switch mode {
2023-01-14 01:41:52 +00:00
case Main :
2023-01-11 17:45:29 +00:00
items , err = MainView ( ctx , client )
if err != nil {
return nil , err
}
2023-01-14 01:41:52 +00:00
case Devices :
2023-01-11 17:45:29 +00:00
items , err = DeviceView ( ctx , client )
if err != nil {
return nil , err
}
2023-01-14 01:41:52 +00:00
case Tracks :
2023-01-11 17:45:29 +00:00
items , err = SavedTracksView ( ctx , client )
if err != nil {
return nil , err
}
}
2023-01-09 18:54:21 +00:00
m := mainModel {
2023-01-30 02:30:33 +00:00
list : list . New ( items , list . NewDefaultDelegate ( ) , 0 , 0 ) ,
ctx : ctx ,
client : client ,
mode : mode ,
progress : prog ,
2023-01-09 18:54:21 +00:00
}
m . list . Title = "GOSPT"
2023-01-30 02:30:33 +00:00
Tick ( )
2023-01-11 22:24:31 +00:00
m . list . DisableQuitKeybindings ( )
2023-01-11 17:45:29 +00:00
m . list . AdditionalShortHelpKeys = func ( ) [ ] key . Binding {
return [ ] key . Binding {
2023-01-11 22:28:34 +00:00
key . NewBinding ( key . WithKeys ( "esc" ) , key . WithHelp ( "esc" , "back" ) ) ,
2023-01-13 20:09:59 +00:00
key . NewBinding ( key . WithKeys ( "s" ) , key . WithHelp ( "s" , "search" ) ) ,
2023-01-11 22:28:34 +00:00
key . NewBinding ( key . WithKeys ( "ctrl+c" ) , key . WithHelp ( "ctrl+c" , "quit" ) ) ,
key . NewBinding ( key . WithKeys ( "ctrl" + "r" ) , key . WithHelp ( "ctrl+r" , "start radio" ) ) ,
2023-01-27 06:28:57 +00:00
key . NewBinding ( key . WithKeys ( "ctrl" + "shift" + "c" ) , key . WithHelp ( "ctrl+shift+c" , "copy url" ) ) ,
2023-01-11 22:28:34 +00:00
key . NewBinding ( key . WithKeys ( "d" ) , key . WithHelp ( "d" , "select device" ) ) ,
}
}
m . list . AdditionalFullHelpKeys = func ( ) [ ] key . Binding {
return [ ] key . Binding {
key . NewBinding ( key . WithKeys ( "esc" ) , key . WithHelp ( "esc" , "back" ) ) ,
2023-01-13 20:09:59 +00:00
key . NewBinding ( key . WithKeys ( "s" ) , key . WithHelp ( "s" , "search" ) ) ,
2023-01-15 12:55:55 +00:00
key . NewBinding ( key . WithKeys ( ">" ) , key . WithHelp ( ">" , "seek forward" ) ) ,
key . NewBinding ( key . WithKeys ( "<" ) , key . WithHelp ( "<" , "seek backward" ) ) ,
key . NewBinding ( key . WithKeys ( "+" ) , key . WithHelp ( "+" , "volume up" ) ) ,
key . NewBinding ( key . WithKeys ( "-" ) , key . WithHelp ( "-" , "volume down" ) ) ,
2023-01-11 22:28:34 +00:00
key . NewBinding ( key . WithKeys ( "ctrl+c" ) , key . WithHelp ( "ctrl+c" , "quit" ) ) ,
2023-01-11 17:45:29 +00:00
key . NewBinding ( key . WithKeys ( "ctrl" + "r" ) , key . WithHelp ( "ctrl+r" , "start radio" ) ) ,
2023-01-27 06:28:57 +00:00
key . NewBinding ( key . WithKeys ( "ctrl" + "shift" + "c" ) , key . WithHelp ( "ctrl+shift+c" , "copy url" ) ) ,
2023-01-11 17:45:29 +00:00
key . NewBinding ( key . WithKeys ( "d" ) , key . WithHelp ( "d" , "select device" ) ) ,
}
}
2023-01-13 09:12:31 +00:00
input := textinput . New ( )
input . Prompt = "$ "
input . Placeholder = "Search..."
input . CharLimit = 250
input . Width = 50
m . input = input
2023-01-09 18:54:21 +00:00
return m , nil
}