Use List to display library
This commit is contained in:
parent
aafe81b48b
commit
7ea726e453
9 changed files with 258 additions and 415 deletions
|
@ -1,5 +1,4 @@
|
|||
# ditty
|
||||
[![GoDoc](https://godoc.org/gitlab.com/tslocum/ditty?status.svg)](https://godoc.org/gitlab.com/tslocum/ditty)
|
||||
[![CI status](https://gitlab.com/tslocum/ditty/badges/master/pipeline.svg)](https://gitlab.com/tslocum/ditty/commits/master)
|
||||
[![Donate](https://img.shields.io/liberapay/receives/rocketnine.space.svg?logo=liberapay)](https://liberapay.com/rocketnine.space)
|
||||
|
||||
|
@ -13,7 +12,7 @@ Audio player
|
|||
|
||||
If you are running Linux with ALSA, you can try ditty without installing:
|
||||
|
||||
```ssh ditty.rocketnine.space -p 20020 2> >(aplay --quiet)```
|
||||
```ssh -q ditty.rocketnine.space -p 20020 2> >(aplay --quiet)```
|
||||
|
||||
If you can't hear anything, you may need to specify which device ```aplay```
|
||||
should use with ```-D```.
|
||||
|
|
2
audio.go
2
audio.go
|
@ -186,7 +186,7 @@ func pause() {
|
|||
}
|
||||
|
||||
func nextTrack() {
|
||||
if queueCursor < len(queueFiles)-1 {
|
||||
if queueList.GetCurrentItem() < len(queueFiles)-1 {
|
||||
queueNext()
|
||||
|
||||
entry := selectedQueueEntry()
|
||||
|
|
16
go.mod
16
go.mod
|
@ -3,20 +3,20 @@ module gitlab.com/tslocum/ditty
|
|||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/dhowden/tag v0.0.0-20191122115059-7e5c04feccd8
|
||||
github.com/dhowden/tag v0.0.0-20200412032933-5d76b8eaae27
|
||||
github.com/faiface/beep v1.0.2
|
||||
github.com/gdamore/tcell v1.3.0
|
||||
github.com/hajimehoshi/go-mp3 v0.2.1 // indirect
|
||||
github.com/hajimehoshi/oto v0.5.4 // indirect
|
||||
github.com/hajimehoshi/oto v0.6.1 // indirect
|
||||
github.com/jfreymuth/oggvorbis v1.0.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.8
|
||||
github.com/mattn/go-runewidth v0.0.9
|
||||
github.com/mewkiz/flac v1.0.6 // indirect
|
||||
github.com/mewkiz/pkg v0.0.0-20200411195739-f6b5e26764c3 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
gitlab.com/tslocum/cbind v0.1.0
|
||||
gitlab.com/tslocum/cview v1.4.2-0.20200128151041-339db80f666d
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a // indirect
|
||||
gitlab.com/tslocum/cbind v0.1.1
|
||||
gitlab.com/tslocum/cview v1.4.5-0.20200424220521-e97629839eba
|
||||
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5 // indirect
|
||||
golang.org/x/image v0.0.0-20200119044424-58c23975cae1 // indirect
|
||||
golang.org/x/mobile v0.0.0-20200123024942-82c397c4c527 // indirect
|
||||
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 // indirect
|
||||
golang.org/x/mobile v0.0.0-20200329125638-4c31acba0007 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
)
|
||||
|
|
47
go.sum
47
go.sum
|
@ -2,8 +2,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
|
|||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo=
|
||||
github.com/dhowden/tag v0.0.0-20191122115059-7e5c04feccd8 h1:nmFnmD8VZXkjDHIb1Gnfz50cgzUvGN72zLjPRXBW/hU=
|
||||
github.com/dhowden/tag v0.0.0-20191122115059-7e5c04feccd8/go.mod h1:SniNVYuaD1jmdEEvi+7ywb1QFR7agjeTdGKyFb0p7Rw=
|
||||
github.com/dhowden/tag v0.0.0-20200412032933-5d76b8eaae27 h1:Z6xaGRBbqfLR797upHuzQ6w4zg33BLKfAKtVCcmMDgg=
|
||||
github.com/dhowden/tag v0.0.0-20200412032933-5d76b8eaae27/go.mod h1:SniNVYuaD1jmdEEvi+7ywb1QFR7agjeTdGKyFb0p7Rw=
|
||||
github.com/faiface/beep v1.0.2 h1:UB5DiRNmA4erfUYnHbgU4UB6DlBOrsdEFRtcc8sCkdQ=
|
||||
github.com/faiface/beep v1.0.2/go.mod h1:1yLb5yRdHMsovYYWVqYLioXkVuziCSITW1oarTeduQM=
|
||||
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
||||
|
@ -14,7 +14,7 @@ github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebK
|
|||
github.com/go-audio/audio v1.0.0/go.mod h1:6uAu0+H2lHkwdGsAY+j2wHPNPpPoeg5AaEFh9FlA+Zs=
|
||||
github.com/go-audio/riff v1.0.0/go.mod h1:l3cQwc85y79NQFCRB7TiPoNiaijp6q8Z0Uv38rVG498=
|
||||
github.com/go-audio/wav v1.0.0/go.mod h1:3yoReyQOsiARkvPl3ERCi8JFjihzG6WhjYpZCf5zAWE=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherwasm v0.1.1/go.mod h1:kx4n9a+MzHH0BJJhvlsQ65hqLFXDO/m256AsaDPQ+/4=
|
||||
|
@ -25,8 +25,8 @@ github.com/hajimehoshi/go-mp3 v0.2.1/go.mod h1:Rr+2P46iH6PwTPVgSsEwBkon0CK5DxCAe
|
|||
github.com/hajimehoshi/oto v0.1.1/go.mod h1:hUiLWeBQnbDu4pZsAhOnGqMI1ZGibS6e2qhQdfpwz04=
|
||||
github.com/hajimehoshi/oto v0.3.1/go.mod h1:e9eTLBB9iZto045HLbzfHJIc+jP3xaKrjZTghvb6fdM=
|
||||
github.com/hajimehoshi/oto v0.3.4/go.mod h1:PgjqsBJff0efqL2nlMJidJgVJywLn6M4y8PI4TfeWfA=
|
||||
github.com/hajimehoshi/oto v0.5.4 h1:Dn+WcYeF310xqStKm0tnvoruYUV5Sce8+sfUaIvWGkE=
|
||||
github.com/hajimehoshi/oto v0.5.4/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
|
||||
github.com/hajimehoshi/oto v0.6.1 h1:7cJz/zRQV4aJvMSSRqzN2TImoVVMpE0BCY4nrNJaDOM=
|
||||
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
|
||||
github.com/icza/bitio v1.0.0 h1:squ/m1SHyFeCA6+6Gyol1AxV9nmPPlJFT8c2vKdj3U8=
|
||||
github.com/icza/bitio v1.0.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr9A=
|
||||
github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6 h1:8UsGZ2rr2ksmEru6lToqnXgA8Mz1DP11X4zSJ159C3k=
|
||||
|
@ -41,33 +41,32 @@ github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1
|
|||
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/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
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.9-0.20200125155203-588506649b41 h1:AkInqmD1OrueaAKIWH0RWU+irX4nL1oqScB++w2CAlU=
|
||||
github.com/mattn/go-runewidth v0.0.9-0.20200125155203-588506649b41/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mewkiz/flac v1.0.5/go.mod h1:EHZNU32dMF6alpurYyKHDLYpW1lYpBZ5WrXi/VuNIGs=
|
||||
github.com/mewkiz/flac v1.0.6 h1:OnMwCWZPAnjDndjEzLynOZ71Y2U+/QYHoVI4JEKgKkk=
|
||||
github.com/mewkiz/flac v1.0.6/go.mod h1:yU74UH277dBUpqxPouHSQIar3G1X/QIclVbFahSd1pU=
|
||||
github.com/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2 h1:EyTNMdePWaoWsRSGQnXiSoQu0r6RS1eA557AwJhlzHU=
|
||||
github.com/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2/go.mod h1:3E2FUC/qYUfM8+r9zAwpeHJzqRVVMIYnpzD/clwWxyA=
|
||||
github.com/mewkiz/pkg v0.0.0-20200411195739-f6b5e26764c3 h1:gVKRsSn2rXZ29y56Xrl+vtw8mpowYz9UmoPJM+V/g5s=
|
||||
github.com/mewkiz/pkg v0.0.0-20200411195739-f6b5e26764c3/go.mod h1:3E2FUC/qYUfM8+r9zAwpeHJzqRVVMIYnpzD/clwWxyA=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
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=
|
||||
gitlab.com/tslocum/cbind v0.1.0 h1:Ot6y7K6mwp7Qp/MWOH5cuhf/VC5HKpJaWFvgzMC8nnM=
|
||||
gitlab.com/tslocum/cbind v0.1.0/go.mod h1:xxuB0UqPYytWTkjI0l2VzOJJzqvIUf18r6YahPXYDd8=
|
||||
gitlab.com/tslocum/cview v1.4.2-0.20200128151041-339db80f666d h1:5rPwwmNYGLcOsyawvAw7m/Jtwp5rAuvLoqVW5k09AP0=
|
||||
gitlab.com/tslocum/cview v1.4.2-0.20200128151041-339db80f666d/go.mod h1:QbxliYQa2I32UJH2boP54jq6tnWlgm6yViaFXKGDfuM=
|
||||
gitlab.com/tslocum/cbind v0.1.1 h1:JXXtxMWHgWLvoF+QkrvcNvOQ59juy7OE1RhT7hZfdt0=
|
||||
gitlab.com/tslocum/cbind v0.1.1/go.mod h1:rX7vkl0pUSg/yy427MmD1FZAf99S7WwpUlxF/qTpPqk=
|
||||
gitlab.com/tslocum/cview v1.4.5-0.20200424220521-e97629839eba h1:DYq4lsxeUfkR6VYGwzWcRNJWLCgjpklNZt4HfESnyLA=
|
||||
gitlab.com/tslocum/cview v1.4.5-0.20200424220521-e97629839eba/go.mod h1:85Ec3ByMemrI3tUK4Rpd8jcF3J7maOFHGwzlNnCrPVI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/exp v0.0.0-20180710024300-14dda7b62fcd/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a h1:7Wlg8L54In96HTWOaI4sreLJ6qfyGuvSau5el3fK41Y=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5 h1:FR+oGxGfbQu1d+jglI3rCkjAjUnhRSZcUxr+DqlDLNo=
|
||||
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
|
||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
|
@ -78,10 +77,11 @@ golang.org/x/mobile v0.0.0-20180806140643-507816974b79/go.mod h1:z+o9i4GpDbdi3rU
|
|||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mobile v0.0.0-20200123024942-82c397c4c527 h1:470B1IvA7JOANiTULBeEJCIcp53VWOsgckscR836cN8=
|
||||
golang.org/x/mobile v0.0.0-20200123024942-82c397c4c527/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
|
||||
golang.org/x/mobile v0.0.0-20200329125638-4c31acba0007 h1:JxsyO7zPDWn1rBZW8FV5RFwCKqYeXnyaS/VQPLpXu6I=
|
||||
golang.org/x/mobile v0.0.0-20200329125638-4c31acba0007/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
|
@ -94,19 +94,18 @@ golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/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-20200103143344-a1369afcdac7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 h1:1/DFK4b7JH8DmkqhUk48onnSfrPzImPoVxuomtbT2nk=
|
||||
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8=
|
||||
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0/go.mod h1:OdE7CF6DbADk7lN8LIKRzRJTTZXIjtWgA5THM5lhBAw=
|
||||
|
|
291
gui.go
291
gui.go
|
@ -20,26 +20,21 @@ import (
|
|||
|
||||
var (
|
||||
app *cview.Application
|
||||
mainbuf *cview.TextView
|
||||
queuebuf *cview.TextView
|
||||
mainList *cview.List
|
||||
queueList *cview.List
|
||||
topstatusbuf *cview.TextView
|
||||
bottomstatusbuf *cview.TextView
|
||||
|
||||
mainBufferFiles []*libraryEntry
|
||||
mainBufferCursor = 1 // Position cursor on first entry
|
||||
mainBufferDirectory string
|
||||
mainBufferOrigin int
|
||||
mainBufHeight int
|
||||
mainBufferAutoFocus string // Entry path to focus after loading display
|
||||
mainFiles []*libraryEntry
|
||||
mainCursor = -1
|
||||
mainDirectory string
|
||||
mainAutoFocus string // Entry path to focus after loading display
|
||||
|
||||
mainBuffer bytes.Buffer
|
||||
mainLock = new(sync.Mutex)
|
||||
|
||||
queueFiles []*libraryEntry
|
||||
queueCursor int
|
||||
queueDirectory string
|
||||
queueOrigin int
|
||||
queueHeight int
|
||||
queueFiles []*libraryEntry
|
||||
queueCursor = -1
|
||||
|
||||
queueBuffer bytes.Buffer
|
||||
queueLock = new(sync.Mutex)
|
||||
|
@ -57,62 +52,59 @@ var (
|
|||
)
|
||||
|
||||
func initTUI() error {
|
||||
/*cview.Styles.TitleColor = tcell.ColorDefault
|
||||
cview.Styles.BorderColor = tcell.ColorDefault
|
||||
cview.Styles.PrimaryTextColor = tcell.ColorDefault
|
||||
cview.Styles.PrimitiveBackgroundColor = tcell.ColorDefault*/
|
||||
|
||||
app = cview.NewApplication()
|
||||
|
||||
if !disableMouse {
|
||||
app.EnableMouse()
|
||||
app.EnableMouse(true)
|
||||
}
|
||||
|
||||
app.SetInputCapture(inputConfig.Capture)
|
||||
|
||||
app.SetAfterResizeFunc(handleResize)
|
||||
|
||||
app.SetMouseCapture(handleMouse)
|
||||
|
||||
app.SetInputCapture(inputConfig.Capture)
|
||||
|
||||
app.SetBeforeFocusFunc(handleBeforeFocus)
|
||||
|
||||
grid := cview.NewGrid().SetRows(-2, -1, 1, 1).SetColumns(-1)
|
||||
|
||||
mainbuf = cview.NewTextView().SetDynamicColors(true).SetWrap(true).SetWordWrap(false)
|
||||
queuebuf = cview.NewTextView().SetDynamicColors(true).SetWrap(true).SetWordWrap(false)
|
||||
mainList = cview.NewList().ShowSecondaryText(false)
|
||||
queueList = cview.NewList().ShowSecondaryText(false)
|
||||
topstatusbuf = cview.NewTextView().SetWrap(false).SetWordWrap(false)
|
||||
bottomstatusbuf = cview.NewTextView().SetWrap(false).SetWordWrap(false)
|
||||
|
||||
mainbuf.SetBorder(true).SetTitleAlign(cview.AlignLeft)
|
||||
mainList.SetBorder(true).SetTitleAlign(cview.AlignLeft)
|
||||
mainList.SetSelectedFunc(handleMainSelection)
|
||||
|
||||
queuebuf.SetBorder(true).SetTitleAlign(cview.AlignLeft).SetTitle(" Queue ")
|
||||
queueList.SetBorder(true).SetTitleAlign(cview.AlignLeft).SetTitle(" Queue ")
|
||||
|
||||
setTextViewParameters(mainbuf)
|
||||
setTextViewParameters(queuebuf)
|
||||
setTextViewParameters(topstatusbuf)
|
||||
setTextViewParameters(bottomstatusbuf)
|
||||
|
||||
grid.AddItem(mainbuf, 0, 0, 1, 1, 0, 0, false)
|
||||
grid.AddItem(queuebuf, 1, 0, 1, 1, 0, 0, false)
|
||||
grid.AddItem(mainList, 0, 0, 1, 1, 0, 0, false)
|
||||
grid.AddItem(queueList, 1, 0, 1, 1, 0, 0, false)
|
||||
grid.AddItem(topstatusbuf, 2, 0, 1, 1, 0, 0, false)
|
||||
grid.AddItem(bottomstatusbuf, 3, 0, 1, 1, 0, 0, false)
|
||||
|
||||
mainbuf.SetDrawFunc(func(screen tcell.Screen, x, y, width, height int) (i int, i2 int, i3 int, i4 int) {
|
||||
mainBufHeight = height
|
||||
return mainbuf.GetInnerRect()
|
||||
})
|
||||
|
||||
queuebuf.SetDrawFunc(func(screen tcell.Screen, x, y, width, height int) (i int, i2 int, i3 int, i4 int) {
|
||||
queueHeight = height
|
||||
return queuebuf.GetInnerRect()
|
||||
})
|
||||
|
||||
app.SetRoot(grid, true)
|
||||
app.SetRoot(grid, true).SetFocus(mainList)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleBeforeFocus(p cview.Primitive) bool {
|
||||
return p == mainList || p == queueList
|
||||
}
|
||||
|
||||
func browseFolder(browse string) {
|
||||
var err error
|
||||
browse, err = filepath.Abs(browse)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if browse == mainBufferDirectory {
|
||||
mainBufferAutoFocus = ""
|
||||
if browse == mainDirectory {
|
||||
mainAutoFocus = ""
|
||||
return
|
||||
}
|
||||
if !strings.HasPrefix(browse, restrictLibrary) {
|
||||
|
@ -126,27 +118,30 @@ func browseFolder(browse string) {
|
|||
return
|
||||
}
|
||||
|
||||
placeCursorAtTop := mainBufferCursor == 0
|
||||
mainBufferFiles = scanFolder(browse)
|
||||
if !placeCursorAtTop && len(mainBufferFiles) > 0 {
|
||||
mainBufferCursor = 1
|
||||
} else {
|
||||
mainBufferCursor = 0
|
||||
}
|
||||
mainBufferOrigin = 0
|
||||
mainList.SetTitle(" " + cview.Escape(runewidth.Truncate(mainDirectory, screenWidth-4, "...")) + "... ")
|
||||
|
||||
mainBufferDirectory = browse
|
||||
if mainBufferAutoFocus != "" {
|
||||
autoSelectAbs, err := filepath.Abs(mainBufferAutoFocus)
|
||||
if err == nil && autoSelectAbs != mainBufferDirectory {
|
||||
placeCursorAtTop := mainList.GetCurrentItem() == 0
|
||||
mainFiles = scanFolder(browse)
|
||||
if mainCursor == -1 {
|
||||
if !placeCursorAtTop && len(mainFiles) > 0 {
|
||||
mainCursor = 1
|
||||
} else {
|
||||
mainCursor = 0
|
||||
}
|
||||
}
|
||||
|
||||
mainDirectory = browse
|
||||
if mainAutoFocus != "" {
|
||||
autoSelectAbs, err := filepath.Abs(mainAutoFocus)
|
||||
if err == nil && autoSelectAbs != mainDirectory {
|
||||
autoSelect := -1
|
||||
var entryPath string
|
||||
for i, entry := range mainBufferFiles {
|
||||
for i, entry := range mainFiles {
|
||||
if !entry.File.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
entryPath, err = filepath.Abs(path.Join(mainBufferDirectory, entry.File.Name()))
|
||||
entryPath, err = filepath.Abs(path.Join(mainDirectory, entry.File.Name()))
|
||||
if err == nil {
|
||||
if entryPath == autoSelectAbs {
|
||||
autoSelect = i
|
||||
|
@ -155,36 +150,18 @@ func browseFolder(browse string) {
|
|||
}
|
||||
}
|
||||
if autoSelect >= 0 {
|
||||
mainBufferCursor = autoSelect
|
||||
mainBufferNewOrigin := (mainBufferCursor - (mainBufHeight - 4)) + ((mainBufHeight - 2) / 2)
|
||||
if mainBufferNewOrigin <= 0 {
|
||||
mainBufferNewOrigin = 0
|
||||
} else if mainBufferNewOrigin > len(mainBufferFiles)-(mainBufHeight-3) {
|
||||
mainBufferNewOrigin = len(mainBufferFiles) - (mainBufHeight - 3)
|
||||
}
|
||||
mainBufferOrigin = mainBufferNewOrigin
|
||||
mainBufferAutoFocus = ""
|
||||
|
||||
go listNext()
|
||||
return
|
||||
mainCursor = autoSelect + 1
|
||||
mainAutoFocus = ""
|
||||
}
|
||||
}
|
||||
mainBufferAutoFocus = ""
|
||||
mainAutoFocus = ""
|
||||
}
|
||||
go app.QueueUpdateDraw(updateMain)
|
||||
}
|
||||
|
||||
func setTextViewParameters(tv *cview.TextView) {
|
||||
tv.SetTitleColor(tcell.ColorDefault)
|
||||
tv.SetBorderColor(tcell.ColorDefault)
|
||||
|
||||
tv.SetTextColor(tcell.ColorDefault)
|
||||
tv.SetBackgroundColor(tcell.ColorDefault)
|
||||
}
|
||||
|
||||
func browseParent() {
|
||||
mainBufferAutoFocus = mainBufferDirectory
|
||||
go browseFolder(path.Join(mainBufferDirectory, ".."))
|
||||
mainAutoFocus = mainDirectory
|
||||
go browseFolder(path.Join(mainDirectory, ".."))
|
||||
}
|
||||
|
||||
func updateMain() {
|
||||
|
@ -196,7 +173,7 @@ func updateMain() {
|
|||
if statusText != "" {
|
||||
statusMessage = statusText
|
||||
} else {
|
||||
statusMessage = mainBufferDirectory
|
||||
statusMessage = mainDirectory
|
||||
}
|
||||
|
||||
truncated := false
|
||||
|
@ -216,69 +193,54 @@ func updateMain() {
|
|||
}
|
||||
mainBuffer.WriteString(statusMessage)
|
||||
|
||||
mainbuf.SetTitle(" " + cview.Escape(runewidth.Truncate(mainBuffer.String(), screenWidth-4, "...")) + " ")
|
||||
mainList.SetTitle(" " + cview.Escape(runewidth.Truncate(mainBuffer.String(), screenWidth-4, "...")) + " ")
|
||||
mainBuffer.Reset()
|
||||
|
||||
l := len(mainBufferFiles) + 1
|
||||
if mainCursor == -1 {
|
||||
mainCursor = mainList.GetCurrentItem()
|
||||
}
|
||||
mainList.Clear()
|
||||
|
||||
var printed int
|
||||
var line string
|
||||
if mainBufferOrigin == 0 {
|
||||
writeListItemPrefix(&mainBuffer, !queueFocused, mainBufferCursor, 0)
|
||||
//var length string
|
||||
|
||||
if mainBufferDirectory == "/" {
|
||||
line = "./"
|
||||
} else {
|
||||
line = "../"
|
||||
}
|
||||
lineWidth := runewidth.StringWidth(line)
|
||||
line = cview.Escape(line)
|
||||
mainBuffer.WriteString(line)
|
||||
|
||||
writeListItemSuffix(&mainBuffer, !queueFocused, mainBufferCursor, 0, 0, l, lineWidth, mainBufHeight-2)
|
||||
|
||||
printed++
|
||||
if mainDirectory == "/" {
|
||||
line = "./"
|
||||
} else {
|
||||
line = "../"
|
||||
}
|
||||
for i, entry := range mainBufferFiles {
|
||||
if i < mainBufferOrigin-1 || i-mainBufferOrigin-1 > mainBufHeight-1 {
|
||||
continue
|
||||
}
|
||||
line = cview.Escape(line)
|
||||
|
||||
if printed > 0 {
|
||||
mainBuffer.WriteRune('\n')
|
||||
}
|
||||
mainList.AddItem(line, "", 0, nil)
|
||||
|
||||
writeListItemPrefix(&mainBuffer, !queueFocused, mainBufferCursor-1, i)
|
||||
printed++
|
||||
|
||||
for _, entry := range mainFiles {
|
||||
//length = ""
|
||||
if entry.File.IsDir() {
|
||||
line = strings.TrimSpace(entry.File.Name()) + "/"
|
||||
} else {
|
||||
line = entry.String()
|
||||
|
||||
if entry.Metadata.Length > 0 {
|
||||
//m := entry.Metadata.Length / time.Minute
|
||||
//length = fmt.Sprintf(" %d:%02d", m, (entry.Metadata.Length%(m*time.Minute))/time.Second)
|
||||
}
|
||||
}
|
||||
lineWidth := runewidth.StringWidth(line)
|
||||
line = cview.Escape(line)
|
||||
mainBuffer.WriteString(line)
|
||||
|
||||
writeListItemSuffix(&mainBuffer, !queueFocused, mainBufferCursor, printed, i+1, l, lineWidth, mainBufHeight-2)
|
||||
|
||||
printed++
|
||||
if printed == mainBufHeight-2 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
remaining := (mainBufHeight - 2) - printed
|
||||
for i := 0; i < remaining; i++ {
|
||||
if printed > 0 {
|
||||
mainBuffer.WriteRune('\n')
|
||||
}
|
||||
|
||||
writeListItemSuffix(&mainBuffer, !queueFocused, mainBufferCursor, printed, remaining-printed, l, 0, mainBufHeight-2)
|
||||
mainList.AddItem(line, "", 0, nil)
|
||||
|
||||
printed++
|
||||
}
|
||||
|
||||
mainbuf.SetText(mainBuffer.String())
|
||||
if mainCursor >= mainList.GetItemCount() {
|
||||
mainList.SetCurrentItem(mainList.GetItemCount() - 1)
|
||||
} else if mainCursor >= 0 {
|
||||
mainList.SetCurrentItem(mainCursor)
|
||||
}
|
||||
mainCursor = -1
|
||||
}
|
||||
|
||||
func updateQueue() {
|
||||
|
@ -287,88 +249,33 @@ func updateQueue() {
|
|||
|
||||
queueBuffer.Reset()
|
||||
|
||||
l := len(queueFiles)
|
||||
if queueCursor == -1 {
|
||||
queueCursor = queueList.GetCurrentItem()
|
||||
}
|
||||
queueList.Clear()
|
||||
|
||||
var printed int
|
||||
var line string
|
||||
for i, entry := range queueFiles {
|
||||
if i < queueOrigin || i-queueOrigin > queueHeight-1 {
|
||||
continue
|
||||
}
|
||||
|
||||
if printed > 0 {
|
||||
queueBuffer.WriteRune('\n')
|
||||
}
|
||||
|
||||
writeListItemPrefix(&queueBuffer, queueFocused, queueCursor, i)
|
||||
|
||||
//var length string
|
||||
for _, entry := range queueFiles {
|
||||
line = entry.String()
|
||||
lineWidth := runewidth.StringWidth(line)
|
||||
//lineWidth := runewidth.StringWidth(line)
|
||||
line = cview.Escape(line)
|
||||
|
||||
queueBuffer.WriteString(line)
|
||||
queueList.AddItem(line, "", 0, nil)
|
||||
|
||||
writeListItemSuffix(&queueBuffer, queueFocused, queueCursor, printed, i, l, lineWidth, queueHeight-2)
|
||||
|
||||
printed++
|
||||
if printed == queueHeight-2 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
remaining := (queueHeight - 2) - printed
|
||||
for i := 0; i < remaining; i++ {
|
||||
if printed > 0 {
|
||||
queueBuffer.WriteRune('\n')
|
||||
}
|
||||
|
||||
writeListItemSuffix(&queueBuffer, queueFocused, queueCursor, printed, remaining-printed, l, 0, queueHeight-2)
|
||||
/*m := entry.Metadata.Length / time.Minute
|
||||
length = fmt.Sprintf(" %d:%02d", m, (entry.Metadata.Length%(m*time.Minute))/time.Second)*/
|
||||
|
||||
printed++
|
||||
}
|
||||
|
||||
queuebuf.SetText(queueBuffer.String())
|
||||
}
|
||||
|
||||
func writeListItemPrefix(buffer *bytes.Buffer, focused bool, cursor int, i int) {
|
||||
if focused {
|
||||
if i == cursor {
|
||||
buffer.WriteString("[::r]")
|
||||
}
|
||||
} else {
|
||||
if i == cursor {
|
||||
buffer.WriteString("[::bu]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func writeListItemSuffix(buffer *bytes.Buffer, focused bool, cursor int, printed int, i int, count int, lineWidth int, height int) {
|
||||
if !focused && i == cursor {
|
||||
buffer.WriteString("[-:-:-]")
|
||||
}
|
||||
for i := lineWidth; i < screenWidth-3; i++ {
|
||||
buffer.WriteRune(' ')
|
||||
}
|
||||
if focused && i == cursor {
|
||||
buffer.WriteString("[-:-:-]")
|
||||
}
|
||||
|
||||
scrollBlockPos := int(float64(height-1) * (float64(cursor) / float64(count-1)))
|
||||
if focused {
|
||||
if printed == scrollBlockPos {
|
||||
buffer.WriteString("[::r]")
|
||||
buffer.WriteRune(' ')
|
||||
buffer.WriteString("[-:-:-]")
|
||||
} else {
|
||||
buffer.WriteRune('▒')
|
||||
}
|
||||
} else {
|
||||
if printed == scrollBlockPos {
|
||||
buffer.WriteRune('▓')
|
||||
} else {
|
||||
buffer.WriteRune('░')
|
||||
}
|
||||
if queueCursor >= queueList.GetItemCount() {
|
||||
queueList.SetCurrentItem(queueList.GetItemCount() - 1)
|
||||
} else if queueCursor >= 0 {
|
||||
queueList.SetCurrentItem(queueCursor)
|
||||
}
|
||||
queueCursor = -1
|
||||
}
|
||||
|
||||
func updateLists() {
|
||||
|
@ -535,3 +442,7 @@ func handleResize(width int, height int) {
|
|||
updateQueue()
|
||||
updateStatus()
|
||||
}
|
||||
|
||||
func handleMainSelection(i int, s string, s2 string, r rune) {
|
||||
go listSelect(i)
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ const (
|
|||
)
|
||||
|
||||
var actionHandlers = map[string]func(){
|
||||
actionSelect: listSelect,
|
||||
actionSelect: listSelectCurrent,
|
||||
actionPause: pause,
|
||||
actionRefresh: listRefresh,
|
||||
actionQueue: listQueue,
|
||||
|
|
165
gui_list.go
165
gui_list.go
|
@ -3,6 +3,8 @@ package main
|
|||
import (
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"gitlab.com/tslocum/cview"
|
||||
)
|
||||
|
||||
func listPrevious() {
|
||||
|
@ -11,12 +13,7 @@ func listPrevious() {
|
|||
return
|
||||
}
|
||||
|
||||
if mainBufferOrigin > 0 && mainBufferCursor == mainBufferOrigin {
|
||||
mainBufferOrigin--
|
||||
}
|
||||
if mainBufferCursor > 0 {
|
||||
mainBufferCursor--
|
||||
}
|
||||
mainList.Transform(cview.TransformPreviousItem)
|
||||
go app.QueueUpdateDraw(updateLists)
|
||||
}
|
||||
|
||||
|
@ -26,53 +23,40 @@ func listNext() {
|
|||
return
|
||||
}
|
||||
|
||||
if mainBufferCursor < len(mainBufferFiles) {
|
||||
mainBufferCursor++
|
||||
if mainBufferCursor-mainBufferOrigin > mainBufHeight-3 {
|
||||
mainBufferOrigin++
|
||||
}
|
||||
}
|
||||
mainList.Transform(cview.TransformNextItem)
|
||||
go app.QueueUpdateDraw(updateLists)
|
||||
}
|
||||
|
||||
func queuePrevious() {
|
||||
if queueOrigin > 0 && queueCursor == queueOrigin {
|
||||
queueOrigin--
|
||||
}
|
||||
if queueCursor > 0 {
|
||||
queueCursor--
|
||||
}
|
||||
|
||||
queueList.Transform(cview.TransformPreviousItem)
|
||||
go app.QueueUpdateDraw(updateQueue)
|
||||
}
|
||||
|
||||
func queueNext() {
|
||||
if queueCursor < len(queueFiles)-1 {
|
||||
queueCursor++
|
||||
queueOrigin = queueCursor - ((queueHeight - 3) / 2)
|
||||
if queueOrigin < 0 {
|
||||
queueOrigin = 0
|
||||
}
|
||||
if queueOrigin > (len(queueFiles)-1)-(queueHeight-3) {
|
||||
queueOrigin = (len(queueFiles) - 1) - (queueHeight - 3)
|
||||
}
|
||||
}
|
||||
|
||||
queueList.Transform(cview.TransformNextItem)
|
||||
go app.QueueUpdateDraw(updateQueue)
|
||||
}
|
||||
|
||||
func listSelect() {
|
||||
func listSelectCurrent() {
|
||||
go listSelect(mainList.GetCurrentItem())
|
||||
}
|
||||
|
||||
func listSelect(cursor int) {
|
||||
if queueFocused {
|
||||
queueSelect()
|
||||
return
|
||||
}
|
||||
|
||||
if mainBufferCursor == 0 {
|
||||
browseFolder(path.Join(mainBufferDirectory, ".."))
|
||||
if cursor == 0 {
|
||||
browseFolder(path.Join(mainDirectory, ".."))
|
||||
return
|
||||
}
|
||||
|
||||
entry := selectedMainEntry()
|
||||
if cursor < 0 || cursor-1 > len(mainFiles) {
|
||||
return
|
||||
}
|
||||
|
||||
entry := mainFiles[cursor-1]
|
||||
if entry.File.IsDir() {
|
||||
browseFolder(entry.Path)
|
||||
return
|
||||
|
@ -118,7 +102,7 @@ func queueSelect() {
|
|||
}
|
||||
|
||||
func listQueue() {
|
||||
if mainBufferCursor == 0 {
|
||||
if mainList.GetCurrentItem() == 0 {
|
||||
// TODO Show error
|
||||
return
|
||||
}
|
||||
|
@ -159,120 +143,77 @@ func listDelete() {
|
|||
queueLock.Lock()
|
||||
defer queueLock.Unlock()
|
||||
|
||||
if len(queueFiles) <= queueCursor {
|
||||
cursor := queueList.GetCurrentItem()
|
||||
|
||||
if cursor < 0 || len(queueFiles) <= cursor {
|
||||
return
|
||||
}
|
||||
|
||||
queueFiles = append(queueFiles[:queueCursor], queueFiles[queueCursor+1:]...)
|
||||
|
||||
if queueCursor > len(queueFiles)-1 {
|
||||
queueCursor = len(queueFiles) - 1
|
||||
if queueCursor < 0 {
|
||||
queueCursor = 0
|
||||
}
|
||||
}
|
||||
queueFiles = append(queueFiles[:cursor], queueFiles[cursor+1:]...)
|
||||
|
||||
go app.QueueUpdateDraw(updateQueue)
|
||||
}
|
||||
|
||||
func selectedMainEntry() *libraryEntry {
|
||||
return mainBufferFiles[mainBufferCursor-1]
|
||||
cursor := mainList.GetCurrentItem()
|
||||
if cursor < 0 || cursor-1 > len(mainFiles) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return mainFiles[cursor-1]
|
||||
}
|
||||
|
||||
func offsetMainEntry(offset int) *libraryEntry {
|
||||
if (mainBufferCursor-1)+offset < 0 || (mainBufferCursor-1)+offset >= len(mainBufferFiles) {
|
||||
cursor := mainList.GetCurrentItem()
|
||||
if (cursor-1)+offset < 0 || (cursor-1)+offset >= len(mainFiles) {
|
||||
return nil
|
||||
}
|
||||
return mainBufferFiles[(mainBufferCursor-1)+offset]
|
||||
return mainFiles[(cursor-1)+offset]
|
||||
}
|
||||
|
||||
func selectedQueueEntry() *libraryEntry {
|
||||
return queueFiles[queueCursor]
|
||||
cursor := queueList.GetCurrentItem()
|
||||
if cursor < 0 || cursor-1 > len(queueFiles) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return queueFiles[cursor]
|
||||
}
|
||||
|
||||
func offsetQueueEntry(offset int) *libraryEntry {
|
||||
if queueCursor+offset < 0 || queueCursor+offset >= len(queueFiles) {
|
||||
cursor := queueList.GetCurrentItem()
|
||||
if cursor+offset < 0 || cursor+offset >= len(queueFiles) {
|
||||
return nil
|
||||
}
|
||||
return queueFiles[queueCursor+offset]
|
||||
|
||||
return queueFiles[cursor+offset]
|
||||
}
|
||||
|
||||
func listPreviousPage() {
|
||||
if !queueFocused {
|
||||
if mainBufferOrigin == 0 {
|
||||
mainBufferCursor = 0
|
||||
|
||||
go app.QueueUpdateDraw(updateMain)
|
||||
return
|
||||
}
|
||||
|
||||
mainBufferOrigin -= (mainBufHeight - 1) - 2
|
||||
if mainBufferOrigin < 0 {
|
||||
mainBufferOrigin = 0
|
||||
}
|
||||
mainBufferCursor = mainBufferOrigin
|
||||
|
||||
mainList.Transform(cview.TransformPreviousPage)
|
||||
go app.QueueUpdateDraw(updateMain)
|
||||
} else {
|
||||
if queueOrigin == 0 {
|
||||
queueCursor = 0
|
||||
|
||||
go app.QueueUpdateDraw(updateQueue)
|
||||
return
|
||||
}
|
||||
|
||||
queueOrigin -= (queueHeight - 1) - 2
|
||||
if queueOrigin < 0 {
|
||||
queueOrigin = 0
|
||||
}
|
||||
queueCursor = queueOrigin
|
||||
|
||||
queueList.Transform(cview.TransformPreviousPage)
|
||||
go app.QueueUpdateDraw(updateQueue)
|
||||
}
|
||||
}
|
||||
|
||||
func listNextPage() {
|
||||
if !queueFocused {
|
||||
numEntries := len(mainBufferFiles)
|
||||
|
||||
if mainBufferOrigin >= numEntries-(mainBufHeight-1) {
|
||||
mainBufferCursor = numEntries
|
||||
|
||||
go app.QueueUpdateDraw(updateMain)
|
||||
return
|
||||
}
|
||||
|
||||
mainBufferOrigin += (mainBufHeight - 1) - 2
|
||||
if mainBufferOrigin > (numEntries-(mainBufHeight-1))+2 {
|
||||
mainBufferOrigin = (numEntries - (mainBufHeight - 1)) + 2
|
||||
}
|
||||
mainBufferCursor = mainBufferOrigin
|
||||
|
||||
mainList.Transform(cview.TransformNextPage)
|
||||
go app.QueueUpdateDraw(updateMain)
|
||||
} else {
|
||||
numEntries := len(queueFiles)
|
||||
|
||||
if queueOrigin >= numEntries-(queueHeight-1) {
|
||||
queueCursor = numEntries - 1
|
||||
|
||||
go app.QueueUpdateDraw(updateQueue)
|
||||
return
|
||||
}
|
||||
|
||||
queueOrigin += queueHeight - 2
|
||||
if queueOrigin > ((numEntries-1)-(queueHeight-1))+2 {
|
||||
queueOrigin = ((numEntries - 1) - (queueHeight - 1)) + 2
|
||||
}
|
||||
queueCursor = queueOrigin
|
||||
|
||||
queueList.Transform(cview.TransformNextPage)
|
||||
go app.QueueUpdateDraw(updateQueue)
|
||||
}
|
||||
}
|
||||
|
||||
func listRefresh() {
|
||||
// TODO Remember cursor position
|
||||
d := mainBufferDirectory
|
||||
mainBufferDirectory = ""
|
||||
mainCursor = mainList.GetCurrentItem()
|
||||
d := mainDirectory
|
||||
|
||||
mainDirectory = ""
|
||||
browseFolder(d)
|
||||
}
|
||||
|
||||
|
@ -296,5 +237,11 @@ func listToggleHidden() {
|
|||
func toggleFocusedList() {
|
||||
queueFocused = !queueFocused
|
||||
|
||||
if queueFocused {
|
||||
app.SetFocus(queueList)
|
||||
} else {
|
||||
app.SetFocus(mainList)
|
||||
}
|
||||
|
||||
go app.QueueUpdateDraw(updateLists)
|
||||
}
|
||||
|
|
130
gui_mouse.go
130
gui_mouse.go
|
@ -10,104 +10,74 @@ import (
|
|||
"gitlab.com/tslocum/cview"
|
||||
)
|
||||
|
||||
func handleMouse(event *cview.EventMouse) *cview.EventMouse {
|
||||
if event.Action()&cview.MouseDown != 0 && event.Buttons()&tcell.Button1 != 0 {
|
||||
mouseX, mouseY := event.Position()
|
||||
if mouseY >= 0 && mouseY < mainBufHeight {
|
||||
if queueFocused {
|
||||
queueFocused = false
|
||||
go app.QueueUpdateDraw(updateLists)
|
||||
}
|
||||
|
||||
// TODO Delay playing while cursor is moved
|
||||
if mouseY > 0 && mouseY < mainBufHeight-1 && mouseY-1 < len(mainBufferFiles)+1 {
|
||||
mainBufferCursor = mainBufferOrigin + (mouseY - 1)
|
||||
go app.QueueUpdateDraw(updateLists)
|
||||
go listSelect()
|
||||
}
|
||||
return nil
|
||||
} else if mouseY >= mainBufHeight && mouseY < screenHeight-2 {
|
||||
if !queueFocused {
|
||||
queueFocused = true
|
||||
go app.QueueUpdateDraw(updateLists)
|
||||
}
|
||||
|
||||
if mouseY > mainBufHeight && mouseY < screenHeight-3 {
|
||||
mouseHit := (mouseY - mainBufHeight) - 1
|
||||
if mouseHit < len(queueFiles) {
|
||||
queueCursor = queueOrigin + mouseHit
|
||||
go app.QueueUpdateDraw(updateLists)
|
||||
go queueSelect()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
} else if mouseY == screenHeight-1 {
|
||||
if mouseX >= seekStart && mouseX <= seekEnd {
|
||||
if strings.ToLower(path.Ext(playingFileName)) == ".flac" {
|
||||
statusText = "Seeking FLAC files is unsupported"
|
||||
go func() {
|
||||
time.Sleep(5 * time.Second)
|
||||
statusText = ""
|
||||
go app.QueueUpdateDraw(updateMain)
|
||||
}()
|
||||
func handleMouse(event *tcell.EventMouse, action cview.MouseAction) (*tcell.EventMouse, cview.MouseAction) {
|
||||
mouseX, mouseY := event.Position()
|
||||
if action == cview.MouseLeftClick && mouseY == screenHeight-1 {
|
||||
if mouseX >= seekStart && mouseX <= seekEnd {
|
||||
if strings.ToLower(path.Ext(playingFileName)) == ".flac" {
|
||||
statusText = "Seeking FLAC files is unsupported"
|
||||
go func() {
|
||||
time.Sleep(5 * time.Second)
|
||||
statusText = ""
|
||||
go app.QueueUpdateDraw(updateMain)
|
||||
}()
|
||||
go app.QueueUpdateDraw(updateMain)
|
||||
|
||||
return nil
|
||||
}
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
audioLock.Lock()
|
||||
speaker.Lock()
|
||||
|
||||
if playingStreamer == nil {
|
||||
speaker.Unlock()
|
||||
audioLock.Unlock()
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
pos := float64(mouseX-seekStart) / float64(seekEnd-seekStart)
|
||||
if pos > 1 {
|
||||
pos = 1
|
||||
}
|
||||
seekTo := int(float64(playingStreamer.Len()-1) * pos)
|
||||
_ = playingStreamer.Seek(seekTo) // Ignore seek errors
|
||||
speaker.Unlock()
|
||||
audioLock.Unlock()
|
||||
|
||||
go app.QueueUpdateDraw(updateStatus)
|
||||
return nil, 0
|
||||
} else if mouseX >= volumeStart && mouseX <= volumeEnd+1 {
|
||||
if mouseX > volumeEnd {
|
||||
mouseX = volumeEnd
|
||||
}
|
||||
|
||||
if mouseX-volumeStart <= 3 {
|
||||
audioLock.Lock()
|
||||
speaker.Lock()
|
||||
|
||||
if playingStreamer == nil {
|
||||
if volume == nil {
|
||||
speaker.Unlock()
|
||||
audioLock.Unlock()
|
||||
return nil
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
pos := float64(mouseX-seekStart) / float64(seekEnd-seekStart)
|
||||
if pos > 1 {
|
||||
pos = 1
|
||||
}
|
||||
seekTo := int(float64(playingStreamer.Len()-1) * pos)
|
||||
_ = playingStreamer.Seek(seekTo) // Ignore seek errors
|
||||
volume.Silent = !volume.Silent
|
||||
speaker.Unlock()
|
||||
audioLock.Unlock()
|
||||
|
||||
go app.QueueUpdateDraw(updateStatus)
|
||||
return nil
|
||||
} else if mouseX >= volumeStart && mouseX <= volumeEnd+1 {
|
||||
if mouseX > volumeEnd {
|
||||
mouseX = volumeEnd
|
||||
} else {
|
||||
vol := -7.5 + float64(7.5)*(float64(mouseX-volumeStart-3)/float64(volumeEnd-volumeStart-3))
|
||||
if vol < -7.0 {
|
||||
vol = -7.0
|
||||
}
|
||||
setVolume(roundUnit(vol, 0.5))
|
||||
|
||||
if mouseX-volumeStart <= 3 {
|
||||
audioLock.Lock()
|
||||
speaker.Lock()
|
||||
|
||||
if volume == nil {
|
||||
speaker.Unlock()
|
||||
audioLock.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
volume.Silent = !volume.Silent
|
||||
speaker.Unlock()
|
||||
audioLock.Unlock()
|
||||
|
||||
go app.QueueUpdateDraw(updateStatus)
|
||||
} else {
|
||||
vol := -7.5 + float64(7.5)*(float64(mouseX-volumeStart-3)/float64(volumeEnd-volumeStart-3))
|
||||
if vol < -7.0 {
|
||||
vol = -7.0
|
||||
}
|
||||
setVolume(roundUnit(vol, 0.5))
|
||||
|
||||
go app.QueueUpdateDraw(updateStatus)
|
||||
}
|
||||
return nil
|
||||
go app.QueueUpdateDraw(updateStatus)
|
||||
}
|
||||
return nil, 0
|
||||
}
|
||||
}
|
||||
|
||||
return event
|
||||
return event, action
|
||||
}
|
||||
|
|
17
library.go
17
library.go
|
@ -7,6 +7,7 @@ import (
|
|||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/dhowden/tag"
|
||||
)
|
||||
|
@ -16,6 +17,7 @@ type metadata struct {
|
|||
Artist string
|
||||
Album string
|
||||
Track int
|
||||
Length time.Duration
|
||||
}
|
||||
|
||||
func readMetadata(f *os.File) *metadata {
|
||||
|
@ -29,6 +31,21 @@ func readMetadata(f *os.File) *metadata {
|
|||
metadata.Artist = strings.TrimSpace(m.Artist())
|
||||
metadata.Album = strings.TrimSpace(m.Album())
|
||||
metadata.Track, _ = m.Track()
|
||||
|
||||
/*
|
||||
TODO Too slow
|
||||
d := mp3.NewDecoder(f)
|
||||
var frame mp3.Frame
|
||||
var skipped int
|
||||
for {
|
||||
err = d.Decode(&frame, &skipped)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
metadata.Length += frame.Duration()
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
return &metadata
|
||||
|
|
Loading…
Reference in a new issue