Untitled
unknown
plain_text
4 months ago
13 kB
4
Indexable
import 'dart:io'; import 'package:edusafair/core/helpers/device_size_helper.dart'; import 'package:edusafair/core/helpers/permision_helper.dart'; import 'package:edusafair/core/theme/colors.dart'; import 'package:edusafair/core/utils/app_asset.dart'; import 'package:edusafair/core/utils/constants.dart'; import 'package:edusafair/data/repository/repository_impl.dart'; import 'package:edusafair/domain/model/response_model.dart'; import 'package:edusafair/domain/model/result.dart'; import 'package:edusafair/presentation/screen/home/widget/result_card_widget.dart'; import 'package:edusafair/presentation/utils/view_constants.dart'; import 'package:flutter/material.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:qr_code_scanner/qr_code_scanner.dart'; class QRScanPage extends StatefulWidget { final String securityKey; const QRScanPage({super.key, required this.securityKey}); @override State<QRScanPage> createState() => _QRScanPageState(); } class _QRScanPageState extends State<QRScanPage> with TickerProviderStateMixin { final GlobalKey _qrKey = GlobalKey(debugLabel: 'QR'); Barcode? _result; ResponseModel? _responseModel; QRViewController? _controller; bool _haveCameraPermission = false; late AnimationController _animationController; DataLoadingState loadingState = DataLoadingState.init; VerificationStatus verificationStatus = VerificationStatus.none; @override void initState() { super.initState(); _checkCameraPermission(); _animationController = AnimationController( vsync: this, duration: const Duration(milliseconds: 300)); } @override void dispose() { _controller?.stopCamera(); _controller?.dispose(); _animationController.dispose(); super.dispose(); } @override void reassemble() { super.reassemble(); if (Platform.isAndroid) { _controller?.pauseCamera(); } else if (Platform.isIOS) { _controller?.resumeCamera(); } } @override Widget build(BuildContext context) { return SafeArea( child: Scaffold( body: Column( children: [ Expanded( flex: 1, child: _qrCameraSection(), ), Expanded(flex: 1, child: _bottomSection()), ], ), ), ); } Widget _bottomSection() { return Container( padding: const EdgeInsets.only(left: 32, right: 32, top: 16, bottom: 16), child: Stack( //mainAxisAlignment: MainAxisAlignment.center, alignment: Alignment.topCenter, children: [ const Text( 'Please move your camera\nover the QR code', textAlign: TextAlign.center, style: TextStyle(color: Colors.grey), ), Center( child: _buildResult( status: verificationStatus, state: loadingState, message: _responseModel?.message), ), const SizedBox( height: 16, ), if (_result != null && loadingState == DataLoadingState.init || loadingState == DataLoadingState.loading) Positioned(bottom: 10, child: _verifyButton()), ], ), ); } Widget _buildResult( {required DataLoadingState state, required VerificationStatus status, String? message}) { Widget widget; if (state == DataLoadingState.completed) { if (status == VerificationStatus.verified) { widget = ResultCardWidget( color: AppColor.colorBlue, title: 'Success', icon: Icons.check, subtitle: message, btnOnClick: _resetAll, btnText: 'Verify Another', btnColor: AppColor.colorBlue, ); } else if (status == VerificationStatus.unverified) { widget = ResultCardWidget( color: const Color(0xffFCAEAE), title: 'Failed', icon: Icons.close, subtitle: message, btnOnClick: _verify, btnText: 'Retry', btnColor: AppColor.colorRed, ); } else if (status == VerificationStatus.error) { widget = ResultCardWidget( color: Colors.grey, title: 'Error', icon: Icons.bug_report_outlined, btnOnClick: _resetAll, btnText: 'Try Again', btnColor: Colors.grey, ); } else { widget = const SizedBox.shrink(); } } else if (state == DataLoadingState.error) { widget = ResultCardWidget( color: Colors.grey, title: 'Error', icon: Icons.bug_report_outlined, btnOnClick: _resetAll, btnText: 'Try Again', btnColor: Colors.grey, ); } else { widget = const SizedBox.shrink(); } return AnimatedScale( duration: const Duration(milliseconds: 300), scale: loadingState == DataLoadingState.completed || loadingState == DataLoadingState.error ? 1 : 0, child: widget, ); } Widget _verifyButton() { return SizedBox( height: 56, child: loadingState == DataLoadingState.loading ? const Center( child: CircularProgressIndicator( color: AppColor.colorBlue, ), ) : loadingState == DataLoadingState.init ? ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: AppColor.colorBlue, foregroundColor: Colors.white, // shape: const BeveledRectangleBorder( // borderRadius: BorderRadius.all( // Radius.elliptical(10, 10), // ), // ), ), onPressed: _verify, child: Text( verificationStatus == VerificationStatus.verified ? 'Verified' : 'Verify', textAlign: TextAlign.center, ), ) : const SizedBox.shrink(), ); } Widget _qrCameraSection() { const double cameraBoxSpace = 48.0; return Stack( fit: StackFit.expand, children: [ Align( alignment: AlignmentDirectional.topCenter, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ const SizedBox( height: 24, ), Image.asset( AppAsset.appLogo, height: 48, ) ], )), //camera view Positioned.fill( top: cameraBoxSpace + cameraBoxSpace, left: cameraBoxSpace, right: cameraBoxSpace, bottom: cameraBoxSpace - cameraBoxSpace, child: Container( clipBehavior: Clip.hardEdge, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), ), child: QRView( key: _qrKey, onQRViewCreated: _onQrViewCreated, cameraFacing: CameraFacing.back, onPermissionSet: (ctrl, p) => _onPermissionSet(context, ctrl, p), overlay: QrScannerOverlayShape( borderColor: AppColor.colorGreen, overlayColor: Colors.white.withOpacity(0.85), borderRadius: 10, borderLength: 30, borderWidth: 10, cutOutSize: DeviceSizeHelper(context).scanArea), ), ), ), //if result captured if (_result != null) Positioned.fill( top: cameraBoxSpace + cameraBoxSpace, child: Container( decoration: BoxDecoration(color: Colors.white.withOpacity(0.4)), child: Center( child: GestureDetector( onTap: () { _resetAll(); }, child: Container( padding: const EdgeInsets.all(8.0), decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.black.withOpacity(0.4), ), child: const Icon( Icons.restart_alt, size: 30, color: Colors.white, ), ), ), ), )), //flip camera Positioned( bottom: 10, right: 48 + 10, child: Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.black.withOpacity(0.2), shape: BoxShape.circle, ), child: AnimatedBuilder( animation: _animationController, builder: (context, child) { return Transform.rotate( angle: _animationController.value * (360 / 100), child: child, ); }, child: InkWell( child: Icon( Icons.adaptive.flip_camera, color: Colors.white, size: 16, ), onTap: () { _controller?.flipCamera(); if (_animationController.isDismissed) { _animationController.forward(); } else { _animationController.reverse(); } _resetAll(); }, ), ), ), ), ], ); } void _onQrViewCreated(QRViewController controller) { _controller = controller; _controller?.scannedDataStream.listen((scanData) { _result = scanData; if (_result != null) { _controller?.pauseCamera(); setState(() {}); } }).onDone(() { _controller?.stopCamera(); }); } void _onPermissionSet(BuildContext context, QRViewController ctrl, bool p) { if (!p) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('no Permission')), ); } } void _checkCameraPermission() async { final permission = await PermissionHelper().hasCameraPermission(); if (!permission) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: const Text("Camera Permission Needed"), action: SnackBarAction( onPressed: () async { await openAppSettings(); }, label: 'Settings', ), )); } } if (_haveCameraPermission != permission) { setState(() { _haveCameraPermission = permission; }); } } void _resetAll() { _controller?.resumeCamera(); setState(() { _result = null; _responseModel = null; verificationStatus = VerificationStatus.none; loadingState = DataLoadingState.init; }); } void showAppSnackBar(BuildContext context, String msg) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(msg))); } } Future<void> _verify() async { setState(() { loadingState = DataLoadingState.loading; verificationStatus = VerificationStatus.none; _responseModel = null; }); final dataResult = await RepositoryImpl().getResponse(AppConstant().generateUrl( scannedUrl: _result?.code ?? '', userKey: widget.securityKey, )); if (dataResult is Success) { _responseModel = dataResult.data; loadingState = DataLoadingState.completed; if (_responseModel?.status ?? false) { verificationStatus = VerificationStatus.verified; } else { verificationStatus = VerificationStatus.unverified; } } else if (dataResult is Failure) { _responseModel = null; verificationStatus = VerificationStatus.error; loadingState = DataLoadingState.error; } setState(() {}); } }
Editor is loading...
Leave a Comment