Flutter app for Asset Management
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

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