mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
feat: optimize image load + genre page and reduce page size of loaded categories
This commit is contained in:
parent
862c4b8faf
commit
7131efa07f
18
.vscode/launch.json
vendored
18
.vscode/launch.json
vendored
@ -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": []
|
||||
}
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -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,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -174,6 +174,7 @@ class TrackCollectionView<T> extends HookConsumerWidget {
|
||||
color: color?.titleTextColor ?? Colors.white,
|
||||
),
|
||||
),
|
||||
isDense: true,
|
||||
prefixIconColor: color?.titleTextColor,
|
||||
prefixIcon: const Icon(SpotubeIcons.search),
|
||||
),
|
||||
@ -269,9 +270,7 @@ class TrackCollectionView<T> extends HookConsumerWidget {
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: UniversalImage(
|
||||
path: titleImage,
|
||||
placeholder: (context, url) {
|
||||
return Assets.albumPlaceholder.image();
|
||||
},
|
||||
placeholder: Assets.albumPlaceholder.path,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -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<String> 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());
|
||||
|
@ -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]);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -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<Page<PlaylistSimple>>(),
|
||||
title: 'Featured',
|
||||
hasNextPage: featuredPlaylistsQuery.hasNextPage,
|
||||
onFetchMore: featuredPlaylistsQuery.fetchNext,
|
||||
),
|
||||
PersonalizedItemCard(
|
||||
albums: newReleases.pages.whereType<Page<AlbumSimple>>(),
|
||||
title: 'New Releases',
|
||||
hasNextPage: newReleases.hasNextPage,
|
||||
onFetchMore: newReleases.fetchNext,
|
||||
),
|
||||
],
|
||||
),
|
||||
return SafeArea(
|
||||
child: ListView(
|
||||
children: [
|
||||
PersonalizedItemCard(
|
||||
playlists:
|
||||
featuredPlaylistsQuery.pages.whereType<Page<PlaylistSimple>>(),
|
||||
title: 'Featured',
|
||||
hasNextPage: featuredPlaylistsQuery.hasNextPage,
|
||||
onFetchMore: featuredPlaylistsQuery.fetchNext,
|
||||
),
|
||||
PersonalizedItemCard(
|
||||
albums: newReleases.pages.whereType<Page<AlbumSimple>>(),
|
||||
title: 'New Releases',
|
||||
hasNextPage: newReleases.hasNextPage,
|
||||
onFetchMore: newReleases.fetchNext,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -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;
|
||||
|
31
pubspec.lock
31
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"
|
||||
|
Loading…
Reference in New Issue
Block a user