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-loader": "^6.2",
"babel-preset-es2015": "^6.6.0", "babel-preset-es2015": "^6.6.0",
"bower": "^1.7.9", "bower": "^1.7.9",
"classnames": "^2.2.3",
"eslint": "^2.7.0", "eslint": "^2.7.0",
"eslint-config-airbnb": "^6.2.0", "eslint-config-airbnb": "^6.2.0",
"html-minifier": "^1.4.0", "html-minifier": "^1.4.0",

View File

@ -10,57 +10,83 @@
font-size: 0px; font-size: 0px;
border-radius: 2px; border-radius: 2px;
transition: height .5s;
background-size: cover;
background-position: center center;
background-color: var(--paper-grey-500);
overflow: hidden; overflow: hidden;
} }
.options { .banner {
float: right; position: relative;
margin-right: -8px;
margin-top: -8px; 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); @apply(--paper-font-caption);
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
background: linear-gradient(to bottom, position: absolute;
rgba(0,0,0,0.5) 0%, left: 0;
rgba(0,0,0,0) 100%); right: 0;
bottom: 0;
padding: 8px; background-color: rgba(0, 0, 0, var(--dark-secondary-opacity));
padding: 16px;
text-transform: capitalize; text-transform: capitalize;
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
color: white; color: white;
transition: background-color .5s;
} }
.caption .title { .banner.is-off > .caption {
background-color: initial;
}
.banner > .caption .title {
@apply(--paper-font-common-nowrap); @apply(--paper-font-common-nowrap);
font-size: 1.2em; font-size: 1.2em;
margin-bottom: 4px; margin: 8px 0 4px;
}
.controls-container {
position: absolute;
left: 8px;
right: 8px;
top: 91px;
} }
.controls { .controls {
@apply(--paper-font-body1); @apply(--paper-font-body1);
padding: 8px; padding: 8px;
border-radius: 2px; border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
background-color: white; background-color: white;
text-align: center;
} }
.controls paper-icon-button { .controls paper-icon-button {
@ -68,6 +94,10 @@
height: 44px; height: 44px;
} }
paper-icon-button {
color: var(--primary-text-color);
}
paper-icon-button.primary { paper-icon-button.primary {
width: 56px !important; width: 56px !important;
height: 56px !important; height: 56px !important;
@ -75,6 +105,11 @@
color: white; color: white;
border-radius: 50%; border-radius: 50%;
padding: 8px; padding: 8px;
transition: background-color .5s;
}
paper-icon-button.primary[disabled] {
background-color: rgba(0, 0, 0, var(--dark-disabled-opacity));
} }
[invisible] { [invisible] {
@ -82,63 +117,50 @@
} }
</style> </style>
<template> <template>
<img src='[[stateObj.attributes.entity_picture]]' hidden <div class$='[[computeBannerClasses(playerObj)]]'>
on-load='imageLoadSuccess' on-error='imageLoadFail'> <div class='cover' id='cover'></div>
<div class='caption'> <div class='caption'>
<div class='options'> [[stateObj.entityDisplay]]
<paper-icon-button <div class='title'>[[playerObj.primaryText]]</div>
class='power-on' [[playerObj.secondaryText]]<br />
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>
<div class='title'>[[playerObj.primaryText]]</div>
[[playerObj.secondaryText]]<br />
@[[stateObj.entityDisplay]]
</div> </div>
<div class='controls-container'> <div class='controls layout horizontal justified'>
<paper-material elevation="1"> <paper-icon-button
<div class='controls layout horizontal justified'> icon='mdi:power'
<paper-icon-button on-tap='handleTogglePower'
icon='[[computeVolumeMuteIcon(playerObj)]]' invisible$='[[!playerObj.supportsTurnOff]]'
on-tap='handleVolumeMute' class='self-center secondary'
invisible$='[[!playerObj.supportsVolumeMute]]' ></paper-icon-button>
class='self-center'
></paper-icon-button>
<div> <div>
<paper-icon-button <paper-icon-button
icon='mdi:skip-previous' icon='mdi:skip-previous'
invisible$='[[!playerObj.supportsPreviousTrack]]' invisible$='[[!playerObj.supportsPreviousTrack]]'
on-tap='handlePrevious' on-tap='handlePrevious'
></paper-icon-button> ></paper-icon-button>
<paper-icon-button <paper-icon-button
class='primary' class='primary'
icon='[[computePlaybackControlIcon(playerObj)]]' icon='[[computePlaybackControlIcon(playerObj)]]'
on-tap='handlePlaybackControl' invisible='[[!computePlaybackControlIcon(playerObj)]]'
></paper-icon-button> disabled='[[playerObj.isOff]]'
<paper-icon-button on-tap='handlePlaybackControl'
icon='mdi:skip-next' ></paper-icon-button>
invisible$='[[!playerObj.supportsNextTrack]]' <paper-icon-button
on-tap='handleNext' icon='mdi:skip-next'
></paper-icon-button> invisible$='[[!playerObj.supportsNextTrack]]'
</div> 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> </div>
</template> </template>
</dom-module> </dom-module>

View File

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