fix(flutter): 修复详情页跳转灰屏
This commit is contained in:
1 parent
da78d8723d
commit
353196aaa3
2 files changed
+193
-10
No files matched your search
@@ -0,0 +1,181 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:fruitshorts/core/data/models/drama.dart';
|
||||
import 'package:fruitshorts/core/data/models/player_port.dart';
|
||||
import 'package:fruitshorts/core/data/repositories/favorite_repository.dart';
|
||||
import 'package:fruitshorts/core/data/repositories/playback_repository.dart';
|
||||
import 'package:fruitshorts/core/data/repositories/watch_history_repository.dart';
|
||||
import 'package:fruitshorts/core/data/services/android_picture_in_picture.dart';
|
||||
import 'package:fruitshorts/core/data/services/catalog_controller.dart';
|
||||
import 'package:fruitshorts/core/data/services/favorite_controller.dart';
|
||||
import 'package:fruitshorts/core/data/services/playback_session.dart';
|
||||
import 'package:fruitshorts/core/data/services/video_player_port.dart';
|
||||
import 'package:fruitshorts/core/platform/haptics.dart';
|
||||
import 'package:fruitshorts/l10n/app_localizations.dart';
|
||||
import 'package:fruitshorts/pages/drama_detail/drama_detail_view.dart';
|
||||
import 'package:fruitshorts/pages/player/player_logic.dart';
|
||||
import 'package:fruitshorts/pages/player/player_view.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:video_player/video_player.dart';
|
||||
|
||||
import '../support/fake_catalog.dart';
|
||||
import '../support/fake_haptics.dart';
|
||||
import '../support/fake_watch_history.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets(
|
||||
'should_keep_active_player_and_progress_when_detail_route_is_open',
|
||||
(tester) async {
|
||||
final drama = _drama();
|
||||
final history = FakeWatchHistory();
|
||||
final playback = FakePlaybackRepository();
|
||||
final catalog = CatalogController(FakeCatalogRepository(dramas: [drama]));
|
||||
final favorites = FavoriteController(
|
||||
InMemoryFavoriteRepository(saved: {drama.id}, cards: [drama]),
|
||||
);
|
||||
final logic = PlayerLogic(
|
||||
history: history,
|
||||
playback: playback,
|
||||
pictureInPicture: AndroidPictureInPicture(
|
||||
channel: const MethodChannel('test/player_open_detail/pip'),
|
||||
),
|
||||
);
|
||||
final factory = _RecordingFactory();
|
||||
logic.attach(
|
||||
PlayerPage(drama: drama, initialIndex: 0),
|
||||
isMounted: () => true,
|
||||
);
|
||||
logic.start(factory: factory.create, coordinator: PlaybackCoordinator());
|
||||
await _pumpSession(tester);
|
||||
|
||||
final active = logic.session.active;
|
||||
final index = logic.session.currentIndex;
|
||||
final player = factory.created.first;
|
||||
final playsBefore = player.plays;
|
||||
final tracked = VideoPlayerPort(drama.episodes.first);
|
||||
tracked.controller.value = const VideoPlayerValue(
|
||||
duration: Duration(minutes: 5),
|
||||
position: Duration(seconds: 37),
|
||||
isInitialized: true,
|
||||
);
|
||||
logic
|
||||
..trackedPlayer = tracked
|
||||
..trackedEpisode = drama.episodes.first
|
||||
..trackedDrama = drama;
|
||||
|
||||
late BuildContext pageContext;
|
||||
await tester.pumpWidget(
|
||||
MultiProvider(
|
||||
providers: [
|
||||
Provider<WatchHistoryRepository>.value(value: history),
|
||||
Provider<PlaybackRepository>.value(value: playback),
|
||||
ChangeNotifierProvider<CatalogController>.value(value: catalog),
|
||||
ChangeNotifierProvider<FavoriteController>.value(value: favorites),
|
||||
Provider<Haptics>.value(value: FakeHaptics()),
|
||||
],
|
||||
child: MaterialApp(
|
||||
locale: const Locale('en'),
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
home: Builder(
|
||||
builder: (context) {
|
||||
pageContext = context;
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
unawaited(logic.openDetail(pageContext));
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 400));
|
||||
await _pumpSession(tester);
|
||||
|
||||
expect(find.byType(DramaDetailPage), findsOneWidget);
|
||||
expect(logic.session.active, same(active));
|
||||
expect(logic.session.currentIndex, index);
|
||||
expect(logic.session.userWantsPlay, isTrue);
|
||||
expect(player.pauses, 1);
|
||||
expect(player.plays, playsBefore);
|
||||
expect(tracked.controller.value.position, const Duration(seconds: 37));
|
||||
expect(history.writes, isEmpty);
|
||||
|
||||
await tester.pageBack();
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 400));
|
||||
await _pumpSession(tester);
|
||||
await logic.pendingWrite;
|
||||
|
||||
expect(logic.session.active, same(active));
|
||||
expect(logic.session.currentIndex, index);
|
||||
expect(logic.session.userWantsPlay, isTrue);
|
||||
expect(player.plays, playsBefore + 1);
|
||||
expect(tracked.controller.value.position, const Duration(seconds: 37));
|
||||
expect(history.writes, ['signal-1|37000|false']);
|
||||
|
||||
logic
|
||||
..trackedPlayer = null
|
||||
..trackedEpisode = null
|
||||
..trackedDrama = null
|
||||
..dispose();
|
||||
await _pumpSession(tester);
|
||||
await tracked.dispose();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Drama _drama() => Drama(
|
||||
id: 'signal',
|
||||
title: 'Signal',
|
||||
synopsis: 'synopsis',
|
||||
posterUrl: '/files/signal.png',
|
||||
episodes: const [
|
||||
Episode(
|
||||
id: 'signal-1',
|
||||
number: 1,
|
||||
title: 'Episode 1',
|
||||
videoUrl: 'https://example.test/signal-1.mp4',
|
||||
isFree: true,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
Future<void> _pumpSession(WidgetTester tester) async {
|
||||
for (var attempt = 0; attempt < 5; attempt++) {
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 1));
|
||||
}
|
||||
}
|
||||
|
||||
class _RecordingFactory {
|
||||
final List<_RecordingPlayer> created = [];
|
||||
|
||||
PlayerPort create(Episode episode) {
|
||||
final player = _RecordingPlayer();
|
||||
created.add(player);
|
||||
return player;
|
||||
}
|
||||
}
|
||||
|
||||
class _RecordingPlayer implements PlayerPort {
|
||||
int plays = 0;
|
||||
int pauses = 0;
|
||||
|
||||
@override
|
||||
Future<void> initialize() async {}
|
||||
|
||||
@override
|
||||
Future<void> play() async => plays++;
|
||||
|
||||
@override
|
||||
Future<void> pause() async => pauses++;
|
||||
|
||||
@override
|
||||
Future<void> dispose() async {}
|
||||
}
|
||||
Reference in new issue
Block a user