Add new Last Seen Indicator with unread count, scroll to it
This is to ensure that when there are a lot of unread messages, the user is given the chance to see all of them by being scrolled to the oldest new message. When a new message comes in, the indicator will be incremented. When the user sends a message or switches away from the conversation, the last seen indicator will be removed. FREEBIE
This commit is contained in:
parent
bec69826ae
commit
fed26c36ca
8 changed files with 133 additions and 2 deletions
|
@ -3,6 +3,20 @@
|
|||
"message": "You left the group",
|
||||
"description": "Displayed when a user can't send a message because they have left the group"
|
||||
},
|
||||
"unreadMessage": {
|
||||
"message": "1 unread message",
|
||||
"description": "Text for unread message separator, just one message"
|
||||
},
|
||||
"unreadMessages": {
|
||||
"message": "$count$ unread messages",
|
||||
"description": "Text for unread message separator, with count",
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"content": "$1",
|
||||
"example": "5"
|
||||
}
|
||||
}
|
||||
},
|
||||
"debugLogExplanation": {
|
||||
"message": "This log will be posted publicly online for contributors to view. You may examine and edit it before submitting."
|
||||
},
|
||||
|
|
|
@ -42,6 +42,11 @@
|
|||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script type='text/x-tmpl-mustache' id='last-seen-indicator-view'>
|
||||
<div class='text'>
|
||||
{{ unreadMessages }}
|
||||
</div>
|
||||
</script>
|
||||
<script type='text/x-tmpl-mustache' id='expired_alert'>
|
||||
<a target='_blank' href='https://chrome.google.com/webstore/detail/bikioccmkafdpakkkcpdbppfkghcmihk'>
|
||||
<button class='upgrade'>{{ upgrade }}</button>
|
||||
|
@ -630,6 +635,7 @@
|
|||
<script type='text/javascript' src='js/emoji_util.js'></script>
|
||||
|
||||
<script type='text/javascript' src='js/views/whisper_view.js'></script>
|
||||
<script type='text/javascript' src='js/views/last_seen_indicator_view.js'></script>
|
||||
<script type='text/javascript' src='js/views/debug_log_view.js'></script>
|
||||
<script type='text/javascript' src='js/views/toast_view.js'></script>
|
||||
<script type='text/javascript' src='js/views/attachment_preview_view.js'></script>
|
||||
|
|
|
@ -201,11 +201,45 @@
|
|||
this.$('.bottom-bar form').addClass('active');
|
||||
},
|
||||
|
||||
updateUnread: function() {
|
||||
this.updateLastSeenIndicator();
|
||||
this.model.markRead();
|
||||
},
|
||||
|
||||
onOpened: function() {
|
||||
this.view.resetScrollPosition();
|
||||
this.$el.trigger('force-resize');
|
||||
this.focusMessageField();
|
||||
this.model.markRead();
|
||||
|
||||
if (this.inProgressFetch) {
|
||||
this.inProgressFetch.then(this.updateUnread.bind(this));
|
||||
} else {
|
||||
this.updateUnread();
|
||||
}
|
||||
},
|
||||
|
||||
removeLastSeenIndicator: function() {
|
||||
if (this.lastSeenIndicator) {
|
||||
this.lastSeenIndicator.remove();
|
||||
this.lastSeenIndicator = null;
|
||||
}
|
||||
},
|
||||
|
||||
updateLastSeenIndicator: function() {
|
||||
this.removeLastSeenIndicator();
|
||||
|
||||
var oldestUnread = this.model.messageCollection.find(function(model) {
|
||||
return model.get('unread');
|
||||
});
|
||||
|
||||
if (oldestUnread) {
|
||||
var unreadCount = this.model.get('unreadCount');
|
||||
this.lastSeenIndicator = new Whisper.LastSeenIndicatorView({count: unreadCount});
|
||||
var unreadEl = this.lastSeenIndicator.render().$el;
|
||||
|
||||
unreadEl.insertBefore(this.$('#' + oldestUnread.get('id')));
|
||||
var position = unreadEl[0].scrollIntoView(true);
|
||||
}
|
||||
},
|
||||
|
||||
focusMessageField: function() {
|
||||
|
@ -215,15 +249,18 @@
|
|||
fetchMessages: function() {
|
||||
console.log('fetchMessages');
|
||||
this.$('.bar-container').show();
|
||||
return this.model.fetchContacts().then(function() {
|
||||
this.inProgressFetch = this.model.fetchContacts().then(function() {
|
||||
return this.model.fetchMessages().then(function() {
|
||||
this.$('.bar-container').hide();
|
||||
this.model.messageCollection.where({unread: 1}).forEach(function(m) {
|
||||
m.fetch();
|
||||
});
|
||||
this.inProgressFetch = null;
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
// TODO catch?
|
||||
|
||||
return this.inProgressFetch;
|
||||
},
|
||||
|
||||
onExpired: function(message) {
|
||||
|
@ -241,6 +278,10 @@
|
|||
this.model.messageCollection.add(message, {merge: true});
|
||||
message.setToExpire();
|
||||
|
||||
if (this.lastSeenIndicator) {
|
||||
this.lastSeenIndicator.increment(1);
|
||||
}
|
||||
|
||||
if (!this.isHidden() && window.isFocused()) {
|
||||
this.markRead();
|
||||
}
|
||||
|
@ -345,6 +386,8 @@
|
|||
},
|
||||
|
||||
sendMessage: function(e) {
|
||||
this.removeLastSeenIndicator();
|
||||
|
||||
var toast;
|
||||
if (extension.expired()) {
|
||||
toast = new Whisper.ExpiredToast();
|
||||
|
|
30
js/views/last_seen_indicator_view.js
Normal file
30
js/views/last_seen_indicator_view.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* vim: ts=4:sw=4:expandtab
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
window.Whisper = window.Whisper || {};
|
||||
|
||||
Whisper.LastSeenIndicatorView = Whisper.View.extend({
|
||||
className: 'last-seen-indicator-view',
|
||||
templateName: 'last-seen-indicator-view',
|
||||
initialize: function(options) {
|
||||
options = options || {};
|
||||
this.count = options.count || 0;
|
||||
},
|
||||
|
||||
increment: function(count) {
|
||||
this.count += count;
|
||||
this.render();
|
||||
},
|
||||
|
||||
render_attributes: function() {
|
||||
var unreadMessages = this.count === 1 ? i18n('unreadMessage')
|
||||
: i18n('unreadMessages', [this.count]);
|
||||
|
||||
return {
|
||||
unreadMessages: unreadMessages
|
||||
};
|
||||
}
|
||||
});
|
||||
})();
|
|
@ -70,4 +70,8 @@
|
|||
.inactive button.back {
|
||||
@include header-icon-black('/images/back.svg');
|
||||
}
|
||||
|
||||
.message-list .last-seen-indicator-view .text {
|
||||
margin-top: 2em;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -682,3 +682,17 @@ li.entry .error-icon-container {
|
|||
border-radius: $border-radius;
|
||||
}
|
||||
}
|
||||
|
||||
.message-list .last-seen-indicator-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.text {
|
||||
border-radius: $border-radius;
|
||||
padding: 5px 10px;
|
||||
margin: 1em;
|
||||
|
||||
background-color: $grey_l2;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -202,4 +202,9 @@ $text-dark: #CCCCCC;
|
|||
.recorder {
|
||||
background: $grey-dark_l2;
|
||||
}
|
||||
|
||||
.message-list .last-seen-indicator-view .text {
|
||||
margin-top: 2em;
|
||||
background-color: $grey-dark_l2;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1496,6 +1496,16 @@ li.entry .error-icon-container {
|
|||
color: #454545;
|
||||
border-radius: 5px; }
|
||||
|
||||
.message-list .last-seen-indicator-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center; }
|
||||
.message-list .last-seen-indicator-view .text {
|
||||
border-radius: 5px;
|
||||
padding: 5px 10px;
|
||||
margin: 1em;
|
||||
background-color: #d9d9d9; }
|
||||
|
||||
.ios #header {
|
||||
height: 64px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||
|
@ -1838,6 +1848,8 @@ li.entry .error-icon-container {
|
|||
-webkit-mask: url("/images/back.svg") no-repeat center;
|
||||
-webkit-mask-size: 100%;
|
||||
background-color: black; }
|
||||
.android .message-list .last-seen-indicator-view .text {
|
||||
margin-top: 2em; }
|
||||
|
||||
.android-dark {
|
||||
color: #CCCCCC; }
|
||||
|
@ -2098,5 +2110,8 @@ li.entry .error-icon-container {
|
|||
background-color: #292929; }
|
||||
.android-dark .recorder {
|
||||
background: #292929; }
|
||||
.android-dark .message-list .last-seen-indicator-view .text {
|
||||
margin-top: 2em;
|
||||
background-color: #292929; }
|
||||
|
||||
/*# sourceMappingURL=manifest.css.map */
|
||||
|
|
Loading…
Reference in a new issue