From 50e6a36ce43d334707d3ae8c9466386ef123667d Mon Sep 17 00:00:00 2001 From: jefry Date: Mon, 1 Aug 2022 12:03:06 +0700 Subject: [PATCH] add* backup and restore db --- android/app/src/main/AndroidManifest.xml | 1 + lib/home.dart | 139 +++++++++++++++++++++++++++++-- lib/util/dbHandler.dart | 72 +++++++++++++++- lib/util/download_Upload_Handler.dart | 4 +- lib/util/prefsKey.dart | 1 + lib/util/utils.dart | 30 +++++++ pubspec.lock | 35 ++++++++ pubspec.yaml | 1 + 8 files changed, 273 insertions(+), 10 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 38d3d62..9d660df 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -6,6 +6,7 @@ additional functionality it is fine to subclass or reimplement FlutterApplication and put your custom class here. --> + { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) async { // await loadMenu(); + await util.permissionCheck(context,pHandler.Permission.storage,()async{print("storage permit granted!");},customMessage: " untuk menyimpan data backup"); + }); } clearData(context)async{ String errMsg; - Directory documentsDirectory = await getApplicationDocumentsDirectory(); + Directory documentsDirectory = await getExternalStorageDirectory(); String path = join(documentsDirectory.path, "assets.db"); File db = File(path); if(db.existsSync()){ @@ -120,7 +124,7 @@ class _HomeState extends State { padding: const EdgeInsets.only(bottom:45.0), child: FloatingActionButton( onPressed: ()async{ - Directory documentsDirectory = await getApplicationDocumentsDirectory(); + Directory documentsDirectory = await getExternalStorageDirectory(); String path = join(documentsDirectory.path, "assets.db"); File db = File(path); if(db.existsSync()){ @@ -168,7 +172,27 @@ class _HomeState extends State { Text('Change Host Address',style: TextStyle(color: Colors.blueGrey,fontWeight: FontWeight.w500),) ], ), - ) + ), + PopupMenuItem( + value:'backup', + child: Row( + children: [ + Icon(Icons.save,color: Colors.black,), + SizedBox(width: 10,), + Text('Backup Data') + ], + ), + ), + PopupMenuItem( + value:'restore', + child: Row( + children: [ + Icon(Icons.sync,color: Colors.black,), + SizedBox(width: 10,), + Text('Restore Data') + ], + ), + ), ], onSelected: (value)async{ if(value == "changeAddress"){ @@ -196,6 +220,108 @@ class _HomeState extends State { }); } + if(value == 'backup'){ + if(prefs.getString(keyClass.dbName) != null){ + bool isBackup = await showDialog(context: context,builder: (context)=>AlertDialog( + title: Text('Backup Data ?'), + content: Text('Backup data akan menghapus dan mengganti data backup unit dan cabang sebelumnya.'), + actions: [ + TextButton( + child: Text('OK'), + onPressed: ()async{ + Navigator.pop(context,true); + }, + ), + TextButton( + child: Text('Cancel'), + onPressed: ()=>Navigator.pop(context,false), + ) + ], + )); + if(isBackup??false){ + var result = await DBHelper.database.backupDb(context); + util.showToast(result["STATUS"]==1?'NORMAL':'ERROR', result['MSG']); + } + } + else{ + util.showToast('ERROR', "Data Unit cabang tidak ditemukan. Silakan get data terlbih dahulu."); + } + } + if(value == 'restore'){ + if(prefs.getString(keyClass.dbName) == null){ + util.showToast('ERROR', "Data Unit cabang tidak ditemukan. Silakan get data terlbih dahulu."); + } + else{ + if(prefs.getString(keyClass.dbName) == prefs.getString(keyClass.backup_stock_id)){ + String stock_taking_id = prefs.getString(keyClass.dbName); + if(stock_taking_id!=null){ + bool isRestore = await showDialog(context: context,builder: (context)=>AlertDialog( + title: Text('Restore Data ?'), + content: Text('Restore data akan menghapus dan mengganti data unit dan cabang yang ada dengan data backup.'), + actions: [ + TextButton( + child: Text('OK'), + onPressed: ()async{ + Navigator.pop(context,true); + }, + ), + TextButton( + child: Text('Cancel'), + onPressed: ()=>Navigator.pop(context,false), + ) + ], + )); + if(isRestore??false){ + var response; + bool isclear; + Directory documentsDirectory = await getExternalStorageDirectory(); + String path = join(documentsDirectory.path, "assets.db"); + File db = File(path); + if(db.existsSync()){ + isclear = await clearData(context); + } + else{ + isclear = true; + } + if(isclear??false){ + var result = await DBHelper.database.restoreDb(context); + if(result["STATUS"]==1){ + await prefs.remove(keyClass.dbName); + // await prefs.remove(keyClass.lastDownload); + // await prefs.remove(keyClass.lastUpload); + // await prefs.remove(keyClass.targetProccess); + // await prefs.remove(keyClass.submitProccess); + setState(() { + // lastUpload = ''; + // lastDownload = ''; + // timeString = ''; + }); + // valueTab value = await DBHelper.database.getValue(keyClass.tgl_start); + // if(value != null)await prefs.setString(keyClass.lastDownload, DateFormat('dd-MM-yyyy HH:mm:ss').parse(value.value).toIso8601String()); + // else { + // await prefs.setString(keyClass.lastDownload, DateTime.now().toIso8601String()); + // } + // value = await DBHelper.database.getValue(keyClass.stock_id); + // if(value != null) await prefs.setString(keyClass.stock_id,value.value); + // else { + await prefs.setString(keyClass.dbName,prefs.getString(keyClass.backup_stock_id)); + // } + // loadState(); + setState(() { + // lastDownload = prefs.getString(keyClass.lastDownload); + }); + } + response = result["MSG"]; + } + if(response != null)util.showToast('GENERAL', response); + } + } + } + else { + util.showToast("ERROR", "File Backup tidak ditemukan atau sudah selesai"); + } + } + } }, child: Padding( padding: const EdgeInsets.all(8.0), @@ -322,6 +448,7 @@ class _HomeState extends State { // await DBHelper.database.closeDb(); // var allUnits = await DBHelper.database.getAllAsset(); // print('${allUnits.length} Units'); + if(prefs.getString(keyClass.backup_stock_id) == null) prefs.setString(keyClass.backup_stock_id,selected); util.showToast('ALERT','Data Downloaded'); } if(value==-1.0){ @@ -379,7 +506,7 @@ class _HomeState extends State { child: InkWell( onTap: ()async{ await Future.delayed(Duration(milliseconds: 300)); - Directory documentsDirectory = await getApplicationDocumentsDirectory(); + Directory documentsDirectory = await getExternalStorageDirectory(); String path = join(documentsDirectory.path, "assets.db"); File db = File(path); if(db.existsSync()) Navigator.pushNamed(context, '/stocking'); @@ -411,7 +538,7 @@ class _HomeState extends State { InkWell( onTap: ()async{ final file = File( - "${(await getApplicationDocumentsDirectory()).path}/assets.db"); + "${(await getExternalStorageDirectory()).path}/assets.db"); if(file.existsSync()){ TextEditingController sendingUser = new TextEditingController(); sendingUser.text = prefs.getString(keyClass.user)??''; @@ -497,7 +624,7 @@ class _HomeState extends State { ), InkWell( onTap: ()async{ - Directory documentsDirectory = await getApplicationDocumentsDirectory(); + Directory documentsDirectory = await getExternalStorageDirectory(); String path = join(documentsDirectory.path, "assets.db"); File db = File(path); if(db.existsSync()) await clearData(context); diff --git a/lib/util/dbHandler.dart b/lib/util/dbHandler.dart index 6f9a481..5220c5f 100644 --- a/lib/util/dbHandler.dart +++ b/lib/util/dbHandler.dart @@ -1,3 +1,5 @@ +import 'dart:typed_data'; + import 'package:assetstock/util/Models.dart'; import 'package:sqflite/sqflite.dart'; import 'package:path_provider/path_provider.dart'; @@ -6,6 +8,10 @@ import 'dart:io'; import 'dart:async'; import 'package:path/path.dart'; import 'package:intl/intl.dart'; +import 'package:assetstock/main.dart'; +import 'package:permission_handler/permission_handler.dart' as pHandler; + + class DBHelper{ DBHelper._(); @@ -19,8 +25,70 @@ class DBHelper{ return _db; } + backupDb(context) async{ + var result = {"STATUS":0,"MSG":"Backup gagal!"}; + var stock_id = prefs.getString(keyClass.dbName)??''; + if(stock_id != ''){ + await util.permissionCheck(context,pHandler.Permission.storage,()async{ + try{ + // if(dbPath == null || dbPath == ''){ + final database = await db; + var dbPath = database.path; + await DBHelper.database.closeDb(); + // } + await prefs.remove(keyClass.backup_stock_id); + if(stock_id !='' && stock_id != null ) await prefs.setString(keyClass.backup_stock_id,stock_id); + //backupDatabase + print(["aaaaaa",dbPath]); + String backupPath = join(dbPath.substring(0,dbPath.indexOf("/Android"))+"/Download", "${prefs.getString(keyClass.backup_stock_id)}_assets.db"); + print("bbbbbb"); + File backupFile = new File(backupPath); + File dbFile = File(dbPath); + if(dbFile.existsSync()){ + // dbFile.copySync(backupPath); + Uint8List byte = dbFile.readAsBytesSync(); + backupFile.writeAsBytesSync(byte); + result = {"STATUS":1,"MSG":"Backup Berhasil!"}; + } + else{ + result = {"STATUS":0,"MSG":"Backup gagal data unit tidak ditemukan!"}; + print('file backup dont exist tho'); + } + } + catch(e){ + print("backup gagal $e"); + result = {"STATUS":0,"MSG":"Backup gagal!"}; + } + },customMessage: " untuk menyimpan data backup"); + } + else{ + result = {"STATUS":0,"MSG":"Backup gagal data unit tidak ditemukan!"}; + } + + return result; + } + restoreDb(context)async{ + var result = {"STATUS":0,"MSG":"File Backup tidak ditemukan!"}; + if(prefs.getString(keyClass.backup_stock_id)!=null){ + await util.permissionCheck(context,pHandler.Permission.storage,()async{ + Directory documentsDirectory = await getExternalStorageDirectory(); + String backupPath = join(documentsDirectory.path.substring(0,documentsDirectory.path.indexOf("/Android"))+"/Download", "${prefs.getString(keyClass.backup_stock_id)}_assets.db"); + File backupdbFile = File(backupPath); + if(backupdbFile.existsSync()){ + File dbFile = new File(join(documentsDirectory.path, "assets.db")); + Uint8List byte = backupdbFile.readAsBytesSync(); + dbFile.writeAsBytesSync(byte); + result = {"STATUS":1,"MSG":"File Back up successfull"}; + await DBHelper.database.closeDb(); + } + else result = {"STATUS":0,"MSG":"File Backup tidak ditemukan!"}; + },customMessage: " untuk menyimpan data backup"); + } + return result; + } + initDb() async { - Directory documentsDirectory = await getApplicationDocumentsDirectory(); + Directory documentsDirectory = await getExternalStorageDirectory(); String path = join(documentsDirectory.path, "assets.db"); var theDb = await openDatabase(path, version: 1,onCreate: _onCreate); return theDb; @@ -34,7 +102,7 @@ class DBHelper{ } void _onCreate(Database db, int version) async { - Directory documentsDirectory = await getApplicationDocumentsDirectory(); + Directory documentsDirectory = await getExternalStorageDirectory(); String path = join(documentsDirectory.path, "assets.db"); File file = File(path); print('Database created, ${file.lengthSync()}'); diff --git a/lib/util/download_Upload_Handler.dart b/lib/util/download_Upload_Handler.dart index 3f9c432..88495d9 100644 --- a/lib/util/download_Upload_Handler.dart +++ b/lib/util/download_Upload_Handler.dart @@ -49,7 +49,7 @@ class file_Trans_Handler { _progress.add(0.0); print('Finish Download'); final file = File( - "${(await getApplicationDocumentsDirectory()).path}/$fileName"); + "${(await getExternalStorageDirectory()).path}/$fileName"); await file.writeAsBytes(_bytes); _path = file.path; }) @@ -72,7 +72,7 @@ class file_Trans_Handler { List _bytes = []; _finish = false; final file = File( - "${(await getApplicationDocumentsDirectory()).path}/$fileName"); + "${(await getExternalStorageDirectory()).path}/$fileName"); _total = file.lengthSync(); print(_total/1024); try{ diff --git a/lib/util/prefsKey.dart b/lib/util/prefsKey.dart index 230ccee..cbfe676 100644 --- a/lib/util/prefsKey.dart +++ b/lib/util/prefsKey.dart @@ -2,6 +2,7 @@ class keyClass{ static String hostAddress = "HOST_ADDRESS"; static String dbName = "dbName"; static String user ="user"; + static String backup_stock_id ='backupDB'; } class tableName{ diff --git a/lib/util/utils.dart b/lib/util/utils.dart index 68592cb..939dc2d 100644 --- a/lib/util/utils.dart +++ b/lib/util/utils.dart @@ -2,11 +2,41 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:http/http.dart' as http; import 'package:barcode_scan2/barcode_scan2.dart'; import 'package:fluttertoast/fluttertoast.dart'; +import 'package:permission_handler/permission_handler.dart' as pHandler; + class Util{ + + permissionCheck(context,pHandler.Permission permissionType,ifGranted,{customMessage=''})async{ + pHandler.PermissionStatus permission = await permissionType.status; + if(permission!= pHandler.PermissionStatus.granted){ + if(permission== pHandler.PermissionStatus.denied || permission== pHandler.PermissionStatus.restricted){ + showToast('NORMAL', '${permissionType.toString().substring(permissionType.toString().lastIndexOf('.')+1)} permission is needed$customMessage. Please grant the permission!'); + await Future.delayed(Duration(seconds: 3)); + permission = await permissionType.request(); + } + if(permission== pHandler.PermissionStatus.permanentlyDenied) { + showToast('ERROR', 'It seems, your system security explicitly denied access to your ${permissionType.toString().substring(permissionType.toString().lastIndexOf('.')+1)} permission. Please MANUALLY enable it in setings!'); + await Future.delayed(Duration(seconds: 3)); + pHandler.openAppSettings(); + SystemChannels.platform.invokeMethod('SystemNavigator.pop'); + } + if(permission== pHandler.PermissionStatus.denied || permission== pHandler.PermissionStatus.restricted){ + showToast('NORMAL', '${permissionType.toString().substring(permissionType.toString().lastIndexOf('.')+1)} permission is needed$customMessage. Please grant the permission!'); + await Future.delayed(Duration(seconds: 3)); + permission = await permissionType.request(); + } + await permissionCheck(context,permissionType,ifGranted); + } + else{ + await ifGranted(); + } + } + scan()async{ String BarcodeText =''; try{ diff --git a/pubspec.lock b/pubspec.lock index 7041f24..63ca6d9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -303,6 +303,41 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + url: "https://pub.dartlang.org" + source: hosted + version: "9.2.0" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + url: "https://pub.dartlang.org" + source: hosted + version: "9.0.2+1" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + url: "https://pub.dartlang.org" + source: hosted + version: "9.0.4" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "3.7.0" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.0" petitparser: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 887fadb..3d756c6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,6 +33,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.5 + permission_handler: ^9.2.0 dev_dependencies: flutter_launcher_icons: