feat(detail): show episode file sizes
This commit is contained in:
@@ -214,6 +214,59 @@ void main() {
|
||||
expect(buildMediaQualityLabels(_episodeWithVersion(null)), isEmpty);
|
||||
});
|
||||
});
|
||||
group('buildMediaSizeLabel', () {
|
||||
test('formats the complete size of a multi-part version', () {
|
||||
final item = _episodeWithVersion(
|
||||
const MediaVersion(
|
||||
id: '1',
|
||||
parts: [
|
||||
MediaPart(id: 'part-1', sizeBytes: 512 * 1024 * 1024),
|
||||
MediaPart(id: 'part-2', sizeBytes: 1024 * 1024 * 1024),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
expect(buildMediaSizeLabel(item), '1.50 GB');
|
||||
});
|
||||
|
||||
test('omits the size when any part is missing a valid size', () {
|
||||
for (final invalidSize in <int?>[null, 0, -1]) {
|
||||
final item = _episodeWithVersion(
|
||||
MediaVersion(
|
||||
id: '1',
|
||||
parts: [
|
||||
const MediaPart(id: 'known', sizeBytes: 1024),
|
||||
MediaPart(id: 'unknown', sizeBytes: invalidSize),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
expect(buildMediaSizeLabel(item), isNull);
|
||||
}
|
||||
});
|
||||
|
||||
test('uses the same requested version index as quality labels', () {
|
||||
final item = testMediaItem(
|
||||
id: 'episode-1',
|
||||
backend: MediaBackend.plex,
|
||||
kind: MediaKind.episode,
|
||||
title: 'Episode',
|
||||
mediaVersions: const [
|
||||
MediaVersion(
|
||||
id: 'small',
|
||||
parts: [MediaPart(id: 'small-part', sizeBytes: 1024 * 1024 * 1024)],
|
||||
),
|
||||
MediaVersion(
|
||||
id: 'large',
|
||||
parts: [MediaPart(id: 'large-part', sizeBytes: 2 * 1024 * 1024 * 1024)],
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
expect(buildMediaSizeLabel(item), '1.00 GB');
|
||||
expect(buildMediaSizeLabel(item, versionIndex: 1), '2.00 GB');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
MediaItem _episodeWithVersion(MediaVersion? version) {
|
||||
|
||||
@@ -6,6 +6,10 @@ import 'package:plezy/database/app_database.dart';
|
||||
import 'package:plezy/i18n/strings.g.dart';
|
||||
import 'package:plezy/media/media_backend.dart';
|
||||
import 'package:plezy/media/media_kind.dart';
|
||||
import 'package:plezy/media/media_item.dart';
|
||||
import 'package:plezy/media/media_part.dart';
|
||||
import 'package:plezy/media/media_stream.dart';
|
||||
import 'package:plezy/media/media_version.dart';
|
||||
import 'package:plezy/providers/download_provider.dart';
|
||||
import 'package:plezy/services/download_manager_service.dart';
|
||||
import 'package:plezy/services/download_storage_service.dart';
|
||||
@@ -50,40 +54,7 @@ void main() {
|
||||
durationMs: 42 * 60 * 1000,
|
||||
);
|
||||
|
||||
final db = AppDatabase.forTesting(NativeDatabase.memory());
|
||||
PlexApiCache.initialize(db);
|
||||
JellyfinApiCache.initialize(db);
|
||||
final downloadManager = DownloadManagerService(
|
||||
database: db,
|
||||
storageService: DownloadStorageService.instance,
|
||||
clientResolver: (serverId, {clientScopeId}) => null,
|
||||
);
|
||||
downloadManager.recoveryFuture = Future<void>.value();
|
||||
final downloadProvider = DownloadProvider.forTesting(downloadManager: downloadManager, database: db);
|
||||
await downloadProvider.ensureInitialized();
|
||||
addTearDown(() async {
|
||||
downloadProvider.dispose();
|
||||
downloadManager.dispose();
|
||||
await db.close();
|
||||
});
|
||||
|
||||
await tester.pumpWidget(
|
||||
TranslationProvider(
|
||||
child: ChangeNotifierProvider<DownloadProvider>.value(
|
||||
value: downloadProvider,
|
||||
child: MaterialApp(
|
||||
theme: monoTheme(dark: true),
|
||||
home: Scaffold(
|
||||
body: SizedBox(
|
||||
width: 360,
|
||||
child: EpisodeCard(episode: episode, isOffline: true, onTap: () {}),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
await _pumpEpisodeCard(tester, episode);
|
||||
|
||||
final summaryText = tester.widget<Text>(
|
||||
find.descendant(of: find.byType(CollapsibleText), matching: find.byType(Text)).first,
|
||||
@@ -107,4 +78,73 @@ void main() {
|
||||
expect(cardSemantics.getSemanticsData().hasAction(SemanticsAction.tap), isTrue);
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('shows file size alongside media quality labels', (tester) async {
|
||||
final episode = testMediaItem(
|
||||
id: 'sized_episode',
|
||||
backend: MediaBackend.plex,
|
||||
kind: MediaKind.episode,
|
||||
title: 'A Large Episode',
|
||||
index: 4,
|
||||
durationMs: 52 * 60 * 1000,
|
||||
mediaVersions: const [
|
||||
MediaVersion(
|
||||
id: 'source',
|
||||
videoResolution: '1080',
|
||||
parts: [
|
||||
MediaPart(
|
||||
id: 'part-1',
|
||||
sizeBytes: 1536 * 1024 * 1024,
|
||||
streams: [
|
||||
MediaStream(id: 'audio', kind: MediaStreamKind.audio, codec: 'eac3', channels: 6, selected: true),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
await _pumpEpisodeCard(tester, episode);
|
||||
|
||||
final metadataWrap = find.ancestor(of: find.text('1.50 GB'), matching: find.byType(Wrap));
|
||||
expect(metadataWrap, findsOneWidget);
|
||||
expect(find.descendant(of: metadataWrap, matching: find.text('EAC3 5.1')), findsOneWidget);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _pumpEpisodeCard(WidgetTester tester, MediaItem episode) async {
|
||||
final db = AppDatabase.forTesting(NativeDatabase.memory());
|
||||
PlexApiCache.initialize(db);
|
||||
JellyfinApiCache.initialize(db);
|
||||
final downloadManager = DownloadManagerService(
|
||||
database: db,
|
||||
storageService: DownloadStorageService.instance,
|
||||
clientResolver: (serverId, {clientScopeId}) => null,
|
||||
);
|
||||
downloadManager.recoveryFuture = Future<void>.value();
|
||||
final downloadProvider = DownloadProvider.forTesting(downloadManager: downloadManager, database: db);
|
||||
await downloadProvider.ensureInitialized();
|
||||
addTearDown(() async {
|
||||
downloadProvider.dispose();
|
||||
downloadManager.dispose();
|
||||
await db.close();
|
||||
});
|
||||
|
||||
await tester.pumpWidget(
|
||||
TranslationProvider(
|
||||
child: ChangeNotifierProvider<DownloadProvider>.value(
|
||||
value: downloadProvider,
|
||||
child: MaterialApp(
|
||||
theme: monoTheme(dark: true),
|
||||
home: Scaffold(
|
||||
body: SizedBox(
|
||||
width: 360,
|
||||
child: EpisodeCard(episode: episode, isOffline: true, onTap: () {}),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user