refactor(ui): 清理 K26 旧 UI 与死代码

This commit is contained in:
Zhou Weidong committed 2026-10-19 15:58:22 +08:00
1 parent a5398daab3
commit 5422581f8b
23 files changed
+291 -1225

No files matched your search

-193
View File
@@ -1,193 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:fruitshorts/l10n/app_localizations.dart';
import 'package:fruitshorts/pages/discover/widgets/cover_carousel.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
List<CoverItem> items(int count) => [
for (var index = 0; index < count; index++)
CoverItem(
title: 'Banner $index',
subtitle: 'Subtitle $index',
image: '/files/banner-$index.png',
onOpen: _noop,
),
];
testWidgets('should_turn_cube_and_keep_title_on_poster_when_carousel_pages', (
tester,
) async {
await tester.pumpWidget(
_localizedApp(
CoverCarousel(
items: [
for (final title in ['The Signal', 'City Lights', 'Vengeance'])
CoverItem(
title: title,
subtitle: 'Mock',
image: '/files/poster.png',
onOpen: _noop,
),
],
),
),
);
await tester.pump();
expect(find.text('The Signal'), findsOneWidget);
expect(find.text('Mock'), findsOneWidget);
final box = tester.getRect(find.byType(CoverCarousel));
final gesture = await tester.startGesture(
Offset(box.right - 40, box.center.dy),
);
await gesture.moveBy(const Offset(-500, 0));
await tester.pump();
final turned = tester
.widgetList<Transform>(find.byType(Transform))
.any((transform) => (transform.transform.entry(0, 0) - 1).abs() > 0.15);
expect(turned, isTrue);
await gesture.moveBy(const Offset(-200, 0));
await gesture.up();
await tester.pump();
await tester.pump(const Duration(milliseconds: 450));
expect(find.text('City Lights'), findsOneWidget);
expect(tester.takeException(), isNull);
});
testWidgets('should_auto_advance_and_show_dots_when_multiple_items_exist', (
tester,
) async {
await tester.pumpWidget(_localizedApp(CoverCarousel(items: items(3))));
await tester.pump();
expect(find.text('Banner 0'), findsOneWidget);
expect(find.byKey(const Key('carousel-dot-0')), findsOneWidget);
expect(find.byKey(const Key('carousel-dot-1')), findsOneWidget);
expect(find.byKey(const Key('carousel-dot-2')), findsOneWidget);
await tester.pump(const Duration(milliseconds: 4500));
await tester.pump(const Duration(milliseconds: 500));
expect(find.text('Banner 1'), findsOneWidget);
await tester.pumpWidget(const SizedBox.shrink());
});
testWidgets('should_not_schedule_auto_advance_when_only_one_item_exists', (
tester,
) async {
await tester.pumpWidget(_localizedApp(CoverCarousel(items: items(1))));
await tester.pump(const Duration(seconds: 12));
expect(find.text('Banner 0'), findsOneWidget);
expect(find.byKey(const Key('carousel-dot-0')), findsOneWidget);
expect(find.byKey(const Key('carousel-dot-1')), findsNothing);
});
testWidgets('should_pause_auto_advance_while_pointer_is_down', (
tester,
) async {
await tester.pumpWidget(_localizedApp(CoverCarousel(items: items(3))));
await tester.pump();
final box = tester.getRect(find.byType(CoverCarousel));
final gesture = await tester.startGesture(box.center);
await tester.pump(const Duration(seconds: 6));
expect(find.text('Banner 0'), findsOneWidget);
await gesture.up();
await tester.pump();
await tester.pump(const Duration(milliseconds: 4500));
await tester.pump(const Duration(milliseconds: 500));
expect(find.text('Banner 1'), findsOneWidget);
await tester.pumpWidget(const SizedBox.shrink());
});
testWidgets('should_pause_when_inactive_and_resume_when_active_again', (
tester,
) async {
final active = ValueNotifier(false);
await tester.pumpWidget(
_localizedApp(
ValueListenableBuilder<bool>(
valueListenable: active,
builder: (context, enabled, _) =>
CoverCarousel(items: items(2), active: enabled),
),
),
);
await tester.pump(const Duration(seconds: 6));
expect(find.text('Banner 0'), findsOneWidget);
active.value = true;
await tester.pump();
await tester.pump(const Duration(milliseconds: 4500));
await tester.pump(const Duration(milliseconds: 500));
expect(find.text('Banner 1'), findsOneWidget);
await tester.pumpWidget(const SizedBox.shrink());
});
testWidgets('should_show_icon_fallback_when_banner_image_is_empty', (
tester,
) async {
await tester.pumpWidget(
_localizedApp(
CoverCarousel(
items: const [
CoverItem(
title: 'Broken image',
subtitle: '',
image: '',
onOpen: _noop,
),
],
),
),
);
await tester.pump();
expect(find.byKey(const Key('carousel-image-fallback')), findsOneWidget);
});
testWidgets(
'should_keep_existing_open_callback_when_active_poster_is_tapped',
(tester) async {
var opened = 0;
await tester.pumpWidget(
_localizedApp(
CoverCarousel(
items: [
CoverItem(
title: 'Tap me',
subtitle: '',
image: '/files/banner.png',
onOpen: () => opened++,
),
...items(1),
],
),
),
);
await tester.pump();
await tester.tap(find.text('Tap me'));
expect(opened, 1);
await tester.pumpWidget(const SizedBox.shrink());
},
);
}
void _noop() {}
Widget _localizedApp(Widget child) => MaterialApp(
locale: const Locale('en'),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: Scaffold(body: child),
);
@@ -38,7 +38,6 @@ void main() {
await tester.pumpAndSettle();
expect(find.text('Continue Watching'), findsNothing);
expect(find.byKey(const Key('home-all-dramas-title')), findsNothing);
expect(find.text('Recommended'), findsOneWidget);
expect(find.text('For You'), findsNothing);
final grid = tester.widget<SliverGrid>(
@@ -133,7 +132,6 @@ void main() {
await tester.tap(find.byKey(const Key('tab-discover')));
await tester.pumpAndSettle();
expect(find.byKey(const Key('home-all-dramas-title')), findsNothing);
expect(find.text('No matching dramas.'), findsOneWidget);
expect(find.byKey(const Key('empty-state-content')), findsOneWidget);
@@ -153,7 +151,6 @@ void main() {
await tester.tap(find.byKey(const Key('tab-discover')));
await tester.pumpAndSettle();
expect(find.byKey(const Key('home-all-dramas-title')), findsNothing);
expect(find.text('Categories could not be loaded.'), findsOneWidget);
expect(find.text('Retry'), findsOneWidget);
expect(find.byKey(const Key('empty-state-icon')), findsOneWidget);
@@ -179,7 +176,6 @@ void main() {
);
await tester.pumpAndSettle();
expect(find.byKey(const Key('home-all-dramas-title')), findsNothing);
expect(find.text('City Lights & Velvet Nights'), findsWidgets);
expect(tester.takeException(), isNull);
});
@@ -1,85 +0,0 @@
// Author: fruit.com.cn
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:fruitshorts/app.dart';
import 'package:fruitshorts/core/data/models/drama.dart';
import 'package:fruitshorts/core/data/models/home_feed.dart';
import 'package:fruitshorts/core/data/repositories/catalog_repository.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/pages/discover/widgets/cover_carousel.dart';
import 'package:shared_preferences_platform_interface/in_memory_shared_preferences_async.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_async_platform_interface.dart';
import '../support/fake_catalog.dart';
import '../support/fake_category.dart';
import '../support/fake_interaction_repositories.dart';
import '../support/fake_notice_repository.dart';
import '../support/widget_player.dart';
void main() {
testWidgets(
'should_not_mount_carousel_on_discover_even_when_home_banners_exist',
(tester) async {
SharedPreferencesAsyncPlatform.instance =
InMemorySharedPreferencesAsync.empty();
final catalog = _HomeBannerCatalogRepository();
await tester.pumpWidget(
LumaDramaApp(
playerFactory: createWidgetPlayer,
catalogRepository: catalog,
categoryRepository: FakeCategoryRepository(catalog: catalog),
watchHistoryRepository: InMemoryWatchHistoryRepository(),
favoriteRepository: InMemoryFavoriteRepository(),
playbackRepository: FakePlaybackRepository(),
commentRepository: FakeCommentRepository(),
interactionRepository: FakeInteractionRepository(),
noticeRepository: FakeNoticeRepository(),
),
);
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('tab-discover')));
await tester.pumpAndSettle();
expect(find.byType(CoverCarousel), findsNothing);
expect(find.byKey(const Key('discover-search')), findsOneWidget);
expect(find.byKey(const Key('home-all-dramas-grid')), findsOneWidget);
expect(find.byKey(const Key('discover-quick-filter')), findsOneWidget);
expect(find.text('The Signal'), findsWidgets);
await tester.pumpWidget(const SizedBox.shrink());
},
);
}
class _HomeBannerCatalogRepository implements CatalogRepository {
final _delegate = FakeCatalogRepository();
@override
Future<HomeFeed> fetchHomeFeed() async => HomeFeed(
banners: const [
FeedBanner(
id: 'banner-1',
imageUrl: '/files/banner-1.png',
linkType: 'DRAMA',
linkValue: 'the-signal-demo',
),
FeedBanner(
id: 'banner-2',
imageUrl: '/files/banner-2.png',
linkType: 'DRAMA',
linkValue: 'city-lights-demo',
),
],
sections: [FeedSection(code: 'hot', title: 'Hot', dramas: demoDramas)],
);
@override
Future<HomeFeed> fetchDiscoverFeed() async => HomeFeed(
sections: [FeedSection(code: 'hot', title: 'Hot', dramas: demoDramas)],
);
@override
Future<Drama> fetchDrama(String dramaId) => _delegate.fetchDrama(dramaId);
}
+6 -12
View File
@@ -109,16 +109,15 @@ void main() {
},
);
test('should_return_home_and_open_drawer_when_system_back_is_pressed', () {
test('should_return_to_discover_and_handle_immersive_back', () {
final logic = HomeLogic(dramas);
// Home is the launch tab; the first back press lands on Discover.
logic.onSystemBack();
expect(logic.tab, 1);
logic.onSystemBack();
expect(logic.drawerOpen, isTrue);
expect(logic.tab, 1);
expect(logic.backRequest, 0);
logic.onDrawerChanged(false);
logic.select(0);
logic.onSystemBack();
@@ -131,30 +130,25 @@ void main() {
expect(logic.backRequest, 1);
expect(logic.tab, 0);
logic.onDrawerChanged(true);
logic.onSystemBack();
expect(logic.backRequest, 1);
logic.onDrawerChanged(false);
logic.onImmersiveChanged(false);
logic.onSystemBack();
expect(logic.tab, 1);
logic.dispose();
});
test('should_notify_only_on_actual_change_when_drawer_state_is_set', () {
test('should_notify_only_on_actual_change_when_menu_state_is_set', () {
final logic = HomeLogic(dramas);
var notifications = 0;
logic.addListener(() => notifications++);
logic.onDrawerChanged(false);
logic.setMenuOpen(false);
expect(notifications, 0);
logic.onDrawerChanged(true);
logic.setMenuOpen(true);
expect(logic.drawerOpen, isTrue);
expect(notifications, 1);
logic.onDrawerChanged(true);
logic.setMenuOpen(true);
expect(notifications, 1);
logic.dispose();
});
-15
View File
@@ -95,24 +95,9 @@ void main() {
);
});
testWidgets('should_hide_themed_navigation_when_immersive_mode_is_enabled', (
tester,
) async {
await _pumpApp(tester);
await tester.tap(find.byKey(const Key('home-feed-more')));
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('home-feed-clear')));
await tester.pumpAndSettle();
for (final key in _keys) {
expect(find.byKey(key), findsNothing);
}
});
testWidgets('should_map_three_tabs_to_home_discover_and_me', (tester) async {
await _pumpApp(tester);
expect(find.byKey(const Key('tab-my-list')), findsNothing);
expect(find.byKey(const Key('tab-home')), findsOneWidget);
expect(find.byKey(const Key('tab-discover')), findsOneWidget);
expect(find.byKey(const Key('tab-my')), findsOneWidget);
-3
View File
@@ -81,9 +81,6 @@ void _expectFullscreenOverlay() {
expect(find.byKey(const Key('rail-like')), findsNothing);
expect(find.byKey(const Key('rail-save')), findsNothing);
expect(find.byKey(const Key('card-player-video-frame')), findsNothing);
expect(find.byKey(const Key('card-player-progress')), findsNothing);
expect(find.byKey(const Key('card-player-next')), findsNothing);
}
Future<void> _pumpApp(WidgetTester tester) async {
+1 -27
View File
@@ -117,33 +117,7 @@ void main() {
});
group('surface flags', () {
test('should_hide_chrome_until_restored_when_screen_is_cleared', () {
final logic = _logic(FakeWatchHistory());
final immersive = <bool>[];
logic.onImmersiveChanged = immersive.add;
var notifications = 0;
logic.addListener(() => notifications++);
expect(logic.chromeHidden, isFalse);
expect(logic.immersive, isFalse);
logic.setScreenCleared(true);
expect(logic.chromeHidden, isTrue);
expect(notifications, 1);
expect(immersive, [true]);
// Repeating the same value is not a state change.
logic.setScreenCleared(true);
expect(notifications, 1);
expect(immersive, [true]);
logic.setScreenCleared(false);
expect(logic.chromeHidden, isFalse);
expect(notifications, 2);
expect(immersive, [true, false]);
});
test('should_outrank_cleared_screen_flag_when_picture_in_picture_callback_fires', () async {
test('should_set_immersive_when_picture_in_picture_callback_fires', () async {
final factory = _RecordingFactory();
final drama = _drama('signal');
final logic = _logic(FakeWatchHistory());
+1 -33
View File
@@ -122,38 +122,12 @@ void main() {
await tester.pumpAndSettle();
expect(find.byKey(const Key('home-feed-download')), findsOneWidget);
expect(find.byKey(const Key('home-feed-pip')), findsOneWidget);
expect(find.byKey(const Key('home-feed-clear')), findsOneWidget);
await tester.binding.handlePopRoute();
await tester.pumpAndSettle();
expect(find.text('Watch Full'), findsNothing);
expect(find.byTooltip('Explore series'), findsNothing);
});
testWidgets('should_hide_tabs_and_restore_them_when_clear_screen_is_tapped', (
tester,
) async {
tester.view.physicalSize = const Size(390, 844);
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.resetPhysicalSize);
addTearDown(tester.view.resetDevicePixelRatio);
await tester.pumpWidget(appUnderTest());
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('tab-home')));
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('home-feed-more')));
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('home-feed-clear')));
await tester.pumpAndSettle();
expect(find.byKey(const Key('home-tabs-bar')), findsNothing);
expect(find.byTooltip('Exit clear screen'), findsOneWidget);
await tester.tap(find.byTooltip('Exit clear screen'));
await tester.pumpAndSettle();
expect(find.byKey(const Key('home-tabs-bar')), findsOneWidget);
expect(find.byKey(const Key('home-feed-more')), findsOneWidget);
expect(tester.takeException(), isNull);
});
testWidgets(
'should_open_current_series_and_switch_root_tabs_when_quick_drawer_is_used',
(tester) async {
@@ -177,13 +151,7 @@ void main() {
);
expect(find.text('Quick access'), findsOneWidget);
expect(find.text('Bahasa Indonesia'), findsOneWidget);
expect(
find.descendant(
of: find.byType(Drawer),
matching: find.text('7 EPISODES'),
),
findsOneWidget,
);
expect(find.text('7 EPISODES'), findsOneWidget);
expect(tester.takeException(), isNull);
await tester.tap(find.byKey(const Key('drawer-open-series')));