fix: update material you theme

This commit is contained in:
xijieyin 2022-06-04 17:45:51 +08:00
parent 92dd3dd34e
commit d032979263
22 changed files with 1673 additions and 1756 deletions

View File

@ -104,7 +104,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
} }
}, },
child: Scaffold( child: Scaffold(
backgroundColor: context.onPrimary, backgroundColor: context.background,
body: SafeArea( body: SafeArea(
child: Stack( child: Stack(
children: <Widget>[ children: <Widget>[
@ -120,6 +120,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
widget.episodeItem!.cardColor(context), widget.episodeItem!.cardColor(context),
floating: true, floating: true,
pinned: true, pinned: true,
scrolledUnderElevation: 0,
title: _showTitle title: _showTitle
? Text( ? Text(
widget.episodeItem?.title ?? '', widget.episodeItem?.title ?? '',
@ -195,8 +196,8 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
s.minsCount( s.minsCount(
widget.episodeItem!.duration! ~/ 60, widget.episodeItem!.duration! ~/ 60,
), ),
style: style: TextStyle(
TextStyle(color: context.onPrimary), color: context.background),
)), )),
if (widget.episodeItem!.enclosureLength != if (widget.episodeItem!.enclosureLength !=
null && null &&
@ -214,7 +215,7 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
child: Text( child: Text(
'${widget.episodeItem!.enclosureLength! ~/ 1000000}MB', '${widget.episodeItem!.enclosureLength! ~/ 1000000}MB',
style: style:
TextStyle(color: context.onPrimary), TextStyle(color: context.background),
), ),
), ),
FutureBuilder<PlayHistory>( FutureBuilder<PlayHistory>(

View File

@ -30,16 +30,16 @@ class AboutApp extends StatelessWidget {
final s = context.s; final s = context.s;
return AnnotatedRegion<SystemUiOverlayStyle>( return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle( value: SystemUiOverlayStyle(
statusBarColor: context.onPrimary, statusBarColor: context.background,
statusBarIconBrightness: context.iconBrightness, statusBarIconBrightness: context.iconBrightness,
systemNavigationBarColor: context.onPrimary, systemNavigationBarColor: context.background,
systemNavigationBarIconBrightness: context.iconBrightness, systemNavigationBarIconBrightness: context.iconBrightness,
), ),
child: SafeArea( child: SafeArea(
child: Scaffold( child: Scaffold(
backgroundColor: context.onPrimary, backgroundColor: context.background,
appBar: AppBar( appBar: AppBar(
backgroundColor: context.onPrimary, backgroundColor: context.background,
title: Text(s.homeToprightMenuAbout), title: Text(s.homeToprightMenuAbout),
scrolledUnderElevation: 1, scrolledUnderElevation: 1,
leading: CustomBackButton(), leading: CustomBackButton(),

View File

@ -97,8 +97,8 @@ class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
value: SystemUiOverlayStyle( value: SystemUiOverlayStyle(
systemNavigationBarIconBrightness: context.brightness, systemNavigationBarIconBrightness: context.brightness,
statusBarIconBrightness: context.iconBrightness, statusBarIconBrightness: context.iconBrightness,
systemNavigationBarColor: context.onPrimary, systemNavigationBarColor: context.background,
statusBarColor: context.onPrimary, statusBarColor: context.background,
), ),
child: WillPopScope( child: WillPopScope(
onWillPop: () async { onWillPop: () async {
@ -115,7 +115,7 @@ class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
}, },
child: Scaffold( child: Scaffold(
key: _scaffoldKey, key: _scaffoldKey,
backgroundColor: context.onPrimary, backgroundColor: context.background,
body: Stack( body: Stack(
children: <Widget>[ children: <Widget>[
SafeArea( SafeArea(
@ -163,8 +163,7 @@ class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
Theme.of(context).brightness == Theme.of(context).brightness ==
Brightness.light Brightness.light
? settings.setTheme = ThemeMode.dark ? settings.setTheme = ThemeMode.dark
: settings.setTheme = : settings.setTheme = ThemeMode.light
ThemeMode.light
}, },
child: Text( child: Text(
'Tsacdop', 'Tsacdop',

View File

@ -94,113 +94,115 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: <Widget>[ children: <Widget>[
GestureDetector( GestureDetector(
onVerticalDragEnd: (event) { onVerticalDragEnd: (event) {
if (event.primaryVelocity! > 200) { if (event.primaryVelocity! > 200) {
if (groups.length == 1) { if (groups.length == 1) {
Fluttertoast.showToast( Fluttertoast.showToast(
msg: s.addSomeGroups, msg: s.addSomeGroups,
gravity: ToastGravity.BOTTOM, gravity: ToastGravity.BOTTOM,
); );
} else { } else {
if (mounted) { if (mounted) {
setState(() { setState(() {
(_groupIndex != 0) (_groupIndex != 0)
? _groupIndex-- ? _groupIndex--
: _groupIndex = groups.length - 1; : _groupIndex = groups.length - 1;
}); });
}
}
} else if (event.primaryVelocity! < -200) {
if (groups.length == 1) {
Fluttertoast.showToast(
msg: s.addSomeGroups,
gravity: ToastGravity.BOTTOM,
);
} else {
if (mounted) {
setState(
() {
(_groupIndex < groups.length - 1)
? _groupIndex++
: _groupIndex = 0;
},
);
}
} }
} }
}, } else if (event.primaryVelocity! < -200) {
child: Column( if (groups.length == 1) {
children: <Widget>[ Fluttertoast.showToast(
SizedBox( msg: s.addSomeGroups,
height: 30, gravity: ToastGravity.BOTTOM,
child: Row( );
children: <Widget>[ } else {
Padding( if (mounted) {
padding: EdgeInsets.symmetric(horizontal: 15.0), setState(
child: Text( () {
groups[_groupIndex]!.name!, (_groupIndex < groups.length - 1)
style: context.textTheme.bodyText1! ? _groupIndex++
.copyWith(color: context.accentColor), : _groupIndex = 0;
), },
);
}
}
}
},
child: Column(
children: <Widget>[
SizedBox(
height: 30,
child: Row(
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(horizontal: 15.0),
child: Text(
groups[_groupIndex]!.name!,
style: context.textTheme.bodyText1!
.copyWith(color: context.accentColor),
), ),
Spacer(), ),
Padding( Spacer(),
padding: EdgeInsets.symmetric(horizontal: 15), Padding(
child: InkWell( padding: EdgeInsets.symmetric(horizontal: 15),
onTap: () { child: InkWell(
if (!import) { borderRadius: BorderRadius.circular(15),
Navigator.push( onTap: () {
context, if (!import) {
SlideLeftRoute( Navigator.push(
page: context context,
.read<SettingState>() SlideLeftRoute(
.openAllPodcastDefalt! page: context
? PodcastList() .read<SettingState>()
: PodcastManage(), .openAllPodcastDefalt!
), ? PodcastList()
); : PodcastManage(),
} ),
}, );
onLongPress: () { }
if (!import) { },
Navigator.push( onLongPress: () {
context, if (!import) {
SlideLeftRoute(page: PodcastList()), Navigator.push(
); context,
} SlideLeftRoute(page: PodcastList()),
}, );
borderRadius: BorderRadius.circular(5), }
child: Padding( },
padding: const EdgeInsets.all(5.0), child: Padding(
child: Text( padding: const EdgeInsets.all(5.0),
s.homeGroupsSeeAll, child: Text(
style: context.textTheme.bodyText1! s.homeGroupsSeeAll,
.copyWith( style:
color: import context.textTheme.bodyText1!.copyWith(
? context.primaryColorDark color: import
: context.accentColor), ? context.primaryColorDark
: context.accentColor,
), ),
), ),
), ),
), ),
], ),
), ],
), ),
Container( ),
height: 70, Container(
color: context.background, height: 70,
child: Row( color: context.background,
children: <Widget>[ child: Row(
_circleContainer(context), children: <Widget>[
_circleContainer(context), _circleContainer(context),
_circleContainer(context) _circleContainer(context),
], _circleContainer(context)
)), ],
], )),
)), ],
),
),
Container( Container(
height: (width - 20) / 3 + 40, height: (width - 20) / 3 + 40,
color: context.onPrimary, color: context.background,
margin: EdgeInsets.symmetric(horizontal: 15), margin: EdgeInsets.symmetric(horizontal: 15),
child: Center( child: Center(
child: _groupIndex == 0 child: _groupIndex == 0
@ -297,39 +299,39 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 15), padding: const EdgeInsets.symmetric(horizontal: 15),
child: InkWell( child: InkWell(
onTap: () { onTap: () {
if (!import) { if (!import) {
Navigator.push( Navigator.push(
context, context,
SlideLeftRoute( SlideLeftRoute(
page: context page: context
.read<SettingState>() .read<SettingState>()
.openAllPodcastDefalt! .openAllPodcastDefalt!
? PodcastList() ? PodcastList()
: PodcastManage()), : PodcastManage()),
); );
} }
}, },
onLongPress: () { onLongPress: () {
if (!import) { if (!import) {
Navigator.push( Navigator.push(
context, context,
SlideLeftRoute(page: PodcastList()), SlideLeftRoute(page: PodcastList()),
); );
} }
}, },
borderRadius: BorderRadius.circular(5), borderRadius: BorderRadius.circular(5),
child: Padding( child: Padding(
padding: const EdgeInsets.all(5.0), padding: const EdgeInsets.all(5.0),
child: Text( child: Text(
s.homeGroupsSeeAll, s.homeGroupsSeeAll,
style: context.textTheme.bodyText1! style: context.textTheme.bodyText1!.copyWith(
.copyWith( color: import
color: import ? context.primaryColorDark
? context.primaryColorDark : context.accentColor),
: context.accentColor), ),
), ),
)), ),
) )
], ],
), ),
@ -338,7 +340,7 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
height: 70, height: 70,
width: width, width: width,
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
color: context.onPrimary, color: context.background,
child: TabBar( child: TabBar(
labelPadding: EdgeInsets.fromLTRB(6.0, 5.0, 6.0, 10.0), labelPadding: EdgeInsets.fromLTRB(6.0, 5.0, 6.0, 10.0),
indicator: CircleTabIndicator( indicator: CircleTabIndicator(
@ -370,47 +372,45 @@ class _ScrollPodcastsState extends State<ScrollPodcasts>
), ),
Container( Container(
height: (width - 20) / 3 + 40, height: (width - 20) / 3 + 40,
margin: const EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.background, color: context.background,
borderRadius: BorderRadius.circular(10),
), ),
child: ScrollConfiguration( child: TabBarView(
behavior: NoGrowBehavior(), children: groups[_groupIndex]!.podcasts.map<Widget>(
child: TabBarView( (podcastLocal) {
children: groups[_groupIndex]!.podcasts.map<Widget>( return Container(
(podcastLocal) { decoration: BoxDecoration(
return Container( color: context.brightness == Brightness.light
decoration: BoxDecoration( ? context.primaryColor
color: context.brightness == Brightness.light : Colors.black12),
? context.primaryColor margin: EdgeInsets.symmetric(horizontal: 5.0),
: Colors.black12), key: ObjectKey(podcastLocal.title),
margin: EdgeInsets.symmetric(horizontal: 5.0), child: Material(
key: ObjectKey(podcastLocal.title), color: Colors.transparent,
child: Material( child: InkWell(
color: Colors.transparent, borderRadius: BorderRadius.circular(20),
child: InkWell( onTap: () {
onTap: () { Navigator.push(
Navigator.push( context,
context, HidePlayerRoute(
HidePlayerRoute( PodcastDetail(
PodcastDetail( podcastLocal: podcastLocal,
podcastLocal: podcastLocal, ),
), PodcastDetail(
PodcastDetail( podcastLocal: podcastLocal, hide: true),
podcastLocal: podcastLocal, duration: Duration(milliseconds: 300),
hide: true), ),
duration: Duration(milliseconds: 300), );
)); },
}, child: PodcastPreview(
child: PodcastPreview( podcastLocal: podcastLocal,
podcastLocal: podcastLocal,
),
), ),
), ),
); ),
}, );
).toList(), },
), ).toList(),
), ),
), ),
], ],
@ -494,7 +494,9 @@ class _PodcastPreviewState extends State<PodcastPreview> {
episodes: snapshot.data, episodes: snapshot.data,
podcastLocal: widget.podcastLocal, podcastLocal: widget.podcastLocal,
) )
: Padding(padding: const EdgeInsets.all(5.0)); : Padding(
padding: const EdgeInsets.all(5.0),
);
}, },
); );
}, },
@ -561,8 +563,8 @@ class ShowEpisode extends StatelessWidget {
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
childAspectRatio: 1.5, childAspectRatio: 1.5,
crossAxisCount: 2, crossAxisCount: 2,
mainAxisSpacing: 8.0, mainAxisSpacing: 20,
crossAxisSpacing: 6.0, crossAxisSpacing: 14,
), ),
delegate: SliverChildBuilderDelegate( delegate: SliverChildBuilderDelegate(
(context, index) { (context, index) {

View File

@ -27,17 +27,6 @@ class DiscoveryPageState extends State<DiscoveryPage> {
final List<OnlinePodcast> _podcastList = []; final List<OnlinePodcast> _podcastList = [];
Future? _searchTopPodcast; Future? _searchTopPodcast;
Future? _getIfHideDiscovery; Future? _getIfHideDiscovery;
Future<List<String?>?> _getSearchHistory() {
final storage = KeyValueStorage(searchHistoryKey);
final history = storage.getStringList();
return history;
}
void backToHome() {
setState(() {
_selectedGenre = null;
});
}
@override @override
void initState() { void initState() {
@ -46,95 +35,257 @@ class DiscoveryPageState extends State<DiscoveryPage> {
_getIfHideDiscovery = _getHideDiscovery(); _getIfHideDiscovery = _getHideDiscovery();
} }
Widget _loadTopPodcasts() => Container( @override
decoration: BoxDecoration( Widget build(BuildContext context) {
borderRadius: BorderRadius.circular(10), color: context.primaryColor), return FutureBuilder<bool>(
width: 120, future: _getIfHideDiscovery!.then((value) => value as bool),
margin: EdgeInsets.fromLTRB(10, 10, 0, 10), builder: (context, snapshot) {
padding: EdgeInsets.all(4), if (!snapshot.hasData) {
alignment: Alignment.topCenter, return Center();
child: Column( } else if (snapshot.data! || environment['apiKey'] == '') {
children: [ return SingleChildScrollView(
Expanded(
flex: 2,
child: Center(
child: Container(
height: 50,
width: 50,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: context.primaryColorDark,
),
alignment: Alignment.center,
child: SizedBox(
width: 20,
height: 2,
child: LinearProgressIndicator(value: 0),
),
),
),
),
Expanded(
flex: 1,
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Container( _historyList(),
width: 80, SizedBox(
height: context.textTheme.bodyText1!.fontSize, height: 150,
decoration: BoxDecoration( child: Center(
color: context.primaryColorDark, child: Icon(
borderRadius: BorderRadius.circular(4)), Icons.search,
size: 80,
color: Colors.grey[400],
),
),
), ),
SizedBox(height: 10), SizedBox(
Container( height: 50,
width: 40, child: Row(
height: context.textTheme.bodyText1!.fontSize, mainAxisAlignment: MainAxisAlignment.center,
decoration: BoxDecoration( children: [
color: context.primaryColorDark, Icon(
borderRadius: BorderRadius.circular(4)), LineIcons.microphone,
size: 30,
color: Colors.lightBlue,
),
SizedBox(width: 50),
Icon(
LineIcons.broadcastTower,
size: 30,
color: Colors.deepPurple,
),
SizedBox(width: 50),
Icon(
LineIcons.rssSquare,
size: 30,
color: Colors.blueGrey,
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(50, 20, 50, 20),
child: Center(
child: Text(
context.s.searchHelper,
textAlign: TextAlign.center,
style: context.textTheme.headline6!
.copyWith(color: Colors.grey[400]),
),
),
), ),
], ],
), ),
), );
Expanded( } else {
flex: 1, return PodcastSlideup(
child: Center( searchEngine: SearchEngine.listenNotes,
child: SizedBox( child: Selector<SearchState, Genre?>(
height: 32, selector: (_, searchState) => searchState.genre,
child: OutlinedButton( builder: (_, genre, __) => IndexedStack(
style: OutlinedButton.styleFrom( index: genre == null ? 0 : 1,
primary: context.accentColor.withOpacity(0.5), children: [
shape: RoundedRectangleBorder( SingleChildScrollView(
borderRadius: BorderRadius.circular(100.0), child: Column(
side: BorderSide(color: Colors.grey[500]!)), mainAxisAlignment: MainAxisAlignment.start,
// highlightedBorderColor: Colors.grey[500], crossAxisAlignment: CrossAxisAlignment.start,
// disabledTextColor: Colors.grey[500], children: [
// disabledBorderColor: Colors.grey[500], _historyList(),
SizedBox(height: 8),
SizedBox(
height: 200,
child: FutureBuilder<List<OnlinePodcast>>(
future: _searchTopPodcast!.then(
(value) => value as List<OnlinePodcast>),
builder: (context, snapshot) {
return ScrollConfiguration(
behavior: NoGrowBehavior(),
child: ListView(
addAutomaticKeepAlives: true,
scrollDirection: Axis.horizontal,
children: snapshot.hasData
? snapshot.data!
.map<Widget>((podcast) {
return _podcastCard(
podcast,
onTap: () {
context
.read<SearchState>()
.selectedPodcast =
podcast;
widget.onTap!('');
},
);
}).toList()
: [
_loadTopPodcasts(),
_loadTopPodcasts(),
_loadTopPodcasts(),
_loadTopPodcasts(),
]),
);
}),
),
Padding(
padding: EdgeInsets.fromLTRB(20, 10, 10, 4),
child: Text('Categories',
style: context.textTheme.headline6!
.copyWith(color: context.accentColor)),
),
ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: genres
.map<Widget>((e) => ListTile(
contentPadding:
EdgeInsets.fromLTRB(20, 0, 20, 0),
onTap: () {
widget.onTap!('');
context.read<SearchState>().setGenre = e;
},
title: Text(e.name!,
style: context.textTheme.headline6),
))
.toList(),
),
SizedBox(
height: 40,
child: Center(
child: Image(
image: context.brightness == Brightness.light
? AssetImage('assets/listennotes.png')
: AssetImage('assets/listennotes_light.png'),
height: 15,
),
),
)
],
), ),
child: Text(context.s.subscribe), ),
onPressed: () {}), genre == null ? Center() : _TopPodcastList(genre: genre),
],
), ),
), ),
), );
], }
)); },
);
}
Widget _loadTopPodcasts() => Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: context.primaryColor),
width: 120,
margin: EdgeInsets.fromLTRB(10, 10, 0, 10),
padding: EdgeInsets.all(4),
alignment: Alignment.topCenter,
child: Column(
children: [
Expanded(
flex: 2,
child: Center(
child: Container(
height: 50,
width: 50,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: context.primaryColorDark,
),
alignment: Alignment.center,
child: SizedBox(
width: 20,
height: 2,
child: LinearProgressIndicator(value: 0),
),
),
),
),
Expanded(
flex: 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 80,
height: context.textTheme.bodyText1!.fontSize,
decoration: BoxDecoration(
color: context.primaryColorDark,
borderRadius: BorderRadius.circular(4)),
),
SizedBox(height: 10),
Container(
width: 40,
height: context.textTheme.bodyText1!.fontSize,
decoration: BoxDecoration(
color: context.primaryColorDark,
borderRadius: BorderRadius.circular(4)),
),
],
),
),
Expanded(
flex: 1,
child: Center(
child: SizedBox(
height: 32,
child: OutlinedButton(
style: OutlinedButton.styleFrom(
primary: context.accentColor.withOpacity(0.5),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100.0),
side: BorderSide(color: Colors.grey[500]!)),
// highlightedBorderColor: Colors.grey[500],
// disabledTextColor: Colors.grey[500],
// disabledBorderColor: Colors.grey[500],
),
child: Text(context.s.subscribe),
onPressed: () {}),
),
),
),
],
),
);
Widget _historyList() => FutureBuilder<List<String?>?>( Widget _historyList() => FutureBuilder<List<String?>?>(
future: _getSearchHistory(), future: _getSearchHistory(),
initialData: [], initialData: [],
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) { if (snapshot.hasData && snapshot.data!.isNotEmpty) {
final history = snapshot.data!; final history = snapshot.data!;
return Wrap( return Wrap(
direction: Axis.horizontal, direction: Axis.horizontal,
children: history children: history
.map<Widget>((e) => Padding( .map<Widget>(
(e) => Padding(
padding: const EdgeInsets.fromLTRB(8, 2, 0, 0), padding: const EdgeInsets.fromLTRB(8, 2, 0, 0),
child: FlatButton.icon( child: TextButton.icon(
color: Colors.accents[history.indexOf(e)].withAlpha(70), style: TextButton.styleFrom(
shape: RoundedRectangleBorder( primary: Colors.accents[history.indexOf(e)],
borderRadius: BorderRadius.circular(100.0), shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100.0),
),
), ),
onPressed: () => widget.onTap!(e), onPressed: () => widget.onTap!(e),
label: Text(e!), label: Text(e!),
@ -143,32 +294,32 @@ class DiscoveryPageState extends State<DiscoveryPage> {
size: 20, size: 20,
), ),
), ),
)) ),
.toList(), )
); .toList(),
} );
return SizedBox( }
height: 0, return Center();
); },
}); );
Widget _podcastCard(OnlinePodcast podcast, {VoidCallback? onTap}) { Widget _podcastCard(OnlinePodcast podcast, {VoidCallback? onTap}) {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(20),
color: context.primaryColor, color: context.background,
border: border:
Border.all(color: context.textColor.withOpacity(0.1), width: 1)), Border.all(color: context.textColor.withOpacity(0.1), width: 1)),
width: 120, width: 140,
margin: EdgeInsets.fromLTRB(10, 10, 0, 10), margin: EdgeInsets.fromLTRB(20, 10, 0, 10),
child: Material( child: Material(
color: Colors.transparent, color: Colors.transparent,
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(20),
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
child: InkWell( child: InkWell(
onTap: onTap, onTap: onTap,
child: Padding( child: Padding(
padding: EdgeInsets.all(4.0), padding: EdgeInsets.all(8.0),
child: Column( child: Column(
children: [ children: [
Expanded( Expanded(
@ -200,6 +351,18 @@ class DiscoveryPageState extends State<DiscoveryPage> {
); );
} }
Future<List<String?>?> _getSearchHistory() {
final storage = KeyValueStorage(searchHistoryKey);
final history = storage.getStringList();
return history;
}
void backToHome() {
setState(() {
_selectedGenre = null;
});
}
Future<List<OnlinePodcast>> _getTopPodcasts({int? page}) async { Future<List<OnlinePodcast>> _getTopPodcasts({int? page}) async {
if (environment['apiKey'] == '') return []; if (environment['apiKey'] == '') return [];
final searchEngine = ListenNotesSearch(); final searchEngine = ListenNotesSearch();
@ -222,167 +385,6 @@ class DiscoveryPageState extends State<DiscoveryPage> {
final storage = KeyValueStorage(hidePodcastDiscoveryKey); final storage = KeyValueStorage(hidePodcastDiscoveryKey);
return await storage.getBool(defaultValue: false); return await storage.getBool(defaultValue: false);
} }
@override
Widget build(BuildContext context) {
return FutureBuilder<bool>(
future: _getIfHideDiscovery!.then((value) => value as bool),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center();
} else if (snapshot.data! || environment['apiKey'] == '') {
return ScrollConfiguration(
behavior: NoGrowBehavior(),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_historyList(),
SizedBox(
height: 150,
child: Center(
child: Icon(
Icons.search,
size: 80,
color: Colors.grey[400],
),
),
),
SizedBox(
height: 50,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
LineIcons.microphone,
size: 30,
color: Colors.lightBlue,
),
SizedBox(width: 50),
Icon(
LineIcons.broadcastTower,
size: 30,
color: Colors.deepPurple,
),
SizedBox(width: 50),
Icon(
LineIcons.rssSquare,
size: 30,
color: Colors.blueGrey,
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(50, 20, 50, 20),
child: Center(
child: Text(
context.s.searchHelper,
textAlign: TextAlign.center,
style: context.textTheme.headline6!
.copyWith(color: Colors.grey[400]),
),
),
),
],
),
),
);
} else {
return PodcastSlideup(
searchEngine: SearchEngine.listenNotes,
child: Selector<SearchState, Genre?>(
selector: (_, searchState) => searchState.genre,
builder: (_, genre, __) => IndexedStack(
index: genre == null ? 0 : 1,
children: [
SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_historyList(),
SizedBox(height: 8),
SizedBox(
height: 200,
child: FutureBuilder<List<OnlinePodcast>>(
future: _searchTopPodcast!.then(
(value) => value as List<OnlinePodcast>),
builder: (context, snapshot) {
return ScrollConfiguration(
behavior: NoGrowBehavior(),
child: ListView(
addAutomaticKeepAlives: true,
scrollDirection: Axis.horizontal,
children: snapshot.hasData
? snapshot.data!
.map<Widget>((podcast) {
return _podcastCard(
podcast,
onTap: () {
context
.read<SearchState>()
.selectedPodcast =
podcast;
widget.onTap!('');
},
);
}).toList()
: [
_loadTopPodcasts(),
_loadTopPodcasts(),
_loadTopPodcasts(),
_loadTopPodcasts(),
]),
);
}),
),
Padding(
padding: EdgeInsets.fromLTRB(20, 10, 10, 4),
child: Text('Categories',
style: context.textTheme.headline6!
.copyWith(color: context.accentColor)),
),
ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: genres
.map<Widget>((e) => ListTile(
contentPadding:
EdgeInsets.fromLTRB(20, 0, 20, 0),
onTap: () {
widget.onTap!('');
context.read<SearchState>().setGenre =
e;
},
title: Text(e.name!,
style: context.textTheme.headline6),
))
.toList(),
),
SizedBox(
height: 40,
child: Center(
child: Image(
image: context.brightness == Brightness.light
? AssetImage('assets/listennotes.png')
: AssetImage(
'assets/listennotes_light.png'),
height: 15,
),
),
)
],
),
),
genre == null ? Center() : _TopPodcastList(genre: genre),
],
),
),
);
}
});
}
} }
class _TopPodcastList extends StatefulWidget { class _TopPodcastList extends StatefulWidget {
@ -398,20 +400,6 @@ class __TopPodcastListState extends State<_TopPodcastList> {
Future? _searchFuture; Future? _searchFuture;
late bool _loading; late bool _loading;
late int _page; late int _page;
Future<List<OnlinePodcast>> _getTopPodcasts(
{required Genre genre, int? page}) async {
final searchEngine = ListenNotesSearch();
var searchResult = await searchEngine.fetchBestPodcast(
genre: genre.id,
page: page,
);
final podcastTopList = [
for (final p in searchResult!.podcasts!) p?.toOnlinePodcast
];
_podcastList.addAll(podcastTopList.cast());
_loading = false;
return _podcastList;
}
@override @override
void initState() { void initState() {
@ -462,12 +450,8 @@ class __TopPodcastListState extends State<_TopPodcastList> {
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.only(top: 10.0, bottom: 20.0), padding: const EdgeInsets.only(top: 10.0, bottom: 20.0),
child: OutlinedButton( child: TextButton(
style: OutlinedButton.styleFrom( style: TextButton.styleFrom(),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(100))),
),
// highlightedBorderColor: context.accentColor, // highlightedBorderColor: context.accentColor,
// splashColor: context.accentColor.withOpacity(0.5), // splashColor: context.accentColor.withOpacity(0.5),
child: _loading child: _loading
@ -498,4 +482,19 @@ class __TopPodcastListState extends State<_TopPodcastList> {
}, },
); );
} }
Future<List<OnlinePodcast>> _getTopPodcasts(
{required Genre genre, int? page}) async {
final searchEngine = ListenNotesSearch();
final searchResult = await searchEngine.fetchBestPodcast(
genre: genre.id,
page: page,
);
final podcastTopList = [
for (final p in searchResult!.podcasts!) p?.toOnlinePodcast
];
_podcastList.addAll(podcastTopList.cast());
_loading = false;
return _podcastList;
}
} }

View File

@ -40,7 +40,7 @@ class MyHomePageDelegate extends SearchDelegate<int?> {
connectTimeout: 30000, connectTimeout: 30000,
receiveTimeout: 90000, receiveTimeout: 90000,
); );
var response = await Dio(options).get(url); final response = await Dio(options).get(url);
return RssFeed.parse(response.data); return RssFeed.parse(response.data);
} catch (e) { } catch (e) {
rethrow; rethrow;
@ -88,7 +88,10 @@ class MyHomePageDelegate extends SearchDelegate<int?> {
child: IconButton( child: IconButton(
tooltip: context.s.back, tooltip: context.s.back,
splashRadius: 20, splashRadius: 20,
icon: Icon(_getIconData(Theme.of(context).platform)), icon: Icon(
_getIconData(Theme.of(context).platform),
color: context.textColor,
),
onPressed: () { onPressed: () {
close(context, 1); close(context, 1);
}, },
@ -164,12 +167,10 @@ class MyHomePageDelegate extends SearchDelegate<int?> {
switch (_searchEngine) { switch (_searchEngine) {
case SearchEngine.listenNotes: case SearchEngine.listenNotes:
return _ListenNotesSearch(query: query); return _ListenNotesSearch(query: query);
break;
case SearchEngine.podcastIndex: case SearchEngine.podcastIndex:
return _PodcastIndexSearch(query: query); return _PodcastIndexSearch(query: query);
default: default:
return Center(); return Center();
break;
} }
} }
} }
@ -217,14 +218,14 @@ class _RssResultState extends State<RssResult> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final s = context.s; final s = context.s;
var items = widget.rssFeed!.items!; final items = widget.rssFeed!.items!;
return DefaultTabController( return DefaultTabController(
length: 2, length: 2,
child: Column( child: Column(
children: [ children: [
Container( Container(
color: context.primaryColor, color: context.primaryColor,
height: 140, height: 160,
child: Row( child: Row(
children: [ children: [
Expanded( Expanded(
@ -314,8 +315,12 @@ class _RssResultState extends State<RssResult> {
url!.launchUrl; url!.launchUrl;
}, },
style: { style: {
'html': Style(
padding: const EdgeInsets.symmetric(horizontal: 12),
),
'a': Style( 'a': Style(
color: context.accentColor, color: context.accentColor,
textDecoration: TextDecoration.none,
) )
}, },
shrinkWrap: true, shrinkWrap: true,
@ -331,13 +336,9 @@ class _RssResultState extends State<RssResult> {
return Container( return Container(
padding: const EdgeInsets.only(top: 10.0, bottom: 20.0), padding: const EdgeInsets.only(top: 10.0, bottom: 20.0),
alignment: Alignment.center, alignment: Alignment.center,
child: OutlinedButton( child: TextButton(
style: OutlinedButton.styleFrom( style: TextButton.styleFrom(
// highlightedBorderColor: context.accentColor,
onSurface: context.accentColor.withOpacity(0.5), onSurface: context.accentColor.withOpacity(0.5),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(100))),
), ),
child: Text(context.s.loadMore), child: Text(context.s.loadMore),
onPressed: () => setState( onPressed: () => setState(
@ -378,18 +379,12 @@ class __SearchPopupMenuState extends State<_SearchPopupMenu> {
_getSearchEngine(); _getSearchEngine();
} }
Future<void> _getSearchEngine() async {
final storage = KeyValueStorage(searchEngineKey);
final index = await storage.getInt();
setState(() => _searchEngine = SearchEngine.values[index]);
widget.onSelected!(_searchEngine);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return PopupMenuButton<SearchEngine>( return PopupMenuButton<SearchEngine>(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
elevation: 1, elevation: 1,
color: context.priamryContainer,
icon: SizedBox( icon: SizedBox(
height: 25, height: 25,
width: 25, width: 25,
@ -437,11 +432,18 @@ class __SearchPopupMenuState extends State<_SearchPopupMenu> {
], ],
); );
} }
Future<void> _getSearchEngine() async {
final storage = KeyValueStorage(searchEngineKey);
final index = await storage.getInt();
setState(() => _searchEngine = SearchEngine.values[index]);
widget.onSelected!(_searchEngine);
}
} }
class _ListenNotesSearch extends StatefulWidget { class _ListenNotesSearch extends StatefulWidget {
final String? query; final String query;
_ListenNotesSearch({this.query, Key? key}) : super(key: key); _ListenNotesSearch({required this.query, Key? key}) : super(key: key);
@override @override
__ListenNotesSearchState createState() => __ListenNotesSearchState(); __ListenNotesSearchState createState() => __ListenNotesSearchState();
@ -461,9 +463,9 @@ class __ListenNotesSearchState extends State<_ListenNotesSearch> {
_searchFuture = _getListenNotesList(widget.query, _nextOffset); _searchFuture = _getListenNotesList(widget.query, _nextOffset);
} }
Future<void> _saveHistory(String? query) async { Future<void> _saveHistory(String query) async {
final storage = KeyValueStorage(searchHistoryKey); final storage = KeyValueStorage(searchHistoryKey);
final history = await (storage.getStringList() as FutureOr<List<String?>>); final history = await storage.getStringList();
if (!history.contains(query)) { if (!history.contains(query)) {
if (history.length >= 6) { if (history.length >= 6) {
history.removeLast(); history.removeLast();
@ -474,7 +476,7 @@ class __ListenNotesSearchState extends State<_ListenNotesSearch> {
} }
Future<List<OnlinePodcast>> _getListenNotesList( Future<List<OnlinePodcast>> _getListenNotesList(
String? searchText, int? nextOffset) async { String searchText, int? nextOffset) async {
if (nextOffset == 0) _saveHistory(searchText); if (nextOffset == 0) _saveHistory(searchText);
final searchEngine = ListenNotesSearch(); final searchEngine = ListenNotesSearch();
var searchResult; var searchResult;
@ -544,12 +546,13 @@ class __ListenNotesSearchState extends State<_ListenNotesSearch> {
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
OutlinedButton( TextButton(
style: OutlinedButton.styleFrom( style: TextButton.styleFrom(
side: BorderSide(color: context.accentColor), side: BorderSide(color: context.accentColor),
onSurface: context.accentColor.withOpacity(0.5), onSurface: context.accentColor.withOpacity(0.5),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100)), borderRadius: BorderRadius.circular(100),
),
), ),
child: _loading child: _loading
? SizedBox( ? SizedBox(
@ -582,7 +585,9 @@ class __ListenNotesSearchState extends State<_ListenNotesSearch> {
child: Text( child: Text(
'Powered by ListenNotes', 'Powered by ListenNotes',
style: GoogleFonts.quicksand( style: GoogleFonts.quicksand(
color: Colors.red, textStyle: TextStyle(fontSize: 15)), color: Colors.red,
textStyle: TextStyle(fontSize: 15),
),
), ),
// Image( // Image(
// image: context.brightness == Brightness.light // image: context.brightness == Brightness.light
@ -662,101 +667,102 @@ class __PodcastIndexSearchState extends State<_PodcastIndexSearch> {
return PodcastSlideup( return PodcastSlideup(
searchEngine: SearchEngine.podcastIndex, searchEngine: SearchEngine.podcastIndex,
child: FutureBuilder<List>( child: FutureBuilder<List>(
future: _searchFuture.then((value) => value as List<dynamic>), future: _searchFuture.then((value) => value as List<dynamic>),
builder: (context, snapshot) { builder: (context, snapshot) {
if (!snapshot.hasData && widget.query != null) { if (!snapshot.hasData && widget.query != null) {
return Container(
padding: EdgeInsets.only(top: 200),
alignment: Alignment.topCenter,
child: Platform.isIOS
? CupertinoActivityIndicator()
: CircularProgressIndicator(),
);
}
if (snapshot.data!.isEmpty) {
if (_loadError) {
return Container( return Container(
padding: EdgeInsets.only(top: 200), padding: EdgeInsets.only(top: 200),
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
child: Platform.isIOS child: Text('Network error.',
? CupertinoActivityIndicator() style: context.textTheme.headline6!
: CircularProgressIndicator(), .copyWith(color: Colors.red)),
);
} else {
return Container(
padding: EdgeInsets.only(top: 200),
alignment: Alignment.topCenter,
child: Text('No result found.',
style: context.textTheme.headline6!
.copyWith(color: context.accentColor)),
); );
} }
if (snapshot.data!.isEmpty) { }
if (_loadError) { var content = snapshot.data!;
return Container( return CustomScrollView(
padding: EdgeInsets.only(top: 200), slivers: [
alignment: Alignment.topCenter, SliverList(
child: Text('Network error.', delegate: SliverChildBuilderDelegate(
style: context.textTheme.headline6! (context, index) {
.copyWith(color: Colors.red)), return SearchResult(onlinePodcast: content[index]);
); },
} else { childCount: content.length,
return Container(
padding: EdgeInsets.only(top: 200),
alignment: Alignment.topCenter,
child: Text('No result found.',
style: context.textTheme.headline6!
.copyWith(color: context.accentColor)),
);
}
}
var content = snapshot.data!;
return CustomScrollView(
slivers: [
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return SearchResult(onlinePodcast: content[index]);
},
childCount: content.length,
),
), ),
SliverToBoxAdapter( ),
child: Row( SliverToBoxAdapter(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, child: Row(
mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ mainAxisSize: MainAxisSize.min,
OutlinedButton( children: [
style: OutlinedButton.styleFrom( TextButton(
side: BorderSide(color: context.accentColor), style: TextButton.styleFrom(
onSurface: context.accentColor.withOpacity(0.5), side: BorderSide(color: context.accentColor),
shape: RoundedRectangleBorder( onSurface: context.accentColor.withOpacity(0.5),
borderRadius: BorderRadius.circular(100)), ),
), child: _loading
child: _loading ? SizedBox(
? SizedBox( height: 20,
height: 20, width: 20,
width: 20, child: CircularProgressIndicator(
child: CircularProgressIndicator( strokeWidth: 2,
strokeWidth: 2,
))
: Text(context.s.loadMore),
onPressed: () => _loading
? null
: setState(
() {
_loading = true;
_limit += 10;
_searchFuture = _getPodcatsIndexList(
widget.query!,
limit: _limit);
},
), ),
) )
], : Text(context.s.loadMore),
), onPressed: () => _loading
? null
: setState(
() {
_loading = true;
_limit += 10;
_searchFuture = _getPodcatsIndexList(
widget.query!,
limit: _limit);
},
),
)
],
), ),
SliverToBoxAdapter( ),
child: Padding( SliverToBoxAdapter(
padding: EdgeInsets.symmetric(vertical: 10), child: Padding(
child: Center( padding: EdgeInsets.symmetric(vertical: 10),
child: Text( child: Center(
'Powered by PODCASTINDEX', child: Text(
style: GoogleFonts.quicksand( 'Powered by PODCASTINDEX',
color: Colors.red, style: GoogleFonts.quicksand(
textStyle: TextStyle(fontSize: 15)), color: Colors.red,
), textStyle: TextStyle(fontSize: 15)),
) ),
// Image( )
// image: AssetImage('assets/podcastindex.png'), // Image(
// height: 15, // image: AssetImage('assets/podcastindex.png'),
// ), // height: 15,
)) // ),
], ),
); )
}), ],
);
},
),
); );
} }
} }
@ -997,12 +1003,10 @@ class _SearchResultDetailState extends State<SearchResultDetail>
padding: const EdgeInsets.only(top: 10.0, bottom: 20.0), padding: const EdgeInsets.only(top: 10.0, bottom: 20.0),
alignment: Alignment.center, alignment: Alignment.center,
child: SizedBox( child: SizedBox(
child: OutlinedButton( child: TextButton(
style: OutlinedButton.styleFrom( style: TextButton.styleFrom(
side: BorderSide(color: context.accentColor), side: BorderSide(color: context.accentColor),
onSurface: context.accentColor.withOpacity(0.5), onSurface: context.accentColor.withOpacity(0.5),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100)),
), ),
child: _loading child: _loading
? SizedBox( ? SizedBox(

View File

@ -44,6 +44,10 @@ Future main() async {
), ),
); );
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); await SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
systemNavigationBarColor: Colors.transparent,
statusBarColor: Colors.transparent,
));
await SystemChrome.setPreferredOrientations( await SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
} }

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tsacdop/util/extension_helper.dart';
class CustomTabView extends StatefulWidget { class CustomTabView extends StatefulWidget {
final int itemCount; final int itemCount;
@ -108,7 +109,7 @@ class _CustomTabsState extends State<CustomTabView>
unselectedLabelColor: Colors.grey[700], unselectedLabelColor: Colors.grey[700],
indicator: BoxDecoration( indicator: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(15)), borderRadius: BorderRadius.all(Radius.circular(15)),
color: Theme.of(context).accentColor, color: context.accentColor,
), ),
tabs: List.generate( tabs: List.generate(
widget.itemCount, widget.itemCount,

View File

@ -122,12 +122,12 @@ class _PodcastDetailState extends State<PodcastDetail> {
); );
} }
if (result > 0) { if (result > 0) {
var autoDownload = await _dbHelper.getAutoDownload(podcastLocal.id); final autoDownload = await _dbHelper.getAutoDownload(podcastLocal.id);
if (autoDownload) { if (autoDownload) {
var downloader = Provider.of<DownloadState>(context, listen: false); final downloader = Provider.of<DownloadState>(context, listen: false);
var result = await Connectivity().checkConnectivity(); final result = await Connectivity().checkConnectivity();
var autoDownloadStorage = KeyValueStorage(autoDownloadNetworkKey); final autoDownloadStorage = KeyValueStorage(autoDownloadNetworkKey);
var autoDownloadNetwork = await autoDownloadStorage.getInt(); final autoDownloadNetwork = await autoDownloadStorage.getInt();
if (autoDownloadNetwork == 1) { if (autoDownloadNetwork == 1) {
var episodes = await _dbHelper.getNewEpisodes(podcastLocal.id); var episodes = await _dbHelper.getNewEpisodes(podcastLocal.id);
// For safety // For safety
@ -232,31 +232,32 @@ class _PodcastDetailState extends State<PodcastDetail> {
VoidCallback? onTap, VoidCallback? onTap,
required Color backgroundColor}) { required Color backgroundColor}) {
return Container( return Container(
padding: EdgeInsets.fromLTRB(5, 10, 5, 0), padding: EdgeInsets.fromLTRB(5, 10, 5, 0),
width: 60.0, width: 60.0,
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
InkWell( InkWell(
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
onTap: onTap, onTap: onTap,
child: CircleAvatar( child: CircleAvatar(
radius: 20, radius: 20,
child: child, child: child,
backgroundColor: backgroundColor.withOpacity(0.5), backgroundColor: backgroundColor.withOpacity(0.5),
),
), ),
SizedBox(height: 4), ),
Text( SizedBox(height: 4),
title, Text(
style: context.textTheme.subtitle2, title,
textAlign: TextAlign.center, style: context.textTheme.subtitle2,
maxLines: 2, textAlign: TextAlign.center,
overflow: TextOverflow.fade, maxLines: 2,
), overflow: TextOverflow.fade,
], ),
)); ],
),
);
} }
Widget _hostsList(BuildContext context, PodcastLocal podcastLocal) { Widget _hostsList(BuildContext context, PodcastLocal podcastLocal) {
@ -673,11 +674,7 @@ class _PodcastDetailState extends State<PodcastDetail> {
final s = context.s; final s = context.s;
return AnnotatedRegion<SystemUiOverlayStyle>( return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle( value: SystemUiOverlayStyle(
statusBarColor: color, statusBarColor: color, statusBarIconBrightness: Brightness.light),
statusBarIconBrightness: Brightness.dark,
systemNavigationBarColor: context.primaryColor,
systemNavigationBarIconBrightness: context.iconBrightness,
),
child: WillPopScope( child: WillPopScope(
onWillPop: () { onWillPop: () {
if (_playerKey.currentState != null && if (_playerKey.currentState != null &&
@ -690,7 +687,6 @@ class _PodcastDetailState extends State<PodcastDetail> {
}, },
child: Scaffold( child: Scaffold(
body: SafeArea( body: SafeArea(
top: false,
child: RefreshIndicator( child: RefreshIndicator(
key: _refreshIndicatorKey, key: _refreshIndicatorKey,
displacement: context.paddingTop + 40, displacement: context.paddingTop + 40,
@ -751,6 +747,7 @@ class _PodcastDetailState extends State<PodcastDetail> {
), ),
], ],
elevation: 0, elevation: 0,
scrolledUnderElevation: 0,
iconTheme: IconThemeData( iconTheme: IconThemeData(
color: Colors.white, color: Colors.white,
), ),
@ -1021,17 +1018,6 @@ class AboutPodcast extends StatefulWidget {
class _AboutPodcastState extends State<AboutPodcast> { class _AboutPodcastState extends State<AboutPodcast> {
late String _description; late String _description;
late bool _load; late bool _load;
void getDescription(String? id) async {
var dbHelper = DBHelper();
var description = await dbHelper.getFeedDescription(id);
if (description == null || description.isEmpty) {
_description = '';
} else {
var doc = parse(description);
_description = parse(doc.body!.text).documentElement!.text;
}
if (mounted) setState(() => _load = true);
}
@override @override
void initState() { void initState() {
@ -1042,75 +1028,30 @@ class _AboutPodcastState extends State<AboutPodcast> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return !_load if (_load)
? Center() return Linkify(
: Linkify( text: _description,
text: _description, onOpen: (link) {
onOpen: (link) { link.url!.launchUrl;
link.url!.launchUrl; },
}, linkStyle: TextStyle(
linkStyle: TextStyle( color: context.accentColor,
color: Theme.of(context).accentColor, decoration: TextDecoration.underline,
decoration: TextDecoration.underline, textBaseline: TextBaseline.ideographic),
textBaseline: TextBaseline.ideographic), );
); return Center();
// LayoutBuilder( }
// builder: (context, size) {
// final span = TextSpan(text: _description);
// final tp = TextPainter(
// text: span, maxLines: 3, textDirection: TextDirection.ltr);
// tp.layout(maxWidth: size.maxWidth);
// if (tp.didExceedMaxLines) { void getDescription(String? id) async {
// return GestureDetector( final dbHelper = DBHelper();
// onTap: () { final description = await dbHelper.getFeedDescription(id);
// setState(() => _expand = !_expand); if (description == null || description.isEmpty) {
// }, _description = '';
// child: !_expand } else {
// ? Column( final doc = parse(description);
// mainAxisAlignment: MainAxisAlignment.start, _description = parse(doc.body!.text).documentElement!.text;
// mainAxisSize: MainAxisSize.min, }
// crossAxisAlignment: CrossAxisAlignment.start, if (mounted) setState(() => _load = true);
// children: <Widget>[
// Linkify(
// onOpen: (link) {
// link.url.launchUrl;
// },
// text: _description,
// linkStyle: TextStyle(
// color: Theme.of(context).accentColor,
// decoration: TextDecoration.underline,
// textBaseline: TextBaseline.ideographic),
// maxLines: 3,
// overflow: TextOverflow.ellipsis,
// ),
// ],
// )
// : Linkify(
// onOpen: (link) {
// link.url.launchUrl;
// },
// text: _description,
// linkStyle: TextStyle(
// color: Theme.of(context).accentColor,
// decoration: TextDecoration.underline,
// textBaseline: TextBaseline.ideographic),
// ),
// );
// } else {
// return Linkify(
// text: _description,
// onOpen: (link) {
// link.url.launchUrl;
// },
// linkStyle: TextStyle(
// color: Theme.of(context).accentColor,
// decoration: TextDecoration.underline,
// textBaseline: TextBaseline.ideographic),
// );
// }
// },
// );
} }
} }
@ -1156,8 +1097,7 @@ class _SearchEpisodeState extends State<SearchEpisode> {
titlePadding: const EdgeInsets.all(20), titlePadding: const EdgeInsets.all(20),
actionsPadding: EdgeInsets.zero, actionsPadding: EdgeInsets.zero,
actions: <Widget>[ actions: <Widget>[
FlatButton( TextButton(
splashColor: context.accentColor.withAlpha(70),
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
child: Text( child: Text(
s.cancel, s.cancel,
@ -1165,8 +1105,7 @@ class _SearchEpisodeState extends State<SearchEpisode> {
style: TextStyle(color: Colors.grey[600]), style: TextStyle(color: Colors.grey[600]),
), ),
), ),
FlatButton( TextButton(
splashColor: context.accentColor.withAlpha(70),
onPressed: () { onPressed: () {
if ((_query ?? '').isNotEmpty) { if ((_query ?? '').isNotEmpty) {
widget.onSearch!(_query); widget.onSearch!(_query);

View File

@ -85,45 +85,6 @@ class __PodcastCardState extends State<_PodcastCard>
int? _seconds; int? _seconds;
int? _skipSeconds; int? _skipSeconds;
Future<int?> _getSkipSecond(String? id) async {
var dbHelper = DBHelper();
var seconds = await dbHelper.getSkipSecondsStart(id);
_skipSeconds = seconds;
return seconds;
}
_saveSkipSeconds(String? id, int? seconds) async {
var dbHelper = DBHelper();
await dbHelper.saveSkipSecondsStart(id, seconds);
}
_setAutoDownload(String? id, bool boo) async {
var permission = await _checkPermmison();
if (permission) {
var dbHelper = DBHelper();
await dbHelper.saveAutoDownload(id, boo: boo);
}
}
Future<bool> _getAutoDownload(String? id) async {
var dbHelper = DBHelper();
return await dbHelper.getAutoDownload(id);
}
Future<bool> _checkPermmison() async {
var permission = await Permission.storage.status;
if (permission != PermissionStatus.granted) {
var permissions = await [Permission.storage].request();
if (permissions[Permission.storage] == PermissionStatus.granted) {
return true;
} else {
return false;
}
} else {
return true;
}
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -134,43 +95,20 @@ class __PodcastCardState extends State<_PodcastCard>
_controller = _controller =
AnimationController(vsync: this, duration: Duration(milliseconds: 300)); AnimationController(vsync: this, duration: Duration(milliseconds: 300));
_animation = Tween<double>(begin: 0.0, end: 1.0).animate(_controller) _animation = Tween<double>(begin: 0.0, end: 1.0).animate(_controller)
..addListener(() { ..addListener(
setState(() { () {
_value = _animation.value; setState(() {
}); _value = _animation.value;
}); });
} },
Widget _buttonOnMenu(
{required Widget icon,
VoidCallback? onTap,
required String tooltip}) =>
Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
child: Container(
height: 50.0,
padding: EdgeInsets.symmetric(horizontal: 5.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: icon,
),
Text(tooltip, style: context.textTheme.subtitle2),
],
)),
),
); );
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final c = widget.podcastLocal!.backgroudColor(context); final c = widget.podcastLocal!.backgroudColor(context);
final s = context.s; final s = context.s;
var groupList = context.watch<GroupList>(); final groupList = context.watch<GroupList>();
_belongGroups = groupList.getPodcastGroup(widget.podcastLocal!.id); _belongGroups = groupList.getPodcastGroup(widget.podcastLocal!.id);
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -398,9 +336,7 @@ class __PodcastCardState extends State<_PodcastCard>
_seconds = value.inSeconds, _seconds = value.inSeconds,
), ),
actions: <Widget>[ actions: <Widget>[
FlatButton( TextButton(
splashColor: context.accentColor
.withAlpha(70),
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
_seconds = 0; _seconds = 0;
@ -411,9 +347,7 @@ class __PodcastCardState extends State<_PodcastCard>
color: Colors.grey[600]), color: Colors.grey[600]),
), ),
), ),
FlatButton( TextButton(
splashColor: context.accentColor
.withAlpha(70),
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
_saveSkipSeconds( _saveSkipSeconds(
@ -431,44 +365,42 @@ class __PodcastCardState extends State<_PodcastCard>
}); });
}), }),
_buttonOnMenu( _buttonOnMenu(
icon: Icon( icon: Icon(
Icons.delete, Icons.delete,
color: Colors.red, color: Colors.red,
size: _value == 0 ? 1 : 20 * _value!, size: _value == 0 ? 1 : 20 * _value!,
), ),
tooltip: s.remove, tooltip: s.remove,
onTap: () { onTap: () {
generalDialog( generalDialog(
context, context,
title: Text(s.removeConfirm), title: Text(s.removeConfirm),
content: Text(s.removePodcastDes), content: Text(s.removePodcastDes),
actions: <Widget>[ actions: <Widget>[
FlatButton( TextButton(
splashColor: onPressed: () =>
context.accentColor.withAlpha(70), Navigator.of(context).pop(),
onPressed: () => child: Text(
Navigator.of(context).pop(), s.cancel,
child: Text( style:
s.cancel, TextStyle(color: Colors.grey[600]),
style: TextStyle(
color: Colors.grey[600]),
),
), ),
FlatButton( ),
splashColor: Colors.red.withAlpha(70), TextButton(
onPressed: () { onPressed: () {
groupList.removePodcast( groupList.removePodcast(
widget.podcastLocal!); widget.podcastLocal!);
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
child: Text( child: Text(
s.confirm, s.confirm,
style: TextStyle(color: Colors.red), style: TextStyle(color: Colors.red),
), ),
) )
], ],
); );
}), },
),
], ],
), ),
), ),
@ -477,6 +409,71 @@ class __PodcastCardState extends State<_PodcastCard>
], ],
); );
} }
Widget _buttonOnMenu(
{required Widget icon,
VoidCallback? onTap,
required String tooltip}) =>
Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
child: Container(
height: 50.0,
padding: EdgeInsets.symmetric(horizontal: 5.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: icon,
),
Text(tooltip, style: context.textTheme.subtitle2),
],
),
),
),
);
Future<int?> _getSkipSecond(String? id) async {
final dbHelper = DBHelper();
final seconds = await dbHelper.getSkipSecondsStart(id);
_skipSeconds = seconds;
return seconds;
}
_saveSkipSeconds(String? id, int? seconds) async {
final dbHelper = DBHelper();
await dbHelper.saveSkipSecondsStart(id, seconds);
}
_setAutoDownload(String? id, bool boo) async {
final permission = await _checkPermmison();
if (permission) {
final dbHelper = DBHelper();
await dbHelper.saveAutoDownload(id, boo: boo);
}
}
Future<bool> _getAutoDownload(String? id) async {
final dbHelper = DBHelper();
return await dbHelper.getAutoDownload(id);
}
Future<bool> _checkPermmison() async {
final permission = await Permission.storage.status;
if (permission != PermissionStatus.granted) {
final permissions = await [Permission.storage].request();
if (permissions[Permission.storage] == PermissionStatus.granted) {
return true;
} else {
return false;
}
} else {
return true;
}
}
} }
class RenameGroup extends StatefulWidget { class RenameGroup extends StatefulWidget {
@ -511,7 +508,7 @@ class _RenameGroupState extends State<RenameGroup> {
final s = context.s; final s = context.s;
return AnnotatedRegion<SystemUiOverlayStyle>( return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle( value: SystemUiOverlayStyle(
statusBarIconBrightness: Brightness.light, statusBarColor: Colors.transparent,
systemNavigationBarColor: systemNavigationBarColor:
Theme.of(context).brightness == Brightness.light Theme.of(context).brightness == Brightness.light
? Color.fromRGBO(113, 113, 113, 1) ? Color.fromRGBO(113, 113, 113, 1)
@ -519,27 +516,28 @@ class _RenameGroupState extends State<RenameGroup> {
), ),
child: AlertDialog( child: AlertDialog(
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10))), borderRadius: const BorderRadius.all(
Radius.circular(20),
),
),
elevation: 1, elevation: 1,
contentPadding: EdgeInsets.symmetric(horizontal: 20), contentPadding: EdgeInsets.symmetric(horizontal: 20),
titlePadding: EdgeInsets.all(20), titlePadding: EdgeInsets.all(20),
actionsPadding: EdgeInsets.zero, actionsPadding: EdgeInsets.zero,
actions: <Widget>[ actions: <Widget>[
FlatButton( TextButton(
splashColor: context.accentColor.withAlpha(70),
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
child: Text( child: Text(
s.cancel, s.cancel,
style: TextStyle(color: Colors.grey[600]), style: TextStyle(color: Colors.grey[600]),
), ),
), ),
FlatButton( TextButton(
splashColor: context.accentColor.withAlpha(70),
onPressed: () async { onPressed: () async {
if (list.contains(_newName)) { if (list.contains(_newName)) {
setState(() => _error = 1); setState(() => _error = 1);
} else { } else {
var newGroup = PodcastGroup(_newName, final newGroup = PodcastGroup(_newName,
color: widget.group!.color, color: widget.group!.color,
id: widget.group!.id, id: widget.group!.id,
podcastList: widget.group!.podcastList); podcastList: widget.group!.podcastList);
@ -547,12 +545,16 @@ class _RenameGroupState extends State<RenameGroup> {
Navigator.of(context).pop(); Navigator.of(context).pop();
} }
}, },
child: Text(s.confirm, child: Text(
style: TextStyle(color: Theme.of(context).accentColor)), s.confirm,
style: TextStyle(color: context.accentColor),
),
) )
], ],
title: title: SizedBox(
SizedBox(width: context.width - 160, child: Text(s.editGroupName)), width: context.width - 160,
child: Text(s.editGroupName),
),
content: Column( content: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: <Widget>[ children: <Widget>[
@ -578,7 +580,7 @@ class _RenameGroupState extends State<RenameGroup> {
_newName = value; _newName = value;
}, },
), ),
Container( Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: (_error == 1) child: (_error == 1)
? Text( ? Text(

View File

@ -42,7 +42,7 @@ class _PodcastManageState extends State<PodcastManage>
_menuValue = 0; _menuValue = 0;
_index = 0; _index = 0;
_menuController = AnimationController( _menuController = AnimationController(
vsync: this, duration: const Duration(milliseconds: 150)); vsync: this, duration: const Duration(milliseconds: 300));
_controller = AnimationController( _controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 500)); vsync: this, duration: const Duration(milliseconds: 500));
_animation = Tween(begin: 0.0, end: 1.0).animate(_controller) _animation = Tween(begin: 0.0, end: 1.0).animate(_controller)
@ -51,8 +51,8 @@ class _PodcastManageState extends State<PodcastManage>
setState(() => _fraction = _animation.value); setState(() => _fraction = _animation.value);
} }
}); });
_menuAnimation = Tween(begin: 0.0, end: 1.0).animate( _menuAnimation = Tween(begin: 0.0, end: 1.0)
CurvedAnimation(parent: _menuController, curve: Curves.elasticInOut)) .animate(CurvedAnimation(parent: _menuController, curve: Curves.ease))
..addListener(() { ..addListener(() {
if (mounted) setState(() => _menuValue = _menuAnimation.value); if (mounted) setState(() => _menuValue = _menuAnimation.value);
}); });
@ -77,6 +77,274 @@ class _PodcastManageState extends State<PodcastManage>
super.dispose(); super.dispose();
} }
@override
Widget build(BuildContext context) {
final s = context.s;
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarColor: context.priamryContainer,
systemNavigationBarColor: context.background,
),
child: Scaffold(
appBar: AppBar(
backgroundColor: context.priamryContainer,
title: Text(context.s.groups(2)),
leading: CustomBackButton(),
systemOverlayStyle: SystemUiOverlayStyle(
statusBarColor: context.priamryContainer,
),
actions: <Widget>[
featureDiscoveryOverlay(
context,
featureId: addGroupFeature,
tapTarget: Icon(Icons.add),
title: s.featureDiscoveryGroup,
backgroundColor: Colors.cyan[600],
description: s.featureDiscoveryGroupDes,
buttonColor: Colors.cyan[500],
child: IconButton(
splashRadius: 20,
onPressed: () => showGeneralDialog(
context: context,
barrierDismissible: true,
barrierLabel: MaterialLocalizations.of(context)
.modalBarrierDismissLabel,
barrierColor: Colors.black54,
transitionDuration: const Duration(milliseconds: 200),
pageBuilder: (context, animaiton, secondaryAnimation) =>
AddGroup()),
icon: Icon(Icons.add_circle_outline)),
),
Selector<SettingState, bool?>(
selector: (_, setting) => setting.openAllPodcastDefalt,
builder: (_, data, __) {
return !data!
? IconButton(
splashRadius: 20,
onPressed: () => Navigator.push(
context, ScaleRoute(page: PodcastList())),
icon: Icon(Icons.all_out))
: Center();
})
// _OrderMenu(),
],
),
body: SafeArea(
child: WillPopScope(
onWillPop: () async {
context.read<GroupList>().clearOrderChanged();
return true;
},
child: Consumer<GroupList>(
builder: (_, groupList, __) {
// var _isLoading = groupList.isLoading;
final _groups = groupList.groups;
if (_groups.isEmpty) return Center();
return Stack(
children: <Widget>[
ColoredBox(
color: context.priamryContainer,
child: CustomTabView(
itemCount: _groups.length,
tabBuilder: (context, index) => Tab(
child: Container(
height: 50.0,
padding: EdgeInsets.symmetric(horizontal: 20.0),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
),
child: Text(
_groups[index]!.name!,
),
),
),
pageBuilder: (context, index) =>
featureDiscoveryOverlay(
context,
featureId: configurePodcast,
tapTarget: Text(s.podcast(1)),
title: s.featureDiscoveryGroupPodcast,
backgroundColor: Colors.cyan[600],
buttonColor: Colors.cyan[500],
description: s.featureDiscoveryGroupPodcastDes,
child: PodcastGroupList(
group: _groups[index],
key: ValueKey<String?>(_groups[index]!.name),
),
),
onPositionChange: (value) =>
// setState(() =>
_index = value,
),
),
if (_showSetting)
Positioned.fill(
top: 50,
child: GestureDetector(
onTap: () async {
await _menuController.reverse();
if (mounted) {
setState(() => _showSetting = false);
}
},
child: Container(
color: context.background.withOpacity(
0.8 * math.min(_menuController.value * 2, 1.0)),
),
),
),
Positioned(
right: 30,
bottom: 30,
child: _saveButton(),
),
if (_showSetting)
Positioned(
right: 100 * _menuValue - 70,
bottom: 100,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
_menuController.reverse();
setState(() => _showSetting = false);
_index == 0
? Fluttertoast.showToast(
msg: s.toastHomeGroupNotSupport,
gravity: ToastGravity.BOTTOM,
)
: showGeneralDialog(
context: context,
barrierDismissible: true,
barrierLabel:
MaterialLocalizations.of(context)
.modalBarrierDismissLabel,
barrierColor: Colors.black54,
transitionDuration:
const Duration(milliseconds: 300),
pageBuilder: (context, animaiton,
secondaryAnimation) =>
RenameGroup(
group: _groups[_index!],
));
},
child: Container(
height: 30.0,
decoration: BoxDecoration(
color: Colors.grey[700],
borderRadius:
BorderRadius.circular(10.0)),
padding: EdgeInsets.symmetric(horizontal: 10),
child: Row(
children: <Widget>[
Icon(
Icons.text_fields,
color: Colors.white,
size: 15.0,
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: 5.0),
),
Text(context.s.editGroupName,
style:
TextStyle(color: Colors.white)),
],
),
),
),
),
SizedBox(height: 20),
Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
_menuController.reverse();
setState(() => _showSetting = false);
_index == 0
? Fluttertoast.showToast(
msg: s.toastHomeGroupNotSupport,
gravity: ToastGravity.BOTTOM,
)
: generalDialog(
context,
title: Text(s.removeConfirm),
content: Text(s.groupRemoveConfirm),
actions: <Widget>[
TextButton(
onPressed: () =>
Navigator.of(context).pop(),
child: Text(
context.s.cancel,
style: TextStyle(
color: Colors.grey[600]),
),
),
TextButton(
onPressed: () {
if (_index ==
groupList.groups.length -
1) {
setState(() {
_index = _index! - 1;
});
groupList.delGroup(
_groups[_index! + 1]!);
} else {
groupList.delGroup(
_groups[_index!]!);
}
Navigator.of(context).pop();
},
child: Text(
context.s.confirm,
style: TextStyle(
color: Colors.red),
),
)
],
);
},
child: Container(
height: 30,
decoration: BoxDecoration(
color: Colors.grey[700],
borderRadius:
BorderRadius.circular(10.0)),
padding: EdgeInsets.symmetric(horizontal: 10),
child: Row(
children: <Widget>[
Icon(
Icons.delete,
color: Colors.red,
size: 15.0,
),
SizedBox(width: 10),
Text(s.remove,
style: TextStyle(color: Colors.red)),
],
),
),
),
),
],
),
),
],
);
},
),
),
),
),
);
}
Widget _saveButton() { Widget _saveButton() {
final s = context.s; final s = context.s;
return Consumer<GroupList>( return Consumer<GroupList>(
@ -150,288 +418,6 @@ class _PodcastManageState extends State<PodcastManage>
}, },
); );
} }
@override
Widget build(BuildContext context) {
final s = context.s;
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarIconBrightness: context.brightness,
systemNavigationBarColor: context.primaryColor,
systemNavigationBarIconBrightness: context.iconBrightness,
// statusBarColor: Theme.of(context).primaryColor,
),
child: Scaffold(
appBar: AppBar(
title: Text(context.s.groups(2)),
leading: CustomBackButton(),
actions: <Widget>[
featureDiscoveryOverlay(
context,
featureId: addGroupFeature,
tapTarget: Icon(Icons.add),
title: s.featureDiscoveryGroup,
backgroundColor: Colors.cyan[600],
description: s.featureDiscoveryGroupDes,
buttonColor: Colors.cyan[500],
child: IconButton(
splashRadius: 20,
onPressed: () => showGeneralDialog(
context: context,
barrierDismissible: true,
barrierLabel: MaterialLocalizations.of(context)
.modalBarrierDismissLabel,
barrierColor: Colors.black54,
transitionDuration: const Duration(milliseconds: 200),
pageBuilder: (context, animaiton, secondaryAnimation) =>
AddGroup()),
icon: Icon(Icons.add_circle_outline)),
),
Selector<SettingState, bool?>(
selector: (_, setting) => setting.openAllPodcastDefalt,
builder: (_, data, __) {
return !data!
? IconButton(
splashRadius: 20,
onPressed: () => Navigator.push(
context, ScaleRoute(page: PodcastList())),
icon: Icon(Icons.all_out))
: Center();
})
// _OrderMenu(),
],
),
body: WillPopScope(
onWillPop: () async {
context.read<GroupList>().clearOrderChanged();
return true;
},
child: Consumer<GroupList>(
builder: (_, groupList, __) {
// var _isLoading = groupList.isLoading;
var _groups = groupList.groups;
return _groups.isEmpty
? Center()
: Stack(
children: <Widget>[
Container(
color: context.background,
child: CustomTabView(
itemCount: _groups.length,
tabBuilder: (context, index) => Tab(
child: Container(
height: 30.0,
padding:
EdgeInsets.symmetric(horizontal: 10.0),
alignment: Alignment.center,
decoration: BoxDecoration(
// color: Colors.grey[600].withOpacity(0.3),
borderRadius: BorderRadius.circular(15),
),
child: Text(
_groups[index]!.name!,
)),
),
pageBuilder: (context, index) =>
featureDiscoveryOverlay(
context,
featureId: configurePodcast,
tapTarget: Text(s.podcast(1)),
title: s.featureDiscoveryGroupPodcast,
backgroundColor: Colors.cyan[600],
buttonColor: Colors.cyan[500],
description: s.featureDiscoveryGroupPodcastDes,
child: PodcastGroupList(
group: _groups[index],
key: ValueKey<String?>(_groups[index]!.name),
),
),
onPositionChange: (value) =>
// setState(() =>
_index = value,
),
),
if (_showSetting)
Positioned.fill(
top: 50,
child: GestureDetector(
onTap: () async {
await _menuController.reverse();
if (mounted) {
setState(() => _showSetting = false);
}
},
child: Container(
color: context.background.withOpacity(0.8 *
math.min(_menuController.value * 2, 1.0)),
),
),
),
Positioned(
right: 30,
bottom: 30,
child: _saveButton(),
),
if (_showSetting)
Positioned(
right: 100 * _menuValue - 70,
bottom: 100,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
_menuController.reverse();
setState(() => _showSetting = false);
_index == 0
? Fluttertoast.showToast(
msg: s.toastHomeGroupNotSupport,
gravity: ToastGravity.BOTTOM,
)
: showGeneralDialog(
context: context,
barrierDismissible: true,
barrierLabel:
MaterialLocalizations.of(
context)
.modalBarrierDismissLabel,
barrierColor: Colors.black54,
transitionDuration:
const Duration(
milliseconds: 300),
pageBuilder: (context, animaiton,
secondaryAnimation) =>
RenameGroup(
group: _groups[_index!],
));
},
child: Container(
height: 30.0,
decoration: BoxDecoration(
color: Colors.grey[700],
borderRadius:
BorderRadius.circular(10.0)),
padding:
EdgeInsets.symmetric(horizontal: 10),
child: Row(
children: <Widget>[
Icon(
Icons.text_fields,
color: Colors.white,
size: 15.0,
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: 5.0),
),
Text(context.s.editGroupName,
style: TextStyle(
color: Colors.white)),
],
),
),
),
),
SizedBox(height: 20),
Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
_menuController.reverse();
setState(() => _showSetting = false);
_index == 0
? Fluttertoast.showToast(
msg: s.toastHomeGroupNotSupport,
gravity: ToastGravity.BOTTOM,
)
: generalDialog(
context,
title: Text(s.removeConfirm),
content:
Text(s.groupRemoveConfirm),
actions: <Widget>[
FlatButton(
splashColor: context
.accentColor
.withAlpha(70),
onPressed: () =>
Navigator.of(context)
.pop(),
child: Text(
context.s.cancel,
style: TextStyle(
color:
Colors.grey[600]),
),
),
FlatButton(
splashColor: context
.accentColor
.withAlpha(70),
onPressed: () {
if (_index ==
groupList
.groups.length -
1) {
setState(() {
_index = _index! - 1;
});
groupList.delGroup(
_groups[
_index! + 1]!);
} else {
groupList.delGroup(
_groups[_index!]!);
}
Navigator.of(context).pop();
},
child: Text(
context.s.confirm,
style: TextStyle(
color: Colors.red),
),
)
],
);
},
child: Container(
height: 30,
decoration: BoxDecoration(
color: Colors.grey[700],
borderRadius:
BorderRadius.circular(10.0)),
padding:
EdgeInsets.symmetric(horizontal: 10),
child: Row(
children: <Widget>[
Icon(
Icons.delete,
color: Colors.red,
size: 15.0,
),
SizedBox(width: 10),
Text(s.remove,
style:
TextStyle(color: Colors.red)),
],
),
),
),
),
],
),
),
],
);
},
),
),
),
);
}
} }
class _OrderMenu extends StatelessWidget { class _OrderMenu extends StatelessWidget {
@ -495,78 +481,81 @@ class _AddGroupState extends State<AddGroup> {
List list = groupList.groups.map((e) => e!.name).toList(); List list = groupList.groups.map((e) => e!.name).toList();
return AnnotatedRegion<SystemUiOverlayStyle>( return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle( value: SystemUiOverlayStyle(
statusBarIconBrightness: Brightness.light, statusBarColor: Colors.transparent,
systemNavigationBarColor: systemNavigationBarColor:
Theme.of(context).brightness == Brightness.light Theme.of(context).brightness == Brightness.light
? Color.fromRGBO(113, 113, 113, 1) ? Color.fromRGBO(113, 113, 113, 1)
: Color.fromRGBO(5, 5, 5, 1), : Color.fromRGBO(5, 5, 5, 1),
), ),
child: AlertDialog( child: SafeArea(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), top: false,
elevation: 1, child: AlertDialog(
contentPadding: EdgeInsets.symmetric(horizontal: 20), shape: RoundedRectangleBorder(
titlePadding: EdgeInsets.all(20), borderRadius: BorderRadius.circular(20),
actionsPadding: EdgeInsets.zero,
actions: <Widget>[
FlatButton(
splashColor: context.accentColor.withAlpha(70),
onPressed: () => Navigator.of(context).pop(),
child: Text(
s.cancel,
style: TextStyle(color: Colors.grey[600]),
),
), ),
FlatButton( elevation: 1,
splashColor: context.accentColor.withAlpha(70), contentPadding: EdgeInsets.symmetric(horizontal: 20),
onPressed: () async { titlePadding: EdgeInsets.all(20),
if (list.contains(_newGroup)) { actionsPadding: EdgeInsets.zero,
setState(() => _error = 1); actions: <Widget>[
} else { TextButton(
groupList.addGroup(PodcastGroup(_newGroup)); onPressed: () => Navigator.of(context).pop(),
Navigator.of(context).pop(); child: Text(
} s.cancel,
}, style: TextStyle(color: Colors.grey[600]),
child:
Text(s.confirm, style: TextStyle(color: context.accentColor)),
)
],
title: SizedBox(width: context.width - 160, child: Text(s.newGroup)),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextField(
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(horizontal: 10),
hintText: s.newGroup,
hintStyle: TextStyle(fontSize: 18),
filled: true,
focusedBorder: UnderlineInputBorder(
borderSide:
BorderSide(color: context.accentColor, width: 2.0),
),
enabledBorder: UnderlineInputBorder(
borderSide:
BorderSide(color: context.accentColor, width: 2.0),
),
), ),
cursorRadius: Radius.circular(2), ),
autofocus: true, TextButton(
maxLines: 1, onPressed: () async {
controller: _controller, if (list.contains(_newGroup)) {
onChanged: (value) { setState(() => _error = 1);
_newGroup = value; } else {
groupList.addGroup(PodcastGroup(_newGroup));
Navigator.of(context).pop();
}
}, },
), child:
Container( Text(s.confirm, style: TextStyle(color: context.accentColor)),
alignment: Alignment.centerLeft, )
child: (_error == 1)
? Text(
s.groupExisted,
style: TextStyle(color: Colors.red[400]),
)
: Center(),
),
], ],
title: SizedBox(width: context.width - 160, child: Text(s.newGroup)),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextField(
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(horizontal: 10),
hintText: s.newGroup,
hintStyle: TextStyle(fontSize: 18),
filled: true,
focusedBorder: UnderlineInputBorder(
borderSide:
BorderSide(color: context.accentColor, width: 2.0),
),
enabledBorder: UnderlineInputBorder(
borderSide:
BorderSide(color: context.accentColor, width: 2.0),
),
),
cursorRadius: Radius.circular(2),
autofocus: true,
maxLines: 1,
controller: _controller,
onChanged: (value) {
_newGroup = value;
},
),
Container(
alignment: Alignment.centerLeft,
child: (_error == 1)
? Text(
s.groupExisted,
style: TextStyle(color: Colors.red[400]),
)
: Center(),
),
],
),
), ),
), ),
); );

View File

@ -52,153 +52,6 @@ class _PodcastSettingState extends State<PodcastSetting> {
_showEndTimePicker = false; _showEndTimePicker = false;
} }
Future<void> _setAutoDownload(bool boo) async {
var permission = await _checkPermmison();
if (permission) {
await _dbHelper.saveAutoDownload(widget.podcastLocal!.id, boo: boo);
}
if (mounted) setState(() {});
}
Future<void> _setNeverUpdate(bool boo) async {
await _dbHelper.saveNeverUpdate(widget.podcastLocal!.id, boo: boo);
if (mounted) setState(() {});
}
Future<void> _setHideNewMark(bool boo) async {
await _dbHelper.saveHideNewMark(widget.podcastLocal!.id, boo: boo);
if (mounted) setState(() {});
}
Future<void> _saveSkipSecondsStart(int? seconds) async {
await _dbHelper.saveSkipSecondsStart(widget.podcastLocal!.id, seconds);
}
Future<void> _saveSkipSecondsEnd(int seconds) async {
await _dbHelper.saveSkipSecondsEnd(widget.podcastLocal!.id, seconds);
}
Future<bool> _getAutoDownload(String? id) async {
return await _dbHelper.getAutoDownload(id);
}
Future<bool> _getNeverUpdate(String? id) async {
return await _dbHelper.getNeverUpdate(id);
}
Future<bool> _getHideNewMark(String? id) async {
return await _dbHelper.getHideNewMark(id);
}
Future<int?> _getSkipSecondStart(String? id) async {
return await _dbHelper.getSkipSecondsStart(id);
}
Future<int?> _getSkipSecondEnd(String id) async {
return await _dbHelper.getSkipSecondsEnd(id);
}
Future<void> _markListened(String? podcastId) async {
setState(() {
_markStatus = MarkStatus.start;
});
final episodes = await _dbHelper.getRssItem(podcastId, -1,
reverse: true, hideListened: true);
for (var episode in episodes) {
final history = PlayHistory(episode.title, episode.enclosureUrl, 0, 1);
await _dbHelper.saveHistory(history);
}
if (mounted) {
setState(() {
_markStatus = MarkStatus.complete;
});
}
}
Future<void> _refreshArtWork() async {
setState(() => _coverStatus = RefreshCoverStatus.start);
var options = BaseOptions(
connectTimeout: 30000,
receiveTimeout: 90000,
);
var dir = await getApplicationDocumentsDirectory();
var filePath = "${dir.path}/${widget.podcastLocal!.id}.png";
var dio = Dio(options);
String? imageUrl;
try {
var response = await dio.get(widget.podcastLocal!.rssUrl);
try {
var p = RssFeed.parse(response.data);
imageUrl = p.itunes!.image!.href ?? p.image!.url;
} catch (e) {
developer.log(e.toString());
if (mounted) setState(() => _coverStatus = RefreshCoverStatus.error);
}
} catch (e) {
developer.log(e.toString());
if (mounted) setState(() => _coverStatus = RefreshCoverStatus.error);
}
if (imageUrl != null && imageUrl.contains('http')) {
try {
img.Image thumbnail;
var imageResponse = await dio.get<List<int>>(imageUrl,
options: Options(
responseType: ResponseType.bytes,
));
var image = img.decodeImage(imageResponse.data!)!;
thumbnail = img.copyResize(image, width: 300);
if (thumbnail != null) {
File(filePath)..writeAsBytesSync(img.encodePng(thumbnail));
_dbHelper.updatePodcastImage(
id: widget.podcastLocal!.id, filePath: filePath);
print('saved image');
if (mounted) {
setState(() => _coverStatus = RefreshCoverStatus.complete);
}
}
} catch (e) {
developer.log(e.toString());
if (mounted) setState(() => _coverStatus = RefreshCoverStatus.error);
}
} else if (_coverStatus == RefreshCoverStatus.start && mounted) {
setState(() => _coverStatus = RefreshCoverStatus.complete);
}
}
Future<bool> _checkPermmison() async {
var permission = await Permission.storage.status;
if (permission != PermissionStatus.granted) {
var permissions = await [Permission.storage].request();
if (permissions[Permission.storage] == PermissionStatus.granted) {
return true;
} else {
return false;
}
} else {
return true;
}
}
Widget _getRefreshStatusIcon(RefreshCoverStatus status) {
switch (status) {
case RefreshCoverStatus.none:
return Center();
break;
case RefreshCoverStatus.start:
return CircularProgressIndicator(strokeWidth: 2);
break;
case RefreshCoverStatus.complete:
return Icon(Icons.done);
break;
case RefreshCoverStatus.error:
return Icon(Icons.refresh, color: Colors.red);
break;
default:
return Center();
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final s = context.s; final s = context.s;
@ -341,42 +194,43 @@ class _PodcastSettingState extends State<PodcastSetting> {
child: _getRefreshStatusIcon(_coverStatus)))), child: _getRefreshStatusIcon(_coverStatus)))),
Divider(height: 1), Divider(height: 1),
ListTile( ListTile(
onTap: () { onTap: () {
setState(() { setState(() {
_removeConfirm = false; _removeConfirm = false;
_showStartTimePicker = false; _showStartTimePicker = false;
_showEndTimePicker = false; _showEndTimePicker = false;
_markConfirm = !_markConfirm; _markConfirm = !_markConfirm;
}); });
}, },
dense: true, dense: true,
title: Row( title: Row(
children: [ children: [
SizedBox( SizedBox(
height: 18, height: 18,
width: 18, width: 18,
child: CustomPaint( child: CustomPaint(
painter: ListenedAllPainter(context.accentColor, stroke: 2), painter: ListenedAllPainter(context.accentColor, stroke: 2),
),
), ),
SizedBox(width: 20), ),
Text(s.menuMarkAllListened, SizedBox(width: 20),
style: textStyle.copyWith( Text(s.menuMarkAllListened,
color: context.accentColor, style: textStyle.copyWith(
fontWeight: FontWeight.bold)), color: context.accentColor, fontWeight: FontWeight.bold)),
], ],
),
trailing: Padding(
padding: const EdgeInsets.only(right: 10.0),
child: SizedBox(
height: 20,
width: 20,
child: _markStatus == MarkStatus.none
? Center()
: _markStatus == MarkStatus.start
? CircularProgressIndicator(strokeWidth: 2)
: Icon(Icons.done),
), ),
trailing: Padding( ),
padding: const EdgeInsets.only(right: 10.0), ),
child: SizedBox(
height: 20,
width: 20,
child: _markStatus == MarkStatus.none
? Center()
: _markStatus == MarkStatus.start
? CircularProgressIndicator(strokeWidth: 2)
: Icon(Icons.done)),
)),
if (_markConfirm) if (_markConfirm)
Container( Container(
width: double.infinity, width: double.infinity,
@ -384,7 +238,7 @@ class _PodcastSettingState extends State<PodcastSetting> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
FlatButton( TextButton(
onPressed: () => setState(() { onPressed: () => setState(() {
_markConfirm = false; _markConfirm = false;
}), }),
@ -392,7 +246,7 @@ class _PodcastSettingState extends State<PodcastSetting> {
s.cancel, s.cancel,
style: TextStyle(color: Colors.grey[600]), style: TextStyle(color: Colors.grey[600]),
)), )),
FlatButton( TextButton(
onPressed: () { onPressed: () {
if (_markStatus != MarkStatus.start) { if (_markStatus != MarkStatus.start) {
_markListened(widget.podcastLocal!.id); _markListened(widget.podcastLocal!.id);
@ -402,7 +256,7 @@ class _PodcastSettingState extends State<PodcastSetting> {
}); });
}, },
child: Text(s.confirm, child: Text(s.confirm,
style: TextStyle(color: context.accentColor))), style: TextStyle(color: context.error))),
], ],
), ),
), ),
@ -433,15 +287,14 @@ class _PodcastSettingState extends State<PodcastSetting> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
FlatButton( TextButton(
onPressed: () => setState(() { onPressed: () => setState(() {
_removeConfirm = false; _removeConfirm = false;
}), }),
child: child:
Text(s.cancel, style: TextStyle(color: Colors.grey[600])), Text(s.cancel, style: TextStyle(color: Colors.grey[600])),
), ),
FlatButton( TextButton(
splashColor: Colors.red.withAlpha(70),
onPressed: () async { onPressed: () async {
await groupList.removePodcast(widget.podcastLocal!); await groupList.removePodcast(widget.podcastLocal!);
Navigator.of(context).pop(); Navigator.of(context).pop();
@ -454,6 +307,147 @@ class _PodcastSettingState extends State<PodcastSetting> {
], ],
); );
} }
Future<void> _setAutoDownload(bool boo) async {
var permission = await _checkPermmison();
if (permission) {
await _dbHelper.saveAutoDownload(widget.podcastLocal!.id, boo: boo);
}
if (mounted) setState(() {});
}
Future<void> _setNeverUpdate(bool boo) async {
await _dbHelper.saveNeverUpdate(widget.podcastLocal!.id, boo: boo);
if (mounted) setState(() {});
}
Future<void> _setHideNewMark(bool boo) async {
await _dbHelper.saveHideNewMark(widget.podcastLocal!.id, boo: boo);
if (mounted) setState(() {});
}
Future<void> _saveSkipSecondsStart(int? seconds) async {
await _dbHelper.saveSkipSecondsStart(widget.podcastLocal!.id, seconds);
}
Future<void> _saveSkipSecondsEnd(int seconds) async {
await _dbHelper.saveSkipSecondsEnd(widget.podcastLocal!.id, seconds);
}
Future<bool> _getAutoDownload(String? id) async {
return await _dbHelper.getAutoDownload(id);
}
Future<bool> _getNeverUpdate(String? id) async {
return await _dbHelper.getNeverUpdate(id);
}
Future<bool> _getHideNewMark(String? id) async {
return await _dbHelper.getHideNewMark(id);
}
Future<int?> _getSkipSecondStart(String? id) async {
return await _dbHelper.getSkipSecondsStart(id);
}
Future<int?> _getSkipSecondEnd(String id) async {
return await _dbHelper.getSkipSecondsEnd(id);
}
Future<void> _markListened(String? podcastId) async {
setState(() {
_markStatus = MarkStatus.start;
});
final episodes = await _dbHelper.getRssItem(podcastId, -1,
reverse: true, hideListened: true);
for (var episode in episodes) {
final history = PlayHistory(episode.title, episode.enclosureUrl, 0, 1);
await _dbHelper.saveHistory(history);
}
if (mounted) {
setState(() {
_markStatus = MarkStatus.complete;
});
}
}
Future<void> _refreshArtWork() async {
setState(() => _coverStatus = RefreshCoverStatus.start);
var options = BaseOptions(
connectTimeout: 30000,
receiveTimeout: 90000,
);
var dir = await getApplicationDocumentsDirectory();
var filePath = "${dir.path}/${widget.podcastLocal!.id}.png";
var dio = Dio(options);
String? imageUrl;
try {
var response = await dio.get(widget.podcastLocal!.rssUrl);
try {
var p = RssFeed.parse(response.data);
imageUrl = p.itunes!.image!.href ?? p.image!.url;
} catch (e) {
developer.log(e.toString());
if (mounted) setState(() => _coverStatus = RefreshCoverStatus.error);
}
} catch (e) {
developer.log(e.toString());
if (mounted) setState(() => _coverStatus = RefreshCoverStatus.error);
}
if (imageUrl != null && imageUrl.contains('http')) {
try {
img.Image thumbnail;
var imageResponse = await dio.get<List<int>>(imageUrl,
options: Options(
responseType: ResponseType.bytes,
));
var image = img.decodeImage(imageResponse.data!)!;
thumbnail = img.copyResize(image, width: 300);
File(filePath)..writeAsBytesSync(img.encodePng(thumbnail));
_dbHelper.updatePodcastImage(
id: widget.podcastLocal!.id, filePath: filePath);
print('saved image');
if (mounted) {
setState(() => _coverStatus = RefreshCoverStatus.complete);
}
} catch (e) {
developer.log(e.toString());
if (mounted) setState(() => _coverStatus = RefreshCoverStatus.error);
}
} else if (_coverStatus == RefreshCoverStatus.start && mounted) {
setState(() => _coverStatus = RefreshCoverStatus.complete);
}
}
Future<bool> _checkPermmison() async {
var permission = await Permission.storage.status;
if (permission != PermissionStatus.granted) {
var permissions = await [Permission.storage].request();
if (permissions[Permission.storage] == PermissionStatus.granted) {
return true;
} else {
return false;
}
} else {
return true;
}
}
Widget _getRefreshStatusIcon(RefreshCoverStatus status) {
switch (status) {
case RefreshCoverStatus.none:
return Center();
case RefreshCoverStatus.start:
return CircularProgressIndicator(strokeWidth: 2);
case RefreshCoverStatus.complete:
return Icon(Icons.done);
case RefreshCoverStatus.error:
return Icon(Icons.refresh, color: Colors.red);
default:
return Center();
}
}
} }
class _TimePicker extends StatelessWidget { class _TimePicker extends StatelessWidget {
@ -477,15 +471,16 @@ class _TimePicker extends StatelessWidget {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
FlatButton( TextButton(
onPressed: onCancel, onPressed: onCancel,
child: Text( child: Text(
s.cancel, s.cancel,
style: TextStyle(color: Colors.grey[600]), style: TextStyle(color: Colors.grey[600]),
), ),
), ),
FlatButton( TextButton(
splashColor: context.accentColor.withAlpha(70), style: TextButton.styleFrom(
surfaceTintColor: context.priamryContainer),
onPressed: onConfirm, onPressed: onConfirm,
child: Text( child: Text(
s.confirm, s.confirm,

View File

@ -1,9 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_html/flutter_html.dart'; import 'package:flutter_html/flutter_html.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -20,78 +18,6 @@ import 'podcast_detail.dart';
import 'podcast_manage.dart'; import 'podcast_manage.dart';
import 'podcast_settings.dart'; import 'podcast_settings.dart';
class AboutPodcast extends StatefulWidget {
final PodcastLocal? podcastLocal;
AboutPodcast({this.podcastLocal, Key? key}) : super(key: key);
@override
_AboutPodcastState createState() => _AboutPodcastState();
}
class _AboutPodcastState extends State<AboutPodcast> {
String? _description;
late bool _load;
void getDescription(String? id) async {
var dbHelper = DBHelper();
var description = await dbHelper.getFeedDescription(id);
_description = description;
setState(() {
_load = true;
});
}
@override
void initState() {
super.initState();
_load = false;
getDescription(widget.podcastLocal!.id);
}
@override
Widget build(BuildContext context) {
var _groupList = Provider.of<GroupList>(context, listen: false);
final s = context.s;
return AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
titlePadding: EdgeInsets.only(
top: 20, left: 20, right: context.width / 3, bottom: 20),
actions: <Widget>[
FlatButton(
splashColor: context.accentColor.withAlpha(70),
padding: EdgeInsets.all(10.0),
onPressed: () {
_groupList.removePodcast(widget.podcastLocal!);
Navigator.of(context).pop();
},
textColor: Colors.red,
child: Text(
s.remove,
),
),
],
title: Text(widget.podcastLocal!.title!),
content: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
!_load
? Center()
: _description != null
? Html(data: _description)
: Center(),
if (widget.podcastLocal!.author != null)
Text(widget.podcastLocal!.author!,
style: TextStyle(color: Colors.blue))
],
),
),
);
}
}
class PodcastList extends StatefulWidget { class PodcastList extends StatefulWidget {
@override @override
_PodcastListState createState() => _PodcastListState(); _PodcastListState createState() => _PodcastListState();
@ -108,32 +34,34 @@ class _PodcastListState extends State<PodcastList> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final width = context.width; final width = context.width;
return AnnotatedRegion<SystemUiOverlayStyle>( return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle( value: context.overlay,
statusBarIconBrightness: Theme.of(context).accentColorBrightness, child: SafeArea(
systemNavigationBarColor: context.primaryColor, child: Scaffold(
systemNavigationBarIconBrightness: backgroundColor: context.background,
Theme.of(context).accentColorBrightness, appBar: AppBar(
), backgroundColor: context.background,
child: Scaffold( title: Text(context.s.podcast(2)),
appBar: AppBar( leading: CustomBackButton(),
title: Text(context.s.podcast(2)), actions: [
leading: CustomBackButton(), Selector<SettingState, bool?>(
actions: [
Selector<SettingState, bool?>(
selector: (_, setting) => setting.openAllPodcastDefalt, selector: (_, setting) => setting.openAllPodcastDefalt,
builder: (_, data, __) { builder: (_, data, __) {
return data! if (!data!) return Center();
? IconButton( return IconButton(
splashRadius: 20, splashRadius: 20,
icon: Icon(Icons.all_out), icon: Icon(Icons.all_out),
onPressed: () => Navigator.push( onPressed: () => Navigator.push(
context, ScaleRoute(page: PodcastManage()))) context,
: Center(); ScaleRoute(
}) page: PodcastManage(),
], ),
), ),
body: SafeArea( );
child: Container( },
)
],
),
body: Container(
color: context.primaryColor, color: context.primaryColor,
child: FutureBuilder<List<PodcastLocal>>( child: FutureBuilder<List<PodcastLocal>>(
future: _getPodcastLocal(), future: _getPodcastLocal(),
@ -212,9 +140,10 @@ class _PodcastListState extends State<PodcastList> {
} }
return Center( return Center(
child: SizedBox( child: SizedBox(
height: 20, height: 20,
width: 20, width: 20,
child: CircularProgressIndicator()), child: CircularProgressIndicator(),
),
); );
}, },
), ),

View File

@ -45,7 +45,7 @@ class _DataBackupState extends State<DataBackup> {
systemNavigationBarIconBrightness: context.brightness, systemNavigationBarIconBrightness: context.brightness,
), ),
child: Scaffold( child: Scaffold(
backgroundColor: context.onPrimary, backgroundColor: context.background,
appBar: AppBar( appBar: AppBar(
elevation: 0, elevation: 0,
title: Text(s.settingsBackup), title: Text(s.settingsBackup),

View File

@ -44,7 +44,7 @@ class _PlayedHistoryState extends State<PlayedHistory>
return AnnotatedRegion<SystemUiOverlayStyle>( return AnnotatedRegion<SystemUiOverlayStyle>(
value: context.overlay, value: context.overlay,
child: Scaffold( child: Scaffold(
backgroundColor: context.onPrimary, backgroundColor: context.background,
body: SafeArea( body: SafeArea(
child: NestedScrollView( child: NestedScrollView(
headerSliverBuilder: (context, innerBoxScrolled) { headerSliverBuilder: (context, innerBoxScrolled) {

View File

@ -28,7 +28,7 @@ class _LayoutSettingState extends State<LayoutSetting> {
return AnnotatedRegion<SystemUiOverlayStyle>( return AnnotatedRegion<SystemUiOverlayStyle>(
value: context.overlay, value: context.overlay,
child: Scaffold( child: Scaffold(
backgroundColor: context.onPrimary, backgroundColor: context.background,
appBar: AppBar( appBar: AppBar(
title: Text(s.settingsLayout), title: Text(s.settingsLayout),
leading: CustomBackButton(), leading: CustomBackButton(),

View File

@ -46,7 +46,7 @@ class _PlaySettingState extends State<PlaySetting> {
return AnnotatedRegion<SystemUiOverlayStyle>( return AnnotatedRegion<SystemUiOverlayStyle>(
value: context.overlay, value: context.overlay,
child: Scaffold( child: Scaffold(
backgroundColor: context.onPrimary, backgroundColor: context.background,
appBar: AppBar( appBar: AppBar(
title: Text(s.play), title: Text(s.play),
leading: CustomBackButton(), leading: CustomBackButton(),

View File

@ -72,16 +72,16 @@ class _SettingsState extends State<Settings> {
return AnnotatedRegion<SystemUiOverlayStyle>( return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle( value: SystemUiOverlayStyle(
statusBarIconBrightness: context.brightness, statusBarIconBrightness: context.brightness,
systemNavigationBarColor: context.onPrimary, systemNavigationBarColor: context.background,
systemNavigationBarIconBrightness: context.iconBrightness, systemNavigationBarIconBrightness: context.iconBrightness,
), ),
child: Scaffold( child: Scaffold(
backgroundColor: context.onPrimary, backgroundColor: context.background,
appBar: AppBar( appBar: AppBar(
title: Text(s.settings), title: Text(s.settings),
leading: CustomBackButton(), leading: CustomBackButton(),
elevation: _showTitle ? 1 : 0, elevation: _showTitle ? 1 : 0,
backgroundColor: context.onPrimary, backgroundColor: context.background,
), ),
body: SingleChildScrollView( body: SingleChildScrollView(
scrollDirection: Axis.vertical, scrollDirection: Axis.vertical,

View File

@ -46,7 +46,7 @@ class _StorageSettingState extends State<StorageSetting>
return AnnotatedRegion<SystemUiOverlayStyle>( return AnnotatedRegion<SystemUiOverlayStyle>(
value: context.overlay, value: context.overlay,
child: Scaffold( child: Scaffold(
backgroundColor: context.onPrimary, backgroundColor: context.background,
appBar: AppBar( appBar: AppBar(
title: Text(s.settingStorage), title: Text(s.settingStorage),
leading: CustomBackButton(), leading: CustomBackButton(),

View File

@ -11,16 +11,16 @@ class ThemeSetting extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final s = context.s; final s = context.s;
var settings = Provider.of<SettingState>(context, listen: false); final settings = Provider.of<SettingState>(context, listen: false);
return AnnotatedRegion<SystemUiOverlayStyle>( return AnnotatedRegion<SystemUiOverlayStyle>(
value: context.overlay, value: context.overlay,
child: Scaffold( child: Scaffold(
backgroundColor: context.onPrimary, backgroundColor: context.background,
appBar: AppBar( appBar: AppBar(
title: Text(s.settingsAppearance), title: Text(s.settingsAppearance),
leading: CustomBackButton(), leading: CustomBackButton(),
elevation: 0, elevation: 0,
backgroundColor: context.onPrimary, backgroundColor: context.background,
), ),
body: Column( body: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
@ -52,7 +52,7 @@ class ThemeSetting extends StatelessWidget {
pageBuilder: (context, animaiton, secondaryAnimation) => pageBuilder: (context, animaiton, secondaryAnimation) =>
AnnotatedRegion<SystemUiOverlayStyle>( AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle( value: SystemUiOverlayStyle(
statusBarIconBrightness: Brightness.light, statusBarColor: Colors.transparent,
systemNavigationBarColor: systemNavigationBarColor:
Theme.of(context).brightness == Brightness.light Theme.of(context).brightness == Brightness.light
? Color.fromRGBO(113, 113, 113, 1) ? Color.fromRGBO(113, 113, 113, 1)
@ -151,13 +151,18 @@ class ThemeSetting extends StatelessWidget {
ListTile( ListTile(
onTap: () => generalDialog( onTap: () => generalDialog(
context, context,
title: Text.rich(TextSpan(text: s.chooseA, children: [ title: Text.rich(
TextSpan( TextSpan(
text: ' ${s.color}', text: s.chooseA,
style: TextStyle( children: [
fontWeight: FontWeight.bold, TextSpan(
color: context.accentColor)) text: ' ${s.color}',
])), style: TextStyle(
fontWeight: FontWeight.bold,
color: context.accentColor))
],
),
),
content: _ColorPicker( content: _ColorPicker(
onColorChanged: (value) => settings.setAccentColor = value, onColorChanged: (value) => settings.setAccentColor = value,
), ),
@ -253,29 +258,6 @@ class __ColorPickerState extends State<_ColorPicker>
}); });
} }
Widget _colorCircle(Color color) => Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.all(Radius.circular(10)),
onTap: () => widget.onColorChanged!(color),
child: Container(
decoration: BoxDecoration(
border: color == context.accentColor
? Border.all(color: Colors.grey[400]!, width: 4)
: null,
borderRadius: BorderRadius.all(Radius.circular(10)),
color: color),
),
),
);
List<Widget> _accentList(MaterialAccentColor color) => [
_colorCircle(color.shade100),
_colorCircle(color.shade200),
_colorCircle(color.shade400),
_colorCircle(color.shade700)
];
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
@ -397,4 +379,27 @@ class __ColorPickerState extends State<_ColorPicker>
), ),
); );
} }
Widget _colorCircle(Color color) => Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.all(Radius.circular(10)),
onTap: () => widget.onColorChanged!(color),
child: Container(
decoration: BoxDecoration(
border: color == context.accentColor
? Border.all(color: Colors.grey[400]!, width: 4)
: null,
borderRadius: BorderRadius.all(Radius.circular(10)),
color: color),
),
),
);
List<Widget> _accentList(MaterialAccentColor color) => [
_colorCircle(color.shade100),
_colorCircle(color.shade200),
_colorCircle(color.shade400),
_colorCircle(color.shade700)
];
} }

View File

@ -32,9 +32,9 @@ extension ContextExtension on BuildContext {
double get paddingTop => MediaQuery.of(this).padding.top; double get paddingTop => MediaQuery.of(this).padding.top;
TextTheme get textTheme => Theme.of(this).textTheme; TextTheme get textTheme => Theme.of(this).textTheme;
SystemUiOverlayStyle get overlay => SystemUiOverlayStyle( SystemUiOverlayStyle get overlay => SystemUiOverlayStyle(
statusBarColor: onPrimary, statusBarColor: background,
statusBarIconBrightness: iconBrightness, statusBarIconBrightness: iconBrightness,
systemNavigationBarColor: onPrimary, systemNavigationBarColor: background,
systemNavigationBarIconBrightness: iconBrightness, systemNavigationBarIconBrightness: iconBrightness,
); );
S get s => S.of(this)!; S get s => S.of(this)!;

View File

@ -72,11 +72,11 @@ class EpisodeGrid extends StatelessWidget {
Future<Tuple5<int, bool, bool, bool, List<int>>> _initData( Future<Tuple5<int, bool, bool, bool, List<int>>> _initData(
EpisodeBrief episode) async { EpisodeBrief episode) async {
var menuList = await _getEpisodeMenu(); final menuList = await _getEpisodeMenu();
var tapToOpen = await _getTapToOpenPopupMenu(); final tapToOpen = await _getTapToOpenPopupMenu();
var listened = await _isListened(episode); final listened = await _isListened(episode);
var liked = await _isLiked(episode); final liked = await _isLiked(episode);
var downloaded = await _isDownloaded(episode); final downloaded = await _isDownloaded(episode);
return Tuple5(listened, liked, downloaded, tapToOpen, menuList); return Tuple5(listened, liked, downloaded, tapToOpen, menuList);
} }
@ -85,8 +85,8 @@ class EpisodeGrid extends StatelessWidget {
} }
Future<List<int>> _getEpisodeMenu() async { Future<List<int>> _getEpisodeMenu() async {
var popupMenuStorage = KeyValueStorage(episodePopupMenuKey); final popupMenuStorage = KeyValueStorage(episodePopupMenuKey);
var list = await popupMenuStorage.getMenu(); final list = await popupMenuStorage.getMenu();
return list; return list;
} }
@ -95,8 +95,8 @@ class EpisodeGrid extends StatelessWidget {
} }
Future<bool> _getTapToOpenPopupMenu() async { Future<bool> _getTapToOpenPopupMenu() async {
var tapToOpenPopupMenuStorage = KeyValueStorage(tapToOpenPopupMenuKey); final tapToOpenPopupMenuStorage = KeyValueStorage(tapToOpenPopupMenuKey);
var boo = await tapToOpenPopupMenuStorage.getBool(defaultValue: false); final boo = await tapToOpenPopupMenuStorage.getBool(defaultValue: false);
return boo; return boo;
} }
@ -307,102 +307,131 @@ class EpisodeGrid extends StatelessWidget {
Color? color, Color? color,
bool? isLiked, bool? isLiked,
bool? isDownloaded, bool? isDownloaded,
Color? cardColor,
required int isListened,
bool? boo}) { bool? boo}) {
var width = context.width; final width = context.width;
if (layout == Layout.one) { if (layout == Layout.one) {
return _layoutOneCard(context, return _layoutOneCard(context,
index: index!, index: index!,
color: color, color: color,
isLiked: isLiked!, isLiked: isLiked!,
cardColor: cardColor,
isListened: isListened,
isDownloaded: isDownloaded, isDownloaded: isDownloaded,
boo: boo!); boo: boo!);
} }
return Padding( return Container(
padding: const EdgeInsets.all(8.0), decoration: BoxDecoration(
child: Column( color: cardColor,
mainAxisAlignment: MainAxisAlignment.start, borderRadius: BorderRadius.circular(15.0),
children: <Widget>[ ),
Expanded( clipBehavior: Clip.hardEdge,
flex: layout == Layout.one ? 1 : 2, child: Stack(
child: Row( alignment: AlignmentDirectional.bottomCenter,
mainAxisAlignment: MainAxisAlignment.start, children: [
crossAxisAlignment: CrossAxisAlignment.center, if (isListened > 0)
children: <Widget>[ Container(
layout != Layout.one height: 4,
? _circleImage(context, color: context.accentColor,
episode: episodes![index!], color: color, boo: boo!)
: _pubDate(context,
episode: episodes![index!], color: color),
Spacer(),
_isNewIndicator(episodes![index]),
_downloadIndicater(context,
episode: episodes![index], isDownloaded: isDownloaded),
_numberIndicater(context, index: index, color: color)
],
), ),
), Padding(
Expanded( padding: const EdgeInsets.all(8.0),
flex: layout == Layout.one ? 3 : 5, child: Column(
child: layout != Layout.one mainAxisAlignment: MainAxisAlignment.start,
? _title(episodes![index]) mainAxisSize: MainAxisSize.min,
: Row( children: <Widget>[
Expanded(
flex: layout == Layout.one ? 1 : 2,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: <Widget>[
_circleImage(context, layout != Layout.one
episode: episodes![index], color: color, boo: boo!), ? _circleImage(context,
SizedBox( episode: episodes![index!],
width: 5, color: color,
), boo: boo!)
Expanded(child: _title(episodes![index])) : _pubDate(context,
episode: episodes![index!], color: color),
Spacer(),
_isNewIndicator(episodes![index]),
_downloadIndicater(context,
episode: episodes![index],
isDownloaded: isDownloaded),
_numberIndicater(context, index: index, color: color)
],
),
),
Expanded(
flex: layout == Layout.one ? 3 : 5,
child: layout != Layout.one
? _title(episodes![index])
: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_circleImage(context,
episode: episodes![index],
color: color,
boo: boo!),
SizedBox(
width: 5,
),
Expanded(child: _title(episodes![index]))
],
),
),
Expanded(
flex: 1,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
if (layout != Layout.one)
_pubDate(context,
episode: episodes![index], color: color),
Spacer(),
if (layout != Layout.three &&
episodes![index].duration != 0)
Align(
alignment: Alignment.center,
child: Text(
episodes![index].duration!.toTime,
style: TextStyle(fontSize: width / 35),
),
),
if (episodes![index].duration != 0 &&
episodes![index].enclosureLength != null &&
episodes![index].enclosureLength != 0 &&
layout != Layout.three)
Text(
'|',
style: TextStyle(
fontSize: width / 35,
),
),
if (layout != Layout.three &&
episodes![index].enclosureLength != null &&
episodes![index].enclosureLength != 0)
Align(
alignment: Alignment.center,
child: Text(
'${episodes![index].enclosureLength! ~/ 1000000}MB',
style: TextStyle(fontSize: width / 35),
),
),
Padding(
padding: EdgeInsets.all(1),
),
if ((showFavorite || layout != Layout.three) && isLiked!)
Icon(
Icons.favorite,
color: Colors.red,
size: width / 35,
)
], ],
), ),
),
Expanded(
flex: 1,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
if (layout != Layout.one)
_pubDate(context, episode: episodes![index], color: color),
Spacer(),
if (layout != Layout.three && episodes![index].duration != 0)
Align(
alignment: Alignment.center,
child: Text(
episodes![index].duration!.toTime,
style: TextStyle(fontSize: width / 35),
),
),
if (episodes![index].duration != 0 &&
episodes![index].enclosureLength != null &&
episodes![index].enclosureLength != 0 &&
layout != Layout.three)
Text(
'|',
style: TextStyle(
fontSize: width / 35,
),
),
if (layout != Layout.three &&
episodes![index].enclosureLength != null &&
episodes![index].enclosureLength != 0)
Align(
alignment: Alignment.center,
child: Text(
'${episodes![index].enclosureLength! ~/ 1000000}MB',
style: TextStyle(fontSize: width / 35),
),
),
Padding(
padding: EdgeInsets.all(1),
), ),
if ((showFavorite || layout != Layout.three) && isLiked!)
Icon(
Icons.favorite,
color: Colors.red,
size: width / 35,
)
], ],
), ),
), ),
@ -416,106 +445,127 @@ class EpisodeGrid extends StatelessWidget {
Color? color, Color? color,
required bool isLiked, required bool isLiked,
bool? isDownloaded, bool? isDownloaded,
Color? cardColor,
required int isListened,
required bool boo}) { required bool boo}) {
var width = context.width; var width = context.width;
return Padding( return Container(
padding: EdgeInsets.symmetric(vertical: 8), decoration: BoxDecoration(
child: Row( color: cardColor,
mainAxisAlignment: MainAxisAlignment.start, borderRadius: BorderRadius.circular(15.0),
mainAxisSize: MainAxisSize.min, ),
crossAxisAlignment: CrossAxisAlignment.center, clipBehavior: Clip.hardEdge,
child: Stack(
alignment: AlignmentDirectional.bottomCenter,
children: [ children: [
Expanded( if (isListened > 0)
flex: 1, Container(
child: Center( height: 4,
child: _circleImage(context, color: context.accentColor,
episode: episodes![index],
color: color,
boo: boo,
radius: context.width / 8),
), ),
), Padding(
Expanded( padding: const EdgeInsets.all(8.0),
flex: 4, child: Row(
child: Column( mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Expanded( Expanded(
flex: 1, flex: 1,
child: Row( child: Center(
mainAxisAlignment: MainAxisAlignment.start, child: _circleImage(context,
crossAxisAlignment: CrossAxisAlignment.center, episode: episodes![index],
children: <Widget>[ color: color,
Expanded( boo: boo,
child: Text(episodes![index].feedTitle!, radius: context.width / 8),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight: FontWeight.bold, color: color)),
),
_isNewIndicator(episodes![index]),
_downloadIndicater(context,
episode: episodes![index],
isDownloaded: isDownloaded),
_numberIndicater(context, index: index, color: color)
],
), ),
), ),
Expanded( Expanded(
flex: 2, flex: 4,
child: Align( child: Column(
alignment: Alignment.topLeft, mainAxisSize: MainAxisSize.min,
child: _title(episodes![index]))), mainAxisAlignment: MainAxisAlignment.center,
Expanded( children: [
flex: 1, Expanded(
child: Row( flex: 1,
crossAxisAlignment: CrossAxisAlignment.center, child: Row(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[ crossAxisAlignment: CrossAxisAlignment.center,
if (episodes![index].duration != 0) children: <Widget>[
Align( Expanded(
alignment: Alignment.center, child: Text(episodes![index].feedTitle!,
child: Text( maxLines: 1,
episodes![index].duration!.toTime, overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: width / 35), style: TextStyle(
fontWeight: FontWeight.bold,
color: color)),
), ),
), _isNewIndicator(episodes![index]),
if (episodes![index].duration != 0 && _downloadIndicater(context,
episodes![index].enclosureLength != null && episode: episodes![index],
episodes![index].enclosureLength != 0 && isDownloaded: isDownloaded),
layout != Layout.three) _numberIndicater(context,
Text( index: index, color: color)
'|', ],
style: TextStyle( ),
fontSize: width / 35, ),
), Expanded(
), flex: 2,
if (episodes![index].enclosureLength != null && child: Align(
episodes![index].enclosureLength != 0) alignment: Alignment.topLeft,
Align( child: _title(episodes![index]))),
alignment: Alignment.center, Expanded(
child: Text( flex: 1,
'${episodes![index].enclosureLength! ~/ 1000000}MB', child: Row(
style: TextStyle(fontSize: width / 35), crossAxisAlignment: CrossAxisAlignment.center,
), mainAxisAlignment: MainAxisAlignment.start,
), children: <Widget>[
SizedBox(width: 4), if (episodes![index].duration != 0)
if (isLiked) Align(
Icon( alignment: Alignment.center,
Icons.favorite, child: Text(
color: Colors.red, episodes![index].duration!.toTime,
size: width / 35, style: TextStyle(fontSize: width / 35),
), ),
Spacer(), ),
_pubDate(context, if (episodes![index].duration != 0 &&
episode: episodes![index], color: color), episodes![index].enclosureLength != null &&
]), episodes![index].enclosureLength != 0 &&
) layout != Layout.three)
Text(
'|',
style: TextStyle(
fontSize: width / 35,
),
),
if (episodes![index].enclosureLength != null &&
episodes![index].enclosureLength != 0)
Align(
alignment: Alignment.center,
child: Text(
'${episodes![index].enclosureLength! ~/ 1000000}MB',
style: TextStyle(fontSize: width / 35),
),
),
SizedBox(width: 4),
if (isLiked)
Icon(
Icons.favorite,
color: Colors.red,
size: width / 35,
),
Spacer(),
_pubDate(context,
episode: episodes![index], color: color),
]),
)
],
),
),
SizedBox(width: 8)
], ],
), ),
), ),
SizedBox(width: 8)
], ],
), ),
); );
@ -533,7 +583,7 @@ class EpisodeGrid extends StatelessWidget {
final s = context.s; final s = context.s;
return SliverPadding( return SliverPadding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
top: 10.0, bottom: 5.0, left: 15.0, right: 15.0), top: 10.0, bottom: 5.0, left: 10.0, right: 10.0),
sliver: LiveSliverGrid.options( sliver: LiveSliverGrid.options(
controller: scrollController, controller: scrollController,
options: options, options: options,
@ -549,8 +599,8 @@ class EpisodeGrid extends StatelessWidget {
: layout == Layout.two : layout == Layout.two
? 2 ? 2
: 1, : 1,
mainAxisSpacing: 6.0, mainAxisSpacing: 10.0,
crossAxisSpacing: 6.0, crossAxisSpacing: 10.0,
), ),
itemBuilder: (context, index, animation) { itemBuilder: (context, index, animation) {
final c = episodes![index].backgroudColor(context); final c = episodes![index].backgroudColor(context);
@ -576,28 +626,31 @@ class EpisodeGrid extends StatelessWidget {
future: _initData(episodes![index]), future: _initData(episodes![index]),
initialData: Tuple5(0, false, false, false, []), initialData: Tuple5(0, false, false, false, []),
builder: (context, snapshot) { builder: (context, snapshot) {
var isListened = snapshot.data!.item1; final isListened = snapshot.data!.item1;
var isLiked = snapshot.data!.item2; final isLiked = snapshot.data!.item2;
var isDownloaded = snapshot.data!.item3; final isDownloaded = snapshot.data!.item3;
var tapToOpen = snapshot.data!.item4; final tapToOpen = snapshot.data!.item4;
var menuList = snapshot.data!.item5; final menuList = snapshot.data!.item5;
return Container( return Container(
decoration: BoxDecoration( // decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.0)), // borderRadius: BorderRadius.all(
color: isListened > 0 // Radius.circular(15.0),
? context.brightness == Brightness.light // ),
? Colors.grey[200] // color: isListened > 0
: Color.fromRGBO(50, 50, 50, 1) // ? context.brightness == Brightness.light
: context.background, // ? Colors.grey[200]
boxShadow: [ // : Color.fromRGBO(50, 50, 50, 1)
BoxShadow( // : context.priamryContainer,
color: context.brightness == Brightness.light // ),
? context.primaryColor // boxShadow: [
: Color.fromRGBO(40, 40, 40, 1), // BoxShadow(
blurRadius: 0.5, // color: context.brightness == Brightness.light
spreadRadius: 0.5, // ? context.primaryColor
), // : Color.fromRGBO(40, 40, 40, 1),
]), // blurRadius: 0.5,
// spreadRadius: 0.5,
// ),
// ]),
alignment: Alignment.center, alignment: Alignment.center,
child: multiSelect! child: multiSelect!
? Material( ? Material(
@ -616,7 +669,8 @@ class EpisodeGrid extends StatelessWidget {
}, },
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0), borderRadius: BorderRadius.circular(15.0),
color: episodes![index].cardColor(context),
border: Border.all( border: Border.all(
color: selectedList! color: selectedList!
.contains(episodes![index]) .contains(episodes![index])
@ -632,6 +686,7 @@ class EpisodeGrid extends StatelessWidget {
index: index, index: index,
isLiked: isLiked, isLiked: isLiked,
isDownloaded: isDownloaded, isDownloaded: isDownloaded,
isListened: isListened,
color: c, color: c,
boo: boo), boo: boo),
), ),
@ -639,7 +694,8 @@ class EpisodeGrid extends StatelessWidget {
) )
: Container( : Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0), color: episodes![index].cardColor(context),
borderRadius: BorderRadius.circular(20.0),
border: Border.all( border: Border.all(
color: context.brightness == Brightness.light color: context.brightness == Brightness.light
? context.primaryColor ? context.primaryColor
@ -652,7 +708,7 @@ class EpisodeGrid extends StatelessWidget {
menuItemExtent: 45, menuItemExtent: 45,
menuBoxDecoration: BoxDecoration( menuBoxDecoration: BoxDecoration(
color: Colors.transparent, color: Colors.transparent,
borderRadius: BorderRadius.circular(15.0)), borderRadius: BorderRadius.circular(20.0)),
duration: Duration(milliseconds: 100), duration: Duration(milliseconds: 100),
tapMode: tapToOpen tapMode: tapToOpen
? TapMode.onTap ? TapMode.onTap
@ -666,10 +722,7 @@ class EpisodeGrid extends StatelessWidget {
menuOffset: 6, menuOffset: 6,
menuItems: <FocusedMenuItem>[ menuItems: <FocusedMenuItem>[
FocusedMenuItem( FocusedMenuItem(
backgroundColor: backgroundColor: context.priamryContainer,
context.brightness == Brightness.light
? context.primaryColor
: context.dialogBackgroundColor,
title: Text( title: Text(
data.item1 != episodes![index] || data.item1 != episodes![index] ||
!data.item4 !data.item4
@ -687,10 +740,8 @@ class EpisodeGrid extends StatelessWidget {
}), }),
if (menuList.contains(1)) if (menuList.contains(1))
FocusedMenuItem( FocusedMenuItem(
backgroundColor: context.brightness == backgroundColor:
Brightness.light context.priamryContainer,
? context.primaryColor
: context.dialogBackgroundColor,
title: data.item2.contains( title: data.item2.contains(
episodes![index].enclosureUrl) episodes![index].enclosureUrl)
? Text(s.remove) ? Text(s.remove)
@ -719,10 +770,8 @@ class EpisodeGrid extends StatelessWidget {
}), }),
if (menuList.contains(2)) if (menuList.contains(2))
FocusedMenuItem( FocusedMenuItem(
backgroundColor: context.brightness == backgroundColor:
Brightness.light context.priamryContainer,
? context.primaryColor
: context.dialogBackgroundColor,
title: isLiked title: isLiked
? Text(s.unlike) ? Text(s.unlike)
: Text(s.like), : Text(s.like),
@ -749,10 +798,8 @@ class EpisodeGrid extends StatelessWidget {
}), }),
if (menuList.contains(3)) if (menuList.contains(3))
FocusedMenuItem( FocusedMenuItem(
backgroundColor: context.brightness == backgroundColor:
Brightness.light context.priamryContainer,
? context.primaryColor
: context.dialogBackgroundColor,
title: isListened > 0 title: isListened > 0
? Text(s.markNotListened, ? Text(s.markNotListened,
style: TextStyle( style: TextStyle(
@ -792,10 +839,8 @@ class EpisodeGrid extends StatelessWidget {
}), }),
if (menuList.contains(4)) if (menuList.contains(4))
FocusedMenuItem( FocusedMenuItem(
backgroundColor: context.brightness == backgroundColor:
Brightness.light context.priamryContainer,
? context.primaryColor
: context.dialogBackgroundColor,
title: isDownloaded title: isDownloaded
? Text(s.downloaded, ? Text(s.downloaded,
style: TextStyle( style: TextStyle(
@ -812,30 +857,33 @@ class EpisodeGrid extends StatelessWidget {
}), }),
if (menuList.contains(5)) if (menuList.contains(5))
FocusedMenuItem( FocusedMenuItem(
backgroundColor: context.brightness == backgroundColor: context.priamryContainer,
Brightness.light title: Text(s.playNext),
? context.primaryColor trailingIcon: Icon(
: context.dialogBackgroundColor, LineIcons.lightningBolt,
title: Text(s.playNext), color: Colors.amber,
trailingIcon: Icon( ),
LineIcons.lightningBolt, onPressed: () {
color: Colors.amber, audio.moveToTop(episodes![index]);
), Fluttertoast.showToast(
onPressed: () { msg: s.playNextDes,
audio.moveToTop(episodes![index]); gravity: ToastGravity.BOTTOM,
Fluttertoast.showToast( );
msg: s.playNextDes, },
gravity: ToastGravity.BOTTOM, ),
);
}),
], ],
onPressed: action, onPressed: action,
child: _episodeCard(context, child: _episodeCard(
index: index, context,
isLiked: isLiked, index: index,
isDownloaded: isDownloaded, isLiked: isLiked,
color: c, isListened: isListened,
boo: boo), isDownloaded: isDownloaded,
cardColor:
episodes![index].cardColor(context),
color: c,
boo: boo,
),
), ),
), ),
); );