Prefix media-player-model and use it for more-info (#1088)

* prefix media player model with hass-
use model for more-info-mplayer

* missed a binding
This commit is contained in:
NovapaX 2018-04-15 00:04:44 +02:00 committed by Paulus Schoutsen
parent a512d9e910
commit 027165c8ac
3 changed files with 95 additions and 197 deletions

View File

@ -6,7 +6,7 @@
<link rel='import' href='../../bower_components/paper-icon-button/paper-icon-button.html'> <link rel='import' href='../../bower_components/paper-icon-button/paper-icon-button.html'>
<link rel='import' href='../../bower_components/paper-progress/paper-progress.html'> <link rel='import' href='../../bower_components/paper-progress/paper-progress.html'>
<link rel='import' href='../util/media-player-model.html'> <link rel='import' href='../util/hass-media-player-model.html'>
<link rel='import' href='../util/hass-mixins.html'> <link rel='import' href='../util/hass-mixins.html'>
<dom-module id='ha-media_player-card'> <dom-module id='ha-media_player-card'>
@ -309,7 +309,7 @@ class HaMediaPlayerCard extends
} }
computePlayerObj(hass, stateObj) { computePlayerObj(hass, stateObj) {
return new window.MediaPlayerEntity(hass, stateObj); return new window.HassMediaPlayerEntity(hass, stateObj);
} }
computePrimaryText(localize, playerObj) { computePrimaryText(localize, playerObj) {

View File

@ -11,6 +11,7 @@
<link rel='import' href='../../../../bower_components/paper-item/paper-item.html'> <link rel='import' href='../../../../bower_components/paper-item/paper-item.html'>
<link rel='import' href='../../../../src/util/hass-mixins.html'> <link rel='import' href='../../../../src/util/hass-mixins.html'>
<link rel='import' href='../../../../src/util/hass-media-player-model.html'>
<dom-module id='more-info-media_player'> <dom-module id='more-info-media_player'>
<template> <template>
@ -57,58 +58,59 @@
<div class$='[[computeClassNames(stateObj)]]'> <div class$='[[computeClassNames(stateObj)]]'>
<div class='layout horizontal'> <div class='layout horizontal'>
<div class='flex'> <div class='flex'>
<paper-icon-button icon='mdi:power' highlight$='[[isOff]]' <paper-icon-button icon='mdi:power' highlight$='[[playerObj.isOff]]'
on-click='handleTogglePower' on-click='handleTogglePower'
hidden$='[[computeHidePowerButton(isOff, supportsTurnOn, supportsTurnOff)]]'></paper-icon-button> hidden$='[[computeHidePowerButton(playerObj)]]'
></paper-icon-button>
</div> </div>
<div> <div>
<template is='dom-if' if='[[computeShowPlaybackControls(isOff, hasMediaControl)]]'> <template is='dom-if' if='[[computeShowPlaybackControls(playerObj)]]'>
<paper-icon-button icon='mdi:skip-previous' on-click='handlePrevious' <paper-icon-button icon='mdi:skip-previous' on-click='handlePrevious'
hidden$='[[!supportsPreviousTrack]]'></paper-icon-button> hidden$='[[!playerObj.supportsPreviousTrack]]'></paper-icon-button>
<paper-icon-button icon='[[computePlaybackControlIcon(isPlaying)]]' <paper-icon-button icon='[[computePlaybackControlIcon(playerObj)]]'
on-click='handlePlaybackControl' on-click='handlePlaybackControl'
hidden$='[[!computePlaybackControlIcon(isPlaying)]]' highlight></paper-icon-button> hidden$='[[!computePlaybackControlIcon(playerObj)]]' highlight></paper-icon-button>
<paper-icon-button icon='mdi:skip-next' on-click='handleNext' <paper-icon-button icon='mdi:skip-next' on-click='handleNext'
hidden$='[[!supportsNextTrack]]'></paper-icon-button> hidden$='[[!playerObj.supportsNextTrack]]'></paper-icon-button>
</template> </template>
</div> </div>
</div> </div>
<!-- VOLUME --> <!-- VOLUME -->
<div class='volume_buttons center horizontal layout' <div class='volume_buttons center horizontal layout'
hidden$='[[computeHideVolumeButtons(isOff, supportsVolumeButtons)]]'> hidden$='[[computeHideVolumeButtons(playerObj)]]'>
<paper-icon-button on-click="handleVolumeTap" <paper-icon-button on-click="handleVolumeTap"
icon="mdi:volume-off"></paper-icon-button> icon="mdi:volume-off"></paper-icon-button>
<paper-icon-button id="volumeDown" disabled$='[[isMuted]]' <paper-icon-button id="volumeDown" disabled$='[[playerObj.isMuted]]'
on-mousedown="handleVolumeDown" on-touchstart="handleVolumeDown" on-mousedown="handleVolumeDown" on-touchstart="handleVolumeDown"
icon="mdi:volume-medium"></paper-icon-button> icon="mdi:volume-medium"></paper-icon-button>
<paper-icon-button id="volumeUp" disabled$='[[isMuted]]' <paper-icon-button id="volumeUp" disabled$='[[playerObj.isMuted]]'
on-mousedown="handleVolumeUp" on-touchstart="handleVolumeUp" on-mousedown="handleVolumeUp" on-touchstart="handleVolumeUp"
icon="mdi:volume-high"></paper-icon-button> icon="mdi:volume-high"></paper-icon-button>
</div> </div>
<div class='volume center horizontal layout' hidden$='[[!supportsVolumeSet]]'> <div class='volume center horizontal layout' hidden$='[[!playerObj.supportsVolumeSet]]'>
<paper-icon-button on-click="handleVolumeTap" <paper-icon-button on-click="handleVolumeTap"
hidden$="[[supportsVolumeButtons]]" hidden$="[[playerObj.supportsVolumeButtons]]"
icon="[[computeMuteVolumeIcon(isMuted)]]"></paper-icon-button> icon="[[computeMuteVolumeIcon(playerObj)]]"></paper-icon-button>
<paper-slider disabled$='[[isMuted]]' <paper-slider disabled$='[[playerObj.isMuted]]'
min='0' max='100' value='[[volumeSliderValue]]' min='0' max='100' value='[[playerObj.volumeSliderValue]]'
on-change='volumeSliderChanged' class='flex' on-change='volumeSliderChanged' class='flex'
ignore-bar-touch> ignore-bar-touch>
</paper-slider> </paper-slider>
</div> </div>
<!-- SOURCE PICKER --> <!-- SOURCE PICKER -->
<div class='controls layout horizontal justified' <div class='controls layout horizontal justified'
hidden$='[[computeHideSelectSource(isOff, supportsSelectSource)]]'> hidden$='[[computeHideSelectSource(playerObj)]]'>
<iron-icon class="source-input" icon="mdi:login-variant"></iron-icon> <iron-icon class="source-input" icon="mdi:login-variant"></iron-icon>
<paper-dropdown-menu class="flex source-input" dynamic-align label-float label='Source'> <paper-dropdown-menu class="flex source-input" dynamic-align label-float label='Source'>
<paper-listbox slot="dropdown-content" selected="{{sourceIndex}}"> <paper-listbox slot="dropdown-content" selected="{{sourceIndex}}">
<template is='dom-repeat' items='[[stateObj.attributes.source_list]]'> <template is='dom-repeat' items='[[playerObj.sourceList]]'>
<paper-item>[[item]]</paper-item> <paper-item>[[item]]</paper-item>
</template> </template>
</paper-listbox> </paper-listbox>
</paper-dropdown-menu> </paper-dropdown-menu>
</div> </div>
<!-- TTS --> <!-- TTS -->
<div hidden$='[[computeHideTTS(ttsLoaded, supportsPlayMedia)]]' class='layout horizontal end'> <div hidden$='[[computeHideTTS(ttsLoaded, playerObj)]]' class='layout horizontal end'>
<paper-input <paper-input
id='ttsInput' id='ttsInput'
label='Text to speak' label='Text to speak'
@ -124,45 +126,17 @@
<script> <script>
{ {
const HAS_MEDIA_STATES = ['playing', 'paused', 'unknown'];
class MoreInfoMediaPlayer extends window.hassMixins.EventsMixin(Polymer.Element) { class MoreInfoMediaPlayer extends window.hassMixins.EventsMixin(Polymer.Element) {
static get is() { return 'more-info-media_player'; } static get is() { return 'more-info-media_player'; }
static get properties() { static get properties() {
return { return {
ttsLoaded: { hass: Object,
type: Boolean, stateObj: Object,
computed: 'computeTTSLoaded(hass)', playerObj: {
},
hass: {
type: Object, type: Object,
}, computed: 'computePlayerObj(hass, stateObj)',
observer: 'playerObjChanged',
stateObj: {
type: Object,
observer: 'stateObjChanged',
},
isOff: {
type: Boolean,
value: false,
},
isPlaying: {
type: Boolean,
value: false,
},
isMuted: {
type: Boolean,
value: false,
},
source: {
type: String,
value: '',
}, },
sourceIndex: { sourceIndex: {
@ -171,9 +145,9 @@
observer: 'handleSourceChanged', observer: 'handleSourceChanged',
}, },
volumeSliderValue: { ttsLoaded: {
type: Number, type: Boolean,
value: 0, computed: 'computeTTSLoaded(hass)',
}, },
ttsMessage: { ttsMessage: {
@ -181,94 +155,16 @@
value: '', value: '',
}, },
supportsPause: {
type: Boolean,
value: false,
},
supportsVolumeSet: {
type: Boolean,
value: false,
},
supportsVolumeMute: {
type: Boolean,
value: false,
},
supportsPreviousTrack: {
type: Boolean,
value: false,
},
supportsNextTrack: {
type: Boolean,
value: false,
},
supportsTurnOn: {
type: Boolean,
value: false,
},
supportsTurnOff: {
type: Boolean,
value: false,
},
supportsPlayMedia: {
type: Boolean,
value: false,
},
supportsVolumeButtons: {
type: Boolean,
value: false,
},
supportsSelectSource: {
type: Boolean,
value: false,
},
supportsPlay: {
type: Boolean,
value: false,
},
hasMediaControl: {
type: Boolean,
value: false,
},
}; };
} }
stateObjChanged(newVal, oldVal) { computePlayerObj(hass, stateObj) {
if (newVal) { return new window.HassMediaPlayerEntity(hass, stateObj);
const props = {
isOff: newVal.state === 'off',
isPlaying: newVal.state === 'playing',
hasMediaControl: HAS_MEDIA_STATES.indexOf(newVal.state) !== -1,
volumeSliderValue: newVal.attributes.volume_level * 100,
isMuted: newVal.attributes.is_volume_muted,
source: newVal.attributes.source,
supportsPause: (newVal.attributes.supported_features & 1) !== 0,
supportsVolumeSet: (newVal.attributes.supported_features & 4) !== 0,
supportsVolumeMute: (newVal.attributes.supported_features & 8) !== 0,
supportsPreviousTrack: (newVal.attributes.supported_features & 16) !== 0,
supportsNextTrack: (newVal.attributes.supported_features & 32) !== 0,
supportsTurnOn: (newVal.attributes.supported_features & 128) !== 0,
supportsTurnOff: (newVal.attributes.supported_features & 256) !== 0,
supportsPlayMedia: (newVal.attributes.supported_features & 512) !== 0,
supportsVolumeButtons: (newVal.attributes.supported_features & 1024) !== 0,
supportsSelectSource: (newVal.attributes.supported_features & 2048) !== 0,
supportsPlay: (newVal.attributes.supported_features & 16384) !== 0,
};
if (newVal.attributes.source_list !== undefined) {
props.sourceIndex = newVal.attributes.source_list.indexOf(props.source);
} }
this.setProperties(props);
playerObjChanged(newVal, oldVal) {
if (newVal && newVal.sourceList !== undefined) {
this.sourceIndex = newVal.sourceList.indexOf(newVal.source);
} }
if (oldVal) { if (oldVal) {
@ -282,43 +178,35 @@
return window.hassUtil.attributeClassNames(stateObj, ['volume_level']); return window.hassUtil.attributeClassNames(stateObj, ['volume_level']);
} }
computeIsOff(stateObj) { computeMuteVolumeIcon(playerObj) {
return stateObj.state === 'off'; return playerObj.isMuted ? 'mdi:volume-off' : 'mdi:volume-high';
} }
computeMuteVolumeIcon(isMuted) { computeHideVolumeButtons(playerObj) {
return isMuted ? 'mdi:volume-off' : 'mdi:volume-high'; return !playerObj.supportsVolumeButtons || playerObj.isOff;
} }
computeHideVolumeButtons(isOff, supportsVolumeButtons) { computeShowPlaybackControls(playerObj) {
return !supportsVolumeButtons || isOff; return !playerObj.isOff && playerObj.hasMediaControl;
} }
computeShowPlaybackControls(isOff, hasMedia) { computePlaybackControlIcon(playerObj) {
return !isOff && hasMedia; if (playerObj.isPlaying) {
return playerObj.supportsPause ? 'mdi:pause' : 'mdi:stop';
}
return playerObj.supportsPlay ? 'mdi:play' : null;
} }
computePlaybackControlIcon(isPlaying) { computeHidePowerButton(playerObj) {
if (isPlaying) { return playerObj.isOff ? !playerObj.supportsTurnOn : !playerObj.supportsTurnOff;
return this.supportsPause ? 'mdi:pause' : 'mdi:stop';
}
return this.supportsPlay ? 'mdi:play' : null;
} }
computeHidePowerButton(isOff, supportsTurnOn, supportsTurnOff) { computeHideSelectSource(playerObj) {
return isOff ? !supportsTurnOn : !supportsTurnOff; return playerObj.isOff || !playerObj.supportsSelectSource || !playerObj.soureList;
} }
computeHideSelectSource(isOff, supportsSelectSource) { computeHideTTS(ttsLoaded, playerObj) {
return isOff || !supportsSelectSource; return !ttsLoaded || !playerObj.supportsPlayMedia;
}
computeSelectedSource(stateObj) {
return stateObj.attributes.source_list.indexOf(stateObj.attributes.source);
}
computeHideTTS(ttsLoaded, supportsPlayMedia) {
return !ttsLoaded || !supportsPlayMedia;
} }
computeTTSLoaded(hass) { computeTTSLoaded(hass) {
@ -326,70 +214,70 @@
} }
handleTogglePower() { handleTogglePower() {
this.callService(this.isOff ? 'turn_on' : 'turn_off'); this.playerObj.togglePower();
} }
handlePrevious() { handlePrevious() {
this.callService('media_previous_track'); this.playerObj.previousTrack();
} }
handlePlaybackControl() { handlePlaybackControl() {
this.callService('media_play_pause'); this.playerObj.mediaPlayPause();
} }
handleNext() { handleNext() {
this.callService('media_next_track'); this.playerObj.nextTrack();
} }
handleSourceChanged(sourceIndex, sourceIndexOld) { handleSourceChanged(sourceIndex, sourceIndexOld) {
var sourceInput;
// Selected Option will transition to '' before transitioning to new value // Selected Option will transition to '' before transitioning to new value
if (!this.stateObj if (!this.playerObj
|| this.stateObj.attributes.source_list === undefined || !this.playerObj.supportsSelectSource
|| this.playerObj.sourceList === undefined
|| sourceIndex < 0 || sourceIndex < 0
|| sourceIndex >= this.stateObj.attributes.source_list.length || sourceIndex >= this.playerObj.sourceList
|| sourceIndexOld === undefined || sourceIndexOld === undefined
) { ) {
return; return;
} }
sourceInput = this.stateObj.attributes.source_list[sourceIndex]; const sourceInput = this.playerObj.sourceList[sourceIndex];
if (sourceInput === this.stateObj.attributes.source) { if (sourceInput === this.playerObj.source) {
return; return;
} }
this.callService('select_source', { source: sourceInput }); this.playerObj.selectSource(sourceInput);
} }
handleVolumeTap() { handleVolumeTap() {
if (!this.supportsVolumeMute) { if (!this.playerObj.supportsVolumeMute) {
return; return;
} }
this.callService('volume_mute', { is_volume_muted: !this.isMuted }); this.playerObj.volumeMute(!this.playerObj.isMuted);
} }
handleVolumeUp() { handleVolumeUp() {
var obj = this.$.volumeUp; const obj = this.$.volumeUp;
this.handleVolumeWorker('volume_up', obj, true); this.handleVolumeWorker('volume_up', obj, true);
} }
handleVolumeDown() { handleVolumeDown() {
var obj = this.$.volumeDown; const obj = this.$.volumeDown;
this.handleVolumeWorker('volume_down', obj, true); this.handleVolumeWorker('volume_down', obj, true);
} }
handleVolumeWorker(service, obj, force) { handleVolumeWorker(service, obj, force) {
if (force || (obj !== undefined && obj.pointerDown)) { if (force || (obj !== undefined && obj.pointerDown)) {
this.callService(service); this.playerObj.callService(service);
setTimeout(() => this.handleVolumeWorker(service, obj, false), 500); setTimeout(() => this.handleVolumeWorker(service, obj, false), 500);
} }
} }
volumeSliderChanged(ev) { volumeSliderChanged(ev) {
var volPercentage = parseFloat(ev.target.value); const volPercentage = parseFloat(ev.target.value);
var vol = volPercentage > 0 ? volPercentage / 100 : 0; const volume = volPercentage > 0 ? volPercentage / 100 : 0;
this.callService('volume_set', { volume_level: vol }); this.playerObj.setVolume(volume);
} }
ttsCheckForEnter(ev) { ttsCheckForEnter(ev) {
@ -397,10 +285,10 @@
} }
sendTTS() { sendTTS() {
var services = this.hass.config.services.tts; const services = this.hass.config.services.tts;
var serviceKeys = Object.keys(services).sort(); const serviceKeys = Object.keys(services).sort();
var service; let service;
var i; let i;
for (i = 0; i < serviceKeys.length; i++) { for (i = 0; i < serviceKeys.length; i++) {
if (serviceKeys[i].indexOf('_say') !== -1) { if (serviceKeys[i].indexOf('_say') !== -1) {
@ -420,12 +308,6 @@
this.ttsMessage = ''; this.ttsMessage = '';
this.$.ttsInput.focus(); this.$.ttsInput.focus();
} }
callService(service, data) {
var serviceData = data || {};
serviceData.entity_id = this.stateObj.entity_id;
this.hass.callService('media_player', service, serviceData);
}
} }
customElements.define(MoreInfoMediaPlayer.is, MoreInfoMediaPlayer); customElements.define(MoreInfoMediaPlayer.is, MoreInfoMediaPlayer);

View File

@ -1,13 +1,13 @@
<script> <script>
(function () { (function () {
window.MediaPlayerEntity = function (hass, stateObj) { window.HassMediaPlayerEntity = function (hass, stateObj) {
this.hass = hass; this.hass = hass;
this.stateObj = stateObj; this.stateObj = stateObj;
}; };
function addGetter(name, getter) { function addGetter(name, getter) {
Object.defineProperty( Object.defineProperty(
window.MediaPlayerEntity.prototype, name, window.HassMediaPlayerEntity.prototype, name,
{ get: getter } { get: getter }
); );
} }
@ -103,6 +103,10 @@
return (this.stateObj.attributes.supported_features & 1024) !== 0; return (this.stateObj.attributes.supported_features & 1024) !== 0;
}); });
addGetter('supportsSelectSource', function () {
return (this.stateObj.attributes.supported_features & 2048) !== 0;
});
addGetter('supportsPlay', function () { addGetter('supportsPlay', function () {
return (this.stateObj.attributes.supported_features & 16384) !== 0; return (this.stateObj.attributes.supported_features & 16384) !== 0;
}); });
@ -134,7 +138,15 @@
return ''; return '';
}); });
Object.assign(window.MediaPlayerEntity.prototype, { addGetter('source', function () {
return this.stateObj.attributes.source;
});
addGetter('sourceList', function () {
return this.stateObj.attributes.source_list;
});
Object.assign(window.HassMediaPlayerEntity.prototype, {
mediaPlayPause: function () { mediaPlayPause: function () {
this.callService('media_play_pause'); this.callService('media_play_pause');
}, },
@ -186,6 +198,10 @@
this.callService('volume_up'); this.callService('volume_up');
}, },
selectSource: function (sourceInput) {
this.callService('select_source', { source: sourceInput });
},
// helper method // helper method
callService: function (service, data) { callService: function (service, data) {