Browse Source

1.0.11 (#152)

* fix filters and add sticky

* upgrade packages

* update version

* Input user on original user, not reblog

* update example config

* update readme
pull/156/head 1.0.11
Rasmus Lindroth 4 years ago committed by GitHub
parent
commit
9b7aaa3a35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      README.md
  2. 64
      api/feed.go
  3. 68
      api/item.go
  4. 10
      config.example.ini
  5. 50
      config/config.go
  6. 10
      config/default_config.go
  7. 78
      feed/feed.go
  8. 6
      go.mod
  9. 12
      go.sum
  10. BIN
      images/preview2.png
  11. 2
      main.go
  12. 2
      ui/cliview.go
  13. 54
      ui/feed.go
  14. 4
      ui/input.go
  15. 11
      ui/item.go
  16. 18
      ui/item_status.go

9
README.md

@ -1,4 +1,9 @@
# Tut - a Mastodon TUI # Tut - a Mastodon TUI
[![Release](https://badgen.net/github/release/RasmusLindroth/tut)](https://github.com/RasmusLindroth/tut/releases)
[![web](https://badgen.net/badge/web/tut.anv.nu/f92672)](https://tut.anv.nu)
[![tut](https://badgen.net/badge/AUR/tut/08c)](https://aur.archlinux.org/packages/tut)
[![tut-bin](https://badgen.net/badge/AUR/tut-bin/08c)](https://aur.archlinux.org/packages/tut-bin)
[![@tut](https://badgen.net/mastodon/follow/tut@fosstodon.org)](https://fosstodon.org/@tut)
A TUI for Mastodon with vim inspired keys. The program has most of the A TUI for Mastodon with vim inspired keys. The program has most of the
features you can find in the web client. features you can find in the web client.
@ -8,6 +13,7 @@ Press `C` to create a new toot and `N` to focus on your notifications.
You can find Linux binaries under [releases](https://github.com/RasmusLindroth/tut/releases). You can find Linux binaries under [releases](https://github.com/RasmusLindroth/tut/releases).
![Preview](./images/preview.png "Preview") ![Preview](./images/preview.png "Preview")
![Preview 2](./images/preview2.png "Preview 2")
## Table of contents ## Table of contents
@ -85,6 +91,7 @@ Head over to https://github.com/RasmusLindroth/tut/releases
You can find it in the Arch User Repository (AUR). I'm the maintainer there. You can find it in the Arch User Repository (AUR). I'm the maintainer there.
https://aur.archlinux.org/packages/tut/ https://aur.archlinux.org/packages/tut/
https://aur.archlinux.org/packages/tut-bin/
You can also use `tut-mastodon`. Currently `aur/tut` collides with a package You can also use `tut-mastodon`. Currently `aur/tut` collides with a package
named `tut` if you're running Manjaro ARM. So if you face the same problem you named `tut` if you're running Manjaro ARM. So if you face the same problem you
@ -127,7 +134,7 @@ cd tut
# Build or install # Build or install
# Install (usally /home/user/go/bin) # Install (usually /home/user/go/bin)
go install go install
# Build (same directory i.e. ./ ) # Build (same directory i.e. ./ )

64
api/feed.go

@ -15,10 +15,8 @@ func (ac *AccountClient) getStatusSimilar(fn func() ([]*mastodon.Status, error),
return items, err return items, err
} }
for _, s := range statuses { for _, s := range statuses {
item, filtered := NewStatusItem(s, ac.Filters, filter) item := NewStatusItem(s, ac.Filters, filter, false)
if !filtered { items = append(items, item)
items = append(items, item)
}
} }
return items, nil return items, nil
} }
@ -89,12 +87,10 @@ func (ac *AccountClient) GetNotifications(pg *mastodon.Pagination) ([]Item, erro
for _, n := range notifications { for _, n := range notifications {
for _, r := range rel { for _, r := range rel {
if n.Account.ID == r.ID { if n.Account.ID == r.ID {
item, filtered := NewNotificationItem(n, &User{ item := NewNotificationItem(n, &User{
Data: &n.Account, Relation: r, Data: &n.Account, Relation: r,
}, ac.Filters) }, ac.Filters)
if !filtered { items = append(items, item)
items = append(items, item)
}
break break
} }
} }
@ -102,29 +98,20 @@ func (ac *AccountClient) GetNotifications(pg *mastodon.Pagination) ([]Item, erro
return items, nil return items, nil
} }
func (ac *AccountClient) GetThread(status *mastodon.Status) ([]Item, int, error) { func (ac *AccountClient) GetThread(status *mastodon.Status) ([]Item, error) {
var items []Item var items []Item
statuses, err := ac.Client.GetStatusContext(context.Background(), status.ID) statuses, err := ac.Client.GetStatusContext(context.Background(), status.ID)
if err != nil { if err != nil {
return items, 0, err return items, err
} }
for _, s := range statuses.Ancestors { for _, s := range statuses.Ancestors {
item, filtered := NewStatusItem(s, ac.Filters, "thread") items = append(items, NewStatusItem(s, ac.Filters, "thread", false))
if !filtered {
items = append(items, item)
}
}
item, filtered := NewStatusItem(status, ac.Filters, "thread")
if !filtered {
items = append(items, item)
} }
items = append(items, NewStatusItem(status, ac.Filters, "thread", false))
for _, s := range statuses.Descendants { for _, s := range statuses.Descendants {
item, filtered := NewStatusItem(s, ac.Filters, "thread") items = append(items, NewStatusItem(s, ac.Filters, "thread", false))
if !filtered {
items = append(items, item)
}
} }
return items, len(statuses.Ancestors), nil return items, nil
} }
func (ac *AccountClient) GetFavorites(pg *mastodon.Pagination) ([]Item, error) { func (ac *AccountClient) GetFavorites(pg *mastodon.Pagination) ([]Item, error) {
@ -148,10 +135,8 @@ func (ac *AccountClient) GetConversations(pg *mastodon.Pagination) ([]Item, erro
return items, err return items, err
} }
for _, c := range conversations { for _, c := range conversations {
item, filtered := NewStatusItem(c.LastStatus, ac.Filters, "thread") item := NewStatusItem(c.LastStatus, ac.Filters, "thread", false)
if !filtered { items = append(items, item)
items = append(items, item)
}
} }
return items, nil return items, nil
} }
@ -240,10 +225,21 @@ func (ac *AccountClient) GetUser(pg *mastodon.Pagination, id mastodon.ID) ([]Ite
return items, err return items, err
} }
for _, s := range statuses { for _, s := range statuses {
item, filtered := NewStatusItem(s, ac.Filters, "account") item := NewStatusItem(s, ac.Filters, "account", false)
if !filtered { items = append(items, item)
items = append(items, item) }
} return items, nil
}
func (ac *AccountClient) GetUserPinned(id mastodon.ID) ([]Item, error) {
var items []Item
statuses, err := ac.Client.GetAccountPinnedStatuses(context.Background(), id)
if err != nil {
return items, err
}
for _, s := range statuses {
item := NewStatusItem(s, ac.Filters, "account", true)
items = append(items, item)
} }
return items, nil return items, nil
} }
@ -267,10 +263,8 @@ func (ac *AccountClient) GetListStatuses(pg *mastodon.Pagination, id mastodon.ID
return items, err return items, err
} }
for _, s := range statuses { for _, s := range statuses {
item, filtered := NewStatusItem(s, ac.Filters, "home") item := NewStatusItem(s, ac.Filters, "home", false)
if !filtered { items = append(items, item)
items = append(items, item)
}
} }
return items, nil return items, nil
} }

68
api/item.go

@ -26,12 +26,19 @@ type Item interface {
ShowSpoiler() bool ShowSpoiler() bool
Raw() interface{} Raw() interface{}
URLs() ([]util.URL, []mastodon.Mention, []mastodon.Tag, int) URLs() ([]util.URL, []mastodon.Mention, []mastodon.Tag, int)
Filtered() (bool, string)
Pinned() bool
} }
func NewStatusItem(item *mastodon.Status, filters []*mastodon.Filter, timeline string) (sitem Item, filtered bool) { type filtered struct {
filtered = false inUse bool
name string
}
func NewStatusItem(item *mastodon.Status, filters []*mastodon.Filter, timeline string, pinned bool) (sitem Item) {
filtered := filtered{inUse: false}
if item == nil { if item == nil {
return &StatusItem{id: newID(), item: item, showSpoiler: false}, false return &StatusItem{id: newID(), item: item, showSpoiler: false, filtered: filtered, pinned: pinned}
} }
s := util.StatusOrReblog(item) s := util.StatusOrReblog(item)
content := s.Content content := s.Content
@ -67,30 +74,35 @@ func NewStatusItem(item *mastodon.Status, filters []*mastodon.Filter, timeline s
filter := strings.Split(strings.ToLower(f.Phrase), " ") filter := strings.Split(strings.ToLower(f.Phrase), " ")
for i := 0; i+len(filter)-1 < len(stripped); i++ { for i := 0; i+len(filter)-1 < len(stripped); i++ {
if strings.ToLower(f.Phrase) == strings.Join(stripped[i:i+len(filter)], " ") { if strings.ToLower(f.Phrase) == strings.Join(stripped[i:i+len(filter)], " ") {
filtered = true filtered.inUse = true
filtered.name = f.Phrase
break break
} }
} }
} else { } else {
if strings.Contains(s.Content, strings.ToLower(f.Phrase)) { if strings.Contains(s.Content, strings.ToLower(f.Phrase)) {
filtered = true filtered.inUse = true
filtered.name = f.Phrase
} }
if strings.Contains(s.SpoilerText, strings.ToLower(f.Phrase)) { if strings.Contains(s.SpoilerText, strings.ToLower(f.Phrase)) {
filtered = true filtered.inUse = true
filtered.name = f.Phrase
} }
} }
if filtered { if filtered.inUse {
break break
} }
} }
sitem = &StatusItem{id: newID(), item: item, showSpoiler: false} sitem = &StatusItem{id: newID(), item: item, showSpoiler: false, filtered: filtered, pinned: pinned}
return sitem, filtered return sitem
} }
type StatusItem struct { type StatusItem struct {
id uint id uint
item *mastodon.Status item *mastodon.Status
showSpoiler bool showSpoiler bool
filtered filtered
pinned bool
} }
func (s *StatusItem) ID() uint { func (s *StatusItem) ID() uint {
@ -141,6 +153,14 @@ func (s *StatusItem) URLs() ([]util.URL, []mastodon.Mention, []mastodon.Tag, int
return realUrls, status.Mentions, status.Tags, length return realUrls, status.Mentions, status.Tags, length
} }
func (s *StatusItem) Filtered() (bool, string) {
return s.filtered.inUse, s.filtered.name
}
func (s *StatusItem) Pinned() bool {
return s.pinned
}
func NewUserItem(item *User, profile bool) Item { func NewUserItem(item *User, profile bool) Item {
return &UserItem{id: newID(), item: item, profile: profile} return &UserItem{id: newID(), item: item, profile: profile}
} }
@ -185,8 +205,16 @@ func (u *UserItem) URLs() ([]util.URL, []mastodon.Mention, []mastodon.Tag, int)
return urls, []mastodon.Mention{}, []mastodon.Tag{}, len(urls) return urls, []mastodon.Mention{}, []mastodon.Tag{}, len(urls)
} }
func NewNotificationItem(item *mastodon.Notification, user *User, filters []*mastodon.Filter) (nitem Item, filtred bool) { func (s *UserItem) Filtered() (bool, string) {
status, filtred := NewStatusItem(item.Status, filters, "notifications") return false, ""
}
func (u *UserItem) Pinned() bool {
return false
}
func NewNotificationItem(item *mastodon.Notification, user *User, filters []*mastodon.Filter) (nitem Item) {
status := NewStatusItem(item.Status, filters, "notifications", false)
nitem = &NotificationItem{ nitem = &NotificationItem{
id: newID(), id: newID(),
item: item, item: item,
@ -195,7 +223,7 @@ func NewNotificationItem(item *mastodon.Notification, user *User, filters []*mas
status: status, status: status,
} }
return nitem, filtred return nitem
} }
type NotificationItem struct { type NotificationItem struct {
@ -240,6 +268,14 @@ func (n *NotificationItem) URLs() ([]util.URL, []mastodon.Mention, []mastodon.Ta
return nil, nil, nil, 0 return nil, nil, nil, 0
} }
func (n *NotificationItem) Filtered() (bool, string) {
return false, ""
}
func (n *NotificationItem) Pinned() bool {
return false
}
func NewListsItem(item *mastodon.List) Item { func NewListsItem(item *mastodon.List) Item {
return &ListItem{id: newID(), item: item, showSpoiler: true} return &ListItem{id: newID(), item: item, showSpoiler: true}
} }
@ -272,3 +308,11 @@ func (s *ListItem) Raw() interface{} {
func (s *ListItem) URLs() ([]util.URL, []mastodon.Mention, []mastodon.Tag, int) { func (s *ListItem) URLs() ([]util.URL, []mastodon.Mention, []mastodon.Tag, int) {
return nil, nil, nil, 0 return nil, nil, nil, 0
} }
func (s *ListItem) Filtered() (bool, string) {
return false, ""
}
func (n *ListItem) Pinned() bool {
return false
}

10
config.example.ini

@ -107,6 +107,10 @@ show-icons=true
# default=false # default=false
short-hints=false short-hints=false
# If you want to display the filter that filtered a toot.
# default=true
show-filter-phrase=true
# If you want to show a message in the cmdbar on how to access the help text. # If you want to show a message in the cmdbar on how to access the help text.
# default=true # default=true
show-help=true show-help=true
@ -132,7 +136,7 @@ leader-key=
leader-timeout=1000 leader-timeout=1000
# You set actions for the leader-key with one or more leader-action. It consists # You set actions for the leader-key with one or more leader-action. It consists
# of two parts first the action then the shortcut. And they're seperated by a # of two parts first the action then the shortcut. And they're separated by a
# comma. # comma.
# #
# Available commands: home, direct, local, federated, compose, blocking, # Available commands: home, direct, local, federated, compose, blocking,
@ -314,7 +318,7 @@ posts=false
# #
# You can also use xrdb colors like this xrdb:color1 The program will use colors # You can also use xrdb colors like this xrdb:color1 The program will use colors
# prefixed with an * first then look for URxvt or XTerm if it can't find any # prefixed with an * first then look for URxvt or XTerm if it can't find any
# color prefixed with an asterik. If you don't want tut to guess the prefix you # color prefixed with an asterisk. If you don't want tut to guess the prefix you
# can set the prefix yourself. If the xrdb color can't be found a preset color # can set the prefix yourself. If the xrdb color can't be found a preset color
# will be used. You'll have to set theme=none for this to work. # will be used. You'll have to set theme=none for this to work.
@ -326,7 +330,7 @@ xrdb-prefix=guess
# available on the URL below. If a theme is named "nord.ini" you just write # available on the URL below. If a theme is named "nord.ini" you just write
# theme=nord # theme=nord
# #
# https://github.com/RasmusLindroth/tut/tree/master/themes # https://github.com/RasmusLindroth/tut/tree/master/config/themes
# #
# If you want to use your own theme set theme to none then you can create your # If you want to use your own theme set theme to none then you can create your
# own theme below # own theme below

50
config/config.go

@ -85,29 +85,29 @@ type Timeline struct {
} }
type General struct { type General struct {
Confirmation bool Confirmation bool
DateTodayFormat string DateTodayFormat string
DateFormat string DateFormat string
DateRelative int DateRelative int
MaxWidth int MaxWidth int
StartTimeline feed.FeedType StartTimeline feed.FeedType
NotificationFeed bool NotificationFeed bool
QuoteReply bool QuoteReply bool
CharLimit int CharLimit int
ShortHints bool ShortHints bool
ListPlacement ListPlacement ShowFilterPhrase bool
ListSplit ListSplit ListPlacement ListPlacement
HideNotificationText bool ListSplit ListSplit
ListProportion int ListProportion int
ContentProportion int ContentProportion int
ShowIcons bool ShowIcons bool
ShowHelp bool ShowHelp bool
RedrawUI bool RedrawUI bool
LeaderKey rune LeaderKey rune
LeaderTimeout int64 LeaderTimeout int64
LeaderActions []LeaderAction LeaderActions []LeaderAction
TimelineName bool TimelineName bool
Timelines []Timeline Timelines []Timeline
} }
type Style struct { type Style struct {
@ -576,7 +576,7 @@ func parseGeneral(cfg *ini.File) General {
general.CharLimit = cfg.Section("general").Key("char-limit").MustInt(500) general.CharLimit = cfg.Section("general").Key("char-limit").MustInt(500)
general.MaxWidth = cfg.Section("general").Key("max-width").MustInt(0) general.MaxWidth = cfg.Section("general").Key("max-width").MustInt(0)
general.ShortHints = cfg.Section("general").Key("short-hints").MustBool(false) general.ShortHints = cfg.Section("general").Key("short-hints").MustBool(false)
general.HideNotificationText = cfg.Section("general").Key("hide-notification-text").MustBool(false) general.ShowFilterPhrase = cfg.Section("general").Key("show-filter-phrase").MustBool(true)
general.ShowIcons = cfg.Section("general").Key("show-icons").MustBool(true) general.ShowIcons = cfg.Section("general").Key("show-icons").MustBool(true)
general.ShowHelp = cfg.Section("general").Key("show-help").MustBool(true) general.ShowHelp = cfg.Section("general").Key("show-help").MustBool(true)
general.RedrawUI = cfg.Section("general").Key("redraw-ui").MustBool(true) general.RedrawUI = cfg.Section("general").Key("redraw-ui").MustBool(true)
@ -630,7 +630,7 @@ func parseGeneral(cfg *ini.File) General {
for _, l := range lactions { for _, l := range lactions {
parts := strings.Split(l, ",") parts := strings.Split(l, ",")
if len(parts) != 2 { if len(parts) != 2 {
fmt.Printf("leader-action must consist of two parts seperated by a comma. Your value is: %s\n", strings.Join(parts, ",")) fmt.Printf("leader-action must consist of two parts separated by a comma. Your value is: %s\n", strings.Join(parts, ","))
os.Exit(1) os.Exit(1)
} }
for i, p := range parts { for i, p := range parts {

10
config/default_config.go

@ -109,6 +109,10 @@ show-icons=true
# default=false # default=false
short-hints=false short-hints=false
# If you want to display the filter that filtered a toot.
# default=true
show-filter-phrase=true
# If you want to show a message in the cmdbar on how to access the help text. # If you want to show a message in the cmdbar on how to access the help text.
# default=true # default=true
show-help=true show-help=true
@ -134,7 +138,7 @@ leader-key=
leader-timeout=1000 leader-timeout=1000
# You set actions for the leader-key with one or more leader-action. It consists # You set actions for the leader-key with one or more leader-action. It consists
# of two parts first the action then the shortcut. And they're seperated by a # of two parts first the action then the shortcut. And they're separated by a
# comma. # comma.
# #
# Available commands: home, direct, local, federated, compose, blocking, # Available commands: home, direct, local, federated, compose, blocking,
@ -316,7 +320,7 @@ posts=false
# #
# You can also use xrdb colors like this xrdb:color1 The program will use colors # You can also use xrdb colors like this xrdb:color1 The program will use colors
# prefixed with an * first then look for URxvt or XTerm if it can't find any # prefixed with an * first then look for URxvt or XTerm if it can't find any
# color prefixed with an asterik. If you don't want tut to guess the prefix you # color prefixed with an asterisk. If you don't want tut to guess the prefix you
# can set the prefix yourself. If the xrdb color can't be found a preset color # can set the prefix yourself. If the xrdb color can't be found a preset color
# will be used. You'll have to set theme=none for this to work. # will be used. You'll have to set theme=none for this to work.
@ -328,7 +332,7 @@ xrdb-prefix=guess
# available on the URL below. If a theme is named "nord.ini" you just write # available on the URL below. If a theme is named "nord.ini" you just write
# theme=nord # theme=nord
# #
# https://github.com/RasmusLindroth/tut/tree/master/themes # https://github.com/RasmusLindroth/tut/tree/master/config/themes
# #
# If you want to use your own theme set theme to none then you can create your # If you want to use your own theme set theme to none then you can create your
# own theme below # own theme below

78
feed/feed.go

@ -16,7 +16,7 @@ type apiEmptyFunc func() ([]api.Item, error)
type apiIDFunc func(pg *mastodon.Pagination, id mastodon.ID) ([]api.Item, error) type apiIDFunc func(pg *mastodon.Pagination, id mastodon.ID) ([]api.Item, error)
type apiSearchFunc func(search string) ([]api.Item, error) type apiSearchFunc func(search string) ([]api.Item, error)
type apiSearchPGFunc func(pg *mastodon.Pagination, search string) ([]api.Item, error) type apiSearchPGFunc func(pg *mastodon.Pagination, search string) ([]api.Item, error)
type apiThreadFunc func(status *mastodon.Status) ([]api.Item, int, error) type apiThreadFunc func(status *mastodon.Status) ([]api.Item, error)
type FeedType uint type FeedType uint
@ -64,6 +64,7 @@ const (
type Feed struct { type Feed struct {
accountClient *api.AccountClient accountClient *api.AccountClient
feedType FeedType feedType FeedType
sticky []api.Item
items []api.Item items []api.Item
itemsMux sync.RWMutex itemsMux sync.RWMutex
loadingNewer *LoadingLock loadingNewer *LoadingLock
@ -85,7 +86,8 @@ func (f *Feed) Type() FeedType {
func (f *Feed) List() []api.Item { func (f *Feed) List() []api.Item {
f.itemsMux.RLock() f.itemsMux.RLock()
defer f.itemsMux.RUnlock() defer f.itemsMux.RUnlock()
return f.items r := f.sticky
return append(r, f.items...)
} }
func (f *Feed) Delete(id uint) { func (f *Feed) Delete(id uint) {
@ -167,6 +169,10 @@ func (f *Feed) Name() string {
return f.name return f.name
} }
func (f *Feed) StickyCount() int {
return len(f.sticky)
}
func (f *Feed) singleNewerSearch(fn apiSearchFunc, search string) { func (f *Feed) singleNewerSearch(fn apiSearchFunc, search string) {
items, err := fn(search) items, err := fn(search)
if err != nil { if err != nil {
@ -181,7 +187,7 @@ func (f *Feed) singleNewerSearch(fn apiSearchFunc, search string) {
} }
func (f *Feed) singleThread(fn apiThreadFunc, status *mastodon.Status) { func (f *Feed) singleThread(fn apiThreadFunc, status *mastodon.Status) {
items, _, err := fn(status) items, err := fn(status)
if err != nil { if err != nil {
return return
} }
@ -322,12 +328,7 @@ func (f *Feed) normalNewerUser(fn apiIDFunc, id mastodon.ID) {
if len(items) > 0 { if len(items) > 0 {
item := items[0].Raw().(*mastodon.Status) item := items[0].Raw().(*mastodon.Status)
f.apiData.MinID = item.ID f.apiData.MinID = item.ID
newItems := []api.Item{f.items[0]} f.items = append(items, f.items...)
newItems = append(newItems, items...)
if len(f.items) > 1 {
newItems = append(newItems, f.items[1:]...)
}
f.items = newItems
f.Updated(DekstopNotificationNone) f.Updated(DekstopNotificationNone)
if f.apiData.MaxID == mastodon.ID("") { if f.apiData.MaxID == mastodon.ID("") {
item = items[len(items)-1].Raw().(*mastodon.Status) item = items[len(items)-1].Raw().(*mastodon.Status)
@ -538,13 +539,11 @@ func (f *Feed) startStream(rec *api.Receiver, timeline string, err error) {
for e := range f.stream.Ch { for e := range f.stream.Ch {
switch t := e.(type) { switch t := e.(type) {
case *mastodon.UpdateEvent: case *mastodon.UpdateEvent:
s, filtered := api.NewStatusItem(t.Status, f.accountClient.Filters, timeline) s := api.NewStatusItem(t.Status, f.accountClient.Filters, timeline, false)
if !filtered { f.itemsMux.Lock()
f.itemsMux.Lock() f.items = append([]api.Item{s}, f.items...)
f.items = append([]api.Item{s}, f.items...) f.Updated(DesktopNotificationPost)
f.Updated(DesktopNotificationPost) f.itemsMux.Unlock()
f.itemsMux.Unlock()
}
} }
} }
}() }()
@ -567,32 +566,30 @@ func (f *Feed) startStreamNotification(rec *api.Receiver, timeline string, err e
log.Fatalln(t.Notification.Account.Acct) log.Fatalln(t.Notification.Account.Acct)
continue continue
} }
s, filtered := api.NewNotificationItem(t.Notification, s := api.NewNotificationItem(t.Notification,
&api.User{ &api.User{
Data: &t.Notification.Account, Data: &t.Notification.Account,
Relation: rel[0], Relation: rel[0],
}, f.accountClient.Filters) }, f.accountClient.Filters)
if !filtered { f.itemsMux.Lock()
f.itemsMux.Lock() f.items = append([]api.Item{s}, f.items...)
f.items = append([]api.Item{s}, f.items...) nft := DekstopNotificationNone
nft := DekstopNotificationNone switch t.Notification.Type {
switch t.Notification.Type { case "follow", "follow_request":
case "follow", "follow_request": nft = DesktopNotificationFollower
nft = DesktopNotificationFollower case "favourite":
case "favourite": nft = DesktopNotificationFollower
nft = DesktopNotificationFollower case "reblog":
case "reblog": nft = DesktopNotificationBoost
nft = DesktopNotificationBoost case "mention":
case "mention": nft = DesktopNotificationMention
nft = DesktopNotificationMention case "status":
case "status": nft = DesktopNotificationPost
nft = DesktopNotificationPost case "poll":
case "poll": nft = DesktopNotificationPoll
nft = DesktopNotificationPoll
}
f.Updated(nft)
f.itemsMux.Unlock()
} }
f.Updated(nft)
f.itemsMux.Unlock()
} }
} }
}() }()
@ -601,6 +598,7 @@ func (f *Feed) startStreamNotification(rec *api.Receiver, timeline string, err e
func newFeed(ac *api.AccountClient, ft FeedType) *Feed { func newFeed(ac *api.AccountClient, ft FeedType) *Feed {
return &Feed{ return &Feed{
accountClient: ac, accountClient: ac,
sticky: make([]api.Item, 0),
items: make([]api.Item, 0), items: make([]api.Item, 0),
feedType: ft, feedType: ft,
loadNewer: func() {}, loadNewer: func() {},
@ -689,7 +687,11 @@ func NewUserSearch(ac *api.AccountClient, search string) *Feed {
func NewUserProfile(ac *api.AccountClient, user *api.User) *Feed { func NewUserProfile(ac *api.AccountClient, user *api.User) *Feed {
feed := newFeed(ac, User) feed := newFeed(ac, User)
feed.name = user.Data.Acct feed.name = user.Data.Acct
feed.items = append(feed.items, api.NewUserItem(user, true)) feed.sticky = append(feed.sticky, api.NewUserItem(user, true))
pinned, err := ac.GetUserPinned(user.Data.ID)
if err == nil {
feed.sticky = append(feed.sticky, pinned...)
}
feed.loadNewer = func() { feed.normalNewerUser(feed.accountClient.GetUser, user.Data.ID) } feed.loadNewer = func() { feed.normalNewerUser(feed.accountClient.GetUser, user.Data.ID) }
feed.loadOlder = func() { feed.normalOlderUser(feed.accountClient.GetUser, user.Data.ID) } feed.loadOlder = func() { feed.normalOlderUser(feed.accountClient.GetUser, user.Data.ID) }

6
go.mod

@ -3,7 +3,7 @@ module github.com/RasmusLindroth/tut
go 1.17 go 1.17
require ( require (
github.com/RasmusLindroth/go-mastodon v0.0.7 github.com/RasmusLindroth/go-mastodon v0.0.8
github.com/atotto/clipboard v0.1.4 github.com/atotto/clipboard v0.1.4
github.com/gdamore/tcell/v2 v2.5.1 github.com/gdamore/tcell/v2 v2.5.1
github.com/gen2brain/beeep v0.0.0-20220518085355-d7852edf42fc github.com/gen2brain/beeep v0.0.0-20220518085355-d7852edf42fc
@ -13,8 +13,8 @@ require (
github.com/pelletier/go-toml/v2 v2.0.1 github.com/pelletier/go-toml/v2 v2.0.1
github.com/rivo/tview v0.0.0-20220307222120-9994674d60a8 github.com/rivo/tview v0.0.0-20220307222120-9994674d60a8
github.com/rivo/uniseg v0.2.0 github.com/rivo/uniseg v0.2.0
golang.org/x/net v0.0.0-20220526153639-5463443f8c37 golang.org/x/net v0.0.0-20220531201128-c960675eff93
gopkg.in/ini.v1 v1.66.4 gopkg.in/ini.v1 v1.66.6
) )
require ( require (

12
go.sum

@ -1,5 +1,5 @@
github.com/RasmusLindroth/go-mastodon v0.0.7 h1:iGgkkvDrPHTiAyACUehLH5zragSHCUSbhcYdQEBIn48= github.com/RasmusLindroth/go-mastodon v0.0.8 h1:t2rrbdNgS4h0JhmPNsmUOQBByDxmUPawnERGn6oR2eA=
github.com/RasmusLindroth/go-mastodon v0.0.7/go.mod h1:4L0oyiNwq1tUoiByczzhSikxR9RiANzELtZgexxKpPM= github.com/RasmusLindroth/go-mastodon v0.0.8/go.mod h1:4L0oyiNwq1tUoiByczzhSikxR9RiANzELtZgexxKpPM=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= 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 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
@ -49,8 +49,8 @@ github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+a
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= 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= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220526153639-5463443f8c37 h1:lUkvobShwKsOesNfWWlCS5q7fnbG1MEliIzwu886fn8= golang.org/x/net v0.0.0-20220531201128-c960675eff93 h1:MYimHLfoXEpOhqd/zgoA/uoXzHB86AEky4LAx5ij9xA=
golang.org/x/net v0.0.0-20220526153639-5463443f8c37/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -71,7 +71,7 @@ golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI=
gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

BIN
images/preview2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

2
main.go

@ -8,7 +8,7 @@ import (
"github.com/rivo/tview" "github.com/rivo/tview"
) )
const version = "1.0.10" const version = "1.0.11"
func main() { func main() {
util.MakeDirs() util.MakeDirs()

2
ui/cliview.go

@ -41,7 +41,7 @@ func CliView(version string) (newUser bool, selectedUser string) {
fmt.Print("\t\tIf two users are named the same. Use full name like tut@fosstodon.org\n\n") fmt.Print("\t\tIf two users are named the same. Use full name like tut@fosstodon.org\n\n")
fmt.Print("Configuration:\n") fmt.Print("Configuration:\n")
fmt.Printf("\tThe config is located in XDG_CONFIG_HOME/tut/config.ini which usally equals to ~/.config/tut/config.ini.\n") fmt.Printf("\tThe config is located in XDG_CONFIG_HOME/tut/config.ini which usually equals to ~/.config/tut/config.ini.\n")
fmt.Printf("\tThe program will generate the file the first time you run tut. The file has comments which exmplains what each configuration option does.\n\n") fmt.Printf("\tThe program will generate the file the first time you run tut. The file has comments which exmplains what each configuration option does.\n\n")
fmt.Print("Contact info for issues or questions:\n") fmt.Print("Contact info for issues or questions:\n")

54
ui/feed.go

@ -14,8 +14,9 @@ import (
) )
type FeedList struct { type FeedList struct {
Text *tview.List Text *tview.List
Symbol *tview.List Symbol *tview.List
stickyCount int
} }
func (fl *FeedList) InFocus(style config.Style) { func (fl *FeedList) InFocus(style config.Style) {
@ -136,7 +137,7 @@ func NewHomeFeed(tv *TutView) *Feed {
tutView: tv, tutView: tv,
Data: f, Data: f,
ListIndex: 0, ListIndex: 0,
List: NewFeedList(tv.tut), List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut), Content: NewFeedContent(tv.tut),
} }
go fd.update() go fd.update()
@ -151,7 +152,7 @@ func NewFederatedFeed(tv *TutView) *Feed {
tutView: tv, tutView: tv,
Data: f, Data: f,
ListIndex: 0, ListIndex: 0,
List: NewFeedList(tv.tut), List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut), Content: NewFeedContent(tv.tut),
} }
go fd.update() go fd.update()
@ -166,7 +167,7 @@ func NewLocalFeed(tv *TutView) *Feed {
tutView: tv, tutView: tv,
Data: f, Data: f,
ListIndex: 0, ListIndex: 0,
List: NewFeedList(tv.tut), List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut), Content: NewFeedContent(tv.tut),
} }
go fd.update() go fd.update()
@ -181,7 +182,7 @@ func NewNotificationFeed(tv *TutView) *Feed {
tutView: tv, tutView: tv,
Data: f, Data: f,
ListIndex: 0, ListIndex: 0,
List: NewFeedList(tv.tut), List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut), Content: NewFeedContent(tv.tut),
} }
go fd.update() go fd.update()
@ -196,7 +197,7 @@ func NewThreadFeed(tv *TutView, item api.Item) *Feed {
tutView: tv, tutView: tv,
Data: f, Data: f,
ListIndex: 0, ListIndex: 0,
List: NewFeedList(tv.tut), List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut), Content: NewFeedContent(tv.tut),
} }
for i, s := range f.List() { for i, s := range f.List() {
@ -218,7 +219,7 @@ func NewConversationsFeed(tv *TutView) *Feed {
tutView: tv, tutView: tv,
Data: f, Data: f,
ListIndex: 0, ListIndex: 0,
List: NewFeedList(tv.tut), List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut), Content: NewFeedContent(tv.tut),
} }
go fd.update() go fd.update()
@ -237,7 +238,7 @@ func NewUserFeed(tv *TutView, item api.Item) *Feed {
tutView: tv, tutView: tv,
Data: f, Data: f,
ListIndex: 0, ListIndex: 0,
List: NewFeedList(tv.tut), List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut), Content: NewFeedContent(tv.tut),
} }
go fd.update() go fd.update()
@ -252,7 +253,7 @@ func NewUserSearchFeed(tv *TutView, search string) *Feed {
tutView: tv, tutView: tv,
Data: f, Data: f,
ListIndex: 0, ListIndex: 0,
List: NewFeedList(tv.tut), List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut), Content: NewFeedContent(tv.tut),
} }
for _, s := range f.List() { for _, s := range f.List() {
@ -271,7 +272,7 @@ func NewTagFeed(tv *TutView, search string) *Feed {
tutView: tv, tutView: tv,
Data: f, Data: f,
ListIndex: 0, ListIndex: 0,
List: NewFeedList(tv.tut), List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut), Content: NewFeedContent(tv.tut),
} }
go fd.update() go fd.update()
@ -285,7 +286,7 @@ func NewListsFeed(tv *TutView) *Feed {
tutView: tv, tutView: tv,
Data: f, Data: f,
ListIndex: 0, ListIndex: 0,
List: NewFeedList(tv.tut), List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut), Content: NewFeedContent(tv.tut),
} }
go fd.update() go fd.update()
@ -300,7 +301,7 @@ func NewListFeed(tv *TutView, l *mastodon.List) *Feed {
tutView: tv, tutView: tv,
Data: f, Data: f,
ListIndex: 0, ListIndex: 0,
List: NewFeedList(tv.tut), List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut), Content: NewFeedContent(tv.tut),
} }
go fd.update() go fd.update()
@ -315,7 +316,7 @@ func NewFavoritedFeed(tv *TutView) *Feed {
tutView: tv, tutView: tv,
Data: f, Data: f,
ListIndex: 0, ListIndex: 0,
List: NewFeedList(tv.tut), List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut), Content: NewFeedContent(tv.tut),
} }
@ -330,7 +331,7 @@ func NewBookmarksFeed(tv *TutView) *Feed {
tutView: tv, tutView: tv,
Data: f, Data: f,
ListIndex: 0, ListIndex: 0,
List: NewFeedList(tv.tut), List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut), Content: NewFeedContent(tv.tut),
} }
go fd.update() go fd.update()
@ -345,7 +346,7 @@ func NewFavoritesStatus(tv *TutView, id mastodon.ID) *Feed {
tutView: tv, tutView: tv,
Data: f, Data: f,
ListIndex: 0, ListIndex: 0,
List: NewFeedList(tv.tut), List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut), Content: NewFeedContent(tv.tut),
} }
go fd.update() go fd.update()
@ -360,7 +361,7 @@ func NewBoosts(tv *TutView, id mastodon.ID) *Feed {
tutView: tv, tutView: tv,
Data: f, Data: f,
ListIndex: 0, ListIndex: 0,
List: NewFeedList(tv.tut), List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut), Content: NewFeedContent(tv.tut),
} }
go fd.update() go fd.update()
@ -375,7 +376,7 @@ func NewFollowers(tv *TutView, id mastodon.ID) *Feed {
tutView: tv, tutView: tv,
Data: f, Data: f,
ListIndex: 0, ListIndex: 0,
List: NewFeedList(tv.tut), List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut), Content: NewFeedContent(tv.tut),
} }
go fd.update() go fd.update()
@ -390,7 +391,7 @@ func NewFollowing(tv *TutView, id mastodon.ID) *Feed {
tutView: tv, tutView: tv,
Data: f, Data: f,
ListIndex: 0, ListIndex: 0,
List: NewFeedList(tv.tut), List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut), Content: NewFeedContent(tv.tut),
} }
go fd.update() go fd.update()
@ -405,7 +406,7 @@ func NewBlocking(tv *TutView) *Feed {
tutView: tv, tutView: tv,
Data: f, Data: f,
ListIndex: 0, ListIndex: 0,
List: NewFeedList(tv.tut), List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut), Content: NewFeedContent(tv.tut),
} }
go fd.update() go fd.update()
@ -420,7 +421,7 @@ func NewMuting(tv *TutView) *Feed {
tutView: tv, tutView: tv,
Data: f, Data: f,
ListIndex: 0, ListIndex: 0,
List: NewFeedList(tv.tut), List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut), Content: NewFeedContent(tv.tut),
} }
go fd.update() go fd.update()
@ -435,7 +436,7 @@ func NewFollowRequests(tv *TutView) *Feed {
tutView: tv, tutView: tv,
Data: f, Data: f,
ListIndex: 0, ListIndex: 0,
List: NewFeedList(tv.tut), List: NewFeedList(tv.tut, f.StickyCount()),
Content: NewFeedContent(tv.tut), Content: NewFeedContent(tv.tut),
} }
go fd.update() go fd.update()
@ -443,10 +444,11 @@ func NewFollowRequests(tv *TutView) *Feed {
return fd return fd
} }
func NewFeedList(t *Tut) *FeedList { func NewFeedList(t *Tut, stickyCount int) *FeedList {
fl := &FeedList{ fl := &FeedList{
Text: NewList(t.Config), Text: NewList(t.Config),
Symbol: NewList(t.Config), Symbol: NewList(t.Config),
stickyCount: stickyCount,
} }
return fl return fl
} }
@ -476,7 +478,7 @@ func (fl *FeedList) Prev() (loadNewer bool) {
} }
fl.Text.SetCurrentItem(ni) fl.Text.SetCurrentItem(ni)
fl.Symbol.SetCurrentItem(ni) fl.Symbol.SetCurrentItem(ni)
return ni < 4 return ni-fl.stickyCount < 4
} }
func (fl *FeedList) Clear() { func (fl *FeedList) Clear() {

4
ui/input.go

@ -452,7 +452,7 @@ func (tv *TutView) InputStatus(event *tcell.EventKey, item api.Item, status *mas
return nil return nil
} }
if tv.tut.Config.Input.StatusUser.Match(event.Key(), event.Rune()) { if tv.tut.Config.Input.StatusUser.Match(event.Key(), event.Rune()) {
id := status.Account.ID id := sr.Account.ID
if nAcc != nil { if nAcc != nil {
id = nAcc.ID id = nAcc.ID
} }
@ -468,7 +468,7 @@ func (tv *TutView) InputStatus(event *tcell.EventKey, item api.Item, status *mas
return nil return nil
} }
if tv.tut.Config.Input.StatusYank.Match(event.Key(), event.Rune()) { if tv.tut.Config.Input.StatusYank.Match(event.Key(), event.Rune()) {
copyToClipboard(status.URL) copyToClipboard(sr.URL)
return nil return nil
} }
if tv.tut.Config.Input.StatusToggleSpoiler.Match(event.Key(), event.Rune()) { if tv.tut.Config.Input.StatusToggleSpoiler.Match(event.Key(), event.Rune()) {

11
ui/item.go

@ -20,13 +20,20 @@ func DrawListItem(cfg *config.Config, item api.Item) (string, string) {
symbol := "" symbol := ""
status := s status := s
if s.Reblog != nil { if s.Reblog != nil {
status = s status = s.Reblog
} }
if status.RepliesCount > 0 { if status.RepliesCount > 0 {
symbol = " ⤶ " symbol = " ⤶ "
} }
if item.Pinned() {
symbol = " ! "
}
acc := strings.TrimSpace(s.Account.Acct)
if s.Reblog != nil && cfg.General.ShowIcons {
acc = fmt.Sprintf("♺ %s", acc)
}
d := OutputDate(cfg, s.CreatedAt.Local()) d := OutputDate(cfg, s.CreatedAt.Local())
return fmt.Sprintf("%s %s", d, strings.TrimSpace(s.Account.Acct)), symbol return fmt.Sprintf("%s %s", d, acc), symbol
case api.UserType: case api.UserType:
a := item.Raw().(*api.User) a := item.Raw().(*api.User)
return strings.TrimSpace(a.Data.Acct), "" return strings.TrimSpace(a.Data.Acct), ""

18
ui/item_status.go

@ -71,6 +71,24 @@ type DisplayTootData struct {
} }
func drawStatus(tut *Tut, item api.Item, status *mastodon.Status, main *tview.TextView, controls *tview.TextView, additional string) { func drawStatus(tut *Tut, item api.Item, status *mastodon.Status, main *tview.TextView, controls *tview.TextView, additional string) {
filtered, phrase := item.Filtered()
if filtered {
var output string
if tut.Config.General.ShowFilterPhrase {
output = fmt.Sprintf("Filtered by phrase: %s", tview.Escape(phrase))
} else {
output = "Filtered."
}
if main != nil {
if additional != "" {
additional = fmt.Sprintf("%s\n\n", config.SublteText(tut.Config, additional))
}
main.SetText(additional + output)
}
controls.SetText("")
return
}
showSensitive := item.ShowSpoiler() showSensitive := item.ShowSpoiler()
var strippedContent string var strippedContent string

Loading…
Cancel
Save