zebra_tc 1.0.0 copy "zebra_tc: ^1.0.0" to clipboard
zebra_tc: ^1.0.0 copied to clipboard

PlatformAndroid

Flutter plugin for Zebra TC series built-in barcode scanner via DataWedge.

example/lib/main.dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:zebra_tc/zebra_tc.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Zebra TC Example',
      theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepOrange), useMaterial3: true),
      home: const ScannerScreen(),
    );
  }
}

class ScannerScreen extends StatefulWidget {
  const ScannerScreen({super.key});

  @override
  State<ScannerScreen> createState() => _ScannerScreenState();
}

class _ScannerScreenState extends State<ScannerScreen> {
  final _zebra = ZebraTc();
  final List<ZebraScan> _scans = [];
  StreamSubscription<ZebraScan>? _subscription;
  bool _isListening = false;
  bool _flashOn = true;
  String? _statusMessage;

  @override
  void initState() {
    super.initState();
    _init();
  }

  @override
  void dispose() {
    _subscription?.cancel();
    super.dispose();
  }

  Future<void> _init() async {
    try {
      await _zebra.createProfile('ZebraTcExample');
      _setStatus('Profile created. Tap "Listen" to start scanning.');
    } catch (e) {
      _setStatus('Init error: $e');
    }
  }

  void _startListening() {
    _subscription = _zebra.scanStream.listen((scan) {
      setState(() => _scans.insert(0, scan));
    }, onError: (e) => _setStatus('Stream error: $e'));
    setState(() => _isListening = true);
    _setStatus('Listening for scans…');
  }

  Future<void> _stopListening() async {
    await _subscription?.cancel();
    _subscription = null;
    setState(() => _isListening = false);
    _setStatus('Stopped listening.');
  }

  Future<void> _toggleFlash() async {
    final next = !_flashOn;
    await _zebra.setFlash(enabled: next);
    setState(() => _flashOn = next);
  }

  void _clearScans() => setState(() => _scans.clear());

  void _setStatus(String msg) => setState(() => _statusMessage = msg);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Zebra TC Scanner'),
        actions: [
          if (_scans.isNotEmpty)
            IconButton(icon: const Icon(Icons.clear_all), tooltip: 'Clear results', onPressed: _clearScans),
        ],
      ),
      body: Column(
        children: [
          _ControlPanel(
            isListening: _isListening,
            flashOn: _flashOn,
            onToggleListen: _isListening ? _stopListening : _startListening,
            onSoftScanStart: () => _zebra.startScan(),
            onSoftScanStop: () => _zebra.stopScan(),
            onToggleFlash: _toggleFlash,
          ),
          if (_statusMessage != null) _StatusBanner(message: _statusMessage!),
          Expanded(
            child: _scans.isEmpty
                ? const _EmptyState()
                : ListView.separated(
                    padding: const EdgeInsets.symmetric(vertical: 8),
                    itemCount: _scans.length,
                    separatorBuilder: (_, __) => const Divider(height: 1),
                    itemBuilder: (_, i) => _ScanTile(scan: _scans[i], index: _scans.length - i),
                  ),
          ),
        ],
      ),
    );
  }
}

class _ControlPanel extends StatelessWidget {
  const _ControlPanel({
    required this.isListening,
    required this.flashOn,
    required this.onToggleListen,
    required this.onSoftScanStart,
    required this.onSoftScanStop,
    required this.onToggleFlash,
  });

  final bool isListening;
  final bool flashOn;
  final VoidCallback onToggleListen;
  final VoidCallback onSoftScanStart;
  final VoidCallback onSoftScanStop;
  final VoidCallback onToggleFlash;

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.all(12),
      child: Padding(
        padding: const EdgeInsets.all(12),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            FilledButton.icon(
              icon: Icon(isListening ? Icons.stop : Icons.play_arrow),
              label: Text(isListening ? 'Stop Listening' : 'Start Listening'),
              style: isListening ? FilledButton.styleFrom(backgroundColor: Colors.red) : null,
              onPressed: onToggleListen,
            ),
            const SizedBox(height: 8),
            Row(
              children: [
                Expanded(
                  child: OutlinedButton.icon(
                    icon: const Icon(Icons.qr_code_scanner),
                    label: const Text('Soft Scan'),
                    onPressed: onSoftScanStart,
                  ),
                ),
                const SizedBox(width: 8),
                Expanded(
                  child: OutlinedButton.icon(
                    icon: const Icon(Icons.stop_circle_outlined),
                    label: const Text('Stop Scan'),
                    onPressed: onSoftScanStop,
                  ),
                ),
                const SizedBox(width: 8),
                IconButton.outlined(
                  icon: Icon(flashOn ? Icons.flash_on : Icons.flash_off),
                  tooltip: flashOn ? 'Flash off' : 'Flash on',
                  onPressed: onToggleFlash,
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

class _StatusBanner extends StatelessWidget {
  const _StatusBanner({required this.message});

  final String message;

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      color: Theme.of(context).colorScheme.surfaceContainerHighest,
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
      child: Text(message, style: Theme.of(context).textTheme.bodySmall),
    );
  }
}

class _EmptyState extends StatelessWidget {
  const _EmptyState();

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(Icons.barcode_reader, size: 64, color: Colors.grey.shade400),
          const SizedBox(height: 12),
          Text('No scans yet', style: Theme.of(context).textTheme.titleMedium?.copyWith(color: Colors.grey)),
          const SizedBox(height: 4),
          Text(
            'Tap "Start Listening", then scan a barcode',
            style: Theme.of(context).textTheme.bodySmall?.copyWith(color: Colors.grey),
          ),
        ],
      ),
    );
  }
}

class _ScanTile extends StatelessWidget {
  const _ScanTile({required this.scan, required this.index});

  final ZebraScan scan;
  final int index;

  @override
  Widget build(BuildContext context) {
    return ListTile(
      leading: CircleAvatar(
        backgroundColor: Theme.of(context).colorScheme.primaryContainer,
        child: Text('$index', style: TextStyle(color: Theme.of(context).colorScheme.onPrimaryContainer, fontSize: 12)),
      ),
      title: Text(scan.barcode, style: const TextStyle(fontFamily: 'monospace', fontSize: 15)),
      subtitle: Text(scan.symbology.isEmpty ? '—' : scan.symbology),
      trailing: const Icon(Icons.check_circle, color: Colors.green, size: 18),
    );
  }
}
1
likes
160
points
15
downloads

Publisher

unverified uploader

Weekly Downloads

Flutter plugin for Zebra TC series built-in barcode scanner via DataWedge.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on zebra_tc

Packages that implement zebra_tc