Flutter app for Asset Management
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

618 linhas
26 KiB

  1. import 'dart:io';
  2. import 'util/photo_viewer.dart';
  3. import 'package:assetstock/util/dbHandler.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:image_picker/image_picker.dart';
  6. import 'main.dart';
  7. import 'util/Models.dart';
  8. import 'package:http/http.dart' as http;
  9. import 'util/prefsKey.dart';
  10. class AssetDetails extends StatefulWidget {
  11. // AssetDetails({Key key}) : super(key: key);
  12. int no;
  13. List<String>lokasi;
  14. String initTag;
  15. AssetDetails({this.no,this.lokasi,this.initTag});
  16. @override
  17. _AssetDetailsState createState() => _AssetDetailsState();
  18. }
  19. class _AssetDetailsState extends State<AssetDetails> with TickerProviderStateMixin {
  20. final barCode = new TextEditingController();
  21. final prefixCode = new TextEditingController();
  22. final qty = new TextEditingController();
  23. final ket = new TextEditingController();
  24. TabController _controller;
  25. int _currentIndex;
  26. Asset _asset = new Asset();
  27. final focusNode = new FocusNode();
  28. bool isAppend = false;
  29. loadAsset()async{
  30. var blob = await DBHelper.database.getBlobbyNo(widget.no);
  31. if(blob!=null){
  32. var result = await DBHelper.database.searchbyTagNumber(blob.tag_number.toUpperCase());
  33. if(result['DATA']!=null) {
  34. result['DATA'].blob = blob.blob;
  35. result['DATA'].no = widget.no;
  36. result['DATA'].keterangan = blob.keterangan;
  37. }
  38. else util.showToast('Alert', 'Asset data not found');
  39. String tag_number = result['DATA'].tag_number;
  40. int separator = tag_number.lastIndexOf('/')+1;
  41. setState(() {
  42. _asset = result['DATA'];
  43. prefixCode.text = tag_number.substring(0,separator);
  44. barCode.text = tag_number.substring(separator);
  45. ket.text = result['DATA'].keterangan;
  46. });
  47. }
  48. else{
  49. util.showToast('Alert', 'Asset data not found');
  50. }
  51. }
  52. redirectNonAudit()async {
  53. var blob = await DBHelper.database.getBlobbyTag(widget.initTag);
  54. print("checkExist $blob");
  55. if(blob!=null){
  56. widget.no = blob.no;
  57. await loadAsset();
  58. // var blob = await DBHelper.database.getBlobbyTag(widget.initTag);
  59. // var result = await DBHelper.database.searchbyTagNumber(blob.tag_number.toUpperCase());
  60. // if(result['DATA']!=null) {
  61. // result['DATA'].blob = blob.blob;
  62. // result['DATA'].no = blob.no;
  63. // result['DATA'].keterangan = blob.keterangan;
  64. // }
  65. // _asset = result['DATA'];
  66. // ket.text = blob.keterangan;
  67. }
  68. else{
  69. setState(() {
  70. prefixCode.text = widget.initTag.substring(0,6);
  71. barCode.text = widget.initTag.substring(6);
  72. });
  73. await findAsset(prefixCode.text+barCode.text);
  74. }
  75. }
  76. @override
  77. void initState() {
  78. // TODO: implement initState
  79. super.initState();
  80. qty.text='1';
  81. _controller = new TabController(length: 1, vsync: this);
  82. _controller.addListener(() {
  83. setState(() {
  84. _currentIndex = _controller.index;
  85. });
  86. });
  87. if(widget.no!=null){
  88. loadAsset();
  89. }
  90. if(widget.initTag!=null){
  91. redirectNonAudit();
  92. }
  93. }
  94. findAsset(query,{silent=false})async{
  95. var result = await DBHelper.database.searchbyTagNumber(query.toUpperCase());
  96. if(result['DATA']!=null){
  97. if(result['EXIST']){
  98. if(widget.no==null){
  99. setState(() {
  100. isAppend=false;
  101. barCode.text = '';
  102. ket.text = '';
  103. _asset = new Asset();
  104. });
  105. FocusScope.of(context).requestFocus(focusNode);
  106. }
  107. else{
  108. String tag_number = _asset.tag_number;
  109. int separator = tag_number.lastIndexOf('/')+1;
  110. setState(() {
  111. prefixCode.text = tag_number.substring(0,separator);
  112. barCode.text = tag_number.substring(separator);
  113. });
  114. }
  115. if(!silent)util.showToast('Alert', 'Asset data already inserted');
  116. }
  117. else{
  118. var image;
  119. if(_asset.blob!=null)image=_asset.blob;
  120. setState(() {
  121. isAppend=false;
  122. _asset = result['DATA'];
  123. if(image!=null)_asset.blob = image;
  124. _asset.no = widget.no;
  125. });
  126. }
  127. }
  128. else{
  129. var image;
  130. if(_asset.blob!=null)image=_asset.blob;
  131. setState(() {
  132. // barCode.text = '';
  133. isAppend=true;
  134. // ket.text = '';
  135. _asset = new Asset();
  136. if(image!=null)_asset.blob = image;
  137. _asset.tag_number = query.toUpperCase();
  138. _asset.no = widget.no;
  139. });
  140. // FocusScope.of(context).requestFocus(focusNode);
  141. if(!silent)util.showToast('Alert', 'Asset data not found');
  142. }
  143. }
  144. @override
  145. Widget build(BuildContext context) {
  146. return Scaffold(
  147. resizeToAvoidBottomInset: true,
  148. body: Container(
  149. padding: EdgeInsets.only(top: 20,bottom: 50),
  150. color: Colors.grey.withOpacity(0.3),
  151. child: Column(
  152. children: <Widget>[
  153. Expanded(
  154. flex: 5,
  155. child: Column(
  156. children: <Widget>[
  157. Expanded(
  158. flex:18,
  159. child: TabBarView(
  160. controller: _controller,
  161. children: <Widget>[
  162. Padding(
  163. padding: EdgeInsets.only(top:20,left: 20,right: 20),
  164. child: Stack(
  165. children: <Widget>[
  166. Container(color: Colors.grey,),
  167. Positioned.fill(child: InkWell(onTap: ()async{
  168. var image = await picker.getImage(source: ImageSource.camera,imageQuality: 60,maxWidth: 600);
  169. if(image!=null){
  170. _asset.blob = await image.readAsBytes();
  171. setState(() {
  172. });
  173. print(File(image.path).lengthSync()/1024);
  174. File(image.path).deleteSync();
  175. }
  176. },child: Container(
  177. decoration: BoxDecoration(
  178. image: (_asset!=null&&_asset.blob!=null)?DecorationImage(
  179. image: MemoryImage(_asset.blob),
  180. fit: BoxFit.fitWidth
  181. ):null
  182. ),
  183. child: (_asset!=null&&_asset.blob!=null)?null:Icon(Icons.camera_alt,size: 200,color: Colors.white,))))
  184. ],
  185. ),
  186. ),
  187. // Padding(
  188. // padding: EdgeInsets.only(top:20,left: 20,right: 20),
  189. // child: Stack(
  190. // children: <Widget>[
  191. // Container(color: Colors.grey,),
  192. // Positioned.fill(child: InkWell(onTap: ()async{
  193. // await picker.getImage(source: ImageSource.camera);
  194. // },child: Container(child: Icon(Icons.camera_alt,size: 200,color: Colors.white,))))
  195. // ],
  196. // ),
  197. // ),
  198. ],
  199. ),
  200. ),
  201. Expanded(
  202. flex:1,
  203. child:
  204. Container(
  205. // color: Colors.grey,
  206. // child: TabBar(
  207. // indicatorColor: Colors.blueGrey,
  208. // controller: _controller,
  209. // labelColor: Colors.blueGrey,
  210. // labelStyle: TextStyle(
  211. // fontSize: 17,
  212. // fontWeight: FontWeight.bold
  213. // ),
  214. // unselectedLabelStyle: TextStyle(
  215. // fontSize: 16
  216. // ),
  217. // indicatorSize: TabBarIndicatorSize.label,
  218. // tabs: <Widget>[
  219. // Tab(
  220. // text: 'Asset',
  221. // ),
  222. // Tab(
  223. // text: 'Barcode',
  224. // ),
  225. // ],
  226. // ),
  227. )
  228. ),
  229. ],
  230. ),
  231. ),
  232. Expanded(
  233. flex: 5,
  234. child: Container(
  235. color: Colors.white,
  236. padding: EdgeInsets.all(20),
  237. child: SingleChildScrollView(
  238. scrollDirection: Axis.vertical,
  239. child: Column(
  240. mainAxisAlignment: MainAxisAlignment.start,
  241. children: <Widget>[
  242. (_asset.tag_number!=null)?Container(
  243. alignment: Alignment.centerRight,
  244. child: InkWell(
  245. onTap: ()async {
  246. try{
  247. var dbName = await DBHelper.database.getDbName();
  248. var bUnit = await DBHelper.database.getBUnit();
  249. util.showLoading(context);
  250. http.Response result = await http.get(
  251. Uri.parse('${prefs.getString(keyClass.hostAddress)??"https://asset.thamringroup.web.id"}/api/images?q=${_asset.tag_number}&s=${dbName}&b=${bUnit}'),
  252. ).timeout(Duration(seconds: 3));
  253. Navigator.pop(context);
  254. if(result!=null){
  255. Navigator.push(context, MaterialPageRoute(builder: (context) => PhotoViewer(result.bodyBytes)));
  256. }
  257. else util.showToast('ALERT', "No Archived Images yet");
  258. }
  259. catch(e){
  260. Navigator.pop(context);
  261. print(e);
  262. util.showToast('ALERT', "No Archived Images yet");
  263. }
  264. //showPhoto
  265. },
  266. child: Padding(
  267. padding: const EdgeInsets.all(4.0),
  268. child: Text('Archived images',style: TextStyle(color: Colors.indigo, decoration: TextDecoration.underline,),),
  269. ),
  270. ),
  271. ):Container(),
  272. (_asset.tag_number!=null)?SizedBox(height: 5,):Container(),
  273. Row(
  274. children: <Widget>[
  275. Expanded(
  276. flex:3,
  277. child: Container(
  278. child: TextField(
  279. controller: prefixCode,
  280. autofocus: (widget.no==null),
  281. onSubmitted: (value)async{
  282. String query = value.replaceAll('*', '');
  283. query = query.substring(0,query.lastIndexOf('/')+1);
  284. setState(() {
  285. prefixCode.text = query;
  286. });
  287. if(prefixCode.text!=''&&barCode.text!='')await findAsset(prefixCode.text+barCode.text);
  288. else FocusScope.of(context).requestFocus(focusNode);
  289. },
  290. decoration: InputDecoration(
  291. hintText: "Prefix code",
  292. alignLabelWithHint: true,
  293. ),
  294. ),
  295. ),
  296. ),
  297. SizedBox(width: 10,),
  298. Expanded(
  299. flex:3,
  300. child: Container(
  301. child: TextField(
  302. controller: barCode,
  303. focusNode: focusNode,
  304. autofocus: (widget.no==null),
  305. onSubmitted: (value)async{
  306. String query = value.replaceAll('*', '');
  307. if(prefixCode.text!=''){
  308. query = query.replaceAll(prefixCode.text.toUpperCase(), '');
  309. }
  310. else{
  311. if(query.contains('/'))query = query.substring(query.lastIndexOf('/'));
  312. util.showToast('ALERT', 'Please fill the prefix first');
  313. }
  314. setState(() {
  315. barCode.text = query;
  316. });
  317. if(prefixCode.text!=''&&barCode.text!='')await findAsset(prefixCode.text+barCode.text);
  318. },
  319. decoration: InputDecoration(
  320. hintText: "Suffix / Barcode",
  321. alignLabelWithHint: true,
  322. suffixIcon: InkWell(onTap: ()async{
  323. if(prefixCode.text!=''){
  324. var scan = await util.scan();
  325. if(scan['STATUS']==1){
  326. String query = scan['DATA'];
  327. // print("$query != ${prefixCode.text.toUpperCase()}");
  328. setState(() {
  329. query = query.trim().replaceAll(prefixCode.text.toUpperCase(), '');
  330. barCode.text = query;
  331. });
  332. if(prefixCode.text!=''&&barCode.text!='')await findAsset(prefixCode.text+barCode.text);
  333. }
  334. }
  335. else util.showToast('ALERT', 'Please fill the prefix first');
  336. },child: Icon(Icons.center_focus_strong))
  337. ),
  338. ),
  339. ),
  340. ),
  341. Expanded(flex: 1,
  342. child: Container(
  343. alignment: Alignment.centerRight,
  344. child: Text('Qty :'),
  345. ),),
  346. Expanded(
  347. flex:2,
  348. child: Container(
  349. child: TextField(
  350. enabled: false,
  351. keyboardType: TextInputType.number,
  352. decoration: InputDecoration(
  353. contentPadding: EdgeInsets.all(8)
  354. ),
  355. controller: qty,
  356. ),
  357. ),
  358. ),
  359. ],
  360. ),
  361. SizedBox(height: 5,),
  362. Container(
  363. alignment: Alignment.centerLeft,
  364. height: 50,
  365. child: Row(
  366. children: <Widget>[
  367. Expanded(
  368. flex : 3,
  369. child: Text('Note ',style: TextStyle(fontSize: 16),),
  370. ),
  371. Expanded(
  372. flex : 1,
  373. child: Text(':',style: TextStyle(fontSize: 16),),
  374. ),
  375. Expanded(
  376. flex : 7,
  377. child: TextField(
  378. controller: ket,
  379. decoration: InputDecoration(
  380. hintText: "Insert Note here",
  381. ),
  382. ),
  383. ),
  384. ],
  385. ),
  386. ),
  387. SizedBox(height: 5,),
  388. Container(
  389. alignment: Alignment.centerLeft,
  390. height: 50,
  391. child: Row(
  392. children: <Widget>[
  393. Expanded(
  394. flex : 3,
  395. child: Text('Asset No ',style: TextStyle(fontSize: 16),),
  396. ),
  397. Expanded(
  398. flex : 1,
  399. child: Text(':',style: TextStyle(fontSize: 16),),
  400. ),
  401. Expanded(
  402. flex : 7,
  403. child: Text((_asset.asset_no??'-')=='null'?'-':_asset.asset_no??'-',style: TextStyle(fontSize: 16),),
  404. ),
  405. ],
  406. ),
  407. ),
  408. SizedBox(height: 5,),
  409. Container(
  410. alignment: Alignment.centerLeft,
  411. height: 50,
  412. child: Row(
  413. children: <Widget>[
  414. Expanded(
  415. flex : 3,
  416. child: Text('Asset Desc ',style: TextStyle(fontSize: 16),),
  417. ),
  418. Expanded(
  419. flex : 1,
  420. child: Text(':',style: TextStyle(fontSize: 16),),
  421. ),
  422. Expanded(
  423. flex : 7,
  424. child: Text(_asset.asset_desc??'-',style: TextStyle(fontSize: 16),),
  425. ),
  426. ],
  427. ),
  428. ),
  429. SizedBox(height: 5,),
  430. Container(
  431. alignment: Alignment.centerLeft,
  432. height: 50,
  433. child: Row(
  434. children: <Widget>[
  435. Expanded(
  436. flex : 3,
  437. child: Text('PIC ',style: TextStyle(fontSize: 16),),
  438. ),
  439. Expanded(
  440. flex : 1,
  441. child: Text(':',style: TextStyle(fontSize: 16),),
  442. ),
  443. Expanded(
  444. flex : 7,
  445. child: Text(_asset.pic??'-',style: TextStyle(fontSize: 16),),
  446. ),
  447. ],
  448. ),
  449. ),
  450. SizedBox(height: 5,),
  451. Container(
  452. alignment: Alignment.centerLeft,
  453. height: 50,
  454. child: Row(
  455. children: <Widget>[
  456. Expanded(
  457. flex : 3,
  458. child: Text('Lantai ',style: TextStyle(fontSize: 16),),
  459. ),
  460. Expanded(
  461. flex : 1,
  462. child: Text(':',style: TextStyle(fontSize: 16),),
  463. ),
  464. Expanded(
  465. flex : 7,
  466. child: Text(_asset.lantai??'-',style: TextStyle(fontSize: 16),),
  467. ),
  468. ],
  469. ),
  470. ),
  471. SizedBox(height: 5,),
  472. Container(
  473. alignment: Alignment.centerLeft,
  474. height: 50,
  475. child: Row(
  476. children: <Widget>[
  477. Expanded(
  478. flex : 3,
  479. child: Text('Ruang ',style: TextStyle(fontSize: 16),),
  480. ),
  481. Expanded(
  482. flex : 1,
  483. child: Text(':',style: TextStyle(fontSize: 16),),
  484. ),
  485. Expanded(
  486. flex : 7,
  487. child: Text(_asset.ruangan??'-',style: TextStyle(fontSize: 16),),
  488. ),
  489. ],
  490. ),
  491. ),
  492. // SizedBox(height: 5,),
  493. // Container(
  494. // alignment: Alignment.centerLeft,
  495. // height: 50,
  496. // child: Row(
  497. // children: <Widget>[
  498. // Expanded(
  499. // flex : 3,
  500. // child: Text('Gedung ',style: TextStyle(fontSize: 16),),
  501. // ),
  502. // Expanded(
  503. // flex : 1,
  504. // child: Text(':',style: TextStyle(fontSize: 16),),
  505. // ),
  506. // Expanded(
  507. // flex : 7,
  508. // child: Text(_asset.gedung??'-',style: TextStyle(fontSize: 16),),
  509. // ),
  510. // ],
  511. // ),
  512. // ),
  513. ],
  514. ),
  515. ),
  516. ),
  517. ),
  518. ],
  519. ),
  520. ),
  521. bottomSheet: Container(
  522. height: 50,
  523. // color: Colors.grey.withOpacity(0.3),
  524. child: Row(
  525. children: <Widget>[
  526. Expanded(
  527. flex: 5,
  528. child: TextButton(
  529. onPressed: ()async{
  530. if(barCode.text!=''&&prefixCode.text!='')await findAsset(prefixCode.text+barCode.text,silent: true);
  531. else _asset.tag_number = null;
  532. if(_asset.tag_number!=null&&_asset.blob!=null){
  533. _asset.keterangan = ket.text;
  534. bool upsertReady = !isAppend;
  535. if(isAppend){
  536. upsertReady = await showDialog(context: context,builder: (context)=>WillPopScope(
  537. onWillPop: ()async{
  538. Navigator.pop(context,false);
  539. return false;
  540. },
  541. child: AlertDialog(
  542. title: Text('Append New Asset'),
  543. content: Text('${(widget.no==null)?'Insert':'Update'} brand new asset?'),
  544. actions: <Widget>[
  545. TextButton(
  546. onPressed: ()async{
  547. Navigator.pop(context,true);
  548. },
  549. child: Text('Save'),
  550. ),
  551. TextButton(
  552. onPressed: ()async{
  553. Navigator.pop(context,false);
  554. },
  555. child: Text('Cancel'),
  556. )
  557. ],
  558. ),
  559. ));
  560. }
  561. if(upsertReady){
  562. if(widget.no==null){
  563. var insert = await DBHelper.database.insertAsset(_asset);
  564. if(insert!=null){
  565. util.showToast("SUCCESS", 'Asset Inserted');
  566. await DBHelper.database.closeDb();
  567. if(widget.initTag!=null)Navigator.pop(context);
  568. setState(() {
  569. barCode.text = '';
  570. ket.text = '';
  571. _asset = new Asset();
  572. });
  573. FocusScope.of(context).requestFocus(focusNode);
  574. }
  575. }
  576. else{
  577. var update = await DBHelper.database.updateAsset(_asset);
  578. if(update!=null){
  579. util.showToast("SUCCESS", 'Asset Updated');
  580. await DBHelper.database.closeDb();
  581. Navigator.pop(context);
  582. }
  583. }
  584. }
  585. }
  586. else{
  587. util.showToast('ERROR', 'Please complete the asset data');
  588. }
  589. },
  590. style: TextButton.styleFrom(
  591. backgroundColor: Colors.green,
  592. ),
  593. child: Container(alignment: Alignment.center,height: 50,
  594. child: Text('Save',style: TextStyle(color: Colors.white),)),
  595. ),
  596. ),
  597. Expanded(
  598. flex: 5,
  599. child: TextButton(
  600. style: TextButton.styleFrom(
  601. backgroundColor: Colors.red,
  602. ),
  603. onPressed: (){
  604. Navigator.pop(context);
  605. },
  606. child: Container(alignment: Alignment.center,height:50,child: Text('Cancel',style: TextStyle(color: Colors.white))),
  607. ),
  608. ),
  609. ],
  610. ),
  611. ),
  612. );
  613. }
  614. }