added support for simultan downloads in files and talk, support for background downloads, enhanced loading in files with retry

This commit is contained in:
2026-07-06 15:43:17 +02:00
parent 614ab159af
commit 124b1a5177
34 changed files with 1866 additions and 409 deletions
@@ -0,0 +1,119 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:marianum_mobile/widget/downloads/download_tray.dart';
void main() {
group('shouldAutoOpenCompletion', () {
test('opens a lone foreground download on its origin screen', () {
expect(
shouldAutoOpenCompletion(
foreground: true,
suppressAutoOpen: false,
completedIsSoleVisibleJob: true,
onOriginScreen: true,
),
isTrue,
);
});
test('does not open while backgrounded', () {
expect(
shouldAutoOpenCompletion(
foreground: false,
suppressAutoOpen: false,
completedIsSoleVisibleJob: true,
onOriginScreen: true,
),
isFalse,
);
});
test('does not open when other downloads are still visible', () {
expect(
shouldAutoOpenCompletion(
foreground: true,
suppressAutoOpen: false,
completedIsSoleVisibleJob: false,
onOriginScreen: true,
),
isFalse,
);
});
test('does not open once parallelism was seen (suppressed), even if now sole', () {
// A burst of parallel downloads drains one by one; the last one left must
// not surprise the user by auto-opening.
expect(
shouldAutoOpenCompletion(
foreground: true,
suppressAutoOpen: true,
completedIsSoleVisibleJob: true,
onOriginScreen: true,
),
isFalse,
);
});
test('does not open if the user left the screen it was started on', () {
// The chip surfaces instead; nothing should pop open unexpectedly.
expect(
shouldAutoOpenCompletion(
foreground: true,
suppressAutoOpen: false,
completedIsSoleVisibleJob: true,
onOriginScreen: false,
),
isFalse,
);
});
});
group('shouldShowDownloadChip', () {
test('hidden while the overview sheet is open', () {
expect(
shouldShowDownloadChip(sheetOpen: true, jobCount: 3, anySurfaced: true),
isFalse,
);
});
test('hidden when there are no jobs', () {
expect(
shouldShowDownloadChip(
sheetOpen: false,
jobCount: 0,
anySurfaced: false,
),
isFalse,
);
});
test('hidden for a lone in-progress download on its own screen', () {
// Single job, not finished, screen not left → inline progress is enough.
expect(
shouldShowDownloadChip(
sheetOpen: false,
jobCount: 1,
anySurfaced: false,
),
isFalse,
);
});
test('shown for multiple downloads', () {
expect(
shouldShowDownloadChip(
sheetOpen: false,
jobCount: 2,
anySurfaced: false,
),
isTrue,
);
});
test('shown for a lone download once surfaced (finished or screen left)', () {
expect(
shouldShowDownloadChip(sheetOpen: false, jobCount: 1, anySurfaced: true),
isTrue,
);
});
});
}
@@ -0,0 +1,54 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:marianum_mobile/state/app/infrastructure/loadable_state/view/loadable_state_primary_loading.dart';
void main() {
Widget wrap(Widget child) => MaterialApp(home: Scaffold(body: child));
const slowHint = LoadableStatePrimaryLoading.slowHintText;
testWidgets('shows the slow hint only after the threshold elapses', (
tester,
) async {
await tester.pumpWidget(
wrap(const LoadableStatePrimaryLoading(visible: true)),
);
expect(find.text(slowHint), findsNothing);
await tester.pump(const Duration(seconds: 7));
expect(find.text(slowHint), findsNothing);
await tester.pump(const Duration(seconds: 2));
expect(find.text(slowHint), findsOneWidget);
});
testWidgets('an explicit statusText takes precedence over the slow hint', (
tester,
) async {
await tester.pumpWidget(
wrap(
const LoadableStatePrimaryLoading(
visible: true,
statusText: 'Erneuter Versuch (2 von 3) …',
),
),
);
expect(find.text('Erneuter Versuch (2 von 3) …'), findsOneWidget);
// Even after the slow-hint threshold the explicit status wins.
await tester.pump(const Duration(seconds: 9));
expect(find.text('Erneuter Versuch (2 von 3) …'), findsOneWidget);
expect(find.text(slowHint), findsNothing);
});
testWidgets('does not arm the slow hint while invisible', (tester) async {
await tester.pumpWidget(
wrap(const LoadableStatePrimaryLoading(visible: false)),
);
await tester.pump(const Duration(seconds: 20));
expect(find.text(slowHint), findsNothing);
});
}