Skip to content

Commit

Permalink
[ 1.0.10 ] * This release requires the SpotifyPlus v1.0.64 release; p…
Browse files Browse the repository at this point in the history
…lease make sure you update the SpotifyPlus integration prior to updating this SpotifyPlus Card release.

  * Added `footerIconSize` general config option to change the size of the footer area icons.
  * Added `playerControlsIconSize` player controls config option to change the size of the player control area icons, volume mute icon, and power on/off icons.
  * Added actions dropdown menu to all section favorites browser details; most of these are the ability to search for related details.  More actions to come in future releases.
  * Added actions dropdown menu to all player information details; most of these are the ability to search for related details.  More actions to come in future releases.
  * Added ability to copy device details to the clipboard; for example, click on the value next to the `Device ID` title to copy the device id to the clipboard.
  * Added (all browsers) action: copy Spotify URI to clipboard.
  * Added playlist action: recover playlists via Spotify web ui.
  * Added playlist action: delete (unfollow) a playlist.
  * Updated playlist item action: track will now be added to the play queue instead of being played.  This will avoid wiping out the play queue.
  * Updated album item action: track will now be added to the play queue instead of being played.  This will avoid wiping out the play queue.
  * Updated podcast show item action: episode will now be added to the play queue instead of being played.  This will avoid wiping out the play queue.
  * Updated audiobook item action: chapter will now be added to the play queue instead of being played.  This will avoid wiping out the play queue.
  • Loading branch information
thlucas1 committed Nov 3, 2024
1 parent b001ff7 commit 20d1c34
Show file tree
Hide file tree
Showing 35 changed files with 1,954 additions and 374 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,22 @@ Change are listed in reverse chronological order (newest to oldest).

<span class="changelog">

###### [ 1.0.10 ] - 2024/11/03

* This release requires the SpotifyPlus v1.0.64 release; please make sure you update the SpotifyPlus integration prior to updating this SpotifyPlus Card release.
* Added `footerIconSize` general config option to change the size of the footer area icons.
* Added `playerControlsIconSize` player controls config option to change the size of the player control area icons, volume mute icon, and power on/off icons.
* Added actions dropdown menu to all section favorites browser details; most of these are the ability to search for related details. More actions to come in future releases.
* Added actions dropdown menu to all player information details; most of these are the ability to search for related details. More actions to come in future releases.
* Added ability to copy device details to the clipboard; for example, click on the value next to the `Device ID` title to copy the device id to the clipboard.
* Added (all browsers) action: copy Spotify URI to clipboard.
* Added playlist action: recover playlists via Spotify web ui.
* Added playlist action: delete (unfollow) a playlist.
* Updated playlist item action: track will now be added to the play queue instead of being played. This will avoid wiping out the play queue.
* Updated album item action: track will now be added to the play queue instead of being played. This will avoid wiping out the play queue.
* Updated podcast show item action: episode will now be added to the play queue instead of being played. This will avoid wiping out the play queue.
* Updated audiobook item action: chapter will now be added to the play queue instead of being played. This will avoid wiping out the play queue.

###### [ 1.0.9 ] - 2024/10/30

* This release requires the SpotifyPlus v1.0.63 release; please make sure you update the SpotifyPlus integration prior to updating this SpotifyPlus Card release.
Expand Down
3 changes: 3 additions & 0 deletions SpotifyPlusCard.njsproj
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@
<TypeScriptCompile Include="src\components\track-actions.ts" />
<TypeScriptCompile Include="src\components\userpreset-actions.ts" />
<TypeScriptCompile Include="src\editor\episode-fav-browser-editor.ts" />
<TypeScriptCompile Include="src\events\search-media.ts">
<SubType>Code</SubType>
</TypeScriptCompile>
<TypeScriptCompile Include="src\sections\episode-fav-browser.ts" />
<TypeScriptCompile Include="src\sections\fav-browser-base.ts" />
<TypeScriptCompile Include="src\styles\shared-styles-grid.js" />
Expand Down
12 changes: 12 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@vibrant/image-browser": "^3.2.1-alpha.1",
"@vibrant/image-node": "^3.2.1-alpha.1",
"@vibrant/quantizer-mmcq": "^3.2.1-alpha.1",
"copy-text-to-clipboard": "^3.2.0",
"custom-card-helpers": "^1.9.0",
"debug": "^4.3.7",
"lit": "^2.8.0",
Expand Down
180 changes: 122 additions & 58 deletions src/card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { HomeAssistant } from 'custom-card-helpers';
import { css, html, LitElement, PropertyValues, TemplateResult } from 'lit';
import { styleMap } from 'lit-html/directives/style-map.js';
import { customElement, property, state } from 'lit/decorators.js';
import { customElement, property, query, state } from 'lit/decorators.js';
import { choose } from 'lit/directives/choose.js';
import { when } from 'lit/directives/when.js';

Expand All @@ -23,16 +23,19 @@ import './components/footer';
import './editor/editor';

// our imports.
import { SEARCH_MEDIA, SearchMediaEventArgs } from './events/search-media';
import { EDITOR_CONFIG_AREA_SELECTED, EditorConfigAreaSelectedEventArgs } from './events/editor-config-area-selected';
import { PROGRESS_STARTED } from './events/progress-started';
import { PROGRESS_ENDED } from './events/progress-ended';
import { Store } from './model/store';
import { Section } from './types/section';
import { ConfigArea } from './types/config-area';
import { CardConfig } from './types/card-config';
import { CustomImageUrls } from './types/custom-image-urls';
import { ConfigArea } from './types/config-area';
import { Section } from './types/section';
import { SearchMediaTypes } from './types/search-media-types';
import { SearchBrowser } from './sections/search-media-browser';
import { formatTitleInfo, removeSpecialChars } from './utils/media-browser-utils';
import { BRAND_LOGO_IMAGE_BASE64, BRAND_LOGO_IMAGE_SIZE } from './constants';
import { BRAND_LOGO_IMAGE_BASE64, BRAND_LOGO_IMAGE_SIZE, FOOTER_ICON_SIZE_DEFAULT } from './constants';
import {
getConfigAreaForSection,
getSectionForConfigArea,
Expand All @@ -41,7 +44,11 @@ import {
isCardInPickerPreview,
isNumber,
} from './utils/utils';
import { SearchMediaTypes } from './types/search-media-types';

// debug logging.
import Debug from 'debug/src/browser.js';
import { DEBUG_APP_NAME } from './constants';
const debuglog = Debug(DEBUG_APP_NAME + ":card");

const HEADER_HEIGHT = 2;
const FOOTER_HEIGHT = 4;
Expand Down Expand Up @@ -88,6 +95,9 @@ export class Card extends LitElement {
@state() private cancelLoader!: boolean;
@state() private playerId!: string;

@query("#elmSearchMediaBrowserForm", false) private elmSearchMediaBrowserForm!: SearchBrowser;


/** Indicates if createStore method is executing for the first time (true) or not (false). */
private isFirstTimeSetup: boolean = true;

Expand Down Expand Up @@ -163,7 +173,7 @@ export class Card extends LitElement {
[Section.PLAYER, () => html`<spc-player id="spcPlayer" .store=${this.store}></spc-player>`],
[Section.PLAYLIST_FAVORITES, () => html`<spc-playlist-fav-browser .store=${this.store} @item-selected=${this.onMediaListItemSelected}></spc-playlist-fav-browser>`],
[Section.RECENTS, () => html`<spc-recent-browser .store=${this.store} @item-selected=${this.onMediaListItemSelected}></spc-recents-browser>`],
[Section.SEARCH_MEDIA, () => html`<spc-search-media-browser .store=${this.store} @item-selected=${this.onMediaListItemSelected}></spc-search-media-browser>`],
[Section.SEARCH_MEDIA, () => html`<spc-search-media-browser .store=${this.store} @item-selected=${this.onMediaListItemSelected} id="elmSearchMediaBrowserForm"></spc-search-media-browser>`],
[Section.SHOW_FAVORITES, () => html`<spc-show-fav-browser .store=${this.store} @item-selected=${this.onMediaListItemSelected}></spc-show-fav-browser>`],
[Section.TRACK_FAVORITES, () => html`<spc-track-fav-browser .store=${this.store} @item-selected=${this.onMediaListItemSelected}></spc-track-fav-browser>`],
[Section.USERPRESETS, () => html`<spc-userpreset-browser .store=${this.store} @item-selected=${this.onMediaListItemSelected}></spc-userpresets-browser>`],
Expand Down Expand Up @@ -274,9 +284,10 @@ export class Card extends LitElement {
align-self: flex-start;
align-items: center;
justify-content: space-around;
flex-wrap: wrap;
width: 100%;
--mdc-icon-size: 1.75rem;
--mdc-icon-button-size: 2.5rem;
--mdc-icon-button-size: var(--spc-footer-icon-button-size, 2.5rem);
--mdc-icon-size: var(--spc-footer-icon-size, 1.75rem);
--mdc-ripple-top: 0px;
--mdc-ripple-left: 0px;
--mdc-ripple-fg-size: 10px;
Expand Down Expand Up @@ -395,9 +406,10 @@ export class Card extends LitElement {
// invoke base class method.
super.connectedCallback();

// add control level event listeners.
// add card level event listeners.
this.addEventListener(PROGRESS_ENDED, this.onProgressEndedEventHandler);
this.addEventListener(PROGRESS_STARTED, this.onProgressStartedEventHandler);
this.addEventListener(SEARCH_MEDIA, this.onSearchMediaEventHandler);

// only add the following events if card configuration is being edited.
if (isCardInEditPreview(this)) {
Expand All @@ -422,9 +434,10 @@ export class Card extends LitElement {
*/
public disconnectedCallback() {

// remove control level event listeners.
// remove card level event listeners.
this.removeEventListener(PROGRESS_ENDED, this.onProgressEndedEventHandler);
this.removeEventListener(PROGRESS_STARTED, this.onProgressStartedEventHandler);
this.removeEventListener(SEARCH_MEDIA, this.onSearchMediaEventHandler);

// the following event is only added when the card configuration editor is created.
// always remove the following events, as isCardInEditPreview() can sometimes
Expand Down Expand Up @@ -507,6 +520,75 @@ export class Card extends LitElement {
}


/**
* Handles the card configuration editor `EDITOR_CONFIG_AREA_SELECTED` event.
*
* This will select a section for display / rendering.
* This event should only be fired from the configuration editor instance.
*
* @param ev Event definition and arguments.
*/
protected onEditorConfigAreaSelectedEventHandler = (ev: Event) => {

// map event arguments.
const evArgs = (ev as CustomEvent).detail as EditorConfigAreaSelectedEventArgs;

// is section activated? if so, then select it.
if (this.config.sections?.includes(evArgs.section)) {

this.section = evArgs.section;
this.store.section = this.section;

} else {

// section is not activated.

}
}


/**
* Handles the footer `show-section` event.
*
* This will change the `section` attribute value to the value supplied, which will also force
* a refresh of the card and display the selected section.
*
* @param args Event arguments that contain the section to show.
*/
protected onFooterShowSection = (args: CustomEvent) => {

const section = args.detail;
if (!this.config.sections || this.config.sections.indexOf(section) > -1) {

this.section = section;
this.store.section = this.section;
super.requestUpdate();

} else {

// specified section is not active.

}
}


/**
* Handles the Media List `item-selected` event.
*
* @param args Event arguments (none passed).
*/
protected onMediaListItemSelected = () => {

// don't need to do anything here, as the section will show the player.
// left this code here though, in case we want to do something else after
// an item is selected.

// example: show the card Player section (after a slight delay).
//setTimeout(() => (this.SetSection(Section.PLAYER)), 1500);

}


/**
* Handles the `PROGRESS_ENDED` event.
* This will hide the circular progress indicator on the main card display.
Expand Down Expand Up @@ -566,74 +648,49 @@ export class Card extends LitElement {


/**
* Handles the card configuration editor `EDITOR_CONFIG_AREA_SELECTED` event.
*
* This will select a section for display / rendering.
* This event should only be fired from the configuration editor instance.
* Handles the `SEARCH_MEDIA` event.
* This will execute a search on the specified criteria passed in the event arguments.
*
* @param ev Event definition and arguments.
*/
protected onEditorConfigAreaSelectedEventHandler = (ev: Event) => {
protected onSearchMediaEventHandler = (ev: Event) => {

// map event arguments.
const evArgs = (ev as CustomEvent).detail as EditorConfigAreaSelectedEventArgs;
const evArgs = (ev as CustomEvent).detail as SearchMediaEventArgs;

// is section activated? if so, then select it.
if (this.config.sections?.includes(evArgs.section)) {
if (this.config.sections?.includes(Section.SEARCH_MEDIA)) {

this.section = evArgs.section;
// show the search section.
this.section = Section.SEARCH_MEDIA;
this.store.section = this.section;
//this.dispatchEvent(customEvent(SHOW_SECTION, Section.SEARCH_MEDIA));

} else {

// section is not activated.

}
}

// wait just a bit before executing the search.
setTimeout(() => {

/**
* Handles the footer `show-section` event.
*
* This will change the `section` attribute value to the value supplied, which will also force
* a refresh of the card and display the selected section.
*
* @param args Event arguments that contain the section to show.
*/
protected onFooterShowSection = (args: CustomEvent) => {
if (debuglog.enabled) {
debuglog("onSearchMediaEventHandler - executing search:\n%s",
JSON.stringify(evArgs, null, 2),
);
}

const section = args.detail;
if (!this.config.sections || this.config.sections.indexOf(section) > -1) {
// execute the search.
this.elmSearchMediaBrowserForm.searchExecute(evArgs);

this.section = section;
this.store.section = this.section;
super.requestUpdate();
}, 250);

} else {

// specified section is not active.
// section is not activated; cannot search.
debuglog("onSearchMediaEventHandler - Search section is not enabled; ignoring search request:\n%s",
JSON.stringify(evArgs, null, 2),
);

}
}


/**
* Handles the Media List `item-selected` event.
*
* @param args Event arguments (none passed).
*/
protected onMediaListItemSelected = () => {

// don't need to do anything here, as the section will show the player.
// left this code here though, in case we want to do something else after
// an item is selected.

// example: show the card Player section (after a slight delay).
//setTimeout(() => (this.SetSection(Section.PLAYER)), 1500);

}


/**
* Home Assistant will call setConfig(config) when the configuration changes. This
* is most likely to occur when changing the configuration via the UI editor, but
Expand Down Expand Up @@ -1036,20 +1093,27 @@ export class Card extends LitElement {
*/
private styleCardFooter() {

// set footer icon size.
const footerIconSize = this.config.footerIconSize || FOOTER_ICON_SIZE_DEFAULT;

// is player selected, and a footer background color set?
if ((this.section == Section.PLAYER) && (this.footerBackgroundColor)) {

// yes - return vibrant background style.
return styleMap({
'--spc-footer-icon-size': `${footerIconSize}`,
'--spc-footer-icon-button-size': `var(--spc-footer-icon-size, ${FOOTER_ICON_SIZE_DEFAULT}) + 0.75rem`,
'--spc-player-footer-bg-color': `${this.footerBackgroundColor || 'transparent'}`,
'background-color': 'var(--spc-player-footer-bg-color)',
'background-image': 'linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 1.6))',
});

} else {

// no - just return an empty style to let it default to the card background.
// return style map (let background color default to the card background color).
return styleMap({
'--spc-footer-icon-size': `${footerIconSize}`,
'--spc-footer-icon-button-size': `var(--spc-footer-icon-size, ${FOOTER_ICON_SIZE_DEFAULT}) + 0.75rem`,
});

}
Expand Down
Loading

0 comments on commit 20d1c34

Please sign in to comment.