Browse Source

1.0.19 (#179)

* skip editor errors

* update version

* add update notification

* add history
pull/184/head
Rasmus Lindroth 3 years ago committed by GitHub
parent
commit
3c364fb448
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      README.md
  2. 12
      api/feed.go
  3. 56
      api/item.go
  4. 1
      api/stream.go
  5. 2
      auth/add.go
  6. 11
      config.example.ini
  7. 6
      config/config.go
  8. 11
      config/default_config.go
  9. 2
      config/toot.tmpl
  10. 74
      feed/feed.go
  11. 2
      go.mod
  12. 47
      go.sum
  13. 2
      main.go
  14. 5
      ui/cmdbar.go
  15. 13
      ui/commands.go
  16. 25
      ui/feed.go
  17. 56
      ui/input.go
  18. 37
      ui/item.go
  19. 22
      ui/item_notification.go
  20. 32
      ui/item_status.go
  21. 5
      ui/open.go
  22. 2
      ui/timeline.go

1
README.md

@ -46,6 +46,7 @@ You can find Linux binaries under [releases](https://github.com/RasmusLindroth/t
* `:favorited` lists toots you've favorited
* `:favorites` lists users that favorited the toot
* `:h` `:help` view help
* `:history` show edits of a toot
* `:lists` show a list of your lists
* `:list-placement` top, right, bottom, left
* `:list-split` row, column

12
api/feed.go

@ -98,6 +98,18 @@ func (ac *AccountClient) GetNotifications(pg *mastodon.Pagination) ([]Item, erro
return items, nil
}
func (ac *AccountClient) GetHistory(status *mastodon.Status) ([]Item, error) {
var items []Item
statuses, err := ac.Client.GetStatusHistory(context.Background(), status.ID)
if err != nil {
return items, err
}
for _, s := range statuses {
items = append(items, NewStatusHistoryItem(s))
}
return items, nil
}
func (ac *AccountClient) GetThread(status *mastodon.Status) ([]Item, error) {
var items []Item
statuses, err := ac.Client.GetStatusContext(context.Background(), status.ID)

56
api/item.go

@ -174,6 +174,57 @@ func (s *StatusItem) Pinned() bool {
return s.pinned
}
func NewStatusHistoryItem(item *mastodon.StatusHistory) (sitem Item) {
return &StatusHistoryItem{id: newID(), item: item, showSpoiler: false}
}
type StatusHistoryItem struct {
id uint
item *mastodon.StatusHistory
showSpoiler bool
}
func (s *StatusHistoryItem) ID() uint {
return s.id
}
func (s *StatusHistoryItem) Type() MastodonType {
return StatusHistoryType
}
func (s *StatusHistoryItem) ToggleSpoiler() {
s.showSpoiler = !s.showSpoiler
}
func (s *StatusHistoryItem) ShowSpoiler() bool {
return s.showSpoiler
}
func (s *StatusHistoryItem) Raw() interface{} {
return s.item
}
func (s *StatusHistoryItem) URLs() ([]util.URL, []mastodon.Mention, []mastodon.Tag, int) {
status := mastodon.Status{
Content: s.item.Content,
SpoilerText: s.item.SpoilerText,
Account: s.item.Account,
Sensitive: s.item.Sensitive,
CreatedAt: s.item.CreatedAt,
Emojis: s.item.Emojis,
MediaAttachments: s.item.MediaAttachments,
}
return getUrlsStatus(&status)
}
func (s *StatusHistoryItem) Filtered() (bool, string) {
return false, ""
}
func (s *StatusHistoryItem) Pinned() bool {
return false
}
func NewUserItem(item *User, profile bool) Item {
return &UserItem{id: newID(), item: item, profile: profile}
}
@ -282,12 +333,15 @@ func (n *NotificationItem) URLs() ([]util.URL, []mastodon.Mention, []mastodon.Ta
return getUrlsStatus(nd.Status.Raw().(*mastodon.Status))
case "poll":
return getUrlsStatus(nd.Status.Raw().(*mastodon.Status))
case "update":
return getUrlsStatus(nd.Status.Raw().(*mastodon.Status))
case "follow":
return getUrlsUser(nd.User.Raw().(*User).Data)
case "follow_request":
return getUrlsUser(nd.User.Raw().(*User).Data)
default:
return []util.URL{}, []mastodon.Mention{}, []mastodon.Tag{}, 0
}
return nil, nil, nil, 0
}
func (n *NotificationItem) Filtered() (bool, string) {

1
api/stream.go

@ -11,6 +11,7 @@ type MastodonType uint
const (
StatusType MastodonType = iota
StatusHistoryType
UserType
ProfileType
NotificationType

2
auth/add.go

@ -54,7 +54,7 @@ func AddAccount(ad *AccountData) *mastodon.Client {
}
util.OpenURL(srv.AuthURI)
fmt.Println("You need to autorize Tut to use your account. Your browser")
fmt.Println("You need to authorize Tut to use your account. Your browser")
fmt.Println("should've opened. If not you can use the URL below.")
fmt.Printf("\n%s\n\n", srv.AuthURI)

11
config.example.ini

@ -150,9 +150,9 @@ leader-timeout=1000
# comma.
#
# Available commands: home, direct, local, federated, clear-notifications,
# compose, blocking, bookmarks, saved, favorited, boosts, favorites, following,
# followers, muting, newer, preferences, profile, notifications, lists, tag,
# window, list-placement, list-split, proportions
# compose, history, blocking, bookmarks, saved, favorited, boosts, favorites,
# following, followers, muting, newer, preferences, profile, notifications,
# lists, tag, window, list-placement, list-split, proportions
#
# The shortcuts are up to you, but keep them quite short and make sure they
# don't collide. If you have one shortcut that is "f" and an other one that is
@ -174,6 +174,7 @@ leader-timeout=1000
# leader-action=lists,li
# leader-action=federated,fed
# leader-action=direct,d
# leader-action=history,h
# leader-action=tag linux,tl
# leader-action=window 0,h
# leader-action=list-placement bottom,b
@ -309,6 +310,10 @@ favorite=false
# default=false
mention=false
# Notification when someone edits their toot.
# default=false
update=false
# Notification when someone boosts one of your toots.
# default=false
boost=false

6
config/config.go

@ -74,6 +74,7 @@ const (
LeaderNotifications
LeaderLists
LeaderTag
LeaderHistory
LeaderUser
LeaderWindow
LeaderLoadNewer
@ -226,6 +227,7 @@ const (
NotificationFollower NotificationType = iota
NotificationFavorite
NotificationMention
NotificationUpdate
NotificationBoost
NotificationPoll
NotificationPost
@ -235,6 +237,7 @@ type Notification struct {
NotificationFollower bool
NotificationFavorite bool
NotificationMention bool
NotificationUpdate bool
NotificationBoost bool
NotificationPoll bool
NotificationPost bool
@ -862,6 +865,8 @@ func parseGeneral(cfg *ini.File) General {
la.Command = LeaderSaved
case "favorited":
la.Command = LeaderFavorited
case "history":
la.Command = LeaderHistory
case "boosts":
la.Command = LeaderBoosts
case "favorites":
@ -1131,6 +1136,7 @@ func parseNotifications(cfg *ini.File) Notification {
nc.NotificationFollower = cfg.Section("desktop-notification").Key("followers").MustBool(false)
nc.NotificationFavorite = cfg.Section("desktop-notification").Key("favorite").MustBool(false)
nc.NotificationMention = cfg.Section("desktop-notification").Key("mention").MustBool(false)
nc.NotificationUpdate = cfg.Section("desktop-notification").Key("update").MustBool(false)
nc.NotificationBoost = cfg.Section("desktop-notification").Key("boost").MustBool(false)
nc.NotificationPoll = cfg.Section("desktop-notification").Key("poll").MustBool(false)
nc.NotificationPost = cfg.Section("desktop-notification").Key("posts").MustBool(false)

11
config/default_config.go

@ -152,9 +152,9 @@ leader-timeout=1000
# comma.
#
# Available commands: home, direct, local, federated, clear-notifications,
# compose, blocking, bookmarks, saved, favorited, boosts, favorites, following,
# followers, muting, newer, preferences, profile, notifications, lists, tag,
# window, list-placement, list-split, proportions
# compose, history, blocking, bookmarks, saved, favorited, boosts, favorites,
# following, followers, muting, newer, preferences, profile, notifications,
# lists, tag, window, list-placement, list-split, proportions
#
# The shortcuts are up to you, but keep them quite short and make sure they
# don't collide. If you have one shortcut that is "f" and an other one that is
@ -176,6 +176,7 @@ leader-timeout=1000
# leader-action=lists,li
# leader-action=federated,fed
# leader-action=direct,d
# leader-action=history,h
# leader-action=tag linux,tl
# leader-action=window 0,h
# leader-action=list-placement bottom,b
@ -311,6 +312,10 @@ favorite=false
# default=false
mention=false
# Notification when someone edits their toot.
# default=false
update=false
# Notification when someone boosts one of your toots.
# default=false
boost=false

2
config/toot.tmpl

@ -17,7 +17,7 @@
{{ Color .Style.TextSpecial1 }}{{ .Toot.Account }}
{{- else -}}
{{ Color .Style.TextSpecial2 }}{{- .Toot.Account }}
{{- end }}
{{- end }} {{- if .Toot.Edited -}}{{ Color .Style.Subtle }} (edited toot){{ end }}
{{ if .Toot.Spoiler -}}
{{ Color .Style.Text }}{{ .Toot.SpoilerText }}

74
feed/feed.go

@ -17,6 +17,7 @@ type apiIDFunc func(pg *mastodon.Pagination, id mastodon.ID) ([]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)
type apiHistoryFunc func(status *mastodon.Status) ([]api.Item, error)
type FeedType uint
@ -29,6 +30,7 @@ const (
FollowRequests
Blocking
Muting
History
InvalidFeed
Notification
Saved
@ -52,10 +54,11 @@ type LoadingLock struct {
type DesktopNotificationType uint
const (
DekstopNotificationNone DesktopNotificationType = iota
DeskstopNotificationNone DesktopNotificationType = iota
DesktopNotificationFollower
DesktopNotificationFavorite
DesktopNotificationMention
DesktopNotificationUpdate
DesktopNotificationBoost
DesktopNotificationPoll
DesktopNotificationPost
@ -100,14 +103,14 @@ func (f *Feed) Delete(id uint) {
}
}
f.items = items
f.Updated(DekstopNotificationNone)
f.Updated(DeskstopNotificationNone)
}
func (f *Feed) Clear() {
f.itemsMux.Lock()
defer f.itemsMux.Unlock()
f.items = []api.Item{}
f.Updated(DekstopNotificationNone)
f.Updated(DeskstopNotificationNone)
}
func (f *Feed) Item(index int) (api.Item, error) {
@ -142,7 +145,7 @@ func (f *Feed) LoadNewer() {
return
}
f.loadNewer()
f.Updated(DekstopNotificationNone)
f.Updated(DeskstopNotificationNone)
f.loadingNewer.last = time.Now()
f.loadingNewer.mux.Unlock()
}
@ -160,7 +163,7 @@ func (f *Feed) LoadOlder() {
return
}
f.loadOlder()
f.Updated(DekstopNotificationNone)
f.Updated(DeskstopNotificationNone)
f.loadingOlder.last = time.Now()
f.loadingOlder.mux.Unlock()
}
@ -191,7 +194,7 @@ func (f *Feed) singleNewerSearch(fn apiSearchFunc, search string) {
f.itemsMux.Lock()
if len(items) > 0 {
f.items = append(items, f.items...)
f.Updated(DekstopNotificationNone)
f.Updated(DeskstopNotificationNone)
}
f.itemsMux.Unlock()
}
@ -204,7 +207,20 @@ func (f *Feed) singleThread(fn apiThreadFunc, status *mastodon.Status) {
f.itemsMux.Lock()
if len(items) > 0 {
f.items = append(items, f.items...)
f.Updated(DekstopNotificationNone)
f.Updated(DeskstopNotificationNone)
}
f.itemsMux.Unlock()
}
func (f *Feed) singleHistory(fn apiHistoryFunc, status *mastodon.Status) {
items, err := fn(status)
if err != nil {
return
}
f.itemsMux.Lock()
if len(items) > 0 {
f.items = append(items, f.items...)
f.Updated(DeskstopNotificationNone)
}
f.itemsMux.Unlock()
}
@ -237,7 +253,7 @@ func (f *Feed) normalNewer(fn apiFunc) {
}
}
f.items = append(items, f.items...)
f.Updated(DekstopNotificationNone)
f.Updated(DeskstopNotificationNone)
}
f.itemsMux.Unlock()
f.apiDataMux.Unlock()
@ -266,7 +282,7 @@ func (f *Feed) normalOlder(fn apiFunc) {
f.apiData.MaxID = item.Item.ID
}
f.items = append(f.items, items...)
f.Updated(DekstopNotificationNone)
f.Updated(DeskstopNotificationNone)
}
f.itemsMux.Unlock()
f.apiDataMux.Unlock()
@ -288,7 +304,7 @@ func (f *Feed) newerSearchPG(fn apiSearchPGFunc, search string) {
item := items[0].Raw().(*mastodon.Status)
f.apiData.MinID = item.ID
f.items = append(items, f.items...)
f.Updated(DekstopNotificationNone)
f.Updated(DeskstopNotificationNone)
if f.apiData.MaxID == mastodon.ID("") {
item = items[len(items)-1].Raw().(*mastodon.Status)
f.apiData.MaxID = item.ID
@ -317,7 +333,7 @@ func (f *Feed) olderSearchPG(fn apiSearchPGFunc, search string) {
item := items[len(items)-1].Raw().(*mastodon.Status)
f.apiData.MaxID = item.ID
f.items = append(f.items, items...)
f.Updated(DekstopNotificationNone)
f.Updated(DeskstopNotificationNone)
}
f.itemsMux.Unlock()
f.apiDataMux.Unlock()
@ -339,7 +355,7 @@ func (f *Feed) normalNewerUser(fn apiIDFunc, id mastodon.ID) {
item := items[0].Raw().(*mastodon.Status)
f.apiData.MinID = item.ID
f.items = append(items, f.items...)
f.Updated(DekstopNotificationNone)
f.Updated(DeskstopNotificationNone)
if f.apiData.MaxID == mastodon.ID("") {
item = items[len(items)-1].Raw().(*mastodon.Status)
f.apiData.MaxID = item.ID
@ -368,7 +384,7 @@ func (f *Feed) normalOlderUser(fn apiIDFunc, id mastodon.ID) {
item := items[len(items)-1].Raw().(*mastodon.Status)
f.apiData.MaxID = item.ID
f.items = append(f.items, items...)
f.Updated(DekstopNotificationNone)
f.Updated(DeskstopNotificationNone)
}
f.itemsMux.Unlock()
f.apiDataMux.Unlock()
@ -390,7 +406,7 @@ func (f *Feed) normalNewerID(fn apiIDFunc, id mastodon.ID) {
item := items[0].Raw().(*mastodon.Status)
f.apiData.MinID = item.ID
f.items = append(items, f.items...)
f.Updated(DekstopNotificationNone)
f.Updated(DeskstopNotificationNone)
if f.apiData.MaxID == mastodon.ID("") {
item = items[len(items)-1].Raw().(*mastodon.Status)
f.apiData.MaxID = item.ID
@ -419,7 +435,7 @@ func (f *Feed) normalOlderID(fn apiIDFunc, id mastodon.ID) {
item := items[len(items)-1].Raw().(*mastodon.Status)
f.apiData.MaxID = item.ID
f.items = append(f.items, items...)
f.Updated(DekstopNotificationNone)
f.Updated(DeskstopNotificationNone)
}
f.itemsMux.Unlock()
f.apiDataMux.Unlock()
@ -433,7 +449,7 @@ func (f *Feed) normalEmpty(fn apiEmptyFunc) {
f.itemsMux.Lock()
if len(items) > 0 {
f.items = append(f.items, items...)
f.Updated(DekstopNotificationNone)
f.Updated(DeskstopNotificationNone)
}
f.itemsMux.Unlock()
}
@ -459,7 +475,7 @@ func (f *Feed) linkNewer(fn apiFunc) {
f.itemsMux.Lock()
if len(items) > 0 {
f.items = append(items, f.items...)
f.Updated(DekstopNotificationNone)
f.Updated(DeskstopNotificationNone)
}
f.itemsMux.Unlock()
}
@ -484,7 +500,7 @@ func (f *Feed) linkOlder(fn apiFunc) {
f.itemsMux.Lock()
if len(items) > 0 {
f.items = append(f.items, items...)
f.Updated(DekstopNotificationNone)
f.Updated(DeskstopNotificationNone)
}
f.itemsMux.Unlock()
}
@ -510,7 +526,7 @@ func (f *Feed) linkNewerID(fn apiIDFunc, id mastodon.ID) {
f.itemsMux.Lock()
if len(items) > 0 {
f.items = append(items, f.items...)
f.Updated(DekstopNotificationNone)
f.Updated(DeskstopNotificationNone)
}
f.itemsMux.Unlock()
}
@ -535,7 +551,7 @@ func (f *Feed) linkOlderID(fn apiIDFunc, id mastodon.ID) {
f.itemsMux.Lock()
if len(items) > 0 {
f.items = append(f.items, items...)
f.Updated(DekstopNotificationNone)
f.Updated(DeskstopNotificationNone)
}
f.itemsMux.Unlock()
}
@ -584,7 +600,7 @@ func (f *Feed) startStreamNotification(rec *api.Receiver, timeline string, err e
}, f.accountClient.Filters)
f.itemsMux.Lock()
f.items = append([]api.Item{s}, f.items...)
nft := DekstopNotificationNone
nft := DeskstopNotificationNone
switch t.Notification.Type {
case "follow", "follow_request":
nft = DesktopNotificationFollower
@ -594,10 +610,14 @@ func (f *Feed) startStreamNotification(rec *api.Receiver, timeline string, err e
nft = DesktopNotificationBoost
case "mention":
nft = DesktopNotificationMention
case "update":
nft = DesktopNotificationUpdate
case "status":
nft = DesktopNotificationPost
case "poll":
nft = DesktopNotificationPoll
default:
nft = DeskstopNotificationNone
}
f.Updated(nft)
f.itemsMux.Unlock()
@ -716,6 +736,18 @@ func NewThread(ac *api.AccountClient, status *mastodon.Status) *Feed {
return feed
}
func NewHistory(ac *api.AccountClient, status *mastodon.Status) *Feed {
feed := newFeed(ac, History)
once := true
feed.loadNewer = func() {
if once {
feed.singleHistory(feed.accountClient.GetHistory, status)
once = false
}
}
return feed
}
func NewTag(ac *api.AccountClient, search string) *Feed {
feed := newFeed(ac, Tag)
feed.name = search

2
go.mod

@ -3,7 +3,7 @@ module github.com/RasmusLindroth/tut
go 1.18
require (
github.com/RasmusLindroth/go-mastodon v0.0.9
github.com/RasmusLindroth/go-mastodon v0.0.10
github.com/atotto/clipboard v0.1.4
github.com/gdamore/tcell/v2 v2.5.3
github.com/gen2brain/beeep v0.0.0-20220909211152-5a9ec94374f6

47
go.sum

@ -1,22 +1,16 @@
github.com/RasmusLindroth/go-mastodon v0.0.8 h1:t2rrbdNgS4h0JhmPNsmUOQBByDxmUPawnERGn6oR2eA=
github.com/RasmusLindroth/go-mastodon v0.0.8/go.mod h1:4L0oyiNwq1tUoiByczzhSikxR9RiANzELtZgexxKpPM=
github.com/RasmusLindroth/go-mastodon v0.0.9 h1:3Moqcs5mr65SUgofwfB4eEiKgwMpbRl3ncfyxu+DFjw=
github.com/RasmusLindroth/go-mastodon v0.0.9/go.mod h1:Lr6n8V1U2b+9P89YZKsICkNc+oNeJXkygY7raei9SXE=
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/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=
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/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell/v2 v2.5.2 h1:tKzG29kO9p2V++3oBY2W9zUjYu7IK1MENFeY/BzJSVY=
github.com/gdamore/tcell/v2 v2.5.2/go.mod h1:wSkrPaXoiIWZqW/g7Px4xc79di6FTcpB8tvaKJ6uGBo=
github.com/gdamore/tcell/v2 v2.5.3 h1:b9XQrT6QGbgI7JvZOJXFNczOQeIYbo8BfeSMzt2sAV0=
github.com/gdamore/tcell/v2 v2.5.3/go.mod h1:wSkrPaXoiIWZqW/g7Px4xc79di6FTcpB8tvaKJ6uGBo=
github.com/gen2brain/beeep v0.0.0-20220518085355-d7852edf42fc h1:6ZZLxG+lB+Qbg+chtzAEeetwqjlPnY0BXbhL3lQWYOg=
github.com/gen2brain/beeep v0.0.0-20220518085355-d7852edf42fc/go.mod h1:/WeFVhhxMOGypVKS0w8DUJxUBbHypnWkUVnW7p5c9Pw=
github.com/gen2brain/beeep v0.0.0-20220909211152-5a9ec94374f6 h1:jFEK/SA/7E8lg9T33+y8D4Z0I782+bbiEjmyyklRzRQ=
github.com/gen2brain/beeep v0.0.0-20220909211152-5a9ec94374f6/go.mod h1:/WeFVhhxMOGypVKS0w8DUJxUBbHypnWkUVnW7p5c9Pw=
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 h1:qZNfIGkIANxGv/OqtnntR4DfOY2+BgwR60cAcu/i3SE=
@ -29,81 +23,48 @@ github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/icza/gox v0.0.0-20220812133721-0fbf7a534d8e h1:vD4inAaWEbFk4Dpu1Y+m9URk8s6dOif7pBW5pW7fAak=
github.com/icza/gox v0.0.0-20220812133721-0fbf7a534d8e/go.mod h1:VbcN86fRkkUMPX2ufM85Um8zFndLZswoIW1eYtpAcVk=
github.com/icza/gox v0.0.0-20221026131554-a08a8cdc726a h1:ctOSka++0Y+9xF7VLtZ8TOJjyXjOGYywzuhbzj3IEHw=
github.com/icza/gox v0.0.0-20221026131554-a08a8cdc726a/go.mod h1:VbcN86fRkkUMPX2ufM85Um8zFndLZswoIW1eYtpAcVk=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/microcosm-cc/bluemonday v1.0.19 h1:OI7hoF5FY4pFz2VA//RN8TfM0YJ2dJcl4P4APrCWy6c=
github.com/microcosm-cc/bluemonday v1.0.19/go.mod h1:QNzV2UbLK2/53oIIwTOyLUSABMkjZ4tqiyC1g/DyqxE=
github.com/microcosm-cc/bluemonday v1.0.21 h1:dNH3e4PSyE4vNX+KlRGHT5KrSvjeUkoNPwEORjffHJg=
github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM=
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/v2 v2.0.2 h1:+jQXlF3scKIcSEKkdHzXhCTDLPFi5r1wnK6yPS+49Gw=
github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI=
github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
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-20220812085834-0e6b21a48e96 h1:O435d1KIgG6KxpP7NDdmj7SdaLIzq4F+PG8ZB/BHC4c=
github.com/rivo/tview v0.0.0-20220812085834-0e6b21a48e96/go.mod h1:hyzpnqn4KWzZopTEjL1AxvlzOLMH1IuKo4lTw6vyOQc=
github.com/rivo/tview v0.0.0-20221029100920-c4a7e501810d h1:jKIUJdMcIVGOSHi6LSqJqw9RqblyblE2ZrHvFbWR3S0=
github.com/rivo/tview v0.0.0-20221029100920-c4a7e501810d/go.mod h1:YX2wUZOcJGOIycErz2s9KvDaP0jnWwRCirQMPLPpQ+Y=
github.com/rivo/tview v0.0.0-20221115143349-ed3ea789e9f7 h1:9m4q3Li2CP/O4yfbZYJhySCuUg/VpV4jZhpvUcUYu8E=
github.com/rivo/tview v0.0.0-20221115143349-ed3ea789e9f7/go.mod h1:YX2wUZOcJGOIycErz2s9KvDaP0jnWwRCirQMPLPpQ+Y=
github.com/rivo/tview v0.0.0-20221117065207-09f052e6ca98 h1:0nVxhPi+jdqG11c3n4zTcZQbjGy0yi60ym/6B+NITPU=
github.com/rivo/tview v0.0.0-20221117065207-09f052e6ca98/go.mod h1:YX2wUZOcJGOIycErz2s9KvDaP0jnWwRCirQMPLPpQ+Y=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.3.4 h1:3Z3Eu6FGHZWSfNKJTOUiPatWwfc7DzJRU04jFUqJODw=
github.com/rivo/uniseg v0.3.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8=
github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
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=
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE=
golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E=
golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220318055525-2edf467146b5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 h1:UiNENfZ8gDvpiWw7IpOMQ27spWmThO1RwwdQVbJahJM=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 h1:Q5284mrmYTpACcm+eAKjKJH48BBwSyfJqmmGDTtT8Vc=
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=

2
main.go

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

5
ui/cmdbar.go

@ -88,6 +88,9 @@ func (c *CmdBar) DoneFunc(key tcell.Key) {
case ":followers":
c.tutView.FollowersCommand()
c.Back()
case ":history":
c.tutView.HistoryCommand()
c.Back()
case ":newer":
c.tutView.LoadNewerCommand()
c.Back()
@ -208,7 +211,7 @@ func (c *CmdBar) DoneFunc(key tcell.Key) {
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,:lists,:list-placement,:list-split,:muting,:newer,:preferences,:profile,:proportions,:requests,:saved,:tag,:timeline,:tl,:user,:window,:quit,:q", ",")
words := strings.Split(":blocking,:boosts,:bookmarks,:clear-notifications,:compose,:favorites,:favorited,:followers,:following,:help,:h,:history,:lists,:list-placement,:list-split,:muting,:newer,:preferences,:profile,:proportions,:requests,:saved,:tag,:timeline,:tl,:user,:window,:quit,:q", ",")
if curr == "" {
return entries
}

13
ui/commands.go

@ -155,6 +155,19 @@ func (tv *TutView) FollowersCommand() {
)
}
func (tv *TutView) HistoryCommand() {
item, itemErr := tv.GetCurrentItem()
if itemErr != nil {
return
}
if item.Type() != api.StatusType {
return
}
tv.Timeline.AddFeed(
NewHistoryFeed(tv, item),
)
}
func (tv *TutView) ProfileCommand() {
item, err := tv.tut.Client.GetUserByID(tv.tut.Client.Me.ID)
if err != nil {

25
ui/feed.go

@ -102,6 +102,10 @@ func (f *Feed) update() {
if f.tutView.tut.Config.NotificationConfig.NotificationMention {
beeep.Notify("Mentioned you", "", "")
}
case feed.DesktopNotificationUpdate:
if f.tutView.tut.Config.NotificationConfig.NotificationUpdate {
beeep.Notify("Changed their toot", "", "")
}
case feed.DesktopNotificationBoost:
if f.tutView.tut.Config.NotificationConfig.NotificationBoost {
beeep.Notify("Boosted your toot", "", "")
@ -214,6 +218,27 @@ func NewThreadFeed(tv *TutView, item api.Item) *Feed {
return fd
}
func NewHistoryFeed(tv *TutView, item api.Item) *Feed {
status := util.StatusOrReblog(item.Raw().(*mastodon.Status))
f := feed.NewHistory(tv.tut.Client, status)
f.LoadNewer()
fd := &Feed{
tutView: tv,
Data: f,
ListIndex: 0,
List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut),
}
for _, s := range f.List() {
main, symbol := DrawListItem(tv.tut.Config, s)
fd.List.AddItem(main, symbol, s.ID())
}
fd.List.SetCurrentItem(0)
fd.DrawContent()
return fd
}
func NewConversationsFeed(tv *TutView) *Feed {
f := feed.NewConversations(tv.tut.Client)
f.LoadNewer()

56
ui/input.go

@ -125,6 +125,8 @@ func (tv *TutView) InputLeaderKey(event *tcell.EventKey) *tcell.EventKey {
tv.BookmarksCommand()
case config.LeaderFavorited:
tv.FavoritedCommand()
case config.LeaderHistory:
tv.HistoryCommand()
case config.LeaderBoosts:
tv.BoostsCommand()
case config.LeaderFavorites:
@ -299,6 +301,8 @@ func (tv *TutView) InputItem(event *tcell.EventKey) *tcell.EventKey {
switch item.Type() {
case api.StatusType:
return tv.InputStatus(event, item, item.Raw().(*mastodon.Status), nil)
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)
@ -318,6 +322,8 @@ func (tv *TutView) InputItem(event *tcell.EventKey) *tcell.EventKey {
return tv.InputStatus(event, nd.Status, nd.Status.Raw().(*mastodon.Status), user.Data)
case "mention":
return tv.InputStatus(event, nd.Status, nd.Status.Raw().(*mastodon.Status), nil)
case "update":
return tv.InputStatus(event, nd.Status, nd.Status.Raw().(*mastodon.Status), nil)
case "status":
return tv.InputStatus(event, nd.Status, nd.Status.Raw().(*mastodon.Status), nil)
case "poll":
@ -492,6 +498,56 @@ func (tv *TutView) InputStatus(event *tcell.EventKey, item api.Item, status *mas
return event
}
func (tv *TutView) InputStatusHistory(event *tcell.EventKey, item api.Item, sr *mastodon.StatusHistory, nAcc *mastodon.Account) *tcell.EventKey {
hasMedia := len(sr.MediaAttachments) > 0
hasSpoiler := sr.Sensitive
status := &mastodon.Status{
Content: sr.Content,
SpoilerText: sr.SpoilerText,
Account: sr.Account,
Sensitive: sr.Sensitive,
CreatedAt: sr.CreatedAt,
Emojis: sr.Emojis,
MediaAttachments: sr.MediaAttachments,
}
if tv.tut.Config.Input.StatusAvatar.Match(event.Key(), event.Rune()) {
if nAcc != nil {
openAvatar(tv, *nAcc)
} else {
openAvatar(tv, sr.Account)
}
return nil
}
if tv.tut.Config.Input.StatusMedia.Match(event.Key(), event.Rune()) {
if hasMedia {
openMedia(tv, status)
}
return nil
}
if tv.tut.Config.Input.StatusLinks.Match(event.Key(), event.Rune()) {
tv.SetPage(LinkFocus)
return nil
}
if tv.tut.Config.Input.StatusViewFocus.Match(event.Key(), event.Rune()) {
tv.SetPage(ViewFocus)
return nil
}
if tv.tut.Config.Input.StatusToggleSpoiler.Match(event.Key(), event.Rune()) {
if !hasSpoiler {
return nil
}
if !item.ShowSpoiler() {
item.ToggleSpoiler()
tv.RedrawContent()
}
return nil
}
return event
}
func (tv *TutView) InputUser(event *tcell.EventKey, user *api.User, fr bool) *tcell.EventKey {
blocking := user.Relation.Blocking
muting := user.Relation.Muting

37
ui/item.go

@ -34,6 +34,11 @@ func DrawListItem(cfg *config.Config, item api.Item) (string, string) {
}
d := OutputDate(cfg, s.CreatedAt.Local())
return fmt.Sprintf("%s %s", d, acc), symbol
case api.StatusHistoryType:
s := item.Raw().(*mastodon.StatusHistory)
acc := strings.TrimSpace(s.Account.Acct)
d := OutputDate(cfg, s.CreatedAt.Local())
return fmt.Sprintf("%s %s", d, acc), ""
case api.UserType:
a := item.Raw().(*api.User)
return strings.TrimSpace(a.Data.Acct), ""
@ -51,6 +56,8 @@ func DrawListItem(cfg *config.Config, item api.Item) (string, string) {
symbol = " ♺ "
case "mention":
symbol = " ⤶ "
case "update":
symbol = " ☢ "
case "poll":
symbol = " = "
case "status":
@ -69,7 +76,20 @@ func DrawListItem(cfg *config.Config, item api.Item) (string, string) {
func DrawItem(tv *TutView, item api.Item, main *tview.TextView, controls *tview.Flex, ft feed.FeedType) {
switch item.Type() {
case api.StatusType:
drawStatus(tv, item, item.Raw().(*mastodon.Status), main, controls, "")
drawStatus(tv, item, item.Raw().(*mastodon.Status), main, controls, false, "")
case api.StatusHistoryType:
s := item.Raw().(*mastodon.StatusHistory)
status := mastodon.Status{
Content: s.Content,
SpoilerText: s.SpoilerText,
Account: s.Account,
Sensitive: s.Sensitive,
CreatedAt: s.CreatedAt,
Emojis: s.Emojis,
MediaAttachments: s.MediaAttachments,
Visibility: mastodon.VisibilityPublic,
}
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)
@ -86,7 +106,20 @@ func DrawItem(tv *TutView, item api.Item, main *tview.TextView, controls *tview.
func DrawItemControls(tv *TutView, item api.Item, controls *tview.Flex, ft feed.FeedType) {
switch item.Type() {
case api.StatusType:
drawStatus(tv, item, item.Raw().(*mastodon.Status), nil, controls, "")
drawStatus(tv, item, item.Raw().(*mastodon.Status), nil, controls, false, "")
case api.StatusHistoryType:
s := item.Raw().(*mastodon.StatusHistory)
status := mastodon.Status{
Content: s.Content,
SpoilerText: s.SpoilerText,
Account: s.Account,
Sensitive: s.Sensitive,
CreatedAt: s.CreatedAt,
Emojis: s.Emojis,
MediaAttachments: s.MediaAttachments,
Visibility: mastodon.VisibilityPublic,
}
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)

22
ui/item_notification.go

@ -4,6 +4,7 @@ import (
"fmt"
"github.com/RasmusLindroth/tut/api"
"github.com/RasmusLindroth/tut/config"
"github.com/RasmusLindroth/tut/util"
"github.com/rivo/tview"
)
@ -15,23 +16,27 @@ func drawNotification(tv *TutView, item api.Item, notification *api.Notification
fmt.Sprintf("%s started following you", util.FormatUsername(notification.Item.Account)), false,
)
case "favourite":
drawStatus(tv, notification.Status, notification.Item.Status, main, controls,
drawStatus(tv, notification.Status, notification.Item.Status, main, controls, false,
fmt.Sprintf("%s favorited your toot", util.FormatUsername(notification.Item.Account)),
)
case "reblog":
drawStatus(tv, notification.Status, notification.Item.Status, main, controls,
drawStatus(tv, notification.Status, notification.Item.Status, main, controls, false,
fmt.Sprintf("%s boosted your toot", util.FormatUsername(notification.Item.Account)),
)
case "mention":
drawStatus(tv, notification.Status, notification.Item.Status, main, controls,
drawStatus(tv, notification.Status, notification.Item.Status, main, controls, false,
fmt.Sprintf("%s mentioned you", util.FormatUsername(notification.Item.Account)),
)
case "update":
drawStatus(tv, notification.Status, notification.Item.Status, main, controls, false,
fmt.Sprintf("%s updated their toot", util.FormatUsername(notification.Item.Account)),
)
case "status":
drawStatus(tv, notification.Status, notification.Item.Status, main, controls,
drawStatus(tv, notification.Status, notification.Item.Status, main, controls, false,
fmt.Sprintf("%s posted a new toot", util.FormatUsername(notification.Item.Account)),
)
case "poll":
drawStatus(tv, notification.Status, notification.Item.Status, main, controls,
drawStatus(tv, notification.Status, notification.Item.Status, main, controls, false,
"A poll of yours or one you participated in has ended",
)
case "follow_request":
@ -39,5 +44,12 @@ func drawNotification(tv *TutView, item api.Item, notification *api.Notification
fmt.Sprintf("%s wants to follow you.", util.FormatUsername(notification.Item.Account)),
true,
)
default:
controls.Clear()
text := fmt.Sprintf("%s\n", config.SublteText(tv.tut.Config,
fmt.Sprintf("Notification \"%s\" is not implemented. Open an issue at https://github.com/RasmusLindroth/tut",
notification.Item.Type),
))
main.SetText(text)
}
}

32
ui/item_status.go

@ -33,6 +33,7 @@ type Toot struct {
Replies int
Boosts int
Favorites int
Edited bool
Controls string
}
@ -70,7 +71,7 @@ type DisplayTootData struct {
Style config.Style
}
func drawStatus(tv *TutView, item api.Item, status *mastodon.Status, main *tview.TextView, controls *tview.Flex, additional string) {
func drawStatus(tv *TutView, item api.Item, status *mastodon.Status, main *tview.TextView, controls *tview.Flex, isHistory bool, additional string) {
filtered, phrase := item.Filtered()
if filtered {
var output string
@ -119,6 +120,7 @@ func drawStatus(tv *TutView, item api.Item, status *mastodon.Status, main *tview
toot.Bookmarked = status.Bookmarked
toot.Visibility = status.Visibility
toot.Spoiler = status.Sensitive
toot.Edited = status.CreatedAt.Before(status.EditedAt)
if status.Poll != nil {
p := *status.Poll
@ -188,20 +190,22 @@ func drawStatus(tv *TutView, item api.Item, status *mastodon.Status, main *tview
}
var info []Control
if status.Favourited {
if status.Favourited && !isHistory {
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusFavorite, false))
} else {
} else if !status.Favourited && !isHistory {
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusFavorite, true))
}
if status.Reblogged {
if status.Reblogged && !isHistory {
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusBoost, false))
} else {
} else if !status.Reblogged && !isHistory {
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusBoost, true))
}
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusThread, true))
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusReply, true))
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusViewFocus, true))
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusUser, true))
if !isHistory {
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusThread, true))
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusReply, true))
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusViewFocus, true))
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusUser, true))
}
if len(status.MediaAttachments) > 0 {
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusMedia, true))
}
@ -210,16 +214,18 @@ func drawStatus(tv *TutView, item api.Item, status *mastodon.Status, main *tview
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusLinks, true))
}
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusAvatar, true))
if status.Account.ID == tv.tut.Client.Me.ID {
if status.Account.ID == tv.tut.Client.Me.ID && !isHistory {
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusDelete, true))
}
if !status.Bookmarked {
if !status.Bookmarked && !isHistory {
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusBookmark, true))
} else {
} else if status.Bookmarked && !isHistory {
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusBookmark, false))
}
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusYank, true))
if !isHistory {
info = append(info, NewControl(tv.tut.Config, tv.tut.Config.Input.StatusYank, true))
}
controls.Clear()
for i, item := range info {

5
ui/open.go

@ -106,10 +106,7 @@ func OpenEditor(tv *TutView, content string) (string, error) {
cmd.Stderr = os.Stderr
var text []byte
tv.tut.App.Suspend(func() {
err = cmd.Run()
if err != nil {
log.Fatalln(err)
}
cmd.Run()
text, err = os.ReadFile(fname)
})
os.Remove(fname)

2
ui/timeline.go

@ -151,6 +151,8 @@ func (tl *Timeline) GetTitle() string {
ct = fmt.Sprintf("tag #%s", name)
case feed.Thread:
ct = "thread feed"
case feed.History:
ct = "history feed"
case feed.TimelineFederated:
ct = "federated"
case feed.TimelineHome:

Loading…
Cancel
Save