quickcapture 1.1.12 copy "quickcapture: ^1.1.12" to clipboard
quickcapture: ^1.1.12 copied to clipboard

QuickCapture - Ai Based Mobile Document Scanning,compression & imaging plugin for Flutter From Extrieve.

example/lib/main.dart

/// Sample Flutter application demonstrating the use of the QuickCapture Flutter plugin.
///
/// This application allows users to:
/// - Attach an image from the gallery.
/// - Capture document with SDK camera with ai features.
/// - Compress and optimize image with proper DPI, Layout control.
/// - Convert images to single TIFF and PDF files.
/// - Detect human faces in images and match them.
///
/// The application showcases how to integrate and use various features of the QuickCapture plugin.
///
/// Author: Extrieve Technologies
/// Website: https://www.extrieve.com
/// Extrieve Technologies - Your Expert in Document Management & AI Solutions
library;

import 'dart:convert';
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:image_gallery_saver_plus/image_gallery_saver_plus.dart';
import 'package:image_picker/image_picker.dart';
import 'package:open_file/open_file.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:image/image.dart' as img;
import 'package:permission_handler/permission_handler.dart';
import 'package:geolocator/geolocator.dart';

// Import Quickcapture plugin
import 'package:quickcapture/quickcapture.dart';

void main() {
  runApp(MaterialApp(navigatorKey: MyApp.navigatorKey, home: MyApp()));
}

class MyApp extends StatefulWidget {
  // If you want to call showDialog without context, you can use this:
  static final GlobalKey<NavigatorState> navigatorKey =
      GlobalKey<NavigatorState>();

  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

typedef MyCallback = void Function(String result);

class _MyAppState extends State<MyApp> {
  bool isScreenProtectionEnabled = false;
  bool isMonitoringEnabled = false;
  final Quickcapture _quickcapturePlugin = Quickcapture();

  // Store captured images from startCapture()
  List<String> _capturedImage = [];
  Uint8List? qrImage;

  @override
  void initState() {
    super.initState();
    requestLocationPermission();
    initPlugin();
  }

  void initPlugin() async {
    await _quickcapturePlugin.initialize();
    await activateLicense();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('QuickCapture Sample Demo')),
      body: SingleChildScrollView(
        child: Column(
          children: [
            if (_capturedImage.isNotEmpty) ...[
              const SizedBox(height: 10),

              Text(
                "Captured Images",
                style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
              ),

              const SizedBox(height: 10),

              SizedBox(
                height: 180,
                child: ListView.builder(
                  scrollDirection: Axis.horizontal,
                  itemCount: _capturedImage.length,
                  itemBuilder: (context, index) {
                    return GestureDetector(
                      onTap: () {
                        Navigator.push(
                          context,
                          MaterialPageRoute(
                            builder: (_) =>
                                FullImageView(imagePath: _capturedImage[index]),
                          ),
                        );
                      },
                      child: Container(
                        margin: EdgeInsets.symmetric(horizontal: 8),
                        child: ClipRRect(
                          borderRadius: BorderRadius.circular(10),
                          child: Image.file(
                            File(_capturedImage[index]),
                            width: 140,
                            fit: BoxFit.cover,
                          ),
                        ),
                      ),
                    );
                  },
                ),
              ),
            ],
            ElevatedButton(
              onPressed: () => startCapture(),
              child: const Text("Start Capture"),
            ),
            ElevatedButton(
              onPressed: () {
                _showBottomStampDialog();
              },
              child: Text("Add Bottom Stamp"),
            ),
            ElevatedButton(
              onPressed: () => assetCapture(),
              child: const Text("Asset Capture"),
            ),

            ElevatedButton(
              onPressed: () => buildPDFForLastCapture(),
              child: const Text("Build PDF For Last Capture"),
            ),

            ElevatedButton(
              onPressed: () => buildTIFFForLastCapture(),
              child: const Text("Build TIFF For Last Capture"),
            ),
            // ElevatedButton(
            //   onPressed: () async {
            //     final ImagePicker picker = ImagePicker();

            //     final XFile? image = await picker.pickImage(
            //       source: ImageSource.gallery,
            //     );

            //     if (image != null) {
            //       compressImage(image.path);
            //     }
            //   },
            //   child: const Text("Pick Image & Compress"),
            // ),
            ElevatedButton(
              onPressed: () => buildPDF(),
              child: const Text("Build PDF from images"),
            ),

            ElevatedButton(
              onPressed: () => buildTIFF(),
              child: const Text("Build TIFF from images"),
            ),

            ElevatedButton(
              onPressed: () => pickImageFromGallery(),
              child: const Text("Attach from Gallery"),
            ),

            ElevatedButton(
              onPressed: () => pickAndDetectHumanFaces(),
              child: const Text("Human Face Detection & Matching"),
            ),
            ElevatedButton(
              onPressed: () {
                _showQrBarCodeDialog();
              },
              child: const Text("Generate QR / Bar Code"),
            ),
             ElevatedButton(
                onPressed: () async {
                  await startCodeScanner();
                },
                child: const Text("Scan QR/ Bar Code"),
              ),

            ElevatedButton(
              onPressed: () => getDeviceInfo(),
              child: const Text("Get Device Info"),
            ),
            ElevatedButton(
              onPressed: () {
                pickImageAndReadInfo();
              },
              child: Text("Read Image Info"),
            ),
            ElevatedButton(
              onPressed: () => getLocationInfo(),
              child: const Text("Generate Location Information "),
            ),
            ElevatedButton(
              onPressed: () => getCurrentDigiPin(),
              child: const Text(" Retrieves the current DigiPIN."),
            ),
            ElevatedButton(
              onPressed: () => getSecurityInfo(),
              child: const Text("Get Security Info"),
            ),
          Center(
            child: SizedBox(
              width: 300, // fixed width for alignment
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: [

                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Expanded(
                        child: Center(
                          child: Text("Screen Protection"),
                        ),
                      ),
                      Switch(
                        value: isScreenProtectionEnabled,
                        onChanged: (value) async {
                          setState(() {
                            isScreenProtectionEnabled = value;
                          });
                          if(value){
                            // Enable screen protection to prevent screenshots and screen recording
                            await _quickcapturePlugin.enableScreenProtection();
                          }else{
                            // Disable screen protection
                            await _quickcapturePlugin.disableScreenProtection();
                          }
                        },
                      ),
                    ],
                  ),

                  SizedBox(height: 16),

                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Expanded(
                        child: Center(
                          child: Text("Device Monitoring"),
                        ),
                      ),
                      Switch(
                        value: isMonitoringEnabled,
                        onChanged: (value) async {
                          setState(() {
                            isMonitoringEnabled = value;
                          });
                          if(value){
                            // Start monitoring device
                            await _quickcapturePlugin.startDeviceMonitoring();
                          }else{
                            // Stop monitoring device
                            await _quickcapturePlugin.stopDeviceMonitoring();
                          }
                        },
                      ),
                    ],
                  ),
                ],
              ),
            ),
          )
        ],
      ),
    ),
  );
}

  /// Activate Quickcapture license
  Future<void> activateLicense() async {
    // TODO: Securely fetch license keys from a secure source.
    String androidLicense =
        "<Pass the license string for Android platform here>";
    String iosLicense = "<Pass the license string for IOS platform here>";
    bool? response = await _quickcapturePlugin.activateLicense(
      android: androidLicense,
      ios: iosLicense,
    );

    String lisMsg = "License activation failed. Invalid license";
    Color bgColor = const Color.fromARGB(255, 216, 90, 58);
    if (response == true) {
      lisMsg = "License for android activated";
      bgColor = const Color.fromARGB(255, 58, 216, 84);
    }

    Fluttertoast.showToast(
      msg: lisMsg,
      toastLength: Toast.LENGTH_SHORT,
      gravity: ToastGravity.CENTER,
      backgroundColor: bgColor,
      textColor: Colors.white,
      fontSize: 16.0,
    );
  }

  /// Set config for capturing images with QuickCapture
  void setConfigForCapture() {
    // Example: Set DPI and layout type
  _quickcapturePlugin.config.image.setDPI(DPI.dpi200);
  _quickcapturePlugin.config.image.setLayoutType(LayoutType.A4);
  _quickcapturePlugin.config.image.setResizeMode(
    ResizeMode.preserveAspectOnly,
  );
   // Enable flash, set max pages, etc.
  _quickcapturePlugin.config.capture.enableFlash = true;
  _quickcapturePlugin.config.capture.captureSound = false;
  _quickcapturePlugin.config.capture.maxPage = 0;
    // Enable torch on low light conditions
  _quickcapturePlugin.config.capture.enableTorchOnLowLight = true;
  // Enable auto-correct document angle in review screen
  _quickcapturePlugin.config.review.enableAutoCorrectDocAngle = true;
}
Future<void> addBottomStamp(String text) async {
  try {
    // Get location info and DigiPIN to include in the bottom stamp
    String? location = await _quickcapturePlugin.getLocationInfo();
    if(location == null){
      Fluttertoast.showToast(
        msg: "Unable to fetch location info",
        backgroundColor: Colors.orange,
        textColor: Colors.white,
      );
      return;
    }
    print(location);
    Map<String, dynamic> jsonMap = json.decode(location);
    String finalText = text + "\$ Latitude : " + jsonMap['Latitude'].toString() + " Longitude : " + jsonMap['Longitude'].toString() + " DigiPIN : " + jsonMap['DigiPIN'].toString();

    _quickcapturePlugin.config.capture.bottomStampData = finalText;

    Fluttertoast.showToast(
      msg: "Bottom Stamping Set Successfully, Now start Asset capture/document capture to see the stamping effect.",
      backgroundColor: const Color.fromARGB(255, 169, 202, 171),
      textColor: Colors.white,
    );
  } catch (e) {
    Fluttertoast.showToast(
      msg: "Stamp Error: ${e.toString()}",
      backgroundColor: Colors.red,
      textColor: Colors.white,
    );
  }
}
  /// Start capturing images using QuickCapture
  Future<void> startCapture() async {
  try {
    setConfigForCapture();
    String? response = await _quickcapturePlugin.startCapture();

    if (response != null) {
        setState(() {
          Map<String, dynamic> jsonResponse = jsonDecode(response);
          _capturedImage = List<String>.from(jsonResponse['fileCollection']);
        });

        // Save to gallery
        for (String imagePath in _capturedImage) {
          final result = await ImageGallerySaverPlus.saveFile(imagePath);
          if (result == true) {
            Fluttertoast.showToast(
              msg: "Image saved to gallery: $imagePath",
              backgroundColor: Colors.green,
              textColor: Colors.white,
            );
          } else {
            Fluttertoast.showToast(
              msg: "Failed to save image: $imagePath",
              backgroundColor: Colors.red,
              textColor: Colors.white,
            );
          }
        }
      } else {
        throw Exception("No response received from startCapture");
      }
    } catch (e) {
      Fluttertoast.showToast(
        msg: "Capture failed",
        backgroundColor: Colors.red,
      );
    }
  } 
  //Asset capture
  Future<void> assetCapture() async {
    try {
      String? response = await _quickcapturePlugin.assetCapture();

      if (response != null) {
        Map<String, dynamic> jsonResponse = jsonDecode(response);

        List<String> capturedImages = List<String>.from(
          jsonResponse['fileCollection'],
        );
        setState(() {
          _capturedImage = (capturedImages);
        });
      } else {
        Fluttertoast.showToast(
          msg: "No images captured",
          backgroundColor: Colors.orange,
          textColor: Colors.white,
        );
      }
    } catch (e) {
       Fluttertoast.showToast(
        msg: "Error in asset capture: ${e.toString()}",
        backgroundColor: Colors.red,
        textColor: Colors.white,
      );
    }
  }

  /// Build PDF from last capture
  Future<void> buildPDFForLastCapture() async {
    String? response = await _quickcapturePlugin.buildPDFForLastCapture();
    if (response != null) {
      OpenFile.open(response);
    }
  }

  /// Build TIFF from last capture
  Future<void> buildTIFFForLastCapture() async {
    String? response = await _quickcapturePlugin.buildTIFFForLastCapture();
    if (response != null) {
      OpenFile.open(response);
    }
  }

  //Pick image and compress
  Future<void> compressImage(String imagePath) async {
    try {
      String? compressedImagePath = await _quickcapturePlugin.compressToJPEG(
        imagePath,
      );

      if (compressedImagePath != null) {
        print("Compressed image: $compressedImagePath");

        await ImageGallerySaverPlus.saveFile(compressedImagePath);
        
        setState(() {
          _capturedImage.add(compressedImagePath);
        });

        Fluttertoast.showToast(
          msg: "Compressed Image Saved",
          backgroundColor: Colors.green,
          textColor: Colors.white,
        );
      } else {
        print("Compression failed");
      }
    } catch (e) {
      print("Error compressing image: $e");
    }
  }

  /// Build PDF from selected images
  Future<void> buildPDF() async {
    final ImagePicker picker = ImagePicker();

    try {

      final List<XFile> images = await picker.pickMultiImage();

      if (images.isEmpty) {
        Fluttertoast.showToast(
          msg: "No images selected.",
          backgroundColor: Colors.orange,
          textColor: Colors.white,
        );
        return;
      }
      final List<String> imagePaths = images
          .map((image) => image.path)
          .toList();

      final String? response = await _quickcapturePlugin.buildPDF(imagePaths);

      if (response != null) {
        OpenFile.open(response);
      } else {
        Fluttertoast.showToast(
          msg: "Failed to create PDF",
          backgroundColor: Colors.red,
          textColor: Colors.white,
        );
      }
    } catch (e) {
      Fluttertoast.showToast(
        msg: "Error building PDF: ${e.toString()}",
        backgroundColor: Colors.red,
        textColor: Colors.white,
      );
    }
  }

  /// Build TIFF from selected images
  Future<void> buildTIFF() async {
    final ImagePicker picker = ImagePicker();

    try {

      final List<XFile> images = await picker.pickMultiImage();

      if (images.isEmpty) {
        Fluttertoast.showToast(
          msg: "No images selected.",
          backgroundColor: Colors.orange,
          textColor: Colors.white,
        );
        return;
      }

      final List<String> imagePaths = images
          .map((image) => image.path)
          .toList();

      final String? response = await _quickcapturePlugin.buildTiff(imagePaths);

      if (response != null) {
        print("TIFF saved at: $response");

        Fluttertoast.showToast(
          msg: "TIFF Created Successfully",
          backgroundColor: Colors.green,
          textColor: Colors.white,
        );

        OpenFile.open(response);
      } else {
        Fluttertoast.showToast(
          msg: "Failed to create TIFF",
          backgroundColor: Colors.red,
          textColor: Colors.white,
        );
      }
    } catch (e) {
      Fluttertoast.showToast(
        msg: "Error building TIFF: ${e.toString()}",
        backgroundColor: Colors.red,
        textColor: Colors.white,
      );
    }
  }

  final ImagePicker _picker = ImagePicker();

  /// Pick image from Gallery, apply QuickCapture compression & optimisation based on imaging config
  Future<void> pickImageFromGallery() async {
    final ImagePicker picker = ImagePicker();

    try {
      final XFile? pickedFile = await picker.pickImage(
        source: ImageSource.gallery,
      );

      if (pickedFile != null) {
        String imagePath = pickedFile.path;
        if (kDebugMode) {
          print("imagePath:$imagePath");
        }

        // Example: set resizing mode
        _quickcapturePlugin.config.image.setResizeMode(
          ResizeMode.preserveAspectOnly,
        );
        //_quickcapturePlugin.config.image.setLayoutType(LayoutType.A4);
        //_quickcapturePlugin.config.image.setCustomLayout(2, 1);

        _quickcapturePlugin.config.review.enableAutoCorrectDocAngle = true;
        String? response = await _quickcapturePlugin.startImageAttach(
          imagePath,
        );
        if (response != null) {
          setState(() {
            Map<String, dynamic> jsonResponse = jsonDecode(response);
            List<String> images = List<String>.from(
              jsonResponse['fileCollection'],
            );
            _capturedImage = (images);
          });
          // Save to gallery
          for (String imagePath in _capturedImage) {
            final result = await ImageGallerySaverPlus.saveFile(imagePath);
            if (result == true) {
              Fluttertoast.showToast(
                msg: "Image saved to gallery: $imagePath",
                backgroundColor: Colors.green,
                textColor: Colors.white,
              );
            } else {
              Fluttertoast.showToast(
                msg: "Failed to save image: $imagePath",
                backgroundColor: Colors.red,
                textColor: Colors.white,
              );
            }
          }
        } else {
          throw Exception("No response received from startImageAttach");
        }
      } else {
        Fluttertoast.showToast(
          msg: "No image selected.",
          backgroundColor: Colors.orange,
          textColor: Colors.white,
        );
      }
    } catch (e) {
      Fluttertoast.showToast(
        msg: "Error picking or processing image: ${e.toString()}",
        backgroundColor: Colors.red,
        textColor: Colors.white,
      );
    }
  } /// Pick image, detect faces, and show a popup for multiple images with face matching
  Future<void> pickAndDetectHumanFaces() async {
    final ImagePicker picker = ImagePicker();
    List<Map<String, dynamic>> attachedImages = [];
    List<Map<String, dynamic>> allFaceThumbnails = [];
    List<Map<String, dynamic>> selectedThumbnails = [];

    void handleFaceThumbnailSelection(Map<String, dynamic> thumbnail) {
      if (selectedThumbnails.contains(thumbnail)) {
        selectedThumbnails.remove(thumbnail);
      } else {
        if (selectedThumbnails.length < 2) {
          selectedThumbnails.add(thumbnail);
        } else {
          Fluttertoast.showToast(
            msg: "Only 2 thumbnails can be selected at a time.",
            backgroundColor: Colors.orange,
            textColor: Colors.white,
          );
        }
      }
    }

    void showPopup() {
      final ctx = MyApp.navigatorKey.currentContext ?? context;

      showDialog(
        context: ctx,
        builder: (context) {
          return StatefulBuilder(
            builder: (context, setState) {
              return AlertDialog(
                title: const Text("Detect and Match Faces"),
                content: SingleChildScrollView(
                  child: Column(
                    children: [
                      // Display attached images
                      attachedImages.isNotEmpty
                          ? Column(
                              children: attachedImages
                                  .map(
                                    (imageData) => Image.file(
                                      File(imageData['path']),
                                      width: 100,
                                      height: 100,
                                    ),
                                  )
                                  .toList(),
                            )
                          : const Text("No images attached"),
                      ElevatedButton(
                        onPressed: () async {
                          final XFile? pickedFile = await picker.pickImage(
                            source: ImageSource.gallery,
                          );

                          if (pickedFile != null) {
                            setState(() {
                              attachedImages.add({
                                'path': pickedFile.path,
                                'docId': null,
                              });
                            });

                            Fluttertoast.showToast(
                              msg: "Image attached. Detecting faces...",
                              backgroundColor: Colors.blue,
                              textColor: Colors.white,
                            );

                            String? detectionResponse =
                                await _quickcapturePlugin.detectHumanFaces(
                                  pickedFile.path,
                                );

                            if (detectionResponse != null &&
                                detectionResponse.isNotEmpty) {
                              Map<String, dynamic> responseJson = jsonDecode(
                                detectionResponse,
                              );

                              if (responseJson["STATUS"] == true &&
                                  responseJson["DATA"] != null) {
                                List<dynamic> faceData = responseJson["DATA"];
                                final originalBytes = await File(
                                  pickedFile.path,
                                ).readAsBytes();
                                final img.Image? originalImage = img
                                    .decodeImage(originalBytes);

                                if (originalImage != null) {
                                  for (var face in faceData) {
                                    int left = face["LEFT"].clamp(
                                      0,
                                      originalImage.width,
                                    );
                                    int right = face["RIGHT"].clamp(
                                      0,
                                      originalImage.width,
                                    );
                                    int top = face["TOP"].clamp(
                                      0,
                                      originalImage.height,
                                    );
                                    int bottom = face["BOTTOM"].clamp(
                                      0,
                                      originalImage.height,
                                    );
                                    final croppedFace = img.copyCrop(
                                      originalImage,
                                      x: left,
                                      y: top,
                                      width: right - left,
                                      height: bottom - top,
                                    );

                                    final croppedBytes = img.encodeJpg(
                                      croppedFace,
                                    );
                                    setState(() {
                                      allFaceThumbnails.add({
                                        'thumbnail': Uint8List.fromList(
                                          croppedBytes,
                                        ),
                                        'docId': responseJson['IDENTIFIER'],
                                        'faceIndex': face['INDEX'],
                                      });
                                    });
                                  }
                                }
                              }
                            }
                          }
                        },
                        child: const Text("Attach Image"),
                      ),
                      const SizedBox(height: 16),
                      // Show face thumbnails
                      allFaceThumbnails.isNotEmpty
                          ? Wrap(
                              spacing: 8,
                              runSpacing: 8,
                              children: allFaceThumbnails.map((thumbnailData) {
                                return GestureDetector(
                                  onTap: () {
                                    setState(() {
                                      handleFaceThumbnailSelection(
                                        thumbnailData,
                                      );
                                    });
                                  },
                                  child: Container(
                                    decoration: BoxDecoration(
                                      border: Border.all(
                                        color:
                                            selectedThumbnails.contains(
                                              thumbnailData,
                                            )
                                            ? Colors.blue
                                            : Colors.transparent,
                                        width: 2,
                                      ),
                                    ),
                                    child: Image.memory(
                                      thumbnailData['thumbnail'],
                                      width: 80,
                                      height: 80,
                                      fit: BoxFit.cover,
                                    ),
                                  ),
                                );
                              }).toList(),
                            )
                          : const Text("No faces detected"),
                    ],
                  ),
                ),
                actions: [
                  TextButton(
                    onPressed: () => Navigator.of(context).pop(),
                    child: const Text("Close"),
                  ),
                  if (selectedThumbnails.length == 2)
                    ElevatedButton(
                      onPressed: () async {
                        Fluttertoast.showToast(
                          msg: "Matching faces...",
                          backgroundColor: Colors.blue,
                          textColor: Colors.white,
                        );

                        String? matchResult = await _quickcapturePlugin
                            .matchHumanFaces(
                              firstDocumentID: selectedThumbnails[0]['docId'],
                              firstDocumentFaceIndex:
                                  selectedThumbnails[0]['faceIndex'],
                              secondDocumentID: selectedThumbnails[1]['docId'],
                              secondDocumentFaceIndex:
                                  selectedThumbnails[1]['faceIndex'],
                            );
                        Fluttertoast.showToast(
                          msg: "Match result: $matchResult",
                          backgroundColor: Colors.green,
                          textColor: Colors.white,
                        );
                      },
                      child: const Text("Match Faces"),
                    ),
                ],
              );
            },
          );
        },
      );
    }

    // Call `initHumanFaceHelper` and show the popup
    bool? initialized = await initHumanFaceHelper();
    if (initialized == true) {
      showPopup();
    } else {
      Fluttertoast.showToast(
        msg: "Failed to initialize Human Face Helper.",
        backgroundColor: Colors.red,
        textColor: Colors.white,
      );
    }
  }

  /// Initialize Human Face Helper
  Future<bool?> initHumanFaceHelper() async {
    bool? result = await _quickcapturePlugin.initHumanFaceHelper();
    String message = result == true
        ? "Human Face Helper initialized successfully."
        : "Failed to initialize Human Face Helper.";
    Fluttertoast.showToast(
      msg: message,
      backgroundColor: result == true ? Colors.green : Colors.red,
      textColor: Colors.white,
    );
    return result;
  }
  // 
void _showBottomStampDialog() {
  final TextEditingController stampController = TextEditingController();

  showDialog(
    context: MyApp.navigatorKey.currentState!.overlay!.context,
    barrierDismissible: false,
    builder: (BuildContext context) {
      return AlertDialog(
        title: const Text("Add Bottom Stamp"),
        content: TextField(
          controller: stampController,
          maxLines: 2,
          decoration: const InputDecoration(
            hintText: "{DATETIME} , Other info \$ next line info....",
            border: OutlineInputBorder(),
          ),
        ),
        actions: [
          TextButton(
            onPressed: () {
              Navigator.of(context).pop();
            },
            child: const Text("Cancel"),
          ),
          ElevatedButton(
            onPressed: () {
              final String stampText = stampController.text.trim();

              if (stampText.isEmpty) {
                ScaffoldMessenger.of(context).showSnackBar(
                  const SnackBar(content: Text("Please enter some text")),
                );
                return;
              }
              addBottomStamp(stampText);

              Navigator.of(context).pop();
            },
            child: const Text("Submit"),
          ),
        ],
      );
    },
  );
}


  Future<void> generateQRCode(String data) async {
    try {
      String? response = await _quickcapturePlugin.generateQRCode(data);

      print("QR RESPONSE: $response");

      if (response != null && response.isNotEmpty) {
        setState(() {
          qrImage = base64Decode(response);
        });
      }
    } catch (e) {
      print("Error Generating QR Code: $e");
    }
  }

  /// Generate a bar code from the provided data
  Future<void> generateBARCode(String data) async {
    try {
      String? response = await _quickcapturePlugin.generateBARCode(data, true);

      print("BARCODE RESPONSE: $response");

      if (response != null && response.isNotEmpty) {
        setState(() {
          qrImage = base64Decode(response);
        });

        Fluttertoast.showToast(
          msg: "Bar code generated successfully",
          backgroundColor: Colors.green,
          textColor: Colors.white,
        );
      }
    } catch (e) {
      print("Error generating bar code: $e");
    }
  }

  /// Get device information
  Future<void> getDeviceInfo() async {
    try {
      String? response = await _quickcapturePlugin.getDeviceInfo();
      if (response != null) {
        Fluttertoast.showToast(
          msg: "Device info: $response",
          backgroundColor: Colors.green,
          textColor: Colors.white,
        );
      }
    } catch (e) {
      Fluttertoast.showToast(
        msg: "Error getting device info: ${e.toString()}",
        backgroundColor: Colors.red,
        textColor: Colors.white,
      );
    }
  }

  Future<void> pickImageAndReadInfo() async {
    try {
      // Image select from gallery
      final XFile? image = await _picker.pickImage(source: ImageSource.gallery);

      if (image == null) {
        print("No image selected");
        return;
      }

      String imagePath = image.path;

      print("Selected Image Path: $imagePath");

      // Read image info
      String? response = await _quickcapturePlugin.readImageInfo(imagePath);

      print("Image Info: $response");

      Fluttertoast.showToast(
        msg: response ?? "No response",
        backgroundColor: Colors.green,
        textColor: Colors.white,
      );
    } catch (e) {
      print("Error: $e");
    }
  }

Future<void> getLocationInfo() async {
    try{
      String? response = await _quickcapturePlugin.getLocationInfo();
      if (response != null) {
        Fluttertoast.showToast(
          msg: "Location Info: $response",
          backgroundColor: Colors.blue,
          textColor: Colors.white,
          toastLength: Toast.LENGTH_LONG,
        );
      }
    } catch (e) {
      Fluttertoast.showToast(
        msg: "Error getting location info: ${e.toString()}",
        backgroundColor: Colors.red,
        textColor: Colors.white,
        toastLength: Toast.LENGTH_LONG,
      );
    }
  }
  // GEt current DigiPin
  Future<void> getCurrentDigiPin() async {
    try{
      String? response = await _quickcapturePlugin.getCurrentDigiPin();
      if (response != null) {
        Fluttertoast.showToast(
          msg: "Current DigiPin: $response",
          backgroundColor: Colors.blue,
          textColor: Colors.white,
          toastLength: Toast.LENGTH_LONG,
        );
      }
    } catch (e) {
      Fluttertoast.showToast(
        msg: "Error getting DigiPin: ${e.toString()}",
        backgroundColor: Colors.red,
        textColor: Colors.white,
        toastLength: Toast.LENGTH_LONG,
      );
    }
  }

  Future<void> requestLocationPermission() async {
    LocationPermission permission = await Geolocator.checkPermission();

    if (permission == LocationPermission.denied) {
      permission = await Geolocator.requestPermission();
    }

    if (permission == LocationPermission.deniedForever) {
      await Geolocator.openAppSettings();
      return;
    }

    Position position = await Geolocator.getCurrentPosition(
      desiredAccuracy: LocationAccuracy.high,
    );
  } 

  Future<void> startImageAttach(String imagePath) async {
    try {
      String? response = await _quickcapturePlugin.startImageAttach(imagePath);

      if (response != null) {
        Map<String, dynamic> jsonResponse = jsonDecode(response);

        List<String> capturedImages = List<String>.from(
          jsonResponse['fileCollection'],
        );

        setState(() {
          _capturedImage = capturedImages;
        });

        print("Captured Images: $capturedImages");
      } else {
        print("Image attach cancelled.");
      }
    } catch (e) {
      print("Error attaching image: $e");
    }
  }

  // Get security information
  Future<void> getSecurityInfo() async {
    try{
      String? response = await _quickcapturePlugin.getSecurityInfo();
      if (response != null) {
        Fluttertoast.showToast(
          msg: "Security Info: $response",
          backgroundColor: Colors.blue,
          textColor: Colors.white,
          toastLength: Toast.LENGTH_LONG,
        );
      }
    } catch (e) {
      Fluttertoast.showToast(
        msg: "Error getting security info: ${e.toString()}",
        backgroundColor: Colors.red,
        textColor: Colors.white,
        toastLength: Toast.LENGTH_LONG,
      );
    }
  }

  /// Show dialog to input barcode data and generate barcode
  void showBarcodeInputDialog() {
    final TextEditingController controller = TextEditingController();
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: const Text("Generate BAR Code"),
          content: TextField(
            controller: controller,
            decoration: const InputDecoration(hintText: "Enter barcode data"),
          ),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(context).pop(),
              child: const Text("Cancel"),
            ),
            ElevatedButton(
              onPressed: () {
                if (controller.text.isNotEmpty) {
                  generateBARCode(controller.text);
                  Navigator.of(context).pop();
                } else {
                  Fluttertoast.showToast(
                    msg: "Please enter barcode data",
                    backgroundColor: Colors.orange,
                    textColor: Colors.white,
                  );
                }
              },
              child: const Text("Generate"),
            ),
          ],
        );
      },
    );
  }

  void showCodeOptions() {
    showModalBottomSheet(
      context: context,
      builder: (context) {
        return Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            ListTile(
              leading: Icon(Icons.qr_code),
              title: Text("Generate QR Code"),
              onTap: () {
                Navigator.pop(context);
                showQRInputDialog();
              },
            ),

            ListTile(
              leading: Icon(Icons.qr_code_2),
              title: Text("Generate Barcode"),
              onTap: () {
                Navigator.pop(context);
                showBarcodeInputDialog();
              },
            ),
            // 🔥 NEW OPTION
            ListTile(
              leading: Icon(Icons.camera_alt),
              title: Text("Scan Code"),
              onTap: () {
                Navigator.pop(context);
                startCodeScanner();
              },
            ),
          ],
        );
      },
    );
  }

  //
  void showQRInputDialog() {
    TextEditingController qrController = TextEditingController();

    showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(
          title: const Text("Enter text for QR Code"),
          content: TextField(
            controller: qrController,
            decoration: const InputDecoration(hintText: "Enter text"),
          ),
          actions: [
            ElevatedButton(
              onPressed: () async {
                String text = qrController.text;

                if (text.isNotEmpty) {
                  await generateQRCode(text);

                  Navigator.pop(context);
                } else {
                  Fluttertoast.showToast(
                    msg: "Enter text first",
                    backgroundColor: Colors.orange,
                    textColor: Colors.white,
                  );
                }
              },
              child: const Text("Submit"),
            ),
          ],
        );
      },
    );
  }
  Future<void> startCodeScanner() async {
    try {
      // Start scanning
      String? response = await _quickcapturePlugin.startOpticalCodeCapture();

      if (response != null && response.isNotEmpty) {
        Fluttertoast.showToast(
          msg: "Scanned: $response",
          backgroundColor: Colors.green,
          textColor: Colors.white,
        );
      } else {
        Fluttertoast.showToast(msg: "No code detected");
      }
    } catch (e) {
      print("SCAN ERROR: $e");

      Fluttertoast.showToast(msg: "Scan failed", backgroundColor: Colors.red);
    }
  }

  Future<String?> buildQRCode(String data) async {
    try {
      String? response = await _quickcapturePlugin.generateQRCode(data);
      return response;
    } catch (e) {
      print("QR Error: $e");
      return null;
    }
  }

  Future<String?> buildBARCode(String data, bool showText) async {
    try {
      String? response = await _quickcapturePlugin.generateBARCode(
        data,
        showText,
      );
      return response;
    } catch (e) {
      print("BAR Error: $e");
      return null;
    }
  }

  void _showQrBarCodeDialog() {
    final TextEditingController qrDataController = TextEditingController();

    String? base64Image;

    showDialog(
      context: MyApp.navigatorKey.currentState!.overlay!.context,

      barrierDismissible: false,

      builder: (BuildContext context) {
        return StatefulBuilder(
          builder: (context, setState) {
            return AlertDialog(
              title: const Text("Build QR/Bar Code"),

              content: SingleChildScrollView(
                child: Column(
                  mainAxisSize: MainAxisSize.min,

                  children: [
                    TextField(
                      controller: qrDataController,

                      maxLines: 4,

                      decoration: const InputDecoration(
                        hintText: "Enter data for QR/Bar code...",

                        border: OutlineInputBorder(),
                      ),
                    ),

                    const SizedBox(height: 16),

                    //  IMAGE PREVIEW
                    if (base64Image != null)
                      SizedBox(
                        height: 200,

                        child: Image.memory(
                          base64Decode(base64Image!.split(',').last),

                          fit: BoxFit.contain,
                        ),
                      ),
                  ],
                ),
              ),

              actions: [
                TextButton(
                  onPressed: () => Navigator.of(context).pop(),

                  child: const Text("Close"),
                ),

                ElevatedButton(
                  onPressed: () async {
                    FocusManager.instance.primaryFocus?.unfocus();

                    final qrData = qrDataController.text.trim();

                    if (qrData.isEmpty) {
                      ScaffoldMessenger.of(context).showSnackBar(
                        const SnackBar(content: Text("Please enter some data")),
                      );

                      return;
                    }
                    // Generate QR code
                    final result = await buildQRCode(qrData); //  base64

                    setState(() {
                      base64Image = result;
                    });
                  },

                  child: const Text("Generate QR Code"),
                ),

                ElevatedButton(
                  onPressed: () async {
                    FocusManager.instance.primaryFocus?.unfocus();

                    final qrData = qrDataController.text.trim();

                    if (qrData.isEmpty) {
                      ScaffoldMessenger.of(context).showSnackBar(
                        const SnackBar(content: Text("Please enter some data")),
                      );

                      return;
                    }
                    // Generate bar code without text
                    final result = await buildBARCode(qrData, false);

                    setState(() {
                      base64Image = result;
                    });
                  },

                  child: const Text("Generate Bar Code"),
                ),

                ElevatedButton(
                  onPressed: () async {
                    FocusManager.instance.primaryFocus?.unfocus();

                    final qrData = qrDataController.text.trim();

                    if (qrData.isEmpty) {
                      ScaffoldMessenger.of(context).showSnackBar(
                        const SnackBar(content: Text("Please enter some data")),
                      );

                      return;
                    }
                    // Generate bar code with text
                    final result = await buildBARCode(qrData, true);

                    setState(() {
                      base64Image = result;
                    });
                  },

                  child: const Text("Generate Bar Code with Text"),
                ),
              ],
            );
          },
        );
      },
    );
  } //
}

class FullImageView extends StatelessWidget {
  final String imagePath;

  const FullImageView({super.key, required this.imagePath});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Captured Image")),
      body: Center(child: Image.file(File(imagePath))),
    );
  }
}

/// Basic widget to display a list of image paths in a grid
class ImageGrid extends StatelessWidget {
  final List<String> imagePaths;

  const ImageGrid(this.imagePaths, {super.key});

  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      shrinkWrap: true,
      physics: NeverScrollableScrollPhysics(),
      itemCount: imagePaths.length,
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 3,
        crossAxisSpacing: 8,
        mainAxisSpacing: 8,
      ),
      itemBuilder: (context, index) {
        return GestureDetector(
          onTap: () {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) =>
                    FullImageView(imagePath: imagePaths[index]),
              ),
            );
          },
          child: Image.file(File(imagePaths[index]), fit: BoxFit.cover),
        );
      },
    );
  }
}
16
likes
150
points
297
downloads

Documentation

API reference

Publisher

verified publisherextrieve.com

Weekly Downloads

QuickCapture - Ai Based Mobile Document Scanning,compression & imaging plugin for Flutter From Extrieve.

Homepage

License

MIT (license)

Dependencies

collection, flutter, plugin_platform_interface

More

Packages that depend on quickcapture

Packages that implement quickcapture