Playback track search retry-able now

Search page not rendering fix
This commit is contained in:
Kingkor Roy Tirtho 2022-07-06 00:59:33 +06:00
parent e2bba4ac94
commit c51a9a4c28
6 changed files with 171 additions and 141 deletions

View File

@ -67,7 +67,7 @@ class PlayerView extends HookConsumerWidget {
), ),
child: BackdropFilter( child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 15, sigmaY: 15), filter: ImageFilter.blur(sigmaX: 15, sigmaY: 15),
child: Container( child: Material(
color: paletteColor.color.withOpacity(.5), color: paletteColor.color.withOpacity(.5),
child: SafeArea( child: SafeArea(
child: Column( child: Column(

View File

@ -37,8 +37,8 @@ class Search extends HookConsumerWidget {
} }
final searchSnapshot = ref.watch(searchQuery(searchTerm)); final searchSnapshot = ref.watch(searchQuery(searchTerm));
return SafeArea( return Expanded(
child: Expanded( child: SafeArea(
child: Container( child: Container(
color: Theme.of(context).backgroundColor, color: Theme.of(context).backgroundColor,
child: Column( child: Column(

View File

@ -177,151 +177,155 @@ class TrackTile extends HookConsumerWidget {
: Colors.transparent, : Colors.transparent,
borderRadius: BorderRadius.circular(isActive ? 10 : 0), borderRadius: BorderRadius.circular(isActive ? 10 : 0),
), ),
child: Row( child: Material(
children: [ type: MaterialType.transparency,
SizedBox( child: Row(
height: 20, children: [
width: 25, SizedBox(
child: Text( height: 20,
(track.key + 1).toString(), width: 25,
textAlign: TextAlign.center, child: Text(
), (track.key + 1).toString(),
), textAlign: TextAlign.center,
if (thumbnailUrl != null)
Padding(
padding: EdgeInsets.symmetric(
horizontal: breakpoint.isMoreThan(Breakpoints.md) ? 8.0 : 0,
vertical: 8.0,
), ),
child: ClipRRect( ),
borderRadius: const BorderRadius.all(Radius.circular(5)), if (thumbnailUrl != null)
child: CachedNetworkImage( Padding(
placeholder: (context, url) { padding: EdgeInsets.symmetric(
return Container( horizontal: breakpoint.isMoreThan(Breakpoints.md) ? 8.0 : 0,
height: 40, vertical: 8.0,
width: 40, ),
color: Theme.of(context).primaryColor, child: ClipRRect(
); borderRadius: const BorderRadius.all(Radius.circular(5)),
}, child: CachedNetworkImage(
imageUrl: thumbnailUrl!, placeholder: (context, url) {
maxHeightDiskCache: 40, return Container(
maxWidthDiskCache: 40, height: 40,
width: 40,
color: Theme.of(context).primaryColor,
);
},
imageUrl: thumbnailUrl!,
maxHeightDiskCache: 40,
maxWidthDiskCache: 40,
),
), ),
), ),
IconButton(
icon: Icon(
playback.track?.id != null &&
playback.track?.id == track.value.id
? Icons.pause_circle_rounded
: Icons.play_circle_rounded,
color: Theme.of(context).primaryColor,
),
onPressed: () => onTrackPlayButtonPressed?.call(
track.value,
),
), ),
IconButton( Expanded(
icon: Icon( child: Column(
playback.track?.id != null && playback.track?.id == track.value.id crossAxisAlignment: CrossAxisAlignment.start,
? Icons.pause_circle_rounded children: [
: Icons.play_circle_rounded, Text(
color: Theme.of(context).primaryColor, track.value.name ?? "",
), style: TextStyle(
onPressed: () => onTrackPlayButtonPressed?.call( fontWeight: FontWeight.bold,
track.value, fontSize: breakpoint.isSm ? 14 : 17,
), ),
), overflow: TextOverflow.ellipsis,
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
track.value.name ?? "",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: breakpoint.isSm ? 14 : 17,
), ),
artistsToClickableArtists(track.value.artists ?? [],
textStyle: TextStyle(
fontSize:
breakpoint.isLessThan(Breakpoints.lg) ? 12 : 14)),
],
),
),
if (breakpoint.isMoreThan(Breakpoints.md) && showAlbum)
Expanded(
child: LinkText(
track.value.album!.name!,
"/album/${track.value.album?.id}",
extra: track.value.album,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
artistsToClickableArtists(track.value.artists ?? [],
textStyle: TextStyle(
fontSize:
breakpoint.isLessThan(Breakpoints.lg) ? 12 : 14)),
],
),
),
if (breakpoint.isMoreThan(Breakpoints.md) && showAlbum)
Expanded(
child: LinkText(
track.value.album!.name!,
"/album/${track.value.album?.id}",
extra: track.value.album,
overflow: TextOverflow.ellipsis,
), ),
), if (!breakpoint.isSm) ...[
if (!breakpoint.isSm) ...[ const SizedBox(width: 10),
Text(duration),
],
const SizedBox(width: 10), const SizedBox(width: 10),
Text(duration), PopupMenuButton(
icon: const Icon(Icons.more_horiz_rounded),
itemBuilder: (context) {
return [
if (auth.isLoggedIn)
PopupMenuItem(
child: Row(
children: const [
Icon(Icons.add_box_rounded),
SizedBox(width: 10),
Text("Add to Playlist"),
],
),
value: "add-playlist",
),
if (userPlaylist && auth.isLoggedIn)
PopupMenuItem(
child: Row(
children: const [
Icon(Icons.remove_circle_outline_rounded),
SizedBox(width: 10),
Text("Remove from Playlist"),
],
),
value: "remove-playlist",
),
if (auth.isLoggedIn)
PopupMenuItem(
child: Row(
children: [
Icon(isSaved
? Icons.favorite_rounded
: Icons.favorite_border_rounded),
const SizedBox(width: 10),
const Text("Favorite")
],
),
value: "favorite",
),
PopupMenuItem(
child: Row(
children: const [
Icon(Icons.share_rounded),
SizedBox(width: 10),
Text("Share")
],
),
value: "share",
)
];
},
onSelected: (value) {
switch (value) {
case "favorite":
actionFavorite(isSaved);
break;
case "add-playlist":
actionAddToPlaylist();
break;
case "remove-playlist":
actionRemoveFromPlaylist();
break;
case "share":
actionShare(track.value);
break;
}
},
),
], ],
const SizedBox(width: 10), ),
PopupMenuButton(
icon: const Icon(Icons.more_horiz_rounded),
itemBuilder: (context) {
return [
if (auth.isLoggedIn)
PopupMenuItem(
child: Row(
children: const [
Icon(Icons.add_box_rounded),
SizedBox(width: 10),
Text("Add to Playlist"),
],
),
value: "add-playlist",
),
if (userPlaylist && auth.isLoggedIn)
PopupMenuItem(
child: Row(
children: const [
Icon(Icons.remove_circle_outline_rounded),
SizedBox(width: 10),
Text("Remove from Playlist"),
],
),
value: "remove-playlist",
),
if (auth.isLoggedIn)
PopupMenuItem(
child: Row(
children: [
Icon(isSaved
? Icons.favorite_rounded
: Icons.favorite_border_rounded),
const SizedBox(width: 10),
const Text("Favorite")
],
),
value: "favorite",
),
PopupMenuItem(
child: Row(
children: const [
Icon(Icons.share_rounded),
SizedBox(width: 10),
Text("Share")
],
),
value: "share",
)
];
},
onSelected: (value) {
switch (value) {
case "favorite":
actionFavorite(isSaved);
break;
case "add-playlist":
actionAddToPlaylist();
break;
case "remove-playlist":
actionRemoveFromPlaylist();
break;
case "share":
actionShare(track.value);
break;
}
},
),
],
), ),
); );
} }

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:async/async.dart';
import 'package:audio_service/audio_service.dart'; import 'package:audio_service/audio_service.dart';
import 'package:audioplayers/audioplayers.dart'; import 'package:audioplayers/audioplayers.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
@ -227,6 +228,27 @@ class Playback extends PersistedChangeNotifier {
player.dispose(); player.dispose();
} }
Future<T> retryingOperation<T>(
Future<T> Function() inner, {
Duration? timeout,
}) async {
T result;
try {
final operation = CancelableOperation.fromFuture(inner());
result = await operation.value;
await Future.delayed(timeout ?? const Duration(seconds: 5), () async {
if (!operation.isCompleted) {
operation.cancel();
result = await inner();
}
});
return result;
} catch (e) {
result = await inner();
return result;
}
}
// playlist & track list methods // playlist & track list methods
Future<SpotubeTrack> toSpotubeTrack(Track track) async { Future<SpotubeTrack> toSpotubeTrack(Track track) async {
final format = preferences.ytSearchFormat; final format = preferences.ytSearchFormat;
@ -260,7 +282,8 @@ class Playback extends PersistedChangeNotifier {
); );
ytVideo = VideoFromCacheTrackExtension.fromCacheTrack(cachedTrack); ytVideo = VideoFromCacheTrackExtension.fromCacheTrack(cachedTrack);
} else { } else {
VideoSearchList videos = await youtube.search.search(queryString); VideoSearchList videos =
await retryingOperation(() => youtube.search.search(queryString));
if (matchAlgorithm != SpotubeTrackMatchAlgorithm.youtube) { if (matchAlgorithm != SpotubeTrackMatchAlgorithm.youtube) {
List<Map> ratedRankedVideos = videos List<Map> ratedRankedVideos = videos
.map((video) { .map((video) {
@ -310,7 +333,9 @@ class Playback extends PersistedChangeNotifier {
} }
} }
final trackManifest = await youtube.videos.streams.getManifest(ytVideo.id); StreamManifest trackManifest = await retryingOperation(
() => youtube.videos.streams.getManifest(ytVideo.id),
);
_logger.v( _logger.v(
"[YouTube Matched Track] ${ytVideo.title} | ${ytVideo.author} - ${ytVideo.url}", "[YouTube Matched Track] ${ytVideo.title} | ${ytVideo.author} - ${ytVideo.url}",

View File

@ -37,7 +37,7 @@ packages:
source: hosted source: hosted
version: "2.3.1" version: "2.3.1"
async: async:
dependency: transitive dependency: "direct main"
description: description:
name: async name: async
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"

View File

@ -64,6 +64,7 @@ dependencies:
dbus: ^0.7.3 dbus: ^0.7.3
audioplayers: ^1.0.1 audioplayers: ^1.0.1
resizable_widget: ^1.0.5 resizable_widget: ^1.0.5
async: ^2.8.2
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: