Commit cae5e9c8 authored by Dele Olajide's avatar Dele Olajide Committed by JC Brand

Updates #1999 - Demarcate first unread message

parent 6157189e
...@@ -21,6 +21,7 @@ Soon we'll deprecate the latter, so prepare now. ...@@ -21,6 +21,7 @@ Soon we'll deprecate the latter, so prepare now.
- #1896: Don't send receipts for messages fetched from the archive - #1896: Don't send receipts for messages fetched from the archive
- #1937: Editing a message removes the mentions highlight - #1937: Editing a message removes the mentions highlight
- #1963: Mentions are visually incorrect when used in message replies - #1963: Mentions are visually incorrect when used in message replies
- #1999: Demarcate first unread message
- #2002: fix rendering of `muc_roomid_policy_hint` - #2002: fix rendering of `muc_roomid_policy_hint`
- #2006: fix rendering of emojis in case `use_system_emojis == false` - #2006: fix rendering of emojis in case `use_system_emojis == false`
- Allow ignoring of bootstrap modules at build using environment variable. For xample: `export BOOTSTRAP_IGNORE_MODULES="Modal,Dropdown" && make dist` - Allow ignoring of bootstrap modules at build using environment variable. For xample: `export BOOTSTRAP_IGNORE_MODULES="Modal,Dropdown" && make dist`
......
...@@ -2244,7 +2244,8 @@ ...@@ -2244,7 +2244,8 @@
"dependencies": { "dependencies": {
"filesize": { "filesize": {
"version": "6.1.0", "version": "6.1.0",
"resolved": false "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz",
"integrity": "sha512-LpCHtPQ3sFx67z+uh2HnSyWSLLu5Jxo21795uRDuar/EOuYWXib5EmPaGIBuSnRqH2IODiKA2k5re/K9OnN/Yg=="
}, },
"fs-extra": { "fs-extra": {
"version": "8.1.0", "version": "8.1.0",
...@@ -2278,7 +2279,8 @@ ...@@ -2278,7 +2279,8 @@
}, },
"jed": { "jed": {
"version": "1.1.1", "version": "1.1.1",
"resolved": false "resolved": "https://registry.npmjs.org/jed/-/jed-1.1.1.tgz",
"integrity": "sha1-elSbvZ/+FYWwzQoZHiAwVb7ldLQ="
}, },
"jsonfile": { "jsonfile": {
"version": "5.0.0", "version": "5.0.0",
...@@ -2299,18 +2301,21 @@ ...@@ -2299,18 +2301,21 @@
}, },
"localforage": { "localforage": {
"version": "1.7.3", "version": "1.7.3",
"resolved": false, "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.7.3.tgz",
"integrity": "sha512-1TulyYfc4udS7ECSBT2vwJksWbkwwTX8BzeUIiq8Y07Riy7bDAAnxDaPU/tWyOVmQAcWJIEIFP9lPfBGqVoPgQ==",
"requires": { "requires": {
"lie": "3.1.1" "lie": "3.1.1"
} }
}, },
"lodash": { "lodash": {
"version": "4.17.15", "version": "4.17.15",
"resolved": false "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
}, },
"pluggable.js": { "pluggable.js": {
"version": "2.0.1", "version": "2.0.1",
"resolved": false, "resolved": "https://registry.npmjs.org/pluggable.js/-/pluggable.js-2.0.1.tgz",
"integrity": "sha512-SBt6v6Tbp20Jf8hU0cpcc/+HBHGMY8/Q+yA6Ih0tBQE8tfdZ6U4PRG0iNvUUjLx/hVyOP53n0UfGBymlfaaXCg==",
"requires": { "requires": {
"lodash": "^4.17.11" "lodash": "^4.17.11"
} }
...@@ -2324,11 +2329,13 @@ ...@@ -2324,11 +2329,13 @@
}, },
"strophe.js": { "strophe.js": {
"version": "1.3.4", "version": "1.3.4",
"resolved": false "resolved": "https://registry.npmjs.org/strophe.js/-/strophe.js-1.3.4.tgz",
"integrity": "sha512-jSLDG8jolhAwGOSgiJ7DTMSYK3wVoEJHKtpVRyEacQZ6CWA6z2WRPJpcFMjsIweq5aP9/XIvKUQqHBu/ZhvESA=="
}, },
"twemoji": { "twemoji": {
"version": "12.1.5", "version": "12.1.5",
"resolved": false, "resolved": "https://registry.npmjs.org/twemoji/-/twemoji-12.1.5.tgz",
"integrity": "sha512-B0PBVy5xomwb1M/WZxf/IqPZfnoIYy1skXnlHjMwLwTNfZ9ljh8VgWQktAPcJXu8080WoEh6YwQGPVhDVqvrVQ==",
"requires": { "requires": {
"fs-extra": "^8.0.1", "fs-extra": "^8.0.1",
"jsonfile": "^5.0.0", "jsonfile": "^5.0.0",
......
...@@ -1296,6 +1296,8 @@ describe("Chatboxes", function () { ...@@ -1296,6 +1296,8 @@ describe("Chatboxes", function () {
await _converse.handleMessageStanza(msg); await _converse.handleMessageStanza(msg);
await u.waitUntil(() => view.model.messages.length); await u.waitUntil(() => view.model.messages.length);
expect(view.model.get('num_unread')).toBe(1); expect(view.model.get('num_unread')).toBe(1);
const msgid = view.model.messages.last().get('id');
expect(view.model.get('first_unread_id')).toBe(msgid);
done(); done();
})); }));
...@@ -1329,9 +1331,12 @@ describe("Chatboxes", function () { ...@@ -1329,9 +1331,12 @@ describe("Chatboxes", function () {
await mock.openChatBoxFor(_converse, sender_jid); await mock.openChatBoxFor(_converse, sender_jid);
const chatbox = _converse.chatboxes.get(sender_jid); const chatbox = _converse.chatboxes.get(sender_jid);
_converse.windowState = 'hidden'; _converse.windowState = 'hidden';
_converse.handleMessageStanza(msgFactory()); const msg = msgFactory();
_converse.handleMessageStanza(msg);
await u.waitUntil(() => chatbox.messages.length); await u.waitUntil(() => chatbox.messages.length);
expect(chatbox.get('num_unread')).toBe(1); expect(chatbox.get('num_unread')).toBe(1);
const msgid = chatbox.messages.last().get('id');
expect(chatbox.get('first_unread_id')).toBe(msgid);
done(); done();
})); }));
...@@ -1347,9 +1352,12 @@ describe("Chatboxes", function () { ...@@ -1347,9 +1352,12 @@ describe("Chatboxes", function () {
const chatbox = _converse.chatboxes.get(sender_jid); const chatbox = _converse.chatboxes.get(sender_jid);
chatbox.save('scrolled', true); chatbox.save('scrolled', true);
_converse.windowState = 'hidden'; _converse.windowState = 'hidden';
_converse.handleMessageStanza(msgFactory()); const msg = msgFactory();
_converse.handleMessageStanza(msg);
await u.waitUntil(() => chatbox.messages.length); await u.waitUntil(() => chatbox.messages.length);
expect(chatbox.get('num_unread')).toBe(1); expect(chatbox.get('num_unread')).toBe(1);
const msgid = chatbox.messages.last().get('id');
expect(chatbox.get('first_unread_id')).toBe(msgid);
done(); done();
})); }));
...@@ -1364,9 +1372,12 @@ describe("Chatboxes", function () { ...@@ -1364,9 +1372,12 @@ describe("Chatboxes", function () {
await mock.openChatBoxFor(_converse, sender_jid); await mock.openChatBoxFor(_converse, sender_jid);
const chatbox = _converse.chatboxes.get(sender_jid); const chatbox = _converse.chatboxes.get(sender_jid);
_converse.windowState = 'hidden'; _converse.windowState = 'hidden';
_converse.handleMessageStanza(msgFactory()); const msg = msgFactory();
_converse.handleMessageStanza(msg);
await u.waitUntil(() => chatbox.messages.length); await u.waitUntil(() => chatbox.messages.length);
expect(chatbox.get('num_unread')).toBe(1); expect(chatbox.get('num_unread')).toBe(1);
const msgid = chatbox.messages.last().get('id');
expect(chatbox.get('first_unread_id')).toBe(msgid);
_converse.saveWindowState(null, 'focus'); _converse.saveWindowState(null, 'focus');
expect(chatbox.get('num_unread')).toBe(0); expect(chatbox.get('num_unread')).toBe(0);
done(); done();
...@@ -1384,11 +1395,15 @@ describe("Chatboxes", function () { ...@@ -1384,11 +1395,15 @@ describe("Chatboxes", function () {
const chatbox = _converse.chatboxes.get(sender_jid); const chatbox = _converse.chatboxes.get(sender_jid);
chatbox.save('scrolled', true); chatbox.save('scrolled', true);
_converse.windowState = 'hidden'; _converse.windowState = 'hidden';
_converse.handleMessageStanza(msgFactory()); const msg = msgFactory();
_converse.handleMessageStanza(msg);
await u.waitUntil(() => chatbox.messages.length); await u.waitUntil(() => chatbox.messages.length);
expect(chatbox.get('num_unread')).toBe(1); expect(chatbox.get('num_unread')).toBe(1);
const msgid = chatbox.messages.last().get('id');
expect(chatbox.get('first_unread_id')).toBe(msgid);
_converse.saveWindowState(null, 'focus'); _converse.saveWindowState(null, 'focus');
expect(chatbox.get('num_unread')).toBe(1); expect(chatbox.get('num_unread')).toBe(1);
expect(chatbox.get('first_unread_id')).toBe(msgid);
done(); done();
})); }));
}); });
......
...@@ -145,7 +145,7 @@ converse.plugins.add('converse-message-view', { ...@@ -145,7 +145,7 @@ converse.plugins.add('converse-message-view', {
return this.renderFileUploadProgresBar(); return this.renderFileUploadProgresBar();
} }
const isValidChange = prop => Object.prototype.hasOwnProperty.call(this.model.changed, prop); const isValidChange = prop => Object.prototype.hasOwnProperty.call(this.model.changed, prop);
const props = ['moderated', 'retracted', 'correcting', 'message', 'type', 'upload', 'received', 'editable']; const props = ['moderated', 'retracted', 'correcting', 'message', 'type', 'upload', 'received', 'editable', 'first_unread'];
if (props.filter(isValidChange).length) { if (props.filter(isValidChange).length) {
await this.debouncedRender(); await this.debouncedRender();
} }
......
...@@ -1110,11 +1110,29 @@ converse.plugins.add('converse-chat', { ...@@ -1110,11 +1110,29 @@ converse.plugins.add('converse-chat', {
return; return;
} }
if (utils.isNewMessage(message) && this.isHidden()) { if (utils.isNewMessage(message) && this.isHidden()) {
this.setFirstUnreadMsgId(message);
this.save({'num_unread': this.get('num_unread') + 1}); this.save({'num_unread': this.get('num_unread') + 1});
_converse.incrementMsgCounter(); _converse.incrementMsgCounter();
} }
}, },
/**
* Sets the msgid of the first unread realtime message in a ChatBox.
* @param {_converse.Message} message
*/
setFirstUnreadMsgId (message) {
if (this.get('num_unread') == 0) {
const first_unread_id = this.get('first_unread_id');
if (first_unread_id) {
const msg = this.messages.get(first_unread_id);
if (msg) msg.save("first_unread", false);
}
message.save("first_unread", true);
this.save({'first_unread_id': message.get('id')});
}
},
clearUnreadMsgCounter () { clearUnreadMsgCounter () {
u.safeSave(this, {'num_unread': 0}); u.safeSave(this, {'num_unread': 0});
}, },
......
...@@ -2387,6 +2387,7 @@ converse.plugins.add('converse-muc', { ...@@ -2387,6 +2387,7 @@ converse.plugins.add('converse-muc', {
const body = message.get('message'); const body = message.get('message');
if (!body) { return; } if (!body) { return; }
if (u.isNewMessage(message) && this.isHidden()) { if (u.isNewMessage(message) && this.isHidden()) {
this.setFirstUnreadMsgId(message);
const settings = {'num_unread_general': this.get('num_unread_general') + 1}; const settings = {'num_unread_general': this.get('num_unread_general') + 1};
if (this.isUserMentioned(message)) { if (this.isUserMentioned(message)) {
settings.num_unread = this.get('num_unread') + 1; settings.num_unread = this.get('num_unread') + 1;
......
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
<canvas class="avatar chat-msg__avatar" height="36" width="36"></canvas> <canvas class="avatar chat-msg__avatar" height="36" width="36"></canvas>
{[ } ]} {[ } ]}
<div class="chat-msg__content chat-msg__content--{{{o.sender}}} {{{o.is_me_message ? 'chat-msg__content--action' : ''}}}"> <div class="chat-msg__content chat-msg__content--{{{o.sender}}} {{{o.is_me_message ? 'chat-msg__content--action' : ''}}}">
{[ if (o.first_unread) { ]}
<div class="message date-separator"><hr class="separator"><span class="separator-text">{{{o.__('unread messages')}}}</span></div>
{[ } ]}
<span class="chat-msg__heading"> <span class="chat-msg__heading">
{[ if (o.is_me_message) { ]}<time timestamp="{{{o.isodate}}}" class="chat-msg__time">{{{o.pretty_time}}}</time>{[ } ]} {[ if (o.is_me_message) { ]}<time timestamp="{{{o.isodate}}}" class="chat-msg__time">{{{o.pretty_time}}}</time>{[ } ]}
<span class="chat-msg__author">{[ if (o.is_me_message) { ]}**{[ }; ]}{{{o.username}}}</span> <span class="chat-msg__author">{[ if (o.is_me_message) { ]}**{[ }; ]}{{{o.username}}}</span>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment