Render identicons in notifications
Render an svg, then canvas, then data url. Fixes #325 // FREEBIE
This commit is contained in:
parent
3bd9108f6e
commit
0ebdf08ceb
4 changed files with 90 additions and 11 deletions
|
@ -87,9 +87,17 @@
|
||||||
<div class='scrollable'></div>
|
<div class='scrollable'></div>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
<script type='text/x-tmpl-mustache' id='identicon-svg'>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="44" height="44">
|
||||||
|
<circle cx="22" cy="22" r="22" fill="{{ color }}" />
|
||||||
|
<text text-anchor="middle" fill="white" font-size="14px" x="22" y="22" baseline-shift="-4px">
|
||||||
|
{{ content }}
|
||||||
|
</text>
|
||||||
|
</svg>
|
||||||
|
</script>
|
||||||
<script type='text/x-tmpl-mustache' id='avatar'>
|
<script type='text/x-tmpl-mustache' id='avatar'>
|
||||||
<span class='avatar {{#avatar.color }} color{{avatar.color}} {{/avatar.color}}'
|
<span class='avatar'
|
||||||
style='background-image: url("{{ avatar.url }}");'>
|
style='background-image: url("{{ avatar.url }}"); background-color: {{ avatar.color }}'>
|
||||||
{{ avatar.content }}
|
{{ avatar.content }}
|
||||||
</span>
|
</span>
|
||||||
</script>
|
</script>
|
||||||
|
@ -286,6 +294,7 @@
|
||||||
<script type="text/javascript" src="js/views/window_controls_view.js"></script>
|
<script type="text/javascript" src="js/views/window_controls_view.js"></script>
|
||||||
<script type="text/javascript" src="js/views/inbox_view.js"></script>
|
<script type="text/javascript" src="js/views/inbox_view.js"></script>
|
||||||
<script type="text/javascript" src="js/views/confirmation_dialog_view.js"></script>
|
<script type="text/javascript" src="js/views/confirmation_dialog_view.js"></script>
|
||||||
|
<script type="text/javascript" src="js/views/identicon_svg_view.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="js/background.js"></script>
|
<script type="text/javascript" src="js/background.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
@ -7,6 +7,24 @@
|
||||||
|
|
||||||
// TODO: Factor out private and group subclasses of Conversation
|
// TODO: Factor out private and group subclasses of Conversation
|
||||||
|
|
||||||
|
var COLORS = [
|
||||||
|
"#EF5350", // red
|
||||||
|
"#EC407A", // pink
|
||||||
|
"#AB47BC", // purple
|
||||||
|
"#7E57C2", // deep purple
|
||||||
|
"#5C6BC0", // indigo
|
||||||
|
"#2196F3", // blue
|
||||||
|
"#03A9F4", // light blue
|
||||||
|
"#00BCD4", // cyan
|
||||||
|
"#009688", // teal
|
||||||
|
"#4CAF50", // green
|
||||||
|
"#7CB342", // light green
|
||||||
|
"#FF9800", // orange
|
||||||
|
"#FF5722", // deep orange
|
||||||
|
"#FFB300", // amber
|
||||||
|
"#607D8B", // blue grey
|
||||||
|
];
|
||||||
|
|
||||||
Whisper.Conversation = Backbone.Model.extend({
|
Whisper.Conversation = Backbone.Model.extend({
|
||||||
database: Whisper.Database,
|
database: Whisper.Database,
|
||||||
storeName: 'conversations',
|
storeName: 'conversations',
|
||||||
|
@ -219,6 +237,17 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getNotificationIcon: function() {
|
||||||
|
return new Promise(function(resolve) {
|
||||||
|
var avatar = this.getAvatar();
|
||||||
|
if (avatar.url) {
|
||||||
|
resolve(avatar.url);
|
||||||
|
} else {
|
||||||
|
resolve(new Whisper.IdenticonSVGView(avatar).getDataUrl());
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
updateAvatarUrl: function(silent) {
|
updateAvatarUrl: function(silent) {
|
||||||
this.revokeAvatarUrl();
|
this.revokeAvatarUrl();
|
||||||
var avatar = this.get('avatar');
|
var avatar = this.get('avatar');
|
||||||
|
@ -243,11 +272,11 @@
|
||||||
} else if (this.isPrivate()) {
|
} else if (this.isPrivate()) {
|
||||||
var title = this.get('name');
|
var title = this.get('name');
|
||||||
if (!title) {
|
if (!title) {
|
||||||
return { content: '#', color: 'gray' };
|
return { content: '#', color: '#999999' };
|
||||||
}
|
}
|
||||||
var initials = title.trim()[0];
|
var initials = title.trim()[0];
|
||||||
return {
|
return {
|
||||||
color: 1 + (Math.abs(this.hashCode()) % 15),
|
color: COLORS[Math.abs(this.hashCode()) % 15],
|
||||||
content: initials
|
content: initials
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -93,14 +93,16 @@
|
||||||
var sender = ConversationController.create({id: message.get('source')});
|
var sender = ConversationController.create({id: message.get('source')});
|
||||||
conversation.fetch().then(function() {
|
conversation.fetch().then(function() {
|
||||||
sender.fetch().then(function() {
|
sender.fetch().then(function() {
|
||||||
var notification = new Notification(sender.getTitle(), {
|
sender.getNotificationIcon().then(function(icon) {
|
||||||
body: message.getDescription(),
|
var notification = new Notification(sender.getTitle(), {
|
||||||
icon: sender.getAvatar().url,
|
body: message.getDescription(),
|
||||||
tag: conversation.id
|
icon: icon,
|
||||||
|
tag: conversation.id
|
||||||
|
});
|
||||||
|
notification.onclick = function() {
|
||||||
|
openConversation(conversation);
|
||||||
|
};
|
||||||
});
|
});
|
||||||
notification.onclick = function() {
|
|
||||||
openConversation(conversation);
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
39
js/views/identicon_svg_view.js
Normal file
39
js/views/identicon_svg_view.js
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* vim: ts=4:sw=4:expandtab
|
||||||
|
*/
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
window.Whisper = window.Whisper || {};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Render an avatar identicon to an svg for use in a notification.
|
||||||
|
*/
|
||||||
|
Whisper.IdenticonSVGView = Whisper.View.extend({
|
||||||
|
templateName: 'identicon-svg',
|
||||||
|
initialize: function(options) {
|
||||||
|
this.render_attributes = options;
|
||||||
|
},
|
||||||
|
getSVGUrl: function() {
|
||||||
|
var html = this.render().$el.html();
|
||||||
|
var svg = new Blob([html], {type: 'image/svg+xml;charset=utf-8'});
|
||||||
|
return URL.createObjectURL(svg);
|
||||||
|
},
|
||||||
|
getDataUrl: function() {
|
||||||
|
var svgurl = this.getSVGUrl();
|
||||||
|
return new Promise(function(resolve) {
|
||||||
|
var img = document.createElement('img');
|
||||||
|
img.onload = function () {
|
||||||
|
var canvas = loadImage.scale(img, {
|
||||||
|
canvas: true, maxWidth: 44, maxHeight: 44
|
||||||
|
});
|
||||||
|
var ctx = canvas.getContext('2d');
|
||||||
|
ctx.drawImage(img, 0, 0);
|
||||||
|
URL.revokeObjectURL(svgurl);
|
||||||
|
resolve(canvas.toDataURL("image/png"));
|
||||||
|
};
|
||||||
|
|
||||||
|
img.src = svgurl;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
Loading…
Reference in a new issue