diff --git a/README.md b/README.md index ac25d88..fcc9aa1 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,9 @@ You can find an updated configuration file in this repo named `config.example.in If there are any new configurations options you can copy them frome that file. ## Install instructions +### Binary releases +Head over to https://github.com/RasmusLindroth/tut/releases + ### Arch or Manjaro? You can find it in the Arch User Repository (AUR). I'm the maintainer there. @@ -90,13 +93,19 @@ go build If you choose to install and want to be able to just run `tut` you will have to add `go/bin` to your `$PATH`. - - -## On my TODO-list: -* Multiple accounts -* Support search -* Support lists -* Better error handling (in other words, don't crash the whole program) +## Flags and commands +``` +Commands: + example-config - creates the default configuration file in the current directory and names it ./config.example.ini + +Flags: + --help -h - prints this message + --version -v - prints the version + --new-user -n - add one more user to tut + --user -u - login directly to user named + Don't use a = between --user and the + If two users are named the same. Use full name like tut@fosstodon.org +``` ## Thanks to * [mattn/go-mastodon](https://github.com/mattn/go-mastodon) - used to make calls to the Mastodon API diff --git a/account.go b/account.go index d61d34a..00115df 100644 --- a/account.go +++ b/account.go @@ -6,21 +6,21 @@ import ( "os" "github.com/mattn/go-mastodon" - "github.com/pelletier/go-toml" + "github.com/pelletier/go-toml/v2" ) -func GetAccounts(filepath string) (AccountData, error) { +func GetAccounts(filepath string) (*AccountData, error) { f, err := os.Open(filepath) if err != nil { - return AccountData{}, err + return &AccountData{}, err } defer f.Close() data, err := ioutil.ReadAll(f) if err != nil { - return AccountData{}, err + return &AccountData{}, err } - accounts := AccountData{} - err = toml.Unmarshal(data, &accounts) + accounts := &AccountData{} + err = toml.Unmarshal(data, accounts) return accounts, err } @@ -60,6 +60,7 @@ func (a *Account) Login() (*mastodon.Client, error) { } client := mastodon.NewClient(config) _, err := client.GetAccountCurrentUser(context.Background()) + return client, err } diff --git a/app.go b/app.go index d8427f8..ca94325 100644 --- a/app.go +++ b/app.go @@ -1,14 +1,54 @@ package main import ( + "context" + "log" + "strings" + "github.com/mattn/go-mastodon" ) type App struct { - UI *UI - Me *mastodon.Account - API *API - Config *Config - HaveAccount bool - FileList []string + UI *UI + Me *mastodon.Account + API *API + Config *Config + FullUsername string + HaveAccount bool + Accounts *AccountData + FileList []string +} + +func (a *App) Login(index int) { + if index >= len(a.Accounts.Accounts) { + log.Fatalln("Tried to login with an account that doesn't exist") + } + acc := a.Accounts.Accounts[index] + client, err := acc.Login() + if err == nil { + a.API.SetClient(client) + a.HaveAccount = true + + me, err := a.API.Client.GetAccountCurrentUser(context.Background()) + if err != nil { + log.Fatalln(err) + } + a.Me = me + if acc.Name == "" { + a.Accounts.Accounts[index].Name = me.Username + + path, _, err := CheckConfig("accounts.toml") + if err != nil { + log.Fatalf("Couldn't open the account file for reading. Error: %v", err) + } + err = a.Accounts.Save(path) + if err != nil { + log.Fatalf("Couldn't update the account file. Error: %v", err) + } + } + + host := strings.TrimPrefix(acc.Server, "https://") + host = strings.TrimPrefix(host, "http://") + a.FullUsername = me.Username + "@" + host + } } diff --git a/authoverlay.go b/authoverlay.go index a912748..e98325e 100644 --- a/authoverlay.go +++ b/authoverlay.go @@ -81,22 +81,19 @@ func (a *AuthOverlay) GotInput() { if err != nil { log.Fatalf("Couldn't open the account file for reading. Error: %v", err) } - ad := AccountData{ - Accounts: []Account{ - { - Server: client.Config.Server, - ClientID: client.Config.ClientID, - ClientSecret: client.Config.ClientSecret, - AccessToken: client.Config.AccessToken, - }, - }, + ad := Account{ + Server: client.Config.Server, + ClientID: client.Config.ClientID, + ClientSecret: client.Config.ClientSecret, + AccessToken: client.Config.AccessToken, } - err = ad.Save(path) + a.app.Accounts.Accounts = append(a.app.Accounts.Accounts, ad) + err = a.app.Accounts.Save(path) if err != nil { log.Fatalf("Couldn't save the account file. Error: %v", err) } - a.app.API.SetClient(client) - a.app.HaveAccount = true + index := len(a.app.Accounts.Accounts) - 1 + a.app.Login(index) a.app.UI.LoggedIn() } } diff --git a/config.go b/config.go index 9e8d55d..905432f 100644 --- a/config.go +++ b/config.go @@ -29,6 +29,7 @@ type GeneralConfig struct { StartTimeline TimelineType NotificationFeed bool QuoteReply bool + CharLimit int } type StyleConfig struct { @@ -236,8 +237,8 @@ func parseGeneral(cfg *ini.File) GeneralConfig { } general.NotificationFeed = cfg.Section("general").Key("notification-feed").MustBool(true) - general.QuoteReply = cfg.Section("general").Key("quote-reply").MustBool(false) + general.CharLimit = cfg.Section("general").Key("char-limit").MustInt(500) return general } @@ -462,6 +463,10 @@ notification-feed=true # default=false quote-reply=false +# If you're on an instance with a custom character limit you can set it here +# default=500 +char-limit=500 + [media] # Your image viewer # default=xdg-open diff --git a/go.mod b/go.mod index 8a4a2c7..67545ab 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/mattn/go-mastodon v0.0.5-0.20210629151305-d39c10ba5e94 github.com/mattn/go-runewidth v0.0.13 // indirect github.com/microcosm-cc/bluemonday v1.0.15 - github.com/pelletier/go-toml v1.9.3 + github.com/pelletier/go-toml/v2 v2.0.0-beta.3 github.com/rivo/tview v0.0.0-20210624155130-5f8430624688 github.com/rivo/uniseg v0.2.0 github.com/smartystreets/goconvey v1.6.4 // indirect diff --git a/go.sum b/go.sum index c318496..5c368b3 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,8 @@ github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= @@ -54,8 +56,10 @@ github.com/microcosm-cc/bluemonday v1.0.15 h1:J4uN+qPng9rvkBZBoBb8YGR+ijuklIMpSO github.com/microcosm-cc/bluemonday v1.0.15/go.mod h1:ZLvAzeakRwrGnzQEvstVzVt3ZpqOF2+sdFr0Om+ce30= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= -github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= -github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.0-beta.3 h1:PNCTU4naEJ8mKal97P3A2qDU74QRQGlv4FXiL1XDqi4= +github.com/pelletier/go-toml/v2 v2.0.0-beta.3/go.mod h1:aNseLYu/uKskg0zpr/kbr2z8yGuWtotWf/0BpGIAL2Y= +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-20210624155130-5f8430624688 h1:ljIaK7yl7pN/wBgNy6g86tzI9kNDldJT1dzo7aqr8Yk= github.com/rivo/tview v0.0.0-20210624155130-5f8430624688/go.mod h1:IxQujbYMAh4trWr0Dwa8jfciForjVmxyHpskZX6aydQ= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -65,6 +69,9 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykE github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.1-0.20210427113832-6241f9ab9942 h1:t0lM6y/M5IiUZyvbBTcngso8SZEZICH7is9B6g/obVU= +github.com/stretchr/testify v1.7.1-0.20210427113832-6241f9ab9942/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG04SN9W+iWHCRyHqlVYILiSXziwk= 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= @@ -102,5 +109,9 @@ golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index f4ca41d..9e1fd02 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,6 @@ package main import ( - "context" "fmt" "log" "os" @@ -10,18 +9,26 @@ import ( "github.com/gdamore/tcell/v2" ) -const version string = "0.0.24" +const version string = "0.0.25" func main() { - + newUser := false + selectedUser := "" if len(os.Args) > 1 { switch os.Args[1] { case "example-config": CreateDefaultConfig("./config.example.ini") os.Exit(0) - case "--help": - fallthrough - case "-h": + case "--new-user", "-n": + newUser = true + case "--user", "-u": + if len(os.Args) > 2 { + name := os.Args[2] + selectedUser = strings.TrimSpace(name) + } else { + log.Fatalln("--user/-u must be followed by a user name. Like -u tut") + } + case "--help", "-h": fmt.Print("tut - a TUI for Mastodon with vim inspired keys.\n\n") fmt.Print("Usage:\n\n") fmt.Print("\tTo run the program you just have to write tut\n\n") @@ -31,7 +38,11 @@ func main() { fmt.Print("Flags:\n\n") fmt.Print("\t--help -h - prints this message\n") - fmt.Print("\t--version -v - prints the version\n\n") + fmt.Print("\t--version -v - prints the version\n") + fmt.Print("\t--new-user -n - add one more user to tut\n") + fmt.Print("\t--user -u - login directly to user namde \n") + fmt.Print("\t\tDon't use a = between --user and the \n") + fmt.Print("\t\tIf two users are named the same. Use full name like tut@fosstodon.org\n\n") fmt.Print("Configuration:\n\n") fmt.Printf("\tThe config is located in XDG_CONFIG_HOME/tut/config.ini which usally equals to ~/.config/tut/config.ini.\n") @@ -41,9 +52,7 @@ func main() { fmt.Printf("\t@rasmus@mastodon.acc.sunet.se\n\trasmus@lindroth.xyz\n") fmt.Printf("\thttps://github.com/RasmusLindroth/tut\n") os.Exit(0) - case "--version": - fallthrough - case "-v": + case "--version", "-v": fmt.Printf("tut version %s\n\n", version) fmt.Printf("https://github.com/RasmusLindroth/tut\n") os.Exit(0) @@ -77,6 +86,7 @@ func main() { API: &API{}, HaveAccount: false, Config: &config, + Accounts: &AccountData{}, } app.UI = NewUI(app) @@ -90,29 +100,44 @@ func main() { } if exists { - accounts, err := GetAccounts(path) + app.Accounts, err = GetAccounts(path) if err != nil { log.Fatalln( fmt.Sprintf("Couldn't access accounts.toml. Error: %v", err), ) } - if len(accounts.Accounts) > 0 { - a := accounts.Accounts[0] - client, err := a.Login() - if err == nil { - app.API.SetClient(client) - app.HaveAccount = true + if len(app.Accounts.Accounts) == 1 && !newUser { + app.Login(0) + } + } - me, err := app.API.Client.GetAccountCurrentUser(context.Background()) - if err != nil { - log.Fatalln(err) + if len(app.Accounts.Accounts) > 1 && !newUser { + if selectedUser != "" { + useHost := false + found := false + if strings.Contains(selectedUser, "@") { + useHost = true + } + for i, acc := range app.Accounts.Accounts { + accName := acc.Name + if useHost { + host := strings.TrimPrefix(acc.Server, "https://") + host = strings.TrimPrefix(host, "http://") + accName += "@" + host } - app.Me = me + if accName == selectedUser { + app.Login(i) + app.UI.LoggedIn() + found = true + } + } + if found == false { + log.Fatalf("Couldn't find a user named %s. Try again", selectedUser) } + } else { + app.UI.SetFocus(UserSelectFocus) } - } - - if !app.HaveAccount { + } else if !app.HaveAccount || newUser { app.UI.SetFocus(AuthOverlayFocus) } else { app.UI.LoggedIn() @@ -122,11 +147,16 @@ func main() { app.UI.Root.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { if !app.HaveAccount { - if event.Key() == tcell.KeyRune { - switch event.Rune() { + if app.UI.Focus == UserSelectFocus { + app.UI.UserSelectOverlay.InputHandler(event) + return nil + } else { + if event.Key() == tcell.KeyRune { + switch event.Rune() { + } } + return event } - return event } if app.UI.Focus == LinkOverlayFocus { @@ -257,7 +287,6 @@ func main() { } return app.UI.StatusView.Input(event) } - return event }) @@ -265,11 +294,6 @@ func main() { app.UI.MediaOverlay.InputField.HandleChanges, ) - app.UI.CmdBar.Input.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { - - return event - }) - app.UI.CmdBar.Input.SetAutocompleteFunc(func(currentText string) (entries []string) { words := strings.Split(":blocking,:boosts,:bookmarks,:compose,:favorites,:muting,:profile,:saved,:tag,:timeline,:tl,:user,:quit,:q", ",") if currentText == "" { diff --git a/messagebox.go b/messagebox.go index 3968a73..0ca016e 100644 --- a/messagebox.go +++ b/messagebox.go @@ -114,13 +114,6 @@ func (m *MessageBox) Down() { } func (m *MessageBox) Post() { - charsLeft := m.TootLength() - - if charsLeft < 0 { - m.app.UI.CmdBar.ShowError(fmt.Sprintf("Reached char limit, make your toot shorter. Length %d\n", charsLeft)) - return - } - toot := m.currentToot send := mastodon.Toot{ Status: strings.TrimSpace(toot.Text), @@ -172,7 +165,7 @@ func (m *MessageBox) TootLength() int { if m.currentToot.Sensitive { totalCount += spoilerCount } - charsLeft := 500 - totalCount + charsLeft := m.app.Config.General.CharLimit - totalCount return charsLeft } diff --git a/ui.go b/ui.go index 44f4b1e..2f29584 100644 --- a/ui.go +++ b/ui.go @@ -22,6 +22,7 @@ const ( LinkOverlayFocus VisibilityOverlayFocus AuthOverlayFocus + UserSelectFocus ) func NewUI(app *App) *UI { @@ -56,6 +57,7 @@ func (ui *UI) Init() { ui.LinkOverlay = NewLinkOverlay(ui.app) ui.VisibilityOverlay = NewVisibilityOverlay(ui.app) ui.AuthOverlay = NewAuthOverlay(ui.app) + ui.UserSelectOverlay = NewUserSelectOverlay(ui.app) ui.MediaOverlay = NewMediaOverlay(ui.app) ui.Pages.SetBackgroundColor(ui.app.Config.Style.Background) @@ -121,7 +123,17 @@ func (ui *UI) Init() { AddItem(nil, 0, 1, false), 0, 6, true). AddItem(nil, 0, 1, false), true, false) - + ui.Pages.AddPage("userselect", + tview.NewFlex(). + AddItem(nil, 0, 1, false). + AddItem(tview.NewFlex().SetDirection(tview.FlexRow). + AddItem(nil, 0, 1, false). + AddItem(ui.UserSelectOverlay.Flex.SetDirection(tview.FlexRow). + AddItem(ui.UserSelectOverlay.Text, 2, 1, false). + AddItem(ui.UserSelectOverlay.List, 0, 9, true), 0, 9, true). + AddItem(nil, 0, 1, false), 0, 6, true). + AddItem(nil, 0, 1, false), + true, false) ui.Pages.AddPage("media", tview.NewFlex().AddItem(nil, 0, 1, false). AddItem(tview.NewFlex().SetDirection(tview.FlexRow). AddItem(nil, 0, 1, false). @@ -151,6 +163,7 @@ type UI struct { LinkOverlay *LinkOverlay VisibilityOverlay *VisibilityOverlay AuthOverlay *AuthOverlay + UserSelectOverlay *UserSelectOverlay MediaOverlay *MediaView Timeline TimelineType StatusView *StatusView @@ -195,6 +208,10 @@ func (ui *UI) SetFocus(f FocusAt) { case AuthOverlayFocus: ui.Pages.ShowPage("login") ui.FocusAt(ui.AuthOverlay.Input, "-- LOGIN --") + case UserSelectFocus: + ui.UserSelectOverlay.Draw() + ui.Pages.ShowPage("userselect") + ui.FocusAt(ui.UserSelectOverlay.List, "-- SELECT USER --") case NotificationPaneFocus: ui.Pages.SwitchToPage("main") ui.FocusAt(nil, "-- NOTIFICATIONS --") @@ -294,7 +311,7 @@ func (ui *UI) SetTopText(s string) { if s == "" { ui.Top.Text.SetText("tut") } else { - ui.Top.Text.SetText(fmt.Sprintf("tut - %s", s)) + ui.Top.Text.SetText(fmt.Sprintf("tut - %s - %s", s, ui.app.FullUsername)) } } diff --git a/userselectoverlay.go b/userselectoverlay.go new file mode 100644 index 0000000..2051b6f --- /dev/null +++ b/userselectoverlay.go @@ -0,0 +1,87 @@ +package main + +import ( + "fmt" + + "github.com/gdamore/tcell/v2" + "github.com/rivo/tview" +) + +func NewUserSelectOverlay(app *App) *UserSelectOverlay { + u := &UserSelectOverlay{ + app: app, + Flex: tview.NewFlex(), + List: tview.NewList(), + Text: tview.NewTextView(), + } + + u.Flex.SetBackgroundColor(app.Config.Style.Background) + u.List.SetMainTextColor(app.Config.Style.Text) + u.List.SetBackgroundColor(app.Config.Style.Background) + u.List.SetSelectedTextColor(app.Config.Style.ListSelectedText) + u.List.SetSelectedBackgroundColor(app.Config.Style.ListSelectedBackground) + u.List.ShowSecondaryText(false) + u.List.SetHighlightFullLine(true) + u.Text.SetBackgroundColor(app.Config.Style.Background) + u.Text.SetTextColor(app.Config.Style.Text) + u.Flex.SetDrawFunc(app.Config.ClearContent) + return u +} + +type UserSelectOverlay struct { + app *App + Flex *tview.Flex + List *tview.List + Text *tview.TextView +} + +func (u *UserSelectOverlay) Prev() { + index := u.List.GetCurrentItem() + if index-1 >= 0 { + u.List.SetCurrentItem(index - 1) + } +} + +func (u *UserSelectOverlay) Next() { + index := u.List.GetCurrentItem() + if index+1 < u.List.GetItemCount() { + u.List.SetCurrentItem(index + 1) + } +} +func (u *UserSelectOverlay) Done() { + index := u.List.GetCurrentItem() + u.app.Login(index) + u.app.UI.LoggedIn() +} + +func (u *UserSelectOverlay) InputHandler(event *tcell.EventKey) { + if event.Key() == tcell.KeyRune { + switch event.Rune() { + case 'j', 'J': + u.Next() + case 'k', 'K': + u.Prev() + case 'q', 'Q': + u.app.UI.Root.Stop() + } + } else { + switch event.Key() { + case tcell.KeyEnter: + u.Done() + case tcell.KeyUp: + u.Prev() + case tcell.KeyDown: + u.Next() + } + } +} + +func (u *UserSelectOverlay) Draw() { + u.Text.SetText("Select the user you want to use for this session by pressing Enter.") + if len(u.app.Accounts.Accounts) > 0 { + for i := 0; i < len(u.app.Accounts.Accounts); i++ { + acc := u.app.Accounts.Accounts[i] + u.List.AddItem(fmt.Sprintf("%s - %s", acc.Name, acc.Server), "", 0, nil) + } + } +}