Imrove startup; Fix layouts; Add time slider;
This commit is contained in:
parent
9fefb780d1
commit
6e39b5435a
|
@ -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',
|
||||||
|
|
|
@ -5,3 +5,9 @@ class HomeProvider with ChangeNotifier {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DownloadProvider with ChangeNotifier {
|
||||||
|
void reload() {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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';
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue