import 'dart:convert'; import 'dart:core'; import 'package:flutter/material.dart'; import 'package:siopas/models/transfer_peti_model.dart'; import 'package:siopas/pages/transfer_peti/controller/transfer_peti_controller.dart'; import 'package:siopas/pages/transfer_peti/edit-finish.dart'; import 'package:siopas/services/controllerApi.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:qr_code_scanner/qr_code_scanner.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:siopas/models/m_asset_status_model.dart'; import 'package:siopas/models/warehouse_mode.dart'; import 'package:intl/date_symbol_data_local.dart'; // Import package intl import 'package:dropdown_search/dropdown_search.dart'; import '../../models/user_model.dart'; import '../../providers/auth_provider.dart'; import 'package:collection/collection.dart'; class EditTransferPetiPage extends StatefulWidget { const EditTransferPetiPage({Key? key}) : super(key: key); @override State createState() => _EditTransferPetiPageState(); } class _EditTransferPetiPageState extends State { String? token; PetiAssetModel? petiSqfliteApi; WarehouseModel? warehouseSqfliteApi; List? _valpeti; List _filteredPetiList = []; bool isQRCodeScanned = false; String searchText = ''; PetiAssetModel? selectedPeti; List? selectedPetiList = []; List scannedPetiList = []; List localSelectedPetiList = []; List temporaryDataList = []; List? _data; final _formKey = GlobalKey(); final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); Barcode? result; QRViewController? controller; bool loading = true; TextEditingController searchBoxController = TextEditingController(); @override void initState() { super.initState(); _getUserToken(); petiListAPI(); initializeDateFormatting('id_ID', null); assetStatusListSqflite(); getSelectedPetiListFromSharedPreferences().then((retrievedPetiList) { setState(() { // Update the state with the retrieved list selectedPetiList = retrievedPetiList; loading = false; }); }); } void _getUserToken() async { SharedPreferences prefs = await SharedPreferences.getInstance(); if (mounted) { setState(() { token = prefs.getString('token'); loading = false; }); } } // Menyimpan nilai ke SharedPreferences untuk Menu 2 void saveSelectedPetiListToSharedPreferences( List selectedPetiList) async { SharedPreferences prefs = await SharedPreferences.getInstance(); List> petiListJson = selectedPetiList.map((peti) => peti.toJson()).toList(); List petiListJsonString = petiListJson.map((peti) => json.encode(peti)).toList(); prefs.setStringList('menu2_transferPetiList', petiListJsonString); } // Mendapatkan nilai dari SharedPreferences untuk Menu 2 Future> getSelectedPetiListFromSharedPreferences() async { SharedPreferences prefs = await SharedPreferences.getInstance(); List? petiListJson = prefs.getStringList('menu2_transferPetiList'); if (petiListJson != null) { List selectedPetiList = petiListJson .map((petiJson) => PetiAssetModel.fromJson(json.decode(petiJson))) .toList(); return selectedPetiList; } else { return []; } } void _handlePetiScanResult(int petiId) { bool isPetiInAssetStatusList = _data?.any((assetStatus) => assetStatus.peti_id == petiId) ?? false; bool isPetiInSelectedPetiList = selectedPetiList!.any((peti) => peti.id == petiId); PetiAssetModel? petiSqfliteApi = _valpeti?.firstWhereOrNull( (peti) => peti.id == petiId, ); String fixLot = petiSqfliteApi?.fix_lot ?? ''; // Menyimpan nilai fix_lot jika petiSqfliteApi tidak null if (isPetiInAssetStatusList) { showErrorMessage( 'Peti dengan $fixLot sudah terdaftar dalam daftar menu transfer peti. Harap periksa kembali.', Colors.yellow[700]!, ); } else if (!isPetiInSelectedPetiList) { PetiAssetModel? allowedPeti = _valpeti?.firstWhereOrNull( (peti) => peti.id == petiId && peti.deleted_at != true && peti.status == 'AKTIF', ); if (allowedPeti != null) { setState(() { isQRCodeScanned = true; _filteredPetiList = [allowedPeti]; petiSqfliteApi = allowedPeti; selectedPetiList!.add(allowedPeti); saveSelectedPetiListToSharedPreferences(selectedPetiList!); }); } else { showErrorMessage( 'Data Peti tidak ditemukan atau tidak sesuai dengan hak akses.', Colors.red[700]!, ); setState(() { isQRCodeScanned = false; petiSqfliteApi = null; }); } } else { showErrorMessage( 'Peti dengan $fixLot sudah ada dalam daftar pilihan List Peti. Harap periksa kembali.', Colors.yellow[700]!, ); } } void _onQRViewCreated(QRViewController controller) async { this.controller = controller; bool scanned = false; // Code to auto-focus the back camera controller.flipCamera(); await Future.delayed(const Duration(milliseconds: 400)); controller.flipCamera(); controller.scannedDataStream.listen( (scanData) async { if (!scanned) { try { result = scanData; List lines = result!.code!.split('\n'); String idPeti = ''; String idWarehouse = ''; for (String line in lines) { if (line.contains(';')) { List values = line.split(';'); if (values.length >= 3) { idPeti = values[1]; idWarehouse = values[2]; break; } } } int? petiId = int.tryParse(idPeti); if (petiId != null) { _handlePetiScanResult(petiId); } else { showErrorMessage( 'Nilai QR Code tidak sesuai dengan yang diharapkan.', Colors.yellow[700]!, ); setState(() { isQRCodeScanned = false; petiSqfliteApi = null; }); } scanned = true; } catch (e) { controller.stopCamera(); setState(() { petiSqfliteApi = null; }); print('Error scanning QR Code: $e'); showErrorMessage(e.toString(), Colors.red[700]!); } finally { controller.stopCamera(); await Future.delayed(Duration(milliseconds: 500)); if (mounted) { Navigator.of(context).pop(); } } } }, ); } void showErrorMessage(String message, Color backgroundColor) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( message, style: TextStyle( color: Colors.black, fontSize: 12, ), ), backgroundColor: backgroundColor, ), ); } Future assetStatusListSqflite() async { if (mounted) { await ControllerTransferPeti() .fetchTransferPetiLocalController() .then((value) { setState(() { _data = (value as List) .map((e) => TransferPetiModel.fromJson(e)) .toList(); loading = false; }); }); } } Future petiListAPI() async { if (mounted) { await ControllerApi().fetchPetiDataAPI().then((value) { setState(() { _valpeti = (value as List) .map((item) => PetiAssetModel.fromJson(item)) .toList(); loading = false; }); }); } } Future> _petiListAPI() async { List petiList = await ControllerApi().fetchPetiDataAPI(); return petiList.map((item) => PetiAssetModel.fromJson(item)).toList(); } @override Widget build(BuildContext context) { AuthProvider authProvider = Provider.of(context, listen: false); UserModel user = authProvider.user; Future saveAssetData() async { print('Entering saveAssetData'); DateTime now = DateTime.now().toLocal(); String formattedDate = DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(now); // Cek apakah ada item yang dipilih di dalam selectedPetiList if (selectedPetiList!.any((peti) => peti == null)) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text("Pilih setidaknya satu peti"), backgroundColor: Colors.red, )); print('Exiting saveAssetData - No peti selected'); return; } // Iterasi melalui selectedPetiList for (var peti in selectedPetiList!) { // Buat model baru TransferPetiModel assetAddModel = TransferPetiModel( id: null, peti_id: peti!.id, // Tambahkan properti lainnya sesuai kebutuhan ); int index = temporaryDataList.indexWhere((data) => data.peti_id == peti.id); if (index != -1) { // Jika peti_id sudah ada, ganti entri yang sudah ada temporaryDataList[index] = assetAddModel; } else { // Jika peti_id belum ada, tambahkan ke dalam list temporaryDataList.add(assetAddModel); } } print('Temporary data added. Length: ${temporaryDataList.length}'); // Navigasi ke halaman selanjutnya dengan membawa data temporaryDataList Navigator.push( context, MaterialPageRoute( builder: (context) => EditFinishTransferPeti( temporaryDataList: temporaryDataList, ), ), ); print('Exiting saveAssetData'); } Future checkAndAddPeti(PetiAssetModel value) async { // print('Checking and adding Peti: ${value.fix_lot}'); List assetStatusList = await ControllerTransferPeti().fetchTransferPetiLocalController(); // Ensure assetStatusList is of type List if (assetStatusList is List) { // Convert JSON strings to AssetStatusModel objects assetStatusList = assetStatusList .map((item) => TransferPetiModel.fromJson(item as Map)) .toList(); } bool isPetiInSqflite = assetStatusList.any((assetStatus) => assetStatus.peti_id == value.id); bool isPetiInLocalList = localSelectedPetiList.contains(value); bool isPetiInSelectedPetiList = selectedPetiList!.any((peti) => peti.id == value.id); if (isPetiInSqflite) { // print('Peti is already in Sqflite.'); showErrorMessage( 'Peti dengan ${value.fix_lot} sudah ada dalam daftar menu transfer peti. Harap periksa kembali.', Colors.yellow[700]!, ); } else if (isPetiInSelectedPetiList || isPetiInLocalList) { // print('Peti is already in selectedPetiList.'); showErrorMessage( 'Peti dengan ${value.fix_lot} sudah ada dalam daftar pilihan List Peti. Harap periksa kembali.', Colors.yellow[700]!, ); } else { // If the item passes all conditions, add it to the list print('Adding Peti to the list.'); setState(() { selectedPetiList!.add(value); saveSelectedPetiListToSharedPreferences(selectedPetiList!); }); } } // Function to remove peti data from SharedPreferences Future removePetiFromSharedPreferences( PetiAssetModel removedPeti) async { SharedPreferences prefs = await SharedPreferences.getInstance(); // Retrieve existing data from SharedPreferences List? petiListJson = prefs.getStringList('menu2_transferPetiList'); if (petiListJson != null) { // Convert JSON strings to PetiAssetModel objects List existingPetiList = petiListJson .map((petiJson) => PetiAssetModel.fromJson(json.decode(petiJson))) .toList(); // Remove the specified peti from the list existingPetiList.removeWhere((peti) => peti.id == removedPeti.id); // Save the updated list back to SharedPreferences List updatedPetiListJson = existingPetiList.map((peti) => json.encode(peti.toJson())).toList(); prefs.setStringList('menu2_transferPetiList', updatedPetiListJson); } } void removePeti(int index) async { PetiAssetModel? selectedPeti = selectedPetiList != null ? selectedPetiList![index] : null; print( 'Before Remove: ${selectedPeti?.fix_lot}'); // Cetak atribut tertentu sebelum penghapusan if (index >= 0 && index < selectedPetiList!.length) { if (mounted) { // Simpan peti yang akan dihapus PetiAssetModel removedPeti = selectedPetiList![index]; // Hapus item dari selectedPetiList selectedPetiList!.removeAt(index); // Hapus entri yang sesuai dari temporaryDataList berdasarkan peti_id temporaryDataList .removeWhere((data) => data.peti_id == removedPeti.id); // Hapus data dari SharedPreferences await removePetiFromSharedPreferences(removedPeti); print( 'After Remove: ${selectedPeti?.fix_lot}'); // Cetak daftar setelah penghapusan } } else { print('Invalid index: $index. Tidak ada penghapusan yang dilakukan.'); } } var scanArea = (MediaQuery.of(context).size.width < 400 || MediaQuery.of(context).size.height < 400) ? 250.0 : 300.0; return WillPopScope( onWillPop: () async { // Mencegah kembali ke halaman sebelumnya return false; }, child: Scaffold( backgroundColor: Colors.grey[100], appBar: AppBar( automaticallyImplyLeading: false, backgroundColor: Colors.indigo[700], elevation: 0, title: Text('Buat Transfer Peti', style: TextStyle( fontSize: 16, )), ), body: loading ? Center(child: CircularProgressIndicator()) : SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(8.0), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Card( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), side: BorderSide( color: Colors.grey.withOpacity(0.8), width: 1), // Tambahkan ini untuk menambahkan border ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( margin: EdgeInsets.only(left: 8, right: 8, top: 13), child: Text( 'Tambah List Peti / Scan Peti:', style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, ), ), ), Row( children: [ Expanded( child: Container( margin: EdgeInsets.only(left: 8), child: FutureBuilder>( future: _petiListAPI(), builder: (context, AsyncSnapshot> snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return Center( child: CircularProgressIndicator(), ); } else if (snapshot.hasError) { return Text( 'Error: ${snapshot.error}'); } else { List filteredItems = snapshot.data?.where((peti) { // Replace the condition with your logic return !localSelectedPetiList .contains( peti.id) && !scannedPetiList .contains( peti.id); }).toList() ?? []; return DropdownSearch< PetiAssetModel>( popupProps: PopupProps.bottomSheet( showSearchBox: true, itemBuilder: (context, PetiAssetModel? peti, bool? isSelected) { if (peti == null) { return SizedBox.shrink(); } String itemAsString( PetiAssetModel item) { return item.fix_lot ?? ''; } // Convert the item to a string for comparison String petiAsString = itemAsString(peti); // Check if the selected item is already in the list obtained from SharedPreferences bool isPetiInSharedPreferences = localSelectedPetiList.any( (selectedPeti) => itemAsString( selectedPeti) == petiAsString); // Check if the selected item is already in the list of scanned peti IDs bool isPetiInScannedList = scannedPetiList.any( (scannedPeti) => itemAsString( scannedPeti) == petiAsString); // Include the item only if it's not in either list if (!isPetiInSharedPreferences && !isPetiInScannedList) { // Tentukan warna dan ikon berdasarkan kondisi status Color bulletColor = peti.status == 'AKTIF' ? Colors.green : Colors.red; IconData bulletIcon = peti.status == 'AKTIF' ? Icons.circle : Icons.circle; return Container( child: Column( children: [ ListTile( title: Text( peti.fix_lot .toString(), style: TextStyle( fontSize: 16, fontFamily: 'OpenSansCondensed', ), ), leading: Icon( bulletIcon, color: bulletColor, size: 24, ), ), Divider( height: 1, color: Colors .grey, // Warna pembatas (divider) ), ], ), color: peti.id == petiSqfliteApi?.id ? Colors.grey .withOpacity(0.7) : Colors.white, ); } else { // Return an empty container for items that should be hidden return SizedBox.shrink(); } }, fit: FlexFit.loose, title: Padding( padding: EdgeInsets.all(8.0), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment .spaceBetween, children: [ Text( 'Pilih Peti', style: TextStyle( fontSize: 18, fontWeight: FontWeight .bold), ), IconButton( icon: Icon( Icons.close, color: Colors.red, ), onPressed: () { Future.delayed( Duration.zero, () { Navigator.pop( context); }); }, ), ], ), Divider(), ], ), ), ), dropdownDecoratorProps: DropDownDecoratorProps( dropdownSearchDecoration: InputDecoration( hintText: 'Pilih Peti', border: OutlineInputBorder( borderRadius: BorderRadius.all( Radius.circular(5.0), ), ), ), ), items: filteredItems, itemAsString: (PetiAssetModel item) => item.fix_lot ?? '', onBeforeChange: (PetiAssetModel? from, PetiAssetModel? to) async { // The logic here should remain the same bool isPetiInSharedPreferences = localSelectedPetiList .contains(to); bool isPetiInScannedList = scannedPetiList .contains(to?.id); if (isPetiInSharedPreferences || isPetiInScannedList) { showErrorMessage( 'Peti dengan ${to?.fix_lot} sudah ada dalam daftar pilihan List Peti. Harap periksa kembali.', Colors.yellow[700]!, ); // Wait for a short time to display the error message before returning false await Future.delayed(Duration( milliseconds: 500)); return false; // Cancel the change } return true; // Allow the change }, onChanged: (PetiAssetModel? value) async { if (value != null) { bool isPetiInSharedPreferences = localSelectedPetiList .contains(value); bool isPetiInScannedList = scannedPetiList .contains(value.id); if (isPetiInSharedPreferences || isPetiInScannedList) { print( 'Peti is already in SharedPreferences or Scanned List.'); showErrorMessage( 'Peti dengan ${value.fix_lot} sudah ada dalam daftar pilihan List Peti. Harap periksa kembali.', Colors.yellow[700]!, ); } else { // Move the asynchronous work outside the setState await checkAndAddPeti( value); } } }, ); } }, ), ), ), SizedBox(width: 8), // Spacer antara dua card Container( margin: EdgeInsets.all(8), height: MediaQuery.of(context).size.height / 10, decoration: BoxDecoration( color: Colors.indigoAccent, borderRadius: BorderRadius.circular(15), border: Border.all( color: Colors.white, width: 3, ), ), child: IconButton( onPressed: () { showModalBottomSheet( context: context, isScrollControlled: true, // Set modal menjadi fullscreen builder: (BuildContext context) { return Stack( alignment: Alignment.center, children: [ Container( height: double.infinity, width: double.infinity, child: QRView( key: qrKey, onQRViewCreated: _onQRViewCreated, overlay: QrScannerOverlayShape( borderColor: Colors.red, borderRadius: 10, borderLength: 30, borderWidth: 10, cutOutSize: scanArea, ), ), ), Positioned( bottom: 30, height: 60, child: Container( height: 60, // Lebar dan tinggi sesuai kebutuhan width: 60, decoration: BoxDecoration( shape: BoxShape.circle, color: Colors .red, // Warna merah untuk close ), child: IconButton( onPressed: () { Navigator.of(context) .pop(); }, icon: Icon( Icons.close, size: 40, ), color: Colors.white, ), ), ), ], ); }, ); }, icon: Icon( Icons.qr_code, size: 30, ), color: Colors.white, // Warna ikon ), ), ], ), ], ), ), Divider(), SizedBox(height: 8), Visibility( visible: selectedPetiList!.isEmpty == false, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( margin: EdgeInsets.only(left: 8, bottom: 8), child: Text( 'List Peti:', style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, ), ), ), Card( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), side: BorderSide( color: Colors.grey.withOpacity(0.8), width: 1), // Tambahkan ini untuk menambahkan border ), child: Container( margin: EdgeInsets.all(8), child: ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemCount: selectedPetiList!.length, itemBuilder: (BuildContext context, int i) { return Container( margin: EdgeInsets.only(bottom: 8), padding: EdgeInsets.all(8), child: Row( children: [ Text( '${i + 1}.', style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, ), ), SizedBox(width: 8), Expanded( child: Container( padding: EdgeInsets.all(8.0), decoration: BoxDecoration( borderRadius: BorderRadius.circular( 5.0), border: Border.all( color: Colors.grey), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( selectedPetiList![i] ?.fix_lot ?? 'Belum dipilih', style: TextStyle( fontSize: 16, fontFamily: 'OpenSansCondensed'), ), ], ), ), ), Container( margin: EdgeInsets.only(left: 8), width: 30, height: 30, decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.red, ), child: InkWell( onTap: () { setState(() { removePeti(i); }); }, child: Center( child: Icon( Icons.delete, color: Colors.white, ), ), ), ), ], ), ); }, ), ), ), ], ), ), ], ), ), ), ), bottomNavigationBar: BottomAppBar( height: MediaQuery.of(context).size.height / 10, color: Color.fromARGB(255, 5, 28, 158), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( width: MediaQuery.of(context).size.width / 3, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( height: 50, // Lebar dan tinggi sesuai kebutuhan width: 50, decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.red, // Warna merah untuk close ), child: IconButton( onPressed: () { Navigator.pop(context); }, icon: Icon(Icons.close, color: Colors.white), ), ), ], ), ), Container( width: MediaQuery.of(context).size.width / 3, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( height: 50, width: 50, decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.blue, ), child: IconButton( onPressed: () async { // Cek apakah ada setidaknya satu peti terpilih if (selectedPetiList!.isEmpty || selectedPetiList!.any((peti) => peti == null)) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text( "Tidak ada peti yang dipilih", style: TextStyle( color: Colors.black, fontWeight: FontWeight.bold, ), ), backgroundColor: Colors.yellow[700], )); return; } await saveAssetData(); }, icon: Icon(Icons.save, color: Colors.white), ), ), ], ), ), ], ), ), ), ); } }