diff --git a/android/app/build.gradle b/android/app/build.gradle index 8a78638..b3d33dd 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -22,6 +22,13 @@ if (flutterVersionName == null) { flutterVersionName = '1.0' } +// // baru push apps +def keystoreProperties = new Properties() +def keystorePropertiesFile = rootProject.file('key.properties') +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) +} + android { namespace "com.example.siopas" compileSdkVersion flutter.compileSdkVersion @@ -46,17 +53,34 @@ android { // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. // minSdkVersion flutter.minSdkVersion - minSdkVersion 20 + minSdkVersion 21 targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName } +// original + // buildTypes { + // release { + // // TODO: Add your own signing config for the release build. + // // Signing with the debug keys for now, so `flutter run --release` works. + // signingConfig signingConfigs.debug + // } + // } + + // baru push apps + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null + storePassword keystoreProperties['storePassword'] + } + } + buildTypes { release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug + signingConfig signingConfigs.release } } } @@ -65,4 +89,6 @@ flutter { source '../..' } -dependencies {} +dependencies { + implementation 'com.google.android.material:material:1.9.0' +} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 6345584..1e0f65f 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ + - + diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index 94b8f71..b23dd73 100644 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index feb2461..3bc4db3 100644 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 0318c6d..8988b50 100644 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index 5346a4d..f672a61 100644 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 31b8796..e9b9a28 100644 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml deleted file mode 100644 index ab98328..0000000 --- a/android/app/src/main/res/values/colors.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - #ffffff - \ No newline at end of file diff --git a/assets/img/logo_siopas_apps.png b/assets/img/logo_siopas_apps.png new file mode 100644 index 0000000..1ca52ff Binary files /dev/null and b/assets/img/logo_siopas_apps.png differ diff --git a/assets/img/putih.png b/assets/img/putih.png new file mode 100644 index 0000000..3c3ad5c Binary files /dev/null and b/assets/img/putih.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png index 6f02f64..739e117 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index cd2103f..2ea907f 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index 208e4bf..774cada 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index f4b6ce8..404ea1d 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 8fb6a2a..30cfffa 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index 55836bc..b573852 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index f474548..ae6cebf 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 208e4bf..774cada 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 2843a7c..4e4a0b2 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index 533094e..c28c9b1 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png index 133f724..55f3c34 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png index ba6764f..1492a12 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png index 263d2fe..63c536f 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png index 35f5050..e24eef2 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index 533094e..c28c9b1 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index 036e85c..b397eda 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png index 94b8f71..b23dd73 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png index 5346a4d..f672a61 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index 57d9a73..da37c5d 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index 09f6152..8667d3f 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index 7d1f591..e4c0663 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/lib/migrations/databasehelper.dart b/lib/migrations/databasehelper.dart index ee8870c..570c706 100644 --- a/lib/migrations/databasehelper.dart +++ b/lib/migrations/databasehelper.dart @@ -196,22 +196,14 @@ class SqfliteDatabaseHelper { await db.execute(""" CREATE TABLE $petiTable ( id INTEGER PRIMARY KEY AUTOINCREMENT, - tipe_peti_id INTEGER NULL, - warna TEXT NULL, fix_lot TEXT NULL, - packing_no INTEGER NULL, customer_id INTEGER NULL, - jumlah INTEGER NULL, - date_pembuatan DATETIME NULL, warehouse_id INTEGER NULL, kondisipeti_id INTEGER NULL, status TEXT NULL, created_at TIMESTAMP NULL, updated_at TIMESTAMP NULL, deleted_at TIMESTAMP NULL, - created_by TEXT NULL, - updated_by TEXT NULL, - FOREIGN KEY (tipe_peti_id) REFERENCES $typePetiTable(id), FOREIGN KEY (customer_id) REFERENCES $customerTable(id), FOREIGN KEY (warehouse_id) REFERENCES $warehouseTable(id) ); diff --git a/lib/models/m_asset_status_model.dart b/lib/models/m_asset_status_model.dart index 0d095b3..79440e5 100644 --- a/lib/models/m_asset_status_model.dart +++ b/lib/models/m_asset_status_model.dart @@ -14,9 +14,6 @@ class PetiAssetModel { int? warehouse_id; int? kondisipeti_id; String? status; - // WarehouseModel? warehouse; - // TypePetiModel? tipe_peti; - // CustomerModel? customer; String? created_by; String? updated_by; @@ -33,9 +30,6 @@ class PetiAssetModel { this.customer_id, this.jumlah, this.date_pembuatan, - // this.warehouse, - // this.tipe_peti, - // this.customer, this.warehouse_id, this.kondisipeti_id, this.status, @@ -44,7 +38,6 @@ class PetiAssetModel { this.created_at, this.updated_at, this.deleted_at, - // required this.warehouse, }); factory PetiAssetModel.fromJson(Map json) { @@ -73,15 +66,6 @@ class PetiAssetModel { date_pembuatan: json['date_pembuatan'] != null ? DateTime.parse(json['date_pembuatan'].toString()) : null, - // warehouse: json['warehouse'] != null - // ? WarehouseModel.fromJson(json['warehouse']) - // : null, - // tipe_peti: json['tipe_peti'] != null - // ? TypePetiModel.fromJson(json['tipe_peti']) - // : null, - // customer: json['customer'] != null - // ? CustomerModel.fromJson(json['customer']) - // : null, created_by: json['created_by'] != null ? json['created_by'].toString() : json['created_by'], @@ -112,9 +96,6 @@ class PetiAssetModel { 'status': status, 'jumlah': jumlah, 'date_pembuatan': date_pembuatan!.toIso8601String(), - // 'warehouse': warehouse != null ? warehouse!.toJson() : null, - // 'customer': customer != null ? customer!.toJson() : null, - // 'tipe_peti': tipe_peti != null ? tipe_peti!.toJson() : null, 'created_by': created_by, 'updated_by': updated_by, 'created_at': created_at!.toIso8601String(), diff --git a/lib/pages/home/home_page.dart b/lib/pages/home/home_page.dart index 47ddefd..0383451 100644 --- a/lib/pages/home/home_page.dart +++ b/lib/pages/home/home_page.dart @@ -53,25 +53,34 @@ class _HomePageState extends State { List? _tipePetiData; List? _customerData; List? _warehouseData; - bool _isLoading = false; Timer? _timer; + bool _isLoading = true; + @override void initState() { super.initState(); _getUserToken(); - warehouseListAPI(); - typePetiListAPI(); - customerListAPI(); - petiListAPI(); - - // Tampil data Datatables - datatablesAssetStatusList(); - datatablesPetiList(); - datatablesTipePetiList(); - datatablesCustomerList(); - datatablesWarehouseList(); + // Menerapkan Future untuk menangani tugas asinkronus + Future.wait([ + warehouseListAPI(), + typePetiListAPI(), + customerListAPI(), + petiListAPI(), + datatablesAssetStatusList(), + datatablesPetiList(), + datatablesTipePetiList(), + datatablesCustomerList(), + datatablesWarehouseList(), + ]).then((_) { + // Selesaikan loading setelah semua tugas selesai + setState(() { + _isLoading = false; + }); + }); + + // Inisialisasi _data di sini jika diperlukan _data = []; } @@ -152,10 +161,16 @@ class _HomePageState extends State { EasyLoading.show(status: 'Mengambil data Peti...'); List petiApiData = await SyncronizationDataAPI().fetchPetiFromApi(); + await ControllerApi() .deleteAllPetiDataAPI(); // Clear existing data in SQLite - await ControllerApi() - .addAllPetiDataAPI(petiApiData); // Add new data to SQLite + + // Menentukan ukuran chunk, misalnya 100 + int chunkSize = 100; + + // Memasukkan data ke SQLite dengan menggunakan chunk + await ControllerApi().addAllPetiDataAPI(petiApiData, chunkSize); + EasyLoading.dismiss(); } diff --git a/lib/pages/home/setting_page.dart b/lib/pages/home/setting_page.dart index 760aa87..045090e 100644 --- a/lib/pages/home/setting_page.dart +++ b/lib/pages/home/setting_page.dart @@ -43,23 +43,75 @@ class SettingPageState extends State { bool? confirm = await showDialog( context: context, builder: (BuildContext context) { - return AlertDialog( - title: Text('Konfirmasi Logout'), - content: Text('Apakah Anda yakin ingin logout?'), - actions: [ - TextButton( - child: Text('Tidak'), - onPressed: () { - Navigator.of(context).pop(false); - }, + return Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.0), + ), + elevation: 0, + backgroundColor: Colors.transparent, + child: Container( + padding: EdgeInsets.all(20), + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: Colors.white, + borderRadius: BorderRadius.circular(16.0), ), - TextButton( - child: Text('Ya'), - onPressed: () { - Navigator.of(context).pop(true); - }, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Konfirmasi Keluar Akun', + style: TextStyle( + fontSize: 16, fontWeight: FontWeight.w600), + ), + IconButton( + icon: Icon(Icons.close), + onPressed: () { + Navigator.of(context).pop(false); + }, + ), + ], + ), + Divider( + height: 10, + thickness: 5, + ), + SizedBox( + height: 15, + ), + Text( + 'Apakah Anda yakin ingin keluar akun?', + style: TextStyle(fontSize: 14), + textAlign: TextAlign.center, + ), + SizedBox( + height: 22, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox(width: 16), + TextButton.icon( + onPressed: () { + Navigator.of(context).pop(true); + }, + icon: Icon( + Icons.exit_to_app, + color: Colors.red, + ), + label: Text( + 'Keluar', + style: TextStyle(color: Colors.red), + ), + ), + ], + ), + ], ), - ], + ), ); }, ); diff --git a/lib/pages/peminjaman_barang/conn/syncronize.dart b/lib/pages/peminjaman_barang/conn/syncronize.dart index 1fd92a9..46f95b1 100644 --- a/lib/pages/peminjaman_barang/conn/syncronize.dart +++ b/lib/pages/peminjaman_barang/conn/syncronize.dart @@ -83,9 +83,69 @@ class SyncronizationPeminjamanData { await dbClient!.delete(SqfliteDatabaseHelper.peminjamanTable); } - Future saveToPeminjamanWith( + // Future saveToPeminjamanWith( + // List assetStatusesLocalList) async { + // for (var i = 0; i < assetStatusesLocalList.length; i++) { + // DateTime? parseDateTime(String? dateTimeString) { + // if (dateTimeString == null || dateTimeString.isEmpty) { + // return null; + // } + + // try { + // return DateTime.parse(dateTimeString); + // } catch (e) { + // print('Error parsing DateTime: $e'); + // return null; + // } + // } + + // // Format tanggal sesuai kebutuhan + // String formattedCreatedAt = assetStatusesLocalList[i].created_at != null + // ? DateFormat('yyyy-MM-dd HH:mm:ss.SSS') + // .format(assetStatusesLocalList[i].created_at!) + // : DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(DateTime.now()); + + // Map data = { + // "mobile_id": assetStatusesLocalList[i].mobile_id.toString(), + // "peti_id": assetStatusesLocalList[i].peti_id.toString(), + // "customer_id": assetStatusesLocalList[i].customer_id.toString(), + // "warehouse_id": assetStatusesLocalList[i].warehouse_id.toString(), + // "exit_at": assetStatusesLocalList[i].exit_at.toString(), + // "est_pengembalian": + // assetStatusesLocalList[i].est_pengembalian.toString(), + // "exit_pic": assetStatusesLocalList[i].exit_pic.toString(), + // "exit_warehouse": assetStatusesLocalList[i].exit_warehouse.toString(), + // "created_by": assetStatusesLocalList[i].created_by.toString(), + // "created_at": formattedCreatedAt, + // }; + + // final response = await http.post( + // Uri.parse(await getBaseUrl() + '/asset-status/store'), + // body: data, + // ); + + // if (response.statusCode == 200) { + // // print("Data uploaded successfully for index $i:"); + // // print("Response body: ${response.body}"); + // print("Saving Data saveToMysqlWith"); + // } else { + // print( + // "Failed to upload data for index $i. Status code: ${response.statusCode}"); + // print("Response body: ${response.body}"); + // } + // } + + // return true; // Pengunggahan berhasil + // } + + Future saveToPeminjamanWith( List assetStatusesLocalList) async { - for (var i = 0; i < assetStatusesLocalList.length; i++) { + const maxRequestsBeforeDelay = 25; + const delayDuration = Duration(seconds: 3); + + int requestCounter = 0; + + await Future.forEach(assetStatusesLocalList, (assetStatus) async { DateTime? parseDateTime(String? dateTimeString) { if (dateTimeString == null || dateTimeString.isEmpty) { return null; @@ -100,22 +160,21 @@ class SyncronizationPeminjamanData { } // Format tanggal sesuai kebutuhan - String formattedCreatedAt = assetStatusesLocalList[i].created_at != null + String formattedCreatedAt = assetStatus.created_at != null ? DateFormat('yyyy-MM-dd HH:mm:ss.SSS') - .format(assetStatusesLocalList[i].created_at!) + .format(assetStatus.created_at!) : DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(DateTime.now()); Map data = { - "mobile_id": assetStatusesLocalList[i].mobile_id.toString(), - "peti_id": assetStatusesLocalList[i].peti_id.toString(), - "customer_id": assetStatusesLocalList[i].customer_id.toString(), - "warehouse_id": assetStatusesLocalList[i].warehouse_id.toString(), - "exit_at": assetStatusesLocalList[i].exit_at.toString(), - "est_pengembalian": - assetStatusesLocalList[i].est_pengembalian.toString(), - "exit_pic": assetStatusesLocalList[i].exit_pic.toString(), - "exit_warehouse": assetStatusesLocalList[i].exit_warehouse.toString(), - "created_by": assetStatusesLocalList[i].created_by.toString(), + "mobile_id": assetStatus.mobile_id.toString(), + "peti_id": assetStatus.peti_id.toString(), + "customer_id": assetStatus.customer_id.toString(), + "warehouse_id": assetStatus.warehouse_id.toString(), + "exit_at": assetStatus.exit_at.toString(), + "est_pengembalian": assetStatus.est_pengembalian.toString(), + "exit_pic": assetStatus.exit_pic.toString(), + "exit_warehouse": assetStatus.exit_warehouse.toString(), + "created_by": assetStatus.created_by.toString(), "created_at": formattedCreatedAt, }; @@ -125,15 +184,21 @@ class SyncronizationPeminjamanData { ); if (response.statusCode == 200) { - // print("Data uploaded successfully for index $i:"); - // print("Response body: ${response.body}"); print("Saving Data saveToMysqlWith"); } else { - print( - "Failed to upload data for index $i. Status code: ${response.statusCode}"); + print("Failed to upload data. Status code: ${response.statusCode}"); print("Response body: ${response.body}"); } - } + + // Increment counter + requestCounter++; + + // Jeda 2 detik setiap 30 permintaan + if (requestCounter % maxRequestsBeforeDelay == 0 && + requestCounter != assetStatusesLocalList.length) { + await Future.delayed(delayDuration); + } + }); return true; // Pengunggahan berhasil } diff --git a/lib/pages/peminjaman_barang/controller/peminjaman_controller.dart b/lib/pages/peminjaman_barang/controller/peminjaman_controller.dart index 6605b56..00a8d47 100644 --- a/lib/pages/peminjaman_barang/controller/peminjaman_controller.dart +++ b/lib/pages/peminjaman_barang/controller/peminjaman_controller.dart @@ -108,6 +108,20 @@ class Controller { return peminjamanList; } + Future deletePeminjamanById(String id) async { + var dbclient = await conn.db; + try { + await dbclient!.delete( + SqfliteDatabaseHelper.peminjamanTable, + where: 'id = ?', + whereArgs: [id], + ); + } catch (e) { + print('Gagal menghapus peminjaman dari database: $e'); + throw Exception('Gagal menghapus peminjaman'); + } + } + Future deleteAllData() async { var dbClient = await conn.db; await dbClient!.delete(SqfliteDatabaseHelper.peminjamanTable); diff --git a/lib/pages/peminjaman_barang/create.dart b/lib/pages/peminjaman_barang/create.dart index 15c5bc7..de56968 100644 --- a/lib/pages/peminjaman_barang/create.dart +++ b/lib/pages/peminjaman_barang/create.dart @@ -19,6 +19,7 @@ import 'package:siopas/models/warehouse_mode.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:intl/date_symbol_data_local.dart'; // Import package intl import 'package:uuid/uuid.dart'; +import 'package:dropdown_search/dropdown_search.dart'; import '../../connection/connection.dart'; import 'package:http/http.dart' as http; @@ -58,7 +59,10 @@ class _CreatePeminjamanBarangState extends State { List _filteredPetiList = []; bool isQRCodeScanned = false; - bool loading = true; + String searchText = ''; + PetiAssetModel? selectedPeti; + TextEditingController searchBoxController = TextEditingController(); + TextEditingController _exit_atController = TextEditingController(); TextEditingController _est_pengembalianController = TextEditingController(); TextEditingController _penanggungJawabController = TextEditingController(); @@ -68,6 +72,8 @@ class _CreatePeminjamanBarangState extends State { Barcode? result; QRViewController? controller; + bool loading = true; + @override void initState() { super.initState(); @@ -76,8 +82,11 @@ class _CreatePeminjamanBarangState extends State { petiListAPI(); disposalListAPI(); customerListAPI(); - initializeDateFormatting('id_ID', null); + + setState(() { + loading = false; // Mengatur loading ke false setelah tugas selesai + }); } void _getUserToken() async { @@ -537,7 +546,7 @@ class _CreatePeminjamanBarangState extends State { automaticallyImplyLeading: false, backgroundColor: Colors.indigo[700], elevation: 0, - title: Text('Buat Peminjaman Barang', + title: Text('Buat Peminjaman Peti', style: TextStyle( fontSize: 16, )), @@ -558,106 +567,130 @@ class _CreatePeminjamanBarangState extends State { elevation: 2, child: Container( margin: EdgeInsets.all(8), - child: - // DropdownButtonFormField( - // validator: (value) { - // if (value == null) { - // return 'Harus diisi'; - // } - // return null; - // }, - // decoration: InputDecoration( - // labelText: 'Peti', - // border: OutlineInputBorder(), - // ), - // hint: Text("Pilih Peti"), - // value: petiSqfliteApi, - // items: (_valpeti ?? []) - // .where((peti) => - // peti.deleted_at != true && - // (peti.warehouse_id == - // user.warehouse_id) && - // (peti.status == 'AKTIF')) - // .map((PetiAssetModel peti) { - // return DropdownMenuItem( - // child: Text( - // '${peti.fix_lot}', // Menampilkan warehouse_id - // style: TextStyle( - // fontSize: 12, - // ), - // ), - // value: peti, - // ); - // }).toList(), - // onChanged: (PetiAssetModel? value) { - // setState( - // () { - // petiSqfliteApi = value; - // if (value != null) { - // warehouseSqfliteApi = - // _valwarehouse?.firstWhere( - // (warehouse) => - // warehouse.id == - // value.warehouse_id, - // ); - // customerSqfliteApi = - // _valcustomer?.firstWhereOrNull( - // (customer) => - // customer.id == - // value.customer_id, - // ); - // } - // }, - // ); - // }, - // ), - - DropdownButtonFormField( - validator: (value) { - if (value == null) { - return 'Harus diisi'; - } - return null; - }, - decoration: InputDecoration( - labelText: 'Peti', - border: OutlineInputBorder(), + child: DropdownSearch( + popupProps: PopupProps.bottomSheet( + showSearchBox: true, + itemBuilder: (context, PetiAssetModel? peti, + bool? isSelected) { + if (peti == null) { + return SizedBox.shrink(); + } + // 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, + ); + }, + 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: () { + Navigator.pop(context); + }, + ), + ], + ), + Divider(), + ], + ), + ), ), - hint: Text("Pilih Peti"), - value: petiSqfliteApi, - items: (isQRCodeScanned - ? _filteredPetiList - : (_valpeti ?? []).where((peti) => - peti.deleted_at != true && - (peti.warehouse_id == - user.warehouse_id) && - (peti.status == 'AKTIF'))) - .map((PetiAssetModel peti) { - return DropdownMenuItem( - child: Text( - '${peti.fix_lot}', - style: TextStyle( - fontSize: 12, + + dropdownDecoratorProps: + DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + labelText: 'Pilih Peti', + border: OutlineInputBorder( + borderRadius: BorderRadius.all( + Radius.circular(5.0), ), ), - value: peti, - ); - }).toList(), + ), + ), + + items: (isQRCodeScanned + ? _filteredPetiList + : (_valpeti ?? []).where((peti) => + peti.deleted_at != true && + (peti.warehouse_id == + user.warehouse_id) && + (peti.status == 'AKTIF'))) + .where((peti) => peti.fix_lot! + .toLowerCase() + .contains(searchBoxController.text + .toLowerCase())) + .toList() ?? + [], + // searchBoxController: searchBoxController, + itemAsString: (PetiAssetModel item) => + item.fix_lot ?? + "", // Ganti dengan properti yang sesuai + + selectedItem: petiSqfliteApi, + onChanged: (PetiAssetModel? value) { setState(() { petiSqfliteApi = value; if (value != null) { - warehouseSqfliteApi = - _valwarehouse?.firstWhere( - (warehouse) => - warehouse.id == - value.warehouse_id, - ); - customerSqfliteApi = - _valcustomer?.firstWhereOrNull( - (customer) => - customer.id == value.customer_id, - ); + warehouseSqfliteApi = _valwarehouse + ?.firstWhere((warehouse) => + warehouse.id == + value.warehouse_id); + customerSqfliteApi = _valcustomer + ?.firstWhereOrNull((customer) => + customer.id == + value.customer_id); // Perbarui _unrestrictedPetiList sesuai pemilihan manual _unrestrictedPetiList = [ @@ -667,6 +700,12 @@ class _CreatePeminjamanBarangState extends State { } }); }, + validator: (PetiAssetModel? value) { + if (value == null) { + return 'Harus diisi'; + } + return null; + }, ), ), ), @@ -751,39 +790,112 @@ class _CreatePeminjamanBarangState extends State { elevation: 2, child: Padding( padding: const EdgeInsets.all(8), - child: DropdownButtonFormField( - validator: (value) { - if (value == null) { - return 'Harus diisi'; - } - return null; - }, - decoration: InputDecoration( - labelText: 'Customer', - border: OutlineInputBorder(), + child: DropdownSearch( + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + labelText: 'Pilih Customer', + border: OutlineInputBorder( + borderRadius: BorderRadius.all( + Radius.circular(5.0), + ), + ), + ), ), - hint: Text("Pilih Customer"), - value: customerSqfliteApi, - items: (_valcustomer ?? []) - .where( - (customer) => customer.deleted_at != true) - .map((CustomerModel customer) { - return DropdownMenuItem( - child: Text( - '${customer.name}', // Menampilkan warehouse_id - style: TextStyle( - fontSize: 12, + popupProps: PopupProps.bottomSheet( + showSearchBox: true, + itemBuilder: (context, CustomerModel? customer, + bool? isSelected) { + if (customer == null) { + return SizedBox.shrink(); + } + + return Container( + child: Column( + children: [ + ListTile( + title: Text( + customer.name.toString(), + style: TextStyle( + fontSize: 16, + fontFamily: 'OpenSansCondensed', + ), + ), + leading: Icon( + Icons.person_pin, + size: 24, + color: customer.id == + customerSqfliteApi?.id + ? Colors.indigo[700] + : Colors.grey, + ), + ), + Divider( + height: 1, + color: Colors + .grey, // Warna pembatas (divider) + ), + ], ), + color: customer.id == customerSqfliteApi?.id + ? Colors.grey.withOpacity(0.7) + : Colors.white, + ); + }, + fit: FlexFit.loose, + title: Padding( + padding: EdgeInsets.all(8.0), + child: Column( + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Pilih Customer', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold), + ), + IconButton( + icon: Icon( + Icons.close, + color: Colors.red, + ), + onPressed: () { + Navigator.pop(context); + }, + ), + ], + ), + Divider(), + ], ), - value: customer, - ); - }).toList(), + ), + ), + + items: (_valcustomer ?? []) + .where((customer) => + customer.deleted_at != true) + .where((customer) => customer.name! + .toLowerCase() + .contains(searchBoxController.text + .toLowerCase())) + .toList() ?? + [], + itemAsString: (CustomerModel customer) => + customer.name ?? + "", // Ganti dengan properti yang sesuai + selectedItem: customerSqfliteApi, onChanged: (CustomerModel? value) { - setState( - () { - customerSqfliteApi = value; - }, - ); + setState(() { + customerSqfliteApi = value; + }); + }, + validator: (CustomerModel? value) { + if (value == null) { + return 'Harus diisi'; + } + return null; }, ), ), @@ -794,6 +906,28 @@ class _CreatePeminjamanBarangState extends State { child: Padding( padding: const EdgeInsets.all(8), child: FormBuilderDateTimePicker( + validator: (value) { + if (_exit_atController.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: Colors.redAccent[700], + content: Row( + children: [ + Icon( + Icons.error_outline, + color: Colors.white, + ), + SizedBox(width: 5), + Text('Tanggal Peminjaman harus diisi'), + ], + ), + duration: Duration(seconds: 2), + ), + ); + return null; // Return null jika ada kesalahan + } + return null; // Return null jika tidak ada kesalahan + }, controller: _exit_atController, name: 'tanggal_peminjaman', inputType: InputType.date, @@ -840,6 +974,30 @@ class _CreatePeminjamanBarangState extends State { Padding( padding: const EdgeInsets.all(8), child: FormBuilderDateTimePicker( + validator: (value) { + if (_est_pengembalianController + .text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: Colors.redAccent[700], + content: Row( + children: [ + Icon( + Icons.error_outline, + color: Colors.white, + ), + SizedBox(width: 5), + Text( + 'Tanggal Estimasi Pengembalian harus diisi'), + ], + ), + duration: Duration(seconds: 2), + ), + ); + return null; // Return null jika ada kesalahan + } + return null; // Return null jika tidak ada kesalahan + }, controller: _est_pengembalianController, name: 'estimasi_pengembalian', inputType: InputType.date, @@ -899,7 +1057,27 @@ class _CreatePeminjamanBarangState extends State { // _valwarehouse?.map((WarehouseModel warehouse) { return DropdownMenuItem( - child: Text('${warehouse.name}'), + child: Row( + children: [ + Icon( + Icons.warehouse, + color: warehouse.id == + warehouseSqfliteApi?.id + ? Colors.indigo[700] + : Colors.grey, + ), + SizedBox( + width: + 8), // Jarak antara ikon dan teks + Text( + '${warehouse.name}', + style: TextStyle( + fontSize: 16, + fontFamily: 'OpenSansCondensed', + ), + ), + ], + ), value: warehouse, ); }).toList() ?? @@ -936,7 +1114,27 @@ class _CreatePeminjamanBarangState extends State { // _valwarehouse?.map((WarehouseModel warehouse) { return DropdownMenuItem( - child: Text('${warehouseTujuan.name}'), + child: Row( + children: [ + Icon( + Icons.local_shipping, + color: warehouseTujuan.id == + warehouseTujuanSqfliteApi?.id + ? Colors.green[700] + : Colors.grey, + ), + SizedBox( + width: + 8), // Jarak antara ikon dan teks + Text( + '${warehouseTujuan.name}', + style: TextStyle( + fontSize: 16, + fontFamily: 'OpenSansCondensed', + ), + ), + ], + ), value: warehouseTujuan, ); }).toList() ?? @@ -974,7 +1172,6 @@ class _CreatePeminjamanBarangState extends State { ), child: IconButton( onPressed: () { - // Navigator.pop(context); Navigator.pushNamed(context, '/peminjaman-barang'); }, icon: Icon(Icons.close, color: Colors.white), diff --git a/lib/pages/peminjaman_barang/peminjaman_stock_page.dart b/lib/pages/peminjaman_barang/peminjaman_stock_page.dart index 3fe62fd..852a539 100644 --- a/lib/pages/peminjaman_barang/peminjaman_stock_page.dart +++ b/lib/pages/peminjaman_barang/peminjaman_stock_page.dart @@ -19,6 +19,7 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'package:siopas/models/asset_status_model.dart'; import 'package:siopas/providers/asset_status_provider.dart'; import 'package:collection/collection.dart'; +import 'package:loading_animation_widget/loading_animation_widget.dart'; import '../../models/condition_peti_model.dart'; import 'show.dart'; @@ -54,26 +55,38 @@ class AssetStatusPageState extends State { List? _customerData; List? _warehouseData; - bool _isLoading = false; Timer? _timer; + bool _isLoading = false; + @override void initState() { super.initState(); _getUserToken(); - warehouseListAPI(); - typePetiListAPI(); - customerListAPI(); - petiListAPI(); - // disposalListAPI(); - - // Tampil data Datatables - datatablesAssetStatusList(); - datatablesPetiList(); - datatablesTipePetiList(); - datatablesCustomerList(); - datatablesWarehouseList(); + // Mengatur _isLoading ke true sebelum tugas dimulai + setState(() { + _isLoading = true; + }); + + Future.wait([ + warehouseListAPI(), + typePetiListAPI(), + customerListAPI(), + petiListAPI(), + datatablesAssetStatusList(), + datatablesPetiList(), + datatablesTipePetiList(), + datatablesCustomerList(), + datatablesWarehouseList(), + ]).then((_) { + // Mengatur _isLoading ke false setelah semua tugas selesai + setState(() { + _isLoading = false; + }); + }); + + // Inisialisasi _data di sini jika diperlukan _data = []; } @@ -152,16 +165,16 @@ class AssetStatusPageState extends State { } } - Future reinitAssetStatusApi() async { - EasyLoading.show(status: 'Mengambil data Asset Status...'); - List assetStatusApiData = - await SyncronizationDataAPI().fetchAssetStatusFromApi(); - await ControllerApi() - .deleteAllAssetStatusDataAPI(); // Clear existing data in SQLite - await ControllerApi() - .addAllAssetStatusDataAPI(assetStatusApiData); // Add new data to SQLite - EasyLoading.dismiss(); - } + // Future reinitAssetStatusApi() async { + // EasyLoading.show(status: 'Mengambil data Asset Status...'); + // List assetStatusApiData = + // await SyncronizationDataAPI().fetchAssetStatusFromApi(); + // await ControllerApi() + // .deleteAllAssetStatusDataAPI(); // Clear existing data in SQLite + // await ControllerApi() + // .addAllAssetStatusDataAPI(assetStatusApiData); // Add new data to SQLite + // EasyLoading.dismiss(); + // } Future reinitWarehouseApi() async { EasyLoading.show(status: 'Mengambil data Warehouse...'); @@ -178,10 +191,16 @@ class AssetStatusPageState extends State { EasyLoading.show(status: 'Mengambil data Peti...'); List petiApiData = await SyncronizationDataAPI().fetchPetiFromApi(); + await ControllerApi() .deleteAllPetiDataAPI(); // Clear existing data in SQLite - await ControllerApi() - .addAllPetiDataAPI(petiApiData); // Add new data to SQLite + + // Menentukan ukuran chunk, misalnya 100 + int chunkSize = 100; + + // Memasukkan data ke SQLite dengan menggunakan chunk + await ControllerApi().addAllPetiDataAPI(petiApiData, chunkSize); + EasyLoading.dismiss(); } @@ -257,7 +276,7 @@ class AssetStatusPageState extends State { .then((peminjamanList) async { EasyLoading.show( status: 'Jangan tutup aplikasi. Kami sedang menyinkronkan...'); - await Future.delayed(Duration(seconds: 3)); + await Future.delayed(Duration(seconds: 2)); // Tambahkan penanganan pengunggahan bool uploadSuccess = await SyncronizationPeminjamanData() @@ -475,7 +494,7 @@ class AssetStatusPageState extends State { appBar: AppBar( backgroundColor: Colors.indigo[700], elevation: 0, - title: Text('Data Peminjaman Barang', + title: Text('Data Peminjaman Peti', style: TextStyle( fontSize: 16, )), @@ -508,7 +527,12 @@ class AssetStatusPageState extends State { ), ), body: _isLoading - ? const Center(child: CircularProgressIndicator()) + ? Center( + child: LoadingAnimationWidget.staggeredDotsWave( + color: Colors.indigo, + size: 40, + ), + ) : TabBarView( children: [ SingleChildScrollView( diff --git a/lib/pages/peminjaman_barang/show.dart b/lib/pages/peminjaman_barang/show.dart index 1d88abd..ab8cc3e 100644 --- a/lib/pages/peminjaman_barang/show.dart +++ b/lib/pages/peminjaman_barang/show.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:siopas/models/asset_status_model.dart'; import 'package:siopas/models/customer_model.dart'; import 'package:siopas/models/m_asset_status_model.dart'; @@ -40,6 +41,9 @@ class _DetailPeminjamanBarangPageState petiListAPI(); warehouseListAPI(); initializeDateFormatting('id_ID', null); + setState(() { + loading = false; + }); } Future customerListAPI() async { @@ -102,6 +106,18 @@ class _DetailPeminjamanBarangPageState } } + Future _deletePeminjaman() async { + try { + // Panggil fungsi untuk menghapus peminjaman berdasarkan ID + await Controller().deletePeminjamanById(widget.peminjamanId); + // Navigasi kembali ke halaman sebelumnya atau halaman yang sesuai + Navigator.pushNamed(context, '/peminjaman-barang'); + } catch (e) { + // Tangani kesalahan jika terjadi + print('Gagal menghapus peminjaman: $e'); + } + } + @override Widget build(BuildContext context) { PetiAssetModel? petiSqfliteApi; @@ -116,20 +132,92 @@ class _DetailPeminjamanBarangPageState WarehouseModel? warehouseSqfliteApi; warehouseSqfliteApi = warehouseData?.firstWhereOrNull( - (warehouse) => warehouse.id == peminjamanInfo!.exit_warehouse, + (warehouse) => warehouse.id == peminjamanInfo!.warehouse_id, ); WarehouseModel? warehouseTujuanSqfliteApi; warehouseTujuanSqfliteApi = warehouseData?.firstWhereOrNull( (warehouse) => warehouse.id == peminjamanInfo!.exit_warehouse, ); + Future _showDeleteConfirmationDialog() async { + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.0), + ), + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Icon( + Icons.info, + color: Colors.blue, + ), + SizedBox(width: 8), + Text( + 'Konfirmasi Hapus', + style: TextStyle( + fontSize: 18, + ), + ), + ], + ), + IconButton( + icon: Icon( + Icons.close, + color: Colors.black54, + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ), + content: SingleChildScrollView( + child: ListBody( + children: [ + Text( + 'Anda yakin ingin menghapus pengembalian ini? ${petiSqfliteApi!.fix_lot.toString()}', + style: TextStyle( + fontSize: 16, + ), + ), + ], + ), + ), + actions: [ + Container( + margin: EdgeInsets.only(right: 3.0), + child: ElevatedButton( + child: Text('Hapus'), + onPressed: () { + // Panggil fungsi untuk menghapus peminjaman berdasarkan ID + _deletePeminjaman(); + Navigator.pushNamed(context, '/peminjaman-barang'); + EasyLoading.showSuccess( + 'Berhasil menghapus data peminjaman'); + }, + style: ElevatedButton.styleFrom( + primary: Colors.red, + ), + ), + ), + ], + ); + }, + ); + } + return Scaffold( backgroundColor: Colors.grey[200], appBar: AppBar( backgroundColor: Colors.indigo[700], elevation: 0, title: Text( - 'Detail Peminjaman Barang', + 'Detail Peminjaman Peti', style: TextStyle( color: Colors.white, fontSize: 16, @@ -141,6 +229,14 @@ class _DetailPeminjamanBarangPageState Navigator.pushNamed(context, '/peminjaman-barang'); }, ), + actions: [ + IconButton( + icon: Icon(Icons.delete, color: Colors.redAccent), + onPressed: () { + _showDeleteConfirmationDialog(); + }, + ), + ], ), body: Padding( padding: EdgeInsets.all(16.0), @@ -225,7 +321,7 @@ class _DetailPeminjamanBarangPageState 'PJ Peminjaman', peminjamanInfo!.exit_pic.toString()), Divider(thickness: 1), _buildDetailItem( - 'Asal Warehouse', + 'Asal Gudang', // peminjamanInfo!.exit_warehouse.toString()), warehouseSqfliteApi != null && warehouseSqfliteApi.name != null @@ -233,11 +329,11 @@ class _DetailPeminjamanBarangPageState : '-'), Divider(thickness: 1), _buildDetailItem( - 'Exit Warehouse', + 'Tujuan Gudang', // peminjamanInfo!.exit_warehouse.toString()), - warehouseSqfliteApi != null && - warehouseSqfliteApi.name != null - ? warehouseSqfliteApi!.name.toString() + warehouseTujuanSqfliteApi != null && + warehouseTujuanSqfliteApi.name != null + ? warehouseTujuanSqfliteApi!.name.toString() : '-'), Divider(thickness: 1), // ... tambahkan data lainnya sesuai kebutuhan @@ -257,9 +353,12 @@ class _DetailPeminjamanBarangPageState children: [ Text( label, - style: TextStyle(fontSize: 12.5, fontWeight: FontWeight.bold), + style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold), + ), + Text( + value, + style: TextStyle(fontSize: 12), ), - Text(value), ], ), ); diff --git a/lib/pages/pengembalian_barang/conn/syncronize.dart b/lib/pages/pengembalian_barang/conn/syncronize.dart index c69574f..d228645 100644 --- a/lib/pages/pengembalian_barang/conn/syncronize.dart +++ b/lib/pages/pengembalian_barang/conn/syncronize.dart @@ -84,9 +84,65 @@ class SyncronizationPengembalianData { await dbClient!.delete(SqfliteDatabaseHelper.pengembalianTable); } - Future savePengembalianToServerWith( + // Future savePengembalianToServerWith( + // List assetStatusesLocalList) async { + // for (var i = 0; i < assetStatusesLocalList.length; i++) { + // DateTime? parseDateTime(String? dateTimeString) { + // if (dateTimeString == null || dateTimeString.isEmpty) { + // return null; + // } + + // try { + // return DateTime.parse(dateTimeString); + // } catch (e) { + // print('Error parsing DateTime: $e'); + // return null; + // } + // } + + // // Format tanggal sesuai kebutuhan + // String formattedCreatedAt = assetStatusesLocalList[i].created_at != null + // ? DateFormat('yyyy-MM-dd HH:mm:ss.SSS') + // .format(assetStatusesLocalList[i].created_at!) + // : DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(DateTime.now()); + + // Map data = { + // "peti_id": assetStatusesLocalList[i].peti_id.toString(), + // "enter_at": assetStatusesLocalList[i].enter_at.toString(), + // "enter_pic": assetStatusesLocalList[i].enter_pic.toString(), + // "enter_warehouse": assetStatusesLocalList[i].enter_warehouse.toString(), + // "kondisi_peti_id": assetStatusesLocalList[i].kondisi_peti_id.toString(), + // "updated_by": assetStatusesLocalList[i].updated_by.toString(), + // "updated_at": formattedCreatedAt, + // }; + + // final response = await http.post( + // Uri.parse(await getBaseUrl() + '/asset-status/update'), + // body: data, + // ); + + // if (response.statusCode == 200) { + // // print("Data uploaded successfully for index $i:"); + // // print("Response body: ${response.body}"); + // print("Saving Data saveToPengembalianWith"); + // } else { + // print( + // "Failed to upload data for index $i. Status code: ${response.statusCode}"); + // print("Response body: ${response.body}"); + // } + // } + + // return true; // Pengunggahan berhasil + // } + + Future savePengembalianToServerWith( List assetStatusesLocalList) async { - for (var i = 0; i < assetStatusesLocalList.length; i++) { + const maxRequestsBeforeDelay = 25; + const delayDuration = Duration(seconds: 3); + + int requestCounter = 0; + + await Future.forEach(assetStatusesLocalList, (assetStatus) async { DateTime? parseDateTime(String? dateTimeString) { if (dateTimeString == null || dateTimeString.isEmpty) { return null; @@ -101,18 +157,18 @@ class SyncronizationPengembalianData { } // Format tanggal sesuai kebutuhan - String formattedCreatedAt = assetStatusesLocalList[i].created_at != null + String formattedCreatedAt = assetStatus.created_at != null ? DateFormat('yyyy-MM-dd HH:mm:ss.SSS') - .format(assetStatusesLocalList[i].created_at!) + .format(assetStatus.created_at!) : DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(DateTime.now()); Map data = { - "peti_id": assetStatusesLocalList[i].peti_id.toString(), - "enter_at": assetStatusesLocalList[i].enter_at.toString(), - "enter_pic": assetStatusesLocalList[i].enter_pic.toString(), - "enter_warehouse": assetStatusesLocalList[i].enter_warehouse.toString(), - "kondisi_peti_id": assetStatusesLocalList[i].kondisi_peti_id.toString(), - "updated_by": assetStatusesLocalList[i].updated_by.toString(), + "peti_id": assetStatus.peti_id.toString(), + "enter_at": assetStatus.enter_at.toString(), + "enter_pic": assetStatus.enter_pic.toString(), + "enter_warehouse": assetStatus.enter_warehouse.toString(), + "kondisi_peti_id": assetStatus.kondisi_peti_id.toString(), + "updated_by": assetStatus.updated_by.toString(), "updated_at": formattedCreatedAt, }; @@ -122,15 +178,21 @@ class SyncronizationPengembalianData { ); if (response.statusCode == 200) { - // print("Data uploaded successfully for index $i:"); - // print("Response body: ${response.body}"); print("Saving Data saveToPengembalianWith"); } else { - print( - "Failed to upload data for index $i. Status code: ${response.statusCode}"); + print("Failed to upload data. Status code: ${response.statusCode}"); print("Response body: ${response.body}"); } - } + + // Increment counter + requestCounter++; + + // Jeda 3 detik setiap 25 permintaan + if (requestCounter % maxRequestsBeforeDelay == 0 && + requestCounter != assetStatusesLocalList.length) { + await Future.delayed(delayDuration); + } + }); return true; // Pengunggahan berhasil } diff --git a/lib/pages/pengembalian_barang/controller/pengembalian_controller.dart b/lib/pages/pengembalian_barang/controller/pengembalian_controller.dart index 4971402..8dfe30d 100644 --- a/lib/pages/pengembalian_barang/controller/pengembalian_controller.dart +++ b/lib/pages/pengembalian_barang/controller/pengembalian_controller.dart @@ -110,6 +110,20 @@ class ControllerPengembalian { return pengembalianList; } + Future deletePengembalianById(String id) async { + var dbclient = await conn.db; + try { + await dbclient!.delete( + SqfliteDatabaseHelper.pengembalianTable, + where: 'id = ?', + whereArgs: [id], + ); + } catch (e) { + print('Gagal menghapus pengembalian dari database: $e'); + throw Exception('Gagal menghapus pengembalian'); + } + } + Future deleteAllData() async { var dbClient = await conn.db; await dbClient!.delete(SqfliteDatabaseHelper.pengembalianTable); diff --git a/lib/pages/pengembalian_barang/edit.dart b/lib/pages/pengembalian_barang/edit.dart index 4e14f55..5cba3a7 100644 --- a/lib/pages/pengembalian_barang/edit.dart +++ b/lib/pages/pengembalian_barang/edit.dart @@ -20,6 +20,7 @@ import 'package:siopas/models/warehouse_mode.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:intl/date_symbol_data_local.dart'; // Import package intl import 'package:uuid/uuid.dart'; +import 'package:dropdown_search/dropdown_search.dart'; import '../../connection/connection.dart'; import 'package:http/http.dart' as http; @@ -63,7 +64,8 @@ class _CreatePengembalianBarangPageState List _filteredPetiList = []; bool isQRCodeScanned = false; - bool loading = true; + TextEditingController searchBoxController = TextEditingController(); + TextEditingController _enterAtController = TextEditingController(); // TextEditingController _enterPicController = TextEditingController(); // TextEditingController _kondisiPetiController = TextEditingController(); @@ -74,19 +76,23 @@ class _CreatePengembalianBarangPageState Barcode? result; QRViewController? controller; + bool loading = true; + @override void initState() { super.initState(); _getUserToken(); warehouseListAPI(); - datatablesAssetStatusList(); // typePetiListAPI(); // customerListAPI(); petiListAPI(); kondisiPetiListAPI(); - initializeDateFormatting('id_ID', null); + + setState(() { + loading = false; // Mengatur loading ke false setelah tugas selesai + }); } void _getUserToken() async { @@ -389,7 +395,7 @@ class _CreatePengembalianBarangPageState automaticallyImplyLeading: false, backgroundColor: Colors.indigo[700], elevation: 0, - title: Text('Buat Pengembalian barang', + title: Text('Buat Pengembalian Peti', style: TextStyle( fontSize: 16, )), @@ -410,48 +416,122 @@ class _CreatePengembalianBarangPageState elevation: 2, child: Container( margin: EdgeInsets.all(8), - child: DropdownButtonFormField( - validator: (value) { - if (value == null) { - return 'Harus diisi'; - } - return null; - }, - decoration: InputDecoration( - labelText: 'Peti', - border: OutlineInputBorder(), + child: DropdownSearch( + popupProps: PopupProps.bottomSheet( + showSearchBox: true, + itemBuilder: (context, PetiAssetModel? peti, + bool? isSelected) { + if (peti == null) { + return SizedBox.shrink(); + } + // 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, + ); + }, + 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: () { + Navigator.pop(context); + }, + ), + ], + ), + Divider(), + ], + ), + ), ), - hint: Text("Pilih Peti"), - value: petiSqfliteApi, - items: (isQRCodeScanned - ? _filteredPetiList - : (_valpeti ?? []).where((peti) => - peti.deleted_at != true && - (peti.warehouse_id == - user.warehouse_id) && - (peti.status == 'AKTIF'))) - .map((PetiAssetModel peti) { - return DropdownMenuItem( - child: Text( - '${peti.fix_lot}', - style: TextStyle( - fontSize: 12, + + dropdownDecoratorProps: + DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + labelText: 'Pilih Peti', + border: OutlineInputBorder( + borderRadius: BorderRadius.all( + Radius.circular(5.0), ), ), - value: peti, - ); - }).toList(), + ), + ), + + items: (isQRCodeScanned + ? _filteredPetiList + : (_valpeti ?? []).where((peti) => + peti.deleted_at != true && + (peti.warehouse_id == + user.warehouse_id) && + (peti.status == 'AKTIF'))) + .where((peti) => peti.fix_lot! + .toLowerCase() + .contains(searchBoxController.text + .toLowerCase())) + .toList() ?? + [], + // searchBoxController: searchBoxController, + itemAsString: (PetiAssetModel item) => + item.fix_lot ?? + "", // Ganti dengan properti yang sesuai + + selectedItem: petiSqfliteApi, + onChanged: (PetiAssetModel? value) { setState(() { petiSqfliteApi = value; if (value != null) { - warehouseSqfliteApi = - _valwarehouse?.firstWhere( - (warehouse) => - warehouse.id == - value.warehouse_id, - ); - // Perbarui _unrestrictedPetiList sesuai pemilihan manual _unrestrictedPetiList = [ _valpeti!.firstWhere( @@ -460,6 +540,12 @@ class _CreatePengembalianBarangPageState } }); }, + validator: (PetiAssetModel? value) { + if (value == null) { + return 'Harus diisi'; + } + return null; + }, ), ), ), @@ -595,17 +681,39 @@ class _CreatePengembalianBarangPageState return null; }, decoration: InputDecoration( - labelText: 'Pilih Gudang', + labelText: 'Gudang Pengembalian', border: OutlineInputBorder(), ), - hint: Text("Pilih Gudang"), + hint: Text("Gudang Pengembalian"), value: warehouseSqfliteApi, items: (_valwarehouse ?? []) .where((warehouse) => warehouse.deleted_at != true) - .map((WarehouseModel warehouse) { + .map((WarehouseModel warehouse) + // _valwarehouse?.map((WarehouseModel warehouse) + { return DropdownMenuItem( - child: Text('${warehouse.name}'), + child: Row( + children: [ + Icon( + Icons.edit_location_alt, + color: warehouse.id == + warehouseSqfliteApi?.id + ? Colors.indigo[700] + : Colors.grey, + ), + SizedBox( + width: + 8), // Jarak antara ikon dan teks + Text( + '${warehouse.name}', + style: TextStyle( + fontSize: 16, + fontFamily: 'OpenSansCondensed', + ), + ), + ], + ), value: warehouse, ); }).toList() ?? @@ -640,7 +748,30 @@ class _CreatePengembalianBarangPageState (kondisi) => kondisi.deleted_at != true) .map((ConditionPetiModel kondisi) { return DropdownMenuItem( - child: Text('${kondisi.nama_kondisi}'), + child: Row( + children: [ + Icon( + kondisi.id == + conditionPetiSqfliteApi?.id + ? Icons.check_box + : Icons.check_box_outline_blank, + color: kondisi.id == + conditionPetiSqfliteApi?.id + ? Colors.teal[700] + : Colors.grey, + ), + SizedBox( + width: 8, + ), + Text( + '${kondisi.nama_kondisi}', + style: TextStyle( + fontSize: 16, + fontFamily: 'OpenSansCondensed', + ), + ), + ], + ), value: kondisi, ); }).toList() ?? diff --git a/lib/pages/pengembalian_barang/index.dart b/lib/pages/pengembalian_barang/index.dart index 3f757d7..dc2f2c8 100644 --- a/lib/pages/pengembalian_barang/index.dart +++ b/lib/pages/pengembalian_barang/index.dart @@ -5,6 +5,7 @@ import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:data_table_2/data_table_2.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:loading_animation_widget/loading_animation_widget.dart'; import 'package:siopas/models/condition_peti_model.dart'; import 'package:siopas/models/customer_model.dart'; import 'package:siopas/models/disposal_model.dart'; @@ -58,28 +59,41 @@ class PengembalianBarangPageState extends State { List? _customerData; List? _warehouseData; List? _conditionData; - bool _isLoading = false; Timer? _timer; + bool _isLoading = false; + @override void initState() { super.initState(); _getUserToken(); - warehouseListAPI(); - conditionPetiListAPI(); - typePetiListAPI(); - customerListAPI(); - petiListAPI(); - // disposalListAPI(); - - // Tampil data Datatables - datatablesPengembalianList(); - datatablesPetiList(); - datatablesTipePetiList(); - datatablesCustomerList(); - datatablesWarehouseList(); - datatablesConditionList(); + // Set _isLoading ke true sebelum memulai tugas + setState(() { + _isLoading = true; + }); + + Future.wait([ + warehouseListAPI(), + conditionPetiListAPI(), + typePetiListAPI(), + customerListAPI(), + petiListAPI(), + // disposalListAPI(), + datatablesPengembalianList(), + datatablesPetiList(), + datatablesTipePetiList(), + datatablesCustomerList(), + datatablesWarehouseList(), + datatablesConditionList(), + ]).then((_) { + // Set _isLoading ke false setelah semua tugas selesai + setState(() { + _isLoading = false; + }); + }); + + // Inisialisasi _data di sini jika diperlukan _data = []; } @@ -195,10 +209,16 @@ class PengembalianBarangPageState extends State { EasyLoading.show(status: 'Mengambil data Peti...'); List petiApiData = await SyncronizationDataAPI().fetchPetiFromApi(); + await ControllerApi() .deleteAllPetiDataAPI(); // Clear existing data in SQLite - await ControllerApi() - .addAllPetiDataAPI(petiApiData); // Add new data to SQLite + + // Menentukan ukuran chunk, misalnya 100 + int chunkSize = 100; + + // Memasukkan data ke SQLite dengan menggunakan chunk + await ControllerApi().addAllPetiDataAPI(petiApiData, chunkSize); + EasyLoading.dismiss(); } @@ -491,7 +511,7 @@ class PengembalianBarangPageState extends State { appBar: AppBar( backgroundColor: Colors.indigo[700], elevation: 0, - title: Text('Data Pengembalian Barang', + title: Text('Data Pengembalian Peti', style: TextStyle( fontSize: 16, )), @@ -524,7 +544,12 @@ class PengembalianBarangPageState extends State { ), ), body: _isLoading - ? const Center(child: CircularProgressIndicator()) + ? Center( + child: LoadingAnimationWidget.staggeredDotsWave( + color: Colors.indigo, + size: 40, + ), + ) : TabBarView( children: [ SingleChildScrollView( diff --git a/lib/pages/pengembalian_barang/show.dart b/lib/pages/pengembalian_barang/show.dart index 56703dc..0dc076f 100644 --- a/lib/pages/pengembalian_barang/show.dart +++ b/lib/pages/pengembalian_barang/show.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:siopas/models/asset_status_model.dart'; import 'package:siopas/models/condition_peti_model.dart'; import 'package:siopas/models/customer_model.dart'; @@ -37,12 +38,22 @@ class _DetailPengembalianBarangPageState @override void initState() { super.initState(); + + // Pemanggilan fungsi-fungsi yang diperlukan getPengembalianIdData(); customerListAPI(); petiListAPI(); warehouseListAPI(); kondisiPetiListAPI(); initializeDateFormatting('id_ID', null); + + // Delay sejenak sebelum memanggil EasyLoading.dismiss() + Future.delayed(Duration(seconds: 1), () { + setState(() { + loading = false; // Mengatur loading ke false setelah tugas selesai + }); + EasyLoading.dismiss(); + }); } Future customerListAPI() async { @@ -118,6 +129,19 @@ class _DetailPengembalianBarangPageState } } + Future _deletePengembalian() async { + try { + // Panggil fungsi untuk menghapus peminjaman berdasarkan ID + await ControllerPengembalian() + .deletePengembalianById(widget.pengembalianId); + // Navigasi kembali ke halaman sebelumnya atau halaman yang sesuai + Navigator.pushNamed(context, '/pengembalian-barang'); + } catch (e) { + // Tangani kesalahan jika terjadi + print('Gagal menghapus pengembalian: $e'); + } + } + @override Widget build(BuildContext context) { PetiAssetModel? petiSqfliteApi; @@ -140,13 +164,85 @@ class _DetailPengembalianBarangPageState (conditionPeti) => conditionPeti.id == pengembalianInfo!.kondisi_peti_id, ); + Future _showDeleteConfirmationDialog() async { + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.0), + ), + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Icon( + Icons.info, + color: Colors.blue, + ), + SizedBox(width: 8), + Text( + 'Konfirmasi Hapus', + style: TextStyle( + fontSize: 18, + ), + ), + ], + ), + IconButton( + icon: Icon( + Icons.close, + color: Colors.black54, + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ), + content: SingleChildScrollView( + child: ListBody( + children: [ + Text( + 'Anda yakin ingin menghapus pengembalian ini? ${petiSqfliteApi!.fix_lot.toString()}', + style: TextStyle( + fontSize: 16, + ), + ), + ], + ), + ), + actions: [ + Container( + margin: EdgeInsets.only(right: 3.0), + child: ElevatedButton( + child: Text('Hapus'), + onPressed: () { + // Panggil fungsi untuk menghapus peminjaman berdasarkan ID + _deletePengembalian(); + Navigator.pushNamed(context, '/pengembalian-barang'); + EasyLoading.showSuccess( + 'Berhasil menghapus data pengembalian'); + }, + style: ElevatedButton.styleFrom( + primary: Colors.red, + ), + ), + ), + ], + ); + }, + ); + } + return Scaffold( backgroundColor: Colors.grey[200], appBar: AppBar( backgroundColor: Colors.indigo[700], elevation: 0, title: Text( - 'Detail Pengembalian Barang', + 'Detail Pengembalian Peti', style: TextStyle( color: Colors.white, fontSize: 16, @@ -158,6 +254,14 @@ class _DetailPengembalianBarangPageState Navigator.pushNamed(context, '/pengembalian-barang'); }, ), + actions: [ + IconButton( + icon: Icon(Icons.delete, color: Colors.redAccent), + onPressed: () { + _showDeleteConfirmationDialog(); + }, + ), + ], ), body: Padding( padding: EdgeInsets.all(16.0), diff --git a/lib/pages/sign_in_page.dart b/lib/pages/sign_in_page.dart index 36b535a..4750b03 100644 --- a/lib/pages/sign_in_page.dart +++ b/lib/pages/sign_in_page.dart @@ -76,7 +76,7 @@ class _SignInPageState extends State { onPressed: () { _showSettingsModal(context); // Show the modal }, - child: Text('Settings'), + child: Text('Pengaturan'), ), ], ), @@ -96,22 +96,37 @@ class _Logo extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ Container( - margin: EdgeInsets.only(top: 30), + // margin: EdgeInsets.only(top: 30), child: Image.asset( - 'assets/img/logo_siopas.png', + 'assets/img/siopas_apps.png', height: isSmallScreen ? 135 : 200, ), ), Padding( padding: const EdgeInsets.all(16.0), - child: Text( - "Welcome To Siopas!", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: isSmallScreen ? 18 : 22, - fontWeight: semiBold, - color: Colors.black, - ), + child: Column( + children: [ + Text( + "Siopas ISTW", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: isSmallScreen ? 18 : 22, + fontWeight: semiBold, + color: Colors.black, + ), + ), + SizedBox( + height: + 8.0), // Berikan sedikit jarak antara teks "Siopas ISTW" dan versi + Text( + "Version 1.0.0", // Gantilah dengan versi aktual + textAlign: TextAlign.center, + style: TextStyle( + fontSize: isSmallScreen ? 14 : 16, + color: Colors.grey, + ), + ), + ], ), ), ], @@ -261,13 +276,27 @@ class __FormContentState extends State<_FormContent> { child: ElevatedButton( style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(4)), + borderRadius: BorderRadius.circular(4), + ), + primary: Colors.indigo, // Ganti warna tombol menjadi indigo + alignment: Alignment.center, // Menyusun isi tombol ke tengah ), - child: const Padding( - padding: EdgeInsets.all(10.0), - child: Text( - 'Login', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Row( + mainAxisAlignment: + MainAxisAlignment.center, // Tengahkan teks 'Login' + children: [ + Icon(Icons.login), + SizedBox( + width: + 8.0), // Berikan sedikit jarak antara ikon dan teks + Text( + 'Masuk', + style: TextStyle( + fontSize: 16, fontWeight: FontWeight.bold), + ), + ], ), ), onPressed: () { @@ -347,7 +376,7 @@ class _SettingsModalState extends State { title: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('Settings'), + Text('Pengaturan'), GestureDetector( onTap: () { Navigator.of(context).pop(); // Close the modal @@ -379,7 +408,7 @@ class _SettingsModalState extends State { saveSettings(ipAddressController.text, portController.text); Navigator.of(context).pop(); // Close the modal }, - child: Text('Save'), + child: Text('Simpan'), ), ], ); diff --git a/lib/pages/splash_page.dart b/lib/pages/splash_page.dart index 46049d4..f851eb8 100644 --- a/lib/pages/splash_page.dart +++ b/lib/pages/splash_page.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:loading_animation_widget/loading_animation_widget.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:siopas/models/user_model.dart'; @@ -73,7 +74,10 @@ class _SplashPageState extends State { ), ), SizedBox(height: 16), - CircularProgressIndicator(), + LoadingAnimationWidget.staggeredDotsWave( + color: Colors.indigo, + size: 40, + ), SizedBox(height: 16), Text( 'Memuat...', diff --git a/lib/pages/transfer_peti/conn/syncronize.dart b/lib/pages/transfer_peti/conn/syncronize.dart index c9467d9..25d2e32 100644 --- a/lib/pages/transfer_peti/conn/syncronize.dart +++ b/lib/pages/transfer_peti/conn/syncronize.dart @@ -85,9 +85,68 @@ class SyncronizationTransferPetiData { await dbClient!.delete(SqfliteDatabaseHelper.transferPetiTable); } - Future saveTransferPetiServerWith( + // Future saveTransferPetiServerWith( + // List transferPetiLocalList) async { + // for (var i = 0; i < transferPetiLocalList.length; i++) { + // DateTime? parseDateTime(String? dateTimeString) { + // if (dateTimeString == null || dateTimeString.isEmpty) { + // return null; + // } + + // try { + // return DateTime.parse(dateTimeString); + // } catch (e) { + // print('Error parsing DateTime: $e'); + // return null; + // } + // } + + // // Format tanggal sesuai kebutuhan + // String formattedCreatedAt = transferPetiLocalList[i].created_at != null + // ? DateFormat('yyyy-MM-dd HH:mm:ss.SSS') + // .format(transferPetiLocalList[i].created_at!) + // : DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(DateTime.now()); + + // Map data = { + // "mobile_id": transferPetiLocalList[i].mobile_id.toString(), // "id": "1 + // "peti_id": transferPetiLocalList[i].peti_id.toString(), + // "name_customer": transferPetiLocalList[i].name_customer.toString(), + // "source_warehouse": + // transferPetiLocalList[i].source_warehouse.toString(), + // "destination_warehouse": + // transferPetiLocalList[i].destination_warehouse.toString(), + // "date": transferPetiLocalList[i].date.toString(), + // "created_by": transferPetiLocalList[i].created_by.toString(), + // "created_at": formattedCreatedAt, + // }; + + // final response = await http.post( + // Uri.parse(await getBaseUrl() + '/m-transfer-peti/store'), + // body: data, + // ); + + // if (response.statusCode == 200) { + // // print("Data uploaded successfully for index $i:"); + // // print("Response body: ${response.body}"); + // print("Saving Data saveToTransferPetiWith"); + // } else { + // print( + // "Failed to upload data for index $i. Status code: ${response.statusCode}"); + // print("Response body: ${response.body}"); + // } + // } + + // return true; // Pengunggahan berhasil + // } + + Future saveTransferPetiServerWith( List transferPetiLocalList) async { - for (var i = 0; i < transferPetiLocalList.length; i++) { + const maxRequestsBeforeDelay = 25; + const delayDuration = Duration(seconds: 3); + + int requestCounter = 0; + + await Future.forEach(transferPetiLocalList, (transferPeti) async { DateTime? parseDateTime(String? dateTimeString) { if (dateTimeString == null || dateTimeString.isEmpty) { return null; @@ -102,21 +161,19 @@ class SyncronizationTransferPetiData { } // Format tanggal sesuai kebutuhan - String formattedCreatedAt = transferPetiLocalList[i].created_at != null + String formattedCreatedAt = transferPeti.created_at != null ? DateFormat('yyyy-MM-dd HH:mm:ss.SSS') - .format(transferPetiLocalList[i].created_at!) + .format(transferPeti.created_at!) : DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(DateTime.now()); Map data = { - "mobile_id": transferPetiLocalList[i].mobile_id.toString(), // "id": "1 - "peti_id": transferPetiLocalList[i].peti_id.toString(), - "name_customer": transferPetiLocalList[i].name_customer.toString(), - "source_warehouse": - transferPetiLocalList[i].source_warehouse.toString(), - "destination_warehouse": - transferPetiLocalList[i].destination_warehouse.toString(), - "date": transferPetiLocalList[i].date.toString(), - "created_by": transferPetiLocalList[i].created_by.toString(), + "mobile_id": transferPeti.mobile_id.toString(), + "peti_id": transferPeti.peti_id.toString(), + "name_customer": transferPeti.name_customer.toString(), + "source_warehouse": transferPeti.source_warehouse.toString(), + "destination_warehouse": transferPeti.destination_warehouse.toString(), + "date": transferPeti.date.toString(), + "created_by": transferPeti.created_by.toString(), "created_at": formattedCreatedAt, }; @@ -126,15 +183,21 @@ class SyncronizationTransferPetiData { ); if (response.statusCode == 200) { - // print("Data uploaded successfully for index $i:"); - // print("Response body: ${response.body}"); print("Saving Data saveToTransferPetiWith"); } else { - print( - "Failed to upload data for index $i. Status code: ${response.statusCode}"); + print("Failed to upload data. Status code: ${response.statusCode}"); print("Response body: ${response.body}"); } - } + + // Increment counter + requestCounter++; + + // Jeda 3 detik setiap 25 permintaan + if (requestCounter % maxRequestsBeforeDelay == 0 && + requestCounter != transferPetiLocalList.length) { + await Future.delayed(delayDuration); + } + }); return true; // Pengunggahan berhasil } diff --git a/lib/pages/transfer_peti/controller/transfer_peti_controller.dart b/lib/pages/transfer_peti/controller/transfer_peti_controller.dart index 59c8fbf..860cde8 100644 --- a/lib/pages/transfer_peti/controller/transfer_peti_controller.dart +++ b/lib/pages/transfer_peti/controller/transfer_peti_controller.dart @@ -95,7 +95,7 @@ class ControllerTransferPeti { return transferPetiList; } - Future> fetchDataId() async { + Future> fetchTransferPetiDataId() async { var dbclient = await conn.db; List transferPetiList = []; try { @@ -110,6 +110,20 @@ class ControllerTransferPeti { return transferPetiList; } + Future deleteTransferPetiById(String id) async { + var dbclient = await conn.db; + try { + await dbclient!.delete( + SqfliteDatabaseHelper.transferPetiTable, + where: 'id = ?', + whereArgs: [id], + ); + } catch (e) { + print('Gagal menghapus transfer peti dari database: $e'); + throw Exception('Gagal menghapus transfer peti'); + } + } + Future deleteAllData() async { var dbClient = await conn.db; await dbClient!.delete(SqfliteDatabaseHelper.transferPetiTable); diff --git a/lib/pages/transfer_peti/edit.dart b/lib/pages/transfer_peti/edit.dart index 9936897..d9d0ca3 100644 --- a/lib/pages/transfer_peti/edit.dart +++ b/lib/pages/transfer_peti/edit.dart @@ -21,6 +21,7 @@ import 'package:siopas/models/warehouse_mode.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:intl/date_symbol_data_local.dart'; // Import package intl import 'package:uuid/uuid.dart'; +import 'package:dropdown_search/dropdown_search.dart'; import '../../models/user_model.dart'; import '../../providers/auth_provider.dart'; @@ -54,15 +55,15 @@ class _EditTransferPetiPageState extends State { List? _valwarehouse; List? _valWarehouse_tujuan_gudang; List? _valconditionPeti; - List? _valcustomer; CustomerModel? customerSqfliteApi; + List? _valcustomer; List _unrestrictedPetiList = []; List _filteredPetiList = []; bool isQRCodeScanned = false; - bool loading = true; + TextEditingController searchBoxController = TextEditingController(); TextEditingController _dateController = TextEditingController(); // TextEditingController _enterPicController = TextEditingController(); // TextEditingController _kondisiPetiController = TextEditingController(); @@ -73,12 +74,19 @@ class _EditTransferPetiPageState extends State { Barcode? result; QRViewController? controller; + bool loading = true; + @override void initState() { super.initState(); _getUserToken(); warehouseListAPI(); + // Memulai loading + setState(() { + loading = true; + }); + datatablesTransferPetiList(); // typePetiListAPI(); customerListAPI(); @@ -86,6 +94,11 @@ class _EditTransferPetiPageState extends State { kondisiPetiListAPI(); initializeDateFormatting('id_ID', null); + + // Mengakhiri loading setelah tugas selesai + setState(() { + loading = false; + }); } void _getUserToken() async { @@ -234,7 +247,7 @@ class _EditTransferPetiPageState extends State { (warehouse) => warehouse.id == allowedPeti.warehouse_id, ); - customerItemSqfliteApi = _valcustomer?.firstWhereOrNull( + customerSqfliteApi = _valcustomer?.firstWhereOrNull( (customer) => customer.id == allowedPeti.customer_id, ); }); @@ -373,7 +386,7 @@ class _EditTransferPetiPageState extends State { id: null, mobile_id: uuid.v4(), peti_id: petiSqfliteApi!.id, - name_customer: customerItemSqfliteApi!.id, + name_customer: customerSqfliteApi!.id, source_warehouse: warehouseSqfliteApi!.id, destination_warehouse: warehouseTujuanSqfliteApi!.id, date: parseDateTime(_dateController.text), @@ -426,52 +439,130 @@ class _EditTransferPetiPageState extends State { elevation: 2, child: Container( margin: EdgeInsets.all(8), - child: DropdownButtonFormField( - validator: (value) { - if (value == null) { - return 'Harus diisi'; - } - return null; - }, - decoration: InputDecoration( - labelText: 'Peti', - border: OutlineInputBorder(), + child: DropdownSearch( + popupProps: PopupProps.bottomSheet( + showSearchBox: true, + itemBuilder: (context, PetiAssetModel? peti, + bool? isSelected) { + if (peti == null) { + return SizedBox.shrink(); + } + // 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, + ); + }, + 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: () { + Navigator.pop(context); + }, + ), + ], + ), + Divider(), + ], + ), + ), ), - hint: Text("Pilih Peti"), - value: petiSqfliteApi, - items: (isQRCodeScanned - ? _filteredPetiList - : (_valpeti ?? []).where((peti) => - peti.deleted_at != true && - (peti.warehouse_id == - user.warehouse_id) && - (peti.status == 'AKTIF'))) - .map((PetiAssetModel peti) { - return DropdownMenuItem( - child: Text( - '${peti.fix_lot}', - style: TextStyle( - fontSize: 12, + + dropdownDecoratorProps: + DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + labelText: 'Pilih Peti', + border: OutlineInputBorder( + borderRadius: BorderRadius.all( + Radius.circular(5.0), ), ), - value: peti, - ); - }).toList(), + ), + ), + + items: (isQRCodeScanned + ? _filteredPetiList + : (_valpeti ?? []).where((peti) => + peti.deleted_at != true && + (peti.warehouse_id == + user.warehouse_id) && + (peti.status == 'AKTIF'))) + .where((peti) => peti.fix_lot! + .toLowerCase() + .contains(searchBoxController.text + .toLowerCase())) + .toList() ?? + [], + // searchBoxController: searchBoxController, + itemAsString: (PetiAssetModel item) => + item.fix_lot ?? + "", // Ganti dengan properti yang sesuai + + selectedItem: petiSqfliteApi, + onChanged: (PetiAssetModel? value) { setState(() { petiSqfliteApi = value; if (value != null) { - warehouseSqfliteApi = - _valwarehouse?.firstWhere( - (warehouse) => - warehouse.id == - value.warehouse_id, - ); - customerItemSqfliteApi = - _valcustomer?.firstWhereOrNull( - (customer) => - customer.id == value.customer_id, - ); + warehouseSqfliteApi = _valwarehouse + ?.firstWhere((warehouse) => + warehouse.id == + value.warehouse_id); + customerSqfliteApi = _valcustomer + ?.firstWhereOrNull((customer) => + customer.id == + value.customer_id); // Perbarui _unrestrictedPetiList sesuai pemilihan manual _unrestrictedPetiList = [ @@ -481,6 +572,12 @@ class _EditTransferPetiPageState extends State { } }); }, + validator: (PetiAssetModel? value) { + if (value == null) { + return 'Harus diisi'; + } + return null; + }, ), ), ), @@ -608,34 +705,113 @@ class _EditTransferPetiPageState extends State { Card( child: Padding( padding: const EdgeInsets.all(8.0), - child: DropdownButtonFormField( - validator: (value) { - if (value == null) { - return 'Harus diisi'; - } - return null; - }, - decoration: InputDecoration( - labelText: 'Pilih Customer', - border: OutlineInputBorder(), + child: DropdownSearch( + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + labelText: 'Pilih Customer', + border: OutlineInputBorder( + borderRadius: BorderRadius.all( + Radius.circular(5.0), + ), + ), + ), ), - hint: Text("Pilih Customer"), - value: customerItemSqfliteApi, + popupProps: PopupProps.bottomSheet( + showSearchBox: true, + itemBuilder: (context, CustomerModel? customer, + bool? isSelected) { + if (customer == null) { + return SizedBox.shrink(); + } + + return Container( + child: Column( + children: [ + ListTile( + title: Text( + customer.name.toString(), + style: TextStyle( + fontSize: 16, + fontFamily: 'OpenSansCondensed', + ), + ), + leading: Icon( + Icons.person_pin, + size: 24, + color: customer.id == + customerSqfliteApi?.id + ? Colors.indigo[700] + : Colors.grey, + ), + ), + Divider( + height: 1, + color: Colors + .grey, // Warna pembatas (divider) + ), + ], + ), + color: customer.id == customerSqfliteApi?.id + ? Colors.grey.withOpacity(0.7) + : Colors.white, + ); + }, + fit: FlexFit.loose, + title: Padding( + padding: EdgeInsets.all(8.0), + child: Column( + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Pilih Customer', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold), + ), + IconButton( + icon: Icon( + Icons.close, + color: Colors.red, + ), + onPressed: () { + Navigator.pop(context); + }, + ), + ], + ), + Divider(), + ], + ), + ), + ), + items: (_valcustomer ?? []) .where((customer) => customer.deleted_at != true) - .map((CustomerModel customer) { - return DropdownMenuItem( - child: Text('${customer.name}'), - value: customer, - ); - }).toList() ?? + .where((customer) => customer.name! + .toLowerCase() + .contains(searchBoxController.text + .toLowerCase())) + .toList() ?? [], + itemAsString: (CustomerModel customer) => + customer.name ?? + "", // Ganti dengan properti yang sesuai + selectedItem: customerSqfliteApi, onChanged: (CustomerModel? value) { setState(() { - customerItemSqfliteApi = value; + customerSqfliteApi = value; }); }, + validator: (CustomerModel? value) { + if (value == null) { + return 'Harus diisi'; + } + return null; + }, ), ), ), @@ -651,17 +827,39 @@ class _EditTransferPetiPageState extends State { return null; }, decoration: InputDecoration( - labelText: 'Pilih Asal Gudang', + labelText: 'Asal Gudang', border: OutlineInputBorder(), ), - hint: Text("Pilih Asal Gudang"), + hint: Text("Asal Gudang"), value: warehouseSqfliteApi, items: (_valwarehouse ?? []) .where((warehouse) => warehouse.deleted_at != true) - .map((WarehouseModel warehouse) { + .map((WarehouseModel warehouse) + // _valwarehouse?.map((WarehouseModel warehouse) + { return DropdownMenuItem( - child: Text('${warehouse.name}'), + child: Row( + children: [ + Icon( + Icons.warehouse, + color: warehouse.id == + warehouseSqfliteApi?.id + ? Colors.indigo[700] + : Colors.grey, + ), + SizedBox( + width: + 8), // Jarak antara ikon dan teks + Text( + '${warehouse.name}', + style: TextStyle( + fontSize: 16, + fontFamily: 'OpenSansCondensed', + ), + ), + ], + ), value: warehouse, ); }).toList() ?? @@ -687,17 +885,39 @@ class _EditTransferPetiPageState extends State { return null; }, decoration: InputDecoration( - labelText: 'Pilih Tujuan Gudang', + labelText: 'Tujuan Transfer Gudang', border: OutlineInputBorder(), ), - hint: Text("Pilih Tujuan Gudang"), + hint: Text("Tujuan Transfer Gudang"), value: warehouseTujuanSqfliteApi, items: (_valwarehouse ?? []) .where((warehouseTujuan) => warehouseTujuan.deleted_at != true) - .map((WarehouseModel warehouseTujuan) { + .map((WarehouseModel warehouseTujuan) + // _valwarehouse?.map((WarehouseModel warehouse) + { return DropdownMenuItem( - child: Text('${warehouseTujuan.name}'), + child: Row( + children: [ + Icon( + Icons.local_shipping, + color: warehouseTujuan.id == + warehouseTujuanSqfliteApi?.id + ? Colors.green[700] + : Colors.grey, + ), + SizedBox( + width: + 8), // Jarak antara ikon dan teks + Text( + '${warehouseTujuan.name}', + style: TextStyle( + fontSize: 16, + fontFamily: 'OpenSansCondensed', + ), + ), + ], + ), value: warehouseTujuan, ); }).toList() ?? diff --git a/lib/pages/transfer_peti/index.dart b/lib/pages/transfer_peti/index.dart index 60c69a3..29ff830 100644 --- a/lib/pages/transfer_peti/index.dart +++ b/lib/pages/transfer_peti/index.dart @@ -5,6 +5,7 @@ import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:data_table_2/data_table_2.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:loading_animation_widget/loading_animation_widget.dart'; import 'package:siopas/models/customer_model.dart'; import 'package:siopas/models/disposal_model.dart'; import 'package:siopas/models/m_asset_status_model.dart'; @@ -26,6 +27,7 @@ import 'package:http/http.dart' as http; import '../../connection/connection.dart'; import '../../models/condition_peti_model.dart'; +import 'show.dart'; class TransferPetiPage extends StatefulWidget { const TransferPetiPage({super.key}); @@ -57,27 +59,38 @@ class TransferPetiPageState extends State { List? _tipePetiData; List? _customerData; List? _warehouseData; - bool _isLoading = false; Timer? _timer; + bool _isLoading = false; @override void initState() { super.initState(); _getUserToken(); - warehouseListAPI(); - typePetiListAPI(); - customerListAPI(); - petiListAPI(); - // disposalListAPI(); - - // Tampil data Datatables - // datatablesAssetStatusList(); - datatablesTransferPetiList(); - datatablesPetiList(); - datatablesTipePetiList(); - datatablesCustomerList(); - datatablesWarehouseList(); + // Memulai loading + setState(() { + _isLoading = true; + }); + + Future.wait([ + warehouseListAPI(), + typePetiListAPI(), + customerListAPI(), + petiListAPI(), + // disposalListAPI(), + datatablesTransferPetiList(), + datatablesPetiList(), + datatablesTipePetiList(), + datatablesCustomerList(), + datatablesWarehouseList(), + ]).then((_) { + // Mengakhiri loading setelah semua tugas selesai + setState(() { + _isLoading = false; + }); + }); + + // Inisialisasi _data di sini jika diperlukan _data = []; } @@ -180,10 +193,16 @@ class TransferPetiPageState extends State { EasyLoading.show(status: 'Mengambil data Peti...'); List petiApiData = await SyncronizationDataAPI().fetchPetiFromApi(); + await ControllerApi() .deleteAllPetiDataAPI(); // Clear existing data in SQLite - await ControllerApi() - .addAllPetiDataAPI(petiApiData); // Add new data to SQLite + + // Menentukan ukuran chunk, misalnya 100 + int chunkSize = 100; + + // Memasukkan data ke SQLite dengan menggunakan chunk + await ControllerApi().addAllPetiDataAPI(petiApiData, chunkSize); + EasyLoading.dismiss(); } @@ -501,7 +520,12 @@ class TransferPetiPageState extends State { ), ), body: _isLoading - ? const Center(child: CircularProgressIndicator()) + ? Center( + child: LoadingAnimationWidget.staggeredDotsWave( + color: Colors.indigo, + size: 40, + ), + ) : TabBarView( children: [ SingleChildScrollView( @@ -520,6 +544,7 @@ class TransferPetiPageState extends State { }, columns: [ DataColumn(label: Text('No')), + DataColumn(label: Text('')), DataColumn(label: Text('Kode Peti')), DataColumn(label: Text('Customer')), DataColumn(label: Text('Tgl Transfer')), @@ -702,6 +727,27 @@ class _DataSourceLokal extends DataTableSource { (index + 1).toString(), ), ), + DataCell( + GestureDetector( + onTap: () { + if (item.id != null) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => DetailTransferPetiPage( + transferPetiId: int.parse(item.id.toString()), + ), + ), + ); + + // print('asset id: ${item.id}'); + } + }, + child: Icon(Icons.article, + size: 40, + color: Colors.indigo[700]), // Ganti ikon sesuai kebutuhan + ), + ), DataCell( Text( petiSqfliteApi != null && petiSqfliteApi.fix_lot != null diff --git a/lib/pages/transfer_peti/show.dart b/lib/pages/transfer_peti/show.dart new file mode 100644 index 0000000..c41991f --- /dev/null +++ b/lib/pages/transfer_peti/show.dart @@ -0,0 +1,367 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:siopas/models/asset_status_model.dart'; +import 'package:siopas/models/customer_model.dart'; +import 'package:siopas/models/m_asset_status_model.dart'; +import 'package:siopas/models/transfer_peti_model.dart'; +import 'package:siopas/pages/peminjaman_barang/controller/peminjaman_controller.dart'; +import 'package:intl/date_symbol_data_local.dart'; +import 'package:intl/intl.dart'; +import 'package:collection/collection.dart'; +import 'package:siopas/pages/transfer_peti/controller/transfer_peti_controller.dart'; + +import '../../models/warehouse_mode.dart'; +import '../../services/controllerApi.dart'; + +class DetailTransferPetiPage extends StatefulWidget { + final int transferPetiId; + + const DetailTransferPetiPage({Key? key, required this.transferPetiId}) + : super(key: key); + + @override + _DetailTransferPetiPageState createState() => _DetailTransferPetiPageState(); +} + +class _DetailTransferPetiPageState extends State { + TransferPetiModel? transferInfo; + WarehouseModel? warehouseInfo; + + List? petiData; + List? customerData; + List? warehouseData; + bool loading = true; + + @override + void initState() { + super.initState(); + + // Pemanggilan fungsi-fungsi yang diperlukan + getTransferIdData(); + customerListAPI(); + petiListAPI(); + warehouseListAPI(); + initializeDateFormatting('id_ID', null); + + // Mengatur loading ke false setelah tugas selesai + setState(() { + loading = false; + }); + } + + Future customerListAPI() async { + if (mounted) { + await ControllerApi().fetchCustomerDataAPI().then((value) { + setState(() { + customerData = (value as List) + .map((item) => CustomerModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + Future petiListAPI() async { + if (mounted) { + await ControllerApi().fetchPetiDataAPI().then((value) { + setState(() { + petiData = (value as List) + .map((item) => PetiAssetModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + Future warehouseListAPI() async { + if (mounted) { + await ControllerApi().fetchWarehouseDataAPI().then((value) { + setState(() { + warehouseData = (value as List) + .map((item) => WarehouseModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + Future getTransferIdData() async { + List transfers = + await ControllerTransferPeti().fetchTransferPetiDataId(); + transferInfo = transfers.firstWhereOrNull( + (transfer) => transfer.id.toString() == widget.transferPetiId.toString(), + ); + + if (mounted) { + setState(() {}); + } + } + + String _formatDate(String? date) { + if (date != null) { + DateTime parsedDate = DateTime.parse(date); + String formattedDate = + DateFormat('EEEE, dd MMMM yyyy', 'id_ID').format(parsedDate); + return formattedDate; + } else { + return ''; + } + } + + Future _deleteTransferPeti() async { + try { + // Panggil fungsi untuk menghapus peminjaman berdasarkan ID + await ControllerTransferPeti() + .deleteTransferPetiById(widget.transferPetiId.toString()); + // Navigasi kembali ke halaman sebelumnya atau halaman yang sesuai + Navigator.pushNamed(context, '/transfer-peti'); + } catch (e) { + // Tangani kesalahan jika terjadi + print('Gagal menghapus transfer peti: $e'); + } + } + + @override + Widget build(BuildContext context) { + PetiAssetModel? petiSqfliteApi; + petiSqfliteApi = petiData?.firstWhereOrNull( + (peti) => peti.id == transferInfo?.peti_id, + ); + + CustomerModel? customerSqfliteApi; + customerSqfliteApi = customerData?.firstWhereOrNull( + (customer) => customer.id == transferInfo?.name_customer, + ); + + WarehouseModel? warehouseSqfliteApi; + warehouseSqfliteApi = warehouseData?.firstWhereOrNull( + (warehouse) => warehouse.id == transferInfo?.source_warehouse, + ); + WarehouseModel? warehouseTujuanSqfliteApi; + warehouseTujuanSqfliteApi = warehouseData?.firstWhereOrNull( + (warehouse) => warehouse.id == transferInfo?.destination_warehouse, + ); + + Future _showDeleteConfirmationDialog() async { + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.0), + ), + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Icon( + Icons.info, + color: Colors.blue, + ), + SizedBox(width: 8), + Text( + 'Konfirmasi Hapus', + style: TextStyle( + fontSize: 18, + ), + ), + ], + ), + IconButton( + icon: Icon( + Icons.close, + color: Colors.black54, + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ), + content: SingleChildScrollView( + child: ListBody( + children: [ + Text( + 'Anda yakin ingin menghapus pengembalian ini? ${petiSqfliteApi!.fix_lot.toString()}', + style: TextStyle( + fontSize: 16, + ), + ), + ], + ), + ), + actions: [ + Container( + margin: EdgeInsets.only(right: 3.0), + child: ElevatedButton( + child: Text('Hapus'), + onPressed: () { + // Panggil fungsi untuk menghapus peminjaman berdasarkan ID + _deleteTransferPeti(); + Navigator.pushNamed(context, '/transfer-peti'); + EasyLoading.showSuccess( + 'Berhasil menghapus data transfer peti'); + }, + style: ElevatedButton.styleFrom( + primary: Colors.red, + ), + ), + ), + ], + ); + }, + ); + } + + return Scaffold( + backgroundColor: Colors.grey[200], + appBar: AppBar( + backgroundColor: Colors.indigo[700], + elevation: 0, + title: Text( + 'Detail Transfer Peti', + style: TextStyle( + color: Colors.white, + fontSize: 16, + ), + ), + leading: IconButton( + icon: Icon(Icons.arrow_back, color: Colors.white), + onPressed: () { + Navigator.pushNamed(context, '/transfer-peti'); + }, + ), + actions: [ + IconButton( + icon: Icon(Icons.delete, color: Colors.redAccent), + onPressed: () { + _showDeleteConfirmationDialog(); + }, + ), + ], + ), + body: Padding( + padding: EdgeInsets.all(16.0), + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15.0), + ), + elevation: 5, + child: Column( + children: [ + Card( + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.vertical(top: Radius.circular(15.0)), + ), + elevation: 0, + margin: EdgeInsets.all(0), + color: Colors.indigo[700], + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon(Icons.article, size: 30, color: Colors.white), + SizedBox(width: 10), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'ID:', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + SizedBox(height: 5), + Text( + petiSqfliteApi != null && + petiSqfliteApi.fix_lot != null + ? petiSqfliteApi!.fix_lot.toString() + : '-', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + ], + ), + ], + ), + ], + ), + ), + ), + SizedBox(height: 10), + if (transferInfo != null) ...[ + _buildDetailItem( + 'Kode Peti', + petiSqfliteApi != null && petiSqfliteApi.fix_lot != null + ? petiSqfliteApi!.fix_lot.toString() + : '-', + ), + Divider(thickness: 1), + _buildDetailItem( + 'Nama Customer', + customerSqfliteApi != null && customerSqfliteApi.name != null + ? customerSqfliteApi!.name.toString() + : '-', + ), + Divider(thickness: 1), + _buildDetailItem( + 'Tgl Transfer', _formatDate(transferInfo!.date.toString())), + Divider(thickness: 1), + + _buildDetailItem( + 'Asal Gudang', + // peminjamanInfo!.exit_warehouse.toString()), + warehouseSqfliteApi != null && + warehouseSqfliteApi.name != null + ? warehouseSqfliteApi!.name.toString() + : '-'), + Divider(thickness: 1), + _buildDetailItem( + 'Tujuan Gudang', + // peminjamanInfo!.exit_warehouse.toString()), + warehouseTujuanSqfliteApi != null && + warehouseTujuanSqfliteApi.name != null + ? warehouseTujuanSqfliteApi!.name.toString() + : '-'), + Divider(thickness: 1), + // ... tambahkan data lainnya sesuai kebutuhan + ], + ], + ), + ), + ), + ); + } + + Widget _buildDetailItem(String label, String value) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + label, + style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold), + ), + Text( + value, + style: TextStyle(fontSize: 12), + ), + ], + ), + ); + } +} diff --git a/lib/services/controllerApi.dart b/lib/services/controllerApi.dart index 8dea81e..ab9c462 100644 --- a/lib/services/controllerApi.dart +++ b/lib/services/controllerApi.dart @@ -104,20 +104,122 @@ class ControllerApi { await dbClient!.delete(SqfliteDatabaseHelper.petiTable); } - Future addAllPetiDataAPI(List petiListApi) async { - var dbclient = await conn.db; - Batch batch = dbclient!.batch(); + // Future addAllPetiDataAPI(List petiListApi) async { + // var dbclient = await conn.db; + // Batch batch = dbclient!.batch(); + + // for (var peti in petiListApi) { + // // Ensure that toJson() correctly converts the model to a map + // batch.insert( + // SqfliteDatabaseHelper.petiTable, + // peti.toJson(), + // ); + // } - for (var peti in petiListApi) { - // Ensure that toJson() correctly converts the model to a map - batch.insert( - SqfliteDatabaseHelper.petiTable, - peti.toJson(), - ); - } + // await batch.commit(); + // } - await batch.commit(); + // ini sudah benar + // Future addAllPetiDataAPI( + // List petiListApi, int chunkSize) async { + // var dbclient = await conn.db; + + // // Mulai batch + // Batch batch = dbclient!.batch(); + + // // Iterasi melalui data dalam chunk + // for (int i = 0; i < petiListApi.length; i += chunkSize) { + // // Ambil chunk dari data + // List chunk = petiListApi.skip(i).take(chunkSize).toList(); + + // // Insert setiap item dalam chunk ke dalam batch + // for (var peti in chunk) { + // batch.insert( + // SqfliteDatabaseHelper.petiTable, + // peti.toJson(), + // ); + // } + // } + + // // Commit batch + // await batch.commit(); + // } + + // Future addAllPetiDataAPI(List petiListApi) async { + // var dbclient = await conn.db; + // Batch batch = dbclient!.batch(); + + // // Tentukan ukuran chunk yang diinginkan + // int chunkSize = 100; + + // // Iterasi melalui data dalam chunk + // for (int i = 0; i < petiListApi.length; i += chunkSize) { + // // Ambil chunk dari data + // List chunk = petiListApi.skip(i).take(chunkSize).toList(); + + // // Insert setiap item dalam chunk ke dalam batch + // for (var peti in chunk) { + // batch.insert( + // SqfliteDatabaseHelper.petiTable, + // peti.toJson(), + // ); + // } + + // // Commit batch setelah menambahkan semua item dalam chunk + // await batch.commit(); + // } + // } + + Future addAllPetiDataAPI( + List petiListApi, int chunkSize) async { + try { + String? formatDateTime(DateTime? dateTime) { + return dateTime + ?.toIso8601String(); // Ubah DateTime ke dalam format ISO 8601 + } + + var dbclient = await conn?.db; + + if (dbclient == null) { + print("Error: Database connection is null"); + return; + } + + await dbclient.transaction((txn) async { + Batch batch = txn.batch(); + + // Iterasi melalui data dalam chunk + for (int i = 0; i < petiListApi.length; i += chunkSize) { + List chunk = + petiListApi.skip(i).take(chunkSize).toList(); + + for (var peti in chunk) { + // Hanya ambil kolom yang diinginkan + var petiData = { + 'id': peti.id, + 'fix_lot': peti.fix_lot, + 'status': peti.status, + 'customer_id': peti.customer_id, + 'warehouse_id': peti.warehouse_id, + 'kondisipeti_id': peti.kondisipeti_id, + 'deleted_at': formatDateTime(peti.deleted_at), + }; + + batch.insert( + SqfliteDatabaseHelper.petiTable, + petiData, + ); + } + } + + await batch.commit(); + }); + } catch (e) { + print("Error during addAllPetiDataAPI: $e"); + // Handle error sesuai kebutuhan Anda + } } + // End Peti ------------------------------------------------------------------------------------------------------------------ // Warehouse ------------------------------------------------------------------------------------------------------------------ diff --git a/lib/services/syncronizeAPI.dart b/lib/services/syncronizeAPI.dart index 89ae02f..383166f 100644 --- a/lib/services/syncronizeAPI.dart +++ b/lib/services/syncronizeAPI.dart @@ -54,57 +54,6 @@ class SyncronizationDataAPI { } } - // Future> fetchPetiFromApi() async { - // final apiURL = 'http://192.168.0.18:8000/api/v1/peti-asset'; - - // final response = await http.get(Uri.parse(apiURL)); - - // if (response.statusCode == 200) { - // List data = json.decode(response.body)['data']['petis']; - // print('Success Fetch Data Peti'); - - // List petiList = data.map((item) { - // // Extracting and transforming data from JSON - // String id = item['id'].toString(); - // String tipePetiId = item['tipe_peti_id'].toString(); - // String warna = item['warna'].toString(); - // int? packingNo = item['packing_no'] != null - // ? int.parse(item['packing_no'].toString()) - // : null; - // String customerID = item['customer_id'].toString(); - // String warehouseID = item['warehouse_id'].toString(); - // String kondisiPetiID = item['kondisipeti_id'].toString(); - // int? jumlah = item['jumlah'] != null - // ? int.parse(item['jumlah'].toString()) - // : null; - // DateTime datePembuatan = DateTime.parse(item['date_pembuatan']); - - // // Creating an instance of PetiAssetModel - // PetiAssetModel peti = PetiAssetModel( - // id: id, - // tipe_peti_id: tipePetiId, - // warna: warna, - // packing_no: packingNo, - // customer_id: customerID, - // warehouse_id: warehouseID, - // kondisipeti_id: kondisiPetiID, - // jumlah: jumlah, - // date_pembuatan: datePembuatan, - // created_by: - // item['created_by'] != null ? item['created_by'].toString() : null, - // updated_by: - // item['updated_by'] != null ? item['updated_by'].toString() : null, - // ); - - // return peti; - // }).toList(); - - // return petiList; - // } else { - // throw Exception('Failed to fetch data from API Peti'); - // } - // } - Future> fetchWarehouseFromApi() async { final apiURL = '${await getBaseUrl()}/m-warehouse'; diff --git a/pubspec.lock b/pubspec.lock index c268714..2c58dc7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -153,6 +153,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.10" + dropdown_search: + dependency: "direct main" + description: + name: dropdown_search + sha256: "55106e8290acaa97ed15bea1fdad82c3cf0c248dd410e651f5a8ac6870f783ab" + url: "https://pub.dev" + source: hosted + version: "5.0.6" fake_async: dependency: transitive description: @@ -296,6 +304,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.8.1" + loading_animation_widget: + dependency: "direct main" + description: + name: loading_animation_widget + sha256: "1901682600273a966c34cf44a85fc5355da92a8d08a8a43c11adc4e471993e3a" + url: "https://pub.dev" + source: hosted + version: "1.2.0+4" matcher: dependency: transitive description: @@ -528,6 +544,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" + shimmer: + dependency: "direct main" + description: + name: shimmer + sha256: "5f88c883a22e9f9f299e5ba0e4f7e6054857224976a5d9f839d4ebdc94a14ac9" + url: "https://pub.dev" + source: hosted + version: "3.0.0" sky_engine: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 407448f..5b3b83d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -52,6 +52,11 @@ dependencies: flutter_easyloading: ^3.0.5 sqflite: ^2.3.0 flutter_launcher_icons: ^0.13.1 + dropdown_search: ^5.0.6 + shimmer: ^3.0.0 + loading_animation_widget: ^1.2.0+4 + + dev_dependencies: @@ -61,10 +66,13 @@ dev_dependencies: flutter_launcher_icons: android: true ios: true - image_path: "assets/img/siopas_apps.png" - adaptive_icon_background: "#ffffff" + image_path_ios: "assets/img/logo_siopas_apps.png" + image_path_android: "assets/img/logo_siopas_apps.png" + # image_path: "assets/img/siopas_apps.png" + adaptive_icon_background: "assets/img/putih.png" adaptive_icon_foreground: "assets/img/siopas_apps.png" - adaptive_icon_mask: "assets/img/siopas_apps.png" + # adaptive_icon_foreground: "assets/img/logo_siopas_apps.jpg" + # adaptive_icon_mask: "assets/img/logo_siopas_apps.jpg" # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is