2020-05-26 06:51:06 +00:00
|
|
|
package session
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/diamondburned/cchat"
|
2020-06-14 18:19:06 +00:00
|
|
|
"github.com/diamondburned/cchat-gtk/internal/gts"
|
2020-06-07 04:27:28 +00:00
|
|
|
"github.com/diamondburned/cchat-gtk/internal/keyring"
|
2020-06-14 18:19:06 +00:00
|
|
|
"github.com/diamondburned/cchat-gtk/internal/log"
|
2020-05-28 19:26:55 +00:00
|
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/primitives"
|
2020-07-14 07:24:55 +00:00
|
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/primitives/spinner"
|
|
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/rich"
|
|
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/rich/parser/markup"
|
2020-06-06 00:47:28 +00:00
|
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/service/breadcrumb"
|
2020-06-30 07:20:13 +00:00
|
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/service/session/commander"
|
2020-05-26 06:51:06 +00:00
|
|
|
"github.com/diamondburned/cchat-gtk/internal/ui/service/session/server"
|
2020-06-04 23:00:41 +00:00
|
|
|
"github.com/diamondburned/cchat/text"
|
2020-06-30 07:20:13 +00:00
|
|
|
"github.com/gotk3/gotk3/gtk"
|
2020-06-14 18:19:06 +00:00
|
|
|
"github.com/pkg/errors"
|
2020-05-26 06:51:06 +00:00
|
|
|
)
|
|
|
|
|
2020-07-14 07:24:55 +00:00
|
|
|
const IconSize = 48
|
2020-07-11 06:48:44 +00:00
|
|
|
const IconName = "face-plain-symbolic"
|
2020-06-04 23:00:41 +00:00
|
|
|
|
2020-07-14 07:24:55 +00:00
|
|
|
// Servicer extends server.RowController to add session.
|
|
|
|
type Servicer interface {
|
|
|
|
// Service asks the controller for its service.
|
|
|
|
Service() cchat.Service
|
2020-06-14 18:19:06 +00:00
|
|
|
// OnSessionDisconnect is called before a session is disconnected. This
|
|
|
|
// function is used for cleanups.
|
|
|
|
OnSessionDisconnect(*Row)
|
2020-07-14 07:24:55 +00:00
|
|
|
// SessionSelected is called when the row is clicked. The parent container
|
|
|
|
// should change the views to show this session's *Servers.
|
|
|
|
SessionSelected(*Row)
|
2020-06-17 07:06:34 +00:00
|
|
|
// RowSelected is called when a server that can display messages (aka
|
2020-06-14 18:19:06 +00:00
|
|
|
// implements ServerMessage) is called.
|
2020-06-17 07:06:34 +00:00
|
|
|
RowSelected(*Row, *server.ServerRow, cchat.ServerMessage)
|
2020-06-14 18:19:06 +00:00
|
|
|
// RestoreSession is called with the session ID to ask the controller to
|
|
|
|
// restore it from keyring information.
|
|
|
|
RestoreSession(*Row, string) // ID string, async
|
|
|
|
// RemoveSession is called to ask the controller to remove the session from
|
|
|
|
// the list of sessions.
|
2020-06-13 07:29:32 +00:00
|
|
|
RemoveSession(*Row)
|
2020-06-14 18:19:06 +00:00
|
|
|
// MoveSession is called to ask the controller to move the session to
|
|
|
|
// somewhere else in the list of sessions.
|
2020-06-13 07:29:32 +00:00
|
|
|
MoveSession(id, movingID string)
|
2020-06-04 23:00:41 +00:00
|
|
|
}
|
|
|
|
|
2020-07-14 07:24:55 +00:00
|
|
|
// Row represents a session row entry in the session List.
|
|
|
|
type Row struct {
|
|
|
|
*gtk.ListBoxRow
|
|
|
|
icon *rich.Icon // nilable
|
|
|
|
|
|
|
|
Session cchat.Session // state; nilable
|
|
|
|
sessionID string
|
|
|
|
|
|
|
|
Servers *Servers // accessed by View for the right view
|
|
|
|
svcctrl Servicer
|
|
|
|
|
|
|
|
// TODO: enum class? having the button be red on fail would be good
|
|
|
|
|
|
|
|
// put commander in either a hover menu or a right click menu. maybe in the
|
|
|
|
// headerbar as well.
|
|
|
|
// TODO headerbar how? custom interface to get menu items and callbacks in
|
|
|
|
// controller?
|
|
|
|
cmder *commander.Buffer
|
|
|
|
}
|
|
|
|
|
|
|
|
var rowCSS = primitives.PrepareClassCSS("session-row", `
|
|
|
|
.session-row:last-child {
|
|
|
|
border-radius: 0 0 14px 14px;
|
|
|
|
}
|
|
|
|
.session-row:selected {
|
|
|
|
background-color: alpha(@theme_selected_bg_color, 0.5);
|
|
|
|
}
|
|
|
|
`)
|
|
|
|
|
|
|
|
var rowIconCSS = primitives.PrepareClassCSS("session-icon", `
|
|
|
|
.session-icon {
|
|
|
|
padding: 4px;
|
|
|
|
margin: 0;
|
|
|
|
}
|
|
|
|
`)
|
|
|
|
|
|
|
|
func New(parent breadcrumb.Breadcrumber, ses cchat.Session, ctrl Servicer) *Row {
|
|
|
|
row := newRow(parent, text.Rich{}, ctrl)
|
|
|
|
row.SetSession(ses)
|
|
|
|
return row
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewLoading(parent breadcrumb.Breadcrumber, id, name string, ctrl Servicer) *Row {
|
|
|
|
row := newRow(parent, text.Rich{Content: name}, ctrl)
|
|
|
|
row.sessionID = id
|
|
|
|
row.SetLoading()
|
|
|
|
return row
|
|
|
|
}
|
|
|
|
|
|
|
|
func newRow(parent breadcrumb.Breadcrumber, name text.Rich, ctrl Servicer) *Row {
|
|
|
|
row := &Row{svcctrl: ctrl}
|
|
|
|
|
|
|
|
row.icon = rich.NewIcon(IconSize)
|
|
|
|
row.icon.SetPlaceholderIcon(IconName, IconSize)
|
|
|
|
row.icon.Show()
|
|
|
|
rowIconCSS(row.icon)
|
|
|
|
|
|
|
|
row.ListBoxRow, _ = gtk.ListBoxRowNew()
|
|
|
|
rowCSS(row.ListBoxRow)
|
|
|
|
|
|
|
|
// TODO: commander button
|
|
|
|
|
|
|
|
row.Servers = NewServers(parent, row)
|
|
|
|
row.Servers.Show()
|
|
|
|
|
|
|
|
return row
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset extends the server row's Reset function and resets additional states.
|
|
|
|
// It resets all states back to nil, but the session ID stays.
|
|
|
|
func (r *Row) Reset() {
|
|
|
|
r.Servers.Reset() // wipe servers
|
|
|
|
// TODO: better visual clue
|
|
|
|
r.icon.Image.SetFromPixbuf(nil) // wipe image
|
|
|
|
r.Session = nil
|
|
|
|
r.cmder = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Activate executes whatever needs to be done. If the row has failed, then this
|
|
|
|
// method will reconnect. If the row is already loaded, then SessionSelected
|
|
|
|
// will be called.
|
|
|
|
func (r *Row) Activate() {
|
|
|
|
// If session is nil, then we've probably failed to load it. The row is
|
|
|
|
// deactivated while loading, so this wouldn't have happened.
|
|
|
|
if r.Session == nil {
|
|
|
|
r.ReconnectSession()
|
|
|
|
} else {
|
|
|
|
r.svcctrl.SessionSelected(r)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetLoading sets the session button to have a spinner circle. DO NOT CONFUSE
|
|
|
|
// THIS WITH THE SERVERS LOADING.
|
|
|
|
func (r *Row) SetLoading() {
|
|
|
|
// Reset the state.
|
|
|
|
r.Session = nil
|
|
|
|
|
|
|
|
// Reset the icon.
|
|
|
|
r.icon.Image.SetFromPixbuf(nil)
|
|
|
|
|
|
|
|
// Remove everything from the row, including the icon.
|
|
|
|
primitives.RemoveChildren(r)
|
|
|
|
|
|
|
|
// Add a loading circle.
|
|
|
|
spin := spinner.New()
|
|
|
|
spin.SetSizeRequest(IconSize, IconSize)
|
|
|
|
spin.Start()
|
|
|
|
spin.Show()
|
|
|
|
|
|
|
|
r.Add(spin)
|
|
|
|
r.SetSensitive(false) // no activate
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetFailed sets the initial connect status to failed. Do note that session can
|
|
|
|
// have 2 types of loading: loading the session and loading the server list.
|
|
|
|
// This one sets the former.
|
|
|
|
func (r *Row) SetFailed(err error) {
|
|
|
|
// Make sure that Session is still nil.
|
|
|
|
r.Session = nil
|
|
|
|
// Re-enable the row.
|
|
|
|
r.SetSensitive(true)
|
|
|
|
// Remove everything off the row.
|
|
|
|
primitives.RemoveChildren(r)
|
|
|
|
// Add the icon.
|
|
|
|
r.Add(r.icon)
|
|
|
|
// Set the button to a retry icon.
|
|
|
|
r.icon.SetPlaceholderIcon("view-refresh-symbolic", IconSize)
|
|
|
|
|
|
|
|
// SetFailed, but also add the callback to retry.
|
|
|
|
// r.Row.SetFailed(err, r.ReconnectSession)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Row) RestoreSession(res cchat.SessionRestorer, k keyring.Session) {
|
|
|
|
go func() {
|
|
|
|
s, err := res.RestoreSession(k.Data)
|
|
|
|
if err != nil {
|
|
|
|
err = errors.Wrapf(err, "Failed to restore session %s (%s)", k.ID, k.Name)
|
|
|
|
log.Error(err)
|
|
|
|
|
|
|
|
gts.ExecAsync(func() { r.SetFailed(err) })
|
|
|
|
} else {
|
|
|
|
gts.ExecAsync(func() { r.SetSession(s) })
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetSession binds the session and marks the row as ready. It extends SetDone.
|
|
|
|
func (r *Row) SetSession(ses cchat.Session) {
|
|
|
|
// Set the states.
|
|
|
|
r.Session = ses
|
|
|
|
r.sessionID = ses.ID()
|
|
|
|
r.SetTooltipMarkup(markup.Render(ses.Name()))
|
|
|
|
r.icon.SetPlaceholderIcon(IconName, IconSize)
|
|
|
|
|
|
|
|
// If the session has an icon, then use it.
|
|
|
|
if iconer, ok := ses.(cchat.Icon); ok {
|
|
|
|
r.icon.AsyncSetIconer(iconer, "Failed to set session icon")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update to indicate that we're done.
|
|
|
|
primitives.RemoveChildren(r)
|
|
|
|
r.SetSensitive(true)
|
|
|
|
r.Add(r.icon)
|
|
|
|
|
|
|
|
// Set the commander, if any. The function will return nil if the assertion
|
|
|
|
// returns nil. As such, we assert with an ignored ok bool, allowing cmd to
|
|
|
|
// be nil.
|
|
|
|
cmd, _ := ses.(commander.SessionCommander)
|
|
|
|
r.cmder = commander.NewBuffer(r.svcctrl.Service(), cmd)
|
|
|
|
|
|
|
|
// TODO commander button
|
|
|
|
|
|
|
|
// // Bind extra menu items before loading. These items won't be clickable
|
|
|
|
// // during loading.
|
|
|
|
// r.SetNormalExtraMenu([]menu.Item{
|
|
|
|
// menu.SimpleItem("Disconnect", r.DisconnectSession),
|
|
|
|
// menu.SimpleItem("Remove", r.RemoveSession),
|
|
|
|
// })
|
|
|
|
|
|
|
|
// Load all top-level servers now.
|
|
|
|
r.Servers.SetList(ses)
|
|
|
|
}
|
|
|
|
|
|
|
|
// BindMover binds with the ID stored in the parent container to be used in the
|
|
|
|
// method itself. The ID may or may not have to do with session.
|
|
|
|
func (r *Row) BindMover(id string) {
|
|
|
|
// TODO: rows can be highlighted.
|
|
|
|
// primitives.BindDragSortable(r.Button, "GTK_TOGGLE_BUTTON", id, r.ctrl.MoveSession)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Row) RowSelected(sr *server.ServerRow, smsg cchat.ServerMessage) {
|
|
|
|
r.svcctrl.RowSelected(r, sr, smsg)
|
|
|
|
}
|
|
|
|
|
|
|
|
// RemoveSession removes itself from the session list.
|
|
|
|
func (r *Row) RemoveSession() {
|
|
|
|
// Remove the session off the list.
|
|
|
|
r.svcctrl.RemoveSession(r)
|
|
|
|
|
|
|
|
// Asynchrously disconnect.
|
|
|
|
go func() {
|
|
|
|
if err := r.Session.Disconnect(); err != nil {
|
|
|
|
log.Error(errors.Wrap(err, "Non-fatal, failed to disconnect removed session"))
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
// ReconnectSession tries to reconnect with the keyring data. This is a slow
|
|
|
|
// method but it's also a very cold path.
|
|
|
|
func (r *Row) ReconnectSession() {
|
|
|
|
// If we haven't ever connected, then don't run. In a legitimate case, this
|
|
|
|
// shouldn't happen.
|
|
|
|
if r.sessionID == "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the row as loading.
|
|
|
|
r.SetLoading()
|
|
|
|
// Try to restore the session.
|
|
|
|
r.svcctrl.RestoreSession(r, r.sessionID)
|
|
|
|
}
|
|
|
|
|
|
|
|
// DisconnectSession disconnects the current session. It does nothing if the row
|
|
|
|
// does not have a session active.
|
|
|
|
func (r *Row) DisconnectSession() {
|
|
|
|
// No-op if no session.
|
|
|
|
if r.Session == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call the disconnect function from the controller first.
|
|
|
|
r.svcctrl.OnSessionDisconnect(r)
|
|
|
|
|
|
|
|
// Show visually that we're disconnected first by wiping all servers.
|
|
|
|
r.Reset()
|
|
|
|
|
|
|
|
// Disable the button because we're busy disconnecting. We'll re-enable them
|
|
|
|
// once we're done reconnecting.
|
|
|
|
r.SetSensitive(false)
|
|
|
|
|
|
|
|
// Try and disconnect asynchronously.
|
|
|
|
gts.Async(func() (func(), error) {
|
|
|
|
// Disconnect and wrap the error if any. Wrap works with a nil error.
|
|
|
|
err := errors.Wrap(r.Session.Disconnect(), "Failed to disconnect.")
|
|
|
|
return func() {
|
|
|
|
// Re-enable access to the menu.
|
|
|
|
r.SetSensitive(true)
|
|
|
|
|
|
|
|
// Set the menu to allow disconnection.
|
|
|
|
// r.Button.SetNormalExtraMenu([]menu.Item{
|
|
|
|
// menu.SimpleItem("Connect", r.ReconnectSession),
|
|
|
|
// menu.SimpleItem("Remove", r.RemoveSession),
|
|
|
|
// })
|
|
|
|
}, err
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// // KeyringSession returns a keyring session, or nil if the session cannot be
|
|
|
|
// // saved.
|
|
|
|
// func (r *Row) KeyringSession() *keyring.Session {
|
|
|
|
// return keyring.ConvertSession(r.Session)
|
|
|
|
// }
|
|
|
|
|
|
|
|
// ID returns the session ID.
|
|
|
|
func (r *Row) ID() string {
|
|
|
|
return r.sessionID
|
|
|
|
}
|
|
|
|
|
|
|
|
// ShowCommander shows the commander dialog, or it does nothing if session does
|
|
|
|
// not implement commander.
|
|
|
|
func (r *Row) ShowCommander() {
|
|
|
|
if r.cmder == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
r.cmder.ShowDialog()
|
|
|
|
}
|
|
|
|
|
|
|
|
// deprecate server.Row inheritance since the structure is entirely different
|
|
|
|
|
|
|
|
/*
|
2020-06-13 07:29:32 +00:00
|
|
|
// Row represents a single session, including the button header and the
|
|
|
|
// children servers.
|
2020-05-26 06:51:06 +00:00
|
|
|
type Row struct {
|
2020-06-17 07:06:34 +00:00
|
|
|
*server.Row
|
|
|
|
Session cchat.Session
|
|
|
|
sessionID string // used for reconnection
|
2020-06-04 23:00:41 +00:00
|
|
|
|
2020-07-14 07:24:55 +00:00
|
|
|
ctrl Servicer
|
2020-06-30 07:20:13 +00:00
|
|
|
|
|
|
|
cmder *commander.Buffer
|
|
|
|
cmdbtn *gtk.Button
|
2020-05-26 06:51:06 +00:00
|
|
|
}
|
|
|
|
|
2020-07-14 07:24:55 +00:00
|
|
|
func New(parent breadcrumb.Breadcrumber, ses cchat.Session, ctrl Servicer) *Row {
|
2020-06-17 07:06:34 +00:00
|
|
|
row := newRow(parent, text.Rich{}, ctrl)
|
2020-06-07 04:27:28 +00:00
|
|
|
row.SetSession(ses)
|
|
|
|
return row
|
|
|
|
}
|
|
|
|
|
2020-07-14 07:24:55 +00:00
|
|
|
func NewLoading(parent breadcrumb.Breadcrumber, id, name string, ctrl Servicer) *Row {
|
2020-06-17 07:06:34 +00:00
|
|
|
row := newRow(parent, text.Rich{Content: name}, ctrl)
|
2020-06-14 18:19:06 +00:00
|
|
|
row.sessionID = id
|
2020-06-17 07:06:34 +00:00
|
|
|
row.Row.SetLoading()
|
2020-06-07 04:27:28 +00:00
|
|
|
return row
|
|
|
|
}
|
|
|
|
|
2020-07-14 07:24:55 +00:00
|
|
|
func newRow(parent breadcrumb.Breadcrumber, name text.Rich, ctrl Servicer) *Row {
|
2020-06-30 07:20:13 +00:00
|
|
|
srow := server.NewRow(parent, name)
|
2020-07-11 06:48:44 +00:00
|
|
|
srow.Button.SetPlaceholderIcon(IconName, IconSize)
|
2020-06-30 07:20:13 +00:00
|
|
|
srow.Show()
|
|
|
|
|
2020-06-17 07:06:34 +00:00
|
|
|
// Bind the row to .session in CSS.
|
2020-06-30 07:20:13 +00:00
|
|
|
primitives.AddClass(srow, "session")
|
|
|
|
primitives.AddClass(srow, "server-list")
|
|
|
|
|
|
|
|
// Make a commander button that's hidden by default in case.
|
|
|
|
cmdbtn, _ := gtk.ButtonNewFromIconName("utilities-terminal-symbolic", gtk.ICON_SIZE_BUTTON)
|
|
|
|
buttonoverlay.Take(srow.Button, cmdbtn, server.IconSize)
|
2020-07-10 23:26:07 +00:00
|
|
|
primitives.AddClass(cmdbtn, "command-button")
|
2020-06-30 07:20:13 +00:00
|
|
|
|
|
|
|
row := &Row{
|
|
|
|
Row: srow,
|
|
|
|
ctrl: ctrl,
|
|
|
|
cmdbtn: cmdbtn,
|
|
|
|
}
|
|
|
|
|
|
|
|
cmdbtn.Connect("clicked", row.ShowCommander)
|
2020-05-28 19:26:55 +00:00
|
|
|
|
2020-06-30 07:20:13 +00:00
|
|
|
return row
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset extends the server row's Reset function and resets additional states.
|
|
|
|
// It resets all states back to nil, but the session ID stays.
|
|
|
|
func (r *Row) Reset() {
|
|
|
|
r.Row.Reset()
|
|
|
|
r.Session = nil
|
|
|
|
r.cmder = nil
|
|
|
|
r.cmdbtn.Hide()
|
2020-06-04 23:00:41 +00:00
|
|
|
}
|
2020-05-26 06:51:06 +00:00
|
|
|
|
2020-06-14 18:19:06 +00:00
|
|
|
// RemoveSession removes itself from the session list.
|
|
|
|
func (r *Row) RemoveSession() {
|
|
|
|
// Remove the session off the list.
|
|
|
|
r.ctrl.RemoveSession(r)
|
|
|
|
|
|
|
|
// Asynchrously disconnect.
|
|
|
|
go func() {
|
|
|
|
if err := r.Session.Disconnect(); err != nil {
|
|
|
|
log.Error(errors.Wrap(err, "Non-fatal, failed to disconnect removed session"))
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
// ReconnectSession tries to reconnect with the keyring data. This is a slow
|
|
|
|
// method but it's also a very cold path.
|
|
|
|
func (r *Row) ReconnectSession() {
|
2020-06-17 07:06:34 +00:00
|
|
|
// If we haven't ever connected, then don't run. In a legitimate case, this
|
|
|
|
// shouldn't happen.
|
2020-06-14 18:19:06 +00:00
|
|
|
if r.sessionID == "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-06-17 07:06:34 +00:00
|
|
|
// Set the row as loading.
|
|
|
|
r.Row.SetLoading()
|
|
|
|
// Try to restore the session.
|
2020-06-14 18:19:06 +00:00
|
|
|
r.ctrl.RestoreSession(r, r.sessionID)
|
|
|
|
}
|
|
|
|
|
2020-06-20 04:40:34 +00:00
|
|
|
// DisconnectSession disconnects the current session. It does nothing if the row
|
|
|
|
// does not have a session active.
|
2020-06-14 18:19:06 +00:00
|
|
|
func (r *Row) DisconnectSession() {
|
2020-06-20 04:40:34 +00:00
|
|
|
// No-op if no session.
|
|
|
|
if r.Session == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-06-14 18:19:06 +00:00
|
|
|
// Call the disconnect function from the controller first.
|
|
|
|
r.ctrl.OnSessionDisconnect(r)
|
|
|
|
|
|
|
|
// Show visually that we're disconnected first by wiping all servers.
|
2020-06-17 07:06:34 +00:00
|
|
|
r.Reset()
|
2020-06-14 18:19:06 +00:00
|
|
|
|
|
|
|
// Set the offline icon to the button.
|
2020-07-11 06:48:44 +00:00
|
|
|
r.Button.Image.SetPlaceholderIcon(IconName, IconSize)
|
2020-06-14 18:19:06 +00:00
|
|
|
// Also unselect the button.
|
|
|
|
r.Button.SetActive(false)
|
|
|
|
|
|
|
|
// Disable the button because we're busy disconnecting. We'll re-enable them
|
|
|
|
// once we're done reconnecting.
|
|
|
|
r.SetSensitive(false)
|
|
|
|
|
|
|
|
// Try and disconnect asynchronously.
|
|
|
|
gts.Async(func() (func(), error) {
|
|
|
|
// Disconnect and wrap the error if any. Wrap works with a nil error.
|
|
|
|
err := errors.Wrap(r.Session.Disconnect(), "Failed to disconnect.")
|
|
|
|
return func() {
|
2020-06-17 07:06:34 +00:00
|
|
|
// Allow access to the menu
|
2020-06-14 18:19:06 +00:00
|
|
|
r.SetSensitive(true)
|
|
|
|
|
2020-06-17 07:06:34 +00:00
|
|
|
// Set the menu to allow disconnection.
|
|
|
|
r.Button.SetNormalExtraMenu([]menu.Item{
|
|
|
|
menu.SimpleItem("Connect", r.ReconnectSession),
|
|
|
|
menu.SimpleItem("Remove", r.RemoveSession),
|
|
|
|
})
|
2020-06-14 18:19:06 +00:00
|
|
|
}, err
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-06-07 04:27:28 +00:00
|
|
|
// KeyringSession returns a keyring session, or nil if the session cannot be
|
2020-06-07 07:06:13 +00:00
|
|
|
// saved.
|
2020-06-07 04:27:28 +00:00
|
|
|
func (r *Row) KeyringSession() *keyring.Session {
|
2020-06-14 18:19:06 +00:00
|
|
|
return keyring.ConvertSession(r.Session, r.Button.GetText())
|
2020-06-07 04:27:28 +00:00
|
|
|
}
|
|
|
|
|
2020-06-14 18:19:06 +00:00
|
|
|
// ID returns the session ID.
|
|
|
|
func (r *Row) ID() string {
|
|
|
|
return r.sessionID
|
|
|
|
}
|
2020-06-07 07:06:13 +00:00
|
|
|
|
2020-06-17 07:06:34 +00:00
|
|
|
// SetFailed sets the initial connect status to failed. Do note that session can
|
|
|
|
// have 2 types of loading: loading the session and loading the server list.
|
|
|
|
// This one sets the former.
|
|
|
|
func (r *Row) SetFailed(err error) {
|
|
|
|
// SetFailed, but also add the callback to retry.
|
|
|
|
r.Row.SetFailed(err, r.ReconnectSession)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetSession binds the session and marks the row as ready. It extends SetDone.
|
2020-06-14 18:19:06 +00:00
|
|
|
func (r *Row) SetSession(ses cchat.Session) {
|
2020-06-07 04:27:28 +00:00
|
|
|
r.Session = ses
|
2020-06-14 18:19:06 +00:00
|
|
|
r.sessionID = ses.ID()
|
2020-06-17 07:06:34 +00:00
|
|
|
r.SetLabelUnsafe(ses.Name())
|
|
|
|
r.SetIconer(ses)
|
|
|
|
|
2020-06-30 07:20:13 +00:00
|
|
|
// Set the commander, if any. The function will return nil if the assertion
|
|
|
|
// returns nil. As such, we assert with an ignored ok bool, allowing cmd to
|
|
|
|
// be nil.
|
|
|
|
cmd, _ := ses.(commander.SessionCommander)
|
|
|
|
r.cmder = commander.NewBuffer(r.ctrl.GetService(), cmd)
|
|
|
|
// Show the command button if the session actually supports the commander.
|
|
|
|
if r.cmder != nil {
|
|
|
|
r.cmdbtn.Show()
|
|
|
|
}
|
|
|
|
|
2020-06-17 07:06:34 +00:00
|
|
|
// Bind extra menu items before loading. These items won't be clickable
|
|
|
|
// during loading.
|
|
|
|
r.SetNormalExtraMenu([]menu.Item{
|
|
|
|
menu.SimpleItem("Disconnect", r.DisconnectSession),
|
|
|
|
menu.SimpleItem("Remove", r.RemoveSession),
|
|
|
|
})
|
2020-06-14 18:19:06 +00:00
|
|
|
|
2020-06-17 07:06:34 +00:00
|
|
|
// Preload now.
|
|
|
|
r.SetServerList(ses, r)
|
|
|
|
r.Load()
|
2020-05-26 06:51:06 +00:00
|
|
|
}
|
2020-06-06 00:47:28 +00:00
|
|
|
|
2020-06-17 07:06:34 +00:00
|
|
|
func (r *Row) RowSelected(server *server.ServerRow, smsg cchat.ServerMessage) {
|
|
|
|
r.ctrl.RowSelected(r, server, smsg)
|
2020-06-06 00:47:28 +00:00
|
|
|
}
|
2020-06-13 07:29:32 +00:00
|
|
|
|
2020-06-30 07:20:13 +00:00
|
|
|
// ShowCommander shows the commander dialog, or it does nothing if session does
|
|
|
|
// not implement commander.
|
|
|
|
func (r *Row) ShowCommander() {
|
|
|
|
if r.cmder == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
r.cmder.ShowDialog()
|
|
|
|
}
|
2020-07-14 07:24:55 +00:00
|
|
|
*/
|