diff --git a/platypush/backend/http/static/css/source/common/elements/dropdown.scss b/platypush/backend/http/static/css/source/common/elements/dropdown.scss
index e09836bb..8301598c 100644
--- a/platypush/backend/http/static/css/source/common/elements/dropdown.scss
+++ b/platypush/backend/http/static/css/source/common/elements/dropdown.scss
@@ -11,6 +11,12 @@
.item {
margin: 0 !important;
padding: 1rem;
+ cursor: pointer;
+
+ &.disabled {
+ color: $dropdown-disabled-color;
+ cursor: initial;
+ }
.icon {
margin: 0 .75rem;
diff --git a/platypush/backend/http/static/css/source/common/vars.scss b/platypush/backend/http/static/css/source/common/vars.scss
index ae0c0c90..31e91752 100644
--- a/platypush/backend/http/static/css/source/common/vars.scss
+++ b/platypush/backend/http/static/css/source/common/vars.scss
@@ -96,6 +96,7 @@ $header-bottom: $default-bottom;
//// Dropdown element
$dropdown-bg: rgba(241,243,242,0.9) !default;
+$dropdown-disabled-color: #999 !default;
$dropdown-shadow: 1px 1px 1px #bbb !default;
//// Modal element
diff --git a/platypush/backend/http/static/css/source/webpanel/plugins/media/devices.scss b/platypush/backend/http/static/css/source/webpanel/plugins/media/devices.scss
index 186c7a83..97ed4c25 100644
--- a/platypush/backend/http/static/css/source/webpanel/plugins/media/devices.scss
+++ b/platypush/backend/http/static/css/source/webpanel/plugins/media/devices.scss
@@ -20,13 +20,18 @@
.item {
display: flex;
align-items: center;
- cursor: pointer;
.text {
text-align: left;
margin-left: 2rem;
}
+ &:first-child {
+ border-bottom: $default-border-3;
+ color: $devices-dropdown-refresh-fg;
+ font-size: .8em;
+ }
+
&:hover {
background: $hover-bg
}
diff --git a/platypush/backend/http/static/css/source/webpanel/plugins/media/index.scss b/platypush/backend/http/static/css/source/webpanel/plugins/media/index.scss
index fb81dc59..a6338a44 100644
--- a/platypush/backend/http/static/css/source/webpanel/plugins/media/index.scss
+++ b/platypush/backend/http/static/css/source/webpanel/plugins/media/index.scss
@@ -20,8 +20,7 @@
.item {
display: flex;
- align-item: center;
- cursor: pointer;
+ align-items: center;
.text {
margin-left: 1rem;
diff --git a/platypush/backend/http/static/css/source/webpanel/plugins/media/vars.scss b/platypush/backend/http/static/css/source/webpanel/plugins/media/vars.scss
index 32d02725..8f169581 100644
--- a/platypush/backend/http/static/css/source/webpanel/plugins/media/vars.scss
+++ b/platypush/backend/http/static/css/source/webpanel/plugins/media/vars.scss
@@ -10,4 +10,5 @@ $control-time-color: #666;
$empty-results-color: #506050;
$devices-dropdown-z-index: 2;
+$devices-dropdown-refresh-fg: #666;
diff --git a/platypush/backend/http/static/js/elements/dropdown.js b/platypush/backend/http/static/js/elements/dropdown.js
index abf2eb90..dbba7a5b 100644
--- a/platypush/backend/http/static/js/elements/dropdown.js
+++ b/platypush/backend/http/static/js/elements/dropdown.js
@@ -18,7 +18,7 @@ Vue.component('dropdown', {
methods: {
clicked: function(item) {
- if (item.click) {
+ if (item.click && !item.disabled) {
item.click();
}
@@ -35,7 +35,6 @@ var clickHndl = function(event) {
}
var element = event.target;
-
while (element) {
if (element == openedDropdown) {
return;
diff --git a/platypush/backend/http/static/js/plugins/media/devices.js b/platypush/backend/http/static/js/plugins/media/devices.js
index 52afa5d2..ee17a580 100644
--- a/platypush/backend/http/static/js/plugins/media/devices.js
+++ b/platypush/backend/http/static/js/plugins/media/devices.js
@@ -1,3 +1,6 @@
+// Will be filled by dynamically loading device scripts
+var mediaPlayers = {};
+
Vue.component('media-devices', {
template: '#tmpl-media-devices',
props: {
@@ -9,12 +12,19 @@ Vue.component('media-devices', {
return {
showDevicesMenu: false,
selectedDevice: {},
+ loading: false,
+ devices: [],
};
},
computed: {
- dropdownItems: function() {
- var items = [
+ staticItems: function() {
+ return [
+ {
+ text: 'Refresh',
+ type: 'refresh',
+ icon: 'sync-alt',
+ },
{
name: this.playerPlugin,
text: this.playerPlugin,
@@ -28,16 +38,42 @@ Vue.component('media-devices', {
icon: 'laptop',
},
];
+ },
+
+ dropdownItems: function() {
+ const items = this.staticItems.concat(
+ this.devices.map(dev => {
+ return {
+ name: dev.name,
+ text: dev.name,
+ type: dev.__type__,
+ icon: dev.icon,
+ iconClass: dev.iconClass,
+ device: dev,
+ };
+ })
+ );
const self = this;
+
const onClick = (item) => {
return () => {
+ if (self.loading) {
+ return;
+ }
+
self.selectDevice(item);
};
};
for (var i=0; i < items.length; i++) {
- items[i].click = onClick(items[i]);
+ if (items[i].type === 'refresh') {
+ items[i].click = this.refreshDevices;
+ } else {
+ items[i].click = onClick(items[i]);
+ }
+
+ items[i].disabled = this.loading;
}
return items;
@@ -45,6 +81,48 @@ Vue.component('media-devices', {
},
methods: {
+ refreshDevices: async function() {
+ if (this.loading) {
+ return;
+ }
+
+ this.loading = true;
+ var devices;
+
+ try {
+ const promises = Object.entries(mediaPlayers).map((p) => {
+ const player = p[0];
+ const handler = p[1];
+
+ return new Promise((resolve, reject) => {
+ handler.scan().then(devs => {
+ for (var i=0; i < devs.length; i++) {
+ devs[i].__type__ = player;
+
+ if (handler.icon) {
+ devs[i].icon = handler.icon instanceof Function ? handler.icon(devs[i]) : handler.icon;
+ } else if (handler.iconClass) {
+ devs[i].iconClass = handler.iconClass instanceof Function ? handler.iconClass(devs[i]) : handler.iconClass;
+ }
+ }
+
+ resolve(devs);
+ });
+ });
+ });
+
+ this.devices = (await Promise.all(promises)).reduce((list, devs) => {
+ for (const d of devs) {
+ list.push(d);
+ }
+
+ return list;
+ }, []);
+ } finally {
+ this.loading = false;
+ }
+ },
+
selectDevice: function(device) {
this.selectedDevice = device;
this.bus.$emit('selected-device', device);
@@ -57,6 +135,7 @@ Vue.component('media-devices', {
created: function() {
this.selectDevice(this.dropdownItems.filter(_ => _.type === 'local')[0]);
+ this.refreshDevices();
},
});
diff --git a/platypush/backend/http/static/js/plugins/media/players/chromecast.js b/platypush/backend/http/static/js/plugins/media/players/chromecast.js
new file mode 100644
index 00000000..ef5fad33
--- /dev/null
+++ b/platypush/backend/http/static/js/plugins/media/players/chromecast.js
@@ -0,0 +1,23 @@
+mediaPlayers.chromecast = {
+ iconClass: function(item) {
+ if (item.type === 'audio') {
+ return 'fa fa-volume-up';
+ } else {
+ return 'fab fa-chromecast';
+ }
+ },
+
+ scan: async function() {
+ return await request('media.chromecast.get_chromecasts');
+ },
+
+ status: function(device) {
+ },
+
+ play: function(item) {
+ },
+
+ stop: function() {
+ },
+};
+
diff --git a/platypush/backend/http/templates/elements/dropdown.html b/platypush/backend/http/templates/elements/dropdown.html
index 34a33399..0b22fd5b 100644
--- a/platypush/backend/http/templates/elements/dropdown.html
+++ b/platypush/backend/http/templates/elements/dropdown.html
@@ -1,8 +1,9 @@
+{% for script in utils.search_directory(static_folder + '/js/plugins/media/players', 'js', recursive=True) %}
+
+{% endfor %}
+