From 455d9fc4c5726e4af9c40b36ee4f4ea18f65a8e9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 22 Feb 2020 01:17:52 +0200 Subject: Improve tags and add initial invite handling --- ui/command-processor.go | 60 ++++++++++++++++++++++++++----------------------- ui/commands.go | 49 +++++++++++++++++++++++++++++++++++++++- ui/member-list.go | 5 +++-- ui/room-list.go | 53 +++++++++++++++++++++++++++++++++++-------- ui/tag-room-list.go | 27 ++++++++++++++-------- 5 files changed, 145 insertions(+), 49 deletions(-) (limited to 'ui') diff --git a/ui/command-processor.go b/ui/command-processor.go index ee975ad..c4dabbd 100644 --- a/ui/command-processor.go +++ b/ui/command-processor.go @@ -90,34 +90,38 @@ func NewCommandProcessor(parent *MainView) *CommandProcessor { }, commands: map[string]CommandHandler{ "unknown-command": cmdUnknownCommand, - "help": cmdHelp, - "me": cmdMe, - "quit": cmdQuit, - "clearcache": cmdClearCache, - "leave": cmdLeave, - "create": cmdCreateRoom, - "pm": cmdPrivateMessage, - "join": cmdJoin, - "kick": cmdKick, - "ban": cmdBan, - "unban": cmdUnban, - "toggle": cmdToggle, - "logout": cmdLogout, - "sendevent": cmdSendEvent, - "msendevent": cmdMSendEvent, - "setstate": cmdSetState, - "msetstate": cmdMSetState, - "roomnick": cmdRoomNick, - "rainbow": cmdRainbow, - "rainbowme": cmdRainbowMe, - "notice": cmdNotice, - "tags": cmdTags, - "tag": cmdTag, - "untag": cmdUntag, - "invite": cmdInvite, - "hprof": cmdHeapProfile, - "cprof": cmdCPUProfile, - "trace": cmdTrace, + + "id": cmdID, + "help": cmdHelp, + "me": cmdMe, + "quit": cmdQuit, + "clearcache": cmdClearCache, + "leave": cmdLeave, + "create": cmdCreateRoom, + "pm": cmdPrivateMessage, + "join": cmdJoin, + "kick": cmdKick, + "ban": cmdBan, + "unban": cmdUnban, + "toggle": cmdToggle, + "logout": cmdLogout, + "accept": cmdAccept, + "reject": cmdReject, + "sendevent": cmdSendEvent, + "msendevent": cmdMSendEvent, + "setstate": cmdSetState, + "msetstate": cmdMSetState, + "roomnick": cmdRoomNick, + "rainbow": cmdRainbow, + "rainbowme": cmdRainbowMe, + "notice": cmdNotice, + "tags": cmdTags, + "tag": cmdTag, + "untag": cmdUntag, + "invite": cmdInvite, + "hprof": cmdHeapProfile, + "cprof": cmdCPUProfile, + "trace": cmdTrace, }, } } diff --git a/ui/commands.go b/ui/commands.go index 0f7a2aa..9b1ac25 100644 --- a/ui/commands.go +++ b/ui/commands.go @@ -106,8 +106,44 @@ func cmdNotice(cmd *Command) { cmd.UI.Render() } +func cmdAccept(cmd *Command) { + room := cmd.Room.MxRoom() + if room.SessionMember.Membership != "invite" { + cmd.Reply("/accept can only be used in rooms you're invited to") + return + } + _, server, _ := mautrix.ParseUserID(room.SessionMember.Sender) + _, err := cmd.Matrix.JoinRoom(room.ID, server) + if err != nil { + cmd.Reply("Failed to accept invite:", err) + } else { + cmd.Reply("Successfully accepted invite") + } +} + +func cmdReject(cmd *Command) { + room := cmd.Room.MxRoom() + if room.SessionMember.Membership != "invite" { + cmd.Reply("/reject can only be used in rooms you're invited to") + return + } + err := cmd.Matrix.LeaveRoom(room.ID) + if err != nil { + cmd.Reply("Failed to reject invite: %v", err) + } else { + cmd.Reply("Successfully accepted invite") + } +} + +func cmdID(cmd *Command) { + cmd.Reply("The internal ID of this room is %s", cmd.Room.MxRoom().ID) +} + func cmdTags(cmd *Command) { tags := cmd.Room.MxRoom().RawTags + if len(cmd.Args) > 0 && cmd.Args[0] == "--internal" { + tags = cmd.Room.MxRoom().Tags() + } if len(tags) == 0 { if cmd.Room.MxRoom().IsDirect { cmd.Reply("This room has no tags, but it's marked as a direct chat.") @@ -142,7 +178,18 @@ func cmdTag(cmd *Command) { return } } - err := cmd.Matrix.Client().AddTag(cmd.Room.MxRoom().ID, cmd.Args[0], order) + var err error + if len(cmd.Args) > 2 && cmd.Args[2] == "--reset" { + tags := mautrix.Tags{ + cmd.Args[0]: {Order: json.Number(fmt.Sprintf("%f", order))}, + } + for _, tag := range cmd.Room.MxRoom().RawTags { + tags[tag.Tag] = mautrix.Tag{Order: tag.Order} + } + err = cmd.Matrix.Client().SetTags(cmd.Room.MxRoom().ID, tags) + } else { + err = cmd.Matrix.Client().AddTag(cmd.Room.MxRoom().ID, cmd.Args[0], order) + } if err != nil { cmd.Reply("Failed to add tag:", err) } diff --git a/ui/member-list.go b/ui/member-list.go index aaddcfb..e836e18 100644 --- a/ui/member-list.go +++ b/ui/member-list.go @@ -27,6 +27,7 @@ import ( "maunium.net/go/mauview" "maunium.net/go/tcell" + "maunium.net/go/gomuks/matrix/rooms" "maunium.net/go/gomuks/ui/widget" ) @@ -39,7 +40,7 @@ func NewMemberList() *MemberList { } type memberListItem struct { - mautrix.Member + rooms.Member PowerLevel int Sigil rune UserID string @@ -63,7 +64,7 @@ func (rml roomMemberList) Swap(i, j int) { rml[i], rml[j] = rml[j], rml[i] } -func (ml *MemberList) Update(data map[string]*mautrix.Member, levels *mautrix.PowerLevels) *MemberList { +func (ml *MemberList) Update(data map[string]*rooms.Member, levels *mautrix.PowerLevels) *MemberList { ml.list = make(roomMemberList, len(data)) i := 0 highestLevel := math.MinInt32 diff --git a/ui/room-list.go b/ui/room-list.go index 2b8af87..31e4c2a 100644 --- a/ui/room-list.go +++ b/ui/room-list.go @@ -19,6 +19,7 @@ package ui import ( "math" "regexp" + "sort" "strings" sync "github.com/sasha-s/go-deadlock" @@ -30,13 +31,43 @@ import ( "maunium.net/go/gomuks/matrix/rooms" ) +var tagOrder = map[string]int{ + "net.maunium.gomuks.fake.invite": 4, + "m.favourite": 3, + "net.maunium.gomuks.fake.direct": 2, + "": 1, + "m.lowpriority": -1, + "m.server_notice": -2, + "net.maunium.gomuks.fake.leave": -3, +} + +// TagNameList is a list of Matrix tag names where default names are sorted in a hardcoded way. +type TagNameList []string + +func (tnl TagNameList) Len() int { + return len(tnl) +} + +func (tnl TagNameList) Less(i, j int) bool { + orderI, _ := tagOrder[tnl[i]] + orderJ, _ := tagOrder[tnl[j]] + if orderI != orderJ { + return orderI > orderJ + } + return strings.Compare(tnl[i], tnl[j]) > 0 +} + +func (tnl TagNameList) Swap(i, j int) { + tnl[i], tnl[j] = tnl[j], tnl[i] +} + type RoomList struct { sync.RWMutex parent *MainView // The list of tags in display order. - tags []string + tags TagNameList // The list of rooms, in reverse order. items map[string]*TagRoomList // The selected room. @@ -107,13 +138,14 @@ func (list *RoomList) checkTag(tag string) { //delete(list.items, tag) ok = false } + debug.Print("Checking", tag, index, trl.IsEmpty(), ok) if ok && index == -1 { list.tags = append(list.tags, tag) - } /* TODO this doesn't work properly - else if index != -1 { + sort.Sort(list.tags) + } else if !ok && index != -1 { list.tags = append(list.tags[0:index], list.tags[index+1:]...) - }*/ + } } func (list *RoomList) AddToTag(tag rooms.RoomTag, room *rooms.Room) { @@ -122,10 +154,9 @@ func (list *RoomList) AddToTag(tag rooms.RoomTag, room *rooms.Room) { trl, ok := list.items[tag.Tag] if !ok { list.items[tag.Tag] = NewTagRoomList(list, tag.Tag, NewDefaultOrderedRoom(room)) - return + } else { + trl.Insert(tag.Order, room) } - - trl.Insert(tag.Order, room) list.checkTag(tag.Tag) } @@ -412,11 +443,11 @@ func (list *RoomList) ContentHeight() (height int) { return } -func (list *RoomList) OnKeyEvent(event mauview.KeyEvent) bool { +func (list *RoomList) OnKeyEvent(_ mauview.KeyEvent) bool { return false } -func (list *RoomList) OnPasteEvent(event mauview.PasteEvent) bool { +func (list *RoomList) OnPasteEvent(_ mauview.PasteEvent) bool { return false } @@ -517,6 +548,10 @@ func (list *RoomList) GetTagDisplayName(tag string) string { return "System Alerts" case tag == "net.maunium.gomuks.fake.direct": return "People" + case tag == "net.maunium.gomuks.fake.invite": + return "Invites" + case tag == "net.maunium.gomuks.fake.leave": + return "Historical" case strings.HasPrefix(tag, "u."): return tag[len("u."):] case !nsRegex.MatchString(tag): diff --git a/ui/tag-room-list.go b/ui/tag-room-list.go index dfc7cb2..d382400 100644 --- a/ui/tag-room-list.go +++ b/ui/tag-room-list.go @@ -17,10 +17,12 @@ package ui import ( + "encoding/json" "fmt" "strconv" "strings" + "maunium.net/go/gomuks/debug" "maunium.net/go/mauview" "maunium.net/go/tcell" @@ -30,10 +32,10 @@ import ( type OrderedRoom struct { *rooms.Room - order string + order json.Number } -func NewOrderedRoom(order string, room *rooms.Room) *OrderedRoom { +func NewOrderedRoom(order json.Number, room *rooms.Room) *OrderedRoom { return &OrderedRoom{ Room: room, order: order, @@ -153,23 +155,25 @@ func (trl *TagRoomList) HasVisibleRooms() bool { // ShouldBeBefore returns if the first room should be after the second room in the room list. // The manual order and last received message timestamp are considered. func (trl *TagRoomList) ShouldBeAfter(room1 *OrderedRoom, room2 *OrderedRoom) bool { - orderComp := strings.Compare(room1.order, room2.order) + orderComp := strings.Compare(string(room1.order), string(room2.order)) return orderComp == 1 || (orderComp == 0 && room2.LastReceivedMessage.After(room1.LastReceivedMessage)) } -func (trl *TagRoomList) Insert(order string, mxRoom *rooms.Room) { +func (trl *TagRoomList) Insert(order json.Number, mxRoom *rooms.Room) { room := NewOrderedRoom(order, mxRoom) - trl.rooms = append(trl.rooms, nil) // The default insert index is the newly added slot. // That index will be used if all other rooms in the list have the same LastReceivedMessage timestamp. - insertAt := len(trl.rooms) - 1 + insertAt := len(trl.rooms) // Find the spot where the new room should be put according to the last received message timestamps. for i := 0; i < len(trl.rooms)-1; i++ { - if trl.ShouldBeAfter(room, trl.rooms[i]) { + if trl.rooms[i].Room == mxRoom { + debug.Printf("Warning: tried to re-insert room %s into tag %s", mxRoom.ID, trl.name) + return + } else if trl.ShouldBeAfter(room, trl.rooms[i]) { insertAt = i - break } } + trl.rooms = append(trl.rooms, nil) // Move newer rooms forward in the array. for i := len(trl.rooms) - 1; i > insertAt; i-- { trl.rooms[i] = trl.rooms[i-1] @@ -207,7 +211,12 @@ func (trl *TagRoomList) RemoveIndex(index int) { if index < 0 || index > len(trl.rooms) { return } - trl.rooms = append(trl.rooms[0:index], trl.rooms[index+1:]...) + last := len(trl.rooms) - 1 + if index < last { + copy(trl.rooms[index:], trl.rooms[index+1:]) + } + trl.rooms[last] = nil + trl.rooms = trl.rooms[:last] } func (trl *TagRoomList) Index(room *rooms.Room) int { -- cgit v1.2.3