modified: lib/class/audiostate.dart

new file:   lib/class/fireside_data.dart
	modified:   lib/episodes/episodedetail.dart
	modified:   lib/home/appbar/addpodcast.dart
	modified:   lib/home/audioplayer.dart
	modified:   lib/local_storage/key_value_storage.dart
	modified:   lib/local_storage/sqflite_localpodcast.dart
	modified:   lib/podcasts/podcastdetail.dart
	modified:   lib/webfeed/domain/atom_feed.dart
	modified:   lib/webfeed/domain/atom_item.dart
	modified:   lib/webfeed/domain/atom_person.dart
	modified:   lib/webfeed/domain/atom_source.dart
	modified:   lib/webfeed/domain/media/community.dart
	modified:   lib/webfeed/domain/media/embed.dart
	modified:   lib/webfeed/domain/media/group.dart
	modified:   lib/webfeed/domain/media/media.dart
	modified:   lib/webfeed/domain/media/scene.dart
	modified:   pubspec.lock
	modified:   pubspec.yaml
This commit is contained in:
stonegate 2020-02-26 17:54:59 +08:00
parent 7caa1f131b
commit 1021f2eea4
19 changed files with 258 additions and 113 deletions

View File

@ -31,7 +31,7 @@ class Playlist {
Playlist(this.name, {List<String> urls}) : urls = urls ?? [];
getPlaylist() async{
List<String> _urls = await storage.getPlayList();
List<String> _urls = await storage.getStringList();
if (_urls.length == 0) {
_playlist = [];
} else {
@ -49,7 +49,7 @@ class Playlist {
urls = [];
urls.addAll(_playlist.map((e) => e.enclosureUrl));
print(urls);
await storage.savePlaylist(urls);
await storage.saveStringlist(urls);
}
addToPlayList(EpisodeBrief episodeBrief) async {
@ -134,6 +134,7 @@ class AudioPlayer extends ChangeNotifier {
} else {
_backgroundAudioPlaying = false;
_remoteAudioLoading = false;
_playerRunning = false;
notifyListeners();
}
}
@ -207,9 +208,7 @@ class AudioPlayer extends ChangeNotifier {
_remoteErrorMessage = null;
_remoteAudioLoading = true;
ByteData audio = _getAudio(path);
if (_backgroundAudioPlaying == true) {
_stopBackgroundAudio();
}
_backgroundAudio?.pause();
_backgroundAudioPositionSeconds = 0;
_setNotification(false);
_backgroundAudio =
@ -246,9 +245,7 @@ class AudioPlayer extends ChangeNotifier {
_remoteErrorMessage = null;
_remoteAudioLoading = true;
notifyListeners();
if (_backgroundAudioPlaying == true) {
_stopBackgroundAudio();
}
_backgroundAudio?.pause();
_backgroundAudioPositionSeconds = 0;
_setNotification(false);
_backgroundAudio =
@ -415,8 +412,8 @@ class AudioPlayer extends ChangeNotifier {
}
void _stopBackgroundAudio() {
_backgroundAudio?.pause();
_backgroundAudio?.dispose();
_backgroundAudio.pause();
_backgroundAudio.dispose();
_backgroundAudioPlaying = false;
AudioSystem.instance.stopBackgroundDisplay();
}
@ -424,7 +421,7 @@ class AudioPlayer extends ChangeNotifier {
void _forwardBackgroundAudio(double seconds) {
final double forwardposition = _backgroundAudioPositionSeconds + seconds;
_backgroundAudio.seek(forwardposition);
//AudioSystem.instance.setPlaybackState(true, _backgroundAudioDurationSeconds);
AudioSystem.instance.setPlaybackState(true, _backgroundAudioPositionSeconds);
}
final _pauseButton = AndroidCustomMediaButton(

View File

@ -0,0 +1,71 @@
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:html/parser.dart';
import 'package:tsacdop/local_storage/sqflite_localpodcast.dart';
class FiresideData {
final String id;
final String link;
String _background;
String get background => _background;
List<PodcastHost> _hosts;
List<PodcastHost> get hosts => _hosts;
FiresideData(this.id, this.link);
DBHelper dbHelper = DBHelper();
Future fatchData() async {
Response response = await Dio().get(link);
if (response.statusCode == 200) {
var doc = parse(response.data);
RegExp reg = RegExp(r'https(.+)jpg');
String backgroundImage = reg.stringMatch(doc.body
.getElementsByClassName('hero-background')
.first
.attributes
.toString());
var ul = doc.body.getElementsByClassName('episode-hosts').first.children;
List<PodcastHost> hosts = [];
ul.forEach((element) {
PodcastHost host;
String name = element.text.trim();
String image =
element.children.first.children.first.attributes.toString();
host = PodcastHost(name, reg.stringMatch(image));
hosts.add(host);
});
List<String> data = [
id,
backgroundImage,
json.encode({'hosts': hosts.map((host) => host.toJson()).toList()})
];
await dbHelper.saveFiresideData(data);
}
}
Future getData() async{
List<String> data = await dbHelper.getFiresideData(id);
_background = data[0];
_hosts = json
.decode(data[1])['hosts']
.cast<Map<String, Object>>()
.map<PodcastHost>(PodcastHost.fromJson)
.toList();
}
}
class PodcastHost {
final String image;
final String name;
PodcastHost(this.name, this.image);
Map<String, Object> toJson() {
return {'name': name, 'image': image};
}
static PodcastHost fromJson(Map<String, Object> json) {
return PodcastHost(json['name'] as String, json['image'] as String);
}
}

View File

@ -188,9 +188,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
return Container(
alignment: Alignment.bottomCenter,
padding: EdgeInsets.only(
left: 5.0,
right: 5.0,
bottom: data == true ? 80.0 : 10.0),
bottom: data == true ? 60.0 : 10.0),
child: MenuBar(
episodeItem: widget.episodeItem,
heroTag: widget.heroTag,
@ -264,9 +262,9 @@ class _MenuBarState extends State<MenuBar> {
border: Border.all(
color: Theme.of(context).brightness == Brightness.light
? Colors.grey[200]
: Theme.of(context).scaffoldBackgroundColor,
: Theme.of(context).primaryColor,
),
borderRadius: BorderRadius.all(Radius.circular(10.0)),
// borderRadius: BorderRadius.all(Radius.circular(10.0)),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,

View File

@ -10,6 +10,7 @@ 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:tsacdop/class/fireside_data.dart';
import 'package:uuid/uuid.dart';
import 'package:tsacdop/class/importompl.dart';
@ -275,7 +276,12 @@ class _SearchResultState extends State<SearchResult> {
_provider,
_link);
podcastLocal.description = _p.description;
groupList.subscribe(podcastLocal);
await groupList.subscribe(podcastLocal);
if(_provider.contains('fireside'))
{
FiresideData data = FiresideData(_uuid, _link);
await data.fatchData();
}
importOmpl.importState = ImportState.parse;

View File

@ -359,13 +359,13 @@ class _PlayerWidgetState extends State<PlayerWidget> {
return Container(
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
boxShadow: [
BoxShadow(
offset: Offset(0, -1),
blurRadius: 4,
color: Colors.grey[400],
),
],
// boxShadow: [
// BoxShadow(
// offset: Offset(0, -1),
// blurRadius: 4,
// color: Colors.grey[400],
// ),
// ],
),
height: 60,
child:

View File

@ -43,12 +43,12 @@ class KeyValueStorage {
return prefs.getInt(key);
}
Future<bool> savePlaylist(List<String> playList) async{
Future<bool> saveStringlist(List<String> playList) async{
SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.setStringList(key, playList);
}
Future<List<String>> getPlayList() async{
Future<List<String>> getStringList() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
if(prefs.getStringList(key) == null) {await prefs.setStringList(key, []);}
print(prefs.getStringList(key).toString());

View File

@ -30,7 +30,8 @@ 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, imagePath TEXT, email TEXT, provider TEXT, link TEXT)""");
description TEXT, add_date INTEGER, imagePath TEXT, email TEXT, provider TEXT, link TEXT,
background_image TEXT DEFAULT '',hosts TEXT DEFAULT '')""");
await db
.execute("""CREATE TABLE Episodes(id INTEGER PRIMARY KEY,title TEXT,
enclosure_url TEXT UNIQUE, enclosure_length INTEGER, pubDate TEXT,
@ -120,6 +121,24 @@ class DBHelper {
});
}
Future<int> saveFiresideData(List<String> list)async{
var dbClient = await database;
int result = await dbClient.rawUpdate(
'UPDATE PodcastLocal SET background_image = ? , hosts = ? WHERE id = ?',[list[1],list[2],list[0]]
);
print('Fireside data save in sqllite');
return result;
}
Future<List<String>> getFiresideData(String id)async{
var dbClient = await database;
List<Map> list = await dbClient.rawQuery(
'SELECT background_image, hosts FROM PodcastLocal WHERE id = ?', [id]
);
List<String> data = [list.first['background_image]'],list.first['hosts']];
return data;
}
Future delPodcastLocal(String id) async {
var dbClient = await database;
await dbClient.rawDelete('DELETE FROM PodcastLocal WHERE id =?', [id]);

View File

@ -9,6 +9,7 @@ import 'package:html/parser.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:tsacdop/class/podcastlocal.dart';
import 'package:tsacdop/class/episodebrief.dart';
import 'package:tsacdop/episodes/episodedetail.dart';
@ -16,6 +17,7 @@ import 'package:tsacdop/local_storage/sqflite_localpodcast.dart';
import 'package:tsacdop/util/episodegrid.dart';
import 'package:tsacdop/util/pageroute.dart';
import 'package:tsacdop/home/audioplayer.dart';
import 'package:tsacdop/class/fireside_data.dart';
class PodcastDetail extends StatefulWidget {
PodcastDetail({Key key, this.podcastLocal}) : super(key: key);
@ -27,7 +29,8 @@ class PodcastDetail extends StatefulWidget {
class _PodcastDetailState extends State<PodcastDetail> {
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
GlobalKey<RefreshIndicatorState>();
String background;
List<PodcastHost> hosts;
Future _updateRssItem(PodcastLocal podcastLocal) async {
var dbHelper = DBHelper();
final result = await dbHelper.updatePodcastRss(podcastLocal);
@ -44,9 +47,14 @@ class _PodcastDetailState extends State<PodcastDetail> {
}
Future<List<EpisodeBrief>> _getRssItem(PodcastLocal podcastLocal) async {
print(podcastLocal.id);
var dbHelper = DBHelper();
List<EpisodeBrief> episodes = await dbHelper.getRssItem(podcastLocal.id);
if (podcastLocal.provider.contains('fireside')) {
FiresideData data = FiresideData(podcastLocal.id, podcastLocal.link);
await data.getData();
background = data.background;
hosts = data.hosts;
}
return episodes;
}
@ -140,7 +148,9 @@ class _PodcastDetailState extends State<PodcastDetail> {
color:
Colors.grey[300])),
Text(
widget.podcastLocal.provider ??
'Hosted on ' +
widget.podcastLocal
.provider ??
'',
style: Theme.of(context)
.textTheme
@ -176,24 +186,61 @@ class _PodcastDetailState extends State<PodcastDetail> {
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
padding: EdgeInsets.only(
left: 10.0,
right: 10.0,
top: 20.0,
bottom: 10.0),
alignment: Alignment.topLeft,
color: Theme.of(context)
.scaffoldBackgroundColor,
child: AboutPodcast(
podcastLocal: widget.podcastLocal),
return Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: EdgeInsets.all(10.0),
),
Container(
alignment: Alignment.centerRight,
padding: EdgeInsets.symmetric(
horizontal: 10.0),
child: hosts != null
? Wrap(
children: hosts
.map((host) => Container(
padding:
EdgeInsets.all(5.0),
width: 60.0,
child: Column(
mainAxisAlignment:
MainAxisAlignment
.center,
mainAxisSize:
MainAxisSize.min,
children: <Widget>[
CachedNetworkImage(
imageUrl:
host.image),
Text(host.name),
],
)))
.toList()
.cast<Widget>(),
)
: Center(),
),
Container(
padding: EdgeInsets.only(
left: 15.0,
right: 15.0,
bottom: 10.0),
alignment: Alignment.topLeft,
color: Theme.of(context)
.scaffoldBackgroundColor,
child: AboutPodcast(
podcastLocal: widget.podcastLocal),
),
],
);
},
childCount: 1,
),
),
SliverPadding(
padding: const EdgeInsets.all(5.0),
padding: const EdgeInsets.symmetric(horizontal:15.0),
sliver: SliverGrid(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
@ -480,7 +527,7 @@ class _AboutPodcastState extends State<AboutPodcast> {
: Text(_description),
);
} else {
return Text(_description);
return SelectableText(_description, toolbarOptions: ToolbarOptions(copy: true),);
}
},
);

View File

@ -1,9 +1,9 @@
import 'package:webfeed/domain/atom_category.dart';
import 'package:webfeed/domain/atom_generator.dart';
import 'package:webfeed/domain/atom_item.dart';
import 'package:webfeed/domain/atom_link.dart';
import 'package:webfeed/domain/atom_person.dart';
import 'package:webfeed/util/helpers.dart';
import 'package:tsacdop/webfeed/domain/atom_category.dart';
import 'package:tsacdop/webfeed/domain/atom_generator.dart';
import 'package:tsacdop/webfeed/domain/atom_item.dart';
import 'package:tsacdop/webfeed/domain/atom_link.dart';
import 'package:tsacdop/webfeed/domain/atom_person.dart';
import 'package:tsacdop/webfeed/util/helpers.dart';
import 'package:xml/xml.dart';
class AtomFeed {

View File

@ -1,9 +1,9 @@
import 'package:webfeed/domain/atom_category.dart';
import 'package:webfeed/domain/atom_link.dart';
import 'package:webfeed/domain/atom_person.dart';
import 'package:webfeed/domain/atom_source.dart';
import 'package:webfeed/domain/media/media.dart';
import 'package:webfeed/util/helpers.dart';
import 'package:tsacdop/webfeed/domain/atom_category.dart';
import 'package:tsacdop/webfeed/domain/atom_link.dart';
import 'package:tsacdop/webfeed/domain/atom_person.dart';
import 'package:tsacdop/webfeed/domain/atom_source.dart';
import 'package:tsacdop/webfeed/domain/media/media.dart';
import 'package:tsacdop/webfeed/util/helpers.dart';
import 'package:xml/xml.dart';
class AtomItem {

View File

@ -1,4 +1,4 @@
import 'package:webfeed/util/helpers.dart';
import 'package:tsacdop/webfeed/util/helpers.dart';
import 'package:xml/xml.dart';
class AtomPerson {

View File

@ -1,4 +1,4 @@
import 'package:webfeed/util/helpers.dart';
import 'package:tsacdop/webfeed/util/helpers.dart';
import 'package:xml/xml.dart';
class AtomSource {

View File

@ -1,7 +1,7 @@
import 'package:webfeed/domain/media/star_rating.dart';
import 'package:webfeed/domain/media/statistics.dart';
import 'package:webfeed/domain/media/tags.dart';
import 'package:webfeed/util/helpers.dart';
import 'package:tsacdop/webfeed/domain/media/star_rating.dart';
import 'package:tsacdop/webfeed/domain/media/statistics.dart';
import 'package:tsacdop/webfeed/domain/media/tags.dart';
import 'package:tsacdop/webfeed/util/helpers.dart';
import 'package:xml/xml.dart';
class Community {

View File

@ -1,4 +1,4 @@
import 'package:webfeed/domain/media/param.dart';
import 'package:tsacdop/webfeed/domain/media/param.dart';
import 'package:xml/xml.dart';
class Embed {

View File

@ -1,8 +1,8 @@
import 'package:webfeed/domain/media/category.dart';
import 'package:webfeed/domain/media/content.dart';
import 'package:webfeed/domain/media/credit.dart';
import 'package:webfeed/domain/media/rating.dart';
import 'package:webfeed/util/helpers.dart';
import 'package:tsacdop/webfeed/domain/media/category.dart';
import 'package:tsacdop/webfeed/domain/media/content.dart';
import 'package:tsacdop/webfeed/domain/media/credit.dart';
import 'package:tsacdop/webfeed/domain/media/rating.dart';
import 'package:tsacdop/webfeed/util/helpers.dart';
import 'package:xml/xml.dart';
class Group {

View File

@ -1,25 +1,25 @@
import 'package:webfeed/domain/media/category.dart';
import 'package:webfeed/domain/media/community.dart';
import 'package:webfeed/domain/media/content.dart';
import 'package:webfeed/domain/media/copyright.dart';
import 'package:webfeed/domain/media/credit.dart';
import 'package:webfeed/domain/media/description.dart';
import 'package:webfeed/domain/media/embed.dart';
import 'package:webfeed/domain/media/group.dart';
import 'package:webfeed/domain/media/hash.dart';
import 'package:webfeed/domain/media/license.dart';
import 'package:webfeed/domain/media/peer_link.dart';
import 'package:webfeed/domain/media/player.dart';
import 'package:webfeed/domain/media/price.dart';
import 'package:webfeed/domain/media/rating.dart';
import 'package:webfeed/domain/media/restriction.dart';
import 'package:webfeed/domain/media/rights.dart';
import 'package:webfeed/domain/media/scene.dart';
import 'package:webfeed/domain/media/status.dart';
import 'package:webfeed/domain/media/text.dart';
import 'package:webfeed/domain/media/thumbnail.dart';
import 'package:webfeed/domain/media/title.dart';
import 'package:webfeed/util/helpers.dart';
import 'package:tsacdop/webfeed/domain/media/category.dart';
import 'package:tsacdop/webfeed/domain/media/community.dart';
import 'package:tsacdop/webfeed/domain/media/content.dart';
import 'package:tsacdop/webfeed/domain/media/copyright.dart';
import 'package:tsacdop/webfeed/domain/media/credit.dart';
import 'package:tsacdop/webfeed/domain/media/description.dart';
import 'package:tsacdop/webfeed/domain/media/embed.dart';
import 'package:tsacdop/webfeed/domain/media/group.dart';
import 'package:tsacdop/webfeed/domain/media/hash.dart';
import 'package:tsacdop/webfeed/domain/media/license.dart';
import 'package:tsacdop/webfeed/domain/media/peer_link.dart';
import 'package:tsacdop/webfeed/domain/media/player.dart';
import 'package:tsacdop/webfeed/domain/media/price.dart';
import 'package:tsacdop/webfeed/domain/media/rating.dart';
import 'package:tsacdop/webfeed/domain/media/restriction.dart';
import 'package:tsacdop/webfeed/domain/media/rights.dart';
import 'package:tsacdop/webfeed/domain/media/scene.dart';
import 'package:tsacdop/webfeed/domain/media/status.dart';
import 'package:tsacdop/webfeed/domain/media/text.dart';
import 'package:tsacdop/webfeed/domain/media/thumbnail.dart';
import 'package:tsacdop/webfeed/domain/media/title.dart';
import 'package:tsacdop/webfeed/util/helpers.dart';
import 'package:xml/xml.dart';
class Media {

View File

@ -1,4 +1,4 @@
import 'package:webfeed/util/helpers.dart';
import 'package:tsacdop/webfeed/util/helpers.dart';
import 'package:xml/xml.dart';
class Scene {

View File

@ -36,6 +36,13 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.5"
cached_network_image:
dependency: "direct dev"
description:
name: cached_network_image
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
charcode:
dependency: transitive
description:
@ -91,7 +98,7 @@ packages:
name: dio
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.8"
version: "3.0.9"
file_picker:
dependency: "direct dev"
description:
@ -104,6 +111,13 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_cache_manager:
dependency: transitive
description:
name: flutter_cache_manager
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.3"
flutter_downloader:
dependency: "direct dev"
description:
@ -141,7 +155,7 @@ packages:
name: google_fonts
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.3.2"
version: "0.3.9"
html:
dependency: transitive
description:
@ -232,7 +246,7 @@ packages:
name: path_provider
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.5.1"
version: "1.6.1"
pedantic:
dependency: transitive
description:
@ -267,14 +281,14 @@ packages:
name: plugin_platform_interface
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.1"
version: "1.0.2"
provider:
dependency: "direct dev"
description:
name: provider
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.0.2"
version: "4.0.4"
quantize_dart:
dependency: transitive
description:
@ -295,28 +309,28 @@ packages:
name: shared_preferences
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.5.6+1"
version: "0.5.6+2"
shared_preferences_macos:
dependency: transitive
description:
name: shared_preferences_macos
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.0.1+5"
version: "0.0.1+6"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.1"
version: "1.0.3"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.1.2+3"
version: "0.1.2+4"
sky_engine:
dependency: transitive
description: flutter
@ -335,7 +349,7 @@ packages:
name: sqflite
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.0"
version: "1.2.1"
stack_trace:
dependency: transitive
description:
@ -363,7 +377,7 @@ packages:
name: synchronized
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.1"
version: "2.2.0"
term_glyph:
dependency: transitive
description:
@ -398,28 +412,28 @@ packages:
name: url_launcher
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.4.1"
version: "5.4.2"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.0.1+2"
version: "0.0.1+4"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.5"
version: "1.0.6"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.1.1"
version: "0.1.1+1"
uuid:
dependency: "direct dev"
description:
@ -434,13 +448,6 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.8"
webfeed:
dependency: "direct dev"
description:
name: webfeed
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.4.2"
xml:
dependency: "direct dev"
description:

View File

@ -30,7 +30,6 @@ dev_dependencies:
json_annotation: any
sqflite: any
flutter_html: ^0.11.1
webfeed: any
path_provider: any
color_thief_flutter: ^1.0.1
provider: ^4.0.1
@ -49,6 +48,7 @@ dev_dependencies:
shared_preferences: ^0.5.6+1
uuid: ^2.0.4
tuple: ^1.0.3
cached_network_image: ^2.0.0