✨ Layout setting, supprt one raw view
This commit is contained in:
parent
e9ba82d5db
commit
b45c7e3a5b
|
@ -9,6 +9,7 @@ import 'package:dio/dio.dart';
|
|||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
|
||||
import '../type/searchpodcast.dart';
|
||||
import '../state/subscribe_podcast.dart';
|
||||
|
@ -391,26 +392,26 @@ class _SearchResultState extends State<SearchResult>
|
|||
},
|
||||
leading: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20.0)),
|
||||
child: Image.network(
|
||||
widget.onlinePodcast.image,
|
||||
child: CachedNetworkImage(
|
||||
height: 40.0,
|
||||
width: 40.0,
|
||||
fit: BoxFit.fitWidth,
|
||||
alignment: Alignment.center,
|
||||
loadingBuilder: (context, child, loadingProgress) {
|
||||
if (loadingProgress == null) return child;
|
||||
return Container(
|
||||
alignment: Alignment.center,
|
||||
height: 40,
|
||||
width: 40,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: context.primaryColorDark),
|
||||
child: SizedBox(
|
||||
width: 20, height: 2, child: LinearProgressIndicator()),
|
||||
);
|
||||
},
|
||||
errorBuilder: (context, error, stackTrace) => Container(
|
||||
imageUrl: widget.onlinePodcast.image,
|
||||
progressIndicatorBuilder: (context, url, downloadProgress) =>
|
||||
Container(
|
||||
height: 40,
|
||||
width: 40,
|
||||
alignment: Alignment.center,
|
||||
color: context.primaryColorDark,
|
||||
child: SizedBox(
|
||||
width: 20,
|
||||
height: 2,
|
||||
child: LinearProgressIndicator(
|
||||
value: downloadProgress.progress),
|
||||
),
|
||||
),
|
||||
errorWidget: (context, url, error) => Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
alignment: Alignment.center,
|
||||
|
|
|
@ -12,6 +12,7 @@ import 'package:fluttertoast/fluttertoast.dart';
|
|||
import '../state/audiostate.dart';
|
||||
import '../type/episodebrief.dart';
|
||||
import '../local_storage/sqflite_localpodcast.dart';
|
||||
import '../local_storage/key_value_storage.dart';
|
||||
import '../util/episodegrid.dart';
|
||||
import '../util/mypopupmenu.dart';
|
||||
import '../util/context_extension.dart';
|
||||
|
@ -401,6 +402,10 @@ class _RecentUpdate extends StatefulWidget {
|
|||
class _RecentUpdateState extends State<_RecentUpdate>
|
||||
with AutomaticKeepAliveClientMixin, SingleTickerProviderStateMixin {
|
||||
Future<List<EpisodeBrief>> _getRssItem(int top, List<String> group) async {
|
||||
KeyValueStorage storage = KeyValueStorage(recentLayoutKey);
|
||||
int index = await storage.getInt();
|
||||
if (_layout == null) _layout = Layout.values[index];
|
||||
|
||||
var dbHelper = DBHelper();
|
||||
List<EpisodeBrief> episodes;
|
||||
if (group.first == 'All')
|
||||
|
@ -441,7 +446,6 @@ class _RecentUpdateState extends State<_RecentUpdate>
|
|||
_loadMore = false;
|
||||
_groupName = 'All';
|
||||
_group = ['All'];
|
||||
_layout = Layout.three;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -641,11 +645,16 @@ class _RecentUpdateState extends State<_RecentUpdate>
|
|||
onPressed: () {
|
||||
if (_layout == Layout.three)
|
||||
setState(() {
|
||||
_layout = Layout.two;
|
||||
_layout = Layout.one;
|
||||
});
|
||||
else if (_layout ==
|
||||
Layout.two)
|
||||
setState(() {
|
||||
_layout = Layout.three;
|
||||
});
|
||||
else
|
||||
setState(() {
|
||||
_layout = Layout.three;
|
||||
_layout = Layout.two;
|
||||
});
|
||||
},
|
||||
icon: _layout == Layout.three
|
||||
|
@ -661,18 +670,33 @@ class _RecentUpdateState extends State<_RecentUpdate>
|
|||
.color),
|
||||
),
|
||||
)
|
||||
: SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child: CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
1,
|
||||
context
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.color),
|
||||
),
|
||||
),
|
||||
: _layout == Layout.two
|
||||
? SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child:
|
||||
CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
1,
|
||||
context
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.color),
|
||||
),
|
||||
)
|
||||
: SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child:
|
||||
CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
4,
|
||||
context
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.color),
|
||||
),
|
||||
),
|
||||
)),
|
||||
],
|
||||
),
|
||||
|
@ -714,6 +738,9 @@ class _MyFavorite extends StatefulWidget {
|
|||
class _MyFavoriteState extends State<_MyFavorite>
|
||||
with AutomaticKeepAliveClientMixin {
|
||||
Future<List<EpisodeBrief>> _getLikedRssItem(int top, int sortBy) async {
|
||||
KeyValueStorage storage = KeyValueStorage(favLayoutKey);
|
||||
int index = await storage.getInt();
|
||||
if (_layout == null) _layout = Layout.values[index];
|
||||
var dbHelper = DBHelper();
|
||||
List<EpisodeBrief> episodes = await dbHelper.getLikedRssItem(top, sortBy);
|
||||
return episodes;
|
||||
|
@ -737,7 +764,6 @@ class _MyFavoriteState extends State<_MyFavorite>
|
|||
void initState() {
|
||||
super.initState();
|
||||
_loadMore = false;
|
||||
_layout = Layout.three;
|
||||
_sortBy = 0;
|
||||
}
|
||||
|
||||
|
@ -832,39 +858,53 @@ class _MyFavoriteState extends State<_MyFavorite>
|
|||
Material(
|
||||
color: Colors.transparent,
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
onPressed: () {
|
||||
if (_layout == Layout.three)
|
||||
setState(() {
|
||||
_layout = Layout.two;
|
||||
});
|
||||
else
|
||||
setState(() {
|
||||
_layout = Layout.three;
|
||||
});
|
||||
},
|
||||
icon: _layout == Layout.three
|
||||
? SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child: CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
0,
|
||||
context.textTheme.bodyText1
|
||||
.color),
|
||||
),
|
||||
)
|
||||
: SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child: CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
1,
|
||||
context.textTheme.bodyText1
|
||||
.color),
|
||||
),
|
||||
),
|
||||
),
|
||||
padding: EdgeInsets.zero,
|
||||
onPressed: () {
|
||||
if (_layout == Layout.three)
|
||||
setState(() {
|
||||
_layout = Layout.one;
|
||||
});
|
||||
else if (_layout == Layout.two)
|
||||
setState(() {
|
||||
_layout = Layout.three;
|
||||
});
|
||||
else
|
||||
setState(() {
|
||||
_layout = Layout.two;
|
||||
});
|
||||
},
|
||||
icon: _layout == Layout.three
|
||||
? SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child: CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
0,
|
||||
context.textTheme
|
||||
.bodyText1.color),
|
||||
),
|
||||
)
|
||||
: _layout == Layout.two
|
||||
? SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child: CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
1,
|
||||
context.textTheme
|
||||
.bodyText1.color),
|
||||
),
|
||||
)
|
||||
: SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child: CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
4,
|
||||
context.textTheme
|
||||
.bodyText1.color),
|
||||
),
|
||||
)),
|
||||
),
|
||||
],
|
||||
)),
|
||||
|
@ -906,10 +946,19 @@ class _MyDownload extends StatefulWidget {
|
|||
class _MyDownloadState extends State<_MyDownload>
|
||||
with AutomaticKeepAliveClientMixin {
|
||||
Layout _layout;
|
||||
_getLayout() async {
|
||||
KeyValueStorage keyValueStorage = KeyValueStorage(downloadLayoutKey);
|
||||
int layout = await keyValueStorage.getInt();
|
||||
if (_layout == null)
|
||||
setState(() {
|
||||
_layout = Layout.values[layout];
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_layout = Layout.three;
|
||||
_getLayout();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -920,50 +969,65 @@ class _MyDownloadState extends State<_MyDownload>
|
|||
slivers: <Widget>[
|
||||
DownloadList(),
|
||||
SliverToBoxAdapter(
|
||||
child: Container(
|
||||
height: 40,
|
||||
color: context.primaryColor,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Text('Downloaded')),
|
||||
Spacer(),
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
onPressed: () {
|
||||
if (_layout == Layout.three)
|
||||
setState(() {
|
||||
_layout = Layout.two;
|
||||
});
|
||||
else
|
||||
setState(() {
|
||||
_layout = Layout.three;
|
||||
});
|
||||
},
|
||||
icon: _layout == Layout.three
|
||||
? SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child: CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
0, context.textTheme.bodyText1.color),
|
||||
),
|
||||
)
|
||||
: SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child: CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
1, context.textTheme.bodyText1.color),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
child: _layout == null
|
||||
? Center()
|
||||
: Container(
|
||||
height: 40,
|
||||
color: context.primaryColor,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Text('Downloaded')),
|
||||
Spacer(),
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
onPressed: () {
|
||||
if (_layout == Layout.three)
|
||||
setState(() {
|
||||
_layout = Layout.one;
|
||||
});
|
||||
else if (_layout == Layout.two)
|
||||
setState(() {
|
||||
_layout = Layout.three;
|
||||
});
|
||||
else
|
||||
setState(() {
|
||||
_layout = Layout.two;
|
||||
});
|
||||
},
|
||||
icon: _layout == Layout.three
|
||||
? SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child: CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
0, context.textTheme.bodyText1.color),
|
||||
),
|
||||
)
|
||||
: _layout == Layout.two
|
||||
? SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child: CustomPaint(
|
||||
painter: LayoutPainter(1,
|
||||
context.textTheme.bodyText1.color),
|
||||
),
|
||||
)
|
||||
: SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child: CustomPaint(
|
||||
painter: LayoutPainter(4,
|
||||
context.textTheme.bodyText1.color),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
),
|
||||
Consumer<DownloadState>(
|
||||
builder: (_, downloader, __) {
|
||||
|
|
|
@ -10,6 +10,7 @@ import 'package:line_icons/line_icons.dart';
|
|||
|
||||
import '../type/episodebrief.dart';
|
||||
import '../state/podcast_group.dart';
|
||||
import '../state/subscribe_podcast.dart';
|
||||
import '../type/podcastlocal.dart';
|
||||
import '../state/audiostate.dart';
|
||||
import '../util/custompaint.dart';
|
||||
|
@ -394,29 +395,31 @@ class _PodcastPreviewState extends State<PodcastPreview> {
|
|||
return Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Container(
|
||||
child: FutureBuilder<List<EpisodeBrief>>(
|
||||
future: _getRssItemTop(widget.podcastLocal),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) {
|
||||
print(snapshot.error);
|
||||
Center();
|
||||
}
|
||||
return (snapshot.hasData)
|
||||
? ShowEpisode(
|
||||
episodes: snapshot.data,
|
||||
podcastLocal: widget.podcastLocal,
|
||||
)
|
||||
: Container(
|
||||
padding: EdgeInsets.all(5.0),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
child: Selector<SubscribeWorker, bool>(
|
||||
selector: (_, worker) => worker.created,
|
||||
builder: (context, created, child) {
|
||||
return FutureBuilder<List<EpisodeBrief>>(
|
||||
future: _getRssItemTop(widget.podcastLocal),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) {
|
||||
print(snapshot.error);
|
||||
Center();
|
||||
}
|
||||
return (snapshot.hasData)
|
||||
? ShowEpisode(
|
||||
episodes: snapshot.data,
|
||||
podcastLocal: widget.podcastLocal,
|
||||
)
|
||||
: Container(
|
||||
padding: EdgeInsets.all(5.0),
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
Container(
|
||||
height: 40,
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.0),
|
||||
padding: EdgeInsets.only(left: 10.0),
|
||||
alignment: Alignment.center,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
|
@ -434,18 +437,25 @@ class _PodcastPreviewState extends State<PodcastPreview> {
|
|||
alignment: Alignment.centerRight,
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: IconButton(
|
||||
icon: Icon(Icons.arrow_forward),
|
||||
tooltip: 'See All',
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
SlideLeftHideRoute(
|
||||
page: PodcastDetail(
|
||||
podcastLocal: widget.podcastLocal,
|
||||
)),
|
||||
);
|
||||
},
|
||||
child: Selector<AudioPlayerNotifier, bool>(
|
||||
selector: (_, audio) => audio.playerRunning,
|
||||
builder: (_, playerRunning, __) => IconButton(
|
||||
icon: Icon(Icons.arrow_forward),
|
||||
tooltip: 'See All',
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
SlideLeftHideRoute(
|
||||
transitionPage: PodcastDetail(
|
||||
podcastLocal: widget.podcastLocal,
|
||||
hide: playerRunning,
|
||||
),
|
||||
page: PodcastDetail(
|
||||
podcastLocal: widget.podcastLocal,
|
||||
)),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flare_flutter/flare_actor.dart';
|
||||
import '../util/context_extension.dart';
|
||||
|
||||
class FirstPage extends StatefulWidget {
|
||||
FirstPage({Key key}) : super(key: key);
|
||||
|
@ -12,7 +13,7 @@ class _FirstPageState extends State<FirstPage> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
body: Container(
|
||||
color: Color.fromRGBO(35, 204, 198, 1),
|
||||
child: Center(
|
||||
child: Column(
|
||||
|
@ -20,10 +21,10 @@ class _FirstPageState extends State<FirstPage> {
|
|||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.all(100),
|
||||
padding: EdgeInsets.symmetric(vertical: 100),
|
||||
),
|
||||
Container(
|
||||
height: 400,
|
||||
height: context.width * 3 / 4,
|
||||
// color: Colors.red,
|
||||
child: FlareActor(
|
||||
'assets/splash.flr',
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flare_flutter/flare_actor.dart';
|
||||
import '../util/context_extension.dart';
|
||||
|
||||
class FourthPage extends StatefulWidget {
|
||||
FourthPage({Key key}) : super(key: key);
|
||||
|
@ -28,7 +29,7 @@ class _FourthPageState extends State<FourthPage> {
|
|||
),),
|
||||
),
|
||||
Container(
|
||||
height: 400,
|
||||
height: context.width*3/4,
|
||||
// color: Colors.red,
|
||||
child: FlareActor(
|
||||
'assets/longtap.flr',
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flare_flutter/flare_actor.dart';
|
||||
import '../util/context_extension.dart';
|
||||
|
||||
class SecondPage extends StatefulWidget {
|
||||
SecondPage({Key key}) : super(key: key);
|
||||
|
@ -21,14 +22,15 @@ class _SecondPageState extends State<SecondPage> {
|
|||
Container(
|
||||
height: 200,
|
||||
alignment: Alignment.center,
|
||||
padding: EdgeInsets.all(40),
|
||||
padding:
|
||||
EdgeInsets.only(top: 20, bottom: 20, left: 40, right: 40),
|
||||
child: Text(
|
||||
'Subscribe podcast via search or import OMPL file.',
|
||||
style: TextStyle(fontSize: 30, color: Colors.white),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: 400,
|
||||
height: context.width * 3 / 4,
|
||||
// color: Colors.red,
|
||||
child: FlareActor(
|
||||
'assets/add.flr',
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flare_flutter/flare_actor.dart';
|
||||
import '../util/context_extension.dart';
|
||||
|
||||
class ThirdPage extends StatefulWidget {
|
||||
ThirdPage({Key key}) : super(key: key);
|
||||
|
@ -22,13 +23,13 @@ class _ThirdPageState extends State<ThirdPage> {
|
|||
height: 200,
|
||||
alignment: Alignment.center,
|
||||
padding: EdgeInsets.all(40),
|
||||
child: Text('Swipe on podcast list to change group.', style: TextStyle(
|
||||
fontSize: 30,
|
||||
color: Colors.white
|
||||
),),
|
||||
child: Text(
|
||||
'Swipe on podcast list to change group.',
|
||||
style: TextStyle(fontSize: 30, color: Colors.white),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: 400,
|
||||
height: context.width * 3 / 4,
|
||||
// color: Colors.red,
|
||||
child: FlareActor(
|
||||
'assets/swipe.flr',
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../state/podcast_group.dart';
|
||||
import '../util/episodegrid.dart';
|
||||
|
||||
const String autoPlayKey = 'autoPlay';
|
||||
const String autoAddKey = 'autoAdd';
|
||||
|
@ -17,6 +19,10 @@ const String downloadUsingDataKey = 'downloadUsingData';
|
|||
const String introKey = 'intro';
|
||||
const String realDarkKey = 'realDark';
|
||||
const String cacheMaxKey = 'cacheMax';
|
||||
const String podcastLayoutKey = 'podcastLayoutKey';
|
||||
const String recentLayoutKey = 'recentLayoutKey';
|
||||
const String favLayoutKey = 'favLayoutKey';
|
||||
const String downloadLayoutKey = 'downloadLayoutKey';
|
||||
|
||||
class KeyValueStorage {
|
||||
final String key;
|
||||
|
|
|
@ -15,6 +15,7 @@ import 'package:cached_network_image/cached_network_image.dart';
|
|||
import '../type/podcastlocal.dart';
|
||||
import '../type/episodebrief.dart';
|
||||
import '../local_storage/sqflite_localpodcast.dart';
|
||||
import '../local_storage/key_value_storage.dart';
|
||||
import '../util/episodegrid.dart';
|
||||
import '../home/audioplayer.dart';
|
||||
import '../type/fireside_data.dart';
|
||||
|
@ -25,8 +26,10 @@ import '../state/audiostate.dart';
|
|||
import '../state/podcast_group.dart';
|
||||
|
||||
class PodcastDetail extends StatefulWidget {
|
||||
PodcastDetail({Key key, this.podcastLocal}) : super(key: key);
|
||||
PodcastDetail({Key key, @required this.podcastLocal, this.hide = false})
|
||||
: super(key: key);
|
||||
final PodcastLocal podcastLocal;
|
||||
final bool hide;
|
||||
@override
|
||||
_PodcastDetailState createState() => _PodcastDetailState();
|
||||
}
|
||||
|
@ -34,8 +37,10 @@ class PodcastDetail extends StatefulWidget {
|
|||
class _PodcastDetailState extends State<PodcastDetail> {
|
||||
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
|
||||
GlobalKey<RefreshIndicatorState>();
|
||||
String backgroundImage;
|
||||
List<PodcastHost> hosts;
|
||||
String _backgroundImage;
|
||||
List<PodcastHost> _hosts;
|
||||
int _episodeCount;
|
||||
Layout _layout;
|
||||
Future _updateRssItem(PodcastLocal podcastLocal) async {
|
||||
var dbHelper = DBHelper();
|
||||
|
||||
|
@ -50,8 +55,8 @@ class _PodcastDetailState extends State<PodcastDetail> {
|
|||
msg: 'Updated $result Episodes',
|
||||
gravity: ToastGravity.TOP,
|
||||
);
|
||||
Provider.of<GroupList>(context, listen: false)
|
||||
.updatePodcast(podcastLocal.id);
|
||||
// Provider.of<GroupList>(context, listen: false)
|
||||
// .updatePodcast(podcastLocal.id);
|
||||
} else {
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Update failed, network error',
|
||||
|
@ -64,13 +69,17 @@ class _PodcastDetailState extends State<PodcastDetail> {
|
|||
Future<List<EpisodeBrief>> _getRssItem(
|
||||
PodcastLocal podcastLocal, int i, bool reverse) async {
|
||||
var dbHelper = DBHelper();
|
||||
_episodeCount = await dbHelper.getPodcastCounts(podcastLocal.id);
|
||||
KeyValueStorage storage = KeyValueStorage(podcastLayoutKey);
|
||||
int index = await storage.getInt();
|
||||
if (_layout == null) _layout = Layout.values[index];
|
||||
List<EpisodeBrief> episodes =
|
||||
await dbHelper.getRssItem(podcastLocal.id, i, reverse);
|
||||
if (podcastLocal.provider.contains('fireside')) {
|
||||
FiresideData data = FiresideData(podcastLocal.id, podcastLocal.link);
|
||||
await data.getData();
|
||||
backgroundImage = data.background;
|
||||
hosts = data.hosts;
|
||||
_backgroundImage = data.background;
|
||||
_hosts = data.hosts;
|
||||
}
|
||||
return episodes;
|
||||
}
|
||||
|
@ -114,7 +123,7 @@ class _PodcastDetailState extends State<PodcastDetail> {
|
|||
image: DecorationImage(
|
||||
// colorFilter: ColorFilter.mode(_color, BlendMode.color),
|
||||
image: CachedNetworkImageProvider(
|
||||
backgroundImage,
|
||||
_backgroundImage,
|
||||
),
|
||||
fit: BoxFit.cover)),
|
||||
alignment: Alignment.centerRight,
|
||||
|
@ -179,14 +188,12 @@ class _PodcastDetailState extends State<PodcastDetail> {
|
|||
ScrollController _controller;
|
||||
int _top;
|
||||
bool _loadMore;
|
||||
Layout _layout;
|
||||
bool _reverse;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadMore = false;
|
||||
_top = 99;
|
||||
_layout = Layout.three;
|
||||
_reverse = false;
|
||||
_controller = ScrollController();
|
||||
}
|
||||
|
@ -211,6 +218,7 @@ class _PodcastDetailState extends State<PodcastDetail> {
|
|||
child: Scaffold(
|
||||
body: SafeArea(
|
||||
top: false,
|
||||
minimum: widget.hide ? EdgeInsets.only(bottom: 50) : EdgeInsets.zero,
|
||||
child: RefreshIndicator(
|
||||
key: _refreshIndicatorKey,
|
||||
color: Theme.of(context).accentColor,
|
||||
|
@ -412,7 +420,7 @@ class _PodcastDetailState extends State<PodcastDetail> {
|
|||
}),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: hostsList(context, hosts),
|
||||
child: hostsList(context, _hosts),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Container(
|
||||
|
@ -485,11 +493,16 @@ class _PodcastDetailState extends State<PodcastDetail> {
|
|||
onPressed: () {
|
||||
if (_layout == Layout.three)
|
||||
setState(() {
|
||||
_layout = Layout.two;
|
||||
_layout = Layout.one;
|
||||
});
|
||||
else if (_layout ==
|
||||
Layout.two)
|
||||
setState(() {
|
||||
_layout = Layout.three;
|
||||
});
|
||||
else
|
||||
setState(() {
|
||||
_layout = Layout.three;
|
||||
_layout = Layout.two;
|
||||
});
|
||||
},
|
||||
icon: _layout == Layout.three
|
||||
|
@ -505,18 +518,33 @@ class _PodcastDetailState extends State<PodcastDetail> {
|
|||
.color),
|
||||
),
|
||||
)
|
||||
: SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child: CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
1,
|
||||
context
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.color),
|
||||
),
|
||||
),
|
||||
: _layout == Layout.two
|
||||
? SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child:
|
||||
CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
1,
|
||||
context
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.color),
|
||||
),
|
||||
)
|
||||
: SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child:
|
||||
CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
4,
|
||||
context
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.color),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -528,8 +556,7 @@ class _PodcastDetailState extends State<PodcastDetail> {
|
|||
showNumber: true,
|
||||
layout: _layout,
|
||||
reverse: _reverse,
|
||||
episodeCount:
|
||||
widget.podcastLocal.episodeCount,
|
||||
episodeCount: _episodeCount,
|
||||
),
|
||||
SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
|
@ -590,7 +617,7 @@ class _AboutPodcastState extends State<AboutPodcast> {
|
|||
var doc = parse(description);
|
||||
_description = parse(doc.body.text).documentElement.text;
|
||||
}
|
||||
if(mounted) setState(() => _load = true);
|
||||
if (mounted) setState(() => _load = true);
|
||||
}
|
||||
|
||||
_launchUrl(String url) async {
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import '../util/context_extension.dart';
|
||||
import '../util/episodegrid.dart';
|
||||
import '../util/custompaint.dart';
|
||||
import '../local_storage/key_value_storage.dart';
|
||||
|
||||
class LayoutSetting extends StatefulWidget {
|
||||
const LayoutSetting({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_LayoutSettingState createState() => _LayoutSettingState();
|
||||
}
|
||||
|
||||
class _LayoutSettingState extends State<LayoutSetting> {
|
||||
Future<Layout> _getLayout(String key) async {
|
||||
KeyValueStorage keyValueStorage = KeyValueStorage(key);
|
||||
int layout = await keyValueStorage.getInt();
|
||||
return Layout.values[layout];
|
||||
}
|
||||
|
||||
Widget _gridOptions(BuildContext context,
|
||||
{String key, Layout layout, Layout option, double scale}) =>
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10.0, bottom: 10.0, left: 20.0),
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
KeyValueStorage storage = KeyValueStorage(key);
|
||||
await storage.saveInt(option.index);
|
||||
print(option.index);
|
||||
setState(() {});
|
||||
},
|
||||
child: Container(
|
||||
height: 30,
|
||||
width: 50,
|
||||
color: layout == option ? context.accentColor : Colors.transparent,
|
||||
alignment: Alignment.center,
|
||||
child: SizedBox(
|
||||
height: 10,
|
||||
width: 30,
|
||||
child: CustomPaint(
|
||||
painter: LayoutPainter(
|
||||
scale,
|
||||
layout == option
|
||||
? Colors.white
|
||||
: context.textTheme.bodyText1.color),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Widget _setDefaultGrid(BuildContext context, {String key}) {
|
||||
return FutureBuilder<Layout>(
|
||||
future: _getLayout(key),
|
||||
builder: (context, snapshot) {
|
||||
return snapshot.hasData
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
_gridOptions(context,
|
||||
key: key,
|
||||
layout: snapshot.data,
|
||||
option: Layout.one,
|
||||
scale: 4),
|
||||
_gridOptions(context,
|
||||
key: key,
|
||||
layout: snapshot.data,
|
||||
option: Layout.two,
|
||||
scale: 1),
|
||||
_gridOptions(context,
|
||||
key: key,
|
||||
layout: snapshot.data,
|
||||
option: Layout.three,
|
||||
scale: 0),
|
||||
],
|
||||
)
|
||||
: Center();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
|
||||
systemNavigationBarColor: context.primaryColor,
|
||||
systemNavigationBarIconBrightness:
|
||||
Theme.of(context).accentColorBrightness,
|
||||
),
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Layout'),
|
||||
elevation: 0,
|
||||
backgroundColor: context.primaryColor,
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
),
|
||||
Container(
|
||||
height: 30.0,
|
||||
padding: EdgeInsets.symmetric(horizontal: 80),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text('Default grid view',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.copyWith(color: Theme.of(context).accentColor)),
|
||||
),
|
||||
ListView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
scrollDirection: Axis.vertical,
|
||||
children: <Widget>[
|
||||
ListTile(
|
||||
contentPadding:
|
||||
EdgeInsets.only(left: 80.0, right: 20, bottom: 10),
|
||||
// leading: Icon(Icons.colorize),
|
||||
title: Text(
|
||||
'Podcast page',
|
||||
),
|
||||
subtitle:
|
||||
_setDefaultGrid(context, key: podcastLayoutKey),
|
||||
),
|
||||
ListTile(
|
||||
contentPadding:
|
||||
EdgeInsets.only(left: 80.0, right: 20, bottom: 10),
|
||||
// leading: Icon(Icons.colorize),
|
||||
title: Text(
|
||||
'Recent tab in homepage',
|
||||
),
|
||||
subtitle:
|
||||
_setDefaultGrid(context, key: recentLayoutKey),
|
||||
),
|
||||
ListTile(
|
||||
contentPadding:
|
||||
EdgeInsets.only(left: 80.0, right: 20, bottom: 10),
|
||||
// leading: Icon(Icons.colorize),
|
||||
title: Text(
|
||||
'Favorite tab in homepage',
|
||||
),
|
||||
subtitle: _setDefaultGrid(context, key: favLayoutKey),
|
||||
),
|
||||
ListTile(
|
||||
contentPadding:
|
||||
EdgeInsets.only(left: 80.0, right: 20, bottom: 10),
|
||||
// leading: Icon(Icons.colorize),
|
||||
title: Text(
|
||||
'Download tab in homepage',
|
||||
),
|
||||
subtitle: _setDefaultGrid(context, key: downloadLayoutKey),
|
||||
),
|
||||
Divider(height: 2),
|
||||
]),
|
||||
],
|
||||
),
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ import '../intro_slider/app_intro.dart';
|
|||
import '../type/podcastlocal.dart';
|
||||
import '../local_storage/sqflite_localpodcast.dart';
|
||||
import 'theme.dart';
|
||||
import 'layouts.dart';
|
||||
import 'storage.dart';
|
||||
import 'history.dart';
|
||||
import 'syncing.dart';
|
||||
|
@ -152,6 +153,18 @@ class _SettingsState extends State<Settings>
|
|||
subtitle: Text('Colors and themes'),
|
||||
),
|
||||
Divider(height: 2),
|
||||
ListTile(
|
||||
onTap: () => Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => LayoutSetting())),
|
||||
contentPadding:
|
||||
EdgeInsets.symmetric(horizontal: 25.0),
|
||||
leading: Icon(LineIcons.stop_circle_solid),
|
||||
title: Text('Layout'),
|
||||
subtitle: Text('App layout'),
|
||||
),
|
||||
Divider(height: 2),
|
||||
ListTile(
|
||||
onTap: () => Navigator.push(
|
||||
context,
|
||||
|
@ -294,6 +307,7 @@ class _SettingsState extends State<Settings>
|
|||
MainAxisAlignment.spaceEvenly,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
SizedBox(width: 75),
|
||||
_feedbackItem(
|
||||
LineIcons.github,
|
||||
'Submit issue',
|
||||
|
|
|
@ -26,175 +26,169 @@ class ThemeSetting extends StatelessWidget {
|
|||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
Padding(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
),
|
||||
Container(
|
||||
height: 30.0,
|
||||
padding: EdgeInsets.symmetric(horizontal: 80),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text('Interface',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.copyWith(color: Theme.of(context).accentColor)),
|
||||
),
|
||||
ListView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
scrollDirection: Axis.vertical,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
),
|
||||
Container(
|
||||
height: 30.0,
|
||||
padding: EdgeInsets.symmetric(horizontal: 80),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text('Interface',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyText1
|
||||
.copyWith(color: Theme.of(context).accentColor)),
|
||||
),
|
||||
ListView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
scrollDirection: Axis.vertical,
|
||||
children: <Widget>[
|
||||
ListTile(
|
||||
onTap: () => showGeneralDialog(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
barrierLabel: MaterialLocalizations.of(context)
|
||||
.modalBarrierDismissLabel,
|
||||
barrierColor: Colors.black54,
|
||||
transitionDuration: const Duration(milliseconds: 200),
|
||||
pageBuilder: (BuildContext context,
|
||||
Animation animaiton,
|
||||
Animation secondaryAnimation) =>
|
||||
AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarIconBrightness: Brightness.light,
|
||||
systemNavigationBarColor:
|
||||
Theme.of(context).brightness ==
|
||||
Brightness.light
|
||||
? Color.fromRGBO(113, 113, 113, 1)
|
||||
: Color.fromRGBO(15, 15, 15, 1),
|
||||
ListTile(
|
||||
onTap: () => showGeneralDialog(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
barrierLabel: MaterialLocalizations.of(context)
|
||||
.modalBarrierDismissLabel,
|
||||
barrierColor: Colors.black54,
|
||||
transitionDuration: const Duration(milliseconds: 200),
|
||||
pageBuilder: (BuildContext context,
|
||||
Animation animaiton,
|
||||
Animation secondaryAnimation) =>
|
||||
AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarIconBrightness: Brightness.light,
|
||||
systemNavigationBarColor:
|
||||
Theme.of(context).brightness ==
|
||||
Brightness.light
|
||||
? Color.fromRGBO(113, 113, 113, 1)
|
||||
: Color.fromRGBO(15, 15, 15, 1),
|
||||
),
|
||||
child: AlertDialog(
|
||||
titlePadding: EdgeInsets.only(
|
||||
top: 20,
|
||||
left: 40,
|
||||
right: context.width / 3,
|
||||
),
|
||||
elevation: 1,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(10.0))),
|
||||
title: Text('Theme'),
|
||||
content: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
RadioListTile(
|
||||
title: Text('System default'),
|
||||
value: ThemeMode.system,
|
||||
groupValue: settings.theme,
|
||||
onChanged: (value) {
|
||||
settings.setTheme = value;
|
||||
Navigator.of(context).pop();
|
||||
}),
|
||||
RadioListTile(
|
||||
title: Text('Dark mode'),
|
||||
value: ThemeMode.dark,
|
||||
groupValue: settings.theme,
|
||||
onChanged: (value) {
|
||||
settings.setTheme = value;
|
||||
Navigator.of(context).pop();
|
||||
}),
|
||||
RadioListTile(
|
||||
title: Text('Light mode'),
|
||||
value: ThemeMode.light,
|
||||
groupValue: settings.theme,
|
||||
onChanged: (value) {
|
||||
settings.setTheme = value;
|
||||
Navigator.of(context).pop();
|
||||
}),
|
||||
],
|
||||
),
|
||||
child: AlertDialog(
|
||||
titlePadding: EdgeInsets.only(
|
||||
),
|
||||
),
|
||||
)),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 80.0),
|
||||
// leading: Icon(Icons.colorize),
|
||||
title: Text('Theme'),
|
||||
subtitle: Text('System default'),
|
||||
),
|
||||
ListTile(
|
||||
contentPadding:
|
||||
EdgeInsets.only(left: 80.0, right: 20, bottom: 10),
|
||||
// leading: Icon(Icons.colorize),
|
||||
title: Text(
|
||||
'Real Dark',
|
||||
),
|
||||
subtitle: Text(
|
||||
'Turn on if you think the night is not dark enough'),
|
||||
trailing: Selector<SettingState, bool>(
|
||||
selector: (_, setting) => setting.realDark,
|
||||
builder: (_, data, __) => Switch(
|
||||
value: data,
|
||||
onChanged: (boo) async {
|
||||
settings.setRealDark = boo;
|
||||
}),
|
||||
),
|
||||
),
|
||||
Divider(height: 2),
|
||||
ListTile(
|
||||
onTap: () => showGeneralDialog(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
barrierLabel: MaterialLocalizations.of(context)
|
||||
.modalBarrierDismissLabel,
|
||||
barrierColor: Colors.black54,
|
||||
transitionDuration: const Duration(milliseconds: 200),
|
||||
pageBuilder: (BuildContext context,
|
||||
Animation animaiton,
|
||||
Animation secondaryAnimation) =>
|
||||
AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarIconBrightness: Brightness.light,
|
||||
systemNavigationBarColor:
|
||||
Theme.of(context).brightness ==
|
||||
Brightness.light
|
||||
? Color.fromRGBO(113, 113, 113, 1)
|
||||
: Color.fromRGBO(15, 15, 15, 1),
|
||||
),
|
||||
child: AlertDialog(
|
||||
elevation: 1,
|
||||
titlePadding: EdgeInsets.only(
|
||||
top: 20,
|
||||
left: 40,
|
||||
right: context.width / 3,
|
||||
),
|
||||
elevation: 1,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(10.0))),
|
||||
title: Text('Theme'),
|
||||
content: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
RadioListTile(
|
||||
title: Text('System default'),
|
||||
value: ThemeMode.system,
|
||||
groupValue: settings.theme,
|
||||
onChanged: (value) {
|
||||
settings.setTheme = value;
|
||||
Navigator.of(context).pop();
|
||||
}),
|
||||
RadioListTile(
|
||||
title: Text('Dark mode'),
|
||||
value: ThemeMode.dark,
|
||||
groupValue: settings.theme,
|
||||
onChanged: (value) {
|
||||
settings.setTheme = value;
|
||||
Navigator.of(context).pop();
|
||||
}),
|
||||
RadioListTile(
|
||||
title: Text('Light mode'),
|
||||
value: ThemeMode.light,
|
||||
groupValue: settings.theme,
|
||||
onChanged: (value) {
|
||||
settings.setTheme = value;
|
||||
Navigator.of(context).pop();
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
right: 200,
|
||||
bottom: 0),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(10.0))),
|
||||
title: Text.rich(
|
||||
TextSpan(text: 'Choose a ', children: [
|
||||
TextSpan(
|
||||
text: 'color',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: context.accentColor))
|
||||
])),
|
||||
content: ColorPicker(
|
||||
onColorChanged: (value) =>
|
||||
settings.setAccentColor = value,
|
||||
),
|
||||
)),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 80.0),
|
||||
// leading: Icon(Icons.colorize),
|
||||
title: Text('Theme'),
|
||||
subtitle: Text('System default'),
|
||||
),
|
||||
ListTile(
|
||||
contentPadding:
|
||||
EdgeInsets.only(left: 80.0, right: 20, bottom: 10),
|
||||
// leading: Icon(Icons.colorize),
|
||||
title: Text(
|
||||
'Real Dark',
|
||||
),
|
||||
subtitle: Text(
|
||||
'Turn on if you think the night is not dark enough'),
|
||||
trailing: Selector<SettingState, bool>(
|
||||
selector: (_, setting) => setting.realDark,
|
||||
builder: (_, data, __) => Switch(
|
||||
value: data,
|
||||
onChanged: (boo) async {
|
||||
settings.setRealDark = boo;
|
||||
}),
|
||||
),
|
||||
),
|
||||
Divider(height: 2),
|
||||
ListTile(
|
||||
onTap: () => showGeneralDialog(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
barrierLabel: MaterialLocalizations.of(context)
|
||||
.modalBarrierDismissLabel,
|
||||
barrierColor: Colors.black54,
|
||||
transitionDuration: const Duration(milliseconds: 200),
|
||||
pageBuilder: (BuildContext context,
|
||||
Animation animaiton,
|
||||
Animation secondaryAnimation) =>
|
||||
AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarIconBrightness: Brightness.light,
|
||||
systemNavigationBarColor:
|
||||
Theme.of(context).brightness ==
|
||||
Brightness.light
|
||||
? Color.fromRGBO(113, 113, 113, 1)
|
||||
: Color.fromRGBO(15, 15, 15, 1),
|
||||
),
|
||||
child: AlertDialog(
|
||||
elevation: 1,
|
||||
titlePadding: EdgeInsets.only(
|
||||
top: 20,
|
||||
left: 40,
|
||||
right: 200,
|
||||
bottom: 0),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(10.0))),
|
||||
title: Text.rich(
|
||||
TextSpan(text: 'Choose a ', children: [
|
||||
TextSpan(
|
||||
text: 'color',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: context.accentColor))
|
||||
])),
|
||||
content: ColorPicker(
|
||||
onColorChanged: (value) =>
|
||||
settings.setAccentColor = value,
|
||||
),
|
||||
))),
|
||||
contentPadding: EdgeInsets.only(left: 80.0, right: 25),
|
||||
title: Text('Accent color'),
|
||||
subtitle: Text('Include the overlay color'),
|
||||
trailing: Container(
|
||||
height: 25,
|
||||
width: 25,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle, color: context.accentColor),
|
||||
),
|
||||
),
|
||||
Divider(height: 2),
|
||||
],
|
||||
))),
|
||||
contentPadding: EdgeInsets.only(left: 80.0, right: 25),
|
||||
title: Text('Accent color'),
|
||||
subtitle: Text('Include the overlay color'),
|
||||
trailing: Container(
|
||||
height: 25,
|
||||
width: 25,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle, color: context.accentColor),
|
||||
),
|
||||
),
|
||||
Divider(height: 2),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
|
|
@ -140,11 +140,11 @@ Future<void> subIsolateEntryPoint(SendPort sendPort) async {
|
|||
String realUrl =
|
||||
response.redirects.isEmpty ? rss : response.realUri.toString();
|
||||
|
||||
print(realUrl);
|
||||
bool checkUrl = await dbHelper.checkPodcast(realUrl);
|
||||
String imageUrl;
|
||||
|
||||
if (checkUrl) {
|
||||
img.Image thumbnail;
|
||||
String imageUrl;
|
||||
try {
|
||||
Response<List<int>> imageResponse = await Dio().get<List<int>>(
|
||||
p.itunes.image.href,
|
||||
|
@ -153,7 +153,6 @@ Future<void> subIsolateEntryPoint(SendPort sendPort) async {
|
|||
img.Image image = img.decodeImage(imageResponse.data);
|
||||
thumbnail = img.copyResize(image, width: 300);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
try {
|
||||
Response<List<int>> imageResponse = await Dio().get<List<int>>(
|
||||
item.imgUrl,
|
||||
|
|
|
@ -17,10 +17,12 @@ class LayoutPainter extends CustomPainter {
|
|||
..strokeCap = StrokeCap.round;
|
||||
|
||||
canvas.drawRect(Rect.fromLTRB(0, 0, 10 + 5 * scale, 10), _paint);
|
||||
canvas.drawRect(
|
||||
Rect.fromLTRB(10 + 5 * scale, 0, 20 + 10 * scale, 10), _paint);
|
||||
canvas.drawRect(
|
||||
Rect.fromLTRB(20 + 5 * scale, 0, 30, 10 - 10 * scale), _paint);
|
||||
if (scale < 4) {
|
||||
canvas.drawRect(
|
||||
Rect.fromLTRB(10 + 5 * scale, 0, 20 + 10 * scale, 10), _paint);
|
||||
canvas.drawRect(
|
||||
Rect.fromLTRB(20 + 5 * scale, 0, 30, 10 - 10 * scale), _paint);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -664,7 +666,10 @@ class _HeartOpenState extends State<HeartOpen>
|
|||
left: widget.width * position,
|
||||
bottom: widget.height * _value * scale,
|
||||
child: Icon(Icons.favorite,
|
||||
color: _value > 0.5 ? Colors.red.withOpacity(2 - _value*2) : Colors.red, size: 20 * _value * scale),
|
||||
color: _value > 0.5
|
||||
? Colors.red.withOpacity(2 - _value * 2)
|
||||
: Colors.red,
|
||||
size: 20 * _value * scale),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ import 'colorize.dart';
|
|||
import 'context_extension.dart';
|
||||
import 'custompaint.dart';
|
||||
|
||||
enum Layout { two, three }
|
||||
enum Layout { three, two, one }
|
||||
|
||||
class EpisodeGrid extends StatelessWidget {
|
||||
final List<EpisodeBrief> episodes;
|
||||
|
@ -56,6 +56,117 @@ class EpisodeGrid extends StatelessWidget {
|
|||
this.reverse,
|
||||
}) : super(key: key);
|
||||
|
||||
Widget _title(EpisodeBrief episode) => Container(
|
||||
alignment:
|
||||
layout == Layout.one ? Alignment.centerLeft : Alignment.topLeft,
|
||||
padding: EdgeInsets.only(top: 2.0),
|
||||
child: Text(
|
||||
episode.title,
|
||||
maxLines: layout == Layout.one ? 1 : 4,
|
||||
overflow:
|
||||
layout == Layout.one ? TextOverflow.ellipsis : TextOverflow.fade,
|
||||
),
|
||||
);
|
||||
Widget _circleImage(BuildContext context,
|
||||
{EpisodeBrief episode, Color color, bool boo}) =>
|
||||
Container(
|
||||
height: context.width / 16,
|
||||
width: context.width / 16,
|
||||
child: boo
|
||||
? Center()
|
||||
: CircleAvatar(
|
||||
backgroundColor: color.withOpacity(0.5),
|
||||
backgroundImage: FileImage(File("${episode.imagePath}")),
|
||||
),
|
||||
);
|
||||
Widget _listenIndicater(BuildContext context,
|
||||
{EpisodeBrief episode, int isListened}) =>
|
||||
Selector<AudioPlayerNotifier, Tuple2<EpisodeBrief, bool>>(
|
||||
selector: (_, audio) => Tuple2(audio.episode, audio.playerRunning),
|
||||
builder: (_, data, __) {
|
||||
return (episode.enclosureUrl == data.item1?.enclosureUrl &&
|
||||
data.item2)
|
||||
? Container(
|
||||
height: 20,
|
||||
width: 20,
|
||||
margin: EdgeInsets.symmetric(horizontal: 2),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: WaveLoader(color: context.accentColor))
|
||||
: layout == Layout.two && isListened > 0
|
||||
? Container(
|
||||
height: 20,
|
||||
width: 20,
|
||||
margin: EdgeInsets.symmetric(horizontal: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: context.accentColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: CustomPaint(
|
||||
painter: ListenedAllPainter(
|
||||
Colors.white,
|
||||
)),
|
||||
)
|
||||
: Center();
|
||||
});
|
||||
|
||||
Widget _downloadIndicater(BuildContext context, {EpisodeBrief episode}) =>
|
||||
showDownload || layout != Layout.three
|
||||
? Container(
|
||||
child: (episode.enclosureUrl != episode.mediaId)
|
||||
? Container(
|
||||
height: 20,
|
||||
width: 20,
|
||||
margin: EdgeInsets.symmetric(horizontal: 5),
|
||||
padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: context.accentColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.done_all,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
)
|
||||
: Center(),
|
||||
)
|
||||
: Center();
|
||||
Widget _isNewIndicator(EpisodeBrief episode) => episode.isNew == 1
|
||||
? Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 2),
|
||||
child: Text('New',
|
||||
style: TextStyle(color: Colors.red, fontStyle: FontStyle.italic)),
|
||||
)
|
||||
: Center();
|
||||
|
||||
Widget _numberIndicater(BuildContext context, {int index, Color color}) =>
|
||||
showNumber
|
||||
? Container(
|
||||
alignment: Alignment.topRight,
|
||||
child: Text(
|
||||
reverse
|
||||
? (index + 1).toString()
|
||||
: (episodeCount - index).toString(),
|
||||
style: GoogleFonts.teko(
|
||||
textStyle: TextStyle(
|
||||
fontSize: context.width / 24,
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Center();
|
||||
Widget _pubDate(BuildContext context, {EpisodeBrief episode, Color color}) =>
|
||||
Text(
|
||||
episode.dateToString(),
|
||||
style: TextStyle(
|
||||
fontSize: context.width / 35,
|
||||
color: color,
|
||||
fontStyle: FontStyle.italic),
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
double _width = MediaQuery.of(context).size.width;
|
||||
|
@ -139,8 +250,10 @@ class EpisodeGrid extends StatelessWidget {
|
|||
options: options,
|
||||
itemCount: episodes.length,
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
childAspectRatio: layout == Layout.three ? 1 : 1.5,
|
||||
crossAxisCount: layout == Layout.three ? 3 : 2,
|
||||
childAspectRatio:
|
||||
layout == Layout.three ? 1 : layout == Layout.two ? 1.5 : 4,
|
||||
crossAxisCount:
|
||||
layout == Layout.three ? 3 : layout == Layout.two ? 2 : 1,
|
||||
mainAxisSpacing: 6.0,
|
||||
crossAxisSpacing: 6.0,
|
||||
),
|
||||
|
@ -211,166 +324,71 @@ class EpisodeGrid extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
flex: 2,
|
||||
flex: layout == Layout.one ? 1 : 2,
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
height: _width / 16,
|
||||
width: _width / 16,
|
||||
child: boo
|
||||
? Center()
|
||||
: CircleAvatar(
|
||||
backgroundColor:
|
||||
_c.withOpacity(0.5),
|
||||
backgroundImage: FileImage(File(
|
||||
"${episodes[index].imagePath}")),
|
||||
),
|
||||
),
|
||||
layout != Layout.one
|
||||
? _circleImage(context,
|
||||
episode: episodes[index],
|
||||
color: _c,
|
||||
boo: boo)
|
||||
: _pubDate(context,
|
||||
episode: episodes[index],
|
||||
color: _c),
|
||||
Spacer(),
|
||||
Selector<AudioPlayerNotifier,
|
||||
Tuple2<EpisodeBrief, bool>>(
|
||||
selector: (_, audio) => Tuple2(
|
||||
audio.episode,
|
||||
audio.playerRunning),
|
||||
builder: (_, data, __) {
|
||||
return (episodes[index]
|
||||
.enclosureUrl ==
|
||||
data.item1
|
||||
?.enclosureUrl &&
|
||||
data.item2)
|
||||
? Container(
|
||||
height: 20,
|
||||
width: 20,
|
||||
margin:
|
||||
EdgeInsets.symmetric(
|
||||
horizontal: 2),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: WaveLoader(
|
||||
color: context
|
||||
.accentColor))
|
||||
: layout == Layout.two &&
|
||||
snapshot.data > 0
|
||||
? Container(
|
||||
height: 20,
|
||||
width: 20,
|
||||
margin: EdgeInsets
|
||||
.symmetric(
|
||||
horizontal:
|
||||
2),
|
||||
decoration:
|
||||
BoxDecoration(
|
||||
color: context
|
||||
.accentColor,
|
||||
shape:
|
||||
BoxShape.circle,
|
||||
),
|
||||
child: CustomPaint(
|
||||
painter:
|
||||
ListenedAllPainter(
|
||||
Colors.white,
|
||||
)),
|
||||
)
|
||||
: Center();
|
||||
}),
|
||||
showDownload || layout == Layout.two
|
||||
? Container(
|
||||
child: (episodes[index]
|
||||
.enclosureUrl !=
|
||||
episodes[index].mediaId)
|
||||
? Container(
|
||||
height: 20,
|
||||
width: 20,
|
||||
margin: EdgeInsets
|
||||
.symmetric(
|
||||
horizontal: 5),
|
||||
padding: EdgeInsets
|
||||
.symmetric(
|
||||
horizontal: 2),
|
||||
decoration:
|
||||
BoxDecoration(
|
||||
color: context
|
||||
.accentColor,
|
||||
shape:
|
||||
BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.done_all,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
)
|
||||
: Center(),
|
||||
)
|
||||
: Center(),
|
||||
episodes[index].isNew == 1
|
||||
? Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 2),
|
||||
child: Text('New',
|
||||
style: TextStyle(
|
||||
color: Colors.red,
|
||||
fontStyle:
|
||||
FontStyle.italic)),
|
||||
)
|
||||
: Center(),
|
||||
showNumber
|
||||
? Container(
|
||||
alignment: Alignment.topRight,
|
||||
child: Text(
|
||||
reverse
|
||||
? (index + 1).toString()
|
||||
: (episodeCount - index)
|
||||
.toString(),
|
||||
style: GoogleFonts.teko(
|
||||
textStyle: TextStyle(
|
||||
fontSize: _width / 24,
|
||||
color: _c,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Center(),
|
||||
_listenIndicater(context,
|
||||
episode: episodes[index],
|
||||
isListened: snapshot.data),
|
||||
_downloadIndicater(context,
|
||||
episode: episodes[index]),
|
||||
_isNewIndicator(episodes[index]),
|
||||
_numberIndicater(context,
|
||||
index: index, color: _c)
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 5,
|
||||
child: Container(
|
||||
alignment: Alignment.topLeft,
|
||||
padding: EdgeInsets.only(top: 2.0),
|
||||
child: Text(
|
||||
episodes[index].title,
|
||||
style: TextStyle(
|
||||
// fontSize: _width / 32,
|
||||
),
|
||||
maxLines: 4,
|
||||
overflow: TextOverflow.fade,
|
||||
),
|
||||
),
|
||||
flex: layout == Layout.one ? 3 : 5,
|
||||
child: layout != Layout.one
|
||||
? _title(episodes[index])
|
||||
: Row(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
children: [
|
||||
_circleImage(context,
|
||||
episode: episodes[index],
|
||||
color: _c,
|
||||
boo: boo),
|
||||
SizedBox(
|
||||
width: 5,
|
||||
),
|
||||
Expanded(
|
||||
child:
|
||||
_title(episodes[index]))
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Row(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Align(
|
||||
alignment: Alignment.bottomLeft,
|
||||
child: Text(
|
||||
episodes[index].dateToString(),
|
||||
style: TextStyle(
|
||||
fontSize: _width / 35,
|
||||
color: _c,
|
||||
fontStyle: FontStyle.italic),
|
||||
),
|
||||
),
|
||||
layout != Layout.one
|
||||
? Align(
|
||||
alignment: Alignment.bottomLeft,
|
||||
child: _pubDate(context,
|
||||
episode: episodes[index],
|
||||
color: _c),
|
||||
)
|
||||
: SizedBox(width: 1),
|
||||
Spacer(),
|
||||
layout == Layout.two &&
|
||||
layout != Layout.three &&
|
||||
episodes[index].duration != 0
|
||||
? Container(
|
||||
alignment: Alignment.center,
|
||||
|
@ -401,7 +419,7 @@ class EpisodeGrid extends StatelessWidget {
|
|||
// fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
layout == Layout.two &&
|
||||
layout != Layout.three &&
|
||||
episodes[index]
|
||||
.enclosureLength !=
|
||||
null &&
|
||||
|
@ -424,19 +442,19 @@ class EpisodeGrid extends StatelessWidget {
|
|||
Padding(
|
||||
padding: EdgeInsets.all(1),
|
||||
),
|
||||
showFavorite || layout == Layout.two
|
||||
showFavorite || layout != Layout.three
|
||||
? FutureBuilder<bool>(
|
||||
future:
|
||||
_isLiked(episodes[index]),
|
||||
initialData: false,
|
||||
builder: (context, snapshot) =>
|
||||
Container(
|
||||
alignment:
|
||||
Alignment.bottomRight,
|
||||
alignment: Alignment.center,
|
||||
child: (snapshot.data)
|
||||
? IconTheme(
|
||||
data: IconThemeData(
|
||||
size: 15),
|
||||
size:
|
||||
_width / 35),
|
||||
child: Icon(
|
||||
Icons.favorite,
|
||||
color: Colors.red,
|
||||
|
|
|
@ -39,22 +39,19 @@ class SlideLeftHideRoute extends PageRouteBuilder {
|
|||
Animation<double> secondaryAnimation,
|
||||
) =>
|
||||
page,
|
||||
transitionDuration: Duration(seconds: 2),
|
||||
transitionDuration: Duration(milliseconds: 500),
|
||||
transitionsBuilder: (
|
||||
BuildContext context,
|
||||
Animation<double> animation,
|
||||
Animation<double> secondaryAnimation,
|
||||
Widget child,
|
||||
) {
|
||||
if (animation.isCompleted)
|
||||
return child;
|
||||
else
|
||||
return SlideTransition(
|
||||
position: Tween<Offset>(
|
||||
begin: const Offset(1, 0),
|
||||
end: Offset.zero,
|
||||
).animate(animation),
|
||||
child: transitionPage);
|
||||
return SlideTransition(
|
||||
position: Tween<Offset>(
|
||||
begin: const Offset(1, 0),
|
||||
end: Offset.zero,
|
||||
).animate(animation),
|
||||
child: child);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue