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:
stonegate 2020-02-20 23:44:42 +08:00
parent 16567a7199
commit 69dfc393ba
17 changed files with 729 additions and 793 deletions

View File

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

View File

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

View File

@ -15,7 +15,9 @@ class ImportOmpl extends ChangeNotifier{
ImportState get importState => _importState;
set importState(ImportState state){
_importState = state;
if(_importState != state)
{_importState = state;
notifyListeners();
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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