pharmago_packages 1.1.2
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 #
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_scannerpackage does not support Windows desktop. Use theBarcodeKeyboardListenerWidgetwith 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),
),
],
),
);
},
)
indexis the code's position in the current frame (0-based) andtotalis 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:
QrTrackerScanneris 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 #
-
Camera Scanner on Windows/macOS/Linux: The
mobile_scannerpackage does not support desktop platforms. UseBarcodeKeyboardListenerWidgetwith external USB scanners. -
Web Camera: Requires HTTPS in production environments.
-
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:
- mobile_scanner: Camera-based barcode scanning
- permission_handler: Camera permission handling
- audioplayers: Beep sound feedback
- shared_preferences: Local settings persistence
- device_info_plus: Device detection for performance optimization
- system_info_plus: RAM detection for adaptive settings
- pdf: PDF document generation
- printing: PDF preview and printing
- get: State management (optional)
- gap: UI spacing utilities
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.