mirror of
https://github.com/stonega/tsacdop
synced 2025-02-17 20:10:37 +01:00
Change episode popup menu style.
This commit is contained in:
parent
0c16ca95f3
commit
6ad2c7dc44
@ -11,7 +11,7 @@ Release date 2020/6/30
|
||||
### Bug fixed
|
||||
|
||||
* Crash on stop player.
|
||||
* Some donwload file didn't auto deleted.
|
||||
* Some download file didn't auto deleted.
|
||||
|
||||
## v0.3.5
|
||||
|
||||
|
@ -6,9 +6,9 @@
|
||||
|
||||
![CircleCI](https://img.shields.io/circleci/build/github/stonega/tsacdop?token=efe1331861e017144f2abb363acd95197e436dad)
|
||||
|
||||
![GitHub release (latest by date)](https://img.shields.io/github/v/release/stonega/tsacdop)
|
||||
|
||||
|
||||
[![GooglePlay](https://img.shields.io/badge/Google-PlayStore-%2323CCC6)](https://play.google.com/store/apps/details?id=com.stonegate.tsacdop)
|
||||
![GitHub release (latest by date)](https://img.shields.io/github/v/release/stonega/tsacdop) [![GooglePlay](https://img.shields.io/badge/Google-PlayStore-%2323CCC6)](https://play.google.com/store/apps/details?id=com.stonegate.tsacdop)
|
||||
|
||||
## About
|
||||
|
||||
@ -56,8 +56,6 @@ final environment = {"apiKey":"APIKEY", "shareKey":"SHAREKEY"};
|
||||
You can get own api key on [ListenNotes](https://www.listennotes.com/api/), basic plan is free to all, and replace "APIKEY" with it.
|
||||
If no api key added, the search function in the app won't work. But you can still add podcasts by serach rss link or import ompl file.
|
||||
|
||||
Share_key is used for generate clip.
|
||||
|
||||
## Known Issue
|
||||
|
||||
* Playlist unstable
|
||||
@ -74,3 +72,4 @@ A few resources to get you started if this is your first Flutter project:
|
||||
For help getting started with Flutter, view our
|
||||
[online documentation](https://flutter.dev/docs), which offers tutorials,
|
||||
samples, guidance on mobile development, and a full API reference.
|
||||
|
||||
|
@ -3,8 +3,11 @@ import 'dart:async';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:focused_menu/focused_menu.dart';
|
||||
import 'package:focused_menu/modals.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:tsacdop/util/episodegrid.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
import 'package:line_icons/line_icons.dart';
|
||||
|
||||
@ -469,12 +472,21 @@ class PodcastPreview extends StatelessWidget {
|
||||
class ShowEpisode extends StatelessWidget {
|
||||
final List<EpisodeBrief> episodes;
|
||||
final PodcastLocal podcastLocal;
|
||||
List<int> _menuList = [];
|
||||
ShowEpisode({Key key, this.episodes, this.podcastLocal}) : super(key: key);
|
||||
String _stringForSeconds(double seconds) {
|
||||
if (seconds == null) return null;
|
||||
return '${(seconds ~/ 60)}:${(seconds.truncate() % 60).toString().padLeft(2, '0')}';
|
||||
}
|
||||
|
||||
Future<Tuple3<int, bool, bool>> _initData(EpisodeBrief episode) async {
|
||||
int listened = await _isListened(episode);
|
||||
bool liked = await _isLiked(episode);
|
||||
bool downloaded = await _isDownloaded(episode);
|
||||
_menuList = await _getEpisodeMenu();
|
||||
return Tuple3(listened, liked, downloaded);
|
||||
}
|
||||
|
||||
Future<int> _isListened(EpisodeBrief episode) async {
|
||||
DBHelper dbHelper = DBHelper();
|
||||
return await dbHelper.isListened(episode.enclosureUrl);
|
||||
@ -506,186 +518,188 @@ class ShowEpisode extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
_saveLiked(String url) async {
|
||||
_saveLiked(String url) async {
|
||||
var dbHelper = DBHelper();
|
||||
await dbHelper.setLiked(url);
|
||||
await dbHelper.setLiked(url);
|
||||
}
|
||||
|
||||
_setUnliked(String url) async {
|
||||
var dbHelper = DBHelper();
|
||||
await dbHelper.setUniked(url);
|
||||
}
|
||||
|
||||
_showPopupMenu(Offset offset, EpisodeBrief episode, BuildContext context,
|
||||
bool isPlaying, bool isInPlaylist) async {
|
||||
var audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
|
||||
double left = offset.dx;
|
||||
double top = offset.dy;
|
||||
bool isLiked, isDownload;
|
||||
int isListened;
|
||||
var downloader = Provider.of<DownloadState>(context, listen: false);
|
||||
List<int> menuList = await _getEpisodeMenu();
|
||||
if (menuList.contains(3)) isListened = await _isListened(episode);
|
||||
if (menuList.contains(2)) isLiked = await _isLiked(episode);
|
||||
if (menuList.contains(4)) isDownload = await _isDownloaded(episode);
|
||||
await showMenu<int>(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(10))),
|
||||
context: context,
|
||||
position: RelativeRect.fromLTRB(left, top, context.width - left, 0),
|
||||
items: <PopupMenuEntry<int>>[
|
||||
PopupMenuItem(
|
||||
value: 0,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: <Widget>[
|
||||
Icon(
|
||||
LineIcons.play_circle_solid,
|
||||
color: Theme.of(context).accentColor,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
),
|
||||
!isPlaying ? Text('Play') : Text('Playing'),
|
||||
],
|
||||
),
|
||||
),
|
||||
menuList.contains(1)
|
||||
? PopupMenuItem(
|
||||
value: 1,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Icon(
|
||||
LineIcons.clock_solid,
|
||||
color: Colors.red,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
),
|
||||
!isInPlaylist ? Text('Later') : Text('Remove')
|
||||
],
|
||||
))
|
||||
: null,
|
||||
menuList.contains(2)
|
||||
? PopupMenuItem(
|
||||
value: 2,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Icon(LineIcons.heart, color: Colors.red, size: 21),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
),
|
||||
isLiked
|
||||
? Text(
|
||||
'Unlike',
|
||||
)
|
||||
: Text('Like')
|
||||
],
|
||||
))
|
||||
: null,
|
||||
menuList.contains(3)
|
||||
? PopupMenuItem(
|
||||
value: 3,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
SizedBox(
|
||||
width: 23,
|
||||
height: 23,
|
||||
child: CustomPaint(
|
||||
painter:
|
||||
ListenedAllPainter(Colors.blue, stroke: 1.5)),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
),
|
||||
isListened > 0
|
||||
? Text('Listened',
|
||||
style: TextStyle(
|
||||
color: context.textColor.withOpacity(0.5)))
|
||||
: Text('Mark\nListened')
|
||||
],
|
||||
))
|
||||
: null,
|
||||
menuList.contains(4)
|
||||
? PopupMenuItem(
|
||||
value: 4,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Icon(LineIcons.download_solid, color: Colors.green),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
),
|
||||
isDownload
|
||||
? Text('Downloaded',
|
||||
style: TextStyle(
|
||||
color: context.textColor.withOpacity(0.5)))
|
||||
: Text('Download')
|
||||
],
|
||||
))
|
||||
: null,
|
||||
],
|
||||
elevation: 5.0,
|
||||
).then((value) async {
|
||||
switch (value) {
|
||||
case 0:
|
||||
if (!isPlaying) audio.episodeLoad(episode);
|
||||
break;
|
||||
case 1:
|
||||
if (!isInPlaylist) {
|
||||
audio.addToPlaylist(episode);
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Added to playlist',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
} else {
|
||||
audio.delFromPlaylist(episode);
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Removed from playlist',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (isLiked) {
|
||||
await _setUnliked(episode.enclosureUrl);
|
||||
audio.setEpisodeState = true;
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Unliked',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
} else {
|
||||
await _saveLiked(episode.enclosureUrl);
|
||||
audio.setEpisodeState = true;
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Liked',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (isListened < 1) {
|
||||
await _markListened(episode);
|
||||
audio.setEpisodeState = true;
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Mark listened',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (!isDownload) downloader.startTask(episode);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
await dbHelper.setUniked(url);
|
||||
}
|
||||
|
||||
// _showPopupMenu(Offset offset, EpisodeBrief episode, BuildContext context,
|
||||
// bool isPlaying, bool isInPlaylist) async {
|
||||
// var audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
|
||||
// double left = offset.dx;
|
||||
// double top = offset.dy;
|
||||
// bool isLiked, isDownload;
|
||||
// int isListened;
|
||||
// var downloader = Provider.of<DownloadState>(context, listen: false);
|
||||
// List<int> menuList = await _getEpisodeMenu();
|
||||
// if (menuList.contains(3)) isListened = await _isListened(episode);
|
||||
// if (menuList.contains(2)) isLiked = await _isLiked(episode);
|
||||
// if (menuList.contains(4)) isDownload = await _isDownloaded(episode);
|
||||
// await showMenu<int>(
|
||||
// shape: RoundedRectangleBorder(
|
||||
// borderRadius: BorderRadius.all(Radius.circular(10))),
|
||||
// context: context,
|
||||
// position: RelativeRect.fromLTRB(left, top, context.width - left, 0),
|
||||
// items: <PopupMenuEntry<int>>[
|
||||
// PopupMenuItem(
|
||||
// value: 0,
|
||||
// child: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.start,
|
||||
// mainAxisSize: MainAxisSize.max,
|
||||
// children: <Widget>[
|
||||
// Icon(
|
||||
// LineIcons.play_circle_solid,
|
||||
// color: Theme.of(context).accentColor,
|
||||
// ),
|
||||
// Padding(
|
||||
// padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
// ),
|
||||
// !isPlaying ? Text('Play') : Text('Playing'),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// menuList.contains(1)
|
||||
// ? PopupMenuItem(
|
||||
// value: 1,
|
||||
// child: Row(
|
||||
// children: <Widget>[
|
||||
// Icon(
|
||||
// LineIcons.clock_solid,
|
||||
// color: Colors.red,
|
||||
// ),
|
||||
// Padding(
|
||||
// padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
// ),
|
||||
// !isInPlaylist ? Text('Later') : Text('Remove')
|
||||
// ],
|
||||
// ))
|
||||
// : null,
|
||||
// menuList.contains(2)
|
||||
// ? PopupMenuItem(
|
||||
// value: 2,
|
||||
// child: Row(
|
||||
// children: <Widget>[
|
||||
// Icon(LineIcons.heart, color: Colors.red, size: 21),
|
||||
// Padding(
|
||||
// padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
// ),
|
||||
// isLiked
|
||||
// ? Text(
|
||||
// 'Unlike',
|
||||
// )
|
||||
// : Text('Like')
|
||||
// ],
|
||||
// ))
|
||||
// : null,
|
||||
// menuList.contains(3)
|
||||
// ? PopupMenuItem(
|
||||
// value: 3,
|
||||
// child: Row(
|
||||
// children: <Widget>[
|
||||
// SizedBox(
|
||||
// width: 23,
|
||||
// height: 23,
|
||||
// child: CustomPaint(
|
||||
// painter:
|
||||
// ListenedAllPainter(Colors.blue, stroke: 1.5)),
|
||||
// ),
|
||||
// Padding(
|
||||
// padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
// ),
|
||||
// isListened > 0
|
||||
// ? Text('Listened',
|
||||
// style: TextStyle(
|
||||
// color: context.textColor.withOpacity(0.5)))
|
||||
// : Text('Mark\nListened')
|
||||
// ],
|
||||
// ))
|
||||
// : null,
|
||||
// menuList.contains(4)
|
||||
// ? PopupMenuItem(
|
||||
// value: 4,
|
||||
// child: Row(
|
||||
// children: <Widget>[
|
||||
// Icon(LineIcons.download_solid, color: Colors.green),
|
||||
// Padding(
|
||||
// padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
// ),
|
||||
// isDownload
|
||||
// ? Text('Downloaded',
|
||||
// style: TextStyle(
|
||||
// color: context.textColor.withOpacity(0.5)))
|
||||
// : Text('Download')
|
||||
// ],
|
||||
// ))
|
||||
// : null,
|
||||
// ],
|
||||
// elevation: 5.0,
|
||||
// ).then((value) async {
|
||||
// switch (value) {
|
||||
// case 0:
|
||||
// if (!isPlaying) audio.episodeLoad(episode);
|
||||
// break;
|
||||
// case 1:
|
||||
// if (!isInPlaylist) {
|
||||
// audio.addToPlaylist(episode);
|
||||
// Fluttertoast.showToast(
|
||||
// msg: 'Added to playlist',
|
||||
// gravity: ToastGravity.BOTTOM,
|
||||
// );
|
||||
// } else {
|
||||
// audio.delFromPlaylist(episode);
|
||||
// Fluttertoast.showToast(
|
||||
// msg: 'Removed from playlist',
|
||||
// gravity: ToastGravity.BOTTOM,
|
||||
// );
|
||||
// }
|
||||
// break;
|
||||
// case 2:
|
||||
// if (isLiked) {
|
||||
// await _setUnliked(episode.enclosureUrl);
|
||||
// audio.setEpisodeState = true;
|
||||
// Fluttertoast.showToast(
|
||||
// msg: 'Unliked',
|
||||
// gravity: ToastGravity.BOTTOM,
|
||||
// );
|
||||
// } else {
|
||||
// await _saveLiked(episode.enclosureUrl);
|
||||
// audio.setEpisodeState = true;
|
||||
// Fluttertoast.showToast(
|
||||
// msg: 'Liked',
|
||||
// gravity: ToastGravity.BOTTOM,
|
||||
// );
|
||||
// }
|
||||
// break;
|
||||
// case 3:
|
||||
// if (isListened < 1) {
|
||||
// await _markListened(episode);
|
||||
// audio.setEpisodeState = true;
|
||||
// Fluttertoast.showToast(
|
||||
// msg: 'Mark listened',
|
||||
// gravity: ToastGravity.BOTTOM,
|
||||
// );
|
||||
// }
|
||||
// break;
|
||||
//
|
||||
// case 4:
|
||||
// if (!isDownload) downloader.startTask(episode);
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
double _width = context.width;
|
||||
var downloader = Provider.of<DownloadState>(context, listen: false);
|
||||
var audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
|
||||
Offset offset;
|
||||
return CustomScrollView(
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
@ -706,186 +720,365 @@ class ShowEpisode extends StatelessWidget {
|
||||
? podcastLocal.primaryColor.colorizedark()
|
||||
: podcastLocal.primaryColor.colorizeLight();
|
||||
return Selector<AudioPlayerNotifier,
|
||||
Tuple2<EpisodeBrief, List<String>>>(
|
||||
selector: (_, audio) => Tuple2(
|
||||
audio?.episode,
|
||||
audio.queue.playlist.map((e) => e.enclosureUrl).toList(),
|
||||
),
|
||||
builder: (_, data, __) => Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(5.0)),
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.all(Radius.circular(5.0)),
|
||||
onTapDown: (details) => offset = Offset(
|
||||
details.globalPosition.dx,
|
||||
details.globalPosition.dy),
|
||||
onLongPress: () => _showPopupMenu(
|
||||
offset,
|
||||
episodes[index],
|
||||
context,
|
||||
data.item1 == episodes[index],
|
||||
data.item2.contains(episodes[index].enclosureUrl)),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
ScaleRoute(
|
||||
page: EpisodeDetail(
|
||||
episodeItem: episodes[index],
|
||||
heroTag: 'scroll',
|
||||
//unique hero tag
|
||||
)),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
Tuple2<EpisodeBrief, List<String>>>(
|
||||
selector: (_, audio) => Tuple2(
|
||||
audio?.episode,
|
||||
audio.queue.playlist
|
||||
.map((e) => e.enclosureUrl)
|
||||
.toList(),
|
||||
),
|
||||
builder: (_, data, __) => FutureBuilder<
|
||||
Tuple3<int, bool, bool>>(
|
||||
future: _initData(episodes[index]),
|
||||
initialData: Tuple3(0, false, false),
|
||||
builder:
|
||||
(BuildContext context, AsyncSnapshot snapshot) {
|
||||
int isListened = snapshot.data.item1;
|
||||
bool isLiked = snapshot.data.item2;
|
||||
bool isDownloaded = snapshot.data.item3;
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(5.0)),
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child:
|
||||
// InkWell(
|
||||
// borderRadius:
|
||||
// BorderRadius.all(Radius.circular(5.0)),
|
||||
// onTapDown: (details) => offset = Offset(
|
||||
// details.globalPosition.dx,
|
||||
// details.globalPosition.dy),
|
||||
// onLongPress: () => _showPopupMenu(
|
||||
// offset,
|
||||
// episodes[index],
|
||||
// context,
|
||||
// data.item1 == episodes[index],
|
||||
// data.item2.contains(
|
||||
// episodes[index].enclosureUrl)),
|
||||
// onTap: () {
|
||||
//
|
||||
// },
|
||||
FocusedMenuHolder(
|
||||
blurSize: 0.0,
|
||||
menuItemExtent: 45,
|
||||
menuBoxDecoration: BoxDecoration(
|
||||
color: Colors.transparent,
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(15.0))),
|
||||
duration: Duration(milliseconds: 100),
|
||||
tapMode: 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.scaffoldBackgroundColor,
|
||||
title: Text(data.item1 != episodes[index]
|
||||
? "Play"
|
||||
: "Playing"),
|
||||
trailingIcon: Icon(
|
||||
LineIcons.play_circle_solid,
|
||||
color: Theme.of(context).accentColor,
|
||||
),
|
||||
onPressed: () {
|
||||
if (data.item1 != episodes[index])
|
||||
audio.episodeLoad(episodes[index]);
|
||||
}),
|
||||
_menuList.contains(1)
|
||||
? FocusedMenuItem(
|
||||
backgroundColor: context.brightness ==
|
||||
Brightness.light
|
||||
? context.primaryColor
|
||||
: context.scaffoldBackgroundColor,
|
||||
title: data.item2.contains(
|
||||
episodes[index].enclosureUrl)
|
||||
? Text("Remove")
|
||||
: Text("Later"),
|
||||
trailingIcon: Icon(
|
||||
LineIcons.clock_solid,
|
||||
color: Colors.cyan,
|
||||
),
|
||||
onPressed: () {
|
||||
if (!data.item2.contains(
|
||||
episodes[index].enclosureUrl)) {
|
||||
audio
|
||||
.addToPlaylist(episodes[index]);
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Added to playlist',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
} else {
|
||||
audio.delFromPlaylist(
|
||||
episodes[index]);
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Removed from playlist',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
})
|
||||
: null,
|
||||
_menuList.contains(2)
|
||||
? FocusedMenuItem(
|
||||
backgroundColor: context.brightness ==
|
||||
Brightness.light
|
||||
? context.primaryColor
|
||||
: context.scaffoldBackgroundColor,
|
||||
title: isLiked
|
||||
? Text("Unlike")
|
||||
: Text("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: 'Unliked',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
} else {
|
||||
await _saveLiked(
|
||||
episodes[index].enclosureUrl);
|
||||
audio.setEpisodeState = true;
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Liked',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
})
|
||||
: null,
|
||||
_menuList.contains(3)
|
||||
? FocusedMenuItem(
|
||||
backgroundColor: context.brightness ==
|
||||
Brightness.light
|
||||
? context.primaryColor
|
||||
: context.scaffoldBackgroundColor,
|
||||
title: isListened > 0
|
||||
? Text('Listened',
|
||||
style: TextStyle(
|
||||
color: context.textColor
|
||||
.withOpacity(0.5)))
|
||||
: Text(
|
||||
'Mark Listened',
|
||||
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: 'Mark listened',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
})
|
||||
: null,
|
||||
_menuList.contains(4)
|
||||
? FocusedMenuItem(
|
||||
backgroundColor: context.brightness ==
|
||||
Brightness.light
|
||||
? context.primaryColor
|
||||
: context.scaffoldBackgroundColor,
|
||||
title: isDownloaded
|
||||
? Text('Downloaded',
|
||||
style: TextStyle(
|
||||
color: context.textColor
|
||||
.withOpacity(0.5)))
|
||||
: Text('Download'),
|
||||
trailingIcon: Icon(
|
||||
LineIcons.download_solid,
|
||||
color: Colors.green),
|
||||
onPressed: () {
|
||||
if (!isDownloaded)
|
||||
downloader
|
||||
.startTask(episodes[index]);
|
||||
})
|
||||
: null
|
||||
],
|
||||
action: () => Navigator.push(
|
||||
context,
|
||||
ScaleRoute(
|
||||
page: EpisodeDetail(
|
||||
episodeItem: episodes[index],
|
||||
heroTag: 'scroll',
|
||||
//unique hero tag
|
||||
)),
|
||||
),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Hero(
|
||||
tag: episodes[index].enclosureUrl +
|
||||
'scroll',
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Hero(
|
||||
tag: episodes[index].enclosureUrl +
|
||||
'scroll',
|
||||
child: Container(
|
||||
height: _width / 18,
|
||||
width: _width / 18,
|
||||
child: CircleAvatar(
|
||||
backgroundImage: FileImage(File(
|
||||
"${podcastLocal.imagePath}")),
|
||||
),
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
Selector<AudioPlayerNotifier,
|
||||
Tuple2<EpisodeBrief, bool>>(
|
||||
selector: (_, audio) => Tuple2(
|
||||
audio.episode,
|
||||
audio.playerRunning),
|
||||
builder: (_, data, __) {
|
||||
return (episodes[index]
|
||||
.enclosureUrl ==
|
||||
data.item1
|
||||
?.enclosureUrl &&
|
||||
data.item2)
|
||||
? Container(
|
||||
height: 20,
|
||||
width: 20,
|
||||
margin: EdgeInsets
|
||||
.symmetric(
|
||||
horizontal: 2),
|
||||
decoration:
|
||||
BoxDecoration(
|
||||
shape:
|
||||
BoxShape.circle,
|
||||
),
|
||||
child: WaveLoader(
|
||||
color: context
|
||||
.accentColor))
|
||||
: Center();
|
||||
}),
|
||||
episodes[index].isNew == 1
|
||||
? Text(
|
||||
'New',
|
||||
style: TextStyle(
|
||||
color: Colors.red,
|
||||
fontStyle:
|
||||
FontStyle.italic),
|
||||
)
|
||||
: Center(),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 5,
|
||||
child: Container(
|
||||
height: _width / 18,
|
||||
width: _width / 18,
|
||||
child: CircleAvatar(
|
||||
backgroundImage: FileImage(File(
|
||||
"${podcastLocal.imagePath}")),
|
||||
padding: EdgeInsets.only(top: 2.0),
|
||||
alignment: Alignment.topLeft,
|
||||
child: Text(
|
||||
episodes[index].title,
|
||||
style: TextStyle(
|
||||
//fontSize: _width / 32,
|
||||
),
|
||||
maxLines: 4,
|
||||
overflow: TextOverflow.fade,
|
||||
),
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
Selector<AudioPlayerNotifier,
|
||||
Tuple2<EpisodeBrief, bool>>(
|
||||
selector: (_, audio) => Tuple2(
|
||||
audio.episode, audio.playerRunning),
|
||||
builder: (_, data, __) {
|
||||
return (episodes[index]
|
||||
.enclosureUrl ==
|
||||
data.item1
|
||||
?.enclosureUrl &&
|
||||
data.item2)
|
||||
? Container(
|
||||
height: 20,
|
||||
width: 20,
|
||||
margin: EdgeInsets.symmetric(
|
||||
horizontal: 2),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
alignment: Alignment.bottomLeft,
|
||||
child: Text(
|
||||
episodes[index].dateToString(),
|
||||
//podcast[index].pubDate.substring(4, 16),
|
||||
style: TextStyle(
|
||||
fontSize: _width / 35,
|
||||
color: _c,
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
episodes[index].duration != 0
|
||||
? Container(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
_stringForSeconds(
|
||||
episodes[index]
|
||||
.duration
|
||||
.toDouble())
|
||||
.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: _width / 35,
|
||||
// color: _c,
|
||||
// fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Center(),
|
||||
episodes[index].duration == 0 ||
|
||||
episodes[index]
|
||||
.enclosureLength ==
|
||||
null ||
|
||||
episodes[index]
|
||||
.enclosureLength ==
|
||||
0
|
||||
? Center()
|
||||
: Text(
|
||||
'|',
|
||||
style: TextStyle(
|
||||
fontSize: _width / 35,
|
||||
// color: _c,
|
||||
// fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
child: WaveLoader(
|
||||
color:
|
||||
context.accentColor))
|
||||
: Center();
|
||||
}),
|
||||
episodes[index].isNew == 1
|
||||
? Text(
|
||||
'New',
|
||||
style: TextStyle(
|
||||
color: Colors.red,
|
||||
fontStyle: FontStyle.italic),
|
||||
)
|
||||
: Center(),
|
||||
episodes[index].enclosureLength !=
|
||||
null &&
|
||||
episodes[index]
|
||||
.enclosureLength !=
|
||||
0
|
||||
? Container(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
((episodes[index]
|
||||
.enclosureLength) ~/
|
||||
1000000)
|
||||
.toString() +
|
||||
'MB',
|
||||
style: TextStyle(
|
||||
fontSize:
|
||||
_width / 35),
|
||||
),
|
||||
)
|
||||
: Center(),
|
||||
],
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 5,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 2.0),
|
||||
alignment: Alignment.topLeft,
|
||||
child: Text(
|
||||
episodes[index].title,
|
||||
style: TextStyle(
|
||||
//fontSize: _width / 32,
|
||||
),
|
||||
maxLines: 4,
|
||||
overflow: TextOverflow.fade,
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
alignment: Alignment.bottomLeft,
|
||||
child: Text(
|
||||
episodes[index].dateToString(),
|
||||
//podcast[index].pubDate.substring(4, 16),
|
||||
style: TextStyle(
|
||||
fontSize: _width / 35,
|
||||
color: _c,
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
episodes[index].duration != 0
|
||||
? Container(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
_stringForSeconds(
|
||||
episodes[index]
|
||||
.duration
|
||||
.toDouble())
|
||||
.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: _width / 35,
|
||||
// color: _c,
|
||||
// fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Center(),
|
||||
episodes[index].duration == 0 ||
|
||||
episodes[index].enclosureLength ==
|
||||
null ||
|
||||
episodes[index].enclosureLength ==
|
||||
0
|
||||
? Center()
|
||||
: Text(
|
||||
'|',
|
||||
style: TextStyle(
|
||||
fontSize: _width / 35,
|
||||
// color: _c,
|
||||
// fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
episodes[index].enclosureLength != null &&
|
||||
episodes[index].enclosureLength !=
|
||||
0
|
||||
? Container(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
((episodes[index]
|
||||
.enclosureLength) ~/
|
||||
1000000)
|
||||
.toString() +
|
||||
'MB',
|
||||
style: TextStyle(
|
||||
fontSize: _width / 35),
|
||||
),
|
||||
)
|
||||
: Center(),
|
||||
],
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
),
|
||||
);
|
||||
}));
|
||||
},
|
||||
childCount: (episodes.length > 2) ? 2 : episodes.length,
|
||||
),
|
||||
|
@ -2,12 +2,15 @@ import 'dart:io';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:focused_menu/focused_menu.dart';
|
||||
import 'package:focused_menu/modals.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
import 'package:line_icons/line_icons.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:auto_animated/auto_animated.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
import 'open_container.dart';
|
||||
|
||||
import '../state/audiostate.dart';
|
||||
@ -22,6 +25,7 @@ import 'custompaint.dart';
|
||||
|
||||
enum Layout { three, two, one }
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class EpisodeGrid extends StatelessWidget {
|
||||
final List<EpisodeBrief> episodes;
|
||||
final bool showFavorite;
|
||||
@ -43,11 +47,22 @@ class EpisodeGrid extends StatelessWidget {
|
||||
this.reverse,
|
||||
}) : super(key: key);
|
||||
|
||||
List<int> _menuList = [];
|
||||
|
||||
Future<int> _isListened(EpisodeBrief episode) async {
|
||||
DBHelper dbHelper = DBHelper();
|
||||
_menuList = await _getEpisodeMenu();
|
||||
return await dbHelper.isListened(episode.enclosureUrl);
|
||||
}
|
||||
|
||||
Future<Tuple3<int, bool, bool>> _initData(EpisodeBrief episode) async {
|
||||
int listened = await _isListened(episode);
|
||||
bool liked = await _isLiked(episode);
|
||||
bool downloaded = await _isDownloaded(episode);
|
||||
_menuList = await _getEpisodeMenu();
|
||||
return Tuple3(listened, liked, downloaded);
|
||||
}
|
||||
|
||||
Future<bool> _isLiked(EpisodeBrief episode) async {
|
||||
DBHelper dbHelper = DBHelper();
|
||||
return await dbHelper.isLiked(episode.enclosureUrl);
|
||||
@ -148,27 +163,26 @@ class EpisodeGrid extends StatelessWidget {
|
||||
// : Center();
|
||||
// });
|
||||
|
||||
Widget _downloadIndicater(BuildContext context, {EpisodeBrief episode}) =>
|
||||
Widget _downloadIndicater(BuildContext context,
|
||||
{EpisodeBrief episode, bool isDownloaded}) =>
|
||||
showDownload || layout != Layout.three
|
||||
? Container(
|
||||
child: (episode.enclosureUrl != episode.mediaId)
|
||||
? Container(
|
||||
height: 20,
|
||||
width: 20,
|
||||
margin: EdgeInsets.symmetric(horizontal: 5),
|
||||
padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: context.accentColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.done_all,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
)
|
||||
: Center(),
|
||||
)
|
||||
? isDownloaded
|
||||
? Container(
|
||||
height: 20,
|
||||
width: 20,
|
||||
margin: EdgeInsets.symmetric(horizontal: 5),
|
||||
padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: context.accentColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.done_all,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
)
|
||||
: Center()
|
||||
: Center();
|
||||
|
||||
Widget _isNewIndicator(EpisodeBrief episode) => episode.isNew == 1
|
||||
@ -209,172 +223,174 @@ class EpisodeGrid extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
double _width = context.width;
|
||||
Offset _offset;
|
||||
_showPopupMenu(Offset offset, EpisodeBrief episode, BuildContext context,
|
||||
{bool isPlaying, bool isInPlaylist}) async {
|
||||
bool isLiked, isDownload;
|
||||
int isListened;
|
||||
var audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
|
||||
var downloader = Provider.of<DownloadState>(context, listen: false);
|
||||
double left = offset.dx;
|
||||
double top = offset.dy;
|
||||
List<int> menuList = await _getEpisodeMenu();
|
||||
if (menuList.contains(3)) isListened = await _isListened(episode);
|
||||
if (menuList.contains(2)) isLiked = await _isLiked(episode);
|
||||
if (menuList.contains(4)) isDownload = await _isDownloaded(episode);
|
||||
await showMenu<int>(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(10))),
|
||||
context: context,
|
||||
position: RelativeRect.fromLTRB(left, top, _width - left, 0),
|
||||
items: <PopupMenuEntry<int>>[
|
||||
PopupMenuItem(
|
||||
value: 0,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: <Widget>[
|
||||
Icon(
|
||||
LineIcons.play_circle_solid,
|
||||
color: Theme.of(context).accentColor,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
),
|
||||
!isPlaying ? Text('Play') : Text('Playing'),
|
||||
],
|
||||
),
|
||||
),
|
||||
menuList.contains(1)
|
||||
? PopupMenuItem(
|
||||
value: 1,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Icon(
|
||||
LineIcons.clock_solid,
|
||||
color: Colors.cyan,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
),
|
||||
!isInPlaylist ? Text('Later') : Text('Remove')
|
||||
],
|
||||
))
|
||||
: null,
|
||||
menuList.contains(2)
|
||||
? PopupMenuItem(
|
||||
value: 2,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Icon(LineIcons.heart, color: Colors.red, size: 21),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
),
|
||||
isLiked
|
||||
? Text(
|
||||
'Unlike',
|
||||
)
|
||||
: Text('Like')
|
||||
],
|
||||
))
|
||||
: null,
|
||||
menuList.contains(3)
|
||||
? PopupMenuItem(
|
||||
value: 3,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
SizedBox(
|
||||
width: 23,
|
||||
height: 23,
|
||||
child: CustomPaint(
|
||||
painter:
|
||||
ListenedAllPainter(Colors.blue, stroke: 1.5)),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
),
|
||||
isListened > 0
|
||||
? Text('Listened',
|
||||
style: TextStyle(
|
||||
color: context.textColor.withOpacity(0.5)))
|
||||
: Text('Mark\nListened')
|
||||
],
|
||||
))
|
||||
: null,
|
||||
menuList.contains(4)
|
||||
? PopupMenuItem(
|
||||
value: 4,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Icon(LineIcons.download_solid, color: Colors.green),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
),
|
||||
isDownload
|
||||
? Text('Downloaded',
|
||||
style: TextStyle(
|
||||
color: context.textColor.withOpacity(0.5)))
|
||||
: Text('Download')
|
||||
],
|
||||
))
|
||||
: null,
|
||||
],
|
||||
elevation: 5.0,
|
||||
).then((value) async {
|
||||
switch (value) {
|
||||
case 0:
|
||||
if (!isPlaying) audio.episodeLoad(episode);
|
||||
break;
|
||||
case 1:
|
||||
if (!isInPlaylist) {
|
||||
audio.addToPlaylist(episode);
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Added to playlist',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
} else {
|
||||
audio.delFromPlaylist(episode);
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Removed from playlist',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (isLiked) {
|
||||
await _setUnliked(episode.enclosureUrl);
|
||||
audio.setEpisodeState = true;
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Unliked',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
} else {
|
||||
await _saveLiked(episode.enclosureUrl);
|
||||
audio.setEpisodeState = true;
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Liked',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (isListened < 1) {
|
||||
await _markListened(episode);
|
||||
audio.setEpisodeState = true;
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Mark listened',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (!isDownload) downloader.startTask(episode);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
var audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
|
||||
var downloader = Provider.of<DownloadState>(context, listen: false);
|
||||
//Offset _offset;
|
||||
//_showPopupMenu(Offset offset, EpisodeBrief episode, BuildContext context,
|
||||
// {bool isPlaying, bool isInPlaylist}) async {
|
||||
// bool isLiked, isDownload;
|
||||
// int isListened;
|
||||
// var audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
|
||||
// var downloader = Provider.of<DownloadState>(context, listen: false);
|
||||
// double left = offset.dx;
|
||||
// double top = offset.dy;
|
||||
// List<int> menuList = await _getEpisodeMenu();
|
||||
// if (menuList.contains(3)) isListened = await _isListened(episode);
|
||||
// if (menuList.contains(2)) isLiked = await _isLiked(episode);
|
||||
// if (menuList.contains(4)) isDownload = await _isDownloaded(episode);
|
||||
// await showMenu<int>(
|
||||
// shape: RoundedRectangleBorder(
|
||||
// borderRadius: BorderRadius.all(Radius.circular(10))),
|
||||
// context: context,
|
||||
// position: RelativeRect.fromLTRB(left, top, _width - left, 0),
|
||||
// items: <PopupMenuEntry<int>>[
|
||||
// PopupMenuItem(
|
||||
// value: 0,
|
||||
// child: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.start,
|
||||
// mainAxisSize: MainAxisSize.max,
|
||||
// children: <Widget>[
|
||||
// Icon(
|
||||
// LineIcons.play_circle_solid,
|
||||
// color: Theme.of(context).accentColor,
|
||||
// ),
|
||||
// Padding(
|
||||
// padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
// ),
|
||||
// !isPlaying ? Text('Play') : Text('Playing'),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// menuList.contains(1)
|
||||
// ? PopupMenuItem(
|
||||
// value: 1,
|
||||
// child: Row(
|
||||
// children: <Widget>[
|
||||
// Icon(
|
||||
// LineIcons.clock_solid,
|
||||
// color: Colors.cyan,
|
||||
// ),
|
||||
// Padding(
|
||||
// padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
// ),
|
||||
// !isInPlaylist ? Text('Later') : Text('Remove')
|
||||
// ],
|
||||
// ))
|
||||
// : null,
|
||||
// menuList.contains(2)
|
||||
// ? PopupMenuItem(
|
||||
// value: 2,
|
||||
// child: Row(
|
||||
// children: <Widget>[
|
||||
// Icon(LineIcons.heart, color: Colors.red, size: 21),
|
||||
// Padding(
|
||||
// padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
// ),
|
||||
// isLiked
|
||||
// ? Text(
|
||||
// 'Unlike',
|
||||
// )
|
||||
// : Text('Like')
|
||||
// ],
|
||||
// ))
|
||||
// : null,
|
||||
// menuList.contains(3)
|
||||
// ? PopupMenuItem(
|
||||
// value: 3,
|
||||
// child: Row(
|
||||
// children: <Widget>[
|
||||
// SizedBox(
|
||||
// width: 23,
|
||||
// height: 23,
|
||||
// child: CustomPaint(
|
||||
// painter:
|
||||
// ListenedAllPainter(Colors.blue, stroke: 1.5)),
|
||||
// ),
|
||||
// Padding(
|
||||
// padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
// ),
|
||||
// isListened > 0
|
||||
// ? Text('Listened',
|
||||
// style: TextStyle(
|
||||
// color: context.textColor.withOpacity(0.5)))
|
||||
// : Text('Mark\nListened')
|
||||
// ],
|
||||
// ))
|
||||
// : null,
|
||||
// menuList.contains(4)
|
||||
// ? PopupMenuItem(
|
||||
// value: 4,
|
||||
// child: Row(
|
||||
// children: <Widget>[
|
||||
// Icon(LineIcons.download_solid, color: Colors.green),
|
||||
// Padding(
|
||||
// padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
// ),
|
||||
// isDownload
|
||||
// ? Text('Downloaded',
|
||||
// style: TextStyle(
|
||||
// color: context.textColor.withOpacity(0.5)))
|
||||
// : Text('Download')
|
||||
// ],
|
||||
// ))
|
||||
// : null,
|
||||
// ],
|
||||
// elevation: 5.0,
|
||||
// ).then((value) async {
|
||||
// switch (value) {
|
||||
// case 0:
|
||||
// if (!isPlaying) audio.episodeLoad(episode);
|
||||
// break;
|
||||
// case 1:
|
||||
// if (!isInPlaylist) {
|
||||
// audio.addToPlaylist(episode);
|
||||
// Fluttertoast.showToast(
|
||||
// msg: 'Added to playlist',
|
||||
// gravity: ToastGravity.BOTTOM,
|
||||
// );
|
||||
// } else {
|
||||
// audio.delFromPlaylist(episode);
|
||||
// Fluttertoast.showToast(
|
||||
// msg: 'Removed from playlist',
|
||||
// gravity: ToastGravity.BOTTOM,
|
||||
// );
|
||||
// }
|
||||
// break;
|
||||
// case 2:
|
||||
// if (isLiked) {
|
||||
// await _setUnliked(episode.enclosureUrl);
|
||||
// audio.setEpisodeState = true;
|
||||
// Fluttertoast.showToast(
|
||||
// msg: 'Unliked',
|
||||
// gravity: ToastGravity.BOTTOM,
|
||||
// );
|
||||
// } else {
|
||||
// await _saveLiked(episode.enclosureUrl);
|
||||
// audio.setEpisodeState = true;
|
||||
// Fluttertoast.showToast(
|
||||
// msg: 'Liked',
|
||||
// gravity: ToastGravity.BOTTOM,
|
||||
// );
|
||||
// }
|
||||
// break;
|
||||
// case 3:
|
||||
// if (isListened < 1) {
|
||||
// await _markListened(episode);
|
||||
// audio.setEpisodeState = true;
|
||||
// Fluttertoast.showToast(
|
||||
// msg: 'Mark listened',
|
||||
// gravity: ToastGravity.BOTTOM,
|
||||
// );
|
||||
// }
|
||||
// break;
|
||||
// case 4:
|
||||
// if (!isDownload) downloader.startTask(episode);
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
// });
|
||||
//}
|
||||
|
||||
final options = LiveOptions(
|
||||
delay: Duration.zero,
|
||||
@ -402,9 +418,8 @@ class EpisodeGrid extends StatelessWidget {
|
||||
Color _c = (Theme.of(context).brightness == Brightness.light)
|
||||
? episodes[index].primaryColor.colorizedark()
|
||||
: episodes[index].primaryColor.colorizeLight();
|
||||
scrollController.addListener(() {
|
||||
print(scrollController.offset);
|
||||
});
|
||||
scrollController.addListener(() {});
|
||||
|
||||
return FadeTransition(
|
||||
opacity: Tween<double>(begin: index < initNum ? 0 : 1, end: 1)
|
||||
.animate(animation),
|
||||
@ -416,15 +431,19 @@ class EpisodeGrid extends StatelessWidget {
|
||||
audio.episodeState),
|
||||
builder: (_, data, __) => OpenContainerWrapper(
|
||||
episode: episodes[index],
|
||||
closedBuilder: (context, action, boo) => FutureBuilder<int>(
|
||||
future: _isListened(episodes[index]),
|
||||
initialData: 0,
|
||||
closedBuilder: (context, action, boo) => FutureBuilder<
|
||||
Tuple3<int, bool, bool>>(
|
||||
future: _initData(episodes[index]),
|
||||
initialData: Tuple3(0, false, false),
|
||||
builder: (BuildContext context, AsyncSnapshot snapshot) {
|
||||
int isListened = snapshot.data.item1;
|
||||
bool isLiked = snapshot.data.item2;
|
||||
bool isDownloaded = snapshot.data.item3;
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(5.0)),
|
||||
color: snapshot.data > 0
|
||||
color: isListened > 0
|
||||
? context.brightness == Brightness.light
|
||||
? Colors.grey[200]
|
||||
: Color.fromRGBO(40, 40, 40, 1)
|
||||
@ -439,35 +458,187 @@ class EpisodeGrid extends StatelessWidget {
|
||||
),
|
||||
]),
|
||||
alignment: Alignment.center,
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
// InkWell(
|
||||
// borderRadius:
|
||||
// BorderRadius.all(Radius.circular(5.0)),
|
||||
// onTapDown: (details) => _offset = Offset(
|
||||
// details.globalPosition.dx,
|
||||
// details.globalPosition.dy),
|
||||
// onLongPress: () => _showPopupMenu(
|
||||
// _offset,
|
||||
// episodes[index],
|
||||
// context,
|
||||
// isPlaying: data.item1 == episodes[index],
|
||||
// isInPlaylist: data.item2
|
||||
// .contains(episodes[index].enclosureUrl),
|
||||
// ),
|
||||
// onTap: action,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(5.0)),
|
||||
onTapDown: (details) => _offset = Offset(
|
||||
details.globalPosition.dx,
|
||||
details.globalPosition.dy),
|
||||
onLongPress: () => _showPopupMenu(
|
||||
_offset,
|
||||
episodes[index],
|
||||
context,
|
||||
isPlaying: data.item1 == episodes[index],
|
||||
isInPlaylist: data.item2
|
||||
.contains(episodes[index].enclosureUrl),
|
||||
border: Border.all(
|
||||
color: context.brightness == Brightness.light
|
||||
? context.primaryColor
|
||||
: context.scaffoldBackgroundColor,
|
||||
width: 1.0,
|
||||
),
|
||||
onTap: action,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
decoration: BoxDecoration(
|
||||
),
|
||||
child: FocusedMenuHolder(
|
||||
blurSize: 0.0,
|
||||
menuItemExtent: 45,
|
||||
menuBoxDecoration: BoxDecoration(
|
||||
color: Colors.transparent,
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(5.0)),
|
||||
border: Border.all(
|
||||
color: context.brightness == Brightness.light
|
||||
? context.primaryColor
|
||||
: context.scaffoldBackgroundColor,
|
||||
width: 1.0,
|
||||
),
|
||||
),
|
||||
BorderRadius.all(Radius.circular(15.0))),
|
||||
duration: Duration(milliseconds: 100),
|
||||
tapMode: TapMode.onTap,
|
||||
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.scaffoldBackgroundColor,
|
||||
title: Text(data.item1 != episodes[index]
|
||||
? "Play"
|
||||
: "Playing"),
|
||||
trailingIcon: Icon(
|
||||
LineIcons.play_circle_solid,
|
||||
color: Theme.of(context).accentColor,
|
||||
),
|
||||
onPressed: () {
|
||||
if (data.item1 != episodes[index])
|
||||
audio.episodeLoad(episodes[index]);
|
||||
}),
|
||||
_menuList.contains(1)
|
||||
? FocusedMenuItem(
|
||||
backgroundColor:
|
||||
context.brightness == Brightness.light
|
||||
? context.primaryColor
|
||||
: context.scaffoldBackgroundColor,
|
||||
title: data.item2.contains(
|
||||
episodes[index].enclosureUrl)
|
||||
? Text("Remove")
|
||||
: Text("Later"),
|
||||
trailingIcon: Icon(
|
||||
LineIcons.clock_solid,
|
||||
color: Colors.cyan,
|
||||
),
|
||||
onPressed: () {
|
||||
if (!data.item2.contains(
|
||||
episodes[index].enclosureUrl)) {
|
||||
audio.addToPlaylist(episodes[index]);
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Added to playlist',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
} else {
|
||||
audio
|
||||
.delFromPlaylist(episodes[index]);
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Removed from playlist',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
})
|
||||
: null,
|
||||
_menuList.contains(2)
|
||||
? FocusedMenuItem(
|
||||
backgroundColor:
|
||||
context.brightness == Brightness.light
|
||||
? context.primaryColor
|
||||
: context.scaffoldBackgroundColor,
|
||||
title: isLiked
|
||||
? Text("Unlike")
|
||||
: Text("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: 'Unliked',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
} else {
|
||||
await _saveLiked(
|
||||
episodes[index].enclosureUrl);
|
||||
audio.setEpisodeState = true;
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Liked',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
})
|
||||
: null,
|
||||
_menuList.contains(3)
|
||||
? FocusedMenuItem(
|
||||
backgroundColor:
|
||||
context.brightness == Brightness.light
|
||||
? context.primaryColor
|
||||
: context.scaffoldBackgroundColor,
|
||||
title: isListened > 0
|
||||
? Text('Listened',
|
||||
style: TextStyle(
|
||||
color: context.textColor
|
||||
.withOpacity(0.5)))
|
||||
: Text(
|
||||
'Mark Listened',
|
||||
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: 'Mark listened',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
})
|
||||
: null,
|
||||
_menuList.contains(4)
|
||||
? FocusedMenuItem(
|
||||
backgroundColor:
|
||||
context.brightness == Brightness.light
|
||||
? context.primaryColor
|
||||
: context.scaffoldBackgroundColor,
|
||||
title: isDownloaded
|
||||
? Text('Downloaded',
|
||||
style: TextStyle(
|
||||
color: context.textColor
|
||||
.withOpacity(0.5)))
|
||||
: Text('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>[
|
||||
@ -491,7 +662,8 @@ class EpisodeGrid extends StatelessWidget {
|
||||
// isListened: snapshot.data),
|
||||
_isNewIndicator(episodes[index]),
|
||||
_downloadIndicater(context,
|
||||
episode: episodes[index]),
|
||||
episode: episodes[index],
|
||||
isDownloaded: isDownloaded),
|
||||
_numberIndicater(context,
|
||||
index: index, color: _c)
|
||||
],
|
||||
@ -588,27 +760,17 @@ class EpisodeGrid extends StatelessWidget {
|
||||
padding: EdgeInsets.all(1),
|
||||
),
|
||||
showFavorite || layout != Layout.three
|
||||
? FutureBuilder<bool>(
|
||||
future:
|
||||
_isLiked(episodes[index]),
|
||||
initialData: false,
|
||||
builder: (context, snapshot) =>
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
child: (snapshot.data)
|
||||
? IconTheme(
|
||||
data: IconThemeData(
|
||||
size:
|
||||
_width / 35),
|
||||
child: Icon(
|
||||
Icons.favorite,
|
||||
color: Colors.red,
|
||||
),
|
||||
)
|
||||
: Center(),
|
||||
),
|
||||
)
|
||||
: Center(),
|
||||
? isLiked
|
||||
? IconTheme(
|
||||
data: IconThemeData(
|
||||
size: _width / 35),
|
||||
child: Icon(
|
||||
Icons.favorite,
|
||||
color: Colors.red,
|
||||
),
|
||||
)
|
||||
: Center()
|
||||
: Center()
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -53,6 +53,9 @@ dependencies:
|
||||
line_icons:
|
||||
git:
|
||||
url: https://github.com/galonsos/line_icons.git
|
||||
focused_menu:
|
||||
git:
|
||||
url: https://github.com/stonega/focused_menu.git
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
Loading…
x
Reference in New Issue
Block a user