Browse Source

1.0.17 (#164)

* bump version

* clear notifications, scroll and buttons

* update example config
pull/167/head 1.0.17
Rasmus Lindroth 4 years ago committed by GitHub
parent
commit
a42e92b8f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      README.md
  2. 9
      api/notifications.go
  3. 4
      auth/file.go
  4. 8
      config.example.ini
  5. 6
      config/config.go
  6. 8
      config/default_config.go
  7. 3
      config/help.tmpl
  8. 8
      config/keys.go
  9. 7
      feed/feed.go
  10. 12
      go.mod
  11. 24
      go.sum
  12. 2
      main.go
  13. 5
      ui/cmdbar.go
  14. 16
      ui/commands.go
  15. 55
      ui/composeview.go
  16. 31
      ui/controls.go
  17. 7
      ui/feed.go
  18. 20
      ui/helpview.go
  19. 364
      ui/input.go
  20. 22
      ui/item.go
  21. 8
      ui/item_list.go
  22. 16
      ui/item_notification.go
  23. 57
      ui/item_status.go
  24. 48
      ui/item_user.go
  25. 38
      ui/linkview.go
  26. 13
      ui/loginview.go
  27. 4
      ui/media.go
  28. 44
      ui/pollview.go
  29. 47
      ui/preferenceview.go
  30. 22
      ui/styled_elements.go
  31. 2
      ui/timeline.go
  32. 4
      ui/tutview.go
  33. 8
      ui/view.go
  34. 35
      ui/voteview.go

8
README.md

@ -10,6 +10,8 @@ features you can find in the web client.
Press `C` to create a new toot and `N` to focus on your notifications.
You can also enable [mouse support](#mouse-support).
You can find Linux binaries under [releases](https://github.com/RasmusLindroth/tut/releases).
![Preview](./images/preview.png "Preview")
@ -28,6 +30,7 @@ You can find Linux binaries under [releases](https://github.com/RasmusLindroth/t
* [Build it yourself](#build-it-yourself)
* [Flags and commands](#flags-and-commands)
* [Templates](#templates)
* [Mouse support](#mouse-support)
* [Password manager for secrets](#password-manager-for-secrets)
* [Thanks to](#thanks-to)
@ -38,6 +41,7 @@ You can find Linux binaries under [releases](https://github.com/RasmusLindroth/t
* `:blocking` lists users that you have blocked
* `:boosts` lists users that boosted the toot
* `:bookmarks` lists all your bookmarks
* `:clear-notifications` clear all notifications
* `:compose` compose a new toot
* `:favorited` lists toots you've favorited
* `:favorites` lists users that favorited the toot
@ -191,6 +195,10 @@ The data available in `user.tmpl` is almost the same. You still have the
`Style` but instead of `Toot` you have a struct named `User`. You can see
all fields in [./ui/item_user.go](./ui/item_user.go).
## Mouse support
To enable mouse support you'll have to set `mouse-support=true` under `[general]`
in your [config](#configuration).
## Password manager for secrets
If you run `pass`, `gopass` or something similar you can protect your secrets.
You'll have to manually update your `accounts.toml`. It should be located at

9
api/notifications.go

@ -0,0 +1,9 @@
package api
import (
"context"
)
func (ac *AccountClient) ClearNotifications() error {
return ac.Client.ClearNotifications(context.Background())
}

4
auth/file.go

@ -1,7 +1,7 @@
package auth
import (
"io/ioutil"
"io"
"log"
"os"
"strings"
@ -27,7 +27,7 @@ func GetAccounts(filepath string) (*AccountData, error) {
return &AccountData{}, err
}
defer f.Close()
data, err := ioutil.ReadAll(f)
data, err := io.ReadAll(f)
if err != nil {
return &AccountData{}, err
}

8
config.example.ini

@ -149,10 +149,10 @@ leader-timeout=1000
# of two parts first the action then the shortcut. And they're separated by a
# comma.
#
# Available commands: home, direct, local, federated, compose, blocking,
# bookmarks, saved, favorited, boosts, favorites, following, followers, muting,
# newer, preferences, profile, notifications, lists, tag, window,
# list-placement, list-split, proportions
# Available commands: home, direct, local, federated, clear-notifications,
# compose, blocking, bookmarks, saved, favorited, boosts, favorites, following,
# followers, muting, newer, preferences, profile, notifications, lists, tag,
# window, list-placement, list-split, proportions
#
# The shortcuts are up to you, but keep them quite short and make sure they
# don't collide. If you have one shortcut that is "f" and an other one that is

6
config/config.go

@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
@ -56,6 +55,7 @@ const (
LeaderDirect
LeaderLocal
LeaderFederated
LeaderClearNotifications
LeaderCompose
LeaderBlocking
LeaderBookmarks
@ -849,6 +849,8 @@ func parseGeneral(cfg *ini.File) General {
la.Command = LeaderLocal
case "federated":
la.Command = LeaderFederated
case "clear-notifications":
la.Command = LeaderClearNotifications
case "compose":
la.Command = LeaderCompose
case "blocking":
@ -1481,7 +1483,7 @@ func getTheme(fname string, isLocal bool) (*ini.File, error) {
if err != nil {
return nil, err
}
content, err := ioutil.ReadAll(f)
content, err := io.ReadAll(f)
if err != nil {
return nil, err
}

8
config/default_config.go

@ -151,10 +151,10 @@ leader-timeout=1000
# of two parts first the action then the shortcut. And they're separated by a
# comma.
#
# Available commands: home, direct, local, federated, compose, blocking,
# bookmarks, saved, favorited, boosts, favorites, following, followers, muting,
# newer, preferences, profile, notifications, lists, tag, window,
# list-placement, list-split, proportions
# Available commands: home, direct, local, federated, clear-notifications,
# compose, blocking, bookmarks, saved, favorited, boosts, favorites, following,
# followers, muting, newer, preferences, profile, notifications, lists, tag,
# window, list-placement, list-split, proportions
#
# The shortcuts are up to you, but keep them quite short and make sure they
# don't collide. If you have one shortcut that is "f" and an other one that is

3
config/help.tmpl

@ -45,6 +45,9 @@ Here's a list of supported commands.
{{ Color .Style.TextSpecial2 }}{{ Flags "b" }}:bookmarks{{ Flags "-" }}{{ Color .Style.Text }}
Lists all your bookmarks
{{ Color .Style.TextSpecial2 }}{{ Flags "b" }}:clear-notifications{{ Flags "-" }}{{ Color .Style.Text }}
Clear all notifications
{{ Color .Style.TextSpecial2 }}{{ Flags "b" }}:compose{{ Flags "-" }}{{ Color .Style.Text }}
Compose a new toot

8
config/keys.go

@ -6,18 +6,18 @@ import (
"github.com/gdamore/tcell/v2"
)
func ColorFromKey(c *Config, k Key, first bool) string {
func ColorFromKey(c *Config, k Key, first bool) (string, int) {
if len(k.Hint) == 0 {
return ""
return "", 0
}
parts := k.Hint[0]
if !first && len(k.Hint) > 1 {
parts = k.Hint[1]
}
if len(parts) != 3 {
return ""
return "", 0
}
return ColorKey(c, parts[0], parts[1], parts[2])
return ColorKey(c, parts[0], parts[1], parts[2]), len(fmt.Sprintf("%s%s%s", parts[0], parts[1], parts[2]))
}
func ColorKey(c *Config, pre, key, end string) string {

7
feed/feed.go

@ -103,6 +103,13 @@ func (f *Feed) Delete(id uint) {
f.Updated(DekstopNotificationNone)
}
func (f *Feed) Clear() {
f.itemsMux.Lock()
defer f.itemsMux.Unlock()
f.items = []api.Item{}
f.Updated(DekstopNotificationNone)
}
func (f *Feed) Item(index int) (api.Item, error) {
f.itemsMux.RLock()
defer f.itemsMux.RUnlock()

12
go.mod

@ -8,13 +8,13 @@ require (
github.com/gdamore/tcell/v2 v2.5.2
github.com/gen2brain/beeep v0.0.0-20220518085355-d7852edf42fc
github.com/gobwas/glob v0.2.3
github.com/icza/gox v0.0.0-20220321141217-e2d488ab2fbc
github.com/icza/gox v0.0.0-20220812133721-0fbf7a534d8e
github.com/microcosm-cc/bluemonday v1.0.19
github.com/pelletier/go-toml/v2 v2.0.2
github.com/rivo/tview v0.0.0-20220801133142-711ef394f9b3
github.com/rivo/uniseg v0.3.1
golang.org/x/net v0.0.0-20220728211354-c7608f3a8462
gopkg.in/ini.v1 v1.66.6
github.com/rivo/tview v0.0.0-20220812085834-0e6b21a48e96
github.com/rivo/uniseg v0.3.4
golang.org/x/net v0.0.0-20220812174116-3211cb980234
gopkg.in/ini.v1 v1.67.0
)
require (
@ -29,7 +29,7 @@ require (
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af // indirect
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect
golang.org/x/sys v0.0.0-20220731174439-a90be440212d // indirect
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 // indirect
golang.org/x/text v0.3.7 // indirect
)

24
go.sum

@ -22,8 +22,8 @@ github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/icza/gox v0.0.0-20220321141217-e2d488ab2fbc h1:/vPVDa098f2SM/Ef3NtrWiyo4UBWL+QkD4hodlNpha8=
github.com/icza/gox v0.0.0-20220321141217-e2d488ab2fbc/go.mod h1:VbcN86fRkkUMPX2ufM85Um8zFndLZswoIW1eYtpAcVk=
github.com/icza/gox v0.0.0-20220812133721-0fbf7a534d8e h1:vD4inAaWEbFk4Dpu1Y+m9URk8s6dOif7pBW5pW7fAak=
github.com/icza/gox v0.0.0-20220812133721-0fbf7a534d8e/go.mod h1:VbcN86fRkkUMPX2ufM85Um8zFndLZswoIW1eYtpAcVk=
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/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
@ -36,11 +36,11 @@ github.com/pelletier/go-toml/v2 v2.0.2 h1:+jQXlF3scKIcSEKkdHzXhCTDLPFi5r1wnK6yPS
github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/tview v0.0.0-20220801133142-711ef394f9b3 h1:gAT0XOEOwYJboaU9CIjJ/2v+/RX6ls7isQhXjl4WYhs=
github.com/rivo/tview v0.0.0-20220801133142-711ef394f9b3/go.mod h1:8NHTlQK5nUcLMAPupYd8thZnu/6jlEWYdJZNcaggXFw=
github.com/rivo/tview v0.0.0-20220812085834-0e6b21a48e96 h1:O435d1KIgG6KxpP7NDdmj7SdaLIzq4F+PG8ZB/BHC4c=
github.com/rivo/tview v0.0.0-20220812085834-0e6b21a48e96/go.mod h1:hyzpnqn4KWzZopTEjL1AxvlzOLMH1IuKo4lTw6vyOQc=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.3.1 h1:SDPP7SHNl1L7KrEFCSJslJ/DM9DT02Nq2C61XrfHMmk=
github.com/rivo/uniseg v0.3.1/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rivo/uniseg v0.3.4 h1:3Z3Eu6FGHZWSfNKJTOUiPatWwfc7DzJRU04jFUqJODw=
github.com/rivo/uniseg v0.3.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
@ -48,13 +48,13 @@ github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG0
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+am0jAwlQLddpoMDM+iewkxxt6nxUQ5nq5o=
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y=
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE=
golang.org/x/net v0.0.0-20220728211354-c7608f3a8462 h1:UreQrH7DbFXSi9ZFox6FNT3WBooWmdANpU+IfkT1T4I=
golang.org/x/net v0.0.0-20220728211354-c7608f3a8462/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E=
golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220318055525-2edf467146b5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220731174439-a90be440212d h1:Sv5ogFZatcgIMMtBSTTAgMYsicp25MXBubjXNDKwm80=
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 h1:Q5284mrmYTpACcm+eAKjKJH48BBwSyfJqmmGDTtT8Vc=
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@ -63,7 +63,7 @@ golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI=
gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

2
main.go

@ -8,7 +8,7 @@ import (
"github.com/rivo/tview"
)
const version = "1.0.16"
const version = "1.0.17"
func main() {
util.SetTerminalTitle("tut")

5
ui/cmdbar.go

@ -91,6 +91,9 @@ func (c *CmdBar) DoneFunc(key tcell.Key) {
case ":newer":
c.tutView.LoadNewerCommand()
c.Back()
case ":clear-notifications":
c.tutView.ClearNotificationsCommand()
c.Back()
case ":list-placement":
if len(parts) < 2 {
break
@ -205,7 +208,7 @@ func (c *CmdBar) DoneFunc(key tcell.Key) {
func (c *CmdBar) Autocomplete(curr string) []string {
var entries []string
words := strings.Split(":blocking,:boosts,:bookmarks,:compose,:favorites,:favorited,:followers,:following,:help,:h,:lists,:list-placement,:list-split,:muting,:newer,:preferences,:profile,:proportions,:requests,:saved,:tag,:timeline,:tl,:user,:window,:quit,:q", ",")
words := strings.Split(":blocking,:boosts,:bookmarks,:clear-notifications,:compose,:favorites,:favorited,:followers,:following,:help,:h,:lists,:list-placement,:list-split,:muting,:newer,:preferences,:profile,:proportions,:requests,:saved,:tag,:timeline,:tl,:user,:window,:quit,:q", ",")
if curr == "" {
return entries
}

16
ui/commands.go

@ -7,6 +7,7 @@ import (
"github.com/RasmusLindroth/go-mastodon"
"github.com/RasmusLindroth/tut/api"
"github.com/RasmusLindroth/tut/config"
"github.com/RasmusLindroth/tut/feed"
"github.com/RasmusLindroth/tut/util"
)
@ -199,3 +200,18 @@ func (tv *TutView) LoadNewerCommand() {
f := tv.GetCurrentFeed()
f.LoadNewer(true)
}
func (tv *TutView) ClearNotificationsCommand() {
err := tv.tut.Client.ClearNotifications()
if err != nil {
tv.ShowError(fmt.Sprintf("Couldn't clear notifications. Error: %v\n", err))
return
}
for _, tl := range tv.Timeline.Feeds {
for _, f := range tl.Feeds {
if f.Data.Type() == feed.Notification {
f.Data.Clear()
}
}
}
}

55
ui/composeview.go

@ -34,7 +34,7 @@ type ComposeView struct {
content *tview.TextView
input *MediaInput
info *tview.TextView
controls *tview.TextView
controls *tview.Flex
visibility *tview.DropDown
media *MediaList
msg *msgToot
@ -59,13 +59,12 @@ func NewComposeView(tv *TutView) *ComposeView {
shared: tv.Shared,
content: NewTextView(tv.tut.Config),
input: NewMediaInput(tv),
controls: NewTextView(tv.tut.Config),
controls: NewControlView(tv.tut.Config),
info: NewTextView(tv.tut.Config),
visibility: NewDropDown(tv.tut.Config),
media: NewMediaList(tv),
}
cv.content.SetDynamicColors(true)
cv.controls.SetDynamicColors(true)
cv.View = newComposeUI(cv)
return cv
}
@ -109,27 +108,33 @@ func (cv *ComposeView) msgLength() int {
}
func (cv *ComposeView) SetControls(ctrl ComposeControls) {
var items []string
var items []Control
switch ctrl {
case ComposeNormal:
items = append(items, config.ColorFromKey(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.ComposePost, true))
items = append(items, config.ColorFromKey(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.ComposeEditText, true))
items = append(items, config.ColorFromKey(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.ComposeVisibility, true))
items = append(items, config.ColorFromKey(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.ComposeToggleContentWarning, true))
items = append(items, config.ColorFromKey(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.ComposeEditSpoiler, true))
items = append(items, config.ColorFromKey(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.ComposeMediaFocus, true))
items = append(items, config.ColorFromKey(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.ComposePoll, true))
items = append(items, NewControl(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.ComposePost, true))
items = append(items, NewControl(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.ComposeEditText, true))
items = append(items, NewControl(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.ComposeVisibility, true))
items = append(items, NewControl(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.ComposeToggleContentWarning, true))
items = append(items, NewControl(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.ComposeEditSpoiler, true))
items = append(items, NewControl(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.ComposeMediaFocus, true))
items = append(items, NewControl(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.ComposePoll, true))
if cv.msg.Status != nil {
items = append(items, config.ColorFromKey(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.ComposeIncludeQuote, true))
items = append(items, NewControl(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.ComposeIncludeQuote, true))
}
case ComposeMedia:
items = append(items, config.ColorFromKey(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.MediaAdd, true))
items = append(items, config.ColorFromKey(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.MediaDelete, true))
items = append(items, config.ColorFromKey(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.MediaEditDesc, true))
items = append(items, config.ColorFromKey(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.GlobalBack, true))
items = append(items, NewControl(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.MediaAdd, true))
items = append(items, NewControl(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.MediaDelete, true))
items = append(items, NewControl(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.MediaEditDesc, true))
items = append(items, NewControl(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.GlobalBack, true))
}
cv.controls.Clear()
for i, item := range items {
if i < len(items)-1 {
cv.controls.AddItem(NewControlButton(cv.tutView, item), item.Len+1, 0, false)
} else {
cv.controls.AddItem(NewControlButton(cv.tutView, item), item.Len, 0, false)
}
}
res := strings.Join(items, " ")
cv.controls.SetText(res)
}
func (cv *ComposeView) SetStatus(status *mastodon.Status) {
@ -374,12 +379,13 @@ func (cv *ComposeView) Post() {
}
type MediaList struct {
tutView *TutView
View *tview.Flex
heading *tview.TextView
text *tview.TextView
list *tview.List
Files []UploadFile
tutView *TutView
View *tview.Flex
heading *tview.TextView
text *tview.TextView
list *tview.List
Files []UploadFile
scrollSleep *scrollSleep
}
func NewMediaList(tv *TutView) *MediaList {
@ -389,6 +395,7 @@ func NewMediaList(tv *TutView) *MediaList {
text: NewTextView(tv.tut.Config),
list: NewList(tv.tut.Config),
}
ml.scrollSleep = NewScrollSleep(ml.Next, ml.Prev)
ml.heading.SetText(fmt.Sprintf("Media files: %d", ml.list.GetItemCount()))
ml.heading.SetBorderPadding(1, 1, 0, 0)
ml.View = tview.NewFlex().SetDirection(tview.FlexRow).

31
ui/controls.go

@ -0,0 +1,31 @@
package ui
import (
"github.com/RasmusLindroth/tut/config"
"github.com/gdamore/tcell/v2"
)
type Control struct {
key config.Key
Label string
Len int
}
func NewControl(c *config.Config, k config.Key, first bool) Control {
label, length := config.ColorFromKey(c, k, first)
return Control{
key: k,
Label: label,
Len: length,
}
}
func (c Control) Click() *tcell.EventKey {
for _, k := range c.key.Keys {
return tcell.NewEventKey(k, 0, tcell.ModNone)
}
for _, r := range c.key.Runes {
return tcell.NewEventKey(tcell.KeyRune, r, tcell.ModNone)
}
return tcell.NewEventKey(tcell.KeyRune, 0, tcell.ModNone)
}

7
ui/feed.go

@ -82,7 +82,7 @@ func (f *Feed) DrawContent() {
if id != item.ID() {
continue
}
DrawItem(f.tutView.tut, item, f.Content.Main, f.Content.Controls, f.Data.Type())
DrawItem(f.tutView, item, f.Content.Main, f.Content.Controls, f.Data.Type())
f.tutView.ShouldSync()
}
}
@ -541,7 +541,7 @@ func (fl *FeedList) SetByID(id uint) {
type FeedContent struct {
Main *tview.TextView
Controls *tview.TextView
Controls *tview.Flex
}
func NewFeedContent(t *Tut) *FeedContent {
@ -558,8 +558,7 @@ func NewFeedContent(t *Tut) *FeedContent {
return x, y, rWidth, height
})
}
c := NewTextView(t.Config)
c.SetDynamicColors(true)
c := NewControlView(t.Config)
fc := &FeedContent{
Main: m,
Controls: c,

20
ui/helpview.go

@ -2,7 +2,6 @@ package ui
import (
"bytes"
"strings"
"github.com/RasmusLindroth/tut/config"
"github.com/rivo/tview"
@ -13,7 +12,7 @@ type HelpView struct {
shared *Shared
View *tview.Flex
content *tview.TextView
controls *tview.TextView
controls *tview.Flex
}
type HelpData struct {
@ -22,7 +21,7 @@ type HelpData struct {
func NewHelpView(tv *TutView) *HelpView {
content := NewTextView(tv.tut.Config)
controls := NewTextView(tv.tut.Config)
controls := NewControlView(tv.tut.Config)
hv := &HelpView{
tutView: tv,
shared: tv.Shared,
@ -36,11 +35,16 @@ func NewHelpView(tv *TutView) *HelpView {
panic(err)
}
hv.content.SetText(output.String())
var items []string
items = append(items, config.ColorFromKey(tv.tut.Config, tv.tut.Config.Input.GlobalBack, true))
items = append(items, config.ColorFromKey(tv.tut.Config, tv.tut.Config.Input.GlobalExit, true))
res := strings.Join(items, " ")
hv.controls.SetText(res)
var items []Control
items = append(items, NewControl(tv.tut.Config, tv.tut.Config.Input.GlobalBack, true))
items = append(items, NewControl(tv.tut.Config, tv.tut.Config.Input.GlobalExit, true))
for i, item := range items {
if i < len(items)-1 {
hv.controls.AddItem(NewControlButton(hv.tutView, item), item.Len+1, 0, false)
} else {
hv.controls.AddItem(NewControlButton(hv.tutView, item), item.Len, 0, false)
}
}
hv.View = newHelpViewUI(hv)
return hv
}

364
ui/input.go

@ -4,6 +4,8 @@ import (
"fmt"
"strconv"
"strings"
"sync"
"time"
"github.com/RasmusLindroth/go-mastodon"
"github.com/RasmusLindroth/tut/api"
@ -113,6 +115,8 @@ func (tv *TutView) InputLeaderKey(event *tcell.EventKey) *tcell.EventKey {
tv.LocalCommand()
case config.LeaderFederated:
tv.FederatedCommand()
case config.LeaderClearNotifications:
tv.ClearNotificationsCommand()
case config.LeaderCompose:
tv.ComposeCommand()
case config.LeaderBlocking:
@ -896,136 +900,294 @@ func (tv *TutView) InputCmdView(event *tcell.EventKey) *tcell.EventKey {
}
func (tv *TutView) MouseInput(event *tcell.EventMouse, action tview.MouseAction) (*tcell.EventMouse, tview.MouseAction) {
if event != nil {
tv.mouseX, tv.mouseY = event.Position()
tv.mouseEvent = event
if event == nil {
return nil, action
}
if tv.PageFocus == MainFocus || tv.PageFocus == ViewFocus {
if action == tview.MouseLeftClick {
f := tv.GetCurrentFeed()
if f.Content.Main.InRect(tv.mouseX, tv.mouseY) {
tv.SetPage(ViewFocus)
return nil, action
}
for i, tl := range tv.Timeline.Feeds {
fl := tl.GetFeedList()
if fl.Text.InRect(tv.mouseX, tv.mouseY) {
tv.feedListMouse(fl.Text, i, action)
return nil, action
}
if fl.Symbol.InRect(tv.mouseX, tv.mouseY) {
tv.feedListMouse(fl.Symbol, i, action)
return nil, action
}
}
}
switch action {
case tview.MouseLeftUp, tview.MouseMiddleUp, tview.MouseRightUp:
return event, action
}
if tv.PageFocus == LoginFocus {
if action == tview.MouseLeftClick {
list := tv.LoginView.list
if !list.InRect(tv.mouseX, tv.mouseY) {
switch tv.PageFocus {
case ViewFocus, MainFocus:
return tv.MouseInputMainView(event, action)
case LoginFocus:
tv.MouseInputLoginView(event, action)
case LinkFocus:
return tv.MouseInputLinkView(event, action)
case MediaFocus:
return tv.MouseInputMediaView(event, action)
case VoteFocus:
return tv.MouseInputVoteView(event, action)
case ModalFocus:
tv.MouseInputModalView(event, action)
case PollFocus:
return tv.MouseInputPollView(event, action)
case HelpFocus:
return tv.MouseInputHelpView(event, action)
case ComposeFocus:
return tv.MouseInputComposeView(event, action)
case PreferenceFocus:
return tv.MouseInputPreferenceView(event, action)
}
return nil, action
}
func (tv *TutView) feedListMouse(list *tview.List, i int, event *tcell.EventMouse, action tview.MouseAction) {
tv.SetPage(MainFocus)
tv.FocusFeed(i)
mh := list.MouseHandler()
if mh == nil {
return
}
lastIndex := list.GetCurrentItem()
mh(action, event, func(p tview.Primitive) {})
newIndex := list.GetCurrentItem()
if lastIndex != newIndex {
tv.Timeline.SetItemFeedIndex(newIndex)
}
}
var scrollSleepTime time.Duration = 150
type scrollSleep struct {
mux sync.Mutex
last time.Time
next func()
prev func()
}
func NewScrollSleep(next func(), prev func()) *scrollSleep {
return &scrollSleep{
next: next,
prev: prev,
}
}
func (sc *scrollSleep) Action(list *tview.List, action tview.MouseAction) {
mh := list.MouseHandler()
if mh == nil {
return
}
lock := sc.mux.TryLock()
if !lock {
return
}
if time.Since(sc.last) < (scrollSleepTime * time.Millisecond) {
sc.mux.Unlock()
return
}
if action == tview.MouseScrollDown {
sc.next()
}
if action == tview.MouseScrollUp {
sc.prev()
}
sc.last = time.Now()
sc.mux.Unlock()
}
func (tv *TutView) MouseInputMainView(event *tcell.EventMouse, action tview.MouseAction) (*tcell.EventMouse, tview.MouseAction) {
x, y := event.Position()
switch action {
case tview.MouseScrollDown, tview.MouseScrollUp:
f := tv.GetCurrentFeed()
if f.Content.Main.InRect(x, y) {
if action == tview.MouseScrollDown {
tv.Timeline.ScrollDown()
return nil, action
}
mh := list.MouseHandler()
if mh == nil {
if action == tview.MouseScrollUp {
tv.Timeline.ScrollUp()
return nil, action
}
mh(action, tv.mouseEvent, func(p tview.Primitive) {})
tv.LoginView.Selected()
}
}
if tv.PageFocus == LinkFocus {
if action == tview.MouseLeftClick {
list := tv.LinkView.list
if !list.InRect(tv.mouseX, tv.mouseY) {
for _, tl := range tv.Timeline.Feeds {
fl := tl.GetFeedList()
if fl.Text.InRect(x, y) {
tv.Timeline.scrollSleep.Action(fl.Text, action)
return nil, action
}
mh := list.MouseHandler()
if mh == nil {
if fl.Symbol.InRect(x, y) {
tv.Timeline.scrollSleep.Action(fl.Symbol, action)
return nil, action
}
mh(action, tv.mouseEvent, func(p tview.Primitive) {})
tv.LinkView.Open()
}
}
if tv.PageFocus == MediaFocus {
if action == tview.MouseLeftClick {
list := tv.ComposeView.media.list
if !list.InRect(tv.mouseX, tv.mouseY) {
case tview.MouseLeftClick:
f := tv.GetCurrentFeed()
if f.Content.Main.InRect(x, y) {
tv.SetPage(ViewFocus)
return nil, action
}
if f.Content.Controls.InRect(x, y) {
return event, action
}
for i, tl := range tv.Timeline.Feeds {
fl := tl.GetFeedList()
if fl.Text.InRect(x, y) {
tv.feedListMouse(fl.Text, i, event, action)
return nil, action
}
mh := list.MouseHandler()
if mh == nil {
if fl.Symbol.InRect(x, y) {
tv.feedListMouse(fl.Symbol, i, event, action)
return nil, action
}
mh(action, tv.mouseEvent, func(p tview.Primitive) {})
}
if tv.PageFocus == MediaFocus {
if action == tview.MouseLeftClick {
list := tv.ComposeView.media.list
if !list.InRect(tv.mouseX, tv.mouseY) {
return nil, action
}
mh := list.MouseHandler()
if mh == nil {
return nil, action
}
mh(action, tv.mouseEvent, func(p tview.Primitive) {})
}
}
return nil, action
}
func (tv *TutView) MouseInputLoginView(event *tcell.EventMouse, action tview.MouseAction) {
x, y := event.Position()
switch action {
case tview.MouseLeftClick:
list := tv.LoginView.list
if !list.InRect(x, y) {
return
}
mh := list.MouseHandler()
if mh == nil {
return
}
mh(action, event, func(p tview.Primitive) {})
tv.LoginView.Selected()
case tview.MouseScrollDown, tview.MouseScrollUp:
tv.LoginView.scrollSleep.Action(tv.LoginView.list, action)
}
if tv.PageFocus == VoteFocus {
if action == tview.MouseLeftClick {
list := tv.VoteView.list
if !list.InRect(tv.mouseX, tv.mouseY) {
return nil, action
}
mh := list.MouseHandler()
if mh == nil {
return nil, action
}
mh(action, tv.mouseEvent, func(p tview.Primitive) {})
tv.VoteView.ToggleSelect()
}
func (tv *TutView) MouseInputLinkView(event *tcell.EventMouse, action tview.MouseAction) (*tcell.EventMouse, tview.MouseAction) {
x, y := event.Position()
switch action {
case tview.MouseLeftClick:
if tv.LinkView.controls.InRect(x, y) {
return event, action
}
list := tv.LinkView.list
if !list.InRect(x, y) {
return nil, action
}
mh := list.MouseHandler()
if mh == nil {
return nil, action
}
mh(action, event, func(p tview.Primitive) {})
tv.LinkView.Open()
case tview.MouseScrollDown, tview.MouseScrollUp:
tv.LinkView.scrollSleep.Action(tv.LinkView.list, action)
}
if tv.PageFocus == ModalFocus {
if action == tview.MouseLeftClick {
modal := tv.ModalView.View
mh := modal.MouseHandler()
if mh == nil {
return nil, action
}
mh(action, tv.mouseEvent, func(p tview.Primitive) {})
return nil, action
}
func (tv *TutView) MouseInputMediaView(event *tcell.EventMouse, action tview.MouseAction) (*tcell.EventMouse, tview.MouseAction) {
x, y := event.Position()
switch action {
case tview.MouseLeftClick:
if tv.ComposeView.controls.InRect(x, y) {
return event, action
}
list := tv.ComposeView.media.list
if !list.InRect(x, y) {
return nil, action
}
mh := list.MouseHandler()
if mh == nil {
return nil, action
}
mh(action, event, func(p tview.Primitive) {})
case tview.MouseScrollDown, tview.MouseScrollUp:
tv.ComposeView.media.scrollSleep.Action(tv.ComposeView.media.list, action)
}
if tv.PageFocus == PollFocus {
if action == tview.MouseLeftClick {
list := tv.PollView.list
if !list.InRect(tv.mouseX, tv.mouseY) {
return nil, action
}
mh := list.MouseHandler()
if mh == nil {
return nil, action
}
mh(action, tv.mouseEvent, func(p tview.Primitive) {})
return nil, action
}
func (tv *TutView) MouseInputVoteView(event *tcell.EventMouse, action tview.MouseAction) (*tcell.EventMouse, tview.MouseAction) {
x, y := event.Position()
switch action {
case tview.MouseLeftClick:
if tv.VoteView.controls.InRect(x, y) {
return event, action
}
list := tv.VoteView.list
if !list.InRect(x, y) {
return nil, action
}
mh := list.MouseHandler()
if mh == nil {
return nil, action
}
mh(action, event, func(p tview.Primitive) {})
tv.VoteView.ToggleSelect()
case tview.MouseScrollDown, tview.MouseScrollUp:
tv.VoteView.scrollSleep.Action(tv.VoteView.list, action)
}
return nil, action
}
func (tv *TutView) feedListMouse(list *tview.List, i int, action tview.MouseAction) {
tv.SetPage(MainFocus)
tv.FocusFeed(i)
mh := list.MouseHandler()
if mh == nil {
return
func (tv *TutView) MouseInputModalView(event *tcell.EventMouse, action tview.MouseAction) {
switch action {
case tview.MouseLeftClick:
modal := tv.ModalView.View
mh := modal.MouseHandler()
if mh == nil {
return
}
mh(action, event, func(p tview.Primitive) {})
}
lastIndex := list.GetCurrentItem()
mh(action, tv.mouseEvent, func(p tview.Primitive) {})
newIndex := list.GetCurrentItem()
if lastIndex != newIndex {
tv.Timeline.SetItemFeedIndex(newIndex)
}
func (tv *TutView) MouseInputPollView(event *tcell.EventMouse, action tview.MouseAction) (*tcell.EventMouse, tview.MouseAction) {
x, y := event.Position()
switch action {
case tview.MouseLeftClick:
if tv.PollView.controls.InRect(x, y) {
return event, action
}
list := tv.PollView.list
if !list.InRect(x, y) {
return nil, action
}
mh := list.MouseHandler()
if mh == nil {
return nil, action
}
mh(action, event, func(p tview.Primitive) {})
case tview.MouseScrollDown, tview.MouseScrollUp:
tv.PollView.scrollSleep.Action(tv.PollView.list, action)
}
return nil, action
}
func (tv *TutView) MouseInputHelpView(event *tcell.EventMouse, action tview.MouseAction) (*tcell.EventMouse, tview.MouseAction) {
x, y := event.Position()
switch action {
case tview.MouseLeftClick:
if tv.HelpView.controls.InRect(x, y) {
return event, action
}
}
return nil, action
}
func (tv *TutView) MouseInputPreferenceView(event *tcell.EventMouse, action tview.MouseAction) (*tcell.EventMouse, tview.MouseAction) {
x, y := event.Position()
switch action {
case tview.MouseLeftClick:
if tv.PreferenceView.controls.InRect(x, y) {
return event, action
}
}
return nil, action
}
func (tv *TutView) MouseInputComposeView(event *tcell.EventMouse, action tview.MouseAction) (*tcell.EventMouse, tview.MouseAction) {
x, y := event.Position()
switch action {
case tview.MouseLeftClick:
if tv.ComposeView.controls.InRect(x, y) {
return event, action
}
}
return nil, action
}

22
ui/item.go

@ -66,35 +66,35 @@ func DrawListItem(cfg *config.Config, item api.Item) (string, string) {
}
}
func DrawItem(tut *Tut, item api.Item, main *tview.TextView, controls *tview.TextView, ft feed.FeedType) {
func DrawItem(tv *TutView, item api.Item, main *tview.TextView, controls *tview.Flex, ft feed.FeedType) {
switch item.Type() {
case api.StatusType:
drawStatus(tut, item, item.Raw().(*mastodon.Status), main, controls, "")
drawStatus(tv, item, item.Raw().(*mastodon.Status), main, controls, "")
case api.UserType, api.ProfileType:
if ft == feed.FollowRequests {
drawUser(tut, item.Raw().(*api.User), main, controls, "", true)
drawUser(tv, item.Raw().(*api.User), main, controls, "", true)
} else {
drawUser(tut, item.Raw().(*api.User), main, controls, "", false)
drawUser(tv, item.Raw().(*api.User), main, controls, "", false)
}
case api.NotificationType:
drawNotification(tut, item, item.Raw().(*api.NotificationData), main, controls)
drawNotification(tv, item, item.Raw().(*api.NotificationData), main, controls)
case api.ListsType:
drawList(tut, item.Raw().(*mastodon.List), main, controls)
drawList(tv, item.Raw().(*mastodon.List), main, controls)
}
}
func DrawItemControls(tut *Tut, item api.Item, controls *tview.TextView, ft feed.FeedType) {
func DrawItemControls(tv *TutView, item api.Item, controls *tview.Flex, ft feed.FeedType) {
switch item.Type() {
case api.StatusType:
drawStatus(tut, item, item.Raw().(*mastodon.Status), nil, controls, "")
drawStatus(tv, item, item.Raw().(*mastodon.Status), nil, controls, "")
case api.UserType, api.ProfileType:
if ft == feed.FollowRequests {
drawUser(tut, item.Raw().(*api.User), nil, controls, "", true)
drawUser(tv, item.Raw().(*api.User), nil, controls, "", true)
} else {
drawUser(tut, item.Raw().(*api.User), nil, controls, "", false)
drawUser(tv, item.Raw().(*api.User), nil, controls, "", false)
}
case api.NotificationType:
drawNotification(tut, item, item.Raw().(*api.NotificationData), nil, controls)
drawNotification(tv, item, item.Raw().(*api.NotificationData), nil, controls)
}
}

8
ui/item_list.go

@ -4,17 +4,15 @@ import (
"fmt"
"github.com/RasmusLindroth/go-mastodon"
"github.com/RasmusLindroth/tut/config"
"github.com/rivo/tview"
)
type List struct {
}
func drawList(tut *Tut, data *mastodon.List, main *tview.TextView, controls *tview.TextView) {
controlItem := config.ColorFromKey(tut.Config, tut.Config.Input.ListOpenFeed, true)
func drawList(tv *TutView, data *mastodon.List, main *tview.TextView, controls *tview.Flex) {
btn := NewControl(tv.tut.Config, tv.tut.Config.Input.ListOpenFeed, true)
controls.AddItem(NewControlButton(tv, btn), btn.Len, 0, false)
main.SetText(fmt.Sprintf("List %s", tview.Escape(data.Title)))
controls.SetText(controlItem)
}

16
ui/item_notification.go

@ -8,34 +8,34 @@ import (
"github.com/rivo/tview"
)
func drawNotification(tut *Tut, item api.Item, notification *api.NotificationData, main *tview.TextView, controls *tview.TextView) {
func drawNotification(tv *TutView, item api.Item, notification *api.NotificationData, main *tview.TextView, controls *tview.Flex) {
switch notification.Item.Type {
case "follow":
drawUser(tut, notification.User.Raw().(*api.User), main, controls,
drawUser(tv, notification.User.Raw().(*api.User), main, controls,
fmt.Sprintf("%s started following you", util.FormatUsername(notification.Item.Account)), false,
)
case "favourite":
drawStatus(tut, notification.Status, notification.Item.Status, main, controls,
drawStatus(tv, notification.Status, notification.Item.Status, main, controls,
fmt.Sprintf("%s favorited your toot", util.FormatUsername(notification.Item.Account)),
)
case "reblog":
drawStatus(tut, notification.Status, notification.Item.Status, main, controls,
drawStatus(tv, notification.Status, notification.Item.Status, main, controls,
fmt.Sprintf("%s boosted your toot", util.FormatUsername(notification.Item.Account)),
)
case "mention":
drawStatus(tut, notification.Status, notification.Item.Status, main, controls,
drawStatus(tv, notification.Status, notification.Item.Status, main, controls,
fmt.Sprintf("%s mentioned you", util.FormatUsername(notification.Item.Account)),
)
case "status":
drawStatus(tut, notification.Status, notification.Item.Status, main, controls,
drawStatus(tv, notification.Status, notification.Item.Status, main, controls,
fmt.Sprintf("%s posted a new toot", util.FormatUsername(notification.Item.Account)),
)
case "poll":
drawStatus(tut, notification.Status, notification.Item.Status, main, controls,
drawStatus(tv, notification.Status, notification.Item.Status, main, controls,
"A poll of yours or one you participated in has ended",
)
case "follow_request":
drawUser(tut, notification.User.Raw().(*api.User), main, controls,
drawUser(tv, notification.User.Raw().(*api.User), main, controls,
fmt.Sprintf("%s wants to follow you.", util.FormatUsername(notification.Item.Account)),
true,
)

57
ui/item_status.go

@ -70,22 +70,21 @@ type DisplayTootData struct {
Style config.Style
}
func drawStatus(tut *Tut, item api.Item, status *mastodon.Status, main *tview.TextView, controls *tview.TextView, additional string) {
func drawStatus(tv *TutView, item api.Item, status *mastodon.Status, main *tview.TextView, controls *tview.Flex, additional string) {
filtered, phrase := item.Filtered()
if filtered {
var output string
if tut.Config.General.ShowFilterPhrase {
if tv.tut.Config.General.ShowFilterPhrase {
output = fmt.Sprintf("Filtered by phrase: %s", tview.Escape(phrase))
} else {
output = "Filtered."
}
if main != nil {
if additional != "" {
additional = fmt.Sprintf("%s\n\n", config.SublteText(tut.Config, additional))
additional = fmt.Sprintf("%s\n\n", config.SublteText(tv.tut.Config, additional))
}
main.SetText(additional + output)
}
controls.SetText("")
return
}
@ -188,57 +187,63 @@ func drawStatus(tut *Tut, item api.Item, status *mastodon.Status, main *tview.Te
main.ScrollToBeginning()
}
var info []string
var info []Control
if status.Favourited {
info = append(info, config.ColorFromKey(tut.Config, tut.Config.Input.StatusFavorite, false))
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusFavorite, false))
} else {
info = append(info, config.ColorFromKey(tut.Config, tut.Config.Input.StatusFavorite, true))
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusFavorite, true))
}
if status.Reblogged {
info = append(info, config.ColorFromKey(tut.Config, tut.Config.Input.StatusBoost, false))
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusBoost, false))
} else {
info = append(info, config.ColorFromKey(tut.Config, tut.Config.Input.StatusBoost, true))
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusBoost, true))
}
info = append(info, config.ColorFromKey(tut.Config, tut.Config.Input.StatusThread, true))
info = append(info, config.ColorFromKey(tut.Config, tut.Config.Input.StatusReply, true))
info = append(info, config.ColorFromKey(tut.Config, tut.Config.Input.StatusViewFocus, true))
info = append(info, config.ColorFromKey(tut.Config, tut.Config.Input.StatusUser, true))
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusThread, true))
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusReply, true))
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusViewFocus, true))
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusUser, true))
if len(status.MediaAttachments) > 0 {
info = append(info, config.ColorFromKey(tut.Config, tut.Config.Input.StatusMedia, true))
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusMedia, true))
}
_, _, _, length := item.URLs()
if length > 0 {
info = append(info, config.ColorFromKey(tut.Config, tut.Config.Input.StatusLinks, true))
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusLinks, true))
}
info = append(info, config.ColorFromKey(tut.Config, tut.Config.Input.StatusAvatar, true))
if status.Account.ID == tut.Client.Me.ID {
info = append(info, config.ColorFromKey(tut.Config, tut.Config.Input.StatusDelete, true))
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusAvatar, true))
if status.Account.ID == tv.tut.Client.Me.ID {
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusDelete, true))
}
if !status.Bookmarked {
info = append(info, config.ColorFromKey(tut.Config, tut.Config.Input.StatusBookmark, true))
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusBookmark, true))
} else {
info = append(info, config.ColorFromKey(tut.Config, tut.Config.Input.StatusBookmark, false))
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusBookmark, false))
}
info = append(info, config.ColorFromKey(tut.Config, tut.Config.Input.StatusYank, true))
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusYank, true))
controlsS := strings.Join(info, " ")
controls.Clear()
for i, item := range info {
if i < len(info)-1 {
controls.AddItem(NewControlButton(tv, item), item.Len+1, 0, false)
} else {
controls.AddItem(NewControlButton(tv, item), item.Len, 0, false)
}
}
td := DisplayTootData{
Toot: toot,
Style: tut.Config.Style,
Style: tv.tut.Config.Style,
}
var output bytes.Buffer
err := tut.Config.Templates.Toot.ExecuteTemplate(&output, "toot.tmpl", td)
err := tv.tut.Config.Templates.Toot.ExecuteTemplate(&output, "toot.tmpl", td)
if err != nil {
panic(err)
}
if main != nil {
if additional != "" {
additional = fmt.Sprintf("%s\n\n", config.SublteText(tut.Config, additional))
additional = fmt.Sprintf("%s\n\n", config.SublteText(tv.tut.Config, additional))
}
main.SetText(additional + output.String())
}
controls.SetText(controlsS)
}

48
ui/item_user.go

@ -3,7 +3,6 @@ package ui
import (
"bytes"
"fmt"
"strings"
"time"
"github.com/RasmusLindroth/tut/api"
@ -44,7 +43,7 @@ type DisplayUserData struct {
Style config.Style
}
func drawUser(tut *Tut, data *api.User, main *tview.TextView, controls *tview.TextView, additional string, fr bool) {
func drawUser(tv *TutView, data *api.User, main *tview.TextView, controls *tview.Flex, additional string, fr bool) {
user := data.Data
relation := data.Relation
showUserControl := true
@ -65,8 +64,6 @@ func drawUser(tut *Tut, data *api.User, main *tview.TextView, controls *tview.Te
Bot: user.Bot,
}
var controlsS string
var urls []util.URL
fields := []Field{}
u.Note, urls = util.CleanHTML(user.Note)
@ -81,52 +78,59 @@ func drawUser(tut *Tut, data *api.User, main *tview.TextView, controls *tview.Te
}
u.Fields = fields
var controlItems []string
var controlItems []Control
if fr {
controlItems = append(controlItems, config.ColorFromKey(tut.Config, tut.Config.Input.UserFollowRequestDecide, false))
controlItems = append(controlItems, NewControl(tv.tut.Config, tv.tut.Config.Input.UserFollowRequestDecide, false))
}
if tut.Client.Me.ID != user.ID {
if tv.tut.Client.Me.ID != user.ID {
if relation.Following {
controlItems = append(controlItems, config.ColorFromKey(tut.Config, tut.Config.Input.UserFollow, false))
controlItems = append(controlItems, NewControl(tv.tut.Config, tv.tut.Config.Input.UserFollow, false))
} else {
controlItems = append(controlItems, config.ColorFromKey(tut.Config, tut.Config.Input.UserFollow, true))
controlItems = append(controlItems, NewControl(tv.tut.Config, tv.tut.Config.Input.UserFollow, true))
}
if relation.Blocking {
controlItems = append(controlItems, config.ColorFromKey(tut.Config, tut.Config.Input.UserBlock, false))
controlItems = append(controlItems, NewControl(tv.tut.Config, tv.tut.Config.Input.UserBlock, false))
} else {
controlItems = append(controlItems, config.ColorFromKey(tut.Config, tut.Config.Input.UserBlock, true))
controlItems = append(controlItems, NewControl(tv.tut.Config, tv.tut.Config.Input.UserBlock, true))
}
if relation.Muting {
controlItems = append(controlItems, config.ColorFromKey(tut.Config, tut.Config.Input.UserMute, false))
controlItems = append(controlItems, NewControl(tv.tut.Config, tv.tut.Config.Input.UserMute, false))
} else {
controlItems = append(controlItems, config.ColorFromKey(tut.Config, tut.Config.Input.UserMute, true))
controlItems = append(controlItems, NewControl(tv.tut.Config, tv.tut.Config.Input.UserMute, true))
}
if len(urls) > 0 {
controlItems = append(controlItems, config.ColorFromKey(tut.Config, tut.Config.Input.UserLinks, true))
controlItems = append(controlItems, NewControl(tv.tut.Config, tv.tut.Config.Input.UserLinks, true))
}
}
if showUserControl {
controlItems = append(controlItems, config.ColorFromKey(tut.Config, tut.Config.Input.UserUser, true))
controlItems = append(controlItems, NewControl(tv.tut.Config, tv.tut.Config.Input.UserUser, true))
}
controlItems = append(controlItems, NewControl(tv.tut.Config, tv.tut.Config.Input.UserAvatar, true))
controlItems = append(controlItems, NewControl(tv.tut.Config, tv.tut.Config.Input.UserYank, true))
controls.Clear()
for i, item := range controlItems {
if i < len(controlItems)-1 {
controls.AddItem(NewControlButton(tv, item), item.Len+1, 0, false)
} else {
controls.AddItem(NewControlButton(tv, item), item.Len, 0, false)
}
}
controlItems = append(controlItems, config.ColorFromKey(tut.Config, tut.Config.Input.UserAvatar, true))
controlItems = append(controlItems, config.ColorFromKey(tut.Config, tut.Config.Input.UserYank, true))
controlsS = strings.Join(controlItems, " ")
ud := DisplayUserData{
User: u,
Style: tut.Config.Style,
Style: tv.tut.Config.Style,
}
var output bytes.Buffer
err := tut.Config.Templates.User.ExecuteTemplate(&output, "user.tmpl", ud)
err := tv.tut.Config.Templates.User.ExecuteTemplate(&output, "user.tmpl", ud)
if err != nil {
panic(err)
}
if main != nil {
if additional != "" {
additional = fmt.Sprintf("%s\n\n", config.SublteText(tut.Config, additional))
additional = fmt.Sprintf("%s\n\n", config.SublteText(tv.tut.Config, additional))
}
main.SetText(additional + output.String())
}
controls.SetText(controlsS)
}

38
ui/linkview.go

@ -2,44 +2,54 @@ package ui
import (
"fmt"
"strings"
"github.com/RasmusLindroth/tut/config"
"github.com/rivo/tview"
)
type LinkView struct {
tutView *TutView
shared *Shared
View *tview.Flex
list *tview.List
controls *tview.TextView
tutView *TutView
shared *Shared
View *tview.Flex
list *tview.List
controls *tview.Flex
scrollSleep *scrollSleep
}
func NewLinkView(tv *TutView) *LinkView {
l := NewList(tv.tut.Config)
txt := NewTextView(tv.tut.Config)
c := NewControlView(tv.tut.Config)
lv := &LinkView{
tutView: tv,
shared: tv.Shared,
list: l,
controls: txt,
controls: c,
}
lv.scrollSleep = NewScrollSleep(lv.Next, lv.Prev)
lv.View = linkViewUI(lv)
return lv
}
func linkViewUI(lv *LinkView) *tview.Flex {
lv.controls.SetBorderPadding(0, 0, 1, 1)
items := []string{
config.ColorFromKey(lv.tutView.tut.Config, lv.tutView.tut.Config.Input.LinkOpen, true),
config.ColorFromKey(lv.tutView.tut.Config, lv.tutView.tut.Config.Input.LinkYank, true),
items := []Control{
NewControl(lv.tutView.tut.Config, lv.tutView.tut.Config.Input.LinkOpen, true),
NewControl(lv.tutView.tut.Config, lv.tutView.tut.Config.Input.LinkYank, true),
}
for _, cust := range lv.tutView.tut.Config.OpenCustom.OpenCustoms {
items = append(items, config.ColorKey(lv.tutView.tut.Config, "", fmt.Sprintf("%d", cust.Index), cust.Name))
key := config.Key{
Hint: [][]string{{"", fmt.Sprintf("%d", cust.Index), cust.Name}},
}
items = append(items, NewControl(lv.tutView.tut.Config, key, true))
}
lv.controls.Clear()
for i, item := range items {
if i < len(items)-1 {
lv.controls.AddItem(NewControlButton(lv.tutView, item), item.Len+1, 0, false)
} else {
lv.controls.AddItem(NewControlButton(lv.tutView, item), item.Len, 0, false)
}
}
res := strings.Join(items, " ")
lv.controls.SetText(res)
r := tview.NewFlex().SetDirection(tview.FlexRow)
if lv.tutView.tut.Config.General.TerminalTitle < 2 {

13
ui/loginview.go

@ -8,10 +8,11 @@ import (
)
type LoginView struct {
tutView *TutView
accounts *auth.AccountData
View tview.Primitive
list *tview.List
tutView *TutView
accounts *auth.AccountData
View tview.Primitive
list *tview.List
scrollSleep *scrollSleep
}
func NewLoginView(tv *TutView, accs *auth.AccountData) *LoginView {
@ -28,12 +29,14 @@ func NewLoginView(tv *TutView, accs *auth.AccountData) *LoginView {
v.AddItem(list, 0, 1, false).
AddItem(tv.Shared.Bottom.View, 2, 0, false)
return &LoginView{
lv := &LoginView{
tutView: tv,
accounts: accs,
View: v,
list: list,
}
lv.scrollSleep = NewScrollSleep(lv.Next, lv.Prev)
return lv
}
func (l *LoginView) Selected() {

4
ui/media.go

@ -3,8 +3,8 @@ package ui
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"os/exec"
"github.com/RasmusLindroth/go-mastodon"
@ -12,7 +12,7 @@ import (
)
func downloadFile(url string) (string, error) {
f, err := ioutil.TempFile("", "tutfile")
f, err := os.CreateTemp("", "tutfile")
if err != nil {
return "", err
}

44
ui/pollview.go

@ -2,10 +2,8 @@ package ui
import (
"fmt"
"strings"
"github.com/RasmusLindroth/go-mastodon"
"github.com/RasmusLindroth/tut/config"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)
@ -30,14 +28,15 @@ var durationsTime = map[string]int64{
}
type PollView struct {
tutView *TutView
shared *Shared
View *tview.Flex
info *tview.TextView
expiration *tview.DropDown
controls *tview.TextView
list *tview.List
poll *mastodon.TootPoll
tutView *TutView
shared *Shared
View *tview.Flex
info *tview.TextView
expiration *tview.DropDown
controls *tview.Flex
list *tview.List
poll *mastodon.TootPoll
scrollSleep *scrollSleep
}
func NewPollView(tv *TutView) *PollView {
@ -46,9 +45,10 @@ func NewPollView(tv *TutView) *PollView {
shared: tv.Shared,
info: NewTextView(tv.tut.Config),
expiration: NewDropDown(tv.tut.Config),
controls: NewTextView(tv.tut.Config),
controls: NewControlView(tv.tut.Config),
list: NewList(tv.tut.Config),
}
p.scrollSleep = NewScrollSleep(p.Next, p.Prev)
p.Reset()
p.View = pollViewUI(p)
@ -56,14 +56,20 @@ func NewPollView(tv *TutView) *PollView {
}
func pollViewUI(p *PollView) *tview.Flex {
var items []string
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PollAdd, true))
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PollEdit, true))
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PollDelete, true))
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PollMultiToggle, true))
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PollExpiration, true))
p.controls.SetText(strings.Join(items, " "))
var items []Control
items = append(items, NewControl(p.tutView.tut.Config, p.tutView.tut.Config.Input.PollAdd, true))
items = append(items, NewControl(p.tutView.tut.Config, p.tutView.tut.Config.Input.PollEdit, true))
items = append(items, NewControl(p.tutView.tut.Config, p.tutView.tut.Config.Input.PollDelete, true))
items = append(items, NewControl(p.tutView.tut.Config, p.tutView.tut.Config.Input.PollMultiToggle, true))
items = append(items, NewControl(p.tutView.tut.Config, p.tutView.tut.Config.Input.PollExpiration, true))
p.controls.Clear()
for i, item := range items {
if i < len(items)-1 {
p.controls.AddItem(NewControlButton(p.tutView, item), item.Len+1, 0, false)
} else {
p.controls.AddItem(NewControlButton(p.tutView, item), item.Len, 0, false)
}
}
p.expiration.SetLabel("Expiration: ")
p.expiration.SetOptions(durations, p.expirationSelected)
p.expiration.SetCurrentOption(4)

47
ui/preferenceview.go

@ -2,10 +2,8 @@ package ui
import (
"fmt"
"strings"
"github.com/RasmusLindroth/go-mastodon"
"github.com/RasmusLindroth/tut/config"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)
@ -31,7 +29,7 @@ type PreferenceView struct {
bio *tview.TextView
fields *tview.List
visibility *tview.DropDown
controls *tview.TextView
controls *tview.Flex
preferences *preferences
fieldFocus bool
}
@ -44,7 +42,7 @@ func NewPreferenceView(tv *TutView) *PreferenceView {
bio: NewTextView(tv.tut.Config),
fields: NewList(tv.tut.Config),
visibility: NewDropDown(tv.tut.Config),
controls: NewTextView(tv.tut.Config),
controls: NewControlView(tv.tut.Config),
preferences: &preferences{},
}
p.View = preferenceViewUI(p)
@ -125,13 +123,19 @@ func (p *PreferenceView) HasFieldFocus() bool {
func (p *PreferenceView) FieldFocus() {
p.fieldFocus = true
var items []string
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceFieldsAdd, true))
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceFieldsEdit, true))
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceFieldsDelete, true))
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.GlobalBack, true))
p.controls.SetText(strings.Join(items, " "))
var items []Control
items = append(items, NewControl(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceFieldsAdd, true))
items = append(items, NewControl(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceFieldsEdit, true))
items = append(items, NewControl(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceFieldsDelete, true))
items = append(items, NewControl(p.tutView.tut.Config, p.tutView.tut.Config.Input.GlobalBack, true))
p.controls.Clear()
for i, item := range items {
if i < len(items)-1 {
p.controls.AddItem(NewControlButton(p.tutView, item), item.Len+1, 0, false)
} else {
p.controls.AddItem(NewControlButton(p.tutView, item), item.Len, 0, false)
}
}
cnf := p.tutView.tut.Config
p.fields.SetSelectedBackgroundColor(cnf.Style.ListSelectedBackground)
p.fields.SetSelectedTextColor(cnf.Style.ListSelectedText)
@ -140,13 +144,20 @@ func (p *PreferenceView) FieldFocus() {
func (p *PreferenceView) MainFocus() {
p.fieldFocus = false
var items []string
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceName, true))
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceVisibility, true))
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceBio, true))
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceFields, true))
items = append(items, config.ColorFromKey(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceSave, true))
p.controls.SetText(strings.Join(items, " "))
var items []Control
items = append(items, NewControl(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceName, true))
items = append(items, NewControl(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceVisibility, true))
items = append(items, NewControl(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceBio, true))
items = append(items, NewControl(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceFields, true))
items = append(items, NewControl(p.tutView.tut.Config, p.tutView.tut.Config.Input.PreferenceSave, true))
p.controls.Clear()
for i, item := range items {
if i < len(items)-1 {
p.controls.AddItem(NewControlButton(p.tutView, item), item.Len+1, 0, false)
} else {
p.controls.AddItem(NewControlButton(p.tutView, item), item.Len, 0, false)
}
}
cnf := p.tutView.tut.Config
p.fields.SetSelectedBackgroundColor(cnf.Style.Background)

22
ui/styled_elements.go

@ -26,6 +26,28 @@ func NewTextView(cnf *config.Config) *tview.TextView {
return tw
}
func NewControlView(cnf *config.Config) *tview.Flex {
f := tview.NewFlex().SetDirection(tview.FlexColumn)
f.SetBackgroundColor(cnf.Style.Background)
return f
}
func NewControlButton(tv *TutView, control Control) *tview.Button {
btn := tview.NewButton(control.Label)
btn.SetBackgroundColor(tv.tut.Config.Style.Background)
btn.SetMouseCapture(func(action tview.MouseAction, event *tcell.EventMouse) (tview.MouseAction, *tcell.EventMouse) {
if !btn.InRect(event.Position()) {
return action, event
}
if action != tview.MouseLeftClick {
return action, event
}
tv.tut.App.QueueEvent(control.Click())
return action, nil
})
return btn
}
func NewList(cnf *config.Config) *tview.List {
l := tview.NewList()
l.ShowSecondaryText(false)

2
ui/timeline.go

@ -17,6 +17,7 @@ type Timeline struct {
Feeds []*FeedHolder
FeedFocusIndex int
update chan bool
scrollSleep *scrollSleep
}
func NewTimeline(tv *TutView, update chan bool) *Timeline {
@ -25,6 +26,7 @@ func NewTimeline(tv *TutView, update chan bool) *Timeline {
Feeds: []*FeedHolder{},
update: update,
}
tl.scrollSleep = NewScrollSleep(tl.NextItemFeed, tl.PrevItemFeed)
var nf *Feed
for _, f := range tv.tut.Config.General.Timelines {
switch f.FeedType {

4
ui/tutview.go

@ -12,7 +12,6 @@ import (
"github.com/RasmusLindroth/tut/api"
"github.com/RasmusLindroth/tut/auth"
"github.com/RasmusLindroth/tut/config"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)
@ -55,9 +54,6 @@ type TutView struct {
PreferenceView *PreferenceView
HelpView *HelpView
ModalView *ModalView
mouseX int
mouseY int
mouseEvent *tcell.EventMouse
FileList []string
}

8
ui/view.go

@ -38,10 +38,10 @@ func (tv *TutView) RedrawContent() {
item, err := f.Data.Item(f.List.Text.GetCurrentItem())
if err != nil {
f.Content.Main.SetText("")
f.Content.Controls.SetText("")
f.Content.Controls.Clear()
return
}
DrawItem(tv.tut, item, f.Content.Main, f.Content.Controls, f.Data.Type())
DrawItem(tv, item, f.Content.Main, f.Content.Controls, f.Data.Type())
}
func (tv *TutView) RedrawPoll(poll *mastodon.Poll) {
f := tv.GetCurrentFeed()
@ -59,7 +59,7 @@ func (tv *TutView) RedrawPoll(poll *mastodon.Poll) {
} else {
so.Poll = poll
}
DrawItem(tv.tut, item, f.Content.Main, f.Content.Controls, f.Data.Type())
DrawItem(tv, item, f.Content.Main, f.Content.Controls, f.Data.Type())
}
func (tv *TutView) RedrawControls() {
f := tv.GetCurrentFeed()
@ -67,7 +67,7 @@ func (tv *TutView) RedrawControls() {
if err != nil {
return
}
DrawItemControls(tv.tut, item, f.Content.Controls, f.Data.Type())
DrawItemControls(tv, item, f.Content.Controls, f.Data.Type())
}
func (tv *TutView) SetPage(f PageFocusAt) {

35
ui/voteview.go

@ -2,22 +2,21 @@ package ui
import (
"fmt"
"strings"
"github.com/RasmusLindroth/go-mastodon"
"github.com/RasmusLindroth/tut/config"
"github.com/rivo/tview"
)
type VoteView struct {
tutView *TutView
shared *Shared
View *tview.Flex
textTop *tview.TextView
controls *tview.TextView
list *tview.List
poll *mastodon.Poll
selected []int
tutView *TutView
shared *Shared
View *tview.Flex
textTop *tview.TextView
controls *tview.Flex
list *tview.List
poll *mastodon.Poll
selected []int
scrollSleep *scrollSleep
}
func NewVoteView(tv *TutView) *VoteView {
@ -25,18 +24,26 @@ func NewVoteView(tv *TutView) *VoteView {
tutView: tv,
shared: tv.Shared,
textTop: NewTextView(tv.tut.Config),
controls: NewTextView(tv.tut.Config),
controls: NewControlView(tv.tut.Config),
list: NewList(tv.tut.Config),
}
v.scrollSleep = NewScrollSleep(v.Next, v.Prev)
v.View = voteViewUI(v)
return v
}
func voteViewUI(v *VoteView) *tview.Flex {
var items []string
items = append(items, config.ColorFromKey(v.tutView.tut.Config, v.tutView.tut.Config.Input.VoteSelect, true))
v.controls.SetText(strings.Join(items, " "))
var items []Control
items = append(items, NewControl(v.tutView.tut.Config, v.tutView.tut.Config.Input.VoteSelect, true))
v.controls.Clear()
for i, item := range items {
if i < len(items)-1 {
v.controls.AddItem(NewControlButton(v.tutView, item), item.Len+1, 0, false)
} else {
v.controls.AddItem(NewControlButton(v.tutView, item), item.Len, 0, false)
}
}
r := tview.NewFlex().SetDirection(tview.FlexRow)
if v.tutView.tut.Config.General.TerminalTitle < 2 {

Loading…
Cancel
Save