mirror of
https://github.com/diamondburned/cchat-gtk.git
synced 2024-12-23 12:46:45 +00:00
185 lines
4.8 KiB
Go
185 lines
4.8 KiB
Go
package ui
|
|
|
|
import (
|
|
"github.com/diamondburned/cchat"
|
|
"github.com/diamondburned/cchat-gtk/icons"
|
|
"github.com/diamondburned/cchat-gtk/internal/gts"
|
|
"github.com/diamondburned/cchat-gtk/internal/log"
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/config/preferences"
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/messages"
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/service"
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/service/auth"
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/service/session"
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/service/session/server"
|
|
"github.com/gotk3/gotk3/gdk"
|
|
"github.com/gotk3/gotk3/glib"
|
|
"github.com/gotk3/gotk3/gtk"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
func init() {
|
|
// Load the local CSS.
|
|
gts.LoadCSS("main", `
|
|
/* Make CSS more consistent across themes */
|
|
headerbar { padding-left: 0 }
|
|
|
|
/* .appmenu { margin: 0 20px } */
|
|
|
|
popover > *:not(stack):not(button) { margin: 6px }
|
|
|
|
/* Hack to fix the input bar being high in Adwaita */
|
|
.input-field * { min-height: 0 }
|
|
`)
|
|
}
|
|
|
|
// constraints for the left panel
|
|
const (
|
|
leftMinWidth = 200
|
|
leftCurrentWidth = 275
|
|
leftMaxWidth = 400
|
|
)
|
|
|
|
func clamp(n, min, max int) int {
|
|
switch {
|
|
case n > max:
|
|
return max
|
|
case n < min:
|
|
return min
|
|
default:
|
|
return n
|
|
}
|
|
}
|
|
|
|
type App struct {
|
|
window *window
|
|
header *header
|
|
|
|
// used to keep track of what row to disconnect before switching
|
|
lastSelector func(bool)
|
|
}
|
|
|
|
var (
|
|
_ gts.Window = (*App)(nil)
|
|
_ service.Controller = (*App)(nil)
|
|
)
|
|
|
|
func NewApplication() *App {
|
|
app := &App{}
|
|
app.window = newWindow(app)
|
|
app.header = newHeader()
|
|
|
|
// Resize the app icon with the left-most sidebar.
|
|
services := app.window.Services.Services
|
|
services.Connect("size-allocate", func() {
|
|
app.header.left.appmenu.SetSizeRequest(services.GetAllocatedWidth(), -1)
|
|
})
|
|
|
|
// Resize the left-side header w/ the left-side pane.
|
|
app.window.Services.ServerView.Connect("size-allocate", func() {
|
|
// Get the current width of the left sidebar.
|
|
width := app.window.GetPosition()
|
|
// Set the left-side header's size.
|
|
app.header.left.SetSizeRequest(width, -1)
|
|
})
|
|
|
|
// Bind the preferences action for our GAction button in the header popover.
|
|
// The action name for this is "app.preferences".
|
|
gts.AddAppAction("preferences", preferences.SpawnPreferenceDialog)
|
|
|
|
return app
|
|
}
|
|
|
|
func (app *App) AddService(svc cchat.Service) {
|
|
app.window.Services.AddService(svc)
|
|
}
|
|
|
|
// OnSessionRemove resets things before the session is removed.
|
|
func (app *App) OnSessionRemove(s *service.Service, r *session.Row) {
|
|
// Reset the message view if it's what we're showing.
|
|
if app.window.MessageView.SessionID() == r.ID() {
|
|
app.window.MessageView.Reset()
|
|
app.header.SetBreadcrumber(nil)
|
|
}
|
|
}
|
|
|
|
func (app *App) OnSessionDisconnect(s *service.Service, r *session.Row) {
|
|
// We're basically doing the same thing as removing a session. Check
|
|
// OnSessionRemove above.
|
|
app.OnSessionRemove(s, r)
|
|
}
|
|
|
|
func (app *App) SessionSelected(svc *service.Service, ses *session.Row) {
|
|
// TODO: restore last message box
|
|
app.window.MessageView.Reset()
|
|
app.header.SetBreadcrumber(ses)
|
|
app.header.SetSessionMenu(ses)
|
|
}
|
|
|
|
func (app *App) RowSelected(ses *session.Row, srv *server.ServerRow, smsg cchat.ServerMessage) {
|
|
// Is there an old row that we should deactivate?
|
|
if app.lastSelector != nil {
|
|
app.lastSelector(false)
|
|
}
|
|
|
|
// Set the new row.
|
|
app.lastSelector = srv.SetSelected
|
|
app.lastSelector(true)
|
|
|
|
app.header.SetBreadcrumber(srv)
|
|
|
|
// Disable the server list because we don't want the user to switch around
|
|
// while we're loading.
|
|
app.window.Services.SetSensitive(false)
|
|
|
|
// Assert that server is also a list, then join the server.
|
|
app.window.MessageView.JoinServer(ses.Session, smsg.(messages.ServerMessage), func() {
|
|
// Re-enable the server list.
|
|
app.window.Services.SetSensitive(true)
|
|
})
|
|
}
|
|
|
|
func (app *App) AuthenticateSession(list *service.List, ssvc *service.Service) {
|
|
var svc = ssvc.Service()
|
|
auth.NewDialog(svc.Name(), svc.Authenticate(), func(ses cchat.Session) {
|
|
ssvc.AddSession(ses)
|
|
})
|
|
}
|
|
|
|
// Close is called when the application finishes gracefully.
|
|
func (app *App) Close() {
|
|
// Disconnect everything. This blocks the main thread, so by the time we're
|
|
// done, the application would exit immediately. There's no need to update
|
|
// the GUI.
|
|
for _, s := range app.window.AllServices() {
|
|
var service = s.Service().Name()
|
|
|
|
for _, session := range s.BodyList.Sessions() {
|
|
if session.Session == nil {
|
|
continue
|
|
}
|
|
|
|
log.Printlnf("Disconnecting %s session %s", service, session.ID())
|
|
|
|
if err := session.Session.Disconnect(); err != nil {
|
|
log.Error(errors.Wrap(err, "Failed to disconnect "+session.ID()))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (app *App) Header() gtk.IWidget {
|
|
return app.header
|
|
}
|
|
|
|
func (app *App) Window() gtk.IWidget {
|
|
return app.window
|
|
}
|
|
|
|
func (app *App) Icon() *gdk.Pixbuf {
|
|
return icons.Logo256(0)
|
|
}
|
|
|
|
func (app *App) Menu() *glib.MenuModel {
|
|
return &app.header.menu.MenuModel
|
|
}
|