cchat-gtk/internal/ui/messages/input/input.go

151 lines
3.2 KiB
Go
Raw Normal View History

2020-05-26 06:51:06 +00:00
package input
import (
2020-06-07 07:06:13 +00:00
"strconv"
"time"
2020-05-26 06:51:06 +00:00
"github.com/diamondburned/cchat"
2020-06-04 23:00:41 +00:00
"github.com/diamondburned/cchat-gtk/internal/gts"
2020-05-26 06:51:06 +00:00
"github.com/diamondburned/cchat-gtk/internal/log"
"github.com/gotk3/gotk3/gtk"
"github.com/pkg/errors"
)
type Field struct {
2020-06-04 23:00:41 +00:00
*gtk.Box
2020-06-06 00:47:28 +00:00
username *usernameContainer
2020-06-04 23:00:41 +00:00
TextScroll *gtk.ScrolledWindow
text *gtk.TextView
buffer *gtk.TextBuffer
UserID string
2020-05-26 06:51:06 +00:00
sender cchat.ServerMessageSender
2020-06-04 23:00:41 +00:00
ctrl Controller
2020-05-26 06:51:06 +00:00
}
2020-06-04 23:00:41 +00:00
type Controller interface {
PresendMessage(msg PresendMessage) (onErr func(error))
}
2020-06-06 00:47:28 +00:00
const inputmargin = 4
2020-06-04 23:00:41 +00:00
func NewField(ctrl Controller) *Field {
2020-06-06 00:47:28 +00:00
username := newUsernameContainer()
2020-06-04 23:00:41 +00:00
username.Show()
2020-05-26 06:51:06 +00:00
text, _ := gtk.TextViewNew()
2020-06-04 23:00:41 +00:00
text.SetSensitive(false)
text.SetWrapMode(gtk.WRAP_WORD_CHAR)
text.SetProperty("top-margin", inputmargin)
text.SetProperty("left-margin", inputmargin)
text.SetProperty("right-margin", inputmargin)
text.SetProperty("bottom-margin", inputmargin)
2020-05-26 06:51:06 +00:00
text.Show()
buf, _ := text.GetBuffer()
sw, _ := gtk.ScrolledWindowNew(nil, nil)
2020-06-04 23:00:41 +00:00
sw.Add(text)
2020-05-26 06:51:06 +00:00
sw.SetPolicy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
2020-06-04 23:00:41 +00:00
sw.SetProperty("propagate-natural-height", true)
2020-05-26 06:51:06 +00:00
sw.SetProperty("max-content-height", 150)
2020-06-04 23:00:41 +00:00
sw.Show()
2020-05-26 06:51:06 +00:00
2020-06-04 23:00:41 +00:00
box, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0)
2020-06-06 00:47:28 +00:00
box.PackStart(username, false, false, 0)
2020-06-04 23:00:41 +00:00
box.PackStart(sw, true, true, 0)
box.Show()
field := &Field{
Box: box,
username: username,
TextScroll: sw,
text: text,
buffer: buf,
ctrl: ctrl,
2020-05-26 06:51:06 +00:00
}
2020-06-04 23:00:41 +00:00
text.SetFocusHAdjustment(sw.GetHAdjustment())
text.SetFocusVAdjustment(sw.GetVAdjustment())
text.Connect("key-press-event", field.keyDown)
return field
2020-05-26 06:51:06 +00:00
}
2020-06-07 07:06:13 +00:00
// Reset prepares the field before SetSender() is called.
func (f *Field) Reset() {
// Paranoia.
f.text.SetSensitive(false)
f.UserID = ""
f.sender = nil
f.username.Reset()
// reset the input
f.buffer.Delete(f.buffer.GetBounds())
}
2020-05-26 06:51:06 +00:00
// SetSender changes the sender of the input field. If nil, the input will be
2020-06-07 07:06:13 +00:00
// disabled. Reset() should be called first.
2020-06-04 23:00:41 +00:00
func (f *Field) SetSender(session cchat.Session, sender cchat.ServerMessageSender) {
2020-06-07 04:27:28 +00:00
// Update the left username container in the input.
f.username.Update(session, sender)
2020-06-04 23:00:41 +00:00
// Set the sender.
2020-06-07 07:06:13 +00:00
if sender != nil {
f.sender = sender
f.text.SetSensitive(true)
}
2020-05-26 06:51:06 +00:00
}
// SendMessage yanks the text from the input field and sends it to the backend.
// This function is not thread-safe.
func (f *Field) SendMessage() {
if f.sender == nil {
return
}
var text = f.yankText()
if text == "" {
return
}
var sender = f.sender
2020-06-07 07:06:13 +00:00
var data = SendMessageData{
content: text,
author: f.username.GetLabel(),
authorID: f.UserID,
authorURL: f.username.GetIconURL(),
nonce: "cchat-gtk_" + strconv.FormatInt(time.Now().UnixNano(), 10),
}
2020-06-04 23:00:41 +00:00
// presend message into the container through the controller
var done = f.ctrl.PresendMessage(data)
2020-05-26 06:51:06 +00:00
go func() {
2020-06-04 23:00:41 +00:00
err := sender.SendMessage(data)
gts.ExecAsync(func() {
done(err)
})
if err != nil {
2020-05-26 06:51:06 +00:00
log.Error(errors.Wrap(err, "Failed to send message"))
}
}()
}
// yankText cuts the text from the input field and returns it.
func (f *Field) yankText() string {
start, end := f.buffer.GetBounds()
text, _ := f.buffer.GetText(start, end, false)
if text != "" {
f.buffer.Delete(start, end)
}
return text
}