Initial commit
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user