Split username container to a separate package

This commit is contained in:
diamondburned (Forefront) 2020-07-01 12:56:32 -07:00
parent 1caa476a84
commit 0200da67e0
2 changed files with 146 additions and 3 deletions

View File

@ -4,6 +4,7 @@ import (
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-gtk/internal/log"
"github.com/diamondburned/cchat-gtk/internal/ui/messages/input/completion"
"github.com/diamondburned/cchat-gtk/internal/ui/messages/input/username"
"github.com/diamondburned/cchat-gtk/internal/ui/primitives/scrollinput"
"github.com/gotk3/gotk3/gtk"
"github.com/pkg/errors"
@ -57,7 +58,7 @@ func (v *InputView) SetSender(session cchat.Session, sender cchat.ServerMessageS
type Field struct {
*gtk.Box
username *usernameContainer
username *username.Container
TextScroll *gtk.ScrolledWindow
text *gtk.TextView
@ -73,10 +74,10 @@ type Field struct {
editingID string // never empty
}
const inputmargin = 4
const inputmargin = username.VMargin
func NewField(text *gtk.TextView, ctrl Controller) *Field {
username := newUsernameContainer()
username := username.NewContainer()
username.Show()
buf, _ := text.GetBuffer()

View File

@ -0,0 +1,142 @@
package username
import (
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-gtk/internal/gts"
"github.com/diamondburned/cchat-gtk/internal/ui/config"
"github.com/diamondburned/cchat-gtk/internal/ui/rich"
"github.com/diamondburned/cchat/text"
"github.com/diamondburned/imgutil"
"github.com/gotk3/gotk3/gtk"
)
const AvatarSize = 24
const VMargin = 4
var showUser = true
var currentRevealer = func(bool) {} // noop by default
func init() {
// Bind this revealer in settings.
config.AppearanceAdd("Show Username in Input", config.Switch(
&showUser,
func(b bool) { currentRevealer(b) },
))
}
type Container struct {
*gtk.Revealer
main *gtk.Box
avatar *rich.Icon
label *rich.Label
}
var (
_ cchat.LabelContainer = (*Container)(nil)
_ cchat.IconContainer = (*Container)(nil)
)
func NewContainer() *Container {
avatar := rich.NewIcon(AvatarSize, imgutil.Round(true))
avatar.SetPlaceholderIcon("user-available-symbolic", AvatarSize)
avatar.Show()
label := rich.NewLabel(text.Rich{})
label.SetMaxWidthChars(35)
label.Show()
box, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 5)
box.PackStart(avatar, false, false, 0)
box.PackStart(label, false, false, 0)
box.SetMarginStart(10)
box.SetMarginEnd(10)
box.SetMarginTop(VMargin)
box.SetMarginBottom(VMargin)
box.SetVAlign(gtk.ALIGN_START)
box.Show()
rev, _ := gtk.RevealerNew()
rev.SetRevealChild(false)
rev.SetTransitionType(gtk.REVEALER_TRANSITION_TYPE_SLIDE_RIGHT)
rev.SetTransitionDuration(50)
rev.Add(box)
// Bind the current global revealer to this revealer for settings. This
// operation should be thread-safe, as everything is being done in the main
// thread.
currentRevealer = rev.SetRevealChild
return &Container{
Revealer: rev,
main: box,
avatar: avatar,
label: label,
}
}
func (u *Container) SetRevealChild(reveal bool) {
// Only reveal if showUser is true.
u.Revealer.SetRevealChild(reveal && showUser)
}
// shouldReveal returns whether or not the container should reveal.
func (u *Container) shouldReveal() bool {
return !u.label.GetLabel().Empty() && showUser
}
func (u *Container) Reset() {
u.SetRevealChild(false)
u.avatar.Reset()
u.label.Reset()
}
// Update is not thread-safe.
func (u *Container) Update(session cchat.Session, sender cchat.ServerMessageSender) {
// Set the fallback username.
u.label.SetLabelUnsafe(session.Name())
// Reveal the name if it's not empty.
u.SetRevealChild(u.shouldReveal())
// Does sender (aka Server) implement ServerNickname? If yes, use it.
if nicknamer, ok := sender.(cchat.ServerNickname); ok {
u.label.AsyncSetLabel(nicknamer.Nickname, "Error fetching server nickname")
}
// Does session implement an icon? Update if yes.
if iconer, ok := session.(cchat.Icon); ok {
u.avatar.AsyncSetIconer(iconer, "Error fetching session icon URL")
}
}
// GetLabel is not thread-safe.
func (u *Container) GetLabel() text.Rich {
return u.label.GetLabel()
}
// SetLabel is thread-safe.
func (u *Container) SetLabel(content text.Rich) {
gts.ExecAsync(func() {
u.label.SetLabelUnsafe(content)
// Reveal if the name is not empty.
u.SetRevealChild(u.shouldReveal())
})
}
// SetIcon is thread-safe.
func (u *Container) SetIcon(url string) {
gts.ExecAsync(func() {
u.avatar.SetIconUnsafe(url)
// Reveal if the icon URL is not empty. We don't touch anything if the
// URL is empty, as the name might not be.
if url != "" {
u.SetRevealChild(true)
}
})
}
// GetIconURL is not thread-safe.
func (u *Container) GetIconURL() string {
return u.avatar.URL()
}