duplicate_images_plugin 0.0.4 duplicate_images_plugin: ^0.0.4 copied to clipboard
Get duplicate images from gallery.
example/lib/main.dart
import 'dart:async';
import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:duplicate_images_plugin/duplicate_images_plugin.dart';
import 'package:photo_manager/photo_manager.dart';
import 'package:flutter_isolate/flutter_isolate.dart';
import 'background_task.dart'; // Import the background task
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;
StreamController<Map<String, List<String>>>? _streamController;
@override
void initState() {
super.initState();
_streamController = StreamController();
_streamController!.stream.listen((data) {
setState(() {
duplicateGroups.addAll(data);
isLoading = false;
});
});
}
@override
void dispose() {
_streamController?.close();
super.dispose();
}
Future<void> findAndListDuplicates() async {
setState(() {
isLoading = true;
});
ReceivePort receivePort = ReceivePort();
await FlutterIsolate.spawn(backgroundTask, receivePort.sendPort);
receivePort.listen((message) {
if (message is Map<String, dynamic> && message.containsKey("error")) {
print("Error finding duplicates: ${message['error']}");
} else if (message is Map<String, List<String>>) {
_streamController?.add(message);
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: InkWell(child: Text('Duplicate Images'),onTap: (){
print("THE TAP");
findAndListDuplicates();
},),
),
body: isLoading
? Center(child: SingleChildScrollView(
child: ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: [
Text('data', style: TextStyle(fontSize: 100),),
Text('data', style: TextStyle(fontSize: 100),),
Text('data', style: TextStyle(fontSize: 100),),
Text('data', style: TextStyle(fontSize: 100),),
Text('data', style: TextStyle(fontSize: 100),),
Text('data', style: TextStyle(fontSize: 100),),
Text('data', style: TextStyle(fontSize: 100),),
Text('data', style: TextStyle(fontSize: 100),),
Text('data', style: TextStyle(fontSize: 100),),
Text('data', style: TextStyle(fontSize: 100),),
Text('data', style: TextStyle(fontSize: 100),),
Text('data', style: TextStyle(fontSize: 100),),
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!;
}
},
);
}
}