Merge pull request #33 from tulir/initial-sync
Use initial sync data instead of fetching room list, state, history, etc manually
This commit is contained in:
commit
7026ed99a3
@ -35,6 +35,8 @@ type Session struct {
|
|||||||
FilterID string
|
FilterID string
|
||||||
Rooms map[string]*rooms.Room
|
Rooms map[string]*rooms.Room
|
||||||
PushRules *pushrules.PushRuleset
|
PushRules *pushrules.PushRuleset
|
||||||
|
|
||||||
|
InitialSyncDone bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (config *Config) LoadSession(mxid string) error {
|
func (config *Config) LoadSession(mxid string) error {
|
||||||
@ -59,6 +61,7 @@ func (s *Session) Clear() {
|
|||||||
s.PushRules = nil
|
s.PushRules = nil
|
||||||
s.NextBatch = ""
|
s.NextBatch = ""
|
||||||
s.FilterID = ""
|
s.FilterID = ""
|
||||||
|
s.InitialSyncDone = false
|
||||||
s.Save()
|
s.Save()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,9 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"maunium.net/go/gomuks/config"
|
"maunium.net/go/gomuks/config"
|
||||||
@ -104,6 +106,13 @@ func (gmx *Gomuks) Stop() {
|
|||||||
func (gmx *Gomuks) Start() {
|
func (gmx *Gomuks) Start() {
|
||||||
_ = gmx.matrix.InitClient()
|
_ = gmx.matrix.InitClient()
|
||||||
|
|
||||||
|
c := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||||
|
go func() {
|
||||||
|
<-c
|
||||||
|
gmx.Stop()
|
||||||
|
}()
|
||||||
|
|
||||||
go gmx.StartAutosave()
|
go gmx.StartAutosave()
|
||||||
if err := gmx.ui.Start(); err != nil {
|
if err := gmx.ui.Start(); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -51,7 +51,7 @@ type MainView interface {
|
|||||||
GetRoom(roomID string) RoomView
|
GetRoom(roomID string) RoomView
|
||||||
AddRoom(roomID string)
|
AddRoom(roomID string)
|
||||||
RemoveRoom(roomID string)
|
RemoveRoom(roomID string)
|
||||||
SetRooms(roomIDs []string)
|
SetRooms(rooms map[string]*rooms.Room)
|
||||||
SaveAllHistory()
|
SaveAllHistory()
|
||||||
|
|
||||||
UpdateTags(room *rooms.Room, newTags []rooms.RoomTag)
|
UpdateTags(room *rooms.Room, newTags []rooms.RoomTag)
|
||||||
|
@ -129,6 +129,7 @@ func (c *Container) Login(user, password string) error {
|
|||||||
// Stop stops the Matrix syncer.
|
// Stop stops the Matrix syncer.
|
||||||
func (c *Container) Stop() {
|
func (c *Container) Stop() {
|
||||||
if c.running {
|
if c.running {
|
||||||
|
debug.Print("Stopping Matrix container...")
|
||||||
c.stop <- true
|
c.stop <- true
|
||||||
c.client.StopSync()
|
c.client.StopSync()
|
||||||
}
|
}
|
||||||
@ -157,22 +158,6 @@ func (c *Container) PushRules() *pushrules.PushRuleset {
|
|||||||
return c.config.Session.PushRules
|
return c.config.Session.PushRules
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateRoomList fetches the list of rooms the user has joined and sends them to the UI.
|
|
||||||
func (c *Container) UpdateRoomList() {
|
|
||||||
resp, err := c.client.JoinedRooms()
|
|
||||||
if err != nil {
|
|
||||||
respErr, _ := err.(gomatrix.HTTPError).WrappedError.(gomatrix.RespError)
|
|
||||||
if respErr.ErrCode == "M_UNKNOWN_TOKEN" {
|
|
||||||
c.OnLogout()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
debug.Print("Error fetching room list:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ui.MainView().SetRooms(resp.JoinedRooms)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnLogout stops the syncer and moves the UI back to the login view.
|
// OnLogout stops the syncer and moves the UI back to the login view.
|
||||||
func (c *Container) OnLogout() {
|
func (c *Container) OnLogout() {
|
||||||
c.Stop()
|
c.Stop()
|
||||||
@ -183,15 +168,23 @@ func (c *Container) OnLogout() {
|
|||||||
func (c *Container) OnLogin() {
|
func (c *Container) OnLogin() {
|
||||||
c.client.Store = c.config.Session
|
c.client.Store = c.config.Session
|
||||||
|
|
||||||
|
debug.Print("Initializing syncer")
|
||||||
c.syncer = NewGomuksSyncer(c.config.Session)
|
c.syncer = NewGomuksSyncer(c.config.Session)
|
||||||
c.syncer.OnEventType("m.room.message", c.HandleMessage)
|
c.syncer.OnEventType("m.room.message", c.HandleMessage)
|
||||||
c.syncer.OnEventType("m.room.member", c.HandleMembership)
|
c.syncer.OnEventType("m.room.member", c.HandleMembership)
|
||||||
c.syncer.OnEventType("m.typing", c.HandleTyping)
|
c.syncer.OnEventType("m.typing", c.HandleTyping)
|
||||||
c.syncer.OnEventType("m.push_rules", c.HandlePushRules)
|
c.syncer.OnEventType("m.push_rules", c.HandlePushRules)
|
||||||
c.syncer.OnEventType("m.tag", c.HandleTag)
|
c.syncer.OnEventType("m.tag", c.HandleTag)
|
||||||
|
c.syncer.InitDoneCallback = func() {
|
||||||
|
c.config.Session.InitialSyncDone = true
|
||||||
|
c.ui.Render()
|
||||||
|
}
|
||||||
c.client.Syncer = c.syncer
|
c.client.Syncer = c.syncer
|
||||||
|
|
||||||
c.UpdateRoomList()
|
debug.Print("Setting existing rooms")
|
||||||
|
c.ui.MainView().SetRooms(c.config.Session.Rooms)
|
||||||
|
|
||||||
|
debug.Print("OnLogin() done.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start moves the UI to the main view, calls OnLogin() and runs the syncer forever until stopped with Stop()
|
// Start moves the UI to the main view, calls OnLogin() and runs the syncer forever until stopped with Stop()
|
||||||
@ -226,19 +219,23 @@ func (c *Container) Start() {
|
|||||||
// HandleMessage is the event handler for the m.room.message timeline event.
|
// HandleMessage is the event handler for the m.room.message timeline event.
|
||||||
func (c *Container) HandleMessage(evt *gomatrix.Event) {
|
func (c *Container) HandleMessage(evt *gomatrix.Event) {
|
||||||
mainView := c.ui.MainView()
|
mainView := c.ui.MainView()
|
||||||
|
|
||||||
roomView := mainView.GetRoom(evt.RoomID)
|
roomView := mainView.GetRoom(evt.RoomID)
|
||||||
if roomView == nil {
|
if roomView == nil {
|
||||||
|
debug.Printf("Failed to handle event %v: No room view found.", evt)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
message := mainView.ParseEvent(roomView, evt)
|
message := mainView.ParseEvent(roomView, evt)
|
||||||
if message != nil {
|
if message != nil {
|
||||||
|
roomView.AddMessage(message, ifc.AppendMessage)
|
||||||
if c.syncer.FirstSyncDone {
|
if c.syncer.FirstSyncDone {
|
||||||
pushRules := c.PushRules().GetActions(roomView.MxRoom(), evt).Should()
|
pushRules := c.PushRules().GetActions(roomView.MxRoom(), evt).Should()
|
||||||
mainView.NotifyMessage(roomView.MxRoom(), message, pushRules)
|
mainView.NotifyMessage(roomView.MxRoom(), message, pushRules)
|
||||||
|
c.ui.Render()
|
||||||
}
|
}
|
||||||
roomView.AddMessage(message, ifc.AppendMessage)
|
} else {
|
||||||
c.ui.Render()
|
debug.Printf("Parsing event %v failed (ParseEvent() returned nil).", evt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,6 +276,7 @@ func (c *Container) processOwnMembershipChange(evt *gomatrix.Event) {
|
|||||||
if evt.Unsigned.PrevContent != nil {
|
if evt.Unsigned.PrevContent != nil {
|
||||||
prevMembership, _ = evt.Unsigned.PrevContent["membership"].(string)
|
prevMembership, _ = evt.Unsigned.PrevContent["membership"].(string)
|
||||||
}
|
}
|
||||||
|
debug.Printf("Processing own membership change: %s->%s in %s", prevMembership, membership, evt.RoomID)
|
||||||
if membership == prevMembership {
|
if membership == prevMembership {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -287,6 +285,9 @@ func (c *Container) processOwnMembershipChange(evt *gomatrix.Event) {
|
|||||||
c.ui.MainView().AddRoom(evt.RoomID)
|
c.ui.MainView().AddRoom(evt.RoomID)
|
||||||
case "leave":
|
case "leave":
|
||||||
c.ui.MainView().RemoveRoom(evt.RoomID)
|
c.ui.MainView().RemoveRoom(evt.RoomID)
|
||||||
|
case "invite":
|
||||||
|
// TODO handle
|
||||||
|
debug.Printf("%s invited the user to %s", evt.Sender, evt.RoomID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,6 +297,11 @@ func (c *Container) HandleMembership(evt *gomatrix.Event) {
|
|||||||
c.processOwnMembershipChange(evt)
|
c.processOwnMembershipChange(evt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !c.config.Session.InitialSyncDone /*&& evt.Timestamp < time.Now().Add(-1*time.Hour).Unix()*/ {
|
||||||
|
// We don't care about other users' membership events in the initial sync.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
mainView := c.ui.MainView()
|
mainView := c.ui.MainView()
|
||||||
roomView := mainView.GetRoom(evt.RoomID)
|
roomView := mainView.GetRoom(evt.RoomID)
|
||||||
if roomView == nil {
|
if roomView == nil {
|
||||||
@ -305,16 +311,17 @@ func (c *Container) HandleMembership(evt *gomatrix.Event) {
|
|||||||
message := mainView.ParseEvent(roomView, evt)
|
message := mainView.ParseEvent(roomView, evt)
|
||||||
if message != nil {
|
if message != nil {
|
||||||
// TODO this shouldn't be necessary
|
// TODO this shouldn't be necessary
|
||||||
roomView.MxRoom().UpdateState(evt)
|
//roomView.MxRoom().UpdateState(evt)
|
||||||
// TODO This should probably also be in a different place
|
// TODO This should probably also be in a different place
|
||||||
roomView.UpdateUserList()
|
//roomView.UpdateUserList()
|
||||||
|
|
||||||
|
roomView.AddMessage(message, ifc.AppendMessage)
|
||||||
|
// We don't want notifications at startup.
|
||||||
if c.syncer.FirstSyncDone {
|
if c.syncer.FirstSyncDone {
|
||||||
pushRules := c.PushRules().GetActions(roomView.MxRoom(), evt).Should()
|
pushRules := c.PushRules().GetActions(roomView.MxRoom(), evt).Should()
|
||||||
mainView.NotifyMessage(roomView.MxRoom(), message, pushRules)
|
mainView.NotifyMessage(roomView.MxRoom(), message, pushRules)
|
||||||
|
c.ui.Render()
|
||||||
}
|
}
|
||||||
roomView.AddMessage(message, ifc.AppendMessage)
|
|
||||||
c.ui.Render()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,12 +478,12 @@ func (c *Container) GetHistory(roomID, prevBatch string, limit int) ([]gomatrix.
|
|||||||
func (c *Container) GetRoom(roomID string) *rooms.Room {
|
func (c *Container) GetRoom(roomID string) *rooms.Room {
|
||||||
room := c.config.Session.GetRoom(roomID)
|
room := c.config.Session.GetRoom(roomID)
|
||||||
if room != nil && len(room.State) == 0 {
|
if room != nil && len(room.State) == 0 {
|
||||||
events := c.getState(room.ID)
|
/*events := c.getState(room.ID)
|
||||||
if events != nil {
|
if events != nil {
|
||||||
for _, event := range events {
|
for _, event := range events {
|
||||||
room.UpdateState(event)
|
room.UpdateState(event)
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
return room
|
return room
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"maunium.net/go/gomatrix"
|
"maunium.net/go/gomatrix"
|
||||||
|
"maunium.net/go/gomuks/debug"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RoomNameSource int
|
type RoomNameSource int
|
||||||
@ -148,6 +149,15 @@ func (room *Room) UpdateState(event *gomatrix.Event) {
|
|||||||
case "m.room.topic":
|
case "m.room.topic":
|
||||||
room.topicCache = ""
|
room.topicCache = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stateKey := ""
|
||||||
|
if event.StateKey != nil {
|
||||||
|
stateKey = *event.StateKey
|
||||||
|
}
|
||||||
|
if event.Type != "m.room.member" {
|
||||||
|
debug.Printf("Updating state %s#%s for %s", event.Type, stateKey, room.ID)
|
||||||
|
}
|
||||||
|
|
||||||
if event.StateKey == nil {
|
if event.StateKey == nil {
|
||||||
room.State[event.Type][""] = event
|
room.State[event.Type][""] = event
|
||||||
} else {
|
} else {
|
||||||
|
@ -20,8 +20,6 @@ package matrix
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"runtime/debug"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"maunium.net/go/gomatrix"
|
"maunium.net/go/gomatrix"
|
||||||
@ -37,9 +35,10 @@ type SyncerSession interface {
|
|||||||
// replace parts of this default syncer (e.g. the ProcessResponse method). The default syncer uses the observer
|
// replace parts of this default syncer (e.g. the ProcessResponse method). The default syncer uses the observer
|
||||||
// pattern to notify callers about incoming events. See GomuksSyncer.OnEventType for more information.
|
// pattern to notify callers about incoming events. See GomuksSyncer.OnEventType for more information.
|
||||||
type GomuksSyncer struct {
|
type GomuksSyncer struct {
|
||||||
Session SyncerSession
|
Session SyncerSession
|
||||||
listeners map[string][]gomatrix.OnEventListener // event type to listeners array
|
listeners map[string][]gomatrix.OnEventListener // event type to listeners array
|
||||||
FirstSyncDone bool
|
FirstSyncDone bool
|
||||||
|
InitDoneCallback func()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGomuksSyncer returns an instantiated GomuksSyncer
|
// NewGomuksSyncer returns an instantiated GomuksSyncer
|
||||||
@ -53,17 +52,6 @@ func NewGomuksSyncer(session SyncerSession) *GomuksSyncer {
|
|||||||
|
|
||||||
// ProcessResponse processes a Matrix sync response.
|
// ProcessResponse processes a Matrix sync response.
|
||||||
func (s *GomuksSyncer) ProcessResponse(res *gomatrix.RespSync, since string) (err error) {
|
func (s *GomuksSyncer) ProcessResponse(res *gomatrix.RespSync, since string) (err error) {
|
||||||
if len(since) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// debug.Print("Processing sync response", since, res)
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
err = fmt.Errorf("ProcessResponse for %s since %s panicked: %s\n%s", s.Session.GetUserID(), since, r, debug.Stack())
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
s.processSyncEvents(nil, res.Presence.Events, false, false)
|
s.processSyncEvents(nil, res.Presence.Events, false, false)
|
||||||
s.processSyncEvents(nil, res.AccountData.Events, false, false)
|
s.processSyncEvents(nil, res.AccountData.Events, false, false)
|
||||||
|
|
||||||
@ -93,6 +81,9 @@ func (s *GomuksSyncer) ProcessResponse(res *gomatrix.RespSync, since string) (er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if since == "" && s.InitDoneCallback != nil {
|
||||||
|
s.InitDoneCallback()
|
||||||
|
}
|
||||||
s.FirstSyncDone = true
|
s.FirstSyncDone = true
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -147,7 +138,13 @@ func (s *GomuksSyncer) GetFilterJSON(userID string) json.RawMessage {
|
|||||||
"room": {
|
"room": {
|
||||||
"include_leave": true,
|
"include_leave": true,
|
||||||
"state": {
|
"state": {
|
||||||
"types": ["m.room.member"]
|
"types": [
|
||||||
|
"m.room.member",
|
||||||
|
"m.room.name",
|
||||||
|
"m.room.topic",
|
||||||
|
"m.room.canonical_alias",
|
||||||
|
"m.room.aliases"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"types": ["m.room.message"],
|
"types": ["m.room.message"],
|
||||||
|
@ -183,7 +183,8 @@ func (view *MessageView) AddMessage(ifcMessage ifc.Message, direction ifc.Messag
|
|||||||
} else if oldMsg != nil {
|
} else if oldMsg != nil {
|
||||||
view.replaceBuffer(oldMsg, message)
|
view.replaceBuffer(oldMsg, message)
|
||||||
} else {
|
} else {
|
||||||
view.replaceBuffer(message, message)
|
debug.Print("Unexpected AddMessage() call: Direction is not append or prepend, but message is new.")
|
||||||
|
debug.PrintStack()
|
||||||
}
|
}
|
||||||
|
|
||||||
view.messageIDs[message.ID()] = message
|
view.messageIDs[message.ID()] = message
|
||||||
@ -232,7 +233,8 @@ func (view *MessageView) replaceBuffer(original messages.UIMessage, new messages
|
|||||||
}
|
}
|
||||||
|
|
||||||
if start == -1 {
|
if start == -1 {
|
||||||
debug.Print("Called replaceBuffer() with message that was not in the buffer:", original)
|
debug.Print("Called replaceBuffer() with message that was not in the buffer:", original.ID())
|
||||||
|
debug.PrintStack()
|
||||||
view.appendBuffer(new)
|
view.appendBuffer(new)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -72,8 +72,18 @@ func (msg *BaseTextMessage) calculateBufferWithText(text tstring.TString, width
|
|||||||
}
|
}
|
||||||
|
|
||||||
matches := boundaryPattern.FindAllStringIndex(extract.String(), -1)
|
matches := boundaryPattern.FindAllStringIndex(extract.String(), -1)
|
||||||
if len(matches) > 0 {
|
if len(matches) == 0 {
|
||||||
extract = extract[:matches[len(matches)-1][1]]
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
match := matches[len(matches)-1]
|
||||||
|
if len(match) < 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
until := match[1]
|
||||||
|
if until < len(extract) {
|
||||||
|
extract = extract[:until]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
msg.buffer = append(msg.buffer, extract)
|
msg.buffer = append(msg.buffer, extract)
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"maunium.net/go/gomuks/debug"
|
||||||
"maunium.net/go/gomuks/matrix/rooms"
|
"maunium.net/go/gomuks/matrix/rooms"
|
||||||
"maunium.net/go/gomuks/ui/widget"
|
"maunium.net/go/gomuks/ui/widget"
|
||||||
"maunium.net/go/tcell"
|
"maunium.net/go/tcell"
|
||||||
@ -57,6 +58,7 @@ func NewRoomList() *RoomList {
|
|||||||
return &RoomList{
|
return &RoomList{
|
||||||
Box: tview.NewBox(),
|
Box: tview.NewBox(),
|
||||||
items: make(map[string][]*rooms.Room),
|
items: make(map[string][]*rooms.Room),
|
||||||
|
tags: []string{"m.favourite", "im.vector.fake.direct", "", "m.lowpriority"},
|
||||||
|
|
||||||
mainTextColor: tcell.ColorWhite,
|
mainTextColor: tcell.ColorWhite,
|
||||||
selectedTextColor: tcell.ColorWhite,
|
selectedTextColor: tcell.ColorWhite,
|
||||||
@ -86,16 +88,17 @@ func (list *RoomList) CheckTag(tag string) {
|
|||||||
|
|
||||||
items, ok := list.items[tag]
|
items, ok := list.items[tag]
|
||||||
|
|
||||||
if len(items) == 0 {
|
if ok && len(items) == 0 {
|
||||||
delete(list.items, tag)
|
delete(list.items, tag)
|
||||||
ok = false
|
ok = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if ok && index == -1 {
|
if ok && index == -1 {
|
||||||
list.tags = append(list.tags, tag)
|
list.tags = append(list.tags, tag)
|
||||||
} else if index != -1 {
|
} /* TODO this doesn't work properly
|
||||||
|
else if index != -1 {
|
||||||
list.tags = append(list.tags[0:index], list.tags[index+1:]...)
|
list.tags = append(list.tags[0:index], list.tags[index+1:]...)
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
func (list *RoomList) AddToTag(tag string, room *rooms.Room) {
|
func (list *RoomList) AddToTag(tag string, room *rooms.Room) {
|
||||||
@ -210,7 +213,8 @@ func (list *RoomList) Clear() {
|
|||||||
|
|
||||||
func (list *RoomList) SetSelected(tag string, room *rooms.Room) {
|
func (list *RoomList) SetSelected(tag string, room *rooms.Room) {
|
||||||
list.selected = room
|
list.selected = room
|
||||||
list.selectedTag = ""
|
list.selectedTag = tag
|
||||||
|
debug.Print("Selecting", room.GetTitle(), "in", tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (list *RoomList) HasSelected() bool {
|
func (list *RoomList) HasSelected() bool {
|
||||||
@ -229,7 +233,7 @@ func (list *RoomList) First() (string, *rooms.Room) {
|
|||||||
for _, tag := range list.tags {
|
for _, tag := range list.tags {
|
||||||
items := list.items[tag]
|
items := list.items[tag]
|
||||||
if len(items) > 0 {
|
if len(items) > 0 {
|
||||||
return tag, items[0]
|
return tag, items[len(items)-1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", nil
|
return "", nil
|
||||||
@ -240,7 +244,7 @@ func (list *RoomList) Last() (string, *rooms.Room) {
|
|||||||
tag := list.tags[tagIndex]
|
tag := list.tags[tagIndex]
|
||||||
items := list.items[tag]
|
items := list.items[tag]
|
||||||
if len(items) > 0 {
|
if len(items) > 0 {
|
||||||
return tag, items[len(items)-1]
|
return tag, items[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", nil
|
return "", nil
|
||||||
@ -264,17 +268,19 @@ func (list *RoomList) Previous() (string, *rooms.Room) {
|
|||||||
|
|
||||||
items := list.items[list.selectedTag]
|
items := list.items[list.selectedTag]
|
||||||
index := list.indexInTag(list.selectedTag, list.selected)
|
index := list.indexInTag(list.selectedTag, list.selected)
|
||||||
if index == len(items)-1 {
|
if index == -1 {
|
||||||
|
return list.First()
|
||||||
|
} else if index == len(items)-1 {
|
||||||
tagIndex := list.IndexTag(list.selectedTag)
|
tagIndex := list.IndexTag(list.selectedTag)
|
||||||
tagIndex++
|
tagIndex--
|
||||||
for ; tagIndex < len(list.tags); tagIndex++ {
|
for ; tagIndex >= 0; tagIndex-- {
|
||||||
nextTag := list.tags[tagIndex]
|
prevTag := list.tags[tagIndex]
|
||||||
nextTagItems := list.items[nextTag]
|
prevTagItems := list.items[prevTag]
|
||||||
if len(nextTagItems) > 0 {
|
if len(prevTagItems) > 0 {
|
||||||
return nextTag, nextTagItems[0]
|
return prevTag, prevTagItems[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list.First()
|
return list.Last()
|
||||||
}
|
}
|
||||||
return list.selectedTag, items[index+1]
|
return list.selectedTag, items[index+1]
|
||||||
}
|
}
|
||||||
@ -288,17 +294,19 @@ func (list *RoomList) Next() (string, *rooms.Room) {
|
|||||||
|
|
||||||
items := list.items[list.selectedTag]
|
items := list.items[list.selectedTag]
|
||||||
index := list.indexInTag(list.selectedTag, list.selected)
|
index := list.indexInTag(list.selectedTag, list.selected)
|
||||||
if index == 0 {
|
if index == -1 {
|
||||||
|
return list.Last()
|
||||||
|
} else if index == 0 {
|
||||||
tagIndex := list.IndexTag(list.selectedTag)
|
tagIndex := list.IndexTag(list.selectedTag)
|
||||||
tagIndex--
|
tagIndex++
|
||||||
for ; tagIndex >= 0; tagIndex-- {
|
for ; tagIndex < len(list.tags); tagIndex++ {
|
||||||
prevTag := list.tags[tagIndex]
|
nextTag := list.tags[tagIndex]
|
||||||
prevTagItems := list.items[prevTag]
|
nextTagItems := list.items[nextTag]
|
||||||
if len(prevTagItems) > 0 {
|
if len(nextTagItems) > 0 {
|
||||||
return prevTag, prevTagItems[len(prevTagItems)-1]
|
return nextTag, nextTagItems[len(nextTagItems)-1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list.Last()
|
return list.First()
|
||||||
}
|
}
|
||||||
return list.selectedTag, items[index-1]
|
return list.selectedTag, items[index-1]
|
||||||
}
|
}
|
||||||
@ -332,6 +340,8 @@ func (list *RoomList) Get(n int) (string, *rooms.Room) {
|
|||||||
|
|
||||||
// Tag items
|
// Tag items
|
||||||
n -= len(items)
|
n -= len(items)
|
||||||
|
// Tag footer
|
||||||
|
n--
|
||||||
}
|
}
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
@ -346,6 +356,8 @@ func (list *RoomList) GetTagDisplayName(tag string) string {
|
|||||||
return "Favorites"
|
return "Favorites"
|
||||||
case tag == "m.lowpriority":
|
case tag == "m.lowpriority":
|
||||||
return "Low Priority"
|
return "Low Priority"
|
||||||
|
case tag == "im.vector.fake.direct":
|
||||||
|
return "People"
|
||||||
case strings.HasPrefix(tag, "m."):
|
case strings.HasPrefix(tag, "m."):
|
||||||
return strings.Title(strings.Replace(tag[len("m."):], "_", " ", -1))
|
return strings.Title(strings.Replace(tag[len("m."):], "_", " ", -1))
|
||||||
case strings.HasPrefix(tag, "u."):
|
case strings.HasPrefix(tag, "u."):
|
||||||
@ -420,5 +432,6 @@ func (list *RoomList) Draw(screen tcell.Screen) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
y++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,7 +173,7 @@ func (view *MainView) KeyEventHandler(roomView *RoomView, key *tcell.EventKey) *
|
|||||||
msgView := roomView.MessageView()
|
msgView := roomView.MessageView()
|
||||||
|
|
||||||
if msgView.IsAtTop() && (k == tcell.KeyPgUp || k == tcell.KeyUp) {
|
if msgView.IsAtTop() && (k == tcell.KeyPgUp || k == tcell.KeyUp) {
|
||||||
go view.LoadHistory(roomView.Room.ID, false)
|
go view.LoadHistory(roomView.Room.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch k {
|
switch k {
|
||||||
@ -215,7 +215,7 @@ func (view *MainView) MouseEventHandler(roomView *RoomView, event *tcell.EventMo
|
|||||||
switch event.Buttons() {
|
switch event.Buttons() {
|
||||||
case tcell.WheelUp:
|
case tcell.WheelUp:
|
||||||
if msgView.IsAtTop() {
|
if msgView.IsAtTop() {
|
||||||
go view.LoadHistory(roomView.Room.ID, false)
|
go view.LoadHistory(roomView.Room.ID)
|
||||||
} else {
|
} else {
|
||||||
msgView.AddScrollOffset(WheelScrollOffsetDiff)
|
msgView.AddScrollOffset(WheelScrollOffsetDiff)
|
||||||
|
|
||||||
@ -293,11 +293,9 @@ func (view *MainView) addRoomPage(room *rooms.Room) {
|
|||||||
view.roomView.AddPage(room.ID, roomView, true, false)
|
view.roomView.AddPage(room.ID, roomView, true, false)
|
||||||
roomView.UpdateUserList()
|
roomView.UpdateUserList()
|
||||||
|
|
||||||
count, err := roomView.LoadHistory(view.matrix, view.config.HistoryDir)
|
_, err := roomView.LoadHistory(view.matrix, view.config.HistoryDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
debug.Printf("Failed to load history of %s: %v", roomView.Room.GetTitle(), err)
|
debug.Printf("Failed to load history of %s: %v", roomView.Room.GetTitle(), err)
|
||||||
} else if count <= 0 {
|
|
||||||
go view.LoadHistory(room.ID, true)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -314,18 +312,25 @@ func (view *MainView) GetRoom(roomID string) ifc.RoomView {
|
|||||||
|
|
||||||
func (view *MainView) AddRoom(roomID string) {
|
func (view *MainView) AddRoom(roomID string) {
|
||||||
if view.roomList.Contains(roomID) {
|
if view.roomList.Contains(roomID) {
|
||||||
|
debug.Print("Add aborted", roomID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
debug.Print("Adding", roomID)
|
||||||
room := view.matrix.GetRoom(roomID)
|
room := view.matrix.GetRoom(roomID)
|
||||||
view.roomList.Add(room)
|
view.roomList.Add(room)
|
||||||
view.addRoomPage(room)
|
view.addRoomPage(room)
|
||||||
|
if !view.roomList.HasSelected() {
|
||||||
|
view.SwitchRoom(view.roomList.First())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *MainView) RemoveRoom(roomID string) {
|
func (view *MainView) RemoveRoom(roomID string) {
|
||||||
roomView := view.GetRoom(roomID)
|
roomView := view.GetRoom(roomID)
|
||||||
if roomView == nil {
|
if roomView == nil {
|
||||||
|
debug.Print("Remove aborted", roomID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
debug.Print("Removing", roomID)
|
||||||
|
|
||||||
view.roomList.Remove(roomView.MxRoom())
|
view.roomList.Remove(roomView.MxRoom())
|
||||||
view.SwitchRoom(view.roomList.Selected())
|
view.SwitchRoom(view.roomList.Selected())
|
||||||
@ -336,12 +341,11 @@ func (view *MainView) RemoveRoom(roomID string) {
|
|||||||
view.parent.Render()
|
view.parent.Render()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *MainView) SetRooms(roomIDs []string) {
|
func (view *MainView) SetRooms(rooms map[string]*rooms.Room) {
|
||||||
view.roomList.Clear()
|
view.roomList.Clear()
|
||||||
view.roomView.Clear()
|
view.roomView.Clear()
|
||||||
view.rooms = make(map[string]*RoomView)
|
view.rooms = make(map[string]*RoomView)
|
||||||
for _, roomID := range roomIDs {
|
for _, room := range rooms {
|
||||||
room := view.matrix.GetRoom(roomID)
|
|
||||||
view.roomList.Add(room)
|
view.roomList.Add(room)
|
||||||
view.addRoomPage(room)
|
view.addRoomPage(room)
|
||||||
}
|
}
|
||||||
@ -425,7 +429,7 @@ func (view *MainView) NotifyMessage(room *rooms.Room, message ifc.Message, shoul
|
|||||||
view.roomList.Bump(room)
|
view.roomList.Bump(room)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *MainView) LoadHistory(room string, initial bool) {
|
func (view *MainView) LoadHistory(room string) {
|
||||||
defer debug.Recover()
|
defer debug.Recover()
|
||||||
roomView := view.rooms[room]
|
roomView := view.rooms[room]
|
||||||
|
|
||||||
@ -446,12 +450,7 @@ func (view *MainView) LoadHistory(room string, initial bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if initial {
|
debug.Print("Fetching history for", room, "starting from", batch)
|
||||||
batch = view.config.Session.NextBatch
|
|
||||||
debug.Print("Loading initial history for", room)
|
|
||||||
} else {
|
|
||||||
debug.Print("Loading more history for", room, "starting from", batch)
|
|
||||||
}
|
|
||||||
history, prevBatch, err := view.matrix.GetHistory(roomView.Room.ID, batch, 50)
|
history, prevBatch, err := view.matrix.GetHistory(roomView.Room.ID, batch, 50)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
roomView.AddServiceMessage("Failed to fetch history")
|
roomView.AddServiceMessage("Failed to fetch history")
|
||||||
|
Loading…
Reference in New Issue
Block a user