fix search ui issues

This commit is contained in:
Fabian Freund
2026-06-02 15:08:33 +02:00
parent 70ab6ddf9e
commit bafd77af5a
2 changed files with 28 additions and 23 deletions
@@ -147,7 +147,7 @@ class _Header extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
// A single record select rebuilds this header only when the session state
// or the number of ready artifacts for *this* result changes.
// or the artifacts for *this* result change.
final fetch = ref.watch(
metaSearchControllerProvider.select((s) {
var ready = 0;
@@ -155,14 +155,27 @@ class _Header extends ConsumerWidget {
if (s.isMethodReady(result.url, choice)) ready++;
}
final busy = s.isFetching(result.url) || s.isAnyCapturing(result.url);
return (open: s.hasOpenSession, ready: ready, busy: busy);
// Any capture/preview artifact produced for this URL, in any state
// (ready, downloading, or failed) — distinct from `ready`, which only
// counts the openable ones.
final hasArtifacts =
s.capturesFor(result.url).isNotEmpty || s.isFetched(result.url);
return (
open: s.hasOpenSession,
ready: ready,
busy: busy,
hasArtifacts: hasArtifacts,
);
}),
);
// Once the WebSocket session has closed no further fetch/capture commands
// can be issued — keep the button only while the session is open or there
// are already-fetched artifacts to (re)open via the sheet.
final showFetch = fetch.open || fetch.ready > 0;
// Keep the button reachable while the session is open (new captures
// possible), while anything is in flight, or whenever artifacts exist for
// this result. After the socket closes the sheet itself greys out every
// capture-endpoint action (see _MethodTile.enabled) — a ready artifact
// still opens locally, a failed one stays visible with its error. This
// only governs whether that sheet is reachable, not what it permits.
final showFetch = fetch.open || fetch.busy || fetch.hasArtifacts;
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -168,26 +168,18 @@ class WebSearchInfoboxCard extends HookConsumerWidget {
}
/// Attributes worth rendering in the factsheet: those with a non-empty value,
/// minus low-signal entries. In particular a lone "type"/"kind" attribute
/// whose value just restates the infobox category (e.g. `Type: Code`) adds
/// nothing the header doesn't already convey, so we drop the whole factsheet
/// in that case rather than show a one-line, oddly-centered tile.
/// minus low-signal entries. We always drop a "type"/"kind" attribute: it is
/// Brave's weakest classifier (emitted only as a fallback when no `category`
/// is available) and as a single taxonomy word (e.g. `Type: Code`) it tells
/// the user nothing the heading/image/links don't already convey.
static List<InfoboxAttribute> _meaningfulAttributes(CompactInfobox info) {
final attributes = (info.attributes ?? const <InfoboxAttribute>[])
return (info.attributes ?? const <InfoboxAttribute>[])
.where((attr) => attr.value?.trim().isNotEmpty ?? false)
.where((attr) {
final label = attr.label.replaceAll(RegExp(r':+\s*$'), '').toLowerCase();
return label != 'type' && label != 'kind';
})
.toList();
if (attributes.length == 1) {
final only = attributes.single;
final label = only.label.replaceAll(RegExp(r':+\s*$'), '').toLowerCase();
final value = only.value!.trim().toLowerCase();
if ((label == 'type' || label == 'kind') &&
value == info.infobox.trim().toLowerCase()) {
return const [];
}
}
return attributes;
}
/// Link chips to show. These are the card's primary actionable content — the