2020-06-06 00:47:28 +00:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/diamondburned/cchat"
|
|
|
|
"github.com/diamondburned/cchat-gtk/internal/gts"
|
|
|
|
"github.com/diamondburned/cchat-gtk/internal/log"
|
|
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/primitives"
|
|
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/rich"
|
|
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/service/breadcrumb"
|
2020-06-13 07:29:32 +00:00
|
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/service/loading"
|
2020-06-07 04:27:28 +00:00
|
|
|
"github.com/diamondburned/imgutil"
|
2020-06-06 00:47:28 +00:00
|
|
|
"github.com/gotk3/gotk3/gtk"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
)
|
|
|
|
|
|
|
|
const ChildrenMargin = 24
|
2020-06-06 07:44:36 +00:00
|
|
|
const IconSize = 18
|
2020-06-06 00:47:28 +00:00
|
|
|
|
|
|
|
type Controller interface {
|
|
|
|
MessageRowSelected(*Row, cchat.ServerMessage)
|
|
|
|
}
|
|
|
|
|
|
|
|
type Row struct {
|
|
|
|
*gtk.Box
|
|
|
|
Button *rich.ToggleButtonImage
|
|
|
|
Server cchat.Server
|
|
|
|
Parent breadcrumb.Breadcrumber
|
|
|
|
|
|
|
|
ctrl Controller
|
|
|
|
|
|
|
|
// enum 1
|
|
|
|
message cchat.ServerMessage
|
|
|
|
|
|
|
|
// enum 2
|
|
|
|
children *Children
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewRow(parent breadcrumb.Breadcrumber, server cchat.Server, ctrl Controller) *Row {
|
2020-06-13 07:29:32 +00:00
|
|
|
button := rich.NewToggleButtonImage(server.Name())
|
2020-06-06 00:47:28 +00:00
|
|
|
button.Box.SetHAlign(gtk.ALIGN_START)
|
2020-06-07 04:27:28 +00:00
|
|
|
button.Image.AddProcessors(imgutil.Round(true))
|
2020-06-06 07:44:36 +00:00
|
|
|
button.Image.SetSize(IconSize)
|
2020-06-06 00:47:28 +00:00
|
|
|
button.SetRelief(gtk.RELIEF_NONE)
|
|
|
|
button.Show()
|
2020-06-13 07:29:32 +00:00
|
|
|
|
|
|
|
if iconer, ok := server.(cchat.Icon); ok {
|
|
|
|
button.Image.AsyncSetIcon(iconer.Icon, "Error getting server icon URL")
|
|
|
|
}
|
2020-06-06 00:47:28 +00:00
|
|
|
|
|
|
|
box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
|
|
|
|
box.PackStart(button, false, false, 0)
|
|
|
|
box.Show()
|
|
|
|
|
|
|
|
primitives.AddClass(box, "server")
|
|
|
|
|
|
|
|
// TODO: images
|
|
|
|
|
|
|
|
var row = &Row{
|
|
|
|
Box: box,
|
|
|
|
Button: button,
|
|
|
|
Server: server,
|
|
|
|
Parent: parent,
|
|
|
|
ctrl: ctrl,
|
|
|
|
}
|
|
|
|
|
|
|
|
switch server := server.(type) {
|
|
|
|
case cchat.ServerList:
|
2020-06-07 07:06:13 +00:00
|
|
|
row.children = NewChildren(row, ctrl)
|
|
|
|
row.children.SetServerList(server)
|
2020-06-06 00:47:28 +00:00
|
|
|
|
2020-06-07 07:06:13 +00:00
|
|
|
box.PackStart(row.children, false, false, 0)
|
2020-06-06 00:47:28 +00:00
|
|
|
primitives.AddClass(box, "server-list")
|
|
|
|
|
|
|
|
case cchat.ServerMessage:
|
|
|
|
row.message = server
|
|
|
|
|
|
|
|
primitives.AddClass(box, "server-message")
|
|
|
|
}
|
|
|
|
|
|
|
|
button.Connect("clicked", row.onClick)
|
|
|
|
|
|
|
|
return row
|
|
|
|
}
|
|
|
|
|
2020-06-13 07:29:32 +00:00
|
|
|
// Deactivate calls the disconnect function then sets the button to false. This
|
|
|
|
// function is not thread-safe.
|
|
|
|
func (row *Row) Deactivate() {
|
|
|
|
row.Button.SetSensitive(true) // allow clicks again
|
|
|
|
row.Button.SetActive(false) // stop highlighting
|
|
|
|
}
|
|
|
|
|
2020-06-06 00:47:28 +00:00
|
|
|
func (row *Row) GetActive() bool {
|
|
|
|
return row.Button.GetActive()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (row *Row) onClick() {
|
|
|
|
switch {
|
|
|
|
// If the server is a message server. We're only selected if the button is
|
|
|
|
// pressed.
|
|
|
|
case row.message != nil && row.GetActive():
|
2020-06-13 07:29:32 +00:00
|
|
|
row.Button.SetSensitive(false) // prevent clicks from deactivating
|
2020-06-06 00:47:28 +00:00
|
|
|
row.ctrl.MessageRowSelected(row, row.message)
|
|
|
|
|
|
|
|
// If the server is a list of smaller servers.
|
|
|
|
case row.children != nil:
|
|
|
|
row.children.SetRevealChild(!row.children.GetRevealChild())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Row) Breadcrumb() breadcrumb.Breadcrumb {
|
|
|
|
return breadcrumb.Try(r.Parent, r.Button.GetText())
|
|
|
|
}
|
|
|
|
|
|
|
|
// Children is a children server with a reference to the parent.
|
|
|
|
type Children struct {
|
|
|
|
*gtk.Revealer
|
|
|
|
Main *gtk.Box
|
|
|
|
List cchat.ServerList
|
|
|
|
|
|
|
|
rowctrl Controller
|
|
|
|
|
2020-06-14 18:19:06 +00:00
|
|
|
load *loading.Button // nil after init
|
2020-06-06 00:47:28 +00:00
|
|
|
Rows []*Row
|
|
|
|
Parent breadcrumb.Breadcrumber
|
|
|
|
}
|
|
|
|
|
2020-06-07 07:06:13 +00:00
|
|
|
func NewChildren(parent breadcrumb.Breadcrumber, ctrl Controller) *Children {
|
2020-06-06 00:47:28 +00:00
|
|
|
main, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
|
|
|
|
main.SetMarginStart(ChildrenMargin)
|
|
|
|
main.Show()
|
|
|
|
|
|
|
|
rev, _ := gtk.RevealerNew()
|
|
|
|
rev.SetRevealChild(false)
|
|
|
|
rev.Add(main)
|
|
|
|
rev.Show()
|
|
|
|
|
2020-06-07 07:06:13 +00:00
|
|
|
return &Children{
|
2020-06-06 00:47:28 +00:00
|
|
|
Revealer: rev,
|
|
|
|
Main: main,
|
|
|
|
rowctrl: ctrl,
|
|
|
|
Parent: parent,
|
|
|
|
}
|
2020-06-07 07:06:13 +00:00
|
|
|
}
|
2020-06-06 00:47:28 +00:00
|
|
|
|
2020-06-14 18:19:06 +00:00
|
|
|
func (c *Children) SetLoading() {
|
|
|
|
// If we're already loading, then exit.
|
|
|
|
if c.load != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
c.load = loading.NewButton()
|
|
|
|
c.load.Show()
|
|
|
|
c.Main.Add(c.load)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Children) Reset() {
|
|
|
|
// Do we have the spinning circle button? If yes, remove it.
|
|
|
|
if c.load != nil {
|
|
|
|
c.Main.Remove(c.load)
|
|
|
|
c.load = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove old servers from the list.
|
|
|
|
for _, row := range c.Rows {
|
|
|
|
c.Main.Remove(row)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wipe the list empty.
|
|
|
|
c.Rows = nil
|
|
|
|
}
|
|
|
|
|
2020-06-07 07:06:13 +00:00
|
|
|
func (c *Children) SetServerList(list cchat.ServerList) {
|
|
|
|
c.List = list
|
|
|
|
|
2020-06-13 07:29:32 +00:00
|
|
|
go func() {
|
|
|
|
if err := list.Servers(c); err != nil {
|
|
|
|
log.Error(errors.Wrap(err, "Failed to get servers"))
|
|
|
|
}
|
|
|
|
}()
|
2020-06-06 00:47:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Children) SetServers(servers []cchat.Server) {
|
|
|
|
gts.ExecAsync(func() {
|
|
|
|
// Save the current state.
|
|
|
|
var oldID string
|
|
|
|
for _, row := range c.Rows {
|
|
|
|
if row.GetActive() {
|
|
|
|
oldID = row.Server.ID()
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-14 18:19:06 +00:00
|
|
|
// Reset before inserting new servers.
|
|
|
|
c.Reset()
|
2020-06-06 00:47:28 +00:00
|
|
|
|
|
|
|
c.Rows = make([]*Row, len(servers))
|
|
|
|
|
|
|
|
for i, server := range servers {
|
|
|
|
row := NewRow(c, server, c.rowctrl)
|
|
|
|
c.Rows[i] = row
|
|
|
|
c.Main.Add(row)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update parent reference? Only if it's activated.
|
|
|
|
if oldID != "" {
|
|
|
|
for _, row := range c.Rows {
|
|
|
|
if row.Server.ID() == oldID {
|
|
|
|
row.Button.SetActive(true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Children) Breadcrumb() breadcrumb.Breadcrumb {
|
|
|
|
return breadcrumb.Try(c.Parent)
|
|
|
|
}
|