Flutter app for Asset Management
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

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