modified: lib/class/audiostate.dart
modified: lib/class/episodebrief.dart modified: lib/class/importompl.dart modified: lib/class/podcast_group.dart modified: lib/class/podcastlocal.dart modified: lib/episodes/episodedetail.dart modified: lib/episodes/episodedownload.dart modified: lib/home/appbar/addpodcast.dart modified: lib/home/appbar/popupmenu.dart modified: lib/home/audio_player.dart modified: lib/home/homescroll.dart modified: lib/local_storage/sqflite_localpodcast.dart modified: lib/main.dart modified: lib/podcasts/podcastdetail.dart modified: lib/podcasts/podcastgroup.dart modified: lib/podcasts/podcastlist.dart modified: lib/util/episodegrid.dart
This commit is contained in:
parent
16567a7199
commit
69dfc393ba
|
@ -1,32 +1,16 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:tsacdop/class/episodebrief.dart';
|
||||
|
||||
enum AudioState {load, play, pause, complete, error}
|
||||
|
||||
class Urlchange with ChangeNotifier {
|
||||
String _audiourl;
|
||||
String get audiourl => _audiourl;
|
||||
set audioUrl(String playing) {
|
||||
_audiourl = playing;
|
||||
class AudioPlay with ChangeNotifier {
|
||||
|
||||
EpisodeBrief _episode;
|
||||
EpisodeBrief get episode => _episode;
|
||||
set episodeLoad(EpisodeBrief episdoe){
|
||||
_episode = episdoe;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
String _title;
|
||||
String get title => _title;
|
||||
set rssTitle(String title){
|
||||
_title = title;
|
||||
}
|
||||
|
||||
String _feedTitle;
|
||||
String get feedtitle => _feedTitle;
|
||||
set feedTitle(String feed){
|
||||
_feedTitle = feed;
|
||||
}
|
||||
|
||||
String _primaryColor;
|
||||
String get primarycolor => _primaryColor;
|
||||
set primaryColor(String c){
|
||||
_primaryColor = c;
|
||||
}
|
||||
|
||||
AudioState _audioState;
|
||||
AudioState get audioState => _audioState;
|
||||
|
|
|
@ -5,23 +5,24 @@ class EpisodeBrief {
|
|||
final int enclosureLength;
|
||||
final String enclosureUrl;
|
||||
final String feedTitle;
|
||||
final String imageUrl;
|
||||
final String primaryColor;
|
||||
final int liked;
|
||||
final String downloaded;
|
||||
final int duration;
|
||||
final int explicit;
|
||||
final String imagePath;
|
||||
EpisodeBrief(
|
||||
this.title,
|
||||
this.enclosureUrl,
|
||||
this.enclosureLength,
|
||||
this.pubDate,
|
||||
this.feedTitle,
|
||||
this.imageUrl,
|
||||
this.primaryColor,
|
||||
this.liked,
|
||||
this.downloaded,
|
||||
this.duration,
|
||||
this.explicit
|
||||
this.explicit,
|
||||
this.imagePath
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
@ -15,7 +15,9 @@ class ImportOmpl extends ChangeNotifier{
|
|||
ImportState get importState => _importState;
|
||||
|
||||
set importState(ImportState state){
|
||||
_importState = state;
|
||||
if(_importState != state)
|
||||
{_importState = state;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,7 +35,7 @@ class PodcastGroup {
|
|||
final String name;
|
||||
final String id;
|
||||
final String color;
|
||||
final List<String> podcastList;
|
||||
List<String> podcastList;
|
||||
|
||||
PodcastGroup(this.name,
|
||||
{this.color = '#000000', String id, List<String> podcastList})
|
||||
|
@ -45,7 +45,7 @@ class PodcastGroup {
|
|||
Future getPodcasts() async {
|
||||
var dbHelper = DBHelper();
|
||||
if (podcastList != []) {
|
||||
_podcasts = await dbHelper.getPodcastLocal(podcastList, 0);
|
||||
_podcasts = await dbHelper.getPodcastLocal(podcastList);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,18 +141,38 @@ class GroupList extends ChangeNotifier {
|
|||
return result;
|
||||
}
|
||||
|
||||
changeGroup(String id, List<String> l) {
|
||||
changeGroup(String id, List<String> list) async{
|
||||
_groups.forEach((group) {
|
||||
if (group.podcastList.contains(id)) {
|
||||
group.podcastList.remove(id);
|
||||
}
|
||||
});
|
||||
l.forEach((s) {
|
||||
_groups.forEach((group) {
|
||||
await Future.forEach(list, (s) {
|
||||
_groups.forEach((group) async{
|
||||
if (group.name == s) group.podcastList.add(id);
|
||||
await group.getPodcasts();
|
||||
});
|
||||
});
|
||||
notifyListeners();
|
||||
_saveGroup();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
removePodcast(String id) async{
|
||||
await Future.forEach(_groups, (group) async{
|
||||
if (group.podcastList.contains(id)) {
|
||||
group.podcastList.remove(id);
|
||||
await group.getPodcasts();
|
||||
}
|
||||
});
|
||||
_saveGroup();
|
||||
await dbHelper.delPodcastLocal(id);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
saveOrder(PodcastGroup group, List<PodcastLocal> podcasts) async{
|
||||
group.podcastList = podcasts.map((e) => e.id).toList();
|
||||
_saveGroup();
|
||||
await group.getPodcasts();
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
class PodcastLocal {
|
||||
final String title;
|
||||
final String imageUrl;
|
||||
|
@ -9,6 +7,7 @@ class PodcastLocal {
|
|||
String description;
|
||||
final String primaryColor;
|
||||
final String id;
|
||||
PodcastLocal(this.title, this.imageUrl, this.rssUrl, this.primaryColor, this.author,{String id}) : id = id ?? Uuid().v4();
|
||||
final String imagePath;
|
||||
PodcastLocal(this.title, this.imageUrl, this.rssUrl, this.primaryColor, this.author, this.id, this.imagePath);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import 'package:flutter/material.dart';
|
|||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_html/flutter_html.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:tsacdop/class/audiostate.dart';
|
||||
import 'package:tsacdop/class/episodebrief.dart';
|
||||
|
@ -15,8 +14,7 @@ import 'episodedownload.dart';
|
|||
class EpisodeDetail extends StatefulWidget {
|
||||
final EpisodeBrief episodeItem;
|
||||
final String heroTag;
|
||||
final String path;
|
||||
EpisodeDetail({this.episodeItem, this.heroTag, this.path, Key key})
|
||||
EpisodeDetail({this.episodeItem, this.heroTag, Key key})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
|
@ -28,11 +26,9 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
|||
double downloadProgress;
|
||||
bool _loaddes;
|
||||
String path;
|
||||
Future getSDescription(String title) async {
|
||||
var dir = await getApplicationDocumentsDirectory();
|
||||
path = dir.path;
|
||||
Future getSDescription(String url) async {
|
||||
var dbHelper = DBHelper();
|
||||
widget.episodeItem.description = await dbHelper.getDescription(title);
|
||||
widget.episodeItem.description = await dbHelper.getDescription(url);
|
||||
if (mounted)
|
||||
setState(() {
|
||||
_loaddes = true;
|
||||
|
@ -51,7 +47,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
|||
void initState() {
|
||||
super.initState();
|
||||
_loaddes = false;
|
||||
getSDescription(widget.episodeItem.title);
|
||||
getSDescription(widget.episodeItem.enclosureUrl);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -167,7 +163,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
|||
MenuBar(
|
||||
episodeItem: widget.episodeItem,
|
||||
heroTag: widget.heroTag,
|
||||
path: widget.path),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -176,10 +172,9 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
|||
}
|
||||
|
||||
class MenuBar extends StatefulWidget {
|
||||
final String path;
|
||||
final EpisodeBrief episodeItem;
|
||||
final String heroTag;
|
||||
MenuBar({this.episodeItem, this.heroTag, this.path, Key key})
|
||||
MenuBar({this.episodeItem, this.heroTag, Key key})
|
||||
: super(key: key);
|
||||
@override
|
||||
_MenuBarState createState() => _MenuBarState();
|
||||
|
@ -189,16 +184,16 @@ class _MenuBarState extends State<MenuBar> {
|
|||
bool _liked;
|
||||
int _like;
|
||||
|
||||
Future<int> saveLiked(String title) async {
|
||||
Future<int> saveLiked(String url) async {
|
||||
var dbHelper = DBHelper();
|
||||
int result = await dbHelper.setLiked(title);
|
||||
int result = await dbHelper.setLiked(url);
|
||||
if (result == 1 && mounted) setState(() => _liked = true);
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<int> setUnliked(String title) async {
|
||||
Future<int> setUnliked(String url) async {
|
||||
var dbHelper = DBHelper();
|
||||
int result = await dbHelper.setUniked(title);
|
||||
int result = await dbHelper.setUniked(url);
|
||||
if (result == 1 && mounted)
|
||||
setState(() {
|
||||
_liked = false;
|
||||
|
@ -227,9 +222,8 @@ class _MenuBarState extends State<MenuBar> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final urlChange = Provider.of<Urlchange>(context);
|
||||
return Consumer<Urlchange>(
|
||||
builder: (context, urlchange, _) => Container(
|
||||
final audioplay = Provider.of<AudioPlay>(context);
|
||||
return Container(
|
||||
height: 50.0,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
|
@ -239,11 +233,11 @@ class _MenuBarState extends State<MenuBar> {
|
|||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
(widget.episodeItem.title == urlChange.title &&
|
||||
urlChange.audioState == AudioState.play)
|
||||
(widget.episodeItem.title == audioplay.episode?.title &&
|
||||
audioplay.audioState == AudioState.play)
|
||||
? ImageRotate(
|
||||
title: widget.episodeItem.feedTitle,
|
||||
path: widget.path,
|
||||
path: widget.episodeItem.imagePath,
|
||||
)
|
||||
: Hero(
|
||||
tag: widget.episodeItem.enclosureUrl + widget.heroTag,
|
||||
|
@ -256,7 +250,7 @@ class _MenuBarState extends State<MenuBar> {
|
|||
width: 30.0,
|
||||
color: Colors.white,
|
||||
child: Image.file(File(
|
||||
"${widget.path}/${widget.episodeItem.feedTitle}.png")),
|
||||
"${widget.episodeItem.imagePath}")),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -267,7 +261,7 @@ class _MenuBarState extends State<MenuBar> {
|
|||
Icons.favorite_border,
|
||||
color: Colors.grey[700],
|
||||
),
|
||||
() => saveLiked(widget.episodeItem.title))
|
||||
() => saveLiked(widget.episodeItem.enclosureUrl))
|
||||
: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
|
@ -277,7 +271,7 @@ class _MenuBarState extends State<MenuBar> {
|
|||
Icons.favorite,
|
||||
color: Colors.red,
|
||||
),
|
||||
() => setUnliked(widget.episodeItem.title)),
|
||||
() => setUnliked(widget.episodeItem.enclosureUrl)),
|
||||
],
|
||||
),
|
||||
DownloadButton(episodeBrief: widget.episodeItem),
|
||||
|
@ -290,7 +284,7 @@ class _MenuBarState extends State<MenuBar> {
|
|||
/*TODO*/
|
||||
}),
|
||||
Spacer(),
|
||||
(widget.episodeItem.title != urlchange.title)
|
||||
(widget.episodeItem.title != audioplay.episode?.title)
|
||||
? Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
|
@ -298,11 +292,7 @@ class _MenuBarState extends State<MenuBar> {
|
|||
topRight: Radius.circular(5.0),
|
||||
bottomRight: Radius.circular(5.0)),
|
||||
onTap: () {
|
||||
urlChange.audioUrl = widget.episodeItem.enclosureUrl;
|
||||
urlChange.rssTitle = widget.episodeItem.title;
|
||||
urlChange.feedTitle = widget.episodeItem.feedTitle;
|
||||
urlChange.primaryColor =
|
||||
widget.episodeItem.primaryColor;
|
||||
audioplay.episodeLoad = widget.episodeItem;
|
||||
},
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
|
@ -325,8 +315,8 @@ class _MenuBarState extends State<MenuBar> {
|
|||
),
|
||||
),
|
||||
)
|
||||
: (widget.episodeItem.title == urlchange.title &&
|
||||
urlchange.audioState == AudioState.play)
|
||||
: (widget.episodeItem.title == audioplay.episode?.title &&
|
||||
audioplay.audioState == AudioState.play)
|
||||
? Container(
|
||||
padding: EdgeInsets.only(right: 30),
|
||||
child: SizedBox(
|
||||
|
@ -341,7 +331,6 @@ class _MenuBarState extends State<MenuBar> {
|
|||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -560,7 +549,7 @@ class _ImageRotateState extends State<ImageRotate>
|
|||
height: 30.0,
|
||||
width: 30.0,
|
||||
color: Colors.white,
|
||||
child: Image.file(File("${widget.path}/${widget.title}.png")),
|
||||
child: Image.file(File("${widget.path}")),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -614,7 +603,7 @@ class _LoveOpenState extends State<LoveOpen>
|
|||
super.initState();
|
||||
_controller = AnimationController(
|
||||
vsync: this,
|
||||
duration: Duration(milliseconds: 100),
|
||||
duration: Duration(milliseconds: 300),
|
||||
);
|
||||
|
||||
_animationA = Tween(begin: 0.0, end: 1.0).animate(_controller)
|
||||
|
|
|
@ -8,7 +8,6 @@ import 'package:path_provider/path_provider.dart';
|
|||
import 'package:flutter_downloader/flutter_downloader.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:tsacdop/class/downloadstate.dart';
|
||||
import 'package:tsacdop/class/episodebrief.dart';
|
||||
import 'package:tsacdop/local_storage/sqflite_localpodcast.dart';
|
||||
|
||||
|
@ -237,7 +236,7 @@ class _DownloadButtonState extends State<DownloadButton> {
|
|||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
(task.progress > 0) ? _pauseDownload(task) : null;
|
||||
if(task.progress > 0) _pauseDownload(task);
|
||||
},
|
||||
child: Container(
|
||||
height: 50.0,
|
||||
|
|
|
@ -9,12 +9,12 @@ import 'package:provider/provider.dart';
|
|||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:image/image.dart' as img;
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import 'package:tsacdop/class/importompl.dart';
|
||||
import 'package:tsacdop/class/podcast_group.dart';
|
||||
import 'package:tsacdop/class/searchpodcast.dart';
|
||||
import 'package:tsacdop/class/podcastlocal.dart';
|
||||
import 'package:tsacdop/class/settingstate.dart';
|
||||
import 'package:tsacdop/local_storage/sqflite_localpodcast.dart';
|
||||
import 'package:tsacdop/home/home.dart';
|
||||
import 'package:tsacdop/home/appbar/popupmenu.dart';
|
||||
|
@ -63,7 +63,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||
class _MyHomePageDelegate extends SearchDelegate<int> {
|
||||
static Future<List> getList(String searchText) async {
|
||||
String url =
|
||||
"https://listennotes.p.mashape.com/api/v1/search?only_in=title&q=" +
|
||||
"https://listennotes.p.mashape.com/api/v1/search?only_in=title%2Cdescription&q=" +
|
||||
searchText +
|
||||
"&sort_by_date=0&type=podcast";
|
||||
Response response = await Dio().get(url,
|
||||
|
@ -189,12 +189,14 @@ class SearchResult extends StatefulWidget {
|
|||
class _SearchResultState extends State<SearchResult> {
|
||||
bool _issubscribe;
|
||||
bool _adding;
|
||||
bool _showDes;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_issubscribe = false;
|
||||
_adding = false;
|
||||
_showDes = false;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -212,92 +214,122 @@ class _SearchResultState extends State<SearchResult> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
ImportOmpl importOmpl = Provider.of<ImportOmpl>(context);
|
||||
var groupList = Provider.of<GroupList>(context);
|
||||
var _settingState = Provider.of<SettingState>(context);
|
||||
var importOmpl = Provider.of<ImportOmpl>(context, listen: false);
|
||||
var groupList = Provider.of<GroupList>(context, listen: false);
|
||||
savePodcast(String rss) async {
|
||||
print(rss);
|
||||
if (mounted) setState(() => _adding = true);
|
||||
|
||||
importOmpl.importState = ImportState.import;
|
||||
|
||||
try {
|
||||
Response response = await Dio().get(rss);
|
||||
|
||||
String _realUrl = response.realUri.toString();
|
||||
if (mounted) setState(() => _issubscribe = true);
|
||||
|
||||
var _p = RssFeed.parse(response.data);
|
||||
|
||||
print(_p.title);
|
||||
|
||||
var dir = await getApplicationDocumentsDirectory();
|
||||
try {
|
||||
|
||||
Response<List<int>> imageResponse = await Dio().get<List<int>>(
|
||||
_p.itunes.image.href,
|
||||
options: Options(responseType: ResponseType.bytes));
|
||||
|
||||
img.Image image = img.decodeImage(imageResponse.data);
|
||||
img.Image thumbnail = img.copyResize(image, width: 300);
|
||||
File("${dir.path}/${_p.title}.png")
|
||||
String _uuid = Uuid().v4();
|
||||
File("${dir.path}/$_uuid.png")
|
||||
..writeAsBytesSync(img.encodePng(thumbnail));
|
||||
|
||||
String _imagePath = "${dir.path}/$_uuid.png";
|
||||
String _primaryColor =
|
||||
await getColor(File("${dir.path}/${_p.title}.png"));
|
||||
await getColor(File("${dir.path}/$_uuid.png"));
|
||||
PodcastLocal podcastLocal = PodcastLocal(
|
||||
_p.title, _p.itunes.image.href, rss, _primaryColor, _p.author);
|
||||
_p.title, _p.itunes.image.href, _realUrl, _primaryColor, _p.author, _uuid, _imagePath);
|
||||
podcastLocal.description = _p.description;
|
||||
groupList.subscribe(podcastLocal);
|
||||
|
||||
importOmpl.importState = ImportState.parse;
|
||||
var dbHelper = DBHelper();
|
||||
await dbHelper.savePodcastRss(_p);
|
||||
await dbHelper.savePodcastRss(_p, _uuid);
|
||||
|
||||
importOmpl.importState = ImportState.complete;
|
||||
|
||||
_settingState.subscribeUpdate = Update.backhome;
|
||||
|
||||
print('fatch data');
|
||||
} catch (e) {
|
||||
importOmpl.importState = ImportState.error;
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Network error, Subscribe failed',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
await Future.delayed(Duration(seconds: 10));
|
||||
importOmpl.importState = ImportState.stop;
|
||||
}
|
||||
}
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.0),
|
||||
child: ListTile(
|
||||
leading: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20.0)),
|
||||
child: Image.network(
|
||||
widget.onlinePodcast.image,
|
||||
height: 40.0,
|
||||
width: 40.0,
|
||||
fit: BoxFit.fitWidth,
|
||||
alignment: Alignment.center,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
ListTile(
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 30.0),
|
||||
onTap: (){setState(() {
|
||||
_showDes = !_showDes;
|
||||
});},
|
||||
leading: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20.0)),
|
||||
child: Image.network(
|
||||
widget.onlinePodcast.image,
|
||||
height: 40.0,
|
||||
width: 40.0,
|
||||
fit: BoxFit.fitWidth,
|
||||
alignment: Alignment.center,
|
||||
),
|
||||
),
|
||||
title: Text(widget.onlinePodcast.title),
|
||||
subtitle: Text(widget.onlinePodcast.publisher),
|
||||
trailing:
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Icon(_showDes ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down),
|
||||
Padding(padding: EdgeInsets.only(right: 10.0)),
|
||||
!_issubscribe
|
||||
? !_adding
|
||||
? OutlineButton(
|
||||
child:
|
||||
Text('Subscribe', style: TextStyle(color: Colors.blue)),
|
||||
onPressed: () {
|
||||
importOmpl.rssTitle = widget.onlinePodcast.title;
|
||||
savePodcast(widget.onlinePodcast.rss);
|
||||
})
|
||||
: OutlineButton(
|
||||
child: SizedBox(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
valueColor: AlwaysStoppedAnimation(Colors.blue),
|
||||
)),
|
||||
onPressed: () {},
|
||||
)
|
||||
: OutlineButton(child: Text('Subscribe'), onPressed: (){}),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
title: Text(widget.onlinePodcast.title),
|
||||
subtitle: Text(widget.onlinePodcast.publisher),
|
||||
trailing: !_issubscribe
|
||||
? !_adding
|
||||
? OutlineButton(
|
||||
child:
|
||||
Text('Subscribe', style: TextStyle(color: Colors.blue)),
|
||||
onPressed: () {
|
||||
importOmpl.rssTitle = widget.onlinePodcast.title;
|
||||
savePodcast(widget.onlinePodcast.rss);
|
||||
})
|
||||
: OutlineButton(
|
||||
child: SizedBox(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
valueColor: AlwaysStoppedAnimation(Colors.blue),
|
||||
)),
|
||||
onPressed: () {},
|
||||
)
|
||||
: OutlineButton(child: Text('Subscribe'), onPressed: null),
|
||||
_showDes ? Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[300],
|
||||
borderRadius: BorderRadius.all(Radius.circular(10.0))
|
||||
),
|
||||
margin: EdgeInsets.only(left: 70, right: 50),
|
||||
padding: EdgeInsets.all(10.0),
|
||||
child: Text(widget.onlinePodcast.description, maxLines: 3, overflow: TextOverflow.ellipsis,),
|
||||
) : Center(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,13 +4,15 @@ import 'dart:async';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tsacdop/class/settingstate.dart';
|
||||
import 'package:tsacdop/class/podcast_group.dart';
|
||||
import 'package:xml/xml.dart' as xml;
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:color_thief_flutter/color_thief_flutter.dart';
|
||||
import 'package:image/image.dart' as img;
|
||||
import 'package:uuid/uuid.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
|
||||
import 'about.dart';
|
||||
import 'package:tsacdop/class/podcastlocal.dart';
|
||||
|
@ -43,22 +45,19 @@ class PopupMenu extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
ImportOmpl importOmpl = Provider.of<ImportOmpl>(context);
|
||||
var _settingState = Provider.of<SettingState>(context);
|
||||
_refreshAll() async {
|
||||
ImportOmpl importOmpl = Provider.of<ImportOmpl>(context, listen: false);
|
||||
GroupList groupList = Provider.of<GroupList>(context, listen: false);
|
||||
_refreshAll() async{
|
||||
var dbHelper = DBHelper();
|
||||
List<PodcastLocal> podcastList =
|
||||
await dbHelper.getPodcastLocalAll();
|
||||
await Future.forEach(podcastList, (podcastLocal) async {
|
||||
importOmpl.rssTitle = podcastLocal.title;
|
||||
importOmpl.importState = ImportState.parse;
|
||||
Response response = await Dio().get(podcastLocal.rssUrl);
|
||||
var _p = RssFeed.parse(response.data);
|
||||
await dbHelper.savePodcastRss(_p);
|
||||
await dbHelper.updatePodcastRss(podcastLocal);
|
||||
print('Refresh ' + podcastLocal.title);
|
||||
});
|
||||
importOmpl.importState = ImportState.complete;
|
||||
importOmpl.importState = ImportState.stop;
|
||||
}
|
||||
|
||||
saveOmpl(String rss) async {
|
||||
|
@ -75,28 +74,34 @@ class PopupMenu extends StatelessWidget {
|
|||
options: Options(responseType: ResponseType.bytes));
|
||||
img.Image image = img.decodeImage(imageResponse.data);
|
||||
img.Image thumbnail = img.copyResize(image, width: 300);
|
||||
File("${dir.path}/${_p.title}.png")
|
||||
String _uuid = Uuid().v4();
|
||||
String _realUrl = response.realUri.toString();
|
||||
File("${dir.path}/$_uuid.png")
|
||||
..writeAsBytesSync(img.encodePng(thumbnail));
|
||||
|
||||
String _imagePath = "${dir.path}/$_uuid.png";
|
||||
String _primaryColor =
|
||||
await getColor(File("${dir.path}/${_p.title}.png"));
|
||||
await getColor(File("${dir.path}/$_uuid.png"));
|
||||
|
||||
PodcastLocal podcastLocal = PodcastLocal(
|
||||
_p.title, _p.itunes.image.href, rss, _primaryColor, _p.author);
|
||||
_p.title, _p.itunes.image.href, _realUrl, _primaryColor, _p.author, _uuid, _imagePath);
|
||||
|
||||
podcastLocal.description = _p.description;
|
||||
|
||||
await dbHelper.savePodcastLocal(podcastLocal);
|
||||
groupList.subscribe(podcastLocal);
|
||||
|
||||
importOmpl.importState = ImportState.parse;
|
||||
|
||||
await dbHelper.savePodcastRss(_p);
|
||||
await dbHelper.savePodcastRss(_p, _uuid);
|
||||
|
||||
importOmpl.importState = ImportState.complete;
|
||||
|
||||
_settingState.subscribeUpdate = Update.backhome;
|
||||
} catch (e) {
|
||||
importOmpl.importState = ImportState.error;
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Network error, Subscribe failed',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
await Future.delayed(Duration(seconds: 10));
|
||||
importOmpl.importState = ImportState.stop;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,13 +9,11 @@ import 'package:audiofileplayer/audio_system.dart';
|
|||
import 'package:logging/logging.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:marquee/marquee.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:flutter_downloader/flutter_downloader.dart';
|
||||
import 'package:tsacdop/class/audiostate.dart';
|
||||
import 'package:tsacdop/class/episodebrief.dart';
|
||||
import 'package:tsacdop/episodes/episodedetail.dart';
|
||||
import 'package:tsacdop/home/audiopanel.dart';
|
||||
import 'package:tsacdop/local_storage/sqflite_localpodcast.dart';
|
||||
import 'package:tsacdop/util/pageroute.dart';
|
||||
|
||||
final Logger _logger = Logger('audiofileplayer');
|
||||
|
@ -40,13 +38,9 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
String _remoteErrorMessage;
|
||||
double _seekSliderValue = 0.0;
|
||||
String url;
|
||||
String _title;
|
||||
String _feedtitle;
|
||||
bool _isLoading;
|
||||
String _primaryColor;
|
||||
Color _c;
|
||||
String _imagePath;
|
||||
bool _loadDir;
|
||||
EpisodeBrief episode;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -54,27 +48,14 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
AudioSystem.instance.addMediaEventListener(_mediaEventListener);
|
||||
_isLoading = false;
|
||||
_remoteAudioLoading = true;
|
||||
_loadDir = false;
|
||||
getPath();
|
||||
}
|
||||
|
||||
//get path to load podcast image in expanded panel
|
||||
getPath() async {
|
||||
var dir = await getApplicationDocumentsDirectory();
|
||||
_imagePath = dir.path;
|
||||
setState(() {
|
||||
_loadDir = true;
|
||||
});
|
||||
}
|
||||
|
||||
//open episoddetail page
|
||||
_gotoEpisode() async {
|
||||
var dbHelper = DBHelper();
|
||||
EpisodeBrief episodeBrief = await dbHelper.getRssItemWithUrl(url);
|
||||
Navigator.push(
|
||||
context,
|
||||
SlideUptRoute(
|
||||
page: EpisodeDetail(episodeItem: episodeBrief, heroTag: 'playpanel')),
|
||||
page: EpisodeDetail(episodeItem: episode, heroTag: 'playpanel')),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -82,7 +63,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
void _initbackgroundAudioPlayer(String url) {
|
||||
_remoteErrorMessage = null;
|
||||
_remoteAudioLoading = true;
|
||||
Provider.of<Urlchange>(context, listen: false).audioState = AudioState.load;
|
||||
Provider.of<AudioPlay>(context, listen: false).audioState = AudioState.load;
|
||||
|
||||
if (_backgroundAudioPlaying == true)
|
||||
{ _backgroundAudio?.pause();
|
||||
|
@ -93,7 +74,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
setState(() {
|
||||
_backgroundAudioDurationSeconds = durationSeconds;
|
||||
_remoteAudioLoading = false;
|
||||
Provider.of<Urlchange>(context, listen: false).audioState =
|
||||
Provider.of<AudioPlay>(context, listen: false).audioState =
|
||||
AudioState.play;
|
||||
});
|
||||
_setNotification();
|
||||
|
@ -117,13 +98,13 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
_backgroundAudio = null;
|
||||
_backgroundAudioPlaying = false;
|
||||
_remoteAudioLoading = false;
|
||||
Provider.of<Urlchange>(context, listen: false).audioState =
|
||||
Provider.of<AudioPlay>(context, listen: false).audioState =
|
||||
AudioState.error;
|
||||
}),
|
||||
onComplete: () => setState(() {
|
||||
_backgroundAudioPlaying = false;
|
||||
_remoteAudioLoading = false;
|
||||
Provider.of<Urlchange>(context, listen: false).audioState =
|
||||
Provider.of<AudioPlay>(context, listen: false).audioState =
|
||||
AudioState.complete;
|
||||
}),
|
||||
looping: false,
|
||||
|
@ -136,7 +117,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
_remoteErrorMessage = null;
|
||||
_remoteAudioLoading = true;
|
||||
ByteData audio = getAudio(path);
|
||||
Provider.of<Urlchange>(context, listen: false).audioState = AudioState.load;
|
||||
Provider.of<AudioPlay>(context, listen: false).audioState = AudioState.load;
|
||||
if (_backgroundAudioPlaying == true)
|
||||
{_backgroundAudio?.pause();
|
||||
AudioSystem.instance.stopBackgroundDisplay();}
|
||||
|
@ -148,7 +129,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
_remoteAudioLoading = false;
|
||||
});
|
||||
_setNotification();
|
||||
Provider.of<Urlchange>(context, listen: false).audioState =
|
||||
Provider.of<AudioPlay>(context, listen: false).audioState =
|
||||
AudioState.play;
|
||||
},
|
||||
onPosition: (double positionSeconds) {
|
||||
|
@ -170,13 +151,13 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
_backgroundAudio = null;
|
||||
_backgroundAudioPlaying = false;
|
||||
_remoteAudioLoading = false;
|
||||
Provider.of<Urlchange>(context, listen: false).audioState =
|
||||
Provider.of<AudioPlay>(context, listen: false).audioState =
|
||||
AudioState.error;
|
||||
}),
|
||||
onComplete: () => setState(() {
|
||||
_backgroundAudioPlaying = false;
|
||||
_remoteAudioLoading = false;
|
||||
Provider.of<Urlchange>(context, listen: false).audioState =
|
||||
Provider.of<AudioPlay>(context, listen: false).audioState =
|
||||
AudioState.complete;
|
||||
}),
|
||||
looping: false,
|
||||
|
@ -205,14 +186,13 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
final url = Provider.of<Urlchange>(context).audiourl;
|
||||
|
||||
final url = Provider.of<AudioPlay>(context).episode?.enclosureUrl;
|
||||
if (url != this.url) {
|
||||
setState(() {
|
||||
this.url = url;
|
||||
_title = Provider.of<Urlchange>(context).title;
|
||||
_feedtitle = Provider.of<Urlchange>(context).feedtitle;
|
||||
_primaryColor = Provider.of<Urlchange>(context).primarycolor;
|
||||
var color = json.decode(_primaryColor);
|
||||
episode = Provider.of<AudioPlay>(context).episode;
|
||||
var color = json.decode(episode?.primaryColor);
|
||||
(color[0] > 200 && color[1] > 200 && color[2] > 200)
|
||||
? _c = Color.fromRGBO(
|
||||
(255 - color[0]), 255 - color[1], 255 - color[2], 1.0)
|
||||
|
@ -290,13 +270,12 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
'playnow', likeButtonId, 'ic_stat_play_circle_filled');
|
||||
|
||||
Future<void> _setNotification() async {
|
||||
var dir = await getApplicationDocumentsDirectory();
|
||||
final Uint8List imageBytes =
|
||||
File('${dir.path}/$_feedtitle.png').readAsBytesSync();
|
||||
File('${episode.imagePath}').readAsBytesSync();
|
||||
AudioSystem.instance.setMetadata(AudioMetadata(
|
||||
title: _title,
|
||||
artist: _feedtitle,
|
||||
album: _feedtitle,
|
||||
title: episode.title,
|
||||
artist:episode.feedTitle,
|
||||
album: episode.feedTitle,
|
||||
genre: "Podcast",
|
||||
durationSeconds: _backgroundAudioDurationSeconds,
|
||||
artBytes: imageBytes));
|
||||
|
@ -327,16 +306,15 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
_backgroundAudio.resume();
|
||||
setState(() {
|
||||
_backgroundAudioPlaying = true;
|
||||
Provider.of<Urlchange>(context, listen: false).audioState =
|
||||
Provider.of<AudioPlay>(context, listen: false).audioState =
|
||||
AudioState.play;
|
||||
});
|
||||
var dir = await getApplicationDocumentsDirectory();
|
||||
final Uint8List imageBytes =
|
||||
File('${dir.path}/$_feedtitle.png').readAsBytesSync();
|
||||
File('${episode.imagePath}').readAsBytesSync();
|
||||
AudioSystem.instance.setMetadata(AudioMetadata(
|
||||
title: _title,
|
||||
artist: _feedtitle,
|
||||
album: _feedtitle,
|
||||
title: episode.title,
|
||||
artist: episode.feedTitle,
|
||||
album: episode.feedTitle,
|
||||
genre: "Podcast",
|
||||
durationSeconds: _backgroundAudioDurationSeconds,
|
||||
artBytes: imageBytes));
|
||||
|
@ -369,7 +347,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
_backgroundAudio.pause();
|
||||
setState(() {
|
||||
_backgroundAudioPlaying = false;
|
||||
Provider.of<Urlchange>(context, listen: false).audioState =
|
||||
Provider.of<AudioPlay>(context, listen: false).audioState =
|
||||
AudioState.pause;
|
||||
});
|
||||
|
||||
|
@ -417,9 +395,9 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
height: 80.0,
|
||||
padding: EdgeInsets.all(20),
|
||||
alignment: Alignment.center,
|
||||
child: (_title.length > 10)
|
||||
child: (episode.title.length > 10)
|
||||
? Marquee(
|
||||
text: _title,
|
||||
text: episode.title,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold, fontSize: 18),
|
||||
scrollAxis: Axis.horizontal,
|
||||
|
@ -434,7 +412,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
decelerationCurve: Curves.easeOut,
|
||||
)
|
||||
: Text(
|
||||
_title,
|
||||
episode.title,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold, fontSize: 20),
|
||||
),
|
||||
|
@ -570,10 +548,8 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
height: 30.0,
|
||||
width: 30.0,
|
||||
color: Colors.white,
|
||||
child: _loadDir
|
||||
? Image.file(
|
||||
File("$_imagePath/$_feedtitle.png"))
|
||||
: Center(),
|
||||
child: Image.file(
|
||||
File("${episode.imagePath}"))
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -615,9 +591,9 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
child: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 5),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: (_title.length > 55)
|
||||
child: (episode.title.length > 55)
|
||||
? Marquee(
|
||||
text: _title,
|
||||
text: episode.title,
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
scrollAxis: Axis.vertical,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
@ -632,7 +608,7 @@ class _PlayerWidgetState extends State<PlayerWidget> {
|
|||
decelerationCurve: Curves.easeOut,
|
||||
)
|
||||
: Text(
|
||||
_title,
|
||||
episode.title,
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
maxLines: 2,
|
||||
),
|
||||
|
|
|
@ -171,7 +171,7 @@ class _ScrollPodcastsState extends State<ScrollPodcasts> {
|
|||
child: !_loaded
|
||||
? CircularProgressIndicator()
|
||||
: Image.file(File(
|
||||
"$dir/${podcastLocal.title}.png")),
|
||||
"${podcastLocal.imagePath}")),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -216,13 +216,11 @@ class PodcastPreview extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _PodcastPreviewState extends State<PodcastPreview> {
|
||||
String path;
|
||||
|
||||
Future<List<EpisodeBrief>> _getRssItemTop(PodcastLocal podcastLocal) async {
|
||||
var dbHelper = DBHelper();
|
||||
var dir = await getApplicationDocumentsDirectory();
|
||||
path = dir.path;
|
||||
Future<List<EpisodeBrief>> episodes =
|
||||
dbHelper.getRssItemTop(podcastLocal.title);
|
||||
dbHelper.getRssItemTop(podcastLocal.id);
|
||||
return episodes;
|
||||
}
|
||||
|
||||
|
@ -254,7 +252,6 @@ class _PodcastPreviewState extends State<PodcastPreview> {
|
|||
? ShowEpisode(
|
||||
podcast: snapshot.data,
|
||||
podcastLocal: widget.podcastLocal,
|
||||
path: path,
|
||||
)
|
||||
: Center(child: CircularProgressIndicator());
|
||||
},
|
||||
|
@ -299,8 +296,7 @@ class _PodcastPreviewState extends State<PodcastPreview> {
|
|||
class ShowEpisode extends StatelessWidget {
|
||||
final List<EpisodeBrief> podcast;
|
||||
final PodcastLocal podcastLocal;
|
||||
final String path;
|
||||
ShowEpisode({Key key, this.podcast, this.podcastLocal, this.path})
|
||||
ShowEpisode({Key key, this.podcast, this.podcastLocal})
|
||||
: super(key: key);
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -335,7 +331,6 @@ class ShowEpisode extends StatelessWidget {
|
|||
episodeItem: podcast[index],
|
||||
heroTag: 'scroll',
|
||||
//unique hero tag
|
||||
path: path,
|
||||
)),
|
||||
);
|
||||
},
|
||||
|
@ -374,7 +369,7 @@ class ShowEpisode extends StatelessWidget {
|
|||
height: _width / 18,
|
||||
width: _width / 18,
|
||||
child: Image.file(File(
|
||||
"$path/${podcastLocal.title}.png")),
|
||||
"${podcastLocal.imagePath}")),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:path/path.dart';
|
|||
import 'package:intl/intl.dart';
|
||||
import 'package:flutter_downloader/flutter_downloader.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:tsacdop/class/podcastlocal.dart';
|
||||
import 'package:tsacdop/class/episodebrief.dart';
|
||||
import 'package:tsacdop/webfeed/webfeed.dart';
|
||||
|
@ -28,43 +29,32 @@ class DBHelper {
|
|||
await db
|
||||
.execute("""CREATE TABLE PodcastLocal(id TEXT PRIMARY KEY,title TEXT,
|
||||
imageUrl TEXT,rssUrl TEXT UNIQUE,primaryColor TEXT,author TEXT,
|
||||
description TEXT, add_date INTEGER, order_id INTEGER DEFAULT 0)""");
|
||||
description TEXT, add_date INTEGER, imagePath TEXT)""");
|
||||
await db
|
||||
.execute("""CREATE TABLE Episodes(id INTEGER PRIMARY KEY,title TEXT,
|
||||
enclosure_url TEXT UNIQUE, enclosure_length INTEGER, pubDate TEXT,
|
||||
description TEXT, feed_title TEXT, feed_link TEXT, milliseconds INTEGER,
|
||||
description TEXT, feed_id TEXT, feed_link TEXT, milliseconds INTEGER,
|
||||
duration INTEGER DEFAULT 0, explicit INTEGER DEFAULT 0, liked INTEGER DEFAULT 0,
|
||||
downloaded TEXT DEFAULT 'ND', download_date INTEGER DEFAULT 0)""");
|
||||
}
|
||||
|
||||
Future<List<PodcastLocal>> getPodcastLocal(
|
||||
List<String> podcasts, int podcastsOrder) async {
|
||||
Future<List<PodcastLocal>> getPodcastLocal(List<String> podcasts) async {
|
||||
var dbClient = await database;
|
||||
List<PodcastLocal> podcastLocal = List();
|
||||
|
||||
await Future.forEach(podcasts, (s) async {
|
||||
List<Map> list;
|
||||
if (podcastsOrder == 0) {
|
||||
list = await dbClient.rawQuery(
|
||||
'SELECT id, title, imageUrl, rssUrl, primaryColor, author FROM PodcastLocal WHERE id = ? ORDER BY add_date DESC',
|
||||
[s]);
|
||||
} else if (podcastsOrder == 1) {
|
||||
list = await dbClient.rawQuery(
|
||||
'SELECT id, title, imageUrl, rssUrl, primaryColor, author FROM PodcastLocal WHERE id = ? ORDER BY add_date',
|
||||
[s]);
|
||||
} else if (podcastsOrder == 2) {
|
||||
list = await dbClient.rawQuery(
|
||||
'SELECT id, title, imageUrl, rssUrl, primaryColor, author FROM PodcastLocal WHERE id = ? ORDER BY order_id , add_date DESC',
|
||||
[s]);
|
||||
print('Get podcasts list Ordered by 2');
|
||||
}
|
||||
list = await dbClient.rawQuery(
|
||||
'SELECT id, title, imageUrl, rssUrl, primaryColor, author, imagePath FROM PodcastLocal WHERE id = ?',
|
||||
[s]);
|
||||
podcastLocal.add(PodcastLocal(
|
||||
list.first['title'],
|
||||
list.first['imageUrl'],
|
||||
list.first['rssUrl'],
|
||||
list.first['primaryColor'],
|
||||
list.first['author'],
|
||||
id: list.first['id']));
|
||||
list.first['id'],
|
||||
list.first['imagePath']));
|
||||
});
|
||||
return podcastLocal;
|
||||
}
|
||||
|
@ -72,27 +62,21 @@ class DBHelper {
|
|||
Future<List<PodcastLocal>> getPodcastLocalAll() async {
|
||||
var dbClient = await database;
|
||||
List<Map> list = await dbClient.rawQuery(
|
||||
'SELECT title, imageUrl, rssUrl, primaryColor, author FROM PodcastLocal ORDER BY add_date DESC');
|
||||
'SELECT title, imageUrl, rssUrl, primaryColor, author, imagePath FROM PodcastLocal ORDER BY add_date DESC');
|
||||
List<PodcastLocal> podcastLocal = List();
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
podcastLocal.add(PodcastLocal(list[i]['title'], list[i]['imageUrl'],
|
||||
list[i]['rssUrl'], list[i]['primaryColor'], list[i]['author'],
|
||||
id: list[i]['id']));
|
||||
podcastLocal.add(PodcastLocal(
|
||||
list[i]['title'],
|
||||
list[i]['imageUrl'],
|
||||
list[i]['rssUrl'],
|
||||
list[i]['primaryColor'],
|
||||
list[i]['author'],
|
||||
list[i]['id'],
|
||||
list[i]['imagePath']));
|
||||
}
|
||||
return podcastLocal;
|
||||
}
|
||||
|
||||
//save podcast order adter user save
|
||||
saveOrder(List<PodcastLocal> podcastList) async {
|
||||
var dbClient = await database;
|
||||
for (int i = 0; i < podcastList.length; i++) {
|
||||
await dbClient.rawUpdate(
|
||||
"UPDATE OR IGNORE PodcastLocal SET order_id = ? WHERE title = ?",
|
||||
[i, podcastList[i].title]);
|
||||
print(podcastList[i].title);
|
||||
}
|
||||
}
|
||||
|
||||
Future savePodcastLocal(PodcastLocal podcastLocal) async {
|
||||
print('podcast saved in sqllite');
|
||||
int _milliseconds = DateTime.now().millisecondsSinceEpoch;
|
||||
|
@ -100,7 +84,7 @@ class DBHelper {
|
|||
await dbClient.transaction((txn) async {
|
||||
return await txn.rawInsert(
|
||||
"""INSERT OR IGNORE INTO PodcastLocal (id, title, imageUrl, rssUrl,
|
||||
primaryColor, author, description, add_date) VALUES(?, ?, ?, ?, ?, ?, ?, ?)""",
|
||||
primaryColor, author, description, add_date, imagePath) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
||||
[
|
||||
podcastLocal.id,
|
||||
podcastLocal.title,
|
||||
|
@ -109,50 +93,36 @@ class DBHelper {
|
|||
podcastLocal.primaryColor,
|
||||
podcastLocal.author,
|
||||
podcastLocal.description,
|
||||
_milliseconds
|
||||
_milliseconds,
|
||||
podcastLocal.imagePath
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
Future delPodcastLocal(String title) async {
|
||||
print('deleted');
|
||||
Future delPodcastLocal(String id) async {
|
||||
var dbClient = await database;
|
||||
await dbClient
|
||||
.rawDelete('DELETE FROM PodcastLocal WHERE title =?', [title]);
|
||||
await dbClient.rawDelete('DELETE FROM PodcastLocal WHERE id =?', [id]);
|
||||
List<Map> list = await dbClient.rawQuery(
|
||||
"""SELECT downloaded FROM Episodes WHERE downloaded != 'ND' AND feed_title = ?""",
|
||||
[title]);
|
||||
"""SELECT downloaded FROM Episodes WHERE downloaded != 'ND' AND feed_id = ?""",
|
||||
[id]);
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
if (list[i] != null)
|
||||
FlutterDownloader.remove(
|
||||
taskId: list[i]['downloaded'], shouldDeleteContent: true);
|
||||
print('Removed all download tasks');
|
||||
}
|
||||
await dbClient
|
||||
.rawDelete('DELETE FROM Episodes WHERE feed_title=?', [title]);
|
||||
}
|
||||
|
||||
Future getImageUrl(String title) async {
|
||||
var dbClient = await database;
|
||||
List<Map> list = await dbClient
|
||||
.rawQuery('SELECT imageUrl FROM PodcastLocal WHERE title = ?', [title]);
|
||||
String url = list[0]['imageUrl'];
|
||||
return url;
|
||||
await dbClient.rawDelete('DELETE FROM Episodes WHERE feed_id=?', [id]);
|
||||
}
|
||||
|
||||
DateTime _parsePubDate(String pubDate) {
|
||||
if (pubDate == null) return null;
|
||||
DateTime date;
|
||||
try {
|
||||
date = DateFormat('EEE, dd MMM yyyy HH:mm:ss Z', 'en_US').parse(pubDate);
|
||||
print('e');
|
||||
date = DateFormat('dd MMM yyyy HH:mm:ss Z', 'en_US').parse(pubDate);
|
||||
} catch (e) {
|
||||
try {
|
||||
print('e');
|
||||
date = DateFormat('dd MMM yyyy HH:mm:ss Z', 'en_US').parse(pubDate);
|
||||
} catch (e) {
|
||||
print('e');
|
||||
date = DateTime(0);
|
||||
}
|
||||
print('e');
|
||||
date = DateTime(0);
|
||||
}
|
||||
return date;
|
||||
}
|
||||
|
@ -173,7 +143,57 @@ class DBHelper {
|
|||
return ximalaya.hasMatch(input);
|
||||
}
|
||||
|
||||
Future<int> savePodcastRss(RssFeed _p) async {
|
||||
Future<int> savePodcastRss(RssFeed _p, String id) async {
|
||||
String _title;
|
||||
String _url;
|
||||
String _description;
|
||||
int _duration;
|
||||
int _result = _p.items.length;
|
||||
var dbClient = await database;
|
||||
for (int i = 0; i < _result; i++) {
|
||||
print(_p.items[i].title);
|
||||
_title = _p.items[i].itunes.title ?? _p.items[i].title;
|
||||
_p.items[i].itunes.summary.contains('<')
|
||||
? _description = _p.items[i].itunes.summary
|
||||
: _description = _p.items[i].description;
|
||||
|
||||
isXimalaya(_p.items[i].enclosure.url)
|
||||
? _url = _p.items[i].enclosure.url.split('=').last
|
||||
: _url = _p.items[i].enclosure.url;
|
||||
|
||||
final _length = _p.items[i].enclosure.length;
|
||||
final _pubDate = _p.items[i].pubDate;
|
||||
final _date = _parsePubDate(_pubDate);
|
||||
final _milliseconds = _date.millisecondsSinceEpoch;
|
||||
|
||||
_duration = _p.items[i].itunes.duration?.inMinutes ?? 0;
|
||||
|
||||
final _explicit = getExplicit(_p.items[i].itunes.explicit);
|
||||
if (_p.items[i].enclosure.url != null) {
|
||||
await dbClient.transaction((txn) {
|
||||
return txn.rawInsert(
|
||||
"""INSERT OR IGNORE INTO Episodes(title, enclosure_url, enclosure_length, pubDate,
|
||||
description, feed_id, milliseconds, duration, explicit) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
||||
[
|
||||
_title,
|
||||
_url,
|
||||
_length,
|
||||
_pubDate,
|
||||
_description,
|
||||
id,
|
||||
_milliseconds,
|
||||
_duration,
|
||||
_explicit,
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
Future<int> updatePodcastRss(PodcastLocal podcastLocal) async {
|
||||
Response response = await Dio().get(podcastLocal.rssUrl);
|
||||
var _p = RssFeed.parse(response.data);
|
||||
String _title;
|
||||
String _url;
|
||||
String _description;
|
||||
|
@ -181,7 +201,7 @@ class DBHelper {
|
|||
int _result = _p.items.length;
|
||||
var dbClient = await database;
|
||||
int _count = Sqflite.firstIntValue(await dbClient.rawQuery(
|
||||
'SELECT COUNT(*) FROM Episodes WHERE feed_title = ?', [_p.title]));
|
||||
'SELECT COUNT(*) FROM Episodes WHERE feed_id = ?', [podcastLocal.id]));
|
||||
print(_count);
|
||||
if (_count == _result) {
|
||||
_result = 0;
|
||||
|
@ -210,14 +230,14 @@ class DBHelper {
|
|||
await dbClient.transaction((txn) {
|
||||
return txn.rawInsert(
|
||||
"""INSERT OR IGNORE INTO Episodes(title, enclosure_url, enclosure_length, pubDate,
|
||||
description, feed_title, milliseconds, duration, explicit) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
||||
description, feed_id, milliseconds, duration, explicit) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
||||
[
|
||||
_title,
|
||||
_url,
|
||||
_length,
|
||||
_pubDate,
|
||||
_description,
|
||||
_p.title,
|
||||
podcastLocal.id,
|
||||
_milliseconds,
|
||||
_duration,
|
||||
_explicit,
|
||||
|
@ -225,20 +245,19 @@ class DBHelper {
|
|||
});
|
||||
}
|
||||
}
|
||||
_result = 0;
|
||||
return _result;
|
||||
return _result - _count;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<EpisodeBrief>> getRssItem(String title) async {
|
||||
Future<List<EpisodeBrief>> getRssItem(String id) async {
|
||||
var dbClient = await database;
|
||||
List<EpisodeBrief> episodes = List();
|
||||
List<Map> list = await dbClient
|
||||
.rawQuery("""SELECT E.title, E.enclosure_url, E.enclosure_length,
|
||||
E.pubDate, E.feed_title, E.duration, E.explicit, E.liked,
|
||||
E.downloaded, P.imageUrl, P.primaryColor
|
||||
FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_title = P.title
|
||||
where E.feed_title = ? ORDER BY E.milliseconds DESC""", [title]);
|
||||
E.pubDate, P.imagePath, P.title as feed_title, E.duration, E.explicit, E.liked,
|
||||
E.downloaded, P.primaryColor
|
||||
FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
|
||||
where E.feed_id = ? ORDER BY E.milliseconds DESC""", [id]);
|
||||
for (int x = 0; x < list.length; x++) {
|
||||
episodes.add(EpisodeBrief(
|
||||
list[x]['title'],
|
||||
|
@ -246,27 +265,25 @@ class DBHelper {
|
|||
list[x]['enclosure_length'],
|
||||
list[x]['pubDate'],
|
||||
list[x]['feed_title'],
|
||||
list[x]['imageUrl'],
|
||||
list[x]['primaryColor'],
|
||||
list[x]['liked'],
|
||||
list[x]['downloaded'],
|
||||
list[x]['duration'],
|
||||
list[x]['explicit']));
|
||||
list[x]['explicit'],
|
||||
list[x]['imagePath']));
|
||||
}
|
||||
print('Loaded' + title);
|
||||
return episodes;
|
||||
}
|
||||
|
||||
Future<List<EpisodeBrief>> getRssItemTop(String title) async {
|
||||
Future<List<EpisodeBrief>> getRssItemTop(String id) async {
|
||||
var dbClient = await database;
|
||||
List<EpisodeBrief> episodes = List();
|
||||
List<Map> list = await dbClient.rawQuery(
|
||||
"""SELECT E.title, E.enclosure_url, E.enclosure_length,
|
||||
E.pubDate, E.feed_title, E.duration, E.explicit, E.liked,
|
||||
E.downloaded, P.imageUrl, P.primaryColor
|
||||
FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_title = P.title
|
||||
where E.feed_title = ? ORDER BY E.milliseconds DESC LIMIT 3""",
|
||||
[title]);
|
||||
List<Map> list = await dbClient
|
||||
.rawQuery("""SELECT E.title, E.enclosure_url, E.enclosure_length,
|
||||
E.pubDate, P.imagePath, P.title as feed_title, E.duration, E.explicit, E.liked,
|
||||
E.downloaded, P.primaryColor
|
||||
FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
|
||||
where E.feed_id = ? ORDER BY E.milliseconds DESC LIMIT 3""", [id]);
|
||||
for (int x = 0; x < list.length; x++) {
|
||||
episodes.add(EpisodeBrief(
|
||||
list[x]['title'],
|
||||
|
@ -274,14 +291,13 @@ class DBHelper {
|
|||
list[x]['enclosure_length'],
|
||||
list[x]['pubDate'],
|
||||
list[x]['feed_title'],
|
||||
list[x]['imageUrl'],
|
||||
list[x]['primaryColor'],
|
||||
list[x]['liked'],
|
||||
list[x]['downloaded'],
|
||||
list[x]['duration'],
|
||||
list[x]['explicit']));
|
||||
list[x]['explicit'],
|
||||
list[x]['imagePath']));
|
||||
}
|
||||
print(title);
|
||||
return episodes;
|
||||
}
|
||||
|
||||
|
@ -290,9 +306,9 @@ class DBHelper {
|
|||
EpisodeBrief episode;
|
||||
List<Map> list = await dbClient.rawQuery(
|
||||
"""SELECT E.title, E.enclosure_url, E.enclosure_length,
|
||||
E.pubDate, E.feed_title, E.duration, E.explicit, E.liked,
|
||||
E.downloaded, P.imageUrl, P.primaryColor
|
||||
FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_title = P.title
|
||||
E.pubDate, P.imagePath, P.title as feed_title, E.duration, E.explicit, E.liked,
|
||||
E.downloaded, P.primaryColor
|
||||
FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
|
||||
where E.enclosure_url = ? ORDER BY E.milliseconds DESC LIMIT 3""",
|
||||
[url]);
|
||||
|
||||
|
@ -303,12 +319,12 @@ class DBHelper {
|
|||
list.first['enclosure_length'],
|
||||
list.first['pubDate'],
|
||||
list.first['feed_title'],
|
||||
list.first['imageUrl'],
|
||||
list.first['primaryColor'],
|
||||
list.first['liked'],
|
||||
list.first['downloaded'],
|
||||
list.first['duration'],
|
||||
list.first['explicit']);
|
||||
list.first['explicit'],
|
||||
list.first['imagePath']);
|
||||
return episode;
|
||||
}
|
||||
|
||||
|
@ -317,9 +333,9 @@ class DBHelper {
|
|||
List<EpisodeBrief> episodes = List();
|
||||
List<Map> list = await dbClient
|
||||
.rawQuery("""SELECT E.title, E.enclosure_url, E.enclosure_length,
|
||||
E.pubDate, E.feed_title, E.duration, E.explicit, E.liked,
|
||||
E.downloaded, P.imageUrl, P.primaryColor
|
||||
FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_title = P.title
|
||||
E.pubDate, P.title as feed_title, E.duration, E.explicit, E.liked,
|
||||
E.downloaded, P.imagePath, P.primaryColor
|
||||
FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
|
||||
ORDER BY E.milliseconds DESC LIMIT 99""");
|
||||
for (int x = 0; x < list.length; x++) {
|
||||
episodes.add(EpisodeBrief(
|
||||
|
@ -328,12 +344,13 @@ class DBHelper {
|
|||
list[x]['enclosure_length'],
|
||||
list[x]['pubDate'],
|
||||
list[x]['feed_title'],
|
||||
list[x]['imageUrl'],
|
||||
list[x]['primaryColor'],
|
||||
list[x]['liked'],
|
||||
list[x]['doanloaded'],
|
||||
list[x]['duration'],
|
||||
list[x]['explicit']));
|
||||
list[x]['explicit'],
|
||||
list[x]['imagePath']
|
||||
));
|
||||
}
|
||||
return episodes;
|
||||
}
|
||||
|
@ -342,9 +359,9 @@ class DBHelper {
|
|||
var dbClient = await database;
|
||||
List<EpisodeBrief> episodes = List();
|
||||
List<Map> list = await dbClient.rawQuery(
|
||||
"""SELECT E.title, E.enclosure_url, E.enclosure_length, E.pubDate,
|
||||
E.feed_title, E.duration, E.explicit, E.liked, E.downloaded, P.imageUrl,
|
||||
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_title = P.title
|
||||
"""SELECT E.title, E.enclosure_url, E.enclosure_length, E.pubDate, P.imagePath,
|
||||
P.title as feed_title, E.duration, E.explicit, E.liked, E.downloaded,
|
||||
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
|
||||
WHERE E.liked = 1 ORDER BY E.milliseconds DESC LIMIT 99""");
|
||||
for (int x = 0; x < list.length; x++) {
|
||||
episodes.add(EpisodeBrief(
|
||||
|
@ -353,28 +370,28 @@ class DBHelper {
|
|||
list[x]['enclosure_length'],
|
||||
list[x]['pubDate'],
|
||||
list[x]['feed_title'],
|
||||
list[x]['imageUrl'],
|
||||
list[x]['primaryColor'],
|
||||
list[x]['liked'],
|
||||
list[x]['downloaded'],
|
||||
list[x]['duration'],
|
||||
list[x]['explicit']));
|
||||
list[x]['explicit'],
|
||||
list[x]['imagePath']));
|
||||
}
|
||||
return episodes;
|
||||
}
|
||||
|
||||
Future<int> setLiked(String title) async {
|
||||
Future<int> setLiked(String url) async {
|
||||
var dbClient = await database;
|
||||
int count = await dbClient
|
||||
.rawUpdate("UPDATE Episodes SET liked = 1 WHERE title = ?", [title]);
|
||||
int count = await dbClient.rawUpdate(
|
||||
"UPDATE Episodes SET liked = 1 WHERE enclosure_url= ?", [url]);
|
||||
print('liked');
|
||||
return count;
|
||||
}
|
||||
|
||||
Future<int> setUniked(String title) async {
|
||||
Future<int> setUniked(String url) async {
|
||||
var dbClient = await database;
|
||||
int count = await dbClient
|
||||
.rawUpdate("UPDATE Episodes SET liked = 0 WHERE title = ?", [title]);
|
||||
int count = await dbClient.rawUpdate(
|
||||
"UPDATE Episodes SET liked = 0 WHERE enclosure_url = ?", [url]);
|
||||
print('unliked');
|
||||
return count;
|
||||
}
|
||||
|
@ -400,9 +417,9 @@ class DBHelper {
|
|||
var dbClient = await database;
|
||||
List<EpisodeBrief> episodes = List();
|
||||
List<Map> list = await dbClient.rawQuery(
|
||||
"""SELECT E.title, E.enclosure_url, E.enclosure_length, E.pubDate,
|
||||
E.feed_title, E.duration, E.explicit, E.liked, E.downloaded, P.imageUrl,
|
||||
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_title = P.title
|
||||
"""SELECT E.title, E.enclosure_url, E.enclosure_length, E.pubDate, P.imagePath,
|
||||
P.title as feed_title, E.duration, E.explicit, E.liked, E.downloaded,
|
||||
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
|
||||
WHERE E.downloaded != 'ND' ORDER BY E.download_date DESC LIMIT 99""");
|
||||
for (int x = 0; x < list.length; x++) {
|
||||
episodes.add(EpisodeBrief(
|
||||
|
@ -411,28 +428,28 @@ class DBHelper {
|
|||
list[x]['enclosure_length'],
|
||||
list[x]['pubDate'],
|
||||
list[x]['feed_title'],
|
||||
list[x]['imageUrl'],
|
||||
list[x]['primaryColor'],
|
||||
list[x]['liked'],
|
||||
list[x]['downloaded'],
|
||||
list[x]['duration'],
|
||||
list[x]['explicit']));
|
||||
list[x]['explicit'],
|
||||
list[x]['imagePath']));
|
||||
}
|
||||
return episodes;
|
||||
}
|
||||
|
||||
Future<String> getDescription(String title) async {
|
||||
Future<String> getDescription(String url) async {
|
||||
var dbClient = await database;
|
||||
List<Map> list = await dbClient
|
||||
.rawQuery('SELECT description FROM Episodes WHERE title = ?', [title]);
|
||||
List<Map> list = await dbClient.rawQuery(
|
||||
'SELECT description FROM Episodes WHERE enclosure_url = ?', [url]);
|
||||
String description = list[0]['description'];
|
||||
return description;
|
||||
}
|
||||
|
||||
Future<String> getFeedDescription(String title) async {
|
||||
Future<String> getFeedDescription(String url) async {
|
||||
var dbClient = await database;
|
||||
List<Map> list = await dbClient.rawQuery(
|
||||
'SELECT description FROM PodcastLocal WHERE title = ?', [title]);
|
||||
'SELECT description FROM PodcastLocal WHERE enclosure_url = ?', [url]);
|
||||
String description = list[0]['description'];
|
||||
return description;
|
||||
}
|
||||
|
@ -441,9 +458,9 @@ class DBHelper {
|
|||
var dbClient = await database;
|
||||
EpisodeBrief episode;
|
||||
List<Map> list = await dbClient.rawQuery(
|
||||
"""SELECT E.title, E.enclosure_url, E.enclosure_length, E.pubDate,
|
||||
E.feed_title, E.duration, E.explicit, E.liked, E.downloaded, P.imageUrl,
|
||||
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_title = P.title
|
||||
"""SELECT E.title, E.enclosure_url, E.enclosure_length, E.pubDate, P.imagePath,
|
||||
P.title as feed_title, E.duration, E.explicit, E.liked, E.downloaded,
|
||||
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
|
||||
WHERE E.enclosure_url = ?""", [url]);
|
||||
episode = EpisodeBrief(
|
||||
list.first['title'],
|
||||
|
@ -451,12 +468,12 @@ class DBHelper {
|
|||
list.first['enclosure_length'],
|
||||
list.first['pubDate'],
|
||||
list.first['feed_title'],
|
||||
list.first['imageUrl'],
|
||||
list.first['primaryColor'],
|
||||
list.first['liked'],
|
||||
list.first['downloaded'],
|
||||
list.first['duration'],
|
||||
list.first['explicit']);
|
||||
list.first['explicit'],
|
||||
list.first['imagePath']);
|
||||
return episode;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_statusbarcolor/flutter_statusbarcolor.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_downloader/flutter_downloader.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:tsacdop/class/podcast_group.dart';
|
||||
import 'package:tsacdop/home/appbar/addpodcast.dart';
|
||||
import 'package:tsacdop/class/audiostate.dart';
|
||||
|
@ -16,7 +13,7 @@ void main() async {
|
|||
runApp(
|
||||
MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider(create: (context) => Urlchange()),
|
||||
ChangeNotifierProvider(create: (context) => AudioPlay()),
|
||||
ChangeNotifierProvider(create: (context) => ImportOmpl()),
|
||||
ChangeNotifierProvider(create: (context) => SettingState()),
|
||||
ChangeNotifierProvider(create: (context) => GroupList()),
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:tsacdop/class/podcastlocal.dart';
|
||||
import 'package:tsacdop/class/episodebrief.dart';
|
||||
import 'package:tsacdop/local_storage/sqflite_localpodcast.dart';
|
||||
import 'package:tsacdop/util/episodegrid.dart';
|
||||
import 'package:tsacdop/webfeed/webfeed.dart';
|
||||
|
||||
class PodcastDetail extends StatefulWidget {
|
||||
PodcastDetail({Key key, this.podcastLocal}) : super(key: key);
|
||||
|
@ -22,16 +20,23 @@ class _PodcastDetailState extends State<PodcastDetail> {
|
|||
|
||||
Future _updateRssItem(PodcastLocal podcastLocal) async {
|
||||
var dbHelper = DBHelper();
|
||||
final response = await Dio().get(podcastLocal.rssUrl);
|
||||
var _p = RssFeed.parse(response.data);
|
||||
final result = await dbHelper.savePodcastRss(_p);
|
||||
if (result == 0 && mounted) setState(() {});
|
||||
final result = await dbHelper.updatePodcastRss(podcastLocal);
|
||||
result == 0 ?
|
||||
Fluttertoast.showToast(
|
||||
msg: 'No Update',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
)
|
||||
: Fluttertoast.showToast(
|
||||
msg: 'Updated $result Episodes',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
if(mounted) setState(() {});
|
||||
}
|
||||
|
||||
Future<List<EpisodeBrief>> _getRssItem(PodcastLocal podcastLocal) async {
|
||||
var dbHelper = DBHelper();
|
||||
List<EpisodeBrief> episodes = await
|
||||
dbHelper.getRssItem(podcastLocal.title);
|
||||
dbHelper.getRssItem(podcastLocal.id);
|
||||
return episodes;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,9 @@ import 'dart:io';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tsacdop/class/podcast_group.dart';
|
||||
import 'package:tsacdop/class/podcastlocal.dart';
|
||||
import 'package:tsacdop/local_storage/sqflite_localpodcast.dart';
|
||||
import 'package:tsacdop/class/settingstate.dart';
|
||||
|
||||
class PodcastGroupList extends StatefulWidget {
|
||||
final PodcastGroup group;
|
||||
|
@ -19,31 +16,17 @@ class PodcastGroupList extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _PodcastGroupListState extends State<PodcastGroupList> {
|
||||
bool _loading;
|
||||
bool _loadSave;
|
||||
String dir;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loading = false;
|
||||
_loadSave = false;
|
||||
getApplicationDocumentsDirectory().then((value) {
|
||||
dir = value.path;
|
||||
setState(() {
|
||||
_loading = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Widget _saveButton(BuildContext context) {
|
||||
var _settingState = Provider.of<SettingState>(context);
|
||||
_saveOrder(List<PodcastLocal> podcastList) async {
|
||||
var dbHelper = DBHelper();
|
||||
await dbHelper.saveOrder(podcastList);
|
||||
}
|
||||
|
||||
var podcastList = widget.group.podcasts;
|
||||
var _groupList = Provider.of<GroupList>(context);
|
||||
return Container(
|
||||
child: InkWell(
|
||||
child: AnimatedContainer(
|
||||
|
@ -51,8 +34,9 @@ class _PodcastGroupListState extends State<PodcastGroupList> {
|
|||
width: _loadSave ? 70 : 0,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue,
|
||||
borderRadius: BorderRadius.all(Radius.circular(5.0))),
|
||||
color: Colors.blue,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
'Save',
|
||||
|
@ -60,12 +44,11 @@ class _PodcastGroupListState extends State<PodcastGroupList> {
|
|||
maxLines: 1,
|
||||
)),
|
||||
onTap: () async {
|
||||
await _saveOrder(podcastList);
|
||||
await _groupList.saveOrder(widget.group, podcastList);
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Setting Saved',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
_settingState.subscribeUpdate = Update.justupdate;
|
||||
setState(() {
|
||||
_loadSave = false;
|
||||
});
|
||||
|
@ -77,82 +60,70 @@ class _PodcastGroupListState extends State<PodcastGroupList> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return widget.group.podcastList.length == 0
|
||||
? Center()
|
||||
: Container(
|
||||
color: Colors.grey[100],
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
ReorderableListView(
|
||||
onReorder: (int oldIndex, int newIndex) {
|
||||
setState(() {
|
||||
if (newIndex > oldIndex) {
|
||||
newIndex -= 1;
|
||||
}
|
||||
final PodcastLocal podcast =
|
||||
widget.group.podcasts.removeAt(oldIndex);
|
||||
widget.group.podcasts.insert(newIndex, podcast);
|
||||
_loadSave = true;
|
||||
});
|
||||
},
|
||||
children:
|
||||
widget.group.podcasts.map<Widget>((PodcastLocal podcastLocal) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(color: Colors.grey[100]),
|
||||
key: ObjectKey(podcastLocal.title),
|
||||
child: !_loading
|
||||
? CircularProgressIndicator()
|
||||
: PodcastCard(
|
||||
path: dir,
|
||||
? Container(
|
||||
color: Colors.grey[100],
|
||||
)
|
||||
: Container(
|
||||
color: Colors.grey[100],
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
ReorderableListView(
|
||||
onReorder: (int oldIndex, int newIndex) {
|
||||
setState(() {
|
||||
if (newIndex > oldIndex) {
|
||||
newIndex -= 1;
|
||||
}
|
||||
final PodcastLocal podcast =
|
||||
widget.group.podcasts.removeAt(oldIndex);
|
||||
widget.group.podcasts.insert(newIndex, podcast);
|
||||
_loadSave = true;
|
||||
});
|
||||
},
|
||||
children: widget.group.podcasts
|
||||
.map<Widget>((PodcastLocal podcastLocal) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(color: Colors.grey[100]),
|
||||
key: ObjectKey(podcastLocal.title),
|
||||
child: PodcastCard(
|
||||
podcastLocal: podcastLocal,
|
||||
group: widget.group.name,
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
AnimatedPositioned(
|
||||
duration: Duration(seconds: 1),
|
||||
bottom: 30,
|
||||
right: _loadSave ? 50 : 0,
|
||||
child: Center(),
|
||||
//_saveButton(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
AnimatedPositioned(
|
||||
duration: Duration(seconds: 1),
|
||||
bottom: 30,
|
||||
right: _loadSave ? 50 : 0,
|
||||
child: _saveButton(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PodcastCard extends StatefulWidget {
|
||||
final PodcastLocal podcastLocal;
|
||||
final String path;
|
||||
final String group;
|
||||
PodcastCard({this.podcastLocal, this.path, this.group, Key key})
|
||||
: super(key: key);
|
||||
PodcastCard({this.podcastLocal, this.group, Key key}) : super(key: key);
|
||||
@override
|
||||
_PodcastCardState createState() => _PodcastCardState();
|
||||
}
|
||||
|
||||
class _PodcastCardState extends State<PodcastCard> {
|
||||
bool _loadMenu;
|
||||
bool _remove;
|
||||
bool _addGroup;
|
||||
bool _loadGroup;
|
||||
List<String> _selectedGroups;
|
||||
List<String> _belongGroups;
|
||||
Color _c;
|
||||
|
||||
_unSubscribe(String title) async {
|
||||
var dbHelper = DBHelper();
|
||||
await dbHelper.delPodcastLocal(title);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadMenu = false;
|
||||
_remove = false;
|
||||
_addGroup = false;
|
||||
_loadGroup = false;
|
||||
_selectedGroups = [widget.group];
|
||||
}
|
||||
|
||||
Widget _buttonOnMenu(Widget widget, VoidCallback onTap) => Material(
|
||||
|
@ -174,225 +145,200 @@ class _PodcastCardState extends State<PodcastCard> {
|
|||
(255 - color[0]), 255 - color[1], 255 - color[2], 1.0)
|
||||
: _c = Color.fromRGBO(color[0], color[1], color[2], 1.0);
|
||||
double _width = MediaQuery.of(context).size.width;
|
||||
var _settingState = Provider.of<SettingState>(context);
|
||||
var _groupList = Provider.of<GroupList>(context);
|
||||
_selectedGroups = _groupList.groups.map((e) => e.name).toList();
|
||||
_belongGroups = _groupList
|
||||
.getPodcastGroup(widget.podcastLocal.id)
|
||||
.map((e) => e.name)
|
||||
.toList();
|
||||
return _remove
|
||||
? Center()
|
||||
: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
InkWell(
|
||||
onTap: () => setState(() => _loadMenu = !_loadMenu),
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12),
|
||||
height: 100,
|
||||
child: Row(children: <Widget>[
|
||||
Container(
|
||||
child: Icon(
|
||||
Icons.unfold_more,
|
||||
color: _c,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(30)),
|
||||
child: Container(
|
||||
height: 60,
|
||||
width: 60,
|
||||
child: Image.file(File(
|
||||
"${widget.path}/${widget.podcastLocal.title}.png")),
|
||||
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
InkWell(
|
||||
onTap: () => setState(() => _loadMenu = !_loadMenu),
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12),
|
||||
height: 100,
|
||||
child: Row(children: <Widget>[
|
||||
Container(
|
||||
child: Icon(
|
||||
Icons.unfold_more,
|
||||
color: _c,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(30)),
|
||||
child: Container(
|
||||
height: 60,
|
||||
width: 60,
|
||||
child: Image.file(File("${widget.podcastLocal.imagePath}")),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: _width / 2,
|
||||
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
widget.podcastLocal.title,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.fade,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold, fontSize: 15),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: _width / 2,
|
||||
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Column(
|
||||
Row(
|
||||
children: _belongGroups.map((group) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(right: 5.0),
|
||||
child: Text(group));
|
||||
}).toList(),
|
||||
),
|
||||
],
|
||||
)),
|
||||
Spacer(),
|
||||
Icon(_loadMenu
|
||||
? Icons.keyboard_arrow_up
|
||||
: Icons.keyboard_arrow_down),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 5.0),
|
||||
),
|
||||
OutlineButton(
|
||||
child: Text('Remove'),
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
child: AlertDialog(
|
||||
elevation: 2.0,
|
||||
title: Text('Remove confirm'),
|
||||
content: Text(
|
||||
'${widget.podcastLocal.title} will be removed from device.'),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text('CANCEL'),
|
||||
),
|
||||
FlatButton(
|
||||
onPressed: () {
|
||||
_groupList.removePodcast(widget.podcastLocal.id);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(
|
||||
'CONFIRM',
|
||||
style: TextStyle(color: Colors.red),
|
||||
),
|
||||
)
|
||||
],
|
||||
));
|
||||
},
|
||||
),
|
||||
]),
|
||||
),
|
||||
),
|
||||
!_loadMenu
|
||||
? Center()
|
||||
: Container(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[100],
|
||||
border: Border(
|
||||
bottom: BorderSide(color: Colors.grey[300]),
|
||||
top: BorderSide(color: Colors.grey[300]))),
|
||||
height: 50,
|
||||
child: _addGroup
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
widget.podcastLocal.title,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.fade,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold, fontSize: 15),
|
||||
Expanded(
|
||||
flex: 4,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: _groupList.groups
|
||||
.map<Widget>((PodcastGroup group){
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 5.0),
|
||||
child: FilterChip(
|
||||
key: ValueKey<String>(group.id),
|
||||
label: Text(group.name),
|
||||
selected:
|
||||
_selectedGroups.contains(group.name),
|
||||
onSelected: (bool value) {
|
||||
setState(() {
|
||||
if (!value) {
|
||||
_selectedGroups.remove(group.name);
|
||||
print(group.name);
|
||||
} else {
|
||||
_selectedGroups.add(group.name);
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
}).toList()),
|
||||
),
|
||||
),
|
||||
!_loadGroup
|
||||
? Center()
|
||||
: Row(
|
||||
children: _belongGroups.map((group) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(right: 5.0),
|
||||
child: Text(group));
|
||||
}).toList(),
|
||||
),
|
||||
],
|
||||
)),
|
||||
Spacer(),
|
||||
Icon(_loadMenu
|
||||
? Icons.keyboard_arrow_up
|
||||
: Icons.keyboard_arrow_down),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 5.0),
|
||||
),
|
||||
OutlineButton(
|
||||
child: Text('Remove'),
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
child: AlertDialog(
|
||||
title: Text('Remove confirm'),
|
||||
content: Text(
|
||||
'${widget.podcastLocal.title} will be removed from device.'),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text('CANCEL'),
|
||||
),
|
||||
FlatButton(
|
||||
onPressed: () {
|
||||
_unSubscribe(widget.podcastLocal.title);
|
||||
_settingState.subscribeUpdate =
|
||||
Update.justupdate;
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(
|
||||
'CONFIRM',
|
||||
style: TextStyle(color: Colors.red),
|
||||
),
|
||||
)
|
||||
],
|
||||
));
|
||||
},
|
||||
),
|
||||
]),
|
||||
),
|
||||
),
|
||||
!_loadMenu
|
||||
? Center()
|
||||
: Container(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[100],
|
||||
border: Border(
|
||||
bottom: BorderSide(color: Colors.grey[300]),
|
||||
top: BorderSide(color: Colors.grey[300]))),
|
||||
height: 50,
|
||||
child: _addGroup
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
flex: 4,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Consumer<GroupList>(
|
||||
builder: (_, groupList, __) => Row(
|
||||
children: groupList.groups
|
||||
.map<Widget>(
|
||||
(PodcastGroup group) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 5.0),
|
||||
child: FilterChip(
|
||||
key: ValueKey<String>(group.name),
|
||||
label: Text(group.name),
|
||||
selected: _belongGroups
|
||||
.contains(group.name) &&
|
||||
_selectedGroups
|
||||
.contains(group.name),
|
||||
onSelected: (bool value) {
|
||||
setState(() {
|
||||
if (!value) {
|
||||
_selectedGroups
|
||||
.remove(group.name);
|
||||
} else {
|
||||
_selectedGroups
|
||||
.add(group.name);
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
}).toList()),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.clear),
|
||||
onPressed: () => setState(() {
|
||||
_addGroup = false;
|
||||
}),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
print(_selectedGroups);
|
||||
if (_selectedGroups.length > 0) {
|
||||
setState(() {
|
||||
_addGroup = false;
|
||||
});
|
||||
await _groupList.changeGroup(
|
||||
widget.podcastLocal.id,
|
||||
_selectedGroups,
|
||||
);
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Setting Saved',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
} else
|
||||
Fluttertoast.showToast(
|
||||
msg: 'At least select one group',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
},
|
||||
icon: Icon(Icons.done),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
IconButton(
|
||||
icon: Icon(Icons.clear),
|
||||
onPressed: () => setState(() {
|
||||
_addGroup = false;
|
||||
}),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
print(_selectedGroups);
|
||||
if (_selectedGroups.length > 0) {
|
||||
setState(() {
|
||||
_addGroup = false;
|
||||
});
|
||||
await _groupList.changeGroup(
|
||||
widget.podcastLocal.id,
|
||||
_selectedGroups,
|
||||
);
|
||||
_settingState.subscribeUpdate =
|
||||
Update.justupdate;
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Setting Saved',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
if (!_selectedGroups
|
||||
.contains(widget.group)) {
|
||||
print(widget.group);
|
||||
setState(() {
|
||||
_remove = true;
|
||||
});
|
||||
}
|
||||
} else
|
||||
Fluttertoast.showToast(
|
||||
msg:
|
||||
'At least select one group',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
},
|
||||
icon: Icon(Icons.done),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceEvenly,
|
||||
children: <Widget>[
|
||||
_buttonOnMenu(Icon(Icons.fullscreen), () {}),
|
||||
_buttonOnMenu(Icon(Icons.add), () {
|
||||
setState(() {
|
||||
_addGroup = true;
|
||||
});
|
||||
}),
|
||||
_buttonOnMenu(
|
||||
Icon(Icons.notifications), () {})
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
)
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: <Widget>[
|
||||
_buttonOnMenu(Icon(Icons.fullscreen), () {}),
|
||||
_buttonOnMenu(Icon(Icons.add), () {
|
||||
setState(() {
|
||||
_addGroup = true;
|
||||
});
|
||||
}),
|
||||
_buttonOnMenu(Icon(Icons.notifications), () {})
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,10 @@ import 'package:flutter/rendering.dart';
|
|||
import 'dart:async';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_html/flutter_html.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tsacdop/class/podcast_group.dart';
|
||||
|
||||
import 'package:tsacdop/class/podcastlocal.dart';
|
||||
import 'package:tsacdop/class/settingstate.dart';
|
||||
import 'package:tsacdop/local_storage/sqflite_localpodcast.dart';
|
||||
import 'package:tsacdop/podcasts/podcastdetail.dart';
|
||||
import 'package:tsacdop/util/pageroute.dart';
|
||||
|
@ -23,12 +22,6 @@ class AboutPodcast extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _AboutPodcastState extends State<AboutPodcast> {
|
||||
void _unSubscribe(String t) async {
|
||||
var dbHelper = DBHelper();
|
||||
dbHelper.delPodcastLocal(t);
|
||||
print('Unsubscribe');
|
||||
}
|
||||
|
||||
String _description;
|
||||
bool _load;
|
||||
|
||||
|
@ -50,14 +43,13 @@ class _AboutPodcastState extends State<AboutPodcast> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var _settingState = Provider.of<SettingState>(context);
|
||||
var _groupList = Provider.of<GroupList>(context, listen: false);
|
||||
return AlertDialog(
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
onPressed: () {
|
||||
_unSubscribe(widget.podcastLocal.title);
|
||||
_settingState.subscribeUpdate = Update.justupdate;
|
||||
_groupList.removePodcast(widget.podcastLocal.id);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
color: Colors.grey[200],
|
||||
|
@ -91,10 +83,8 @@ class PodcastList extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _PodcastListState extends State<PodcastList> {
|
||||
var dir;
|
||||
|
||||
Future<List<PodcastLocal>> getPodcastLocal() async {
|
||||
dir = await getApplicationDocumentsDirectory();
|
||||
var dbHelper = DBHelper();
|
||||
var podcastList = await dbHelper.getPodcastLocalAll();
|
||||
return podcastList;
|
||||
|
@ -160,7 +150,7 @@ class _PodcastListState extends State<PodcastList> {
|
|||
height: _width / 4,
|
||||
width: _width / 4,
|
||||
child: Image.file(File(
|
||||
"${dir.path}/${snapshot.data[index].title}.png")),
|
||||
"${snapshot.data[index].imagePath}")),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
|
|
|
@ -6,7 +6,6 @@ import 'dart:ui';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_downloader/flutter_downloader.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:tsacdop/class/episodebrief.dart';
|
||||
import 'package:tsacdop/episodes/episodedetail.dart';
|
||||
import 'package:tsacdop/util/pageroute.dart';
|
||||
|
@ -25,184 +24,164 @@ class EpisodeGrid extends StatelessWidget {
|
|||
this.showNumber,
|
||||
this.heroTag})
|
||||
: super(key: key);
|
||||
Future<String> _getPath() async {
|
||||
var dir = await getApplicationDocumentsDirectory();
|
||||
return dir.path;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
double _width = MediaQuery.of(context).size.width;
|
||||
return FutureBuilder(
|
||||
future: _getPath(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return CustomScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
primary: false,
|
||||
slivers: <Widget>[
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
childAspectRatio: 1.0,
|
||||
crossAxisCount: 3,
|
||||
mainAxisSpacing: 6.0,
|
||||
crossAxisSpacing: 6.0,
|
||||
),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(BuildContext context, int index) {
|
||||
Color _c;
|
||||
var color = json.decode(podcast[index].primaryColor);
|
||||
(color[0] > 200 && color[1] > 200 && color[2] > 200)
|
||||
? _c = Color.fromRGBO((255 - color[0]),
|
||||
255 - color[1], 255 - color[2], 1.0)
|
||||
: _c = Color.fromRGBO(
|
||||
color[0], color[1], color[2], 1.0);
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
ScaleRoute(
|
||||
page: EpisodeDetail(
|
||||
episodeItem: podcast[index],
|
||||
heroTag: heroTag,
|
||||
path: snapshot.data,)),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(5.0)),
|
||||
color:
|
||||
Theme.of(context).scaffoldBackgroundColor,
|
||||
border: Border.all(
|
||||
color: Colors.grey[100],
|
||||
width: 3.0,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey[100],
|
||||
blurRadius: 1.0,
|
||||
spreadRadius: 0.5,
|
||||
),
|
||||
]),
|
||||
alignment: Alignment.center,
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Hero(
|
||||
tag: podcast[index].enclosureUrl +
|
||||
heroTag,
|
||||
child: Container(
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(_width/32)),
|
||||
child: Container(
|
||||
height: _width/16,
|
||||
width: _width/16,
|
||||
child: Image.file(File(
|
||||
"${snapshot.data}/${podcast[index].feedTitle}.png")),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
showNumber
|
||||
? Container(
|
||||
alignment: Alignment.topRight,
|
||||
child: Text(
|
||||
(podcast.length - index)
|
||||
.toString(),
|
||||
style: GoogleFonts.teko(
|
||||
textStyle: TextStyle(
|
||||
fontSize: _width/24,
|
||||
color: _c,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Center(),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 5,
|
||||
child: Container(
|
||||
alignment: Alignment.topLeft,
|
||||
padding: EdgeInsets.only(top: 2.0),
|
||||
child: Text(
|
||||
podcast[index].title,
|
||||
style: TextStyle(
|
||||
fontSize: _width/32,
|
||||
),
|
||||
maxLines: 4,
|
||||
overflow: TextOverflow.fade,
|
||||
return CustomScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
primary: false,
|
||||
slivers: <Widget>[
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
childAspectRatio: 1.0,
|
||||
crossAxisCount: 3,
|
||||
mainAxisSpacing: 6.0,
|
||||
crossAxisSpacing: 6.0,
|
||||
),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(BuildContext context, int index) {
|
||||
Color _c;
|
||||
var color = json.decode(podcast[index].primaryColor);
|
||||
(color[0] > 200 && color[1] > 200 && color[2] > 200)
|
||||
? _c = Color.fromRGBO(
|
||||
(255 - color[0]), 255 - color[1], 255 - color[2], 1.0)
|
||||
: _c = Color.fromRGBO(color[0], color[1], color[2], 1.0);
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
ScaleRoute(
|
||||
page: EpisodeDetail(
|
||||
episodeItem: podcast[index],
|
||||
heroTag: heroTag,
|
||||
)),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(5.0)),
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
border: Border.all(
|
||||
color: Colors.grey[100],
|
||||
width: 3.0,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey[100],
|
||||
blurRadius: 1.0,
|
||||
spreadRadius: 0.5,
|
||||
),
|
||||
]),
|
||||
alignment: Alignment.center,
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Hero(
|
||||
tag: podcast[index].enclosureUrl + heroTag,
|
||||
child: Container(
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(_width / 32)),
|
||||
child: Container(
|
||||
height: _width / 16,
|
||||
width: _width / 16,
|
||||
child: Image.file(
|
||||
File("${podcast[index].imagePath}")),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Align(
|
||||
alignment: Alignment.bottomLeft,
|
||||
child: Text(
|
||||
podcast[index]
|
||||
.pubDate
|
||||
.substring(4, 16),
|
||||
style: TextStyle(
|
||||
fontSize: _width/35,
|
||||
color: _c,
|
||||
fontStyle: FontStyle.italic),
|
||||
),
|
||||
Spacer(),
|
||||
showNumber
|
||||
? Container(
|
||||
alignment: Alignment.topRight,
|
||||
child: Text(
|
||||
(podcast.length - index).toString(),
|
||||
style: GoogleFonts.teko(
|
||||
textStyle: TextStyle(
|
||||
fontSize: _width / 24,
|
||||
color: _c,
|
||||
),
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
showDownload
|
||||
? DownloadIcon(
|
||||
episodeBrief: podcast[index])
|
||||
: Center(),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(1),
|
||||
),
|
||||
showFavorite
|
||||
? Container(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: (podcast[index].liked == 0)
|
||||
? Center()
|
||||
: IconTheme(
|
||||
data: IconThemeData(
|
||||
size: 15),
|
||||
child: Icon(
|
||||
Icons.favorite,
|
||||
color: Colors.red,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Center(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Center(),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 5,
|
||||
child: Container(
|
||||
alignment: Alignment.topLeft,
|
||||
padding: EdgeInsets.only(top: 2.0),
|
||||
child: Text(
|
||||
podcast[index].title,
|
||||
style: TextStyle(
|
||||
fontSize: _width / 32,
|
||||
),
|
||||
maxLines: 4,
|
||||
overflow: TextOverflow.fade,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
childCount: podcast.length,
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Align(
|
||||
alignment: Alignment.bottomLeft,
|
||||
child: Text(
|
||||
podcast[index].pubDate.substring(4, 16),
|
||||
style: TextStyle(
|
||||
fontSize: _width / 35,
|
||||
color: _c,
|
||||
fontStyle: FontStyle.italic),
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
showDownload
|
||||
? DownloadIcon(episodeBrief: podcast[index])
|
||||
: Center(),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(1),
|
||||
),
|
||||
showFavorite
|
||||
? Container(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: (podcast[index].liked == 0)
|
||||
? Center()
|
||||
: IconTheme(
|
||||
data: IconThemeData(size: 15),
|
||||
child: Icon(
|
||||
Icons.favorite,
|
||||
color: Colors.red,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Center(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
return Center();
|
||||
});
|
||||
);
|
||||
},
|
||||
childCount: podcast.length,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue