mirror of
https://github.com/tulir/gomuks.git
synced 2025-04-20 10:33:41 -05:00
hicli/database,web/roomlist: show marked unread status
This commit is contained in:
parent
ead1365c12
commit
80f9a8bb6b
11 changed files with 49 additions and 9 deletions
|
@ -23,7 +23,7 @@ const (
|
||||||
getRoomBaseQuery = `
|
getRoomBaseQuery = `
|
||||||
SELECT room_id, creation_content, tombstone_content, name, name_quality, avatar, explicit_avatar, topic, canonical_alias,
|
SELECT room_id, creation_content, tombstone_content, name, name_quality, avatar, explicit_avatar, topic, canonical_alias,
|
||||||
lazy_load_summary, encryption_event, has_member_list, preview_event_rowid, sorting_timestamp,
|
lazy_load_summary, encryption_event, has_member_list, preview_event_rowid, sorting_timestamp,
|
||||||
unread_highlights, unread_notifications, unread_messages, prev_batch
|
unread_highlights, unread_notifications, unread_messages, marked_unread, prev_batch
|
||||||
FROM room
|
FROM room
|
||||||
`
|
`
|
||||||
getRoomsBySortingTimestampQuery = getRoomBaseQuery + `WHERE sorting_timestamp < $1 AND sorting_timestamp > 0 ORDER BY sorting_timestamp DESC LIMIT $2`
|
getRoomsBySortingTimestampQuery = getRoomBaseQuery + `WHERE sorting_timestamp < $1 AND sorting_timestamp > 0 ORDER BY sorting_timestamp DESC LIMIT $2`
|
||||||
|
@ -50,7 +50,8 @@ const (
|
||||||
unread_highlights = COALESCE($15, room.unread_highlights),
|
unread_highlights = COALESCE($15, room.unread_highlights),
|
||||||
unread_notifications = COALESCE($16, room.unread_notifications),
|
unread_notifications = COALESCE($16, room.unread_notifications),
|
||||||
unread_messages = COALESCE($17, room.unread_messages),
|
unread_messages = COALESCE($17, room.unread_messages),
|
||||||
prev_batch = COALESCE($18, room.prev_batch)
|
marked_unread = COALESCE($18, room.marked_unread),
|
||||||
|
prev_batch = COALESCE($19, room.prev_batch)
|
||||||
WHERE room_id = $1
|
WHERE room_id = $1
|
||||||
`
|
`
|
||||||
setRoomPrevBatchQuery = `
|
setRoomPrevBatchQuery = `
|
||||||
|
@ -157,6 +158,7 @@ type Room struct {
|
||||||
PreviewEventRowID EventRowID `json:"preview_event_rowid"`
|
PreviewEventRowID EventRowID `json:"preview_event_rowid"`
|
||||||
SortingTimestamp jsontime.UnixMilli `json:"sorting_timestamp"`
|
SortingTimestamp jsontime.UnixMilli `json:"sorting_timestamp"`
|
||||||
UnreadCounts
|
UnreadCounts
|
||||||
|
MarkedUnread *bool `json:"marked_unread,omitempty"`
|
||||||
|
|
||||||
PrevBatch string `json:"prev_batch"`
|
PrevBatch string `json:"prev_batch"`
|
||||||
}
|
}
|
||||||
|
@ -220,6 +222,10 @@ func (r *Room) CheckChangesAndCopyInto(other *Room) (hasChanges bool) {
|
||||||
other.UnreadMessages = r.UnreadMessages
|
other.UnreadMessages = r.UnreadMessages
|
||||||
hasChanges = true
|
hasChanges = true
|
||||||
}
|
}
|
||||||
|
if r.MarkedUnread != other.MarkedUnread {
|
||||||
|
other.MarkedUnread = r.MarkedUnread
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
if r.PrevBatch != "" && other.PrevBatch == "" {
|
if r.PrevBatch != "" && other.PrevBatch == "" {
|
||||||
other.PrevBatch = r.PrevBatch
|
other.PrevBatch = r.PrevBatch
|
||||||
hasChanges = true
|
hasChanges = true
|
||||||
|
@ -248,6 +254,7 @@ func (r *Room) Scan(row dbutil.Scannable) (*Room, error) {
|
||||||
&r.UnreadHighlights,
|
&r.UnreadHighlights,
|
||||||
&r.UnreadNotifications,
|
&r.UnreadNotifications,
|
||||||
&r.UnreadMessages,
|
&r.UnreadMessages,
|
||||||
|
&r.MarkedUnread,
|
||||||
&prevBatch,
|
&prevBatch,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -278,6 +285,7 @@ func (r *Room) sqlVariables() []any {
|
||||||
r.UnreadHighlights,
|
r.UnreadHighlights,
|
||||||
r.UnreadNotifications,
|
r.UnreadNotifications,
|
||||||
r.UnreadMessages,
|
r.UnreadMessages,
|
||||||
|
r.MarkedUnread,
|
||||||
dbutil.StrPtr(r.PrevBatch),
|
dbutil.StrPtr(r.PrevBatch),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
-- v0 -> v6 (compatible with v5+): Latest revision
|
-- v0 -> v7 (compatible with v5+): Latest revision
|
||||||
CREATE TABLE account (
|
CREATE TABLE account (
|
||||||
user_id TEXT NOT NULL PRIMARY KEY,
|
user_id TEXT NOT NULL PRIMARY KEY,
|
||||||
device_id TEXT NOT NULL,
|
device_id TEXT NOT NULL,
|
||||||
|
@ -29,6 +29,7 @@ CREATE TABLE room (
|
||||||
unread_highlights INTEGER NOT NULL DEFAULT 0,
|
unread_highlights INTEGER NOT NULL DEFAULT 0,
|
||||||
unread_notifications INTEGER NOT NULL DEFAULT 0,
|
unread_notifications INTEGER NOT NULL DEFAULT 0,
|
||||||
unread_messages INTEGER NOT NULL DEFAULT 0,
|
unread_messages INTEGER NOT NULL DEFAULT 0,
|
||||||
|
marked_unread INTEGER NOT NULL DEFAULT false,
|
||||||
|
|
||||||
prev_batch TEXT,
|
prev_batch TEXT,
|
||||||
|
|
||||||
|
|
2
pkg/hicli/database/upgrades/07-marked-unread.sql
Normal file
2
pkg/hicli/database/upgrades/07-marked-unread.sql
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
-- v7 (compatible with v5+): Add room column for marking unread
|
||||||
|
ALTER TABLE room ADD COLUMN marked_unread INTEGER NOT NULL DEFAULT false;
|
|
@ -151,6 +151,12 @@ func (h *HiClient) SendMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HiClient) MarkRead(ctx context.Context, roomID id.RoomID, eventID id.EventID, receiptType event.ReceiptType) error {
|
func (h *HiClient) MarkRead(ctx context.Context, roomID id.RoomID, eventID id.EventID, receiptType event.ReceiptType) error {
|
||||||
|
room, err := h.DB.Room.Get(ctx, roomID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get room metadata: %w", err)
|
||||||
|
} else if room == nil {
|
||||||
|
return fmt.Errorf("unknown room")
|
||||||
|
}
|
||||||
content := &mautrix.ReqSetReadMarkers{
|
content := &mautrix.ReqSetReadMarkers{
|
||||||
FullyRead: eventID,
|
FullyRead: eventID,
|
||||||
}
|
}
|
||||||
|
@ -161,10 +167,16 @@ func (h *HiClient) MarkRead(ctx context.Context, roomID id.RoomID, eventID id.Ev
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("invalid receipt type: %v", receiptType)
|
return fmt.Errorf("invalid receipt type: %v", receiptType)
|
||||||
}
|
}
|
||||||
err := h.Client.SetReadMarkers(ctx, roomID, content)
|
err = h.Client.SetReadMarkers(ctx, roomID, content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to mark event as read: %w", err)
|
return fmt.Errorf("failed to mark event as read: %w", err)
|
||||||
}
|
}
|
||||||
|
if ptr.Val(room.MarkedUnread) {
|
||||||
|
err = h.Client.SetRoomAccountData(ctx, roomID, event.AccountDataMarkedUnread.Type, &event.MarkedUnreadEventContent{Unread: false})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to mark room as read: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"go.mau.fi/util/emojirunes"
|
"go.mau.fi/util/emojirunes"
|
||||||
"go.mau.fi/util/exzerolog"
|
"go.mau.fi/util/exzerolog"
|
||||||
"go.mau.fi/util/jsontime"
|
"go.mau.fi/util/jsontime"
|
||||||
|
"go.mau.fi/util/ptr"
|
||||||
"maunium.net/go/mautrix"
|
"maunium.net/go/mautrix"
|
||||||
"maunium.net/go/mautrix/crypto"
|
"maunium.net/go/mautrix/crypto"
|
||||||
"maunium.net/go/mautrix/crypto/olm"
|
"maunium.net/go/mautrix/crypto/olm"
|
||||||
|
@ -772,6 +773,10 @@ func (h *HiClient) processStateAndTimeline(
|
||||||
updatedRoom.Avatar = &dmAvatarURL
|
updatedRoom.Avatar = &dmAvatarURL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mu, ok := accountData[event.AccountDataMarkedUnread]
|
||||||
|
if ok {
|
||||||
|
updatedRoom.MarkedUnread = ptr.Ptr(gjson.GetBytes(mu.Content, "unread").Bool())
|
||||||
|
}
|
||||||
|
|
||||||
if len(receipts) > 0 {
|
if len(receipts) > 0 {
|
||||||
err = h.DB.Receipt.PutMany(ctx, room.ID, receipts...)
|
err = h.DB.Receipt.PutMany(ctx, room.ID, receipts...)
|
||||||
|
|
|
@ -50,6 +50,7 @@ export interface RoomListEntry {
|
||||||
unread_messages: number
|
unread_messages: number
|
||||||
unread_notifications: number
|
unread_notifications: number
|
||||||
unread_highlights: number
|
unread_highlights: number
|
||||||
|
marked_unread: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export class StateStore {
|
export class StateStore {
|
||||||
|
@ -102,6 +103,7 @@ export class StateStore {
|
||||||
entry.meta.unread_messages !== oldEntry.meta.current.unread_messages ||
|
entry.meta.unread_messages !== oldEntry.meta.current.unread_messages ||
|
||||||
entry.meta.unread_notifications !== oldEntry.meta.current.unread_notifications ||
|
entry.meta.unread_notifications !== oldEntry.meta.current.unread_notifications ||
|
||||||
entry.meta.unread_highlights !== oldEntry.meta.current.unread_highlights ||
|
entry.meta.unread_highlights !== oldEntry.meta.current.unread_highlights ||
|
||||||
|
entry.meta.marked_unread !== oldEntry.meta.current.marked_unread ||
|
||||||
entry.meta.preview_event_rowid !== oldEntry.meta.current.preview_event_rowid ||
|
entry.meta.preview_event_rowid !== oldEntry.meta.current.preview_event_rowid ||
|
||||||
entry.events.findIndex(evt => evt.rowid === entry.meta.preview_event_rowid) !== -1
|
entry.events.findIndex(evt => evt.rowid === entry.meta.preview_event_rowid) !== -1
|
||||||
}
|
}
|
||||||
|
@ -129,6 +131,7 @@ export class StateStore {
|
||||||
unread_messages: entry.meta.unread_messages,
|
unread_messages: entry.meta.unread_messages,
|
||||||
unread_notifications: entry.meta.unread_notifications,
|
unread_notifications: entry.meta.unread_notifications,
|
||||||
unread_highlights: entry.meta.unread_highlights,
|
unread_highlights: entry.meta.unread_highlights,
|
||||||
|
marked_unread: entry.meta.marked_unread,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@ export interface DBRoom {
|
||||||
unread_highlights: number
|
unread_highlights: number
|
||||||
unread_notifications: number
|
unread_notifications: number
|
||||||
unread_messages: number
|
unread_messages: number
|
||||||
|
marked_unread: boolean
|
||||||
|
|
||||||
prev_batch: string
|
prev_batch: string
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
--unread-counter-text-color: var(--inverted-text-color);
|
--unread-counter-text-color: var(--inverted-text-color);
|
||||||
--unread-counter-message-bg: rgba(0, 0, 0, 0.35);
|
--unread-counter-message-bg: rgba(0, 0, 0, 0.35);
|
||||||
--unread-counter-notification-bg: rgba(50, 150, 0, 0.7);
|
--unread-counter-notification-bg: rgba(50, 150, 0, 0.7);
|
||||||
|
--unread-counter-marked-unread-bg: var(--unread-counter-notification-bg);
|
||||||
--unread-counter-highlight-bg: rgba(200, 0, 0, 0.7);
|
--unread-counter-highlight-bg: rgba(200, 0, 0, 0.7);
|
||||||
|
|
||||||
--sender-color-0: #a4041d;
|
--sender-color-0: #a4041d;
|
||||||
|
|
|
@ -68,8 +68,9 @@ const EntryInner = ({ room }: InnerProps) => {
|
||||||
<div className="room-name">{room.name}</div>
|
<div className="room-name">{room.name}</div>
|
||||||
{previewText && <div className="message-preview" title={previewText}>{croppedPreviewText}</div>}
|
{previewText && <div className="message-preview" title={previewText}>{croppedPreviewText}</div>}
|
||||||
</div>
|
</div>
|
||||||
{room.unread_messages ? <div className="room-entry-unreads">
|
{(room.unread_messages || room.marked_unread) ? <div className="room-entry-unreads">
|
||||||
<div className={`unread-count ${
|
<div className={`unread-count ${
|
||||||
|
room.marked_unread ? "marked-unread" : ""} ${
|
||||||
room.unread_notifications ? "notified" : ""} ${
|
room.unread_notifications ? "notified" : ""} ${
|
||||||
room.unread_highlights ? "highlighted" : ""}`}
|
room.unread_highlights ? "highlighted" : ""}`}
|
||||||
>
|
>
|
||||||
|
|
|
@ -117,7 +117,7 @@ div.room-entry {
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
font-size: .75em;
|
font-size: .75em;
|
||||||
|
|
||||||
&.notified, &.highlighted {
|
&.notified, &.marked-unread, &.highlighted {
|
||||||
width: 1.5rem;
|
width: 1.5rem;
|
||||||
height: 1.5rem;
|
height: 1.5rem;
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
|
@ -125,7 +125,11 @@ div.room-entry {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.notified:not(.highlighted) {
|
&.marked-unread {
|
||||||
|
background-color: var(--unread-counter-marked-unread-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.notified {
|
||||||
background-color: var(--unread-counter-notification-bg);
|
background-color: var(--unread-counter-notification-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,10 +75,12 @@ const TimelineView = () => {
|
||||||
&& focused
|
&& focused
|
||||||
&& newestEvent
|
&& newestEvent
|
||||||
&& newestEvent.timeline_rowid > 0
|
&& newestEvent.timeline_rowid > 0
|
||||||
&& room.readUpToRow < newestEvent.timeline_rowid
|
&& (room.meta.current.marked_unread
|
||||||
&& newestEvent.sender !== client.userID
|
|| (room.readUpToRow < newestEvent.timeline_rowid
|
||||||
|
&& newestEvent.sender !== client.userID))
|
||||||
) {
|
) {
|
||||||
room.readUpToRow = newestEvent.timeline_rowid
|
room.readUpToRow = newestEvent.timeline_rowid
|
||||||
|
room.meta.current.marked_unread = false
|
||||||
const receiptType = roomCtx.store.preferences.send_read_receipts ? "m.read" : "m.read.private"
|
const receiptType = roomCtx.store.preferences.send_read_receipts ? "m.read" : "m.read.private"
|
||||||
client.rpc.markRead(room.roomID, newestEvent.event_id, receiptType).then(
|
client.rpc.markRead(room.roomID, newestEvent.event_id, receiptType).then(
|
||||||
() => console.log("Marked read up to", newestEvent.event_id, newestEvent.timeline_rowid),
|
() => console.log("Marked read up to", newestEvent.event_id, newestEvent.timeline_rowid),
|
||||||
|
|
Loading…
Add table
Reference in a new issue