perf: shrink semantics tree on media lists

Poster images are decorative (the card exposes one merged node), and
the default per-child AutomaticKeepAlive/_SelectionKeepAlive/
IndexedSemantics wrappers are inert here — no keep-alive clients or
SelectionArea exist. The semantics phase ran ~9ms every frame on TV
devices with an accessibility service; it scales with node count.
This commit is contained in:
edde746
2026-07-02 11:41:25 +02:00
parent c38f24aee9
commit 43ab5d3246
11 changed files with 107 additions and 37 deletions
@@ -1741,6 +1741,10 @@ class _LibraryBrowseTabState extends BaseLibraryTabState<MediaItem, LibraryBrows
return SliverPadding(
padding: .fromLTRB(8, topPadding, rightPadding, 8),
sliver: SliverList.builder(
// Inert on media lists (no keep-alive clients): dropping the
// per-child wrappers shrinks build + semantics work per item.
addAutomaticKeepAlives: false,
addSemanticIndexes: false,
itemCount: itemCount,
itemBuilder: (context, index) {
final child = _buildMediaCardItem(
@@ -1784,6 +1788,10 @@ class _LibraryBrowseTabState extends BaseLibraryTabState<MediaItem, LibraryBrows
itemHeight: geometry.itemHeight,
);
return SliverGrid.builder(
// Inert on media lists (no keep-alive clients): dropping the
// per-child wrappers shrinks build + semantics work per item.
addAutomaticKeepAlives: false,
addSemanticIndexes: false,
gridDelegate: geometry.delegate,
itemCount: itemCount,
itemBuilder: (context, index) => _buildMediaCardItem(
@@ -139,6 +139,10 @@ class _LibraryCollectionsTabState extends BaseLibraryTabState<MediaItem, Library
return SliverPadding(
padding: _effectivePadding,
sliver: SliverList.builder(
// Inert on media lists (no keep-alive clients): dropping the
// per-child wrappers shrinks build + semantics work per item.
addAutomaticKeepAlives: false,
addSemanticIndexes: false,
itemCount: totalSize,
itemBuilder: (context, index) =>
_buildMediaCardItem(index, isFirstRow: index == 0, isFirstColumn: true, disableScale: true),
@@ -158,6 +162,10 @@ class _LibraryCollectionsTabState extends BaseLibraryTabState<MediaItem, Library
fullBleedImage: fullCardLayout,
);
return SliverGrid.builder(
// Inert on media lists (no keep-alive clients): dropping the
// per-child wrappers shrinks build + semantics work per item.
addAutomaticKeepAlives: false,
addSemanticIndexes: false,
gridDelegate: geometry.delegate,
itemCount: totalSize,
itemBuilder: (context, index) => _buildMediaCardItem(
@@ -141,6 +141,10 @@ class _LibraryPlaylistsTabState extends BaseLibraryTabState<MediaPlaylist, Libra
return SliverPadding(
padding: _effectivePadding,
sliver: SliverList.builder(
// Inert on media lists (no keep-alive clients): dropping the
// per-child wrappers shrinks build + semantics work per item.
addAutomaticKeepAlives: false,
addSemanticIndexes: false,
itemCount: totalSize,
itemBuilder: (context, index) =>
_buildPlaylistCard(index, isFirstRow: index == 0, isFirstColumn: true, disableScale: true),
@@ -160,6 +164,10 @@ class _LibraryPlaylistsTabState extends BaseLibraryTabState<MediaPlaylist, Libra
fullBleedImage: fullCardLayout,
);
return SliverGrid.builder(
// Inert on media lists (no keep-alive clients): dropping the
// per-child wrappers shrinks build + semantics work per item.
addAutomaticKeepAlives: false,
addSemanticIndexes: false,
gridDelegate: geometry.delegate,
itemCount: totalSize,
itemBuilder: (context, index) => _buildPlaylistCard(