mirror of
https://github.com/diamondburned/cchat-gtk.git
synced 2024-12-22 20:27:07 +00:00
Added type broadcasting; WIP unread indicator; minor fixes
This commit is contained in:
parent
4bb3726101
commit
4c173773bf
4
go.mod
4
go.mod
|
@ -7,8 +7,8 @@ replace github.com/gotk3/gotk3 => github.com/diamondburned/gotk3 v0.0.0-20200630
|
|||
require (
|
||||
github.com/Xuanwo/go-locale v0.2.0
|
||||
github.com/alecthomas/chroma v0.7.3
|
||||
github.com/diamondburned/cchat v0.0.43
|
||||
github.com/diamondburned/cchat-discord v0.0.0-20200717002543-508f355b9657
|
||||
github.com/diamondburned/cchat v0.0.45
|
||||
github.com/diamondburned/cchat-discord v0.0.0-20200717063909-2f4cb5f246c4
|
||||
github.com/diamondburned/cchat-mock v0.0.0-20200709231652-ad222ce5a74b
|
||||
github.com/diamondburned/imgutil v0.0.0-20200710174014-8a3be144a972
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
|
|
14
go.sum
14
go.sum
|
@ -44,20 +44,22 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/diamondburned/aqs v0.0.0-20200704043812-99b676ee44eb h1:Ja/niwykeFoSkYxdRRzM8QUAuCswfLmaiBTd2UIU+54=
|
||||
github.com/diamondburned/aqs v0.0.0-20200704043812-99b676ee44eb/go.mod h1:q1MbMBfZrv7xqV8n7LgMwhHs3oBbNwWJes8exs2AmDs=
|
||||
github.com/diamondburned/arikawa v0.10.5 h1:o5lBopooA+8cXlKZdct5qF0xztuZZ35phvQrwGS5vYM=
|
||||
github.com/diamondburned/arikawa v0.10.5/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660=
|
||||
github.com/diamondburned/arikawa v0.12.4 h1:lhWJqcGkIIMiOYWdsoEuGlri2UbMkzMeh+VfuJPkXt4=
|
||||
github.com/diamondburned/arikawa v0.12.4/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660=
|
||||
github.com/diamondburned/cchat v0.0.43 h1:HetAujSaUSdnQgAUZgprNLARjf/MSWXpCfWdvX2wOCU=
|
||||
github.com/diamondburned/cchat v0.0.43/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
|
||||
github.com/diamondburned/cchat-discord v0.0.0-20200717002543-508f355b9657 h1:/ZwVENnNKBioK34qA4sr/2B0pcJbDpPyw6DpiI3Cjr0=
|
||||
github.com/diamondburned/cchat-discord v0.0.0-20200717002543-508f355b9657/go.mod h1:cX6rGfvIv2rfNPrhfcRx88bfNxyL7eFmiYZLCWGfchw=
|
||||
github.com/diamondburned/cchat v0.0.45 h1:HMVSKx1h6lh2OenWaBTvMSK531hWaXAW7I0tKZepYug=
|
||||
github.com/diamondburned/cchat v0.0.45/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
|
||||
github.com/diamondburned/cchat-discord v0.0.0-20200717063909-2f4cb5f246c4 h1:otasqokx6kIGo9KnJt1F22MdCyUIvZmxZkLv+kcdKiI=
|
||||
github.com/diamondburned/cchat-discord v0.0.0-20200717063909-2f4cb5f246c4/go.mod h1:Z0uWBUaheEtozKj4NMgsSK4X5a3Du5tYakDb5plEluY=
|
||||
github.com/diamondburned/cchat-mock v0.0.0-20200709231652-ad222ce5a74b h1:sq0MXjJc3yAOZvuolRxOpKQNvpMLyTmsECxQqdYgF5E=
|
||||
github.com/diamondburned/cchat-mock v0.0.0-20200709231652-ad222ce5a74b/go.mod h1:+bAf0m2o5qH54DmYJ/lR1HeITV53ol0JaoKyFFx3m3E=
|
||||
github.com/diamondburned/gotk3 v0.0.0-20200630065217-97aeb06d705d h1:Ha/I6PMKi+B4hpWclwlXj0tUMehR7Q0TNxPczzBwzPI=
|
||||
github.com/diamondburned/gotk3 v0.0.0-20200630065217-97aeb06d705d/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q=
|
||||
github.com/diamondburned/imgutil v0.0.0-20200710174014-8a3be144a972 h1:OWxllHbUptXzDias6YI4MM0R3o50q8MfhkkwVIlfiNo=
|
||||
github.com/diamondburned/imgutil v0.0.0-20200710174014-8a3be144a972/go.mod h1:kBQKaukR/LyCfhED99/T4/XxUMDNEEzf1Fx6vreD3RQ=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200715040340-2395a0dbd0fa h1:ntHcz6GNzxn3TovtYZVwOBvL3xn7Iq1luaV/KEIEXrk=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200715040340-2395a0dbd0fa/go.mod h1:SKPY3387RHCbMrnefex9D+zlrA2yB+LCtaaQAgatAuc=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200717013108-297a3bdf84dc h1:YZ84Kdlv91tdcyLfGfQ+LG9kWZN8dTKIic0KlEtGV0U=
|
||||
github.com/diamondburned/ningen v0.1.1-0.20200717013108-297a3bdf84dc/go.mod h1:Sunqp1b9Tc0+DtWKslhf83Zepgj/TELB6h8J9HZCPqQ=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package input
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/diamondburned/cchat"
|
||||
"github.com/diamondburned/cchat-gtk/internal/gts"
|
||||
"github.com/diamondburned/cchat-gtk/internal/log"
|
||||
|
@ -96,12 +98,14 @@ type Field struct {
|
|||
UserID string
|
||||
Sender cchat.ServerMessageSender
|
||||
editor cchat.ServerMessageEditor
|
||||
typer cchat.ServerMessageTypingIndicator
|
||||
|
||||
ctrl Controller
|
||||
|
||||
// states
|
||||
editingID string // never empty
|
||||
sendings []PresendMessage
|
||||
lastTyped time.Time
|
||||
typerDura time.Duration
|
||||
}
|
||||
|
||||
var inputFieldCSS = primitives.PrepareCSS(`
|
||||
|
@ -178,6 +182,10 @@ func (f *Field) Reset() {
|
|||
f.UserID = ""
|
||||
f.Sender = nil
|
||||
f.editor = nil
|
||||
f.typer = nil
|
||||
f.lastTyped = time.Time{}
|
||||
f.typerDura = 0
|
||||
|
||||
f.Username.Reset()
|
||||
|
||||
// reset the input
|
||||
|
@ -197,11 +205,14 @@ func (f *Field) SetSender(session cchat.Session, sender cchat.ServerMessageSende
|
|||
f.text.SetSensitive(true)
|
||||
|
||||
// Allow editor to be nil.
|
||||
ed, ok := sender.(cchat.ServerMessageEditor)
|
||||
if !ok {
|
||||
log.Printlnf("Editor is not implemented for %T", sender)
|
||||
f.editor, _ = sender.(cchat.ServerMessageEditor)
|
||||
// Allow typer to be nil.
|
||||
f.typer, _ = sender.(cchat.ServerMessageTypingIndicator)
|
||||
|
||||
// Populate the duration state if typer is not nil.
|
||||
if f.typer != nil {
|
||||
f.typerDura = f.typer.TypingTimeout()
|
||||
}
|
||||
f.editor = ed
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package input
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/diamondburned/cchat-gtk/internal/gts"
|
||||
"github.com/diamondburned/cchat-gtk/internal/log"
|
||||
"github.com/gotk3/gotk3/gdk"
|
||||
|
@ -95,6 +97,23 @@ func (f *Field) keyDown(tv *gtk.TextView, ev *gdk.Event) bool {
|
|||
}
|
||||
}
|
||||
|
||||
// If the server supports typing indication, then announce that we are
|
||||
// typing with a proper rate limit.
|
||||
if f.typer != nil {
|
||||
// Get the current time; if the next timestamp is before now, then that
|
||||
// means it's time for us to update it and send a typing indication.
|
||||
if now := time.Now(); f.lastTyped.Add(f.typerDura).Before(now) {
|
||||
// Update.
|
||||
f.lastTyped = now
|
||||
// Send asynchronously.
|
||||
go func() {
|
||||
if err := f.typer.Typing(); err != nil {
|
||||
log.Error(errors.Wrap(err, "Failed to announce typing"))
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
// Passthrough.
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -64,6 +64,19 @@ func RemoveClass(styleCtx StyleContexter, classes ...string) {
|
|||
}
|
||||
}
|
||||
|
||||
type ClassEnum struct{ class string }
|
||||
|
||||
func (c *ClassEnum) SetClass(ctx StyleContexter, class string) {
|
||||
var style, _ = ctx.GetStyleContext()
|
||||
if c.class != "" {
|
||||
style.RemoveClass(c.class)
|
||||
}
|
||||
|
||||
if c.class = class; class != "" {
|
||||
style.AddClass(class)
|
||||
}
|
||||
}
|
||||
|
||||
type StyleContextFocuser interface {
|
||||
StyleContexter
|
||||
GrabFocus()
|
||||
|
|
|
@ -39,7 +39,7 @@ func (a *AppendMap) Anchor(start, end int, href string) {
|
|||
a.Close(end, "</a>")
|
||||
}
|
||||
|
||||
// AnchorNU makes a new <a> tag without underlines.
|
||||
// AnchorNU makes a new <a> tag without underlines and colors.
|
||||
func (a *AppendMap) AnchorNU(start, end int, href string) {
|
||||
a.Anchor(start, end, href)
|
||||
a.Span(start, end, `underline="none"`)
|
||||
|
|
|
@ -3,8 +3,9 @@ package button
|
|||
import (
|
||||
"github.com/diamondburned/cchat"
|
||||
"github.com/diamondburned/cchat-gtk/internal/gts"
|
||||
"github.com/diamondburned/cchat-gtk/internal/ui/rich"
|
||||
"github.com/diamondburned/cchat-gtk/internal/ui/primitives"
|
||||
"github.com/diamondburned/cchat-gtk/internal/ui/primitives/menu"
|
||||
"github.com/diamondburned/cchat-gtk/internal/ui/rich"
|
||||
"github.com/diamondburned/cchat/text"
|
||||
)
|
||||
|
||||
|
@ -15,6 +16,7 @@ type ToggleButtonImage struct {
|
|||
menu *menu.LazyMenu
|
||||
|
||||
clicked func(bool)
|
||||
readcss primitives.ClassEnum
|
||||
|
||||
err error
|
||||
icon string // whether or not the button has an icon
|
||||
|
@ -23,6 +25,12 @@ type ToggleButtonImage struct {
|
|||
|
||||
var _ cchat.IconContainer = (*ToggleButtonImage)(nil)
|
||||
|
||||
var serverButtonCSS = primitives.PrepareCSS(`
|
||||
.read { color: alpha(@theme_fg_color, 0.5) }
|
||||
.unread { color: @theme_fg_color }
|
||||
.mentioned { color: red }
|
||||
`)
|
||||
|
||||
func NewToggleButtonImage(content text.Rich) *ToggleButtonImage {
|
||||
b := rich.NewToggleButtonImage(content)
|
||||
b.Show()
|
||||
|
@ -33,10 +41,8 @@ func NewToggleButtonImage(content text.Rich) *ToggleButtonImage {
|
|||
clicked: func(bool) {},
|
||||
menu: menu.NewLazyMenu(b.ToggleButton),
|
||||
}
|
||||
|
||||
tb.Connect("clicked", func() {
|
||||
tb.clicked(tb.GetActive())
|
||||
})
|
||||
tb.Connect("clicked", func() { tb.clicked(tb.GetActive()) })
|
||||
primitives.AttachCSS(tb, serverButtonCSS)
|
||||
|
||||
return tb
|
||||
}
|
||||
|
@ -92,6 +98,17 @@ func (b *ToggleButtonImage) SetFailed(err error, retry func()) {
|
|||
}
|
||||
}
|
||||
|
||||
func (b *ToggleButtonImage) SetUnreadUnsafe(unread, mentioned bool) {
|
||||
switch {
|
||||
case unread:
|
||||
b.readcss.SetClass(b, "unread")
|
||||
case mentioned:
|
||||
b.readcss.SetClass(b, "mentioned")
|
||||
default:
|
||||
b.readcss.SetClass(b, "read")
|
||||
}
|
||||
}
|
||||
|
||||
func (b *ToggleButtonImage) SetPlaceholderIcon(iconName string, iconSzPx int) {
|
||||
b.icon = iconName
|
||||
b.Image.SetPlaceholderIcon(iconName, iconSzPx)
|
|
@ -7,7 +7,7 @@ import (
|
|||
"github.com/diamondburned/cchat-gtk/internal/ui/primitives/menu"
|
||||
"github.com/diamondburned/cchat-gtk/internal/ui/rich"
|
||||
"github.com/diamondburned/cchat-gtk/internal/ui/service/breadcrumb"
|
||||
"github.com/diamondburned/cchat-gtk/internal/ui/service/button"
|
||||
"github.com/diamondburned/cchat-gtk/internal/ui/service/session/server/button"
|
||||
"github.com/diamondburned/cchat/text"
|
||||
"github.com/gotk3/gotk3/gtk"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -45,6 +45,21 @@ func NewServerRow(p breadcrumb.Breadcrumber, server cchat.Server, ctrl Controlle
|
|||
case cchat.ServerMessage:
|
||||
row.Button.SetClickedIfTrue(func() { ctrl.RowSelected(serverRow, server) })
|
||||
primitives.AddClass(row, "server-message")
|
||||
|
||||
// Check if the server is capable of indicating unread state.
|
||||
if unreader, ok := server.(cchat.ServerMessageUnreadIndicator); ok {
|
||||
// Set as read by default.
|
||||
row.Button.SetUnreadUnsafe(false, false)
|
||||
|
||||
gts.Async(func() (func(), error) {
|
||||
c, err := unreader.UnreadIndicate(row)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to use unread indicator")
|
||||
}
|
||||
|
||||
return func() { row.Connect("destroy", c) }, nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return serverRow
|
||||
|
@ -208,6 +223,15 @@ func (r *Row) SetRevealChild(reveal bool) {
|
|||
}
|
||||
}
|
||||
|
||||
// GetRevealChild returns whether or not the server list is expanded, or always
|
||||
// false if there is no server list.
|
||||
func (r *Row) GetRevealChild() bool {
|
||||
if r.childrev != nil {
|
||||
return r.childrev.GetRevealChild()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Load loads the row without uncollapsing it.
|
||||
func (r *Row) Load() {
|
||||
// Safeguard.
|
||||
|
@ -239,11 +263,11 @@ func (r *Row) Load() {
|
|||
}()
|
||||
}
|
||||
|
||||
// GetRevealChild returns whether or not the server list is expanded, or always
|
||||
// false if there is no server list.
|
||||
func (r *Row) GetRevealChild() bool {
|
||||
if r.childrev != nil {
|
||||
return r.childrev.GetRevealChild()
|
||||
}
|
||||
return false
|
||||
// SetUnread is thread-safe.
|
||||
func (r *Row) SetUnread(unread, mentioned bool) {
|
||||
gts.ExecAsync(func() { r.SetUnreadUnsafe(unread, mentioned) })
|
||||
}
|
||||
|
||||
func (r *Row) SetUnreadUnsafe(unread, mentioned bool) {
|
||||
r.Button.SetUnreadUnsafe(unread, mentioned)
|
||||
}
|
||||
|
|
|
@ -62,12 +62,8 @@ type Row struct {
|
|||
|
||||
ActionsMenu *actions.Menu // session.*
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue