From c201624f996edcbe9110574293c94f96cf38bd38 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Thu, 3 Nov 2022 09:12:43 +0600 Subject: [PATCH] refactor: platform alert dialog for all dialogs --- lib/components/Home/Shell.dart | 5 +- lib/components/Library/UserDownloads.dart | 10 +- .../Lyrics/LyricDelayAdjustDialog.dart | 9 +- lib/components/Lyrics/SyncedLyrics.dart | 4 +- .../Playlist/PlaylistCreateDialog.dart | 19 ++- .../Settings/ColorSchemePickerDialog.dart | 19 ++- lib/components/Settings/Settings.dart | 4 +- lib/components/Shared/AdaptiveListTile.dart | 8 +- .../Shared/DownloadConfirmationDialog.dart | 53 ++++--- .../Shared/ReplaceDownloadedFileDialog.dart | 21 +-- lib/components/Shared/TrackTile.dart | 144 +++++++++--------- lib/components/Shared/TracksTableView.dart | 9 +- lib/hooks/useUpdateChecker.dart | 60 ++++---- lib/main.dart | 8 +- lib/themes/light-theme.dart | 3 +- 15 files changed, 194 insertions(+), 182 deletions(-) diff --git a/lib/components/Home/Shell.dart b/lib/components/Home/Shell.dart index dc51c464..2d24a7f8 100644 --- a/lib/components/Home/Shell.dart +++ b/lib/components/Home/Shell.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:platform_ui/platform_ui.dart'; import 'package:spotube/components/Home/Sidebar.dart'; import 'package:spotube/components/Home/SpotubeNavigationBar.dart'; import 'package:spotube/components/Player/Player.dart'; @@ -35,8 +36,8 @@ class Shell extends HookConsumerWidget { useEffect(() { downloader.onFileExists = (track) async { if (!isMounted()) return false; - return await showDialog( - context: context, + return await showPlatformAlertDialog( + context, builder: (context) => ReplaceDownloadedFileDialog( track: track, ), diff --git a/lib/components/Library/UserDownloads.dart b/lib/components/Library/UserDownloads.dart index bd7fb732..33263d6d 100644 --- a/lib/components/Library/UserDownloads.dart +++ b/lib/components/Library/UserDownloads.dart @@ -31,14 +31,14 @@ class UserDownloads extends HookConsumerWidget { ), const SizedBox(width: 10), PlatformFilledButton( - style: ElevatedButton.styleFrom( - backgroundColor: Colors.red[50], - foregroundColor: Colors.red[400], + style: ButtonStyle( + backgroundColor: MaterialStatePropertyAll(Colors.red[50]), + foregroundColor: MaterialStatePropertyAll(Colors.red[400]), ), onPressed: downloader.currentlyRunning > 0 ? downloader.cancelAll : null, - macOSIsSecondary: true, + isSecondary: true, child: const PlatformText("Cancel All"), ), ], @@ -50,7 +50,7 @@ class UserDownloads extends HookConsumerWidget { itemBuilder: (context, index) { final track = downloader.inQueue.elementAt(index); return PlatformListTile( - title: Text(track.name!), + title: Text(track.name ?? ''), leading: Padding( padding: const EdgeInsets.symmetric(horizontal: 5), child: ClipRRect( diff --git a/lib/components/Lyrics/LyricDelayAdjustDialog.dart b/lib/components/Lyrics/LyricDelayAdjustDialog.dart index f0c5c909..402fc896 100644 --- a/lib/components/Lyrics/LyricDelayAdjustDialog.dart +++ b/lib/components/Lyrics/LyricDelayAdjustDialog.dart @@ -16,15 +16,18 @@ class LyricDelayAdjustDialog extends HookConsumerWidget { double getValue() => double.tryParse(controller.text.replaceAll("ms", "")) ?? 0; - return AlertDialog( + return PlatformAlertDialog( title: const Center(child: Text("Adjust Lyrics Delay")), - actions: [ + secondaryActions: [ PlatformFilledButton( - child: const Text("Cancel"), + isSecondary: true, onPressed: () { Navigator.of(context).pop(); }, + child: const Text("Cancel"), ), + ], + primaryActions: [ PlatformFilledButton( child: const Text("Done"), onPressed: () { diff --git a/lib/components/Lyrics/SyncedLyrics.dart b/lib/components/Lyrics/SyncedLyrics.dart index ed69c350..1edf4f97 100644 --- a/lib/components/Lyrics/SyncedLyrics.dart +++ b/lib/components/Lyrics/SyncedLyrics.dart @@ -90,8 +90,8 @@ class SyncedLyrics extends HookConsumerWidget { tooltip: "Lyrics Delay", icon: const Icon(Icons.av_timer_rounded), onPressed: () async { - final delay = await showDialog( - context: context, + final delay = await showPlatformAlertDialog( + context, builder: (context) => const LyricDelayAdjustDialog(), ); if (delay != null) { diff --git a/lib/components/Playlist/PlaylistCreateDialog.dart b/lib/components/Playlist/PlaylistCreateDialog.dart index dc085786..97033d5d 100644 --- a/lib/components/Playlist/PlaylistCreateDialog.dart +++ b/lib/components/Playlist/PlaylistCreateDialog.dart @@ -15,8 +15,8 @@ class PlaylistCreateDialog extends HookConsumerWidget { return PlatformTextButton( onPressed: () { - showDialog( - context: context, + showPlatformAlertDialog( + context, builder: (context) { return HookBuilder(builder: (context) { final playlistName = useTextEditingController(); @@ -24,13 +24,9 @@ class PlaylistCreateDialog extends HookConsumerWidget { final public = useState(false); final collaborative = useState(false); - return AlertDialog( + return PlatformAlertDialog( title: const Text("Create a Playlist"), - actions: [ - PlatformTextButton( - child: const Text("Cancel"), - onPressed: () => Navigator.of(context).pop(), - ), + primaryActions: [ PlatformFilledButton( child: const Text("Create"), onPressed: () async { @@ -53,6 +49,13 @@ class PlaylistCreateDialog extends HookConsumerWidget { }, ) ], + secondaryActions: [ + PlatformFilledButton( + isSecondary: true, + onPressed: () => Navigator.of(context).pop(), + child: const Text("Cancel"), + ), + ], content: Container( width: MediaQuery.of(context).size.width, constraints: const BoxConstraints(maxWidth: 500), diff --git a/lib/components/Settings/ColorSchemePickerDialog.dart b/lib/components/Settings/ColorSchemePickerDialog.dart index 7c0fbe8a..8bd14935 100644 --- a/lib/components/Settings/ColorSchemePickerDialog.dart +++ b/lib/components/Settings/ColorSchemePickerDialog.dart @@ -66,15 +66,9 @@ class ColorSchemePickerDialog extends HookConsumerWidget { }, ).key); - return AlertDialog( + return PlatformAlertDialog( title: Text("Pick ${schemeType.name} color scheme"), - actions: [ - PlatformTextButton( - child: const Text("Cancel"), - onPressed: () { - Navigator.pop(context); - }, - ), + primaryActions: [ PlatformFilledButton( child: const Text("Save"), onPressed: () { @@ -91,6 +85,15 @@ class ColorSchemePickerDialog extends HookConsumerWidget { }, ) ], + secondaryActions: [ + PlatformFilledButton( + isSecondary: true, + child: const Text("Cancel"), + onPressed: () { + Navigator.pop(context); + }, + ), + ], content: SizedBox( height: 200, width: 400, diff --git a/lib/components/Settings/Settings.dart b/lib/components/Settings/Settings.dart index 28a652e4..4bf361a0 100644 --- a/lib/components/Settings/Settings.dart +++ b/lib/components/Settings/Settings.dart @@ -28,9 +28,7 @@ class Settings extends HookConsumerWidget { final Auth auth = ref.watch(authProvider); final pickColorScheme = useCallback((ColorSchemeType schemeType) { - return () => showDialog( - context: context, - builder: (context) { + return () => showPlatformAlertDialog(context, builder: (context) { return ColorSchemePickerDialog( schemeType: schemeType, ); diff --git a/lib/components/Shared/AdaptiveListTile.dart b/lib/components/Shared/AdaptiveListTile.dart index ba81621b..3d219ee8 100644 --- a/lib/components/Shared/AdaptiveListTile.dart +++ b/lib/components/Shared/AdaptiveListTile.dart @@ -34,11 +34,11 @@ class AdaptiveListTile extends HookWidget { onTap: breakpoint.isLessThan(breakOn) ? () { onTap?.call(); - showDialog( - context: context, + showPlatformAlertDialog( + context, builder: (context) { return StatefulBuilder(builder: (context, update) { - return AlertDialog( + return PlatformAlertDialog( title: title != null ? Row( crossAxisAlignment: CrossAxisAlignment.center, @@ -50,7 +50,7 @@ class AdaptiveListTile extends HookWidget { Flexible(child: title!), ], ) - : null, + : Container(), content: trailing?.call(context, update), ); }); diff --git a/lib/components/Shared/DownloadConfirmationDialog.dart b/lib/components/Shared/DownloadConfirmationDialog.dart index 73c04a59..5e770b31 100644 --- a/lib/components/Shared/DownloadConfirmationDialog.dart +++ b/lib/components/Shared/DownloadConfirmationDialog.dart @@ -7,22 +7,24 @@ class DownloadConfirmationDialog extends StatelessWidget { @override Widget build(BuildContext context) { - return AlertDialog( - contentPadding: const EdgeInsets.all(15), - title: Row( - children: const [ - Text("Are you sure?"), - SizedBox(width: 10), - UniversalImage( - path: - "https://c.tenor.com/kHcmsxlKHEAAAAAM/rock-one-eyebrow-raised-rock-staring.gif", - height: 40, - width: 40, - ) - ], + return PlatformAlertDialog( + title: Padding( + padding: const EdgeInsets.all(15), + child: Row( + children: const [ + Text("Are you sure?"), + SizedBox(width: 10), + UniversalImage( + path: + "https://c.tenor.com/kHcmsxlKHEAAAAAM/rock-one-eyebrow-raised-rock-staring.gif", + height: 40, + width: 40, + ) + ], + ), ), - content: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 400), + content: Padding( + padding: const EdgeInsets.all(15), child: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, @@ -57,19 +59,22 @@ class DownloadConfirmationDialog extends StatelessWidget { ), ), ), - actions: [ + primaryActions: [ PlatformFilledButton( + style: const ButtonStyle( + foregroundColor: MaterialStatePropertyAll(Colors.white), + backgroundColor: MaterialStatePropertyAll(Colors.red), + ), + onPressed: () => Navigator.of(context).pop(true), + child: const Text("Accept"), + ) + ], + secondaryActions: [ + PlatformFilledButton( + isSecondary: true, child: const Text("Decline"), onPressed: () => Navigator.of(context).pop(false), ), - PlatformFilledButton( - onPressed: () => Navigator.of(context).pop(true), - style: ElevatedButton.styleFrom( - foregroundColor: Colors.white, - backgroundColor: Colors.red, - ), - child: const Text("Accept"), - ) ], ); } diff --git a/lib/components/Shared/ReplaceDownloadedFileDialog.dart b/lib/components/Shared/ReplaceDownloadedFileDialog.dart index ec472b8d..58263746 100644 --- a/lib/components/Shared/ReplaceDownloadedFileDialog.dart +++ b/lib/components/Shared/ReplaceDownloadedFileDialog.dart @@ -14,7 +14,7 @@ class ReplaceDownloadedFileDialog extends ConsumerWidget { Widget build(BuildContext context, ref) { final groupValue = ref.watch(replaceDownloadedFileState); - return AlertDialog( + return PlatformAlertDialog( title: Text("Track ${track.name} Already Exists"), content: Column( mainAxisSize: MainAxisSize.min, @@ -48,20 +48,23 @@ class ReplaceDownloadedFileDialog extends ConsumerWidget { ), ], ), - actions: [ - PlatformTextButton( - child: const Text("No"), - onPressed: () { - Navigator.pop(context, false); - }, - ), - PlatformTextButton( + primaryActions: [ + PlatformFilledButton( child: const Text("Yes"), onPressed: () { Navigator.pop(context, true); }, ) ], + secondaryActions: [ + PlatformFilledButton( + isSecondary: true, + child: const Text("No"), + onPressed: () { + Navigator.pop(context, false); + }, + ), + ], ); } } diff --git a/lib/components/Shared/TrackTile.dart b/lib/components/Shared/TrackTile.dart index 8250e768..dedcb1bc 100644 --- a/lib/components/Shared/TrackTile.dart +++ b/lib/components/Shared/TrackTile.dart @@ -84,81 +84,79 @@ class TrackTile extends HookConsumerWidget { } Future actionAddToPlaylist() async { - showDialog( - context: context, - builder: (context) { - return FutureBuilder>( - future: spotify.playlists.me.all().then((playlists) async { - final me = await spotify.me.get(); - return playlists.where((playlist) => - playlist.owner?.id != null && - playlist.owner!.id == me.id); - }), - builder: (context, snapshot) { - return HookBuilder(builder: (context) { - final playlistsCheck = useState({}); - return AlertDialog( - title: PlatformText( - "Add `${track.value.name}` to following Playlists"), - titleTextStyle: - Theme.of(context).textTheme.bodyText1?.copyWith( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - actions: [ - PlatformTextButton( - child: const PlatformText("Cancel"), - onPressed: () => Navigator.pop(context), - ), - PlatformFilledButton( - child: const PlatformText("Add"), - onPressed: () async { - final selectedPlaylists = playlistsCheck - .value.entries - .where((entry) => entry.value) - .map((entry) => entry.key); + showPlatformAlertDialog(context, builder: (context) { + return FutureBuilder>( + future: spotify.playlists.me.all().then((playlists) async { + final me = await spotify.me.get(); + return playlists.where((playlist) => + playlist.owner?.id != null && playlist.owner!.id == me.id); + }), + builder: (context, snapshot) { + return HookBuilder(builder: (context) { + final playlistsCheck = useState({}); + return PlatformAlertDialog( + title: PlatformText( + "Add `${track.value.name}` to following Playlists", + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + secondaryActions: [ + PlatformFilledButton( + isSecondary: true, + child: const PlatformText("Cancel"), + onPressed: () => Navigator.pop(context), + ), + ], + primaryActions: [ + PlatformFilledButton( + child: const PlatformText("Add"), + onPressed: () async { + final selectedPlaylists = playlistsCheck.value.entries + .where((entry) => entry.value) + .map((entry) => entry.key); - await Future.wait( - selectedPlaylists.map( - (playlistId) => spotify.playlists - .addTrack(track.value.uri!, playlistId), - ), - ).then((_) => Navigator.pop(context)); - }, - ) - ], - content: SizedBox( - height: 300, - width: 300, - child: !snapshot.hasData - ? const Center( - child: PlatformCircularProgressIndicator()) - : ListView.builder( - shrinkWrap: true, - itemCount: snapshot.data!.length, - itemBuilder: (context, index) { - final playlist = - snapshot.data!.elementAt(index); - return CheckboxListTile( - title: PlatformText(playlist.name!), - controlAffinity: - ListTileControlAffinity.leading, - value: playlistsCheck.value[playlist.id] ?? - false, - onChanged: (val) { - playlistsCheck.value = { - ...playlistsCheck.value, - playlist.id!: val == true - }; - }, - ); + await Future.wait( + selectedPlaylists.map( + (playlistId) => spotify.playlists + .addTrack(track.value.uri!, playlistId), + ), + ).then((_) => Navigator.pop(context)); + }, + ) + ], + content: SizedBox( + height: 300, + width: 300, + child: !snapshot.hasData + ? const Center( + child: PlatformCircularProgressIndicator()) + : ListView.builder( + shrinkWrap: true, + itemCount: snapshot.data!.length, + itemBuilder: (context, index) { + final playlist = snapshot.data!.elementAt(index); + return CheckboxListTile( + title: PlatformText(playlist.name!), + controlAffinity: + ListTileControlAffinity.leading, + value: + playlistsCheck.value[playlist.id] ?? false, + onChanged: (val) { + playlistsCheck.value = { + ...playlistsCheck.value, + playlist.id!: val == true + }; }, - ), - ), - ); - }); - }); - }); + ); + }, + ), + ), + ); + }); + }); + }); } final String thumbnailUrl = TypeConversionUtils.image_X_UrlString( diff --git a/lib/components/Shared/TracksTableView.dart b/lib/components/Shared/TracksTableView.dart index 05922eb9..1dca965f 100644 --- a/lib/components/Shared/TracksTableView.dart +++ b/lib/components/Shared/TracksTableView.dart @@ -146,11 +146,10 @@ class TracksTableView extends HookConsumerWidget { switch (action) { case "download": { - final isConfirmed = await showDialog( - context: context, - builder: (context) { - return const DownloadConfirmationDialog(); - }); + final isConfirmed = await showPlatformAlertDialog( + context, builder: (context) { + return const DownloadConfirmationDialog(); + }); if (isConfirmed != true) return; for (final selectedTrack in selectedTracks) { downloader.addToQueue(selectedTrack); diff --git a/lib/hooks/useUpdateChecker.dart b/lib/hooks/useUpdateChecker.dart index f0648a55..8105b119 100644 --- a/lib/hooks/useUpdateChecker.dart +++ b/lib/hooks/useUpdateChecker.dart @@ -52,41 +52,39 @@ void useUpdateChecker(WidgetRef ref) { final latestVersion = value.last; if (currentVersion == null || latestVersion == null) return; if (latestVersion <= currentVersion) return; - showDialog( - context: context, - builder: (context) { - const url = - "https://spotube.netlify.app/other-downloads/stable-downloads"; - return AlertDialog( - title: const Text("Spotube has an update"), - actions: [ - PlatformFilledButton( - child: const Text("Download Now"), - onPressed: () => download(url), - ), - ], - content: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, + showPlatformAlertDialog(context, builder: (context) { + const url = + "https://spotube.netlify.app/other-downloads/stable-downloads"; + return PlatformAlertDialog( + title: const PlatformText("Spotube has an update"), + primaryActions: [ + PlatformFilledButton( + child: const Text("Download Now"), + onPressed: () => download(url), + ), + ], + content: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text("Spotube v${value.last} has been released"), + Row( children: [ - Text("Spotube v${value.last} has been released"), - Row( - children: [ - const Text("Read the latest "), - AnchorButton( - "release notes", - style: const TextStyle(color: Colors.blue), - onTap: () => launchUrlString( - url, - mode: LaunchMode.externalApplication, - ), - ), - ], + const PlatformText("Read the latest "), + AnchorButton( + "release notes", + style: const TextStyle(color: Colors.blue), + onTap: () => launchUrlString( + url, + mode: LaunchMode.externalApplication, + ), ), ], ), - ); - }); + ], + ), + ); + }); }); return null; }, [packageInfo, isCheckUpdateEnabled]); diff --git a/lib/main.dart b/lib/main.dart index cdc1260e..0d7dbbe4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -109,8 +109,8 @@ void main() async { logger.v( "[onFileExists] download confirmation for ${track.name}", ); - return showDialog( - context: context, + return showPlatformAlertDialog( + context, builder: (_) => ReplaceDownloadedFileDialog(track: track), ).then((s) => s ?? false); @@ -201,7 +201,7 @@ class SpotubeState extends ConsumerState with WidgetsBindingObserver { }; }, []); - platform = TargetPlatform.macOS; + platform = TargetPlatform.windows; return PlatformApp.router( routeInformationParser: router.routeInformationParser, @@ -217,7 +217,7 @@ class SpotubeState extends ConsumerState with WidgetsBindingObserver { accentMaterialColor: accentMaterialColor, backgroundMaterialColor: backgroundMaterialColor, ), - iosTheme: iosTheme, + iosTheme: themeMode == ThemeMode.dark ? iosDarkTheme : iosTheme, windowsTheme: windowsTheme, windowsDarkTheme: windowsDarkTheme, macosTheme: macosTheme, diff --git a/lib/themes/light-theme.dart b/lib/themes/light-theme.dart index 5a9d5590..0b4ab77e 100644 --- a/lib/themes/light-theme.dart +++ b/lib/themes/light-theme.dart @@ -147,4 +147,5 @@ final macosDarkTheme = MacosThemeData.dark().copyWith( iconTheme: const MacosIconThemeData(size: 14), typography: MacosTypography(color: MacosColors.textColor), ); -final iosTheme = CupertinoThemeData(); +const iosTheme = CupertinoThemeData(brightness: Brightness.light); +const iosDarkTheme = CupertinoThemeData(brightness: Brightness.dark);