morpheus

A Matrix client written in Go-QT
git clone git://archive.git.mtrnord.blog/Nordgedanken/morpheus.git
Log | Files | Refs | README | LICENSE

commit 69a7d07df2fd6b52a00b075733e0b45cf9d88afb
parent 9e8131e118385847073d9dbbb38e4ca5b70648fd
Author: MTRNord <mtrnord1@gmail.com>
Date:   Sun, 15 Oct 2017 17:03:44 +0200

Refactor UIs

Signed-off-by: MTRNord <mtrnord1@gmail.com>

Diffstat:
Melements/moc_cgo_windows_windows_amd64.go | 1-
Mmain.go | 24++++++++++++++++++------
Ascripts/lint.sh | 33+++++++++++++++++++++++++++++++++
Dtags | 81-------------------------------------------------------------------------------
Mui/LoginUI.go | 168+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mui/MainUI.go | 254+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aui/types.go | 39+++++++++++++++++++++++++++++++++++++++
Duis.go | 312-------------------------------------------------------------------------------
Duis.old | 147-------------------------------------------------------------------------------
9 files changed, 512 insertions(+), 547 deletions(-)

diff --git a/elements/moc_cgo_windows_windows_amd64.go b/elements/moc_cgo_windows_windows_amd64.go @@ -8,4 +8,3 @@ package elements #cgo LDFLAGS: -lglu32 -lopengl32 -lgdi32 -luser32 -lmingw32 -LC:/msys64/mingw64/lib -lqtmain -lshell32 -lQt5Widgets -lQt5Gui -lQt5Core #cgo LDFLAGS: -Wl,--allow-multiple-definition */ -import "C" diff --git a/main.go b/main.go @@ -5,6 +5,7 @@ import ( "os" "github.com/Nordgedanken/Morpheus/matrix" + "github.com/Nordgedanken/Morpheus/ui" "github.com/Nordgedanken/Morpheus/util" "github.com/matrix-org/gomatrix" "github.com/therecipe/qt/core" @@ -105,23 +106,34 @@ func main() { //Show MainUI for result := range results { //TODO Don't switch screen on wrong login data. - mainUI, mainUIErr := NewMainUI(windowWidth, windowHeight, result, window) + MainUIStruct := ui.NewMainUIStruct(windowWidth, windowHeight, window) + MainUIStruct.SetCli(result) + MainUILoggerInitErr := MainUIStruct.InitLogger() + if MainUILoggerInitErr != nil { + localLog.Fatalln(MainUILoggerInitErr) + } + mainUIErr := MainUIStruct.NewUI() if mainUIErr != nil { localLog.Fatalln(mainUIErr) return } - mainUI.Resize2(windowWidth, windowHeight) - window.SetCentralWidget(mainUI) + MainUIStruct.GetWidget().Resize2(windowWidth, windowHeight) + window.SetCentralWidget(MainUIStruct.GetWidget()) } } else { //Show loginUI - loginUI, loginUIErr := NewLoginUI(windowWidth, windowHeight, window) + LoginUIStruct := ui.NewLoginUIStruct(windowWidth, windowHeight, window) + LoginUIStructInitErr := LoginUIStruct.InitLogger() + if LoginUIStructInitErr != nil { + localLog.Fatalln(LoginUIStructInitErr) + } + loginUIErr := LoginUIStruct.NewUI() if loginUIErr != nil { localLog.Fatalln(loginUIErr) return } - loginUI.Resize2(windowWidth, windowHeight) - window.SetCentralWidget(loginUI) + LoginUIStruct.GetWidget().Resize2(windowWidth, windowHeight) + window.SetCentralWidget(LoginUIStruct.GetWidget()) } window.Resize2(windowWidth, windowHeight) diff --git a/scripts/lint.sh b/scripts/lint.sh @@ -0,0 +1,32 @@ + +#! /bin/bash + +# Runs the linters against dendrite + +# The linters can take a lot of resources and are slow, so they can be +# configured using two environment variables: +# +# - `DENDRITE_LINT_CONCURRENCY` - number of concurrent linters to run, +# gometalinter defaults this to 8 +# - `DENDRITE_LINT_DISABLE_GC` - if set then the the go gc will be disabled +# when running the linters, speeding them up but using much more memory. + + +set -eu + +args="--config=linter.json" + +if [ -n "${MORPHEUS_LINT_CONCURRENCY:-}" ] +then args="$args --concurrency=$MORPHEUS_LINT_CONCURRENCY" +fi + +if [ -z "${MORPHEUS_LINT_DISABLE_GC:-}" ] +then args="$args --enable-gc" +fi + +echo "Installing lint search engine..." +go install github.com/alecthomas/gometalinter/ +gometalinter --config=linter.json ./... --install + +echo "Looking for lint..." +gometalinter ./... ${args} +\ No newline at end of file diff --git a/tags b/tags @@ -1,81 +0,0 @@ -!_TAG_FILE_FORMAT 2 -!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted/ -!_TAG_PROGRAM_AUTHOR Joel Stemmer /stemmertech@gmail.com/ -!_TAG_PROGRAM_NAME gotags -!_TAG_PROGRAM_URL https://github.com/jstemmer/gotags -!_TAG_PROGRAM_VERSION 1.4.1 /go1.8.3/ -*gomatrix.Client matrix\types.go 10;" e access:public ctype:Client language:Go line:10 type:*gomatrix.Client -Client matrix\types.go 9;" t access:public language:Go line:9 type:struct -ClientInstance matrix\login.go 10;" v access:public language:Go line:10 type:*Client -DisplayName matrix\types.go 15;" w access:public ctype:RespUserDisplayName language:Go line:15 type:string -DoLogin ui\uis.go 20;" f access:public language:Go line:20 signature:(username, password, homeserverURL, userID, accessToken string, localLog *log.Logger, results chan *matrix.Client) -GetClient matrix\login.go 13;" f access:public language:Go line:13 signature:(homeserverURL, userID, accessToken string) type:*Client, error -GetOwnUserAvatar matrix\types.go 25;" m access:public ctype:Client language:Go line:25 signature:() type:*gui.QPixmap -GetUserDisplayName matrix\types.go 19;" m access:public ctype:Client language:Go line:19 signature:(mxid string) type:string, error -Logger util\logger.go 18;" f access:public language:Go line:18 signature:() type:*log.Logger -LoginUser matrix\login.go 36;" f access:public language:Go line:36 signature:(username, password string) type:*Client, error -NewLoginUI ui\uis.go 48;" f access:public language:Go line:48 signature:(windowWidth, windowHeight int) type:*widgets.QWidget -NewMainUI ui\uis.go 143;" f access:public language:Go line:143 signature:(windowWidth, windowHeight int, cli *matrix.Client) type:*widgets.QWidget -OpenDB matrix\db.go 14;" f access:public language:Go line:14 signature:() type:*buntdb.DB -RespUserDisplayName matrix\types.go 14;" t access:public language:Go line:14 type:struct -StartFileLog util\logger.go 26;" f access:public language:Go line:26 signature:(localLog *log.Logger) type:*log.Logger, *os.File -db main.go 16;" v access:private language:Go line:16 type:*buntdb.DB -db matrix\db.go 12;" v access:private language:Go line:12 type:*buntdb.DB -getOwnUserAvatar matrix\ownUser.go 55;" f access:private language:Go line:55 signature:(cli *Client) type:*gui.QPixmap -getUserDisplayName matrix\ownUser.go 23;" f access:private language:Go line:23 signature:(mxid string, cli *Client) type:string, error -github.com/Nordgedanken/Neo/matrix main.go 7;" i language:Go line:7 -github.com/Nordgedanken/Neo/matrix ui\uis.go 9;" i language:Go line:9 -github.com/Nordgedanken/Neo/ui main.go 8;" i language:Go line:8 -github.com/Nordgedanken/Neo/util main.go 9;" i language:Go line:9 -github.com/Nordgedanken/Neo/util matrix\ownUser.go 8;" i language:Go line:8 -github.com/matrix-org/gomatrix matrix\login.go 6;" i language:Go line:6 -github.com/matrix-org/gomatrix matrix\types.go 4;" i language:Go line:4 -github.com/matrix-org/gomatrix ui\uis.go 10;" i language:Go line:10 -github.com/shibukawa/configdir matrix\db.go 8;" i language:Go line:8 -github.com/shibukawa/configdir util\logger.go 11;" i language:Go line:11 -github.com/therecipe/qt/core ui\uis.go 11;" i language:Go line:11 -github.com/therecipe/qt/gui matrix\ownUser.go 9;" i language:Go line:9 -github.com/therecipe/qt/gui matrix\types.go 5;" i language:Go line:5 -github.com/therecipe/qt/widgets main.go 10;" i language:Go line:10 -github.com/therecipe/qt/widgets ui\uis.go 12;" i language:Go line:12 -github.com/tidwall/buntdb main.go 11;" i language:Go line:11 -github.com/tidwall/buntdb matrix\db.go 9;" i language:Go line:9 -github.com/tidwall/buntdb matrix\login.go 7;" i language:Go line:7 -github.com/tidwall/buntdb matrix\ownUser.go 10;" i language:Go line:10 -github.com/tidwall/buntdb ui\uis.go 13;" i language:Go line:13 -init matrix\ownUser.go 15;" f access:private language:Go line:15 signature:() -io util\logger.go 4;" i language:Go line:4 -localLog main.go 15;" v access:private language:Go line:15 type:*log.Logger -localLog matrix\ownUser.go 13;" v access:private language:Go line:13 type:*log.Logger -log main.go 4;" i language:Go line:4 -log matrix\db.go 4;" i language:Go line:4 -log matrix\ownUser.go 4;" i language:Go line:4 -log ui\uis.go 4;" i language:Go line:4 -log util\logger.go 5;" i language:Go line:5 -logInstance util\logger.go 14;" v access:private language:Go line:14 type:*log.Logger -main main.go 18;" f access:private language:Go line:18 signature:() -main main.go 1;" p language:Go line:1 -matrix matrix\db.go 1;" p language:Go line:1 -matrix matrix\login.go 1;" p language:Go line:1 -matrix matrix\ownUser.go 1;" p language:Go line:1 -matrix matrix\types.go 1;" p language:Go line:1 -once util\logger.go 15;" v access:private language:Go line:15 type:sync.Once -os main.go 5;" i language:Go line:5 -os matrix\db.go 5;" i language:Go line:5 -os matrix\ownUser.go 5;" i language:Go line:5 -os util\logger.go 6;" i language:Go line:6 -password ui\uis.go 17;" v access:private language:Go line:17 type:string -path/filepath matrix\db.go 6;" i language:Go line:6 -path/filepath util\logger.go 7;" i language:Go line:7 -strings matrix\login.go 4;" i language:Go line:4 -strings matrix\ownUser.go 6;" i language:Go line:6 -strings ui\uis.go 5;" i language:Go line:5 -sync ui\uis.go 6;" i language:Go line:6 -sync util\logger.go 8;" i language:Go line:8 -time ui\uis.go 7;" i language:Go line:7 -time util\logger.go 9;" i language:Go line:9 -ui ui\uis.go 1;" p language:Go line:1 -username ui\uis.go 16;" v access:private language:Go line:16 type:string -util util\logger.go 1;" p language:Go line:1 -wg ui\uis.go 18;" v access:private language:Go line:18 type:sync.WaitGroup -window main.go 14;" v access:private language:Go line:14 type:*widgets.QMainWindow diff --git a/ui/LoginUI.go b/ui/LoginUI.go @@ -1 +1,169 @@ package ui + +import ( + "github.com/Nordgedanken/Morpheus/matrix" + "github.com/Nordgedanken/Morpheus/util" + "github.com/matrix-org/gomatrix" + "github.com/therecipe/qt/core" + "github.com/therecipe/qt/widgets" + "sync" +) + +// NewLoginUIStruct gives you a LoginUI struct with prefilled data +func NewLoginUIStruct(windowWidth, windowHeight int, window *widgets.QMainWindow) (loginUIStruct LoginUI) { + configStruct := config{ + windowWidth: windowWidth, + windowHeight: windowHeight, + } + loginUIStruct = LoginUI{ + config: configStruct, + window: window, + } + return +} + +// NewLoginUIStructWithExistingConfig gives you a LoginUI struct with prefilled data and data from a previous Config +func NewLoginUIStructWithExistingConfig(configStruct config, window *widgets.QMainWindow) (loginUIStruct LoginUI) { + loginUIStruct = LoginUI{ + config: configStruct, + window: window, + } + return +} + +// GetWidget gives you the widget of the LoginUI struct +func (l *LoginUI) GetWidget() (widget *widgets.QWidget) { + widget = l.widget + return +} + +// InitLogger adds a new logger to the LoginUI struct +func (l *LoginUI) InitLogger() error { + localLog := util.Logger() + localLog, _, err := util.StartFileLog(localLog) + if err != nil { + return err + } + l.localLog = localLog + return nil +} + +// NewUI initializes a new login Screen +func (l *LoginUI) NewUI() (err error) { + widget := widgets.NewQWidget(nil, 0) + widget.SetObjectName("LoginWrapper") + widget.SetStyleSheet("QWidget#LoginWrapper { border: 0px; };") + topLayout := widgets.NewQVBoxLayout() + + formWidget := widgets.NewQWidget(nil, 0) + formWrapper := widgets.NewQHBoxLayout() + + formLayout := widgets.NewQVBoxLayout() + formLayout.SetSpacing(20) + formLayout.SetContentsMargins(0, 0, 0, 30) + formWidget.SetLayout(formLayout) + + formWrapper.AddStretch(1) + formWrapper.AddWidget(formWidget, 0, 0) + formWrapper.AddStretch(1) + + // UsernameInput + usernameInput := widgets.NewQLineEdit(nil) + usernameInput.SetPlaceholderText("Insert MXID") + + usernameLayout := widgets.NewQHBoxLayout() + usernameLayout.AddWidget(usernameInput, 0, core.Qt__AlignVCenter) + + // PasswordInput + passwordInput := widgets.NewQLineEdit(nil) + passwordInput.SetPlaceholderText("Insert password") + passwordInput.SetEchoMode(widgets.QLineEdit__Password) + + passwordLayout := widgets.NewQHBoxLayout() + passwordLayout.AddWidget(passwordInput, 0, core.Qt__AlignVCenter) + + formLayout.AddLayout(usernameLayout, 0) + formLayout.AddLayout(passwordLayout, 0) + + // loginButton + buttonLayout := widgets.NewQHBoxLayout() + buttonLayout.SetSpacing(0) + buttonLayout.SetContentsMargins(0, 0, 0, 30) + + loginButton := widgets.NewQPushButton2("LOGIN", nil) + loginButton.SetMinimumSize2(350, 65) + + buttonLayout.AddStretch(1) + buttonLayout.AddWidget(loginButton, 0, 0) + buttonLayout.AddStretch(1) + + topLayout.AddStretch(1) + topLayout.AddLayout(formWrapper, 0) + topLayout.AddStretch(1) + topLayout.AddLayout(buttonLayout, 0) + topLayout.AddStretch(1) + + widget.SetLayout(topLayout) + + usernameInput.ConnectTextChanged(func(value string) { + l.username = value + }) + + passwordInput.ConnectTextChanged(func(value string) { + l.password = value + }) + + loginButton.ConnectClicked(func(_ bool) { + LoginErr := l.login() + if err != nil { + err = LoginErr + return + } + }) + + widget.SetWindowTitle("Morpheus - Login") + + l.widget = widget + return +} + +func (l *LoginUI) login() (err error) { + //TODO register enter and show loader or so + + var wg sync.WaitGroup + + if l.username != "" && l.password != "" { + l.localLog.Println("Starting Login Sequenze in background") + results := make(chan *gomatrix.Client) + + wg.Add(1) + go matrix.DoLogin(l.username, l.password, "", "", "", l.localLog, results, &wg) + + go func() { + wg.Wait() // wait for each execTask to return + close(results) // then close the results channel + }() + + //Show MainUI + for result := range results { + //TODO Don't switch screen on wrong login data. + l.cli = result + MainUIStruct := NewMainUIStructWithExistingConfig(l.config, l.window) + MainUILoggerInitErr := MainUIStruct.InitLogger() + if MainUILoggerInitErr != nil { + err = MainUILoggerInitErr + return + } + mainUIErr := MainUIStruct.NewUI() + if mainUIErr != nil { + err = mainUIErr + return + } + l.window.SetCentralWidget(MainUIStruct.GetWidget()) + l.window.Resize(l.widget.Size()) + } + } else { + l.localLog.Println("Username and/or password is empty. Do Nothing.") + } + return +} diff --git a/ui/MainUI.go b/ui/MainUI.go @@ -1 +1,255 @@ package ui + +import ( + "github.com/Nordgedanken/Morpheus/elements" + "github.com/Nordgedanken/Morpheus/matrix" + "github.com/Nordgedanken/Morpheus/util" + "github.com/matrix-org/gomatrix" + "github.com/rhinoman/go-commonmark" + "github.com/therecipe/qt/core" + "github.com/therecipe/qt/gui" + "github.com/therecipe/qt/uitools" + "github.com/therecipe/qt/widgets" + "github.com/tidwall/buntdb" + "log" + "sync" + "time" +) + +// NewMainUIStruct gives you a MainUI struct with prefilled data +func NewMainUIStruct(windowWidth, windowHeight int, window *widgets.QMainWindow) (mainUIStruct MainUI) { + configStruct := config{ + windowWidth: windowWidth, + windowHeight: windowHeight, + } + mainUIStruct = MainUI{ + config: configStruct, + window: window, + } + return +} + +// NewMainUIStructWithExistingConfig gives you a MainUI struct with prefilled data and data from a previous Config +func NewMainUIStructWithExistingConfig(configStruct config, window *widgets.QMainWindow) (mainUIStruct MainUI) { + mainUIStruct = MainUI{ + config: configStruct, + window: window, + } + return +} + +// SetCli allows you to add a gomatrix.Client to your MainUI struct +func (m *MainUI) SetCli(cli *gomatrix.Client) { + m.cli = cli +} + +// GetWidget gives you the widget of the MainUI struct +func (m *MainUI) GetWidget() (widget *widgets.QWidget) { + widget = m.widget + return +} + +// InitLogger adds a new logger to the MainUI struct +func (m *MainUI) InitLogger() error { + localLog := util.Logger() + localLog, _, err := util.StartFileLog(localLog) + if err != nil { + return err + } + m.localLog = localLog + return nil +} + +// NewUI initializes a new Main Screen +func (m *MainUI) NewUI() (err error) { + var widget = widgets.NewQWidget(nil, 0) + + var loader = uitools.NewQUiLoader(nil) + var file = core.NewQFile2(":/qml/ui/chat.ui") + + file.Open(core.QIODevice__ReadOnly) + var mainWidget = loader.Load(file, widget) + file.Close() + + InitDataErr := matrix.InitData(m.cli) + if InitDataErr != nil { + err = InitDataErr + return + } + + messageScrollArea := widgets.NewQScrollAreaFromPointer(widget.FindChild("messageScroll", core.Qt__FindChildrenRecursively).Pointer()) + messagesScrollAreaContent := widgets.NewQWidgetFromPointer(widget.FindChild("messagesScrollAreaContent", core.Qt__FindChildrenRecursively).Pointer()) + + mainWidget.SetWindowTitle("Morpheus - MatrixHQ") + + var layout = widgets.NewQHBoxLayout() + layout.AddWidget(mainWidget, 1, core.Qt__AlignTop|core.Qt__AlignLeft) + widget.SetLayout(layout) + layout.SetSpacing(0) + layout.SetContentsMargins(0, 0, 0, 0) + + m.window.ConnectResizeEvent(func(event *gui.QResizeEvent) { + widget.Resize2(event.Size().Width(), event.Size().Height()) + + }) + + widget.ConnectResizeEvent(func(event *gui.QResizeEvent) { + mainWidget.Resize2(event.Size().Width(), event.Size().Height()) + + }) + + messageScrollArea.ConnectResizeEvent(func(event *gui.QResizeEvent) { + messageScrollArea.Resize(event.Size()) + }) + + //Set Avatar + avatarLogo := widgets.NewQLabelFromPointer(widget.FindChild("UserAvatar", core.Qt__FindChildrenRecursively).Pointer()) + avatar, AvatarErr := matrix.GetOwnUserAvatar(m.cli) + if AvatarErr != nil { + err = AvatarErr + return + } + avatarLogo.SetPixmap(avatar) + + //Handle LogoutButton + logoutButton := widgets.NewQPushButtonFromPointer(widget.FindChild("LogoutButton", core.Qt__FindChildrenRecursively).Pointer()) + logoutButton.ConnectClicked(func(_ bool) { + //TODO register enter and show loader or so + m.localLog.Println("Starting Logout Sequenze in background") + var wg sync.WaitGroup + results := make(chan bool) + + wg.Add(1) + go func(cli *gomatrix.Client, localLog *log.Logger, results chan<- bool) { + defer wg.Done() + _, LogoutErr := cli.Logout() + if LogoutErr != nil { + localLog.Println(LogoutErr) + results <- false + } + cli.ClearCredentials() + + db, DBOpenErr := matrix.OpenDB() + if DBOpenErr != nil { + localLog.Fatalln(DBOpenErr) + } + defer db.Close() + + //Flush complete DB + DBErr := db.Update(func(tx *buntdb.Tx) error { + QueryErr := tx.DeleteAll() + return QueryErr + }) + if DBErr != nil { + localLog.Panicln(DBErr) + results <- false + } else { + results <- true + } + }(m.cli, m.localLog, results) + + go func() { + wg.Wait() // wait for each execTask to return + close(results) // then close the results channel + }() + + //Show LoginUI + for result := range results { + if result { + m.window.DisconnectKeyPressEvent() + m.window.DisconnectResizeEvent() + widget.DisconnectResizeEvent() + messageScrollArea.DisconnectResizeEvent() + + LoginUIStruct := NewLoginUIStructWithExistingConfig(m.config, m.window) + LoginUIStructInitErr := LoginUIStruct.InitLogger() + if LoginUIStructInitErr != nil { + err = LoginUIStructInitErr + return + } + loginUIErr := LoginUIStruct.NewUI() + if loginUIErr != nil { + m.localLog.Panicln(loginUIErr) + } + m.window.SetCentralWidget(LoginUIStruct.GetWidget()) + } + } + }) + + //Start Syncer! + syncer := m.cli.Syncer.(*gomatrix.DefaultSyncer) + customStore := gomatrix.NewInMemoryStore() + m.cli.Store = customStore + syncer.Store = customStore + + // Init Message View + messageListLayout := elements.NewMessageList(messageScrollArea, messagesScrollAreaContent) + + messageListLayout.ConnectTriggerMessage(func(messageBody, sender string) { + NewMessageErr := messageListLayout.NewMessage(messageBody, m.cli, sender, messageScrollArea) + if NewMessageErr != nil { + err = NewMessageErr + return + } + }) + messageScrollArea.SetWidgetResizable(true) + messageScrollArea.SetHorizontalScrollBarPolicy(core.Qt__ScrollBarAlwaysOff) + messageScrollArea.SetContentsMargins(0, 0, 0, 0) + + syncer.OnEventType("m.room.message", func(ev *gomatrix.Event) { + msg, _ := ev.Body() + room := ev.RoomID + sender := ev.Sender + id := ev.ID + timestamp := ev.Timestamp + CacheErr := matrix.CacheMessageEvents(id, sender, room, msg, timestamp) + if CacheErr != nil { + err = CacheErr + return + } + messageListLayout.TriggerMessage(msg, sender) + }) + + // Start Non-blocking sync + go func() { + m.localLog.Println("Start sync") + for { + + if e := m.cli.Sync(); e != nil { + m.localLog.Println("Fatal Sync() error") + time.Sleep(5 * time.Second) + } + time.Sleep(10 * time.Second) + } + }() + + messageInput := widgets.NewQLineEditFromPointer(widget.FindChild("MessageInput", core.Qt__FindChildrenRecursively).Pointer()) + var message string + m.window.ConnectKeyPressEvent(func(ev *gui.QKeyEvent) { + if int(ev.Key()) == int(core.Qt__Key_Enter) || int(ev.Key()) == int(core.Qt__Key_Return) { + mardownMessage := commonmark.Md2Html(message, 0) + if mardownMessage == message { + _, SendErr := m.cli.SendText("!zTIXGmDjyRcAqbrWab:matrix.ffslfl.net", message) + if SendErr != nil { + err = SendErr + return + } + } else { + _, SendErr := m.cli.SendMessageEvent("!zTIXGmDjyRcAqbrWab:matrix.ffslfl.net", "m.room.message", matrix.HTMLMessage{"m.text", message, mardownMessage, "org.matrix.custom.html"}) + if SendErr != nil { + err = SendErr + return + } + } + messageInput.Clear() + } else { + messageInput.KeyPressEventDefault(ev) + } + }) + messageInput.ConnectTextChanged(func(value string) { + message = value + }) + + m.widget = widget + return +} diff --git a/ui/types.go b/ui/types.go @@ -0,0 +1,39 @@ +package ui + +import ( + "github.com/matrix-org/gomatrix" + "github.com/therecipe/qt/widgets" + "log" +) + +// Config holds important reused information in the UI +type config struct { + username string + password string + + windowWidth int + windowHeight int + + cli *gomatrix.Client +} + +// Logger holds the initialised Logger +type logger struct { + localLog *log.Logger +} + +// MainUI holds information about the MainUI +type MainUI struct { + logger + config + widget *widgets.QWidget + window *widgets.QMainWindow +} + +// LoginUI holds information about the LoginUI +type LoginUI struct { + logger + config + widget *widgets.QWidget + window *widgets.QMainWindow +} diff --git a/uis.go b/uis.go @@ -1,312 +0,0 @@ -package main - -import ( - "github.com/Nordgedanken/Morpheus/elements" - "github.com/Nordgedanken/Morpheus/matrix" - "github.com/matrix-org/gomatrix" - "github.com/rhinoman/go-commonmark" - "github.com/therecipe/qt/core" - "github.com/therecipe/qt/gui" - "github.com/therecipe/qt/uitools" - "github.com/therecipe/qt/widgets" - "github.com/tidwall/buntdb" - "log" - "sync" - "time" -) - -var username string -var password string - -//NewLoginUI initializes the login Screen -func NewLoginUI(windowWidth, windowHeight int, window *widgets.QMainWindow) (respWidget *widgets.QWidget, err error) { - widget := widgets.NewQWidget(nil, 0) - widget.SetObjectName("LoginWrapper") - widget.SetStyleSheet("QWidget#LoginWrapper { border: 0px; };") - topLayout := widgets.NewQVBoxLayout() - - formWidget := widgets.NewQWidget(nil, 0) - formWrapper := widgets.NewQHBoxLayout() - - formLayout := widgets.NewQVBoxLayout() - formLayout.SetSpacing(20) - formLayout.SetContentsMargins(0, 0, 0, 30) - formWidget.SetLayout(formLayout) - - formWrapper.AddStretch(1) - formWrapper.AddWidget(formWidget, 0, 0) - formWrapper.AddStretch(1) - - // UsernameInput - usernameInput := widgets.NewQLineEdit(nil) - usernameInput.SetPlaceholderText("Insert MXID") - - usernameLayout := widgets.NewQHBoxLayout() - usernameLayout.AddWidget(usernameInput, 0, core.Qt__AlignVCenter) - - // PasswordInput - passwordInput := widgets.NewQLineEdit(nil) - passwordInput.SetPlaceholderText("Insert password") - passwordInput.SetEchoMode(widgets.QLineEdit__Password) - - passwordLayout := widgets.NewQHBoxLayout() - passwordLayout.AddWidget(passwordInput, 0, core.Qt__AlignVCenter) - - formLayout.AddLayout(usernameLayout, 0) - formLayout.AddLayout(passwordLayout, 0) - - // loginButton - buttonLayout := widgets.NewQHBoxLayout() - buttonLayout.SetSpacing(0) - buttonLayout.SetContentsMargins(0, 0, 0, 30) - - loginButton := widgets.NewQPushButton2("LOGIN", nil) - loginButton.SetMinimumSize2(350, 65) - - buttonLayout.AddStretch(1) - buttonLayout.AddWidget(loginButton, 0, 0) - buttonLayout.AddStretch(1) - - topLayout.AddStretch(1) - topLayout.AddLayout(formWrapper, 0) - topLayout.AddStretch(1) - topLayout.AddLayout(buttonLayout, 0) - topLayout.AddStretch(1) - - widget.SetLayout(topLayout) - - usernameInput.ConnectTextChanged(func(value string) { - username = value - }) - - passwordInput.ConnectTextChanged(func(value string) { - password = value - }) - - loginButton.ConnectClicked(func(_ bool) { - //TODO register enter and show loader or so - - var wg sync.WaitGroup - - if username != "" && password != "" { - localLog.Println("Starting Login Sequenze in background") - results := make(chan *gomatrix.Client) - - wg.Add(1) - go matrix.DoLogin(username, password, "", "", "", localLog, results, &wg) - - go func() { - wg.Wait() // wait for each execTask to return - close(results) // then close the results channel - }() - - //Show MainUI - for result := range results { - //TODO Don't switch screen on wrong login data. - mainUI, mainUIErr := NewMainUI(windowWidth, windowHeight, result, window) - if mainUIErr != nil { - err = mainUIErr - return - } - window.SetCentralWidget(mainUI) - window.Resize(widget.Size()) - } - } else { - localLog.Println("Username and/or password is empty. Do Nothing.") - } - }) - - widget.SetWindowTitle("Morpheus - Login") - - respWidget = widget - return -} - -//NewMainUI initializes the login Screen -//func NewMainUI(windowWidth, windowHeight int, cli *gomatrix.Client) *widgets.QWidget { -func NewMainUI(windowWidth, windowHeight int, cli *gomatrix.Client, window *widgets.QMainWindow) (respWidget *widgets.QWidget, err error) { - var widget = widgets.NewQWidget(nil, 0) - - var loader = uitools.NewQUiLoader(nil) - var file = core.NewQFile2(":/qml/ui/chat.ui") - - file.Open(core.QIODevice__ReadOnly) - var mainWidget = loader.Load(file, widget) - file.Close() - - InitDataErr := matrix.InitData(cli) - if InitDataErr != nil { - err = InitDataErr - return - } - - messageScrollArea := widgets.NewQScrollAreaFromPointer(widget.FindChild("messageScroll", core.Qt__FindChildrenRecursively).Pointer()) - messagesScrollAreaContent := widgets.NewQWidgetFromPointer(widget.FindChild("messagesScrollAreaContent", core.Qt__FindChildrenRecursively).Pointer()) - - mainWidget.SetWindowTitle("Morpheus - MatrixHQ") - - var layout = widgets.NewQHBoxLayout() - layout.AddWidget(mainWidget, 1, core.Qt__AlignTop|core.Qt__AlignLeft) - widget.SetLayout(layout) - layout.SetSpacing(0) - layout.SetContentsMargins(0, 0, 0, 0) - - window.ConnectResizeEvent(func(event *gui.QResizeEvent) { - widget.Resize2(event.Size().Width(), event.Size().Height()) - - }) - - widget.ConnectResizeEvent(func(event *gui.QResizeEvent) { - mainWidget.Resize2(event.Size().Width(), event.Size().Height()) - - }) - - messageScrollArea.ConnectResizeEvent(func(event *gui.QResizeEvent) { - messageScrollArea.Resize(event.Size()) - }) - - //Set Avatar - avatarLogo := widgets.NewQLabelFromPointer(widget.FindChild("UserAvatar", core.Qt__FindChildrenRecursively).Pointer()) - avatar, AvatarErr := matrix.GetOwnUserAvatar(cli) - if AvatarErr != nil { - err = AvatarErr - return - } - avatarLogo.SetPixmap(avatar) - - //Handle LogoutButton - logoutButton := widgets.NewQPushButtonFromPointer(widget.FindChild("LogoutButton", core.Qt__FindChildrenRecursively).Pointer()) - logoutButton.ConnectClicked(func(_ bool) { - //TODO register enter and show loader or so - localLog.Println("Starting Logout Sequenze in background") - var wg sync.WaitGroup - results := make(chan bool) - - wg.Add(1) - go func(cli *gomatrix.Client, localLog *log.Logger, results chan<- bool) { - defer wg.Done() - _, LogoutErr := cli.Logout() - if LogoutErr != nil { - localLog.Println(LogoutErr) - results <- false - } - cli.ClearCredentials() - - db, DBOpenErr := matrix.OpenDB() - if DBOpenErr != nil { - localLog.Fatalln(DBOpenErr) - } - defer db.Close() - - //Flush complete DB - DBErr := db.Update(func(tx *buntdb.Tx) error { - QueryErr := tx.DeleteAll() - return QueryErr - }) - if DBErr != nil { - localLog.Panicln(DBErr) - results <- false - } else { - results <- true - } - }(cli, localLog, results) - - go func() { - wg.Wait() // wait for each execTask to return - close(results) // then close the results channel - }() - - //Show LoginUI - for result := range results { - if result { - window.DisconnectKeyPressEvent() - window.DisconnectResizeEvent() - widget.DisconnectResizeEvent() - messageScrollArea.DisconnectResizeEvent() - - loginUI, loginUIErr := NewLoginUI(windowWidth, windowHeight, window) - if loginUIErr != nil { - localLog.Panicln(loginUIErr) - } - window.SetCentralWidget(loginUI) - } - } - }) - - //Start Syncer! - syncer := cli.Syncer.(*gomatrix.DefaultSyncer) - customStore := gomatrix.NewInMemoryStore() - cli.Store = customStore - syncer.Store = customStore - - // Init Message View - messageListLayout := elements.NewMessageList(messageScrollArea, messagesScrollAreaContent) - - messageListLayout.ConnectTriggerMessage(func(messageBody, sender string) { - NewMessageErr := messageListLayout.NewMessage(messageBody, cli, sender, messageScrollArea) - if NewMessageErr != nil { - err = NewMessageErr - return - } - }) - messageScrollArea.SetWidgetResizable(true) - messageScrollArea.SetHorizontalScrollBarPolicy(core.Qt__ScrollBarAlwaysOff) - messageScrollArea.SetContentsMargins(0, 0, 0, 0) - - syncer.OnEventType("m.room.message", func(ev *gomatrix.Event) { - msg, _ := ev.Body() - room := ev.RoomID - sender := ev.Sender - id := ev.ID - timestamp := ev.Timestamp - CacheErr := matrix.CacheMessageEvents(id, sender, room, msg, timestamp) - if CacheErr != nil { - err = CacheErr - return - } - messageListLayout.TriggerMessage(msg, sender) - }) - - // Start Non-blocking sync - go func() { - localLog.Println("Start sync") - for { - - if e := cli.Sync(); e != nil { - localLog.Println("Fatal Sync() error") - time.Sleep(5 * time.Second) - } - time.Sleep(10 * time.Second) - } - }() - - messageInput := widgets.NewQLineEditFromPointer(widget.FindChild("MessageInput", core.Qt__FindChildrenRecursively).Pointer()) - var message string - window.ConnectKeyPressEvent(func(ev *gui.QKeyEvent) { - if int(ev.Key()) == int(core.Qt__Key_Enter) || int(ev.Key()) == int(core.Qt__Key_Return) { - mardownMessage := commonmark.Md2Html(message, 0) - if mardownMessage == message { - _, SendErr := cli.SendText("!zTIXGmDjyRcAqbrWab:matrix.ffslfl.net", message) - if SendErr != nil { - err = SendErr - return - } - } else { - _, SendErr := cli.SendMessageEvent("!zTIXGmDjyRcAqbrWab:matrix.ffslfl.net", "m.room.message", matrix.HTMLMessage{"m.text", message, mardownMessage, "org.matrix.custom.html"}) - if SendErr != nil { - err = SendErr - return - } - } - messageInput.Clear() - } else { - messageInput.KeyPressEventDefault(ev) - } - }) - messageInput.ConnectTextChanged(func(value string) { - message = value - }) - - respWidget = widget - return -} diff --git a/uis.old b/uis.old @@ -1,146 +0,0 @@ - widget := widgets.NewQWidget(nil, 0) - widget.SetObjectName("MainWrapper") - widget.SetStyleSheet("QWidget#MainWrapper { border: 0px; };") - window.SetupUi(widget) - topLayout := widgets.NewQVBoxLayout2(widget) - topLayout.SetSpacing(0) - - // var ( - // usernameLabel = widgets.NewQLabelFromPointer(widget.FindChild("UsernameLabel", core.Qt__FindChildrenRecursively).Pointer()) - // mxidLabel = widgets.NewQLabelFromPointer(widget.FindChild("MXIDLabel", core.Qt__FindChildrenRecursively).Pointer()) - // avatarLogo = widgets.NewQLabelFromPointer(widget.FindChild("AvatarLabel", core.Qt__FindChildrenRecursively).Pointer()) - // ) - // - // // Set MXID Label - // mxidLabel.SetText(fmt.Sprint(username)) - // - // // Set Dispalyname Label - // displayName, displayNameErr := cli.GetUserDisplayName(username) - // if displayNameErr != nil { - // localLog.Println(displayNameErr) - // } - // usernameLabel.SetText(fmt.Sprint(displayName)) - // - // // Set Avatar - // avatarLogo.SetAlignment(core.Qt__AlignBottom | core.Qt__AlignRight) - // avatarLogo.SetPixmap(cli.GetOwnUserAvatar()) - - // Wrapper - wrapperWidget := widgets.NewQGroupBox2("", nil) - wrapperWidget.SetContentsMargins(0, 0, 0, 0) - wrapperWidget.SetObjectName("MainWrapperWidget") - wrapperWidget.SetStyleSheet("QWidget#MainWrapperWidget { border: 0px; };") - wrapperLayout := widgets.NewQGridLayout2() - wrapperLayout.SetSpacing(0) - wrapperLayout.SetContentsMargins(0, 0, 0, 0) - - // Roomlist - roomList, roomListLayout := elements.NewRoomList() - - // Fake Room - elements.NewRoom("Test", roomListLayout) - - wrapperLayout.AddWidget(roomList, 0, 0, 0) - - // Message View - messageList, messageListLayout := elements.NewMessageList() - - // Messages - syncer := cli.Syncer.(*gomatrix.DefaultSyncer) - customStore := gomatrix.NewInMemoryStore() - cli.Store = customStore - syncer.Store = customStore - syncer.OnEventType("m.room.message", func(ev *gomatrix.Event) { - // TODO Later needs to match current Room - if ev.RoomID == "!zTIXGmDjyRcAqbrWab:matrix.ffslfl.net" { - messageBody, messageOk := ev.Body() - if messageOk == true { - elements.NewMessage(messageBody, messageListLayout) - } else { - localLog.Println("Message not ok: ", messageOk) - } - } - }) - - // Start Non-blocking sync - localLog.Println("Syncing now") - go func() { - for { - fmt.Println("sync") - if e := cli.Sync(); e != nil { - fmt.Println("Fatal Sync() error") - time.Sleep(10 * time.Second) - } - time.Sleep(10 * time.Second) - } - }() - - localLog.Println("Started Syncing") - - wrapperLayout.AddWidget(messageList, 0, 1, 0) - - // logoutButton //TODO move it to correct place - buttonWidget := widgets.NewQWidget(nil, 0) - buttonLayout := widgets.NewQVBoxLayout() - buttonLayout.SetSpacing(0) - - logoutButton := widgets.NewQPushButton2("LOGOUT", nil) - logoutButton.SetMinimumSize2(350, 65) - - buttonLayout.AddStretch(1) - buttonLayout.AddWidget(logoutButton, 0, 0) - buttonLayout.AddStretch(1) - - buttonWidget.SetLayout(buttonLayout) - wrapperLayout.AddWidget(buttonWidget, 1, 0, core.Qt__AlignBottom) - - logoutButton.ConnectClicked(func(checked bool) { - //TODO register enter and show loader or so - localLog.Println("Starting Logout Sequenze in background") - var wg sync.WaitGroup - results := make(chan bool) - - wg.Add(1) - go func(cli *gomatrix.Client, localLog *log.Logger, results chan<- bool) { - defer wg.Done() - _, err := cli.Logout() - if err != nil { - localLog.Println(err) - results <- false - } else { - cli.ClearCredentials() - //Flush complete DB - db.View(func(tx *buntdb.Tx) error { - var QueryErr error - QueryErr = tx.DeleteAll() - if QueryErr != nil { - return QueryErr - } - return nil - }) - results <- true - } - }(cli, localLog, results) - - go func() { - wg.Wait() // wait for each execTask to return - close(results) // then close the results channel - }() - - //Show MainUI - for result := range results { - if result { - LoginUI := NewLoginUI(windowWidth, windowHeight) - window.SetCentralWidget(LoginUI) - } - } - }) - - wrapperLayout.SetColumnMinimumWidth(0, windowWidth/3) - wrapperLayout.SetColumnMinimumWidth(1, (windowWidth/3)*2) - wrapperLayout.SetRowMinimumHeight(0, windowHeight) - wrapperWidget.SetLayout(wrapperLayout) - topLayout.AddWidget(wrapperWidget, 1, core.Qt__AlignVCenter) - widget.SetLayout(topLayout) - - return widget -\ No newline at end of file