fix(download): size quality picker to its content

This commit is contained in:
zarzet
2026-09-07 00:50:05 +07:00
parent 40546f48e6
commit 650af6e59d
2 changed files with 70 additions and 56 deletions
+10 -16
View File
@@ -1,7 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:spotiflac_android/widgets/app_bottom_sheet.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:spotiflac_android/providers/extension_provider.dart'; import 'package:spotiflac_android/providers/extension_provider.dart';
import 'package:spotiflac_android/providers/settings_provider.dart'; import 'package:spotiflac_android/providers/settings_provider.dart';
@@ -13,7 +12,6 @@ class DownloadServicePicker extends ConsumerStatefulWidget {
final String? coverUrl; final String? coverUrl;
final void Function(String quality, String service) onSelect; final void Function(String quality, String service) onSelect;
final String? recommendedService; final String? recommendedService;
final ScrollController? scrollController;
const DownloadServicePicker({ const DownloadServicePicker({
super.key, super.key,
@@ -22,7 +20,6 @@ class DownloadServicePicker extends ConsumerStatefulWidget {
this.coverUrl, this.coverUrl,
required this.onSelect, required this.onSelect,
this.recommendedService, this.recommendedService,
this.scrollController,
}); });
@override @override
@@ -44,15 +41,16 @@ class DownloadServicePicker extends ConsumerStatefulWidget {
useRootNavigator: true, useRootNavigator: true,
backgroundColor: colorScheme.surfaceContainerHigh, backgroundColor: colorScheme.surfaceContainerHigh,
isScrollControlled: true, isScrollControlled: true,
builder: (context) => AppDraggableSheet( showDragHandle: true,
builder: (context, scrollController) => DownloadServicePicker( constraints: BoxConstraints(
trackName: trackName, maxHeight: MediaQuery.sizeOf(context).height * 0.88,
artistName: artistName, ),
coverUrl: coverUrl, builder: (context) => DownloadServicePicker(
onSelect: onSelect, trackName: trackName,
recommendedService: recommendedService, artistName: artistName,
scrollController: scrollController, coverUrl: coverUrl,
), onSelect: onSelect,
recommendedService: recommendedService,
), ),
); );
} }
@@ -126,7 +124,6 @@ class _DownloadServicePickerState extends ConsumerState<DownloadServicePicker> {
return SafeArea( return SafeArea(
top: false, top: false,
child: SingleChildScrollView( child: SingleChildScrollView(
controller: widget.scrollController,
physics: const ClampingScrollPhysics(), physics: const ClampingScrollPhysics(),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@@ -142,8 +139,6 @@ class _DownloadServicePickerState extends ConsumerState<DownloadServicePicker> {
height: 1, height: 1,
color: colorScheme.outlineVariant.withValues(alpha: 0.5), color: colorScheme.outlineVariant.withValues(alpha: 0.5),
), ),
] else ...[
const AppSheetHandle(),
], ],
Padding( Padding(
@@ -513,7 +508,6 @@ class _TrackInfoHeaderState extends State<_TrackInfoHeader> {
), ),
child: Column( child: Column(
children: [ children: [
const AppSheetHandle(),
Padding( Padding(
padding: const EdgeInsets.fromLTRB(16, 12, 16, 12), padding: const EdgeInsets.fromLTRB(16, 12, 16, 12),
child: Row( child: Row(
+60 -40
View File
@@ -8,6 +8,10 @@ import 'package:spotiflac_android/providers/settings_provider.dart';
import 'package:spotiflac_android/widgets/download_service_picker.dart'; import 'package:spotiflac_android/widgets/download_service_picker.dart';
class _Extensions extends ExtensionNotifier { class _Extensions extends ExtensionNotifier {
_Extensions(this.qualityCount);
final int qualityCount;
@override @override
ExtensionState build() => ExtensionState( ExtensionState build() => ExtensionState(
extensions: [ extensions: [
@@ -21,7 +25,7 @@ class _Extensions extends ExtensionNotifier {
status: 'loaded', status: 'loaded',
hasDownloadProvider: true, hasDownloadProvider: true,
qualityOptions: List.generate( qualityOptions: List.generate(
16, qualityCount,
(index) => QualityOption(id: '$index', label: 'Quality $index'), (index) => QualityOption(id: '$index', label: 'Quality $index'),
), ),
), ),
@@ -38,48 +42,64 @@ class _Settings extends SettingsNotifier {
} }
void main() { void main() {
testWidgets('iOS picker scrolls options and dismisses when pulled down', ( for (final qualityCount in [3, 16]) {
tester, testWidgets('iOS picker fits $qualityCount options and handle dismisses', (
) async { tester,
await tester.pumpWidget( ) async {
ProviderScope( await tester.pumpWidget(
overrides: [ ProviderScope(
extensionProvider.overrideWith(_Extensions.new), overrides: [
settingsProvider.overrideWith(_Settings.new), extensionProvider.overrideWith(() => _Extensions(qualityCount)),
], settingsProvider.overrideWith(_Settings.new),
child: MaterialApp( ],
theme: ThemeData(platform: TargetPlatform.iOS), child: MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates, theme: ThemeData(platform: TargetPlatform.iOS),
supportedLocales: AppLocalizations.supportedLocales, localizationsDelegates: AppLocalizations.localizationsDelegates,
home: Scaffold( supportedLocales: AppLocalizations.supportedLocales,
body: Builder( home: Scaffold(
builder: (context) => TextButton( body: Builder(
onPressed: () => DownloadServicePicker.show( builder: (context) => TextButton(
context, onPressed: () => DownloadServicePicker.show(
trackName: 'Example track', context,
onSelect: (_, _) {}, trackName: 'Example track',
onSelect: (_, _) {},
),
child: const Text('Open'),
), ),
child: const Text('Open'),
), ),
), ),
), ),
), ),
), );
); await tester.tap(find.text('Open'));
await tester.tap(find.text('Open')); await tester.pumpAndSettle();
await tester.pumpAndSettle(); if (qualityCount == 3) {
final scroll = find.descendant( final sheetBottom = tester.getBottomLeft(find.byType(BottomSheet)).dy;
of: find.byType(DownloadServicePicker), final lastOptionBottom = tester
matching: find.byType(SingleChildScrollView), .getBottomLeft(find.text('Quality 2'))
); .dy;
await tester.drag(scroll, const Offset(0, -300)); expect(sheetBottom - lastOptionBottom, lessThan(100));
await tester.pumpAndSettle(); }
expect(find.byType(DownloadServicePicker), findsOneWidget); if (qualityCount == 16) {
await tester.drag(scroll, const Offset(0, 1500)); final scroll = find.descendant(
await tester.pumpAndSettle(); of: find.byType(DownloadServicePicker),
await tester.drag(find.text('Example track'), const Offset(0, 600)); matching: find.byType(SingleChildScrollView),
await tester.pumpAndSettle(); );
expect(find.byType(DownloadServicePicker), findsNothing); await tester.drag(scroll, const Offset(0, -300));
expect(tester.takeException(), isNull); await tester.pumpAndSettle();
}); expect(find.byType(DownloadServicePicker), findsOneWidget);
await tester.drag(scroll, const Offset(0, 1500));
await tester.pumpAndSettle();
}
final sheetTop = tester.getTopLeft(find.byType(BottomSheet));
final sheetWidth = tester.getSize(find.byType(BottomSheet)).width;
await tester.dragFrom(
sheetTop + Offset(sheetWidth / 2, 16),
const Offset(0, 600),
);
await tester.pumpAndSettle();
expect(find.byType(DownloadServicePicker), findsNothing);
expect(tester.takeException(), isNull);
});
}
} }