mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-09-18 15:52:30 +02:00
revert: remove download size estimates
This commit is contained in:
@@ -1,209 +0,0 @@
|
||||
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/models/track.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 _PickerExtensions extends ExtensionNotifier {
|
||||
@override
|
||||
ExtensionState build() => const ExtensionState(
|
||||
extensions: [
|
||||
Extension(
|
||||
id: 'provider-a',
|
||||
name: 'provider-a',
|
||||
displayName: 'Audio A',
|
||||
version: '1.0.0',
|
||||
description: '',
|
||||
enabled: true,
|
||||
status: 'loaded',
|
||||
hasDownloadProvider: true,
|
||||
qualityOptions: [
|
||||
QualityOption(id: 'LOSSLESS', label: 'Lossless'),
|
||||
QualityOption(id: 'HI_RES', label: 'Hi-Res'),
|
||||
QualityOption(id: 'HI_RES_LOSSLESS', label: 'Hi-Res'),
|
||||
],
|
||||
),
|
||||
Extension(
|
||||
id: 'provider-b',
|
||||
name: 'provider-b',
|
||||
displayName: 'Audio B',
|
||||
version: '1.0.0',
|
||||
description: '',
|
||||
enabled: true,
|
||||
status: 'loaded',
|
||||
hasDownloadProvider: true,
|
||||
qualityOptions: [
|
||||
QualityOption(id: 'opus_256', label: 'Opus 256kbps'),
|
||||
QualityOption(id: 'custom', label: 'Custom'),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
class _PickerSettings extends SettingsNotifier {
|
||||
final AppSettings _settings;
|
||||
|
||||
_PickerSettings(this._settings);
|
||||
|
||||
@override
|
||||
AppSettings build() => _settings;
|
||||
}
|
||||
|
||||
Future<void> _openPicker(
|
||||
WidgetTester tester, {
|
||||
Duration? duration,
|
||||
String? audioQuality = '16bit/44.1kHz',
|
||||
String? source = 'provider-a',
|
||||
AppSettings settings = const AppSettings(),
|
||||
Locale locale = const Locale('en'),
|
||||
double textScale = 1,
|
||||
void Function(String, String)? onSelect,
|
||||
}) async {
|
||||
await tester.pumpWidget(
|
||||
ProviderScope(
|
||||
overrides: [
|
||||
extensionProvider.overrideWith(_PickerExtensions.new),
|
||||
settingsProvider.overrideWith(() => _PickerSettings(settings)),
|
||||
],
|
||||
child: MaterialApp(
|
||||
locale: locale,
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
builder: (context, child) => MediaQuery(
|
||||
data: MediaQuery.of(
|
||||
context,
|
||||
).copyWith(textScaler: TextScaler.linear(textScale)),
|
||||
child: child!,
|
||||
),
|
||||
home: Scaffold(
|
||||
body: Builder(
|
||||
builder: (context) => TextButton(
|
||||
onPressed: () => DownloadServicePicker.show(
|
||||
context,
|
||||
trackName: 'Selected tracks',
|
||||
tracks: [
|
||||
Track(
|
||||
id: 'sample',
|
||||
name: 'Sample',
|
||||
artistName: 'Artist',
|
||||
albumName: 'Album',
|
||||
duration: duration?.inSeconds ?? 0,
|
||||
source: source,
|
||||
audioQuality: audioQuality,
|
||||
),
|
||||
],
|
||||
onSelect: onSelect ?? (_, _) {},
|
||||
),
|
||||
child: const Text('Open'),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.tap(find.text('Open'));
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
void main() {
|
||||
testWidgets('estimates change with the provider and selection stays intact', (
|
||||
tester,
|
||||
) async {
|
||||
(String, String)? selected;
|
||||
await _openPicker(
|
||||
tester,
|
||||
duration: const Duration(minutes: 4),
|
||||
onSelect: (quality, service) => selected = (quality, service),
|
||||
);
|
||||
expect(find.text('≈ 26.2 MB'), findsNWidgets(3));
|
||||
expect(find.textContaining('MB–'), findsNothing);
|
||||
await tester.tap(find.text('Audio B'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('≈ 7.3 MB'), findsOneWidget);
|
||||
expect(find.text('Size estimate unavailable'), findsOneWidget);
|
||||
expect(find.text('≈ 26.2 MB'), findsNothing);
|
||||
expect(find.textContaining('if 24-bit'), findsNothing);
|
||||
await tester.tap(find.text('Opus 256kbps'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(selected, ('opus_256', 'provider-b'));
|
||||
expect(find.byType(DownloadServicePicker), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'missing duration stays unknown and downloads remain selectable',
|
||||
(tester) async {
|
||||
await _openPicker(tester, locale: const Locale('id'));
|
||||
expect(find.text('Estimasi ukuran belum tersedia'), findsNWidgets(3));
|
||||
expect(find.textContaining('≈'), findsNothing);
|
||||
await tester.tap(find.text('FLAC Lossless'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byType(DownloadServicePicker), findsNothing);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets('metadata caps both hi-res tiers to the available sample rate', (
|
||||
tester,
|
||||
) async {
|
||||
await _openPicker(
|
||||
tester,
|
||||
duration: const Duration(minutes: 4),
|
||||
audioQuality: '24bit/96kHz',
|
||||
locale: const Locale('id'),
|
||||
);
|
||||
expect(find.text('≈ 85.7 MB'), findsNWidgets(2));
|
||||
expect(find.text('≈ 26.2 MB'), findsOneWidget);
|
||||
expect(find.textContaining('171.4'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('foreign or incomplete track quality stays unavailable', (
|
||||
tester,
|
||||
) async {
|
||||
await _openPicker(
|
||||
tester,
|
||||
duration: const Duration(minutes: 4),
|
||||
source: 'provider-b',
|
||||
);
|
||||
expect(find.text('Size estimate unavailable'), findsNWidgets(3));
|
||||
await tester.pumpWidget(const SizedBox.shrink());
|
||||
await tester.pumpAndSettle();
|
||||
await _openPicker(
|
||||
tester,
|
||||
duration: const Duration(minutes: 4),
|
||||
audioQuality: '24bit',
|
||||
);
|
||||
expect(find.text('Size estimate unavailable'), findsNWidgets(3));
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'conversion estimate is separate and fits narrow, enlarged text',
|
||||
(tester) async {
|
||||
tester.view.physicalSize = const Size(320, 720);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
addTearDown(tester.view.resetPhysicalSize);
|
||||
addTearDown(tester.view.resetDevicePixelRatio);
|
||||
await _openPicker(
|
||||
tester,
|
||||
duration: const Duration(minutes: 4),
|
||||
textScale: 1.8,
|
||||
settings: const AppSettings(
|
||||
autoConvertDownloads: true,
|
||||
autoConvertFormat: 'opus',
|
||||
autoConvertBitrate: '256k',
|
||||
),
|
||||
);
|
||||
expect(find.text('≈ 26.2 MB'), findsNWidgets(3));
|
||||
final conversionNote = find.textContaining(
|
||||
'After conversion to OPUS: ≈ 7.3 MB',
|
||||
);
|
||||
expect(conversionNote, findsOneWidget);
|
||||
await tester.ensureVisible(conversionNote);
|
||||
await tester.pumpAndSettle();
|
||||
expect(tester.takeException(), isNull);
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1,211 +0,0 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:spotiflac_android/models/track.dart';
|
||||
import 'package:spotiflac_android/providers/extension_provider.dart';
|
||||
import 'package:spotiflac_android/utils/download_size_estimate.dart';
|
||||
|
||||
Track _track(
|
||||
int duration, {
|
||||
String? itemType,
|
||||
String? audioQuality,
|
||||
String? source = 'provider-a',
|
||||
}) => Track(
|
||||
id: 'track',
|
||||
name: 'Track',
|
||||
artistName: 'Artist',
|
||||
albumName: 'Album',
|
||||
duration: duration,
|
||||
itemType: itemType,
|
||||
audioQuality: audioQuality,
|
||||
source: source,
|
||||
);
|
||||
|
||||
void main() {
|
||||
const duration = Duration(minutes: 4);
|
||||
|
||||
test('track metadata caps quality and sums each recording separately', () {
|
||||
final cd = _track(240, audioQuality: '16bit/44.1kHz');
|
||||
final hiRes = _track(120, audioQuality: '24-bit/96000Hz');
|
||||
for (final id in ['LOSSLESS', 'HI_RES', 'HI_RES_LOSSLESS']) {
|
||||
expect(
|
||||
estimateDownloadSize(
|
||||
duration: duration,
|
||||
quality: QualityOption(id: id, label: ''),
|
||||
tracks: [cd],
|
||||
providerId: 'provider-a',
|
||||
)!.bytes,
|
||||
27518400,
|
||||
);
|
||||
}
|
||||
final tracks = [cd, hiRes];
|
||||
expect(
|
||||
estimateDownloadSize(
|
||||
duration: totalDownloadDuration(tracks),
|
||||
quality: QualityOption.fromJson({
|
||||
'id': 'best',
|
||||
'label': 'Best',
|
||||
'kind': 'lossless',
|
||||
}),
|
||||
tracks: tracks,
|
||||
providerId: 'provider-a',
|
||||
)!.bytes,
|
||||
27518400 + 44928000,
|
||||
);
|
||||
});
|
||||
|
||||
test(
|
||||
'lossless metadata must be complete and belong to selected provider',
|
||||
() {
|
||||
for (final track in [
|
||||
_track(240),
|
||||
_track(240, audioQuality: '24bit'),
|
||||
_track(240, audioQuality: '16bit/44.1kHz', source: 'provider-b'),
|
||||
]) {
|
||||
expect(
|
||||
estimateDownloadSize(
|
||||
duration: duration,
|
||||
quality: const QualityOption(id: 'LOSSLESS', label: ''),
|
||||
tracks: [track],
|
||||
providerId: 'provider-a',
|
||||
),
|
||||
isNull,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test('four minutes at 256 kbps is 7,680,000 bytes before overhead', () {
|
||||
for (final quality in [
|
||||
const QualityOption(id: 'opus_256', label: 'Opus'),
|
||||
const QualityOption(id: 'custom', label: 'Opus 256kbps'),
|
||||
QualityOption.fromJson({
|
||||
'id': 'custom',
|
||||
'label': 'Audio',
|
||||
'sizeEstimate': {'bitrateKbps': 256},
|
||||
}),
|
||||
]) {
|
||||
final estimate = estimateDownloadSize(
|
||||
duration: duration,
|
||||
quality: quality,
|
||||
)!;
|
||||
expect(estimate.bytes, 7680000);
|
||||
}
|
||||
});
|
||||
|
||||
test('lossless estimates compare each tier at its own quality', () {
|
||||
const cd = QualityOption(id: 'LOSSLESS', label: 'Lossless');
|
||||
final cdSize = estimateDownloadSize(duration: duration, quality: cd)!;
|
||||
expect(cdSize.bytes, 27518400);
|
||||
final batchSize = estimateDownloadSize(
|
||||
duration: totalDownloadDuration([_track(240), _track(240)]),
|
||||
quality: cd,
|
||||
)!;
|
||||
expect(batchSize.bytes, cdSize.bytes * 2);
|
||||
|
||||
for (final (id, bytes) in [
|
||||
('HI_RES', 89856000),
|
||||
('HI_RES_LOSSLESS', 179712000),
|
||||
]) {
|
||||
final size = estimateDownloadSize(
|
||||
duration: duration,
|
||||
quality: QualityOption(id: id, label: ''),
|
||||
)!;
|
||||
expect(size.bytes, bytes);
|
||||
expect(size.bytes, greaterThan(cdSize.bytes));
|
||||
}
|
||||
});
|
||||
|
||||
test(
|
||||
'explicit parameters override legacy assumptions and preserve channels',
|
||||
() {
|
||||
final quality = QualityOption.fromJson({
|
||||
'id': 'LOSSLESS',
|
||||
'label': 'Custom lossless',
|
||||
'sizeEstimate': {'bitDepth': 24, 'sampleRate': 48000, 'channels': 1},
|
||||
});
|
||||
final estimate = estimateDownloadSize(
|
||||
duration: duration,
|
||||
quality: quality,
|
||||
)!;
|
||||
expect(estimate.bytes, 22464000);
|
||||
final capped = estimateDownloadSize(
|
||||
duration: duration,
|
||||
quality: QualityOption.fromJson({
|
||||
'id': 'best',
|
||||
'label': 'Best',
|
||||
'sizeEstimate': {
|
||||
'bitDepth': 24,
|
||||
'sampleRate': 192000,
|
||||
'isMaximum': true,
|
||||
},
|
||||
}),
|
||||
)!;
|
||||
expect(capped.bytes, 179712000);
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'unknown tiers, incomplete or invalid parameters do not invent sizes',
|
||||
() {
|
||||
for (final quality in [
|
||||
const QualityOption(id: 'best', label: 'Best'),
|
||||
const QualityOption(id: 'HIGH', label: 'High'),
|
||||
const QualityOption(id: 'DOLBY_ATMOS', label: 'Spatial'),
|
||||
const QualityOption(id: 'opus', label: 'Opus'),
|
||||
const QualityOption(
|
||||
id: 'custom',
|
||||
label: 'Best',
|
||||
description: 'May fall back to Opus 256kbps',
|
||||
),
|
||||
const QualityOption(
|
||||
id: 'LOSSLESS',
|
||||
label: '',
|
||||
sizeEstimate: QualitySizeEstimate(bitDepth: 24),
|
||||
),
|
||||
const QualityOption(
|
||||
id: 'LOSSLESS',
|
||||
label: '',
|
||||
sizeEstimate: QualitySizeEstimate(bitDepth: 0, sampleRate: 48000),
|
||||
),
|
||||
const QualityOption(
|
||||
id: 'opus_256',
|
||||
label: '',
|
||||
sizeEstimate: QualitySizeEstimate(bitrateKbps: -1),
|
||||
),
|
||||
const QualityOption(
|
||||
id: 'custom',
|
||||
label: '',
|
||||
sizeEstimate: QualitySizeEstimate(bitrateKbps: 320, isMaximum: true),
|
||||
),
|
||||
]) {
|
||||
expect(
|
||||
estimateDownloadSize(duration: duration, quality: quality),
|
||||
isNull,
|
||||
);
|
||||
}
|
||||
for (final duration in [
|
||||
null,
|
||||
Duration.zero,
|
||||
const Duration(seconds: -1),
|
||||
]) {
|
||||
expect(
|
||||
estimateDownloadSize(
|
||||
duration: duration,
|
||||
quality: const QualityOption(id: 'mp3_320', label: 'MP3'),
|
||||
),
|
||||
isNull,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test('batch duration is unavailable when tracks are missing duration', () {
|
||||
expect(totalDownloadDuration([]), isNull);
|
||||
expect(totalDownloadDuration([_track(240), _track(0)]), isNull);
|
||||
expect(totalDownloadDuration([_track(-1)]), isNull);
|
||||
expect(totalDownloadDuration([_track(240, itemType: 'album')]), isNull);
|
||||
expect(
|
||||
totalDownloadDuration([_track(120), _track(180)]),
|
||||
const Duration(minutes: 5),
|
||||
);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user