123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- 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<CacheSettingsScreen> createState() => _CacheSettingsScreenState();
- }
- class _CacheSettingsScreenState extends ConsumerState<CacheSettingsScreen> {
- final Map<String, CacheStats> _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<void> _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<CacheStats> _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<File>()) {
- totalSize += await file.length();
- }
-
- return CacheStats(name, files.length, totalSize);
- } catch (e) {
- debugPrint('Cache stats error: $e');
- return CacheStats(name, 0, 0);
- }
- }
- Future<void> _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<KemonoSource>(
- 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: <KemonoSource>{currentSource},
- onSelectionChanged: (Set<KemonoSource> 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<Color>(
- 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);
- }
|