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

425 lines
18 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/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/helpers/base_storage.dart';
import 'package:hub/shared/helpers/storage_helper.dart';
import 'package:hub/shared/utils/biometric_util.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;
return SafeArea(
// top: true,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
if (_model.isAccess == true && _model.key != null)
Text(
FFLocalizations.of(context).getVariableText(
ptText: 'Use esse QR Code para acesso',
enText: 'Use this QR Code for access',
),
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: FlutterFlowTheme.of(context).bodyMediumFamily,
fontSize: 20.0,
letterSpacing: 0.0,
fontWeight: FontWeight.bold,
useGoogleFonts: GoogleFonts.asMap().containsKey(FlutterFlowTheme.of(context).bodyMediumFamily),
),
),
Stack(
children: [
if (_model.isAccess == true && _model.key != null)
Align(
alignment: const AlignmentDirectional(0.0, 0.0),
child: InkWell(
onTap: () async {
_resetAnimationAndToggleAccess();
log('isFingerprint: ${_model.isFingerprint}');
_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 {
log('isFingerprint: ${_model.isFingerprint}');
_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),
),
elevation: 3.0,
borderSide: const BorderSide(
color: Colors.transparent,
width: 1.0,
),
borderRadius: BorderRadius.circular(8.0),
),
),
),
),
),
),
],
),
if (_model.isAccess == true && _model.key != null)
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 ... */,
),
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: FlutterFlowTheme.of(context).bodyMediumFamily,
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap().containsKey(FlutterFlowTheme.of(context).bodyMediumFamily),
),
),
),
),
if (_model.isAccess == true && _model.key != null)
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',
),
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),
),
),
),
),
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: 14.0,
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 {
final key =
await StorageHelper().get(SecureStorageKey.fingerprintPass.value, Storage.SecureStorage) ?? '';
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(
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).getText('ku7jqe53'),
style: FlutterFlowTheme.of(context).headlineMedium.override(
fontFamily: FlutterFlowTheme.of(context).headlineMediumFamily,
color: FlutterFlowTheme.of(context).primaryText,
fontSize: 15.0,
fontWeight: FontWeight.bold,
letterSpacing: 0.0,
useGoogleFonts: GoogleFonts.asMap().containsKey(FlutterFlowTheme.of(context).headlineMediumFamily),
),
),
actions: const [],
centerTitle: true,
elevation: 0.0,
);
}
}