import 'dart:io'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:path_provider/path_provider.dart'; import 'package:veloe_kemono_party_flutter/app_layout.dart'; import 'package:veloe_kemono_party_flutter/main.dart'; class CacheSettingsScreen extends ConsumerStatefulWidget { const CacheSettingsScreen({super.key}); @override ConsumerState createState() => _CacheSettingsScreenState(); } class _CacheSettingsScreenState extends ConsumerState { final Map _cacheStats = { 'Images': CacheStats('Images', 0, 0), 'Videos': CacheStats('Videos', 0, 0), 'Icons': CacheStats('Icons', 0, 0), }; bool _isLoading = true; @override void initState() { super.initState(); _loadCacheStats(); } Future _loadCacheStats() async { setState(() => _isLoading = true); final stats = await Future.wait([ _getCacheStats(imageCacheManager, 'Images'), _getCacheStats(videoCacheManager, 'Videos'), _getCacheStats(iconsCacheManager, 'Icons'), ]); setState(() { for (var stat in stats) { _cacheStats[stat.name] = stat; } _isLoading = false; }); } Future _getCacheStats(CacheManager manager, String name) async { try { final directory = await getTemporaryDirectory(); final cacheDir = Directory('${directory.path}/${manager.config.cacheKey}'); if (!await cacheDir.exists()) return CacheStats(name, 0, 0); final files = await cacheDir.list().where((entity) => entity is File).toList(); int totalSize = 0; for (var file in files.cast()) { totalSize += await file.length(); } return CacheStats(name, files.length, totalSize); } catch (e) { debugPrint('Cache stats error: $e'); return CacheStats(name, 0, 0); } } Future _clearCache(BaseCacheManager manager) async { await manager.emptyCache(); _loadCacheStats(); } String _formatBytes(int bytes) { if (bytes <= 0) return "0 B"; const suffixes = ["B", "KB", "MB", "GB", "TB"]; final i = (log(bytes) / log(1024)).floor(); return '${(bytes / pow(1024, i)).toStringAsFixed(2)} ${suffixes[i]}'; } @override Widget build(BuildContext context) { final currentSource = ref.watch(sourceProvider); return Scaffold( appBar: AppBar( title: const Text('Content Settings'), leading: Builder( builder: (context) => IconButton( icon: const Icon(Icons.menu), onPressed: () => AppLayout.openDrawer(context), ), ), actions: [ IconButton( icon: const Icon(Icons.refresh), onPressed: _loadCacheStats, tooltip: 'Refresh Stats', ), ], ), body: _isLoading ? const Center(child: CircularProgressIndicator()) : Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Source selection Text('Content Source', style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 10), SegmentedButton( segments: const [ ButtonSegment( value: KemonoSource.kemono, label: Text('Kemono.su'), icon: Icon(Icons.image), ), ButtonSegment( value: KemonoSource.coomer, label: Text('Coomer.su'), icon: Icon(Icons.person), ), ], selected: {currentSource}, onSelectionChanged: (Set newSelection) { ref.read(sourceProvider.notifier).state = newSelection.first; ref.invalidate(kemonoClientProvider); // Invalidate client ref.invalidate(creatorsProvider); // Refresh creators list }, ), const SizedBox(height: 30), // Cache statistics header Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Cache Statistics', style: Theme.of(context).textTheme.titleMedium), TextButton( onPressed: () async { await imageCacheManager.emptyCache(); await videoCacheManager.emptyCache(); await iconsCacheManager.emptyCache(); _loadCacheStats(); }, child: const Text('Clear All'), ), ], ), const SizedBox(height: 10), // Cache stats cards Expanded( child: ListView( children: [ _buildCacheCard(_cacheStats['Images']!, imageCacheManager), _buildCacheCard(_cacheStats['Videos']!, videoCacheManager), _buildCacheCard(_cacheStats['Icons']!, iconsCacheManager), ], ), ), ], ), ), ); } Widget _buildCacheCard(CacheStats stats, BaseCacheManager manager) { return Card( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( stats.name, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), IconButton( icon: const Icon(Icons.delete, size: 20), onPressed: () => _clearCache(manager), tooltip: 'Clear ${stats.name} Cache', ), ], ), const SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text('Files:'), Text('${stats.fileCount}', style: const TextStyle(fontWeight: FontWeight.bold)), ], ), const SizedBox(height: 8), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text('Size:'), Text(_formatBytes(stats.totalSize), style: const TextStyle(fontWeight: FontWeight.bold)), ], ), const SizedBox(height: 10), LinearProgressIndicator( value: stats.totalSize / (1024 * 1024 * 100), // 100MB scale minHeight: 6, backgroundColor: Colors.grey[200], valueColor: AlwaysStoppedAnimation( stats.name == 'Images' ? Colors.blue : stats.name == 'Videos' ? Colors.red : Colors.green, ), ), ], ), ), ); } } class CacheStats { final String name; final int fileCount; final int totalSize; CacheStats(this.name, this.fileCount, this.totalSize); }