Files

165 lines
4.7 KiB
Dart
Raw Permalink Normal View History

2026-07-14 11:11:36 +08:00
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../shared/theme/app_theme.dart';
import '../../shared/widgets/app_sliver_header.dart';
import '../../shared/widgets/page_background.dart';
import '../../shared/widgets/pill_tab_bar.dart';
import '../favorites/aggregated_favorites_page.dart';
import '../history/history_page.dart';
import 'aggregated_recent_page.dart';
const _kTabHistory = 'history';
const _kTabFavorites = 'favorites';
const _kTabRecent = 'recent';
int _tabIndexFromKey(String? key) => switch (key) {
_kTabFavorites => 1,
_kTabRecent => 2,
_ => 0,
};
String _tabKeyFromIndex(int index) => switch (index) {
1 => _kTabFavorites,
2 => _kTabRecent,
_ => _kTabHistory,
};
class AggregatedViewPage extends ConsumerStatefulWidget {
final String? initialTab;
final bool isCompactMode;
const AggregatedViewPage({
super.key,
this.initialTab,
this.isCompactMode = false,
});
@override
ConsumerState<AggregatedViewPage> createState() => _AggregatedViewPageState();
}
class _AggregatedViewPageState extends ConsumerState<AggregatedViewPage> {
late int _index;
int _historyRefreshSeed = 0;
int _favoritesRefreshSeed = 0;
int _recentRefreshSeed = 0;
String get _storagePrefix => widget.isCompactMode ? 'watch' : 'aggregated';
@override
void initState() {
super.initState();
_index = _tabIndexFromKey(widget.initialTab);
}
@override
void didUpdateWidget(covariant AggregatedViewPage oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.initialTab != oldWidget.initialTab) {
final next = _tabIndexFromKey(widget.initialTab);
if (next != _index) {
setState(() => _index = next);
}
}
}
void _onTabChanged(int next) {
if (next == _index) return;
setState(() => _index = next);
final key = _tabKeyFromIndex(next);
context.go('/aggregated?tab=$key');
}
Future<void> _refreshActive() async {
setState(() {
switch (_index) {
case 1:
_favoritesRefreshSeed++;
break;
case 2:
_recentRefreshSeed++;
break;
default:
_historyRefreshSeed++;
}
});
await Future<void>.delayed(const Duration(milliseconds: 250));
}
@override
Widget build(BuildContext context) {
final tokens = context.appTokens;
final firstTabLabel = widget.isCompactMode ? '继续观看' : '播放记录';
return Scaffold(
extendBodyBehindAppBar: true,
backgroundColor: Colors.transparent,
body: Stack(
children: [
const Positioned.fill(child: PageBackground()),
RefreshIndicator(
onRefresh: _refreshActive,
child: NestedScrollView(
physics: const AlwaysScrollableScrollPhysics(
parent: BouncingScrollPhysics(),
),
floatHeaderSlivers: false,
headerSliverBuilder: (context, innerBoxIsScrolled) => [
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
context,
),
sliver: AppSliverHeader(
toolbarHeight: tokens.titleBarHeight,
automaticallyImplyLeading: false,
titleWidget: _buildTitleRow(firstTabLabel),
),
),
],
body: IndexedStack(
index: _index,
children: [
KeyedSubtree(
key: PageStorageKey(
'${_storagePrefix}_history_$_historyRefreshSeed',
),
child: const HistoryPage(embedded: true),
),
KeyedSubtree(
key: PageStorageKey(
'${_storagePrefix}_favorites_$_favoritesRefreshSeed',
),
child: const AggregatedFavoritesPage(embedded: true),
),
KeyedSubtree(
key: PageStorageKey(
'${_storagePrefix}_recent_$_recentRefreshSeed',
),
child: const AggregatedRecentPage(embedded: true),
),
],
),
),
),
],
),
);
}
Widget _buildTitleRow(String firstTabLabel) {
final tabBar = PillTabBar(
padding: const EdgeInsets.only(left: 8),
tabs: [firstTabLabel, '我的收藏', '最近添加'],
selectedIndex: _index,
onSelect: _onTabChanged,
);
return Align(alignment: Alignment.centerLeft, child: tabBar);
}
}