refacto: cut widgets

This commit is contained in:
poka 2023-04-16 02:37:57 +02:00
parent 422aaefbac
commit 60c4a1f68d
9 changed files with 385 additions and 374 deletions

View File

@ -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;

View File

@ -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'),
),
);

View File

@ -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);
// }

View File

@ -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);
// });
// }
// });
// }
// }

View File

@ -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]),
]);
})),
);
}
}

View File

@ -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)
],
);
},
);
}
}

View File

@ -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';
}

View File

@ -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],
),
),
),
]),
);
}
}

View File

@ -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],
),
),
);
}
}