perf: optimize scrolling and image loading performance

Added performance optimizations to all library browser views:

- Added cacheExtent: 500 to all GridView/ListView builders to pre-render
  items and reduce stuttering during scrolling
- Wrapped grid items in RepaintBoundary to isolate repaints and improve
  performance
- Optimized CachedNetworkImage with:
  - fadeInDuration/fadeOutDuration: Duration.zero to remove animation overhead
  - memCacheHeight: 300 to limit in-memory cache size
  - maxHeightDiskCache: 600 to resize images for better performance

These changes should significantly reduce the stuttering observed when
scrolling the authors grid and filtering books, especially on first load.
This commit is contained in:
Claude 2025-11-20 22:18:20 +00:00
parent ccb8318341
commit b434f73b2a
No known key found for this signature in database
4 changed files with 18 additions and 2 deletions

View file

@ -84,6 +84,7 @@ class FilteredLibraryItemsPage extends HookConsumerWidget {
return GridView.builder(
padding: const EdgeInsets.all(16),
cacheExtent: 500, // Pre-render items for smoother scrolling
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 0.65,
@ -93,7 +94,9 @@ class FilteredLibraryItemsPage extends HookConsumerWidget {
itemCount: response.results.length,
itemBuilder: (context, index) {
final item = response.results[index];
return LibraryItemCard(item: item);
return RepaintBoundary(
child: LibraryItemCard(item: item),
);
},
);
},
@ -247,6 +250,10 @@ class LibraryItemCard extends ConsumerWidget {
? CachedNetworkImage(
imageUrl: imageUrl,
fit: BoxFit.cover,
fadeInDuration: Duration.zero, // Remove fade animation for better performance
fadeOutDuration: Duration.zero,
memCacheHeight: 300, // Limit memory cache size
maxHeightDiskCache: 600, // Limit disk cache size
httpHeaders: {
if (apiSettings.activeUser?.authToken != null)
'Authorization':

View file

@ -37,6 +37,7 @@ class LibraryAuthorsPage extends HookConsumerWidget {
return GridView.builder(
padding: const EdgeInsets.all(16),
cacheExtent: 500, // Pre-render items for smoother scrolling
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.75,
@ -46,7 +47,9 @@ class LibraryAuthorsPage extends HookConsumerWidget {
itemCount: sortedAuthors.length,
itemBuilder: (context, index) {
final author = sortedAuthors[index];
return AuthorCard(author: author);
return RepaintBoundary(
child: AuthorCard(author: author),
);
},
);
},
@ -125,6 +128,10 @@ class AuthorCard extends HookConsumerWidget {
'Authorization': 'Bearer ${apiSettings.activeUser?.authToken}',
},
fit: BoxFit.cover,
fadeInDuration: Duration.zero, // Remove fade animation for better performance
fadeOutDuration: Duration.zero,
memCacheHeight: 300, // Limit memory cache size
maxHeightDiskCache: 600, // Limit disk cache size
placeholder: (context, url) => Container(
color: Theme.of(context).colorScheme.surfaceContainerHighest,
child: const Center(

View file

@ -29,6 +29,7 @@ class LibraryGenresPage extends HookConsumerWidget {
return ListView.builder(
padding: const EdgeInsets.symmetric(vertical: 8),
cacheExtent: 500, // Pre-render items for smoother scrolling
itemCount: sortedGenres.length,
itemBuilder: (context, index) {
final genre = sortedGenres[index];

View file

@ -38,6 +38,7 @@ class LibrarySeriesPage extends HookConsumerWidget {
return ListView.builder(
padding: const EdgeInsets.symmetric(vertical: 8),
cacheExtent: 500, // Pre-render items for smoother scrolling
itemCount: seriesList.length,
itemBuilder: (context, index) {
final series = seriesList[index];