import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:nfc_manager/nfc_manager.dart'; import 'package:nfc_manager/nfc_manager_android.dart' show NfcAAndroid, NfcBAndroid; import 'package:nfc_manager/nfc_manager_ios.dart' show MiFareIos, Iso15693Ios; import 'package:test_sa/dashboard_latest/dashboard_view.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/views/app_style/sizing.dart'; void showNfcReader(BuildContext context, {Function(String?)? onNcfScan}) { showModalBottomSheet( context: context, enableDrag: false, isDismissible: false, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.only(topLeft: Radius.circular(12), topRight: Radius.circular(12)), ), backgroundColor: Colors.white, builder: (context) { return NfcLayout( onNcfScan: onNcfScan, ); }, ); } class NfcLayout extends StatefulWidget { final Function(String? nfcId)? onNcfScan; const NfcLayout({super.key, required this.onNcfScan}); @override _NfcLayoutState createState() => _NfcLayoutState(); } class _NfcLayoutState extends State { bool _reading = false; Widget? mainWidget; String? nfcId; @override void initState() { super.initState(); _startNfcSession(); } @override void dispose() { // Ensure session is stopped when widget is disposed NfcManager.instance.stopSession().catchError((e) { print('Error stopping NFC session in dispose: $e'); }); super.dispose(); } void _startNfcSession() async { // Stop any existing session before starting a new one try { await NfcManager.instance.stopSession(); } catch (e) { print('No active session to stop: $e'); } NfcManager.instance.startSession( onDiscovered: (NfcTag tag) async { String? identifier; try { if (Platform.isAndroid) { // Try NfcA first (most common) final nfcA = NfcAAndroid.from(tag); if (nfcA != null) { identifier = nfcA.tag.id.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); } else { // Fallback to NfcB final nfcB = NfcBAndroid.from(tag); if (nfcB != null) { identifier = nfcB.tag.id.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); } } } else { // For iOS, try MiFare first final mifare = MiFareIos.from(tag); if (mifare != null) { identifier = mifare.identifier.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); } else { // Fallback to Iso15693 for iOS final iso15693 = Iso15693Ios.from(tag); if (iso15693 != null) { identifier = iso15693.identifier.map((e) => e.toRadixString(16).padLeft(2, '0')).join(''); } } } } catch (e) { print('Error reading NFC tag: $e'); } nfcId = identifier; if (!mounted) return; setState(() { _reading = true; mainWidget = doneNfc(); }); Future.delayed(const Duration(seconds: 1), () async { try { await NfcManager.instance.stopSession(); } catch (e) { print('Error stopping session: $e'); } if (mounted) { Navigator.pop(context); widget.onNcfScan!(nfcId!); } }); }, pollingOptions: {NfcPollingOption.iso14443}, ).catchError((err) { print('NFC session error: $err'); // Stop session on error NfcManager.instance.stopSession().catchError((e) { print('Error stopping session after error: $e'); }); }); } @override Widget build(BuildContext context) { (mainWidget == null && !_reading) ? mainWidget = scanNfc() : mainWidget = doneNfc(); return AnimatedSwitcher(duration: Duration(milliseconds: 500), child: mainWidget); } Widget scanNfc() { return Container( color: AppColor.background(context), key: ValueKey(1), child: Column( mainAxisSize: MainAxisSize.min, children: [ SizedBox( height: 30, ), Text( "Ready To Scan", style: TextStyle( fontWeight: FontWeight.bold, fontSize: 24, color:AppColor.headingTextColor(context) ), ), SizedBox( height: 30, ), Image.asset( "assets/images/ic_nfc.png", height: MediaQuery.of(context).size.width / 3, color: AppColor.iconColor(context), width: double.infinity, ), const SizedBox( height: 30, ), const Text( "Approach an NFC Tag", style: TextStyle( fontSize: 18, ), ), const SizedBox( height: 30, ), ButtonTheme( minWidth: MediaQuery.of(context).size.width / 1.2, height: 45.0, buttonColor: Colors.grey[300], shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(6), ), child: TextButton( onPressed: () async { try { await NfcManager.instance.stopSession(); } catch (e) { print('Error stopping NFC session: $e'); } if (mounted) { Navigator.pop(context); } }, // elevation: 0, child: const Text("CANCEL"), ), ), SizedBox( height: 30, ), ], ), ); } Widget doneNfc() { return Container( color: AppColor.background(context), key: ValueKey(2), child: Column( mainAxisSize: MainAxisSize.min, children: [ SizedBox( height: 30, ), Text( "Successfully Scanned", style: TextStyle( fontWeight: FontWeight.bold, fontSize: 24, color:AppColor.headingTextColor(context) ), ), SizedBox( height: 30, ), Image.asset( // "assets/icons/nfc/ic_done.png", "assets/images/ic_done.png", height: MediaQuery.of(context).size.width / 3, width: double.infinity, color: AppColor.iconColor(context), ), SizedBox( height: 30, ), Text( "Approach an NFC Tag", style: TextStyle( fontSize: 18, ), ), SizedBox( height: 30, ), ButtonTheme( minWidth: MediaQuery.of(context).size.width / 1.2, height: 45.0, buttonColor: Colors.grey[300], shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(6), ), child: TextButton( // onPressed: () { // _stream?.cancel(); // widget.onNcfScan(nfcId); // Navigator.pop(context); // }, onPressed: null, // elevation: 0, child: Text("DONE",style: TextStyle(color: context.isDark?AppColor.primary10:null),), ), ), SizedBox( height: 30, ), ], ), ); } }