feat(recommend): 新增分区流全部短剧与剧单
This commit is contained in:
1 parent
0ef2438100
commit
f1b5418954
22 files changed
+1426
-722
No files matched your search
@@ -0,0 +1,199 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../core/data/models/drama.dart';
|
||||
import '../../core/data/services/catalog_controller.dart';
|
||||
import '../../core/data/services/category_controller.dart';
|
||||
import '../../core/data/services/download_controller.dart';
|
||||
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 '../../l10n/app_localizations.dart';
|
||||
import '../player/player_view.dart';
|
||||
import '../ranking/ranking_page.dart';
|
||||
import 'widgets/all_dramas_filter_grid.dart';
|
||||
import 'widgets/recommend_sections_view.dart';
|
||||
|
||||
enum RecommendInnerTab { feed, playlists, allDramas }
|
||||
|
||||
class RecommendPage extends StatefulWidget {
|
||||
const RecommendPage({
|
||||
super.key,
|
||||
required this.feedController,
|
||||
required this.onSearch,
|
||||
required this.onOpenFilter,
|
||||
});
|
||||
|
||||
final HomeFeedController feedController;
|
||||
final VoidCallback onSearch;
|
||||
final VoidCallback onOpenFilter;
|
||||
|
||||
@override
|
||||
State<RecommendPage> createState() => _RecommendPageState();
|
||||
}
|
||||
|
||||
class _RecommendPageState extends State<RecommendPage> {
|
||||
RecommendInnerTab _tab = RecommendInnerTab.feed;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final categories = context.watch<CategoryController>();
|
||||
return ColoredBox(
|
||||
key: const Key('recommend-page'),
|
||||
color: AppColors.appBackground,
|
||||
child: SafeArea(
|
||||
bottom: false,
|
||||
child: Column(
|
||||
children: [
|
||||
_header(l10n),
|
||||
Expanded(
|
||||
child: IndexedStack(
|
||||
index: _tab.index,
|
||||
children: [
|
||||
RecommendSectionsView(
|
||||
feedController: widget.feedController,
|
||||
categories: categories,
|
||||
onOpenDrama: _openDrama,
|
||||
onMore: _handleMore,
|
||||
),
|
||||
const RankingPage(embedded: true),
|
||||
AllDramasFilterGrid(
|
||||
feedController: widget.feedController,
|
||||
onOpenDrama: _openDrama,
|
||||
onOpenFilter: widget.onOpenFilter,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
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,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: AppDimens.pageHorizontal,
|
||||
),
|
||||
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.textSecondary,
|
||||
fontSize: AppDimens.listTitle,
|
||||
fontWeight: selected ? FontWeight.w700 : FontWeight.w500,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 3),
|
||||
Container(
|
||||
width: selected ? 20 : 0,
|
||||
height: 2,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.textPrimary,
|
||||
borderRadius: BorderRadius.circular(AppDimens.pillRadius),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _handleMore(RecommendSectionKind section) {
|
||||
setState(() {
|
||||
_tab = section == RecommendSectionKind.hits
|
||||
? RecommendInnerTab.playlists
|
||||
: RecommendInnerTab.allDramas;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _openDrama(Drama drama) async {
|
||||
final catalog = context.read<CatalogController>();
|
||||
final wallet = context.read<WalletController>();
|
||||
final downloads = context.read<DownloadController>();
|
||||
var playable = drama;
|
||||
try {
|
||||
playable = await catalog.requireDetail(drama);
|
||||
} catch (_) {
|
||||
// 卡片预览仍可直接进入播放器。
|
||||
}
|
||||
if (!mounted) return;
|
||||
await Navigator.of(context).push<void>(
|
||||
FadePageRoute(
|
||||
builder: (_) => PlayerPage(
|
||||
drama: playable,
|
||||
initialIndex: 0,
|
||||
homeMode: true,
|
||||
feedDramas: [playable],
|
||||
wallet: wallet,
|
||||
downloads: downloads,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user