Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package tut for openSUSE:Factory checked in at 2022-11-24 12:24:24 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/tut (Old) and /work/SRC/openSUSE:Factory/.tut.new.1597 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "tut" Thu Nov 24 12:24:24 2022 rev:2 rq:1037754 version:1.0.20 Changes: -------- --- /work/SRC/openSUSE:Factory/tut/tut.changes 2022-11-22 16:10:47.142213476 +0100 +++ /work/SRC/openSUSE:Factory/.tut.new.1597/tut.changes 2022-11-24 12:24:26.693761053 +0100 @@ -1,0 +2,25 @@ +Wed Nov 23 18:59:51 UTC 2022 - [email protected] + +- Update to version 1.0.20: + * 1.0.20 (#183) + You can now follow and unfollow tags with :follow-tag tut and + :unfollow-tag tut. + You can now add and remove users from lists. Run :lists and + then you can use the keys that tut displays. This feature only + works okay as it doesn't give you any response if the user is + added to the list or not. But it works. + An error from the terminal programs like lynx shouldn't crash + tut. + When you are reading a thread tut won't make unnecessary API + requests + * add history to help + * 1.0.19 (#179) + * 1.0.18 (#175) + * Updating go install command. (#167) + * 1.0.17 (#164) + * 1.0.16 (#161) + * 1.0.15 (#160) + * 1.0.14 (#159) + * 1.0.13 (#157) + +------------------------------------------------------------------- Old: ---- tut-1.0.19.tar.gz New: ---- tut-1.0.20.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ tut.spec ++++++ --- /var/tmp/diff_new_pack.dnr6H6/_old 2022-11-24 12:24:27.585766721 +0100 +++ /var/tmp/diff_new_pack.dnr6H6/_new 2022-11-24 12:24:27.589766747 +0100 @@ -17,7 +17,7 @@ Name: tut -Version: 1.0.19 +Version: 1.0.20 Release: 0 Summary: A TUI for Mastodon with vim inspired keys License: MIT @@ -25,7 +25,6 @@ URL: https://tut.anv.nu Source0: %{name}-%{version}.tar.gz Source1: vendor.tar.gz -BuildRequires: gcc-c++ BuildRequires: golang-packaging # some modules require go 1.18+ BuildRequires: golang(API) >= 1.18 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.dnr6H6/_old 2022-11-24 12:24:27.637767051 +0100 +++ /var/tmp/diff_new_pack.dnr6H6/_new 2022-11-24 12:24:27.653767154 +0100 @@ -2,7 +2,7 @@ <service mode="disabled" name="obs_scm"> <param name="url">https://github.com/RasmusLindroth/tut.git</param> <param name="scm">git</param> - <param name="revision">refs/tags/1.0.19</param> + <param name="revision">refs/tags/1.0.20</param> <param name="versionformat">@PARENT_TAG@</param> <param name="changesgenerate">enable</param> </service> ++++++ tut-1.0.19.tar.gz -> tut-1.0.20.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/README.md new/tut-1.0.20/README.md --- old/tut-1.0.19/README.md 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/README.md 2022-11-23 19:07:42.000000000 +0100 @@ -45,6 +45,9 @@ * `:compose` compose a new toot * `:favorited` lists toots you've favorited * `:favorites` lists users that favorited the toot +* `:follow-tag` followed by the hashtag to follow e.g. `:follow-tag tut` +* `:followers` list of people the account are following. It only works on profiles. +* `:following` list of people following the account. It only works on profiles. * `:h` `:help` view help * `:history` show edits of a toot * `:lists` show a list of your lists @@ -58,6 +61,7 @@ * `:requests` see following requests * `:saved` alias for bookmarks * `:tag` followed by the hashtag e.g. `:tag linux` +* `:unfollow-tag` followed by the hashtag to unfollow e.g. `:unfollow-tag tut` * `:user` followed by a username e.g. `:user rasmus` to narrow a search include * `:window` switch window by index (zero indexed) e.g. `:window 0` for the first window. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/api/feed.go new/tut-1.0.20/api/feed.go --- old/tut-1.0.19/api/feed.go 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/api/feed.go 2022-11-23 19:07:42.000000000 +0100 @@ -21,7 +21,7 @@ return items, nil } -func (ac *AccountClient) getUserSimilar(fn func() ([]*mastodon.Account, error)) ([]Item, error) { +func (ac *AccountClient) getUserSimilar(fn func() ([]*mastodon.Account, error), data interface{}) ([]Item, error) { var items []Item users, err := fn() if err != nil { @@ -39,8 +39,9 @@ for _, r := range rel { if u.ID == r.ID { items = append(items, NewUserItem(&User{ - Data: u, - Relation: r, + Data: u, + Relation: r, + AdditionalData: data, }, false)) break } @@ -185,49 +186,49 @@ fn := func() ([]*mastodon.Account, error) { return ac.Client.GetRebloggedBy(context.Background(), id, pg) } - return ac.getUserSimilar(fn) + return ac.getUserSimilar(fn, nil) } func (ac *AccountClient) GetFavoritesStatus(pg *mastodon.Pagination, id mastodon.ID) ([]Item, error) { fn := func() ([]*mastodon.Account, error) { return ac.Client.GetFavouritedBy(context.Background(), id, pg) } - return ac.getUserSimilar(fn) + return ac.getUserSimilar(fn, nil) } func (ac *AccountClient) GetFollowers(pg *mastodon.Pagination, id mastodon.ID) ([]Item, error) { fn := func() ([]*mastodon.Account, error) { return ac.Client.GetAccountFollowers(context.Background(), id, pg) } - return ac.getUserSimilar(fn) + return ac.getUserSimilar(fn, nil) } func (ac *AccountClient) GetFollowing(pg *mastodon.Pagination, id mastodon.ID) ([]Item, error) { fn := func() ([]*mastodon.Account, error) { return ac.Client.GetAccountFollowing(context.Background(), id, pg) } - return ac.getUserSimilar(fn) + return ac.getUserSimilar(fn, nil) } func (ac *AccountClient) GetBlocking(pg *mastodon.Pagination) ([]Item, error) { fn := func() ([]*mastodon.Account, error) { return ac.Client.GetBlocks(context.Background(), pg) } - return ac.getUserSimilar(fn) + return ac.getUserSimilar(fn, nil) } func (ac *AccountClient) GetMuting(pg *mastodon.Pagination) ([]Item, error) { fn := func() ([]*mastodon.Account, error) { return ac.Client.GetMutes(context.Background(), pg) } - return ac.getUserSimilar(fn) + return ac.getUserSimilar(fn, nil) } func (ac *AccountClient) GetFollowRequests(pg *mastodon.Pagination) ([]Item, error) { fn := func() ([]*mastodon.Account, error) { return ac.Client.GetFollowRequests(context.Background(), pg) } - return ac.getUserSimilar(fn) + return ac.getUserSimilar(fn, nil) } func (ac *AccountClient) GetUser(pg *mastodon.Pagination, id mastodon.ID) ([]Item, error) { @@ -281,6 +282,20 @@ return items, nil } +func (ac *AccountClient) GetFollowingForList(pg *mastodon.Pagination, id mastodon.ID, data interface{}) ([]Item, error) { + fn := func() ([]*mastodon.Account, error) { + return ac.Client.GetAccountFollowing(context.Background(), id, pg) + } + return ac.getUserSimilar(fn, data) +} + +func (ac *AccountClient) GetListUsers(pg *mastodon.Pagination, id mastodon.ID, data interface{}) ([]Item, error) { + fn := func() ([]*mastodon.Account, error) { + return ac.Client.GetListAccounts(context.Background(), id) + } + return ac.getUserSimilar(fn, data) +} + func (ac *AccountClient) GetTag(pg *mastodon.Pagination, search string) ([]Item, error) { fn := func() ([]*mastodon.Status, error) { return ac.Client.GetTimelineHashtag(context.Background(), search, false, pg) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/api/tags.go new/tut-1.0.20/api/tags.go --- old/tut-1.0.19/api/tags.go 1970-01-01 01:00:00.000000000 +0100 +++ new/tut-1.0.20/api/tags.go 2022-11-23 19:07:42.000000000 +0100 @@ -0,0 +1,35 @@ +package api + +import ( + "context" + "errors" +) + +func (ac *AccountClient) FollowTag(tag string) error { + t, err := ac.Client.TagFollow(context.Background(), tag) + if err != nil { + return err + } + if t.Following == nil { + return errors.New("following is set to nil") + } + if t.Following == false { + return errors.New("following is still set to false") + } + return nil +} + +func (ac *AccountClient) UnfollowTag(tag string) error { + t, err := ac.Client.TagUnfollow(context.Background(), tag) + if err != nil { + return err + } + + if t.Following == nil { + return errors.New("following is set to nil") + } + if t.Following == true { + return errors.New("following is still set to true") + } + return nil +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/api/types.go new/tut-1.0.20/api/types.go --- old/tut-1.0.19/api/types.go 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/api/types.go 2022-11-23 19:07:42.000000000 +0100 @@ -15,6 +15,7 @@ } type User struct { - Data *mastodon.Account - Relation *mastodon.Relationship + Data *mastodon.Account + Relation *mastodon.Relationship + AdditionalData interface{} } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/api/user.go new/tut-1.0.20/api/user.go --- old/tut-1.0.19/api/user.go 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/api/user.go 2022-11-23 19:07:42.000000000 +0100 @@ -87,3 +87,11 @@ } return err } + +func (ac *AccountClient) AddUserToList(u *mastodon.Account, l *mastodon.List) error { + return ac.Client.AddToList(context.Background(), l.ID, u.ID) +} + +func (ac *AccountClient) DeleteUserFromList(u *mastodon.Account, l *mastodon.List) error { + return ac.Client.RemoveFromList(context.Background(), l.ID, u.ID) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/config/config.go new/tut-1.0.20/config/config.go --- old/tut-1.0.19/config/config.go 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/config/config.go 2022-11-23 19:07:42.000000000 +0100 @@ -380,7 +380,10 @@ UserViewFocus Key UserYank Key - ListOpenFeed Key + ListOpenFeed Key + ListUserList Key + ListUserAdd Key + ListUserDelete Key LinkOpen Key LinkYank Key @@ -1265,7 +1268,10 @@ UserViewFocus: inputStrOrErr([]string{"\"[V]iew\"", "'v'", "'V'"}, false), UserYank: inputStrOrErr([]string{"\"[Y]ank\"", "'y'", "'Y'"}, false), - ListOpenFeed: inputStrOrErr([]string{"\"[O]pen\"", "'o'", "'O'"}, false), + ListOpenFeed: inputStrOrErr([]string{"\"[O]pen\"", "'o'", "'O'"}, false), + ListUserList: inputStrOrErr([]string{"\"[U]sers\"", "'u'", "'U'"}, false), + ListUserAdd: inputStrOrErr([]string{"\"[A]dd\"", "'a'", "'A'"}, false), + ListUserDelete: inputStrOrErr([]string{"\"[D]elete\"", "'d'", "'D'"}, false), LinkOpen: inputStrOrErr([]string{"\"[O]pen\"", "'o'", "'O'"}, false), LinkYank: inputStrOrErr([]string{"\"[Y]ank\"", "'y'", "'Y'"}, false), @@ -1340,6 +1346,9 @@ ic.UserYank = inputOrErr(cfg, "user-yank", false, ic.UserYank) ic.ListOpenFeed = inputOrErr(cfg, "list-open-feed", false, ic.ListOpenFeed) + ic.ListUserList = inputOrErr(cfg, "list-user-list", false, ic.ListUserList) + ic.ListUserAdd = inputOrErr(cfg, "list-user-add", false, ic.ListUserAdd) + ic.ListUserDelete = inputOrErr(cfg, "list-user-delete", false, ic.ListUserDelete) ic.LinkOpen = inputOrErr(cfg, "link-open", false, ic.LinkOpen) ic.LinkYank = inputOrErr(cfg, "link-yank", false, ic.LinkYank) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/config/default_config.go new/tut-1.0.20/config/default_config.go --- old/tut-1.0.19/config/default_config.go 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/config/default_config.go 2022-11-23 19:07:42.000000000 +0100 @@ -644,6 +644,18 @@ # default="[O]pen",'o','O' list-open-feed="[O]pen",'o','O' +# List all users in a list +# default="[U]sers",'u','U' +list-user-list="[U]sers",'u','U' + +# Add user to list +# default="[A]dd",'a','A' +list-user-add="[A]dd",'a','A' + +# Delete user from list +# default="[D]elete",'d','D' +list-user-delete="[D]elete",'d','D' + # Open URL # default="[O]pen",'o','O' link-open="[O]pen",'o','O' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/config/help.tmpl new/tut-1.0.20/config/help.tmpl --- old/tut-1.0.19/config/help.tmpl 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/config/help.tmpl 2022-11-23 19:07:42.000000000 +0100 @@ -57,6 +57,15 @@ {{ Color .Style.TextSpecial2 }}{{ Flags "b" }}:favorites{{ Flags "-" }}{{ Color .Style.Text }} Lists users that favorited the toot +{{ Color .Style.TextSpecial2 }}{{ Flags "b" }}:follow-tag{{ Flags "-" }}{{ Color .Style.Text }} + Followed by the hashtag to follow e.g. :follow-tag tut + +{{ Color .Style.TextSpecial2 }}{{ Flags "b" }}:followers{{ Flags "-" }}{{ Color .Style.Text }} + List of people the account are following. It only works on profiles. + +{{ Color .Style.TextSpecial2 }}{{ Flags "b" }}:following{{ Flags "-" }}{{ Color .Style.Text }} + List of people following the account. It only works on profiles. + {{ Color .Style.TextSpecial2 }}{{ Flags "b" }}:h{{ Flags "-" }}{{ Color .Style.Text }} or {{- Color .Style.TextSpecial2 }}{{ Flags "b" }} :help{{ Flags "-" }}{{ Color .Style.Text }} View this help message @@ -92,7 +101,10 @@ Alias for :bookmarks {{ Color .Style.TextSpecial2 }}{{ Flags "b" }}:tag{{ Flags "-" }}{{ Color .Style.Text }} tagname - See toots for a tag. E.g. :tag linux + See toots for a tag e.g. :tag linux + +{{ Color .Style.TextSpecial2 }}{{ Flags "b" }}:unfollow-tag{{ Flags "-" }}{{ Color .Style.Text }} + Followed by the hashtag to unfollow e.g. :unfollow-tag tut {{ Color .Style.TextSpecial2 }}{{ Flags "b" }}:user{{ Flags "-" }}{{ Color .Style.Text }} username Go to profile for <username>. E.g. :user rasmus diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/config.example.ini new/tut-1.0.20/config.example.ini --- old/tut-1.0.19/config.example.ini 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/config.example.ini 2022-11-23 19:07:42.000000000 +0100 @@ -642,6 +642,18 @@ # default="[O]pen",'o','O' list-open-feed="[O]pen",'o','O' +# List all users in a list +# default="[U]sers",'u','U' +list-user-list="[U]sers",'u','U' + +# Add user to list +# default="[A]dd",'a','A' +list-user-add="[A]dd",'a','A' + +# Delete user from list +# default="[D]elete",'d','D' +list-user-delete="[D]elete",'d','D' + # Open URL # default="[O]pen",'o','O' link-open="[O]pen",'o','O' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/feed/feed.go new/tut-1.0.20/feed/feed.go --- old/tut-1.0.19/feed/feed.go 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/feed/feed.go 2022-11-23 19:07:42.000000000 +0100 @@ -14,6 +14,7 @@ type apiFunc func(pg *mastodon.Pagination) ([]api.Item, error) type apiEmptyFunc func() ([]api.Item, error) type apiIDFunc func(pg *mastodon.Pagination, id mastodon.ID) ([]api.Item, error) +type apiIDFuncData func(pg *mastodon.Pagination, id mastodon.ID, data interface{}) ([]api.Item, error) type apiSearchFunc func(search string) ([]api.Item, error) type apiSearchPGFunc func(pg *mastodon.Pagination, search string) ([]api.Item, error) type apiThreadFunc func(status *mastodon.Status) ([]api.Item, error) @@ -44,6 +45,8 @@ UserList Lists List + ListUsersIn + ListUsersAdd ) type LoadingLock struct { @@ -556,6 +559,57 @@ f.itemsMux.Unlock() } +func (f *Feed) linkNewerIDdata(fn apiIDFuncData, id mastodon.ID, data interface{}) { + f.apiDataMux.Lock() + pg := &mastodon.Pagination{} + pg.MinID = f.apiData.MinID + maxTmp := f.apiData.MaxID + + items, err := fn(pg, id, data) + if err != nil { + f.apiDataMux.Unlock() + return + } + f.apiData.MinID = pg.MinID + if pg.MaxID == "" { + f.apiData.MaxID = maxTmp + } else { + f.apiData.MaxID = pg.MaxID + } + f.apiDataMux.Unlock() + f.itemsMux.Lock() + if len(items) > 0 { + f.items = append(items, f.items...) + f.Updated(DeskstopNotificationNone) + } + f.itemsMux.Unlock() +} + +func (f *Feed) linkOlderIDdata(fn apiIDFuncData, id mastodon.ID, data interface{}) { + f.apiDataMux.Lock() + pg := &mastodon.Pagination{} + pg.MaxID = f.apiData.MaxID + if pg.MaxID == "" { + f.apiDataMux.Unlock() + return + } + + items, err := fn(pg, id, data) + if err != nil { + f.apiDataMux.Unlock() + return + } + f.apiData.MaxID = pg.MaxID + f.apiDataMux.Unlock() + + f.itemsMux.Lock() + if len(items) > 0 { + f.items = append(f.items, items...) + f.Updated(DeskstopNotificationNone) + } + f.itemsMux.Unlock() +} + func (f *Feed) startStream(rec *api.Receiver, timeline string, err error) { if err != nil { log.Fatalln("Couldn't open stream") @@ -731,7 +785,13 @@ func NewThread(ac *api.AccountClient, status *mastodon.Status) *Feed { feed := newFeed(ac, Thread) - feed.loadNewer = func() { feed.singleThread(feed.accountClient.GetThread, status) } + once := true + feed.loadNewer = func() { + if once { + feed.singleThread(feed.accountClient.GetThread, status) + once = false + } + } return feed } @@ -782,6 +842,36 @@ return feed } + +func NewUsersInList(ac *api.AccountClient, list *mastodon.List) *Feed { + feed := newFeed(ac, ListUsersIn) + feed.name = list.Title + once := true + feed.loadNewer = func() { + if once { + feed.linkNewerIDdata(feed.accountClient.GetListUsers, list.ID, list) + } + once = false + } + feed.loadOlder = func() { feed.linkOlderIDdata(feed.accountClient.GetListUsers, list.ID, list) } + + return feed +} + +func NewUsersAddList(ac *api.AccountClient, list *mastodon.List) *Feed { + feed := newFeed(ac, ListUsersAdd) + feed.name = list.Title + once := true + feed.loadNewer = func() { + if once { + feed.linkNewerIDdata(feed.accountClient.GetFollowingForList, ac.Me.ID, list) + } + once = false + } + feed.loadOlder = func() { feed.linkOlderIDdata(feed.accountClient.GetFollowingForList, ac.Me.ID, list) } + + return feed +} func NewFavoritesStatus(ac *api.AccountClient, id mastodon.ID) *Feed { feed := newFeed(ac, Favorites) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/go.mod new/tut-1.0.20/go.mod --- old/tut-1.0.19/go.mod 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/go.mod 2022-11-23 19:07:42.000000000 +0100 @@ -3,7 +3,7 @@ go 1.18 require ( - github.com/RasmusLindroth/go-mastodon v0.0.10 + github.com/RasmusLindroth/go-mastodon v0.0.11 github.com/atotto/clipboard v0.1.4 github.com/gdamore/tcell/v2 v2.5.3 github.com/gen2brain/beeep v0.0.0-20220909211152-5a9ec94374f6 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/go.sum new/tut-1.0.20/go.sum --- old/tut-1.0.19/go.sum 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/go.sum 2022-11-23 19:07:42.000000000 +0100 @@ -1,5 +1,7 @@ github.com/RasmusLindroth/go-mastodon v0.0.10 h1:huGNcPn5SASfJDhBL4drKL0PFJ29+hqjCroIrkf2R0E= github.com/RasmusLindroth/go-mastodon v0.0.10/go.mod h1:Lr6n8V1U2b+9P89YZKsICkNc+oNeJXkygY7raei9SXE= +github.com/RasmusLindroth/go-mastodon v0.0.11 h1:Qcad+urrDVrboo13ayoHG3DcwsGK/07qR6IfOPPMilY= +github.com/RasmusLindroth/go-mastodon v0.0.11/go.mod h1:Lr6n8V1U2b+9P89YZKsICkNc+oNeJXkygY7raei9SXE= 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/main.go new/tut-1.0.20/main.go --- old/tut-1.0.19/main.go 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/main.go 2022-11-23 19:07:42.000000000 +0100 @@ -8,7 +8,7 @@ "github.com/rivo/tview" ) -const version = "1.0.19" +const version = "1.0.20" func main() { util.SetTerminalTitle("tut") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/ui/cmdbar.go new/tut-1.0.20/ui/cmdbar.go --- old/tut-1.0.19/ui/cmdbar.go 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/ui/cmdbar.go 2022-11-23 19:07:42.000000000 +0100 @@ -198,6 +198,26 @@ NewUserSearchFeed(c.tutView, user), ) c.Back() + case ":follow-tag": + if len(parts) < 2 { + break + } + tag := strings.TrimSpace(parts[1]) + if len(tag) == 0 { + break + } + c.tutView.TagFollowCommand(parts[1]) + c.Back() + case ":unfollow-tag": + if len(parts) < 2 { + break + } + tag := strings.TrimSpace(parts[1]) + if len(tag) == 0 { + break + } + c.tutView.TagUnfollowCommand(parts[1]) + c.Back() case ":lists": c.tutView.ListsCommand() c.Back() @@ -211,7 +231,7 @@ func (c *CmdBar) Autocomplete(curr string) []string { var entries []string - words := strings.Split(":blocking,:boosts,:bookmarks,:clear-notifications,:compose,:favorites,:favorited,:followers,:following,:help,:h,:history,: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,:follow-tag,:followers,:following,:help,:h,:history,:lists,:list-placement,:list-split,:muting,:newer,:preferences,:profile,:proportions,:requests,:saved,:tag,:timeline,:tl,:unfollow-tag,:user,:window,:quit,:q", ",") if curr == "" { return entries } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/ui/commands.go new/tut-1.0.20/ui/commands.go --- old/tut-1.0.19/ui/commands.go 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/ui/commands.go 2022-11-23 19:07:42.000000000 +0100 @@ -86,6 +86,22 @@ ) } +func (tv *TutView) TagFollowCommand(tag string) { + err := tv.tut.Client.FollowTag(tag) + if err != nil { + tv.ShowError(fmt.Sprintf("Couldn't follow tag. Error: %v\n", err)) + return + } +} + +func (tv *TutView) TagUnfollowCommand(tag string) { + err := tv.tut.Client.UnfollowTag(tag) + if err != nil { + tv.ShowError(fmt.Sprintf("Couldn't unfollow tag. Error: %v\n", err)) + return + } +} + func (tv *TutView) WindowCommand(index string) { i, err := strconv.Atoi(index) if err != nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/ui/feed.go new/tut-1.0.20/ui/feed.go --- old/tut-1.0.19/ui/feed.go 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/ui/feed.go 2022-11-23 19:07:42.000000000 +0100 @@ -336,6 +336,36 @@ return fd } +func NewUsersInListFeed(tv *TutView, l *mastodon.List) *Feed { + f := feed.NewUsersInList(tv.tut.Client, l) + f.LoadNewer() + fd := &Feed{ + tutView: tv, + Data: f, + ListIndex: 0, + List: NewFeedList(tv.tut, f.StickyCount()), + Content: NewFeedContent(tv.tut), + } + go fd.update() + + return fd +} + +func NewUsersAddListFeed(tv *TutView, l *mastodon.List) *Feed { + f := feed.NewUsersAddList(tv.tut.Client, l) + f.LoadNewer() + fd := &Feed{ + tutView: tv, + Data: f, + ListIndex: 0, + List: NewFeedList(tv.tut, f.StickyCount()), + Content: NewFeedContent(tv.tut), + } + go fd.update() + + return fd +} + func NewFavoritedFeed(tv *TutView) *Feed { f := feed.NewFavorites(tv.tut.Client) f.LoadNewer() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/ui/input.go new/tut-1.0.20/ui/input.go --- old/tut-1.0.19/ui/input.go 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/ui/input.go 2022-11-23 19:07:42.000000000 +0100 @@ -304,16 +304,21 @@ case api.StatusHistoryType: return tv.InputStatusHistory(event, item, item.Raw().(*mastodon.StatusHistory), nil) case api.UserType, api.ProfileType: - if ft == feed.FollowRequests { - return tv.InputUser(event, item.Raw().(*api.User), true) - } else { - return tv.InputUser(event, item.Raw().(*api.User), false) + switch ft { + case feed.FollowRequests: + return tv.InputUser(event, item.Raw().(*api.User), InputUserFollowRequest) + case feed.ListUsersAdd: + return tv.InputUser(event, item.Raw().(*api.User), InputUserListAdd) + case feed.ListUsersIn: + return tv.InputUser(event, item.Raw().(*api.User), InputUserListDelete) + default: + return tv.InputUser(event, item.Raw().(*api.User), InputUserNormal) } case api.NotificationType: nd := item.Raw().(*api.NotificationData) switch nd.Item.Type { case "follow": - return tv.InputUser(event, nd.User.Raw().(*api.User), false) + return tv.InputUser(event, nd.User.Raw().(*api.User), InputUserNormal) case "favourite": user := nd.User.Raw().(*api.User) return tv.InputStatus(event, nd.Status, nd.Status.Raw().(*mastodon.Status), user.Data) @@ -329,7 +334,7 @@ case "poll": return tv.InputStatus(event, nd.Status, nd.Status.Raw().(*mastodon.Status), nil) case "follow_request": - return tv.InputUser(event, nd.User.Raw().(*api.User), true) + return tv.InputUser(event, nd.User.Raw().(*api.User), InputUserFollowRequest) } case api.ListsType: ld := item.Raw().(*mastodon.List) @@ -548,12 +553,60 @@ return event } -func (tv *TutView) InputUser(event *tcell.EventKey, user *api.User, fr bool) *tcell.EventKey { +type InputUserType uint + +const ( + InputUserNormal = iota + InputUserFollowRequest + InputUserListAdd + InputUserListDelete +) + +func (tv *TutView) InputUser(event *tcell.EventKey, user *api.User, ut InputUserType) *tcell.EventKey { blocking := user.Relation.Blocking muting := user.Relation.Muting following := user.Relation.Following - if tv.tut.Config.Input.UserFollowRequestDecide.Match(event.Key(), event.Rune()) { + if ut == InputUserListAdd { + if tv.tut.Config.Input.GlobalEnter.Match(event.Key(), event.Rune()) || + tv.tut.Config.Input.ListUserAdd.Match(event.Key(), event.Rune()) { + ad := user.AdditionalData + switch ad.(type) { + case *mastodon.List: + l := user.AdditionalData.(*mastodon.List) + err := tv.tut.Client.AddUserToList(user.Data, l) + if err != nil { + tv.ShowError(fmt.Sprintf("Couldn't add user to list. Error: %v", err)) + } + return nil + default: + return event + } + + } + return event + } + + if ut == InputUserListDelete { + if tv.tut.Config.Input.GlobalEnter.Match(event.Key(), event.Rune()) || + tv.tut.Config.Input.ListUserDelete.Match(event.Key(), event.Rune()) { + ad := user.AdditionalData + switch ad.(type) { + case *mastodon.List: + l := user.AdditionalData.(*mastodon.List) + err := tv.tut.Client.DeleteUserFromList(user.Data, l) + if err != nil { + tv.ShowError(fmt.Sprintf("Couldn't remove user from list. Error: %v", err)) + } + return nil + default: + return event + } + } + return event + } + + if ut == InputUserFollowRequest && tv.tut.Config.Input.UserFollowRequestDecide.Match(event.Key(), event.Rune()) { tv.ModalView.RunDecide("Do you want accept the follow request?", func() { err := tv.tut.Client.FollowRequestAccept(user.Data) @@ -671,6 +724,14 @@ tv.Timeline.AddFeed(NewListFeed(tv, list)) return nil } + if tv.tut.Config.Input.ListUserList.Match(event.Key(), event.Rune()) { + tv.Timeline.AddFeed(NewUsersInListFeed(tv, list)) + return nil + } + if tv.tut.Config.Input.ListUserAdd.Match(event.Key(), event.Rune()) { + tv.Timeline.AddFeed(NewUsersAddListFeed(tv, list)) + return nil + } return event } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/ui/item.go new/tut-1.0.20/ui/item.go --- old/tut-1.0.19/ui/item.go 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/ui/item.go 2022-11-23 19:07:42.000000000 +0100 @@ -91,10 +91,15 @@ } drawStatus(tv, item, &status, main, controls, true, "") case api.UserType, api.ProfileType: - if ft == feed.FollowRequests { - drawUser(tv, item.Raw().(*api.User), main, controls, "", true) - } else { - drawUser(tv, item.Raw().(*api.User), main, controls, "", false) + switch ft { + case feed.FollowRequests: + drawUser(tv, item.Raw().(*api.User), main, controls, "", InputUserFollowRequest) + case feed.ListUsersAdd: + drawUser(tv, item.Raw().(*api.User), main, controls, "", InputUserListAdd) + case feed.ListUsersIn: + drawUser(tv, item.Raw().(*api.User), main, controls, "", InputUserListDelete) + default: + drawUser(tv, item.Raw().(*api.User), main, controls, "", InputUserFollowRequest) } case api.NotificationType: drawNotification(tv, item, item.Raw().(*api.NotificationData), main, controls) @@ -122,9 +127,9 @@ drawStatus(tv, item, &status, nil, controls, true, "") case api.UserType, api.ProfileType: if ft == feed.FollowRequests { - drawUser(tv, item.Raw().(*api.User), nil, controls, "", true) + drawUser(tv, item.Raw().(*api.User), nil, controls, "", InputUserFollowRequest) } else { - drawUser(tv, item.Raw().(*api.User), nil, controls, "", false) + drawUser(tv, item.Raw().(*api.User), nil, controls, "", InputUserNormal) } case api.NotificationType: drawNotification(tv, item, item.Raw().(*api.NotificationData), nil, controls) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/ui/item_list.go new/tut-1.0.20/ui/item_list.go --- old/tut-1.0.19/ui/item_list.go 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/ui/item_list.go 2022-11-23 19:07:42.000000000 +0100 @@ -11,9 +11,19 @@ } 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.Clear() - controls.AddItem(NewControlButton(tv, btn), btn.Len, 0, false) + var items []Control + items = append(items, NewControl(tv.tut.Config, tv.tut.Config.Input.ListOpenFeed, true)) + items = append(items, NewControl(tv.tut.Config, tv.tut.Config.Input.ListUserList, true)) + items = append(items, NewControl(tv.tut.Config, tv.tut.Config.Input.ListUserAdd, true)) + controls.Clear() + for i, item := range items { + if i < len(items)-1 { + controls.AddItem(NewControlButton(tv, item), item.Len+1, 0, false) + } else { + controls.AddItem(NewControlButton(tv, item), item.Len, 0, false) + } + } main.SetText(fmt.Sprintf("List %s", tview.Escape(data.Title))) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/ui/item_notification.go new/tut-1.0.20/ui/item_notification.go --- old/tut-1.0.19/ui/item_notification.go 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/ui/item_notification.go 2022-11-23 19:07:42.000000000 +0100 @@ -13,7 +13,7 @@ switch notification.Item.Type { case "follow": drawUser(tv, notification.User.Raw().(*api.User), main, controls, - fmt.Sprintf("%s started following you", util.FormatUsername(notification.Item.Account)), false, + fmt.Sprintf("%s started following you", util.FormatUsername(notification.Item.Account)), InputUserNormal, ) case "favourite": drawStatus(tv, notification.Status, notification.Item.Status, main, controls, false, @@ -42,7 +42,7 @@ case "follow_request": drawUser(tv, notification.User.Raw().(*api.User), main, controls, fmt.Sprintf("%s wants to follow you.", util.FormatUsername(notification.Item.Account)), - true, + InputUserFollowRequest, ) default: controls.Clear() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/ui/item_user.go new/tut-1.0.20/ui/item_user.go --- old/tut-1.0.19/ui/item_user.go 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/ui/item_user.go 2022-11-23 19:07:42.000000000 +0100 @@ -43,7 +43,7 @@ Style config.Style } -func drawUser(tv *TutView, data *api.User, main *tview.TextView, controls *tview.Flex, additional string, fr bool) { +func drawUser(tv *TutView, data *api.User, main *tview.TextView, controls *tview.Flex, additional string, ut InputUserType) { user := data.Data relation := data.Relation showUserControl := true @@ -79,7 +79,7 @@ u.Fields = fields var controlItems []Control - if fr { + if ut == InputUserFollowRequest { controlItems = append(controlItems, NewControl(tv.tut.Config, tv.tut.Config.Input.UserFollowRequestDecide, false)) } if tv.tut.Client.Me.ID != user.ID { @@ -108,6 +108,13 @@ 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)) + // Clear controls and only have add and delete for lists. + if ut == InputUserListAdd { + controlItems = []Control{NewControl(tv.tut.Config, tv.tut.Config.Input.ListUserAdd, true)} + } else if ut == InputUserListDelete { + controlItems = []Control{NewControl(tv.tut.Config, tv.tut.Config.Input.ListUserDelete, true)} + } + controls.Clear() for i, item := range controlItems { if i < len(controlItems)-1 { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/ui/open.go new/tut-1.0.20/ui/open.go --- old/tut-1.0.19/ui/open.go 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/ui/open.go 2022-11-23 19:07:42.000000000 +0100 @@ -1,7 +1,7 @@ package ui import ( - "log" + "fmt" "os" "os/exec" "strings" @@ -36,11 +36,11 @@ var err error tv.tut.App.Suspend(func() { err = cmd.Run() - if err != nil { - log.Fatalln(err) - } }) - return err + if err != nil { + tv.ShowError(fmt.Sprintf("Eroror while opening: %v", err)) + } + return nil } func openCustom(tv *TutView, program string, args []string, terminal bool, url string) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tut-1.0.19/ui/timeline.go new/tut-1.0.20/ui/timeline.go --- old/tut-1.0.19/ui/timeline.go 2022-11-20 19:44:42.000000000 +0100 +++ new/tut-1.0.20/ui/timeline.go 2022-11-23 19:07:42.000000000 +0100 @@ -183,8 +183,10 @@ ct = "follow requests" case feed.Blocking: ct = "blocking" - case feed.Muting: - ct = "muting" + case feed.ListUsersAdd: + ct = fmt.Sprintf("Add users to %s", name) + case feed.ListUsersIn: + ct = fmt.Sprintf("Delete users from %s", name) } return fmt.Sprintf("%s (%d/%d)", ct, index+1, total) } ++++++ vendor.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/RasmusLindroth/go-mastodon/lists.go new/vendor/github.com/RasmusLindroth/go-mastodon/lists.go --- old/vendor/github.com/RasmusLindroth/go-mastodon/lists.go 2022-11-21 12:47:23.000000000 +0100 +++ new/vendor/github.com/RasmusLindroth/go-mastodon/lists.go 2022-11-23 20:03:29.000000000 +0100 @@ -90,7 +90,7 @@ func (c *Client) AddToList(ctx context.Context, list ID, accounts ...ID) error { params := url.Values{} for _, acct := range accounts { - params.Add("account_ids", string(acct)) + params.Add("account_ids[]", string(acct)) } return c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/lists/%s/accounts", url.PathEscape(string(list))), params, nil, nil) @@ -100,7 +100,7 @@ func (c *Client) RemoveFromList(ctx context.Context, list ID, accounts ...ID) error { params := url.Values{} for _, acct := range accounts { - params.Add("account_ids", string(acct)) + params.Add("account_ids[]", string(acct)) } return c.doAPI(ctx, http.MethodDelete, fmt.Sprintf("/api/v1/lists/%s/accounts", url.PathEscape(string(list))), params, nil, nil) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/RasmusLindroth/go-mastodon/mastodon.go new/vendor/github.com/RasmusLindroth/go-mastodon/mastodon.go --- old/vendor/github.com/RasmusLindroth/go-mastodon/mastodon.go 2022-11-21 12:47:23.000000000 +0100 +++ new/vendor/github.com/RasmusLindroth/go-mastodon/mastodon.go 2022-11-23 20:03:29.000000000 +0100 @@ -251,13 +251,6 @@ ID ID `json:"id"` } -// Tag hold information for tag. -type Tag struct { - Name string `json:"name"` - URL string `json:"url"` - History []History `json:"history"` -} - // History hold information for history. type History struct { Day string `json:"day"` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/RasmusLindroth/go-mastodon/tags.go new/vendor/github.com/RasmusLindroth/go-mastodon/tags.go --- old/vendor/github.com/RasmusLindroth/go-mastodon/tags.go 1970-01-01 01:00:00.000000000 +0100 +++ new/vendor/github.com/RasmusLindroth/go-mastodon/tags.go 2022-11-23 20:03:29.000000000 +0100 @@ -0,0 +1,46 @@ +package mastodon + +import ( + "context" + "fmt" + "net/http" + "net/url" +) + +// Tag hold information for tag. +type Tag struct { + Name string `json:"name"` + URL string `json:"url"` + History []History `json:"history"` + Following interface{} `json:"following"` +} + +// TagInfo gets statistics and information about a tag +func (c *Client) TagInfo(ctx context.Context, tag string) (*Tag, error) { + var hashtag Tag + err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/tags/%s", url.PathEscape(string(tag))), nil, &hashtag, nil) + if err != nil { + return nil, err + } + return &hashtag, nil +} + +// TagFollow lets you follow a hashtag +func (c *Client) TagFollow(ctx context.Context, tag string) (*Tag, error) { + var hashtag Tag + err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/tags/%s/follow", url.PathEscape(string(tag))), nil, &hashtag, nil) + if err != nil { + return nil, err + } + return &hashtag, nil +} + +// TagUnfollow lets you unfollow a hashtag +func (c *Client) TagUnfollow(ctx context.Context, tag string) (*Tag, error) { + var hashtag Tag + err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/tags/%s/unfollow", url.PathEscape(string(tag))), nil, &hashtag, nil) + if err != nil { + return nil, err + } + return &hashtag, nil +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/modules.txt new/vendor/modules.txt --- old/vendor/modules.txt 2022-11-21 12:47:23.000000000 +0100 +++ new/vendor/modules.txt 2022-11-23 20:03:29.000000000 +0100 @@ -1,4 +1,4 @@ -# github.com/RasmusLindroth/go-mastodon v0.0.10 +# github.com/RasmusLindroth/go-mastodon v0.0.11 ## explicit; go 1.16 github.com/RasmusLindroth/go-mastodon # github.com/atotto/clipboard v0.1.4
