Add multi select in podcast deatil page.

This commit is contained in:
stonegate 2020-09-15 03:02:32 +08:00
parent e1fe91983e
commit 4385c58668
7 changed files with 714 additions and 410 deletions

View File

@ -293,71 +293,6 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
),
),
_ShowNote(episode: widget.episodeItem),
// _loaddes
// ? _description.length > 0
// ? Selector<AudioPlayerNotifier, EpisodeBrief>(
// selector: (_, audio) => audio.episode,
// builder: (_, data, __) {
// var description = _description;
// if (data == widget.episodeItem) {
// final linkList = linkify(_description,
// options:
// LinkifyOptions(humanize: false),
// linkifiers: [TimeStampLinkifier()]);
// for (var element in linkList) {
// if (element is TimeStampElement) {
// final time = element.timeStamp;
// description = description.replaceFirst(
// time,
// '<a rel="nofollow" href = "skipto:$time">$time</a>');
// }
// }
// }
// return Html(
// padding: EdgeInsets.only(
// left: 20.0, right: 20, bottom: 50),
// defaultTextStyle: GoogleFonts.martel(
// textStyle: TextStyle(
// height: 1.8,
// ),
// ),
// data: description,
// linkStyle: TextStyle(
// color: context.accentColor,
// textBaseline:
// TextBaseline.ideographic),
// onLinkTap: (url) {
// if (url.substring(0, 6) == 'skipto') {
// final seconds = _getTimeStamp(url);
// audio.seekTo(seconds * 1000);
// } else {
// url.launchUrl;
// }
// },
// useRichText: true,
// );
// })
// : Container(
// height: context.width,
// alignment: Alignment.center,
// child: Column(
// mainAxisAlignment: MainAxisAlignment.center,
// children: <Widget>[
// Image(
// image:
// AssetImage('assets/shownote.png'),
// height: 100.0,
// ),
// Padding(padding: EdgeInsets.all(5.0)),
// Text(s.noShownote,
// textAlign: TextAlign.center,
// style: TextStyle(
// color: context.textColor
// .withOpacity(0.5))),
// ],
// ),
// )
// : Center(),
Selector<AudioPlayerNotifier, Tuple2<bool, PlayerHeight>>(
selector: (_, audio) =>
Tuple2(audio.playerRunning, audio.playerHeight),

View File

@ -1,6 +1,6 @@
import 'dart:async';
import 'dart:ui';
import 'dart:math' as math;
import 'dart:ui';
import 'package:connectivity/connectivity.dart';
import 'package:flutter/material.dart';

View File

@ -1,5 +1,3 @@
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
@ -171,7 +169,7 @@ class DiscoveryPageState extends State<DiscoveryPage> {
);
}
return SizedBox(
height: 1,
height: 0,
);
}),
Padding(

View File

@ -161,7 +161,6 @@ class RssResult extends StatefulWidget {
class _RssResultState extends State<RssResult> {
OnlinePodcast _onlinePodcast;
bool _isSubscribed = false;
int _loadItems;
@override
@ -180,14 +179,7 @@ class _RssResultState extends State<RssResult> {
@override
Widget build(BuildContext context) {
var subscribeWorker = Provider.of<GroupList>(context, listen: false);
final s = context.s;
_subscribePodcast(OnlinePodcast podcast) {
var item = SubscribeItem(podcast.rss, podcast.title,
imgUrl: podcast.image, group: 'Home');
subscribeWorker.setSubscribeItem(item);
}
var items = widget.rssFeed.items;
return DefaultTabController(
length: 2,

View File

@ -20,6 +20,7 @@ import '../state/audio_state.dart';
import '../state/download_state.dart';
import '../type/episodebrief.dart';
import '../type/fireside_data.dart';
import '../type/play_histroy.dart';
import '../type/podcastlocal.dart';
import '../util/audiopanel.dart';
import '../util/custom_widget.dart';
@ -75,6 +76,12 @@ class _PodcastDetailState extends State<PodcastDetail> {
///Hide listened.
bool _hideListened;
///Selected episode list.
List<EpisodeBrief> _selectedEpisodes;
///Toggle for multi-select.
bool _multiSelect;
@override
void initState() {
super.initState();
@ -82,6 +89,7 @@ class _PodcastDetailState extends State<PodcastDetail> {
_reverse = false;
_controller = ScrollController();
_scroll = false;
_multiSelect = false;
}
@override
@ -519,34 +527,35 @@ class _PodcastDetailState extends State<PodcastDetail> {
PopupMenuItem(
value: 3,
child: Container(
padding: EdgeInsets.only(
top: 5, bottom: 5, left: 2, right: 2),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
border: Border.all(
width: 2,
color: context.textColor.withOpacity(0.2))),
child: _query == ''
? Row(
children: [
Text(s.search,
padding:
EdgeInsets.only(top: 5, bottom: 5, left: 2, right: 2),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
border: Border.all(
width: 2,
color: context.textColor.withOpacity(0.2))),
child: _query == ''
? Row(
children: [
Text(s.search,
style: TextStyle(
color: context.textColor
.withOpacity(0.4))),
Spacer()
],
)
: Row(
children: [
Expanded(
child: Text(_query,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: context.textColor
.withOpacity(0.4))),
Spacer()
],
)
: Row(
children: [
Expanded(
child: Text(_query,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: context.accentColor)),
),
],
)),
color: context.accentColor)),
),
],
),
),
),
],
onSelected: (value) {
@ -638,6 +647,24 @@ class _PodcastDetailState extends State<PodcastDetail> {
),
);
}),
Material(
color: Colors.transparent,
clipBehavior: Clip.hardEdge,
borderRadius: BorderRadius.circular(100),
child: IconButton(
icon: SizedBox(
width: 20,
height: 10,
child: CustomPaint(
painter: MultiSelectPainter(color: context.textColor)),
),
onPressed: () {
setState(() {
_selectedEpisodes = [];
_multiSelect = true;
});
},
)),
SizedBox(width: 10)
],
));
@ -667,8 +694,6 @@ class _PodcastDetailState extends State<PodcastDetail> {
child: Scaffold(
body: SafeArea(
top: false,
//minimum:
// widget.hide ? EdgeInsets.only(bottom: 50) : EdgeInsets.zero,
child: RefreshIndicator(
key: _refreshIndicatorKey,
color: context.accentColor,
@ -789,7 +814,10 @@ class _PodcastDetailState extends State<PodcastDetail> {
SliverToBoxAdapter(
child: _hostsList(context, widget.podcastLocal),
),
SliverToBoxAdapter(child: _actionBar(context)),
SliverToBoxAdapter(
child: _multiSelect
? Center()
: _actionBar(context)),
FutureBuilder<List<EpisodeBrief>>(
future: _getRssItem(widget.podcastLocal,
count: _top,
@ -809,6 +837,11 @@ class _PodcastDetailState extends State<PodcastDetail> {
reverse: _reverse,
episodeCount: _episodeCount,
initNum: _scroll ? 0 : 12,
multiSelect: _multiSelect,
selectedList:
_selectedEpisodes ?? [],
onSelect: (value) => setState(() =>
_selectedEpisodes = value),
)
: SliverToBoxAdapter(
child: Center(),
@ -835,8 +868,19 @@ class _PodcastDetailState extends State<PodcastDetail> {
Tuple2(audio.playerRunning, audio.playerHeight),
builder: (_, data, __) {
var height = kMinPlayerHeight[data.item2.index];
return SizedBox(
height: data.item1 ? height : 0,
return Column(
children: [
if (_multiSelect)
MultiSelectMenuBar(
selectedList: _selectedEpisodes,
onClose: (value) {
setState(() => _multiSelect = false);
},
),
SizedBox(
height: data.item1 ? height : 0,
),
],
);
}),
],
@ -855,6 +899,150 @@ class _PodcastDetailState extends State<PodcastDetail> {
}
}
class MultiSelectMenuBar extends StatefulWidget {
MultiSelectMenuBar({this.selectedList, this.onClose, Key key})
: super(key: key);
final List<EpisodeBrief> selectedList;
final ValueChanged<bool> onClose;
@override
_MultiSelectMenuBarState createState() => _MultiSelectMenuBarState();
}
///Multi select menu bar.
class _MultiSelectMenuBarState extends State<MultiSelectMenuBar> {
bool _liked;
bool _marked;
bool _downloaded;
final _dbHelper = DBHelper();
@override
void initState() {
super.initState();
_liked = false;
_marked = false;
_downloaded = false;
}
@override
void didUpdateWidget(MultiSelectMenuBar oldWidget) {
if (oldWidget.selectedList != widget.selectedList) {
super.didUpdateWidget(oldWidget);
}
}
Future<void> _saveLiked() async {
for (var episode in widget.selectedList) {
await _dbHelper.setLiked(episode.enclosureUrl);
}
if (mounted) setState(() => _liked = true);
}
Future<void> _setUnliked() async {
for (var episode in widget.selectedList) {
await _dbHelper.setUniked(episode.enclosureUrl);
}
if (mounted) setState(() => _liked = false);
}
Future<void> _markListened() async {
for (var episode in widget.selectedList) {
final history = PlayHistory(episode.title, episode.enclosureUrl, 0, 1);
await _dbHelper.saveHistory(history);
}
if (mounted) setState(() => _marked = true);
}
Future<void> _markNotListened() async {
for (var episode in widget.selectedList) {
await _dbHelper.markNotListened(episode.enclosureUrl);
}
if (mounted) setState(() => _marked = false);
}
Widget _buttonOnMenu({Widget child, VoidCallback onTap}) => Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
child: SizedBox(
height: 50,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 15.0), child: child),
),
),
);
OverlayEntry _createOverlayEntry() {
RenderBox renderBox = context.findRenderObject();
var offset = renderBox.localToGlobal(Offset.zero);
return OverlayEntry(
builder: (constext) => Positioned(
left: offset.dx + 50,
top: offset.dy - 60,
child: Container(
width: 70,
height: 100,
//color: Colors.grey[200],
child: HeartOpen(width: 50, height: 80)),
),
);
}
@override
Widget build(BuildContext context) {
return Container(
height: 50.0,
decoration: BoxDecoration(color: context.primaryColor),
child: Row(
children: [
_buttonOnMenu(
child: _liked
? Icon(Icons.favorite, color: Colors.red)
: Icon(
Icons.favorite_border,
color: Colors.grey[700],
),
onTap: () async {
if (!_liked) {
await _saveLiked();
} else {
await _setUnliked();
}
// OverlayEntry _overlayEntry;
// _overlayEntry = _createOverlayEntry();
// Overlay.of(context).insert(_overlayEntry);
// await Future.delayed(Duration(seconds: 2));
// _overlayEntry?.remove();
}),
_buttonOnMenu(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 12),
child: CustomPaint(
size: Size(25, 20),
painter: ListenedAllPainter(
_marked ? context.accentColor : Colors.grey[700],
stroke: 2.0),
),
),
onTap: () async {
if (!_marked) {
await _markListened();
} else {
await _markNotListened();
}
}),
Spacer(),
Padding(
padding: EdgeInsets.symmetric(horizontal: 10.0),
child: Text('${widget.selectedList.length} selected',
style: context.textTheme.headline6)),
_buttonOnMenu(
child: Icon(Icons.close), onTap: () => widget.onClose(true))
],
),
);
}
}
class AboutPodcast extends StatefulWidget {
final PodcastLocal podcastLocal;
AboutPodcast({this.podcastLocal, Key key}) : super(key: key);

View File

@ -38,6 +38,36 @@ class LayoutPainter extends CustomPainter {
}
}
/// Multi select button.
class MultiSelectPainter extends CustomPainter {
Color color;
MultiSelectPainter({@required this.color});
@override
void paint(Canvas canvas, Size size) {
var paint = Paint()
..color = color
..strokeWidth = 1.0
..style = PaintingStyle.stroke
..strokeCap = StrokeCap.round;
final x = size.width / 2;
final y = size.height / 2;
var path = Path();
path.moveTo(0, 0);
path.lineTo(x, 0);
path.lineTo(x, y * 2);
path.lineTo(x * 2, y * 2);
path.lineTo(x * 2, y);
path.lineTo(0, y);
path.lineTo(0, 0);
canvas.drawPath(path, paint);
}
@override
bool shouldRepaint(MultiSelectPainter oldDelegate) {
return false;
}
}
//Dark sky used in sleep timer
class StarSky extends CustomPainter {
@override
@ -908,6 +938,7 @@ class DotIndicator extends StatelessWidget {
}
}
///Download button.
class DownloadPainter extends CustomPainter {
double fraction;
Color color;
@ -1021,7 +1052,7 @@ class LayoutButton extends StatelessWidget {
height: 10,
width: 30,
child: CustomPaint(
painter: LayoutPainter(0, context.textTheme.bodyText1.color),
painter: LayoutPainter(0, context.textColor),
),
)
: layout == Layout.two
@ -1029,8 +1060,7 @@ class LayoutButton extends StatelessWidget {
height: 10,
width: 30,
child: CustomPaint(
painter:
LayoutPainter(1, context.textTheme.bodyText1.color),
painter: LayoutPainter(1, context.textColor),
),
)
: SizedBox(

View File

@ -33,21 +33,29 @@ class EpisodeGrid extends StatelessWidget {
final int episodeCount;
final Layout layout;
final bool reverse;
final bool multiSelect;
final ValueChanged<List<EpisodeBrief>> onSelect;
final List<EpisodeBrief> selectedList;
/// Count of animation items.
final int initNum;
EpisodeGrid({
Key key,
@required this.episodes,
this.initNum = 12,
this.showDownload = false,
this.showFavorite = false,
this.showNumber = false,
this.episodeCount = 0,
this.layout = Layout.three,
this.reverse,
}) : super(key: key);
EpisodeGrid(
{Key key,
@required this.episodes,
this.initNum = 12,
this.showDownload = false,
this.showFavorite = false,
this.showNumber = false,
this.episodeCount = 0,
this.layout = Layout.three,
this.reverse,
this.multiSelect = false,
this.onSelect,
this.selectedList})
: super(key: key);
List<EpisodeBrief> _selectedList = [];
Future<int> _isListened(EpisodeBrief episode) async {
var dbHelper = DBHelper();
@ -201,10 +209,104 @@ class EpisodeGrid extends StatelessWidget {
color: color,
fontStyle: FontStyle.italic),
);
Widget _episodeCard(BuildContext context,
{int index, Color color, bool isLiked, bool isDownloaded, bool boo}) {
var width = context.width;
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
flex: layout == Layout.one ? 1 : 2,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
layout != Layout.one
? _circleImage(context,
episode: episodes[index], color: color, boo: boo)
: _pubDate(context, episode: episodes[index], color: color),
Spacer(),
_isNewIndicator(episodes[index]),
_downloadIndicater(context,
episode: episodes[index], isDownloaded: isDownloaded),
_numberIndicater(context, index: index, color: color)
],
),
),
Expanded(
flex: layout == Layout.one ? 3 : 5,
child: layout != Layout.one
? _title(episodes[index])
: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_circleImage(context,
episode: episodes[index], color: color, boo: boo),
SizedBox(
width: 5,
),
Expanded(child: _title(episodes[index]))
],
),
),
Expanded(
flex: 1,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
if (layout != Layout.one)
_pubDate(context, episode: episodes[index], color: color),
Spacer(),
if (layout != Layout.three && episodes[index].duration != 0)
Align(
alignment: Alignment.center,
child: Text(
episodes[index].duration.toTime,
style: TextStyle(fontSize: width / 35),
),
),
if (episodes[index].duration != 0 &&
episodes[index].enclosureLength != null &&
episodes[index].enclosureLength != 0 &&
layout != Layout.three)
Text(
'|',
style: TextStyle(
fontSize: width / 35,
),
),
if (layout != Layout.three &&
episodes[index].enclosureLength != null &&
episodes[index].enclosureLength != 0)
Align(
alignment: Alignment.center,
child: Text(
'${(episodes[index].enclosureLength) ~/ 1000000}MB',
style: TextStyle(fontSize: width / 35),
),
),
Padding(
padding: EdgeInsets.all(1),
),
if ((showFavorite || layout != Layout.three) && isLiked)
Icon(
Icons.favorite,
color: Colors.red,
size: width / 35,
)
],
),
),
],
),
);
}
@override
Widget build(BuildContext context) {
var _width = context.width;
var audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
var downloader = Provider.of<DownloadState>(context, listen: false);
final options = LiveOptions(
@ -273,300 +375,359 @@ class EpisodeGrid extends StatelessWidget {
),
]),
alignment: Alignment.center,
child: Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(5.0)),
border: Border.all(
color: context.brightness == Brightness.light
? context.primaryColor
: context.scaffoldBackgroundColor,
width: 1.0,
),
),
child: FocusedMenuHolder(
blurSize: 0.0,
menuItemExtent: 45,
menuBoxDecoration: BoxDecoration(
child: multiSelect
? Material(
color: Colors.transparent,
borderRadius:
BorderRadius.all(Radius.circular(15.0))),
duration: Duration(milliseconds: 100),
tapMode:
tapToOpen ? TapMode.onTap : TapMode.onLongPress,
animateMenuItems: false,
blurBackgroundColor:
context.brightness == Brightness.light
? Colors.white38
: Colors.black38,
bottomOffsetHeight: 10,
menuOffset: 6,
menuItems: <FocusedMenuItem>[
FocusedMenuItem(
backgroundColor:
context.brightness == Brightness.light
? context.primaryColor
: context.dialogBackgroundColor,
title: Text(data.item1 != episodes[index]
? s.play
: s.playing),
trailingIcon: Icon(
LineIcons.play_circle_solid,
color: Theme.of(context).accentColor,
),
onPressed: () {
if (data.item1 != episodes[index]) {
audio.episodeLoad(episodes[index]);
child: InkWell(
onTap: () {
if (!selectedList
.contains(episodes[index])) {
_selectedList = selectedList;
_selectedList.add(episodes[index]);
} else {
_selectedList = selectedList;
_selectedList.remove(episodes[index]);
}
}),
menuList.contains(1)
? FocusedMenuItem(
backgroundColor:
context.brightness == Brightness.light
? context.primaryColor
: context.dialogBackgroundColor,
title: data.item2.contains(
episodes[index].enclosureUrl)
? Text(s.remove)
: Text(s.later),
trailingIcon: Icon(
LineIcons.clock_solid,
color: Colors.cyan,
onSelect(_selectedList);
},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color: selectedList
.contains(episodes[index])
? context.accentColor
: context.brightness ==
Brightness.light
? context.primaryColor
: context
.scaffoldBackgroundColor,
width: 1.0,
),
onPressed: () {
if (!data.item2.contains(
episodes[index].enclosureUrl)) {
audio.addToPlaylist(episodes[index]);
Fluttertoast.showToast(
msg: s.toastAddPlaylist,
gravity: ToastGravity.BOTTOM,
);
} else {
audio
.delFromPlaylist(episodes[index]);
Fluttertoast.showToast(
msg: s.toastRemovePlaylist,
gravity: ToastGravity.BOTTOM,
);
}
})
: null,
menuList.contains(2)
? FocusedMenuItem(
backgroundColor:
context.brightness == Brightness.light
? context.primaryColor
: context.dialogBackgroundColor,
title: isLiked
? Text(s.unlike)
: Text(s.like),
trailingIcon: Icon(LineIcons.heart,
color: Colors.red, size: 21),
onPressed: () async {
if (isLiked) {
await _setUnliked(
episodes[index].enclosureUrl);
audio.setEpisodeState = true;
Fluttertoast.showToast(
msg: s.unliked,
gravity: ToastGravity.BOTTOM,
);
} else {
await _saveLiked(
episodes[index].enclosureUrl);
audio.setEpisodeState = true;
Fluttertoast.showToast(
msg: s.liked,
gravity: ToastGravity.BOTTOM,
);
}
})
: null,
menuList.contains(3)
? FocusedMenuItem(
backgroundColor:
context.brightness == Brightness.light
? context.primaryColor
: context.dialogBackgroundColor,
title: isListened > 0
? Text(s.markNotListened,
style: TextStyle(
color: context.textColor
.withOpacity(0.5)))
: Text(
s.markListened,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
trailingIcon: SizedBox(
width: 23,
height: 23,
child: CustomPaint(
painter: ListenedAllPainter(
Colors.blue,
stroke: 1.5)),
),
onPressed: () async {
if (isListened < 1) {
await _markListened(episodes[index]);
audio.setEpisodeState = true;
Fluttertoast.showToast(
msg: s.markListened,
gravity: ToastGravity.BOTTOM,
);
} else {
await _markNotListened(
episodes[index].enclosureUrl);
audio.setEpisodeState = true;
Fluttertoast.showToast(
msg: s.markNotListened,
gravity: ToastGravity.BOTTOM,
);
}
})
: null,
menuList.contains(4)
? FocusedMenuItem(
backgroundColor:
context.brightness == Brightness.light
? context.primaryColor
: context.dialogBackgroundColor,
title: isDownloaded
? Text(s.downloaded,
style: TextStyle(
color: context.textColor
.withOpacity(0.5)))
: Text(s.download),
trailingIcon: Icon(
LineIcons.download_solid,
color: Colors.green),
onPressed: () {
if (!isDownloaded) {
downloader.startTask(episodes[index]);
}
})
: null
],
action: action,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
flex: layout == Layout.one ? 1 : 2,
child: Row(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.center,
children: <Widget>[
layout != Layout.one
? _circleImage(context,
episode: episodes[index],
color: c,
boo: boo)
: _pubDate(context,
episode: episodes[index],
color: c),
Spacer(),
_isNewIndicator(episodes[index]),
_downloadIndicater(context,
episode: episodes[index],
isDownloaded: isDownloaded),
_numberIndicater(context,
index: index, color: c)
],
),
child: _episodeCard(context,
index: index,
isLiked: isLiked,
isDownloaded: isDownloaded,
color: c,
boo: boo),
),
Expanded(
flex: layout == Layout.one ? 3 : 5,
child: layout != Layout.one
? _title(episodes[index])
: Row(
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
_circleImage(context,
episode: episodes[index],
color: c,
boo: boo),
SizedBox(
width: 5,
),
Expanded(
child:
_title(episodes[index]))
],
),
),
)
: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color:
context.brightness == Brightness.light
? context.primaryColor
: context.scaffoldBackgroundColor,
width: 1.0,
),
Expanded(
flex: 1,
child: Row(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
children: <Widget>[
if (layout != Layout.one)
_pubDate(context,
episode: episodes[index],
color: c),
Spacer(),
if (layout != Layout.three &&
episodes[index].duration != 0)
Align(
alignment: Alignment.center,
child: Text(
episodes[index].duration.toTime,
style: TextStyle(
fontSize: _width / 35),
),
),
if (episodes[index].duration != 0 &&
episodes[index].enclosureLength !=
null &&
episodes[index].enclosureLength !=
0 &&
layout != Layout.three)
Text(
'|',
style: TextStyle(
fontSize: _width / 35,
),
),
if (layout != Layout.three &&
episodes[index].enclosureLength !=
null &&
episodes[index].enclosureLength !=
0)
Align(
alignment: Alignment.center,
child: Text(
'${(episodes[index].enclosureLength) ~/ 1000000}MB',
style: TextStyle(
fontSize: _width / 35),
),
),
Padding(
padding: EdgeInsets.all(1),
),
child: FocusedMenuHolder(
blurSize: 0.0,
menuItemExtent: 45,
menuBoxDecoration: BoxDecoration(
color: Colors.transparent,
borderRadius:
BorderRadius.circular(15.0)),
duration: Duration(milliseconds: 100),
tapMode: tapToOpen
? TapMode.onTap
: TapMode.onLongPress,
animateMenuItems: false,
blurBackgroundColor:
context.brightness == Brightness.light
? Colors.white38
: Colors.black38,
bottomOffsetHeight: 10,
menuOffset: 6,
menuItems: <FocusedMenuItem>[
FocusedMenuItem(
backgroundColor: context.brightness ==
Brightness.light
? context.primaryColor
: context.dialogBackgroundColor,
title: Text(
data.item1 != episodes[index]
? s.play
: s.playing),
trailingIcon: Icon(
LineIcons.play_circle_solid,
color: Theme.of(context).accentColor,
),
if ((showFavorite ||
layout != Layout.three) &&
isLiked)
Icon(
Icons.favorite,
color: Colors.red,
size: _width / 35,
)
],
),
),
],
onPressed: () {
if (data.item1 != episodes[index]) {
audio.episodeLoad(episodes[index]);
}
}),
menuList.contains(1)
? FocusedMenuItem(
backgroundColor: context
.brightness ==
Brightness.light
? context.primaryColor
: context.dialogBackgroundColor,
title: data.item2.contains(
episodes[index]
.enclosureUrl)
? Text(s.remove)
: Text(s.later),
trailingIcon: Icon(
LineIcons.clock_solid,
color: Colors.cyan,
),
onPressed: () {
if (!data.item2.contains(
episodes[index]
.enclosureUrl)) {
audio.addToPlaylist(
episodes[index]);
Fluttertoast.showToast(
msg: s.toastAddPlaylist,
gravity: ToastGravity.BOTTOM,
);
} else {
audio.delFromPlaylist(
episodes[index]);
Fluttertoast.showToast(
msg: s.toastRemovePlaylist,
gravity: ToastGravity.BOTTOM,
);
}
})
: null,
menuList.contains(2)
? FocusedMenuItem(
backgroundColor: context
.brightness ==
Brightness.light
? context.primaryColor
: context.dialogBackgroundColor,
title: isLiked
? Text(s.unlike)
: Text(s.like),
trailingIcon: Icon(LineIcons.heart,
color: Colors.red, size: 21),
onPressed: () async {
if (isLiked) {
await _setUnliked(
episodes[index]
.enclosureUrl);
audio.setEpisodeState = true;
Fluttertoast.showToast(
msg: s.unliked,
gravity: ToastGravity.BOTTOM,
);
} else {
await _saveLiked(episodes[index]
.enclosureUrl);
audio.setEpisodeState = true;
Fluttertoast.showToast(
msg: s.liked,
gravity: ToastGravity.BOTTOM,
);
}
})
: null,
menuList.contains(3)
? FocusedMenuItem(
backgroundColor: context
.brightness ==
Brightness.light
? context.primaryColor
: context.dialogBackgroundColor,
title: isListened > 0
? Text(s.markNotListened,
style: TextStyle(
color: context.textColor
.withOpacity(0.5)))
: Text(
s.markListened,
maxLines: 1,
overflow:
TextOverflow.ellipsis,
),
trailingIcon: SizedBox(
width: 23,
height: 23,
child: CustomPaint(
painter: ListenedAllPainter(
Colors.blue,
stroke: 1.5)),
),
onPressed: () async {
if (isListened < 1) {
await _markListened(
episodes[index]);
audio.setEpisodeState = true;
Fluttertoast.showToast(
msg: s.markListened,
gravity: ToastGravity.BOTTOM,
);
} else {
await _markNotListened(
episodes[index]
.enclosureUrl);
audio.setEpisodeState = true;
Fluttertoast.showToast(
msg: s.markNotListened,
gravity: ToastGravity.BOTTOM,
);
}
})
: null,
menuList.contains(4)
? FocusedMenuItem(
backgroundColor: context
.brightness ==
Brightness.light
? context.primaryColor
: context.dialogBackgroundColor,
title: isDownloaded
? Text(s.downloaded,
style: TextStyle(
color: context.textColor
.withOpacity(0.5)))
: Text(s.download),
trailingIcon: Icon(
LineIcons.download_solid,
color: Colors.green),
onPressed: () {
if (!isDownloaded) {
downloader
.startTask(episodes[index]);
}
})
: null
],
action: action,
child: _episodeCard(context,
index: index,
isLiked: isLiked,
isDownloaded: isDownloaded,
color: c,
boo: boo),
// Padding(
// padding: const EdgeInsets.all(8.0),
// child: Column(
// mainAxisAlignment: MainAxisAlignment.start,
// children: <Widget>[
// Expanded(
// flex: layout == Layout.one ? 1 : 2,
// child: Row(
// mainAxisAlignment:
// MainAxisAlignment.start,
// crossAxisAlignment:
// CrossAxisAlignment.center,
// children: <Widget>[
// layout != Layout.one
// ? _circleImage(context,
// episode: episodes[index],
// color: c,
// boo: boo)
// : _pubDate(context,
// episode: episodes[index],
// color: c),
// Spacer(),
// _isNewIndicator(episodes[index]),
// _downloadIndicater(context,
// episode: episodes[index],
// isDownloaded: isDownloaded),
// _numberIndicater(context,
// index: index, color: c)
// ],
// ),
// ),
// Expanded(
// flex: layout == Layout.one ? 3 : 5,
// child: layout != Layout.one
// ? _title(episodes[index])
// : Row(
// crossAxisAlignment:
// CrossAxisAlignment.center,
// children: [
// _circleImage(context,
// episode: episodes[index],
// color: c,
// boo: boo),
// SizedBox(
// width: 5,
// ),
// Expanded(
// child:
// _title(episodes[index]))
// ],
// ),
// ),
// Expanded(
// flex: 1,
// child: Row(
// crossAxisAlignment:
// CrossAxisAlignment.start,
// mainAxisAlignment:
// MainAxisAlignment.start,
// children: <Widget>[
// if (layout != Layout.one)
// _pubDate(context,
// episode: episodes[index],
// color: c),
// Spacer(),
// if (layout != Layout.three &&
// episodes[index].duration != 0)
// Align(
// alignment: Alignment.center,
// child: Text(
// episodes[index].duration.toTime,
// style: TextStyle(
// fontSize: _width / 35),
// ),
// ),
// if (episodes[index].duration != 0 &&
// episodes[index].enclosureLength !=
// null &&
// episodes[index].enclosureLength !=
// 0 &&
// layout != Layout.three)
// Text(
// '|',
// style: TextStyle(
// fontSize: _width / 35,
// ),
// ),
// if (layout != Layout.three &&
// episodes[index].enclosureLength !=
// null &&
// episodes[index].enclosureLength !=
// 0)
// Align(
// alignment: Alignment.center,
// child: Text(
// '${(episodes[index].enclosureLength) ~/ 1000000}MB',
// style: TextStyle(
// fontSize: _width / 35),
// ),
// ),
// Padding(
// padding: EdgeInsets.all(1),
// ),
// if ((showFavorite ||
// layout != Layout.three) &&
// isLiked)
// Icon(
// Icons.favorite,
// color: Colors.red,
// size: _width / 35,
// )
// ],
// ),
// ),
// ],
// ),
// ),
),
),
),
),
),
);
}),
),