mirror of
https://github.com/diamondburned/cchat-gtk.git
synced 2025-03-23 02:19:20 +00:00
Split username container to a separate package
This commit is contained in:
parent
1caa476a84
commit
0200da67e0
|
@ -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()
|
||||
|
|
142
internal/ui/messages/input/username/username.go
Normal file
142
internal/ui/messages/input/username/username.go
Normal 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()
|
||||
}
|
Loading…
Reference in a new issue