Imrove startup; Fix layouts; Add time slider;

This commit is contained in:
poka 2022-04-29 12:18:26 +02:00
parent 9fefb780d1
commit 6e39b5435a
3 changed files with 192 additions and 84 deletions

View File

@ -25,6 +25,7 @@ class FipyApp extends StatelessWidget {
providers: [ providers: [
ChangeNotifierProvider(create: (_) => PlayerProvider()), ChangeNotifierProvider(create: (_) => PlayerProvider()),
ChangeNotifierProvider(create: (_) => HomeProvider()), ChangeNotifierProvider(create: (_) => HomeProvider()),
ChangeNotifierProvider(create: (_) => DownloadProvider()),
], ],
child: MaterialApp( child: MaterialApp(
title: 'Fipy', title: 'Fipy',

View File

@ -5,3 +5,9 @@ class HomeProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
} }
class DownloadProvider with ChangeNotifier {
void reload() {
notifyListeners();
}
}

View File

@ -18,6 +18,7 @@ PlayerController? player;
Track? currentTrack; Track? currentTrack;
List<Track> trackList = []; List<Track> trackList = [];
String radio = 'groove'; String radio = 'groove';
int isDownloading = -1;
class HomeScreen extends StatefulWidget { class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key, required this.title}) : super(key: key); const HomeScreen({Key? key, required this.title}) : super(key: key);
@ -51,7 +52,7 @@ class _HomeScreenState extends State<HomeScreen> {
onChanged: (String? newRadio) { onChanged: (String? newRadio) {
setState(() { setState(() {
radio = newRadio!; radio = newRadio!;
getTracks(radio, hours); // getTracks(radio, hours);
}); });
}, },
items: radioList), items: radioList),
@ -89,6 +90,11 @@ class _HomeScreenState extends State<HomeScreen> {
return const Text('Error'); return const Text('Error');
} else if (snapshot.hasData) { } else if (snapshot.hasData) {
return Table( return Table(
columnWidths: {
0: const FlexColumnWidth(4),
1: const FlexColumnWidth(2),
2: const FlexColumnWidth(1),
},
defaultVerticalAlignment: defaultVerticalAlignment:
TableCellVerticalAlignment.middle, TableCellVerticalAlignment.middle,
children: snapshot.data! children: snapshot.data!
@ -180,16 +186,24 @@ class _HomeScreenState extends State<HomeScreen> {
), ),
]), ]),
), ),
Column(children: [
const Spacer(),
Row(children: [
Column(children: [
IconButton( IconButton(
icon: Icon(Icons.skip_previous, icon: Icon(Icons.skip_previous,
color: Colors.grey[500], size: 32), color: Colors.grey[500], size: 32),
onPressed: () { onPressed: () {
if (currentTrack != null && currentTrack!.number > 1) { if (currentTrack != null &&
currentTrack!.number > 1) {
currentTrack = trackList.firstWhere((element) => currentTrack = trackList.firstWhere((element) =>
element.number == currentTrack!.number - 1); element.number == currentTrack!.number - 1);
playTrack(context, currentTrack!); playTrack(context, currentTrack!);
} }
}), }),
const SizedBox(height: 7),
]),
const SizedBox(width: 8),
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
player?.playing ?? false player?.playing ?? false
@ -202,7 +216,7 @@ class _HomeScreenState extends State<HomeScreen> {
? Icons.pause ? Icons.pause
: Icons.play_arrow, : Icons.play_arrow,
color: Colors.grey[900], color: Colors.grey[900],
size: 32), size: 30),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
shape: const CircleBorder(), shape: const CircleBorder(),
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
@ -210,17 +224,68 @@ class _HomeScreenState extends State<HomeScreen> {
onPrimary: Colors.grey[900], onPrimary: Colors.grey[900],
), ),
), ),
Column(children: [
IconButton( IconButton(
icon: Icon(Icons.skip_next, icon: Icon(Icons.skip_next,
color: Colors.grey[500], size: 32), color: Colors.grey[500], size: 32),
onPressed: () { onPressed: () {
if (currentTrack != null && if (currentTrack != null &&
currentTrack!.number < trackList.last.number) { currentTrack!.number <
trackList.last.number) {
currentTrack = trackList.firstWhere((element) => currentTrack = trackList.firstWhere((element) =>
element.number == currentTrack!.number + 1); element.number == currentTrack!.number + 1);
playTrack(context, currentTrack!); playTrack(context, currentTrack!);
} }
}), }),
const SizedBox(height: 7),
]),
]),
const Spacer(),
Row(children: [
Text(
timeFormat(
player?.position ?? const Duration(seconds: 0)),
style: TextStyle(color: Colors.grey[500], fontSize: 12),
),
const SizedBox(width: 3),
SliderTheme(
data: const SliderThemeData(
thumbShape:
RoundSliderThumbShape(enabledThumbRadius: 2),
overlayShape:
RoundSliderThumbShape(enabledThumbRadius: 5),
trackHeight: 2,
),
child: SizedBox(
width: 300,
child: Slider(
value: double.parse(
player?.position.inSeconds.toString() ?? '0'),
max: double.parse(
player?.duration.inSeconds.toString() ??
'2000'),
onChanged: (double value) {
print(value);
if (player?.position != null) {
player!.position =
Duration(seconds: value.toInt());
playerProvider.reload();
}
},
activeColor: Colors.grey[400],
inactiveColor: Colors.grey[700],
),
),
),
const SizedBox(width: 3),
Text(
timeFormat(
player?.duration ?? const Duration(seconds: 0)),
style: TextStyle(color: Colors.grey[500], fontSize: 12),
),
]),
const Spacer(),
]),
const Spacer(), const Spacer(),
SliderTheme( SliderTheme(
data: const SliderThemeData( data: const SliderThemeData(
@ -339,8 +404,8 @@ Future<List<Track>> getTracks(String radio, int hours) async {
int trackNbr = 0; int trackNbr = 0;
trackList.clear(); trackList.clear();
final yt = YoutubeExplode(); // final yt = YoutubeExplode();
List resultUrlPool = []; // List resultUrlPool = [];
for (Map track in data) { for (Map track in data) {
track = track['track']; track = track['track'];
@ -358,36 +423,39 @@ Future<List<Track>> getTracks(String radio, int hours) async {
Track(number: trackNbr, title: title, artiste: artiste, album: album); Track(number: trackNbr, title: title, artiste: artiste, album: album);
trackList.add(thisTrack); trackList.add(thisTrack);
final secondMatch = artiste == '' ? album : artiste; // final secondMatch = artiste == '' ? album : artiste;
final resultUrl = yt.search.search(title + ' ' + secondMatch); // final resultUrl = yt.search.search(title + ' ' + secondMatch);
resultUrlPool.add(resultUrl); // resultUrlPool.add(resultUrl);
resultUrl.then((value) { // resultUrl.then((value) {
try { // try {
trackList[trackNbr - 1].id = value.first.id.value; // trackList[trackNbr - 1].id = value.first.id.value;
} catch (e) { // } catch (e) {
print( // print(
'Error: ' + trackList[trackNbr - 1].title + ' -> ' + e.toString()); // 'Error: ' + trackList[trackNbr - 1].title + ' -> ' + e.toString());
} // }
}); // });
} }
trackList.sort((a, b) => a.number.compareTo(b.number)); // trackList.sort((a, b) => a.number.compareTo(b.number));
final secondMatch = // final secondMatch =
trackList[0].artiste == '' ? trackList[0].album : trackList[0].artiste; // trackList[0].artiste == '' ? trackList[0].album : trackList[0].artiste;
yt.search.search(trackList[0].title + ' ' + secondMatch!).then((resultUrl) { // yt.search.search(trackList[0].title + ' ' + secondMatch!).then((resultUrl) {
trackList[0].id = resultUrl.first.id.value; // trackList[0].id = resultUrl.first.id.value;
player = Player.network( // player = Player.network(
"https://invidious.fdn.fr/embed/${trackList[0].id}?raw=1&?listen=1"); // "https://invidious.fdn.fr/embed/${trackList[0].id}?raw=1&?listen=1");
currentTrack = trackList[0]; // currentTrack = trackList[0];
}); // });
return trackList; return trackList;
} }
TableRow _buildTableRow(Track track, BuildContext context) { TableRow _buildTableRow(Track track, BuildContext context) {
DownloadProvider downloadProvider =
Provider.of<DownloadProvider>(context, listen: false);
final textStyle = TextStyle( final textStyle = TextStyle(
fontWeight: track.number == -1 ? FontWeight.w200 : FontWeight.normal, fontWeight: track.number == -1 ? FontWeight.w200 : FontWeight.normal,
color: Colors.grey[500], color: Colors.grey[500],
@ -443,6 +511,8 @@ TableRow _buildTableRow(Track track, BuildContext context) {
padding: rowPadding, padding: rowPadding,
child: InkWell( child: InkWell(
onTap: () async { onTap: () async {
isDownloading = track.number;
downloadProvider.reload();
if (track.id == null) { if (track.id == null) {
final secondMatch = final secondMatch =
track.artiste == '' ? track.album : track.artiste; track.artiste == '' ? track.album : track.artiste;
@ -458,9 +528,27 @@ TableRow _buildTableRow(Track track, BuildContext context) {
launchUrl(Uri.parse(dlLink)); launchUrl(Uri.parse(dlLink));
} }
} }
isDownloading = -1;
downloadProvider.reload();
}, },
child: Text('TÉLÉCHARGER', style: textStyle), child: track.number == -1
)), ? Text('TÉLÉCHARGER', style: textStyle)
: Consumer<DownloadProvider>(
builder: (context, playerProvider, _) {
return Row(children: [
const SizedBox(width: 37),
isDownloading == track.number
? SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
color: Colors.grey[500],
),
)
: Icon(Icons.download, color: Colors.grey[500]),
]);
}))),
), ),
]); ]);
} }
@ -472,32 +560,38 @@ Future playTrack(BuildContext context, Track track) async {
HomeProvider homeProvider = Provider.of<HomeProvider>(context, listen: false); HomeProvider homeProvider = Provider.of<HomeProvider>(context, listen: false);
track = trackList[track.number - 1]; track = trackList[track.number - 1];
currentTrack = track;
if (track.id == null) { if (track.id == null) {
final secondMatch = track.artiste == '' ? track.album : track.artiste; final secondMatch = track.artiste == '' ? track.album : track.artiste;
final resultUrl = await yt.search.search(track.title + ' ' + secondMatch!); final resultUrl = await yt.search.search(track.title + ' ' + secondMatch!);
track.id = resultUrl.first.id.value; track.id = resultUrl.first.id.value;
} }
final currentVolume = player?.volume ?? 1;
player?.dispose(); player?.dispose();
Future.delayed(const Duration(milliseconds: 5)); Future.delayed(const Duration(milliseconds: 5));
player = Player.network( player = Player.network(
"https://invidious.fdn.fr/embed/${track.id}?raw=1&?listen=1"); "https://invidious.fdn.fr/embed/${track.id}?raw=1&?listen=1");
print(track.id); print(track.id);
player!.volume = currentVolume;
try { try {
player!.play(); player!.play();
} catch (e) { } catch (e) {
print('Play error: ' + e.toString()); print('Play error: ' + e.toString());
} }
Future.delayed(const Duration(milliseconds: 50)); Future.delayed(const Duration(milliseconds: 500));
player!.callback = (PlayerEvent event) { player!.callback = (PlayerEvent event) {
if (event.name == 'position') {
currentTrack!.duration = player!.duration;
playerProvider.reload();
}
if (event.name == 'status') { if (event.name == 'status') {
var nextTrack = var nextTrack =
trackList.firstWhere((element) => element.number == track.number + 1); trackList.firstWhere((element) => element.number == track.number + 1);
playTrack(context, nextTrack); playTrack(context, nextTrack);
} }
}; };
currentTrack = track;
playerProvider.reload(); playerProvider.reload();
homeProvider.reload(); homeProvider.reload();
} }
@ -528,3 +622,10 @@ List<DropdownMenuItem<String>> get radioList {
]; ];
return menuItems; return menuItems;
} }
String timeFormat(Duration d) {
String dd = d.toString().split('.').first;
String minutes = dd.toString().split(':')[1];
String seconds = dd.toString().split(':')[2];
return '$minutes:$seconds';
}