diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index 61a5424c6..802162e07 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -475,6 +475,10 @@
"message": "Message not sent.",
"description": "Informational label, appears on messages that failed to send"
},
+ "someRecipientsFailed": {
+ "message": "Some recipients failed",
+ "description": "Informational label, for messages where some recipients succeeded, others failed"
+ },
"showMore": {
"message": "Details",
"description": "Displays the details of a key change"
diff --git a/background.html b/background.html
index 17bac7fbd..a1129bb75 100644
--- a/background.html
+++ b/background.html
@@ -191,6 +191,9 @@
{{ messageNotSent }}
{{ resend }}
+
diff --git a/js/models/messages.js b/js/models/messages.js
index 7903443bf..6f1c5b108 100644
--- a/js/models/messages.js
+++ b/js/models/messages.js
@@ -249,6 +249,25 @@
}.bind(this));
},
+ someRecipientsFailed: function() {
+ var c = this.getConversation();
+ if (c.isPrivate()) {
+ return false;
+ }
+
+ var recipients = c.contactCollection.length - 1;
+ var errors = this.get('errors');
+ if (!errors) {
+ return false;
+ }
+
+ if (errors.length > 0 && recipients > 0 && errors.length < recipients) {
+ return true;
+ }
+
+ return false;
+ },
+
sendSyncMessage: function() {
this.syncPromise = this.syncPromise || Promise.resolve();
this.syncPromise = this.syncPromise.then(function() {
diff --git a/js/views/message_view.js b/js/views/message_view.js
index 707825cbb..31b3b468e 100644
--- a/js/views/message_view.js
+++ b/js/views/message_view.js
@@ -25,6 +25,14 @@
resend: i18n('resend')
}
});
+ var SomeFailedView = Whisper.View.extend({
+ tagName: 'span',
+ className: 'some-failed',
+ templateName: 'some-failed',
+ render_attributes: {
+ someFailed: i18n('someRecipientsFailed')
+ }
+ });
var TimerView = Whisper.View.extend({
templateName: 'hourglass',
update: function() {
@@ -172,6 +180,7 @@
'click .error-icon': 'select',
'click .timestamp': 'select',
'click .status': 'select',
+ 'click .some-failed': 'select',
'click .error-message': 'select'
},
retryMessage: function() {
@@ -241,6 +250,10 @@
if (this.model.hasNetworkError()) {
this.$('.meta').prepend(new NetworkErrorView().render().el);
}
+ this.$('.meta .some-failed').remove();
+ if (this.model.someRecipientsFailed()) {
+ this.$('.meta').prepend(new SomeFailedView().render().el);
+ }
},
renderControl: function() {
if (this.model.isEndSession() || this.model.isGroupUpdate()) {
diff --git a/stylesheets/_conversation.scss b/stylesheets/_conversation.scss
index 4bc0593ac..3474573c3 100644
--- a/stylesheets/_conversation.scss
+++ b/stylesheets/_conversation.scss
@@ -406,11 +406,17 @@ li.entry .error-icon-container {
cursor: pointer;
}
+ .some-failed {
+ float: left;
+ margin-left: 6px;
+ margin-right: 6px;
+ }
+
.hasRetry, .timestamp, .status, .timer {
float: left;
}
- .timestamp, .status {
+ .timestamp, .status, .some-failed {
cursor: pointer;
opacity: 0.5;
diff --git a/stylesheets/manifest.css b/stylesheets/manifest.css
index 45842eb7c..cc8dc584d 100644
--- a/stylesheets/manifest.css
+++ b/stylesheets/manifest.css
@@ -1332,20 +1332,27 @@ li.entry .error-icon-container {
.message-list .meta .retry {
text-decoration: underline;
cursor: pointer; }
+ .message-container .meta .some-failed,
+ .message-list .meta .some-failed {
+ float: left;
+ margin-left: 6px;
+ margin-right: 6px; }
.message-container .meta .hasRetry, .message-container .meta .timestamp, .message-container .meta .status, .message-container .meta .timer,
.message-list .meta .hasRetry,
.message-list .meta .timestamp,
.message-list .meta .status,
.message-list .meta .timer {
float: left; }
- .message-container .meta .timestamp, .message-container .meta .status,
+ .message-container .meta .timestamp, .message-container .meta .status, .message-container .meta .some-failed,
.message-list .meta .timestamp,
- .message-list .meta .status {
+ .message-list .meta .status,
+ .message-list .meta .some-failed {
cursor: pointer;
opacity: 0.5; }
- .message-container .meta .timestamp:hover, .message-container .meta .status:hover,
+ .message-container .meta .timestamp:hover, .message-container .meta .status:hover, .message-container .meta .some-failed:hover,
.message-list .meta .timestamp:hover,
- .message-list .meta .status:hover {
+ .message-list .meta .status:hover,
+ .message-list .meta .some-failed:hover {
opacity: 1.0; }
.message-container .status,
.message-list .status {