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

View File

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

View File

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

View File

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

View File

@ -27,17 +27,6 @@ class DiscoveryPageState extends State<DiscoveryPage> {
final List<OnlinePodcast> _podcastList = [];
Future? _searchTopPodcast;
Future? _getIfHideDiscovery;
Future<List<String?>?> _getSearchHistory() {
final storage = KeyValueStorage(searchHistoryKey);
final history = storage.getStringList();
return history;
}
void backToHome() {
setState(() {
_selectedGenre = null;
});
}
@override
void initState() {
@ -46,95 +35,257 @@ class DiscoveryPageState extends State<DiscoveryPage> {
_getIfHideDiscovery = _getHideDiscovery();
}
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,
@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 SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 80,
height: context.textTheme.bodyText1!.fontSize,
decoration: BoxDecoration(
color: context.primaryColorDark,
borderRadius: BorderRadius.circular(4)),
_historyList(),
SizedBox(
height: 150,
child: Center(
child: Icon(
Icons.search,
size: 80,
color: Colors.grey[400],
),
),
),
SizedBox(height: 10),
Container(
width: 40,
height: context.textTheme.bodyText1!.fontSize,
decoration: BoxDecoration(
color: context.primaryColorDark,
borderRadius: BorderRadius.circular(4)),
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]),
),
),
),
],
),
),
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],
);
} 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,
),
),
)
],
),
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?>?>(
future: _getSearchHistory(),
initialData: [],
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
final history = snapshot.data!;
return Wrap(
direction: Axis.horizontal,
children: history
.map<Widget>((e) => Padding(
future: _getSearchHistory(),
initialData: [],
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
final history = snapshot.data!;
return Wrap(
direction: Axis.horizontal,
children: history
.map<Widget>(
(e) => Padding(
padding: const EdgeInsets.fromLTRB(8, 2, 0, 0),
child: FlatButton.icon(
color: Colors.accents[history.indexOf(e)].withAlpha(70),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100.0),
child: TextButton.icon(
style: TextButton.styleFrom(
primary: Colors.accents[history.indexOf(e)],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100.0),
),
),
onPressed: () => widget.onTap!(e),
label: Text(e!),
@ -143,32 +294,32 @@ class DiscoveryPageState extends State<DiscoveryPage> {
size: 20,
),
),
))
.toList(),
);
}
return SizedBox(
height: 0,
);
});
),
)
.toList(),
);
}
return Center();
},
);
Widget _podcastCard(OnlinePodcast podcast, {VoidCallback? onTap}) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: context.primaryColor,
borderRadius: BorderRadius.circular(20),
color: context.background,
border:
Border.all(color: context.textColor.withOpacity(0.1), width: 1)),
width: 120,
margin: EdgeInsets.fromLTRB(10, 10, 0, 10),
width: 140,
margin: EdgeInsets.fromLTRB(20, 10, 0, 10),
child: Material(
color: Colors.transparent,
borderRadius: BorderRadius.circular(10),
borderRadius: BorderRadius.circular(20),
clipBehavior: Clip.hardEdge,
child: InkWell(
onTap: onTap,
child: Padding(
padding: EdgeInsets.all(4.0),
padding: EdgeInsets.all(8.0),
child: Column(
children: [
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 {
if (environment['apiKey'] == '') return [];
final searchEngine = ListenNotesSearch();
@ -222,167 +385,6 @@ class DiscoveryPageState extends State<DiscoveryPage> {
final storage = KeyValueStorage(hidePodcastDiscoveryKey);
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 {
@ -398,20 +400,6 @@ class __TopPodcastListState extends State<_TopPodcastList> {
Future? _searchFuture;
late bool _loading;
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
void initState() {
@ -462,12 +450,8 @@ class __TopPodcastListState extends State<_TopPodcastList> {
children: [
Padding(
padding: const EdgeInsets.only(top: 10.0, bottom: 20.0),
child: OutlinedButton(
style: OutlinedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(100))),
),
child: TextButton(
style: TextButton.styleFrom(),
// highlightedBorderColor: context.accentColor,
// splashColor: context.accentColor.withOpacity(0.5),
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,
receiveTimeout: 90000,
);
var response = await Dio(options).get(url);
final response = await Dio(options).get(url);
return RssFeed.parse(response.data);
} catch (e) {
rethrow;
@ -88,7 +88,10 @@ class MyHomePageDelegate extends SearchDelegate<int?> {
child: IconButton(
tooltip: context.s.back,
splashRadius: 20,
icon: Icon(_getIconData(Theme.of(context).platform)),
icon: Icon(
_getIconData(Theme.of(context).platform),
color: context.textColor,
),
onPressed: () {
close(context, 1);
},
@ -164,12 +167,10 @@ class MyHomePageDelegate extends SearchDelegate<int?> {
switch (_searchEngine) {
case SearchEngine.listenNotes:
return _ListenNotesSearch(query: query);
break;
case SearchEngine.podcastIndex:
return _PodcastIndexSearch(query: query);
default:
return Center();
break;
}
}
}
@ -217,14 +218,14 @@ class _RssResultState extends State<RssResult> {
@override
Widget build(BuildContext context) {
final s = context.s;
var items = widget.rssFeed!.items!;
final items = widget.rssFeed!.items!;
return DefaultTabController(
length: 2,
child: Column(
children: [
Container(
color: context.primaryColor,
height: 140,
height: 160,
child: Row(
children: [
Expanded(
@ -314,8 +315,12 @@ class _RssResultState extends State<RssResult> {
url!.launchUrl;
},
style: {
'html': Style(
padding: const EdgeInsets.symmetric(horizontal: 12),
),
'a': Style(
color: context.accentColor,
textDecoration: TextDecoration.none,
)
},
shrinkWrap: true,
@ -331,13 +336,9 @@ class _RssResultState extends State<RssResult> {
return Container(
padding: const EdgeInsets.only(top: 10.0, bottom: 20.0),
alignment: Alignment.center,
child: OutlinedButton(
style: OutlinedButton.styleFrom(
// highlightedBorderColor: context.accentColor,
child: TextButton(
style: TextButton.styleFrom(
onSurface: context.accentColor.withOpacity(0.5),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(100))),
),
child: Text(context.s.loadMore),
onPressed: () => setState(
@ -378,18 +379,12 @@ class __SearchPopupMenuState extends State<_SearchPopupMenu> {
_getSearchEngine();
}
Future<void> _getSearchEngine() async {
final storage = KeyValueStorage(searchEngineKey);
final index = await storage.getInt();
setState(() => _searchEngine = SearchEngine.values[index]);
widget.onSelected!(_searchEngine);
}
@override
Widget build(BuildContext context) {
return PopupMenuButton<SearchEngine>(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
elevation: 1,
color: context.priamryContainer,
icon: SizedBox(
height: 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 {
final String? query;
_ListenNotesSearch({this.query, Key? key}) : super(key: key);
final String query;
_ListenNotesSearch({required this.query, Key? key}) : super(key: key);
@override
__ListenNotesSearchState createState() => __ListenNotesSearchState();
@ -461,9 +463,9 @@ class __ListenNotesSearchState extends State<_ListenNotesSearch> {
_searchFuture = _getListenNotesList(widget.query, _nextOffset);
}
Future<void> _saveHistory(String? query) async {
Future<void> _saveHistory(String query) async {
final storage = KeyValueStorage(searchHistoryKey);
final history = await (storage.getStringList() as FutureOr<List<String?>>);
final history = await storage.getStringList();
if (!history.contains(query)) {
if (history.length >= 6) {
history.removeLast();
@ -474,7 +476,7 @@ class __ListenNotesSearchState extends State<_ListenNotesSearch> {
}
Future<List<OnlinePodcast>> _getListenNotesList(
String? searchText, int? nextOffset) async {
String searchText, int? nextOffset) async {
if (nextOffset == 0) _saveHistory(searchText);
final searchEngine = ListenNotesSearch();
var searchResult;
@ -544,12 +546,13 @@ class __ListenNotesSearchState extends State<_ListenNotesSearch> {
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.min,
children: [
OutlinedButton(
style: OutlinedButton.styleFrom(
TextButton(
style: TextButton.styleFrom(
side: BorderSide(color: context.accentColor),
onSurface: context.accentColor.withOpacity(0.5),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100)),
borderRadius: BorderRadius.circular(100),
),
),
child: _loading
? SizedBox(
@ -582,7 +585,9 @@ class __ListenNotesSearchState extends State<_ListenNotesSearch> {
child: Text(
'Powered by ListenNotes',
style: GoogleFonts.quicksand(
color: Colors.red, textStyle: TextStyle(fontSize: 15)),
color: Colors.red,
textStyle: TextStyle(fontSize: 15),
),
),
// Image(
// image: context.brightness == Brightness.light
@ -662,101 +667,102 @@ class __PodcastIndexSearchState extends State<_PodcastIndexSearch> {
return PodcastSlideup(
searchEngine: SearchEngine.podcastIndex,
child: FutureBuilder<List>(
future: _searchFuture.then((value) => value as List<dynamic>),
builder: (context, snapshot) {
if (!snapshot.hasData && widget.query != null) {
future: _searchFuture.then((value) => value as List<dynamic>),
builder: (context, snapshot) {
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(
padding: EdgeInsets.only(top: 200),
alignment: Alignment.topCenter,
child: Platform.isIOS
? CupertinoActivityIndicator()
: CircularProgressIndicator(),
child: Text('Network error.',
style: context.textTheme.headline6!
.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) {
return Container(
padding: EdgeInsets.only(top: 200),
alignment: Alignment.topCenter,
child: Text('Network error.',
style: context.textTheme.headline6!
.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)),
);
}
}
var content = snapshot.data!;
return CustomScrollView(
slivers: [
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return SearchResult(onlinePodcast: content[index]);
},
childCount: content.length,
),
}
var content = snapshot.data!;
return CustomScrollView(
slivers: [
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return SearchResult(onlinePodcast: content[index]);
},
childCount: content.length,
),
SliverToBoxAdapter(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.min,
children: [
OutlinedButton(
style: OutlinedButton.styleFrom(
side: BorderSide(color: context.accentColor),
onSurface: context.accentColor.withOpacity(0.5),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100)),
),
child: _loading
? SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
))
: Text(context.s.loadMore),
onPressed: () => _loading
? null
: setState(
() {
_loading = true;
_limit += 10;
_searchFuture = _getPodcatsIndexList(
widget.query!,
limit: _limit);
},
),
SliverToBoxAdapter(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.min,
children: [
TextButton(
style: TextButton.styleFrom(
side: BorderSide(color: context.accentColor),
onSurface: context.accentColor.withOpacity(0.5),
),
child: _loading
? SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
),
)
],
),
)
: Text(context.s.loadMore),
onPressed: () => _loading
? null
: setState(
() {
_loading = true;
_limit += 10;
_searchFuture = _getPodcatsIndexList(
widget.query!,
limit: _limit);
},
),
)
],
),
SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 10),
child: Center(
child: Text(
'Powered by PODCASTINDEX',
style: GoogleFonts.quicksand(
color: Colors.red,
textStyle: TextStyle(fontSize: 15)),
),
)
// Image(
// image: AssetImage('assets/podcastindex.png'),
// height: 15,
// ),
))
],
);
}),
),
SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 10),
child: Center(
child: Text(
'Powered by PODCASTINDEX',
style: GoogleFonts.quicksand(
color: Colors.red,
textStyle: TextStyle(fontSize: 15)),
),
)
// Image(
// 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),
alignment: Alignment.center,
child: SizedBox(
child: OutlinedButton(
style: OutlinedButton.styleFrom(
child: TextButton(
style: TextButton.styleFrom(
side: BorderSide(color: context.accentColor),
onSurface: context.accentColor.withOpacity(0.5),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100)),
),
child: _loading
? SizedBox(

View File

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

View File

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

View File

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

View File

@ -85,45 +85,6 @@ class __PodcastCardState extends State<_PodcastCard>
int? _seconds;
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
void initState() {
super.initState();
@ -134,43 +95,20 @@ class __PodcastCardState extends State<_PodcastCard>
_controller =
AnimationController(vsync: this, duration: Duration(milliseconds: 300));
_animation = Tween<double>(begin: 0.0, end: 1.0).animate(_controller)
..addListener(() {
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),
],
)),
),
..addListener(
() {
setState(() {
_value = _animation.value;
});
},
);
}
@override
Widget build(BuildContext context) {
final c = widget.podcastLocal!.backgroudColor(context);
final s = context.s;
var groupList = context.watch<GroupList>();
final groupList = context.watch<GroupList>();
_belongGroups = groupList.getPodcastGroup(widget.podcastLocal!.id);
return Column(
mainAxisSize: MainAxisSize.min,
@ -398,9 +336,7 @@ class __PodcastCardState extends State<_PodcastCard>
_seconds = value.inSeconds,
),
actions: <Widget>[
FlatButton(
splashColor: context.accentColor
.withAlpha(70),
TextButton(
onPressed: () {
Navigator.of(context).pop();
_seconds = 0;
@ -411,9 +347,7 @@ class __PodcastCardState extends State<_PodcastCard>
color: Colors.grey[600]),
),
),
FlatButton(
splashColor: context.accentColor
.withAlpha(70),
TextButton(
onPressed: () {
Navigator.of(context).pop();
_saveSkipSeconds(
@ -431,44 +365,42 @@ class __PodcastCardState extends State<_PodcastCard>
});
}),
_buttonOnMenu(
icon: Icon(
Icons.delete,
color: Colors.red,
size: _value == 0 ? 1 : 20 * _value!,
),
tooltip: s.remove,
onTap: () {
generalDialog(
context,
title: Text(s.removeConfirm),
content: Text(s.removePodcastDes),
actions: <Widget>[
FlatButton(
splashColor:
context.accentColor.withAlpha(70),
onPressed: () =>
Navigator.of(context).pop(),
child: Text(
s.cancel,
style: TextStyle(
color: Colors.grey[600]),
),
icon: Icon(
Icons.delete,
color: Colors.red,
size: _value == 0 ? 1 : 20 * _value!,
),
tooltip: s.remove,
onTap: () {
generalDialog(
context,
title: Text(s.removeConfirm),
content: Text(s.removePodcastDes),
actions: <Widget>[
TextButton(
onPressed: () =>
Navigator.of(context).pop(),
child: Text(
s.cancel,
style:
TextStyle(color: Colors.grey[600]),
),
FlatButton(
splashColor: Colors.red.withAlpha(70),
onPressed: () {
groupList.removePodcast(
widget.podcastLocal!);
Navigator.of(context).pop();
},
child: Text(
s.confirm,
style: TextStyle(color: Colors.red),
),
)
],
);
}),
),
TextButton(
onPressed: () {
groupList.removePodcast(
widget.podcastLocal!);
Navigator.of(context).pop();
},
child: Text(
s.confirm,
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 {
@ -511,7 +508,7 @@ class _RenameGroupState extends State<RenameGroup> {
final s = context.s;
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarIconBrightness: Brightness.light,
statusBarColor: Colors.transparent,
systemNavigationBarColor:
Theme.of(context).brightness == Brightness.light
? Color.fromRGBO(113, 113, 113, 1)
@ -519,27 +516,28 @@ class _RenameGroupState extends State<RenameGroup> {
),
child: AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10))),
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
),
elevation: 1,
contentPadding: EdgeInsets.symmetric(horizontal: 20),
titlePadding: EdgeInsets.all(20),
actionsPadding: EdgeInsets.zero,
actions: <Widget>[
FlatButton(
splashColor: context.accentColor.withAlpha(70),
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text(
s.cancel,
style: TextStyle(color: Colors.grey[600]),
),
),
FlatButton(
splashColor: context.accentColor.withAlpha(70),
TextButton(
onPressed: () async {
if (list.contains(_newName)) {
setState(() => _error = 1);
} else {
var newGroup = PodcastGroup(_newName,
final newGroup = PodcastGroup(_newName,
color: widget.group!.color,
id: widget.group!.id,
podcastList: widget.group!.podcastList);
@ -547,12 +545,16 @@ class _RenameGroupState extends State<RenameGroup> {
Navigator.of(context).pop();
}
},
child: Text(s.confirm,
style: TextStyle(color: Theme.of(context).accentColor)),
child: Text(
s.confirm,
style: TextStyle(color: context.accentColor),
),
)
],
title:
SizedBox(width: context.width - 160, child: Text(s.editGroupName)),
title: SizedBox(
width: context.width - 160,
child: Text(s.editGroupName),
),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
@ -578,7 +580,7 @@ class _RenameGroupState extends State<RenameGroup> {
_newName = value;
},
),
Container(
Align(
alignment: Alignment.centerLeft,
child: (_error == 1)
? Text(

View File

@ -42,7 +42,7 @@ class _PodcastManageState extends State<PodcastManage>
_menuValue = 0;
_index = 0;
_menuController = AnimationController(
vsync: this, duration: const Duration(milliseconds: 150));
vsync: this, duration: const Duration(milliseconds: 300));
_controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 500));
_animation = Tween(begin: 0.0, end: 1.0).animate(_controller)
@ -51,8 +51,8 @@ class _PodcastManageState extends State<PodcastManage>
setState(() => _fraction = _animation.value);
}
});
_menuAnimation = Tween(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: _menuController, curve: Curves.elasticInOut))
_menuAnimation = Tween(begin: 0.0, end: 1.0)
.animate(CurvedAnimation(parent: _menuController, curve: Curves.ease))
..addListener(() {
if (mounted) setState(() => _menuValue = _menuAnimation.value);
});
@ -77,6 +77,274 @@ class _PodcastManageState extends State<PodcastManage>
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() {
final s = context.s;
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 {
@ -495,78 +481,81 @@ class _AddGroupState extends State<AddGroup> {
List list = groupList.groups.map((e) => e!.name).toList();
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarIconBrightness: Brightness.light,
statusBarColor: Colors.transparent,
systemNavigationBarColor:
Theme.of(context).brightness == Brightness.light
? Color.fromRGBO(113, 113, 113, 1)
: Color.fromRGBO(5, 5, 5, 1),
),
child: AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
elevation: 1,
contentPadding: EdgeInsets.symmetric(horizontal: 20),
titlePadding: EdgeInsets.all(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]),
),
child: SafeArea(
top: false,
child: AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
FlatButton(
splashColor: context.accentColor.withAlpha(70),
onPressed: () async {
if (list.contains(_newGroup)) {
setState(() => _error = 1);
} else {
groupList.addGroup(PodcastGroup(_newGroup));
Navigator.of(context).pop();
}
},
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),
),
elevation: 1,
contentPadding: EdgeInsets.symmetric(horizontal: 20),
titlePadding: EdgeInsets.all(20),
actionsPadding: EdgeInsets.zero,
actions: <Widget>[
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text(
s.cancel,
style: TextStyle(color: Colors.grey[600]),
),
cursorRadius: Radius.circular(2),
autofocus: true,
maxLines: 1,
controller: _controller,
onChanged: (value) {
_newGroup = value;
),
TextButton(
onPressed: () async {
if (list.contains(_newGroup)) {
setState(() => _error = 1);
} else {
groupList.addGroup(PodcastGroup(_newGroup));
Navigator.of(context).pop();
}
},
),
Container(
alignment: Alignment.centerLeft,
child: (_error == 1)
? Text(
s.groupExisted,
style: TextStyle(color: Colors.red[400]),
)
: Center(),
),
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,
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;
}
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
Widget build(BuildContext context) {
final s = context.s;
@ -341,42 +194,43 @@ class _PodcastSettingState extends State<PodcastSetting> {
child: _getRefreshStatusIcon(_coverStatus)))),
Divider(height: 1),
ListTile(
onTap: () {
setState(() {
_removeConfirm = false;
_showStartTimePicker = false;
_showEndTimePicker = false;
_markConfirm = !_markConfirm;
});
},
dense: true,
title: Row(
children: [
SizedBox(
height: 18,
width: 18,
child: CustomPaint(
painter: ListenedAllPainter(context.accentColor, stroke: 2),
),
onTap: () {
setState(() {
_removeConfirm = false;
_showStartTimePicker = false;
_showEndTimePicker = false;
_markConfirm = !_markConfirm;
});
},
dense: true,
title: Row(
children: [
SizedBox(
height: 18,
width: 18,
child: CustomPaint(
painter: ListenedAllPainter(context.accentColor, stroke: 2),
),
SizedBox(width: 20),
Text(s.menuMarkAllListened,
style: textStyle.copyWith(
color: context.accentColor,
fontWeight: FontWeight.bold)),
],
),
SizedBox(width: 20),
Text(s.menuMarkAllListened,
style: textStyle.copyWith(
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)
Container(
width: double.infinity,
@ -384,7 +238,7 @@ class _PodcastSettingState extends State<PodcastSetting> {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
FlatButton(
TextButton(
onPressed: () => setState(() {
_markConfirm = false;
}),
@ -392,7 +246,7 @@ class _PodcastSettingState extends State<PodcastSetting> {
s.cancel,
style: TextStyle(color: Colors.grey[600]),
)),
FlatButton(
TextButton(
onPressed: () {
if (_markStatus != MarkStatus.start) {
_markListened(widget.podcastLocal!.id);
@ -402,7 +256,7 @@ class _PodcastSettingState extends State<PodcastSetting> {
});
},
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(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
FlatButton(
TextButton(
onPressed: () => setState(() {
_removeConfirm = false;
}),
child:
Text(s.cancel, style: TextStyle(color: Colors.grey[600])),
),
FlatButton(
splashColor: Colors.red.withAlpha(70),
TextButton(
onPressed: () async {
await groupList.removePodcast(widget.podcastLocal!);
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 {
@ -477,15 +471,16 @@ class _TimePicker extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
FlatButton(
TextButton(
onPressed: onCancel,
child: Text(
s.cancel,
style: TextStyle(color: Colors.grey[600]),
),
),
FlatButton(
splashColor: context.accentColor.withAlpha(70),
TextButton(
style: TextButton.styleFrom(
surfaceTintColor: context.priamryContainer),
onPressed: onConfirm,
child: Text(
s.confirm,

View File

@ -1,9 +1,7 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:provider/provider.dart';
@ -20,78 +18,6 @@ import 'podcast_detail.dart';
import 'podcast_manage.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 {
@override
_PodcastListState createState() => _PodcastListState();
@ -108,32 +34,34 @@ class _PodcastListState extends State<PodcastList> {
Widget build(BuildContext context) {
final width = context.width;
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarIconBrightness: Theme.of(context).accentColorBrightness,
systemNavigationBarColor: context.primaryColor,
systemNavigationBarIconBrightness:
Theme.of(context).accentColorBrightness,
),
child: Scaffold(
appBar: AppBar(
title: Text(context.s.podcast(2)),
leading: CustomBackButton(),
actions: [
Selector<SettingState, bool?>(
value: context.overlay,
child: SafeArea(
child: Scaffold(
backgroundColor: context.background,
appBar: AppBar(
backgroundColor: context.background,
title: Text(context.s.podcast(2)),
leading: CustomBackButton(),
actions: [
Selector<SettingState, bool?>(
selector: (_, setting) => setting.openAllPodcastDefalt,
builder: (_, data, __) {
return data!
? IconButton(
splashRadius: 20,
icon: Icon(Icons.all_out),
onPressed: () => Navigator.push(
context, ScaleRoute(page: PodcastManage())))
: Center();
})
],
),
body: SafeArea(
child: Container(
if (!data!) return Center();
return IconButton(
splashRadius: 20,
icon: Icon(Icons.all_out),
onPressed: () => Navigator.push(
context,
ScaleRoute(
page: PodcastManage(),
),
),
);
},
)
],
),
body: Container(
color: context.primaryColor,
child: FutureBuilder<List<PodcastLocal>>(
future: _getPodcastLocal(),
@ -212,9 +140,10 @@ class _PodcastListState extends State<PodcastList> {
}
return Center(
child: SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator()),
height: 20,
width: 20,
child: CircularProgressIndicator(),
),
);
},
),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -11,16 +11,16 @@ class ThemeSetting extends StatelessWidget {
@override
Widget build(BuildContext context) {
final s = context.s;
var settings = Provider.of<SettingState>(context, listen: false);
final settings = Provider.of<SettingState>(context, listen: false);
return AnnotatedRegion<SystemUiOverlayStyle>(
value: context.overlay,
child: Scaffold(
backgroundColor: context.onPrimary,
backgroundColor: context.background,
appBar: AppBar(
title: Text(s.settingsAppearance),
leading: CustomBackButton(),
elevation: 0,
backgroundColor: context.onPrimary,
backgroundColor: context.background,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
@ -52,7 +52,7 @@ class ThemeSetting extends StatelessWidget {
pageBuilder: (context, animaiton, secondaryAnimation) =>
AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarIconBrightness: Brightness.light,
statusBarColor: Colors.transparent,
systemNavigationBarColor:
Theme.of(context).brightness == Brightness.light
? Color.fromRGBO(113, 113, 113, 1)
@ -151,13 +151,18 @@ class ThemeSetting extends StatelessWidget {
ListTile(
onTap: () => generalDialog(
context,
title: Text.rich(TextSpan(text: s.chooseA, children: [
title: Text.rich(
TextSpan(
text: ' ${s.color}',
style: TextStyle(
fontWeight: FontWeight.bold,
color: context.accentColor))
])),
text: s.chooseA,
children: [
TextSpan(
text: ' ${s.color}',
style: TextStyle(
fontWeight: FontWeight.bold,
color: context.accentColor))
],
),
),
content: _ColorPicker(
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
Widget build(BuildContext context) {
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;
TextTheme get textTheme => Theme.of(this).textTheme;
SystemUiOverlayStyle get overlay => SystemUiOverlayStyle(
statusBarColor: onPrimary,
statusBarColor: background,
statusBarIconBrightness: iconBrightness,
systemNavigationBarColor: onPrimary,
systemNavigationBarColor: background,
systemNavigationBarIconBrightness: iconBrightness,
);
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(
EpisodeBrief episode) async {
var menuList = await _getEpisodeMenu();
var tapToOpen = await _getTapToOpenPopupMenu();
var listened = await _isListened(episode);
var liked = await _isLiked(episode);
var downloaded = await _isDownloaded(episode);
final menuList = await _getEpisodeMenu();
final tapToOpen = await _getTapToOpenPopupMenu();
final listened = await _isListened(episode);
final liked = await _isLiked(episode);
final downloaded = await _isDownloaded(episode);
return Tuple5(listened, liked, downloaded, tapToOpen, menuList);
}
@ -85,8 +85,8 @@ class EpisodeGrid extends StatelessWidget {
}
Future<List<int>> _getEpisodeMenu() async {
var popupMenuStorage = KeyValueStorage(episodePopupMenuKey);
var list = await popupMenuStorage.getMenu();
final popupMenuStorage = KeyValueStorage(episodePopupMenuKey);
final list = await popupMenuStorage.getMenu();
return list;
}
@ -95,8 +95,8 @@ class EpisodeGrid extends StatelessWidget {
}
Future<bool> _getTapToOpenPopupMenu() async {
var tapToOpenPopupMenuStorage = KeyValueStorage(tapToOpenPopupMenuKey);
var boo = await tapToOpenPopupMenuStorage.getBool(defaultValue: false);
final tapToOpenPopupMenuStorage = KeyValueStorage(tapToOpenPopupMenuKey);
final boo = await tapToOpenPopupMenuStorage.getBool(defaultValue: false);
return boo;
}
@ -307,102 +307,131 @@ class EpisodeGrid extends StatelessWidget {
Color? color,
bool? isLiked,
bool? isDownloaded,
Color? cardColor,
required int isListened,
bool? boo}) {
var width = context.width;
final width = context.width;
if (layout == Layout.one) {
return _layoutOneCard(context,
index: index!,
color: color,
isLiked: isLiked!,
cardColor: cardColor,
isListened: isListened,
isDownloaded: isDownloaded,
boo: boo!);
}
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
flex: layout == Layout.one ? 1 : 2,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
layout != Layout.one
? _circleImage(context,
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)
],
return Container(
decoration: BoxDecoration(
color: cardColor,
borderRadius: BorderRadius.circular(15.0),
),
clipBehavior: Clip.hardEdge,
child: Stack(
alignment: AlignmentDirectional.bottomCenter,
children: [
if (isListened > 0)
Container(
height: 4,
color: context.accentColor,
),
),
Expanded(
flex: layout == Layout.one ? 3 : 5,
child: layout != Layout.one
? _title(episodes![index])
: Row(
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Expanded(
flex: layout == Layout.one ? 1 : 2,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_circleImage(context,
episode: episodes![index], color: color, boo: boo!),
SizedBox(
width: 5,
),
Expanded(child: _title(episodes![index]))
children: <Widget>[
layout != Layout.one
? _circleImage(context,
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)
],
),
),
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,
required bool isLiked,
bool? isDownloaded,
Color? cardColor,
required int isListened,
required bool boo}) {
var width = context.width;
return Padding(
padding: EdgeInsets.symmetric(vertical: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
return Container(
decoration: BoxDecoration(
color: cardColor,
borderRadius: BorderRadius.circular(15.0),
),
clipBehavior: Clip.hardEdge,
child: Stack(
alignment: AlignmentDirectional.bottomCenter,
children: [
Expanded(
flex: 1,
child: Center(
child: _circleImage(context,
episode: episodes![index],
color: color,
boo: boo,
radius: context.width / 8),
if (isListened > 0)
Container(
height: 4,
color: context.accentColor,
),
),
Expanded(
flex: 4,
child: Column(
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: 1,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: Text(episodes![index].feedTitle!,
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)
],
child: Center(
child: _circleImage(context,
episode: episodes![index],
color: color,
boo: boo,
radius: context.width / 8),
),
),
Expanded(
flex: 2,
child: Align(
alignment: Alignment.topLeft,
child: _title(episodes![index]))),
Expanded(
flex: 1,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
if (episodes![index].duration != 0)
Align(
alignment: Alignment.center,
child: Text(
episodes![index].duration!.toTime,
style: TextStyle(fontSize: width / 35),
flex: 4,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
flex: 1,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: Text(episodes![index].feedTitle!,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight: FontWeight.bold,
color: color)),
),
),
if (episodes![index].duration != 0 &&
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),
]),
)
_isNewIndicator(episodes![index]),
_downloadIndicater(context,
episode: episodes![index],
isDownloaded: isDownloaded),
_numberIndicater(context,
index: index, color: color)
],
),
),
Expanded(
flex: 2,
child: Align(
alignment: Alignment.topLeft,
child: _title(episodes![index]))),
Expanded(
flex: 1,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
if (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 (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;
return SliverPadding(
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(
controller: scrollController,
options: options,
@ -549,8 +599,8 @@ class EpisodeGrid extends StatelessWidget {
: layout == Layout.two
? 2
: 1,
mainAxisSpacing: 6.0,
crossAxisSpacing: 6.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
),
itemBuilder: (context, index, animation) {
final c = episodes![index].backgroudColor(context);
@ -576,28 +626,31 @@ class EpisodeGrid extends StatelessWidget {
future: _initData(episodes![index]),
initialData: Tuple5(0, false, false, false, []),
builder: (context, snapshot) {
var isListened = snapshot.data!.item1;
var isLiked = snapshot.data!.item2;
var isDownloaded = snapshot.data!.item3;
var tapToOpen = snapshot.data!.item4;
var menuList = snapshot.data!.item5;
final isListened = snapshot.data!.item1;
final isLiked = snapshot.data!.item2;
final isDownloaded = snapshot.data!.item3;
final tapToOpen = snapshot.data!.item4;
final menuList = snapshot.data!.item5;
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.0)),
color: isListened > 0
? context.brightness == Brightness.light
? Colors.grey[200]
: Color.fromRGBO(50, 50, 50, 1)
: context.background,
boxShadow: [
BoxShadow(
color: context.brightness == Brightness.light
? context.primaryColor
: Color.fromRGBO(40, 40, 40, 1),
blurRadius: 0.5,
spreadRadius: 0.5,
),
]),
// decoration: BoxDecoration(
// borderRadius: BorderRadius.all(
// Radius.circular(15.0),
// ),
// color: isListened > 0
// ? context.brightness == Brightness.light
// ? Colors.grey[200]
// : Color.fromRGBO(50, 50, 50, 1)
// : context.priamryContainer,
// ),
// boxShadow: [
// BoxShadow(
// color: context.brightness == Brightness.light
// ? context.primaryColor
// : Color.fromRGBO(40, 40, 40, 1),
// blurRadius: 0.5,
// spreadRadius: 0.5,
// ),
// ]),
alignment: Alignment.center,
child: multiSelect!
? Material(
@ -616,7 +669,8 @@ class EpisodeGrid extends StatelessWidget {
},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
borderRadius: BorderRadius.circular(15.0),
color: episodes![index].cardColor(context),
border: Border.all(
color: selectedList!
.contains(episodes![index])
@ -632,6 +686,7 @@ class EpisodeGrid extends StatelessWidget {
index: index,
isLiked: isLiked,
isDownloaded: isDownloaded,
isListened: isListened,
color: c,
boo: boo),
),
@ -639,7 +694,8 @@ class EpisodeGrid extends StatelessWidget {
)
: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
color: episodes![index].cardColor(context),
borderRadius: BorderRadius.circular(20.0),
border: Border.all(
color: context.brightness == Brightness.light
? context.primaryColor
@ -652,7 +708,7 @@ class EpisodeGrid extends StatelessWidget {
menuItemExtent: 45,
menuBoxDecoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.circular(15.0)),
borderRadius: BorderRadius.circular(20.0)),
duration: Duration(milliseconds: 100),
tapMode: tapToOpen
? TapMode.onTap
@ -666,10 +722,7 @@ class EpisodeGrid extends StatelessWidget {
menuOffset: 6,
menuItems: <FocusedMenuItem>[
FocusedMenuItem(
backgroundColor:
context.brightness == Brightness.light
? context.primaryColor
: context.dialogBackgroundColor,
backgroundColor: context.priamryContainer,
title: Text(
data.item1 != episodes![index] ||
!data.item4
@ -687,10 +740,8 @@ class EpisodeGrid extends StatelessWidget {
}),
if (menuList.contains(1))
FocusedMenuItem(
backgroundColor: context.brightness ==
Brightness.light
? context.primaryColor
: context.dialogBackgroundColor,
backgroundColor:
context.priamryContainer,
title: data.item2.contains(
episodes![index].enclosureUrl)
? Text(s.remove)
@ -719,10 +770,8 @@ class EpisodeGrid extends StatelessWidget {
}),
if (menuList.contains(2))
FocusedMenuItem(
backgroundColor: context.brightness ==
Brightness.light
? context.primaryColor
: context.dialogBackgroundColor,
backgroundColor:
context.priamryContainer,
title: isLiked
? Text(s.unlike)
: Text(s.like),
@ -749,10 +798,8 @@ class EpisodeGrid extends StatelessWidget {
}),
if (menuList.contains(3))
FocusedMenuItem(
backgroundColor: context.brightness ==
Brightness.light
? context.primaryColor
: context.dialogBackgroundColor,
backgroundColor:
context.priamryContainer,
title: isListened > 0
? Text(s.markNotListened,
style: TextStyle(
@ -792,10 +839,8 @@ class EpisodeGrid extends StatelessWidget {
}),
if (menuList.contains(4))
FocusedMenuItem(
backgroundColor: context.brightness ==
Brightness.light
? context.primaryColor
: context.dialogBackgroundColor,
backgroundColor:
context.priamryContainer,
title: isDownloaded
? Text(s.downloaded,
style: TextStyle(
@ -812,30 +857,33 @@ class EpisodeGrid extends StatelessWidget {
}),
if (menuList.contains(5))
FocusedMenuItem(
backgroundColor: context.brightness ==
Brightness.light
? context.primaryColor
: context.dialogBackgroundColor,
title: Text(s.playNext),
trailingIcon: Icon(
LineIcons.lightningBolt,
color: Colors.amber,
),
onPressed: () {
audio.moveToTop(episodes![index]);
Fluttertoast.showToast(
msg: s.playNextDes,
gravity: ToastGravity.BOTTOM,
);
}),
backgroundColor: context.priamryContainer,
title: Text(s.playNext),
trailingIcon: Icon(
LineIcons.lightningBolt,
color: Colors.amber,
),
onPressed: () {
audio.moveToTop(episodes![index]);
Fluttertoast.showToast(
msg: s.playNextDes,
gravity: ToastGravity.BOTTOM,
);
},
),
],
onPressed: action,
child: _episodeCard(context,
index: index,
isLiked: isLiked,
isDownloaded: isDownloaded,
color: c,
boo: boo),
child: _episodeCard(
context,
index: index,
isLiked: isLiked,
isListened: isListened,
isDownloaded: isDownloaded,
cardColor:
episodes![index].cardColor(context),
color: c,
boo: boo,
),
),
),
);