flutter_cache_vault 1.0.0
flutter_cache_vault: ^1.0.0 copied to clipboard
A developer-friendly, user-transparent cache manager for Flutter apps. Features named buckets, multiple backends (memory, file, SQLite, SharedPrefs, hybrid), eviction strategies (LRU, LFU, FIFO, Prior [...]
example/lib/main.dart
import 'dart:typed_data';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_cache_vault/flutter_cache_vault.dart';
import 'package:flutter_cache_vault/ui.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize CacheVault
await CacheVault.init(
CacheConfig(
globalMaxSize: 500 * 1024 * 1024, // 500 MB
defaultTTL: Duration(days: 7),
defaultBackend: BackendType.memory,
enableDiagnostics: true,
autoFlushOnPause: true,
),
);
// Create buckets
CacheVault.bucket(
'images',
BucketOptions(
maxSize: 100 * 1024 * 1024,
ttl: Duration(days: 30),
evictionStrategy: EvictionStrategy.lru,
backend: BackendType.memory,
group: 'media',
displayName: 'Images',
iconCodePoint: Icons.image_outlined.codePoint,
iconFontFamily: 'MaterialIcons',
),
);
CacheVault.bucket(
'api_responses',
BucketOptions(
maxSize: 50 * 1024 * 1024,
ttl: Duration(hours: 1),
evictionStrategy: EvictionStrategy.lfu,
backend: BackendType.memory,
group: 'network',
displayName: 'API Responses',
iconCodePoint: Icons.cloud_outlined.codePoint,
iconFontFamily: 'MaterialIcons',
),
);
CacheVault.bucket(
'user_data',
BucketOptions(
maxSize: 20 * 1024 * 1024,
ttl: Duration(days: 14),
evictionStrategy: EvictionStrategy.fifo,
backend: BackendType.memory,
displayName: 'User Data',
iconCodePoint: Icons.person_outlined.codePoint,
iconFontFamily: 'MaterialIcons',
),
);
runApp(const CacheVaultExampleApp());
}
class CacheVaultExampleApp extends StatelessWidget {
const CacheVaultExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Cache Vault Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF6C5CE7),
brightness: Brightness.dark,
),
scaffoldBackgroundColor: const Color(0xFF0F0F1A),
cardColor: const Color(0xFF1A1A2E),
useMaterial3: true,
),
home: CacheDebugOverlay(enabled: true, child: const ExampleHomePage()),
);
}
}
class ExampleHomePage extends StatefulWidget {
const ExampleHomePage({super.key});
@override
State<ExampleHomePage> createState() => _ExampleHomePageState();
}
class _ExampleHomePageState extends State<ExampleHomePage> {
final _random = Random();
String _statusMessage = 'Ready';
CacheReport? _report;
@override
void initState() {
super.initState();
_refreshReport();
}
Future<void> _refreshReport() async {
final report = await CacheVault.report();
if (mounted) setState(() => _report = report);
}
Future<void> _populateSampleData() async {
final images = CacheVault.getBucket('images')!;
final api = CacheVault.getBucket('api_responses')!;
final user = CacheVault.getBucket('user_data')!;
setState(() => _statusMessage = 'Writing sample data...');
// Simulate cached images (random bytes)
for (int i = 0; i < 15; i++) {
final size = 1024 * (50 + _random.nextInt(200)); // 50KB to 250KB
final bytes = Uint8List(size);
for (int j = 0; j < bytes.length; j++) {
bytes[j] = _random.nextInt(256);
}
await images.set(
'photo_${i + 1}.jpg',
bytes,
ttl: Duration(days: 7 + _random.nextInt(30)),
tags: ['gallery', if (i < 5) 'favorites'],
);
}
// Simulate API responses
for (int i = 0; i < 20; i++) {
final payload =
'{"id": $i, "title": "Item $i", '
'"data": "${List.generate(100, (_) => _random.nextInt(10)).join()}"}';
await api.set(
'endpoint_${i + 1}',
payload,
ttl: Duration(minutes: 30 + _random.nextInt(120)),
tags: ['api', 'endpoint_group_${i % 3}'],
);
}
// Simulate user data
final userEntries = {
'profile':
'{"name": "Alice", "email": "alice@example.com", "avatar_url": "https://example.com/avatar.jpg"}',
'preferences':
'{"theme": "dark", "language": "en", "notifications": true}',
'session_token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.demo.token',
'recently_viewed': '[1, 5, 12, 8, 3, 20, 15]',
'search_history':
'["flutter cache", "telegram storage", "dart packages"]',
};
for (final entry in userEntries.entries) {
await user.set(entry.key, entry.value, tags: ['user:alice']);
}
// Perform some reads to generate hit/miss stats
for (int i = 0; i < 10; i++) {
await images.get<Uint8List>('photo_${_random.nextInt(15) + 1}.jpg');
await api.get<String>('endpoint_${_random.nextInt(20) + 1}');
await user.get<String>('profile');
}
// Some misses
await images.get<Uint8List>('nonexistent_photo.jpg');
await api.get<String>('missing_endpoint');
await _refreshReport();
setState(() => _statusMessage = 'Sample data populated successfully!');
}
Future<void> _testCacheOrFetch() async {
final api = CacheVault.getBucket('api_responses')!;
setState(() => _statusMessage = 'Testing cacheOrFetch...');
final result = await api.cacheOrFetch<String>(
'user_profile_live',
fetcher: () async {
// Simulate API call
await Future.delayed(const Duration(seconds: 1));
return '{"id": 1, "name": "Live User", "fetched_at": "${DateTime.now()}"}';
},
ttl: Duration(hours: 1),
tags: ['user', 'profile'],
);
await _refreshReport();
setState(
() =>
_statusMessage = 'cacheOrFetch result: ${result.substring(0, 50)}...',
);
}
Future<void> _invalidateUserTag() async {
setState(() => _statusMessage = 'Invalidating tag user:alice...');
await CacheVault.invalidateTag('user:alice');
await _refreshReport();
setState(
() => _statusMessage = 'Invalidated all items tagged "user:alice"',
);
}
Future<void> _clearMediaGroup() async {
setState(() => _statusMessage = 'Clearing media group...');
await CacheVault.clearGroup('media');
await _refreshReport();
setState(() => _statusMessage = 'Cleared all media buckets');
}
void _openCacheManager() {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => CacheManagerScreen(
title: 'Storage Usage',
footerNote: 'All media stays in the cloud and can be re-downloaded.',
theme: const CacheManagerTheme(
primaryColor: Color(0xFF6C5CE7),
backgroundColor: Color(0xFF0F0F1A),
cardColor: Color(0xFF1A1A2E),
textColor: Colors.white,
subtitleColor: Color(0xFF8E8E93),
dangerColor: Color(0xFFE17055),
successColor: Color(0xFF00B894),
),
onClearComplete: (freedBytes) {
_refreshReport();
},
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF0F0F1A),
appBar: AppBar(
title: const Text(
'Cache Vault Demo',
style: TextStyle(fontWeight: FontWeight.bold),
),
backgroundColor: Colors.transparent,
elevation: 0,
actions: [
IconButton(
icon: const Icon(Icons.storage_outlined),
tooltip: 'Open Cache Manager',
onPressed: _openCacheManager,
),
],
),
body: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// ─── Donut Chart ───
if (_report != null)
Center(
child: CacheUsageDonut(
size: 180,
strokeWidth: 20,
showCenterLabel: true,
report: _report,
theme: const CacheManagerTheme(
primaryColor: Color(0xFF6C5CE7),
cardColor: Color(0xFF1A1A2E),
textColor: Colors.white,
subtitleColor: Color(0xFF8E8E93),
),
),
),
const SizedBox(height: 24),
// ─── Status Message ───
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xFF1A1A2E),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: const Color(0xFF6C5CE7).withValues(alpha: 0.3),
),
),
child: Row(
children: [
const Icon(
Icons.info_outline,
color: Color(0xFF6C5CE7),
size: 20,
),
const SizedBox(width: 12),
Expanded(
child: Text(
_statusMessage,
style: const TextStyle(
color: Colors.white70,
fontSize: 13,
),
),
),
],
),
),
const SizedBox(height: 24),
// ─── Action Buttons ───
_buildActionButton(
icon: Icons.dataset_outlined,
label: 'Populate Sample Data',
description: 'Fill buckets with random test data',
color: const Color(0xFF6C5CE7),
onTap: _populateSampleData,
),
const SizedBox(height: 12),
_buildActionButton(
icon: Icons.sync_outlined,
label: 'Test cacheOrFetch',
description: 'Cache-or-fetch pattern demo',
color: const Color(0xFF0984E3),
onTap: _testCacheOrFetch,
),
const SizedBox(height: 12),
_buildActionButton(
icon: Icons.label_off_outlined,
label: 'Invalidate "user:alice" Tag',
description: 'Remove all items tagged user:alice',
color: const Color(0xFFFDAA5E),
onTap: _invalidateUserTag,
),
const SizedBox(height: 12),
_buildActionButton(
icon: Icons.perm_media_outlined,
label: 'Clear Media Group',
description: 'Clear all buckets in "media" group',
color: const Color(0xFFE17055),
onTap: _clearMediaGroup,
),
const SizedBox(height: 12),
_buildActionButton(
icon: Icons.settings_outlined,
label: 'Open Cache Manager',
description: 'Full Telegram-style storage screen',
color: const Color(0xFF00B894),
onTap: _openCacheManager,
),
const SizedBox(height: 12),
_buildActionButton(
icon: Icons.print_outlined,
label: 'Debug Print Report',
description: 'Print diagnostics to console',
color: const Color(0xFFA29BFE),
onTap: () async {
await CacheVault.debugPrint();
setState(() => _statusMessage = 'Report printed to console');
},
),
const SizedBox(height: 24),
// ─── Bucket Tiles ───
if (_report != null && _report!.perBucket.isNotEmpty) ...[
const Text(
'BUCKETS',
style: TextStyle(
color: Color(0xFF8E8E93),
fontSize: 12,
fontWeight: FontWeight.w600,
letterSpacing: 1.2,
),
),
const SizedBox(height: 12),
..._report!.perBucket.map((b) {
final colors = CacheManagerTheme.defaultChartColors;
final colorIndex =
_report!.perBucket.indexOf(b) % colors.length;
return Padding(
padding: const EdgeInsets.only(bottom: 8),
child: CacheBucketTile(
bucketName: b.name,
report: b,
dotColor: colors[colorIndex],
showClearButton: true,
onClear: _refreshReport,
theme: const CacheManagerTheme(
cardColor: Color(0xFF1A1A2E),
textColor: Colors.white,
subtitleColor: Color(0xFF8E8E93),
),
),
);
}),
],
const SizedBox(height: 40),
],
),
),
);
}
Widget _buildActionButton({
required IconData icon,
required String label,
required String description,
required Color color,
required VoidCallback onTap,
}) {
return Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(16),
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xFF1A1A2E),
borderRadius: BorderRadius.circular(16),
border: Border.all(color: color.withValues(alpha: 0.2)),
),
child: Row(
children: [
Container(
width: 44,
height: 44,
decoration: BoxDecoration(
color: color.withValues(alpha: 0.15),
borderRadius: BorderRadius.circular(12),
),
child: Icon(icon, color: color, size: 22),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 15,
),
),
Text(
description,
style: const TextStyle(
color: Color(0xFF8E8E93),
fontSize: 12,
),
),
],
),
),
Icon(Icons.chevron_right, color: color.withValues(alpha: 0.5)),
],
),
),
),
);
}
}