new file: lib/class/settingstate.dart

modified:   lib/class/sqflite_localpodcast.dart
	modified:   lib/episodes/episodedetail.dart
	modified:   lib/home/appbar/importompl.dart
	modified:   lib/home/appbar/popupmenu.dart
	modified:   lib/home/home.dart
	modified:   lib/home/homescroll.dart
	modified:   lib/main.dart
	modified:   lib/podcasts/podcastlist.dart
	new file:   lib/podcasts/podcastmanage.dart
	modified:   lib/util/episodegrid.dart
	modified:   pubspec.lock
	modified:   pubspec.yaml
Add: reorder podcasts
This commit is contained in:
stonegate 2020-02-16 16:25:53 +08:00
parent 3200eeacd7
commit d3efce463c
13 changed files with 321 additions and 87 deletions

View File

@ -0,0 +1,19 @@
import 'package:flutter/foundation.dart';
enum Setting {start, stop}
class SettingState extends ChangeNotifier{
Setting _subscribeupdate;
Setting get subscribeupdate => _subscribeupdate;
set subscribeUpdate(Setting s){
_subscribeupdate = s;
notifyListeners();
}
Setting _themeupdate;
Setting get themeUpdate => _themeupdate;
set themeUpdate(Setting s){
_themeupdate = s;
notifyListeners();
}
}

View File

@ -27,19 +27,38 @@ class DBHelper {
void _onCreate(Database db, int version) async {
await db.execute(
"""CREATE TABLE PodcastLocal(id INTEGER PRIMARY KEY,title TEXT,
imageUrl TEXT,rssUrl TEXT UNIQUE,primaryColor TEXT,author TEXT, description TEXT, add_date INTEGER)""");
imageUrl TEXT,rssUrl TEXT UNIQUE,primaryColor TEXT,author TEXT,
description TEXT, add_date INTEGER, order_id INTEGER default 0)""");
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,
duration INTEGER DEFAULT 0, explicit INTEGER DEFAULT 0, liked INTEGER DEFAULT 0,
downloaded TEXT DEFAULT 'ND', download_date INTEGER DEFAULT 0)""");
await db.execute(
"""CREATE TABLE Setting(id INTEGER PRIMARY KEY, setting TEXT, setting_value INTEGER DEFAULT 0)""");
await db
.execute("""INSERT INTO Setting (setting) VALUES('podcasts_order') """);
}
Future<List<PodcastLocal>> getPodcastLocal() async {
var dbClient = await database;
List<Map> list = await dbClient.rawQuery(
//query podcasts order setting
List<Map> setting = await dbClient.rawQuery("SELECT setting_value FROM Setting WHERE setting = 'podcasts_order'");
int podcastsOrder = setting.first['setting_value'];
List<Map> list;
if (podcastsOrder == 0)
{ list = await dbClient.rawQuery(
'SELECT title, imageUrl, rssUrl, primaryColor, author FROM PodcastLocal ORDER BY add_date DESC');
print('Get podcasts list Ordered by 0');}
else if (podcastsOrder == 1)
{ list = await dbClient.rawQuery(
'SELECT title, imageUrl, rssUrl, primaryColor, author FROM PodcastLocal ORDER BY add_date');}
else if (podcastsOrder ==2)
{ list = await dbClient.rawQuery(
'SELECT title, imageUrl, rssUrl, primaryColor, author FROM PodcastLocal ORDER BY order_id');
print('Get podcasts list Ordered by 2');}
List<PodcastLocal> podcastLocal = List();
for (int i = 0; i < list.length; i++) {
podcastLocal.add(PodcastLocal(
@ -50,12 +69,32 @@ class DBHelper {
list[i]['author'],
));
}
print(podcastLocal.length);
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);
}
await dbClient.rawUpdate(
"UPDATE OR IGNORE Setting SET setting_value = 2 WHERE setting = 'podcasts_order' ");
print('Changed order');
}
updateOrderSetting(int value) async{
var dbClient = await database;
await dbClient.rawUpdate(
"UPDATE OR IGNORE Setting SET setting_value = ? WHERE setting = 'podcasts_order'",[value]);
}
Future savePodcastLocal(PodcastLocal podcastLocal) async {
print('save');
print('podcast saved in sqllite');
int _milliseconds = DateTime.now().millisecondsSinceEpoch;
var dbClient = await database;
await dbClient.transaction((txn) async {
@ -106,10 +145,10 @@ class DBHelper {
try {
date = DateFormat('EEE, 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) {
try {
print('e');
date = DateFormat('dd MMM yyyy HH:mm:ss Z', 'en_US').parse(pubDate);
} catch (e) {
print('e');
date = DateTime(0);
}
@ -162,9 +201,9 @@ class DBHelper {
final _pubDate = _p.items[i].pubDate;
final _date = _parsePubDate(_pubDate);
final _milliseconds = _date.millisecondsSinceEpoch;
(_p.items[i].itunes.duration != null )
? _duration = _p.items[i].itunes.duration.inMinutes
: _duration = 0;
(_p.items[i].itunes.duration != null)
? _duration = _p.items[i].itunes.duration.inMinutes
: _duration = 0;
final _explicit = getExplicit(_p.items[i].itunes.explicit);
if (_p.items[i].enclosure.url != null) {
await dbClient.transaction((txn) {
@ -213,8 +252,7 @@ class DBHelper {
list[x]['duration'],
list[x]['explicit']));
}
print(episodes.length);
print(title);
print('Loaded' + title);
return episodes;
}
@ -242,7 +280,6 @@ class DBHelper {
list[x]['duration'],
list[x]['explicit']));
}
print(episodes.length);
print(title);
return episodes;
}
@ -297,7 +334,6 @@ class DBHelper {
list[x]['duration'],
list[x]['explicit']));
}
print(episodes.length);
return episodes;
}
@ -323,7 +359,6 @@ class DBHelper {
list[x]['duration'],
list[x]['explicit']));
}
print(episodes.length);
return episodes;
}
@ -383,7 +418,6 @@ class DBHelper {
list[x]['duration'],
list[x]['explicit']));
}
print(episodes.length);
return episodes;
}
@ -403,26 +437,26 @@ class DBHelper {
return description;
}
Future<EpisodeBrief> getRssItemWithUrl(String url) async {
Future<EpisodeBrief> getRssItemWithUrl(String url) async {
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
WHERE E.enclosure_url = ?""",[url]);
episode = EpisodeBrief(
list.first['title'],
list.first['enclosure_url'],
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']);
WHERE E.enclosure_url = ?""", [url]);
episode = EpisodeBrief(
list.first['title'],
list.first['enclosure_url'],
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']);
return episode;
}
}

View File

@ -293,14 +293,16 @@ class _MenuBarState extends State<MenuBar> {
urlChange.feedTitle = widget.episodeItem.feedTitle;
urlChange.primaryColor =
widget.episodeItem.primaryColor;
print('Playing');
},
child: Container(
alignment: Alignment.center,
height: 50.0,
padding: EdgeInsets.symmetric(horizontal: 20.0),
child: Icon(
Icons.play_arrow,
color: Colors.grey[700],
child:Row(
children: <Widget>[
Text('Play Now', style: TextStyle(color: Colors.blue, fontSize: 15, fontWeight: FontWeight.bold,)),
Icon(Icons.play_arrow, color: Colors.blue,),
],
),
),
),
@ -308,13 +310,13 @@ class _MenuBarState extends State<MenuBar> {
: (widget.episodeItem.title == urlchange.title &&
urlchange.audioState == AudioState.play)
? Container(
padding: EdgeInsets.only(right: 15),
padding: EdgeInsets.only(right: 30),
child: SizedBox(
width: 15, height: 15, child: WaveLoader()))
width: 20, height: 15, child: WaveLoader()))
: Container(
padding: EdgeInsets.only(right: 15),
padding: EdgeInsets.only(right: 30),
child: SizedBox(
width: 15,
width: 20,
height: 15,
child: LineLoader(),
),

View File

@ -46,7 +46,8 @@ class Import extends StatelessWidget {
height: 20.0,
padding: EdgeInsets.symmetric(horizontal: 20.0),
alignment: Alignment.centerLeft,
child: Text('Fetch data: ' + (importOmpl.rsstitle)),
child:
Text('Fetch data: ' + (importOmpl.rsstitle)),
),
],
)

View File

@ -90,7 +90,7 @@ class PopupMenu extends StatelessWidget {
await dbHelper.savePodcastRss(_p);
} catch (e) {
print(e);
importOmpl.importState = ImportState.error;
}
}
@ -114,7 +114,6 @@ class PopupMenu extends StatelessWidget {
importOmpl.importState = ImportState.stop;
print('Import fisnished');
} catch (e) {
print(e);
importOmpl.importState = ImportState.error;
}
}

View File

@ -7,6 +7,7 @@ import 'package:tsacdop/home/appbar/importompl.dart';
import 'package:tsacdop/home/audio_player.dart';
import 'homescroll.dart';
import 'package:tsacdop/util/pageroute.dart';
import 'package:tsacdop/podcasts/podcastmanage.dart';
class Home extends StatelessWidget {
@ -26,7 +27,7 @@ class Home extends StatelessWidget {
onTap: () {
Navigator.push(
context,
SlideLeftRoute(page: Podcast()),
SlideLeftRoute(page: PodcastManage()),
);
},
child: Container(

View File

@ -14,7 +14,9 @@ import 'package:tsacdop/class/sqflite_localpodcast.dart';
import 'package:tsacdop/episodes/episodedetail.dart';
import 'package:tsacdop/podcasts/podcastdetail.dart';
import 'package:tsacdop/podcasts/podcastlist.dart';
import 'package:tsacdop/util/pageroute.dart';
import 'package:tsacdop/class/settingstate.dart';
class ScrollPodcasts extends StatefulWidget {
@override
@ -23,31 +25,50 @@ class ScrollPodcasts extends StatefulWidget {
class _ScrollPodcastsState extends State<ScrollPodcasts> {
var dir;
Future<List<PodcastLocal>> getPodcastLocal() async {
bool _loading;
List<PodcastLocal> podcastList;
getPodcastLocal() async {
var dbHelper = DBHelper();
List<PodcastLocal> podcastList = await dbHelper.getPodcastLocal();
podcastList = await dbHelper.getPodcastLocal();
dir = await getApplicationDocumentsDirectory();
return podcastList;
setState(() {
_loading = true;
});
}
ImportState importState;
didChangeDependencies() {
Setting subscribeUpdate;
@override
void didChangeDependencies() {
super.didChangeDependencies();
final importState = Provider.of<ImportOmpl>(context).importState;
if (importState == ImportState.complete) {
setState(() {});
final subscribeUpdate = Provider.of<SettingState>(context).subscribeupdate;
if (importState == ImportState.complete ||
subscribeUpdate == Setting.start) {
setState(() {
getPodcastLocal();
});
}
}
@override
void initState() {
super.initState();
_loading = false;
getPodcastLocal();
}
@override
Widget build(BuildContext context) {
double _width = MediaQuery.of(context).size.width;
return FutureBuilder<List<PodcastLocal>>(
future: getPodcastLocal(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return DefaultTabController(
length: snapshot.data.length,
return !_loading
? Container(
height: (_width - 20) / 3 + 110,
)
: DefaultTabController(
length: podcastList.length,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
@ -61,7 +82,7 @@ class _ScrollPodcastsState extends State<ScrollPodcasts> {
indicator:
CircleTabIndicator(color: Colors.blue, radius: 3),
isScrollable: true,
tabs: snapshot.data.map<Tab>((PodcastLocal podcastLocal) {
tabs: podcastList.map<Tab>((PodcastLocal podcastLocal) {
return Tab(
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(25.0)),
@ -77,14 +98,14 @@ class _ScrollPodcastsState extends State<ScrollPodcasts> {
),
),
Container(
height: (_width-20)/3+40,
height: (_width - 20) / 3 + 40,
margin: EdgeInsets.only(left: 10, right: 10),
decoration: BoxDecoration(
color: Colors.white,
),
child: TabBarView(
children:
snapshot.data.map<Widget>((PodcastLocal podcastLocal) {
podcastList.map<Widget>((PodcastLocal podcastLocal) {
return Container(
decoration: BoxDecoration(color: Colors.grey[100]),
margin: EdgeInsets.symmetric(horizontal: 5.0),
@ -99,12 +120,6 @@ class _ScrollPodcastsState extends State<ScrollPodcasts> {
],
),
);
}
return Container(
height: 250.0,
);
},
);
}
}
@ -267,11 +282,11 @@ class ShowEpisode extends StatelessWidget {
tag: podcast[index].enclosureUrl + 'scroll',
child: Container(
child: ClipRRect(
borderRadius:
BorderRadius.all(Radius.circular(_width/36)),
borderRadius: BorderRadius.all(
Radius.circular(_width / 36)),
child: Container(
height: _width/18,
width: _width/18,
height: _width / 18,
width: _width / 18,
child: Image.file(File(
"$path/${podcastLocal.title}.png")),
),
@ -290,7 +305,7 @@ class ShowEpisode extends StatelessWidget {
child: Text(
podcast[index].title,
style: TextStyle(
fontSize: _width/32,
fontSize: _width / 32,
),
maxLines: 4,
overflow: TextOverflow.fade,
@ -304,7 +319,7 @@ class ShowEpisode extends StatelessWidget {
child: Text(
podcast[index].pubDate.substring(4, 16),
style: TextStyle(
fontSize: _width/35,
fontSize: _width / 35,
color: _c,
fontStyle: FontStyle.italic,
),

View File

@ -6,6 +6,7 @@ import 'package:flutter_downloader/flutter_downloader.dart';
import 'package:tsacdop/home/appbar/addpodcast.dart';
import 'package:tsacdop/class/audiostate.dart';
import 'package:tsacdop/class/importompl.dart';
import 'package:tsacdop/class/settingstate.dart';
void main() async {
runApp(
@ -13,6 +14,7 @@ void main() async {
providers: [
ChangeNotifierProvider(create: (context) => Urlchange()),
ChangeNotifierProvider(create: (context) => ImportOmpl()),
ChangeNotifierProvider(create: (context) => SettingState()),
],
child: MyApp(),
),
@ -21,7 +23,17 @@ void main() async {
await FlutterDownloader.initialize();
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
await FlutterStatusbarcolor.setStatusBarColor(Colors.grey[100]);
if (useWhiteForeground(Colors.grey[100])) {
FlutterStatusbarcolor.setStatusBarWhiteForeground(true);
} else {
FlutterStatusbarcolor.setStatusBarWhiteForeground(false);
}
await FlutterStatusbarcolor.setNavigationBarColor(Colors.grey[100]);
if (useWhiteForeground(Colors.grey[100])) {
FlutterStatusbarcolor.setNavigationBarWhiteForeground(true);
} else {
FlutterStatusbarcolor.setNavigationBarWhiteForeground(false);
}
}
class MyApp extends StatelessWidget {

View File

@ -91,7 +91,7 @@ class _PodcastListState extends State<PodcastList> {
Future<List<PodcastLocal>> getPodcastLocal() async {
dir = await getApplicationDocumentsDirectory();
var dbHelper = DBHelper();
Future<List<PodcastLocal>> podcastList = dbHelper.getPodcastLocal();
var podcastList = await dbHelper.getPodcastLocal();
return podcastList;
}

View File

@ -0,0 +1,167 @@
import 'dart:convert';
import 'dart:io';
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/podcastlocal.dart';
import 'package:tsacdop/class/sqflite_localpodcast.dart';
import 'package:tsacdop/class/settingstate.dart';
class PodcastManage extends StatefulWidget {
@override
_PodcastManageState createState() => _PodcastManageState();
}
class _PodcastManageState extends State<PodcastManage> {
var dir;
bool _loading;
bool _loadSave;
Color _c;
double _width;
List<PodcastLocal> podcastList;
getPodcastLocal() async {
dir = await getApplicationDocumentsDirectory();
var dbHelper = DBHelper();
podcastList = await dbHelper.getPodcastLocal();
setState(() {
_loading = true;
});
}
_unSubscribe(String title) async {
var dbHelper = DBHelper();
await dbHelper.delPodcastLocal(title);
print('Unsubscribe');
}
@override
void initState() {
super.initState();
_loading = false;
_loadSave = false;
getPodcastLocal();
}
void _onReorder(int oldIndex, int newIndex) {
setState(() {
if (newIndex > oldIndex) {
newIndex -= 1;
}
final PodcastLocal podcast = podcastList.removeAt(oldIndex);
podcastList.insert(newIndex, podcast);
_loadSave = true;
});
}
_saveOrder(List<PodcastLocal> podcastList) async {
var dbHelper = DBHelper();
await dbHelper.saveOrder(podcastList);
}
Widget _podcastCard(BuildContext context, PodcastLocal podcastLocal) {
var _settingState = Provider.of<SettingState>(context);
return 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("${dir.path}/${podcastLocal.title}.png")),
),
),
),
Container(
width: _width / 2,
padding: EdgeInsets.symmetric(horizontal: 10),
child: Text(
podcastLocal.title,
maxLines: 2,
overflow: TextOverflow.fade,
)),
Spacer(),
OutlineButton(
child: Text('Unsubscribe'),
onPressed: () {
_unSubscribe(podcastLocal.title);
_settingState.subscribeUpdate = Setting.start;
setState(() {
getPodcastLocal();
});
},
),
]),
);
}
@override
Widget build(BuildContext context) {
_width = MediaQuery.of(context).size.width;
var _settingState = Provider.of<SettingState>(context);
return Scaffold(
appBar: AppBar(
title: Text('Podcasts'),
backgroundColor: Colors.grey[100],
elevation: 0,
centerTitle: true,
actions: <Widget>[
!_loadSave
? Center()
: InkWell(
child: Container(
padding: EdgeInsets.all(20.0),
alignment: Alignment.center,
child: Text('Save')),
onTap: () async{
await _saveOrder(podcastList);
Fluttertoast.showToast(
msg: 'Saved',
gravity: ToastGravity.BOTTOM,
);
_settingState.subscribeUpdate = Setting.start;
setState(() {
_loadSave = false;
});
},
),
IconButton(
icon: Icon(Icons.menu),
onPressed: () {},
),
],
),
body: Container(
color: Colors.grey[100],
child: !_loading
? CircularProgressIndicator()
: ReorderableListView(
onReorder: _onReorder,
children: podcastList.map<Widget>((PodcastLocal podcastLocal) {
var color = json.decode(podcastLocal.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 Container(
decoration: BoxDecoration(color: Colors.grey[100]),
margin: EdgeInsets.symmetric(horizontal: 5.0),
key: ObjectKey(podcastLocal.title),
child: _podcastCard(context, podcastLocal),
);
}).toList(),
),
),
);
}
}

View File

@ -27,7 +27,6 @@ class EpisodeGrid extends StatelessWidget {
: super(key: key);
double _width;
Future<String> _getPath() async {
print(_width);
var dir = await getApplicationDocumentsDirectory();
return dir.path;
}

View File

@ -1,13 +1,6 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
after_layout:
dependency: transitive
description:
name: after_layout
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.7+2"
archive:
dependency: transitive
description:
@ -324,13 +317,6 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.5"
rubber:
dependency: "direct dev"
description:
name: rubber
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.4.0"
sky_engine:
dependency: transitive
description: flutter

View File

@ -49,7 +49,6 @@ dev_dependencies:
intl: ^0.16.1
url_launcher: ^5.4.1
image: ^2.1.4
rubber: ^0.4.0
# For information on the generic Dart part of this file, see the