Minor fixes
This commit is contained in:
parent
4a615e02bb
commit
d8f68cb852
2
go.mod
2
go.mod
|
@ -6,7 +6,7 @@ require (
|
||||||
github.com/Xuanwo/go-locale v1.0.0
|
github.com/Xuanwo/go-locale v1.0.0
|
||||||
github.com/alecthomas/chroma v0.7.3
|
github.com/alecthomas/chroma v0.7.3
|
||||||
github.com/diamondburned/cchat v0.6.4
|
github.com/diamondburned/cchat v0.6.4
|
||||||
github.com/diamondburned/cchat-discord v0.0.0-20210501072434-cc2b2ee4c799
|
github.com/diamondburned/cchat-discord v0.0.0-20210501221918-71c3069fa46f
|
||||||
github.com/diamondburned/gspell v0.0.0-20201229064336-e43698fd5828
|
github.com/diamondburned/gspell v0.0.0-20201229064336-e43698fd5828
|
||||||
github.com/diamondburned/handy v0.0.0-20210329054445-387ad28eb2c2
|
github.com/diamondburned/handy v0.0.0-20210329054445-387ad28eb2c2
|
||||||
github.com/diamondburned/imgutil v0.0.0-20200710174014-8a3be144a972
|
github.com/diamondburned/imgutil v0.0.0-20200710174014-8a3be144a972
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -147,6 +147,8 @@ github.com/diamondburned/cchat-discord v0.0.0-20210326063953-deb4ccb32bff h1:p5X
|
||||||
github.com/diamondburned/cchat-discord v0.0.0-20210326063953-deb4ccb32bff/go.mod h1:zbm+BpkQOMD6s87x4FrP3lTt9ddJLWTTPXyMROT+LZs=
|
github.com/diamondburned/cchat-discord v0.0.0-20210326063953-deb4ccb32bff/go.mod h1:zbm+BpkQOMD6s87x4FrP3lTt9ddJLWTTPXyMROT+LZs=
|
||||||
github.com/diamondburned/cchat-discord v0.0.0-20210501072434-cc2b2ee4c799 h1:xxqeuAx0T9SsS8DYKe4jxzL2saEpLyQeAttD0sX/g1E=
|
github.com/diamondburned/cchat-discord v0.0.0-20210501072434-cc2b2ee4c799 h1:xxqeuAx0T9SsS8DYKe4jxzL2saEpLyQeAttD0sX/g1E=
|
||||||
github.com/diamondburned/cchat-discord v0.0.0-20210501072434-cc2b2ee4c799/go.mod h1:zbm+BpkQOMD6s87x4FrP3lTt9ddJLWTTPXyMROT+LZs=
|
github.com/diamondburned/cchat-discord v0.0.0-20210501072434-cc2b2ee4c799/go.mod h1:zbm+BpkQOMD6s87x4FrP3lTt9ddJLWTTPXyMROT+LZs=
|
||||||
|
github.com/diamondburned/cchat-discord v0.0.0-20210501221918-71c3069fa46f h1:IDC3qToEm5owHf5FlJY9q9Kjbsv45+nly4I2YMv76lE=
|
||||||
|
github.com/diamondburned/cchat-discord v0.0.0-20210501221918-71c3069fa46f/go.mod h1:zbm+BpkQOMD6s87x4FrP3lTt9ddJLWTTPXyMROT+LZs=
|
||||||
github.com/diamondburned/cchat-mock v0.0.0-20201115033644-df8d1b10f9db h1:VQI2PdbsdsRJ7d669kp35GbCUO44KZ0Xfqdu4o/oqVg=
|
github.com/diamondburned/cchat-mock v0.0.0-20201115033644-df8d1b10f9db h1:VQI2PdbsdsRJ7d669kp35GbCUO44KZ0Xfqdu4o/oqVg=
|
||||||
github.com/diamondburned/cchat-mock v0.0.0-20201115033644-df8d1b10f9db/go.mod h1:M87kjNzWVPlkZycFNzpGPKQXzkHNnZphuwMf3E9ckgc=
|
github.com/diamondburned/cchat-mock v0.0.0-20201115033644-df8d1b10f9db/go.mod h1:M87kjNzWVPlkZycFNzpGPKQXzkHNnZphuwMf3E9ckgc=
|
||||||
github.com/diamondburned/gotk3 v0.0.0-20201209182406-e7291341a091 h1:lQpSWzbi3rQf66aMSip/rIypasIFwqCqF0Wfn5og6gw=
|
github.com/diamondburned/gotk3 v0.0.0-20201209182406-e7291341a091 h1:lQpSWzbi3rQf66aMSip/rIypasIFwqCqF0Wfn5og6gw=
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package gts
|
package gts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
@ -154,6 +155,7 @@ func Main(wfn func() MainApplication) {
|
||||||
|
|
||||||
// Async runs fn asynchronously, then runs the function it returns in the Gtk
|
// Async runs fn asynchronously, then runs the function it returns in the Gtk
|
||||||
// main thread.
|
// main thread.
|
||||||
|
// TODO: deprecate Async.
|
||||||
func Async(fn func() (func(), error)) {
|
func Async(fn func() (func(), error)) {
|
||||||
go func() {
|
go func() {
|
||||||
f, err := fn()
|
f, err := fn()
|
||||||
|
@ -168,27 +170,66 @@ func Async(fn func() (func(), error)) {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AsyncCancel is similar to AsyncCtx, but the context is created internally.
|
||||||
|
func AsyncCancel(fn func(ctx context.Context) (func(), error)) context.CancelFunc {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
// fn() is assumed to use the same given ctx.
|
||||||
|
f, err := fn(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to run the callback if it's there.
|
||||||
|
if f != nil {
|
||||||
|
ExecAsyncCtx(ctx, f)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return cancel
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsyncCtx does what Async does, except the returned callback will not be
|
||||||
|
// executed if the given context has expired or the returned callback is called.
|
||||||
|
func AsyncCtx(ctx context.Context, fn func() (func(), error)) {
|
||||||
|
go func() {
|
||||||
|
// fn() is assumed to use the same given ctx.
|
||||||
|
f, err := fn()
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to run the callback if it's there.
|
||||||
|
if f != nil {
|
||||||
|
ExecAsyncCtx(ctx, f)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
// ExecLater executes the function asynchronously with a low priority.
|
// ExecLater executes the function asynchronously with a low priority.
|
||||||
func ExecLater(fn func()) {
|
func ExecLater(fn func()) {
|
||||||
glib.IdleAddPriority(glib.PRIORITY_DEFAULT_IDLE, fn)
|
glib.IdleAddPriority(glib.PRIORITY_DEFAULT_IDLE, fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecAsync executes function asynchronously in the Gtk main thread.
|
// ExecAsync executes function asynchronously in the Gtk main thread.
|
||||||
|
// TODO: deprecate Async.
|
||||||
func ExecAsync(fn func()) {
|
func ExecAsync(fn func()) {
|
||||||
glib.IdleAddPriority(glib.PRIORITY_HIGH, fn)
|
glib.IdleAddPriority(glib.PRIORITY_HIGH, fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecSync executes the function asynchronously, but returns a channel that
|
// ExecAsyncCtx executes the function asynchronously in the Gtk main thread only
|
||||||
// indicates when the job is done.
|
// if the context has not expired. This API has absolutely no race conditions if
|
||||||
func ExecSync(fn func()) <-chan struct{} {
|
// the context is only canceled in the main thread.
|
||||||
var ch = make(chan struct{})
|
func ExecAsyncCtx(ctx context.Context, fn func()) {
|
||||||
|
ExecAsync(func() {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
|
||||||
glib.IdleAddPriority(glib.PRIORITY_HIGH, func() {
|
default:
|
||||||
fn()
|
fn()
|
||||||
close(ch)
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return ch
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DoAfter calls f after the given duration in the Gtk main loop.
|
// DoAfter calls f after the given duration in the Gtk main loop.
|
||||||
|
|
|
@ -21,8 +21,8 @@ type truncator struct {
|
||||||
var shortTruncators = []truncator{
|
var shortTruncators = []truncator{
|
||||||
{d: Day, s: "15:04"},
|
{d: Day, s: "15:04"},
|
||||||
{d: Week, s: "Mon 15:04"},
|
{d: Week, s: "Mon 15:04"},
|
||||||
{d: Year, s: "15:04 02/01"},
|
{d: Year, s: "02/01 15:04"},
|
||||||
{d: -1, s: "15:04 02/01/2006"},
|
{d: -1, s: "02/01/2006 15:04"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TimeAgo(t time.Time) string {
|
func TimeAgo(t time.Time) string {
|
||||||
|
|
|
@ -110,3 +110,16 @@ var toRestore = map[string]interface{}{}
|
||||||
func RegisterConfig(filename string, jsonValue interface{}) {
|
func RegisterConfig(filename string, jsonValue interface{}) {
|
||||||
toRestore[filename] = jsonValue
|
toRestore[filename] = jsonValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Updaters contains a list of callbacks to be called when something is updated.
|
||||||
|
type Updaters []func()
|
||||||
|
|
||||||
|
func (us *Updaters) Add(f func()) {
|
||||||
|
*us = append(*us, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (us *Updaters) Updated() {
|
||||||
|
for _, f := range *us {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,10 +6,29 @@ import (
|
||||||
"github.com/diamondburned/cchat-gtk/internal/ui/messages/container"
|
"github.com/diamondburned/cchat-gtk/internal/ui/messages/container"
|
||||||
"github.com/diamondburned/cchat-gtk/internal/ui/messages/message"
|
"github.com/diamondburned/cchat-gtk/internal/ui/messages/message"
|
||||||
"github.com/diamondburned/cchat-gtk/internal/ui/primitives"
|
"github.com/diamondburned/cchat-gtk/internal/ui/primitives"
|
||||||
|
"github.com/gotk3/gotk3/gtk"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Container struct {
|
type Container struct {
|
||||||
*container.ListContainer
|
*container.ListContainer
|
||||||
|
sg SizeGroups
|
||||||
|
}
|
||||||
|
|
||||||
|
type SizeGroups struct {
|
||||||
|
Timestamp *gtk.SizeGroup
|
||||||
|
Username *gtk.SizeGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSizeGroups() SizeGroups {
|
||||||
|
sg1, _ := gtk.SizeGroupNew(gtk.SIZE_GROUP_HORIZONTAL)
|
||||||
|
sg2, _ := gtk.SizeGroupNew(gtk.SIZE_GROUP_HORIZONTAL)
|
||||||
|
|
||||||
|
return SizeGroups{sg1, sg2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sgs *SizeGroups) Add(msg Message) {
|
||||||
|
sgs.Timestamp.AddWidget(msg.Timestamp)
|
||||||
|
sgs.Username.AddWidget(msg.Username)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ container.Container = (*Container)(nil)
|
var _ container.Container = (*Container)(nil)
|
||||||
|
@ -17,11 +36,12 @@ var _ container.Container = (*Container)(nil)
|
||||||
func NewContainer(ctrl container.Controller) *Container {
|
func NewContainer(ctrl container.Controller) *Container {
|
||||||
c := container.NewListContainer(ctrl)
|
c := container.NewListContainer(ctrl)
|
||||||
primitives.AddClass(c, "compact-container")
|
primitives.AddClass(c, "compact-container")
|
||||||
return &Container{c}
|
return &Container{c, NewSizeGroups()}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Container) NewPresendMessage(state *message.PresendState) container.PresendMessageRow {
|
func (c *Container) NewPresendMessage(state *message.PresendState) container.PresendMessageRow {
|
||||||
msg := WrapPresendMessage(state)
|
msg := WrapPresendMessage(state)
|
||||||
|
c.sg.Add(msg.Message)
|
||||||
c.addMessage(msg)
|
c.addMessage(msg)
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
@ -29,6 +49,7 @@ func (c *Container) NewPresendMessage(state *message.PresendState) container.Pre
|
||||||
func (c *Container) CreateMessage(msg cchat.MessageCreate) {
|
func (c *Container) CreateMessage(msg cchat.MessageCreate) {
|
||||||
gts.ExecAsync(func() {
|
gts.ExecAsync(func() {
|
||||||
msg := WrapMessage(message.NewState(msg))
|
msg := WrapMessage(message.NewState(msg))
|
||||||
|
c.sg.Add(msg)
|
||||||
c.addMessage(msg)
|
c.addMessage(msg)
|
||||||
c.CleanMessages()
|
c.CleanMessages()
|
||||||
})
|
})
|
||||||
|
|
|
@ -16,8 +16,7 @@ import (
|
||||||
|
|
||||||
var messageTimeCSS = primitives.PrepareClassCSS("", `
|
var messageTimeCSS = primitives.PrepareClassCSS("", `
|
||||||
.message-time {
|
.message-time {
|
||||||
margin-left: 1em;
|
margin: 0 8px;
|
||||||
margin-right: 1em;
|
|
||||||
}
|
}
|
||||||
`)
|
`)
|
||||||
|
|
||||||
|
@ -52,13 +51,18 @@ var _ container.MessageRow = (*Message)(nil)
|
||||||
func WrapMessage(ct *message.State) Message {
|
func WrapMessage(ct *message.State) Message {
|
||||||
ts := message.NewTimestamp()
|
ts := message.NewTimestamp()
|
||||||
ts.SetVAlign(gtk.ALIGN_START)
|
ts.SetVAlign(gtk.ALIGN_START)
|
||||||
|
ts.SetHAlign(gtk.ALIGN_END)
|
||||||
|
ts.SetXAlign(1.00)
|
||||||
ts.SetText(humanize.TimeAgo(ct.Time))
|
ts.SetText(humanize.TimeAgo(ct.Time))
|
||||||
ts.SetTooltipText(ct.Time.Format(time.Stamp))
|
ts.SetTooltipText(ct.Time.Format(time.Stamp))
|
||||||
ts.Show()
|
ts.Show()
|
||||||
messageTimeCSS(ts)
|
messageTimeCSS(ts)
|
||||||
|
|
||||||
user := message.NewUsername()
|
user := message.NewUsername()
|
||||||
user.SetMaxWidthChars(25)
|
user.SetMaxWidthChars(22)
|
||||||
|
user.SetHAlign(gtk.ALIGN_END)
|
||||||
|
user.SetXAlign(1.0)
|
||||||
|
user.SetJustify(gtk.JUSTIFY_RIGHT)
|
||||||
user.SetEllipsize(pango.ELLIPSIZE_NONE)
|
user.SetEllipsize(pango.ELLIPSIZE_NONE)
|
||||||
user.SetLineWrap(true)
|
user.SetLineWrap(true)
|
||||||
user.SetLineWrapMode(pango.WRAP_WORD_CHAR)
|
user.SetLineWrapMode(pango.WRAP_WORD_CHAR)
|
||||||
|
|
|
@ -10,10 +10,7 @@ import (
|
||||||
"github.com/diamondburned/cchat-gtk/internal/ui/primitives"
|
"github.com/diamondburned/cchat-gtk/internal/ui/primitives"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const AvatarSize = message.AvatarSize
|
||||||
AvatarSize = 40
|
|
||||||
AvatarMargin = 10
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewMessage creates a new message.
|
// NewMessage creates a new message.
|
||||||
func NewMessage(
|
func NewMessage(
|
||||||
|
@ -47,7 +44,7 @@ func NewContainer(ctrl container.Controller) *Container {
|
||||||
return &Container{ListContainer: c}
|
return &Container{ListContainer: c}
|
||||||
}
|
}
|
||||||
|
|
||||||
const splitDuration = 10 * time.Minute
|
const splitDuration = 3 * time.Minute
|
||||||
|
|
||||||
// isCollapsible returns true if the given lastMsg has matching conditions with
|
// isCollapsible returns true if the given lastMsg has matching conditions with
|
||||||
// the given msg.
|
// the given msg.
|
||||||
|
|
|
@ -3,7 +3,6 @@ package cozy
|
||||||
import (
|
import (
|
||||||
"github.com/diamondburned/cchat-gtk/internal/ui/messages/container"
|
"github.com/diamondburned/cchat-gtk/internal/ui/messages/container"
|
||||||
"github.com/diamondburned/cchat-gtk/internal/ui/messages/message"
|
"github.com/diamondburned/cchat-gtk/internal/ui/messages/message"
|
||||||
"github.com/gotk3/gotk3/gtk"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Collapsed is a message that follows after FullMessage. It does not show
|
// Collapsed is a message that follows after FullMessage. It does not show
|
||||||
|
@ -11,36 +10,26 @@ import (
|
||||||
type CollapsedMessage struct {
|
type CollapsedMessage struct {
|
||||||
// Author is still updated normally.
|
// Author is still updated normally.
|
||||||
*message.State
|
*message.State
|
||||||
Timestamp *gtk.Label
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WrapCollapsedMessage wraps the given message state to be a collapsed message.
|
// WrapCollapsedMessage wraps the given message state to be a collapsed message.
|
||||||
func WrapCollapsedMessage(gc *message.State) *CollapsedMessage {
|
func WrapCollapsedMessage(gc *message.State) *CollapsedMessage {
|
||||||
// Set Timestamp's padding accordingly to Avatar's.
|
|
||||||
ts := message.NewTimestamp()
|
|
||||||
ts.SetSizeRequest(AvatarSize, -1)
|
|
||||||
ts.SetVAlign(gtk.ALIGN_START)
|
|
||||||
ts.SetXAlign(0.5) // middle align
|
|
||||||
ts.SetMarginEnd(container.ColumnSpacing)
|
|
||||||
ts.SetMarginStart(container.ColumnSpacing * 2)
|
|
||||||
|
|
||||||
// Set Content's padding accordingly to FullMessage's main box.
|
// Set Content's padding accordingly to FullMessage's main box.
|
||||||
gc.Content.SetMarginEnd(container.ColumnSpacing * 2)
|
gc.Content.SetMarginStart(container.ColumnSpacing*2 + AvatarSize)
|
||||||
|
gc.Content.SetMarginEnd(container.ColumnSpacing)
|
||||||
|
|
||||||
gc.PackStart(ts, false, false, 0)
|
|
||||||
gc.PackStart(gc.Content, true, true, 0)
|
gc.PackStart(gc.Content, true, true, 0)
|
||||||
gc.SetClass("cozy-collapsed")
|
gc.SetClass("cozy-collapsed")
|
||||||
|
|
||||||
return &CollapsedMessage{
|
return &CollapsedMessage{
|
||||||
State: gc,
|
State: gc,
|
||||||
Timestamp: ts,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CollapsedMessage) Revert() *message.State {
|
func (c *CollapsedMessage) Revert() *message.State {
|
||||||
c.ClearBox()
|
c.ClearBox()
|
||||||
|
c.Content.SetMarginStart(0)
|
||||||
c.Content.SetMarginEnd(0)
|
c.Content.SetMarginEnd(0)
|
||||||
c.Timestamp.Destroy()
|
|
||||||
return c.Unwrap()
|
return c.Unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ func WrapFullMessage(gc *message.State) *FullMessage {
|
||||||
header.Show()
|
header.Show()
|
||||||
|
|
||||||
avatar := NewAvatar(gc.Row)
|
avatar := NewAvatar(gc.Row)
|
||||||
avatar.SetMarginStart(container.ColumnSpacing * 2)
|
avatar.SetMarginStart(container.ColumnSpacing)
|
||||||
avatar.Connect("clicked", func(w gtk.IWidget) {
|
avatar.Connect("clicked", func(w gtk.IWidget) {
|
||||||
if output := header.Output(); len(output.Mentions) > 0 {
|
if output := header.Output(); len(output.Mentions) > 0 {
|
||||||
labeluri.PopoverMentioner(w, output.Input, output.Mentions[0])
|
labeluri.PopoverMentioner(w, output.Input, output.Mentions[0])
|
||||||
|
@ -78,12 +78,10 @@ func WrapFullMessage(gc *message.State) *FullMessage {
|
||||||
main, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
|
main, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
|
||||||
main.PackStart(header, false, false, 0)
|
main.PackStart(header, false, false, 0)
|
||||||
main.PackStart(gc.Content, false, false, 0)
|
main.PackStart(gc.Content, false, false, 0)
|
||||||
main.SetMarginEnd(container.ColumnSpacing * 2)
|
main.SetMarginEnd(container.ColumnSpacing)
|
||||||
main.SetMarginStart(container.ColumnSpacing)
|
main.SetMarginStart(container.ColumnSpacing)
|
||||||
main.Show()
|
main.Show()
|
||||||
|
mainCSS(main)
|
||||||
// Also attach a class for the main box shown on the right.
|
|
||||||
primitives.AddClass(main, "cozy-main")
|
|
||||||
|
|
||||||
gc.PackStart(avatar, false, false, 0)
|
gc.PackStart(avatar, false, false, 0)
|
||||||
gc.PackStart(main, true, true, 0)
|
gc.PackStart(main, true, true, 0)
|
||||||
|
|
|
@ -479,6 +479,7 @@ func (c *ListStore) Highlight(msg MessageRow) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func destroyMsg(row *messageRow) {
|
func destroyMsg(row *messageRow) {
|
||||||
|
row.Revert()
|
||||||
row.state.Author.Name.Stop()
|
row.state.Author.Name.Stop()
|
||||||
row.state.Row.Destroy()
|
row.state.Row.Destroy()
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,14 +14,16 @@ import (
|
||||||
|
|
||||||
const AvatarSize = 24
|
const AvatarSize = 24
|
||||||
|
|
||||||
var showUser = true
|
var (
|
||||||
var currentRevealer = func(bool) {} // noop by default
|
showUser = true
|
||||||
|
updaters config.Updaters
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// Bind this revealer in settings.
|
// Bind this revealer in settings.
|
||||||
config.AppearanceAdd("Show Username in Input", config.Switch(
|
config.AppearanceAdd("Show Username in Input", config.Switch(
|
||||||
&showUser,
|
&showUser,
|
||||||
func(b bool) { currentRevealer(b) },
|
func(b bool) { updaters.Updated() },
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +57,7 @@ func NewContainer() *Container {
|
||||||
// Bind the current global revealer to this revealer for settings. This
|
// Bind the current global revealer to this revealer for settings. This
|
||||||
// operation should be thread-safe, as everything is being done in the main
|
// operation should be thread-safe, as everything is being done in the main
|
||||||
// thread.
|
// thread.
|
||||||
currentRevealer = rev.SetRevealChild
|
updaters.Add(func() { rev.SetRevealChild(showUser) })
|
||||||
|
|
||||||
author := message.NewCustomAuthor("", text.Plain("self"))
|
author := message.NewCustomAuthor("", text.Plain("self"))
|
||||||
|
|
||||||
|
@ -68,6 +70,7 @@ func NewContainer() *Container {
|
||||||
|
|
||||||
u.avatar = roundimage.NewImage(0)
|
u.avatar = roundimage.NewImage(0)
|
||||||
u.avatar.SetSize(AvatarSize)
|
u.avatar.SetSize(AvatarSize)
|
||||||
|
u.avatar.SetHAlign(gtk.ALIGN_CENTER)
|
||||||
u.avatar.SetPlaceholderIcon("user-available-symbolic", AvatarSize)
|
u.avatar.SetPlaceholderIcon("user-available-symbolic", AvatarSize)
|
||||||
u.avatar.Show()
|
u.avatar.Show()
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@ import (
|
||||||
"github.com/gotk3/gotk3/pango"
|
"github.com/gotk3/gotk3/pango"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const AvatarSize = 40
|
||||||
|
|
||||||
// Container describes a message container that wraps a state. These methods are
|
// Container describes a message container that wraps a state. These methods are
|
||||||
// made for containers to override; methods not meant to be override are not
|
// made for containers to override; methods not meant to be override are not
|
||||||
// exposed and will be done directly on the State.
|
// exposed and will be done directly on the State.
|
||||||
|
@ -70,6 +72,7 @@ func NewState(msg cchat.MessageCreate) *State {
|
||||||
// immediately afterwards; it is invalid once the state is used.
|
// immediately afterwards; it is invalid once the state is used.
|
||||||
func NewEmptyState() *State {
|
func NewEmptyState() *State {
|
||||||
ctbody := labeluri.NewLabel(text.Rich{})
|
ctbody := labeluri.NewLabel(text.Rich{})
|
||||||
|
ctbody.Tooltip = false
|
||||||
ctbody.SetHAlign(gtk.ALIGN_FILL)
|
ctbody.SetHAlign(gtk.ALIGN_FILL)
|
||||||
ctbody.SetEllipsize(pango.ELLIPSIZE_NONE)
|
ctbody.SetEllipsize(pango.ELLIPSIZE_NONE)
|
||||||
ctbody.SetLineWrap(true)
|
ctbody.SetLineWrap(true)
|
||||||
|
|
|
@ -24,6 +24,8 @@ func RenderSkipImages(rich text.Rich) markup.RenderOutput {
|
||||||
// need to manually
|
// need to manually
|
||||||
type Label struct {
|
type Label struct {
|
||||||
gtk.Label
|
gtk.Label
|
||||||
|
Tooltip bool
|
||||||
|
|
||||||
label text.Rich
|
label text.Rich
|
||||||
output markup.RenderOutput
|
output markup.RenderOutput
|
||||||
render LabelRenderer
|
render LabelRenderer
|
||||||
|
@ -41,7 +43,7 @@ func NewStaticLabel(rich text.Rich) *Label {
|
||||||
label.SetMarkup(markup.Render(rich))
|
label.SetMarkup(markup.Render(rich))
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Label{Label: *label}
|
return &Label{Label: *label, Tooltip: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLabel creates a self-updating label.
|
// NewLabel creates a self-updating label.
|
||||||
|
@ -83,7 +85,10 @@ func (l *Label) SetLabel(content text.Rich) {
|
||||||
|
|
||||||
l.output = out
|
l.output = out
|
||||||
l.SetMarkup(out.Markup)
|
l.SetMarkup(out.Markup)
|
||||||
l.SetTooltipMarkup(out.Markup)
|
|
||||||
|
if l.Tooltip {
|
||||||
|
l.SetTooltipMarkup(out.Markup)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetRenderer sets a custom renderer. If the given renderer is nil, then the
|
// SetRenderer sets a custom renderer. If the given renderer is nil, then the
|
||||||
|
|
|
@ -59,6 +59,7 @@ type ServerRow struct {
|
||||||
mentioned bool
|
mentioned bool
|
||||||
showLabel bool
|
showLabel bool
|
||||||
|
|
||||||
|
UnreadIndicator cchat.UnreadIndicator
|
||||||
// callback to cancel unread indicator
|
// callback to cancel unread indicator
|
||||||
cancelUnread func()
|
cancelUnread func()
|
||||||
}
|
}
|
||||||
|
@ -96,9 +97,10 @@ func NewHollowServer(p traverse.Breadcrumber, sv cchat.Server, ctrl ParentContro
|
||||||
serverRow.children.SetUnreadHandler(serverRow.SetUnreadUnsafe)
|
serverRow.children.SetUnreadHandler(serverRow.SetUnreadUnsafe)
|
||||||
|
|
||||||
case messenger != nil:
|
case messenger != nil:
|
||||||
if unreader := messenger.AsUnreadIndicator(); unreader != nil {
|
serverRow.UnreadIndicator = messenger.AsUnreadIndicator()
|
||||||
|
if serverRow.UnreadIndicator != nil {
|
||||||
gts.Async(func() (func(), error) {
|
gts.Async(func() (func(), error) {
|
||||||
c, err := unreader.UnreadIndicate(&serverRow)
|
c, err := serverRow.UnreadIndicator.UnreadIndicate(&serverRow)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "Failed to use unread indicator")
|
return nil, errors.Wrap(err, "Failed to use unread indicator")
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,8 +181,10 @@ func (s *Servers) setDone() {
|
||||||
s.SetVisibleChild(s.Main)
|
s.SetVisibleChild(s.Main)
|
||||||
|
|
||||||
// stop the spinner.
|
// stop the spinner.
|
||||||
s.spinner.Destroy()
|
if s.spinner != nil {
|
||||||
s.spinner = nil
|
s.spinner.Destroy()
|
||||||
|
s.spinner = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// setLoading shows a loading spinner. Use this after the session row is
|
// setLoading shows a loading spinner. Use this after the session row is
|
||||||
|
|
|
@ -20,7 +20,12 @@ undershoot { background-size: 0 }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.top-level .server-list.expanded {
|
.top-level .server-list.expanded {
|
||||||
background-color: @borders;
|
background-color: @theme_bg_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-level .server-list.expanded > .server-button,
|
||||||
|
.top-level .server-list.expanded > revealer > .server-children {
|
||||||
|
background-color: mix(alpha(@theme_selected_bg_color, 0.5), @borders, 0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-level .server-button {
|
.top-level .server-button {
|
||||||
|
|
Loading…
Reference in New Issue