parent
c88801a657
commit
8a3fbc24ab
@ -35,6 +35,7 @@ type MatrixContainer interface {
|
|||||||
SendMessage(roomID, msgtype, message string) (string, error)
|
SendMessage(roomID, msgtype, message string) (string, error)
|
||||||
SendMarkdownMessage(roomID, msgtype, message string) (string, error)
|
SendMarkdownMessage(roomID, msgtype, message string) (string, error)
|
||||||
SendTyping(roomID string, typing bool)
|
SendTyping(roomID string, typing bool)
|
||||||
|
MarkRead(roomID, eventID string)
|
||||||
JoinRoom(roomID, server string) (*rooms.Room, error)
|
JoinRoom(roomID, server string) (*rooms.Room, error)
|
||||||
LeaveRoom(roomID string) error
|
LeaveRoom(roomID string) error
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ type MainView interface {
|
|||||||
SetRooms(rooms map[string]*rooms.Room)
|
SetRooms(rooms map[string]*rooms.Room)
|
||||||
SaveAllHistory()
|
SaveAllHistory()
|
||||||
|
|
||||||
UpdateTags(room *rooms.Room, newTags []rooms.RoomTag)
|
UpdateTags(room *rooms.Room)
|
||||||
|
|
||||||
SetTyping(roomID string, users []string)
|
SetTyping(roomID string, users []string)
|
||||||
ParseEvent(roomView RoomView, evt *gomatrix.Event) Message
|
ParseEvent(roomView RoomView, evt *gomatrix.Event) Message
|
||||||
|
@ -177,7 +177,9 @@ func (c *Container) OnLogin() {
|
|||||||
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.receipt", c.HandleReadReceipt)
|
||||||
c.syncer.OnEventType("m.typing", c.HandleTyping)
|
c.syncer.OnEventType("m.typing", c.HandleTyping)
|
||||||
|
c.syncer.OnEventType("m.direct", c.HandleDirectChatInfo)
|
||||||
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.syncer.InitDoneCallback = func() {
|
||||||
@ -228,7 +230,7 @@ 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(source EventSource, evt *gomatrix.Event) {
|
func (c *Container) HandleMessage(source EventSource, evt *gomatrix.Event) {
|
||||||
if source & EventSourceLeave != 0 {
|
if source&EventSourceLeave != 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mainView := c.ui.MainView()
|
mainView := c.ui.MainView()
|
||||||
@ -253,6 +255,82 @@ func (c *Container) HandleMessage(source EventSource, evt *gomatrix.Event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Container) parseReadReceipt(evt *gomatrix.Event) (largestTimestampEvent string) {
|
||||||
|
var largestTimestamp int64
|
||||||
|
for eventID, rawContent := range evt.Content {
|
||||||
|
content, ok := rawContent.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
mRead, ok := content["m.read"].(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
myInfo, ok := mRead[c.config.Session.UserID].(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ts, ok := myInfo["ts"].(float64)
|
||||||
|
if int64(ts) > largestTimestamp {
|
||||||
|
largestTimestamp = int64(ts)
|
||||||
|
largestTimestampEvent = eventID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Container) HandleReadReceipt(source EventSource, evt *gomatrix.Event) {
|
||||||
|
if source&EventSourceLeave != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lastReadEvent := c.parseReadReceipt(evt)
|
||||||
|
if len(lastReadEvent) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
room := c.GetRoom(evt.RoomID)
|
||||||
|
room.MarkRead(lastReadEvent)
|
||||||
|
c.ui.Render()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Container) parseDirectChatInfo(evt *gomatrix.Event) (map[*rooms.Room]bool){
|
||||||
|
directChats := make(map[*rooms.Room]bool)
|
||||||
|
for _, rawRoomIDList := range evt.Content {
|
||||||
|
roomIDList, ok := rawRoomIDList.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rawRoomID := range roomIDList {
|
||||||
|
roomID, ok := rawRoomID.(string)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
room := c.GetRoom(roomID)
|
||||||
|
if room != nil && !room.HasLeft {
|
||||||
|
directChats[room] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return directChats
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Container) HandleDirectChatInfo(source EventSource, evt *gomatrix.Event) {
|
||||||
|
directChats := c.parseDirectChatInfo(evt)
|
||||||
|
for _, room := range c.config.Session.Rooms {
|
||||||
|
shouldBeDirect := directChats[room]
|
||||||
|
if shouldBeDirect != room.IsDirect {
|
||||||
|
room.IsDirect = shouldBeDirect
|
||||||
|
c.ui.MainView().UpdateTags(room)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// HandlePushRules is the event handler for the m.push_rules account data event.
|
// HandlePushRules is the event handler for the m.push_rules account data event.
|
||||||
func (c *Container) HandlePushRules(source EventSource, evt *gomatrix.Event) {
|
func (c *Container) HandlePushRules(source EventSource, evt *gomatrix.Event) {
|
||||||
debug.Print("Received updated push rules")
|
debug.Print("Received updated push rules")
|
||||||
@ -285,7 +363,8 @@ func (c *Container) HandleTag(source EventSource, evt *gomatrix.Event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mainView := c.ui.MainView()
|
mainView := c.ui.MainView()
|
||||||
mainView.UpdateTags(room, newTags)
|
room.RawTags = newTags
|
||||||
|
mainView.UpdateTags(room)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Container) processOwnMembershipChange(evt *gomatrix.Event) {
|
func (c *Container) processOwnMembershipChange(evt *gomatrix.Event) {
|
||||||
@ -314,8 +393,8 @@ func (c *Container) processOwnMembershipChange(evt *gomatrix.Event) {
|
|||||||
|
|
||||||
// HandleMembership is the event handler for the m.room.member state event.
|
// HandleMembership is the event handler for the m.room.member state event.
|
||||||
func (c *Container) HandleMembership(source EventSource, evt *gomatrix.Event) {
|
func (c *Container) HandleMembership(source EventSource, evt *gomatrix.Event) {
|
||||||
isLeave := source & EventSourceLeave != 0
|
isLeave := source&EventSourceLeave != 0
|
||||||
isTimeline := source & EventSourceTimeline != 0
|
isTimeline := source&EventSourceTimeline != 0
|
||||||
isNonTimelineLeave := isLeave && !isTimeline
|
isNonTimelineLeave := isLeave && !isTimeline
|
||||||
if !c.config.Session.InitialSyncDone && isNonTimelineLeave {
|
if !c.config.Session.InitialSyncDone && isNonTimelineLeave {
|
||||||
return
|
return
|
||||||
@ -356,6 +435,11 @@ func (c *Container) HandleTyping(source EventSource, evt *gomatrix.Event) {
|
|||||||
c.ui.MainView().SetTyping(evt.RoomID, strUsers)
|
c.ui.MainView().SetTyping(evt.RoomID, strUsers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Container) MarkRead(roomID, eventID string) {
|
||||||
|
urlPath := c.client.BuildURL("rooms", roomID, "receipt", "m.read", eventID)
|
||||||
|
c.client.MakeRequest("POST", urlPath, struct{}{}, nil)
|
||||||
|
}
|
||||||
|
|
||||||
// SendMessage sends a message with the given text to the given room.
|
// SendMessage sends a message with the given text to the given room.
|
||||||
func (c *Container) SendMessage(roomID, msgtype, text string) (string, error) {
|
func (c *Container) SendMessage(roomID, msgtype, text string) (string, error) {
|
||||||
defer debug.Recover()
|
defer debug.Recover()
|
||||||
|
@ -43,6 +43,12 @@ type RoomTag struct {
|
|||||||
Order string
|
Order string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UnreadMessage struct {
|
||||||
|
EventID string
|
||||||
|
Counted bool
|
||||||
|
Highlight bool
|
||||||
|
}
|
||||||
|
|
||||||
// Room represents a single Matrix room.
|
// Room represents a single Matrix room.
|
||||||
type Room struct {
|
type Room struct {
|
||||||
*gomatrix.Room
|
*gomatrix.Room
|
||||||
@ -57,13 +63,11 @@ type Room struct {
|
|||||||
SessionUserID string
|
SessionUserID string
|
||||||
|
|
||||||
// The number of unread messages that were notified about.
|
// The number of unread messages that were notified about.
|
||||||
UnreadMessages int
|
UnreadMessages []UnreadMessage
|
||||||
// Whether or not any of the unread messages were highlights.
|
unreadCountCache *int
|
||||||
Highlighted bool
|
highlightCache *bool
|
||||||
// Whether or not the room contains any new messages.
|
// Whether or not this room is marked as a direct chat.
|
||||||
// This can be true even when UnreadMessages is zero if there's
|
IsDirect bool
|
||||||
// a notificationless message like bot notices.
|
|
||||||
HasNewMessages bool
|
|
||||||
|
|
||||||
// List of tags given to this room
|
// List of tags given to this room
|
||||||
RawTags []RoomTag
|
RawTags []RoomTag
|
||||||
@ -110,14 +114,74 @@ func (room *Room) UnlockHistory() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MarkRead clears the new message statuses on this room.
|
// MarkRead clears the new message statuses on this room.
|
||||||
func (room *Room) MarkRead() {
|
func (room *Room) MarkRead(eventID string) {
|
||||||
room.UnreadMessages = 0
|
readToIndex := -1
|
||||||
room.Highlighted = false
|
for index, unreadMessage := range room.UnreadMessages {
|
||||||
room.HasNewMessages = false
|
if unreadMessage.EventID == eventID {
|
||||||
|
readToIndex = index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if readToIndex >= 0 {
|
||||||
|
room.UnreadMessages = room.UnreadMessages[readToIndex+1:]
|
||||||
|
room.highlightCache = nil
|
||||||
|
room.unreadCountCache = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (room *Room) UnreadCount() int {
|
||||||
|
if room.unreadCountCache == nil {
|
||||||
|
room.unreadCountCache = new(int)
|
||||||
|
for _, unreadMessage := range room.UnreadMessages {
|
||||||
|
if unreadMessage.Counted {
|
||||||
|
*room.unreadCountCache++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *room.unreadCountCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (room *Room) Highlighted() bool {
|
||||||
|
if room.highlightCache == nil {
|
||||||
|
room.highlightCache = new(bool)
|
||||||
|
for _, unreadMessage := range room.UnreadMessages {
|
||||||
|
if unreadMessage.Highlight {
|
||||||
|
*room.highlightCache = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *room.highlightCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (room *Room) HasNewMessages() bool {
|
||||||
|
return len(room.UnreadMessages) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (room *Room) AddUnread(eventID string, counted, highlight bool) {
|
||||||
|
room.UnreadMessages = append(room.UnreadMessages, UnreadMessage{
|
||||||
|
EventID: eventID,
|
||||||
|
Counted: counted,
|
||||||
|
Highlight: highlight,
|
||||||
|
})
|
||||||
|
if counted {
|
||||||
|
if room.unreadCountCache == nil {
|
||||||
|
room.unreadCountCache = new(int)
|
||||||
|
}
|
||||||
|
*room.unreadCountCache++
|
||||||
|
}
|
||||||
|
if highlight {
|
||||||
|
if room.highlightCache == nil {
|
||||||
|
room.highlightCache = new(bool)
|
||||||
|
}
|
||||||
|
*room.highlightCache = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (room *Room) Tags() []RoomTag {
|
func (room *Room) Tags() []RoomTag {
|
||||||
if len(room.RawTags) == 0 {
|
if len(room.RawTags) == 0 {
|
||||||
|
if room.IsDirect {
|
||||||
|
return []RoomTag{{"net.maunium.gomuks.fake.direct", "0.5"}}
|
||||||
|
}
|
||||||
return []RoomTag{{"", "0.5"}}
|
return []RoomTag{{"", "0.5"}}
|
||||||
}
|
}
|
||||||
return room.RawTags
|
return room.RawTags
|
||||||
|
@ -215,11 +215,19 @@ func TestRoom_GetTitle_Members_GroupChat(t *testing.T) {
|
|||||||
|
|
||||||
func TestRoom_MarkRead(t *testing.T) {
|
func TestRoom_MarkRead(t *testing.T) {
|
||||||
room := rooms.NewRoom("!test:maunium.net", "@tulir:maunium.net")
|
room := rooms.NewRoom("!test:maunium.net", "@tulir:maunium.net")
|
||||||
room.UnreadMessages = 123
|
|
||||||
room.Highlighted = true
|
room.AddUnread("foo", true, false)
|
||||||
room.HasNewMessages = true
|
assert.Equal(t, 1, room.UnreadCount())
|
||||||
room.MarkRead()
|
assert.False(t, room.Highlighted())
|
||||||
assert.Zero(t, room.UnreadMessages)
|
|
||||||
assert.False(t, room.Highlighted)
|
room.AddUnread("bar", true, false)
|
||||||
assert.False(t, room.HasNewMessages)
|
assert.Equal(t, 2, room.UnreadCount())
|
||||||
|
assert.False(t, room.Highlighted())
|
||||||
|
|
||||||
|
room.AddUnread("asd", false, true)
|
||||||
|
assert.Equal(t, 2, room.UnreadCount())
|
||||||
|
assert.True(t, room.Highlighted())
|
||||||
|
|
||||||
|
room.MarkRead("")
|
||||||
|
assert.Empty(t, room.UnreadMessages)
|
||||||
}
|
}
|
||||||
|
@ -177,14 +177,14 @@ func (s *GomuksSyncer) GetFilterJSON(userID string) json.RawMessage {
|
|||||||
Limit: 50,
|
Limit: 50,
|
||||||
},
|
},
|
||||||
Ephemeral: gomatrix.FilterPart{
|
Ephemeral: gomatrix.FilterPart{
|
||||||
Types: []string{"m.typing"},
|
Types: []string{"m.typing", "m.receipt"},
|
||||||
},
|
},
|
||||||
AccountData: gomatrix.FilterPart{
|
AccountData: gomatrix.FilterPart{
|
||||||
Types: []string{"m.tag"},
|
Types: []string{"m.tag"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
AccountData: gomatrix.FilterPart{
|
AccountData: gomatrix.FilterPart{
|
||||||
Types: []string{"m.push_rules"},
|
Types: []string{"m.push_rules", "m.direct"},
|
||||||
},
|
},
|
||||||
Presence: gomatrix.FilterPart{
|
Presence: gomatrix.FilterPart{
|
||||||
Types: []string{},
|
Types: []string{},
|
||||||
|
@ -265,6 +265,7 @@ func (list *RoomList) Contains(roomID string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (list *RoomList) Add(room *rooms.Room) {
|
func (list *RoomList) Add(room *rooms.Room) {
|
||||||
|
debug.Print("Adding room to list", room.ID, room.GetTitle(), room.IsDirect, room.Tags())
|
||||||
for _, tag := range room.Tags() {
|
for _, tag := range room.Tags() {
|
||||||
list.AddToTag(tag, room)
|
list.AddToTag(tag, room)
|
||||||
}
|
}
|
||||||
@ -289,10 +290,6 @@ func (list *RoomList) CheckTag(tag string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (list *RoomList) AddToTag(tag rooms.RoomTag, room *rooms.Room) {
|
func (list *RoomList) AddToTag(tag rooms.RoomTag, room *rooms.Room) {
|
||||||
if tag.Tag == "" && len(room.GetMembers()) == 2 {
|
|
||||||
tag.Tag = "net.maunium.gomuks.fake.direct"
|
|
||||||
}
|
|
||||||
|
|
||||||
tagRoomList, ok := list.items[tag.Tag]
|
tagRoomList, ok := list.items[tag.Tag]
|
||||||
if !ok {
|
if !ok {
|
||||||
list.items[tag.Tag] = newTagRoomList(convertRoom(room))
|
list.items[tag.Tag] = newTagRoomList(convertRoom(room))
|
||||||
@ -304,8 +301,8 @@ func (list *RoomList) AddToTag(tag rooms.RoomTag, room *rooms.Room) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (list *RoomList) Remove(room *rooms.Room) {
|
func (list *RoomList) Remove(room *rooms.Room) {
|
||||||
for _, tag := range room.Tags() {
|
for _, tag := range list.tags {
|
||||||
list.RemoveFromTag(tag.Tag, room)
|
list.RemoveFromTag(tag, room)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -707,21 +704,22 @@ func (list *RoomList) Draw(screen tcell.Screen) {
|
|||||||
if tag == list.selectedTag && item.Room == list.selected {
|
if tag == list.selectedTag && item.Room == list.selected {
|
||||||
style = style.Foreground(list.selectedTextColor).Background(list.selectedBackgroundColor)
|
style = style.Foreground(list.selectedTextColor).Background(list.selectedBackgroundColor)
|
||||||
}
|
}
|
||||||
if item.HasNewMessages {
|
if item.HasNewMessages() {
|
||||||
style = style.Bold(true)
|
style = style.Bold(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
if item.UnreadMessages > 0 {
|
unreadCount := item.UnreadCount()
|
||||||
|
if unreadCount > 0 {
|
||||||
unreadMessageCount := "99+"
|
unreadMessageCount := "99+"
|
||||||
if item.UnreadMessages < 100 {
|
if unreadCount < 100 {
|
||||||
unreadMessageCount = strconv.Itoa(item.UnreadMessages)
|
unreadMessageCount = strconv.Itoa(unreadCount)
|
||||||
}
|
}
|
||||||
if item.Highlighted {
|
if item.Highlighted() {
|
||||||
unreadMessageCount += "!"
|
unreadMessageCount += "!"
|
||||||
}
|
}
|
||||||
unreadMessageCount = fmt.Sprintf("(%s)", unreadMessageCount)
|
unreadMessageCount = fmt.Sprintf("(%s)", unreadMessageCount)
|
||||||
widget.WriteLine(screen, tview.AlignRight, unreadMessageCount, x+lineWidth-6, y, 6, style)
|
widget.WriteLine(screen, tview.AlignRight, unreadMessageCount, x+lineWidth-7, y, 7, style)
|
||||||
lineWidth -= len(unreadMessageCount) + 1
|
lineWidth -= len(unreadMessageCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
widget.WriteLinePadded(screen, tview.AlignLeft, text, x, y, lineWidth, style)
|
widget.WriteLinePadded(screen, tview.AlignLeft, text, x, y, lineWidth, style)
|
||||||
|
@ -67,15 +67,25 @@ func (ui *GomuksUI) NewMainView() tview.Primitive {
|
|||||||
mainView.AddItem(mainView.roomList, 25, 0, false)
|
mainView.AddItem(mainView.roomList, 25, 0, false)
|
||||||
mainView.AddItem(widget.NewBorder(), 1, 0, false)
|
mainView.AddItem(widget.NewBorder(), 1, 0, false)
|
||||||
mainView.AddItem(mainView.roomView, 0, 1, true)
|
mainView.AddItem(mainView.roomView, 0, 1, true)
|
||||||
mainView.BumpFocus()
|
mainView.BumpFocus(nil)
|
||||||
|
|
||||||
ui.mainView = mainView
|
ui.mainView = mainView
|
||||||
|
|
||||||
return mainView
|
return mainView
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *MainView) BumpFocus() {
|
func (view *MainView) BumpFocus(roomView *RoomView) {
|
||||||
view.lastFocusTime = time.Now()
|
view.lastFocusTime = time.Now()
|
||||||
|
view.MarkRead(roomView)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (view *MainView) MarkRead(roomView *RoomView) {
|
||||||
|
if roomView != nil && roomView.Room.HasNewMessages() && roomView.MessageView().ScrollOffset == 0 {
|
||||||
|
msgList := roomView.MessageView().messages
|
||||||
|
msg := msgList[len(msgList)-1]
|
||||||
|
roomView.Room.MarkRead(msg.ID())
|
||||||
|
view.matrix.MarkRead(roomView.Room.ID, msg.ID())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *MainView) InputChanged(roomView *RoomView, text string) {
|
func (view *MainView) InputChanged(roomView *RoomView, text string) {
|
||||||
@ -182,7 +192,7 @@ func (view *MainView) HandleCommand(roomView *RoomView, command string, args []s
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (view *MainView) KeyEventHandler(roomView *RoomView, key *tcell.EventKey) *tcell.EventKey {
|
func (view *MainView) KeyEventHandler(roomView *RoomView, key *tcell.EventKey) *tcell.EventKey {
|
||||||
view.BumpFocus()
|
view.BumpFocus(roomView)
|
||||||
|
|
||||||
k := key.Key()
|
k := key.Key()
|
||||||
if key.Modifiers() == tcell.ModCtrl || key.Modifiers() == tcell.ModAlt {
|
if key.Modifiers() == tcell.ModCtrl || key.Modifiers() == tcell.ModAlt {
|
||||||
@ -232,7 +242,7 @@ func (view *MainView) MouseEventHandler(roomView *RoomView, event *tcell.EventMo
|
|||||||
if event.Buttons() == tcell.ButtonNone || event.HasMotion() {
|
if event.Buttons() == tcell.ButtonNone || event.HasMotion() {
|
||||||
return event
|
return event
|
||||||
}
|
}
|
||||||
view.BumpFocus()
|
view.BumpFocus(roomView)
|
||||||
|
|
||||||
msgView := roomView.MessageView()
|
msgView := roomView.MessageView()
|
||||||
x, y := event.Position()
|
x, y := event.Position()
|
||||||
@ -251,12 +261,8 @@ func (view *MainView) MouseEventHandler(roomView *RoomView, event *tcell.EventMo
|
|||||||
}
|
}
|
||||||
case tcell.WheelDown:
|
case tcell.WheelDown:
|
||||||
msgView.AddScrollOffset(-WheelScrollOffsetDiff)
|
msgView.AddScrollOffset(-WheelScrollOffsetDiff)
|
||||||
|
|
||||||
view.parent.Render()
|
view.parent.Render()
|
||||||
|
view.MarkRead(roomView)
|
||||||
if msgView.ScrollOffset == 0 {
|
|
||||||
roomView.Room.MarkRead()
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
if msgView.HandleClick(x-mx, y-my, event.Buttons()) {
|
if msgView.HandleClick(x-mx, y-my, event.Buttons()) {
|
||||||
view.parent.Render()
|
view.parent.Render()
|
||||||
@ -293,9 +299,12 @@ func (view *MainView) SwitchRoom(tag string, room *rooms.Room) {
|
|||||||
|
|
||||||
view.roomView.SwitchToPage(room.ID)
|
view.roomView.SwitchToPage(room.ID)
|
||||||
roomView := view.rooms[room.ID]
|
roomView := view.rooms[room.ID]
|
||||||
if roomView.MessageView().ScrollOffset == 0 {
|
if roomView == nil {
|
||||||
roomView.Room.MarkRead()
|
debug.Print("Tried to switch to non-nil room with nil roomView!")
|
||||||
|
debug.Print(tag, room)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
view.MarkRead(roomView)
|
||||||
view.roomList.SetSelected(tag, room)
|
view.roomList.SetSelected(tag, room)
|
||||||
view.parent.app.SetFocus(view)
|
view.parent.app.SetFocus(view)
|
||||||
view.parent.Render()
|
view.parent.Render()
|
||||||
@ -353,10 +362,10 @@ func (view *MainView) GetRoom(roomID string) ifc.RoomView {
|
|||||||
|
|
||||||
func (view *MainView) AddRoom(room *rooms.Room) {
|
func (view *MainView) AddRoom(room *rooms.Room) {
|
||||||
if view.roomList.Contains(room.ID) {
|
if view.roomList.Contains(room.ID) {
|
||||||
debug.Print("Add aborted", room.ID)
|
debug.Print("Add aborted (room exists)", room.ID, room.GetTitle())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
debug.Print("Adding", room.ID)
|
debug.Print("Adding", room.ID, room.GetTitle())
|
||||||
view.roomList.Add(room)
|
view.roomList.Add(room)
|
||||||
view.addRoomPage(room)
|
view.addRoomPage(room)
|
||||||
if !view.roomList.HasSelected() {
|
if !view.roomList.HasSelected() {
|
||||||
@ -367,10 +376,10 @@ func (view *MainView) AddRoom(room *rooms.Room) {
|
|||||||
func (view *MainView) RemoveRoom(room *rooms.Room) {
|
func (view *MainView) RemoveRoom(room *rooms.Room) {
|
||||||
roomView := view.GetRoom(room.ID)
|
roomView := view.GetRoom(room.ID)
|
||||||
if roomView == nil {
|
if roomView == nil {
|
||||||
debug.Print("Remove aborted", room.ID)
|
debug.Print("Remove aborted (not found)", room.ID, room.GetTitle())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
debug.Print("Removing", room.ID)
|
debug.Print("Removing", room.ID, room.GetTitle())
|
||||||
|
|
||||||
view.roomList.Remove(room)
|
view.roomList.Remove(room)
|
||||||
view.SwitchRoom(view.roomList.Selected())
|
view.SwitchRoom(view.roomList.Selected())
|
||||||
@ -395,38 +404,12 @@ func (view *MainView) SetRooms(rooms map[string]*rooms.Room) {
|
|||||||
view.SwitchRoom(view.roomList.First())
|
view.SwitchRoom(view.roomList.First())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *MainView) UpdateTags(room *rooms.Room, newTags []rooms.RoomTag) {
|
func (view *MainView) UpdateTags(room *rooms.Room) {
|
||||||
if len(newTags) == 0 {
|
if !view.roomList.Contains(room.ID) {
|
||||||
for _, tag := range room.RawTags {
|
return
|
||||||
view.roomList.RemoveFromTag(tag.Tag, room)
|
|
||||||
}
|
|
||||||
view.roomList.AddToTag(rooms.RoomTag{Tag: "", Order: "0.5"}, room)
|
|
||||||
} else if len(room.RawTags) == 0 {
|
|
||||||
view.roomList.RemoveFromTag("", room)
|
|
||||||
for _, tag := range newTags {
|
|
||||||
view.roomList.AddToTag(tag, room)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
NewTags:
|
|
||||||
for _, newTag := range newTags {
|
|
||||||
for _, oldTag := range room.RawTags {
|
|
||||||
if newTag.Tag == oldTag.Tag {
|
|
||||||
continue NewTags
|
|
||||||
}
|
|
||||||
}
|
|
||||||
view.roomList.AddToTag(newTag, room)
|
|
||||||
}
|
|
||||||
OldTags:
|
|
||||||
for _, oldTag := range room.RawTags {
|
|
||||||
for _, newTag := range newTags {
|
|
||||||
if newTag.Tag == oldTag.Tag {
|
|
||||||
continue OldTags
|
|
||||||
}
|
|
||||||
}
|
|
||||||
view.roomList.RemoveFromTag(oldTag.Tag, room)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
room.RawTags = newTags
|
view.roomList.Remove(room)
|
||||||
|
view.roomList.Add(room)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *MainView) SetTyping(room string, users []string) {
|
func (view *MainView) SetTyping(room string, users []string) {
|
||||||
@ -449,21 +432,20 @@ func (view *MainView) NotifyMessage(room *rooms.Room, message ifc.Message, shoul
|
|||||||
// Whether or not the room where the message came is the currently shown room.
|
// Whether or not the room where the message came is the currently shown room.
|
||||||
isCurrent := room == view.roomList.SelectedRoom()
|
isCurrent := room == view.roomList.SelectedRoom()
|
||||||
// Whether or not the terminal window is focused.
|
// Whether or not the terminal window is focused.
|
||||||
isFocused := time.Now().Add(-30 * time.Second).Before(view.lastFocusTime)
|
recentlyFocused := time.Now().Add(-30 * time.Second).Before(view.lastFocusTime)
|
||||||
|
isFocused := time.Now().Add(-5 * time.Second).Before(view.lastFocusTime)
|
||||||
|
|
||||||
// Whether or not the push rules say this message should be notified about.
|
// Whether or not the push rules say this message should be notified about.
|
||||||
shouldNotify := (should.Notify || !should.NotifySpecified) && message.Sender() != view.config.Session.UserID
|
shouldNotify := (should.Notify || !should.NotifySpecified) && message.Sender() != view.config.Session.UserID
|
||||||
|
|
||||||
if !isCurrent {
|
if !isCurrent || !isFocused {
|
||||||
// The message is not in the current room, show new message status in room list.
|
// The message is not in the current room, show new message status in room list.
|
||||||
room.HasNewMessages = true
|
room.AddUnread(message.ID(), shouldNotify, should.Highlight)
|
||||||
room.Highlighted = should.Highlight || room.Highlighted
|
} else {
|
||||||
if shouldNotify {
|
view.matrix.MarkRead(room.ID, message.ID())
|
||||||
room.UnreadMessages++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if shouldNotify && !isFocused {
|
if shouldNotify && !recentlyFocused {
|
||||||
// Push rules say notify and the terminal is not focused, send desktop notification.
|
// Push rules say notify and the terminal is not focused, send desktop notification.
|
||||||
shouldPlaySound := should.PlaySound && should.SoundName == "default"
|
shouldPlaySound := should.PlaySound && should.SoundName == "default"
|
||||||
sendNotification(room, message.Sender(), message.NotificationContent(), should.Highlight, shouldPlaySound)
|
sendNotification(room, message.Sender(), message.NotificationContent(), should.Highlight, shouldPlaySound)
|
||||||
|
Loading…
Reference in New Issue
Block a user