feat(recommend): 对齐沉浸式推荐页视觉布局
This commit is contained in:
1 parent
77689a3eaa
commit
5dd3492aea
17 files changed
+831
-398
No files matched your search
@@ -13,14 +13,13 @@ import '../../core/data/services/home_feed_controller.dart';
|
||||
import '../../core/data/services/wallet_controller.dart';
|
||||
import '../../core/navigation/fade_page_route.dart';
|
||||
import '../../core/theme/app_colors.dart';
|
||||
import '../../core/theme/app_dimens.dart';
|
||||
import '../../core/widgets/empty_state.dart';
|
||||
import '../../l10n/app_localizations.dart';
|
||||
import '../player/player_view.dart';
|
||||
import 'recommend_types.dart';
|
||||
import 'widgets/all_dramas_filter_grid.dart';
|
||||
import 'widgets/recommend_sections_view.dart';
|
||||
|
||||
enum RecommendInnerTab { feed, playlists, allDramas }
|
||||
import 'widgets/recommend_top_nav.dart';
|
||||
|
||||
class RecommendPage extends StatefulWidget {
|
||||
const RecommendPage({
|
||||
@@ -50,38 +49,49 @@ class _RecommendPageState extends State<RecommendPage> {
|
||||
return ColoredBox(
|
||||
key: const Key('recommend-page'),
|
||||
color: AppColors.appBackground,
|
||||
child: SafeArea(
|
||||
bottom: false,
|
||||
child: Column(
|
||||
children: [
|
||||
_header(l10n),
|
||||
Expanded(
|
||||
child: ListenableBuilder(
|
||||
listenable: Listenable.merge([
|
||||
widget.feedController,
|
||||
categories,
|
||||
]),
|
||||
builder: (context, _) => IndexedStack(
|
||||
index: _tab.index,
|
||||
children: [
|
||||
_recommendFeed(context),
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: ListenableBuilder(
|
||||
listenable: Listenable.merge([widget.feedController, categories]),
|
||||
builder: (context, _) => IndexedStack(
|
||||
index: _tab.index,
|
||||
children: [
|
||||
_recommendFeed(context),
|
||||
_withTopNavSpace(
|
||||
RecommendSectionsView(
|
||||
feedController: widget.feedController,
|
||||
categories: categories,
|
||||
onOpenDrama: _openDrama,
|
||||
onMore: _handleMore,
|
||||
),
|
||||
),
|
||||
_withTopNavSpace(
|
||||
AllDramasFilterGrid(
|
||||
feedController: widget.feedController,
|
||||
onOpenDrama: _openDrama,
|
||||
onOpenFilter: widget.onOpenFilter,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: SafeArea(
|
||||
bottom: false,
|
||||
child: RecommendTopNav(
|
||||
selected: _tab,
|
||||
onVideo: _tab == RecommendInnerTab.feed,
|
||||
onSelected: (tab) => setState(() => _tab = tab),
|
||||
onSearch: widget.onSearch,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -129,88 +139,12 @@ class _RecommendPageState extends State<RecommendPage> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _header(AppLocalizations l10n) {
|
||||
final items = [
|
||||
(RecommendInnerTab.feed, l10n.recommendTopTab, 'recommend'),
|
||||
(RecommendInnerTab.playlists, l10n.playlistTopTab, 'playlist'),
|
||||
(RecommendInnerTab.allDramas, l10n.allDramasTopTab, 'all'),
|
||||
];
|
||||
return SizedBox(
|
||||
key: const Key('recommend-top-nav'),
|
||||
height: 56,
|
||||
Widget _withTopNavSpace(Widget child) {
|
||||
return SafeArea(
|
||||
bottom: false,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: AppDimens.feedPageHorizontal,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
for (final item in items)
|
||||
Expanded(
|
||||
child: _tabButton(
|
||||
key: Key('recommend-tab-${item.$3}'),
|
||||
label: item.$2,
|
||||
selected: _tab == item.$1,
|
||||
onTap: () => setState(() => _tab = item.$1),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: AppDimens.spaceSm),
|
||||
IconButton(
|
||||
key: const Key('recommend-search'),
|
||||
tooltip: l10n.search,
|
||||
onPressed: widget.onSearch,
|
||||
iconSize: 24,
|
||||
color: AppColors.textPrimary,
|
||||
icon: const Icon(Icons.search_rounded),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _tabButton({
|
||||
required Key key,
|
||||
required String label,
|
||||
required bool selected,
|
||||
required VoidCallback onTap,
|
||||
}) {
|
||||
return InkWell(
|
||||
key: key,
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: AppDimens.spaceSm),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
color: selected
|
||||
? AppColors.textPrimary
|
||||
: AppColors.textTertiary,
|
||||
fontSize: AppDimens.homePrimaryTabFont,
|
||||
fontWeight: selected ? FontWeight.w700 : FontWeight.w400,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 3),
|
||||
Container(
|
||||
width: selected ? 20 : 0,
|
||||
height: 2,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.textPrimary,
|
||||
borderRadius: BorderRadius.circular(AppDimens.pillRadius),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
padding: const EdgeInsets.only(top: RecommendTopNav.height),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user