flutter_cache_vault 1.0.0 copy "flutter_cache_vault: ^1.0.0" to clipboard
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)),
            ],
          ),
        ),
      ),
    );
  }
}
1
likes
130
points
28
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

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, Priority), TTL, encryption, tagging, diagnostics, and ready-made Telegram-style cache management UI widgets.

Topics

#cache #storage #cache-manager #flutter-cache

License

MIT (license)

Dependencies

encrypt, flutter, path, path_provider, rxdart, shared_preferences, sqflite

More

Packages that depend on flutter_cache_vault