fix(download): allow dragging the quality picker to dismiss

This commit is contained in:
zarzet
2026-09-07 00:47:15 +07:00
parent 7556d64596
commit 40546f48e6
2 changed files with 99 additions and 9 deletions
+14 -9
View File
@@ -13,6 +13,7 @@ class DownloadServicePicker extends ConsumerStatefulWidget {
final String? coverUrl;
final void Function(String quality, String service) onSelect;
final String? recommendedService;
final ScrollController? scrollController;
const DownloadServicePicker({
super.key,
@@ -21,6 +22,7 @@ class DownloadServicePicker extends ConsumerStatefulWidget {
this.coverUrl,
required this.onSelect,
this.recommendedService,
this.scrollController,
});
@override
@@ -42,15 +44,15 @@ class DownloadServicePicker extends ConsumerStatefulWidget {
useRootNavigator: true,
backgroundColor: colorScheme.surfaceContainerHigh,
isScrollControlled: true,
constraints: BoxConstraints(
maxHeight: MediaQuery.sizeOf(context).height * 0.88,
),
builder: (context) => DownloadServicePicker(
trackName: trackName,
artistName: artistName,
coverUrl: coverUrl,
onSelect: onSelect,
recommendedService: recommendedService,
builder: (context) => AppDraggableSheet(
builder: (context, scrollController) => DownloadServicePicker(
trackName: trackName,
artistName: artistName,
coverUrl: coverUrl,
onSelect: onSelect,
recommendedService: recommendedService,
scrollController: scrollController,
),
),
);
}
@@ -122,7 +124,10 @@ class _DownloadServicePickerState extends ConsumerState<DownloadServicePicker> {
final qualityOptions = _getQualityOptions(downloadExtensions);
return SafeArea(
top: false,
child: SingleChildScrollView(
controller: widget.scrollController,
physics: const ClampingScrollPhysics(),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
@@ -0,0 +1,85 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:spotiflac_android/l10n/app_localizations.dart';
import 'package:spotiflac_android/models/settings.dart';
import 'package:spotiflac_android/providers/extension_provider.dart';
import 'package:spotiflac_android/providers/settings_provider.dart';
import 'package:spotiflac_android/widgets/download_service_picker.dart';
class _Extensions extends ExtensionNotifier {
@override
ExtensionState build() => ExtensionState(
extensions: [
Extension(
id: 'example',
name: 'example',
displayName: 'Example',
version: '1.0.0',
description: '',
enabled: true,
status: 'loaded',
hasDownloadProvider: true,
qualityOptions: List.generate(
16,
(index) => QualityOption(id: '$index', label: 'Quality $index'),
),
),
],
);
@override
void refreshEnabledExtensionHealth({bool force = false}) {}
}
class _Settings extends SettingsNotifier {
@override
AppSettings build() => const AppSettings();
}
void main() {
testWidgets('iOS picker scrolls options and dismisses when pulled down', (
tester,
) async {
await tester.pumpWidget(
ProviderScope(
overrides: [
extensionProvider.overrideWith(_Extensions.new),
settingsProvider.overrideWith(_Settings.new),
],
child: MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: Scaffold(
body: Builder(
builder: (context) => TextButton(
onPressed: () => DownloadServicePicker.show(
context,
trackName: 'Example track',
onSelect: (_, _) {},
),
child: const Text('Open'),
),
),
),
),
),
);
await tester.tap(find.text('Open'));
await tester.pumpAndSettle();
final scroll = find.descendant(
of: find.byType(DownloadServicePicker),
matching: find.byType(SingleChildScrollView),
);
await tester.drag(scroll, const Offset(0, -300));
await tester.pumpAndSettle();
expect(find.byType(DownloadServicePicker), findsOneWidget);
await tester.drag(scroll, const Offset(0, 1500));
await tester.pumpAndSettle();
await tester.drag(find.text('Example track'), const Offset(0, 600));
await tester.pumpAndSettle();
expect(find.byType(DownloadServicePicker), findsNothing);
expect(tester.takeException(), isNull);
});
}