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.
313 lines
6.7 KiB
313 lines
6.7 KiB
package ui |
|
|
|
import ( |
|
"context" |
|
"fmt" |
|
"log" |
|
"os" |
|
"strings" |
|
"time" |
|
|
|
"github.com/RasmusLindroth/go-mastodon" |
|
"github.com/RasmusLindroth/tut/api" |
|
"github.com/RasmusLindroth/tut/auth" |
|
"github.com/RasmusLindroth/tut/config" |
|
"github.com/rivo/tview" |
|
) |
|
|
|
type TimelineFocusAt uint |
|
|
|
const ( |
|
FeedFocus TimelineFocusAt = iota |
|
NotificationFocus |
|
) |
|
|
|
type SubFocusAt uint |
|
|
|
const ( |
|
ListFocus SubFocusAt = iota |
|
ContentFocus |
|
) |
|
|
|
type Tut struct { |
|
Client *api.AccountClient |
|
App *tview.Application |
|
Config *config.Config |
|
} |
|
|
|
var App *tview.Application |
|
var Config *config.Config |
|
var Accounts *auth.AccountData |
|
var TutViews *TutViewsHolder |
|
|
|
type TutViewsHolder struct { |
|
Views []*TutView |
|
Current int |
|
} |
|
|
|
func SetVars(config *config.Config, app *tview.Application, accounts *auth.AccountData) { |
|
Config = config |
|
App = app |
|
Accounts = accounts |
|
} |
|
|
|
type TutView struct { |
|
tut *Tut |
|
Timeline *Timeline |
|
PageFocus PageFocusAt |
|
PrevPageFocus PageFocusAt |
|
SubFocus SubFocusAt |
|
Leader *Leader |
|
Shared *Shared |
|
View *tview.Pages |
|
|
|
LoginView *LoginView |
|
MainView *MainView |
|
LinkView *LinkView |
|
ComposeView *ComposeView |
|
VoteView *VoteView |
|
PollView *PollView |
|
PreferenceView *PreferenceView |
|
HelpView *HelpView |
|
EditorView *EditorView |
|
ModalView *ModalView |
|
|
|
FileList []string |
|
} |
|
|
|
func (tv *TutView) CleanExit(code int) { |
|
tv.ClearTemp() |
|
os.Exit(code) |
|
} |
|
|
|
func NewLeader(tv *TutView) *Leader { |
|
return &Leader{ |
|
tv: tv, |
|
} |
|
} |
|
|
|
type Leader struct { |
|
tv *TutView |
|
timeStart time.Time |
|
content string |
|
} |
|
|
|
func (l *Leader) IsActive() bool { |
|
td := time.Duration(l.tv.tut.Config.General.LeaderTimeout) |
|
return time.Since(l.timeStart) < td*time.Millisecond |
|
} |
|
|
|
func (l *Leader) Reset() { |
|
l.timeStart = time.Now() |
|
l.content = "" |
|
} |
|
|
|
func (l *Leader) ResetInactive() { |
|
l.timeStart = time.Now().Add(-1 * time.Hour) |
|
l.content = "" |
|
} |
|
|
|
func (l *Leader) AddRune(r rune) { |
|
l.content += string(r) |
|
} |
|
|
|
func (l *Leader) Content() string { |
|
return l.content |
|
} |
|
|
|
func NewTutView(selectedUser string) { |
|
if TutViews == nil { |
|
TutViews = &TutViewsHolder{} |
|
} |
|
accs := Accounts |
|
tv := &TutView{ |
|
tut: &Tut{ |
|
Client: &api.AccountClient{}, |
|
App: App, |
|
Config: Config, |
|
}, |
|
View: tview.NewPages(), |
|
FileList: []string{}, |
|
} |
|
tv.Leader = NewLeader(tv) |
|
tv.Shared = NewShared(tv) |
|
if selectedUser != "" { |
|
useHost := false |
|
found := false |
|
if strings.Contains(selectedUser, "@") { |
|
useHost = true |
|
} |
|
for _, acc := range accs.Accounts { |
|
accName := acc.Name |
|
if useHost { |
|
host := strings.TrimPrefix(acc.Server, "https://") |
|
host = strings.TrimPrefix(host, "http://") |
|
accName += "@" + host |
|
} |
|
if accName == selectedUser { |
|
tv.loggedIn(acc) |
|
found = true |
|
break |
|
} |
|
} |
|
if !found { |
|
log.Fatalf("Couldn't find a user named %s. Try again", selectedUser) |
|
} |
|
} else if len(accs.Accounts) > 1 { |
|
tv.LoginView = NewLoginView(tv, accs) |
|
tv.View.AddPage("login", tv.LoginView.View, true, true) |
|
tv.SetPage(LoginFocus) |
|
} else { |
|
tv.loggedIn(accs.Accounts[0]) |
|
} |
|
TutViews.Views = append(TutViews.Views, tv) |
|
TutViews.SetFocusedTutView(len(TutViews.Views) - 1) |
|
} |
|
|
|
func (tvh *TutViewsHolder) SetFocusedTutView(index int) { |
|
if index < 0 && index >= len(tvh.Views) { |
|
return |
|
} |
|
tvh.Current = index |
|
curr := tvh.Views[tvh.Current] |
|
App.SetRoot(curr.View, true) |
|
App.SetInputCapture(curr.Input) |
|
if Config.General.MouseSupport { |
|
App.SetMouseCapture(curr.MouseInput) |
|
} |
|
if curr.MainView != nil { |
|
curr.MainView.ForceUpdate() |
|
} |
|
} |
|
|
|
func (tvh *TutViewsHolder) Next() { |
|
if len(tvh.Views) < 2 { |
|
return |
|
} |
|
next := tvh.Current + 1 |
|
if next >= len(tvh.Views) { |
|
next = 0 |
|
} |
|
tvh.SetFocusedTutView(next) |
|
} |
|
|
|
func (tvh *TutViewsHolder) Prev() { |
|
if len(tvh.Views) < 2 { |
|
return |
|
} |
|
prev := tvh.Current - 1 |
|
if prev < 0 { |
|
prev = len(tvh.Views) - 1 |
|
} |
|
tvh.SetFocusedTutView(prev) |
|
} |
|
|
|
func DoneAdding() { |
|
if len(TutViews.Views) > 0 { |
|
TutViews.SetFocusedTutView(0) |
|
} |
|
} |
|
|
|
func (tv *TutView) loggedIn(acc auth.Account) { |
|
conf := &mastodon.Config{ |
|
Server: acc.Server, |
|
ClientID: acc.ClientID, |
|
ClientSecret: acc.ClientSecret, |
|
AccessToken: acc.AccessToken, |
|
} |
|
if tv.tut.Config.General.ShowHelp { |
|
tv.Shared.Bottom.Cmd.ShowMsg("Press ? or :help to learn how tut functions") |
|
} |
|
client := mastodon.NewClient(conf) |
|
me, err := client.GetAccountCurrentUser(context.Background()) |
|
if err != nil { |
|
fmt.Printf("Couldn't login. Error %s\n", err) |
|
tv.tut.App.Stop() |
|
tv.CleanExit(1) |
|
} |
|
ac := &api.AccountClient{ |
|
Me: me, |
|
Client: client, |
|
Streams: make(map[string]*api.Stream), |
|
WSClient: client.NewWSClient(), |
|
} |
|
inst, err := ac.Client.GetInstanceV2(context.Background()) |
|
if err != nil { |
|
inst, err := ac.Client.GetInstance(context.Background()) |
|
if err != nil { |
|
fmt.Printf("Couldn't get instance. Error %s\n", err) |
|
tv.tut.App.Stop() |
|
tv.CleanExit(1) |
|
} |
|
ac.InstanceOld = inst |
|
} else { |
|
ac.Instance = inst |
|
} |
|
tv.tut.Client = ac |
|
|
|
update := make(chan bool, 1) |
|
tv.SubFocus = ListFocus |
|
tv.LinkView = NewLinkView(tv) |
|
tv.Timeline = NewTimeline(tv, update) |
|
tv.MainView = NewMainView(tv, update) |
|
tv.ComposeView = NewComposeView(tv) |
|
tv.VoteView = NewVoteView(tv) |
|
tv.PollView = NewPollView(tv) |
|
tv.PreferenceView = NewPreferenceView(tv) |
|
tv.HelpView = NewHelpView(tv) |
|
tv.EditorView = NewEditorView(tv) |
|
tv.ModalView = NewModalView(tv) |
|
|
|
tv.View.AddPage("main", tv.MainView.View, true, false) |
|
tv.View.AddPage("link", tv.LinkView.View, true, false) |
|
tv.View.AddPage("compose", tv.ComposeView.View, true, false) |
|
tv.View.AddPage("vote", tv.VoteView.View, true, false) |
|
tv.View.AddPage("help", tv.HelpView.View, true, false) |
|
tv.View.AddPage("editor", tv.EditorView.View, true, false) |
|
tv.View.AddPage("poll", tv.PollView.View, true, false) |
|
tv.View.AddPage("preference", tv.PreferenceView.View, true, false) |
|
tv.View.AddPage("modal", tv.ModalView.View, true, false) |
|
tv.SetPage(MainFocus) |
|
} |
|
|
|
func (tv *TutView) FocusFeed(index int, ct *config.Timeline) { |
|
if index < 0 || index >= len(tv.Timeline.Feeds) { |
|
return |
|
} |
|
tv.Timeline.FeedFocusIndex = index |
|
for i := 0; i < len(tv.Timeline.Feeds); i++ { |
|
if i == index { |
|
for _, f := range tv.Timeline.Feeds[i].Feeds { |
|
f.ListInFocus() |
|
} |
|
} else { |
|
for _, f := range tv.Timeline.Feeds[i].Feeds { |
|
f.ListOutFocus() |
|
} |
|
} |
|
} |
|
for i, tl := range tv.Timeline.Feeds[index].Feeds { |
|
if ct == tl.Timeline { |
|
tv.Timeline.Feeds[index].FeedIndex = i |
|
break |
|
} |
|
} |
|
tv.Shared.Top.SetText(tv.Timeline.GetTitle()) |
|
tv.Timeline.update <- true |
|
} |
|
|
|
func (tv *TutView) NextFeed() { |
|
index := tv.Timeline.FeedFocusIndex + 1 |
|
if index >= len(tv.Timeline.Feeds) { |
|
index = 0 |
|
} |
|
tv.FocusFeed(index, nil) |
|
} |
|
|
|
func (tv *TutView) PrevFeed() { |
|
index := tv.Timeline.FeedFocusIndex - 1 |
|
if index < 0 { |
|
index = len(tv.Timeline.Feeds) - 1 |
|
} |
|
tv.FocusFeed(index, nil) |
|
}
|
|
|