Browse Source

1.0.6 (#143)

* fix streams not closing

* prepare for filters

* support for filters

* wrap words

* support for tag leader

* update config

* bump version
pull/148/head 1.0.6
Rasmus Lindroth 4 years ago committed by GitHub
parent
commit
f43fec0b8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 70
      api/feed.go
  2. 70
      api/item.go
  3. 34
      api/stream.go
  4. 1
      api/types.go
  5. 6
      config.example.ini
  6. 19
      config/config.go
  7. 6
      config/default_config.go
  8. 227
      feed/feed.go
  9. 2
      main.go
  10. 6
      ui/commands.go
  11. 1
      ui/feed.go
  12. 5
      ui/input.go
  13. 2
      ui/tutview.go

70
api/feed.go

@ -15,7 +15,10 @@ func (ac *AccountClient) GetTimeline(pg *mastodon.Pagination) ([]Item, error) {
return items, err
}
for _, s := range statuses {
items = append(items, NewStatusItem(s))
item, filtered := NewStatusItem(s, ac.Filters, "home")
if !filtered {
items = append(items, item)
}
}
return items, nil
}
@ -27,7 +30,10 @@ func (ac *AccountClient) GetTimelineFederated(pg *mastodon.Pagination) ([]Item,
return items, err
}
for _, s := range statuses {
items = append(items, NewStatusItem(s))
item, filtered := NewStatusItem(s, ac.Filters, "public")
if !filtered {
items = append(items, item)
}
}
return items, nil
}
@ -39,7 +45,10 @@ func (ac *AccountClient) GetTimelineLocal(pg *mastodon.Pagination) ([]Item, erro
return items, err
}
for _, s := range statuses {
items = append(items, NewStatusItem(s))
item, filtered := NewStatusItem(s, ac.Filters, "public")
if !filtered {
items = append(items, item)
}
}
return items, nil
}
@ -61,10 +70,12 @@ func (ac *AccountClient) GetNotifications(pg *mastodon.Pagination) ([]Item, erro
for _, n := range notifications {
for _, r := range rel {
if n.Account.ID == r.ID {
items = append(items, NewNotificationItem(n, &User{
Data: &n.Account,
Relation: r,
}))
item, filtered := NewNotificationItem(n, &User{
Data: &n.Account, Relation: r,
}, ac.Filters)
if !filtered {
items = append(items, item)
}
break
}
}
@ -79,11 +90,20 @@ func (ac *AccountClient) GetThread(status *mastodon.Status) ([]Item, int, error)
return items, 0, err
}
for _, s := range statuses.Ancestors {
items = append(items, NewStatusItem(s))
item, filtered := NewStatusItem(s, ac.Filters, "thread")
if !filtered {
items = append(items, item)
}
}
item, filtered := NewStatusItem(status, ac.Filters, "thread")
if !filtered {
items = append(items, item)
}
items = append(items, NewStatusItem(status))
for _, s := range statuses.Descendants {
items = append(items, NewStatusItem(s))
item, filtered := NewStatusItem(s, ac.Filters, "thread")
if !filtered {
items = append(items, item)
}
}
return items, len(statuses.Ancestors), nil
}
@ -95,7 +115,10 @@ func (ac *AccountClient) GetFavorites(pg *mastodon.Pagination) ([]Item, error) {
return items, err
}
for _, s := range statuses {
items = append(items, NewStatusItem(s))
item, filtered := NewStatusItem(s, ac.Filters, "home")
if !filtered {
items = append(items, item)
}
}
return items, nil
}
@ -107,7 +130,10 @@ func (ac *AccountClient) GetBookmarks(pg *mastodon.Pagination) ([]Item, error) {
return items, err
}
for _, s := range statuses {
items = append(items, NewStatusItem(s))
item, filtered := NewStatusItem(s, ac.Filters, "home")
if !filtered {
items = append(items, item)
}
}
return items, nil
}
@ -119,7 +145,10 @@ func (ac *AccountClient) GetConversations(pg *mastodon.Pagination) ([]Item, erro
return items, err
}
for _, c := range conversations {
items = append(items, NewStatusItem(c.LastStatus))
item, filtered := NewStatusItem(c.LastStatus, ac.Filters, "thread")
if !filtered {
items = append(items, item)
}
}
return items, nil
}
@ -229,7 +258,10 @@ func (ac *AccountClient) GetUser(pg *mastodon.Pagination, id mastodon.ID) ([]Ite
return items, err
}
for _, s := range statuses {
items = append(items, NewStatusItem(s))
item, filtered := NewStatusItem(s, ac.Filters, "account")
if !filtered {
items = append(items, item)
}
}
return items, nil
}
@ -253,7 +285,10 @@ func (ac *AccountClient) GetListStatuses(pg *mastodon.Pagination, id mastodon.ID
return items, err
}
for _, s := range statuses {
items = append(items, NewStatusItem(s))
item, filtered := NewStatusItem(s, ac.Filters, "home")
if !filtered {
items = append(items, item)
}
}
return items, nil
}
@ -265,7 +300,10 @@ func (ac *AccountClient) GetTag(pg *mastodon.Pagination, search string) ([]Item,
return items, err
}
for _, s := range statuses {
items = append(items, NewStatusItem(s))
item, filtered := NewStatusItem(s, ac.Filters, "public")
if !filtered {
items = append(items, item)
}
}
return items, nil
}

70
api/item.go

@ -1,7 +1,9 @@
package api
import (
"strings"
"sync"
"unicode"
"github.com/RasmusLindroth/go-mastodon"
"github.com/RasmusLindroth/tut/util"
@ -26,8 +28,63 @@ type Item interface {
URLs() ([]util.URL, []mastodon.Mention, []mastodon.Tag, int)
}
func NewStatusItem(item *mastodon.Status) Item {
return &StatusItem{id: newID(), item: item, showSpoiler: false}
func NewStatusItem(item *mastodon.Status, filters []*mastodon.Filter, timeline string) (sitem Item, filtered bool) {
filtered = false
if item == nil {
return &StatusItem{id: newID(), item: item, showSpoiler: false}, false
}
s := util.StatusOrReblog(item)
content := s.Content
if s.Sensitive {
content += "\n" + s.SpoilerText
}
content = strings.ToLower(content)
for _, f := range filters {
apply := false
for _, c := range f.Context {
if timeline == c {
apply = true
break
}
}
if !apply {
continue
}
if f.WholeWord {
lines := strings.Split(content, "\n")
var stripped []string
for _, l := range lines {
var words []string
words = append(words, strings.Split(l, " ")...)
for _, w := range words {
ns := strings.TrimSpace(w)
ns = strings.TrimFunc(ns, func(r rune) bool {
return !unicode.IsLetter(r) && !unicode.IsNumber(r)
})
stripped = append(stripped, ns)
}
}
filter := strings.Split(strings.ToLower(f.Phrase), " ")
for i := 0; i+len(filter)-1 < len(stripped); i++ {
if strings.ToLower(f.Phrase) == strings.Join(stripped[i:i+len(filter)], " ") {
filtered = true
break
}
}
} else {
if strings.Contains(s.Content, strings.ToLower(f.Phrase)) {
filtered = true
}
if strings.Contains(s.SpoilerText, strings.ToLower(f.Phrase)) {
filtered = true
}
}
if filtered {
break
}
}
sitem = &StatusItem{id: newID(), item: item, showSpoiler: false}
return sitem, filtered
}
type StatusItem struct {
@ -128,16 +185,17 @@ func (u *UserItem) URLs() ([]util.URL, []mastodon.Mention, []mastodon.Tag, int)
return urls, []mastodon.Mention{}, []mastodon.Tag{}, len(urls)
}
func NewNotificationItem(item *mastodon.Notification, user *User) Item {
n := &NotificationItem{
func NewNotificationItem(item *mastodon.Notification, user *User, filters []*mastodon.Filter) (nitem Item, filtred bool) {
status, filtred := NewStatusItem(item.Status, filters, "notifications")
nitem = &NotificationItem{
id: newID(),
item: item,
showSpoiler: false,
user: NewUserItem(user, false),
status: NewStatusItem(item.Status),
status: status,
}
return n
return nitem, filtred
}
type NotificationItem struct {

34
api/stream.go

@ -153,28 +153,34 @@ func (ac *AccountClient) NewGenericStream(st StreamType, data string) (rec *Rece
return rec, nil
}
func (ac *AccountClient) NewHomeStream() (*Receiver, error) {
return ac.NewGenericStream(HomeStream, "")
func (ac *AccountClient) NewHomeStream() (*Receiver, string, error) {
rec, err := ac.NewGenericStream(HomeStream, "")
return rec, "home", err
}
func (ac *AccountClient) NewLocalStream() (*Receiver, error) {
return ac.NewGenericStream(LocalStream, "")
func (ac *AccountClient) NewLocalStream() (*Receiver, string, error) {
rec, err := ac.NewGenericStream(LocalStream, "")
return rec, "public", err
}
func (ac *AccountClient) NewFederatedStream() (*Receiver, error) {
return ac.NewGenericStream(FederatedStream, "")
func (ac *AccountClient) NewFederatedStream() (*Receiver, string, error) {
rec, err := ac.NewGenericStream(FederatedStream, "")
return rec, "public", err
}
func (ac *AccountClient) NewDirectStream() (*Receiver, error) {
return ac.NewGenericStream(DirectStream, "")
func (ac *AccountClient) NewDirectStream() (*Receiver, string, error) {
rec, err := ac.NewGenericStream(DirectStream, "")
return rec, "public", err
}
func (ac *AccountClient) NewListStream(id mastodon.ID) (*Receiver, error) {
return ac.NewGenericStream(ListStream, string(id))
func (ac *AccountClient) NewListStream(id mastodon.ID) (*Receiver, string, error) {
rec, err := ac.NewGenericStream(ListStream, string(id))
return rec, "home", err
}
func (ac *AccountClient) NewTagStream(tag string) (*Receiver, error) {
return ac.NewGenericStream(TagStream, tag)
func (ac *AccountClient) NewTagStream(tag string) (*Receiver, string, error) {
rec, err := ac.NewGenericStream(TagStream, tag)
return rec, "public", err
}
func (ac *AccountClient) RemoveGenericReceiver(rec *Receiver, st StreamType, data string) {
@ -214,6 +220,10 @@ func (ac *AccountClient) RemoveLocalReceiver(rec *Receiver) {
ac.RemoveGenericReceiver(rec, LocalStream, "")
}
func (ac *AccountClient) RemoveConversationReceiver(rec *Receiver) {
ac.RemoveGenericReceiver(rec, DirectStream, "")
}
func (ac *AccountClient) RemoveFederatedReceiver(rec *Receiver) {
ac.RemoveGenericReceiver(rec, FederatedStream, "")
}

1
api/types.go

@ -11,6 +11,7 @@ type AccountClient struct {
Client *mastodon.Client
Streams map[string]*Stream
Me *mastodon.Account
Filters []*mastodon.Filter
}
type User struct {

6
config.example.ini

@ -115,17 +115,19 @@ leader-timeout=1000
#
# Available commands: home, direct, local, federated, compose, blocking,
# bookmarks, saved, favorited, boosts, favorites, following, followers, muting,
# profile, notifications, lists
# profile, notifications, lists, tag
#
# The shortcuts are up to you, but keep them quite short and make sure they
# don't collide. If you have one shortcut that is "f" and an other one that is
# "fav", the one with "f" will always run and "fav" will never run.
# "fav", the one with "f" will always run and "fav" will never run. Tag is
# special as you need to add the tag after, see the example below.
#
# Some examples:
# leader-action=local,lo
# leader-action=lists,li
# leader-action=federated,fed
# leader-action=direct,d
# leader-action=tag linux,tl
#

19
config/config.go

@ -42,8 +42,9 @@ type Config struct {
}
type LeaderAction struct {
Command LeaderCommand
Shortcut string
Command LeaderCommand
Subaction string
Shortcut string
}
type LeaderCommand uint
@ -67,6 +68,8 @@ const (
LeaderProfile
LeaderNotifications
LeaderLists
LeaderTag
LeaderUser
)
type General struct {
@ -600,8 +603,15 @@ func parseGeneral(cfg *ini.File) General {
for i, p := range parts {
parts[i] = strings.TrimSpace(p)
}
cmd := parts[0]
var subaction string
if strings.Contains(parts[0], " ") {
p := strings.Split(cmd, " ")
cmd = p[0]
subaction = strings.Join(p[1:], " ")
}
la := LeaderAction{}
switch parts[0] {
switch cmd {
case "home":
la.Command = LeaderHome
case "direct":
@ -636,6 +646,9 @@ func parseGeneral(cfg *ini.File) General {
la.Command = LeaderNotifications
case "lists":
la.Command = LeaderLists
case "tag":
la.Command = LeaderTag
la.Subaction = subaction
default:
fmt.Printf("leader-action %s is invalid\n", parts[0])
os.Exit(1)

6
config/default_config.go

@ -117,17 +117,19 @@ leader-timeout=1000
#
# Available commands: home, direct, local, federated, compose, blocking,
# bookmarks, saved, favorited, boosts, favorites, following, followers, muting,
# profile, notifications, lists
# profile, notifications, lists, tag
#
# The shortcuts are up to you, but keep them quite short and make sure they
# don't collide. If you have one shortcut that is "f" and an other one that is
# "fav", the one with "f" will always run and "fav" will never run.
# "fav", the one with "f" will always run and "fav" will never run. Tag is
# special as you need to add the tag after, see the example below.
#
# Some examples:
# leader-action=local,lo
# leader-action=lists,li
# leader-action=federated,fed
# leader-action=direct,d
# leader-action=tag linux,tl
#

227
feed/feed.go

@ -180,113 +180,134 @@ func (f *Feed) singleThread(fn apiThreadFunc, status *mastodon.Status) {
}
func (f *Feed) normalNewer(fn apiFunc) {
f.itemsMux.RLock()
pg := mastodon.Pagination{}
if len(f.items) > 0 {
switch item := f.items[0].Raw().(type) {
case *mastodon.Status:
pg.MinID = item.ID
case *api.NotificationData:
pg.MinID = item.Item.ID
}
f.apiDataMux.Lock()
if f.apiData.MinID != mastodon.ID("") {
pg.MinID = f.apiData.MinID
}
f.itemsMux.RUnlock()
items, err := fn(&pg)
if err != nil {
f.apiDataMux.Unlock()
return
}
f.itemsMux.Lock()
if len(items) > 0 {
switch item := items[0].Raw().(type) {
case *mastodon.Status:
f.apiData.MinID = item.ID
case *api.NotificationData:
f.apiData.MinID = item.Item.ID
}
if f.apiData.MaxID == mastodon.ID("") {
switch item := items[len(items)-1].Raw().(type) {
case *mastodon.Status:
f.apiData.MaxID = item.ID
case *api.NotificationData:
f.apiData.MaxID = item.Item.ID
}
}
f.items = append(items, f.items...)
f.Updated(DekstopNotificationNone)
}
f.itemsMux.Unlock()
f.apiDataMux.Unlock()
}
func (f *Feed) normalOlder(fn apiFunc) {
f.itemsMux.RLock()
pg := mastodon.Pagination{}
if len(f.items) > 0 {
switch item := f.items[len(f.items)-1].Raw().(type) {
case *mastodon.Status:
pg.MaxID = item.ID
case *api.NotificationData:
pg.MaxID = item.Item.ID
}
f.apiDataMux.Lock()
if f.apiData.MaxID == mastodon.ID("") {
f.apiDataMux.Unlock()
f.loadNewer()
return
}
f.itemsMux.RUnlock()
pg.MaxID = f.apiData.MaxID
items, err := fn(&pg)
if err != nil {
f.apiDataMux.Unlock()
return
}
f.itemsMux.Lock()
if len(items) > 0 {
switch item := items[len(items)-1].Raw().(type) {
case *mastodon.Status:
f.apiData.MaxID = item.ID
case *api.NotificationData:
f.apiData.MaxID = item.Item.ID
}
f.items = append(f.items, items...)
f.Updated(DekstopNotificationNone)
}
f.itemsMux.Unlock()
f.apiDataMux.Unlock()
}
func (f *Feed) newerSearchPG(fn apiSearchPGFunc, search string) {
f.itemsMux.RLock()
pg := mastodon.Pagination{}
if len(f.items) > 0 {
switch item := f.items[0].Raw().(type) {
case *mastodon.Status:
pg.MinID = item.ID
}
f.apiDataMux.Lock()
if f.apiData.MinID != mastodon.ID("") {
pg.MinID = f.apiData.MinID
}
f.itemsMux.RUnlock()
items, err := fn(&pg, search)
if err != nil {
f.apiDataMux.Unlock()
return
}
f.itemsMux.Lock()
if len(items) > 0 {
item := items[0].Raw().(*mastodon.Status)
f.apiData.MinID = item.ID
f.items = append(items, f.items...)
f.Updated(DekstopNotificationNone)
if f.apiData.MaxID == mastodon.ID("") {
item = items[len(items)-1].Raw().(*mastodon.Status)
f.apiData.MaxID = item.ID
}
}
f.itemsMux.Unlock()
f.apiDataMux.Unlock()
}
func (f *Feed) olderSearchPG(fn apiSearchPGFunc, search string) {
f.itemsMux.RLock()
pg := mastodon.Pagination{}
if len(f.items) > 0 {
switch item := f.items[len(f.items)-1].Raw().(type) {
case *mastodon.Status:
pg.MaxID = item.ID
}
f.apiDataMux.Lock()
if f.apiData.MaxID == mastodon.ID("") {
f.apiDataMux.Unlock()
f.loadNewer()
return
}
f.itemsMux.RUnlock()
pg.MaxID = f.apiData.MaxID
items, err := fn(&pg, search)
if err != nil {
f.apiDataMux.Unlock()
return
}
f.itemsMux.Lock()
if len(items) > 0 {
item := items[len(items)-1].Raw().(*mastodon.Status)
f.apiData.MaxID = item.ID
f.items = append(f.items, items...)
f.Updated(DekstopNotificationNone)
}
f.itemsMux.Unlock()
f.apiDataMux.Unlock()
}
func (f *Feed) normalNewerUser(fn apiIDFunc, id mastodon.ID) {
f.itemsMux.RLock()
pg := mastodon.Pagination{}
if len(f.items) > 1 {
switch item := f.items[1].Raw().(type) {
case *mastodon.Status:
pg.MinID = item.ID
}
f.apiDataMux.Lock()
if f.apiData.MinID != mastodon.ID("") {
pg.MinID = f.apiData.MinID
}
f.itemsMux.RUnlock()
items, err := fn(&pg, id)
if err != nil {
f.apiDataMux.Unlock()
return
}
f.itemsMux.Lock()
if len(items) > 0 {
item := items[0].Raw().(*mastodon.Status)
f.apiData.MinID = item.ID
newItems := []api.Item{f.items[0]}
newItems = append(newItems, items...)
if len(f.items) > 1 {
@ -294,74 +315,89 @@ func (f *Feed) normalNewerUser(fn apiIDFunc, id mastodon.ID) {
}
f.items = newItems
f.Updated(DekstopNotificationNone)
if f.apiData.MaxID == mastodon.ID("") {
item = items[len(items)-1].Raw().(*mastodon.Status)
f.apiData.MaxID = item.ID
}
}
f.itemsMux.Unlock()
f.apiDataMux.Unlock()
}
func (f *Feed) normalOlderUser(fn apiIDFunc, id mastodon.ID) {
f.itemsMux.RLock()
pg := mastodon.Pagination{}
if len(f.items) > 1 {
switch item := f.items[len(f.items)-1].Raw().(type) {
case *mastodon.Status:
pg.MaxID = item.ID
}
f.apiDataMux.Lock()
if f.apiData.MaxID == mastodon.ID("") {
f.apiDataMux.Unlock()
f.loadNewer()
return
}
f.itemsMux.RUnlock()
pg.MaxID = f.apiData.MaxID
items, err := fn(&pg, id)
if err != nil {
f.apiDataMux.Unlock()
return
}
f.itemsMux.Lock()
if len(items) > 0 {
item := items[len(items)-1].Raw().(*mastodon.Status)
f.apiData.MaxID = item.ID
f.items = append(f.items, items...)
f.Updated(DekstopNotificationNone)
}
f.itemsMux.Unlock()
f.apiDataMux.Unlock()
}
func (f *Feed) normalNewerID(fn apiIDFunc, id mastodon.ID) {
f.itemsMux.RLock()
pg := mastodon.Pagination{}
if len(f.items) > 0 {
switch item := f.items[0].Raw().(type) {
case *mastodon.Status:
pg.MinID = item.ID
}
f.apiDataMux.Lock()
if f.apiData.MinID != mastodon.ID("") {
pg.MinID = f.apiData.MinID
}
f.itemsMux.RUnlock()
items, err := fn(&pg, id)
if err != nil {
f.apiDataMux.Unlock()
return
}
f.itemsMux.Lock()
if len(items) > 0 {
item := items[0].Raw().(*mastodon.Status)
f.apiData.MinID = item.ID
f.items = append(items, f.items...)
f.Updated(DekstopNotificationNone)
if f.apiData.MaxID == mastodon.ID("") {
item = items[len(items)-1].Raw().(*mastodon.Status)
f.apiData.MaxID = item.ID
}
}
f.itemsMux.Unlock()
f.apiDataMux.Unlock()
}
func (f *Feed) normalOlderID(fn apiIDFunc, id mastodon.ID) {
f.itemsMux.RLock()
pg := mastodon.Pagination{}
if len(f.items) > 0 {
switch item := f.items[len(f.items)-1].Raw().(type) {
case *mastodon.Status:
pg.MaxID = item.ID
}
f.apiDataMux.Lock()
if f.apiData.MaxID == mastodon.ID("") {
f.apiDataMux.Unlock()
f.loadNewer()
return
}
f.itemsMux.RUnlock()
pg.MaxID = f.apiData.MaxID
items, err := fn(&pg, id)
if err != nil {
f.apiDataMux.Unlock()
return
}
f.itemsMux.Lock()
if len(items) > 0 {
item := items[len(items)-1].Raw().(*mastodon.Status)
f.apiData.MaxID = item.ID
f.items = append(f.items, items...)
f.Updated(DekstopNotificationNone)
}
f.itemsMux.Unlock()
f.apiDataMux.Unlock()
}
func (f *Feed) normalEmpty(fn apiEmptyFunc) {
@ -479,7 +515,7 @@ func (f *Feed) linkOlderID(fn apiIDFunc, id mastodon.ID) {
f.itemsMux.Unlock()
}
func (f *Feed) startStream(rec *api.Receiver, err error) {
func (f *Feed) startStream(rec *api.Receiver, timeline string, err error) {
if err != nil {
log.Fatalln("Couldn't open stream")
}
@ -488,17 +524,19 @@ func (f *Feed) startStream(rec *api.Receiver, err error) {
for e := range f.stream.Ch {
switch t := e.(type) {
case *mastodon.UpdateEvent:
s := api.NewStatusItem(t.Status)
f.itemsMux.Lock()
f.items = append([]api.Item{s}, f.items...)
f.Updated(DesktopNotificationPost)
f.itemsMux.Unlock()
s, filtered := api.NewStatusItem(t.Status, f.accountClient.Filters, timeline)
if !filtered {
f.itemsMux.Lock()
f.items = append([]api.Item{s}, f.items...)
f.Updated(DesktopNotificationPost)
f.itemsMux.Unlock()
}
}
}
}()
}
func (f *Feed) startStreamNotification(rec *api.Receiver, err error) {
func (f *Feed) startStreamNotification(rec *api.Receiver, timeline string, err error) {
if err != nil {
log.Fatalln("Couldn't open stream")
}
@ -515,30 +553,32 @@ func (f *Feed) startStreamNotification(rec *api.Receiver, err error) {
log.Fatalln(t.Notification.Account.Acct)
continue
}
s := api.NewNotificationItem(t.Notification,
s, filtered := api.NewNotificationItem(t.Notification,
&api.User{
Data: &t.Notification.Account,
Relation: rel[0],
})
f.itemsMux.Lock()
f.items = append([]api.Item{s}, f.items...)
nft := DekstopNotificationNone
switch t.Notification.Type {
case "follow", "follow_request":
nft = DesktopNotificationFollower
case "favourite":
nft = DesktopNotificationFollower
case "reblog":
nft = DesktopNotificationBoost
case "mention":
nft = DesktopNotificationMention
case "status":
nft = DesktopNotificationPost
case "poll":
nft = DesktopNotificationPoll
}, f.accountClient.Filters)
if !filtered {
f.itemsMux.Lock()
f.items = append([]api.Item{s}, f.items...)
nft := DekstopNotificationNone
switch t.Notification.Type {
case "follow", "follow_request":
nft = DesktopNotificationFollower
case "favourite":
nft = DesktopNotificationFollower
case "reblog":
nft = DesktopNotificationBoost
case "mention":
nft = DesktopNotificationMention
case "status":
nft = DesktopNotificationPost
case "poll":
nft = DesktopNotificationPoll
}
f.Updated(nft)
f.itemsMux.Unlock()
}
f.Updated(nft)
f.itemsMux.Unlock()
}
}
}()
@ -599,7 +639,7 @@ func NewTimelineLocal(ac *api.AccountClient) *Feed {
feed.loadNewer = func() { feed.normalNewer(feed.accountClient.GetTimelineLocal) }
feed.loadOlder = func() { feed.normalOlder(feed.accountClient.GetTimelineLocal) }
feed.startStream(feed.accountClient.NewLocalStream())
feed.close = func() { feed.accountClient.RemoveFederatedReceiver(feed.stream) }
feed.close = func() { feed.accountClient.RemoveLocalReceiver(feed.stream) }
return feed
}
@ -619,7 +659,7 @@ func NewConversations(ac *api.AccountClient) *Feed {
feed.loadNewer = func() { feed.normalNewer(feed.accountClient.GetConversations) }
feed.loadOlder = func() { feed.normalOlder(feed.accountClient.GetConversations) }
feed.startStream(feed.accountClient.NewDirectStream())
feed.close = func() { feed.accountClient.RemoveFederatedReceiver(feed.stream) }
feed.close = func() { feed.accountClient.RemoveConversationReceiver(feed.stream) }
return feed
}
@ -763,8 +803,13 @@ func NewListList(ac *api.AccountClient) *Feed {
loadingNewer: &LoadingLock{},
loadingOlder: &LoadingLock{},
}
feed.loadNewer = func() { feed.normalEmpty(feed.accountClient.GetLists) }
once := true
feed.loadNewer = func() {
if once {
feed.normalEmpty(feed.accountClient.GetLists)
}
once = false
}
return feed
}

2
main.go

@ -10,7 +10,7 @@ import (
"github.com/rivo/tview"
)
const version = "1.0.5"
const version = "1.0.6"
func main() {
util.MakeDirs()

6
ui/commands.go

@ -71,6 +71,12 @@ func (tv *TutView) ListsCommand() {
)
}
func (tv *TutView) TagCommand(tag string) {
tv.Timeline.AddFeed(
NewTagFeed(tv, tag),
)
}
func (tv *TutView) BoostsCommand() {
item, itemErr := tv.GetCurrentItem()
if itemErr != nil {

1
ui/feed.go

@ -510,6 +510,7 @@ type FeedContent struct {
func NewFeedContent(t *Tut) *FeedContent {
m := NewTextView(t.Config)
m.SetWordWrap(true)
if t.Config.General.MaxWidth > 0 {
mw := t.Config.General.MaxWidth

5
ui/input.go

@ -80,10 +80,12 @@ func (tv *TutView) InputLeaderKey(event *tcell.EventKey) *tcell.EventKey {
tv.Leader.AddRune(event.Rune())
}
action := config.LeaderNone
var subaction string
content := tv.Leader.Content()
for _, la := range tv.tut.Config.General.LeaderActions {
if la.Shortcut == content {
action = la.Command
subaction = la.Subaction
break
}
}
@ -123,6 +125,9 @@ func (tv *TutView) InputLeaderKey(event *tcell.EventKey) *tcell.EventKey {
tv.NotificationsCommand()
case config.LeaderLists:
tv.ListsCommand()
case config.LeaderTag:
tv.TagCommand(subaction)
}
tv.Leader.ResetInactive()
return nil

2
ui/tutview.go

@ -145,10 +145,12 @@ func (tv *TutView) loggedIn(acc auth.Account) {
tv.tut.App.Stop()
os.Exit(1)
}
filters, _ := client.GetFilters(context.Background())
ac := &api.AccountClient{
Me: me,
Client: client,
Streams: make(map[string]*api.Stream),
Filters: filters,
}
tv.tut.Client = ac

Loading…
Cancel
Save