diff --git a/README.md b/README.md index 3865c30..d4a3202 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ You can find Linux binaries under [releases](https://github.com/RasmusLindroth/t * `:saved` alias for bookmarks * `:tag` followed by the hashtag e.g. `:tag linux` * `:user` followed by a username e.g. `:user rasmus` to narrow a search include -the instance like this `:user rasmus@mastodon.acc.sunet.se`. +* `:window` switch window by index (zero indexed) e.g. `:window 0` for the first window. Keys without description in tut * `c` = Compose a new toot diff --git a/api/feed.go b/api/feed.go index 7fcd906..d8776dd 100644 --- a/api/feed.go +++ b/api/feed.go @@ -8,14 +8,14 @@ import ( type TimelineType uint -func (ac *AccountClient) GetTimeline(pg *mastodon.Pagination) ([]Item, error) { +func (ac *AccountClient) getStatusSimilar(fn func() ([]*mastodon.Status, error), filter string) ([]Item, error) { var items []Item - statuses, err := ac.Client.GetTimelineHome(context.Background(), pg) + statuses, err := fn() if err != nil { return items, err } for _, s := range statuses { - item, filtered := NewStatusItem(s, ac.Filters, "home") + item, filtered := NewStatusItem(s, ac.Filters, filter) if !filtered { items = append(items, item) } @@ -23,36 +23,55 @@ func (ac *AccountClient) GetTimeline(pg *mastodon.Pagination) ([]Item, error) { return items, nil } -func (ac *AccountClient) GetTimelineFederated(pg *mastodon.Pagination) ([]Item, error) { +func (ac *AccountClient) getUserSimilar(fn func() ([]*mastodon.Account, error)) ([]Item, error) { var items []Item - statuses, err := ac.Client.GetTimelinePublic(context.Background(), false, pg) + users, err := fn() if err != nil { return items, err } - for _, s := range statuses { - item, filtered := NewStatusItem(s, ac.Filters, "public") - if !filtered { - items = append(items, item) - } + ids := []string{} + for _, u := range users { + ids = append(ids, string(u.ID)) } - return items, nil -} - -func (ac *AccountClient) GetTimelineLocal(pg *mastodon.Pagination) ([]Item, error) { - var items []Item - statuses, err := ac.Client.GetTimelinePublic(context.Background(), true, pg) + rel, err := ac.Client.GetAccountRelationships(context.Background(), ids) if err != nil { return items, err } - for _, s := range statuses { - item, filtered := NewStatusItem(s, ac.Filters, "public") - if !filtered { - items = append(items, item) + for _, u := range users { + for _, r := range rel { + if u.ID == r.ID { + items = append(items, NewUserItem(&User{ + Data: u, + Relation: r, + }, false)) + break + } } } return items, nil } +func (ac *AccountClient) GetTimeline(pg *mastodon.Pagination) ([]Item, error) { + fn := func() ([]*mastodon.Status, error) { + return ac.Client.GetTimelineHome(context.Background(), pg) + } + return ac.getStatusSimilar(fn, "home") +} + +func (ac *AccountClient) GetTimelineFederated(pg *mastodon.Pagination) ([]Item, error) { + fn := func() ([]*mastodon.Status, error) { + return ac.Client.GetTimelinePublic(context.Background(), false, pg) + } + return ac.getStatusSimilar(fn, "public") +} + +func (ac *AccountClient) GetTimelineLocal(pg *mastodon.Pagination) ([]Item, error) { + fn := func() ([]*mastodon.Status, error) { + return ac.Client.GetTimelinePublic(context.Background(), true, pg) + } + return ac.getStatusSimilar(fn, "public") +} + func (ac *AccountClient) GetNotifications(pg *mastodon.Pagination) ([]Item, error) { var items []Item notifications, err := ac.Client.GetNotifications(context.Background(), pg) @@ -109,33 +128,17 @@ func (ac *AccountClient) GetThread(status *mastodon.Status) ([]Item, int, error) } func (ac *AccountClient) GetFavorites(pg *mastodon.Pagination) ([]Item, error) { - var items []Item - statuses, err := ac.Client.GetFavourites(context.Background(), pg) - if err != nil { - return items, err + fn := func() ([]*mastodon.Status, error) { + return ac.Client.GetFavourites(context.Background(), pg) } - for _, s := range statuses { - item, filtered := NewStatusItem(s, ac.Filters, "home") - if !filtered { - items = append(items, item) - } - } - return items, nil + return ac.getStatusSimilar(fn, "home") } func (ac *AccountClient) GetBookmarks(pg *mastodon.Pagination) ([]Item, error) { - var items []Item - statuses, err := ac.Client.GetBookmarks(context.Background(), pg) - if err != nil { - return items, err + fn := func() ([]*mastodon.Status, error) { + return ac.Client.GetBookmarks(context.Background(), pg) } - for _, s := range statuses { - item, filtered := NewStatusItem(s, ac.Filters, "home") - if !filtered { - items = append(items, item) - } - } - return items, nil + return ac.getStatusSimilar(fn, "home") } func (ac *AccountClient) GetConversations(pg *mastodon.Pagination) ([]Item, error) { @@ -230,34 +233,6 @@ func (ac *AccountClient) GetFollowRequests(pg *mastodon.Pagination) ([]Item, err return ac.getUserSimilar(fn) } -func (ac *AccountClient) getUserSimilar(fn func() ([]*mastodon.Account, error)) ([]Item, error) { - var items []Item - users, err := fn() - if err != nil { - return items, err - } - ids := []string{} - for _, u := range users { - ids = append(ids, string(u.ID)) - } - rel, err := ac.Client.GetAccountRelationships(context.Background(), ids) - if err != nil { - return items, err - } - for _, u := range users { - for _, r := range rel { - if u.ID == r.ID { - items = append(items, NewUserItem(&User{ - Data: u, - Relation: r, - }, false)) - break - } - } - } - return items, nil -} - func (ac *AccountClient) GetUser(pg *mastodon.Pagination, id mastodon.ID) ([]Item, error) { var items []Item statuses, err := ac.Client.GetAccountStatuses(context.Background(), id, pg) @@ -301,16 +276,8 @@ func (ac *AccountClient) GetListStatuses(pg *mastodon.Pagination, id mastodon.ID } func (ac *AccountClient) GetTag(pg *mastodon.Pagination, search string) ([]Item, error) { - var items []Item - statuses, err := ac.Client.GetTimelineHashtag(context.Background(), search, false, pg) - if err != nil { - return items, err + fn := func() ([]*mastodon.Status, error) { + return ac.Client.GetTimelineHashtag(context.Background(), search, false, pg) } - for _, s := range statuses { - item, filtered := NewStatusItem(s, ac.Filters, "public") - if !filtered { - items = append(items, item) - } - } - return items, nil + return ac.getStatusSimilar(fn, "public") } diff --git a/config/config.go b/config/config.go index a5654ab..feaf378 100644 --- a/config/config.go +++ b/config/config.go @@ -70,6 +70,7 @@ const ( LeaderLists LeaderTag LeaderUser + LeaderWindow ) type Timeline struct { @@ -360,6 +361,7 @@ type Input struct { ComposePost Key ComposeToggleContentWarning Key ComposeVisibility Key + ComposePoll Key MediaDelete Key MediaEditDesc Key @@ -367,6 +369,12 @@ type Input struct { VoteVote Key VoteSelect Key + + PollAdd Key + PollEdit Key + PollDelete Key + PollMultiToggle Key + PollExpiration Key } func parseColor(input string, def string, xrdb map[string]string) tcell.Color { @@ -661,6 +669,9 @@ func parseGeneral(cfg *ini.File) General { case "tag": la.Command = LeaderTag la.Subaction = subaction + case "window": + la.Command = LeaderWindow + la.Subaction = subaction default: fmt.Printf("leader-action %s is invalid\n", parts[0]) os.Exit(1) @@ -1025,6 +1036,7 @@ func parseInput(cfg *ini.File) Input { ComposePost: inputStrOrErr([]string{"\"[P]ost\"", "'p'", "'P'"}, false), ComposeToggleContentWarning: inputStrOrErr([]string{"\"[T]oggle CW\"", "'t'", "'T'"}, false), ComposeVisibility: inputStrOrErr([]string{"\"[V]isibility\"", "'v'", "'V'"}, false), + ComposePoll: inputStrOrErr([]string{"\"P[O]ll\"", "'o'", "'O'"}, false), MediaDelete: inputStrOrErr([]string{"\"[D]elete\"", "'d'", "'D'"}, false), MediaEditDesc: inputStrOrErr([]string{"\"[E]dit desc\"", "'e'", "'E'"}, false), @@ -1032,6 +1044,12 @@ func parseInput(cfg *ini.File) Input { VoteVote: inputStrOrErr([]string{"\"[V]ote\"", "'v'", "'V'"}, false), VoteSelect: inputStrOrErr([]string{"\"[Enter] to select\"", "' '", "\"Enter\""}, false), + + PollAdd: inputStrOrErr([]string{"\"[A]dd\"", "'a'", "'A'"}, false), + PollEdit: inputStrOrErr([]string{"\"[E]dit\"", "'e'", "'E'"}, false), + PollDelete: inputStrOrErr([]string{"\"[D]elete\"", "'d'", "'D'"}, false), + PollMultiToggle: inputStrOrErr([]string{"\"Toggle [M]ultiple\"", "'m'", "'M'"}, false), + PollExpiration: inputStrOrErr([]string{"\"E[X]pires\"", "'x'", "'X'"}, false), } ic.GlobalDown = inputOrErr(cfg, "global-down", false, ic.GlobalDown) ic.GlobalUp = inputOrErr(cfg, "global-up", false, ic.GlobalUp) @@ -1082,6 +1100,7 @@ func parseInput(cfg *ini.File) Input { ic.ComposePost = inputOrErr(cfg, "compose-post", false, ic.ComposePost) ic.ComposeToggleContentWarning = inputOrErr(cfg, "compose-toggle-content-warning", false, ic.ComposeToggleContentWarning) ic.ComposeVisibility = inputOrErr(cfg, "compose-visibility", false, ic.ComposeVisibility) + ic.ComposePoll = inputOrErr(cfg, "compose-poll", false, ic.ComposePoll) ic.MediaDelete = inputOrErr(cfg, "media-delete", false, ic.MediaDelete) ic.MediaEditDesc = inputOrErr(cfg, "media-edit-desc", false, ic.MediaEditDesc) @@ -1089,6 +1108,12 @@ func parseInput(cfg *ini.File) Input { ic.VoteVote = inputOrErr(cfg, "vote-vote", false, ic.VoteVote) ic.VoteSelect = inputOrErr(cfg, "vote-select", false, ic.VoteSelect) + + ic.PollAdd = inputOrErr(cfg, "poll-add", false, ic.PollAdd) + ic.PollEdit = inputOrErr(cfg, "poll-edit", false, ic.PollEdit) + ic.PollDelete = inputOrErr(cfg, "poll-delete", false, ic.PollDelete) + ic.PollMultiToggle = inputOrErr(cfg, "poll-multi-toggle", false, ic.PollMultiToggle) + ic.PollExpiration = inputOrErr(cfg, "poll-expiration", false, ic.PollExpiration) return ic } diff --git a/config/default_config.go b/config/default_config.go index adf561c..57d2507 100644 --- a/config/default_config.go +++ b/config/default_config.go @@ -139,19 +139,24 @@ leader-timeout=1000 # # Available commands: home, direct, local, federated, compose, blocking, # bookmarks, saved, favorited, boosts, favorites, following, followers, muting, -# profile, notifications, lists, tag +# profile, notifications, lists, tag, window # # 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 # "fav", the one with "f" will always run and "fav" will never run. Tag is # special as you need to add the tag after, see the example below. # +# Window is also special as it's a shortcut for switching between the timelines +# you've set under general and they are zero indexed. window 0 = your first +# timeline, window 1 = your second and so on. +# # Some examples: # leader-action=local,lo # leader-action=lists,li # leader-action=federated,fed # leader-action=direct,d # leader-action=tag linux,tl +# leader-action=window 0,h # @@ -593,6 +598,10 @@ compose-toggle-content-warning="[T]oggle CW",'t','T' # default="[V]isibility",'v','V' compose-visibility="[V]isibility",'v','V' +# Switch to creating a poll +# default="P[O]ll",'o','O' +compose-poll="P[O]ll",'o','O' + # Delete media file # default="[D]elete",'d','D' media-delete="[D]elete",'d','D' @@ -612,4 +621,24 @@ vote-vote="[V]ote",'v','V' # Select item to vote on # default="[Enter] to select",' ', "Enter" vote-select="[Enter] to select",' ', "Enter" + +# Add a new poll option +# default="[A]dd",'a','A' +poll-add="[A]dd",'a','A' + +# Edit a poll option +# default="[E]dit",'e','E' +poll-edit="[E]dit",'e','E' + +# Delete a poll option +# default="[D]elete",'d','D' +poll-delete="[D]elete",'d','D' + +# Toggle voting on multiple options +# default="Toggle [M]ultiple",'m','M' +poll-multi-toggle="Toggle [M]ultiple",'m','M' + +# Change the expiration of poll +# default="E[X]pires",'x','X' +poll-expiration="E[X]pires",'x','X' ` diff --git a/feed/feed.go b/feed/feed.go index 1a9ff16..e25329a 100644 --- a/feed/feed.go +++ b/feed/feed.go @@ -598,18 +598,22 @@ func (f *Feed) startStreamNotification(rec *api.Receiver, timeline string, err e }() } -func NewTimelineHome(ac *api.AccountClient) *Feed { - feed := &Feed{ +func newFeed(ac *api.AccountClient, ft FeedType) *Feed { + return &Feed{ accountClient: ac, - feedType: TimelineHome, items: make([]api.Item, 0), + feedType: ft, + loadNewer: func() {}, loadOlder: func() {}, apiData: &api.RequestData{}, Update: make(chan DesktopNotificationType, 1), loadingNewer: &LoadingLock{}, loadingOlder: &LoadingLock{}, } +} +func NewTimelineHome(ac *api.AccountClient) *Feed { + feed := newFeed(ac, TimelineHome) feed.loadNewer = func() { feed.normalNewer(feed.accountClient.GetTimeline) } feed.loadOlder = func() { feed.normalOlder(feed.accountClient.GetTimeline) } feed.startStream(feed.accountClient.NewHomeStream()) @@ -619,17 +623,7 @@ func NewTimelineHome(ac *api.AccountClient) *Feed { } func NewTimelineFederated(ac *api.AccountClient) *Feed { - feed := &Feed{ - accountClient: ac, - feedType: TimelineFederated, - items: make([]api.Item, 0), - loadOlder: func() {}, - apiData: &api.RequestData{}, - Update: make(chan DesktopNotificationType, 1), - loadingNewer: &LoadingLock{}, - loadingOlder: &LoadingLock{}, - } - + feed := newFeed(ac, TimelineFederated) feed.loadNewer = func() { feed.normalNewer(feed.accountClient.GetTimelineFederated) } feed.loadOlder = func() { feed.normalOlder(feed.accountClient.GetTimelineFederated) } feed.startStream(feed.accountClient.NewFederatedStream()) @@ -639,17 +633,7 @@ func NewTimelineFederated(ac *api.AccountClient) *Feed { } func NewTimelineLocal(ac *api.AccountClient) *Feed { - feed := &Feed{ - accountClient: ac, - feedType: TimelineLocal, - items: make([]api.Item, 0), - loadOlder: func() {}, - apiData: &api.RequestData{}, - Update: make(chan DesktopNotificationType, 1), - loadingNewer: &LoadingLock{}, - loadingOlder: &LoadingLock{}, - } - + feed := newFeed(ac, TimelineLocal) feed.loadNewer = func() { feed.normalNewer(feed.accountClient.GetTimelineLocal) } feed.loadOlder = func() { feed.normalOlder(feed.accountClient.GetTimelineLocal) } feed.startStream(feed.accountClient.NewLocalStream()) @@ -659,17 +643,7 @@ func NewTimelineLocal(ac *api.AccountClient) *Feed { } func NewConversations(ac *api.AccountClient) *Feed { - feed := &Feed{ - accountClient: ac, - feedType: Conversations, - items: make([]api.Item, 0), - loadOlder: func() {}, - apiData: &api.RequestData{}, - Update: make(chan DesktopNotificationType, 1), - loadingNewer: &LoadingLock{}, - loadingOlder: &LoadingLock{}, - } - + feed := newFeed(ac, Conversations) feed.loadNewer = func() { feed.normalNewer(feed.accountClient.GetConversations) } feed.loadOlder = func() { feed.normalOlder(feed.accountClient.GetConversations) } feed.startStream(feed.accountClient.NewDirectStream()) @@ -679,17 +653,7 @@ func NewConversations(ac *api.AccountClient) *Feed { } func NewNotifications(ac *api.AccountClient) *Feed { - feed := &Feed{ - accountClient: ac, - feedType: Notification, - items: make([]api.Item, 0), - loadOlder: func() {}, - apiData: &api.RequestData{}, - Update: make(chan DesktopNotificationType, 1), - loadingNewer: &LoadingLock{}, - loadingOlder: &LoadingLock{}, - } - + feed := newFeed(ac, Notification) feed.loadNewer = func() { feed.normalNewer(feed.accountClient.GetNotifications) } feed.loadOlder = func() { feed.normalOlder(feed.accountClient.GetNotifications) } feed.startStreamNotification(feed.accountClient.NewHomeStream()) @@ -699,16 +663,7 @@ func NewNotifications(ac *api.AccountClient) *Feed { } func NewFavorites(ac *api.AccountClient) *Feed { - feed := &Feed{ - accountClient: ac, - feedType: Favorited, - items: make([]api.Item, 0), - apiData: &api.RequestData{}, - Update: make(chan DesktopNotificationType, 1), - loadingNewer: &LoadingLock{}, - loadingOlder: &LoadingLock{}, - } - + feed := newFeed(ac, Favorited) feed.loadNewer = func() { feed.linkNewer(feed.accountClient.GetFavorites) } feed.loadOlder = func() { feed.linkOlder(feed.accountClient.GetFavorites) } @@ -716,16 +671,7 @@ func NewFavorites(ac *api.AccountClient) *Feed { } func NewBookmarks(ac *api.AccountClient) *Feed { - feed := &Feed{ - accountClient: ac, - feedType: Saved, - items: make([]api.Item, 0), - apiData: &api.RequestData{}, - Update: make(chan DesktopNotificationType, 1), - loadingNewer: &LoadingLock{}, - loadingOlder: &LoadingLock{}, - } - + feed := newFeed(ac, Saved) feed.loadNewer = func() { feed.linkNewer(feed.accountClient.GetBookmarks) } feed.loadOlder = func() { feed.linkOlder(feed.accountClient.GetBookmarks) } @@ -733,35 +679,16 @@ func NewBookmarks(ac *api.AccountClient) *Feed { } func NewUserSearch(ac *api.AccountClient, search string) *Feed { - feed := &Feed{ - accountClient: ac, - feedType: UserList, - items: make([]api.Item, 0), - loadOlder: func() {}, - apiData: &api.RequestData{}, - Update: make(chan DesktopNotificationType, 1), - name: search, - loadingNewer: &LoadingLock{}, - loadingOlder: &LoadingLock{}, - } - + feed := newFeed(ac, UserList) + feed.name = search feed.loadNewer = func() { feed.singleNewerSearch(feed.accountClient.GetUsers, search) } return feed } func NewUserProfile(ac *api.AccountClient, user *api.User) *Feed { - feed := &Feed{ - accountClient: ac, - feedType: User, - items: make([]api.Item, 0), - loadOlder: func() {}, - apiData: &api.RequestData{}, - Update: make(chan DesktopNotificationType, 1), - name: user.Data.Acct, - loadingNewer: &LoadingLock{}, - loadingOlder: &LoadingLock{}, - } + feed := newFeed(ac, User) + feed.name = user.Data.Acct feed.items = append(feed.items, api.NewUserItem(user, true)) feed.loadNewer = func() { feed.normalNewerUser(feed.accountClient.GetUser, user.Data.ID) } feed.loadOlder = func() { feed.normalOlderUser(feed.accountClient.GetUser, user.Data.ID) } @@ -770,35 +697,15 @@ func NewUserProfile(ac *api.AccountClient, user *api.User) *Feed { } func NewThread(ac *api.AccountClient, status *mastodon.Status) *Feed { - feed := &Feed{ - accountClient: ac, - feedType: Thread, - items: make([]api.Item, 0), - loadOlder: func() {}, - apiData: &api.RequestData{}, - Update: make(chan DesktopNotificationType, 1), - loadingNewer: &LoadingLock{}, - loadingOlder: &LoadingLock{}, - } - + feed := newFeed(ac, Thread) feed.loadNewer = func() { feed.singleThread(feed.accountClient.GetThread, status) } return feed } func NewTag(ac *api.AccountClient, search string) *Feed { - feed := &Feed{ - accountClient: ac, - feedType: Tag, - items: make([]api.Item, 0), - loadOlder: func() {}, - apiData: &api.RequestData{}, - Update: make(chan DesktopNotificationType, 1), - name: search, - loadingNewer: &LoadingLock{}, - loadingOlder: &LoadingLock{}, - } - + feed := newFeed(ac, Tag) + feed.name = search feed.loadNewer = func() { feed.newerSearchPG(feed.accountClient.GetTag, search) } feed.loadOlder = func() { feed.olderSearchPG(feed.accountClient.GetTag, search) } feed.startStream(feed.accountClient.NewTagStream(search)) @@ -808,16 +715,7 @@ func NewTag(ac *api.AccountClient, search string) *Feed { } func NewListList(ac *api.AccountClient) *Feed { - feed := &Feed{ - accountClient: ac, - feedType: Lists, - items: make([]api.Item, 0), - loadOlder: func() {}, - apiData: &api.RequestData{}, - Update: make(chan DesktopNotificationType, 1), - loadingNewer: &LoadingLock{}, - loadingOlder: &LoadingLock{}, - } + feed := newFeed(ac, Lists) once := true feed.loadNewer = func() { if once { @@ -830,17 +728,8 @@ func NewListList(ac *api.AccountClient) *Feed { } func NewList(ac *api.AccountClient, list *mastodon.List) *Feed { - feed := &Feed{ - accountClient: ac, - feedType: List, - items: make([]api.Item, 0), - loadOlder: func() {}, - apiData: &api.RequestData{}, - Update: make(chan DesktopNotificationType, 1), - name: list.Title, - loadingNewer: &LoadingLock{}, - loadingOlder: &LoadingLock{}, - } + feed := newFeed(ac, List) + feed.name = list.Title feed.loadNewer = func() { feed.normalNewerID(feed.accountClient.GetListStatuses, list.ID) } feed.loadOlder = func() { feed.normalOlderID(feed.accountClient.GetListStatuses, list.ID) } feed.startStream(feed.accountClient.NewListStream(list.ID)) @@ -850,17 +739,7 @@ func NewList(ac *api.AccountClient, list *mastodon.List) *Feed { } func NewFavoritesStatus(ac *api.AccountClient, id mastodon.ID) *Feed { - feed := &Feed{ - accountClient: ac, - feedType: Favorites, - items: make([]api.Item, 0), - apiData: &api.RequestData{}, - Update: make(chan DesktopNotificationType, 1), - loadOlder: func() {}, - loadingNewer: &LoadingLock{}, - loadingOlder: &LoadingLock{}, - } - + feed := newFeed(ac, Favorites) once := true feed.loadNewer = func() { if once { @@ -873,17 +752,7 @@ func NewFavoritesStatus(ac *api.AccountClient, id mastodon.ID) *Feed { } func NewBoosts(ac *api.AccountClient, id mastodon.ID) *Feed { - feed := &Feed{ - accountClient: ac, - feedType: Boosts, - items: make([]api.Item, 0), - apiData: &api.RequestData{}, - Update: make(chan DesktopNotificationType, 1), - loadOlder: func() {}, - loadingNewer: &LoadingLock{}, - loadingOlder: &LoadingLock{}, - } - + feed := newFeed(ac, Boosts) once := true feed.loadNewer = func() { if once { @@ -896,16 +765,7 @@ func NewBoosts(ac *api.AccountClient, id mastodon.ID) *Feed { } func NewFollowers(ac *api.AccountClient, id mastodon.ID) *Feed { - feed := &Feed{ - accountClient: ac, - feedType: Followers, - items: make([]api.Item, 0), - apiData: &api.RequestData{}, - Update: make(chan DesktopNotificationType, 1), - loadingNewer: &LoadingLock{}, - loadingOlder: &LoadingLock{}, - } - + feed := newFeed(ac, Followers) once := true feed.loadNewer = func() { if once { @@ -919,16 +779,7 @@ func NewFollowers(ac *api.AccountClient, id mastodon.ID) *Feed { } func NewFollowing(ac *api.AccountClient, id mastodon.ID) *Feed { - feed := &Feed{ - accountClient: ac, - feedType: Following, - items: make([]api.Item, 0), - apiData: &api.RequestData{}, - Update: make(chan DesktopNotificationType, 1), - loadingNewer: &LoadingLock{}, - loadingOlder: &LoadingLock{}, - } - + feed := newFeed(ac, Following) once := true feed.loadNewer = func() { if once { @@ -942,19 +793,7 @@ func NewFollowing(ac *api.AccountClient, id mastodon.ID) *Feed { } func NewBlocking(ac *api.AccountClient) *Feed { - feed := &Feed{ - accountClient: ac, - feedType: Blocking, - items: make([]api.Item, 0), - apiData: &api.RequestData{}, - Update: make(chan DesktopNotificationType, 1), - loadingNewer: &LoadingLock{}, - loadingOlder: &LoadingLock{}, - } - - feed.loadNewer = func() { feed.linkNewer(feed.accountClient.GetBlocking) } - feed.loadOlder = func() { feed.linkOlder(feed.accountClient.GetBlocking) } - + feed := newFeed(ac, Blocking) once := true feed.loadNewer = func() { if once { @@ -968,16 +807,7 @@ func NewBlocking(ac *api.AccountClient) *Feed { } func NewMuting(ac *api.AccountClient) *Feed { - feed := &Feed{ - accountClient: ac, - feedType: Muting, - items: make([]api.Item, 0), - apiData: &api.RequestData{}, - Update: make(chan DesktopNotificationType, 1), - loadingNewer: &LoadingLock{}, - loadingOlder: &LoadingLock{}, - } - + feed := newFeed(ac, Muting) once := true feed.loadNewer = func() { if once { @@ -991,16 +821,7 @@ func NewMuting(ac *api.AccountClient) *Feed { } func NewFollowRequests(ac *api.AccountClient) *Feed { - feed := &Feed{ - accountClient: ac, - feedType: FollowRequests, - items: make([]api.Item, 0), - apiData: &api.RequestData{}, - Update: make(chan DesktopNotificationType, 1), - loadingNewer: &LoadingLock{}, - loadingOlder: &LoadingLock{}, - } - + feed := newFeed(ac, FollowRequests) once := true feed.loadNewer = func() { if once { diff --git a/go.mod b/go.mod index 9e7697a..8e1286d 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/RasmusLindroth/tut go 1.17 require ( - github.com/RasmusLindroth/go-mastodon v0.0.5 + github.com/RasmusLindroth/go-mastodon v0.0.6 github.com/atotto/clipboard v0.1.4 github.com/gdamore/tcell/v2 v2.5.1 github.com/gen2brain/beeep v0.0.0-20220402123239-6a3042f4b71a diff --git a/go.sum b/go.sum index 053393a..83ec885 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/RasmusLindroth/go-mastodon v0.0.5 h1:GHyyv2qc4X9XmUfM1IytRjaU5bWqMoPD+wM+Wvkc/4U= -github.com/RasmusLindroth/go-mastodon v0.0.5/go.mod h1:4L0oyiNwq1tUoiByczzhSikxR9RiANzELtZgexxKpPM= +github.com/RasmusLindroth/go-mastodon v0.0.6 h1:dhVXungiJeRKIE2ZRUJrPibBJ7YkeM4eVyeg3+q6Juk= +github.com/RasmusLindroth/go-mastodon v0.0.6/go.mod h1:4L0oyiNwq1tUoiByczzhSikxR9RiANzELtZgexxKpPM= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= diff --git a/main.go b/main.go index f2d618a..3759eae 100644 --- a/main.go +++ b/main.go @@ -10,7 +10,7 @@ import ( "github.com/rivo/tview" ) -const version = "1.0.7" +const version = "1.0.8" func main() { util.MakeDirs() diff --git a/ui/cmdbar.go b/ui/cmdbar.go index ae81419..ccb6545 100644 --- a/ui/cmdbar.go +++ b/ui/cmdbar.go @@ -133,9 +133,13 @@ func (c *CmdBar) DoneFunc(key tcell.Key) { if len(tag) == 0 { break } - c.tutView.Timeline.AddFeed( - NewTagFeed(c.tutView, tag), - ) + c.tutView.TagCommand(tag) + c.Back() + case ":window": + if len(parts) < 2 { + break + } + c.tutView.WindowCommand(parts[1]) c.Back() case ":user": if len(parts) < 2 { @@ -162,7 +166,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,:muting,:profile,:requests,:saved,:tag,:timeline,:tl,:user,:quit,:q", ",") + words := strings.Split(":blocking,:boosts,:bookmarks,:compose,:favorites,:favorited,:followers,:following,:help,:h,:lists,:muting,:profile,:requests,:saved,:tag,:timeline,:tl,:user,:window,:quit,:q", ",") if curr == "" { return entries } diff --git a/ui/commands.go b/ui/commands.go index f016294..df7a3b0 100644 --- a/ui/commands.go +++ b/ui/commands.go @@ -2,6 +2,7 @@ package ui import ( "fmt" + "strconv" "github.com/RasmusLindroth/go-mastodon" "github.com/RasmusLindroth/tut/api" @@ -83,6 +84,17 @@ func (tv *TutView) TagCommand(tag string) { ) } +func (tv *TutView) WindowCommand(index string) { + i, err := strconv.Atoi(index) + if err != nil { + tv.ShowError( + fmt.Sprintf("couldn't convert str to int. Error %v", err), + ) + return + } + tv.FocusFeed(i) +} + func (tv *TutView) BoostsCommand() { item, itemErr := tv.GetCurrentItem() if itemErr != nil { diff --git a/ui/composeview.go b/ui/composeview.go index c0f1da7..b19921c 100644 --- a/ui/composeview.go +++ b/ui/composeview.go @@ -68,7 +68,7 @@ func newComposeUI(cv *ComposeView) *tview.Flex { AddItem(tview.NewBox(), 2, 0, false). AddItem(tview.NewFlex().SetDirection(tview.FlexRow). AddItem(cv.visibility, 1, 0, false). - AddItem(cv.info, 4, 0, false). + AddItem(cv.info, 5, 0, false). AddItem(cv.media.View, 0, 1, false), 0, 1, false), 0, 1, false). AddItem(cv.input.View, 1, 0, false). AddItem(cv.controls, 1, 0, false). @@ -104,6 +104,7 @@ func (cv *ComposeView) SetControls(ctrl ComposeControls) { 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)) if cv.msg.Status != nil { items = append(items, config.ColorFromKey(cv.tutView.tut.Config, cv.tutView.tut.Config.Input.ComposeIncludeQuote, true)) } @@ -118,6 +119,8 @@ func (cv *ComposeView) SetControls(ctrl ComposeControls) { } func (cv *ComposeView) SetStatus(status *mastodon.Status) { + cv.tutView.PollView.Reset() + cv.media.Reset() msg := &msgToot{} if status != nil { if status.Reblog != nil { @@ -146,7 +149,7 @@ func (cv *ComposeView) SetStatus(status *mastodon.Status) { cv.visibility.SetOptions(visibilities, cv.visibilitySelected) cv.visibility.SetCurrentOption(index) cv.visibility.SetInputCapture(cv.visibilityInput) - cv.updateContent() + cv.UpdateContent() cv.SetControls(ComposeNormal) } @@ -178,7 +181,7 @@ func (cv *ComposeView) EditText() { return } cv.msg.Text = text - cv.updateContent() + cv.UpdateContent() } func (cv *ComposeView) EditSpoiler() { @@ -190,16 +193,16 @@ func (cv *ComposeView) EditSpoiler() { return } cv.msg.SpoilerText = text - cv.updateContent() + cv.UpdateContent() } func (cv *ComposeView) ToggleCW() { cv.msg.Sensitive = !cv.msg.Sensitive - cv.updateContent() + cv.UpdateContent() } -func (cv *ComposeView) updateContent() { - cv.info.SetText(fmt.Sprintf("Chars left: %d\nSpoiler: %t\n", cv.msgLength(), cv.msg.Sensitive)) +func (cv *ComposeView) UpdateContent() { + cv.info.SetText(fmt.Sprintf("Chars left: %d\nSpoiler: %t\nHas poll: %t\n", cv.msgLength(), cv.msg.Sensitive, cv.tutView.PollView.HasPoll())) normal := config.ColorMark(cv.tutView.tut.Config.Style.Text) subtleColor := config.ColorMark(cv.tutView.tut.Config.Style.Subtle) warningColor := config.ColorMark(cv.tutView.tut.Config.Style.WarningText) @@ -252,26 +255,24 @@ func (cv *ComposeView) IncludeQuote() { t += "\n" cv.msg.Text = t cv.msg.QuoteIncluded = true - cv.updateContent() + cv.UpdateContent() +} + +func (cv *ComposeView) HasMedia() bool { + return len(cv.media.Files) > 0 } func (cv *ComposeView) visibilityInput(event *tcell.EventKey) *tcell.EventKey { - if event.Key() == tcell.KeyRune { - switch event.Rune() { - case 'j', 'J': - return tcell.NewEventKey(tcell.KeyDown, 0, tcell.ModNone) - case 'k', 'K': - return tcell.NewEventKey(tcell.KeyUp, 0, tcell.ModNone) - case 'q', 'Q': - cv.exitVisibility() - return nil - } - } else { - switch event.Key() { - case tcell.KeyEsc: - cv.exitVisibility() - return nil - } + if cv.tutView.tut.Config.Input.GlobalDown.Match(event.Key(), event.Rune()) { + return tcell.NewEventKey(tcell.KeyDown, 0, tcell.ModNone) + } + if cv.tutView.tut.Config.Input.GlobalUp.Match(event.Key(), event.Rune()) { + return tcell.NewEventKey(tcell.KeyUp, 0, tcell.ModNone) + } + if cv.tutView.tut.Config.Input.GlobalExit.Match(event.Key(), event.Rune()) || + cv.tutView.tut.Config.Input.GlobalBack.Match(event.Key(), event.Rune()) { + cv.exitVisibility() + return nil } return event } @@ -306,32 +307,37 @@ func (cv *ComposeView) Post() { send.SpoilerText = toot.SpoilerText } - attachments := cv.media.Files - for _, ap := range attachments { - f, err := os.Open(ap.Path) - if err != nil { - cv.tutView.ShowError( - fmt.Sprintf("Couldn't upload media. Error: %v\n", err), - ) - f.Close() - return - } - media := &mastodon.Media{ - File: f, - } - if ap.Description != "" { - media.Description = ap.Description - } - a, err := cv.tutView.tut.Client.Client.UploadMediaFromMedia(context.Background(), media) - if err != nil { - cv.tutView.ShowError( - fmt.Sprintf("Couldn't upload media. Error: %v\n", err), - ) + if cv.HasMedia() { + attachments := cv.media.Files + for _, ap := range attachments { + f, err := os.Open(ap.Path) + if err != nil { + cv.tutView.ShowError( + fmt.Sprintf("Couldn't upload media. Error: %v\n", err), + ) + f.Close() + return + } + media := &mastodon.Media{ + File: f, + } + if ap.Description != "" { + media.Description = ap.Description + } + a, err := cv.tutView.tut.Client.Client.UploadMediaFromMedia(context.Background(), media) + if err != nil { + cv.tutView.ShowError( + fmt.Sprintf("Couldn't upload media. Error: %v\n", err), + ) + f.Close() + return + } f.Close() - return + send.MediaIDs = append(send.MediaIDs, a.ID) } - f.Close() - send.MediaIDs = append(send.MediaIDs, a.ID) + } + if cv.tutView.PollView.HasPoll() && !cv.HasMedia() { + send.Poll = cv.tutView.PollView.GetPoll() } send.Visibility = cv.msg.Visibility diff --git a/ui/input.go b/ui/input.go index 924ad11..b75ef8a 100644 --- a/ui/input.go +++ b/ui/input.go @@ -36,6 +36,8 @@ func (tv *TutView) Input(event *tcell.EventKey) *tcell.EventKey { return tv.InputViewItem(event) case ComposeFocus: return tv.InputComposeView(event) + case PollFocus: + return tv.InputPollView(event) case LinkFocus: return tv.InputLinkView(event) case CmdFocus: @@ -128,7 +130,8 @@ func (tv *TutView) InputLeaderKey(event *tcell.EventKey) *tcell.EventKey { tv.ListsCommand() case config.LeaderTag: tv.TagCommand(subaction) - + case config.LeaderWindow: + tv.WindowCommand(subaction) } tv.Leader.ResetInactive() return nil @@ -614,9 +617,21 @@ func (tv *TutView) InputComposeView(event *tcell.EventKey) *tcell.EventKey { return nil } if tv.tut.Config.Input.ComposeMediaFocus.Match(event.Key(), event.Rune()) { + if tv.PollView.HasPoll() { + tv.ShowError("Can't add media when you have a poll") + return nil + } tv.SetPage(MediaFocus) return nil } + if tv.tut.Config.Input.ComposePoll.Match(event.Key(), event.Rune()) { + if tv.ComposeView.HasMedia() { + tv.ShowError("Can't add poll when you have added media") + return nil + } + tv.SetPage(PollFocus) + return nil + } if tv.tut.Config.Input.ComposePost.Match(event.Key(), event.Rune()) { tv.ComposeView.Post() return nil @@ -696,6 +711,43 @@ func (tv *TutView) InputMediaAdd(event *tcell.EventKey) *tcell.EventKey { return event } +func (tv *TutView) InputPollView(event *tcell.EventKey) *tcell.EventKey { + if tv.tut.Config.Input.PollAdd.Match(event.Key(), event.Rune()) { + tv.PollView.Add() + return nil + } + if tv.tut.Config.Input.PollEdit.Match(event.Key(), event.Rune()) { + tv.PollView.Edit() + return nil + } + if tv.tut.Config.Input.PollDelete.Match(event.Key(), event.Rune()) { + tv.PollView.Delete() + return nil + } + if tv.tut.Config.Input.PollMultiToggle.Match(event.Key(), event.Rune()) { + tv.PollView.ToggleMultiple() + return nil + } + if tv.tut.Config.Input.PollExpiration.Match(event.Key(), event.Rune()) { + tv.PollView.FocusExpiration() + return nil + } + if tv.tut.Config.Input.GlobalDown.Match(event.Key(), event.Rune()) { + tv.PollView.Next() + return nil + } + if tv.tut.Config.Input.GlobalUp.Match(event.Key(), event.Rune()) { + tv.PollView.Prev() + return nil + } + if tv.tut.Config.Input.GlobalBack.Match(event.Key(), event.Rune()) || + tv.tut.Config.Input.GlobalExit.Match(event.Key(), event.Rune()) { + tv.SetPage(ComposeFocus) + return nil + } + return event +} + func (tv *TutView) InputVote(event *tcell.EventKey) *tcell.EventKey { if tv.tut.Config.Input.GlobalDown.Match(event.Key(), event.Rune()) { tv.VoteView.Next() diff --git a/ui/pollview.go b/ui/pollview.go new file mode 100644 index 0000000..fad7f10 --- /dev/null +++ b/ui/pollview.go @@ -0,0 +1,245 @@ +package ui + +import ( + "fmt" + "strings" + "unicode/utf8" + + "github.com/RasmusLindroth/go-mastodon" + "github.com/RasmusLindroth/tut/config" + "github.com/gdamore/tcell/v2" + "github.com/rivo/tview" +) + +var durations = []string{ + "5 minutes", + "30 minutes", + "1 hour", + "6 hours", + "1 day", + "3 days", + "7 days", +} +var durationsTime = map[string]int64{ + "5 minutes": 60 * 50, + "30 minutes": 60 * 30, + "1 hour": 60 * 60, + "6 hours": 60 * 60 * 6, + "1 day": 60 * 60 * 24, + "3 days": 60 * 60 * 24 * 3, + "7 days": 60 * 60 * 24 * 7, +} + +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 +} + +func NewPollView(tv *TutView) *PollView { + p := &PollView{ + tutView: tv, + shared: tv.Shared, + info: NewTextView(tv.tut.Config), + expiration: NewDropDown(tv.tut.Config), + controls: NewTextView(tv.tut.Config), + list: NewList(tv.tut.Config), + } + p.Reset() + p.View = pollViewUI(p) + + return p +} + +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, " ")) + + p.expiration.SetLabel("Expiration: ") + p.expiration.SetOptions(durations, p.expirationSelected) + p.expiration.SetCurrentOption(4) + + return tview.NewFlex().SetDirection(tview.FlexRow). + AddItem(p.shared.Top.View, 1, 0, false). + AddItem(tview.NewFlex().SetDirection(tview.FlexColumn). + AddItem(tview.NewFlex().SetDirection(tview.FlexRow). + AddItem(p.list, 0, 10, false), 0, 2, false). + AddItem(tview.NewBox(), 2, 0, false). + AddItem(tview.NewFlex().SetDirection(tview.FlexRow). + AddItem(p.expiration, 1, 0, false). + AddItem(p.info, 3, 0, false), 0, 1, false), 0, 1, false). + AddItem(p.controls, 1, 0, false). + AddItem(p.shared.Bottom.View, 2, 0, false) +} + +func (p *PollView) Reset() { + p.poll = &mastodon.TootPoll{ + Options: []string{}, + ExpiresInSeconds: durationsTime[durations[4]], + Multiple: false, + HideTotals: false, + } + p.list.Clear() + p.redrawInfo() +} + +func (p *PollView) HasPoll() bool { + return p.list.GetItemCount() > 1 +} + +func (p *PollView) GetPoll() *mastodon.TootPoll { + options := []string{} + for i := 0; i < p.list.GetItemCount(); i++ { + m, _ := p.list.GetItemText(i) + options = append(options, m) + } + return &mastodon.TootPoll{ + Options: options, + ExpiresInSeconds: p.poll.ExpiresInSeconds, + Multiple: p.poll.Multiple, + HideTotals: false, + } +} + +func (p *PollView) redrawInfo() { + content := fmt.Sprintf("Multiple answers: %v", p.poll.Multiple) + p.info.SetText(content) +} + +func (p *PollView) Prev() { + index := p.list.GetCurrentItem() + if index-1 >= 0 { + p.list.SetCurrentItem(index - 1) + } +} + +func (p *PollView) Next() { + index := p.list.GetCurrentItem() + if index+1 < p.list.GetItemCount() { + p.list.SetCurrentItem(index + 1) + } +} + +func checkOption(s string) (string, bool) { + s = strings.TrimSpace(s) + if len(s) == 0 { + return "", false + } + if utf8.RuneCountInString(s) > 25 { + ns := "" + i := 0 + for _, r := range s { + if i >= 25 { + break + } + ns += string(r) + i++ + } + s = ns + } + return s, true +} + +func (p *PollView) Add() { + if p.list.GetItemCount() > 3 { + p.tutView.ShowError("You can only have a maximum of 4 options.") + return + } + text, err := OpenEditor(p.tutView, "") + if err != nil { + p.tutView.ShowError( + fmt.Sprintf("Couldn't open editor. Error: %v", err), + ) + return + } + text, valid := checkOption(text) + if !valid { + return + } + p.list.AddItem(text, "", 0, nil) + p.list.SetCurrentItem( + p.list.GetItemCount() - 1, + ) +} + +func (p *PollView) Edit() { + if p.list.GetItemCount() == 0 { + return + } + text, _ := p.list.GetItemText(p.list.GetCurrentItem()) + text, err := OpenEditor(p.tutView, text) + if err != nil { + p.tutView.ShowError( + fmt.Sprintf("Couldn't open editor. Error: %v", err), + ) + return + } + text, valid := checkOption(text) + if !valid { + return + } + p.list.SetItemText(p.list.GetCurrentItem(), text, "") +} + +func (p *PollView) Delete() { + if p.list.GetItemCount() == 0 { + return + } + item := p.list.GetCurrentItem() + p.list.RemoveItem(item) + if p.list.GetCurrentItem() < 0 && p.list.GetItemCount() > 0 { + p.list.SetCurrentItem(0) + } +} + +func (p *PollView) ToggleMultiple() { + p.poll.Multiple = !p.poll.Multiple + p.redrawInfo() +} +func (p *PollView) expirationSelected(s string, index int) { + _, v := p.expiration.GetCurrentOption() + for k, dur := range durationsTime { + if v == k { + p.poll.ExpiresInSeconds = dur + break + } + } + p.exitExpiration() +} + +func (p *PollView) expirationInput(event *tcell.EventKey) *tcell.EventKey { + if p.tutView.tut.Config.Input.GlobalDown.Match(event.Key(), event.Rune()) { + return tcell.NewEventKey(tcell.KeyDown, 0, tcell.ModNone) + } + if p.tutView.tut.Config.Input.GlobalUp.Match(event.Key(), event.Rune()) { + return tcell.NewEventKey(tcell.KeyUp, 0, tcell.ModNone) + } + if p.tutView.tut.Config.Input.GlobalExit.Match(event.Key(), event.Rune()) || + p.tutView.tut.Config.Input.GlobalBack.Match(event.Key(), event.Rune()) { + p.exitExpiration() + return nil + } + return event +} + +func (p *PollView) FocusExpiration() { + p.tutView.tut.App.SetInputCapture(p.expirationInput) + p.tutView.tut.App.SetFocus(p.expiration) + ev := tcell.NewEventKey(tcell.KeyDown, 0, tcell.ModNone) + p.tutView.tut.App.QueueEvent(ev) +} + +func (p *PollView) exitExpiration() { + p.tutView.tut.App.SetInputCapture(p.tutView.Input) + p.tutView.tut.App.SetFocus(p.tutView.View) +} diff --git a/ui/statusbar.go b/ui/statusbar.go index 2b48aed..d083c6a 100644 --- a/ui/statusbar.go +++ b/ui/statusbar.go @@ -30,6 +30,7 @@ const ( ScrollMode UserMode VoteMode + PollMode ) func (sb *StatusBar) SetMode(m ViewMode) { @@ -58,5 +59,7 @@ func (sb *StatusBar) SetMode(m ViewMode) { sb.View.SetText("-- VIEW --") case UserMode: sb.View.SetText("-- SELECT USER --") + case PollMode: + sb.View.SetText("-- CREATE POLL --") } } diff --git a/ui/tutview.go b/ui/tutview.go index 4bbbdd5..92c5d2c 100644 --- a/ui/tutview.go +++ b/ui/tutview.go @@ -50,6 +50,7 @@ type TutView struct { LinkView *LinkView ComposeView *ComposeView VoteView *VoteView + PollView *PollView HelpView *HelpView ModalView *ModalView @@ -161,6 +162,7 @@ func (tv *TutView) loggedIn(acc auth.Account) { tv.MainView = NewMainView(tv, update) tv.ComposeView = NewComposeView(tv) tv.VoteView = NewVoteView(tv) + tv.PollView = NewPollView(tv) tv.HelpView = NewHelpView(tv) tv.ModalView = NewModalView(tv) @@ -169,6 +171,7 @@ func (tv *TutView) loggedIn(acc auth.Account) { tv.View.AddPage("compose", tv.ComposeView.View, true, false) tv.View.AddPage("vote", tv.VoteView.View, true, false) tv.View.AddPage("help", tv.HelpView.View, true, false) + tv.View.AddPage("poll", tv.PollView.View, true, false) tv.View.AddPage("modal", tv.ModalView.View, true, false) tv.SetPage(MainFocus) } diff --git a/ui/view.go b/ui/view.go index 362c2bb..622ae33 100644 --- a/ui/view.go +++ b/ui/view.go @@ -19,6 +19,7 @@ const ( CmdFocus VoteFocus HelpFocus + PollFocus ) func (tv *TutView) GetCurrentFeed() *Feed { @@ -106,6 +107,7 @@ func (tv *TutView) SetPage(f PageFocusAt) { tv.View.SwitchToPage("compose") tv.Shared.Bottom.StatusBar.SetMode(ComposeMode) tv.Shared.Top.SetText("write a toot") + tv.ComposeView.UpdateContent() tv.ComposeView.SetControls(ComposeNormal) tv.tut.App.SetFocus(tv.ComposeView.content) case MediaFocus: @@ -135,6 +137,12 @@ func (tv *TutView) SetPage(f PageFocusAt) { tv.PageFocus = ModalFocus tv.View.SwitchToPage("modal") tv.tut.App.SetFocus(tv.ModalView.View) + case PollFocus: + tv.PageFocus = PollFocus + tv.View.SwitchToPage("poll") + tv.tut.App.SetFocus(tv.View) + tv.Shared.Bottom.StatusBar.SetMode(PollMode) + tv.Shared.Top.SetText("create a poll") } tv.ShouldSync() diff --git a/ui/voteview.go b/ui/voteview.go index 215b38f..522bfbb 100644 --- a/ui/voteview.go +++ b/ui/voteview.go @@ -36,7 +36,6 @@ func NewVoteView(tv *TutView) *VoteView { 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)) - items = append(items, config.ColorFromKey(v.tutView.tut.Config, v.tutView.tut.Config.Input.VoteSelect, true)) v.controls.SetText(strings.Join(items, " ")) return tview.NewFlex().SetDirection(tview.FlexRow).