feat: 开屏后直接展示首页骨架
This commit is contained in:
1 parent
56d7abc6b1
commit
5f278a3510
10 files changed
+300
-166
No files matched your search
@@ -12,10 +12,11 @@ import '../player/open_player.dart';
|
||||
import '../watch_records/watch_records_page.dart';
|
||||
|
||||
class HomeLogic extends ChangeNotifier {
|
||||
HomeLogic(List<Drama> dramas) : currentDrama = dramas.first;
|
||||
HomeLogic(List<Drama> dramas)
|
||||
: currentDrama = dramas.isEmpty ? null : dramas.first;
|
||||
|
||||
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
Drama currentDrama;
|
||||
Drama? currentDrama;
|
||||
int tab = 0;
|
||||
int resumeRequest = 0;
|
||||
int backRequest = 0;
|
||||
@@ -44,13 +45,15 @@ class HomeLogic extends ChangeNotifier {
|
||||
}
|
||||
|
||||
Future<void> openCurrentSeries(BuildContext context) async {
|
||||
final drama = currentDrama;
|
||||
if (drama == null) return;
|
||||
detailOpen = true;
|
||||
notify();
|
||||
await WidgetsBinding.instance.endOfFrame;
|
||||
if (!context.mounted) return;
|
||||
try {
|
||||
await Navigator.of(context).push<void>(
|
||||
MaterialPageRoute(builder: (_) => DramaDetailPage(drama: currentDrama)),
|
||||
MaterialPageRoute(builder: (_) => DramaDetailPage(drama: drama)),
|
||||
);
|
||||
} finally {
|
||||
if (context.mounted) {
|
||||
|
||||
@@ -9,7 +9,6 @@ import 'package:provider/provider.dart';
|
||||
import '../../core/config/app_config.dart';
|
||||
import '../../core/data/services/home_feed_controller.dart';
|
||||
import '../../core/data/services/catalog_controller.dart';
|
||||
import '../../core/data/services/catalog_retry.dart';
|
||||
import '../../core/data/services/category_controller.dart';
|
||||
import '../../core/data/services/favorite_controller.dart';
|
||||
import '../../core/data/services/wallet_controller.dart';
|
||||
@@ -18,9 +17,6 @@ import '../../core/theme/app_colors.dart';
|
||||
import '../../core/theme/app_theme.dart';
|
||||
import '../../core/widgets/auth_gate.dart';
|
||||
import '../../core/widgets/app_root_tab.dart';
|
||||
import '../../core/widgets/catalog_endpoint_editor.dart';
|
||||
import '../../core/widgets/empty_state.dart';
|
||||
import '../../l10n/app_localizations.dart';
|
||||
import '../discover/search_page.dart';
|
||||
import '../following/following_page.dart';
|
||||
import '../filter/filter_page.dart';
|
||||
@@ -32,7 +28,6 @@ import '../wallet/wallet_page.dart';
|
||||
import 'home_binding.dart';
|
||||
import 'home_logic.dart';
|
||||
import 'widgets/home_feed_grid.dart';
|
||||
import 'widgets/home_failure_view.dart';
|
||||
import 'widgets/home_grid_header.dart';
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
@@ -85,58 +80,15 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _retryHome(CatalogController catalog) {
|
||||
return retryCatalogLoad(reload: catalog.load);
|
||||
}
|
||||
|
||||
Future<void> _editHomeEndpoint(CatalogController catalog) {
|
||||
return showCatalogEndpointEditor(context, reload: catalog.load);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final catalog = context.watch<CatalogController>();
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return Theme(
|
||||
data: AppTheme.dark(),
|
||||
child: _buildHome(context, catalog, l10n),
|
||||
);
|
||||
return Theme(data: AppTheme.dark(), child: _buildHome(context, catalog));
|
||||
}
|
||||
|
||||
Widget _buildHome(
|
||||
BuildContext context,
|
||||
CatalogController catalog,
|
||||
AppLocalizations l10n,
|
||||
) {
|
||||
if (catalog.loading) {
|
||||
return _retryLoading();
|
||||
}
|
||||
if (catalog.error != null) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.transparent,
|
||||
body: HomeFailureView(
|
||||
error: catalog.debugError ?? catalog.error,
|
||||
onRetry: () => unawaited(_retryHome(catalog)),
|
||||
onEditEndpoint: () => unawaited(_editHomeEndpoint(catalog)),
|
||||
),
|
||||
);
|
||||
}
|
||||
if (catalog.dramas.isEmpty) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.transparent,
|
||||
body: EmptyState(
|
||||
key: const Key('home-empty'),
|
||||
icon: Icons.movie_outlined,
|
||||
title: l10n.noStories,
|
||||
subtitle: l10n.emptyHint,
|
||||
actionLabel: l10n.retry,
|
||||
onAction: catalog.load,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHome(BuildContext context, CatalogController catalog) {
|
||||
final homeFeed = _ensureHomeFeed(catalog);
|
||||
if (!_recommendSeeded) {
|
||||
if (!_recommendSeeded && catalog.dramas.isNotEmpty) {
|
||||
_recommendSeeded = true;
|
||||
homeFeed.seedRecommend(catalog.dramas);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
@@ -155,16 +107,6 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
|
||||
await homeFeed.prefetchChannels();
|
||||
}
|
||||
}
|
||||
|
||||
Widget _retryLoading() {
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle.light,
|
||||
child: const Scaffold(
|
||||
backgroundColor: AppColors.splashInk,
|
||||
body: Center(child: CircularProgressIndicator(color: AppColors.blue)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 四个根页面共享同一路由并保持各自状态。
|
||||
|
||||
@@ -8,12 +8,14 @@ import 'package:provider/provider.dart';
|
||||
import '../../../core/data/models/content_category.dart';
|
||||
import '../../../core/data/models/drama.dart';
|
||||
import '../../../core/data/services/auth_controller.dart';
|
||||
import '../../../core/data/services/catalog_controller.dart';
|
||||
import '../../../core/data/services/category_controller.dart';
|
||||
import '../../../core/data/services/home_feed_controller.dart';
|
||||
import '../../../core/data/services/wallet_controller.dart';
|
||||
import '../../../core/theme/app_colors.dart';
|
||||
import '../../../core/theme/app_dimens.dart';
|
||||
import '../../../core/widgets/app_pull_to_refresh.dart';
|
||||
import '../../../core/widgets/drama_grid_skeleton.dart';
|
||||
import '../../../core/widgets/empty_state.dart';
|
||||
import '../../../core/widgets/paged_list_footer.dart';
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
@@ -75,6 +77,7 @@ class _HomeFeedGridState extends State<HomeFeedGrid> {
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final categories = context.watch<CategoryController>().categories;
|
||||
final catalog = context.watch<CatalogController>();
|
||||
final auth = context.watch<AuthController>();
|
||||
final wallet = context.watch<WalletController>();
|
||||
final shortcuts = _categoryShortcuts(categories, l10n);
|
||||
@@ -123,6 +126,7 @@ class _HomeFeedGridState extends State<HomeFeedGrid> {
|
||||
context,
|
||||
l10n,
|
||||
tab: HomePrimaryTab.values[index],
|
||||
catalog: catalog,
|
||||
shortcuts: shortcuts,
|
||||
),
|
||||
),
|
||||
@@ -154,21 +158,36 @@ class _HomeFeedGridState extends State<HomeFeedGrid> {
|
||||
BuildContext context,
|
||||
AppLocalizations l10n, {
|
||||
required HomePrimaryTab tab,
|
||||
required CatalogController catalog,
|
||||
required List<HomeGridCategoryShortcut> shortcuts,
|
||||
}) {
|
||||
if (catalog.error != null && widget.feedController.dramas.isEmpty) {
|
||||
return _catalogErrorState(l10n, catalog);
|
||||
}
|
||||
if ((!catalog.settled || catalog.loading) &&
|
||||
widget.feedController.dramas.isEmpty) {
|
||||
return const DramaGridSkeleton(
|
||||
key: Key('home-grid-skeleton'),
|
||||
columns: 3,
|
||||
horizontalPadding: AppDimens.feedPageHorizontal,
|
||||
crossAxisSpacing: AppDimens.homeGridGap,
|
||||
mainAxisSpacing: AppDimens.homeGridRowGap,
|
||||
);
|
||||
}
|
||||
if (tab == HomePrimaryTab.ranking) {
|
||||
return const RankingPage(embedded: true);
|
||||
}
|
||||
if (widget.feedController.loadingFirstPage) {
|
||||
return const Center(
|
||||
child: SizedBox.square(
|
||||
dimension: 24,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
),
|
||||
);
|
||||
}
|
||||
final tag = _selectedTags[tab];
|
||||
final dramas = _dramasFor(tab, tag, shortcuts);
|
||||
if (widget.feedController.loadingFirstPage && dramas.isEmpty) {
|
||||
return const DramaGridSkeleton(
|
||||
key: Key('home-grid-skeleton'),
|
||||
columns: 3,
|
||||
horizontalPadding: AppDimens.feedPageHorizontal,
|
||||
crossAxisSpacing: AppDimens.homeGridGap,
|
||||
mainAxisSpacing: AppDimens.homeGridRowGap,
|
||||
);
|
||||
}
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final itemWidth =
|
||||
@@ -237,6 +256,24 @@ class _HomeFeedGridState extends State<HomeFeedGrid> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _catalogErrorState(AppLocalizations l10n, CatalogController catalog) {
|
||||
final theme = Theme.of(context);
|
||||
return Theme(
|
||||
data: theme.copyWith(
|
||||
colorScheme: theme.colorScheme.copyWith(
|
||||
onSurface: AppColors.textTertiary,
|
||||
),
|
||||
),
|
||||
child: EmptyState(
|
||||
key: const Key('home-grid-error'),
|
||||
icon: Icons.cloud_off_rounded,
|
||||
title: l10n.catalogError,
|
||||
actionLabel: l10n.retry,
|
||||
onAction: catalog.load,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _refresh() async {
|
||||
await widget.feedController.refreshCurrent();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user