| @@ -6,6 +6,7 @@ | |||||
| additional functionality it is fine to subclass or reimplement | additional functionality it is fine to subclass or reimplement | ||||
| FlutterApplication and put your custom class here. --> | FlutterApplication and put your custom class here. --> | ||||
| <uses-permission android:name="android.permission.INTERNET" /> | <uses-permission android:name="android.permission.INTERNET" /> | ||||
| <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> | |||||
| <application | <application | ||||
| android:name="${applicationName}" | android:name="${applicationName}" | ||||
| android:label="assetstock" | android:label="assetstock" | ||||
| @@ -9,6 +9,8 @@ import 'package:path_provider/path_provider.dart'; | |||||
| import 'main.dart'; | import 'main.dart'; | ||||
| import 'util/prefsKey.dart'; | import 'util/prefsKey.dart'; | ||||
| import 'util/dbHandler.dart'; | import 'util/dbHandler.dart'; | ||||
| import 'package:permission_handler/permission_handler.dart' as pHandler; | |||||
| class Home extends StatefulWidget { | class Home extends StatefulWidget { | ||||
| Home({Key key}) : super(key: key); | Home({Key key}) : super(key: key); | ||||
| @@ -43,12 +45,14 @@ class _HomeState extends State<Home> { | |||||
| super.initState(); | super.initState(); | ||||
| WidgetsBinding.instance.addPostFrameCallback((_) async { | WidgetsBinding.instance.addPostFrameCallback((_) async { | ||||
| // await loadMenu(); | // await loadMenu(); | ||||
| await util.permissionCheck(context,pHandler.Permission.storage,()async{print("storage permit granted!");},customMessage: " untuk menyimpan data backup"); | |||||
| }); | }); | ||||
| } | } | ||||
| clearData(context)async{ | clearData(context)async{ | ||||
| String errMsg; | String errMsg; | ||||
| Directory documentsDirectory = await getApplicationDocumentsDirectory(); | |||||
| Directory documentsDirectory = await getExternalStorageDirectory(); | |||||
| String path = join(documentsDirectory.path, "assets.db"); | String path = join(documentsDirectory.path, "assets.db"); | ||||
| File db = File(path); | File db = File(path); | ||||
| if(db.existsSync()){ | if(db.existsSync()){ | ||||
| @@ -120,7 +124,7 @@ class _HomeState extends State<Home> { | |||||
| padding: const EdgeInsets.only(bottom:45.0), | padding: const EdgeInsets.only(bottom:45.0), | ||||
| child: FloatingActionButton( | child: FloatingActionButton( | ||||
| onPressed: ()async{ | onPressed: ()async{ | ||||
| Directory documentsDirectory = await getApplicationDocumentsDirectory(); | |||||
| Directory documentsDirectory = await getExternalStorageDirectory(); | |||||
| String path = join(documentsDirectory.path, "assets.db"); | String path = join(documentsDirectory.path, "assets.db"); | ||||
| File db = File(path); | File db = File(path); | ||||
| if(db.existsSync()){ | if(db.existsSync()){ | ||||
| @@ -168,7 +172,27 @@ class _HomeState extends State<Home> { | |||||
| Text('Change Host Address',style: TextStyle(color: Colors.blueGrey,fontWeight: FontWeight.w500),) | Text('Change Host Address',style: TextStyle(color: Colors.blueGrey,fontWeight: FontWeight.w500),) | ||||
| ], | ], | ||||
| ), | ), | ||||
| ) | |||||
| ), | |||||
| PopupMenuItem( | |||||
| value:'backup', | |||||
| child: Row( | |||||
| children: <Widget>[ | |||||
| Icon(Icons.save,color: Colors.black,), | |||||
| SizedBox(width: 10,), | |||||
| Text('Backup Data') | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| PopupMenuItem( | |||||
| value:'restore', | |||||
| child: Row( | |||||
| children: <Widget>[ | |||||
| Icon(Icons.sync,color: Colors.black,), | |||||
| SizedBox(width: 10,), | |||||
| Text('Restore Data') | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ], | ], | ||||
| onSelected: (value)async{ | onSelected: (value)async{ | ||||
| if(value == "changeAddress"){ | if(value == "changeAddress"){ | ||||
| @@ -196,6 +220,108 @@ class _HomeState extends State<Home> { | |||||
| }); | }); | ||||
| } | } | ||||
| 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: <Widget>[ | |||||
| 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: <Widget>[ | |||||
| 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( | child: Padding( | ||||
| padding: const EdgeInsets.all(8.0), | padding: const EdgeInsets.all(8.0), | ||||
| @@ -322,6 +448,7 @@ class _HomeState extends State<Home> { | |||||
| // await DBHelper.database.closeDb(); | // await DBHelper.database.closeDb(); | ||||
| // var allUnits = await DBHelper.database.getAllAsset(); | // var allUnits = await DBHelper.database.getAllAsset(); | ||||
| // print('${allUnits.length} Units'); | // print('${allUnits.length} Units'); | ||||
| if(prefs.getString(keyClass.backup_stock_id) == null) prefs.setString(keyClass.backup_stock_id,selected); | |||||
| util.showToast('ALERT','Data Downloaded'); | util.showToast('ALERT','Data Downloaded'); | ||||
| } | } | ||||
| if(value==-1.0){ | if(value==-1.0){ | ||||
| @@ -379,7 +506,7 @@ class _HomeState extends State<Home> { | |||||
| child: InkWell( | child: InkWell( | ||||
| onTap: ()async{ | onTap: ()async{ | ||||
| await Future.delayed(Duration(milliseconds: 300)); | await Future.delayed(Duration(milliseconds: 300)); | ||||
| Directory documentsDirectory = await getApplicationDocumentsDirectory(); | |||||
| Directory documentsDirectory = await getExternalStorageDirectory(); | |||||
| String path = join(documentsDirectory.path, "assets.db"); | String path = join(documentsDirectory.path, "assets.db"); | ||||
| File db = File(path); | File db = File(path); | ||||
| if(db.existsSync()) Navigator.pushNamed(context, '/stocking'); | if(db.existsSync()) Navigator.pushNamed(context, '/stocking'); | ||||
| @@ -411,7 +538,7 @@ class _HomeState extends State<Home> { | |||||
| InkWell( | InkWell( | ||||
| onTap: ()async{ | onTap: ()async{ | ||||
| final file = File( | final file = File( | ||||
| "${(await getApplicationDocumentsDirectory()).path}/assets.db"); | |||||
| "${(await getExternalStorageDirectory()).path}/assets.db"); | |||||
| if(file.existsSync()){ | if(file.existsSync()){ | ||||
| TextEditingController sendingUser = new TextEditingController(); | TextEditingController sendingUser = new TextEditingController(); | ||||
| sendingUser.text = prefs.getString(keyClass.user)??''; | sendingUser.text = prefs.getString(keyClass.user)??''; | ||||
| @@ -497,7 +624,7 @@ class _HomeState extends State<Home> { | |||||
| ), | ), | ||||
| InkWell( | InkWell( | ||||
| onTap: ()async{ | onTap: ()async{ | ||||
| Directory documentsDirectory = await getApplicationDocumentsDirectory(); | |||||
| Directory documentsDirectory = await getExternalStorageDirectory(); | |||||
| String path = join(documentsDirectory.path, "assets.db"); | String path = join(documentsDirectory.path, "assets.db"); | ||||
| File db = File(path); | File db = File(path); | ||||
| if(db.existsSync()) await clearData(context); | if(db.existsSync()) await clearData(context); | ||||
| @@ -1,3 +1,5 @@ | |||||
| import 'dart:typed_data'; | |||||
| import 'package:assetstock/util/Models.dart'; | import 'package:assetstock/util/Models.dart'; | ||||
| import 'package:sqflite/sqflite.dart'; | import 'package:sqflite/sqflite.dart'; | ||||
| import 'package:path_provider/path_provider.dart'; | import 'package:path_provider/path_provider.dart'; | ||||
| @@ -6,6 +8,10 @@ import 'dart:io'; | |||||
| import 'dart:async'; | import 'dart:async'; | ||||
| import 'package:path/path.dart'; | import 'package:path/path.dart'; | ||||
| import 'package:intl/intl.dart'; | import 'package:intl/intl.dart'; | ||||
| import 'package:assetstock/main.dart'; | |||||
| import 'package:permission_handler/permission_handler.dart' as pHandler; | |||||
| class DBHelper{ | class DBHelper{ | ||||
| DBHelper._(); | DBHelper._(); | ||||
| @@ -19,8 +25,70 @@ class DBHelper{ | |||||
| return _db; | 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 { | initDb() async { | ||||
| Directory documentsDirectory = await getApplicationDocumentsDirectory(); | |||||
| Directory documentsDirectory = await getExternalStorageDirectory(); | |||||
| String path = join(documentsDirectory.path, "assets.db"); | String path = join(documentsDirectory.path, "assets.db"); | ||||
| var theDb = await openDatabase(path, version: 1,onCreate: _onCreate); | var theDb = await openDatabase(path, version: 1,onCreate: _onCreate); | ||||
| return theDb; | return theDb; | ||||
| @@ -34,7 +102,7 @@ class DBHelper{ | |||||
| } | } | ||||
| void _onCreate(Database db, int version) async { | void _onCreate(Database db, int version) async { | ||||
| Directory documentsDirectory = await getApplicationDocumentsDirectory(); | |||||
| Directory documentsDirectory = await getExternalStorageDirectory(); | |||||
| String path = join(documentsDirectory.path, "assets.db"); | String path = join(documentsDirectory.path, "assets.db"); | ||||
| File file = File(path); | File file = File(path); | ||||
| print('Database created, ${file.lengthSync()}'); | print('Database created, ${file.lengthSync()}'); | ||||
| @@ -49,7 +49,7 @@ class file_Trans_Handler { | |||||
| _progress.add(0.0); | _progress.add(0.0); | ||||
| print('Finish Download'); | print('Finish Download'); | ||||
| final file = File( | final file = File( | ||||
| "${(await getApplicationDocumentsDirectory()).path}/$fileName"); | |||||
| "${(await getExternalStorageDirectory()).path}/$fileName"); | |||||
| await file.writeAsBytes(_bytes); | await file.writeAsBytes(_bytes); | ||||
| _path = file.path; | _path = file.path; | ||||
| }) | }) | ||||
| @@ -72,7 +72,7 @@ class file_Trans_Handler { | |||||
| List<int> _bytes = []; | List<int> _bytes = []; | ||||
| _finish = false; | _finish = false; | ||||
| final file = File( | final file = File( | ||||
| "${(await getApplicationDocumentsDirectory()).path}/$fileName"); | |||||
| "${(await getExternalStorageDirectory()).path}/$fileName"); | |||||
| _total = file.lengthSync(); | _total = file.lengthSync(); | ||||
| print(_total/1024); | print(_total/1024); | ||||
| try{ | try{ | ||||
| @@ -2,6 +2,7 @@ class keyClass{ | |||||
| static String hostAddress = "HOST_ADDRESS"; | static String hostAddress = "HOST_ADDRESS"; | ||||
| static String dbName = "dbName"; | static String dbName = "dbName"; | ||||
| static String user ="user"; | static String user ="user"; | ||||
| static String backup_stock_id ='backupDB'; | |||||
| } | } | ||||
| class tableName{ | class tableName{ | ||||
| @@ -2,11 +2,41 @@ import 'dart:async'; | |||||
| import 'dart:convert'; | import 'dart:convert'; | ||||
| import 'dart:io'; | import 'dart:io'; | ||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| import 'package:flutter/services.dart'; | |||||
| import 'package:http/http.dart' as http; | import 'package:http/http.dart' as http; | ||||
| import 'package:barcode_scan2/barcode_scan2.dart'; | import 'package:barcode_scan2/barcode_scan2.dart'; | ||||
| import 'package:fluttertoast/fluttertoast.dart'; | import 'package:fluttertoast/fluttertoast.dart'; | ||||
| import 'package:permission_handler/permission_handler.dart' as pHandler; | |||||
| class Util{ | 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{ | scan()async{ | ||||
| String BarcodeText =''; | String BarcodeText =''; | ||||
| try{ | try{ | ||||
| @@ -303,6 +303,41 @@ packages: | |||||
| url: "https://pub.dartlang.org" | url: "https://pub.dartlang.org" | ||||
| source: hosted | source: hosted | ||||
| version: "2.1.0" | 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: | petitparser: | ||||
| dependency: transitive | dependency: transitive | ||||
| description: | description: | ||||
| @@ -33,6 +33,7 @@ dependencies: | |||||
| # The following adds the Cupertino Icons font to your application. | # The following adds the Cupertino Icons font to your application. | ||||
| # Use with the CupertinoIcons class for iOS style icons. | # Use with the CupertinoIcons class for iOS style icons. | ||||
| cupertino_icons: ^1.0.5 | cupertino_icons: ^1.0.5 | ||||
| permission_handler: ^9.2.0 | |||||
| dev_dependencies: | dev_dependencies: | ||||
| flutter_launcher_icons: | flutter_launcher_icons: | ||||