Skip to content

Commit

Permalink
Add notifications; UI tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
diamondburned committed Apr 14, 2022
1 parent 784dcd4 commit e7c89f1
Show file tree
Hide file tree
Showing 15 changed files with 355 additions and 75 deletions.
12 changes: 8 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ module github.com/diamondburned/gtkcord4

go 1.17

// replace github.com/diamondburned/ningen/v3 => ../../ningen
// replace github.com/diamondburned/arikawa/v3 => ../../arikawa
// replace github.com/diamondburned/gotkit => ../gotkit

require (
github.com/diamondburned/adaptive v0.0.2-0.20220328111603-4f867d7948b2
github.com/diamondburned/arikawa/v3 v3.0.0-rc.6.0.20220408124721-4108d10b444c
github.com/diamondburned/chatkit v0.0.0-20220410003350-362494224d02
github.com/diamondburned/arikawa/v3 v3.0.0-rc.6.0.20220412174302-bd0369136f51
github.com/diamondburned/chatkit v0.0.0-20220412205050-65f5794df56f
github.com/diamondburned/gotk4/pkg v0.0.0-20220408070453-08962439fbbc
github.com/diamondburned/gotkit v0.0.0-20220411012151-ec16933b1564
github.com/diamondburned/ningen/v3 v3.0.0-20220411010635-498c8aa4f724
github.com/diamondburned/gotkit v0.0.0-20220411230819-e3907853ff4e
github.com/diamondburned/ningen/v3 v3.0.0-20220412001139-82f55294365b
)

require (
Expand Down
13 changes: 4 additions & 9 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,14 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/diamondburned/adaptive v0.0.2-0.20220226002257-ef8720b54399/go.mod h1:cLoCdQtpCp/TSJBJTgXe7W2FJNelXrmPv+X7luB6/Qg=
github.com/diamondburned/adaptive v0.0.2-0.20220328111603-4f867d7948b2 h1:xMYuLPsjREtnGwJJik1BiNy28cU7QhGfp5rNbneBmdU=
github.com/diamondburned/adaptive v0.0.2-0.20220328111603-4f867d7948b2/go.mod h1:cLoCdQtpCp/TSJBJTgXe7W2FJNelXrmPv+X7luB6/Qg=
github.com/diamondburned/arikawa/v3 v3.0.0-rc.6/go.mod h1:5jBSNnp82Z/EhsKa6Wk9FsOqSxfVkNZDTDBPOj47LpY=
github.com/diamondburned/arikawa/v3 v3.0.0-rc.6.0.20220408124721-4108d10b444c h1:c1Lhm8o6jmW6wpA7/9eNFKGvdvenNBToX+Pxpt9IAtc=
github.com/diamondburned/arikawa/v3 v3.0.0-rc.6.0.20220408124721-4108d10b444c/go.mod h1:5jBSNnp82Z/EhsKa6Wk9FsOqSxfVkNZDTDBPOj47LpY=
github.com/diamondburned/chatkit v0.0.0-20220410003350-362494224d02 h1:IczxKyNUM+qZCmyQVpaBO4oBO24xH7+uBubjUeepVv4=
github.com/diamondburned/chatkit v0.0.0-20220410003350-362494224d02/go.mod h1:QkyQFOy/ndA6XUgVm5Jw8Xu9BKjDw2GE8Zj+octTKF8=
github.com/diamondburned/chatkit v0.0.0-20220412205050-65f5794df56f h1:aAUMQYa21PZqkfCitj66TZH9p0v9X+T9hEebDVJY1P0=
github.com/diamondburned/chatkit v0.0.0-20220412205050-65f5794df56f/go.mod h1:QkyQFOy/ndA6XUgVm5Jw8Xu9BKjDw2GE8Zj+octTKF8=
github.com/diamondburned/gotk4/pkg v0.0.0-20220225135826-2bb7260a63bb/go.mod h1:dJ2gfR0gvBsGg4IteP8aMBq/U5Q9boDw0DP7kAjXTwM=
github.com/diamondburned/gotk4/pkg v0.0.0-20220408070453-08962439fbbc h1:BkDOBlc7okNAJL5KYPXD7ZB4pB3x23XeCh79wmVC5x8=
github.com/diamondburned/gotk4/pkg v0.0.0-20220408070453-08962439fbbc/go.mod h1:rLH6FHos690jFgAM/GYEpMykuE/9NmN6zOvFlr8JTvE=
github.com/diamondburned/gotkit v0.0.0-20220409081802-93f160de50f1/go.mod h1:TXAbYeGcMkR6RLo9ZlCR6W1lvD9ZhxA8iSS3KYEes3Q=
github.com/diamondburned/gotkit v0.0.0-20220411012151-ec16933b1564 h1:I8X4y8FBR+rjL9Y3nXX7n2Pe8+wq/Mz9WJ5Gs2BMO1o=
github.com/diamondburned/gotkit v0.0.0-20220411012151-ec16933b1564/go.mod h1:TXAbYeGcMkR6RLo9ZlCR6W1lvD9ZhxA8iSS3KYEes3Q=
github.com/diamondburned/ningen/v3 v3.0.0-20220411010635-498c8aa4f724 h1:5aDwei68fV5SUInrkhGBbadVGZYAZxrXMCOAo/KUk6k=
github.com/diamondburned/ningen/v3 v3.0.0-20220411010635-498c8aa4f724/go.mod h1:WLSUx3megnWk5I6rYLE+yPHN3iPJf4Nag2B5Y7l+Vmc=
github.com/diamondburned/gotkit v0.0.0-20220411230819-e3907853ff4e h1:TU7AzL0fGTgsnyfR72Qt27+AyQXI3K7pjlaoraljDTg=
github.com/diamondburned/gotkit v0.0.0-20220411230819-e3907853ff4e/go.mod h1:TXAbYeGcMkR6RLo9ZlCR6W1lvD9ZhxA8iSS3KYEes3Q=
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
Expand Down
12 changes: 12 additions & 0 deletions internal/gtkcord/dbus.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package gtkcord

import "github.com/diamondburned/arikawa/v3/discord"

// IPC commands go here.

// OpenChannelCommand is the data type for a command sent over DBus to open a
// message channel. Its action ID is app.open-channel.
type OpenChannelCommand struct {
ChannelID discord.ChannelID
MessageID discord.MessageID // optional, used to highlight message
}
27 changes: 9 additions & 18 deletions internal/gtkcord/message/content.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@ package message

import (
"context"
"strings"

"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/chatkit/components/author"
"github.com/diamondburned/chatkit/md"
"github.com/diamondburned/chatkit/md/block"
"github.com/diamondburned/chatkit/md/mdrender"
"github.com/diamondburned/gotk4/pkg/gio/v2"
"github.com/diamondburned/gotk4/pkg/gtk/v4"
"github.com/diamondburned/gotk4/pkg/pango"
"github.com/diamondburned/gotkit/components/onlineimage"
"github.com/diamondburned/gotkit/gtkutil"
"github.com/diamondburned/gotkit/gtkutil/cssutil"
"github.com/diamondburned/gotkit/gtkutil/imgutil"
"github.com/diamondburned/gotkit/gtkutil/textutil"
Expand Down Expand Up @@ -68,13 +67,10 @@ func (c *Content) SetExtraMenu(menu gio.MenuModeller) {
}

func (c *Content) setMenu() {
// TODO: this doesn't cover embeds. Maybe just walking the widget tree is a
// far better choice.
state := c.view.State()
state.Walk(func(w block.WidgetBlock) bool {
if text, ok := w.(block.TextBlock); ok {
text := text.TextBlock()
text.SetExtraMenu(c.menu)
gtkutil.WalkWidget(c, func(w gtk.Widgetter) bool {
s, ok := w.(interface{ SetExtraWidget(gio.MenuModeller) })
if ok {
s.SetExtraWidget(c.menu)
}
return false
})
Expand Down Expand Up @@ -112,17 +108,12 @@ func (c *Content) Update(m *discord.Message, customs ...gtk.Widgetter) {
chip.Unpad()
topBox.Append(chip)

b := strings.Builder{}
s := []byte(msg.Content)
n := discordmd.ParseWithMessage(s, *state.Cabinet, msg, true)
discordmd.DefaultRenderer.Render(&b, s, n)

reply := gtk.NewLabel("")
reply.AddCSSClass("message-reply-content")
reply.SetEllipsize(pango.EllipsizeEnd)
reply.SetXAlign(0)
reply.SetSingleLineMode(true)
reply.SetText(b.String())
reply.SetText(state.MessagePreview(msg))

replyBox.Append(reply)
}
Expand All @@ -137,9 +128,6 @@ func (c *Content) Update(m *discord.Message, customs ...gtk.Widgetter) {

c.append(v)

c.view = v
c.setMenu()

for i := range m.Attachments {
v := newAttachment(c.ctx, &m.Attachments[i])
c.append(v)
Expand All @@ -153,6 +141,9 @@ func (c *Content) Update(m *discord.Message, customs ...gtk.Widgetter) {
for _, custom := range customs {
c.append(custom)
}

c.view = v
c.setMenu()
}

func (c *Content) append(w gtk.Widgetter) {
Expand Down
20 changes: 17 additions & 3 deletions internal/gtkcord/message/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,10 +251,19 @@ func NewView(ctx context.Context, chID discord.ChannelID) *View {
return v
}

// GuildID returns the guild ID of the channel that the message view is
// displaying for.
func (v *View) GuildID() discord.GuildID {
return v.guildID
}

// ChannelID returns the channel ID of the message view.
func (v *View) ChannelID() discord.ChannelID {
return v.chID
}

// ChannelName returns the name of the channel that the message view is
// displaying for.
func (v *View) ChannelName() string {
return v.chName
}
Expand Down Expand Up @@ -586,11 +595,9 @@ func (v *View) Delete(id discord.MessageID) {
}

func (v *View) onScrollBottomed() {
win := app.GTKWindowFromContext(v.ctx.Take())
if !win.IsActive() {
if !v.IsActive() {
return
}

v.MarkRead()
}

Expand All @@ -606,3 +613,10 @@ func (v *View) MarkRead() {
state := gtkcord.FromContext(v.ctx.Take())
state.ReadState.MarkRead(v.chID, msg.ID)
}

// IsActive returns true if View is active and visible. This implies that the
// window is focused.
func (v *View) IsActive() bool {
win := app.GTKWindowFromContext(v.ctx.Take())
return win.IsActive() && v.Mapped()
}
36 changes: 35 additions & 1 deletion internal/gtkcord/sidebar/channels/channels.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ type View struct {
tree *GuildTree
cols []*gtk.TreeViewColumn

guildID discord.GuildID
guildID discord.GuildID
selectID discord.ChannelID // delegate to select later
}

var viewCSS = cssutil.Applier("channels-view", `
Expand Down Expand Up @@ -291,6 +292,22 @@ func NewView(ctx context.Context, ctrl Controller, guildID discord.GuildID) *Vie
return &v
}

// SelectChannel selects a known channel. If none is known, then it is selected
// later when the list is changed or never selected if the user selects
// something else.
func (v *View) SelectChannel(chID discord.ChannelID) {
if v.tree != nil {
node := v.tree.Node(chID)
if node != nil {
selection := v.Child.Tree.Selection()
selection.SelectPath(node.TreePath())
return
}
}

v.selectID = chID
}

// GuildID returns the view's guild ID.
func (v *View) GuildID() discord.GuildID {
return v.guildID
Expand Down Expand Up @@ -327,7 +344,24 @@ func (v *View) InvalidateChannels() {
}

v.tree = NewGuildTree(v.ctx.Take())
v.tree.ConnectRowInserted(func(path *gtk.TreePath, iter *gtk.TreeIter) {
if v.selectID.IsValid() {
node := v.tree.NodeFromPath(path)
if node == nil {
return
}

if node.ID() == v.selectID {
// Found the channel that we want to select.
selection := v.Child.Tree.Selection()
selection.SelectPath(path)

v.selectID = 0
}
}
})
v.tree.Add(chs)

v.Child.Tree.SetModel(v.tree)
v.setDone()

Expand Down
6 changes: 6 additions & 0 deletions internal/gtkcord/sidebar/channels/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,12 @@ func (t *GuildTree) state() *gtkcord.State {
return gtkcord.FromContext(t.ctx)
}

// NodeFromPath quickly looks up the channel tree for a node from the given tree
// path.
func (t *GuildTree) NodeFromPath(path *gtk.TreePath) Node {
return t.paths[path.String()]
}

// Has returns true if the guild tree has the given channel.
func (t *GuildTree) Has(id discord.ChannelID) bool {
_, ok := t.nodes[id]
Expand Down
36 changes: 33 additions & 3 deletions internal/gtkcord/sidebar/direct/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type ChannelView struct {

ctx context.Context
channels map[discord.ChannelID]*Channel
selectID discord.ChannelID // delegate to be selected later
}

// Controller is the parent controller that ChannelView controls.
Expand All @@ -53,8 +54,11 @@ func NewChannelView(ctx context.Context, ctrl Controller) *ChannelView {
v.list.SetHExpand(true)
v.list.SetSortFunc(v.sort)
v.list.SetFilterFunc(v.filter)
v.list.SetActivateOnSingleClick(true)
v.list.ConnectRowActivated(func(r *gtk.ListBoxRow) {
v.list.SetSelectionMode(gtk.SelectionBrowse)
v.list.ConnectRowSelected(func(r *gtk.ListBoxRow) {
// Invalidate our selection state.
v.selectID = 0

ch := v.rowChannel(r)
ctrl.OpenChannel(ch.id)
})
Expand Down Expand Up @@ -96,6 +100,10 @@ func NewChannelView(ctx context.Context, ctrl Controller) *ChannelView {
// TODO: Channel events

switch ev := ev.(type) {
case *gateway.ChannelCreateEvent:
if !ev.GuildID.IsValid() {
v.Invalidate() // recreate everything
}
case *gateway.ChannelDeleteEvent:
v.deleteCh(ev.ID)
case *gateway.MessageCreateEvent:
Expand All @@ -110,6 +118,19 @@ func NewChannelView(ctx context.Context, ctrl Controller) *ChannelView {
return &v
}

// SelectChannel selects a known channel. If none is known, then it is selected
// later when the list is changed or never selected if the user selects
// something else.
func (v *ChannelView) SelectChannel(chID discord.ChannelID) {
ch, ok := v.channels[chID]
if !ok {
v.selectID = chID
return
}

v.list.SelectRow(ch.ListBoxRow)
}

// Invalidate invalidates the whole channel view.
func (v *ChannelView) Invalidate() {
v.SetLoading()
Expand Down Expand Up @@ -141,10 +162,11 @@ func (v *ChannelView) Invalidate() {
ch.Update(&chs[i])

v.channels[channel.ID] = ch
v.list.Append(ch)

if _, ok := keep[channel.ID]; ok {
keep[channel.ID] = true
} else {
v.list.Append(ch)
}
}

Expand All @@ -156,6 +178,14 @@ func (v *ChannelView) Invalidate() {
}

v.SetChild(v.box)

// If we have a channel to be selectedd, then select it.
if v.selectID.IsValid() {
if ch, ok := v.channels[v.selectID]; ok {
v.list.SelectRow(ch.ListBoxRow)
v.selectID = 0
}
}
}

func (v *ChannelView) deleteCh(id discord.ChannelID) {
Expand Down
36 changes: 23 additions & 13 deletions internal/gtkcord/sidebar/guilds/guilds.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,28 @@ func (v *View) Guild(id discord.GuildID) *Guild {
return nil
}

// SelectGuild selects the guild with the given ID. If the guild is not known,
// then the sidebar's guild view is closed.
func (v *View) SelectGuild(id discord.GuildID) {
guild := (*View)(v).Guild(id)
if guild == nil {
v.ctrl.CloseGuild(true)
return
}

current := currentGuild{
guild: guild,
folder: guild.ParentFolder(),
}

if current != v.current {
(*View)(v).Unselect()
v.current = current
}

v.ctrl.OpenGuild(id)
}

// Unselect unselects any guilds inside this guild view. Use this when the
// window is showing a channel that's not from any guild.
func (v *View) Unselect() {
Expand All @@ -263,17 +285,5 @@ func (v *View) Unselect() {
type guildOpenerView View

func (v *guildOpenerView) OpenGuild(id discord.GuildID) {
guild := (*View)(v).Guild(id)

current := currentGuild{
guild: guild,
folder: guild.ParentFolder(),
}

if current != v.current {
(*View)(v).Unselect()
v.current = current
}

v.ctrl.OpenGuild(id)
(*View)(v).SelectGuild(id)
}
Loading

0 comments on commit e7c89f1

Please sign in to comment.