Business Login Flutter Apps
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

393 rivejä
20 KiB

  1. import 'dart:async';
  2. import 'dart:typed_data';
  3. import 'package:flutter/services.dart';
  4. import '../main.dart';
  5. import 'package:flutter/cupertino.dart';
  6. import 'package:flutter/material.dart';
  7. import 'unit_details.dart';
  8. import '../Widgets/photo_viewer.dart';
  9. import 'package:barcode_scan2/barcode_scan2.dart';
  10. import '../Model/unit.dart';
  11. import '../Utils/db_helper.dart';
  12. import '../Blocs/Units/List/list_unit_bloc.dart';
  13. import 'package:flutter_bloc/flutter_bloc.dart';
  14. class UnitsPage extends StatefulWidget {
  15. UnitsPage({Key? key}) : super(key: key);
  16. @override
  17. _UnitsState createState() => _UnitsState();
  18. }
  19. class _UnitsState extends State<UnitsPage> with SingleTickerProviderStateMixin,RouteAware {
  20. List<Unit> unitsRef = [];
  21. List<Blob?> BlobsRef = [];
  22. bool completed = false;
  23. int totalUnit = 0;
  24. final search_controller = new TextEditingController();
  25. bool hideAppbar = false;
  26. String search = '';
  27. late ListUnitBloc _unitBloc;
  28. Map<Function, Timer> _timeouts = {};
  29. void debounce(Duration timeout, Function target, [List arguments = const []]) {
  30. if (_timeouts.containsKey(target)) {
  31. _timeouts[target]?.cancel();
  32. }
  33. Timer timer = Timer(timeout, () {
  34. Function.apply(target, arguments);
  35. });
  36. _timeouts[target] = timer;
  37. }
  38. void _onChanged(String val)async {
  39. search = search_controller.text;
  40. _unitBloc.add(ListUnit(search: search,completed: completed));
  41. }
  42. Future scan() async {
  43. try {
  44. search = '';
  45. setState(() => search_controller.text = search);
  46. ScanResult result = await BarcodeScanner.scan();
  47. String barcode = result.rawContent;
  48. setState(() => this.search = barcode);
  49. } on PlatformException catch (e) {
  50. if (e.code == BarcodeScanner.cameraAccessDenied) {
  51. util.showFlushbar(context, 'The user did not grant the camera permission!',color: Colors.red);
  52. setState(() {
  53. this.search = '';
  54. });
  55. } else {
  56. util.showFlushbar(context, 'Unknown error: $e',color: Colors.red);
  57. setState(() => this.search = '');
  58. }
  59. } on FormatException {
  60. setState(() => this.search =
  61. '');
  62. } catch (e) {
  63. util.showFlushbar(context, 'Unknown error: $e',color: Colors.red);
  64. setState(() => this.search = '');
  65. }
  66. setState(() => search_controller.text = search);
  67. }
  68. @override
  69. void initState() {
  70. super.initState();
  71. _unitBloc = ListUnitBloc();
  72. WidgetsBinding.instance!.addPostFrameCallback((_) async {
  73. if(locationStream==null)await util.streamLocation(context);
  74. else {
  75. if(locationStream!.isPaused) locationStream!.resume();
  76. }
  77. });
  78. }
  79. @override
  80. void didChangeDependencies() {
  81. super.didChangeDependencies();
  82. routeObserver.subscribe(this, ModalRoute.of(context) as PageRoute);
  83. }
  84. @override
  85. void dispose() {
  86. print('LocationStream paused');
  87. if(locationStream!.isPaused)locationStream!.pause();
  88. _unitBloc.close();
  89. routeObserver.unsubscribe(this);
  90. super.dispose();
  91. }
  92. // @override
  93. // void didPushNext() async {
  94. // //pushed from home
  95. // _unitBloc.add(ListUnit(search: search,completed: completed));
  96. // }
  97. @override
  98. void didPopNext() async {
  99. //popped to home
  100. _unitBloc.add(ListUnit(search: search,completed: completed));
  101. }
  102. @override
  103. Widget build(BuildContext context) {
  104. return WillPopScope(
  105. onWillPop: ()async{
  106. if(hideAppbar) {
  107. setState(() {
  108. hideAppbar=false;
  109. search = '';
  110. search_controller.text = '';
  111. });
  112. _unitBloc.add(ListUnit(search: search,completed: completed));
  113. return false;
  114. }
  115. else {
  116. return true;
  117. }
  118. },
  119. child: Scaffold(
  120. appBar: (hideAppbar)?
  121. AppBar(
  122. backgroundColor: Colors.white,
  123. leading: GestureDetector(
  124. onTap:()async{
  125. setState(() {
  126. hideAppbar=false;
  127. search = '';
  128. search_controller.text = '';
  129. });
  130. _unitBloc.add(ListUnit(search: search,completed: completed));
  131. },child: Container(width: 20,child: Icon(Icons.arrow_back,color:Colors.grey))),
  132. title: Container(
  133. color: Colors.white,
  134. child: TextFormField(
  135. maxLines: 1,
  136. controller: search_controller,
  137. onChanged: (val) => debounce(const Duration(milliseconds: 300), _onChanged, [val]),
  138. decoration: InputDecoration.collapsed(
  139. hintText: 'Search..',
  140. ),
  141. ),
  142. ),
  143. actions: <Widget>[
  144. TextButton(
  145. onPressed: ()async{
  146. await scan();
  147. _unitBloc.add(ListUnit(search: search,completed: completed));
  148. },
  149. child: Icon(Icons.select_all,color:Colors.grey),
  150. )
  151. ],
  152. )
  153. :null,
  154. body: BlocProvider(
  155. create: (BuildContext context) => _unitBloc,
  156. child: BlocListener<ListUnitBloc,ListUnitState>(
  157. bloc: _unitBloc,
  158. listener: (context,state){
  159. if(state is ListUnitError){
  160. util.showFlushbar(context, state.err,color: Colors.red);
  161. }
  162. },
  163. child: Column(
  164. children: <Widget>[
  165. (hideAppbar)?Container():SizedBox(height: MediaQuery.of(context).size.height/25,),
  166. Expanded(
  167. child:Stack(
  168. children: <Widget>[
  169. Container(
  170. alignment: Alignment.topRight,
  171. child: BlocBuilder<ListUnitBloc,ListUnitState>(
  172. bloc: _unitBloc,
  173. builder: (context, state) {
  174. if (state is ListUnitFinish){
  175. unitsRef = state.units;
  176. BlobsRef = state.blobs;
  177. }
  178. else if(state is ListUnitInitial){
  179. _unitBloc.add(ListUnit());
  180. }
  181. if(state is ListUnitLoading){
  182. return Center(
  183. child: Container(
  184. height: 15,
  185. width: 15,
  186. child: CircularProgressIndicator(),
  187. ),
  188. );
  189. }
  190. else{
  191. return (unitsRef.isEmpty)
  192. ? Container(padding: EdgeInsets.only(top: 10,left: 10,right: 10),
  193. child: Row(
  194. crossAxisAlignment: CrossAxisAlignment.start,
  195. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  196. children: <Widget>[
  197. Row(
  198. children: <Widget>[
  199. Checkbox(
  200. value: completed,
  201. onChanged: (value)async{
  202. setState(() {
  203. completed = value??false;
  204. });
  205. _unitBloc.add(ListUnit(search: search,completed: completed));
  206. },
  207. ),
  208. Text('Completed')
  209. ],
  210. ),
  211. (completed||hideAppbar)?Container():Row(
  212. mainAxisAlignment: MainAxisAlignment.end,
  213. children: <Widget>[
  214. Text('Unit : ',style: TextStyle(color: Colors.grey,fontSize: 15),),
  215. Text('${(unitsRef.where((element) => element.flag=='TRUE').length==unitsRef.length)?'Done':'${unitsRef.length-unitsRef.where((element) => element.flag=='TRUE').length}'}',style: TextStyle(color: (unitsRef.length==unitsRef.where((element) => element.flag=='TRUE').length)?Colors.green:Colors.black,fontWeight: FontWeight.bold,fontSize: 16),),
  216. Text(!(unitsRef.length==unitsRef.where((element) => element.flag=='TRUE').length)?' of':'',style: TextStyle(color: Colors.grey,fontSize: 15),),
  217. Text(!(unitsRef.length==unitsRef.where((element) => element.flag=='TRUE').length)?' ${unitsRef.length}':'',style: TextStyle(color: Colors.black,fontSize: 16,fontWeight: FontWeight.bold,),),
  218. ],
  219. ),
  220. ],
  221. ),)
  222. :ListView.builder(
  223. padding: EdgeInsets.only(bottom: 10),
  224. itemCount: unitsRef.length,
  225. shrinkWrap: false,
  226. itemBuilder: (context,index){
  227. Uint8List? display;
  228. display = unitsRef[index].flag=='FALSE'?null:(BlobsRef.length==unitsRef.length)?BlobsRef[index]!.bytes:null;
  229. return Column(
  230. children: <Widget>[
  231. (index==0)?Container(padding: EdgeInsets.only(top: 10,left: 10,right: 10),alignment: Alignment.centerRight,
  232. child: Row(
  233. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  234. children: <Widget>[
  235. Row(
  236. children: <Widget>[
  237. Checkbox(
  238. value: completed,
  239. onChanged: (value)async{
  240. setState(() {
  241. completed = value??false;
  242. });
  243. _unitBloc.add(ListUnit(search: search,completed: completed));
  244. },
  245. ),
  246. Text('Completed')
  247. ],
  248. ),
  249. (completed||hideAppbar)?Container():Row(
  250. mainAxisAlignment: MainAxisAlignment.end,
  251. children: <Widget>[
  252. Text('Unit : ',style: TextStyle(color: Colors.grey,fontSize: 15),),
  253. Text('${(unitsRef.where((element) => element.flag=='TRUE').length==unitsRef.length)?'Done':'${unitsRef.length-unitsRef.where((element) => element.flag=='TRUE').length}'}',style: TextStyle(color: (unitsRef.length==unitsRef.where((element) => element.flag=='TRUE').length)?Colors.green:Colors.black,fontWeight: FontWeight.bold,fontSize: 16),),
  254. Text(!(unitsRef.length==unitsRef.where((element) => element.flag=='TRUE').length)?' of':'',style: TextStyle(color: Colors.grey,fontSize: 15),),
  255. Text(!(unitsRef.length==unitsRef.where((element) => element.flag=='TRUE').length)?' ${unitsRef.length}':'',style: TextStyle(color: Colors.black,fontSize: 16,fontWeight: FontWeight.bold,),),
  256. ],
  257. ),
  258. ],
  259. ),):Container(),
  260. Padding(
  261. padding: const EdgeInsets.only(left:10,right: 10,top: 10),
  262. child: Container(
  263. padding: EdgeInsets.all(5.0),
  264. decoration: BoxDecoration(
  265. borderRadius: BorderRadius.circular(5),
  266. color: Colors.white,
  267. boxShadow: [
  268. BoxShadow(
  269. color: Colors.grey,
  270. blurRadius: 5.0, // has the effect of softening the shadow
  271. spreadRadius: 2.0, // has the effect of extending the shadow
  272. offset: Offset(
  273. 00.0, // horizontal, move right 10
  274. 2.0, // vertical, move down 10
  275. ),
  276. )
  277. ],
  278. border: Border.all(color: Colors.grey.withOpacity(0.5)),
  279. ),
  280. child:Row(
  281. children: <Widget>[
  282. Expanded(
  283. flex: 3,
  284. child: InkWell(
  285. onTap: ()async{
  286. if(display==null){
  287. await Navigator.push(
  288. context,
  289. MaterialPageRoute(
  290. builder: (context) => UnitDetails(unitsRef[index],),
  291. ),
  292. );
  293. }
  294. else{
  295. await Navigator.push(context, MaterialPageRoute(builder: (context) => PhotoViewer(display!,id: unitsRef[index].id.toString(),jenis: '',edit: false,)));
  296. }
  297. },
  298. child: Hero(tag: unitsRef[index].id,child: Padding(
  299. padding: EdgeInsets.only(right: 10),
  300. child: Container(width: 100,height: 100,alignment: Alignment.center,child:(display==null)?Icon(Icons.crop_original,color: Colors.white,size: 80,):null,
  301. decoration: BoxDecoration(
  302. color: Colors.grey.withOpacity(0.5),
  303. image: (display!=null)?DecorationImage(
  304. image: MemoryImage(display),fit: BoxFit.cover,):null,)),
  305. )),
  306. )),
  307. Expanded(
  308. flex: 7,
  309. child: InkWell(
  310. onTap: ()async{
  311. await Navigator.push(
  312. context,
  313. MaterialPageRoute(
  314. builder: (context) => UnitDetails(unitsRef[index],),
  315. ),
  316. );
  317. },
  318. child: SingleChildScrollView(
  319. scrollDirection: Axis.horizontal,
  320. child: Column(
  321. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  322. crossAxisAlignment: CrossAxisAlignment.start,
  323. children: <Widget>[
  324. Text('Rangka : ${unitsRef[index].rangka}'),
  325. Divider(height: 10,),
  326. Text('Tipe : ${unitsRef[index].tipe}'),
  327. Divider(height: 10,),
  328. Row(
  329. children: <Widget>[
  330. // Container(width: MediaQuery.of(context).size.width*0.35,child: Text('State : ${unitsRef[index].state}')),
  331. // Container(width: MediaQuery.of(context).size.width*0.5,child: Text('Tipe : ${unitsRef[index].tipe}',style: TextStyle(fontSize: 12),)),
  332. Text('Timestamp : ${unitsRef[index].timestamp}'),
  333. ],
  334. ),
  335. Divider(height: 10,),
  336. Row(
  337. children: <Widget>[
  338. Container(width: MediaQuery.of(context).size.width*0.35,child: Text('Warna : ${unitsRef[index].warna}')),
  339. Text('State : ${unitsRef[index].state}'),
  340. ],
  341. )
  342. ],
  343. ),
  344. ),
  345. )),
  346. ],
  347. )),
  348. ),
  349. ],
  350. );
  351. },
  352. );
  353. }
  354. }),
  355. ),
  356. ],
  357. ),
  358. ),
  359. ],
  360. ),
  361. )
  362. ),
  363. floatingActionButton: FloatingActionButton(
  364. backgroundColor: Colors.indigo.withOpacity(0.8),
  365. onPressed: ()async{
  366. setState(() {
  367. hideAppbar = !(hideAppbar);
  368. });
  369. },
  370. child: Icon(Icons.search,color:Colors.white),
  371. ),
  372. ),
  373. );
  374. }
  375. }