pharmago_packages 1.1.2 copy "pharmago_packages: ^1.1.2" to clipboard
pharmago_packages: ^1.1.2 copied to clipboard

Reusable Flutter components for pharmacy applications. Provides cross-platform widgets for barcode scanning (camera and external USB readers) and comprehensive PDF generation with KPIs, tables, and charts.

PharmaGO Packages #

pub package License

Reusable Flutter components for pharmacy applications. This package provides generic, cross-platform widgets and utilities for barcode scanning and PDF generation.

Platform Support #

Feature Android iOS Windows Web macOS Linux
PDF Generation
PDF Preview/Print
Camera Barcode Scanner
External Keyboard Scanner

Platform-Specific Notes #

Windows

  • Camera Scanner: Not supported. The mobile_scanner package does not support Windows desktop. Use the BarcodeKeyboardListenerWidget with an external USB barcode scanner instead.
  • PDF: Fully supported with print preview capabilities.

Web

  • Camera Scanner: Supported (requires HTTPS in production for camera access).
  • External Keyboard Scanner: Works with USB barcode scanners that emulate keyboard input.
  • PDF: Fully supported with browser print dialog.

macOS / Linux

  • Camera Scanner: Not currently supported by mobile_scanner.
  • External Keyboard Scanner: Fully supported.
  • PDF: Fully supported.

Features #

Barcode Scanning #

  • Camera-based scanning with customizable overlay and controls
  • Live QR/barcode tracking (QrTrackerScanner): detects multiple codes at once and draws an overlay that follows each code as it moves, with fully customizable colors and per-detection widgets
  • External keyboard/scanner support for USB barcode readers (Datalogic, Honeywell, etc.)
  • Auto-focus and zoom controls
  • Flash/torch support
  • Configurable scan area with expand/collapse
  • Beep sound feedback
  • Cooldown between scans to prevent duplicate reads

PDF Generation #

  • Custom headers with logo, app name, title, and subtitle
  • KPI sections with Bootstrap-like grid system (col1-col12)
  • Tables with customizable headers, body, and footers
  • Charts: Bar (vertical/horizontal), Pie, and Line charts
  • Custom footers with pagination
  • Portrait and landscape page orientations
  • Page limit protection with configurable max pages

Installation #

Add this package to your pubspec.yaml:

dependencies:
  pharmago_packages: ^1.0.0

Then run:

flutter pub get

Usage #

Barcode Scanner (Camera) #

import 'package:pharmago_packages/pharmago_packages.dart';

// Camera-based scanner (Android, iOS, Web)
BarcodeScannerWidget(
  onBarcodeDetected: (barcode) {
    print('Scanned: $barcode');
  },
  config: BarcodeScannerConfig(
    enableFlash: true,
    enableZoom: true,
    enableAutoFocus: true,
    scanIntervalSeconds: 2.0,
    showSettingsButton: true, // Shows settings bottom sheet with all controls
    onScanIntervalChanged: (value) {
      print('Scan interval changed to: $value s');
    },
    permissionDeniedText: 'Camera permission is required',
    allowCameraText: 'Allow Camera',
    cameraReadDelayText: 'Read Delay',
    cameraReadDelaySubtitleText: '{seconds}s between reads',
  ),
)

Live Camera Detection & Tracking (QrTrackerScanner) #

QrTrackerScanner is a full-area camera widget that auto-detects QR Codes (or any barcode format) and draws a live overlay that follows each code as it moves. It detects multiple codes at the same time, and lets you fully customize the overlay colors/style and the widget shown for each detected code.

Codes are kept on screen for a short window (clearAfter) even when the camera reports them in alternating frames, so two or more codes stay highlighted together.

Basic usage

import 'package:pharmago_packages/pharmago_packages.dart';

// Fills the available space, auto-starts the camera, and tracks every QR Code.
QrTrackerScanner(
  onDetections: (detections) {
    // Called whenever the set of visible codes changes.
    for (final d in detections) {
      print('Code "${d.value}" at ${d.center}');
    }
  },
)

By default it scans QR Codes only. To detect other/multiple formats:

QrTrackerScanner(
  formats: const [BarcodeFormat.qrCode, BarcodeFormat.ean13],
  onDetections: (detections) => print('${detections.length} codes'),
)

Each QrDetection is already mapped to widget (screen) coordinates, so you never deal with raw camera-image coordinates:

Property Description
barcode The underlying Barcode (value, format, raw bytes, ...)
value Convenience getter: displayValue ?? rawValue
corners The four corners (clockwise from top-left), in widget coordinates
bounds Axis-aligned bounding box, in widget coordinates
center Center of the code, in widget coordinates

Customizing the overlay colors and style

Pass a QrDetectionOverlayStyle to change every aspect of the drawing that follows each code:

QrTrackerScanner(
  overlayStyle: const QrDetectionOverlayStyle(
    borderColor: Colors.greenAccent,   // outline color
    borderWidth: 4.0,                  // outline thickness
    fillColor: Color(0x3300FF6A),      // translucent fill over the code
    showCorners: true,                 // dots on the 4 corners
    cornerColor: Colors.white,
    cornerRadius: 5.0,
    showCrosshair: true,               // crosshair at the center
    crosshairColor: Colors.greenAccent,
    crosshairSize: 12.0,
    crosshairWidth: 2.0,
    glow: true,                        // soft glow around the outline
    glowBlur: 3.0,
  ),
)
Property Default Description
borderColor Color(0xFF00E5FF) Outline color around the code
borderWidth 4.0 Outline stroke width
fillColor Color(0x3300E5FF) Translucent fill over the code area
showCorners / cornerColor / cornerRadius true / white / 5.0 Corner dots
showCrosshair / crosshairColor / crosshairSize / crosshairWidth true / cyan / 12.0 / 2.0 Center crosshair
glow / glowBlur true / 3.0 Soft glow around the outline

Customizing the widget shown for each detected code

Use labelBuilder to render your own widget for every detected code. It is positioned automatically (anchored just above the center of the code) and follows the code as it moves:

QrTrackerScanner(
  labelBuilder: (context, detection, index, total) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
      decoration: BoxDecoration(
        color: Colors.green,
        borderRadius: BorderRadius.circular(20),
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          const Icon(Icons.qr_code_2, color: Colors.white, size: 18),
          const SizedBox(width: 6),
          Text(
            detection.value ?? '',
            style: const TextStyle(color: Colors.white),
          ),
        ],
      ),
    );
  },
)

index is the code's position in the current frame (0-based) and total is how many codes are detected at the same time. The returned widget can receive taps.

To hide the built-in label entirely, set showDefaultLabels: false and don't provide a labelBuilder.

Customizing the "N detected" indicator

Use countBuilder to replace the default count badge shown at the top:

QrTrackerScanner(
  countBuilder: (context, count) => Container(
    margin: const EdgeInsets.only(top: 12),
    padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
    decoration: BoxDecoration(
      color: Colors.black54,
      borderRadius: BorderRadius.circular(20),
    ),
    child: Text(
      '$count detected',
      style: const TextStyle(color: Colors.white),
    ),
  ),
)

Set showDefaultCount: false to hide the indicator when no countBuilder is given.

All parameters

Parameter Default Description
controller null Optional external MobileScannerController. If null, one is created and disposed automatically.
formats [BarcodeFormat.qrCode] Formats to detect (used when controller is null).
fit BoxFit.cover How the camera preview fills the area.
overlayStyle QrDetectionOverlayStyle() Colors/style of the detection drawing.
labelBuilder null Custom widget per detected code.
countBuilder null Custom "N detected" indicator.
showDefaultLabels true Show the default label when no labelBuilder.
showDefaultCount true Show the default count badge when no countBuilder.
onDetections null Called when the set of visible codes changes.
clearAfter 500ms How long a code stays visible after it was last seen.
errorBuilder null Builder for the camera error state.
placeholderBuilder null Builder for the camera initialization placeholder.

Full example

QrTrackerScanner(
  formats: const [BarcodeFormat.qrCode],
  fit: BoxFit.cover,
  overlayStyle: const QrDetectionOverlayStyle(
    borderColor: Colors.pinkAccent,
    fillColor: Color(0x33FF4081),
    crosshairColor: Colors.pinkAccent,
  ),
  onDetections: (detections) {
    debugPrint('Visible codes: ${detections.map((d) => d.value).toList()}');
  },
  labelBuilder: (context, detection, index, total) => Chip(
    label: Text('${index + 1}/$total: ${detection.value}'),
  ),
  countBuilder: (context, count) => Padding(
    padding: const EdgeInsets.all(12),
    child: Text('$count QR Codes', style: const TextStyle(color: Colors.white)),
  ),
)

Note: QrTrackerScanner is camera-based, so it follows the same platform support as the camera scanner (Android, iOS, Web). Remember to configure the camera permissions described in Platform-Specific Setup.

Barcode Scanner (External Keyboard/USB Reader) #

import 'package:pharmago_packages/pharmago_packages.dart';

// External keyboard/scanner listener (all platforms)
BarcodeKeyboardListenerWidget(
  onBarcode: (barcode) {
    print('Scanned: $barcode');
  },
  config: BarcodeKeyboardListenerConfig(
    minBarcodeLength: 4,
    maxBarcodeLength: 13,
    numericOnly: true,
    activeText: 'External Reader Active',
    instructionText: 'Point the scanner at a barcode',
  ),
)

Scanner Settings Persistence #

The barcode scanner settings can be persisted locally on the device. This allows users to configure their preferred settings once and have them remembered across app sessions.

import 'package:pharmago_packages/pharmago_packages.dart';

// Retrieve all settings at once
final settings = await BarcodeScannerSettings.getAllSettings();
print('Read delay: ${settings.cameraReadDelay}s');
print('Zoom: ${settings.zoomLevel}');
print('Flash: ${settings.flashEnabled}');
print('Auto Focus: ${settings.autoFocusEnabled}');
print('Expanded Area: ${settings.expandedScanArea}');

// Set individual settings
await BarcodeScannerSettings.setCameraReadDelay(1.5); // 0.25 to 3.0 seconds
await BarcodeScannerSettings.setZoomLevel(0.5);       // 0.0 to 1.0
await BarcodeScannerSettings.setFlashEnabled(true);
await BarcodeScannerSettings.setAutoFocusEnabled(true);
await BarcodeScannerSettings.setExpandedScanArea(true);

// Get individual settings
final delay = await BarcodeScannerSettings.getCameraReadDelay();
final zoom = await BarcodeScannerSettings.getZoomLevel();

// Save all settings at once
await BarcodeScannerSettings.saveAllSettings(
  BarcodeScannerSettingsData(
    cameraReadDelay: 1.5,
    zoomLevel: 0.5,
    flashEnabled: true,
    autoFocusEnabled: false,
    expandedScanArea: false,
  ),
);

// Reset to defaults
await BarcodeScannerSettings.resetToDefaults();

// Get valid delay values (0.25, 0.5, 0.75, ..., 3.0)
final validValues = BarcodeScannerSettings.validCameraReadDelayValues;

Camera Read Delay Slider

The settings bottom sheet includes a slider to configure the camera read delay (time between barcode reads). The slider allows values from 0.25 to 3.0 seconds in 0.25s increments:

  • 0.25s - Fastest scanning, good for rapid inventory counting
  • 1.0s - Balanced speed for general use
  • 2.0s - Default, prevents accidental duplicate scans
  • 3.0s - Slowest, for careful single-item scanning

The selected value is automatically persisted to local storage and restored when the app restarts.

PDF Generation #

import 'package:pharmago_packages/pharmago_packages.dart';
import 'package:printing/printing.dart';

// Create a PDF builder
final pdfBuilder = PdfBuilder(
  config: PdfConfig.a4Portrait(),
  header: PdfHeaderConfig(
    title: 'Monthly Report',
    subtitle: 'January 2025 - Sales Summary',
    appName: 'MyApp',
  ),
  footer: const PdfFooterConfig(
    leftText: 'Generated by MyApp',
    showPageNumbers: true,
  ),
  maxPages: 500,
);

// Add KPI section
pdfBuilder.addSection(
  PdfKpiSection(
    order: 1,
    sectionTitle: 'Key Metrics',
    items: [
      const PdfKpiItem(
        title: 'Total Sales',
        value: '\$125,430.00',
        columnSpan: PdfColumnSpan.col6,
        trend: KpiTrend.positive,
        trendValue: '+12.5%',
      ),
      const PdfKpiItem(
        title: 'Units Sold',
        value: '3,847',
        columnSpan: PdfColumnSpan.col6,
        trend: KpiTrend.positive,
        trendValue: '+8.2%',
      ),
    ],
  ),
);

// Add Table section
pdfBuilder.addSection(
  PdfTableSection(
    order: 2,
    sectionTitle: 'Top Products',
    headers: [
      const PdfTableHeaderConfig(title: '#', flex: 1),
      const PdfTableHeaderConfig(title: 'Product', flex: 4),
      const PdfTableHeaderConfig(title: 'Qty', flex: 1, textAlign: pw.TextAlign.right),
    ],
    rows: [
      // Your table rows here
    ],
  ),
);

// Add Chart section
pdfBuilder.addSection(
  PdfChartSection(
    order: 3,
    sectionTitle: 'Sales Analytics',
    items: [
      PdfChartItem(
        columnSpan: PdfColumnSpan.col6,
        config: const PdfChartConfig(
          type: PdfChartType.barVertical,
          title: 'Monthly Sales',
          height: 180,
          dataPoints: [
            PdfChartDataPoint(label: 'Jan', value: 125430),
            PdfChartDataPoint(label: 'Feb', value: 98750),
            // ...
          ],
        ),
      ),
    ],
  ),
);

// Build and preview PDF
final result = await pdfBuilder.buildWithResult();
await Printing.layoutPdf(
  onLayout: (format) async => result.bytes,
  name: 'Report.pdf',
);

Platform-Specific Setup #

Android #

Add camera permission to android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.CAMERA" />

iOS #

Add camera usage description to ios/Runner/Info.plist:

<key>NSCameraUsageDescription</key>
<string>Camera access is required for barcode scanning</string>

Web #

For camera access on web, your app must be served over HTTPS in production. During development, localhost works without HTTPS.

Windows #

No special setup required. Note that camera-based barcode scanning is not available on Windows - use external USB barcode scanners with BarcodeKeyboardListenerWidget instead.

Known Limitations #

  1. Camera Scanner on Windows/macOS/Linux: The mobile_scanner package does not support desktop platforms. Use BarcodeKeyboardListenerWidget with external USB scanners.

  2. Web Camera: Requires HTTPS in production environments.

  3. External Scanner on Web: Works with USB scanners that emulate keyboard input. Some advanced scanner features (like Datalogic broadcast) are not available on web.

Dependencies #

This package uses the following dependencies:

Example #

Check the /example folder for a complete demo application showcasing all features.

cd example
flutter run

Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

License #

This project is licensed under the MIT License - see the LICENSE file for details.

Author #

PharmaGO Team

For questions or support, please open an issue on GitHub.

0
likes
110
points
48
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Reusable Flutter components for pharmacy applications. Provides cross-platform widgets for barcode scanning (camera and external USB readers) and comprehensive PDF generation with KPIs, tables, and charts.

Repository (GitHub)
View/report issues

Topics

#barcode #scanner #pdf #pharmacy #widget

License

MIT (license)

Dependencies

audioplayers, device_info_plus, flutter, flutter_web_plugins, gap, get, pdf, permission_handler, plugin_platform_interface, printing, shared_preferences, system_info_plus, web

More

Packages that depend on pharmago_packages

Packages that implement pharmago_packages