Improve search page performance.
This commit is contained in:
parent
3405afce83
commit
ba3347e31e
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:line_icons/line_icons.dart';
|
import 'package:line_icons/line_icons.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../.env.dart';
|
||||||
import '../local_storage/key_value_storage.dart';
|
import '../local_storage/key_value_storage.dart';
|
||||||
import '../service/search_api.dart';
|
import '../service/search_api.dart';
|
||||||
import '../state/search_state.dart';
|
import '../state/search_state.dart';
|
||||||
|
@ -9,7 +10,6 @@ import '../type/search_api/search_genre.dart';
|
||||||
import '../type/search_api/searchpodcast.dart';
|
import '../type/search_api/searchpodcast.dart';
|
||||||
import '../util/extension_helper.dart';
|
import '../util/extension_helper.dart';
|
||||||
import '../widgets/custom_widget.dart';
|
import '../widgets/custom_widget.dart';
|
||||||
import '../.env.dart';
|
|
||||||
import 'search_podcast.dart';
|
import 'search_podcast.dart';
|
||||||
|
|
||||||
class DiscoveryPage extends StatefulWidget {
|
class DiscoveryPage extends StatefulWidget {
|
||||||
|
@ -149,6 +149,51 @@ class DiscoveryPageState extends State<DiscoveryPage> {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Widget _podcastCard(OnlinePodcast podcast, {VoidCallback onTap}) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10), color: context.primaryColor),
|
||||||
|
width: 120,
|
||||||
|
margin: EdgeInsets.fromLTRB(10, 10, 0, 10),
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: onTap,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(4.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child: Center(child: PodcastAvatar(podcast)),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Text(
|
||||||
|
podcast.title,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.fade,
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Center(
|
||||||
|
child:
|
||||||
|
SizedBox(height: 32, child: SubscribeButton(podcast)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<List<OnlinePodcast>> _getTopPodcasts({int page}) async {
|
Future<List<OnlinePodcast>> _getTopPodcasts({int page}) async {
|
||||||
final searchEngine = ListenNotesSearch();
|
final searchEngine = ListenNotesSearch();
|
||||||
var searchResult = await searchEngine.fetchBestPodcast(
|
var searchResult = await searchEngine.fetchBestPodcast(
|
||||||
|
@ -168,7 +213,7 @@ class DiscoveryPageState extends State<DiscoveryPage> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final searchState = context.watch<SearchState>();
|
final searchState = context.read<SearchState>();
|
||||||
return FutureBuilder<bool>(
|
return FutureBuilder<bool>(
|
||||||
future: _getHideDiscovery(),
|
future: _getHideDiscovery(),
|
||||||
initialData: true,
|
initialData: true,
|
||||||
|
@ -233,8 +278,12 @@ class DiscoveryPageState extends State<DiscoveryPage> {
|
||||||
)
|
)
|
||||||
: PodcastSlideup(
|
: PodcastSlideup(
|
||||||
searchEngine: SearchEngine.listenNotes,
|
searchEngine: SearchEngine.listenNotes,
|
||||||
child: _selectedGenre == null
|
child: Selector<SearchState, Genre>(
|
||||||
? SingleChildScrollView(
|
selector: (_, searchState) => searchState.genre,
|
||||||
|
builder: (_, genre, __) => IndexedStack(
|
||||||
|
index: genre == null ? 0 : 1,
|
||||||
|
children: [
|
||||||
|
SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
@ -254,75 +303,19 @@ class DiscoveryPageState extends State<DiscoveryPage> {
|
||||||
return ScrollConfiguration(
|
return ScrollConfiguration(
|
||||||
behavior: NoGrowBehavior(),
|
behavior: NoGrowBehavior(),
|
||||||
child: ListView(
|
child: ListView(
|
||||||
|
addAutomaticKeepAlives: true,
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
children: snapshot.hasData
|
children: snapshot.hasData
|
||||||
? snapshot.data
|
? snapshot.data
|
||||||
.map<Widget>((podcast) {
|
.map<Widget>((podcast) {
|
||||||
return Container(
|
return _podcastCard(
|
||||||
decoration: BoxDecoration(
|
podcast,
|
||||||
borderRadius:
|
onTap: () {
|
||||||
BorderRadius.circular(
|
searchState
|
||||||
10),
|
.selectedPodcast =
|
||||||
color:
|
podcast;
|
||||||
context.primaryColor),
|
widget.onTap('');
|
||||||
width: 120,
|
},
|
||||||
margin: EdgeInsets.fromLTRB(
|
|
||||||
10, 10, 0, 10),
|
|
||||||
child: Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
borderRadius:
|
|
||||||
BorderRadius.circular(
|
|
||||||
10),
|
|
||||||
clipBehavior: Clip.hardEdge,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () {
|
|
||||||
searchState
|
|
||||||
.selectedPodcast =
|
|
||||||
podcast;
|
|
||||||
widget.onTap('');
|
|
||||||
},
|
|
||||||
child: Padding(
|
|
||||||
padding:
|
|
||||||
EdgeInsets.all(4.0),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
flex: 2,
|
|
||||||
child: Center(
|
|
||||||
child: PodcastAvatar(
|
|
||||||
podcast)),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
flex: 1,
|
|
||||||
child: Text(
|
|
||||||
podcast.title,
|
|
||||||
textAlign:
|
|
||||||
TextAlign
|
|
||||||
.center,
|
|
||||||
maxLines: 2,
|
|
||||||
overflow:
|
|
||||||
TextOverflow
|
|
||||||
.fade,
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight:
|
|
||||||
FontWeight
|
|
||||||
.bold),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
flex: 1,
|
|
||||||
child: Center(
|
|
||||||
child: SizedBox(
|
|
||||||
height: 32,
|
|
||||||
child: SubscribeButton(
|
|
||||||
podcast)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}).toList()
|
}).toList()
|
||||||
: [
|
: [
|
||||||
|
@ -349,7 +342,7 @@ class DiscoveryPageState extends State<DiscoveryPage> {
|
||||||
EdgeInsets.fromLTRB(20, 0, 20, 0),
|
EdgeInsets.fromLTRB(20, 0, 20, 0),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
widget.onTap('');
|
widget.onTap('');
|
||||||
setState(() => _selectedGenre = e);
|
searchState.setGenre = e;
|
||||||
},
|
},
|
||||||
title: Text(e.name),
|
title: Text(e.name),
|
||||||
))
|
))
|
||||||
|
@ -369,8 +362,11 @@ class DiscoveryPageState extends State<DiscoveryPage> {
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
: _TopPodcastList(genre: _selectedGenre),
|
genre == null ? Center() : _TopPodcastList(genre: genre),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import 'package:fluttertoast/fluttertoast.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:webfeed/webfeed.dart';
|
import 'package:webfeed/webfeed.dart';
|
||||||
|
|
||||||
|
import '../.env.dart';
|
||||||
import '../local_storage/key_value_storage.dart';
|
import '../local_storage/key_value_storage.dart';
|
||||||
import '../service/search_api.dart';
|
import '../service/search_api.dart';
|
||||||
import '../state/podcast_group.dart';
|
import '../state/podcast_group.dart';
|
||||||
|
@ -18,13 +19,10 @@ import '../type/search_api/searchepisodes.dart';
|
||||||
import '../type/search_api/searchpodcast.dart';
|
import '../type/search_api/searchpodcast.dart';
|
||||||
import '../util/extension_helper.dart';
|
import '../util/extension_helper.dart';
|
||||||
import '../widgets/custom_widget.dart';
|
import '../widgets/custom_widget.dart';
|
||||||
import '../.env.dart';
|
|
||||||
import 'pocast_discovery.dart';
|
import 'pocast_discovery.dart';
|
||||||
|
|
||||||
class MyHomePageDelegate extends SearchDelegate<int> {
|
class MyHomePageDelegate extends SearchDelegate<int> {
|
||||||
final String searchFieldLabel;
|
final String searchFieldLabel;
|
||||||
final GlobalKey<DiscoveryPageState> _discoveryKey =
|
|
||||||
GlobalKey<DiscoveryPageState>();
|
|
||||||
MyHomePageDelegate({this.searchFieldLabel})
|
MyHomePageDelegate({this.searchFieldLabel})
|
||||||
: super(
|
: super(
|
||||||
searchFieldLabel: searchFieldLabel,
|
searchFieldLabel: searchFieldLabel,
|
||||||
|
@ -43,15 +41,6 @@ class MyHomePageDelegate extends SearchDelegate<int> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<SearchEngine> _getSearchEngine() async {
|
|
||||||
final storage = KeyValueStorage(searchEngineKey);
|
|
||||||
final index = await storage.getInt();
|
|
||||||
if (_searchEngine == null) {
|
|
||||||
_searchEngine = SearchEngine.values[index];
|
|
||||||
}
|
|
||||||
return _searchEngine;
|
|
||||||
}
|
|
||||||
|
|
||||||
RegExp rssExp = RegExp(r'^(https?):\/\/(.*)');
|
RegExp rssExp = RegExp(r'^(https?):\/\/(.*)');
|
||||||
|
|
||||||
Widget _invalidRss(BuildContext context) => Container(
|
Widget _invalidRss(BuildContext context) => Container(
|
||||||
|
@ -63,14 +52,15 @@ class MyHomePageDelegate extends SearchDelegate<int> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void close(BuildContext context, int result) {
|
void close(BuildContext context, int result) {
|
||||||
final selectedPodcast = context.read<SearchState>().selectedPodcast;
|
final searchState = context.read<SearchState>();
|
||||||
|
final selectedPodcast = searchState.selectedPodcast;
|
||||||
if (selectedPodcast != null) {
|
if (selectedPodcast != null) {
|
||||||
context.read<SearchState>().clearSelect();
|
searchState.clearSelect();
|
||||||
} else {
|
} else {
|
||||||
if (_discoveryKey.currentState?.selectedGenre != null) {
|
if (searchState.genre != null) {
|
||||||
_discoveryKey.currentState.backToHome();
|
searchState.clearGenre();
|
||||||
} else {
|
} else {
|
||||||
context.read<SearchState>().clearList();
|
searchState.clearList();
|
||||||
super.close(context, result);
|
super.close(context, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,6 +69,9 @@ class MyHomePageDelegate extends SearchDelegate<int> {
|
||||||
@override
|
@override
|
||||||
ThemeData appBarTheme(BuildContext context) => Theme.of(context);
|
ThemeData appBarTheme(BuildContext context) => Theme.of(context);
|
||||||
|
|
||||||
|
@override
|
||||||
|
TextStyle get searchFieldStyle => TextStyle(fontSize: 20);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget buildLeading(BuildContext context) {
|
Widget buildLeading(BuildContext context) {
|
||||||
return WillPopScope(
|
return WillPopScope(
|
||||||
|
@ -103,7 +96,6 @@ class MyHomePageDelegate extends SearchDelegate<int> {
|
||||||
@override
|
@override
|
||||||
Widget buildSuggestions(BuildContext context) {
|
Widget buildSuggestions(BuildContext context) {
|
||||||
return DiscoveryPage(
|
return DiscoveryPage(
|
||||||
key: _discoveryKey,
|
|
||||||
onTap: (history) {
|
onTap: (history) {
|
||||||
query = history;
|
query = history;
|
||||||
showResults(context);
|
showResults(context);
|
||||||
|
@ -124,76 +116,25 @@ class MyHomePageDelegate extends SearchDelegate<int> {
|
||||||
showResults(context);
|
showResults(context);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
FutureBuilder<SearchEngine>(
|
_SearchPopupMenu(
|
||||||
future: _getSearchEngine(),
|
onSelected: (searchEngine) {
|
||||||
initialData: SearchEngine.podcastIndex,
|
_searchEngine = searchEngine;
|
||||||
builder: (context, snapshot) => PopupMenuButton<SearchEngine>(
|
showSuggestions(context);
|
||||||
shape:
|
if (query != '') {
|
||||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
showResults(context);
|
||||||
elevation: 1,
|
}
|
||||||
icon: SizedBox(
|
},
|
||||||
height: 30,
|
|
||||||
width: 30,
|
|
||||||
child: CircleAvatar(
|
|
||||||
backgroundImage: snapshot.data == SearchEngine.podcastIndex
|
|
||||||
? AssetImage('assets/podcastindex_logo.png')
|
|
||||||
: AssetImage('assets/listennotes_logo.png'),
|
|
||||||
maxRadius: 25,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onSelected: (value) {
|
|
||||||
_searchEngine = value;
|
|
||||||
showSuggestions(context);
|
|
||||||
if (query != '') {
|
|
||||||
showResults(context);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
itemBuilder: (context) => [
|
|
||||||
PopupMenuItem(
|
|
||||||
value: SearchEngine.podcastIndex,
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.only(left: 10),
|
|
||||||
child: Row(
|
|
||||||
children: <Widget>[
|
|
||||||
Text('Podcastindex'),
|
|
||||||
Spacer(),
|
|
||||||
if (_searchEngine == SearchEngine.podcastIndex)
|
|
||||||
DotIndicator()
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if(environment['apiKey'] != '')
|
|
||||||
PopupMenuItem(
|
|
||||||
value: SearchEngine.listenNotes,
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.only(left: 10),
|
|
||||||
child: Row(
|
|
||||||
children: <Widget>[
|
|
||||||
Text('ListenNotes'),
|
|
||||||
Spacer(),
|
|
||||||
if (_searchEngine == SearchEngine.listenNotes)
|
|
||||||
DotIndicator()
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
SizedBox(width: 10),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget buildResults(BuildContext context) {
|
Widget buildResults(BuildContext context) {
|
||||||
if (query.isEmpty) {
|
if (query.isEmpty) {
|
||||||
return DiscoveryPage(
|
return DiscoveryPage(onTap: (history) {
|
||||||
key: _discoveryKey,
|
query = history;
|
||||||
onTap: (history) {
|
showResults(context);
|
||||||
query = history;
|
});
|
||||||
showResults(context);
|
|
||||||
});
|
|
||||||
} else if (rssExp.stringMatch(query) != null) {
|
} else if (rssExp.stringMatch(query) != null) {
|
||||||
return FutureBuilder(
|
return FutureBuilder(
|
||||||
future: _getRss(rssExp.stringMatch(query)),
|
future: _getRss(rssExp.stringMatch(query)),
|
||||||
|
@ -401,6 +342,85 @@ class _RssResultState extends State<RssResult> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _SearchPopupMenu extends StatefulWidget {
|
||||||
|
final ValueChanged<SearchEngine> onSelected;
|
||||||
|
_SearchPopupMenu({this.onSelected, Key key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
__SearchPopupMenuState createState() => __SearchPopupMenuState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class __SearchPopupMenuState extends State<_SearchPopupMenu> {
|
||||||
|
SearchEngine _searchEngine;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_searchEngine = SearchEngine.podcastIndex;
|
||||||
|
_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,
|
||||||
|
icon: SizedBox(
|
||||||
|
height: 20,
|
||||||
|
width: 20,
|
||||||
|
child: CircleAvatar(
|
||||||
|
backgroundImage: _searchEngine == SearchEngine.podcastIndex
|
||||||
|
? AssetImage('assets/podcastindex_logo.png')
|
||||||
|
: AssetImage('assets/listennotes_logo.png'),
|
||||||
|
maxRadius: 25,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onSelected: (searchEngine) {
|
||||||
|
widget.onSelected(searchEngine);
|
||||||
|
setState(() {
|
||||||
|
_searchEngine = searchEngine;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
itemBuilder: (context) => [
|
||||||
|
PopupMenuItem(
|
||||||
|
value: SearchEngine.podcastIndex,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(left: 10),
|
||||||
|
child: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Text('Podcastindex'),
|
||||||
|
Spacer(),
|
||||||
|
if (_searchEngine == SearchEngine.podcastIndex) DotIndicator()
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (environment['apiKey'] != '')
|
||||||
|
PopupMenuItem(
|
||||||
|
value: SearchEngine.listenNotes,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(left: 10),
|
||||||
|
child: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Text('ListenNotes'),
|
||||||
|
Spacer(),
|
||||||
|
if (_searchEngine == SearchEngine.listenNotes) DotIndicator()
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class _ListenNotesSearch extends StatefulWidget {
|
class _ListenNotesSearch extends StatefulWidget {
|
||||||
final String query;
|
final String query;
|
||||||
_ListenNotesSearch({this.query, Key key}) : super(key: key);
|
_ListenNotesSearch({this.query, Key key}) : super(key: key);
|
||||||
|
@ -1058,103 +1078,107 @@ class _SearchResultDetailState extends State<SearchResultDetail>
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TabBarView(children: [
|
child: Container(
|
||||||
ListView(
|
color: context.scaffoldBackgroundColor,
|
||||||
physics: _animation.value != widget.maxHeight
|
child: TabBarView(children: [
|
||||||
? NeverScrollableScrollPhysics()
|
ListView(
|
||||||
: null,
|
physics: _animation.value != widget.maxHeight
|
||||||
children: [
|
? NeverScrollableScrollPhysics()
|
||||||
Html(
|
: null,
|
||||||
onLinkTap: (url) {
|
children: [
|
||||||
url.launchUrl;
|
Html(
|
||||||
},
|
onLinkTap: (url) {
|
||||||
linkStyle: TextStyle(
|
url.launchUrl;
|
||||||
color: context.accentColor,
|
},
|
||||||
textBaseline: TextBaseline.ideographic),
|
linkStyle: TextStyle(
|
||||||
shrinkToFit: true,
|
color: context.accentColor,
|
||||||
data: widget.onlinePodcast.description,
|
textBaseline: TextBaseline.ideographic),
|
||||||
padding: const EdgeInsets.only(
|
shrinkToFit: true,
|
||||||
left: 20.0, right: 20, bottom: 20),
|
data: widget.onlinePodcast.description,
|
||||||
defaultTextStyle: TextStyle(
|
padding: const EdgeInsets.only(
|
||||||
height: 1.8,
|
left: 20.0, right: 20, bottom: 20),
|
||||||
|
defaultTextStyle: TextStyle(
|
||||||
|
height: 1.8,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
FutureBuilder<List<OnlineEpisode>>(
|
||||||
FutureBuilder<List<OnlineEpisode>>(
|
future: _searchFuture,
|
||||||
future: _searchFuture,
|
builder: (context, snapshot) {
|
||||||
builder: (context, snapshot) {
|
if (snapshot.hasData) {
|
||||||
if (snapshot.hasData) {
|
var content = snapshot.data;
|
||||||
var content = snapshot.data;
|
return ListView.builder(
|
||||||
return ListView.builder(
|
physics: _animation.value != widget.maxHeight
|
||||||
physics: _animation.value != widget.maxHeight
|
? NeverScrollableScrollPhysics()
|
||||||
? NeverScrollableScrollPhysics()
|
: null,
|
||||||
: null,
|
itemCount: content.length + 1,
|
||||||
itemCount: content.length + 1,
|
itemBuilder: (context, index) {
|
||||||
itemBuilder: (context, index) {
|
if (index == content.length) {
|
||||||
if (index == content.length) {
|
return Container(
|
||||||
return Container(
|
padding: const EdgeInsets.only(
|
||||||
padding: const EdgeInsets.only(
|
top: 10.0, bottom: 20.0),
|
||||||
top: 10.0, bottom: 20.0),
|
alignment: Alignment.center,
|
||||||
alignment: Alignment.center,
|
child: SizedBox(
|
||||||
child: SizedBox(
|
child: OutlineButton(
|
||||||
child: OutlineButton(
|
highlightedBorderColor:
|
||||||
highlightedBorderColor:
|
context.accentColor,
|
||||||
context.accentColor,
|
splashColor: context.accentColor
|
||||||
splashColor: context.accentColor
|
.withOpacity(0.5),
|
||||||
.withOpacity(0.5),
|
shape: RoundedRectangleBorder(
|
||||||
shape: RoundedRectangleBorder(
|
borderRadius: BorderRadius.all(
|
||||||
borderRadius: BorderRadius.all(
|
Radius.circular(100))),
|
||||||
Radius.circular(100))),
|
child: _loading
|
||||||
child: _loading
|
? SizedBox(
|
||||||
? SizedBox(
|
height: 20,
|
||||||
height: 20,
|
width: 20,
|
||||||
width: 20,
|
child:
|
||||||
child:
|
CircularProgressIndicator(
|
||||||
CircularProgressIndicator(
|
strokeWidth: 2,
|
||||||
strokeWidth: 2,
|
))
|
||||||
))
|
: Text(context.s.loadMore),
|
||||||
: Text(context.s.loadMore),
|
onPressed: () {
|
||||||
onPressed: () {
|
if (widget.searchEngine ==
|
||||||
if (widget.searchEngine ==
|
SearchEngine.listenNotes) {
|
||||||
SearchEngine.listenNotes) {
|
_loading
|
||||||
_loading
|
? null
|
||||||
? null
|
: setState(
|
||||||
: setState(
|
() {
|
||||||
() {
|
_loading = true;
|
||||||
_loading = true;
|
_searchFuture =
|
||||||
_searchFuture =
|
_getListenNotesEpisodes(
|
||||||
_getListenNotesEpisodes(
|
id: widget
|
||||||
id: widget
|
.onlinePodcast
|
||||||
.onlinePodcast
|
.id,
|
||||||
.id,
|
nextEpisodeDate:
|
||||||
nextEpisodeDate:
|
_nextEpisdoeDate);
|
||||||
_nextEpisdoeDate);
|
},
|
||||||
},
|
);
|
||||||
);
|
}
|
||||||
}
|
}),
|
||||||
}),
|
),
|
||||||
),
|
);
|
||||||
|
}
|
||||||
|
return ListTile(
|
||||||
|
title: Text(content[index].title),
|
||||||
|
tileColor: Colors.transparent,
|
||||||
|
subtitle: Text(
|
||||||
|
content[index].length == 0
|
||||||
|
? '${content[index].pubDate.toDate(context)}'
|
||||||
|
: '${content[index].length.toTime} | '
|
||||||
|
'${content[index].pubDate.toDate(context)}',
|
||||||
|
style: TextStyle(
|
||||||
|
color: context.accentColor)),
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
return ListTile(
|
);
|
||||||
title: Text(content[index].title),
|
}
|
||||||
subtitle: Text(
|
return Center(
|
||||||
content[index].length == 0
|
child: CircularProgressIndicator(),
|
||||||
? '${content[index].pubDate.toDate(context)}'
|
|
||||||
: '${content[index].length.toTime} | '
|
|
||||||
'${content[index].pubDate.toDate(context)}',
|
|
||||||
style:
|
|
||||||
TextStyle(color: context.accentColor)),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
})
|
||||||
return Center(
|
]),
|
||||||
child: CircularProgressIndicator(),
|
),
|
||||||
);
|
|
||||||
})
|
|
||||||
]),
|
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tsacdop/type/search_api/search_genre.dart';
|
||||||
import '../type/search_api/searchpodcast.dart';
|
import '../type/search_api/searchpodcast.dart';
|
||||||
|
|
||||||
class SearchState extends ChangeNotifier {
|
class SearchState extends ChangeNotifier {
|
||||||
|
@ -8,12 +9,19 @@ class SearchState extends ChangeNotifier {
|
||||||
bool get update => _update;
|
bool get update => _update;
|
||||||
OnlinePodcast _selectedPodcast;
|
OnlinePodcast _selectedPodcast;
|
||||||
OnlinePodcast get selectedPodcast => _selectedPodcast;
|
OnlinePodcast get selectedPodcast => _selectedPodcast;
|
||||||
|
Genre _genre;
|
||||||
|
Genre get genre => _genre;
|
||||||
|
|
||||||
set selectedPodcast(OnlinePodcast podcast) {
|
set selectedPodcast(OnlinePodcast podcast) {
|
||||||
_selectedPodcast = podcast;
|
_selectedPodcast = podcast;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set setGenre(Genre genre) {
|
||||||
|
_genre = genre;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
bool isSubscribed(OnlinePodcast podcast) => _subscribedList.contains(podcast);
|
bool isSubscribed(OnlinePodcast podcast) => _subscribedList.contains(podcast);
|
||||||
|
|
||||||
void clearSelect() {
|
void clearSelect() {
|
||||||
|
@ -25,6 +33,11 @@ class SearchState extends ChangeNotifier {
|
||||||
_subscribedList.clear();
|
_subscribedList.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clearGenre(){
|
||||||
|
_genre = null;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
void addPodcast(OnlinePodcast podcast) {
|
void addPodcast(OnlinePodcast podcast) {
|
||||||
_subscribedList.add(podcast);
|
_subscribedList.add(podcast);
|
||||||
_update = !_update;
|
_update = !_update;
|
||||||
|
|
Loading…
Reference in New Issue