refactor: platform alert dialog for all dialogs

This commit is contained in:
Kingkor Roy Tirtho 2022-11-03 09:12:43 +06:00
parent e086b520e7
commit c201624f99
15 changed files with 194 additions and 182 deletions

View File

@ -3,6 +3,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.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/Sidebar.dart';
import 'package:spotube/components/Home/SpotubeNavigationBar.dart'; import 'package:spotube/components/Home/SpotubeNavigationBar.dart';
import 'package:spotube/components/Player/Player.dart'; import 'package:spotube/components/Player/Player.dart';
@ -35,8 +36,8 @@ class Shell extends HookConsumerWidget {
useEffect(() { useEffect(() {
downloader.onFileExists = (track) async { downloader.onFileExists = (track) async {
if (!isMounted()) return false; if (!isMounted()) return false;
return await showDialog<bool>( return await showPlatformAlertDialog<bool>(
context: context, context,
builder: (context) => ReplaceDownloadedFileDialog( builder: (context) => ReplaceDownloadedFileDialog(
track: track, track: track,
), ),

View File

@ -31,14 +31,14 @@ class UserDownloads extends HookConsumerWidget {
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
PlatformFilledButton( PlatformFilledButton(
style: ElevatedButton.styleFrom( style: ButtonStyle(
backgroundColor: Colors.red[50], backgroundColor: MaterialStatePropertyAll(Colors.red[50]),
foregroundColor: Colors.red[400], foregroundColor: MaterialStatePropertyAll(Colors.red[400]),
), ),
onPressed: downloader.currentlyRunning > 0 onPressed: downloader.currentlyRunning > 0
? downloader.cancelAll ? downloader.cancelAll
: null, : null,
macOSIsSecondary: true, isSecondary: true,
child: const PlatformText("Cancel All"), child: const PlatformText("Cancel All"),
), ),
], ],
@ -50,7 +50,7 @@ class UserDownloads extends HookConsumerWidget {
itemBuilder: (context, index) { itemBuilder: (context, index) {
final track = downloader.inQueue.elementAt(index); final track = downloader.inQueue.elementAt(index);
return PlatformListTile( return PlatformListTile(
title: Text(track.name!), title: Text(track.name ?? ''),
leading: Padding( leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5), padding: const EdgeInsets.symmetric(horizontal: 5),
child: ClipRRect( child: ClipRRect(

View File

@ -16,15 +16,18 @@ class LyricDelayAdjustDialog extends HookConsumerWidget {
double getValue() => double getValue() =>
double.tryParse(controller.text.replaceAll("ms", "")) ?? 0; double.tryParse(controller.text.replaceAll("ms", "")) ?? 0;
return AlertDialog( return PlatformAlertDialog(
title: const Center(child: Text("Adjust Lyrics Delay")), title: const Center(child: Text("Adjust Lyrics Delay")),
actions: [ secondaryActions: [
PlatformFilledButton( PlatformFilledButton(
child: const Text("Cancel"), isSecondary: true,
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
child: const Text("Cancel"),
), ),
],
primaryActions: [
PlatformFilledButton( PlatformFilledButton(
child: const Text("Done"), child: const Text("Done"),
onPressed: () { onPressed: () {

View File

@ -90,8 +90,8 @@ class SyncedLyrics extends HookConsumerWidget {
tooltip: "Lyrics Delay", tooltip: "Lyrics Delay",
icon: const Icon(Icons.av_timer_rounded), icon: const Icon(Icons.av_timer_rounded),
onPressed: () async { onPressed: () async {
final delay = await showDialog( final delay = await showPlatformAlertDialog(
context: context, context,
builder: (context) => const LyricDelayAdjustDialog(), builder: (context) => const LyricDelayAdjustDialog(),
); );
if (delay != null) { if (delay != null) {

View File

@ -15,8 +15,8 @@ class PlaylistCreateDialog extends HookConsumerWidget {
return PlatformTextButton( return PlatformTextButton(
onPressed: () { onPressed: () {
showDialog( showPlatformAlertDialog(
context: context, context,
builder: (context) { builder: (context) {
return HookBuilder(builder: (context) { return HookBuilder(builder: (context) {
final playlistName = useTextEditingController(); final playlistName = useTextEditingController();
@ -24,13 +24,9 @@ class PlaylistCreateDialog extends HookConsumerWidget {
final public = useState(false); final public = useState(false);
final collaborative = useState(false); final collaborative = useState(false);
return AlertDialog( return PlatformAlertDialog(
title: const Text("Create a Playlist"), title: const Text("Create a Playlist"),
actions: [ primaryActions: [
PlatformTextButton(
child: const Text("Cancel"),
onPressed: () => Navigator.of(context).pop(),
),
PlatformFilledButton( PlatformFilledButton(
child: const Text("Create"), child: const Text("Create"),
onPressed: () async { 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( content: Container(
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
constraints: const BoxConstraints(maxWidth: 500), constraints: const BoxConstraints(maxWidth: 500),

View File

@ -66,15 +66,9 @@ class ColorSchemePickerDialog extends HookConsumerWidget {
}, },
).key); ).key);
return AlertDialog( return PlatformAlertDialog(
title: Text("Pick ${schemeType.name} color scheme"), title: Text("Pick ${schemeType.name} color scheme"),
actions: [ primaryActions: [
PlatformTextButton(
child: const Text("Cancel"),
onPressed: () {
Navigator.pop(context);
},
),
PlatformFilledButton( PlatformFilledButton(
child: const Text("Save"), child: const Text("Save"),
onPressed: () { onPressed: () {
@ -91,6 +85,15 @@ class ColorSchemePickerDialog extends HookConsumerWidget {
}, },
) )
], ],
secondaryActions: [
PlatformFilledButton(
isSecondary: true,
child: const Text("Cancel"),
onPressed: () {
Navigator.pop(context);
},
),
],
content: SizedBox( content: SizedBox(
height: 200, height: 200,
width: 400, width: 400,

View File

@ -28,9 +28,7 @@ class Settings extends HookConsumerWidget {
final Auth auth = ref.watch(authProvider); final Auth auth = ref.watch(authProvider);
final pickColorScheme = useCallback((ColorSchemeType schemeType) { final pickColorScheme = useCallback((ColorSchemeType schemeType) {
return () => showDialog( return () => showPlatformAlertDialog(context, builder: (context) {
context: context,
builder: (context) {
return ColorSchemePickerDialog( return ColorSchemePickerDialog(
schemeType: schemeType, schemeType: schemeType,
); );

View File

@ -34,11 +34,11 @@ class AdaptiveListTile extends HookWidget {
onTap: breakpoint.isLessThan(breakOn) onTap: breakpoint.isLessThan(breakOn)
? () { ? () {
onTap?.call(); onTap?.call();
showDialog( showPlatformAlertDialog(
context: context, context,
builder: (context) { builder: (context) {
return StatefulBuilder(builder: (context, update) { return StatefulBuilder(builder: (context, update) {
return AlertDialog( return PlatformAlertDialog(
title: title != null title: title != null
? Row( ? Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
@ -50,7 +50,7 @@ class AdaptiveListTile extends HookWidget {
Flexible(child: title!), Flexible(child: title!),
], ],
) )
: null, : Container(),
content: trailing?.call(context, update), content: trailing?.call(context, update),
); );
}); });

View File

@ -7,9 +7,10 @@ class DownloadConfirmationDialog extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AlertDialog( return PlatformAlertDialog(
contentPadding: const EdgeInsets.all(15), title: Padding(
title: Row( padding: const EdgeInsets.all(15),
child: Row(
children: const [ children: const [
Text("Are you sure?"), Text("Are you sure?"),
SizedBox(width: 10), SizedBox(width: 10),
@ -21,8 +22,9 @@ class DownloadConfirmationDialog extends StatelessWidget {
) )
], ],
), ),
content: ConstrainedBox( ),
constraints: const BoxConstraints(maxWidth: 400), content: Padding(
padding: const EdgeInsets.all(15),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -57,19 +59,22 @@ class DownloadConfirmationDialog extends StatelessWidget {
), ),
), ),
), ),
actions: [ primaryActions: [
PlatformFilledButton( 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"), child: const Text("Decline"),
onPressed: () => Navigator.of(context).pop(false), 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"),
)
], ],
); );
} }

View File

@ -14,7 +14,7 @@ class ReplaceDownloadedFileDialog extends ConsumerWidget {
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final groupValue = ref.watch(replaceDownloadedFileState); final groupValue = ref.watch(replaceDownloadedFileState);
return AlertDialog( return PlatformAlertDialog(
title: Text("Track ${track.name} Already Exists"), title: Text("Track ${track.name} Already Exists"),
content: Column( content: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -48,20 +48,23 @@ class ReplaceDownloadedFileDialog extends ConsumerWidget {
), ),
], ],
), ),
actions: [ primaryActions: [
PlatformTextButton( PlatformFilledButton(
child: const Text("No"),
onPressed: () {
Navigator.pop(context, false);
},
),
PlatformTextButton(
child: const Text("Yes"), child: const Text("Yes"),
onPressed: () { onPressed: () {
Navigator.pop(context, true); Navigator.pop(context, true);
}, },
) )
], ],
secondaryActions: [
PlatformFilledButton(
isSecondary: true,
child: const Text("No"),
onPressed: () {
Navigator.pop(context, false);
},
),
],
); );
} }
} }

View File

@ -84,37 +84,36 @@ class TrackTile extends HookConsumerWidget {
} }
Future<void> actionAddToPlaylist() async { Future<void> actionAddToPlaylist() async {
showDialog( showPlatformAlertDialog(context, builder: (context) {
context: context,
builder: (context) {
return FutureBuilder<Iterable<PlaylistSimple>>( return FutureBuilder<Iterable<PlaylistSimple>>(
future: spotify.playlists.me.all().then((playlists) async { future: spotify.playlists.me.all().then((playlists) async {
final me = await spotify.me.get(); final me = await spotify.me.get();
return playlists.where((playlist) => return playlists.where((playlist) =>
playlist.owner?.id != null && playlist.owner?.id != null && playlist.owner!.id == me.id);
playlist.owner!.id == me.id);
}), }),
builder: (context, snapshot) { builder: (context, snapshot) {
return HookBuilder(builder: (context) { return HookBuilder(builder: (context) {
final playlistsCheck = useState(<String, bool>{}); final playlistsCheck = useState(<String, bool>{});
return AlertDialog( return PlatformAlertDialog(
title: PlatformText( title: PlatformText(
"Add `${track.value.name}` to following Playlists"), "Add `${track.value.name}` to following Playlists",
titleTextStyle: style: const TextStyle(
Theme.of(context).textTheme.bodyText1?.copyWith(
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
actions: [ ),
PlatformTextButton( secondaryActions: [
PlatformFilledButton(
isSecondary: true,
child: const PlatformText("Cancel"), child: const PlatformText("Cancel"),
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
), ),
],
primaryActions: [
PlatformFilledButton( PlatformFilledButton(
child: const PlatformText("Add"), child: const PlatformText("Add"),
onPressed: () async { onPressed: () async {
final selectedPlaylists = playlistsCheck final selectedPlaylists = playlistsCheck.value.entries
.value.entries
.where((entry) => entry.value) .where((entry) => entry.value)
.map((entry) => entry.key); .map((entry) => entry.key);
@ -137,14 +136,13 @@ class TrackTile extends HookConsumerWidget {
shrinkWrap: true, shrinkWrap: true,
itemCount: snapshot.data!.length, itemCount: snapshot.data!.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final playlist = final playlist = snapshot.data!.elementAt(index);
snapshot.data!.elementAt(index);
return CheckboxListTile( return CheckboxListTile(
title: PlatformText(playlist.name!), title: PlatformText(playlist.name!),
controlAffinity: controlAffinity:
ListTileControlAffinity.leading, ListTileControlAffinity.leading,
value: playlistsCheck.value[playlist.id] ?? value:
false, playlistsCheck.value[playlist.id] ?? false,
onChanged: (val) { onChanged: (val) {
playlistsCheck.value = { playlistsCheck.value = {
...playlistsCheck.value, ...playlistsCheck.value,

View File

@ -146,9 +146,8 @@ class TracksTableView extends HookConsumerWidget {
switch (action) { switch (action) {
case "download": case "download":
{ {
final isConfirmed = await showDialog( final isConfirmed = await showPlatformAlertDialog(
context: context, context, builder: (context) {
builder: (context) {
return const DownloadConfirmationDialog(); return const DownloadConfirmationDialog();
}); });
if (isConfirmed != true) return; if (isConfirmed != true) return;

View File

@ -52,14 +52,12 @@ void useUpdateChecker(WidgetRef ref) {
final latestVersion = value.last; final latestVersion = value.last;
if (currentVersion == null || latestVersion == null) return; if (currentVersion == null || latestVersion == null) return;
if (latestVersion <= currentVersion) return; if (latestVersion <= currentVersion) return;
showDialog( showPlatformAlertDialog(context, builder: (context) {
context: context,
builder: (context) {
const url = const url =
"https://spotube.netlify.app/other-downloads/stable-downloads"; "https://spotube.netlify.app/other-downloads/stable-downloads";
return AlertDialog( return PlatformAlertDialog(
title: const Text("Spotube has an update"), title: const PlatformText("Spotube has an update"),
actions: [ primaryActions: [
PlatformFilledButton( PlatformFilledButton(
child: const Text("Download Now"), child: const Text("Download Now"),
onPressed: () => download(url), onPressed: () => download(url),
@ -72,7 +70,7 @@ void useUpdateChecker(WidgetRef ref) {
Text("Spotube v${value.last} has been released"), Text("Spotube v${value.last} has been released"),
Row( Row(
children: [ children: [
const Text("Read the latest "), const PlatformText("Read the latest "),
AnchorButton( AnchorButton(
"release notes", "release notes",
style: const TextStyle(color: Colors.blue), style: const TextStyle(color: Colors.blue),

View File

@ -109,8 +109,8 @@ void main() async {
logger.v( logger.v(
"[onFileExists] download confirmation for ${track.name}", "[onFileExists] download confirmation for ${track.name}",
); );
return showDialog<bool>( return showPlatformAlertDialog<bool>(
context: context, context,
builder: (_) => builder: (_) =>
ReplaceDownloadedFileDialog(track: track), ReplaceDownloadedFileDialog(track: track),
).then((s) => s ?? false); ).then((s) => s ?? false);
@ -201,7 +201,7 @@ class SpotubeState extends ConsumerState<Spotube> with WidgetsBindingObserver {
}; };
}, []); }, []);
platform = TargetPlatform.macOS; platform = TargetPlatform.windows;
return PlatformApp.router( return PlatformApp.router(
routeInformationParser: router.routeInformationParser, routeInformationParser: router.routeInformationParser,
@ -217,7 +217,7 @@ class SpotubeState extends ConsumerState<Spotube> with WidgetsBindingObserver {
accentMaterialColor: accentMaterialColor, accentMaterialColor: accentMaterialColor,
backgroundMaterialColor: backgroundMaterialColor, backgroundMaterialColor: backgroundMaterialColor,
), ),
iosTheme: iosTheme, iosTheme: themeMode == ThemeMode.dark ? iosDarkTheme : iosTheme,
windowsTheme: windowsTheme, windowsTheme: windowsTheme,
windowsDarkTheme: windowsDarkTheme, windowsDarkTheme: windowsDarkTheme,
macosTheme: macosTheme, macosTheme: macosTheme,

View File

@ -147,4 +147,5 @@ final macosDarkTheme = MacosThemeData.dark().copyWith(
iconTheme: const MacosIconThemeData(size: 14), iconTheme: const MacosIconThemeData(size: 14),
typography: MacosTypography(color: MacosColors.textColor), typography: MacosTypography(color: MacosColors.textColor),
); );
final iosTheme = CupertinoThemeData(); const iosTheme = CupertinoThemeData(brightness: Brightness.light);
const iosDarkTheme = CupertinoThemeData(brightness: Brightness.dark);