You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
449 lines
10 KiB
449 lines
10 KiB
package ui |
|
|
|
import ( |
|
"fmt" |
|
"strings" |
|
|
|
"github.com/RasmusLindroth/tut/config" |
|
) |
|
|
|
type FeedHolder struct { |
|
Feeds []*Feed |
|
FeedIndex int |
|
} |
|
|
|
type Timeline struct { |
|
tutView *TutView |
|
Feeds []*FeedHolder |
|
FeedFocusIndex int |
|
update chan bool |
|
scrollSleep *scrollSleep |
|
} |
|
|
|
func (fh *FeedHolder) GetTitle() string { |
|
if fh.FeedIndex >= len(fh.Feeds) { |
|
return "" |
|
} |
|
current := fh.Feeds[fh.FeedIndex] |
|
if len(current.Timeline.Name) > 0 { |
|
return current.Timeline.Name |
|
} |
|
for _, f := range fh.Feeds { |
|
if len(f.Timeline.Name) > 0 { |
|
return f.Timeline.Name |
|
} |
|
} |
|
return "" |
|
} |
|
|
|
func CreateFeed(tv *TutView, f *config.Timeline) *Feed { |
|
var nf *Feed |
|
switch f.FeedType { |
|
case config.TimelineHome: |
|
nf = NewHomeFeed(tv, f) |
|
case config.TimelineHomeSpecial: |
|
nf = NewHomeSpecialFeed(tv, f) |
|
case config.Conversations: |
|
nf = NewConversationsFeed(tv, f) |
|
case config.TimelineLocal: |
|
nf = NewLocalFeed(tv, f) |
|
case config.TimelineFederated: |
|
nf = NewFederatedFeed(tv, f) |
|
case config.Saved: |
|
nf = NewBookmarksFeed(tv, f) |
|
case config.Favorited: |
|
nf = NewFavoritedFeed(tv, f) |
|
case config.Notifications: |
|
nf = NewNotificationFeed(tv, f) |
|
case config.Mentions: |
|
nf = NewNotificatioMentionsFeed(tv, f) |
|
case config.Lists: |
|
nf = NewListsFeed(tv, f) |
|
case config.Tag: |
|
nf = NewTagFeed(tv, f) |
|
default: |
|
fmt.Println("Invalid feed") |
|
tv.CleanExit(1) |
|
} |
|
return nf |
|
} |
|
|
|
func NewTimeline(tv *TutView, update chan bool) *Timeline { |
|
tl := &Timeline{ |
|
tutView: tv, |
|
Feeds: []*FeedHolder{}, |
|
update: update, |
|
} |
|
tl.scrollSleep = NewScrollSleep(tl.NextItemFeed, tl.PrevItemFeed) |
|
for _, f := range tv.tut.Config.General.Timelines { |
|
if f.Closed { |
|
continue |
|
} |
|
nf := CreateFeed(tv, f) |
|
tl.Feeds = append(tl.Feeds, &FeedHolder{ |
|
Feeds: []*Feed{nf}, |
|
}) |
|
} |
|
for i := 1; i < len(tl.Feeds); i++ { |
|
for _, f := range tl.Feeds[i].Feeds { |
|
f.ListOutFocus() |
|
} |
|
} |
|
|
|
return tl |
|
} |
|
|
|
func (tl *Timeline) AddFeed(f *Feed, newPane bool) { |
|
if f.Timeline.Name == "" && tl.tutView.tut.Config.General.DynamicTimelineName { |
|
name := f.Data.Name() |
|
switch f.Timeline.FeedType { |
|
case config.Favorited: |
|
f.Timeline.Name = "Favorited" |
|
case config.Notifications: |
|
f.Timeline.Name = "Notifications" |
|
case config.Mentions: |
|
f.Timeline.Name = "Mentions" |
|
case config.Tag: |
|
parts := strings.Split(name, " ") |
|
for i, p := range parts { |
|
parts[i] = fmt.Sprintf("#%s", p) |
|
} |
|
f.Timeline.Name = strings.Join(parts, " ") |
|
case config.Thread: |
|
f.Timeline.Name = "Thread" |
|
case config.History: |
|
f.Timeline.Name = "History" |
|
case config.TimelineFederated: |
|
f.Timeline.Name = "Federated" |
|
case config.TimelineHome: |
|
f.Timeline.Name = "Home" |
|
case config.TimelineHomeSpecial: |
|
f.Timeline.Name = "Special" |
|
case config.TimelineLocal: |
|
f.Timeline.Name = "Local" |
|
case config.Saved: |
|
f.Timeline.Name = "Bookmarked" |
|
case config.User: |
|
f.Timeline.Name = fmt.Sprintf("@%s", name) |
|
case config.UserList: |
|
f.Timeline.Name = fmt.Sprintf("Search %s", name) |
|
case config.Conversations: |
|
f.Timeline.Name = "Direct" |
|
case config.Lists: |
|
f.Timeline.Name = "Lists" |
|
case config.List: |
|
f.Timeline.Name = fmt.Sprintf("List %s", name) |
|
case config.Boosts: |
|
f.Timeline.Name = "Boosts" |
|
case config.Favorites: |
|
f.Timeline.Name = "Favorites" |
|
case config.Followers: |
|
f.Timeline.Name = "Followers" |
|
case config.Following: |
|
f.Timeline.Name = "Following" |
|
case config.FollowRequests: |
|
f.Timeline.Name = "Follow requests" |
|
case config.Blocking: |
|
f.Timeline.Name = "Blocking" |
|
case config.ListUsersAdd: |
|
f.Timeline.Name = fmt.Sprintf("Add users to %s", name) |
|
case config.ListUsersIn: |
|
f.Timeline.Name = fmt.Sprintf("Delete users from %s", name) |
|
} |
|
} |
|
|
|
if newPane { |
|
tl.Feeds = append(tl.Feeds, &FeedHolder{ |
|
Feeds: []*Feed{f}, |
|
}) |
|
tl.tutView.FocusFeed(len(tl.Feeds)-1, nil) |
|
} else { |
|
fh := tl.Feeds[tl.FeedFocusIndex] |
|
fh.Feeds = append(fh.Feeds, f) |
|
fh.FeedIndex = fh.FeedIndex + 1 |
|
} |
|
tl.tutView.Shared.Top.SetText(tl.GetTitle()) |
|
tl.update <- true |
|
} |
|
|
|
func (tl *Timeline) RemoveCurrent(quit bool) bool { |
|
if len(tl.Feeds[tl.FeedFocusIndex].Feeds) == 1 && !quit { |
|
return true |
|
} |
|
if len(tl.Feeds[tl.FeedFocusIndex].Feeds) == 1 && quit { |
|
tl.tutView.tut.App.Stop() |
|
tl.tutView.CleanExit(0) |
|
} |
|
|
|
f := tl.Feeds[tl.FeedFocusIndex] |
|
f.Feeds[f.FeedIndex].Data.Close() |
|
f.Feeds = append(f.Feeds[:f.FeedIndex], f.Feeds[f.FeedIndex+1:]...) |
|
ni := f.FeedIndex - 1 |
|
if ni < 0 { |
|
ni = 0 |
|
} |
|
f.FeedIndex = ni |
|
tl.tutView.Shared.Top.SetText(tl.GetTitle()) |
|
tl.update <- true |
|
return false |
|
} |
|
|
|
func (tl *Timeline) MoveCurrentPaneLeft() { |
|
length := len(tl.Feeds) |
|
if length < 2 { |
|
return |
|
} |
|
ni := tl.FeedFocusIndex - 1 |
|
if ni < 0 { |
|
return |
|
} |
|
tl.Feeds[tl.FeedFocusIndex], tl.Feeds[ni] = tl.Feeds[ni], tl.Feeds[tl.FeedFocusIndex] |
|
tl.tutView.FocusFeed(ni, nil) |
|
} |
|
|
|
func (tl *Timeline) MoveCurrentPaneRight() { |
|
length := len(tl.Feeds) |
|
if length < 2 { |
|
return |
|
} |
|
ni := tl.FeedFocusIndex + 1 |
|
if ni > length-1 { |
|
return |
|
} |
|
tl.Feeds[tl.FeedFocusIndex], tl.Feeds[ni] = tl.Feeds[ni], tl.Feeds[tl.FeedFocusIndex] |
|
tl.tutView.FocusFeed(ni, nil) |
|
} |
|
|
|
func (tl *Timeline) MoveCurrentPaneHome() { |
|
length := len(tl.Feeds) |
|
if length < 2 { |
|
return |
|
} |
|
ni := 0 |
|
tl.Feeds[tl.FeedFocusIndex], tl.Feeds[ni] = tl.Feeds[ni], tl.Feeds[tl.FeedFocusIndex] |
|
tl.tutView.FocusFeed(ni, nil) |
|
} |
|
|
|
func (tl *Timeline) MoveCurrentPaneEnd() { |
|
length := len(tl.Feeds) |
|
if length < 2 { |
|
return |
|
} |
|
ni := len(tl.Feeds) - 1 |
|
tl.Feeds[tl.FeedFocusIndex], tl.Feeds[ni] = tl.Feeds[ni], tl.Feeds[tl.FeedFocusIndex] |
|
tl.tutView.FocusFeed(ni, nil) |
|
} |
|
|
|
func (tl *Timeline) CloseCurrentPane() { |
|
if len(tl.Feeds) < 2 { |
|
return |
|
} |
|
feeds := tl.Feeds[tl.FeedFocusIndex] |
|
for _, f := range feeds.Feeds { |
|
f.Data.Close() |
|
} |
|
tl.Feeds = append(tl.Feeds[:tl.FeedFocusIndex], tl.Feeds[tl.FeedFocusIndex+1:]...) |
|
ni := tl.FeedFocusIndex - 1 |
|
if ni < 0 { |
|
ni = 0 |
|
} |
|
tl.tutView.FocusFeed(ni, nil) |
|
} |
|
|
|
func (tl *Timeline) NextFeed() { |
|
f := tl.Feeds[tl.FeedFocusIndex] |
|
l := len(f.Feeds) |
|
ni := f.FeedIndex + 1 |
|
if ni >= l { |
|
ni = l - 1 |
|
} |
|
f.FeedIndex = ni |
|
tl.tutView.Shared.Top.SetText(tl.GetTitle()) |
|
tl.update <- true |
|
} |
|
|
|
func (tl *Timeline) PrevFeed() { |
|
f := tl.Feeds[tl.FeedFocusIndex] |
|
ni := f.FeedIndex - 1 |
|
if ni < 0 { |
|
ni = 0 |
|
} |
|
f.FeedIndex = ni |
|
tl.tutView.Shared.Top.SetText(tl.GetTitle()) |
|
tl.update <- true |
|
} |
|
|
|
func (tl *Timeline) FindAndGoTo(ft config.FeedType, data string, hideBoosts, hideReplies bool) bool { |
|
for i, fh := range tl.Feeds { |
|
for j, f := range fh.Feeds { |
|
if f.Data.Type() == ft && f.Timeline.HideBoosts == hideBoosts && f.Timeline.HideReplies == hideReplies { |
|
if ft == config.Tag && f.Data.Name() != data { |
|
continue |
|
} |
|
tl.tutView.FocusFeed(i, nil) |
|
fh.FeedIndex = j |
|
tl.tutView.Shared.Top.SetText(tl.GetTitle()) |
|
tl.update <- true |
|
return true |
|
} |
|
} |
|
} |
|
return false |
|
} |
|
|
|
func (tl *Timeline) DrawContent() { |
|
fh := tl.Feeds[tl.FeedFocusIndex] |
|
f := fh.Feeds[fh.FeedIndex] |
|
f.DrawContent() |
|
} |
|
|
|
func (fh *FeedHolder) GetFeedList() *FeedList { |
|
return fh.Feeds[fh.FeedIndex].List |
|
} |
|
|
|
func (tl *Timeline) GetFeedContent() *FeedContent { |
|
fh := tl.Feeds[tl.FeedFocusIndex] |
|
return fh.Feeds[fh.FeedIndex].Content |
|
} |
|
|
|
func (tl *Timeline) GetTitle() string { |
|
fh := tl.Feeds[tl.FeedFocusIndex] |
|
f := fh.Feeds[fh.FeedIndex] |
|
index := fh.FeedIndex |
|
total := len(fh.Feeds) |
|
current := f.Data.Type() |
|
name := f.Data.Name() |
|
ct := "" |
|
switch current { |
|
case config.Favorited: |
|
ct = "favorited" |
|
case config.Notifications: |
|
ct = "notifications" |
|
case config.Mentions: |
|
ct = "mentions" |
|
case config.Tag: |
|
parts := strings.Split(name, " ") |
|
for i, p := range parts { |
|
parts[i] = fmt.Sprintf("#%s", p) |
|
} |
|
ct = strings.Join(parts, " ") |
|
case config.Thread: |
|
ct = "thread" |
|
case config.History: |
|
ct = "history" |
|
case config.TimelineFederated: |
|
ct = "federated" |
|
case config.TimelineHome: |
|
ct = "home" |
|
case config.TimelineHomeSpecial: |
|
ct = "special" |
|
case config.TimelineLocal: |
|
ct = "local" |
|
case config.Saved: |
|
ct = "bookmarked" |
|
case config.User: |
|
ct = fmt.Sprintf("user %s", name) |
|
case config.UserList: |
|
ct = fmt.Sprintf("user search %s", name) |
|
case config.Conversations: |
|
ct = "direct" |
|
case config.Lists: |
|
ct = "lists" |
|
case config.List: |
|
ct = fmt.Sprintf("list %s", name) |
|
case config.Boosts: |
|
ct = "boosts" |
|
case config.Favorites: |
|
ct = "favorites" |
|
case config.Followers: |
|
ct = "followers" |
|
case config.Following: |
|
ct = "following" |
|
case config.FollowRequests: |
|
ct = "follow requests" |
|
case config.Blocking: |
|
ct = "blocking" |
|
case config.ListUsersAdd: |
|
ct = fmt.Sprintf("Add users to %s", name) |
|
case config.ListUsersIn: |
|
ct = fmt.Sprintf("Delete users from %s", name) |
|
} |
|
return fmt.Sprintf("%s (%d/%d)", ct, index+1, total) |
|
} |
|
|
|
func (tl *Timeline) ScrollUp() { |
|
fh := tl.Feeds[tl.FeedFocusIndex] |
|
f := fh.Feeds[fh.FeedIndex] |
|
row, _ := f.Content.Main.GetScrollOffset() |
|
if row > 0 { |
|
row = row - 1 |
|
} |
|
f.Content.Main.ScrollTo(row, 0) |
|
} |
|
|
|
func (tl *Timeline) ScrollDown() { |
|
fh := tl.Feeds[tl.FeedFocusIndex] |
|
f := fh.Feeds[fh.FeedIndex] |
|
row, _ := f.Content.Main.GetScrollOffset() |
|
f.Content.Main.ScrollTo(row+1, 0) |
|
} |
|
|
|
func (tl *Timeline) NextItemFeed() { |
|
fh := tl.Feeds[tl.FeedFocusIndex] |
|
f := fh.Feeds[fh.FeedIndex] |
|
loadMore := f.List.Next() |
|
if loadMore { |
|
f.LoadOlder() |
|
} |
|
tl.DrawContent() |
|
} |
|
func (tl *Timeline) PrevItemFeed() { |
|
fh := tl.Feeds[tl.FeedFocusIndex] |
|
f := fh.Feeds[fh.FeedIndex] |
|
loadMore := f.List.Prev() |
|
if loadMore { |
|
f.LoadNewer(false) |
|
} |
|
tl.DrawContent() |
|
} |
|
|
|
func (tl *Timeline) SetItemFeedIndex(index int) { |
|
fh := tl.Feeds[tl.FeedFocusIndex] |
|
f := fh.Feeds[fh.FeedIndex] |
|
loadOlder, loadNewer := f.List.Set(index) |
|
if loadOlder { |
|
f.LoadOlder() |
|
} |
|
if loadNewer { |
|
f.LoadNewer(false) |
|
} |
|
tl.DrawContent() |
|
} |
|
|
|
func (tl *Timeline) HomeItemFeed() { |
|
fh := tl.Feeds[tl.FeedFocusIndex] |
|
f := fh.Feeds[fh.FeedIndex] |
|
f.List.SetCurrentItem(0) |
|
f.LoadNewer(false) |
|
tl.DrawContent() |
|
} |
|
|
|
func (tl *Timeline) DeleteItemFeed() { |
|
fh := tl.Feeds[tl.FeedFocusIndex] |
|
f := fh.Feeds[fh.FeedIndex] |
|
f.List.GetCurrentID() |
|
|
|
tl.DrawContent() |
|
} |
|
|
|
func (tl *Timeline) EndItemFeed() { |
|
fh := tl.Feeds[tl.FeedFocusIndex] |
|
f := fh.Feeds[fh.FeedIndex] |
|
ni := f.List.GetItemCount() - 1 |
|
if ni < 0 { |
|
return |
|
} |
|
f.List.SetCurrentItem(ni) |
|
f.LoadOlder() |
|
tl.DrawContent() |
|
}
|
|
|