diff --git a/lib/components/ViewSelector/no_music_libraries_message.dart b/lib/components/ViewSelector/no_music_libraries_message.dart new file mode 100644 index 000000000..16fd85d04 --- /dev/null +++ b/lib/components/ViewSelector/no_music_libraries_message.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +class NoMusicLibrariesMessage extends StatelessWidget { + const NoMusicLibrariesMessage({ + super.key, + this.onRefresh, + }); + + final VoidCallback? onRefresh; + + @override + Widget build(BuildContext context) { + return Center( + child: Scrollbar( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(8), + child: Column( + children: [ + Text( + AppLocalizations.of(context)!.noMusicLibrariesTitle, + style: Theme.of(context).textTheme.titleLarge, + textAlign: TextAlign.center, + ), + Text( + AppLocalizations.of(context)!.noMusicLibrariesBody, + textAlign: TextAlign.center, + ), + ElevatedButton( + onPressed: onRefresh, + child: Text(AppLocalizations.of(context)!.refresh)) + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index b2f3ee0e7..6d3bbeaa2 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -495,5 +495,11 @@ "language": "Language", "confirm": "Confirm", "showUncensoredLogMessage": "This log contains your login information. Show?", - "resetTabs": "Reset tabs" + "resetTabs": "Reset tabs", + "noMusicLibrariesTitle": "No Music Libraries", + "@noMusicLibrariesTitle": { + "description": "Title for message that shows on the views screen when no music libraries could be found." + }, + "noMusicLibrariesBody": "Finamp could not find any music libraries. Please ensure that your Jellyfin server contains at least one library with the content type set to \"Music\".", + "refresh": "REFRESH" } \ No newline at end of file diff --git a/lib/screens/view_selector.dart b/lib/screens/view_selector.dart index 862603301..e5689f359 100644 --- a/lib/screens/view_selector.dart +++ b/lib/screens/view_selector.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:get_it/get_it.dart'; +import '../components/ViewSelector/no_music_libraries_message.dart'; import '../services/finamp_user_helper.dart'; import 'music_screen.dart'; import '../services/jellyfin_api_helper.dart'; @@ -22,6 +23,7 @@ class _ViewSelectorState extends State { final _finampUserHelper = GetIt.instance(); late Future> viewListFuture; final Map _views = {}; + bool isSubmitButtonEnabled = false; @override void initState() { @@ -35,29 +37,36 @@ class _ViewSelectorState extends State { appBar: AppBar( title: Text(AppLocalizations.of(context)!.selectMusicLibraries), ), - floatingActionButton: FloatingActionButton( - onPressed: _submitChoice, - child: const Icon(Icons.check), - ), + floatingActionButton: isSubmitButtonEnabled + ? FloatingActionButton( + onPressed: _submitChoice, + child: const Icon(Icons.check), + ) + : null, body: FutureBuilder>( future: viewListFuture, builder: (context, snapshot) { if (snapshot.hasData) { - if (snapshot.data!.isEmpty) { - // If snapshot.data is empty, getMusicViews returned no music libraries. This means that the user doesn't have any music libraries. - return Center( - child: Padding( - padding: const EdgeInsets.all(8), - child: - Text(AppLocalizations.of(context)!.couldNotFindLibraries), - ), + // Finamp only supports music libraries. We used to allow people to + // select unsupported libraries, but some people selected "general" + // libraries and thought Finamp was broken. + if (snapshot.data!.isEmpty || + !snapshot.data! + .any((element) => element.collectionType == "music")) { + return NoMusicLibrariesMessage( + onRefresh: () { + setState(() { + _views.clear(); + viewListFuture = _jellyfinApiHelper.getViews(); + }); + }, ); - } else { - if (_views.isEmpty) { - _views.addEntries(snapshot.data! - .where((element) => element.collectionType != "playlists") - .map((e) => MapEntry(e, e.collectionType == "music"))); - } + } + + if (_views.isEmpty) { + _views.addEntries(snapshot.data! + .where((element) => element.collectionType != "playlists") + .map((e) => MapEntry(e, e.collectionType == "music"))); // If only one music library is available and user doesn't have a // view saved (assuming setup is in progress), skip the selector. @@ -66,37 +75,30 @@ class _ViewSelectorState extends State { _finampUserHelper.currentUser!.currentView == null) { _submitChoice(); } - - return Scrollbar( - child: ListView.builder( - itemCount: _views.length, - itemBuilder: (context, index) { - return CheckboxListTile( - value: _views.values.elementAt(index), - title: Text(_views.keys.elementAt(index).name ?? - AppLocalizations.of(context)!.unknownName), - onChanged: (value) { - setState(() { - _views[_views.keys.elementAt(index)] = value!; - }); - }, - // onTap: () async { - // JellyfinApiData jellyfinApiHelper = - // GetIt.instance(); - // try { - // jellyfinApiHelper.saveView(snapshot.data![index], - // jellyfinApiHelper.currentUser!.id); - // Navigator.of(context) - // .pushNamedAndRemoveUntil("/music", (route) => false); - // } catch (e) { - // errorSnackbar(e, context); - // } - // }, - ); - }, - ), - ); } + + return Scrollbar( + child: ListView.builder( + itemCount: _views.length, + itemBuilder: (context, index) { + final isSelected = _views.values.elementAt(index); + final view = _views.keys.elementAt(index); + + return CheckboxListTile( + value: isSelected, + enabled: view.collectionType == "music", + title: Text(_views.keys.elementAt(index).name ?? + AppLocalizations.of(context)!.unknownName), + onChanged: (value) { + setState(() { + _views[_views.keys.elementAt(index)] = value!; + isSubmitButtonEnabled = _views.values.contains(true); + }); + }, + ); + }, + ), + ); } else if (snapshot.hasError) { errorSnackbar(snapshot.error, context); // TODO: Let the user refresh the page