165 lines
4.7 KiB
Dart
165 lines
4.7 KiB
Dart
|
|
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);
|
||
|
|
}
|
||
|
|
}
|