diff --git a/platypush/backend/http/__init__.py b/platypush/backend/http/__init__.py index cb77e4704..2d78fb7e5 100644 --- a/platypush/backend/http/__init__.py +++ b/platypush/backend/http/__init__.py @@ -25,6 +25,9 @@ class HttpBackend(Backend): websocket_ping_tries = 3 websocket_ping_timeout = 60.0 + hidden_plugins = { + 'assistant.google' + } def __init__(self, port=8008, websocket_port=8009, disable_websocket=False, token=None, **kwargs): @@ -98,13 +101,17 @@ class HttpBackend(Backend): def index(): configured_plugins = Config.get_plugins() enabled_plugins = {} + hidden_plugins = {} for plugin, conf in configured_plugins.items(): template_file = os.path.join('plugins', plugin + '.html') if os.path.isfile(os.path.join(template_dir, template_file)): - enabled_plugins[plugin] = conf + if plugin in self.hidden_plugins: + hidden_plugins[plugin] = conf + else: + enabled_plugins[plugin] = conf - return render_template('index.html', plugins=enabled_plugins, + return render_template('index.html', plugins=enabled_plugins, hidden_plugins=hidden_plugins, token=self.token, websocket_port=self.websocket_port) diff --git a/platypush/backend/http/static/css/application.css b/platypush/backend/http/static/css/application.css index 2dab9f307..46663d87a 100644 --- a/platypush/backend/http/static/css/application.css +++ b/platypush/backend/http/static/css/application.css @@ -144,3 +144,66 @@ button[disabled] { text-align: right !important; } +#notification-container { + position: fixed; + bottom: 0; + right: 0; + width: 25em; +} + + #notification-container > .notification { + background: rgba(180,245,188,0.85); + border: 1px solid #bbb; + border-radius: 5px; + margin-bottom: 1rem; + margin-right: 1rem; + cursor: pointer; + display: none; + } + + #notification-container > .notification:hover { + background: rgba(160,235,168,0.9); + } + + #notification-container * > .notification-title { + padding: 4px 10px; + font-weight: bold; + text-transform: capitalize; + line-height: 30px; + letter-spacing: .1rem; + } + + #notification-container * > .notification-body { + height: 6em; + overflow: hidden; + padding-bottom: 1rem; + letter-spacing: .05rem; + } + + #notification-container * > .notification-text { + margin-left: 0 !important; + } + + #notification-container * > .notification-image { + height: 100%; + text-align: center; + padding-top: .6em; + padding-bottom: .6em; + } + + #notification-container * > .notification-image-item { + width: 100%; + height: 100%; + margin: auto; + } + + #notification-container * > .fa.notification-image-item { + margin-top: .8em; + margin-left: .2em; + font-size: 25px; + } + +#hidden-plugins-container > .plugin { + display: none; +} + diff --git a/platypush/backend/http/static/css/assistant.google.css b/platypush/backend/http/static/css/assistant.google.css new file mode 100644 index 000000000..e69de29bb diff --git a/platypush/backend/http/static/js/application.js b/platypush/backend/http/static/js/application.js index 5604e1332..b841bffe1 100644 --- a/platypush/backend/http/static/js/application.js +++ b/platypush/backend/http/static/js/application.js @@ -176,3 +176,112 @@ $(document).ready(function() { init(); }); +function execute(request, onSuccess, onError, onComplete) { + request['target'] = 'localhost'; + return $.ajax({ + type: 'POST', + url: '/execute', + contentType: 'application/json', + dataType: 'json', + data: JSON.stringify(request), + complete: function() { + if (onComplete) { + onComplete(); + } + }, + error: function(xhr, status, error) { + if (onError) { + onError(xhr, status, error); + } + }, + success: function(response, status, xhr) { + if (onSuccess) { + onSuccess(response, status, xhr); + } + }, + beforeSend: function(xhr) { + if (window.token) { + xhr.setRequestHeader('X-Token', window.token); + } + }, + }); +} + +function createNotification(options) { + var $notificationContainer = $('#notification-container'); + var $notification = $('
').addClass('notification'); + var $title = $('').addClass('notification-title'); + var timeout = 'timeout' in options ? options.timeout : 10000; + + if ('title' in options) { + $title.text(options.title); + } + + var $body = $('').addClass('notification-body'); + var $imgDiv = $('').addClass('notification-image').addClass('three columns'); + var $img = $('').addClass('fa fa-bell').addClass('three columns').addClass('notification-image-item'); + var $text = $('').addClass('notification-text').addClass('nine columns') + + if ('image' in options) { + $img = $('').attr('src', options.image); + } else if ('icon' in options) { + $img.removeClass('fa-bell').addClass('fa-' + options.icon); + } + + if ('text' in options) { + $text.text(options.text); + } else if ('html' in options) { + $text.html(options.html); + } + + $img.appendTo($imgDiv); + $imgDiv.appendTo($body); + $text.appendTo($body); + + var clickHandler; + var removeTimeoutId; + + var removeNotification = function() { + $notification.fadeOut(300, function() { + $notification.remove(); + }); + }; + + var setRemoveTimeout = function() { + if (timeout) { + removeTimeoutId = setTimeout(removeNotification, timeout); + } + }; + + setRemoveTimeout(); + + if ('onclick' in options) { + clickHandler = options.onclick; + } else { + clickHandler = removeNotification; + } + + $notification.on('click', clickHandler); + $notification.hover( + // on hover start + function() { + if (removeTimeoutId) { + clearTimeout(removeTimeoutId); + removeTimeoutId = undefined; + } + }, + + // on hover end + function() { + if (timeout) { + setRemoveTimeout(); + } + } + ); + + $title.appendTo($notification); + $body.appendTo($notification); + $notification.prependTo($notificationContainer); + $notification.fadeIn(); +} + diff --git a/platypush/backend/http/static/js/assistant.google.js b/platypush/backend/http/static/js/assistant.google.js new file mode 100644 index 000000000..7d01e25c6 --- /dev/null +++ b/platypush/backend/http/static/js/assistant.google.js @@ -0,0 +1,36 @@ +$(document).ready(function() { + var onEvent = function(event) { + switch (event.args.type) { + case 'platypush.message.event.assistant.ConversationStartEvent': + createNotification({ + 'text': 'Assistant listening', + 'icon': 'microphone', + }); + + break; + + case 'platypush.message.event.assistant.SpeechRecognizedEvent': + createNotification({ + 'title': 'Speech recognized', + 'text': event.args.phrase, + 'icon': 'microphone', + }); + + break; + + case 'platypush.message.event.assistant.ConversationEndEvent': + break; + } + }; + + var initEvents = function() { + window.registerEventListener(onEvent); + }; + + var init = function() { + initEvents(); + }; + + init(); +}); + diff --git a/platypush/backend/http/static/js/gpio.zeroborg.js b/platypush/backend/http/static/js/gpio.zeroborg.js index 9ac182278..037e0f811 100644 --- a/platypush/backend/http/static/js/gpio.zeroborg.js +++ b/platypush/backend/http/static/js/gpio.zeroborg.js @@ -3,37 +3,6 @@ $(document).ready(function() { $controlsContainer = $('.zb-controls-container'), curDirection = undefined; - var execute = function(request, onSuccess, onError, onComplete) { - request['target'] = 'localhost'; - return $.ajax({ - type: 'POST', - url: '/execute', - contentType: 'application/json', - dataType: 'json', - data: JSON.stringify(request), - complete: function() { - if (onComplete) { - onComplete(); - } - }, - error: function(xhr, status, error) { - if (onError) { - onError(xhr, status, error); - } - }, - success: function(response, status, xhr) { - if (onSuccess) { - onSuccess(response, status, xhr); - } - }, - beforeSend: function(xhr) { - if (window.token) { - xhr.setRequestHeader('X-Token', window.token); - } - }, - }); - }; - var initBindings = function() { $controlsContainer.on('mousedown touchstart', '.zb-ctrl-btn[data-direction]', function() { var direction = $(this).data('direction'); diff --git a/platypush/backend/http/static/js/light.hue.js b/platypush/backend/http/static/js/light.hue.js index d1d8a96bb..e1d009f40 100644 --- a/platypush/backend/http/static/js/light.hue.js +++ b/platypush/backend/http/static/js/light.hue.js @@ -6,37 +6,6 @@ $(document).ready(function() { $lightsList = $('#lights-list'), $scenesList = $('#scenes-list'); - var execute = function(request, onSuccess, onError, onComplete) { - request['target'] = 'localhost'; - return $.ajax({ - type: 'POST', - url: '/execute', - contentType: 'application/json', - dataType: 'json', - data: JSON.stringify(request), - complete: function() { - if (onComplete) { - onComplete(); - } - }, - error: function(xhr, status, error) { - if (onError) { - onError(xhr, status, error); - } - }, - success: function(response, status, xhr) { - if (onSuccess) { - onSuccess(response, status, xhr); - } - }, - beforeSend: function(xhr) { - if (window.token) { - xhr.setRequestHeader('X-Token', window.token); - } - }, - }); - }; - var createPowerToggleElement = function(data) { var id = data['type'] + '_' + data['id']; var $powerToggle = $('').addClass('toggle toggle--push light-ctrl-switch-container'); diff --git a/platypush/backend/http/static/js/music.mpd.js b/platypush/backend/http/static/js/music.mpd.js index 3608c6a47..7613e7169 100644 --- a/platypush/backend/http/static/js/music.mpd.js +++ b/platypush/backend/http/static/js/music.mpd.js @@ -16,37 +16,6 @@ $(document).ready(function() { $resetSearchBtn = $('#music-search-reset'); $doSearchBtns = $('.do-search-btns'); - var execute = function(request, onSuccess, onError, onComplete) { - request['target'] = 'localhost'; - $.ajax({ - type: 'POST', - url: '/execute', - contentType: 'application/json', - dataType: 'json', - data: JSON.stringify(request), - complete: function() { - if (onComplete) { - onComplete(); - } - }, - error: function(xhr, status, error) { - if (onError) { - onError(xhr, status, error); - } - }, - success: function(response, status, xhr) { - if (onSuccess) { - onSuccess(response, status, xhr); - } - }, - beforeSend: function(xhr) { - if (window.token) { - xhr.setRequestHeader('X-Token', window.token); - } - }, - }); - }; - var formatMinutes = function(time) { if (typeof time === 'string') { time = parseInt(time); @@ -198,10 +167,17 @@ $(document).ready(function() { 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 : '') + + '