Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add File message to chat #39

Merged
merged 1 commit into from
Aug 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
github.com/rs/zerolog v1.31.0
github.com/seternate/go-lanty v0.1.0-beta.0.20240809132204-3be3d1587bdd
github.com/seternate/go-lanty v0.1.0-beta.0.20240818103544-c247788a1ae4
golang.design/x/clipboard v0.7.0
)

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,8 @@ github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWR
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/seternate/go-lanty v0.1.0-beta.0.20240809132204-3be3d1587bdd h1:vb22tGtb2yVepWmO/O6qHH6Zgqo8Ztd+PK47kg3xQCU=
github.com/seternate/go-lanty v0.1.0-beta.0.20240809132204-3be3d1587bdd/go.mod h1:QL66bV5xXhUysHVUI8VaX773dsvXJp0bDzrXWWq3IOs=
github.com/seternate/go-lanty v0.1.0-beta.0.20240818103544-c247788a1ae4 h1:vZbd/gyKrHFOBXz4htFCNR/AxD2c8avrPFazuYtMOdk=
github.com/seternate/go-lanty v0.1.0-beta.0.20240818103544-c247788a1ae4/go.mod h1:QL66bV5xXhUysHVUI8VaX773dsvXJp0bDzrXWWq3IOs=
github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
Expand Down
48 changes: 48 additions & 0 deletions pkg/controller/chatcontroller.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package controller

import (
"fmt"
"net/url"
"slices"
"sync"
"time"
Expand Down Expand Up @@ -31,13 +33,59 @@ func NewChatController(parent *Controller) (controller *ChatController) {
return
}

func (controller *ChatController) DownloadFile(message chat.Message) {
if message.GetType() != chat.TYPE_FILE {
log.Warn().Interface("message", message).Msg("wrong message type provided for file download")
return
}
m := message.(*chat.FileMessage)
u, err := url.Parse(m.Message.URL)
if err != nil {
log.Error().Err(err).Interface("message", message).Msg("error parsing filemessage url")
controller.parent.Status.Error("Failed to start download", 3*time.Second)
return
}
download, err := controller.parent.client.File.GetFile(controller.parent.ctx, *u, controller.parent.settings.DownloadDirectory)
if err != nil {
log.Error().Err(err).Interface("message", message).Msg("error starting filemessage download")
controller.parent.Status.Error(fmt.Sprintf("Failed downloading %s", download.Filename()), 3*time.Second)
return
}
go func() {
<-download.Done
if download.Err != nil {
log.Error().Err(err).Str("file", download.Filename()).Msg("error downloading filemessage file")
controller.parent.Status.Error(fmt.Sprintf("Failed downloading %s", download.Filename()), 3*time.Second)
return
}
log.Debug().Str("file", download.Filename()).Msg("sucessfully downloaded filemessage file")
controller.parent.Status.Info(fmt.Sprintf("Downloaded \"%s\" to \"%s\"", download.Filename(), controller.parent.settings.DownloadDirectory), 3*time.Second)
}()
}

func (controller *ChatController) SendTextMessage(message string) {
err := controller.parent.client.Chat.SendMessage(chat.NewTextMessage(controller.parent.User.GetUser(), message))
if err != nil {
log.Error().Err(err).Msg("error sending textmessage to server")
}
}

func (controller *ChatController) SendFileMessage(path string) {
controller.parent.Status.Info(fmt.Sprintf("Uploading file \"%s\" ...", path), 3*time.Second)
fileresponse, err := controller.parent.client.File.UploadFile(path)
if err != nil {
controller.parent.Status.Error(fmt.Sprintf("Error uploading file \"%s\"", path), 3*time.Second)
log.Error().Err(err).Str("file", path).Msg("error uploading file to server")
return
}

message := chat.NewFileMessage(controller.parent.User.GetUser(), fileresponse)
err = controller.parent.client.Chat.SendMessage(message)
if err != nil {
log.Error().Err(err).Interface("message", message).Msg("error sending filemessage to server")
}
}

func (controller *ChatController) Subscribe(subscriber chan chat.Message) {
defer controller.mutex.Unlock()
controller.mutex.Lock()
Expand Down
8 changes: 8 additions & 0 deletions pkg/controller/settingscontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ func (controller *SettingsController) SetUsername(username string) {
controller.Save()
}

func (controller *SettingsController) SetDownloadDirectory(downloaddirectory string) {
controller.mutex.Lock()
controller.settings.DownloadDirectory = downloaddirectory
controller.mutex.Unlock()
controller.notifySubcriber()
controller.Save()
}

func (controller *SettingsController) Settings() setting.Settings {
defer controller.mutex.RUnlock()
controller.mutex.RLock()
Expand Down
7 changes: 4 additions & 3 deletions pkg/setting/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ const (
)

type Settings struct {
ServerURL string `yaml:"serverurl"`
GameDirectory string `yaml:"gamedirectory"`
Username string `yaml:"username"`
ServerURL string `yaml:"serverurl"`
GameDirectory string `yaml:"gamedirectory"`
Username string `yaml:"username"`
DownloadDirectory string `yaml:"downloaddirectory"`
}

func LoadSettings() (s *Settings, err error) {
Expand Down
39 changes: 35 additions & 4 deletions pkg/widget/chatbrowser.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package widget
import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/storage"
fynetheme "fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
"github.com/rs/zerolog/log"
Expand All @@ -13,20 +15,24 @@ import (
type ChatBrowser struct {
widget.BaseWidget
controller *controller.Controller
window fyne.Window
messageboard *MessageBoard
scroll *ScrollWithState
messageentry *widget.Entry
sendbutton *widget.Button
filebutton *widget.Button
newmessage chan struct{}
}

func NewChatBrowser(controller *controller.Controller) (chatbrowser *ChatBrowser) {
func NewChatBrowser(controller *controller.Controller, window fyne.Window) (chatbrowser *ChatBrowser) {
chatbrowser = &ChatBrowser{
controller: controller,
window: window,
messageboard: NewMessageBoard(controller),
messageentry: widget.NewMultiLineEntry(),
newmessage: make(chan struct{}, 50),
sendbutton: widget.NewButtonWithIcon("", fynetheme.MailSendIcon(), nil),
filebutton: widget.NewButtonWithIcon("", fynetheme.MailAttachmentIcon(), nil),
}
chatbrowser.ExtendBaseWidget(chatbrowser)

Expand All @@ -37,18 +43,40 @@ func NewChatBrowser(controller *controller.Controller) (chatbrowser *ChatBrowser
chatbrowser.messageentry.SetPlaceHolder("Type your message here!")
chatbrowser.messageentry.OnSubmitted = func(s string) {
controller.Chat.SendTextMessage(s)
chatbrowser.messageentry.SetText("")
}

chatbrowser.sendbutton.OnTapped = func() {
controller.Chat.SendTextMessage(chatbrowser.messageentry.Text)
chatbrowser.messageentry.SetText("")
}

chatbrowser.filebutton.OnTapped = chatbrowser.fileUploadCallback

chatbrowser.messageboard.Subscribe(chatbrowser.newmessage)
chatbrowser.run()

return chatbrowser
}

func (widget *ChatBrowser) fileUploadCallback() {
folderdialog := dialog.NewFileOpen(func(uri fyne.URIReadCloser, err error) {
if uri == nil || err != nil {
return
}
widget.controller.Chat.SendFileMessage(uri.URI().Path())
}, widget.window)

dialogStartURI, err := storage.ListerForURI(storage.NewFileURI(widget.controller.Settings.Settings().GameDirectory))
if err == nil {
folderdialog.SetLocation(dialogStartURI)
}

//This will make the folderopen dialog to be "fullscreen" inside the app
folderdialog.Resize(fyne.NewSize(10000, 10000))
folderdialog.Show()
}

func (widget *ChatBrowser) run() {
widget.controller.WaitGroup().Add(1)
go widget.messageUpdater()
Expand Down Expand Up @@ -89,6 +117,7 @@ func (renderer *chatBrowserRenderer) Objects() []fyne.CanvasObject {
objects := []fyne.CanvasObject{
renderer.widget.scroll,
renderer.widget.sendbutton,
renderer.widget.filebutton,
renderer.widget.messageentry,
}
return objects
Expand All @@ -101,14 +130,15 @@ func (renderer *chatBrowserRenderer) Layout(size fyne.Size) {
renderer.widget.scroll.Resize(fyne.NewSize(size.Width-2*theme.InnerPadding(), size.Height-3*theme.InnerPadding()-bottomHeight))
renderer.widget.sendbutton.Resize(fyne.NewSize(bottomHeight, bottomHeight))
renderer.widget.sendbutton.Move(fyne.NewPos(size.Width-theme.InnerPadding()-renderer.widget.sendbutton.Size().Width, renderer.widget.scroll.Position().Y+renderer.widget.scroll.Size().Height+theme.InnerPadding()))
renderer.widget.filebutton.Resize(fyne.NewSize(bottomHeight, bottomHeight))
renderer.widget.filebutton.Move(fyne.NewPos(renderer.widget.sendbutton.Position().X-theme.InnerPadding()-renderer.widget.filebutton.Size().Width, renderer.widget.scroll.Position().Y+renderer.widget.scroll.Size().Height+theme.InnerPadding()))
renderer.widget.messageentry.Move(fyne.NewPos(renderer.widget.scroll.Position().X, renderer.widget.scroll.Position().Y+renderer.widget.scroll.Size().Height+theme.InnerPadding()))
renderer.widget.messageentry.Resize(fyne.NewSize(size.Width-3*theme.InnerPadding()-renderer.widget.sendbutton.Size().Width, bottomHeight))

renderer.widget.messageentry.Resize(fyne.NewSize(renderer.widget.filebutton.Position().X-2*theme.InnerPadding(), bottomHeight))
}

func (renderer *chatBrowserRenderer) MinSize() fyne.Size {
bottomHeight := fyne.Max(renderer.widget.messageentry.MinSize().Height, renderer.widget.sendbutton.MinSize().Height)
minWidth := fyne.Max(3*theme.InnerPadding()+renderer.widget.messageentry.MinSize().Width+renderer.widget.sendbutton.MinSize().Width, 2*theme.InnerPadding()+renderer.widget.scroll.MinSize().Width)
minWidth := fyne.Max(4*theme.InnerPadding()+renderer.widget.messageentry.MinSize().Width+renderer.widget.sendbutton.MinSize().Width+renderer.widget.filebutton.MinSize().Width, 2*theme.InnerPadding()+renderer.widget.scroll.MinSize().Width)
minHeight := 3*theme.InnerPadding() + bottomHeight
return fyne.NewSize(minWidth, minHeight)
}
Expand All @@ -118,6 +148,7 @@ func (renderer *chatBrowserRenderer) Refresh() {
renderer.widget.scroll.Refresh()
renderer.widget.messageentry.Refresh()
renderer.widget.sendbutton.Refresh()
renderer.widget.filebutton.Refresh()
//Without first messagetiles will be never be shown until "resize" event happens
//then all messagetile are shown correctly
canvas.Refresh(renderer.widget)
Expand Down
2 changes: 1 addition & 1 deletion pkg/widget/lanty.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func NewLanty(controller *controller.Controller, window fyne.Window) *Lanty {
downloadbrowser := NewDownloadBrowser(controller)
userbrowser := NewUserBrowser(controller)
settingsbrowser := NewSettingsBrowser(controller, window)
chatbrowser := NewChatBrowser(controller)
chatbrowser := NewChatBrowser(controller, window)

lanty := &Lanty{
controller: controller,
Expand Down
14 changes: 14 additions & 0 deletions pkg/widget/messageboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"slices"
"strings"
"sync"
"time"

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
Expand All @@ -15,6 +16,7 @@ import (
"github.com/seternate/go-lanty-client/pkg/theme"
"github.com/seternate/go-lanty/pkg/chat"
"github.com/seternate/go-lanty/pkg/util"
"golang.design/x/clipboard"
)

type MessageBoard struct {
Expand Down Expand Up @@ -82,6 +84,15 @@ func (widget *MessageBoard) addMessageTile(message chat.Message) {
messagetile.SetBackgroundColor(fynetheme.PrimaryColor())
messagetile.HideUser()
}
if message.GetType() == chat.TYPE_FILE {
messagetile.SetIcon(fynetheme.FileIcon())
messagetile.OnTapped = widget.controller.Chat.DownloadFile
} else if message.GetType() == chat.TYPE_TEXT {
messagetile.OnTapped = func(m chat.Message) {
clipboard.Write(clipboard.FmtText, []byte(m.GetMessage()))
widget.controller.Status.Info("Message copied", 3*time.Second)
}
}
widget.messagetiles.PushFront(messagetile)
widget.Refresh()
widget.notifySubcriber()
Expand Down Expand Up @@ -134,6 +145,9 @@ func (renderer *messageBoardRenderer) Layout(size fyne.Size) {
}
//Calculate Tile Width
maxtextwidth := fyne.MeasureText(longestline, fynetheme.TextSize(), fyne.TextStyle{}).Width + 4*fynetheme.LineSpacing()
if messagetile.HasIcon() {
maxtextwidth = maxtextwidth + 18
}
messagetilewidth := fyne.Max(maxtextwidth, messagetile.MinSize().Width)
if messagetilewidth > size.Width*0.6 {
messagetilewidth = size.Width * 0.6
Expand Down
Loading
Loading