diff --git a/platypush/backend/http/static/css/application.css b/platypush/backend/http/static/css/application.css
index 46663d87a..580392225 100644
--- a/platypush/backend/http/static/css/application.css
+++ b/platypush/backend/http/static/css/application.css
@@ -203,6 +203,11 @@ button[disabled] {
font-size: 25px;
}
+ #notification-container * > .notification-image img {
+ width: 80%;
+ height: 80%;
+ }
+
#hidden-plugins-container > .plugin {
display: none;
}
diff --git a/platypush/backend/http/static/css/dashboard.css b/platypush/backend/http/static/css/dashboard.css
new file mode 100644
index 000000000..7c7b03992
--- /dev/null
+++ b/platypush/backend/http/static/css/dashboard.css
@@ -0,0 +1,17 @@
+body {
+ background: rgba(240,240,245,1.0);
+ font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
+}
+
+#widgets-container {
+ padding: 1em;
+}
+
+.widget {
+ background: white;
+ border-radius: 5px;
+ height: 18em;
+ overflow: hidden;
+ box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16), 0 0 0 1px rgba(0,0,0,0.08);
+}
+
diff --git a/platypush/backend/http/static/css/widgets/date-time-weather.css b/platypush/backend/http/static/css/widgets/date-time-weather.css
new file mode 100644
index 000000000..6790ba2f9
--- /dev/null
+++ b/platypush/backend/http/static/css/widgets/date-time-weather.css
@@ -0,0 +1,17 @@
+.widget.date-time-weather {
+ text-align: center;
+}
+
+.date-time-weather-container {
+ padding: 2rem;
+}
+
+h1.temperature {
+ font-size: 45px;
+ margin: 4rem;
+}
+
+ .widget.date-time-weather * > .time {
+ font-size: 22px;
+ }
+
diff --git a/platypush/backend/http/static/css/widgets/music.css b/platypush/backend/http/static/css/widgets/music.css
new file mode 100644
index 000000000..3ed8d1e99
--- /dev/null
+++ b/platypush/backend/http/static/css/widgets/music.css
@@ -0,0 +1,49 @@
+.music-container {
+ width: inherit;
+ height: inherit;
+ display: table-cell;
+ vertical-align: middle;
+ text-align: center;
+}
+
+.track-info {
+ font-size: 20px;
+}
+
+ .track-info > .artist {
+ font-weight: bold;
+ margin-bottom: 1rem;
+ }
+
+ .track-info > .title {
+ margin-bottom: 2rem;
+ }
+
+.time-bar {
+ height: 7.5px;
+ background: #ddd;
+ margin: 7.5px;
+ border-radius: 10px;
+}
+
+ .time-bar > .elapsed {
+ height: 7.5px;
+ background: #98ffb0;
+ border-radius: 10px;
+ }
+
+.time-elapsed {
+ text-align: left;
+ margin-left: 1rem;
+}
+
+.time-total {
+ float: right;
+ margin-right: 1rem;
+}
+
+.time-elapsed, .time-total {
+ color: rgba(0, 0, 0, 0.7);
+ letter-spacing: 1px;
+}
+
diff --git a/platypush/backend/http/static/js/pushbullet.js b/platypush/backend/http/static/js/pushbullet.js
new file mode 100644
index 000000000..65f1b081e
--- /dev/null
+++ b/platypush/backend/http/static/js/pushbullet.js
@@ -0,0 +1,27 @@
+$(document).ready(function() {
+ var onEvent = function(event) {
+ switch (event.args.type) {
+ case 'platypush.message.event.pushbullet.PushbulletEvent':
+ if (event.args.push_type === 'mirror') {
+ createNotification({
+ 'title': event.args.title,
+ 'text': event.args.body,
+ 'image': 'data:image/png;base64, ' + event.args.icon,
+ });
+ }
+
+ break;
+ }
+ };
+
+ var initEvents = function() {
+ window.registerEventListener(onEvent);
+ };
+
+ var init = function() {
+ initEvents();
+ };
+
+ init();
+});
+
diff --git a/platypush/backend/http/static/js/widgets/music.js b/platypush/backend/http/static/js/widgets/music.js
new file mode 100644
index 000000000..24d5c2a72
--- /dev/null
+++ b/platypush/backend/http/static/js/widgets/music.js
@@ -0,0 +1,123 @@
+$(document).ready(function() {
+ var $widget = $('.widget.music'),
+ $trackContainer = $widget.find('.track-container'),
+ $timeContainer = $widget.find('.time-container'),
+ $noTrackElement = $trackContainer.find('.no-track-info'),
+ $trackElement = $trackContainer.find('.track-info'),
+ $artistElement = $trackElement.find('[data-bind=artist]'),
+ $titleElement = $trackElement.find('[data-bind=title]'),
+ $timeElapsedElement = $timeContainer.find('.time-elapsed'),
+ $timeTotalElement = $timeContainer.find('.time-total'),
+ $elapsedTimeBar = $widget.find('.time-bar > .elapsed'),
+ timeElapsed,
+ timeTotal,
+ refreshElapsedInterval;
+
+ var onEvent = function(event) {
+ switch (event.args.type) {
+ case 'platypush.message.event.music.NewPlayingTrackEvent':
+ createNotification({
+ 'icon': 'play',
+ 'html': '' + ('artist' in event.args.track ? event.args.track.artist : '')
+ + '
'
+ + ('title' in event.args.track ? event.args.track.title : '[No name]'),
+ });
+
+ case 'platypush.message.event.music.MusicPlayEvent':
+ case 'platypush.message.event.music.MusicPauseEvent':
+ refreshTrack(event.args.track);
+
+ case 'platypush.message.event.music.MusicStopEvent':
+ refreshStatus(event.args.status);
+ break;
+ }
+ };
+
+ var initEvents = function() {
+ window.registerEventListener(onEvent);
+ };
+
+
+ var setState = function(state) {
+ if (state === 'play') {
+ $noTrackElement.hide();
+ $trackElement.show();
+ $timeContainer.show();
+ } else if (state === 'pause') {
+ $noTrackElement.hide();
+ $trackElement.show();
+ $timeContainer.hide();
+ } else if (state === 'stop') {
+ $noTrackElement.show();
+ $trackElement.hide();
+ $timeContainer.hide();
+ }
+ };
+
+ var secondsToTimeString = function(seconds) {
+ seconds = parseInt(seconds);
+
+ if (seconds) {
+ return (parseInt(seconds/60) + ':' +
+ (seconds%60 < 10 ? '0' : '') + seconds%60);
+ } else {
+ return '-:--';
+ }
+ };
+
+ var setTrackTime = function(time) {
+ $timeTotalElement.text(secondsToTimeString(time));
+ timeTotal = parseInt(time);
+ };
+
+ var setTrackElapsed = function(time) {
+ if (refreshElapsedInterval) {
+ clearInterval(refreshElapsedInterval);
+ refreshElapsedInterval = undefined;
+ }
+
+ timeElapsed = parseInt(time);
+ $timeElapsedElement.text(secondsToTimeString(timeElapsed));
+
+ var ratio = 100 * Math.min(timeElapsed/timeTotal, 1);
+ $elapsedTimeBar.css('width', ratio + '%');
+
+ refreshElapsedInterval = setInterval(function() {
+ timeElapsed += 1;
+ ratio = 100 * Math.min(timeElapsed/timeTotal, 1);
+ $elapsedTimeBar.css('width', ratio + '%');
+ $timeElapsedElement.text(secondsToTimeString(timeElapsed));
+ }, 1000);
+ };
+
+ var refreshStatus = function(status) {
+ setState(state=status.state);
+ if ('elapsed' in status) {
+ setTrackElapsed(status.elapsed);
+ }
+ };
+
+ var refreshTrack = function(track) {
+ setTrackTime(track.time);
+ $artistElement.text(track.artist);
+ $titleElement.text(track.title);
+ };
+
+ var initWidget = function() {
+ $.when(
+ execute({ type: 'request', action: 'music.mpd.currentsong' }),
+ execute({ type: 'request', action: 'music.mpd.status' })
+ ).done(function(t, s) {
+ refreshTrack(t[0].response.output);
+ refreshStatus(s[0].response.output);
+ });
+ };
+
+ var init = function() {
+ initEvents();
+ initWidget();
+ };
+
+ init();
+});
+
diff --git a/platypush/backend/http/templates/dashboard.html b/platypush/backend/http/templates/dashboard.html
index ef25b4a29..19926bab9 100644
--- a/platypush/backend/http/templates/dashboard.html
+++ b/platypush/backend/http/templates/dashboard.html
@@ -7,12 +7,14 @@
+
+
+
+
-