1
0
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:
stonegate 2020-07-28 12:35:57 +08:00
parent 691c25fd6b
commit 4009f84c38
5 changed files with 1011 additions and 790 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -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(() {