Files
whatscli/main.go
2021-11-02 19:06:17 +01:00

737 lines
23 KiB
Go

package main
import (
"bufio"
"fmt"
"io"
"os/exec"
"strings"
"time"
"code.rocketnine.space/tslocum/cbind"
"github.com/gdamore/tcell/v2"
"github.com/normen/whatscli/config"
"github.com/normen/whatscli/messages"
"github.com/rivo/tview"
"github.com/skratchdot/open-golang/open"
"github.com/zyedidia/clipboard"
)
var VERSION string = "v1.0.11"
var sndTxt string = ""
var currentReceiver messages.Chat = messages.Chat{}
var curRegions []messages.Message
var textView *tview.TextView
var treeView *tview.TreeView
var textInput *tview.InputField
var topBar *tview.TextView
var infoBar *tview.TextView
var chatRoot *tview.TreeNode
var app *tview.Application
var sessionManager *messages.SessionManager
var keyBindings *cbind.Configuration
var uiHandler messages.UiMessageHandler
func main() {
config.InitConfig()
uiHandler = UiHandler{}
sessionManager = &messages.SessionManager{}
sessionManager.Init(uiHandler)
app = tview.NewApplication()
sideBarWidth := config.Config.Ui.ChatSidebarWidth
gridLayout := tview.NewGrid()
gridLayout.SetRows(1, 0, 1)
gridLayout.SetColumns(sideBarWidth, 0, sideBarWidth)
gridLayout.SetBorders(true)
gridLayout.SetBackgroundColor(tcell.ColorNames[config.Config.Colors.Background])
gridLayout.SetBordersColor(tcell.ColorNames[config.Config.Colors.Borders])
cmdPrefix := config.Config.General.CmdPrefix
topBar = tview.NewTextView()
topBar.SetDynamicColors(true)
topBar.SetScrollable(false)
topBar.SetText("[::b] WhatsCLI " + VERSION + " [-::d]Type " + cmdPrefix + "help or press " + config.Config.Keymap.CommandHelp + " for help")
topBar.SetBackgroundColor(tcell.ColorNames[config.Config.Colors.Background])
infoBar = tview.NewTextView()
infoBar.SetDynamicColors(true)
UpdateStatusBar(messages.SessionStatus{})
textView = tview.NewTextView().
SetDynamicColors(true).
SetRegions(true).
SetWordWrap(true).
SetChangedFunc(func() {
app.Draw()
})
textView.SetBackgroundColor(tcell.ColorNames[config.Config.Colors.Background])
textView.SetTextColor(tcell.ColorNames[config.Config.Colors.Text])
PrintHelp()
textInput = tview.NewInputField()
textInput.SetBackgroundColor(tcell.ColorNames[config.Config.Colors.Background])
textInput.SetFieldBackgroundColor(tcell.ColorNames[config.Config.Colors.InputBackground])
textInput.SetFieldTextColor(tcell.ColorNames[config.Config.Colors.InputText])
textInput.SetChangedFunc(func(change string) {
sndTxt = change
})
textInput.SetDoneFunc(EnterCommand)
textInput.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
if event.Key() == tcell.KeyDown {
offset, _ := textView.GetScrollOffset()
offset += 1
textView.ScrollTo(offset, 0)
return nil
}
if event.Key() == tcell.KeyUp {
offset, _ := textView.GetScrollOffset()
offset -= 1
textView.ScrollTo(offset, 0)
return nil
}
if event.Key() == tcell.KeyPgDn {
offset, _ := textView.GetScrollOffset()
offset += 10
textView.ScrollTo(offset, 0)
return nil
}
if event.Key() == tcell.KeyPgUp {
offset, _ := textView.GetScrollOffset()
offset -= 10
textView.ScrollTo(offset, 0)
return nil
}
return event
})
gridLayout.AddItem(topBar, 0, 0, 1, 4, 0, 0, false)
gridLayout.AddItem(infoBar, 2, 0, 1, 1, 0, 0, false)
gridLayout.AddItem(MakeTree(), 1, 0, 1, 1, 0, 0, false)
gridLayout.AddItem(textView, 1, 1, 1, 3, 0, 0, false)
gridLayout.AddItem(textInput, 2, 1, 1, 3, 0, 0, false)
app.SetRoot(gridLayout, true)
app.EnableMouse(true)
app.SetFocus(textInput)
if err := sessionManager.StartManager(); err != nil {
PrintError(err)
}
LoadShortcuts()
app.Run()
}
// creates the TreeView for chats
func MakeTree() *tview.TreeView {
rootDir := "Chats"
chatRoot = tview.NewTreeNode(rootDir).
SetColor(tcell.ColorNames[config.Config.Colors.ListHeader])
treeView = tview.NewTreeView().
SetRoot(chatRoot).
SetCurrentNode(chatRoot)
treeView.SetBackgroundColor(tcell.ColorNames[config.Config.Colors.Background])
// If a chat was selected, open it.
treeView.SetChangedFunc(func(node *tview.TreeNode) {
reference := node.GetReference()
if reference == nil {
SetDisplayedChat(messages.Chat{"", false, "", 0, 0})
return // Selecting the root node does nothing.
}
children := node.GetChildren()
if len(children) == 0 {
// Load and show files in this directory.
recv := reference.(messages.Chat)
SetDisplayedChat(recv)
} else {
// Collapse if visible, expand if collapsed.
node.SetExpanded(!node.IsExpanded())
}
})
return treeView
}
func handleFocusMessage(ev *tcell.EventKey) *tcell.EventKey {
if !textView.HasFocus() {
app.SetFocus(textView)
if curRegions != nil && len(curRegions) > 0 {
textView.Highlight(curRegions[len(curRegions)-1].Id)
}
}
return nil
}
func handleFocusInput(ev *tcell.EventKey) *tcell.EventKey {
ResetMsgSelection()
if !textInput.HasFocus() {
app.SetFocus(textInput)
}
return nil
}
func handleFocusContacts(ev *tcell.EventKey) *tcell.EventKey {
ResetMsgSelection()
if !treeView.HasFocus() {
app.SetFocus(treeView)
}
return nil
}
func handleSwitchPanels(ev *tcell.EventKey) *tcell.EventKey {
ResetMsgSelection()
if !textInput.HasFocus() {
app.SetFocus(textInput)
} else {
app.SetFocus(treeView)
}
return nil
}
func handleCommand(command string) func(ev *tcell.EventKey) *tcell.EventKey {
return func(ev *tcell.EventKey) *tcell.EventKey {
sessionManager.CommandChannel <- messages.Command{command, nil}
return nil
}
}
func handleCopyUser(ev *tcell.EventKey) *tcell.EventKey {
if hls := textView.GetHighlights(); len(hls) > 0 {
for _, val := range curRegions {
if val.Id == hls[0] {
clipboard.WriteAll(val.ContactId, "clipboard")
PrintText("copied id of " + val.ContactName + " to clipboard")
}
}
ResetMsgSelection()
} else if currentReceiver.Id != "" {
clipboard.WriteAll(currentReceiver.Id, "clipboard")
PrintText("copied id of " + currentReceiver.Name + " to clipboard")
}
return nil
}
func handlePasteUser(ev *tcell.EventKey) *tcell.EventKey {
if clip, err := clipboard.ReadAll("clipboard"); err == nil {
textInput.SetText(textInput.GetText() + " " + clip)
}
return nil
}
func handleQuit(ev *tcell.EventKey) *tcell.EventKey {
sessionManager.CommandChannel <- messages.Command{"disconnect", nil}
app.Stop()
return nil
}
func handleHelp(ev *tcell.EventKey) *tcell.EventKey {
PrintHelp()
return nil
}
func handleMessageCommand(command string) func(ev *tcell.EventKey) *tcell.EventKey {
return func(ev *tcell.EventKey) *tcell.EventKey {
hls := textView.GetHighlights()
if len(hls) > 0 {
sessionManager.CommandChannel <- messages.Command{command, []string{hls[0]}}
ResetMsgSelection()
app.SetFocus(textInput)
}
return nil
}
}
func handleMessagesMove(amount int) func(ev *tcell.EventKey) *tcell.EventKey {
return func(ev *tcell.EventKey) *tcell.EventKey {
if curRegions == nil || len(curRegions) == 0 {
return nil
}
hls := textView.GetHighlights()
if len(hls) > 0 {
newId := GetOffsetMsgId(hls[0], amount)
if newId != "" {
textView.Highlight(newId)
}
} else {
if amount < 0 {
textView.Highlight(curRegions[0].Id)
} else {
textView.Highlight(curRegions[len(curRegions)-1].Id)
}
}
textView.ScrollToHighlight()
return nil
}
}
func handleChatPanelUp(ev *tcell.EventKey) *tcell.EventKey {
//TODO: scroll selection in treeView? or chatRoot? How?
return ev
}
func handleChatPanelDown(ev *tcell.EventKey) *tcell.EventKey {
return ev
}
func handleMessagesLast(ev *tcell.EventKey) *tcell.EventKey {
if curRegions == nil || len(curRegions) == 0 {
return nil
}
textView.Highlight(curRegions[len(curRegions)-1].Id)
textView.ScrollToHighlight()
return nil
}
func handleMessagesFirst(ev *tcell.EventKey) *tcell.EventKey {
if curRegions == nil || len(curRegions) == 0 {
return nil
}
textView.Highlight(curRegions[0].Id)
textView.ScrollToHighlight()
return nil
}
func handleExitMessages(ev *tcell.EventKey) *tcell.EventKey {
if curRegions == nil || len(curRegions) == 0 {
return nil
}
ResetMsgSelection()
app.SetFocus(textInput)
return nil
}
// load the key map
func LoadShortcuts() {
// global bindings for app
keyBindings = cbind.NewConfiguration()
if err := keyBindings.Set(config.Config.Keymap.FocusMessages, handleFocusMessage); err != nil {
PrintErrorMsg("focus_messages:", err)
}
if err := keyBindings.Set(config.Config.Keymap.FocusInput, handleFocusInput); err != nil {
PrintErrorMsg("focus_input:", err)
}
if err := keyBindings.Set(config.Config.Keymap.FocusChats, handleFocusContacts); err != nil {
PrintErrorMsg("focus_contacts:", err)
}
if err := keyBindings.Set(config.Config.Keymap.SwitchPanels, handleSwitchPanels); err != nil {
PrintErrorMsg("switch_panels:", err)
}
if err := keyBindings.Set(config.Config.Keymap.CommandRead, handleCommand("read")); err != nil {
PrintErrorMsg("command_read:", err)
}
if err := keyBindings.Set(config.Config.Keymap.Copyuser, handleCopyUser); err != nil {
PrintErrorMsg("copyuser:", err)
}
if err := keyBindings.Set(config.Config.Keymap.Pasteuser, handlePasteUser); err != nil {
PrintErrorMsg("pasteuser:", err)
}
if err := keyBindings.Set(config.Config.Keymap.CommandBacklog, handleCommand("backlog")); err != nil {
PrintErrorMsg("command_backlog:", err)
}
if err := keyBindings.Set(config.Config.Keymap.CommandConnect, handleCommand("login")); err != nil {
PrintErrorMsg("command_connect:", err)
}
if err := keyBindings.Set(config.Config.Keymap.CommandQuit, handleQuit); err != nil {
PrintErrorMsg("command_quit:", err)
}
if err := keyBindings.Set(config.Config.Keymap.CommandHelp, handleHelp); err != nil {
PrintErrorMsg("command_help:", err)
}
app.SetInputCapture(keyBindings.Capture)
// bindings for chat message text view
keysMessages := cbind.NewConfiguration()
if err := keysMessages.Set(config.Config.Keymap.MessageDownload, handleMessageCommand("download")); err != nil {
PrintErrorMsg("message_download:", err)
}
if err := keysMessages.Set(config.Config.Keymap.MessageOpen, handleMessageCommand("open")); err != nil {
PrintErrorMsg("message_open:", err)
}
if err := keysMessages.Set(config.Config.Keymap.Copyuser, handleCopyUser); err != nil {
PrintErrorMsg("copyuser:", err)
}
if err := keysMessages.Set(config.Config.Keymap.Pasteuser, handlePasteUser); err != nil {
PrintErrorMsg("pasteuser:", err)
}
if err := keysMessages.Set(config.Config.Keymap.MessageShow, handleMessageCommand("show")); err != nil {
PrintErrorMsg("message_show:", err)
}
if err := keysMessages.Set(config.Config.Keymap.MessageUrl, handleMessageCommand("url")); err != nil {
PrintErrorMsg("message_url:", err)
}
if err := keysMessages.Set(config.Config.Keymap.MessageInfo, handleMessageCommand("info")); err != nil {
PrintErrorMsg("message_info:", err)
}
if err := keysMessages.Set(config.Config.Keymap.MessageRevoke, handleMessageCommand("revoke")); err != nil {
PrintErrorMsg("message_revoke:", err)
}
keysMessages.SetKey(tcell.ModNone, tcell.KeyEscape, handleExitMessages)
keysMessages.SetKey(tcell.ModNone, tcell.KeyUp, handleMessagesMove(-1))
keysMessages.SetKey(tcell.ModNone, tcell.KeyDown, handleMessagesMove(1))
keysMessages.SetKey(tcell.ModNone, tcell.KeyPgUp, handleMessagesMove(-10))
keysMessages.SetKey(tcell.ModNone, tcell.KeyPgDn, handleMessagesMove(10))
keysMessages.SetRune(tcell.ModNone, 'k', handleMessagesMove(-1))
keysMessages.SetRune(tcell.ModNone, 'j', handleMessagesMove(1))
keysMessages.SetRune(tcell.ModNone, 'g', handleMessagesFirst)
keysMessages.SetRune(tcell.ModNone, 'G', handleMessagesLast)
keysMessages.SetRune(tcell.ModCtrl, 'u', handleMessagesMove(-10))
keysMessages.SetRune(tcell.ModCtrl, 'd', handleMessagesMove(10))
textView.SetInputCapture(keysMessages.Capture)
keysChatPanel := cbind.NewConfiguration()
keysChatPanel.SetRune(tcell.ModCtrl, 'u', handleChatPanelUp)
keysChatPanel.SetRune(tcell.ModCtrl, 'd', handleChatPanelDown)
treeView.SetInputCapture(keysChatPanel.Capture)
}
// prints help to chat view
func PrintHelp() {
cmdPrefix := config.Config.General.CmdPrefix
fmt.Fprintln(textView, "[-::u]Keys:[-::-]")
fmt.Fprintln(textView, "")
fmt.Fprintln(textView, "Global")
fmt.Fprintln(textView, "[::b] Up/Down[::-] = Scroll history/chats")
fmt.Fprintln(textView, "[::b]", config.Config.Keymap.SwitchPanels, "[::-] = Switch input/chats")
fmt.Fprintln(textView, "[::b]", config.Config.Keymap.FocusMessages, "[::-] = Focus message panel")
fmt.Fprintln(textView, "[::b]", config.Config.Keymap.CommandQuit, "[::-] = Exit app")
fmt.Fprintln(textView, "")
fmt.Fprintln(textView, "[-::-]Message panel[-::-]")
fmt.Fprintln(textView, "[::b] Up/Down[::-] = select message")
fmt.Fprintln(textView, "[::b]", config.Config.Keymap.MessageDownload, "[::-] = Download attachment")
fmt.Fprintln(textView, "[::b]", config.Config.Keymap.MessageOpen, "[::-] = Download & open attachment")
fmt.Fprintln(textView, "[::b]", config.Config.Keymap.MessageShow, "[::-] = Download & show image using", config.Config.General.ShowCommand)
fmt.Fprintln(textView, "[::b]", config.Config.Keymap.MessageUrl, "[::-] = Find URL in message and open it")
fmt.Fprintln(textView, "[::b]", config.Config.Keymap.MessageRevoke, "[::-] = Revoke message")
fmt.Fprintln(textView, "[::b]", config.Config.Keymap.MessageInfo, "[::-] = Info about message")
fmt.Fprintln(textView, "")
fmt.Fprintln(textView, "Config file in ->", config.GetConfigFilePath())
fmt.Fprintln(textView, "")
fmt.Fprintln(textView, "Type [::b]"+cmdPrefix+"commands[::-] to see all commands")
fmt.Fprintln(textView, "")
}
func PrintCommands() {
cmdPrefix := config.Config.General.CmdPrefix
fmt.Fprintln(textView, "")
fmt.Fprintln(textView, "[-::u]Commands:[-::-]")
fmt.Fprintln(textView, "")
fmt.Fprintln(textView, "[-::-]Global[-::-]")
fmt.Fprintln(textView, "[::b] "+cmdPrefix+"connect [::-]or[::b]", config.Config.Keymap.CommandConnect, "[::-] = (Re)Connect to server")
fmt.Fprintln(textView, "[::b] "+cmdPrefix+"disconnect[::-] = Close the connection")
fmt.Fprintln(textView, "[::b] "+cmdPrefix+"logout[::-] = Remove login data from computer")
fmt.Fprintln(textView, "[::b] "+cmdPrefix+"quit [::-]or[::b]", config.Config.Keymap.CommandQuit, "[::-] = Exit app")
fmt.Fprintln(textView, "")
fmt.Fprintln(textView, "[-::-]Chat[-::-]")
fmt.Fprintln(textView, "[::b] "+cmdPrefix+"backlog [::-]or[::b]", config.Config.Keymap.CommandBacklog, "[::-] = load next", config.Config.General.BacklogMsgQuantity, "previous messages")
fmt.Fprintln(textView, "[::b] "+cmdPrefix+"read [::-]or[::b]", config.Config.Keymap.CommandRead, "[::-] = mark new messages in chat as read")
fmt.Fprintln(textView, "[::b] "+cmdPrefix+"upload[::-] /path/to/file = Upload any file as document")
fmt.Fprintln(textView, "[::b] "+cmdPrefix+"sendimage[::-] /path/to/file = Send image message")
fmt.Fprintln(textView, "[::b] "+cmdPrefix+"sendvideo[::-] /path/to/file = Send video message")
fmt.Fprintln(textView, "[::b] "+cmdPrefix+"sendaudio[::-] /path/to/file = Send audio message")
fmt.Fprintln(textView, "")
fmt.Fprintln(textView, "[-::-]Groups[-::-]")
fmt.Fprintln(textView, "[::b] "+cmdPrefix+"leave[::-] = Leave group")
fmt.Fprintln(textView, "[::b] "+cmdPrefix+"create[::-] [user-id[] [user-id[] Group Subject = Create group with users")
fmt.Fprintln(textView, "[::b] "+cmdPrefix+"subject[::-] New Subject = Change subject of group")
fmt.Fprintln(textView, "[::b] "+cmdPrefix+"add[::-] [user-id[] = Add user to group")
fmt.Fprintln(textView, "[::b] "+cmdPrefix+"remove[::-] [user-id[] = Remove user from group")
fmt.Fprintln(textView, "[::b] "+cmdPrefix+"admin[::-] [user-id[] = Set admin role for user in group")
fmt.Fprintln(textView, "[::b] "+cmdPrefix+"removeadmin[::-] [user-id[] = Remove admin role for user in group")
fmt.Fprintln(textView, "")
fmt.Fprintln(textView, "Use[::b]", config.Config.Keymap.Copyuser, "[::-]to copy a selected user id to clipboard")
fmt.Fprintln(textView, "Use[::b]", config.Config.Keymap.Pasteuser, "[::-]to paste clipboard to text input")
fmt.Fprintln(textView, "")
}
// called when text is entered by the user
func EnterCommand(key tcell.Key) {
if sndTxt == "" {
return
}
if key == tcell.KeyEsc {
textInput.SetText("")
return
}
cmdPrefix := config.Config.General.CmdPrefix
if sndTxt == cmdPrefix+"help" {
PrintHelp()
textInput.SetText("")
return
}
if sndTxt == cmdPrefix+"commands" {
PrintCommands()
textInput.SetText("")
return
}
if sndTxt == cmdPrefix+"quit" {
sessionManager.CommandChannel <- messages.Command{"disconnect", nil}
app.Stop()
return
}
if strings.HasPrefix(sndTxt, cmdPrefix) {
cmd := strings.TrimPrefix(sndTxt, cmdPrefix)
var params []string
if strings.Index(cmd, " ") >= 0 {
cmdParts := strings.Split(cmd, " ")
cmd = cmdParts[0]
params = cmdParts[1:]
}
sessionManager.CommandChannel <- messages.Command{cmd, params}
textInput.SetText("")
return
}
if currentReceiver.Id == "" {
PrintText("no receiver")
textInput.SetText("")
return
}
// no command, send as message
msg := messages.Command{
Name: "send",
Params: []string{currentReceiver.Id, sndTxt},
}
sessionManager.CommandChannel <- msg
textInput.SetText("")
}
// get the next message id to select (highlighted + offset)
func GetOffsetMsgId(curId string, offset int) string {
if curRegions == nil || len(curRegions) == 0 {
return ""
}
for idx, val := range curRegions {
if val.Id == curId {
arrPos := idx + offset
if len(curRegions) > arrPos && arrPos >= 0 {
return curRegions[arrPos].Id
}
}
}
if offset > 0 {
return curRegions[0].Id
} else {
return curRegions[len(curRegions)-1].Id
}
}
// resets the selection in the textView and scrolls it down
func ResetMsgSelection() {
if len(textView.GetHighlights()) > 0 {
textView.Highlight("")
}
textView.ScrollToEnd()
}
// prints text to the TextView
func PrintText(txt string) {
fmt.Fprintln(textView, txt)
}
// prints an error to the TextView
func PrintError(err error) {
if err == nil {
return
}
fmt.Fprintln(textView, "["+config.Config.Colors.Negative+"]", err.Error(), "[-]")
}
// prints an error to the TextView
func PrintErrorMsg(text string, err error) {
if err == nil {
return
}
fmt.Fprintln(textView, "["+config.Config.Colors.Negative+"]", text, err.Error(), "[-]")
}
// prints an image attachment to the TextView (by message id)
func PrintImage(path string) {
var err error
cmdParts := strings.Split(config.Config.General.ShowCommand, " ")
cmdParts = append(cmdParts, path)
var cmd *exec.Cmd
size := len(cmdParts)
if size > 1 {
cmd = exec.Command(cmdParts[0], cmdParts[1:]...)
} else if size > 0 {
cmd = exec.Command(cmdParts[0])
}
var stdout io.ReadCloser
if stdout, err = cmd.StdoutPipe(); err == nil {
if err = cmd.Start(); err == nil {
reader := bufio.NewReader(stdout)
io.Copy(tview.ANSIWriter(textView), reader)
return
}
}
PrintError(err)
}
// updates the status bar
func UpdateStatusBar(statusInfo messages.SessionStatus) {
out := " "
if statusInfo.Connected {
out += "[" + config.Config.Colors.Positive + "]online[-]"
} else {
out += "[" + config.Config.Colors.Negative + "]offline[-]"
}
out += " "
out += "[::d] ("
out += fmt.Sprint(statusInfo.BatteryCharge)
out += "%"
if statusInfo.BatteryLoading {
out += " [" + config.Config.Colors.Positive + "]L[-]"
} else {
out += " [" + config.Config.Colors.Negative + "]l[-]"
}
if statusInfo.BatteryPowersave {
out += " [" + config.Config.Colors.Negative + "]S[-]"
} else {
out += " [" + config.Config.Colors.Positive + "]s[-]"
}
out += ")[::-] "
out += statusInfo.LastSeen
infoBar.SetText(out)
//infoBar.SetText("🔋: ??%")
}
// sets the current chat, loads text from storage to TextView
func SetDisplayedChat(wid messages.Chat) {
//TODO: how to get chat to set
currentReceiver = wid
textView.Clear()
textView.SetTitle(wid.Name)
sessionManager.CommandChannel <- messages.Command{"select", []string{currentReceiver.Id}}
}
// get a string representation of all messages for chat
func getMessagesString(msgs []messages.Message) string {
out := ""
for _, msg := range msgs {
out += getTextMessageString(&msg)
out += "\n"
}
return out
}
// create a formatted string with regions based on message ID from a text message
//TODO: optimize, use Sprintf etc
func getTextMessageString(msg *messages.Message) string {
colorMe := config.Config.Colors.ChatMe
colorContact := config.Config.Colors.ChatContact
out := ""
text := tview.Escape(msg.Text)
if msg.Forwarded {
text = "[" + config.Config.Colors.ForwardedText + "]" + text + "[-]"
}
tim := time.Unix(int64(msg.Timestamp), 0)
time := tim.Format("02-01-06 15:04:05")
out += "[\""
out += msg.Id
out += "\"]"
if msg.FromMe { //msg from me
out += "[-::d](" + time + ") [" + colorMe + "::b]Me: [-::-]" + text
} else { // message from others
out += "[-::d](" + time + ") [" + colorContact + "::b]" + msg.ContactShort + ": [-::-]" + text
}
out += "[\"\"]"
return out
}
type UiHandler struct{}
func (u UiHandler) NewMessage(msg messages.Message) {
//TODO: its stupid to "go" this as its supposed to run
//on the ui thread anyway. But QueueUpdate blocks...?
go app.QueueUpdateDraw(func() {
curRegions = append(curRegions, msg)
PrintText(getTextMessageString(&msg))
})
}
func (u UiHandler) NewScreen(msgs []messages.Message) {
go app.QueueUpdateDraw(func() {
textView.Clear()
screen := getMessagesString(msgs)
textView.SetText(screen)
curRegions = msgs
if screen == "" {
if currentReceiver.Id == "" {
PrintHelp()
} else {
PrintText("[::d] ~~~ no messages, press " + config.Config.Keymap.CommandBacklog + " to load backlog if available ~~~[::-]")
}
}
})
}
// loads the chat data from storage to the TreeView
func (u UiHandler) SetChats(ids []messages.Chat) {
go app.QueueUpdateDraw(func() {
chatRoot.ClearChildren()
oldId := currentReceiver.Id
for _, element := range ids {
name := element.Name
if name == "" {
name = strings.TrimSuffix(strings.TrimSuffix(element.Id, messages.GROUPSUFFIX), messages.CONTACTSUFFIX)
}
if element.Unread > 0 {
name += " ([" + config.Config.Colors.UnreadCount + "]" + fmt.Sprint(element.Unread) + "[-])"
//tim := time.Unix(element.LastMessage, 0)
//sin := time.Since(tim)
//since := fmt.Sprintf("%s", sin)
//time := tim.Format("02-01-06 15:04:05")
//name += since
}
node := tview.NewTreeNode(name).
SetReference(element).
SetSelectable(true)
if element.IsGroup {
node.SetColor(tcell.ColorNames[config.Config.Colors.ListGroup])
} else {
node.SetColor(tcell.ColorNames[config.Config.Colors.ListContact])
}
// store new currentReceiver, else the selection on the left goes off
if element.Id == oldId {
currentReceiver = element
}
chatRoot.AddChild(node)
if element.Id == currentReceiver.Id {
treeView.SetCurrentNode(node)
}
}
})
}
func (u UiHandler) PrintError(err error) {
PrintError(err)
}
func (u UiHandler) PrintText(msg string) {
PrintText(msg)
}
func (u UiHandler) PrintFile(path string) {
go app.QueueUpdateDraw(func() {
PrintImage(path)
})
}
func (u UiHandler) OpenFile(path string) {
open.Run(path)
}
func (u UiHandler) SetStatus(status messages.SessionStatus) {
go app.QueueUpdateDraw(func() {
UpdateStatusBar(status)
})
}
func (u UiHandler) GetWriter() io.Writer {
return textView
}