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: [
ChangeNotifierProvider(create: (_) => PlayerProvider()),
ChangeNotifierProvider(create: (_) => HomeProvider()),
ChangeNotifierProvider(create: (_) => DownloadProvider()),
],
child: MaterialApp(
title: 'Fipy',

View File

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

View File

@ -18,6 +18,7 @@ PlayerController? player;
Track? currentTrack;
List<Track> trackList = [];
String radio = 'groove';
int isDownloading = -1;
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key, required this.title}) : super(key: key);
@ -51,7 +52,7 @@ class _HomeScreenState extends State<HomeScreen> {
onChanged: (String? newRadio) {
setState(() {
radio = newRadio!;
getTracks(radio, hours);
// getTracks(radio, hours);
});
},
items: radioList),
@ -89,6 +90,11 @@ class _HomeScreenState extends State<HomeScreen> {
return const Text('Error');
} else if (snapshot.hasData) {
return Table(
columnWidths: {
0: const FlexColumnWidth(4),
1: const FlexColumnWidth(2),
2: const FlexColumnWidth(1),
},
defaultVerticalAlignment:
TableCellVerticalAlignment.middle,
children: snapshot.data!
@ -180,47 +186,106 @@ class _HomeScreenState extends State<HomeScreen> {
),
]),
),
IconButton(
icon: Icon(Icons.skip_previous,
color: Colors.grey[500], size: 32),
onPressed: () {
if (currentTrack != null && currentTrack!.number > 1) {
currentTrack = trackList.firstWhere((element) =>
element.number == currentTrack!.number - 1);
playTrack(context, currentTrack!);
}
}),
ElevatedButton(
onPressed: () {
player?.playing ?? false
? player?.pause()
: player?.play();
playerProvider.reload();
},
child: Icon(
player?.playing ?? false
? Icons.pause
: Icons.play_arrow,
color: Colors.grey[900],
size: 32),
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
padding: const EdgeInsets.all(12),
primary: Colors.grey[300],
onPrimary: Colors.grey[900],
),
),
IconButton(
icon: Icon(Icons.skip_next,
color: Colors.grey[500], size: 32),
onPressed: () {
if (currentTrack != null &&
currentTrack!.number < trackList.last.number) {
currentTrack = trackList.firstWhere((element) =>
element.number == currentTrack!.number + 1);
playTrack(context, currentTrack!);
}
}),
Column(children: [
const Spacer(),
Row(children: [
Column(children: [
IconButton(
icon: Icon(Icons.skip_previous,
color: Colors.grey[500], size: 32),
onPressed: () {
if (currentTrack != null &&
currentTrack!.number > 1) {
currentTrack = trackList.firstWhere((element) =>
element.number == currentTrack!.number - 1);
playTrack(context, currentTrack!);
}
}),
const SizedBox(height: 7),
]),
const SizedBox(width: 8),
ElevatedButton(
onPressed: () {
player?.playing ?? false
? player?.pause()
: player?.play();
playerProvider.reload();
},
child: Icon(
player?.playing ?? false
? Icons.pause
: Icons.play_arrow,
color: Colors.grey[900],
size: 30),
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
padding: const EdgeInsets.all(12),
primary: Colors.grey[300],
onPrimary: Colors.grey[900],
),
),
Column(children: [
IconButton(
icon: Icon(Icons.skip_next,
color: Colors.grey[500], size: 32),
onPressed: () {
if (currentTrack != null &&
currentTrack!.number <
trackList.last.number) {
currentTrack = trackList.firstWhere((element) =>
element.number == currentTrack!.number + 1);
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(),
SliderTheme(
data: const SliderThemeData(
@ -339,8 +404,8 @@ Future<List<Track>> getTracks(String radio, int hours) async {
int trackNbr = 0;
trackList.clear();
final yt = YoutubeExplode();
List resultUrlPool = [];
// final yt = YoutubeExplode();
// List resultUrlPool = [];
for (Map track in data) {
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);
trackList.add(thisTrack);
final secondMatch = artiste == '' ? album : artiste;
final resultUrl = yt.search.search(title + ' ' + secondMatch);
// final secondMatch = artiste == '' ? album : artiste;
// final resultUrl = yt.search.search(title + ' ' + secondMatch);
resultUrlPool.add(resultUrl);
// resultUrlPool.add(resultUrl);
resultUrl.then((value) {
try {
trackList[trackNbr - 1].id = value.first.id.value;
} catch (e) {
print(
'Error: ' + trackList[trackNbr - 1].title + ' -> ' + e.toString());
}
});
// resultUrl.then((value) {
// try {
// trackList[trackNbr - 1].id = value.first.id.value;
// } catch (e) {
// print(
// '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 =
trackList[0].artiste == '' ? trackList[0].album : trackList[0].artiste;
yt.search.search(trackList[0].title + ' ' + secondMatch!).then((resultUrl) {
trackList[0].id = resultUrl.first.id.value;
// final secondMatch =
// trackList[0].artiste == '' ? trackList[0].album : trackList[0].artiste;
// yt.search.search(trackList[0].title + ' ' + secondMatch!).then((resultUrl) {
// trackList[0].id = resultUrl.first.id.value;
player = Player.network(
"https://invidious.fdn.fr/embed/${trackList[0].id}?raw=1&?listen=1");
currentTrack = trackList[0];
});
// player = Player.network(
// "https://invidious.fdn.fr/embed/${trackList[0].id}?raw=1&?listen=1");
// currentTrack = trackList[0];
// });
return trackList;
}
TableRow _buildTableRow(Track track, BuildContext context) {
DownloadProvider downloadProvider =
Provider.of<DownloadProvider>(context, listen: false);
final textStyle = TextStyle(
fontWeight: track.number == -1 ? FontWeight.w200 : FontWeight.normal,
color: Colors.grey[500],
@ -442,25 +510,45 @@ TableRow _buildTableRow(Track track, BuildContext context) {
child: Padding(
padding: rowPadding,
child: InkWell(
onTap: () async {
if (track.id == null) {
final secondMatch =
track.artiste == '' ? track.album : track.artiste;
final resultUrl = await yt.search
.search(track.title + ' ' + secondMatch!);
track.id = resultUrl.first.id.value;
}
if (track.id != null) {
final response = await http.get(Uri.parse(
'https://ytdl.p2p.legal/ytdl.sh?${track.id}'));
final dlLink = response.body;
if (await canLaunchUrl(Uri.parse(dlLink))) {
launchUrl(Uri.parse(dlLink));
onTap: () async {
isDownloading = track.number;
downloadProvider.reload();
if (track.id == null) {
final secondMatch =
track.artiste == '' ? track.album : track.artiste;
final resultUrl = await yt.search
.search(track.title + ' ' + secondMatch!);
track.id = resultUrl.first.id.value;
}
}
},
child: Text('TÉLÉCHARGER', style: textStyle),
)),
if (track.id != null) {
final response = await http.get(Uri.parse(
'https://ytdl.p2p.legal/ytdl.sh?${track.id}'));
final dlLink = response.body;
if (await canLaunchUrl(Uri.parse(dlLink))) {
launchUrl(Uri.parse(dlLink));
}
}
isDownloading = -1;
downloadProvider.reload();
},
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);
track = trackList[track.number - 1];
currentTrack = track;
if (track.id == null) {
final secondMatch = track.artiste == '' ? track.album : track.artiste;
final resultUrl = await yt.search.search(track.title + ' ' + secondMatch!);
track.id = resultUrl.first.id.value;
}
final currentVolume = player?.volume ?? 1;
player?.dispose();
Future.delayed(const Duration(milliseconds: 5));
player = Player.network(
"https://invidious.fdn.fr/embed/${track.id}?raw=1&?listen=1");
print(track.id);
player!.volume = currentVolume;
try {
player!.play();
} catch (e) {
print('Play error: ' + e.toString());
}
Future.delayed(const Duration(milliseconds: 50));
Future.delayed(const Duration(milliseconds: 500));
player!.callback = (PlayerEvent event) {
if (event.name == 'position') {
currentTrack!.duration = player!.duration;
playerProvider.reload();
}
if (event.name == 'status') {
var nextTrack =
trackList.firstWhere((element) => element.number == track.number + 1);
playTrack(context, nextTrack);
}
};
currentTrack = track;
playerProvider.reload();
homeProvider.reload();
}
@ -528,3 +622,10 @@ List<DropdownMenuItem<String>> get radioList {
];
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';
}