making typing indicators per-channel

This commit is contained in:
hippoz 2022-08-07 21:57:41 +03:00
parent 579ff19921
commit f9a62cec4e
Signed by: hippoz
GPG key ID: 7C52899193467641
4 changed files with 50 additions and 34 deletions

View file

@ -12,8 +12,8 @@
$: messages = messagesStoreProvider.getStore(channel.id); $: messages = messagesStoreProvider.getStore(channel.id);
$: { $: {
const typing = [ ...$typingStore ]; const typing = $typingStore.filter(a => a.channelId === channel.id);
const ownIndex = typing.findIndex(a => a.id === $userInfoStore.id); const ownIndex = typing.findIndex(a => a.user.id === $userInfoStore.id);
if (ownIndex !== -1) { if (ownIndex !== -1) {
typing.splice(ownIndex, 1); typing.splice(ownIndex, 1);
} }
@ -22,7 +22,7 @@
typingList = "?no one?"; typingList = "?no one?";
typingMessage = "is typing..."; typingMessage = "is typing...";
} else if (typing.length === 1) { } else if (typing.length === 1) {
typingList = `${typing[0].username}`; typingList = `${typing[0].user.username}`;
typingMessage = "is typing..."; typingMessage = "is typing...";
} else if (typing.length > 1) { } else if (typing.length > 1) {
typingList = ""; typingList = "";
@ -30,9 +30,9 @@
const item = typing[i]; const item = typing[i];
if (i == (typing.length - 1)) { if (i == (typing.length - 1)) {
// we are at the end // we are at the end
typingList += `and ${item.username} `; typingList += `and ${item.user.username} `;
} else { } else {
typingList += `${item.username}, `; typingList += `${item.user.username}, `;
} }
} }
typingMessage = "are typing..."; typingMessage = "are typing...";

View file

@ -326,10 +326,11 @@ class TypingStore extends Store {
this.ownTimeout = null; this.ownTimeout = null;
this.ownNeedsUpdate = true; this.ownNeedsUpdate = true;
gateway.subscribe(GatewayPayloadType.TypingStart, ({ user, time }) => { gateway.subscribe(GatewayPayloadType.TypingStart, ({ user, channel, time }) => {
if (userInfoStore.value && user.id === userInfoStore.value.id) if (userInfoStore && user.id === userInfoStore.value.id)
return; return;
this.startedTyping(user, time);
this.startedTyping(user, channel.id, time);
}); });
// assume someone has stopped typing once they send a message // assume someone has stopped typing once they send a message
@ -339,7 +340,7 @@ class TypingStore extends Store {
} }
stoppedTyping(id) { stoppedTyping(id) {
const index = this.value.findIndex(e => e.id === id); const index = this.value.findIndex(e => e.user.id === id);
this.value.splice(index, 1); this.value.splice(index, 1);
if (this.timeouts.get(id)) { if (this.timeouts.get(id)) {
@ -356,7 +357,7 @@ class TypingStore extends Store {
this.updated(); this.updated();
} }
startedTyping(user, time) { startedTyping(user, channelId, time) {
if (this.timeouts.get(user.id)) { if (this.timeouts.get(user.id)) {
clearTimeout(this.timeouts.get(user.id)); clearTimeout(this.timeouts.get(user.id));
} }
@ -372,9 +373,15 @@ class TypingStore extends Store {
}, time); }, time);
} }
const index = this.value.findIndex(e => e.id === user.id); const index = this.value.findIndex(e => e.user.id === user.id);
if (index === -1) { if (index === -1) {
this.value.push(user); this.value.push({
user,
channelId
});
this.updated();
} else if (this.value[index].channelId !== channelId) { // user just switched the channel they're typing in
this.value[index].channelId = channelId;
this.updated(); this.updated();
} }
} }
@ -383,10 +390,10 @@ class TypingStore extends Store {
if (!userInfoStore.value) if (!userInfoStore.value)
return; return;
this.startedTyping(userInfoStore.value, 6500); this.startedTyping(userInfoStore.value, selectedChannel.value.id, 6500);
if (this.ownNeedsUpdate) { if (this.ownNeedsUpdate) {
this.ownNeedsUpdate = false; this.ownNeedsUpdate = false;
await request("PUT", apiRoute("users/self/typing"), true, {}); await request("POST", apiRoute(`channels/${selectedChannel.value.id}/typing`), true, {});
} }
} }
} }

View file

@ -236,5 +236,34 @@ router.get(
} }
); );
router.post(
"/:id/typing",
authenticateRoute(),
param("id").isNumeric(),
async (req, res) => {
const validationErrors = validationResult(req);
if (!validationErrors.isEmpty()) {
return res.status(400).json({ ...errors.INVALID_DATA, errors: validationErrors.array() });
}
const channelId = parseInt(req.params.id);
dispatch(`channel:${channelId}`, {
t: GatewayPayloadType.TypingStart,
d: {
user: {
id: req.publicUser.id,
username: req.publicUser.username
},
channel: {
id: channelId
},
time: 7500
}
});
return res.status(201).send("");
}
);
export default router; export default router;

View file

@ -109,24 +109,4 @@ router.post(
} }
); );
router.put(
"/self/typing",
authenticateRoute(),
(req, res) => {
// TODO: add a ratelimit to this
dispatch("*", {
t: GatewayPayloadType.TypingStart,
d: {
user: {
id: req.publicUser.id,
username: req.publicUser.username
},
time: 7500
}
});
return res.status(204).send("");
}
);
export default router; export default router;