瀏覽代碼

bugfix: update roster on presence changes

JC Brand 1 月之前
父節點
當前提交
2e7c244574

+ 1 - 1
src/headless/shared/chatbox.js

@@ -61,7 +61,7 @@ export default class ChatBoxBase extends ModelWithMessages(Model) {
             return this;
         }
         // Overlayed view mode
-        u.safeSave(this, { 'hidden': false });
+        u.safeSave(this, { hidden: false });
         this.trigger('show');
         return this;
     }

+ 1 - 0
src/plugins/rosterview/rosterview.js

@@ -32,6 +32,7 @@ export default class RosterView extends CustomElement {
         this.listenTo(roster, 'destroy', () => this.requestUpdate());
         this.listenTo(roster, 'remove', () => this.requestUpdate());
         this.listenTo(roster, 'change', () => this.requestUpdate());
+        this.listenTo(roster, 'presence:change', () => this.requestUpdate());
         this.listenTo(roster.state, 'change', () => this.requestUpdate());
         this.listenTo(this.model, 'change', () => this.requestUpdate());
         /**

+ 30 - 7
src/plugins/rosterview/tests/roster.js

@@ -515,7 +515,7 @@ describe("The Contacts Roster", function () {
                 "Ungrouped",
             ]);
 
-            const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
+            const contact_jid = mock.getContactJID(0);
             const contact = await _converse.api.contacts.get(contact_jid);
             contact.save({'num_unread': 5});
 
@@ -839,23 +839,23 @@ describe("The Contacts Roster", function () {
             const icon_el = document.querySelector('converse-roster-contact converse-icon');
             expect(icon_el.getAttribute('color')).toBe('var(--chat-status-offline)');
 
-            let pres = $pres({from: 'mercutio@montague.lit/resource'});
+            let pres = stx`<presence from="mercutio@montague.lit/resource" xmlns="jabber:client"/>`;
             _converse.api.connection.get()._dataRecv(mock.createRequest(pres));
             await u.waitUntil(() => icon_el.getAttribute('color') === 'var(--chat-status-online)');
 
-            pres = $pres({from: 'mercutio@montague.lit/resource'}).c('show', 'away');
+            pres = stx`<presence from="mercutio@montague.lit/resource" xmlns="jabber:client"><show>away</show></presence>`;
             _converse.api.connection.get()._dataRecv(mock.createRequest(pres));
             await u.waitUntil(() => icon_el.getAttribute('color') === 'var(--chat-status-away)');
 
-            pres = $pres({from: 'mercutio@montague.lit/resource'}).c('show', 'xa');
+            pres = stx`<presence from="mercutio@montague.lit/resource" xmlns="jabber:client"><show>xa</show></presence>`;
             _converse.api.connection.get()._dataRecv(mock.createRequest(pres));
             await u.waitUntil(() => icon_el.getAttribute('color') === 'var(--chat-status-offline)');
 
-            pres = $pres({from: 'mercutio@montague.lit/resource'}).c('show', 'dnd');
+            pres = stx`<presence from="mercutio@montague.lit/resource" xmlns="jabber:client"><show>dnd</show></presence>`;
             _converse.api.connection.get()._dataRecv(mock.createRequest(pres));
             await u.waitUntil(() => icon_el.getAttribute('color') === 'var(--chat-status-busy)');
 
-            pres = $pres({from: 'mercutio@montague.lit/resource', type: 'unavailable'});
+            pres = stx`<presence from="mercutio@montague.lit/resource" type="unavailable" xmlns="jabber:client"/>`;
             _converse.api.connection.get()._dataRecv(mock.createRequest(pres));
             await u.waitUntil(() => icon_el.getAttribute('color') === 'var(--chat-status-offline)');
         }));
@@ -867,10 +867,11 @@ describe("The Contacts Roster", function () {
 
             const { api } = _converse;
             await mock.waitForRoster(_converse, 'current', 0);
+            const { roster } = _converse.state;
             await mock.openControlBox(_converse);
             const rosterview = document.querySelector('converse-roster');
             await Promise.all(mock.cur_names.map(name => {
-                const contact = _converse.roster.create({
+                const contact = roster.create({
                     jid: name.replace(/ /g,'.').toLowerCase() + '@montague.lit',
                     subscription: 'both',
                     ask: null,
@@ -885,6 +886,28 @@ describe("The Contacts Roster", function () {
             const els = sizzle('.current-xmpp-contact.offline a.open-chat .contact-name', rosterview)
             const t = els.reduce((result, value) => (result + value.textContent.trim()), '');
             expect(t).toEqual(mock.cur_names.slice(0,mock.cur_names.length).sort().join(''));
+
+            // Check that ordering changes based on chat status
+            let contact_jid = mock.getContactJID(roster.length-1);
+            let contact = await _converse.api.contacts.get(contact_jid);
+            contact.presence.set('presence', 'online');
+            let sel = 'ul.roster-group-contacts li:first-child converse-roster-contact';
+            await u.waitUntil(() => rosterview.querySelector(sel).model?.get('jid') === contact_jid);
+
+            contact_jid = mock.getContactJID(roster.length-2);
+            contact = await _converse.api.contacts.get(contact_jid);
+            contact.presence.set({ show: 'dnd', presence: 'online' });
+
+            sel = 'ul.roster-group-contacts li:nth-child(3) converse-roster-contact';
+            await u.waitUntil(() => rosterview.querySelector(sel).model?.get('jid') === contact_jid);
+
+            contact_jid = mock.getContactJID(roster.length-3);
+            contact = await _converse.api.contacts.get(contact_jid);
+            contact.presence.set({ show: 'away', presence: 'online' });
+
+            sel = 'ul.roster-group-contacts li:nth-child(4) converse-roster-contact';
+            await u.waitUntil(() => rosterview.querySelector(sel).model?.get('jid') === contact_jid);
+
         }));
 
         it("can be removed by the user",

+ 6 - 6
src/shared/styles/themes/classic.scss

@@ -8,8 +8,8 @@
     --blue-rgb: 56, 117, 146;
     --dark-blue: #397491;
     --dark-green: #1e9652;
-    --dark-red: #d24e2b;
-    --dark-red-rgb: 210, 78, 43;
+    --red: #d24e2b;
+    --red-rgb: 210, 78, 43;
     --gray: #818479;
     --green: #3aa569;
     --green-rgb: 58, 165, 105;
@@ -36,8 +36,8 @@
     --secondary-rgb: var(--light-blue-rgb);
     --success-color: var(--green);
     --success-color-rgb: var(--green-rgb);
-    --danger-color: var(--dark-red);
-    --danger-color-rgb: var(--dark-red-rgb);
+    --danger-color: var(--red);
+    --danger-color-rgb: var(--red-rgb);
     --warning-color: var(--orange);
     --info-color: var(--light-blue);
     --info-color-rgb: var(--light-blue-rgb);
@@ -51,7 +51,7 @@
 
     --converse-body-bg: var(--background-color);
     --converse-body-color: var(--foreground-color) !important;
-    --converse-highlight-color: var(--dark-red);
+    --converse-highlight-color: var(--red);
     .navbar-nav {
         --converse-nav-link-color: var(--link-color) !important;
     }
@@ -75,7 +75,7 @@
 
     --controlbox-color: var(--light-blue);
     --disabled-color: gray;
-    --error-color: var(--dark-red);
+    --error-color: var(--red);
     --focus-color: var(--light-blue);
     --heading-color: var(--background-color);
     --headlines-color: var(--orange);

+ 6 - 1
src/shared/tests/mock.js

@@ -54,7 +54,11 @@ function initConverse (promise_names=[], settings=null, func) {
     }
 }
 
-export async function checkHeaderToggling(group) {
+function getContactJID(index) {
+    return mock.cur_names[index].replace(/ /g,'.').toLowerCase() + '@montague.lit';
+}
+
+async function checkHeaderToggling(group) {
     const toggle = group.querySelector('a.group-toggle');
     expect(u.isVisible(group)).toBeTruthy();
     expect(group.querySelectorAll('ul.collapsed').length).toBe(0);
@@ -959,6 +963,7 @@ Object.assign(mock, {
     groups,
     groups_map,
     initConverse,
+    getContactJID,
     initializedOMEMO,
     num_contacts,
     openAddMUCModal,