feat(detail): show episode file sizes

This commit is contained in:
edde746
2026-07-18 13:32:40 +02:00
parent a1b6a89714
commit 46dfc7f992
4 changed files with 146 additions and 36 deletions
+53
View File
@@ -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) {
+74 -34
View File
@@ -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();
}