1
0
Fork 0
mirror of https://github.com/diamondburned/cchat-gtk.git synced 2024-11-01 03:54:16 +00:00
cchat-gtk/internal/ui/messages/typing/typing.go
diamondburned (Forefront) 2fae6ffbb3 UI changes; typing state working
This commit refactors the input container's UI as well as fixing some
bugs related to asynchronous fetching of images.

It also adds complete typing indicator capabilities, all without using a
single mutex!
2020-07-08 02:17:54 -07:00

119 lines
2.3 KiB
Go

package typing
import (
"strings"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-gtk/internal/ui/primitives"
"github.com/diamondburned/cchat-gtk/internal/ui/rich/parser"
"github.com/gotk3/gotk3/gtk"
"github.com/gotk3/gotk3/pango"
)
var typingIndicatorCSS = primitives.PrepareCSS(`
.typing-indicator {
margin: 0 6px;
border-radius: 6px 6px 0 0;
color: alpha(@theme_fg_color, 0.8);
background-color: @theme_base_color;
}
`)
var smallfonts = primitives.PrepareCSS(`
* { font-size: 0.9em; }
`)
type Container struct {
*gtk.Revealer
state *State
}
func New() *Container {
d := NewDots()
d.Show()
l, _ := gtk.LabelNew("")
l.SetXAlign(0)
l.SetEllipsize(pango.ELLIPSIZE_END)
l.Show()
primitives.AttachCSS(l, smallfonts)
b, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0)
b.PackStart(d, false, false, 4)
b.PackStart(l, true, true, 0)
b.Show()
r, _ := gtk.RevealerNew()
r.SetTransitionDuration(50)
r.SetTransitionType(gtk.REVEALER_TRANSITION_TYPE_CROSSFADE)
r.SetRevealChild(false)
r.Add(b)
primitives.AddClass(b, "typing-indicator")
primitives.AttachCSS(b, typingIndicatorCSS)
state := NewState(func(s *State, empty bool) {
r.SetRevealChild(!empty)
l.SetMarkup(render(s.typers))
})
// On label destroy, stop the state loop as well.
l.Connect("destroy", state.stopper)
return &Container{
Revealer: r,
state: state,
}
}
func (c *Container) Reset() {
c.state.reset()
c.SetRevealChild(false)
}
func (c *Container) RemoveAuthor(author cchat.MessageAuthor) {
c.state.removeTyper(author.ID())
}
func (c *Container) TrySubscribe(svmsg cchat.ServerMessage) bool {
ti, ok := svmsg.(cchat.ServerMessageTypingIndicator)
if !ok {
return false
}
c.state.Subscribe(ti)
return true
}
func render(typers []cchat.Typer) string {
// fast path
if len(typers) == 0 {
return ""
}
var builder strings.Builder
for i, typer := range typers {
builder.WriteString("<b>")
builder.WriteString(parser.RenderMarkup(typer.Name()))
builder.WriteString("</b>")
switch i {
case len(typers) - 2:
builder.WriteString(" and ")
case len(typers) - 1:
// Write nothing if this is the last item.
default:
builder.WriteString(", ")
}
}
if len(typers) == 1 {
builder.WriteString(" is typing.")
} else {
builder.WriteString(" are typing.")
}
return builder.String()
}