flutter-freaccess-hub/lib/pages/qr_code_page/qr_code_page_widget.dart

512 lines
22 KiB
Dart

// ignore_for_file: use_build_context_synchronously
import 'dart:async';
import 'dart:developer';
import 'package:barcode_widget/barcode_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hub/components/templates_components/qr_code_pass_key_template_component/qr_code_pass_key_template_component_widget.dart';
import 'package:hub/features/storage/index.dart';
import 'package:hub/flutter_flow/custom_functions.dart';
import 'package:hub/flutter_flow/flutter_flow_animations.dart';
import 'package:hub/flutter_flow/flutter_flow_icon_button.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/flutter_flow_util.dart';
import 'package:hub/flutter_flow/flutter_flow_widgets.dart';
import 'package:hub/flutter_flow/nav/nav.dart';
import 'package:hub/pages/qr_code_page/qr_code_page_model.dart';
import 'package:hub/shared/utils/biometric_util.dart';
import 'package:hub/shared/utils/limited_text_size.dart';
import 'package:percent_indicator/circular_percent_indicator.dart';
import 'package:qr_flutter/qr_flutter.dart';
class QrCodePageWidget extends StatefulWidget {
const QrCodePageWidget({super.key});
@override
State<QrCodePageWidget> createState() => _QrCodePageWidgetState();
}
class _QrCodePageWidgetState extends State<QrCodePageWidget>
with TickerProviderStateMixin {
late QrCodePageModel _model;
final scaffoldKey = GlobalKey<ScaffoldState>();
final animationsMap = <String, AnimationInfo>{};
@override
void initState() {
super.initState();
_model = createModel(context, () => QrCodePageModel());
_model.safeSetState = () => safeSetState(() {});
SchedulerBinding.instance.addPostFrameCallback((_) async {
if (animationsMap['barcodeOnActionTriggerAnimation'] != null) {
animationsMap['barcodeOnActionTriggerAnimation']!.controller.fling();
}
});
animationsMap.addAll({
'barcodeOnActionTriggerAnimation': AnimationInfo(
trigger: AnimationTrigger.onActionTrigger,
applyInitialState: true,
effectsBuilder: () => [
VisibilityEffect(duration: 1.ms),
BlurEffect(
curve: Curves.linear,
delay: 0.0.ms,
duration: 600.0.ms,
begin: const Offset(0.0, 0.0),
end: const Offset(10.0, 10.0),
),
],
),
});
setupAnimations(
animationsMap.values.where((anim) =>
anim.trigger == AnimationTrigger.onActionTrigger ||
!anim.applyInitialState),
this,
);
}
@override
void dispose() {
// Removendo o ouvinte antes de chamar super.dispose para evitar vazamentos de memória
if (animationsMap['barcodeOnActionTriggerAnimation'] != null) {
animationsMap['barcodeOnActionTriggerAnimation']!
.controller
.removeStatusListener((status) {});
}
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
backgroundColor: FlutterFlowTheme.of(context).primaryBackground,
appBar: buildAppBar(context),
body: buildBody(context),
);
}
Widget buildBody(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
double screenHeight = MediaQuery.of(context).size.height;
double smallerDimension =
screenWidth < screenHeight ? screenWidth : screenHeight;
double dimension = smallerDimension * 0.75;
double totalTimeInSeconds = 100.0;
LimitedFontSizeUtil.getCalculateFontSize(context, 18, 18, 16);
double limitedBodyFontSize = LimitedFontSizeUtil.getBodyFontSize(context);
return SafeArea(
// top: true,
child: Center(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
if (_model.isAccess == true && _model.key != null)
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 20),
child: Text(
FFLocalizations.of(context).getVariableText(
ptText: 'Use esse QR Code para acesso',
enText: 'Use this QR Code for access',
),
textAlign: TextAlign.center,
style: FlutterFlowTheme.of(context).headlineMedium.override(
fontFamily:
FlutterFlowTheme.of(context).headlineMediumFamily,
color: FlutterFlowTheme.of(context).primaryText,
fontSize: 16.0,
fontWeight: FontWeight.bold,
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap().containsKey(
FlutterFlowTheme.of(context)
.headlineMediumFamily),
),
),
),
Stack(
children: [
if (_model.isAccess == true && _model.key != null)
Align(
alignment: const AlignmentDirectional(0.0, 0.0),
child: InkWell(
onTap: () async {
safeSetState(() async {
_resetAnimationAndToggleAccess();
});
_model.isFingerprint
? await _showBiometricsAuth(context)
: await _showQrCodeBottomSheet(context);
},
child: _model.buildQrCode(
dimension: dimension,
errorCorrectLevel: QrErrorCorrectLevel.M,
identifier: _model.userDevUUID,
pass: _model.key!,
direction: 5,
),
),
),
if (_model.isAccess == false && _model.key == null)
Align(
alignment: const AlignmentDirectional(0, 0),
child: BarcodeWidget(
data: 'Barcode',
barcode: Barcode.qrCode(),
width: 300.0,
height: 200.0,
color: FlutterFlowTheme.of(context).primaryText,
backgroundColor: Colors.transparent,
errorBuilder: (context, error) => const SizedBox(
width: 300.0,
height: 200.0,
),
drawText: false,
).animateOnActionTrigger(
animationsMap['barcodeOnActionTriggerAnimation']!,
),
),
if (_model.isAccess == false && _model.key == null)
Align(
alignment: const AlignmentDirectional(0.0, 0.0),
child: InkWell(
splashColor: Colors.transparent,
focusColor: Colors.transparent,
hoverColor: Colors.transparent,
highlightColor: Colors.transparent,
onLongPress: () async {
await _model.qrCodeEncoder(
context,
key: _model.key,
);
setState(() {});
},
child: Container(
width: 200.0,
height: 200.0,
decoration: const BoxDecoration(),
child: Align(
alignment: const AlignmentDirectional(0.0, 0.0),
child: FFButtonWidget(
onPressed: () async {
_model.isFingerprint
? await _showBiometricsAuth(context)
: await _showQrCodeBottomSheet(context);
},
text: FFLocalizations.of(context).getVariableText(
ptText: 'Gerar QR Code',
enText: 'Generate QR Code',
),
options: FFButtonOptions(
height: 40.0,
padding: const EdgeInsetsDirectional.fromSTEB(
24.0, 0.0, 24.0, 0.0),
iconPadding:
const EdgeInsetsDirectional.fromSTEB(
0.0, 0.0, 0.0, 0.0),
color: FlutterFlowTheme.of(context).primary,
textStyle: FlutterFlowTheme.of(context)
.titleSmall
.override(
fontFamily: FlutterFlowTheme.of(context)
.titleSmallFamily,
color: Colors.white,
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap()
.containsKey(
FlutterFlowTheme.of(context)
.titleSmallFamily),
fontSize: LimitedFontSizeUtil
.getCalculateFontSize(
context, 12, 12, 10),
),
elevation: 3.0,
borderSide: const BorderSide(
color: Colors.transparent,
width: 1.0,
),
borderRadius: BorderRadius.circular(8.0),
),
),
),
),
),
),
],
),
if (_model.isAccess == true && _model.key != null)
Padding(
padding: const EdgeInsets.fromLTRB(0, 20, 0, 0),
child: Container(
width: 300.0,
decoration: const BoxDecoration(),
child: Visibility(
visible: _model.isAccess == true,
child: Text(
FFLocalizations.of(context).getVariableText(
ptText:
'Certifique-se de que o QRCode está visivel para o leitor',
enText:
'Make sure the QRCode is visible to the reader',
// '6z6kvmhl' /* Certifique-se de que o QRCode ... */,
),
textAlign: TextAlign.center,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily:
FlutterFlowTheme.of(context).bodyMediumFamily,
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap().containsKey(
FlutterFlowTheme.of(context)
.bodyMediumFamily),
fontSize: limitedBodyFontSize,
),
),
),
),
),
if (_model.isAccess == true && _model.key != null)
Padding(
padding: const EdgeInsets.fromLTRB(0, 20, 0, 20),
child: Container(
width: 250.0,
height: 80.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100.0),
border: Border.all(
color: FlutterFlowTheme.of(context).primary,
),
),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: Padding(
padding: const EdgeInsetsDirectional.fromSTEB(
10.0, 0.0, 0.0, 0.0),
child: Text(
FFLocalizations.of(context).getVariableText(
ptText: 'Expirando QR code em',
enText: 'Expiring QR code in',
// 'wkjkxd2e' /* Trocando QR code em */,
),
textAlign: TextAlign.center,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: FlutterFlowTheme.of(context)
.bodyMediumFamily,
letterSpacing: 0.0,
fontWeight: FontWeight.w600,
useGoogleFonts: GoogleFonts.asMap()
.containsKey(
FlutterFlowTheme.of(context)
.bodyMediumFamily),
fontSize:
LimitedFontSizeUtil.getNoResizeFont(
context, 14),
),
),
),
),
Align(
alignment: const AlignmentDirectional(0.0, 0.0),
child: Padding(
padding: const EdgeInsetsDirectional.fromSTEB(
0.0, 0.0, 20.0, 0.0),
child: StreamBuilder<double>(
stream: getProgressValue(),
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return const CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else if (!snapshot.hasData) {
return const Text('No data');
} else {
final progress = snapshot.data!;
return CircularPercentIndicator(
percent: progress,
restartAnimation: true,
reverse: false,
radius: 30.0,
lineWidth: 7.0,
animation: true,
animateFromLastPercent: true,
onAnimationEnd: () {
_resetAnimationAndToggleAccess();
},
progressColor:
FlutterFlowTheme.of(context).primary,
backgroundColor:
FlutterFlowTheme.of(context)
.primaryText,
center: Text(
'${(progress * totalTimeInSeconds / 5).toStringAsFixed(1)}s',
style: FlutterFlowTheme.of(context)
.headlineSmall
.override(
fontFamily:
FlutterFlowTheme.of(context)
.headlineSmallFamily,
fontSize: LimitedFontSizeUtil
.getNoResizeFont(context, 14),
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap()
.containsKey(
FlutterFlowTheme.of(context)
.headlineSmallFamily),
),
),
startAngle: 20.0,
);
}
},
),
),
),
],
),
),
),
],
),
),
),
);
}
Future<void> _showBiometricsAuth(BuildContext context) async {
await BiometricHelper.checkBiometrics()
.then((value) async =>
await BiometricHelper.authenticateBiometric().then((value) async {
if (value == false)
throw Exception('Biometric authentication failed');
final key = await StorageHelper()
.get(SecureStorageKey.fingerprintPass.value);
if (key == null || key.isEmpty) throw Exception('No key found');
safeSetState(() {
if (animationsMap['barcodeOnActionTriggerAnimation'] != null) {
animationsMap['barcodeOnActionTriggerAnimation']!
.controller
.stop();
animationsMap['barcodeOnActionTriggerAnimation']!
.controller
.reverse();
}
_model.isAccess = !_model.isAccess;
_model.key = key;
});
}))
.onError((error, stackTrace) {
log('Error', error: error, stackTrace: stackTrace);
if (mounted) _showQrCodeBottomSheet(context);
});
}
Future<void> _showQrCodeBottomSheet(BuildContext context) async {
await showModalBottomSheet(
isScrollControlled: true,
backgroundColor: Colors.transparent,
useSafeArea: true,
context: context,
builder: (context) {
return GestureDetector(
onTap: () => _model.unfocusNode.canRequestFocus
? FocusScope.of(context).requestFocus(_model.unfocusNode)
: FocusScope.of(context).unfocus(),
child: Padding(
padding: MediaQuery.viewInsetsOf(context),
child: QrCodePassKeyTemplateComponentWidget(
toggleActionStatus: (key) async {
safeSetState(() {
if (animationsMap['barcodeOnActionTriggerAnimation'] !=
null) {
animationsMap['barcodeOnActionTriggerAnimation']!
.controller
.stop();
animationsMap['barcodeOnActionTriggerAnimation']!
.controller
.reverse();
}
_model.isAccess = !_model.isAccess;
_model.key = key;
});
},
),
),
);
},
).catchError(
(error) => safeSetState(() => _resetAnimationAndToggleAccess()));
unawaited(
() async {
await _model.qrCodeEncoder(context, key: _model.key);
safeSetState(() {});
}(),
);
}
void _resetAnimationAndToggleAccess() {
safeSetState(() {
animationsMap['barcodeOnActionTriggerAnimation']!.controller.reset();
animationsMap['barcodeOnActionTriggerAnimation']!.controller.forward();
_model.isAccess = !_model.isAccess;
_model.key = null;
});
}
AppBar buildAppBar(BuildContext context) {
return AppBar(
key: ValueKey<String>('BackNavigationAppBar'),
backgroundColor: FlutterFlowTheme.of(context).primaryBackground,
automaticallyImplyLeading: false,
leading: FlutterFlowIconButton(
borderColor: Colors.transparent,
borderRadius: 30.0,
borderWidth: 1.0,
buttonSize: 60.0,
icon: Icon(
Icons.keyboard_arrow_left,
color: FlutterFlowTheme.of(context).primaryText,
size: 30.0,
),
onPressed: () async {
context.pop();
},
),
title: Text(
FFLocalizations.of(context).getVariableText(
ptText: 'QRCode de Acesso',
enText: 'Access QRCode',
),
style: FlutterFlowTheme.of(context).headlineMedium.override(
fontFamily: FlutterFlowTheme.of(context).headlineMediumFamily,
color: FlutterFlowTheme.of(context).primaryText,
fontSize: 16.0,
fontWeight: FontWeight.bold,
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap().containsKey(
FlutterFlowTheme.of(context).headlineMediumFamily),
),
),
actions: const [],
centerTitle: true,
elevation: 0.0,
);
}
}