Skip to content

Commit d14100a

Browse files
committed
fix: itemsPerRow not working when browsing media
1 parent 74ed515 commit d14100a

File tree

5 files changed

+88
-14
lines changed

5 files changed

+88
-14
lines changed

scripts/sync-upstream.sh

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,30 @@ sed -i '' 's/@customElement("ha-media-player-browse")/@customElement("sonos-ha-m
7575

7676
# Apply Sonos Card customizations to grid layout
7777
echo "Applying Sonos Card grid customizations..."
78-
# Change grid item size from 175px to 100px for compact display (4 columns instead of 2)
78+
# Change grid item size heights and gap
7979
sed -i '' \
80-
-e "s/width: '175px'/width: '100px'/g" \
8180
-e "s/height: '312px'/height: '180px'/g" \
8281
-e "s/height: '225px'/height: '150px'/g" \
8382
-e "s/gap: '16px'/gap: '8px'/g" \
8483
"$UPSTREAM_DIR/ha-media-player-browse.ts"
8584

85+
# Replace the hardcoded itemSize with getGridItemSize function call
86+
echo "Updating grid to use getGridItemSize..."
87+
sed -i '' "s/itemSize: {[^}]*width: '175px'[^}]*}/itemSize: getGridItemSize(this.itemsPerRow, childrenMediaClass.thumbnail_ratio === 'portrait')/g" \
88+
"$UPSTREAM_DIR/ha-media-player-browse.ts"
89+
90+
# Add itemsPerRow property to the component
91+
echo "Adding itemsPerRow property..."
92+
sed -i '' '/public preferredLayout.*auto/a\
93+
\
94+
@property({ type: Number }) public itemsPerRow?: number;
95+
' "$UPSTREAM_DIR/ha-media-player-browse.ts"
96+
97+
# Remove type import of LitVirtualizer (causes duplicate registration)
98+
echo "Fixing LitVirtualizer import..."
99+
sed -i '' '/^import type { LitVirtualizer }/d' "$UPSTREAM_DIR/ha-media-player-browse.ts"
100+
sed -i '' 's/private _virtualizer?: LitVirtualizer/private _virtualizer?: any/g' "$UPSTREAM_DIR/ha-media-player-browse.ts"
101+
86102
# Reduce play button size for smaller grid items
87103
echo "Reducing play button size..."
88104
sed -i '' \
@@ -92,13 +108,29 @@ sed -i '' \
92108
-e 's/right: calc(50% - 35px)/right: calc(50% - 20px)/g' \
93109
"$UPSTREAM_DIR/ha-media-player-browse.ts"
94110

111+
# Update virtualizer.ts to conditionally register lit-virtualizer
112+
echo "Updating virtualizer.ts..."
113+
cat > "$UPSTREAM_DIR/resources/virtualizer.ts" << 'EOF'
114+
// @ts-nocheck
115+
import { LitVirtualizer } from '@lit-labs/virtualizer/LitVirtualizer.js';
116+
117+
// Only register if not already defined (HA might have it already)
118+
if (!customElements.get('lit-virtualizer')) {
119+
customElements.define('lit-virtualizer', LitVirtualizer);
120+
}
121+
122+
export const loadVirtualizer = async (): Promise<void> => {
123+
// Element is registered above via static import
124+
};
125+
EOF
126+
95127
# Save version info
96128
echo "$RELEASE_TAG" > "$VERSION_FILE"
97129
echo "Synced: $(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> "$VERSION_FILE"
98130

99-
# Add filterOutIgnoredMediaSources import to ha-media-player-browse.ts
100-
echo "Adding filterOutIgnoredMediaSources import..."
101-
sed -i '' '1s/^/import { filterOutIgnoredMediaSources } from '\''..\/utils\/media-browse-utils'\'';\n/' \
131+
# Add custom imports to ha-media-player-browse.ts
132+
echo "Adding custom imports..."
133+
sed -i '' '1s/^/import { filterOutIgnoredMediaSources, getGridItemSize } from '\''..\/utils\/media-browse-utils'\'';\n/' \
102134
"$UPSTREAM_DIR/ha-media-player-browse.ts"
103135

104136
# Add @ts-nocheck to all upstream TypeScript files
@@ -112,7 +144,8 @@ done
112144
echo ""
113145
echo "✅ Synced from HA frontend release: $RELEASE_TAG"
114146
echo "✅ Component renamed to 'sonos-ha-media-player-browse'"
115-
echo "✅ Grid customizations applied (100px items, 8px gap)"
147+
echo "✅ Grid customizations applied (dynamic itemsPerRow width, 8px gap)"
148+
echo "✅ itemsPerRow property added for configurable grid columns"
116149
echo "✅ Non-audio media sources filtered (TTS, camera, images)"
117150
echo "✅ @ts-nocheck added to all upstream files"
118151
echo "✅ Version saved to $VERSION_FILE"

src/sections/media-browser.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,7 @@ export class MediaBrowser extends LitElement {
387387
.entityId=${activePlayer.id}
388388
.navigateIds=${this.navigateIds}
389389
.preferredLayout=${this.layout}
390+
.itemsPerRow=${mediaBrowserConfig.itemsPerRow}
390391
.action=${'play'}
391392
@media-picked=${this.onMediaPicked}
392393
@media-browsed=${this.onMediaBrowsed}

src/upstream/ha-media-player-browse.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// @ts-nocheck
2-
import type { LitVirtualizer } from '@lit-labs/virtualizer';
32
import { grid } from '@lit-labs/virtualizer/layouts/grid.js';
43

54
import { mdiArrowUpRight, mdiKeyboard, mdiPlay, mdiPlus } from '@mdi/js';
@@ -28,7 +27,7 @@ import { loadVirtualizer } from './resources/virtualizer';
2827
import type { HomeAssistant } from 'custom-card-helpers';
2928
import { brandsUrl, extractDomainFromBrandUrl, isBrandUrl } from './util/brands-url';
3029
import { documentationUrl } from './util/documentation-url';
31-
import { filterOutIgnoredMediaSources } from '../utils/media-browse-utils';
30+
import { filterOutIgnoredMediaSources, getGridItemSize } from '../utils/media-browse-utils';
3231
// HA components are available at runtime - no need to import
3332
import type { ManualMediaPickedEvent } from './ha-browse-media-manual';
3433
import type { TtsMediaPickedEvent } from './ha-browse-media-tts';
@@ -75,6 +74,8 @@ export class HaMediaPlayerBrowse extends LitElement {
7574
@property({ attribute: false })
7675
public preferredLayout: MediaPlayerLayoutType = 'auto';
7776

77+
@property({ type: Number }) public itemsPerRow?: number;
78+
7879
@property({ type: Boolean }) public dialog = false;
7980

8081
@property({ attribute: false }) public navigateIds: MediaPlayerItemId[] = [];
@@ -105,7 +106,7 @@ export class HaMediaPlayerBrowse extends LitElement {
105106

106107
@query('.content') private _content?: HTMLDivElement;
107108

108-
@query('lit-virtualizer') private _virtualizer?: LitVirtualizer;
109+
@query('lit-virtualizer') private _virtualizer?: any;
109110

110111
private _observed = false;
111112

@@ -474,10 +475,7 @@ export class HaMediaPlayerBrowse extends LitElement {
474475
<lit-virtualizer
475476
scroller
476477
.layout=${grid({
477-
itemSize: {
478-
width: '100px',
479-
height: childrenMediaClass.thumbnail_ratio === 'portrait' ? '180px' : '150px',
480-
},
478+
itemSize: getGridItemSize(this.itemsPerRow, childrenMediaClass.thumbnail_ratio === 'portrait'),
481479
gap: '8px',
482480
flex: { preserve: 'aspect-ratio' },
483481
justify: 'space-evenly',
Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
// @ts-nocheck
2+
import { LitVirtualizer } from '@lit-labs/virtualizer/LitVirtualizer.js';
3+
4+
// Only register if not already defined (HA might have it already)
5+
if (!customElements.get('lit-virtualizer')) {
6+
customElements.define('lit-virtualizer', LitVirtualizer);
7+
}
8+
29
export const loadVirtualizer = async (): Promise<void> => {
3-
await import('@lit-labs/virtualizer');
10+
// Element is registered above via static import
411
};

src/utils/media-browse-utils.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,41 @@ export function filterOutIgnoredMediaSources<T extends { media_content_id?: stri
6565
return items.filter((item) => !IGNORED_MEDIA_SOURCES.some((src) => item.media_content_id?.startsWith(src)));
6666
}
6767

68+
/**
69+
* Calculate grid item size based on itemsPerRow setting.
70+
* Used by media browser to support configurable grid columns.
71+
*/
72+
export function getGridItemSize(
73+
itemsPerRow: number | undefined,
74+
isPortrait: boolean,
75+
): { width: string; height: string } {
76+
const defaultWidth = 100;
77+
const defaultHeight = isPortrait ? 180 : 150;
78+
79+
if (!itemsPerRow || itemsPerRow === 4) {
80+
return { width: `${defaultWidth}px`, height: `${defaultHeight}px` };
81+
}
82+
83+
// Width map based on typical card width (~400px)
84+
const widthMap: Record<number, number> = {
85+
1: 380,
86+
2: 180,
87+
3: 120,
88+
4: 100,
89+
5: 75,
90+
6: 60,
91+
7: 50,
92+
8: 42,
93+
};
94+
95+
const width = widthMap[itemsPerRow] || defaultWidth;
96+
// Scale height proportionally to maintain aspect ratio
97+
const scale = width / defaultWidth;
98+
const height = Math.round(defaultHeight * scale);
99+
100+
return { width: `${width}px`, height: `${height}px` };
101+
}
102+
68103
export function itemsWithFallbacks(mediaPlayerItems: MediaPlayerItem[], config: CardConfig): MediaPlayerItem[] {
69104
const itemsWithImage = hasItemsWithImage(mediaPlayerItems);
70105
return mediaPlayerItems.map((item) => {

0 commit comments

Comments
 (0)