diff --git a/README.md b/README.md index 51988b1..cc9b6f6 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,13 @@ A simple terminal UI player for [di.fm Premium](http://di.fm) ![App Screenshot](https://user-images.githubusercontent.com/3331648/81481515-bb668400-91fe-11ea-8a7c-39e1bb76c55d.png) -# Dependencies +## Dependencies -## PulseAudio +### PulseAudio Both linux and MacOS depend on pulseaudio to be running. -### MacOS +#### MacOS By default, pulseaudio on MacOS runs as "root", which is not ideal. PulseAudio is best run by non-root users. By symbolically linking the pulseaudio plist file into your user's `~/Library/LaunchAgents/`, it runs as your user. @@ -19,17 +19,17 @@ ln -s $(brew info pulseaudio | grep "/usr/local/Cellar" | awk '{print $1}')//hom brew services start pulseaudio ``` -### Linux +#### Debian / Ubuntu `apt install pulseaudio` -# Install +## Install -## Binary Releases +### Binary Releases There are binary builds available in [releases](https://github.com/acaloiaro/di-tui/releases). -## With `go install` +### With `go install` `go install github.com/acaloiaro/di-tui@latest` If `$GOPATH/bin` is not on your `$PATH` (modify accordingly for ZSH users `~/.zshrc`) @@ -40,14 +40,14 @@ source ~/.bashrc If your `$GOPATH` is not set, see https://github.com/golang/go/wiki/SettingGOPATH -# Authenticate +## Authenticate There are two authentication options - Enter your username and password directly into `di-tui` - If you're justifiably uncomfortable with entering your username/password into this application, copy your "Listen Key" from (https://www.di.fm/settings) and create the following file: -## ~/.config/di-tui/config.yml +### ~/.config/di-tui/config.yml ```yml token: album_art: @@ -58,6 +58,23 @@ album_art: | token | Your di.fm authentication "Listen Key" found at https://www.di.fm/settings | | album_art | Turn album art on or off | -# Run +## Configuration + +### Themes + +By default, `di-tui` respects your terminal's color scheme. However, there are four color settings that one can change by adding a `theme` to `config.yml`. + +**Tomorrow-Night** inspired theme + +```yml +theme: + primary_color: "#81a2be" + background_color: "#2a1f1a" + primary_text_color: "#969896" + secondary_text_color: "#81a2be" +``` + +## Run `di-tui` + diff --git a/config/config.go b/config/config.go index 92d6cf4..6b94af5 100644 --- a/config/config.go +++ b/config/config.go @@ -8,6 +8,14 @@ import ( "github.com/spf13/viper" ) +// TODO This application is migrating to having all of its configuration read into this `Config` struct, rather than +// using individual `ReadType` functions from viper. Migrating all `Get*` methods to use `Config` instead. +type Config struct { + Theme map[string]string +} + +var C Config + func init() { viper.SetConfigName("config") viper.SetConfigType("yaml") @@ -21,6 +29,11 @@ func init() { if err != nil { saveConfig() } + + if err := viper.Unmarshal(&C); err != nil { + fmt.Fprintf(os.Stderr, "unable to load di-tui configuration file: %v", err) + os.Exit(1) + } } // AlbumArt returns true if album art should be fetched when a new song begins playing @@ -76,6 +89,35 @@ func SaveListenToken(token string) { saveConfig() } +// HasTheme returns true if the di-tui config has a Theme set +func HasTheme() bool { + if C.Theme["primary_color"] != "" { + return true + } else { + return false + } +} + +// GetThemePrimaryColor gets the theme's primary color +func GetThemePrimaryColor() string { + return C.Theme["primary_color"] +} + +// GetThemePrimaryColor gets the theme's background color +func GetThemeBackgroundColor() string { + return C.Theme["background_color"] +} + +// GetThemePrimaryTextColor gets the theme's primary text color +func GetThemePrimaryTextColor() string { + return C.Theme["primary_text_color"] +} + +// GetThemePrimaryColor gets the theme's primary color +func GetThemeSecondaryTextColor() string { + return C.Theme["secondary_text_color"] +} + func saveConfig() { viper.SetConfigFile(configFilePath()) viper.SetConfigType("yaml") diff --git a/go.mod b/go.mod index b5d8669..0f270f6 100644 --- a/go.mod +++ b/go.mod @@ -4,12 +4,12 @@ go 1.19 require ( github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 - github.com/gdamore/tcell v1.3.0 + github.com/gdamore/tcell/v2 v2.6.0 github.com/hajimehoshi/go-mp3 v0.2.1 github.com/jfreymuth/pulse v0.1.0 github.com/michiwend/gomusicbrainz v0.0.0-20181012083520-6c07e13dd396 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 - github.com/rivo/tview v0.0.0-20200219210816-cd38d7432498 + github.com/rivo/tview v0.0.0-20230621164836-6cc0565babaf github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.6.2 gopkg.in/ini.v1 v1.52.0 @@ -21,19 +21,20 @@ require ( github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/kr/pretty v0.2.0 // indirect - github.com/lucasb-eyer/go-colorful v1.0.3 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/magiconair/properties v1.8.1 // indirect - github.com/mattn/go-runewidth v0.0.8 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect github.com/michiwend/golang-pretty v0.0.0-20141116172505-8ac61812ea3f // indirect github.com/mitchellh/mapstructure v1.1.2 // indirect github.com/pelletier/go-toml v1.6.0 // indirect - github.com/rivo/uniseg v0.1.0 // indirect + github.com/rivo/uniseg v0.4.3 // indirect github.com/spf13/afero v1.2.2 // indirect github.com/spf13/cast v1.3.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/stretchr/testify v1.4.0 // indirect github.com/subosito/gotenv v1.2.0 // indirect golang.org/x/sys v0.6.0 // indirect + golang.org/x/term v0.5.0 // indirect golang.org/x/text v0.8.0 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/yaml.v2 v2.2.8 // indirect diff --git a/go.sum b/go.sum index 1c10cd1..d7f61e5 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -26,8 +25,8 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= -github.com/gdamore/tcell v1.3.0 h1:r35w0JBADPZCVQijYebl6YMWWtHRqVEGt7kL2eBADRM= -github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM= +github.com/gdamore/tcell/v2 v2.6.0 h1:OKbluoP9VYmJwZwq/iLb4BxwKcwGthaa1YNBJIyCySg= +github.com/gdamore/tcell/v2 v2.6.0/go.mod h1:be9omFATkdr0D9qewWW3d+MEvl5dha+Etb5y65J2H8Y= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -54,8 +53,6 @@ github.com/hajimehoshi/go-mp3 v0.2.1/go.mod h1:Rr+2P46iH6PwTPVgSsEwBkon0CK5DxCAe github.com/hajimehoshi/oto v0.3.4/go.mod h1:PgjqsBJff0efqL2nlMJidJgVJywLn6M4y8PI4TfeWfA= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/jfreymuth/pulse v0.0.0-20201014123913-1e525c426c93 h1:gDcaH96SZ7q1JU6hj0tSv8FiuqadFERU17lLxhphLa8= -github.com/jfreymuth/pulse v0.0.0-20201014123913-1e525c426c93/go.mod h1:cpYspI6YljhkUf1WLXLLDmeaaPFc3CnGLjDZf9dZ4no= github.com/jfreymuth/pulse v0.1.0 h1:KN38/9hoF9PJvP5DpEVhMRKNuwnJUonc8c9ARorRXUA= github.com/jfreymuth/pulse v0.1.0/go.mod h1:cpYspI6YljhkUf1WLXLLDmeaaPFc3CnGLjDZf9dZ4no= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= @@ -72,14 +69,12 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= -github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac= -github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuujKs0= -github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/michiwend/golang-pretty v0.0.0-20141116172505-8ac61812ea3f h1:oF0u/1VBm5gYitYvcIh443XZuYYkR50CP0Vsj3gAa1o= github.com/michiwend/golang-pretty v0.0.0-20141116172505-8ac61812ea3f/go.mod h1:k0nOQg5bmAmEwWAuodvib9B74Oyny6aRMpkBcVWEtKs= @@ -106,10 +101,11 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rivo/tview v0.0.0-20200219210816-cd38d7432498 h1:4CFNy7/q7P06AsIONZzuWy7jcdqEmYQvOZ9FAFZdbls= -github.com/rivo/tview v0.0.0-20200219210816-cd38d7432498/go.mod h1:6lkG1x+13OShEf0EaOCaTQYyB7d5nSbb181KtjlS+84= -github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY= -github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/tview v0.0.0-20230621164836-6cc0565babaf h1:IchpMMtnfvzg7T3je672bP1nKWz1M4tW3kMZT6CbgoM= +github.com/rivo/tview v0.0.0-20230621164836-6cc0565babaf/go.mod h1:nVwGv4MP47T0jvlk7KuTTjjuSmrGO4JF0iaiNt4bufE= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= +github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= @@ -143,26 +139,34 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1 github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -170,12 +174,21 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -184,6 +197,9 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= diff --git a/main.go b/main.go index a9a9cfb..95d020e 100644 --- a/main.go +++ b/main.go @@ -12,18 +12,13 @@ import ( "github.com/acaloiaro/di-tui/views" "github.com/rivo/tview" - "github.com/gdamore/tcell" + "github.com/gdamore/tcell/v2" "github.com/spf13/pflag" "github.com/spf13/viper" ) var ctx *context.AppContext -func init() { - // when true color is on, tcell does not respect your terminal colors - os.Setenv("TCELL_TRUECOLOR", "disable") -} - func main() { pflag.String("username", "", "your di.fm username") pflag.String("password", "", "your di.fm password") @@ -55,9 +50,10 @@ func main() { func run() { configureEventHandling() updateScreenLayout() - configureKeybindings(ctx) FetchFavoritesAndChannels() + ctx.View.Keybindings.Bindings = views.GetKeybindings() + err := ctx.View.App.Run() if err != nil { @@ -173,21 +169,6 @@ func configureEventHandling() { } -func configureKeybindings(ctx *context.AppContext) { - bindings := []views.UIKeybinding{ - views.UIKeybinding{Shortcut: "c", Description: "Channels", Func: func() {}}, - views.UIKeybinding{Shortcut: "f", Description: "Favorites", Func: func() {}}, - views.UIKeybinding{Shortcut: "F", Description: "Toggle Favorite", Func: func() {}}, - views.UIKeybinding{Shortcut: "j", Description: "Scroll Down", Func: func() {}}, - views.UIKeybinding{Shortcut: "k", Description: "Scroll Up", Func: func() {}}, - views.UIKeybinding{Shortcut: "q", Description: "Quit", Func: func() {}}, - views.UIKeybinding{Shortcut: "p", Description: "Pause", Func: func() {}}, - views.UIKeybinding{Shortcut: "Enter", Description: "Play", Func: func() {}}, - } - - ctx.View.Keybindings.Bindings = bindings -} - func FetchFavoritesAndChannels() { ctx.View.ChannelList.Clear() ctx.View.FavoriteList.Clear() diff --git a/views/views.go b/views/views.go index f016e1e..cbb25e7 100644 --- a/views/views.go +++ b/views/views.go @@ -2,13 +2,43 @@ package views import ( "fmt" + "os" "strings" "github.com/acaloiaro/di-tui/components" - "github.com/gdamore/tcell" + "github.com/acaloiaro/di-tui/config" + "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) +var primaryTextColorString string +var secondaryTextColorString string +var primaryColor tcell.Color +var backgroundColor tcell.Color +var primaryTextColor tcell.Color +var secondaryTextColor tcell.Color + +func init() { + if config.HasTheme() { + os.Setenv("COLORTERM", "24bit") + primaryTextColorString = config.GetThemePrimaryTextColor() + secondaryTextColorString = config.GetThemeSecondaryTextColor() + secondaryTextColor = tcell.GetColor(secondaryTextColorString) + primaryColor = tcell.GetColor(config.GetThemePrimaryColor()) + backgroundColor = tcell.GetColor(config.GetThemeBackgroundColor()) + } else { + // do not override the terminal's theme, use all of its defaults + os.Setenv("TCELL_TRUECOLOR", "disable") + primaryTextColorString = "white" + secondaryTextColorString = "blue" + primaryColor = tcell.ColorBlue + primaryTextColor = tcell.GetColor(primaryTextColorString) + secondaryTextColor = tcell.GetColor(secondaryTextColorString) + } + + primaryTextColor = tcell.GetColor(primaryTextColorString) +} + // ViewContext holds references to all the top-level UI elements in the application type ViewContext struct { App *tview.Application @@ -62,19 +92,21 @@ func CreateViewContext() *ViewContext { // Draw draws a NowPlayingView onto the scren func (n *NowPlayingView) Draw(screen tcell.Screen) { n.Box.Draw(screen) + n.Box.SetBackgroundColor(backgroundColor) + x, y, width, _ := n.GetInnerRect() - line := fmt.Sprintf("%s[white] %s", "Channel:", n.Channel.Name) - tview.Print(screen, line, x, y, width, tview.AlignLeft, tcell.ColorBlue) + line := fmt.Sprintf("%s[%s] %s", "Channel:", secondaryTextColorString, n.Channel.Name) + tview.Print(screen, line, x, y, width, tview.AlignLeft, primaryTextColor) - line = fmt.Sprintf("%s[white] %s", "Artist:", n.Track.Artist) - tview.Print(screen, line, x, y+1, width, tview.AlignLeft, tcell.ColorBlue) + line = fmt.Sprintf("%s[%s] %s", "Artist:", secondaryTextColorString, n.Track.Artist) + tview.Print(screen, line, x, y+1, width, tview.AlignLeft, primaryTextColor) - line = fmt.Sprintf("%s[white] %s", "Track:", n.Track.Title) - tview.Print(screen, line, x, y+2, width, tview.AlignLeft, tcell.ColorBlue) + line = fmt.Sprintf("%s[%s] %s", "Track:", secondaryTextColorString, n.Track.Title) + tview.Print(screen, line, x, y+2, width, tview.AlignLeft, primaryTextColor) - line = fmt.Sprintf("%s[white] %s", "Elapsed:", n.elapsedString()) - tview.Print(screen, line, x, y+3, width, tview.AlignLeft, tcell.ColorBlue) + line = fmt.Sprintf("%s[%s] %s", "Elapsed:", secondaryTextColorString, n.elapsedString()) + tview.Print(screen, line, x, y+3, width, tview.AlignLeft, primaryTextColor) if n.Art == "" { return @@ -83,12 +115,12 @@ func (n *NowPlayingView) Draw(screen tcell.Screen) { artLines := strings.Split(n.Art, "\n") for i, line := range artLines { if i == 0 { - label := fmt.Sprintf("[white] %s", "Album Cover") - tview.Print(screen, label, x, y+4, width, tview.AlignCenter, tcell.ColorBlue) + label := fmt.Sprintf("[%s] %s", primaryTextColorString, "Album Cover") + tview.Print(screen, label, x, y+4, width, tview.AlignCenter, secondaryTextColor) } - l := fmt.Sprintf("[white] %s", line) - tview.Print(screen, l, x, y+5+i, width, tview.AlignCenter, tcell.ColorBlue) + l := fmt.Sprintf("[%s] %s", primaryTextColorString, line) + tview.Print(screen, l, x, y+5+i, width, tview.AlignCenter, secondaryTextColor) } } @@ -107,20 +139,24 @@ func (n *NowPlayingView) elapsedString() (str string) { func (s *StatusView) Draw(screen tcell.Screen) { s.Box.Draw(screen) + s.Box.SetBackgroundColor(backgroundColor) + x, y, width, _ := s.GetInnerRect() - line := fmt.Sprintf("%s[white] %s", "Message:", s.Message) - tview.Print(screen, line, x, y, width, tview.AlignLeft, tcell.ColorBlue) + line := fmt.Sprintf("%s[%s] %s", "Message:", secondaryTextColorString, s.Message) + tview.Print(screen, line, x, y, width, tview.AlignLeft, primaryTextColor) } // Draw draws the key bindings view on to the screen func (k *KeybindingView) Draw(screen tcell.Screen) { k.Box.Draw(screen) + k.Box.SetBackgroundColor(backgroundColor) + x, y, width, _ := k.GetInnerRect() previousWidth := 0 for j, bnd := range k.Bindings { - line := fmt.Sprintf("(%s)[white] %s", bnd.Shortcut, bnd.Description) - tview.Print(screen, line, x+previousWidth, y, width, tview.AlignLeft, tcell.ColorBlue) + line := fmt.Sprintf("(%s)[%s] %s", bnd.Shortcut, primaryTextColorString, bnd.Description) + tview.Print(screen, line, x+previousWidth, y, width, tview.AlignLeft, secondaryTextColor) previousWidth += len(bnd.Shortcut) + len(bnd.Description) + 4 // virtically separate playback controls from ui controls // yes, this is hacky, but there's a comment, so it's ok, right? @@ -136,7 +172,12 @@ func createChannelList() *tview.List { list. ShowSecondaryText(false). SetBorder(true). - SetTitle(" Channels ") + SetTitle(" Channels "). + SetTitleColor(primaryTextColor). + SetBorderColor(primaryColor) + + list.SetMainTextColor(primaryTextColor) + list.Box.SetBackgroundColor(backgroundColor) return list } @@ -146,7 +187,12 @@ func createFavoriteList() *tview.List { list. ShowSecondaryText(false). SetBorder(true). - SetTitle(" Favorites ") + SetBorderColor(primaryColor). + SetTitle(" Favorites "). + SetTitleColor(primaryTextColor) + + list.Box.SetBackgroundColor(backgroundColor) + list.SetMainTextColor(primaryTextColor) return list } @@ -155,8 +201,12 @@ func createKeybindings() *KeybindingView { kbv := &KeybindingView{Box: tview.NewBox()} kbv. SetBorder(true). + SetBorderColor(primaryColor). + SetTitleColor(primaryTextColor). SetTitle(" Keyboard Controls ") + kbv.SetBorderColor(primaryColor) + return kbv } @@ -167,8 +217,10 @@ func createNowPlaying() *NowPlayingView { Elapsed: 0.0, } - np.SetTitle(" Now Playing ") - np.SetBorder(true) + np.SetTitle(" Now Playing "). + SetBorder(true). + SetBorderColor(primaryColor). + SetTitleColor(primaryTextColor) return np } @@ -179,7 +231,24 @@ func createStatusView() *StatusView { Message: "Ready to Play", } sv.SetTitle(" Status ") + sv.SetTitleColor(primaryTextColor) sv.SetBorder(true) + sv.SetBorderColor(primaryColor) return sv } + +func GetKeybindings() (bindings []UIKeybinding) { + bindings = []UIKeybinding{ + UIKeybinding{Shortcut: "c", Description: "Channels", Func: func() {}}, + UIKeybinding{Shortcut: "f", Description: "Favorites", Func: func() {}}, + UIKeybinding{Shortcut: "F", Description: "Toggle Favorite", Func: func() {}}, + UIKeybinding{Shortcut: "j", Description: "Scroll Down", Func: func() {}}, + UIKeybinding{Shortcut: "k", Description: "Scroll Up", Func: func() {}}, + UIKeybinding{Shortcut: "q", Description: "Quit", Func: func() {}}, + UIKeybinding{Shortcut: "p", Description: "Pause", Func: func() {}}, + UIKeybinding{Shortcut: "Enter", Description: "Play", Func: func() {}}, + } + + return bindings +}