Various fixes and improvements

* Re-set user's status if they disconnect and reconnect
* Remove "(offline)" text next to ChatServer/ChatClient messages
* Make names and pictures in presence messages clickable to open profile
  cards
This commit is contained in:
Noah 2023-10-14 11:01:58 -07:00
parent 30c5538ce6
commit bdb5e6359b
3 changed files with 63 additions and 50 deletions

View File

@ -134,8 +134,6 @@ func pushMessageContext(sub *Subscriber, channel string, msg messages.Message) {
strings.TrimSpace(msg.Message), strings.TrimSpace(msg.Message),
)) ))
fmt.Printf("Context %s:\n%+v\n", channel, messageContexts[channel])
// Trim the context to recent messages only. // Trim the context to recent messages only.
if len(messageContexts[channel]) > messageContextSize { if len(messageContexts[channel]) > messageContextSize {
messageContexts[channel] = messageContexts[channel][len(messageContexts[channel])-messageContextSize:] messageContexts[channel] = messageContexts[channel][len(messageContexts[channel])-messageContextSize:]

View File

@ -967,6 +967,7 @@ export default {
// WhoList updates. // WhoList updates.
onWho(msg) { onWho(msg) {
let sendMe = false; // re-send our 'me' at the end
this.whoList = msg.whoList; this.whoList = msg.whoList;
this.whoOnline = {}; this.whoOnline = {};
@ -974,15 +975,21 @@ export default {
this.whoList = []; this.whoList = [];
} }
// If we had a camera open with any of these and they have gone
// off camera, close our side of the connection.
for (let row of this.whoList) { for (let row of this.whoList) {
this.whoMap[row.username] = row; this.whoMap[row.username] = row;
this.whoOnline[row.username] = true; this.whoOnline[row.username] = true;
// If we had a camera open with any of these and they have gone
// off camera, close our side of the connection.
if (this.WebRTC.streams[row.username] != undefined && if (this.WebRTC.streams[row.username] != undefined &&
!(row.video & this.VideoFlag.Active)) { !(row.video & this.VideoFlag.Active)) {
this.closeVideo(row.username, "offerer"); this.closeVideo(row.username, "offerer");
} }
// If the server disagrees with our current status, send our status back.
if (row.username === this.username && row.status !== this.status) {
sendMe = true;
}
} }
// Hang up on mutual cameras, if they changed their setting while we // Hang up on mutual cameras, if they changed their setting while we
@ -992,6 +999,11 @@ export default {
// Has the back-end server forgotten we are on video? This can // Has the back-end server forgotten we are on video? This can
// happen if we disconnect/reconnect while we were streaming. // happen if we disconnect/reconnect while we were streaming.
if (this.webcam.active && !(this.whoMap[this.username]?.video & this.VideoFlag.Active)) { if (this.webcam.active && !(this.whoMap[this.username]?.video & this.VideoFlag.Active)) {
sendMe = true;
}
// Do we need to set our me status again?
if (sendMe) {
this.sendMe(); this.sendMe();
} }
}, },
@ -1670,7 +1682,7 @@ export default {
}, },
isUserOffline(username) { isUserOffline(username) {
// Return if the username is not presently online in the chat. // Return if the username is not presently online in the chat.
return this.whoOnline[username] !== true; return this.whoOnline[username] !== true && username !== 'ChatServer' && username !== 'ChatClient';
}, },
avatarForUsername(username) { avatarForUsername(username) {
if (this.whoMap[username] != undefined && this.whoMap[username].avatar) { if (this.whoMap[username] != undefined && this.whoMap[username].avatar) {
@ -1703,9 +1715,6 @@ export default {
if (nick) { if (nick) {
return nick; return nick;
} }
} else if (this.whoMap[username] == undefined && username !== 'ChatServer' && username !== 'ChatClient') {
// User is not even logged in! Add this note to their name
username += " (offline)";
} }
return username; return username;
}, },
@ -3751,37 +3760,10 @@ export default {
</div> </div>
<div v-for="(msg, i) in chatHistory" v-bind:key="i"> <div v-for="(msg, i) in chatHistory" v-bind:key="i">
<!-- Enter chat presence messages draw as a short banner -->
<div v-if="msg.action === 'presence'" class="notification is-success is-light py-1 px-3 mb-2">
<!-- Tiny avatar next to name and action buttons -->
<div class="columns is-mobile">
<div class="column is-narrow pr-0 pt-4">
<figure class="image is-16x16">
<img v-if="avatarForUsername(msg.username)"
:src="avatarForUsername(msg.username)">
<img v-else src="/static/img/shy.png">
</figure>
</div>
<div class="column">
<!-- Timestamp on the right -->
<span class="float-right is-size-7" :title="msg.at">
{{ prettyDate(msg.at) }}
</span>
<strong>{{ nicknameForUsername(msg.username) }}</strong>
<span v-if="isUserOffline(msg.username)" class="ml-1">(offline)</span>
<small v-else class="ml-1">(@{{ msg.username }})</small>
{{ msg.message }}
</div>
</div>
</div>
<!-- Normal chat message: full size card w/ avatar -->
<MessageBox <MessageBox
v-else
:message="msg" :message="msg"
:is-presence="msg.action === 'presence'"
:appearance="messageStyle" :appearance="messageStyle"
:position="i" :position="i"
:user="getUser(msg.username)" :user="getUser(msg.username)"

View File

@ -4,20 +4,21 @@ import 'vue3-emoji-picker/css';
export default { export default {
props: { props: {
message: Object, // chat Message object message: Object, // chat Message object
appearance: String, // message style appearance (cards, compact, etc.) isPresence: Boolean, // presence message (joined/left room, kicked, etc.)
user: Object, // User object of the Message author appearance: String, // message style appearance (cards, compact, etc.)
isOffline: Boolean, // user is not currently online user: Object, // User object of the Message author
username: String, // current username logged in isOffline: Boolean, // user is not currently online
websiteUrl: String, // Base URL to website (for profile/avatar URLs) username: String, // current username logged in
isDnd: Boolean, // user is not accepting DMs websiteUrl: String, // Base URL to website (for profile/avatar URLs)
isMuted: Boolean, // user is muted by current user isDnd: Boolean, // user is not accepting DMs
reactions: Object, // emoji reactions on the message isMuted: Boolean, // user is muted by current user
reactions: Object, // emoji reactions on the message
reportEnabled: Boolean, // Report Message webhook is available reportEnabled: Boolean, // Report Message webhook is available
position: Number, // position of the message (0 to n), for the emoji menu to know which side to pop position: Number, // position of the message (0 to n), for the emoji menu to know which side to pop
isDm: Boolean, // is in a DM thread (hide DM buttons) isDm: Boolean, // is in a DM thread (hide DM buttons)
isOp: Boolean, // current user is Operator (always show takeback button) isOp: Boolean, // current user is Operator (always show takeback button)
noButtons: Boolean, // hide all message buttons (e.g. for Report Modal) noButtons: Boolean, // hide all message buttons (e.g. for Report Modal)
}, },
components: { components: {
EmojiPicker, EmojiPicker,
@ -172,8 +173,40 @@ export default {
</script> </script>
<template> <template>
<!-- Presence message banners -->
<div v-if="isPresence" class="notification is-success is-light py-1 px-3 mb-2">
<!-- Tiny avatar next to name and action buttons -->
<div class="columns is-mobile">
<div class="column is-narrow pr-0 pt-4">
<a :href="profileURL"
@click.prevent="openProfile()"
:class="{ 'cursor-default': !profileURL }">
<figure class="image is-16x16">
<img v-if="avatarURL" :src="avatarURL">
<img v-else src="/static/img/shy.png">
</figure>
</a>
</div>
<div class="column">
<!-- Timestamp on the right -->
<span class="float-right is-size-7" :title="message.at">
{{ prettyDate(message.at) }}
</span>
<span @click="openProfile()" class="cursor-pointer">
<strong>{{ nickname }}</strong>
<span v-if="isOffline" class="ml-1">(offline)</span>
<small v-else class="ml-1">(@{{ message.username }})</small>
</span>
{{ message.message }}
</div>
</div>
</div>
<!-- Card Style (default) --> <!-- Card Style (default) -->
<div v-if="appearance === 'cards' || !appearance" class="box mb-2 px-4 pt-3 pb-1 position-relative"> <div v-else-if="appearance === 'cards' || !appearance" class="box mb-2 px-4 pt-3 pb-1 position-relative">
<div class="media mb-0"> <div class="media mb-0">
<div class="media-left"> <div class="media-left">
<a :href="profileURL" <a :href="profileURL"