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

View file

@ -326,10 +326,11 @@ class TypingStore extends Store {
this.ownTimeout = null;
this.ownNeedsUpdate = true;
gateway.subscribe(GatewayPayloadType.TypingStart, ({ user, time }) => {
if (userInfoStore.value && user.id === userInfoStore.value.id)
gateway.subscribe(GatewayPayloadType.TypingStart, ({ user, channel, time }) => {
if (userInfoStore && user.id === userInfoStore.value.id)
return;
this.startedTyping(user, time);
this.startedTyping(user, channel.id, time);
});
// assume someone has stopped typing once they send a message
@ -339,7 +340,7 @@ class TypingStore extends Store {
}
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);
if (this.timeouts.get(id)) {
@ -356,7 +357,7 @@ class TypingStore extends Store {
this.updated();
}
startedTyping(user, time) {
startedTyping(user, channelId, time) {
if (this.timeouts.get(user.id)) {
clearTimeout(this.timeouts.get(user.id));
}
@ -372,9 +373,15 @@ class TypingStore extends Store {
}, 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) {
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();
}
}
@ -383,10 +390,10 @@ class TypingStore extends Store {
if (!userInfoStore.value)
return;
this.startedTyping(userInfoStore.value, 6500);
this.startedTyping(userInfoStore.value, selectedChannel.value.id, 6500);
if (this.ownNeedsUpdate) {
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;

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;