feat: 统一首页与推荐搜索入口
This commit is contained in:
1 parent
933333b0fe
commit
9aa797504b
18 files changed
+325
-107
No files matched your search
@@ -1304,3 +1304,9 @@ $ flutter test
|
||||
- 移除视频表面点击识别器,双击后增加 300ms 暂停防护;飘心收敛为 3~4 颗、20~26、±18、90~120dp、600~700ms。
|
||||
- 双击窗口延长至 320ms,单击 Timer 使用点击序号校验,双击后保留 350ms 播放切换保护。
|
||||
- `double_tap_like_test.dart` 覆盖 120/250/300ms 双击与 500ms 单击恢复:2 项测试全部通过。
|
||||
|
||||
## 2026-10-22 统一二级搜索页
|
||||
|
||||
- 首页与推荐/剧单/全部短剧搜索入口统一 push SearchPage,不再切换推荐 tab 聚焦。
|
||||
- 搜索页提供返回、自动聚焦输入框与取消,复用 `/app/search` 逻辑和首页三列卡片。
|
||||
- 清理旧的 searchRequest/focusSearch/syncSearch 参数;`flutter analyze`:No issues found。
|
||||
@@ -16,6 +16,7 @@
|
||||
"currentSeries": "Current series",
|
||||
"discoverTab": "Theater",
|
||||
"searchDiscover": "Search dramas, actors, genres...",
|
||||
"searchCancel": "Cancel",
|
||||
"featured": "Featured",
|
||||
"recommended": "Recommended",
|
||||
"fruitShortsBrand": "FruitShorts",
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"currentSeries": "Serial saat ini",
|
||||
"discoverTab": "Teater",
|
||||
"searchDiscover": "Cari drama, aktor, genre...",
|
||||
"searchCancel": "Batal",
|
||||
"featured": "Unggulan",
|
||||
"recommended": "Rekomendasi",
|
||||
"fruitShortsBrand": "FruitShorts",
|
||||
|
||||
@@ -196,6 +196,12 @@ abstract class AppLocalizations {
|
||||
/// **'Search dramas, actors, genres...'**
|
||||
String get searchDiscover;
|
||||
|
||||
/// No description provided for @searchCancel.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Cancel'**
|
||||
String get searchCancel;
|
||||
|
||||
/// No description provided for @featured.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
||||
@@ -57,6 +57,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
@override
|
||||
String get searchDiscover => 'Search dramas, actors, genres...';
|
||||
|
||||
@override
|
||||
String get searchCancel => 'Cancel';
|
||||
|
||||
@override
|
||||
String get featured => 'Featured';
|
||||
|
||||
|
||||
@@ -57,6 +57,9 @@ class AppLocalizationsId extends AppLocalizations {
|
||||
@override
|
||||
String get searchDiscover => 'Cari drama, aktor, genre...';
|
||||
|
||||
@override
|
||||
String get searchCancel => 'Batal';
|
||||
|
||||
@override
|
||||
String get featured => 'Unggulan';
|
||||
|
||||
|
||||
@@ -56,6 +56,9 @@ class AppLocalizationsZh extends AppLocalizations {
|
||||
@override
|
||||
String get searchDiscover => '搜索短剧、演员、类型…';
|
||||
|
||||
@override
|
||||
String get searchCancel => '取消';
|
||||
|
||||
@override
|
||||
String get featured => '精选';
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"currentSeries": "当前短剧",
|
||||
"discoverTab": "剧场",
|
||||
"searchDiscover": "搜索短剧、演员、类型…",
|
||||
"searchCancel": "取消",
|
||||
"featured": "精选",
|
||||
"recommended": "推荐",
|
||||
"fruitShortsBrand": "水果短剧",
|
||||
|
||||
@@ -118,20 +118,6 @@ class DiscoverLogic extends ChangeNotifier {
|
||||
searchResults = const [];
|
||||
}
|
||||
|
||||
/// 从播放器发起的搜索请求只在剧场页可见时抢焦点。
|
||||
void syncSearch({
|
||||
required bool active,
|
||||
required int request,
|
||||
required int previousRequest,
|
||||
required bool Function() isActive,
|
||||
}) {
|
||||
if (!active || request == previousRequest) return;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (isActive()) searchFocus.requestFocus();
|
||||
});
|
||||
WidgetsBinding.instance.scheduleFrame();
|
||||
}
|
||||
|
||||
void act(
|
||||
BuildContext context,
|
||||
DiscoverPageAction action, {
|
||||
|
||||
@@ -56,14 +56,10 @@ class DiscoverPage extends StatefulWidget {
|
||||
const DiscoverPage({
|
||||
super.key,
|
||||
this.active = true,
|
||||
this.searchRequest = 0,
|
||||
this.focusSearch = false,
|
||||
this.callbacks = const DiscoverPageCallbacks(),
|
||||
});
|
||||
|
||||
final bool active;
|
||||
final int searchRequest;
|
||||
final bool focusSearch;
|
||||
final DiscoverPageCallbacks callbacks;
|
||||
|
||||
@override
|
||||
@@ -89,7 +85,6 @@ class _DiscoverPageState extends State<DiscoverPage> {
|
||||
logic.scroll.addListener(_onScroll);
|
||||
theater.addListener(_onTheaterChanged);
|
||||
unawaited(theater.select(null));
|
||||
if (widget.focusSearch) _focusOnFirstFrame();
|
||||
}
|
||||
|
||||
void _onScroll() {
|
||||
@@ -106,23 +101,6 @@ class _DiscoverPageState extends State<DiscoverPage> {
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
void _focusOnFirstFrame() {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted && widget.active) logic.openSearch();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant DiscoverPage oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
logic.syncSearch(
|
||||
active: widget.active,
|
||||
request: widget.searchRequest,
|
||||
previousRequest: oldWidget.searchRequest,
|
||||
isActive: () => mounted && widget.active,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
logic.scroll.removeListener(_onScroll);
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../core/data/repositories/search_repository.dart';
|
||||
import '../../core/formatting/error_text.dart';
|
||||
import '../../core/theme/app_colors.dart';
|
||||
import '../../core/theme/app_dimens.dart';
|
||||
import '../../core/theme/app_theme.dart';
|
||||
import '../../core/widgets/empty_state.dart';
|
||||
import '../../l10n/app_localizations.dart';
|
||||
import '../home/widgets/home_feed_card.dart';
|
||||
import '../player/open_player.dart';
|
||||
import 'discover_binding.dart';
|
||||
import 'discover_logic.dart';
|
||||
|
||||
class SearchPage extends StatefulWidget {
|
||||
const SearchPage({super.key});
|
||||
|
||||
@override
|
||||
State<SearchPage> createState() => _SearchPageState();
|
||||
}
|
||||
|
||||
class _SearchPageState extends State<SearchPage> {
|
||||
late final DiscoverLogic _logic;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_logic = DiscoverBinding().create(search: context.read<SearchRepository>());
|
||||
_logic.addListener(_rebuild);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) _logic.searchFocus.requestFocus();
|
||||
});
|
||||
}
|
||||
|
||||
void _rebuild() {
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_logic
|
||||
..removeListener(_rebuild)
|
||||
..dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle.light,
|
||||
child: Theme(
|
||||
data: AppTheme.dark(),
|
||||
child: Scaffold(
|
||||
key: const Key('search-page'),
|
||||
backgroundColor: AppColors.appBackground,
|
||||
body: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
_header(l10n),
|
||||
Expanded(child: _body(l10n)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _header(AppLocalizations l10n) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(8, 6, 14, 8),
|
||||
child: SizedBox(
|
||||
height: AppDimens.searchHeight,
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox.square(
|
||||
dimension: AppDimens.buttonMedium,
|
||||
child: IconButton(
|
||||
key: const Key('search-back'),
|
||||
padding: EdgeInsets.zero,
|
||||
onPressed: () => Navigator.of(context).maybePop(),
|
||||
icon: const Icon(
|
||||
Icons.arrow_back_ios_new_rounded,
|
||||
color: AppColors.textPrimary,
|
||||
size: 22,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: AppDimens.spaceSm),
|
||||
Expanded(child: _field(l10n)),
|
||||
const SizedBox(width: AppDimens.spaceSm),
|
||||
TextButton(
|
||||
key: const Key('search-cancel'),
|
||||
onPressed: () => Navigator.of(context).maybePop(),
|
||||
child: Text(l10n.searchCancel),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _field(AppLocalizations l10n) {
|
||||
final hasText = _logic.search.text.isNotEmpty;
|
||||
return Container(
|
||||
key: const Key('search-field'),
|
||||
height: AppDimens.searchHeight,
|
||||
padding: const EdgeInsets.symmetric(horizontal: AppDimens.spaceMd),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.contentSurface,
|
||||
borderRadius: BorderRadius.circular(AppDimens.searchRadius),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.search_rounded,
|
||||
color: AppColors.textSecondary,
|
||||
size: 18,
|
||||
),
|
||||
const SizedBox(width: AppDimens.spaceSm),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
key: const Key('discover-search'),
|
||||
controller: _logic.search,
|
||||
focusNode: _logic.searchFocus,
|
||||
autofocus: true,
|
||||
onChanged: (_) => _logic.onSearchChanged(),
|
||||
textInputAction: TextInputAction.search,
|
||||
style: const TextStyle(
|
||||
color: AppColors.textPrimary,
|
||||
fontSize: 14,
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
hintText: l10n.searchDiscover,
|
||||
hintStyle: const TextStyle(
|
||||
color: AppColors.textSecondary,
|
||||
fontSize: 13,
|
||||
),
|
||||
border: InputBorder.none,
|
||||
enabledBorder: InputBorder.none,
|
||||
focusedBorder: InputBorder.none,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (_logic.searchLoading)
|
||||
const SizedBox.square(
|
||||
dimension: 16,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: AppColors.textPrimary,
|
||||
),
|
||||
)
|
||||
else if (hasText)
|
||||
IconButton(
|
||||
key: const Key('search-clear'),
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints.tightFor(width: 24, height: 24),
|
||||
onPressed: () {
|
||||
_logic.search.clear();
|
||||
_logic.onSearchChanged();
|
||||
_logic.searchFocus.requestFocus();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.close_rounded,
|
||||
color: AppColors.textSecondary,
|
||||
size: 16,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _body(AppLocalizations l10n) {
|
||||
if (!_logic.hasSearchQuery) {
|
||||
return EmptyState(
|
||||
key: const Key('search-idle'),
|
||||
icon: Icons.search_rounded,
|
||||
title: l10n.searchDiscover,
|
||||
);
|
||||
}
|
||||
if (_logic.searchLoading) {
|
||||
return const Center(
|
||||
child: SizedBox.square(
|
||||
key: Key('search-loading'),
|
||||
dimension: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: AppColors.textPrimary,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
if (_logic.searchError != null) {
|
||||
return EmptyState(
|
||||
key: const Key('search-error'),
|
||||
icon: Icons.cloud_off_rounded,
|
||||
title: errorText(l10n, _logic.searchError, l10n.searchFailed),
|
||||
actionLabel: l10n.retry,
|
||||
onAction: _logic.retrySearch,
|
||||
);
|
||||
}
|
||||
if (_logic.searchResults.isEmpty) {
|
||||
return EmptyState(
|
||||
key: const Key('search-empty'),
|
||||
icon: Icons.search_off_rounded,
|
||||
title: l10n.noSearchResults,
|
||||
subtitle: l10n.emptyHint,
|
||||
);
|
||||
}
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final width =
|
||||
(constraints.maxWidth -
|
||||
AppDimens.feedPageHorizontal * 2 -
|
||||
AppDimens.homeGridGap * 2) /
|
||||
3;
|
||||
final itemExtent =
|
||||
width / AppDimens.cardCoverAspectRatio +
|
||||
AppDimens.homeCardBodyExtent;
|
||||
return GridView.builder(
|
||||
key: const Key('search-results-grid'),
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
AppDimens.feedPageHorizontal,
|
||||
AppDimens.spaceMd,
|
||||
AppDimens.feedPageHorizontal,
|
||||
AppDimens.spaceXl,
|
||||
),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 3,
|
||||
crossAxisSpacing: AppDimens.homeGridGap,
|
||||
mainAxisSpacing: AppDimens.homeGridRowGap,
|
||||
mainAxisExtent: itemExtent,
|
||||
),
|
||||
itemCount: _logic.searchResults.length,
|
||||
itemBuilder: (context, index) {
|
||||
final drama = _logic.searchResults[index];
|
||||
return HomeFeedCard(
|
||||
drama: drama,
|
||||
onTap: () => unawaited(playDramaFromCatalog(context, drama)),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../core/data/models/drama.dart';
|
||||
import '../../../core/formatting/error_text.dart';
|
||||
import '../../../core/theme/app_colors.dart';
|
||||
import '../../../core/widgets/empty_state.dart';
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
import 'drama_grid.dart';
|
||||
@@ -38,7 +39,15 @@ class DiscoverSearchResults extends StatelessWidget {
|
||||
if (loading) {
|
||||
return const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 80),
|
||||
child: Center(child: CircularProgressIndicator(strokeWidth: 2)),
|
||||
child: Center(
|
||||
child: SizedBox.square(
|
||||
dimension: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: AppColors.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
final message = error;
|
||||
|
||||
@@ -17,7 +17,6 @@ class HomeLogic extends ChangeNotifier {
|
||||
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
Drama currentDrama;
|
||||
int tab = 0;
|
||||
int searchRequest = 0;
|
||||
int resumeRequest = 0;
|
||||
int backRequest = 0;
|
||||
int followingHistoryRequest = 0;
|
||||
@@ -31,10 +30,9 @@ class HomeLogic extends ChangeNotifier {
|
||||
if (!_disposed) notifyListeners();
|
||||
}
|
||||
|
||||
void select(int nextTab, {bool search = false, bool resume = false}) {
|
||||
void select(int nextTab, {bool resume = false}) {
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
tab = nextTab;
|
||||
if (search) searchRequest++;
|
||||
if (resume) resumeRequest++;
|
||||
notify();
|
||||
}
|
||||
@@ -81,7 +79,7 @@ class HomeLogic extends ChangeNotifier {
|
||||
case DiscoverPageAction.home:
|
||||
select(0);
|
||||
case DiscoverPageAction.recommend:
|
||||
select(1, search: true);
|
||||
select(1);
|
||||
case DiscoverPageAction.following:
|
||||
select(2);
|
||||
case DiscoverPageAction.mine:
|
||||
@@ -112,7 +110,7 @@ class HomeLogic extends ChangeNotifier {
|
||||
case MyPageAction.home:
|
||||
select(0);
|
||||
case MyPageAction.recommend:
|
||||
select(1, search: true);
|
||||
select(1);
|
||||
case MyPageAction.following:
|
||||
select(2);
|
||||
case MyPageAction.mine:
|
||||
|
||||
@@ -22,7 +22,7 @@ import '../../core/widgets/app_root_tab.dart';
|
||||
import '../../core/widgets/catalog_endpoint_editor.dart';
|
||||
import '../../core/widgets/empty_state.dart';
|
||||
import '../../l10n/app_localizations.dart';
|
||||
import '../discover/discover_view.dart';
|
||||
import '../discover/search_page.dart';
|
||||
import '../following/following_page.dart';
|
||||
import '../filter/filter_page.dart';
|
||||
import '../mine/mine_types.dart';
|
||||
@@ -292,9 +292,9 @@ class _HomeTabsState extends State<_HomeTabs> {
|
||||
}
|
||||
|
||||
void _openSearch(BuildContext context) {
|
||||
Navigator.of(context).push<void>(
|
||||
MaterialPageRoute(builder: (_) => const DiscoverPage(focusSearch: true)),
|
||||
);
|
||||
Navigator.of(
|
||||
context,
|
||||
).push<void>(MaterialPageRoute(builder: (_) => const SearchPage()));
|
||||
}
|
||||
|
||||
void _pushPage(BuildContext context, Widget page) {
|
||||
|
||||
@@ -26,8 +26,7 @@ import '../../core/formatting/localized_content.dart';
|
||||
import '../../core/theme/app_colors.dart';
|
||||
import '../../core/navigation/fade_page_route.dart';
|
||||
import '../../l10n/app_localizations.dart';
|
||||
import '../discover/discover_types.dart';
|
||||
import '../discover/discover_view.dart';
|
||||
import '../discover/search_page.dart';
|
||||
import '../drama_detail/drama_detail_view.dart';
|
||||
import '../mine/mine_types.dart';
|
||||
import '../mine/mine_view.dart';
|
||||
@@ -1127,13 +1126,10 @@ class PlayerLogic extends ChangeNotifier {
|
||||
onSearch?.call();
|
||||
return;
|
||||
}
|
||||
await showDiscover(context, focusSearch: true);
|
||||
await showDiscover(context);
|
||||
}
|
||||
|
||||
Future<void> showDiscover(
|
||||
BuildContext context, {
|
||||
bool focusSearch = false,
|
||||
}) async {
|
||||
Future<void> showDiscover(BuildContext context) async {
|
||||
if (embedded) {
|
||||
onDiscover?.call();
|
||||
return;
|
||||
@@ -1142,13 +1138,10 @@ class PlayerLogic extends ChangeNotifier {
|
||||
await session.playbackSettled;
|
||||
await saveCurrentProgress();
|
||||
if (!context.mounted) return;
|
||||
final action = await Navigator.of(context).push<DiscoverPageAction>(
|
||||
MaterialPageRoute(builder: (_) => DiscoverPage(focusSearch: focusSearch)),
|
||||
);
|
||||
if (!context.mounted) return;
|
||||
if (action == DiscoverPageAction.mine) {
|
||||
await showMy(context);
|
||||
} else {
|
||||
await Navigator.of(
|
||||
context,
|
||||
).push<void>(MaterialPageRoute(builder: (_) => const SearchPage()));
|
||||
if (context.mounted) {
|
||||
session.setRouteVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,44 +23,6 @@ void main() {
|
||||
logic.dispose();
|
||||
});
|
||||
|
||||
testWidgets('should_focus_search_only_for_new_request_on_active_page', (
|
||||
tester,
|
||||
) async {
|
||||
final logic = DiscoverLogic();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: TextField(
|
||||
controller: logic.search,
|
||||
focusNode: logic.searchFocus,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
logic.syncSearch(
|
||||
active: false,
|
||||
request: 1,
|
||||
previousRequest: 0,
|
||||
isActive: () => false,
|
||||
);
|
||||
await tester.pump();
|
||||
expect(logic.searchFocus.hasFocus, isFalse);
|
||||
|
||||
logic.syncSearch(
|
||||
active: true,
|
||||
request: 2,
|
||||
previousRequest: 1,
|
||||
isActive: () => true,
|
||||
);
|
||||
await tester.pump();
|
||||
await tester.pump();
|
||||
expect(logic.searchFocus.hasFocus, isTrue);
|
||||
|
||||
await tester.pumpWidget(const SizedBox.shrink());
|
||||
logic.dispose();
|
||||
});
|
||||
|
||||
testWidgets('should_forward_action_when_embedded_or_pop_when_standalone', (
|
||||
tester,
|
||||
) async {
|
||||
|
||||
@@ -42,23 +42,17 @@ void main() {
|
||||
logic.select(1);
|
||||
|
||||
expect(logic.tab, 1);
|
||||
expect(logic.searchRequest, 0);
|
||||
expect(logic.resumeRequest, 0);
|
||||
expect(logic.backRequest, 0);
|
||||
expect(notifications, 1);
|
||||
logic.dispose();
|
||||
});
|
||||
|
||||
test('should_raise_only_its_own_counter_when_each_select_flag_is_used', () {
|
||||
test('should_raise_only_resume_counter_when_select_flag_is_used', () {
|
||||
final logic = HomeLogic(dramas);
|
||||
|
||||
logic.select(1, search: true);
|
||||
expect(logic.searchRequest, 1);
|
||||
expect(logic.resumeRequest, 0);
|
||||
|
||||
logic.select(0, resume: true);
|
||||
expect(logic.resumeRequest, 1);
|
||||
expect(logic.searchRequest, 1);
|
||||
logic.dispose();
|
||||
});
|
||||
|
||||
@@ -161,7 +155,6 @@ void main() {
|
||||
|
||||
logic.myAction(MyPageAction.recommend);
|
||||
expect(logic.tab, 1);
|
||||
expect(logic.searchRequest, 1);
|
||||
|
||||
logic.myAction(MyPageAction.following);
|
||||
expect(logic.tab, 2);
|
||||
|
||||
@@ -118,6 +118,10 @@ void main() {
|
||||
await _pumpApp(tester);
|
||||
await tester.tap(find.byKey(const Key('home-search-entry')));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(const Key('search-page')), findsOneWidget);
|
||||
expect(find.byKey(const Key('search-back')), findsOneWidget);
|
||||
expect(find.byKey(const Key('search-cancel')), findsOneWidget);
|
||||
expect(find.byType(AppBottomNav), findsNothing);
|
||||
expect(
|
||||
tester
|
||||
.widget<TextField>(find.byKey(const Key('discover-search')))
|
||||
@@ -125,7 +129,7 @@ void main() {
|
||||
?.hasFocus,
|
||||
isTrue,
|
||||
);
|
||||
await tester.binding.handlePopRoute();
|
||||
await tester.tap(find.byKey(const Key('search-cancel')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byKey(const Key('tab-recommend')));
|
||||
@@ -133,6 +137,20 @@ void main() {
|
||||
await tester.tap(find.byKey(const Key('recommend-search')));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(const Key('discover-search')), findsOneWidget);
|
||||
await tester.enterText(find.byKey(const Key('discover-search')), 'signal');
|
||||
await tester.pump(const Duration(milliseconds: 400));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(const Key('search-results-grid')), findsOneWidget);
|
||||
final results = tester.widget<GridView>(
|
||||
find.byKey(const Key('search-results-grid')),
|
||||
);
|
||||
final delegate =
|
||||
results.gridDelegate as SliverGridDelegateWithFixedCrossAxisCount;
|
||||
expect(delegate.crossAxisCount, 3);
|
||||
await tester.tap(find.byKey(const Key('search-back')));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(const Key('recommend-page')), findsOneWidget);
|
||||
expect(find.byKey(const Key('recommend-tab-recommend')), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('should_open_player_from_home_grid_card', (tester) async {
|
||||
@@ -188,6 +206,7 @@ Future<void> _pumpApp(
|
||||
playerFactory: createWidgetPlayer,
|
||||
catalogRepository: catalog,
|
||||
categoryRepository: FakeCategoryRepository(catalog: catalog),
|
||||
searchRepository: catalog,
|
||||
watchHistoryRepository: InMemoryWatchHistoryRepository(),
|
||||
favoriteRepository: InMemoryFavoriteRepository(cards: catalog.dramas),
|
||||
playbackRepository: FakePlaybackRepository(),
|
||||
|
||||
Reference in new issue
Block a user