1
0
mirror of https://github.com/spacebarchat/client.git synced 2024-11-21 18:02:32 +01:00

mark channel as read on open

This commit is contained in:
Puyodead1 2024-07-17 20:48:27 -04:00
parent 329a14ccf5
commit 2f6a56d65e
No known key found for this signature in database
GPG Key ID: A4FA4FEC0DD353FC
5 changed files with 52 additions and 6 deletions

View File

@ -4,13 +4,13 @@ import { useNavigate } from "react-router-dom";
import styled from "styled-components"; import styled from "styled-components";
import { ContextMenuContext } from "../../contexts/ContextMenuContext"; import { ContextMenuContext } from "../../contexts/ContextMenuContext";
import { modalController } from "../../controllers/modals"; import { modalController } from "../../controllers/modals";
import { useAppStore } from "../../hooks/useAppStore";
import Channel from "../../stores/objects/Channel"; import Channel from "../../stores/objects/Channel";
import { Permissions } from "../../utils/Permissions"; import { Permissions } from "../../utils/Permissions";
import Icon from "../Icon"; import Icon from "../Icon";
import SidebarPill from "../SidebarPill"; import SidebarPill from "../SidebarPill";
import Floating from "../floating/Floating"; import Floating from "../floating/Floating";
import FloatingTrigger from "../floating/FloatingTrigger"; import FloatingTrigger from "../floating/FloatingTrigger";
import { useAppStore } from "../../hooks/useAppStore";
const ListItem = styled.div<{ isCategory?: boolean }>` const ListItem = styled.div<{ isCategory?: boolean }>`
padding: ${(props) => (props.isCategory ? "16px 8px 0 0" : "1px 8px 0 0")}; padding: ${(props) => (props.isCategory ? "16px 8px 0 0" : "1px 8px 0 0")};
@ -90,7 +90,7 @@ function ChannelListItem({ channel, isCategory, active }: Props) {
alignItems: "center", alignItems: "center",
}} }}
> >
<SidebarPill type={channel.hasUnread() ? "unread" : "none"} /> <SidebarPill type={channel.unread ? "unread" : "none"} />
{channel.channelIcon && !isCategory && ( {channel.channelIcon && !isCategory && (
<Icon <Icon
icon={channel.channelIcon} icon={channel.channelIcon}

View File

@ -1,6 +1,6 @@
import { runInAction } from "mobx"; import { runInAction } from "mobx";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import React from "react"; import React, { useEffect } from "react";
import styled from "styled-components"; import styled from "styled-components";
import { useAppStore } from "../../hooks/useAppStore"; import { useAppStore } from "../../hooks/useAppStore";
import useLogger from "../../hooks/useLogger"; import useLogger from "../../hooks/useLogger";
@ -57,6 +57,10 @@ function ChatContent({ channel, guild }: Props2) {
const app = useAppStore(); const app = useAppStore();
const readstate = app.readStateStore.get(channel.id); const readstate = app.readStateStore.get(channel.id);
useEffect(() => {
channel.markAsRead();
}, [channel, guild]);
return ( return (
<Container> <Container>
<MessageList guild={guild} channel={channel} before={readstate?.lastMessageId} /> <MessageList guild={guild} channel={channel} before={readstate?.lastMessageId} />

View File

@ -143,6 +143,8 @@ export default class GatewayConnectionStore {
this.dispatchHandlers.set(GatewayDispatchEvents.ChannelCreate, this.onChannelCreate); this.dispatchHandlers.set(GatewayDispatchEvents.ChannelCreate, this.onChannelCreate);
this.dispatchHandlers.set(GatewayDispatchEvents.ChannelUpdate, this.onChannelUpdate); this.dispatchHandlers.set(GatewayDispatchEvents.ChannelUpdate, this.onChannelUpdate);
this.dispatchHandlers.set(GatewayDispatchEvents.ChannelDelete, this.onChannelDelete); this.dispatchHandlers.set(GatewayDispatchEvents.ChannelDelete, this.onChannelDelete);
// @ts-expect-error missing event in typings
this.dispatchHandlers.set("MESSAGE_ACK", this.onMessageAck);
this.dispatchHandlers.set(GatewayDispatchEvents.MessageCreate, this.onMessageCreate); this.dispatchHandlers.set(GatewayDispatchEvents.MessageCreate, this.onMessageCreate);
this.dispatchHandlers.set(GatewayDispatchEvents.MessageUpdate, this.onMessageUpdate); this.dispatchHandlers.set(GatewayDispatchEvents.MessageUpdate, this.onMessageUpdate);
@ -633,6 +635,23 @@ export default class GatewayConnectionStore {
guild.removeChannel(data.id); guild.removeChannel(data.id);
}; };
private onMessageAck = (data: { channel_id: string; message_id: string; version: number }) => {
// get readstate for channel
const readstate = this.app.readStateStore.get(data.channel_id);
if (!readstate) {
this.logger.warn(`[MessageAck] Readstate not found for channel ${data.channel_id}`);
return;
}
runInAction(() => {
readstate.lastMessageId = data.message_id;
});
this.logger.debug(
`[MessageAck] Updated last message id for channel readstate ${data.channel_id} to ${data.message_id}`,
);
};
private onMessageCreate = (data: GatewayMessageCreateDispatchData) => { private onMessageCreate = (data: GatewayMessageCreateDispatchData) => {
const guild = this.app.guilds.get(data.guild_id!); const guild = this.app.guilds.get(data.guild_id!);
if (!guild) { if (!guild) {

View File

@ -311,7 +311,8 @@ export default class Channel {
return listId; return listId;
} }
hasUnread() { @computed
get unread() {
const readState = this.app.readStateStore.get(this.id); const readState = this.app.readStateStore.get(this.id);
if (!readState) { if (!readState) {
// this.logger.warn(`Failed to find readstate for channel ${this.id}`); // this just causes unnecessary spam // this.logger.warn(`Failed to find readstate for channel ${this.id}`); // this just causes unnecessary spam
@ -320,4 +321,23 @@ export default class Channel {
return readState.lastMessageId !== this.lastMessageId; return readState.lastMessageId !== this.lastMessageId;
} }
markAsRead() {
const readState = this.app.readStateStore.get(this.id);
if (!readState) {
this.logger.warn(`Failed to find readstate for channel ${this.id}`); // this just causes unnecessary spam
return;
}
this.app.rest
.post(Routes.channelMessage(this.id, readState.lastMessageId) + "/ack", {
mention_count: readState.mentionCount,
})
.then((r) => {
this.logger.debug(`Acked ${this.lastMessageId} for channel ${this.id}`, r);
})
.catch((e) => {
this.logger.error(`Failed to ack ${this.lastMessageId} for channel ${this.id}`, e);
});
}
} }

View File

@ -1,8 +1,10 @@
import type { APIReadState } from "@spacebarchat/spacebar-api-types/v9"; import { type APIReadState } from "@spacebarchat/spacebar-api-types/v9";
import { action, observable } from "mobx"; import { action, observable } from "mobx";
import Logger from "../../utils/Logger";
import AppStore from "../AppStore"; import AppStore from "../AppStore";
export default class ReadState { export default class ReadState {
private readonly logger: Logger;
private readonly app: AppStore; private readonly app: AppStore;
id: string; id: string;
@ -11,9 +13,10 @@ export default class ReadState {
@observable mentionCount: number | null; @observable mentionCount: number | null;
constructor(app: AppStore, data: APIReadState) { constructor(app: AppStore, data: APIReadState) {
this.logger = new Logger("ReadState");
this.app = app; this.app = app;
this.id = data.id; this.id = data.id; // channel id
this.lastMessageId = data.last_message_id; this.lastMessageId = data.last_message_id;
this.lastPinTimestamp = data.last_pin_timestamp; this.lastPinTimestamp = data.last_pin_timestamp;
this.mentionCount = data.mention_count; this.mentionCount = data.mention_count;