fix lints

This commit is contained in:
Fabian Freund
2026-05-22 19:16:03 +02:00
parent a5974617aa
commit ee99d28379
72 changed files with 244 additions and 274 deletions
@@ -17,16 +17,15 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
library;
/// Curated picker options for the web-search language and country selectors.
///
/// Codes intersect what Brave (`search_lang`/`country`) and Mojeek
/// (`lb`/`rb`) accept; English display names so the menu doesn't need a
/// per-locale translation pass. The protocol carries just the primary
/// ISO 639-1 / ISO 3166-1 alpha-2 codes — region qualifiers (`en-gb`,
/// `pt-br`, etc.) are reconstructed server-side from the language+country
/// pair.
// Curated picker options for the web-search language and country selectors.
//
// Codes intersect what Brave (`search_lang`/`country`) and Mojeek
// (`lb`/`rb`) accept; English display names so the menu doesn't need a
// per-locale translation pass. The protocol carries just the primary
// ISO 639-1 / ISO 3166-1 alpha-2 codes — region qualifiers (`en-gb`,
// `pt-br`, etc.) are reconstructed server-side from the language+country
// pair.
class LanguageOption {
final String code; // ISO 639-1
@@ -3,7 +3,6 @@ import 'dart:async';
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'
as fmc;
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:search_protocol/search_protocol.dart';
import 'package:search_client/search_client.dart';
import 'package:weblibre/core/routing/routes.dart';
import 'package:weblibre/features/geckoview/domain/entities/states/tab.dart';
@@ -18,9 +17,9 @@ import 'package:weblibre/features/geckoview/features/tabs/data/entities/tab_mode
import 'package:weblibre/features/geckoview/features/tabs/data/providers.dart';
import 'package:weblibre/features/search_credits/domain/controllers/search_token_issuance_controller.dart';
import 'package:weblibre/features/search_credits/domain/providers.dart';
import 'package:weblibre/features/search_credits/domain/providers/proxy_client.dart';
import 'package:weblibre/features/search_credits/domain/repositories/search_token_stash_repository.dart';
import 'package:weblibre/features/user/domain/repositories/cache.dart';
import 'package:weblibre/features/search_credits/domain/providers/proxy_client.dart';
import 'package:weblibre/features/web_search/domain/services/capture_artifact_downloader.dart';
import 'package:weblibre/features/web_search/domain/services/capture_server.dart';
import 'package:weblibre/features/web_search/domain/services/sandbox_capture_store.dart';
@@ -114,7 +113,7 @@ SandboxCaptureStore sandboxCaptureStore(Ref ref) => SandboxCaptureStore();
@Riverpod(keepAlive: true)
Stream<SandboxCaptureError> sandboxCaptureErrors(Ref ref) {
final ctrl = ref.watch(sandboxCaptureControllerProvider.notifier);
return ctrl.errors;
return ctrl.errorStream();
}
/// Orchestrates sandbox capture browsing:
@@ -148,10 +147,7 @@ class SandboxCaptureController extends _$SandboxCaptureController {
static const _defaultMethod = 'singlefile';
static const _defaultVariant = 'balanced';
StreamSubscription<List<CaptureTabData>>? _captureTabSub;
StreamSubscription<RetryRequest>? _retrySub;
Stream<SandboxCaptureError> get errors => _errors.stream;
Stream<SandboxCaptureError> errorStream() => _errors.stream;
@override
void build() {
@@ -159,9 +155,9 @@ class SandboxCaptureController extends _$SandboxCaptureController {
fmc.SandboxCaptureHostEvents.setUp(_hostEvents);
final dao = ref.read(tabDatabaseProvider).captureTabDao;
_captureTabSub = dao.watchAll().listen(_onCaptureTabChange);
final captureTabSub = dao.watchAll().listen(_onCaptureTabChange);
_retrySub = ref
final retrySub = ref
.read(captureServerProvider)
.retryRequests
.listen(_onRetryRequest);
@@ -173,10 +169,8 @@ class SandboxCaptureController extends _$SandboxCaptureController {
// stream — otherwise an in-flight Pigeon event or DAO emit could
// race with handler cleanup, or _markFailed could try to add to a
// closed _errors sink.
final captureTabSub = _captureTabSub;
final retrySub = _retrySub;
if (captureTabSub != null) unawaited(captureTabSub.cancel());
if (retrySub != null) unawaited(retrySub.cancel());
unawaited(captureTabSub.cancel());
unawaited(retrySub.cancel());
fmc.SandboxCaptureHostEvents.setUp(null);
_hostEvents.controller = null;
unawaited(_errors.close());
@@ -4,7 +4,6 @@ import 'dart:typed_data';
import 'package:riverpod/riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:search_protocol/search_protocol.dart';
import 'package:search_client/search_client.dart';
import 'package:weblibre/domain/services/generic_website.dart';
import 'package:weblibre/features/search_credits/domain/controllers/search_token_issuance_controller.dart';
@@ -1226,7 +1225,10 @@ class WebSearchScrollOffset extends _$WebSearchScrollOffset {
@override
double build() => 0;
void update(double offset) => state = offset;
void update(double offset) {
if (state == offset) return;
state = offset;
}
void reset() => state = 0;
}
@@ -5,7 +5,6 @@ import 'dart:ui';
import 'package:http/http.dart' as http;
import 'package:path/path.dart' as p;
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:search_protocol/search_protocol.dart';
import 'package:search_client/search_client.dart';
import 'package:weblibre/core/filesystem.dart';
import 'package:weblibre/features/search_credits/domain/providers.dart';
@@ -361,14 +361,14 @@ class CaptureServer {
final tabIdJson = jsonEncode(tabId);
final captureIdJson = jsonEncode(captureId);
final html =
'<!doctype html><html><head><meta charset="utf-8">'
'<meta name="viewport" content="width=device-width,initial-scale=1">'
'<title>Capturing…</title><style>$_loaderStyles</style>'
'</head><body>$body'
'<script>window.__TAB_ID__=$tabIdJson;'
'window.__CAPTURE_ID__=$captureIdJson;</script>'
'<script>$_loaderScript</script>'
'</body></html>';
'''
<!doctype html><html><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Capturing…</title><style>$_loaderStyles</style>
</head><body>$body
<script>window.__TAB_ID__=$tabIdJson;window.__CAPTURE_ID__=$captureIdJson;</script>
<script>$_loaderScript</script>
</body></html>''';
request.response.write(html);
await request.response.close();
}
@@ -510,35 +510,24 @@ class CaptureServer {
"base-uri 'none'; "
"form-action 'self'";
static const _loaderStyles =
'html,body{height:100%}'
'body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,'
'sans-serif;display:flex;align-items:center;justify-content:center;'
'min-height:100vh;margin:0;background:#0b0d10;color:#e6e8eb}'
'main{text-align:center;max-width:480px;padding:32px;opacity:0;'
'animation:fade .35s ease-out forwards}'
'@keyframes fade{to{opacity:1}}'
'.spinner{width:56px;height:56px;margin:0 auto 20px;border-radius:50%;'
'border:3px solid rgba(255,255,255,.08);border-top-color:#7aa2f7;'
'animation:spin 1s linear infinite}'
'@keyframes spin{to{transform:rotate(360deg)}}'
'h1{font-size:18px;font-weight:600;margin:0 0 8px;letter-spacing:.2px}'
'p{margin:0;color:#9aa1a8;font-size:14px;line-height:1.5}'
'.dots::after{display:inline-block;width:1.2em;text-align:left;'
'animation:dots 1.4s steps(4,end) infinite;content:""}'
'@keyframes dots{0%{content:""}25%{content:"."}50%{content:".."}'
'75%{content:"..."}100%{content:""}}'
'.error h1{color:#f7768e}'
'.actions{margin-top:20px;display:flex;gap:8px;justify-content:center}'
'.btn{padding:10px 16px;border:0;border-radius:10px;cursor:pointer;'
'font:inherit;font-weight:600;background:#7aa2f7;color:#0b0d10}'
'.btn.secondary{background:transparent;color:#9aa1a8;'
'border:1px solid rgba(255,255,255,.12)}'
'.hidden{display:none}'
'@media(prefers-color-scheme:light){body{background:#f5f6f8;'
'color:#1a1d22}.spinner{border-color:rgba(0,0,0,.08);'
'border-top-color:#3b82f6}.btn{background:#3b82f6;color:white}'
'p{color:#52606b}}';
static const _loaderStyles = '''
html,body{height:100%}
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;background:#0b0d10;color:#e6e8eb}
main{text-align:center;max-width:480px;padding:32px;opacity:0;animation:fade .35s ease-out forwards}
@keyframes fade{to{opacity:1}}
.spinner{width:56px;height:56px;margin:0 auto 20px;border-radius:50%;border:3px solid rgba(255,255,255,.08);border-top-color:#7aa2f7;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
h1{font-size:18px;font-weight:600;margin:0 0 8px;letter-spacing:.2px}
p{margin:0;color:#9aa1a8;font-size:14px;line-height:1.5}
.dots::after{display:inline-block;width:1.2em;text-align:left;animation:dots 1.4s steps(4,end) infinite;content:""}
@keyframes dots{0%{content:""}25%{content:"."}50%{content:".."}75%{content:"..."}100%{content:""}}
.error h1{color:#f7768e}
.actions{margin-top:20px;display:flex;gap:8px;justify-content:center}
.btn{padding:10px 16px;border:0;border-radius:10px;cursor:pointer;font:inherit;font-weight:600;background:#7aa2f7;color:#0b0d10}
.btn.secondary{background:transparent;color:#9aa1a8;border:1px solid rgba(255,255,255,.12)}
.hidden{display:none}
@media(prefers-color-scheme:light){body{background:#f5f6f8;color:#1a1d22}.spinner{border-color:rgba(0,0,0,.08);border-top-color:#3b82f6}.btn{background:#3b82f6;color:white}p{color:#52606b}}
''';
// Inline script for the loader shell. Reads window.__TAB_ID__ and
// window.__CAPTURE_ID__, long-polls /loader/wait, then either redirects
@@ -548,7 +537,7 @@ class CaptureServer {
// service has gone away doesn't busy-loop forever — after the cap the
// loader gives up and shows the error pane with a Retry button (which
// resets the counter via showPending → poll()).
static const _loaderScript = r'''
static const _loaderScript = '''
(function(){
var pending=document.getElementById('pending');
var error=document.getElementById('error');
@@ -606,18 +595,19 @@ class CaptureServer {
String _loaderShellBody({required bool initialError}) {
final pendingClass = initialError ? 'hidden' : '';
final errorClass = initialError ? 'error' : 'error hidden';
return '<main id="pending" class="$pendingClass">'
'<div class="spinner"></div>'
'<h1>Capturing page<span class="dots"></span></h1>'
'<p>Saving an offline copy. This usually takes a few seconds.</p>'
'</main>'
'<main id="error" class="$errorClass">'
'<h1>Capture failed</h1>'
'<p>The page could not be saved. Check the notification for details.</p>'
'<div class="actions">'
'<button id="retry" class="btn" type="button">Retry</button>'
'</div>'
'</main>';
return '''
<main id="pending" class="$pendingClass">
<div class="spinner"></div>
<h1>Capturing page<span class="dots"></span></h1>
<p>Saving an offline copy. This usually takes a few seconds.</p>
</main>
<main id="error" class="$errorClass">
<h1>Capture failed</h1>
<p>The page could not be saved. Check the notification for details.</p>
<div class="actions">
<button id="retry" class="btn" type="button">Retry</button>
</div>
</main>''';
}
}
@@ -1,6 +1,5 @@
import 'dart:typed_data';
import 'package:fast_equatable/fast_equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -211,7 +210,7 @@ class _ContentRow extends StatelessWidget {
/// instances on every state mutation). Equality is driven instead by scalar
/// signatures derived from those collections, which is enough to detect any
/// change a single result card cares about.
class _FooterState with FastEquatable {
class _FooterState {
final bool hasOpenSession;
final bool isFetching;
final bool isFetched;
@@ -260,14 +259,26 @@ class _FooterState with FastEquatable {
}
@override
List<Object?> get hashParameters => [
bool operator ==(Object other) {
return identical(this, other) ||
other is _FooterState &&
hasOpenSession == other.hasOpenSession &&
isFetching == other.isFetching &&
isFetched == other.isFetched &&
fetchError == other.fetchError &&
_capturingSignature == other._capturingSignature &&
_capturesSignature == other._capturesSignature;
}
@override
int get hashCode => Object.hash(
hasOpenSession,
isFetching,
isFetched,
fetchError,
_capturingSignature,
_capturesSignature,
];
);
}
class _FetchFooter extends ConsumerWidget {
@@ -151,10 +151,10 @@ bool _languageMatchesQuery(String resultLanguage, String? queryTag) {
final result = resultLanguage
.trim()
.toLowerCase()
.split(RegExp(r'[-_]'))
.split(RegExp('[-_]'))
.first;
final query = queryTag.trim().toLowerCase().split(RegExp(r'[-_]')).first;
final query = queryTag.trim().toLowerCase().split(RegExp('[-_]')).first;
if (result.isEmpty || query.isEmpty) return false;