flutter_zebra_scale 1.0.16
flutter_zebra_scale: ^1.0.16 copied to clipboard
Flutter plugin for Zebra Scale SDK
example/lib/main.dart
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter_zebra_scale/flutter_zebra_scale.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';
String _statusMessage = 'Ready';
bool _isInitialized = false;
bool _isConnected = false;
int? _connectedScannerId;
final TextEditingController _scannerIdController = TextEditingController();
final _flutterZebraScalePlugin = FlutterZebraScale();
// Scale state
bool _isScaleEnabled = false;
bool _isLiveWeightRunning = false;
String _weight = '';
String _weightMode = '';
String _weightStatus = '';
// Event state
StreamSubscription<Map<String, dynamic>>? _eventSubscription;
List<String> _eventLog = [];
String _lastBarcode = '';
String _lastBarcodeType = '';
// Scanner list state
List<Map<String, dynamic>> _availableScanners = [];
List<Map<String, dynamic>> _activeScanners = [];
bool _isLoadingScanners = false;
@override
void initState() {
super.initState();
initPlatformState();
_setupLiveWeightListener();
_setupEventListener();
}
@override
void dispose() {
_scannerIdController.dispose();
_eventSubscription?.cancel();
_flutterZebraScalePlugin.stopLiveWeight();
super.dispose();
}
void _setupLiveWeightListener() {
// Set up method channel to listen for live weight updates
const MethodChannel channel = MethodChannel('flutter_zebra_scale');
channel.setMethodCallHandler((call) async {
if (call.method == 'onLiveWeightUpdate') {
final data = call.arguments as Map<Object?, Object?>;
if (mounted) {
setState(() {
_weight = data['weight']?.toString() ?? '';
_weightMode = data['weightMode']?.toString() ?? '';
_weightStatus = data['statusText']?.toString() ?? '';
});
}
}
});
}
void _setupEventListener() {
_eventSubscription = _flutterZebraScalePlugin.getEventStream().listen(
(event) {
if (!mounted) return;
final eventType = event['eventType'] as String?;
// Safer extraction: platform may send Map<Object?, Object?>
Map<String, dynamic>? data;
final dataRaw = event['data'];
if (dataRaw is Map) {
try {
data = Map<String, dynamic>.from(
dataRaw.map((k, v) => MapEntry(k?.toString() ?? '', v)),
);
} catch (_) {
data = null;
}
}
setState(() {
// Add to event log (keep last 20 events)
_eventLog.insert(
0,
'[$eventType] ${DateTime.now().toString().substring(11, 19)}',
);
if (_eventLog.length > 20) {
_eventLog.removeLast();
}
// Handle specific events
switch (eventType) {
case 'barcode':
if (data != null) {
_lastBarcode = data['barcodeData']?.toString() ?? '';
_lastBarcodeType = data['barcodeType']?.toString() ?? '';
_statusMessage = 'Barcode scanned: $_lastBarcode';
} else {
_statusMessage = 'Barcode event received (data null)';
}
break;
case 'scannerAppeared':
if (data != null) {
final scannerName =
data['scannerName']?.toString() ?? 'Unknown';
_statusMessage = 'Scanner appeared: $scannerName';
// Auto-refresh scanner list when a new scanner appears
Future.delayed(const Duration(milliseconds: 500), () {
if (mounted) {
_refreshScannersList();
}
});
}
break;
case 'scannerDisappeared':
if (data != null) {
final scannerId = data['scannerID']?.toString() ?? 'Unknown';
_statusMessage = 'Scanner disappeared: $scannerId';
}
break;
case 'sessionEstablished':
if (data != null) {
final scannerName =
data['scannerName']?.toString() ?? 'Unknown';
_statusMessage = 'Connected to: $scannerName';
_isConnected = true;
_connectedScannerId = data['scannerID'] as int?;
}
break;
case 'sessionTerminated':
if (data != null) {
final scannerId = data['scannerID']?.toString() ?? 'Unknown';
_statusMessage = 'Disconnected from scanner: $scannerId';
_isConnected = false;
_connectedScannerId = null;
}
break;
}
});
},
onError: (error) {
if (mounted) {
setState(() {
_statusMessage = 'Event error: $error';
});
}
},
);
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
// We also handle the message potentially returning null.
try {
platformVersion =
await _flutterZebraScalePlugin.getPlatformVersion() ??
'Unknown platform version';
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
}
Future<void> _initializeSDK() async {
setState(() {
_statusMessage = 'Initializing SDK...';
});
try {
final success = await _flutterZebraScalePlugin.initialize();
if (mounted) {
setState(() {
_isInitialized = success;
if (success) {
_statusMessage = 'SDK initialized successfully';
// Enable scanner detection and Bluetooth discovery after initialization
_enableScannerDetection();
} else {
_statusMessage = 'Failed to initialize SDK';
}
});
}
} on PlatformException catch (e) {
if (mounted) {
setState(() {
_statusMessage = 'Error: ${e.message}';
});
}
} catch (e) {
if (mounted) {
setState(() {
_statusMessage = 'Error: $e';
});
}
}
}
Future<void> _enableScannerDetection() async {
try {
// Enable scanner detection
await _flutterZebraScalePlugin.enableScannersDetection(true);
// Enable Bluetooth scanner discovery
await _flutterZebraScalePlugin.enableBluetoothScannerDiscovery(true);
if (mounted) {
setState(() {
_statusMessage = 'Scanner detection enabled. Waiting for scanners...';
});
// Wait a bit for scanners to be discovered, then refresh the list
Future.delayed(const Duration(seconds: 2), () {
if (mounted) {
_loadAvailableScanners();
}
});
}
} catch (e) {
if (mounted) {
setState(() {
_statusMessage = 'Error enabling scanner detection: $e';
});
}
}
}
Future<void> _connectToScanner() async {
final scannerIdText = _scannerIdController.text.trim();
if (scannerIdText.isEmpty) {
setState(() {
_statusMessage = 'Please enter a scanner ID';
});
return;
}
final scannerId = int.tryParse(scannerIdText);
if (scannerId == null || scannerId <= 0) {
setState(() {
_statusMessage = 'Invalid scanner ID. Must be a positive number';
});
return;
}
setState(() {
_statusMessage = 'Connecting to scanner $scannerId...';
});
try {
final success = await _flutterZebraScalePlugin.connect(scannerId);
if (mounted) {
setState(() {
if (success) {
_isConnected = true;
_connectedScannerId = scannerId;
_statusMessage = 'Connected to scanner $scannerId';
} else {
_isConnected = false;
_connectedScannerId = null;
_statusMessage = 'Failed to connect to scanner $scannerId';
}
});
}
} on PlatformException catch (e) {
if (mounted) {
setState(() {
_isConnected = false;
_connectedScannerId = null;
_statusMessage = 'Error connecting: ${e.message}';
});
}
} catch (e) {
if (mounted) {
setState(() {
_isConnected = false;
_connectedScannerId = null;
_statusMessage = 'Error: $e';
});
}
}
}
Future<void> _disconnectFromScanner() async {
if (!_isConnected || _connectedScannerId == null) {
setState(() {
_statusMessage = 'No scanner connected';
});
return;
}
final scannerId = _connectedScannerId!;
setState(() {
_statusMessage = 'Disconnecting from scanner $scannerId...';
});
try {
// Stop live weight if running
if (_isLiveWeightRunning) {
await _flutterZebraScalePlugin.stopLiveWeight();
}
final success = await _flutterZebraScalePlugin.disconnect(scannerId);
if (mounted) {
setState(() {
_isConnected = false;
_connectedScannerId = null;
_isScaleEnabled = false;
_isLiveWeightRunning = false;
_weight = '';
_weightMode = '';
_weightStatus = '';
_statusMessage = success
? 'Disconnected from scanner $scannerId'
: 'Failed to disconnect from scanner $scannerId';
});
}
} on PlatformException catch (e) {
if (mounted) {
setState(() {
_statusMessage = 'Error disconnecting: ${e.message}';
});
}
} catch (e) {
if (mounted) {
setState(() {
_statusMessage = 'Error: $e';
});
}
}
}
Future<void> _enableScale() async {
if (!_isConnected || _connectedScannerId == null) {
setState(() {
_statusMessage = 'Please connect to a scanner first';
});
return;
}
setState(() {
_statusMessage = 'Enabling scale...';
});
try {
final success = await _flutterZebraScalePlugin.enableScale(
_connectedScannerId!,
);
if (mounted) {
setState(() {
_isScaleEnabled = success;
_statusMessage = success ? 'Scale enabled' : 'Failed to enable scale';
});
}
} catch (e) {
if (mounted) {
setState(() {
_statusMessage = 'Error: $e';
});
}
}
}
Future<void> _disableScale() async {
if (!_isConnected || _connectedScannerId == null) {
return;
}
// Stop live weight if running
if (_isLiveWeightRunning) {
await _flutterZebraScalePlugin.stopLiveWeight();
}
setState(() {
_statusMessage = 'Disabling scale...';
});
try {
final success = await _flutterZebraScalePlugin.disableScale(
_connectedScannerId!,
);
if (mounted) {
setState(() {
_isScaleEnabled = !success;
_isLiveWeightRunning = false;
_weight = '';
_weightMode = '';
_weightStatus = '';
_statusMessage = success
? 'Scale disabled'
: 'Failed to disable scale';
});
}
} catch (e) {
if (mounted) {
setState(() {
_statusMessage = 'Error: $e';
});
}
}
}
Future<void> _readWeight() async {
if (!_isConnected || _connectedScannerId == null) {
setState(() {
_statusMessage = 'Please connect to a scanner first';
});
return;
}
setState(() {
_statusMessage = 'Reading weight...';
});
try {
final weightData = await _flutterZebraScalePlugin.readWeight(
_connectedScannerId!,
);
if (mounted) {
setState(() {
if (weightData != null) {
_weight = weightData['weight']?.toString() ?? '';
_weightMode = weightData['weightMode']?.toString() ?? '';
_weightStatus = weightData['statusText']?.toString() ?? '';
_statusMessage = 'Weight read successfully';
} else {
_statusMessage = 'Failed to read weight';
}
});
}
} catch (e) {
if (mounted) {
setState(() {
_statusMessage = 'Error: $e';
});
}
}
}
Future<void> _zeroScale() async {
if (!_isConnected || _connectedScannerId == null) {
setState(() {
_statusMessage = 'Please connect to a scanner first';
});
return;
}
setState(() {
_statusMessage = 'Zeroing scale...';
});
try {
final success = await _flutterZebraScalePlugin.zeroScale(
_connectedScannerId!,
);
if (mounted) {
setState(() {
_statusMessage = success ? 'Scale zeroed' : 'Failed to zero scale';
});
}
} catch (e) {
if (mounted) {
setState(() {
_statusMessage = 'Error: $e';
});
}
}
}
Future<void> _resetScale() async {
if (!_isConnected || _connectedScannerId == null) {
setState(() {
_statusMessage = 'Please connect to a scanner first';
});
return;
}
setState(() {
_statusMessage = 'Resetting scale...';
});
try {
final success = await _flutterZebraScalePlugin.resetScale(
_connectedScannerId!,
);
if (mounted) {
setState(() {
_statusMessage = success ? 'Scale reset' : 'Failed to reset scale';
});
}
} catch (e) {
if (mounted) {
setState(() {
_statusMessage = 'Error: $e';
});
}
}
}
Future<void> _startLiveWeight() async {
if (!_isConnected || _connectedScannerId == null) {
setState(() {
_statusMessage = 'Please connect to a scanner first';
});
return;
}
setState(() {
_statusMessage = 'Starting live weight...';
});
try {
final success = await _flutterZebraScalePlugin.startLiveWeight(
_connectedScannerId!,
);
if (mounted) {
setState(() {
_isLiveWeightRunning = success;
_statusMessage = success
? 'Live weight started'
: 'Failed to start live weight';
});
}
} catch (e) {
if (mounted) {
setState(() {
_statusMessage = 'Error: $e';
});
}
}
}
Future<void> _stopLiveWeight() async {
setState(() {
_statusMessage = 'Stopping live weight...';
});
try {
final success = await _flutterZebraScalePlugin.stopLiveWeight();
if (mounted) {
setState(() {
_isLiveWeightRunning = !success;
_statusMessage = success
? 'Live weight stopped'
: 'Failed to stop live weight';
});
}
} catch (e) {
if (mounted) {
setState(() {
_statusMessage = 'Error: $e';
});
}
}
}
Future<void> _loadAvailableScanners() async {
setState(() {
_isLoadingScanners = true;
_statusMessage = 'Loading available scanners...';
});
try {
final result = await _flutterZebraScalePlugin.getAvailableScanners();
if (mounted) {
setState(() {
_availableScanners =
(result['scanners'] as List?)
?.map((s) => Map<String, dynamic>.from(s as Map))
.toList() ??
[];
_isLoadingScanners = false;
_statusMessage = 'Found ${result['count']} available scanner(s)';
});
}
} catch (e) {
if (mounted) {
setState(() {
_isLoadingScanners = false;
_statusMessage = 'Error loading scanners: $e';
});
}
}
}
Future<void> _loadActiveScanners() async {
setState(() {
_isLoadingScanners = true;
_statusMessage = 'Loading active scanners...';
});
try {
final result = await _flutterZebraScalePlugin.getActiveScanners();
if (mounted) {
setState(() {
_activeScanners =
(result['scanners'] as List?)
?.map((s) => Map<String, dynamic>.from(s as Map))
.toList() ??
[];
_isLoadingScanners = false;
_statusMessage = 'Found ${result['count']} active scanner(s)';
});
}
} catch (e) {
if (mounted) {
setState(() {
_isLoadingScanners = false;
_statusMessage = 'Error loading active scanners: $e';
});
}
}
}
Future<void> _refreshScannersList() async {
setState(() {
_isLoadingScanners = true;
_statusMessage = 'Refreshing scanner list...';
});
try {
// Use updateScannersList which gets both available and active scanners
final result = await _flutterZebraScalePlugin.updateScannersList();
if (mounted) {
final allScanners =
(result['scanners'] as List?)
?.map((s) => Map<String, dynamic>.from(s as Map))
.toList() ??
[];
// Separate into available and active
_availableScanners = allScanners
.where((s) => s['isActive'] != true)
.toList();
_activeScanners = allScanners
.where((s) => s['isActive'] == true)
.toList();
setState(() {
_isLoadingScanners = false;
_statusMessage =
'Found ${result['count']} scanner(s) (${_availableScanners.length} available, ${_activeScanners.length} active)';
});
}
} catch (e) {
if (mounted) {
setState(() {
_isLoadingScanners = false;
_statusMessage = 'Error refreshing scanner list: $e';
});
}
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Zebra Scanner Example'),
backgroundColor: Colors.blue,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Platform Version Card
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Platform Info',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text('Running on: $_platformVersion'),
],
),
),
),
const SizedBox(height: 16),
// Status Card
Card(
color: _isConnected
? Colors.green.shade50
: Colors.grey.shade100,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
_isConnected ? Icons.check_circle : Icons.info,
color: _isConnected ? Colors.green : Colors.grey,
),
const SizedBox(width: 8),
const Text(
'Status',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 8),
Text(_statusMessage),
if (_isInitialized)
Padding(
padding: const EdgeInsets.only(top: 4.0),
child: Row(
children: [
Icon(Icons.check, size: 16, color: Colors.green),
const SizedBox(width: 4),
const Text(
'SDK Initialized',
style: TextStyle(
fontSize: 12,
color: Colors.green,
),
),
],
),
),
if (_isConnected && _connectedScannerId != null)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
'Connected Scanner ID: $_connectedScannerId',
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.green,
),
),
),
],
),
),
),
const SizedBox(height: 16),
// Initialize Button
ElevatedButton.icon(
onPressed: _initializeSDK,
icon: const Icon(Icons.settings),
label: const Text('Initialize SDK'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
),
),
const SizedBox(height: 16),
// Scanner List Section
const Divider(),
const SizedBox(height: 8),
const Text(
'Scanner Discovery',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
// Scanner List Buttons
Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: _isLoadingScanners
? null
: _loadAvailableScanners,
icon: _isLoadingScanners
? const SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.search),
label: const Text('Available Scanners'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 12),
),
),
),
const SizedBox(width: 8),
Expanded(
child: ElevatedButton.icon(
onPressed: _isLoadingScanners
? null
: _loadActiveScanners,
icon: _isLoadingScanners
? const SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.link),
label: const Text('Active Scanners'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 12),
backgroundColor: Colors.green,
foregroundColor: Colors.white,
),
),
),
],
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: _isLoadingScanners ? null : _refreshScannersList,
icon: _isLoadingScanners
? const SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.refresh),
label: const Text('Refresh Scanner List'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 12),
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
),
),
const SizedBox(height: 16),
// Available Scanners List
if (_availableScanners.isNotEmpty) ...[
Text(
'Available Scanners (${_availableScanners.length})',
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
..._availableScanners.map((scanner) {
return Card(
margin: const EdgeInsets.only(bottom: 8),
child: ListTile(
leading: Icon(
scanner['isActive'] == true
? Icons.check_circle
: Icons.radio_button_unchecked,
color: scanner['isActive'] == true
? Colors.green
: Colors.grey,
),
title: Text(
scanner['scannerName']?.toString() ?? 'Unknown',
style: const TextStyle(fontWeight: FontWeight.bold),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('ID: ${scanner['scannerID']}'),
Text(
'Type: ${scanner['connectionTypeName'] ?? 'Unknown'}',
),
if (scanner['scannerModel']?.toString().isNotEmpty ==
true)
Text('Model: ${scanner['scannerModel']}'),
if (scanner['scannerSerialNumber']
?.toString()
.isNotEmpty ==
true)
Text('Serial: ${scanner['scannerSerialNumber']}'),
],
),
trailing: scanner['isActive'] == true
? const Chip(
label: Text('Active'),
backgroundColor: Colors.green,
labelStyle: TextStyle(color: Colors.white),
)
: ElevatedButton(
onPressed: () {
final scannerId = scanner['scannerID'] as int?;
if (scannerId != null) {
_scannerIdController.text = scannerId
.toString();
_connectToScanner();
}
},
child: const Text('Connect'),
),
),
);
}),
const SizedBox(height: 16),
],
// Active Scanners List
if (_activeScanners.isNotEmpty) ...[
Text(
'Active Scanners (${_activeScanners.length})',
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
..._activeScanners.map((scanner) {
return Card(
margin: const EdgeInsets.only(bottom: 8),
color: Colors.green.shade50,
child: ListTile(
leading: const Icon(
Icons.check_circle,
color: Colors.green,
),
title: Text(
scanner['scannerName']?.toString() ?? 'Unknown',
style: const TextStyle(fontWeight: FontWeight.bold),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('ID: ${scanner['scannerID']}'),
Text(
'Type: ${scanner['connectionTypeName'] ?? 'Unknown'}',
),
if (scanner['scannerModel']?.toString().isNotEmpty ==
true)
Text('Model: ${scanner['scannerModel']}'),
if (scanner['scannerSerialNumber']
?.toString()
.isNotEmpty ==
true)
Text('Serial: ${scanner['scannerSerialNumber']}'),
],
),
trailing: const Chip(
label: Text('Connected'),
backgroundColor: Colors.green,
labelStyle: TextStyle(color: Colors.white),
),
),
);
}),
const SizedBox(height: 16),
],
// Scanner ID Input
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Scanner ID',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
TextField(
controller: _scannerIdController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
hintText: 'Enter scanner ID (e.g., 123)',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.scanner),
),
),
],
),
),
),
const SizedBox(height: 16),
// Connect Button
ElevatedButton.icon(
onPressed: _isConnected ? null : _connectToScanner,
icon: const Icon(Icons.link),
label: const Text('Connect'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
backgroundColor: Colors.green,
foregroundColor: Colors.white,
),
),
const SizedBox(height: 8),
// Disconnect Button
ElevatedButton.icon(
onPressed: _isConnected ? _disconnectFromScanner : null,
icon: const Icon(Icons.link_off),
label: const Text('Disconnect'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
backgroundColor: Colors.red,
foregroundColor: Colors.white,
),
),
const SizedBox(height: 24),
// Barcode Section
const Divider(),
const SizedBox(height: 8),
const Text(
'Barcode Scanner',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
// Last Barcode Card
if (_lastBarcode.isNotEmpty)
Card(
color: Colors.green.shade50,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Row(
children: [
Icon(Icons.qr_code_scanner, color: Colors.green),
SizedBox(width: 8),
Text(
'Last Scanned Barcode',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 12),
Text(
_lastBarcode,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.green,
),
),
if (_lastBarcodeType.isNotEmpty) ...[
const SizedBox(height: 8),
Text(
'Type: $_lastBarcodeType',
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
),
),
],
],
),
),
)
else
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
const Icon(Icons.qr_code_scanner, color: Colors.grey),
const SizedBox(width: 8),
Text(
_isConnected
? 'Scan a barcode to see it here'
: 'Connect to scanner to scan barcodes',
style: const TextStyle(color: Colors.grey),
),
],
),
),
),
const SizedBox(height: 16),
// Event Log Section
const Text(
'Event Log',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Card(
child: Container(
height: 150,
padding: const EdgeInsets.all(8.0),
child: _eventLog.isEmpty
? const Center(
child: Text(
'No events yet',
style: TextStyle(color: Colors.grey),
),
)
: ListView.builder(
itemCount: _eventLog.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.symmetric(
vertical: 2.0,
),
child: Text(
_eventLog[index],
style: const TextStyle(
fontSize: 12,
fontFamily: 'monospace',
),
),
);
},
),
),
),
const SizedBox(height: 24),
// Scale Section
if (_isConnected) ...[
const Divider(),
const SizedBox(height: 8),
const Text(
'Scale Controls',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
// Enable/Disable Scale Toggle
Card(
child: SwitchListTile(
title: const Text('Enable Scale'),
subtitle: Text(
_isScaleEnabled
? 'Scale is enabled'
: 'Scale is disabled',
),
value: _isScaleEnabled,
onChanged: _isConnected
? (value) {
if (value) {
_enableScale();
} else {
_disableScale();
}
}
: null,
),
),
const SizedBox(height: 16),
// Weight Display Card
if (_weight.isNotEmpty || _weightStatus.isNotEmpty)
Card(
color: Colors.blue.shade50,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Weight Reading',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 12),
if (_weight.isNotEmpty)
Row(
children: [
Text(
_weight,
style: const TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
if (_weightMode.isNotEmpty) ...[
const SizedBox(width: 8),
Text(
_weightMode,
style: const TextStyle(
fontSize: 20,
color: Colors.grey,
),
),
],
],
),
if (_weightStatus.isNotEmpty) ...[
const SizedBox(height: 8),
Text(
'Status: $_weightStatus',
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
),
),
],
],
),
),
),
const SizedBox(height: 16),
// Scale Control Buttons
Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: _isScaleEnabled && !_isLiveWeightRunning
? _readWeight
: null,
icon: const Icon(Icons.scale),
label: const Text('Read Weight'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 12),
),
),
),
const SizedBox(width: 8),
Expanded(
child: ElevatedButton.icon(
onPressed: _isScaleEnabled
? (_isLiveWeightRunning
? _stopLiveWeight
: _startLiveWeight)
: null,
icon: Icon(
_isLiveWeightRunning ? Icons.stop : Icons.play_arrow,
),
label: Text(
_isLiveWeightRunning ? 'Stop Live' : 'Live Weight',
),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 12),
backgroundColor: _isLiveWeightRunning
? Colors.orange
: Colors.green,
foregroundColor: Colors.white,
),
),
),
],
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: _isScaleEnabled ? _zeroScale : null,
icon: const Icon(Icons.exposure_zero),
label: const Text('Zero Scale'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 12),
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
),
),
),
const SizedBox(width: 8),
Expanded(
child: ElevatedButton.icon(
onPressed: _isScaleEnabled ? _resetScale : null,
icon: const Icon(Icons.refresh),
label: const Text('Reset Scale'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 12),
backgroundColor: Colors.purple,
foregroundColor: Colors.white,
),
),
),
],
),
],
],
),
),
),
);
}
}