mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 17:26:42 +00:00
Add media player card
This commit is contained in:
parent
ac311416a9
commit
a127c74a53
@ -20,7 +20,7 @@
|
|||||||
"author": "Paulus Schoutsen <Paulus@PaulusSchoutsen.nl> (http://paulusschoutsen.nl)",
|
"author": "Paulus Schoutsen <Paulus@PaulusSchoutsen.nl> (http://paulusschoutsen.nl)",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"home-assistant-js": "git+https://github.com/balloob/home-assistant-js.git#ea9bf003e0a668842f5306628ea88a9d0c1eeb50",
|
"home-assistant-js": "git+https://github.com/balloob/home-assistant-js.git#7dc486d2195435eca2c0e194c1f6ca7ee3163138",
|
||||||
"lodash": "^4.8.2",
|
"lodash": "^4.8.2",
|
||||||
"moment": "^2.12.0"
|
"moment": "^2.12.0"
|
||||||
},
|
},
|
||||||
|
@ -3,3 +3,4 @@
|
|||||||
<link rel='import' href='./ha-camera-card.html'>
|
<link rel='import' href='./ha-camera-card.html'>
|
||||||
<link rel='import' href='./ha-entities-card.html'>
|
<link rel='import' href='./ha-entities-card.html'>
|
||||||
<link rel='import' href='./ha-introduction-card.html'>
|
<link rel='import' href='./ha-introduction-card.html'>
|
||||||
|
<link rel='import' href='./ha-media_player-card.html'>
|
||||||
|
@ -5,6 +5,7 @@ import dynamicContentUpdater from '../util/dynamic-content-updater';
|
|||||||
require('./ha-camera-card');
|
require('./ha-camera-card');
|
||||||
require('./ha-entities-card');
|
require('./ha-entities-card');
|
||||||
require('./ha-introduction-card');
|
require('./ha-introduction-card');
|
||||||
|
require('./ha-media_player-card');
|
||||||
|
|
||||||
export default new Polymer({
|
export default new Polymer({
|
||||||
is: 'ha-card-chooser',
|
is: 'ha-card-chooser',
|
||||||
|
139
src/cards/ha-media_player-card.html
Normal file
139
src/cards/ha-media_player-card.html
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
<link rel='import' href='../../bower_components/polymer/polymer.html'>
|
||||||
|
<link rel="import" href="../../bower_components/paper-material/paper-material.html">
|
||||||
|
<link rel='import' href='../../bower_components/paper-icon-button/paper-icon-button.html'>
|
||||||
|
|
||||||
|
<dom-module id='ha-media_player-card'>
|
||||||
|
<style include="paper-material iron-flex iron-flex-alignment iron-positioning">
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
font-size: 0px;
|
||||||
|
border-radius: 2px;
|
||||||
|
|
||||||
|
transition: height .5s;
|
||||||
|
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center center;
|
||||||
|
background-color: var(--paper-grey-500);
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.options {
|
||||||
|
float: right;
|
||||||
|
margin-right: -8px;
|
||||||
|
margin-top: -8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.caption {
|
||||||
|
@apply(--paper-font-caption);
|
||||||
|
border-bottom-left-radius: 2px;
|
||||||
|
border-bottom-right-radius: 2px;
|
||||||
|
|
||||||
|
background: linear-gradient(to bottom,
|
||||||
|
rgba(0,0,0,0.5) 0%,
|
||||||
|
rgba(0,0,0,0) 100%);
|
||||||
|
|
||||||
|
padding: 8px;
|
||||||
|
|
||||||
|
text-transform: capitalize;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.caption .title {
|
||||||
|
@apply(--paper-font-common-nowrap);
|
||||||
|
font-size: 1.2em;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls-container {
|
||||||
|
position: absolute;
|
||||||
|
left: 8px;
|
||||||
|
right: 8px;
|
||||||
|
top: 91px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
@apply(--paper-font-body1);
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background-color: white;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
color: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[invisible] {
|
||||||
|
visibility: hidden !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<template>
|
||||||
|
<img src='[[stateObj.attributes.entity_picture]]' hidden
|
||||||
|
on-load='imageLoadSuccess' on-error='imageLoadFail'>
|
||||||
|
|
||||||
|
<div class='caption'>
|
||||||
|
<div class='options'>
|
||||||
|
<paper-icon-button
|
||||||
|
class='power-on'
|
||||||
|
icon='mdi:power'
|
||||||
|
on-tap='handlePowerOn'
|
||||||
|
hidden$='[[computeHidePowerOnButton(playerObj)]]'
|
||||||
|
></paper-icon-button>
|
||||||
|
<paper-icon-button
|
||||||
|
icon='mdi:open-in-app'
|
||||||
|
on-tap='handleOpenMoreInfo'
|
||||||
|
></paper-icon-button>
|
||||||
|
</div>
|
||||||
|
<div class='title'>[[playerObj.primaryText]]</div>
|
||||||
|
[[playerObj.secondaryText]]<br />
|
||||||
|
@[[stateObj.entityDisplay]]
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='controls-container'>
|
||||||
|
<paper-material elevation="1">
|
||||||
|
<div class='controls layout horizontal justified'>
|
||||||
|
<paper-icon-button
|
||||||
|
icon='[[computeVolumeMuteIcon(playerObj)]]'
|
||||||
|
on-tap='handleVolumeMute'
|
||||||
|
invisible$='[[!playerObj.supportsVolumeMute]]'
|
||||||
|
class='self-center'
|
||||||
|
></paper-icon-button>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<paper-icon-button
|
||||||
|
icon='mdi:skip-previous'
|
||||||
|
invisible$='[[!playerObj.supportsPreviousTrack]]'
|
||||||
|
on-tap='handlePrevious'
|
||||||
|
></paper-icon-button>
|
||||||
|
<paper-icon-button
|
||||||
|
class='primary'
|
||||||
|
icon='[[computePlaybackControlIcon(playerObj)]]'
|
||||||
|
on-tap='handlePlaybackControl'
|
||||||
|
></paper-icon-button>
|
||||||
|
<paper-icon-button
|
||||||
|
icon='mdi:skip-next'
|
||||||
|
invisible$='[[!playerObj.supportsNextTrack]]'
|
||||||
|
on-tap='handleNext'
|
||||||
|
></paper-icon-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<paper-icon-button
|
||||||
|
icon='mdi:power'
|
||||||
|
on-tap='handlePowerOff'
|
||||||
|
invisible$='[[!playerObj.supportsTurnOff]]'
|
||||||
|
class='self-center'
|
||||||
|
></paper-icon-button>
|
||||||
|
</div>
|
||||||
|
</paper-material>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</dom-module>
|
114
src/cards/ha-media_player-card.js
Normal file
114
src/cards/ha-media_player-card.js
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
import Polymer from '../polymer';
|
||||||
|
import hass from '../util/home-assistant-js-instance';
|
||||||
|
|
||||||
|
const { moreInfoActions } = hass;
|
||||||
|
|
||||||
|
export default new Polymer({
|
||||||
|
is: 'ha-media_player-card',
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
stateObj: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
|
||||||
|
playerObj: {
|
||||||
|
type: Object,
|
||||||
|
computed: 'computePlayerObj(stateObj)',
|
||||||
|
observer: 'playerObjChanged',
|
||||||
|
},
|
||||||
|
|
||||||
|
imageLoaded: {
|
||||||
|
type: Boolean,
|
||||||
|
value: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
playbackControlIcon: {
|
||||||
|
type: String,
|
||||||
|
computed: 'computePlaybackControlIcon(playerObj)',
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The z-depth of the card, from 0-5.
|
||||||
|
*/
|
||||||
|
elevation: {
|
||||||
|
type: Number,
|
||||||
|
value: 1,
|
||||||
|
reflectToAttribute: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
playerObjChanged(playerObj) {
|
||||||
|
this.style.height = this.computeShowControls(playerObj) ? '175px' : '78px';
|
||||||
|
this.style.backgroundImage = playerObj.stateObj.attributes.entity_picture ?
|
||||||
|
`url(${playerObj.stateObj.attributes.entity_picture})` : '';
|
||||||
|
},
|
||||||
|
|
||||||
|
imageLoadSuccess() {
|
||||||
|
this.imageLoaded = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
imageLoadFail() {
|
||||||
|
this.imageLoaded = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
computeHidePowerOnButton(playerObj) {
|
||||||
|
return !playerObj.isOff || !playerObj.supportsTurnOn;
|
||||||
|
},
|
||||||
|
|
||||||
|
computePlayerObj(stateObj) {
|
||||||
|
return stateObj.domainModel(hass);
|
||||||
|
},
|
||||||
|
|
||||||
|
computePlaybackControlIcon(playerObj) {
|
||||||
|
if (playerObj.isPlaying) {
|
||||||
|
return playerObj.supportsPause ? 'mdi:pause' : 'mdi:stop';
|
||||||
|
} else if (playerObj.isPaused) {
|
||||||
|
return 'mdi:play';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
|
||||||
|
computeShowControls(playerObj) {
|
||||||
|
return !playerObj.isOff;
|
||||||
|
},
|
||||||
|
|
||||||
|
computeVolumeMuteIcon(playerObj) {
|
||||||
|
return playerObj.isMuted ? 'mdi:volume-high' : 'mdi:volume-off';
|
||||||
|
},
|
||||||
|
|
||||||
|
handleNext(ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.playerObj.nextTrack();
|
||||||
|
},
|
||||||
|
|
||||||
|
handleOpenMoreInfo(ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.async(() => moreInfoActions.selectEntity(this.stateObj.entityId), 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
handlePlaybackControl(ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.playerObj.mediaPlayPause();
|
||||||
|
},
|
||||||
|
|
||||||
|
handlePrevious(ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.playerObj.previousTrack();
|
||||||
|
},
|
||||||
|
|
||||||
|
handlePowerOff(ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.playerObj.turnOff();
|
||||||
|
},
|
||||||
|
|
||||||
|
handlePowerOn(ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.playerObj.turnOn();
|
||||||
|
},
|
||||||
|
|
||||||
|
handleVolumeMute(ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.playerObj.volumeMute(!this.playerObj.isMuted);
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
@ -7,7 +7,7 @@ require('../cards/ha-card-chooser');
|
|||||||
|
|
||||||
const { util } = hass;
|
const { util } = hass;
|
||||||
|
|
||||||
const DOMAINS_WITH_CARD = ['camera'];
|
const DOMAINS_WITH_CARD = ['camera', 'media_player'];
|
||||||
|
|
||||||
const PRIORITY = {
|
const PRIORITY = {
|
||||||
configurator: -20,
|
configurator: -20,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user