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.

512 lines
16 KiB

package main
import (
"log"
"strings"
"github.com/gdamore/tcell"
"github.com/rivo/tview"
)
func main() {
config := Config{
Style: StyleConfig{
Background: tcell.ColorDefault,
Text: tcell.ColorWhite,
Subtle: tcell.ColorGray,
WarningText: tcell.NewRGBColor(249, 38, 114),
TextSpecial1: tcell.NewRGBColor(174, 129, 255),
TextSpecial2: tcell.NewRGBColor(166, 226, 46),
TopBarBackground: tcell.NewRGBColor(249, 38, 114),
TopBarText: tcell.ColorWhite,
StatusBarBackground: tcell.NewRGBColor(249, 38, 114),
StatusBarText: tcell.ColorWhite,
ListSelectedBackground: tcell.NewRGBColor(249, 38, 114),
ListSelectedText: tcell.ColorWhite,
},
}
err := CreateConfigDir()
if err != nil {
log.Fatalln(err)
}
path, exists, err := CheckConfig("accounts.toml")
if err != nil {
log.Fatalln(err)
}
app := &App{
App: tview.NewApplication(),
API: &API{},
HaveAccount: false,
Config: &config,
}
clearContent := func(screen tcell.Screen, x int, y int, width int, height int) (int, int, int, int) {
for cx := x; cx < width+x; cx++ {
for cy := y; cy < height+y; cy++ {
screen.SetContent(cx, cy, ' ', nil, tcell.StyleDefault.Background(app.Config.Style.Background))
}
}
y2 := y + height
for cx := x + 1; cx < width+x; cx++ {
screen.SetContent(cx, y, tview.BoxDrawingsLightHorizontal, nil, tcell.StyleDefault.Foreground(app.Config.Style.Subtle))
screen.SetContent(cx, y2, tview.BoxDrawingsLightHorizontal, nil, tcell.StyleDefault.Foreground(app.Config.Style.Subtle))
}
x2 := x + width
for cy := y + 1; cy < height+y; cy++ {
screen.SetContent(x, cy, tview.BoxDrawingsLightVertical, nil, tcell.StyleDefault.Foreground(app.Config.Style.Subtle))
screen.SetContent(x2, cy, tview.BoxDrawingsLightVertical, nil, tcell.StyleDefault.Foreground(app.Config.Style.Subtle))
}
screen.SetContent(x, y, tview.BoxDrawingsLightDownAndRight, nil, tcell.StyleDefault.Foreground(app.Config.Style.Subtle))
screen.SetContent(x, y+height, tview.BoxDrawingsLightUpAndRight, nil, tcell.StyleDefault.Foreground(app.Config.Style.Subtle))
screen.SetContent(x+width, y, tview.BoxDrawingsLightDownAndLeft, nil, tcell.StyleDefault.Foreground(app.Config.Style.Subtle))
screen.SetContent(x+width, y+height, tview.BoxDrawingsLightUpAndLeft, nil, tcell.StyleDefault.Foreground(app.Config.Style.Subtle))
return x + 1, y + 1, width - 1, height - 1
}
if exists {
accounts, err := GetAccounts(path)
if err != nil {
log.Fatalln(err)
}
if len(accounts.Accounts) > 0 {
a := accounts.Accounts[0]
client, err := a.Login()
if err == nil {
app.API.Client = client
app.HaveAccount = true
}
}
}
app.App.SetBeforeDrawFunc(func(screen tcell.Screen) bool {
screen.Clear()
return false
})
tview.Borders.HorizontalFocus = tview.BoxDrawingsLightHorizontal
tview.Borders.VerticalFocus = tview.BoxDrawingsLightVertical
tview.Borders.TopLeftFocus = tview.BoxDrawingsLightDownAndRight
tview.Borders.TopRightFocus = tview.BoxDrawingsLightDownAndLeft
tview.Borders.BottomLeftFocus = tview.BoxDrawingsLightUpAndRight
tview.Borders.BottomRightFocus = tview.BoxDrawingsLightUpAndLeft
top := tview.NewTextView()
top.SetBackgroundColor(app.Config.Style.TopBarBackground)
top.SetTextColor(app.Config.Style.TopBarText)
app.UI = &UI{app: app, Top: top, Timeline: TimelineHome}
app.UI.TootList = NewTootList(app, tview.NewList())
app.UI.TootList.View.SetBackgroundColor(app.Config.Style.Background)
app.UI.TootList.View.SetSelectedTextColor(app.Config.Style.ListSelectedText)
app.UI.TootList.View.SetSelectedBackgroundColor(app.Config.Style.ListSelectedBackground)
app.UI.TootList.View.ShowSecondaryText(false)
app.UI.TootList.View.SetHighlightFullLine(true)
app.UI.TootList.View.SetChangedFunc(func(index int, _ string, _ string, _ rune) {
if app.HaveAccount {
app.UI.StatusText.ShowToot(index)
}
})
app.UI.StatusText = NewStatusText(app, tview.NewTextView(),
NewControls(app, tview.NewTextView()), NewLinkOverlay(app),
)
app.UI.StatusText.View.SetWordWrap(true).SetDynamicColors(true)
app.UI.StatusText.View.SetBackgroundColor(app.Config.Style.Background)
app.UI.StatusText.View.SetTextColor(app.Config.Style.Text)
app.UI.StatusText.Controls.View.SetDynamicColors(true)
app.UI.StatusText.Controls.View.SetBackgroundColor(app.Config.Style.Background)
app.UI.CmdBar = NewCmdBar(app,
tview.NewInputField(),
)
app.UI.CmdBar.View.SetFieldBackgroundColor(app.Config.Style.Background)
app.UI.CmdBar.View.SetFieldTextColor(app.Config.Style.Text)
app.UI.Status = tview.NewTextView()
app.UI.Status.SetBackgroundColor(app.Config.Style.StatusBarBackground)
app.UI.Status.SetTextColor(app.Config.Style.StatusBarText)
verticalLine := tview.NewBox().SetBackgroundColor(app.Config.Style.Background)
verticalLine.SetDrawFunc(func(screen tcell.Screen, x int, y int, width int, height int) (int, int, int, int) {
for cy := y; cy < y+height; cy++ {
screen.SetContent(x, cy, tview.BoxDrawingsLightVertical, nil, tcell.StyleDefault.Foreground(app.Config.Style.Subtle))
}
return 0, 0, 0, 0
})
app.UI.Pages = tview.NewPages()
app.UI.Pages.SetBackgroundColor(app.Config.Style.Background)
app.UI.Pages.AddPage("main",
tview.NewFlex().
AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
AddItem(top, 1, 0, false).
AddItem(tview.NewFlex().SetDirection(tview.FlexColumn).
AddItem(app.UI.TootList.View, 0, 2, false).
AddItem(verticalLine, 1, 0, false).
AddItem(tview.NewBox().SetBackgroundColor(app.Config.Style.Background), 1, 0, false).
AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
AddItem(app.UI.StatusText.View, 0, 9, false).
AddItem(app.UI.StatusText.Controls.View, 1, 0, false),
0, 4, false),
0, 1, false).
AddItem(app.UI.Status, 1, 1, false).
AddItem(app.UI.CmdBar.View, 1, 0, false), 0, 1, false), true, true)
flLinks := tview.NewFlex()
flLinks.SetDrawFunc(clearContent)
flToot := tview.NewFlex()
flToot.SetDrawFunc(clearContent)
modal := func(fl *tview.Flex, p tview.Primitive, c tview.Primitive) tview.Primitive {
return tview.NewFlex().
AddItem(nil, 0, 1, false).
AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
AddItem(nil, 0, 1, false).
AddItem(fl.SetDirection(tview.FlexRow).
AddItem(p, 0, 9, true).
AddItem(c, 2, 1, false), 0, 8, false).
AddItem(nil, 0, 1, false), 0, 8, true).
AddItem(nil, 0, 1, false)
}
authModal := func(f *tview.Flex, p tview.Primitive, c tview.Primitive) tview.Primitive {
return tview.NewFlex().
AddItem(nil, 0, 1, false).
AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
AddItem(nil, 0, 1, false).
AddItem(f.SetDirection(tview.FlexRow).
AddItem(c, 4, 1, false).
AddItem(p, 0, 9, true), 0, 9, true).
AddItem(nil, 0, 1, false), 0, 6, true).
AddItem(nil, 0, 1, false)
}
app.UI.MessageBox = NewMessageBox(app, tview.NewTextView(),
NewControls(app, tview.NewTextView()),
)
app.UI.MessageBox.View.SetBackgroundColor(app.Config.Style.Background)
app.UI.MessageBox.View.SetTextColor(app.Config.Style.Text)
app.UI.MessageBox.View.SetDynamicColors(true)
app.UI.MessageBox.Controls.View.SetDynamicColors(true)
app.UI.MessageBox.Controls.View.SetBackgroundColor(app.Config.Style.Background)
app.UI.MessageBox.Controls.View.SetTextColor(app.Config.Style.Text)
app.UI.Pages.AddPage("toot",
modal(flToot, app.UI.MessageBox.View, app.UI.MessageBox.Controls.View), true, false)
app.UI.Pages.AddPage("links", tview.NewFlex().AddItem(nil, 0, 1, false).
AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
AddItem(nil, 0, 1, false).
AddItem(app.UI.StatusText.LinkOverlay.Flex.SetDirection(tview.FlexRow).
AddItem(app.UI.StatusText.LinkOverlay.List, 0, 10, true).
AddItem(app.UI.StatusText.LinkOverlay.TextBottom, 1, 1, true), 0, 8, false).
AddItem(nil, 0, 1, false), 0, 8, true).
AddItem(nil, 0, 1, false), true, false)
app.UI.StatusText.LinkOverlay.Flex.SetDrawFunc(clearContent)
app.UI.StatusText.LinkOverlay.TextBottom.SetBackgroundColor(app.Config.Style.Background)
app.UI.StatusText.LinkOverlay.List.SetBackgroundColor(app.Config.Style.Background)
app.UI.StatusText.LinkOverlay.List.SetMainTextColor(app.Config.Style.Text)
app.UI.StatusText.LinkOverlay.List.SetSelectedBackgroundColor(app.Config.Style.ListSelectedBackground)
app.UI.StatusText.LinkOverlay.List.SetSelectedTextColor(app.Config.Style.ListSelectedText)
app.UI.StatusText.LinkOverlay.List.ShowSecondaryText(false)
app.UI.StatusText.LinkOverlay.List.SetHighlightFullLine(true)
app.UI.AuthOverlay = NewAuthoverlay(app, tview.NewFlex(), tview.NewInputField(),
NewControls(app, tview.NewTextView()))
app.UI.Pages.AddPage("login",
authModal(app.UI.AuthOverlay.Flex, app.UI.AuthOverlay.View, app.UI.AuthOverlay.Controls.View), true, false)
app.UI.AuthOverlay.Flex.SetDrawFunc(clearContent)
app.UI.AuthOverlay.Flex.SetBackgroundColor(app.Config.Style.Background)
app.UI.AuthOverlay.View.SetBackgroundColor(app.Config.Style.Background)
app.UI.AuthOverlay.View.SetFieldBackgroundColor(app.Config.Style.Background)
app.UI.AuthOverlay.View.SetFieldTextColor(app.Config.Style.Text)
app.UI.AuthOverlay.Controls.View.SetBackgroundColor(app.Config.Style.Background)
app.UI.AuthOverlay.Controls.View.SetTextColor(app.Config.Style.Text)
app.UI.AuthOverlay.Draw()
app.UI.MediaOverlay = NewMediaView(app)
app.UI.Pages.AddPage("media", tview.NewFlex().AddItem(nil, 0, 1, false).
AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
AddItem(nil, 0, 1, false).
AddItem(app.UI.MediaOverlay.Flex.SetDirection(tview.FlexRow).
AddItem(app.UI.MediaOverlay.TextTop, 1, 1, true).
AddItem(app.UI.MediaOverlay.FileList, 0, 10, true).
AddItem(app.UI.MediaOverlay.TextBottom, 1, 1, true).
AddItem(app.UI.MediaOverlay.InputField.View, 2, 1, false), 0, 8, false).
AddItem(nil, 0, 1, false), 0, 8, true).
AddItem(nil, 0, 1, false), true, false)
app.UI.MediaOverlay.FileList.SetBackgroundColor(app.Config.Style.Background)
app.UI.MediaOverlay.FileList.SetMainTextColor(app.Config.Style.Text)
app.UI.MediaOverlay.FileList.SetSelectedBackgroundColor(app.Config.Style.ListSelectedBackground)
app.UI.MediaOverlay.FileList.SetSelectedTextColor(app.Config.Style.ListSelectedText)
app.UI.MediaOverlay.FileList.ShowSecondaryText(false)
app.UI.MediaOverlay.FileList.SetHighlightFullLine(true)
app.UI.MediaOverlay.Flex.SetBackgroundColor(app.Config.Style.Background)
app.UI.MediaOverlay.TextTop.SetBackgroundColor(app.Config.Style.Background)
app.UI.MediaOverlay.TextTop.SetTextColor(app.Config.Style.Text)
app.UI.MediaOverlay.TextBottom.SetBackgroundColor(app.Config.Style.Background)
app.UI.MediaOverlay.TextBottom.SetTextColor(app.Config.Style.Text)
app.UI.MediaOverlay.InputField.View.SetBackgroundColor(app.Config.Style.Background)
app.UI.MediaOverlay.InputField.View.SetFieldBackgroundColor(app.Config.Style.Background)
app.UI.MediaOverlay.InputField.View.SetFieldTextColor(app.Config.Style.Text)
app.UI.MediaOverlay.Flex.SetDrawFunc(clearContent)
if !app.HaveAccount {
app.UI.SetFocus(AuthOverlayFocus)
} else {
app.UI.LoggedIn()
}
app.App.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
if !app.HaveAccount {
if event.Key() == tcell.KeyRune {
switch event.Rune() {
}
}
return event
}
if app.UI.Focus == LinkOverlayFocus {
app.UI.StatusText.LinkOverlay.InputHandler(event)
return nil
}
if app.UI.Focus == CmdBarFocus {
switch event.Key() {
case tcell.KeyEsc:
app.UI.CmdBar.View.SetText("")
app.UI.CmdBar.View.Autocomplete().Blur()
app.UI.SetFocus(LeftPaneFocus)
return nil
}
return event
}
if app.UI.Focus == MessageFocus {
if event.Key() == tcell.KeyRune {
switch event.Rune() {
case 'p', 'P':
app.UI.MessageBox.Post()
return nil
case 'e', 'E':
app.UI.MessageBox.EditText()
return nil
case 'c', 'C':
app.UI.MessageBox.EditSpoiler()
return nil
case 't', 'T':
app.UI.MessageBox.ToggleSpoiler()
return nil
case 'm', 'M':
app.UI.SetFocus(MessageAttachmentFocus)
return nil
case 'q', 'Q':
app.UI.SetFocus(LeftPaneFocus)
return nil
}
} else {
switch event.Key() {
case tcell.KeyEsc:
app.UI.SetFocus(LeftPaneFocus)
return nil
}
}
return event
}
if app.UI.Focus == MessageAttachmentFocus && app.UI.MediaOverlay.Focus == MediaFocusOverview {
if event.Key() == tcell.KeyRune {
switch event.Rune() {
case 'j', 'J':
app.UI.MediaOverlay.Next()
case 'k', 'K':
app.UI.MediaOverlay.Prev()
case 'd', 'D':
app.UI.MediaOverlay.Delete()
case 'a', 'A':
app.UI.MediaOverlay.SetFocus(MediaFocusAdd)
case 'q', 'Q':
app.UI.SetFocus(MessageFocus)
return nil
}
} else {
switch event.Key() {
case tcell.KeyUp:
app.UI.MediaOverlay.Prev()
case tcell.KeyDown:
app.UI.MediaOverlay.Next()
case tcell.KeyEsc:
app.UI.SetFocus(MessageFocus)
return nil
}
}
return event
}
if app.UI.Focus == MessageAttachmentFocus && app.UI.MediaOverlay.Focus == MediaFocusAdd {
if event.Key() == tcell.KeyRune {
app.UI.MediaOverlay.InputField.AddRune(event.Rune())
return nil
}
switch event.Key() {
case tcell.KeyTab, tcell.KeyDown:
app.UI.MediaOverlay.InputField.AutocompleteNext()
return nil
case tcell.KeyBacktab, tcell.KeyUp:
app.UI.MediaOverlay.InputField.AutocompletePrev()
return nil
case tcell.KeyEnter:
app.UI.MediaOverlay.InputField.CheckDone()
return nil
case tcell.KeyEsc:
app.UI.MediaOverlay.SetFocus(MediaFocusOverview)
}
return event
}
if app.UI.Focus == LeftPaneFocus {
if event.Key() == tcell.KeyRune {
switch event.Rune() {
case 'v', 'V':
app.UI.SetFocus(RightPaneFocus)
return nil
case 'k', 'K':
app.UI.TootList.Prev()
return nil
case 'j', 'J':
app.UI.TootList.Next()
return nil
case 'q', 'Q':
app.App.Stop()
return nil
}
} else {
switch event.Key() {
case tcell.KeyUp:
app.UI.TootList.Prev()
return nil
case tcell.KeyDown:
app.UI.TootList.Next()
return nil
case tcell.KeyEsc:
app.UI.TootList.GoBack()
return nil
case tcell.KeyCtrlC:
app.App.Stop()
return nil
}
}
}
if app.UI.Focus == RightPaneFocus {
if event.Key() != tcell.KeyRune {
switch event.Key() {
case tcell.KeyEsc:
app.UI.SetFocus(LeftPaneFocus)
}
}
}
if app.UI.Focus == LeftPaneFocus || app.UI.Focus == RightPaneFocus {
if event.Key() == tcell.KeyRune {
switch event.Rune() {
case ':':
app.UI.CmdBar.View.SetText(":")
app.UI.SetFocus(CmdBarFocus)
return nil
case 't', 'T':
app.UI.ShowThread()
case 's', 'S':
app.UI.ShowSensetive()
case 'c', 'C':
app.UI.NewToot()
case 'o', 'O':
app.UI.ShowLinks()
case 'r', 'R':
app.UI.Reply()
case 'm', 'M':
app.UI.OpenMedia()
case 'f', 'F':
//TODO UPDATE TOOT IN LIST
app.UI.FavoriteEvent()
case 'b':
//TODO UPDATE TOOT IN LIST
app.UI.BoostEvent()
case 'd':
app.UI.DeleteStatus()
}
}
}
return event
})
app.UI.MediaOverlay.InputField.View.SetChangedFunc(
app.UI.MediaOverlay.InputField.HandleChanges,
)
words := strings.Split(":q,:quit,:timeline", ",")
app.UI.CmdBar.View.SetAutocompleteFunc(func(currentText string) (entries []string) {
if currentText == "" {
return
}
for _, word := range words {
if strings.HasPrefix(strings.ToLower(word), strings.ToLower(currentText)) {
entries = append(entries, word)
}
}
if len(entries) < 1 {
entries = nil
}
return
})
app.UI.CmdBar.View.SetDoneFunc(func(key tcell.Key) {
input := app.UI.CmdBar.GetInput()
parts := strings.Split(input, " ")
if len(parts) == 0 {
return
}
switch parts[0] {
case ":q":
fallthrough
case ":quit":
app.App.Stop()
case ":timeline":
if len(parts) < 2 {
break
}
switch parts[1] {
case "local":
app.UI.SetTimeline(TimelineLocal)
app.UI.SetFocus(LeftPaneFocus)
app.UI.CmdBar.ClearInput()
case "federated":
app.UI.SetTimeline(TimelineFederated)
app.UI.SetFocus(LeftPaneFocus)
app.UI.CmdBar.ClearInput()
case "direct":
app.UI.SetTimeline(TimelineDirect)
app.UI.SetFocus(LeftPaneFocus)
app.UI.CmdBar.ClearInput()
case "home":
app.UI.SetTimeline(TimelineHome)
app.UI.SetFocus(LeftPaneFocus)
app.UI.CmdBar.ClearInput()
}
}
})
app.UI.AuthOverlay.View.SetDoneFunc(func(key tcell.Key) {
app.UI.AuthOverlay.GotInput()
})
if err := app.App.SetRoot(app.UI.Pages, true).Run(); err != nil {
panic(err)
}
}