freezer/lib/ui/search.dart

953 lines
32 KiB
Dart
Raw Normal View History

import 'package:connectivity/connectivity.dart';
2020-06-23 19:23:12 +00:00
import 'package:flutter/material.dart';
2021-08-29 22:25:18 +00:00
import 'package:flutter/services.dart';
2020-11-28 21:32:17 +00:00
import 'package:flutter/widgets.dart';
import 'package:fluttericon/font_awesome5_icons.dart';
import 'package:fluttericon/typicons_icons.dart';
import 'package:freezer/api/cache.dart';
2020-06-23 19:23:12 +00:00
import 'package:freezer/api/download.dart';
import 'package:freezer/api/player.dart';
import 'package:freezer/ui/details_screens.dart';
import 'package:freezer/ui/elements.dart';
2020-11-28 21:32:17 +00:00
import 'package:freezer/ui/home_screen.dart';
2020-06-23 19:23:12 +00:00
import 'package:freezer/ui/menu.dart';
import 'package:freezer/translations.i18n.dart';
2020-06-23 19:23:12 +00:00
import 'tiles.dart';
import '../api/deezer.dart';
import '../api/definitions.dart';
import 'error.dart';
openScreenByURL(BuildContext context, String url) async {
DeezerLinkResponse res = await deezerAPI.parseLink(url);
if (res == null) return;
switch (res.type) {
case DeezerLinkType.TRACK:
Track t = await deezerAPI.track(res.id);
MenuSheet(context).defaultTrackMenu(t);
break;
case DeezerLinkType.ALBUM:
Album a = await deezerAPI.album(res.id);
2021-08-29 22:25:18 +00:00
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => AlbumDetails(a)));
break;
case DeezerLinkType.ARTIST:
Artist a = await deezerAPI.artist(res.id);
2021-08-29 22:25:18 +00:00
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => ArtistDetails(a)));
break;
case DeezerLinkType.PLAYLIST:
Playlist p = await deezerAPI.playlist(res.id);
2021-08-29 22:25:18 +00:00
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => PlaylistDetails(p)));
break;
}
}
2020-06-23 19:23:12 +00:00
class SearchScreen extends StatefulWidget {
@override
_SearchScreenState createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
String _query;
bool _offline = false;
bool _loading = false;
TextEditingController _controller = new TextEditingController();
List _suggestions = [];
bool _cancel = false;
2020-11-28 21:32:17 +00:00
bool _showCards = true;
//FocusNode _focus = FocusNode();
2020-06-23 19:23:12 +00:00
void _submit(BuildContext context, {String query}) async {
2020-06-23 19:23:12 +00:00
if (query != null) _query = query;
//URL
if (_query.startsWith('http')) {
setState(() => _loading = true);
try {
await openScreenByURL(context, _query);
} catch (e) {}
setState(() => _loading = false);
return;
}
2021-08-29 22:25:18 +00:00
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => SearchResultsScreen(
_query,
offline: _offline,
)));
2020-06-23 19:23:12 +00:00
}
@override
void initState() {
2020-10-20 19:55:14 +00:00
_cancel = false;
//Check for connectivity and enable offline mode
Connectivity().checkConnectivity().then((res) {
2021-08-29 22:25:18 +00:00
if (res == ConnectivityResult.none)
setState(() {
_offline = true;
});
});
super.initState();
}
//Load search suggestions
Future<void> _loadSuggestions() async {
2021-08-29 22:25:18 +00:00
if (_query == null || _query.length < 2 || _query.startsWith('http'))
return null;
String q = _query;
await Future.delayed(Duration(milliseconds: 300));
if (q != _query) return null;
//Load
2020-10-10 20:51:20 +00:00
List sugg;
try {
sugg = await deezerAPI.searchSuggestions(_query);
2021-08-29 22:25:18 +00:00
} catch (e) {
print(e);
}
2020-10-10 20:51:20 +00:00
2021-08-29 22:25:18 +00:00
if (sugg != null && !_cancel) setState(() => _suggestions = sugg);
}
2020-10-20 19:55:14 +00:00
Widget _removeHistoryItemWidget(int index) {
return IconButton(
2021-08-29 22:25:18 +00:00
icon: Icon(
Icons.close,
semanticLabel: "Remove".i18n,
),
onPressed: () async {
if (cache.searchHistory != null) cache.searchHistory.removeAt(index);
setState(() {});
await cache.save();
});
2020-10-20 19:55:14 +00:00
}
@override
void dispose() {
_cancel = true;
super.dispose();
}
2020-06-23 19:23:12 +00:00
@override
Widget build(BuildContext context) {
2020-10-31 21:04:27 +00:00
var textFielFocusNode = FocusNode();
2020-06-23 19:23:12 +00:00
return Scaffold(
appBar: FreezerAppBar('Search'.i18n),
body: FocusScope(
2021-08-29 22:25:18 +00:00
child: ListView(
2020-06-23 19:23:12 +00:00
children: <Widget>[
Container(height: 4.0),
2020-06-23 19:23:12 +00:00
Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Row(
children: <Widget>[
Expanded(
2021-08-29 22:25:18 +00:00
child: Stack(
alignment: Alignment(1.0, 0.0),
children: [
RawKeyboardListener(
focusNode: FocusNode(),
onKey: (event) {
// For Android TV: quit search textfield
if (event.runtimeType.toString() == 'RawKeyUpEvent') {
LogicalKeyboardKey key = event.data.logicalKey;
if (key == LogicalKeyboardKey.arrowDown) {
textFielFocusNode.unfocus();
2020-10-31 21:04:27 +00:00
}
2021-08-29 22:25:18 +00:00
}
},
child: TextField(
onChanged: (String s) {
setState(() => _query = s);
_loadSuggestions();
2020-10-31 21:04:27 +00:00
},
2021-08-29 22:25:18 +00:00
onTap: () {
setState(() => _showCards = false);
},
focusNode: textFielFocusNode,
decoration: InputDecoration(
labelText: 'Search or paste URL'.i18n,
fillColor: Theme.of(context).bottomAppBarColor,
filled: true,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey)),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey)),
),
controller: _controller,
onSubmitted: (String s) => _submit(context, query: s),
)),
Focus(
canRequestFocus:
false, // Focus is moving to cross, and hangs out there,
descendantsAreFocusable:
false, // so we disable focusing on it at all
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 40.0,
child: IconButton(
splashRadius: 20.0,
2021-08-29 22:25:18 +00:00
icon: Icon(
Icons.clear,
semanticLabel: "Clear".i18n,
),
onPressed: () {
setState(() {
_suggestions = [];
_query = '';
});
_controller.clear();
},
),
),
],
2021-08-29 22:25:18 +00:00
))
],
)),
2020-06-23 19:23:12 +00:00
],
),
),
Container(height: 8.0),
2020-06-23 19:23:12 +00:00
ListTile(
title: Text('Offline search'.i18n),
leading: Icon(Icons.offline_pin),
trailing: Switch(
2020-06-23 19:23:12 +00:00
value: _offline,
onChanged: (v) {
setState(() => _offline = !_offline);
2020-06-23 19:23:12 +00:00
},
),
),
2021-08-29 22:25:18 +00:00
if (_loading) LinearProgressIndicator(),
FreezerDivider(),
2020-11-28 21:32:17 +00:00
//"Browse" Cards
2021-08-29 22:25:18 +00:00
if (_showCards) ...[
Padding(
padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
child: Text(
'Quick access',
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
2020-11-28 21:32:17 +00:00
),
2021-08-29 22:25:18 +00:00
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SearchBrowseCard(
color: Color(0xff11b192),
text: 'Flow'.i18n,
icon: Icon(Typicons.waves),
onTap: () async {
await playerHelper
.playFromSmartTrackList(SmartTrackList(id: 'flow'));
},
),
SearchBrowseCard(
color: Color(0xff7c42bb),
text: 'Shows'.i18n,
icon: Icon(FontAwesome5.podcast),
onTap: () => Navigator.of(context).push(MaterialPageRoute(
builder: (context) => Scaffold(
appBar: FreezerAppBar('Shows'.i18n),
body: SingleChildScrollView(
2020-11-28 21:32:17 +00:00
child: HomePageScreen(
2021-08-29 22:25:18 +00:00
channel: DeezerChannel(target: 'shows'))),
),
)),
)
],
),
Container(height: 4.0),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SearchBrowseCard(
color: Color(0xffff555d),
icon: Icon(FontAwesome5.chart_line),
text: 'Charts'.i18n,
onTap: () => Navigator.of(context).push(MaterialPageRoute(
builder: (context) => Scaffold(
appBar: FreezerAppBar('Charts'.i18n),
body: SingleChildScrollView(
2020-11-28 21:32:17 +00:00
child: HomePageScreen(
2021-08-29 22:25:18 +00:00
channel:
DeezerChannel(target: 'channels/charts'))),
),
)),
),
SearchBrowseCard(
color: Color(0xff2c4ea7),
text: 'Browse'.i18n,
icon: Image.asset('assets/browse_icon.png', width: 26.0),
onTap: () => Navigator.of(context).push(MaterialPageRoute(
builder: (context) => Scaffold(
appBar: FreezerAppBar('Browse'.i18n),
body: SingleChildScrollView(
2020-11-28 21:32:17 +00:00
child: HomePageScreen(
2021-08-29 22:25:18 +00:00
channel:
DeezerChannel(target: 'channels/explore'))),
),
)),
)
],
)
],
2020-11-28 21:32:17 +00:00
//History
2021-08-29 22:25:18 +00:00
if (!_showCards &&
cache.searchHistory != null &&
cache.searchHistory.length > 0 &&
(_query ?? '').length < 2)
...List.generate(
cache.searchHistory.length > 10
? 10
: cache.searchHistory.length, (int i) {
2020-10-20 19:55:14 +00:00
dynamic data = cache.searchHistory[i].data;
switch (cache.searchHistory[i].type) {
case SearchHistoryItemType.TRACK:
return TrackTile(
data,
onTap: () {
2021-08-29 22:25:18 +00:00
List<Track> queue = cache.searchHistory
.where((h) => h.type == SearchHistoryItemType.TRACK)
.map<Track>((t) => t.data)
.toList();
playerHelper.playFromTrackList(
queue,
data.id,
QueueSource(
text: 'Search history'.i18n,
source: 'searchhistory',
id: 'searchhistory'));
2020-10-20 19:55:14 +00:00
},
onHold: () {
MenuSheet m = MenuSheet(context);
m.defaultTrackMenu(data);
},
trailing: _removeHistoryItemWidget(i),
);
case SearchHistoryItemType.ALBUM:
return AlbumTile(
data,
onTap: () {
2021-08-29 22:25:18 +00:00
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => AlbumDetails(data)));
2020-10-20 19:55:14 +00:00
},
onHold: () {
MenuSheet m = MenuSheet(context);
m.defaultAlbumMenu(data);
},
trailing: _removeHistoryItemWidget(i),
);
case SearchHistoryItemType.ARTIST:
return ArtistHorizontalTile(
data,
onTap: () {
2021-08-29 22:25:18 +00:00
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ArtistDetails(data)));
2020-10-20 19:55:14 +00:00
},
onHold: () {
MenuSheet m = MenuSheet(context);
m.defaultArtistMenu(data);
},
trailing: _removeHistoryItemWidget(i),
);
case SearchHistoryItemType.PLAYLIST:
return PlaylistTile(
data,
onTap: () {
2021-08-29 22:25:18 +00:00
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => PlaylistDetails(data)));
2020-10-20 19:55:14 +00:00
},
onHold: () {
MenuSheet m = MenuSheet(context);
m.defaultPlaylistMenu(data);
},
trailing: _removeHistoryItemWidget(i),
);
}
return Container();
2021-08-29 22:25:18 +00:00
}),
2020-10-20 19:55:14 +00:00
//Clear history
if (cache.searchHistory != null && cache.searchHistory.length > 2)
ListTile(
title: Text('Clear search history'.i18n),
leading: Icon(Icons.clear_all),
onTap: () {
2020-10-20 19:55:14 +00:00
cache.searchHistory = [];
cache.save();
2021-08-29 22:25:18 +00:00
setState(() {});
},
2020-10-20 19:55:14 +00:00
),
//Suggestions
2021-08-29 22:25:18 +00:00
...List.generate(
(_suggestions ?? []).length,
(i) => ListTile(
title: Text(_suggestions[i]),
leading: Icon(Icons.search),
onTap: () {
setState(() => _query = _suggestions[i]);
_submit(context);
},
))
2020-06-23 19:23:12 +00:00
],
2021-08-29 22:25:18 +00:00
)),
2020-06-23 19:23:12 +00:00
);
}
}
2020-11-28 21:32:17 +00:00
class SearchBrowseCard extends StatelessWidget {
final Color color;
final Widget icon;
final Function onTap;
final String text;
2021-08-29 22:25:18 +00:00
SearchBrowseCard(
{@required this.color,
@required this.onTap,
@required this.text,
this.icon});
2020-11-28 21:32:17 +00:00
@override
Widget build(BuildContext context) {
return Card(
2021-08-29 22:25:18 +00:00
color: color,
child: InkWell(
onTap: this.onTap,
child: Container(
width: MediaQuery.of(context).size.width / 2 - 32,
height: 75,
child: Center(
child: Row(
2020-11-28 21:32:17 +00:00
mainAxisSize: MainAxisSize.min,
children: [
2021-08-29 22:25:18 +00:00
if (icon != null) icon,
if (icon != null) Container(width: 8.0),
2020-11-28 21:32:17 +00:00
Text(
text,
textAlign: TextAlign.center,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
2021-08-29 22:25:18 +00:00
fontSize: 18.0,
fontWeight: FontWeight.bold,
color: (color.computeLuminance() > 0.5)
? Colors.black
: Colors.white),
2020-11-28 21:32:17 +00:00
),
],
2021-08-29 22:25:18 +00:00
)),
2020-11-28 21:32:17 +00:00
),
2021-08-29 22:25:18 +00:00
));
2020-11-28 21:32:17 +00:00
}
}
2020-06-23 19:23:12 +00:00
class SearchResultsScreen extends StatelessWidget {
final String query;
final bool offline;
SearchResultsScreen(this.query, {this.offline});
Future _search() async {
2021-08-29 22:25:18 +00:00
if (offline ?? false) {
2020-06-23 19:23:12 +00:00
return await downloadManager.search(query);
}
return await deezerAPI.search(query);
}
@override
Widget build(BuildContext context) {
return Scaffold(
2021-08-29 22:25:18 +00:00
appBar: FreezerAppBar('Search Results'.i18n),
body: FutureBuilder(
future: _search(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData)
return Center(
child: CircularProgressIndicator(),
);
if (snapshot.hasError) return ErrorScreen();
SearchResults results = snapshot.data;
if (results.empty)
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Icon(
Icons.warning,
size: 64,
),
Text('No results!'.i18n)
],
),
);
2020-06-23 19:23:12 +00:00
2021-08-29 22:25:18 +00:00
//Tracks
List<Widget> tracks = [];
if (results.tracks != null && results.tracks.length != 0) {
tracks = [
Padding(
padding:
EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0),
child: Text(
'Tracks'.i18n,
textAlign: TextAlign.left,
style:
TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
),
2020-06-23 19:23:12 +00:00
),
2021-08-29 22:25:18 +00:00
...List.generate(3, (i) {
if (results.tracks.length <= i)
return Container(
width: 0,
height: 0,
);
Track t = results.tracks[i];
return TrackTile(
t,
onTap: () {
cache.addToSearchHistory(t);
playerHelper.playFromTrackList(
results.tracks,
t.id,
QueueSource(
text: 'Search'.i18n,
id: query,
source: 'search'));
},
onHold: () {
MenuSheet m = MenuSheet(context);
m.defaultTrackMenu(t);
},
);
}),
ListTile(
title: Text('Show all tracks'.i18n),
2020-06-23 19:23:12 +00:00
onTap: () {
2021-08-29 22:25:18 +00:00
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => TrackListScreen(
results.tracks,
QueueSource(
id: query,
source: 'search',
text: 'Search'.i18n))));
2020-06-23 19:23:12 +00:00
},
2021-08-29 22:25:18 +00:00
),
FreezerDivider()
];
}
//Albums
List<Widget> albums = [];
if (results.albums != null && results.albums.length != 0) {
albums = [
Padding(
padding:
EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0),
child: Text(
'Albums'.i18n,
textAlign: TextAlign.left,
style:
TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
),
2020-06-23 19:23:12 +00:00
),
2021-08-29 22:25:18 +00:00
...List.generate(3, (i) {
if (results.albums.length <= i)
return Container(
height: 0,
width: 0,
2020-06-23 19:23:12 +00:00
);
2021-08-29 22:25:18 +00:00
Album a = results.albums[i];
return AlbumTile(
a,
onHold: () {
MenuSheet m = MenuSheet(context);
m.defaultAlbumMenu(a);
},
onTap: () {
cache.addToSearchHistory(a);
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => AlbumDetails(a)));
},
2020-06-23 19:23:12 +00:00
);
2021-08-29 22:25:18 +00:00
}),
ListTile(
title: Text('Show all albums'.i18n),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => AlbumListScreen(results.albums)));
},
),
FreezerDivider()
];
}
//Artists
List<Widget> artists = [];
if (results.artists != null && results.artists.length != 0) {
artists = [
Padding(
padding:
EdgeInsets.symmetric(vertical: 4.0, horizontal: 16.0),
child: Text(
'Artists'.i18n,
textAlign: TextAlign.left,
style:
TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
),
2020-06-23 19:23:12 +00:00
),
2021-08-29 22:25:18 +00:00
Container(height: 4),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: List.generate(results.artists.length, (int i) {
Artist a = results.artists[i];
return ArtistTile(
a,
onTap: () {
cache.addToSearchHistory(a);
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ArtistDetails(a)));
},
onHold: () {
MenuSheet m = MenuSheet(context);
m.defaultArtistMenu(a);
},
2020-06-23 19:23:12 +00:00
);
2021-08-29 22:25:18 +00:00
}),
)),
FreezerDivider()
];
}
//Playlists
List<Widget> playlists = [];
if (results.playlists != null && results.playlists.length != 0) {
playlists = [
Padding(
padding:
EdgeInsets.symmetric(vertical: 4.0, horizontal: 16.0),
child: Text(
'Playlists'.i18n,
textAlign: TextAlign.left,
style:
TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
),
2020-06-23 19:23:12 +00:00
),
2021-08-29 22:25:18 +00:00
...List.generate(3, (i) {
if (results.playlists.length <= i)
return Container(
height: 0,
width: 0,
2020-06-23 19:23:12 +00:00
);
2021-08-29 22:25:18 +00:00
Playlist p = results.playlists[i];
return PlaylistTile(
p,
onTap: () {
cache.addToSearchHistory(p);
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => PlaylistDetails(p)));
},
onHold: () {
MenuSheet m = MenuSheet(context);
m.defaultPlaylistMenu(p);
},
2020-06-23 19:23:12 +00:00
);
2021-08-29 22:25:18 +00:00
}),
ListTile(
title: Text('Show all playlists'.i18n),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) =>
SearchResultPlaylists(results.playlists)));
},
),
FreezerDivider()
];
}
//Shows
List<Widget> shows = [];
if (results.shows != null && results.shows.length != 0) {
shows = [
Padding(
padding:
EdgeInsets.symmetric(vertical: 4.0, horizontal: 16.0),
child: Text(
'Shows'.i18n,
textAlign: TextAlign.left,
style:
TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
),
),
2021-08-29 22:25:18 +00:00
...List.generate(3, (i) {
if (results.shows.length <= i)
return Container(
height: 0,
width: 0,
);
Show s = results.shows[i];
return ShowTile(
s,
onTap: () async {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ShowScreen(s)));
},
);
}),
ListTile(
title: Text('Show all shows'.i18n),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
2021-08-29 22:25:18 +00:00
builder: (context) => ShowListScreen(results.shows)));
},
2021-08-29 22:25:18 +00:00
),
FreezerDivider()
];
}
//Episodes
List<Widget> episodes = [];
if (results.episodes != null && results.episodes.length != 0) {
episodes = [
Padding(
padding:
EdgeInsets.symmetric(vertical: 4.0, horizontal: 16.0),
child: Text(
'Episodes'.i18n,
textAlign: TextAlign.left,
style:
TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
),
),
2021-08-29 22:25:18 +00:00
...List.generate(3, (i) {
if (results.episodes.length <= i)
return Container(
height: 0,
width: 0,
);
ShowEpisode e = results.episodes[i];
return ShowEpisodeTile(
e,
trailing: IconButton(
icon: Icon(
Icons.more_vert,
semanticLabel: "Options".i18n,
),
onPressed: () {
MenuSheet m = MenuSheet(context);
m.defaultShowEpisodeMenu(e.show, e);
},
),
onTap: () async {
//Load entire show, then play
List<ShowEpisode> episodes =
await deezerAPI.allShowEpisodes(e.show.id);
await playerHelper.playShowEpisode(e.show, episodes,
index: episodes.indexWhere((ep) => e.id == ep.id));
},
);
2021-08-29 22:25:18 +00:00
}),
ListTile(
title: Text('Show all episodes'.i18n),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) =>
EpisodeListScreen(results.episodes)));
})
];
}
return ListView(
children: <Widget>[
Container(
height: 8.0,
),
...tracks,
Container(
height: 8.0,
),
...albums,
Container(
height: 8.0,
),
...artists,
Container(
height: 8.0,
),
...playlists,
Container(
height: 8.0,
),
...shows,
Container(
height: 8.0,
),
...episodes
],
);
},
));
2020-06-23 19:23:12 +00:00
}
}
//List all tracks
class TrackListScreen extends StatelessWidget {
final QueueSource queueSource;
final List<Track> tracks;
TrackListScreen(this.tracks, this.queueSource);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: FreezerAppBar('Tracks'.i18n),
2020-06-23 19:23:12 +00:00
body: ListView.builder(
itemCount: tracks.length,
itemBuilder: (BuildContext context, int i) {
Track t = tracks[i];
return TrackTile(
t,
onTap: () {
playerHelper.playFromTrackList(tracks, t.id, queueSource);
},
onHold: () {
MenuSheet m = MenuSheet(context);
m.defaultTrackMenu(t);
},
);
},
),
);
}
}
//List all albums
class AlbumListScreen extends StatelessWidget {
final List<Album> albums;
AlbumListScreen(this.albums);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: FreezerAppBar('Albums'.i18n),
2020-06-23 19:23:12 +00:00
body: ListView.builder(
itemCount: albums.length,
itemBuilder: (context, i) {
Album a = albums[i];
return AlbumTile(
a,
onTap: () {
Navigator.of(context).push(
2021-08-29 22:25:18 +00:00
MaterialPageRoute(builder: (context) => AlbumDetails(a)));
2020-06-23 19:23:12 +00:00
},
onHold: () {
MenuSheet m = MenuSheet(context);
m.defaultAlbumMenu(a);
},
);
},
),
);
}
}
class SearchResultPlaylists extends StatelessWidget {
final List<Playlist> playlists;
SearchResultPlaylists(this.playlists);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: FreezerAppBar('Playlists'.i18n),
2020-06-23 19:23:12 +00:00
body: ListView.builder(
itemCount: playlists.length,
itemBuilder: (context, i) {
Playlist p = playlists[i];
return PlaylistTile(
p,
onTap: () {
Navigator.of(context).push(
2021-08-29 22:25:18 +00:00
MaterialPageRoute(builder: (context) => PlaylistDetails(p)));
2020-06-23 19:23:12 +00:00
},
onHold: () {
MenuSheet m = MenuSheet(context);
m.defaultPlaylistMenu(p);
},
);
},
),
);
}
}
class ShowListScreen extends StatelessWidget {
final List<Show> shows;
ShowListScreen(this.shows);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: FreezerAppBar('Shows'.i18n),
body: ListView.builder(
itemCount: shows.length,
itemBuilder: (context, i) {
Show s = shows[i];
return ShowTile(
s,
onTap: () {
2021-08-29 22:25:18 +00:00
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => ShowScreen(s)));
},
);
},
),
);
}
}
class EpisodeListScreen extends StatelessWidget {
final List<ShowEpisode> episodes;
EpisodeListScreen(this.episodes);
@override
Widget build(BuildContext context) {
return Scaffold(
2021-08-29 22:25:18 +00:00
appBar: FreezerAppBar('Episodes'.i18n),
body: ListView.builder(
itemCount: episodes.length,
itemBuilder: (context, i) {
ShowEpisode e = episodes[i];
return ShowEpisodeTile(
e,
trailing: IconButton(
icon: Icon(
Icons.more_vert,
semanticLabel: "Options".i18n,
),
onPressed: () {
MenuSheet m = MenuSheet(context);
m.defaultShowEpisodeMenu(e.show, e);
},
),
onTap: () async {
//Load entire show, then play
List<ShowEpisode> episodes =
await deezerAPI.allShowEpisodes(e.show.id);
await playerHelper.playShowEpisode(e.show, episodes,
index: episodes.indexWhere((ep) => e.id == ep.id));
},
2021-08-29 22:25:18 +00:00
);
},
));
}
2021-08-29 22:25:18 +00:00
}