Advertisement
Zuhairy_Harry

screen.dart(with qr)

Jun 13th, 2025
569
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Dart 39.31 KB | None | 0 0
  1. import 'package:einventorycomputer/modules/home/screen/location/location.dart';
  2. import 'package:einventorycomputer/services/auth.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:firebase_auth/firebase_auth.dart';
  5. import 'package:cloud_firestore/cloud_firestore.dart';
  6. import 'package:einventorycomputer/modules/home/screen/home.dart';
  7. import 'package:einventorycomputer/modules/home/screen/devices/inventory.dart';
  8. import 'package:einventorycomputer/modules/home/screen/settings/settings.dart';
  9. import 'package:einventorycomputer/modules/home/screen/user/account.dart';
  10. import 'package:einventorycomputer/modules/home/screen/devices/add_device.dart';
  11. import 'package:mobile_scanner/mobile_scanner.dart';
  12. import 'package:einventorycomputer/modules/home/screen/devices/device_details.dart';
  13.  
  14. class ScreenPage extends StatefulWidget {
  15.   @override
  16.   _ScreenPageState createState() => _ScreenPageState();
  17. }
  18.  
  19. class _ScreenPageState extends State<ScreenPage> with TickerProviderStateMixin {
  20.   final AuthService _auth = AuthService();
  21.   int _selectedIndex = 0;
  22.   String? _username;
  23.   String? _profileImageUrl;
  24.   late AnimationController _drawerAnimationController;
  25.   late AnimationController _fabAnimationController;
  26.  
  27.   final List<String> _titles = [
  28.     "Home",
  29.     "Inventory",
  30.     "Add Device",
  31.     "QR Scanner",
  32.     "Settings",
  33.     "Account",
  34.     "Location",
  35.   ];
  36.  
  37.   // Method to navigate to inventory page
  38.   void _navigateToInventory() {
  39.     setState(() {
  40.       _selectedIndex = 1; // Inventory page index
  41.     });
  42.   }
  43.  
  44.   // Define which indices are in the bottom navigation
  45.   final List<int> _bottomNavIndexes = [0, 1, 5, 6];
  46.  
  47.   @override
  48.   void initState() {
  49.     super.initState();
  50.     _loadUserData();
  51.     _drawerAnimationController = AnimationController(
  52.       duration: const Duration(milliseconds: 300),
  53.       vsync: this,
  54.     );
  55.     _fabAnimationController = AnimationController(
  56.       duration: const Duration(milliseconds: 300),
  57.       vsync: this,
  58.     );
  59.     _fabAnimationController.forward();
  60.   }
  61.  
  62.   @override
  63.   void dispose() {
  64.     _drawerAnimationController.dispose();
  65.     _fabAnimationController.dispose();
  66.     super.dispose();
  67.   }
  68.  
  69.   Future<void> _loadUserData() async {
  70.     final user = FirebaseAuth.instance.currentUser;
  71.     if (user != null) {
  72.       try {
  73.         final doc = await FirebaseFirestore.instance.collection('users').doc(user.uid).get();
  74.         if (doc.exists && mounted) {
  75.           final data = doc.data();
  76.           setState(() {
  77.             _username = data?['username'] ?? 'User';
  78.             _profileImageUrl = data?['profileImageUrl'];
  79.           });
  80.           print('Profile image URL: $_profileImageUrl');
  81.         }
  82.       } catch (e) {
  83.         print('Error loading user data: $e');
  84.       }
  85.     }
  86.   }
  87.  
  88.   void _onSelect(int index) {
  89.     if (_selectedIndex != index) {
  90.       setState(() {
  91.         _selectedIndex = index;
  92.       });
  93.       // Refresh user data when navigating to Account page
  94.       if (index == 5) { // Account page index (updated)
  95.         _loadUserData();
  96.       }
  97.     }
  98.     Navigator.pop(context); // Close drawer
  99.   }
  100.  
  101.   void _onFabPressed() {
  102.     // Add a small animation when pressed
  103.     _fabAnimationController.reverse().then((_) {
  104.       _fabAnimationController.forward();
  105.     });
  106.    
  107.     setState(() {
  108.       _selectedIndex = 2; // Navigate to Add Device page (index 2)
  109.     });
  110.   }
  111.  
  112.   // New method to handle QR scanner FAB press
  113.   void _onQRScannerPressed() {
  114.     _fabAnimationController.reverse().then((_) {
  115.       _fabAnimationController.forward();
  116.     });
  117.    
  118.     setState(() {
  119.       _selectedIndex = 3; // Navigate to QR Scanner page (index 3)
  120.     });
  121.   }
  122.  
  123.   Widget _buildProfileImage() {
  124.     return Container(
  125.       width: 80,
  126.       height: 80,
  127.       decoration: BoxDecoration(
  128.         borderRadius: BorderRadius.circular(20),
  129.         boxShadow: [
  130.           BoxShadow(
  131.             color: const Color(0xFFFFC727).withOpacity(0.3),
  132.             blurRadius: 12,
  133.             offset: const Offset(0, 4),
  134.           ),
  135.         ],
  136.       ),
  137.       child: ClipRRect(
  138.         borderRadius: BorderRadius.circular(20),
  139.         child: Container(
  140.           width: 80,
  141.           height: 80,
  142.           color: const Color(0xFFFFC727),
  143.           child: _profileImageUrl != null && _profileImageUrl!.isNotEmpty
  144.               ? Image.network(
  145.                   _profileImageUrl!,
  146.                   width: 80,
  147.                   height: 80,
  148.                   fit: BoxFit.cover,
  149.                   errorBuilder: (context, error, stackTrace) {
  150.                     print('Error loading image: $error');
  151.                     return const Icon(
  152.                       Icons.person_rounded,
  153.                       size: 40,
  154.                       color: Color(0xFF212529),
  155.                     );
  156.                   },
  157.                   loadingBuilder: (context, child, loadingProgress) {
  158.                     if (loadingProgress == null) return child;
  159.                     return const Center(
  160.                       child: CircularProgressIndicator(
  161.                         valueColor: AlwaysStoppedAnimation<Color>(Color(0xFF212529)),
  162.                         strokeWidth: 2,
  163.                       ),
  164.                     );
  165.                   },
  166.                 )
  167.               : const Icon(
  168.                   Icons.person_rounded,
  169.                   size: 40,
  170.                   color: Color(0xFF212529),
  171.                 ),
  172.         ),
  173.       ),
  174.     );
  175.   }
  176.  
  177.   Widget _getCurrentPage() {
  178.     switch (_selectedIndex) {
  179.       case 0:
  180.         return HomePage();
  181.       case 1:
  182.         return InventoryPage();
  183.       case 2:
  184.         return AddDevicePage(onNavigateToInventory: _navigateToInventory);
  185.       case 3:
  186.         return QRScannerPage();
  187.       case 4:
  188.         return SettingsPage();
  189.       case 5:
  190.         return AccountPage();
  191.       case 6:
  192.         return LocationPage();
  193.       default:
  194.         return HomePage();
  195.     }
  196.   }
  197.  
  198.   @override
  199.   Widget build(BuildContext context) {
  200.     final isBottomNavPage = _bottomNavIndexes.contains(_selectedIndex);
  201.     final safeCurrentIndex = _bottomNavIndexes.indexWhere((i) => i == _selectedIndex);
  202.     final isQRScannerPage = _selectedIndex == 3;
  203.  
  204.     return Scaffold(
  205.       backgroundColor: const Color(0xFFF8F9FA),
  206.       appBar: AppBar(
  207.         title: Text(
  208.           _titles[_selectedIndex],
  209.           style: const TextStyle(
  210.             fontFamily: 'SansRegular',
  211.             color: Color(0xFF212529),
  212.             fontWeight: FontWeight.w600,
  213.             fontSize: 20,
  214.           ),
  215.         ),
  216.         backgroundColor: Colors.transparent,
  217.         elevation: 0,
  218.         iconTheme: const IconThemeData(color: Color(0xFF212529)),
  219.         leading: Builder(
  220.           builder: (context) => IconButton(
  221.             icon: Container(
  222.               padding: const EdgeInsets.all(8),
  223.               decoration: BoxDecoration(
  224.                 color: Colors.white,
  225.                 borderRadius: BorderRadius.circular(12),
  226.                 boxShadow: [
  227.                   BoxShadow(
  228.                     color: Colors.black.withOpacity(0.1),
  229.                     blurRadius: 8,
  230.                     offset: const Offset(0, 2),
  231.                   ),
  232.                 ],
  233.               ),
  234.               child: const Icon(
  235.                 Icons.menu_rounded,
  236.                 color: Color(0xFF212529),
  237.                 size: 20,
  238.               ),
  239.             ),
  240.             onPressed: () => Scaffold.of(context).openDrawer(),
  241.           ),
  242.         ),
  243.       ),
  244.       drawer: Drawer(
  245.         backgroundColor: Colors.white,
  246.         elevation: 0,
  247.         child: SafeArea(
  248.           child: Column(
  249.             children: [
  250.               // Header Section
  251.               Container(
  252.                 width: double.infinity,
  253.                 padding: const EdgeInsets.all(24),
  254.                 decoration: const BoxDecoration(
  255.                   color: Color(0xFF212529),
  256.                   borderRadius: BorderRadius.only(
  257.                     bottomLeft: Radius.circular(24),
  258.                     bottomRight: Radius.circular(24),
  259.                   ),
  260.                 ),
  261.                 child: Column(
  262.                   children: [
  263.                     _buildProfileImage(),
  264.                     const SizedBox(height: 16),
  265.                     Text(
  266.                       _username ?? 'Loading...',
  267.                       style: const TextStyle(
  268.                         fontFamily: 'SansRegular',
  269.                         fontWeight: FontWeight.w600,
  270.                         fontSize: 18,
  271.                         color: Color(0xFFFFC727),
  272.                       ),
  273.                     ),
  274.                     const SizedBox(height: 4),
  275.                     Text(
  276.                       FirebaseAuth.instance.currentUser?.email ?? '',
  277.                       style: const TextStyle(
  278.                         fontFamily: 'SansRegular',
  279.                         fontSize: 14,
  280.                         color: Color(0xFFADB5BD),
  281.                       ),
  282.                       overflow: TextOverflow.ellipsis,
  283.                     ),
  284.                   ],
  285.                 ),
  286.               ),
  287.              
  288.               const SizedBox(height: 24),
  289.              
  290.               // Navigation Items
  291.               Expanded(
  292.                 child: Padding(
  293.                   padding: const EdgeInsets.symmetric(horizontal: 16),
  294.                   child: Column(
  295.                     children: [
  296.                       _buildDrawerItem(Icons.home_outlined, Icons.home_rounded, "Home", 0),
  297.                       _buildDrawerItem(Icons.inventory_2_outlined, Icons.inventory_2_rounded, "Inventory", 1),
  298.                       _buildDrawerItem(Icons.add_box_outlined, Icons.add_box_rounded, "Add Device", 2),
  299.                       _buildDrawerItem(Icons.qr_code_scanner_outlined, Icons.qr_code_scanner_rounded, "QR Scanner", 3),
  300.                       _buildDrawerItem(Icons.settings_outlined, Icons.settings_rounded, "Settings", 4),
  301.                       _buildDrawerItem(Icons.person_outline_rounded, Icons.person_rounded, "Account", 5),
  302.                       _buildDrawerItem(Icons.location_city_outlined, Icons.location_city_rounded, "Location", 6),
  303.                     ],
  304.                   ),
  305.                 ),
  306.               ),
  307.              
  308.               // Logout Section
  309.               Padding(
  310.                 padding: const EdgeInsets.all(24),
  311.                 child: Container(
  312.                   width: double.infinity,
  313.                   decoration: BoxDecoration(
  314.                     gradient: const LinearGradient(
  315.                       colors: [Color(0xFF212529), Color(0xFF343A40)],
  316.                       begin: Alignment.topLeft,
  317.                       end: Alignment.bottomRight,
  318.                     ),
  319.                     borderRadius: BorderRadius.circular(16),
  320.                     boxShadow: [
  321.                       BoxShadow(
  322.                         color: Colors.black.withOpacity(0.1),
  323.                         blurRadius: 12,
  324.                         offset: const Offset(0, 4),
  325.                       ),
  326.                     ],
  327.                   ),
  328.                   child: Material(
  329.                     color: Colors.transparent,
  330.                     child: InkWell(
  331.                       borderRadius: BorderRadius.circular(16),
  332.                       onTap: () async {
  333.                         await _auth.signOut();
  334.                       },
  335.                       child: Padding(
  336.                         padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 20),
  337.                         child: Row(
  338.                           mainAxisAlignment: MainAxisAlignment.center,
  339.                           children: [
  340.                             Container(
  341.                               padding: const EdgeInsets.all(8),
  342.                               decoration: BoxDecoration(
  343.                                 color: const Color(0xFFFFC727).withOpacity(0.2),
  344.                                 borderRadius: BorderRadius.circular(8),
  345.                               ),
  346.                               child: const Icon(
  347.                                 Icons.logout_rounded,
  348.                                 color: Color(0xFFFFC727),
  349.                                 size: 20,
  350.                               ),
  351.                             ),
  352.                             const SizedBox(width: 12),
  353.                             const Text(
  354.                               "Sign Out",
  355.                               style: TextStyle(
  356.                                 fontSize: 16,
  357.                                 fontWeight: FontWeight.w600,
  358.                                 color: Color(0xFFFFC727),
  359.                                 fontFamily: 'SansRegular',
  360.                               ),
  361.                             ),
  362.                           ],
  363.                         ),
  364.                       ),
  365.                     ),
  366.                   ),
  367.                 ),
  368.               ),
  369.             ],
  370.           ),
  371.         ),
  372.       ),
  373.       body: Stack(
  374.         children: [
  375.           _getCurrentPage(),
  376.           // Floating Action Buttons
  377.           if (isBottomNavPage)
  378.             Positioned(
  379.               bottom: 10,
  380.               right: 24,
  381.               child: Column(
  382.                 mainAxisSize: MainAxisSize.min,
  383.                 children: [
  384.                   // QR Scanner FAB
  385.                   ScaleTransition(
  386.                     scale: _fabAnimationController,
  387.                     child: Container(
  388.                       margin: const EdgeInsets.only(bottom: 16),
  389.                       decoration: BoxDecoration(
  390.                         gradient: const LinearGradient(
  391.                           colors: [Color(0xFF007BFF), Color(0xFF0056B3)],
  392.                           begin: Alignment.topLeft,
  393.                           end: Alignment.bottomRight,
  394.                         ),
  395.                         borderRadius: BorderRadius.circular(20),
  396.                         boxShadow: [
  397.                           BoxShadow(
  398.                             color: const Color(0xFF007BFF).withOpacity(0.4),
  399.                             blurRadius: 16,
  400.                             offset: const Offset(0, 6),
  401.                           ),
  402.                         ],
  403.                       ),
  404.                       child: Material(
  405.                         color: Colors.transparent,
  406.                         child: InkWell(
  407.                           borderRadius: BorderRadius.circular(20),
  408.                           onTap: _onQRScannerPressed,
  409.                           child: Container(
  410.                             width: 56,
  411.                             height: 56,
  412.                             child: const Icon(
  413.                               Icons.qr_code_scanner_rounded,
  414.                               color: Colors.white,
  415.                               size: 28,
  416.                             ),
  417.                           ),
  418.                         ),
  419.                       ),
  420.                     ),
  421.                   ),
  422.                   // Add Device FAB
  423.                   ScaleTransition(
  424.                     scale: _fabAnimationController,
  425.                     child: Container(
  426.                       decoration: BoxDecoration(
  427.                         gradient: const LinearGradient(
  428.                           colors: [Color(0xFFFFC727), Color(0xFFFFD54F)],
  429.                           begin: Alignment.topLeft,
  430.                           end: Alignment.bottomRight,
  431.                         ),
  432.                         borderRadius: BorderRadius.circular(20),
  433.                         boxShadow: [
  434.                           BoxShadow(
  435.                             color: const Color(0xFFFFC727).withOpacity(0.4),
  436.                             blurRadius: 16,
  437.                             offset: const Offset(0, 6),
  438.                           ),
  439.                         ],
  440.                       ),
  441.                       child: Material(
  442.                         color: Colors.transparent,
  443.                         child: InkWell(
  444.                           borderRadius: BorderRadius.circular(20),
  445.                           onTap: _onFabPressed,
  446.                           child: Container(
  447.                             width: 56,
  448.                             height: 56,
  449.                             child: const Icon(
  450.                               Icons.add_rounded,
  451.                               color: Color(0xFF212529),
  452.                               size: 28,
  453.                             ),
  454.                           ),
  455.                         ),
  456.                       ),
  457.                     ),
  458.                   ),
  459.                 ],
  460.               ),
  461.             ),
  462.         ],
  463.       ),
  464.       bottomNavigationBar: isBottomNavPage
  465.           ? Container(
  466.               margin: const EdgeInsets.all(16),
  467.               decoration: BoxDecoration(
  468.                 color: const Color(0xFF212529),
  469.                 borderRadius: BorderRadius.circular(24),
  470.                 boxShadow: [
  471.                   BoxShadow(
  472.                     color: Colors.black.withOpacity(0.15),
  473.                     blurRadius: 20,
  474.                     offset: const Offset(0, 8),
  475.                   ),
  476.                 ],
  477.               ),
  478.               child: ClipRRect(
  479.                 borderRadius: BorderRadius.circular(24),
  480.                 child: BottomNavigationBar(
  481.                   currentIndex: safeCurrentIndex,
  482.                   selectedItemColor: const Color(0xFFFFC727),
  483.                   unselectedItemColor: const Color(0xFF6C757D),
  484.                   backgroundColor: const Color(0xFF212529),
  485.                   type: BottomNavigationBarType.fixed,
  486.                   elevation: 0,
  487.                   onTap: (index) {
  488.                     setState(() {
  489.                       _selectedIndex = _bottomNavIndexes[index];
  490.                     });
  491.                   },
  492.                   selectedLabelStyle: const TextStyle(
  493.                     fontFamily: 'SansRegular',
  494.                     fontWeight: FontWeight.w600,
  495.                     fontSize: 12,
  496.                   ),
  497.                   unselectedLabelStyle: const TextStyle(
  498.                     fontFamily: 'SansRegular',
  499.                     fontWeight: FontWeight.w400,
  500.                     fontSize: 12,
  501.                   ),
  502.                   items: [
  503.                     BottomNavigationBarItem(
  504.                       icon: _buildBottomNavIcon(Icons.home_outlined, 0, safeCurrentIndex),
  505.                       activeIcon: _buildBottomNavIcon(Icons.home_rounded, 0, safeCurrentIndex),
  506.                       label: "Home",
  507.                     ),
  508.                     BottomNavigationBarItem(
  509.                       icon: _buildBottomNavIcon(Icons.inventory_2_outlined, 1, safeCurrentIndex),
  510.                       activeIcon: _buildBottomNavIcon(Icons.inventory_2_rounded, 1, safeCurrentIndex),
  511.                       label: "Inventory",
  512.                     ),
  513.                     BottomNavigationBarItem(
  514.                       icon: _buildBottomNavIcon(Icons.person_outline_rounded, 2, safeCurrentIndex),
  515.                       activeIcon: _buildBottomNavIcon(Icons.person_rounded, 2, safeCurrentIndex),
  516.                       label: "Account",
  517.                     ),
  518.                     BottomNavigationBarItem(
  519.                       icon: _buildBottomNavIcon(Icons.location_city_outlined, 3, safeCurrentIndex),
  520.                       activeIcon: _buildBottomNavIcon(Icons.location_city_rounded, 3, safeCurrentIndex),
  521.                       label: "Location",
  522.                     ),
  523.                   ],
  524.                 ),
  525.               ),
  526.             )
  527.           : null,
  528.     );
  529.   }
  530.  
  531.   Widget _buildDrawerItem(IconData icon, IconData activeIcon, String title, int index) {
  532.     final isSelected = _selectedIndex == index;
  533.  
  534.     return Container(
  535.       decoration: BoxDecoration(
  536.         color: isSelected ? const Color(0xFFFFC727).withOpacity(0.1) : Colors.transparent,
  537.         borderRadius: BorderRadius.circular(16),
  538.       ),
  539.       child: Material(
  540.         color: Colors.transparent,
  541.         child: InkWell(
  542.           borderRadius: BorderRadius.circular(16),
  543.           onTap: () => _onSelect(index),
  544.           child: Padding(
  545.             padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
  546.             child: Row(
  547.               children: [
  548.                 Container(
  549.                   padding: const EdgeInsets.all(8),
  550.                   decoration: BoxDecoration(
  551.                     color: isSelected
  552.                         ? const Color(0xFFFFC727)
  553.                         : const Color(0xFFF8F9FA),
  554.                     borderRadius: BorderRadius.circular(12),
  555.                   ),
  556.                   child: Icon(
  557.                     isSelected ? activeIcon : icon,
  558.                     color: isSelected
  559.                         ? const Color(0xFF212529)
  560.                         : const Color(0xFF6C757D),
  561.                     size: 20,
  562.                   ),
  563.                 ),
  564.                 const SizedBox(width: 16),
  565.                 Expanded(
  566.                   child: Text(
  567.                     title,
  568.                     style: TextStyle(
  569.                       color: isSelected
  570.                           ? const Color(0xFF212529)
  571.                           : const Color(0xFF6C757D),
  572.                       fontFamily: 'SansRegular',
  573.                       fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400,
  574.                       fontSize: 16,
  575.                     ),
  576.                   ),
  577.                 ),
  578.                 if (isSelected)
  579.                   Container(
  580.                     width: 6,
  581.                     height: 6,
  582.                     decoration: const BoxDecoration(
  583.                       color: Color(0xFFFFC727),
  584.                       shape: BoxShape.circle,
  585.                     ),
  586.                   ),
  587.               ],
  588.             ),
  589.           ),
  590.         ),
  591.       ),
  592.     );
  593.   }
  594.  
  595.   Widget _buildBottomNavIcon(IconData icon, int index, int currentIndex) {
  596.     final isSelected = index == currentIndex;
  597.    
  598.     return Container(
  599.       padding: const EdgeInsets.all(8),
  600.       decoration: BoxDecoration(
  601.         color: isSelected
  602.             ? const Color(0xFFFFC727).withOpacity(0.2)
  603.             : Colors.transparent,
  604.         borderRadius: BorderRadius.circular(12),
  605.       ),
  606.       child: Icon(
  607.         icon,
  608.         size: 24,
  609.         color: isSelected
  610.             ? const Color(0xFFFFC727)
  611.             : const Color(0xFF6C757D),
  612.       ),
  613.     );
  614.   }
  615. }
  616.  
  617. // QR Scanner Page Widget
  618. class QRScannerPage extends StatefulWidget {
  619.   @override
  620.   _QRScannerPageState createState() => _QRScannerPageState();
  621. }
  622.  
  623. class _QRScannerPageState extends State<QRScannerPage> {
  624.   MobileScannerController cameraController = MobileScannerController();
  625.   bool isScanning = true;
  626.   String? scannedData;
  627.  
  628.   @override
  629.   void dispose() {
  630.     cameraController.dispose();
  631.     super.dispose();
  632.   }
  633.  
  634.   void _onDetect(BarcodeCapture capture) {
  635.     if (!isScanning) return;
  636.    
  637.     final List<Barcode> barcodes = capture.barcodes;
  638.     if (barcodes.isNotEmpty) {
  639.       final String? code = barcodes.first.rawValue;
  640.       if (code != null) {
  641.         setState(() {
  642.           isScanning = false;
  643.           scannedData = code;
  644.         });
  645.         _showScannedDataDialog(code);
  646.       }
  647.     }
  648.   }
  649.  
  650.   // Also modify the _showScannedDataDialog method to make the Process button more intuitive
  651. void _showScannedDataDialog(String data) {
  652.   showDialog(
  653.     context: context,
  654.     builder: (BuildContext context) {
  655.       return AlertDialog(
  656.         shape: RoundedRectangleBorder(
  657.           borderRadius: BorderRadius.circular(16),
  658.         ),
  659.         title: Row(
  660.           children: [
  661.             Container(
  662.               padding: const EdgeInsets.all(8),
  663.               decoration: BoxDecoration(
  664.                 color: const Color(0xFFFFC727).withOpacity(0.2),
  665.                 borderRadius: BorderRadius.circular(8),
  666.               ),
  667.               child: const Icon(
  668.                 Icons.qr_code_rounded,
  669.                 color: Color(0xFF212529),
  670.                 size: 24,
  671.               ),
  672.             ),
  673.             const SizedBox(width: 12),
  674.             const Text(
  675.               'QR Code Scanned',
  676.               style: TextStyle(
  677.                 fontFamily: 'SansRegular',
  678.                 fontWeight: FontWeight.w600,
  679.                 fontSize: 18,
  680.                 color: Color(0xFF212529),
  681.               ),
  682.             ),
  683.           ],
  684.         ),
  685.         content: Column(
  686.           mainAxisSize: MainAxisSize.min,
  687.           crossAxisAlignment: CrossAxisAlignment.start,
  688.           children: [
  689.             const Text(
  690.               'Device Name:',
  691.               style: TextStyle(
  692.                 fontFamily: 'SansRegular',
  693.                 fontWeight: FontWeight.w600,
  694.                 fontSize: 16,
  695.                 color: Color(0xFF212529),
  696.               ),
  697.             ),
  698.             const SizedBox(height: 8),
  699.             Container(
  700.               width: double.infinity,
  701.               padding: const EdgeInsets.all(12),
  702.               decoration: BoxDecoration(
  703.                 color: const Color(0xFFF8F9FA),
  704.                 borderRadius: BorderRadius.circular(8),
  705.                 border: Border.all(
  706.                   color: const Color(0xFFE9ECEF),
  707.                   width: 1,
  708.                 ),
  709.               ),
  710.               child: Text(
  711.                 data,
  712.                 style: const TextStyle(
  713.                   fontFamily: 'SansRegular',
  714.                   fontSize: 16,
  715.                   fontWeight: FontWeight.w600,
  716.                   color: Color(0xFF495057),
  717.                 ),
  718.               ),
  719.             ),
  720.             const SizedBox(height: 12),
  721.             const Text(
  722.               'Tap "Find Device" to search for this device in your inventory.',
  723.               style: TextStyle(
  724.                 fontFamily: 'SansRegular',
  725.                 fontSize: 14,
  726.                 color: Color(0xFF6C757D),
  727.               ),
  728.             ),
  729.           ],
  730.         ),
  731.         actions: [
  732.           TextButton(
  733.             onPressed: () {
  734.               Navigator.of(context).pop();
  735.               setState(() {
  736.                 isScanning = true;
  737.                 scannedData = null;
  738.               });
  739.             },
  740.             child: const Text(
  741.               'Scan Again',
  742.               style: TextStyle(
  743.                 fontFamily: 'SansRegular',
  744.                 color: Color(0xFF6C757D),
  745.                 fontWeight: FontWeight.w500,
  746.               ),
  747.             ),
  748.           ),
  749.           ElevatedButton(
  750.             onPressed: () {
  751.               Navigator.of(context).pop();
  752.               _processDeviceData(data);
  753.             },
  754.             style: ElevatedButton.styleFrom(
  755.               backgroundColor: const Color(0xFFFFC727),
  756.               foregroundColor: const Color(0xFF212529),
  757.               shape: RoundedRectangleBorder(
  758.                 borderRadius: BorderRadius.circular(8),
  759.               ),
  760.               elevation: 0,
  761.             ),
  762.             child: const Text(
  763.               'Find Device',
  764.               style: TextStyle(
  765.                 fontFamily: 'SansRegular',
  766.                 fontWeight: FontWeight.w600,
  767.               ),
  768.             ),
  769.           ),
  770.         ],
  771.       );
  772.     },
  773.   );
  774. }
  775.  
  776.   // Replace the _processDeviceData method in your QRScannerPage class
  777. void _processDeviceData(String data) async {
  778.   try {
  779.     // Show loading indicator
  780.     showDialog(
  781.       context: context,
  782.       barrierDismissible: false,
  783.       builder: (BuildContext context) {
  784.         return const Center(
  785.           child: CircularProgressIndicator(
  786.             valueColor: AlwaysStoppedAnimation<Color>(Color(0xFFFFC727)),
  787.           ),
  788.         );
  789.       },
  790.     );
  791.  
  792.     // Search for device in Firestore
  793.     final querySnapshot = await FirebaseFirestore.instance
  794.         .collection('devices')
  795.         .where('name', isEqualTo: data.trim())
  796.         .get();
  797.  
  798.     // Close loading dialog
  799.     Navigator.of(context).pop();
  800.  
  801.     if (querySnapshot.docs.isNotEmpty) {
  802.       // Device found - get the first matching device
  803.       final deviceDoc = querySnapshot.docs.first;
  804.       final deviceData = deviceDoc.data();
  805.       deviceData['id'] = deviceDoc.id; // Add document ID to the data
  806.  
  807.       // Navigate to device details page
  808.       Navigator.push(
  809.         context,
  810.         MaterialPageRoute(
  811.           builder: (context) => DeviceDetailsPage(device: deviceData),
  812.         ),
  813.       );
  814.  
  815.       // Show success message
  816.       ScaffoldMessenger.of(context).showSnackBar(
  817.         SnackBar(
  818.           content: Text('Device found: ${deviceData['name']}'),
  819.           backgroundColor: const Color(0xFF28A745),
  820.           behavior: SnackBarBehavior.floating,
  821.           shape: RoundedRectangleBorder(
  822.             borderRadius: BorderRadius.circular(8),
  823.           ),
  824.         ),
  825.       );
  826.     } else {
  827.       // Device not found
  828.       _showDeviceNotFoundDialog(data);
  829.     }
  830.    
  831.     // Reset scanner state
  832.     setState(() {
  833.       isScanning = true;
  834.       scannedData = null;
  835.     });
  836.    
  837.   } catch (e) {
  838.     // Close loading dialog if still open
  839.     Navigator.of(context).pop();
  840.    
  841.     // Show error message
  842.     ScaffoldMessenger.of(context).showSnackBar(
  843.       SnackBar(
  844.         content: Text('Error searching for device: $e'),
  845.         backgroundColor: const Color(0xFFDC3545),
  846.         behavior: SnackBarBehavior.floating,
  847.         shape: RoundedRectangleBorder(
  848.           borderRadius: BorderRadius.circular(8),
  849.         ),
  850.       ),
  851.     );
  852.    
  853.     // Reset scanner state
  854.     setState(() {
  855.       isScanning = true;
  856.       scannedData = null;
  857.     });
  858.   }
  859. }
  860.  
  861.  
  862.  
  863. // Add this new method to show device not found dialog
  864. void _showDeviceNotFoundDialog(String deviceName) {
  865.   showDialog(
  866.     context: context,
  867.     builder: (BuildContext context) {
  868.       return AlertDialog(
  869.         shape: RoundedRectangleBorder(
  870.           borderRadius: BorderRadius.circular(16),
  871.         ),
  872.         title: Row(
  873.           children: [
  874.             Container(
  875.               padding: const EdgeInsets.all(8),
  876.               decoration: BoxDecoration(
  877.                 color: const Color(0xFFDC3545).withOpacity(0.2),
  878.                 borderRadius: BorderRadius.circular(8),
  879.               ),
  880.               child: const Icon(
  881.                 Icons.error_outline,
  882.                 color: Color(0xFFDC3545),
  883.                 size: 24,
  884.               ),
  885.             ),
  886.             const SizedBox(width: 12),
  887.             const Text(
  888.               'Device Not Found',
  889.               style: TextStyle(
  890.                 fontFamily: 'SansRegular',
  891.                 fontWeight: FontWeight.w600,
  892.                 fontSize: 18,
  893.                 color: Color(0xFF212529),
  894.               ),
  895.             ),
  896.           ],
  897.         ),
  898.         content: Column(
  899.           mainAxisSize: MainAxisSize.min,
  900.           crossAxisAlignment: CrossAxisAlignment.start,
  901.           children: [
  902.             Text(
  903.               'No device found with the name "$deviceName".',
  904.               style: const TextStyle(
  905.                 fontFamily: 'SansRegular',
  906.                 fontSize: 16,
  907.                 color: Color(0xFF495057),
  908.               ),
  909.             ),
  910.             const SizedBox(height: 12),
  911.             const Text(
  912.               'Please check the QR code or make sure the device is registered in the system.',
  913.               style: TextStyle(
  914.                 fontFamily: 'SansRegular',
  915.                 fontSize: 14,
  916.                 color: Color(0xFF6C757D),
  917.               ),
  918.             ),
  919.           ],
  920.         ),
  921.         actions: [
  922.           TextButton(
  923.             onPressed: () {
  924.               Navigator.of(context).pop();
  925.             },
  926.             child: const Text(
  927.               'Scan Again',
  928.               style: TextStyle(
  929.                 fontFamily: 'SansRegular',
  930.                 color: Color(0xFF007BFF),
  931.                 fontWeight: FontWeight.w500,
  932.               ),
  933.             ),
  934.           ),
  935.           ElevatedButton(
  936.             onPressed: () {
  937.               Navigator.of(context).pop();
  938.               // Navigate to Add Device page with pre-filled name
  939.               // You can modify this based on your app's navigation structure
  940.             },
  941.             style: ElevatedButton.styleFrom(
  942.               backgroundColor: const Color(0xFFFFC727),
  943.               foregroundColor: const Color(0xFF212529),
  944.               shape: RoundedRectangleBorder(
  945.                 borderRadius: BorderRadius.circular(8),
  946.               ),
  947.               elevation: 0,
  948.             ),
  949.             child: const Text(
  950.               'Add Device',
  951.               style: TextStyle(
  952.                 fontFamily: 'SansRegular',
  953.                 fontWeight: FontWeight.w600,
  954.               ),
  955.             ),
  956.           ),
  957.         ],
  958.       );
  959.     },
  960.   );
  961. }
  962.  
  963.   @override
  964.   Widget build(BuildContext context) {
  965.     return Scaffold(
  966.       backgroundColor: Colors.black,
  967.       body: Stack(
  968.         children: [
  969.           // Camera View
  970.           MobileScanner(
  971.             controller: cameraController,
  972.             onDetect: _onDetect,
  973.           ),
  974.          
  975.           // Overlay with scanning frame
  976.           Container(
  977.             decoration: ShapeDecoration(
  978.               shape: QRScannerOverlayShape(
  979.                 borderColor: const Color(0xFFFFC727),
  980.                 borderRadius: 16,
  981.                 borderLength: 30,
  982.                 borderWidth: 4,
  983.                 cutOutSize: 250,
  984.               ),
  985.             ),
  986.           ),
  987.          
  988.           // Top instruction
  989.           Positioned(
  990.             top: 100,
  991.             left: 0,
  992.             right: 0,
  993.             child: Container(
  994.               margin: const EdgeInsets.symmetric(horizontal: 24),
  995.               padding: const EdgeInsets.all(16),
  996.               decoration: BoxDecoration(
  997.                 color: Colors.black.withOpacity(0.7),
  998.                 borderRadius: BorderRadius.circular(12),
  999.               ),
  1000.               child: const Text(
  1001.                 'Position the QR code within the frame to scan device details',
  1002.                 textAlign: TextAlign.center,
  1003.                 style: TextStyle(
  1004.                   color: Colors.white,
  1005.                   fontSize: 16,
  1006.                   fontFamily: 'SansRegular',
  1007.                   fontWeight: FontWeight.w500,
  1008.                 ),
  1009.               ),
  1010.             ),
  1011.           ),
  1012.          
  1013.           // Bottom controls
  1014.           Positioned(
  1015.             bottom: 100,
  1016.             left: 0,
  1017.             right: 0,
  1018.             child: Row(
  1019.               mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  1020.               children: [
  1021.                 // Flash toggle
  1022.                 Container(
  1023.                   decoration: BoxDecoration(
  1024.                     color: Colors.black.withOpacity(0.7),
  1025.                     borderRadius: BorderRadius.circular(30),
  1026.                   ),
  1027.                   child: IconButton(
  1028.                     onPressed: () => cameraController.toggleTorch(),
  1029.                     icon: const Icon(
  1030.                       Icons.flash_on,
  1031.                       color: Colors.white,
  1032.                       size: 28,
  1033.                     ),
  1034.                   ),
  1035.                 ),
  1036.                
  1037.                 // Switch camera
  1038.                 Container(
  1039.                   decoration: BoxDecoration(
  1040.                     color: Colors.black.withOpacity(0.7),
  1041.                     borderRadius: BorderRadius.circular(30),
  1042.                   ),
  1043.                   child: IconButton(
  1044.                     onPressed: () => cameraController.switchCamera(),
  1045.                     icon: const Icon(
  1046.                       Icons.flip_camera_ios,
  1047.                       color: Colors.white,
  1048.                       size: 28,
  1049.                     ),
  1050.                   ),
  1051.                 ),
  1052.               ],
  1053.             ),
  1054.           ),
  1055.         ],
  1056.       ),
  1057.     );
  1058.   }
  1059. }
  1060.  
  1061. // Custom QR Scanner Overlay Shape
  1062. class QRScannerOverlayShape extends ShapeBorder {
  1063.   const QRScannerOverlayShape({
  1064.     this.borderColor = Colors.white,
  1065.     this.borderWidth = 3.0,
  1066.     this.overlayColor = const Color.fromRGBO(0, 0, 0, 80),
  1067.     this.borderRadius = 0,
  1068.     this.borderLength = 40,
  1069.     this.cutOutSize = 250,
  1070.   });
  1071.  
  1072.   final Color borderColor;
  1073.   final double borderWidth;
  1074.   final Color overlayColor;
  1075.   final double borderRadius;
  1076.   final double borderLength;
  1077.   final double cutOutSize;
  1078.  
  1079.   @override
  1080.   EdgeInsetsGeometry get dimensions => const EdgeInsets.all(10);
  1081.  
  1082.   @override
  1083.   Path getInnerPath(Rect rect, {TextDirection? textDirection}) {
  1084.     return Path()
  1085.       ..fillType = PathFillType.evenOdd
  1086.       ..addPath(getOuterPath(rect), Offset.zero);
  1087.   }
  1088.  
  1089.   @override
  1090.   Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
  1091.     Path outerPath = Path()..addRect(rect);
  1092.     Path innerPath = Path()
  1093.       ..addRRect(RRect.fromRectAndRadius(
  1094.         Rect.fromCenter(
  1095.           center: rect.center,
  1096.           width: cutOutSize,
  1097.           height: cutOutSize,
  1098.         ),
  1099.         Radius.circular(borderRadius),
  1100.       ));
  1101.     return Path.combine(PathOperation.difference, outerPath, innerPath);
  1102.   }
  1103.  
  1104.   @override
  1105.   void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {
  1106.     final Paint paint = Paint()
  1107.       ..color = overlayColor
  1108.       ..style = PaintingStyle.fill;
  1109.  
  1110.     canvas.drawPath(getOuterPath(rect), paint);
  1111.  
  1112.     // Draw border corners
  1113.     final Paint borderPaint = Paint()
  1114.       ..color = borderColor
  1115.       ..style = PaintingStyle.stroke
  1116.       ..strokeWidth = borderWidth;
  1117.  
  1118.     final double halfBorderLength = borderLength / 2;
  1119.     final Rect cutOutRect = Rect.fromCenter(
  1120.       center: rect.center,
  1121.       width: cutOutSize,
  1122.       height: cutOutSize,
  1123.     );
  1124.  
  1125.     // Top-left corner
  1126.     canvas.drawPath(
  1127.       Path()
  1128.         ..moveTo(cutOutRect.left, cutOutRect.top + halfBorderLength)
  1129.         ..lineTo(cutOutRect.left, cutOutRect.top + borderRadius)
  1130.         ..quadraticBezierTo(cutOutRect.left, cutOutRect.top, cutOutRect.left + borderRadius, cutOutRect.top)
  1131.         ..lineTo(cutOutRect.left + halfBorderLength, cutOutRect.top),
  1132.       borderPaint,
  1133.     );
  1134.  
  1135.     // Top-right corner
  1136.     canvas.drawPath(
  1137.       Path()
  1138.         ..moveTo(cutOutRect.right - halfBorderLength, cutOutRect.top)
  1139.         ..lineTo(cutOutRect.right - borderRadius, cutOutRect.top)
  1140.         ..quadraticBezierTo(cutOutRect.right, cutOutRect.top, cutOutRect.right, cutOutRect.top + borderRadius)
  1141.         ..lineTo(cutOutRect.right, cutOutRect.top + halfBorderLength),
  1142.       borderPaint,
  1143.     );
  1144.  
  1145.     // Bottom-left corner
  1146.     canvas.drawPath(
  1147.       Path()
  1148.         ..moveTo(cutOutRect.left, cutOutRect.bottom - halfBorderLength)
  1149.         ..lineTo(cutOutRect.left, cutOutRect.bottom - borderRadius)
  1150.         ..quadraticBezierTo(cutOutRect.left, cutOutRect.bottom, cutOutRect.left + borderRadius, cutOutRect.bottom)
  1151.         ..lineTo(cutOutRect.left + halfBorderLength, cutOutRect.bottom),
  1152.       borderPaint,
  1153.     );
  1154.  
  1155.     // Bottom-right corner
  1156.     canvas.drawPath(
  1157.       Path()
  1158.         ..moveTo(cutOutRect.right - halfBorderLength, cutOutRect.bottom)
  1159.         ..lineTo(cutOutRect.right - borderRadius, cutOutRect.bottom)
  1160.         ..quadraticBezierTo(cutOutRect.right, cutOutRect.bottom, cutOutRect.right, cutOutRect.bottom - borderRadius)
  1161.         ..lineTo(cutOutRect.right, cutOutRect.bottom - halfBorderLength),
  1162.       borderPaint,
  1163.     );
  1164.   }
  1165.  
  1166.   @override
  1167.   ShapeBorder scale(double t) => QRScannerOverlayShape(
  1168.         borderColor: borderColor,
  1169.         borderWidth: borderWidth,
  1170.         overlayColor: overlayColor,
  1171.         borderRadius: borderRadius,
  1172.         borderLength: borderLength,
  1173.         cutOutSize: cutOutSize,
  1174.       );
  1175. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement