refacto: cut widgets
This commit is contained in:
parent
422aaefbac
commit
60c4a1f68d
|
@ -5,6 +5,10 @@ import 'package:logger/logger.dart';
|
|||
TextStyle globalTextStyle = TextStyle(color: Colors.grey[350]);
|
||||
const proxyHeader =
|
||||
kDebugMode || !kIsWeb ? 'https://' : 'http://127.0.0.1:8080/';
|
||||
|
||||
|
||||
// Logger
|
||||
final log = Logger();
|
||||
final log = Logger();
|
||||
|
||||
// context
|
||||
late BuildContext homeContext;
|
||||
late BuildContext playerContext;
|
||||
|
|
|
@ -18,12 +18,12 @@ class FipyApp extends StatelessWidget {
|
|||
providers: [
|
||||
ChangeNotifierProvider(create: (_) => PlayerProvider()),
|
||||
ChangeNotifierProvider(create: (_) => HomeProvider()),
|
||||
ChangeNotifierProvider(create: (_) => DownloadProvider()),
|
||||
],
|
||||
child: MaterialApp(
|
||||
title: 'Fipy',
|
||||
theme: ThemeData(
|
||||
colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.blue).copyWith(background: Colors.grey[900])),
|
||||
colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.blue)
|
||||
.copyWith(background: Colors.grey[900])),
|
||||
home: const HomeScreen(title: 'Fipy'),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// ignore_for_file: avoid_print
|
||||
// ignore_for_file: avoid_print, use_build_context_synchronously
|
||||
|
||||
import 'dart:convert';
|
||||
import 'package:fipy/globals.dart';
|
||||
|
@ -36,6 +36,7 @@ class HomeProvider with ChangeNotifier {
|
|||
"Access-Control-Allow-Methods": "GET, HEAD, POST, OPTIONS",
|
||||
'Content-Type': 'text/plain'
|
||||
});
|
||||
|
||||
if (res.statusCode == 200) {
|
||||
Map body = jsonDecode(res.body);
|
||||
if (body['next'] != null) {
|
||||
|
@ -70,12 +71,12 @@ class HomeProvider with ChangeNotifier {
|
|||
return trackList;
|
||||
}
|
||||
|
||||
Future playTrack(BuildContext context, Track track) async {
|
||||
Future playTrack(Track track) async {
|
||||
var yt = YoutubeExplode();
|
||||
PlayerProvider playerProvider =
|
||||
Provider.of<PlayerProvider>(context, listen: false);
|
||||
Provider.of<PlayerProvider>(homeContext, listen: false);
|
||||
HomeProvider homeProvider =
|
||||
Provider.of<HomeProvider>(context, listen: false);
|
||||
Provider.of<HomeProvider>(homeContext, listen: false);
|
||||
|
||||
// track = trackList[track.number - 1];
|
||||
currentTrack = track;
|
||||
|
@ -120,7 +121,7 @@ class HomeProvider with ChangeNotifier {
|
|||
var nextTrack =
|
||||
trackList.firstWhere((element) => element.number == track.number + 1);
|
||||
currentTrack = nextTrack;
|
||||
playTrack(context, nextTrack);
|
||||
playTrack(nextTrack);
|
||||
});
|
||||
|
||||
playerProvider.reload();
|
||||
|
@ -162,6 +163,14 @@ class HomeProvider with ChangeNotifier {
|
|||
|
||||
track.file = file;
|
||||
|
||||
notifyListeners();
|
||||
ScaffoldMessenger.of(playerContext).showSnackBar(
|
||||
SnackBar(
|
||||
content:
|
||||
SizedBox(height: 90, child: Text('Son téléchargé: ${file.path}')),
|
||||
),
|
||||
);
|
||||
|
||||
print(file.path);
|
||||
}
|
||||
}
|
||||
|
@ -197,34 +206,3 @@ class HomeProvider with ChangeNotifier {
|
|||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
class DownloadProvider with ChangeNotifier {
|
||||
void reload() {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// Future convertToMp3(String audioFile) async {
|
||||
// audioFile = 'E:\\Téléchargements/test.webm';
|
||||
// final command = FfmpegCommand(
|
||||
// inputs: [FfmpegInput.asset(audioFile)],
|
||||
// args: [
|
||||
// // CliArg(name: 'i', value: audioFile),
|
||||
// const CliArg(name: 'ab', value: '320'),
|
||||
// const CliArg(name: 'ar', value: '44100'),
|
||||
// ],
|
||||
// filterGraph: const FilterGraph(
|
||||
// chains: [
|
||||
// FilterChain(
|
||||
// inputs: [],
|
||||
// filters: [],
|
||||
// outputs: [],
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// outputFilepath: "E:\\Téléchargements/test.mp3",
|
||||
// );
|
||||
|
||||
// // Execute command
|
||||
// await Ffmpeg().run(command);
|
||||
// }
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
// ignore_for_file: prefer_const_literals_to_create_immutables, avoid_print
|
||||
|
||||
import 'dart:convert';
|
||||
import 'package:fipy/globals.dart';
|
||||
import 'package:fipy/models/track.dart';
|
||||
import 'package:fipy/providers/home.dart';
|
||||
import 'package:fipy/providers/player.dart';
|
||||
import 'package:fipy/widgets/download_track.dart';
|
||||
import 'package:fipy/widgets/player/player.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:miniplayer/miniplayer.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:youtube_explode_dart/youtube_explode_dart.dart';
|
||||
// import 'dart:math';
|
||||
// import 'package:flutter/rendering.dart';
|
||||
|
||||
class HomeScreen extends StatefulWidget {
|
||||
const HomeScreen({Key? key, required this.title}) : super(key: key);
|
||||
|
@ -24,8 +23,8 @@ class _HomeScreenState extends State<HomeScreen> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
homeContext = context;
|
||||
HomeProvider hp = Provider.of<HomeProvider>(context, listen: false);
|
||||
final MiniplayerController controller = MiniplayerController();
|
||||
|
||||
return RawKeyboardListener(
|
||||
autofocus: true,
|
||||
|
@ -42,8 +41,8 @@ class _HomeScreenState extends State<HomeScreen> {
|
|||
child: Stack(
|
||||
children: <Widget>[
|
||||
Scaffold(
|
||||
backgroundColor: Colors.black,
|
||||
body: SingleChildScrollView(
|
||||
// controller: AdjustableScrollController(40),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
|
@ -135,18 +134,16 @@ class _HomeScreenState extends State<HomeScreen> {
|
|||
defaultVerticalAlignment:
|
||||
TableCellVerticalAlignment.middle,
|
||||
children: snapshot.data!
|
||||
.map((item) => _buildTableRow(item, context))
|
||||
.map((item) => _buildTableRow(item))
|
||||
.toList()
|
||||
..insert(
|
||||
0,
|
||||
_buildTableRow(
|
||||
Track(
|
||||
number: -1,
|
||||
title: 'TITRE',
|
||||
artiste: 'ARTISTE',
|
||||
album: 'ALBUM',
|
||||
id: 'URL'),
|
||||
context),
|
||||
_buildTableRow(Track(
|
||||
number: -1,
|
||||
title: 'TITRE',
|
||||
artiste: 'ARTISTE',
|
||||
album: 'ALBUM',
|
||||
id: 'URL')),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
|
@ -162,263 +159,21 @@ class _HomeScreenState extends State<HomeScreen> {
|
|||
),
|
||||
),
|
||||
),
|
||||
Consumer<PlayerProvider>(builder: (context, playerProvider, _) {
|
||||
TextEditingController trackTitle = TextEditingController();
|
||||
TextEditingController trackArtiste = TextEditingController();
|
||||
trackTitle.text = hp.currentTrack?.title ?? '';
|
||||
trackArtiste.text = hp.currentTrack?.artiste ?? '';
|
||||
|
||||
// if ((hp.currentTrack?.duration?.inSeconds ?? -1) <= 0) {
|
||||
// return const Text('attenddssss !!');
|
||||
// }
|
||||
return Miniplayer(
|
||||
controller: controller,
|
||||
backgroundColor: Colors.grey[900]!,
|
||||
minHeight: 70,
|
||||
maxHeight: 70,
|
||||
builder: (height, percentage) {
|
||||
return Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
hp.currentTrack?.imageUrl != '' &&
|
||||
hp.currentTrack?.imageUrl != null
|
||||
? Image.network(
|
||||
hp.currentTrack!.imageUrl!,
|
||||
width: 70,
|
||||
)
|
||||
: const SizedBox(width: 70),
|
||||
Expanded(
|
||||
child: Column(children: [
|
||||
SizedBox(
|
||||
height: 20,
|
||||
child: TextField(
|
||||
enabled: false,
|
||||
maxLines: 1,
|
||||
controller: trackTitle,
|
||||
decoration: const InputDecoration(
|
||||
border: InputBorder.none,
|
||||
focusedBorder: InputBorder.none,
|
||||
enabledBorder: InputBorder.none,
|
||||
disabledBorder: InputBorder.none,
|
||||
contentPadding: EdgeInsets.only(left: 15),
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey[300],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
child: TextField(
|
||||
enabled: false,
|
||||
maxLines: 1,
|
||||
controller: trackArtiste,
|
||||
decoration: const InputDecoration(
|
||||
border: InputBorder.none,
|
||||
focusedBorder: InputBorder.none,
|
||||
enabledBorder: InputBorder.none,
|
||||
disabledBorder: InputBorder.none,
|
||||
contentPadding: EdgeInsets.only(left: 15),
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey[500],
|
||||
),
|
||||
),
|
||||
),
|
||||
]),
|
||||
),
|
||||
Column(children: [
|
||||
const Spacer(),
|
||||
Row(children: [
|
||||
const SizedBox(width: 70),
|
||||
Column(children: [
|
||||
IconButton(
|
||||
padding: const EdgeInsets.all(0),
|
||||
icon: Icon(Icons.skip_previous,
|
||||
color: Colors.grey[500], size: 32),
|
||||
onPressed: () {
|
||||
if (hp.currentTrack != null &&
|
||||
hp.currentTrack!.number > 1) {
|
||||
hp.currentTrack = hp.trackList.firstWhere(
|
||||
(element) =>
|
||||
element.number ==
|
||||
hp.currentTrack!.number - 1);
|
||||
hp.playTrack(context, hp.currentTrack!);
|
||||
}
|
||||
}),
|
||||
]),
|
||||
const SizedBox(width: 1),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
hp.player.state.name == 'playing'
|
||||
? hp.player.pause()
|
||||
: hp.player.resume();
|
||||
|
||||
// playerProvider.reload();
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
foregroundColor: Colors.grey[900],
|
||||
backgroundColor: Colors.grey[300],
|
||||
shape: const CircleBorder(),
|
||||
padding: const EdgeInsets.all(12),
|
||||
),
|
||||
child: Icon(
|
||||
hp.player.state.name == 'playing'
|
||||
? Icons.pause
|
||||
: Icons.play_arrow,
|
||||
color: Colors.grey[900],
|
||||
size: 30),
|
||||
),
|
||||
Column(children: [
|
||||
IconButton(
|
||||
padding: const EdgeInsets.all(0),
|
||||
icon: Icon(Icons.skip_next,
|
||||
color: Colors.grey[500], size: 32),
|
||||
onPressed: () {
|
||||
if (hp.currentTrack != null &&
|
||||
hp.currentTrack!.number <
|
||||
hp.trackList.last.number) {
|
||||
hp.currentTrack = hp.trackList.firstWhere(
|
||||
(element) =>
|
||||
element.number ==
|
||||
hp.currentTrack!.number + 1);
|
||||
hp.playTrack(context, hp.currentTrack!);
|
||||
}
|
||||
}),
|
||||
// const SizedBox(height: 7),
|
||||
]),
|
||||
]),
|
||||
const Spacer(),
|
||||
Row(children: [
|
||||
const SizedBox(width: 70),
|
||||
Text(
|
||||
timeFormat(hp.currentTrack?.position ??
|
||||
const Duration(seconds: 0)),
|
||||
style:
|
||||
TextStyle(color: Colors.grey[500], fontSize: 12),
|
||||
),
|
||||
const SizedBox(width: 3),
|
||||
(hp.currentTrack?.duration?.inSeconds ?? -1) <= 0
|
||||
? Column(
|
||||
children: [
|
||||
const SizedBox(width: 300),
|
||||
hp.currentTrack?.title == null
|
||||
? Text(
|
||||
'Choisissez un titre',
|
||||
style: TextStyle(
|
||||
color: Colors.grey[500]),
|
||||
)
|
||||
: const SizedBox(
|
||||
height: 15,
|
||||
width: 15,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: Colors.orange,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: SliderTheme(
|
||||
data: const SliderThemeData(
|
||||
thumbShape: RoundSliderThumbShape(
|
||||
enabledThumbRadius: 2),
|
||||
overlayShape: RoundSliderThumbShape(
|
||||
enabledThumbRadius: 5),
|
||||
trackHeight: 2,
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 300,
|
||||
child: Slider(
|
||||
value: double.parse(hp
|
||||
.currentTrack?.position?.inSeconds
|
||||
.toString() ??
|
||||
'0'),
|
||||
max: double.parse(hp
|
||||
.currentTrack?.duration?.inSeconds
|
||||
.toString() ??
|
||||
'2000'),
|
||||
onChanged: (double value) {
|
||||
if (hp.currentTrack?.position != null) {
|
||||
hp.player.seek(
|
||||
Duration(seconds: value.toInt()),
|
||||
);
|
||||
playerProvider.reload();
|
||||
}
|
||||
},
|
||||
activeColor: Colors.grey[400],
|
||||
inactiveColor: Colors.grey[700],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 3),
|
||||
Text(
|
||||
timeFormat(hp.currentTrack?.duration ??
|
||||
const Duration(seconds: 0)),
|
||||
style:
|
||||
TextStyle(color: Colors.grey[500], fontSize: 12),
|
||||
),
|
||||
]),
|
||||
const Spacer(),
|
||||
]),
|
||||
const Spacer(),
|
||||
SliderTheme(
|
||||
data: const SliderThemeData(
|
||||
thumbShape:
|
||||
RoundSliderThumbShape(enabledThumbRadius: 7),
|
||||
overlayShape:
|
||||
RoundSliderThumbShape(enabledThumbRadius: 8),
|
||||
trackHeight: 2.5,
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 130,
|
||||
child: Slider(
|
||||
value: hp.currentVolume,
|
||||
max: 1,
|
||||
onChanged: (double value) async {
|
||||
hp.currentVolume = value;
|
||||
await hp.player.setVolume(value);
|
||||
playerProvider.reload();
|
||||
},
|
||||
activeColor: Colors.grey[400],
|
||||
inactiveColor: Colors.grey[700],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 20)
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
})
|
||||
const Player()
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget trackLine(Track track) {
|
||||
return SizedBox(
|
||||
height: 30,
|
||||
child: Row(
|
||||
children: [Text('${track.title} - ${track.artiste}')],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
TableRow _buildTableRow(Track track, BuildContext context) {
|
||||
DownloadProvider downloadProvider =
|
||||
Provider.of<DownloadProvider>(context, listen: false);
|
||||
HomeProvider hp = Provider.of<HomeProvider>(context, listen: false);
|
||||
int isDownloading = -1;
|
||||
TableRow _buildTableRow(Track track) {
|
||||
final hp = Provider.of<HomeProvider>(homeContext, listen: false);
|
||||
|
||||
final textStyle = TextStyle(
|
||||
fontWeight: track.number == -1 ? FontWeight.w200 : FontWeight.normal,
|
||||
color: Colors.grey[500],
|
||||
fontSize: track.number == -1 ? 15 : 14);
|
||||
const rowPadding = EdgeInsets.all(10);
|
||||
final yt = YoutubeExplode();
|
||||
|
||||
return TableRow(
|
||||
decoration: const BoxDecoration(
|
||||
|
@ -431,16 +186,7 @@ TableRow _buildTableRow(Track track, BuildContext context) {
|
|||
child: InkWell(
|
||||
onTap: () async {
|
||||
if (track.number != -1) {
|
||||
// FutureBuilder<void>(
|
||||
// future: hp.playTrack(context, track),
|
||||
// builder: (
|
||||
// BuildContext context,
|
||||
// AsyncSnapshot<void> snapshot,
|
||||
// ) {
|
||||
// return const SizedBox();
|
||||
// },
|
||||
// );
|
||||
hp.playTrack(context, track);
|
||||
hp.playTrack(track);
|
||||
}
|
||||
},
|
||||
child: Row(children: [
|
||||
|
@ -485,70 +231,9 @@ TableRow _buildTableRow(Track track, BuildContext context) {
|
|||
),
|
||||
TableCell(
|
||||
child: Padding(
|
||||
padding: rowPadding,
|
||||
child: InkWell(
|
||||
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;
|
||||
}
|
||||
if (track.id != null) {
|
||||
// ignore: use_build_context_synchronously
|
||||
hp.downloadMusic(context, track);
|
||||
}
|
||||
isDownloading = -1;
|
||||
yt.close();
|
||||
downloadProvider.reload();
|
||||
},
|
||||
child: track.number == -1
|
||||
? Text('TÉLÉCHARGER', style: textStyle)
|
||||
: Consumer<DownloadProvider>(builder: (context, _, __) {
|
||||
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]),
|
||||
]);
|
||||
}))),
|
||||
padding: rowPadding,
|
||||
child: DownloadTrack(track: track),
|
||||
),
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
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';
|
||||
}
|
||||
|
||||
// class AdjustableScrollController extends ScrollController {
|
||||
// AdjustableScrollController([int extraScrollSpeed = 40]) {
|
||||
// // super.initialScrollOffset = 50;
|
||||
// super.addListener(() {
|
||||
// ScrollDirection scrollDirection = super.position.userScrollDirection;
|
||||
// if (scrollDirection != ScrollDirection.idle) {
|
||||
// double scrollEnd = super.offset +
|
||||
// (scrollDirection == ScrollDirection.reverse
|
||||
// ? extraScrollSpeed
|
||||
// : -extraScrollSpeed);
|
||||
// scrollEnd = min(super.position.maxScrollExtent,
|
||||
// max(super.position.minScrollExtent, scrollEnd));
|
||||
// WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
// if (super.hasClients) jumpTo(scrollEnd);
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
import 'package:fipy/globals.dart';
|
||||
import 'package:fipy/models/track.dart';
|
||||
import 'package:fipy/providers/home.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:youtube_explode_dart/youtube_explode_dart.dart';
|
||||
|
||||
class DownloadTrack extends StatelessWidget {
|
||||
const DownloadTrack({Key? key, this.track}) : super(key: key);
|
||||
|
||||
final Track? track;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final hp = Provider.of<HomeProvider>(context, listen: false);
|
||||
int isDownloading = -1;
|
||||
final yt = YoutubeExplode();
|
||||
|
||||
final track = this.track ??
|
||||
hp.currentTrack ??
|
||||
Track(number: -1, title: 'title', artiste: 'artiste');
|
||||
|
||||
return Visibility(
|
||||
visible: track.number != -1,
|
||||
child: InkWell(onTap: () async {
|
||||
isDownloading = track.number;
|
||||
hp.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;
|
||||
}
|
||||
if (track.id != null) {
|
||||
// ignore: use_build_context_synchronously
|
||||
hp.downloadMusic(context, track);
|
||||
}
|
||||
isDownloading = -1;
|
||||
yt.close();
|
||||
// hp.reload();
|
||||
}, child: Consumer<HomeProvider>(builder: (context, _, __) {
|
||||
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]),
|
||||
]);
|
||||
})),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
import 'package:fipy/globals.dart';
|
||||
import 'package:fipy/providers/home.dart';
|
||||
import 'package:fipy/widgets/download_track.dart';
|
||||
import 'package:fipy/widgets/player/player_controls.dart';
|
||||
import 'package:fipy/widgets/player/player_title.dart';
|
||||
import 'package:fipy/widgets/player/player_volume.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:miniplayer/miniplayer.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class Player extends StatelessWidget {
|
||||
const Player({
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
playerContext = context;
|
||||
final controller = MiniplayerController();
|
||||
final hp = Provider.of<HomeProvider>(context, listen: false);
|
||||
|
||||
return Miniplayer(
|
||||
controller: controller,
|
||||
backgroundColor: Colors.grey[900]!,
|
||||
minHeight: 70,
|
||||
maxHeight: 70,
|
||||
builder: (height, percentage) {
|
||||
return Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
hp.currentTrack?.imageUrl != '' && hp.currentTrack?.imageUrl != null
|
||||
? Image.network(
|
||||
hp.currentTrack!.imageUrl!,
|
||||
width: 70,
|
||||
)
|
||||
: const SizedBox(width: 70),
|
||||
const PlayerTitle(),
|
||||
const SizedBox(width: 90),
|
||||
const PlayerControls(),
|
||||
const Spacer(),
|
||||
const DownloadTrack(),
|
||||
const SizedBox(width: 20),
|
||||
const PlayerVolume(),
|
||||
const SizedBox(width: 20)
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
import 'package:fipy/providers/home.dart';
|
||||
import 'package:fipy/providers/player.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class PlayerControls extends StatelessWidget {
|
||||
const PlayerControls({
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final hp = Provider.of<HomeProvider>(context, listen: true);
|
||||
final playerProvider = Provider.of<PlayerProvider>(context, listen: true);
|
||||
return Column(children: [
|
||||
const Spacer(),
|
||||
Row(children: [
|
||||
const SizedBox(width: 70),
|
||||
Column(children: [
|
||||
IconButton(
|
||||
padding: const EdgeInsets.all(0),
|
||||
icon:
|
||||
Icon(Icons.skip_previous, color: Colors.grey[500], size: 32),
|
||||
onPressed: () {
|
||||
if (hp.currentTrack != null && hp.currentTrack!.number > 1) {
|
||||
hp.currentTrack = hp.trackList.firstWhere((element) =>
|
||||
element.number == hp.currentTrack!.number - 1);
|
||||
hp.playTrack(hp.currentTrack!);
|
||||
}
|
||||
}),
|
||||
]),
|
||||
const SizedBox(width: 1),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
hp.player.state.name == 'playing'
|
||||
? hp.player.pause()
|
||||
: hp.player.resume();
|
||||
|
||||
// playerProvider.reload();
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
foregroundColor: Colors.grey[900],
|
||||
backgroundColor: Colors.grey[300],
|
||||
shape: const CircleBorder(),
|
||||
padding: const EdgeInsets.all(12),
|
||||
),
|
||||
child: Icon(
|
||||
hp.player.state.name == 'playing'
|
||||
? Icons.pause
|
||||
: Icons.play_arrow,
|
||||
color: Colors.grey[900],
|
||||
size: 30),
|
||||
),
|
||||
Column(children: [
|
||||
IconButton(
|
||||
padding: const EdgeInsets.all(0),
|
||||
icon: Icon(Icons.skip_next, color: Colors.grey[500], size: 32),
|
||||
onPressed: () {
|
||||
if (hp.currentTrack != null &&
|
||||
hp.currentTrack!.number < hp.trackList.last.number) {
|
||||
hp.currentTrack = hp.trackList.firstWhere((element) =>
|
||||
element.number == hp.currentTrack!.number + 1);
|
||||
hp.playTrack(hp.currentTrack!);
|
||||
}
|
||||
}),
|
||||
// const SizedBox(height: 7),
|
||||
]),
|
||||
]),
|
||||
const Spacer(),
|
||||
Row(children: [
|
||||
const SizedBox(width: 70),
|
||||
Text(
|
||||
timeFormat(hp.currentTrack?.position ?? const Duration(seconds: 0)),
|
||||
style: TextStyle(color: Colors.grey[500], fontSize: 12),
|
||||
),
|
||||
const SizedBox(width: 3),
|
||||
(hp.currentTrack?.duration?.inSeconds ?? -1) <= 0
|
||||
? Column(
|
||||
children: [
|
||||
const SizedBox(width: 300),
|
||||
hp.currentTrack?.title == null
|
||||
? Text(
|
||||
'Choisissez un titre',
|
||||
style: TextStyle(color: Colors.grey[500]),
|
||||
)
|
||||
: const SizedBox(
|
||||
height: 15,
|
||||
width: 15,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: Colors.orange,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: SliderTheme(
|
||||
data: const SliderThemeData(
|
||||
thumbShape: RoundSliderThumbShape(enabledThumbRadius: 2),
|
||||
overlayShape: RoundSliderThumbShape(enabledThumbRadius: 5),
|
||||
trackHeight: 2,
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 300,
|
||||
child: Slider(
|
||||
value: double.parse(
|
||||
hp.currentTrack?.position?.inSeconds.toString() ?? '0'),
|
||||
max: double.parse(
|
||||
hp.currentTrack?.duration?.inSeconds.toString() ??
|
||||
'2000'),
|
||||
onChanged: (double value) {
|
||||
if (hp.currentTrack?.position != null) {
|
||||
hp.player.seek(
|
||||
Duration(seconds: value.toInt()),
|
||||
);
|
||||
playerProvider.reload();
|
||||
}
|
||||
},
|
||||
activeColor: Colors.grey[400],
|
||||
inactiveColor: Colors.grey[700],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 3),
|
||||
Text(
|
||||
timeFormat(hp.currentTrack?.duration ?? const Duration(seconds: 0)),
|
||||
style: TextStyle(color: Colors.grey[500], fontSize: 12),
|
||||
),
|
||||
]),
|
||||
const Spacer(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
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';
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
import 'package:fipy/providers/home.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class PlayerTitle extends StatelessWidget {
|
||||
const PlayerTitle({
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final hp = Provider.of<HomeProvider>(context, listen: true);
|
||||
final trackTitle = TextEditingController();
|
||||
final trackArtiste = TextEditingController();
|
||||
trackTitle.text = hp.currentTrack?.title ?? '';
|
||||
trackArtiste.text = hp.currentTrack?.artiste ?? '';
|
||||
|
||||
return Expanded(
|
||||
child: Column(children: [
|
||||
SizedBox(
|
||||
height: 20,
|
||||
child: TextField(
|
||||
enabled: false,
|
||||
maxLines: 1,
|
||||
controller: trackTitle,
|
||||
decoration: const InputDecoration(
|
||||
border: InputBorder.none,
|
||||
focusedBorder: InputBorder.none,
|
||||
enabledBorder: InputBorder.none,
|
||||
disabledBorder: InputBorder.none,
|
||||
contentPadding: EdgeInsets.only(left: 15),
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey[300],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
child: TextField(
|
||||
enabled: false,
|
||||
maxLines: 1,
|
||||
controller: trackArtiste,
|
||||
decoration: const InputDecoration(
|
||||
border: InputBorder.none,
|
||||
focusedBorder: InputBorder.none,
|
||||
enabledBorder: InputBorder.none,
|
||||
disabledBorder: InputBorder.none,
|
||||
contentPadding: EdgeInsets.only(left: 15),
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey[500],
|
||||
),
|
||||
),
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
import 'package:fipy/providers/home.dart';
|
||||
import 'package:fipy/providers/player.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class PlayerVolume extends StatelessWidget {
|
||||
const PlayerVolume({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final hp = Provider.of<HomeProvider>(context, listen: false);
|
||||
final playerProvider = Provider.of<PlayerProvider>(context, listen: true);
|
||||
|
||||
return SliderTheme(
|
||||
data: const SliderThemeData(
|
||||
thumbShape: RoundSliderThumbShape(enabledThumbRadius: 7),
|
||||
overlayShape: RoundSliderThumbShape(enabledThumbRadius: 8),
|
||||
trackHeight: 2.5,
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 130,
|
||||
child: Slider(
|
||||
value: hp.currentVolume,
|
||||
max: 1,
|
||||
onChanged: (double value) async {
|
||||
hp.currentVolume = value;
|
||||
await hp.player.setVolume(value);
|
||||
playerProvider.reload();
|
||||
},
|
||||
activeColor: Colors.grey[400],
|
||||
inactiveColor: Colors.grey[700],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue