mirror of
https://github.com/stonega/tsacdop
synced 2025-02-17 20:10:37 +01:00
Update player widget design.
This commit is contained in:
parent
691c25fd6b
commit
4009f84c38
@ -38,12 +38,6 @@ final List<BoxShadow> _customShadowNight = [
|
||||
BoxShadow(blurRadius: 8, offset: Offset(2, 2), color: Colors.black)
|
||||
];
|
||||
|
||||
String _stringForSeconds(double seconds) {
|
||||
if (seconds == null) return null;
|
||||
return '${(seconds ~/ 60)}:'
|
||||
'${(seconds.truncate() % 60).toString().padLeft(2, '0')}';
|
||||
}
|
||||
|
||||
const List minsToSelect = [10, 15, 20, 25, 30, 45, 60, 70, 80, 90, 99];
|
||||
const List speedToSelect = [0.5, 0.6, 0.8, 1.0, 1.2, 1.5, 2.0];
|
||||
|
||||
@ -371,16 +365,6 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
||||
color: Theme.of(context).accentColor,
|
||||
width: 2.0)),
|
||||
),
|
||||
// Container(
|
||||
// height: 8.0,
|
||||
// width: 8.0,
|
||||
// decoration: BoxDecoration(
|
||||
// shape: BoxShape.circle,
|
||||
// color: Colors.transparent,
|
||||
// border: Border.all(
|
||||
// color: Theme.of(context).accentColor,
|
||||
// width: 2.0)),
|
||||
// ),
|
||||
]),
|
||||
),
|
||||
),
|
||||
@ -463,7 +447,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
||||
)
|
||||
: Text(
|
||||
s.timeLeft(
|
||||
_stringForSeconds(data.item2) ?? ''),
|
||||
(data.item2).toInt().toTime ?? ''),
|
||||
maxLines: 2,
|
||||
),
|
||||
);
|
||||
@ -479,7 +463,6 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
//Spacer(),
|
||||
data.item1
|
||||
? Stack(
|
||||
alignment: Alignment.center,
|
||||
@ -487,7 +470,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: 10.0),
|
||||
child: Container(
|
||||
child: SizedBox(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: CircleAvatar(
|
||||
@ -521,7 +504,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: 10.0),
|
||||
child: Container(
|
||||
child: SizedBox(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: CircleAvatar(
|
||||
@ -572,7 +555,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
||||
? Center()
|
||||
: AudioPanel(
|
||||
miniPanel: _miniPanel(_width, context),
|
||||
expandedPanel: _expandedPanel(context));
|
||||
expandedPanel: ControlPanel());
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -767,13 +750,6 @@ class _MeteorLoaderState extends State<MeteorLoader>
|
||||
}
|
||||
});
|
||||
controller.forward();
|
||||
// controller.addStatusListener((status) {
|
||||
// if (status == AnimationStatus.completed) {
|
||||
// controller.reset();
|
||||
// } else if (status == AnimationStatus.dismissed) {
|
||||
// controller.forward();
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
@override
|
||||
@ -795,6 +771,271 @@ class _MeteorLoaderState extends State<MeteorLoader>
|
||||
}
|
||||
}
|
||||
|
||||
class PlaylistWidget extends StatefulWidget {
|
||||
const PlaylistWidget({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_PlaylistWidgetState createState() => _PlaylistWidgetState();
|
||||
}
|
||||
|
||||
class _PlaylistWidgetState extends State<PlaylistWidget> {
|
||||
final GlobalKey<AnimatedListState> miniPlaylistKey = GlobalKey();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
|
||||
return Container(
|
||||
alignment: Alignment.topLeft,
|
||||
height: 300,
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: context.accentColor.withAlpha(70),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child:
|
||||
Selector<AudioPlayerNotifier, Tuple2<List<EpisodeBrief>, bool>>(
|
||||
selector: (_, audio) =>
|
||||
Tuple2(audio.queue.playlist, audio.queueUpdate),
|
||||
builder: (_, data, __) {
|
||||
return AnimatedList(
|
||||
key: miniPlaylistKey,
|
||||
shrinkWrap: true,
|
||||
scrollDirection: Axis.vertical,
|
||||
initialItemCount: data.item1.length,
|
||||
itemBuilder: (context, index, animation) => ScaleTransition(
|
||||
alignment: Alignment.center,
|
||||
scale: animation,
|
||||
child: index == 0 || index > data.item1.length - 1
|
||||
? Center()
|
||||
: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
audio.episodeLoad(data.item1[index]);
|
||||
miniPlaylistKey.currentState
|
||||
.removeItem(
|
||||
index,
|
||||
(context, animation) =>
|
||||
Center());
|
||||
miniPlaylistKey.currentState
|
||||
.insertItem(0);
|
||||
},
|
||||
child: Container(
|
||||
height: 60,
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 20),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
child: ClipRRect(
|
||||
borderRadius:
|
||||
BorderRadius.all(
|
||||
Radius.circular(
|
||||
15.0)),
|
||||
child: Container(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: Image.file(File(
|
||||
"${data.item1[index].imagePath}"))),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
alignment:
|
||||
Alignment.centerLeft,
|
||||
child: Text(
|
||||
data.item1[index].title,
|
||||
maxLines: 1,
|
||||
overflow:
|
||||
TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
margin:
|
||||
EdgeInsets.symmetric(horizontal: 20),
|
||||
width: 30.0,
|
||||
height: 30.0,
|
||||
decoration: BoxDecoration(
|
||||
boxShadow:
|
||||
(Theme.of(context).brightness ==
|
||||
Brightness.dark)
|
||||
? _customShadowNight
|
||||
: _customShadow,
|
||||
color: Theme.of(context).primaryColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(15.0)),
|
||||
onTap: () async {
|
||||
await audio
|
||||
.moveToTop(data.item1[index]);
|
||||
miniPlaylistKey.currentState
|
||||
.removeItem(
|
||||
index,
|
||||
(context, animation) => Center(),
|
||||
duration:
|
||||
Duration(milliseconds: 500),
|
||||
);
|
||||
miniPlaylistKey.currentState
|
||||
.insertItem(1,
|
||||
duration: Duration(
|
||||
milliseconds: 200));
|
||||
},
|
||||
child: SizedBox(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: Transform.rotate(
|
||||
angle: math.pi,
|
||||
child: Icon(
|
||||
LineIcons.download_solid,
|
||||
size: 20.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Divider(height: 2),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.0),
|
||||
height: 60.0,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.0),
|
||||
height: 20.0,
|
||||
// color: context.primaryColorDark,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
context.s.homeMenuPlaylist,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16),
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
Container(
|
||||
height: 60,
|
||||
alignment: Alignment.center,
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
height: 30,
|
||||
width: 60,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).primaryColor,
|
||||
borderRadius: BorderRadius.all(Radius.circular(15)),
|
||||
border: Border.all(
|
||||
color: Theme.of(context).brightness == Brightness.dark
|
||||
? Colors.black12
|
||||
: Colors.white10,
|
||||
width: 1),
|
||||
// boxShadow:
|
||||
// Theme.of(context).brightness == Brightness.dark
|
||||
// ? _customShadowNight
|
||||
// : _customShadow,
|
||||
),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.all(Radius.circular(15)),
|
||||
onTap: () {
|
||||
audio.playNext();
|
||||
miniPlaylistKey.currentState.removeItem(
|
||||
0, (context, animation) => Container());
|
||||
miniPlaylistKey.currentState.insertItem(0);
|
||||
},
|
||||
child: SizedBox(
|
||||
height: 30,
|
||||
width: 60,
|
||||
child: Icon(
|
||||
Icons.skip_next,
|
||||
size: 30,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
margin: EdgeInsets.only(left: 20),
|
||||
width: 30.0,
|
||||
height: 30.0,
|
||||
decoration: BoxDecoration(
|
||||
// boxShadow: (Theme.of(context).brightness == Brightness.dark)
|
||||
// ? _customShadowNight
|
||||
// : _customShadow,
|
||||
color: Theme.of(context).primaryColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.all(Radius.circular(15.0)),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
SlideLeftRoute(page: PlaylistPage()),
|
||||
);
|
||||
},
|
||||
child: SizedBox(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: Transform.rotate(
|
||||
angle: math.pi,
|
||||
child: Icon(
|
||||
LineIcons.database_solid,
|
||||
size: 20.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SleepMode extends StatefulWidget {
|
||||
SleepMode({Key key}) : super(key: key);
|
||||
|
||||
@ -866,17 +1107,20 @@ class SleepModeState extends State<SleepMode>
|
||||
Widget build(BuildContext context) {
|
||||
final s = context.s;
|
||||
final _colorTween =
|
||||
ColorTween(begin: context.primaryColor, end: Colors.black);
|
||||
ColorTween(begin: context.accentColor.withAlpha(60), end: Colors.black);
|
||||
var audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
|
||||
return Selector<AudioPlayerNotifier, Tuple3<int, double, SleepTimerMode>>(
|
||||
selector: (_, audio) =>
|
||||
Tuple3(audio.timeLeft, audio.switchValue, audio.sleepTimerMode),
|
||||
Tuple3(audio?.timeLeft, audio?.switchValue, audio.sleepTimerMode),
|
||||
builder: (_, data, __) {
|
||||
var fraction = data.item2 < 0.5 ? data.item2 * 2 : 1;
|
||||
var move = data.item2 > 0.5 ? data.item2 * 2 - 1 : 0;
|
||||
var fraction = math.min(data.item2 * 2, 1.0);
|
||||
var move = math.max(data.item2 * 2 - 1, 0.0);
|
||||
return LayoutBuilder(builder: (context, constraints) {
|
||||
return Container(
|
||||
height: 300,
|
||||
decoration: BoxDecoration(
|
||||
color: _colorTween.transform(move),
|
||||
borderRadius: BorderRadius.circular(10)),
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Column(
|
||||
@ -894,7 +1138,8 @@ class SleepModeState extends State<SleepMode>
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: minsToSelect
|
||||
.map((e) => InkWell(
|
||||
onTap: () => setState(() => _minSelected = e),
|
||||
onTap: () =>
|
||||
setState(() => _minSelected = e),
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
@ -904,14 +1149,15 @@ class SleepModeState extends State<SleepMode>
|
||||
decoration: BoxDecoration(
|
||||
boxShadow: !(e == _minSelected ||
|
||||
fraction > 0)
|
||||
? (Theme.of(context).brightness ==
|
||||
? (context.brightness ==
|
||||
Brightness.dark)
|
||||
? customShadowNight(fraction)
|
||||
? customShadowNight(
|
||||
fraction)
|
||||
: customShadow(fraction)
|
||||
: null,
|
||||
color: (e == _minSelected)
|
||||
? Theme.of(context).accentColor
|
||||
: Theme.of(context).primaryColor,
|
||||
? context.accentColor
|
||||
: context.primaryColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
@ -928,8 +1174,8 @@ class SleepModeState extends State<SleepMode>
|
||||
height: 30 * move,
|
||||
width: 30 * move,
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
_colorTween.transform(fraction),
|
||||
color: _colorTween
|
||||
.transform(fraction),
|
||||
shape: BoxShape.circle),
|
||||
),
|
||||
],
|
||||
@ -1042,11 +1288,8 @@ class SleepModeState extends State<SleepMode>
|
||||
child: Center(
|
||||
child: Text(
|
||||
data.item2 == 1
|
||||
? _stringForSeconds(
|
||||
data.item1.toDouble())
|
||||
: _stringForSeconds(
|
||||
(_minSelected * 60)
|
||||
.toDouble()),
|
||||
? data.item1.toTime
|
||||
: (_minSelected * 60).toTime,
|
||||
style: TextStyle(
|
||||
// fontWeight: FontWeight.bold,
|
||||
// fontSize: 20,
|
||||
@ -1087,8 +1330,8 @@ class SleepModeState extends State<SleepMode>
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
child: Text(s.sleepTimer,
|
||||
style:
|
||||
TextStyle(fontWeight: FontWeight.bold, fontSize: 20)),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold, fontSize: 20)),
|
||||
),
|
||||
),
|
||||
data.item2 == 1 ? CustomPaint(painter: StarSky()) : Center(),
|
||||
@ -1096,6 +1339,7 @@ class SleepModeState extends State<SleepMode>
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -1103,7 +1347,6 @@ class SleepModeState extends State<SleepMode>
|
||||
|
||||
class ControlPanel extends StatefulWidget {
|
||||
ControlPanel({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_ControlPanelState createState() => _ControlPanelState();
|
||||
}
|
||||
@ -1157,10 +1400,15 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
|
||||
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
print(constraints.maxHeight);
|
||||
var maxHeight = constraints.maxHeight;
|
||||
return Container(
|
||||
color: context.primaryColor,
|
||||
height: 300,
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.0),
|
||||
//padding: EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Column(
|
||||
@ -1181,11 +1429,15 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
EdgeInsets.only(top: 10, left: 10, right: 10),
|
||||
child: SliderTheme(
|
||||
data: SliderTheme.of(context).copyWith(
|
||||
activeTrackColor: Theme.of(context).brightness ==
|
||||
activeTrackColor: maxHeight <= 300
|
||||
? Theme.of(context).brightness ==
|
||||
Brightness.dark
|
||||
? Colors.grey[900]
|
||||
: Colors.grey[400],
|
||||
inactiveTrackColor: context.primaryColorDark,
|
||||
: Colors.grey[400]
|
||||
: context.primaryColor,
|
||||
inactiveTrackColor: maxHeight > 300
|
||||
? context.primaryColor
|
||||
: context.primaryColorDark,
|
||||
trackHeight: 20.0,
|
||||
trackShape: MyRectangularTrackShape(),
|
||||
thumbColor: context.accentColor,
|
||||
@ -1193,10 +1445,11 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
enabledThumbRadius: 10.0,
|
||||
disabledThumbRadius: 10.0,
|
||||
thumbCenterColor: _c),
|
||||
overlayColor:
|
||||
Theme.of(context).accentColor.withAlpha(32),
|
||||
overlayShape:
|
||||
RoundSliderOverlayShape(overlayRadius: 4.0),
|
||||
overlayColor: Theme.of(context)
|
||||
.accentColor
|
||||
.withAlpha(32),
|
||||
overlayShape: RoundSliderOverlayShape(
|
||||
overlayRadius: 4.0),
|
||||
),
|
||||
child: Slider(
|
||||
value: data.seekSliderValue,
|
||||
@ -1208,21 +1461,25 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
Container(
|
||||
height: 20.0,
|
||||
padding: EdgeInsets.symmetric(horizontal: 30.0),
|
||||
child: Row(
|
||||
child: maxHeight > 300
|
||||
? Center()
|
||||
: Row(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
_stringForSeconds(
|
||||
data.backgroundAudioPosition / 1000) ??
|
||||
(data.backgroundAudioPosition ~/ 1000)
|
||||
.toTime ??
|
||||
'',
|
||||
style: TextStyle(fontSize: 10),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
child: data.remoteErrorMessage != null
|
||||
child: data.remoteErrorMessage !=
|
||||
null
|
||||
? Text(data.remoteErrorMessage,
|
||||
style: const TextStyle(
|
||||
color: Color(0xFFFF0000)))
|
||||
color:
|
||||
Color(0xFFFF0000)))
|
||||
: Text(
|
||||
data.audioState ==
|
||||
AudioProcessingState
|
||||
@ -1245,8 +1502,8 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
),
|
||||
),
|
||||
Text(
|
||||
_stringForSeconds(
|
||||
data.backgroundAudioDuration / 1000) ??
|
||||
(data.backgroundAudioDuration ~/ 1000)
|
||||
.toTime ??
|
||||
'',
|
||||
style: TextStyle(fontSize: 10),
|
||||
),
|
||||
@ -1270,7 +1527,8 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
padding: EdgeInsets.symmetric(horizontal: 0),
|
||||
padding:
|
||||
EdgeInsets.symmetric(horizontal: 0),
|
||||
onPressed:
|
||||
playing ? () => audio.rewind() : null,
|
||||
iconSize: 32.0,
|
||||
@ -1279,7 +1537,8 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
Selector<AudioPlayerNotifier, int>(
|
||||
selector: (_, audio) => audio.rewindSeconds,
|
||||
builder: (_, seconds, __) => Padding(
|
||||
padding: const EdgeInsets.only(top: 5.0),
|
||||
padding:
|
||||
const EdgeInsets.only(top: 5.0),
|
||||
child: Text('$seconds s',
|
||||
style: GoogleFonts.teko(
|
||||
textBaseline:
|
||||
@ -1297,8 +1556,8 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
color: context.primaryColor,
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color:
|
||||
context.brightness == Brightness.dark
|
||||
color: context.brightness ==
|
||||
Brightness.dark
|
||||
? Colors.black12
|
||||
: Colors.white10,
|
||||
width: 1),
|
||||
@ -1353,7 +1612,8 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
selector: (_, audio) =>
|
||||
audio.fastForwardSeconds,
|
||||
builder: (_, seconds, __) => Padding(
|
||||
padding: const EdgeInsets.only(top: 5.0),
|
||||
padding:
|
||||
const EdgeInsets.only(top: 5.0),
|
||||
child: Text('$seconds s',
|
||||
style: GoogleFonts.teko(
|
||||
textStyle: TextStyle(
|
||||
@ -1362,9 +1622,11 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
)),
|
||||
)),
|
||||
IconButton(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.0),
|
||||
onPressed:
|
||||
playing ? () => audio.fastForward() : null,
|
||||
padding:
|
||||
EdgeInsets.symmetric(horizontal: 10.0),
|
||||
onPressed: playing
|
||||
? () => audio.fastForward()
|
||||
: null,
|
||||
iconSize: 32.0,
|
||||
icon: Icon(Icons.fast_forward),
|
||||
color: Colors.grey[500],
|
||||
@ -1377,8 +1639,8 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
),
|
||||
Container(
|
||||
height: 70.0,
|
||||
padding:
|
||||
EdgeInsets.only(left: 60, right: 60, bottom: 10, top: 10),
|
||||
padding: EdgeInsets.only(
|
||||
left: 60, right: 60, bottom: 10, top: 10),
|
||||
alignment: Alignment.center,
|
||||
child: Selector<AudioPlayerNotifier, String>(
|
||||
selector: (_, audio) => audio.episode.title,
|
||||
@ -1389,7 +1651,8 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
var span = TextSpan(
|
||||
text: title,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold, fontSize: 20));
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20));
|
||||
var tp = TextPainter(
|
||||
text: span,
|
||||
maxLines: 1,
|
||||
@ -1399,9 +1662,11 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
return Marquee(
|
||||
text: title,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold, fontSize: 18),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18),
|
||||
scrollAxis: Axis.horizontal,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
blankSpace: 30.0,
|
||||
velocity: 50.0,
|
||||
pauseAfterRound: Duration.zero,
|
||||
@ -1417,7 +1682,8 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
return Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold, fontSize: 20),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20),
|
||||
);
|
||||
}
|
||||
},
|
||||
@ -1426,14 +1692,39 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
},
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
Selector<AudioPlayerNotifier, Tuple3<EpisodeBrief, bool, bool>>(
|
||||
if (constraints.maxHeight > 300)
|
||||
SizedBox(
|
||||
height: constraints.maxHeight - 300,
|
||||
child: SingleChildScrollView(
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
child: SizedBox(
|
||||
height: 300,
|
||||
child: PageView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 20.0),
|
||||
child: PlaylistWidget(),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 20.0),
|
||||
child: SleepMode(),
|
||||
)
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
Expanded(
|
||||
child: Selector<AudioPlayerNotifier,
|
||||
Tuple3<EpisodeBrief, bool, bool>>(
|
||||
selector: (_, audio) => Tuple3(audio.episode,
|
||||
audio.stopOnComplete, audio.startSleepTimer),
|
||||
builder: (_, data, __) {
|
||||
return Container(
|
||||
padding:
|
||||
EdgeInsets.only(left: 5.0, right: 5.0, bottom: 5.0),
|
||||
padding: EdgeInsets.only(
|
||||
left: 5.0, right: 5.0, bottom: 5.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@ -1449,13 +1740,14 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: CircleAvatar(
|
||||
backgroundImage:
|
||||
FileImage(File("${data.item1.imagePath}")),
|
||||
backgroundImage: FileImage(
|
||||
File("${data.item1.imagePath}")),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 5.0),
|
||||
padding:
|
||||
EdgeInsets.symmetric(horizontal: 5.0),
|
||||
width: 150,
|
||||
child: Text(
|
||||
data.item1.feedTitle,
|
||||
@ -1463,6 +1755,12 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
overflow: TextOverflow.fade,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.playlist_play),
|
||||
onPressed: () {},
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.timer), onPressed: null),
|
||||
Spacer(),
|
||||
LastPosition(),
|
||||
IconButton(
|
||||
@ -1475,7 +1773,8 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
}
|
||||
},
|
||||
icon: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceEvenly,
|
||||
children: <Widget>[
|
||||
Transform.rotate(
|
||||
angle: math.pi * _setSpeed,
|
||||
@ -1494,6 +1793,7 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
]),
|
||||
Positioned(
|
||||
right: 0,
|
||||
@ -1515,9 +1815,10 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
child: Container(
|
||||
height: 30,
|
||||
width: 30,
|
||||
margin: EdgeInsets.symmetric(horizontal: 5),
|
||||
decoration:
|
||||
e == _speedSelected && _setSpeed > 0
|
||||
margin:
|
||||
EdgeInsets.symmetric(horizontal: 5),
|
||||
decoration: e == _speedSelected &&
|
||||
_setSpeed > 0
|
||||
? BoxDecoration(
|
||||
color: context.accentColor,
|
||||
shape: BoxShape.circle,
|
||||
@ -1552,5 +1853,7 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -943,14 +943,13 @@ class _RecentUpdateState extends State<_RecentUpdate>
|
||||
child: IconButton(
|
||||
tooltip: s
|
||||
.addNewEpisodeTooltip,
|
||||
icon:
|
||||
// Icon(Icons.playlist_add),
|
||||
SizedBox(
|
||||
height:
|
||||
16,
|
||||
icon: SizedBox(
|
||||
height: 16,
|
||||
width: 21,
|
||||
child: CustomPaint(
|
||||
painter: AddToPlaylistPainter(
|
||||
child:
|
||||
CustomPaint(
|
||||
painter:
|
||||
AddToPlaylistPainter(
|
||||
context
|
||||
.textColor,
|
||||
context
|
||||
@ -961,67 +960,14 @@ class _RecentUpdateState extends State<_RecentUpdate>
|
||||
}),
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: IconButton(
|
||||
tooltip: s.changeLayout,
|
||||
padding: EdgeInsets.zero,
|
||||
onPressed: () {
|
||||
if (_layout ==
|
||||
Layout.three) {
|
||||
child: LayoutButton(
|
||||
layout: _layout,
|
||||
onPressed: (layout) =>
|
||||
setState(() {
|
||||
_layout = Layout.one;
|
||||
});
|
||||
} else if (_layout ==
|
||||
Layout.two) {
|
||||
setState(() {
|
||||
_layout = Layout.three;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_layout = Layout.two;
|
||||
});
|
||||
}
|
||||
},
|
||||
icon: _layout == Layout.three
|
||||
? SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child: CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
0,
|
||||
context
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.color),
|
||||
),
|
||||
)
|
||||
: _layout == Layout.two
|
||||
? SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child:
|
||||
CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
1,
|
||||
context
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.color),
|
||||
),
|
||||
)
|
||||
: SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child:
|
||||
CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
4,
|
||||
context
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.color),
|
||||
_layout = layout;
|
||||
}),
|
||||
),
|
||||
),
|
||||
)),
|
||||
],
|
||||
),
|
||||
)),
|
||||
@ -1204,62 +1150,12 @@ class _MyFavoriteState extends State<_MyFavorite>
|
||||
Spacer(),
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
onPressed: () {
|
||||
if (_layout == Layout.three) {
|
||||
setState(() {
|
||||
_layout = Layout.one;
|
||||
});
|
||||
} else if (_layout ==
|
||||
Layout.two) {
|
||||
setState(() {
|
||||
_layout = Layout.three;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_layout = Layout.two;
|
||||
});
|
||||
}
|
||||
},
|
||||
icon: _layout == Layout.three
|
||||
? SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child: CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
0,
|
||||
context
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.color),
|
||||
child: LayoutButton(
|
||||
layout: _layout,
|
||||
onPressed: (layout) => setState(() {
|
||||
_layout = layout;
|
||||
}),
|
||||
),
|
||||
)
|
||||
: _layout == Layout.two
|
||||
? SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child: CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
1,
|
||||
context
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.color),
|
||||
),
|
||||
)
|
||||
: SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child: CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
4,
|
||||
context
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.color),
|
||||
),
|
||||
)),
|
||||
),
|
||||
],
|
||||
)),
|
||||
|
@ -270,7 +270,7 @@ class DBHelper {
|
||||
var playHistory = <PlayHistory>[];
|
||||
for (var record in list) {
|
||||
playHistory.add(PlayHistory(record['title'], record['enclosure_url'],
|
||||
record['seconds'], record['seek_value'],
|
||||
(record['seconds']).toInt(), record['seek_value'],
|
||||
playdate: DateTime.fromMillisecondsSinceEpoch(record['add_date'])));
|
||||
}
|
||||
return playHistory;
|
||||
@ -337,7 +337,7 @@ class DBHelper {
|
||||
[episodeBrief.enclosureUrl]);
|
||||
return list.isNotEmpty
|
||||
? PlayHistory(list.first['title'], list.first['enclosure_url'],
|
||||
list.first['seconds'], list.first['seek_value'],
|
||||
(list.first['seconds']).toInt(), list.first['seek_value'],
|
||||
playdate:
|
||||
DateTime.fromMillisecondsSinceEpoch(list.first['add_date']))
|
||||
: PlayHistory(episodeBrief.title, episodeBrief.enclosureUrl, 0, 0);
|
||||
|
@ -606,34 +606,11 @@ class _PodcastDetailState extends State<PodcastDetail> {
|
||||
color: Colors.transparent,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
onPressed: () {
|
||||
if (_layout == Layout.three) {
|
||||
setState(() {
|
||||
_layout = Layout.one;
|
||||
});
|
||||
} else if (_layout == Layout.two) {
|
||||
setState(() {
|
||||
_layout = Layout.three;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_layout = Layout.two;
|
||||
});
|
||||
}
|
||||
},
|
||||
icon: _layout == Layout.three
|
||||
? IconPainter(
|
||||
LayoutPainter(0, context.textColor),
|
||||
)
|
||||
: _layout == Layout.two
|
||||
? IconPainter(
|
||||
LayoutPainter(1, context.textColor),
|
||||
)
|
||||
: IconPainter(
|
||||
LayoutPainter(4, context.textColor),
|
||||
),
|
||||
child: LayoutButton(
|
||||
layout: _layout,
|
||||
onPressed: (layout) => setState(() {
|
||||
_layout = layout;
|
||||
}),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10)
|
||||
|
@ -1,15 +1,23 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'extension_helper.dart';
|
||||
|
||||
enum SlideDirection { up, down }
|
||||
|
||||
class AudioPanel extends StatefulWidget {
|
||||
final Widget miniPanel;
|
||||
final Widget expandedPanel;
|
||||
final Widget optionPanel;
|
||||
final Widget cover;
|
||||
final double minHeight;
|
||||
final double maxHeight;
|
||||
AudioPanel(
|
||||
{@required this.miniPanel,
|
||||
@required this.expandedPanel,
|
||||
this.optionPanel,
|
||||
this.cover,
|
||||
this.minHeight = 60,
|
||||
this.maxHeight = 300,
|
||||
Key key})
|
||||
@ -26,11 +34,11 @@ class _AudioPanelState extends State<AudioPanel> with TickerProviderStateMixin {
|
||||
AnimationController _slowController;
|
||||
Animation _animation;
|
||||
SlideDirection _slideDirection;
|
||||
double _expandHeight;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
initSize = widget.minHeight;
|
||||
_slideDirection = SlideDirection.up;
|
||||
_controller =
|
||||
AnimationController(vsync: this, duration: Duration(milliseconds: 50))
|
||||
..addListener(() {
|
||||
@ -44,7 +52,9 @@ class _AudioPanelState extends State<AudioPanel> with TickerProviderStateMixin {
|
||||
_animation =
|
||||
Tween<double>(begin: 0, end: initSize).animate(_slowController);
|
||||
_controller.forward();
|
||||
_slideDirection = SlideDirection.up;
|
||||
super.initState();
|
||||
_expandHeight = 600;
|
||||
}
|
||||
|
||||
@override
|
||||
@ -54,6 +64,16 @@ class _AudioPanelState extends State<AudioPanel> with TickerProviderStateMixin {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
double _getHeight() {
|
||||
if (_animation.value >= _expandHeight) {
|
||||
return _expandHeight;
|
||||
} else if (_animation.value <= widget.minHeight) {
|
||||
return widget.minHeight;
|
||||
} else {
|
||||
return _animation.value;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(children: <Widget>[
|
||||
@ -65,7 +85,8 @@ class _AudioPanelState extends State<AudioPanel> with TickerProviderStateMixin {
|
||||
child: Container(
|
||||
color: Theme.of(context)
|
||||
.scaffoldBackgroundColor
|
||||
.withOpacity(0.8),
|
||||
.withOpacity(0.9 *
|
||||
math.min(_animation.value / widget.maxHeight, 1)),
|
||||
),
|
||||
),
|
||||
)
|
||||
@ -78,11 +99,7 @@ class _AudioPanelState extends State<AudioPanel> with TickerProviderStateMixin {
|
||||
onVerticalDragUpdate: _update,
|
||||
onVerticalDragEnd: (event) => _end(),
|
||||
child: Container(
|
||||
height: (_animation.value >= widget.maxHeight)
|
||||
? widget.maxHeight
|
||||
: (_animation.value <= widget.minHeight)
|
||||
? widget.minHeight
|
||||
: _animation.value,
|
||||
height: _getHeight(),
|
||||
child: _animation.value < widget.minHeight + 30
|
||||
? Container(
|
||||
color: Theme.of(context).primaryColor,
|
||||
@ -97,7 +114,7 @@ class _AudioPanelState extends State<AudioPanel> with TickerProviderStateMixin {
|
||||
)
|
||||
: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).primaryColor,
|
||||
color: context.primaryColor,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
offset: Offset(0, -0.5),
|
||||
@ -117,7 +134,8 @@ class _AudioPanelState extends State<AudioPanel> with TickerProviderStateMixin {
|
||||
(widget.maxHeight - widget.minHeight - 50)
|
||||
: 1,
|
||||
child: Container(
|
||||
height: widget.maxHeight,
|
||||
height: math.max(widget.maxHeight,
|
||||
math.min(_animation.value, _expandHeight)),
|
||||
child: widget.expandedPanel,
|
||||
),
|
||||
),
|
||||
@ -160,12 +178,21 @@ class _AudioPanelState extends State<AudioPanel> with TickerProviderStateMixin {
|
||||
_end() {
|
||||
if (_slideDirection == SlideDirection.up) {
|
||||
if (_move > 20) {
|
||||
if (_animation.value > widget.maxHeight + 20) {
|
||||
setState(() {
|
||||
_animation =
|
||||
Tween<double>(begin: _animation.value, end: _expandHeight)
|
||||
.animate(_slowController);
|
||||
initSize = _expandHeight;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_animation =
|
||||
Tween<double>(begin: _animation.value, end: widget.maxHeight)
|
||||
.animate(_slowController);
|
||||
initSize = widget.maxHeight;
|
||||
});
|
||||
}
|
||||
_slowController.forward();
|
||||
} else {
|
||||
setState(() {
|
||||
@ -178,13 +205,30 @@ class _AudioPanelState extends State<AudioPanel> with TickerProviderStateMixin {
|
||||
}
|
||||
} else if (_slideDirection == SlideDirection.down) {
|
||||
if (_move > -50) {
|
||||
if (_animation.value > widget.maxHeight) {
|
||||
setState(() {
|
||||
_animation =
|
||||
Tween<double>(begin: _animation.value, end: _expandHeight)
|
||||
.animate(_slowController);
|
||||
initSize = _expandHeight;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_animation =
|
||||
Tween<double>(begin: _animation.value, end: widget.maxHeight)
|
||||
.animate(_slowController);
|
||||
initSize = widget.maxHeight;
|
||||
});
|
||||
}
|
||||
_slowController.forward();
|
||||
} else {
|
||||
if (_animation.value > widget.maxHeight) {
|
||||
setState(() {
|
||||
_animation =
|
||||
Tween<double>(begin: _animation.value, end: widget.maxHeight)
|
||||
.animate(_slowController);
|
||||
initSize = widget.maxHeight;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_animation =
|
||||
@ -192,12 +236,13 @@ class _AudioPanelState extends State<AudioPanel> with TickerProviderStateMixin {
|
||||
.animate(_controller);
|
||||
initSize = widget.minHeight;
|
||||
});
|
||||
}
|
||||
_controller.forward();
|
||||
}
|
||||
}
|
||||
if (_animation.value >= widget.maxHeight) {
|
||||
if (_animation.value >= _expandHeight) {
|
||||
setState(() {
|
||||
initSize = widget.maxHeight;
|
||||
initSize = _expandHeight;
|
||||
});
|
||||
} else if (_animation.value < widget.minHeight) {
|
||||
setState(() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user