Redesign media player card (thanks @DesignFirst)

This commit is contained in:
Paulus Schoutsen 2016-04-12 00:22:18 -07:00
parent ed6d3cfa1d
commit 4ab308a9d2
3 changed files with 116 additions and 111 deletions

View File

@ -29,6 +29,7 @@
"babel-loader": "^6.2",
"babel-preset-es2015": "^6.6.0",
"bower": "^1.7.9",
"classnames": "^2.2.3",
"eslint": "^2.7.0",
"eslint-config-airbnb": "^6.2.0",
"html-minifier": "^1.4.0",

View File

@ -10,57 +10,83 @@
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;
.banner {
position: relative;
background-position: center center;
background-image: url(/static/images/card_media_player_bg.png);
background-repeat: no-repeat;
background-color: var(--primary-color);
}
.caption {
.banner:before {
display: block;
content: "";
width: 100%;
/* removed .25% from 16:9 ratio to fix YT black bars */
padding-top: 56%;
}
.banner > .cover {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
background-position: center center;
background-size: cover;
transition: opacity .8s;
opacity: 1;
}
.banner.is-off > .cover {
opacity: 0;
}
.banner > .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%);
position: absolute;
left: 0;
right: 0;
bottom: 0;
padding: 8px;
background-color: rgba(0, 0, 0, var(--dark-secondary-opacity));
padding: 16px;
text-transform: capitalize;
font-size: 14px;
font-weight: 500;
color: white;
transition: background-color .5s;
}
.caption .title {
.banner.is-off > .caption {
background-color: initial;
}
.banner > .caption .title {
@apply(--paper-font-common-nowrap);
font-size: 1.2em;
margin-bottom: 4px;
}
.controls-container {
position: absolute;
left: 8px;
right: 8px;
top: 91px;
margin: 8px 0 4px;
}
.controls {
@apply(--paper-font-body1);
padding: 8px;
border-radius: 2px;
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
background-color: white;
text-align: center;
}
.controls paper-icon-button {
@ -68,6 +94,10 @@
height: 44px;
}
paper-icon-button {
color: var(--primary-text-color);
}
paper-icon-button.primary {
width: 56px !important;
height: 56px !important;
@ -75,6 +105,11 @@
color: white;
border-radius: 50%;
padding: 8px;
transition: background-color .5s;
}
paper-icon-button.primary[disabled] {
background-color: rgba(0, 0, 0, var(--dark-disabled-opacity));
}
[invisible] {
@ -82,63 +117,50 @@
}
</style>
<template>
<img src='[[stateObj.attributes.entity_picture]]' hidden
on-load='imageLoadSuccess' on-error='imageLoadFail'>
<div class$='[[computeBannerClasses(playerObj)]]'>
<div class='cover' id='cover'></div>
<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 class='caption'>
[[stateObj.entityDisplay]]
<div class='title'>[[playerObj.primaryText]]</div>
[[playerObj.secondaryText]]<br />
</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 class='controls layout horizontal justified'>
<paper-icon-button
icon='mdi:power'
on-tap='handleTogglePower'
invisible$='[[!playerObj.supportsTurnOff]]'
class='self-center secondary'
></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>
<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)]]'
invisible='[[!computePlaybackControlIcon(playerObj)]]'
disabled='[[playerObj.isOff]]'
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:dots-vertical'
on-tap='handleOpenMoreInfo'
class='self-center secondary'
></paper-icon-button>
<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>

View File

@ -1,3 +1,5 @@
import classnames from 'classnames';
import Polymer from '../polymer';
import hass from '../util/home-assistant-js-instance';
@ -17,11 +19,6 @@ export default new Polymer({
observer: 'playerObjChanged',
},
imageLoaded: {
type: Boolean,
value: true,
},
playbackControlIcon: {
type: String,
computed: 'computePlaybackControlIcon(playerObj)',
@ -38,17 +35,17 @@ export default new Polymer({
},
playerObjChanged(playerObj) {
this.style.height = this.computeShowControls(playerObj) ? '175px' : '78px';
this.style.backgroundImage = playerObj.stateObj.attributes.entity_picture ?
`url(${playerObj.stateObj.attributes.entity_picture})` : '';
if (!playerObj.isOff && !playerObj.isIdle) {
this.$.cover.style.backgroundImage = playerObj.stateObj.attributes.entity_picture ?
`url(${playerObj.stateObj.attributes.entity_picture})` : '';
}
},
imageLoadSuccess() {
this.imageLoaded = true;
},
imageLoadFail() {
this.imageLoaded = false;
computeBannerClasses(playerObj) {
return classnames({
banner: true,
'is-off': playerObj.isOff || playerObj.isIdle,
});
},
computeHidePowerOnButton(playerObj) {
@ -62,7 +59,7 @@ export default new Polymer({
computePlaybackControlIcon(playerObj) {
if (playerObj.isPlaying) {
return playerObj.supportsPause ? 'mdi:pause' : 'mdi:stop';
} else if (playerObj.isPaused) {
} else if (playerObj.isPaused || playerObj.isOff) {
return 'mdi:play';
}
return '';
@ -72,10 +69,6 @@ export default new Polymer({
return !playerObj.isOff;
},
computeVolumeMuteIcon(playerObj) {
return playerObj.isMuted ? 'mdi:volume-off' : 'mdi:volume-high';
},
handleNext(ev) {
ev.stopPropagation();
this.playerObj.nextTrack();
@ -96,19 +89,8 @@ export default new Polymer({
this.playerObj.previousTrack();
},
handlePowerOff(ev) {
handleTogglePower(ev) {
ev.stopPropagation();
this.playerObj.turnOff();
this.playerObj.togglePower();
},
handlePowerOn(ev) {
ev.stopPropagation();
this.playerObj.turnOn();
},
handleVolumeMute(ev) {
ev.stopPropagation();
this.playerObj.volumeMute(!this.playerObj.isMuted);
},
});