Compare commits

...

12 Commits

42 changed files with 1160 additions and 899 deletions

View File

@ -4,8 +4,8 @@
# This file should be version controlled.
version:
revision: 5293f3cd4427b4b48ed155e7a3852c6b3c53d94a
channel: beta
revision: f72efea43c3013323d1b95cff571f3c1caa37583
channel: stable
project_type: app
@ -13,11 +13,11 @@ project_type: app
migration:
platforms:
- platform: root
create_revision: 5293f3cd4427b4b48ed155e7a3852c6b3c53d94a
base_revision: 5293f3cd4427b4b48ed155e7a3852c6b3c53d94a
create_revision: f72efea43c3013323d1b95cff571f3c1caa37583
base_revision: f72efea43c3013323d1b95cff571f3c1caa37583
- platform: windows
create_revision: 5293f3cd4427b4b48ed155e7a3852c6b3c53d94a
base_revision: 5293f3cd4427b4b48ed155e7a3852c6b3c53d94a
create_revision: f72efea43c3013323d1b95cff571f3c1caa37583
base_revision: f72efea43c3013323d1b95cff571f3c1caa37583
# User provided section

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

@ -1,122 +1,122 @@
{
"images" : [
"images": [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
"filename": "Icon-App-20x20@2x.png",
"idiom": "iphone",
"scale": "2x",
"size": "20x20"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
"filename": "Icon-App-20x20@3x.png",
"idiom": "iphone",
"scale": "3x",
"size": "20x20"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
"filename": "Icon-App-29x29@1x.png",
"idiom": "iphone",
"scale": "1x",
"size": "29x29"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
"filename": "Icon-App-29x29@2x.png",
"idiom": "iphone",
"scale": "2x",
"size": "29x29"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
"filename": "Icon-App-29x29@3x.png",
"idiom": "iphone",
"scale": "3x",
"size": "29x29"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
"filename": "Icon-App-40x40@2x.png",
"idiom": "iphone",
"scale": "2x",
"size": "40x40"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
"filename": "Icon-App-40x40@3x.png",
"idiom": "iphone",
"scale": "3x",
"size": "40x40"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
"filename": "Icon-App-60x60@2x.png",
"idiom": "iphone",
"scale": "2x",
"size": "60x60"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
"filename": "Icon-App-60x60@3x.png",
"idiom": "iphone",
"scale": "3x",
"size": "60x60"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
"filename": "Icon-App-20x20@1x.png",
"idiom": "ipad",
"scale": "1x",
"size": "20x20"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
"filename": "Icon-App-20x20@2x.png",
"idiom": "ipad",
"scale": "2x",
"size": "20x20"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
"filename": "Icon-App-29x29@1x.png",
"idiom": "ipad",
"scale": "1x",
"size": "29x29"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
"filename": "Icon-App-29x29@2x.png",
"idiom": "ipad",
"scale": "2x",
"size": "29x29"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
"filename": "Icon-App-40x40@1x.png",
"idiom": "ipad",
"scale": "1x",
"size": "40x40"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
"filename": "Icon-App-40x40@2x.png",
"idiom": "ipad",
"scale": "2x",
"size": "40x40"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
"filename": "Icon-App-76x76@1x.png",
"idiom": "ipad",
"scale": "1x",
"size": "76x76"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
"filename": "Icon-App-76x76@2x.png",
"idiom": "ipad",
"scale": "2x",
"size": "76x76"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
"filename": "Icon-App-83.5x83.5@2x.png",
"idiom": "ipad",
"scale": "2x",
"size": "83.5x83.5"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
"filename": "Icon-App-1024x1024@1x.png",
"idiom": "ios-marketing",
"scale": "1x",
"size": "1024x1024"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
"info": {
"author": "icons_launcher",
"version": 1
}
}
}

View File

@ -1,7 +1,14 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:logger/logger.dart';
late String token;
TextStyle globalTextStyle = TextStyle(color: Colors.grey[350]);
const proxyHeader =
kDebugMode || !kIsWeb ? 'https://' : 'http://127.0.0.1:8080/';
// Logger
final log = Logger();
// context
late BuildContext homeContext;
late BuildContext playerContext;

View File

@ -1,15 +1,12 @@
import 'package:fipy/providers/download.dart';
import 'package:fipy/providers/home.dart';
import 'package:fipy/providers/player.dart';
import 'package:fipy/screens/home.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:kplayer/kplayer.dart';
import 'package:kplayer_with_audioplayers/kplayer_with_audioplayers.dart' as kp;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
Player.boot();
kp.Player.boot();
runApp(const FipyApp());
}
@ -27,7 +24,8 @@ class FipyApp extends StatelessWidget {
child: MaterialApp(
title: 'Fipy',
theme: ThemeData(
primarySwatch: Colors.blue, backgroundColor: Colors.grey[900]),
colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.blue)
.copyWith(background: Colors.grey[900])),
home: const HomeScreen(title: 'Fipy'),
),
);

View File

@ -8,6 +8,7 @@ class Track {
String? image;
String? imageUrl;
String? id;
Duration? position;
Duration? duration;
File? file;
@ -18,6 +19,7 @@ class Track {
this.album,
this.id,
this.duration,
this.position,
this.file,
this.image,
this.imageUrl});

View File

@ -0,0 +1,61 @@
// ignore_for_file: use_build_context_synchronously
import 'dart:io';
import 'package:fipy/globals.dart';
import 'package:fipy/models/track.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:youtube_explode_dart/youtube_explode_dart.dart';
class DownloadProvider with ChangeNotifier {
Future downloadMusic(BuildContext context, Track track) async {
var yt = YoutubeExplode();
var manifest = await yt.videos.streamsClient.getManifest(track.id);
var streamManifest = StreamManifest(manifest.streams);
var streamInfo = streamManifest.audioOnly.withHighestBitrate();
var stream = yt.videos.streamsClient.get(streamInfo);
final fileName = '${track.title} - ${track.artiste}'
.replaceAll('\\', '')
.replaceAll('/', '')
.replaceAll(':', '')
.replaceAll('*', '')
.replaceAll('?', '')
.replaceAll('"', '')
.replaceAll('<', '')
.replaceAll('>', '')
.replaceAll('|', '');
if (!kIsWeb) {
final filePath = Platform.isAndroid
? Directory('/storage/emulated/0/Download')
: await getDownloadsDirectory();
var file = File('${filePath!.path}/$fileName.webm');
var fileStream = file.openWrite();
await stream.pipe(fileStream);
await fileStream.flush();
await fileStream.close();
yt.close();
// convertToMp3(file.path);
track.file = file;
ScaffoldMessenger.of(playerContext).showSnackBar(
SnackBar(
content:
SizedBox(height: 90, child: Text('Son téléchargé: ${file.path}')),
),
);
log.d(file.path);
}
}
void reload() {
notifyListeners();
}
}

View File

@ -1,28 +1,21 @@
// ignore_for_file: avoid_print
import 'dart:convert';
import 'package:fipy/globals.dart';
import 'package:flutter/foundation.dart';
import 'package:universal_io/io.dart';
import 'package:fipy/models/track.dart';
import 'package:flutter/material.dart';
import 'package:kplayer/kplayer.dart';
import 'package:path_provider/path_provider.dart';
import 'package:youtube_explode_dart/youtube_explode_dart.dart';
import 'package:fipy/providers/player.dart';
import 'package:provider/provider.dart';
import 'package:http/http.dart';
import 'package:audioplayers/audioplayers.dart';
import 'package:kplayer_with_audioplayers/kplayer_with_audioplayers.dart' as kp;
class HomeProvider with ChangeNotifier {
Track? currentTrack;
PlayerController? player;
AudioPlayer audioPlayer = AudioPlayer();
AudioPlayer player = AudioPlayer(playerId: 'fipyPlayerID');
List<Track> trackList = [];
int trackNbr = 0;
int userPageNbr = 3;
double currentVolume = 1;
Future<List<Track>> getTracks(String radio, {String cursor = ''}) async {
int pageNbr = 0;
@ -38,12 +31,13 @@ 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) {
cursor = body['next'];
} else {
print('Page N°$pageNbr');
log.d('Page N°$pageNbr');
stop = true;
}
@ -72,24 +66,20 @@ 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;
final currentVolume = player?.volume ?? 1;
if (player?.playing ?? false) player?.stop();
Future.delayed(const Duration(milliseconds: 5));
if (track.id == null) {
final secondMatch = track.artiste == '' ? track.album : track.artiste;
final resultUrl = await yt.search
.search(track.title + ' ' + secondMatch!, filter: TypeFilters.video);
.search('${track.title} ${secondMatch!}', filter: TypeFilters.video);
track.id = resultUrl.first.id.value;
}
const invidiousUrl = [
@ -99,112 +89,89 @@ class HomeProvider with ChangeNotifier {
'invidious.fdn.fr',
];
// audioPlayer.stop();
// Future.delayed(const Duration(milliseconds: 5));
// await audioPlayer.play(DeviceFileSource(
// "https://${invidiousUrl[1]}/latest_version?id=${track.id}&itag=140&local=true&listen=1"));
final media = PlayerMedia(
type: PlayerMediaType.network,
resource:
"https://${invidiousUrl[1]}/latest_version?id=${track.id}&itag=140&local=true&listen=1");
player = kp.Player(media: media);
// player = Player.network(
// "https://${invidiousUrl[0]}/latest_version?id=${track.id}&itag=140&local=true&listen=1"); // https://${invidiousUrl[0]}/embed/${track.id}?listen=1&raw=1&local=true
player!.init();
print(player!.media.resource);
player!.volume = currentVolume;
player.stop();
Future.delayed(const Duration(milliseconds: 5));
try {
player!.play();
final source = UrlSource(
"https://${invidiousUrl[3]}/latest_version?id=${track.id}&itag=140&local=true&listen=1");
log.d(source.url);
await player.play(source);
} catch (e) {
print('Play error: ' + e.toString());
log.d('Play error: $e');
}
Future.delayed(const Duration(milliseconds: 500));
player!.callback = (PlayerEvent event) {
print(event.name);
if (event.name == 'position') {
currentTrack!.duration = player!.duration;
playerProvider.reload();
}
if (event.name == 'end' &&
currentTrack == track &&
(currentTrack!.duration!.inSeconds - player!.position.inSeconds <=
1)) {
var nextTrack = trackList
.firstWhere((element) => element.number == track.number + 1);
currentTrack = nextTrack;
playTrack(context, nextTrack);
}
};
Future.delayed(const Duration(milliseconds: 50));
player.onDurationChanged.listen((event) async {
currentTrack!.duration = await player.getDuration();
playerProvider.reload();
});
player.onPositionChanged.listen((position) async {
currentTrack!.position = position;
playerProvider.reload();
});
player.onPlayerComplete.listen((event) {
var nextTrack =
trackList.firstWhere((element) => element.number == track.number + 1);
currentTrack = nextTrack;
playTrack(nextTrack);
});
playerProvider.reload();
homeProvider.reload();
yt.close();
}
Future downloadMusic(BuildContext context, Track track) async {
var yt = YoutubeExplode();
var manifest = await yt.videos.streamsClient.getManifest(track.id);
var streamManifest = StreamManifest(manifest.streams);
var streamInfo = streamManifest.audioOnly.withHighestBitrate();
var stream = yt.videos.streamsClient.get(streamInfo);
final fileName = '${track.title} - ${track.artiste}'
.replaceAll('\\', '')
.replaceAll('/', '')
.replaceAll(':', '')
.replaceAll('*', '')
.replaceAll('?', '')
.replaceAll('"', '')
.replaceAll('<', '')
.replaceAll('>', '')
.replaceAll('|', '');
if (!kIsWeb) {
final filePath = Platform.isAndroid
? Directory('/storage/emulated/0/Download')
: await getDownloadsDirectory();
var file = File('${filePath!.path}/$fileName.webm');
var fileStream = file.openWrite();
await stream.pipe(fileStream);
await fileStream.flush();
await fileStream.close();
yt.close();
// convertToMp3(file.path);
track.file = file;
print(file.path);
Future nextTrack() async {
if (currentTrack != null && currentTrack!.number < trackList.last.number) {
currentTrack = trackList
.firstWhere((element) => element.number == currentTrack!.number + 1);
await playTrack(currentTrack!);
}
}
Future backTrack() async {
if (currentTrack != null && currentTrack!.number > 1) {
currentTrack = trackList
.firstWhere((element) => element.number == currentTrack!.number - 1);
await playTrack(currentTrack!);
}
}
void resumePlay() {
if (currentTrack == null) {
currentTrack = trackList.first;
playTrack(currentTrack!);
} else {
player.state.name == 'playing' ? player.pause() : player.resume();
}
}
List<DropdownMenuItem<String>> get radioList {
List<DropdownMenuItem<String>> menuItems = [
const DropdownMenuItem(child: Text("FIP"), value: "fip"),
const DropdownMenuItem(child: Text("Electro"), value: "fip_electro"),
const DropdownMenuItem(child: Text("Groove"), value: "fip_groove"),
const DropdownMenuItem(child: Text("Rock"), value: "fip_rock"),
const DropdownMenuItem(child: Text("Jazz"), value: "fip_jazz"),
const DropdownMenuItem(child: Text("Pop"), value: "fip_pop"),
const DropdownMenuItem(child: Text("Reggae"), value: "fip_reggae"),
const DropdownMenuItem(child: Text("World"), value: "fip_world"),
const DropdownMenuItem(value: "fip", child: Text("FIP")),
const DropdownMenuItem(value: "fip_electro", child: Text("Electro")),
const DropdownMenuItem(value: "fip_groove", child: Text("Groove")),
const DropdownMenuItem(value: "fip_rock", child: Text("Rock")),
const DropdownMenuItem(value: "fip_jazz", child: Text("Jazz")),
const DropdownMenuItem(value: "fip_pop", child: Text("Pop")),
const DropdownMenuItem(value: "fip_reggae", child: Text("Reggae")),
const DropdownMenuItem(value: "fip_world", child: Text("World")),
const DropdownMenuItem(
child: Text("Nouveautés"), value: "fip_nouveautes"),
value: "fip_nouveautes", child: Text("Nouveautés")),
];
return menuItems;
}
List<DropdownMenuItem<String>> get pageList {
List<DropdownMenuItem<String>> menuItems = [
const DropdownMenuItem(child: Text("25"), value: "3"),
const DropdownMenuItem(child: Text("50"), value: "6"),
const DropdownMenuItem(child: Text("100"), value: "12"),
const DropdownMenuItem(child: Text("200"), value: "25"),
const DropdownMenuItem(child: Text("500"), value: "62"),
const DropdownMenuItem(value: "3", child: Text("25")),
const DropdownMenuItem(value: "6", child: Text("50")),
const DropdownMenuItem(value: "12", child: Text("100")),
const DropdownMenuItem(value: "25", child: Text("200")),
const DropdownMenuItem(value: "62", child: Text("500")),
];
return menuItems;
}
@ -213,34 +180,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,14 +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';
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key, required this.title}) : super(key: key);
@ -22,381 +23,169 @@ 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,
focusNode: FocusNode(),
onKey: (RawKeyEvent event) {
if (event.runtimeType == RawKeyDownEvent &&
event.data.logicalKey.keyId == 32) //Enter Key ID from keyboard
// log.d(event.data.logicalKey.keyId);
if (event.runtimeType == RawKeyDownEvent) //Enter Key ID from keyboard
{
print('tata');
hp.player?.playing ?? false ? hp.player?.pause() : hp.player?.play();
switch (event.data.logicalKey.keyId) {
case 32:
case 112:
case 4294969861:
hp.resumePlay();
break;
case 110:
case 94489280688:
hp.nextTrack();
break;
case 98:
case 94489280689:
hp.backTrack();
break;
}
}
},
child: Stack(
children: <Widget>[
Scaffold(
body: RawScrollbar(
thumbColor: Colors.grey[600],
radius: const Radius.circular(20),
thickness: 12,
// thumbVisibility: true,
mainAxisMargin: 70,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
color: Colors.grey[900],
height: 50,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
DropdownButton(
dropdownColor: Colors.grey[900],
value: radio,
style: TextStyle(
fontSize: 15, color: Colors.grey[300]),
underline: const SizedBox(),
iconSize: 22,
onChanged: (String? newRadio) {
setState(() {
radio = newRadio!;
});
},
items: hp.radioList),
const SizedBox(width: 50),
DropdownButton(
dropdownColor: Colors.grey[900],
value: hp.userPageNbr.toString(),
style: TextStyle(
fontSize: 15, color: Colors.grey[300]),
underline: const SizedBox(),
iconSize: 22,
onChanged: (String? newPageNumber) {
setState(() {
hp.userPageNbr =
int.parse(newPageNumber!);
});
},
items: hp.pageList),
]),
),
FutureBuilder<List<Track>>(
future: hp.getTracks(radio),
builder: (
BuildContext context,
AsyncSnapshot<List<Track>> snapshot,
) {
print(snapshot.connectionState);
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Stack(children: [
Container(
height: 10000,
width: 10000,
color: const Color(0xFF121212)),
Center(
child: Column(children: [
const SizedBox(height: 20),
SizedBox(
height: 30,
width: 30,
child: CircularProgressIndicator(
color: Colors.amber[100],
),
),
]),
),
]);
} else if (snapshot.connectionState ==
ConnectionState.done) {
if (snapshot.hasError) {
return Stack(children: [
Container(
height: 10000,
width: 10000,
color: const Color(0xFF121212)),
Center(
child: Column(children: [
const SizedBox(height: 20),
Text(
'Error: ' + snapshot.error.toString(),
style: TextStyle(color: Colors.grey[500]),
),
]),
),
]);
} 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!
.map(
(item) => _buildTableRow(item, context))
.toList()
..insert(
0,
_buildTableRow(
Track(
number: -1,
title: 'TITRE',
artiste: 'ARTISTE',
album: 'ALBUM',
id: 'URL'),
context),
),
);
} else {
return const Text('Empty data');
}
} else {
return Text('State: ${snapshot.connectionState}');
}
},
),
const SizedBox(height: 70)
],
),
)),
),
Consumer<PlayerProvider>(builder: (context, playerProvider, _) {
TextEditingController trackTitle = TextEditingController();
TextEditingController trackArtiste = TextEditingController();
trackTitle.text = hp.currentTrack?.title ?? '';
trackArtiste.text = hp.currentTrack?.artiste ?? '';
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?.playing ?? false
? hp.player?.pause()
: hp.player?.play();
// playerProvider.reload();
},
child: Icon(
hp.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(
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.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(
hp.player?.position.inSeconds.toString() ??
'0'),
max: double.parse(
hp.player?.duration.inSeconds.toString() ??
'2000'),
onChanged: (double value) {
if (hp.player?.position != null) {
hp.player!.position =
Duration(seconds: value.toInt());
playerProvider.reload();
}
backgroundColor: Colors.black,
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
color: Colors.grey[900],
height: 50,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
DropdownButton(
dropdownColor: Colors.grey[900],
value: radio,
style: TextStyle(
fontSize: 15, color: Colors.grey[300]),
underline: const SizedBox(),
iconSize: 22,
onChanged: (String? newRadio) {
setState(() {
radio = newRadio!;
});
},
activeColor: Colors.grey[400],
inactiveColor: Colors.grey[700],
),
items: hp.radioList),
const SizedBox(width: 50),
DropdownButton(
dropdownColor: Colors.grey[900],
value: hp.userPageNbr.toString(),
style: TextStyle(
fontSize: 15, color: Colors.grey[300]),
underline: const SizedBox(),
iconSize: 22,
onChanged: (String? newPageNumber) {
setState(() {
hp.userPageNbr = int.parse(newPageNumber!);
});
},
items: hp.pageList),
]),
),
FutureBuilder<List<Track>>(
future: hp.getTracks(radio),
builder: (
BuildContext context,
AsyncSnapshot<List<Track>> snapshot,
) {
print(snapshot.connectionState);
if (snapshot.connectionState == ConnectionState.waiting) {
return Stack(children: [
Container(
height: 10000,
width: 10000,
color: const Color(0xFF121212)),
Center(
child: Column(children: [
const SizedBox(height: 20),
SizedBox(
height: 30,
width: 30,
child: CircularProgressIndicator(
color: Colors.amber[100],
),
),
]),
),
),
const SizedBox(width: 3),
Text(
timeFormat(hp.player?.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.player?.volume ?? 1,
max: 1,
onChanged: (double value) {
if (hp.player?.volume != null) {
hp.player!.volume = value;
playerProvider.reload();
}
},
activeColor: Colors.grey[400],
inactiveColor: Colors.grey[700],
),
),
),
const SizedBox(width: 20)
],
);
},
);
})
]);
} else if (snapshot.connectionState ==
ConnectionState.done) {
if (snapshot.hasError) {
return Stack(children: [
Container(
height: 10000,
width: 10000,
color: const Color(0xFF121212)),
Center(
child: Column(children: [
const SizedBox(height: 20),
Text(
'Error: ${snapshot.error}',
style: TextStyle(color: Colors.grey[500]),
),
]),
),
]);
} 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!
.map((item) => _buildTableRow(item))
.toList()
..insert(
0,
_buildTableRow(Track(
number: -1,
title: 'TITRE',
artiste: 'ARTISTE',
album: 'ALBUM',
id: 'URL')),
),
);
} else {
return const Text('Empty data');
}
} else {
return Text('State: ${snapshot.connectionState}');
}
},
),
const SizedBox(height: 70)
],
),
),
),
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(
@ -409,7 +198,7 @@ TableRow _buildTableRow(Track track, BuildContext context) {
child: InkWell(
onTap: () async {
if (track.number != -1) {
hp.playTrack(context, track);
hp.playTrack(track);
}
},
child: Row(children: [
@ -454,49 +243,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) {
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';
}

View File

@ -0,0 +1,61 @@
import 'package:fipy/models/track.dart';
import 'package:fipy/providers/download.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: true);
final dl = Provider.of<DownloadProvider>(context, listen: false);
int isDownloading = -2;
final yt = YoutubeExplode();
final track = this.track ??
hp.currentTrack ??
Track(number: -3, title: 'title', artiste: 'artiste');
return InkWell(
onTap: track.number == -3
? null
: () async {
isDownloading = track.number;
dl.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
await dl.downloadMusic(context, track);
}
isDownloading = -2;
yt.close();
dl.reload();
},
child: 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]),
]);
}));
}
}

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,126 @@
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: () {
hp.backTrack();
}),
]),
const SizedBox(width: 1),
ElevatedButton(
onPressed: () {
hp.resumePlay();
},
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: () {
hp.nextTrack();
}),
// 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],
),
),
);
}
}

View File

@ -6,14 +6,10 @@
#include "generated_plugin_registrant.h"
#include <dart_vlc/dart_vlc_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
#include <audioplayers_linux/audioplayers_linux_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) dart_vlc_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "DartVlcPlugin");
dart_vlc_plugin_register_with_registrar(dart_vlc_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "AudioplayersLinuxPlugin");
audioplayers_linux_plugin_register_with_registrar(audioplayers_linux_registrar);
}

View File

@ -3,8 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
dart_vlc
url_launcher_linux
audioplayers_linux
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST

View File

@ -0,0 +1,14 @@
//
// Generated file. Do not edit.
//
import FlutterMacOS
import Foundation
import audioplayers_darwin
import path_provider_foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
}

View File

@ -0,0 +1,11 @@
// This is a generated file; do not edit or check into version control.
FLUTTER_ROOT=C:\Users\poka\dev\flutter
FLUTTER_APPLICATION_PATH=C:\Users\poka\dev\fipy
COCOAPODS_PARALLEL_CODE_SIGN=true
FLUTTER_BUILD_DIR=build
FLUTTER_BUILD_NAME=0.0.2
FLUTTER_BUILD_NUMBER=2
DART_OBFUSCATION=false
TRACK_WIDGET_CREATION=true
TREE_SHAKE_ICONS=false
PACKAGE_CONFIG=.dart_tool/package_config.json

View File

@ -0,0 +1,12 @@
#!/bin/sh
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=C:\Users\poka\dev\flutter"
export "FLUTTER_APPLICATION_PATH=C:\Users\poka\dev\fipy"
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
export "FLUTTER_BUILD_DIR=build"
export "FLUTTER_BUILD_NAME=0.0.2"
export "FLUTTER_BUILD_NUMBER=2"
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=true"
export "TREE_SHAKE_ICONS=false"
export "PACKAGE_CONFIG=.dart_tool/package_config.json"

View File

@ -0,0 +1,68 @@
{
"images": [
{
"filename": "app_icon_16.png",
"idiom": "mac",
"scale": "1x",
"size": "16x16"
},
{
"filename": "app_icon_32.png",
"idiom": "mac",
"scale": "2x",
"size": "16x16"
},
{
"filename": "app_icon_32.png",
"idiom": "mac",
"scale": "1x",
"size": "32x32"
},
{
"filename": "app_icon_64.png",
"idiom": "mac",
"scale": "2x",
"size": "32x32"
},
{
"filename": "app_icon_128.png",
"idiom": "mac",
"scale": "1x",
"size": "128x128"
},
{
"filename": "app_icon_256.png",
"idiom": "mac",
"scale": "2x",
"size": "128x128"
},
{
"filename": "app_icon_256.png",
"idiom": "mac",
"scale": "1x",
"size": "256x256"
},
{
"filename": "app_icon_512.png",
"idiom": "mac",
"scale": "2x",
"size": "256x256"
},
{
"filename": "app_icon_512.png",
"idiom": "mac",
"scale": "1x",
"size": "512x512"
},
{
"filename": "app_icon_1024.png",
"idiom": "mac",
"scale": "2x",
"size": "512x512"
}
],
"info": {
"author": "icons_launcher",
"version": 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 871 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -36,13 +36,9 @@ Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{
[Files]
Source: "C:\Users\poka\dev\fipy\build\windows\runner\Release\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Users\poka\dev\fipy\build\windows\runner\Release\dart_vlc_plugin.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Users\poka\dev\fipy\build\windows\runner\Release\flutter_windows.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Users\poka\dev\fipy\build\windows\runner\Release\libvlc.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Users\poka\dev\fipy\build\windows\runner\Release\libvlccore.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Users\poka\dev\fipy\build\windows\runner\Release\audioplayers_windows_plugin.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Users\poka\dev\fipy\build\windows\runner\Release\data\*"; DestDir: "{app}\data"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "C:\Users\poka\dev\fipy\build\windows\runner\Release\plugins\*"; DestDir: "{app}\plugins"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]

View File

@ -5,170 +5,170 @@ packages:
dependency: transitive
description:
name: archive
url: "https://pub.dartlang.org"
sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a"
url: "https://pub.dev"
source: hosted
version: "3.3.0"
version: "3.3.7"
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
sha256: "4cab82a83ffef80b262ddedf47a0a8e56ee6fbf7fe21e6e768b02792034dd440"
url: "https://pub.dev"
source: hosted
version: "2.3.0"
version: "2.4.0"
async:
dependency: transitive
description:
name: async
url: "https://pub.dartlang.org"
sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0
url: "https://pub.dev"
source: hosted
version: "2.8.2"
audio_session:
dependency: transitive
description:
name: audio_session
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.6+1"
audio_video_progress_bar:
dependency: transitive
description:
name: audio_video_progress_bar
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.0"
version: "2.10.0"
audioplayers:
dependency: transitive
dependency: "direct main"
description:
name: audioplayers
url: "https://pub.dartlang.org"
sha256: "6063c05f987596ba7a3dad9bb9a5d8adfa5e7c07b9bae5301b27c11d0b3a239f"
url: "https://pub.dev"
source: hosted
version: "1.0.0-rc.2"
version: "4.0.1"
audioplayers_android:
dependency: transitive
description:
name: audioplayers_android
url: "https://pub.dartlang.org"
sha256: fb6bca878ad175d8f6ddc0e0a2d4226d81fa7c10747c12db420e96c7a096b2cc
url: "https://pub.dev"
source: hosted
version: "1.0.0-rc.2"
version: "3.0.1"
audioplayers_darwin:
dependency: transitive
description:
name: audioplayers_darwin
url: "https://pub.dartlang.org"
sha256: c4a56c49347b2e85ac4e1efea218948ca0fba87f04d2a3d3de07ce2410037038
url: "https://pub.dev"
source: hosted
version: "1.0.0-rc.2"
version: "4.0.1"
audioplayers_linux:
dependency: transitive
description:
name: audioplayers_linux
sha256: "897e24f190232a3fbb88134b062aa83a9240f55789b5e8d17c114283284ef56b"
url: "https://pub.dev"
source: hosted
version: "2.0.1"
audioplayers_platform_interface:
dependency: transitive
description:
name: audioplayers_platform_interface
url: "https://pub.dartlang.org"
sha256: "3a90a46198d375fc7d47bc1d3070c8fd8863b6469b7d87ca80f953efb090f976"
url: "https://pub.dev"
source: hosted
version: "1.0.0-rc.2"
version: "5.0.0"
audioplayers_web:
dependency: transitive
description:
name: audioplayers_web
url: "https://pub.dartlang.org"
sha256: "4f5dcbfec0bf98ea09e243d5f5b64ea43a4e6710a2f292724bed16cdba3c691e"
url: "https://pub.dev"
source: hosted
version: "1.0.0-rc.2"
version: "3.0.1"
audioplayers_windows:
dependency: transitive
description:
name: audioplayers_windows
url: "https://pub.dartlang.org"
sha256: "010f575653c01ccbe9756050b18df83d89426740e04b684f6438aa26c775a965"
url: "https://pub.dev"
source: hosted
version: "1.0.0-rc.2"
version: "2.0.1"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
url: "https://pub.dartlang.org"
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.dartlang.org"
sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c
url: "https://pub.dev"
source: hosted
version: "1.2.0"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.1"
version: "1.2.1"
clock:
dependency: transitive
description:
name: clock
url: "https://pub.dartlang.org"
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.dartlang.org"
sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0
url: "https://pub.dev"
source: hosted
version: "1.16.0"
version: "1.17.0"
convert:
dependency: transitive
description:
name: convert
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
url: "https://pub.dev"
source: hosted
version: "3.1.1"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.0.2"
csslib:
dependency: transitive
description:
name: csslib
url: "https://pub.dartlang.org"
sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745
url: "https://pub.dev"
source: hosted
version: "0.17.1"
version: "0.17.2"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
url: "https://pub.dartlang.org"
sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
url: "https://pub.dev"
source: hosted
version: "1.0.4"
dart_vlc:
dependency: transitive
description:
name: dart_vlc
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.9"
dart_vlc_ffi:
dependency: transitive
description:
name: dart_vlc_ffi
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.5+1"
version: "1.0.5"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.3.1"
ffi:
dependency: transitive
description:
name: ffi
url: "https://pub.dartlang.org"
sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978
url: "https://pub.dev"
source: hosted
version: "1.1.2"
version: "2.0.1"
file:
dependency: transitive
description:
name: file
url: "https://pub.dartlang.org"
sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
url: "https://pub.dev"
source: hosted
version: "6.1.2"
version: "6.1.4"
flutter:
dependency: "direct main"
description: flutter
@ -178,9 +178,10 @@ packages:
dependency: "direct dev"
description:
name: flutter_lints
url: "https://pub.dartlang.org"
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
url: "https://pub.dev"
source: hosted
version: "1.0.4"
version: "2.0.1"
flutter_test:
dependency: "direct dev"
description: flutter
@ -195,142 +196,106 @@ packages:
dependency: transitive
description:
name: freezed_annotation
url: "https://pub.dartlang.org"
sha256: aeac15850ef1b38ee368d4c53ba9a847e900bb2c53a4db3f6881cbb3cb684338
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "2.2.0"
html:
dependency: transitive
description:
name: html
url: "https://pub.dartlang.org"
sha256: "79d498e6d6761925a34ee5ea8fa6dfef38607781d2fa91e37523474282af55cb"
url: "https://pub.dev"
source: hosted
version: "0.15.0"
version: "0.15.2"
http:
dependency: "direct main"
description:
name: http
url: "https://pub.dartlang.org"
sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482"
url: "https://pub.dev"
source: hosted
version: "0.13.4"
version: "0.13.5"
http_parser:
dependency: transitive
description:
name: http_parser
url: "https://pub.dartlang.org"
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
url: "https://pub.dev"
source: hosted
version: "4.0.0"
version: "4.0.2"
icons_launcher:
dependency: "direct dev"
description:
name: icons_launcher
url: "https://pub.dartlang.org"
sha256: f8ccfb80b56856b6eac586980bdd9c14f5ec24fb87127514055445ceb9424f4c
url: "https://pub.dev"
source: hosted
version: "1.1.3"
version: "2.1.0"
image:
dependency: transitive
description:
name: image
url: "https://pub.dartlang.org"
sha256: "483a389d6ccb292b570c31b3a193779b1b0178e7eb571986d9a49904b6861227"
url: "https://pub.dev"
source: hosted
version: "3.1.3"
version: "4.0.15"
js:
dependency: transitive
description:
name: js
url: "https://pub.dartlang.org"
sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7"
url: "https://pub.dev"
source: hosted
version: "0.6.4"
version: "0.6.5"
json_annotation:
dependency: transitive
description:
name: json_annotation
url: "https://pub.dartlang.org"
sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317
url: "https://pub.dev"
source: hosted
version: "4.5.0"
just_audio:
dependency: transitive
description:
name: just_audio
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.20"
just_audio_platform_interface:
dependency: transitive
description:
name: just_audio_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "4.1.0"
just_audio_web:
dependency: transitive
description:
name: just_audio_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.7"
kplayer:
dependency: "direct main"
description:
name: kplayer
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.18"
kplayer_platform_interface:
dependency: transitive
description:
name: kplayer_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.12"
kplayer_with_audioplayers:
dependency: "direct main"
description:
name: kplayer_with_audioplayers
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.10"
kplayer_with_dart_vlc:
dependency: transitive
description:
name: kplayer_with_dart_vlc
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.10"
kplayer_with_just_audio:
dependency: transitive
description:
name: kplayer_with_just_audio
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.10"
version: "4.8.0"
lints:
dependency: transitive
description:
name: lints
url: "https://pub.dartlang.org"
sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
version: "2.0.1"
logger:
dependency: "direct main"
description:
name: logger
sha256: db2ff852ed77090ba9f62d3611e4208a3d11dfa35991a81ae724c113fcb3e3f7
url: "https://pub.dev"
source: hosted
version: "1.3.0"
matcher:
dependency: transitive
description:
name: matcher
url: "https://pub.dartlang.org"
sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72"
url: "https://pub.dev"
source: hosted
version: "0.12.11"
version: "0.12.13"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
url: "https://pub.dev"
source: hosted
version: "0.1.4"
version: "0.2.0"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42"
url: "https://pub.dev"
source: hosted
version: "1.7.0"
version: "1.8.0"
miniplayer:
dependency: "direct main"
description:
@ -344,107 +309,114 @@ packages:
dependency: transitive
description:
name: nested
url: "https://pub.dartlang.org"
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
path:
dependency: transitive
description:
name: path
url: "https://pub.dartlang.org"
sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b
url: "https://pub.dev"
source: hosted
version: "1.8.1"
version: "1.8.2"
path_provider:
dependency: "direct main"
description:
name: path_provider
url: "https://pub.dartlang.org"
sha256: c7edf82217d4b2952b2129a61d3ad60f1075b9299e629e149a8d2e39c2e6aad4
url: "https://pub.dev"
source: hosted
version: "2.0.9"
version: "2.0.14"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
url: "https://pub.dartlang.org"
sha256: da97262be945a72270513700a92b39dd2f4a54dad55d061687e2e37a6390366a
url: "https://pub.dev"
source: hosted
version: "2.0.13"
path_provider_ios:
version: "2.0.25"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_ios
url: "https://pub.dartlang.org"
name: path_provider_foundation
sha256: ad4c4d011830462633f03eb34445a45345673dfd4faf1ab0b4735fbd93b19183
url: "https://pub.dev"
source: hosted
version: "2.0.8"
version: "2.2.2"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
url: "https://pub.dartlang.org"
sha256: "2ae08f2216225427e64ad224a24354221c2c7907e448e6e0e8b57b1eb9f10ad1"
url: "https://pub.dev"
source: hosted
version: "2.1.5"
path_provider_macos:
dependency: transitive
description:
name: path_provider_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.5"
version: "2.1.10"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
url: "https://pub.dartlang.org"
sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec"
url: "https://pub.dev"
source: hosted
version: "2.0.3"
version: "2.0.6"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
url: "https://pub.dartlang.org"
sha256: f53720498d5a543f9607db4b0e997c4b5438884de25b0f73098cc2671a51b130
url: "https://pub.dev"
source: hosted
version: "2.0.5"
version: "2.1.5"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.dartlang.org"
sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4"
url: "https://pub.dev"
source: hosted
version: "4.4.0"
version: "5.1.0"
platform:
dependency: transitive
description:
name: platform
url: "https://pub.dartlang.org"
sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76"
url: "https://pub.dev"
source: hosted
version: "3.1.0"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
url: "https://pub.dartlang.org"
sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.4"
pointycastle:
dependency: transitive
description:
name: pointycastle
sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
url: "https://pub.dev"
source: hosted
version: "3.7.3"
process:
dependency: transitive
description:
name: process
url: "https://pub.dartlang.org"
sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
url: "https://pub.dev"
source: hosted
version: "4.2.4"
provider:
dependency: "direct main"
description:
name: provider
url: "https://pub.dartlang.org"
sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f
url: "https://pub.dev"
source: hosted
version: "6.0.2"
rxdart:
dependency: transitive
description:
name: rxdart
url: "https://pub.dartlang.org"
source: hosted
version: "0.27.3"
version: "6.0.5"
sky_engine:
dependency: transitive
description: flutter
@ -454,107 +426,130 @@ packages:
dependency: transitive
description:
name: source_span
url: "https://pub.dartlang.org"
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
url: "https://pub.dev"
source: hosted
version: "1.8.2"
version: "1.9.1"
stack_trace:
dependency: transitive
description:
name: stack_trace
url: "https://pub.dartlang.org"
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
url: "https://pub.dev"
source: hosted
version: "1.10.0"
version: "1.11.0"
stream_channel:
dependency: transitive
description:
name: stream_channel
url: "https://pub.dartlang.org"
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
string_scanner:
dependency: transitive
description:
name: string_scanner
url: "https://pub.dartlang.org"
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.2.0"
synchronized:
dependency: transitive
description:
name: synchronized
sha256: "33b31b6beb98100bf9add464a36a8dd03eb10c7a8cf15aeec535e9b054aaf04b"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.2.1"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206
url: "https://pub.dev"
source: hosted
version: "0.4.9"
version: "0.4.16"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.dartlang.org"
sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.3.1"
universal_io:
dependency: "direct main"
description:
name: universal_io
url: "https://pub.dartlang.org"
sha256: "06866290206d196064fd61df4c7aea1ffe9a4e7c4ccaa8fcded42dd41948005d"
url: "https://pub.dev"
source: hosted
version: "2.0.4"
version: "2.2.0"
uuid:
dependency: transitive
description:
name: uuid
url: "https://pub.dartlang.org"
sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313"
url: "https://pub.dev"
source: hosted
version: "3.0.6"
version: "3.0.7"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.dartlang.org"
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.4"
win32:
dependency: transitive
description:
name: win32
url: "https://pub.dartlang.org"
sha256: a6f0236dbda0f63aa9a25ad1ff9a9d8a4eaaa5012da0dc59d21afdb1dc361ca4
url: "https://pub.dev"
source: hosted
version: "2.5.2"
version: "3.1.4"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.dartlang.org"
sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1
url: "https://pub.dev"
source: hosted
version: "0.2.0+1"
version: "1.0.0"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.dartlang.org"
sha256: "979ee37d622dec6365e2efa4d906c37470995871fe9ae080d967e192d88286b5"
url: "https://pub.dev"
source: hosted
version: "5.3.1"
version: "6.2.2"
yaml:
dependency: transitive
description:
name: yaml
url: "https://pub.dartlang.org"
sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370"
url: "https://pub.dev"
source: hosted
version: "3.1.0"
version: "3.1.1"
youtube_explode_dart:
dependency: "direct main"
description:
name: youtube_explode_dart
url: "https://pub.dartlang.org"
sha256: "07889a6229a63e78f8d45a3b852897c2e0fa42e96c4daa38d411be211575bc38"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.12.4"
sdks:
dart: ">=2.17.0-266.5.beta <3.0.0"
flutter: ">=2.8.1"
dart: ">=2.18.0 <3.0.0"
flutter: ">=3.3.0"

View File

@ -2,7 +2,7 @@ name: fipy
description: Advanced FIP radio track explorer
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 0.0.2+1
version: 0.0.3+2
environment:
sdk: ">=2.16.2 <3.0.0"
@ -16,8 +16,8 @@ dependencies:
# url: https://git.p2p.legal/poka/youtube_explode.git
# ref: master
http: ^0.13.4
kplayer: ^0.1.18
kplayer_with_audioplayers: ^0.0.10
# kplayer: ^0.1.18
# kplayer_with_audioplayers: ^0.0.10
miniplayer: #^1.0.1
git:
url: https://git.p2p.legal/poka/flutter_miniplayer.git
@ -26,21 +26,40 @@ dependencies:
path_provider: ^2.0.9
universal_io: ^2.0.4
# ffmpeg_cli: ^0.1.0
# audioplayers: ^1.0.0-rc.2
audioplayers: ^4.0.1
logger: ^1.3.0
# git:
# url: https://github.com/bluefireteam/audioplayers/tree/main/packages/audioplayers_linux
# ref: main
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^1.0.0
icons_launcher: ^1.1.3
flutter_lints: ^2.0.1
icons_launcher: ^2.0.6
flutter_icons:
android: true
ios: true
# macos: true
windows: true
web: true
image_path: "assets/logo_green_dark.jpg"
icons_launcher:
image_path: 'assets/logo_green_dark.jpg'
platforms:
android:
enable: true
ios:
enable: true
windows:
enable: true
linux:
enable: true
macos:
enable: true
# flutter_icons:
# android: true
# ios: true
# # macos: true
# windows: true
# web: true
# image_path: "assets/logo_green_dark.jpg"
flutter:
uses-material-design: true

View File

@ -0,0 +1,8 @@
[Desktop Entry]
Name=Flutter Linux App
Comment=Flutter Linux launcher icon
Exec=app_icon
Icon=app_icon.png
Terminal=false
Type=Application
Categories=Entertainment;

BIN
snap/gui/app_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -7,11 +7,8 @@
#include "generated_plugin_registrant.h"
#include <audioplayers_windows/audioplayers_windows_plugin.h>
#include <dart_vlc/dart_vlc_plugin.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
AudioplayersWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin"));
DartVlcPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("DartVlcPlugin"));
}

View File

@ -4,7 +4,6 @@
list(APPEND FLUTTER_PLUGIN_LIST
audioplayers_windows
dart_vlc
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST

View File

@ -20,12 +20,20 @@ add_executable(${BINARY_NAME} WIN32
# that need different build settings.
apply_standard_settings(${BINARY_NAME})
# Add preprocessor definitions for the build version.
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"")
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}")
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}")
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}")
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}")
# Disable Windows macros that collide with C++ standard library functions.
target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
# Add dependency libraries and include directories. Add any application-specific
# dependencies here.
target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib")
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
# Run the Flutter tool portions of the build. This must not be removed.

View File

@ -60,14 +60,14 @@ IDI_APP_ICON ICON "resources\\app_icon.ico"
// Version
//
#ifdef FLUTTER_BUILD_NUMBER
#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER
#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD)
#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD
#else
#define VERSION_AS_NUMBER 1,0,0
#define VERSION_AS_NUMBER 1,0,0,0
#endif
#ifdef FLUTTER_BUILD_NAME
#define VERSION_AS_STRING #FLUTTER_BUILD_NAME
#if defined(FLUTTER_VERSION)
#define VERSION_AS_STRING FLUTTER_VERSION
#else
#define VERSION_AS_STRING "1.0.0"
#endif
@ -93,7 +93,7 @@ BEGIN
VALUE "FileDescription", "fipy" "\0"
VALUE "FileVersion", VERSION_AS_STRING "\0"
VALUE "InternalName", "fipy" "\0"
VALUE "LegalCopyright", "Copyright (C) 2022 fipy.p2p. All rights reserved." "\0"
VALUE "LegalCopyright", "Copyright (C) 2023 fipy.p2p. All rights reserved." "\0"
VALUE "OriginalFilename", "fipy.exe" "\0"
VALUE "ProductName", "fipy" "\0"
VALUE "ProductVersion", VERSION_AS_STRING "\0"

View File

@ -26,6 +26,11 @@ bool FlutterWindow::OnCreate() {
}
RegisterPlugins(flutter_controller_->engine());
SetChildContent(flutter_controller_->view()->GetNativeWindow());
flutter_controller_->engine()->SetNextFrameCallback([&]() {
this->Show();
});
return true;
}

View File

@ -27,7 +27,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
FlutterWindow window(project);
Win32Window::Point origin(10, 10);
Win32Window::Size size(1280, 720);
if (!window.CreateAndShow(L"fipy", origin, size)) {
if (!window.Create(L"fipy", origin, size)) {
return EXIT_FAILURE;
}
window.SetQuitOnClose(true);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -7,7 +7,7 @@
</application>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 -->
<!-- Windows 10 and Windows 11 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>

View File

@ -1,13 +1,31 @@
#include "win32_window.h"
#include <dwmapi.h>
#include <flutter_windows.h>
#include "resource.h"
namespace {
/// Window attribute that enables dark mode window decorations.
///
/// Redefined in case the developer's machine has a Windows SDK older than
/// version 10.0.22000.0.
/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
#endif
constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW";
/// Registry key for app theme preference.
///
/// A value of 0 indicates apps should use dark mode. A non-zero or missing
/// value indicates apps should use light mode.
constexpr const wchar_t kGetPreferredBrightnessRegKey[] =
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme";
// The number of Win32Window objects that currently exist.
static int g_active_window_count = 0;
@ -31,8 +49,8 @@ void EnableFullDpiSupportIfAvailable(HWND hwnd) {
GetProcAddress(user32_module, "EnableNonClientDpiScaling"));
if (enable_non_client_dpi_scaling != nullptr) {
enable_non_client_dpi_scaling(hwnd);
FreeLibrary(user32_module);
}
FreeLibrary(user32_module);
}
} // namespace
@ -102,9 +120,9 @@ Win32Window::~Win32Window() {
Destroy();
}
bool Win32Window::CreateAndShow(const std::wstring& title,
const Point& origin,
const Size& size) {
bool Win32Window::Create(const std::wstring& title,
const Point& origin,
const Size& size) {
Destroy();
const wchar_t* window_class =
@ -117,7 +135,7 @@ bool Win32Window::CreateAndShow(const std::wstring& title,
double scale_factor = dpi / 96.0;
HWND window = CreateWindow(
window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE,
window_class, title.c_str(), WS_OVERLAPPEDWINDOW,
Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),
Scale(size.width, scale_factor), Scale(size.height, scale_factor),
nullptr, nullptr, GetModuleHandle(nullptr), this);
@ -126,9 +144,15 @@ bool Win32Window::CreateAndShow(const std::wstring& title,
return false;
}
UpdateTheme(window);
return OnCreate();
}
bool Win32Window::Show() {
return ShowWindow(window_handle_, SW_SHOWNORMAL);
}
// static
LRESULT CALLBACK Win32Window::WndProc(HWND const window,
UINT const message,
@ -188,6 +212,10 @@ Win32Window::MessageHandler(HWND hwnd,
SetFocus(child_content_);
}
return 0;
case WM_DWMCOLORIZATIONCOLORCHANGED:
UpdateTheme(hwnd);
return 0;
}
return DefWindowProc(window_handle_, message, wparam, lparam);
@ -243,3 +271,18 @@ bool Win32Window::OnCreate() {
void Win32Window::OnDestroy() {
// No-op; provided for subclasses.
}
void Win32Window::UpdateTheme(HWND const window) {
DWORD light_mode;
DWORD light_mode_size = sizeof(light_mode);
LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey,
kGetPreferredBrightnessRegValue,
RRF_RT_REG_DWORD, nullptr, &light_mode,
&light_mode_size);
if (result == ERROR_SUCCESS) {
BOOL enable_dark_mode = light_mode == 0;
DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE,
&enable_dark_mode, sizeof(enable_dark_mode));
}
}

View File

@ -28,15 +28,16 @@ class Win32Window {
Win32Window();
virtual ~Win32Window();
// Creates and shows a win32 window with |title| and position and size using
// Creates a win32 window with |title| that is positioned and sized using
// |origin| and |size|. New windows are created on the default monitor. Window
// sizes are specified to the OS in physical pixels, hence to ensure a
// consistent size to will treat the width height passed in to this function
// as logical pixels and scale to appropriate for the default monitor. Returns
// true if the window was created successfully.
bool CreateAndShow(const std::wstring& title,
const Point& origin,
const Size& size);
// consistent size this function will scale the inputted width and height as
// as appropriate for the default monitor. The window is invisible until
// |Show| is called. Returns true if the window was created successfully.
bool Create(const std::wstring& title, const Point& origin, const Size& size);
// Show the current window. Returns true if the window was successfully shown.
bool Show();
// Release OS resources associated with window.
void Destroy();
@ -86,6 +87,9 @@ class Win32Window {
// Retrieves a class instance pointer for |window|
static Win32Window* GetThisFromHandle(HWND const window) noexcept;
// Update the window frame's theme to match the system theme.
static void UpdateTheme(HWND const window);
bool quit_on_close_ = false;
// window handle for top level window.