improve weblibre search
This commit is contained in:
+65
-25
@@ -4,6 +4,8 @@ import 'package:weblibre/features/web_search/domain/controllers/search_controlle
|
||||
import 'package:weblibre/features/web_search/domain/entities/captured_page_state.dart';
|
||||
import 'package:weblibre/features/web_search/domain/entities/fetch_method.dart';
|
||||
import 'package:weblibre/features/web_search/domain/services/capture_artifact_downloader.dart';
|
||||
import 'package:weblibre/presentation/widgets/uri_breadcrumb.dart';
|
||||
import 'package:weblibre/presentation/widgets/url_icon.dart';
|
||||
|
||||
Future<void> showFetchMethodSheet(
|
||||
BuildContext context, {
|
||||
@@ -55,13 +57,12 @@ class _FetchMethodSheet extends ConsumerWidget {
|
||||
children: [
|
||||
Text('Fetch Page Data', style: textTheme.titleLarge),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
url.toString(),
|
||||
UriBreadcrumb(
|
||||
uri: url,
|
||||
icon: UrlIcon([url], iconSize: 14, cacheOnly: true),
|
||||
style: textTheme.bodySmall?.copyWith(
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -99,35 +100,63 @@ class _MethodTile extends ConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final textTheme = Theme.of(context).textTheme;
|
||||
final theme = Theme.of(context);
|
||||
final colorScheme = theme.colorScheme;
|
||||
final textTheme = theme.textTheme;
|
||||
|
||||
final busy = state.isMethodBusy(url, choice);
|
||||
final ready = state.isMethodReady(url, choice);
|
||||
final captured = state.capturedPage(url, choice);
|
||||
final failed = captured?.status == CapturedPageStatus.downloadFailed;
|
||||
|
||||
// The trafilatura "preview" goes through fetchPage/fetchErrorByUrl rather
|
||||
// than the capture pipeline, so its failures live in a different place
|
||||
// than a capture's downloadFailed status. Surface either as the tile's
|
||||
// error here (the card no longer shows per-method error chips).
|
||||
final String? errorMessage;
|
||||
if (busy || ready) {
|
||||
errorMessage = null;
|
||||
} else if (choice == FetchMethodChoice.trafilatura) {
|
||||
errorMessage = state.fetchError(url);
|
||||
} else if (captured?.status == CapturedPageStatus.downloadFailed) {
|
||||
errorMessage = captured?.errorMessage ?? 'Download failed — tap to retry';
|
||||
} else {
|
||||
errorMessage = null;
|
||||
}
|
||||
final failed = errorMessage != null;
|
||||
|
||||
// Starting (or retrying) anything needs an open session; already-ready
|
||||
// artifacts can still be opened after the session closes.
|
||||
final enabled = !busy && (ready || state.hasOpenSession);
|
||||
|
||||
// A disabled ListTile only dims its title automatically; the leading icon
|
||||
// and subtitle carry explicit colors, so dim them too (matching the title's
|
||||
// disabled color) to keep the whole tile reading as deactivated.
|
||||
final leadingColor = enabled
|
||||
? colorScheme.onSurfaceVariant
|
||||
: theme.disabledColor;
|
||||
final subtitleColor = !enabled
|
||||
? theme.disabledColor
|
||||
: (failed ? colorScheme.error : colorScheme.onSurfaceVariant);
|
||||
|
||||
return ListTile(
|
||||
enabled: enabled,
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 24, vertical: 4),
|
||||
leading: Icon(choice.icon, color: colorScheme.onSurfaceVariant),
|
||||
leading: Icon(choice.icon, color: leadingColor),
|
||||
title: Text(choice.title),
|
||||
subtitle: Text(
|
||||
failed
|
||||
? (captured?.errorMessage ?? 'Download failed — tap to retry')
|
||||
: choice.subtitle,
|
||||
style: textTheme.bodySmall?.copyWith(
|
||||
color: failed ? colorScheme.error : colorScheme.onSurfaceVariant,
|
||||
),
|
||||
failed ? errorMessage : choice.subtitle,
|
||||
style: textTheme.bodySmall?.copyWith(color: subtitleColor),
|
||||
),
|
||||
trailing: _StatusIndicator(
|
||||
busy: busy,
|
||||
ready: ready,
|
||||
failed: failed,
|
||||
idleColor: leadingColor,
|
||||
colorScheme: colorScheme,
|
||||
),
|
||||
onTap: busy
|
||||
? null
|
||||
: () => _handleTap(context, ref, ready, failed, captured),
|
||||
onTap: enabled
|
||||
? () => _handleTap(context, ref, ready, failed, captured)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -148,17 +177,25 @@ class _MethodTile extends ConsumerWidget {
|
||||
return;
|
||||
}
|
||||
|
||||
Navigator.of(context).pop();
|
||||
// Keep the sheet open while a fetch/download runs so its per-method tile
|
||||
// shows the live spinner; the user opens the result from here once ready.
|
||||
|
||||
if (failed && captured != null) {
|
||||
await ref
|
||||
.read(metaSearchControllerProvider.notifier)
|
||||
.retryCaptureDownload(url, choice);
|
||||
// Trafilatura (re)fetch — the same call covers a first fetch and a retry
|
||||
// after a previous fetch error.
|
||||
if (choice == FetchMethodChoice.trafilatura) {
|
||||
await ref.read(metaSearchControllerProvider.notifier).fetchPage(url);
|
||||
return;
|
||||
}
|
||||
|
||||
if (choice == FetchMethodChoice.trafilatura) {
|
||||
await ref.read(metaSearchControllerProvider.notifier).fetchPage(url);
|
||||
// A failed *download* (we still hold the captureId/downloadToken) only
|
||||
// needs the artifact re-fetched — no new upstream render. A server-side
|
||||
// capture failure has no token, so it falls through to a fresh capture.
|
||||
if (failed &&
|
||||
captured?.captureId != null &&
|
||||
captured?.downloadToken != null) {
|
||||
await ref
|
||||
.read(metaSearchControllerProvider.notifier)
|
||||
.retryCaptureDownload(url, choice);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -178,12 +215,14 @@ class _StatusIndicator extends StatelessWidget {
|
||||
final bool busy;
|
||||
final bool ready;
|
||||
final bool failed;
|
||||
final Color idleColor;
|
||||
final ColorScheme colorScheme;
|
||||
|
||||
const _StatusIndicator({
|
||||
required this.busy,
|
||||
required this.ready,
|
||||
required this.failed,
|
||||
required this.idleColor,
|
||||
required this.colorScheme,
|
||||
});
|
||||
|
||||
@@ -202,6 +241,7 @@ class _StatusIndicator extends StatelessWidget {
|
||||
if (failed) {
|
||||
return Icon(Icons.refresh, color: colorScheme.error);
|
||||
}
|
||||
return Icon(Icons.download_rounded, color: colorScheme.onSurfaceVariant);
|
||||
// Idle: mirror the leading icon so a disabled tile dims uniformly.
|
||||
return Icon(Icons.download_rounded, color: idleColor);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user