slim_cached_network_image 0.0.7-dev.1 copy "slim_cached_network_image: ^0.0.7-dev.1" to clipboard
slim_cached_network_image: ^0.0.7-dev.1 copied to clipboard

Slim cached network image.

example/lib/main.dart

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:slim_cached_network_image/slim_cached_network_image.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();

  // Optional: Configure the image decode queue (default is 20)
  // This prevents Chrome crashes when loading many images simultaneously
  // See: https://issues.chromium.org/issues/40792189
  SlimImageDecodeConfig.setMaxConcurrentDecodes(25);

  // Optional: Set default configuration for the cache manager
  SlimCacheManager.setDefaultConfig(SlimCachedImageConfig(
    maxNrOfCacheObjects: 150, // Default max objects
    stalePeriod: const Duration(days: 10), // Default stale period
    maxMemWidth: 600, // Default max width for disk cache
    maxMemHeight: 600, // Default max height for disk cache
  ));
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'SlimCachedNetworkImage Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'SlimCachedNetworkImage Example'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(title),
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            const Text(
              'Using SlimCachedNetworkImage (Default Config):',
              style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 8),
            Center(
              child: SlimCachedNetworkImage(
                // Using a random image URL from picsum.photos
                imageUrl: "https://picsum.photos/seed/picsum1/300/200",
                placeholder: (context, url) => const SizedBox(
                  width: 50,
                  height: 50,
                  child: CircularProgressIndicator(),
                ),
                errorWidget: (context, url, error) => const Icon(Icons.error, color: Colors.red),
                width: 300,
                height: 200,
                fit: BoxFit.cover,
              ),
            ),
            const SizedBox(height: 24),
            const Text(
              'Using SlimCachedNetworkImage (Specific Config):',
              style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 8),
            Center(
              child: SlimCachedNetworkImage(
                imageUrl: "https://picsum.photos/seed/picsum2/1200/600",
                // Override global config for this specific image
                placeholder: (context, url) => const SizedBox(
                  width: 40,
                  height: 40,
                  child: CircularProgressIndicator(strokeWidth: 2),
                ),
                errorWidget: (context, url, error) => const Icon(Icons.broken_image, color: Colors.orange),
                width: 1200,
                height: 200,
                fit: BoxFit.cover,
              ),
            ),
            const SizedBox(height: 24),
            const Text(
              'Using SlimCachedNetworkImageProvider:',
              style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 8),
            Center(
              child: Container(
                width: 150,
                height: 150,
                decoration: BoxDecoration(
                  color: Colors.grey[300],
                  image: DecorationImage(
                    image: const SlimCachedNetworkImageProvider(
                      "https://picsum.photos/seed/picsum3/150/150",
                      // Optionally provide config here too
                      // cacheConfig: SlimCacheConfig(maxWidth: 150, maxHeight: 150),
                    ),
                    fit: BoxFit.cover,
                    // Optional: Add error builder for DecorationImage
                    onError: (exception, stackTrace) {
                      // Handle error if needed
                    },
                  ),
                  border: Border.all(color: Colors.blueAccent),
                  borderRadius: BorderRadius.circular(8),
                ),
                // You could add a child here to show loading/error state for the provider
                // but DecorationImage doesn't directly support placeholders like the widget.
              ),
            ),
            const SizedBox(height: 24),
            const Text(
              'Image Decode Queue Statistics:',
              style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 8),
            _QueueStatsWidget(),
            const SizedBox(height: 24),
            const Text(
              'Image batch to stress test (2000 images).',
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 8),
            const Text(
              'This tests the queue system that prevents Chrome crashes.',
              textAlign: TextAlign.center,
              style: TextStyle(fontSize: 12, color: Colors.grey),
            ),
            const SizedBox(height: 8),
            Wrap(
              children: List.generate(
                2000,
                (index) => SlimCachedNetworkImage(
                  imageUrl: "https://picsum.photos/500?random=${Random().nextInt(1000000)}",
                  width: 100,
                  height: 100,
                  fit: BoxFit.cover,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

/// A widget that displays the current image decode queue statistics
class _QueueStatsWidget extends StatefulWidget {
  @override
  State<_QueueStatsWidget> createState() => _QueueStatsWidgetState();
}

class _QueueStatsWidgetState extends State<_QueueStatsWidget> {
  Map<String, int> _stats = {};

  @override
  void initState() {
    super.initState();
    _updateStats();
    // Update stats periodically
    Future.doWhile(() async {
      await Future.delayed(const Duration(milliseconds: 100));
      if (mounted) {
        _updateStats();
        return true;
      }
      return false;
    });
  }

  void _updateStats() {
    if (mounted) {
      setState(() {
        _stats = SlimImageDecodeConfig.getQueueStats();
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(12),
      decoration: BoxDecoration(
        color: Colors.blue[50],
        border: Border.all(color: Colors.blue[200]!),
        borderRadius: BorderRadius.circular(8),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text('Active Decodes: ${_stats['activeDecodes'] ?? 0}'),
          Text('Pending in Queue: ${_stats['pendingDecodes'] ?? 0}'),
          Text('Max Concurrent: ${_stats['maxConcurrent'] ?? 0}'),
        ],
      ),
    );
  }
}