fix(ui): enable task detail text selection and compact extension stats (#1511)

This commit is contained in:
Levi authored and GitHub committed 2026-09-13 23:30:45 +08:00
1 parent a29f4bb42a
commit a760290213
6 files changed
+236 -71

No files matched your search

@@ -11,6 +11,7 @@ import 'package:url_launcher/url_launcher.dart';
import '../../../../api/model/extension.dart' as api_extension;
import '../../../../api/model/store_extension.dart';
import '../../../../core/utils/breakpoints.dart';
import '../../../../core/utils/compact_count_formatter.dart';
import '../../../../core/window/app_window_chrome.dart';
import '../../../../shared/theme/app_design_tokens.dart';
import '../../../../shared/theme/app_palette.dart';
@@ -26,7 +27,7 @@ import '../widgets/extension_detail_view.dart';
import '../widgets/extension_icon.dart';
import '../widgets/extension_setting_field.dart';
const _extensionCardMinWidth = 280.0;
const _extensionCardMinWidth = 290.0;
const _extensionGridSpacing = 10.0;
int _extensionGridColumnCount(double width) {
@@ -995,71 +996,100 @@ class _ExtensionCard extends ConsumerWidget {
const Spacer(),
Row(
children: [
if (item.store != null) ...[
Icon(Icons.star_rounded, size: 15, color: palette.textMuted),
const SizedBox(width: 3),
Text('${item.stars}', style: TextStyle(color: palette.textSecondary, fontSize: 12)),
const SizedBox(width: 10),
Icon(Icons.download_outlined, size: 15, color: palette.textMuted),
const SizedBox(width: 3),
Text('${item.installCount}', style: TextStyle(color: palette.textSecondary, fontSize: 12)),
],
const Spacer(),
if (canUpdate && installed != null)
shad.GhostButton(
density: shad.ButtonDensity.icon,
onPressed: busy
? null
: () =>
onAction(() => ref.read(extensionsControllerProvider.notifier).upgradeExtension(installed)),
child: const Icon(Icons.refresh),
),
if (installed == null && item.store != null)
shad.GhostButton(
key: ValueKey('install-store-extension-${item.store!.id}'),
density: shad.ButtonDensity.icon,
onPressed: busy
? null
: () => onAction(
() => ref.read(extensionsControllerProvider.notifier).installFromStore(item.store!),
),
child: busy
? const SizedBox.square(dimension: 14, child: shad.CircularProgressIndicator())
: const Icon(Icons.download),
),
if ((item.homepage ?? '').isNotEmpty)
shad.GhostButton(
density: shad.ButtonDensity.icon,
onPressed: () => unawaited(launchUrl(Uri.parse(item.homepage!))),
child: const Icon(Icons.home_outlined),
),
if ((item.repoUrl ?? '').isNotEmpty)
shad.GhostButton(
density: shad.ButtonDensity.icon,
onPressed: () => unawaited(launchUrl(Uri.parse(item.repoUrl!))),
child: const Icon(Icons.code),
),
if (installed?.settings?.isNotEmpty == true)
shad.GhostButton(
density: shad.ButtonDensity.icon,
onPressed: busy ? null : () => onOpenSettings(installed!),
child: const Icon(Icons.settings_outlined),
),
if (installed != null)
shad.GhostButton(
key: ValueKey('remove-extension-${installed.identity}'),
density: shad.ButtonDensity.icon,
onPressed: busy
? null
: () async {
final confirmed = await _showRemoveExtensionDialog(context, installed.title);
if (!confirmed || !context.mounted) return;
await onAction(
() => ref.read(extensionsControllerProvider.notifier).removeExtension(installed),
);
},
child: const Icon(Icons.delete_outline),
),
if (item.store != null)
Expanded(
child: Align(
alignment: Alignment.centerLeft,
child: FittedBox(
fit: BoxFit.scaleDown,
alignment: Alignment.centerLeft,
child: Row(
key: ValueKey('extension-card-stats-${item.id}'),
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star_rounded, size: 15, color: palette.textMuted),
const SizedBox(width: 3),
Text(
CompactCountFormatter.format(item.stars),
style: TextStyle(color: palette.textSecondary, fontSize: 12),
),
const SizedBox(width: 10),
Icon(Icons.download_outlined, size: 15, color: palette.textMuted),
const SizedBox(width: 3),
Text(
CompactCountFormatter.format(item.installCount),
style: TextStyle(color: palette.textSecondary, fontSize: 12),
),
],
),
),
),
)
else
const Spacer(),
const SizedBox(width: 8),
Row(
key: ValueKey('extension-card-actions-${item.id}'),
mainAxisSize: MainAxisSize.min,
children: [
if (canUpdate && installed != null)
shad.GhostButton(
density: shad.ButtonDensity.icon,
onPressed: busy
? null
: () => onAction(
() => ref.read(extensionsControllerProvider.notifier).upgradeExtension(installed),
),
child: const Icon(Icons.refresh),
),
if (installed == null && item.store != null)
shad.GhostButton(
key: ValueKey('install-store-extension-${item.store!.id}'),
density: shad.ButtonDensity.icon,
onPressed: busy
? null
: () => onAction(
() => ref.read(extensionsControllerProvider.notifier).installFromStore(item.store!),
),
child: busy
? const SizedBox.square(dimension: 14, child: shad.CircularProgressIndicator())
: const Icon(Icons.download),
),
if ((item.homepage ?? '').isNotEmpty)
shad.GhostButton(
density: shad.ButtonDensity.icon,
onPressed: () => unawaited(launchUrl(Uri.parse(item.homepage!))),
child: const Icon(Icons.home_outlined),
),
if ((item.repoUrl ?? '').isNotEmpty)
shad.GhostButton(
density: shad.ButtonDensity.icon,
onPressed: () => unawaited(launchUrl(Uri.parse(item.repoUrl!))),
child: const Icon(Icons.code),
),
if (installed?.settings?.isNotEmpty == true)
shad.GhostButton(
density: shad.ButtonDensity.icon,
onPressed: busy ? null : () => onOpenSettings(installed!),
child: const Icon(Icons.settings_outlined),
),
if (installed != null)
shad.GhostButton(
key: ValueKey('remove-extension-${installed.identity}'),
density: shad.ButtonDensity.icon,
onPressed: busy
? null
: () async {
final confirmed = await _showRemoveExtensionDialog(context, installed.title);
if (!confirmed || !context.mounted) return;
await onAction(
() => ref.read(extensionsControllerProvider.notifier).removeExtension(installed),
);
},
child: const Icon(Icons.delete_outline),
),
],
),
],
),
],
@@ -10,6 +10,7 @@ import 'package:shadcn_flutter/shadcn_flutter.dart' as shad;
import 'package:url_launcher/url_launcher.dart';
import '../../../../api/model/store_extension.dart';
import '../../../../core/utils/compact_count_formatter.dart';
import '../../../../l10n/l10n.dart';
import '../../../../shared/theme/app_design_tokens.dart';
import '../../../../shared/theme/app_palette.dart';
@@ -338,9 +339,9 @@ class _ExtensionStats extends StatelessWidget {
key: const ValueKey('extension-details-stats'),
mainAxisSize: MainAxisSize.min,
children: [
_MetadataItem(icon: Icons.star_rounded, value: store.stars.toString()),
_MetadataItem(icon: Icons.star_rounded, value: CompactCountFormatter.format(store.stars)),
const SizedBox(width: 12),
_MetadataItem(icon: Icons.download_outlined, value: store.installCount.toString()),
_MetadataItem(icon: Icons.download_outlined, value: CompactCountFormatter.format(store.installCount)),
],
);
}