0.6.5 - Local streaming http server

This commit is contained in:
exttex 2020-11-28 22:32:17 +01:00
parent 28c2de55fb
commit 21e7f55017
31 changed files with 1744 additions and 460 deletions

View file

@ -1,10 +1,15 @@
import 'dart:convert';
import 'dart:isolate';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:audio_service/audio_service.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/screenutil.dart';
import 'package:freezer/api/cache.dart';
import 'package:freezer/api/deezer.dart';
import 'package:freezer/api/download.dart';
import 'package:freezer/api/player.dart';
import 'package:freezer/settings.dart';
import 'package:freezer/translations.i18n.dart';
@ -25,6 +30,7 @@ import 'player_bar.dart';
import 'dart:ui';
import 'dart:async';
class PlayerScreen extends StatefulWidget {
@override
_PlayerScreenState createState() => _PlayerScreenState();
@ -36,26 +42,34 @@ class _PlayerScreenState extends State<PlayerScreen> {
StreamSubscription _mediaItemSub;
//Calculate background color
Future _calculateColor() async {
Future _updateColor() async {
if (!settings.colorGradientBackground)
return;
//Run in isolate
PaletteGenerator palette = await PaletteGenerator.fromImageProvider(CachedNetworkImageProvider(AudioService.currentMediaItem.extras['thumb'] ?? AudioService.currentMediaItem.artUri));
//Update notification
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: palette.dominantColor.color.withOpacity(0.5)
));
setState(() => _bgGradient = LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [palette.dominantColor.color.withOpacity(0.5), Theme.of(context).bottomAppBarColor],
stops: [
0.0,
0.4
]
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [palette.dominantColor.color.withOpacity(0.5), Theme.of(context).bottomAppBarColor],
stops: [
0.0,
0.4
]
));
}
@override
void initState() {
_calculateColor();
Future.delayed(Duration(milliseconds: 1000), _updateColor);
_mediaItemSub = AudioService.currentMediaItemStream.listen((event) {
_calculateColor();
_updateColor();
});
super.initState();
}
@ -67,6 +81,7 @@ class _PlayerScreenState extends State<PlayerScreen> {
//Fix bottom buttons
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
systemNavigationBarColor: settings.themeData.bottomAppBarColor,
statusBarColor: Colors.transparent
));
super.dispose();
}
@ -214,26 +229,9 @@ class _PlayerScreenHorizontalState extends State<PlayerScreenHorizontal> {
));
},
),
if (AudioService.currentMediaItem.extras['qualityString'] != null)
FlatButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (context) => QualitySettings())
),
child: Text(
AudioService.currentMediaItem.extras['qualityString'] ?? '',
style: TextStyle(fontSize: ScreenUtil().setSp(24)),
),
),
QualityInfoWidget(),
RepeatButton(ScreenUtil().setWidth(32)),
IconButton(
icon: Icon(Icons.more_vert, size: ScreenUtil().setWidth(32)),
onPressed: () {
Track t = Track.fromMediaItem(AudioService.currentMediaItem);
MenuSheet m = MenuSheet(context);
m.defaultTrackMenu(t, options: [m.sleepTimer()]);
},
)
PlayerMenuButton()
],
),
)
@ -333,28 +331,9 @@ class _PlayerScreenVerticalState extends State<PlayerScreenVertical> {
));
},
),
if (AudioService.currentMediaItem.extras['qualityString'] != null)
FlatButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (context) => QualitySettings())
),
child: Text(
AudioService.currentMediaItem.extras['qualityString'] ?? '',
style: TextStyle(
fontSize: ScreenUtil().setSp(32),
),
),
),
QualityInfoWidget(),
RepeatButton(ScreenUtil().setWidth(46)),
IconButton(
icon: Icon(Icons.more_vert, size: ScreenUtil().setWidth(46)),
onPressed: () {
Track t = Track.fromMediaItem(AudioService.currentMediaItem);
MenuSheet m = MenuSheet(context);
m.defaultTrackMenu(t, options: [m.sleepTimer()]);
},
)
PlayerMenuButton()
],
),
)
@ -363,6 +342,86 @@ class _PlayerScreenVerticalState extends State<PlayerScreenVertical> {
}
}
class QualityInfoWidget extends StatefulWidget {
@override
_QualityInfoWidgetState createState() => _QualityInfoWidgetState();
}
class _QualityInfoWidgetState extends State<QualityInfoWidget> {
String value = '';
StreamSubscription streamSubscription;
//Load data from native
void _load() async {
if (AudioService.currentMediaItem == null) return;
Map data = await DownloadManager.platform.invokeMethod("getStreamInfo", {"id": AudioService.currentMediaItem.id});
//N/A
if (data == null) {
setState(() => value = '');
//If not show, try again later
if (AudioService.currentMediaItem.extras['show'] == null)
Future.delayed(Duration(milliseconds: 200), _load);
return;
}
//Update
StreamQualityInfo info = StreamQualityInfo.fromJson(data);
setState(() {
value = '${info.format} ${info.bitrate(AudioService.currentMediaItem.duration)}kbps';
});
}
@override
void initState() {
_load();
if (streamSubscription == null)
streamSubscription = AudioService.currentMediaItemStream.listen((event) async {
await _load();
});
super.initState();
}
@override
void dispose() {
if (streamSubscription != null)
streamSubscription.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return FlatButton(
child: Text(value),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => QualitySettings()));
},
);
}
}
class PlayerMenuButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return IconButton(
icon: Icon(Icons.more_vert, size: ScreenUtil().setWidth(46)),
onPressed: () {
Track t = Track.fromMediaItem(AudioService.currentMediaItem);
MenuSheet m = MenuSheet(context);
if (AudioService.currentMediaItem.extras['show'] == null)
m.defaultTrackMenu(t, options: [m.sleepTimer()]);
else
m.defaultShowEpisodeMenu(
Show.fromJson(jsonDecode(AudioService.currentMediaItem.extras['show'])),
ShowEpisode.fromMediaItem(AudioService.currentMediaItem),
options: [m.sleepTimer()]
);
},
);
}
}
class RepeatButton extends StatefulWidget {