From b0fd9a1c7848343ef378b772eb76a0e99747260c Mon Sep 17 00:00:00 2001 From: citrons Date: Wed, 4 Jun 2025 12:12:13 -0500 Subject: channel list --- client/application.go | 12 ++++++ client/channel_list.go | 99 ++++++++++++++++++++++++++++++++++++++++++++++++ client/channel_window.go | 1 + client/ui.go | 29 ++++++++++---- server/object/object.go | 1 + server/server/command.go | 20 +++++++++- 6 files changed, 154 insertions(+), 8 deletions(-) create mode 100644 client/channel_list.go diff --git a/client/application.go b/client/application.go index 35f38c8..2d16591 100644 --- a/client/application.go +++ b/client/application.go @@ -18,6 +18,7 @@ type application struct { windowCache window.WindowCache currentWindow window.Location windowHist []window.Location + channelList channelList cmdWindow cmdWindow prompts []window.Prompt } @@ -121,6 +122,7 @@ func (a *application) auth(name string, authCallback func(success bool)) { a.authenticated = true a.uid = me.Id a.cache.Watch(a.uid) + a.onAuth() if authCallback != nil { authCallback(true) } @@ -138,6 +140,14 @@ func (a *application) auth(name string, authCallback func(success bool)) { }), callback) } +func (a *application) onAuth() { + a.Request(proto.NewCmd("channels", ""), func(response proto.Command) { + if response.Kind == "channels" { + a.channelList.setChannels(response.Args) + } + }) +} + func (a *application) sendUpdate(o proto.Object, cb func(proto.Command)) { a.Request(proto.NewCmd("update", o.Id, o), cb) } @@ -170,6 +180,7 @@ func (a *application) join(channelName string) { a.Request(proto.NewCmd("join", ch.Id), func(response proto.Command) { switch response.Kind { case "ok": + a.channelList.add(channelName, channelLocation {id: ch.Id}) a.goTo(channelLocation {id: ch.Id}) case "fail": if len(response.Args) > 0 { @@ -188,6 +199,7 @@ func (a *application) createChannel(name string) { case "create": if len(response.Args) > 0 { ch := response.Args[0] + a.channelList.add(ch.Fields[""], channelLocation {id: ch.Id}) a.goTo(channelLocation {id: ch.Id}) } case "fail": diff --git a/client/channel_list.go b/client/channel_list.go new file mode 100644 index 0000000..5903792 --- /dev/null +++ b/client/channel_list.go @@ -0,0 +1,99 @@ +package main + +import ( + "citrons.xyz/talk/proto" + "citrons.xyz/talk/tui" + "sort" +) + +type channelList []channelListEntry + +type channelListEntry struct { + name string + location channelLocation +} + +func (cl *channelList) Len() int { + return len(*cl) +} + +func (cl *channelList) Less(i, j int) bool { + return (*cl)[i].name < (*cl)[j].name +} + +func (cl *channelList) Swap(i, j int) { + x := (*cl)[i] + (*cl)[i] = (*cl)[j] + (*cl)[j] = x +} + +func (cl *channelList) setChannels(cs []proto.Object) { + *cl = nil + for _, c := range cs { + *cl = append(*cl, channelListEntry { + c.Fields[""], channelLocation {c.Id}, + }) + } + sort.Sort(cl) +} + +func (cl *channelList) remove(location channelLocation) { + for i := len(*cl) - 1; i >= 0; i-- { + if (*cl)[i].location != location { + continue + } + if i < len(*cl) - 1 { + *cl = append((*cl)[:i], (*cl)[i + 1:]...) + } else { + *cl = (*cl)[:i] + } + break + } +} + +func (cl *channelList) traverse(direction int) { + var i int + for i = 0; i < len(*cl); i++ { + if (*cl)[i].location == globalApp.currentWindow { + break + } + } + if i == len(*cl) { + i = 0 + } else { + i += direction + i %= len(*cl) + if i < 0 { + i = len(*cl) + i + } + } + globalApp.goTo((*cl)[i].location) +} + +func (cl *channelList) add(name string, location channelLocation) { + cl.remove(location) + entry := channelListEntry {name, location} + *cl = append([]channelListEntry {entry}, *cl...) +} + +func (cl *channelList) show() { + tui.Push("channel list", tui.Box {Width: 12, Height: tui.Fill}) + for i, entry := range *cl { + var style *tui.Style + if entry.location == globalApp.currentWindow { + style = &tui.Style {Fg: tui.Black, Bg: tui.White} + } + + tui.Push("channel list." + entry.location.id, tui.Box { + Width: tui.Fill, Height: 1, NoWrap: true, Style: style, + }) + ch := globalApp.cache.Get(entry.location.id) + if ch != nil { + entry.name = ch.Fields[""] + (*cl)[i] = entry + } + tui.Text(entry.name, nil) + tui.Pop() + } + tui.Pop() +} diff --git a/client/channel_window.go b/client/channel_window.go index 6ec9ea0..b3788da 100644 --- a/client/channel_window.go +++ b/client/channel_window.go @@ -111,6 +111,7 @@ func (cw *channelWindow) leaveChannel() { globalApp.Request(proto.NewCmd("leave", cw.location.id), nil) globalApp.windowCache.Evict(cw.location) globalApp.removeFromHistory(cw.location) + globalApp.channelList.remove(cw.location) } func (cw *channelWindow) renameChannel(newName string) { diff --git a/client/ui.go b/client/ui.go index 014c7e9..87edea8 100644 --- a/client/ui.go +++ b/client/ui.go @@ -67,6 +67,10 @@ func (a *application) onInput(ev tui.Event) { input.SetText("") } } + case keys.Up | keys.Alt: + a.channelList.traverse(-1) + case keys.Down | keys.Alt: + a.channelList.traverse(1) case 'p' | keys.Ctrl: a.traverseHistory(-1) case 'n' | keys.Ctrl: @@ -106,13 +110,8 @@ func (a *application) showNickBox() { tui.Pop() } -func (a *application) show() { - tui.Clear() - s := tui.Size() - tui.Push("", tui.Box { - Width: tui.BoxSize(s.Width), Height: tui.BoxSize(s.Height), - Style: &tui.Style {Fg: tui.White, Bg: colorDefault[false]}, - }) +func (a *application) showWindow() { + tui.Push("window", tui.Box {Width: tui.Fill, Height: tui.Fill}) if a.currentWindow != (cmdWindowLocation{}) { a.cmdWindow.showPreview() @@ -153,6 +152,22 @@ func (a *application) show() { tui.Pop() tui.Pop() +} + +func (a *application) show() { + tui.Clear() + s := tui.Size() + tui.Push("", tui.Box { + Width: tui.BoxSize(s.Width), Height: tui.BoxSize(s.Height), + Dir: tui.Right, + }) + + a.channelList.show() + tui.Push("border", tui.Box {Width: 1, Height: tui.Fill}) + tui.Text(strings.Repeat("│", s.Height), nil) + tui.Pop() + a.showWindow() + tui.DrawLayout() if tui.Present() != nil { os.Exit(-1) diff --git a/server/object/object.go b/server/object/object.go index d18507c..bae274a 100644 --- a/server/object/object.go +++ b/server/object/object.go @@ -7,6 +7,7 @@ import ( type Object interface { SendRequest(session.Request) + GetInfo() proto.Object } type World struct { diff --git a/server/server/command.go b/server/server/command.go index 603b033..306a445 100644 --- a/server/server/command.go +++ b/server/server/command.go @@ -111,6 +111,22 @@ func (s *server) SendRequest(r session.Request) { r.ReplyInvalid() } + case "channels": + if r.From.UserId == "" { + r.Reply(proto.NewCmd("channels", "", )) + return + } + if len(r.Cmd.Args) != 0 { + r.ReplyInvalid() + return + } + u := s.world.GetObject(r.From.UserId).(*user.User) + var channels []proto.Object + for c := range u.Channels { + channels = append(channels, s.world.GetObject(c).GetInfo()) + } + r.Reply(proto.NewCmd("channels", "", channels...)) + case "meow": r.Reply(proto.NewCmd("meow", "")) @@ -119,4 +135,6 @@ func (s *server) SendRequest(r session.Request) { } } - +func (s *server) GetInfo() proto.Object { + return proto.Object {} +} -- cgit v1.2.3