mirror of https://github.com/zulip/zulip.git
Show a mobile icon in the presence list when relevant
We show a user as "on mobile" if: * They are only active on mobile * They are inactive on all devices and can receive push notifications (imported from commit 0510b9371727cd19c72f6990df7112921c36ad48)
This commit is contained in:
parent
4397c25976
commit
bd20a756f9
|
@ -13,6 +13,14 @@ var ACTIVE_PING_INTERVAL_MS = 50 * 1000;
|
||||||
/* Mark users as offline after 140 seconds since their last checkin */
|
/* Mark users as offline after 140 seconds since their last checkin */
|
||||||
var OFFLINE_THRESHOLD_SECS = 140;
|
var OFFLINE_THRESHOLD_SECS = 140;
|
||||||
|
|
||||||
|
// Testing
|
||||||
|
exports._OFFLINE_THRESHOLD_SECS = OFFLINE_THRESHOLD_SECS;
|
||||||
|
|
||||||
|
var MOBILE_DEVICES = ["Android", "IOS"];
|
||||||
|
|
||||||
|
function is_mobile(device) {
|
||||||
|
return MOBILE_DEVICES.indexOf(device) !== -1;
|
||||||
|
}
|
||||||
|
|
||||||
var presence_descriptions = {
|
var presence_descriptions = {
|
||||||
active: 'is active',
|
active: 'is active',
|
||||||
|
@ -41,6 +49,7 @@ var presence_info = {};
|
||||||
|
|
||||||
var huddle_timestamps = new Dict();
|
var huddle_timestamps = new Dict();
|
||||||
|
|
||||||
|
|
||||||
exports.process_loaded_messages = function (messages) {
|
exports.process_loaded_messages = function (messages) {
|
||||||
_.each(messages, function (message) {
|
_.each(messages, function (message) {
|
||||||
if (message.type === 'private') {
|
if (message.type === 'private') {
|
||||||
|
@ -222,7 +231,8 @@ function actually_update_users() {
|
||||||
email: email,
|
email: email,
|
||||||
num_unread: get_num_unread(email),
|
num_unread: get_num_unread(email),
|
||||||
type: presence,
|
type: presence,
|
||||||
type_desc: presence_descriptions[presence]
|
type_desc: presence_descriptions[presence],
|
||||||
|
mobile: presence_info[email].mobile
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,19 +295,45 @@ exports.update_huddles = function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
function status_from_timestamp(baseline_time, presence) {
|
function status_from_timestamp(baseline_time, presence) {
|
||||||
if (presence.website === undefined) {
|
|
||||||
return {status: 'offline'};
|
|
||||||
}
|
|
||||||
|
|
||||||
var age = baseline_time - presence.website.timestamp;
|
|
||||||
|
|
||||||
var status = 'offline';
|
var status = 'offline';
|
||||||
if (age < OFFLINE_THRESHOLD_SECS) {
|
var mobileAvailable = false;
|
||||||
status = presence.website.status;
|
var nonmobileAvailable = false;
|
||||||
}
|
_.each(presence, function (device_presence, device) {
|
||||||
return {status: status};
|
var age = baseline_time - device_presence.timestamp;
|
||||||
|
if (is_mobile(device)) {
|
||||||
|
mobileAvailable = device_presence.pushable || mobileAvailable;
|
||||||
|
}
|
||||||
|
if (age < OFFLINE_THRESHOLD_SECS) {
|
||||||
|
switch (device_presence.status) {
|
||||||
|
case 'active':
|
||||||
|
if (is_mobile(device)) {
|
||||||
|
mobileAvailable = true;
|
||||||
|
} else {
|
||||||
|
nonmobileAvailable = true;
|
||||||
|
}
|
||||||
|
status = device_presence.status;
|
||||||
|
break;
|
||||||
|
case 'idle':
|
||||||
|
if (status !== 'active') {
|
||||||
|
status = device_presence.status;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'offline':
|
||||||
|
if (status !== 'active' && status !== 'idle') {
|
||||||
|
status = device_presence.status;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
blueslip.error('Unexpected status', {'presence_object': device_presence, 'device': device}, undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {status: status, mobile: !nonmobileAvailable && mobileAvailable };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For testing
|
||||||
|
exports._status_from_timestamp = status_from_timestamp;
|
||||||
|
|
||||||
function focus_ping() {
|
function focus_ping() {
|
||||||
channel.post({
|
channel.post({
|
||||||
url: '/json/update_active_status',
|
url: '/json/update_active_status',
|
||||||
|
|
|
@ -825,6 +825,9 @@ a .icon-vector-flip-vertical:before {
|
||||||
.icon-vector-lemon:before {
|
.icon-vector-lemon:before {
|
||||||
content: "\f094";
|
content: "\f094";
|
||||||
}
|
}
|
||||||
|
.icon-vector-mobile:before {
|
||||||
|
content: "\f10b";
|
||||||
|
}
|
||||||
.icon-vector-phone:before {
|
.icon-vector-phone:before {
|
||||||
content: "\f095";
|
content: "\f095";
|
||||||
}
|
}
|
||||||
|
|
|
@ -444,6 +444,18 @@ a:hover code {
|
||||||
border-color: gray;
|
border-color: gray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-device-indicator {
|
||||||
|
display: block;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
float: left;
|
||||||
|
position: relative;
|
||||||
|
top: 5px;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
#user_presences a, #group-pms a {
|
#user_presences a, #group-pms a {
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
<li data-email="{{email}}" class="user_sidebar_entry {{#if num_unread}}user-with-count {{/if}}narrow-filter user_{{type}}">
|
<li data-email="{{email}}" class="user_sidebar_entry {{#if num_unread}}user-with-count {{/if}}narrow-filter user_{{type}}">
|
||||||
<span class="selectable_sidebar_block">
|
<span class="selectable_sidebar_block">
|
||||||
<span class="user-status-indicator"></span>
|
<span class="user-status-indicator"></span>
|
||||||
|
<span class="user-device-indicator{{#if mobile}} icon-vector-mobile{{/if}}"></span>
|
||||||
<a href="#" data-email="{{email}}" data-name="{{name}}" title="{{name}} {{type_desc}}"
|
<a href="#" data-email="{{email}}" data-name="{{name}}" title="{{name}} {{type_desc}}"
|
||||||
class="{{#if my_fullname}} my_fullname{{/if}}">{{name}}</a>
|
class="{{#if my_fullname}} my_fullname{{/if}}">{{name}}</a>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -153,3 +153,64 @@ var activity = require('js/activity.js');
|
||||||
);
|
);
|
||||||
}());
|
}());
|
||||||
|
|
||||||
|
|
||||||
|
(function test_on_mobile_property() {
|
||||||
|
var base_time = 500;
|
||||||
|
var presence = {
|
||||||
|
website: {
|
||||||
|
status: "active",
|
||||||
|
timestamp: base_time
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var status = activity._status_from_timestamp(
|
||||||
|
base_time + activity._OFFLINE_THRESHOLD_SECS - 1, presence
|
||||||
|
);
|
||||||
|
assert.equal(status.mobile, false);
|
||||||
|
|
||||||
|
presence.Android = {
|
||||||
|
status: "active",
|
||||||
|
timestamp: base_time + activity._OFFLINE_THRESHOLD_SECS / 2,
|
||||||
|
pushable: false
|
||||||
|
};
|
||||||
|
status = activity._status_from_timestamp(
|
||||||
|
base_time + activity._OFFLINE_THRESHOLD_SECS, presence
|
||||||
|
);
|
||||||
|
assert.equal(status.mobile, true);
|
||||||
|
assert.equal(status.status, "active");
|
||||||
|
|
||||||
|
status = activity._status_from_timestamp(
|
||||||
|
base_time + activity._OFFLINE_THRESHOLD_SECS - 1, presence
|
||||||
|
);
|
||||||
|
assert.equal(status.mobile, false);
|
||||||
|
assert.equal(status.status, "active");
|
||||||
|
|
||||||
|
status = activity._status_from_timestamp(
|
||||||
|
base_time + activity._OFFLINE_THRESHOLD_SECS * 2, presence
|
||||||
|
);
|
||||||
|
assert.equal(status.mobile, false);
|
||||||
|
assert.equal(status.status, "offline");
|
||||||
|
|
||||||
|
presence.Android = {
|
||||||
|
status: "idle",
|
||||||
|
timestamp: base_time + activity._OFFLINE_THRESHOLD_SECS / 2,
|
||||||
|
pushable: true
|
||||||
|
};
|
||||||
|
status = activity._status_from_timestamp(
|
||||||
|
base_time + activity._OFFLINE_THRESHOLD_SECS, presence
|
||||||
|
);
|
||||||
|
assert.equal(status.mobile, true);
|
||||||
|
assert.equal(status.status, "idle");
|
||||||
|
|
||||||
|
status = activity._status_from_timestamp(
|
||||||
|
base_time + activity._OFFLINE_THRESHOLD_SECS - 1, presence
|
||||||
|
);
|
||||||
|
assert.equal(status.mobile, false);
|
||||||
|
assert.equal(status.status, "active");
|
||||||
|
|
||||||
|
status = activity._status_from_timestamp(
|
||||||
|
base_time + activity._OFFLINE_THRESHOLD_SECS * 2, presence
|
||||||
|
);
|
||||||
|
assert.equal(status.mobile, true);
|
||||||
|
assert.equal(status.status, "offline");
|
||||||
|
|
||||||
|
}());
|
||||||
|
|
Loading…
Reference in New Issue