mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-10-20 22:41:38 +02:00
refactor(ui): unify expressive actions and modal transitions
This commit is contained in:
1 parent
bd0b4a50c3
commit
1bae2e6b16
17 files changed
+70
-28
No files matched your search
@@ -1001,6 +1001,7 @@ class _ArtistScreenState extends ConsumerState<ArtistScreen>
|
||||
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
sheetAnimationStyle: AppMotion.surfaceEntrance(context),
|
||||
useRootNavigator: true,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: context.isMornye
|
||||
|
||||
@@ -430,6 +430,7 @@ extension _HomeTabExploreUI on _HomeTabState {
|
||||
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
sheetAnimationStyle: AppMotion.surfaceEntrance(context),
|
||||
useRootNavigator: true,
|
||||
backgroundColor: colorScheme.surface,
|
||||
builder: (context) => SafeArea(
|
||||
|
||||
@@ -177,6 +177,7 @@ extension _HomeTabSearchResultsUI on _HomeTabState {
|
||||
final mornye = context.isMornye;
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
sheetAnimationStyle: AppMotion.surfaceEntrance(context),
|
||||
useRootNavigator: true,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: mornye
|
||||
@@ -494,7 +495,8 @@ extension _HomeTabSearchResultsUI on _HomeTabState {
|
||||
if (showSortButton)
|
||||
SizedBox(
|
||||
height: 32,
|
||||
child: TextButton.icon(
|
||||
child: ExpressiveButton(
|
||||
text: true,
|
||||
onPressed: () => _showSortOptions(colorScheme),
|
||||
icon: mornye
|
||||
? null
|
||||
@@ -507,7 +509,11 @@ extension _HomeTabSearchResultsUI on _HomeTabState {
|
||||
? colorScheme.primary
|
||||
: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
label: Text(
|
||||
style: TextButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
child: Text(
|
||||
_searchSortOption != HomeSearchSortOption.defaultOrder
|
||||
? _sortOptionLabel(_searchSortOption)
|
||||
: context.l10n.libraryFilterSort,
|
||||
@@ -519,10 +525,6 @@ extension _HomeTabSearchResultsUI on _HomeTabState {
|
||||
: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
style: TextButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -309,10 +309,10 @@ extension _QueueTabNavigation on _QueueTabState {
|
||||
final controller = TextEditingController();
|
||||
final formKey = GlobalKey<FormState>();
|
||||
|
||||
final playlistName = await showDialog<String>(
|
||||
final playlistName = await showAppDialog<String>(
|
||||
context: context,
|
||||
builder: (dialogContext) {
|
||||
return AlertDialog(
|
||||
return AppAlertDialog(
|
||||
title: Text(dialogContext.l10n.collectionCreatePlaylist),
|
||||
content: Form(
|
||||
key: formKey,
|
||||
@@ -336,12 +336,12 @@ extension _QueueTabNavigation on _QueueTabState {
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
ExpressiveButton(
|
||||
text: true,
|
||||
AppDialogAction(
|
||||
onPressed: () => Navigator.of(dialogContext).pop(),
|
||||
child: Text(dialogContext.l10n.dialogCancel),
|
||||
),
|
||||
ExpressiveButton(
|
||||
AppDialogAction(
|
||||
filled: true,
|
||||
onPressed: () {
|
||||
if (formKey.currentState?.validate() != true) return;
|
||||
Navigator.of(dialogContext).pop(controller.text.trim());
|
||||
|
||||
@@ -438,6 +438,7 @@ class _SetupScreenState extends ConsumerState<SetupScreen>
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
await showModalBottomSheet<void>(
|
||||
context: context,
|
||||
sheetAnimationStyle: AppMotion.surfaceEntrance(context),
|
||||
useRootNavigator: true,
|
||||
backgroundColor: colorScheme.surfaceContainerHigh,
|
||||
builder: (ctx) => SafeArea(
|
||||
|
||||
@@ -56,6 +56,7 @@ extension _TrackMetadataFileActions on _TrackMetadataScreenState {
|
||||
|
||||
final saved = await showModalBottomSheet<bool>(
|
||||
context: context,
|
||||
sheetAnimationStyle: AppMotion.surfaceEntrance(context),
|
||||
useRootNavigator: true,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: context.isMornye
|
||||
|
||||
@@ -281,6 +281,7 @@ extension _TrackMetadataConvertAndCueSplit on _TrackMetadataScreenState {
|
||||
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
sheetAnimationStyle: AppMotion.surfaceEntrance(context),
|
||||
useRootNavigator: true,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: context.isMornye ? Colors.transparent : null,
|
||||
@@ -382,6 +383,7 @@ extension _TrackMetadataConvertAndCueSplit on _TrackMetadataScreenState {
|
||||
|
||||
showModalBottomSheet<void>(
|
||||
context: this.context,
|
||||
sheetAnimationStyle: AppMotion.surfaceEntrance(this.context),
|
||||
useRootNavigator: true,
|
||||
isScrollControlled: true,
|
||||
builder: (sheetContext) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:spotiflac_android/controllers/metadata_editor_controller.dart';
|
||||
import 'package:spotiflac_android/l10n/l10n.dart';
|
||||
import 'package:spotiflac_android/theme/app_motion.dart';
|
||||
import 'package:spotiflac_android/providers/extension_provider.dart';
|
||||
import 'package:spotiflac_android/providers/settings_provider.dart';
|
||||
import 'package:spotiflac_android/services/metadata_cover_resources.dart';
|
||||
@@ -120,6 +121,7 @@ class _EditMetadataSheetState extends State<EditMetadataSheet> {
|
||||
FocusScope.of(context).unfocus();
|
||||
final selectedId = await showModalBottomSheet<String>(
|
||||
context: context,
|
||||
sheetAnimationStyle: AppMotion.surfaceEntrance(context),
|
||||
useRootNavigator: true,
|
||||
isScrollControlled: true,
|
||||
showDragHandle: true,
|
||||
@@ -202,6 +204,7 @@ class _EditMetadataSheetState extends State<EditMetadataSheet> {
|
||||
final currentValue = _coverMaxDimension ?? 0;
|
||||
final selectedValue = await showModalBottomSheet<int>(
|
||||
context: context,
|
||||
sheetAnimationStyle: AppMotion.surfaceEntrance(context),
|
||||
useRootNavigator: true,
|
||||
isScrollControlled: true,
|
||||
showDragHandle: true,
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:ui' show ImageFilter;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:spotiflac_android/theme/app_motion.dart';
|
||||
import 'package:spotiflac_android/widgets/app_alert_dialog.dart';
|
||||
import 'package:flutter/cupertino.dart' show CupertinoButton, CupertinoIcons;
|
||||
import 'package:spotiflac_android/widgets/app_bottom_sheet.dart';
|
||||
|
||||
@@ -268,6 +268,7 @@ extension _TrackMetadataMenu on _TrackMetadataScreenState {
|
||||
}
|
||||
showModalBottomSheet<void>(
|
||||
context: screenContext,
|
||||
sheetAnimationStyle: AppMotion.surfaceEntrance(screenContext),
|
||||
useRootNavigator: true,
|
||||
backgroundColor: colorScheme.surfaceContainerHigh,
|
||||
isScrollControlled: true,
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:spotiflac_android/l10n/l10n.dart';
|
||||
import 'package:spotiflac_android/theme/app_motion.dart';
|
||||
import 'package:spotiflac_android/models/unified_library_item.dart';
|
||||
import 'package:spotiflac_android/providers/download_history_provider.dart';
|
||||
import 'package:spotiflac_android/providers/local_library_provider.dart';
|
||||
@@ -97,6 +98,7 @@ Future<void> showBatchConvertSheet(
|
||||
|
||||
await showModalBottomSheet<void>(
|
||||
context: modalContext,
|
||||
sheetAnimationStyle: AppMotion.surfaceEntrance(modalContext),
|
||||
useRootNavigator: true,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: modalContext.isMornye ? Colors.transparent : null,
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'package:spotiflac_android/services/app_navigation_service.dart';
|
||||
import 'package:spotiflac_android/services/platform_bridge.dart';
|
||||
import 'package:spotiflac_android/utils/extension_session_callback.dart';
|
||||
import 'package:spotiflac_android/utils/logger.dart';
|
||||
import 'package:spotiflac_android/widgets/app_alert_dialog.dart';
|
||||
import 'package:spotiflac_android/widgets/app_loading_indicator.dart';
|
||||
import 'package:spotiflac_android/widgets/expressive_button.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
@@ -298,15 +299,14 @@ Future<bool> showExtensionVerificationHelpDialog(
|
||||
});
|
||||
|
||||
try {
|
||||
await showDialog<void>(
|
||||
await showAppDialog<void>(
|
||||
context: context,
|
||||
useRootNavigator: true,
|
||||
barrierDismissible: false,
|
||||
builder: (dialogContext) {
|
||||
activeDialogContext = dialogContext;
|
||||
final dialogL10n = dialogContext.l10n;
|
||||
return StatefulBuilder(
|
||||
builder: (dialogContext, setDialogState) => AlertDialog(
|
||||
builder: (dialogContext, setDialogState) => AppAlertDialog(
|
||||
title: Text(title),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
||||
@@ -2,7 +2,9 @@ import 'package:flutter/material.dart';
|
||||
import 'package:spotiflac_android/l10n/l10n.dart';
|
||||
import 'package:spotiflac_android/models/artist_concert.dart';
|
||||
import 'package:spotiflac_android/screens/artist_concerts_screen.dart';
|
||||
import 'package:spotiflac_android/theme/mornye_theme.dart';
|
||||
import 'package:spotiflac_android/widgets/animation_utils.dart';
|
||||
import 'package:spotiflac_android/widgets/expressive_button.dart';
|
||||
|
||||
class ArtistConcertsButton extends StatelessWidget {
|
||||
const ArtistConcertsButton({
|
||||
@@ -21,17 +23,36 @@ class ArtistConcertsButton extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (concerts.isEmpty) return const SizedBox.shrink();
|
||||
return TextButton.icon(
|
||||
onPressed: () => Navigator.of(context).push(
|
||||
slidePageRoute<void>(
|
||||
page: ArtistConcertsScreen(
|
||||
artistName: artistName,
|
||||
concerts: concerts,
|
||||
coverUrl: coverUrl,
|
||||
providerId: providerId,
|
||||
),
|
||||
void open() => Navigator.of(context).push(
|
||||
slidePageRoute<void>(
|
||||
page: ArtistConcertsScreen(
|
||||
artistName: artistName,
|
||||
concerts: concerts,
|
||||
coverUrl: coverUrl,
|
||||
providerId: providerId,
|
||||
),
|
||||
),
|
||||
);
|
||||
final label = Text(
|
||||
context.l10n.artistUpcomingConcerts,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
);
|
||||
if (!context.isMornye) {
|
||||
// A compact tonal pill with the expressive press morph.
|
||||
return ExpressiveButton(
|
||||
tonal: true,
|
||||
onPressed: open,
|
||||
icon: const Icon(Icons.confirmation_number_rounded, size: 16),
|
||||
style: FilledButton.styleFrom(
|
||||
minimumSize: const Size(0, 36),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14),
|
||||
),
|
||||
child: label,
|
||||
);
|
||||
}
|
||||
return TextButton.icon(
|
||||
onPressed: open,
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: Colors.white,
|
||||
backgroundColor: Colors.black.withValues(alpha: 0.35),
|
||||
@@ -45,11 +66,7 @@ class ArtistConcertsButton extends StatelessWidget {
|
||||
textStyle: const TextStyle(fontSize: 13, fontWeight: FontWeight.w600),
|
||||
),
|
||||
icon: const Icon(Icons.confirmation_number_rounded, size: 16),
|
||||
label: Text(
|
||||
context.l10n.artistUpcomingConcerts,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
label: label,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:spotiflac_android/providers/extension_provider.dart';
|
||||
import 'package:spotiflac_android/theme/app_motion.dart';
|
||||
import 'package:spotiflac_android/providers/settings_provider.dart';
|
||||
import 'package:spotiflac_android/l10n/l10n.dart';
|
||||
import 'package:spotiflac_android/theme/mornye_icons.dart';
|
||||
@@ -44,6 +45,7 @@ class DownloadServicePicker extends ConsumerStatefulWidget {
|
||||
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
sheetAnimationStyle: AppMotion.surfaceEntrance(context),
|
||||
useRootNavigator: true,
|
||||
backgroundColor: mornye
|
||||
? Colors.transparent
|
||||
@@ -57,7 +59,9 @@ class DownloadServicePicker extends ConsumerStatefulWidget {
|
||||
: null,
|
||||
isScrollControlled: true,
|
||||
showDragHandle: !mornye,
|
||||
// Explicit constraints replace the theme's, so repeat its tablet width.
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: 640,
|
||||
maxHeight: MediaQuery.sizeOf(context).height * 0.88,
|
||||
),
|
||||
builder: (context) {
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:audio_service/audio_service.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:spotiflac_android/controllers/player_metadata_controller.dart';
|
||||
import 'package:spotiflac_android/l10n/l10n.dart';
|
||||
import 'package:spotiflac_android/theme/app_motion.dart';
|
||||
import 'package:spotiflac_android/theme/mornye_theme.dart';
|
||||
import 'package:spotiflac_android/utils/isrc_utils.dart';
|
||||
import 'package:spotiflac_android/widgets/app_icon.dart';
|
||||
@@ -19,6 +20,7 @@ Future<void> showPlayerDetailsSheet(
|
||||
final metadataFuture = metadata.readDetails(mediaItem);
|
||||
return showModalBottomSheet<void>(
|
||||
context: context,
|
||||
sheetAnimationStyle: AppMotion.surfaceEntrance(context),
|
||||
isScrollControlled: true,
|
||||
useRootNavigator: mornye,
|
||||
showDragHandle: !mornye,
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:spotiflac_android/l10n/l10n.dart';
|
||||
import 'package:spotiflac_android/theme/app_motion.dart';
|
||||
import 'package:spotiflac_android/models/track.dart';
|
||||
import 'package:spotiflac_android/providers/library_collections_provider.dart';
|
||||
import 'package:spotiflac_android/theme/mornye_theme.dart';
|
||||
@@ -39,6 +40,7 @@ Future<void> showAddTracksToPlaylistSheet(
|
||||
|
||||
await showModalBottomSheet<void>(
|
||||
context: context,
|
||||
sheetAnimationStyle: AppMotion.surfaceEntrance(context),
|
||||
useRootNavigator: true,
|
||||
showDragHandle: !context.isMornye,
|
||||
backgroundColor: context.isMornye ? Colors.transparent : null,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:spotiflac_android/theme/app_motion.dart';
|
||||
import 'package:spotiflac_android/theme/mornye_theme.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:spotiflac_android/widgets/app_bottom_sheet.dart';
|
||||
@@ -49,6 +50,7 @@ class TrackCollectionQuickActions extends ConsumerWidget {
|
||||
}
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
sheetAnimationStyle: AppMotion.surfaceEntrance(context),
|
||||
useRootNavigator: true,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: colorScheme.surfaceContainerHigh,
|
||||
|
||||
Reference in new issue
Block a user