duplicate_images_plugin 0.0.3 copy "duplicate_images_plugin: ^0.0.3" to clipboard
duplicate_images_plugin: ^0.0.3 copied to clipboard

Get duplicate images from gallery.

example/lib/main.dart

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:duplicate_images_plugin/duplicate_images_plugin.dart';
import 'package:flutter/services.dart';
import 'package:photo_manager/photo_manager.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DuplicateImagesScreen(),
    );
  }
}

class DuplicateImagesScreen extends StatefulWidget {
  @override
  _DuplicateImagesScreenState createState() => _DuplicateImagesScreenState();
}

class _DuplicateImagesScreenState extends State<DuplicateImagesScreen> {
  Map<String, List<String>> duplicateGroups = {};
  bool isLoading = true;

  @override
  void initState() {
    super.initState();
    findAndListDuplicates();
  }

  Future<void> findAndListDuplicates() async {
    setState(() {
      isLoading = true;
    });

    try {
      final result = await compute(findDuplicates, RootIsolateToken.instance!);
      setState(() {
        duplicateGroups = result;
      });
    } catch (e) {
      print("Error finding duplicates: $e");
    } finally {
      setState(() {
        isLoading = false;
      });
    }
  }

  static Future<Map<String, List<String>>> findDuplicates(dynamic token) async {
    BackgroundIsolateBinaryMessenger.ensureInitialized(token);
    return await DuplicateImagesPlugin().findAndListDuplicates();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Duplicate Images'),
      ),
      body: isLoading
          ? Center(child: CircularProgressIndicator())
          : ListView.builder(
        itemCount: duplicateGroups.keys.length,
        itemBuilder: (context, index) {
          String key = duplicateGroups.keys.elementAt(index);
          List<String> assets = duplicateGroups[key]!;
          return ExpansionTile(
            title: Text('Group Key: $key'),
            children: assets.map((asset) => AssetImageView(assetId: asset)).toList(),
          );
        },
      ),
    );
  }
}

class AssetImageView extends StatelessWidget {
  final String assetId;

  const AssetImageView({Key? key, required this.assetId}) : super(key: key);

  Future<Widget> _loadImage() async {
    final asset = await AssetEntity.fromId(assetId);
    if (asset == null) {
      return Text('Image not found');
    }

    final thumb = await asset.thumbnailDataWithSize(ThumbnailSize(300, 300));
    if (thumb == null) {
      return Text('Image not available');
    }

    return Image.memory(thumb, fit: BoxFit.cover);
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<Widget>(
      future: _loadImage(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return CircularProgressIndicator();
        } else if (snapshot.hasError) {
          return Text('Error loading image');
        } else {
          return snapshot.data!;
        }
      },
    );
  }
}