|
|
|
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<EditTransferPetiPage> createState() => _EditTransferPetiPageState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class _EditTransferPetiPageState extends State<EditTransferPetiPage> {
|
|
|
|
String? token;
|
|
|
|
PetiAssetModel? petiSqfliteApi;
|
|
|
|
WarehouseModel? warehouseSqfliteApi;
|
|
|
|
List<PetiAssetModel>? _valpeti;
|
|
|
|
List<PetiAssetModel> _filteredPetiList = [];
|
|
|
|
bool isQRCodeScanned = false;
|
|
|
|
String searchText = '';
|
|
|
|
PetiAssetModel? selectedPeti;
|
|
|
|
|
|
|
|
List<PetiAssetModel>? selectedPetiList = [];
|
|
|
|
List<PetiAssetModel> scannedPetiList = [];
|
|
|
|
List<PetiAssetModel> localSelectedPetiList = [];
|
|
|
|
List<TransferPetiModel> temporaryDataList = [];
|
|
|
|
List<TransferPetiModel>? _data;
|
|
|
|
|
|
|
|
final _formKey = GlobalKey<FormState>();
|
|
|
|
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<PetiAssetModel> selectedPetiList) async {
|
|
|
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
|
|
List<Map<String, dynamic>> petiListJson =
|
|
|
|
selectedPetiList.map((peti) => peti.toJson()).toList();
|
|
|
|
List<String> petiListJsonString =
|
|
|
|
petiListJson.map((peti) => json.encode(peti)).toList();
|
|
|
|
prefs.setStringList('menu2_transferPetiList', petiListJsonString);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mendapatkan nilai dari SharedPreferences untuk Menu 2
|
|
|
|
Future<List<PetiAssetModel>>
|
|
|
|
getSelectedPetiListFromSharedPreferences() async {
|
|
|
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
|
|
List<String>? petiListJson = prefs.getStringList('menu2_transferPetiList');
|
|
|
|
if (petiListJson != null) {
|
|
|
|
List<PetiAssetModel> 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<String> lines = result!.code!.split('\n');
|
|
|
|
String idPeti = '';
|
|
|
|
String idWarehouse = '';
|
|
|
|
for (String line in lines) {
|
|
|
|
if (line.contains(';')) {
|
|
|
|
List<String> 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<dynamic>)
|
|
|
|
.map((e) => TransferPetiModel.fromJson(e))
|
|
|
|
.toList();
|
|
|
|
loading = false;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future petiListAPI() async {
|
|
|
|
if (mounted) {
|
|
|
|
await ControllerApi().fetchPetiDataAPI().then((value) {
|
|
|
|
setState(() {
|
|
|
|
_valpeti = (value as List<dynamic>)
|
|
|
|
.map((item) => PetiAssetModel.fromJson(item))
|
|
|
|
.toList();
|
|
|
|
loading = false;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<List<PetiAssetModel>> _petiListAPI() async {
|
|
|
|
List petiList = await ControllerApi().fetchPetiDataAPI();
|
|
|
|
return petiList.map((item) => PetiAssetModel.fromJson(item)).toList();
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
AuthProvider authProvider =
|
|
|
|
Provider.of<AuthProvider>(context, listen: false);
|
|
|
|
UserModel user = authProvider.user;
|
|
|
|
|
|
|
|
Future<void> 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<void> 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<String, dynamic>))
|
|
|
|
.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<void> removePetiFromSharedPreferences(
|
|
|
|
PetiAssetModel removedPeti) async {
|
|
|
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
|
|
|
|
|
|
// Retrieve existing data from SharedPreferences
|
|
|
|
List<String>? petiListJson =
|
|
|
|
prefs.getStringList('menu2_transferPetiList');
|
|
|
|
|
|
|
|
if (petiListJson != null) {
|
|
|
|
// Convert JSON strings to PetiAssetModel objects
|
|
|
|
List<PetiAssetModel> 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<String> 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<List<PetiAssetModel>>(
|
|
|
|
future: _petiListAPI(),
|
|
|
|
builder: (context,
|
|
|
|
AsyncSnapshot<List<PetiAssetModel>>
|
|
|
|
snapshot) {
|
|
|
|
if (snapshot.connectionState ==
|
|
|
|
ConnectionState.waiting) {
|
|
|
|
return Center(
|
|
|
|
child:
|
|
|
|
CircularProgressIndicator(),
|
|
|
|
);
|
|
|
|
} else if (snapshot.hasError) {
|
|
|
|
return Text(
|
|
|
|
'Error: ${snapshot.error}');
|
|
|
|
} else {
|
|
|
|
List<PetiAssetModel> 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),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|