feat(nav): 底部导航改为首页推荐追剧我的

This commit is contained in:
Zhou Weidong committed 2026-10-22 16:21:05 +08:00
1 parent ec3cb8f163
commit 91e869d589
34 files changed
+359 -263

No files matched your search

+2 -2
View File
@@ -4,8 +4,8 @@ import 'package:flutter/foundation.dart';
import '../../core/data/models/drama.dart';
/// 剧场页与根导航之间的动作。
enum DiscoverPageAction { home, create, my }
/// 推荐页与根导航之间的动作。
enum DiscoverPageAction { home, recommend, following, mine }
/// 剧场页导航回调;没有 `onAction` 时按独立页面处理。
class DiscoverPageCallbacks {
+20 -30
View File
@@ -19,6 +19,7 @@ import '../../core/theme/app_dimens.dart';
import '../../core/theme/app_theme.dart';
import '../../core/widgets/app_bottom_nav.dart';
import '../../core/widgets/app_pull_to_refresh.dart';
import '../../core/widgets/app_root_tab.dart';
import '../../core/widgets/catalog_debug_info.dart';
import '../../core/widgets/catalog_endpoint_editor.dart';
import '../../core/widgets/empty_state.dart';
@@ -149,7 +150,7 @@ class _DiscoverPageState extends State<DiscoverPage> {
key: const Key('theater-page-surface'),
color: AppColors.ink,
child: SafeArea(
bottom: !embedded,
bottom: false,
child: Column(
children: [
DiscoverHeader(
@@ -613,37 +614,26 @@ class _DiscoverPageState extends State<DiscoverPage> {
Widget _bottomNav(AppLocalizations l10n) => AppBottomNav(
items: [
AppBottomNavItem(
tabKey: const Key('discover-nav-home'),
icon: Icons.home_outlined,
selectedIcon: Icons.home_rounded,
label: l10n.homeTab,
onTap: () => _act(DiscoverPageAction.home),
),
AppBottomNavItem(
tabKey: const Key('discover-nav-current'),
icon: Icons.explore_outlined,
selectedIcon: Icons.explore_rounded,
label: l10n.theaterTab,
selected: true,
onTap: () {},
),
AppBottomNavItem(
tabKey: const Key('discover-nav-create'),
icon: Icons.add_box_outlined,
selectedIcon: Icons.add_box_rounded,
label: l10n.createTab,
onTap: () => _act(DiscoverPageAction.create),
),
AppBottomNavItem(
tabKey: const Key('discover-nav-my'),
icon: Icons.person_outline_rounded,
selectedIcon: Icons.person_rounded,
label: l10n.myTab,
onTap: () => _act(DiscoverPageAction.my),
),
for (final tab in AppRootTab.values)
AppBottomNavItem(
tabKey: tab.tabKey,
icon: tab.icon,
selectedIcon: tab.selectedIcon,
label: tab.label(l10n),
selected: tab == AppRootTab.recommend,
onTap: tab == AppRootTab.recommend
? () {}
: () => _act(_actionOf(tab)),
),
],
);
DiscoverPageAction _actionOf(AppRootTab tab) => switch (tab) {
AppRootTab.home => DiscoverPageAction.home,
AppRootTab.recommend => DiscoverPageAction.recommend,
AppRootTab.following => DiscoverPageAction.following,
AppRootTab.mine => DiscoverPageAction.mine,
};
}
/// 分类 tab 的弧形选中线。
+36 -24
View File
@@ -44,14 +44,33 @@ const double _loadMoreThreshold = 240;
final RegExp _tagSplitter = RegExp(r'[,/、·]');
/// 独立我的收藏页。
class FavoritesPage extends StatefulWidget {
class FavoritesPage extends StatelessWidget {
const FavoritesPage({super.key});
@override
State<FavoritesPage> createState() => _FavoritesPageState();
Widget build(BuildContext context) {
return Theme(
data: AppTheme.dark(),
child: Scaffold(
key: const Key('favorites-page'),
backgroundColor: AppColors.ink,
body: const SafeArea(child: FavoritesContent()),
),
);
}
}
class _FavoritesPageState extends State<FavoritesPage> {
/// 收藏列表主体;可独立使用,也可直接嵌入根导航。
class FavoritesContent extends StatefulWidget {
const FavoritesContent({super.key, this.showBack = true});
final bool showBack;
@override
State<FavoritesContent> createState() => _FavoritesContentState();
}
class _FavoritesContentState extends State<FavoritesContent> {
bool _requested = false;
@override
@@ -74,28 +93,21 @@ class _FavoritesPageState extends State<FavoritesPage> {
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
final signedIn = context.watch<AuthController>().isSignedIn;
return Theme(
data: AppTheme.dark(),
child: Scaffold(
key: const Key('favorites-page'),
backgroundColor: AppColors.ink,
body: SafeArea(
child: Column(
children: [
AppSubpageHeader(
title: l10n.myFavorites,
backKey: const Key('favorites-back'),
),
Expanded(
child: signedIn
? _FavoritesBody(
favorites: context.watch<FavoriteController>(),
)
: const AuthGatePanel(),
),
],
return SafeArea(
bottom: false,
child: Column(
children: [
AppSubpageHeader(
title: l10n.myFavorites,
backKey: const Key('favorites-back'),
showBack: widget.showBack,
),
),
Expanded(
child: signedIn
? _FavoritesBody(favorites: context.watch<FavoriteController>())
: const AuthGatePanel(),
),
],
),
);
}
+8 -4
View File
@@ -79,9 +79,11 @@ class HomeLogic extends ChangeNotifier {
switch (action) {
case DiscoverPageAction.home:
select(0);
case DiscoverPageAction.create:
case DiscoverPageAction.recommend:
select(1, search: true);
case DiscoverPageAction.following:
select(2);
case DiscoverPageAction.my:
case DiscoverPageAction.mine:
select(3);
}
}
@@ -102,10 +104,12 @@ class HomeLogic extends ChangeNotifier {
switch (action) {
case MyPageAction.home:
select(0);
case MyPageAction.discover:
case MyPageAction.recommend:
select(1, search: true);
case MyPageAction.create:
case MyPageAction.following:
select(2);
case MyPageAction.mine:
select(3);
case MyPageAction.resume:
select(0, resume: true);
}
+16 -42
View File
@@ -17,13 +17,14 @@ import '../../core/platform/haptics.dart';
import '../../core/theme/app_colors.dart';
import '../../core/theme/app_theme.dart';
import '../../core/widgets/app_bottom_nav.dart';
import '../../core/widgets/app_root_tab.dart';
import '../../core/widgets/catalog_debug_info.dart';
import '../../core/widgets/catalog_endpoint_editor.dart';
import '../../core/widgets/empty_state.dart';
import '../../l10n/app_localizations.dart';
import '../discover/discover_types.dart';
import '../discover/discover_view.dart';
import '../create/create_view.dart';
import '../favorites/favorites_page.dart';
import '../mine/mine_types.dart';
import '../player/widgets/home_feed_header.dart';
import '../player/player_view.dart';
@@ -295,7 +296,7 @@ class _HomeTabsState extends State<_HomeTabs> {
children: [
_home(context),
_discover(context),
const CreatePage(),
const FavoritesContent(key: Key('favorites-page'), showBack: false),
_my(context),
],
);
@@ -455,10 +456,10 @@ class _HomeTabsState extends State<_HomeTabs> {
barKey: const Key('home-tabs-bar'),
dark: logic.tab == 0,
items: [
_navItem(context, l10n, 0),
_navItem(context, l10n, 1),
_navItem(context, l10n, 2),
_navItem(context, l10n, 3),
_navItem(context, l10n, AppRootTab.home),
_navItem(context, l10n, AppRootTab.recommend),
_navItem(context, l10n, AppRootTab.following),
_navItem(context, l10n, AppRootTab.mine),
],
);
}
@@ -466,43 +467,16 @@ class _HomeTabsState extends State<_HomeTabs> {
AppBottomNavItem _navItem(
BuildContext context,
AppLocalizations l10n,
int index,
AppRootTab tab,
) {
final selected = logic.tab == index;
return switch (index) {
0 => AppBottomNavItem(
tabKey: const Key('tab-home'),
icon: Icons.home_outlined,
selectedIcon: Icons.home_rounded,
label: l10n.homeTab,
selected: selected,
onTap: () => _selectTab(context, index),
),
1 => AppBottomNavItem(
tabKey: const Key('tab-theater'),
icon: Icons.explore_outlined,
selectedIcon: Icons.explore_rounded,
label: l10n.theaterTab,
selected: selected,
onTap: () => _selectTab(context, index),
),
2 => AppBottomNavItem(
tabKey: const Key('tab-create'),
icon: Icons.add_box_outlined,
selectedIcon: Icons.add_box_rounded,
label: l10n.createTab,
selected: selected,
onTap: () => _selectTab(context, index),
),
_ => AppBottomNavItem(
tabKey: const Key('tab-mine'),
icon: Icons.person_outline_rounded,
selectedIcon: Icons.person_rounded,
label: l10n.myTab,
selected: selected,
onTap: () => _selectTab(context, index),
),
};
return AppBottomNavItem(
tabKey: tab.tabKey,
icon: tab.icon,
selectedIcon: tab.selectedIcon,
label: tab.label(l10n),
selected: logic.tab == tab.index,
onTap: () => _selectTab(context, tab.index),
);
}
void _selectTab(BuildContext context, int tab) {
+1 -1
View File
@@ -5,7 +5,7 @@ import 'package:flutter/foundation.dart';
import '../../core/data/models/drama.dart';
/// 「我的」页与根导航之间的返回动作。
enum MyPageAction { home, discover, create, resume }
enum MyPageAction { home, recommend, following, mine, resume }
/// 「我的」页可进入的功能目的地。
enum MineDestination {
+18 -30
View File
@@ -13,6 +13,7 @@ import '../../core/theme/app_colors.dart';
import '../../core/theme/app_dimens.dart';
import '../../core/theme/app_theme.dart';
import '../../core/widgets/app_bottom_nav.dart';
import '../../core/widgets/app_root_tab.dart';
import '../../core/widgets/auth_gate.dart';
import '../../core/widgets/plain_page_scaffold.dart';
import '../../l10n/app_localizations.dart';
@@ -81,7 +82,7 @@ class _MyPageState extends State<MyPage> {
Widget _page(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
final content = SafeArea(
bottom: !embedded,
bottom: false,
child: Column(
children: [
_topBar(l10n),
@@ -240,39 +241,26 @@ class _MyPageState extends State<MyPage> {
Widget _bottomNav(AppLocalizations l10n) {
return AppBottomNav(
items: [
AppBottomNavItem(
tabKey: const Key('mine-nav-home'),
icon: Icons.home_outlined,
selectedIcon: Icons.home_rounded,
label: l10n.homeTab,
onTap: () => _act(MyPageAction.home),
),
AppBottomNavItem(
tabKey: const Key('mine-nav-discover'),
icon: Icons.explore_outlined,
selectedIcon: Icons.explore_rounded,
label: l10n.theaterTab,
onTap: () => _act(MyPageAction.discover),
),
AppBottomNavItem(
tabKey: const Key('mine-nav-create'),
icon: Icons.add_box_outlined,
selectedIcon: Icons.add_box_rounded,
label: l10n.createTab,
onTap: () => _act(MyPageAction.create),
),
AppBottomNavItem(
tabKey: const Key('mine-nav-current'),
icon: Icons.person_outline_rounded,
selectedIcon: Icons.person_rounded,
label: l10n.myTab,
selected: true,
onTap: () {},
),
for (final tab in AppRootTab.values)
AppBottomNavItem(
tabKey: tab.tabKey,
icon: tab.icon,
selectedIcon: tab.selectedIcon,
label: tab.label(l10n),
selected: tab == AppRootTab.mine,
onTap: tab == AppRootTab.mine ? () {} : () => _act(_actionOf(tab)),
),
],
);
}
MyPageAction _actionOf(AppRootTab tab) => switch (tab) {
AppRootTab.home => MyPageAction.home,
AppRootTab.recommend => MyPageAction.recommend,
AppRootTab.following => MyPageAction.following,
AppRootTab.mine => MyPageAction.mine,
};
void _act(MyPageAction action) {
logic.act(
context,
+2 -2
View File
@@ -1085,7 +1085,7 @@ class PlayerLogic extends ChangeNotifier {
context,
).push<MyPageAction>(MaterialPageRoute(builder: (_) => const MyPage()));
if (!context.mounted) return;
if (action == MyPageAction.discover) {
if (action == MyPageAction.recommend) {
await showDiscover(context);
} else {
session.setRouteVisible(true);
@@ -1117,7 +1117,7 @@ class PlayerLogic extends ChangeNotifier {
MaterialPageRoute(builder: (_) => DiscoverPage(focusSearch: focusSearch)),
);
if (!context.mounted) return;
if (action == DiscoverPageAction.my) {
if (action == DiscoverPageAction.mine) {
await showMy(context);
} else {
session.setRouteVisible(true);