diff --git a/channels.go b/channels.go index 8f8a524..f03cc27 100644 --- a/channels.go +++ b/channels.go @@ -1,7 +1,7 @@ package main import ( - "strconv" + "time" "fyne.io/fyne" "fyne.io/fyne/canvas" @@ -9,18 +9,45 @@ import ( ) func (client *GUI) renderChannelList() fyne.CanvasObject { - right := widget.NewVBox() + var hideEmptyChannels = true + + client.channelPane = widget.NewVBox() for _, channel := range client.db.Channels { - row := widget.NewHBox() - numOfMessages := strconv.Itoa(len(client.db.chanList[channel.IdentHash])) - test := canvas.NewImageFromImage(client.db.getAvatar(channel.IdentHash)) - test.SetMinSize(fyne.NewSize(32, 32)) - test.FillMode = canvas.ImageFillContain - row.Append(test) - row.Append(widget.NewLabel(channel.Name + " " + shortIdent(channel.IdentHash) + " " + numOfMessages + "/" + numOfMessages)) - right.Append(row) + if hideEmptyChannels { + if len(client.db.chanList[channel.IdentHash]) == 0 { + continue + } + } + rw := new(ChannelWidget) + rw.Name = channel.Name + rw.Text = widget.NewLabel(channel.IdentHash) + rw.Icon = canvas.NewImageFromImage(client.db.getAvatar(channel.IdentHash)) + + rw.SelectedChannel = make(chan string) + go func() { + for contact := range rw.SelectedChannel { + client.selectedChannel = contact + close(rw.SelectedChannel) + client.repaint() + } + }() + client.channelPane.Append(rw) } - return right + return client.channelPane +} + +func (client *GUI) renderThreadList() fyne.CanvasObject { + client.threadPane = widget.NewVBox() + if client.selectedChannel == "" { + client.threadPane.Append(widget.NewLabel("Select a channel from the menu to the left to get started")) + } else { + for _, msg := range client.db.chanList[client.selectedChannel] { + client.threadPane.Append(widget.NewLabel(msg.Subject)) + date := time.Unix(0, int64(msg.ID)*int64(time.Millisecond)) + client.threadPane.Append(widget.NewLabel("by " + client.db.nameFromChanIdentHash(msg.Author) + " " + shortIdent(msg.Author) + " on " + date.Format("2006-01-02"))) + } + } + return client.threadPane } func shortIdent(i string) string { diff --git a/database.go b/database.go index 4a062c9..4dd6b9f 100644 --- a/database.go +++ b/database.go @@ -85,3 +85,15 @@ func (db *database) getAvatar(identhash string) image.Image { } return *db.avatars["empty"] } + +func (db *database) nameFromChanIdentHash(s string) string { + for _, channel := range db.Channels { + if channel.IdentHash == s { + if s == "" { + return "Anonymous" + } + return channel.Name + } + } + return "Unknown" +} diff --git a/gui.go b/gui.go index 41956a8..b13d124 100644 --- a/gui.go +++ b/gui.go @@ -1,12 +1,23 @@ package main import ( + "fyne.io/fyne" "fyne.io/fyne/app" + "fyne.io/fyne/layout" "fyne.io/fyne/widget" ) type GUI struct { - db *database + db *database + window fyne.Window + + channelPane *widget.Box + threadPane *widget.Box + channelList *widget.ScrollContainer + messageList *widget.ScrollContainer + contentArea *widget.Label + selectedChannel string + selectedMessage string } func NewGUI() *GUI { @@ -22,8 +33,15 @@ func (client *GUI) Start(path string) { a := app.New() - w := a.NewWindow("Syndie GUI") - rightSideBar := widget.NewVScrollContainer(client.renderChannelList()) - w.SetContent(rightSideBar) - w.ShowAndRun() + client.window = a.NewWindow("Syndie GUI") + client.contentArea = widget.NewLabel("This is where the message content goes") + + client.repaint() + client.window.ShowAndRun() +} + +func (client *GUI) repaint() { + client.channelList = widget.NewVScrollContainer(client.renderChannelList()) + client.messageList = widget.NewVScrollContainer(client.renderThreadList()) + client.window.SetContent(fyne.NewContainerWithLayout(layout.NewGridLayout(2), widget.NewHSplitContainer(client.channelList, client.messageList), client.contentArea)) } diff --git a/widgets.go b/widgets.go new file mode 100644 index 0000000..f7302cf --- /dev/null +++ b/widgets.go @@ -0,0 +1,82 @@ +package main + +import ( + "image/color" + + "fyne.io/fyne" + "fyne.io/fyne/canvas" + "fyne.io/fyne/theme" + "fyne.io/fyne/widget" +) + +type ChannelWidget struct { + widget.BaseWidget + Name string + Icon *canvas.Image + Text *widget.Label + SelectedChannel chan string + Highlight bool +} + +type ChannelWidgetRenderer struct { + icon *canvas.Image + text *widget.Label + name *widget.Label + highlight bool + objects []fyne.CanvasObject +} + +func (rw *ChannelWidget) Tapped(_ *fyne.PointEvent) { + rw.SelectedChannel <- rw.Text.Text +} + +func (rw *ChannelWidget) TappedSecondary(_ *fyne.PointEvent) { +} + +func (rw *ChannelWidget) CreateRenderer() fyne.WidgetRenderer { + rw.ExtendBaseWidget(rw) + n := widget.NewLabelWithStyle(rw.Name, fyne.TextAlignLeading, fyne.TextStyle{Bold: true}) + + rwr := &ChannelWidgetRenderer{} + rwr.icon = rw.Icon + rwr.name = n + rwr.text = rw.Text + rwr.highlight = rw.Highlight + rwr.objects = []fyne.CanvasObject{rw.Icon, n, rw.Text} + return rwr +} + +func (rwr *ChannelWidgetRenderer) Layout(size fyne.Size) { + rwr.name.Move(fyne.NewPos(0, 0)) + rwr.text.Move(fyne.NewPos(0, 25)) + // Move everything over 50 for the icon + rwr.name.Move(fyne.NewPos(50+rwr.name.Position().X, rwr.name.Position().Y)) + rwr.text.Move(fyne.NewPos(50+rwr.text.Position().X, rwr.text.Position().Y)) + // Display the icon + rwr.icon.Move(fyne.NewPos(0, 0)) + rwr.icon.Resize(fyne.NewSize(50, 50)) +} + +func (rwr *ChannelWidgetRenderer) Objects() []fyne.CanvasObject { + return rwr.objects +} + +func (rw *ChannelWidgetRenderer) MinSize() fyne.Size { + return fyne.NewSize(100, 50) +} + +func (rwr *ChannelWidgetRenderer) BackgroundColor() color.Color { + if rwr.highlight { + return theme.HoverColor() + } + return theme.BackgroundColor() +} + +func (rw *ChannelWidgetRenderer) Destroy() { +} + +func (rwr *ChannelWidgetRenderer) Refresh() { + rwr.objects = append(rwr.objects, rwr.icon) + rwr.objects = append(rwr.objects, rwr.name) + rwr.objects = append(rwr.objects, rwr.text) +}