From 7131efa07fdbcf17965fc59ff635a6198b0e5e25 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 17 Mar 2023 13:05:26 +0600 Subject: [PATCH] feat: optimize image load + genre page and reduce page size of loaded categories --- .vscode/launch.json | 18 ++++- .../player/player_track_details.dart | 7 +- .../shared/image/universal_image.dart | 67 ++++++++++--------- lib/components/shared/playbutton_card.dart | 5 +- .../track_table/track_collection_view.dart | 5 +- .../shared/track_table/track_tile.dart | 7 +- lib/main.dart | 2 + lib/pages/home/genres.dart | 25 +++---- lib/pages/home/personalized.dart | 37 +++++----- lib/services/queries/category.dart | 4 +- pubspec.lock | 31 +-------- 11 files changed, 88 insertions(+), 120 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 6c0bb0d86..3c8209ffe 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,11 +2,25 @@ "version": "0.2.0", "configurations": [ { - "name": "Flutter", + "name": "spotube", "type": "dart", "request": "launch", - "program": "${workspaceFolder}/lib/main.dart" + "program": "lib/main.dart" }, + { + "name": "spotube (profile)", + "type": "dart", + "request": "launch", + "program": "lib/main.dart", + "flutterMode": "profile" + }, + { + "name": "spotube (release)", + "type": "dart", + "request": "launch", + "program": "lib/main.dart", + "flutterMode": "release" + } ], "compounds": [] } \ No newline at end of file diff --git a/lib/components/player/player_track_details.dart b/lib/components/player/player_track_details.dart index 4dee246f2..8e2a57ee6 100644 --- a/lib/components/player/player_track_details.dart +++ b/lib/components/player/player_track_details.dart @@ -33,12 +33,7 @@ class PlayerTrackDetails extends HookConsumerWidget { borderRadius: BorderRadius.circular(4), child: UniversalImage( path: albumArt ?? "", - placeholder: (context, url) { - return Assets.albumPlaceholder.image( - height: 50, - width: 50, - ); - }, + placeholder: Assets.albumPlaceholder.path, ), ), ), diff --git a/lib/components/shared/image/universal_image.dart b/lib/components/shared/image/universal_image.dart index 74cc76bec..45c7a15c7 100644 --- a/lib/components/shared/image/universal_image.dart +++ b/lib/components/shared/image/universal_image.dart @@ -11,7 +11,7 @@ class UniversalImage extends HookWidget { final double? height; final double? width; final double scale; - final PlaceholderWidgetBuilder? placeholder; + final String? placeholder; const UniversalImage({ required this.path, this.height, @@ -46,16 +46,17 @@ class UniversalImage extends HookWidget { @override Widget build(BuildContext context) { if (path.startsWith("http")) { - return CachedNetworkImage( - imageUrl: path, + return FadeInImage( + image: CachedNetworkImageProvider( + path, + maxHeight: height?.toInt(), + maxWidth: width?.toInt(), + cacheKey: path, + scale: scale, + ), height: height, width: width, - maxWidthDiskCache: width?.toInt(), - maxHeightDiskCache: height?.toInt(), - memCacheHeight: height?.toInt(), - memCacheWidth: width?.toInt(), - placeholder: placeholder, - cacheKey: path, + placeholder: AssetImage(placeholder ?? Assets.placeholder.path), ); } else if (Uri.tryParse(path) != null && !path.startsWith("assets")) { return Image.file( @@ -66,14 +67,14 @@ class UniversalImage extends HookWidget { cacheWidth: width?.toInt(), scale: scale, errorBuilder: (context, error, stackTrace) { - return placeholder?.call(context, error.toString()) ?? - Assets.placeholder.image( - width: width, - height: height, - cacheHeight: height?.toInt(), - cacheWidth: width?.toInt(), - scale: scale, - ); + return Image.asset( + placeholder ?? Assets.placeholder.path, + width: width, + height: height, + cacheHeight: height?.toInt(), + cacheWidth: width?.toInt(), + scale: scale, + ); }, ); } else if (path.startsWith("assets")) { @@ -85,14 +86,14 @@ class UniversalImage extends HookWidget { cacheWidth: width?.toInt(), scale: scale, errorBuilder: (context, error, stackTrace) { - return placeholder?.call(context, error.toString()) ?? - Assets.placeholder.image( - width: width, - height: height, - cacheHeight: height?.toInt(), - cacheWidth: width?.toInt(), - scale: scale, - ); + return Image.asset( + placeholder ?? Assets.placeholder.path, + width: width, + height: height, + cacheHeight: height?.toInt(), + cacheWidth: width?.toInt(), + scale: scale, + ); }, ); } @@ -105,14 +106,14 @@ class UniversalImage extends HookWidget { cacheWidth: width?.toInt(), scale: scale, errorBuilder: (context, error, stackTrace) { - return placeholder?.call(context, error.toString()) ?? - Assets.placeholder.image( - width: width, - height: height, - cacheHeight: height?.toInt(), - cacheWidth: width?.toInt(), - scale: scale, - ); + return Image.asset( + placeholder ?? Assets.placeholder.path, + width: width, + height: height, + cacheHeight: height?.toInt(), + cacheWidth: width?.toInt(), + scale: scale, + ); }, ); } diff --git a/lib/components/shared/playbutton_card.dart b/lib/components/shared/playbutton_card.dart index 34384e6d5..046945228 100644 --- a/lib/components/shared/playbutton_card.dart +++ b/lib/components/shared/playbutton_card.dart @@ -84,10 +84,7 @@ class PlaybuttonCard extends HookWidget { borderRadius: radius, child: UniversalImage( path: imageUrl, - placeholder: (context, url) { - return Assets.albumPlaceholder - .image(fit: BoxFit.cover); - }, + placeholder: Assets.albumPlaceholder.path, ), ), ), diff --git a/lib/components/shared/track_table/track_collection_view.dart b/lib/components/shared/track_table/track_collection_view.dart index b846d4609..ab2e4977f 100644 --- a/lib/components/shared/track_table/track_collection_view.dart +++ b/lib/components/shared/track_table/track_collection_view.dart @@ -174,6 +174,7 @@ class TrackCollectionView extends HookConsumerWidget { color: color?.titleTextColor ?? Colors.white, ), ), + isDense: true, prefixIconColor: color?.titleTextColor, prefixIcon: const Icon(SpotubeIcons.search), ), @@ -269,9 +270,7 @@ class TrackCollectionView extends HookConsumerWidget { borderRadius: BorderRadius.circular(10), child: UniversalImage( path: titleImage, - placeholder: (context, url) { - return Assets.albumPlaceholder.image(); - }, + placeholder: Assets.albumPlaceholder.path, ), ), ), diff --git a/lib/components/shared/track_table/track_tile.dart b/lib/components/shared/track_table/track_tile.dart index 1e20a6b4b..fd0b249dc 100644 --- a/lib/components/shared/track_table/track_tile.dart +++ b/lib/components/shared/track_table/track_tile.dart @@ -216,12 +216,7 @@ class TrackTile extends HookConsumerWidget { path: thumbnailUrl, height: 40, width: 40, - placeholder: (context, url) { - return Assets.albumPlaceholder.image( - height: 40, - width: 40, - ); - }, + placeholder: Assets.albumPlaceholder.path, ), ), ), diff --git a/lib/main.dart b/lib/main.dart index 92a72c1ea..36259aa42 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -14,6 +14,7 @@ import 'package:package_info_plus/package_info_plus.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:spotube/collections/cache_keys.dart'; import 'package:spotube/collections/env.dart'; +import 'package:spotube/components/settings/color_scheme_picker_dialog.dart'; import 'package:spotube/components/shared/dialogs/replace_downloaded_dialog.dart'; import 'package:spotube/entities/cache_track.dart'; import 'package:spotube/collections/routes.dart'; @@ -69,6 +70,7 @@ void main(List rawArgs) async { WidgetsFlutterBinding.ensureInitialized(); await SystemTheme.accentColor.load(); + colorsMap["System"] = SystemTheme.accentColor.accent; await QueryClient.initialize(cachePrefix: "oss.krtirtho.spotube"); Hive.registerAdapter(CacheTrackAdapter()); Hive.registerAdapter(CacheTrackEngagementAdapter()); diff --git a/lib/pages/home/genres.dart b/lib/pages/home/genres.dart index 315684b9c..598092624 100644 --- a/lib/pages/home/genres.dart +++ b/lib/pages/home/genres.dart @@ -68,20 +68,17 @@ class GenrePage extends HookConsumerWidget { } }, controller: scrollController, - child: SingleChildScrollView( - child: SafeArea( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ...categories.mapIndexed((index, category) { - if (searchText.value.isEmpty && - index == categories.length - 1) { - return const ShimmerCategories(); - } - return CategoryCard(category); - }) - ], - ), + child: SafeArea( + child: ListView.builder( + controller: scrollController, + itemCount: categories.length, + shrinkWrap: true, + itemBuilder: (context, index) { + if (searchText.value.isEmpty && index == categories.length - 1) { + return const ShimmerCategories(); + } + return CategoryCard(categories[index]); + }, ), ), ), diff --git a/lib/pages/home/personalized.dart b/lib/pages/home/personalized.dart index 3752f18a6..78fdbda03 100644 --- a/lib/pages/home/personalized.dart +++ b/lib/pages/home/personalized.dart @@ -110,26 +110,23 @@ class PersonalizedPage extends HookConsumerWidget { final newReleases = useQueries.album.newReleases(ref); - return SingleChildScrollView( - child: SafeArea( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - PersonalizedItemCard( - playlists: featuredPlaylistsQuery.pages - .whereType>(), - title: 'Featured', - hasNextPage: featuredPlaylistsQuery.hasNextPage, - onFetchMore: featuredPlaylistsQuery.fetchNext, - ), - PersonalizedItemCard( - albums: newReleases.pages.whereType>(), - title: 'New Releases', - hasNextPage: newReleases.hasNextPage, - onFetchMore: newReleases.fetchNext, - ), - ], - ), + return SafeArea( + child: ListView( + children: [ + PersonalizedItemCard( + playlists: + featuredPlaylistsQuery.pages.whereType>(), + title: 'Featured', + hasNextPage: featuredPlaylistsQuery.hasNextPage, + onFetchMore: featuredPlaylistsQuery.fetchNext, + ), + PersonalizedItemCard( + albums: newReleases.pages.whereType>(), + title: 'New Releases', + hasNextPage: newReleases.hasNextPage, + onFetchMore: newReleases.fetchNext, + ), + ], ), ); } diff --git a/lib/services/queries/category.dart b/lib/services/queries/category.dart index ff8ca5734..ddf66a103 100644 --- a/lib/services/queries/category.dart +++ b/lib/services/queries/category.dart @@ -16,13 +16,13 @@ class CategoryQueries { country: recommendationMarket, locale: 'en_US', ) - .getPage(15, pageParam); + .getPage(8, pageParam); return categories; }, initialPage: 0, nextPage: (lastPage, lastPageData) { - if (lastPageData.isLast || (lastPageData.items ?? []).length < 15) { + if (lastPageData.isLast || (lastPageData.items ?? []).length < 8) { return null; } return lastPageData.nextOffset; diff --git a/pubspec.lock b/pubspec.lock index 721e0dac1..97589595d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -554,14 +554,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0-alpha.2" - fluent_ui: - dependency: "direct main" - description: - name: fluent_ui - sha256: "29d85b74ee8d051bed9b5234afd50af4a693fef91f4e79657644051c23d789fb" - url: "https://pub.dev" - source: hosted - version: "4.4.1" fluentui_system_icons: dependency: "direct main" description: @@ -679,11 +671,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" - flutter_localizations: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" flutter_mailer: dependency: transitive description: @@ -1286,14 +1273,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.1" - recase: - dependency: transitive - description: - name: recase - sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 - url: "https://pub.dev" - source: hosted - version: "4.1.0" riverpod: dependency: transitive description: @@ -1318,14 +1297,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.6" - scroll_pos: - dependency: transitive - description: - name: scroll_pos - sha256: cfca311b6b8d51538ff90e206fbe6ce3b36e7125ea6da4a40eb626c7f9f083b1 - url: "https://pub.dev" - source: hosted - version: "0.3.0" scroll_to_index: dependency: "direct main" description: @@ -1807,4 +1778,4 @@ packages: version: "1.12.3" sdks: dart: ">=2.19.0 <3.0.0" - flutter: ">=3.7.0" + flutter: ">=3.3.0"