import 'dart:convert'; import 'package:filesize/filesize.dart'; import 'package:flutter/material.dart'; import '../../api/cache_store.dart'; import '../../extensions/date_time.dart'; import '../../routing/app_routes.dart'; import '../app_progress_indicator.dart'; import '../confirm_dialog.dart'; import '../placeholder_view.dart'; /// Lists the [CacheStore] entries (one file per request key), newest first. class CacheView extends StatefulWidget { const CacheView({super.key}); @override State createState() => _CacheViewState(); } class _CacheViewState extends State { late Future>> _entries = _read(); Future>> _read() async => (await CacheStore.instance.readAll()).entries.toList() ..sort((a, b) => b.value.lastUpdate.compareTo(a.value.lastUpdate)); void _reload() => setState(() { _entries = _read(); }); void _confirmDelete(String key) { ConfirmDialog( title: 'Eintrag löschen', content: '„$key“ wird gelöscht und bei Bedarf neu geladen.', confirmButton: 'Löschen', errorBuilder: (e) => '$e', onConfirmAsync: () async { await CacheStore.instance.delete(key); if (mounted) _reload(); }, ).asDialog(context); } void _confirmClear() { ConfirmDialog( title: 'Request-Cache leeren', content: 'Alle Einträge werden gelöscht. Der Cache baut sich bei Nutzung der ' 'App automatisch wieder auf.', confirmButton: 'Alles löschen', errorBuilder: (e) => '$e', onConfirmAsync: () async { await CacheStore.instance.clear(); if (mounted) _reload(); }, ).asDialog(context); } @override Widget build(BuildContext context) => Scaffold( appBar: AppBar( title: const Text('Request-Cache'), actions: [ IconButton( tooltip: 'Neu laden', icon: const Icon(Icons.refresh), onPressed: _reload, ), IconButton( tooltip: 'Alles löschen', icon: const Icon(Icons.delete_sweep_outlined), onPressed: _confirmClear, ), ], ), body: FutureBuilder( future: _entries, builder: (context, snapshot) { if (snapshot.connectionState != ConnectionState.done) { return const Center(child: AppProgressIndicator.large()); } final entries = snapshot.data ?? const []; if (entries.isEmpty) { return const PlaceholderView( icon: Icons.hourglass_empty, text: 'Keine Daten', ); } return ListView.builder( itemCount: entries.length, itemBuilder: (context, index) { final MapEntry(:key, :value) = entries[index]; return ListTile( leading: const Icon(Icons.text_snippet_outlined), title: Text(key), subtitle: Text( '${filesize(utf8.encode(value.json).length)} · ' '${DateTime.fromMillisecondsSinceEpoch(value.lastUpdate).formatRelative()}', ), onTap: () => AppRoutes.openJsonViewer( context, jsonDecode(value.json), title: key, ), trailing: IconButton( tooltip: 'Löschen', icon: const Icon(Icons.delete_outline), onPressed: () => _confirmDelete(key), ), ); }, ); }, ), ); }