CacheInterceptor кэширует каждый успешный GET по путь+параметры в drift (sqlite нативно, wasm+OPFS в браузере) и подменяет им сетевую ошибку; провайдер отдаёт Cached<T>, экран показывает баннер «данные на …». Контракт для остальных экранов — docs/ai/offline-cache.md. flake.nix: libsecret/pkg-config для линуксовой сборки, jq/curl для just app-web-assets (сборка sqlite3.wasm + drift_worker.js).
37 lines
1.3 KiB
Dart
37 lines
1.3 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import '../utils/ru_date.dart';
|
|
|
|
/// "Нет соединения — данные на …": shown instead of pretending a screen built
|
|
/// from the offline cache is current. Pass the oldest `fetchedAt` among the
|
|
/// providers a screen watches (`core/cache/cached.dart`'s `oldestFetch`).
|
|
class StaleBanner extends StatelessWidget {
|
|
const StaleBanner({required this.fetchedAt, super.key});
|
|
|
|
final DateTime fetchedAt;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final scheme = Theme.of(context).colorScheme;
|
|
final at = fetchedAt.toLocal();
|
|
final time = '${at.hour.toString().padLeft(2, '0')}:${at.minute.toString().padLeft(2, '0')}';
|
|
return Container(
|
|
margin: const EdgeInsets.only(bottom: 12),
|
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
|
decoration: BoxDecoration(color: scheme.errorContainer, borderRadius: BorderRadius.circular(8)),
|
|
child: Row(
|
|
children: [
|
|
Icon(Icons.cloud_off, size: 18, color: scheme.onErrorContainer),
|
|
const SizedBox(width: 8),
|
|
Expanded(
|
|
child: Text(
|
|
'Нет соединения — данные на ${ruDate(at)} $time',
|
|
style: TextStyle(color: scheme.onErrorContainer),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|