perf(extensions): load store summaries and check updates asynchronously (#1583)

This commit is contained in:
Levi authored and GitHub committed 2026-10-14 20:08:41 +08:00
1 parent b86c2c18e7
commit 12860bb207
41 files changed
+1567 -257

No files matched your search

@@ -17,7 +17,9 @@ import '../../../../shared/theme/app_design_tokens.dart';
import '../../../../shared/theme/app_palette.dart';
import '../../../../shared/widgets/app_swipe_tabs.dart';
import '../../../../shared/widgets/app_primary_button.dart';
import '../../../../shared/widgets/app_empty_state.dart';
import '../../../../shared/widgets/app_text_field.dart';
import '../../../../shared/widgets/app_search_field.dart';
import '../../../../shared/widgets/app_tooltip.dart';
import '../../../../shared/widgets/app_toast.dart';
import '../../../../l10n/l10n.dart';
@@ -124,10 +126,8 @@ class _ExtensionsPageState extends ConsumerState<ExtensionsPage> {
),
child: stateAsync.when(
loading: () => _buildContent(const ExtensionsState(loadingInstalled: true, loadingStore: true)),
error: (error, _) => _ErrorState(
error: error,
onRetry: () => ref.read(extensionsControllerProvider.notifier).loadInitialData(),
),
error: (error, _) =>
_ErrorState(onRetry: () => ref.read(extensionsControllerProvider.notifier).loadInitialData()),
data: (state) {
if (state.listFilter == ExtensionListFilter.market &&
state.storePagination?.hasNext == true &&
@@ -409,11 +409,17 @@ class _Content extends StatelessWidget {
)
else if (state.displayItems.isEmpty)
SliverFillRemaining(
child: Center(
child: Text(
context.l10n.noExtensions,
style: TextStyle(color: palette.textSecondary, fontSize: 14),
),
hasScrollBody: false,
child: AppEmptyState(
key: const ValueKey('extensions-empty-state'),
illustration:
state.listFilter == ExtensionListFilter.market && state.storeQuery.isNotEmpty
? AppEmptyIllustrationType.search
: AppEmptyIllustrationType.puzzle,
illustrationKey: const ValueKey('extensions-empty-illustration'),
message: state.listFilter == ExtensionListFilter.market && state.storeQuery.isNotEmpty
? context.l10n.extensionStoreEmpty
: context.l10n.noExtensions,
),
)
else
@@ -663,12 +669,11 @@ class _Toolbar extends StatelessWidget {
@override
Widget build(BuildContext context) {
final palette = AppPalette.of(context);
final search = AppTextField(
final search = AppSearchField(
key: const ValueKey('extension-search-input'),
controller: searchController,
padding: MediaQuery.sizeOf(context).width >= Breakpoints.mobile ? AppDesignTokens.compactTextFieldPadding : null,
placeholder: Text(context.l10n.searchExtensions, style: TextStyle(color: palette.searchHint)),
features: [shad.InputFeature.leading(Icon(Icons.search_rounded, size: 16, color: palette.textMuted))],
onSubmitted: onSearch,
);
final sorting = Row(
@@ -1255,36 +1260,23 @@ class _ExtensionSettingsPanel extends StatelessWidget {
}
class _ErrorState extends StatelessWidget {
const _ErrorState({required this.error, required this.onRetry});
const _ErrorState({required this.onRetry});
final Object error;
final VoidCallback onRetry;
@override
Widget build(BuildContext context) {
final palette = AppPalette.of(context);
return Center(
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.extension_off_outlined, size: 32, color: palette.error),
const SizedBox(height: 12),
Text(
context.l10n.unableLoadExtensions,
style: TextStyle(color: palette.textPrimary, fontWeight: FontWeight.w700),
),
const SizedBox(height: 8),
Text(
error.toString(),
textAlign: TextAlign.center,
style: TextStyle(color: palette.textSecondary),
),
const SizedBox(height: 16),
shad.SecondaryButton(onPressed: onRetry, child: Text(context.l10n.retry)),
],
),
return AppEmptyState(
key: const ValueKey('extensions-error-state'),
illustration: AppEmptyIllustrationType.connectionError,
illustrationKey: const ValueKey('extensions-error-illustration'),
message: context.l10n.unableLoadExtensions,
action: AppEmptyStateAction(
buttonKey: const ValueKey('extensions-error-retry'),
icon: Icons.refresh_rounded,
label: context.l10n.retry,
hint: context.l10n.emptyStateRetryHint,
onPressed: onRetry,
),
);
}