mirror of
https://github.com/stonega/tsacdop
synced 2025-02-17 20:10:37 +01:00
Add multi select in podcast deatil page.
This commit is contained in:
parent
e1fe91983e
commit
4385c58668
@ -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),
|
||||
|
@ -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';
|
||||
|
@ -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(
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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(
|
||||
|
@ -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,
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
|
Loading…
x
Reference in New Issue
Block a user