Code additions/edits
This commit is contained in:
parent
f0333df1b2
commit
90629c5c78
26
config.go
26
config.go
@ -29,14 +29,23 @@ type Config struct {
|
||||
MXID string `yaml:"mxid"`
|
||||
HS string `yaml:"homeserver"`
|
||||
|
||||
dir string `yaml:"-"`
|
||||
Session *Session `yaml:"-"`
|
||||
dir string `yaml:"-"`
|
||||
gmx Gomuks `yaml:"-"`
|
||||
debug DebugPrinter `yaml:"-"`
|
||||
Session *Session `yaml:"-"`
|
||||
}
|
||||
|
||||
func (config *Config) Load(dir string) {
|
||||
config.dir = dir
|
||||
os.MkdirAll(dir, 0700)
|
||||
configPath := filepath.Join(dir, "config.yaml")
|
||||
func NewConfig(gmx Gomuks, dir string) *Config {
|
||||
return &Config{
|
||||
gmx: gmx,
|
||||
debug: gmx.Debug(),
|
||||
dir: dir,
|
||||
}
|
||||
}
|
||||
|
||||
func (config *Config) Load() {
|
||||
os.MkdirAll(config.dir, 0700)
|
||||
configPath := filepath.Join(config.dir, "config.yaml")
|
||||
data, err := ioutil.ReadFile(configPath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
@ -55,16 +64,17 @@ func (config *Config) Load(dir string) {
|
||||
}
|
||||
|
||||
func (config *Config) Save() {
|
||||
os.MkdirAll(config.dir, 0700)
|
||||
data, err := yaml.Marshal(&config)
|
||||
if err != nil {
|
||||
debug.Print("Failed to marshal config")
|
||||
config.debug.Print("Failed to marshal config")
|
||||
panic(err)
|
||||
}
|
||||
|
||||
path := filepath.Join(config.dir, "config.yaml")
|
||||
err = ioutil.WriteFile(path, data, 0600)
|
||||
if err != nil {
|
||||
debug.Print("Failed to write config to", path)
|
||||
config.debug.Print("Failed to write config to", path)
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
45
debug.go
45
debug.go
@ -22,35 +22,54 @@ import (
|
||||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
const DebugPaneHeight = 40
|
||||
|
||||
type DebugPrinter interface {
|
||||
Printf(text string, args ...interface{})
|
||||
Print(text ...interface{})
|
||||
}
|
||||
|
||||
type DebugPane struct {
|
||||
text string
|
||||
pane *tview.TextView
|
||||
num int
|
||||
gmx Gomuks
|
||||
}
|
||||
|
||||
func NewDebugPane(gmx Gomuks) *DebugPane {
|
||||
pane := tview.NewTextView()
|
||||
pane.
|
||||
SetScrollable(true).
|
||||
SetWrap(true)
|
||||
pane.SetChangedFunc(func() {
|
||||
gmx.App().Draw()
|
||||
})
|
||||
pane.SetBorder(true).SetTitle("Debug output")
|
||||
fmt.Fprintln(pane, "[0] Debug pane initialized")
|
||||
|
||||
return &DebugPane{
|
||||
pane: pane,
|
||||
num: 0,
|
||||
gmx: gmx,
|
||||
}
|
||||
}
|
||||
|
||||
func (db *DebugPane) Printf(text string, args ...interface{}) {
|
||||
db.num++
|
||||
db.Write(fmt.Sprintf("[%d] %s\n", db.num, fmt.Sprintf(text, args...)))
|
||||
db.Write(fmt.Sprintf(text, args...))
|
||||
}
|
||||
|
||||
func (db *DebugPane) Print(text ...interface{}) {
|
||||
db.num++
|
||||
db.Write(fmt.Sprintf("[%d] %s", db.num, fmt.Sprintln(text...)))
|
||||
db.Write(fmt.Sprint(text...))
|
||||
}
|
||||
|
||||
func (db *DebugPane) Write(text string) {
|
||||
if db.pane != nil {
|
||||
db.text += text
|
||||
db.pane.SetText(db.text)
|
||||
db.num++
|
||||
fmt.Fprintf(db.pane, "[%d] %s\n", db.num, text)
|
||||
}
|
||||
}
|
||||
|
||||
func (db *DebugPane) Wrap(main *tview.Pages) tview.Primitive {
|
||||
db.pane = tview.NewTextView()
|
||||
db.pane.SetBorder(true).SetTitle("Debug output")
|
||||
db.text += "[0] Debug pane initialized\n"
|
||||
db.pane.SetText(db.text)
|
||||
return tview.NewGrid().SetRows(0, 20).SetColumns(0).
|
||||
func (db *DebugPane) Wrap(main tview.Primitive) tview.Primitive {
|
||||
return tview.NewGrid().SetRows(0, DebugPaneHeight).SetColumns(0).
|
||||
AddItem(main, 0, 0, 1, 1, 1, 1, true).
|
||||
AddItem(db.pane, 1, 0, 1, 1, 1, 1, false)
|
||||
}
|
||||
|
124
gomuks.go
124
gomuks.go
@ -20,94 +20,84 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gdamore/tcell"
|
||||
"github.com/matrix-org/gomatrix"
|
||||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
var matrix = new(MatrixContainer)
|
||||
var config = new(Config)
|
||||
var debug = new(DebugPane)
|
||||
type Gomuks interface {
|
||||
Debug() DebugPrinter
|
||||
Matrix() *gomatrix.Client
|
||||
MatrixContainer() *MatrixContainer
|
||||
App() *tview.Application
|
||||
UI() *GomuksUI
|
||||
Config() *Config
|
||||
}
|
||||
|
||||
func main() {
|
||||
type gomuks struct {
|
||||
app *tview.Application
|
||||
ui *GomuksUI
|
||||
matrix *MatrixContainer
|
||||
debug *DebugPane
|
||||
config *Config
|
||||
}
|
||||
|
||||
func NewGomuks(debug bool) *gomuks {
|
||||
configDir := filepath.Join(os.Getenv("HOME"), ".config/gomuks")
|
||||
os.MkdirAll(configDir, 0700)
|
||||
config.Load(configDir)
|
||||
|
||||
views := tview.NewPages()
|
||||
InitUI(views)
|
||||
|
||||
main := debug.Wrap(views)
|
||||
|
||||
if len(config.MXID) > 0 {
|
||||
config.LoadSession(config.MXID)
|
||||
gmx := &gomuks{
|
||||
app: tview.NewApplication(),
|
||||
}
|
||||
matrix.Init(config)
|
||||
gmx.debug = NewDebugPane(gmx)
|
||||
gmx.config = NewConfig(gmx, configDir)
|
||||
gmx.ui = NewGomuksUI(gmx)
|
||||
gmx.matrix = NewMatrixContainer(gmx)
|
||||
gmx.ui.matrix = gmx.matrix
|
||||
|
||||
if err := tview.NewApplication().SetRoot(main, true).Run(); err != nil {
|
||||
gmx.config.Load()
|
||||
if len(gmx.config.MXID) > 0 {
|
||||
gmx.config.LoadSession(gmx.config.MXID)
|
||||
}
|
||||
|
||||
gmx.matrix.InitClient()
|
||||
|
||||
main := gmx.ui.InitViews()
|
||||
if debug {
|
||||
main = gmx.debug.Wrap(main)
|
||||
}
|
||||
gmx.app.SetRoot(main, true)
|
||||
|
||||
return gmx
|
||||
}
|
||||
|
||||
func (gmx *gomuks) Start() {
|
||||
if err := gmx.app.Run(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func InitUI(views *tview.Pages) {
|
||||
views.AddPage("login", InitLoginUI(), true, true)
|
||||
func (gmx *gomuks) Debug() DebugPrinter {
|
||||
return gmx.debug
|
||||
}
|
||||
|
||||
func Center(width, height int, p tview.Primitive) tview.Primitive {
|
||||
return tview.NewFlex().
|
||||
AddItem(tview.NewBox(), 0, 1, false).
|
||||
AddItem(tview.NewFlex().
|
||||
SetDirection(tview.FlexRow).
|
||||
AddItem(tview.NewBox(), 0, 1, false).
|
||||
AddItem(p, height, 1, true).
|
||||
AddItem(tview.NewBox(), 0, 1, false), width, 1, true).
|
||||
AddItem(tview.NewBox(), 0, 1, false)
|
||||
func (gmx *gomuks) Matrix() *gomatrix.Client {
|
||||
return gmx.matrix.client
|
||||
}
|
||||
|
||||
type FormTextView struct {
|
||||
*tview.TextView
|
||||
func (gmx *gomuks) MatrixContainer() *MatrixContainer {
|
||||
return gmx.matrix
|
||||
}
|
||||
|
||||
func (ftv *FormTextView) GetLabel() string {
|
||||
return ""
|
||||
func (gmx *gomuks) App() *tview.Application {
|
||||
return gmx.app
|
||||
}
|
||||
|
||||
func (ftv *FormTextView) SetFormAttributes(label string, labelColor, bgColor, fieldTextColor, fieldBgColor tcell.Color) tview.FormItem {
|
||||
return ftv
|
||||
func (gmx *gomuks) Config() *Config {
|
||||
return gmx.config
|
||||
}
|
||||
|
||||
func (ftv *FormTextView) GetFieldWidth() int {
|
||||
_, _, w, _ := ftv.TextView.GetRect()
|
||||
return w
|
||||
func (gmx *gomuks) UI() *GomuksUI {
|
||||
return gmx.ui
|
||||
}
|
||||
|
||||
func (ftv *FormTextView) SetFinishedFunc(handler func(key tcell.Key)) tview.FormItem {
|
||||
ftv.SetDoneFunc(handler)
|
||||
return ftv
|
||||
}
|
||||
|
||||
func login(form *tview.Form) func() {
|
||||
return func() {
|
||||
hs := form.GetFormItem(0).(*tview.InputField).GetText()
|
||||
mxid := form.GetFormItem(1).(*tview.InputField).GetText()
|
||||
password := form.GetFormItem(2).(*tview.InputField).GetText()
|
||||
debug.Printf("%s %s %s", hs, mxid, password)
|
||||
config.HS = hs
|
||||
debug.Print(matrix.Init(config))
|
||||
debug.Print(matrix.Login(mxid, password))
|
||||
}
|
||||
}
|
||||
|
||||
func InitLoginUI() tview.Primitive {
|
||||
form := tview.NewForm().SetButtonsAlign(tview.AlignCenter)
|
||||
hs := config.HS
|
||||
if len(hs) == 0 {
|
||||
hs = "https://matrix.org"
|
||||
}
|
||||
form.
|
||||
AddInputField("Homeserver", hs, 30, nil, nil).
|
||||
AddInputField("Username", config.MXID, 30, nil, nil).
|
||||
AddPasswordField("Password", "", 30, '*', nil).
|
||||
AddButton("Log in", login(form))
|
||||
form.SetBorder(true).SetTitle("Log in to Matrix")
|
||||
return Center(45, 13, form)
|
||||
func main() {
|
||||
NewGomuks(true).Start()
|
||||
}
|
||||
|
74
matrix.go
74
matrix.go
@ -23,27 +23,36 @@ import (
|
||||
)
|
||||
|
||||
type MatrixContainer struct {
|
||||
lient *gomatrix.Client
|
||||
client *gomatrix.Client
|
||||
gmx Gomuks
|
||||
ui *GomuksUI
|
||||
debug DebugPrinter
|
||||
config *Config
|
||||
running bool
|
||||
stop chan bool
|
||||
}
|
||||
|
||||
func (c *MatrixContainer) Initialized() bool {
|
||||
return c.lient != nil
|
||||
}
|
||||
|
||||
func (c *MatrixContainer) Init(config *Config) error {
|
||||
c.config = config
|
||||
|
||||
if c.lient != nil {
|
||||
c.lient.StopSync()
|
||||
func NewMatrixContainer(gmx Gomuks) *MatrixContainer {
|
||||
c := &MatrixContainer{
|
||||
config: gmx.Config(),
|
||||
debug: gmx.Debug(),
|
||||
ui: gmx.UI(),
|
||||
gmx: gmx,
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *MatrixContainer) InitClient() error {
|
||||
if len(c.config.HS) == 0 {
|
||||
return fmt.Errorf("no homeserver in config")
|
||||
}
|
||||
|
||||
if c.client != nil {
|
||||
c.Stop()
|
||||
c.client = nil
|
||||
}
|
||||
|
||||
var mxid, accessToken string
|
||||
if c.config.Session != nil {
|
||||
accessToken = c.config.Session.AccessToken
|
||||
@ -51,7 +60,7 @@ func (c *MatrixContainer) Init(config *Config) error {
|
||||
}
|
||||
|
||||
var err error
|
||||
c.lient, err = gomatrix.NewClient(c.config.HS, mxid, accessToken)
|
||||
c.client, err = gomatrix.NewClient(c.config.HS, mxid, accessToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -64,8 +73,12 @@ func (c *MatrixContainer) Init(config *Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *MatrixContainer) Initialized() bool {
|
||||
return c.client != nil
|
||||
}
|
||||
|
||||
func (c *MatrixContainer) Login(user, password string) error {
|
||||
resp, err := c.lient.Login(&gomatrix.ReqLogin{
|
||||
resp, err := c.client.Login(&gomatrix.ReqLogin{
|
||||
Type: "m.login.password",
|
||||
User: user,
|
||||
Password: password,
|
||||
@ -73,7 +86,7 @@ func (c *MatrixContainer) Login(user, password string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.lient.SetCredentials(resp.UserID, resp.AccessToken)
|
||||
c.client.SetCredentials(resp.UserID, resp.AccessToken)
|
||||
c.config.MXID = resp.UserID
|
||||
c.config.Save()
|
||||
|
||||
@ -88,31 +101,50 @@ func (c *MatrixContainer) Login(user, password string) error {
|
||||
|
||||
func (c *MatrixContainer) Stop() {
|
||||
c.stop <- true
|
||||
c.lient.StopSync()
|
||||
c.client.StopSync()
|
||||
}
|
||||
|
||||
func (c *MatrixContainer) UpdateRoomList() {
|
||||
rooms, err := c.client.JoinedRooms()
|
||||
if err != nil {
|
||||
c.debug.Print(err)
|
||||
}
|
||||
|
||||
c.ui.SetRoomList(rooms.JoinedRooms)
|
||||
}
|
||||
|
||||
func (c *MatrixContainer) Start() {
|
||||
debug.Print("Starting sync...")
|
||||
c.debug.Print("Starting sync...")
|
||||
c.running = true
|
||||
c.lient.Store = c.config.Session
|
||||
c.ui.SetView(ViewMain)
|
||||
c.client.Store = c.config.Session
|
||||
|
||||
syncer := c.lient.Syncer.(*gomatrix.DefaultSyncer)
|
||||
c.UpdateRoomList()
|
||||
|
||||
syncer := c.client.Syncer.(*gomatrix.DefaultSyncer)
|
||||
syncer.OnEventType("m.room.message", c.HandleMessage)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-c.stop:
|
||||
debug.Print("Stopping sync...")
|
||||
c.debug.Print("Stopping sync...")
|
||||
c.running = false
|
||||
return
|
||||
default:
|
||||
if err := c.lient.Sync(); err != nil {
|
||||
debug.Print("Sync() errored", err)
|
||||
if err := c.client.Sync(); err != nil {
|
||||
c.debug.Print("Sync() errored", err)
|
||||
} else {
|
||||
c.debug.Print("Sync() returned without error")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *MatrixContainer) HandleMessage(evt *gomatrix.Event) {
|
||||
debug.Print("Message received")
|
||||
message, _ := evt.Content["body"].(string)
|
||||
c.ui.Append(evt.RoomID, evt.Sender, message)
|
||||
}
|
||||
|
||||
func (c *MatrixContainer) SendMessage(roomID, message string) {
|
||||
c.client.SendText(roomID, message)
|
||||
}
|
||||
|
11
session.go
11
session.go
@ -31,6 +31,8 @@ type Session struct {
|
||||
NextBatch string
|
||||
FilterID string
|
||||
Rooms map[string]*gomatrix.Room
|
||||
|
||||
debug DebugPrinter `json:"-"`
|
||||
}
|
||||
|
||||
func (config *Config) LoadSession(mxid string) {
|
||||
@ -43,19 +45,20 @@ func (config *Config) NewSession(mxid string) *Session {
|
||||
MXID: mxid,
|
||||
path: filepath.Join(config.dir, mxid+".session"),
|
||||
Rooms: make(map[string]*gomatrix.Room),
|
||||
debug: config.debug,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Session) Load() {
|
||||
data, err := ioutil.ReadFile(s.path)
|
||||
if err != nil {
|
||||
debug.Print("Failed to read session from", s.path)
|
||||
s.debug.Print("Failed to read session from", s.path)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(data, s)
|
||||
if err != nil {
|
||||
debug.Print("Failed to parse session at", s.path)
|
||||
s.debug.Print("Failed to parse session at", s.path)
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@ -63,13 +66,13 @@ func (s *Session) Load() {
|
||||
func (s *Session) Save() {
|
||||
data, err := json.Marshal(s)
|
||||
if err != nil {
|
||||
debug.Print("Failed to marshal session of", s.MXID)
|
||||
s.debug.Print("Failed to marshal session of", s.MXID)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(s.path, data, 0600)
|
||||
if err != nil {
|
||||
debug.Print("Failed to write session to", s.path)
|
||||
s.debug.Print("Failed to write session to", s.path)
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
71
ui.go
Normal file
71
ui.go
Normal file
@ -0,0 +1,71 @@
|
||||
// gomuks - A terminal Matrix client written in Go.
|
||||
// Copyright (C) 2018 Tulir Asokan
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
// Allowed views in GomuksUI
|
||||
const (
|
||||
ViewLogin = "login"
|
||||
ViewMain = "main"
|
||||
)
|
||||
|
||||
type GomuksUI struct {
|
||||
gmx Gomuks
|
||||
app *tview.Application
|
||||
matrix *MatrixContainer
|
||||
debug DebugPrinter
|
||||
config *Config
|
||||
views *tview.Pages
|
||||
|
||||
mainView *tview.Grid
|
||||
mainViewRoomList *tview.List
|
||||
mainViewRoomView *tview.Pages
|
||||
mainViewInput *tview.InputField
|
||||
mainViewRooms map[string]*RoomView
|
||||
currentRoomIndex int
|
||||
roomList []string
|
||||
}
|
||||
|
||||
func NewGomuksUI(gmx Gomuks) (ui *GomuksUI) {
|
||||
ui = &GomuksUI{
|
||||
gmx: gmx,
|
||||
app: gmx.App(),
|
||||
matrix: gmx.MatrixContainer(),
|
||||
debug: gmx.Debug(),
|
||||
config: gmx.Config(),
|
||||
views: tview.NewPages(),
|
||||
}
|
||||
ui.views.SetChangedFunc(ui.Render)
|
||||
return
|
||||
}
|
||||
|
||||
func (ui *GomuksUI) Render() {
|
||||
ui.app.Draw()
|
||||
}
|
||||
|
||||
func (ui *GomuksUI) SetView(name string) {
|
||||
ui.views.SwitchToPage(name)
|
||||
}
|
||||
|
||||
func (ui *GomuksUI) InitViews() tview.Primitive {
|
||||
ui.views.AddPage(ViewLogin, ui.MakeLoginUI(), true, true)
|
||||
ui.views.AddPage(ViewMain, ui.MakeMainUI(), true, false)
|
||||
return ui.views
|
||||
}
|
55
uiutil.go
Normal file
55
uiutil.go
Normal file
@ -0,0 +1,55 @@
|
||||
// gomuks - A terminal Matrix client written in Go.
|
||||
// Copyright (C) 2018 Tulir Asokan
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gdamore/tcell"
|
||||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
func Center(width, height int, p tview.Primitive) tview.Primitive {
|
||||
return tview.NewFlex().
|
||||
AddItem(tview.NewBox(), 0, 1, false).
|
||||
AddItem(tview.NewFlex().
|
||||
SetDirection(tview.FlexRow).
|
||||
AddItem(tview.NewBox(), 0, 1, false).
|
||||
AddItem(p, height, 1, true).
|
||||
AddItem(tview.NewBox(), 0, 1, false), width, 1, true).
|
||||
AddItem(tview.NewBox(), 0, 1, false)
|
||||
}
|
||||
|
||||
type FormTextView struct {
|
||||
*tview.TextView
|
||||
}
|
||||
|
||||
func (ftv *FormTextView) GetLabel() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (ftv *FormTextView) SetFormAttributes(label string, labelColor, bgColor, fieldTextColor, fieldBgColor tcell.Color) tview.FormItem {
|
||||
return ftv
|
||||
}
|
||||
|
||||
func (ftv *FormTextView) GetFieldWidth() int {
|
||||
_, _, w, _ := ftv.TextView.GetRect()
|
||||
return w
|
||||
}
|
||||
|
||||
func (ftv *FormTextView) SetFinishedFunc(handler func(key tcell.Key)) tview.FormItem {
|
||||
ftv.SetDoneFunc(handler)
|
||||
return ftv
|
||||
}
|
49
view-login.go
Normal file
49
view-login.go
Normal file
@ -0,0 +1,49 @@
|
||||
// gomuks - A terminal Matrix client written in Go.
|
||||
// Copyright (C) 2018 Tulir Asokan
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
func (ui *GomuksUI) MakeLoginUI() tview.Primitive {
|
||||
form := tview.NewForm().SetButtonsAlign(tview.AlignCenter)
|
||||
hs := ui.config.HS
|
||||
if len(hs) == 0 {
|
||||
hs = "https://matrix.org"
|
||||
}
|
||||
form.
|
||||
AddInputField("Homeserver", hs, 30, nil, nil).
|
||||
AddInputField("Username", ui.config.MXID, 30, nil, nil).
|
||||
AddPasswordField("Password", "", 30, '*', nil).
|
||||
AddButton("Log in", ui.login(form))
|
||||
form.SetBorder(true).SetTitle("Log in to Matrix")
|
||||
return Center(45, 13, form)
|
||||
}
|
||||
|
||||
func (ui *GomuksUI) login(form *tview.Form) func() {
|
||||
return func() {
|
||||
hs := form.GetFormItem(0).(*tview.InputField).GetText()
|
||||
mxid := form.GetFormItem(1).(*tview.InputField).GetText()
|
||||
password := form.GetFormItem(2).(*tview.InputField).GetText()
|
||||
|
||||
ui.debug.Printf("Logging into %s as %s...", hs, mxid)
|
||||
ui.config.HS = hs
|
||||
ui.debug.Print(ui.matrix.InitClient())
|
||||
ui.debug.Print(ui.matrix.Login(mxid, password))
|
||||
}
|
||||
}
|
164
view-main.go
Normal file
164
view-main.go
Normal file
@ -0,0 +1,164 @@
|
||||
// gomuks - A terminal Matrix client written in Go.
|
||||
// Copyright (C) 2018 Tulir Asokan
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gdamore/tcell"
|
||||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
type RoomView struct {
|
||||
*tview.Grid
|
||||
|
||||
sender, message *tview.TextView
|
||||
}
|
||||
|
||||
func NewRoomView() *RoomView {
|
||||
view := &RoomView{
|
||||
tview.NewGrid(),
|
||||
tview.NewTextView(),
|
||||
tview.NewTextView(),
|
||||
}
|
||||
view.SetColumns(30, 0).SetRows(0)
|
||||
|
||||
view.sender.SetTextAlign(tview.AlignRight)
|
||||
view.sender.SetScrollable(true)
|
||||
view.message.SetScrollable(true)
|
||||
|
||||
view.AddItem(view.sender, 0, 0, 1, 1, 1, 1, false)
|
||||
view.AddItem(view.message, 0, 1, 1, 1, 1, 1, false)
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
func (ui *GomuksUI) MakeMainUI() tview.Primitive {
|
||||
ui.mainView = tview.NewGrid().SetColumns(40, 0).SetRows(0, 2)
|
||||
|
||||
ui.mainViewRoomList = tview.NewList().ShowSecondaryText(false)
|
||||
ui.mainViewRoomList.SetBorderPadding(1, 1, 1, 1)
|
||||
ui.mainView.AddItem(ui.mainViewRoomList, 0, 0, 2, 1, 2, 1, false)
|
||||
|
||||
ui.mainViewRoomView = tview.NewPages()
|
||||
ui.mainViewRoomView.SetChangedFunc(ui.Render)
|
||||
ui.mainView.AddItem(ui.mainViewRoomView, 0, 1, 1, 1, 1, 1, false)
|
||||
|
||||
ui.mainViewInput = tview.NewInputField()
|
||||
ui.mainViewInput.SetDoneFunc(func(key tcell.Key) {
|
||||
if key == tcell.KeyEnter {
|
||||
room, text := ui.currentRoom(), ui.mainViewInput.GetText()
|
||||
if len(text) == 0 {
|
||||
return
|
||||
} else if text[0] == '/' {
|
||||
args := strings.SplitN(text, " ", 2)
|
||||
command := strings.ToLower(args[0])
|
||||
args = args[1:]
|
||||
ui.HandleCommand(room, command, args)
|
||||
} else {
|
||||
ui.matrix.SendMessage(room, text)
|
||||
}
|
||||
ui.mainViewInput.SetText("")
|
||||
}
|
||||
})
|
||||
ui.mainView.AddItem(ui.mainViewInput, 1, 1, 1, 1, 1, 1, true)
|
||||
|
||||
ui.debug.Print(ui.mainViewInput.SetInputCapture(ui.MainUIKeyHandler))
|
||||
|
||||
ui.mainViewRooms = make(map[string]*RoomView)
|
||||
|
||||
return ui.mainView
|
||||
}
|
||||
|
||||
func (ui *GomuksUI) HandleCommand(room, command string, args []string) {
|
||||
switch command {
|
||||
case "quit":
|
||||
ui.matrix.Stop()
|
||||
ui.app.Stop()
|
||||
case "part":
|
||||
case "leave":
|
||||
ui.matrix.client.LeaveRoom(room)
|
||||
case "join":
|
||||
if len(args) == 0 {
|
||||
ui.Append(room, "*", "Usage: /join <room>")
|
||||
}
|
||||
mxid := args[0]
|
||||
server := mxid[strings.Index(mxid, ":")+1:]
|
||||
ui.matrix.client.JoinRoom(mxid, server, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func (ui *GomuksUI) MainUIKeyHandler(key *tcell.EventKey) *tcell.EventKey {
|
||||
ui.debug.Print(key)
|
||||
if key.Modifiers() == tcell.ModCtrl {
|
||||
if key.Key() == tcell.KeyDown {
|
||||
ui.SwitchRoom(ui.currentRoomIndex + 1)
|
||||
ui.mainViewRoomList.SetCurrentItem(ui.currentRoomIndex)
|
||||
} else if key.Key() == tcell.KeyUp {
|
||||
ui.SwitchRoom(ui.currentRoomIndex - 1)
|
||||
ui.mainViewRoomList.SetCurrentItem(ui.currentRoomIndex)
|
||||
}
|
||||
} else if key.Key() == tcell.KeyPgUp || key.Key() == tcell.KeyPgDn {
|
||||
ui.mainViewRooms[ui.currentRoom()].sender.InputHandler()(key, nil)
|
||||
ui.mainViewRooms[ui.currentRoom()].message.InputHandler()(key, nil)
|
||||
} else {
|
||||
return key
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ui *GomuksUI) SetRoomList(rooms []string) {
|
||||
ui.roomList = rooms
|
||||
ui.mainViewRoomList.Clear()
|
||||
for index, room := range rooms {
|
||||
localRoomIndex := index
|
||||
ui.mainViewRoomList.AddItem(room, "", 0, func() {
|
||||
ui.SwitchRoom(localRoomIndex)
|
||||
})
|
||||
if !ui.mainViewRoomView.HasPage(room) {
|
||||
roomView := NewRoomView()
|
||||
ui.mainViewRooms[room] = roomView
|
||||
ui.mainViewRoomView.AddPage(room, roomView, true, false)
|
||||
}
|
||||
}
|
||||
ui.SwitchRoom(0)
|
||||
}
|
||||
|
||||
func (ui *GomuksUI) currentRoom() string {
|
||||
if len(ui.roomList) == 0 {
|
||||
return ""
|
||||
}
|
||||
return ui.roomList[ui.currentRoomIndex]
|
||||
}
|
||||
|
||||
func (ui *GomuksUI) SwitchRoom(roomIndex int) {
|
||||
if roomIndex < 0 {
|
||||
roomIndex = len(ui.roomList) - 1
|
||||
}
|
||||
ui.currentRoomIndex = roomIndex % len(ui.roomList)
|
||||
ui.mainViewRoomView.SwitchToPage(ui.roomList[ui.currentRoomIndex])
|
||||
}
|
||||
|
||||
func (ui *GomuksUI) Append(room, sender, message string) {
|
||||
roomView, ok := ui.mainViewRooms[room]
|
||||
if ok {
|
||||
fmt.Fprintf(roomView.sender, sender)
|
||||
fmt.Fprintf(roomView.message, sender)
|
||||
ui.Render()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user