feat(home): 顶部导航随翻页联动并把推荐更名为精选
This commit is contained in:
1 parent
2f4593a46e
commit
335e5dc286
27 files changed
+1095
-214
No files matched your search
@@ -20,12 +20,15 @@ import '../../l10n/app_localizations.dart';
|
||||
import '../home/home_feed_channel.dart';
|
||||
import '../player/open_player.dart';
|
||||
import '../player/player_view.dart';
|
||||
import 'home_tab_motion_controller.dart';
|
||||
import 'recommend_types.dart';
|
||||
import 'widgets/all_dramas_filter_grid.dart';
|
||||
import 'widgets/playlist_detail_page.dart';
|
||||
import 'widgets/recommend_sections_view.dart';
|
||||
import 'widgets/recommend_top_nav.dart';
|
||||
|
||||
part 'recommend_page_parts.dart';
|
||||
|
||||
class RecommendPage extends StatefulWidget {
|
||||
const RecommendPage({
|
||||
super.key,
|
||||
@@ -60,7 +63,9 @@ class _RecommendPageState extends State<RecommendPage>
|
||||
static const int _maxRecommendRetries = 3;
|
||||
|
||||
RecommendInnerTab _tab = RecommendInnerTab.feed;
|
||||
final PageController _pageController = PageController();
|
||||
late final _pageController = HomeTabMotionController(
|
||||
onSettled: _onPageChanged,
|
||||
);
|
||||
int _scrubCancelRequest = 0;
|
||||
bool _recommendDataRefreshScheduled = false;
|
||||
bool _recommendRefreshInFlight = false;
|
||||
@@ -274,12 +279,16 @@ class _RecommendPageState extends State<RecommendPage>
|
||||
right: 0,
|
||||
child: SafeArea(
|
||||
bottom: false,
|
||||
child: RecommendTopNav(
|
||||
selected: _tab,
|
||||
onVideo: _tab == RecommendInnerTab.feed,
|
||||
onSelected: _selectTab,
|
||||
onSearch: _handleSearch,
|
||||
onGift: widget.onOpenWallet,
|
||||
child: ListenableBuilder(
|
||||
listenable: _pageController,
|
||||
builder: (context, _) => RecommendTopNav(
|
||||
selected: _tab,
|
||||
pagePosition: _pageController.pagePosition,
|
||||
onVideo: _tab == RecommendInnerTab.feed,
|
||||
onSelected: _selectTab,
|
||||
onSearch: _handleSearch,
|
||||
onGift: widget.onOpenWallet,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -401,18 +410,16 @@ class _RecommendPageState extends State<RecommendPage>
|
||||
_tab = tab;
|
||||
_scrubCancelRequest++;
|
||||
});
|
||||
if (_pageController.hasClients) {
|
||||
unawaited(
|
||||
_pageController.animateToPage(
|
||||
tab.index,
|
||||
duration: const Duration(milliseconds: 220),
|
||||
curve: Curves.easeOut,
|
||||
),
|
||||
);
|
||||
}
|
||||
unawaited(
|
||||
_pageController.selectPage(
|
||||
tab.index,
|
||||
reduceMotion: MediaQuery.disableAnimationsOf(context),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onPageChanged(int index) {
|
||||
if (!_pageController.acceptsSelection(index)) return;
|
||||
final next = RecommendInnerTab.values[index];
|
||||
if (next == _tab) return;
|
||||
setState(() {
|
||||
@@ -484,110 +491,7 @@ class _RecommendPageState extends State<RecommendPage>
|
||||
);
|
||||
}
|
||||
|
||||
(String, String) _sectionCopy(
|
||||
AppLocalizations l10n,
|
||||
RecommendSectionKind section,
|
||||
) {
|
||||
return switch (section) {
|
||||
RecommendSectionKind.hits => (
|
||||
l10n.weeklyHitsTitle,
|
||||
l10n.weeklyHitsSubtitle,
|
||||
),
|
||||
RecommendSectionKind.newReleases => (
|
||||
l10n.weeklyNewTitle,
|
||||
l10n.weeklyNewSubtitle,
|
||||
),
|
||||
RecommendSectionKind.costume => (
|
||||
l10n.costumeAwardsTitle,
|
||||
l10n.costumeAwardsSubtitle,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
Future<void> _openDrama(Drama drama, {String? episodeId}) async {
|
||||
await playDramaFromCatalog(context, drama, episodeId: episodeId);
|
||||
}
|
||||
}
|
||||
|
||||
class _RecommendFeedSkeleton extends StatelessWidget {
|
||||
const _RecommendFeedSkeleton();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const ColoredBox(
|
||||
key: Key('recommend-feed-skeleton'),
|
||||
color: AppColors.mediaBlack,
|
||||
child: Stack(
|
||||
children: [
|
||||
Center(
|
||||
child: SizedBox(
|
||||
width: 132,
|
||||
height: 176,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.skeletonMedia,
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 14,
|
||||
right: 72,
|
||||
bottom: 42,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_SkeletonLine(width: 190, height: 18),
|
||||
SizedBox(height: 10),
|
||||
_SkeletonLine(width: 140, height: 12),
|
||||
SizedBox(height: 8),
|
||||
_SkeletonLine(width: 220, height: 10),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SkeletonLine extends StatelessWidget {
|
||||
const _SkeletonLine({required this.width, required this.height});
|
||||
|
||||
final double width;
|
||||
final double height;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: width,
|
||||
height: height,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.skeletonMedia,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _KeepAliveTab extends StatefulWidget {
|
||||
const _KeepAliveTab({super.key, required this.child});
|
||||
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
State<_KeepAliveTab> createState() => _KeepAliveTabState();
|
||||
}
|
||||
|
||||
class _KeepAliveTabState extends State<_KeepAliveTab>
|
||||
with AutomaticKeepAliveClientMixin<_KeepAliveTab> {
|
||||
@override
|
||||
bool get wantKeepAlive => true;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
return widget.child;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user