chore: normalize line endings (CRLF -> LF)
No content changes: git diff --ignore-all-space over these files is empty. The churn came from editing on Windows against a repo checked out with LF.
This commit is contained in:
1 parent
15566a6951
commit
caf8e98378
315 files changed
+86950
-86950
No files matched your search
@@ -1,238 +1,238 @@
|
||||
part of 'editor_screen.dart';
|
||||
|
||||
mixin EditorLogic on ConsumerState<EditorScreen> {
|
||||
DocumentModel? _document;
|
||||
|
||||
// Controllers
|
||||
final _tanggalCtrl = TextEditingController();
|
||||
final _noPoCtrl = TextEditingController();
|
||||
final _noSoCtrl = TextEditingController();
|
||||
final _noDoCtrl = TextEditingController();
|
||||
|
||||
final _kepadaYthCtrl = TextEditingController();
|
||||
final _orderUntukCtrl = TextEditingController();
|
||||
final _alamatCtrl = TextEditingController();
|
||||
final _platTrukCtrl = TextEditingController();
|
||||
final _namaDriverCtrl = TextEditingController();
|
||||
final _namaPenerimaCtrl = TextEditingController();
|
||||
|
||||
final _latitudeCtrl = TextEditingController();
|
||||
final _longitudeCtrl = TextEditingController();
|
||||
|
||||
List<Map<String, TextEditingController>> _itemControllers = [];
|
||||
bool _isAgreed = false;
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
|
||||
void _loadDocumentData() {
|
||||
if (widget.pendingId == null) return;
|
||||
|
||||
final pendingDocs = ref.read(pendingDocumentsProvider);
|
||||
final pendingDoc = pendingDocs.firstWhere(
|
||||
(doc) => doc.id == widget.pendingId,
|
||||
orElse: () => PendingDocument(id: '', imagePath: '')
|
||||
);
|
||||
|
||||
if (pendingDoc.document != null) {
|
||||
final doc = pendingDoc.document!;
|
||||
setState(() {
|
||||
_document = doc;
|
||||
_tanggalCtrl.text = doc.tanggal;
|
||||
_noPoCtrl.text = doc.noPo;
|
||||
_noSoCtrl.text = doc.noSo;
|
||||
_noDoCtrl.text = doc.noDo;
|
||||
|
||||
_kepadaYthCtrl.text = doc.kepadaYth;
|
||||
_orderUntukCtrl.text = doc.orderUntuk;
|
||||
_alamatCtrl.text = doc.alamat;
|
||||
_platTrukCtrl.text = doc.platTruk;
|
||||
_namaDriverCtrl.text = doc.namaDriver;
|
||||
|
||||
final lat = pendingDoc.latitude ?? doc.latitude;
|
||||
final lng = pendingDoc.longitude ?? doc.longitude;
|
||||
_latitudeCtrl.text = lat != null ? lat.toString() : '-';
|
||||
_longitudeCtrl.text = lng != null ? lng.toString() : '-';
|
||||
|
||||
for (var item in doc.items) {
|
||||
_addItem(
|
||||
sku: item.nomorSku,
|
||||
nama: item.namaBarang,
|
||||
banyak: item.banyak,
|
||||
jumlah: item.jumlah,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _addItem({String sku = '', String nama = '', String banyak = '', String jumlah = ''}) {
|
||||
final skuCtrl = TextEditingController(text: sku);
|
||||
final namaCtrl = TextEditingController(text: nama);
|
||||
final banyakCtrl = TextEditingController(text: banyak);
|
||||
final jumlahCtrl = TextEditingController(text: jumlah);
|
||||
|
||||
setState(() {
|
||||
_itemControllers.add({
|
||||
'sku': skuCtrl,
|
||||
'nama': namaCtrl,
|
||||
'banyak': banyakCtrl,
|
||||
'jumlah': jumlahCtrl,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void _removeItem(int index) {
|
||||
setState(() {
|
||||
final ctrls = _itemControllers[index];
|
||||
ctrls['sku']?.dispose();
|
||||
ctrls['nama']?.dispose();
|
||||
ctrls['banyak']?.dispose();
|
||||
ctrls['jumlah']?.dispose();
|
||||
_itemControllers.removeAt(index);
|
||||
});
|
||||
}
|
||||
|
||||
void _showConfirmationDialog() {
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
||||
),
|
||||
builder: (context) {
|
||||
return ConfirmationDialog(
|
||||
nameController: _namaPenerimaCtrl,
|
||||
initialAgreed: _isAgreed,
|
||||
onConfirm: (agreed, name) {
|
||||
setState(() {
|
||||
_isAgreed = agreed;
|
||||
});
|
||||
Navigator.pop(context);
|
||||
_submitDocument();
|
||||
},
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _submitDocument() async {
|
||||
final pendingDocs = ref.read(pendingDocumentsProvider);
|
||||
final pendingDoc = pendingDocs.firstWhere(
|
||||
(doc) => doc.id == widget.pendingId,
|
||||
orElse: () => PendingDocument(id: '', imagePath: '')
|
||||
);
|
||||
final double? finalLat = pendingDoc.latitude ?? _document?.latitude;
|
||||
final double? finalLng = pendingDoc.longitude ?? _document?.longitude;
|
||||
|
||||
final saveAction = resolveDocumentSaveAction(
|
||||
existingDocument: _document,
|
||||
localImagePath: pendingDoc.imagePath,
|
||||
);
|
||||
|
||||
if (saveAction.kind == DocumentSaveActionKind.blocked) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(saveAction.blockedMessage!),
|
||||
backgroundColor: AppConfig.errorColor,
|
||||
duration: const Duration(seconds: 5),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final apiClient = ref.read(apiClientProvider);
|
||||
String serverId;
|
||||
if (saveAction.kind == DocumentSaveActionKind.reuploadThenPut) {
|
||||
try {
|
||||
final formData = FormData.fromMap({
|
||||
'image': await MultipartFile.fromFile(
|
||||
pendingDoc.imagePath,
|
||||
filename: pendingDoc.imagePath.split(RegExp(r'[/\\]')).last,
|
||||
),
|
||||
if (finalLat != null) 'latitude': finalLat.toString(),
|
||||
if (finalLng != null) 'longitude': finalLng.toString(),
|
||||
'scan_mode': pendingDoc.scanMode ?? 'DO',
|
||||
});
|
||||
final response = await apiClient.client.post(AppConfig.uploadDocumentEndpoint, data: formData);
|
||||
serverId = DocumentModel.fromJson(response.data['data']).id;
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Gagal membuat dokumen di server: ${ApiException.from(e).displayMessage}'),
|
||||
backgroundColor: AppConfig.errorColor,
|
||||
duration: const Duration(seconds: 5),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
serverId = saveAction.serverId!;
|
||||
}
|
||||
|
||||
final finalDoc = DocumentModel(
|
||||
id: serverId,
|
||||
tanggal: _tanggalCtrl.text,
|
||||
noPo: _noPoCtrl.text,
|
||||
noSo: _noSoCtrl.text,
|
||||
noDo: _noDoCtrl.text,
|
||||
kepadaYth: _kepadaYthCtrl.text,
|
||||
orderUntuk: _orderUntukCtrl.text,
|
||||
alamat: _alamatCtrl.text,
|
||||
platTruk: _platTrukCtrl.text,
|
||||
namaDriver: _namaDriverCtrl.text,
|
||||
namaPenerima: _namaPenerimaCtrl.text,
|
||||
latitude: finalLat,
|
||||
longitude: finalLng,
|
||||
items: _itemControllers.map((ctrls) => DocumentItem(
|
||||
nomorSku: ctrls['sku']!.text,
|
||||
namaBarang: ctrls['nama']!.text,
|
||||
banyak: ctrls['banyak']!.text,
|
||||
jumlah: ctrls['jumlah']!.text,
|
||||
)).toList(),
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
|
||||
final localStorage = ref.read(localStorageProvider);
|
||||
await localStorage.saveDocument(finalDoc);
|
||||
|
||||
bool syncedToServer = false;
|
||||
String? syncError;
|
||||
try {
|
||||
await apiClient.client.put(
|
||||
'${AppConfig.fetchDocumentsEndpoint}/${finalDoc.id}',
|
||||
data: finalDoc.toPutPayload(),
|
||||
);
|
||||
syncedToServer = true;
|
||||
} catch (e) {
|
||||
syncError = ApiException.from(e).displayMessage;
|
||||
}
|
||||
|
||||
if (widget.pendingId != null) {
|
||||
if (syncedToServer) {
|
||||
ref.read(pendingDocumentsProvider.notifier).removeDocument(widget.pendingId!);
|
||||
} else {
|
||||
ref.read(pendingDocumentsProvider.notifier).markSyncFailed(
|
||||
widget.pendingId!,
|
||||
finalDoc,
|
||||
'Belum tersinkron ke server: $syncError',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
syncedToServer
|
||||
? const SnackBar(content: Text('Dokumen Berhasil Disimpan!'), backgroundColor: AppConfig.successColor)
|
||||
: const SnackBar(
|
||||
content: Text('Tersimpan lokal, tapi GAGAL sinkron ke server. Cek koneksi lalu retry dari daftar dokumen.'),
|
||||
backgroundColor: Colors.deepOrange,
|
||||
duration: Duration(seconds: 5),
|
||||
),
|
||||
);
|
||||
context.pop(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
part of 'editor_screen.dart';
|
||||
|
||||
mixin EditorLogic on ConsumerState<EditorScreen> {
|
||||
DocumentModel? _document;
|
||||
|
||||
// Controllers
|
||||
final _tanggalCtrl = TextEditingController();
|
||||
final _noPoCtrl = TextEditingController();
|
||||
final _noSoCtrl = TextEditingController();
|
||||
final _noDoCtrl = TextEditingController();
|
||||
|
||||
final _kepadaYthCtrl = TextEditingController();
|
||||
final _orderUntukCtrl = TextEditingController();
|
||||
final _alamatCtrl = TextEditingController();
|
||||
final _platTrukCtrl = TextEditingController();
|
||||
final _namaDriverCtrl = TextEditingController();
|
||||
final _namaPenerimaCtrl = TextEditingController();
|
||||
|
||||
final _latitudeCtrl = TextEditingController();
|
||||
final _longitudeCtrl = TextEditingController();
|
||||
|
||||
List<Map<String, TextEditingController>> _itemControllers = [];
|
||||
bool _isAgreed = false;
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
|
||||
void _loadDocumentData() {
|
||||
if (widget.pendingId == null) return;
|
||||
|
||||
final pendingDocs = ref.read(pendingDocumentsProvider);
|
||||
final pendingDoc = pendingDocs.firstWhere(
|
||||
(doc) => doc.id == widget.pendingId,
|
||||
orElse: () => PendingDocument(id: '', imagePath: '')
|
||||
);
|
||||
|
||||
if (pendingDoc.document != null) {
|
||||
final doc = pendingDoc.document!;
|
||||
setState(() {
|
||||
_document = doc;
|
||||
_tanggalCtrl.text = doc.tanggal;
|
||||
_noPoCtrl.text = doc.noPo;
|
||||
_noSoCtrl.text = doc.noSo;
|
||||
_noDoCtrl.text = doc.noDo;
|
||||
|
||||
_kepadaYthCtrl.text = doc.kepadaYth;
|
||||
_orderUntukCtrl.text = doc.orderUntuk;
|
||||
_alamatCtrl.text = doc.alamat;
|
||||
_platTrukCtrl.text = doc.platTruk;
|
||||
_namaDriverCtrl.text = doc.namaDriver;
|
||||
|
||||
final lat = pendingDoc.latitude ?? doc.latitude;
|
||||
final lng = pendingDoc.longitude ?? doc.longitude;
|
||||
_latitudeCtrl.text = lat != null ? lat.toString() : '-';
|
||||
_longitudeCtrl.text = lng != null ? lng.toString() : '-';
|
||||
|
||||
for (var item in doc.items) {
|
||||
_addItem(
|
||||
sku: item.nomorSku,
|
||||
nama: item.namaBarang,
|
||||
banyak: item.banyak,
|
||||
jumlah: item.jumlah,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _addItem({String sku = '', String nama = '', String banyak = '', String jumlah = ''}) {
|
||||
final skuCtrl = TextEditingController(text: sku);
|
||||
final namaCtrl = TextEditingController(text: nama);
|
||||
final banyakCtrl = TextEditingController(text: banyak);
|
||||
final jumlahCtrl = TextEditingController(text: jumlah);
|
||||
|
||||
setState(() {
|
||||
_itemControllers.add({
|
||||
'sku': skuCtrl,
|
||||
'nama': namaCtrl,
|
||||
'banyak': banyakCtrl,
|
||||
'jumlah': jumlahCtrl,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void _removeItem(int index) {
|
||||
setState(() {
|
||||
final ctrls = _itemControllers[index];
|
||||
ctrls['sku']?.dispose();
|
||||
ctrls['nama']?.dispose();
|
||||
ctrls['banyak']?.dispose();
|
||||
ctrls['jumlah']?.dispose();
|
||||
_itemControllers.removeAt(index);
|
||||
});
|
||||
}
|
||||
|
||||
void _showConfirmationDialog() {
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
||||
),
|
||||
builder: (context) {
|
||||
return ConfirmationDialog(
|
||||
nameController: _namaPenerimaCtrl,
|
||||
initialAgreed: _isAgreed,
|
||||
onConfirm: (agreed, name) {
|
||||
setState(() {
|
||||
_isAgreed = agreed;
|
||||
});
|
||||
Navigator.pop(context);
|
||||
_submitDocument();
|
||||
},
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _submitDocument() async {
|
||||
final pendingDocs = ref.read(pendingDocumentsProvider);
|
||||
final pendingDoc = pendingDocs.firstWhere(
|
||||
(doc) => doc.id == widget.pendingId,
|
||||
orElse: () => PendingDocument(id: '', imagePath: '')
|
||||
);
|
||||
final double? finalLat = pendingDoc.latitude ?? _document?.latitude;
|
||||
final double? finalLng = pendingDoc.longitude ?? _document?.longitude;
|
||||
|
||||
final saveAction = resolveDocumentSaveAction(
|
||||
existingDocument: _document,
|
||||
localImagePath: pendingDoc.imagePath,
|
||||
);
|
||||
|
||||
if (saveAction.kind == DocumentSaveActionKind.blocked) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(saveAction.blockedMessage!),
|
||||
backgroundColor: AppConfig.errorColor,
|
||||
duration: const Duration(seconds: 5),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final apiClient = ref.read(apiClientProvider);
|
||||
String serverId;
|
||||
if (saveAction.kind == DocumentSaveActionKind.reuploadThenPut) {
|
||||
try {
|
||||
final formData = FormData.fromMap({
|
||||
'image': await MultipartFile.fromFile(
|
||||
pendingDoc.imagePath,
|
||||
filename: pendingDoc.imagePath.split(RegExp(r'[/\\]')).last,
|
||||
),
|
||||
if (finalLat != null) 'latitude': finalLat.toString(),
|
||||
if (finalLng != null) 'longitude': finalLng.toString(),
|
||||
'scan_mode': pendingDoc.scanMode ?? 'DO',
|
||||
});
|
||||
final response = await apiClient.client.post(AppConfig.uploadDocumentEndpoint, data: formData);
|
||||
serverId = DocumentModel.fromJson(response.data['data']).id;
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Gagal membuat dokumen di server: ${ApiException.from(e).displayMessage}'),
|
||||
backgroundColor: AppConfig.errorColor,
|
||||
duration: const Duration(seconds: 5),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
serverId = saveAction.serverId!;
|
||||
}
|
||||
|
||||
final finalDoc = DocumentModel(
|
||||
id: serverId,
|
||||
tanggal: _tanggalCtrl.text,
|
||||
noPo: _noPoCtrl.text,
|
||||
noSo: _noSoCtrl.text,
|
||||
noDo: _noDoCtrl.text,
|
||||
kepadaYth: _kepadaYthCtrl.text,
|
||||
orderUntuk: _orderUntukCtrl.text,
|
||||
alamat: _alamatCtrl.text,
|
||||
platTruk: _platTrukCtrl.text,
|
||||
namaDriver: _namaDriverCtrl.text,
|
||||
namaPenerima: _namaPenerimaCtrl.text,
|
||||
latitude: finalLat,
|
||||
longitude: finalLng,
|
||||
items: _itemControllers.map((ctrls) => DocumentItem(
|
||||
nomorSku: ctrls['sku']!.text,
|
||||
namaBarang: ctrls['nama']!.text,
|
||||
banyak: ctrls['banyak']!.text,
|
||||
jumlah: ctrls['jumlah']!.text,
|
||||
)).toList(),
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
|
||||
final localStorage = ref.read(localStorageProvider);
|
||||
await localStorage.saveDocument(finalDoc);
|
||||
|
||||
bool syncedToServer = false;
|
||||
String? syncError;
|
||||
try {
|
||||
await apiClient.client.put(
|
||||
'${AppConfig.fetchDocumentsEndpoint}/${finalDoc.id}',
|
||||
data: finalDoc.toPutPayload(),
|
||||
);
|
||||
syncedToServer = true;
|
||||
} catch (e) {
|
||||
syncError = ApiException.from(e).displayMessage;
|
||||
}
|
||||
|
||||
if (widget.pendingId != null) {
|
||||
if (syncedToServer) {
|
||||
ref.read(pendingDocumentsProvider.notifier).removeDocument(widget.pendingId!);
|
||||
} else {
|
||||
ref.read(pendingDocumentsProvider.notifier).markSyncFailed(
|
||||
widget.pendingId!,
|
||||
finalDoc,
|
||||
'Belum tersinkron ke server: $syncError',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
syncedToServer
|
||||
? const SnackBar(content: Text('Dokumen Berhasil Disimpan!'), backgroundColor: AppConfig.successColor)
|
||||
: const SnackBar(
|
||||
content: Text('Tersimpan lokal, tapi GAGAL sinkron ke server. Cek koneksi lalu retry dari daftar dokumen.'),
|
||||
backgroundColor: Colors.deepOrange,
|
||||
duration: Duration(seconds: 5),
|
||||
),
|
||||
);
|
||||
context.pop(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user