Skip to content

Commit f8fd6e0

Browse files
authored
feat: add an "Add playlist" button to the song saving dialog (#759)
1 parent 95b563a commit f8fd6e0

File tree

3 files changed

+323
-267
lines changed

3 files changed

+323
-267
lines changed

lib/screens/library_page.dart

Lines changed: 3 additions & 267 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import 'package:musify/utilities/async_loader.dart';
3434
import 'package:musify/utilities/common_variables.dart';
3535
import 'package:musify/utilities/flutter_toast.dart';
3636
import 'package:musify/utilities/offline_playlist_dialogs.dart';
37+
import 'package:musify/utilities/playlist_dialogs.dart';
3738
import 'package:musify/utilities/playlist_image_picker.dart';
3839
import 'package:musify/utilities/utils.dart';
3940
import 'package:musify/widgets/confirmation_dialog.dart';
@@ -157,7 +158,7 @@ class _LibraryPageState extends State<LibraryPage> {
157158
),
158159
IconButton(
159160
padding: const EdgeInsets.symmetric(horizontal: 2),
160-
onPressed: _showAddPlaylistDialog,
161+
onPressed: () => showCreatePlaylistDialog(context),
161162
icon: Icon(
162163
FluentIcons.add_24_filled,
163164
color: colorScheme.onSurfaceVariant,
@@ -232,7 +233,7 @@ class _LibraryPageState extends State<LibraryPage> {
232233
icon: FluentIcons.add_circle_24_filled,
233234
actionButton: IconButton(
234235
padding: const EdgeInsets.only(right: 5),
235-
onPressed: _showAddPlaylistDialog,
236+
onPressed: () => showCreatePlaylistDialog(context),
236237
icon: Icon(
237238
FluentIcons.add_24_filled,
238239
color: colorScheme.onSurfaceVariant,
@@ -374,271 +375,6 @@ class _LibraryPageState extends State<LibraryPage> {
374375
);
375376
}
376377

377-
void _showAddPlaylistDialog() => showDialog(
378-
context: context,
379-
builder: (BuildContext context) {
380-
var id = '';
381-
var customPlaylistName = '';
382-
var isYouTubeMode = true;
383-
String? imageUrl;
384-
String? imageBase64;
385-
386-
return StatefulBuilder(
387-
builder: (context, dialogSetState) {
388-
final colorScheme = Theme.of(context).colorScheme;
389-
390-
Future<void> _pickImage() async {
391-
final result = await pickImage();
392-
if (result != null) {
393-
dialogSetState(() {
394-
imageBase64 = result;
395-
imageUrl = null;
396-
});
397-
}
398-
}
399-
400-
Widget _imagePreview() {
401-
return buildImagePreview(
402-
imageBase64: imageBase64,
403-
imageUrl: imageUrl,
404-
);
405-
}
406-
407-
return AlertDialog(
408-
backgroundColor: colorScheme.surface,
409-
surfaceTintColor: Colors.transparent,
410-
shape: RoundedRectangleBorder(
411-
borderRadius: BorderRadius.circular(28),
412-
),
413-
title: Text(
414-
context.l10n!.addPlaylist,
415-
style: TextStyle(
416-
color: colorScheme.onSurface,
417-
fontWeight: FontWeight.w600,
418-
),
419-
),
420-
content: SingleChildScrollView(
421-
child: Column(
422-
mainAxisSize: MainAxisSize.min,
423-
children: <Widget>[
424-
Container(
425-
decoration: BoxDecoration(
426-
color: colorScheme.surfaceContainerLow,
427-
borderRadius: BorderRadius.circular(16),
428-
),
429-
padding: const EdgeInsets.all(4),
430-
child: Row(
431-
children: [
432-
Expanded(
433-
child: GestureDetector(
434-
onTap: () {
435-
dialogSetState(() {
436-
isYouTubeMode = true;
437-
id = '';
438-
customPlaylistName = '';
439-
imageUrl = null;
440-
imageBase64 = null;
441-
});
442-
},
443-
child: AnimatedContainer(
444-
duration: const Duration(milliseconds: 200),
445-
padding: const EdgeInsets.symmetric(vertical: 12),
446-
decoration: BoxDecoration(
447-
color: isYouTubeMode
448-
? colorScheme.primaryContainer
449-
: Colors.transparent,
450-
borderRadius: BorderRadius.circular(12),
451-
),
452-
child: Row(
453-
mainAxisAlignment: MainAxisAlignment.center,
454-
children: [
455-
Icon(
456-
FluentIcons.globe_20_filled,
457-
size: 20,
458-
color: isYouTubeMode
459-
? colorScheme.onPrimaryContainer
460-
: colorScheme.onSurfaceVariant,
461-
),
462-
const SizedBox(width: 8),
463-
Text(
464-
'YouTube',
465-
style: TextStyle(
466-
color: isYouTubeMode
467-
? colorScheme.onPrimaryContainer
468-
: colorScheme.onSurfaceVariant,
469-
fontWeight: isYouTubeMode
470-
? FontWeight.w600
471-
: FontWeight.w500,
472-
),
473-
),
474-
],
475-
),
476-
),
477-
),
478-
),
479-
Expanded(
480-
child: GestureDetector(
481-
onTap: () {
482-
dialogSetState(() {
483-
isYouTubeMode = false;
484-
id = '';
485-
customPlaylistName = '';
486-
imageUrl = null;
487-
imageBase64 = null;
488-
});
489-
},
490-
child: AnimatedContainer(
491-
duration: const Duration(milliseconds: 200),
492-
padding: const EdgeInsets.symmetric(vertical: 12),
493-
decoration: BoxDecoration(
494-
color: !isYouTubeMode
495-
? colorScheme.primaryContainer
496-
: Colors.transparent,
497-
borderRadius: BorderRadius.circular(12),
498-
),
499-
child: Row(
500-
mainAxisAlignment: MainAxisAlignment.center,
501-
children: [
502-
Icon(
503-
FluentIcons.person_20_filled,
504-
size: 20,
505-
color: !isYouTubeMode
506-
? colorScheme.onPrimaryContainer
507-
: colorScheme.onSurfaceVariant,
508-
),
509-
const SizedBox(width: 8),
510-
Text(
511-
context.l10n!.custom,
512-
style: TextStyle(
513-
color: !isYouTubeMode
514-
? colorScheme.onPrimaryContainer
515-
: colorScheme.onSurfaceVariant,
516-
fontWeight: !isYouTubeMode
517-
? FontWeight.w600
518-
: FontWeight.w500,
519-
),
520-
),
521-
],
522-
),
523-
),
524-
),
525-
),
526-
],
527-
),
528-
),
529-
const SizedBox(height: 20),
530-
if (isYouTubeMode)
531-
TextField(
532-
decoration: InputDecoration(
533-
labelText: context.l10n!.youtubePlaylistLinkOrId,
534-
prefixIcon: Icon(
535-
FluentIcons.link_20_regular,
536-
color: colorScheme.onSurfaceVariant,
537-
),
538-
border: OutlineInputBorder(
539-
borderRadius: BorderRadius.circular(12),
540-
),
541-
filled: true,
542-
fillColor: colorScheme.surfaceContainerLow,
543-
),
544-
onChanged: (value) {
545-
id = value;
546-
},
547-
)
548-
else ...[
549-
TextField(
550-
decoration: InputDecoration(
551-
labelText: context.l10n!.customPlaylistName,
552-
prefixIcon: Icon(
553-
FluentIcons.text_field_20_regular,
554-
color: colorScheme.onSurfaceVariant,
555-
),
556-
border: OutlineInputBorder(
557-
borderRadius: BorderRadius.circular(12),
558-
),
559-
filled: true,
560-
fillColor: colorScheme.surfaceContainerLow,
561-
),
562-
onChanged: (value) {
563-
customPlaylistName = value;
564-
},
565-
),
566-
if (imageBase64 == null) ...[
567-
const SizedBox(height: 12),
568-
TextField(
569-
decoration: InputDecoration(
570-
labelText: context.l10n!.customPlaylistImgUrl,
571-
prefixIcon: Icon(
572-
FluentIcons.image_20_regular,
573-
color: colorScheme.onSurfaceVariant,
574-
),
575-
border: OutlineInputBorder(
576-
borderRadius: BorderRadius.circular(12),
577-
),
578-
filled: true,
579-
fillColor: colorScheme.surfaceContainerLow,
580-
),
581-
onChanged: (value) {
582-
imageUrl = value;
583-
imageBase64 = null;
584-
dialogSetState(() {});
585-
},
586-
),
587-
],
588-
const SizedBox(height: 12),
589-
if (imageUrl == null) ...[
590-
buildImagePickerRow(
591-
context,
592-
_pickImage,
593-
imageBase64 != null,
594-
),
595-
_imagePreview(),
596-
],
597-
],
598-
],
599-
),
600-
),
601-
actions: <Widget>[
602-
TextButton(
603-
onPressed: () => Navigator.pop(context),
604-
child: Text(
605-
context.l10n!.cancel,
606-
style: TextStyle(color: colorScheme.onSurfaceVariant),
607-
),
608-
),
609-
FilledButton.icon(
610-
onPressed: () async {
611-
if (isYouTubeMode && id.isNotEmpty) {
612-
showToast(context, await addUserPlaylist(id, context));
613-
} else if (!isYouTubeMode && customPlaylistName.isNotEmpty) {
614-
showToast(
615-
context,
616-
createCustomPlaylist(
617-
customPlaylistName,
618-
imageBase64 ?? imageUrl,
619-
context,
620-
),
621-
);
622-
} else {
623-
showToast(
624-
context,
625-
'${context.l10n!.provideIdOrNameError}.',
626-
);
627-
}
628-
629-
if (!mounted) return;
630-
Navigator.pop(context);
631-
},
632-
icon: const Icon(FluentIcons.add_20_filled),
633-
label: Text(context.l10n!.add),
634-
),
635-
],
636-
);
637-
},
638-
);
639-
},
640-
);
641-
642378
void _showRemoveOfflinePlaylistDialog(Map playlist) {
643379
final playlistId = playlist['ytid']?.toString() ?? '';
644380
if (playlistId.isEmpty) return;

0 commit comments

Comments
 (0)