flutter_bt_print 0.0.1 copy "flutter_bt_print: ^0.0.1" to clipboard
flutter_bt_print: ^0.0.1 copied to clipboard

Bluetooth thermal printing plugin for Flutter supporting ESC/POS printers, image and PDF printing.

example/lib/main.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bt_print/flutter_bt_print.dart';
import 'package:permission_handler/permission_handler.dart';
import 'bluetooth_controller.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

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

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

class _MyAppState extends State<MyApp> {
  final BluetoothController bt = BluetoothController();
  BluetoothDevice? _selected;

  @override
  void initState() {
    super.initState();
    _initBluetooth();
    bt.status$.listen((status) {
      if (!mounted) return;
      String msg = "";
      if (status == BTStatus.connecting) msg = "Establishing connection...";
      if (status == BTStatus.connected) msg = "Printer connected successfully!";
      if (status == BTStatus.disconnected) msg = "Printer disconnected.";
      if (status == BTStatus.error) msg = "Connection failed. Check printer.";
      if (msg.isNotEmpty) {
        PremiumToast.show(context, msg, status);
      }
    });
  }

  Future<void> _initBluetooth() async {
    final granted = await _requestPermissions();
    if (!granted) return;
    await bt.loadDevices();
    await bt.syncConnection();
  }

  Future<bool> _requestPermissions() async {
    final statuses = await [
      Permission.bluetooth,
      Permission.bluetoothScan,
      Permission.bluetoothConnect,
      Permission.location,
    ].request();
    return statuses.values.every((e) => e.isGranted);
  }

  @override
  void dispose() {
    bt.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(),
      home: Scaffold(
        backgroundColor: const Color(0xFFF5F7FA),
        appBar: AppBar(
          toolbarHeight: 65,
          title: Column(
            children: [
              const Text("flutter_bt_print",
                style: TextStyle(fontWeight: FontWeight.w900, fontSize: 18),
              ),
              Text(bt.systemOS, style: TextStyle(fontSize: 12)),
            ],
          ),
          centerTitle: true,
          elevation: 0,
          backgroundColor: Colors.white,
          foregroundColor: Colors.black,
        ),
        body: Stack(
          children: [
            SingleChildScrollView(
              padding: const EdgeInsets.all(20),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  _buildSectionHeader("Available Printers", Icons.bluetooth),
                  const SizedBox(height: 12),
                  _buildDeviceSelector(),
                  const SizedBox(height: 24),
                  _buildSectionHeader("Connection Status", Icons.settings_input_component),
                  const SizedBox(height: 12),
                  _buildConnectionCard(),
                  const SizedBox(height: 24),
                  _buildSectionHeader("Actions", Icons.print_rounded),
                  const SizedBox(height: 12),
                  _buildPrintActionCard(),
                ],
              ),
            ),
            StreamBuilder<BTStatus>(
              stream: bt.status$,
              builder: (context, snapshot) {
                final status = snapshot.data;
                if (status == BTStatus.connecting) {
                  return Center(
                    child: CupertinoActivityIndicator(color: CupertinoColors.activeBlue),
                  );
                }
                return const SizedBox.shrink();
              },
            ),
          ],
        ),
      ),
    );
  }

  void printText() async {
    return bt.printText(
      "================================\n"
      "        MY PROFILE\n"
      "================================\n\n"
      "Name   : Rahman\n"
      "Role   : Full Stack Developer\n"
      "Phone  : +91 8052399848\n"
      "Email  : rahman.infodev@gmail.com\n\n"
      "--------------------------------\n"
      "SKILLS\n"
      "--------------------------------\n"
      "• Flutter / Dart\n"
      "• Android (Java / Kotlin)\n"
      "• REST APIs\n"
      "• Firebase / AWS\n\n"
      "--------------------------------\n"
      "EXPERIENCE\n"
      "--------------------------------\n"
      "• 4+ Years Mobile Development\n"
      "• Production Apps Published\n\n"
      "--------------------------------\n"
      "PRINT INFO\n"
      "--------------------------------\n"
      "Date : 30 Jan 2026\n"
      "Time : 10:55 AM\n\n"
      "================================\n"
      "        THANK YOU 🙏\n"
      "================================\n\n\n",
    );
  }

  Widget _buildSectionHeader(String title, IconData icon) {
    return Row(
      children: [
        Icon(icon, size: 18, color: Colors.blueGrey),
        const SizedBox(width: 8),
        Text(title.toUpperCase(),
          style: const TextStyle(fontSize: 13,
            fontWeight: FontWeight.w800, color: Colors.blueGrey,
            letterSpacing: 1.2,
          ),
        ),
      ],
    );
  }

  Widget _buildDeviceSelector() {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(15),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withValues(alpha: 0.05),
            blurRadius: 10,
          ),
        ],
      ),
      child: StreamBuilder<List<BluetoothDevice>>(
        stream: bt.devices$,
        builder: (context, snapshot) {
          final devices = snapshot.data ?? [];
          BluetoothDevice? currentSelection;
          try {
            currentSelection = devices.firstWhere((d) => d.address == _selected?.address);
          } catch (_) {
            currentSelection = null;
          }
          return DropdownButtonHideUnderline(
            child: DropdownButton<BluetoothDevice>(
              isExpanded: true,
              value: currentSelection,
              hint: const Text("Select a paired printer"),
              items: devices.map((data) {
                return DropdownMenuItem<BluetoothDevice>(
                  value: data,
                  child: Row(
                    children: [
                      Icon(Icons.print_rounded, size: 18,
                        color: data.isConnected ? Colors.green : Colors.grey,
                      ),
                      const SizedBox(width: 10),
                      Text(data.name,
                        style: const TextStyle(fontWeight: FontWeight.w500),
                      ),
                    ],
                  ),
                );
              }).toList(),
              onChanged: (d) {
                setState(() => _selected = d);
              },
            ),
          );
        },
      ),
    );
  }

  Widget _buildConnectionCard() {
    return StreamBuilder<bool>(
      stream: bt.isConnected$,
      builder: (context, snapshot) {
        final connected = snapshot.data ?? false;
        return Container(
          padding: const EdgeInsets.all(20),
          decoration: BoxDecoration(
            gradient: connected
                ? LinearGradient(colors: [Colors.green.shade600, Colors.green.shade400])
                : const LinearGradient(colors: [Colors.white, Colors.white]),
            borderRadius: BorderRadius.circular(20),
            boxShadow: [
              BoxShadow(
                color: Colors.black.withValues(alpha: 0.05),
                blurRadius: 10,
              ),
            ],
          ),
          child: Column(
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Text(
                    connected ? "Connected" : "Disconnected",
                    style: TextStyle(fontSize: 18,
                      fontWeight: FontWeight.bold,
                      color: connected ? Colors.white : Colors.black87,
                    ),
                  ),
                  Icon(
                    connected ? Icons.check_circle : Icons.error_outline,
                    color: connected ? Colors.white : Colors.redAccent,
                  ),
                ],
              ),
              const SizedBox(height: 20),
              Row(
                children: [
                  Expanded(
                    child: _buildButton(
                      label: "Connect",
                      icon: Icons.link,
                      color: connected
                          ? Colors.white.withValues(alpha: 0.2)
                          : Colors.blue,
                      textColor: connected ? Colors.white : Colors.white,
                      onPressed: connected
                          ? null
                          : () {
                              if (_selected == null) {
                                PremiumToast.show(context, "Select a printer first", BTStatus.error);
                                return;
                              }
                              bt.connect(_selected!.address);
                            },
                    ),
                  ),
                  const SizedBox(width: 12),
                  Expanded(
                    child: _buildButton(
                      label: "Disconnect",
                      icon: Icons.link_off,
                      color: connected ? Colors.white.withValues(alpha: 0.3) : Colors.grey.shade200,
                      textColor: connected ? Colors.white : Colors.black54,
                      onPressed: connected ? bt.disconnect : null,
                    ),
                  ),
                ],
              ),
            ],
          ),
        );
      },
    );
  }

  Widget _buildPrintActionCard() {
    return StreamBuilder<bool>(
      stream: bt.isConnected$,
      builder: (context, snapshot) {
        final connected = snapshot.data ?? false;
        return Card(
          elevation: 0,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(20),
          ),
          child: Padding(
            padding: const EdgeInsets.all(20),
            child: Column(
              children: [
                const Text("Ready to print receipts and labels using thermal technology.",
                  textAlign: TextAlign.center,
                  style: TextStyle(color: Colors.grey),
                ),
                const SizedBox(height: 20),
                SizedBox(
                  width: double.infinity,
                  height: 55,
                  child: ElevatedButton.icon(
                    style: ElevatedButton.styleFrom(
                      backgroundColor: connected ? Colors.black87 : Colors.grey.shade300,
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(15),
                      ),
                    ),

                    /// BYTES PRINT FOR TEST PURPOSE
                    onPressed: connected ? () => bt.selectPdfAndPrint() : null,

                    /// TEXT PRINT FOR TEST PURPOSE
                    // onPressed: connected ? () => printText() : null,
                    icon: const Icon(Icons.print, color: Colors.white),
                    label: const Text("PRINT TEST RECEIPT",
                      style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
                    ),
                  ),
                ),
              ],
            ),
          ),
        );
      },
    );
  }

  Widget _buildButton({
    required String label, required IconData icon,
    required Color color, required Color textColor, VoidCallback? onPressed }) {
    return SizedBox(
      height: 50,
      child: TextButton.icon(
        style: TextButton.styleFrom(
          backgroundColor: color,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(12),
          ),
        ),
        onPressed: onPressed,
        icon: Icon(icon, color: textColor, size: 20),
        label: Text(
          label,
          style: TextStyle(color: textColor, fontWeight: FontWeight.bold),
        ),
      ),
    );
  }
}

class PremiumToast {
  static void show(BuildContext context, String message, BTStatus status) {
    Color bgColor;
    IconData icon;

    switch (status) {
      case BTStatus.connected:
        bgColor = const Color(0xFF2E7D32);
        icon = Icons.check_circle_outline;
        break;
      case BTStatus.disconnected:
        bgColor = const Color(0xFFC62828);
        icon = Icons.link_off;
        break;
      case BTStatus.connecting:
        bgColor = const Color(0xFF1565C0);
        icon = Icons.sync;
        break;
      case BTStatus.error:
        bgColor = Colors.orange.shade900;
        icon = Icons.warning_amber_rounded;
        break;
      default:
        bgColor = Colors.black87;
        icon = Icons.info_outline;
    }

    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        elevation: 0,
        behavior: SnackBarBehavior.floating,
        backgroundColor: Colors.transparent,
        content: Container(
          padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
          decoration: BoxDecoration(
            color: bgColor,
            borderRadius: BorderRadius.circular(20),
            boxShadow: [
              BoxShadow(
                color: bgColor.withValues(alpha: 0.4),
                blurRadius: 12,
                offset: const Offset(0, 4),
              ),
            ],
          ),
          child: Row(
            children: [
              Icon(icon, color: Colors.white, size: 28),
              const SizedBox(width: 12),
              Expanded(
                child: Text(
                  message,
                  style: const TextStyle(
                    color: Colors.white,
                    fontWeight: FontWeight.w600,
                    fontSize: 15,
                  ),
                ),
              ),
            ],
          ),
        ),
        duration: const Duration(seconds: 3),
      ),
    );
  }
}
0
likes
140
points
148
downloads

Publisher

unverified uploader

Weekly Downloads

Bluetooth thermal printing plugin for Flutter supporting ESC/POS printers, image and PDF printing.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter, pdf, plugin_platform_interface, printing

More

Packages that depend on flutter_bt_print

Packages that implement flutter_bt_print